]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 3 Apr 2009 04:05:30 +0000 (21:05 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 3 Apr 2009 04:05:30 +0000 (21:05 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (54 commits)
  glge: remove unused #include <version.h>
  dnet: remove unused #include <version.h>
  tcp: miscounts due to tcp_fragment pcount reset
  tcp: add helper for counter tweaking due mid-wq change
  hso: fix for the 'invalid frame length' messages
  hso: fix for crash when unplugging the device
  fsl_pq_mdio: Fix compile failure
  fsl_pq_mdio: Revive UCC MDIO support
  ucc_geth: Pass proper device to DMA routines, otherwise oops happens
  i.MX31: Fixing cs89x0 network building to i.MX31ADS
  tc35815: Fix build error if NAPI enabled
  hso: add Vendor/Product ID's for new devices
  ucc_geth: Remove unused header
  gianfar: Remove unused header
  kaweth: Fix locking to be SMP-safe
  net: allow multiple dev per napi with GRO
  r8169: reset IntrStatus after chip reset
  ixgbe: Fix potential memory leak/driver panic issue while setting up Tx & Rx ring parameters
  ixgbe: fix ethtool -A|a behavior
  ixgbe: Patch to fix driver panic while freeing up tx & rx resources
  ...

2019 files changed:
CREDITS
Documentation/ABI/testing/sysfs-bus-pci
Documentation/ABI/testing/sysfs-fs-ext4 [new file with mode: 0644]
Documentation/DMA-API.txt
Documentation/DocBook/.gitignore
Documentation/DocBook/kernel-api.tmpl
Documentation/DocBook/procfs_example.c
Documentation/PCI/MSI-HOWTO.txt
Documentation/PCI/pci-iov-howto.txt [new file with mode: 0644]
Documentation/Smack.txt
Documentation/cgroups/cgroups.txt
Documentation/cgroups/memcg_test.txt
Documentation/dvb/get_dvb_firmware
Documentation/fb/00-INDEX
Documentation/fb/cyblafb/bugs [deleted file]
Documentation/fb/cyblafb/credits [deleted file]
Documentation/fb/cyblafb/documentation [deleted file]
Documentation/fb/cyblafb/fb.modes [deleted file]
Documentation/fb/cyblafb/performance [deleted file]
Documentation/fb/cyblafb/todo [deleted file]
Documentation/fb/cyblafb/usage [deleted file]
Documentation/fb/cyblafb/whatsnew [deleted file]
Documentation/fb/cyblafb/whycyblafb [deleted file]
Documentation/feature-removal-schedule.txt
Documentation/filesystems/Locking
Documentation/filesystems/ext4.txt
Documentation/filesystems/proc.txt
Documentation/filesystems/sysfs-pci.txt
Documentation/gpio.txt
Documentation/hwmon/ds1621
Documentation/hwmon/lis3lv02d
Documentation/hwmon/ltc4215 [new file with mode: 0644]
Documentation/hwmon/pcf8591 [moved from Documentation/i2c/chips/pcf8591 with 100% similarity]
Documentation/hwmon/sysfs-interface
Documentation/hwmon/w83627ehf
Documentation/ioctl/ioctl-number.txt
Documentation/kernel-parameters.txt
Documentation/lguest/lguest.c
Documentation/lockdep-design.txt
Documentation/misc-devices/isl29003 [new file with mode: 0644]
Documentation/powerpc/dts-bindings/fsl/dma.txt
Documentation/powerpc/dts-bindings/fsl/esdhc.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/fsl/ssi.txt
Documentation/powerpc/dts-bindings/mmc-spi-slot.txt [new file with mode: 0644]
Documentation/sysctl/00-INDEX
Documentation/sysctl/fs.txt
Documentation/sysctl/kernel.txt
Documentation/sysctl/net.txt [new file with mode: 0644]
Documentation/sysrq.txt
Documentation/video4linux/CARDLIST.bttv
Documentation/video4linux/CARDLIST.cx23885
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/Zoran
Documentation/video4linux/bttv/Insmod-options
Documentation/video4linux/bttv/README
Documentation/video4linux/cx2341x/README.hm12
Documentation/video4linux/gspca.txt
Documentation/video4linux/si470x.txt
Documentation/video4linux/v4l2-framework.txt
Documentation/video4linux/v4lgrab.c
Documentation/video4linux/zr364xx.txt
Documentation/x86/earlyprintk.txt [new file with mode: 0644]
MAINTAINERS
arch/Kconfig
arch/alpha/include/asm/machvec.h
arch/alpha/include/asm/pci.h
arch/alpha/include/asm/spinlock.h
arch/alpha/include/asm/system.h
arch/alpha/include/asm/types.h
arch/alpha/include/asm/uaccess.h
arch/alpha/include/asm/xchg.h [new file with mode: 0644]
arch/alpha/kernel/Makefile
arch/alpha/kernel/err_ev6.c
arch/alpha/kernel/err_ev7.c
arch/alpha/kernel/err_marvel.c
arch/alpha/kernel/err_titan.c
arch/alpha/kernel/pci-sysfs.c [new file with mode: 0644]
arch/alpha/kernel/pci.c
arch/alpha/kernel/pci_iommu.c
arch/alpha/kernel/process.c
arch/alpha/kernel/proto.h
arch/alpha/kernel/setup.c
arch/alpha/kernel/smc37c669.c
arch/alpha/kernel/srm_env.c
arch/alpha/kernel/sys_jensen.c
arch/alpha/kernel/sys_sable.c
arch/alpha/kernel/traps.c
arch/arm/include/asm/spinlock.h
arch/arm/kernel/process.c
arch/arm/mach-pxa/pcm990-baseboard.c
arch/arm/plat-mxc/include/mach/mx3_camera.h [new file with mode: 0644]
arch/avr32/kernel/process.c
arch/avr32/mm/fault.c
arch/blackfin/kernel/process.c
arch/blackfin/mm/sram-alloc.c
arch/cris/arch-v10/kernel/process.c
arch/cris/arch-v10/kernel/time.c
arch/cris/arch-v32/kernel/process.c
arch/cris/arch-v32/kernel/smp.c
arch/cris/arch-v32/kernel/time.c
arch/cris/include/arch-v32/arch/spinlock.h
arch/frv/kernel/irq-mb93091.c
arch/frv/kernel/irq-mb93093.c
arch/frv/kernel/irq-mb93493.c
arch/frv/kernel/process.c
arch/frv/kernel/time.c
arch/h8300/kernel/process.c
arch/h8300/kernel/timer/itu.c
arch/h8300/kernel/timer/timer16.c
arch/h8300/kernel/timer/timer8.c
arch/h8300/kernel/timer/tpu.c
arch/ia64/configs/generic_defconfig
arch/ia64/dig/Makefile
arch/ia64/dig/dig_vtd_iommu.c [deleted file]
arch/ia64/hp/common/hwsw_iommu.c
arch/ia64/hp/common/sba_iommu.c
arch/ia64/hp/sim/simserial.c
arch/ia64/include/asm/dma-mapping.h
arch/ia64/include/asm/intrinsics.h
arch/ia64/include/asm/machvec.h
arch/ia64/include/asm/machvec_dig_vtd.h
arch/ia64/include/asm/machvec_hpzx1.h
arch/ia64/include/asm/machvec_hpzx1_swiotlb.h
arch/ia64/include/asm/machvec_sn2.h
arch/ia64/include/asm/mmu_context.h
arch/ia64/include/asm/module.h
arch/ia64/include/asm/native/inst.h
arch/ia64/include/asm/native/patchlist.h [new file with mode: 0644]
arch/ia64/include/asm/native/pvchk_inst.h
arch/ia64/include/asm/paravirt.h
arch/ia64/include/asm/paravirt_patch.h [new file with mode: 0644]
arch/ia64/include/asm/paravirt_privop.h
arch/ia64/include/asm/smp.h
arch/ia64/include/asm/spinlock.h
arch/ia64/include/asm/timex.h
arch/ia64/include/asm/topology.h
arch/ia64/include/asm/uv/uv_hub.h
arch/ia64/include/asm/uv/uv_mmrs.h
arch/ia64/include/asm/xen/hypervisor.h
arch/ia64/include/asm/xen/inst.h
arch/ia64/include/asm/xen/interface.h
arch/ia64/include/asm/xen/minstate.h
arch/ia64/include/asm/xen/patchlist.h [new file with mode: 0644]
arch/ia64/include/asm/xen/privop.h
arch/ia64/kernel/Makefile
arch/ia64/kernel/Makefile.gate [new file with mode: 0644]
arch/ia64/kernel/acpi.c
arch/ia64/kernel/asm-offsets.c
arch/ia64/kernel/dma-mapping.c [new file with mode: 0644]
arch/ia64/kernel/efi.c
arch/ia64/kernel/entry.S
arch/ia64/kernel/fsys.S
arch/ia64/kernel/gate.S
arch/ia64/kernel/gate.lds.S
arch/ia64/kernel/head.S
arch/ia64/kernel/ivt.S
arch/ia64/kernel/machvec.c
arch/ia64/kernel/mca.c
arch/ia64/kernel/module.c
arch/ia64/kernel/palinfo.c
arch/ia64/kernel/paravirt.c
arch/ia64/kernel/paravirt_patch.c [new file with mode: 0644]
arch/ia64/kernel/paravirt_patchlist.c [new file with mode: 0644]
arch/ia64/kernel/paravirt_patchlist.h [new file with mode: 0644]
arch/ia64/kernel/paravirtentry.S
arch/ia64/kernel/patch.c
arch/ia64/kernel/pci-dma.c
arch/ia64/kernel/pci-swiotlb.c
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/process.c
arch/ia64/kernel/salinfo.c
arch/ia64/kernel/setup.c
arch/ia64/kernel/smp.c
arch/ia64/kernel/smpboot.c
arch/ia64/kernel/time.c
arch/ia64/kernel/vmlinux.lds.S
arch/ia64/kvm/kvm-ia64.c
arch/ia64/kvm/vcpu.c
arch/ia64/kvm/vtlb.c
arch/ia64/mm/init.c
arch/ia64/mm/tlb.c
arch/ia64/scripts/pvcheck.sed
arch/ia64/sn/kernel/io_common.c
arch/ia64/sn/kernel/io_init.c
arch/ia64/sn/kernel/setup.c
arch/ia64/sn/kernel/sn2/prominfo_proc.c
arch/ia64/sn/kernel/sn2/sn2_smp.c
arch/ia64/sn/kernel/sn2/sn_hwperf.c
arch/ia64/sn/pci/pci_dma.c
arch/ia64/sn/pci/pcibr/pcibr_dma.c
arch/ia64/xen/Makefile
arch/ia64/xen/gate-data.S [new file with mode: 0644]
arch/ia64/xen/hypercall.S
arch/ia64/xen/time.c
arch/ia64/xen/xen_pv_ops.c
arch/m32r/kernel/process.c
arch/m32r/kernel/time.c
arch/m68k/include/asm/ide.h
arch/m68k/kernel/process.c
arch/m68knommu/kernel/process.c
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/alchemy/Kconfig
arch/mips/alchemy/common/gpio.c
arch/mips/alchemy/devboards/pb1200/platform.c
arch/mips/cavium-octeon/Makefile
arch/mips/cavium-octeon/flash_setup.c
arch/mips/cavium-octeon/octeon-irq.c
arch/mips/cobalt/irq.c
arch/mips/emma/markeins/irq.c
arch/mips/emma/markeins/platform.c
arch/mips/include/asm/cpu.h
arch/mips/include/asm/hazards.h
arch/mips/include/asm/mach-au1x00/cpu-feature-overrides.h [new file with mode: 0644]
arch/mips/include/asm/mach-au1x00/gpio.h
arch/mips/include/asm/mach-bcm47xx/gpio.h
arch/mips/include/asm/mach-ip27/topology.h
arch/mips/include/asm/mips-boards/generic.h
arch/mips/include/asm/smp-ops.h
arch/mips/include/asm/spinlock.h
arch/mips/include/asm/types.h
arch/mips/include/asm/unistd.h
arch/mips/jazz/irq.c
arch/mips/jazz/jazzdma.c
arch/mips/kernel/cevt-bcm1480.c
arch/mips/kernel/cevt-sb1250.c
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/i8253.c
arch/mips/kernel/i8259.c
arch/mips/kernel/irq-msc01.c
arch/mips/kernel/irq_cpu.c
arch/mips/kernel/linux32.c
arch/mips/kernel/process.c
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/setup.c
arch/mips/kernel/smp-up.c
arch/mips/kernel/smp.c
arch/mips/kernel/traps.c
arch/mips/lasat/interrupt.c
arch/mips/lemote/lm2e/irq.c
arch/mips/mm/c-r4k.c
arch/mips/mm/highmem.c
arch/mips/mm/init.c
arch/mips/mm/ioremap.c
arch/mips/mm/tlbex.c
arch/mips/mti-malta/malta-init.c
arch/mips/sgi-ip27/ip27-berr.c
arch/mips/sgi-ip27/ip27-nmi.c
arch/mips/sgi-ip32/ip32-irq.c
arch/mips/sgi-ip32/ip32-memory.c
arch/mips/sibyte/bcm1480/irq.c
arch/mips/sibyte/sb1250/irq.c
arch/mips/sni/a20r.c
arch/mips/sni/pcimt.c
arch/mips/sni/pcit.c
arch/mips/sni/rm200.c
arch/mips/txx9/Kconfig
arch/mips/vr41xx/common/irq.c
arch/mn10300/kernel/process.c
arch/mn10300/kernel/time.c
arch/parisc/include/asm/spinlock.h
arch/parisc/kernel/process.c
arch/parisc/kernel/time.c
arch/powerpc/Kconfig
arch/powerpc/Kconfig.debug
arch/powerpc/Makefile
arch/powerpc/boot/Makefile
arch/powerpc/boot/cuboot-amigaone.c [new file with mode: 0644]
arch/powerpc/boot/dts/amigaone.dts [new file with mode: 0644]
arch/powerpc/boot/dts/asp834x-redboot.dts
arch/powerpc/boot/dts/canyonlands.dts
arch/powerpc/boot/dts/cm5200.dts
arch/powerpc/boot/dts/digsy_mtc.dts [new file with mode: 0644]
arch/powerpc/boot/dts/gef_ppc9a.dts [new file with mode: 0644]
arch/powerpc/boot/dts/gef_sbc310.dts [new file with mode: 0644]
arch/powerpc/boot/dts/gef_sbc610.dts
arch/powerpc/boot/dts/ksi8560.dts
arch/powerpc/boot/dts/lite5200.dts
arch/powerpc/boot/dts/lite5200b.dts
arch/powerpc/boot/dts/media5200.dts [new file with mode: 0644]
arch/powerpc/boot/dts/motionpro.dts
arch/powerpc/boot/dts/mpc8313erdb.dts
arch/powerpc/boot/dts/mpc8315erdb.dts
arch/powerpc/boot/dts/mpc832x_rdb.dts
arch/powerpc/boot/dts/mpc8349emitx.dts
arch/powerpc/boot/dts/mpc8349emitxgp.dts
arch/powerpc/boot/dts/mpc834x_mds.dts
arch/powerpc/boot/dts/mpc8377_mds.dts
arch/powerpc/boot/dts/mpc8377_rdb.dts
arch/powerpc/boot/dts/mpc8378_mds.dts
arch/powerpc/boot/dts/mpc8378_rdb.dts
arch/powerpc/boot/dts/mpc8379_mds.dts
arch/powerpc/boot/dts/mpc8379_rdb.dts
arch/powerpc/boot/dts/mpc8536ds.dts
arch/powerpc/boot/dts/mpc8540ads.dts
arch/powerpc/boot/dts/mpc8541cds.dts
arch/powerpc/boot/dts/mpc8544ds.dts
arch/powerpc/boot/dts/mpc8548cds.dts
arch/powerpc/boot/dts/mpc8555cds.dts
arch/powerpc/boot/dts/mpc8560ads.dts
arch/powerpc/boot/dts/mpc8568mds.dts
arch/powerpc/boot/dts/mpc8572ds.dts
arch/powerpc/boot/dts/mpc8572ds_36b.dts [new file with mode: 0644]
arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts
arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts
arch/powerpc/boot/dts/mpc8610_hpcd.dts
arch/powerpc/boot/dts/mpc8641_hpcn.dts
arch/powerpc/boot/dts/pcm030.dts
arch/powerpc/boot/dts/pcm032.dts [new file with mode: 0644]
arch/powerpc/boot/dts/redwood.dts [new file with mode: 0644]
arch/powerpc/boot/dts/sbc8349.dts
arch/powerpc/boot/dts/sbc8548.dts
arch/powerpc/boot/dts/sbc8560.dts
arch/powerpc/boot/dts/sbc8641d.dts
arch/powerpc/boot/dts/socrates.dts [new file with mode: 0644]
arch/powerpc/boot/dts/stx_gp3_8560.dts
arch/powerpc/boot/dts/tqm5200.dts
arch/powerpc/boot/dts/tqm8540.dts
arch/powerpc/boot/dts/tqm8541.dts
arch/powerpc/boot/dts/tqm8548-bigflash.dts
arch/powerpc/boot/dts/tqm8548.dts
arch/powerpc/boot/dts/tqm8555.dts
arch/powerpc/boot/dts/tqm8560.dts
arch/powerpc/boot/dts/virtex440-ml507.dts
arch/powerpc/boot/serial.c
arch/powerpc/boot/wrapper
arch/powerpc/configs/44x/canyonlands_defconfig
arch/powerpc/configs/44x/redwood_defconfig [new file with mode: 0644]
arch/powerpc/configs/85xx/socrates_defconfig [new file with mode: 0644]
arch/powerpc/configs/86xx/gef_ppc9a_defconfig [new file with mode: 0644]
arch/powerpc/configs/86xx/gef_sbc310_defconfig [new file with mode: 0644]
arch/powerpc/configs/amigaone_defconfig [new file with mode: 0644]
arch/powerpc/configs/mpc5200_defconfig
arch/powerpc/configs/ppc64_defconfig
arch/powerpc/include/asm/code-patching.h
arch/powerpc/include/asm/cputable.h
arch/powerpc/include/asm/dbell.h [new file with mode: 0644]
arch/powerpc/include/asm/dma-mapping.h
arch/powerpc/include/asm/elf.h
arch/powerpc/include/asm/fixmap.h
arch/powerpc/include/asm/ftrace.h
arch/powerpc/include/asm/highmem.h
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/include/asm/io.h
arch/powerpc/include/asm/lppaca.h
arch/powerpc/include/asm/machdep.h
arch/powerpc/include/asm/mmu-44x.h
arch/powerpc/include/asm/mmu-book3e.h [moved from arch/powerpc/include/asm/mmu-fsl-booke.h with 53% similarity]
arch/powerpc/include/asm/mmu-hash64.h
arch/powerpc/include/asm/mmu.h
arch/powerpc/include/asm/mmu_context.h
arch/powerpc/include/asm/mpc52xx.h
arch/powerpc/include/asm/page.h
arch/powerpc/include/asm/page_32.h
arch/powerpc/include/asm/pci.h
arch/powerpc/include/asm/pgtable-ppc32.h
arch/powerpc/include/asm/pgtable-ppc64-4k.h [moved from arch/powerpc/include/asm/pgtable-4k.h with 57% similarity]
arch/powerpc/include/asm/pgtable-ppc64-64k.h [new file with mode: 0644]
arch/powerpc/include/asm/pgtable-ppc64.h
arch/powerpc/include/asm/pgtable.h
arch/powerpc/include/asm/ppc-opcode.h [new file with mode: 0644]
arch/powerpc/include/asm/ppc_asm.h
arch/powerpc/include/asm/processor.h
arch/powerpc/include/asm/ps3av.h
arch/powerpc/include/asm/ps3fb.h
arch/powerpc/include/asm/pte-40x.h [new file with mode: 0644]
arch/powerpc/include/asm/pte-44x.h [new file with mode: 0644]
arch/powerpc/include/asm/pte-8xx.h [new file with mode: 0644]
arch/powerpc/include/asm/pte-common.h [new file with mode: 0644]
arch/powerpc/include/asm/pte-fsl-booke.h [new file with mode: 0644]
arch/powerpc/include/asm/pte-hash32.h [new file with mode: 0644]
arch/powerpc/include/asm/pte-hash64-4k.h [new file with mode: 0644]
arch/powerpc/include/asm/pte-hash64-64k.h [moved from arch/powerpc/include/asm/pgtable-64k.h with 73% similarity]
arch/powerpc/include/asm/pte-hash64.h [new file with mode: 0644]
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/reg_booke.h
arch/powerpc/include/asm/spinlock.h
arch/powerpc/include/asm/suspend.h
arch/powerpc/include/asm/system.h
arch/powerpc/include/asm/thread_info.h
arch/powerpc/include/asm/topology.h
arch/powerpc/include/asm/udbg.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/align.c
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/cpu_setup_44x.S
arch/powerpc/kernel/cpu_setup_6xx.S
arch/powerpc/kernel/cpu_setup_fsl_booke.S [new file with mode: 0644]
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/crash_dump.c
arch/powerpc/kernel/dbell.c [new file with mode: 0644]
arch/powerpc/kernel/entry_32.S
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/ftrace.c
arch/powerpc/kernel/head_32.S
arch/powerpc/kernel/head_64.S
arch/powerpc/kernel/head_booke.h
arch/powerpc/kernel/head_fsl_booke.S
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/module_64.c
arch/powerpc/kernel/msi.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/pci_32.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/prom_init_check.sh
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/rtas_flash.c
arch/powerpc/kernel/setup-common.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/signal.c
arch/powerpc/kernel/signal.h
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/signal_64.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/kernel/traps.c
arch/powerpc/kernel/udbg.c
arch/powerpc/kernel/udbg_16550.c
arch/powerpc/kernel/vio.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/lib/dma-noncoherent.c
arch/powerpc/lib/feature-fixups.c
arch/powerpc/math-emu/Makefile
arch/powerpc/mm/Makefile
arch/powerpc/mm/fault.c
arch/powerpc/mm/fsl_booke_mmu.c
arch/powerpc/mm/gup.c
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/mmap_64.c [moved from arch/powerpc/mm/mmap.c with 65% similarity]
arch/powerpc/mm/mmu_context_nohash.c
arch/powerpc/mm/numa.c
arch/powerpc/mm/pgtable.c
arch/powerpc/mm/pgtable_32.c
arch/powerpc/mm/pgtable_64.c
arch/powerpc/mm/ppc_mmu_32.c
arch/powerpc/mm/tlb_hash64.c
arch/powerpc/mm/tlb_nohash.c
arch/powerpc/mm/tlb_nohash_low.S
arch/powerpc/oprofile/op_model_7450.c
arch/powerpc/platforms/44x/Kconfig
arch/powerpc/platforms/44x/ppc44x_simple.c
arch/powerpc/platforms/512x/Kconfig
arch/powerpc/platforms/52xx/Kconfig
arch/powerpc/platforms/52xx/Makefile
arch/powerpc/platforms/52xx/media5200.c [new file with mode: 0644]
arch/powerpc/platforms/52xx/mpc5200_simple.c
arch/powerpc/platforms/52xx/mpc52xx_common.c
arch/powerpc/platforms/52xx/mpc52xx_gpio.c
arch/powerpc/platforms/52xx/mpc52xx_gpt.c [new file with mode: 0644]
arch/powerpc/platforms/52xx/mpc52xx_pic.c
arch/powerpc/platforms/82xx/Kconfig
arch/powerpc/platforms/83xx/Kconfig
arch/powerpc/platforms/83xx/asp834x.c
arch/powerpc/platforms/83xx/mpc831x_rdb.c
arch/powerpc/platforms/83xx/mpc832x_rdb.c
arch/powerpc/platforms/83xx/mpc834x_itx.c
arch/powerpc/platforms/83xx/mpc834x_mds.c
arch/powerpc/platforms/83xx/mpc837x_mds.c
arch/powerpc/platforms/83xx/mpc837x_rdb.c
arch/powerpc/platforms/83xx/sbc834x.c
arch/powerpc/platforms/83xx/usb.c
arch/powerpc/platforms/85xx/Kconfig
arch/powerpc/platforms/85xx/Makefile
arch/powerpc/platforms/85xx/ksi8560.c
arch/powerpc/platforms/85xx/mpc8536_ds.c
arch/powerpc/platforms/85xx/mpc85xx_ads.c
arch/powerpc/platforms/85xx/mpc85xx_cds.c
arch/powerpc/platforms/85xx/mpc85xx_ds.c
arch/powerpc/platforms/85xx/mpc85xx_mds.c
arch/powerpc/platforms/85xx/sbc8548.c
arch/powerpc/platforms/85xx/sbc8560.c
arch/powerpc/platforms/85xx/smp.c
arch/powerpc/platforms/85xx/socrates.c [new file with mode: 0644]
arch/powerpc/platforms/85xx/socrates_fpga_pic.c [new file with mode: 0644]
arch/powerpc/platforms/85xx/socrates_fpga_pic.h [new file with mode: 0644]
arch/powerpc/platforms/85xx/stx_gp3.c
arch/powerpc/platforms/85xx/tqm85xx.c
arch/powerpc/platforms/86xx/Kconfig
arch/powerpc/platforms/86xx/Makefile
arch/powerpc/platforms/86xx/gef_gpio.c
arch/powerpc/platforms/86xx/gef_ppc9a.c [new file with mode: 0644]
arch/powerpc/platforms/86xx/gef_sbc310.c [new file with mode: 0644]
arch/powerpc/platforms/86xx/gef_sbc610.c
arch/powerpc/platforms/86xx/mpc8610_hpcd.c
arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
arch/powerpc/platforms/86xx/sbc8641d.c
arch/powerpc/platforms/8xx/m8xx_setup.c
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/Makefile
arch/powerpc/platforms/amigaone/Kconfig [new file with mode: 0644]
arch/powerpc/platforms/amigaone/Makefile [new file with mode: 0644]
arch/powerpc/platforms/amigaone/setup.c [new file with mode: 0644]
arch/powerpc/platforms/cell/Kconfig
arch/powerpc/platforms/cell/Makefile
arch/powerpc/platforms/cell/io-workarounds.c
arch/powerpc/platforms/cell/iommu.c
arch/powerpc/platforms/cell/qpace_setup.c
arch/powerpc/platforms/cell/spu_base.c
arch/powerpc/platforms/cell/spu_fault.c
arch/powerpc/platforms/cell/spufs/context.c
arch/powerpc/platforms/cell/spufs/file.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/cell/spufs/run.c
arch/powerpc/platforms/cell/spufs/spufs.h
arch/powerpc/platforms/chrp/Kconfig
arch/powerpc/platforms/chrp/pegasos_eth.c
arch/powerpc/platforms/chrp/setup.c
arch/powerpc/platforms/embedded6xx/Kconfig
arch/powerpc/platforms/iseries/Kconfig
arch/powerpc/platforms/iseries/irq.c
arch/powerpc/platforms/iseries/setup.c
arch/powerpc/platforms/maple/Kconfig
arch/powerpc/platforms/pasemi/Kconfig
arch/powerpc/platforms/powermac/Kconfig
arch/powerpc/platforms/powermac/cpufreq_64.c
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/platforms/powermac/pic.h
arch/powerpc/platforms/powermac/setup.c
arch/powerpc/platforms/powermac/smp.c
arch/powerpc/platforms/prep/Kconfig
arch/powerpc/platforms/ps3/Kconfig
arch/powerpc/platforms/ps3/mm.c
arch/powerpc/platforms/pseries/Kconfig
arch/powerpc/platforms/pseries/Makefile
arch/powerpc/platforms/pseries/dtl.c [new file with mode: 0644]
arch/powerpc/platforms/pseries/eeh_driver.c
arch/powerpc/platforms/pseries/msi.c
arch/powerpc/platforms/pseries/pci_dlpar.c
arch/powerpc/platforms/pseries/plpar_wrappers.h
arch/powerpc/platforms/pseries/reconfig.c
arch/powerpc/sysdev/cpm1.c
arch/powerpc/sysdev/cpm2.c
arch/powerpc/sysdev/cpm_common.c
arch/powerpc/sysdev/fsl_pci.c
arch/powerpc/sysdev/fsl_soc.c
arch/powerpc/sysdev/fsl_soc.h
arch/powerpc/sysdev/ipic.c
arch/powerpc/sysdev/msi_bitmap.c
arch/powerpc/sysdev/pmi.c
arch/powerpc/sysdev/ppc4xx_pci.c
arch/s390/Kconfig
arch/s390/Kconfig.debug
arch/s390/hypfs/hypfs_diag.c
arch/s390/include/asm/cio.h
arch/s390/include/asm/spinlock.h
arch/s390/kernel/process.c
arch/sh/boards/board-ap325rxa.c
arch/sh/boards/mach-migor/setup.c
arch/sh/include/asm/spinlock.h
arch/sh/include/asm/topology.h
arch/sh/kernel/process_32.c
arch/sh/kernel/process_64.c
arch/sh/kernel/time_64.c
arch/sh/kernel/timers/timer-cmt.c
arch/sh/kernel/timers/timer-mtu2.c
arch/sh/kernel/timers/timer-tmu.c
arch/sparc/Kconfig
arch/sparc/Kconfig.debug
arch/sparc/include/asm/mmu_context_64.h
arch/sparc/include/asm/smp_64.h
arch/sparc/include/asm/spinlock_32.h
arch/sparc/include/asm/spinlock_64.h
arch/sparc/include/asm/system_32.h
arch/sparc/include/asm/topology_64.h
arch/sparc/kernel/ds.c
arch/sparc/kernel/irq_32.c
arch/sparc/kernel/irq_64.c
arch/sparc/kernel/led.c
arch/sparc/kernel/mdesc.c
arch/sparc/kernel/nmi.c
arch/sparc/kernel/process_32.c
arch/sparc/kernel/process_64.c
arch/sparc/kernel/prom_64.c
arch/sparc/kernel/smp_32.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/sun4d_irq.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc/mm/highmem.c
arch/sparc/mm/init_64.c
arch/sparc/mm/srmmu.c
arch/um/drivers/net_kern.c
arch/um/drivers/pcap_user.h
arch/um/drivers/port.h
arch/um/drivers/ssl.h
arch/um/drivers/stdio_console.h
arch/um/drivers/ubd_kern.c
arch/um/drivers/xterm.h
arch/um/include/asm/irq_vectors.h
arch/um/include/asm/mmu.h
arch/um/include/asm/pda.h
arch/um/include/asm/pgalloc.h
arch/um/include/asm/pgtable-3level.h
arch/um/include/shared/frame_kern.h
arch/um/include/shared/initrd.h
arch/um/include/shared/irq_kern.h
arch/um/include/shared/mem_kern.h
arch/um/include/shared/ubd_user.h
arch/um/kernel/Makefile
arch/um/kernel/config.c.in
arch/um/kernel/process.c
arch/um/kernel/syscall.c
arch/um/os-Linux/start_up.c
arch/um/sys-i386/asm/archparam.h
arch/um/sys-i386/shared/sysdep/checksum.h
arch/um/sys-i386/sys_call_table.S
arch/um/sys-ia64/sysdep/ptrace.h
arch/um/sys-ia64/sysdep/sigcontext.h
arch/um/sys-ia64/sysdep/syscalls.h
arch/um/sys-ppc/miscthings.c
arch/um/sys-ppc/ptrace.c
arch/um/sys-ppc/ptrace_user.c
arch/um/sys-ppc/shared/sysdep/ptrace.h
arch/um/sys-ppc/shared/sysdep/sigcontext.h
arch/um/sys-ppc/shared/sysdep/syscalls.h
arch/um/sys-ppc/sigcontext.c
arch/um/sys-x86_64/asm/archparam.h
arch/um/sys-x86_64/asm/module.h
arch/um/sys-x86_64/mem.c
arch/x86/Kconfig
arch/x86/Kconfig.cpu
arch/x86/Kconfig.debug
arch/x86/Makefile
arch/x86/boot/Makefile
arch/x86/boot/header.S
arch/x86/boot/memory.c
arch/x86/boot/pm.c
arch/x86/boot/pmjump.S
arch/x86/boot/setup.ld
arch/x86/boot/tools/build.c
arch/x86/boot/video-vga.c
arch/x86/ia32/ia32entry.S
arch/x86/include/asm/apic.h
arch/x86/include/asm/apicdef.h
arch/x86/include/asm/boot.h
arch/x86/include/asm/cacheflush.h
arch/x86/include/asm/cpu_debug.h [new file with mode: 0755]
arch/x86/include/asm/desc.h
arch/x86/include/asm/device.h
arch/x86/include/asm/dma-mapping.h
arch/x86/include/asm/dmi.h
arch/x86/include/asm/e820.h
arch/x86/include/asm/entry_arch.h
arch/x86/include/asm/ftrace.h
arch/x86/include/asm/hardirq.h
arch/x86/include/asm/highmem.h
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/init.h [new file with mode: 0644]
arch/x86/include/asm/io_apic.h
arch/x86/include/asm/iommu.h
arch/x86/include/asm/irq.h
arch/x86/include/asm/irq_remapping.h
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/kexec.h
arch/x86/include/asm/lguest_hcall.h
arch/x86/include/asm/linkage.h
arch/x86/include/asm/mce.h
arch/x86/include/asm/msidef.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/page_32_types.h
arch/x86/include/asm/page_types.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/pat.h
arch/x86/include/asm/pci.h
arch/x86/include/asm/pgtable-2level.h
arch/x86/include/asm/pgtable-3level.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/pgtable_32.h
arch/x86/include/asm/pgtable_32_types.h
arch/x86/include/asm/pgtable_types.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/sections.h
arch/x86/include/asm/setup.h
arch/x86/include/asm/spinlock.h
arch/x86/include/asm/suspend_32.h
arch/x86/include/asm/timer.h
arch/x86/include/asm/topology.h
arch/x86/include/asm/unistd_32.h
arch/x86/include/asm/unistd_64.h
arch/x86/include/asm/uv/uv_hub.h
arch/x86/include/asm/uv/uv_mmrs.h
arch/x86/include/asm/xen/hypercall.h
arch/x86/kernel/Makefile
arch/x86/kernel/alternative.c
arch/x86/kernel/amd_iommu.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/apic_flat_64.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/probe_64.c
arch/x86/kernel/apic/x2apic_cluster.c
arch/x86/kernel/apic/x2apic_phys.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/apm_32.c
arch/x86/kernel/asm-offsets_32.c
arch/x86/kernel/asm-offsets_64.c
arch/x86/kernel/check.c
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/addon_cpuid_features.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/centaur.c
arch/x86/kernel/cpu/centaur_64.c [deleted file]
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpu.h
arch/x86/kernel/cpu/cpu_debug.c [new file with mode: 0755]
arch/x86/kernel/cpu/cyrix.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/Makefile
arch/x86/kernel/cpu/mcheck/mce_32.c
arch/x86/kernel/cpu/mcheck/mce_64.c
arch/x86/kernel/cpu/mcheck/mce_amd_64.c
arch/x86/kernel/cpu/mcheck/mce_intel_64.c
arch/x86/kernel/cpu/mcheck/threshold.c [new file with mode: 0644]
arch/x86/kernel/cpu/mtrr/Makefile
arch/x86/kernel/cpu/mtrr/cleanup.c [new file with mode: 0644]
arch/x86/kernel/cpu/mtrr/generic.c
arch/x86/kernel/cpu/mtrr/if.c
arch/x86/kernel/cpu/mtrr/main.c
arch/x86/kernel/cpu/mtrr/mtrr.h
arch/x86/kernel/cpu/transmeta.c
arch/x86/kernel/cpu/umc.c
arch/x86/kernel/dumpstack.c
arch/x86/kernel/e820.c
arch/x86/kernel/early_printk.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/ftrace.c
arch/x86/kernel/head32.c
arch/x86/kernel/head64.c
arch/x86/kernel/head_32.S
arch/x86/kernel/i8253.c
arch/x86/kernel/io_delay.c
arch/x86/kernel/irq.c
arch/x86/kernel/irqinit_32.c
arch/x86/kernel/irqinit_64.c
arch/x86/kernel/kdebugfs.c
arch/x86/kernel/kprobes.c
arch/x86/kernel/kvm.c
arch/x86/kernel/machine_kexec_32.c
arch/x86/kernel/machine_kexec_64.c
arch/x86/kernel/mfgpt_32.c
arch/x86/kernel/mmconf-fam10h_64.c
arch/x86/kernel/mpparse.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/pci-calgary_64.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/pci-gart_64.c
arch/x86/kernel/pci-nommu.c
arch/x86/kernel/pci-swiotlb.c [moved from arch/x86/kernel/pci-swiotlb_64.c with 81% similarity]
arch/x86/kernel/process.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/quirks.c
arch/x86/kernel/relocate_kernel_32.S
arch/x86/kernel/relocate_kernel_64.S
arch/x86/kernel/rtc.c
arch/x86/kernel/setup.c
arch/x86/kernel/signal.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/syscall_table_32.S
arch/x86/kernel/time_64.c
arch/x86/kernel/tlb_uv.c
arch/x86/kernel/topology.c
arch/x86/kernel/uv_time.c [new file with mode: 0644]
arch/x86/kernel/visws_quirks.c
arch/x86/kernel/vmi_32.c
arch/x86/kernel/vmiclock_32.c
arch/x86/kernel/vmlinux_32.lds.S
arch/x86/kernel/vmlinux_64.lds.S
arch/x86/kernel/vsmp_64.c
arch/x86/lguest/boot.c
arch/x86/lguest/i386_head.S
arch/x86/lib/memcpy_64.S
arch/x86/mm/highmem_32.c
arch/x86/mm/init.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/iomap_32.c
arch/x86/mm/ioremap.c
arch/x86/mm/kmmio.c
arch/x86/mm/memtest.c
arch/x86/mm/numa_32.c
arch/x86/mm/pageattr.c
arch/x86/mm/pat.c
arch/x86/mm/pgtable_32.c
arch/x86/mm/tlb.c
arch/x86/pci/common.c
arch/x86/pci/early.c
arch/x86/pci/fixup.c
arch/x86/pci/i386.c
arch/x86/pci/legacy.c
arch/x86/pci/mmconfig-shared.c
arch/x86/pci/mmconfig_64.c
arch/x86/power/cpu_32.c
arch/x86/power/cpu_64.c
arch/x86/power/hibernate_64.c
arch/x86/xen/mmu.c
arch/xtensa/kernel/process.c
arch/xtensa/platforms/iss/console.c
drivers/acpi/ac.c
drivers/acpi/battery.c
drivers/acpi/button.c
drivers/acpi/fan.c
drivers/acpi/pci_root.c
drivers/acpi/processor_core.c
drivers/acpi/sbs.c
drivers/acpi/thermal.c
drivers/acpi/video.c
drivers/auxdisplay/Kconfig
drivers/base/cpu.c
drivers/base/iommu.c
drivers/base/power/main.c
drivers/base/sys.c
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/nbd.c
drivers/block/ps3vram.c
drivers/char/amiserial.c
drivers/char/cyclades.c
drivers/char/hpet.c
drivers/char/ip2/ip2main.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/istallion.c
drivers/char/pcmcia/synclink_cs.c
drivers/char/random.c
drivers/char/raw.c
drivers/char/stallion.c
drivers/char/synclink.c
drivers/char/synclink_gt.c
drivers/char/synclinkmp.c
drivers/char/sysrq.c
drivers/char/tty_io.c
drivers/crypto/hifn_795x.c
drivers/edac/Kconfig
drivers/edac/Makefile
drivers/edac/amd8111_edac.c [new file with mode: 0644]
drivers/edac/amd8111_edac.h [new file with mode: 0644]
drivers/edac/amd8131_edac.c [new file with mode: 0644]
drivers/edac/amd8131_edac.h [new file with mode: 0644]
drivers/edac/edac_core.h
drivers/edac/edac_pci.c
drivers/edac/ppc4xx_edac.c [new file with mode: 0644]
drivers/edac/ppc4xx_edac.h [new file with mode: 0644]
drivers/firmware/dmi_scan.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/ati_pcigart.c
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_context.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_info.c
drivers/gpu/drm/drm_ioc32.c
drivers/gpu/drm/drm_memory.c
drivers/gpu/drm/drm_proc.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/drm_sysfs.c
drivers/gpu/drm/drm_vm.c
drivers/gpu/drm/i810/i810_drv.h
drivers/gpu/drm/i830/i830_drv.h
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/mga/mga_dma.c
drivers/gpu/drm/mga/mga_drv.h
drivers/gpu/drm/r128/r128_cce.c
drivers/gpu/drm/radeon/Makefile
drivers/gpu/drm/radeon/r300_cmdbuf.c
drivers/gpu/drm/radeon/r300_reg.h
drivers/gpu/drm/radeon/r600_cp.c [new file with mode: 0644]
drivers/gpu/drm/radeon/r600_microcode.h [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_cp.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_drv.h
drivers/gpu/drm/radeon/radeon_irq.c
drivers/gpu/drm/radeon/radeon_state.c
drivers/gpu/drm/savage/savage_bci.c
drivers/gpu/drm/via/via_drv.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/ds1621.c
drivers/hwmon/fschmd.c
drivers/hwmon/hdaps.c
drivers/hwmon/hp_accel.c
drivers/hwmon/lis3lv02d.c
drivers/hwmon/lis3lv02d.h
drivers/hwmon/lis3lv02d_spi.c [new file with mode: 0644]
drivers/hwmon/lm95241.c [new file with mode: 0644]
drivers/hwmon/ltc4215.c [new file with mode: 0644]
drivers/hwmon/pcf8591.c [moved from drivers/i2c/chips/pcf8591.c with 96% similarity]
drivers/hwmon/w83627ehf.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/chips/Kconfig
drivers/i2c/chips/Makefile
drivers/ide/Kconfig
drivers/ide/Makefile
drivers/ide/alim15x3.c
drivers/ide/at91_ide.c
drivers/ide/au1xxx-ide.c
drivers/ide/buddha.c
drivers/ide/cmd64x.c
drivers/ide/cs5530.c
drivers/ide/cs5536.c
drivers/ide/delkin_cb.c
drivers/ide/dtc2278.c
drivers/ide/falconide.c
drivers/ide/gayle.c
drivers/ide/hpt366.c
drivers/ide/ht6560b.c
drivers/ide/icside.c
drivers/ide/ide-4drives.c
drivers/ide/ide-acpi.c
drivers/ide/ide-atapi.c
drivers/ide/ide-cd.c
drivers/ide/ide-cd.h
drivers/ide/ide-cs.c
drivers/ide/ide-devsets.c
drivers/ide/ide-disk.c
drivers/ide/ide-disk_proc.c
drivers/ide/ide-dma-sff.c
drivers/ide/ide-dma.c
drivers/ide/ide-eh.c
drivers/ide/ide-floppy.c
drivers/ide/ide-floppy_ioctl.c
drivers/ide/ide-gd.c
drivers/ide/ide-gd.h
drivers/ide/ide-generic.c
drivers/ide/ide-h8300.c
drivers/ide/ide-io-std.c
drivers/ide/ide-io.c
drivers/ide/ide-ioctls.c
drivers/ide/ide-iops.c
drivers/ide/ide-lib.c
drivers/ide/ide-park.c
drivers/ide/ide-pm.c
drivers/ide/ide-pnp.c
drivers/ide/ide-probe.c
drivers/ide/ide-proc.c
drivers/ide/ide-tape.c
drivers/ide/ide-taskfile.c
drivers/ide/ide-timings.c
drivers/ide/ide-xfer-mode.c
drivers/ide/ide_arm.c [deleted file]
drivers/ide/it821x.c
drivers/ide/macide.c
drivers/ide/ns87415.c
drivers/ide/palm_bk3710.c
drivers/ide/pdc202xx_old.c
drivers/ide/pmac.c
drivers/ide/q40ide.c
drivers/ide/qd65xx.c
drivers/ide/sc1200.c
drivers/ide/scc_pata.c
drivers/ide/setup-pci.c
drivers/ide/sgiioc4.c
drivers/ide/siimage.c
drivers/ide/sl82c105.c
drivers/ide/tc86c001.c
drivers/ide/trm290.c
drivers/ide/tx4938ide.c
drivers/ide/tx4939ide.c
drivers/input/input.c
drivers/input/mouse/hgpk.c
drivers/isdn/capi/capi.c
drivers/isdn/hardware/eicon/divasi.c
drivers/lguest/core.c
drivers/lguest/interrupts_and_traps.c
drivers/lguest/lg.h
drivers/lguest/lguest_device.c
drivers/lguest/page_tables.c
drivers/lguest/segments.c
drivers/lguest/x86/core.c
drivers/macintosh/therm_adt746x.c
drivers/media/Kconfig
drivers/media/common/ir-keymaps.c
drivers/media/common/saa7146_core.c
drivers/media/common/saa7146_fops.c
drivers/media/common/saa7146_i2c.c
drivers/media/common/saa7146_video.c
drivers/media/common/tuners/Kconfig
drivers/media/common/tuners/Makefile
drivers/media/common/tuners/mc44s803.c [new file with mode: 0644]
drivers/media/common/tuners/mc44s803.h [new file with mode: 0644]
drivers/media/common/tuners/mc44s803_priv.h [new file with mode: 0644]
drivers/media/common/tuners/mt2060.c
drivers/media/common/tuners/mt20xx.c
drivers/media/common/tuners/mxl5005s.c
drivers/media/common/tuners/mxl5007t.c
drivers/media/common/tuners/tda18271-common.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/tda827x.c
drivers/media/common/tuners/tda8290.c
drivers/media/common/tuners/tea5761.c
drivers/media/common/tuners/tea5767.c
drivers/media/common/tuners/xc5000.c
drivers/media/dvb/b2c2/Kconfig
drivers/media/dvb/b2c2/Makefile
drivers/media/dvb/b2c2/flexcop-common.h
drivers/media/dvb/b2c2/flexcop-dma.c
drivers/media/dvb/b2c2/flexcop-eeprom.c
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
drivers/media/dvb/b2c2/flexcop-hw-filter.c
drivers/media/dvb/b2c2/flexcop-i2c.c
drivers/media/dvb/b2c2/flexcop-misc.c
drivers/media/dvb/b2c2/flexcop-pci.c
drivers/media/dvb/b2c2/flexcop-reg.h
drivers/media/dvb/b2c2/flexcop-sram.c
drivers/media/dvb/b2c2/flexcop-usb.c
drivers/media/dvb/b2c2/flexcop-usb.h
drivers/media/dvb/b2c2/flexcop.c
drivers/media/dvb/b2c2/flexcop.h
drivers/media/dvb/b2c2/flexcop_ibi_value_be.h
drivers/media/dvb/b2c2/flexcop_ibi_value_le.h
drivers/media/dvb/bt8xx/Kconfig
drivers/media/dvb/bt8xx/dst_ca.c
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/dm1105/Kconfig
drivers/media/dvb/dm1105/dm1105.c
drivers/media/dvb/dvb-core/dmxdev.c
drivers/media/dvb/dvb-core/dvb_ca_en50221.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_net.c
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-core/dvbdev.h
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/Makefile
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/af9015.h
drivers/media/dvb/dvb-usb/ce6230.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/ce6230.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dib0700_core.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb.h
drivers/media/dvb/firewire/firedtv-avc.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/au8522.h
drivers/media/dvb/frontends/au8522_decoder.c [new file with mode: 0644]
drivers/media/dvb/frontends/au8522_dig.c [moved from drivers/media/dvb/frontends/au8522.c with 91% similarity]
drivers/media/dvb/frontends/au8522_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/cx24113.c
drivers/media/dvb/frontends/cx24116.c
drivers/media/dvb/frontends/cx24123.c
drivers/media/dvb/frontends/dib0070.h
drivers/media/dvb/frontends/dib3000mc.h
drivers/media/dvb/frontends/dib7000m.h
drivers/media/dvb/frontends/dib7000p.h
drivers/media/dvb/frontends/dvb_dummy_fe.h
drivers/media/dvb/frontends/itd1000_priv.h
drivers/media/dvb/frontends/lgdt3304.c
drivers/media/dvb/frontends/lgdt3305.c [new file with mode: 0644]
drivers/media/dvb/frontends/lgdt3305.h [new file with mode: 0644]
drivers/media/dvb/frontends/lnbh24.h [new file with mode: 0644]
drivers/media/dvb/frontends/lnbp21.c
drivers/media/dvb/frontends/lnbp21.h
drivers/media/dvb/frontends/s921_module.c
drivers/media/dvb/frontends/stb6100_cfg.h
drivers/media/dvb/frontends/stv0900.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv0900_core.c [new file with mode: 0644]
drivers/media/dvb/frontends/stv0900_init.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv0900_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv0900_reg.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv0900_sw.c [new file with mode: 0644]
drivers/media/dvb/frontends/stv6110.c [new file with mode: 0644]
drivers/media/dvb/frontends/stv6110.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda1004x.c
drivers/media/dvb/frontends/zl10036.c [new file with mode: 0644]
drivers/media/dvb/frontends/zl10036.h [new file with mode: 0644]
drivers/media/dvb/frontends/zl10353.c
drivers/media/dvb/frontends/zl10353.h
drivers/media/dvb/frontends/zl10353_priv.h
drivers/media/dvb/pluto2/pluto2.c
drivers/media/dvb/siano/Makefile
drivers/media/dvb/siano/sms-cards.c
drivers/media/dvb/siano/sms-cards.h
drivers/media/dvb/siano/smscoreapi.c
drivers/media/dvb/siano/smscoreapi.h
drivers/media/dvb/siano/smsdvb.c
drivers/media/dvb/siano/smsusb.c
drivers/media/dvb/ttpci/Kconfig
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/av7110_av.c
drivers/media/dvb/ttpci/av7110_ca.c
drivers/media/dvb/ttpci/av7110_v4l.c
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/radio/dsbr100.c
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-gemtek-pci.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-maestro.c
drivers/media/radio/radio-maxiradio.c
drivers/media/radio/radio-mr800.c
drivers/media/radio/radio-rtrack2.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-si470x.c
drivers/media/radio/radio-terratec.c
drivers/media/radio/radio-trust.c
drivers/media/radio/radio-typhoon.c
drivers/media/radio/radio-zoltrix.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adv7170.c
drivers/media/video/adv7175.c
drivers/media/video/au0828/Kconfig
drivers/media/video/au0828/Makefile
drivers/media/video/au0828/au0828-cards.c
drivers/media/video/au0828/au0828-core.c
drivers/media/video/au0828/au0828-dvb.c
drivers/media/video/au0828/au0828-i2c.c
drivers/media/video/au0828/au0828-reg.h
drivers/media/video/au0828/au0828-video.c [new file with mode: 0644]
drivers/media/video/au0828/au0828.h
drivers/media/video/bt819.c
drivers/media/video/bt856.c
drivers/media/video/bt866.c
drivers/media/video/bt8xx/Kconfig
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-if.c
drivers/media/video/bt8xx/bttv-risc.c
drivers/media/video/bt8xx/bttv-vbi.c
drivers/media/video/bt8xx/bttv.h
drivers/media/video/bt8xx/bttvp.h
drivers/media/video/cafe_ccic.c
drivers/media/video/cpia.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cs5345.c
drivers/media/video/cs53l32a.c
drivers/media/video/cx18/Kconfig
drivers/media/video/cx18/cx18-audio.c
drivers/media/video/cx18/cx18-audio.h
drivers/media/video/cx18/cx18-av-audio.c
drivers/media/video/cx18/cx18-av-core.c
drivers/media/video/cx18/cx18-av-core.h
drivers/media/video/cx18/cx18-av-firmware.c
drivers/media/video/cx18/cx18-av-vbi.c
drivers/media/video/cx18/cx18-cards.c
drivers/media/video/cx18/cx18-cards.h
drivers/media/video/cx18/cx18-controls.c
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-dvb.c
drivers/media/video/cx18/cx18-fileops.c
drivers/media/video/cx18/cx18-firmware.c
drivers/media/video/cx18/cx18-gpio.c
drivers/media/video/cx18/cx18-gpio.h
drivers/media/video/cx18/cx18-i2c.c
drivers/media/video/cx18/cx18-i2c.h
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx18/cx18-mailbox.c
drivers/media/video/cx18/cx18-queue.c
drivers/media/video/cx18/cx18-queue.h
drivers/media/video/cx18/cx18-streams.c
drivers/media/video/cx18/cx18-vbi.c
drivers/media/video/cx18/cx18-vbi.h
drivers/media/video/cx18/cx18-version.h
drivers/media/video/cx18/cx18-video.c
drivers/media/video/cx18/cx23418.h
drivers/media/video/cx2341x.c
drivers/media/video/cx23885/Kconfig
drivers/media/video/cx23885/Makefile
drivers/media/video/cx23885/cimax2.c [new file with mode: 0644]
drivers/media/video/cx23885/cimax2.h [new file with mode: 0644]
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-reg.h
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx23885/netup-eeprom.c [new file with mode: 0644]
drivers/media/video/cx23885/netup-eeprom.h [new file with mode: 0644]
drivers/media/video/cx23885/netup-init.c [new file with mode: 0644]
drivers/media/video/cx23885/netup-init.h [new file with mode: 0644]
drivers/media/video/cx25840/cx25840-audio.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx25840/cx25840-core.h
drivers/media/video/cx25840/cx25840-vbi.c
drivers/media/video/cx88/Kconfig
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-i2c.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/dabusb.c
drivers/media/video/em28xx/em28xx-audio.c
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-input.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/finepix.c
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/jpeg.h
drivers/media/video/gspca/m5602/m5602_core.c
drivers/media/video/gspca/mars.c
drivers/media/video/gspca/mr97310a.c [new file with mode: 0644]
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/ov534.c
drivers/media/video/gspca/pac207.c
drivers/media/video/gspca/pac7311.c
drivers/media/video/gspca/sonixb.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/spca500.c
drivers/media/video/gspca/spca501.c
drivers/media/video/gspca/spca505.c
drivers/media/video/gspca/spca506.c
drivers/media/video/gspca/spca508.c
drivers/media/video/gspca/spca561.c
drivers/media/video/gspca/sq905.c [new file with mode: 0644]
drivers/media/video/gspca/sq905c.c [new file with mode: 0644]
drivers/media/video/gspca/stk014.c
drivers/media/video/gspca/stv06xx/stv06xx.c
drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
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/Kconfig [new file with mode: 0644]
drivers/media/video/hdpvr/Makefile [new file with mode: 0644]
drivers/media/video/hdpvr/hdpvr-control.c [new file with mode: 0644]
drivers/media/video/hdpvr/hdpvr-core.c [new file with mode: 0644]
drivers/media/video/hdpvr/hdpvr-i2c.c [new file with mode: 0644]
drivers/media/video/hdpvr/hdpvr-video.c [new file with mode: 0644]
drivers/media/video/hdpvr/hdpvr.h [new file with mode: 0644]
drivers/media/video/hexium_gemini.c
drivers/media/video/hexium_orion.c
drivers/media/video/indycam.c
drivers/media/video/indycam.h
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-controls.c
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-firmware.c
drivers/media/video/ivtv/ivtv-gpio.c
drivers/media/video/ivtv/ivtv-i2c.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-irq.c
drivers/media/video/ivtv/ivtv-queue.c
drivers/media/video/ivtv/ivtv-queue.h
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/ivtv/ivtv-udma.c
drivers/media/video/ivtv/ivtv-udma.h
drivers/media/video/ivtv/ivtv-vbi.c
drivers/media/video/ivtv/ivtv-version.h
drivers/media/video/ivtv/ivtv-yuv.c
drivers/media/video/ivtv/ivtvfb.c
drivers/media/video/ks0127.c
drivers/media/video/ks0127.h
drivers/media/video/m52790.c
drivers/media/video/meye.c
drivers/media/video/msp3400-driver.c
drivers/media/video/mt9m001.c
drivers/media/video/mt9m111.c
drivers/media/video/mt9t031.c
drivers/media/video/mt9v022.c
drivers/media/video/mx3_camera.c [new file with mode: 0644]
drivers/media/video/mxb.c
drivers/media/video/omap24xxcam.c
drivers/media/video/ov7670.c
drivers/media/video/ov772x.c
drivers/media/video/ovcamchip/ovcamchip_core.c
drivers/media/video/ovcamchip/ovcamchip_priv.h
drivers/media/video/pvrusb2/Kconfig
drivers/media/video/pvrusb2/Makefile
drivers/media/video/pvrusb2/pvrusb2-audio.c
drivers/media/video/pvrusb2/pvrusb2-audio.h
drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-cs53l32a.h [moved from drivers/media/video/pvrusb2/pvrusb2-tuner.h with 64% similarity]
drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
drivers/media/video/pvrusb2/pvrusb2-debugifc.c
drivers/media/video/pvrusb2/pvrusb2-debugifc.h
drivers/media/video/pvrusb2/pvrusb2-devattr.c
drivers/media/video/pvrusb2/pvrusb2-devattr.h
drivers/media/video/pvrusb2/pvrusb2-dvb.c
drivers/media/video/pvrusb2/pvrusb2-encoder.c
drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-hdw.h
drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c [deleted file]
drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c [deleted file]
drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h [deleted file]
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
drivers/media/video/pvrusb2/pvrusb2-main.c
drivers/media/video/pvrusb2/pvrusb2-sysfs.c
drivers/media/video/pvrusb2/pvrusb2-tuner.c [deleted file]
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
drivers/media/video/pvrusb2/pvrusb2-wm8775.c
drivers/media/video/pvrusb2/pvrusb2-wm8775.h
drivers/media/video/pwc/Kconfig
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc.h
drivers/media/video/pxa_camera.c
drivers/media/video/s2255drv.c
drivers/media/video/saa5246a.c
drivers/media/video/saa5249.c
drivers/media/video/saa6588.c
drivers/media/video/saa7110.c
drivers/media/video/saa7111.c [deleted file]
drivers/media/video/saa7114.c [deleted file]
drivers/media/video/saa7115.c
drivers/media/video/saa7127.c
drivers/media/video/saa7134/Kconfig
drivers/media/video/saa7134/saa6752hs.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-empress.c
drivers/media/video/saa7134/saa7134-i2c.c
drivers/media/video/saa7134/saa7134-ts.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/saa7146.h
drivers/media/video/saa717x.c
drivers/media/video/saa7185.c
drivers/media/video/saa7191.c
drivers/media/video/saa7191.h
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/sn9c102/sn9c102_devtable.h
drivers/media/video/soc_camera.c
drivers/media/video/soc_camera_platform.c
drivers/media/video/stk-webcam.c
drivers/media/video/tcm825x.c
drivers/media/video/tcm825x.h
drivers/media/video/tda7432.c
drivers/media/video/tda9840.c
drivers/media/video/tda9840.h [deleted file]
drivers/media/video/tda9875.c
drivers/media/video/tea6415c.c
drivers/media/video/tea6415c.h
drivers/media/video/tea6420.c
drivers/media/video/tea6420.h
drivers/media/video/tlv320aic23b.c
drivers/media/video/tuner-core.c
drivers/media/video/tvaudio.c
drivers/media/video/tveeprom.c
drivers/media/video/tvp514x.c
drivers/media/video/tvp5150.c
drivers/media/video/tw9910.c
drivers/media/video/upd64031a.c
drivers/media/video/upd64083.c
drivers/media/video/usbvideo/vicam.c
drivers/media/video/usbvision/usbvision-core.c
drivers/media/video/usbvision/usbvision-i2c.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/usbvision/usbvision.h
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvc_status.c
drivers/media/video/uvc/uvc_v4l2.c
drivers/media/video/uvc/uvc_video.c
drivers/media/video/uvc/uvcvideo.h
drivers/media/video/v4l2-common.c
drivers/media/video/v4l2-compat-ioctl32.c
drivers/media/video/v4l2-dev.c
drivers/media/video/v4l2-device.c
drivers/media/video/v4l2-ioctl.c
drivers/media/video/v4l2-subdev.c
drivers/media/video/videobuf-dma-contig.c
drivers/media/video/videobuf-vmalloc.c
drivers/media/video/vino.c
drivers/media/video/vivi.c
drivers/media/video/vp27smpx.c
drivers/media/video/vpx3220.c
drivers/media/video/w9966.c
drivers/media/video/w9968cf.c
drivers/media/video/w9968cf.h
drivers/media/video/wm8739.c
drivers/media/video/wm8775.c
drivers/media/video/zc0301/zc0301_sensor.h
drivers/media/video/zoran/Kconfig
drivers/media/video/zoran/videocodec.h
drivers/media/video/zoran/zoran.h
drivers/media/video/zoran/zoran_card.c
drivers/media/video/zoran/zoran_card.h
drivers/media/video/zoran/zoran_device.c
drivers/media/video/zoran/zoran_device.h
drivers/media/video/zoran/zoran_driver.c
drivers/media/video/zoran/zoran_procfs.c
drivers/media/video/zoran/zr36016.c
drivers/media/video/zoran/zr36050.c
drivers/media/video/zoran/zr36060.c
drivers/media/video/zr364xx.c
drivers/message/i2o/i2o_proc.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/eeprom/at24.c
drivers/misc/eeprom/at25.c
drivers/misc/hpilo.c
drivers/misc/hpilo.h
drivers/misc/isl29003.c [new file with mode: 0644]
drivers/misc/sgi-gru/Makefile
drivers/misc/sgi-gru/gru_instructions.h
drivers/misc/sgi-gru/grufault.c
drivers/misc/sgi-gru/grufile.c
drivers/misc/sgi-gru/gruhandles.c [new file with mode: 0644]
drivers/misc/sgi-gru/gruhandles.h
drivers/misc/sgi-gru/grukservices.c
drivers/misc/sgi-gru/grukservices.h
drivers/misc/sgi-gru/grumain.c
drivers/misc/sgi-gru/gruprocfs.c
drivers/misc/sgi-gru/grutables.h
drivers/misc/sgi-gru/grutlbpurge.c
drivers/misc/sgi-xp/xpc.h
drivers/misc/sgi-xp/xpc_channel.c
drivers/misc/sgi-xp/xpc_main.c
drivers/misc/sgi-xp/xpc_sn2.c
drivers/misc/sgi-xp/xpc_uv.c
drivers/mmc/card/sdio_uart.c
drivers/net/bonding/bond_main.c
drivers/net/dm9000.c
drivers/net/fec_mpc52xx.c
drivers/net/irda/vlsi_ir.c
drivers/net/meth.c
drivers/net/mlx4/en_netdev.c
drivers/net/mlx4/en_rx.c
drivers/net/mlx4/sense.c
drivers/net/phy/phy.c
drivers/net/smc91x.h
drivers/net/wireless/airo.c
drivers/of/base.c
drivers/oprofile/buffer_sync.c
drivers/parport/parport_serial.c
drivers/pci/Kconfig
drivers/pci/Makefile
drivers/pci/bus.c
drivers/pci/dmar.c
drivers/pci/hotplug/acpi_pcihp.c
drivers/pci/hotplug/fakephp.c
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_acpi.c
drivers/pci/hotplug/pciehp_core.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/shpchp.h
drivers/pci/hotplug/shpchp_pci.c
drivers/pci/intel-iommu.c
drivers/pci/intr_remapping.c
drivers/pci/iov.c [new file with mode: 0644]
drivers/pci/msi.c
drivers/pci/msi.h
drivers/pci/pci-acpi.c
drivers/pci/pci-driver.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aer/aerdrv.c
drivers/pci/pcie/aer/aerdrv_acpi.c
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/pcie/portdrv.h
drivers/pci/pcie/portdrv_bus.c
drivers/pci/pcie/portdrv_core.c
drivers/pci/pcie/portdrv_pci.c
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/remove.c
drivers/pci/search.c
drivers/pci/setup-bus.c
drivers/pci/setup-res.c
drivers/pci/slot.c
drivers/platform/x86/asus_acpi.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/toshiba_acpi.c
drivers/pnp/pnpbios/core.c
drivers/ps3/ps3av.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1374.c
drivers/rtc/rtc-efi.c [new file with mode: 0644]
drivers/rtc/rtc-lib.c
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-parisc.c
drivers/rtc/rtc-proc.c
drivers/rtc/rtc-v3020.c
drivers/rtc/rtc-wm8350.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_proc.c
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_fsm.c
drivers/s390/net/qeth_core_offl.c [deleted file]
drivers/s390/net/qeth_core_offl.h [deleted file]
drivers/s390/scsi/zfcp_ccw.c
drivers/s390/scsi/zfcp_fc.c
drivers/scsi/scsi_devinfo.c
drivers/scsi/scsi_proc.c
drivers/serial/cpm_uart/cpm_uart_core.c
drivers/serial/mpc52xx_uart.c
drivers/serial/serial_core.c
drivers/sh/maple/maple.c
drivers/spi/spi_gpio.c
drivers/spi/spi_mpc83xx.c
drivers/spi/xilinx_spi.c
drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
drivers/staging/rtl8187se/r8180_core.c
drivers/usb/serial/usb-serial.c
drivers/usb/wusbcore/devconnect.c
drivers/video/68328fb.c
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/amba-clcd.c
drivers/video/amifb.c
drivers/video/arkfb.c
drivers/video/asiliantfb.c
drivers/video/aty/mach64_accel.c
drivers/video/aty/mach64_cursor.c
drivers/video/aty/radeon_pm.c
drivers/video/backlight/backlight.c
drivers/video/backlight/lcd.c
drivers/video/cirrusfb.c
drivers/video/console/fbcon.c
drivers/video/cyblafb.c [deleted file]
drivers/video/efifb.c
drivers/video/fb_defio.c
drivers/video/fbmem.c
drivers/video/nvidia/nv_setup.c
drivers/video/nvidia/nv_type.h
drivers/video/nvidia/nvidia.c
drivers/video/omap/hwa742.c
drivers/video/omap/omapfb_main.c
drivers/video/s1d13xxxfb.c
drivers/video/s3c-fb.c [new file with mode: 0644]
drivers/video/sgivwfb.c
drivers/video/skeletonfb.c
drivers/video/sm501fb.c
drivers/video/sstfb.c
drivers/video/stifb.c
drivers/video/sunxvr500.c
drivers/video/tdfxfb.c
drivers/video/tgafb.c
drivers/video/tridentfb.c
drivers/video/uvesafb.c
drivers/video/valkyriefb.c
drivers/video/vesafb.c
drivers/video/vfb.c
drivers/video/via/accel.c
drivers/video/via/viafbdev.c
drivers/virtio/virtio_ring.c
drivers/w1/w1_io.c
drivers/watchdog/Kconfig
drivers/watchdog/hpwdt.c
drivers/xen/manage.c
fs/adfs/super.c
fs/affs/super.c
fs/afs/proc.c
fs/autofs4/autofs_i.h
fs/autofs4/dev-ioctl.c
fs/autofs4/expire.c
fs/autofs4/root.c
fs/befs/linuxvfs.c
fs/binfmt_elf_fdpic.c
fs/btrfs/Makefile
fs/btrfs/btrfs_inode.h
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/delayed-ref.c [new file with mode: 0644]
fs/btrfs/delayed-ref.h [new file with mode: 0644]
fs/btrfs/dir-item.c
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/inode-item.c
fs/btrfs/inode.c
fs/btrfs/locking.c
fs/btrfs/ordered-data.c
fs/btrfs/ordered-data.h
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-defrag.c
fs/btrfs/tree-log.c
fs/btrfs/tree-log.h
fs/buffer.c
fs/cifs/cifs_debug.c
fs/compat.c
fs/cramfs/inode.c
fs/cramfs/uncompress.c
fs/drop_caches.c
fs/ecryptfs/keystore.c
fs/ecryptfs/messaging.c
fs/efs/super.c
fs/eventfd.c
fs/eventpoll.c
fs/exec.c
fs/ext3/dir.c
fs/ext3/file.c
fs/ext3/inode.c
fs/ext3/ioctl.c
fs/ext3/namei.c
fs/ext4/balloc.c
fs/ext4/dir.c
fs/ext4/ext4.h
fs/ext4/ext4_extents.h
fs/ext4/ext4_i.h
fs/ext4/ext4_sb.h
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/mballoc.h
fs/ext4/namei.c
fs/ext4/resize.c
fs/ext4/super.c
fs/fat/inode.c
fs/fcntl.c
fs/fs-writeback.c
fs/fuse/file.c
fs/gfs2/ops_file.c
fs/hfs/super.c
fs/hfsplus/super.c
fs/hpfs/super.c
fs/hppfs/hppfs.c
fs/hugetlbfs/inode.c
fs/internal.h
fs/isofs/inode.c
fs/jbd/journal.c
fs/jbd2/commit.c
fs/jbd2/revoke.c
fs/jbd2/transaction.c
fs/jfs/Kconfig
fs/jfs/jfs_debug.c
fs/jfs/jfs_extent.c
fs/jfs/jfs_imap.c
fs/jfs/jfs_metapage.c
fs/jfs/jfs_types.h
fs/jfs/jfs_xtree.c
fs/jfs/jfs_xtree.h
fs/jfs/super.c
fs/lockd/clntlock.c
fs/lockd/mon.c
fs/lockd/svc.c
fs/minix/inode.c
fs/nfs/callback.c
fs/nfs/callback.h
fs/nfs/client.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/getroot.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs2xdr.c
fs/nfs/nfs3proc.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/pagelist.c
fs/nfs/proc.c
fs/nfs/super.c
fs/nfs/write.c
fs/nfsd/nfsctl.c
fs/nfsd/nfssvc.c
fs/ntfs/dir.c
fs/ntfs/inode.c
fs/ntfs/layout.h
fs/ntfs/logfile.h
fs/ntfs/mft.c
fs/ntfs/super.c
fs/ntfs/usnjrnl.h
fs/ocfs2/mmap.c
fs/omfs/inode.c
fs/proc/base.c
fs/proc/generic.c
fs/proc/inode-alloc.txt [deleted file]
fs/proc/inode.c
fs/proc/internal.h
fs/proc/meminfo.c
fs/proc/proc_tty.c
fs/proc/task_mmu.c
fs/proc/task_nommu.c
fs/proc/uptime.c
fs/qnx4/inode.c
fs/quota/dquot.c
fs/ramfs/file-nommu.c
fs/ramfs/inode.c
fs/read_write.c
fs/reiserfs/Kconfig
fs/reiserfs/Makefile
fs/reiserfs/README
fs/reiserfs/bitmap.c
fs/reiserfs/dir.c
fs/reiserfs/do_balan.c
fs/reiserfs/file.c
fs/reiserfs/fix_node.c
fs/reiserfs/hashes.c
fs/reiserfs/ibalance.c
fs/reiserfs/inode.c
fs/reiserfs/ioctl.c
fs/reiserfs/item_ops.c
fs/reiserfs/journal.c
fs/reiserfs/lbalance.c
fs/reiserfs/namei.c
fs/reiserfs/objectid.c
fs/reiserfs/prints.c
fs/reiserfs/procfs.c
fs/reiserfs/resize.c
fs/reiserfs/stree.c
fs/reiserfs/super.c
fs/reiserfs/tail_conversion.c
fs/reiserfs/xattr.c
fs/reiserfs/xattr_acl.c
fs/reiserfs/xattr_security.c
fs/reiserfs/xattr_trusted.c
fs/reiserfs/xattr_user.c
fs/seq_file.c
fs/squashfs/super.c
fs/sysfs/bin.c
fs/sysv/inode.c
fs/ubifs/file.c
fs/ufs/super.c
fs/xfs/linux-2.6/xfs_file.c
include/asm-frv/highmem.h
include/asm-generic/dma-mapping.h [deleted file]
include/asm-generic/gpio.h
include/asm-generic/topology.h
include/asm-m32r/spinlock.h
include/asm-mn10300/highmem.h
include/drm/drmP.h
include/drm/drm_crtc.h
include/drm/drm_os_linux.h
include/drm/drm_pciids.h
include/drm/radeon_drm.h
include/linux/Kbuild
include/linux/acpi.h
include/linux/auto_dev-ioctl.h
include/linux/auto_fs.h
include/linux/binfmts.h
include/linux/bootmem.h
include/linux/buffer_head.h
include/linux/cgroup.h
include/linux/compat.h
include/linux/cpu.h
include/linux/cpuset.h
include/linux/dma-debug.h [new file with mode: 0644]
include/linux/dma-mapping.h
include/linux/dmar.h
include/linux/dmi.h
include/linux/eventfd.h
include/linux/ext3_fs.h
include/linux/fb.h
include/linux/fs.h
include/linux/fs_struct.h
include/linux/fsl_devices.h
include/linux/ftrace.h
include/linux/highmem.h
include/linux/i2c-id.h
include/linux/i2c/at24.h
include/linux/ide.h
include/linux/idr.h
include/linux/intel-iommu.h
include/linux/interrupt.h
include/linux/ipmi_smi.h
include/linux/irq.h
include/linux/ivtv.h
include/linux/jbd2.h
include/linux/kernel.h
include/linux/lockdep.h
include/linux/loop.h
include/linux/memcontrol.h
include/linux/memory.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/mmzone.h
include/linux/msi.h
include/linux/mutex.h
include/linux/nfs_fs.h
include/linux/nfs_fs_sb.h
include/linux/nfs_xdr.h
include/linux/page-debug-flags.h [new file with mode: 0644]
include/linux/page-flags.h
include/linux/page_cgroup.h
include/linux/pagemap.h
include/linux/pagevec.h
include/linux/pci-acpi.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/pci_regs.h
include/linux/pcieport_if.h
include/linux/poison.h
include/linux/proc_fs.h
include/linux/ptrace.h
include/linux/reiserfs_acl.h
include/linux/reiserfs_fs.h
include/linux/reiserfs_fs_i.h
include/linux/reiserfs_fs_sb.h
include/linux/reiserfs_xattr.h
include/linux/rtc-v3020.h
include/linux/rtc.h
include/linux/sched.h
include/linux/security.h
include/linux/seq_file.h
include/linux/spi/eeprom.h
include/linux/spi/spi_gpio.h
include/linux/spinlock.h
include/linux/string.h
include/linux/sunrpc/svc.h
include/linux/sunrpc/svc_xprt.h
include/linux/sunrpc/xprt.h
include/linux/suspend.h
include/linux/swap.h
include/linux/swiotlb.h
include/linux/synclink.h
include/linux/syscalls.h
include/linux/timer.h
include/linux/tracehook.h
include/linux/tty_driver.h
include/linux/video_decoder.h [deleted file]
include/linux/video_encoder.h [deleted file]
include/linux/videodev.h
include/linux/videodev2.h
include/linux/wait.h
include/linux/workqueue.h
include/linux/writeback.h
include/media/bt819.h [new file with mode: 0644]
include/media/cx2341x.h
include/media/cx25840.h
include/media/ir-common.h
include/media/ir-kbd-i2c.h
include/media/ov772x.h
include/media/saa7146.h
include/media/saa7146_vv.h
include/media/sh_mobile_ceu.h
include/media/soc_camera.h
include/media/v4l2-chip-ident.h
include/media/v4l2-common.h
include/media/v4l2-dev.h
include/media/v4l2-device.h
include/media/v4l2-ioctl.h
include/media/v4l2-subdev.h
include/media/videobuf-core.h
include/net/cipso_ipv4.h
include/net/netlabel.h
include/sound/tea575x-tuner.h
include/video/aty128.h
include/video/cirrus.h
include/video/newport.h
include/video/radeon.h
include/video/s1d13xxxfb.h
init/Kconfig
init/initramfs.c
init/main.c
ipc/ipc_sysctl.c
ipc/shm.c
kernel/cgroup.c
kernel/cgroup_debug.c
kernel/cpu.c
kernel/cpuset.c
kernel/exit.c
kernel/fork.c
kernel/futex.c
kernel/irq/Makefile
kernel/irq/internals.h
kernel/irq/manage.c
kernel/irq/pm.c [new file with mode: 0644]
kernel/kexec.c
kernel/kmod.c
kernel/kthread.c
kernel/lockdep.c
kernel/lockdep_internals.h
kernel/lockdep_proc.c
kernel/lockdep_states.h [new file with mode: 0644]
kernel/mutex-debug.c
kernel/mutex-debug.h
kernel/mutex.c
kernel/mutex.h
kernel/ns_cgroup.c
kernel/pid.c
kernel/pid_namespace.c
kernel/power/disk.c
kernel/power/main.c
kernel/power/snapshot.c
kernel/power/swsusp.c
kernel/printk.c
kernel/ptrace.c
kernel/rcutorture.c
kernel/relay.c
kernel/sched.c
kernel/sched_cpupri.h
kernel/sched_features.h
kernel/signal.c
kernel/spinlock.c
kernel/stop_machine.c
kernel/sys.c
kernel/sysctl.c
kernel/timer.c
kernel/trace/trace_functions_graph.c
kernel/utsname_sysctl.c
kernel/workqueue.c
lib/Kconfig.debug
lib/Makefile
lib/cpumask.c
lib/dma-debug.c [new file with mode: 0644]
lib/idr.c
lib/lmb.c
lib/rbtree.c
lib/swiotlb.c
mm/Kconfig
mm/Kconfig.debug [new file with mode: 0644]
mm/Makefile
mm/allocpercpu.c
mm/debug-pagealloc.c [new file with mode: 0644]
mm/filemap_xip.c
mm/highmem.c
mm/hugetlb.c
mm/internal.h
mm/memcontrol.c
mm/memory.c
mm/mmap.c
mm/nommu.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_cgroup.c
mm/pdflush.c
mm/shmem.c
mm/slab.c
mm/slob.c
mm/slub.c
mm/sparse.c
mm/swap.c
mm/util.c
mm/vmalloc.c
mm/vmscan.c
mm/vmstat.c
net/appletalk/atalk_proc.c
net/atm/mpoa_proc.c
net/atm/proc.c
net/bluetooth/rfcomm/tty.c
net/can/bcm.c
net/can/proc.c
net/core/pktgen.c
net/core/sock.c
net/ipv4/cipso_ipv4.c
net/ipv4/syncookies.c
net/ipv4/tcp_ipv4.c
net/irda/ircomm/ircomm_tty.c
net/irda/irproc.c
net/llc/llc_proc.c
net/netlabel/netlabel_kapi.c
net/sctp/protocol.c
net/socket.c
net/sunrpc/Kconfig
net/sunrpc/cache.c
net/sunrpc/clnt.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/stats.c
net/sunrpc/svc.c
net/sunrpc/svc_xprt.c
net/sunrpc/svcsock.c
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/rpc_rdma.c
net/sunrpc/xprtrdma/svc_rdma_sendto.c
net/sunrpc/xprtsock.c
security/capability.c
security/device_cgroup.c
security/security.c
security/selinux/hooks.c
security/selinux/include/netlabel.h
security/selinux/netlabel.c
security/selinux/selinuxfs.c
security/smack/smack.h
security/smack/smack_access.c
security/smack/smack_lsm.c
security/smack/smackfs.c
security/tomoyo/common.h
sound/core/info.c
sound/i2c/other/tea575x-tuner.c
sound/pci/Kconfig
usr/Kconfig

diff --git a/CREDITS b/CREDITS
index e8b7d36611e5ade69bb9524618752aa36820f3c9..9a93e3e26d700c757baaac7a851eb3da2bff68ab 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -495,6 +495,11 @@ S: Kopmansg 2
 S: 411 13  Goteborg
 S: Sweden
 
+N: Paul Bristow
+E: paul@paulbristow.net
+W: http://paulbristow.net/linux/idefloppy.html
+D: Maintainer of IDE/ATAPI floppy driver
+
 N: Dominik Brodowski
 E: linux@brodo.de
 W: http://www.brodo.de/
@@ -2642,6 +2647,10 @@ S: C/ Mieses 20, 9-B
 S: Valladolid 47009
 S: Spain
 
+N: Gadi Oxman
+E: gadio@netvision.net.il
+D: Original author and maintainer of IDE/ATAPI floppy/tape drivers
+
 N: Greg Page
 E: gpage@sovereign.org
 D: IPX development and support
index e638e15a8895abef445cedccb2df273f1e3ad0e1..97ad190e13af0586a528bbb7e6dfb10e748eddcd 100644 (file)
@@ -41,6 +41,49 @@ Description:
                for the device and attempt to bind to it.  For example:
                # echo "8086 10f5" > /sys/bus/pci/drivers/foo/new_id
 
+What:          /sys/bus/pci/drivers/.../remove_id
+Date:          February 2009
+Contact:       Chris Wright <chrisw@sous-sol.org>
+Description:
+               Writing a device ID to this file will remove an ID
+               that was dynamically added via the new_id sysfs entry.
+               The format for the device ID is:
+               VVVV DDDD SVVV SDDD CCCC MMMM.  That is Vendor ID, Device
+               ID, Subsystem Vendor ID, Subsystem Device ID, Class,
+               and Class Mask.  The Vendor ID and Device ID fields are
+               required, the rest are optional.  After successfully
+               removing an ID, the driver will no longer support the
+               device.  This is useful to ensure auto probing won't
+               match the driver to the device.  For example:
+               # echo "8086 10f5" > /sys/bus/pci/drivers/foo/remove_id
+
+What:          /sys/bus/pci/rescan
+Date:          January 2009
+Contact:       Linux PCI developers <linux-pci@vger.kernel.org>
+Description:
+               Writing a non-zero value to this attribute will
+               force a rescan of all PCI buses in the system, and
+               re-discover previously removed devices.
+               Depends on CONFIG_HOTPLUG.
+
+What:          /sys/bus/pci/devices/.../remove
+Date:          January 2009
+Contact:       Linux PCI developers <linux-pci@vger.kernel.org>
+Description:
+               Writing a non-zero value to this attribute will
+               hot-remove the PCI device and any of its children.
+               Depends on CONFIG_HOTPLUG.
+
+What:          /sys/bus/pci/devices/.../rescan
+Date:          January 2009
+Contact:       Linux PCI developers <linux-pci@vger.kernel.org>
+Description:
+               Writing a non-zero value to this attribute will
+               force a rescan of the device's parent bus and all
+               child buses, and re-discover devices removed earlier
+               from this part of the device tree.
+               Depends on CONFIG_HOTPLUG.
+
 What:          /sys/bus/pci/devices/.../vpd
 Date:          February 2008
 Contact:       Ben Hutchings <bhutchings@solarflare.com>
@@ -52,3 +95,30 @@ Description:
                that some devices may have malformatted data.  If the
                underlying VPD has a writable section then the
                corresponding section of this file will be writable.
+
+What:          /sys/bus/pci/devices/.../virtfnN
+Date:          March 2009
+Contact:       Yu Zhao <yu.zhao@intel.com>
+Description:
+               This symbolic link appears when hardware supports the SR-IOV
+               capability and the Physical Function driver has enabled it.
+               The symbolic link points to the PCI device sysfs entry of the
+               Virtual Function whose index is N (0...MaxVFs-1).
+
+What:          /sys/bus/pci/devices/.../dep_link
+Date:          March 2009
+Contact:       Yu Zhao <yu.zhao@intel.com>
+Description:
+               This symbolic link appears when hardware supports the SR-IOV
+               capability and the Physical Function driver has enabled it,
+               and this device has vendor specific dependencies with others.
+               The symbolic link points to the PCI device sysfs entry of
+               Physical Function this device depends on.
+
+What:          /sys/bus/pci/devices/.../physfn
+Date:          March 2009
+Contact:       Yu Zhao <yu.zhao@intel.com>
+Description:
+               This symbolic link appears when a device is a Virtual Function.
+               The symbolic link points to the PCI device sysfs entry of the
+               Physical Function this device associates with.
diff --git a/Documentation/ABI/testing/sysfs-fs-ext4 b/Documentation/ABI/testing/sysfs-fs-ext4
new file mode 100644 (file)
index 0000000..4e79074
--- /dev/null
@@ -0,0 +1,81 @@
+What:          /sys/fs/ext4/<disk>/mb_stats
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+                Controls whether the multiblock allocator should
+                collect statistics, which are shown during the unmount.
+                1 means to collect statistics, 0 means not to collect
+                statistics
+
+What:          /sys/fs/ext4/<disk>/mb_group_prealloc
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               The multiblock allocator will round up allocation
+               requests to a multiple of this tuning parameter if the
+               stripe size is not set in the ext4 superblock
+
+What:          /sys/fs/ext4/<disk>/mb_max_to_scan
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               The maximum number of extents the multiblock allocator
+               will search to find the best extent
+
+What:          /sys/fs/ext4/<disk>/mb_min_to_scan
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               The minimum number of extents the multiblock allocator
+               will search to find the best extent
+
+What:          /sys/fs/ext4/<disk>/mb_order2_req
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               Tuning parameter which controls the minimum size for 
+               requests (as a power of 2) where the buddy cache is
+               used
+
+What:          /sys/fs/ext4/<disk>/mb_stream_req
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               Files which have fewer blocks than this tunable
+               parameter will have their blocks allocated out of a
+               block group specific preallocation pool, so that small
+               files are packed closely together.  Each large file
+                will have its blocks allocated out of its own unique
+                preallocation pool.
+
+What:          /sys/fs/ext4/<disk>/inode_readahead
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               Tuning parameter which controls the maximum number of
+               inode table blocks that ext4's inode table readahead
+               algorithm will pre-read into the buffer cache
+
+What:          /sys/fs/ext4/<disk>/delayed_allocation_blocks
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               This file is read-only and shows the number of blocks
+               that are dirty in the page cache, but which do not
+               have their location in the filesystem allocated yet.
+
+What:          /sys/fs/ext4/<disk>/lifetime_write_kbytes
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               This file is read-only and shows the number of kilobytes
+               of data that have been written to this filesystem since it was
+               created.
+
+What:          /sys/fs/ext4/<disk>/session_write_kbytes
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               This file is read-only and shows the number of
+               kilobytes of data that have been written to this
+               filesystem since it was mounted.
index 2a3fcc55e98157b83a514c98c0e13fcd71bab30a..d9aa43d78bcc9fc92e582a62cadb18cd9b27f4f0 100644 (file)
@@ -609,3 +609,109 @@ size is the size (and should be a page-sized multiple).
 The return value will be either a pointer to the processor virtual
 address of the memory, or an error (via PTR_ERR()) if any part of the
 region is occupied.
+
+Part III - Debug drivers use of the DMA-API
+-------------------------------------------
+
+The DMA-API as described above as some constraints. DMA addresses must be
+released with the corresponding function with the same size for example. With
+the advent of hardware IOMMUs it becomes more and more important that drivers
+do not violate those constraints. In the worst case such a violation can
+result in data corruption up to destroyed filesystems.
+
+To debug drivers and find bugs in the usage of the DMA-API checking code can
+be compiled into the kernel which will tell the developer about those
+violations. If your architecture supports it you can select the "Enable
+debugging of DMA-API usage" option in your kernel configuration. Enabling this
+option has a performance impact. Do not enable it in production kernels.
+
+If you boot the resulting kernel will contain code which does some bookkeeping
+about what DMA memory was allocated for which device. If this code detects an
+error it prints a warning message with some details into your kernel log. An
+example warning message may look like this:
+
+------------[ cut here ]------------
+WARNING: at /data2/repos/linux-2.6-iommu/lib/dma-debug.c:448
+       check_unmap+0x203/0x490()
+Hardware name:
+forcedeth 0000:00:08.0: DMA-API: device driver frees DMA memory with wrong
+       function [device address=0x00000000640444be] [size=66 bytes] [mapped as
+single] [unmapped as page]
+Modules linked in: nfsd exportfs bridge stp llc r8169
+Pid: 0, comm: swapper Tainted: G        W  2.6.28-dmatest-09289-g8bb99c0 #1
+Call Trace:
+ <IRQ>  [<ffffffff80240b22>] warn_slowpath+0xf2/0x130
+ [<ffffffff80647b70>] _spin_unlock+0x10/0x30
+ [<ffffffff80537e75>] usb_hcd_link_urb_to_ep+0x75/0xc0
+ [<ffffffff80647c22>] _spin_unlock_irqrestore+0x12/0x40
+ [<ffffffff8055347f>] ohci_urb_enqueue+0x19f/0x7c0
+ [<ffffffff80252f96>] queue_work+0x56/0x60
+ [<ffffffff80237e10>] enqueue_task_fair+0x20/0x50
+ [<ffffffff80539279>] usb_hcd_submit_urb+0x379/0xbc0
+ [<ffffffff803b78c3>] cpumask_next_and+0x23/0x40
+ [<ffffffff80235177>] find_busiest_group+0x207/0x8a0
+ [<ffffffff8064784f>] _spin_lock_irqsave+0x1f/0x50
+ [<ffffffff803c7ea3>] check_unmap+0x203/0x490
+ [<ffffffff803c8259>] debug_dma_unmap_page+0x49/0x50
+ [<ffffffff80485f26>] nv_tx_done_optimized+0xc6/0x2c0
+ [<ffffffff80486c13>] nv_nic_irq_optimized+0x73/0x2b0
+ [<ffffffff8026df84>] handle_IRQ_event+0x34/0x70
+ [<ffffffff8026ffe9>] handle_edge_irq+0xc9/0x150
+ [<ffffffff8020e3ab>] do_IRQ+0xcb/0x1c0
+ [<ffffffff8020c093>] ret_from_intr+0x0/0xa
+ <EOI> <4>---[ end trace f6435a98e2a38c0e ]---
+
+The driver developer can find the driver and the device including a stacktrace
+of the DMA-API call which caused this warning.
+
+Per default only the first error will result in a warning message. All other
+errors will only silently counted. This limitation exist to prevent the code
+from flooding your kernel log. To support debugging a device driver this can
+be disabled via debugfs. See the debugfs interface documentation below for
+details.
+
+The debugfs directory for the DMA-API debugging code is called dma-api/. In
+this directory the following files can currently be found:
+
+       dma-api/all_errors      This file contains a numeric value. If this
+                               value is not equal to zero the debugging code
+                               will print a warning for every error it finds
+                               into the kernel log. Be carefull with this
+                               option. It can easily flood your logs.
+
+       dma-api/disabled        This read-only file contains the character 'Y'
+                               if the debugging code is disabled. This can
+                               happen when it runs out of memory or if it was
+                               disabled at boot time
+
+       dma-api/error_count     This file is read-only and shows the total
+                               numbers of errors found.
+
+       dma-api/num_errors      The number in this file shows how many
+                               warnings will be printed to the kernel log
+                               before it stops. This number is initialized to
+                               one at system boot and be set by writing into
+                               this file
+
+       dma-api/min_free_entries
+                               This read-only file can be read to get the
+                               minimum number of free dma_debug_entries the
+                               allocator has ever seen. If this value goes
+                               down to zero the code will disable itself
+                               because it is not longer reliable.
+
+       dma-api/num_free_entries
+                               The current number of free dma_debug_entries
+                               in the allocator.
+
+If you have this code compiled into your kernel it will be enabled by default.
+If you want to boot without the bookkeeping anyway you can provide
+'dma_debug=off' as a boot parameter. This will disable DMA-API debugging.
+Notice that you can not enable it again at runtime. You have to reboot to do
+so.
+
+When the code disables itself at runtime this is most likely because it ran
+out of dma_debug_entries. These entries are preallocated at boot. The number
+of preallocated entries is defined per architecture. If it is too low for you
+boot with 'dma_debug_entries=<your_desired_number>' to overwrite the
+architectural default.
index c102c02ecf896059e410ff9f867b69cccd537fa5..c6def352fe39e667bd884e1e518872bc962aaf41 100644 (file)
@@ -4,3 +4,7 @@
 *.html
 *.9.gz
 *.9
+*.aux
+*.dvi
+*.log
+*.out
index bc962cda650485aea9cddcced9823ef39a3252b6..58c194572c763c8cfcba3e6c607f91220115e977 100644 (file)
@@ -199,6 +199,7 @@ X!Edrivers/pci/hotplug.c
 -->
 !Edrivers/pci/probe.c
 !Edrivers/pci/rom.c
+!Edrivers/pci/iov.c
      </sect1>
      <sect1><title>PCI Hotplug Support Library</title>
 !Edrivers/pci/hotplug/pci_hotplug_core.c
index 8c6396e4bf311901a19fd717500c422eeba4869a..a5b11793b1e0167bf32d1b1a19d13aca7a424aa5 100644 (file)
@@ -117,9 +117,6 @@ static int __init init_procfs_example(void)
                rv = -ENOMEM;
                goto out;
        }
-       
-       example_dir->owner = THIS_MODULE;
-       
        /* create jiffies using convenience function */
        jiffies_file = create_proc_read_entry("jiffies", 
                                              0444, example_dir, 
@@ -130,8 +127,6 @@ static int __init init_procfs_example(void)
                goto no_jiffies;
        }
 
-       jiffies_file->owner = THIS_MODULE;
-
        /* create foo and bar files using same callback
         * functions 
         */
@@ -146,7 +141,6 @@ static int __init init_procfs_example(void)
        foo_file->data = &foo_data;
        foo_file->read_proc = proc_read_foobar;
        foo_file->write_proc = proc_write_foobar;
-       foo_file->owner = THIS_MODULE;
                
        bar_file = create_proc_entry("bar", 0644, example_dir);
        if(bar_file == NULL) {
@@ -159,7 +153,6 @@ static int __init init_procfs_example(void)
        bar_file->data = &bar_data;
        bar_file->read_proc = proc_read_foobar;
        bar_file->write_proc = proc_write_foobar;
-       bar_file->owner = THIS_MODULE;
                
        /* create symlink */
        symlink = proc_symlink("jiffies_too", example_dir, 
@@ -169,8 +162,6 @@ static int __init init_procfs_example(void)
                goto no_symlink;
        }
 
-       symlink->owner = THIS_MODULE;
-
        /* everything OK */
        printk(KERN_INFO "%s %s initialised\n",
               MODULE_NAME, MODULE_VERS);
index 256defd7e1742be45497e1bcc8912d493241c5af..dcf7acc720e18bb68c572e38c6913863b5ead701 100644 (file)
        Revised Feb 12, 2004 by Martine Silbermann
                email: Martine.Silbermann@hp.com
        Revised Jun 25, 2004 by Tom L Nguyen
+       Revised Jul  9, 2008 by Matthew Wilcox <willy@linux.intel.com>
+               Copyright 2003, 2008 Intel Corporation
 
 1. About this guide
 
-This guide describes the basics of Message Signaled Interrupts (MSI),
-the advantages of using MSI over traditional interrupt mechanisms,
-and how to enable your driver to use MSI or MSI-X. Also included is
-a Frequently Asked Questions (FAQ) section.
-
-1.1 Terminology
-
-PCI devices can be single-function or multi-function.  In either case,
-when this text talks about enabling or disabling MSI on a "device
-function," it is referring to one specific PCI device and function and
-not to all functions on a PCI device (unless the PCI device has only
-one function).
-
-2. Copyright 2003 Intel Corporation
-
-3. What is MSI/MSI-X?
-
-Message Signaled Interrupt (MSI), as described in the PCI Local Bus
-Specification Revision 2.3 or later, is an optional feature, and a
-required feature for PCI Express devices. MSI enables a device function
-to request service by sending an Inbound Memory Write on its PCI bus to
-the FSB as a Message Signal Interrupt transaction. Because MSI is
-generated in the form of a Memory Write, all transaction conditions,
-such as a Retry, Master-Abort, Target-Abort or normal completion, are
-supported.
-
-A PCI device that supports MSI must also support pin IRQ assertion
-interrupt mechanism to provide backward compatibility for systems that
-do not support MSI. In systems which support MSI, the bus driver is
-responsible for initializing the message address and message data of
-the device function's MSI/MSI-X capability structure during device
-initial configuration.
-
-An MSI capable device function indicates MSI support by implementing
-the MSI/MSI-X capability structure in its PCI capability list. The
-device function may implement both the MSI capability structure and
-the MSI-X capability structure; however, the bus driver should not
-enable both.
-
-The MSI capability structure contains Message Control register,
-Message Address register and Message Data register. These registers
-provide the bus driver control over MSI. The Message Control register
-indicates the MSI capability supported by the device. The Message
-Address register specifies the target address and the Message Data
-register specifies the characteristics of the message. To request
-service, the device function writes the content of the Message Data
-register to the target address. The device and its software driver
-are prohibited from writing to these registers.
-
-The MSI-X capability structure is an optional extension to MSI. It
-uses an independent and separate capability structure. There are
-some key advantages to implementing the MSI-X capability structure
-over the MSI capability structure as described below.
-
-       - Support a larger maximum number of vectors per function.
-
-       - Provide the ability for system software to configure
-       each vector with an independent message address and message
-       data, specified by a table that resides in Memory Space.
-
-        - MSI and MSI-X both support per-vector masking. Per-vector
-       masking is an optional extension of MSI but a required
-       feature for MSI-X. Per-vector masking provides the kernel the
-       ability to mask/unmask a single MSI while running its
-       interrupt service routine. If per-vector masking is
-       not supported, then the device driver should provide the
-       hardware/software synchronization to ensure that the device
-       generates MSI when the driver wants it to do so.
-
-4. Why use MSI?
-
-As a benefit to the simplification of board design, MSI allows board
-designers to remove out-of-band interrupt routing. MSI is another
-step towards a legacy-free environment.
-
-Due to increasing pressure on chipset and processor packages to
-reduce pin count, the need for interrupt pins is expected to
-diminish over time. Devices, due to pin constraints, may implement
-messages to increase performance.
-
-PCI Express endpoints uses INTx emulation (in-band messages) instead
-of IRQ pin assertion. Using INTx emulation requires interrupt
-sharing among devices connected to the same node (PCI bridge) while
-MSI is unique (non-shared) and does not require BIOS configuration
-support. As a result, the PCI Express technology requires MSI
-support for better interrupt performance.
-
-Using MSI enables the device functions to support two or more
-vectors, which can be configured to target different CPUs to
-increase scalability.
-
-5. Configuring a driver to use MSI/MSI-X
-
-By default, the kernel will not enable MSI/MSI-X on all devices that
-support this capability. The CONFIG_PCI_MSI kernel option
-must be selected to enable MSI/MSI-X support.
-
-5.1 Including MSI/MSI-X support into the kernel
-
-To allow MSI/MSI-X capable device drivers to selectively enable
-MSI/MSI-X (using pci_enable_msi()/pci_enable_msix() as described
-below), the VECTOR based scheme needs to be enabled by setting
-CONFIG_PCI_MSI during kernel config.
-
-Since the target of the inbound message is the local APIC, providing
-CONFIG_X86_LOCAL_APIC must be enabled as well as CONFIG_PCI_MSI.
-
-5.2 Configuring for MSI support
-
-Due to the non-contiguous fashion in vector assignment of the
-existing Linux kernel, this version does not support multiple
-messages regardless of a device function is capable of supporting
-more than one vector. To enable MSI on a device function's MSI
-capability structure requires a device driver to call the function
-pci_enable_msi() explicitly.
-
-5.2.1 API pci_enable_msi
+This guide describes the basics of Message Signaled Interrupts (MSIs),
+the advantages of using MSI over traditional interrupt mechanisms, how
+to change your driver to use MSI or MSI-X and some basic diagnostics to
+try if a device doesn't support MSIs.
 
-int pci_enable_msi(struct pci_dev *dev)
 
-With this new API, a device driver that wants to have MSI
-enabled on its device function must call this API to enable MSI.
-A successful call will initialize the MSI capability structure
-with ONE vector, regardless of whether a device function is
-capable of supporting multiple messages. This vector replaces the
-pre-assigned dev->irq with a new MSI vector. To avoid a conflict
-of the new assigned vector with existing pre-assigned vector requires
-a device driver to call this API before calling request_irq().
+2. What are MSIs?
 
-5.2.2 API pci_disable_msi
+A Message Signaled Interrupt is a write from the device to a special
+address which causes an interrupt to be received by the CPU.
 
-void pci_disable_msi(struct pci_dev *dev)
+The MSI capability was first specified in PCI 2.2 and was later enhanced
+in PCI 3.0 to allow each interrupt to be masked individually.  The MSI-X
+capability was also introduced with PCI 3.0.  It supports more interrupts
+per device than MSI and allows interrupts to be independently configured.
 
-This API should always be used to undo the effect of pci_enable_msi()
-when a device driver is unloading. This API restores dev->irq with
-the pre-assigned IOAPIC vector and switches a device's interrupt
-mode to PCI pin-irq assertion/INTx emulation mode.
-
-Note that a device driver should always call free_irq() on the MSI vector
-that it has done request_irq() on before calling this API. Failure to do
-so results in a BUG_ON() and a device will be left with MSI enabled and
-leaks its vector.
-
-5.2.3 MSI mode vs. legacy mode diagram
-
-The below diagram shows the events which switch the interrupt
-mode on the MSI-capable device function between MSI mode and
-PIN-IRQ assertion mode.
-
-        ------------   pci_enable_msi   ------------------------
-       |            | <=============== |                        |
-       | MSI MODE   |                  | PIN-IRQ ASSERTION MODE |
-       |            | ===============> |                        |
-        ------------   pci_disable_msi  ------------------------
-
-
-Figure 1. MSI Mode vs. Legacy Mode
-
-In Figure 1, a device operates by default in legacy mode. Legacy
-in this context means PCI pin-irq assertion or PCI-Express INTx
-emulation. A successful MSI request (using pci_enable_msi()) switches
-a device's interrupt mode to MSI mode. A pre-assigned IOAPIC vector
-stored in dev->irq will be saved by the PCI subsystem and a new
-assigned MSI vector will replace dev->irq.
-
-To return back to its default mode, a device driver should always call
-pci_disable_msi() to undo the effect of pci_enable_msi(). Note that a
-device driver should always call free_irq() on the MSI vector it has
-done request_irq() on before calling pci_disable_msi(). Failure to do
-so results in a BUG_ON() and a device will be left with MSI enabled and
-leaks its vector. Otherwise, the PCI subsystem restores a device's
-dev->irq with a pre-assigned IOAPIC vector and marks the released
-MSI vector as unused.
-
-Once being marked as unused, there is no guarantee that the PCI
-subsystem will reserve this MSI vector for a device. Depending on
-the availability of current PCI vector resources and the number of
-MSI/MSI-X requests from other drivers, this MSI may be re-assigned.
-
-For the case where the PCI subsystem re-assigns this MSI vector to
-another driver, a request to switch back to MSI mode may result
-in being assigned a different MSI vector or a failure if no more
-vectors are available.
-
-5.3 Configuring for MSI-X support
-
-Due to the ability of the system software to configure each vector of
-the MSI-X capability structure with an independent message address
-and message data, the non-contiguous fashion in vector assignment of
-the existing Linux kernel has no impact on supporting multiple
-messages on an MSI-X capable device functions. To enable MSI-X on
-a device function's MSI-X capability structure requires its device
-driver to call the function pci_enable_msix() explicitly.
-
-The function pci_enable_msix(), once invoked, enables either
-all or nothing, depending on the current availability of PCI vector
-resources. If the PCI vector resources are available for the number
-of vectors requested by a device driver, this function will configure
-the MSI-X table of the MSI-X capability structure of a device with
-requested messages. To emphasize this reason, for example, a device
-may be capable for supporting the maximum of 32 vectors while its
-software driver usually may request 4 vectors. It is recommended
-that the device driver should call this function once during the
-initialization phase of the device driver.
-
-Unlike the function pci_enable_msi(), the function pci_enable_msix()
-does not replace the pre-assigned IOAPIC dev->irq with a new MSI
-vector because the PCI subsystem writes the 1:1 vector-to-entry mapping
-into the field vector of each element contained in a second argument.
-Note that the pre-assigned IOAPIC dev->irq is valid only if the device
-operates in PIN-IRQ assertion mode. In MSI-X mode, any attempt at
-using dev->irq by the device driver to request for interrupt service
-may result in unpredictable behavior.
-
-For each MSI-X vector granted, a device driver is responsible for calling
-other functions like request_irq(), enable_irq(), etc. to enable
-this vector with its corresponding interrupt service handler. It is
-a device driver's choice to assign all vectors with the same
-interrupt service handler or each vector with a unique interrupt
-service handler.
-
-5.3.1 Handling MMIO address space of MSI-X Table
-
-The PCI 3.0 specification has implementation notes that MMIO address
-space for a device's MSI-X structure should be isolated so that the
-software system can set different pages for controlling accesses to the
-MSI-X structure. The implementation of MSI support requires the PCI
-subsystem, not a device driver, to maintain full control of the MSI-X
-table/MSI-X PBA (Pending Bit Array) and MMIO address space of the MSI-X
-table/MSI-X PBA.  A device driver should not access the MMIO address
-space of the MSI-X table/MSI-X PBA.
-
-5.3.2 API pci_enable_msix
+Devices may support both MSI and MSI-X, but only one can be enabled at
+a time.
 
-int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
 
-This API enables a device driver to request the PCI subsystem
-to enable MSI-X messages on its hardware device. Depending on
-the availability of PCI vectors resources, the PCI subsystem enables
-either all or none of the requested vectors.
+3. Why use MSIs?
+
+There are three reasons why using MSIs can give an advantage over
+traditional pin-based interrupts.
+
+Pin-based PCI interrupts are often shared amongst several devices.
+To support this, the kernel must call each interrupt handler associated
+with an interrupt, which leads to reduced performance for the system as
+a whole.  MSIs are never shared, so this problem cannot arise.
+
+When a device writes data to memory, then raises a pin-based interrupt,
+it is possible that the interrupt may arrive before all the data has
+arrived in memory (this becomes more likely with devices behind PCI-PCI
+bridges).  In order to ensure that all the data has arrived in memory,
+the interrupt handler must read a register on the device which raised
+the interrupt.  PCI transaction ordering rules require that all the data
+arrives in memory before the value can be returned from the register.
+Using MSIs avoids this problem as the interrupt-generating write cannot
+pass the data writes, so by the time the interrupt is raised, the driver
+knows that all the data has arrived in memory.
+
+PCI devices can only support a single pin-based interrupt per function.
+Often drivers have to query the device to find out what event has
+occurred, slowing down interrupt handling for the common case.  With
+MSIs, a device can support more interrupts, allowing each interrupt
+to be specialised to a different purpose.  One possible design gives
+infrequent conditions (such as errors) their own interrupt which allows
+the driver to handle the normal interrupt handling path more efficiently.
+Other possible designs include giving one interrupt to each packet queue
+in a network card or each port in a storage controller.
+
+
+4. How to use MSIs
+
+PCI devices are initialised to use pin-based interrupts.  The device
+driver has to set up the device to use MSI or MSI-X.  Not all machines
+support MSIs correctly, and for those machines, the APIs described below
+will simply fail and the device will continue to use pin-based interrupts.
+
+4.1 Include kernel support for MSIs
+
+To support MSI or MSI-X, the kernel must be built with the CONFIG_PCI_MSI
+option enabled.  This option is only available on some architectures,
+and it may depend on some other options also being set.  For example,
+on x86, you must also enable X86_UP_APIC or SMP in order to see the
+CONFIG_PCI_MSI option.
+
+4.2 Using MSI
+
+Most of the hard work is done for the driver in the PCI layer.  It simply
+has to request that the PCI layer set up the MSI capability for this
+device.
+
+4.2.1 pci_enable_msi
+
+int pci_enable_msi(struct pci_dev *dev)
+
+A successful call will allocate ONE interrupt to the device, regardless
+of how many MSIs the device supports.  The device will be switched from
+pin-based interrupt mode to MSI mode.  The dev->irq number is changed
+to a new number which represents the message signaled interrupt.
+This function should be called before the driver calls request_irq()
+since enabling MSIs disables the pin-based IRQ and the driver will not
+receive interrupts on the old interrupt.
+
+4.2.2 pci_enable_msi_block
+
+int pci_enable_msi_block(struct pci_dev *dev, int count)
+
+This variation on the above call allows a device driver to request multiple
+MSIs.  The MSI specification only allows interrupts to be allocated in
+powers of two, up to a maximum of 2^5 (32).
+
+If this function returns 0, it has succeeded in allocating at least as many
+interrupts as the driver requested (it may have allocated more in order
+to satisfy the power-of-two requirement).  In this case, the function
+enables MSI on this device and updates dev->irq to be the lowest of
+the new interrupts assigned to it.  The other interrupts assigned to
+the device are in the range dev->irq to dev->irq + count - 1.
+
+If this function returns a negative number, it indicates an error and
+the driver should not attempt to request any more MSI interrupts for
+this device.  If this function returns a positive number, it will be
+less than 'count' and indicate the number of interrupts that could have
+been allocated.  In neither case will the irq value have been
+updated, nor will the device have been switched into MSI mode.
+
+The device driver must decide what action to take if
+pci_enable_msi_block() returns a value less than the number asked for.
+Some devices can make use of fewer interrupts than the maximum they
+request; in this case the driver should call pci_enable_msi_block()
+again.  Note that it is not guaranteed to succeed, even when the
+'count' has been reduced to the value returned from a previous call to
+pci_enable_msi_block().  This is because there are multiple constraints
+on the number of vectors that can be allocated; pci_enable_msi_block()
+will return as soon as it finds any constraint that doesn't allow the
+call to succeed.
+
+4.2.3 pci_disable_msi
+
+void pci_disable_msi(struct pci_dev *dev)
 
-Argument 'dev' points to the device (pci_dev) structure.
+This function should be used to undo the effect of pci_enable_msi() or
+pci_enable_msi_block().  Calling it restores dev->irq to the pin-based
+interrupt number and frees the previously allocated message signaled
+interrupt(s).  The interrupt may subsequently be assigned to another
+device, so drivers should not cache the value of dev->irq.
 
-Argument 'entries' is a pointer to an array of msix_entry structs.
-The number of entries is indicated in argument 'nvec'.
-struct msix_entry is defined in /driver/pci/msi.h:
+A device driver must always call free_irq() on the interrupt(s)
+for which it has called request_irq() before calling this function.
+Failure to do so will result in a BUG_ON(), the device will be left with
+MSI enabled and will leak its vector.
+
+4.3 Using MSI-X
+
+The MSI-X capability is much more flexible than the MSI capability.
+It supports up to 2048 interrupts, each of which can be controlled
+independently.  To support this flexibility, drivers must use an array of
+`struct msix_entry':
 
 struct msix_entry {
        u16     vector; /* kernel uses to write alloc vector */
        u16     entry; /* driver uses to specify entry */
 };
 
-A device driver is responsible for initializing the field 'entry' of
-each element with a unique entry supported by MSI-X table. Otherwise,
--EINVAL will be returned as a result. A successful return of zero
-indicates the PCI subsystem completed initializing each of the requested
-entries of the MSI-X table with message address and message data.
-Last but not least, the PCI subsystem will write the 1:1
-vector-to-entry mapping into the field 'vector' of each element. A
-device driver is responsible for keeping track of allocated MSI-X
-vectors in its internal data structure.
-
-A return of zero indicates that the number of MSI-X vectors was
-successfully allocated. A return of greater than zero indicates
-MSI-X vector shortage. Or a return of less than zero indicates
-a failure. This failure may be a result of duplicate entries
-specified in second argument, or a result of no available vector,
-or a result of failing to initialize MSI-X table entries.
-
-5.3.3 API pci_disable_msix
+This allows for the device to use these interrupts in a sparse fashion;
+for example it could use interrupts 3 and 1027 and allocate only a
+two-element array.  The driver is expected to fill in the 'entry' value
+in each element of the array to indicate which entries it wants the kernel
+to assign interrupts for.  It is invalid to fill in two entries with the
+same number.
+
+4.3.1 pci_enable_msix
+
+int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
+
+Calling this function asks the PCI subsystem to allocate 'nvec' MSIs.
+The 'entries' argument is a pointer to an array of msix_entry structs
+which should be at least 'nvec' entries in size.  On success, the
+function will return 0 and the device will have been switched into
+MSI-X interrupt mode.  The 'vector' elements in each entry will have
+been filled in with the interrupt number.  The driver should then call
+request_irq() for each 'vector' that it decides to use.
+
+If this function returns a negative number, it indicates an error and
+the driver should not attempt to allocate any more MSI-X interrupts for
+this device.  If it returns a positive number, it indicates the maximum
+number of interrupt vectors that could have been allocated. See example
+below.
+
+This function, in contrast with pci_enable_msi(), does not adjust
+dev->irq.  The device will not generate interrupts for this interrupt
+number once MSI-X is enabled.  The device driver is responsible for
+keeping track of the interrupts assigned to the MSI-X vectors so it can
+free them again later.
+
+Device drivers should normally call this function once per device
+during the initialization phase.
+
+It is ideal if drivers can cope with a variable number of MSI-X interrupts,
+there are many reasons why the platform may not be able to provide the
+exact number a driver asks for.
+
+A request loop to achieve that might look like:
+
+static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
+{
+       while (nvec >= FOO_DRIVER_MINIMUM_NVEC) {
+               rc = pci_enable_msix(adapter->pdev,
+                                    adapter->msix_entries, nvec);
+               if (rc > 0)
+                       nvec = rc;
+               else
+                       return rc;
+       }
+
+       return -ENOSPC;
+}
+
+4.3.2 pci_disable_msix
 
 void pci_disable_msix(struct pci_dev *dev)
 
-This API should always be used to undo the effect of pci_enable_msix()
-when a device driver is unloading. Note that a device driver should
-always call free_irq() on all MSI-X vectors it has done request_irq()
-on before calling this API. Failure to do so results in a BUG_ON() and
-a device will be left with MSI-X enabled and leaks its vectors.
-
-5.3.4 MSI-X mode vs. legacy mode diagram
-
-The below diagram shows the events which switch the interrupt
-mode on the MSI-X capable device function between MSI-X mode and
-PIN-IRQ assertion mode (legacy).
-
-        ------------   pci_enable_msix(,,n) ------------------------
-       |            | <===============     |                        |
-       | MSI-X MODE |                      | PIN-IRQ ASSERTION MODE |
-       |            | ===============>     |                        |
-        ------------   pci_disable_msix     ------------------------
-
-Figure 2. MSI-X Mode vs. Legacy Mode
-
-In Figure 2, a device operates by default in legacy mode. A
-successful MSI-X request (using pci_enable_msix()) switches a
-device's interrupt mode to MSI-X mode. A pre-assigned IOAPIC vector
-stored in dev->irq will be saved by the PCI subsystem; however,
-unlike MSI mode, the PCI subsystem will not replace dev->irq with
-assigned MSI-X vector because the PCI subsystem already writes the 1:1
-vector-to-entry mapping into the field 'vector' of each element
-specified in second argument.
-
-To return back to its default mode, a device driver should always call
-pci_disable_msix() to undo the effect of pci_enable_msix(). Note that
-a device driver should always call free_irq() on all MSI-X vectors it
-has done request_irq() on before calling pci_disable_msix(). Failure
-to do so results in a BUG_ON() and a device will be left with MSI-X
-enabled and leaks its vectors. Otherwise, the PCI subsystem switches a
-device function's interrupt mode from MSI-X mode to legacy mode and
-marks all allocated MSI-X vectors as unused.
-
-Once being marked as unused, there is no guarantee that the PCI
-subsystem will reserve these MSI-X vectors for a device. Depending on
-the availability of current PCI vector resources and the number of
-MSI/MSI-X requests from other drivers, these MSI-X vectors may be
-re-assigned.
-
-For the case where the PCI subsystem re-assigned these MSI-X vectors
-to other drivers, a request to switch back to MSI-X mode may result
-being assigned with another set of MSI-X vectors or a failure if no
-more vectors are available.
-
-5.4 Handling function implementing both MSI and MSI-X capabilities
-
-For the case where a function implements both MSI and MSI-X
-capabilities, the PCI subsystem enables a device to run either in MSI
-mode or MSI-X mode but not both. A device driver determines whether it
-wants MSI or MSI-X enabled on its hardware device. Once a device
-driver requests for MSI, for example, it is prohibited from requesting
-MSI-X; in other words, a device driver is not permitted to ping-pong
-between MSI mod MSI-X mode during a run-time.
-
-5.5 Hardware requirements for MSI/MSI-X support
-
-MSI/MSI-X support requires support from both system hardware and
-individual hardware device functions.
-
-5.5.1 Required x86 hardware support
-
-Since the target of MSI address is the local APIC CPU, enabling
-MSI/MSI-X support in the Linux kernel is dependent on whether existing
-system hardware supports local APIC. Users should verify that their
-system supports local APIC operation by testing that it runs when
-CONFIG_X86_LOCAL_APIC=y.
-
-In SMP environment, CONFIG_X86_LOCAL_APIC is automatically set;
-however, in UP environment, users must manually set
-CONFIG_X86_LOCAL_APIC. Once CONFIG_X86_LOCAL_APIC=y, setting
-CONFIG_PCI_MSI enables the VECTOR based scheme and the option for
-MSI-capable device drivers to selectively enable MSI/MSI-X.
-
-Note that CONFIG_X86_IO_APIC setting is irrelevant because MSI/MSI-X
-vector is allocated new during runtime and MSI/MSI-X support does not
-depend on BIOS support. This key independency enables MSI/MSI-X
-support on future IOxAPIC free platforms.
-
-5.5.2 Device hardware support
-
-The hardware device function supports MSI by indicating the
-MSI/MSI-X capability structure on its PCI capability list. By
-default, this capability structure will not be initialized by
-the kernel to enable MSI during the system boot. In other words,
-the device function is running on its default pin assertion mode.
-Note that in many cases the hardware supporting MSI have bugs,
-which may result in system hangs. The software driver of specific
-MSI-capable hardware is responsible for deciding whether to call
-pci_enable_msi or not. A return of zero indicates the kernel
-successfully initialized the MSI/MSI-X capability structure of the
-device function. The device function is now running on MSI/MSI-X mode.
-
-5.6 How to tell whether MSI/MSI-X is enabled on device function
-
-At the driver level, a return of zero from the function call of
-pci_enable_msi()/pci_enable_msix() indicates to a device driver that
-its device function is initialized successfully and ready to run in
-MSI/MSI-X mode.
-
-At the user level, users can use the command 'cat /proc/interrupts'
-to display the vectors allocated for devices and their interrupt
-MSI/MSI-X modes ("PCI-MSI"/"PCI-MSI-X"). Below shows MSI mode is
-enabled on a SCSI Adaptec 39320D Ultra320 controller.
-
-           CPU0       CPU1
-  0:     324639          0    IO-APIC-edge  timer
-  1:       1186          0    IO-APIC-edge  i8042
-  2:          0          0          XT-PIC  cascade
- 12:       2797          0    IO-APIC-edge  i8042
- 14:       6543          0    IO-APIC-edge  ide0
- 15:          1          0    IO-APIC-edge  ide1
-169:          0          0   IO-APIC-level  uhci-hcd
-185:          0          0   IO-APIC-level  uhci-hcd
-193:        138         10         PCI-MSI  aic79xx
-201:         30          0         PCI-MSI  aic79xx
-225:         30          0   IO-APIC-level  aic7xxx
-233:         30          0   IO-APIC-level  aic7xxx
-NMI:          0          0
-LOC:     324553     325068
-ERR:          0
-MIS:          0
-
-6. MSI quirks
-
-Several PCI chipsets or devices are known to not support MSI.
-The PCI stack provides 3 possible levels of MSI disabling:
-* on a single device
-* on all devices behind a specific bridge
-* globally
-
-6.1. Disabling MSI on a single device
-
-Under some circumstances it might be required to disable MSI on a
-single device.  This may be achieved by either not calling pci_enable_msi()
-or all, or setting the pci_dev->no_msi flag before (most of the time
-in a quirk).
-
-6.2. Disabling MSI below a bridge
-
-The vast majority of MSI quirks are required by PCI bridges not
-being able to route MSI between busses. In this case, MSI have to be
-disabled on all devices behind this bridge. It is achieves by setting
-the PCI_BUS_FLAGS_NO_MSI flag in the pci_bus->bus_flags of the bridge
-subordinate bus. There is no need to set the same flag on bridges that
-are below the broken bridge. When pci_enable_msi() is called to enable
-MSI on a device, pci_msi_supported() takes care of checking the NO_MSI
-flag in all parent busses of the device.
-
-Some bridges actually support dynamic MSI support enabling/disabling
-by changing some bits in their PCI configuration space (especially
-the Hypertransport chipsets such as the nVidia nForce and Serverworks
-HT2000). It may then be required to update the NO_MSI flag on the
-corresponding devices in the sysfs hierarchy. To enable MSI support
-on device "0000:00:0e", do:
-
-       echo 1 > /sys/bus/pci/devices/0000:00:0e/msi_bus
-
-To disable MSI support, echo 0 instead of 1. Note that it should be
-used with caution since changing this value might break interrupts.
-
-6.3. Disabling MSI globally
-
-Some extreme cases may require to disable MSI globally on the system.
-For now, the only known case is a Serverworks PCI-X chipsets (MSI are
-not supported on several busses that are not all connected to the
-chipset in the Linux PCI hierarchy). In the vast majority of other
-cases, disabling only behind a specific bridge is enough.
-
-For debugging purpose, the user may also pass pci=nomsi on the kernel
-command-line to explicitly disable MSI globally. But, once the appro-
-priate quirks are added to the kernel, this option should not be
-required anymore.
-
-6.4. Finding why MSI cannot be enabled on a device
-
-Assuming that MSI are not enabled on a device, you should look at
-dmesg to find messages that quirks may output when disabling MSI
-on some devices, some bridges or even globally.
-Then, lspci -t gives the list of bridges above a device. Reading
-/sys/bus/pci/devices/0000:00:0e/msi_bus will tell you whether MSI
-are enabled (1) or disabled (0). In 0 is found in a single bridge
-msi_bus file above the device, MSI cannot be enabled.
-
-7. FAQ
-
-Q1. Are there any limitations on using the MSI?
-
-A1. If the PCI device supports MSI and conforms to the
-specification and the platform supports the APIC local bus,
-then using MSI should work.
-
-Q2. Will it work on all the Pentium processors (P3, P4, Xeon,
-AMD processors)? In P3 IPI's are transmitted on the APIC local
-bus and in P4 and Xeon they are transmitted on the system
-bus. Are there any implications with this?
-
-A2. MSI support enables a PCI device sending an inbound
-memory write (0xfeexxxxx as target address) on its PCI bus
-directly to the FSB. Since the message address has a
-redirection hint bit cleared, it should work.
-
-Q3. The target address 0xfeexxxxx will be translated by the
-Host Bridge into an interrupt message. Are there any
-limitations on the chipsets such as Intel 8xx, Intel e7xxx,
-or VIA?
-
-A3. If these chipsets support an inbound memory write with
-target address set as 0xfeexxxxx, as conformed to PCI
-specification 2.3 or latest, then it should work.
-
-Q4. From the driver point of view, if the MSI is lost because
-of errors occurring during inbound memory write, then it may
-wait forever. Is there a mechanism for it to recover?
-
-A4. Since the target of the transaction is an inbound memory
-write, all transaction termination conditions (Retry,
-Master-Abort, Target-Abort, or normal completion) are
-supported. A device sending an MSI must abide by all the PCI
-rules and conditions regarding that inbound memory write. So,
-if a retry is signaled it must retry, etc... We believe that
-the recommendation for Abort is also a retry (refer to PCI
-specification 2.3 or latest).
+This API should be used to undo the effect of pci_enable_msix().  It frees
+the previously allocated message signaled interrupts.  The interrupts may
+subsequently be assigned to another device, so drivers should not cache
+the value of the 'vector' elements over a call to pci_disable_msix().
+
+A device driver must always call free_irq() on the interrupt(s)
+for which it has called request_irq() before calling this function.
+Failure to do so will result in a BUG_ON(), the device will be left with
+MSI enabled and will leak its vector.
+
+4.3.3 The MSI-X Table
+
+The MSI-X capability specifies a BAR and offset within that BAR for the
+MSI-X Table.  This address is mapped by the PCI subsystem, and should not
+be accessed directly by the device driver.  If the driver wishes to
+mask or unmask an interrupt, it should call disable_irq() / enable_irq().
+
+4.4 Handling devices implementing both MSI and MSI-X capabilities
+
+If a device implements both MSI and MSI-X capabilities, it can
+run in either MSI mode or MSI-X mode but not both simultaneously.
+This is a requirement of the PCI spec, and it is enforced by the
+PCI layer.  Calling pci_enable_msi() when MSI-X is already enabled or
+pci_enable_msix() when MSI is already enabled will result in an error.
+If a device driver wishes to switch between MSI and MSI-X at runtime,
+it must first quiesce the device, then switch it back to pin-interrupt
+mode, before calling pci_enable_msi() or pci_enable_msix() and resuming
+operation.  This is not expected to be a common operation but may be
+useful for debugging or testing during development.
+
+4.5 Considerations when using MSIs
+
+4.5.1 Choosing between MSI-X and MSI
+
+If your device supports both MSI-X and MSI capabilities, you should use
+the MSI-X facilities in preference to the MSI facilities.  As mentioned
+above, MSI-X supports any number of interrupts between 1 and 2048.
+In constrast, MSI is restricted to a maximum of 32 interrupts (and
+must be a power of two).  In addition, the MSI interrupt vectors must
+be allocated consecutively, so the system may not be able to allocate
+as many vectors for MSI as it could for MSI-X.  On some platforms, MSI
+interrupts must all be targetted at the same set of CPUs whereas MSI-X
+interrupts can all be targetted at different CPUs.
+
+4.5.2 Spinlocks
+
+Most device drivers have a per-device spinlock which is taken in the
+interrupt handler.  With pin-based interrupts or a single MSI, it is not
+necessary to disable interrupts (Linux guarantees the same interrupt will
+not be re-entered).  If a device uses multiple interrupts, the driver
+must disable interrupts while the lock is held.  If the device sends
+a different interrupt, the driver will deadlock trying to recursively
+acquire the spinlock.
+
+There are two solutions.  The first is to take the lock with
+spin_lock_irqsave() or spin_lock_irq() (see
+Documentation/DocBook/kernel-locking).  The second is to specify
+IRQF_DISABLED to request_irq() so that the kernel runs the entire
+interrupt routine with interrupts disabled.
+
+If your MSI interrupt routine does not hold the lock for the whole time
+it is running, the first solution may be best.  The second solution is
+normally preferred as it avoids making two transitions from interrupt
+disabled to enabled and back again.
+
+4.6 How to tell whether MSI/MSI-X is enabled on a device
+
+Using 'lspci -v' (as root) may show some devices with "MSI", "Message
+Signalled Interrupts" or "MSI-X" capabilities.  Each of these capabilities
+has an 'Enable' flag which will be followed with either "+" (enabled)
+or "-" (disabled).
+
+
+5. MSI quirks
+
+Several PCI chipsets or devices are known not to support MSIs.
+The PCI stack provides three ways to disable MSIs:
+
+1. globally
+2. on all devices behind a specific bridge
+3. on a single device
+
+5.1. Disabling MSIs globally
+
+Some host chipsets simply don't support MSIs properly.  If we're
+lucky, the manufacturer knows this and has indicated it in the ACPI
+FADT table.  In this case, Linux will automatically disable MSIs.
+Some boards don't include this information in the table and so we have
+to detect them ourselves.  The complete list of these is found near the
+quirk_disable_all_msi() function in drivers/pci/quirks.c.
+
+If you have a board which has problems with MSIs, you can pass pci=nomsi
+on the kernel command line to disable MSIs on all devices.  It would be
+in your best interests to report the problem to linux-pci@vger.kernel.org
+including a full 'lspci -v' so we can add the quirks to the kernel.
+
+5.2. Disabling MSIs below a bridge
+
+Some PCI bridges are not able to route MSIs between busses properly.
+In this case, MSIs must be disabled on all devices behind the bridge.
+
+Some bridges allow you to enable MSIs by changing some bits in their
+PCI configuration space (especially the Hypertransport chipsets such
+as the nVidia nForce and Serverworks HT2000).  As with host chipsets,
+Linux mostly knows about them and automatically enables MSIs if it can.
+If you have a bridge which Linux doesn't yet know about, you can enable
+MSIs in configuration space using whatever method you know works, then
+enable MSIs on that bridge by doing:
+
+       echo 1 > /sys/bus/pci/devices/$bridge/msi_bus
+
+where $bridge is the PCI address of the bridge you've enabled (eg
+0000:00:0e.0).
+
+To disable MSIs, echo 0 instead of 1.  Changing this value should be
+done with caution as it can break interrupt handling for all devices
+below this bridge.
+
+Again, please notify linux-pci@vger.kernel.org of any bridges that need
+special handling.
+
+5.3. Disabling MSIs on a single device
+
+Some devices are known to have faulty MSI implementations.  Usually this
+is handled in the individual device driver but occasionally it's necessary
+to handle this with a quirk.  Some drivers have an option to disable use
+of MSI.  While this is a convenient workaround for the driver author,
+it is not good practise, and should not be emulated.
+
+5.4. Finding why MSIs are disabled on a device
+
+From the above three sections, you can see that there are many reasons
+why MSIs may not be enabled for a given device.  Your first step should
+be to examine your dmesg carefully to determine whether MSIs are enabled
+for your machine.  You should also check your .config to be sure you
+have enabled CONFIG_PCI_MSI.
+
+Then, 'lspci -t' gives the list of bridges above a device.  Reading
+/sys/bus/pci/devices/*/msi_bus will tell you whether MSI are enabled (1)
+or disabled (0).  If 0 is found in any of the msi_bus files belonging
+to bridges between the PCI root and the device, MSIs are disabled.
+
+It is also worth checking the device driver to see whether it supports MSIs.
+For example, it may contain calls to pci_enable_msi(), pci_enable_msix() or
+pci_enable_msi_block().
diff --git a/Documentation/PCI/pci-iov-howto.txt b/Documentation/PCI/pci-iov-howto.txt
new file mode 100644 (file)
index 0000000..fc73ef5
--- /dev/null
@@ -0,0 +1,99 @@
+               PCI Express I/O Virtualization Howto
+               Copyright (C) 2009 Intel Corporation
+                   Yu Zhao <yu.zhao@intel.com>
+
+
+1. Overview
+
+1.1 What is SR-IOV
+
+Single Root I/O Virtualization (SR-IOV) is a PCI Express Extended
+capability which makes one physical device appear as multiple virtual
+devices. The physical device is referred to as Physical Function (PF)
+while the virtual devices are referred to as Virtual Functions (VF).
+Allocation of the VF can be dynamically controlled by the PF via
+registers encapsulated in the capability. By default, this feature is
+not enabled and the PF behaves as traditional PCIe device. Once it's
+turned on, each VF's PCI configuration space can be accessed by its own
+Bus, Device and Function Number (Routing ID). And each VF also has PCI
+Memory Space, which is used to map its register set. VF device driver
+operates on the register set so it can be functional and appear as a
+real existing PCI device.
+
+2. User Guide
+
+2.1 How can I enable SR-IOV capability
+
+The device driver (PF driver) will control the enabling and disabling
+of the capability via API provided by SR-IOV core. If the hardware
+has SR-IOV capability, loading its PF driver would enable it and all
+VFs associated with the PF.
+
+2.2 How can I use the Virtual Functions
+
+The VF is treated as hot-plugged PCI devices in the kernel, so they
+should be able to work in the same way as real PCI devices. The VF
+requires device driver that is same as a normal PCI device's.
+
+3. Developer Guide
+
+3.1 SR-IOV API
+
+To enable SR-IOV capability:
+       int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
+       'nr_virtfn' is number of VFs to be enabled.
+
+To disable SR-IOV capability:
+       void pci_disable_sriov(struct pci_dev *dev);
+
+To notify SR-IOV core of Virtual Function Migration:
+       irqreturn_t pci_sriov_migration(struct pci_dev *dev);
+
+3.2 Usage example
+
+Following piece of code illustrates the usage of the SR-IOV API.
+
+static int __devinit dev_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       pci_enable_sriov(dev, NR_VIRTFN);
+
+       ...
+
+       return 0;
+}
+
+static void __devexit dev_remove(struct pci_dev *dev)
+{
+       pci_disable_sriov(dev);
+
+       ...
+}
+
+static int dev_suspend(struct pci_dev *dev, pm_message_t state)
+{
+       ...
+
+       return 0;
+}
+
+static int dev_resume(struct pci_dev *dev)
+{
+       ...
+
+       return 0;
+}
+
+static void dev_shutdown(struct pci_dev *dev)
+{
+       ...
+}
+
+static struct pci_driver dev_driver = {
+       .name =         "SR-IOV Physical Function driver",
+       .id_table =     dev_id_table,
+       .probe =        dev_probe,
+       .remove =       __devexit_p(dev_remove),
+       .suspend =      dev_suspend,
+       .resume =       dev_resume,
+       .shutdown =     dev_shutdown,
+};
index 989c2fcd8111719ce5cc5a4351a03ec93e999e38..629c92e99783ecb7934ee00cf42c4a9f8556004f 100644 (file)
@@ -184,14 +184,16 @@ length. Single character labels using special characters, that being anything
 other than a letter or digit, are reserved for use by the Smack development
 team. Smack labels are unstructured, case sensitive, and the only operation
 ever performed on them is comparison for equality. Smack labels cannot
-contain unprintable characters or the "/" (slash) character.
+contain unprintable characters or the "/" (slash) character. Smack labels
+cannot begin with a '-', which is reserved for special options.
 
 There are some predefined labels:
 
-       _ Pronounced "floor", a single underscore character.
-       ^ Pronounced "hat", a single circumflex character.
-       * Pronounced "star", a single asterisk character.
-       ? Pronounced "huh", a single question mark character.
+       _       Pronounced "floor", a single underscore character.
+       ^       Pronounced "hat", a single circumflex character.
+       *       Pronounced "star", a single asterisk character.
+       ?       Pronounced "huh", a single question mark character.
+       @       Pronounced "Internet", a single at sign character.
 
 Every task on a Smack system is assigned a label. System tasks, such as
 init(8) and systems daemons, are run with the floor ("_") label. User tasks
@@ -412,6 +414,36 @@ sockets.
        A privileged program may set this to match the label of another
        task with which it hopes to communicate.
 
+Smack Netlabel Exceptions
+
+You will often find that your labeled application has to talk to the outside,
+unlabeled world. To do this there's a special file /smack/netlabel where you can
+add some exceptions in the form of :
+@IP1      LABEL1 or
+@IP2/MASK  LABEL2
+
+It means that your application will have unlabeled access to @IP1 if it has
+write access on LABEL1, and access to the subnet @IP2/MASK if it has write
+access on LABEL2.
+
+Entries in the /smack/netlabel file are matched by longest mask first, like in
+classless IPv4 routing.
+
+A special label '@' and an option '-CIPSO' can be used there :
+@      means Internet, any application with any label has access to it
+-CIPSO means standard CIPSO networking
+
+If you don't know what CIPSO is and don't plan to use it, you can just do :
+echo 127.0.0.1 -CIPSO > /smack/netlabel
+echo 0.0.0.0/0 @      > /smack/netlabel
+
+If you use CIPSO on your 192.168.0.0/16 local network and need also unlabeled
+Internet access, you can have :
+echo 127.0.0.1      -CIPSO > /smack/netlabel
+echo 192.168.0.0/16 -CIPSO > /smack/netlabel
+echo 0.0.0.0/0      @      > /smack/netlabel
+
+
 Writing Applications for Smack
 
 There are three sorts of applications that will run on a Smack system. How an
index 93feb8444489686b1a9874da9c964f388d5ed316..4ea852345a474aa802335a964accb4ab78731822 100644 (file)
@@ -333,12 +333,23 @@ The "xxx" is not interpreted by the cgroup code, but will appear in
 
 To mount a cgroup hierarchy with just the cpuset and numtasks
 subsystems, type:
-# mount -t cgroup -o cpuset,numtasks hier1 /dev/cgroup
+# mount -t cgroup -o cpuset,memory hier1 /dev/cgroup
 
 To change the set of subsystems bound to a mounted hierarchy, just
 remount with different options:
+# mount -o remount,cpuset,ns hier1 /dev/cgroup
 
-# mount -o remount,cpuset,ns  /dev/cgroup
+Now memory is removed from the hierarchy and ns is added.
+
+Note this will add ns to the hierarchy but won't remove memory or
+cpuset, because the new options are appended to the old ones:
+# mount -o remount,ns /dev/cgroup
+
+To Specify a hierarchy's release_agent:
+# mount -t cgroup -o cpuset,release_agent="/sbin/cpuset_release_agent" \
+  xxx /dev/cgroup
+
+Note that specifying 'release_agent' more than once will return failure.
 
 Note that changing the set of subsystems is currently only supported
 when the hierarchy consists of a single (root) cgroup. Supporting
@@ -349,6 +360,11 @@ Then under /dev/cgroup you can find a tree that corresponds to the
 tree of the cgroups in the system. For instance, /dev/cgroup
 is the cgroup that holds the whole system.
 
+If you want to change the value of release_agent:
+# echo "/sbin/new_release_agent" > /dev/cgroup/release_agent
+
+It can also be changed via remount.
+
 If you want to create a new cgroup under /dev/cgroup:
 # cd /dev/cgroup
 # mkdir my_cgroup
@@ -476,11 +492,13 @@ cgroup->parent is still valid. (Note - can also be called for a
 newly-created cgroup if an error occurs after this subsystem's
 create() method has been called for the new cgroup).
 
-void pre_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp);
+int pre_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp);
 
 Called before checking the reference count on each subsystem. This may
 be useful for subsystems which have some extra references even if
-there are not tasks in the cgroup.
+there are not tasks in the cgroup. If pre_destroy() returns error code,
+rmdir() will fail with it. From this behavior, pre_destroy() can be
+called multiple times against a cgroup.
 
 int can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
               struct task_struct *task)
index 523a9c16c400526e31d05a1aadee8164ef768800..8a11caf417a06777d48cfe9afe5517cd3925cb15 100644 (file)
@@ -1,5 +1,5 @@
 Memory Resource Controller(Memcg)  Implementation Memo.
-Last Updated: 2009/1/19
+Last Updated: 2009/1/20
 Base Kernel Version: based on 2.6.29-rc2.
 
 Because VM is getting complex (one of reasons is memcg...), memcg's behavior
@@ -360,3 +360,21 @@ Under below explanation, we assume CONFIG_MEM_RES_CTRL_SWAP=y.
        # kill malloc task.
 
        Of course, tmpfs v.s. swapoff test should be tested, too.
+
+ 9.8 OOM-Killer
+       Out-of-memory caused by memcg's limit will kill tasks under
+       the memcg. When hierarchy is used, a task under hierarchy
+       will be killed by the kernel.
+       In this case, panic_on_oom shouldn't be invoked and tasks
+       in other groups shouldn't be killed.
+
+       It's not difficult to cause OOM under memcg as following.
+       Case A) when you can swapoff
+       #swapoff -a
+       #echo 50M > /memory.limit_in_bytes
+       run 51M of malloc
+
+       Case B) when you use mem+swap limitation.
+       #echo 50M > memory.limit_in_bytes
+       #echo 50M > memory.memsw.limit_in_bytes
+       run 51M of malloc
index f2e908d7f90d104fd23d166279f52a180afda822..2f21ecd4c205fefcefd870abe5c415b49a1b5253 100644 (file)
@@ -25,7 +25,7 @@ use IO::Handle;
                "tda10046lifeview", "av7110", "dec2000t", "dec2540t",
                "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
                "or51211", "or51132_qam", "or51132_vsb", "bluebird",
-               "opera1");
+               "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2" );
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -37,8 +37,8 @@ for ($i=0; $i < scalar(@components); $i++) {
        $outfile = eval($cid);
        die $@ if $@;
        print STDERR <<EOF;
-Firmware $outfile extracted successfully.
-Now copy it to either /usr/lib/hotplug/firmware or /lib/firmware
+Firmware(s) $outfile extracted successfully.
+Now copy it(they) to either /usr/lib/hotplug/firmware or /lib/firmware
 (depending on configuration of firmware hotplug).
 EOF
        exit(0);
@@ -345,6 +345,85 @@ sub or51211 {
     $fwfile;
 }
 
+sub cx231xx {
+    my $fwfile = "v4l-cx231xx-avcore-01.fw";
+    my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
+    my $hash = "7d3bb956dc9df0eafded2b56ba57cc42";
+
+    checkstandard();
+
+    wgetfile($fwfile, $url);
+    verify($fwfile, $hash);
+
+    $fwfile;
+}
+
+sub cx18 {
+    my $url = "http://linuxtv.org/downloads/firmware/";
+
+    my %files = (
+       'v4l-cx23418-apu.fw' => '588f081b562f5c653a3db1ad8f65939a',
+       'v4l-cx23418-cpu.fw' => 'b6c7ed64bc44b1a6e0840adaeac39d79',
+       'v4l-cx23418-dig.fw' => '95bc688d3e7599fd5800161e9971cc55',
+    );
+
+    checkstandard();
+
+    my $allfiles;
+    foreach my $fwfile (keys %files) {
+       wgetfile($fwfile, "$url/$fwfile");
+       verify($fwfile, $files{$fwfile});
+       $allfiles .= " $fwfile";
+    }
+
+    $allfiles =~ s/^\s//;
+
+    $allfiles;
+}
+
+sub cx23885 {
+    my $url = "http://linuxtv.org/downloads/firmware/";
+
+    my %files = (
+       'v4l-cx23885-avcore-01.fw' => 'a9f8f5d901a7fb42f552e1ee6384f3bb',
+       'v4l-cx23885-enc.fw'       => 'a9f8f5d901a7fb42f552e1ee6384f3bb',
+    );
+
+    checkstandard();
+
+    my $allfiles;
+    foreach my $fwfile (keys %files) {
+       wgetfile($fwfile, "$url/$fwfile");
+       verify($fwfile, $files{$fwfile});
+       $allfiles .= " $fwfile";
+    }
+
+    $allfiles =~ s/^\s//;
+
+    $allfiles;
+}
+
+sub pvrusb2 {
+    my $url = "http://linuxtv.org/downloads/firmware/";
+
+    my %files = (
+       'v4l-cx25840.fw'           => 'dadb79e9904fc8af96e8111d9cb59320',
+    );
+
+    checkstandard();
+
+    my $allfiles;
+    foreach my $fwfile (keys %files) {
+       wgetfile($fwfile, "$url/$fwfile");
+       verify($fwfile, $files{$fwfile});
+       $allfiles .= " $fwfile";
+    }
+
+    $allfiles =~ s/^\s//;
+
+    $allfiles;
+}
+
 sub or51132_qam {
     my $fwfile = "dvb-fe-or51132-qam.fw";
     my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
index caabbd395e6194c117444e538605af9582c7c392..a618fd99c9f0164298cd343ce404d04f3d38cd40 100644 (file)
@@ -11,8 +11,6 @@ aty128fb.txt
        - info on the ATI Rage128 frame buffer driver.
 cirrusfb.txt
        - info on the driver for Cirrus Logic chipsets.
-cyblafb/
-       - directory with documentation files related to the cyblafb driver.
 deferred_io.txt
        - an introduction to deferred IO.
 fbcon.txt
diff --git a/Documentation/fb/cyblafb/bugs b/Documentation/fb/cyblafb/bugs
deleted file mode 100644 (file)
index 9443a6d..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Bugs
-====
-
-I currently don't know of any bug. Please do send reports to:
- - linux-fbdev-devel@lists.sourceforge.net
- - Knut_Petersen@t-online.de.
-
-
-Untested features
-=================
-
-All LCD stuff is untested. If it worked in tridentfb, it should work in
-cyblafb. Please test and report the results to Knut_Petersen@t-online.de.
diff --git a/Documentation/fb/cyblafb/credits b/Documentation/fb/cyblafb/credits
deleted file mode 100644 (file)
index 0eb3b44..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Thanks to
-=========
-   *   Alan Hourihane, for writing the X trident driver
-   *   Jani Monoses, for writing the tridentfb driver
-   *   Antonino A. Daplas, for review of the first published
-       version of cyblafb and some code
-   *   Jochen Hein, for testing and a helpfull bug report
diff --git a/Documentation/fb/cyblafb/documentation b/Documentation/fb/cyblafb/documentation
deleted file mode 100644 (file)
index bb1aac0..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-Available Documentation
-=======================
-
-Apollo PLE 133 Chipset VT8601A North Bridge Datasheet, Rev. 1.82, October 22,
-2001, available from VIA:
-
-       http://www.viavpsd.com/product/6/15/DS8601A182.pdf
-
-The datasheet is incomplete, some registers that need to be programmed are not
-explained at all and important bits are listed as "reserved". But you really
-need the datasheet to understand the code.  "p. xxx" comments refer to page
-numbers of this document.
-
-XFree/XOrg drivers are available and of good quality, looking at the code
-there is a good idea if the datasheet does not provide enough information
-or if the datasheet seems to be wrong.
-
diff --git a/Documentation/fb/cyblafb/fb.modes b/Documentation/fb/cyblafb/fb.modes
deleted file mode 100644 (file)
index fe0e522..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-#
-#   Sample fb.modes file
-#
-#      Provides an incomplete list of working modes for
-#      the cyberblade/i1 graphics core.
-#
-#      The value 4294967256 is used instead of -40. Of course, -40 is not
-#      a really reasonable value, but chip design does not always follow
-#      logic. Believe me, it's ok, and it's the way the BIOS does it.
-#
-#      fbset requires 4294967256 in fb.modes and -40 as an argument to
-#      the -t parameter. That's also not too reasonable, and it might change
-#      in the future or might even be differt for your current version.
-#
-
-mode "640x480-50"
-    geometry 640 480 2048 4096 8
-    timings 47619 4294967256 24 17 0 216 3
-endmode
-
-mode "640x480-60"
-    geometry 640 480 2048 4096 8
-    timings 39682 4294967256 24 17 0 216 3
-endmode
-
-mode "640x480-70"
-    geometry 640 480 2048 4096 8
-    timings 34013 4294967256 24 17 0 216 3
-endmode
-
-mode "640x480-72"
-    geometry 640 480 2048 4096 8
-    timings 33068 4294967256 24 17 0 216 3
-endmode
-
-mode "640x480-75"
-    geometry 640 480 2048 4096 8
-    timings 31746 4294967256 24 17 0 216 3
-endmode
-
-mode "640x480-80"
-    geometry 640 480 2048 4096 8
-    timings 29761 4294967256 24 17 0 216 3
-endmode
-
-mode "640x480-85"
-    geometry 640 480 2048 4096 8
-    timings 28011 4294967256 24 17 0 216 3
-endmode
-
-mode "800x600-50"
-    geometry 800 600 2048 4096 8
-    timings 30303 96 24 14 0 136 11
-endmode
-
-mode "800x600-60"
-    geometry 800 600 2048 4096 8
-    timings 25252 96 24 14 0 136 11
-endmode
-
-mode "800x600-70"
-    geometry 800 600 2048 4096 8
-    timings 21645 96 24 14 0 136 11
-endmode
-
-mode "800x600-72"
-    geometry 800 600 2048 4096 8
-    timings 21043 96 24 14 0 136 11
-endmode
-
-mode "800x600-75"
-    geometry 800 600 2048 4096 8
-    timings 20202 96 24 14 0 136 11
-endmode
-
-mode "800x600-80"
-    geometry 800 600 2048 4096 8
-    timings 18939 96 24 14 0 136 11
-endmode
-
-mode "800x600-85"
-    geometry 800 600 2048 4096 8
-    timings 17825 96 24 14 0 136 11
-endmode
-
-mode "1024x768-50"
-    geometry 1024 768 2048 4096 8
-    timings 19054 144 24 29 0 120 3
-endmode
-
-mode "1024x768-60"
-    geometry 1024 768 2048 4096 8
-    timings 15880 144 24 29 0 120 3
-endmode
-
-mode "1024x768-70"
-    geometry 1024 768 2048 4096 8
-    timings 13610 144 24 29 0 120 3
-endmode
-
-mode "1024x768-72"
-    geometry 1024 768 2048 4096 8
-    timings 13232 144 24 29 0 120 3
-endmode
-
-mode "1024x768-75"
-    geometry 1024 768 2048 4096 8
-    timings 12703 144 24 29 0 120 3
-endmode
-
-mode "1024x768-80"
-    geometry 1024 768 2048 4096 8
-    timings 11910 144 24 29 0 120 3
-endmode
-
-mode "1024x768-85"
-    geometry 1024 768 2048 4096 8
-    timings 11209 144 24 29 0 120 3
-endmode
-
-mode "1280x1024-50"
-    geometry 1280 1024 2048 4096 8
-    timings 11114 232 16 39 0 160 3
-endmode
-
-mode "1280x1024-60"
-    geometry 1280 1024 2048 4096 8
-    timings 9262 232 16 39 0 160 3
-endmode
-
-mode "1280x1024-70"
-    geometry 1280 1024 2048 4096 8
-    timings 7939 232 16 39 0 160 3
-endmode
-
-mode "1280x1024-72"
-    geometry 1280 1024 2048 4096 8
-    timings 7719 232 16 39 0 160 3
-endmode
-
-mode "1280x1024-75"
-    geometry 1280 1024 2048 4096 8
-    timings 7410 232 16 39 0 160 3
-endmode
-
-mode "1280x1024-80"
-    geometry 1280 1024 2048 4096 8
-    timings 6946 232 16 39 0 160 3
-endmode
-
-mode "1280x1024-85"
-    geometry 1280 1024 2048 4096 8
-    timings 6538 232 16 39 0 160 3
-endmode
diff --git a/Documentation/fb/cyblafb/performance b/Documentation/fb/cyblafb/performance
deleted file mode 100644 (file)
index 8d15d5d..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-Speed
-=====
-
-CyBlaFB is much faster than tridentfb and vesafb. Compare the performance data
-for mode 1280x1024-[8,16,32]@61 Hz.
-
-Test 1: Cat a file with 2000 lines of 0 characters.
-Test 2: Cat a file with 2000 lines of 80 characters.
-Test 3: Cat a file with 2000 lines of 160 characters.
-
-All values show system time use in seconds, kernel 2.6.12 was used for
-the measurements. 2.6.13 is a bit slower, 2.6.14 hopefully will include a
-patch that speeds up kernel bitblitting a lot ( > 20%).
-
-+-----------+-----------------------------------------------------+
-|          |                   not accelerated                   |
-| TRIDENTFB +-----------------+-----------------+-----------------+
-| of 2.6.12 |     8 bpp      |     16 bpp      |     32 bpp      |
-|          | noypan |   ypan | noypan |   ypan | noypan |   ypan |
-+-----------+--------+--------+--------+--------+--------+--------+
-|    Test 1 |  4.31 |   4.33 |   6.05 |  12.81 |  ----  |  ----  |
-|    Test 2 |  67.94 |  5.44 | 123.16 |  14.79 |  ----  |  ----  |
-|    Test 3 | 131.36 |  6.55 | 240.12 |  16.76 |  ----  |  ----  |
-+-----------+--------+--------+--------+--------+--------+--------+
-|  Comments |                |                 | completely bro- |
-|          |                 |                 | ken, monitor    |
-|          |                 |                 | switches off    |
-+-----------+-----------------+-----------------+-----------------+
-
-
-+-----------+-----------------------------------------------------+
-|          |                     accelerated                     |
-| TRIDENTFB +-----------------+-----------------+-----------------+
-| of 2.6.12 |     8 bpp      |     16 bpp      |     32 bpp      |
-|          | noypan |   ypan | noypan |   ypan | noypan |   ypan |
-+-----------+--------+--------+--------+--------+--------+--------+
-|    Test 1 |  ----  | ----  |  20.62 |   1.22 |  ----  |  ----  |
-|    Test 2 |  ----  | ----  |  22.61 |   3.19 |  ----  |  ----  |
-|    Test 3 |  ----  | ----  |  24.59 |   5.16 |  ----  |  ----  |
-+-----------+--------+--------+--------+--------+--------+--------+
-|  Comments | broken, writing | broken, ok only | completely bro- |
-|          | to wrong places | if bgcolor is   | ken, monitor    |
-|          | on screen + bug | black, bug in   | switches off    |
-|          | in fillrect()   | fillrect()      |                 |
-+-----------+-----------------+-----------------+-----------------+
-
-
-+-----------+-----------------------------------------------------+
-|          |                   not accelerated                   |
-|   VESAFB  +-----------------+-----------------+-----------------+
-| of 2.6.12 |     8 bpp      |     16 bpp      |     32 bpp      |
-|          | noypan |   ypan | noypan |   ypan | noypan |   ypan |
-+-----------+--------+--------+--------+--------+--------+--------+
-|    Test 1 |  4.26 |   3.76 |   5.99 |   7.23 |  ----  |  ----  |
-|    Test 2 |  65.65 |  4.89 | 120.88 |   9.08 |  ----  |  ----  |
-|    Test 3 | 126.91 |  5.94 | 235.77 |  11.03 |  ----  |  ----  |
-+-----------+--------+--------+--------+--------+--------+--------+
-|  Comments | vga=0x307       | vga=0x31a      | vga=0x31b not   |
-|          | fh=80kHz        | fh=80kHz        | supported by    |
-|          | fv=75kHz        | fv=75kHz        | video BIOS and  |
-|          |                 |                 | hardware        |
-+-----------+-----------------+-----------------+-----------------+
-
-
-+-----------+-----------------------------------------------------+
-|          |                     accelerated                     |
-|  CYBLAFB  +-----------------+-----------------+-----------------+
-|          |      8 bpp      |     16 bpp      |     32 bpp      |
-|          | noypan |   ypan | noypan |   ypan | noypan |   ypan |
-+-----------+--------+--------+--------+--------+--------+--------+
-|    Test 1 |  8.02 |   0.23 |  19.04 |   0.61 |  57.12 |   2.74 |
-|    Test 2 |  8.38 |   0.55 |  19.39 |   0.92 |  57.54 |   3.13 |
-|    Test 3 |  8.73 |   0.86 |  19.74 |   1.24 |  57.95 |   3.51 |
-+-----------+--------+--------+--------+--------+--------+--------+
-|  Comments |                |                 |                 |
-|          |                 |                 |                 |
-|          |                 |                 |                 |
-|          |                 |                 |                 |
-+-----------+-----------------+-----------------+-----------------+
diff --git a/Documentation/fb/cyblafb/todo b/Documentation/fb/cyblafb/todo
deleted file mode 100644 (file)
index c5f6d0e..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-TODO / Missing features
-=======================
-
-Verify LCD stuff               "stretch" and "center" options are
-                               completely untested ... this code needs to be
-                               verified. As I don't have access to such
-                               hardware, please contact me if you are
-                               willing run some tests.
-
-Interlaced video modes         The reason that interleaved
-                               modes are disabled is that I do not know
-                               the meaning of the vertical interlace
-                               parameter. Also the datasheet mentions a
-                               bit d8 of a horizontal interlace parameter,
-                               but nowhere the lower 8 bits. Please help
-                               if you can.
-
-low-res double scan modes      Who needs it?
-
-accelerated color blitting     Who needs it? The console driver does use color
-                               blitting for nothing but drawing the penguine,
-                               everything else is done using color expanding
-                               blitting of 1bpp character bitmaps.
-
-ioctls                         Who needs it?
-
-TV-out                         Will be done later. Use "vga= " at boot time
-                               to set a suitable video mode.
-
-???                            Feel free to contact me if you have any
-                               feature requests
diff --git a/Documentation/fb/cyblafb/usage b/Documentation/fb/cyblafb/usage
deleted file mode 100644 (file)
index a39bb3d..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-CyBlaFB is a framebuffer driver for the Cyberblade/i1 graphics core integrated
-into the VIA Apollo PLE133 (aka vt8601) south bridge. It is developed and
-tested using a VIA EPIA 5000 board.
-
-Cyblafb - compiled into the kernel or as a module?
-==================================================
-
-You might compile cyblafb either as a module or compile it permanently into the
-kernel.
-
-Unless you have a real reason to do so you should not compile both vesafb and
-cyblafb permanently into the kernel. It's possible and it helps during the
-developement cycle, but it's useless and will at least block some otherwise
-usefull memory for ordinary users.
-
-Selecting Modes
-===============
-
-       Startup Mode
-       ============
-
-       First of all, you might use the "vga=???" boot parameter as it is
-       documented in vesafb.txt and svga.txt. Cyblafb will detect the video
-       mode selected and will use the geometry and timings found by
-       inspecting the hardware registers.
-
-               video=cyblafb vga=0x317
-
-       Alternatively you might use a combination of the mode, ref and bpp
-       parameters. If you compiled the driver into the kernel, add something
-       like this to the kernel command line:
-
-               video=cyblafb:1280x1024,bpp=16,ref=50 ...
-
-       If you compiled the driver as a module, the same mode would be
-       selected by the following command:
-
-               modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
-
-       None of the modes possible to select as startup modes are affected by
-       the problems described at the end of the next subsection.
-
-       For all startup modes cyblafb chooses a virtual x resolution of 2048,
-       the only exception is mode 1280x1024 in combination with 32 bpp. This
-       allows ywrap scrolling for all those modes if rotation is 0 or 2, and
-       also fast scrolling if rotation is 1 or 3. The default virtual y reso-
-       lution is 4096 for bpp == 8, 2048 for bpp==16 and 1024 for bpp == 32,
-       again with the only exception of 1280x1024 at 32 bpp.
-
-       Please do set your video memory size to 8 Mb in the Bios setup. Other
-       values will work, but performace is decreased for a lot of modes.
-
-       Mode changes using fbset
-       ========================
-
-       You might use fbset to change the video mode, see "man fbset". Cyblafb
-       generally does assume that you know what you are doing. But it does
-       some checks, especially those that are needed to prevent you from
-       damaging your hardware.
-
-               - only 8, 16, 24 and 32 bpp video modes are accepted
-               - interlaced video modes are not accepted
-               - double scan video modes are not accepted
-               - if a flat panel is found, cyblafb does not allow you
-                 to program a resolution higher than the physical
-                 resolution of the flat panel monitor
-               - cyblafb does not allow vclk to exceed 230 MHz. As 32 bpp
-                 and (currently) 24 bit modes use a doubled vclk internally,
-                 the dotclock limit as seen by fbset is 115 MHz for those
-                 modes and 230 MHz for 8 and 16 bpp modes.
-               - cyblafb will allow you to select very high resolutions as
-                 long as the hardware can be programmed to these modes. The
-                 documented limit 1600x1200 is not enforced, but don't expect
-                 perfect signal quality.
-
-       Any request that violates the rules given above will be either changed
-       to something the hardware supports or an error value will be returned.
-
-       If you program a virtual y resolution higher than the hardware limit,
-       cyblafb will silently decrease that value to the highest possible
-       value. The same is true for a virtual x resolution that is not
-       supported by the hardware. Cyblafb tries to adapt vyres first because
-       vxres decides if ywrap scrolling is possible or not.
-
-       Attempts to disable acceleration are ignored, I believe that this is
-       safe.
-
-       Some video modes that should work do not work as expected. If you use
-       the standard fb.modes, fbset 640x480-60 will program that mode, but
-       you will see a vertical area, about two characters wide, with only
-       much darker characters than the other characters on the screen.
-       Cyblafb does allow that mode to be set, as it does not violate the
-       official specifications. It would need a lot of code to reliably sort
-       out all invalid modes, playing around with the margin values will
-       give a valid mode quickly. And if cyblafb would detect such an invalid
-       mode, should it silently alter the requested values or should it
-       report an error? Both options have some pros and cons. As stated
-       above, none of the startup modes are affected, and if you set
-       verbosity to 1 or higher, cyblafb will print the fbset command that
-       would be needed to program that mode using fbset.
-
-
-Other Parameters
-================
-
-
-crt            don't autodetect, assume monitor connected to
-               standard VGA connector
-
-fp             don't autodetect, assume flat panel display
-               connected to flat panel monitor interface
-
-nativex        inform driver about native x resolution of
-               flat panel monitor connected to special
-               interface (should be autodetected)
-
-stretch        stretch image to adapt low resolution modes to
-               higer resolutions of flat panel monitors
-               connected to special interface
-
-center         center image to adapt low resolution modes to
-               higer resolutions of flat panel monitors
-               connected to special interface
-
-memsize        use if autodetected memsize is wrong ...
-               should never be necessary
-
-nopcirr        disable PCI read retry
-nopciwr        disable PCI write retry
-nopcirb        disable PCI read bursts
-nopciwb        disable PCI write bursts
-
-bpp            bpp for specified modes
-               valid values: 8 || 16 || 24 || 32
-
-ref            refresh rate for specified mode
-               valid values: 50 <= ref <= 85
-
-mode           640x480 or 800x600 or 1024x768 or 1280x1024
-               if not specified, the startup mode will be detected
-               and used, so you might also use the vga=??? parameter
-               described in vesafb.txt. If you do not specify a mode,
-               bpp and ref parameters are ignored.
-
-verbosity      0 is the default, increase to at least 2 for every
-               bug report!
-
-Development hints
-=================
-
-It's much faster do compile a module and to load the new version after
-unloading the old module than to compile a new kernel and to reboot. So if you
-try to work on cyblafb, it might be a good idea to use cyblafb as a module.
-In real life, fast often means dangerous, and that's also the case here. If
-you introduce a serious bug when cyblafb is compiled into the kernel, the
-kernel will lock or oops with a high probability before the file system is
-mounted, and the danger for your data is low. If you load a broken own version
-of cyblafb on a running system, the danger for the integrity of the file
-system is much higher as you might need a hard reset afterwards. Decide
-yourself.
-
-Module unloading, the vfb method
-================================
-
-If you want to unload/reload cyblafb using the virtual framebuffer, you need
-to enable vfb support in the kernel first. After that, load the modules as
-shown below:
-
-       modprobe vfb vfb_enable=1
-       modprobe fbcon
-       modprobe cyblafb
-       fbset -fb /dev/fb1 1280x1024-60 -vyres 2662
-       con2fb /dev/fb1 /dev/tty1
-       ...
-
-If you now made some changes to cyblafb and want to reload it, you might do it
-as show below:
-
-       con2fb /dev/fb0 /dev/tty1
-       ...
-       rmmod cyblafb
-       modprobe cyblafb
-       con2fb /dev/fb1 /dev/tty1
-       ...
-
-Of course, you might choose another mode, and most certainly you also want to
-map some other /dev/tty* to the real framebuffer device. You might also choose
-to compile fbcon as a kernel module or place it permanently in the kernel.
-
-I do not know of any way to unload fbcon, and fbcon will prevent the
-framebuffer device loaded first from unloading. [If there is a way, then
-please add a description here!]
-
-Module unloading, the vesafb method
-===================================
-
-Configure the kernel:
-
-       <*> Support for frame buffer devices
-       [*]   VESA VGA graphics support
-       <M>   Cyberblade/i1 support
-
-Add e.g. "video=vesafb:ypan vga=0x307" to the kernel parameters. The ypan
-parameter is important, choose any vga parameter you like as long as it is
-a graphics mode.
-
-After booting, load cyblafb without any mode and bpp parameter and assign
-cyblafb to individual ttys using con2fb, e.g.:
-
-       modprobe cyblafb
-       con2fb /dev/fb1 /dev/tty1
-
-Unloading cyblafb works without problems after you assign vesafb to all
-ttys again, e.g.:
-
-       con2fb /dev/fb0 /dev/tty1
-       rmmod cyblafb
diff --git a/Documentation/fb/cyblafb/whatsnew b/Documentation/fb/cyblafb/whatsnew
deleted file mode 100644 (file)
index 76c07a2..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-0.62
-====
-
-      - the vesafb parameter has been removed as I decided to allow the
-       feature without any special parameter.
-
-      - Cyblafb does not use the vga style of panning any longer, now the
-       "right view" register in the graphics engine IO space is used. Without
-       that change it was impossible to use all available memory, and without
-       access to all available memory it is impossible to ywrap.
-
-      - The imageblit function now uses hardware acceleration for all font
-        widths. Hardware blitting across pixel column 2048 is broken in the
-       cyberblade/i1 graphics core, but we work around that hardware bug.
-
-      - modes with vxres != xres are supported now.
-
-      - ywrap scrolling is supported now and the default. This is a big
-        performance gain.
-
-      - default video modes use vyres > yres and vxres > xres to allow
-        almost optimal scrolling speed for normal and rotated screens
-
-      - some features mainly usefull for debugging the upper layers of the
-        framebuffer system have been added, have a look at the code
-
-      - fixed: Oops after unloading cyblafb when reading /proc/io*
-
-      - we work around some bugs of the higher framebuffer layers.
diff --git a/Documentation/fb/cyblafb/whycyblafb b/Documentation/fb/cyblafb/whycyblafb
deleted file mode 100644 (file)
index a123bc1..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-I tried the following framebuffer drivers:
-
-       - TRIDENTFB is full of bugs. Acceleration is broken for Blade3D
-         graphics cores like the cyberblade/i1. It claims to support a great
-         number of devices, but documentation for most of these devices is
-         unfortunately not available. There is _no_ reason to use tridentfb
-         for cyberblade/i1 + CRT users. VESAFB is faster, and the one
-         advantage, mode switching, is broken in tridentfb.
-
-       - VESAFB is used by many distributions as a standard. Vesafb does
-         not support mode switching. VESAFB is a bit faster than the working
-         configurations of TRIDENTFB, but it is still too slow, even if you
-         use ypan.
-
-       - EPIAFB (you'll find it on sourceforge) supports the Cyberblade/i1
-         graphics core, but it still has serious bugs and developement seems
-         to have stopped. This is the one driver with TV-out support. If you
-         do need this feature, try epiafb.
-
-None of these drivers was a real option for me.
-
-I believe that is unreasonable to change code that announces to support 20
-devices if I only have more or less sufficient documentation for exactly one
-of these. The risk of breaking device foo while fixing device bar is too high.
-
-So I decided to start CyBlaFB as a stripped down tridentfb.
-
-All code specific to other Trident chips has been removed. After that there
-were a lot of cosmetic changes to increase the readability of the code. All
-register names were changed to those mnemonics used in the datasheet. Function
-and macro names were changed if they hindered easy understanding of the code.
-
-After that I debugged the code and implemented some new features. I'll try to
-give a little summary of the main changes:
-
-       - calculation of vertical and horizontal timings was fixed
-
-       - video signal quality has been improved dramatically
-
-       - acceleration:
-
-               - fillrect and copyarea were fixed and reenabled
-
-               - color expanding imageblit was newly implemented, color
-                 imageblit (only used to draw the penguine) still uses the
-                 generic code.
-
-               - init of the acceleration engine was improved and moved to a
-                 place where it really works ...
-
-               - sync function has a timeout now and tries to reset and
-                 reinit the accel engine if necessary
-
-               - fewer slow copyarea calls when doing ypan scrolling by using
-                 undocumented bit d21 of screen start address stored in
-                 CR2B[5]. BIOS does use it also, so this should be safe.
-
-       - cyblafb rejects any attempt to set modes that would cause vclk
-         values above reasonable 230 MHz. 32bit modes use a clock
-         multiplicator of 2, so fbset does show the correct values for
-         pixclock but not for vclk in this case. The fbset limit is 115 MHz
-         for 32 bpp modes.
-
-       - cyblafb rejects modes known to be broken or unimplemented (all
-         interlaced modes, all doublescan modes for now)
-
-       - cyblafb now works independant of the video mode in effect at startup
-         time (tridentfb does not init all needed registers to reasonable
-         values)
-
-       - switching between video modes does work reliably now
-
-       - the first video mode now is the one selected on startup using the
-         vga=???? mechanism or any of
-               - 640x480, 800x600, 1024x768, 1280x1024
-               - 8, 16, 24 or 32 bpp
-               - refresh between 50 Hz and 85 Hz, 1 Hz steps (1280x1024-32
-                 is limited to 63Hz)
-
-       - pci retry and pci burst mode are settable (try to disable if you
-         experience latency problems)
-
-       - built as a module cyblafb might be unloaded and reloaded using
-         the vfb module and con2vt or might be used together with vesafb
-
index 7907586c6e08e4d3b48b4d1b6f2ccf95d54224e4..a23361e80c645835c7ef34b9fc969da22f93bed9 100644 (file)
@@ -64,10 +64,10 @@ Who:        Pavel Machek <pavel@suse.cz>
 
 ---------------------------
 
-What:  Video4Linux API 1 ioctls and video_decoder.h from Video devices.
-When:  December 2008
-Files: include/linux/video_decoder.h include/linux/videodev.h
-Check: include/linux/video_decoder.h include/linux/videodev.h
+What:  Video4Linux API 1 ioctls and from Video devices.
+When:  July 2009
+Files: include/linux/videodev.h
+Check: include/linux/videodev.h
 Why:   V4L1 AP1 was replaced by V4L2 API during migration from 2.4 to 2.6
        series. The old API have lots of drawbacks and don't provide enough
        means to work with all video and audio standards. The newer API is
@@ -255,6 +255,16 @@ Who:       Jan Engelhardt <jengelh@computergmbh.de>
 
 ---------------------------
 
+What:  GPIO autorequest on gpio_direction_{input,output}() in gpiolib
+When:  February 2010
+Why:   All callers should use explicit gpio_request()/gpio_free().
+       The autorequest mechanism in gpiolib was provided mostly as a
+       migration aid for legacy GPIO interfaces (for SOC based GPIOs).
+       Those users have now largely migrated.  Platforms implementing
+       the GPIO interfaces without using gpiolib will see no changes.
+Who:   David Brownell <dbrownell@users.sourceforge.net>
+---------------------------
+
 What:  b43 support for firmware revision < 410
 When:  The schedule was July 2008, but it was decided that we are going to keep the
         code as long as there are no major maintanance headaches.
@@ -311,6 +321,18 @@ Who:       Vlad Yasevich <vladislav.yasevich@hp.com>
 
 ---------------------------
 
+What:  Ability for non root users to shm_get hugetlb pages based on mlock
+       resource limits
+When:  2.6.31
+Why:   Non root users need to be part of /proc/sys/vm/hugetlb_shm_group or
+       have CAP_IPC_LOCK to be able to allocate shm segments backed by
+       huge pages.  The mlock based rlimit check to allow shm hugetlb is
+       inconsistent with mmap based allocations.  Hence it is being
+       deprecated.
+Who:   Ravikiran Thirumalai <kiran@scalex86.org>
+
+---------------------------
+
 What:  CONFIG_THERMAL_HWMON
 When:  January 2009
 Why:   This option was introduced just to allow older lm-sensors userspace
@@ -356,17 +378,6 @@ Who:       Hans de Goede <hdegoede@redhat.com>
 
 ---------------------------
 
-What:  SELinux "compat_net" functionality
-When:  2.6.30 at the earliest
-Why:   In 2.6.18 the Secmark concept was introduced to replace the "compat_net"
-       network access control functionality of SELinux.  Secmark offers both
-       better performance and greater flexibility than the "compat_net"
-       mechanism.  Now that the major Linux distributions have moved to
-       Secmark, it is time to deprecate the older mechanism and start the
-       process of removing the old code.
-Who:   Paul Moore <paul.moore@hp.com>
----------------------------
-
 What:  sysfs ui for changing p4-clockmod parameters
 When:  September 2009
 Why:   See commits 129f8ae9b1b5be94517da76009ea956e89104ce8 and
@@ -391,3 +402,35 @@ Why:       The defines and typedefs (hw_interrupt_type, no_irq_type, irq_desc_t)
        have been kept around for migration reasons. After more than two years
        it's time to remove them finally
 Who:   Thomas Gleixner <tglx@linutronix.de>
+
+---------------------------
+
+What:  fakephp and associated sysfs files in /sys/bus/pci/slots/
+When:  2011
+Why:   In 2.6.27, the semantics of /sys/bus/pci/slots was redefined to
+       represent a machine's physical PCI slots. The change in semantics
+       had userspace implications, as the hotplug core no longer allowed
+       drivers to create multiple sysfs files per physical slot (required
+       for multi-function devices, e.g.). fakephp was seen as a developer's
+       tool only, and its interface changed. Too late, we learned that
+       there were some users of the fakephp interface.
+
+       In 2.6.30, the original fakephp interface was restored. At the same
+       time, the PCI core gained the ability that fakephp provided, namely
+       function-level hot-remove and hot-add.
+
+       Since the PCI core now provides the same functionality, exposed in:
+
+               /sys/bus/pci/rescan
+               /sys/bus/pci/devices/.../remove
+               /sys/bus/pci/devices/.../rescan
+
+       there is no functional reason to maintain fakephp as well.
+
+       We will keep the existing module so that 'modprobe fakephp' will
+       present the old /sys/bus/pci/slots/... interface for compatibility,
+       but users are urged to migrate their applications to the API above.
+
+       After a reasonable transition period, we will remove the legacy
+       fakephp interface.
+Who:   Alex Chiang <achiang@hp.com>
index 4e78ce6778435aacf321de21baffe4095739f2e9..76efe5b71d7d8f744739a129f4b5333b898acf5c 100644 (file)
@@ -505,7 +505,7 @@ prototypes:
        void (*open)(struct vm_area_struct*);
        void (*close)(struct vm_area_struct*);
        int (*fault)(struct vm_area_struct*, struct vm_fault *);
-       int (*page_mkwrite)(struct vm_area_struct *, struct page *);
+       int (*page_mkwrite)(struct vm_area_struct *, struct vm_fault *);
        int (*access)(struct vm_area_struct *, unsigned long, void*, int, int);
 
 locking rules:
index cec829bc7291623da6189de984fedd753ce51450..97882df0486567c229bb0ee867752da15b24089f 100644 (file)
@@ -85,7 +85,7 @@ Note: More extensive information for getting started with ext4 can be
 * extent format more robust in face of on-disk corruption due to magics,
 * internal redundancy in tree
 * improved file allocation (multi-block alloc)
-* fix 32000 subdirectory limit
+* lift 32000 subdirectory limit imposed by i_links_count[1]
 * nsec timestamps for mtime, atime, ctime, create time
 * inode version field on disk (NFSv4, Lustre)
 * reduced e2fsck time via uninit_bg feature
@@ -100,6 +100,9 @@ Note: More extensive information for getting started with ext4 can be
 * efficent new ordered mode in JBD2 and ext4(avoid using buffer head to force
   the ordering)
 
+[1] Filesystems with a block size of 1k may see a limit imposed by the
+directory hash tree having a maximum depth of two.
+
 2.2 Candidate features for future inclusion
 
 * Online defrag (patches available but not well tested)
@@ -180,8 +183,8 @@ commit=nrsec        (*)     Ext4 can be told to sync all its data and metadata
                        performance.
 
 barrier=<0|1(*)>       This enables/disables the use of write barriers in
-                       the jbd code.  barrier=0 disables, barrier=1 enables.
-                       This also requires an IO stack which can support
+barrier(*)             the jbd code.  barrier=0 disables, barrier=1 enables.
+nobarrier              This also requires an IO stack which can support
                        barriers, and if jbd gets an error on a barrier
                        write, it will disable again with a warning.
                        Write barriers enforce proper on-disk ordering
@@ -189,6 +192,9 @@ barrier=<0|1(*)>    This enables/disables the use of write barriers in
                        safe to use, at some performance penalty.  If
                        your disks are battery-backed in one way or another,
                        disabling barriers may safely improve performance.
+                       The mount options "barrier" and "nobarrier" can
+                       also be used to enable or disable barriers, for
+                       consistency with other ext4 mount options.
 
 inode_readahead=n      This tuning parameter controls the maximum
                        number of inode table blocks that ext4's inode
@@ -310,6 +316,24 @@ journal_ioprio=prio        The I/O priority (from 0 to 7, where 0 is the
                        a slightly higher priority than the default I/O
                        priority.
 
+auto_da_alloc(*)       Many broken applications don't use fsync() when 
+noauto_da_alloc                replacing existing files via patterns such as
+                       fd = open("foo.new")/write(fd,..)/close(fd)/
+                       rename("foo.new", "foo"), or worse yet,
+                       fd = open("foo", O_TRUNC)/write(fd,..)/close(fd).
+                       If auto_da_alloc is enabled, ext4 will detect
+                       the replace-via-rename and replace-via-truncate
+                       patterns and force that any delayed allocation
+                       blocks are allocated such that at the next
+                       journal commit, in the default data=ordered
+                       mode, the data blocks of the new file are forced
+                       to disk before the rename() operation is
+                       commited.  This provides roughly the same level
+                       of guarantees as ext3, and avoids the
+                       "zero-length" problem that can happen when a
+                       system crashes before the delayed allocation
+                       blocks are forced to disk.
+
 Data Mode
 =========
 There are 3 different data modes:
index 830bad7cce0f946ba356e7aff283775d270063f1..ce84cfc9eae0a923f7aca7ae1e03797a7a7bea7e 100644 (file)
@@ -5,6 +5,7 @@
                   Bodo Bauer <bb@ricochet.net>
 
 2.4.x update     Jorge Nerin <comandante@zaralinux.com>      November 14 2000
+move /proc/sys   Shen Feng <shen@cn.fujitsu.com>                   April 1 2009
 ------------------------------------------------------------------------------
 Version 1.3                                              Kernel version 2.2.12
                                              Kernel version 2.4.0-test11-pre4
@@ -26,25 +27,17 @@ Table of Contents
   1.6  Parallel port info in /proc/parport
   1.7  TTY info in /proc/tty
   1.8  Miscellaneous kernel statistics in /proc/stat
+  1.9 Ext4 file system parameters
 
   2    Modifying System Parameters
-  2.1  /proc/sys/fs - File system data
-  2.2  /proc/sys/fs/binfmt_misc - Miscellaneous binary formats
-  2.3  /proc/sys/kernel - general kernel parameters
-  2.4  /proc/sys/vm - The virtual memory subsystem
-  2.5  /proc/sys/dev - Device specific parameters
-  2.6  /proc/sys/sunrpc - Remote procedure calls
-  2.7  /proc/sys/net - Networking stuff
-  2.8  /proc/sys/net/ipv4 - IPV4 settings
-  2.9  Appletalk
-  2.10 IPX
-  2.11 /proc/sys/fs/mqueue - POSIX message queues filesystem
-  2.12 /proc/<pid>/oom_adj - Adjust the oom-killer score
-  2.13 /proc/<pid>/oom_score - Display current oom-killer score
-  2.14 /proc/<pid>/io - Display the IO accounting fields
-  2.15 /proc/<pid>/coredump_filter - Core dump filtering settings
-  2.16 /proc/<pid>/mountinfo - Information about mounts
-  2.17 /proc/sys/fs/epoll - Configuration options for the epoll interface
+
+  3    Per-Process Parameters
+  3.1  /proc/<pid>/oom_adj - Adjust the oom-killer score
+  3.2  /proc/<pid>/oom_score - Display current oom-killer score
+  3.3  /proc/<pid>/io - Display the IO accounting fields
+  3.4  /proc/<pid>/coredump_filter - Core dump filtering settings
+  3.5  /proc/<pid>/mountinfo - Information about mounts
+
 
 ------------------------------------------------------------------------------
 Preface
@@ -940,27 +933,6 @@ Table 1-10: Files in /proc/fs/ext4/<devname>
  File            Content                                        
  mb_groups       details of multiblock allocator buddy cache of free blocks
  mb_history      multiblock allocation history
- stats           controls whether the multiblock allocator should start
-                 collecting statistics, which are shown during the unmount
- group_prealloc  the multiblock allocator will round up allocation
-                 requests to a multiple of this tuning parameter if the
-                 stripe size is not set in the ext4 superblock
- max_to_scan     The maximum number of extents the multiblock allocator
-                 will search to find the best extent
- min_to_scan     The minimum number of extents the multiblock allocator
-                 will search to find the best extent
- order2_req      Tuning parameter which controls the minimum size for 
-                 requests (as a power of 2) where the buddy cache is
-                 used
- stream_req      Files which have fewer blocks than this tunable
-                 parameter will have their blocks allocated out of a
-                 block group specific preallocation pool, so that small
-                 files are packed closely together.  Each large file
-                 will have its blocks allocated out of its own unique
-                 preallocation pool.
-inode_readahead  Tuning parameter which controls the maximum number of
-                 inode table blocks that ext4's inode table readahead
-                 algorithm will pre-read into the buffer cache
 ..............................................................................
 
 
@@ -1011,1021 +983,24 @@ review the kernel documentation in the directory /usr/src/linux/Documentation.
 This chapter  is  heavily  based  on the documentation included in the pre 2.2
 kernels, and became part of it in version 2.2.1 of the Linux kernel.
 
-2.1 /proc/sys/fs - File system data
------------------------------------
-
-This subdirectory  contains  specific  file system, file handle, inode, dentry
-and quota information.
-
-Currently, these files are in /proc/sys/fs:
-
-dentry-state
-------------
-
-Status of  the  directory  cache.  Since  directory  entries  are  dynamically
-allocated and  deallocated,  this  file indicates the current status. It holds
-six values, in which the last two are not used and are always zero. The others
-are listed in table 2-1.
-
-
-Table 2-1: Status files of the directory cache 
-..............................................................................
- File       Content                                                            
- nr_dentry  Almost always zero                                                 
- nr_unused  Number of unused cache entries                                     
- age_limit  
-            in seconds after the entry may be reclaimed, when memory is short 
- want_pages internally                                                         
-..............................................................................
-
-dquot-nr and dquot-max
-----------------------
-
-The file dquot-max shows the maximum number of cached disk quota entries.
-
-The file  dquot-nr  shows  the  number of allocated disk quota entries and the
-number of free disk quota entries.
-
-If the number of available cached disk quotas is very low and you have a large
-number of simultaneous system users, you might want to raise the limit.
-
-file-nr and file-max
---------------------
-
-The kernel  allocates file handles dynamically, but doesn't free them again at
-this time.
-
-The value  in  file-max  denotes  the  maximum number of file handles that the
-Linux kernel will allocate. When you get a lot of error messages about running
-out of  file handles, you might want to raise this limit. The default value is
-10% of  RAM in kilobytes.  To  change it, just  write the new number  into the
-file:
-
-  # cat /proc/sys/fs/file-max 
-  4096 
-  # echo 8192 > /proc/sys/fs/file-max 
-  # cat /proc/sys/fs/file-max 
-  8192 
-
-
-This method  of  revision  is  useful  for  all customizable parameters of the
-kernel - simply echo the new value to the corresponding file.
-
-Historically, the three values in file-nr denoted the number of allocated file
-handles,  the number of  allocated but  unused file  handles, and  the maximum
-number of file handles. Linux 2.6 always  reports 0 as the number of free file
-handles -- this  is not an error,  it just means that the  number of allocated
-file handles exactly matches the number of used file handles.
-
-Attempts to  allocate more  file descriptors than  file-max are  reported with
-printk, look for "VFS: file-max limit <number> reached".
-
-inode-state and inode-nr
-------------------------
-
-The file inode-nr contains the first two items from inode-state, so we'll skip
-to that file...
-
-inode-state contains  two  actual numbers and five dummy values. The numbers
-are nr_inodes and nr_free_inodes (in order of appearance).
-
-nr_inodes
-~~~~~~~~~
-
-Denotes the  number  of  inodes the system has allocated. This number will
-grow and shrink dynamically.
-
-nr_open
--------
-
-Denotes the maximum number of file-handles a process can
-allocate. Default value is 1024*1024 (1048576) which should be
-enough for most machines. Actual limit depends on RLIMIT_NOFILE
-resource limit.
-
-nr_free_inodes
---------------
-
-Represents the  number of free inodes. Ie. The number of inuse inodes is
-(nr_inodes - nr_free_inodes).
-
-aio-nr and aio-max-nr
----------------------
-
-aio-nr is the running total of the number of events specified on the
-io_setup system call for all currently active aio contexts.  If aio-nr
-reaches aio-max-nr then io_setup will fail with EAGAIN.  Note that
-raising aio-max-nr does not result in the pre-allocation or re-sizing
-of any kernel data structures.
-
-2.2 /proc/sys/fs/binfmt_misc - Miscellaneous binary formats
------------------------------------------------------------
-
-Besides these  files, there is the subdirectory /proc/sys/fs/binfmt_misc. This
-handles the kernel support for miscellaneous binary formats.
-
-Binfmt_misc provides  the ability to register additional binary formats to the
-Kernel without  compiling  an additional module/kernel. Therefore, binfmt_misc
-needs to  know magic numbers at the beginning or the filename extension of the
-binary.
-
-It works by maintaining a linked list of structs that contain a description of
-a binary  format,  including  a  magic  with size (or the filename extension),
-offset and  mask,  and  the  interpreter name. On request it invokes the given
-interpreter with  the  original  program  as  argument,  as  binfmt_java  and
-binfmt_em86 and  binfmt_mz  do.  Since binfmt_misc does not define any default
-binary-formats, you have to register an additional binary-format.
-
-There are two general files in binfmt_misc and one file per registered format.
-The two general files are register and status.
-
-Registering a new binary format
--------------------------------
-
-To register a new binary format you have to issue the command
-
-  echo :name:type:offset:magic:mask:interpreter: > /proc/sys/fs/binfmt_misc/register 
-
-
-
-with appropriate  name (the name for the /proc-dir entry), offset (defaults to
-0, if  omitted),  magic, mask (which can be omitted, defaults to all 0xff) and
-last but  not  least,  the  interpreter that is to be invoked (for example and
-testing /bin/echo).  Type  can be M for usual magic matching or E for filename
-extension matching (give extension in place of magic).
-
-Check or reset the status of the binary format handler
-------------------------------------------------------
-
-If you  do a cat on the file /proc/sys/fs/binfmt_misc/status, you will get the
-current status (enabled/disabled) of binfmt_misc. Change the status by echoing
-0 (disables)  or  1  (enables)  or  -1  (caution:  this  clears all previously
-registered binary  formats)  to status. For example echo 0 > status to disable
-binfmt_misc (temporarily).
-
-Status of a single handler
---------------------------
-
-Each registered  handler has an entry in /proc/sys/fs/binfmt_misc. These files
-perform the  same function as status, but their scope is limited to the actual
-binary format.  By  cating this file, you also receive all related information
-about the interpreter/magic of the binfmt.
-
-Example usage of binfmt_misc (emulate binfmt_java)
---------------------------------------------------
-
-  cd /proc/sys/fs/binfmt_misc  
-  echo ':Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/javawrapper:' > register  
-  echo ':HTML:E::html::/usr/local/java/bin/appletviewer:' > register  
-  echo ':Applet:M::<!--applet::/usr/local/java/bin/appletviewer:' > register 
-  echo ':DEXE:M::\x0eDEX::/usr/bin/dosexec:' > register 
-
-
-These four  lines  add  support  for  Java  executables and Java applets (like
-binfmt_java, additionally  recognizing the .html extension with no need to put
-<!--applet> to  every  applet  file).  You  have  to  install  the JDK and the
-shell-script /usr/local/java/bin/javawrapper  too.  It  works  around  the
-brokenness of  the Java filename handling. To add a Java binary, just create a
-link to the class-file somewhere in the path.
-
-2.3 /proc/sys/kernel - general kernel parameters
-------------------------------------------------
-
-This directory  reflects  general  kernel  behaviors. As I've said before, the
-contents depend  on  your  configuration.  Here you'll find the most important
-files, along with descriptions of what they mean and how to use them.
-
-acct
-----
-
-The file contains three values; highwater, lowwater, and frequency.
-
-It exists  only  when  BSD-style  process  accounting is enabled. These values
-control its behavior. If the free space on the file system where the log lives
-goes below  lowwater  percentage,  accounting  suspends.  If  it  goes  above
-highwater percentage,  accounting  resumes. Frequency determines how often you
-check the amount of free space (value is in seconds). Default settings are: 4,
-2, and  30.  That is, suspend accounting if there is less than 2 percent free;
-resume it  if we have a value of 3 or more percent; consider information about
-the amount of free space valid for 30 seconds
-
-ctrl-alt-del
-------------
-
-When the value in this file is 0, ctrl-alt-del is trapped and sent to the init
-program to  handle a graceful restart. However, when the value is greater that
-zero, Linux's  reaction  to  this key combination will be an immediate reboot,
-without syncing its dirty buffers.
-
-[NOTE]
-    When a  program  (like  dosemu)  has  the  keyboard  in  raw  mode,  the
-    ctrl-alt-del is  intercepted  by  the  program  before it ever reaches the
-    kernel tty  layer,  and  it is up to the program to decide what to do with
-    it.
-
-domainname and hostname
------------------------
-
-These files  can  be controlled to set the NIS domainname and hostname of your
-box. For the classic darkstar.frop.org a simple:
-
-  # echo "darkstar" > /proc/sys/kernel/hostname 
-  # echo "frop.org" > /proc/sys/kernel/domainname 
-
-
-would suffice to set your hostname and NIS domainname.
-
-osrelease, ostype and version
------------------------------
-
-The names make it pretty obvious what these fields contain:
-
-  > cat /proc/sys/kernel/osrelease 
-  2.2.12 
-   
-  > cat /proc/sys/kernel/ostype 
-  Linux 
-   
-  > cat /proc/sys/kernel/version 
-  #4 Fri Oct 1 12:41:14 PDT 1999 
-
-
-The files  osrelease and ostype should be clear enough. Version needs a little
-more clarification.  The  #4 means that this is the 4th kernel built from this
-source base and the date after it indicates the time the kernel was built. The
-only way to tune these values is to rebuild the kernel.
-
-panic
------
-
-The value  in  this  file  represents  the  number of seconds the kernel waits
-before rebooting  on  a  panic.  When  you  use  the  software  watchdog,  the
-recommended setting  is  60. If set to 0, the auto reboot after a kernel panic
-is disabled, which is the default setting.
-
-printk
-------
-
-The four values in printk denote
-* console_loglevel,
-* default_message_loglevel,
-* minimum_console_loglevel and
-* default_console_loglevel
-respectively.
-
-These values  influence  printk()  behavior  when  printing  or  logging error
-messages, which  come  from  inside  the  kernel.  See  syslog(2)  for  more
-information on the different log levels.
-
-console_loglevel
-----------------
-
-Messages with a higher priority than this will be printed to the console.
-
-default_message_level
----------------------
-
-Messages without an explicit priority will be printed with this priority.
-
-minimum_console_loglevel
-------------------------
-
-Minimum (highest) value to which the console_loglevel can be set.
-
-default_console_loglevel
-------------------------
-
-Default value for console_loglevel.
-
-sg-big-buff
------------
-
-This file  shows  the size of the generic SCSI (sg) buffer. At this point, you
-can't tune  it  yet,  but  you  can  change  it  at  compile  time  by editing
-include/scsi/sg.h and changing the value of SG_BIG_BUFF.
-
-If you use a scanner with SANE (Scanner Access Now Easy) you might want to set
-this to a higher value. Refer to the SANE documentation on this issue.
-
-modprobe
---------
-
-The location  where  the  modprobe  binary  is  located.  The kernel uses this
-program to load modules on demand.
-
-unknown_nmi_panic
------------------
-
-The value in this file affects behavior of handling NMI. When the value is
-non-zero, unknown NMI is trapped and then panic occurs. At that time, kernel
-debugging information is displayed on console.
-
-NMI switch that most IA32 servers have fires unknown NMI up, for example.
-If a system hangs up, try pressing the NMI switch.
-
-panic_on_unrecovered_nmi
-------------------------
-
-The default Linux behaviour on an NMI of either memory or unknown is to continue
-operation. For many environments such as scientific computing it is preferable
-that the box is taken out and the error dealt with than an uncorrected
-parity/ECC error get propogated.
-
-A small number of systems do generate NMI's for bizarre random reasons such as
-power management so the default is off. That sysctl works like the existing
-panic controls already in that directory.
-
-nmi_watchdog
-------------
-
-Enables/Disables the NMI watchdog on x86 systems.  When the value is non-zero
-the NMI watchdog is enabled and will continuously test all online cpus to
-determine whether or not they are still functioning properly. Currently,
-passing "nmi_watchdog=" parameter at boot time is required for this function
-to work.
-
-If LAPIC NMI watchdog method is in use (nmi_watchdog=2 kernel parameter), the
-NMI watchdog shares registers with oprofile. By disabling the NMI watchdog,
-oprofile may have more registers to utilize.
-
-msgmni
-------
-
-Maximum number of message queue ids on the system.
-This value scales to the amount of lowmem. It is automatically recomputed
-upon memory add/remove or ipc namespace creation/removal.
-When a value is written into this file, msgmni's value becomes fixed, i.e. it
-is not recomputed anymore when one of the above events occurs.
-Use auto_msgmni to change this behavior.
-
-auto_msgmni
------------
-
-Enables/Disables automatic recomputing of msgmni upon memory add/remove or
-upon ipc namespace creation/removal (see the msgmni description above).
-Echoing "1" into this file enables msgmni automatic recomputing.
-Echoing "0" turns it off.
-auto_msgmni default value is 1.
-
-
-2.4 /proc/sys/vm - The virtual memory subsystem
------------------------------------------------
-
-Please see: Documentation/sysctls/vm.txt for a description of these
+Please see: Documentation/sysctls/ directory for descriptions of these
 entries.
 
+------------------------------------------------------------------------------
+Summary
+------------------------------------------------------------------------------
+Certain aspects  of  kernel  behavior  can be modified at runtime, without the
+need to  recompile  the kernel, or even to reboot the system. The files in the
+/proc/sys tree  can  not only be read, but also modified. You can use the echo
+command to write value into these files, thereby changing the default settings
+of the kernel.
+------------------------------------------------------------------------------
 
-2.5 /proc/sys/dev - Device specific parameters
-----------------------------------------------
-
-Currently there is only support for CDROM drives, and for those, there is only
-one read-only  file containing information about the CD-ROM drives attached to
-the system:
-
-  >cat /proc/sys/dev/cdrom/info 
-  CD-ROM information, Id: cdrom.c 2.55 1999/04/25 
-   
-  drive name:             sr0     hdb 
-  drive speed:            32      40 
-  drive # of slots:       1       0 
-  Can close tray:         1       1 
-  Can open tray:          1       1 
-  Can lock tray:          1       1 
-  Can change speed:       1       1 
-  Can select disk:        0       1 
-  Can read multisession:  1       1 
-  Can read MCN:           1       1 
-  Reports media changed:  1       1 
-  Can play audio:         1       1 
-
-
-You see two drives, sr0 and hdb, along with a list of their features.
-
-2.6 /proc/sys/sunrpc - Remote procedure calls
----------------------------------------------
-
-This directory  contains four files, which enable or disable debugging for the
-RPC functions NFS, NFS-daemon, RPC and NLM. The default values are 0. They can
-be set to one to turn debugging on. (The default value is 0 for each)
-
-2.7 /proc/sys/net - Networking stuff
-------------------------------------
-
-The interface  to  the  networking  parts  of  the  kernel  is  located  in
-/proc/sys/net. Table  2-3  shows all possible subdirectories. You may see only
-some of them, depending on your kernel's configuration.
-
-
-Table 2-3: Subdirectories in /proc/sys/net 
-..............................................................................
- Directory Content             Directory  Content            
- core      General parameter   appletalk  Appletalk protocol 
- unix      Unix domain sockets netrom     NET/ROM            
- 802       E802 protocol       ax25       AX25               
- ethernet  Ethernet protocol   rose       X.25 PLP layer     
- ipv4      IP version 4        x25        X.25 protocol      
- ipx       IPX                 token-ring IBM token ring     
- bridge    Bridging            decnet     DEC net            
- ipv6      IP version 6                   
-..............................................................................
-
-We will  concentrate  on IP networking here. Since AX15, X.25, and DEC Net are
-only minor players in the Linux world, we'll skip them in this chapter. You'll
-find some  short  info on Appletalk and IPX further on in this chapter. Review
-the online  documentation  and the kernel source to get a detailed view of the
-parameters for  those  protocols.  In  this  section  we'll  discuss  the
-subdirectories printed  in  bold letters in the table above. As default values
-are suitable for most needs, there is no need to change these values.
-
-/proc/sys/net/core - Network core options
------------------------------------------
-
-rmem_default
-------------
-
-The default setting of the socket receive buffer in bytes.
-
-rmem_max
---------
-
-The maximum receive socket buffer size in bytes.
-
-wmem_default
-------------
-
-The default setting (in bytes) of the socket send buffer.
-
-wmem_max
---------
-
-The maximum send socket buffer size in bytes.
-
-message_burst and message_cost
-------------------------------
-
-These parameters  are used to limit the warning messages written to the kernel
-log from  the  networking  code.  They  enforce  a  rate  limit  to  make  a
-denial-of-service attack  impossible. A higher message_cost factor, results in
-fewer messages that will be written. Message_burst controls when messages will
-be dropped.  The  default  settings  limit  warning messages to one every five
-seconds.
-
-warnings
---------
-
-This controls console messages from the networking stack that can occur because
-of problems on the network like duplicate address or bad checksums. Normally,
-this should be enabled, but if the problem persists the messages can be
-disabled.
-
-netdev_budget
--------------
-
-Maximum number of packets taken from all interfaces in one polling cycle (NAPI
-poll). In one polling cycle interfaces which are registered to polling are
-probed in a round-robin manner. The limit of packets in one such probe can be
-set per-device via sysfs class/net/<device>/weight .
-
-netdev_max_backlog
-------------------
-
-Maximum number  of  packets,  queued  on  the  INPUT  side, when the interface
-receives packets faster than kernel can process them.
-
-optmem_max
-----------
-
-Maximum ancillary buffer size allowed per socket. Ancillary data is a sequence
-of struct cmsghdr structures with appended data.
-
-/proc/sys/net/unix - Parameters for Unix domain sockets
--------------------------------------------------------
-
-There are  only  two  files  in this subdirectory. They control the delays for
-deleting and destroying socket descriptors.
-
-2.8 /proc/sys/net/ipv4 - IPV4 settings
---------------------------------------
-
-IP version  4  is  still the most used protocol in Unix networking. It will be
-replaced by  IP version 6 in the next couple of years, but for the moment it's
-the de  facto  standard  for  the  internet  and  is  used  in most networking
-environments around  the  world.  Because  of the importance of this protocol,
-we'll have a deeper look into the subtree controlling the behavior of the IPv4
-subsystem of the Linux kernel.
-
-Let's start with the entries in /proc/sys/net/ipv4.
-
-ICMP settings
--------------
-
-icmp_echo_ignore_all and icmp_echo_ignore_broadcasts
-----------------------------------------------------
-
-Turn on (1) or off (0), if the kernel should ignore all ICMP ECHO requests, or
-just those to broadcast and multicast addresses.
-
-Please note that if you accept ICMP echo requests with a broadcast/multi\-cast
-destination address  your  network  may  be  used as an exploder for denial of
-service packet flooding attacks to other hosts.
-
-icmp_destunreach_rate, icmp_echoreply_rate, icmp_paramprob_rate and icmp_timeexeed_rate
----------------------------------------------------------------------------------------
-
-Sets limits  for  sending  ICMP  packets  to specific targets. A value of zero
-disables all  limiting.  Any  positive  value sets the maximum package rate in
-hundredth of a second (on Intel systems).
-
-IP settings
------------
-
-ip_autoconfig
--------------
-
-This file contains the number one if the host received its IP configuration by
-RARP, BOOTP, DHCP or a similar mechanism. Otherwise it is zero.
-
-ip_default_ttl
---------------
-
-TTL (Time  To  Live) for IPv4 interfaces. This is simply the maximum number of
-hops a packet may travel.
-
-ip_dynaddr
-----------
-
-Enable dynamic  socket  address rewriting on interface address change. This is
-useful for dialup interface with changing IP addresses.
-
-ip_forward
-----------
-
-Enable or  disable forwarding of IP packages between interfaces. Changing this
-value resets  all other parameters to their default values. They differ if the
-kernel is configured as host or router.
-
-ip_local_port_range
--------------------
-
-Range of  ports  used  by  TCP  and UDP to choose the local port. Contains two
-numbers, the  first  number  is the lowest port, the second number the highest
-local port.  Default  is  1024-4999.  Should  be  changed  to  32768-61000 for
-high-usage systems.
-
-ip_no_pmtu_disc
----------------
-
-Global switch  to  turn  path  MTU  discovery off. It can also be set on a per
-socket basis by the applications or on a per route basis.
-
-ip_masq_debug
--------------
-
-Enable/disable debugging of IP masquerading.
-
-IP fragmentation settings
--------------------------
-
-ipfrag_high_trash and ipfrag_low_trash
---------------------------------------
-
-Maximum memory  used to reassemble IP fragments. When ipfrag_high_thresh bytes
-of memory  is  allocated  for  this  purpose,  the  fragment handler will toss
-packets until ipfrag_low_thresh is reached.
-
-ipfrag_time
------------
-
-Time in seconds to keep an IP fragment in memory.
-
-TCP settings
-------------
-
-tcp_ecn
--------
-
-This file controls the use of the ECN bit in the IPv4 headers. This is a new
-feature about Explicit Congestion Notification, but some routers and firewalls
-block traffic that has this bit set, so it could be necessary to echo 0 to
-/proc/sys/net/ipv4/tcp_ecn if you want to talk to these sites. For more info
-you could read RFC2481.
-
-tcp_retrans_collapse
---------------------
-
-Bug-to-bug compatibility with some broken printers. On retransmit, try to send
-larger packets to work around bugs in certain TCP stacks. Can be turned off by
-setting it to zero.
-
-tcp_keepalive_probes
---------------------
-
-Number of  keep  alive  probes  TCP  sends  out,  until  it  decides  that the
-connection is broken.
-
-tcp_keepalive_time
-------------------
-
-How often  TCP  sends out keep alive messages, when keep alive is enabled. The
-default is 2 hours.
-
-tcp_syn_retries
----------------
-
-Number of  times  initial  SYNs  for  a  TCP  connection  attempt  will  be
-retransmitted. Should  not  be  higher  than 255. This is only the timeout for
-outgoing connections,  for  incoming  connections the number of retransmits is
-defined by tcp_retries1.
-
-tcp_sack
---------
-
-Enable select acknowledgments after RFC2018.
-
-tcp_timestamps
---------------
-
-Enable timestamps as defined in RFC1323.
-
-tcp_stdurg
-----------
-
-Enable the  strict  RFC793 interpretation of the TCP urgent pointer field. The
-default is  to  use  the  BSD  compatible interpretation of the urgent pointer
-pointing to the first byte after the urgent data. The RFC793 interpretation is
-to have  it  point  to  the last byte of urgent data. Enabling this option may
-lead to interoperability problems. Disabled by default.
-
-tcp_syncookies
---------------
-
-Only valid  when  the  kernel  was  compiled  with CONFIG_SYNCOOKIES. Send out
-syncookies when  the  syn backlog queue of a socket overflows. This is to ward
-off the common 'syn flood attack'. Disabled by default.
-
-Note that  the  concept  of a socket backlog is abandoned. This means the peer
-may not  receive  reliable  error  messages  from  an  over loaded server with
-syncookies enabled.
-
-tcp_window_scaling
-------------------
-
-Enable window scaling as defined in RFC1323.
-
-tcp_fin_timeout
----------------
-
-The length  of  time  in  seconds  it  takes to receive a final FIN before the
-socket is  always  closed.  This  is  strictly  a  violation  of  the  TCP
-specification, but required to prevent denial-of-service attacks.
-
-tcp_max_ka_probes
------------------
-
-Indicates how  many  keep alive probes are sent per slow timer run. Should not
-be set too high to prevent bursts.
-
-tcp_max_syn_backlog
--------------------
-
-Length of  the per socket backlog queue. Since Linux 2.2 the backlog specified
-in listen(2)  only  specifies  the  length  of  the  backlog  queue of already
-established sockets. When more connection requests arrive Linux starts to drop
-packets. When  syncookies  are  enabled the packets are still answered and the
-maximum queue is effectively ignored.
-
-tcp_retries1
-------------
-
-Defines how  often  an  answer  to  a  TCP connection request is retransmitted
-before giving up.
-
-tcp_retries2
-------------
-
-Defines how often a TCP packet is retransmitted before giving up.
-
-Interface specific settings
----------------------------
-
-In the directory /proc/sys/net/ipv4/conf you'll find one subdirectory for each
-interface the  system  knows about and one directory calls all. Changes in the
-all subdirectory  affect  all  interfaces,  whereas  changes  in  the  other
-subdirectories affect  only  one  interface.  All  directories  have  the same
-entries:
-
-accept_redirects
-----------------
-
-This switch  decides  if the kernel accepts ICMP redirect messages or not. The
-default is 'yes' if the kernel is configured for a regular host and 'no' for a
-router configuration.
-
-accept_source_route
--------------------
-
-Should source  routed  packages  be  accepted  or  declined.  The  default  is
-dependent on  the  kernel  configuration.  It's 'yes' for routers and 'no' for
-hosts.
-
-bootp_relay
-~~~~~~~~~~~
-
-Accept packets  with source address 0.b.c.d with destinations not to this host
-as local ones. It is supposed that a BOOTP relay daemon will catch and forward
-such packets.
-
-The default  is  0,  since this feature is not implemented yet (kernel version
-2.2.12).
-
-forwarding
-----------
-
-Enable or disable IP forwarding on this interface.
-
-log_martians
-------------
-
-Log packets with source addresses with no known route to kernel log.
-
-mc_forwarding
--------------
-
-Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE and a
-multicast routing daemon is required.
-
-proxy_arp
----------
-
-Does (1) or does not (0) perform proxy ARP.
-
-rp_filter
----------
-
-Integer value determines if a source validation should be made. 1 means yes, 0
-means no.  Disabled by default, but local/broadcast address spoofing is always
-on.
-
-If you  set this to 1 on a router that is the only connection for a network to
-the net,  it  will  prevent  spoofing  attacks  against your internal networks
-(external addresses  can  still  be  spoofed), without the need for additional
-firewall rules.
-
-secure_redirects
-----------------
-
-Accept ICMP  redirect  messages  only  for gateways, listed in default gateway
-list. Enabled by default.
-
-shared_media
-------------
-
-If it  is  not  set  the kernel does not assume that different subnets on this
-device can communicate directly. Default setting is 'yes'.
-
-send_redirects
---------------
-
-Determines whether to send ICMP redirects to other hosts.
-
-Routing settings
-----------------
-
-The directory  /proc/sys/net/ipv4/route  contains  several  file  to  control
-routing issues.
-
-error_burst and error_cost
---------------------------
-
-These  parameters  are used to limit how many ICMP destination unreachable to 
-send  from  the  host  in question. ICMP destination unreachable messages are 
-sent  when  we  cannot reach  the next hop while trying to transmit a packet. 
-It  will also print some error messages to kernel logs if someone is ignoring 
-our   ICMP  redirects.  The  higher  the  error_cost  factor  is,  the  fewer 
-destination  unreachable  and error messages will be let through. Error_burst 
-controls  when  destination  unreachable  messages and error messages will be
-dropped. The default settings limit warning messages to five every second.
-
-flush
------
-
-Writing to this file results in a flush of the routing cache.
-
-gc_elasticity, gc_interval, gc_min_interval_ms, gc_timeout, gc_thresh
----------------------------------------------------------------------
-
-Values to  control  the  frequency  and  behavior  of  the  garbage collection
-algorithm for the routing cache. gc_min_interval is deprecated and replaced
-by gc_min_interval_ms.
-
-
-max_size
---------
-
-Maximum size  of  the routing cache. Old entries will be purged once the cache
-reached has this size.
-
-redirect_load, redirect_number
-------------------------------
-
-Factors which  determine  if  more ICPM redirects should be sent to a specific
-host. No  redirects  will be sent once the load limit or the maximum number of
-redirects has been reached.
-
-redirect_silence
-----------------
-
-Timeout for redirects. After this period redirects will be sent again, even if
-this has been stopped, because the load or number limit has been reached.
-
-Network Neighbor handling
--------------------------
-
-Settings about how to handle connections with direct neighbors (nodes attached
-to the same link) can be found in the directory /proc/sys/net/ipv4/neigh.
-
-As we  saw  it  in  the  conf directory, there is a default subdirectory which
-holds the  default  values, and one directory for each interface. The contents
-of the  directories  are identical, with the single exception that the default
-settings contain additional options to set garbage collection parameters.
-
-In the interface directories you'll find the following entries:
-
-base_reachable_time, base_reachable_time_ms
--------------------------------------------
-
-A base  value  used for computing the random reachable time value as specified
-in RFC2461.
-
-Expression of base_reachable_time, which is deprecated, is in seconds.
-Expression of base_reachable_time_ms is in milliseconds.
-
-retrans_time, retrans_time_ms
------------------------------
-
-The time between retransmitted Neighbor Solicitation messages.
-Used for address resolution and to determine if a neighbor is
-unreachable.
-
-Expression of retrans_time, which is deprecated, is in 1/100 seconds (for
-IPv4) or in jiffies (for IPv6).
-Expression of retrans_time_ms is in milliseconds.
-
-unres_qlen
-----------
-
-Maximum queue  length  for a pending arp request - the number of packets which
-are accepted from other layers while the ARP address is still resolved.
-
-anycast_delay
--------------
-
-Maximum for  random  delay  of  answers  to  neighbor solicitation messages in
-jiffies (1/100  sec). Not yet implemented (Linux does not have anycast support
-yet).
-
-ucast_solicit
--------------
-
-Maximum number of retries for unicast solicitation.
-
-mcast_solicit
--------------
-
-Maximum number of retries for multicast solicitation.
-
-delay_first_probe_time
-----------------------
-
-Delay for  the  first  time  probe  if  the  neighbor  is  reachable.  (see
-gc_stale_time)
-
-locktime
---------
-
-An ARP/neighbor  entry  is only replaced with a new one if the old is at least
-locktime old. This prevents ARP cache thrashing.
-
-proxy_delay
------------
-
-Maximum time  (real  time is random [0..proxytime]) before answering to an ARP
-request for  which  we have an proxy ARP entry. In some cases, this is used to
-prevent network flooding.
-
-proxy_qlen
-----------
-
-Maximum queue length of the delayed proxy arp timer. (see proxy_delay).
-
-app_solicit
-----------
-
-Determines the  number of requests to send to the user level ARP daemon. Use 0
-to turn off.
-
-gc_stale_time
--------------
-
-Determines how  often  to  check  for stale ARP entries. After an ARP entry is
-stale it  will  be resolved again (which is useful when an IP address migrates
-to another  machine).  When  ucast_solicit is greater than 0 it first tries to
-send an  ARP  packet  directly  to  the  known  host  When  that  fails  and
-mcast_solicit is greater than 0, an ARP request is broadcasted.
-
-2.9 Appletalk
--------------
-
-The /proc/sys/net/appletalk  directory  holds the Appletalk configuration data
-when Appletalk is loaded. The configurable parameters are:
-
-aarp-expiry-time
-----------------
-
-The amount  of  time  we keep an ARP entry before expiring it. Used to age out
-old hosts.
-
-aarp-resolve-time
------------------
-
-The amount of time we will spend trying to resolve an Appletalk address.
-
-aarp-retransmit-limit
----------------------
-
-The number of times we will retransmit a query before giving up.
-
-aarp-tick-time
---------------
-
-Controls the rate at which expires are checked.
-
-The directory  /proc/net/appletalk  holds the list of active Appletalk sockets
-on a machine.
-
-The fields  indicate  the DDP type, the local address (in network:node format)
-the remote  address,  the  size of the transmit pending queue, the size of the
-received queue  (bytes waiting for applications to read) the state and the uid
-owning the socket.
-
-/proc/net/atalk_iface lists  all  the  interfaces  configured for appletalk.It
-shows the  name  of the interface, its Appletalk address, the network range on
-that address  (or  network number for phase 1 networks), and the status of the
-interface.
-
-/proc/net/atalk_route lists  each  known  network  route.  It lists the target
-(network) that the route leads to, the router (may be directly connected), the
-route flags, and the device the route is using.
-
-2.10 IPX
---------
-
-The IPX protocol has no tunable values in proc/sys/net.
-
-The IPX  protocol  does,  however,  provide  proc/net/ipx. This lists each IPX
-socket giving  the  local  and  remote  addresses  in  Novell  format (that is
-network:node:port). In  accordance  with  the  strange  Novell  tradition,
-everything but the port is in hex. Not_Connected is displayed for sockets that
-are not  tied to a specific remote address. The Tx and Rx queue sizes indicate
-the number  of  bytes  pending  for  transmission  and  reception.  The  state
-indicates the  state  the  socket  is  in and the uid is the owning uid of the
-socket.
-
-The /proc/net/ipx_interface  file lists all IPX interfaces. For each interface
-it gives  the network number, the node number, and indicates if the network is
-the primary  network.  It  also  indicates  which  device  it  is bound to (or
-Internal for  internal  networks)  and  the  Frame  Type if appropriate. Linux
-supports 802.3,  802.2,  802.2  SNAP  and DIX (Blue Book) ethernet framing for
-IPX.
-
-The /proc/net/ipx_route  table  holds  a list of IPX routes. For each route it
-gives the  destination  network, the router node (or Directly) and the network
-address of the router (or Connected) for internal networks.
-
-2.11 /proc/sys/fs/mqueue - POSIX message queues filesystem
-----------------------------------------------------------
-
-The "mqueue"  filesystem provides  the necessary kernel features to enable the
-creation of a  user space  library that  implements  the  POSIX message queues
-API (as noted by the  MSG tag in the  POSIX 1003.1-2001 version  of the System
-Interfaces specification.)
-
-The "mqueue" filesystem contains values for determining/setting  the amount of
-resources used by the file system.
-
-/proc/sys/fs/mqueue/queues_max is a read/write  file for  setting/getting  the
-maximum number of message queues allowed on the system.
-
-/proc/sys/fs/mqueue/msg_max  is  a  read/write file  for  setting/getting  the
-maximum number of messages in a queue value.  In fact it is the limiting value
-for another (user) limit which is set in mq_open invocation. This attribute of
-a queue must be less or equal then msg_max.
-
-/proc/sys/fs/mqueue/msgsize_max is  a read/write  file for setting/getting the
-maximum  message size value (it is every  message queue's attribute set during
-its creation).
+------------------------------------------------------------------------------
+CHAPTER 3: PER-PROCESS PARAMETERS
+------------------------------------------------------------------------------
 
-2.12 /proc/<pid>/oom_adj - Adjust the oom-killer score
+3.1 /proc/<pid>/oom_adj - Adjust the oom-killer score
 ------------------------------------------------------
 
 This file can be used to adjust the score used to select which processes
@@ -2062,25 +1037,15 @@ The task with the highest badness score is then selected and its children
 are killed, process itself will be killed in an OOM situation when it does
 not have children or some of them disabled oom like described above.
 
-2.13 /proc/<pid>/oom_score - Display current oom-killer score
+3.2 /proc/<pid>/oom_score - Display current oom-killer score
 -------------------------------------------------------------
 
-------------------------------------------------------------------------------
 This file can be used to check the current score used by the oom-killer is for
 any given <pid>. Use it together with /proc/<pid>/oom_adj to tune which
 process should be killed in an out-of-memory situation.
 
-------------------------------------------------------------------------------
-Summary
-------------------------------------------------------------------------------
-Certain aspects  of  kernel  behavior  can be modified at runtime, without the
-need to  recompile  the kernel, or even to reboot the system. The files in the
-/proc/sys tree  can  not only be read, but also modified. You can use the echo
-command to write value into these files, thereby changing the default settings
-of the kernel.
-------------------------------------------------------------------------------
 
-2.14  /proc/<pid>/io - Display the IO accounting fields
+3.3  /proc/<pid>/io - Display the IO accounting fields
 -------------------------------------------------------
 
 This file contains IO statistics for each running process
@@ -2182,7 +1147,7 @@ those 64-bit counters, process A could see an intermediate result.
 More information about this can be found within the taskstats documentation in
 Documentation/accounting.
 
-2.15 /proc/<pid>/coredump_filter - Core dump filtering settings
+3.4 /proc/<pid>/coredump_filter - Core dump filtering settings
 ---------------------------------------------------------------
 When a process is dumped, all anonymous memory is written to a core file as
 long as the size of the core file isn't limited. But sometimes we don't want
@@ -2226,7 +1191,7 @@ For example:
   $ echo 0x7 > /proc/self/coredump_filter
   $ ./some_program
 
-2.16   /proc/<pid>/mountinfo - Information about mounts
+3.5    /proc/<pid>/mountinfo - Information about mounts
 --------------------------------------------------------
 
 This file contains lines of the form:
@@ -2263,30 +1228,3 @@ For more information on mount propagation see:
 
   Documentation/filesystems/sharedsubtree.txt
 
-2.17   /proc/sys/fs/epoll - Configuration options for the epoll interface
---------------------------------------------------------
-
-This directory contains configuration options for the epoll(7) interface.
-
-max_user_instances
-------------------
-
-This is the maximum number of epoll file descriptors that a single user can
-have open at a given time. The default value is 128, and should be enough
-for normal users.
-
-max_user_watches
-----------------
-
-Every epoll file descriptor can store a number of files to be monitored
-for event readiness. Each one of these monitored files constitutes a "watch".
-This configuration option sets the maximum number of "watches" that are
-allowed for each user.
-Each "watch" costs roughly 90 bytes on a 32bit kernel, and roughly 160 bytes
-on a 64bit one.
-The current default value for  max_user_watches  is the 1/32 of the available
-low memory, divided for the "watch" cost in bytes.
-
-
-------------------------------------------------------------------------------
-
index 9f8740ca3f3bc514d9f5426168eb5b2273b96d42..26e4b8bc53ee097b0660650b83d276751855b1ea 100644 (file)
@@ -12,6 +12,7 @@ that support it.  For example, a given bus might look like this:
      |   |-- enable
      |   |-- irq
      |   |-- local_cpus
+     |   |-- remove
      |   |-- resource
      |   |-- resource0
      |   |-- resource1
@@ -36,6 +37,7 @@ files, each with their own function.
        enable             Whether the device is enabled (ascii, rw)
        irq                IRQ number (ascii, ro)
        local_cpus         nearby CPU mask (cpumask, ro)
+       remove             remove device from kernel's list (ascii, wo)
        resource                   PCI resource host addresses (ascii, ro)
        resource0..N       PCI resource N, if present (binary, mmap)
        resource0_wc..N_wc  PCI WC map resource N, if prefetchable (binary, mmap)
@@ -46,6 +48,7 @@ files, each with their own function.
 
   ro - read only file
   rw - file is readable and writable
+  wo - write only file
   mmap - file is mmapable
   ascii - file contains ascii text
   binary - file contains binary data
@@ -73,6 +76,13 @@ that the device must be enabled for a rom read to return data succesfully.
 In the event a driver is not bound to the device, it can be enabled using the
 'enable' file, documented above.
 
+The 'remove' file is used to remove the PCI device, by writing a non-zero
+integer to the file.  This does not involve any kind of hot-plug functionality,
+e.g. powering off the device.  The device is removed from the kernel's list of
+PCI devices, the sysfs directory for it is removed, and the device will be
+removed from any drivers attached to it. Removal of PCI root buses is
+disallowed.
+
 Accessing legacy resources through sysfs
 ----------------------------------------
 
index b1b9887012478f9b654edaa90bcdd13e72a9f20e..145c25a170c7abf6e0e489fba4c00b4784759dca 100644 (file)
@@ -123,7 +123,10 @@ platform-specific implementation issue.
 
 Using GPIOs
 -----------
-One of the first things to do with a GPIO, often in board setup code when
+The first thing a system should do with a GPIO is allocate it, using
+the gpio_request() call; see later.
+
+One of the next things to do with a GPIO, often in board setup code when
 setting up a platform_device using the GPIO, is mark its direction:
 
        /* set as input or output, returning 0 or negative errno */
@@ -141,8 +144,8 @@ This helps avoid signal glitching during system startup.
 
 For compatibility with legacy interfaces to GPIOs, setting the direction
 of a GPIO implicitly requests that GPIO (see below) if it has not been
-requested already.  That compatibility may be removed in the future;
-explicitly requesting GPIOs is strongly preferred.
+requested already.  That compatibility is being removed from the optional
+gpiolib framework.
 
 Setting the direction can fail if the GPIO number is invalid, or when
 that particular GPIO can't be used in that mode.  It's generally a bad
@@ -195,7 +198,7 @@ This requires sleeping, which can't be done from inside IRQ handlers.
 
 Platforms that support this type of GPIO distinguish them from other GPIOs
 by returning nonzero from this call (which requires a valid GPIO number,
-either explicitly or implicitly requested):
+which should have been previously allocated with gpio_request):
 
        int gpio_cansleep(unsigned gpio);
 
@@ -212,10 +215,9 @@ for GPIOs that can't be accessed from IRQ handlers, these calls act the
 same as the spinlock-safe calls.
 
 
-Claiming and Releasing GPIOs (OPTIONAL)
----------------------------------------
+Claiming and Releasing GPIOs
+----------------------------
 To help catch system configuration errors, two calls are defined.
-However, many platforms don't currently support this mechanism.
 
        /* request GPIO, returning 0 or negative errno.
         * non-null labels may be useful for diagnostics.
@@ -244,13 +246,6 @@ Some platforms may also use knowledge about what GPIOs are active for
 power management, such as by powering down unused chip sectors and, more
 easily, gating off unused clocks.
 
-These two calls are optional because not not all current Linux platforms
-offer such functionality in their GPIO support; a valid implementation
-could return success for all gpio_request() calls.  Unlike the other calls,
-the state they represent doesn't normally match anything from a hardware
-register; it's just a software bitmap which clearly is not necessary for
-correct operation of hardware or (bug free) drivers.
-
 Note that requesting a GPIO does NOT cause it to be configured in any
 way; it just marks that GPIO as in use.  Separate code must handle any
 pin setup (e.g. controlling which pin the GPIO uses, pullup/pulldown).
index 1fee6f1e6bc5574102b04d13d5ed1fd1396f0641..5e97f333c4df547e79507631a5b848578409f3d6 100644 (file)
@@ -49,12 +49,9 @@ of up to +/- 0.5 degrees even when compared against precise temperature
 readings. Be sure to have a high vs. low temperature limit gap of al least
 1.0 degree Celsius to avoid Tout "bouncing", though!
 
-As for alarms, you can read the alarm status of the DS1621 via the 'alarms'
-/sys file interface. The result consists mainly of bit 6 and 5 of the
-configuration register of the chip; bit 6 (0x40 or 64) is the high alarm
-bit and bit 5 (0x20 or 32) the low one. These bits are set when the high or
-low limits are met or exceeded and are reset by the module as soon as the
-respective temperature ranges are left.
+The alarm bits are set when the high or low limits are met or exceeded and
+are reset by the module as soon as the respective temperature ranges are
+left.
 
 The alarm registers are in no way suitable to find out about the actual
 status of Tout. They will only tell you about its history, whether or not
@@ -64,45 +61,3 @@ with neither of the alarms set.
 
 Temperature conversion of the DS1621 takes up to 1000ms; internal access to
 non-volatile registers may last for 10ms or below.
-
-High Accuracy Temperature Reading
----------------------------------
-
-As said before, the temperature issued via the 9-bit i2c-bus data is
-somewhat arbitrary. Internally, the temperature conversion is of a
-different kind that is explained (not so...) well in the DS1621 data sheet.
-To cut the long story short: Inside the DS1621 there are two oscillators,
-both of them biassed by a temperature coefficient.
-
-Higher resolution of the temperature reading can be achieved using the
-internal projection, which means taking account of REG_COUNT and REG_SLOPE
-(the driver manages them):
-
-Taken from Dallas Semiconductors App Note 068: 'Increasing Temperature
-Resolution on the DS1620' and App Note 105: 'High Resolution Temperature
-Measurement with Dallas Direct-to-Digital Temperature Sensors'
-
-- Read the 9-bit temperature and strip the LSB (Truncate the .5 degs)
-- The resulting value is TEMP_READ.
-- Then, read REG_COUNT.
-- And then, REG_SLOPE.
-
-      TEMP = TEMP_READ - 0.25 + ((REG_SLOPE - REG_COUNT) / REG_SLOPE)
-
-Note that this is what the DONE bit in the DS1621 configuration register is
-good for: Internally, one temperature conversion takes up to 1000ms. Before
-that conversion is complete you will not be able to read valid things out
-of REG_COUNT and REG_SLOPE. The DONE bit, as you may have guessed by now,
-tells you whether the conversion is complete ("done", in plain English) and
-thus, whether the values you read are good or not.
-
-The DS1621 has two modes of operation: "Continuous" conversion, which can
-be understood as the default stand-alone mode where the chip gets the
-temperature and controls external devices via its Tout pin or tells other
-i2c's about it if they care. The other mode is called "1SHOT", that means
-that it only figures out about the temperature when it is explicitly told
-to do so; this can be seen as power saving mode.
-
-Now if you want to read REG_COUNT and REG_SLOPE, you have to either stop
-the continuous conversions until the contents of these registers are valid,
-or, in 1SHOT mode, you have to have one conversion made.
index 287f8c902656db40353954b967b06503d517dc70..effe949a7282cccd600365bffe78dd70541b9aa3 100644 (file)
@@ -1,11 +1,11 @@
 Kernel driver lis3lv02d
-==================
+=======================
 
 Supported chips:
 
   * STMicroelectronics LIS3LV02DL and LIS3LV02DQ
 
-Author:
+Authors:
         Yan Burman <burman.yan@gmail.com>
        Eric Piel <eric.piel@tremplin-utc.net>
 
@@ -15,7 +15,7 @@ Description
 
 This driver provides support for the accelerometer found in various HP
 laptops sporting the feature officially called "HP Mobile Data
-Protection System 3D" or "HP 3D DriveGuard". It detect automatically
+Protection System 3D" or "HP 3D DriveGuard". It detects automatically
 laptops with this sensor. Known models (for now the HP 2133, nc6420,
 nc2510, nc8510, nc84x0, nw9440 and nx9420) will have their axis
 automatically oriented on standard way (eg: you can directly play
@@ -27,7 +27,7 @@ position - 3D position that the accelerometer reports. Format: "(x,y,z)"
 calibrate - read: values (x, y, z) that are used as the base for input
                  class device operation.
             write: forces the base to be recalibrated with the current
-                 position.
+                  position.
 rate - reports the sampling rate of the accelerometer device in HZ
 
 This driver also provides an absolute input class device, allowing
@@ -48,7 +48,7 @@ For better compatibility between the various laptops. The values reported by
 the accelerometer are converted into a "standard" organisation of the axes
 (aka "can play neverball out of the box"):
  * When the laptop is horizontal the position reported is about 0 for X and Y
-and a positive value for Z
+       and a positive value for Z
  * If the left side is elevated, X increases (becomes positive)
  * If the front side (where the touchpad is) is elevated, Y decreases
        (becomes negative)
@@ -59,3 +59,13 @@ email to the authors to add it to the database.  When reporting a new
 laptop, please include the output of "dmidecode" plus the value of
 /sys/devices/platform/lis3lv02d/position in these four cases.
 
+Q&A
+---
+
+Q: How do I safely simulate freefall? I have an HP "portable
+workstation" which has about 3.5kg and a plastic case, so letting it
+fall to the ground is out of question...
+
+A: The sensor is pretty sensitive, so your hands can do it. Lift it
+into free space, follow the fall with your hands for like 10
+centimeters. That should be enough to trigger the detection.
diff --git a/Documentation/hwmon/ltc4215 b/Documentation/hwmon/ltc4215
new file mode 100644 (file)
index 0000000..2e6a21e
--- /dev/null
@@ -0,0 +1,50 @@
+Kernel driver ltc4215
+=====================
+
+Supported chips:
+  * Linear Technology LTC4215
+    Prefix: 'ltc4215'
+    Addresses scanned: 0x44
+    Datasheet:
+        http://www.linear.com/pc/downloadDocument.do?navId=H0,C1,C1003,C1006,C1163,P17572,D12697
+
+Author: Ira W. Snyder <iws@ovro.caltech.edu>
+
+
+Description
+-----------
+
+The LTC4215 controller allows a board to be safely inserted and removed
+from a live backplane.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for LTC4215 devices, due to the fact that some
+of the possible addresses are unfriendly to probing. You will need to use
+the "force" parameter to tell the driver where to find the device.
+
+Example: the following will load the driver for an LTC4215 at address 0x44
+on I2C bus #0:
+$ modprobe ltc4215 force=0,0x44
+
+
+Sysfs entries
+-------------
+
+The LTC4215 has built-in limits for overvoltage, undervoltage, and
+undercurrent warnings. This makes it very likely that the reference
+circuit will be used.
+
+in1_input              input voltage
+in2_input              output voltage
+
+in1_min_alarm          input undervoltage alarm
+in1_max_alarm          input overvoltage alarm
+
+curr1_input            current
+curr1_max_alarm                overcurrent alarm
+
+power1_input           power usage
+power1_alarm           power bad alarm
index 6dbfd5efd991de9f6a69eaa831d1a45634ba5979..2f10ce6a879f7276f635cd1ac51c03d8c004d8c1 100644 (file)
@@ -365,6 +365,7 @@ energy[1-*]_input           Cumulative energy use
                                Unit: microJoule
                                RO
 
+
 **********
 * Alarms *
 **********
@@ -453,6 +454,27 @@ beep_mask  Bitmask for beep.
                RW
 
 
+***********************
+* Intrusion detection *
+***********************
+
+intrusion[0-*]_alarm
+               Chassis intrusion detection
+               0: OK
+               1: intrusion detected
+               RW
+               Contrary to regular alarm flags which clear themselves
+               automatically when read, this one sticks until cleared by
+               the user. This is done by writing 0 to the file. Writing
+               other values is unsupported.
+
+intrusion[0-*]_beep
+               Chassis intrusion beep
+               0: disable
+               1: enable
+               RW
+
+
 sysfs attribute writes interpretation
 -------------------------------------
 
index d6e1ae30fa6e61f3da3e523befa708dcfbedb627..b6eb59384bb39c1b67d0c99a1ade601269a64d05 100644 (file)
@@ -2,30 +2,40 @@ Kernel driver w83627ehf
 =======================
 
 Supported chips:
-  * Winbond W83627EHF/EHG/DHG (ISA access ONLY)
+  * Winbond W83627EHF/EHG (ISA access ONLY)
     Prefix: 'w83627ehf'
     Addresses scanned: ISA address retrieved from Super I/O registers
     Datasheet:
-        http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83627EHF_%20W83627EHGb.pdf
-        DHG datasheet confidential.
+        http://www.nuvoton.com.tw/NR/rdonlyres/A6A258F0-F0C9-4F97-81C0-C4D29E7E943E/0/W83627EHF.pdf
+  * Winbond W83627DHG
+    Prefix: 'w83627dhg'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet:
+        http://www.nuvoton.com.tw/NR/rdonlyres/7885623D-A487-4CF9-A47F-30C5F73D6FE6/0/W83627DHG.pdf
+  * Winbond W83667HG
+    Prefix: 'w83667hg'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet: not available
 
 Authors:
         Jean Delvare <khali@linux-fr.org>
         Yuan Mu (Winbond)
         Rudolf Marek <r.marek@assembler.cz>
         David Hubbard <david.c.hubbard@gmail.com>
+        Gong Jun <JGong@nuvoton.com>
 
 Description
 -----------
 
-This driver implements support for the Winbond W83627EHF, W83627EHG, and
-W83627DHG super I/O chips. We will refer to them collectively as Winbond chips.
+This driver implements support for the Winbond W83627EHF, W83627EHG,
+W83627DHG and W83667HG super I/O chips. We will refer to them collectively
+as Winbond chips.
 
 The chips implement three temperature sensors, five fan rotation
 speed sensors, ten analog voltage sensors (only nine for the 627DHG), one
-VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG), alarms with beep
-warnings (control unimplemented), and some automatic fan regulation
-strategies (plus manual fan control mode).
+VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG and 667HG), alarms
+with beep warnings (control unimplemented), and some automatic fan
+regulation strategies (plus manual fan control mode).
 
 Temperatures are measured in degrees Celsius and measurement resolution is 1
 degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
@@ -54,7 +64,8 @@ follows:
 temp1 -> pwm1
 temp2 -> pwm2
 temp3 -> pwm3
-prog  -> pwm4 (the programmable setting is not supported by the driver)
+prog  -> pwm4 (not on 667HG; the programmable setting is not supported by
+              the driver)
 
 /sys files
 ----------
index f1d639903325ca697cd23f6e34e7074aba05daed..1f779a25c703f68775b10d6aff74f18638cbcd37 100644 (file)
@@ -122,10 +122,8 @@ Code       Seq#    Include File            Comments
 'c'    00-7F   linux/coda.h            conflict!
 'c'    80-9F   arch/s390/include/asm/chsc.h
 'd'    00-FF   linux/char/drm/drm/h    conflict!
-'d'    00-DF   linux/video_decoder.h   conflict!
 'd'    F0-FF   linux/digi1.h
 'e'    all     linux/digi1.h           conflict!
-'e'    00-1F   linux/video_encoder.h   conflict!
 'e'    00-1F   net/irda/irtty.h        conflict!
 'f'    00-1F   linux/ext2_fs.h
 'h'    00-7F                           Charon filesystem
index d1e2fcb6298b6f2ae7873a033602b52510463e66..240257dd4238fc55608989541b79c37e40101abc 100644 (file)
@@ -492,6 +492,16 @@ and is between 256 and 4096 characters. It is defined in the file
                        Range: 0 - 8192
                        Default: 64
 
+       dma_debug=off   If the kernel is compiled with DMA_API_DEBUG support
+                       this option disables the debugging code at boot.
+
+       dma_debug_entries=<number>
+                       This option allows to tune the number of preallocated
+                       entries for DMA-API debugging code. One entry is
+                       required per DMA-API allocation. Use this if the
+                       DMA-API debugging code disables itself because the
+                       architectural default is too low.
+
        hpet=           [X86-32,HPET] option to control HPET usage
                        Format: { enable (default) | disable | force |
                                verbose }
@@ -1685,6 +1695,8 @@ and is between 256 and 4096 characters. It is defined in the file
                        See also Documentation/blockdev/paride.txt.
 
        pci=option[,option...]  [PCI] various PCI subsystem options:
+               earlydump       [X86] dump PCI config space before the kernel
+                               changes anything
                off             [X86] don't probe for the PCI bus
                bios            [X86-32] force use of PCI BIOS, don't access
                                the hardware directly. Use this if your machine
@@ -1784,6 +1796,15 @@ and is between 256 and 4096 characters. It is defined in the file
                cbmemsize=nn[KMG]       The fixed amount of bus space which is
                                reserved for the CardBus bridge's memory
                                window. The default value is 64 megabytes.
+               resource_alignment=
+                               Format:
+                               [<order of align>@][<domain>:]<bus>:<slot>.<func>[; ...]
+                               Specifies alignment and device to reassign
+                               aligned memory resources.
+                               If <order of align> is not specified,
+                               PAGE_SIZE is used as alignment.
+                               PCI-PCI bridge can be specified, if resource
+                               windows need to be expanded.
 
        pcie_aspm=      [PCIE] Forcibly enable or disable PCIe Active State Power
                        Management.
@@ -2030,15 +2051,6 @@ and is between 256 and 4096 characters. It is defined in the file
                        If enabled at boot time, /selinux/disable can be used
                        later to disable prior to initial policy load.
 
-       selinux_compat_net =
-                       [SELINUX] Set initial selinux_compat_net flag value.
-                        Format: { "0" | "1" }
-                        0 -- use new secmark-based packet controls
-                        1 -- use legacy packet controls
-                        Default value is 0 (preferred).
-                        Value can be changed at runtime via
-                        /selinux/compat_net.
-
        serialnumber    [BUGS=X86-32]
 
        shapers=        [NET]
index f2dbbf3bdeaba7a5c6d58e1ccb3f8a686ade88ed..d36fcc0f2715c705d0f70d1aa9c13e20b8aaa917 100644 (file)
@@ -1630,6 +1630,13 @@ static bool service_io(struct device *dev)
                }
        }
 
+       /* OK, so we noted that it was pretty poor to use an fdatasync as a
+        * barrier.  But Christoph Hellwig points out that we need a sync
+        * *afterwards* as well: "Barriers specify no reordering to the front
+        * or the back."  And Jens Axboe confirmed it, so here we are: */
+       if (out->type & VIRTIO_BLK_T_BARRIER)
+               fdatasync(vblk->fd);
+
        /* We can't trigger an IRQ, because we're not the Launcher.  It does
         * that when we tell it we're done. */
        add_used(dev->vq, head, wlen);
index 488773018152056ea159685e732e42452a7ae142..938ea22f2cc096f6838a678217e463bf9ec0cd4d 100644 (file)
@@ -27,33 +27,37 @@ lock-class.
 State
 -----
 
-The validator tracks lock-class usage history into 5 separate state bits:
+The validator tracks lock-class usage history into 4n + 1 separate state bits:
 
-- 'ever held in hardirq context'                    [ == hardirq-safe   ]
-- 'ever held in softirq context'                    [ == softirq-safe   ]
-- 'ever held with hardirqs enabled'                 [ == hardirq-unsafe ]
-- 'ever held with softirqs and hardirqs enabled'    [ == softirq-unsafe ]
+- 'ever held in STATE context'
+- 'ever head as readlock in STATE context'
+- 'ever head with STATE enabled'
+- 'ever head as readlock with STATE enabled'
+
+Where STATE can be either one of (kernel/lockdep_states.h)
+ - hardirq
+ - softirq
+ - reclaim_fs
 
 - 'ever used'                                       [ == !unused        ]
 
-When locking rules are violated, these state bits are presented in the
-locking error messages, inside curlies.  A contrived example:
+When locking rules are violated, these state bits are presented in the
+locking error messages, inside curlies. A contrived example:
 
    modprobe/2287 is trying to acquire lock:
-    (&sio_locks[i].lock){--..}, at: [<c02867fd>] mutex_lock+0x21/0x24
+    (&sio_locks[i].lock){-.-...}, at: [<c02867fd>] mutex_lock+0x21/0x24
 
    but task is already holding lock:
-    (&sio_locks[i].lock){--..}, at: [<c02867fd>] mutex_lock+0x21/0x24
+    (&sio_locks[i].lock){-.-...}, at: [<c02867fd>] mutex_lock+0x21/0x24
 
 
-The bit position indicates hardirq, softirq, hardirq-read,
-softirq-read respectively, and the character displayed in each
-indicates:
+The bit position indicates STATE, STATE-read, for each of the states listed
+above, and the character displayed in each indicates:
 
    '.'  acquired while irqs disabled
    '+'  acquired in irq context
    '-'  acquired with irqs enabled
-   '?' read acquired in irq context with irqs enabled.
+   '?'  acquired in irq context with irqs enabled.
 
 Unused mutexes cannot be part of the cause of an error.
 
diff --git a/Documentation/misc-devices/isl29003 b/Documentation/misc-devices/isl29003
new file mode 100644 (file)
index 0000000..c4ff5f3
--- /dev/null
@@ -0,0 +1,62 @@
+Kernel driver isl29003
+=====================
+
+Supported chips:
+* Intersil ISL29003
+Prefix: 'isl29003'
+Addresses scanned: none
+Datasheet:
+http://www.intersil.com/data/fn/fn7464.pdf
+
+Author: Daniel Mack <daniel@caiaq.de>
+
+
+Description
+-----------
+The ISL29003 is an integrated light sensor with a 16-bit integrating type
+ADC, I2C user programmable lux range select for optimized counts/lux, and
+I2C multi-function control and monitoring capabilities. The internal ADC
+provides 16-bit resolution while rejecting 50Hz and 60Hz flicker caused by
+artificial light sources.
+
+The driver allows to set the lux range, the bit resolution, the operational
+mode (see below) and the power state of device and can read the current lux
+value, of course.
+
+
+Detection
+---------
+
+The ISL29003 does not have an ID register which could be used to identify
+it, so the detection routine will just try to read from the configured I2C
+addess and consider the device to be present as soon as it ACKs the
+transfer.
+
+
+Sysfs entries
+-------------
+
+range:
+       0: 0 lux to 1000 lux (default)
+       1: 0 lux to 4000 lux
+       2: 0 lux to 16,000 lux
+       3: 0 lux to 64,000 lux
+
+resolution:
+       0: 2^16 cycles (default)
+       1: 2^12 cycles
+       2: 2^8 cycles
+       3: 2^4 cycles
+
+mode:
+       0: diode1's current (unsigned 16bit) (default)
+       1: diode1's current (unsigned 16bit)
+       2: difference between diodes (l1 - l2, signed 15bit)
+
+power_state:
+       0: device is disabled (default)
+       1: device is enabled
+
+lux (read only):
+       returns the value from the last sensor reading
+
index cc453110fc4651bcbc135e2dfc163e45776eb574..0732cdd05ba1e43b9ff05f336036938de588ad0b 100644 (file)
@@ -35,30 +35,30 @@ Example:
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "fsl,mpc8349-dma", "fsl,elo-dma";
-               reg = <82a8 4>;
-               ranges = <0 8100 1a4>;
+               reg = <0x82a8 4>;
+               ranges = <0 0x8100 0x1a4>;
                interrupt-parent = <&ipic>;
-               interrupts = <47 8>;
+               interrupts = <71 8>;
                cell-index = <0>;
                dma-channel@0 {
                        compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                        cell-index = <0>;
-                       reg = <0 80>;
+                       reg = <0 0x80>;
                };
                dma-channel@80 {
                        compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                        cell-index = <1>;
-                       reg = <80 80>;
+                       reg = <0x80 0x80>;
                };
                dma-channel@100 {
                        compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                        cell-index = <2>;
-                       reg = <100 80>;
+                       reg = <0x100 0x80>;
                };
                dma-channel@180 {
                        compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                        cell-index = <3>;
-                       reg = <180 80>;
+                       reg = <0x180 0x80>;
                };
        };
 
@@ -93,36 +93,36 @@ Example:
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "fsl,mpc8540-dma", "fsl,eloplus-dma";
-               reg = <21300 4>;
-               ranges = <0 21100 200>;
+               reg = <0x21300 4>;
+               ranges = <0 0x21100 0x200>;
                cell-index = <0>;
                dma-channel@0 {
                        compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
-                       reg = <0 80>;
+                       reg = <0 0x80>;
                        cell-index = <0>;
                        interrupt-parent = <&mpic>;
-                       interrupts = <14 2>;
+                       interrupts = <20 2>;
                };
                dma-channel@80 {
                        compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
-                       reg = <80 80>;
+                       reg = <0x80 0x80>;
                        cell-index = <1>;
                        interrupt-parent = <&mpic>;
-                       interrupts = <15 2>;
+                       interrupts = <21 2>;
                };
                dma-channel@100 {
                        compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
-                       reg = <100 80>;
+                       reg = <0x100 0x80>;
                        cell-index = <2>;
                        interrupt-parent = <&mpic>;
-                       interrupts = <16 2>;
+                       interrupts = <22 2>;
                };
                dma-channel@180 {
                        compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
-                       reg = <180 80>;
+                       reg = <0x180 0x80>;
                        cell-index = <3>;
                        interrupt-parent = <&mpic>;
-                       interrupts = <17 2>;
+                       interrupts = <23 2>;
                };
        };
 
diff --git a/Documentation/powerpc/dts-bindings/fsl/esdhc.txt b/Documentation/powerpc/dts-bindings/fsl/esdhc.txt
new file mode 100644 (file)
index 0000000..6008465
--- /dev/null
@@ -0,0 +1,24 @@
+* Freescale Enhanced Secure Digital Host Controller (eSDHC)
+
+The Enhanced Secure Digital Host Controller provides an interface
+for MMC, SD, and SDIO types of memory cards.
+
+Required properties:
+  - compatible : should be
+    "fsl,<chip>-esdhc", "fsl,mpc8379-esdhc" for MPC83xx processors.
+    "fsl,<chip>-esdhc", "fsl,mpc8536-esdhc" for MPC85xx processors.
+  - reg : should contain eSDHC registers location and length.
+  - interrupts : should contain eSDHC interrupt.
+  - interrupt-parent : interrupt source phandle.
+  - clock-frequency : specifies eSDHC base clock frequency.
+
+Example:
+
+sdhci@2e000 {
+       compatible = "fsl,mpc8378-esdhc", "fsl,mpc8379-esdhc";
+       reg = <0x2e000 0x1000>;
+       interrupts = <42 0x8>;
+       interrupt-parent = <&ipic>;
+       /* Filled in by U-Boot */
+       clock-frequency = <0>;
+};
index a2d963998a654ab5042d67b24130dbf33dc12f71..5ff76c9c57d27212d88723b85442e431cfa1aed4 100644 (file)
@@ -4,44 +4,56 @@ The SSI is a serial device that communicates with audio codecs.  It can
 be programmed in AC97, I2S, left-justified, or right-justified modes.
 
 Required properties:
-- compatible     : compatible list, containing "fsl,ssi"
-- cell-index     : the SSI, <0> = SSI1, <1> = SSI2, and so on
-- reg            : offset and length of the register set for the device
-- interrupts     : <a b> where a is the interrupt number and b is a
-                     field that represents an encoding of the sense and
-                   level information for the interrupt.  This should be
-                   encoded based on the information in section 2)
-                   depending on the type of interrupt controller you
-                   have.
-- interrupt-parent : the phandle for the interrupt controller that
-                     services interrupts for this device.
-- fsl,mode       : the operating mode for the SSI interface
-                   "i2s-slave" - I2S mode, SSI is clock slave
-                   "i2s-master" - I2S mode, SSI is clock master
-                   "lj-slave" - left-justified mode, SSI is clock slave
-                   "lj-master" - l.j. mode, SSI is clock master
-                   "rj-slave" - right-justified mode, SSI is clock slave
-                   "rj-master" - r.j., SSI is clock master
-                   "ac97-slave" - AC97 mode, SSI is clock slave
-                   "ac97-master" - AC97 mode, SSI is clock master
-- fsl,playback-dma: phandle to a node for the DMA channel to use for
+- compatible:       Compatible list, contains "fsl,ssi".
+- cell-index:       The SSI, <0> = SSI1, <1> = SSI2, and so on.
+- reg:              Offset and length of the register set for the device.
+- interrupts:       <a b> where a is the interrupt number and b is a
+                    field that represents an encoding of the sense and
+                    level information for the interrupt.  This should be
+                    encoded based on the information in section 2)
+                    depending on the type of interrupt controller you
+                    have.
+- interrupt-parent: The phandle for the interrupt controller that
+                    services interrupts for this device.
+- fsl,mode:         The operating mode for the SSI interface.
+                    "i2s-slave" - I2S mode, SSI is clock slave
+                    "i2s-master" - I2S mode, SSI is clock master
+                    "lj-slave" - left-justified mode, SSI is clock slave
+                    "lj-master" - l.j. mode, SSI is clock master
+                    "rj-slave" - right-justified mode, SSI is clock slave
+                    "rj-master" - r.j., SSI is clock master
+                    "ac97-slave" - AC97 mode, SSI is clock slave
+                    "ac97-master" - AC97 mode, SSI is clock master
+- fsl,playback-dma: Phandle to a node for the DMA channel to use for
                     playback of audio.  This is typically dictated by SOC
                     design.  See the notes below.
-- fsl,capture-dma:  phandle to a node for the DMA channel to use for
+- fsl,capture-dma:  Phandle to a node for the DMA channel to use for
                     capture (recording) of audio.  This is typically dictated
                     by SOC design.  See the notes below.
+- fsl,fifo-depth:   The number of elements in the transmit and receive FIFOs.
+                    This number is the maximum allowed value for SFCSR[TFWM0].
+- fsl,ssi-asynchronous:
+                    If specified, the SSI is to be programmed in asynchronous
+                    mode.  In this mode, pins SRCK, STCK, SRFS, and STFS must
+                    all be connected to valid signals.  In synchronous mode,
+                    SRCK and SRFS are ignored.  Asynchronous mode allows
+                    playback and capture to use different sample sizes and
+                    sample rates.  Some drivers may require that SRCK and STCK
+                    be connected together, and SRFS and STFS be connected
+                    together.  This would still allow different sample sizes,
+                    but not different sample rates.
 
 Optional properties:
-- codec-handle   : phandle to a 'codec' node that defines an audio
-                   codec connected to this SSI.  This node is typically
-                   a child of an I2C or other control node.
+- codec-handle:     Phandle to a 'codec' node that defines an audio
+                    codec connected to this SSI.  This node is typically
+                    a child of an I2C or other control node.
 
 Child 'codec' node required properties:
-- compatible     : compatible list, contains the name of the codec
+- compatible:       Compatible list, contains the name of the codec
 
 Child 'codec' node optional properties:
-- clock-frequency  : The frequency of the input clock, which typically
-                     comes from an on-board dedicated oscillator.
+- clock-frequency:  The frequency of the input clock, which typically comes
+                    from an on-board dedicated oscillator.
 
 Notes on fsl,playback-dma and fsl,capture-dma:
 
diff --git a/Documentation/powerpc/dts-bindings/mmc-spi-slot.txt b/Documentation/powerpc/dts-bindings/mmc-spi-slot.txt
new file mode 100644 (file)
index 0000000..c39ac28
--- /dev/null
@@ -0,0 +1,23 @@
+MMC/SD/SDIO slot directly connected to a SPI bus
+
+Required properties:
+- compatible : should be "mmc-spi-slot".
+- reg : should specify SPI address (chip-select number).
+- spi-max-frequency : maximum frequency for this device (Hz).
+- voltage-ranges : two cells are required, first cell specifies minimum
+  slot voltage (mV), second cell specifies maximum slot voltage (mV).
+  Several ranges could be specified.
+- gpios : (optional) may specify GPIOs in this order: Card-Detect GPIO,
+  Write-Protect GPIO.
+
+Example:
+
+       mmc-slot@0 {
+               compatible = "fsl,mpc8323rdb-mmc-slot",
+                            "mmc-spi-slot";
+               reg = <0>;
+               gpios = <&qe_pio_d 14 1
+                        &qe_pio_d 15 0>;
+               voltage-ranges = <3300 3300>;
+               spi-max-frequency = <50000000>;
+       };
index a20a9066dc4c21af860c5dbbb06ef356af565ff7..1286f455992f195f2a0ae1511614d9617dbe22b3 100644 (file)
@@ -10,6 +10,8 @@ fs.txt
        - documentation for /proc/sys/fs/*.
 kernel.txt
        - documentation for /proc/sys/kernel/*.
+net.txt
+       - documentation for /proc/sys/net/*.
 sunrpc.txt
        - documentation for /proc/sys/sunrpc/*.
 vm.txt
index f99254327ae59b59971d979b38cc083d3ac096e5..1458448436cc4589bc329167ba945eb92719792b 100644 (file)
@@ -1,5 +1,6 @@
 Documentation for /proc/sys/fs/*       kernel version 2.2.10
        (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
+       (c) 2009,        Shen Feng<shen@cn.fujitsu.com>
 
 For general info and legal blurb, please look in README.
 
@@ -14,7 +15,12 @@ kernel. Since some of the files _can_ be used to screw up your
 system, it is advisable to read both documentation and source
 before actually making adjustments.
 
+1. /proc/sys/fs
+----------------------------------------------------------
+
 Currently, these files are in /proc/sys/fs:
+- aio-max-nr
+- aio-nr
 - dentry-state
 - dquot-max
 - dquot-nr
@@ -30,8 +36,15 @@ Currently, these files are in /proc/sys/fs:
 - super-max
 - super-nr
 
-Documentation for the files in /proc/sys/fs/binfmt_misc is
-in Documentation/binfmt_misc.txt.
+==============================================================
+
+aio-nr & aio-max-nr:
+
+aio-nr is the running total of the number of events specified on the
+io_setup system call for all currently active aio contexts.  If aio-nr
+reaches aio-max-nr then io_setup will fail with EAGAIN.  Note that
+raising aio-max-nr does not result in the pre-allocation or re-sizing
+of any kernel data structures.
 
 ==============================================================
 
@@ -178,3 +191,60 @@ requests.  aio-max-nr allows you to change the maximum value
 aio-nr can grow to.
 
 ==============================================================
+
+
+2. /proc/sys/fs/binfmt_misc
+----------------------------------------------------------
+
+Documentation for the files in /proc/sys/fs/binfmt_misc is
+in Documentation/binfmt_misc.txt.
+
+
+3. /proc/sys/fs/mqueue - POSIX message queues filesystem
+----------------------------------------------------------
+
+The "mqueue"  filesystem provides  the necessary kernel features to enable the
+creation of a  user space  library that  implements  the  POSIX message queues
+API (as noted by the  MSG tag in the  POSIX 1003.1-2001 version  of the System
+Interfaces specification.)
+
+The "mqueue" filesystem contains values for determining/setting  the amount of
+resources used by the file system.
+
+/proc/sys/fs/mqueue/queues_max is a read/write  file for  setting/getting  the
+maximum number of message queues allowed on the system.
+
+/proc/sys/fs/mqueue/msg_max  is  a  read/write file  for  setting/getting  the
+maximum number of messages in a queue value.  In fact it is the limiting value
+for another (user) limit which is set in mq_open invocation. This attribute of
+a queue must be less or equal then msg_max.
+
+/proc/sys/fs/mqueue/msgsize_max is  a read/write  file for setting/getting the
+maximum  message size value (it is every  message queue's attribute set during
+its creation).
+
+
+4. /proc/sys/fs/epoll - Configuration options for the epoll interface
+--------------------------------------------------------
+
+This directory contains configuration options for the epoll(7) interface.
+
+max_user_instances
+------------------
+
+This is the maximum number of epoll file descriptors that a single user can
+have open at a given time. The default value is 128, and should be enough
+for normal users.
+
+max_user_watches
+----------------
+
+Every epoll file descriptor can store a number of files to be monitored
+for event readiness. Each one of these monitored files constitutes a "watch".
+This configuration option sets the maximum number of "watches" that are
+allowed for each user.
+Each "watch" costs roughly 90 bytes on a 32bit kernel, and roughly 160 bytes
+on a 64bit one.
+The current default value for  max_user_watches  is the 1/32 of the available
+low memory, divided for the "watch" cost in bytes.
+
index a4ccdd1981cfbc9f45b8aaabf46017dd739ab5fa..f11ca7979fa67b5bbf08339cf473d110ecf92f7d 100644 (file)
@@ -1,5 +1,6 @@
 Documentation for /proc/sys/kernel/*   kernel version 2.2.10
        (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
+       (c) 2009,        Shen Feng<shen@cn.fujitsu.com>
 
 For general info and legal blurb, please look in README.
 
@@ -18,6 +19,7 @@ Currently, these files might (depending on your configuration)
 show up in /proc/sys/kernel:
 - acpi_video_flags
 - acct
+- auto_msgmni
 - core_pattern
 - core_uses_pid
 - ctrl-alt-del
@@ -33,6 +35,7 @@ show up in /proc/sys/kernel:
 - msgmax
 - msgmnb
 - msgmni
+- nmi_watchdog
 - osrelease
 - ostype
 - overflowgid
@@ -40,6 +43,7 @@ show up in /proc/sys/kernel:
 - panic
 - pid_max
 - powersave-nap               [ PPC only ]
+- panic_on_unrecovered_nmi
 - printk
 - randomize_va_space
 - real-root-dev               ==> Documentation/initrd.txt
@@ -55,6 +59,7 @@ show up in /proc/sys/kernel:
 - sysrq                       ==> Documentation/sysrq.txt
 - tainted
 - threads-max
+- unknown_nmi_panic
 - version
 
 ==============================================================
@@ -381,3 +386,51 @@ can be ORed together:
  512 - A kernel warning has occurred.
 1024 - A module from drivers/staging was loaded.
 
+==============================================================
+
+auto_msgmni:
+
+Enables/Disables automatic recomputing of msgmni upon memory add/remove or
+upon ipc namespace creation/removal (see the msgmni description above).
+Echoing "1" into this file enables msgmni automatic recomputing.
+Echoing "0" turns it off.
+auto_msgmni default value is 1.
+
+==============================================================
+
+nmi_watchdog:
+
+Enables/Disables the NMI watchdog on x86 systems.  When the value is non-zero
+the NMI watchdog is enabled and will continuously test all online cpus to
+determine whether or not they are still functioning properly. Currently,
+passing "nmi_watchdog=" parameter at boot time is required for this function
+to work.
+
+If LAPIC NMI watchdog method is in use (nmi_watchdog=2 kernel parameter), the
+NMI watchdog shares registers with oprofile. By disabling the NMI watchdog,
+oprofile may have more registers to utilize.
+
+==============================================================
+
+unknown_nmi_panic:
+
+The value in this file affects behavior of handling NMI. When the value is
+non-zero, unknown NMI is trapped and then panic occurs. At that time, kernel
+debugging information is displayed on console.
+
+NMI switch that most IA32 servers have fires unknown NMI up, for example.
+If a system hangs up, try pressing the NMI switch.
+
+==============================================================
+
+panic_on_unrecovered_nmi:
+
+The default Linux behaviour on an NMI of either memory or unknown is to continue
+operation. For many environments such as scientific computing it is preferable
+that the box is taken out and the error dealt with than an uncorrected
+parity/ECC error get propogated.
+
+A small number of systems do generate NMI's for bizarre random reasons such as
+power management so the default is off. That sysctl works like the existing
+panic controls already in that directory.
+
diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt
new file mode 100644 (file)
index 0000000..a34d55b
--- /dev/null
@@ -0,0 +1,175 @@
+Documentation for /proc/sys/net/*      kernel version 2.4.0-test11-pre4
+       (c) 1999                Terrehon Bowden <terrehon@pacbell.net>
+                               Bodo Bauer <bb@ricochet.net>
+       (c) 2000                Jorge Nerin <comandante@zaralinux.com>
+       (c) 2009                Shen Feng <shen@cn.fujitsu.com>
+
+For general info and legal blurb, please look in README.
+
+==============================================================
+
+This file contains the documentation for the sysctl files in
+/proc/sys/net and is valid for Linux kernel version 2.4.0-test11-pre4.
+
+The interface  to  the  networking  parts  of  the  kernel  is  located  in
+/proc/sys/net. The following table shows all possible subdirectories.You may
+see only some of them, depending on your kernel's configuration.
+
+
+Table : Subdirectories in /proc/sys/net
+..............................................................................
+ Directory Content             Directory  Content
+ core      General parameter   appletalk  Appletalk protocol
+ unix      Unix domain sockets netrom     NET/ROM
+ 802       E802 protocol       ax25       AX25
+ ethernet  Ethernet protocol   rose       X.25 PLP layer
+ ipv4      IP version 4        x25        X.25 protocol
+ ipx       IPX                 token-ring IBM token ring
+ bridge    Bridging            decnet     DEC net
+ ipv6      IP version 6
+..............................................................................
+
+1. /proc/sys/net/core - Network core options
+-------------------------------------------------------
+
+rmem_default
+------------
+
+The default setting of the socket receive buffer in bytes.
+
+rmem_max
+--------
+
+The maximum receive socket buffer size in bytes.
+
+wmem_default
+------------
+
+The default setting (in bytes) of the socket send buffer.
+
+wmem_max
+--------
+
+The maximum send socket buffer size in bytes.
+
+message_burst and message_cost
+------------------------------
+
+These parameters  are used to limit the warning messages written to the kernel
+log from  the  networking  code.  They  enforce  a  rate  limit  to  make  a
+denial-of-service attack  impossible. A higher message_cost factor, results in
+fewer messages that will be written. Message_burst controls when messages will
+be dropped.  The  default  settings  limit  warning messages to one every five
+seconds.
+
+warnings
+--------
+
+This controls console messages from the networking stack that can occur because
+of problems on the network like duplicate address or bad checksums. Normally,
+this should be enabled, but if the problem persists the messages can be
+disabled.
+
+netdev_budget
+-------------
+
+Maximum number of packets taken from all interfaces in one polling cycle (NAPI
+poll). In one polling cycle interfaces which are registered to polling are
+probed in a round-robin manner. The limit of packets in one such probe can be
+set per-device via sysfs class/net/<device>/weight .
+
+netdev_max_backlog
+------------------
+
+Maximum number  of  packets,  queued  on  the  INPUT  side, when the interface
+receives packets faster than kernel can process them.
+
+optmem_max
+----------
+
+Maximum ancillary buffer size allowed per socket. Ancillary data is a sequence
+of struct cmsghdr structures with appended data.
+
+2. /proc/sys/net/unix - Parameters for Unix domain sockets
+-------------------------------------------------------
+
+There is only one file in this directory.
+unix_dgram_qlen limits the max number of datagrams queued in Unix domain
+socket's buffer. It will not take effect unless PF_UNIX flag is spicified.
+
+
+3. /proc/sys/net/ipv4 - IPV4 settings
+-------------------------------------------------------
+Please see: Documentation/networking/ip-sysctl.txt and ipvs-sysctl.txt for
+descriptions of these entries.
+
+
+4. Appletalk
+-------------------------------------------------------
+
+The /proc/sys/net/appletalk  directory  holds the Appletalk configuration data
+when Appletalk is loaded. The configurable parameters are:
+
+aarp-expiry-time
+----------------
+
+The amount  of  time  we keep an ARP entry before expiring it. Used to age out
+old hosts.
+
+aarp-resolve-time
+-----------------
+
+The amount of time we will spend trying to resolve an Appletalk address.
+
+aarp-retransmit-limit
+---------------------
+
+The number of times we will retransmit a query before giving up.
+
+aarp-tick-time
+--------------
+
+Controls the rate at which expires are checked.
+
+The directory  /proc/net/appletalk  holds the list of active Appletalk sockets
+on a machine.
+
+The fields  indicate  the DDP type, the local address (in network:node format)
+the remote  address,  the  size of the transmit pending queue, the size of the
+received queue  (bytes waiting for applications to read) the state and the uid
+owning the socket.
+
+/proc/net/atalk_iface lists  all  the  interfaces  configured for appletalk.It
+shows the  name  of the interface, its Appletalk address, the network range on
+that address  (or  network number for phase 1 networks), and the status of the
+interface.
+
+/proc/net/atalk_route lists  each  known  network  route.  It lists the target
+(network) that the route leads to, the router (may be directly connected), the
+route flags, and the device the route is using.
+
+
+5. IPX
+-------------------------------------------------------
+
+The IPX protocol has no tunable values in proc/sys/net.
+
+The IPX  protocol  does,  however,  provide  proc/net/ipx. This lists each IPX
+socket giving  the  local  and  remote  addresses  in  Novell  format (that is
+network:node:port). In  accordance  with  the  strange  Novell  tradition,
+everything but the port is in hex. Not_Connected is displayed for sockets that
+are not  tied to a specific remote address. The Tx and Rx queue sizes indicate
+the number  of  bytes  pending  for  transmission  and  reception.  The  state
+indicates the  state  the  socket  is  in and the uid is the owning uid of the
+socket.
+
+The /proc/net/ipx_interface  file lists all IPX interfaces. For each interface
+it gives  the network number, the node number, and indicates if the network is
+the primary  network.  It  also  indicates  which  device  it  is bound to (or
+Internal for  internal  networks)  and  the  Frame  Type if appropriate. Linux
+supports 802.3,  802.2,  802.2  SNAP  and DIX (Blue Book) ethernet framing for
+IPX.
+
+The /proc/net/ipx_route  table  holds  a list of IPX routes. For each route it
+gives the  destination  network, the router node (or Directly) and the network
+address of the router (or Connected) for internal networks.
index 9e592c718afb4bb41737399b29ff088adca386da..afa2946892da0e8c785d6b1d2fe879751b397499 100644 (file)
@@ -81,6 +81,8 @@ On all -  write a character to /proc/sysrq-trigger.  e.g.:
 
 'i'     - Send a SIGKILL to all processes, except for init.
 
+'j'     - Forcibly "Just thaw it" - filesystems frozen by the FIFREEZE ioctl.
+
 'k'     - Secure Access Key (SAK) Kills all programs on the current virtual
           console. NOTE: See important comments below in SAK section.
 
@@ -160,6 +162,9 @@ t'E'rm and k'I'll are useful if you have some sort of runaway process you
 are unable to kill any other way, especially if it's spawning other
 processes.
 
+"'J'ust thaw it" is useful if your system becomes unresponsive due to a frozen
+(probably root) filesystem via the FIFREEZE ioctl.
+
 *  Sometimes SysRq seems to get 'stuck' after using it, what can I do?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 That happens to me, also. I've found that tapping shift, alt, and control
index 0d93fa1ac25e344311ca53d71adb859c24984b52..f11c583295e9a9e88519002e6f759a95625ead26 100644 (file)
 134 -> Adlink RTV24
 135 -> DViCO FusionHDTV 5 Lite                             [18ac:d500]
 136 -> Acorp Y878F                                         [9511:1540]
-137 -> Conceptronic CTVFMi v2
+137 -> Conceptronic CTVFMi v2                              [036e:109e]
 138 -> Prolink Pixelview PV-BT878P+ (Rev.2E)
 139 -> Prolink PixelView PlayTV MPEG2 PV-M4900
 140 -> Osprey 440                                          [0070:ff07]
 153 -> PHYTEC VD-012 (bt878)
 154 -> PHYTEC VD-012-X1 (bt878)
 155 -> PHYTEC VD-012-X2 (bt878)
+156 -> IVCE-8784                                           [0000:f050,0001:f050,0002:f050,0003:f050]
+157 -> Geovision GV-800(S) (master)                        [800a:763d]
+158 -> Geovision GV-800(S) (slave)                         [800b:763d,800c:763d,800d:763d]
+159 -> ProVideo PV183                                      [1830:1540,1831:1540,1832:1540,1833:1540,1834:1540,1835:1540,1836:1540,1837:1540]
index 35ea130e9898c21231347559f601ea572687cb08..91aa3c0f0dd29b47cd6fff8fbea649e523ce2e75 100644 (file)
@@ -12,3 +12,7 @@
  11 -> DViCO FusionHDTV DVB-T Dual Express                 [18ac:db78]
  12 -> Leadtek Winfast PxDVR3200 H                         [107d:6681]
  13 -> Compro VideoMate E650F                              [185b:e800]
+ 14 -> TurboSight TBS 6920                                 [6920:8888]
+ 15 -> TeVii S470                                          [d470:9022]
+ 16 -> DVBWorld DVB-S2 2005                                [0001:2005]
+ 17 -> NetUP Dual DVB-S2 CI                                [1b55:2a2c]
index 0d08f1edcf6d1d978dbfd6265b17126bb87fe96f..71e9db0b26f74d43ab7025caef914ec462f13707 100644 (file)
@@ -77,3 +77,4 @@
  76 -> SATTRADE ST4200 DVB-S/S2                            [b200:4200]
  77 -> TBS 8910 DVB-S                                      [8910:8888]
  78 -> Prof 6200 DVB-S                                     [b022:3022]
+ 79 -> Terratec Cinergy HT PCI MKII                        [153b:1177]
index 75bded8a4aa2e449b09c4454da01b3eeae76d022..78d0a6eed5715809855698d76de27e1bcbde4464 100644 (file)
@@ -7,12 +7,12 @@
   6 -> Terratec Cinergy 200 USB                 (em2800)
   7 -> Leadtek Winfast USB II                   (em2800)        [0413:6023]
   8 -> Kworld USB2800                           (em2800)
-  9 -> Pinnacle Dazzle DVC 90/DVC 100           (em2820/em2840) [2304:0207,2304:021a]
+  9 -> Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker (em2820/em2840) [1b80:e302,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)
  13 -> Terratec Prodigy XS                      (em2880)        [0ccd:0047]
- 14 -> Pixelview Prolink PlayTV USB 2.0         (em2820/em2840)
+ 14 -> SIIG AVTuner-PVR / Pixelview Prolink PlayTV USB 2.0 (em2820/em2840)
  15 -> V-Gear PocketTV                          (em2800)
  16 -> Hauppauge WinTV HVR 950                  (em2883)        [2040:6513,2040:6517,2040:651b]
  17 -> Pinnacle PCTV HD Pro Stick               (em2880)        [2304:0227]
@@ -30,7 +30,6 @@
  30 -> Videology 20K14XUSB USB2.0               (em2820/em2840)
  31 -> Usbgear VD204v9                          (em2821)
  32 -> Supercomp USB 2.0 TV                     (em2821)
- 33 -> SIIG AVTuner-PVR/Prolink PlayTV USB 2.0  (em2821)
  34 -> Terratec Cinergy A Hybrid XS             (em2860)        [0ccd:004f]
  35 -> Typhoon DVD Maker                        (em2860)
  36 -> NetGMBH Cam                              (em2860)
@@ -58,3 +57,7 @@
  58 -> Compro VideoMate ForYou/Stereo           (em2820/em2840) [185b:2041]
  60 -> Hauppauge WinTV HVR 850                  (em2883)        [2040:651f]
  61 -> Pixelview PlayTV Box 4 USB 2.0           (em2820/em2840)
+ 62 -> Gadmei TVR200                            (em2820/em2840)
+ 63 -> Kaiomy TVnPC U2                          (em2860)        [eb1a:e303]
+ 64 -> Easy Cap Capture DC-60                   (em2860)
+ 65 -> IO-DATA GV-MVP/SZ                        (em2820/em2840) [04bb:0515]
index b8d470596b0cceadc9b74ed7005d3cb3d144aeed..6dacf2825259a143de95e0d5fe15a67194b7b0ab 100644 (file)
 152 -> Asus Tiger Rev:1.00                      [1043:4857]
 153 -> Kworld Plus TV Analog Lite PCI           [17de:7128]
 154 -> Avermedia AVerTV GO 007 FM Plus          [1461:f31d]
+155 -> Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid  [0070:6706,0070:6708]
+156 -> Hauppauge WinTV-HVR1110r3                [0070:6707,0070:6709,0070:670a]
index 295462b2317a46a3c191c446030030efea063bdb..0e89e76762983ebf964bf9d3fd3e5d78ebc4202e 100644 (file)
@@ -401,8 +401,7 @@ Additional notes for software developers:
    first set the correct norm. Well, it seems logically correct: TV
    standard is "more constant" for current country than geometry
    settings of a variety of TV capture cards which may work in ITU or
-   square pixel format. Remember that users now can lock the norm to
-   avoid any ambiguity.
+   square pixel format.
 --
 Please note that lavplay/lavrec are also included in the MJPEG-tools
 (http://mjpeg.sf.net/).
index 5ef75787f83a271c3916614d61549c87b5087af3..bbe3ed667d911a1a6fa06646f21b22fe34c464aa 100644 (file)
@@ -81,16 +81,6 @@ tuner.o
                pal=[bdgil]     select PAL variant (used for some tuners
                                only, important for the audio carrier).
 
-tvmixer.o
-       registers a mixer device for the TV card's volume/bass/treble
-       controls (requires a i2c audio control chip like the msp3400).
-
-       insmod args:
-               debug=1         print some debug info to the syslog.
-               devnr=n         allocate device #n (0 == /dev/mixer,
-                               1 = /dev/mixer1, ...), default is to
-                               use the first free one.
-
 tvaudio.o
        new, experimental module which is supported to provide a single
        driver for all simple i2c audio control chips (tda/tea*).
index 7ca2154c2bf5eb75221c9186361333b3fe4bfdc6..3a367cdb664e9b1e8947a5d427a19f1bf23f1b22 100644 (file)
@@ -63,8 +63,8 @@ If you have some knowledge and spare time, please try to fix this
 yourself (patches very welcome of course...)  You know: The linux
 slogan is "Do it yourself".
 
-There is a mailing list: video4linux-list@redhat.com.
-https://listman.redhat.com/mailman/listinfo/video4linux-list
+There is a mailing list: linux-media@vger.kernel.org
+http://vger.kernel.org/vger-lists.html#linux-media
 
 If you have trouble with some specific TV card, try to ask there
 instead of mailing me directly.  The chance that someone with the
index 0e213ed095e68b02436a2754d2869b29bbe90f44..b36148ea07501bdac37ae74b31cc258150f75a81 100644 (file)
@@ -32,6 +32,10 @@ Y, U and V planes. This code assumes frames of 720x576 (PAL) pixels.
 The width of a frame is always 720 pixels, regardless of the actual specified
 width.
 
+If the height is not a multiple of 32 lines, then the captured video is
+missing macroblocks at the end and is unusable. So the height must be a
+multiple of 32.
+
 --------------------------------------------------------------------------
 
 #include <stdio.h>
index 1c58a763014646182a17aa50efb5dc19b01425f3..98529e03a46e196b25f086e604bf0a39bbefceaf 100644 (file)
@@ -32,6 +32,7 @@ spca561               041e:403b       Creative Webcam Vista (VF0010)
 zc3xx          041e:4051       Creative Live!Cam Notebook Pro (VF0250)
 ov519          041e:4052       Creative Live! VISTA IM
 zc3xx          041e:4053       Creative Live!Cam Video IM
+vc032x         041e:405b       Creative Live! Cam Notebook Ultra (VC0130)
 ov519          041e:405f       Creative Live! VISTA VF0330
 ov519          041e:4060       Creative Live! VISTA VF0350
 ov519          041e:4061       Creative Live! VISTA VF0400
@@ -193,6 +194,7 @@ spca500             084d:0003       D-Link DSC-350
 spca500                08ca:0103       Aiptek PocketDV
 sunplus                08ca:0104       Aiptek PocketDVII 1.3
 sunplus                08ca:0106       Aiptek Pocket DV3100+
+mr97310a       08ca:0111       Aiptek PenCam VGA+
 sunplus                08ca:2008       Aiptek Mini PenCam 2 M
 sunplus                08ca:2010       Aiptek PocketCam 3M
 sunplus                08ca:2016       Aiptek PocketCam 2 Mega
@@ -215,6 +217,7 @@ pac207              093a:2468       PAC207
 pac207         093a:2470       Genius GF112
 pac207         093a:2471       Genius VideoCam ge111
 pac207         093a:2472       Genius VideoCam ge110
+pac207         093a:2474       Genius iLook 111
 pac207         093a:2476       Genius e-Messenger 112
 pac7311                093a:2600       PAC7311 Typhoon
 pac7311                093a:2601       Philips SPC 610 NC
@@ -279,6 +282,7 @@ spca561             10fd:7e50       FlyCam Usb 100
 zc3xx          10fd:8050       Typhoon Webshot II USB 300k
 ov534          1415:2000       Sony HD Eye for PS3 (SLEH 00201)
 pac207         145f:013a       Trust WB-1300N
+vc032x         15b8:6001       HP 2.0 Megapixel
 vc032x         15b8:6002       HP 2.0 Megapixel rz406aa
 spca501                1776:501c       Arowana 300K CMOS Camera
 t613           17a1:0128       TASCORP JPEG Webcam, NGS Cyclops
index 49679e6aaa7617daa69d72d7034cf5ebd0e63c20..3a7823e01b4d777b2220aa4cdf0162391b69b002 100644 (file)
@@ -1,6 +1,6 @@
 Driver for USB radios for the Silicon Labs Si470x FM Radio Receivers
 
-Copyright (c) 2008 Tobias Lorenz <tobias.lorenz@gmx.net>
+Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.net>
 
 
 Information from Silicon Labs
@@ -41,7 +41,7 @@ chips are known to work:
 - 10c4:818a: Silicon Labs USB FM Radio Reference Design
 - 06e1:a155: ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF)
 - 1b80:d700: KWorld USB FM Radio SnapMusic Mobile 700 (FM700)
-- 10c5:819a: DealExtreme USB Radio
+- 10c5:819a: Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear)
 
 
 Software
@@ -52,6 +52,7 @@ Testing is usually done with most application under Debian/testing:
 - gradio - GTK FM radio tuner
 - kradio - Comfortable Radio Application for KDE
 - radio - ncurses-based radio application
+- mplayer - The Ultimate Movie Player For Linux
 
 There is also a library libv4l, which can be used. It's going to have a function
 for frequency seeking, either by using hardware functionality as in radio-si470x
@@ -69,7 +70,7 @@ Audio Listing
 USB Audio is provided by the ALSA snd_usb_audio module. It is recommended to
 also select SND_USB_AUDIO, as this is required to get sound from the radio. For
 listing you have to redirect the sound, for example using one of the following
-commands.
+commands. Please adjust the audio devices to your needs (/dev/dsp* and hw:x,x).
 
 If you just want to test audio (very poor quality):
 cat /dev/dsp1 > /dev/dsp
@@ -80,6 +81,10 @@ sox -2 --endian little -r 96000 -t oss /dev/dsp1 -t oss /dev/dsp
 If you use arts try:
 arecord -D hw:1,0 -r96000 -c2 -f S16_LE | artsdsp aplay -B -
 
+If you use mplayer try:
+mplayer -radio adevice=hw=1.0:arate=96000 \
+       -rawaudio rate=96000 \
+       radio://<frequency>/capture
 
 Module Parameters
 =================
index ff124374e9ba3211a078b0ec042a21e6e55ec001..a31177390e551a5873a28121901dc904bebacee0 100644 (file)
@@ -47,7 +47,9 @@ All drivers have the following structure:
 3) Creating V4L2 device nodes (/dev/videoX, /dev/vbiX, /dev/radioX and
    /dev/vtxX) and keeping track of device-node specific data.
 
-4) Filehandle-specific structs containing per-filehandle data.
+4) Filehandle-specific structs containing per-filehandle data;
+
+5) video buffer handling.
 
 This is a rough schematic of how it all relates:
 
@@ -82,12 +84,20 @@ You must register the device instance:
        v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
 
 Registration will initialize the v4l2_device struct and link dev->driver_data
-to v4l2_dev. Registration will also set v4l2_dev->name to a value derived from
-dev (driver name followed by the bus_id, to be precise). You may change the
-name after registration if you want.
+to v4l2_dev. If v4l2_dev->name is empty then it will be set to a value derived
+from dev (driver name followed by the bus_id, to be precise). If you set it
+up before calling v4l2_device_register then it will be untouched. If dev is
+NULL, then you *must* setup v4l2_dev->name before calling v4l2_device_register.
 
 The first 'dev' argument is normally the struct device pointer of a pci_dev,
-usb_device or platform_device.
+usb_device or platform_device. It is rare for dev to be NULL, but it happens
+with ISA devices or when one device creates multiple PCI devices, thus making
+it impossible to associate v4l2_dev with a particular parent.
+
+You can also supply a notify() callback that can be called by sub-devices to
+notify you of events. Whether you need to set this depends on the sub-device.
+Any notifications a sub-device supports must be defined in a header in
+include/media/<subdevice>.h.
 
 You unregister with:
 
@@ -95,6 +105,17 @@ You unregister with:
 
 Unregistering will also automatically unregister all subdevs from the device.
 
+If you have a hotpluggable device (e.g. a USB device), then when a disconnect
+happens the parent device becomes invalid. Since v4l2_device has a pointer to
+that parent device it has to be cleared as well to mark that the parent is
+gone. To do this call:
+
+       v4l2_device_disconnect(struct v4l2_device *v4l2_dev);
+
+This does *not* unregister the subdevs, so you still need to call the
+v4l2_device_unregister() function for that. If your driver is not hotpluggable,
+then there is no need to call v4l2_device_disconnect().
+
 Sometimes you need to iterate over all devices registered by a specific
 driver. This is usually the case if multiple device drivers use the same
 hardware. E.g. the ivtvfb driver is a framebuffer driver that uses the ivtv
@@ -134,7 +155,7 @@ The recommended approach is as follows:
 
 static atomic_t drv_instance = ATOMIC_INIT(0);
 
-static int __devinit drv_probe(struct pci_dev *dev,
+static int __devinit drv_probe(struct pci_dev *pdev,
                                const struct pci_device_id *pci_id)
 {
        ...
@@ -218,7 +239,7 @@ to add new ops and categories.
 
 A sub-device driver initializes the v4l2_subdev struct using:
 
-       v4l2_subdev_init(subdev, &ops);
+       v4l2_subdev_init(sd, &ops);
 
 Afterwards you need to initialize subdev->name with a unique name and set the
 module owner. This is done for you if you use the i2c helper functions.
@@ -226,7 +247,7 @@ module owner. This is done for you if you use the i2c helper functions.
 A device (bridge) driver needs to register the v4l2_subdev with the
 v4l2_device:
 
-       int err = v4l2_device_register_subdev(device, subdev);
+       int err = v4l2_device_register_subdev(v4l2_dev, sd);
 
 This can fail if the subdev module disappeared before it could be registered.
 After this function was called successfully the subdev->dev field points to
@@ -234,17 +255,17 @@ the v4l2_device.
 
 You can unregister a sub-device using:
 
-       v4l2_device_unregister_subdev(subdev);
+       v4l2_device_unregister_subdev(sd);
 
-Afterwards the subdev module can be unloaded and subdev->dev == NULL.
+Afterwards the subdev module can be unloaded and sd->dev == NULL.
 
 You can call an ops function either directly:
 
-       err = subdev->ops->core->g_chip_ident(subdev, &chip);
+       err = sd->ops->core->g_chip_ident(sd, &chip);
 
 but it is better and easier to use this macro:
 
-       err = v4l2_subdev_call(subdev, core, g_chip_ident, &chip);
+       err = v4l2_subdev_call(sd, core, g_chip_ident, &chip);
 
 The macro will to the right NULL pointer checks and returns -ENODEV if subdev
 is NULL, -ENOIOCTLCMD if either subdev->core or subdev->core->g_chip_ident is
@@ -252,19 +273,19 @@ NULL, or the actual result of the subdev->ops->core->g_chip_ident ops.
 
 It is also possible to call all or a subset of the sub-devices:
 
-       v4l2_device_call_all(dev, 0, core, g_chip_ident, &chip);
+       v4l2_device_call_all(v4l2_dev, 0, core, g_chip_ident, &chip);
 
 Any subdev that does not support this ops is skipped and error results are
 ignored. If you want to check for errors use this:
 
-       err = v4l2_device_call_until_err(dev, 0, core, g_chip_ident, &chip);
+       err = v4l2_device_call_until_err(v4l2_dev, 0, core, g_chip_ident, &chip);
 
 Any error except -ENOIOCTLCMD will exit the loop with that error. If no
 errors (except -ENOIOCTLCMD) occured, then 0 is returned.
 
 The second argument to both calls is a group ID. If 0, then all subdevs are
 called. If non-zero, then only those whose group ID match that value will
-be called. Before a bridge driver registers a subdev it can set subdev->grp_id
+be called. Before a bridge driver registers a subdev it can set sd->grp_id
 to whatever value it wants (it's 0 by default). This value is owned by the
 bridge driver and the sub-device driver will never modify or use it.
 
@@ -276,6 +297,11 @@ e.g. AUDIO_CONTROLLER and specify that as the group ID value when calling
 v4l2_device_call_all(). That ensures that it will only go to the subdev
 that needs it.
 
+If the sub-device needs to notify its v4l2_device parent of an event, then
+it can call v4l2_subdev_notify(sd, notification, arg). This macro checks
+whether there is a notify() callback defined and returns -ENODEV if not.
+Otherwise the result of the notify() call is returned.
+
 The advantage of using v4l2_subdev is that it is a generic struct and does
 not contain any knowledge about the underlying hardware. So a driver might
 contain several subdevs that use an I2C bus, but also a subdev that is
@@ -340,6 +366,12 @@ Make sure to call v4l2_device_unregister_subdev(sd) when the remove() callback
 is called. This will unregister the sub-device from the bridge driver. It is
 safe to call this even if the sub-device was never registered.
 
+You need to do this because when the bridge driver destroys the i2c adapter
+the remove() callbacks are called of the i2c devices on that adapter.
+After that the corresponding v4l2_subdev structures are invalid, so they
+have to be unregistered first. Calling v4l2_device_unregister_subdev(sd)
+from the remove() callback ensures that this is always done correctly.
+
 
 The bridge driver also has some helper functions it can use:
 
@@ -349,8 +381,8 @@ This loads the given module (can be NULL if no module needs to be loaded) and
 calls i2c_new_device() with the given i2c_adapter and chip/address arguments.
 If all goes well, then it registers the subdev with the v4l2_device. It gets
 the v4l2_device by calling i2c_get_adapdata(adapter), so you should make sure
-that adapdata is set to v4l2_device when you setup the i2c_adapter in your
-driver.
+to call i2c_set_adapdata(adapter, v4l2_device) when you setup the i2c_adapter
+in your driver.
 
 You can also use v4l2_i2c_new_probed_subdev() which is very similar to
 v4l2_i2c_new_subdev(), except that it has an array of possible I2C addresses
@@ -358,6 +390,14 @@ that it should probe. Internally it calls i2c_new_probed_device().
 
 Both functions return NULL if something went wrong.
 
+Note that the chipid you pass to v4l2_i2c_new_(probed_)subdev() is usually
+the same as the module name. It allows you to specify a chip variant, e.g.
+"saa7114" or "saa7115". In general though the i2c driver autodetects this.
+The use of chipid is something that needs to be looked at more closely at a
+later date. It differs between i2c drivers and as such can be confusing.
+To see which chip variants are supported you can look in the i2c driver code
+for the i2c_device_id table. This lists all the possibilities.
+
 
 struct video_device
 -------------------
@@ -396,6 +436,15 @@ You should also set these fields:
 - ioctl_ops: if you use the v4l2_ioctl_ops to simplify ioctl maintenance
   (highly recommended to use this and it might become compulsory in the
   future!), then set this to your v4l2_ioctl_ops struct.
+- parent: you only set this if v4l2_device was registered with NULL as
+  the parent device struct. This only happens in cases where one hardware
+  device has multiple PCI devices that all share the same v4l2_device core.
+
+  The cx88 driver is an example of this: one core v4l2_device struct, but
+  it is used by both an raw video PCI device (cx8800) and a MPEG PCI device
+  (cx8802). Since the v4l2_device cannot be associated with a particular
+  PCI device it is setup without a parent device. But when the struct
+  video_device is setup you do know which parent PCI device to use.
 
 If you use v4l2_ioctl_ops, then you should set either .unlocked_ioctl or
 .ioctl to video_ioctl2 in your v4l2_file_operations struct.
@@ -499,8 +548,8 @@ There are a few useful helper functions:
 
 You can set/get driver private data in the video_device struct using:
 
-void *video_get_drvdata(struct video_device *dev);
-void video_set_drvdata(struct video_device *dev, void *data);
+void *video_get_drvdata(struct video_device *vdev);
+void video_set_drvdata(struct video_device *vdev, void *data);
 
 Note that you can safely call video_set_drvdata() before calling
 video_register_device().
@@ -519,3 +568,103 @@ void *video_drvdata(struct file *file);
 You can go from a video_device struct to the v4l2_device struct using:
 
 struct v4l2_device *v4l2_dev = vdev->v4l2_dev;
+
+video buffer helper functions
+-----------------------------
+
+The v4l2 core API provides a standard method for dealing with video
+buffers. Those methods allow a driver to implement read(), mmap() and
+overlay() on a consistent way.
+
+There are currently methods for using video buffers on devices that
+supports DMA with scatter/gather method (videobuf-dma-sg), DMA with
+linear access (videobuf-dma-contig), and vmalloced buffers, mostly
+used on USB drivers (videobuf-vmalloc).
+
+Any driver using videobuf should provide operations (callbacks) for
+four handlers:
+
+ops->buf_setup   - calculates the size of the video buffers and avoid they
+                  to waste more than some maximum limit of RAM;
+ops->buf_prepare - fills the video buffer structs and calls
+                  videobuf_iolock() to alloc and prepare mmaped memory;
+ops->buf_queue   - advices the driver that another buffer were
+                  requested (by read() or by QBUF);
+ops->buf_release - frees any buffer that were allocated.
+
+In order to use it, the driver need to have a code (generally called at
+interrupt context) that will properly handle the buffer request lists,
+announcing that a new buffer were filled.
+
+The irq handling code should handle the videobuf task lists, in order
+to advice videobuf that a new frame were filled, in order to honor to a
+request. The code is generally like this one:
+       if (list_empty(&dma_q->active))
+               return;
+
+       buf = list_entry(dma_q->active.next, struct vbuffer, vb.queue);
+
+       if (!waitqueue_active(&buf->vb.done))
+               return;
+
+       /* Some logic to handle the buf may be needed here */
+
+       list_del(&buf->vb.queue);
+       do_gettimeofday(&buf->vb.ts);
+       wake_up(&buf->vb.done);
+
+Those are the videobuffer functions used on drivers, implemented on
+videobuf-core:
+
+- Videobuf init functions
+  videobuf_queue_sg_init()
+      Initializes the videobuf infrastructure. This function should be
+      called before any other videobuf function on drivers that uses DMA
+      Scatter/Gather buffers.
+
+  videobuf_queue_dma_contig_init
+      Initializes the videobuf infrastructure. This function should be
+      called before any other videobuf function on drivers that need DMA
+      contiguous buffers.
+
+  videobuf_queue_vmalloc_init()
+      Initializes the videobuf infrastructure. This function should be
+      called before any other videobuf function on USB (and other drivers)
+      that need a vmalloced type of videobuf.
+
+- videobuf_iolock()
+  Prepares the videobuf memory for the proper method (read, mmap, overlay).
+
+- videobuf_queue_is_busy()
+  Checks if a videobuf is streaming.
+
+- videobuf_queue_cancel()
+  Stops video handling.
+
+- videobuf_mmap_free()
+  frees mmap buffers.
+
+- videobuf_stop()
+  Stops video handling, ends mmap and frees mmap and other buffers.
+
+- V4L2 api functions. Those functions correspond to VIDIOC_foo ioctls:
+   videobuf_reqbufs(), videobuf_querybuf(), videobuf_qbuf(),
+   videobuf_dqbuf(), videobuf_streamon(), videobuf_streamoff().
+
+- V4L1 api function (corresponds to VIDIOCMBUF ioctl):
+   videobuf_cgmbuf()
+      This function is used to provide backward compatibility with V4L1
+      API.
+
+- Some help functions for read()/poll() operations:
+   videobuf_read_stream()
+      For continuous stream read()
+   videobuf_read_one()
+      For snapshot read()
+   videobuf_poll_stream()
+      polling help function
+
+The better way to understand it is to take a look at vivi driver. One
+of the main reasons for vivi is to be a videobuf usage example. the
+vivi_thread_tick() does the task that the IRQ callback would do on PCI
+drivers (or the irq callback on USB).
index d6e70bef8ad0a98d040b8dd5cb5a3272a233f7bb..05769cff100998a60ba991325f48f62fe80bc889 100644 (file)
@@ -105,8 +105,8 @@ int main(int argc, char ** argv)
   struct video_picture vpic;
 
   unsigned char *buffer, *src;
-  int bpp = 24, r, g, b;
-  unsigned int i, src_depth;
+  int bpp = 24, r = 0, g = 0, b = 0;
+  unsigned int i, src_depth = 16;
 
   if (fd < 0) {
     perror(VIDEO_DEV);
index 5c81e3ae6458b1e3a8a9b115698eb3d595afb59f..7f3d1955d214fb0efa7fc16237aac2a1bd21b907 100644 (file)
@@ -65,3 +65,4 @@ Vendor  Product  Distributor     Model
 0x06d6  0x003b   Trust           Powerc@m 970Z
 0x0a17  0x004e   Pentax          Optio 50
 0x041e  0x405d   Creative        DiVi CAM 516
+0x08ca  0x2102   Aiptek          DV T300
diff --git a/Documentation/x86/earlyprintk.txt b/Documentation/x86/earlyprintk.txt
new file mode 100644 (file)
index 0000000..607b1a0
--- /dev/null
@@ -0,0 +1,101 @@
+
+Mini-HOWTO for using the earlyprintk=dbgp boot option with a
+USB2 Debug port key and a debug cable, on x86 systems.
+
+You need two computers, the 'USB debug key' special gadget and
+and two USB cables, connected like this:
+
+  [host/target] <-------> [USB debug key] <-------> [client/console]
+
+1. There are three specific hardware requirements:
+
+ a.) Host/target system needs to have USB debug port capability.
+
+ You can check this capability by looking at a 'Debug port' bit in
+ the lspci -vvv output:
+
+ # lspci -vvv
+ ...
+ 00:1d.7 USB Controller: Intel Corporation 82801H (ICH8 Family) USB2 EHCI Controller #1 (rev 03) (prog-if 20 [EHCI])
+         Subsystem: Lenovo ThinkPad T61
+         Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx-
+         Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
+         Latency: 0
+         Interrupt: pin D routed to IRQ 19
+         Region 0: Memory at fe227000 (32-bit, non-prefetchable) [size=1K]
+         Capabilities: [50] Power Management version 2
+                 Flags: PMEClk- DSI- D1- D2- AuxCurrent=375mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
+                 Status: D0 PME-Enable- DSel=0 DScale=0 PME+
+         Capabilities: [58] Debug port: BAR=1 offset=00a0
+                            ^^^^^^^^^^^ <==================== [ HERE ]
+        Kernel driver in use: ehci_hcd
+         Kernel modules: ehci-hcd
+ ...
+
+( If your system does not list a debug port capability then you probably
+  wont be able to use the USB debug key. )
+
+ b.) You also need a Netchip USB debug cable/key:
+
+        http://www.plxtech.com/products/NET2000/NET20DC/default.asp
+
+     This is a small blue plastic connector with two USB connections,
+     it draws power from its USB connections.
+
+ c.) Thirdly, you need a second client/console system with a regular USB port.
+
+2. Software requirements:
+
+ a.) On the host/target system:
+
+    You need to enable the following kernel config option:
+
+      CONFIG_EARLY_PRINTK_DBGP=y
+
+    And you need to add the boot command line: "earlyprintk=dbgp".
+    (If you are using Grub, append it to the 'kernel' line in
+     /etc/grub.conf)
+
+    NOTE: normally earlyprintk console gets turned off once the
+    regular console is alive - use "earlyprintk=dbgp,keep" to keep
+    this channel open beyond early bootup. This can be useful for
+    debugging crashes under Xorg, etc.
+
+ b.) On the client/console system:
+
+    You should enable the following kernel config option:
+
+      CONFIG_USB_SERIAL_DEBUG=y
+
+    On the next bootup with the modified kernel you should
+    get a /dev/ttyUSBx device(s).
+
+    Now this channel of kernel messages is ready to be used: start
+    your favorite terminal emulator (minicom, etc.) and set
+    it up to use /dev/ttyUSB0 - or use a raw 'cat /dev/ttyUSBx' to
+    see the raw output.
+
+ c.) On Nvidia Southbridge based systems: the kernel will try to probe
+     and find out which port has debug device connected.
+
+3. Testing that it works fine:
+
+   You can test the output by using earlyprintk=dbgp,keep and provoking
+   kernel messages on the host/target system. You can provoke a harmless
+   kernel message by for example doing:
+
+     echo h > /proc/sysrq-trigger
+
+   On the host/target system you should see this help line in "dmesg" output:
+
+     SysRq : HELP : loglevel(0-9) reBoot Crashdump terminate-all-tasks(E) memory-full-oom-kill(F) kill-all-tasks(I) saK show-backtrace-all-active-cpus(L) show-memory-usage(M) nice-all-RT-tasks(N) powerOff show-registers(P) show-all-timers(Q) unRaw Sync show-task-states(T) Unmount show-blocked-tasks(W) dump-ftrace-buffer(Z)
+
+   On the client/console system do:
+
+       cat /dev/ttyUSB0
+
+   And you should see the help line above displayed shortly after you've
+   provoked it on the host system.
+
+If it does not work then please ask about it on the linux-kernel@vger.kernel.org
+mailing list or contact the x86 maintainers.
index 08a141b0ee91eed3f0f6329d746cf94f9116c0bc..ebaf77ebd8b717e8fe42208f7b49c9b38f55e180 100644 (file)
@@ -357,6 +357,7 @@ S:  Odd Fixes for 2.4; Maintained for 2.6.
 P:     Ivan Kokshaysky
 M:     ink@jurassic.park.msu.ru
 S:     Maintained for 2.4; PCI support for 2.6.
+L:     linux-alpha@vger.kernel.org
 
 AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER
 P:     Thomas Dahlmann
@@ -1063,7 +1064,6 @@ BTTV VIDEO4LINUX DRIVER
 P:     Mauro Carvalho Chehab
 M:     mchehab@infradead.org
 L:     linux-media@vger.kernel.org
-L:     video4linux-list@redhat.com
 W:     http://linuxtv.org
 T:     git kernel.org:/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
 S:     Maintained
@@ -1945,6 +1945,12 @@ L:       lm-sensors@lm-sensors.org
 W:     http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
 S:     Maintained
 
+HYPERVISOR VIRTUAL CONSOLE DRIVER
+L:     linuxppc-dev@ozlabs.org
+L:     linux-kernel@vger.kernel.org
+S:     Odd Fixes
+F:     drivers/char/hvc_*
+
 GSPCA FINEPIX SUBDRIVER
 P:     Frank Zago
 M:     frank@zago.net
@@ -2202,25 +2208,12 @@ L:      linux-ide@vger.kernel.org
 T:     quilt kernel.org/pub/linux/kernel/people/bart/pata-2.6/
 S:     Maintained
 
-IDE/ATAPI CDROM DRIVER
+IDE/ATAPI DRIVERS
 P:     Borislav Petkov
 M:     petkovbb@gmail.com
 L:     linux-ide@vger.kernel.org
 S:     Maintained
 
-IDE/ATAPI FLOPPY DRIVERS
-P:     Paul Bristow
-M:     Paul Bristow <paul@paulbristow.net>
-W:     http://paulbristow.net/linux/idefloppy.html
-L:     linux-kernel@vger.kernel.org
-S:     Maintained
-
-IDE/ATAPI TAPE DRIVERS
-P:     Gadi Oxman
-M:     Gadi Oxman <gadio@netvision.net.il>
-L:     linux-kernel@vger.kernel.org
-S:     Maintained
-
 IDLE-I7300
 P:     Andy Henroid
 M:     andrew.d.henroid@intel.com
@@ -4838,7 +4831,6 @@ VIDEO FOR LINUX (V4L)
 P:     Mauro Carvalho Chehab
 M:     mchehab@infradead.org
 L:     linux-media@vger.kernel.org
-L:     video4linux-list@redhat.com
 W:     http://linuxtv.org
 T:     git kernel.org:/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
 S:     Maintained
index 550dab22daa14b492d88258c9eb8ae7498d76ec1..830c16a2b801d38795139b941f277011e760ba37 100644 (file)
@@ -106,3 +106,5 @@ config HAVE_CLK
          The <linux/clk.h> calls support software clock gating and
          thus are a key power management tool on many systems.
 
+config HAVE_DMA_API_DEBUG
+       bool
index fea4ea75b79d20d08cac71369968a5d95c4a104b..13cd42743810e916b1be719497ac511034ddef67 100644 (file)
@@ -80,7 +80,7 @@ struct alpha_machine_vector
        void (*update_irq_hw)(unsigned long, unsigned long, int);
        void (*ack_irq)(unsigned long);
        void (*device_interrupt)(unsigned long vector);
-       void (*machine_check)(u64 vector, u64 la);
+       void (*machine_check)(unsigned long vector, unsigned long la);
 
        void (*smp_callin)(void);
        void (*init_arch)(void);
index 2a14302c17a337194cf3df0a7d20ae4dfa28273d..cb04eaa6ba33d13fb7be187c2bcd67ea626a2bfa 100644 (file)
@@ -273,4 +273,18 @@ struct pci_dev *alpha_gendev_to_pci(struct device *dev);
 
 extern struct pci_dev *isa_bridge;
 
+extern int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val,
+                          size_t count);
+extern int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val,
+                           size_t count);
+extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
+                                     struct vm_area_struct *vma,
+                                     enum pci_mmap_state mmap_state);
+extern void pci_adjust_legacy_attr(struct pci_bus *bus,
+                                  enum pci_mmap_state mmap_type);
+#define HAVE_PCI_LEGACY        1
+
+extern int pci_create_resource_files(struct pci_dev *dev);
+extern void pci_remove_resource_files(struct pci_dev *dev);
+
 #endif /* __ALPHA_PCI_H */
index aeeb125f68513df03fe1d625de0cf1883b46c869..e38fb95cb3352fd15c5bf3e505459bc8f702500f 100644 (file)
@@ -166,6 +166,9 @@ static inline void __raw_write_unlock(raw_rwlock_t * lock)
        lock->lock = 0;
 }
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
index afe20fa58c990927fd10c5e94d41fe4d8d9eee8a..5aa40cca4f2356ea12a62e8576d50303a2b704b5 100644 (file)
@@ -309,518 +309,71 @@ extern int __min_ipl;
 #define tbia()         __tbi(-2, /* no second argument */)
 
 /*
- * Atomic exchange.
- * Since it can be used to implement critical sections
- * it must clobber "memory" (also for interrupts in UP).
+ * Atomic exchange routines.
  */
 
-static inline unsigned long
-__xchg_u8(volatile char *m, unsigned long val)
-{
-       unsigned long ret, tmp, addr64;
-
-       __asm__ __volatile__(
-       "       andnot  %4,7,%3\n"
-       "       insbl   %1,%4,%1\n"
-       "1:     ldq_l   %2,0(%3)\n"
-       "       extbl   %2,%4,%0\n"
-       "       mskbl   %2,%4,%2\n"
-       "       or      %1,%2,%2\n"
-       "       stq_c   %2,0(%3)\n"
-       "       beq     %2,2f\n"
-#ifdef CONFIG_SMP
-       "       mb\n"
-#endif
-       ".subsection 2\n"
-       "2:     br      1b\n"
-       ".previous"
-       : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
-       : "r" ((long)m), "1" (val) : "memory");
-
-       return ret;
-}
-
-static inline unsigned long
-__xchg_u16(volatile short *m, unsigned long val)
-{
-       unsigned long ret, tmp, addr64;
-
-       __asm__ __volatile__(
-       "       andnot  %4,7,%3\n"
-       "       inswl   %1,%4,%1\n"
-       "1:     ldq_l   %2,0(%3)\n"
-       "       extwl   %2,%4,%0\n"
-       "       mskwl   %2,%4,%2\n"
-       "       or      %1,%2,%2\n"
-       "       stq_c   %2,0(%3)\n"
-       "       beq     %2,2f\n"
-#ifdef CONFIG_SMP
-       "       mb\n"
-#endif
-       ".subsection 2\n"
-       "2:     br      1b\n"
-       ".previous"
-       : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
-       : "r" ((long)m), "1" (val) : "memory");
-
-       return ret;
-}
-
-static inline unsigned long
-__xchg_u32(volatile int *m, unsigned long val)
-{
-       unsigned long dummy;
-
-       __asm__ __volatile__(
-       "1:     ldl_l %0,%4\n"
-       "       bis $31,%3,%1\n"
-       "       stl_c %1,%2\n"
-       "       beq %1,2f\n"
-#ifdef CONFIG_SMP
-       "       mb\n"
-#endif
-       ".subsection 2\n"
-       "2:     br 1b\n"
-       ".previous"
-       : "=&r" (val), "=&r" (dummy), "=m" (*m)
-       : "rI" (val), "m" (*m) : "memory");
-
-       return val;
-}
-
-static inline unsigned long
-__xchg_u64(volatile long *m, unsigned long val)
-{
-       unsigned long dummy;
-
-       __asm__ __volatile__(
-       "1:     ldq_l %0,%4\n"
-       "       bis $31,%3,%1\n"
-       "       stq_c %1,%2\n"
-       "       beq %1,2f\n"
-#ifdef CONFIG_SMP
-       "       mb\n"
-#endif
-       ".subsection 2\n"
-       "2:     br 1b\n"
-       ".previous"
-       : "=&r" (val), "=&r" (dummy), "=m" (*m)
-       : "rI" (val), "m" (*m) : "memory");
+#define __ASM__MB
+#define ____xchg(type, args...)                __xchg ## type ## _local(args)
+#define ____cmpxchg(type, args...)     __cmpxchg ## type ## _local(args)
+#include <asm/xchg.h>
 
-       return val;
-}
-
-/* This function doesn't exist, so you'll get a linker error
-   if something tries to do an invalid xchg().  */
-extern void __xchg_called_with_bad_pointer(void);
-
-#define __xchg(ptr, x, size) \
-({ \
-       unsigned long __xchg__res; \
-       volatile void *__xchg__ptr = (ptr); \
-       switch (size) { \
-               case 1: __xchg__res = __xchg_u8(__xchg__ptr, x); break; \
-               case 2: __xchg__res = __xchg_u16(__xchg__ptr, x); break; \
-               case 4: __xchg__res = __xchg_u32(__xchg__ptr, x); break; \
-               case 8: __xchg__res = __xchg_u64(__xchg__ptr, x); break; \
-               default: __xchg_called_with_bad_pointer(); __xchg__res = x; \
-       } \
-       __xchg__res; \
-})
-
-#define xchg(ptr,x)                                                         \
-  ({                                                                        \
-     __typeof__(*(ptr)) _x_ = (x);                                          \
-     (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \
+#define xchg_local(ptr,x)                                              \
+  ({                                                                   \
+     __typeof__(*(ptr)) _x_ = (x);                                     \
+     (__typeof__(*(ptr))) __xchg_local((ptr), (unsigned long)_x_,      \
+                                      sizeof(*(ptr)));                 \
   })
 
-static inline unsigned long
-__xchg_u8_local(volatile char *m, unsigned long val)
-{
-       unsigned long ret, tmp, addr64;
-
-       __asm__ __volatile__(
-       "       andnot  %4,7,%3\n"
-       "       insbl   %1,%4,%1\n"
-       "1:     ldq_l   %2,0(%3)\n"
-       "       extbl   %2,%4,%0\n"
-       "       mskbl   %2,%4,%2\n"
-       "       or      %1,%2,%2\n"
-       "       stq_c   %2,0(%3)\n"
-       "       beq     %2,2f\n"
-       ".subsection 2\n"
-       "2:     br      1b\n"
-       ".previous"
-       : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
-       : "r" ((long)m), "1" (val) : "memory");
-
-       return ret;
-}
-
-static inline unsigned long
-__xchg_u16_local(volatile short *m, unsigned long val)
-{
-       unsigned long ret, tmp, addr64;
-
-       __asm__ __volatile__(
-       "       andnot  %4,7,%3\n"
-       "       inswl   %1,%4,%1\n"
-       "1:     ldq_l   %2,0(%3)\n"
-       "       extwl   %2,%4,%0\n"
-       "       mskwl   %2,%4,%2\n"
-       "       or      %1,%2,%2\n"
-       "       stq_c   %2,0(%3)\n"
-       "       beq     %2,2f\n"
-       ".subsection 2\n"
-       "2:     br      1b\n"
-       ".previous"
-       : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
-       : "r" ((long)m), "1" (val) : "memory");
-
-       return ret;
-}
-
-static inline unsigned long
-__xchg_u32_local(volatile int *m, unsigned long val)
-{
-       unsigned long dummy;
-
-       __asm__ __volatile__(
-       "1:     ldl_l %0,%4\n"
-       "       bis $31,%3,%1\n"
-       "       stl_c %1,%2\n"
-       "       beq %1,2f\n"
-       ".subsection 2\n"
-       "2:     br 1b\n"
-       ".previous"
-       : "=&r" (val), "=&r" (dummy), "=m" (*m)
-       : "rI" (val), "m" (*m) : "memory");
-
-       return val;
-}
-
-static inline unsigned long
-__xchg_u64_local(volatile long *m, unsigned long val)
-{
-       unsigned long dummy;
-
-       __asm__ __volatile__(
-       "1:     ldq_l %0,%4\n"
-       "       bis $31,%3,%1\n"
-       "       stq_c %1,%2\n"
-       "       beq %1,2f\n"
-       ".subsection 2\n"
-       "2:     br 1b\n"
-       ".previous"
-       : "=&r" (val), "=&r" (dummy), "=m" (*m)
-       : "rI" (val), "m" (*m) : "memory");
-
-       return val;
-}
-
-#define __xchg_local(ptr, x, size) \
-({ \
-       unsigned long __xchg__res; \
-       volatile void *__xchg__ptr = (ptr); \
-       switch (size) { \
-               case 1: __xchg__res = __xchg_u8_local(__xchg__ptr, x); break; \
-               case 2: __xchg__res = __xchg_u16_local(__xchg__ptr, x); break; \
-               case 4: __xchg__res = __xchg_u32_local(__xchg__ptr, x); break; \
-               case 8: __xchg__res = __xchg_u64_local(__xchg__ptr, x); break; \
-               default: __xchg_called_with_bad_pointer(); __xchg__res = x; \
-       } \
-       __xchg__res; \
-})
-
-#define xchg_local(ptr,x)                                                   \
-  ({                                                                        \
-     __typeof__(*(ptr)) _x_ = (x);                                          \
-     (__typeof__(*(ptr))) __xchg_local((ptr), (unsigned long)_x_,           \
-               sizeof(*(ptr))); \
+#define cmpxchg_local(ptr, o, n)                                       \
+  ({                                                                   \
+     __typeof__(*(ptr)) _o_ = (o);                                     \
+     __typeof__(*(ptr)) _n_ = (n);                                     \
+     (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,   \
+                                         (unsigned long)_n_,           \
+                                         sizeof(*(ptr)));              \
   })
 
-/* 
- * Atomic compare and exchange.  Compare OLD with MEM, if identical,
- * store NEW in MEM.  Return the initial value in MEM.  Success is
- * indicated by comparing RETURN with OLD.
- *
- * The memory barrier should be placed in SMP only when we actually
- * make the change. If we don't change anything (so if the returned
- * prev is equal to old) then we aren't acquiring anything new and
- * we don't need any memory barrier as far I can tell.
- */
-
-#define __HAVE_ARCH_CMPXCHG 1
-
-static inline unsigned long
-__cmpxchg_u8(volatile char *m, long old, long new)
-{
-       unsigned long prev, tmp, cmp, addr64;
-
-       __asm__ __volatile__(
-       "       andnot  %5,7,%4\n"
-       "       insbl   %1,%5,%1\n"
-       "1:     ldq_l   %2,0(%4)\n"
-       "       extbl   %2,%5,%0\n"
-       "       cmpeq   %0,%6,%3\n"
-       "       beq     %3,2f\n"
-       "       mskbl   %2,%5,%2\n"
-       "       or      %1,%2,%2\n"
-       "       stq_c   %2,0(%4)\n"
-       "       beq     %2,3f\n"
-#ifdef CONFIG_SMP
-       "       mb\n"
-#endif
-       "2:\n"
-       ".subsection 2\n"
-       "3:     br      1b\n"
-       ".previous"
-       : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
-       : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
-
-       return prev;
-}
-
-static inline unsigned long
-__cmpxchg_u16(volatile short *m, long old, long new)
-{
-       unsigned long prev, tmp, cmp, addr64;
-
-       __asm__ __volatile__(
-       "       andnot  %5,7,%4\n"
-       "       inswl   %1,%5,%1\n"
-       "1:     ldq_l   %2,0(%4)\n"
-       "       extwl   %2,%5,%0\n"
-       "       cmpeq   %0,%6,%3\n"
-       "       beq     %3,2f\n"
-       "       mskwl   %2,%5,%2\n"
-       "       or      %1,%2,%2\n"
-       "       stq_c   %2,0(%4)\n"
-       "       beq     %2,3f\n"
-#ifdef CONFIG_SMP
-       "       mb\n"
-#endif
-       "2:\n"
-       ".subsection 2\n"
-       "3:     br      1b\n"
-       ".previous"
-       : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
-       : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
-
-       return prev;
-}
-
-static inline unsigned long
-__cmpxchg_u32(volatile int *m, int old, int new)
-{
-       unsigned long prev, cmp;
-
-       __asm__ __volatile__(
-       "1:     ldl_l %0,%5\n"
-       "       cmpeq %0,%3,%1\n"
-       "       beq %1,2f\n"
-       "       mov %4,%1\n"
-       "       stl_c %1,%2\n"
-       "       beq %1,3f\n"
-#ifdef CONFIG_SMP
-       "       mb\n"
-#endif
-       "2:\n"
-       ".subsection 2\n"
-       "3:     br 1b\n"
-       ".previous"
-       : "=&r"(prev), "=&r"(cmp), "=m"(*m)
-       : "r"((long) old), "r"(new), "m"(*m) : "memory");
-
-       return prev;
-}
+#define cmpxchg64_local(ptr, o, n)                                     \
+  ({                                                                   \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
+       cmpxchg_local((ptr), (o), (n));                                 \
+  })
 
-static inline unsigned long
-__cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
-{
-       unsigned long prev, cmp;
-
-       __asm__ __volatile__(
-       "1:     ldq_l %0,%5\n"
-       "       cmpeq %0,%3,%1\n"
-       "       beq %1,2f\n"
-       "       mov %4,%1\n"
-       "       stq_c %1,%2\n"
-       "       beq %1,3f\n"
 #ifdef CONFIG_SMP
-       "       mb\n"
+#undef __ASM__MB
+#define __ASM__MB      "\tmb\n"
 #endif
-       "2:\n"
-       ".subsection 2\n"
-       "3:     br 1b\n"
-       ".previous"
-       : "=&r"(prev), "=&r"(cmp), "=m"(*m)
-       : "r"((long) old), "r"(new), "m"(*m) : "memory");
-
-       return prev;
-}
-
-/* This function doesn't exist, so you'll get a linker error
-   if something tries to do an invalid cmpxchg().  */
-extern void __cmpxchg_called_with_bad_pointer(void);
-
-static __always_inline unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
-{
-       switch (size) {
-               case 1:
-                       return __cmpxchg_u8(ptr, old, new);
-               case 2:
-                       return __cmpxchg_u16(ptr, old, new);
-               case 4:
-                       return __cmpxchg_u32(ptr, old, new);
-               case 8:
-                       return __cmpxchg_u64(ptr, old, new);
-       }
-       __cmpxchg_called_with_bad_pointer();
-       return old;
-}
-
-#define cmpxchg(ptr, o, n)                                              \
-  ({                                                                    \
-     __typeof__(*(ptr)) _o_ = (o);                                      \
-     __typeof__(*(ptr)) _n_ = (n);                                      \
-     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,          \
-                                   (unsigned long)_n_, sizeof(*(ptr))); \
+#undef ____xchg
+#undef ____cmpxchg
+#define ____xchg(type, args...)                __xchg ##type(args)
+#define ____cmpxchg(type, args...)     __cmpxchg ##type(args)
+#include <asm/xchg.h>
+
+#define xchg(ptr,x)                                                    \
+  ({                                                                   \
+     __typeof__(*(ptr)) _x_ = (x);                                     \
+     (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_,            \
+                                sizeof(*(ptr)));                       \
   })
-#define cmpxchg64(ptr, o, n)                                            \
-  ({                                                                    \
-       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                               \
-       cmpxchg((ptr), (o), (n));                                        \
-  })
-
-static inline unsigned long
-__cmpxchg_u8_local(volatile char *m, long old, long new)
-{
-       unsigned long prev, tmp, cmp, addr64;
-
-       __asm__ __volatile__(
-       "       andnot  %5,7,%4\n"
-       "       insbl   %1,%5,%1\n"
-       "1:     ldq_l   %2,0(%4)\n"
-       "       extbl   %2,%5,%0\n"
-       "       cmpeq   %0,%6,%3\n"
-       "       beq     %3,2f\n"
-       "       mskbl   %2,%5,%2\n"
-       "       or      %1,%2,%2\n"
-       "       stq_c   %2,0(%4)\n"
-       "       beq     %2,3f\n"
-       "2:\n"
-       ".subsection 2\n"
-       "3:     br      1b\n"
-       ".previous"
-       : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
-       : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
-
-       return prev;
-}
-
-static inline unsigned long
-__cmpxchg_u16_local(volatile short *m, long old, long new)
-{
-       unsigned long prev, tmp, cmp, addr64;
-
-       __asm__ __volatile__(
-       "       andnot  %5,7,%4\n"
-       "       inswl   %1,%5,%1\n"
-       "1:     ldq_l   %2,0(%4)\n"
-       "       extwl   %2,%5,%0\n"
-       "       cmpeq   %0,%6,%3\n"
-       "       beq     %3,2f\n"
-       "       mskwl   %2,%5,%2\n"
-       "       or      %1,%2,%2\n"
-       "       stq_c   %2,0(%4)\n"
-       "       beq     %2,3f\n"
-       "2:\n"
-       ".subsection 2\n"
-       "3:     br      1b\n"
-       ".previous"
-       : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
-       : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
-
-       return prev;
-}
-
-static inline unsigned long
-__cmpxchg_u32_local(volatile int *m, int old, int new)
-{
-       unsigned long prev, cmp;
-
-       __asm__ __volatile__(
-       "1:     ldl_l %0,%5\n"
-       "       cmpeq %0,%3,%1\n"
-       "       beq %1,2f\n"
-       "       mov %4,%1\n"
-       "       stl_c %1,%2\n"
-       "       beq %1,3f\n"
-       "2:\n"
-       ".subsection 2\n"
-       "3:     br 1b\n"
-       ".previous"
-       : "=&r"(prev), "=&r"(cmp), "=m"(*m)
-       : "r"((long) old), "r"(new), "m"(*m) : "memory");
-
-       return prev;
-}
-
-static inline unsigned long
-__cmpxchg_u64_local(volatile long *m, unsigned long old, unsigned long new)
-{
-       unsigned long prev, cmp;
-
-       __asm__ __volatile__(
-       "1:     ldq_l %0,%5\n"
-       "       cmpeq %0,%3,%1\n"
-       "       beq %1,2f\n"
-       "       mov %4,%1\n"
-       "       stq_c %1,%2\n"
-       "       beq %1,3f\n"
-       "2:\n"
-       ".subsection 2\n"
-       "3:     br 1b\n"
-       ".previous"
-       : "=&r"(prev), "=&r"(cmp), "=m"(*m)
-       : "r"((long) old), "r"(new), "m"(*m) : "memory");
-
-       return prev;
-}
-
-static __always_inline unsigned long
-__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
-               int size)
-{
-       switch (size) {
-               case 1:
-                       return __cmpxchg_u8_local(ptr, old, new);
-               case 2:
-                       return __cmpxchg_u16_local(ptr, old, new);
-               case 4:
-                       return __cmpxchg_u32_local(ptr, old, new);
-               case 8:
-                       return __cmpxchg_u64_local(ptr, old, new);
-       }
-       __cmpxchg_called_with_bad_pointer();
-       return old;
-}
 
-#define cmpxchg_local(ptr, o, n)                                        \
-  ({                                                                    \
-     __typeof__(*(ptr)) _o_ = (o);                                      \
-     __typeof__(*(ptr)) _n_ = (n);                                      \
-     (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,    \
-                                   (unsigned long)_n_, sizeof(*(ptr))); \
+#define cmpxchg(ptr, o, n)                                             \
+  ({                                                                   \
+     __typeof__(*(ptr)) _o_ = (o);                                     \
+     __typeof__(*(ptr)) _n_ = (n);                                     \
+     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,         \
+                                   (unsigned long)_n_, sizeof(*(ptr)));\
   })
-#define cmpxchg64_local(ptr, o, n)                                      \
-  ({                                                                    \
-       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                               \
-       cmpxchg_local((ptr), (o), (n));                                  \
+
+#define cmpxchg64(ptr, o, n)                                           \
+  ({                                                                   \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
+       cmpxchg((ptr), (o), (n));                                       \
   })
 
+#undef __ASM__MB
+#undef ____cmpxchg
+
+#define __HAVE_ARCH_CMPXCHG 1
 
 #endif /* __ASSEMBLY__ */
 
index c1541353ccefe04e67fe183ecb2013f7cb491642..f072f344497e7adba62719db66324bb11144c5ae 100644 (file)
@@ -8,7 +8,12 @@
  * not a major issue.  However, for interoperability, libraries still
  * need to be careful to avoid a name clashes.
  */
+
+#ifdef __KERNEL__
+#include <asm-generic/int-ll64.h>
+#else
 #include <asm-generic/int-l64.h>
+#endif
 
 #ifndef __ASSEMBLY__
 
index 22de3b434a22a59d7f16bce6520787efab1fc8f9..163f3053001c82e4976c082d1798ab656615088a 100644 (file)
@@ -498,13 +498,13 @@ struct exception_table_entry
 };
 
 /* Returns the new pc */
-#define fixup_exception(map_reg, fixup, pc)                    \
+#define fixup_exception(map_reg, _fixup, pc)                   \
 ({                                                             \
-       if ((fixup)->fixup.bits.valreg != 31)                   \
-               map_reg((fixup)->fixup.bits.valreg) = 0;        \
-       if ((fixup)->fixup.bits.errreg != 31)                   \
-               map_reg((fixup)->fixup.bits.errreg) = -EFAULT;  \
-       (pc) + (fixup)->fixup.bits.nextinsn;                    \
+       if ((_fixup)->fixup.bits.valreg != 31)                  \
+               map_reg((_fixup)->fixup.bits.valreg) = 0;       \
+       if ((_fixup)->fixup.bits.errreg != 31)                  \
+               map_reg((_fixup)->fixup.bits.errreg) = -EFAULT; \
+       (pc) + (_fixup)->fixup.bits.nextinsn;                   \
 })
 
 
diff --git a/arch/alpha/include/asm/xchg.h b/arch/alpha/include/asm/xchg.h
new file mode 100644 (file)
index 0000000..beba1b8
--- /dev/null
@@ -0,0 +1,258 @@
+#ifndef __ALPHA_SYSTEM_H
+#error Do not include xchg.h directly!
+#else
+/*
+ * xchg/xchg_local and cmpxchg/cmpxchg_local share the same code
+ * except that local version do not have the expensive memory barrier.
+ * So this file is included twice from asm/system.h.
+ */
+
+/*
+ * Atomic exchange.
+ * Since it can be used to implement critical sections
+ * it must clobber "memory" (also for interrupts in UP).
+ */
+
+static inline unsigned long
+____xchg(_u8, volatile char *m, unsigned long val)
+{
+       unsigned long ret, tmp, addr64;
+
+       __asm__ __volatile__(
+       "       andnot  %4,7,%3\n"
+       "       insbl   %1,%4,%1\n"
+       "1:     ldq_l   %2,0(%3)\n"
+       "       extbl   %2,%4,%0\n"
+       "       mskbl   %2,%4,%2\n"
+       "       or      %1,%2,%2\n"
+       "       stq_c   %2,0(%3)\n"
+       "       beq     %2,2f\n"
+               __ASM__MB
+       ".subsection 2\n"
+       "2:     br      1b\n"
+       ".previous"
+       : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
+       : "r" ((long)m), "1" (val) : "memory");
+
+       return ret;
+}
+
+static inline unsigned long
+____xchg(_u16, volatile short *m, unsigned long val)
+{
+       unsigned long ret, tmp, addr64;
+
+       __asm__ __volatile__(
+       "       andnot  %4,7,%3\n"
+       "       inswl   %1,%4,%1\n"
+       "1:     ldq_l   %2,0(%3)\n"
+       "       extwl   %2,%4,%0\n"
+       "       mskwl   %2,%4,%2\n"
+       "       or      %1,%2,%2\n"
+       "       stq_c   %2,0(%3)\n"
+       "       beq     %2,2f\n"
+               __ASM__MB
+       ".subsection 2\n"
+       "2:     br      1b\n"
+       ".previous"
+       : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
+       : "r" ((long)m), "1" (val) : "memory");
+
+       return ret;
+}
+
+static inline unsigned long
+____xchg(_u32, volatile int *m, unsigned long val)
+{
+       unsigned long dummy;
+
+       __asm__ __volatile__(
+       "1:     ldl_l %0,%4\n"
+       "       bis $31,%3,%1\n"
+       "       stl_c %1,%2\n"
+       "       beq %1,2f\n"
+               __ASM__MB
+       ".subsection 2\n"
+       "2:     br 1b\n"
+       ".previous"
+       : "=&r" (val), "=&r" (dummy), "=m" (*m)
+       : "rI" (val), "m" (*m) : "memory");
+
+       return val;
+}
+
+static inline unsigned long
+____xchg(_u64, volatile long *m, unsigned long val)
+{
+       unsigned long dummy;
+
+       __asm__ __volatile__(
+       "1:     ldq_l %0,%4\n"
+       "       bis $31,%3,%1\n"
+       "       stq_c %1,%2\n"
+       "       beq %1,2f\n"
+               __ASM__MB
+       ".subsection 2\n"
+       "2:     br 1b\n"
+       ".previous"
+       : "=&r" (val), "=&r" (dummy), "=m" (*m)
+       : "rI" (val), "m" (*m) : "memory");
+
+       return val;
+}
+
+/* This function doesn't exist, so you'll get a linker error
+   if something tries to do an invalid xchg().  */
+extern void __xchg_called_with_bad_pointer(void);
+
+static __always_inline unsigned long
+____xchg(, volatile void *ptr, unsigned long x, int size)
+{
+       switch (size) {
+               case 1:
+                       return ____xchg(_u8, ptr, x);
+               case 2:
+                       return ____xchg(_u16, ptr, x);
+               case 4:
+                       return ____xchg(_u32, ptr, x);
+               case 8:
+                       return ____xchg(_u64, ptr, x);
+       }
+       __xchg_called_with_bad_pointer();
+       return x;
+}
+
+/*
+ * Atomic compare and exchange.  Compare OLD with MEM, if identical,
+ * store NEW in MEM.  Return the initial value in MEM.  Success is
+ * indicated by comparing RETURN with OLD.
+ *
+ * The memory barrier should be placed in SMP only when we actually
+ * make the change. If we don't change anything (so if the returned
+ * prev is equal to old) then we aren't acquiring anything new and
+ * we don't need any memory barrier as far I can tell.
+ */
+
+static inline unsigned long
+____cmpxchg(_u8, volatile char *m, unsigned char old, unsigned char new)
+{
+       unsigned long prev, tmp, cmp, addr64;
+
+       __asm__ __volatile__(
+       "       andnot  %5,7,%4\n"
+       "       insbl   %1,%5,%1\n"
+       "1:     ldq_l   %2,0(%4)\n"
+       "       extbl   %2,%5,%0\n"
+       "       cmpeq   %0,%6,%3\n"
+       "       beq     %3,2f\n"
+       "       mskbl   %2,%5,%2\n"
+       "       or      %1,%2,%2\n"
+       "       stq_c   %2,0(%4)\n"
+       "       beq     %2,3f\n"
+               __ASM__MB
+       "2:\n"
+       ".subsection 2\n"
+       "3:     br      1b\n"
+       ".previous"
+       : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
+       : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
+
+       return prev;
+}
+
+static inline unsigned long
+____cmpxchg(_u16, volatile short *m, unsigned short old, unsigned short new)
+{
+       unsigned long prev, tmp, cmp, addr64;
+
+       __asm__ __volatile__(
+       "       andnot  %5,7,%4\n"
+       "       inswl   %1,%5,%1\n"
+       "1:     ldq_l   %2,0(%4)\n"
+       "       extwl   %2,%5,%0\n"
+       "       cmpeq   %0,%6,%3\n"
+       "       beq     %3,2f\n"
+       "       mskwl   %2,%5,%2\n"
+       "       or      %1,%2,%2\n"
+       "       stq_c   %2,0(%4)\n"
+       "       beq     %2,3f\n"
+               __ASM__MB
+       "2:\n"
+       ".subsection 2\n"
+       "3:     br      1b\n"
+       ".previous"
+       : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
+       : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
+
+       return prev;
+}
+
+static inline unsigned long
+____cmpxchg(_u32, volatile int *m, int old, int new)
+{
+       unsigned long prev, cmp;
+
+       __asm__ __volatile__(
+       "1:     ldl_l %0,%5\n"
+       "       cmpeq %0,%3,%1\n"
+       "       beq %1,2f\n"
+       "       mov %4,%1\n"
+       "       stl_c %1,%2\n"
+       "       beq %1,3f\n"
+               __ASM__MB
+       "2:\n"
+       ".subsection 2\n"
+       "3:     br 1b\n"
+       ".previous"
+       : "=&r"(prev), "=&r"(cmp), "=m"(*m)
+       : "r"((long) old), "r"(new), "m"(*m) : "memory");
+
+       return prev;
+}
+
+static inline unsigned long
+____cmpxchg(_u64, volatile long *m, unsigned long old, unsigned long new)
+{
+       unsigned long prev, cmp;
+
+       __asm__ __volatile__(
+       "1:     ldq_l %0,%5\n"
+       "       cmpeq %0,%3,%1\n"
+       "       beq %1,2f\n"
+       "       mov %4,%1\n"
+       "       stq_c %1,%2\n"
+       "       beq %1,3f\n"
+               __ASM__MB
+       "2:\n"
+       ".subsection 2\n"
+       "3:     br 1b\n"
+       ".previous"
+       : "=&r"(prev), "=&r"(cmp), "=m"(*m)
+       : "r"((long) old), "r"(new), "m"(*m) : "memory");
+
+       return prev;
+}
+
+/* This function doesn't exist, so you'll get a linker error
+   if something tries to do an invalid cmpxchg().  */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+static __always_inline unsigned long
+____cmpxchg(, volatile void *ptr, unsigned long old, unsigned long new,
+             int size)
+{
+       switch (size) {
+               case 1:
+                       return ____cmpxchg(_u8, ptr, old, new);
+               case 2:
+                       return ____cmpxchg(_u16, ptr, old, new);
+               case 4:
+                       return ____cmpxchg(_u32, ptr, old, new);
+               case 8:
+                       return ____cmpxchg(_u64, ptr, old, new);
+       }
+       __cmpxchg_called_with_bad_pointer();
+       return old;
+}
+
+#endif
index b4697759a1235ad60ce5458fcd6b896fb4f24e1d..a427538252f878aa664520e5c3f6f6d7ee844513 100644 (file)
@@ -12,7 +12,7 @@ obj-y    := entry.o traps.o process.o init_task.o osf_sys.o irq.o \
 
 obj-$(CONFIG_VGA_HOSE) += console.o
 obj-$(CONFIG_SMP)      += smp.o
-obj-$(CONFIG_PCI)      += pci.o pci_iommu.o
+obj-$(CONFIG_PCI)      += pci.o pci_iommu.o pci-sysfs.o
 obj-$(CONFIG_SRM_ENV)  += srm_env.o
 obj-$(CONFIG_MODULES)  += module.o
 
index 11aee012a8aed0986b7e744c7a43a0f7ac275814..985e5c1681ace50d0ef11c1bfdf29c485bcfbdda 100644 (file)
@@ -157,8 +157,8 @@ ev6_parse_cbox(u64 c_addr, u64 c1_syn, u64 c2_syn,
                       err_print_prefix,
                       streamname[stream], bitsname[bits], sourcename[source]);
 
-       printk("%s    Address: 0x%016lx\n"
-                "    Syndrome[upper.lower]: %02lx.%02lx\n", 
+       printk("%s    Address: 0x%016llx\n"
+                "    Syndrome[upper.lower]: %02llx.%02llx\n",
               err_print_prefix,
               c_addr,
               c2_syn, c1_syn);
index 68cd493f54c5fd93b5fddec8eb2323a65e124924..73770c6ca01321457d0430133525d4668dcc97e0 100644 (file)
@@ -246,13 +246,13 @@ ev7_process_pal_subpacket(struct el_subpacket *header)
 
        switch(header->type) {
        case EL_TYPE__PAL__LOGOUT_FRAME:
-               printk("%s*** MCHK occurred on LPID %ld (RBOX %lx)\n",
+               printk("%s*** MCHK occurred on LPID %ld (RBOX %llx)\n",
                       err_print_prefix,
                       packet->by_type.logout.whami, 
                       packet->by_type.logout.rbox_whami);
                el_print_timestamp(&packet->by_type.logout.timestamp);
-               printk("%s  EXC_ADDR: %016lx\n"
-                        "  HALT_CODE: %lx\n", 
+               printk("%s  EXC_ADDR: %016llx\n"
+                        "  HALT_CODE: %llx\n",
                       err_print_prefix,
                       packet->by_type.logout.exc_addr,
                       packet->by_type.logout.halt_code);
index 413bf37eb094057b0e38e03b965764056cb11c5a..6bfd243efba342200a36a51b4be1033921c0b3c0 100644 (file)
@@ -129,7 +129,7 @@ marvel_print_po7_crrct_sym(u64 crrct_sym)
 
 
        printk("%s      Correctable Error Symptoms:\n"
-              "%s        Syndrome: 0x%lx\n",
+              "%s        Syndrome: 0x%llx\n",
               err_print_prefix,
               err_print_prefix, EXTRACT(crrct_sym, IO7__PO7_CRRCT_SYM__SYN));
        marvel_print_err_cyc(EXTRACT(crrct_sym, IO7__PO7_CRRCT_SYM__ERR_CYC));
@@ -186,7 +186,7 @@ marvel_print_po7_uncrr_sym(u64 uncrr_sym, u64 valid_mask)
        uncrr_sym &= valid_mask;
 
        if (EXTRACT(valid_mask, IO7__PO7_UNCRR_SYM__SYN))
-               printk("%s        Syndrome: 0x%lx\n",
+               printk("%s        Syndrome: 0x%llx\n",
                       err_print_prefix, 
                       EXTRACT(uncrr_sym, IO7__PO7_UNCRR_SYM__SYN));
 
@@ -307,7 +307,7 @@ marvel_print_po7_ugbge_sym(u64 ugbge_sym)
                sprintf(opcode_str, "BlkIO");
                break;
        default:
-               sprintf(opcode_str, "0x%lx\n", 
+               sprintf(opcode_str, "0x%llx\n",
                        EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_OPCODE));
                break;
        }
@@ -321,7 +321,7 @@ marvel_print_po7_ugbge_sym(u64 ugbge_sym)
               opcode_str);
 
        if (0xC5 != EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_OPCODE))
-               printk("%s        Packet Offset 0x%08lx\n",
+               printk("%s        Packet Offset 0x%08llx\n",
                       err_print_prefix,
                       EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_PKT_OFF));
 }
@@ -480,8 +480,8 @@ marvel_print_po7_err_sum(struct ev7_pal_io_subpacket *io)
                printk("%s    Lost Error\n", err_print_prefix);
 
        printk("%s    Failing Packet:\n"
-              "%s      Cycle 1: %016lx\n"
-              "%s      Cycle 2: %016lx\n",
+              "%s      Cycle 1: %016llx\n"
+              "%s      Cycle 2: %016llx\n",
               err_print_prefix,
               err_print_prefix, io->po7_err_pkt0,
               err_print_prefix, io->po7_err_pkt1);
@@ -515,9 +515,9 @@ marvel_print_pox_tlb_err(u64 tlb_err)
        if (!(tlb_err & IO7__POX_TLBERR__ERR_VALID))
                return;
 
-       printk("%s      TLB Error on index 0x%lx:\n"
+       printk("%s      TLB Error on index 0x%llx:\n"
               "%s        - %s\n"
-              "%s        - Addr: 0x%016lx\n",
+              "%s        - Addr: 0x%016llx\n",
               err_print_prefix,
               EXTRACT(tlb_err, IO7__POX_TLBERR__ERR_TLB_PTR),
               err_print_prefix,
@@ -579,7 +579,7 @@ marvel_print_pox_spl_cmplt(u64 spl_cmplt)
                sprintf(message, "Uncorrectable Split Write Data Error");
                break;
        default:
-               sprintf(message, "%08lx\n", 
+               sprintf(message, "%08llx\n",
                        EXTRACT(spl_cmplt, IO7__POX_SPLCMPLT__MESSAGE));
                break;
        }
@@ -620,9 +620,9 @@ marvel_print_pox_trans_sum(u64 trans_sum)
                return;
 
        printk("%s      Transaction Summary:\n"
-              "%s        Command: 0x%lx - %s\n"
-              "%s        Address: 0x%016lx%s\n"
-              "%s        PCI-X Master Slot: 0x%lx\n",
+              "%s        Command: 0x%llx - %s\n"
+              "%s        Address: 0x%016llx%s\n"
+              "%s        PCI-X Master Slot: 0x%llx\n",
               err_print_prefix, 
               err_print_prefix, 
               EXTRACT(trans_sum, IO7__POX_TRANSUM__PCIX_CMD),
@@ -964,12 +964,12 @@ marvel_process_io_error(struct ev7_lf_subpackets *lf_subpackets, int print)
 
 #if 0
                printk("%s  PORT 7 ERROR:\n"
-                      "%s    PO7_ERROR_SUM: %016lx\n"
-                      "%s    PO7_UNCRR_SYM: %016lx\n"
-                      "%s    PO7_CRRCT_SYM: %016lx\n"
-                      "%s    PO7_UGBGE_SYM: %016lx\n"
-                      "%s    PO7_ERR_PKT0:  %016lx\n"
-                      "%s    PO7_ERR_PKT1:  %016lx\n",
+                      "%s    PO7_ERROR_SUM: %016llx\n"
+                      "%s    PO7_UNCRR_SYM: %016llx\n"
+                      "%s    PO7_CRRCT_SYM: %016llx\n"
+                      "%s    PO7_UGBGE_SYM: %016llx\n"
+                      "%s    PO7_ERR_PKT0:  %016llx\n"
+                      "%s    PO7_ERR_PKT1:  %016llx\n",
                       err_print_prefix,
                       err_print_prefix, io->po7_error_sum,
                       err_print_prefix, io->po7_uncrr_sym,
@@ -987,12 +987,12 @@ marvel_process_io_error(struct ev7_lf_subpackets *lf_subpackets, int print)
                if (!MARVEL_IO_ERR_VALID(io->ports[i].pox_err_sum))
                        continue;
 
-               printk("%s  PID %u PORT %d POx_ERR_SUM: %016lx\n", 
+               printk("%s  PID %u PORT %d POx_ERR_SUM: %016llx\n",
                       err_print_prefix, 
                       lf_subpackets->io_pid, i, io->ports[i].pox_err_sum);
                marvel_print_pox_err(io->ports[i].pox_err_sum, &io->ports[i]);
 
-               printk("%s  [ POx_FIRST_ERR: %016lx ]\n", 
+               printk("%s  [ POx_FIRST_ERR: %016llx ]\n",
                       err_print_prefix, io->ports[i].pox_first_err);
                marvel_print_pox_err(io->ports[i].pox_first_err, 
                                     &io->ports[i]);
index 257449ed15efca1ac97d46e999acb0e223e62408..c7e28a88d6e31b2869ab45488d7e5f9092127ffb 100644 (file)
@@ -107,12 +107,12 @@ titan_parse_p_serror(int which, u64 serror, int print)
        if (!print)
                return status;
 
-       printk("%s  PChip %d SERROR: %016lx\n", 
+       printk("%s  PChip %d SERROR: %016llx\n",
               err_print_prefix, which, serror);
        if (serror & TITAN__PCHIP_SERROR__ECCMASK) {
                printk("%s    %sorrectable ECC Error:\n"
                       "      Source: %-6s  Command: %-8s  Syndrome: 0x%08x\n"
-                      "      Address: 0x%lx\n", 
+                      "      Address: 0x%llx\n",
                       err_print_prefix,
                       (serror & TITAN__PCHIP_SERROR__UECC) ? "Unc" : "C",
                       serror_src[EXTRACT(serror, TITAN__PCHIP_SERROR__SRC)],
@@ -223,7 +223,7 @@ titan_parse_p_perror(int which, int port, u64 perror, int print)
        if (!print) 
                return status;
 
-       printk("%s  PChip %d %cPERROR: %016lx\n", 
+       printk("%s  PChip %d %cPERROR: %016llx\n",
               err_print_prefix, which, 
               port ? 'A' : 'G', perror);
        if (perror & TITAN__PCHIP_PERROR__IPTPW)
@@ -316,7 +316,7 @@ titan_parse_p_agperror(int which, u64 agperror, int print)
        addr = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__ADDR) << 3;
        len = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__LEN);
 
-       printk("%s  PChip %d AGPERROR: %016lx\n", err_print_prefix,
+       printk("%s  PChip %d AGPERROR: %016llx\n", err_print_prefix,
               which, agperror);
        if (agperror & TITAN__PCHIP_AGPERROR__NOWINDOW)
                printk("%s    No Window\n", err_print_prefix);
@@ -597,16 +597,16 @@ privateer_process_680_frame(struct el_common *mchk_header, int print)
                return status;
 
        /* TODO - decode instead of just dumping... */
-       printk("%s  Summary Flags:         %016lx\n"
-                "  CChip DIRx:            %016lx\n"
-                "  System Management IR:  %016lx\n"
-                "  CPU IR:                %016lx\n"
-                "  Power Supply IR:       %016lx\n"
-                "  LM78 Fault Status:     %016lx\n"
-                "  System Doors:          %016lx\n"
-                "  Temperature Warning:   %016lx\n"
-                "  Fan Control:           %016lx\n"
-                "  Fatal Power Down Code: %016lx\n",
+       printk("%s  Summary Flags:         %016llx\n"
+                "  CChip DIRx:            %016llx\n"
+                "  System Management IR:  %016llx\n"
+                "  CPU IR:                %016llx\n"
+                "  Power Supply IR:       %016llx\n"
+                "  LM78 Fault Status:     %016llx\n"
+                "  System Doors:          %016llx\n"
+                "  Temperature Warning:   %016llx\n"
+                "  Fan Control:           %016llx\n"
+                "  Fatal Power Down Code: %016llx\n",
               err_print_prefix,
               emchk->summary,
               emchk->c_dirx,
diff --git a/arch/alpha/kernel/pci-sysfs.c b/arch/alpha/kernel/pci-sysfs.c
new file mode 100644 (file)
index 0000000..6ea822e
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * arch/alpha/kernel/pci-sysfs.c
+ *
+ * Copyright (C) 2009 Ivan Kokshaysky
+ *
+ * Alpha PCI resource files.
+ *
+ * Loosely based on generic HAVE_PCI_MMAP implementation in
+ * drivers/pci/pci-sysfs.c
+ */
+
+#include <linux/sched.h>
+#include <linux/pci.h>
+
+static int hose_mmap_page_range(struct pci_controller *hose,
+                               struct vm_area_struct *vma,
+                               enum pci_mmap_state mmap_type, int sparse)
+{
+       unsigned long base;
+
+       if (mmap_type == pci_mmap_mem)
+               base = sparse ? hose->sparse_mem_base : hose->dense_mem_base;
+       else
+               base = sparse ? hose->sparse_io_base : hose->dense_io_base;
+
+       vma->vm_pgoff += base >> PAGE_SHIFT;
+       vma->vm_flags |= (VM_IO | VM_RESERVED);
+
+       return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+                                 vma->vm_end - vma->vm_start,
+                                 vma->vm_page_prot);
+}
+
+static int __pci_mmap_fits(struct pci_dev *pdev, int num,
+                          struct vm_area_struct *vma, int sparse)
+{
+       unsigned long nr, start, size;
+       int shift = sparse ? 5 : 0;
+
+       nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+       start = vma->vm_pgoff;
+       size = ((pci_resource_len(pdev, num) - 1) >> (PAGE_SHIFT - shift)) + 1;
+
+       if (start < size && size - start >= nr)
+               return 1;
+       WARN(1, "process \"%s\" tried to map%s 0x%08lx-0x%08lx on %s BAR %d "
+               "(size 0x%08lx)\n",
+               current->comm, sparse ? " sparse" : "", start, start + nr,
+               pci_name(pdev), num, size);
+       return 0;
+}
+
+/**
+ * pci_mmap_resource - map a PCI resource into user memory space
+ * @kobj: kobject for mapping
+ * @attr: struct bin_attribute for the file being mapped
+ * @vma: struct vm_area_struct passed into the mmap
+ * @sparse: address space type
+ *
+ * Use the bus mapping routines to map a PCI resource into userspace.
+ */
+static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
+                            struct vm_area_struct *vma, int sparse)
+{
+       struct pci_dev *pdev = to_pci_dev(container_of(kobj,
+                                                      struct device, kobj));
+       struct resource *res = (struct resource *)attr->private;
+       enum pci_mmap_state mmap_type;
+       struct pci_bus_region bar;
+       int i;
+
+       for (i = 0; i < PCI_ROM_RESOURCE; i++)
+               if (res == &pdev->resource[i])
+                       break;
+       if (i >= PCI_ROM_RESOURCE)
+               return -ENODEV;
+
+       if (!__pci_mmap_fits(pdev, i, vma, sparse))
+               return -EINVAL;
+
+       if (iomem_is_exclusive(res->start))
+               return -EINVAL;
+
+       pcibios_resource_to_bus(pdev, &bar, res);
+       vma->vm_pgoff += bar.start >> (PAGE_SHIFT - (sparse ? 5 : 0));
+       mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
+
+       return hose_mmap_page_range(pdev->sysdata, vma, mmap_type, sparse);
+}
+
+static int pci_mmap_resource_sparse(struct kobject *kobj,
+                                   struct bin_attribute *attr,
+                                   struct vm_area_struct *vma)
+{
+       return pci_mmap_resource(kobj, attr, vma, 1);
+}
+
+static int pci_mmap_resource_dense(struct kobject *kobj,
+                                  struct bin_attribute *attr,
+                                  struct vm_area_struct *vma)
+{
+       return pci_mmap_resource(kobj, attr, vma, 0);
+}
+
+/**
+ * pci_remove_resource_files - cleanup resource files
+ * @dev: dev to cleanup
+ *
+ * If we created resource files for @dev, remove them from sysfs and
+ * free their resources.
+ */
+void pci_remove_resource_files(struct pci_dev *pdev)
+{
+       int i;
+
+       for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+               struct bin_attribute *res_attr;
+
+               res_attr = pdev->res_attr[i];
+               if (res_attr) {
+                       sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
+                       kfree(res_attr);
+               }
+
+               res_attr = pdev->res_attr_wc[i];
+               if (res_attr) {
+                       sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
+                       kfree(res_attr);
+               }
+       }
+}
+
+static int sparse_mem_mmap_fits(struct pci_dev *pdev, int num)
+{
+       struct pci_bus_region bar;
+       struct pci_controller *hose = pdev->sysdata;
+       long dense_offset;
+       unsigned long sparse_size;
+
+       pcibios_resource_to_bus(pdev, &bar, &pdev->resource[num]);
+
+       /* All core logic chips have 4G sparse address space, except
+          CIA which has 16G (see xxx_SPARSE_MEM and xxx_DENSE_MEM
+          definitions in asm/core_xxx.h files). This corresponds
+          to 128M or 512M of the bus space. */
+       dense_offset = (long)(hose->dense_mem_base - hose->sparse_mem_base);
+       sparse_size = dense_offset >= 0x400000000UL ? 0x20000000 : 0x8000000;
+
+       return bar.end < sparse_size;
+}
+
+static int pci_create_one_attr(struct pci_dev *pdev, int num, char *name,
+                              char *suffix, struct bin_attribute *res_attr,
+                              unsigned long sparse)
+{
+       size_t size = pci_resource_len(pdev, num);
+
+       sprintf(name, "resource%d%s", num, suffix);
+       res_attr->mmap = sparse ? pci_mmap_resource_sparse :
+                                 pci_mmap_resource_dense;
+       res_attr->attr.name = name;
+       res_attr->attr.mode = S_IRUSR | S_IWUSR;
+       res_attr->size = sparse ? size << 5 : size;
+       res_attr->private = &pdev->resource[num];
+       return sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
+}
+
+static int pci_create_attr(struct pci_dev *pdev, int num)
+{
+       /* allocate attribute structure, piggyback attribute name */
+       int retval, nlen1, nlen2 = 0, res_count = 1;
+       unsigned long sparse_base, dense_base;
+       struct bin_attribute *attr;
+       struct pci_controller *hose = pdev->sysdata;
+       char *suffix, *attr_name;
+
+       suffix = "";    /* Assume bwx machine, normal resourceN files. */
+       nlen1 = 10;
+
+       if (pdev->resource[num].flags & IORESOURCE_MEM) {
+               sparse_base = hose->sparse_mem_base;
+               dense_base = hose->dense_mem_base;
+               if (sparse_base && !sparse_mem_mmap_fits(pdev, num)) {
+                       sparse_base = 0;
+                       suffix = "_dense";
+                       nlen1 = 16;     /* resourceN_dense */
+               }
+       } else {
+               sparse_base = hose->sparse_io_base;
+               dense_base = hose->dense_io_base;
+       }
+
+       if (sparse_base) {
+               suffix = "_sparse";
+               nlen1 = 17;
+               if (dense_base) {
+                       nlen2 = 16;     /* resourceN_dense */
+                       res_count = 2;
+               }
+       }
+
+       attr = kzalloc(sizeof(*attr) * res_count + nlen1 + nlen2, GFP_ATOMIC);
+       if (!attr)
+               return -ENOMEM;
+
+       /* Create bwx, sparse or single dense file */
+       attr_name = (char *)(attr + res_count);
+       pdev->res_attr[num] = attr;
+       retval = pci_create_one_attr(pdev, num, attr_name, suffix, attr,
+                                    sparse_base);
+       if (retval || res_count == 1)
+               return retval;
+
+       /* Create dense file */
+       attr_name += nlen1;
+       attr++;
+       pdev->res_attr_wc[num] = attr;
+       return pci_create_one_attr(pdev, num, attr_name, "_dense", attr, 0);
+}
+
+/**
+ * pci_create_resource_files - create resource files in sysfs for @dev
+ * @dev: dev in question
+ *
+ * Walk the resources in @dev creating files for each resource available.
+ */
+int pci_create_resource_files(struct pci_dev *pdev)
+{
+       int i;
+       int retval;
+
+       /* Expose the PCI resources from this device as files */
+       for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+
+               /* skip empty resources */
+               if (!pci_resource_len(pdev, i))
+                       continue;
+
+               retval = pci_create_attr(pdev, i);
+               if (retval) {
+                       pci_remove_resource_files(pdev);
+                       return retval;
+               }
+       }
+       return 0;
+}
+
+/* Legacy I/O bus mapping stuff. */
+
+static int __legacy_mmap_fits(struct pci_controller *hose,
+                             struct vm_area_struct *vma,
+                             unsigned long res_size, int sparse)
+{
+       unsigned long nr, start, size;
+
+       nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+       start = vma->vm_pgoff;
+       size = ((res_size - 1) >> PAGE_SHIFT) + 1;
+
+       if (start < size && size - start >= nr)
+               return 1;
+       WARN(1, "process \"%s\" tried to map%s 0x%08lx-0x%08lx on hose %d "
+               "(size 0x%08lx)\n",
+               current->comm, sparse ? " sparse" : "", start, start + nr,
+               hose->index, size);
+       return 0;
+}
+
+static inline int has_sparse(struct pci_controller *hose,
+                            enum pci_mmap_state mmap_type)
+{
+       unsigned long base;
+
+       base = (mmap_type == pci_mmap_mem) ? hose->sparse_mem_base :
+                                            hose->sparse_io_base;
+
+       return base != 0;
+}
+
+int pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma,
+                              enum pci_mmap_state mmap_type)
+{
+       struct pci_controller *hose = bus->sysdata;
+       int sparse = has_sparse(hose, mmap_type);
+       unsigned long res_size;
+
+       res_size = (mmap_type == pci_mmap_mem) ? bus->legacy_mem->size :
+                                                bus->legacy_io->size;
+       if (!__legacy_mmap_fits(hose, vma, res_size, sparse))
+               return -EINVAL;
+
+       return hose_mmap_page_range(hose, vma, mmap_type, sparse);
+}
+
+/**
+ * pci_adjust_legacy_attr - adjustment of legacy file attributes
+ * @b: bus to create files under
+ * @mmap_type: I/O port or memory
+ *
+ * Adjust file name and size for sparse mappings.
+ */
+void pci_adjust_legacy_attr(struct pci_bus *bus, enum pci_mmap_state mmap_type)
+{
+       struct pci_controller *hose = bus->sysdata;
+
+       if (!has_sparse(hose, mmap_type))
+               return;
+
+       if (mmap_type == pci_mmap_mem) {
+               bus->legacy_mem->attr.name = "legacy_mem_sparse";
+               bus->legacy_mem->size <<= 5;
+       } else {
+               bus->legacy_io->attr.name = "legacy_io_sparse";
+               bus->legacy_io->size <<= 5;
+       }
+       return;
+}
+
+/* Legacy I/O bus read/write functions */
+int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val, size_t size)
+{
+       struct pci_controller *hose = bus->sysdata;
+
+       port += hose->io_space->start;
+
+       switch(size) {
+       case 1:
+               *((u8 *)val) = inb(port);
+               return 1;
+       case 2:
+               if (port & 1)
+                       return -EINVAL;
+               *((u16 *)val) = inw(port);
+               return 2;
+       case 4:
+               if (port & 3)
+                       return -EINVAL;
+               *((u32 *)val) = inl(port);
+               return 4;
+       }
+       return -EINVAL;
+}
+
+int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size)
+{
+       struct pci_controller *hose = bus->sysdata;
+
+       port += hose->io_space->start;
+
+       switch(size) {
+       case 1:
+               outb(port, val);
+               return 1;
+       case 2:
+               if (port & 1)
+                       return -EINVAL;
+               outw(port, val);
+               return 2;
+       case 4:
+               if (port & 3)
+                       return -EINVAL;
+               outl(port, val);
+               return 4;
+       }
+       return -EINVAL;
+}
index a3b938811400f70c82ec960082f6bdeaab935e0f..a91ba28999b57a03d34036f105fd1070fa8fe2d3 100644 (file)
@@ -168,7 +168,7 @@ pcibios_align_resource(void *data, struct resource *res,
                 */
 
                /* Align to multiple of size of minimum base.  */
-               alignto = max(0x1000UL, align);
+               alignto = max_t(resource_size_t, 0x1000, align);
                start = ALIGN(start, alignto);
                if (hose->sparse_mem_base && size <= 7 * 16*MB) {
                        if (((start / (16*MB)) & 0x7) == 0) {
index b9094da05d7a136a5dff6bf7a6a0751e25af5316..bfb880af959d4d39c4ed335cc4afb3326fcc989a 100644 (file)
@@ -247,7 +247,7 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
            && paddr + size <= __direct_map_size) {
                ret = paddr + __direct_map_base;
 
-               DBGA2("pci_map_single: [%p,%lx] -> direct %lx from %p\n",
+               DBGA2("pci_map_single: [%p,%zx] -> direct %llx from %p\n",
                      cpu_addr, size, ret, __builtin_return_address(0));
 
                return ret;
@@ -258,7 +258,7 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
        if (dac_allowed) {
                ret = paddr + alpha_mv.pci_dac_offset;
 
-               DBGA2("pci_map_single: [%p,%lx] -> DAC %lx from %p\n",
+               DBGA2("pci_map_single: [%p,%zx] -> DAC %llx from %p\n",
                      cpu_addr, size, ret, __builtin_return_address(0));
 
                return ret;
@@ -299,7 +299,7 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
        ret = arena->dma_base + dma_ofs * PAGE_SIZE;
        ret += (unsigned long)cpu_addr & ~PAGE_MASK;
 
-       DBGA2("pci_map_single: [%p,%lx] np %ld -> sg %lx from %p\n",
+       DBGA2("pci_map_single: [%p,%zx] np %ld -> sg %llx from %p\n",
              cpu_addr, size, npages, ret, __builtin_return_address(0));
 
        return ret;
@@ -355,14 +355,14 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
            && dma_addr < __direct_map_base + __direct_map_size) {
                /* Nothing to do.  */
 
-               DBGA2("pci_unmap_single: direct [%lx,%lx] from %p\n",
+               DBGA2("pci_unmap_single: direct [%llx,%zx] from %p\n",
                      dma_addr, size, __builtin_return_address(0));
 
                return;
        }
 
        if (dma_addr > 0xffffffff) {
-               DBGA2("pci64_unmap_single: DAC [%lx,%lx] from %p\n",
+               DBGA2("pci64_unmap_single: DAC [%llx,%zx] from %p\n",
                      dma_addr, size, __builtin_return_address(0));
                return;
        }
@@ -373,9 +373,9 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
 
        dma_ofs = (dma_addr - arena->dma_base) >> PAGE_SHIFT;
        if (dma_ofs * PAGE_SIZE >= arena->size) {
-               printk(KERN_ERR "Bogus pci_unmap_single: dma_addr %lx "
-                      " base %lx size %x\n", dma_addr, arena->dma_base,
-                      arena->size);
+               printk(KERN_ERR "Bogus pci_unmap_single: dma_addr %llx "
+                      " base %llx size %x\n",
+                      dma_addr, arena->dma_base, arena->size);
                return;
                BUG();
        }
@@ -394,7 +394,7 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
 
        spin_unlock_irqrestore(&arena->lock, flags);
 
-       DBGA2("pci_unmap_single: sg [%lx,%lx] np %ld from %p\n",
+       DBGA2("pci_unmap_single: sg [%llx,%zx] np %ld from %p\n",
              dma_addr, size, npages, __builtin_return_address(0));
 }
 EXPORT_SYMBOL(pci_unmap_single);
@@ -444,7 +444,7 @@ try_again:
                goto try_again;
        }
                
-       DBGA2("pci_alloc_consistent: %lx -> [%p,%x] from %p\n",
+       DBGA2("pci_alloc_consistent: %zx -> [%p,%llx] from %p\n",
              size, cpu_addr, *dma_addrp, __builtin_return_address(0));
 
        return cpu_addr;
@@ -464,7 +464,7 @@ pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu_addr,
        pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL);
        free_pages((unsigned long)cpu_addr, get_order(size));
 
-       DBGA2("pci_free_consistent: [%x,%lx] from %p\n",
+       DBGA2("pci_free_consistent: [%llx,%zx] from %p\n",
              dma_addr, size, __builtin_return_address(0));
 }
 EXPORT_SYMBOL(pci_free_consistent);
@@ -551,7 +551,7 @@ sg_fill(struct device *dev, struct scatterlist *leader, struct scatterlist *end,
                out->dma_address = paddr + __direct_map_base;
                out->dma_length = size;
 
-               DBGA("    sg_fill: [%p,%lx] -> direct %lx\n",
+               DBGA("    sg_fill: [%p,%lx] -> direct %llx\n",
                     __va(paddr), size, out->dma_address);
 
                return 0;
@@ -563,7 +563,7 @@ sg_fill(struct device *dev, struct scatterlist *leader, struct scatterlist *end,
                out->dma_address = paddr + alpha_mv.pci_dac_offset;
                out->dma_length = size;
 
-               DBGA("    sg_fill: [%p,%lx] -> DAC %lx\n",
+               DBGA("    sg_fill: [%p,%lx] -> DAC %llx\n",
                     __va(paddr), size, out->dma_address);
 
                return 0;
@@ -589,7 +589,7 @@ sg_fill(struct device *dev, struct scatterlist *leader, struct scatterlist *end,
        out->dma_address = arena->dma_base + dma_ofs*PAGE_SIZE + paddr;
        out->dma_length = size;
 
-       DBGA("    sg_fill: [%p,%lx] -> sg %lx np %ld\n",
+       DBGA("    sg_fill: [%p,%lx] -> sg %llx np %ld\n",
             __va(paddr), size, out->dma_address, npages);
 
        /* All virtually contiguous.  We need to find the length of each
@@ -752,7 +752,7 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
 
                if (addr > 0xffffffff) {
                        /* It's a DAC address -- nothing to do.  */
-                       DBGA("    (%ld) DAC [%lx,%lx]\n",
+                       DBGA("    (%ld) DAC [%llx,%zx]\n",
                              sg - end + nents, addr, size);
                        continue;
                }
@@ -760,12 +760,12 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
                if (addr >= __direct_map_base
                    && addr < __direct_map_base + __direct_map_size) {
                        /* Nothing to do.  */
-                       DBGA("    (%ld) direct [%lx,%lx]\n",
+                       DBGA("    (%ld) direct [%llx,%zx]\n",
                              sg - end + nents, addr, size);
                        continue;
                }
 
-               DBGA("    (%ld) sg [%lx,%lx]\n",
+               DBGA("    (%ld) sg [%llx,%zx]\n",
                     sg - end + nents, addr, size);
 
                npages = iommu_num_pages(addr, size, PAGE_SIZE);
index 8d0097f10208dad922760de0a72756a55272c722..3a2fb7a02db402a75b8eaaea3dfe8a51d02eddd9 100644 (file)
@@ -272,7 +272,7 @@ alpha_vfork(struct pt_regs *regs)
  */
 
 int
-copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+copy_thread(unsigned long clone_flags, unsigned long usp,
            unsigned long unused,
            struct task_struct * p, struct pt_regs * regs)
 {
index fe14c6747cd651d56e07d10d6094f5671eb532c6..567f2598d090a331f89a1444ab42b82763ab1297 100644 (file)
@@ -20,7 +20,7 @@ struct pci_controller;
 extern struct pci_ops apecs_pci_ops;
 extern void apecs_init_arch(void);
 extern void apecs_pci_clr_err(void);
-extern void apecs_machine_check(u64, u64);
+extern void apecs_machine_check(unsigned long vector, unsigned long la_ptr);
 extern void apecs_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_cia.c */
@@ -29,7 +29,7 @@ extern void cia_init_pci(void);
 extern void cia_init_arch(void);
 extern void pyxis_init_arch(void);
 extern void cia_kill_arch(int);
-extern void cia_machine_check(u64, u64);
+extern void cia_machine_check(unsigned long vector, unsigned long la_ptr);
 extern void cia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_irongate.c */
@@ -42,7 +42,7 @@ extern void irongate_machine_check(u64, u64);
 /* core_lca.c */
 extern struct pci_ops lca_pci_ops;
 extern void lca_init_arch(void);
-extern void lca_machine_check(u64, u64);
+extern void lca_machine_check(unsigned long vector, unsigned long la_ptr);
 extern void lca_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_marvel.c */
@@ -64,7 +64,7 @@ void io7_clear_errors(struct io7 *io7);
 extern struct pci_ops mcpcia_pci_ops;
 extern void mcpcia_init_arch(void);
 extern void mcpcia_init_hoses(void);
-extern void mcpcia_machine_check(u64, u64);
+extern void mcpcia_machine_check(unsigned long vector, unsigned long la_ptr);
 extern void mcpcia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_polaris.c */
@@ -72,14 +72,14 @@ extern struct pci_ops polaris_pci_ops;
 extern int polaris_read_config_dword(struct pci_dev *, int, u32 *);
 extern int polaris_write_config_dword(struct pci_dev *, int, u32);
 extern void polaris_init_arch(void);
-extern void polaris_machine_check(u64, u64);
+extern void polaris_machine_check(unsigned long vector, unsigned long la_ptr);
 #define polaris_pci_tbi ((void *)0)
 
 /* core_t2.c */
 extern struct pci_ops t2_pci_ops;
 extern void t2_init_arch(void);
 extern void t2_kill_arch(int);
-extern void t2_machine_check(u64, u64);
+extern void t2_machine_check(unsigned long vector, unsigned long la_ptr);
 extern void t2_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_titan.c */
@@ -94,14 +94,14 @@ extern struct _alpha_agp_info *titan_agp_info(void);
 extern struct pci_ops tsunami_pci_ops;
 extern void tsunami_init_arch(void);
 extern void tsunami_kill_arch(int);
-extern void tsunami_machine_check(u64, u64);
+extern void tsunami_machine_check(unsigned long vector, unsigned long la_ptr);
 extern void tsunami_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_wildfire.c */
 extern struct pci_ops wildfire_pci_ops;
 extern void wildfire_init_arch(void);
 extern void wildfire_kill_arch(int);
-extern void wildfire_machine_check(u64, u64);
+extern void wildfire_machine_check(unsigned long vector, unsigned long la_ptr);
 extern void wildfire_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 extern int wildfire_pa_to_nid(unsigned long);
 extern int wildfire_cpuid_to_nid(int);
index 02bee6983ce2e7f9a91cd57a264ec189671c073e..80df86cd746bd2e8ca81ef82f338f7b337c229d5 100644 (file)
@@ -1255,7 +1255,7 @@ show_cpuinfo(struct seq_file *f, void *slot)
                       platform_string(), nr_processors);
 
 #ifdef CONFIG_SMP
-       seq_printf(f, "cpus active\t\t: %d\n"
+       seq_printf(f, "cpus active\t\t: %u\n"
                      "cpu active mask\t\t: %016lx\n",
                       num_online_cpus(), cpus_addr(cpu_possible_map)[0]);
 #endif
index fd467b207f0f9527cfb18596bc5d79747462c597..bca5bda90cde75407940f0f238d3099c29ca0567 100644 (file)
@@ -2542,8 +2542,8 @@ void __init SMC669_Init ( int index )
         SMC37c669_display_device_info( );
 #endif
        local_irq_restore(flags);
-        printk( "SMC37c669 Super I/O Controller found @ 0x%lx\n",
-               (unsigned long) SMC_base );
+        printk( "SMC37c669 Super I/O Controller found @ 0x%p\n",
+               SMC_base );
     }
     else {
        local_irq_restore(flags);
index 78ad7cd1bbd60326d38bee8f00c8beb6a55f03eb..d12af472e1c0ec4aa380e8bdc73aab15627d7a2c 100644 (file)
@@ -218,7 +218,6 @@ srm_env_init(void)
                                BASE_DIR);
                goto cleanup;
        }
-       base_dir->owner = THIS_MODULE;
 
        /*
         * Create per-name subdirectory
@@ -229,7 +228,6 @@ srm_env_init(void)
                                BASE_DIR, NAMED_DIR);
                goto cleanup;
        }
-       named_dir->owner = THIS_MODULE;
 
        /*
         * Create per-number subdirectory
@@ -241,7 +239,6 @@ srm_env_init(void)
                goto cleanup;
 
        }
-       numbered_dir->owner = THIS_MODULE;
 
        /*
         * Create all named nodes
@@ -254,7 +251,6 @@ srm_env_init(void)
                        goto cleanup;
 
                entry->proc_entry->data         = (void *) entry;
-               entry->proc_entry->owner        = THIS_MODULE;
                entry->proc_entry->read_proc    = srm_env_read;
                entry->proc_entry->write_proc   = srm_env_write;
 
@@ -275,7 +271,6 @@ srm_env_init(void)
 
                entry->id                       = var_num;
                entry->proc_entry->data         = (void *) entry;
-               entry->proc_entry->owner        = THIS_MODULE;
                entry->proc_entry->read_proc    = srm_env_read;
                entry->proc_entry->write_proc   = srm_env_write;
        }
index e2516f9a8967e45aa8c4df23f3de48cae1cdd67e..2b5caf3d9b1526678506fef65bc0e746b61edc9f 100644 (file)
@@ -244,12 +244,11 @@ jensen_init_arch(void)
 }
 
 static void
-jensen_machine_check (u64 vector, u64 la)
+jensen_machine_check(unsigned long vector, unsigned long la)
 {
        printk(KERN_CRIT "Machine check\n");
 }
 
-
 /*
  * The System Vector
  */
index d232e42be018ba13cf61522377785c4e5947ec28..9e263256a42d551c386c345147d77817f8d221a7 100644 (file)
@@ -453,7 +453,7 @@ sable_lynx_enable_irq(unsigned int irq)
        sable_lynx_irq_swizzle->update_irq_hw(bit, mask);
        spin_unlock(&sable_lynx_irq_lock);
 #if 0
-       printk("%s: mask 0x%lx bit 0x%x irq 0x%x\n",
+       printk("%s: mask 0x%lx bit 0x%lx irq 0x%x\n",
               __func__, mask, bit, irq);
 #endif
 }
@@ -469,7 +469,7 @@ sable_lynx_disable_irq(unsigned int irq)
        sable_lynx_irq_swizzle->update_irq_hw(bit, mask);
        spin_unlock(&sable_lynx_irq_lock);
 #if 0
-       printk("%s: mask 0x%lx bit 0x%x irq 0x%x\n",
+       printk("%s: mask 0x%lx bit 0x%lx irq 0x%x\n",
               __func__, mask, bit, irq);
 #endif
 }
index cefc5a355ef9645233bfec5535e71e1d96e47e54..6ee7655b7568bf36719f2447e389831244721f01 100644 (file)
@@ -623,7 +623,7 @@ do_entUna(void * va, unsigned long opcode, unsigned long reg,
        }
 
        lock_kernel();
-       printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n",
+       printk("Bad unaligned kernel access at %016lx: %p %lx %lu\n",
                pc, va, opcode, reg);
        do_exit(SIGSEGV);
 
index 2b41ebbfa7ffe261841d8bd17835f24abe8750ea..c13681ac1ede0cada819fb8c577b2e0e7c82ae5c 100644 (file)
@@ -217,6 +217,9 @@ static inline int __raw_read_trylock(raw_rwlock_t *rw)
 /* read_can_lock - would read_trylock() succeed? */
 #define __raw_read_can_lock(x)         ((x)->lock < 0x80000000)
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
index 2de14e2afdc5df8d3295f0aca4e3e6f7963980ba..c3265a2e7cd43278686b1d2e4168bb84554d9d6a 100644 (file)
@@ -301,7 +301,7 @@ void release_thread(struct task_struct *dead_task)
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
 int
-copy_thread(int nr, unsigned long clone_flags, unsigned long stack_start,
+copy_thread(unsigned long clone_flags, unsigned long stack_start,
            unsigned long stk_sz, struct task_struct *p, struct pt_regs *regs)
 {
        struct thread_info *thread = task_thread_info(p);
index f46698e20c1f063278798869237f0a5ecc4fb6a0..6112740b4ae9c88ac213b7e4f89ad2b7cf7730af 100644 (file)
@@ -380,14 +380,49 @@ static struct pca953x_platform_data pca9536_data = {
        .gpio_base      = NR_BUILTIN_GPIO + 1,
 };
 
-static struct soc_camera_link iclink[] = {
-       {
-               .bus_id = 0, /* Must match with the camera ID above */
-               .gpio   = NR_BUILTIN_GPIO + 1,
-       }, {
-               .bus_id = 0, /* Must match with the camera ID above */
-               .gpio   = -ENXIO,
+static int gpio_bus_switch;
+
+static int pcm990_camera_set_bus_param(struct soc_camera_link *link,
+               unsigned long flags)
+{
+       if (gpio_bus_switch <= 0) {
+               if (flags == SOCAM_DATAWIDTH_10)
+                       return 0;
+               else
+                       return -EINVAL;
+       }
+
+       if (flags & SOCAM_DATAWIDTH_8)
+               gpio_set_value(gpio_bus_switch, 1);
+       else
+               gpio_set_value(gpio_bus_switch, 0);
+
+       return 0;
+}
+
+static unsigned long pcm990_camera_query_bus_param(struct soc_camera_link *link)
+{
+       int ret;
+
+       if (!gpio_bus_switch) {
+               ret = gpio_request(NR_BUILTIN_GPIO + 1, "camera");
+               if (!ret) {
+                       gpio_bus_switch = NR_BUILTIN_GPIO + 1;
+                       gpio_direction_output(gpio_bus_switch, 0);
+               } else
+                       gpio_bus_switch = -EINVAL;
        }
+
+       if (gpio_bus_switch > 0)
+               return SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_10;
+       else
+               return SOCAM_DATAWIDTH_10;
+}
+
+static struct soc_camera_link iclink = {
+       .bus_id = 0, /* Must match with the camera ID above */
+       .query_bus_param = pcm990_camera_query_bus_param,
+       .set_bus_param = pcm990_camera_set_bus_param,
 };
 
 /* Board I2C devices. */
@@ -398,10 +433,10 @@ static struct i2c_board_info __initdata pcm990_i2c_devices[] = {
                .platform_data = &pca9536_data,
        }, {
                I2C_BOARD_INFO("mt9v022", 0x48),
-               .platform_data = &iclink[0], /* With extender */
+               .platform_data = &iclink, /* With extender */
        }, {
                I2C_BOARD_INFO("mt9m001", 0x5d),
-               .platform_data = &iclink[0], /* With extender */
+               .platform_data = &iclink, /* With extender */
        },
 };
 #endif /* CONFIG_VIDEO_PXA27x ||CONFIG_VIDEO_PXA27x_MODULE */
diff --git a/arch/arm/plat-mxc/include/mach/mx3_camera.h b/arch/arm/plat-mxc/include/mach/mx3_camera.h
new file mode 100644 (file)
index 0000000..36d7ff2
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * mx3_camera.h - i.MX3x camera driver header file
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski, DENX Software Engineering, <lg@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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _MX3_CAMERA_H_
+#define _MX3_CAMERA_H_
+
+#include <linux/device.h>
+
+#define MX3_CAMERA_CLK_SRC     1
+#define MX3_CAMERA_EXT_VSYNC   2
+#define MX3_CAMERA_DP          4
+#define MX3_CAMERA_PCP         8
+#define MX3_CAMERA_HSP         0x10
+#define MX3_CAMERA_VSP         0x20
+#define MX3_CAMERA_DATAWIDTH_4 0x40
+#define MX3_CAMERA_DATAWIDTH_8 0x80
+#define MX3_CAMERA_DATAWIDTH_10        0x100
+#define MX3_CAMERA_DATAWIDTH_15        0x200
+
+#define MX3_CAMERA_DATAWIDTH_MASK (MX3_CAMERA_DATAWIDTH_4 | MX3_CAMERA_DATAWIDTH_8 | \
+                                  MX3_CAMERA_DATAWIDTH_10 | MX3_CAMERA_DATAWIDTH_15)
+
+/**
+ * struct mx3_camera_pdata - i.MX3x camera platform data
+ * @flags:     MX3_CAMERA_* flags
+ * @mclk_10khz:        master clock frequency in 10kHz units
+ * @dma_dev:   IPU DMA device to match against in channel allocation
+ */
+struct mx3_camera_pdata {
+       unsigned long flags;
+       unsigned long mclk_10khz;
+       struct device *dma_dev;
+};
+
+#endif
index 43ae555ecb33995e906d3b4f5567197893b08ce9..1bbe1da54869bd2192f6a9f4638bdf20e468b983 100644 (file)
@@ -332,7 +332,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 
 asmlinkage void ret_from_fork(void);
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(unsigned long clone_flags, unsigned long usp,
                unsigned long unused,
                struct task_struct *p, struct pt_regs *regs)
 {
index ce4e4296b95467f3e0b715a9ec953398917be8f7..62d4abbaa65431185993ee249722dcb2d3cfdc44 100644 (file)
@@ -250,21 +250,3 @@ asmlinkage void do_bus_error(unsigned long addr, int write_access,
        dump_dtlb();
        die("Bus Error", regs, SIGKILL);
 }
-
-/*
- * This functionality is currently not possible to implement because
- * we're using segmentation to ensure a fixed mapping of the kernel
- * virtual address space.
- *
- * It would be possible to implement this, but it would require us to
- * disable segmentation at startup and load the kernel mappings into
- * the TLB like any other pages. There will be lots of trickery to
- * avoid recursive invocation of the TLB miss handler, though...
- */
-#ifdef CONFIG_DEBUG_PAGEALLOC
-void kernel_map_pages(struct page *page, int numpages, int enable)
-{
-
-}
-EXPORT_SYMBOL(kernel_map_pages);
-#endif
index 33e2e8993f7f967739c8539f932ea6b1d46725da..f49427293ca1c48e688e1f95a92504d2d8fa0b0a 100644 (file)
@@ -193,7 +193,7 @@ asmlinkage int bfin_clone(struct pt_regs *regs)
 }
 
 int
-copy_thread(int nr, unsigned long clone_flags,
+copy_thread(unsigned long clone_flags,
            unsigned long usp, unsigned long topstk,
            struct task_struct *p, struct pt_regs *regs)
 {
index 834cab7438a8fa3293f2c8e1ef4269c6740d8e13..530d1393a23226926c80ef833dd6b32230405214 100644 (file)
@@ -854,7 +854,6 @@ static int __init sram_proc_init(void)
                printk(KERN_WARNING "unable to create /proc/sram\n");
                return -1;
        }
-       ptr->owner = THIS_MODULE;
        ptr->read_proc = sram_proc_read;
        return 0;
 }
index bd9b3ff63f6c7b772ce89b8bd1df0e9934b75d06..c4c69cf721e5155141f8261ed536ede9570c3e35 100644 (file)
@@ -115,7 +115,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
  */
 asmlinkage void ret_from_fork(void);
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(unsigned long clone_flags, unsigned long usp,
                unsigned long unused,
                struct task_struct *p, struct pt_regs *regs)
 {
index c685ba4c33875c978abb599ce82c132ed3527f1e..2b73c7a5b6499a195a66badd8ef97b4d0c84b413 100644 (file)
@@ -261,7 +261,6 @@ timer_interrupt(int irq, void *dev_id)
 static struct irqaction irq2  = {
        .handler = timer_interrupt,
        .flags = IRQF_SHARED | IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "timer",
 };
 
index ced5b725d9bd0a1ec2d5da7495877c30e3dbf95d..120e7f796fea9707f009af5bffbc15aad6fbdd0f 100644 (file)
@@ -131,7 +131,7 @@ kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 extern asmlinkage void ret_from_fork(void);
 
 int
-copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+copy_thread(unsigned long clone_flags, unsigned long usp,
        unsigned long unused,
        struct task_struct *p, struct pt_regs *regs)
 {
index 9dac17334640a9cf3eda77c0c0a22b53e817f0a1..f59a973c97ee31893595b2a6c6e2e7778ce15e10 100644 (file)
@@ -65,7 +65,6 @@ static int send_ipi(int vector, int wait, cpumask_t cpu_mask);
 static struct irqaction irq_ipi  = {
        .handler = crisv32_ipi_interrupt,
        .flags = IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "ipi",
 };
 
index 3a13dd6e0a9a0d7e7eb40aaaff2ada62a2033239..65633d0dab860847b1367455b275a535448b6ee3 100644 (file)
@@ -267,7 +267,6 @@ timer_interrupt(int irq, void *dev_id)
 static struct irqaction irq_timer = {
        .handler = timer_interrupt,
        .flags = IRQF_SHARED | IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "timer"
 };
 
index 0d5709b983a103038fae9de47d557e407086c2d4..129756b96661257945d768bfe3f5eecee2b4e282 100644 (file)
@@ -121,6 +121,8 @@ static  inline int __raw_write_trylock(raw_rwlock_t *rw)
        return 1;
 }
 
+#define _raw_read_lock_flags(lock, flags) _raw_read_lock(lock)
+#define _raw_write_lock_flags(lock, flags) _raw_write_lock(lock)
 
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
index 9e38f99bbab89c7e0677e5da0f38f09d9d6590ea..4dd9adaf115a4de8083ce7bfde075e5f3ac82123 100644 (file)
@@ -109,28 +109,24 @@ static struct irqaction fpga_irq[4]  = {
        [0] = {
                .handler        = fpga_interrupt,
                .flags          = IRQF_DISABLED | IRQF_SHARED,
-               .mask           = CPU_MASK_NONE,
                .name           = "fpga.0",
                .dev_id         = (void *) 0x0028UL,
        },
        [1] = {
                .handler        = fpga_interrupt,
                .flags          = IRQF_DISABLED | IRQF_SHARED,
-               .mask           = CPU_MASK_NONE,
                .name           = "fpga.1",
                .dev_id         = (void *) 0x0050UL,
        },
        [2] = {
                .handler        = fpga_interrupt,
                .flags          = IRQF_DISABLED | IRQF_SHARED,
-               .mask           = CPU_MASK_NONE,
                .name           = "fpga.2",
                .dev_id         = (void *) 0x1c00UL,
        },
        [3] = {
                .handler        = fpga_interrupt,
                .flags          = IRQF_DISABLED | IRQF_SHARED,
-               .mask           = CPU_MASK_NONE,
                .name           = "fpga.3",
                .dev_id         = (void *) 0x6386UL,
        }
index 3c2752ca97754eb881d5fef6ceeeb576ee679df1..e45209031873e63de6e0202bbd3e831a29ff27bb 100644 (file)
@@ -108,7 +108,6 @@ static struct irqaction fpga_irq[1]  = {
        [0] = {
                .handler        = fpga_interrupt,
                .flags          = IRQF_DISABLED,
-               .mask           = CPU_MASK_NONE,
                .name           = "fpga.0",
                .dev_id         = (void *) 0x0700UL,
        }
index 7754c7338e4b42cfaeb4c3a76158665f3b05d275..ba55ecdfb245a5c201bf34583bcad836677ea26e 100644 (file)
@@ -120,14 +120,12 @@ static struct irqaction mb93493_irq[2]  = {
        [0] = {
                .handler        = mb93493_interrupt,
                .flags          = IRQF_DISABLED | IRQF_SHARED,
-               .mask           = CPU_MASK_NONE,
                .name           = "mb93493.0",
                .dev_id         = (void *) __addr_MB93493_IQSR(0),
        },
        [1] = {
                .handler        = mb93493_interrupt,
                .flags          = IRQF_DISABLED | IRQF_SHARED,
-               .mask           = CPU_MASK_NONE,
                .name           = "mb93493.1",
                .dev_id         = (void *) __addr_MB93493_IQSR(1),
        }
index 9583a338e9d6022b7529dcffa34201917502151d..0de50df7497036e52602c2bcfc5a0a0753f6b534 100644 (file)
@@ -204,7 +204,7 @@ void prepare_to_copy(struct task_struct *tsk)
 /*
  * set up the kernel stack and exception frames for a new process
  */
-int copy_thread(int nr, unsigned long clone_flags,
+int copy_thread(unsigned long clone_flags,
                unsigned long usp, unsigned long topstk,
                struct task_struct *p, struct pt_regs *regs)
 {
index 69f6a4ef5d61b35c67323a85485e1cebedff7a43..fb0ce75772256568bc2195ba08cbfb9a652def94 100644 (file)
@@ -45,7 +45,6 @@ static irqreturn_t timer_interrupt(int irq, void *dummy);
 static struct irqaction timer_irq  = {
        .handler = timer_interrupt,
        .flags = IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "timer",
 };
 
index a8ef654a5a0b8403af3a52c709478956140d2690..e2f33d0f99698ceb03212a5f46fa1e61ccd72cc1 100644 (file)
@@ -191,7 +191,7 @@ asmlinkage int h8300_clone(struct pt_regs *regs)
 
 }
 
-int copy_thread(int nr, unsigned long clone_flags,
+int copy_thread(unsigned long clone_flags,
                 unsigned long usp, unsigned long topstk,
                 struct task_struct * p, struct pt_regs * regs)
 {
index d1c926596b087ace1359ac7504303296e31f9b9b..4883ba7103a84d8b391a290fc64198949f2c3ca9 100644 (file)
@@ -60,7 +60,6 @@ static struct irqaction itu_irq = {
        .name           = "itu",
        .handler        = timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_TIMER,
-       .mask           = CPU_MASK_NONE,
 };
 
 static const int __initdata divide_rate[] = {1, 2, 4, 8};
index e14271b7211943b183b23dc7076c78cdd280ba9c..042dbb53f3fb372707ab7a533a884e7ccb6b8dd3 100644 (file)
@@ -55,7 +55,6 @@ static struct irqaction timer16_irq = {
        .name           = "timer-16",
        .handler        = timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_TIMER,
-       .mask           = CPU_MASK_NONE,
 };
 
 static const int __initdata divide_rate[] = {1, 2, 4, 8};
index 0556d7c7bea62c620377b82ca3b35f92d46f5712..38be0cabef0da0c4433d9d52924eef8f199e5b0b 100644 (file)
@@ -75,7 +75,6 @@ static struct irqaction timer8_irq = {
        .name           = "timer-8",
        .handler        = timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_TIMER,
-       .mask           = CPU_MASK_NONE,
 };
 
 static const int __initdata divide_rate[] = {8, 64, 8192};
index df7f453a9673c6cdddd0e4f5b24d6cca49be7ceb..ad383caae196c282583d57e54d6e467dca9fcc62 100644 (file)
@@ -65,7 +65,6 @@ static struct irqaction tpu_irq = {
        .name           = "tpu",
        .handler        = timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_TIMER,
-       .mask           = CPU_MASK_NONE,
 };
 
 const static int __initdata divide_rate[] = {
index a109db30ce55e0ade28e542f475cd0b479d45639..75645495c2ddc491605ca29e9405b71edf8081f4 100644 (file)
@@ -193,7 +193,6 @@ CONFIG_BOUNCE=y
 CONFIG_NR_QUICK=1
 CONFIG_VIRT_TO_BUS=y
 CONFIG_UNEVICTABLE_LRU=y
-CONFIG_MMU_NOTIFIER=y
 CONFIG_ARCH_SELECT_MEMORY_MODEL=y
 CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
@@ -416,8 +415,6 @@ CONFIG_SGI_IOC4=y
 # CONFIG_ENCLOSURE_SERVICES is not set
 CONFIG_SGI_XP=m
 # CONFIG_HP_ILO is not set
-CONFIG_SGI_GRU=m
-# CONFIG_SGI_GRU_DEBUG is not set
 # CONFIG_C2PORT is not set
 CONFIG_HAVE_IDE=y
 CONFIG_IDE=y
index 5c0283830bd611d951c28f3b64ed49b41f961c73..2f7caddf093e8bce77d4d92f2933ee2500f8ab60 100644 (file)
@@ -7,8 +7,8 @@
 
 obj-y := setup.o
 ifeq ($(CONFIG_DMAR), y)
-obj-$(CONFIG_IA64_GENERIC) += machvec.o machvec_vtd.o dig_vtd_iommu.o
+obj-$(CONFIG_IA64_GENERIC) += machvec.o machvec_vtd.o
 else
 obj-$(CONFIG_IA64_GENERIC) += machvec.o
 endif
-obj-$(CONFIG_IA64_DIG_VTD) += dig_vtd_iommu.o
+
diff --git a/arch/ia64/dig/dig_vtd_iommu.c b/arch/ia64/dig/dig_vtd_iommu.c
deleted file mode 100644 (file)
index 1c8a079..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/intel-iommu.h>
-
-void *
-vtd_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-                gfp_t flags)
-{
-       return intel_alloc_coherent(dev, size, dma_handle, flags);
-}
-EXPORT_SYMBOL_GPL(vtd_alloc_coherent);
-
-void
-vtd_free_coherent(struct device *dev, size_t size, void *vaddr,
-                dma_addr_t dma_handle)
-{
-       intel_free_coherent(dev, size, vaddr, dma_handle);
-}
-EXPORT_SYMBOL_GPL(vtd_free_coherent);
-
-dma_addr_t
-vtd_map_single_attrs(struct device *dev, void *addr, size_t size,
-                    int dir, struct dma_attrs *attrs)
-{
-       return intel_map_single(dev, (phys_addr_t)addr, size, dir);
-}
-EXPORT_SYMBOL_GPL(vtd_map_single_attrs);
-
-void
-vtd_unmap_single_attrs(struct device *dev, dma_addr_t iova, size_t size,
-                      int dir, struct dma_attrs *attrs)
-{
-       intel_unmap_single(dev, iova, size, dir);
-}
-EXPORT_SYMBOL_GPL(vtd_unmap_single_attrs);
-
-int
-vtd_map_sg_attrs(struct device *dev, struct scatterlist *sglist, int nents,
-                int dir, struct dma_attrs *attrs)
-{
-       return intel_map_sg(dev, sglist, nents, dir);
-}
-EXPORT_SYMBOL_GPL(vtd_map_sg_attrs);
-
-void
-vtd_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist,
-                  int nents, int dir, struct dma_attrs *attrs)
-{
-       intel_unmap_sg(dev, sglist, nents, dir);
-}
-EXPORT_SYMBOL_GPL(vtd_unmap_sg_attrs);
-
-int
-vtd_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-       return 0;
-}
-EXPORT_SYMBOL_GPL(vtd_dma_mapping_error);
index 2769dbfd03bf8146852e7340ef5aee44746c0d30..e4a80d82e3d8b570d2ce2950319094f5d286b9c7 100644 (file)
  */
 
 #include <linux/device.h>
+#include <linux/dma-mapping.h>
 #include <linux/swiotlb.h>
-
 #include <asm/machvec.h>
 
+extern struct dma_map_ops sba_dma_ops, swiotlb_dma_ops;
+
 /* swiotlb declarations & definitions: */
 extern int swiotlb_late_init_with_default_size (size_t size);
 
-/* hwiommu declarations & definitions: */
-
-extern ia64_mv_dma_alloc_coherent      sba_alloc_coherent;
-extern ia64_mv_dma_free_coherent       sba_free_coherent;
-extern ia64_mv_dma_map_single_attrs    sba_map_single_attrs;
-extern ia64_mv_dma_unmap_single_attrs  sba_unmap_single_attrs;
-extern ia64_mv_dma_map_sg_attrs                sba_map_sg_attrs;
-extern ia64_mv_dma_unmap_sg_attrs      sba_unmap_sg_attrs;
-extern ia64_mv_dma_supported           sba_dma_supported;
-extern ia64_mv_dma_mapping_error       sba_dma_mapping_error;
-
-#define hwiommu_alloc_coherent         sba_alloc_coherent
-#define hwiommu_free_coherent          sba_free_coherent
-#define hwiommu_map_single_attrs       sba_map_single_attrs
-#define hwiommu_unmap_single_attrs     sba_unmap_single_attrs
-#define hwiommu_map_sg_attrs           sba_map_sg_attrs
-#define hwiommu_unmap_sg_attrs         sba_unmap_sg_attrs
-#define hwiommu_dma_supported          sba_dma_supported
-#define hwiommu_dma_mapping_error      sba_dma_mapping_error
-#define hwiommu_sync_single_for_cpu    machvec_dma_sync_single
-#define hwiommu_sync_sg_for_cpu                machvec_dma_sync_sg
-#define hwiommu_sync_single_for_device machvec_dma_sync_single
-#define hwiommu_sync_sg_for_device     machvec_dma_sync_sg
-
-
 /*
  * Note: we need to make the determination of whether or not to use
  * the sw I/O TLB based purely on the device structure.  Anything else
  * would be unreliable or would be too intrusive.
  */
-static inline int
-use_swiotlb (struct device *dev)
+static inline int use_swiotlb(struct device *dev)
 {
-       return dev && dev->dma_mask && !hwiommu_dma_supported(dev, *dev->dma_mask);
+       return dev && dev->dma_mask &&
+               !sba_dma_ops.dma_supported(dev, *dev->dma_mask);
 }
 
+struct dma_map_ops *hwsw_dma_get_ops(struct device *dev)
+{
+       if (use_swiotlb(dev))
+               return &swiotlb_dma_ops;
+       return &sba_dma_ops;
+}
+EXPORT_SYMBOL(hwsw_dma_get_ops);
+
 void __init
 hwsw_init (void)
 {
@@ -71,125 +56,3 @@ hwsw_init (void)
 #endif
        }
 }
-
-void *
-hwsw_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags)
-{
-       if (use_swiotlb(dev))
-               return swiotlb_alloc_coherent(dev, size, dma_handle, flags);
-       else
-               return hwiommu_alloc_coherent(dev, size, dma_handle, flags);
-}
-
-void
-hwsw_free_coherent (struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle)
-{
-       if (use_swiotlb(dev))
-               swiotlb_free_coherent(dev, size, vaddr, dma_handle);
-       else
-               hwiommu_free_coherent(dev, size, vaddr, dma_handle);
-}
-
-dma_addr_t
-hwsw_map_single_attrs(struct device *dev, void *addr, size_t size, int dir,
-                      struct dma_attrs *attrs)
-{
-       if (use_swiotlb(dev))
-               return swiotlb_map_single_attrs(dev, addr, size, dir, attrs);
-       else
-               return hwiommu_map_single_attrs(dev, addr, size, dir, attrs);
-}
-EXPORT_SYMBOL(hwsw_map_single_attrs);
-
-void
-hwsw_unmap_single_attrs(struct device *dev, dma_addr_t iova, size_t size,
-                        int dir, struct dma_attrs *attrs)
-{
-       if (use_swiotlb(dev))
-               return swiotlb_unmap_single_attrs(dev, iova, size, dir, attrs);
-       else
-               return hwiommu_unmap_single_attrs(dev, iova, size, dir, attrs);
-}
-EXPORT_SYMBOL(hwsw_unmap_single_attrs);
-
-int
-hwsw_map_sg_attrs(struct device *dev, struct scatterlist *sglist, int nents,
-                  int dir, struct dma_attrs *attrs)
-{
-       if (use_swiotlb(dev))
-               return swiotlb_map_sg_attrs(dev, sglist, nents, dir, attrs);
-       else
-               return hwiommu_map_sg_attrs(dev, sglist, nents, dir, attrs);
-}
-EXPORT_SYMBOL(hwsw_map_sg_attrs);
-
-void
-hwsw_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist, int nents,
-                    int dir, struct dma_attrs *attrs)
-{
-       if (use_swiotlb(dev))
-               return swiotlb_unmap_sg_attrs(dev, sglist, nents, dir, attrs);
-       else
-               return hwiommu_unmap_sg_attrs(dev, sglist, nents, dir, attrs);
-}
-EXPORT_SYMBOL(hwsw_unmap_sg_attrs);
-
-void
-hwsw_sync_single_for_cpu (struct device *dev, dma_addr_t addr, size_t size, int dir)
-{
-       if (use_swiotlb(dev))
-               swiotlb_sync_single_for_cpu(dev, addr, size, dir);
-       else
-               hwiommu_sync_single_for_cpu(dev, addr, size, dir);
-}
-
-void
-hwsw_sync_sg_for_cpu (struct device *dev, struct scatterlist *sg, int nelems, int dir)
-{
-       if (use_swiotlb(dev))
-               swiotlb_sync_sg_for_cpu(dev, sg, nelems, dir);
-       else
-               hwiommu_sync_sg_for_cpu(dev, sg, nelems, dir);
-}
-
-void
-hwsw_sync_single_for_device (struct device *dev, dma_addr_t addr, size_t size, int dir)
-{
-       if (use_swiotlb(dev))
-               swiotlb_sync_single_for_device(dev, addr, size, dir);
-       else
-               hwiommu_sync_single_for_device(dev, addr, size, dir);
-}
-
-void
-hwsw_sync_sg_for_device (struct device *dev, struct scatterlist *sg, int nelems, int dir)
-{
-       if (use_swiotlb(dev))
-               swiotlb_sync_sg_for_device(dev, sg, nelems, dir);
-       else
-               hwiommu_sync_sg_for_device(dev, sg, nelems, dir);
-}
-
-int
-hwsw_dma_supported (struct device *dev, u64 mask)
-{
-       if (hwiommu_dma_supported(dev, mask))
-               return 1;
-       return swiotlb_dma_supported(dev, mask);
-}
-
-int
-hwsw_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-       return hwiommu_dma_mapping_error(dev, dma_addr) ||
-               swiotlb_dma_mapping_error(dev, dma_addr);
-}
-
-EXPORT_SYMBOL(hwsw_dma_mapping_error);
-EXPORT_SYMBOL(hwsw_dma_supported);
-EXPORT_SYMBOL(hwsw_alloc_coherent);
-EXPORT_SYMBOL(hwsw_free_coherent);
-EXPORT_SYMBOL(hwsw_sync_single_for_cpu);
-EXPORT_SYMBOL(hwsw_sync_single_for_device);
-EXPORT_SYMBOL(hwsw_sync_sg_for_cpu);
-EXPORT_SYMBOL(hwsw_sync_sg_for_device);
index 6d5e6c5630e3b8a6efa5eccae0d3d5c10ece4516..56ceb68eb99d244fffc70feab344e337ec385f7d 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/bitops.h>         /* hweight64() */
 #include <linux/crash_dump.h>
 #include <linux/iommu-helper.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/delay.h>         /* ia64_get_itc() */
 #include <asm/io.h>
@@ -908,11 +909,13 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
  *
  * See Documentation/PCI/PCI-DMA-mapping.txt
  */
-dma_addr_t
-sba_map_single_attrs(struct device *dev, void *addr, size_t size, int dir,
-                    struct dma_attrs *attrs)
+static dma_addr_t sba_map_page(struct device *dev, struct page *page,
+                              unsigned long poff, size_t size,
+                              enum dma_data_direction dir,
+                              struct dma_attrs *attrs)
 {
        struct ioc *ioc;
+       void *addr = page_address(page) + poff;
        dma_addr_t iovp;
        dma_addr_t offset;
        u64 *pdir_start;
@@ -990,7 +993,14 @@ sba_map_single_attrs(struct device *dev, void *addr, size_t size, int dir,
 #endif
        return SBA_IOVA(ioc, iovp, offset);
 }
-EXPORT_SYMBOL(sba_map_single_attrs);
+
+static dma_addr_t sba_map_single_attrs(struct device *dev, void *addr,
+                                      size_t size, enum dma_data_direction dir,
+                                      struct dma_attrs *attrs)
+{
+       return sba_map_page(dev, virt_to_page(addr),
+                           (unsigned long)addr & ~PAGE_MASK, size, dir, attrs);
+}
 
 #ifdef ENABLE_MARK_CLEAN
 static SBA_INLINE void
@@ -1026,8 +1036,8 @@ sba_mark_clean(struct ioc *ioc, dma_addr_t iova, size_t size)
  *
  * See Documentation/PCI/PCI-DMA-mapping.txt
  */
-void sba_unmap_single_attrs(struct device *dev, dma_addr_t iova, size_t size,
-                           int dir, struct dma_attrs *attrs)
+static void sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
+                          enum dma_data_direction dir, struct dma_attrs *attrs)
 {
        struct ioc *ioc;
 #if DELAYED_RESOURCE_CNT > 0
@@ -1094,7 +1104,12 @@ void sba_unmap_single_attrs(struct device *dev, dma_addr_t iova, size_t size,
        spin_unlock_irqrestore(&ioc->res_lock, flags);
 #endif /* DELAYED_RESOURCE_CNT == 0 */
 }
-EXPORT_SYMBOL(sba_unmap_single_attrs);
+
+void sba_unmap_single_attrs(struct device *dev, dma_addr_t iova, size_t size,
+                           enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+       sba_unmap_page(dev, iova, size, dir, attrs);
+}
 
 /**
  * sba_alloc_coherent - allocate/map shared mem for DMA
@@ -1104,7 +1119,7 @@ EXPORT_SYMBOL(sba_unmap_single_attrs);
  *
  * See Documentation/PCI/PCI-DMA-mapping.txt
  */
-void *
+static void *
 sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags)
 {
        struct ioc *ioc;
@@ -1167,7 +1182,8 @@ sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp
  *
  * See Documentation/PCI/PCI-DMA-mapping.txt
  */
-void sba_free_coherent (struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle)
+static void sba_free_coherent (struct device *dev, size_t size, void *vaddr,
+                              dma_addr_t dma_handle)
 {
        sba_unmap_single_attrs(dev, dma_handle, size, 0, NULL);
        free_pages((unsigned long) vaddr, get_order(size));
@@ -1422,8 +1438,9 @@ sba_coalesce_chunks(struct ioc *ioc, struct device *dev,
  *
  * See Documentation/PCI/PCI-DMA-mapping.txt
  */
-int sba_map_sg_attrs(struct device *dev, struct scatterlist *sglist, int nents,
-                    int dir, struct dma_attrs *attrs)
+static int sba_map_sg_attrs(struct device *dev, struct scatterlist *sglist,
+                           int nents, enum dma_data_direction dir,
+                           struct dma_attrs *attrs)
 {
        struct ioc *ioc;
        int coalesced, filled = 0;
@@ -1502,7 +1519,6 @@ int sba_map_sg_attrs(struct device *dev, struct scatterlist *sglist, int nents,
 
        return filled;
 }
-EXPORT_SYMBOL(sba_map_sg_attrs);
 
 /**
  * sba_unmap_sg_attrs - unmap Scatter/Gather list
@@ -1514,8 +1530,9 @@ EXPORT_SYMBOL(sba_map_sg_attrs);
  *
  * See Documentation/PCI/PCI-DMA-mapping.txt
  */
-void sba_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist,
-                       int nents, int dir, struct dma_attrs *attrs)
+static void sba_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist,
+                              int nents, enum dma_data_direction dir,
+                              struct dma_attrs *attrs)
 {
 #ifdef ASSERT_PDIR_SANITY
        struct ioc *ioc;
@@ -1551,7 +1568,6 @@ void sba_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist,
 #endif
 
 }
-EXPORT_SYMBOL(sba_unmap_sg_attrs);
 
 /**************************************************************
 *
@@ -2064,6 +2080,8 @@ static struct acpi_driver acpi_sba_ioc_driver = {
        },
 };
 
+extern struct dma_map_ops swiotlb_dma_ops;
+
 static int __init
 sba_init(void)
 {
@@ -2077,6 +2095,7 @@ sba_init(void)
         * a successful kdump kernel boot is to use the swiotlb.
         */
        if (is_kdump_kernel()) {
+               dma_ops = &swiotlb_dma_ops;
                if (swiotlb_late_init_with_default_size(64 * (1<<20)) != 0)
                        panic("Unable to initialize software I/O TLB:"
                                  " Try machvec=dig boot option");
@@ -2092,6 +2111,7 @@ sba_init(void)
                 * If we didn't find something sba_iommu can claim, we
                 * need to setup the swiotlb and switch to the dig machvec.
                 */
+               dma_ops = &swiotlb_dma_ops;
                if (swiotlb_late_init_with_default_size(64 * (1<<20)) != 0)
                        panic("Unable to find SBA IOMMU or initialize "
                              "software I/O TLB: Try machvec=dig boot option");
@@ -2138,15 +2158,13 @@ nosbagart(char *str)
        return 1;
 }
 
-int
-sba_dma_supported (struct device *dev, u64 mask)
+static int sba_dma_supported (struct device *dev, u64 mask)
 {
        /* make sure it's at least 32bit capable */
        return ((mask & 0xFFFFFFFFUL) == 0xFFFFFFFFUL);
 }
 
-int
-sba_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+static int sba_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
        return 0;
 }
@@ -2176,7 +2194,22 @@ sba_page_override(char *str)
 
 __setup("sbapagesize=",sba_page_override);
 
-EXPORT_SYMBOL(sba_dma_mapping_error);
-EXPORT_SYMBOL(sba_dma_supported);
-EXPORT_SYMBOL(sba_alloc_coherent);
-EXPORT_SYMBOL(sba_free_coherent);
+struct dma_map_ops sba_dma_ops = {
+       .alloc_coherent         = sba_alloc_coherent,
+       .free_coherent          = sba_free_coherent,
+       .map_page               = sba_map_page,
+       .unmap_page             = sba_unmap_page,
+       .map_sg                 = sba_map_sg_attrs,
+       .unmap_sg               = sba_unmap_sg_attrs,
+       .sync_single_for_cpu    = machvec_dma_sync_single,
+       .sync_sg_for_cpu        = machvec_dma_sync_sg,
+       .sync_single_for_device = machvec_dma_sync_single,
+       .sync_sg_for_device     = machvec_dma_sync_sg,
+       .dma_supported          = sba_dma_supported,
+       .mapping_error          = sba_dma_mapping_error,
+};
+
+void sba_dma_init(void)
+{
+       dma_ops = &sba_dma_ops;
+}
index 24b1ad5334cb7bda3bb35b8c6d14616fb956a504..2bef5261d96dce13c983758a68f0e280041bdaa5 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/major.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/capability.h>
 #include <linux/console.h>
@@ -848,38 +849,36 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
  * /proc fs routines....
  */
 
-static inline int line_info(char *buf, struct serial_state *state)
+static inline void line_info(struct seq_file *m, struct serial_state *state)
 {
-       return sprintf(buf, "%d: uart:%s port:%lX irq:%d\n",
+       seq_printf(m, "%d: uart:%s port:%lX irq:%d\n",
                       state->line, uart_config[state->type].name,
                       state->port, state->irq);
 }
 
-static int rs_read_proc(char *page, char **start, off_t off, int count,
-                int *eof, void *data)
+static int rs_proc_show(struct seq_file *m, void *v)
 {
-       int i, len = 0, l;
-       off_t   begin = 0;
-
-       len += sprintf(page, "simserinfo:1.0 driver:%s\n", serial_version);
-       for (i = 0; i < NR_PORTS && len < 4000; i++) {
-               l = line_info(page + len, &rs_table[i]);
-               len += l;
-               if (len+begin > off+count)
-                       goto done;
-               if (len+begin < off) {
-                       begin += len;
-                       len = 0;
-               }
-       }
-       *eof = 1;
-done:
-       if (off >= len+begin)
-               return 0;
-       *start = page + (begin-off);
-       return ((count < begin+len-off) ? count : begin+len-off);
+       int i;
+
+       seq_printf(m, "simserinfo:1.0 driver:%s\n", serial_version);
+       for (i = 0; i < NR_PORTS; i++)
+               line_info(m, &rs_table[i]);
+       return 0;
 }
 
+static int rs_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, rs_proc_show, NULL);
+}
+
+static const struct file_operations rs_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = rs_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*
  * ---------------------------------------------------------------------
  * rs_init() and friends
@@ -917,7 +916,7 @@ static const struct tty_operations hp_ops = {
        .start = rs_start,
        .hangup = rs_hangup,
        .wait_until_sent = rs_wait_until_sent,
-       .read_proc = rs_read_proc,
+       .proc_fops = &rs_proc_fops,
 };
 
 /*
index 1f912d927585efbc69cb29734a4ddb4f67bff154..36c0009dbece5d29d80ac8253edb64e6cd98867b 100644 (file)
 
 #define ARCH_HAS_DMA_GET_REQUIRED_MASK
 
-struct dma_mapping_ops {
-       int             (*mapping_error)(struct device *dev,
-                                        dma_addr_t dma_addr);
-       void*           (*alloc_coherent)(struct device *dev, size_t size,
-                               dma_addr_t *dma_handle, gfp_t gfp);
-       void            (*free_coherent)(struct device *dev, size_t size,
-                               void *vaddr, dma_addr_t dma_handle);
-       dma_addr_t      (*map_single)(struct device *hwdev, unsigned long ptr,
-                               size_t size, int direction);
-       void            (*unmap_single)(struct device *dev, dma_addr_t addr,
-                               size_t size, int direction);
-       void            (*sync_single_for_cpu)(struct device *hwdev,
-                               dma_addr_t dma_handle, size_t size,
-                               int direction);
-       void            (*sync_single_for_device)(struct device *hwdev,
-                               dma_addr_t dma_handle, size_t size,
-                               int direction);
-       void            (*sync_single_range_for_cpu)(struct device *hwdev,
-                               dma_addr_t dma_handle, unsigned long offset,
-                               size_t size, int direction);
-       void            (*sync_single_range_for_device)(struct device *hwdev,
-                               dma_addr_t dma_handle, unsigned long offset,
-                               size_t size, int direction);
-       void            (*sync_sg_for_cpu)(struct device *hwdev,
-                               struct scatterlist *sg, int nelems,
-                               int direction);
-       void            (*sync_sg_for_device)(struct device *hwdev,
-                               struct scatterlist *sg, int nelems,
-                               int direction);
-       int             (*map_sg)(struct device *hwdev, struct scatterlist *sg,
-                               int nents, int direction);
-       void            (*unmap_sg)(struct device *hwdev,
-                               struct scatterlist *sg, int nents,
-                               int direction);
-       int             (*dma_supported_op)(struct device *hwdev, u64 mask);
-       int             is_phys;
-};
-
-extern struct dma_mapping_ops *dma_ops;
+extern struct dma_map_ops *dma_ops;
 extern struct ia64_machine_vector ia64_mv;
 extern void set_iommu_machvec(void);
 
-#define dma_alloc_coherent(dev, size, handle, gfp)     \
-       platform_dma_alloc_coherent(dev, size, handle, (gfp) | GFP_DMA)
+extern void machvec_dma_sync_single(struct device *, dma_addr_t, size_t,
+                                   enum dma_data_direction);
+extern void machvec_dma_sync_sg(struct device *, struct scatterlist *, int,
+                               enum dma_data_direction);
 
-/* coherent mem. is cheap */
-static inline void *
-dma_alloc_noncoherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-                     gfp_t flag)
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+                                      dma_addr_t *daddr, gfp_t gfp)
 {
-       return dma_alloc_coherent(dev, size, dma_handle, flag);
+       struct dma_map_ops *ops = platform_dma_get_ops(dev);
+       return ops->alloc_coherent(dev, size, daddr, gfp);
 }
-#define dma_free_coherent      platform_dma_free_coherent
-static inline void
-dma_free_noncoherent(struct device *dev, size_t size, void *cpu_addr,
-                    dma_addr_t dma_handle)
+
+static inline void dma_free_coherent(struct device *dev, size_t size,
+                                    void *caddr, dma_addr_t daddr)
+{
+       struct dma_map_ops *ops = platform_dma_get_ops(dev);
+       ops->free_coherent(dev, size, caddr, daddr);
+}
+
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+
+static inline dma_addr_t dma_map_single_attrs(struct device *dev,
+                                             void *caddr, size_t size,
+                                             enum dma_data_direction dir,
+                                             struct dma_attrs *attrs)
+{
+       struct dma_map_ops *ops = platform_dma_get_ops(dev);
+       return ops->map_page(dev, virt_to_page(caddr),
+                            (unsigned long)caddr & ~PAGE_MASK, size,
+                            dir, attrs);
+}
+
+static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t daddr,
+                                         size_t size,
+                                         enum dma_data_direction dir,
+                                         struct dma_attrs *attrs)
+{
+       struct dma_map_ops *ops = platform_dma_get_ops(dev);
+       ops->unmap_page(dev, daddr, size, dir, attrs);
+}
+
+#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, NULL)
+#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, NULL)
+
+static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
+                                  int nents, enum dma_data_direction dir,
+                                  struct dma_attrs *attrs)
+{
+       struct dma_map_ops *ops = platform_dma_get_ops(dev);
+       return ops->map_sg(dev, sgl, nents, dir, attrs);
+}
+
+static inline void dma_unmap_sg_attrs(struct device *dev,
+                                     struct scatterlist *sgl, int nents,
+                                     enum dma_data_direction dir,
+                                     struct dma_attrs *attrs)
+{
+       struct dma_map_ops *ops = platform_dma_get_ops(dev);
+       ops->unmap_sg(dev, sgl, nents, dir, attrs);
+}
+
+#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL)
+#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL)
+
+static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t daddr,
+                                          size_t size,
+                                          enum dma_data_direction dir)
 {
-       dma_free_coherent(dev, size, cpu_addr, dma_handle);
+       struct dma_map_ops *ops = platform_dma_get_ops(dev);
+       ops->sync_single_for_cpu(dev, daddr, size, dir);
 }
-#define dma_map_single_attrs   platform_dma_map_single_attrs
-static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
-                                       size_t size, int dir)
+
+static inline void dma_sync_sg_for_cpu(struct device *dev,
+                                      struct scatterlist *sgl,
+                                      int nents, enum dma_data_direction dir)
 {
-       return dma_map_single_attrs(dev, cpu_addr, size, dir, NULL);
+       struct dma_map_ops *ops = platform_dma_get_ops(dev);
+       ops->sync_sg_for_cpu(dev, sgl, nents, dir);
 }
-#define dma_map_sg_attrs       platform_dma_map_sg_attrs
-static inline int dma_map_sg(struct device *dev, struct scatterlist *sgl,
-                            int nents, int dir)
+
+static inline void dma_sync_single_for_device(struct device *dev,
+                                             dma_addr_t daddr,
+                                             size_t size,
+                                             enum dma_data_direction dir)
 {
-       return dma_map_sg_attrs(dev, sgl, nents, dir, NULL);
+       struct dma_map_ops *ops = platform_dma_get_ops(dev);
+       ops->sync_single_for_device(dev, daddr, size, dir);
 }
-#define dma_unmap_single_attrs platform_dma_unmap_single_attrs
-static inline void dma_unmap_single(struct device *dev, dma_addr_t cpu_addr,
-                                   size_t size, int dir)
+
+static inline void dma_sync_sg_for_device(struct device *dev,
+                                         struct scatterlist *sgl,
+                                         int nents,
+                                         enum dma_data_direction dir)
 {
-       return dma_unmap_single_attrs(dev, cpu_addr, size, dir, NULL);
+       struct dma_map_ops *ops = platform_dma_get_ops(dev);
+       ops->sync_sg_for_device(dev, sgl, nents, dir);
 }
-#define dma_unmap_sg_attrs     platform_dma_unmap_sg_attrs
-static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sgl,
-                               int nents, int dir)
+
+static inline int dma_mapping_error(struct device *dev, dma_addr_t daddr)
+{
+       struct dma_map_ops *ops = platform_dma_get_ops(dev);
+       return ops->mapping_error(dev, daddr);
+}
+
+static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
+                                     size_t offset, size_t size,
+                                     enum dma_data_direction dir)
 {
-       return dma_unmap_sg_attrs(dev, sgl, nents, dir, NULL);
+       struct dma_map_ops *ops = platform_dma_get_ops(dev);
+       return ops->map_page(dev, page, offset, size, dir, NULL);
 }
-#define dma_sync_single_for_cpu        platform_dma_sync_single_for_cpu
-#define dma_sync_sg_for_cpu    platform_dma_sync_sg_for_cpu
-#define dma_sync_single_for_device platform_dma_sync_single_for_device
-#define dma_sync_sg_for_device platform_dma_sync_sg_for_device
-#define dma_mapping_error      platform_dma_mapping_error
 
-#define dma_map_page(dev, pg, off, size, dir)                          \
-       dma_map_single(dev, page_address(pg) + (off), (size), (dir))
-#define dma_unmap_page(dev, dma_addr, size, dir)                       \
-       dma_unmap_single(dev, dma_addr, size, dir)
+static inline void dma_unmap_page(struct device *dev, dma_addr_t addr,
+                                 size_t size, enum dma_data_direction dir)
+{
+       dma_unmap_single(dev, addr, size, dir);
+}
 
 /*
  * Rest of this file is part of the "Advanced DMA API".  Use at your own risk.
@@ -115,7 +144,11 @@ static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sgl,
 #define dma_sync_single_range_for_device(dev, dma_handle, offset, size, dir)   \
        dma_sync_single_for_device(dev, dma_handle, size, dir)
 
-#define dma_supported          platform_dma_supported
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+       struct dma_map_ops *ops = platform_dma_get_ops(dev);
+       return ops->dma_supported(dev, mask);
+}
 
 static inline int
 dma_set_mask (struct device *dev, u64 mask)
@@ -141,11 +174,4 @@ dma_cache_sync (struct device *dev, void *vaddr, size_t size,
 
 #define dma_is_consistent(d, h)        (1)     /* all we do is coherent memory... */
 
-static inline struct dma_mapping_ops *get_dma_ops(struct device *dev)
-{
-       return dma_ops;
-}
-
-
-
 #endif /* _ASM_IA64_DMA_MAPPING_H */
index c47830e26cb7dd310af374b9b8ccd60194bef129..111ed52228921cac226a8994e404e3100defb73c 100644 (file)
@@ -202,7 +202,11 @@ extern long ia64_cmpxchg_called_with_bad_pointer (void);
 
 #ifndef __ASSEMBLY__
 #if defined(CONFIG_PARAVIRT) && defined(__KERNEL__)
-#define IA64_INTRINSIC_API(name)       pv_cpu_ops.name
+#ifdef ASM_SUPPORTED
+# define IA64_INTRINSIC_API(name)      paravirt_ ## name
+#else
+# define IA64_INTRINSIC_API(name)      pv_cpu_ops.name
+#endif
 #define IA64_INTRINSIC_MACRO(name)     paravirt_ ## name
 #else
 #define IA64_INTRINSIC_API(name)       ia64_native_ ## name
index fe87b21217077b4765553b59d2a41742ee558562..367d299d99384e1448e9376b1c899af149e0f599 100644 (file)
@@ -11,7 +11,6 @@
 #define _ASM_IA64_MACHVEC_H
 
 #include <linux/types.h>
-#include <linux/swiotlb.h>
 
 /* forward declarations: */
 struct device;
@@ -45,24 +44,8 @@ typedef void ia64_mv_kernel_launch_event_t(void);
 
 /* DMA-mapping interface: */
 typedef void ia64_mv_dma_init (void);
-typedef void *ia64_mv_dma_alloc_coherent (struct device *, size_t, dma_addr_t *, gfp_t);
-typedef void ia64_mv_dma_free_coherent (struct device *, size_t, void *, dma_addr_t);
-typedef dma_addr_t ia64_mv_dma_map_single (struct device *, void *, size_t, int);
-typedef void ia64_mv_dma_unmap_single (struct device *, dma_addr_t, size_t, int);
-typedef int ia64_mv_dma_map_sg (struct device *, struct scatterlist *, int, int);
-typedef void ia64_mv_dma_unmap_sg (struct device *, struct scatterlist *, int, int);
-typedef void ia64_mv_dma_sync_single_for_cpu (struct device *, dma_addr_t, size_t, int);
-typedef void ia64_mv_dma_sync_sg_for_cpu (struct device *, struct scatterlist *, int, int);
-typedef void ia64_mv_dma_sync_single_for_device (struct device *, dma_addr_t, size_t, int);
-typedef void ia64_mv_dma_sync_sg_for_device (struct device *, struct scatterlist *, int, int);
-typedef int ia64_mv_dma_mapping_error(struct device *, dma_addr_t dma_addr);
-typedef int ia64_mv_dma_supported (struct device *, u64);
-
-typedef dma_addr_t ia64_mv_dma_map_single_attrs (struct device *, void *, size_t, int, struct dma_attrs *);
-typedef void ia64_mv_dma_unmap_single_attrs (struct device *, dma_addr_t, size_t, int, struct dma_attrs *);
-typedef int ia64_mv_dma_map_sg_attrs (struct device *, struct scatterlist *, int, int, struct dma_attrs *);
-typedef void ia64_mv_dma_unmap_sg_attrs (struct device *, struct scatterlist *, int, int, struct dma_attrs *);
 typedef u64 ia64_mv_dma_get_required_mask (struct device *);
+typedef struct dma_map_ops *ia64_mv_dma_get_ops(struct device *);
 
 /*
  * WARNING: The legacy I/O space is _architected_.  Platforms are
@@ -114,8 +97,6 @@ machvec_noop_bus (struct pci_bus *bus)
 
 extern void machvec_setup (char **);
 extern void machvec_timer_interrupt (int, void *);
-extern void machvec_dma_sync_single (struct device *, dma_addr_t, size_t, int);
-extern void machvec_dma_sync_sg (struct device *, struct scatterlist *, int, int);
 extern void machvec_tlb_migrate_finish (struct mm_struct *);
 
 # if defined (CONFIG_IA64_HP_SIM)
@@ -148,19 +129,8 @@ extern void machvec_tlb_migrate_finish (struct mm_struct *);
 #  define platform_global_tlb_purge    ia64_mv.global_tlb_purge
 #  define platform_tlb_migrate_finish  ia64_mv.tlb_migrate_finish
 #  define platform_dma_init            ia64_mv.dma_init
-#  define platform_dma_alloc_coherent  ia64_mv.dma_alloc_coherent
-#  define platform_dma_free_coherent   ia64_mv.dma_free_coherent
-#  define platform_dma_map_single_attrs        ia64_mv.dma_map_single_attrs
-#  define platform_dma_unmap_single_attrs      ia64_mv.dma_unmap_single_attrs
-#  define platform_dma_map_sg_attrs    ia64_mv.dma_map_sg_attrs
-#  define platform_dma_unmap_sg_attrs  ia64_mv.dma_unmap_sg_attrs
-#  define platform_dma_sync_single_for_cpu ia64_mv.dma_sync_single_for_cpu
-#  define platform_dma_sync_sg_for_cpu ia64_mv.dma_sync_sg_for_cpu
-#  define platform_dma_sync_single_for_device ia64_mv.dma_sync_single_for_device
-#  define platform_dma_sync_sg_for_device ia64_mv.dma_sync_sg_for_device
-#  define platform_dma_mapping_error           ia64_mv.dma_mapping_error
-#  define platform_dma_supported       ia64_mv.dma_supported
 #  define platform_dma_get_required_mask ia64_mv.dma_get_required_mask
+#  define platform_dma_get_ops         ia64_mv.dma_get_ops
 #  define platform_irq_to_vector       ia64_mv.irq_to_vector
 #  define platform_local_vector_to_irq ia64_mv.local_vector_to_irq
 #  define platform_pci_get_legacy_mem  ia64_mv.pci_get_legacy_mem
@@ -203,19 +173,8 @@ struct ia64_machine_vector {
        ia64_mv_global_tlb_purge_t *global_tlb_purge;
        ia64_mv_tlb_migrate_finish_t *tlb_migrate_finish;
        ia64_mv_dma_init *dma_init;
-       ia64_mv_dma_alloc_coherent *dma_alloc_coherent;
-       ia64_mv_dma_free_coherent *dma_free_coherent;
-       ia64_mv_dma_map_single_attrs *dma_map_single_attrs;
-       ia64_mv_dma_unmap_single_attrs *dma_unmap_single_attrs;
-       ia64_mv_dma_map_sg_attrs *dma_map_sg_attrs;
-       ia64_mv_dma_unmap_sg_attrs *dma_unmap_sg_attrs;
-       ia64_mv_dma_sync_single_for_cpu *dma_sync_single_for_cpu;
-       ia64_mv_dma_sync_sg_for_cpu *dma_sync_sg_for_cpu;
-       ia64_mv_dma_sync_single_for_device *dma_sync_single_for_device;
-       ia64_mv_dma_sync_sg_for_device *dma_sync_sg_for_device;
-       ia64_mv_dma_mapping_error *dma_mapping_error;
-       ia64_mv_dma_supported *dma_supported;
        ia64_mv_dma_get_required_mask *dma_get_required_mask;
+       ia64_mv_dma_get_ops *dma_get_ops;
        ia64_mv_irq_to_vector *irq_to_vector;
        ia64_mv_local_vector_to_irq *local_vector_to_irq;
        ia64_mv_pci_get_legacy_mem_t *pci_get_legacy_mem;
@@ -254,19 +213,8 @@ struct ia64_machine_vector {
        platform_global_tlb_purge,              \
        platform_tlb_migrate_finish,            \
        platform_dma_init,                      \
-       platform_dma_alloc_coherent,            \
-       platform_dma_free_coherent,             \
-       platform_dma_map_single_attrs,          \
-       platform_dma_unmap_single_attrs,        \
-       platform_dma_map_sg_attrs,              \
-       platform_dma_unmap_sg_attrs,            \
-       platform_dma_sync_single_for_cpu,       \
-       platform_dma_sync_sg_for_cpu,           \
-       platform_dma_sync_single_for_device,    \
-       platform_dma_sync_sg_for_device,        \
-       platform_dma_mapping_error,                     \
-       platform_dma_supported,                 \
        platform_dma_get_required_mask,         \
+       platform_dma_get_ops,                   \
        platform_irq_to_vector,                 \
        platform_local_vector_to_irq,           \
        platform_pci_get_legacy_mem,            \
@@ -302,6 +250,9 @@ extern void machvec_init_from_cmdline(const char *cmdline);
 #  error Unknown configuration.  Update arch/ia64/include/asm/machvec.h.
 # endif /* CONFIG_IA64_GENERIC */
 
+extern void swiotlb_dma_init(void);
+extern struct dma_map_ops *dma_get_ops(struct device *);
+
 /*
  * Define default versions so we can extend machvec for new platforms without having
  * to update the machvec files for all existing platforms.
@@ -332,43 +283,10 @@ extern void machvec_init_from_cmdline(const char *cmdline);
 # define platform_kernel_launch_event  machvec_noop
 #endif
 #ifndef platform_dma_init
-# define platform_dma_init             swiotlb_init
-#endif
-#ifndef platform_dma_alloc_coherent
-# define platform_dma_alloc_coherent   swiotlb_alloc_coherent
-#endif
-#ifndef platform_dma_free_coherent
-# define platform_dma_free_coherent    swiotlb_free_coherent
-#endif
-#ifndef platform_dma_map_single_attrs
-# define platform_dma_map_single_attrs swiotlb_map_single_attrs
-#endif
-#ifndef platform_dma_unmap_single_attrs
-# define platform_dma_unmap_single_attrs       swiotlb_unmap_single_attrs
-#endif
-#ifndef platform_dma_map_sg_attrs
-# define platform_dma_map_sg_attrs     swiotlb_map_sg_attrs
-#endif
-#ifndef platform_dma_unmap_sg_attrs
-# define platform_dma_unmap_sg_attrs   swiotlb_unmap_sg_attrs
-#endif
-#ifndef platform_dma_sync_single_for_cpu
-# define platform_dma_sync_single_for_cpu      swiotlb_sync_single_for_cpu
-#endif
-#ifndef platform_dma_sync_sg_for_cpu
-# define platform_dma_sync_sg_for_cpu          swiotlb_sync_sg_for_cpu
-#endif
-#ifndef platform_dma_sync_single_for_device
-# define platform_dma_sync_single_for_device   swiotlb_sync_single_for_device
-#endif
-#ifndef platform_dma_sync_sg_for_device
-# define platform_dma_sync_sg_for_device       swiotlb_sync_sg_for_device
-#endif
-#ifndef platform_dma_mapping_error
-# define platform_dma_mapping_error            swiotlb_dma_mapping_error
+# define platform_dma_init             swiotlb_dma_init
 #endif
-#ifndef platform_dma_supported
-# define  platform_dma_supported       swiotlb_dma_supported
+#ifndef platform_dma_get_ops
+# define platform_dma_get_ops          dma_get_ops
 #endif
 #ifndef platform_dma_get_required_mask
 # define  platform_dma_get_required_mask       ia64_dma_get_required_mask
index 3400b561e711b63820429702b8710025c98b35cc..6ab1de5c45efe74b9e86e542f6b066578e2aa751 100644 (file)
@@ -2,14 +2,6 @@
 #define _ASM_IA64_MACHVEC_DIG_VTD_h
 
 extern ia64_mv_setup_t                 dig_setup;
-extern ia64_mv_dma_alloc_coherent      vtd_alloc_coherent;
-extern ia64_mv_dma_free_coherent       vtd_free_coherent;
-extern ia64_mv_dma_map_single_attrs    vtd_map_single_attrs;
-extern ia64_mv_dma_unmap_single_attrs  vtd_unmap_single_attrs;
-extern ia64_mv_dma_map_sg_attrs                vtd_map_sg_attrs;
-extern ia64_mv_dma_unmap_sg_attrs      vtd_unmap_sg_attrs;
-extern ia64_mv_dma_supported           iommu_dma_supported;
-extern ia64_mv_dma_mapping_error       vtd_dma_mapping_error;
 extern ia64_mv_dma_init                        pci_iommu_alloc;
 
 /*
@@ -22,17 +14,5 @@ extern ia64_mv_dma_init                      pci_iommu_alloc;
 #define platform_name                          "dig_vtd"
 #define platform_setup                         dig_setup
 #define platform_dma_init                      pci_iommu_alloc
-#define platform_dma_alloc_coherent            vtd_alloc_coherent
-#define platform_dma_free_coherent             vtd_free_coherent
-#define platform_dma_map_single_attrs          vtd_map_single_attrs
-#define platform_dma_unmap_single_attrs                vtd_unmap_single_attrs
-#define platform_dma_map_sg_attrs              vtd_map_sg_attrs
-#define platform_dma_unmap_sg_attrs            vtd_unmap_sg_attrs
-#define platform_dma_sync_single_for_cpu       machvec_dma_sync_single
-#define platform_dma_sync_sg_for_cpu           machvec_dma_sync_sg
-#define platform_dma_sync_single_for_device    machvec_dma_sync_single
-#define platform_dma_sync_sg_for_device                machvec_dma_sync_sg
-#define platform_dma_supported                 iommu_dma_supported
-#define platform_dma_mapping_error             vtd_dma_mapping_error
 
 #endif /* _ASM_IA64_MACHVEC_DIG_VTD_h */
index 2f57f5144b9fbc55363734d0dbf0920bac497fa6..3bd83d78a412047099be119a2fa1b3094d767f47 100644 (file)
@@ -2,14 +2,7 @@
 #define _ASM_IA64_MACHVEC_HPZX1_h
 
 extern ia64_mv_setup_t                 dig_setup;
-extern ia64_mv_dma_alloc_coherent      sba_alloc_coherent;
-extern ia64_mv_dma_free_coherent       sba_free_coherent;
-extern ia64_mv_dma_map_single_attrs    sba_map_single_attrs;
-extern ia64_mv_dma_unmap_single_attrs  sba_unmap_single_attrs;
-extern ia64_mv_dma_map_sg_attrs                sba_map_sg_attrs;
-extern ia64_mv_dma_unmap_sg_attrs      sba_unmap_sg_attrs;
-extern ia64_mv_dma_supported           sba_dma_supported;
-extern ia64_mv_dma_mapping_error       sba_dma_mapping_error;
+extern ia64_mv_dma_init                        sba_dma_init;
 
 /*
  * This stuff has dual use!
@@ -20,18 +13,6 @@ extern ia64_mv_dma_mapping_error     sba_dma_mapping_error;
  */
 #define platform_name                          "hpzx1"
 #define platform_setup                         dig_setup
-#define platform_dma_init                      machvec_noop
-#define platform_dma_alloc_coherent            sba_alloc_coherent
-#define platform_dma_free_coherent             sba_free_coherent
-#define platform_dma_map_single_attrs          sba_map_single_attrs
-#define platform_dma_unmap_single_attrs                sba_unmap_single_attrs
-#define platform_dma_map_sg_attrs              sba_map_sg_attrs
-#define platform_dma_unmap_sg_attrs            sba_unmap_sg_attrs
-#define platform_dma_sync_single_for_cpu       machvec_dma_sync_single
-#define platform_dma_sync_sg_for_cpu           machvec_dma_sync_sg
-#define platform_dma_sync_single_for_device    machvec_dma_sync_single
-#define platform_dma_sync_sg_for_device                machvec_dma_sync_sg
-#define platform_dma_supported                 sba_dma_supported
-#define platform_dma_mapping_error             sba_dma_mapping_error
+#define platform_dma_init                      sba_dma_init
 
 #endif /* _ASM_IA64_MACHVEC_HPZX1_h */
index a842cdda827bd8203f95d4e367e1a8eed47d8764..1091ac39740c6c407c35bb43e8d511eea2aafb02 100644 (file)
@@ -2,18 +2,7 @@
 #define _ASM_IA64_MACHVEC_HPZX1_SWIOTLB_h
 
 extern ia64_mv_setup_t                         dig_setup;
-extern ia64_mv_dma_alloc_coherent              hwsw_alloc_coherent;
-extern ia64_mv_dma_free_coherent               hwsw_free_coherent;
-extern ia64_mv_dma_map_single_attrs            hwsw_map_single_attrs;
-extern ia64_mv_dma_unmap_single_attrs          hwsw_unmap_single_attrs;
-extern ia64_mv_dma_map_sg_attrs                        hwsw_map_sg_attrs;
-extern ia64_mv_dma_unmap_sg_attrs              hwsw_unmap_sg_attrs;
-extern ia64_mv_dma_supported                   hwsw_dma_supported;
-extern ia64_mv_dma_mapping_error               hwsw_dma_mapping_error;
-extern ia64_mv_dma_sync_single_for_cpu         hwsw_sync_single_for_cpu;
-extern ia64_mv_dma_sync_sg_for_cpu             hwsw_sync_sg_for_cpu;
-extern ia64_mv_dma_sync_single_for_device      hwsw_sync_single_for_device;
-extern ia64_mv_dma_sync_sg_for_device          hwsw_sync_sg_for_device;
+extern ia64_mv_dma_get_ops                     hwsw_dma_get_ops;
 
 /*
  * This stuff has dual use!
@@ -23,20 +12,8 @@ extern ia64_mv_dma_sync_sg_for_device                hwsw_sync_sg_for_device;
  * the macros are used directly.
  */
 #define platform_name                          "hpzx1_swiotlb"
-
 #define platform_setup                         dig_setup
 #define platform_dma_init                      machvec_noop
-#define platform_dma_alloc_coherent            hwsw_alloc_coherent
-#define platform_dma_free_coherent             hwsw_free_coherent
-#define platform_dma_map_single_attrs          hwsw_map_single_attrs
-#define platform_dma_unmap_single_attrs                hwsw_unmap_single_attrs
-#define platform_dma_map_sg_attrs              hwsw_map_sg_attrs
-#define platform_dma_unmap_sg_attrs            hwsw_unmap_sg_attrs
-#define platform_dma_supported                 hwsw_dma_supported
-#define platform_dma_mapping_error             hwsw_dma_mapping_error
-#define platform_dma_sync_single_for_cpu       hwsw_sync_single_for_cpu
-#define platform_dma_sync_sg_for_cpu           hwsw_sync_sg_for_cpu
-#define platform_dma_sync_single_for_device    hwsw_sync_single_for_device
-#define platform_dma_sync_sg_for_device                hwsw_sync_sg_for_device
+#define platform_dma_get_ops                   hwsw_dma_get_ops
 
 #endif /* _ASM_IA64_MACHVEC_HPZX1_SWIOTLB_h */
index f1a6e0d6dfa582c1533e2b66f3a8cfb6744b5233..f061a30aac42c7b297434d0ec88ae0f5d348f5ee 100644 (file)
@@ -55,19 +55,8 @@ extern ia64_mv_readb_t __sn_readb_relaxed;
 extern ia64_mv_readw_t __sn_readw_relaxed;
 extern ia64_mv_readl_t __sn_readl_relaxed;
 extern ia64_mv_readq_t __sn_readq_relaxed;
-extern ia64_mv_dma_alloc_coherent      sn_dma_alloc_coherent;
-extern ia64_mv_dma_free_coherent       sn_dma_free_coherent;
-extern ia64_mv_dma_map_single_attrs    sn_dma_map_single_attrs;
-extern ia64_mv_dma_unmap_single_attrs  sn_dma_unmap_single_attrs;
-extern ia64_mv_dma_map_sg_attrs                sn_dma_map_sg_attrs;
-extern ia64_mv_dma_unmap_sg_attrs      sn_dma_unmap_sg_attrs;
-extern ia64_mv_dma_sync_single_for_cpu sn_dma_sync_single_for_cpu;
-extern ia64_mv_dma_sync_sg_for_cpu     sn_dma_sync_sg_for_cpu;
-extern ia64_mv_dma_sync_single_for_device sn_dma_sync_single_for_device;
-extern ia64_mv_dma_sync_sg_for_device  sn_dma_sync_sg_for_device;
-extern ia64_mv_dma_mapping_error       sn_dma_mapping_error;
-extern ia64_mv_dma_supported           sn_dma_supported;
 extern ia64_mv_dma_get_required_mask   sn_dma_get_required_mask;
+extern ia64_mv_dma_init                        sn_dma_init;
 extern ia64_mv_migrate_t               sn_migrate;
 extern ia64_mv_kernel_launch_event_t   sn_kernel_launch_event;
 extern ia64_mv_setup_msi_irq_t         sn_setup_msi_irq;
@@ -111,20 +100,8 @@ extern ia64_mv_pci_fixup_bus_t             sn_pci_fixup_bus;
 #define platform_pci_get_legacy_mem    sn_pci_get_legacy_mem
 #define platform_pci_legacy_read       sn_pci_legacy_read
 #define platform_pci_legacy_write      sn_pci_legacy_write
-#define platform_dma_init              machvec_noop
-#define platform_dma_alloc_coherent    sn_dma_alloc_coherent
-#define platform_dma_free_coherent     sn_dma_free_coherent
-#define platform_dma_map_single_attrs  sn_dma_map_single_attrs
-#define platform_dma_unmap_single_attrs        sn_dma_unmap_single_attrs
-#define platform_dma_map_sg_attrs      sn_dma_map_sg_attrs
-#define platform_dma_unmap_sg_attrs    sn_dma_unmap_sg_attrs
-#define platform_dma_sync_single_for_cpu sn_dma_sync_single_for_cpu
-#define platform_dma_sync_sg_for_cpu   sn_dma_sync_sg_for_cpu
-#define platform_dma_sync_single_for_device sn_dma_sync_single_for_device
-#define platform_dma_sync_sg_for_device        sn_dma_sync_sg_for_device
-#define platform_dma_mapping_error             sn_dma_mapping_error
-#define platform_dma_supported         sn_dma_supported
 #define platform_dma_get_required_mask sn_dma_get_required_mask
+#define platform_dma_init              sn_dma_init
 #define platform_migrate               sn_migrate
 #define platform_kernel_launch_event    sn_kernel_launch_event
 #ifdef CONFIG_PCI_MSI
index 040bc87db9304766b5379abefcd563c25aa3c01c..7f2a456603cbf52d8d9af527b67e459c1e4eb740 100644 (file)
@@ -87,7 +87,7 @@ get_mmu_context (struct mm_struct *mm)
        /* re-check, now that we've got the lock: */
        context = mm->context;
        if (context == 0) {
-               cpus_clear(mm->cpu_vm_mask);
+               cpumask_clear(mm_cpumask(mm));
                if (ia64_ctx.next >= ia64_ctx.limit) {
                        ia64_ctx.next = find_next_zero_bit(ia64_ctx.bitmap,
                                        ia64_ctx.max_ctx, ia64_ctx.next);
@@ -166,8 +166,8 @@ activate_context (struct mm_struct *mm)
 
        do {
                context = get_mmu_context(mm);
-               if (!cpu_isset(smp_processor_id(), mm->cpu_vm_mask))
-                       cpu_set(smp_processor_id(), mm->cpu_vm_mask);
+               if (!cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm)))
+                       cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
                reload_context(context);
                /*
                 * in the unlikely event of a TLB-flush by another thread,
index d2da61e4c49bb690021e332f38bace45d3a1e4b7..908eaef42a08d1dfd9451b55cf9852f61faaab80 100644 (file)
@@ -16,6 +16,12 @@ struct mod_arch_specific {
        struct elf64_shdr *got;         /* global offset table */
        struct elf64_shdr *opd;         /* official procedure descriptors */
        struct elf64_shdr *unwind;      /* unwind-table section */
+#ifdef CONFIG_PARAVIRT
+       struct elf64_shdr *paravirt_bundles;
+                                       /* paravirt_alt_bundle_patch table */
+       struct elf64_shdr *paravirt_insts;
+                                       /* paravirt_alt_inst_patch table */
+#endif
        unsigned long gp;               /* global-pointer for module */
 
        void *core_unw_table;           /* core unwind-table cookie returned by unwinder */
index 0a1026cca4fab0bd68d4ca1158dfb3466c580729..d2d46efb3e6e83888e4f53910439b15794076785 100644 (file)
@@ -30,6 +30,9 @@
 #define __paravirt_work_processed_syscall_target \
                                                ia64_work_processed_syscall
 
+#define paravirt_fsyscall_table                        ia64_native_fsyscall_table
+#define paravirt_fsys_bubble_down              ia64_native_fsys_bubble_down
+
 #ifdef CONFIG_PARAVIRT_GUEST_ASM_CLOBBER_CHECK
 # define PARAVIRT_POISON       0xdeadbeefbaadf00d
 # define CLOBBER(clob)                         \
 (pred) mov reg = psr                   \
        CLOBBER(clob)
 
+#define MOV_FROM_ITC(pred, pred_clob, reg, clob)       \
+(pred) mov reg = ar.itc                                \
+       CLOBBER(clob)                                   \
+       CLOBBER_PRED(pred_clob)
+
 #define MOV_TO_IFA(reg, clob)  \
        mov cr.ifa = reg        \
        CLOBBER(clob)
 #define RSM_PSR_DT             \
        rsm psr.dt
 
+#define RSM_PSR_BE_I(clob0, clob1)     \
+       rsm psr.be | psr.i              \
+       CLOBBER(clob0)                  \
+       CLOBBER(clob1)
+
 #define SSM_PSR_DT_AND_SRLZ_I  \
        ssm psr.dt              \
        ;;                      \
diff --git a/arch/ia64/include/asm/native/patchlist.h b/arch/ia64/include/asm/native/patchlist.h
new file mode 100644 (file)
index 0000000..be16ca9
--- /dev/null
@@ -0,0 +1,38 @@
+/******************************************************************************
+ * arch/ia64/include/asm/native/inst.h
+ *
+ * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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
+ *
+ */
+
+#define __paravirt_start_gate_fsyscall_patchlist               \
+       __ia64_native_start_gate_fsyscall_patchlist
+#define __paravirt_end_gate_fsyscall_patchlist                 \
+       __ia64_native_end_gate_fsyscall_patchlist
+#define __paravirt_start_gate_brl_fsys_bubble_down_patchlist   \
+       __ia64_native_start_gate_brl_fsys_bubble_down_patchlist
+#define __paravirt_end_gate_brl_fsys_bubble_down_patchlist     \
+       __ia64_native_end_gate_brl_fsys_bubble_down_patchlist
+#define __paravirt_start_gate_vtop_patchlist                   \
+       __ia64_native_start_gate_vtop_patchlist
+#define __paravirt_end_gate_vtop_patchlist                     \
+       __ia64_native_end_gate_vtop_patchlist
+#define __paravirt_start_gate_mckinley_e9_patchlist            \
+       __ia64_native_start_gate_mckinley_e9_patchlist
+#define __paravirt_end_gate_mckinley_e9_patchlist              \
+       __ia64_native_end_gate_mckinley_e9_patchlist
index b8e6eb1090d77f2f62be6463da22f3db4d5dba57..8d72962ec8383b8d77ba65c4cbdaa4aec271518c 100644 (file)
        IS_PRED_IN(pred)                        \
        IS_RREG_OUT(reg)                        \
        IS_RREG_CLOB(clob)
+#define MOV_FROM_ITC(pred, pred_clob, reg, clob)       \
+       IS_PRED_IN(pred)                                \
+       IS_PRED_CLOB(pred_clob)                         \
+       IS_RREG_OUT(reg)                                \
+       IS_RREG_CLOB(clob)
 #define MOV_TO_IFA(reg, clob)                  \
        IS_RREG_IN(reg)                         \
        IS_RREG_CLOB(clob)
        IS_RREG_CLOB(clob2)
 #define RSM_PSR_DT                             \
        nop 0
+#define RSM_PSR_BE_I(clob0, clob1)             \
+       IS_RREG_CLOB(clob0)                     \
+       IS_RREG_CLOB(clob1)
 #define SSM_PSR_DT_AND_SRLZ_I                  \
        nop 0
 #define BSW_0(clob0, clob1, clob2)             \
index 2bf3636473fe9c5b826b53488f00ff4aa5a1f33b..2eb0a981a09a8adcbf1302915f085ad08c721b91 100644 (file)
 #ifndef __ASM_PARAVIRT_H
 #define __ASM_PARAVIRT_H
 
+#ifndef __ASSEMBLY__
+/******************************************************************************
+ * fsys related addresses
+ */
+struct pv_fsys_data {
+       unsigned long *fsyscall_table;
+       void *fsys_bubble_down;
+};
+
+extern struct pv_fsys_data pv_fsys_data;
+
+unsigned long *paravirt_get_fsyscall_table(void);
+char *paravirt_get_fsys_bubble_down(void);
+
+/******************************************************************************
+ * patchlist addresses for gate page
+ */
+enum pv_gate_patchlist {
+       PV_GATE_START_FSYSCALL,
+       PV_GATE_END_FSYSCALL,
+
+       PV_GATE_START_BRL_FSYS_BUBBLE_DOWN,
+       PV_GATE_END_BRL_FSYS_BUBBLE_DOWN,
+
+       PV_GATE_START_VTOP,
+       PV_GATE_END_VTOP,
+
+       PV_GATE_START_MCKINLEY_E9,
+       PV_GATE_END_MCKINLEY_E9,
+};
+
+struct pv_patchdata {
+       unsigned long start_fsyscall_patchlist;
+       unsigned long end_fsyscall_patchlist;
+       unsigned long start_brl_fsys_bubble_down_patchlist;
+       unsigned long end_brl_fsys_bubble_down_patchlist;
+       unsigned long start_vtop_patchlist;
+       unsigned long end_vtop_patchlist;
+       unsigned long start_mckinley_e9_patchlist;
+       unsigned long end_mckinley_e9_patchlist;
+
+       void *gate_section;
+};
+
+extern struct pv_patchdata pv_patchdata;
+
+unsigned long paravirt_get_gate_patchlist(enum pv_gate_patchlist type);
+void *paravirt_get_gate_section(void);
+#endif
+
 #ifdef CONFIG_PARAVIRT_GUEST
 
 #define PARAVIRT_HYPERVISOR_TYPE_DEFAULT       0
@@ -68,6 +118,14 @@ struct pv_init_ops {
        int (*arch_setup_nomca)(void);
 
        void (*post_smp_prepare_boot_cpu)(void);
+
+#ifdef ASM_SUPPORTED
+       unsigned long (*patch_bundle)(void *sbundle, void *ebundle,
+                                     unsigned long type);
+       unsigned long (*patch_inst)(unsigned long stag, unsigned long etag,
+                                   unsigned long type);
+#endif
+       void (*patch_branch)(unsigned long tag, unsigned long type);
 };
 
 extern struct pv_init_ops pv_init_ops;
@@ -210,6 +268,8 @@ struct pv_time_ops {
        int (*do_steal_accounting)(unsigned long *new_itm);
 
        void (*clocksource_resume)(void);
+
+       unsigned long long (*sched_clock)(void);
 };
 
 extern struct pv_time_ops pv_time_ops;
@@ -227,6 +287,11 @@ paravirt_do_steal_accounting(unsigned long *new_itm)
        return pv_time_ops.do_steal_accounting(new_itm);
 }
 
+static inline unsigned long long paravirt_sched_clock(void)
+{
+       return pv_time_ops.sched_clock();
+}
+
 #endif /* !__ASSEMBLY__ */
 
 #else
diff --git a/arch/ia64/include/asm/paravirt_patch.h b/arch/ia64/include/asm/paravirt_patch.h
new file mode 100644 (file)
index 0000000..128ff5d
--- /dev/null
@@ -0,0 +1,143 @@
+/******************************************************************************
+ * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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 __ASM_PARAVIRT_PATCH_H
+#define __ASM_PARAVIRT_PATCH_H
+
+#ifdef __ASSEMBLY__
+
+       .section .paravirt_branches, "a"
+       .previous
+#define PARAVIRT_PATCH_SITE_BR(type)           \
+       {                                       \
+       [1:] ;                                  \
+       br.cond.sptk.many 2f ;                  \
+       nop.b 0 ;                               \
+       nop.b 0;; ;                             \
+       } ;                                     \
+       2:                                      \
+       .xdata8 ".paravirt_branches", 1b, type
+
+#else
+
+#include <linux/stringify.h>
+#include <asm/intrinsics.h>
+
+/* for binary patch */
+struct paravirt_patch_site_bundle {
+       void            *sbundle;
+       void            *ebundle;
+       unsigned long   type;
+};
+
+/* label means the beginning of new bundle */
+#define paravirt_alt_bundle(instr, privop)                             \
+       "\t998:\n"                                                      \
+       "\t" instr "\n"                                                 \
+       "\t999:\n"                                                      \
+       "\t.pushsection .paravirt_bundles, \"a\"\n"                     \
+       "\t.popsection\n"                                               \
+       "\t.xdata8 \".paravirt_bundles\", 998b, 999b, "                 \
+       __stringify(privop) "\n"
+
+
+struct paravirt_patch_bundle_elem {
+       const void      *sbundle;
+       const void      *ebundle;
+       unsigned long   type;
+};
+
+
+struct paravirt_patch_site_inst {
+       unsigned long   stag;
+       unsigned long   etag;
+       unsigned long   type;
+};
+
+#define paravirt_alt_inst(instr, privop)                               \
+       "\t[998:]\n"                                                    \
+       "\t" instr "\n"                                                 \
+       "\t[999:]\n"                                                    \
+       "\t.pushsection .paravirt_insts, \"a\"\n"                       \
+       "\t.popsection\n"                                               \
+       "\t.xdata8 \".paravirt_insts\", 998b, 999b, "                   \
+       __stringify(privop) "\n"
+
+struct paravirt_patch_site_branch {
+       unsigned long   tag;
+       unsigned long   type;
+};
+
+struct paravirt_patch_branch_target {
+       const void      *entry;
+       unsigned long   type;
+};
+
+void
+__paravirt_patch_apply_branch(
+       unsigned long tag, unsigned long type,
+       const struct paravirt_patch_branch_target *entries,
+       unsigned int nr_entries);
+
+void
+paravirt_patch_reloc_br(unsigned long tag, const void *target);
+
+void
+paravirt_patch_reloc_brl(unsigned long tag, const void *target);
+
+
+#if defined(ASM_SUPPORTED) && defined(CONFIG_PARAVIRT)
+unsigned long
+ia64_native_patch_bundle(void *sbundle, void *ebundle, unsigned long type);
+
+unsigned long
+__paravirt_patch_apply_bundle(void *sbundle, void *ebundle, unsigned long type,
+                             const struct paravirt_patch_bundle_elem *elems,
+                             unsigned long nelems,
+                             const struct paravirt_patch_bundle_elem **found);
+
+void
+paravirt_patch_apply_bundle(const struct paravirt_patch_site_bundle *start,
+                           const struct paravirt_patch_site_bundle *end);
+
+void
+paravirt_patch_apply_inst(const struct paravirt_patch_site_inst *start,
+                         const struct paravirt_patch_site_inst *end);
+
+void paravirt_patch_apply(void);
+#else
+#define paravirt_patch_apply_bundle(start, end)        do { } while (0)
+#define paravirt_patch_apply_inst(start, end)  do { } while (0)
+#define paravirt_patch_apply()                 do { } while (0)
+#endif
+
+#endif /* !__ASSEMBLEY__ */
+
+#endif /* __ASM_PARAVIRT_PATCH_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "linux"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ */
index 33c8e55f5775f7e12330ffe8e37e61568f937f00..3d2951130b5ff94ca3d05e434100e1b0918bbb95 100644 (file)
@@ -33,7 +33,7 @@
  */
 
 struct pv_cpu_ops {
-       void (*fc)(unsigned long addr);
+       void (*fc)(void *addr);
        unsigned long (*thash)(unsigned long addr);
        unsigned long (*get_cpuid)(int index);
        unsigned long (*get_pmd)(int index);
@@ -60,12 +60,18 @@ extern unsigned long ia64_native_getreg_func(int regnum);
 /* Instructions paravirtualized for performance */
 /************************************************/
 
+#ifndef ASM_SUPPORTED
+#define paravirt_ssm_i()       pv_cpu_ops.ssm_i()
+#define paravirt_rsm_i()       pv_cpu_ops.rsm_i()
+#define __paravirt_getreg()    pv_cpu_ops.getreg()
+#endif
+
 /* mask for ia64_native_ssm/rsm() must be constant.("i" constraing).
  * static inline function doesn't satisfy it. */
 #define paravirt_ssm(mask)                     \
        do {                                    \
                if ((mask) == IA64_PSR_I)       \
-                       pv_cpu_ops.ssm_i();     \
+                       paravirt_ssm_i();       \
                else                            \
                        ia64_native_ssm(mask);  \
        } while (0)
@@ -73,7 +79,7 @@ extern unsigned long ia64_native_getreg_func(int regnum);
 #define paravirt_rsm(mask)                     \
        do {                                    \
                if ((mask) == IA64_PSR_I)       \
-                       pv_cpu_ops.rsm_i();     \
+                       paravirt_rsm_i();       \
                else                            \
                        ia64_native_rsm(mask);  \
        } while (0)
@@ -86,7 +92,7 @@ extern unsigned long ia64_native_getreg_func(int regnum);
                if ((reg) == _IA64_REG_IP)                      \
                        res = ia64_native_getreg(_IA64_REG_IP); \
                else                                            \
-                       res = pv_cpu_ops.getreg(reg);           \
+                       res = __paravirt_getreg(reg);           \
                res;                                            \
        })
 
@@ -112,6 +118,12 @@ void paravirt_cpu_asm_init(const struct pv_cpu_asm_switch *cpu_asm_switch);
 
 #endif /* CONFIG_PARAVIRT */
 
+#if defined(CONFIG_PARAVIRT) && defined(ASM_SUPPORTED)
+#define paravirt_dv_serialize_data()   ia64_dv_serialize_data()
+#else
+#define paravirt_dv_serialize_data()   /* nothing */
+#endif
+
 /* these routines utilize privilege-sensitive or performance-sensitive
  * privileged instructions so the code must be replaced with
  * paravirtualized versions */
@@ -121,4 +133,349 @@ void paravirt_cpu_asm_init(const struct pv_cpu_asm_switch *cpu_asm_switch);
        IA64_PARAVIRT_ASM_FUNC(work_processed_syscall)
 #define ia64_leave_kernel              IA64_PARAVIRT_ASM_FUNC(leave_kernel)
 
+
+#if defined(CONFIG_PARAVIRT)
+/******************************************************************************
+ * binary patching infrastructure
+ */
+#define PARAVIRT_PATCH_TYPE_FC                         1
+#define PARAVIRT_PATCH_TYPE_THASH                      2
+#define PARAVIRT_PATCH_TYPE_GET_CPUID                  3
+#define PARAVIRT_PATCH_TYPE_GET_PMD                    4
+#define PARAVIRT_PATCH_TYPE_PTCGA                      5
+#define PARAVIRT_PATCH_TYPE_GET_RR                     6
+#define PARAVIRT_PATCH_TYPE_SET_RR                     7
+#define PARAVIRT_PATCH_TYPE_SET_RR0_TO_RR4             8
+#define PARAVIRT_PATCH_TYPE_SSM_I                      9
+#define PARAVIRT_PATCH_TYPE_RSM_I                      10
+#define PARAVIRT_PATCH_TYPE_GET_PSR_I                  11
+#define PARAVIRT_PATCH_TYPE_INTRIN_LOCAL_IRQ_RESTORE   12
+
+/* PARAVIRT_PATY_TYPE_[GS]ETREG + _IA64_REG_xxx */
+#define PARAVIRT_PATCH_TYPE_GETREG                     0x10000000
+#define PARAVIRT_PATCH_TYPE_SETREG                     0x20000000
+
+/*
+ * struct task_struct* (*ia64_switch_to)(void* next_task);
+ * void *ia64_leave_syscall;
+ * void *ia64_work_processed_syscall
+ * void *ia64_leave_kernel;
+ */
+
+#define PARAVIRT_PATCH_TYPE_BR_START                   0x30000000
+#define PARAVIRT_PATCH_TYPE_BR_SWITCH_TO               \
+       (PARAVIRT_PATCH_TYPE_BR_START + 0)
+#define PARAVIRT_PATCH_TYPE_BR_LEAVE_SYSCALL           \
+       (PARAVIRT_PATCH_TYPE_BR_START + 1)
+#define PARAVIRT_PATCH_TYPE_BR_WORK_PROCESSED_SYSCALL  \
+       (PARAVIRT_PATCH_TYPE_BR_START + 2)
+#define PARAVIRT_PATCH_TYPE_BR_LEAVE_KERNEL            \
+       (PARAVIRT_PATCH_TYPE_BR_START + 3)
+
+#ifdef ASM_SUPPORTED
+#include <asm/paravirt_patch.h>
+
+/*
+ * pv_cpu_ops calling stub.
+ * normal function call convension can't be written by gcc
+ * inline assembly.
+ *
+ * from the caller's point of view,
+ * the following registers will be clobbered.
+ * r2, r3
+ * r8-r15
+ * r16, r17
+ * b6, b7
+ * p6-p15
+ * ar.ccv
+ *
+ * from the callee's point of view ,
+ * the following registers can be used.
+ * r2, r3: scratch
+ * r8: scratch, input argument0 and return value
+ * r0-r15: scratch, input argument1-5
+ * b6: return pointer
+ * b7: scratch
+ * p6-p15: scratch
+ * ar.ccv: scratch
+ *
+ * other registers must not be changed. especially
+ * b0: rp: preserved. gcc ignores b0 in clobbered register.
+ * r16: saved gp
+ */
+/* 5 bundles */
+#define __PARAVIRT_BR                                                  \
+       ";;\n"                                                          \
+       "{ .mlx\n"                                                      \
+       "nop 0\n"                                                       \
+       "movl r2 = %[op_addr]\n"/* get function pointer address */      \
+       ";;\n"                                                          \
+       "}\n"                                                           \
+       "1:\n"                                                          \
+       "{ .mii\n"                                                      \
+       "ld8 r2 = [r2]\n"       /* load function descriptor address */  \
+       "mov r17 = ip\n"        /* get ip to calc return address */     \
+       "mov r16 = gp\n"        /* save gp */                           \
+       ";;\n"                                                          \
+       "}\n"                                                           \
+       "{ .mii\n"                                                      \
+       "ld8 r3 = [r2], 8\n"    /* load entry address */                \
+       "adds r17 =  1f - 1b, r17\n"    /* calculate return address */  \
+       ";;\n"                                                          \
+       "mov b7 = r3\n"         /* set entry address */                 \
+       "}\n"                                                           \
+       "{ .mib\n"                                                      \
+       "ld8 gp = [r2]\n"       /* load gp value */                     \
+       "mov b6 = r17\n"        /* set return address */                \
+       "br.cond.sptk.few b7\n" /* intrinsics are very short isns */    \
+       "}\n"                                                           \
+       "1:\n"                                                          \
+       "{ .mii\n"                                                      \
+       "mov gp = r16\n"        /* restore gp value */                  \
+       "nop 0\n"                                                       \
+       "nop 0\n"                                                       \
+       ";;\n"                                                          \
+       "}\n"
+
+#define PARAVIRT_OP(op)                                \
+       [op_addr] "i"(&pv_cpu_ops.op)
+
+#define PARAVIRT_TYPE(type)                    \
+       PARAVIRT_PATCH_TYPE_ ## type
+
+#define PARAVIRT_REG_CLOBBERS0                                 \
+       "r2", "r3", /*"r8",*/ "r9", "r10", "r11", "r14",        \
+               "r15", "r16", "r17"
+
+#define PARAVIRT_REG_CLOBBERS1                                 \
+       "r2","r3", /*"r8",*/ "r9", "r10", "r11", "r14",         \
+               "r15", "r16", "r17"
+
+#define PARAVIRT_REG_CLOBBERS2                                 \
+       "r2", "r3", /*"r8", "r9",*/ "r10", "r11", "r14",        \
+               "r15", "r16", "r17"
+
+#define PARAVIRT_REG_CLOBBERS5                                 \
+       "r2", "r3", /*"r8", "r9", "r10", "r11", "r14",*/        \
+               "r15", "r16", "r17"
+
+#define PARAVIRT_BR_CLOBBERS                   \
+       "b6", "b7"
+
+#define PARAVIRT_PR_CLOBBERS                                           \
+       "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15"
+
+#define PARAVIRT_AR_CLOBBERS                   \
+       "ar.ccv"
+
+#define PARAVIRT_CLOBBERS0                     \
+               PARAVIRT_REG_CLOBBERS0,         \
+               PARAVIRT_BR_CLOBBERS,           \
+               PARAVIRT_PR_CLOBBERS,           \
+               PARAVIRT_AR_CLOBBERS,           \
+               "memory"
+
+#define PARAVIRT_CLOBBERS1                     \
+               PARAVIRT_REG_CLOBBERS1,         \
+               PARAVIRT_BR_CLOBBERS,           \
+               PARAVIRT_PR_CLOBBERS,           \
+               PARAVIRT_AR_CLOBBERS,           \
+               "memory"
+
+#define PARAVIRT_CLOBBERS2                     \
+               PARAVIRT_REG_CLOBBERS2,         \
+               PARAVIRT_BR_CLOBBERS,           \
+               PARAVIRT_PR_CLOBBERS,           \
+               PARAVIRT_AR_CLOBBERS,           \
+               "memory"
+
+#define PARAVIRT_CLOBBERS5                     \
+               PARAVIRT_REG_CLOBBERS5,         \
+               PARAVIRT_BR_CLOBBERS,           \
+               PARAVIRT_PR_CLOBBERS,           \
+               PARAVIRT_AR_CLOBBERS,           \
+               "memory"
+
+#define PARAVIRT_BR0(op, type)                                 \
+       register unsigned long ia64_clobber asm ("r8");         \
+       asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,        \
+                                         PARAVIRT_TYPE(type))  \
+                     : "=r"(ia64_clobber)                      \
+                     : PARAVIRT_OP(op)                         \
+                     : PARAVIRT_CLOBBERS0)
+
+#define PARAVIRT_BR0_RET(op, type)                             \
+       register unsigned long ia64_intri_res asm ("r8");       \
+       asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,        \
+                                         PARAVIRT_TYPE(type))  \
+                     : "=r"(ia64_intri_res)                    \
+                     : PARAVIRT_OP(op)                         \
+                     : PARAVIRT_CLOBBERS0)
+
+#define PARAVIRT_BR1(op, type, arg1)                           \
+       register unsigned long __##arg1 asm ("r8") = arg1;      \
+       register unsigned long ia64_clobber asm ("r8");         \
+       asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,        \
+                                         PARAVIRT_TYPE(type))  \
+                     : "=r"(ia64_clobber)                      \
+                     : PARAVIRT_OP(op), "0"(__##arg1)          \
+                     : PARAVIRT_CLOBBERS1)
+
+#define PARAVIRT_BR1_RET(op, type, arg1)                       \
+       register unsigned long ia64_intri_res asm ("r8");       \
+       register unsigned long __##arg1 asm ("r8") = arg1;      \
+       asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,        \
+                                         PARAVIRT_TYPE(type))  \
+                     : "=r"(ia64_intri_res)                    \
+                     : PARAVIRT_OP(op), "0"(__##arg1)          \
+                     : PARAVIRT_CLOBBERS1)
+
+#define PARAVIRT_BR1_VOID(op, type, arg1)                      \
+       register void *__##arg1 asm ("r8") = arg1;              \
+       register unsigned long ia64_clobber asm ("r8");         \
+       asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,        \
+                                         PARAVIRT_TYPE(type))  \
+                     : "=r"(ia64_clobber)                      \
+                     : PARAVIRT_OP(op), "0"(__##arg1)          \
+                     : PARAVIRT_CLOBBERS1)
+
+#define PARAVIRT_BR2(op, type, arg1, arg2)                             \
+       register unsigned long __##arg1 asm ("r8") = arg1;              \
+       register unsigned long __##arg2 asm ("r9") = arg2;              \
+       register unsigned long ia64_clobber1 asm ("r8");                \
+       register unsigned long ia64_clobber2 asm ("r9");                \
+       asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,                \
+                                         PARAVIRT_TYPE(type))          \
+                     : "=r"(ia64_clobber1), "=r"(ia64_clobber2)        \
+                     : PARAVIRT_OP(op), "0"(__##arg1), "1"(__##arg2)   \
+                     : PARAVIRT_CLOBBERS2)
+
+
+#define PARAVIRT_DEFINE_CPU_OP0(op, type)              \
+       static inline void                              \
+       paravirt_ ## op (void)                          \
+       {                                               \
+               PARAVIRT_BR0(op, type);                 \
+       }
+
+#define PARAVIRT_DEFINE_CPU_OP0_RET(op, type)          \
+       static inline unsigned long                     \
+       paravirt_ ## op (void)                          \
+       {                                               \
+               PARAVIRT_BR0_RET(op, type);             \
+               return ia64_intri_res;                  \
+       }
+
+#define PARAVIRT_DEFINE_CPU_OP1_VOID(op, type)         \
+       static inline void                              \
+       paravirt_ ## op (void *arg1)                    \
+       {                                               \
+               PARAVIRT_BR1_VOID(op, type, arg1);      \
+       }
+
+#define PARAVIRT_DEFINE_CPU_OP1(op, type)              \
+       static inline void                              \
+       paravirt_ ## op (unsigned long arg1)            \
+       {                                               \
+               PARAVIRT_BR1(op, type, arg1);           \
+       }
+
+#define PARAVIRT_DEFINE_CPU_OP1_RET(op, type)          \
+       static inline unsigned long                     \
+       paravirt_ ## op (unsigned long arg1)            \
+       {                                               \
+               PARAVIRT_BR1_RET(op, type, arg1);       \
+               return ia64_intri_res;                  \
+       }
+
+#define PARAVIRT_DEFINE_CPU_OP2(op, type)              \
+       static inline void                              \
+       paravirt_ ## op (unsigned long arg1,            \
+                        unsigned long arg2)            \
+       {                                               \
+               PARAVIRT_BR2(op, type, arg1, arg2);     \
+       }
+
+
+PARAVIRT_DEFINE_CPU_OP1_VOID(fc, FC);
+PARAVIRT_DEFINE_CPU_OP1_RET(thash, THASH)
+PARAVIRT_DEFINE_CPU_OP1_RET(get_cpuid, GET_CPUID)
+PARAVIRT_DEFINE_CPU_OP1_RET(get_pmd, GET_PMD)
+PARAVIRT_DEFINE_CPU_OP2(ptcga, PTCGA)
+PARAVIRT_DEFINE_CPU_OP1_RET(get_rr, GET_RR)
+PARAVIRT_DEFINE_CPU_OP2(set_rr, SET_RR)
+PARAVIRT_DEFINE_CPU_OP0(ssm_i, SSM_I)
+PARAVIRT_DEFINE_CPU_OP0(rsm_i, RSM_I)
+PARAVIRT_DEFINE_CPU_OP0_RET(get_psr_i, GET_PSR_I)
+PARAVIRT_DEFINE_CPU_OP1(intrin_local_irq_restore, INTRIN_LOCAL_IRQ_RESTORE)
+
+static inline void
+paravirt_set_rr0_to_rr4(unsigned long val0, unsigned long val1,
+                       unsigned long val2, unsigned long val3,
+                       unsigned long val4)
+{
+       register unsigned long __val0 asm ("r8") = val0;
+       register unsigned long __val1 asm ("r9") = val1;
+       register unsigned long __val2 asm ("r10") = val2;
+       register unsigned long __val3 asm ("r11") = val3;
+       register unsigned long __val4 asm ("r14") = val4;
+
+       register unsigned long ia64_clobber0 asm ("r8");
+       register unsigned long ia64_clobber1 asm ("r9");
+       register unsigned long ia64_clobber2 asm ("r10");
+       register unsigned long ia64_clobber3 asm ("r11");
+       register unsigned long ia64_clobber4 asm ("r14");
+
+       asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,
+                                         PARAVIRT_TYPE(SET_RR0_TO_RR4))
+                     : "=r"(ia64_clobber0),
+                       "=r"(ia64_clobber1),
+                       "=r"(ia64_clobber2),
+                       "=r"(ia64_clobber3),
+                       "=r"(ia64_clobber4)
+                     : PARAVIRT_OP(set_rr0_to_rr4),
+                       "0"(__val0), "1"(__val1), "2"(__val2),
+                       "3"(__val3), "4"(__val4)
+                     : PARAVIRT_CLOBBERS5);
+}
+
+/* unsigned long paravirt_getreg(int reg) */
+#define __paravirt_getreg(reg)                                         \
+       ({                                                              \
+               register unsigned long ia64_intri_res asm ("r8");       \
+               register unsigned long __reg asm ("r8") = (reg);        \
+                                                                       \
+               BUILD_BUG_ON(!__builtin_constant_p(reg));               \
+               asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,        \
+                                                 PARAVIRT_TYPE(GETREG) \
+                                                 + (reg))              \
+                             : "=r"(ia64_intri_res)                    \
+                             : PARAVIRT_OP(getreg), "0"(__reg)         \
+                             : PARAVIRT_CLOBBERS1);                    \
+                                                                       \
+               ia64_intri_res;                                         \
+       })
+
+/* void paravirt_setreg(int reg, unsigned long val) */
+#define paravirt_setreg(reg, val)                                      \
+       do {                                                            \
+               register unsigned long __val asm ("r8") = val;          \
+               register unsigned long __reg asm ("r9") = reg;          \
+               register unsigned long ia64_clobber1 asm ("r8");        \
+               register unsigned long ia64_clobber2 asm ("r9");        \
+                                                                       \
+               BUILD_BUG_ON(!__builtin_constant_p(reg));               \
+               asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,        \
+                                                 PARAVIRT_TYPE(SETREG) \
+                                                 + (reg))              \
+                             : "=r"(ia64_clobber1),                    \
+                               "=r"(ia64_clobber2)                     \
+                             : PARAVIRT_OP(setreg),                    \
+                               "1"(__reg), "0"(__val)                  \
+                             : PARAVIRT_CLOBBERS2);                    \
+       } while (0)
+
+#endif /* ASM_SUPPORTED */
+#endif /* CONFIG_PARAVIRT && ASM_SUPPOTED */
+
 #endif /* _ASM_IA64_PARAVIRT_PRIVOP_H */
index 21c402365d0ea7f86bf63cbf0009bb7c7e266642..59840833625165fc72c75b40c24e94a1ba7db5ae 100644 (file)
@@ -126,7 +126,8 @@ extern void identify_siblings (struct cpuinfo_ia64 *);
 extern int is_multithreading_enabled(void);
 
 extern void arch_send_call_function_single_ipi(int cpu);
-extern void arch_send_call_function_ipi(cpumask_t mask);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
+#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
 
 #else /* CONFIG_SMP */
 
index 0229fb95fb3824f657452dc4adbd1bd4e52c48e1..13ab71576bc7a42e698508a92a04b2ed87ee7fd7 100644 (file)
@@ -120,6 +120,38 @@ do {                                                                                       \
 #define __raw_read_can_lock(rw)                (*(volatile int *)(rw) >= 0)
 #define __raw_write_can_lock(rw)       (*(volatile int *)(rw) == 0)
 
+#ifdef ASM_SUPPORTED
+
+static __always_inline void
+__raw_read_lock_flags(raw_rwlock_t *lock, unsigned long flags)
+{
+       __asm__ __volatile__ (
+               "tbit.nz p6, p0 = %1,%2\n"
+               "br.few 3f\n"
+               "1:\n"
+               "fetchadd4.rel r2 = [%0], -1;;\n"
+               "(p6) ssm psr.i\n"
+               "2:\n"
+               "hint @pause\n"
+               "ld4 r2 = [%0];;\n"
+               "cmp4.lt p7,p0 = r2, r0\n"
+               "(p7) br.cond.spnt.few 2b\n"
+               "(p6) rsm psr.i\n"
+               ";;\n"
+               "3:\n"
+               "fetchadd4.acq r2 = [%0], 1;;\n"
+               "cmp4.lt p7,p0 = r2, r0\n"
+               "(p7) br.cond.spnt.few 1b\n"
+               : : "r"(lock), "r"(flags), "i"(IA64_PSR_I_BIT)
+               : "p6", "p7", "r2", "memory");
+}
+
+#define __raw_read_lock(lock) __raw_read_lock_flags(lock, 0)
+
+#else /* !ASM_SUPPORTED */
+
+#define __raw_read_lock_flags(rw, flags) __raw_read_lock(rw)
+
 #define __raw_read_lock(rw)                                                            \
 do {                                                                                   \
        raw_rwlock_t *__read_lock_ptr = (rw);                                           \
@@ -131,6 +163,8 @@ do {                                                                                        \
        }                                                                               \
 } while (0)
 
+#endif /* !ASM_SUPPORTED */
+
 #define __raw_read_unlock(rw)                                  \
 do {                                                           \
        raw_rwlock_t *__read_lock_ptr = (rw);                   \
@@ -138,20 +172,33 @@ do {                                                              \
 } while (0)
 
 #ifdef ASM_SUPPORTED
-#define __raw_write_lock(rw)                                                   \
-do {                                                                           \
-       __asm__ __volatile__ (                                                  \
-               "mov ar.ccv = r0\n"                                             \
-               "dep r29 = -1, r0, 31, 1;;\n"                                   \
-               "1:\n"                                                          \
-               "ld4 r2 = [%0];;\n"                                             \
-               "cmp4.eq p0,p7 = r0,r2\n"                                       \
-               "(p7) br.cond.spnt.few 1b \n"                                   \
-               "cmpxchg4.acq r2 = [%0], r29, ar.ccv;;\n"                       \
-               "cmp4.eq p0,p7 = r0, r2\n"                                      \
-               "(p7) br.cond.spnt.few 1b;;\n"                                  \
-               :: "r"(rw) : "ar.ccv", "p7", "r2", "r29", "memory");            \
-} while(0)
+
+static __always_inline void
+__raw_write_lock_flags(raw_rwlock_t *lock, unsigned long flags)
+{
+       __asm__ __volatile__ (
+               "tbit.nz p6, p0 = %1, %2\n"
+               "mov ar.ccv = r0\n"
+               "dep r29 = -1, r0, 31, 1\n"
+               "br.few 3f;;\n"
+               "1:\n"
+               "(p6) ssm psr.i\n"
+               "2:\n"
+               "hint @pause\n"
+               "ld4 r2 = [%0];;\n"
+               "cmp4.eq p0,p7 = r0, r2\n"
+               "(p7) br.cond.spnt.few 2b\n"
+               "(p6) rsm psr.i\n"
+               ";;\n"
+               "3:\n"
+               "cmpxchg4.acq r2 = [%0], r29, ar.ccv;;\n"
+               "cmp4.eq p0,p7 = r0, r2\n"
+               "(p7) br.cond.spnt.few 1b;;\n"
+               : : "r"(lock), "r"(flags), "i"(IA64_PSR_I_BIT)
+               : "ar.ccv", "p6", "p7", "r2", "r29", "memory");
+}
+
+#define __raw_write_lock(rw) __raw_write_lock_flags(rw, 0)
 
 #define __raw_write_trylock(rw)                                                        \
 ({                                                                             \
@@ -174,6 +221,8 @@ static inline void __raw_write_unlock(raw_rwlock_t *x)
 
 #else /* !ASM_SUPPORTED */
 
+#define __raw_write_lock_flags(l, flags) __raw_write_lock(l)
+
 #define __raw_write_lock(l)                                                            \
 ({                                                                                     \
        __u64 ia64_val, ia64_set_val = ia64_dep_mi(-1, 0, 31, 1);                       \
index 4e03cfe74a0c40712c7ff328c0436eca46946e95..86c7db86118034bcc8ed60162112786afd30c4f5 100644 (file)
@@ -40,5 +40,6 @@ get_cycles (void)
 }
 
 extern void ia64_cpu_local_tick (void);
+extern unsigned long long ia64_native_sched_clock (void);
 
 #endif /* _ASM_IA64_TIMEX_H */
index 3193f4417e16c8ea919016f05aa904215f6eeae9..7b4c8c70b2d18f7949372899ab056f41d913ed6b 100644 (file)
  */
 #define parent_node(nid) (nid)
 
-/*
- * Returns the number of the first CPU on Node 'node'.
- */
-#define node_to_first_cpu(node) (cpumask_first(cpumask_of_node(node)))
-
 /*
  * Determines the node for a given pci bus
  */
@@ -117,11 +112,6 @@ void build_cpu_to_node_map(void);
 
 extern void arch_fix_phys_package_id(int num, u32 slot);
 
-#define pcibus_to_cpumask(bus) (pcibus_to_node(bus) == -1 ? \
-                                       CPU_MASK_ALL : \
-                                       node_to_cpumask(pcibus_to_node(bus)) \
-                               )
-
 #define cpumask_of_pcibus(bus) (pcibus_to_node(bus) == -1 ?            \
                                 cpu_all_mask :                         \
                                 cpumask_of_node(pcibus_to_node(bus)))
index f607018af4a19397691212e7074a55455a2f3cd2..53e9dfacd07393a57b9ae9ab114c2e4b5596f4dc 100644 (file)
@@ -305,5 +305,11 @@ static inline int uv_num_possible_blades(void)
        return 1;
 }
 
+static inline void uv_hub_send_ipi(int pnode, int apicid, int vector)
+{
+       /* not currently needed on ia64 */
+}
+
+
 #endif /* __ASM_IA64_UV_HUB__ */
 
index c149ef085437f22cc46b2ad6db09c1ec0520d45f..fe0b8f05e1a8719c39b91babcd4afe06b80eefed 100644 (file)
@@ -8,8 +8,8 @@
  * Copyright (C) 2007-2008 Silicon Graphics, Inc. All rights reserved.
  */
 
-#ifndef __ASM_IA64_UV_MMRS__
-#define __ASM_IA64_UV_MMRS__
+#ifndef _ASM_IA64_UV_UV_MMRS_H
+#define _ASM_IA64_UV_UV_MMRS_H
 
 #define UV_MMR_ENABLE          (1UL << 63)
 
@@ -242,6 +242,158 @@ union uvh_event_occurred0_u {
 #define UVH_EVENT_OCCURRED0_ALIAS 0x0000000000070008UL
 #define UVH_EVENT_OCCURRED0_ALIAS_32 0x005f0
 
+/* ========================================================================= */
+/*                         UVH_GR0_TLB_INT0_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR0_TLB_INT0_CONFIG 0x61b00UL
+
+#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_SHFT 0
+#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_GR0_TLB_INT0_CONFIG_DM_SHFT 8
+#define UVH_GR0_TLB_INT0_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_GR0_TLB_INT0_CONFIG_DESTMODE_SHFT 11
+#define UVH_GR0_TLB_INT0_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_GR0_TLB_INT0_CONFIG_STATUS_SHFT 12
+#define UVH_GR0_TLB_INT0_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_GR0_TLB_INT0_CONFIG_P_SHFT 13
+#define UVH_GR0_TLB_INT0_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_GR0_TLB_INT0_CONFIG_T_SHFT 15
+#define UVH_GR0_TLB_INT0_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_GR0_TLB_INT0_CONFIG_M_SHFT 16
+#define UVH_GR0_TLB_INT0_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_GR0_TLB_INT0_CONFIG_APIC_ID_SHFT 32
+#define UVH_GR0_TLB_INT0_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_gr0_tlb_int0_config_u {
+    unsigned long      v;
+    struct uvh_gr0_tlb_int0_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                         UVH_GR0_TLB_INT1_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR0_TLB_INT1_CONFIG 0x61b40UL
+
+#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_SHFT 0
+#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_GR0_TLB_INT1_CONFIG_DM_SHFT 8
+#define UVH_GR0_TLB_INT1_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_GR0_TLB_INT1_CONFIG_DESTMODE_SHFT 11
+#define UVH_GR0_TLB_INT1_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_GR0_TLB_INT1_CONFIG_STATUS_SHFT 12
+#define UVH_GR0_TLB_INT1_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_GR0_TLB_INT1_CONFIG_P_SHFT 13
+#define UVH_GR0_TLB_INT1_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_GR0_TLB_INT1_CONFIG_T_SHFT 15
+#define UVH_GR0_TLB_INT1_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_GR0_TLB_INT1_CONFIG_M_SHFT 16
+#define UVH_GR0_TLB_INT1_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_GR0_TLB_INT1_CONFIG_APIC_ID_SHFT 32
+#define UVH_GR0_TLB_INT1_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_gr0_tlb_int1_config_u {
+    unsigned long      v;
+    struct uvh_gr0_tlb_int1_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                         UVH_GR1_TLB_INT0_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR1_TLB_INT0_CONFIG 0x61f00UL
+
+#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_SHFT 0
+#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_GR1_TLB_INT0_CONFIG_DM_SHFT 8
+#define UVH_GR1_TLB_INT0_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_GR1_TLB_INT0_CONFIG_DESTMODE_SHFT 11
+#define UVH_GR1_TLB_INT0_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_GR1_TLB_INT0_CONFIG_STATUS_SHFT 12
+#define UVH_GR1_TLB_INT0_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_GR1_TLB_INT0_CONFIG_P_SHFT 13
+#define UVH_GR1_TLB_INT0_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_GR1_TLB_INT0_CONFIG_T_SHFT 15
+#define UVH_GR1_TLB_INT0_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_GR1_TLB_INT0_CONFIG_M_SHFT 16
+#define UVH_GR1_TLB_INT0_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_GR1_TLB_INT0_CONFIG_APIC_ID_SHFT 32
+#define UVH_GR1_TLB_INT0_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_gr1_tlb_int0_config_u {
+    unsigned long      v;
+    struct uvh_gr1_tlb_int0_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                         UVH_GR1_TLB_INT1_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR1_TLB_INT1_CONFIG 0x61f40UL
+
+#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_SHFT 0
+#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_GR1_TLB_INT1_CONFIG_DM_SHFT 8
+#define UVH_GR1_TLB_INT1_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_GR1_TLB_INT1_CONFIG_DESTMODE_SHFT 11
+#define UVH_GR1_TLB_INT1_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_GR1_TLB_INT1_CONFIG_STATUS_SHFT 12
+#define UVH_GR1_TLB_INT1_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_GR1_TLB_INT1_CONFIG_P_SHFT 13
+#define UVH_GR1_TLB_INT1_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_GR1_TLB_INT1_CONFIG_T_SHFT 15
+#define UVH_GR1_TLB_INT1_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_GR1_TLB_INT1_CONFIG_M_SHFT 16
+#define UVH_GR1_TLB_INT1_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_GR1_TLB_INT1_CONFIG_APIC_ID_SHFT 32
+#define UVH_GR1_TLB_INT1_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_gr1_tlb_int1_config_u {
+    unsigned long      v;
+    struct uvh_gr1_tlb_int1_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
 /* ========================================================================= */
 /*                               UVH_INT_CMPB                                */
 /* ========================================================================= */
@@ -670,4 +822,4 @@ union uvh_si_alias2_overlay_config_u {
 };
 
 
-#endif /* __ASM_IA64_UV_MMRS__ */
+#endif /* _ASM_IA64_UV_UV_MMRS_H */
index 7a804e80fc67d0c0aee90d0cbe13e365512d0570..e425227a418e9b15a40a0dce0d8f09be3061ec90 100644 (file)
@@ -33,9 +33,6 @@
 #ifndef _ASM_IA64_XEN_HYPERVISOR_H
 #define _ASM_IA64_XEN_HYPERVISOR_H
 
-#ifdef CONFIG_XEN
-
-#include <linux/init.h>
 #include <xen/interface/xen.h>
 #include <xen/interface/version.h>     /* to compile feature.c */
 #include <xen/features.h>              /* to comiple xen-netfront.c */
 
 /* xen_domain_type is set before executing any C code by early_xen_setup */
 enum xen_domain_type {
-       XEN_NATIVE,
-       XEN_PV_DOMAIN,
-       XEN_HVM_DOMAIN,
+       XEN_NATIVE,     /* running on bare hardware */
+       XEN_PV_DOMAIN,  /* running in a PV domain */
+       XEN_HVM_DOMAIN, /* running in a Xen hvm domain*/
 };
 
+#ifdef CONFIG_XEN
 extern enum xen_domain_type xen_domain_type;
+#else
+#define xen_domain_type                XEN_NATIVE
+#endif
 
 #define xen_domain()           (xen_domain_type != XEN_NATIVE)
-#define xen_pv_domain()                (xen_domain_type == XEN_PV_DOMAIN)
-#define xen_initial_domain()   (xen_pv_domain() && \
+#define xen_pv_domain()                (xen_domain() &&                        \
+                                xen_domain_type == XEN_PV_DOMAIN)
+#define xen_hvm_domain()       (xen_domain() &&                        \
+                                xen_domain_type == XEN_HVM_DOMAIN)
+
+#ifdef CONFIG_XEN_DOM0
+#define xen_initial_domain()   (xen_pv_domain() &&                     \
                                 (xen_start_info->flags & SIF_INITDOMAIN))
-#define xen_hvm_domain()       (xen_domain_type == XEN_HVM_DOMAIN)
+#else
+#define xen_initial_domain()   (0)
+#endif
 
-/* deprecated. remove this */
-#define is_running_on_xen()    (xen_domain_type == XEN_PV_DOMAIN)
 
+#ifdef CONFIG_XEN
 extern struct shared_info *HYPERVISOR_shared_info;
 extern struct start_info *xen_start_info;
 
@@ -74,16 +81,6 @@ void force_evtchn_callback(void);
 
 /* For setup_arch() in arch/ia64/kernel/setup.c */
 void xen_ia64_enable_opt_feature(void);
-
-#else /* CONFIG_XEN */
-
-#define xen_domain()           (0)
-#define xen_pv_domain()                (0)
-#define xen_initial_domain()   (0)
-#define xen_hvm_domain()       (0)
-#define is_running_on_xen()    (0)     /* deprecated. remove this */
 #endif
 
-#define is_initial_xendomain() (0)     /* deprecated. remove this */
-
 #endif /* _ASM_IA64_XEN_HYPERVISOR_H */
index 19c2ae1d878a0473278b35a198114b860ba52d74..c53a476112082328ac403943fa784629b7ca1f4f 100644 (file)
@@ -33,6 +33,9 @@
 #define __paravirt_work_processed_syscall_target \
                                                xen_work_processed_syscall
 
+#define paravirt_fsyscall_table                        xen_fsyscall_table
+#define paravirt_fsys_bubble_down              xen_fsys_bubble_down
+
 #define MOV_FROM_IFA(reg)      \
        movl reg = XSI_IFA;     \
        ;;                      \
 .endm
 #define MOV_FROM_PSR(pred, reg, clob)  __MOV_FROM_PSR pred, reg, clob
 
+/* assuming ar.itc is read with interrupt disabled. */
+#define MOV_FROM_ITC(pred, pred_clob, reg, clob)               \
+(pred) movl clob = XSI_ITC_OFFSET;                             \
+       ;;                                                      \
+(pred) ld8 clob = [clob];                                      \
+(pred) mov reg = ar.itc;                                       \
+       ;;                                                      \
+(pred) add reg = reg, clob;                                    \
+       ;;                                                      \
+(pred) movl clob = XSI_ITC_LAST;                               \
+       ;;                                                      \
+(pred) ld8 clob = [clob];                                      \
+       ;;                                                      \
+(pred) cmp.geu.unc pred_clob, p0 = clob, reg;                  \
+       ;;                                                      \
+(pred_clob)    add reg = 1, clob;                              \
+       ;;                                                      \
+(pred) movl clob = XSI_ITC_LAST;                               \
+       ;;                                                      \
+(pred) st8 [clob] = reg
+
 
 #define MOV_TO_IFA(reg, clob)  \
        movl clob = XSI_IFA;    \
 #define RSM_PSR_DT             \
        XEN_HYPER_RSM_PSR_DT
 
+#define RSM_PSR_BE_I(clob0, clob1)     \
+       RSM_PSR_I(p0, clob0, clob1);    \
+       rum psr.be
+
 #define SSM_PSR_DT_AND_SRLZ_I  \
        XEN_HYPER_SSM_PSR_DT
 
index f00fab40854d1951b473b88ec201adee9b03a41a..e951e740bdf21514c8622f9b8ba875ada702e450 100644 (file)
@@ -209,6 +209,15 @@ struct mapped_regs {
                        unsigned long krs[8];   /* kernel registers */
                        unsigned long tmp[16];  /* temp registers
                                                   (e.g. for hyperprivops) */
+
+                       /* itc paravirtualization
+                        * vAR.ITC = mAR.ITC + itc_offset
+                        * itc_last is one which was lastly passed to
+                        * the guest OS in order to prevent it from
+                        * going backwords.
+                        */
+                       unsigned long itc_offset;
+                       unsigned long itc_last;
                };
        };
 };
index 4d92d9bbda7be19dd419107a34c08f344edfbff1..c57fa910f2c937e7473a9ea63e5ac9a7be74c86c 100644 (file)
@@ -1,3 +1,12 @@
+
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+/* read ar.itc in advance, and use it before leaving bank 0 */
+#define XEN_ACCOUNT_GET_STAMP          \
+       MOV_FROM_ITC(pUStk, p6, r20, r2);
+#else
+#define XEN_ACCOUNT_GET_STAMP
+#endif
+
 /*
  * DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves
  * the minimum state necessary that allows us to turn psr.ic back
        ;;                                                                                      \
 .mem.offset 0,0; st8.spill [r16]=r2,16;                                                                \
 .mem.offset 8,0; st8.spill [r17]=r3,16;                                                                \
-       ACCOUNT_GET_STAMP                                                                       \
+       XEN_ACCOUNT_GET_STAMP                                                                   \
        adds r2=IA64_PT_REGS_R16_OFFSET,r1;                                                     \
        ;;                                                                                      \
        EXTRA;                                                                                  \
diff --git a/arch/ia64/include/asm/xen/patchlist.h b/arch/ia64/include/asm/xen/patchlist.h
new file mode 100644 (file)
index 0000000..eae944e
--- /dev/null
@@ -0,0 +1,38 @@
+/******************************************************************************
+ * arch/ia64/include/asm/xen/patchlist.h
+ *
+ * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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
+ *
+ */
+
+#define __paravirt_start_gate_fsyscall_patchlist               \
+       __xen_start_gate_fsyscall_patchlist
+#define __paravirt_end_gate_fsyscall_patchlist                 \
+       __xen_end_gate_fsyscall_patchlist
+#define __paravirt_start_gate_brl_fsys_bubble_down_patchlist   \
+       __xen_start_gate_brl_fsys_bubble_down_patchlist
+#define __paravirt_end_gate_brl_fsys_bubble_down_patchlist     \
+       __xen_end_gate_brl_fsys_bubble_down_patchlist
+#define __paravirt_start_gate_vtop_patchlist                   \
+       __xen_start_gate_vtop_patchlist
+#define __paravirt_end_gate_vtop_patchlist                     \
+       __xen_end_gate_vtop_patchlist
+#define __paravirt_start_gate_mckinley_e9_patchlist            \
+       __xen_start_gate_mckinley_e9_patchlist
+#define __paravirt_end_gate_mckinley_e9_patchlist              \
+       __xen_end_gate_mckinley_e9_patchlist
index 71ec7546e100d5a5f549874057caead44c4809e5..fb4ec5e0b066b81741078f9f00374417b3c9de60 100644 (file)
@@ -55,6 +55,8 @@
 #define XSI_BANK1_R16                  (XSI_BASE + XSI_BANK1_R16_OFS)
 #define XSI_BANKNUM                    (XSI_BASE + XSI_BANKNUM_OFS)
 #define XSI_IHA                                (XSI_BASE + XSI_IHA_OFS)
+#define XSI_ITC_OFFSET                 (XSI_BASE + XSI_ITC_OFFSET_OFS)
+#define XSI_ITC_LAST                   (XSI_BASE + XSI_ITC_LAST_OFS)
 #endif
 
 #ifndef __ASSEMBLY__
@@ -67,7 +69,7 @@
  *  may have different semantics depending on whether they are executed
  *  at PL0 vs PL!=0.  When paravirtualized, these instructions mustn't
  *  be allowed to execute directly, lest incorrect semantics result. */
-extern void xen_fc(unsigned long addr);
+extern void xen_fc(void *addr);
 extern unsigned long xen_thash(unsigned long addr);
 
 /* Note that "ttag" and "cover" are also privilege-sensitive; "ttag"
@@ -80,8 +82,10 @@ extern unsigned long xen_thash(unsigned long addr);
 extern unsigned long xen_get_cpuid(int index);
 extern unsigned long xen_get_pmd(int index);
 
+#ifndef ASM_SUPPORTED
 extern unsigned long xen_get_eflag(void);      /* see xen_ia64_getreg */
 extern void xen_set_eflag(unsigned long);      /* see xen_ia64_setreg */
+#endif
 
 /************************************************/
 /* Instructions paravirtualized for performance */
@@ -106,6 +110,7 @@ extern void xen_set_eflag(unsigned long);   /* see xen_ia64_setreg */
 #define xen_get_virtual_pend()         \
        (*(((uint8_t *)XEN_MAPPEDREGS->interrupt_mask_addr) - 1))
 
+#ifndef ASM_SUPPORTED
 /* Although all privileged operations can be left to trap and will
  * be properly handled by Xen, some are frequent enough that we use
  * hyperprivops for performance. */
@@ -123,6 +128,7 @@ extern void xen_set_rr0_to_rr4(unsigned long val0, unsigned long val1,
                               unsigned long val4);
 extern void xen_set_kr(unsigned long index, unsigned long val);
 extern void xen_ptcga(unsigned long addr, unsigned long size);
+#endif /* !ASM_SUPPORTED */
 
 #endif /* !__ASSEMBLY__ */
 
index c381ea9548924149835ba223f758729dea3ebc03..5628e9a990a61225196c5de205ebdceeaf800aee 100644 (file)
@@ -5,9 +5,9 @@
 extra-y        := head.o init_task.o vmlinux.lds
 
 obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o      \
-        irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o          \
+        irq_lsapic.o ivt.o machvec.o pal.o paravirt_patchlist.o patch.o process.o perfmon.o ptrace.o sal.o             \
         salinfo.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \
-        unwind.o mca.o mca_asm.o topology.o
+        unwind.o mca.o mca_asm.o topology.o dma-mapping.o
 
 obj-$(CONFIG_IA64_BRL_EMU)     += brl_emu.o
 obj-$(CONFIG_IA64_GENERIC)     += acpi-ext.o
@@ -36,46 +36,23 @@ obj-$(CONFIG_PCI_MSI)               += msi_ia64.o
 mca_recovery-y                 += mca_drv.o mca_drv_asm.o
 obj-$(CONFIG_IA64_MC_ERR_INJECT)+= err_inject.o
 
-obj-$(CONFIG_PARAVIRT)         += paravirt.o paravirtentry.o
+obj-$(CONFIG_PARAVIRT)         += paravirt.o paravirtentry.o \
+                                  paravirt_patch.o
 
 obj-$(CONFIG_IA64_ESI)         += esi.o
 ifneq ($(CONFIG_IA64_ESI),)
 obj-y                          += esi_stub.o   # must be in kernel proper
 endif
 obj-$(CONFIG_DMAR)             += pci-dma.o
-ifeq ($(CONFIG_DMAR), y)
 obj-$(CONFIG_SWIOTLB)          += pci-swiotlb.o
-endif
-
-# The gate DSO image is built using a special linker script.
-targets += gate.so gate-syms.o
-
-extra-y += gate.so gate-syms.o gate.lds gate.o
 
 # fp_emulate() expects f2-f5,f16-f31 to contain the user-level state.
 CFLAGS_traps.o  += -mfixed-range=f2-f5,f16-f31
 
-CPPFLAGS_gate.lds := -P -C -U$(ARCH)
-
-quiet_cmd_gate = GATE $@
-      cmd_gate = $(CC) -nostdlib $(GATECFLAGS_$(@F)) -Wl,-T,$(filter-out FORCE,$^) -o $@
-
-GATECFLAGS_gate.so = -shared -s -Wl,-soname=linux-gate.so.1 \
-                    $(call ld-option, -Wl$(comma)--hash-style=sysv)
-$(obj)/gate.so: $(obj)/gate.lds $(obj)/gate.o FORCE
-       $(call if_changed,gate)
-
-$(obj)/built-in.o: $(obj)/gate-syms.o
-$(obj)/built-in.o: ld_flags += -R $(obj)/gate-syms.o
-
-GATECFLAGS_gate-syms.o = -r
-$(obj)/gate-syms.o: $(obj)/gate.lds $(obj)/gate.o FORCE
-       $(call if_changed,gate)
-
-# gate-data.o contains the gate DSO image as data in section .data.gate.
-# We must build gate.so before we can assemble it.
-# Note: kbuild does not track this dependency due to usage of .incbin
-$(obj)/gate-data.o: $(obj)/gate.so
+# The gate DSO image is built using a special linker script.
+include $(srctree)/arch/ia64/kernel/Makefile.gate
+# tell compiled for native
+CPPFLAGS_gate.lds += -D__IA64_GATE_PARAVIRTUALIZED_NATIVE
 
 # Calculate NR_IRQ = max(IA64_NATIVE_NR_IRQS, XEN_NR_IRQS, ...) based on config
 define sed-y
@@ -111,9 +88,9 @@ include/asm-ia64/nr-irqs.h: arch/$(SRCARCH)/kernel/nr-irqs.s
 clean-files += $(objtree)/include/asm-ia64/nr-irqs.h
 
 #
-# native ivt.S and entry.S
+# native ivt.S, entry.S and fsys.S
 #
-ASM_PARAVIRT_OBJS = ivt.o entry.o
+ASM_PARAVIRT_OBJS = ivt.o entry.o fsys.o
 define paravirtualized_native
 AFLAGS_$(1) += -D__IA64_ASM_PARAVIRTUALIZED_NATIVE
 AFLAGS_pvchk-sed-$(1) += -D__IA64_ASM_PARAVIRTUALIZED_PVCHECK
diff --git a/arch/ia64/kernel/Makefile.gate b/arch/ia64/kernel/Makefile.gate
new file mode 100644 (file)
index 0000000..1d87f84
--- /dev/null
@@ -0,0 +1,27 @@
+# The gate DSO image is built using a special linker script.
+
+targets += gate.so gate-syms.o
+
+extra-y += gate.so gate-syms.o gate.lds gate.o
+
+CPPFLAGS_gate.lds := -P -C -U$(ARCH)
+
+quiet_cmd_gate = GATE $@
+      cmd_gate = $(CC) -nostdlib $(GATECFLAGS_$(@F)) -Wl,-T,$(filter-out FORCE,$^) -o $@
+
+GATECFLAGS_gate.so = -shared -s -Wl,-soname=linux-gate.so.1 \
+                    $(call ld-option, -Wl$(comma)--hash-style=sysv)
+$(obj)/gate.so: $(obj)/gate.lds $(obj)/gate.o FORCE
+       $(call if_changed,gate)
+
+$(obj)/built-in.o: $(obj)/gate-syms.o
+$(obj)/built-in.o: ld_flags += -R $(obj)/gate-syms.o
+
+GATECFLAGS_gate-syms.o = -r
+$(obj)/gate-syms.o: $(obj)/gate.lds $(obj)/gate.o FORCE
+       $(call if_changed,gate)
+
+# gate-data.o contains the gate DSO image as data in section .data.gate.
+# We must build gate.so before we can assemble it.
+# Note: kbuild does not track this dependency due to usage of .incbin
+$(obj)/gate-data.o: $(obj)/gate.so
index bdef2ce38c8b45c3227b7d70673db1bce4deb46f..5510317db37b2a439711bb3fa97d6af0c7cd00bf 100644 (file)
@@ -890,7 +890,7 @@ __init void prefill_possible_map(void)
                possible, max((possible - available_cpus), 0));
 
        for (i = 0; i < possible; i++)
-               cpu_set(i, cpu_possible_map);
+               set_cpu_possible(i, true);
 }
 
 int acpi_map_lsapic(acpi_handle handle, int *pcpu)
@@ -928,9 +928,9 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
        buffer.length = ACPI_ALLOCATE_BUFFER;
        buffer.pointer = NULL;
 
-       cpus_complement(tmp_map, cpu_present_map);
-       cpu = first_cpu(tmp_map);
-       if (cpu >= NR_CPUS)
+       cpumask_complement(&tmp_map, cpu_present_mask);
+       cpu = cpumask_first(&tmp_map);
+       if (cpu >= nr_cpu_ids)
                return -EINVAL;
 
        acpi_map_cpu2node(handle, cpu, physid);
index 742dbb1d5a4fb06cd8cfd3a2f63358b48e20535e..af56501690432110a1f27847bea9dffd60737b81 100644 (file)
@@ -316,5 +316,7 @@ void foo(void)
        DEFINE_MAPPED_REG_OFS(XSI_BANK1_R16_OFS, bank1_regs[0]);
        DEFINE_MAPPED_REG_OFS(XSI_B0NATS_OFS, vbnat);
        DEFINE_MAPPED_REG_OFS(XSI_B1NATS_OFS, vnat);
+       DEFINE_MAPPED_REG_OFS(XSI_ITC_OFFSET_OFS, itc_offset);
+       DEFINE_MAPPED_REG_OFS(XSI_ITC_LAST_OFS, itc_last);
 #endif /* CONFIG_XEN */
 }
diff --git a/arch/ia64/kernel/dma-mapping.c b/arch/ia64/kernel/dma-mapping.c
new file mode 100644 (file)
index 0000000..086a2ae
--- /dev/null
@@ -0,0 +1,13 @@
+#include <linux/dma-mapping.h>
+
+/* Set this to 1 if there is a HW IOMMU in the system */
+int iommu_detected __read_mostly;
+
+struct dma_map_ops *dma_ops;
+EXPORT_SYMBOL(dma_ops);
+
+struct dma_map_ops *dma_get_ops(struct device *dev)
+{
+       return dma_ops;
+}
+EXPORT_SYMBOL(dma_get_ops);
index efaff15d8cf1dc9cad35a767a53b3865d51037b4..7ef80e8161ce3dbad06d522ef5634e9e8520be3e 100644 (file)
@@ -456,6 +456,7 @@ efi_map_pal_code (void)
                 GRANULEROUNDDOWN((unsigned long) pal_vaddr),
                 pte_val(pfn_pte(__pa(pal_vaddr) >> PAGE_SHIFT, PAGE_KERNEL)),
                 IA64_GRANULE_SHIFT);
+       paravirt_dv_serialize_data();
        ia64_set_psr(psr);              /* restore psr */
 }
 
index e5341e2c1175c6f0b5e16f88bd831f90422fbf03..ccfdeee9d89f7c291306b7bdfa08caa689ecc14f 100644 (file)
@@ -735,7 +735,7 @@ GLOBAL_ENTRY(__paravirt_leave_syscall)
 __paravirt_work_processed_syscall:
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        adds r2=PT(LOADRS)+16,r12
-(pUStk)        mov.m r22=ar.itc                        // fetch time at leave
+       MOV_FROM_ITC(pUStk, p9, r22, r19)       // fetch time at leave
        adds r18=TI_FLAGS+IA64_TASK_SIZE,r13
        ;;
 (p6)   ld4 r31=[r18]                           // load current_thread_info()->flags
@@ -984,7 +984,7 @@ GLOBAL_ENTRY(__paravirt_leave_kernel)
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        .pred.rel.mutex pUStk,pKStk
        MOV_FROM_PSR(pKStk, r22, r29)   // M2 read PSR now that interrupts are disabled
-(pUStk)        mov.m r22=ar.itc        // M  fetch time at leave
+       MOV_FROM_ITC(pUStk, p9, r22, r29)       // M  fetch time at leave
        nop.i 0
        ;;
 #else
index c1625c7e17795b093acd281eb7d2a56fd1a6be47..3567d54f8cee7533ecba41847c5f9957d9481296 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/unistd.h>
 
 #include "entry.h"
+#include "paravirt_inst.h"
 
 /*
  * See Documentation/ia64/fsys.txt for details on fsyscalls.
@@ -279,7 +280,7 @@ ENTRY(fsys_gettimeofday)
 (p9)   cmp.eq p13,p0 = 0,r30   // if mmio_ptr, clear p13 jitter control
        ;;
        .pred.rel.mutex p8,p9
-(p8)   mov r2 = ar.itc         // CPU_TIMER. 36 clocks latency!!!
+       MOV_FROM_ITC(p8, p6, r2, r10)   // CPU_TIMER. 36 clocks latency!!!
 (p9)   ld8 r2 = [r30]          // MMIO_TIMER. Could also have latency issues..
 (p13)  ld8 r25 = [r19]         // get itc_lastcycle value
        ld8 r9 = [r22],IA64_TIMESPEC_TV_NSEC_OFFSET     // tv_sec
@@ -418,7 +419,7 @@ EX(.fail_efault, ld8 r14=[r33])                     // r14 <- *set
        mov r17=(1 << (SIGKILL - 1)) | (1 << (SIGSTOP - 1))
        ;;
 
-       rsm psr.i                               // mask interrupt delivery
+       RSM_PSR_I(p0, r18, r19)                 // mask interrupt delivery
        mov ar.ccv=0
        andcm r14=r14,r17                       // filter out SIGKILL & SIGSTOP
 
@@ -491,7 +492,7 @@ EX(.fail_efault, ld8 r14=[r33])                     // r14 <- *set
 #ifdef CONFIG_SMP
        st4.rel [r31]=r0                        // release the lock
 #endif
-       ssm psr.i
+       SSM_PSR_I(p0, p9, r31)
        ;;
 
        srlz.d                                  // ensure psr.i is set again
@@ -513,7 +514,7 @@ EX(.fail_efault, (p15) st8 [r34]=r3)
 #ifdef CONFIG_SMP
        st4.rel [r31]=r0                        // release the lock
 #endif
-       ssm psr.i
+       SSM_PSR_I(p0, p9, r17)
        ;;
        srlz.d
        br.sptk.many fsys_fallback_syscall      // with signal pending, do the heavy-weight syscall
@@ -521,7 +522,7 @@ EX(.fail_efault, (p15) st8 [r34]=r3)
 #ifdef CONFIG_SMP
 .lock_contention:
        /* Rather than spinning here, fall back on doing a heavy-weight syscall.  */
-       ssm psr.i
+       SSM_PSR_I(p0, p9, r17)
        ;;
        srlz.d
        br.sptk.many fsys_fallback_syscall
@@ -592,17 +593,17 @@ ENTRY(fsys_fallback_syscall)
        adds r17=-1024,r15
        movl r14=sys_call_table
        ;;
-       rsm psr.i
+       RSM_PSR_I(p0, r26, r27)
        shladd r18=r17,3,r14
        ;;
        ld8 r18=[r18]                           // load normal (heavy-weight) syscall entry-point
-       mov r29=psr                             // read psr (12 cyc load latency)
+       MOV_FROM_PSR(p0, r29, r26)              // read psr (12 cyc load latency)
        mov r27=ar.rsc
        mov r21=ar.fpsr
        mov r26=ar.pfs
 END(fsys_fallback_syscall)
        /* FALL THROUGH */
-GLOBAL_ENTRY(fsys_bubble_down)
+GLOBAL_ENTRY(paravirt_fsys_bubble_down)
        .prologue
        .altrp b6
        .body
@@ -640,7 +641,7 @@ GLOBAL_ENTRY(fsys_bubble_down)
         *
         * PSR.BE : already is turned off in __kernel_syscall_via_epc()
         * PSR.AC : don't care (kernel normally turns PSR.AC on)
-        * PSR.I  : already turned off by the time fsys_bubble_down gets
+        * PSR.I  : already turned off by the time paravirt_fsys_bubble_down gets
         *          invoked
         * PSR.DFL: always 0 (kernel never turns it on)
         * PSR.DFH: don't care --- kernel never touches f32-f127 on its own
@@ -650,7 +651,7 @@ GLOBAL_ENTRY(fsys_bubble_down)
         * PSR.DB : don't care --- kernel never enables kernel-level
         *          breakpoints
         * PSR.TB : must be 0 already; if it wasn't zero on entry to
-        *          __kernel_syscall_via_epc, the branch to fsys_bubble_down
+        *          __kernel_syscall_via_epc, the branch to paravirt_fsys_bubble_down
         *          will trigger a taken branch; the taken-trap-handler then
         *          converts the syscall into a break-based system-call.
         */
@@ -683,7 +684,7 @@ GLOBAL_ENTRY(fsys_bubble_down)
        ;;
        mov ar.rsc=0                            // M2   set enforced lazy mode, pl 0, LE, loadrs=0
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-       mov.m r30=ar.itc                        // M    get cycle for accounting
+       MOV_FROM_ITC(p0, p6, r30, r23)          // M    get cycle for accounting
 #else
        nop.m 0
 #endif
@@ -734,21 +735,21 @@ GLOBAL_ENTRY(fsys_bubble_down)
        mov rp=r14                              // I0   set the real return addr
        and r3=_TIF_SYSCALL_TRACEAUDIT,r3       // A
        ;;
-       ssm psr.i                               // M2   we're on kernel stacks now, reenable irqs
+       SSM_PSR_I(p0, p6, r22)                  // M2   we're on kernel stacks now, reenable irqs
        cmp.eq p8,p0=r3,r0                      // A
 (p10)  br.cond.spnt.many ia64_ret_from_syscall // B    return if bad call-frame or r15 is a NaT
 
        nop.m 0
 (p8)   br.call.sptk.many b6=b6                 // B    (ignore return address)
        br.cond.spnt ia64_trace_syscall         // B
-END(fsys_bubble_down)
+END(paravirt_fsys_bubble_down)
 
        .rodata
        .align 8
-       .globl fsyscall_table
+       .globl paravirt_fsyscall_table
 
-       data8 fsys_bubble_down
-fsyscall_table:
+       data8 paravirt_fsys_bubble_down
+paravirt_fsyscall_table:
        data8 fsys_ni_syscall
        data8 0                         // exit                 // 1025
        data8 0                         // read
@@ -1033,4 +1034,4 @@ fsyscall_table:
 
        // fill in zeros for the remaining entries
        .zero:
-       .space fsyscall_table + 8*NR_syscalls - .zero, 0
+       .space paravirt_fsyscall_table + 8*NR_syscalls - .zero, 0
index 74b1ccce4e848187f59df741e944d3edf054f444..cf5e0a105e16521cf20f1fc6aa1957cf5af2e97f 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/sigcontext.h>
 #include <asm/system.h>
 #include <asm/unistd.h>
+#include "paravirt_inst.h"
 
 /*
  * We can't easily refer to symbols inside the kernel.  To avoid full runtime relocation,
@@ -48,87 +49,6 @@ GLOBAL_ENTRY(__kernel_syscall_via_break)
 }
 END(__kernel_syscall_via_break)
 
-/*
- * On entry:
- *     r11 = saved ar.pfs
- *     r15 = system call #
- *     b0  = saved return address
- *     b6  = return address
- * On exit:
- *     r11 = saved ar.pfs
- *     r15 = system call #
- *     b0  = saved return address
- *     all other "scratch" registers:  undefined
- *     all "preserved" registers:      same as on entry
- */
-
-GLOBAL_ENTRY(__kernel_syscall_via_epc)
-       .prologue
-       .altrp b6
-       .body
-{
-       /*
-        * Note: the kernel cannot assume that the first two instructions in this
-        * bundle get executed.  The remaining code must be safe even if
-        * they do not get executed.
-        */
-       adds r17=-1024,r15                      // A
-       mov r10=0                               // A    default to successful syscall execution
-       epc                                     // B    causes split-issue
-}
-       ;;
-       rsm psr.be | psr.i                      // M2 (5 cyc to srlz.d)
-       LOAD_FSYSCALL_TABLE(r14)                // X
-       ;;
-       mov r16=IA64_KR(CURRENT)                // M2 (12 cyc)
-       shladd r18=r17,3,r14                    // A
-       mov r19=NR_syscalls-1                   // A
-       ;;
-       lfetch [r18]                            // M0|1
-       mov r29=psr                             // M2 (12 cyc)
-       // If r17 is a NaT, p6 will be zero
-       cmp.geu p6,p7=r19,r17                   // A    (sysnr > 0 && sysnr < 1024+NR_syscalls)?
-       ;;
-       mov r21=ar.fpsr                         // M2 (12 cyc)
-       tnat.nz p10,p9=r15                      // I0
-       mov.i r26=ar.pfs                        // I0 (would stall anyhow due to srlz.d...)
-       ;;
-       srlz.d                                  // M0 (forces split-issue) ensure PSR.BE==0
-(p6)   ld8 r18=[r18]                           // M0|1
-       nop.i 0
-       ;;
-       nop.m 0
-(p6)   tbit.z.unc p8,p0=r18,0                  // I0 (dual-issues with "mov b7=r18"!)
-       nop.i 0
-       ;;
-(p8)   ssm psr.i
-(p6)   mov b7=r18                              // I0
-(p8)   br.dptk.many b7                         // B
-
-       mov r27=ar.rsc                          // M2 (12 cyc)
-/*
- * brl.cond doesn't work as intended because the linker would convert this branch
- * into a branch to a PLT.  Perhaps there will be a way to avoid this with some
- * future version of the linker.  In the meantime, we just use an indirect branch
- * instead.
- */
-#ifdef CONFIG_ITANIUM
-(p6)   add r14=-8,r14                          // r14 <- addr of fsys_bubble_down entry
-       ;;
-(p6)   ld8 r14=[r14]                           // r14 <- fsys_bubble_down
-       ;;
-(p6)   mov b7=r14
-(p6)   br.sptk.many b7
-#else
-       BRL_COND_FSYS_BUBBLE_DOWN(p6)
-#endif
-       ssm psr.i
-       mov r10=-1
-(p10)  mov r8=EINVAL
-(p9)   mov r8=ENOSYS
-       FSYS_RETURN
-END(__kernel_syscall_via_epc)
-
 #      define ARG0_OFF         (16 + IA64_SIGFRAME_ARG0_OFFSET)
 #      define ARG1_OFF         (16 + IA64_SIGFRAME_ARG1_OFFSET)
 #      define ARG2_OFF         (16 + IA64_SIGFRAME_ARG2_OFFSET)
@@ -374,3 +294,92 @@ restore_rbs:
        // invala not necessary as that will happen when returning to user-mode
        br.cond.sptk back_from_restore_rbs
 END(__kernel_sigtramp)
+
+/*
+ * On entry:
+ *     r11 = saved ar.pfs
+ *     r15 = system call #
+ *     b0  = saved return address
+ *     b6  = return address
+ * On exit:
+ *     r11 = saved ar.pfs
+ *     r15 = system call #
+ *     b0  = saved return address
+ *     all other "scratch" registers:  undefined
+ *     all "preserved" registers:      same as on entry
+ */
+
+GLOBAL_ENTRY(__kernel_syscall_via_epc)
+       .prologue
+       .altrp b6
+       .body
+{
+       /*
+        * Note: the kernel cannot assume that the first two instructions in this
+        * bundle get executed.  The remaining code must be safe even if
+        * they do not get executed.
+        */
+       adds r17=-1024,r15                      // A
+       mov r10=0                               // A    default to successful syscall execution
+       epc                                     // B    causes split-issue
+}
+       ;;
+       RSM_PSR_BE_I(r20, r22)                  // M2 (5 cyc to srlz.d)
+       LOAD_FSYSCALL_TABLE(r14)                // X
+       ;;
+       mov r16=IA64_KR(CURRENT)                // M2 (12 cyc)
+       shladd r18=r17,3,r14                    // A
+       mov r19=NR_syscalls-1                   // A
+       ;;
+       lfetch [r18]                            // M0|1
+       MOV_FROM_PSR(p0, r29, r8)               // M2 (12 cyc)
+       // If r17 is a NaT, p6 will be zero
+       cmp.geu p6,p7=r19,r17                   // A    (sysnr > 0 && sysnr < 1024+NR_syscalls)?
+       ;;
+       mov r21=ar.fpsr                         // M2 (12 cyc)
+       tnat.nz p10,p9=r15                      // I0
+       mov.i r26=ar.pfs                        // I0 (would stall anyhow due to srlz.d...)
+       ;;
+       srlz.d                                  // M0 (forces split-issue) ensure PSR.BE==0
+(p6)   ld8 r18=[r18]                           // M0|1
+       nop.i 0
+       ;;
+       nop.m 0
+(p6)   tbit.z.unc p8,p0=r18,0                  // I0 (dual-issues with "mov b7=r18"!)
+       nop.i 0
+       ;;
+       SSM_PSR_I(p8, p14, r25)
+(p6)   mov b7=r18                              // I0
+(p8)   br.dptk.many b7                         // B
+
+       mov r27=ar.rsc                          // M2 (12 cyc)
+/*
+ * brl.cond doesn't work as intended because the linker would convert this branch
+ * into a branch to a PLT.  Perhaps there will be a way to avoid this with some
+ * future version of the linker.  In the meantime, we just use an indirect branch
+ * instead.
+ */
+#ifdef CONFIG_ITANIUM
+(p6)   add r14=-8,r14                          // r14 <- addr of fsys_bubble_down entry
+       ;;
+(p6)   ld8 r14=[r14]                           // r14 <- fsys_bubble_down
+       ;;
+(p6)   mov b7=r14
+(p6)   br.sptk.many b7
+#else
+       BRL_COND_FSYS_BUBBLE_DOWN(p6)
+#endif
+       SSM_PSR_I(p0, p14, r10)
+       mov r10=-1
+(p10)  mov r8=EINVAL
+(p9)   mov r8=ENOSYS
+       FSYS_RETURN
+
+#ifdef CONFIG_PARAVIRT
+       /*
+        * padd to make the size of this symbol constant
+        * independent of paravirtualization.
+        */
+       .align PAGE_SIZE / 8
+#endif
+END(__kernel_syscall_via_epc)
index 3cb1abc00e24f585119def5e51cc72da0d47ea37..88c64ed47c36bb8d20e9166775bd14cc55f166ed 100644 (file)
@@ -7,6 +7,7 @@
 
 
 #include <asm/system.h>
+#include "paravirt_patchlist.h"
 
 SECTIONS
 {
@@ -33,21 +34,21 @@ SECTIONS
        . = GATE_ADDR + 0x600;
 
        .data.patch             : {
-               __start_gate_mckinley_e9_patchlist = .;
+               __paravirt_start_gate_mckinley_e9_patchlist = .;
                *(.data.patch.mckinley_e9)
-               __end_gate_mckinley_e9_patchlist = .;
+               __paravirt_end_gate_mckinley_e9_patchlist = .;
 
-               __start_gate_vtop_patchlist = .;
+               __paravirt_start_gate_vtop_patchlist = .;
                *(.data.patch.vtop)
-               __end_gate_vtop_patchlist = .;
+               __paravirt_end_gate_vtop_patchlist = .;
 
-               __start_gate_fsyscall_patchlist = .;
+               __paravirt_start_gate_fsyscall_patchlist = .;
                *(.data.patch.fsyscall_table)
-               __end_gate_fsyscall_patchlist = .;
+               __paravirt_end_gate_fsyscall_patchlist = .;
 
-               __start_gate_brl_fsys_bubble_down_patchlist = .;
+               __paravirt_start_gate_brl_fsys_bubble_down_patchlist = .;
                *(.data.patch.brl_fsys_bubble_down)
-               __end_gate_brl_fsys_bubble_down_patchlist = .;
+               __paravirt_end_gate_brl_fsys_bubble_down_patchlist = .;
        }                                               :readable
 
        .IA_64.unwind_info      : { *(.IA_64.unwind_info*) }
index 59301c4728009ecb410516fb0e737107eda42d67..23f846de62d58ae6e60a9c445911419daa4ff17f 100644 (file)
@@ -1050,7 +1050,7 @@ END(ia64_delay_loop)
  * except that the multiplication and the shift are done with 128-bit
  * intermediate precision so that we can produce a full 64-bit result.
  */
-GLOBAL_ENTRY(sched_clock)
+GLOBAL_ENTRY(ia64_native_sched_clock)
        addl r8=THIS_CPU(cpu_info) + IA64_CPUINFO_NSEC_PER_CYC_OFFSET,r0
        mov.m r9=ar.itc         // fetch cycle-counter                          (35 cyc)
        ;;
@@ -1066,7 +1066,13 @@ GLOBAL_ENTRY(sched_clock)
        ;;
        shrp r8=r9,r8,IA64_NSEC_PER_CYC_SHIFT
        br.ret.sptk.many rp
-END(sched_clock)
+END(ia64_native_sched_clock)
+#ifndef CONFIG_PARAVIRT
+       //unsigned long long
+       //sched_clock(void) __attribute__((alias("ia64_native_sched_clock")));
+       .global sched_clock
+sched_clock = ia64_native_sched_clock
+#endif
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 GLOBAL_ENTRY(cycle_to_cputime)
index f675d8e338533c5f2b47ce416a56624915835aa3..ec9a5fdfa1b9dc6e899fe690503bc8a4604cf4db 100644 (file)
@@ -804,7 +804,7 @@ ENTRY(break_fault)
 ///////////////////////////////////////////////////////////////////////
        st1 [r16]=r0                            // M2|3 clear current->thread.on_ustack flag
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-       mov.m r30=ar.itc                        // M    get cycle for accounting
+       MOV_FROM_ITC(p0, p14, r30, r18)         // M    get cycle for accounting
 #else
        mov b6=r30                              // I0   setup syscall handler branch reg early
 #endif
index 7ccb228ceedc337e90ae956ad3d1934e66c25bda..d41a40ef80c074575a5f5706011b22a563b4e99d 100644 (file)
@@ -1,5 +1,5 @@
 #include <linux/module.h>
-
+#include <linux/dma-mapping.h>
 #include <asm/machvec.h>
 #include <asm/system.h>
 
@@ -75,14 +75,16 @@ machvec_timer_interrupt (int irq, void *dev_id)
 EXPORT_SYMBOL(machvec_timer_interrupt);
 
 void
-machvec_dma_sync_single (struct device *hwdev, dma_addr_t dma_handle, size_t size, int dir)
+machvec_dma_sync_single(struct device *hwdev, dma_addr_t dma_handle, size_t size,
+                       enum dma_data_direction dir)
 {
        mb();
 }
 EXPORT_SYMBOL(machvec_dma_sync_single);
 
 void
-machvec_dma_sync_sg (struct device *hwdev, struct scatterlist *sg, int n, int dir)
+machvec_dma_sync_sg(struct device *hwdev, struct scatterlist *sg, int n,
+                   enum dma_data_direction dir)
 {
        mb();
 }
index bab1de2d2f6a0920f40c76a5c36359d56ed2af87..8f33a8840422ce96bc1a6df85f4876e0f5180b1d 100644 (file)
@@ -1456,9 +1456,9 @@ ia64_mca_cmc_int_caller(int cmc_irq, void *arg)
 
        ia64_mca_cmc_int_handler(cmc_irq, arg);
 
-       for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++);
+       cpuid = cpumask_next(cpuid+1, cpu_online_mask);
 
-       if (cpuid < NR_CPUS) {
+       if (cpuid < nr_cpu_ids) {
                platform_send_ipi(cpuid, IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0);
        } else {
                /* If no log record, switch out of polling mode */
@@ -1525,7 +1525,7 @@ ia64_mca_cpe_int_caller(int cpe_irq, void *arg)
 
        ia64_mca_cpe_int_handler(cpe_irq, arg);
 
-       for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++);
+       cpuid = cpumask_next(cpuid+1, cpu_online_mask);
 
        if (cpuid < NR_CPUS) {
                platform_send_ipi(cpuid, IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0);
index aaa7d901521fd7590e3132a68b65ffd995197551..da3b0cf495a36a27d80c5befab84f7a7f2f84e94 100644 (file)
@@ -446,6 +446,14 @@ module_frob_arch_sections (Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings,
                        mod->arch.opd = s;
                else if (strcmp(".IA_64.unwind", secstrings + s->sh_name) == 0)
                        mod->arch.unwind = s;
+#ifdef CONFIG_PARAVIRT
+               else if (strcmp(".paravirt_bundles",
+                               secstrings + s->sh_name) == 0)
+                       mod->arch.paravirt_bundles = s;
+               else if (strcmp(".paravirt_insts",
+                               secstrings + s->sh_name) == 0)
+                       mod->arch.paravirt_insts = s;
+#endif
 
        if (!mod->arch.core_plt || !mod->arch.init_plt || !mod->arch.got || !mod->arch.opd) {
                printk(KERN_ERR "%s: sections missing\n", mod->name);
@@ -525,8 +533,7 @@ get_ltoff (struct module *mod, uint64_t value, int *okp)
                        goto found;
 
        /* Not enough GOT entries? */
-       if (e >= (struct got_entry *) (mod->arch.got->sh_addr + mod->arch.got->sh_size))
-               BUG();
+       BUG_ON(e >= (struct got_entry *) (mod->arch.got->sh_addr + mod->arch.got->sh_size));
 
        e->val = value;
        ++mod->arch.next_got_entry;
@@ -921,6 +928,30 @@ module_finalize (const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mo
        DEBUGP("%s: init: entry=%p\n", __func__, mod->init);
        if (mod->arch.unwind)
                register_unwind_table(mod);
+#ifdef CONFIG_PARAVIRT
+        if (mod->arch.paravirt_bundles) {
+                struct paravirt_patch_site_bundle *start =
+                        (struct paravirt_patch_site_bundle *)
+                        mod->arch.paravirt_bundles->sh_addr;
+                struct paravirt_patch_site_bundle *end =
+                        (struct paravirt_patch_site_bundle *)
+                        (mod->arch.paravirt_bundles->sh_addr +
+                         mod->arch.paravirt_bundles->sh_size);
+
+                paravirt_patch_apply_bundle(start, end);
+        }
+        if (mod->arch.paravirt_insts) {
+                struct paravirt_patch_site_inst *start =
+                        (struct paravirt_patch_site_inst *)
+                        mod->arch.paravirt_insts->sh_addr;
+                struct paravirt_patch_site_inst *end =
+                        (struct paravirt_patch_site_inst *)
+                        (mod->arch.paravirt_insts->sh_addr +
+                         mod->arch.paravirt_insts->sh_size);
+
+                paravirt_patch_apply_inst(start, end);
+        }
+#endif
        return 0;
 }
 
index e5c57f413ca27b197ef0edeb2166efde99d113cb..a4f19c70aadd39d95878740ecc92905c94d4270e 100644 (file)
@@ -1002,8 +1002,6 @@ create_palinfo_proc_entries(unsigned int cpu)
                *pdir = create_proc_read_entry(
                                palinfo_entries[j].name, 0, cpu_dir,
                                palinfo_read_entry, (void *)f.value);
-               if (*pdir)
-                       (*pdir)->owner = THIS_MODULE;
                pdir++;
        }
 }
index 9f14c16f63693794445645753ff6d61443151b61..a21d7bb9c69c8f11eaddabf62df77ee672cbf426 100644 (file)
@@ -46,13 +46,23 @@ struct pv_info pv_info = {
  * initialization hooks.
  */
 
-struct pv_init_ops pv_init_ops;
+static void __init
+ia64_native_patch_branch(unsigned long tag, unsigned long type);
+
+struct pv_init_ops pv_init_ops =
+{
+#ifdef ASM_SUPPORTED
+       .patch_bundle = ia64_native_patch_bundle,
+#endif
+       .patch_branch = ia64_native_patch_branch,
+};
 
 /***************************************************************************
  * pv_cpu_ops
  * intrinsics hooks.
  */
 
+#ifndef ASM_SUPPORTED
 /* ia64_native_xxx are macros so that we have to make them real functions */
 
 #define DEFINE_VOID_FUNC1(name)                                        \
@@ -60,7 +70,14 @@ struct pv_init_ops pv_init_ops;
        ia64_native_ ## name ## _func(unsigned long arg)        \
        {                                                       \
                ia64_native_ ## name(arg);                      \
-       }                                                       \
+       }
+
+#define DEFINE_VOID_FUNC1_VOID(name)                           \
+       static void                                             \
+       ia64_native_ ## name ## _func(void *arg)                \
+       {                                                       \
+               ia64_native_ ## name(arg);                      \
+       }
 
 #define DEFINE_VOID_FUNC2(name)                                        \
        static void                                             \
@@ -68,7 +85,7 @@ struct pv_init_ops pv_init_ops;
                                      unsigned long arg1)       \
        {                                                       \
                ia64_native_ ## name(arg0, arg1);               \
-       }                                                       \
+       }
 
 #define DEFINE_FUNC0(name)                     \
        static unsigned long                    \
@@ -84,7 +101,7 @@ struct pv_init_ops pv_init_ops;
                return ia64_native_ ## name(arg);       \
        }                                               \
 
-DEFINE_VOID_FUNC1(fc);
+DEFINE_VOID_FUNC1_VOID(fc);
 DEFINE_VOID_FUNC1(intrin_local_irq_restore);
 
 DEFINE_VOID_FUNC2(ptcga);
@@ -274,6 +291,266 @@ ia64_native_setreg_func(int regnum, unsigned long val)
                break;
        }
 }
+#else
+
+#define __DEFINE_FUNC(name, code)                                      \
+       extern const char ia64_native_ ## name ## _direct_start[];      \
+       extern const char ia64_native_ ## name ## _direct_end[];        \
+       asm (".align 32\n"                                              \
+            ".proc ia64_native_" #name "_func\n"                       \
+            "ia64_native_" #name "_func:\n"                            \
+            "ia64_native_" #name "_direct_start:\n"                    \
+            code                                                       \
+            "ia64_native_" #name "_direct_end:\n"                      \
+            "br.cond.sptk.many b6\n"                                   \
+            ".endp ia64_native_" #name "_func\n")
+
+#define DEFINE_VOID_FUNC0(name, code)                          \
+       extern void                                             \
+       ia64_native_ ## name ## _func(void);                    \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_VOID_FUNC1(name, code)                          \
+       extern void                                             \
+       ia64_native_ ## name ## _func(unsigned long arg);       \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_VOID_FUNC1_VOID(name, code)                     \
+       extern void                                             \
+       ia64_native_ ## name ## _func(void *arg);               \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_VOID_FUNC2(name, code)                          \
+       extern void                                             \
+       ia64_native_ ## name ## _func(unsigned long arg0,       \
+                                     unsigned long arg1);      \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_FUNC0(name, code)               \
+       extern unsigned long                    \
+       ia64_native_ ## name ## _func(void);    \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_FUNC1(name, type, code)                 \
+       extern unsigned long                            \
+       ia64_native_ ## name ## _func(type arg);        \
+       __DEFINE_FUNC(name, code)
+
+DEFINE_VOID_FUNC1_VOID(fc,
+                      "fc r8\n");
+DEFINE_VOID_FUNC1(intrin_local_irq_restore,
+                 ";;\n"
+                 "     cmp.ne p6, p7 = r8, r0\n"
+                 ";;\n"
+                 "(p6) ssm psr.i\n"
+                 "(p7) rsm psr.i\n"
+                 ";;\n"
+                 "(p6) srlz.d\n");
+
+DEFINE_VOID_FUNC2(ptcga,
+                 "ptc.ga r8, r9\n");
+DEFINE_VOID_FUNC2(set_rr,
+                 "mov rr[r8] = r9\n");
+
+/* ia64_native_getreg(_IA64_REG_PSR) & IA64_PSR_I */
+DEFINE_FUNC0(get_psr_i,
+            "mov r2 = " __stringify(1 << IA64_PSR_I_BIT) "\n"
+            "mov r8 = psr\n"
+            ";;\n"
+            "and r8 = r2, r8\n");
+
+DEFINE_FUNC1(thash, unsigned long,
+            "thash r8 = r8\n");
+DEFINE_FUNC1(get_cpuid, int,
+            "mov r8 = cpuid[r8]\n");
+DEFINE_FUNC1(get_pmd, int,
+            "mov r8 = pmd[r8]\n");
+DEFINE_FUNC1(get_rr, unsigned long,
+            "mov r8 = rr[r8]\n");
+
+DEFINE_VOID_FUNC0(ssm_i,
+                 "ssm psr.i\n");
+DEFINE_VOID_FUNC0(rsm_i,
+                 "rsm psr.i\n");
+
+extern void
+ia64_native_set_rr0_to_rr4_func(unsigned long val0, unsigned long val1,
+                               unsigned long val2, unsigned long val3,
+                               unsigned long val4);
+__DEFINE_FUNC(set_rr0_to_rr4,
+             "mov rr[r0] = r8\n"
+             "movl r2 = 0x2000000000000000\n"
+             ";;\n"
+             "mov rr[r2] = r9\n"
+             "shl r3 = r2, 1\n"        /* movl r3 = 0x4000000000000000 */
+             ";;\n"
+             "add r2 = r2, r3\n"       /* movl r2 = 0x6000000000000000 */
+             "mov rr[r3] = r10\n"
+             ";;\n"
+             "mov rr[r2] = r11\n"
+             "shl r3 = r3, 1\n"        /* movl r3 = 0x8000000000000000 */
+             ";;\n"
+             "mov rr[r3] = r14\n");
+
+extern unsigned long ia64_native_getreg_func(int regnum);
+asm(".global ia64_native_getreg_func\n");
+#define __DEFINE_GET_REG(id, reg)                      \
+       "mov r2 = " __stringify(_IA64_REG_ ## id) "\n"  \
+       ";;\n"                                          \
+       "cmp.eq p6, p0 = r2, r8\n"                      \
+       ";;\n"                                          \
+       "(p6) mov r8 = " #reg "\n"                      \
+       "(p6) br.cond.sptk.many b6\n"                   \
+       ";;\n"
+#define __DEFINE_GET_AR(id, reg)       __DEFINE_GET_REG(AR_ ## id, ar.reg)
+#define __DEFINE_GET_CR(id, reg)       __DEFINE_GET_REG(CR_ ## id, cr.reg)
+
+__DEFINE_FUNC(getreg,
+             __DEFINE_GET_REG(GP, gp)
+             /*__DEFINE_GET_REG(IP, ip)*/ /* returned ip value shouldn't be constant */
+             __DEFINE_GET_REG(PSR, psr)
+             __DEFINE_GET_REG(TP, tp)
+             __DEFINE_GET_REG(SP, sp)
+
+             __DEFINE_GET_REG(AR_KR0, ar0)
+             __DEFINE_GET_REG(AR_KR1, ar1)
+             __DEFINE_GET_REG(AR_KR2, ar2)
+             __DEFINE_GET_REG(AR_KR3, ar3)
+             __DEFINE_GET_REG(AR_KR4, ar4)
+             __DEFINE_GET_REG(AR_KR5, ar5)
+             __DEFINE_GET_REG(AR_KR6, ar6)
+             __DEFINE_GET_REG(AR_KR7, ar7)
+             __DEFINE_GET_AR(RSC, rsc)
+             __DEFINE_GET_AR(BSP, bsp)
+             __DEFINE_GET_AR(BSPSTORE, bspstore)
+             __DEFINE_GET_AR(RNAT, rnat)
+             __DEFINE_GET_AR(FCR, fcr)
+             __DEFINE_GET_AR(EFLAG, eflag)
+             __DEFINE_GET_AR(CSD, csd)
+             __DEFINE_GET_AR(SSD, ssd)
+             __DEFINE_GET_REG(AR_CFLAG, ar27)
+             __DEFINE_GET_AR(FSR, fsr)
+             __DEFINE_GET_AR(FIR, fir)
+             __DEFINE_GET_AR(FDR, fdr)
+             __DEFINE_GET_AR(CCV, ccv)
+             __DEFINE_GET_AR(UNAT, unat)
+             __DEFINE_GET_AR(FPSR, fpsr)
+             __DEFINE_GET_AR(ITC, itc)
+             __DEFINE_GET_AR(PFS, pfs)
+             __DEFINE_GET_AR(LC, lc)
+             __DEFINE_GET_AR(EC, ec)
+
+             __DEFINE_GET_CR(DCR, dcr)
+             __DEFINE_GET_CR(ITM, itm)
+             __DEFINE_GET_CR(IVA, iva)
+             __DEFINE_GET_CR(PTA, pta)
+             __DEFINE_GET_CR(IPSR, ipsr)
+             __DEFINE_GET_CR(ISR, isr)
+             __DEFINE_GET_CR(IIP, iip)
+             __DEFINE_GET_CR(IFA, ifa)
+             __DEFINE_GET_CR(ITIR, itir)
+             __DEFINE_GET_CR(IIPA, iipa)
+             __DEFINE_GET_CR(IFS, ifs)
+             __DEFINE_GET_CR(IIM, iim)
+             __DEFINE_GET_CR(IHA, iha)
+             __DEFINE_GET_CR(LID, lid)
+             __DEFINE_GET_CR(IVR, ivr)
+             __DEFINE_GET_CR(TPR, tpr)
+             __DEFINE_GET_CR(EOI, eoi)
+             __DEFINE_GET_CR(IRR0, irr0)
+             __DEFINE_GET_CR(IRR1, irr1)
+             __DEFINE_GET_CR(IRR2, irr2)
+             __DEFINE_GET_CR(IRR3, irr3)
+             __DEFINE_GET_CR(ITV, itv)
+             __DEFINE_GET_CR(PMV, pmv)
+             __DEFINE_GET_CR(CMCV, cmcv)
+             __DEFINE_GET_CR(LRR0, lrr0)
+             __DEFINE_GET_CR(LRR1, lrr1)
+
+             "mov r8 = -1\n"   /* unsupported case */
+       );
+
+extern void ia64_native_setreg_func(int regnum, unsigned long val);
+asm(".global ia64_native_setreg_func\n");
+#define __DEFINE_SET_REG(id, reg)                      \
+       "mov r2 = " __stringify(_IA64_REG_ ## id) "\n"  \
+       ";;\n"                                          \
+       "cmp.eq p6, p0 = r2, r9\n"                      \
+       ";;\n"                                          \
+       "(p6) mov " #reg " = r8\n"                      \
+       "(p6) br.cond.sptk.many b6\n"                   \
+       ";;\n"
+#define __DEFINE_SET_AR(id, reg)       __DEFINE_SET_REG(AR_ ## id, ar.reg)
+#define __DEFINE_SET_CR(id, reg)       __DEFINE_SET_REG(CR_ ## id, cr.reg)
+__DEFINE_FUNC(setreg,
+             "mov r2 = " __stringify(_IA64_REG_PSR_L) "\n"
+             ";;\n"
+             "cmp.eq p6, p0 = r2, r9\n"
+             ";;\n"
+             "(p6) mov psr.l = r8\n"
+#ifdef HAVE_SERIALIZE_DIRECTIVE
+             ".serialize.data\n"
+#endif
+             "(p6) br.cond.sptk.many b6\n"
+             __DEFINE_SET_REG(GP, gp)
+             __DEFINE_SET_REG(SP, sp)
+
+             __DEFINE_SET_REG(AR_KR0, ar0)
+             __DEFINE_SET_REG(AR_KR1, ar1)
+             __DEFINE_SET_REG(AR_KR2, ar2)
+             __DEFINE_SET_REG(AR_KR3, ar3)
+             __DEFINE_SET_REG(AR_KR4, ar4)
+             __DEFINE_SET_REG(AR_KR5, ar5)
+             __DEFINE_SET_REG(AR_KR6, ar6)
+             __DEFINE_SET_REG(AR_KR7, ar7)
+             __DEFINE_SET_AR(RSC, rsc)
+             __DEFINE_SET_AR(BSP, bsp)
+             __DEFINE_SET_AR(BSPSTORE, bspstore)
+             __DEFINE_SET_AR(RNAT, rnat)
+             __DEFINE_SET_AR(FCR, fcr)
+             __DEFINE_SET_AR(EFLAG, eflag)
+             __DEFINE_SET_AR(CSD, csd)
+             __DEFINE_SET_AR(SSD, ssd)
+             __DEFINE_SET_REG(AR_CFLAG, ar27)
+             __DEFINE_SET_AR(FSR, fsr)
+             __DEFINE_SET_AR(FIR, fir)
+             __DEFINE_SET_AR(FDR, fdr)
+             __DEFINE_SET_AR(CCV, ccv)
+             __DEFINE_SET_AR(UNAT, unat)
+             __DEFINE_SET_AR(FPSR, fpsr)
+             __DEFINE_SET_AR(ITC, itc)
+             __DEFINE_SET_AR(PFS, pfs)
+             __DEFINE_SET_AR(LC, lc)
+             __DEFINE_SET_AR(EC, ec)
+
+             __DEFINE_SET_CR(DCR, dcr)
+             __DEFINE_SET_CR(ITM, itm)
+             __DEFINE_SET_CR(IVA, iva)
+             __DEFINE_SET_CR(PTA, pta)
+             __DEFINE_SET_CR(IPSR, ipsr)
+             __DEFINE_SET_CR(ISR, isr)
+             __DEFINE_SET_CR(IIP, iip)
+             __DEFINE_SET_CR(IFA, ifa)
+             __DEFINE_SET_CR(ITIR, itir)
+             __DEFINE_SET_CR(IIPA, iipa)
+             __DEFINE_SET_CR(IFS, ifs)
+             __DEFINE_SET_CR(IIM, iim)
+             __DEFINE_SET_CR(IHA, iha)
+             __DEFINE_SET_CR(LID, lid)
+             __DEFINE_SET_CR(IVR, ivr)
+             __DEFINE_SET_CR(TPR, tpr)
+             __DEFINE_SET_CR(EOI, eoi)
+             __DEFINE_SET_CR(IRR0, irr0)
+             __DEFINE_SET_CR(IRR1, irr1)
+             __DEFINE_SET_CR(IRR2, irr2)
+             __DEFINE_SET_CR(IRR3, irr3)
+             __DEFINE_SET_CR(ITV, itv)
+             __DEFINE_SET_CR(PMV, pmv)
+             __DEFINE_SET_CR(CMCV, cmcv)
+             __DEFINE_SET_CR(LRR0, lrr0)
+             __DEFINE_SET_CR(LRR1, lrr1)
+       );
+#endif
 
 struct pv_cpu_ops pv_cpu_ops = {
        .fc             = ia64_native_fc_func,
@@ -366,4 +643,258 @@ ia64_native_do_steal_accounting(unsigned long *new_itm)
 
 struct pv_time_ops pv_time_ops = {
        .do_steal_accounting = ia64_native_do_steal_accounting,
+       .sched_clock = ia64_native_sched_clock,
+};
+
+/***************************************************************************
+ * binary pacthing
+ * pv_init_ops.patch_bundle
+ */
+
+#ifdef ASM_SUPPORTED
+#define IA64_NATIVE_PATCH_DEFINE_GET_REG(name, reg)    \
+       __DEFINE_FUNC(get_ ## name,                     \
+                     ";;\n"                            \
+                     "mov r8 = " #reg "\n"             \
+                     ";;\n")
+
+#define IA64_NATIVE_PATCH_DEFINE_SET_REG(name, reg)    \
+       __DEFINE_FUNC(set_ ## name,                     \
+                     ";;\n"                            \
+                     "mov " #reg " = r8\n"             \
+                     ";;\n")
+
+#define IA64_NATIVE_PATCH_DEFINE_REG(name, reg)                \
+       IA64_NATIVE_PATCH_DEFINE_GET_REG(name, reg);    \
+       IA64_NATIVE_PATCH_DEFINE_SET_REG(name, reg)     \
+
+#define IA64_NATIVE_PATCH_DEFINE_AR(name, reg)                 \
+       IA64_NATIVE_PATCH_DEFINE_REG(ar_ ## name, ar.reg)
+
+#define IA64_NATIVE_PATCH_DEFINE_CR(name, reg)                 \
+       IA64_NATIVE_PATCH_DEFINE_REG(cr_ ## name, cr.reg)
+
+
+IA64_NATIVE_PATCH_DEFINE_GET_REG(psr, psr);
+IA64_NATIVE_PATCH_DEFINE_GET_REG(tp, tp);
+
+/* IA64_NATIVE_PATCH_DEFINE_SET_REG(psr_l, psr.l); */
+__DEFINE_FUNC(set_psr_l,
+             ";;\n"
+             "mov psr.l = r8\n"
+#ifdef HAVE_SERIALIZE_DIRECTIVE
+             ".serialize.data\n"
+#endif
+             ";;\n");
+
+IA64_NATIVE_PATCH_DEFINE_REG(gp, gp);
+IA64_NATIVE_PATCH_DEFINE_REG(sp, sp);
+
+IA64_NATIVE_PATCH_DEFINE_REG(kr0, ar0);
+IA64_NATIVE_PATCH_DEFINE_REG(kr1, ar1);
+IA64_NATIVE_PATCH_DEFINE_REG(kr2, ar2);
+IA64_NATIVE_PATCH_DEFINE_REG(kr3, ar3);
+IA64_NATIVE_PATCH_DEFINE_REG(kr4, ar4);
+IA64_NATIVE_PATCH_DEFINE_REG(kr5, ar5);
+IA64_NATIVE_PATCH_DEFINE_REG(kr6, ar6);
+IA64_NATIVE_PATCH_DEFINE_REG(kr7, ar7);
+
+IA64_NATIVE_PATCH_DEFINE_AR(rsc, rsc);
+IA64_NATIVE_PATCH_DEFINE_AR(bsp, bsp);
+IA64_NATIVE_PATCH_DEFINE_AR(bspstore, bspstore);
+IA64_NATIVE_PATCH_DEFINE_AR(rnat, rnat);
+IA64_NATIVE_PATCH_DEFINE_AR(fcr, fcr);
+IA64_NATIVE_PATCH_DEFINE_AR(eflag, eflag);
+IA64_NATIVE_PATCH_DEFINE_AR(csd, csd);
+IA64_NATIVE_PATCH_DEFINE_AR(ssd, ssd);
+IA64_NATIVE_PATCH_DEFINE_REG(ar27, ar27);
+IA64_NATIVE_PATCH_DEFINE_AR(fsr, fsr);
+IA64_NATIVE_PATCH_DEFINE_AR(fir, fir);
+IA64_NATIVE_PATCH_DEFINE_AR(fdr, fdr);
+IA64_NATIVE_PATCH_DEFINE_AR(ccv, ccv);
+IA64_NATIVE_PATCH_DEFINE_AR(unat, unat);
+IA64_NATIVE_PATCH_DEFINE_AR(fpsr, fpsr);
+IA64_NATIVE_PATCH_DEFINE_AR(itc, itc);
+IA64_NATIVE_PATCH_DEFINE_AR(pfs, pfs);
+IA64_NATIVE_PATCH_DEFINE_AR(lc, lc);
+IA64_NATIVE_PATCH_DEFINE_AR(ec, ec);
+
+IA64_NATIVE_PATCH_DEFINE_CR(dcr, dcr);
+IA64_NATIVE_PATCH_DEFINE_CR(itm, itm);
+IA64_NATIVE_PATCH_DEFINE_CR(iva, iva);
+IA64_NATIVE_PATCH_DEFINE_CR(pta, pta);
+IA64_NATIVE_PATCH_DEFINE_CR(ipsr, ipsr);
+IA64_NATIVE_PATCH_DEFINE_CR(isr, isr);
+IA64_NATIVE_PATCH_DEFINE_CR(iip, iip);
+IA64_NATIVE_PATCH_DEFINE_CR(ifa, ifa);
+IA64_NATIVE_PATCH_DEFINE_CR(itir, itir);
+IA64_NATIVE_PATCH_DEFINE_CR(iipa, iipa);
+IA64_NATIVE_PATCH_DEFINE_CR(ifs, ifs);
+IA64_NATIVE_PATCH_DEFINE_CR(iim, iim);
+IA64_NATIVE_PATCH_DEFINE_CR(iha, iha);
+IA64_NATIVE_PATCH_DEFINE_CR(lid, lid);
+IA64_NATIVE_PATCH_DEFINE_CR(ivr, ivr);
+IA64_NATIVE_PATCH_DEFINE_CR(tpr, tpr);
+IA64_NATIVE_PATCH_DEFINE_CR(eoi, eoi);
+IA64_NATIVE_PATCH_DEFINE_CR(irr0, irr0);
+IA64_NATIVE_PATCH_DEFINE_CR(irr1, irr1);
+IA64_NATIVE_PATCH_DEFINE_CR(irr2, irr2);
+IA64_NATIVE_PATCH_DEFINE_CR(irr3, irr3);
+IA64_NATIVE_PATCH_DEFINE_CR(itv, itv);
+IA64_NATIVE_PATCH_DEFINE_CR(pmv, pmv);
+IA64_NATIVE_PATCH_DEFINE_CR(cmcv, cmcv);
+IA64_NATIVE_PATCH_DEFINE_CR(lrr0, lrr0);
+IA64_NATIVE_PATCH_DEFINE_CR(lrr1, lrr1);
+
+static const struct paravirt_patch_bundle_elem ia64_native_patch_bundle_elems[]
+__initdata_or_module =
+{
+#define IA64_NATIVE_PATCH_BUNDLE_ELEM(name, type)              \
+       {                                                       \
+               (void*)ia64_native_ ## name ## _direct_start,   \
+               (void*)ia64_native_ ## name ## _direct_end,     \
+               PARAVIRT_PATCH_TYPE_ ## type,                   \
+       }
+
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(fc, FC),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(thash, THASH),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(get_cpuid, GET_CPUID),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(get_pmd, GET_PMD),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(ptcga, PTCGA),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(get_rr, GET_RR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(set_rr, SET_RR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(set_rr0_to_rr4, SET_RR0_TO_RR4),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(ssm_i, SSM_I),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(rsm_i, RSM_I),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(get_psr_i, GET_PSR_I),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(intrin_local_irq_restore,
+                                     INTRIN_LOCAL_IRQ_RESTORE),
+
+#define IA64_NATIVE_PATCH_BUNDLE_ELEM_GETREG(name, reg)                        \
+       {                                                               \
+               (void*)ia64_native_get_ ## name ## _direct_start,       \
+               (void*)ia64_native_get_ ## name ## _direct_end,         \
+               PARAVIRT_PATCH_TYPE_GETREG + _IA64_REG_ ## reg,         \
+       }
+
+#define IA64_NATIVE_PATCH_BUNDLE_ELEM_SETREG(name, reg)                        \
+       {                                                               \
+               (void*)ia64_native_set_ ## name ## _direct_start,       \
+               (void*)ia64_native_set_ ## name ## _direct_end,         \
+               PARAVIRT_PATCH_TYPE_SETREG + _IA64_REG_ ## reg,         \
+       }
+
+#define IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(name, reg)           \
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_GETREG(name, reg),        \
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_SETREG(name, reg)         \
+
+#define IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(name, reg)            \
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(ar_ ## name, AR_ ## reg)
+
+#define IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(name, reg)            \
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(cr_ ## name, CR_ ## reg)
+
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_GETREG(psr, PSR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_GETREG(tp, TP),
+
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_SETREG(psr_l, PSR_L),
+
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(gp, GP),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(sp, SP),
+
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr0, AR_KR0),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr1, AR_KR1),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr2, AR_KR2),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr3, AR_KR3),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr4, AR_KR4),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr5, AR_KR5),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr6, AR_KR6),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr7, AR_KR7),
+
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(rsc, RSC),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(bsp, BSP),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(bspstore, BSPSTORE),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(rnat, RNAT),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(fcr, FCR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(eflag, EFLAG),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(csd, CSD),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(ssd, SSD),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(ar27, AR_CFLAG),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(fsr, FSR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(fir, FIR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(fdr, FDR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(ccv, CCV),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(unat, UNAT),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(fpsr, FPSR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(itc, ITC),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(pfs, PFS),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(lc, LC),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(ec, EC),
+
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(dcr, DCR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(itm, ITM),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(iva, IVA),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(pta, PTA),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(ipsr, IPSR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(isr, ISR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(iip, IIP),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(ifa, IFA),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(itir, ITIR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(iipa, IIPA),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(ifs, IFS),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(iim, IIM),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(iha, IHA),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(lid, LID),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(ivr, IVR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(tpr, TPR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(eoi, EOI),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(irr0, IRR0),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(irr1, IRR1),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(irr2, IRR2),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(irr3, IRR3),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(itv, ITV),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(pmv, PMV),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(cmcv, CMCV),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(lrr0, LRR0),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(lrr1, LRR1),
 };
+
+unsigned long __init_or_module
+ia64_native_patch_bundle(void *sbundle, void *ebundle, unsigned long type)
+{
+       const unsigned long nelems = sizeof(ia64_native_patch_bundle_elems) /
+               sizeof(ia64_native_patch_bundle_elems[0]);
+
+       return __paravirt_patch_apply_bundle(sbundle, ebundle, type,
+                                             ia64_native_patch_bundle_elems,
+                                             nelems, NULL);
+}
+#endif /* ASM_SUPPOTED */
+
+extern const char ia64_native_switch_to[];
+extern const char ia64_native_leave_syscall[];
+extern const char ia64_native_work_processed_syscall[];
+extern const char ia64_native_leave_kernel[];
+
+const struct paravirt_patch_branch_target ia64_native_branch_target[]
+__initconst = {
+#define PARAVIRT_BR_TARGET(name, type)                 \
+       {                                               \
+               ia64_native_ ## name,                   \
+               PARAVIRT_PATCH_TYPE_BR_ ## type,        \
+       }
+       PARAVIRT_BR_TARGET(switch_to, SWITCH_TO),
+       PARAVIRT_BR_TARGET(leave_syscall, LEAVE_SYSCALL),
+       PARAVIRT_BR_TARGET(work_processed_syscall, WORK_PROCESSED_SYSCALL),
+       PARAVIRT_BR_TARGET(leave_kernel, LEAVE_KERNEL),
+};
+
+static void __init
+ia64_native_patch_branch(unsigned long tag, unsigned long type)
+{
+       const unsigned long nelem =
+               sizeof(ia64_native_branch_target) /
+               sizeof(ia64_native_branch_target[0]);
+       __paravirt_patch_apply_branch(tag, type,
+                                     ia64_native_branch_target, nelem);
+}
diff --git a/arch/ia64/kernel/paravirt_patch.c b/arch/ia64/kernel/paravirt_patch.c
new file mode 100644 (file)
index 0000000..bfdfef1
--- /dev/null
@@ -0,0 +1,514 @@
+/******************************************************************************
+ * linux/arch/ia64/xen/paravirt_patch.c
+ *
+ * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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/init.h>
+#include <asm/intrinsics.h>
+#include <asm/kprobes.h>
+#include <asm/paravirt.h>
+#include <asm/paravirt_patch.h>
+
+typedef union ia64_inst {
+        struct {
+               unsigned long long qp : 6;
+               unsigned long long : 31;
+               unsigned long long opcode : 4;
+               unsigned long long reserved : 23;
+        } generic;
+        unsigned long long l;
+} ia64_inst_t;
+
+/*
+ * flush_icache_range() can't be used here.
+ * we are here before cpu_init() which initializes
+ * ia64_i_cache_stride_shift. flush_icache_range() uses it.
+ */
+void __init_or_module
+paravirt_flush_i_cache_range(const void *instr, unsigned long size)
+{
+       extern void paravirt_fc_i(const void *addr);
+       unsigned long i;
+
+       for (i = 0; i < size; i += sizeof(bundle_t))
+               paravirt_fc_i(instr + i);
+}
+
+bundle_t* __init_or_module
+paravirt_get_bundle(unsigned long tag)
+{
+       return (bundle_t *)(tag & ~3UL);
+}
+
+unsigned long __init_or_module
+paravirt_get_slot(unsigned long tag)
+{
+       return tag & 3UL;
+}
+
+unsigned long __init_or_module
+paravirt_get_num_inst(unsigned long stag, unsigned long etag)
+{
+       bundle_t *sbundle = paravirt_get_bundle(stag);
+       unsigned long sslot = paravirt_get_slot(stag);
+       bundle_t *ebundle = paravirt_get_bundle(etag);
+       unsigned long eslot = paravirt_get_slot(etag);
+
+       return (ebundle - sbundle) * 3 + eslot - sslot + 1;
+}
+
+unsigned long __init_or_module
+paravirt_get_next_tag(unsigned long tag)
+{
+       unsigned long slot = paravirt_get_slot(tag);
+
+       switch (slot) {
+       case 0:
+       case 1:
+               return tag + 1;
+       case 2: {
+               bundle_t *bundle = paravirt_get_bundle(tag);
+               return (unsigned long)(bundle + 1);
+       }
+       default:
+               BUG();
+       }
+       /* NOTREACHED */
+}
+
+ia64_inst_t __init_or_module
+paravirt_read_slot0(const bundle_t *bundle)
+{
+       ia64_inst_t inst;
+       inst.l = bundle->quad0.slot0;
+       return inst;
+}
+
+ia64_inst_t __init_or_module
+paravirt_read_slot1(const bundle_t *bundle)
+{
+       ia64_inst_t inst;
+       inst.l = bundle->quad0.slot1_p0 |
+               ((unsigned long long)bundle->quad1.slot1_p1 << 18UL);
+       return inst;
+}
+
+ia64_inst_t __init_or_module
+paravirt_read_slot2(const bundle_t *bundle)
+{
+       ia64_inst_t inst;
+       inst.l = bundle->quad1.slot2;
+       return inst;
+}
+
+ia64_inst_t __init_or_module
+paravirt_read_inst(unsigned long tag)
+{
+       bundle_t *bundle = paravirt_get_bundle(tag);
+       unsigned long slot = paravirt_get_slot(tag);
+
+       switch (slot) {
+       case 0:
+               return paravirt_read_slot0(bundle);
+       case 1:
+               return paravirt_read_slot1(bundle);
+       case 2:
+               return paravirt_read_slot2(bundle);
+       default:
+               BUG();
+       }
+       /* NOTREACHED */
+}
+
+void __init_or_module
+paravirt_write_slot0(bundle_t *bundle, ia64_inst_t inst)
+{
+       bundle->quad0.slot0 = inst.l;
+}
+
+void __init_or_module
+paravirt_write_slot1(bundle_t *bundle, ia64_inst_t inst)
+{
+       bundle->quad0.slot1_p0 = inst.l;
+       bundle->quad1.slot1_p1 = inst.l >> 18UL;
+}
+
+void __init_or_module
+paravirt_write_slot2(bundle_t *bundle, ia64_inst_t inst)
+{
+       bundle->quad1.slot2 = inst.l;
+}
+
+void __init_or_module
+paravirt_write_inst(unsigned long tag, ia64_inst_t inst)
+{
+       bundle_t *bundle = paravirt_get_bundle(tag);
+       unsigned long slot = paravirt_get_slot(tag);
+
+       switch (slot) {
+       case 0:
+               paravirt_write_slot0(bundle, inst);
+               break;
+       case 1:
+               paravirt_write_slot1(bundle, inst);
+               break;
+       case 2:
+               paravirt_write_slot2(bundle, inst);
+               break;
+       default:
+               BUG();
+               break;
+       }
+       paravirt_flush_i_cache_range(bundle, sizeof(*bundle));
+}
+
+/* for debug */
+void
+paravirt_print_bundle(const bundle_t *bundle)
+{
+       const unsigned long *quad = (const unsigned long *)bundle;
+       ia64_inst_t slot0 = paravirt_read_slot0(bundle);
+       ia64_inst_t slot1 = paravirt_read_slot1(bundle);
+       ia64_inst_t slot2 = paravirt_read_slot2(bundle);
+
+       printk(KERN_DEBUG
+              "bundle 0x%p 0x%016lx 0x%016lx\n", bundle, quad[0], quad[1]);
+       printk(KERN_DEBUG
+              "bundle template 0x%x\n",
+              bundle->quad0.template);
+       printk(KERN_DEBUG
+              "slot0 0x%lx slot1_p0 0x%lx slot1_p1 0x%lx slot2 0x%lx\n",
+              (unsigned long)bundle->quad0.slot0,
+              (unsigned long)bundle->quad0.slot1_p0,
+              (unsigned long)bundle->quad1.slot1_p1,
+              (unsigned long)bundle->quad1.slot2);
+       printk(KERN_DEBUG
+              "slot0 0x%016llx slot1 0x%016llx slot2 0x%016llx\n",
+              slot0.l, slot1.l, slot2.l);
+}
+
+static int noreplace_paravirt __init_or_module = 0;
+
+static int __init setup_noreplace_paravirt(char *str)
+{
+       noreplace_paravirt = 1;
+       return 1;
+}
+__setup("noreplace-paravirt", setup_noreplace_paravirt);
+
+#ifdef ASM_SUPPORTED
+static void __init_or_module
+fill_nop_bundle(void *sbundle, void *ebundle)
+{
+       extern const char paravirt_nop_bundle[];
+       extern const unsigned long paravirt_nop_bundle_size;
+
+       void *bundle = sbundle;
+
+       BUG_ON((((unsigned long)sbundle) % sizeof(bundle_t)) != 0);
+       BUG_ON((((unsigned long)ebundle) % sizeof(bundle_t)) != 0);
+
+       while (bundle < ebundle) {
+               memcpy(bundle, paravirt_nop_bundle, paravirt_nop_bundle_size);
+
+               bundle += paravirt_nop_bundle_size;
+       }
+}
+
+/* helper function */
+unsigned long __init_or_module
+__paravirt_patch_apply_bundle(void *sbundle, void *ebundle, unsigned long type,
+                             const struct paravirt_patch_bundle_elem *elems,
+                             unsigned long nelems,
+                             const struct paravirt_patch_bundle_elem **found)
+{
+       unsigned long used = 0;
+       unsigned long i;
+
+       BUG_ON((((unsigned long)sbundle) % sizeof(bundle_t)) != 0);
+       BUG_ON((((unsigned long)ebundle) % sizeof(bundle_t)) != 0);
+
+       found = NULL;
+       for (i = 0; i < nelems; i++) {
+               const struct paravirt_patch_bundle_elem *p = &elems[i];
+               if (p->type == type) {
+                       unsigned long need = p->ebundle - p->sbundle;
+                       unsigned long room = ebundle - sbundle;
+
+                       if (found != NULL)
+                               *found = p;
+
+                       if (room < need) {
+                               /* no room to replace. skip it */
+                               printk(KERN_DEBUG
+                                      "the space is too small to put "
+                                      "bundles. type %ld need %ld room %ld\n",
+                                      type, need, room);
+                               break;
+                       }
+
+                       used = need;
+                       memcpy(sbundle, p->sbundle, used);
+                       break;
+               }
+       }
+
+       return used;
+}
+
+void __init_or_module
+paravirt_patch_apply_bundle(const struct paravirt_patch_site_bundle *start,
+                           const struct paravirt_patch_site_bundle *end)
+{
+       const struct paravirt_patch_site_bundle *p;
+
+       if (noreplace_paravirt)
+               return;
+       if (pv_init_ops.patch_bundle == NULL)
+               return;
+
+       for (p = start; p < end; p++) {
+               unsigned long used;
+
+               used = (*pv_init_ops.patch_bundle)(p->sbundle, p->ebundle,
+                                                  p->type);
+               if (used == 0)
+                       continue;
+
+               fill_nop_bundle(p->sbundle + used, p->ebundle);
+               paravirt_flush_i_cache_range(p->sbundle,
+                                            p->ebundle - p->sbundle);
+       }
+       ia64_sync_i();
+       ia64_srlz_i();
+}
+
+/*
+ * nop.i, nop.m, nop.f instruction are same format.
+ * but nop.b has differennt format.
+ * This doesn't support nop.b for now.
+ */
+static void __init_or_module
+fill_nop_inst(unsigned long stag, unsigned long etag)
+{
+       extern const bundle_t paravirt_nop_mfi_inst_bundle[];
+       unsigned long tag;
+       const ia64_inst_t nop_inst =
+               paravirt_read_slot0(paravirt_nop_mfi_inst_bundle);
+
+       for (tag = stag; tag < etag; tag = paravirt_get_next_tag(tag))
+               paravirt_write_inst(tag, nop_inst);
+}
+
+void __init_or_module
+paravirt_patch_apply_inst(const struct paravirt_patch_site_inst *start,
+                         const struct paravirt_patch_site_inst *end)
+{
+       const struct paravirt_patch_site_inst *p;
+
+       if (noreplace_paravirt)
+               return;
+       if (pv_init_ops.patch_inst == NULL)
+               return;
+
+       for (p = start; p < end; p++) {
+               unsigned long tag;
+               bundle_t *sbundle;
+               bundle_t *ebundle;
+
+               tag = (*pv_init_ops.patch_inst)(p->stag, p->etag, p->type);
+               if (tag == p->stag)
+                       continue;
+
+               fill_nop_inst(tag, p->etag);
+               sbundle = paravirt_get_bundle(p->stag);
+               ebundle = paravirt_get_bundle(p->etag) + 1;
+               paravirt_flush_i_cache_range(sbundle, (ebundle - sbundle) *
+                                            sizeof(bundle_t));
+       }
+       ia64_sync_i();
+       ia64_srlz_i();
+}
+#endif /* ASM_SUPPOTED */
+
+/* brl.cond.sptk.many <target64> X3 */
+typedef union inst_x3_op {
+       ia64_inst_t inst;
+       struct {
+               unsigned long qp: 6;
+               unsigned long btyp: 3;
+               unsigned long unused: 3;
+               unsigned long p: 1;
+               unsigned long imm20b: 20;
+               unsigned long wh: 2;
+               unsigned long d: 1;
+               unsigned long i: 1;
+               unsigned long opcode: 4;
+       };
+       unsigned long l;
+} inst_x3_op_t;
+
+typedef union inst_x3_imm {
+       ia64_inst_t inst;
+       struct {
+               unsigned long unused: 2;
+               unsigned long imm39: 39;
+       };
+       unsigned long l;
+} inst_x3_imm_t;
+
+void __init_or_module
+paravirt_patch_reloc_brl(unsigned long tag, const void *target)
+{
+       unsigned long tag_op = paravirt_get_next_tag(tag);
+       unsigned long tag_imm = tag;
+       bundle_t *bundle = paravirt_get_bundle(tag);
+
+       ia64_inst_t inst_op = paravirt_read_inst(tag_op);
+       ia64_inst_t inst_imm = paravirt_read_inst(tag_imm);
+
+       inst_x3_op_t inst_x3_op = { .l = inst_op.l };
+       inst_x3_imm_t inst_x3_imm = { .l = inst_imm.l };
+
+       unsigned long imm60 =
+               ((unsigned long)target - (unsigned long)bundle) >> 4;
+
+       BUG_ON(paravirt_get_slot(tag) != 1); /* MLX */
+       BUG_ON(((unsigned long)target & (sizeof(bundle_t) - 1)) != 0);
+
+       /* imm60[59] 1bit */
+       inst_x3_op.i = (imm60 >> 59) & 1;
+       /* imm60[19:0] 20bit */
+       inst_x3_op.imm20b = imm60 & ((1UL << 20) - 1);
+       /* imm60[58:20] 39bit */
+       inst_x3_imm.imm39 = (imm60 >> 20) & ((1UL << 39) - 1);
+
+       inst_op.l = inst_x3_op.l;
+       inst_imm.l = inst_x3_imm.l;
+
+       paravirt_write_inst(tag_op, inst_op);
+       paravirt_write_inst(tag_imm, inst_imm);
+}
+
+/* br.cond.sptk.many <target25>        B1 */
+typedef union inst_b1 {
+       ia64_inst_t inst;
+       struct {
+               unsigned long qp: 6;
+               unsigned long btype: 3;
+               unsigned long unused: 3;
+               unsigned long p: 1;
+               unsigned long imm20b: 20;
+               unsigned long wh: 2;
+               unsigned long d: 1;
+               unsigned long s: 1;
+               unsigned long opcode: 4;
+       };
+       unsigned long l;
+} inst_b1_t;
+
+void __init
+paravirt_patch_reloc_br(unsigned long tag, const void *target)
+{
+       bundle_t *bundle = paravirt_get_bundle(tag);
+       ia64_inst_t inst = paravirt_read_inst(tag);
+       unsigned long target25 = (unsigned long)target - (unsigned long)bundle;
+       inst_b1_t inst_b1;
+
+       BUG_ON(((unsigned long)target & (sizeof(bundle_t) - 1)) != 0);
+
+       inst_b1.l = inst.l;
+       if (target25 & (1UL << 63))
+               inst_b1.s = 1;
+       else
+               inst_b1.s = 0;
+
+       inst_b1.imm20b = target25 >> 4;
+       inst.l = inst_b1.l;
+
+       paravirt_write_inst(tag, inst);
+}
+
+void __init
+__paravirt_patch_apply_branch(
+       unsigned long tag, unsigned long type,
+       const struct paravirt_patch_branch_target *entries,
+       unsigned int nr_entries)
+{
+       unsigned int i;
+       for (i = 0; i < nr_entries; i++) {
+               if (entries[i].type == type) {
+                       paravirt_patch_reloc_br(tag, entries[i].entry);
+                       break;
+               }
+       }
+}
+
+static void __init
+paravirt_patch_apply_branch(const struct paravirt_patch_site_branch *start,
+                           const struct paravirt_patch_site_branch *end)
+{
+       const struct paravirt_patch_site_branch *p;
+
+       if (noreplace_paravirt)
+               return;
+       if (pv_init_ops.patch_branch == NULL)
+               return;
+
+       for (p = start; p < end; p++)
+               (*pv_init_ops.patch_branch)(p->tag, p->type);
+
+       ia64_sync_i();
+       ia64_srlz_i();
+}
+
+void __init
+paravirt_patch_apply(void)
+{
+       extern const char __start_paravirt_bundles[];
+       extern const char __stop_paravirt_bundles[];
+       extern const char __start_paravirt_insts[];
+       extern const char __stop_paravirt_insts[];
+       extern const char __start_paravirt_branches[];
+       extern const char __stop_paravirt_branches[];
+
+       paravirt_patch_apply_bundle((const struct paravirt_patch_site_bundle *)
+                                   __start_paravirt_bundles,
+                                   (const struct paravirt_patch_site_bundle *)
+                                   __stop_paravirt_bundles);
+       paravirt_patch_apply_inst((const struct paravirt_patch_site_inst *)
+                                 __start_paravirt_insts,
+                                 (const struct paravirt_patch_site_inst *)
+                                 __stop_paravirt_insts);
+       paravirt_patch_apply_branch((const struct paravirt_patch_site_branch *)
+                                   __start_paravirt_branches,
+                                   (const struct paravirt_patch_site_branch *)
+                                   __stop_paravirt_branches);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "linux"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ */
diff --git a/arch/ia64/kernel/paravirt_patchlist.c b/arch/ia64/kernel/paravirt_patchlist.c
new file mode 100644 (file)
index 0000000..b28082a
--- /dev/null
@@ -0,0 +1,79 @@
+/******************************************************************************
+ * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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/bug.h>
+#include <asm/paravirt.h>
+
+#define DECLARE(name)                                          \
+       extern unsigned long                                    \
+               __ia64_native_start_gate_##name##_patchlist[];  \
+       extern unsigned long                                    \
+               __ia64_native_end_gate_##name##_patchlist[]
+
+DECLARE(fsyscall);
+DECLARE(brl_fsys_bubble_down);
+DECLARE(vtop);
+DECLARE(mckinley_e9);
+
+extern unsigned long __start_gate_section[];
+
+#define ASSIGN(name)                                                       \
+       .start_##name##_patchlist =                                         \
+               (unsigned long)__ia64_native_start_gate_##name##_patchlist, \
+       .end_##name##_patchlist =                                           \
+               (unsigned long)__ia64_native_end_gate_##name##_patchlist
+
+struct pv_patchdata pv_patchdata __initdata = {
+       ASSIGN(fsyscall),
+       ASSIGN(brl_fsys_bubble_down),
+       ASSIGN(vtop),
+       ASSIGN(mckinley_e9),
+
+       .gate_section = (void*)__start_gate_section,
+};
+
+
+unsigned long __init
+paravirt_get_gate_patchlist(enum pv_gate_patchlist type)
+{
+
+#define CASE(NAME, name)                                       \
+       case PV_GATE_START_##NAME:                              \
+               return pv_patchdata.start_##name##_patchlist;   \
+       case PV_GATE_END_##NAME:                                \
+               return pv_patchdata.end_##name##_patchlist;     \
+
+       switch (type) {
+               CASE(FSYSCALL, fsyscall);
+               CASE(BRL_FSYS_BUBBLE_DOWN, brl_fsys_bubble_down);
+               CASE(VTOP, vtop);
+               CASE(MCKINLEY_E9, mckinley_e9);
+       default:
+               BUG();
+               break;
+       }
+       return 0;
+}
+
+void * __init
+paravirt_get_gate_section(void)
+{
+       return pv_patchdata.gate_section;
+}
diff --git a/arch/ia64/kernel/paravirt_patchlist.h b/arch/ia64/kernel/paravirt_patchlist.h
new file mode 100644 (file)
index 0000000..0684aa6
--- /dev/null
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * linux/arch/ia64/xen/paravirt_patchlist.h
+ *
+ * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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
+ *
+ */
+
+#if defined(__IA64_GATE_PARAVIRTUALIZED_XEN)
+#include <asm/xen/patchlist.h>
+#else
+#include <asm/native/patchlist.h>
+#endif
+
index 2f42fcb9776a1c9752465317a8efcaa393d47ec4..6158560d7f1738993ee4fa00437cd809c8854661 100644 (file)
  *
  */
 
+#include <linux/init.h>
 #include <asm/asmmacro.h>
 #include <asm/asm-offsets.h>
+#include <asm/paravirt_privop.h>
+#include <asm/paravirt_patch.h>
 #include "entry.h"
 
 #define DATA8(sym, init_value)                 \
        data8 init_value ;                      \
        .popsection
 
-#define BRANCH(targ, reg, breg)                \
-       movl reg=targ ;                 \
-       ;;                              \
-       ld8 reg=[reg] ;                 \
-       ;;                              \
-       mov breg=reg ;                  \
+#define BRANCH(targ, reg, breg, type)                                  \
+       PARAVIRT_PATCH_SITE_BR(PARAVIRT_PATCH_TYPE_BR_ ## type) ;       \
+       ;;                                                              \
+       movl reg=targ ;                                                 \
+       ;;                                                              \
+       ld8 reg=[reg] ;                                                 \
+       ;;                                                              \
+       mov breg=reg ;                                                  \
        br.cond.sptk.many breg
 
-#define BRANCH_PROC(sym, reg, breg)                            \
-       DATA8(paravirt_ ## sym ## _targ, ia64_native_ ## sym) ; \
-       GLOBAL_ENTRY(paravirt_ ## sym) ;                        \
-               BRANCH(paravirt_ ## sym ## _targ, reg, breg) ;  \
+#define BRANCH_PROC(sym, reg, breg, type)                              \
+       DATA8(paravirt_ ## sym ## _targ, ia64_native_ ## sym) ;         \
+       GLOBAL_ENTRY(paravirt_ ## sym) ;                                \
+               BRANCH(paravirt_ ## sym ## _targ, reg, breg, type) ;    \
        END(paravirt_ ## sym)
 
-#define BRANCH_PROC_UNWINFO(sym, reg, breg)                    \
-       DATA8(paravirt_ ## sym ## _targ, ia64_native_ ## sym) ; \
-       GLOBAL_ENTRY(paravirt_ ## sym) ;                        \
-               PT_REGS_UNWIND_INFO(0) ;                        \
-               BRANCH(paravirt_ ## sym ## _targ, reg, breg) ;  \
+#define BRANCH_PROC_UNWINFO(sym, reg, breg, type)                      \
+       DATA8(paravirt_ ## sym ## _targ, ia64_native_ ## sym) ;         \
+       GLOBAL_ENTRY(paravirt_ ## sym) ;                                \
+               PT_REGS_UNWIND_INFO(0) ;                                \
+               BRANCH(paravirt_ ## sym ## _targ, reg, breg, type) ;    \
        END(paravirt_ ## sym)
 
 
-BRANCH_PROC(switch_to, r22, b7)
-BRANCH_PROC_UNWINFO(leave_syscall, r22, b7)
-BRANCH_PROC(work_processed_syscall, r2, b7)
-BRANCH_PROC_UNWINFO(leave_kernel, r22, b7)
+BRANCH_PROC(switch_to, r22, b7, SWITCH_TO)
+BRANCH_PROC_UNWINFO(leave_syscall, r22, b7, LEAVE_SYSCALL)
+BRANCH_PROC(work_processed_syscall, r2, b7, WORK_PROCESSED_SYSCALL)
+BRANCH_PROC_UNWINFO(leave_kernel, r22, b7, LEAVE_KERNEL)
+
+
+#ifdef CONFIG_MODULES
+#define __INIT_OR_MODULE       .text
+#define __INITDATA_OR_MODULE   .data
+#else
+#define __INIT_OR_MODULE       __INIT
+#define __INITDATA_OR_MODULE   __INITDATA
+#endif /* CONFIG_MODULES */
+
+       __INIT_OR_MODULE
+       GLOBAL_ENTRY(paravirt_fc_i)
+       fc.i r32
+       br.ret.sptk.many rp
+       END(paravirt_fc_i)
+       __FINIT
+
+       __INIT_OR_MODULE
+       .align 32
+       GLOBAL_ENTRY(paravirt_nop_b_inst_bundle)
+       {
+               nop.b 0
+               nop.b 0
+               nop.b 0
+       }
+       END(paravirt_nop_b_inst_bundle)
+       __FINIT
+
+       /* NOTE: nop.[mfi] has same format */
+       __INIT_OR_MODULE
+       GLOBAL_ENTRY(paravirt_nop_mfi_inst_bundle)
+       {
+               nop.m 0
+               nop.f 0
+               nop.i 0
+       }
+       END(paravirt_nop_mfi_inst_bundle)
+       __FINIT
+
+       __INIT_OR_MODULE
+       GLOBAL_ENTRY(paravirt_nop_bundle)
+paravirt_nop_bundle_start:
+       {
+               nop 0
+               nop 0
+               nop 0
+       }
+paravirt_nop_bundle_end:
+       END(paravirt_nop_bundle)
+       __FINIT
+
+       __INITDATA_OR_MODULE
+       .align 8
+       .global paravirt_nop_bundle_size
+paravirt_nop_bundle_size:
+       data8   paravirt_nop_bundle_end - paravirt_nop_bundle_start
index b83b2c516008d4cdac5db340a53c74dfa8f4444a..68a1311db806b49a918c76ecea4af5ca75a55da0 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/init.h>
 #include <linux/string.h>
 
+#include <asm/paravirt.h>
 #include <asm/patch.h>
 #include <asm/processor.h>
 #include <asm/sections.h>
@@ -169,16 +170,35 @@ ia64_patch_mckinley_e9 (unsigned long start, unsigned long end)
        ia64_srlz_i();
 }
 
+extern unsigned long ia64_native_fsyscall_table[NR_syscalls];
+extern char ia64_native_fsys_bubble_down[];
+struct pv_fsys_data pv_fsys_data __initdata = {
+       .fsyscall_table = (unsigned long *)ia64_native_fsyscall_table,
+       .fsys_bubble_down = (void *)ia64_native_fsys_bubble_down,
+};
+
+unsigned long * __init
+paravirt_get_fsyscall_table(void)
+{
+       return pv_fsys_data.fsyscall_table;
+}
+
+char * __init
+paravirt_get_fsys_bubble_down(void)
+{
+       return pv_fsys_data.fsys_bubble_down;
+}
+
 static void __init
 patch_fsyscall_table (unsigned long start, unsigned long end)
 {
-       extern unsigned long fsyscall_table[NR_syscalls];
+       u64 fsyscall_table = (u64)paravirt_get_fsyscall_table();
        s32 *offp = (s32 *) start;
        u64 ip;
 
        while (offp < (s32 *) end) {
                ip = (u64) ia64_imva((char *) offp + *offp);
-               ia64_patch_imm64(ip, (u64) fsyscall_table);
+               ia64_patch_imm64(ip, fsyscall_table);
                ia64_fc((void *) ip);
                ++offp;
        }
@@ -189,7 +209,7 @@ patch_fsyscall_table (unsigned long start, unsigned long end)
 static void __init
 patch_brl_fsys_bubble_down (unsigned long start, unsigned long end)
 {
-       extern char fsys_bubble_down[];
+       u64 fsys_bubble_down = (u64)paravirt_get_fsys_bubble_down();
        s32 *offp = (s32 *) start;
        u64 ip;
 
@@ -207,13 +227,13 @@ patch_brl_fsys_bubble_down (unsigned long start, unsigned long end)
 void __init
 ia64_patch_gate (void)
 {
-#      define START(name)      ((unsigned long) __start_gate_##name##_patchlist)
-#      define END(name)        ((unsigned long)__end_gate_##name##_patchlist)
+#      define START(name)      paravirt_get_gate_patchlist(PV_GATE_START_##name)
+#      define END(name)        paravirt_get_gate_patchlist(PV_GATE_END_##name)
 
-       patch_fsyscall_table(START(fsyscall), END(fsyscall));
-       patch_brl_fsys_bubble_down(START(brl_fsys_bubble_down), END(brl_fsys_bubble_down));
-       ia64_patch_vtop(START(vtop), END(vtop));
-       ia64_patch_mckinley_e9(START(mckinley_e9), END(mckinley_e9));
+       patch_fsyscall_table(START(FSYSCALL), END(FSYSCALL));
+       patch_brl_fsys_bubble_down(START(BRL_FSYS_BUBBLE_DOWN), END(BRL_FSYS_BUBBLE_DOWN));
+       ia64_patch_vtop(START(VTOP), END(VTOP));
+       ia64_patch_mckinley_e9(START(MCKINLEY_E9), END(MCKINLEY_E9));
 }
 
 void ia64_patch_phys_stack_reg(unsigned long val)
@@ -229,7 +249,7 @@ void ia64_patch_phys_stack_reg(unsigned long val)
        while (offp < end) {
                ip = (u64) offp + *offp;
                ia64_patch(ip, mask, imm);
-               ia64_fc(ip);
+               ia64_fc((void *)ip);
                ++offp;
        }
        ia64_sync_i();
index d0ada067a4af52bd83fdac763b862d3b62e2ed13..e4cb443bb988feffbf93840dd023e319d205e7ca 100644 (file)
@@ -32,9 +32,6 @@ int force_iommu __read_mostly = 1;
 int force_iommu __read_mostly;
 #endif
 
-/* Set this to 1 if there is a HW IOMMU in the system */
-int iommu_detected __read_mostly;
-
 /* Dummy device used for NULL arguments (normally ISA). Better would
    be probably a smaller DMA mask, but this is bug-to-bug compatible
    to i386. */
@@ -44,18 +41,7 @@ struct device fallback_dev = {
        .dma_mask = &fallback_dev.coherent_dma_mask,
 };
 
-void __init pci_iommu_alloc(void)
-{
-       /*
-        * The order of these functions is important for
-        * fall-back/fail-over reasons
-        */
-       detect_intel_iommu();
-
-#ifdef CONFIG_SWIOTLB
-       pci_swiotlb_init();
-#endif
-}
+extern struct dma_map_ops intel_dma_ops;
 
 static int __init pci_iommu_init(void)
 {
@@ -79,15 +65,12 @@ iommu_dma_init(void)
        return;
 }
 
-struct dma_mapping_ops *dma_ops;
-EXPORT_SYMBOL(dma_ops);
-
 int iommu_dma_supported(struct device *dev, u64 mask)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(dev);
+       struct dma_map_ops *ops = platform_dma_get_ops(dev);
 
-       if (ops->dma_supported_op)
-               return ops->dma_supported_op(dev, mask);
+       if (ops->dma_supported)
+               return ops->dma_supported(dev, mask);
 
        /* Copied from i386. Doesn't make much sense, because it will
           only work for pci_alloc_coherent.
@@ -116,4 +99,25 @@ int iommu_dma_supported(struct device *dev, u64 mask)
 }
 EXPORT_SYMBOL(iommu_dma_supported);
 
+void __init pci_iommu_alloc(void)
+{
+       dma_ops = &intel_dma_ops;
+
+       dma_ops->sync_single_for_cpu = machvec_dma_sync_single;
+       dma_ops->sync_sg_for_cpu = machvec_dma_sync_sg;
+       dma_ops->sync_single_for_device = machvec_dma_sync_single;
+       dma_ops->sync_sg_for_device = machvec_dma_sync_sg;
+       dma_ops->dma_supported = iommu_dma_supported;
+
+       /*
+        * The order of these functions is important for
+        * fall-back/fail-over reasons
+        */
+       detect_intel_iommu();
+
+#ifdef CONFIG_SWIOTLB
+       pci_swiotlb_init();
+#endif
+}
+
 #endif
index 16c50516dbc11ffb9e0a3042eabef9d4fbd81127..573f02c39a00295adb4edbbb1a2666e9e1e33da7 100644 (file)
 int swiotlb __read_mostly;
 EXPORT_SYMBOL(swiotlb);
 
-struct dma_mapping_ops swiotlb_dma_ops = {
-       .mapping_error = swiotlb_dma_mapping_error,
-       .alloc_coherent = swiotlb_alloc_coherent,
+static void *ia64_swiotlb_alloc_coherent(struct device *dev, size_t size,
+                                        dma_addr_t *dma_handle, gfp_t gfp)
+{
+       if (dev->coherent_dma_mask != DMA_64BIT_MASK)
+               gfp |= GFP_DMA;
+       return swiotlb_alloc_coherent(dev, size, dma_handle, gfp);
+}
+
+struct dma_map_ops swiotlb_dma_ops = {
+       .alloc_coherent = ia64_swiotlb_alloc_coherent,
        .free_coherent = swiotlb_free_coherent,
-       .map_single = swiotlb_map_single,
-       .unmap_single = swiotlb_unmap_single,
+       .map_page = swiotlb_map_page,
+       .unmap_page = swiotlb_unmap_page,
+       .map_sg = swiotlb_map_sg_attrs,
+       .unmap_sg = swiotlb_unmap_sg_attrs,
        .sync_single_for_cpu = swiotlb_sync_single_for_cpu,
        .sync_single_for_device = swiotlb_sync_single_for_device,
        .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,
-       .map_sg = swiotlb_map_sg,
-       .unmap_sg = swiotlb_unmap_sg,
-       .dma_supported_op = swiotlb_dma_supported,
+       .dma_supported = swiotlb_dma_supported,
+       .mapping_error = swiotlb_dma_mapping_error,
 };
 
+void __init swiotlb_dma_init(void)
+{
+       dma_ops = &swiotlb_dma_ops;
+       swiotlb_init();
+}
+
 void __init pci_swiotlb_init(void)
 {
        if (!iommu_detected) {
index 5c0f408cfd719f02ded2c58dc6ebf2b3c181c7b5..8a06dc480594c0d3e93636eccad9ea9316944127 100644 (file)
@@ -5603,7 +5603,7 @@ pfm_interrupt_handler(int irq, void *arg)
  * /proc/perfmon interface, for debug only
  */
 
-#define PFM_PROC_SHOW_HEADER   ((void *)NR_CPUS+1)
+#define PFM_PROC_SHOW_HEADER   ((void *)nr_cpu_ids+1)
 
 static void *
 pfm_proc_start(struct seq_file *m, loff_t *pos)
@@ -5612,7 +5612,7 @@ pfm_proc_start(struct seq_file *m, loff_t *pos)
                return PFM_PROC_SHOW_HEADER;
        }
 
-       while (*pos <= NR_CPUS) {
+       while (*pos <= nr_cpu_ids) {
                if (cpu_online(*pos - 1)) {
                        return (void *)*pos;
                }
index c57162705147e500981235cbec79bd416c5ec136..5d7c0e5b9e76f150b20269cb9ba9e2497062209a 100644 (file)
@@ -413,7 +413,7 @@ ia64_load_extra (struct task_struct *task)
  * so there is nothing to worry about.
  */
 int
-copy_thread (int nr, unsigned long clone_flags,
+copy_thread(unsigned long clone_flags,
             unsigned long user_stack_base, unsigned long user_stack_size,
             struct task_struct *p, struct pt_regs *regs)
 {
index ecb9eb78d6877685de4d677d52e4b21292de4ddc..7053c55b7649337c19f5495c205a0d1584f33caa 100644 (file)
@@ -317,7 +317,7 @@ retry:
        }
 
        n = data->cpu_check;
-       for (i = 0; i < NR_CPUS; i++) {
+       for (i = 0; i < nr_cpu_ids; i++) {
                if (cpu_isset(n, data->cpu_event)) {
                        if (!cpu_online(n)) {
                                cpu_clear(n, data->cpu_event);
@@ -326,7 +326,7 @@ retry:
                        cpu = n;
                        break;
                }
-               if (++n == NR_CPUS)
+               if (++n == nr_cpu_ids)
                        n = 0;
        }
 
@@ -337,7 +337,7 @@ retry:
 
        /* for next read, start checking at next CPU */
        data->cpu_check = cpu;
-       if (++data->cpu_check == NR_CPUS)
+       if (++data->cpu_check == nr_cpu_ids)
                data->cpu_check = 0;
 
        snprintf(cmd, sizeof(cmd), "read %d\n", cpu);
index 865af27c7737c1596dde7762e3ab65555fc990db..714066aeda7f6f758ecd080ec52bd4ae8a17be89 100644 (file)
@@ -52,6 +52,7 @@
 #include <asm/meminit.h>
 #include <asm/page.h>
 #include <asm/paravirt.h>
+#include <asm/paravirt_patch.h>
 #include <asm/patch.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
@@ -537,6 +538,7 @@ setup_arch (char **cmdline_p)
        paravirt_arch_setup_early();
 
        ia64_patch_vtop((u64) __start___vtop_patchlist, (u64) __end___vtop_patchlist);
+       paravirt_patch_apply();
 
        *cmdline_p = __va(ia64_boot_param->command_line);
        strlcpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE);
@@ -730,10 +732,10 @@ static void *
 c_start (struct seq_file *m, loff_t *pos)
 {
 #ifdef CONFIG_SMP
-       while (*pos < NR_CPUS && !cpu_isset(*pos, cpu_online_map))
+       while (*pos < nr_cpu_ids && !cpu_online(*pos))
                ++*pos;
 #endif
-       return *pos < NR_CPUS ? cpu_data(*pos) : NULL;
+       return *pos < nr_cpu_ids ? cpu_data(*pos) : NULL;
 }
 
 static void *
@@ -1016,8 +1018,7 @@ cpu_init (void)
                                        | IA64_DCR_DA | IA64_DCR_DD | IA64_DCR_LC));
        atomic_inc(&init_mm.mm_count);
        current->active_mm = &init_mm;
-       if (current->mm)
-               BUG();
+       BUG_ON(current->mm);
 
        ia64_mmu_init(ia64_imva(cpu_data));
        ia64_mca_cpu_init(ia64_imva(cpu_data));
index da8f020d82c1f5acb7e20fc2dd6ef4a1b8d86333..2ea4199d9c57895a7814282212033267895f28e6 100644 (file)
@@ -166,11 +166,11 @@ send_IPI_allbutself (int op)
  * Called with preemption disabled.
  */
 static inline void
-send_IPI_mask(cpumask_t mask, int op)
+send_IPI_mask(const struct cpumask *mask, int op)
 {
        unsigned int cpu;
 
-       for_each_cpu_mask(cpu, mask) {
+       for_each_cpu(cpu, mask) {
                        send_IPI_single(cpu, op);
        }
 }
@@ -316,7 +316,7 @@ void arch_send_call_function_single_ipi(int cpu)
        send_IPI_single(cpu, IPI_CALL_FUNC_SINGLE);
 }
 
-void arch_send_call_function_ipi(cpumask_t mask)
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
 {
        send_IPI_mask(mask, IPI_CALL_FUNC);
 }
index 52290547c85ba89edd5ba3fa1a98985891803361..7700e23034bb4ba94ceb1d236fb632cb9b8bf924 100644 (file)
@@ -581,14 +581,14 @@ smp_build_cpu_map (void)
 
        ia64_cpu_to_sapicid[0] = boot_cpu_id;
        cpus_clear(cpu_present_map);
-       cpu_set(0, cpu_present_map);
-       cpu_set(0, cpu_possible_map);
+       set_cpu_present(0, true);
+       set_cpu_possible(0, true);
        for (cpu = 1, i = 0; i < smp_boot_data.cpu_count; i++) {
                sapicid = smp_boot_data.cpu_phys_id[i];
                if (sapicid == boot_cpu_id)
                        continue;
-               cpu_set(cpu, cpu_present_map);
-               cpu_set(cpu, cpu_possible_map);
+               set_cpu_present(cpu, true);
+               set_cpu_possible(cpu, true);
                ia64_cpu_to_sapicid[cpu] = sapicid;
                cpu++;
        }
@@ -626,12 +626,9 @@ smp_prepare_cpus (unsigned int max_cpus)
         */
        if (!max_cpus) {
                printk(KERN_INFO "SMP mode deactivated.\n");
-               cpus_clear(cpu_online_map);
-               cpus_clear(cpu_present_map);
-               cpus_clear(cpu_possible_map);
-               cpu_set(0, cpu_online_map);
-               cpu_set(0, cpu_present_map);
-               cpu_set(0, cpu_possible_map);
+               init_cpu_online(cpumask_of(0));
+               init_cpu_present(cpumask_of(0));
+               init_cpu_possible(cpumask_of(0));
                return;
        }
 }
index f0ebb342409d0b4ab3cd5d9ba470aa3284ef2667..641c8b61c4f167200adf0e52646d5d823a509096 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/efi.h>
 #include <linux/timex.h>
 #include <linux/clocksource.h>
+#include <linux/platform_device.h>
 
 #include <asm/machvec.h>
 #include <asm/delay.h>
@@ -49,6 +50,15 @@ EXPORT_SYMBOL(last_cli_ip);
 
 #endif
 
+#ifdef CONFIG_PARAVIRT
+/* We need to define a real function for sched_clock, to override the
+   weak default version */
+unsigned long long sched_clock(void)
+{
+        return paravirt_sched_clock();
+}
+#endif
+
 #ifdef CONFIG_PARAVIRT
 static void
 paravirt_clocksource_resume(void)
@@ -405,6 +415,21 @@ static struct irqaction timer_irqaction = {
        .name =         "timer"
 };
 
+static struct platform_device rtc_efi_dev = {
+       .name = "rtc-efi",
+       .id = -1,
+};
+
+static int __init rtc_init(void)
+{
+       if (platform_device_register(&rtc_efi_dev) < 0)
+               printk(KERN_ERR "unable to register rtc device...\n");
+
+       /* not necessarily an error */
+       return 0;
+}
+module_init(rtc_init);
+
 void __init
 time_init (void)
 {
index 3765efc5f96333d3a40df579c075f5e6e95a77eb..4a95e86b9ac200bafd30ddca8b1d50be6aec5081 100644 (file)
@@ -169,6 +169,30 @@ SECTIONS
          __end___mckinley_e9_bundles = .;
        }
 
+#if defined(CONFIG_PARAVIRT)
+  . = ALIGN(16);
+  .paravirt_bundles : AT(ADDR(.paravirt_bundles) - LOAD_OFFSET)
+       {
+         __start_paravirt_bundles = .;
+          *(.paravirt_bundles)
+         __stop_paravirt_bundles = .;
+       }
+  . = ALIGN(16);
+  .paravirt_insts : AT(ADDR(.paravirt_insts) - LOAD_OFFSET)
+       {
+         __start_paravirt_insts = .;
+          *(.paravirt_insts)
+         __stop_paravirt_insts = .;
+       }
+  . = ALIGN(16);
+  .paravirt_branches : AT(ADDR(.paravirt_branches) - LOAD_OFFSET)
+       {
+         __start_paravirt_branches = .;
+         *(.paravirt_branches)
+         __stop_paravirt_branches = .;
+       }
+#endif
+
 #if defined(CONFIG_IA64_GENERIC)
   /* Machine Vector */
   . = ALIGN(16);
@@ -201,6 +225,12 @@ SECTIONS
          __start_gate_section = .;
          *(.data.gate)
          __stop_gate_section = .;
+#ifdef CONFIG_XEN
+         . = ALIGN(PAGE_SIZE);
+         __xen_start_gate_section = .;
+         *(.data.gate.xen)
+         __xen_stop_gate_section = .;
+#endif
        }
   . = ALIGN(PAGE_SIZE);                /* make sure the gate page doesn't expose
                                 * kernel data
index 076b00d1dbffe3696eecb5662726faa204478bad..28af6a731bb8a26361a60650263a3c943ff7bb9f 100644 (file)
@@ -70,7 +70,7 @@ static void kvm_flush_icache(unsigned long start, unsigned long len)
        int l;
 
        for (l = 0; l < (len + 32); l += 32)
-               ia64_fc(start + l);
+               ia64_fc((void *)(start + l));
 
        ia64_sync_i();
        ia64_srlz_i();
index d4d28050587883e0f708fb5f46ed9cdb4a7ae3da..a18ee17b9192e01f3c3f1683817be3ae775e1ca7 100644 (file)
@@ -386,7 +386,7 @@ void set_rse_reg(struct kvm_pt_regs *regs, unsigned long r1,
                else
                        *rnat_addr = (*rnat_addr) & (~nat_mask);
 
-               ia64_setreg(_IA64_REG_AR_BSPSTORE, bspstore);
+               ia64_setreg(_IA64_REG_AR_BSPSTORE, (unsigned long)bspstore);
                ia64_setreg(_IA64_REG_AR_RNAT, rnat);
        }
        local_irq_restore(psr);
index 38232b37668b3be87e8c8404aac2caea282bcc67..2c2501f131597c6389e82e6c4e3e62eb6ecf7f80 100644 (file)
@@ -210,6 +210,7 @@ void thash_vhpt_insert(struct kvm_vcpu *v, u64 pte, u64 itir, u64 va, int type)
                phy_pte  &= ~PAGE_FLAGS_RV_MASK;
                psr = ia64_clear_ic();
                ia64_itc(type, va, phy_pte, itir_ps(itir));
+               paravirt_dv_serialize_data();
                ia64_set_psr(psr);
        }
 
@@ -456,6 +457,7 @@ void  thash_purge_and_insert(struct kvm_vcpu *v, u64 pte, u64 itir,
                phy_pte  &= ~PAGE_FLAGS_RV_MASK;
                psr = ia64_clear_ic();
                ia64_itc(type, ifa, phy_pte, ps);
+               paravirt_dv_serialize_data();
                ia64_set_psr(psr);
        }
        if (!(pte&VTLB_PTE_IO))
index 56e12903973cc6456d9e2d7f48a7ec45e6301edd..c0f3bee690424da0ed3f7489fd57b832b8d622cc 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 #include <asm/mca.h>
+#include <asm/paravirt.h>
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
@@ -259,6 +260,7 @@ put_kernel_page (struct page *page, unsigned long address, pgprot_t pgprot)
 static void __init
 setup_gate (void)
 {
+       void *gate_section;
        struct page *page;
 
        /*
@@ -266,10 +268,11 @@ setup_gate (void)
         * headers etc. and once execute-only page to enable
         * privilege-promotion via "epc":
         */
-       page = virt_to_page(ia64_imva(__start_gate_section));
+       gate_section = paravirt_get_gate_section();
+       page = virt_to_page(ia64_imva(gate_section));
        put_kernel_page(page, GATE_ADDR, PAGE_READONLY);
 #ifdef HAVE_BUGGY_SEGREL
-       page = virt_to_page(ia64_imva(__start_gate_section + PAGE_SIZE));
+       page = virt_to_page(ia64_imva(gate_section + PAGE_SIZE));
        put_kernel_page(page, GATE_ADDR + PAGE_SIZE, PAGE_GATE);
 #else
        put_kernel_page(page, GATE_ADDR + PERCPU_PAGE_SIZE, PAGE_GATE);
@@ -633,8 +636,7 @@ mem_init (void)
 #endif
 
 #ifdef CONFIG_FLATMEM
-       if (!mem_map)
-               BUG();
+       BUG_ON(!mem_map);
        max_mapnr = max_low_pfn;
 #endif
 
@@ -667,8 +669,8 @@ mem_init (void)
         * code can tell them apart.
         */
        for (i = 0; i < NR_syscalls; ++i) {
-               extern unsigned long fsyscall_table[NR_syscalls];
                extern unsigned long sys_call_table[NR_syscalls];
+               unsigned long *fsyscall_table = paravirt_get_fsyscall_table();
 
                if (!fsyscall_table[i] || nolwsys)
                        fsyscall_table[i] = sys_call_table[i] | 1;
index bd9818a36b4769e9aa961ea82206bdfb8ff21fb9..b9f3d7bbb3384d97b01a48be9db4683dab10340a 100644 (file)
@@ -309,7 +309,7 @@ flush_tlb_range (struct vm_area_struct *vma, unsigned long start,
 
        preempt_disable();
 #ifdef CONFIG_SMP
-       if (mm != current->active_mm || cpus_weight(mm->cpu_vm_mask) != 1) {
+       if (mm != current->active_mm || cpumask_weight(mm_cpumask(mm)) != 1) {
                platform_global_tlb_purge(mm, start, end, nbits);
                preempt_enable();
                return;
index ba66ac2e4c60f07241ed80203fe5741631327866..e59809a3fc01e1d7d502aa8e3e10d2a36f3f042b 100644 (file)
@@ -17,6 +17,7 @@ s/mov.*=.*cr\.iip/.warning \"cr.iip should not used directly\"/g
 s/mov.*=.*cr\.ivr/.warning \"cr.ivr should not used directly\"/g
 s/mov.*=[^\.]*psr/.warning \"psr should not used directly\"/g  # avoid ar.fpsr
 s/mov.*=.*ar\.eflags/.warning \"ar.eflags should not used directly\"/g
+s/mov.*=.*ar\.itc.*/.warning \"ar.itc should not used directly\"/g
 s/mov.*cr\.ifa.*=.*/.warning \"cr.ifa should not used directly\"/g
 s/mov.*cr\.itir.*=.*/.warning \"cr.itir should not used directly\"/g
 s/mov.*cr\.iha.*=.*/.warning \"cr.iha should not used directly\"/g
index 0d4ffa4da1da755361b5506c945333a246d6a694..57f280dd9defe70d6320ce22b7c51c76e31f5710 100644 (file)
@@ -135,8 +135,7 @@ static s64 sn_device_fixup_war(u64 nasid, u64 widget, int device,
        }
 
        war_list = kzalloc(DEV_PER_WIDGET * sizeof(*war_list), GFP_KERNEL);
-       if (!war_list)
-               BUG();
+       BUG_ON(!war_list);
 
        SAL_CALL_NOLOCK(isrv, SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST,
                        nasid, widget, __pa(war_list), 0, 0, 0 ,0);
@@ -180,23 +179,20 @@ sn_common_hubdev_init(struct hubdev_info *hubdev)
                sizeof(struct sn_flush_device_kernel *);
        hubdev->hdi_flush_nasid_list.widget_p =
                kzalloc(size, GFP_KERNEL);
-       if (!hubdev->hdi_flush_nasid_list.widget_p)
-               BUG();
+       BUG_ON(!hubdev->hdi_flush_nasid_list.widget_p);
 
        for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) {
                size = DEV_PER_WIDGET *
                        sizeof(struct sn_flush_device_kernel);
                sn_flush_device_kernel = kzalloc(size, GFP_KERNEL);
-               if (!sn_flush_device_kernel)
-                       BUG();
+               BUG_ON(!sn_flush_device_kernel);
 
                dev_entry = sn_flush_device_kernel;
                for (device = 0; device < DEV_PER_WIDGET;
                     device++, dev_entry++) {
                        size = sizeof(struct sn_flush_device_common);
                        dev_entry->common = kzalloc(size, GFP_KERNEL);
-                       if (!dev_entry->common)
-                               BUG();
+                       BUG_ON(!dev_entry->common);
                        if (sn_prom_feature_available(PRF_DEVICE_FLUSH_LIST))
                                status = sal_get_device_dmaflush_list(
                                             hubdev->hdi_nasid, widget, device,
@@ -326,8 +322,7 @@ sn_common_bus_fixup(struct pci_bus *bus,
         */
        controller->platform_data = kzalloc(sizeof(struct sn_platform_data),
                                            GFP_KERNEL);
-       if (controller->platform_data == NULL)
-               BUG();
+       BUG_ON(controller->platform_data == NULL);
        sn_platform_data =
                        (struct sn_platform_data *) controller->platform_data;
        sn_platform_data->provider_soft = provider_soft;
index e2eb2da60f963ee3aa7e62c727ef408026b4cd13..ee774c366a06c82840a89c80dfb46b3086ead611 100644 (file)
@@ -128,8 +128,7 @@ sn_legacy_pci_window_fixup(struct pci_controller *controller,
 {
                controller->window = kcalloc(2, sizeof(struct pci_window),
                                             GFP_KERNEL);
-               if (controller->window == NULL)
-                       BUG();
+               BUG_ON(controller->window == NULL);
                controller->window[0].offset = legacy_io;
                controller->window[0].resource.name = "legacy_io";
                controller->window[0].resource.flags = IORESOURCE_IO;
@@ -168,8 +167,7 @@ sn_pci_window_fixup(struct pci_dev *dev, unsigned int count,
        idx = controller->windows;
        new_count = controller->windows + count;
        new_window = kcalloc(new_count, sizeof(struct pci_window), GFP_KERNEL);
-       if (new_window == NULL)
-               BUG();
+       BUG_ON(new_window == NULL);
        if (controller->window) {
                memcpy(new_window, controller->window,
                       sizeof(struct pci_window) * controller->windows);
@@ -222,8 +220,7 @@ sn_io_slot_fixup(struct pci_dev *dev)
                (u64) __pa(pcidev_info),
                (u64) __pa(sn_irq_info));
 
-       if (status)
-               BUG(); /* Cannot get platform pci device information */
+       BUG_ON(status); /* Cannot get platform pci device information */
 
 
        /* Copy over PIO Mapped Addresses */
@@ -307,8 +304,7 @@ sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
        prom_bussoft_ptr = __va(prom_bussoft_ptr);
 
        controller = kzalloc(sizeof(*controller), GFP_KERNEL);
-       if (!controller)
-               BUG();
+       BUG_ON(!controller);
        controller->segment = segment;
 
        /*
index 02c5b8a9fb6061037e8c35551a4881198cf1d4fc..e456f062f2419deb5f2bfd9d0e968d88b1c79ac5 100644 (file)
@@ -732,8 +732,7 @@ void __init build_cnode_tables(void)
                kl_config_hdr_t *klgraph_header;
                nasid = cnodeid_to_nasid(node);
                klgraph_header = ia64_sn_get_klconfig_addr(nasid);
-               if (klgraph_header == NULL)
-                       BUG();
+               BUG_ON(klgraph_header == NULL);
                brd = NODE_OFFSET_TO_LBOARD(nasid, klgraph_header->ch_board_info);
                while (brd) {
                        if (board_needs_cnode(brd->brd_type) && physical_node_map[brd->brd_nasid] < 0) {
@@ -750,7 +749,7 @@ nasid_slice_to_cpuid(int nasid, int slice)
 {
        long cpu;
 
-       for (cpu = 0; cpu < NR_CPUS; cpu++)
+       for (cpu = 0; cpu < nr_cpu_ids; cpu++)
                if (cpuid_to_nasid(cpu) == nasid &&
                                        cpuid_to_slice(cpu) == slice)
                        return cpu;
index 4dcce3d0e04ca1c9bc0e10d10cf4d7fcab6f7723..e6332881864374111440c339a0da72e55130ff40 100644 (file)
@@ -225,7 +225,6 @@ static struct proc_dir_entry *sgi_prominfo_entry;
 int __init prominfo_init(void)
 {
        struct proc_dir_entry **entp;
-       struct proc_dir_entry *p;
        cnodeid_t cnodeid;
        unsigned long nasid;
        int size;
@@ -246,14 +245,10 @@ int __init prominfo_init(void)
                sprintf(name, "node%d", cnodeid);
                *entp = proc_mkdir(name, sgi_prominfo_entry);
                nasid = cnodeid_to_nasid(cnodeid);
-               p = create_proc_read_entry("fit", 0, *entp, read_fit_entry,
+               create_proc_read_entry("fit", 0, *entp, read_fit_entry,
                                           (void *)nasid);
-               if (p)
-                       p->owner = THIS_MODULE;
-               p = create_proc_read_entry("version", 0, *entp,
+               create_proc_read_entry("version", 0, *entp,
                                           read_version_entry, (void *)nasid);
-               if (p)
-                       p->owner = THIS_MODULE;
                entp++;
        }
 
index e585f9a2afb936c74f9ec0ceea13beb1ef7271c4..1176506b2baeb780e5cad3ba08cb533c54a801d8 100644 (file)
@@ -133,7 +133,7 @@ sn2_ipi_flush_all_tlb(struct mm_struct *mm)
        unsigned long itc;
 
        itc = ia64_get_itc();
-       smp_flush_tlb_cpumask(mm->cpu_vm_mask);
+       smp_flush_tlb_cpumask(*mm_cpumask(mm));
        itc = ia64_get_itc() - itc;
        __get_cpu_var(ptcstats).shub_ipi_flushes_itc_clocks += itc;
        __get_cpu_var(ptcstats).shub_ipi_flushes++;
@@ -182,7 +182,7 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start,
        nodes_clear(nodes_flushed);
        i = 0;
 
-       for_each_cpu_mask(cpu, mm->cpu_vm_mask) {
+       for_each_cpu(cpu, mm_cpumask(mm)) {
                cnode = cpu_to_node(cpu);
                node_set(cnode, nodes_flushed);
                lcpu = cpu;
@@ -461,7 +461,7 @@ bool sn_cpu_disable_allowed(int cpu)
 
 static void *sn2_ptc_seq_start(struct seq_file *file, loff_t * offset)
 {
-       if (*offset < NR_CPUS)
+       if (*offset < nr_cpu_ids)
                return offset;
        return NULL;
 }
@@ -469,7 +469,7 @@ static void *sn2_ptc_seq_start(struct seq_file *file, loff_t * offset)
 static void *sn2_ptc_seq_next(struct seq_file *file, void *data, loff_t * offset)
 {
        (*offset)++;
-       if (*offset < NR_CPUS)
+       if (*offset < nr_cpu_ids)
                return offset;
        return NULL;
 }
@@ -491,7 +491,7 @@ static int sn2_ptc_seq_show(struct seq_file *file, void *data)
                seq_printf(file, "# ptctest %d, flushopt %d\n", sn2_ptctest, sn2_flush_opt);
        }
 
-       if (cpu < NR_CPUS && cpu_online(cpu)) {
+       if (cpu < nr_cpu_ids && cpu_online(cpu)) {
                stat = &per_cpu(ptcstats, cpu);
                seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n", cpu, stat->ptc_l,
                                stat->change_rid, stat->shub_ptc_flushes, stat->nodes_flushed,
@@ -554,7 +554,7 @@ static int __init sn2_ptc_init(void)
 
        proc_sn2_ptc = proc_create(PTC_BASENAME, 0444,
                                   NULL, &proc_sn2_ptc_operations);
-       if (!&proc_sn2_ptc_operations) {
+       if (!proc_sn2_ptc) {
                printk(KERN_ERR "unable to create %s proc entry", PTC_BASENAME);
                return -EINVAL;
        }
index be339477f90603f8a5186dc5a634165dcd3b5e3e..9e6491cf72bd4f1d1246b826e4fa878b4fce7394 100644 (file)
@@ -275,8 +275,7 @@ static int sn_hwperf_get_nearest_node_objdata(struct sn_hwperf_object_info *objb
 
        /* get it's interconnect topology */
        sz = op->ports * sizeof(struct sn_hwperf_port_info);
-       if (sz > sizeof(ptdata))
-               BUG();
+       BUG_ON(sz > sizeof(ptdata));
        e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
                              SN_HWPERF_ENUM_PORTS, nodeobj->id, sz,
                              (u64)&ptdata, 0, 0, NULL);
@@ -310,8 +309,7 @@ static int sn_hwperf_get_nearest_node_objdata(struct sn_hwperf_object_info *objb
        if (router && (!found_cpu || !found_mem)) {
                /* search for a node connected to the same router */
                sz = router->ports * sizeof(struct sn_hwperf_port_info);
-               if (sz > sizeof(ptdata))
-                       BUG();
+               BUG_ON(sz > sizeof(ptdata));
                e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
                                      SN_HWPERF_ENUM_PORTS, router->id, sz,
                                      (u64)&ptdata, 0, 0, NULL);
@@ -612,7 +610,7 @@ static int sn_hwperf_op_cpu(struct sn_hwperf_op_info *op_info)
        op_info->a->arg &= SN_HWPERF_ARG_OBJID_MASK;
 
        if (cpu != SN_HWPERF_ARG_ANY_CPU) {
-               if (cpu >= NR_CPUS || !cpu_online(cpu)) {
+               if (cpu >= nr_cpu_ids || !cpu_online(cpu)) {
                        r = -EINVAL;
                        goto out;
                }
index 863f5017baae6d6981ff809ce2ffe931d8fdcdf6..8c130e8f00e1d3aee8052eb3141b8e33eb3ec3bd 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include <linux/module.h>
-#include <linux/dma-attrs.h>
+#include <linux/dma-mapping.h>
 #include <asm/dma.h>
 #include <asm/sn/intr.h>
 #include <asm/sn/pcibus_provider_defs.h>
@@ -31,7 +31,7 @@
  * this function.  Of course, SN only supports devices that have 32 or more
  * address bits when using the PMU.
  */
-int sn_dma_supported(struct device *dev, u64 mask)
+static int sn_dma_supported(struct device *dev, u64 mask)
 {
        BUG_ON(dev->bus != &pci_bus_type);
 
@@ -39,7 +39,6 @@ int sn_dma_supported(struct device *dev, u64 mask)
                return 0;
        return 1;
 }
-EXPORT_SYMBOL(sn_dma_supported);
 
 /**
  * sn_dma_set_mask - set the DMA mask
@@ -75,8 +74,8 @@ EXPORT_SYMBOL(sn_dma_set_mask);
  * queue for a SCSI controller).  See Documentation/DMA-API.txt for
  * more information.
  */
-void *sn_dma_alloc_coherent(struct device *dev, size_t size,
-                           dma_addr_t * dma_handle, gfp_t flags)
+static void *sn_dma_alloc_coherent(struct device *dev, size_t size,
+                                  dma_addr_t * dma_handle, gfp_t flags)
 {
        void *cpuaddr;
        unsigned long phys_addr;
@@ -124,7 +123,6 @@ void *sn_dma_alloc_coherent(struct device *dev, size_t size,
 
        return cpuaddr;
 }
-EXPORT_SYMBOL(sn_dma_alloc_coherent);
 
 /**
  * sn_pci_free_coherent - free memory associated with coherent DMAable region
@@ -136,8 +134,8 @@ EXPORT_SYMBOL(sn_dma_alloc_coherent);
  * Frees the memory allocated by dma_alloc_coherent(), potentially unmapping
  * any associated IOMMU mappings.
  */
-void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-                         dma_addr_t dma_handle)
+static void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
+                                dma_addr_t dma_handle)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
@@ -147,7 +145,6 @@ void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
        provider->dma_unmap(pdev, dma_handle, 0);
        free_pages((unsigned long)cpu_addr, get_order(size));
 }
-EXPORT_SYMBOL(sn_dma_free_coherent);
 
 /**
  * sn_dma_map_single_attrs - map a single page for DMA
@@ -173,10 +170,12 @@ EXPORT_SYMBOL(sn_dma_free_coherent);
  * TODO: simplify our interface;
  *       figure out how to save dmamap handle so can use two step.
  */
-dma_addr_t sn_dma_map_single_attrs(struct device *dev, void *cpu_addr,
-                                  size_t size, int direction,
-                                  struct dma_attrs *attrs)
+static dma_addr_t sn_dma_map_page(struct device *dev, struct page *page,
+                                 unsigned long offset, size_t size,
+                                 enum dma_data_direction dir,
+                                 struct dma_attrs *attrs)
 {
+       void *cpu_addr = page_address(page) + offset;
        dma_addr_t dma_addr;
        unsigned long phys_addr;
        struct pci_dev *pdev = to_pci_dev(dev);
@@ -201,7 +200,6 @@ dma_addr_t sn_dma_map_single_attrs(struct device *dev, void *cpu_addr,
        }
        return dma_addr;
 }
-EXPORT_SYMBOL(sn_dma_map_single_attrs);
 
 /**
  * sn_dma_unmap_single_attrs - unamp a DMA mapped page
@@ -215,21 +213,20 @@ EXPORT_SYMBOL(sn_dma_map_single_attrs);
  * by @dma_handle into the coherence domain.  On SN, we're always cache
  * coherent, so we just need to free any ATEs associated with this mapping.
  */
-void sn_dma_unmap_single_attrs(struct device *dev, dma_addr_t dma_addr,
-                              size_t size, int direction,
-                              struct dma_attrs *attrs)
+static void sn_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
+                             size_t size, enum dma_data_direction dir,
+                             struct dma_attrs *attrs)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
 
        BUG_ON(dev->bus != &pci_bus_type);
 
-       provider->dma_unmap(pdev, dma_addr, direction);
+       provider->dma_unmap(pdev, dma_addr, dir);
 }
-EXPORT_SYMBOL(sn_dma_unmap_single_attrs);
 
 /**
- * sn_dma_unmap_sg_attrs - unmap a DMA scatterlist
+ * sn_dma_unmap_sg - unmap a DMA scatterlist
  * @dev: device to unmap
  * @sg: scatterlist to unmap
  * @nhwentries: number of scatterlist entries
@@ -238,9 +235,9 @@ EXPORT_SYMBOL(sn_dma_unmap_single_attrs);
  *
  * Unmap a set of streaming mode DMA translations.
  */
-void sn_dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sgl,
-                          int nhwentries, int direction,
-                          struct dma_attrs *attrs)
+static void sn_dma_unmap_sg(struct device *dev, struct scatterlist *sgl,
+                           int nhwentries, enum dma_data_direction dir,
+                           struct dma_attrs *attrs)
 {
        int i;
        struct pci_dev *pdev = to_pci_dev(dev);
@@ -250,15 +247,14 @@ void sn_dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sgl,
        BUG_ON(dev->bus != &pci_bus_type);
 
        for_each_sg(sgl, sg, nhwentries, i) {
-               provider->dma_unmap(pdev, sg->dma_address, direction);
+               provider->dma_unmap(pdev, sg->dma_address, dir);
                sg->dma_address = (dma_addr_t) NULL;
                sg->dma_length = 0;
        }
 }
-EXPORT_SYMBOL(sn_dma_unmap_sg_attrs);
 
 /**
- * sn_dma_map_sg_attrs - map a scatterlist for DMA
+ * sn_dma_map_sg - map a scatterlist for DMA
  * @dev: device to map for
  * @sg: scatterlist to map
  * @nhwentries: number of entries
@@ -272,8 +268,9 @@ EXPORT_SYMBOL(sn_dma_unmap_sg_attrs);
  *
  * Maps each entry of @sg for DMA.
  */
-int sn_dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
-                       int nhwentries, int direction, struct dma_attrs *attrs)
+static int sn_dma_map_sg(struct device *dev, struct scatterlist *sgl,
+                        int nhwentries, enum dma_data_direction dir,
+                        struct dma_attrs *attrs)
 {
        unsigned long phys_addr;
        struct scatterlist *saved_sg = sgl, *sg;
@@ -310,8 +307,7 @@ int sn_dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
                         * Free any successfully allocated entries.
                         */
                        if (i > 0)
-                               sn_dma_unmap_sg_attrs(dev, saved_sg, i,
-                                                     direction, attrs);
+                               sn_dma_unmap_sg(dev, saved_sg, i, dir, attrs);
                        return 0;
                }
 
@@ -320,41 +316,36 @@ int sn_dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
 
        return nhwentries;
 }
-EXPORT_SYMBOL(sn_dma_map_sg_attrs);
 
-void sn_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-                               size_t size, int direction)
+static void sn_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+                                      size_t size, enum dma_data_direction dir)
 {
        BUG_ON(dev->bus != &pci_bus_type);
 }
-EXPORT_SYMBOL(sn_dma_sync_single_for_cpu);
 
-void sn_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
-                                  size_t size, int direction)
+static void sn_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+                                         size_t size,
+                                         enum dma_data_direction dir)
 {
        BUG_ON(dev->bus != &pci_bus_type);
 }
-EXPORT_SYMBOL(sn_dma_sync_single_for_device);
 
-void sn_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
-                           int nelems, int direction)
+static void sn_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+                                  int nelems, enum dma_data_direction dir)
 {
        BUG_ON(dev->bus != &pci_bus_type);
 }
-EXPORT_SYMBOL(sn_dma_sync_sg_for_cpu);
 
-void sn_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
-                              int nelems, int direction)
+static void sn_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+                                     int nelems, enum dma_data_direction dir)
 {
        BUG_ON(dev->bus != &pci_bus_type);
 }
-EXPORT_SYMBOL(sn_dma_sync_sg_for_device);
 
-int sn_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+static int sn_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
        return 0;
 }
-EXPORT_SYMBOL(sn_dma_mapping_error);
 
 u64 sn_dma_get_required_mask(struct device *dev)
 {
@@ -471,3 +462,23 @@ int sn_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size)
  out:
        return ret;
 }
+
+static struct dma_map_ops sn_dma_ops = {
+       .alloc_coherent         = sn_dma_alloc_coherent,
+       .free_coherent          = sn_dma_free_coherent,
+       .map_page               = sn_dma_map_page,
+       .unmap_page             = sn_dma_unmap_page,
+       .map_sg                 = sn_dma_map_sg,
+       .unmap_sg               = sn_dma_unmap_sg,
+       .sync_single_for_cpu    = sn_dma_sync_single_for_cpu,
+       .sync_sg_for_cpu        = sn_dma_sync_sg_for_cpu,
+       .sync_single_for_device = sn_dma_sync_single_for_device,
+       .sync_sg_for_device     = sn_dma_sync_sg_for_device,
+       .mapping_error          = sn_dma_mapping_error,
+       .dma_supported          = sn_dma_supported,
+};
+
+void sn_dma_init(void)
+{
+       dma_ops = &sn_dma_ops;
+}
index 060df4aa9916853297a0be09d4221c5a95e37654..c659ad5613a009f1fea4922275c5d83d286e3b71 100644 (file)
@@ -256,9 +256,7 @@ void sn_dma_flush(u64 addr)
 
        hubinfo = (NODEPDA(nasid_to_cnodeid(nasid)))->pdinfo;
 
-       if (!hubinfo) {
-               BUG();
-       }
+       BUG_ON(!hubinfo);
 
        flush_nasid_list = &hubinfo->hdi_flush_nasid_list;
        if (flush_nasid_list->widget_p == NULL)
index 0ad0224693d99b75bca4724459c454cb5f7f000a..e6f4a0a74228adcafd9628fec7215afd4bc8044b 100644 (file)
@@ -3,14 +3,29 @@
 #
 
 obj-y := hypercall.o xenivt.o xensetup.o xen_pv_ops.o irq_xen.o \
-        hypervisor.o xencomm.o xcom_hcall.o grant-table.o time.o suspend.o
+        hypervisor.o xencomm.o xcom_hcall.o grant-table.o time.o suspend.o \
+        gate-data.o
 
 obj-$(CONFIG_IA64_GENERIC) += machvec.o
 
+# The gate DSO image is built using a special linker script.
+include $(srctree)/arch/ia64/kernel/Makefile.gate
+
+# tell compiled for xen
+CPPFLAGS_gate.lds += -D__IA64_GATE_PARAVIRTUALIZED_XEN
+AFLAGS_gate.o += -D__IA64_ASM_PARAVIRTUALIZED_XEN -D__IA64_GATE_PARAVIRTUALIZED_XEN
+
+# use same file of native.
+$(obj)/gate.o: $(src)/../kernel/gate.S FORCE
+       $(call if_changed_dep,as_o_S)
+$(obj)/gate.lds: $(src)/../kernel/gate.lds.S FORCE
+       $(call if_changed_dep,cpp_lds_S)
+
+
 AFLAGS_xenivt.o += -D__IA64_ASM_PARAVIRTUALIZED_XEN
 
 # xen multi compile
-ASM_PARAVIRT_MULTI_COMPILE_SRCS = ivt.S entry.S
+ASM_PARAVIRT_MULTI_COMPILE_SRCS = ivt.S entry.S fsys.S
 ASM_PARAVIRT_OBJS = $(addprefix xen-,$(ASM_PARAVIRT_MULTI_COMPILE_SRCS:.S=.o))
 obj-y += $(ASM_PARAVIRT_OBJS)
 define paravirtualized_xen
diff --git a/arch/ia64/xen/gate-data.S b/arch/ia64/xen/gate-data.S
new file mode 100644 (file)
index 0000000..7d4830a
--- /dev/null
@@ -0,0 +1,3 @@
+       .section .data.gate.xen, "aw"
+
+       .incbin "arch/ia64/xen/gate.so"
index 45e02bb64a92353137b484cd1d9d1d364f60ca63..e32dae444dd6ec077f0f1ae259927aac723d5ec7 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/intrinsics.h>
 #include <asm/xen/privop.h>
 
+#ifdef __INTEL_COMPILER
 /*
  * Hypercalls without parameter.
  */
@@ -72,6 +73,7 @@ GLOBAL_ENTRY(xen_set_rr0_to_rr4)
        br.ret.sptk.many rp
        ;;
 END(xen_set_rr0_to_rr4)
+#endif
 
 GLOBAL_ENTRY(xen_send_ipi)
        mov r14=r32
index 68d6204c3f1627d0bd76cb04b1aeef2cf885218f..fb8332690179062dafee85ab92075b8fb8d4a3cc 100644 (file)
@@ -175,10 +175,58 @@ static void xen_itc_jitter_data_reset(void)
        } while (unlikely(ret != lcycle));
 }
 
+/* based on xen_sched_clock() in arch/x86/xen/time.c. */
+/*
+ * This relies on HAVE_UNSTABLE_SCHED_CLOCK. If it can't be defined,
+ * something similar logic should be implemented here.
+ */
+/*
+ * Xen sched_clock implementation.  Returns the number of unstolen
+ * nanoseconds, which is nanoseconds the VCPU spent in RUNNING+BLOCKED
+ * states.
+ */
+static unsigned long long xen_sched_clock(void)
+{
+       struct vcpu_runstate_info runstate;
+
+       unsigned long long now;
+       unsigned long long offset;
+       unsigned long long ret;
+
+       /*
+        * Ideally sched_clock should be called on a per-cpu basis
+        * anyway, so preempt should already be disabled, but that's
+        * not current practice at the moment.
+        */
+       preempt_disable();
+
+       /*
+        * both ia64_native_sched_clock() and xen's runstate are
+        * based on mAR.ITC. So difference of them makes sense.
+        */
+       now = ia64_native_sched_clock();
+
+       get_runstate_snapshot(&runstate);
+
+       WARN_ON(runstate.state != RUNSTATE_running);
+
+       offset = 0;
+       if (now > runstate.state_entry_time)
+               offset = now - runstate.state_entry_time;
+       ret = runstate.time[RUNSTATE_blocked] +
+               runstate.time[RUNSTATE_running] +
+               offset;
+
+       preempt_enable();
+
+       return ret;
+}
+
 struct pv_time_ops xen_time_ops __initdata = {
        .init_missing_ticks_accounting  = xen_init_missing_ticks_accounting,
        .do_steal_accounting            = xen_do_steal_accounting,
        .clocksource_resume             = xen_itc_jitter_data_reset,
+       .sched_clock                    = xen_sched_clock,
 };
 
 /* Called after suspend, to resume time.  */
index 936cff3c96e0215f413054d038950fc8ecc22973..5e2270a999fa58f410093c50cd30f92510c7a780 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/pm.h>
+#include <linux/unistd.h>
 
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/xencomm.h>
@@ -153,6 +154,13 @@ xen_post_smp_prepare_boot_cpu(void)
        xen_setup_vcpu_info_placement();
 }
 
+#ifdef ASM_SUPPORTED
+static unsigned long __init_or_module
+xen_patch_bundle(void *sbundle, void *ebundle, unsigned long type);
+#endif
+static void __init
+xen_patch_branch(unsigned long tag, unsigned long type);
+
 static const struct pv_init_ops xen_init_ops __initconst = {
        .banner = xen_banner,
 
@@ -163,6 +171,53 @@ static const struct pv_init_ops xen_init_ops __initconst = {
        .arch_setup_nomca = xen_arch_setup_nomca,
 
        .post_smp_prepare_boot_cpu = xen_post_smp_prepare_boot_cpu,
+#ifdef ASM_SUPPORTED
+       .patch_bundle = xen_patch_bundle,
+#endif
+       .patch_branch = xen_patch_branch,
+};
+
+/***************************************************************************
+ * pv_fsys_data
+ * addresses for fsys
+ */
+
+extern unsigned long xen_fsyscall_table[NR_syscalls];
+extern char xen_fsys_bubble_down[];
+struct pv_fsys_data xen_fsys_data __initdata = {
+       .fsyscall_table = (unsigned long *)xen_fsyscall_table,
+       .fsys_bubble_down = (void *)xen_fsys_bubble_down,
+};
+
+/***************************************************************************
+ * pv_patchdata
+ * patchdata addresses
+ */
+
+#define DECLARE(name)                                                  \
+       extern unsigned long __xen_start_gate_##name##_patchlist[];     \
+       extern unsigned long __xen_end_gate_##name##_patchlist[]
+
+DECLARE(fsyscall);
+DECLARE(brl_fsys_bubble_down);
+DECLARE(vtop);
+DECLARE(mckinley_e9);
+
+extern unsigned long __xen_start_gate_section[];
+
+#define ASSIGN(name)                                                   \
+       .start_##name##_patchlist =                                     \
+               (unsigned long)__xen_start_gate_##name##_patchlist,     \
+       .end_##name##_patchlist =                                       \
+               (unsigned long)__xen_end_gate_##name##_patchlist
+
+static struct pv_patchdata xen_patchdata __initdata = {
+       ASSIGN(fsyscall),
+       ASSIGN(brl_fsys_bubble_down),
+       ASSIGN(vtop),
+       ASSIGN(mckinley_e9),
+
+       .gate_section = (void*)__xen_start_gate_section,
 };
 
 /***************************************************************************
@@ -170,6 +225,76 @@ static const struct pv_init_ops xen_init_ops __initconst = {
  * intrinsics hooks.
  */
 
+#ifndef ASM_SUPPORTED
+static void
+xen_set_itm_with_offset(unsigned long val)
+{
+       /* ia64_cpu_local_tick() calls this with interrupt enabled. */
+       /* WARN_ON(!irqs_disabled()); */
+       xen_set_itm(val - XEN_MAPPEDREGS->itc_offset);
+}
+
+static unsigned long
+xen_get_itm_with_offset(void)
+{
+       /* unused at this moment */
+       printk(KERN_DEBUG "%s is called.\n", __func__);
+
+       WARN_ON(!irqs_disabled());
+       return ia64_native_getreg(_IA64_REG_CR_ITM) +
+               XEN_MAPPEDREGS->itc_offset;
+}
+
+/* ia64_set_itc() is only called by
+ * cpu_init() with ia64_set_itc(0) and ia64_sync_itc().
+ * So XEN_MAPPEDRESG->itc_offset cal be considered as almost constant.
+ */
+static void
+xen_set_itc(unsigned long val)
+{
+       unsigned long mitc;
+
+       WARN_ON(!irqs_disabled());
+       mitc = ia64_native_getreg(_IA64_REG_AR_ITC);
+       XEN_MAPPEDREGS->itc_offset = val - mitc;
+       XEN_MAPPEDREGS->itc_last = val;
+}
+
+static unsigned long
+xen_get_itc(void)
+{
+       unsigned long res;
+       unsigned long itc_offset;
+       unsigned long itc_last;
+       unsigned long ret_itc_last;
+
+       itc_offset = XEN_MAPPEDREGS->itc_offset;
+       do {
+               itc_last = XEN_MAPPEDREGS->itc_last;
+               res = ia64_native_getreg(_IA64_REG_AR_ITC);
+               res += itc_offset;
+               if (itc_last >= res)
+                       res = itc_last + 1;
+               ret_itc_last = cmpxchg(&XEN_MAPPEDREGS->itc_last,
+                                      itc_last, res);
+       } while (unlikely(ret_itc_last != itc_last));
+       return res;
+
+#if 0
+       /* ia64_itc_udelay() calls ia64_get_itc() with interrupt enabled.
+          Should it be paravirtualized instead? */
+       WARN_ON(!irqs_disabled());
+       itc_offset = XEN_MAPPEDREGS->itc_offset;
+       itc_last = XEN_MAPPEDREGS->itc_last;
+       res = ia64_native_getreg(_IA64_REG_AR_ITC);
+       res += itc_offset;
+       if (itc_last >= res)
+               res = itc_last + 1;
+       XEN_MAPPEDREGS->itc_last = res;
+       return res;
+#endif
+}
+
 static void xen_setreg(int regnum, unsigned long val)
 {
        switch (regnum) {
@@ -181,11 +306,14 @@ static void xen_setreg(int regnum, unsigned long val)
                xen_set_eflag(val);
                break;
 #endif
+       case _IA64_REG_AR_ITC:
+               xen_set_itc(val);
+               break;
        case _IA64_REG_CR_TPR:
                xen_set_tpr(val);
                break;
        case _IA64_REG_CR_ITM:
-               xen_set_itm(val);
+               xen_set_itm_with_offset(val);
                break;
        case _IA64_REG_CR_EOI:
                xen_eoi(val);
@@ -209,6 +337,12 @@ static unsigned long xen_getreg(int regnum)
                res = xen_get_eflag();
                break;
 #endif
+       case _IA64_REG_AR_ITC:
+               res = xen_get_itc();
+               break;
+       case _IA64_REG_CR_ITM:
+               res = xen_get_itm_with_offset();
+               break;
        case _IA64_REG_CR_IVR:
                res = xen_get_ivr();
                break;
@@ -259,8 +393,417 @@ xen_intrin_local_irq_restore(unsigned long mask)
        else
                xen_rsm_i();
 }
+#else
+#define __DEFINE_FUNC(name, code)                                      \
+       extern const char xen_ ## name ## _direct_start[];              \
+       extern const char xen_ ## name ## _direct_end[];                \
+       asm (".align 32\n"                                              \
+            ".proc xen_" #name "\n"                                    \
+            "xen_" #name ":\n"                                         \
+            "xen_" #name "_direct_start:\n"                            \
+            code                                                       \
+            "xen_" #name "_direct_end:\n"                              \
+            "br.cond.sptk.many b6\n"                                   \
+            ".endp xen_" #name "\n")
+
+#define DEFINE_VOID_FUNC0(name, code)          \
+       extern void                             \
+       xen_ ## name (void);                    \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_VOID_FUNC1(name, code)          \
+       extern void                             \
+       xen_ ## name (unsigned long arg);       \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_VOID_FUNC1_VOID(name, code)     \
+       extern void                             \
+       xen_ ## name (void *arg);               \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_VOID_FUNC2(name, code)          \
+       extern void                             \
+       xen_ ## name (unsigned long arg0,       \
+                     unsigned long arg1);      \
+       __DEFINE_FUNC(name, code)
 
-static const struct pv_cpu_ops xen_cpu_ops __initdata = {
+#define DEFINE_FUNC0(name, code)               \
+       extern unsigned long                    \
+       xen_ ## name (void);                    \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_FUNC1(name, type, code)         \
+       extern unsigned long                    \
+       xen_ ## name (type arg);                \
+       __DEFINE_FUNC(name, code)
+
+#define XEN_PSR_I_ADDR_ADDR     (XSI_BASE + XSI_PSR_I_ADDR_OFS)
+
+/*
+ * static void xen_set_itm_with_offset(unsigned long val)
+ *        xen_set_itm(val - XEN_MAPPEDREGS->itc_offset);
+ */
+/* 2 bundles */
+DEFINE_VOID_FUNC1(set_itm_with_offset,
+                 "mov r2 = " __stringify(XSI_BASE) " + "
+                 __stringify(XSI_ITC_OFFSET_OFS) "\n"
+                 ";;\n"
+                 "ld8 r3 = [r2]\n"
+                 ";;\n"
+                 "sub r8 = r8, r3\n"
+                 "break " __stringify(HYPERPRIVOP_SET_ITM) "\n");
+
+/*
+ * static unsigned long xen_get_itm_with_offset(void)
+ *    return ia64_native_getreg(_IA64_REG_CR_ITM) + XEN_MAPPEDREGS->itc_offset;
+ */
+/* 2 bundles */
+DEFINE_FUNC0(get_itm_with_offset,
+            "mov r2 = " __stringify(XSI_BASE) " + "
+            __stringify(XSI_ITC_OFFSET_OFS) "\n"
+            ";;\n"
+            "ld8 r3 = [r2]\n"
+            "mov r8 = cr.itm\n"
+            ";;\n"
+            "add r8 = r8, r2\n");
+
+/*
+ * static void xen_set_itc(unsigned long val)
+ *     unsigned long mitc;
+ *
+ *     WARN_ON(!irqs_disabled());
+ *     mitc = ia64_native_getreg(_IA64_REG_AR_ITC);
+ *     XEN_MAPPEDREGS->itc_offset = val - mitc;
+ *     XEN_MAPPEDREGS->itc_last = val;
+ */
+/* 2 bundles */
+DEFINE_VOID_FUNC1(set_itc,
+                 "mov r2 = " __stringify(XSI_BASE) " + "
+                 __stringify(XSI_ITC_LAST_OFS) "\n"
+                 "mov r3 = ar.itc\n"
+                 ";;\n"
+                 "sub r3 = r8, r3\n"
+                 "st8 [r2] = r8, "
+                 __stringify(XSI_ITC_LAST_OFS) " - "
+                 __stringify(XSI_ITC_OFFSET_OFS) "\n"
+                 ";;\n"
+                 "st8 [r2] = r3\n");
+
+/*
+ * static unsigned long xen_get_itc(void)
+ *     unsigned long res;
+ *     unsigned long itc_offset;
+ *     unsigned long itc_last;
+ *     unsigned long ret_itc_last;
+ *
+ *     itc_offset = XEN_MAPPEDREGS->itc_offset;
+ *     do {
+ *             itc_last = XEN_MAPPEDREGS->itc_last;
+ *             res = ia64_native_getreg(_IA64_REG_AR_ITC);
+ *             res += itc_offset;
+ *             if (itc_last >= res)
+ *                     res = itc_last + 1;
+ *             ret_itc_last = cmpxchg(&XEN_MAPPEDREGS->itc_last,
+ *                                    itc_last, res);
+ *     } while (unlikely(ret_itc_last != itc_last));
+ *     return res;
+ */
+/* 5 bundles */
+DEFINE_FUNC0(get_itc,
+            "mov r2 = " __stringify(XSI_BASE) " + "
+            __stringify(XSI_ITC_OFFSET_OFS) "\n"
+            ";;\n"
+            "ld8 r9 = [r2], " __stringify(XSI_ITC_LAST_OFS) " - "
+            __stringify(XSI_ITC_OFFSET_OFS) "\n"
+                                       /* r9 = itc_offset */
+                                       /* r2 = XSI_ITC_OFFSET */
+            "888:\n"
+            "mov r8 = ar.itc\n"        /* res = ar.itc */
+            ";;\n"
+            "ld8 r3 = [r2]\n"          /* r3 = itc_last */
+            "add r8 = r8, r9\n"        /* res = ar.itc + itc_offset */
+            ";;\n"
+            "cmp.gtu p6, p0 = r3, r8\n"
+            ";;\n"
+            "(p6) add r8 = 1, r3\n"    /* if (itc_last > res) itc_last + 1 */
+            ";;\n"
+            "mov ar.ccv = r8\n"
+            ";;\n"
+            "cmpxchg8.acq r10 = [r2], r8, ar.ccv\n"
+            ";;\n"
+            "cmp.ne p6, p0 = r10, r3\n"
+            "(p6) hint @pause\n"
+            "(p6) br.cond.spnt 888b\n");
+
+DEFINE_VOID_FUNC1_VOID(fc,
+                      "break " __stringify(HYPERPRIVOP_FC) "\n");
+
+/*
+ * psr_i_addr_addr = XEN_PSR_I_ADDR_ADDR
+ * masked_addr = *psr_i_addr_addr
+ * pending_intr_addr = masked_addr - 1
+ * if (val & IA64_PSR_I) {
+ *   masked = *masked_addr
+ *   *masked_addr = 0:xen_set_virtual_psr_i(1)
+ *   compiler barrier
+ *   if (masked) {
+ *      uint8_t pending = *pending_intr_addr;
+ *      if (pending)
+ *              XEN_HYPER_SSM_I
+ *   }
+ * } else {
+ *   *masked_addr = 1:xen_set_virtual_psr_i(0)
+ * }
+ */
+/* 6 bundles */
+DEFINE_VOID_FUNC1(intrin_local_irq_restore,
+                 /* r8 = input value: 0 or IA64_PSR_I
+                  * p6 =  (flags & IA64_PSR_I)
+                  *    = if clause
+                  * p7 = !(flags & IA64_PSR_I)
+                  *    = else clause
+                  */
+                 "cmp.ne p6, p7 = r8, r0\n"
+                 "mov r9 = " __stringify(XEN_PSR_I_ADDR_ADDR) "\n"
+                 ";;\n"
+                 /* r9 = XEN_PSR_I_ADDR */
+                 "ld8 r9 = [r9]\n"
+                 ";;\n"
+
+                 /* r10 = masked previous value */
+                 "(p6) ld1.acq r10 = [r9]\n"
+                 ";;\n"
+
+                 /* p8 = !masked interrupt masked previously? */
+                 "(p6) cmp.ne.unc p8, p0 = r10, r0\n"
+
+                 /* p7 = else clause */
+                 "(p7) mov r11 = 1\n"
+                 ";;\n"
+                 /* masked = 1 */
+                 "(p7) st1.rel [r9] = r11\n"
+
+                 /* p6 = if clause */
+                 /* masked = 0
+                  * r9 = masked_addr - 1
+                  *    = pending_intr_addr
+                  */
+                 "(p8) st1.rel [r9] = r0, -1\n"
+                 ";;\n"
+                 /* r8 = pending_intr */
+                 "(p8) ld1.acq r11 = [r9]\n"
+                 ";;\n"
+                 /* p9 = interrupt pending? */
+                 "(p8) cmp.ne.unc p9, p10 = r11, r0\n"
+                 ";;\n"
+                 "(p10) mf\n"
+                 /* issue hypercall to trigger interrupt */
+                 "(p9) break " __stringify(HYPERPRIVOP_SSM_I) "\n");
+
+DEFINE_VOID_FUNC2(ptcga,
+                 "break " __stringify(HYPERPRIVOP_PTC_GA) "\n");
+DEFINE_VOID_FUNC2(set_rr,
+                 "break " __stringify(HYPERPRIVOP_SET_RR) "\n");
+
+/*
+ * tmp = XEN_MAPPEDREGS->interrupt_mask_addr = XEN_PSR_I_ADDR_ADDR;
+ * tmp = *tmp
+ * tmp = *tmp;
+ * psr_i = tmp? 0: IA64_PSR_I;
+ */
+/* 4 bundles */
+DEFINE_FUNC0(get_psr_i,
+            "mov r9 = " __stringify(XEN_PSR_I_ADDR_ADDR) "\n"
+            ";;\n"
+            "ld8 r9 = [r9]\n"                  /* r9 = XEN_PSR_I_ADDR */
+            "mov r8 = 0\n"                     /* psr_i = 0 */
+            ";;\n"
+            "ld1.acq r9 = [r9]\n"              /* r9 = XEN_PSR_I */
+            ";;\n"
+            "cmp.eq.unc p6, p0 = r9, r0\n"     /* p6 = (XEN_PSR_I != 0) */
+            ";;\n"
+            "(p6) mov r8 = " __stringify(1 << IA64_PSR_I_BIT) "\n");
+
+DEFINE_FUNC1(thash, unsigned long,
+            "break " __stringify(HYPERPRIVOP_THASH) "\n");
+DEFINE_FUNC1(get_cpuid, int,
+            "break " __stringify(HYPERPRIVOP_GET_CPUID) "\n");
+DEFINE_FUNC1(get_pmd, int,
+            "break " __stringify(HYPERPRIVOP_GET_PMD) "\n");
+DEFINE_FUNC1(get_rr, unsigned long,
+            "break " __stringify(HYPERPRIVOP_GET_RR) "\n");
+
+/*
+ * void xen_privop_ssm_i(void)
+ *
+ * int masked = !xen_get_virtual_psr_i();
+ *     // masked = *(*XEN_MAPPEDREGS->interrupt_mask_addr)
+ * xen_set_virtual_psr_i(1)
+ *     // *(*XEN_MAPPEDREGS->interrupt_mask_addr) = 0
+ * // compiler barrier
+ * if (masked) {
+ *     uint8_t* pend_int_addr =
+ *             (uint8_t*)(*XEN_MAPPEDREGS->interrupt_mask_addr) - 1;
+ *     uint8_t pending = *pend_int_addr;
+ *     if (pending)
+ *             XEN_HYPER_SSM_I
+ * }
+ */
+/* 4 bundles */
+DEFINE_VOID_FUNC0(ssm_i,
+                 "mov r8 = " __stringify(XEN_PSR_I_ADDR_ADDR) "\n"
+                 ";;\n"
+                 "ld8 r8 = [r8]\n"             /* r8 = XEN_PSR_I_ADDR */
+                 ";;\n"
+                 "ld1.acq r9 = [r8]\n"         /* r9 = XEN_PSR_I */
+                 ";;\n"
+                 "st1.rel [r8] = r0, -1\n"     /* psr_i = 0. enable interrupt
+                                                * r8 = XEN_PSR_I_ADDR - 1
+                                                *    = pend_int_addr
+                                                */
+                 "cmp.eq.unc p0, p6 = r9, r0\n"/* p6 = !XEN_PSR_I
+                                                * previously interrupt
+                                                * masked?
+                                                */
+                 ";;\n"
+                 "(p6) ld1.acq r8 = [r8]\n"    /* r8 = xen_pend_int */
+                 ";;\n"
+                 "(p6) cmp.eq.unc p6, p7 = r8, r0\n"   /*interrupt pending?*/
+                 ";;\n"
+                 /* issue hypercall to get interrupt */
+                 "(p7) break " __stringify(HYPERPRIVOP_SSM_I) "\n"
+                 ";;\n");
+
+/*
+ * psr_i_addr_addr = XEN_MAPPEDREGS->interrupt_mask_addr
+ *                = XEN_PSR_I_ADDR_ADDR;
+ * psr_i_addr = *psr_i_addr_addr;
+ * *psr_i_addr = 1;
+ */
+/* 2 bundles */
+DEFINE_VOID_FUNC0(rsm_i,
+                 "mov r8 = " __stringify(XEN_PSR_I_ADDR_ADDR) "\n"
+                                               /* r8 = XEN_PSR_I_ADDR */
+                 "mov r9 = 1\n"
+                 ";;\n"
+                 "ld8 r8 = [r8]\n"             /* r8 = XEN_PSR_I */
+                 ";;\n"
+                 "st1.rel [r8] = r9\n");       /* XEN_PSR_I = 1 */
+
+extern void
+xen_set_rr0_to_rr4(unsigned long val0, unsigned long val1,
+                  unsigned long val2, unsigned long val3,
+                  unsigned long val4);
+__DEFINE_FUNC(set_rr0_to_rr4,
+             "break " __stringify(HYPERPRIVOP_SET_RR0_TO_RR4) "\n");
+
+
+extern unsigned long xen_getreg(int regnum);
+#define __DEFINE_GET_REG(id, privop)                                   \
+       "mov r2 = " __stringify(_IA64_REG_ ## id) "\n"                  \
+       ";;\n"                                                          \
+       "cmp.eq p6, p0 = r2, r8\n"                                      \
+       ";;\n"                                                          \
+       "(p6) break " __stringify(HYPERPRIVOP_GET_ ## privop) "\n"      \
+       "(p6) br.cond.sptk.many b6\n"                                   \
+       ";;\n"
+
+__DEFINE_FUNC(getreg,
+             __DEFINE_GET_REG(PSR, PSR)
+#ifdef CONFIG_IA32_SUPPORT
+             __DEFINE_GET_REG(AR_EFLAG, EFLAG)
+#endif
+
+             /* get_itc */
+             "mov r2 = " __stringify(_IA64_REG_AR_ITC) "\n"
+             ";;\n"
+             "cmp.eq p6, p0 = r2, r8\n"
+             ";;\n"
+             "(p6) br.cond.spnt xen_get_itc\n"
+             ";;\n"
+
+             /* get itm */
+             "mov r2 = " __stringify(_IA64_REG_CR_ITM) "\n"
+             ";;\n"
+             "cmp.eq p6, p0 = r2, r8\n"
+             ";;\n"
+             "(p6) br.cond.spnt xen_get_itm_with_offset\n"
+             ";;\n"
+
+             __DEFINE_GET_REG(CR_IVR, IVR)
+             __DEFINE_GET_REG(CR_TPR, TPR)
+
+             /* fall back */
+             "movl r2 = ia64_native_getreg_func\n"
+             ";;\n"
+             "mov b7 = r2\n"
+             ";;\n"
+             "br.cond.sptk.many b7\n");
+
+extern void xen_setreg(int regnum, unsigned long val);
+#define __DEFINE_SET_REG(id, privop)                                   \
+       "mov r2 = " __stringify(_IA64_REG_ ## id) "\n"                  \
+       ";;\n"                                                          \
+       "cmp.eq p6, p0 = r2, r9\n"                                      \
+       ";;\n"                                                          \
+       "(p6) break " __stringify(HYPERPRIVOP_ ## privop) "\n"          \
+       "(p6) br.cond.sptk.many b6\n"                                   \
+       ";;\n"
+
+__DEFINE_FUNC(setreg,
+             /* kr0 .. kr 7*/
+             /*
+              * if (_IA64_REG_AR_KR0 <= regnum &&
+              *     regnum <= _IA64_REG_AR_KR7) {
+              *     register __index asm ("r8") = regnum - _IA64_REG_AR_KR0
+              *     register __val asm ("r9") = val
+              *    "break HYPERPRIVOP_SET_KR"
+              * }
+              */
+             "mov r17 = r9\n"
+             "mov r2 = " __stringify(_IA64_REG_AR_KR0) "\n"
+             ";;\n"
+             "cmp.ge p6, p0 = r9, r2\n"
+             "sub r17 = r17, r2\n"
+             ";;\n"
+             "(p6) cmp.ge.unc p7, p0 = "
+             __stringify(_IA64_REG_AR_KR7) " - " __stringify(_IA64_REG_AR_KR0)
+             ", r17\n"
+             ";;\n"
+             "(p7) mov r9 = r8\n"
+             ";;\n"
+             "(p7) mov r8 = r17\n"
+             "(p7) break " __stringify(HYPERPRIVOP_SET_KR) "\n"
+
+             /* set itm */
+             "mov r2 = " __stringify(_IA64_REG_CR_ITM) "\n"
+             ";;\n"
+             "cmp.eq p6, p0 = r2, r8\n"
+             ";;\n"
+             "(p6) br.cond.spnt xen_set_itm_with_offset\n"
+
+             /* set itc */
+             "mov r2 = " __stringify(_IA64_REG_AR_ITC) "\n"
+             ";;\n"
+             "cmp.eq p6, p0 = r2, r8\n"
+             ";;\n"
+             "(p6) br.cond.spnt xen_set_itc\n"
+
+#ifdef CONFIG_IA32_SUPPORT
+             __DEFINE_SET_REG(AR_EFLAG, SET_EFLAG)
+#endif
+             __DEFINE_SET_REG(CR_TPR, SET_TPR)
+             __DEFINE_SET_REG(CR_EOI, EOI)
+
+             /* fall back */
+             "movl r2 = ia64_native_setreg_func\n"
+             ";;\n"
+             "mov b7 = r2\n"
+             ";;\n"
+             "br.cond.sptk.many b7\n");
+#endif
+
+static const struct pv_cpu_ops xen_cpu_ops __initconst = {
        .fc             = xen_fc,
        .thash          = xen_thash,
        .get_cpuid      = xen_get_cpuid,
@@ -337,7 +880,7 @@ xen_iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
        HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op);
 }
 
-static const struct pv_iosapic_ops xen_iosapic_ops __initconst = {
+static struct pv_iosapic_ops xen_iosapic_ops __initdata = {
        .pcat_compat_init = xen_pcat_compat_init,
        .__get_irq_chip = xen_iosapic_get_irq_chip,
 
@@ -355,6 +898,8 @@ xen_setup_pv_ops(void)
        xen_info_init();
        pv_info = xen_info;
        pv_init_ops = xen_init_ops;
+       pv_fsys_data = xen_fsys_data;
+       pv_patchdata = xen_patchdata;
        pv_cpu_ops = xen_cpu_ops;
        pv_iosapic_ops = xen_iosapic_ops;
        pv_irq_ops = xen_irq_ops;
@@ -362,3 +907,252 @@ xen_setup_pv_ops(void)
 
        paravirt_cpu_asm_init(&xen_cpu_asm_switch);
 }
+
+#ifdef ASM_SUPPORTED
+/***************************************************************************
+ * binary pacthing
+ * pv_init_ops.patch_bundle
+ */
+
+#define DEFINE_FUNC_GETREG(name, privop)                               \
+       DEFINE_FUNC0(get_ ## name,                                      \
+                    "break "__stringify(HYPERPRIVOP_GET_ ## privop) "\n")
+
+DEFINE_FUNC_GETREG(psr, PSR);
+DEFINE_FUNC_GETREG(eflag, EFLAG);
+DEFINE_FUNC_GETREG(ivr, IVR);
+DEFINE_FUNC_GETREG(tpr, TPR);
+
+#define DEFINE_FUNC_SET_KR(n)                                          \
+       DEFINE_VOID_FUNC0(set_kr ## n,                                  \
+                         ";;\n"                                        \
+                         "mov r9 = r8\n"                               \
+                         "mov r8 = " #n "\n"                           \
+                         "break " __stringify(HYPERPRIVOP_SET_KR) "\n")
+
+DEFINE_FUNC_SET_KR(0);
+DEFINE_FUNC_SET_KR(1);
+DEFINE_FUNC_SET_KR(2);
+DEFINE_FUNC_SET_KR(3);
+DEFINE_FUNC_SET_KR(4);
+DEFINE_FUNC_SET_KR(5);
+DEFINE_FUNC_SET_KR(6);
+DEFINE_FUNC_SET_KR(7);
+
+#define __DEFINE_FUNC_SETREG(name, privop)                             \
+       DEFINE_VOID_FUNC0(name,                                         \
+                         "break "__stringify(HYPERPRIVOP_ ## privop) "\n")
+
+#define DEFINE_FUNC_SETREG(name, privop)                       \
+       __DEFINE_FUNC_SETREG(set_ ## name, SET_ ## privop)
+
+DEFINE_FUNC_SETREG(eflag, EFLAG);
+DEFINE_FUNC_SETREG(tpr, TPR);
+__DEFINE_FUNC_SETREG(eoi, EOI);
+
+extern const char xen_check_events[];
+extern const char __xen_intrin_local_irq_restore_direct_start[];
+extern const char __xen_intrin_local_irq_restore_direct_end[];
+extern const unsigned long __xen_intrin_local_irq_restore_direct_reloc;
+
+asm (
+       ".align 32\n"
+       ".proc xen_check_events\n"
+       "xen_check_events:\n"
+       /* masked = 0
+        * r9 = masked_addr - 1
+        *    = pending_intr_addr
+        */
+       "st1.rel [r9] = r0, -1\n"
+       ";;\n"
+       /* r8 = pending_intr */
+       "ld1.acq r11 = [r9]\n"
+       ";;\n"
+       /* p9 = interrupt pending? */
+       "cmp.ne p9, p10 = r11, r0\n"
+       ";;\n"
+       "(p10) mf\n"
+       /* issue hypercall to trigger interrupt */
+       "(p9) break " __stringify(HYPERPRIVOP_SSM_I) "\n"
+       "br.cond.sptk.many b6\n"
+       ".endp xen_check_events\n"
+       "\n"
+       ".align 32\n"
+       ".proc __xen_intrin_local_irq_restore_direct\n"
+       "__xen_intrin_local_irq_restore_direct:\n"
+       "__xen_intrin_local_irq_restore_direct_start:\n"
+       "1:\n"
+       "{\n"
+       "cmp.ne p6, p7 = r8, r0\n"
+       "mov r17 = ip\n" /* get ip to calc return address */
+       "mov r9 = "__stringify(XEN_PSR_I_ADDR_ADDR) "\n"
+       ";;\n"
+       "}\n"
+       "{\n"
+       /* r9 = XEN_PSR_I_ADDR */
+       "ld8 r9 = [r9]\n"
+       ";;\n"
+       /* r10 = masked previous value */
+       "(p6) ld1.acq r10 = [r9]\n"
+       "adds r17 =  1f - 1b, r17\n" /* calculate return address */
+       ";;\n"
+       "}\n"
+       "{\n"
+       /* p8 = !masked interrupt masked previously? */
+       "(p6) cmp.ne.unc p8, p0 = r10, r0\n"
+       "\n"
+       /* p7 = else clause */
+       "(p7) mov r11 = 1\n"
+       ";;\n"
+       "(p8) mov b6 = r17\n" /* set return address */
+       "}\n"
+       "{\n"
+       /* masked = 1 */
+       "(p7) st1.rel [r9] = r11\n"
+       "\n"
+       "[99:]\n"
+       "(p8) brl.cond.dptk.few xen_check_events\n"
+       "}\n"
+       /* pv calling stub is 5 bundles. fill nop to adjust return address */
+       "{\n"
+       "nop 0\n"
+       "nop 0\n"
+       "nop 0\n"
+       "}\n"
+       "1:\n"
+       "__xen_intrin_local_irq_restore_direct_end:\n"
+       ".endp __xen_intrin_local_irq_restore_direct\n"
+       "\n"
+       ".align 8\n"
+       "__xen_intrin_local_irq_restore_direct_reloc:\n"
+       "data8 99b\n"
+);
+
+static struct paravirt_patch_bundle_elem xen_patch_bundle_elems[]
+__initdata_or_module =
+{
+#define XEN_PATCH_BUNDLE_ELEM(name, type)              \
+       {                                               \
+               (void*)xen_ ## name ## _direct_start,   \
+               (void*)xen_ ## name ## _direct_end,     \
+               PARAVIRT_PATCH_TYPE_ ## type,           \
+       }
+
+       XEN_PATCH_BUNDLE_ELEM(fc, FC),
+       XEN_PATCH_BUNDLE_ELEM(thash, THASH),
+       XEN_PATCH_BUNDLE_ELEM(get_cpuid, GET_CPUID),
+       XEN_PATCH_BUNDLE_ELEM(get_pmd, GET_PMD),
+       XEN_PATCH_BUNDLE_ELEM(ptcga, PTCGA),
+       XEN_PATCH_BUNDLE_ELEM(get_rr, GET_RR),
+       XEN_PATCH_BUNDLE_ELEM(set_rr, SET_RR),
+       XEN_PATCH_BUNDLE_ELEM(set_rr0_to_rr4, SET_RR0_TO_RR4),
+       XEN_PATCH_BUNDLE_ELEM(ssm_i, SSM_I),
+       XEN_PATCH_BUNDLE_ELEM(rsm_i, RSM_I),
+       XEN_PATCH_BUNDLE_ELEM(get_psr_i, GET_PSR_I),
+       {
+               (void*)__xen_intrin_local_irq_restore_direct_start,
+               (void*)__xen_intrin_local_irq_restore_direct_end,
+               PARAVIRT_PATCH_TYPE_INTRIN_LOCAL_IRQ_RESTORE,
+       },
+
+#define XEN_PATCH_BUNDLE_ELEM_GETREG(name, reg)                        \
+       {                                                       \
+               xen_get_ ## name ## _direct_start,              \
+               xen_get_ ## name ## _direct_end,                \
+               PARAVIRT_PATCH_TYPE_GETREG + _IA64_REG_ ## reg, \
+       }
+
+       XEN_PATCH_BUNDLE_ELEM_GETREG(psr, PSR),
+       XEN_PATCH_BUNDLE_ELEM_GETREG(eflag, AR_EFLAG),
+
+       XEN_PATCH_BUNDLE_ELEM_GETREG(ivr, CR_IVR),
+       XEN_PATCH_BUNDLE_ELEM_GETREG(tpr, CR_TPR),
+
+       XEN_PATCH_BUNDLE_ELEM_GETREG(itc, AR_ITC),
+       XEN_PATCH_BUNDLE_ELEM_GETREG(itm_with_offset, CR_ITM),
+
+
+#define __XEN_PATCH_BUNDLE_ELEM_SETREG(name, reg)              \
+       {                                                       \
+               xen_ ## name ## _direct_start,                  \
+               xen_ ## name ## _direct_end,                    \
+               PARAVIRT_PATCH_TYPE_SETREG + _IA64_REG_ ## reg, \
+       }
+
+#define XEN_PATCH_BUNDLE_ELEM_SETREG(name, reg)                        \
+       __XEN_PATCH_BUNDLE_ELEM_SETREG(set_ ## name, reg)
+
+       XEN_PATCH_BUNDLE_ELEM_SETREG(kr0, AR_KR0),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(kr1, AR_KR1),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(kr2, AR_KR2),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(kr3, AR_KR3),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(kr4, AR_KR4),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(kr5, AR_KR5),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(kr6, AR_KR6),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(kr7, AR_KR7),
+
+       XEN_PATCH_BUNDLE_ELEM_SETREG(eflag, AR_EFLAG),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(tpr, CR_TPR),
+       __XEN_PATCH_BUNDLE_ELEM_SETREG(eoi, CR_EOI),
+
+       XEN_PATCH_BUNDLE_ELEM_SETREG(itc, AR_ITC),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(itm_with_offset, CR_ITM),
+};
+
+static unsigned long __init_or_module
+xen_patch_bundle(void *sbundle, void *ebundle, unsigned long type)
+{
+       const unsigned long nelems = sizeof(xen_patch_bundle_elems) /
+               sizeof(xen_patch_bundle_elems[0]);
+       unsigned long used;
+       const struct paravirt_patch_bundle_elem *found;
+
+       used = __paravirt_patch_apply_bundle(sbundle, ebundle, type,
+                                            xen_patch_bundle_elems, nelems,
+                                            &found);
+
+       if (found == NULL)
+               /* fallback */
+               return ia64_native_patch_bundle(sbundle, ebundle, type);
+       if (used == 0)
+               return used;
+
+       /* relocation */
+       switch (type) {
+       case PARAVIRT_PATCH_TYPE_INTRIN_LOCAL_IRQ_RESTORE: {
+               unsigned long reloc =
+                       __xen_intrin_local_irq_restore_direct_reloc;
+               unsigned long reloc_offset = reloc - (unsigned long)
+                       __xen_intrin_local_irq_restore_direct_start;
+               unsigned long tag = (unsigned long)sbundle + reloc_offset;
+               paravirt_patch_reloc_brl(tag, xen_check_events);
+               break;
+       }
+       default:
+               /* nothing */
+               break;
+       }
+       return used;
+}
+#endif /* ASM_SUPPOTED */
+
+const struct paravirt_patch_branch_target xen_branch_target[]
+__initconst = {
+#define PARAVIRT_BR_TARGET(name, type)                 \
+       {                                               \
+               &xen_ ## name,                          \
+               PARAVIRT_PATCH_TYPE_BR_ ## type,        \
+       }
+       PARAVIRT_BR_TARGET(switch_to, SWITCH_TO),
+       PARAVIRT_BR_TARGET(leave_syscall, LEAVE_SYSCALL),
+       PARAVIRT_BR_TARGET(work_processed_syscall, WORK_PROCESSED_SYSCALL),
+       PARAVIRT_BR_TARGET(leave_kernel, LEAVE_KERNEL),
+};
+
+static void __init
+xen_patch_branch(unsigned long tag, unsigned long type)
+{
+       const unsigned long nelem =
+               sizeof(xen_branch_target) / sizeof(xen_branch_target[0]);
+       __paravirt_patch_apply_branch(tag, type, xen_branch_target, nelem);
+}
index 7103d91e1a2f92ee3db9a4d060336ee29c08d347..3e876f0baebca2e6ef344dc94a07feb0cbcf6298 100644 (file)
@@ -225,7 +225,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
        return 0; /* Task didn't use the fpu at all. */
 }
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long spu,
+int copy_thread(unsigned long clone_flags, unsigned long spu,
        unsigned long unused, struct task_struct *tsk, struct pt_regs *regs)
 {
        struct pt_regs *childregs = task_pt_regs(tsk);
index 6ea017727cced935c638a876dc193e7ef4e3288e..cada3ba4b9902f23bb13620e726a2625897e5d8a 100644 (file)
@@ -230,7 +230,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 static struct irqaction irq0 = {
        .handler = timer_interrupt,
        .flags = IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "MFT2",
 };
 
index b996a3c8cff54ae4a4857c1a5b955af6b6a391d4..3958726664bad268c0e185a462f6859bfe3e67f5 100644 (file)
 #define _M68K_IDE_H
 
 #ifdef __KERNEL__
-
-
 #include <asm/setup.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#ifdef CONFIG_ATARI
-#include <linux/interrupt.h>
-#include <asm/atari_stdma.h>
-#endif
-
-#ifdef CONFIG_MAC
-#include <asm/macints.h>
-#endif
-
 /*
  * Get rid of defs from io.h - ide has its private and conflicting versions
  * Since so far no single m68k platform uses ISA/PCI I/O space for IDE, we
  * always use the `raw' MMIO versions
  */
-#undef inb
-#undef inw
-#undef insw
-#undef inl
-#undef insl
-#undef outb
-#undef outw
-#undef outsw
-#undef outl
-#undef outsl
 #undef readb
 #undef readw
-#undef readl
 #undef writeb
 #undef writew
-#undef writel
 
-#define inb                            in_8
-#define inw                            in_be16
-#define insw(port, addr, n)            raw_insw((u16 *)port, addr, n)
-#define inl                            in_be32
-#define insl(port, addr, n)            raw_insl((u32 *)port, addr, n)
-#define outb(val, port)                        out_8(port, val)
-#define outw(val, port)                        out_be16(port, val)
-#define outsw(port, addr, n)           raw_outsw((u16 *)port, addr, n)
-#define outl(val, port)                        out_be32(port, val)
-#define outsl(port, addr, n)           raw_outsl((u32 *)port, addr, n)
 #define readb                          in_8
 #define readw                          in_be16
 #define __ide_mm_insw(port, addr, n)   raw_insw((u16 *)port, addr, n)
-#define readl                          in_be32
 #define __ide_mm_insl(port, addr, n)   raw_insl((u32 *)port, addr, n)
 #define writeb(val, port)              out_8(port, val)
 #define writew(val, port)              out_be16(port, val)
 #define __ide_mm_outsw(port, addr, n)  raw_outsw((u16 *)port, addr, n)
-#define writel(val, port)              out_be32(port, val)
 #define __ide_mm_outsl(port, addr, n)  raw_outsl((u32 *)port, addr, n)
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-#define insw_swapw(port, addr, n)      raw_insw_swapw((u16 *)port, addr, n)
-#define outsw_swapw(port, addr, n)     raw_outsw_swapw((u16 *)port, addr, n)
-#endif
-
-#ifdef CONFIG_BLK_DEV_FALCON_IDE
-#define IDE_ARCH_LOCK
-
-extern int falconide_intr_lock;
-
-static __inline__ void ide_release_lock (void)
-{
-       if (MACH_IS_ATARI) {
-               if (falconide_intr_lock == 0) {
-                       printk("ide_release_lock: bug\n");
-                       return;
-               }
-               falconide_intr_lock = 0;
-               stdma_release();
-       }
-}
-
-static __inline__ void
-ide_get_lock(irq_handler_t handler, void *data)
-{
-       if (MACH_IS_ATARI) {
-               if (falconide_intr_lock == 0) {
-                       if (in_interrupt() > 0)
-                               panic( "Falcon IDE hasn't ST-DMA lock in interrupt" );
-                       stdma_lock(handler, data);
-                       falconide_intr_lock = 1;
-               }
-       }
-}
-#endif /* CONFIG_BLK_DEV_FALCON_IDE */
-
-#define IDE_ARCH_ACK_INTR
-#define ide_ack_intr(hwif)     ((hwif)->ack_intr ? (hwif)->ack_intr(hwif) : 1)
 
 #endif /* __KERNEL__ */
 #endif /* _M68K_IDE_H */
index 632ce016014d27d6190d1776d86ecaa1503aeca6..ec37fb56c127a095ed8f5060c8af8ff6672f90d0 100644 (file)
@@ -233,7 +233,7 @@ asmlinkage int m68k_clone(struct pt_regs *regs)
                       parent_tidptr, child_tidptr);
 }
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(unsigned long clone_flags, unsigned long usp,
                 unsigned long unused,
                 struct task_struct * p, struct pt_regs * regs)
 {
index 3f2d7745f31e8321f629b80dd1eceacced2a52e2..1e96c6eb631258f75946f9ab84f4ab26f1ab3890 100644 (file)
@@ -199,7 +199,7 @@ asmlinkage int m68k_clone(struct pt_regs *regs)
         return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
 }
 
-int copy_thread(int nr, unsigned long clone_flags,
+int copy_thread(unsigned long clone_flags,
                unsigned long usp, unsigned long topstk,
                struct task_struct * p, struct pt_regs * regs)
 {
index 206cb7953b0cb21360cb331cae3069ac49e8ce38..dc787190430a44d18bb2ff69d0f7ca5ee1e4452a 100644 (file)
@@ -77,7 +77,6 @@ config MIPS_COBALT
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_LITTLE_ENDIAN
-       select GENERIC_HARDIRQS_NO__DO_IRQ
 
 config MACH_DECSTATION
        bool "DECstations"
@@ -132,7 +131,6 @@ config MACH_JAZZ
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
        select SYS_SUPPORTS_100HZ
-       select GENERIC_HARDIRQS_NO__DO_IRQ
        help
         This a family of machines based on the MIPS R4030 chipset which was
         used by several vendors to build RISC/os and Windows NT workstations.
@@ -154,7 +152,6 @@ config LASAT
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_64BIT_KERNEL if BROKEN
        select SYS_SUPPORTS_LITTLE_ENDIAN
-       select GENERIC_HARDIRQS_NO__DO_IRQ
 
 config LEMOTE_FULONG
        bool "Lemote Fulong mini-PC"
@@ -175,7 +172,6 @@ config LEMOTE_FULONG
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_SUPPORTS_HIGHMEM
        select SYS_HAS_EARLY_PRINTK
-       select GENERIC_HARDIRQS_NO__DO_IRQ
        select GENERIC_ISA_DMA_SUPPORT_BROKEN
        select CPU_HAS_WB
        help
@@ -250,7 +246,6 @@ config MACH_VR41XX
        select CEVT_R4K
        select CSRC_R4K
        select SYS_HAS_CPU_VR41XX
-       select GENERIC_HARDIRQS_NO__DO_IRQ
 
 config NXP_STB220
        bool "NXP STB220 board"
@@ -364,7 +359,6 @@ config SGI_IP27
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_NUMA
        select SYS_SUPPORTS_SMP
-       select GENERIC_HARDIRQS_NO__DO_IRQ
        help
          This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics
          workstations.  To compile a Linux kernel that runs on these, say Y
@@ -563,7 +557,6 @@ config MIKROTIK_RB532
        select CEVT_R4K
        select CSRC_R4K
        select DMA_NONCOHERENT
-       select GENERIC_HARDIRQS_NO__DO_IRQ
        select HW_HAS_PCI
        select IRQ_CPU
        select SYS_HAS_CPU_MIPS32_R1
@@ -700,8 +693,7 @@ config SCHED_OMIT_FRAME_POINTER
        default y
 
 config GENERIC_HARDIRQS_NO__DO_IRQ
-       bool
-       default n
+       def_bool y
 
 #
 # Select some configuration options automatically based on user selections.
@@ -920,7 +912,6 @@ config SOC_PNX833X
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_SUPPORTS_BIG_ENDIAN
-       select GENERIC_HARDIRQS_NO__DO_IRQ
        select GENERIC_GPIO
        select CPU_MIPSR2_IRQ_VI
 
@@ -939,7 +930,6 @@ config SOC_PNX8550
        select SYS_HAS_CPU_MIPS32_R1
        select SYS_HAS_EARLY_PRINTK
        select SYS_SUPPORTS_32BIT_KERNEL
-       select GENERIC_HARDIRQS_NO__DO_IRQ
        select GENERIC_GPIO
 
 config SWAP_IO_SPACE
index 22dab2e1434861045a86b9968fdaf273f2479197..8d544c7c9fe9435d11d831b8fcae6ee219f2aad3 100644 (file)
@@ -720,11 +720,17 @@ ifdef CONFIG_MIPS32_O32
        $(Q)$(MAKE) $(build)=. missing-syscalls EXTRA_CFLAGS="-mabi=32"
 endif
 
+install:
+       $(Q)install -D -m 755 vmlinux $(INSTALL_PATH)/vmlinux-$(KERNELRELEASE)
+       $(Q)install -D -m 644 .config $(INSTALL_PATH)/config-$(KERNELRELEASE)
+       $(Q)install -D -m 644 System.map $(INSTALL_PATH)/System.map-$(KERNELRELEASE)
+
 archclean:
        @$(MAKE) $(clean)=arch/mips/boot
        @$(MAKE) $(clean)=arch/mips/lasat
 
 define archhelp
+       echo '  install              - install kernel into $(INSTALL_PATH)'
        echo '  vmlinux.ecoff        - ECOFF boot image'
        echo '  vmlinux.bin          - Raw binary boot image'
        echo '  vmlinux.srec         - SREC boot image'
index 7f8ef13d0014e3dd022ef4a354fe23c5982c49d8..8128aebfb1559118f354a4f292a917aacf6e70ba 100644 (file)
@@ -134,4 +134,4 @@ config SOC_AU1X00
        select SYS_HAS_CPU_MIPS32_R1
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_APM_EMULATION
-       select GENERIC_HARDIRQS_NO__DO_IRQ
+       select ARCH_REQUIRE_GPIOLIB
index e660ddd611c465dc6665ecf7d1346f82a5e77b98..91a9c4436c392ad266237850bca5acf49bda761f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2007, OpenWrt.org, Florian Fainelli <florian@openwrt.org>
+ *  Copyright (C) 2007-2009, OpenWrt.org, Florian Fainelli <florian@openwrt.org>
  *     Architecture specific GPIO support
  *
  *  This program is free software; you can redistribute         it and/or modify it
  *     others have a second one : GPIO2
  */
 
+#include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
 
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/gpio.h>
 
-#define gpio1 sys
-#if !defined(CONFIG_SOC_AU1000)
-
-static struct au1x00_gpio2 *const gpio2 = (struct au1x00_gpio2 *) GPIO2_BASE;
-#define GPIO2_OUTPUT_ENABLE_MASK       0x00010000
+struct au1000_gpio_chip {
+       struct gpio_chip        chip;
+       void __iomem            *regbase;
+};
 
-static int au1xxx_gpio2_read(unsigned gpio)
+#if !defined(CONFIG_SOC_AU1000)
+static int au1000_gpio2_get(struct gpio_chip *chip, unsigned offset)
 {
-       gpio -= AU1XXX_GPIO_BASE;
-       return ((gpio2->pinstate >> gpio) & 0x01);
+       u32 mask = 1 << offset;
+       struct au1000_gpio_chip *gpch;
+
+       gpch = container_of(chip, struct au1000_gpio_chip, chip);
+       return readl(gpch->regbase + AU1000_GPIO2_ST) & mask;
 }
 
-static void au1xxx_gpio2_write(unsigned gpio, int value)
+static void au1000_gpio2_set(struct gpio_chip *chip,
+                               unsigned offset, int value)
 {
-       gpio -= AU1XXX_GPIO_BASE;
+       u32 mask = ((GPIO2_OUT_EN_MASK << offset) | (!!value << offset));
+       struct au1000_gpio_chip *gpch;
+       unsigned long flags;
+
+       gpch = container_of(chip, struct au1000_gpio_chip, chip);
 
-       gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << gpio) | ((!!value) << gpio);
+       local_irq_save(flags);
+       writel(mask, gpch->regbase + AU1000_GPIO2_OUT);
+       local_irq_restore(flags);
 }
 
-static int au1xxx_gpio2_direction_input(unsigned gpio)
+static int au1000_gpio2_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-       gpio -= AU1XXX_GPIO_BASE;
-       gpio2->dir &= ~(0x01 << gpio);
+       u32 mask = 1 << offset;
+       u32 tmp;
+       struct au1000_gpio_chip *gpch;
+       unsigned long flags;
+
+       gpch = container_of(chip, struct au1000_gpio_chip, chip);
+
+       local_irq_save(flags);
+       tmp = readl(gpch->regbase + AU1000_GPIO2_DIR);
+       tmp &= ~mask;
+       writel(tmp, gpch->regbase + AU1000_GPIO2_DIR);
+       local_irq_restore(flags);
+
        return 0;
 }
 
-static int au1xxx_gpio2_direction_output(unsigned gpio, int value)
+static int au1000_gpio2_direction_output(struct gpio_chip *chip,
+                                       unsigned offset, int value)
 {
-       gpio -= AU1XXX_GPIO_BASE;
-       gpio2->dir |= 0x01 << gpio;
-       gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << gpio) | ((!!value) << gpio);
+       u32 mask = 1 << offset;
+       u32 out_mask = ((GPIO2_OUT_EN_MASK << offset) | (!!value << offset));
+       u32 tmp;
+       struct au1000_gpio_chip *gpch;
+       unsigned long flags;
+
+       gpch = container_of(chip, struct au1000_gpio_chip, chip);
+
+       local_irq_save(flags);
+       tmp = readl(gpch->regbase + AU1000_GPIO2_DIR);
+       tmp |= mask;
+       writel(tmp, gpch->regbase + AU1000_GPIO2_DIR);
+       writel(out_mask, gpch->regbase + AU1000_GPIO2_OUT);
+       local_irq_restore(flags);
+
        return 0;
 }
-
 #endif /* !defined(CONFIG_SOC_AU1000) */
 
-static int au1xxx_gpio1_read(unsigned gpio)
+static int au1000_gpio1_get(struct gpio_chip *chip, unsigned offset)
 {
-       return (gpio1->pinstaterd >> gpio) & 0x01;
+       u32 mask = 1 << offset;
+       struct au1000_gpio_chip *gpch;
+
+       gpch = container_of(chip, struct au1000_gpio_chip, chip);
+       return readl(gpch->regbase + AU1000_GPIO1_ST) & mask;
 }
 
-static void au1xxx_gpio1_write(unsigned gpio, int value)
+static void au1000_gpio1_set(struct gpio_chip *chip,
+                               unsigned offset, int value)
 {
+       u32 mask = 1 << offset;
+       u32 reg_offset;
+       struct au1000_gpio_chip *gpch;
+       unsigned long flags;
+
+       gpch = container_of(chip, struct au1000_gpio_chip, chip);
+
        if (value)
-               gpio1->outputset = (0x01 << gpio);
+               reg_offset = AU1000_GPIO1_OUT;
        else
-               /* Output a zero */
-               gpio1->outputclr = (0x01 << gpio);
-}
+               reg_offset = AU1000_GPIO1_CLR;
 
-static int au1xxx_gpio1_direction_input(unsigned gpio)
-{
-       gpio1->pininputen = (0x01 << gpio);
-       return 0;
+       local_irq_save(flags);
+       writel(mask, gpch->regbase + reg_offset);
+       local_irq_restore(flags);
 }
 
-static int au1xxx_gpio1_direction_output(unsigned gpio, int value)
+static int au1000_gpio1_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-       gpio1->trioutclr = (0x01 & gpio);
-       au1xxx_gpio1_write(gpio, value);
+       u32 mask = 1 << offset;
+       struct au1000_gpio_chip *gpch;
+
+       gpch = container_of(chip, struct au1000_gpio_chip, chip);
+       writel(mask, gpch->regbase + AU1000_GPIO1_ST);
+
        return 0;
 }
 
-int au1xxx_gpio_get_value(unsigned gpio)
+static int au1000_gpio1_direction_output(struct gpio_chip *chip,
+                                       unsigned offset, int value)
 {
-       if (gpio >= AU1XXX_GPIO_BASE)
-#if defined(CONFIG_SOC_AU1000)
-               return 0;
-#else
-               return au1xxx_gpio2_read(gpio);
-#endif
-       else
-               return au1xxx_gpio1_read(gpio);
-}
-EXPORT_SYMBOL(au1xxx_gpio_get_value);
+       u32 mask = 1 << offset;
+       struct au1000_gpio_chip *gpch;
 
-void au1xxx_gpio_set_value(unsigned gpio, int value)
-{
-       if (gpio >= AU1XXX_GPIO_BASE)
-#if defined(CONFIG_SOC_AU1000)
-               ;
-#else
-               au1xxx_gpio2_write(gpio, value);
-#endif
-       else
-               au1xxx_gpio1_write(gpio, value);
-}
-EXPORT_SYMBOL(au1xxx_gpio_set_value);
+       gpch = container_of(chip, struct au1000_gpio_chip, chip);
 
-int au1xxx_gpio_direction_input(unsigned gpio)
-{
-       if (gpio >= AU1XXX_GPIO_BASE)
-#if defined(CONFIG_SOC_AU1000)
-               return -ENODEV;
-#else
-               return au1xxx_gpio2_direction_input(gpio);
-#endif
+       writel(mask, gpch->regbase + AU1000_GPIO1_TRI_OUT);
+       au1000_gpio1_set(chip, offset, value);
 
-       return au1xxx_gpio1_direction_input(gpio);
+       return 0;
 }
-EXPORT_SYMBOL(au1xxx_gpio_direction_input);
 
-int au1xxx_gpio_direction_output(unsigned gpio, int value)
+struct au1000_gpio_chip au1000_gpio_chip[] = {
+       [0] = {
+               .regbase                        = (void __iomem *)SYS_BASE,
+               .chip = {
+                       .label                  = "au1000-gpio1",
+                       .direction_input        = au1000_gpio1_direction_input,
+                       .direction_output       = au1000_gpio1_direction_output,
+                       .get                    = au1000_gpio1_get,
+                       .set                    = au1000_gpio1_set,
+                       .base                   = 0,
+                       .ngpio                  = 32,
+               },
+       },
+#if !defined(CONFIG_SOC_AU1000)
+       [1] = {
+               .regbase                        = (void __iomem *)GPIO2_BASE,
+               .chip = {
+                       .label                  = "au1000-gpio2",
+                       .direction_input        = au1000_gpio2_direction_input,
+                       .direction_output       = au1000_gpio2_direction_output,
+                       .get                    = au1000_gpio2_get,
+                       .set                    = au1000_gpio2_set,
+                       .base                   = AU1XXX_GPIO_BASE,
+                       .ngpio                  = 32,
+               },
+       },
+#endif
+};
+
+static int __init au1000_gpio_init(void)
 {
-       if (gpio >= AU1XXX_GPIO_BASE)
-#if defined(CONFIG_SOC_AU1000)
-               return -ENODEV;
-#else
-               return au1xxx_gpio2_direction_output(gpio, value);
+       gpiochip_add(&au1000_gpio_chip[0].chip);
+#if !defined(CONFIG_SOC_AU1000)
+       gpiochip_add(&au1000_gpio_chip[1].chip);
 #endif
 
-       return au1xxx_gpio1_direction_output(gpio, value);
+       return 0;
 }
-EXPORT_SYMBOL(au1xxx_gpio_direction_output);
+arch_initcall(au1000_gpio_init);
+
index 95303297c5343d9da6714f364731f4ce70f13423..0d68e1985ffd15d2ca62b67280600fd4c088b150 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/leds.h>
 #include <linux/platform_device.h>
+#include <linux/smc91x.h>
 
 #include <asm/mach-au1x00/au1xxx.h>
 #include <asm/mach-au1x00/au1100_mmc.h>
@@ -131,6 +132,12 @@ static struct platform_device ide_device = {
        .resource       = ide_resources
 };
 
+static struct smc91x_platdata smc_data = {
+       .flags  = SMC91X_NOWAIT | SMC91X_USE_16BIT,
+       .leda   = RPC_LED_100_10,
+       .ledb   = RPC_LED_TX_RX,
+};
+
 static struct resource smc91c111_resources[] = {
        [0] = {
                .name   = "smc91x-regs",
@@ -146,6 +153,9 @@ static struct resource smc91c111_resources[] = {
 };
 
 static struct platform_device smc91c111_device = {
+       .dev    = {
+               .platform_data  = &smc_data,
+       },
        .name           = "smc91x",
        .id             = -1,
        .num_resources  = ARRAY_SIZE(smc91c111_resources),
index 1c2a7faf588102a4675351ea29709d60640324dd..d6903c3f3d513c0cd0990138aaada2445d27562b 100644 (file)
@@ -14,3 +14,5 @@ obj-y += dma-octeon.o flash_setup.o
 obj-y += octeon-memcpy.o
 
 obj-$(CONFIG_SMP)                     += smp.o
+
+EXTRA_CFLAGS += -Werror
index 553d36cbcc42b7ec6e24778d111f08d7a035ead6..008f657116eb4a61822a711fe8f0c845b157a500 100644 (file)
@@ -57,7 +57,7 @@ static int __init flash_init(void)
                flash_map.bankwidth = 1;
                flash_map.virt = ioremap(flash_map.phys, flash_map.size);
                pr_notice("Bootbus flash: Setting flash for %luMB flash at "
-                         "0x%08lx\n", flash_map.size >> 20, flash_map.phys);
+                         "0x%08llx\n", flash_map.size >> 20, flash_map.phys);
                simple_map_init(&flash_map);
                mymtd = do_map_probe("cfi_probe", &flash_map);
                if (mymtd) {
index fc72984a5dae56c73675997c490322d82d88f6c3..1c19af8daa62a3f992f20ecb1a281a527bfec3cd 100644 (file)
@@ -31,7 +31,7 @@ static void octeon_irq_core_ack(unsigned int irq)
 
 static void octeon_irq_core_eoi(unsigned int irq)
 {
-       irq_desc_t *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_desc + irq;
        unsigned int bit = irq - OCTEON_IRQ_SW0;
        /*
         * If an IRQ is being processed while we are disabling it the
index ac4fb912649d4e2397083864e06e62169f77a1d6..cb9bf820fe53b4640a7b72264be61deacf998fa7 100644 (file)
@@ -47,7 +47,6 @@ asmlinkage void plat_irq_dispatch(void)
 
 static struct irqaction cascade = {
        .handler        = no_action,
-       .mask           = CPU_MASK_NONE,
        .name           = "cascade",
 };
 
index c2583ecc93cf876a530d9daeef066a1dadd35c53..43828ae796ec9d0d3276b50ffe5b8f0c29ea1b2f 100644 (file)
@@ -80,9 +80,9 @@ void emma2rh_irq_init(void)
        u32 i;
 
        for (i = 0; i < NUM_EMMA2RH_IRQ; i++)
-               set_irq_chip_and_handler(EMMA2RH_IRQ_BASE + i,
-                                        &emma2rh_irq_controller,
-                                        handle_level_irq);
+               set_irq_chip_and_handler_name(EMMA2RH_IRQ_BASE + i,
+                                             &emma2rh_irq_controller,
+                                             handle_level_irq, "level");
 }
 
 static void emma2rh_sw_irq_enable(unsigned int irq)
@@ -120,9 +120,9 @@ void emma2rh_sw_irq_init(void)
        u32 i;
 
        for (i = 0; i < NUM_EMMA2RH_IRQ_SW; i++)
-               set_irq_chip_and_handler(EMMA2RH_SW_IRQ_BASE + i,
-                                        &emma2rh_sw_irq_controller,
-                                        handle_level_irq);
+               set_irq_chip_and_handler_name(EMMA2RH_SW_IRQ_BASE + i,
+                                             &emma2rh_sw_irq_controller,
+                                             handle_level_irq, "level");
 }
 
 static void emma2rh_gpio_irq_enable(unsigned int irq)
@@ -149,37 +149,28 @@ static void emma2rh_gpio_irq_disable(unsigned int irq)
 
 static void emma2rh_gpio_irq_ack(unsigned int irq)
 {
-       u32 reg;
-
        irq -= EMMA2RH_GPIO_IRQ_BASE;
        emma2rh_out32(EMMA2RH_GPIO_INT_ST, ~(1 << irq));
-
-       reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK);
-       reg &= ~(1 << irq);
-       emma2rh_out32(EMMA2RH_GPIO_INT_MASK, reg);
 }
 
-static void emma2rh_gpio_irq_end(unsigned int irq)
+static void emma2rh_gpio_irq_mask_ack(unsigned int irq)
 {
        u32 reg;
 
-       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
-
-               irq -= EMMA2RH_GPIO_IRQ_BASE;
+       irq -= EMMA2RH_GPIO_IRQ_BASE;
+       emma2rh_out32(EMMA2RH_GPIO_INT_ST, ~(1 << irq));
 
-               reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK);
-               reg |= 1 << irq;
-               emma2rh_out32(EMMA2RH_GPIO_INT_MASK, reg);
-       }
+       reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK);
+       reg &= ~(1 << irq);
+       emma2rh_out32(EMMA2RH_GPIO_INT_MASK, reg);
 }
 
 struct irq_chip emma2rh_gpio_irq_controller = {
        .name = "emma2rh_gpio_irq",
        .ack = emma2rh_gpio_irq_ack,
        .mask = emma2rh_gpio_irq_disable,
-       .mask_ack = emma2rh_gpio_irq_ack,
+       .mask_ack = emma2rh_gpio_irq_mask_ack,
        .unmask = emma2rh_gpio_irq_enable,
-       .end = emma2rh_gpio_irq_end,
 };
 
 void emma2rh_gpio_irq_init(void)
@@ -187,14 +178,14 @@ void emma2rh_gpio_irq_init(void)
        u32 i;
 
        for (i = 0; i < NUM_EMMA2RH_IRQ_GPIO; i++)
-               set_irq_chip(EMMA2RH_GPIO_IRQ_BASE + i,
-                            &emma2rh_gpio_irq_controller);
+               set_irq_chip_and_handler_name(EMMA2RH_GPIO_IRQ_BASE + i,
+                                             &emma2rh_gpio_irq_controller,
+                                             handle_edge_irq, "edge");
 }
 
 static struct irqaction irq_cascade = {
           .handler = no_action,
           .flags = 0,
-          .mask = CPU_MASK_NONE,
           .name = "cascade",
           .dev_id = NULL,
           .next = NULL,
@@ -213,8 +204,7 @@ void emma2rh_irq_dispatch(void)
                    emma2rh_in32(EMMA2RH_BHIF_INT_EN_0);
 
 #ifdef EMMA2RH_SW_CASCADE
-       if (intStatus &
-           (1 << ((EMMA2RH_SW_CASCADE - EMMA2RH_IRQ_INT0) & (32 - 1)))) {
+       if (intStatus & (1UL << EMMA2RH_SW_CASCADE)) {
                u32 swIntStatus;
                swIntStatus = emma2rh_in32(EMMA2RH_BHIF_SW_INT)
                    & emma2rh_in32(EMMA2RH_BHIF_SW_INT_EN);
@@ -225,6 +215,8 @@ void emma2rh_irq_dispatch(void)
                        }
                }
        }
+       /* Skip S/W interrupt */
+       intStatus &= ~(1UL << EMMA2RH_SW_CASCADE);
 #endif
 
        for (i = 0, bitmask = 1; i < 32; i++, bitmask <<= 1) {
@@ -238,8 +230,7 @@ void emma2rh_irq_dispatch(void)
                    emma2rh_in32(EMMA2RH_BHIF_INT_EN_1);
 
 #ifdef EMMA2RH_GPIO_CASCADE
-       if (intStatus &
-           (1 << ((EMMA2RH_GPIO_CASCADE - EMMA2RH_IRQ_INT0) & (32 - 1)))) {
+       if (intStatus & (1UL << (EMMA2RH_GPIO_CASCADE % 32))) {
                u32 gpioIntStatus;
                gpioIntStatus = emma2rh_in32(EMMA2RH_GPIO_INT_ST)
                    & emma2rh_in32(EMMA2RH_GPIO_INT_MASK);
@@ -250,6 +241,8 @@ void emma2rh_irq_dispatch(void)
                        }
                }
        }
+       /* Skip GPIO interrupt */
+       intStatus &= ~(1UL << (EMMA2RH_GPIO_CASCADE % 32));
 #endif
 
        for (i = 32, bitmask = 1; i < 64; i++, bitmask <<= 1) {
index d5f47e4f0d1831cdea4adf0bbdb3dad7c084f0eb..80ae12ef87db8d31d4b2a2df247a4ca4507801ba 100644 (file)
@@ -110,6 +110,7 @@ struct platform_device i2c_emma_devices[] = {
 static struct  plat_serial8250_port platform_serial_ports[] = {
        [0] = {
                .membase= (void __iomem*)KSEG1ADDR(EMMA2RH_PFUR0_BASE + 3),
+               .mapbase = EMMA2RH_PFUR0_BASE + 3,
                .irq = EMMA2RH_IRQ_PFUR0,
                .uartclk = EMMA2RH_SERIAL_CLOCK,
                .regshift = 4,
@@ -117,6 +118,7 @@ static struct  plat_serial8250_port platform_serial_ports[] = {
                .flags = EMMA2RH_SERIAL_FLAGS,
        }, [1] = {
                .membase = (void __iomem*)KSEG1ADDR(EMMA2RH_PFUR1_BASE + 3),
+               .mapbase = EMMA2RH_PFUR1_BASE + 3,
                .irq = EMMA2RH_IRQ_PFUR1,
                .uartclk = EMMA2RH_SERIAL_CLOCK,
                .regshift = 4,
@@ -124,6 +126,7 @@ static struct  plat_serial8250_port platform_serial_ports[] = {
                .flags = EMMA2RH_SERIAL_FLAGS,
        }, [2] = {
                .membase = (void __iomem*)KSEG1ADDR(EMMA2RH_PFUR2_BASE + 3),
+               .mapbase = EMMA2RH_PFUR2_BASE + 3,
                .irq = EMMA2RH_IRQ_PFUR2,
                .uartclk = EMMA2RH_SERIAL_CLOCK,
                .regshift = 4,
index c018727c7ddc251b58b6d1d2da27d2b81f6a1866..3bdc0e3d89ccd2f8edb707c0c1c5dc1702438620 100644 (file)
@@ -209,8 +209,7 @@ enum cpu_type_enum {
         * MIPS32 class processors
         */
        CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K,
-       CPU_AU1000, CPU_AU1100, CPU_AU1200, CPU_AU1210, CPU_AU1250, CPU_AU1500,
-       CPU_AU1550, CPU_PR4450, CPU_BCM3302, CPU_BCM4710,
+       CPU_ALCHEMY, CPU_PR4450, CPU_BCM3302, CPU_BCM4710,
 
        /*
         * MIPS64 class processors
index 134e1fc8f4d6d7a5eb5ae3b2d361284b23ab5e95..a12d971db4f9c8662dcd456969f38d4a1bc48402 100644 (file)
@@ -87,7 +87,7 @@ do {                                                                  \
        : "=r" (tmp));                                                  \
 } while (0)
 
-#elif defined(CONFIG_CPU_MIPSR1)
+#elif defined(CONFIG_CPU_MIPSR1) && !defined(CONFIG_MACH_ALCHEMY)
 
 /*
  * These are slightly complicated by the fact that we guarantee R1 kernels to
@@ -139,7 +139,7 @@ do {                                                                        \
 } while (0)
 
 #elif defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_CAVIUM_OCTEON) || \
-      defined(CONFIG_CPU_R5500)
+      defined(CONFIG_CPU_R5500) || defined(CONFIG_MACH_ALCHEMY)
 
 /*
  * R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer.
diff --git a/arch/mips/include/asm/mach-au1x00/cpu-feature-overrides.h b/arch/mips/include/asm/mach-au1x00/cpu-feature-overrides.h
new file mode 100644 (file)
index 0000000..d5df0ca
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef __ASM_MACH_AU1X00_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_AU1X00_CPU_FEATURE_OVERRIDES_H
+
+#define cpu_has_tlb                    1
+#define cpu_has_4kex                   1
+#define cpu_has_3k_cache               0
+#define cpu_has_4k_cache               1
+#define cpu_has_tx39_cache             0
+#define cpu_has_fpu                    0
+#define cpu_has_counter                        1
+#define cpu_has_watch                  1
+#define cpu_has_divec                  1
+#define cpu_has_vce                    0
+#define cpu_has_cache_cdex_p           0
+#define cpu_has_cache_cdex_s           0
+#define cpu_has_mcheck                 1
+#define cpu_has_ejtag                  1
+#define cpu_has_llsc                   1
+#define cpu_has_mips16                 0
+#define cpu_has_mdmx                   0
+#define cpu_has_mips3d                 0
+#define cpu_has_smartmips              0
+#define cpu_has_vtag_icache            0
+#define cpu_has_dc_aliases             0
+#define cpu_has_ic_fills_f_dc          1
+#define cpu_has_mips32r1               1
+#define cpu_has_mips32r2               0
+#define cpu_has_mips64r1               0
+#define cpu_has_mips64r2               0
+#define cpu_has_dsp                    0
+#define cpu_has_mipsmt                 0
+#define cpu_has_userlocal              0
+#define cpu_has_nofpuex                        0
+#define cpu_has_64bits                 0
+#define cpu_has_64bit_zero_reg         0
+#define cpu_has_vint                   0
+#define cpu_has_veic                   0
+#define cpu_has_inclusive_pcaches      0
+
+#define cpu_dcache_line_size()         32
+#define cpu_icache_line_size()         32
+
+#endif /* __ASM_MACH_AU1X00_CPU_FEATURE_OVERRIDES_H */
index 2dc61e009a08e4d416b966322044d227222ff701..34d9b72790249b604efc7657c76c12adf0d60e6e 100644 (file)
@@ -5,65 +5,29 @@
 
 #define AU1XXX_GPIO_BASE       200
 
-struct au1x00_gpio2 {
-       u32     dir;
-       u32     reserved;
-       u32     output;
-       u32     pinstate;
-       u32     inten;
-       u32     enable;
-};
+/* GPIO bank 1 offsets */
+#define AU1000_GPIO1_TRI_OUT   0x0100
+#define AU1000_GPIO1_OUT       0x0108
+#define AU1000_GPIO1_ST                0x0110
+#define AU1000_GPIO1_CLR       0x010C
 
-extern int au1xxx_gpio_get_value(unsigned gpio);
-extern void au1xxx_gpio_set_value(unsigned gpio, int value);
-extern int au1xxx_gpio_direction_input(unsigned gpio);
-extern int au1xxx_gpio_direction_output(unsigned gpio, int value);
+/* GPIO bank 2 offsets */
+#define AU1000_GPIO2_DIR       0x00
+#define AU1000_GPIO2_RSVD      0x04
+#define AU1000_GPIO2_OUT       0x08
+#define AU1000_GPIO2_ST                0x0C
+#define AU1000_GPIO2_INT       0x10
+#define AU1000_GPIO2_EN                0x14
 
+#define GPIO2_OUT_EN_MASK      0x00010000
 
-/* Wrappers for the arch-neutral GPIO API */
+#define gpio_to_irq(gpio)      NULL
 
-static inline int gpio_request(unsigned gpio, const char *label)
-{
-       /* Not yet implemented */
-       return 0;
-}
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
 
-static inline void gpio_free(unsigned gpio)
-{
-       /* Not yet implemented */
-}
+#define gpio_cansleep __gpio_cansleep
 
-static inline int gpio_direction_input(unsigned gpio)
-{
-       return au1xxx_gpio_direction_input(gpio);
-}
-
-static inline int gpio_direction_output(unsigned gpio, int value)
-{
-       return au1xxx_gpio_direction_output(gpio, value);
-}
-
-static inline int gpio_get_value(unsigned gpio)
-{
-       return au1xxx_gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned gpio, int value)
-{
-       au1xxx_gpio_set_value(gpio, value);
-}
-
-static inline int gpio_to_irq(unsigned gpio)
-{
-       return gpio;
-}
-
-static inline int irq_to_gpio(unsigned irq)
-{
-       return irq;
-}
-
-/* For cansleep */
 #include <asm-generic/gpio.h>
 
 #endif /* _AU1XXX_GPIO_H_ */
index d8ff4cd89ab50731d68f360f04bf5b08d9b779be..1784fde2e28fc3ae4f69d338863c907148c56ba1 100644 (file)
@@ -31,24 +31,28 @@ static inline void gpio_set_value(unsigned gpio, int value)
 
 static inline int gpio_direction_input(unsigned gpio)
 {
-       return ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 0);
+       ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 0);
+       return 0;
 }
 
 static inline int gpio_direction_output(unsigned gpio, int value)
 {
-       return ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio);
+       ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio);
+       return 0;
 }
 
-static int gpio_intmask(unsigned gpio, int value)
+static inline int gpio_intmask(unsigned gpio, int value)
 {
-       return ssb_gpio_intmask(&ssb_bcm47xx, 1 << gpio,
-                               value ? 1 << gpio : 0);
+       ssb_gpio_intmask(&ssb_bcm47xx, 1 << gpio,
+                        value ? 1 << gpio : 0);
+       return 0;
 }
 
-static int gpio_polarity(unsigned gpio, int value)
+static inline int gpio_polarity(unsigned gpio, int value)
 {
-       return ssb_gpio_polarity(&ssb_bcm47xx, 1 << gpio,
-                                value ? 1 << gpio : 0);
+       ssb_gpio_polarity(&ssb_bcm47xx, 1 << gpio,
+                         value ? 1 << gpio : 0);
+       return 0;
 }
 
 
index 55d481569a1f494e1c33a71fe22bbfb8b88f9af4..07547231e078dd3ecd35a988b3cd73bfc30c3683 100644 (file)
@@ -26,7 +26,6 @@ extern struct cpuinfo_ip27 sn_cpu_info[NR_CPUS];
 #define parent_node(node)      (node)
 #define node_to_cpumask(node)  (hub_data(node)->h_cpus)
 #define cpumask_of_node(node)  (&hub_data(node)->h_cpus)
-#define node_to_first_cpu(node)        (cpumask_first(cpumask_of_node(node)))
 struct pci_bus;
 extern int pcibus_to_node(struct pci_bus *);
 
index 7f0b034dd9a5fa19d766a3300b4ff3e1dd4ab70f..c0da1a881e3da030170fa010189d35ca33e9324e 100644 (file)
@@ -71,8 +71,6 @@
 
 #define MIPS_REVISION_CORID (((*(volatile u32 *)ioremap(MIPS_REVISION_REG, 4)) >> 10) & 0x3f)
 
-extern int mips_revision_corid;
-
 #define MIPS_REVISION_SCON_OTHER          0
 #define MIPS_REVISION_SCON_SOCITSC        1
 #define MIPS_REVISION_SCON_SOCITSCP       2
index 43c207e72a637042902b43aa871131923ca52fc2..64ffc0290b84dcf98fb003ba0ba7e77f6faed454 100644 (file)
@@ -15,6 +15,8 @@
 
 #include <linux/cpumask.h>
 
+struct task_struct;
+
 struct plat_smp_ops {
        void (*send_ipi_single)(int cpu, unsigned int action);
        void (*send_ipi_mask)(cpumask_t mask, unsigned int action);
index 0884947ebe270c404bb293b2acac0b067e7fd9d7..5b60a09a0f0894e8c8b1301683064b841a5b8e4b 100644 (file)
@@ -76,7 +76,7 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
                "2:                                                     \n"
                "       .subsection 2                                   \n"
                "4:     andi    %[ticket], %[ticket], 0x1fff            \n"
-               "5:     sll     %[ticket], 5                            \n"
+               "       sll     %[ticket], 5                            \n"
                "                                                       \n"
                "6:     bnez    %[ticket], 6b                           \n"
                "        subu   %[ticket], 1                            \n"
@@ -85,7 +85,7 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
                "       andi    %[ticket], %[ticket], 0x1fff            \n"
                "       beq     %[ticket], %[my_ticket], 2b             \n"
                "        subu   %[ticket], %[my_ticket], %[ticket]      \n"
-               "       b       5b                                      \n"
+               "       b       4b                                      \n"
                "        subu   %[ticket], %[ticket], 1                 \n"
                "       .previous                                       \n"
                "       .set pop                                        \n"
@@ -113,7 +113,7 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
                "        ll     %[ticket], %[ticket_ptr]                \n"
                "                                                       \n"
                "4:     andi    %[ticket], %[ticket], 0x1fff            \n"
-               "5:     sll     %[ticket], 5                            \n"
+               "       sll     %[ticket], 5                            \n"
                "                                                       \n"
                "6:     bnez    %[ticket], 6b                           \n"
                "        subu   %[ticket], 1                            \n"
@@ -122,7 +122,7 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
                "       andi    %[ticket], %[ticket], 0x1fff            \n"
                "       beq     %[ticket], %[my_ticket], 2b             \n"
                "        subu   %[ticket], %[my_ticket], %[ticket]      \n"
-               "       b       5b                                      \n"
+               "       b       4b                                      \n"
                "        subu   %[ticket], %[ticket], 1                 \n"
                "       .previous                                       \n"
                "       .set pop                                        \n"
@@ -480,6 +480,8 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
        return ret;
 }
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
 
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
index bcbb8d675af5ffdd51bd1a8ddb2b45985c5a6e49..7956e69a3bd5cfe6a8b50466f7460996599f9ce5 100644 (file)
@@ -4,12 +4,18 @@
  * for more details.
  *
  * Copyright (C) 1994, 1995, 1996, 1999 by Ralf Baechle
+ * Copyright (C) 2008 Wind River Systems,
+ *   written by Ralf Baechle
  * Copyright (C) 1999 Silicon Graphics, Inc.
  */
 #ifndef _ASM_TYPES_H
 #define _ASM_TYPES_H
 
-#if _MIPS_SZLONG == 64
+/*
+ * We don't use int-l64.h for the kernel anymore but still use it for
+ * userspace to avoid code changes.
+ */
+#if (_MIPS_SZLONG == 64) && !defined(__KERNEL__)
 # include <asm-generic/int-l64.h>
 #else
 # include <asm-generic/int-ll64.h>
index a73e1531e151fc7b0645038bea939aba58e5ce09..40005010827cb4f72c1734778a520a74c7958153 100644 (file)
 #define __NR_dup3                      (__NR_Linux + 327)
 #define __NR_pipe2                     (__NR_Linux + 328)
 #define __NR_inotify_init1             (__NR_Linux + 329)
+#define __NR_preadv                    (__NR_Linux + 330)
+#define __NR_pwritev                   (__NR_Linux + 331)
 
 /*
  * Offset of the last Linux o32 flavoured syscall
  */
-#define __NR_Linux_syscalls            329
+#define __NR_Linux_syscalls            331
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 
 #define __NR_O32_Linux                 4000
-#define __NR_O32_Linux_syscalls                329
+#define __NR_O32_Linux_syscalls                331
 
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 
 #define __NR_dup3                      (__NR_Linux + 286)
 #define __NR_pipe2                     (__NR_Linux + 287)
 #define __NR_inotify_init1             (__NR_Linux + 288)
+#define __NR_preadv                    (__NR_Linux + 289)
+#define __NR_pwritev                   (__NR_Linux + 290)
 
 /*
  * Offset of the last Linux 64-bit flavoured syscall
  */
-#define __NR_Linux_syscalls            288
+#define __NR_Linux_syscalls            290
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
 
 #define __NR_64_Linux                  5000
-#define __NR_64_Linux_syscalls         288
+#define __NR_64_Linux_syscalls         290
 
 #if _MIPS_SIM == _MIPS_SIM_NABI32
 
 #define __NR_dup3                      (__NR_Linux + 290)
 #define __NR_pipe2                     (__NR_Linux + 291)
 #define __NR_inotify_init1             (__NR_Linux + 292)
+#define __NR_preadv                    (__NR_Linux + 293)
+#define __NR_pwritev                   (__NR_Linux + 294)
 
 /*
  * Offset of the last N32 flavoured syscall
  */
-#define __NR_Linux_syscalls            292
+#define __NR_Linux_syscalls            294
 
 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
 
 #define __NR_N32_Linux                 6000
-#define __NR_N32_Linux_syscalls                292
+#define __NR_N32_Linux_syscalls                294
 
 #ifdef __KERNEL__
 
index 03965cb1b2527e23fd60a003284f51279b42a758..d9b6a5b5399d25b3959921288e84b08074571965 100644 (file)
@@ -134,7 +134,6 @@ static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id)
 static struct irqaction r4030_timer_irqaction = {
        .handler        = r4030_timer_interrupt,
        .flags          = IRQF_DISABLED,
-       .mask           = CPU_MASK_CPU0,
        .name           = "R4030 timer",
 };
 
index c672c08d49e597a1597fef23716d2a4b688c675f..f0fd636723be1d2663e16ada6af9aeab32a225cb 100644 (file)
@@ -68,8 +68,7 @@ static int __init vdma_init(void)
         */
        pgtbl = (VDMA_PGTBL_ENTRY *)__get_free_pages(GFP_KERNEL | GFP_DMA,
                                                    get_order(VDMA_PGTBL_SIZE));
-       if (!pgtbl)
-               BUG();
+       BUG_ON(!pgtbl);
        dma_cache_wback_inv((unsigned long)pgtbl, VDMA_PGTBL_SIZE);
        pgtbl = (VDMA_PGTBL_ENTRY *)KSEG1ADDR(pgtbl);
 
index b820661678b0b948e7fb56e8332a28277df07a98..a5182a20769619dda6bc81a216f89e2059769052 100644 (file)
@@ -144,7 +144,6 @@ void __cpuinit sb1480_clockevent_init(void)
 
        action->handler = sibyte_counter_handler;
        action->flags   = IRQF_DISABLED | IRQF_PERCPU;
-       action->mask    = cpumask_of_cpu(cpu);
        action->name    = name;
        action->dev_id  = cd;
 
index a2eebaafda52c224ee385193bcb998984d9d790d..340f53e5c6b19cd686f2a45bd69dc3f139d581d1 100644 (file)
@@ -143,7 +143,6 @@ void __cpuinit sb1250_clockevent_init(void)
 
        action->handler = sibyte_counter_handler;
        action->flags   = IRQF_DISABLED | IRQF_PERCPU;
-       action->mask    = cpumask_of_cpu(cpu);
        action->name    = name;
        action->dev_id  = cd;
 
index 1bdbcad3bb7414d2a394150e02bfcbbb0eb9db27..b13b8eb3059631c732479aa4da8ed35c4cb48c5c 100644 (file)
@@ -183,13 +183,7 @@ void __init check_wait(void)
        case CPU_TX49XX:
                cpu_wait = r4k_wait_irqoff;
                break;
-       case CPU_AU1000:
-       case CPU_AU1100:
-       case CPU_AU1500:
-       case CPU_AU1550:
-       case CPU_AU1200:
-       case CPU_AU1210:
-       case CPU_AU1250:
+       case CPU_ALCHEMY:
                cpu_wait = au1k_wait;
                break;
        case CPU_20KC:
@@ -783,37 +777,30 @@ static inline void cpu_probe_alchemy(struct cpuinfo_mips *c, unsigned int cpu)
        switch (c->processor_id & 0xff00) {
        case PRID_IMP_AU1_REV1:
        case PRID_IMP_AU1_REV2:
+               c->cputype = CPU_ALCHEMY;
                switch ((c->processor_id >> 24) & 0xff) {
                case 0:
-                       c->cputype = CPU_AU1000;
                        __cpu_name[cpu] = "Au1000";
                        break;
                case 1:
-                       c->cputype = CPU_AU1500;
                        __cpu_name[cpu] = "Au1500";
                        break;
                case 2:
-                       c->cputype = CPU_AU1100;
                        __cpu_name[cpu] = "Au1100";
                        break;
                case 3:
-                       c->cputype = CPU_AU1550;
                        __cpu_name[cpu] = "Au1550";
                        break;
                case 4:
-                       c->cputype = CPU_AU1200;
                        __cpu_name[cpu] = "Au1200";
-                       if ((c->processor_id & 0xff) == 2) {
-                               c->cputype = CPU_AU1250;
+                       if ((c->processor_id & 0xff) == 2)
                                __cpu_name[cpu] = "Au1250";
-                       }
                        break;
                case 5:
-                       c->cputype = CPU_AU1210;
                        __cpu_name[cpu] = "Au1210";
                        break;
                default:
-                       panic("Unknown Au Core!");
+                       __cpu_name[cpu] = "Au1xxx";
                        break;
                }
                break;
index f4d187825f96406612d16a6016ab8defcf997658..689719e34f085db04c1c09f8d18b89f1b9da91cd 100644 (file)
@@ -98,7 +98,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 static struct irqaction irq0  = {
        .handler = timer_interrupt,
        .flags = IRQF_DISABLED | IRQF_NOBALANCING,
-       .mask = CPU_MASK_NONE,
        .name = "timer"
 };
 
@@ -121,7 +120,6 @@ void __init setup_pit_timer(void)
        cd->min_delta_ns = clockevent_delta2ns(0xF, cd);
        clockevents_register_device(cd);
 
-       irq0.mask = cpumask_of_cpu(cpu);
        setup_irq(0, &irq0);
 }
 
index 413bd1d37f5499171e4337b78ee62f387152d811..01c0885a8061569dffe59d31e7ec7aee97588773 100644 (file)
@@ -306,7 +306,6 @@ static void init_8259A(int auto_eoi)
  */
 static struct irqaction irq2 = {
        .handler = no_action,
-       .mask = CPU_MASK_NONE,
        .name = "cascade",
 };
 
index 963c16d266aba30da2d14d95813979b7170f3f75..6a8cd28133d5cf02727102199232a8f7e71134ae 100644 (file)
@@ -140,14 +140,16 @@ void __init init_msc_irqs(unsigned long icubase, unsigned int irqbase, msc_irqma
 
                switch (imp->im_type) {
                case MSC01_IRQ_EDGE:
-                       set_irq_chip(irqbase+n, &msc_edgeirq_type);
+                       set_irq_chip_and_handler_name(irqbase + n,
+                               &msc_edgeirq_type, handle_edge_irq, "edge");
                        if (cpu_has_veic)
                                MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT);
                        else
                                MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl);
                        break;
                case MSC01_IRQ_LEVEL:
-                       set_irq_chip(irqbase+n, &msc_levelirq_type);
+                       set_irq_chip_and_handler_name(irqbase+n,
+                               &msc_levelirq_type, handle_level_irq, "level");
                        if (cpu_has_veic)
                                MSCIC_WRITE(MSC01_IC_SUP+n*8, 0);
                        else
index 0ee2567b780d4c4d6496eab4ff043a19bc1f3397..55c8a3ca507b2800fab0406d81d0844c660a7c04 100644 (file)
@@ -112,7 +112,8 @@ void __init mips_cpu_irq_init(void)
         */
        if (cpu_has_mipsmt)
                for (i = irq_base; i < irq_base + 2; i++)
-                       set_irq_chip(i, &mips_mt_cpu_irq_controller);
+                       set_irq_chip_and_handler(i, &mips_mt_cpu_irq_controller,
+                                                handle_percpu_irq);
 
        for (i = irq_base + 2; i < irq_base + 8; i++)
                set_irq_chip_and_handler(i, &mips_cpu_irq_controller,
index 2a472713de8e535353ec32718b181a8405b487a6..6242bc68add720f86d66698fe544af7f08a23c1b 100644 (file)
@@ -133,9 +133,9 @@ SYSCALL_DEFINE4(32_ftruncate64, unsigned long, fd, unsigned long, __dummy,
        return sys_ftruncate(fd, merge_64(a2, a3));
 }
 
-SYSCALL_DEFINE5(32_llseek, unsigned long, fd, unsigned long, offset_high,
-       unsigned long, offset_low, loff_t __user *, result,
-       unsigned long, origin)
+SYSCALL_DEFINE5(32_llseek, unsigned int, fd, unsigned int, offset_high,
+               unsigned int, offset_low, loff_t __user *, result,
+               unsigned int, origin)
 {
        return sys_llseek(fd, offset_high, offset_low, result, origin);
 }
index ca2e4026ad20b3c00365d0dc3b85904bbd2e273a..1eaaa450e20c3a83be8daf6cafe0e2935e45e5a1 100644 (file)
@@ -99,7 +99,7 @@ void flush_thread(void)
 {
 }
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(unsigned long clone_flags, unsigned long usp,
        unsigned long unused, struct task_struct *p, struct pt_regs *regs)
 {
        struct thread_info *ti = task_thread_info(p);
index 9ab70c3b5be6bac233e00568ac3ce9dd51f410e8..0b31b9bda0486988128d39d07d52ac2c0d0ad8d8 100644 (file)
@@ -650,6 +650,8 @@ einval:     li      v0, -ENOSYS
        sys     sys_dup3                3
        sys     sys_pipe2               2
        sys     sys_inotify_init1       1
+       sys     sys_preadv              6       /* 4330 */
+       sys     sys_pwritev             6
        .endm
 
        /* We pre-compute the number of _instruction_ bytes needed to
index 9b46986671545dea233ce1f96aca4f59e7eb912a..c647fd6e722f7acb2872ad0f01491b6f2a2637e9 100644 (file)
@@ -487,4 +487,6 @@ sys_call_table:
        PTR     sys_dup3
        PTR     sys_pipe2
        PTR     sys_inotify_init1
+       PTR     sys_preadv
+       PTR     sys_pwritev                     /* 5390 */
        .size   sys_call_table,.-sys_call_table
index f61d6b0e5731dadfcac24715babed10639ce97d2..c2c16ef9218febbb8123e6bf320f1fc5ace5c79e 100644 (file)
@@ -413,4 +413,6 @@ EXPORT(sysn32_call_table)
        PTR     sys_dup3                        /* 5290 */
        PTR     sys_pipe2
        PTR     sys_inotify_init1
+       PTR     sys_preadv
+       PTR     sys_pwritev
        .size   sysn32_call_table,.-sysn32_call_table
index 60997f1f69d4e857861df014ab37e403f1d53c60..002fac27021e61c2ed5aeac2de56b8a01ac70651 100644 (file)
@@ -533,4 +533,6 @@ sys_call_table:
        PTR     sys_dup3
        PTR     sys_pipe2
        PTR     sys_inotify_init1
+       PTR     compat_sys_preadv               /* 4330 */
+       PTR     compat_sys_pwritev
        .size   sys_call_table,.-sys_call_table
index 4430a1f8fdf127da309875755735a949f188c98a..2950b97253b7348c02134a2317372e78ba61c703 100644 (file)
@@ -277,7 +277,8 @@ static void __init bootmem_init(void)
         * not selected. Once that done we can determine the low bound
         * of usable memory.
         */
-       reserved_end = max(init_initrd(), PFN_UP(__pa_symbol(&_end)));
+       reserved_end = max(init_initrd(),
+                          (unsigned long) PFN_UP(__pa_symbol(&_end)));
 
        /*
         * max_low_pfn is not a number of pages. The number of pages
index ead6c30eeb145fdc8be0e7d7736ef74411552f66..878e3733bbb2c6577074899e34cb034accee3d60 100644 (file)
@@ -13,7 +13,7 @@
 /*
  * Send inter-processor interrupt
  */
-void up_send_ipi_single(int cpu, unsigned int action)
+static void up_send_ipi_single(int cpu, unsigned int action)
 {
        panic(KERN_ERR "%s called", __func__);
 }
@@ -27,31 +27,31 @@ static inline void up_send_ipi_mask(cpumask_t mask, unsigned int action)
  *  After we've done initial boot, this function is called to allow the
  *  board code to clean up state, if needed
  */
-void __cpuinit up_init_secondary(void)
+static void __cpuinit up_init_secondary(void)
 {
 }
 
-void __cpuinit up_smp_finish(void)
+static void __cpuinit up_smp_finish(void)
 {
 }
 
 /* Hook for after all CPUs are online */
-void up_cpus_done(void)
+static void up_cpus_done(void)
 {
 }
 
 /*
  * Firmware CPU startup hook
  */
-void __cpuinit up_boot_secondary(int cpu, struct task_struct *idle)
+static void __cpuinit up_boot_secondary(int cpu, struct task_struct *idle)
 {
 }
 
-void __init up_smp_setup(void)
+static void __init up_smp_setup(void)
 {
 }
 
-void __init up_prepare_cpus(unsigned int max_cpus)
+static void __init up_prepare_cpus(unsigned int max_cpus)
 {
 }
 
index 3da94704f81645027d246cf6aea5be80119eddfa..c937506a03aac9f1eedcea13f05e30c0ed0c9fcc 100644 (file)
@@ -44,7 +44,7 @@
 #include <asm/mipsmtregs.h>
 #endif /* CONFIG_MIPS_MT_SMTC */
 
-volatile cpumask_t cpu_callin_map;     /* Bitmask of started secondaries */
+static volatile cpumask_t cpu_callin_map;      /* Bitmask of started secondaries */
 int __cpu_number_map[NR_CPUS];         /* Map physical to logical */
 int __cpu_logical_map[NR_CPUS];                /* Map logical to physical */
 
index 29fadaccecddef31d5da3ea33f819b1ad3941fe0..e83da174b5333537f5daaf089e9ad2e6d86c2b0f 100644 (file)
@@ -1277,8 +1277,7 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs)
        u32 *w;
        unsigned char *b;
 
-       if (!cpu_has_veic && !cpu_has_vint)
-               BUG();
+       BUG_ON(!cpu_has_veic && !cpu_has_vint);
 
        if (addr == NULL) {
                handler = (unsigned long) do_default_vi;
index d1ac7a25c85613635cdc14dc7858ff44d921e099..1353fb135ed370969d9b2b7628a13cd041470542 100644 (file)
@@ -104,7 +104,6 @@ asmlinkage void plat_irq_dispatch(void)
 
 static struct irqaction cascade = {
        .handler        = no_action,
-       .mask           = CPU_MASK_NONE,
        .name           = "cascade",
 };
 
index 3e0b7beb1009b336c0eee30f2da22428d6196db2..1d0a09f3b832a69d4617f37222209fc1a569cc0b 100644 (file)
@@ -92,7 +92,6 @@ asmlinkage void plat_irq_dispatch(void)
 
 static struct irqaction cascade_irqaction = {
        .handler = no_action,
-       .mask = CPU_MASK_NONE,
        .name = "cascade",
 };
 
index 871e828bc62ac2e7db45405f4347b598374301a5..58d9075e86feee1021b0c5e9a91b4f8f49ac9e75 100644 (file)
@@ -1026,13 +1026,7 @@ static void __cpuinit probe_pcache(void)
                c->icache.flags |= MIPS_CACHE_VTAG;
                break;
 
-       case CPU_AU1000:
-       case CPU_AU1500:
-       case CPU_AU1100:
-       case CPU_AU1550:
-       case CPU_AU1200:
-       case CPU_AU1210:
-       case CPU_AU1250:
+       case CPU_ALCHEMY:
                c->icache.flags |= MIPS_CACHE_IC_F_DC;
                break;
        }
@@ -1244,7 +1238,7 @@ void au1x00_fixup_config_od(void)
        /*
         * Au1100 errata actually keeps silence about this bit, so we set it
         * just in case for those revisions that require it to be set according
-        * to arch/mips/au1000/common/cputable.c
+        * to the (now gone) cpu table.
         */
        case 0x02030200: /* Au1100 AB */
        case 0x02030201: /* Au1100 BA */
@@ -1314,11 +1308,10 @@ static void __cpuinit coherency_setup(void)
                break;
        /*
         * We need to catch the early Alchemy SOCs with
-        * the write-only co_config.od bit and set it back to one...
+        * the write-only co_config.od bit and set it back to one on:
+        * Au1000 rev DA, HA, HB;  Au1100 AB, BA, BC, Au1500 AB
         */
-       case CPU_AU1000: /* rev. DA, HA, HB */
-       case CPU_AU1100: /* rev. AB, BA, BC ?? */
-       case CPU_AU1500: /* rev. AB */
+       case CPU_ALCHEMY:
                au1x00_fixup_config_od();
                break;
 
index 8f2cd8eda7415c37d0a2ff2da7a8c3e1d587ebd0..4481656d10656f37a6e088dbb91aa50286216646 100644 (file)
@@ -17,8 +17,7 @@ void *__kmap(struct page *page)
 
 void __kunmap(struct page *page)
 {
-       if (in_interrupt())
-               BUG();
+       BUG_ON(in_interrupt());
        if (!PageHighMem(page))
                return;
        kunmap_high(page);
@@ -43,11 +42,11 @@ void *__kmap_atomic(struct page *page, enum km_type type)
        if (!PageHighMem(page))
                return page_address(page);
 
+       debug_kmap_atomic(type);
        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
-       if (!pte_none(*(kmap_pte-idx)))
-               BUG();
+       BUG_ON(!pte_none(*(kmap_pte - idx)));
 #endif
        set_pte(kmap_pte-idx, mk_pte(page, kmap_prot));
        local_flush_tlb_one((unsigned long)vaddr);
@@ -66,8 +65,7 @@ void __kunmap_atomic(void *kvaddr, enum km_type type)
                return;
        }
 
-       if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx))
-               BUG();
+       BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
 
        /*
         * force other mappings to Oops if they'll try to access
@@ -91,6 +89,7 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
 
        pagefault_disable();
 
+       debug_kmap_atomic(type);
        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
        set_pte(kmap_pte-idx, pfn_pte(pfn, kmap_prot));
index 137c14bafd6b55932e793017f02bda315dea12b5..d9348946a19e1844cc9dff5b7bb21ba37a03fd65 100644 (file)
@@ -307,8 +307,7 @@ void __init fixrange_init(unsigned long start, unsigned long end,
                                if (pmd_none(*pmd)) {
                                        pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
                                        set_pmd(pmd, __pmd((unsigned long)pte));
-                                       if (pte != pte_offset_kernel(pmd, 0))
-                                               BUG();
+                                       BUG_ON(pte != pte_offset_kernel(pmd, 0));
                                }
                                vaddr += PMD_SIZE;
                        }
index 59945b9ee23c1818aa08463f2e8e98f401d376f0..0c43248347bd82e8ad0b7fb97414e401fdbe2bba 100644 (file)
@@ -27,8 +27,7 @@ static inline void remap_area_pte(pte_t * pte, unsigned long address,
        end = address + size;
        if (end > PMD_SIZE)
                end = PMD_SIZE;
-       if (address >= end)
-               BUG();
+       BUG_ON(address >= end);
        pfn = phys_addr >> PAGE_SHIFT;
        do {
                if (!pte_none(*pte)) {
@@ -52,8 +51,7 @@ static inline int remap_area_pmd(pmd_t * pmd, unsigned long address,
        if (end > PGDIR_SIZE)
                end = PGDIR_SIZE;
        phys_addr -= address;
-       if (address >= end)
-               BUG();
+       BUG_ON(address >= end);
        do {
                pte_t * pte = pte_alloc_kernel(pmd, address);
                if (!pte)
@@ -75,8 +73,7 @@ static int remap_area_pages(unsigned long address, phys_t phys_addr,
        phys_addr -= address;
        dir = pgd_offset(&init_mm, address);
        flush_cache_all();
-       if (address >= end)
-               BUG();
+       BUG_ON(address >= end);
        do {
                pud_t *pud;
                pmd_t *pmd;
index f335cf6cdd78ed1c60da268fc63d5979fb9800a8..0615b62efd6d187533bea477c968d86e5074f0b8 100644 (file)
@@ -292,13 +292,6 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l,
        case CPU_R4300:
        case CPU_5KC:
        case CPU_TX49XX:
-       case CPU_AU1000:
-       case CPU_AU1100:
-       case CPU_AU1500:
-       case CPU_AU1550:
-       case CPU_AU1200:
-       case CPU_AU1210:
-       case CPU_AU1250:
        case CPU_PR4450:
                uasm_i_nop(p);
                tlbw(p);
@@ -321,6 +314,7 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l,
        case CPU_R5500:
                if (m4kc_tlbp_war())
                        uasm_i_nop(p);
+       case CPU_ALCHEMY:
                tlbw(p);
                break;
 
index 4832af2516680d4ac653ac31017f6a6960bab0d6..475038a141a65038ee34792a6d06395010004a93 100644 (file)
@@ -48,7 +48,7 @@ int *_prom_argv, *_prom_envp;
 
 int init_debug = 0;
 
-int mips_revision_corid;
+static int mips_revision_corid;
 int mips_revision_sconid;
 
 /* Bonito64 system controller register base. */
index 7d05e68fdc77974454cf22583f57af720cf135e8..04cebadc2b3cf41bece15fdf87af92e4f1dfef0b 100644 (file)
@@ -66,7 +66,7 @@ int ip27_be_handler(struct pt_regs *regs, int is_fixup)
        printk("Slice %c got %cbe at 0x%lx\n", 'A' + cpu, data ? 'd' : 'i',
               regs->cp0_epc);
        printk("Hub information:\n");
-       printk("ERR_INT_PEND = 0x%06lx\n", LOCAL_HUB_L(PI_ERR_INT_PEND));
+       printk("ERR_INT_PEND = 0x%06llx\n", LOCAL_HUB_L(PI_ERR_INT_PEND));
        errst0 = LOCAL_HUB_L(cpu ? PI_ERR_STATUS0_B : PI_ERR_STATUS0_A);
        errst1 = LOCAL_HUB_L(cpu ? PI_ERR_STATUS1_B : PI_ERR_STATUS1_A);
        dump_hub_information(errst0, errst1);
index 64459e7d891b1a45f5d089b350b65598626f163f..6c5a630566f93d77997839577fbc5386c5830c97 100644 (file)
@@ -143,8 +143,8 @@ void nmi_dump_hub_irq(nasid_t nasid, int slice)
        pend0 = REMOTE_HUB_L(nasid, PI_INT_PEND0);
        pend1 = REMOTE_HUB_L(nasid, PI_INT_PEND1);
 
-       printk("PI_INT_MASK0: %16lx PI_INT_MASK1: %16lx\n", mask0, mask1);
-       printk("PI_INT_PEND0: %16lx PI_INT_PEND1: %16lx\n", pend0, pend1);
+       printk("PI_INT_MASK0: %16Lx PI_INT_MASK1: %16Lx\n", mask0, mask1);
+       printk("PI_INT_PEND0: %16Lx PI_INT_PEND1: %16Lx\n", pend0, pend1);
        printk("\n\n");
 }
 
@@ -219,7 +219,7 @@ cont_nmi_dump(void)
                if (i == 1000) {
                        for_each_online_node(node)
                                if (NODEPDA(node)->dump_count == 0) {
-                                       cpu = node_to_first_cpu(node);
+                                       cpu = cpumask_first(cpumask_of_node(node));
                                        for (n=0; n < CNODE_NUM_CPUS(node); cpu++, n++) {
                                                CPUMASK_SETB(nmied_cpus, cpu);
                                                /*
index 0d6b6663d5f6756e1beb4c1426573a7424bc8c25..83a0b3c359daecee88c87223beef876d9b35aab9 100644 (file)
@@ -115,14 +115,12 @@ extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id);
 struct irqaction memerr_irq = {
        .handler = crime_memerr_intr,
        .flags = IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "CRIME memory error",
 };
 
 struct irqaction cpuerr_irq = {
        .handler = crime_cpuerr_intr,
        .flags = IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "CRIME CPU error",
 };
 
@@ -325,16 +323,11 @@ static void mask_and_ack_maceisa_irq(unsigned int irq)
 {
        unsigned long mace_int;
 
-       switch (irq) {
-       case MACEISA_PARALLEL_IRQ:
-       case MACEISA_SERIAL1_TDMAPR_IRQ:
-       case MACEISA_SERIAL2_TDMAPR_IRQ:
-               /* edge triggered */
-               mace_int = mace->perif.ctrl.istat;
-               mace_int &= ~(1 << (irq - MACEISA_AUDIO_SW_IRQ));
-               mace->perif.ctrl.istat = mace_int;
-               break;
-       }
+       /* edge triggered */
+       mace_int = mace->perif.ctrl.istat;
+       mace_int &= ~(1 << (irq - MACEISA_AUDIO_SW_IRQ));
+       mace->perif.ctrl.istat = mace_int;
+
        disable_maceisa_irq(irq);
 }
 
@@ -344,7 +337,16 @@ static void end_maceisa_irq(unsigned irq)
                enable_maceisa_irq(irq);
 }
 
-static struct irq_chip ip32_maceisa_interrupt = {
+static struct irq_chip ip32_maceisa_level_interrupt = {
+       .name           = "IP32 MACE ISA",
+       .ack            = disable_maceisa_irq,
+       .mask           = disable_maceisa_irq,
+       .mask_ack       = disable_maceisa_irq,
+       .unmask         = enable_maceisa_irq,
+       .end            = end_maceisa_irq,
+};
+
+static struct irq_chip ip32_maceisa_edge_interrupt = {
        .name           = "IP32 MACE ISA",
        .ack            = mask_and_ack_maceisa_irq,
        .mask           = disable_maceisa_irq,
@@ -500,27 +502,50 @@ void __init arch_init_irq(void)
        for (irq = CRIME_IRQ_BASE; irq <= IP32_IRQ_MAX; irq++) {
                switch (irq) {
                case MACE_VID_IN1_IRQ ... MACE_PCI_BRIDGE_IRQ:
-                       set_irq_chip(irq, &ip32_mace_interrupt);
+                       set_irq_chip_and_handler_name(irq,&ip32_mace_interrupt,
+                               handle_level_irq, "level");
                        break;
+
                case MACEPCI_SCSI0_IRQ ...  MACEPCI_SHARED2_IRQ:
-                       set_irq_chip(irq, &ip32_macepci_interrupt);
+                       set_irq_chip_and_handler_name(irq,
+                               &ip32_macepci_interrupt, handle_level_irq,
+                               "level");
                        break;
+
                case CRIME_GBE0_IRQ ... CRIME_GBE3_IRQ:
-                       set_irq_chip(irq, &crime_edge_interrupt);
+                       set_irq_chip_and_handler_name(irq,
+                               &crime_edge_interrupt, handle_edge_irq, "edge");
                        break;
                case CRIME_CPUERR_IRQ:
                case CRIME_MEMERR_IRQ:
-                       set_irq_chip(irq, &crime_level_interrupt);
+                       set_irq_chip_and_handler_name(irq,
+                               &crime_level_interrupt, handle_level_irq,
+                               "level");
                        break;
+
                case CRIME_RE_EMPTY_E_IRQ ... CRIME_RE_IDLE_E_IRQ:
                case CRIME_SOFT0_IRQ ... CRIME_SOFT2_IRQ:
-                       set_irq_chip(irq, &crime_edge_interrupt);
+                       set_irq_chip_and_handler_name(irq,
+                               &crime_edge_interrupt, handle_edge_irq, "edge");
                        break;
+
                case CRIME_VICE_IRQ:
-                       set_irq_chip(irq, &crime_edge_interrupt);
+                       set_irq_chip_and_handler_name(irq,
+                               &crime_edge_interrupt, handle_edge_irq, "edge");
+                       break;
+
+               case MACEISA_PARALLEL_IRQ:
+               case MACEISA_SERIAL1_TDMAPR_IRQ:
+               case MACEISA_SERIAL2_TDMAPR_IRQ:
+                       set_irq_chip_and_handler_name(irq,
+                               &ip32_maceisa_edge_interrupt, handle_edge_irq,
+                               "edge");
                        break;
+
                default:
-                       set_irq_chip(irq, &ip32_maceisa_interrupt);
+                       set_irq_chip_and_handler_name(irq,
+                               &ip32_maceisa_level_interrupt, handle_level_irq,
+                               "level");
                        break;
                }
        }
index ca93ecf825ae73b84e1d1a2bb0f38dcd70962c3e..828ce131c22800ab2c496d049ba7396286ff1fbe 100644 (file)
@@ -36,7 +36,7 @@ void __init prom_meminit(void)
                if (base + size > (256 << 20))
                        base += CRIME_HI_MEM_BASE;
 
-               printk("CRIME MC: bank %u base 0x%016lx size %luMiB\n",
+               printk("CRIME MC: bank %u base 0x%016Lx size %LuMiB\n",
                        bank, base, size >> 20);
                add_memory_region(base, size, BOOT_MEM_RAM);
        }
index 12b465d404dfc393e0996a248ff5e9a510aefe5e..352352b3cb2fad84f74a43e3c46b8cd479d39c19 100644 (file)
@@ -236,7 +236,7 @@ void __init init_bcm1480_irqs(void)
        int i;
 
        for (i = 0; i < BCM1480_NR_IRQS; i++) {
-               set_irq_chip(i, &bcm1480_irq_type);
+               set_irq_chip_and_handler(i, &bcm1480_irq_type, handle_level_irq);
                bcm1480_irq_owner[i] = 0;
        }
 }
index 808ac2959b8c497ff69f3bfe64090893ea57ca64..c08ff582da6f05144535cf3c04615ab640b5e805 100644 (file)
@@ -220,7 +220,7 @@ void __init init_sb1250_irqs(void)
        int i;
 
        for (i = 0; i < SB1250_NR_IRQS; i++) {
-               set_irq_chip(i, &sb1250_irq_type);
+               set_irq_chip_and_handler(i, &sb1250_irq_type, handle_level_irq);
                sb1250_irq_owner[i] = 0;
        }
 }
index 3f8cf5eb2f063be6efc7a56467e621ea9eafa21d..7dd76fb3b64500b67e1554c7c229b010cce6391d 100644 (file)
@@ -219,7 +219,7 @@ void __init sni_a20r_irq_init(void)
        int i;
 
        for (i = SNI_A20R_IRQ_BASE + 2 ; i < SNI_A20R_IRQ_BASE + 8; i++)
-               set_irq_chip(i, &a20r_irq_type);
+               set_irq_chip_and_handler(i, &a20r_irq_type, handle_level_irq);
        sni_hwint = a20r_hwint;
        change_c0_status(ST0_IM, IE_IRQ0);
        setup_irq(SNI_A20R_IRQ_BASE + 3, &sni_isa_irq);
index 834650f371e08ebb5917cd8b7ca9a1659eaaf54f..74e6c67982fb693134c023866aa80328826dbf73 100644 (file)
@@ -304,7 +304,7 @@ void __init sni_pcimt_irq_init(void)
        mips_cpu_irq_init();
        /* Actually we've got more interrupts to handle ...  */
        for (i = PCIMT_IRQ_INT2; i <= PCIMT_IRQ_SCSI; i++)
-               set_irq_chip(i, &pcimt_irq_type);
+               set_irq_chip_and_handler(i, &pcimt_irq_type, handle_level_irq);
        sni_hwint = sni_pcimt_hwint;
        change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ3);
 }
index e5f12cf96e8ec2ab9ce96d649ad8fd7289f2aab7..071a9573ac7f65345d4d6b23589b3851d5f511a8 100644 (file)
@@ -246,7 +246,7 @@ void __init sni_pcit_irq_init(void)
 
        mips_cpu_irq_init();
        for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++)
-               set_irq_chip(i, &pcit_irq_type);
+               set_irq_chip_and_handler(i, &pcit_irq_type, handle_level_irq);
        *(volatile u32 *)SNI_PCIT_INT_REG = 0;
        sni_hwint = sni_pcit_hwint;
        change_c0_status(ST0_IM, IE_IRQ1);
@@ -259,7 +259,7 @@ void __init sni_pcit_cplus_irq_init(void)
 
        mips_cpu_irq_init();
        for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++)
-               set_irq_chip(i, &pcit_irq_type);
+               set_irq_chip_and_handler(i, &pcit_irq_type, handle_level_irq);
        *(volatile u32 *)SNI_PCIT_INT_REG = 0x40000000;
        sni_hwint = sni_pcit_hwint_cplus;
        change_c0_status(ST0_IM, IE_IRQ0);
index 5310aa75afa43bf88740c4ebd1642ec69006b5ad..5e687819cbc2aec4aec85dbada30184a345a6551 100644 (file)
@@ -359,7 +359,8 @@ void sni_rm200_init_8259A(void)
  * IRQ2 is cascade interrupt to second interrupt controller
  */
 static struct irqaction sni_rm200_irq2 = {
-       no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL
+       .handler = no_action,
+       .name = "cascade",
 };
 
 static struct resource sni_rm200_pic1_resource = {
@@ -487,7 +488,7 @@ void __init sni_rm200_irq_init(void)
        mips_cpu_irq_init();
        /* Actually we've got more interrupts to handle ...  */
        for (i = SNI_RM200_INT_START; i <= SNI_RM200_INT_END; i++)
-               set_irq_chip(i, &rm200_irq_type);
+               set_irq_chip_and_handler(i, &rm200_irq_type, handle_level_irq);
        sni_hwint = sni_rm200_hwint;
        change_c0_status(ST0_IM, IE_IRQ0);
        setup_irq(SNI_RM200_INT_START + 0, &sni_rm200_i8259A_irq);
index 226e8bb2f0a1bb6336e9b5ce64352bdfaec666d5..0db7cf38ed8b557de52909a2231a3625cb85bee5 100644 (file)
@@ -20,7 +20,6 @@ config MACH_TXX9
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_SUPPORTS_BIG_ENDIAN
-       select GENERIC_HARDIRQS_NO__DO_IRQ
 
 config TOSHIBA_JMR3927
        bool "Toshiba JMR-TX3927 board"
index 92dd1a0ca3523023a30d887067c9e280864cfce5..9cc389109b19f42ee82f5d09f69b8d3e8de27024 100644 (file)
@@ -32,7 +32,6 @@ static irq_cascade_t irq_cascade[NR_IRQS] __cacheline_aligned;
 
 static struct irqaction cascade_irqaction = {
        .handler        = no_action,
-       .mask           = CPU_MASK_NONE,
        .name           = "cascade",
 };
 
index b28c9a60445bda4df1f4f83de51346b121e36067..234cf344cdceb1e39f550947ddae8d2331435d63 100644 (file)
@@ -193,7 +193,7 @@ void prepare_to_copy(struct task_struct *tsk)
  * set up the kernel stack for a new thread and copy arch-specific thread
  * control information
  */
-int copy_thread(int nr, unsigned long clone_flags,
+int copy_thread(unsigned long clone_flags,
                unsigned long c_usp, unsigned long ustk_size,
                struct task_struct *p, struct pt_regs *kregs)
 {
index e4606586f94ce5e08d35720ca8b4f7512db4aa34..395caf01b9099cc42c2b2e3b0148765df3de0ed9 100644 (file)
@@ -37,7 +37,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id);
 static struct irqaction timer_irq = {
        .handler        = timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER,
-       .mask           = CPU_MASK_NONE,
        .name           = "timer",
 };
 
index f3d2090a18dc316e5a4cbd388abb32e94717b764..fae03e136fa8619b6d1efc09d750992949ec3dc2 100644 (file)
@@ -187,6 +187,9 @@ static __inline__ int __raw_write_can_lock(raw_rwlock_t *rw)
        return !rw->counter;
 }
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
index b80e02a4d81de3d193ec1faae269b7614a783cf1..8aa591ed9127d5e1f8aa9982ce3827c6b3bc2982 100644 (file)
@@ -263,7 +263,7 @@ sys_vfork(struct pt_regs *regs)
 }
 
 int
-copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+copy_thread(unsigned long clone_flags, unsigned long usp,
            unsigned long unused,       /* in ia64 this is "user_stack_size" */
            struct task_struct * p, struct pt_regs * pregs)
 {
index 9d46c43a415291a005fc8ff2ef7331d3ff8dbbb7..e75cae6072c574592d9146b8fe30354ebb2cb4a4 100644 (file)
@@ -216,17 +216,14 @@ void __init start_cpu_itimer(void)
        per_cpu(cpu_data, cpu).it_value = next_tick;
 }
 
-struct platform_device rtc_parisc_dev = {
+static struct platform_device rtc_parisc_dev = {
        .name = "rtc-parisc",
        .id = -1,
 };
 
 static int __init rtc_init(void)
 {
-       int ret;
-
-       ret = platform_device_register(&rtc_parisc_dev);
-       if (ret < 0)
+       if (platform_device_register(&rtc_parisc_dev) < 0)
                printk(KERN_ERR "unable to register rtc device...\n");
 
        /* not necessarily an error */
index 74cc312c347cf8d49f56eb9a60a0bb0c08a4408c..45192dce65c44099c011a3aca3dfd5ead15bd6f8 100644 (file)
@@ -111,6 +111,7 @@ config PPC
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_DYNAMIC_FTRACE
        select HAVE_FUNCTION_TRACER
+       select HAVE_FUNCTION_GRAPH_TRACER
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select HAVE_IDE
        select HAVE_IOREMAP_PROT
@@ -227,6 +228,9 @@ config PPC_OF_PLATFORM_PCI
        depends on PPC64 # not supported on 32 bits yet
        default n
 
+config ARCH_SUPPORTS_DEBUG_PAGEALLOC
+       def_bool y
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
@@ -312,7 +316,7 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE
 
 config KEXEC
        bool "kexec system call (EXPERIMENTAL)"
-       depends on (PPC_PRPMC2800 || PPC_MULTIPLATFORM) && EXPERIMENTAL
+       depends on BOOK3S && EXPERIMENTAL
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
@@ -409,6 +413,18 @@ config PPC_HAS_HASH_64K
        depends on PPC64
        default n
 
+config STDBINUTILS
+       bool "Using standard binutils settings"
+       depends on 44x
+       default y
+       help
+         Turning this option off allows you to select 256KB PAGE_SIZE on 44x.
+         Note, that kernel will be able to run only those applications,
+         which had been compiled using binutils later than 2.17.50.0.3 with
+         '-zmax-page-size' set to 256K (the default is 64K). Or, if using
+         the older binutils, you can patch them with a trivial patch, which
+         changes the ELF_MAXPAGESIZE definition from 0x10000 to 0x40000.
+
 choice
        prompt "Page size"
        default PPC_4K_PAGES
@@ -444,6 +460,19 @@ config PPC_64K_PAGES
        bool "64k page size" if 44x || PPC_STD_MMU_64
        select PPC_HAS_HASH_64K if PPC_STD_MMU_64
 
+config PPC_256K_PAGES
+       bool "256k page size" if 44x
+       depends on !STDBINUTILS && (!SHMEM || BROKEN)
+       help
+         Make the page size 256k.
+
+         As the ELF standard only requires alignment to support page
+         sizes up to 64k, you will need to compile all of your user
+         space applications with a non-standard binutils settings
+         (see the STDBINUTILS description for details).
+
+         Say N unless you know what you are doing.
+
 endchoice
 
 config FORCE_MAX_ZONEORDER
@@ -456,6 +485,8 @@ config FORCE_MAX_ZONEORDER
        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 11 64
        default "11"
        help
@@ -594,6 +625,7 @@ config FSL_SOC
 config FSL_PCI
        bool
        select PPC_INDIRECT_PCI
+       select PCI_QUIRKS
 
 config 4xx_SOC
        bool
@@ -730,6 +762,22 @@ config LOWMEM_SIZE
        hex "Maximum low memory size (in bytes)" if LOWMEM_SIZE_BOOL
        default "0x30000000"
 
+config LOWMEM_CAM_NUM_BOOL
+       bool "Set number of CAMs to use to map low memory"
+       depends on ADVANCED_OPTIONS && FSL_BOOKE
+       help
+         This option allows you to set the maximum number of CAM slots that
+         will be used to map low memory.  There are a limited number of slots
+         available and even more limited number that will fit in the L1 MMU.
+         However, using more entries will allow mapping more low memory.  This
+         can be useful in optimizing the layout of kernel virtual memory.
+
+         Say N here unless you know what you are doing.
+
+config LOWMEM_CAM_NUM
+       int "Number of CAMs to use to map low memory" if LOWMEM_CAM_NUM_BOOL
+       default 3
+
 config RELOCATABLE
        bool "Build a relocatable kernel (EXPERIMENTAL)"
        depends on EXPERIMENTAL && ADVANCED_OPTIONS && FLATMEM && FSL_BOOKE
@@ -794,7 +842,7 @@ config PHYSICAL_START
 
 config PHYSICAL_ALIGN
        hex
-       default "0x10000000" if FSL_BOOKE
+       default "0x04000000" if FSL_BOOKE
        help
          This value puts the alignment restrictions on physical address
          where kernel is loaded and run from. Kernel is compiled for an
@@ -815,31 +863,6 @@ config TASK_SIZE
        default "0x80000000" if PPC_PREP || PPC_8xx
        default "0xc0000000"
 
-config CONSISTENT_START_BOOL
-       bool "Set custom consistent memory pool address"
-       depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE
-       help
-         This option allows you to set the base virtual address
-         of the consistent memory pool.  This pool of virtual
-         memory is used to make consistent memory allocations.
-
-config CONSISTENT_START
-       hex "Base virtual address of consistent memory pool" if CONSISTENT_START_BOOL
-       default "0xfd000000" if (NOT_COHERENT_CACHE && 8xx)
-       default "0xff100000" if NOT_COHERENT_CACHE
-
-config CONSISTENT_SIZE_BOOL
-       bool "Set custom consistent memory pool size"
-       depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE
-       help
-         This option allows you to set the size of the
-         consistent memory pool.  This pool of virtual memory
-         is used to make consistent memory allocations.
-
-config CONSISTENT_SIZE
-       hex "Size of consistent memory pool" if CONSISTENT_SIZE_BOOL
-       default "0x00200000" if NOT_COHERENT_CACHE
-
 config PIN_TLB
        bool "Pinned Kernel TLBs (860 ONLY)"
        depends on ADVANCED_OPTIONS && 8xx
index 08f7cc0a1953a2c3bae6c88e165f44e50379c23d..a1098e23221fb1debd36fc62bf54740f1829a3e4 100644 (file)
@@ -27,15 +27,6 @@ config DEBUG_STACK_USAGE
 
          This option will slow down process creation somewhat.
 
-config DEBUG_PAGEALLOC
-        bool "Debug page memory allocations"
-        depends on DEBUG_KERNEL && !HIBERNATION
-        help
-          Unmap pages from the kernel linear mapping after free_pages().
-          This results in a large slowdown, but helps to find certain types
-          of memory corruptions.
-
-
 config HCALL_STATS
        bool "Hypervisor call instrumentation"
        depends on PPC_PSERIES && DEBUG_FS
@@ -129,7 +120,7 @@ config BDI_SWITCH
 
 config BOOTX_TEXT
        bool "Support for early boot text console (BootX or OpenFirmware only)"
-       depends on PPC_OF && PPC_MULTIPLATFORM
+       depends on PPC_OF && PPC_BOOK3S
        help
          Say Y here to see progress messages from the boot firmware in text
          mode. Requires either BootX or Open Firmware.
index 72d17f50e54fa7befc6b920fb781d393dd04a98a..551fc58c05cf7d4299acf91b71fa0f395ac75ed9 100644 (file)
@@ -147,8 +147,8 @@ core-y                              += arch/powerpc/kernel/ \
                                   arch/powerpc/mm/ \
                                   arch/powerpc/lib/ \
                                   arch/powerpc/sysdev/ \
-                                  arch/powerpc/platforms/
-core-$(CONFIG_MATH_EMULATION)  += arch/powerpc/math-emu/
+                                  arch/powerpc/platforms/ \
+                                  arch/powerpc/math-emu/
 core-$(CONFIG_XMON)            += arch/powerpc/xmon/
 core-$(CONFIG_KVM)             += arch/powerpc/kvm/
 
index e84df338ea298762cb3f75c8393aef3dc14a3167..4458abb67c51bc5df204d261aeaed778122476a4 100644 (file)
@@ -70,7 +70,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-acadia.c cuboot-amigaone.c
 src-boot := $(src-wlib) $(src-plat) empty.c
 
 src-boot := $(addprefix $(obj)/, $(src-boot))
@@ -235,7 +235,9 @@ image-$(CONFIG_PPC_ADDER875)                += cuImage.adder875-uboot \
                                           dtbImage.adder875-redboot
 
 # Board ports in arch/powerpc/platform/52xx/Kconfig
-image-$(CONFIG_PPC_LITE5200)           += cuImage.lite5200 cuImage.lite5200b
+image-$(CONFIG_PPC_LITE5200)           += cuImage.lite5200 lite5200.dtb
+image-$(CONFIG_PPC_LITE5200)           += cuImage.lite5200b lite5200b.dtb
+image-$(CONFIG_PPC_MEDIA5200)          += cuImage.media5200 media5200.dtb
 
 # Board ports in arch/powerpc/platform/82xx/Kconfig
 image-$(CONFIG_MPC8272_ADS)            += cuImage.mpc8272ads
@@ -274,6 +276,9 @@ image-$(CONFIG_STORCENTER)          += cuImage.storcenter
 image-$(CONFIG_MPC7448HPC2)            += cuImage.mpc7448hpc2
 image-$(CONFIG_PPC_C2K)                        += cuImage.c2k
 
+# Board port in arch/powerpc/platform/amigaone/Kconfig
+image-$(CONFIG_AMIGAONE)               += cuImage.amigaone
+
 # For 32-bit powermacs, build the COFF and miboot images
 # as well as the ELF images.
 ifeq ($(CONFIG_PPC32),y)
diff --git a/arch/powerpc/boot/cuboot-amigaone.c b/arch/powerpc/boot/cuboot-amigaone.c
new file mode 100644 (file)
index 0000000..d502967
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Old U-boot compatibility for AmigaOne
+ *
+ * Author: Gerhard Pircher (gerhard_pircher@gmx.net)
+ *
+ *   Based on cuboot-83xx.c
+ * Copyright (c) 2007 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 version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "ops.h"
+#include "stdio.h"
+#include "cuboot.h"
+
+#include "ppcboot.h"
+
+static bd_t bd;
+
+static void platform_fixups(void)
+{
+       dt_fixup_memory(bd.bi_memstart, bd.bi_memsize);
+       dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 4, bd.bi_busfreq);
+}
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+                   unsigned long r6, unsigned long r7)
+{
+       CUBOOT_INIT();
+       fdt_init(_dtb_start);
+       serial_console_init();
+       platform_ops.fixups = platform_fixups;
+}
diff --git a/arch/powerpc/boot/dts/amigaone.dts b/arch/powerpc/boot/dts/amigaone.dts
new file mode 100644 (file)
index 0000000..26549fc
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * AmigaOne Device Tree Source
+ *
+ * Copyright 2008 Gerhard Pircher (gerhard_pircher@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.
+ */
+
+/dts-v1/;
+
+/ {
+       model = "AmigaOne";
+       compatible = "eyetech,amigaone";
+       coherency-off;
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       cpus {
+               #cpus = <1>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <32>;       // 32 bytes
+                       i-cache-line-size = <32>;       // 32 bytes
+                       d-cache-size = <32768>;         // L1, 32K
+                       i-cache-size = <32768>;         // L1, 32K
+                       timebase-frequency = <0>;       // 33.3 MHz, from U-boot
+                       clock-frequency = <0>;          // From U-boot
+                       bus-frequency = <0>;            // From U-boot
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0 0>;                            // From U-boot
+       };
+
+       pci@80000000 {
+               device_type = "pci";
+               compatible = "mai-logic,articia-s";
+               bus-frequency = <33333333>;
+               bus-range = <0 0xff>;
+               ranges = <0x01000000 0 0x00000000 0xfe000000 0 0x00c00000       // PCI I/O
+                         0x02000000 0 0x80000000 0x80000000 0 0x7d000000       // PCI memory
+                         0x02000000 0 0x00000000 0xfd000000 0 0x01000000>;     // PCI alias memory (ISA)
+               // Configuration address and data register.
+               reg = <0xfec00cf8 4
+                      0xfee00cfc 4>;
+               8259-interrupt-acknowledge = <0xfef00000>;
+               // Do not define a interrupt-parent here, if there is no
+               // interrupt-map property.
+               #address-cells = <3>;
+               #size-cells = <2>;
+
+               isa@7 {
+                       device_type = "isa";
+                       compatible = "pciclass,0601";
+                       vendor-id = <0x00001106>;
+                       device-id = <0x00000686>;
+                       revision-id = <0x00000010>;
+                       class-code = <0x00060100>;
+                       subsystem-id = <0>;
+                       subsystem-vendor-id = <0>;
+                       devsel-speed = <0x00000001>;
+                       min-grant = <0>;
+                       max-latency = <0>;
+                       /* First 64k for I/O at 0x0 on PCI mapped to 0x0 on ISA. */
+                       ranges = <0x00000001 0 0x01000000 0 0x00000000 0x00010000>;
+                       interrupt-parent = <&i8259>;
+                       #interrupt-cells = <2>;
+                       #address-cells = <2>;
+                       #size-cells = <1>;
+
+                       dma-controller@0 {
+                               compatible = "pnpPNP,200";
+                               reg = <1 0x00000000 0x00000020
+                                      1 0x00000080 0x00000010
+                                      1 0x000000c0 0x00000020>;
+                       };
+
+                       i8259: interrupt-controller@20 {
+                               device_type = "interrupt-controller";
+                               compatible = "pnpPNP,000";
+                               interrupt-controller;
+                               reg = <1 0x00000020 0x00000002
+                                      1 0x000000a0 0x00000002
+                                      1 0x000004d0 0x00000002>;
+                               reserved-interrupts = <2>;
+                               #interrupt-cells = <2>;
+                       };
+
+                       timer@40 {
+                               // Also adds pcspkr to platform devices.
+                               compatible = "pnpPNP,100";
+                               reg = <1 0x00000040 0x00000020>;
+                       };
+
+                       8042@60 {
+                               device_type = "8042";
+                               reg = <1 0x00000060 0x00000001
+                                      1 0x00000064 0x00000001>;
+                               interrupts = <1 3 12 3>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               keyboard@0 {
+                                       compatible = "pnpPNP,303";
+                                       reg = <0>;
+                               };
+
+                               mouse@1 {
+                                       compatible = "pnpPNP,f03";
+                                       reg = <1>;
+                               };
+                       };
+
+                       rtc@70 {
+                               compatible = "pnpPNP,b00";
+                               reg = <1 0x00000070 0x00000002>;
+                               interrupts = <8 3>;
+                       };
+
+                       serial@3f8 {
+                               device_type = "serial";
+                               compatible = "pnpPNP,501","pnpPNP,500";
+                               reg = <1 0x000003f8 0x00000008>;
+                               interrupts = <4 3>;
+                               clock-frequency = <1843200>;
+                               current-speed = <115200>;
+                       };
+
+                       serial@2f8 {
+                               device_type = "serial";
+                               compatible = "pnpPNP,501","pnpPNP,500";
+                               reg = <1 0x000002f8 0x00000008>;
+                               interrupts = <3 3>;
+                               clock-frequency = <1843200>;
+                               current-speed = <115200>;
+                       };
+
+                       parallel@378 {
+                               device_type = "parallel";
+                               // No ECP support for now, otherwise add "pnpPNP,401".
+                               compatible = "pnpPNP,400";
+                               reg = <1 0x00000378 0x00000003
+                                      1 0x00000778 0x00000003>;
+                       };
+
+                       fdc@3f0 {
+                               device_type = "fdc";
+                               compatible = "pnpPNP,700";
+                               reg = <1 0x000003f0 0x00000008>;
+                               interrupts = <6 3>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               disk@0 {
+                                       reg = <0>;
+                               };
+                       };
+               };
+       };
+
+       chosen {
+               linux,stdout-path = "/pci@80000000/isa@7/serial@3f8";
+       };
+};
index 524af7ef9f26742e388aa7b6f21adbe75df2b8e5..7da84fd7be93faf176058dd51e6f022f1dca5bf8 100644 (file)
                        phy_type = "ulpi";
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy0: ethernet-phy@0 {
-                               interrupt-parent = <&ipic>;
-                               interrupts = <17 0x8>;
-                               reg = <0x1>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&ipic>;
-                               interrupts = <18 0x8>;
-                               reg = <0x2>;
-                               device_type = "ethernet-phy";
-                       };
-
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        compatible = "gianfar";
                        reg = <0x24000 0x1000>;
+                       ranges = <0x0 0x24000 0x1000>;
                        local-mac-address = [ 00 08 e5 11 32 33 ];
                        interrupts = <32 0x8 33 0x8 34 0x8>;
                        interrupt-parent = <&ipic>;
                        tbi-handle = <&tbi0>;
                        phy-handle = <&phy0>;
                        linux,network-index = <0>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@0 {
+                                       interrupt-parent = <&ipic>;
+                                       interrupts = <17 0x8>;
+                                       reg = <0x1>;
+                                       device_type = "ethernet-phy";
+                               };
+
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&ipic>;
+                                       interrupts = <18 0x8>;
+                                       reg = <0x2>;
+                                       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 = "TSEC";
                        compatible = "gianfar";
                        reg = <0x25000 0x1000>;
+                       ranges = <0x0 0x25000 0x1000>;
                        local-mac-address = [ 00 08 e5 11 32 34 ];
                        interrupts = <35 0x8 36 0x8 37 0x8>;
                        interrupt-parent = <&ipic>;
                        tbi-handle = <&tbi1>;
                        phy-handle = <&phy1>;
                        linux,network-index = <1>;
+
+                       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 {
index 4447def69dc5175f78afb33a7546e901cb9d99b4..5fd1ad09bdf2c1661b0293fd19fcff9f58f71767 100644 (file)
                                        /*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>;
+                };
+
+                USB1: usb@bffd0000 {
+                        compatible = "ohci-le";
+                        reg = <4 0xbffd0000 0x60>;
+                        interrupt-parent = <&UIC2>;
+                        interrupts = <0x1e 4>;
+                };
+
                POB0: opb {
                        compatible = "ibm,opb-460ex", "ibm,opb";
                        #address-cells = <1>;
                                reg = <0xef600700 0x00000014>;
                                interrupt-parent = <&UIC0>;
                                interrupts = <0x2 0x4>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                                rtc@68 {
+                                        compatible = "stm,m41t80";
+                                        reg = <0x68>;
+                                       interrupt-parent = <&UIC2>;
+                                       interrupts = <0x19 0x8>;
+                                };
+                                sttm@48 {
+                                        compatible = "ad,ad7414";
+                                        reg = <0x48>;
+                                       interrupt-parent = <&UIC1>;
+                                       interrupts = <0x14 0x8>;
+                                };
                        };
 
                        IIC1: i2c@ef600800 {
index 2f74cc4e093e16564548179cd035b1df304112a9..cee8080aa2454871cae0f54e39f3c5afab2a2773 100644 (file)
@@ -17,6 +17,7 @@
        compatible = "schindler,cm5200";
        #address-cells = <1>;
        #size-cells = <1>;
+       interrupt-parent = <&mpc5200_pic>;
 
        cpus {
                #address-cells = <1>;
@@ -66,7 +67,6 @@
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        reg = <0x600 0x10>;
                        interrupts = <1 9 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        fsl,has-wdt;
                };
 
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        reg = <0x610 0x10>;
                        interrupts = <1 10 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@620 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        reg = <0x620 0x10>;
                        interrupts = <1 11 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@630 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        reg = <0x630 0x10>;
                        interrupts = <1 12 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@640 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        reg = <0x640 0x10>;
                        interrupts = <1 13 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@650 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        reg = <0x650 0x10>;
                        interrupts = <1 14 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@660 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        reg = <0x660 0x10>;
                        interrupts = <1 15 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@670 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        reg = <0x670 0x10>;
                        interrupts = <1 16 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                rtc@800 {       // Real time clock
                        compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc";
                        reg = <0x800 0x100>;
                        interrupts = <1 5 0 1 6 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
-               gpio@b00 {
+               gpio_simple: gpio@b00 {
                        compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
                        reg = <0xb00 0x40>;
                        interrupts = <1 7 0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
                };
 
-               gpio@c00 {
+               gpio_wkup: gpio@c00 {
                        compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
                        reg = <0xc00 0x40>;
                        interrupts = <1 8 0 0 3 0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
                };
 
                spi@f00 {
                        compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
                        reg = <0xf00 0x20>;
                        interrupts = <2 13 0 2 14 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                usb@1000 {
                        compatible = "fsl,mpc5200b-ohci","fsl,mpc5200-ohci","ohci-be";
                        reg = <0x1000 0xff>;
                        interrupts = <2 6 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                dma-controller@1200 {
                                      3 4 0  3 5 0  3 6 0  3 7 0
                                      3 8 0  3 9 0  3 10 0  3 11 0
                                      3 12 0  3 13 0  3 14 0  3 15 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                xlb@1f00 {
                };
 
                serial@2000 {           // PSC1
-                       device_type = "serial";
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       port-number = <0>;  // Logical port assignment
                        reg = <0x2000 0x100>;
                        interrupts = <2 1 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                serial@2200 {           // PSC2
-                       device_type = "serial";
-                       compatible = "fsl,mpc5200-psc-uart";
-                       port-number = <1>;  // Logical port assignment
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
                        reg = <0x2200 0x100>;
                        interrupts = <2 2 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                serial@2400 {           // PSC3
-                       device_type = "serial";
-                       compatible = "fsl,mpc5200-psc-uart";
-                       port-number = <2>;  // Logical port assignment
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
                        reg = <0x2400 0x100>;
                        interrupts = <2 3 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                serial@2c00 {           // PSC6
-                       device_type = "serial";
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       port-number = <5>;  // Logical port assignment
                        reg = <0x2c00 0x100>;
                        interrupts = <2 4 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                ethernet@3000 {
-                       device_type = "network";
                        compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
                        reg = <0x3000 0x400>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <2 5 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        phy-handle = <&phy0>;
                };
 
                        compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
                        reg = <0x3000 0x400>;       // fec range, since we need to setup fec interrupts
                        interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
-                       interrupt-parent = <&mpc5200_pic>;
 
                        phy0: ethernet-phy@0 {
-                               device_type = "ethernet-phy";
                                reg = <0>;
                        };
                };
                        compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
                        reg = <0x3d40 0x40>;
                        interrupts = <2 16 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        fsl5200-clocking;
                };
 
                };
        };
 
-       lpb {
-               model = "fsl,lpb";
-               compatible = "fsl,lpb";
+       localbus {
+               compatible = "fsl,mpc5200b-lpb","simple-bus";
                #address-cells = <2>;
                #size-cells = <1>;
                ranges = <0 0 0xfc000000 0x2000000>;
diff --git a/arch/powerpc/boot/dts/digsy_mtc.dts b/arch/powerpc/boot/dts/digsy_mtc.dts
new file mode 100644 (file)
index 0000000..4c36186
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Digsy MTC board Device Tree Source
+ *
+ * Copyright (C) 2009 Semihalf
+ *
+ * Based on the CM5200 by M. Balakowicz
+ *
+ * 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 = "intercontrol,digsy-mtc";
+       compatible = "intercontrol,digsy-mtc";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       interrupt-parent = <&mpc5200_pic>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,5200@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <32>;
+                       i-cache-line-size = <32>;
+                       d-cache-size = <0x4000>;                // L1, 16K
+                       i-cache-size = <0x4000>;                // L1, 16K
+                       timebase-frequency = <0>;       // from bootloader
+                       bus-frequency = <0>;            // from bootloader
+                       clock-frequency = <0>;          // from bootloader
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x00000000 0x02000000>;  // 32MB
+       };
+
+       soc5200@f0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc5200b-immr";
+               ranges = <0 0xf0000000 0x0000c000>;
+               reg = <0xf0000000 0x00000100>;
+               bus-frequency = <0>;            // from bootloader
+               system-frequency = <0>;         // from bootloader
+
+               cdm@200 {
+                       compatible = "fsl,mpc5200b-cdm","fsl,mpc5200-cdm";
+                       reg = <0x200 0x38>;
+               };
+
+               mpc5200_pic: interrupt-controller@500 {
+                       // 5200 interrupts are encoded into two levels;
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+                       compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
+                       reg = <0x500 0x80>;
+               };
+
+               timer@600 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x600 0x10>;
+                       interrupts = <1 9 0>;
+                       fsl,has-wdt;
+               };
+
+               timer@610 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x610 0x10>;
+                       interrupts = <1 10 0>;
+               };
+
+               timer@620 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x620 0x10>;
+                       interrupts = <1 11 0>;
+               };
+
+               timer@630 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x630 0x10>;
+                       interrupts = <1 12 0>;
+               };
+
+               timer@640 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x640 0x10>;
+                       interrupts = <1 13 0>;
+               };
+
+               timer@650 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x650 0x10>;
+                       interrupts = <1 14 0>;
+               };
+
+               timer@660 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x660 0x10>;
+                       interrupts = <1 15 0>;
+               };
+
+               timer@670 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x670 0x10>;
+                       interrupts = <1 16 0>;
+               };
+
+               gpio_simple: gpio@b00 {
+                       compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
+                       reg = <0xb00 0x40>;
+                       interrupts = <1 7 0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpio_wkup: gpio@c00 {
+                       compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
+                       reg = <0xc00 0x40>;
+                       interrupts = <1 8 0 0 3 0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               spi@f00 {
+                       compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
+                       reg = <0xf00 0x20>;
+                       interrupts = <2 13 0 2 14 0>;
+               };
+
+               usb@1000 {
+                       compatible = "fsl,mpc5200b-ohci","fsl,mpc5200-ohci","ohci-be";
+                       reg = <0x1000 0xff>;
+                       interrupts = <2 6 0>;
+               };
+
+               dma-controller@1200 {
+                       compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
+                       reg = <0x1200 0x80>;
+                       interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
+                                     3 4 0  3 5 0  3 6 0  3 7 0
+                                     3 8 0  3 9 0  3 10 0  3 11 0
+                                     3 12 0  3 13 0  3 14 0  3 15 0>;
+               };
+
+               xlb@1f00 {
+                       compatible = "fsl,mpc5200b-xlb","fsl,mpc5200-xlb";
+                       reg = <0x1f00 0x100>;
+               };
+
+               serial@2600 {           // PSC4
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+                       reg = <0x2600 0x100>;
+                       interrupts = <2 11 0>;
+               };
+
+               serial@2800 {           // PSC5
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+                       reg = <0x2800 0x100>;
+                       interrupts = <2 12 0>;
+               };
+
+               ethernet@3000 {
+                       compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
+                       reg = <0x3000 0x400>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <2 5 0>;
+                       phy-handle = <&phy0>;
+               };
+
+               mdio@3000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
+                       reg = <0x3000 0x400>;       // fec range, since we need to setup fec interrupts
+                       interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
+
+                       phy0: ethernet-phy@0 {
+                               reg = <0>;
+                       };
+               };
+
+               ata@3a00 {
+                       compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
+                       reg = <0x3a00 0x100>;
+                       interrupts = <2 7 0>;
+               };
+
+               i2c@3d00 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
+                       reg = <0x3d00 0x40>;
+                       interrupts = <2 15 0>;
+                       fsl5200-clocking;
+
+                       rtc@50 {
+                               compatible = "at,24c08";
+                               reg = <0x50>;
+                       };
+
+                       rtc@68 {
+                               compatible = "dallas,ds1339";
+                               reg = <0x68>;
+                       };
+               };
+
+               sram@8000 {
+                       compatible = "fsl,mpc5200b-sram","fsl,mpc5200-sram";
+                       reg = <0x8000 0x4000>;
+               };
+       };
+
+       lpb {
+               compatible = "fsl,mpc5200b-lpb","simple-bus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               ranges = <0 0 0xff000000 0x1000000>;
+
+               // 16-bit flash device at LocalPlus Bus CS0
+               flash@0,0 {
+                       compatible = "cfi-flash";
+                       reg = <0 0 0x1000000>;
+                       bank-width = <2>;
+                       device-width = <2>;
+                       #size-cells = <1>;
+                       #address-cells = <1>;
+
+                       partition@0 {
+                               label = "kernel";
+                               reg = <0x0 0x00200000>;
+                       };
+                       partition@200000 {
+                               label = "root";
+                               reg = <0x00200000 0x00300000>;
+                       };
+                       partition@500000 {
+                               label = "user";
+                               reg = <0x00500000 0x00a00000>;
+                       };
+                       partition@f00000 {
+                               label = "u-boot";
+                               reg = <0x00f00000 0x100000>;
+                       };
+               };
+       };
+};
diff --git a/arch/powerpc/boot/dts/gef_ppc9a.dts b/arch/powerpc/boot/dts/gef_ppc9a.dts
new file mode 100644 (file)
index 0000000..d47ad07
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * GE Fanuc PPC9A Device Tree Source
+ *
+ * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, 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.
+ *
+ * Based on: SBS CM6 Device Tree Source
+ * Copyright 2007 SBS Technologies GmbH & Co. KG
+ * And: mpc8641_hpcn.dts (MPC8641 HPCN Device Tree Source)
+ * Copyright 2006 Freescale Semiconductor Inc.
+ */
+
+/*
+ * Compiled with dtc -I dts -O dtb -o gef_ppc9a.dtb gef_ppc9a.dts
+ */
+
+/dts-v1/;
+
+/ {
+       model = "GEF_PPC9A";
+       compatible = "gef,ppc9a";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       aliases {
+               ethernet0 = &enet0;
+               ethernet1 = &enet1;
+               serial0 = &serial0;
+               serial1 = &serial1;
+               pci0 = &pci0;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,8641@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <32>;       // 32 bytes
+                       i-cache-line-size = <32>;       // 32 bytes
+                       d-cache-size = <32768>;         // L1, 32K
+                       i-cache-size = <32768>;         // L1, 32K
+                       timebase-frequency = <0>;       // From uboot
+                       bus-frequency = <0>;            // From uboot
+                       clock-frequency = <0>;          // From uboot
+               };
+               PowerPC,8641@1 {
+                       device_type = "cpu";
+                       reg = <1>;
+                       d-cache-line-size = <32>;       // 32 bytes
+                       i-cache-line-size = <32>;       // 32 bytes
+                       d-cache-size = <32768>;         // L1, 32K
+                       i-cache-size = <32768>;         // L1, 32K
+                       timebase-frequency = <0>;       // From uboot
+                       bus-frequency = <0>;            // From uboot
+                       clock-frequency = <0>;          // From uboot
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x0 0x40000000>; // set by uboot
+       };
+
+       localbus@fef05000 {
+               #address-cells = <2>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8641-localbus", "simple-bus";
+               reg = <0xfef05000 0x1000>;
+               interrupts = <19 2>;
+               interrupt-parent = <&mpic>;
+
+               ranges = <0 0 0xff000000 0x01000000     // 16MB Boot flash
+                         1 0 0xe8000000 0x08000000     // Paged Flash 0
+                         2 0 0xe0000000 0x08000000     // Paged Flash 1
+                         3 0 0xfc100000 0x00020000     // NVRAM
+                         4 0 0xfc000000 0x00008000     // FPGA
+                         5 0 0xfc008000 0x00008000     // AFIX FPGA
+                         6 0 0xfd000000 0x00800000     // IO FPGA (8-bit)
+                         7 0 0xfd800000 0x00800000>;   // IO FPGA (32-bit)
+
+               /* flash@0,0 is a mirror of part of the memory in flash@1,0
+               flash@0,0 {
+                       compatible = "gef,ppc9a-firmware-mirror", "cfi-flash";
+                       reg = <0x0 0x0 0x1000000>;
+                       bank-width = <4>;
+                       device-width = <2>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       partition@0 {
+                               label = "firmware";
+                               reg = <0x0 0x1000000>;
+                               read-only;
+                       };
+               };
+               */
+
+               flash@1,0 {
+                       compatible = "gef,ppc9a-paged-flash", "cfi-flash";
+                       reg = <0x1 0x0 0x8000000>;
+                       bank-width = <4>;
+                       device-width = <2>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       partition@0 {
+                               label = "user";
+                               reg = <0x0 0x7800000>;
+                       };
+                       partition@7800000 {
+                               label = "firmware";
+                               reg = <0x7800000 0x800000>;
+                               read-only;
+                       };
+               };
+
+               fpga@4,0 {
+                       compatible = "gef,ppc9a-fpga-regs";
+                       reg = <0x4 0x0 0x40>;
+               };
+
+               wdt@4,2000 {
+                       compatible = "gef,ppc9a-fpga-wdt", "gef,fpga-wdt-1.00",
+                               "gef,fpga-wdt";
+                       reg = <0x4 0x2000 0x8>;
+                       interrupts = <0x1a 0x4>;
+                       interrupt-parent = <&gef_pic>;
+               };
+               /* Second watchdog available, driver currently supports one.
+               wdt@4,2010 {
+                       compatible = "gef,ppc9a-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,ppc9a-fpga-pic", "gef,fpga-pic-1.00";
+                       reg = <0x4 0x4000 0x20>;
+                       interrupts = <0x8
+                                     0x9>;
+                       interrupt-parent = <&mpic>;
+
+               };
+               gef_gpio: gpio@7,14000 {
+                       #gpio-cells = <2>;
+                       compatible = "gef,ppc9a-gpio", "gef,sbc610-gpio";
+                       reg = <0x7 0x14000 0x24>;
+                       gpio-controller;
+               };
+       };
+
+       soc@fef00000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               #interrupt-cells = <2>;
+               compatible = "fsl,mpc8641-soc", "simple-bus";
+               ranges = <0x0 0xfef00000 0x00100000>;
+               reg = <0xfef00000 0x100000>;    // CCSRBAR 1M
+               bus-frequency = <33333333>;
+
+               i2c1: i2c@3000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl-i2c";
+                       reg = <0x3000 0x100>;
+                       interrupts = <0x2b 0x2>;
+                       interrupt-parent = <&mpic>;
+                       dfsrr;
+
+                       hwmon@48 {
+                               compatible = "national,lm92";
+                               reg = <0x48>;
+                       };
+
+                       hwmon@4c {
+                               compatible = "adi,adt7461";
+                               reg = <0x4c>;
+                       };
+
+                       rtc@51 {
+                               compatible = "epson,rx8581";
+                               reg = <0x00000051>;
+                       };
+
+                       eti@6b {
+                               compatible = "dallas,ds1682";
+                               reg = <0x6b>;
+                       };
+               };
+
+               i2c2: i2c@3100 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl-i2c";
+                       reg = <0x3100 0x100>;
+                       interrupts = <0x2b 0x2>;
+                       interrupt-parent = <&mpic>;
+                       dfsrr;
+               };
+
+               dma@21300 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,mpc8641-dma", "fsl,eloplus-dma";
+                       reg = <0x21300 0x4>;
+                       ranges = <0x0 0x21100 0x200>;
+                       cell-index = <0>;
+                       dma-channel@0 {
+                               compatible = "fsl,mpc8641-dma-channel",
+                                          "fsl,eloplus-dma-channel";
+                               reg = <0x0 0x80>;
+                               cell-index = <0>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <20 2>;
+                       };
+                       dma-channel@80 {
+                               compatible = "fsl,mpc8641-dma-channel",
+                                          "fsl,eloplus-dma-channel";
+                               reg = <0x80 0x80>;
+                               cell-index = <1>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <21 2>;
+                       };
+                       dma-channel@100 {
+                               compatible = "fsl,mpc8641-dma-channel",
+                                          "fsl,eloplus-dma-channel";
+                               reg = <0x100 0x80>;
+                               cell-index = <2>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <22 2>;
+                       };
+                       dma-channel@180 {
+                               compatible = "fsl,mpc8641-dma-channel",
+                                          "fsl,eloplus-dma-channel";
+                               reg = <0x180 0x80>;
+                               cell-index = <3>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <23 2>;
+                       };
+               };
+
+               enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       device_type = "network";
+                       model = "eTSEC";
+                       compatible = "gianfar";
+                       reg = <0x24000 0x1000>;
+                       ranges = <0x0 0x24000 0x1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>;
+                       interrupt-parent = <&mpic>;
+                       phy-handle = <&phy0>;
+                       phy-connection-type = "gmii";
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@0 {
+                                       interrupt-parent = <&gef_pic>;
+                                       interrupts = <0x9 0x4>;
+                                       reg = <1>;
+                               };
+                               phy2: ethernet-phy@2 {
+                                       interrupt-parent = <&gef_pic>;
+                                       interrupts = <0x8 0x4>;
+                                       reg = <3>;
+                               };
+                       };
+               };
+
+               enet1: ethernet@26000 {
+                       device_type = "network";
+                       model = "eTSEC";
+                       compatible = "gianfar";
+                       reg = <0x26000 0x1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <0x1f 0x2 0x20 0x2 0x21 0x2>;
+                       interrupt-parent = <&mpic>;
+                       phy-handle = <&phy2>;
+                       phy-connection-type = "gmii";
+               };
+
+               serial0: serial@4500 {
+                       cell-index = <0>;
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0x4500 0x100>;
+                       clock-frequency = <0>;
+                       interrupts = <0x2a 0x2>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               serial1: serial@4600 {
+                       cell-index = <1>;
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0x4600 0x100>;
+                       clock-frequency = <0>;
+                       interrupts = <0x1c 0x2>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               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";
+               };
+
+               global-utilities@e0000 {
+                       compatible = "fsl,mpc8641-guts";
+                       reg = <0xe0000 0x1000>;
+                       fsl,has-rstcr;
+               };
+       };
+
+       pci0: pcie@fef08000 {
+               compatible = "fsl,mpc8641-pcie";
+               device_type = "pci";
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0xfef08000 0x1000>;
+               bus-range = <0x0 0xff>;
+               ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x40000000
+                         0x01000000 0x0 0x00000000 0xfe000000 0x0 0x00400000>;
+               clock-frequency = <33333333>;
+               interrupt-parent = <&mpic>;
+               interrupts = <0x18 0x2>;
+               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+               interrupt-map = <
+                       0x0000 0x0 0x0 0x1 &mpic 0x0 0x1
+                       0x0000 0x0 0x0 0x2 &mpic 0x1 0x1
+                       0x0000 0x0 0x0 0x3 &mpic 0x2 0x1
+                       0x0000 0x0 0x0 0x4 &mpic 0x3 0x1
+               >;
+
+               pcie@0 {
+                       reg = <0 0 0 0 0>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       device_type = "pci";
+                       ranges = <0x02000000 0x0 0x80000000
+                                 0x02000000 0x0 0x80000000
+                                 0x0 0x40000000
+
+                                 0x01000000 0x0 0x00000000
+                                 0x01000000 0x0 0x00000000
+                                 0x0 0x00400000>;
+               };
+       };
+};
diff --git a/arch/powerpc/boot/dts/gef_sbc310.dts b/arch/powerpc/boot/dts/gef_sbc310.dts
new file mode 100644 (file)
index 0000000..1569117
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * GE Fanuc SBC310 Device Tree Source
+ *
+ * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, 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.
+ *
+ * Based on: SBS CM6 Device Tree Source
+ * Copyright 2007 SBS Technologies GmbH & Co. KG
+ * And: mpc8641_hpcn.dts (MPC8641 HPCN Device Tree Source)
+ * Copyright 2006 Freescale Semiconductor Inc.
+ */
+
+/*
+ * Compiled with dtc -I dts -O dtb -o gef_sbc310.dtb gef_sbc310.dts
+ */
+
+/dts-v1/;
+
+/ {
+       model = "GEF_SBC310";
+       compatible = "gef,sbc310";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       aliases {
+               ethernet0 = &enet0;
+               ethernet1 = &enet1;
+               serial0 = &serial0;
+               serial1 = &serial1;
+               pci0 = &pci0;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,8641@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <32>;       // 32 bytes
+                       i-cache-line-size = <32>;       // 32 bytes
+                       d-cache-size = <32768>;         // L1, 32K
+                       i-cache-size = <32768>;         // L1, 32K
+                       timebase-frequency = <0>;       // From uboot
+                       bus-frequency = <0>;            // From uboot
+                       clock-frequency = <0>;          // From uboot
+               };
+               PowerPC,8641@1 {
+                       device_type = "cpu";
+                       reg = <1>;
+                       d-cache-line-size = <32>;       // 32 bytes
+                       i-cache-line-size = <32>;       // 32 bytes
+                       d-cache-size = <32768>;         // L1, 32K
+                       i-cache-size = <32768>;         // L1, 32K
+                       timebase-frequency = <0>;       // From uboot
+                       bus-frequency = <0>;            // From uboot
+                       clock-frequency = <0>;          // From uboot
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x0 0x40000000>; // set by uboot
+       };
+
+       localbus@fef05000 {
+               #address-cells = <2>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8641-localbus", "simple-bus";
+               reg = <0xfef05000 0x1000>;
+               interrupts = <19 2>;
+               interrupt-parent = <&mpic>;
+
+               ranges = <0 0 0xff000000 0x01000000     // 16MB Boot flash
+                         1 0 0xe0000000 0x08000000     // Paged Flash 0
+                         2 0 0xe8000000 0x08000000     // Paged Flash 1
+                         3 0 0xfc100000 0x00020000     // NVRAM
+                         4 0 0xfc000000 0x00010000>;   // FPGA
+
+               /* 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>;
+                       bank-width = <2>;
+                       device-width = <2>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       partition@0 {
+                               label = "firmware";
+                               reg = <0x00000000 0x01000000>;
+                               read-only;
+                       };
+               };
+               */
+
+               flash@1,0 {
+                       compatible = "cfi-flash";
+                       reg = <1 0 0x8000000>;
+                       bank-width = <2>;
+                       device-width = <2>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       partition@0 {
+                               label = "user";
+                               reg = <0x00000000 0x07800000>;
+                       };
+                       partition@7800000 {
+                               label = "firmware";
+                               reg = <0x07800000 0x00800000>;
+                               read-only;
+                       };
+               };
+
+               fpga@4,0 {
+                       compatible = "gef,fpga-regs";
+                       reg = <0x4 0x0 0x40>;
+               };
+
+               wdt@4,2000 {
+                       #interrupt-cells = <2>;
+                       device_type = "watchdog";
+                       compatible = "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";
+                       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";
+                       reg = <0x4 0x4000 0x20>;
+                       interrupts = <0x8
+                                     0x9>;
+                       interrupt-parent = <&mpic>;
+
+               };
+               gef_gpio: gpio@4,8000 {
+                       #gpio-cells = <2>;
+                       compatible = "gef,sbc310-gpio";
+                       reg = <0x4 0x8000 0x24>;
+                       gpio-controller;
+               };
+       };
+
+       soc@fef00000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               #interrupt-cells = <2>;
+               device_type = "soc";
+               compatible = "simple-bus";
+               ranges = <0x0 0xfef00000 0x00100000>;
+               reg = <0xfef00000 0x100000>;    // CCSRBAR 1M
+               bus-frequency = <33333333>;
+
+               i2c1: i2c@3000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl-i2c";
+                       reg = <0x3000 0x100>;
+                       interrupts = <0x2b 0x2>;
+                       interrupt-parent = <&mpic>;
+                       dfsrr;
+
+                       rtc@51 {
+                               compatible = "epson,rx8581";
+                               reg = <0x00000051>;
+                       };
+               };
+
+               i2c2: i2c@3100 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl-i2c";
+                       reg = <0x3100 0x100>;
+                       interrupts = <0x2b 0x2>;
+                       interrupt-parent = <&mpic>;
+                       dfsrr;
+
+                       hwmon@48 {
+                               compatible = "national,lm92";
+                               reg = <0x48>;
+                       };
+
+                       hwmon@4c {
+                               compatible = "adi,adt7461";
+                               reg = <0x4c>;
+                       };
+
+                       eti@6b {
+                               compatible = "dallas,ds1682";
+                               reg = <0x6b>;
+                       };
+               };
+
+               dma@21300 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,mpc8641-dma", "fsl,eloplus-dma";
+                       reg = <0x21300 0x4>;
+                       ranges = <0x0 0x21100 0x200>;
+                       cell-index = <0>;
+                       dma-channel@0 {
+                               compatible = "fsl,mpc8641-dma-channel",
+                                          "fsl,eloplus-dma-channel";
+                               reg = <0x0 0x80>;
+                               cell-index = <0>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <20 2>;
+                       };
+                       dma-channel@80 {
+                               compatible = "fsl,mpc8641-dma-channel",
+                                          "fsl,eloplus-dma-channel";
+                               reg = <0x80 0x80>;
+                               cell-index = <1>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <21 2>;
+                       };
+                       dma-channel@100 {
+                               compatible = "fsl,mpc8641-dma-channel",
+                                          "fsl,eloplus-dma-channel";
+                               reg = <0x100 0x80>;
+                               cell-index = <2>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <22 2>;
+                       };
+                       dma-channel@180 {
+                               compatible = "fsl,mpc8641-dma-channel",
+                                          "fsl,eloplus-dma-channel";
+                               reg = <0x180 0x80>;
+                               cell-index = <3>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <23 2>;
+                       };
+               };
+
+               enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       device_type = "network";
+                       model = "eTSEC";
+                       compatible = "gianfar";
+                       reg = <0x24000 0x1000>;
+                       ranges = <0x0 0x24000 0x1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>;
+                       interrupt-parent = <&mpic>;
+                       phy-handle = <&phy0>;
+                       phy-connection-type = "gmii";
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@0 {
+                                       interrupt-parent = <&gef_pic>;
+                                       interrupts = <0x9 0x4>;
+                                       reg = <1>;
+                               };
+                               phy2: ethernet-phy@2 {
+                                       interrupt-parent = <&gef_pic>;
+                                       interrupts = <0x8 0x4>;
+                                       reg = <3>;
+                               };
+                       };
+               };
+
+               enet1: ethernet@26000 {
+                       device_type = "network";
+                       model = "eTSEC";
+                       compatible = "gianfar";
+                       reg = <0x26000 0x1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <0x1f 0x2 0x20 0x2 0x21 0x2>;
+                       interrupt-parent = <&mpic>;
+                       phy-handle = <&phy2>;
+                       phy-connection-type = "gmii";
+               };
+
+               serial0: serial@4500 {
+                       cell-index = <0>;
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0x4500 0x100>;
+                       clock-frequency = <0>;
+                       interrupts = <0x2a 0x2>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               serial1: serial@4600 {
+                       cell-index = <1>;
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0x4600 0x100>;
+                       clock-frequency = <0>;
+                       interrupts = <0x1c 0x2>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               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";
+               };
+
+               global-utilities@e0000 {
+                       compatible = "fsl,mpc8641-guts";
+                       reg = <0xe0000 0x1000>;
+                       fsl,has-rstcr;
+               };
+       };
+
+       pci0: pcie@fef08000 {
+               compatible = "fsl,mpc8641-pcie";
+               device_type = "pci";
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0xfef08000 0x1000>;
+               bus-range = <0x0 0xff>;
+               ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x40000000
+                         0x01000000 0x0 0x00000000 0xfe000000 0x0 0x00400000>;
+               clock-frequency = <33333333>;
+               interrupt-parent = <&mpic>;
+               interrupts = <0x18 0x2>;
+               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+               interrupt-map = <
+                       0x0000 0x0 0x0 0x1 &mpic 0x0 0x2
+                       0x0000 0x0 0x0 0x2 &mpic 0x1 0x2
+                       0x0000 0x0 0x0 0x3 &mpic 0x2 0x2
+                       0x0000 0x0 0x0 0x4 &mpic 0x3 0x2
+               >;
+
+               pcie@0 {
+                       reg = <0 0 0 0 0>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       device_type = "pci";
+                       ranges = <0x02000000 0x0 0x80000000
+                                 0x02000000 0x0 0x80000000
+                                 0x0 0x40000000
+
+                                 0x01000000 0x0 0x00000000
+                                 0x01000000 0x0 0x00000000
+                                 0x0 0x00400000>;
+               };
+       };
+};
index e78c355c7bac8974ea2c84e55856499b260bbbc7..6582dbd36da7ff5b99de958f7bec0841ca7270db 100644 (file)
@@ -71,7 +71,7 @@
                #address-cells = <2>;
                #size-cells = <1>;
                compatible = "fsl,mpc8641-localbus", "simple-bus";
-               reg = <0xf8005000 0x1000>;
+               reg = <0xfef05000 0x1000>;
                interrupts = <19 2>;
                interrupt-parent = <&mpic>;
 
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy0: ethernet-phy@0 {
-                               interrupt-parent = <&gef_pic>;
-                               interrupts = <0x9 0x4>;
-                               reg = <1>;
-                       };
-                       phy2: ethernet-phy@2 {
-                               interrupt-parent = <&gef_pic>;
-                               interrupts = <0x8 0x4>;
-                               reg = <3>;
-                       };
-               };
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        device_type = "network";
                        model = "eTSEC";
                        compatible = "gianfar";
                        reg = <0x24000 0x1000>;
+                       ranges = <0x0 0x24000 0x1000>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>;
                        interrupt-parent = <&mpic>;
                        phy-handle = <&phy0>;
                        phy-connection-type = "gmii";
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@0 {
+                                       interrupt-parent = <&gef_pic>;
+                                       interrupts = <0x9 0x4>;
+                                       reg = <1>;
+                               };
+                               phy2: ethernet-phy@2 {
+                                       interrupt-parent = <&gef_pic>;
+                                       interrupts = <0x8 0x4>;
+                                       reg = <3>;
+                               };
+                       };
                };
 
                enet1: ethernet@26000 {
index 3bfff47418db434c1520637b557d7812ad62b9ae..308fe7c29deaf662379baa3e1106a1b82b045cea 100644 (file)
                        };
                };
 
-               mdio@24520 {                                    /* For TSECs */
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       PHY1: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               reg = <0x1>;
-                               device_type = "ethernet-phy";
-                       };
-
-                       PHY2: ethernet-phy@2 {
-                               interrupt-parent = <&mpic>;
-                               reg = <0x2>;
-                               device_type = "ethernet-phy";
-                       };
-
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        device_type = "network";
                        model = "TSEC";
                        compatible = "gianfar";
                        reg = <0x24000 0x1000>;
+                       ranges = <0x0 0x24000 0x1000>;
                        /* Mac address filled in by bootwrapper */
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi0>;
                        phy-handle = <&PHY1>;
+
+                       mdio@520 {                                      /* For TSECs */
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               PHY1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       reg = <0x1>;
+                                       device_type = "ethernet-phy";
+                               };
+
+                               PHY2: ethernet-phy@2 {
+                                       interrupt-parent = <&mpic>;
+                                       reg = <0x2>;
+                                       device_type = "ethernet-phy";
+                               };
+
+                               tbi0: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
                };
 
                enet1: ethernet@25000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        device_type = "network";
                        model = "TSEC";
                        compatible = "gianfar";
                        reg = <0x25000 0x1000>;
+                       ranges = <0x0 0x25000 0x1000>;
                        /* Mac address filled in by bootwrapper */
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <0x23 0x2 0x24 0x2 0x28 0x2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi1>;
                        phy-handle = <&PHY2>;
+
+                       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";
+                               };
+                       };
                };
 
                mpic: pic@40000 {
index 3f7a5dce8de0bc397bde3177927cd65667118f1f..de30b3f9eb264b60582a9836c873dd2a555c2d5d 100644 (file)
@@ -17,6 +17,7 @@
        compatible = "fsl,lite5200";
        #address-cells = <1>;
        #size-cells = <1>;
+       interrupt-parent = <&mpc5200_pic>;
 
        cpus {
                #address-cells = <1>;
                        // 5200 interrupts are encoded into two levels;
                        interrupt-controller;
                        #interrupt-cells = <3>;
-                       device_type = "interrupt-controller";
                        compatible = "fsl,mpc5200-pic";
                        reg = <0x500 0x80>;
                };
 
                timer@600 {     // General Purpose Timer
                        compatible = "fsl,mpc5200-gpt";
-                       cell-index = <0>;
                        reg = <0x600 0x10>;
                        interrupts = <1 9 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        fsl,has-wdt;
                };
 
                timer@610 {     // General Purpose Timer
                        compatible = "fsl,mpc5200-gpt";
-                       cell-index = <1>;
                        reg = <0x610 0x10>;
                        interrupts = <1 10 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@620 {     // General Purpose Timer
                        compatible = "fsl,mpc5200-gpt";
-                       cell-index = <2>;
                        reg = <0x620 0x10>;
                        interrupts = <1 11 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@630 {     // General Purpose Timer
                        compatible = "fsl,mpc5200-gpt";
-                       cell-index = <3>;
                        reg = <0x630 0x10>;
                        interrupts = <1 12 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@640 {     // General Purpose Timer
                        compatible = "fsl,mpc5200-gpt";
-                       cell-index = <4>;
                        reg = <0x640 0x10>;
                        interrupts = <1 13 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@650 {     // General Purpose Timer
                        compatible = "fsl,mpc5200-gpt";
-                       cell-index = <5>;
                        reg = <0x650 0x10>;
                        interrupts = <1 14 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@660 {     // General Purpose Timer
                        compatible = "fsl,mpc5200-gpt";
-                       cell-index = <6>;
                        reg = <0x660 0x10>;
                        interrupts = <1 15 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@670 {     // General Purpose Timer
                        compatible = "fsl,mpc5200-gpt";
-                       cell-index = <7>;
                        reg = <0x670 0x10>;
                        interrupts = <1 16 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                rtc@800 {       // Real time clock
                        compatible = "fsl,mpc5200-rtc";
                        reg = <0x800 0x100>;
                        interrupts = <1 5 0 1 6 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                can@900 {
                        compatible = "fsl,mpc5200-mscan";
-                       cell-index = <0>;
                        interrupts = <2 17 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        reg = <0x900 0x80>;
                };
 
                can@980 {
                        compatible = "fsl,mpc5200-mscan";
-                       cell-index = <1>;
                        interrupts = <2 18 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        reg = <0x980 0x80>;
                };
 
                        compatible = "fsl,mpc5200-gpio";
                        reg = <0xb00 0x40>;
                        interrupts = <1 7 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                gpio@c00 {
                        compatible = "fsl,mpc5200-gpio-wkup";
                        reg = <0xc00 0x40>;
                        interrupts = <1 8 0 0 3 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                spi@f00 {
                        compatible = "fsl,mpc5200-spi";
                        reg = <0xf00 0x20>;
                        interrupts = <2 13 0 2 14 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                usb@1000 {
                        compatible = "fsl,mpc5200-ohci","ohci-be";
                        reg = <0x1000 0xff>;
                        interrupts = <2 6 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                dma-controller@1200 {
-                       device_type = "dma-controller";
                        compatible = "fsl,mpc5200-bestcomm";
                        reg = <0x1200 0x80>;
                        interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
                                      3 4 0  3 5 0  3 6 0  3 7 0
                                      3 8 0  3 9 0  3 10 0  3 11 0
                                      3 12 0  3 13 0  3 14 0  3 15 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                xlb@1f00 {
                };
 
                serial@2000 {           // PSC1
-                       device_type = "serial";
                        compatible = "fsl,mpc5200-psc-uart";
-                       port-number = <0>;  // Logical port assignment
                        cell-index = <0>;
                        reg = <0x2000 0x100>;
                        interrupts = <2 1 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                // PSC2 in ac97 mode example
                //      cell-index = <1>;
                //      reg = <0x2200 0x100>;
                //      interrupts = <2 2 0>;
-               //      interrupt-parent = <&mpc5200_pic>;
                //};
 
                // PSC3 in CODEC mode example
                //      cell-index = <2>;
                //      reg = <0x2400 0x100>;
                //      interrupts = <2 3 0>;
-               //      interrupt-parent = <&mpc5200_pic>;
                //};
 
                // PSC4 in uart mode example
                //serial@2600 {         // PSC4
-               //      device_type = "serial";
                //      compatible = "fsl,mpc5200-psc-uart";
                //      cell-index = <3>;
                //      reg = <0x2600 0x100>;
                //      interrupts = <2 11 0>;
-               //      interrupt-parent = <&mpc5200_pic>;
                //};
 
                // PSC5 in uart mode example
                //serial@2800 {         // PSC5
-               //      device_type = "serial";
                //      compatible = "fsl,mpc5200-psc-uart";
                //      cell-index = <4>;
                //      reg = <0x2800 0x100>;
                //      interrupts = <2 12 0>;
-               //      interrupt-parent = <&mpc5200_pic>;
                //};
 
                // PSC6 in spi mode example
                //      cell-index = <5>;
                //      reg = <0x2c00 0x100>;
                //      interrupts = <2 4 0>;
-               //      interrupt-parent = <&mpc5200_pic>;
                //};
 
                ethernet@3000 {
-                       device_type = "network";
                        compatible = "fsl,mpc5200-fec";
                        reg = <0x3000 0x400>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <2 5 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        phy-handle = <&phy0>;
                };
 
                        compatible = "fsl,mpc5200-mdio";
                        reg = <0x3000 0x400>;   // fec range, since we need to setup fec interrupts
                        interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
-                       interrupt-parent = <&mpc5200_pic>;
 
                        phy0: ethernet-phy@1 {
-                               device_type = "ethernet-phy";
                                reg = <1>;
                        };
                };
 
                ata@3a00 {
-                       device_type = "ata";
                        compatible = "fsl,mpc5200-ata";
                        reg = <0x3a00 0x100>;
                        interrupts = <2 7 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                i2c@3d00 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        compatible = "fsl,mpc5200-i2c","fsl-i2c";
-                       cell-index = <0>;
                        reg = <0x3d00 0x40>;
                        interrupts = <2 15 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        fsl5200-clocking;
                };
 
                        #address-cells = <1>;
                        #size-cells = <0>;
                        compatible = "fsl,mpc5200-i2c","fsl-i2c";
-                       cell-index = <1>;
                        reg = <0x3d40 0x40>;
                        interrupts = <2 16 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        fsl5200-clocking;
                };
                sram@8000 {
-                       compatible = "fsl,mpc5200-sram","sram";
+                       compatible = "fsl,mpc5200-sram";
                        reg = <0x8000 0x4000>;
                };
        };
                                 0xc000 0 0 4 &mpc5200_pic 0 0 3>;
                clock-frequency = <0>; // From boot loader
                interrupts = <2 8 0 2 9 0 2 10 0>;
-               interrupt-parent = <&mpc5200_pic>;
                bus-range = <0 0>;
                ranges = <0x42000000 0 0x80000000 0x80000000 0 0x20000000
                          0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
index 63e3bb48e843980953aa844b64862e7910f4a3f6..c63e3566479eaf2995d8cea596edcfb14c687f0e 100644 (file)
@@ -17,6 +17,7 @@
        compatible = "fsl,lite5200b";
        #address-cells = <1>;
        #size-cells = <1>;
+       interrupt-parent = <&mpc5200_pic>;
 
        cpus {
                #address-cells = <1>;
                        // 5200 interrupts are encoded into two levels;
                        interrupt-controller;
                        #interrupt-cells = <3>;
-                       device_type = "interrupt-controller";
                        compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
                        reg = <0x500 0x80>;
                };
 
                timer@600 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       cell-index = <0>;
                        reg = <0x600 0x10>;
                        interrupts = <1 9 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        fsl,has-wdt;
                };
 
                timer@610 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       cell-index = <1>;
                        reg = <0x610 0x10>;
                        interrupts = <1 10 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@620 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       cell-index = <2>;
                        reg = <0x620 0x10>;
                        interrupts = <1 11 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@630 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       cell-index = <3>;
                        reg = <0x630 0x10>;
                        interrupts = <1 12 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@640 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       cell-index = <4>;
                        reg = <0x640 0x10>;
                        interrupts = <1 13 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@650 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       cell-index = <5>;
                        reg = <0x650 0x10>;
                        interrupts = <1 14 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@660 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       cell-index = <6>;
                        reg = <0x660 0x10>;
                        interrupts = <1 15 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@670 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       cell-index = <7>;
                        reg = <0x670 0x10>;
                        interrupts = <1 16 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                rtc@800 {       // Real time clock
                        compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc";
                        reg = <0x800 0x100>;
                        interrupts = <1 5 0 1 6 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                can@900 {
                        compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
-                       cell-index = <0>;
                        interrupts = <2 17 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        reg = <0x900 0x80>;
                };
 
                can@980 {
                        compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
-                       cell-index = <1>;
                        interrupts = <2 18 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        reg = <0x980 0x80>;
                };
 
-               gpio@b00 {
+               gpio_simple: gpio@b00 {
                        compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
                        reg = <0xb00 0x40>;
                        interrupts = <1 7 0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
                };
 
-               gpio@c00 {
+               gpio_wkup: gpio@c00 {
                        compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
                        reg = <0xc00 0x40>;
                        interrupts = <1 8 0 0 3 0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
                };
 
                spi@f00 {
                        compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
                        reg = <0xf00 0x20>;
                        interrupts = <2 13 0 2 14 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                usb@1000 {
                        compatible = "fsl,mpc5200b-ohci","fsl,mpc5200-ohci","ohci-be";
                        reg = <0x1000 0xff>;
                        interrupts = <2 6 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                dma-controller@1200 {
-                       device_type = "dma-controller";
                        compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
                        reg = <0x1200 0x80>;
                        interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
                                      3 4 0  3 5 0  3 6 0  3 7 0
                                      3 8 0  3 9 0  3 10 0  3 11 0
                                      3 12 0  3 13 0  3 14 0  3 15 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                xlb@1f00 {
                };
 
                serial@2000 {           // PSC1
-                       device_type = "serial";
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       port-number = <0>;  // Logical port assignment
                        cell-index = <0>;
                        reg = <0x2000 0x100>;
                        interrupts = <2 1 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                // PSC2 in ac97 mode example
                //      cell-index = <1>;
                //      reg = <0x2200 0x100>;
                //      interrupts = <2 2 0>;
-               //      interrupt-parent = <&mpc5200_pic>;
                //};
 
                // PSC3 in CODEC mode example
                //      cell-index = <2>;
                //      reg = <0x2400 0x100>;
                //      interrupts = <2 3 0>;
-               //      interrupt-parent = <&mpc5200_pic>;
                //};
 
                // PSC4 in uart mode example
                //serial@2600 {         // PSC4
-               //      device_type = "serial";
                //      compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
                //      cell-index = <3>;
                //      reg = <0x2600 0x100>;
                //      interrupts = <2 11 0>;
-               //      interrupt-parent = <&mpc5200_pic>;
                //};
 
                // PSC5 in uart mode example
                //serial@2800 {         // PSC5
-               //      device_type = "serial";
                //      compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
                //      cell-index = <4>;
                //      reg = <0x2800 0x100>;
                //      interrupts = <2 12 0>;
-               //      interrupt-parent = <&mpc5200_pic>;
                //};
 
                // PSC6 in spi mode example
                //      cell-index = <5>;
                //      reg = <0x2c00 0x100>;
                //      interrupts = <2 4 0>;
-               //      interrupt-parent = <&mpc5200_pic>;
                //};
 
                ethernet@3000 {
-                       device_type = "network";
                        compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
                        reg = <0x3000 0x400>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <2 5 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        phy-handle = <&phy0>;
                };
 
                mdio@3000 {
                        #address-cells = <1>;
                        #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-mdio", "fsl,mpc5200-mdio";
+                       compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
                        reg = <0x3000 0x400>;   // fec range, since we need to setup fec interrupts
                        interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
-                       interrupt-parent = <&mpc5200_pic>;
 
                        phy0: ethernet-phy@0 {
-                               device_type = "ethernet-phy";
                                reg = <0>;
                        };
                };
 
                ata@3a00 {
-                       device_type = "ata";
                        compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
                        reg = <0x3a00 0x100>;
                        interrupts = <2 7 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                i2c@3d00 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       cell-index = <0>;
                        reg = <0x3d00 0x40>;
                        interrupts = <2 15 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        fsl5200-clocking;
                };
 
                        #address-cells = <1>;
                        #size-cells = <0>;
                        compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       cell-index = <1>;
                        reg = <0x3d40 0x40>;
                        interrupts = <2 16 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        fsl5200-clocking;
                };
+
                sram@8000 {
-                       compatible = "fsl,mpc5200b-sram","fsl,mpc5200-sram","sram";
+                       compatible = "fsl,mpc5200b-sram","fsl,mpc5200-sram";
                        reg = <0x8000 0x4000>;
                };
        };
                                 0xc800 0 0 4 &mpc5200_pic 0 0 3>;
                clock-frequency = <0>; // From boot loader
                interrupts = <2 8 0 2 9 0 2 10 0>;
-               interrupt-parent = <&mpc5200_pic>;
                bus-range = <0 0>;
                ranges = <0x42000000 0 0x80000000 0x80000000 0 0x20000000
                          0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
diff --git a/arch/powerpc/boot/dts/media5200.dts b/arch/powerpc/boot/dts/media5200.dts
new file mode 100644 (file)
index 0000000..e297d8b
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * Freescale Media5200 board Device Tree Source
+ *
+ * Copyright 2009 Secret Lab Technologies Ltd.
+ * Grant Likely <grant.likely@secretlab.ca>
+ * Steven Cavanagh <scavanagh@secretlab.ca>
+ *
+ * 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,media5200";
+       compatible = "fsl,media5200";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       interrupt-parent = <&mpc5200_pic>;
+
+       aliases {
+               console = &console;
+               ethernet0 = &eth0;
+       };
+
+       chosen {
+               linux,stdout-path = &console;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,5200@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <32>;
+                       i-cache-line-size = <32>;
+                       d-cache-size = <0x4000>;                // L1, 16K
+                       i-cache-size = <0x4000>;                // L1, 16K
+                       timebase-frequency = <33000000>;        // 33 MHz, these were configured by U-Boot
+                       bus-frequency = <132000000>;            // 132 MHz
+                       clock-frequency = <396000000>;          // 396 MHz
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x00000000 0x08000000>;  // 128MB RAM
+       };
+
+       soc@f0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc5200b-immr";
+               ranges = <0 0xf0000000 0x0000c000>;
+               reg = <0xf0000000 0x00000100>;
+               bus-frequency = <132000000>;// 132 MHz
+               system-frequency = <0>;         // from bootloader
+
+               cdm@200 {
+                       compatible = "fsl,mpc5200b-cdm","fsl,mpc5200-cdm";
+                       reg = <0x200 0x38>;
+               };
+
+               mpc5200_pic: interrupt-controller@500 {
+                       // 5200 interrupts are encoded into two levels;
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+                       compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
+                       reg = <0x500 0x80>;
+               };
+
+               timer@600 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x600 0x10>;
+                       interrupts = <1 9 0>;
+                       fsl,has-wdt;
+               };
+
+               timer@610 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x610 0x10>;
+                       interrupts = <1 10 0>;
+               };
+
+               timer@620 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x620 0x10>;
+                       interrupts = <1 11 0>;
+               };
+
+               timer@630 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x630 0x10>;
+                       interrupts = <1 12 0>;
+               };
+
+               timer@640 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x640 0x10>;
+                       interrupts = <1 13 0>;
+               };
+
+               timer@650 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x650 0x10>;
+                       interrupts = <1 14 0>;
+               };
+
+               timer@660 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x660 0x10>;
+                       interrupts = <1 15 0>;
+               };
+
+               timer@670 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x670 0x10>;
+                       interrupts = <1 16 0>;
+               };
+
+               rtc@800 {       // Real time clock
+                       compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc";
+                       reg = <0x800 0x100>;
+                       interrupts = <1 5 0 1 6 0>;
+               };
+
+               can@900 {
+                       compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
+                       interrupts = <2 17 0>;
+                       reg = <0x900 0x80>;
+               };
+
+               can@980 {
+                       compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
+                       interrupts = <2 18 0>;
+                       reg = <0x980 0x80>;
+               };
+
+               gpio_simple: gpio@b00 {
+                       compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
+                       reg = <0xb00 0x40>;
+                       interrupts = <1 7 0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpio_wkup: gpio@c00 {
+                       compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
+                       reg = <0xc00 0x40>;
+                       interrupts = <1 8 0 0 3 0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               spi@f00 {
+                       compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
+                       reg = <0xf00 0x20>;
+                       interrupts = <2 13 0 2 14 0>;
+               };
+
+               usb@1000 {
+                       compatible = "fsl,mpc5200b-ohci","fsl,mpc5200-ohci","ohci-be";
+                       reg = <0x1000 0x100>;
+                       interrupts = <2 6 0>;
+               };
+
+               dma-controller@1200 {
+                       compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
+                       reg = <0x1200 0x80>;
+                       interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
+                                     3 4 0  3 5 0  3 6 0  3 7 0
+                                     3 8 0  3 9 0  3 10 0  3 11 0
+                                     3 12 0  3 13 0  3 14 0  3 15 0>;
+               };
+
+               xlb@1f00 {
+                       compatible = "fsl,mpc5200b-xlb","fsl,mpc5200-xlb";
+                       reg = <0x1f00 0x100>;
+               };
+
+               // PSC6 in uart mode
+               console: serial@2c00 {          // PSC6
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+                       cell-index = <5>;
+                       port-number = <0>;  // Logical port assignment
+                       reg = <0x2c00 0x100>;
+                       interrupts = <2 4 0>;
+               };
+
+               eth0: ethernet@3000 {
+                       compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
+                       reg = <0x3000 0x400>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <2 5 0>;
+                       phy-handle = <&phy0>;
+               };
+
+               mdio@3000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
+                       reg = <0x3000 0x400>;   // fec range, since we need to setup fec interrupts
+                       interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
+
+                       phy0: ethernet-phy@0 {
+                               reg = <0>;
+                       };
+               };
+
+               ata@3a00 {
+                       compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
+                       reg = <0x3a00 0x100>;
+                       interrupts = <2 7 0>;
+               };
+
+               i2c@3d00 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
+                       reg = <0x3d00 0x40>;
+                       interrupts = <2 15 0>;
+                       fsl5200-clocking;
+               };
+
+               i2c@3d40 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
+                       reg = <0x3d40 0x40>;
+                       interrupts = <2 16 0>;
+                       fsl5200-clocking;
+               };
+
+               sram@8000 {
+                       compatible = "fsl,mpc5200b-sram","fsl,mpc5200-sram";
+                       reg = <0x8000 0x4000>;
+               };
+       };
+
+       pci@f0000d00 {
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               device_type = "pci";
+               compatible = "fsl,mpc5200b-pci","fsl,mpc5200-pci";
+               reg = <0xf0000d00 0x100>;
+               interrupt-map-mask = <0xf800 0 0 7>;
+               interrupt-map = <0xc000 0 0 1 &media5200_fpga 0 2 // 1st slot
+                                0xc000 0 0 2 &media5200_fpga 0 3
+                                0xc000 0 0 3 &media5200_fpga 0 4
+                                0xc000 0 0 4 &media5200_fpga 0 5
+
+                                0xc800 0 0 1 &media5200_fpga 0 3 // 2nd slot
+                                0xc800 0 0 2 &media5200_fpga 0 4
+                                0xc800 0 0 3 &media5200_fpga 0 5
+                                0xc800 0 0 4 &media5200_fpga 0 2
+
+                                0xd000 0 0 1 &media5200_fpga 0 4 // miniPCI
+                                0xd000 0 0 2 &media5200_fpga 0 5
+
+                                0xe000 0 0 1 &media5200_fpga 0 5 // CoralIP
+                               >;
+               clock-frequency = <0>; // From boot loader
+               interrupts = <2 8 0 2 9 0 2 10 0>;
+               interrupt-parent = <&mpc5200_pic>;
+               bus-range = <0 0>;
+               ranges = <0x42000000 0 0x80000000 0x80000000 0 0x20000000
+                         0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
+                         0x01000000 0 0x00000000 0xb0000000 0 0x01000000>;
+       };
+
+       localbus {
+               compatible = "fsl,mpc5200b-lpb","simple-bus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+
+               ranges = < 0 0 0xfc000000 0x02000000
+                          1 0 0xfe000000 0x02000000
+                          2 0 0xf0010000 0x00010000
+                          3 0 0xf0020000 0x00010000 >;
+
+               flash@0,0 {
+                       compatible = "amd,am29lv28ml", "cfi-flash";
+                       reg = <0 0x0 0x2000000>;                // 32 MB
+                       bank-width = <4>;                       // Width in bytes of the flash bank
+                       device-width = <2>;                     // Two devices on each bank
+               };
+
+               flash@1,0 {
+                       compatible = "amd,am29lv28ml", "cfi-flash";
+                       reg = <1 0 0x2000000>;                  // 32 MB
+                       bank-width = <4>;                       // Width in bytes of the flash bank
+                       device-width = <2>;                     // Two devices on each bank
+               };
+
+               media5200_fpga: fpga@2,0 {
+                       compatible = "fsl,media5200-fpga";
+                       interrupt-controller;
+                       #interrupt-cells = <2>; // 0:bank 1:id; no type field
+                       reg = <2 0 0x10000>;
+
+                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <0 0 3     // IRQ bank 0
+                                     1 1 3>;   // IRQ bank 1
+               };
+
+               uart@3,0 {
+                       compatible = "ti,tl16c752bpt";
+                       reg = <3 0 0x10000>;
+                       interrupt-parent = <&media5200_fpga>;
+                       interrupts = <0 0  0 1>; // 2 irqs
+               };
+       };
+};
index 52ba6f98b27311d351c114118cc4333a06474396..7be8ca0386766aa6b31a5f0a1ae7fa6eec4c291b 100644 (file)
@@ -17,6 +17,7 @@
        compatible = "promess,motionpro";
        #address-cells = <1>;
        #size-cells = <1>;
+       interrupt-parent = <&mpc5200_pic>;
 
        cpus {
                #address-cells = <1>;
@@ -66,7 +67,6 @@
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        reg = <0x600 0x10>;
                        interrupts = <1 9 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        fsl,has-wdt;
                };
 
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        reg = <0x610 0x10>;
                        interrupts = <1 10 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@620 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        reg = <0x620 0x10>;
                        interrupts = <1 11 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@630 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        reg = <0x630 0x10>;
                        interrupts = <1 12 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@640 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        reg = <0x640 0x10>;
                        interrupts = <1 13 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                timer@650 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        reg = <0x650 0x10>;
                        interrupts = <1 14 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                motionpro-led@660 {     // Motion-PRO status LED
                        label = "motionpro-statusled";
                        reg = <0x660 0x10>;
                        interrupts = <1 15 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        blink-delay = <100>; // 100 msec
                };
 
                        label = "motionpro-readyled";
                        reg = <0x670 0x10>;
                        interrupts = <1 16 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                rtc@800 {       // Real time clock
                        compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc";
                        reg = <0x800 0x100>;
                        interrupts = <1 5 0 1 6 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                can@980 {
                        compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
                        interrupts = <2 18 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        reg = <0x980 0x80>;
                };
 
-               gpio@b00 {
+               gpio_simple: gpio@b00 {
                        compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
                        reg = <0xb00 0x40>;
                        interrupts = <1 7 0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
                };
 
-               gpio@c00 {
+               gpio_wkup: gpio@c00 {
                        compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
                        reg = <0xc00 0x40>;
                        interrupts = <1 8 0 0 3 0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
                };
 
                spi@f00 {
                        compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
                        reg = <0xf00 0x20>;
                        interrupts = <2 13 0 2 14 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                usb@1000 {
                        compatible = "fsl,mpc5200b-ohci","fsl,mpc5200-ohci","ohci-be";
                        reg = <0x1000 0xff>;
                        interrupts = <2 6 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                dma-controller@1200 {
                                      3 4 0  3 5 0  3 6 0  3 7 0
                                      3 8 0  3 9 0  3 10 0  3 11 0
                                      3 12 0  3 13 0  3 14 0  3 15 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                xlb@1f00 {
                };
 
                serial@2000 {           // PSC1
-                       device_type = "serial";
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       port-number = <0>;  // Logical port assignment
                        reg = <0x2000 0x100>;
                        interrupts = <2 1 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                // PSC2 in spi master mode 
                        cell-index = <1>;
                        reg = <0x2200 0x100>;
                        interrupts = <2 2 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                // PSC5 in uart mode
                serial@2800 {           // PSC5
-                       device_type = "serial";
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       port-number = <4>;  // Logical port assignment
                        reg = <0x2800 0x100>;
                        interrupts = <2 12 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                ethernet@3000 {
-                       device_type = "network";
                        compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
                        reg = <0x3000 0x400>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <2 5 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        phy-handle = <&phy0>;
                };
 
                        compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
                        reg = <0x3000 0x400>;       // fec range, since we need to setup fec interrupts
                        interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
-                       interrupt-parent = <&mpc5200_pic>;
 
                        phy0: ethernet-phy@2 {
-                               device_type = "ethernet-phy";
                                reg = <2>;
                        };
                };
                        compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
                        reg = <0x3a00 0x100>;
                        interrupts = <2 7 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                i2c@3d40 {
                        compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
                        reg = <0x3d40 0x40>;
                        interrupts = <2 16 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        fsl5200-clocking;
 
                        rtc@68 {
                };
        };
 
-       lpb {
-               compatible = "fsl,lpb";
+       localbus {
+               compatible = "fsl,mpc5200b-lpb","simple-bus";
                #address-cells = <2>;
                #size-cells = <1>;
                ranges = <0 0 0xff000000 0x01000000
                        compatible = "promess,motionpro-kollmorgen";
                        reg = <1 0 0x10000>;
                        interrupts = <1 1 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                // 8-bit board CPLD on LocalPlus Bus CS2
index 3ebf7ec0484cde8820b97806ad929df74155dbe8..761faa7b6964e3dd6601e2acca95796f84fcfe44 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <1>;
                        sleep = <&pmc 0x20000000>;
-                       ranges;
+                       ranges = <0x0 0x24000 0x1000>;
 
                        cell-index = <0>;
                        device_type = "network";
                        fixed-link = <1 1 1000 0 0>;
                        fsl,magic-packet;
 
-                       mdio@24520 {
+                       mdio@520 {
                                #address-cells = <1>;
                                #size-cells = <0>;
                                compatible = "fsl,gianfar-mdio";
-                               reg = <0x24520 0x20>;
+                               reg = <0x520 0x20>;
                                phy4: ethernet-phy@4 {
                                        interrupt-parent = <&ipic>;
                                        interrupts = <20 0x8>;
                        model = "eTSEC";
                        compatible = "gianfar";
                        reg = <0x25000 0x1000>;
+                       ranges = <0x0 0x25000 0x1000>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <34 0x8 33 0x8 32 0x8>;
                        interrupt-parent = <&ipic>;
                        sleep = <&pmc 0x10000000>;
                        fsl,magic-packet;
 
-                       mdio@25520 {
+                       mdio@520 {
                                #address-cells = <1>;
                                #size-cells = <0>;
                                compatible = "fsl,gianfar-tbi";
-                               reg = <0x25520 0x20>;
+                               reg = <0x520 0x20>;
 
                                tbi1: tbi-phy@11 {
                                        reg = <0x11>;
index 71784165b77e42624d22aadd1215c969ec923a8a..3f4c5fb988a02fffa5409ee9d66fa9178d99418a 100644 (file)
@@ -22,6 +22,8 @@
                serial0 = &serial0;
                serial1 = &serial1;
                pci0 = &pci0;
+               pci1 = &pci1;
+               pci2 = &pci2;
        };
 
        cpus {
                        phy_type = "utmi";
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-                       phy0: ethernet-phy@0 {
-                               interrupt-parent = <&ipic>;
-                               interrupts = <20 0x8>;
-                               reg = <0x0>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&ipic>;
-                               interrupts = <19 0x8>;
-                               reg = <0x1>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-
                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>;
                        interrupt-parent = <&ipic>;
                        tbi-handle = <&tbi0>;
                        phy-handle = < &phy0 >;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@0 {
+                                       interrupt-parent = <&ipic>;
+                                       interrupts = <20 0x8>;
+                                       reg = <0x0>;
+                                       device_type = "ethernet-phy";
+                               };
+
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&ipic>;
+                                       interrupts = <19 0x8>;
+                                       reg = <0x1>;
+                                       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>;
                        interrupt-parent = <&ipic>;
                        tbi-handle = <&tbi1>;
                        phy-handle = < &phy1 >;
+
+                       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 {
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
+
+       pci1: pcie@e0009000 {
+               #address-cells = <3>;
+               #size-cells = <2>;
+               #interrupt-cells = <1>;
+               device_type = "pci";
+               compatible = "fsl,mpc8315-pcie", "fsl,mpc8314-pcie";
+               reg = <0xe0009000 0x00001000>;
+               ranges = <0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
+                         0x01000000 0 0x00000000 0xb1000000 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>;
+               clock-frequency = <0>;
+
+               pcie@0 {
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       reg = <0 0 0 0 0>;
+                       ranges = <0x02000000 0 0xa0000000
+                                 0x02000000 0 0xa0000000
+                                 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,mpc8315-pcie", "fsl,mpc8314-pcie";
+               reg = <0xe000a000 0x00001000>;
+               ranges = <0x02000000 0 0xc0000000 0xc0000000 0 0x10000000
+                         0x01000000 0 0x00000000 0xd1000000 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>;
+               clock-frequency = <0>;
+
+               pcie@0 {
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       reg = <0 0 0 0 0>;
+                       ranges = <0x02000000 0 0xc0000000
+                                 0x02000000 0 0xc0000000
+                                 0 0x10000000
+                                 0x01000000 0 0x00000000
+                                 0x01000000 0 0x00000000
+                                 0 0x00800000>;
+               };
+       };
 };
index dea30910c136800cbe1bdb37fbe3e354376cf9d3..4319bd70a580beaa65a992eb92c6b94e91285c7c 100644 (file)
                };
 
                par_io@1400 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        reg = <0x1400 0x100>;
+                       ranges = <3 0x1448 0x18>;
+                       compatible = "fsl,mpc8323-qe-pario";
                        device_type = "par_io";
                        num-ports = <7>;
 
+                       qe_pio_d: gpio-controller@1448 {
+                               #gpio-cells = <2>;
+                               compatible = "fsl,mpc8323-qe-pario-bank";
+                               reg = <3 0x18>;
+                               gpio-controller;
+                       };
+
                        ucc2pio:ucc_pin@02 {
                                pio-map = <
                        /* port  pin  dir  open_drain  assignment  has_irq */
                };
 
                spi@4c0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                        cell-index = <0>;
                        compatible = "fsl,spi";
                        reg = <0x4c0 0x40>;
                        interrupts = <2>;
                        interrupt-parent = <&qeic>;
+                       gpios = <&qe_pio_d 13 0>;
                        mode = "cpu-qe";
+
+                       mmc-slot@0 {
+                               compatible = "fsl,mpc8323rdb-mmc-slot",
+                                            "mmc-spi-slot";
+                               reg = <0>;
+                               gpios = <&qe_pio_d 14 1
+                                        &qe_pio_d 15 0>;
+                               voltage-ranges = <3300 3300>;
+                               spi-max-frequency = <50000000>;
+                       };
                };
 
                spi@500 {
index b5eda94a8e2aa3afb1b108b138de1ff68cb5ed6f..1ae38f0ddef885d32e25d13e7bee99009ddb1766 100644 (file)
                        phy_type = "ulpi";
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       /* Vitesse 8201 */
-                       phy1c: ethernet-phy@1c {
-                               interrupt-parent = <&ipic>;
-                               interrupts = <18 0x8>;
-                               reg = <0x1c>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        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>;
                        interrupt-parent = <&ipic>;
                        tbi-handle = <&tbi0>;
                        phy-handle = <&phy1c>;
                        linux,network-index = <0>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               /* Vitesse 8201 */
+                               phy1c: ethernet-phy@1c {
+                                       interrupt-parent = <&ipic>;
+                                       interrupts = <18 0x8>;
+                                       reg = <0x1c>;
+                                       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 = "TSEC";
                        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>;
                        interrupt-parent = <&ipic>;
                        fixed-link = <1 1 1000 0 0>;
                        linux,network-index = <1>;
                        tbi-handle = <&tbi1>;
+
+                       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 {
index c87a6015e165a9ac5aaf4f57fef1f76900e8ede8..662abe1fb80488f1dd97ba7cbcdd03469471086d 100644 (file)
                        phy_type = "ulpi";
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       /* Vitesse 8201 */
-                       phy1c: ethernet-phy@1c {
-                               interrupt-parent = <&ipic>;
-                               interrupts = <18 0x8>;
-                               reg = <0x1c>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        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>;
                        interrupt-parent = <&ipic>;
                        tbi-handle = <&tbi0>;
                        phy-handle = <&phy1c>;
                        linux,network-index = <0>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               /* Vitesse 8201 */
+                               phy1c: ethernet-phy@1c {
+                                       interrupt-parent = <&ipic>;
+                                       interrupts = <18 0x8>;
+                                       reg = <0x1c>;
+                                       device_type = "ethernet-phy";
+                               };
+
+                               tbi0: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
                };
 
                serial0: serial@4500 {
index d9adba01c09c7564898dca8bd5a2f3fd9e1e9c26..d9f0a2325fa4fddbc93f8019a94446f76d4d0cdc 100644 (file)
                        phy_type = "ulpi";
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy0: ethernet-phy@0 {
-                               interrupt-parent = <&ipic>;
-                               interrupts = <17 0x8>;
-                               reg = <0x0>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&ipic>;
-                               interrupts = <18 0x8>;
-                               reg = <0x1>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        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>;
                        interrupt-parent = <&ipic>;
                        tbi-handle = <&tbi0>;
                        phy-handle = <&phy0>;
                        linux,network-index = <0>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@0 {
+                                       interrupt-parent = <&ipic>;
+                                       interrupts = <17 0x8>;
+                                       reg = <0x0>;
+                                       device_type = "ethernet-phy";
+                               };
+
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&ipic>;
+                                       interrupts = <18 0x8>;
+                                       reg = <0x1>;
+                                       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 = "TSEC";
                        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>;
                        interrupt-parent = <&ipic>;
                        tbi-handle = <&tbi1>;
                        phy-handle = <&phy1>;
                        linux,network-index = <1>;
+
+                       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 {
index 1d14d7052e6d534711ae067fe3dee07b89f6ed84..963708017e6c304fa5c11846e3c12abc903cf482 100644 (file)
@@ -23,6 +23,8 @@
                serial0 = &serial0;
                serial1 = &serial1;
                pci0 = &pci0;
+               pci1 = &pci1;
+               pci2 = &pci2;
        };
 
        cpus {
                        reg = <0x200 0x100>;
                };
 
-               i2c@3000 {
+               sleep-nexus {
                        #address-cells = <1>;
-                       #size-cells = <0>;
-                       cell-index = <0>;
-                       compatible = "fsl-i2c";
-                       reg = <0x3000 0x100>;
-                       interrupts = <14 0x8>;
-                       interrupt-parent = <&ipic>;
-                       dfsrr;
+                       #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;
+
+                               rtc@68 {
+                                       compatible = "dallas,ds1374";
+                                       reg = <0x68>;
+                                       interrupts = <19 0x8>;
+                                       interrupt-parent = <&ipic>;
+                               };
+                       };
 
-                       rtc@68 {
-                               compatible = "dallas,ds1374";
-                               reg = <0x68>;
-                               interrupts = <19 0x8>;
+                       sdhci@2e000 {
+                               compatible = "fsl,mpc8377-esdhc", "fsl,mpc8379-esdhc";
+                               reg = <0x2e000 0x1000>;
+                               interrupts = <42 0x8>;
                                interrupt-parent = <&ipic>;
+                               /* Filled in by U-Boot */
+                               clock-frequency = <0>;
                        };
                };
 
                        interrupts = <38 0x8>;
                        dr_mode = "host";
                        phy_type = "ulpi";
+                       sleep = <&pmc 0x00c00000>;
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 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";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-
                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>;
                        tbi-handle = <&tbi1>;
                        phy-handle = <&phy3>;
+                       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 {
                        fsl,channel-fifo-len = <24>;
                        fsl,exec-units-mask = <0x9fe>;
                        fsl,descriptor-types-mask = <0x3ab0ebf>;
-               };
-
-               sdhc@2e000 {
-                       model = "eSDHC";
-                       compatible = "fsl,esdhc";
-                       reg = <0x2e000 0x1000>;
-                       interrupts = <42 0x8>;
-                       interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x03000000>;
                };
 
                sata@18000 {
                        reg = <0x18000 0x1000>;
                        interrupts = <44 0x8>;
                        interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x000000c0>;
                };
 
                sata@19000 {
                        reg = <0x19000 0x1000>;
                        interrupts = <45 0x8>;
                        interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x00000030>;
                };
 
                /* IPIC
                        #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 {
                ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000
                          0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
                          0x01000000 0x0 0x00000000 0xe0300000 0x0 0x00100000>;
+               sleep = <&pmc 0x00010000>;
                clock-frequency = <0>;
                #interrupt-cells = <1>;
                #size-cells = <2>;
                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 9413af3b99259c14fa1ea9127896d89f20dd5dcb..053339390c22b96081d0175921e486c9ba023b66 100644 (file)
@@ -22,6 +22,8 @@
                serial0 = &serial0;
                serial1 = &serial1;
                pci0 = &pci0;
+               pci1 = &pci1;
+               pci2 = &pci2;
        };
 
        cpus {
                        reg = <0x200 0x100>;
                };
 
-               i2c@3000 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       cell-index = <0>;
-                       compatible = "fsl-i2c";
-                       reg = <0x3000 0x100>;
-                       interrupts = <14 0x8>;
+               gpio1: gpio-controller@c00 {
+                       #gpio-cells = <2>;
+                       compatible = "fsl,mpc8377-gpio", "fsl,mpc8349-gpio";
+                       reg = <0xc00 0x100>;
+                       interrupts = <74 0x8>;
                        interrupt-parent = <&ipic>;
-                       dfsrr;
-                       rtc@68 {
-                               compatible = "dallas,ds1339";
-                               reg = <0x68>;
+                       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;
+
+                               dtt@48 {
+                                       compatible = "national,lm75";
+                                       reg = <0x48>;
+                               };
+
+                               at24@50 {
+                                       compatible = "at24,24c256";
+                                       reg = <0x50>;
+                               };
+
+                               rtc@68 {
+                                       compatible = "dallas,ds1339";
+                                       reg = <0x68>;
+                               };
+
+                               mcu_pio: mcu@a {
+                                       #gpio-cells = <2>;
+                                       compatible = "fsl,mc9s08qg8-mpc8377erdb",
+                                                    "fsl,mcu-mpc8349emitx";
+                                       reg = <0x0a>;
+                                       gpio-controller;
+                               };
                        };
 
-                       mcu_pio: mcu@a {
-                               #gpio-cells = <2>;
-                               compatible = "fsl,mc9s08qg8-mpc8377erdb",
-                                            "fsl,mcu-mpc8349emitx";
-                               reg = <0x0a>;
-                               gpio-controller;
+                       sdhci@2e000 {
+                               compatible = "fsl,mpc8377-esdhc", "fsl,mpc8379-esdhc";
+                               reg = <0x2e000 0x1000>;
+                               interrupts = <42 0x8>;
+                               interrupt-parent = <&ipic>;
+                               /* Filled in by U-Boot */
+                               clock-frequency = <0>;
                        };
                };
 
                        interrupt-parent = <&ipic>;
                        interrupts = <38 0x8>;
                        phy_type = "ulpi";
+                       sleep = <&pmc 0x00c00000>;
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-                       phy2: ethernet-phy@2 {
-                               interrupt-parent = <&ipic>;
-                               interrupts = <17 0x8>;
-                               reg = <0x2>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-
                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";
+                               };
+
+                               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>;
                        fixed-link = <1 1 1000 0 0>;
                        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 {
                        fsl,channel-fifo-len = <24>;
                        fsl,exec-units-mask = <0x9fe>;
                        fsl,descriptor-types-mask = <0x3ab0ebf>;
+                       sleep = <&pmc 0x03000000>;
                };
 
                sata@18000 {
                        reg = <0x18000 0x1000>;
                        interrupts = <44 0x8>;
                        interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x000000c0>;
                };
 
                sata@19000 {
                        reg = <0x19000 0x1000>;
                        interrupts = <45 0x8>;
                        interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x00000030>;
                };
 
                /* IPIC
                        #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 {
                ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000
                          0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
                          0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>;
+               sleep = <&pmc 0x00010000>;
                clock-frequency = <66666666>;
                #interrupt-cells = <1>;
                #size-cells = <2>;
                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 b85fc02682d250991d3af01c3966dcd859704901..651ff2f9db2d9e3ab963953752579aae34da3bf3 100644 (file)
@@ -23,6 +23,8 @@
                serial0 = &serial0;
                serial1 = &serial1;
                pci0 = &pci0;
+               pci1 = &pci1;
+               pci2 = &pci2;
        };
 
        cpus {
                        reg = <0x200 0x100>;
                };
 
-               i2c@3000 {
+               sleep-nexus {
                        #address-cells = <1>;
-                       #size-cells = <0>;
-                       cell-index = <0>;
-                       compatible = "fsl-i2c";
-                       reg = <0x3000 0x100>;
-                       interrupts = <14 0x8>;
-                       interrupt-parent = <&ipic>;
-                       dfsrr;
+                       #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;
+
+                               rtc@68 {
+                                       compatible = "dallas,ds1374";
+                                       reg = <0x68>;
+                                       interrupts = <19 0x8>;
+                                       interrupt-parent = <&ipic>;
+                               };
+                       };
 
-                       rtc@68 {
-                               compatible = "dallas,ds1374";
-                               reg = <0x68>;
-                               interrupts = <19 0x8>;
+                       sdhci@2e000 {
+                               compatible = "fsl,mpc8378-esdhc", "fsl,mpc8379-esdhc";
+                               reg = <0x2e000 0x1000>;
+                               interrupts = <42 0x8>;
                                interrupt-parent = <&ipic>;
+                               /* Filled in by U-Boot */
+                               clock-frequency = <0>;
                        };
                };
 
                        interrupts = <38 0x8>;
                        dr_mode = "host";
                        phy_type = "ulpi";
+                       sleep = <&pmc 0x00c00000>;
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 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";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-
                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>;
                        tbi-handle = <&tbi1>;
                        phy-handle = <&phy3>;
+                       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 {
                        fsl,channel-fifo-len = <24>;
                        fsl,exec-units-mask = <0x9fe>;
                        fsl,descriptor-types-mask = <0x3ab0ebf>;
-               };
-
-               sdhc@2e000 {
-                       model = "eSDHC";
-                       compatible = "fsl,esdhc";
-                       reg = <0x2e000 0x1000>;
-                       interrupts = <42 0x8>;
-                       interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x03000000>;
                };
 
                /* IPIC
                        #interrupt-cells = <2>;
                        reg = <0x700 0x100>;
                };
+
+               pmc: power@b00 {
+                       compatible = "fsl,mpc8378-pmc", "fsl,mpc8349-pmc";
+                       reg = <0xb00 0x100 0xa00 0x100>;
+                       interrupts = <80 0x8>;
+                       interrupt-parent = <&ipic>;
+               };
        };
 
        pci0: pci@e0008500 {
                          0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
                          0x01000000 0x0 0x00000000 0xe0300000 0x0 0x00100000>;
                clock-frequency = <0>;
+               sleep = <&pmc 0x00010000>;
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
+
+       pci1: pcie@e0009000 {
+               #address-cells = <3>;
+               #size-cells = <2>;
+               #interrupt-cells = <1>;
+               device_type = "pci";
+               compatible = "fsl,mpc8378-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,mpc8378-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 23c10ce22c2cd6b95597e52a975eed284d54ddea..5d90e85704c3e1c4620c7e695a07aafdcf21276f 100644 (file)
@@ -22,6 +22,8 @@
                serial0 = &serial0;
                serial1 = &serial1;
                pci0 = &pci0;
+               pci1 = &pci1;
+               pci2 = &pci2;
        };
 
        cpus {
                        reg = <0x200 0x100>;
                };
 
-               i2c@3000 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       cell-index = <0>;
-                       compatible = "fsl-i2c";
-                       reg = <0x3000 0x100>;
-                       interrupts = <14 0x8>;
+               gpio1: gpio-controller@c00 {
+                       #gpio-cells = <2>;
+                       compatible = "fsl,mpc8378-gpio", "fsl,mpc8349-gpio";
+                       reg = <0xc00 0x100>;
+                       interrupts = <74 0x8>;
                        interrupt-parent = <&ipic>;
-                       dfsrr;
-                       rtc@68 {
-                               compatible = "dallas,ds1339";
-                               reg = <0x68>;
+                       gpio-controller;
+               };
+
+               gpio2: gpio-controller@d00 {
+                       #gpio-cells = <2>;
+                       compatible = "fsl,mpc8378-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;
+
+                               dtt@48 {
+                                       compatible = "national,lm75";
+                                       reg = <0x48>;
+                               };
+
+                               at24@50 {
+                                       compatible = "at24,24c256";
+                                       reg = <0x50>;
+                               };
+
+                               rtc@68 {
+                                       compatible = "dallas,ds1339";
+                                       reg = <0x68>;
+                               };
+
+                               mcu_pio: mcu@a {
+                                       #gpio-cells = <2>;
+                                       compatible = "fsl,mc9s08qg8-mpc8378erdb",
+                                                    "fsl,mcu-mpc8349emitx";
+                                       reg = <0x0a>;
+                                       gpio-controller;
+                               };
                        };
 
-                       mcu_pio: mcu@a {
-                               #gpio-cells = <2>;
-                               compatible = "fsl,mc9s08qg8-mpc8378erdb",
-                                            "fsl,mcu-mpc8349emitx";
-                               reg = <0x0a>;
-                               gpio-controller;
+                       sdhci@2e000 {
+                               compatible = "fsl,mpc8378-esdhc", "fsl,mpc8379-esdhc";
+                               reg = <0x2e000 0x1000>;
+                               interrupts = <42 0x8>;
+                               interrupt-parent = <&ipic>;
+                               /* Filled in by U-Boot */
+                               clock-frequency = <0>;
                        };
                };
 
                        interrupt-parent = <&ipic>;
                        interrupts = <38 0x8>;
                        phy_type = "ulpi";
+                       sleep = <&pmc 0x00c00000>;
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-                       phy2: ethernet-phy@2 {
-                               interrupt-parent = <&ipic>;
-                               interrupts = <17 0x8>;
-                               reg = <0x2>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-
                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";
+                               };
+
+                               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>;
                        fixed-link = <1 1 1000 0 0>;
+                       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 {
                        fsl,channel-fifo-len = <24>;
                        fsl,exec-units-mask = <0x9fe>;
                        fsl,descriptor-types-mask = <0x3ab0ebf>;
+                       sleep = <&pmc 0x03000000>;
                };
 
                /* IPIC
                        #interrupt-cells = <2>;
                        reg = <0x700 0x100>;
                };
+
+               pmc: power@b00 {
+                       compatible = "fsl,mpc8378-pmc", "fsl,mpc8349-pmc";
+                       reg = <0xb00 0x100 0xa00 0x100>;
+                       interrupts = <80 0x8>;
+                       interrupt-parent = <&ipic>;
+               };
        };
 
        pci0: pci@e0008500 {
                ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000
                          0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
                          0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>;
+               sleep = <&pmc 0x00010000>;
                clock-frequency = <66666666>;
                #interrupt-cells = <1>;
                #size-cells = <2>;
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
+
+       pci1: pcie@e0009000 {
+               #address-cells = <3>;
+               #size-cells = <2>;
+               #interrupt-cells = <1>;
+               device_type = "pci";
+               compatible = "fsl,mpc8378-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,mpc8378-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 acf06c438dbf60bc5beb736a373ec7b24ce5a0af..d6f208b8297a834de4c97a3b4521650819311e41 100644 (file)
                        reg = <0x200 0x100>;
                };
 
-               i2c@3000 {
+               sleep-nexus {
                        #address-cells = <1>;
-                       #size-cells = <0>;
-                       cell-index = <0>;
-                       compatible = "fsl-i2c";
-                       reg = <0x3000 0x100>;
-                       interrupts = <14 0x8>;
-                       interrupt-parent = <&ipic>;
-                       dfsrr;
+                       #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;
+
+                               rtc@68 {
+                                       compatible = "dallas,ds1374";
+                                       reg = <0x68>;
+                                       interrupts = <19 0x8>;
+                                       interrupt-parent = <&ipic>;
+                               };
+                       };
 
-                       rtc@68 {
-                               compatible = "dallas,ds1374";
-                               reg = <0x68>;
-                               interrupts = <19 0x8>;
+                       sdhci@2e000 {
+                               compatible = "fsl,mpc8379-esdhc";
+                               reg = <0x2e000 0x1000>;
+                               interrupts = <42 0x8>;
                                interrupt-parent = <&ipic>;
+                               /* Filled in by U-Boot */
+                               clock-frequency = <0>;
                        };
                };
 
                        interrupts = <38 0x8>;
                        dr_mode = "host";
                        phy_type = "ulpi";
-               };
-
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 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";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
+                       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>;
                        tbi-handle = <&tbi1>;
                        phy-handle = <&phy3>;
+                       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 {
                        fsl,channel-fifo-len = <24>;
                        fsl,exec-units-mask = <0x9fe>;
                        fsl,descriptor-types-mask = <0x3ab0ebf>;
-               };
-
-               sdhc@2e000 {
-                       model = "eSDHC";
-                       compatible = "fsl,esdhc";
-                       reg = <0x2e000 0x1000>;
-                       interrupts = <42 0x8>;
-                       interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x03000000>;
                };
 
                sata@18000 {
                        reg = <0x18000 0x1000>;
                        interrupts = <44 0x8>;
                        interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x000000c0>;
                };
 
                sata@19000 {
                        reg = <0x19000 0x1000>;
                        interrupts = <45 0x8>;
                        interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x00000030>;
                };
 
                sata@1a000 {
                        reg = <0x1a000 0x1000>;
                        interrupts = <46 0x8>;
                        interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x0000000c>;
                };
 
                sata@1b000 {
                        reg = <0x1b000 0x1000>;
                        interrupts = <47 0x8>;
                        interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x00000003>;
                };
 
                /* IPIC
                        #interrupt-cells = <2>;
                        reg = <0x700 0x100>;
                };
+
+               pmc: power@b00 {
+                       compatible = "fsl,mpc8379-pmc", "fsl,mpc8349-pmc";
+                       reg = <0xb00 0x100 0xa00 0x100>;
+                       interrupts = <80 0x8>;
+                       interrupt-parent = <&ipic>;
+               };
        };
 
        pci0: pci@e0008500 {
                ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000
                          0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
                          0x01000000 0x0 0x00000000 0xe0300000 0x0 0x00100000>;
+               sleep = <&pmc 0x00010000>;
                clock-frequency = <0>;
                #interrupt-cells = <1>;
                #size-cells = <2>;
index 72cdc3c4c7e36190e2c7c144c414e53d855165b4..98ae95bd18f4988088f7fab563b2b482d8c9cbf2 100644 (file)
                        reg = <0x200 0x100>;
                };
 
-               i2c@3000 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       cell-index = <0>;
-                       compatible = "fsl-i2c";
-                       reg = <0x3000 0x100>;
-                       interrupts = <14 0x8>;
+               gpio1: gpio-controller@c00 {
+                       #gpio-cells = <2>;
+                       compatible = "fsl,mpc8379-gpio", "fsl,mpc8349-gpio";
+                       reg = <0xc00 0x100>;
+                       interrupts = <74 0x8>;
                        interrupt-parent = <&ipic>;
-                       dfsrr;
-                       rtc@68 {
-                               compatible = "dallas,ds1339";
-                               reg = <0x68>;
+                       gpio-controller;
+               };
+
+               gpio2: gpio-controller@d00 {
+                       #gpio-cells = <2>;
+                       compatible = "fsl,mpc8379-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;
+
+                               dtt@48 {
+                                       compatible = "national,lm75";
+                                       reg = <0x48>;
+                               };
+
+                               at24@50 {
+                                       compatible = "at24,24c256";
+                                       reg = <0x50>;
+                               };
+
+                               rtc@68 {
+                                       compatible = "dallas,ds1339";
+                                       reg = <0x68>;
+                               };
+
+                               mcu_pio: mcu@a {
+                                       #gpio-cells = <2>;
+                                       compatible = "fsl,mc9s08qg8-mpc8379erdb",
+                                                    "fsl,mcu-mpc8349emitx";
+                                       reg = <0x0a>;
+                                       gpio-controller;
+                               };
                        };
 
-                       mcu_pio: mcu@a {
-                               #gpio-cells = <2>;
-                               compatible = "fsl,mc9s08qg8-mpc8379erdb",
-                                            "fsl,mcu-mpc8349emitx";
-                               reg = <0x0a>;
-                               gpio-controller;
+                       sdhci@2e000 {
+                               compatible = "fsl,mpc8379-esdhc";
+                               reg = <0x2e000 0x1000>;
+                               interrupts = <42 0x8>;
+                               interrupt-parent = <&ipic>;
+                               /* Filled in by U-Boot */
+                               clock-frequency = <0>;
                        };
                };
 
                        interrupt-parent = <&ipic>;
                        interrupts = <38 0x8>;
                        phy_type = "ulpi";
-               };
-
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-                       phy2: ethernet-phy@2 {
-                               interrupt-parent = <&ipic>;
-                               interrupts = <17 0x8>;
-                               reg = <0x2>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
+                       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";
+                               };
+
+                               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>;
                        fixed-link = <1 1 1000 0 0>;
                        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 {
                        fsl,channel-fifo-len = <24>;
                        fsl,exec-units-mask = <0x9fe>;
                        fsl,descriptor-types-mask = <0x3ab0ebf>;
+                       sleep = <&pmc 0x03000000>;
                };
 
                sata@18000 {
                        reg = <0x18000 0x1000>;
                        interrupts = <44 0x8>;
                        interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x000000c0>;
                };
 
                sata@19000 {
                        reg = <0x19000 0x1000>;
                        interrupts = <45 0x8>;
                        interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x00000030>;
                };
 
                sata@1a000 {
                        reg = <0x1a000 0x1000>;
                        interrupts = <46 0x8>;
                        interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x0000000c>;
                };
 
                sata@1b000 {
                        reg = <0x1b000 0x1000>;
                        interrupts = <47 0x8>;
                        interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x00000003>;
                };
 
                /* IPIC
                        #interrupt-cells = <2>;
                        reg = <0x700 0x100>;
                };
+
+               pmc: power@b00 {
+                       compatible = "fsl,mpc8379-pmc", "fsl,mpc8349-pmc";
+                       reg = <0xb00 0x100 0xa00 0x100>;
+                       interrupts = <80 0x8>;
+                       interrupt-parent = <&ipic>;
+               };
        };
 
        pci0: pci@e0008500 {
                ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000
                          0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
                          0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>;
+               sleep = <&pmc 0x00010000>;
                clock-frequency = <66666666>;
                #interrupt-cells = <1>;
                #size-cells = <2>;
index 3c905df1812ca1d50844e50f857d974505f12618..b31c5041350b18b983ef055ee1d2e79250741bb2 100644 (file)
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 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";
-                       };
-               };
-
-               mdio@26520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x26520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                usb@22000 {
                        compatible = "fsl,mpc8536-usb2-mph", "fsl-usb2-mph";
                        reg = <0x22000 0x1000>;
                };
 
                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 {
index 79570ffe41b9e46179779044b8df213ed195cc34..ddd67be10b033f6afa6683aa67654ea66f173c30 100644 (file)
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy0: ethernet-phy@0 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <5 1>;
-                               reg = <0x0>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <5 1>;
-                               reg = <0x1>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy3: ethernet-phy@3 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <7 1>;
-                               reg = <0x3>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@26520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x26520 0x20>;
-
-                       tbi2: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        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 = <&phy0>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@0 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <5 1>;
+                                       reg = <0x0>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <5 1>;
+                                       reg = <0x1>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy3: ethernet-phy@3 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <7 1>;
+                                       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 = "TSEC";
                        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 = <&tbi1>;
                        phy-handle = <&phy1>;
+
+                       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";
+                               };
+                       };
                };
 
                enet2: ethernet@26000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <2>;
                        device_type = "network";
                        model = "FEC";
                        compatible = "gianfar";
                        reg = <0x26000 0x1000>;
+                       ranges = <0x0 0x26000 0x1000>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <41 2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi2>;
                        phy-handle = <&phy3>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi2: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
                };
 
                serial0: serial@4500 {
index 221036a8ce236ca1a808274a0a9c874ba8cfb703..e45097f44fbde4fecc1a2df04d0a8700283e391b 100644 (file)
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy0: ethernet-phy@0 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <5 1>;
-                               reg = <0x0>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <5 1>;
-                               reg = <0x1>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        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 = <&phy0>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@0 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <5 1>;
+                                       reg = <0x0>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <5 1>;
+                                       reg = <0x1>;
+                                       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 = "TSEC";
                        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 = <&tbi1>;
                        phy-handle = <&phy1>;
+
+                       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 {
index 0668d10487795648fce808ab04b4e3da15aafd76..7c6932be01978222a964fa47f932991952b92959 100644 (file)
                        dfsrr;
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy0: ethernet-phy@0 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <10 1>;
-                               reg = <0x0>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <10 1>;
-                               reg = <0x1>;
-                               device_type = "ethernet-phy";
-                       };
-
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@26520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x26520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-
                dma@21300 {
                        #address-cells = <1>;
                        #size-cells = <1>;
                };
 
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        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>;
                        phy-handle = <&phy0>;
                        tbi-handle = <&tbi0>;
                        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 1>;
+                                       reg = <0x0>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 1>;
+                                       reg = <0x1>;
+                                       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 = "TSEC";
                        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>;
                        tbi-handle = <&tbi1>;
                        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";
+                               };
+                       };
                };
 
                serial0: serial@4500 {
index df774a7088ffd409d8f3e3e921bbdab2d8287ee3..804e903532939c59caa7f1681a2c7a00fb1da89a 100644 (file)
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy0: ethernet-phy@0 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <5 1>;
-                               reg = <0x0>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <5 1>;
-                               reg = <0x1>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy2: ethernet-phy@2 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <5 1>;
-                               reg = <0x2>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy3: ethernet-phy@3 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <5 1>;
-                               reg = <0x3>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@26520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x26520 0x20>;
-
-                       tbi2: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@27520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x27520 0x20>;
-
-                       tbi3: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                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 = <&phy0>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@0 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <5 1>;
+                                       reg = <0x0>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <5 1>;
+                                       reg = <0x1>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy2: ethernet-phy@2 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <5 1>;
+                                       reg = <0x2>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy3: ethernet-phy@3 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <5 1>;
+                                       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 2 36 2 40 2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi1>;
                        phy-handle = <&phy1>;
+
+                       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";
+                               };
+                       };
                };
 
 /* eTSEC 3/4 are currently broken
                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>;
                        tbi-handle = <&tbi2>;
                        phy-handle = <&phy2>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi2: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
                };
 
                enet3: ethernet@27000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <3>;
                        device_type = "network";
                        model = "eTSEC";
                        compatible = "gianfar";
                        reg = <0x27000 0x1000>;
+                       ranges = <0x0 0x27000 0x1000>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <37 2 38 2 39 2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi3>;
                        phy-handle = <&phy3>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi3: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
                };
  */
 
index 053b01e1c93bf4d5603098a1d61098b1c225322c..9484f0729b1080bd2342e3efe622c3437cbcaf97 100644 (file)
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy0: ethernet-phy@0 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <5 1>;
-                               reg = <0x0>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <5 1>;
-                               reg = <0x1>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        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 = <&phy0>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@0 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <5 1>;
+                                       reg = <0x0>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <5 1>;
+                                       reg = <0x1>;
+                                       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 = "TSEC";
                        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 = <&tbi1>;
                        phy-handle = <&phy1>;
+
+                       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 {
index 11b1bcbe14cedaf47e297265bde1230fbcb84a1c..cc2acf87d02fdac479cdb8ca99ad29c5decd1402 100644 (file)
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy0: ethernet-phy@0 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <5 1>;
-                               reg = <0x0>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <5 1>;
-                               reg = <0x1>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy2: ethernet-phy@2 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <7 1>;
-                               reg = <0x2>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy3: ethernet-phy@3 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <7 1>;
-                               reg = <0x3>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        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 = <&phy0>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@0 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <5 1>;
+                                       reg = <0x0>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <5 1>;
+                                       reg = <0x1>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy2: ethernet-phy@2 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <7 1>;
+                                       reg = <0x2>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy3: ethernet-phy@3 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <7 1>;
+                                       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 = "TSEC";
                        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 = <&tbi1>;
                        phy-handle = <&phy1>;
+
+                       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";
+                               };
+                       };
                };
 
                mpic: pic@40000 {
index 1955bd9e113d9d605d7264f790f669197a715074..9d52e3b250474782ebabc42cdd18d5b410f33044 100644 (file)
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy0: ethernet-phy@7 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <1 1>;
-                               reg = <0x7>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <2 1>;
-                               reg = <0x1>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy2: ethernet-phy@2 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <1 1>;
-                               reg = <0x2>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy3: ethernet-phy@3 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <2 1>;
-                               reg = <0x3>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                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 = <&phy2>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@7 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <1 1>;
+                                       reg = <0x7>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <2 1>;
+                                       reg = <0x1>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy2: ethernet-phy@2 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <1 1>;
+                                       reg = <0x2>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy3: ethernet-phy@3 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <2 1>;
+                                       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 2 36 2 40 2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi1>;
                        phy-handle = <&phy3>;
+
+                       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 {
index 359c3b727420fec88a5f2585744b0f3b6c923f5e..6e79a4169088554deec5f5231c9db5ea88f5bc1b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * MPC8572 DS Device Tree Source
  *
- * Copyright 2007, 2008 Freescale Semiconductor Inc.
+ * Copyright 2007-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
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy0: ethernet-phy@0 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <10 1>;
-                               reg = <0x0>;
-                       };
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <10 1>;
-                               reg = <0x1>;
-                       };
-                       phy2: ethernet-phy@2 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <10 1>;
-                               reg = <0x2>;
-                       };
-                       phy3: ethernet-phy@3 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <10 1>;
-                               reg = <0x3>;
-                       };
-
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@26520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x26520 0x20>;
-
-                       tbi2: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@27520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x27520 0x20>;
-
-                       tbi3: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                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 = <&phy0>;
                        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 1>;
+                                       reg = <0x0>;
+                               };
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 1>;
+                                       reg = <0x1>;
+                               };
+                               phy2: ethernet-phy@2 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 1>;
+                                       reg = <0x2>;
+                               };
+                               phy3: ethernet-phy@3 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 1>;
+                                       reg = <0x3>;
+                               };
+
+                               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 2 36 2 40 2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi1>;
                        phy-handle = <&phy1>;
                        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";
+                               };
+                       };
                };
 
                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>;
                        tbi-handle = <&tbi2>;
                        phy-handle = <&phy2>;
                        phy-connection-type = "rgmii-id";
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi2: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
                };
 
                enet3: ethernet@27000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <3>;
                        device_type = "network";
                        model = "eTSEC";
                        compatible = "gianfar";
                        reg = <0x27000 0x1000>;
+                       ranges = <0x0 0x27000 0x1000>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <37 2 38 2 39 2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi3>;
                        phy-handle = <&phy3>;
                        phy-connection-type = "rgmii-id";
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi3: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
                };
 
                serial0: serial@4500 {
 
                                  0x1000000 0x0 0x0
                                  0x1000000 0x0 0x0
-                                 0x0 0x100000>;
+                                 0x0 0x10000>;
                        uli1575@0 {
                                reg = <0x0 0x0 0x0 0x0 0x0>;
                                #size-cells = <2>;
 
                                          0x1000000 0x0 0x0
                                          0x1000000 0x0 0x0
-                                         0x0 0x100000>;
+                                         0x0 0x10000>;
                                isa@1e {
                                        device_type = "isa";
                                        #interrupt-cells = <2>;
 
                                  0x1000000 0x0 0x0
                                  0x1000000 0x0 0x0
-                                 0x0 0x100000>;
+                                 0x0 0x10000>;
                };
        };
 
 
                                  0x1000000 0x0 0x0
                                  0x1000000 0x0 0x0
-                                 0x0 0x100000>;
+                                 0x0 0x10000>;
                };
        };
 };
diff --git a/arch/powerpc/boot/dts/mpc8572ds_36b.dts b/arch/powerpc/boot/dts/mpc8572ds_36b.dts
new file mode 100644 (file)
index 0000000..dbd81a7
--- /dev/null
@@ -0,0 +1,799 @@
+/*
+ * MPC8572 DS Device Tree Source
+ *
+ * Copyright 2007-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,MPC8572DS";
+       compatible = "fsl,MPC8572DS";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       aliases {
+               ethernet0 = &enet0;
+               ethernet1 = &enet1;
+               ethernet2 = &enet2;
+               ethernet3 = &enet3;
+               serial0 = &serial0;
+               serial1 = &serial1;
+               pci0 = &pci0;
+               pci1 = &pci1;
+               pci2 = &pci2;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,8572@0 {
+                       device_type = "cpu";
+                       reg = <0x0>;
+                       d-cache-line-size = <32>;       // 32 bytes
+                       i-cache-line-size = <32>;       // 32 bytes
+                       d-cache-size = <0x8000>;                // L1, 32K
+                       i-cache-size = <0x8000>;                // L1, 32K
+                       timebase-frequency = <0>;
+                       bus-frequency = <0>;
+                       clock-frequency = <0>;
+                       next-level-cache = <&L2>;
+               };
+
+               PowerPC,8572@1 {
+                       device_type = "cpu";
+                       reg = <0x1>;
+                       d-cache-line-size = <32>;       // 32 bytes
+                       i-cache-line-size = <32>;       // 32 bytes
+                       d-cache-size = <0x8000>;                // L1, 32K
+                       i-cache-size = <0x8000>;                // L1, 32K
+                       timebase-frequency = <0>;
+                       bus-frequency = <0>;
+                       clock-frequency = <0>;
+                       next-level-cache = <&L2>;
+               };
+       };
+
+       memory {
+               device_type = "memory";
+       };
+
+       localbus@fffe05000 {
+               #address-cells = <2>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8572-elbc", "fsl,elbc", "simple-bus";
+               reg = <0xf 0xffe05000 0 0x1000>;
+               interrupts = <19 2>;
+               interrupt-parent = <&mpic>;
+
+               ranges = <0x0 0x0 0xf 0xe8000000 0x08000000
+                         0x1 0x0 0xf 0xe0000000 0x08000000
+                         0x2 0x0 0xf 0xffa00000 0x00040000
+                         0x3 0x0 0xf 0xffdf0000 0x00008000
+                         0x4 0x0 0xf 0xffa40000 0x00040000
+                         0x5 0x0 0xf 0xffa80000 0x00040000
+                         0x6 0x0 0xf 0xffac0000 0x00040000>;
+
+               nor@0,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "cfi-flash";
+                       reg = <0x0 0x0 0x8000000>;
+                       bank-width = <2>;
+                       device-width = <1>;
+
+                       ramdisk@0 {
+                               reg = <0x0 0x03000000>;
+                               read-only;
+                       };
+
+                       diagnostic@3000000 {
+                               reg = <0x03000000 0x00e00000>;
+                               read-only;
+                       };
+
+                       dink@3e00000 {
+                               reg = <0x03e00000 0x00200000>;
+                               read-only;
+                       };
+
+                       kernel@4000000 {
+                               reg = <0x04000000 0x00400000>;
+                               read-only;
+                       };
+
+                       jffs2@4400000 {
+                               reg = <0x04400000 0x03b00000>;
+                       };
+
+                       dtb@7f00000 {
+                               reg = <0x07f00000 0x00080000>;
+                               read-only;
+                       };
+
+                       u-boot@7f80000 {
+                               reg = <0x07f80000 0x00080000>;
+                               read-only;
+                       };
+               };
+
+               nand@2,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,mpc8572-fcm-nand",
+                                    "fsl,elbc-fcm-nand";
+                       reg = <0x2 0x0 0x40000>;
+
+                       u-boot@0 {
+                               reg = <0x0 0x02000000>;
+                               read-only;
+                       };
+
+                       jffs2@2000000 {
+                               reg = <0x02000000 0x10000000>;
+                       };
+
+                       ramdisk@12000000 {
+                               reg = <0x12000000 0x08000000>;
+                               read-only;
+                       };
+
+                       kernel@1a000000 {
+                               reg = <0x1a000000 0x04000000>;
+                       };
+
+                       dtb@1e000000 {
+                               reg = <0x1e000000 0x01000000>;
+                               read-only;
+                       };
+
+                       empty@1f000000 {
+                               reg = <0x1f000000 0x21000000>;
+                       };
+               };
+
+               nand@4,0 {
+                       compatible = "fsl,mpc8572-fcm-nand",
+                                    "fsl,elbc-fcm-nand";
+                       reg = <0x4 0x0 0x40000>;
+               };
+
+               nand@5,0 {
+                       compatible = "fsl,mpc8572-fcm-nand",
+                                    "fsl,elbc-fcm-nand";
+                       reg = <0x5 0x0 0x40000>;
+               };
+
+               nand@6,0 {
+                       compatible = "fsl,mpc8572-fcm-nand",
+                                    "fsl,elbc-fcm-nand";
+                       reg = <0x6 0x0 0x40000>;
+               };
+       };
+
+       soc8572@fffe00000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               device_type = "soc";
+               compatible = "simple-bus";
+               ranges = <0x0 0xf 0xffe00000 0x100000>;
+               reg = <0xf 0xffe00000 0 0x1000>;        // CCSRBAR & soc regs, remove once parse code for immrbase fixed
+               bus-frequency = <0>;            // Filled out by uboot.
+
+               memory-controller@2000 {
+                       compatible = "fsl,mpc8572-memory-controller";
+                       reg = <0x2000 0x1000>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <18 2>;
+               };
+
+               memory-controller@6000 {
+                       compatible = "fsl,mpc8572-memory-controller";
+                       reg = <0x6000 0x1000>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <18 2>;
+               };
+
+               L2: l2-cache-controller@20000 {
+                       compatible = "fsl,mpc8572-l2-cache-controller";
+                       reg = <0x20000 0x1000>;
+                       cache-line-size = <32>; // 32 bytes
+                       cache-size = <0x100000>; // L2, 1M
+                       interrupt-parent = <&mpic>;
+                       interrupts = <16 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;
+               };
+
+               i2c@3100 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       cell-index = <1>;
+                       compatible = "fsl-i2c";
+                       reg = <0x3100 0x100>;
+                       interrupts = <43 2>;
+                       interrupt-parent = <&mpic>;
+                       dfsrr;
+               };
+
+               dma@c300 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,mpc8572-dma", "fsl,eloplus-dma";
+                       reg = <0xc300 0x4>;
+                       ranges = <0x0 0xc100 0x200>;
+                       cell-index = <1>;
+                       dma-channel@0 {
+                               compatible = "fsl,mpc8572-dma-channel",
+                                               "fsl,eloplus-dma-channel";
+                               reg = <0x0 0x80>;
+                               cell-index = <0>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <76 2>;
+                       };
+                       dma-channel@80 {
+                               compatible = "fsl,mpc8572-dma-channel",
+                                               "fsl,eloplus-dma-channel";
+                               reg = <0x80 0x80>;
+                               cell-index = <1>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <77 2>;
+                       };
+                       dma-channel@100 {
+                               compatible = "fsl,mpc8572-dma-channel",
+                                               "fsl,eloplus-dma-channel";
+                               reg = <0x100 0x80>;
+                               cell-index = <2>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <78 2>;
+                       };
+                       dma-channel@180 {
+                               compatible = "fsl,mpc8572-dma-channel",
+                                               "fsl,eloplus-dma-channel";
+                               reg = <0x180 0x80>;
+                               cell-index = <3>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <79 2>;
+                       };
+               };
+
+               dma@21300 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,mpc8572-dma", "fsl,eloplus-dma";
+                       reg = <0x21300 0x4>;
+                       ranges = <0x0 0x21100 0x200>;
+                       cell-index = <0>;
+                       dma-channel@0 {
+                               compatible = "fsl,mpc8572-dma-channel",
+                                               "fsl,eloplus-dma-channel";
+                               reg = <0x0 0x80>;
+                               cell-index = <0>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <20 2>;
+                       };
+                       dma-channel@80 {
+                               compatible = "fsl,mpc8572-dma-channel",
+                                               "fsl,eloplus-dma-channel";
+                               reg = <0x80 0x80>;
+                               cell-index = <1>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <21 2>;
+                       };
+                       dma-channel@100 {
+                               compatible = "fsl,mpc8572-dma-channel",
+                                               "fsl,eloplus-dma-channel";
+                               reg = <0x100 0x80>;
+                               cell-index = <2>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <22 2>;
+                       };
+                       dma-channel@180 {
+                               compatible = "fsl,mpc8572-dma-channel",
+                                               "fsl,eloplus-dma-channel";
+                               reg = <0x180 0x80>;
+                               cell-index = <3>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <23 2>;
+                       };
+               };
+
+               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 = <&phy0>;
+                       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 1>;
+                                       reg = <0x0>;
+                               };
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 1>;
+                                       reg = <0x1>;
+                               };
+                               phy2: ethernet-phy@2 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 1>;
+                                       reg = <0x2>;
+                               };
+                               phy3: ethernet-phy@3 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 1>;
+                                       reg = <0x3>;
+                               };
+
+                               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 2 36 2 40 2>;
+                       interrupt-parent = <&mpic>;
+                       tbi-handle = <&tbi1>;
+                       phy-handle = <&phy1>;
+                       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";
+                               };
+                       };
+               };
+
+               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>;
+                       tbi-handle = <&tbi2>;
+                       phy-handle = <&phy2>;
+                       phy-connection-type = "rgmii-id";
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi2: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
+               };
+
+               enet3: ethernet@27000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       cell-index = <3>;
+                       device_type = "network";
+                       model = "eTSEC";
+                       compatible = "gianfar";
+                       reg = <0x27000 0x1000>;
+                       ranges = <0x0 0x27000 0x1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <37 2 38 2 39 2>;
+                       interrupt-parent = <&mpic>;
+                       tbi-handle = <&tbi3>;
+                       phy-handle = <&phy3>;
+                       phy-connection-type = "rgmii-id";
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi3: 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 = <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>;
+               };
+
+               global-utilities@e0000 {        //global utilities block
+                       compatible = "fsl,mpc8572-guts";
+                       reg = <0xe0000 0x1000>;
+                       fsl,has-rstcr;
+               };
+
+               msi@41600 {
+                       compatible = "fsl,mpc8572-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>;
+               };
+
+               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>;
+               };
+
+               mpic: pic@40000 {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <2>;
+                       reg = <0x40000 0x40000>;
+                       compatible = "chrp,open-pic";
+                       device_type = "open-pic";
+               };
+       };
+
+       pci0: pcie@fffe08000 {
+               cell-index = <0>;
+               compatible = "fsl,mpc8548-pcie";
+               device_type = "pci";
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0xf 0xffe08000 0 0x1000>;
+               bus-range = <0 255>;
+               ranges = <0x2000000 0x0 0xc0000000 0xc 0x00000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x00010000>;
+               clock-frequency = <33333333>;
+               interrupt-parent = <&mpic>;
+               interrupts = <24 2>;
+               interrupt-map-mask = <0xff00 0x0 0x0 0x7>;
+               interrupt-map = <
+                       /* IDSEL 0x11 func 0 - PCI slot 1 */
+                       0x8800 0x0 0x0 0x1 &mpic 0x2 0x1
+                       0x8800 0x0 0x0 0x2 &mpic 0x3 0x1
+                       0x8800 0x0 0x0 0x3 &mpic 0x4 0x1
+                       0x8800 0x0 0x0 0x4 &mpic 0x1 0x1
+
+                       /* IDSEL 0x11 func 1 - PCI slot 1 */
+                       0x8900 0x0 0x0 0x1 &mpic 0x2 0x1
+                       0x8900 0x0 0x0 0x2 &mpic 0x3 0x1
+                       0x8900 0x0 0x0 0x3 &mpic 0x4 0x1
+                       0x8900 0x0 0x0 0x4 &mpic 0x1 0x1
+
+                       /* IDSEL 0x11 func 2 - PCI slot 1 */
+                       0x8a00 0x0 0x0 0x1 &mpic 0x2 0x1
+                       0x8a00 0x0 0x0 0x2 &mpic 0x3 0x1
+                       0x8a00 0x0 0x0 0x3 &mpic 0x4 0x1
+                       0x8a00 0x0 0x0 0x4 &mpic 0x1 0x1
+
+                       /* IDSEL 0x11 func 3 - PCI slot 1 */
+                       0x8b00 0x0 0x0 0x1 &mpic 0x2 0x1
+                       0x8b00 0x0 0x0 0x2 &mpic 0x3 0x1
+                       0x8b00 0x0 0x0 0x3 &mpic 0x4 0x1
+                       0x8b00 0x0 0x0 0x4 &mpic 0x1 0x1
+
+                       /* IDSEL 0x11 func 4 - PCI slot 1 */
+                       0x8c00 0x0 0x0 0x1 &mpic 0x2 0x1
+                       0x8c00 0x0 0x0 0x2 &mpic 0x3 0x1
+                       0x8c00 0x0 0x0 0x3 &mpic 0x4 0x1
+                       0x8c00 0x0 0x0 0x4 &mpic 0x1 0x1
+
+                       /* IDSEL 0x11 func 5 - PCI slot 1 */
+                       0x8d00 0x0 0x0 0x1 &mpic 0x2 0x1
+                       0x8d00 0x0 0x0 0x2 &mpic 0x3 0x1
+                       0x8d00 0x0 0x0 0x3 &mpic 0x4 0x1
+                       0x8d00 0x0 0x0 0x4 &mpic 0x1 0x1
+
+                       /* IDSEL 0x11 func 6 - PCI slot 1 */
+                       0x8e00 0x0 0x0 0x1 &mpic 0x2 0x1
+                       0x8e00 0x0 0x0 0x2 &mpic 0x3 0x1
+                       0x8e00 0x0 0x0 0x3 &mpic 0x4 0x1
+                       0x8e00 0x0 0x0 0x4 &mpic 0x1 0x1
+
+                       /* IDSEL 0x11 func 7 - PCI slot 1 */
+                       0x8f00 0x0 0x0 0x1 &mpic 0x2 0x1
+                       0x8f00 0x0 0x0 0x2 &mpic 0x3 0x1
+                       0x8f00 0x0 0x0 0x3 &mpic 0x4 0x1
+                       0x8f00 0x0 0x0 0x4 &mpic 0x1 0x1
+
+                       /* IDSEL 0x12 func 0 - PCI slot 2 */
+                       0x9000 0x0 0x0 0x1 &mpic 0x3 0x1
+                       0x9000 0x0 0x0 0x2 &mpic 0x4 0x1
+                       0x9000 0x0 0x0 0x3 &mpic 0x1 0x1
+                       0x9000 0x0 0x0 0x4 &mpic 0x2 0x1
+
+                       /* IDSEL 0x12 func 1 - PCI slot 2 */
+                       0x9100 0x0 0x0 0x1 &mpic 0x3 0x1
+                       0x9100 0x0 0x0 0x2 &mpic 0x4 0x1
+                       0x9100 0x0 0x0 0x3 &mpic 0x1 0x1
+                       0x9100 0x0 0x0 0x4 &mpic 0x2 0x1
+
+                       /* IDSEL 0x12 func 2 - PCI slot 2 */
+                       0x9200 0x0 0x0 0x1 &mpic 0x3 0x1
+                       0x9200 0x0 0x0 0x2 &mpic 0x4 0x1
+                       0x9200 0x0 0x0 0x3 &mpic 0x1 0x1
+                       0x9200 0x0 0x0 0x4 &mpic 0x2 0x1
+
+                       /* IDSEL 0x12 func 3 - PCI slot 2 */
+                       0x9300 0x0 0x0 0x1 &mpic 0x3 0x1
+                       0x9300 0x0 0x0 0x2 &mpic 0x4 0x1
+                       0x9300 0x0 0x0 0x3 &mpic 0x1 0x1
+                       0x9300 0x0 0x0 0x4 &mpic 0x2 0x1
+
+                       /* IDSEL 0x12 func 4 - PCI slot 2 */
+                       0x9400 0x0 0x0 0x1 &mpic 0x3 0x1
+                       0x9400 0x0 0x0 0x2 &mpic 0x4 0x1
+                       0x9400 0x0 0x0 0x3 &mpic 0x1 0x1
+                       0x9400 0x0 0x0 0x4 &mpic 0x2 0x1
+
+                       /* IDSEL 0x12 func 5 - PCI slot 2 */
+                       0x9500 0x0 0x0 0x1 &mpic 0x3 0x1
+                       0x9500 0x0 0x0 0x2 &mpic 0x4 0x1
+                       0x9500 0x0 0x0 0x3 &mpic 0x1 0x1
+                       0x9500 0x0 0x0 0x4 &mpic 0x2 0x1
+
+                       /* IDSEL 0x12 func 6 - PCI slot 2 */
+                       0x9600 0x0 0x0 0x1 &mpic 0x3 0x1
+                       0x9600 0x0 0x0 0x2 &mpic 0x4 0x1
+                       0x9600 0x0 0x0 0x3 &mpic 0x1 0x1
+                       0x9600 0x0 0x0 0x4 &mpic 0x2 0x1
+
+                       /* IDSEL 0x12 func 7 - PCI slot 2 */
+                       0x9700 0x0 0x0 0x1 &mpic 0x3 0x1
+                       0x9700 0x0 0x0 0x2 &mpic 0x4 0x1
+                       0x9700 0x0 0x0 0x3 &mpic 0x1 0x1
+                       0x9700 0x0 0x0 0x4 &mpic 0x2 0x1
+
+                       // IDSEL 0x1c  USB
+                       0xe000 0x0 0x0 0x1 &i8259 0xc 0x2
+                       0xe100 0x0 0x0 0x2 &i8259 0x9 0x2
+                       0xe200 0x0 0x0 0x3 &i8259 0xa 0x2
+                       0xe300 0x0 0x0 0x4 &i8259 0xb 0x2
+
+                       // IDSEL 0x1d  Audio
+                       0xe800 0x0 0x0 0x1 &i8259 0x6 0x2
+
+                       // IDSEL 0x1e Legacy
+                       0xf000 0x0 0x0 0x1 &i8259 0x7 0x2
+                       0xf100 0x0 0x0 0x1 &i8259 0x7 0x2
+
+                       // IDSEL 0x1f IDE/SATA
+                       0xf800 0x0 0x0 0x1 &i8259 0xe 0x2
+                       0xf900 0x0 0x0 0x1 &i8259 0x5 0x2
+
+                       >;
+
+               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 0x10000>;
+                       uli1575@0 {
+                               reg = <0x0 0x0 0x0 0x0 0x0>;
+                               #size-cells = <2>;
+                               #address-cells = <3>;
+                               ranges = <0x2000000 0x0 0xc0000000
+                                         0x2000000 0x0 0xc0000000
+                                         0x0 0x20000000
+
+                                         0x1000000 0x0 0x0
+                                         0x1000000 0x0 0x0
+                                         0x0 0x10000>;
+                               isa@1e {
+                                       device_type = "isa";
+                                       #interrupt-cells = <2>;
+                                       #size-cells = <1>;
+                                       #address-cells = <2>;
+                                       reg = <0xf000 0x0 0x0 0x0 0x0>;
+                                       ranges = <0x1 0x0 0x1000000 0x0 0x0
+                                                 0x1000>;
+                                       interrupt-parent = <&i8259>;
+
+                                       i8259: interrupt-controller@20 {
+                                               reg = <0x1 0x20 0x2
+                                                      0x1 0xa0 0x2
+                                                      0x1 0x4d0 0x2>;
+                                               interrupt-controller;
+                                               device_type = "interrupt-controller";
+                                               #address-cells = <0>;
+                                               #interrupt-cells = <2>;
+                                               compatible = "chrp,iic";
+                                               interrupts = <9 2>;
+                                               interrupt-parent = <&mpic>;
+                                       };
+
+                                       i8042@60 {
+                                               #size-cells = <0>;
+                                               #address-cells = <1>;
+                                               reg = <0x1 0x60 0x1 0x1 0x64 0x1>;
+                                               interrupts = <1 3 12 3>;
+                                               interrupt-parent =
+                                                       <&i8259>;
+
+                                               keyboard@0 {
+                                                       reg = <0x0>;
+                                                       compatible = "pnpPNP,303";
+                                               };
+
+                                               mouse@1 {
+                                                       reg = <0x1>;
+                                                       compatible = "pnpPNP,f03";
+                                               };
+                                       };
+
+                                       rtc@70 {
+                                               compatible = "pnpPNP,b00";
+                                               reg = <0x1 0x70 0x2>;
+                                       };
+
+                                       gpio@400 {
+                                               reg = <0x1 0x400 0x80>;
+                                       };
+                               };
+                       };
+               };
+
+       };
+
+       pci1: pcie@fffe09000 {
+               cell-index = <1>;
+               compatible = "fsl,mpc8548-pcie";
+               device_type = "pci";
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0xf 0xffe09000 0 0x1000>;
+               bus-range = <0 255>;
+               ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x00010000>;
+               clock-frequency = <33333333>;
+               interrupt-parent = <&mpic>;
+               interrupts = <25 2>;
+               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+               interrupt-map = <
+                       /* IDSEL 0x0 */
+                       0000 0x0 0x0 0x1 &mpic 0x4 0x1
+                       0000 0x0 0x0 0x2 &mpic 0x5 0x1
+                       0000 0x0 0x0 0x3 &mpic 0x6 0x1
+                       0000 0x0 0x0 0x4 &mpic 0x7 0x1
+                       >;
+               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 0x10000>;
+               };
+       };
+
+       pci2: pcie@fffe0a000 {
+               cell-index = <2>;
+               compatible = "fsl,mpc8548-pcie";
+               device_type = "pci";
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0xf 0xffe0a000 0 0x1000>;
+               bus-range = <0 255>;
+               ranges = <0x2000000 0x0 0xc0000000 0xc 0x40000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x00010000>;
+               clock-frequency = <33333333>;
+               interrupt-parent = <&mpic>;
+               interrupts = <26 2>;
+               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+               interrupt-map = <
+                       /* IDSEL 0x0 */
+                       0000 0x0 0x0 0x1 &mpic 0x0 0x1
+                       0000 0x0 0x0 0x2 &mpic 0x1 0x1
+                       0000 0x0 0x0 0x3 &mpic 0x2 0x1
+                       0000 0x0 0x0 0x4 &mpic 0x3 0x1
+                       >;
+               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 0x10000>;
+               };
+       };
+};
index fd462efa9e61c0fbc0b7541c0cf58cedc527024f..2bc0c71896538bb06183eb93b27f5fb618bdd4d7 100644 (file)
@@ -6,7 +6,7 @@
  * This dts file allows core0 to have memory, l2, i2c, dma1, global-util, eth0,
  * eth1, crypto, pci0, pci1.
  *
- * Copyright 2007, 2008 Freescale Semiconductor Inc.
+ * Copyright 2007-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
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy0: ethernet-phy@0 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <10 1>;
-                               reg = <0x0>;
-                       };
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <10 1>;
-                               reg = <0x1>;
-                       };
-               };
-
                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>;
                        phy-handle = <&phy0>;
                        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 1>;
+                                       reg = <0x0>;
+                               };
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 1>;
+                                       reg = <0x1>;
+                               };
+                       };
                };
 
                enet1: ethernet@25000 {
                        device_type = "open-pic";
                        protected-sources = <
                        31 32 33 37 38 39       /* enet2 enet3 */
-                       76 77 78 79 27 42       /* dma2 pci2 serial*/
+                       76 77 78 79 26 42       /* dma2 pci2 serial*/
                        0xe0 0xe1 0xe2 0xe3     /* msi */
                        0xe4 0xe5 0xe6 0xe7
                        >;
 
                                  0x1000000 0x0 0x0
                                  0x1000000 0x0 0x0
-                                 0x0 0x100000>;
+                                 0x0 0x10000>;
                        uli1575@0 {
                                reg = <0x0 0x0 0x0 0x0 0x0>;
                                #size-cells = <2>;
 
                                          0x1000000 0x0 0x0
                                          0x1000000 0x0 0x0
-                                         0x0 0x100000>;
+                                         0x0 0x10000>;
                                isa@1e {
                                        device_type = "isa";
                                        #interrupt-cells = <2>;
 
                                  0x1000000 0x0 0x0
                                  0x1000000 0x0 0x0
-                                 0x0 0x100000>;
+                                 0x0 0x10000>;
                };
        };
 };
index e35230f2ac936041573cc2899cc952e3fe9761b4..159cb3a875f0b13bf6773e7f41c1df29c69e7c3d 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Please note to add "-b 1" for core1's dts compiling.
  *
- * Copyright 2007, 2008 Freescale Semiconductor Inc.
+ * Copyright 2007-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
                        protected-sources = <
                        18 16 10 42 45 58       /* MEM L2 mdio serial crypto */
                        29 30 34 35 36 40       /* enet0 enet1 */
-                       24 26 20 21 22 23       /* pcie0 pcie1 dma1 */
+                       24 25 20 21 22 23       /* pci0 pci1 dma1 */
                        43                      /* i2c */
                        0x1 0x2 0x3 0x4         /* pci slot */
                        0x9 0xa 0xb 0xc         /* usb */
 
                                  0x1000000 0x0 0x0
                                  0x1000000 0x0 0x0
-                                 0x0 0x100000>;
+                                 0x0 0x10000>;
                };
        };
 };
index f724d72c7b92db819d2b9229da620938ba6c0104..1bd3ebe114377baf5c0c748e05f5ee4a6a31bb87 100644 (file)
                        codec-handle = <&cs4270>;
                        fsl,playback-dma = <&dma00>;
                        fsl,capture-dma = <&dma01>;
+                       fsl,fifo-depth = <8>;
                };
 
                ssi@16100 {
                        reg = <0x16100 0x100>;
                        interrupt-parent = <&mpic>;
                        interrupts = <63 2>;
+                       fsl,fifo-depth = <8>;
                };
 
                dma@21300 {
index 4481532cbe7751c95dcb6b49a816a8640ffb09d5..d72beb192460043e81e54e34270f6bee081011d3 100644 (file)
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy0: ethernet-phy@0 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <10 1>;
-                               reg = <0>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <10 1>;
-                               reg = <1>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy2: ethernet-phy@2 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <10 1>;
-                               reg = <2>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy3: ethernet-phy@3 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <10 1>;
-                               reg = <3>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@26520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x26520 0x20>;
-
-                       tbi2: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@27520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x27520 0x20>;
-
-                       tbi3: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        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 = <&phy0>;
                        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 1>;
+                                       reg = <0>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 1>;
+                                       reg = <1>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy2: ethernet-phy@2 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 1>;
+                                       reg = <2>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy3: ethernet-phy@3 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 1>;
+                                       reg = <3>;
+                                       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 = "TSEC";
                        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 = <&tbi1>;
                        phy-handle = <&phy1>;
                        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";
+                               };
+                       };
                };
                
                enet2: ethernet@26000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <2>;
                        device_type = "network";
                        model = "TSEC";
                        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 = <&tbi2>;
                        phy-handle = <&phy2>;
                        phy-connection-type = "rgmii-id";
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi2: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
                };
 
                enet3: ethernet@27000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <3>;
                        device_type = "network";
                        model = "TSEC";
                        compatible = "gianfar";
                        reg = <0x27000 0x1000>;
+                       ranges = <0x0 0x27000 0x1000>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <37 2 38 2 39 2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi3>;
                        phy-handle = <&phy3>;
                        phy-connection-type = "rgmii-id";
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi3: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
                };
 
                serial0: serial@4500 {
index be2c11ca05944de59a21a936ee4d08f8439a771b..895834713894f1baf0ae2bb4ea50ee7ff1458dca 100644 (file)
@@ -19,6 +19,7 @@
        compatible = "phytec,pcm030";
        #address-cells = <1>;
        #size-cells = <1>;
+       interrupt-parent = <&mpc5200_pic>;
 
        cpus {
                #address-cells = <1>;
                        reg = <0>;
                        d-cache-line-size = <32>;
                        i-cache-line-size = <32>;
-                       d-cache-size = <0x4000>;        /* L1, 16K          */
-                       i-cache-size = <0x4000>;        /* L1, 16K          */
-                       timebase-frequency = <0>;       /* From Bootloader  */
-                       bus-frequency = <0>;            /* From Bootloader  */
-                       clock-frequency = <0>;          /* From Bootloader  */
+                       d-cache-size = <0x4000>;        // L1, 16K
+                       i-cache-size = <0x4000>;        // L1, 16K
+                       timebase-frequency = <0>;       // from bootloader
+                       bus-frequency = <0>;            // from bootloader
+                       clock-frequency = <0>;          // from bootloader
                };
        };
 
        memory {
                device_type = "memory";
-               reg = <0x00000000 0x04000000>;  /* 64MB */
+               reg = <0x00000000 0x04000000>;  // 64MB
        };
 
        soc5200@f0000000 {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "fsl,mpc5200b-immr";
-               ranges = <0x0 0xf0000000 0x0000c000>;
-               bus-frequency = <0>;            /* From bootloader */
-               system-frequency = <0>;         /* From bootloader */
+               ranges = <0 0xf0000000 0x0000c000>;
+               bus-frequency = <0>;            // from bootloader
+               system-frequency = <0>;         // from bootloader
 
                cdm@200 {
                        compatible = "fsl,mpc5200b-cdm","fsl,mpc5200-cdm";
                };
 
                mpc5200_pic: interrupt-controller@500 {
-                       /* 5200 interrupts are encoded into two levels; */
+                       // 5200 interrupts are encoded into two levels;
                        interrupt-controller;
                        #interrupt-cells = <3>;
-                       device_type = "interrupt-controller";
                        compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
                        reg = <0x500 0x80>;
                };
 
-               timer@600 {     /* General Purpose Timer */
+               timer@600 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       cell-index = <0>;
                        reg = <0x600 0x10>;
-                       interrupts = <0x1 0x9 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <1 9 0>;
                        fsl,has-wdt;
                };
 
-               timer@610 {     /* General Purpose Timer */
+               timer@610 {     // General Purpose Timer
                        compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       cell-index = <1>;
                        reg = <0x610 0x10>;
-                       interrupts = <0x1 0xa 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <1 10 0>;
                };
 
-               gpt2: timer@620 { /* General Purpose Timer in GPIO mode */
+               gpt2: timer@620 {       // General Purpose Timer in GPIO mode
                        compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
-                       cell-index = <2>;
                        reg = <0x620 0x10>;
-                       interrupts = <0x1 0xb 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <1 11 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
-               gpt3: timer@630 { /* General Purpose Timer in GPIO mode */
+               gpt3: timer@630 {       // General Purpose Timer in GPIO mode
                        compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
-                       cell-index = <3>;
                        reg = <0x630 0x10>;
-                       interrupts = <0x1 0xc 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <1 12 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
-               gpt4: timer@640 { /* General Purpose Timer in GPIO mode */
+               gpt4: timer@640 {       // General Purpose Timer in GPIO mode
                        compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
-                       cell-index = <4>;
                        reg = <0x640 0x10>;
-                       interrupts = <0x1 0xd 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <1 13 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
-               gpt5: timer@650 { /* General Purpose Timer in GPIO mode */
+               gpt5: timer@650 {       // General Purpose Timer in GPIO mode
                        compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
-                       cell-index = <5>;
                        reg = <0x650 0x10>;
-                       interrupts = <0x1 0xe 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <1 14 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
-               gpt6: timer@660 { /* General Purpose Timer in GPIO mode */
+               gpt6: timer@660 {       // General Purpose Timer in GPIO mode
                        compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
-                       cell-index = <6>;
                        reg = <0x660 0x10>;
-                       interrupts = <0x1 0xf 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <1 15 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
-               gpt7: timer@670 { /* General Purpose Timer in GPIO mode */
+               gpt7: timer@670 {       // General Purpose Timer in GPIO mode
                        compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
-                       cell-index = <7>;
                        reg = <0x670 0x10>;
-                       interrupts = <0x1 0x10 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <1 16 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
                rtc@800 {       // Real time clock
                        compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc";
                        reg = <0x800 0x100>;
-                       interrupts = <0x1 0x5 0x0 0x1 0x6 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <1 5 0 1 6 0>;
                };
 
                can@900 {
                        compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
-                       cell-index = <0>;
-                       interrupts = <0x2 0x11 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <2 17 0>;
                        reg = <0x900 0x80>;
                };
 
                can@980 {
                        compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
-                       cell-index = <1>;
-                       interrupts = <0x2 0x12 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <2 18 0>;
                        reg = <0x980 0x80>;
                };
 
                gpio_simple: gpio@b00 {
                        compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
                        reg = <0xb00 0x40>;
-                       interrupts = <0x1 0x7 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <1 7 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
-               gpio_wkup: gpio-wkup@c00 {
+               gpio_wkup: gpio@c00 {
                        compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
                        reg = <0xc00 0x40>;
-                       interrupts = <0x1 0x8 0x0 0x0 0x3 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <1 8 0 0 3 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
                spi@f00 {
                        compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
                        reg = <0xf00 0x20>;
-                       interrupts = <0x2 0xd 0x0 0x2 0xe 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <2 13 0 2 14 0>;
                };
 
                usb@1000 {
                        compatible = "fsl,mpc5200b-ohci","fsl,mpc5200-ohci","ohci-be";
                        reg = <0x1000 0xff>;
-                       interrupts = <0x2 0x6 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <2 6 0>;
                };
 
                dma-controller@1200 {
-                       device_type = "dma-controller";
                        compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
                        reg = <0x1200 0x80>;
-                       interrupts = <0x3 0x0 0x0  0x3 0x1 0x0  0x3 0x2 0x0  0x3 0x3 0x0
-                                     0x3 0x4 0x0  0x3 0x5 0x0  0x3 0x6 0x0  0x3 0x7 0x0
-                                     0x3 0x8 0x0  0x3 0x9 0x0  0x3 0xa 0x0  0x3 0xb 0x0
-                                     0x3 0xc 0x0  0x3 0xd 0x0  0x3 0xe 0x0  0x3 0xf 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
+                                     3 4 0  3 5 0  3 6 0  3 7 0
+                                     3 8 0  3 9 0  3 10 0  3 11 0
+                                     3 12 0  3 13 0  3 14 0  3 15 0>;
                };
 
                xlb@1f00 {
                };
 
                ac97@2000 { /* PSC1 in ac97 mode */
-                       device_type = "sound";
                        compatible = "mpc5200b-psc-ac97","fsl,mpc5200b-psc-ac97";
                        cell-index = <0>;
                        reg = <0x2000 0x100>;
-                       interrupts = <0x2 0x2 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <2 1 0>;
                };
 
                /* PSC2 port is used by CAN1/2 */
 
                serial@2400 { /* PSC3 in UART mode */
-                       device_type = "serial";
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       port-number = <0>;
                        cell-index = <2>;
                        reg = <0x2400 0x100>;
-                       interrupts = <0x2 0x3 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <2 3 0>;
                };
 
                /* PSC4 is ??? */
                /* PSC5 is ??? */
 
                serial@2c00 { /* PSC6 in UART mode */
-                       device_type = "serial";
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       port-number = <1>;
                        cell-index = <5>;
                        reg = <0x2c00 0x100>;
-                       interrupts = <0x2 0x4 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <2 4 0>;
                };
 
                ethernet@3000 {
-                       device_type = "network";
                        compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
                        reg = <0x3000 0x400>;
-                       local-mac-address = [00 00 00 00 00 00];
-                       interrupts = <0x2 0x5 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <2 5 0>;
                        phy-handle = <&phy0>;
                };
 
                mdio@3000 {
                        #address-cells = <1>;
                        #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-mdio", "fsl,mpc5200-mdio";
-                       reg = <0x3000 0x400>;   /* fec range, since we need to setup fec interrupts */
-                       interrupts = <0x2 0x5 0x0>;     /* these are for "mii command finished", not link changes & co. */
-                       interrupt-parent = <&mpc5200_pic>;
-
-                       phy0:ethernet-phy@0 {
-                               device_type = "ethernet-phy";
-                               reg = <0x0>;
+                       compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
+                       reg = <0x3000 0x400>;   // fec range, since we need to setup fec interrupts
+                       interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
+
+                       phy0: ethernet-phy@0 {
+                               reg = <0>;
                        };
                };
 
                ata@3a00 {
-                       device_type = "ata";
                        compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
                        reg = <0x3a00 0x100>;
-                       interrupts = <0x2 0x7 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <2 7 0>;
                };
 
                i2c@3d00 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       cell-index = <0>;
                        reg = <0x3d00 0x40>;
-                       interrupts = <0x2 0xf 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <2 15 0>;
                        fsl5200-clocking;
                };
 
                        #address-cells = <1>;
                        #size-cells = <0>;
                        compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       cell-index = <1>;
                        reg = <0x3d40 0x40>;
-                       interrupts = <0x2 0x10 0x0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       interrupts = <2 16 0>;
                        fsl5200-clocking;
                        rtc@51 {
                                compatible = "nxp,pcf8563";
                };
 
                sram@8000 {
-                       compatible = "fsl,mpc5200b-sram","fsl,mpc5200-sram","sram";
+                       compatible = "fsl,mpc5200b-sram","fsl,mpc5200-sram";
                        reg = <0x8000 0x4000>;
                };
 
                device_type = "pci";
                compatible = "fsl,mpc5200b-pci","fsl,mpc5200-pci";
                reg = <0xf0000d00 0x100>;
-               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
-               interrupt-map = <0xc000 0x0 0x0 0x1 &mpc5200_pic 0x0 0x0 0x3 /* 1st slot */
-                                0xc000 0x0 0x0 0x2 &mpc5200_pic 0x1 0x1 0x3
-                                0xc000 0x0 0x0 0x3 &mpc5200_pic 0x1 0x2 0x3
-                                0xc000 0x0 0x0 0x4 &mpc5200_pic 0x1 0x3 0x3
-
-                                0xc800 0x0 0x0 0x1 &mpc5200_pic 0x1 0x1 0x3 /* 2nd slot */
-                                0xc800 0x0 0x0 0x2 &mpc5200_pic 0x1 0x2 0x3
-                                0xc800 0x0 0x0 0x3 &mpc5200_pic 0x1 0x3 0x3
-                                0xc800 0x0 0x0 0x4 &mpc5200_pic 0x0 0x0 0x3>;
+               interrupt-map-mask = <0xf800 0 0 7>;
+               interrupt-map = <0xc000 0 0 1 &mpc5200_pic 0 0 3 // 1st slot
+                                0xc000 0 0 2 &mpc5200_pic 1 1 3
+                                0xc000 0 0 3 &mpc5200_pic 1 2 3
+                                0xc000 0 0 4 &mpc5200_pic 1 3 3
+
+                                0xc800 0 0 1 &mpc5200_pic 1 1 3 // 2nd slot
+                                0xc800 0 0 2 &mpc5200_pic 1 2 3
+                                0xc800 0 0 3 &mpc5200_pic 1 3 3
+                                0xc800 0 0 4 &mpc5200_pic 0 0 3>;
                clock-frequency = <0>; // From boot loader
-               interrupts = <0x2 0x8 0x0 0x2 0x9 0x0 0x2 0xa 0x0>;
-               interrupt-parent = <&mpc5200_pic>;
+               interrupts = <2 8 0 2 9 0 2 10 0>;
                bus-range = <0 0>;
-               ranges = <0x42000000 0x0 0x80000000 0x80000000 0x0 0x20000000
-                         0x02000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000
-                         0x01000000 0x0 0x00000000 0xb0000000 0x0 0x01000000>;
+               ranges = <0x42000000 0 0x80000000 0x80000000 0 0x20000000
+                         0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
+                         0x01000000 0 0x00000000 0xb0000000 0 0x01000000>;
        };
 };
diff --git a/arch/powerpc/boot/dts/pcm032.dts b/arch/powerpc/boot/dts/pcm032.dts
new file mode 100644 (file)
index 0000000..0300426
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * phyCORE-MPC5200B-IO (pcm032) board Device Tree Source
+ *
+ * Copyright (C) 2006-2009 Pengutronix
+ * Sascha Hauer <s.hauer@pengutronix.de>
+ * Juergen Beisert <j.beisert@pengutronix.de>
+ * Wolfram Sang <w.sang@pengutronix.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.
+ */
+
+/dts-v1/;
+
+/ {
+       model = "phytec,pcm032";
+       compatible = "phytec,pcm032";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       interrupt-parent = <&mpc5200_pic>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,5200@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <32>;
+                       i-cache-line-size = <32>;
+                       d-cache-size = <0x4000>;        // L1, 16K
+                       i-cache-size = <0x4000>;        // L1, 16K
+                       timebase-frequency = <0>;       // from bootloader
+                       bus-frequency = <0>;            // from bootloader
+                       clock-frequency = <0>;          // from bootloader
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x00000000 0x08000000>;  // 128MB
+       };
+
+       soc5200@f0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc5200b-immr";
+               ranges = <0 0xf0000000 0x0000c000>;
+               bus-frequency = <0>;            // from bootloader
+               system-frequency = <0>;         // from bootloader
+
+               cdm@200 {
+                       compatible = "fsl,mpc5200b-cdm","fsl,mpc5200-cdm";
+                       reg = <0x200 0x38>;
+               };
+
+               mpc5200_pic: interrupt-controller@500 {
+                       // 5200 interrupts are encoded into two levels;
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+                       compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
+                       reg = <0x500 0x80>;
+               };
+
+               timer@600 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x600 0x10>;
+                       interrupts = <1 9 0>;
+                       fsl,has-wdt;
+               };
+
+               timer@610 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x610 0x10>;
+                       interrupts = <1 10 0>;
+               };
+
+               gpt2: timer@620 {       // General Purpose Timer in GPIO mode
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x620 0x10>;
+                       interrupts = <1 11 0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpt3: timer@630 {       // General Purpose Timer in GPIO mode
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x630 0x10>;
+                       interrupts = <1 12 0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpt4: timer@640 {       // General Purpose Timer in GPIO mode
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x640 0x10>;
+                       interrupts = <1 13 0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpt5: timer@650 {       // General Purpose Timer in GPIO mode
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x650 0x10>;
+                       interrupts = <1 14 0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpt6: timer@660 {       // General Purpose Timer in GPIO mode
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x660 0x10>;
+                       interrupts = <1 15 0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpt7: timer@670 {       // General Purpose Timer in GPIO mode
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x670 0x10>;
+                       interrupts = <1 16 0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               rtc@800 {       // Real time clock
+                       compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc";
+                       reg = <0x800 0x100>;
+                       interrupts = <1 5 0 1 6 0>;
+               };
+
+               can@900 {
+                       compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
+                       interrupts = <2 17 0>;
+                       reg = <0x900 0x80>;
+               };
+
+               can@980 {
+                       compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
+                       interrupts = <2 18 0>;
+                       reg = <0x980 0x80>;
+               };
+
+               gpio_simple: gpio@b00 {
+                       compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
+                       reg = <0xb00 0x40>;
+                       interrupts = <1 7 0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpio_wkup: gpio@c00 {
+                       compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
+                       reg = <0xc00 0x40>;
+                       interrupts = <1 8 0 0 3 0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               spi@f00 {
+                       compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
+                       reg = <0xf00 0x20>;
+                       interrupts = <2 13 0 2 14 0>;
+               };
+
+               usb@1000 {
+                       compatible = "fsl,mpc5200b-ohci","fsl,mpc5200-ohci","ohci-be";
+                       reg = <0x1000 0xff>;
+                       interrupts = <2 6 0>;
+               };
+
+               dma-controller@1200 {
+                       compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
+                       reg = <0x1200 0x80>;
+                       interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
+                                     3 4 0  3 5 0  3 6 0  3 7 0
+                                     3 8 0  3 9 0  3 10 0  3 11 0
+                                     3 12 0  3 13 0  3 14 0  3 15 0>;
+               };
+
+               xlb@1f00 {
+                       compatible = "fsl,mpc5200b-xlb","fsl,mpc5200-xlb";
+                       reg = <0x1f00 0x100>;
+               };
+
+               ac97@2000 {     /* PSC1 is ac97 */
+                       compatible = "fsl,mpc5200b-psc-ac97","fsl,mpc5200-psc-ac97";
+                       cell-index = <0>;
+                       reg = <0x2000 0x100>;
+                       interrupts = <2 1 0>;
+               };
+
+               /* PSC2 port is used by CAN1/2 */
+
+               serial@2400 { /* PSC3 in UART mode */
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+                       cell-index = <2>;
+                       reg = <0x2400 0x100>;
+                       interrupts = <2 3 0>;
+               };
+
+               /* PSC4 is ??? */
+
+               /* PSC5 is ??? */
+
+               serial@2c00 { /* PSC6 in UART mode */
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+                       cell-index = <5>;
+                       reg = <0x2c00 0x100>;
+                       interrupts = <2 4 0>;
+               };
+
+               ethernet@3000 {
+                       compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
+                       reg = <0x3000 0x400>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <2 5 0>;
+                       phy-handle = <&phy0>;
+               };
+
+               mdio@3000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
+                       reg = <0x3000 0x400>;   // fec range, since we need to setup fec interrupts
+                       interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
+
+                       phy0: ethernet-phy@0 {
+                               reg = <0>;
+                       };
+               };
+
+               ata@3a00 {
+                       compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
+                       reg = <0x3a00 0x100>;
+                       interrupts = <2 7 0>;
+               };
+
+               i2c@3d00 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
+                       reg = <0x3d00 0x40>;
+                       interrupts = <2 15 0>;
+                       fsl5200-clocking;
+               };
+
+               i2c@3d40 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
+                       reg = <0x3d40 0x40>;
+                       interrupts = <2 16 0>;
+                       fsl5200-clocking;
+                       rtc@51 {
+                               compatible = "nxp,pcf8563";
+                               reg = <0x51>;
+                       };
+                       eeprom@52 {
+                               compatible = "at24,24c32";
+                               reg = <0x52>;
+                       };
+               };
+
+               sram@8000 {
+                       compatible = "fsl,mpc5200b-sram","fsl,mpc5200-sram";
+                       reg = <0x8000 0x4000>;
+               };
+       };
+
+       pci@f0000d00 {
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               device_type = "pci";
+               compatible = "fsl,mpc5200b-pci","fsl,mpc5200-pci";
+               reg = <0xf0000d00 0x100>;
+               interrupt-map-mask = <0xf800 0 0 7>;
+               interrupt-map = <0xc000 0 0 1 &mpc5200_pic 0 0 3 // 1st slot
+                                0xc000 0 0 2 &mpc5200_pic 1 1 3
+                                0xc000 0 0 3 &mpc5200_pic 1 2 3
+                                0xc000 0 0 4 &mpc5200_pic 1 3 3
+
+                                0xc800 0 0 1 &mpc5200_pic 1 1 3 // 2nd slot
+                                0xc800 0 0 2 &mpc5200_pic 1 2 3
+                                0xc800 0 0 3 &mpc5200_pic 1 3 3
+                                0xc800 0 0 4 &mpc5200_pic 0 0 3>;
+               clock-frequency = <0>; // From boot loader
+               interrupts = <2 8 0 2 9 0 2 10 0>;
+               bus-range = <0 0>;
+               ranges = <0x42000000 0 0x80000000 0x80000000 0 0x20000000
+                         0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
+                         0x01000000 0 0x00000000 0xb0000000 0 0x01000000>;
+       };
+
+       localbus {
+               compatible = "fsl,mpc5200b-lpb","fsl,mpc5200-lpb","simple-bus";
+
+               #address-cells = <2>;
+               #size-cells = <1>;
+
+               ranges = <0 0 0xfe000000 0x02000000
+                         1 0 0xfc000000 0x02000000
+                         2 0 0xfbe00000 0x00200000
+                         3 0 0xf9e00000 0x02000000
+                         4 0 0xf7e00000 0x02000000
+                         5 0 0xe6000000 0x02000000
+                         6 0 0xe8000000 0x02000000
+                         7 0 0xea000000 0x02000000>;
+
+               flash@0,0 {
+                       compatible = "cfi-flash";
+                       reg = <0 0 0x02000000>;
+                       bank-width = <4>;
+                       #size-cells = <1>;
+                       #address-cells = <1>;
+
+                       partition@0 {
+                               label = "ubootl";
+                               reg = <0x00000000 0x00040000>;
+                       };
+                       partition@40000 {
+                               label = "kernel";
+                               reg = <0x00040000 0x001c0000>;
+                       };
+                       partition@200000 {
+                               label = "jffs2";
+                               reg = <0x00200000 0x01d00000>;
+                       };
+                       partition@1f00000 {
+                               label = "uboot";
+                               reg = <0x01f00000 0x00040000>;
+                       };
+                       partition@1f40000 {
+                               label = "env";
+                               reg = <0x01f40000 0x00040000>;
+                       };
+                       partition@1f80000 {
+                               label = "oftree";
+                               reg = <0x01f80000 0x00040000>;
+                       };
+                       partition@1fc0000 {
+                               label = "space";
+                               reg = <0x01fc0000 0x00040000>;
+                       };
+               };
+
+               sram@2,0 {
+                       compatible = "mtd-ram";
+                       reg = <2 0 0x00200000>;
+                       bank-width = <2>;
+               };
+
+                /*
+                * example snippets for FPGA
+                *
+                * fpga@3,0 {
+                *         compatible = "fpga_driver";
+                *         reg = <3 0 0x02000000>;
+                *         bank-width = <4>;
+                * };
+                *
+                * fpga@4,0 {
+                *         compatible = "fpga_driver";
+                *         reg = <4 0 0x02000000>;
+                *         bank-width = <4>;
+                * };
+                 */
+
+                /*
+                * example snippets for free chipselects
+                 *
+                * device@5,0 {
+                *         compatible = "custom_driver";
+                *         reg = <5 0 0x02000000>;
+                * };
+                 *
+                * device@6,0 {
+                *         compatible = "custom_driver";
+                *         reg = <6 0 0x02000000>;
+                * };
+                 *
+                * device@7,0 {
+                *         compatible = "custom_driver";
+                *         reg = <7 0 0x02000000>;
+                * };
+                 */
+       };
+};
+
diff --git a/arch/powerpc/boot/dts/redwood.dts b/arch/powerpc/boot/dts/redwood.dts
new file mode 100644 (file)
index 0000000..ad402c4
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Device Tree Source for AMCC Redwood(460SX)
+ *
+ * Copyright 2008 AMCC <tmarri@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,redwood";
+       compatible = "amcc,redwood";
+       dcr-parent = <&{/cpus/cpu@0}>;
+
+       aliases {
+               ethernet0 = &EMAC0;
+               serial0 = &UART0;
+       };
+
+       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 = <0x0000000 0x00000000 0x04000000>;
+                                       #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>;
+                                       };
+                               };
+                       };
+
+                       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>;
+                       };
+
+                       RGMII0: emac-rgmii@ef600900 {
+                               compatible = "ibm,rgmii-460sx", "ibm,rgmii";
+                               reg = <0xef600900 0x00000008>;
+                       };
+
+                       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>;
+                               has-inverted-stacr-oc;
+                               has-new-stacr-staopc;
+                       };
+
+               };
+
+       };
+       chosen {
+               linux,stdout-path = "/plb/opb/serial@ef600200";
+       };
+
+};
index 8d365a57ebc122bbc4aefce181a30c1ae638daa7..a36dbbc48694749aefc10d74fdda78270bff3245 100644 (file)
                        phy_type = "ulpi";
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy0: ethernet-phy@19 {
-                               interrupt-parent = <&ipic>;
-                               interrupts = <20 0x8>;
-                               reg = <0x19>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy1: ethernet-phy@1a {
-                               interrupt-parent = <&ipic>;
-                               interrupts = <21 0x8>;
-                               reg = <0x1a>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        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>;
                        interrupt-parent = <&ipic>;
                        tbi-handle = <&tbi0>;
                        phy-handle = <&phy0>;
                        linux,network-index = <0>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@19 {
+                                       interrupt-parent = <&ipic>;
+                                       interrupts = <20 0x8>;
+                                       reg = <0x19>;
+                                       device_type = "ethernet-phy";
+                               };
+
+                               phy1: ethernet-phy@1a {
+                                       interrupt-parent = <&ipic>;
+                                       interrupts = <21 0x8>;
+                                       reg = <0x1a>;
+                                       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 = "TSEC";
                        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>;
                        interrupt-parent = <&ipic>;
                        tbi-handle = <&tbi1>;
                        phy-handle = <&phy1>;
                        linux,network-index = <1>;
+
+                       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 {
index 2baf4a51f224a9c7a63792182a0d837d6fad4624..9c5079fec4f23b3750e671d2b39bf34e3a069d8a 100644 (file)
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy0: ethernet-phy@19 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <0x6 0x1>;
-                               reg = <0x19>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy1: ethernet-phy@1a {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <0x7 0x1>;
-                               reg = <0x1a>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                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 = <0x1d 0x2 0x1e 0x2 0x22 0x2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi0>;
                        phy-handle = <&phy0>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@19 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <0x6 0x1>;
+                                       reg = <0x19>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy1: ethernet-phy@1a {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <0x7 0x1>;
+                                       reg = <0x1a>;
+                                       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 = <0x23 0x2 0x24 0x2 0x28 0x2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi1>;
                        phy-handle = <&phy1>;
+
+                       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 {
index 01542f7062abf7d6cb428ac9eadefbd8e117adab..b772405a9a0a2f70ef0821d7474ce9b9312c4e4d 100644 (file)
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-                       phy0: ethernet-phy@19 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <0x6 0x1>;
-                               reg = <0x19>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy1: ethernet-phy@1a {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <0x7 0x1>;
-                               reg = <0x1a>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy2: ethernet-phy@1b {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <0x8 0x1>;
-                               reg = <0x1b>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy3: ethernet-phy@1c {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <0x8 0x1>;
-                               reg = <0x1c>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        compatible = "gianfar";
                        reg = <0x24000 0x1000>;
+                       ranges = <0x0 0x24000 0x1000>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi0>;
                        phy-handle = <&phy0>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+                               phy0: ethernet-phy@19 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <0x6 0x1>;
+                                       reg = <0x19>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy1: ethernet-phy@1a {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <0x7 0x1>;
+                                       reg = <0x1a>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy2: ethernet-phy@1b {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <0x8 0x1>;
+                                       reg = <0x1b>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy3: ethernet-phy@1c {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <0x8 0x1>;
+                                       reg = <0x1c>;
+                                       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 = "TSEC";
                        compatible = "gianfar";
                        reg = <0x25000 0x1000>;
+                       ranges = <0x0 0x25000 0x1000>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <0x23 0x2 0x24 0x2 0x28 0x2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi1>;
                        phy-handle = <&phy1>;
+
+                       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";
+                               };
+                       };
                };
 
                mpic: pic@40000 {
index 36db981548e4754768ecbc4c69f780d4a7b46381..e3e914e78caa2e6fdec7f5181e6a2e0a39d97a72 100644 (file)
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy0: ethernet-phy@1f {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <10 1>;
-                               reg = <0x1f>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy1: ethernet-phy@0 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <10 1>;
-                               reg = <0>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy2: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <10 1>;
-                               reg = <1>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy3: ethernet-phy@2 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <10 1>;
-                               reg = <2>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@26520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x26520 0x20>;
-
-                       tbi2: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@27520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x27520 0x20>;
-
-                       tbi3: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        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 = <&phy0>;
                        phy-connection-type = "rgmii-id";
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@1f {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 1>;
+                                       reg = <0x1f>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy1: ethernet-phy@0 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 1>;
+                                       reg = <0>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy2: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 1>;
+                                       reg = <1>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy3: ethernet-phy@2 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 1>;
+                                       reg = <2>;
+                                       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 = "TSEC";
                        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 = <&tbi1>;
                        phy-handle = <&phy1>;
                        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";
+                               };
+                       };
                };
 
                enet2: ethernet@26000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <2>;
                        device_type = "network";
                        model = "TSEC";
                        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 = <&tbi2>;
                        phy-handle = <&phy2>;
                        phy-connection-type = "rgmii-id";
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi2: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
                };
 
                enet3: ethernet@27000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <3>;
                        device_type = "network";
                        model = "TSEC";
                        compatible = "gianfar";
                        reg = <0x27000 0x1000>;
+                       ranges = <0x0 0x27000 0x1000>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <37 2 38 2 39 2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi3>;
                        phy-handle = <&phy3>;
                        phy-connection-type = "rgmii-id";
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi3: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
                };
 
                serial0: serial@4500 {
diff --git a/arch/powerpc/boot/dts/socrates.dts b/arch/powerpc/boot/dts/socrates.dts
new file mode 100644 (file)
index 0000000..b8d0fc6
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * Device Tree Source for the Socrates board (MPC8544).
+ *
+ * Copyright (c) 2008 Emcraft Systems.
+ * Sergei Poselenov, <sposelenov@emcraft.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.
+ */
+
+/dts-v1/;
+
+/ {
+       model = "abb,socrates";
+       compatible = "abb,socrates";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       aliases {
+               ethernet0 = &enet0;
+               ethernet1 = &enet1;
+               serial0 = &serial0;
+               serial1 = &serial1;
+               pci0 = &pci0;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,8544@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <32>;
+                       i-cache-line-size = <32>;
+                       d-cache-size = <0x8000>;        // L1, 32K
+                       i-cache-size = <0x8000>;        // L1, 32K
+                       timebase-frequency = <0>;
+                       bus-frequency = <0>;
+                       clock-frequency = <0>;
+                       next-level-cache = <&L2>;
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x00000000 0x00000000>;  // Filled in by U-Boot
+       };
+
+       soc8544@e0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               ranges = <0x00000000 0xe0000000 0x00100000>;
+               reg = <0xe0000000 0x00001000>;  // CCSRBAR 1M
+               bus-frequency = <0>;            // Filled in by U-Boot
+               compatible = "fsl,mpc8544-immr", "simple-bus";
+
+               memory-controller@2000 {
+                       compatible = "fsl,mpc8544-memory-controller";
+                       reg = <0x2000 0x1000>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <18 2>;
+               };
+
+               L2: l2-cache-controller@20000 {
+                       compatible = "fsl,mpc8544-l2-cache-controller";
+                       reg = <0x20000 0x1000>;
+                       cache-line-size = <32>;
+                       cache-size = <0x40000>; // L2, 256K
+                       interrupt-parent = <&mpic>;
+                       interrupts = <16 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;
+
+                       dtt@28 {
+                               compatible = "winbond,w83782d";
+                               reg = <0x28>;
+                       };
+                       rtc@32 {
+                               compatible = "epson,rx8025";
+                               reg = <0x32>;
+                               interrupts = <7 1>;
+                               interrupt-parent = <&mpic>;
+                       };
+                       dtt@4c {
+                               compatible = "dallas,ds75";
+                               reg = <0x4c>;
+                       };
+                       ts@4a {
+                               compatible = "ti,tsc2003";
+                               reg = <0x4a>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <8 1>;
+                       };
+               };
+
+               i2c@3100 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       cell-index = <1>;
+                       compatible = "fsl-i2c";
+                       reg = <0x3100 0x100>;
+                       interrupts = <43 2>;
+                       interrupt-parent = <&mpic>;
+                       dfsrr;
+               };
+
+               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>;
+                       phy-handle = <&phy0>;
+                       tbi-handle = <&tbi0>;
+                       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 = <0 1>;
+                                       reg = <0>;
+                               };
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <0 1>;
+                                       reg = <1>;
+                               };
+                               tbi0: tbi-phy@11 {
+                                       reg = <0x11>;
+                               };
+                       };
+               };
+
+               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>;
+                       phy-handle = <&phy1>;
+                       tbi-handle = <&tbi1>;
+                       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>;
+                               };
+                       };
+               };
+
+               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>;
+               };
+
+               global-utilities@e0000 {        //global utilities block
+                       compatible = "fsl,mpc8548-guts";
+                       reg = <0xe0000 0x1000>;
+                       fsl,has-rstcr;
+               };
+
+               mpic: pic@40000 {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <2>;
+                       reg = <0x40000 0x40000>;
+                       compatible = "chrp,open-pic";
+                       device_type = "open-pic";
+               };
+       };
+
+
+       localbus {
+               compatible = "fsl,mpc8544-localbus",
+                            "fsl,pq3-localbus",
+                            "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               reg = <0xe0005000 0x40>;
+
+               ranges = <0 0 0xfc000000 0x04000000
+                         2 0 0xc8000000 0x04000000
+                         3 0 0xc0000000 0x00100000
+                       >; /* Overwritten by U-Boot */
+
+               nor_flash@0,0 {
+                       compatible = "amd,s29gl256n", "cfi-flash";
+                       bank-width = <2>;
+                       reg = <0x0 0x000000 0x4000000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       partition@0 {
+                               label = "kernel";
+                               reg = <0x0 0x1e0000>;
+                               read-only;
+                       };
+                       partition@1e0000 {
+                               label = "dtb";
+                               reg = <0x1e0000 0x20000>;
+                       };
+                       partition@200000 {
+                               label = "root";
+                               reg = <0x200000 0x200000>;
+                       };
+                       partition@400000 {
+                               label = "user";
+                               reg = <0x400000 0x3b80000>;
+                       };
+                       partition@3f80000 {
+                               label = "env";
+                               reg = <0x3f80000 0x40000>;
+                               read-only;
+                       };
+                       partition@3fc0000 {
+                               label = "u-boot";
+                               reg = <0x3fc0000 0x40000>;
+                               read-only;
+                       };
+               };
+
+               display@2,0 {
+                       compatible = "fujitsu,lime";
+                       reg = <2 0x0 0x4000000>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <6 1>;
+               };
+
+               fpga_pic: fpga-pic@3,10 {
+                       compatible = "abb,socrates-fpga-pic";
+                       reg = <3 0x10 0x10>;
+                       interrupt-controller;
+                       /* IRQs 2, 10, 11, active low, level-sensitive */
+                       interrupts = <2 1 10 1 11 1>;
+                       interrupt-parent = <&mpic>;
+                       #interrupt-cells = <3>;
+               };
+
+               spi@3,60 {
+                       compatible = "abb,socrates-spi";
+                       reg = <3 0x60 0x10>;
+                       interrupts = <8 4 0>;   // number, type, routing
+                       interrupt-parent = <&fpga_pic>;
+               };
+
+               nand@3,70 {
+                       compatible = "abb,socrates-nand";
+                       reg = <3 0x70 0x04>;
+                       bank-width = <1>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       data@0 {
+                               label = "data";
+                               reg = <0x0 0x40000000>;
+                       };
+               };
+
+               can@3,100 {
+                       compatible = "philips,sja1000";
+                       reg = <3 0x100 0x80>;
+                       interrupts = <2 8 1>;   // number, type, routing
+                       interrupt-parent = <&fpga_pic>;
+               };
+       };
+
+       pci0: pci@e0008000 {
+               cell-index = <0>;
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               compatible = "fsl,mpc8540-pci";
+               device_type = "pci";
+               reg = <0xe0008000 0x1000>;
+               clock-frequency = <66666666>;
+
+               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+               interrupt-map = <
+                               /* IDSEL 0x11 */
+                                0x8800 0x0 0x0 1 &mpic 5 1
+                               /* IDSEL 0x12 */
+                                0x9000 0x0 0x0 1 &mpic 4 1>;
+               interrupt-parent = <&mpic>;
+               interrupts = <24 2>;
+               bus-range = <0x0 0x0>;
+               ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x20000000
+                         0x01000000 0x0 0x00000000 0xe2000000 0x0 0x01000000>;
+       };
+
+};
index fff33fe6efc61211449673e24f9fc85f4a21d7b8..8b173957fb5f67ac9e99bcec040d755d77901c95 100644 (file)
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy2: ethernet-phy@2 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <5 4>;
-                               reg = <2>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy4: ethernet-phy@4 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <5 4>;
-                               reg = <4>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        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 = <&phy2>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy2: ethernet-phy@2 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <5 4>;
+                                       reg = <2>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy4: ethernet-phy@4 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <5 4>;
+                                       reg = <4>;
+                                       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 = "TSEC";
                        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 = <&tbi1>;
                        phy-handle = <&phy4>;
+
+                       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";
+                               };
+                       };
                };
 
                mpic: pic@40000 {
index 906302e26a6225f5f0ff1ca5b731adf68368f8e0..c9590b58b7b0ce6d3d6a3136f588ffe9e0d2031d 100644 (file)
@@ -17,6 +17,7 @@
        compatible = "tqc,tqm5200";
        #address-cells = <1>;
        #size-cells = <1>;
+       interrupt-parent = <&mpc5200_pic>;
 
        cpus {
                #address-cells = <1>;
                        compatible = "fsl,mpc5200-gpt";
                        reg = <0x600 0x10>;
                        interrupts = <1 9 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        fsl,has-wdt;
                };
 
                can@900 {
                        compatible = "fsl,mpc5200-mscan";
                        interrupts = <2 17 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        reg = <0x900 0x80>;
                };
 
                can@980 {
                        compatible = "fsl,mpc5200-mscan";
                        interrupts = <2 18 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        reg = <0x980 0x80>;
                };
 
-               gpio@b00 {
+               gpio_simple: gpio@b00 {
                        compatible = "fsl,mpc5200-gpio";
                        reg = <0xb00 0x40>;
                        interrupts = <1 7 0>;
-                       interrupt-parent = <&mpc5200_pic>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
                };
 
                usb@1000 {
                        compatible = "fsl,mpc5200-ohci","ohci-be";
                        reg = <0x1000 0xff>;
                        interrupts = <2 6 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                dma-controller@1200 {
                                      3 4 0  3 5 0  3 6 0  3 7 0
                                      3 8 0  3 9 0  3 10 0  3 11 0
                                      3 12 0  3 13 0  3 14 0  3 15 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                xlb@1f00 {
                };
 
                serial@2000 {           // PSC1
-                       device_type = "serial";
                        compatible = "fsl,mpc5200-psc-uart";
-                       port-number = <0>;  // Logical port assignment
                        reg = <0x2000 0x100>;
                        interrupts = <2 1 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                serial@2200 {           // PSC2
-                       device_type = "serial";
                        compatible = "fsl,mpc5200-psc-uart";
-                       port-number = <1>;  // Logical port assignment
                        reg = <0x2200 0x100>;
                        interrupts = <2 2 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                serial@2400 {           // PSC3
-                       device_type = "serial";
                        compatible = "fsl,mpc5200-psc-uart";
-                       port-number = <2>;  // Logical port assignment
                        reg = <0x2400 0x100>;
                        interrupts = <2 3 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                ethernet@3000 {
-                       device_type = "network";
                        compatible = "fsl,mpc5200-fec";
                        reg = <0x3000 0x400>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <2 5 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        phy-handle = <&phy0>;
                };
 
                        compatible = "fsl,mpc5200-mdio";
                        reg = <0x3000 0x400>;       // fec range, since we need to setup fec interrupts
                        interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
-                       interrupt-parent = <&mpc5200_pic>;
 
                        phy0: ethernet-phy@0 {
-                               device_type = "ethernet-phy";
                                reg = <0>;
                        };
                };
                        compatible = "fsl,mpc5200-ata";
                        reg = <0x3a00 0x100>;
                        interrupts = <2 7 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                };
 
                i2c@3d40 {
                        compatible = "fsl,mpc5200-i2c","fsl-i2c";
                        reg = <0x3d40 0x40>;
                        interrupts = <2 16 0>;
-                       interrupt-parent = <&mpc5200_pic>;
                        fsl5200-clocking;
 
                         rtc@68 {
                };
        };
 
-       lpb {
-               model = "fsl,lpb";
-               compatible = "fsl,lpb";
+       localbus {
+               compatible = "fsl,mpc5200-lpb","simple-bus";
                #address-cells = <2>;
                #size-cells = <1>;
                ranges = <0 0 0xfc000000 0x02000000>;
                                 0xc000 0 0 4 &mpc5200_pic 0 0 3>;
                clock-frequency = <0>; // From boot loader
                interrupts = <2 8 0 2 9 0 2 10 0>;
-               interrupt-parent = <&mpc5200_pic>;
                bus-range = <0 0>;
                ranges = <0x42000000 0 0x80000000 0x80000000 0 0x10000000
                          0x02000000 0 0x90000000 0x90000000 0 0x10000000
index a693f01c21aa6874f0688437425da6622094522b..ac9413a29f9f5d6033bb52a63fcbe91f5bb2eb86 100644 (file)
                        interrupt-parent = <&mpic>;
                        dfsrr;
 
+                       dtt@50 {
+                               compatible = "national,lm75";
+                               reg = <0x50>;
+                       };
+
                        rtc@68 {
                                compatible = "dallas,ds1337";
                                reg = <0x68>;
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <1>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy2: ethernet-phy@2 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <2>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy3: ethernet-phy@3 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <3>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@26520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x26520 0x20>;
-
-                       tbi2: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        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>;
                        phy-handle = <&phy2>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <1>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy2: ethernet-phy@2 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <2>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy3: ethernet-phy@3 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <3>;
+                                       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 = "TSEC";
                        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>;
                        phy-handle = <&phy1>;
+
+                       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";
+                               };
+                       };
                };
 
                enet2: ethernet@26000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <2>;
                        device_type = "network";
                        model = "FEC";
                        compatible = "gianfar";
                        reg = <0x26000 0x1000>;
+                       ranges = <0x0 0x26000 0x1000>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <41 2>;
                        interrupt-parent = <&mpic>;
                        phy-handle = <&phy3>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi2: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
                };
 
                serial0: serial@4500 {
index 9e3f5f0dde2002049b531600c52a48f61a53f4a9..c71bb5dd5e5ec02226ac3c410111edc00b7258b9 100644 (file)
                        interrupt-parent = <&mpic>;
                        dfsrr;
 
+                       dtt@50 {
+                               compatible = "national,lm75";
+                               reg = <0x50>;
+                       };
+
                        rtc@68 {
                                compatible = "dallas,ds1337";
                                reg = <0x68>;
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <1>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy2: ethernet-phy@2 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <2>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy3: ethernet-phy@3 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <3>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        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 = <&phy2>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <1>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy2: ethernet-phy@2 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <2>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy3: ethernet-phy@3 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <3>;
+                                       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 = "TSEC";
                        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 = <&tbi1>;
                        phy-handle = <&phy1>;
+
+                       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 {
index 15086eb65c507cf039c920ee91d84117b189bb75..28b1a95257cdfd8d5986f971b8cdf318d2808537 100644 (file)
                        interrupt-parent = <&mpic>;
                        dfsrr;
 
+                       dtt@50 {
+                               compatible = "national,lm75";
+                               reg = <0x50>;
+                       };
+
                        rtc@68 {
                                compatible = "dallas,ds1337";
                                reg = <0x68>;
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy1: ethernet-phy@0 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <1>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy2: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <2>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy3: ethernet-phy@3 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <3>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy4: ethernet-phy@4 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <4>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy5: ethernet-phy@5 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <5>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@26520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x26520 0x20>;
-
-                       tbi2: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@27520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x27520 0x20>;
-
-                       tbi3: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                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 = <&phy2>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy1: ethernet-phy@0 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <1>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy2: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <2>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy3: ethernet-phy@3 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <3>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy4: ethernet-phy@4 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <4>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy5: ethernet-phy@5 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <5>;
+                                       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 2 36 2 40 2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi1>;
                        phy-handle = <&phy1>;
+
+                       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";
+                               };
+                       };
                };
 
                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>;
                        tbi-handle = <&tbi2>;
                        phy-handle = <&phy3>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi2: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
                };
 
                enet3: ethernet@27000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <3>;
                        device_type = "network";
                        model = "eTSEC";
                        compatible = "gianfar";
                        reg = <0x27000 0x1000>;
+                       ranges = <0x0 0x27000 0x1000>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <37 2 38 2 39 2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi3>;
                        phy-handle = <&phy4>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi3: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
                };
 
                serial0: serial@4500 {
                can0@2,0 {
                        compatible = "intel,82527"; // Bosch CC770
                        reg = <2 0x0 0x100>;
-                       interrupts = <4 0>;
+                       interrupts = <4 1>;
                        interrupt-parent = <&mpic>;
                };
 
                can1@2,100 {
                        compatible = "intel,82527"; // Bosch CC770
                        reg = <2 0x100 0x100>;
-                       interrupts = <4 0>;
+                       interrupts = <4 1>;
                        interrupt-parent = <&mpic>;
                };
 
index b7b65f5e79b654a024c1b1cff191b28d01c65bfb..826fb622cd3c4525f3f897401302016a97b8d53d 100644 (file)
                        interrupt-parent = <&mpic>;
                        dfsrr;
 
+                       dtt@50 {
+                               compatible = "national,lm75";
+                               reg = <0x50>;
+                       };
+
                        rtc@68 {
                                compatible = "dallas,ds1337";
                                reg = <0x68>;
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy1: ethernet-phy@0 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <1>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy2: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <2>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy3: ethernet-phy@3 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <3>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy4: ethernet-phy@4 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <4>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy5: ethernet-phy@5 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <5>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@26520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x26520 0x20>;
-
-                       tbi2: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@27520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x27520 0x20>;
-
-                       tbi3: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                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 = <&phy2>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy1: ethernet-phy@0 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <1>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy2: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <2>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy3: ethernet-phy@3 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <3>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy4: ethernet-phy@4 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <4>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy5: ethernet-phy@5 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <5>;
+                                       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 2 36 2 40 2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi1>;
                        phy-handle = <&phy1>;
+
+                       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";
+                               };
+                       };
                };
 
                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>;
                        tbi-handle = <&tbi2>;
                        phy-handle = <&phy3>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi2: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
                };
 
                enet3: ethernet@27000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <3>;
                        device_type = "network";
                        model = "eTSEC";
                        compatible = "gianfar";
                        reg = <0x27000 0x1000>;
+                       ranges = <0x0 0x27000 0x1000>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <37 2 38 2 39 2>;
                        interrupt-parent = <&mpic>;
                        tbi-handle = <&tbi3>;
                        phy-handle = <&phy4>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi3: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
                };
 
                serial0: serial@4500 {
                can0@2,0 {
                        compatible = "intel,82527"; // Bosch CC770
                        reg = <2 0x0 0x100>;
-                       interrupts = <4 0>;
+                       interrupts = <4 1>;
                        interrupt-parent = <&mpic>;
                };
 
                can1@2,100 {
                        compatible = "intel,82527"; // Bosch CC770
                        reg = <2 0x100 0x100>;
-                       interrupts = <4 0>;
+                       interrupts = <4 1>;
                        interrupt-parent = <&mpic>;
                };
 
index cf92b4e7945e3d6fa61b57907929692ac48b29d0..a133ded6dddbba41886407edcb54717d1879287e 100644 (file)
                        interrupt-parent = <&mpic>;
                        dfsrr;
 
+                       dtt@50 {
+                               compatible = "national,lm75";
+                               reg = <0x50>;
+                       };
+
                        rtc@68 {
                                compatible = "dallas,ds1337";
                                reg = <0x68>;
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <1>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy2: ethernet-phy@2 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <2>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy3: ethernet-phy@3 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <3>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        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 = <&phy2>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <1>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy2: ethernet-phy@2 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <2>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy3: ethernet-phy@3 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <3>;
+                                       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 = "TSEC";
                        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 = <&tbi1>;
                        phy-handle = <&phy1>;
+
+                       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 {
index 9e1ab2d2f669b003d7b676a312aac96a0b8bfbe3..649e2e576267a5eb913f3cfece032eb4437fd0ab 100644 (file)
                        interrupt-parent = <&mpic>;
                        dfsrr;
 
+                       dtt@50 {
+                               compatible = "national,lm75";
+                               reg = <0x50>;
+                       };
+
                        rtc@68 {
                                compatible = "dallas,ds1337";
                                reg = <0x68>;
                        };
                };
 
-               mdio@24520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-mdio";
-                       reg = <0x24520 0x20>;
-
-                       phy1: ethernet-phy@1 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <1>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy2: ethernet-phy@2 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <2>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy3: ethernet-phy@3 {
-                               interrupt-parent = <&mpic>;
-                               interrupts = <8 1>;
-                               reg = <3>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               mdio@25520 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,gianfar-tbi";
-                       reg = <0x25520 0x20>;
-
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
                enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        cell-index = <0>;
                        device_type = "network";
                        model = "TSEC";
                        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 = <&phy2>;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <1>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy2: ethernet-phy@2 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <2>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy3: ethernet-phy@3 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <8 1>;
+                                       reg = <3>;
+                                       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 = "TSEC";
                        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 = <&tbi1>;
                        phy-handle = <&phy1>;
+
+                       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";
+                               };
+                       };
                };
 
                mpic: pic@40000 {
                can0@2,0 {
                        compatible = "intel,82527"; // Bosch CC770
                        reg = <2 0x0 0x100>;
-                       interrupts = <4 0>;
+                       interrupts = <4 1>;
                        interrupt-parent = <&mpic>;
                };
 
                can1@2,100 {
                        compatible = "intel,82527"; // Bosch CC770
                        reg = <2 0x100 0x100>;
-                       interrupts = <4 0>;
+                       interrupts = <4 1>;
                        interrupt-parent = <&mpic>;
                };
        };
index dc8e78e2dceb27d791f07e1f9d78c760665dd4b3..52d8c1ad26a153d9a0782337e4a86ba86aec19c6 100644 (file)
@@ -7,6 +7,15 @@
  * 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.
+ *
+ * ---
+ *
+ * Device Tree Generator version: 1.1
+ *
+ * CAUTION: This file is automatically generated by libgen.
+ * Version: Xilinx EDK 10.1.03 EDK_K_SP3.6
+ *
+ * XPS project directory: ml507_ppc440_emb_ref
  */
 
 /dts-v1/;
@@ -22,8 +31,8 @@
                reg = < 0 0x10000000 >;
        } ;
        chosen {
-               bootargs = "console=ttyS0 ip=on root=/dev/ram";
-               linux,stdout-path = "/plb@0/serial@83e00000";
+               bootargs = "console=ttyS0 root=/dev/ram";
+               linux,stdout-path = &RS232_Uart_1;
        } ;
        cpus {
                #address-cells = <1>;
                                compatible = "xlnx,ll-dma-1.00.a";
                                dcr-reg = < 0x80 0x11 >;
                                interrupt-parent = <&xps_intc_0>;
-                               interrupts = < 9 2 0xa 2 >;
+                               interrupts = < 10 2 11 2 >;
                        } ;
                } ;
        } ;
        plb_v46_0: plb@0 {
                #address-cells = <1>;
                #size-cells = <1>;
-               compatible = "xlnx,plb-v46-1.02.a", "simple-bus";
+               compatible = "xlnx,plb-v46-1.03.a", "simple-bus";
                ranges ;
                DIP_Switches_8Bit: gpio@81460000 {
                        compatible = "xlnx,xps-gpio-1.00.a";
                        interrupt-parent = <&xps_intc_0>;
-                       interrupts = < 6 2 >;
+                       interrupts = < 7 2 >;
                        reg = < 0x81460000 0x10000 >;
                        xlnx,all-inputs = <1>;
                        xlnx,all-inputs-2 = <0>;
                        xlnx,tri-default = <0xffffffff>;
                        xlnx,tri-default-2 = <0xffffffff>;
                } ;
+               FLASH: flash@fc000000 {
+                       bank-width = <2>;
+                       compatible = "xlnx,xps-mch-emc-2.00.a", "cfi-flash";
+                       reg = < 0xfc000000 0x2000000 >;
+                       xlnx,family = "virtex5";
+                       xlnx,include-datawidth-matching-0 = <0x1>;
+                       xlnx,include-datawidth-matching-1 = <0x0>;
+                       xlnx,include-datawidth-matching-2 = <0x0>;
+                       xlnx,include-datawidth-matching-3 = <0x0>;
+                       xlnx,include-negedge-ioregs = <0x0>;
+                       xlnx,include-plb-ipif = <0x1>;
+                       xlnx,include-wrbuf = <0x1>;
+                       xlnx,max-mem-width = <0x10>;
+                       xlnx,mch-native-dwidth = <0x20>;
+                       xlnx,mch-plb-clk-period-ps = <0x2710>;
+                       xlnx,mch-splb-awidth = <0x20>;
+                       xlnx,mch0-accessbuf-depth = <0x10>;
+                       xlnx,mch0-protocol = <0x0>;
+                       xlnx,mch0-rddatabuf-depth = <0x10>;
+                       xlnx,mch1-accessbuf-depth = <0x10>;
+                       xlnx,mch1-protocol = <0x0>;
+                       xlnx,mch1-rddatabuf-depth = <0x10>;
+                       xlnx,mch2-accessbuf-depth = <0x10>;
+                       xlnx,mch2-protocol = <0x0>;
+                       xlnx,mch2-rddatabuf-depth = <0x10>;
+                       xlnx,mch3-accessbuf-depth = <0x10>;
+                       xlnx,mch3-protocol = <0x0>;
+                       xlnx,mch3-rddatabuf-depth = <0x10>;
+                       xlnx,mem0-width = <0x10>;
+                       xlnx,mem1-width = <0x20>;
+                       xlnx,mem2-width = <0x20>;
+                       xlnx,mem3-width = <0x20>;
+                       xlnx,num-banks-mem = <0x1>;
+                       xlnx,num-channels = <0x2>;
+                       xlnx,priority-mode = <0x0>;
+                       xlnx,synch-mem-0 = <0x0>;
+                       xlnx,synch-mem-1 = <0x0>;
+                       xlnx,synch-mem-2 = <0x0>;
+                       xlnx,synch-mem-3 = <0x0>;
+                       xlnx,synch-pipedelay-0 = <0x2>;
+                       xlnx,synch-pipedelay-1 = <0x2>;
+                       xlnx,synch-pipedelay-2 = <0x2>;
+                       xlnx,synch-pipedelay-3 = <0x2>;
+                       xlnx,tavdv-ps-mem-0 = <0x1adb0>;
+                       xlnx,tavdv-ps-mem-1 = <0x3a98>;
+                       xlnx,tavdv-ps-mem-2 = <0x3a98>;
+                       xlnx,tavdv-ps-mem-3 = <0x3a98>;
+                       xlnx,tcedv-ps-mem-0 = <0x1adb0>;
+                       xlnx,tcedv-ps-mem-1 = <0x3a98>;
+                       xlnx,tcedv-ps-mem-2 = <0x3a98>;
+                       xlnx,tcedv-ps-mem-3 = <0x3a98>;
+                       xlnx,thzce-ps-mem-0 = <0x88b8>;
+                       xlnx,thzce-ps-mem-1 = <0x1b58>;
+                       xlnx,thzce-ps-mem-2 = <0x1b58>;
+                       xlnx,thzce-ps-mem-3 = <0x1b58>;
+                       xlnx,thzoe-ps-mem-0 = <0x1b58>;
+                       xlnx,thzoe-ps-mem-1 = <0x1b58>;
+                       xlnx,thzoe-ps-mem-2 = <0x1b58>;
+                       xlnx,thzoe-ps-mem-3 = <0x1b58>;
+                       xlnx,tlzwe-ps-mem-0 = <0x88b8>;
+                       xlnx,tlzwe-ps-mem-1 = <0x0>;
+                       xlnx,tlzwe-ps-mem-2 = <0x0>;
+                       xlnx,tlzwe-ps-mem-3 = <0x0>;
+                       xlnx,twc-ps-mem-0 = <0x2af8>;
+                       xlnx,twc-ps-mem-1 = <0x3a98>;
+                       xlnx,twc-ps-mem-2 = <0x3a98>;
+                       xlnx,twc-ps-mem-3 = <0x3a98>;
+                       xlnx,twp-ps-mem-0 = <0x11170>;
+                       xlnx,twp-ps-mem-1 = <0x2ee0>;
+                       xlnx,twp-ps-mem-2 = <0x2ee0>;
+                       xlnx,twp-ps-mem-3 = <0x2ee0>;
+                       xlnx,xcl0-linesize = <0x4>;
+                       xlnx,xcl0-writexfer = <0x1>;
+                       xlnx,xcl1-linesize = <0x4>;
+                       xlnx,xcl1-writexfer = <0x1>;
+                       xlnx,xcl2-linesize = <0x4>;
+                       xlnx,xcl2-writexfer = <0x1>;
+                       xlnx,xcl3-linesize = <0x4>;
+                       xlnx,xcl3-writexfer = <0x1>;
+               } ;
                Hard_Ethernet_MAC: xps-ll-temac@81c00000 {
                        #address-cells = <1>;
                        #size-cells = <1>;
                                xlnx,txfifo = <0x1000>;
                        } ;
                } ;
+               IIC_EEPROM: i2c@81600000 {
+                       compatible = "xlnx,xps-iic-2.00.a";
+                       interrupt-parent = <&xps_intc_0>;
+                       interrupts = < 6 2 >;
+                       reg = < 0x81600000 0x10000 >;
+                       xlnx,clk-freq = <0x5f5e100>;
+                       xlnx,family = "virtex5";
+                       xlnx,gpo-width = <0x1>;
+                       xlnx,iic-freq = <0x186a0>;
+                       xlnx,scl-inertial-delay = <0x0>;
+                       xlnx,sda-inertial-delay = <0x0>;
+                       xlnx,ten-bit-adr = <0x0>;
+               } ;
                LEDs_8Bit: gpio@81400000 {
                        compatible = "xlnx,xps-gpio-1.00.a";
                        reg = < 0x81400000 0x10000 >;
                Push_Buttons_5Bit: gpio@81440000 {
                        compatible = "xlnx,xps-gpio-1.00.a";
                        interrupt-parent = <&xps_intc_0>;
-                       interrupts = < 7 2 >;
+                       interrupts = < 8 2 >;
                        reg = < 0x81440000 0x10000 >;
                        xlnx,all-inputs = <1>;
                        xlnx,all-inputs-2 = <0>;
                } ;
                RS232_Uart_1: serial@83e00000 {
                        clock-frequency = <100000000>;
-                       compatible = "xlnx,xps-uart16550-2.00.a", "ns16550";
-                       current-speed = <0x2580>;
+                       compatible = "xlnx,xps-uart16550-2.00.b", "ns16550";
+                       current-speed = <9600>;
                        device_type = "serial";
                        interrupt-parent = <&xps_intc_0>;
-                       interrupts = < 8 2 >;
+                       interrupts = < 9 2 >;
                        reg = < 0x83e00000 0x10000 >;
-                       reg-offset = <3>;
+                       reg-offset = <0x1003>;
                        reg-shift = <2>;
                        xlnx,family = "virtex5";
                        xlnx,has-external-rclk = <0>;
                        compatible = "xlnx,xps-intc-1.00.a";
                        interrupt-controller ;
                        reg = < 0x81800000 0x10000 >;
-                       xlnx,num-intr-inputs = <0xb>;
+                       xlnx,num-intr-inputs = <0xc>;
                } ;
                xps_timebase_wdt_1: xps-timebase-wdt@83a00000 {
                        compatible = "xlnx,xps-timebase-wdt-1.00.b";
index 8b3607cb53fb158075a41d5af9845eb1b2bc9e32..f2156f07571f995f3673f67a59d0d20606b27e09 100644 (file)
@@ -117,7 +117,8 @@ int serial_console_init(void)
        if (devp == NULL)
                goto err_out;
 
-       if (dt_is_compatible(devp, "ns16550"))
+       if (dt_is_compatible(devp, "ns16550") ||
+           dt_is_compatible(devp, "pnpPNP,501"))
                rc = ns16550_console_init(devp, &serial_cd);
        else if (dt_is_compatible(devp, "marvell,mv64360-mpsc"))
                rc = mpsc_console_init(devp, &serial_cd);
index 965c237c122d781063697dff3a9cef20dd2859ca..3ac75aecdb94c38e36b770881430350641c0a4ad 100755 (executable)
@@ -186,6 +186,9 @@ cuboot*)
     *-mpc85*|*-tqm85*|*-sbc85*)
         platformo=$object/cuboot-85xx.o
         ;;
+    *-amigaone)
+        link_address='0x800000'
+        ;;
     esac
     ;;
 ps3)
@@ -211,11 +214,11 @@ simpleboot-virtex405-*)
     binary=y
     ;;
 simpleboot-virtex440-*)
-    platformo="$object/simpleboot.o $object/virtex.o"
+    platformo="$object/fixed-head.o $object/simpleboot.o $object/virtex.o"
     binary=y
     ;;
 simpleboot-*)
-    platformo="$object/simpleboot.o"
+    platformo="$object/fixed-head.o $object/simpleboot.o"
     binary=y
     ;;
 asp834x-redboot)
index 81cdcc4b9278ac1ffb3954e674a874103abefd36..f9a08ee49b9671b70ac67488b12a7516b4e5e7a4 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29-rc2
-# Tue Jan 20 08:22:35 2009
+# Linux kernel version: 2.6.29-rc3
+# Mon Feb  2 13:13:04 2009
 #
 # CONFIG_PPC64 is not set
 
@@ -74,6 +74,15 @@ CONFIG_POSIX_MQUEUE=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
@@ -147,11 +156,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
 
@@ -373,6 +377,7 @@ CONFIG_CONNECTOR=y
 CONFIG_PROC_EVENTS=y
 # CONFIG_MTD 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
@@ -384,6 +389,7 @@ CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_LOOP 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=35000
@@ -466,6 +472,15 @@ CONFIG_IBM_NEW_EMAC_EMAC4=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
@@ -533,13 +548,136 @@ 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
+# CONFIG_I2C_TINY_USB 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_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
 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_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_LTC4245 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_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_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,7 +694,12 @@ 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_REGULATOR is not set
 
 #
@@ -574,6 +717,7 @@ CONFIG_SSB_POSSIBLE=y
 # Multimedia drivers
 #
 CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
@@ -590,7 +734,109 @@ CONFIG_VIDEO_OUTPUT_CONTROL=m
 #
 # CONFIG_DISPLAY_SUPPORT is not set
 # CONFIG_SOUND is not set
-# 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=y
+
+#
+# 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_EHCI_HCD=m
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+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=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_PCI=y
+CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
+CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# 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 information
+#
+CONFIG_USB_LIBUSUAL=y
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 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_PHIDGET 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_UWB is not set
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
diff --git a/arch/powerpc/configs/44x/redwood_defconfig b/arch/powerpc/configs/44x/redwood_defconfig
new file mode 100644 (file)
index 0000000..e665433
--- /dev/null
@@ -0,0 +1,1176 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29-rc3
+# Wed Feb  4 14:31:09 2009
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+# CONFIG_6xx 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_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_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_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
+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_DEFAULT_UIMAGE is not set
+CONFIG_PPC_DCR_NATIVE=y
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_PPC_DCR=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# 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_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_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=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_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_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING 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
+# 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_LBD=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# 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=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_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_UNEVICTABLE_LRU=y
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_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_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_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_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
+# 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_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_PHONET 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
+# CONFIG_MAC80211 is not set
+# 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 is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_QINFO_PROBE 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
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# 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_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_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_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_LIBFC 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_MVSAS 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_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
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# 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_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=y
+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_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_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_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E 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
+# CONFIG_IWLWIFI_LEDS 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=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+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_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 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
+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_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
+
+#
+# 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_UIO is not set
+# 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_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_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
+
+#
+# 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_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_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
+# 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
+
+#
+# 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_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=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_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_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_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_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
+# 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_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+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_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_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_GF128MUL=y
+# CONFIG_CRYPTO_NULL is not set
+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_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_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/powerpc/configs/85xx/socrates_defconfig b/arch/powerpc/configs/85xx/socrates_defconfig
new file mode 100644 (file)
index 0000000..0cc9048
--- /dev/null
@@ -0,0 +1,1410 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.26.2
+# Sat Oct 18 11:06:13 2008
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+# CONFIG_6xx is not set
+CONFIG_PPC_85xx=y
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+CONFIG_FSL_EMB_PERFMON=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+CONFIG_PPC_MERGE=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_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_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
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_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_DEFAULT_UIMAGE=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# 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 is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=16
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED 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_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+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 is not set
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=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_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG 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_CLASSIC_RCU=y
+
+#
+# Platform support
+#
+# CONFIG_PPC_MPC512x is not set
+# CONFIG_PPC_MPC5121 is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+CONFIG_MPC85xx=y
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_MPC85xx_CDS is not set
+# CONFIG_MPC85xx_MDS is not set
+# CONFIG_MPC85xx_DS is not set
+CONFIG_SOCRATES=y
+# CONFIG_KSI8560 is not set
+# CONFIG_STX_GP3 is not set
+# CONFIG_TQM8540 is not set
+# CONFIG_TQM8541 is not set
+# CONFIG_TQM8555 is not set
+# CONFIG_TQM8560 is not set
+# CONFIG_SBC8548 is not set
+# CONFIG_SBC8560 is not set
+# CONFIG_IPIC is not set
+CONFIG_MPIC=y
+# 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_CPM2 is not set
+# CONFIG_FSL_ULI1575 is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+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 is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_MATH_EMULATION=y
+# CONFIG_IOMMU_HELPER is not set
+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_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+# CONFIG_PROC_DEVICETREE is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_FSL_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+# CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY=y
+# 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_PHYSICAL_ALIGN=0x10000000
+CONFIG_TASK_SIZE=0xc0000000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# 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_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_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_CAN=y
+CONFIG_CAN_RAW=y
+CONFIG_CAN_BCM=y
+
+#
+# CAN Device Drivers
+#
+# CONFIG_CAN_VCAN is not set
+# CONFIG_CAN_OLD_DRIVERS is not set
+# CONFIG_CAN_SLCAN is not set
+CONFIG_CAN_SJA1000=y
+CONFIG_CAN_SJA1000_MEM_OF=y
+# CONFIG_CAN_EMS_PCI is not set
+# CONFIG_CAN_IXXAT_PCI is not set
+# CONFIG_CAN_PEAK_PCI is not set
+# CONFIG_CAN_KVASER_PCI is not set
+# CONFIG_CAN_MSCAN is not set
+# CONFIG_CAN_DEBUG_DEVICES is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# 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=y
+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_DATAFLASH is not set
+# CONFIG_MTD_M25P80 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 is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=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_NAND_SOCRATES=y
+# CONFIG_MTD_ONENAND 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=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
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ENCLOSURE_SERVICES 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 is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# 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_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# 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_NETDEVICES_MULTIQUEUE is not set
+# 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=y
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=y
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_E1000E_ENABLED is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB 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_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 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
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# 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
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=800
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+CONFIG_TOUCHSCREEN_TSC2003=y
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING 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=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# 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 is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM 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
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 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=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+CONFIG_SPI_SOCRATES=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=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_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 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_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 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_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 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_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+CONFIG_SENSORS_W83781D=y
+# 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=y
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 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_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+CONFIG_FB_FOREIGN_ENDIAN=y
+CONFIG_FB_BOTH_ENDIAN=y
+# CONFIG_FB_BIG_ENDIAN is not set
+# CONFIG_FB_LITTLE_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_FB_MB862XX=y
+# CONFIG_FB_MB862XX_PCI_GDC is not set
+CONFIG_FB_MB862XX_LIME=y
+# CONFIG_FB_PRE_INIT_FB is not set
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_OF is not set
+# CONFIG_FB_CT65550 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_FSL_DIU is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV 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=y
+
+#
+# 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
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_EHCI_FSL is not set
+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 is not set
+CONFIG_USB_OHCI_HCD_PCI=y
+CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
+CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_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
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM 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
+CONFIG_USB_MON=y
+
+#
+# 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_AUERSWALD 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_PHIDGET 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_GADGET 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_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 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+CONFIG_RTC_DRV_RX8025=y
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS 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_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_PPC=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO 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=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# 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_OCFS2_FS is not set
+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
+
+#
+# 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_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# 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=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_VXFS_FS is not set
+# CONFIG_MINIX_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_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_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# 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=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 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_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=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 is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# 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_LZO is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
new file mode 100644 (file)
index 0000000..df2c163
--- /dev/null
@@ -0,0 +1,1889 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29-rc7
+# Fri Mar 13 15:36:11 2009
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+CONFIG_6xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_PPC_FPU=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+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_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_LOCKBREAK=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_GPIO=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=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=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_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# 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=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=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_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_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING 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
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+# 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_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# 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 is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+CONFIG_CLASSIC32=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_MPC5121_ADS is not set
+# CONFIG_MPC5121_GENERIC is not set
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_PMAC is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_PPC_83xx is not set
+CONFIG_PPC_86xx=y
+# CONFIG_MPC8641_HPCN is not set
+# CONFIG_SBC8641D is not set
+# CONFIG_MPC8610_HPCD is not set
+CONFIG_GEF_PPC9A=y
+# CONFIG_GEF_SBC310 is not set
+# CONFIG_GEF_SBC610 is not set
+CONFIG_MPC8641=y
+# CONFIG_IPIC is not set
+CONFIG_MPIC=y
+# 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_TAU is not set
+# CONFIG_QUICC_ENGINE is not set
+# CONFIG_FSL_ULI1575 is not set
+# CONFIG_MPC8xxx_GPIO is not set
+# CONFIG_SIMPLE_GPIO is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+CONFIG_SCHED_HRTICK=y
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+CONFIG_BINFMT_MISC=m
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_IRQ_ALL_CPUS=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 is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_PAGES is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+# CONFIG_PROC_DEVICETREE is not set
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_FSL_PCI=y
+CONFIG_PPC_PCI_CHOICE=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEAER=y
+# CONFIG_PCIEASPM is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+# CONFIG_PCI_LEGACY is not set
+CONFIG_PCI_DEBUG=y
+# CONFIG_PCI_STUB 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_NET=y
+
+#
+# Networking options
+#
+CONFIG_COMPAT_NET_DEV_OPS=y
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_XFRM_IPCOMP=m
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# 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=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+# CONFIG_IPV6_MIP6 is not set
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_NF_DEFRAG_IPV4 is not set
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+# CONFIG_IP_NF_MATCH_AH is not set
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_ECN=m
+# CONFIG_IP_NF_TARGET_TTL is not set
+CONFIG_IP_NF_RAW=m
+# CONFIG_IP_NF_SECURITY is not set
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+# CONFIG_IP6_NF_MATCH_AH is not set
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+# CONFIG_IP6_NF_MATCH_MH is not set
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
+# CONFIG_IP6_NF_TARGET_REJECT is not set
+CONFIG_IP6_NF_MANGLE=m
+# CONFIG_IP6_NF_TARGET_HL is not set
+CONFIG_IP6_NF_RAW=m
+# CONFIG_IP6_NF_SECURITY is not set
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+# CONFIG_IP_DCCP is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+CONFIG_TIPC=m
+# CONFIG_TIPC_ADVANCED is not set
+# CONFIG_TIPC_DEBUG is not set
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_STP=m
+CONFIG_BRIDGE=m
+# CONFIG_NET_DSA is not set
+CONFIG_VLAN_8021Q=m
+# CONFIG_VLAN_8021Q_GVRP is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# 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=m
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+# CONFIG_NET_SCH_MULTIQ is not set
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+# CONFIG_NET_SCH_DRR is not set
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_BASIC is not set
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_CLS_U32_MARK is not set
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# 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_PHONET is not set
+CONFIG_FIB_RULES=y
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_OLD_REGULATORY=y
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_LIB80211 is not set
+# CONFIG_MAC80211 is not set
+# 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 is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR 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 is not set
+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=y
+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=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_GPIO=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=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# 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=131072
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_93CX6 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=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# 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=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# 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_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_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_LIBFC 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_MVSAS is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR 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_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_SATA_PMP=y
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_FSL is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_SATA_SIL=y
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# 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_DUMMY=m
+CONFIG_BONDING=m
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# 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_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 is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB 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_GIANFAR=y
+# CONFIG_MV643XX_ETH 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
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# 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_ATM_DRIVERS=y
+# CONFIG_ATM_DUMMY is not set
+# CONFIG_ATM_TCP is not set
+# CONFIG_ATM_LANAI is not set
+# CONFIG_ATM_ENI is not set
+# CONFIG_ATM_FIRESTREAM is not set
+# CONFIG_ATM_ZATM is not set
+# CONFIG_ATM_NICSTAR is not set
+# CONFIG_ATM_IDT77252 is not set
+# CONFIG_ATM_AMBASSADOR is not set
+# CONFIG_ATM_HORIZON is not set
+# CONFIG_ATM_IA is not set
+# CONFIG_ATM_FORE200E is not set
+# CONFIG_ATM_HE is not set
+# CONFIG_ATM_SOLOS is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+# CONFIG_PPPOL2TP is not set
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLHC=m
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_NET_FC is not set
+CONFIG_NETCONSOLE=y
+# CONFIG_NETCONSOLE_DYNAMIC is not set
+CONFIG_NETPOLL=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_FF_MEMLESS=m
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING 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 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 is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HVC_UDBG is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+CONFIG_NVRAM=y
+# 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_GPIO is not set
+CONFIG_I2C_MPC=y
+# 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
+# CONFIG_I2C_TINY_USB 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=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
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_XILINX is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+# CONFIG_GPIO_BT8XX is not set
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY 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_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=y
+CONFIG_SENSORS_LM92=y
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4245 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_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_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=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_ALIM7101_WDT is not set
+CONFIG_GEF_WDT=y
+# CONFIG_8xxx_WDT is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG 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_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_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_USB_DABUSB 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
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+# CONFIG_HID_NTRIG is not set
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+CONFIG_THRUSTMASTER_FF=m
+CONFIG_ZEROPLUS_FF=m
+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 is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# 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 is not set
+# 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_EHCI_HCD=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_EHCI_FSL is not set
+# CONFIG_USB_EHCI_HCD_PPC_OF is not set
+# 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=y
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# 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 information
+#
+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_PHIDGET 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_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_ATM is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS 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_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 is not set
+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 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+CONFIG_RTC_DRV_RX8581=y
+
+#
+# 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_PPC is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+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
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# 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=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 is not set
+# 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_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL 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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=m
+# 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=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=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 is not set
+# 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_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB 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_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=y
+# 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_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
+# 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_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+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_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_BDI_SWITCH is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITYFS is not set
+CONFIG_SECURITY_NETWORK=y
+# CONFIG_SECURITY_NETWORK_XFRM is not set
+# CONFIG_SECURITY_PATH is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_NULL=m
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# 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=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+# CONFIG_CRYPTO_CAMELLIA is not set
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/powerpc/configs/86xx/gef_sbc310_defconfig b/arch/powerpc/configs/86xx/gef_sbc310_defconfig
new file mode 100644 (file)
index 0000000..bd236b3
--- /dev/null
@@ -0,0 +1,1613 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29-rc3
+# Wed Jan 28 23:05:34 2009
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+CONFIG_6xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_PPC_FPU=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+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_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_LOCKBREAK=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_GPIO=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=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=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_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# 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=y
+CONFIG_IKCONFIG_PROC=y
+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=y
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+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_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING 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
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+# 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_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# 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 is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+CONFIG_PPC_MSI_BITMAP=y
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+CONFIG_CLASSIC32=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_MPC5121_ADS is not set
+# CONFIG_MPC5121_GENERIC is not set
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_PMAC is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_PPC_83xx is not set
+CONFIG_PPC_86xx=y
+# CONFIG_MPC8641_HPCN is not set
+# CONFIG_SBC8641D is not set
+# CONFIG_MPC8610_HPCD is not set
+CONFIG_GEF_SBC310=y
+# CONFIG_GEF_SBC610 is not set
+CONFIG_MPC8641=y
+# CONFIG_IPIC is not set
+CONFIG_MPIC=y
+# 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_TAU is not set
+# CONFIG_QUICC_ENGINE is not set
+# CONFIG_FSL_ULI1575 is not set
+# CONFIG_MPC8xxx_GPIO is not set
+# CONFIG_SIMPLE_GPIO is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+CONFIG_SCHED_HRTICK=y
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+CONFIG_BINFMT_MISC=y
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_IRQ_ALL_CPUS=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 is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_PAGES is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+# CONFIG_PROC_DEVICETREE is not set
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_FSL_PCI=y
+CONFIG_PPC_PCI_CHOICE=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEAER=y
+# CONFIG_PCIEASPM is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+CONFIG_PCI_MSI=y
+# CONFIG_PCI_LEGACY is not set
+# CONFIG_PCI_STUB 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_LOWMEM_CAM_NUM=3
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0xc0000000
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_COMPAT_NET_DEV_OPS=y
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_XFRM_IPCOMP=m
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_LRO=y
+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=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+# CONFIG_IPV6_MIP6 is not set
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE 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_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# 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_PHONET is not set
+CONFIG_FIB_RULES=y
+# CONFIG_WIRELESS is not set
+# 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 is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR 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 is not set
+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=y
+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=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
+# CONFIG_MTD_QINFO_PROBE is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_DEVICE=y
+CONFIG_OF_GPIO=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=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# 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=131072
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_93CX6 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=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# 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=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# 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_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_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_LIBFC 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_MVSAS is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR 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_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_SATA_PMP=y
+# CONFIG_SATA_AHCI is not set
+CONFIG_SATA_SIL24=y
+# CONFIG_SATA_FSL is not set
+# CONFIG_ATA_SFF is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# 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_DUMMY=m
+CONFIG_BONDING=m
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# 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_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 is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB 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_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E 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
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# 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=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+CONFIG_PPPOE=m
+# CONFIG_PPPOL2TP is not set
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLHC=m
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_NET_FC is not set
+CONFIG_NETCONSOLE=y
+# CONFIG_NETCONSOLE_DYNAMIC is not set
+CONFIG_NETPOLL=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING 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 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 is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HVC_UDBG is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+CONFIG_NVRAM=y
+# 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_GPIO is not set
+CONFIG_I2C_MPC=y
+# 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
+# CONFIG_I2C_TINY_USB 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=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
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_XILINX is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+# CONFIG_GPIO_BT8XX is not set
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY 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_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=y
+CONFIG_SENSORS_LM92=y
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4245 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_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_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=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_ALIM7101_WDT is not set
+CONFIG_GEF_WDT=y
+# CONFIG_8xxx_WDT is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG 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_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_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_USB_DABUSB 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
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+# CONFIG_HID_NTRIG is not set
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF 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 is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# 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 is not set
+# 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_EHCI_HCD=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_EHCI_FSL is not set
+# CONFIG_USB_EHCI_HCD_PPC_OF is not set
+# 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=y
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# 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 information
+#
+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_PHIDGET 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_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS 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_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 is not set
+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 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+CONFIG_RTC_DRV_RX8581=y
+
+#
+# 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_PPC is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+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
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=850
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+# 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=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 is not set
+# 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_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL 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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=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 is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+
+#
+# Tracers
+#
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_IRQSTACKS is not set
+# CONFIG_BOOTX_TEXT 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=m
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=m
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=m
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_MD4 is not set
+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=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# 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=m
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/powerpc/configs/amigaone_defconfig b/arch/powerpc/configs/amigaone_defconfig
new file mode 100644 (file)
index 0000000..b63cc38
--- /dev/null
@@ -0,0 +1,1636 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29-rc3
+# Sun Feb  1 14:22:42 2009
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+CONFIG_6xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_PPC_FPU=y
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_PPC_MM_SLICES is not set
+# CONFIG_SMP is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_CHECK_CACHE_COHERENCY=y
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+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_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_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
+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_DEFAULT_UIMAGE=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=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=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=15
+# 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=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+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_PCSPKR_PLATFORM=y
+# CONFIG_COMPAT_BRK is not set
+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_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING 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
+# 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=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_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
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+CONFIG_CLASSIC32=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_MPC5121_ADS is not set
+# CONFIG_MPC5121_GENERIC is not set
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_PMAC is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_86xx is not set
+# CONFIG_EMBEDDED6xx is not set
+CONFIG_AMIGAONE=y
+# CONFIG_IPIC is not set
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+CONFIG_PPC_I8259=y
+# 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_TAU is not set
+# CONFIG_FSL_ULI1575 is not set
+# CONFIG_SIMPLE_GPIO is not set
+
+#
+# Kernel options
+#
+CONFIG_HIGHMEM=y
+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=y
+# CONFIG_IOMMU_HELPER 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_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+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 is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_PAGES is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+# CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+# CONFIG_PCI_LEGACY is not set
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_STUB 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_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
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_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=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_NETFILTER_ADVANCED is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NETFILTER_XTABLES=m
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_STATE is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_NF_NAT=m
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_IRC=m
+# CONFIG_NF_NAT_TFTP is not set
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_H323 is not set
+CONFIG_NF_NAT_SIP=m
+# CONFIG_IP_NF_MANGLE 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_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_PHONET is not set
+# CONFIG_WIRELESS is not set
+# 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 is not set
+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 is not set
+# CONFIG_MTD is not set
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+# CONFIG_PARPORT_SERIAL is not set
+CONFIG_PARPORT_PC_FIFO=y
+# CONFIG_PARPORT_PC_SUPERIO is not set
+# CONFIG_PARPORT_GSC is not set
+# CONFIG_PARPORT_AX88796 is not set
+# CONFIG_PARPORT_1284 is not set
+CONFIG_BLK_DEV=y
+CONFIG_BLK_DEV_FD=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+CONFIG_IDE=y
+
+#
+# Please see Documentation/ide/ide.txt for help/info on IDE drives
+#
+CONFIG_IDE_TIMINGS=y
+CONFIG_IDE_ATAPI=y
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_IDE_GD=y
+CONFIG_IDE_GD_ATA=y
+# CONFIG_IDE_GD_ATAPI is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_PLATFORM is not set
+CONFIG_BLK_DEV_IDEDMA_SFF=y
+
+#
+# PCI IDE chipsets support
+#
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_PCIBUS_ORDER is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8172 is not set
+# CONFIG_BLK_DEV_IT8213 is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+CONFIG_BLK_DEV_SIIMAGE=y
+# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
+# CONFIG_BLK_DEV_TC86C001 is not set
+CONFIG_BLK_DEV_IDEDMA=y
+
+#
+# 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=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# 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=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# 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_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_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_LIBFC 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_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_STEX is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_MMIO 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_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# 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_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=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# 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=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+CONFIG_8139CP=y
+CONFIG_8139TOO=y
+CONFIG_8139TOO_PIO=y
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_R6040 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SMSC9420 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_SC92031 is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_ATL2 is not set
+# CONFIG_NETDEV_1000 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
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# 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_PLIP is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# 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=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PCSPKR=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+CONFIG_INPUT_UINPUT=y
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_XILINX_XPS_PS2 is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING 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=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED 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 is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
+# CONFIG_HVC_UDBG is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM 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 is not set
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=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_MPC is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT is not set
+# 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
+#
+# 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_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
+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_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
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_DDC=y
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+CONFIG_FB_MACMODES=y
+CONFIG_FB_BACKLIGHT=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_OF is not set
+# CONFIG_FB_CT65550 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+CONFIG_FB_RADEON=y
+CONFIG_FB_RADEON_I2C=y
+CONFIG_FB_RADEON_BACKLIGHT=y
+# CONFIG_FB_RADEON_DEBUG is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_VIA is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+CONFIG_FB_3DFX=y
+# CONFIG_FB_3DFX_ACCEL is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_CARMINE is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=m
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+
+#
+# Display device support
+#
+CONFIG_DISPLAY_SUPPORT=m
+
+#
+# Display hardware drivers
+#
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+# CONFIG_GREENASIA_FF is not set
+CONFIG_HID_TOPSEED=y
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF 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_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_EHCI_HCD is not set
+# 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=y
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=y
+# 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 information
+#
+CONFIG_USB_STORAGE=m
+# 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_USS720 is not set
+# 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_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY 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_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_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 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+CONFIG_RTC_DRV_CMOS=y
+# 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_PPC is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# 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=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_EXT4_FS=y
+# CONFIG_EXT4DEV_COMPAT is not set
+CONFIG_EXT4_FS_XATTR=y
+# CONFIG_EXT4_FS_POSIX_ACL is not set
+# CONFIG_EXT4_FS_SECURITY is not set
+CONFIG_JBD=y
+CONFIG_JBD2=y
+CONFIG_FS_MBCACHE=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_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
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# 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=m
+# 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_CRAMFS is not set
+# 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_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD 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=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+CONFIG_AMIGA_PARTITION=y
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION 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=y
+CONFIG_NLS_ISO8859_1=m
+# 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
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=y
+CONFIG_CRC_T10DIF=y
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=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 is not set
+# 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_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_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=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
+# 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_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+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_CODE_PATCHING_SELFTEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+CONFIG_XMON=y
+CONFIG_XMON_DEFAULT=y
+CONFIG_XMON_DISASSEMBLY=y
+CONFIG_DEBUGGER=y
+CONFIG_IRQSTACKS=y
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BOOTX_TEXT 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=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_AEAD2=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=m
+CONFIG_CRYPTO_HASH=m
+CONFIG_CRYPTO_HASH2=m
+CONFIG_CRYPTO_RNG2=m
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=m
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=m
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# 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=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# 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_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
index 81afc8b373d7e0498d403544d094b8388470a4e2..af0cd55605d0a0b8f307b3a56deb52ac7ac1af83 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29-rc2
-# Mon Jan 26 21:40:44 2009
+# Linux kernel version: 2.6.29-rc3
+# Fri Feb  6 09:48:53 2009
 #
 # CONFIG_PPC64 is not set
 
@@ -388,7 +388,10 @@ CONFIG_MTD=y
 CONFIG_MTD_CONCAT=y
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_TESTS is not set
-# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
 CONFIG_MTD_CMDLINE_PARTS=y
 # CONFIG_MTD_OF_PARTS is not set
 # CONFIG_MTD_AR7_PARTS is not set
@@ -502,7 +505,7 @@ CONFIG_MISC_DEVICES=y
 #
 # EEPROM support
 #
-# CONFIG_EEPROM_AT24 is not set
+CONFIG_EEPROM_AT24=y
 # CONFIG_EEPROM_LEGACY is not set
 # CONFIG_EEPROM_93CX6 is not set
 CONFIG_HAVE_IDE=y
@@ -678,7 +681,7 @@ CONFIG_PHYLIB=y
 # CONFIG_MARVELL_PHY is not set
 # CONFIG_DAVICOM_PHY is not set
 # CONFIG_QSEMI_PHY is not set
-# CONFIG_LXT_PHY is not set
+CONFIG_LXT_PHY=y
 # CONFIG_CICADA_PHY is not set
 # CONFIG_VITESSE_PHY is not set
 # CONFIG_SMSC_PHY is not set
@@ -815,8 +818,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=y
-# CONFIG_GEN_RTC_X is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 # CONFIG_RAW_DRIVER is not set
@@ -1281,7 +1282,61 @@ CONFIG_NEW_LEDS=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
+
+#
+# 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_PPC is not set
 # CONFIG_DMADEVICES is not set
 # CONFIG_UIO is not set
 # CONFIG_STAGING is not set
index 88c6295b76c11c34c93e4cb4dda4398c181bcf4e..252401824575c0b6b8207bebd463db242c096bae 100644 (file)
@@ -2067,9 +2067,9 @@ CONFIG_DEBUG_STACKOVERFLOW=y
 CONFIG_DEBUG_STACK_USAGE=y
 # CONFIG_DEBUG_PAGEALLOC is not set
 # CONFIG_HCALL_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_CODE_PATCHING_SELFTEST=y
+CONFIG_FTR_FIXUP_SELFTEST=y
+CONFIG_MSI_BITMAP_SELFTEST=y
 CONFIG_XMON=y
 # CONFIG_XMON_DEFAULT is not set
 CONFIG_XMON_DISASSEMBLY=y
index 107d9b915e33e9559f14357a2e4f55cf3f857e82..37c32aba79b7f690dc749af1b2c9393719cc27cb 100644 (file)
@@ -11,9 +11,7 @@
  */
 
 #include <asm/types.h>
-
-#define PPC_NOP_INSTR          0x60000000
-#define PPC_LWSYNC_INSTR       0x7c2004ac
+#include <asm/ppc-opcode.h>
 
 /* Flags for create_branch:
  * "b"   == create_branch(addr, target, 0);
index 21172badd708fc4f3d893a526339345f77a11281..80f315e8a421b2f0bde0bb6cc9d931c7fb5d5372 100644 (file)
@@ -145,6 +145,7 @@ extern const char *powerpc_base_platform;
 #define CPU_FTR_USE_TB                 ASM_CONST(0x0000000000000040)
 #define CPU_FTR_L2CSR                  ASM_CONST(0x0000000000000080)
 #define CPU_FTR_601                    ASM_CONST(0x0000000000000100)
+#define CPU_FTR_DBELL                  ASM_CONST(0x0000000000000200)
 #define CPU_FTR_CAN_NAP                        ASM_CONST(0x0000000000000400)
 #define CPU_FTR_L3CR                   ASM_CONST(0x0000000000000800)
 #define CPU_FTR_L3_DISABLE_NAP         ASM_CONST(0x0000000000001000)
@@ -375,7 +376,8 @@ extern const char *powerpc_base_platform;
            CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE)
 #define CPU_FTRS_E500MC        (CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \
            CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NODSISRALIGN | \
-           CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE)
+           CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \
+           CPU_FTR_DBELL)
 #define CPU_FTRS_GENERIC_32    (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN)
 
 /* 64-bit CPUs */
diff --git a/arch/powerpc/include/asm/dbell.h b/arch/powerpc/include/asm/dbell.h
new file mode 100644 (file)
index 0000000..501189a
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2009 Freescale Semicondutor, 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.
+ *
+ * provides masks and opcode images for use by code generation, emulation
+ * and for instructions that older assemblers might not know about
+ */
+#ifndef _ASM_POWERPC_DBELL_H
+#define _ASM_POWERPC_DBELL_H
+
+#include <linux/smp.h>
+#include <linux/threads.h>
+
+#include <asm/ppc-opcode.h>
+
+#define PPC_DBELL_MSG_BRDCAST  (0x04000000)
+#define PPC_DBELL_TYPE(x)      (((x) & 0xf) << 28)
+enum ppc_dbell {
+       PPC_DBELL = 0,          /* doorbell */
+       PPC_DBELL_CRIT = 1,     /* critical doorbell */
+       PPC_G_DBELL = 2,        /* guest doorbell */
+       PPC_G_DBELL_CRIT = 3,   /* guest critical doorbell */
+       PPC_G_DBELL_MC = 4,     /* guest mcheck doorbell */
+};
+
+#ifdef CONFIG_SMP
+extern unsigned long dbell_smp_message[NR_CPUS];
+extern void smp_dbell_message_pass(int target, int msg);
+#endif
+
+static inline void ppc_msgsnd(enum ppc_dbell type, u32 flags, u32 tag)
+{
+       u32 msg = PPC_DBELL_TYPE(type) | (flags & PPC_DBELL_MSG_BRDCAST) |
+                       (tag & 0x07ffffff);
+
+       __asm__ __volatile__ (PPC_MSGSND(%0) : : "r" (msg));
+}
+
+#endif /* _ASM_POWERPC_DBELL_H */
index 86cef7ddc8d5f251b07c6c838bf7dcba9d8d579d..c69f2b5f0cc40035877ccea1f363c3de6711fc61 100644 (file)
@@ -109,18 +109,8 @@ static inline struct dma_mapping_ops *get_dma_ops(struct device *dev)
         * only ISA DMA device we support is the floppy and we have a hack
         * in the floppy driver directly to get a device for us.
         */
-
-       if (unlikely(dev == NULL) || dev->archdata.dma_ops == NULL) {
-#ifdef CONFIG_PPC64
+       if (unlikely(dev == NULL))
                return NULL;
-#else
-               /* Use default on 32-bit if dma_ops is not set up */
-               /* TODO: Long term, we should fix drivers so that dev and
-                * archdata dma_ops are set up for all buses.
-                */
-               return &dma_direct_ops;
-#endif
-       }
 
        return dev->archdata.dma_ops;
 }
index b5600ce6055ea7d324fdff62686d385d6160a272..1a856b15226e70e1c40f7b4d8d2f347c19cc2af8 100644 (file)
@@ -8,6 +8,7 @@
 #endif
 
 #include <linux/types.h>
+
 #include <asm/ptrace.h>
 #include <asm/cputable.h>
 #include <asm/auxvec.h>
@@ -178,7 +179,8 @@ typedef elf_fpreg_t elf_vsrreghalf_t32[ELF_NVSRHALFREG];
    the loader.  We need to make sure that it is out of the way of the program
    that it will "exec", and that there is sufficient room for the brk.  */
 
-#define ELF_ET_DYN_BASE         (0x20000000)
+extern unsigned long randomize_et_dyn(unsigned long base);
+#define ELF_ET_DYN_BASE                (randomize_et_dyn(0x20000000))
 
 /*
  * Our registers are always unsigned longs, whether we're a 32 bit
@@ -270,6 +272,14 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm,
                                       int uses_interp);
 #define VDSO_AUX_ENT(a,b) NEW_AUX_ENT(a,b);
 
+/* 1GB for 64bit, 8MB for 32bit */
+#define STACK_RND_MASK (is_32bit_task() ? \
+       (0x7ff >> (PAGE_SHIFT - 12)) : \
+       (0x3ffff >> (PAGE_SHIFT - 12)))
+
+extern unsigned long arch_randomize_brk(struct mm_struct *mm);
+#define arch_randomize_brk arch_randomize_brk
+
 #endif /* __KERNEL__ */
 
 /*
index 8428b38a3d30342087581fbfa49702724cded54c..d60fd18f428cb53b3e4a35c90bdc8590c0283be9 100644 (file)
@@ -61,7 +61,7 @@ extern void __set_fixmap (enum fixed_addresses idx,
  * Some hardware wants to get fixmapped without caching.
  */
 #define set_fixmap_nocache(idx, phys) \
-               __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
+               __set_fixmap(idx, phys, PAGE_KERNEL_NCG)
 
 #define clear_fixmap(idx) \
                __set_fixmap(idx, 0, __pgprot(0))
index e5f2ae8362f7ea8e15fcaca975fefa6e3662010b..dde1296b8b41a903dd2707f0d9465162efd36fbc 100644 (file)
@@ -5,7 +5,44 @@
 #define MCOUNT_ADDR            ((long)(_mcount))
 #define MCOUNT_INSN_SIZE       4 /* sizeof mcount call */
 
-#ifndef __ASSEMBLY__
+#ifdef __ASSEMBLY__
+
+/* Based off of objdump optput from glibc */
+
+#define MCOUNT_SAVE_FRAME                      \
+       stwu    r1,-48(r1);                     \
+       stw     r3, 12(r1);                     \
+       stw     r4, 16(r1);                     \
+       stw     r5, 20(r1);                     \
+       stw     r6, 24(r1);                     \
+       mflr    r3;                             \
+       lwz     r4, 52(r1);                     \
+       mfcr    r5;                             \
+       stw     r7, 28(r1);                     \
+       stw     r8, 32(r1);                     \
+       stw     r9, 36(r1);                     \
+       stw     r10,40(r1);                     \
+       stw     r3, 44(r1);                     \
+       stw     r5, 8(r1)
+
+#define MCOUNT_RESTORE_FRAME                   \
+       lwz     r6, 8(r1);                      \
+       lwz     r0, 44(r1);                     \
+       lwz     r3, 12(r1);                     \
+       mtctr   r0;                             \
+       lwz     r4, 16(r1);                     \
+       mtcr    r6;                             \
+       lwz     r5, 20(r1);                     \
+       lwz     r6, 24(r1);                     \
+       lwz     r0, 52(r1);                     \
+       lwz     r7, 28(r1);                     \
+       lwz     r8, 32(r1);                     \
+       mtlr    r0;                             \
+       lwz     r9, 36(r1);                     \
+       lwz     r10,40(r1);                     \
+       addi    r1, r1, 48
+
+#else /* !__ASSEMBLY__ */
 extern void _mcount(void);
 
 #ifdef CONFIG_DYNAMIC_FTRACE
index 04e4a620952eaefead81d476e95e03fb9dab9e3e..684a73f4324f4ad203c71ef4eb09b5045ab60516 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/highmem.h>
 #include <asm/kmap_types.h>
 #include <asm/tlbflush.h>
 #include <asm/page.h>
@@ -39,15 +40,15 @@ extern pte_t *pkmap_page_table;
  * chunk of RAM.
  */
 /*
- * We use one full pte table with 4K pages. And with 16K/64K pages pte
- * table covers enough memory (32MB and 512MB resp.) that both FIXMAP
- * and PKMAP can be placed in single pte table. We use 1024 pages for
- * PKMAP in case of 16K/64K pages.
+ * We use one full pte table with 4K pages. And with 16K/64K/256K pages pte
+ * table covers enough memory (32MB/512MB/2GB resp.), so that both FIXMAP
+ * and PKMAP can be placed in a single pte table. We use 512 pages for PKMAP
+ * in case of 16K/64K/256K page sizes.
  */
 #ifdef CONFIG_PPC_4K_PAGES
 #define PKMAP_ORDER    PTE_SHIFT
 #else
-#define PKMAP_ORDER    10
+#define PKMAP_ORDER    9
 #endif
 #define LAST_PKMAP     (1 << PKMAP_ORDER)
 #ifndef CONFIG_PPC_4K_PAGES
@@ -94,12 +95,13 @@ static inline void *kmap_atomic_prot(struct page *page, enum km_type type, pgpro
        if (!PageHighMem(page))
                return page_address(page);
 
+       debug_kmap_atomic(type);
        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
        BUG_ON(!pte_none(*(kmap_pte-idx)));
 #endif
-       __set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot));
+       __set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot), 1);
        local_flush_tlb_page(NULL, vaddr);
 
        return (void*) vaddr;
index f75a5fc64d2e64c8eb117c3faacb0c35f804b919..b7e034b0a6ddbd4bb9d491106e08b791ef3fac22 100644 (file)
@@ -129,7 +129,7 @@ static inline int irqs_disabled_flags(unsigned long flags)
  * interrupt-retrigger: should we handle this via lost interrupts and IPIs
  * or should we not care like we do now ? --BenH.
  */
-struct hw_interrupt_type;
+struct irq_chip;
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_HW_IRQ_H */
index 494cd8b0a278a8b8299f149cd765505513c6b3bb..001f2f11c19bbf9f1cfaa1f0e417986eacdb80f5 100644 (file)
@@ -632,6 +632,9 @@ static inline void iosync(void)
  *   ioremap_flags and cannot be hooked (but can be used by a hook on one
  *   of the previous ones)
  *
+ * * __ioremap_caller is the same as above but takes an explicit caller
+ *   reference rather than using __builtin_return_address(0)
+ *
  * * __iounmap, is the low level implementation used by iounmap and cannot
  *   be hooked (but can be used by a hook on iounmap)
  *
@@ -646,6 +649,9 @@ extern void iounmap(volatile void __iomem *addr);
 
 extern void __iomem *__ioremap(phys_addr_t, unsigned long size,
                               unsigned long flags);
+extern void __iomem *__ioremap_caller(phys_addr_t, unsigned long size,
+                                     unsigned long flags, void *caller);
+
 extern void __iounmap(volatile void __iomem *addr);
 
 extern void __iomem * __ioremap_at(phys_addr_t pa, void *ea,
index 25aaa97facd821954a2a85a53fafe67497082e50..68235f7e4a8fabb4febe5302adee68e6a20d1d64 100644 (file)
@@ -97,7 +97,7 @@ struct lppaca {
        u64     saved_gpr4;             // Saved GPR4                   x28-x2F
        u64     saved_gpr5;             // Saved GPR5                   x30-x37
 
-       u8      reserved4;              // Reserved                     x38-x38
+       u8      dtl_enable_mask;        // Dispatch Trace Log mask      x38-x38
        u8      donate_dedicated_cpu;   // Donate dedicated CPU cycles  x39-x39
        u8      fpregs_in_use;          // FP regs in use               x3A-x3A
        u8      pmcregs_in_use;         // PMC regs in use              x3B-x3B
@@ -133,8 +133,10 @@ struct lppaca {
 //=============================================================================
 // CACHE_LINE_4-5 0x0180 - 0x027F Contains PMC interrupt data
 //=============================================================================
-       u32     page_ins;                       // CMO Hint - # page ins by OS  x00-x04
-       u8      pmc_save_area[252];     // PMC interrupt Area           x04-xFF
+       u32     page_ins;               // CMO Hint - # page ins by OS  x00-x03
+       u8      reserved8[148];         // Reserved                     x04-x97
+       volatile u64 dtl_idx;           // Dispatch Trace Log head idx  x98-x9F
+       u8      reserved9[96];          // Reserved                     xA0-xFF
 } __attribute__((__aligned__(0x400)));
 
 extern struct lppaca lppaca[];
index 2740c44ff71766e5e9dad9c01b33e7377d0d4bbd..0efdb1dfdc5f577ea336d4a96fd8dd246d703514 100644 (file)
@@ -90,7 +90,7 @@ struct machdep_calls {
        void            (*tce_flush)(struct iommu_table *tbl);
 
        void __iomem *  (*ioremap)(phys_addr_t addr, unsigned long size,
-                                  unsigned long flags);
+                                  unsigned long flags, void *caller);
        void            (*iounmap)(volatile void __iomem *token);
 
 #ifdef CONFIG_PM
@@ -327,8 +327,6 @@ extern void __devinit smp_generic_take_timebase(void);
  */
 /* Print a boot progress message. */
 void ppc64_boot_msg(unsigned int src, const char *msg);
-/* Print a termination message (print only -- does not stop the kernel) */
-void ppc64_terminate_msg(unsigned int src, const char *msg);
 
 static inline void log_error(char *buf, unsigned int err_type, int fatal)
 {
index 27cc6fdcd3b79e81cadca44218a8a17994336d1d..3c86576bfefa616b6a6e37f6857ec63d17578cf4 100644 (file)
@@ -83,6 +83,8 @@ typedef struct {
 #define PPC44x_TLBE_SIZE       PPC44x_TLB_16K
 #elif (PAGE_SHIFT == 16)
 #define PPC44x_TLBE_SIZE       PPC44x_TLB_64K
+#elif (PAGE_SHIFT == 18)
+#define PPC44x_TLBE_SIZE       PPC44x_TLB_256K
 #else
 #error "Unsupported PAGE_SIZE"
 #endif
similarity index 53%
rename from arch/powerpc/include/asm/mmu-fsl-booke.h
rename to arch/powerpc/include/asm/mmu-book3e.h
index 4285b64a65e0a3a10245b68d57809332d7dc8bc8..7e74cff81d864556b12030da29805d590334fe9a 100644 (file)
@@ -1,26 +1,42 @@
-#ifndef _ASM_POWERPC_MMU_FSL_BOOKE_H_
-#define _ASM_POWERPC_MMU_FSL_BOOKE_H_
+#ifndef _ASM_POWERPC_MMU_BOOK3E_H_
+#define _ASM_POWERPC_MMU_BOOK3E_H_
 /*
- * Freescale Book-E MMU support
+ * Freescale Book-E/Book-3e (ISA 2.06+) MMU support
  */
 
-/* Book-E defined page sizes */
-#define BOOKE_PAGESZ_1K                0
-#define BOOKE_PAGESZ_4K                1
-#define BOOKE_PAGESZ_16K       2
-#define BOOKE_PAGESZ_64K       3
-#define BOOKE_PAGESZ_256K      4
-#define BOOKE_PAGESZ_1M                5
-#define BOOKE_PAGESZ_4M                6
-#define BOOKE_PAGESZ_16M       7
-#define BOOKE_PAGESZ_64M       8
-#define BOOKE_PAGESZ_256M      9
-#define BOOKE_PAGESZ_1GB       10
-#define BOOKE_PAGESZ_4GB       11
-#define BOOKE_PAGESZ_16GB      12
-#define BOOKE_PAGESZ_64GB      13
-#define BOOKE_PAGESZ_256GB     14
-#define BOOKE_PAGESZ_1TB       15
+/* Book-3e defined page sizes */
+#define BOOK3E_PAGESZ_1K       0
+#define BOOK3E_PAGESZ_2K       1
+#define BOOK3E_PAGESZ_4K       2
+#define BOOK3E_PAGESZ_8K       3
+#define BOOK3E_PAGESZ_16K      4
+#define BOOK3E_PAGESZ_32K      5
+#define BOOK3E_PAGESZ_64K      6
+#define BOOK3E_PAGESZ_128K     7
+#define BOOK3E_PAGESZ_256K     8
+#define BOOK3E_PAGESZ_512K     9
+#define BOOK3E_PAGESZ_1M       10
+#define BOOK3E_PAGESZ_2M       11
+#define BOOK3E_PAGESZ_4M       12
+#define BOOK3E_PAGESZ_8M       13
+#define BOOK3E_PAGESZ_16M      14
+#define BOOK3E_PAGESZ_32M      15
+#define BOOK3E_PAGESZ_64M      16
+#define BOOK3E_PAGESZ_128M     17
+#define BOOK3E_PAGESZ_256M     18
+#define BOOK3E_PAGESZ_512M     19
+#define BOOK3E_PAGESZ_1GB      20
+#define BOOK3E_PAGESZ_2GB      21
+#define BOOK3E_PAGESZ_4GB      22
+#define BOOK3E_PAGESZ_8GB      23
+#define BOOK3E_PAGESZ_16GB     24
+#define BOOK3E_PAGESZ_32GB     25
+#define BOOK3E_PAGESZ_64GB     26
+#define BOOK3E_PAGESZ_128GB    27
+#define BOOK3E_PAGESZ_256GB    28
+#define BOOK3E_PAGESZ_512GB    29
+#define BOOK3E_PAGESZ_1TB      30
+#define BOOK3E_PAGESZ_2TB      31
 
 #define MAS0_TLBSEL(x) ((x << 28) & 0x30000000)
 #define MAS0_ESEL(x)   ((x << 16) & 0x0FFF0000)
@@ -29,8 +45,9 @@
 #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 << 8) & 0x00000F00)
+#define MAS1_TSIZE(x)  ((x << 7) & 0x00000F80)
 
 #define MAS2_EPN       0xFFFFF000
 #define MAS2_X0                0x00000040
@@ -40,7 +57,7 @@
 #define MAS2_M         0x00000004
 #define MAS2_G         0x00000002
 #define MAS2_E         0x00000001
-#define MAS2_EPN_MASK(size)            (~0 << (2*(size) + 10))
+#define MAS2_EPN_MASK(size)            (~0 << (size + 10))
 #define MAS2_VAL(addr, size, flags)    ((addr) & MAS2_EPN_MASK(size) | (flags))
 
 #define MAS3_RPN       0xFFFFF000
@@ -56,7 +73,7 @@
 #define MAS3_SR                0x00000001
 
 #define MAS4_TLBSELD(x) MAS0_TLBSEL(x)
-#define MAS4_TIDDSEL   0x000F0000
+#define MAS4_INDD      0x00008000
 #define MAS4_TSIZED(x) MAS1_TSIZE(x)
 #define MAS4_X0D       0x00000040
 #define MAS4_X1D       0x00000020
@@ -68,6 +85,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
 
@@ -84,4 +102,4 @@ typedef struct {
 } mm_context_t;
 #endif /* !__ASSEMBLY__ */
 
-#endif /* _ASM_POWERPC_MMU_FSL_BOOKE_H_ */
+#endif /* _ASM_POWERPC_MMU_BOOK3E_H_ */
index 68b752626808b673d4a0ca2f2264fe61e1af7894..98c104a0996196a7932e83c846e80a81a315e87c 100644 (file)
@@ -284,8 +284,6 @@ extern void add_gpage(unsigned long addr, unsigned long page_size,
                          unsigned long number_of_pages);
 extern void demote_segment_4k(struct mm_struct *mm, unsigned long addr);
 
-extern void htab_initialize(void);
-extern void htab_initialize_secondary(void);
 extern void hpte_init_native(void);
 extern void hpte_init_lpar(void);
 extern void hpte_init_iSeries(void);
index 6e76399113189baaf849676a188127efb46e4e5a..cbf154387091542e24dbf47926e9b5a5e9a5d34a 100644 (file)
@@ -36,9 +36,9 @@
  */
 #define MMU_FTR_USE_TLBIVAX_BCAST      ASM_CONST(0x00040000)
 
-/* Enable use of tlbilx invalidate-by-PID variant.
+/* Enable use of tlbilx invalidate instructions.
  */
-#define MMU_FTR_USE_TLBILX_PID         ASM_CONST(0x00080000)
+#define MMU_FTR_USE_TLBILX             ASM_CONST(0x00080000)
 
 /* This indicates that the processor cannot handle multiple outstanding
  * broadcast tlbivax or tlbsync. This makes the code use a spinlock
  */
 #define MMU_FTR_LOCK_BCAST_INVAL       ASM_CONST(0x00100000)
 
+/* This indicates that the processor doesn't handle way selection
+ * properly and needs SW to track and update the LRU state.  This
+ * is specific to an errata on e300c2/c3/c4 class parts
+ */
+#define MMU_FTR_NEED_DTLB_SW_LRU       ASM_CONST(0x00200000)
+
 #ifndef __ASSEMBLY__
 #include <asm/cputable.h>
 
@@ -56,6 +62,10 @@ static inline int mmu_has_feature(unsigned long feature)
 
 extern unsigned int __start___mmu_ftr_fixup, __stop___mmu_ftr_fixup;
 
+/* MMU initialization (64-bit only fo now) */
+extern void early_init_mmu(void);
+extern void early_init_mmu_secondary(void);
+
 #endif /* !__ASSEMBLY__ */
 
 
@@ -71,9 +81,9 @@ extern unsigned int __start___mmu_ftr_fixup, __stop___mmu_ftr_fixup;
 #elif defined(CONFIG_44x)
 /* 44x-style software loaded TLB */
 #  include <asm/mmu-44x.h>
-#elif defined(CONFIG_FSL_BOOKE)
-/* Freescale Book-E software loaded TLB */
-#  include <asm/mmu-fsl-booke.h>
+#elif defined(CONFIG_PPC_BOOK3E_MMU)
+/* Freescale Book-E software loaded TLB or Book-3e (ISA 2.06+) MMU */
+#  include <asm/mmu-book3e.h>
 #elif defined (CONFIG_PPC_8xx)
 /* Motorola/Freescale 8xx software loaded TLB */
 #  include <asm/mmu-8xx.h>
index ab4f19263c4286b199a084ea5dff32259d50820b..b7063669f972b04238c16c945c34987a67e81524 100644 (file)
@@ -31,7 +31,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                             struct task_struct *tsk)
 {
        /* Mark this context has been used on the new CPU */
-       cpu_set(smp_processor_id(), next->cpu_vm_mask);
+       cpumask_set_cpu(smp_processor_id(), mm_cpumask(next));
 
        /* 32-bit keeps track of the current PGDIR in the thread struct */
 #ifdef CONFIG_PPC32
index 81a23932a160c7e47aaa4ceb359e591ee7ee5c6f..52e049cd9e687c09b2b95eb5b71082cecca5bfb9 100644 (file)
@@ -273,6 +273,7 @@ extern void mpc5200_setup_xlb_arbiter(void);
 extern void mpc52xx_declare_of_platform_devices(void);
 extern void mpc52xx_map_common_devices(void);
 extern int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv);
+extern unsigned int mpc52xx_get_xtal_freq(struct device_node *node);
 extern void mpc52xx_restart(char *cmd);
 
 /* mpc52xx_pic.c */
index 197d569f5bd3c44a1f3718f0714e165b72a453de..32cbf16f10eac9090640bbb9c8d4033870989892 100644 (file)
 #include <asm/kdump.h>
 
 /*
- * On regular PPC32 page size is 4K (but we support 4K/16K/64K pages
+ * On regular PPC32 page size is 4K (but we support 4K/16K/64K/256K pages
  * on PPC44x). For PPC64 we support either 4K or 64K software
  * page size. When using 64K pages however, whether we are really supporting
  * 64K pages in HW or not is irrelevant to those definitions.
  */
-#if defined(CONFIG_PPC_64K_PAGES)
+#if defined(CONFIG_PPC_256K_PAGES)
+#define PAGE_SHIFT             18
+#elif defined(CONFIG_PPC_64K_PAGES)
 #define PAGE_SHIFT             16
 #elif defined(CONFIG_PPC_16K_PAGES)
 #define PAGE_SHIFT             14
index 1458d95003814dbc591d6e0d5b124485488218c9..a0e3f6e6b4eeadc2140080843dc35ebeda6c241f 100644 (file)
 #define PTE_FLAGS_OFFSET       0
 #endif
 
+#ifdef CONFIG_PPC_256K_PAGES
+#define PTE_SHIFT      (PAGE_SHIFT - PTE_T_LOG2 - 2)   /* 1/4 of a page */
+#else
 #define PTE_SHIFT      (PAGE_SHIFT - PTE_T_LOG2)       /* full page */
+#endif
 
 #ifndef __ASSEMBLY__
 /*
index 3548159a1beb98b55ef6c7e39985da655f85920d..ba17d5d90a493c2128c75dd8712fa6c05e3df145 100644 (file)
@@ -114,6 +114,10 @@ extern int pci_domain_nr(struct pci_bus *bus);
 /* Decide whether to display the domain number in /proc */
 extern int pci_proc_domain(struct pci_bus *bus);
 
+/* MSI arch hooks */
+#define arch_setup_msi_irqs arch_setup_msi_irqs
+#define arch_teardown_msi_irqs arch_teardown_msi_irqs
+#define arch_msi_check_device arch_msi_check_device
 
 struct vm_area_struct;
 /* Map a range of PCI memory or I/O space for a device into user space */
index 820b5f0a35ce309fcc1b2f662625d0205abfc8dc..ba45c997830fa05e814d18c1323ad6467ed79bef 100644 (file)
@@ -18,55 +18,6 @@ extern int icache_44x_need_flush;
 
 #endif /* __ASSEMBLY__ */
 
-/*
- * The PowerPC MMU uses a hash table containing PTEs, together with
- * a set of 16 segment registers (on 32-bit implementations), to define
- * the virtual to physical address mapping.
- *
- * We use the hash table as an extended TLB, i.e. a cache of currently
- * active mappings.  We maintain a two-level page table tree, much
- * like that used by the i386, for the sake of the Linux memory
- * management code.  Low-level assembler code in hashtable.S
- * (procedure hash_page) is responsible for extracting ptes from the
- * tree and putting them into the hash table when necessary, and
- * updating the accessed and modified bits in the page table tree.
- */
-
-/*
- * The PowerPC MPC8xx uses a TLB with hardware assisted, software tablewalk.
- * We also use the two level tables, but we can put the real bits in them
- * needed for the TLB and tablewalk.  These definitions require Mx_CTR.PPM = 0,
- * Mx_CTR.PPCS = 0, and MD_CTR.TWAM = 1.  The level 2 descriptor has
- * additional page protection (when Mx_CTR.PPCS = 1) that allows TLB hit
- * based upon user/super access.  The TLB does not have accessed nor write
- * protect.  We assume that if the TLB get loaded with an entry it is
- * accessed, and overload the changed bit for write protect.  We use
- * two bits in the software pte that are supposed to be set to zero in
- * the TLB entry (24 and 25) for these indicators.  Although the level 1
- * descriptor contains the guarded and writethrough/copyback bits, we can
- * set these at the page level since they get copied from the Mx_TWC
- * register when the TLB entry is loaded.  We will use bit 27 for guard, since
- * that is where it exists in the MD_TWC, and bit 26 for writethrough.
- * These will get masked from the level 2 descriptor at TLB load time, and
- * copied to the MD_TWC before it gets loaded.
- * Large page sizes added.  We currently support two sizes, 4K and 8M.
- * This also allows a TLB hander optimization because we can directly
- * load the PMD into MD_TWC.  The 8M pages are only used for kernel
- * mapping of well known areas.  The PMD (PGD) entries contain control
- * flags in addition to the address, so care must be taken that the
- * software no longer assumes these are only pointers.
- */
-
-/*
- * At present, all PowerPC 400-class processors share a similar TLB
- * architecture. The instruction and data sides share a unified,
- * 64-entry, fully-associative TLB which is maintained totally under
- * software control. In addition, the instruction side has a
- * hardware-managed, 4-entry, fully-associative TLB which serves as a
- * first level to the shared TLB. These two TLBs are known as the UTLB
- * and ITLB, respectively (see "mmu.h" for definitions).
- */
-
 /*
  * The normal case is that PTEs are 32-bits and we have a 1-page
  * 1024-entry pgdir pointing to 1-page 1024-entry PTE pages.  -- paulus
@@ -135,409 +86,22 @@ extern int icache_44x_need_flush;
  */
 
 #if defined(CONFIG_40x)
-
-/* There are several potential gotchas here.  The 40x hardware TLBLO
-   field looks like this:
-
-   0  1  2  3  4  ... 18 19 20 21 22 23 24 25 26 27 28 29 30 31
-   RPN.....................  0  0 EX WR ZSEL.......  W  I  M  G
-
-   Where possible we make the Linux PTE bits match up with this
-
-   - bits 20 and 21 must be cleared, because we use 4k pages (40x can
-     support down to 1k pages), this is done in the TLBMiss exception
-     handler.
-   - We use only zones 0 (for kernel pages) and 1 (for user pages)
-     of the 16 available.  Bit 24-26 of the TLB are cleared in the TLB
-     miss handler.  Bit 27 is PAGE_USER, thus selecting the correct
-     zone.
-   - PRESENT *must* be in the bottom two bits because swap cache
-     entries use the top 30 bits.  Because 40x doesn't support SMP
-     anyway, M is irrelevant so we borrow it for PAGE_PRESENT.  Bit 30
-     is cleared in the TLB miss handler before the TLB entry is loaded.
-   - All other bits of the PTE are loaded into TLBLO without
-     modification, leaving us only the bits 20, 21, 24, 25, 26, 30 for
-     software PTE bits.  We actually use use bits 21, 24, 25, and
-     30 respectively for the software bits: ACCESSED, DIRTY, RW, and
-     PRESENT.
-*/
-
-/* Definitions for 40x embedded chips. */
-#define        _PAGE_GUARDED   0x001   /* G: page is guarded from prefetch */
-#define _PAGE_FILE     0x001   /* when !present: nonlinear file mapping */
-#define _PAGE_PRESENT  0x002   /* software: PTE contains a translation */
-#define        _PAGE_NO_CACHE  0x004   /* I: caching is inhibited */
-#define        _PAGE_WRITETHRU 0x008   /* W: caching is write-through */
-#define        _PAGE_USER      0x010   /* matches one of the zone permission bits */
-#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_ACCESSED 0x400   /* software: R: page referenced */
-
-#define _PMD_PRESENT   0x400   /* PMD points to page of PTEs */
-#define _PMD_BAD       0x802
-#define _PMD_SIZE      0x0e0   /* size field, != 0 for large-page PMD entry */
-#define _PMD_SIZE_4M   0x0c0
-#define _PMD_SIZE_16M  0x0e0
-#define PMD_PAGE_SIZE(pmdval)  (1024 << (((pmdval) & _PMD_SIZE) >> 4))
-
-/* Until my rework is finished, 40x still needs atomic PTE updates */
-#define PTE_ATOMIC_UPDATES     1
-
+#include <asm/pte-40x.h>
 #elif defined(CONFIG_44x)
-/*
- * Definitions for PPC440
- *
- * Because of the 3 word TLB entries to support 36-bit addressing,
- * the attribute are difficult to map in such a fashion that they
- * are easily loaded during exception processing.  I decided to
- * organize the entry so the ERPN is the only portion in the
- * upper word of the PTE and the attribute bits below are packed
- * in as sensibly as they can be in the area below a 4KB page size
- * oriented RPN.  This at least makes it easy to load the RPN and
- * ERPN fields in the TLB. -Matt
- *
- * Note that these bits preclude future use of a page size
- * less than 4KB.
- *
- *
- * PPC 440 core has following TLB attribute fields;
- *
- *   TLB1:
- *   0  1  2  3  4  ... 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
- *   RPN.................................  -  -  -  -  -  - ERPN.......
- *
- *   TLB2:
- *   0  1  2  3  4  ... 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
- *   -  -  -  -  -    - U0 U1 U2 U3 W  I  M  G  E   - UX UW UR SX SW SR
- *
- * Newer 440 cores (440x6 as used on AMCC 460EX/460GT) have additional
- * TLB2 storage attibute fields. Those are:
- *
- *   TLB2:
- *   0...10    11   12   13   14   15   16...31
- *   no change WL1  IL1I IL1D IL2I IL2D no change
- *
- * There are some constrains and options, to decide mapping software bits
- * into TLB entry.
- *
- *   - PRESENT *must* be in the bottom three bits because swap cache
- *     entries use the top 29 bits for TLB2.
- *
- *   - FILE *must* be in the bottom three bits because swap cache
- *     entries use the top 29 bits for TLB2.
- *
- *   - CACHE COHERENT bit (M) has no effect on original PPC440 cores,
- *     because it doesn't support SMP. However, some later 460 variants
- *     have -some- form of SMP support and so I keep the bit there for
- *     future use
- *
- * With the PPC 44x Linux implementation, the 0-11th LSBs of the PTE are used
- * for memory protection related functions (see PTE structure in
- * include/asm-ppc/mmu.h).  The _PAGE_XXX definitions in this file map to the
- * above bits.  Note that the bit values are CPU specific, not architecture
- * specific.
- *
- * The kernel PTE entry holds an arch-dependent swp_entry structure under
- * certain situations. In other words, in such situations some portion of
- * the PTE bits are used as a swp_entry. In the PPC implementation, the
- * 3-24th LSB are shared with swp_entry, however the 0-2nd three LSB still
- * hold protection values. That means the three protection bits are
- * reserved for both PTE and SWAP entry at the most significant three
- * LSBs.
- *
- * There are three protection bits available for SWAP entry:
- *     _PAGE_PRESENT
- *     _PAGE_FILE
- *     _PAGE_HASHPTE (if HW has)
- *
- * So those three bits have to be inside of 0-2nd LSB of PTE.
- *
- */
-
-#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_ACCESSED 0x00000008              /* S: Page referenced */
-#define _PAGE_DIRTY    0x00000010              /* S: Page dirty */
-#define _PAGE_SPECIAL  0x00000020              /* S: Special page */
-#define _PAGE_USER     0x00000040              /* S: User page */
-#define _PAGE_ENDIAN   0x00000080              /* H: E bit */
-#define _PAGE_GUARDED  0x00000100              /* H: G bit */
-#define _PAGE_COHERENT 0x00000200              /* H: M bit */
-#define _PAGE_NO_CACHE 0x00000400              /* H: I bit */
-#define _PAGE_WRITETHRU        0x00000800              /* H: W bit */
-
-/* TODO: Add large page lowmem mapping support */
-#define _PMD_PRESENT   0
-#define _PMD_PRESENT_MASK (PAGE_MASK)
-#define _PMD_BAD       (~PAGE_MASK)
-
-/* ERPN in a PTE never gets cleared, ignore it */
-#define _PTE_NONE_MASK 0xffffffff00000000ULL
-
-#define __HAVE_ARCH_PTE_SPECIAL
-
+#include <asm/pte-44x.h>
 #elif defined(CONFIG_FSL_BOOKE)
-/*
-   MMU Assist Register 3:
-
-   32 33 34 35 36  ... 50 51 52 53 54 55 56 57 58 59 60 61 62 63
-   RPN......................  0  0 U0 U1 U2 U3 UX SX UW SW UR SR
-
-   - PRESENT *must* be in the bottom three bits because swap cache
-     entries use the top 29 bits.
-
-   - FILE *must* be in the bottom three bits because swap cache
-     entries use the top 29 bits.
-*/
-
-/* Definitions for FSL Book-E Cores */
-#define _PAGE_PRESENT  0x00001 /* S: PTE contains a translation */
-#define _PAGE_USER     0x00002 /* S: User page (maps to UR) */
-#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_ACCESSED 0x00020 /* S: Page referenced */
-
-#define _PAGE_ENDIAN   0x00040 /* H: E bit */
-#define _PAGE_GUARDED  0x00080 /* H: G bit */
-#define _PAGE_COHERENT 0x00100 /* H: M bit */
-#define _PAGE_NO_CACHE 0x00200 /* H: I 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
-#endif
-
-#define _PMD_PRESENT   0
-#define _PMD_PRESENT_MASK (PAGE_MASK)
-#define _PMD_BAD       (~PAGE_MASK)
-
-#define __HAVE_ARCH_PTE_SPECIAL
-
+#include <asm/pte-fsl-booke.h>
 #elif defined(CONFIG_8xx)
-/* Definitions for 8xx embedded chips. */
-#define _PAGE_PRESENT  0x0001  /* Page is valid */
-#define _PAGE_FILE     0x0002  /* when !present: nonlinear file mapping */
-#define _PAGE_NO_CACHE 0x0002  /* I: cache inhibit */
-#define _PAGE_SHARED   0x0004  /* No ASID (context) compare */
-
-/* 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 */
-#define _PAGE_ACCESSED 0x0080  /* software: page referenced */
-
-/* Setting any bits in the nibble with the follow two controls will
- * require a TLB exception handler change.  It is assumed unused bits
- * are always zero.
- */
-#define _PAGE_HWWRITE  0x0100  /* h/w write enable: never set in Linux PTE */
-#define _PAGE_USER     0x0800  /* One of the PP bits, the other is USER&~RW */
-
-#define _PMD_PRESENT   0x0001
-#define _PMD_BAD       0x0ff0
-#define _PMD_PAGE_MASK 0x000c
-#define _PMD_PAGE_8M   0x000c
-
-#define _PTE_NONE_MASK _PAGE_ACCESSED
-
-/* Until my rework is finished, 8xx still needs atomic PTE updates */
-#define PTE_ATOMIC_UPDATES     1
-
+#include <asm/pte-8xx.h>
 #else /* CONFIG_6xx */
-/* Definitions for 60x, 740/750, etc. */
-#define _PAGE_PRESENT  0x001   /* software: pte contains a translation */
-#define _PAGE_HASHPTE  0x002   /* hash_page has made an HPTE for this pte */
-#define _PAGE_FILE     0x004   /* when !present: nonlinear file mapping */
-#define _PAGE_USER     0x004   /* usermode access allowed */
-#define _PAGE_GUARDED  0x008   /* G: prohibit speculative access */
-#define _PAGE_COHERENT 0x010   /* M: enforce memory coherence (SMP systems) */
-#define _PAGE_NO_CACHE 0x020   /* I: cache inhibit */
-#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 */
-
-#ifdef CONFIG_PTE_64BIT
-/* We never clear the high word of the pte */
-#define _PTE_NONE_MASK (0xffffffff00000000ULL | _PAGE_HASHPTE)
-#else
-#define _PTE_NONE_MASK _PAGE_HASHPTE
+#include <asm/pte-hash32.h>
 #endif
 
-#define _PMD_PRESENT   0
-#define _PMD_PRESENT_MASK (PAGE_MASK)
-#define _PMD_BAD       (~PAGE_MASK)
-
-/* Hash table based platforms need atomic updates of the linux PTE */
-#define PTE_ATOMIC_UPDATES     1
-
-#define __HAVE_ARCH_PTE_SPECIAL
-
-#endif
-
-/*
- * Some bits are only used on some cpu families...
- */
-#ifndef _PAGE_HASHPTE
-#define _PAGE_HASHPTE  0
-#endif
-#ifndef _PTE_NONE_MASK
-#define _PTE_NONE_MASK 0
-#endif
-#ifndef _PAGE_SHARED
-#define _PAGE_SHARED   0
-#endif
-#ifndef _PAGE_HWWRITE
-#define _PAGE_HWWRITE  0
-#endif
-#ifndef _PAGE_HWEXEC
-#define _PAGE_HWEXEC   0
-#endif
-#ifndef _PAGE_EXEC
-#define _PAGE_EXEC     0
-#endif
-#ifndef _PAGE_ENDIAN
-#define _PAGE_ENDIAN   0
-#endif
-#ifndef _PAGE_COHERENT
-#define _PAGE_COHERENT 0
-#endif
-#ifndef _PAGE_WRITETHRU
-#define _PAGE_WRITETHRU        0
-#endif
-#ifndef _PAGE_SPECIAL
-#define _PAGE_SPECIAL  0
-#endif
-#ifndef _PMD_PRESENT_MASK
-#define _PMD_PRESENT_MASK      _PMD_PRESENT
-#endif
-#ifndef _PMD_SIZE
-#define _PMD_SIZE      0
-#define PMD_PAGE_SIZE(pmd)     bad_call_to_PMD_PAGE_SIZE()
-#endif
-
-#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | \
-                        _PAGE_SPECIAL)
-
-
-#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \
-                        _PAGE_WRITETHRU | _PAGE_ENDIAN | \
-                        _PAGE_USER | _PAGE_ACCESSED | \
-                        _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | \
-                        _PAGE_EXEC | _PAGE_HWEXEC)
-
-/*
- * We define 2 sets of base prot bits, one for basic pages (ie,
- * cacheable kernel and user pages) and one for non cacheable
- * pages. We always set _PAGE_COHERENT when SMP is enabled or
- * the processor might need it for DMA coherency.
- */
-#if defined(CONFIG_SMP) || defined(CONFIG_PPC_STD_MMU)
-#define _PAGE_BASE     (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT)
-#else
-#define _PAGE_BASE     (_PAGE_PRESENT | _PAGE_ACCESSED)
-#endif
-#define _PAGE_BASE_NC  (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_NO_CACHE)
-
-#define _PAGE_WRENABLE (_PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE)
-#define _PAGE_KERNEL   (_PAGE_BASE | _PAGE_SHARED | _PAGE_WRENABLE)
-#define _PAGE_KERNEL_NC        (_PAGE_BASE_NC | _PAGE_SHARED | _PAGE_WRENABLE)
-
-#ifdef CONFIG_PPC_STD_MMU
-/* On standard PPC MMU, no user access implies kernel read/write access,
- * so to write-protect kernel memory we must turn on user access */
-#define _PAGE_KERNEL_RO        (_PAGE_BASE | _PAGE_SHARED | _PAGE_USER)
-#else
-#define _PAGE_KERNEL_RO        (_PAGE_BASE | _PAGE_SHARED)
-#endif
-
-#define _PAGE_IO       (_PAGE_KERNEL_NC | _PAGE_GUARDED)
-#define _PAGE_RAM      (_PAGE_KERNEL | _PAGE_HWEXEC)
-
-#if defined(CONFIG_KGDB) || defined(CONFIG_XMON) || defined(CONFIG_BDI_SWITCH) ||\
-       defined(CONFIG_KPROBES)
-/* We want the debuggers to be able to set breakpoints anywhere, so
- * don't write protect the kernel text */
-#define _PAGE_RAM_TEXT _PAGE_RAM
-#else
-#define _PAGE_RAM_TEXT (_PAGE_KERNEL_RO | _PAGE_HWEXEC)
-#endif
-
-#define PAGE_NONE      __pgprot(_PAGE_BASE)
-#define PAGE_READONLY  __pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_READONLY_X        __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
-#define PAGE_SHARED    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
-#define PAGE_SHARED_X  __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC)
-#define PAGE_COPY      __pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_COPY_X    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
-
-#define PAGE_KERNEL            __pgprot(_PAGE_RAM)
-#define PAGE_KERNEL_NOCACHE    __pgprot(_PAGE_IO)
-
-/*
- * The PowerPC can only do execute protection on a segment (256MB) basis,
- * not on a page basis.  So we consider execute permission the same as read.
- * Also, write permissions imply read permissions.
- * This is the closest we can get..
- */
-#define __P000 PAGE_NONE
-#define __P001 PAGE_READONLY_X
-#define __P010 PAGE_COPY
-#define __P011 PAGE_COPY_X
-#define __P100 PAGE_READONLY
-#define __P101 PAGE_READONLY_X
-#define __P110 PAGE_COPY
-#define __P111 PAGE_COPY_X
-
-#define __S000 PAGE_NONE
-#define __S001 PAGE_READONLY_X
-#define __S010 PAGE_SHARED
-#define __S011 PAGE_SHARED_X
-#define __S100 PAGE_READONLY
-#define __S101 PAGE_READONLY_X
-#define __S110 PAGE_SHARED
-#define __S111 PAGE_SHARED_X
+/* And here we include common definitions */
+#include <asm/pte-common.h>
 
 #ifndef __ASSEMBLY__
-/* Make sure we get a link error if PMD_PAGE_SIZE is ever called on a
- * kernel without large page PMD support */
-extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
-
-/*
- * Conversions between PTE values and page frame numbers.
- */
-
-/* in some case we want to additionaly adjust where the pfn is in the pte to
- * allow room for more flags */
-#if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_PTE_64BIT)
-#define PFN_SHIFT_OFFSET       (PAGE_SHIFT + 8)
-#else
-#define PFN_SHIFT_OFFSET       (PAGE_SHIFT)
-#endif
 
-#define pte_pfn(x)             (pte_val(x) >> PFN_SHIFT_OFFSET)
-#define pte_page(x)            pfn_to_page(pte_pfn(x))
-
-#define pfn_pte(pfn, prot)     __pte(((pte_basic_t)(pfn) << PFN_SHIFT_OFFSET) |\
-                                       pgprot_val(prot))
-#define mk_pte(page, prot)     pfn_pte(page_to_pfn(page), prot)
-#endif /* __ASSEMBLY__ */
-
-#define pte_none(pte)          ((pte_val(pte) & ~_PTE_NONE_MASK) == 0)
-#define pte_present(pte)       (pte_val(pte) & _PAGE_PRESENT)
 #define pte_clear(mm, addr, ptep) \
        do { pte_update(ptep, ~_PAGE_HASHPTE, 0); } while (0)
 
@@ -546,43 +110,6 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
 #define        pmd_present(pmd)        (pmd_val(pmd) & _PMD_PRESENT_MASK)
 #define        pmd_clear(pmdp)         do { pmd_val(*(pmdp)) = 0; } while (0)
 
-#ifndef __ASSEMBLY__
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
- */
-static inline int pte_write(pte_t pte)         { return pte_val(pte) & _PAGE_RW; }
-static inline int pte_dirty(pte_t pte)         { return pte_val(pte) & _PAGE_DIRTY; }
-static inline int pte_young(pte_t pte)         { return pte_val(pte) & _PAGE_ACCESSED; }
-static inline int pte_file(pte_t pte)          { return pte_val(pte) & _PAGE_FILE; }
-static inline int pte_special(pte_t pte)       { return pte_val(pte) & _PAGE_SPECIAL; }
-
-static inline pte_t pte_wrprotect(pte_t pte) {
-       pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; }
-static inline pte_t pte_mkclean(pte_t pte) {
-       pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; }
-static inline pte_t pte_mkold(pte_t pte) {
-       pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
-
-static inline pte_t pte_mkwrite(pte_t pte) {
-       pte_val(pte) |= _PAGE_RW; return pte; }
-static inline pte_t pte_mkdirty(pte_t pte) {
-       pte_val(pte) |= _PAGE_DIRTY; return pte; }
-static inline pte_t pte_mkyoung(pte_t pte) {
-       pte_val(pte) |= _PAGE_ACCESSED; return pte; }
-static inline pte_t pte_mkspecial(pte_t pte) {
-       pte_val(pte) |= _PAGE_SPECIAL; return pte; }
-static inline pgprot_t pte_pgprot(pte_t pte)
-{
-       return __pgprot(pte_val(pte) & PAGE_PROT_BITS);
-}
-
-static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{
-       pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
-       return pte;
-}
-
 /*
  * When flushing the tlb entry for a page, we also need to flush the hash
  * table entry.  flush_hash_pages is assembler (for speed) in hashtable.S.
@@ -599,11 +126,19 @@ extern void flush_hash_entry(struct mm_struct *mm, pte_t *ptep,
                             unsigned long address);
 
 /*
- * Atomic PTE updates.
+ * PTE updates. This function is called whenever an existing
+ * valid PTE is updated. This does -not- include set_pte_at()
+ * which nowadays only sets a new PTE.
  *
- * pte_update clears and sets bit atomically, and returns
- * the old pte value.  In the 64-bit PTE case we lock around the
- * low PTE word since we expect ALL flag bits to be there
+ * Depending on the type of MMU, we may need to use atomic updates
+ * and the PTE may be either 32 or 64 bit wide. In the later case,
+ * when using atomic updates, only the low part of the PTE is
+ * accessed atomically.
+ *
+ * In addition, on 44x, we also maintain a global flag indicating
+ * that an executable user mapping was modified, which is needed
+ * to properly flush the virtually tagged instruction cache of
+ * those implementations.
  */
 #ifndef CONFIG_PTE_64BIT
 static inline unsigned long pte_update(pte_t *p,
@@ -667,44 +202,6 @@ static inline unsigned long long pte_update(pte_t *p,
 }
 #endif /* CONFIG_PTE_64BIT */
 
-/*
- * set_pte stores a linux PTE into the linux page table.
- * On machines which use an MMU hash table we avoid changing the
- * _PAGE_HASHPTE bit.
- */
-
-static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
-                             pte_t *ptep, pte_t pte)
-{
-#if (_PAGE_HASHPTE != 0) && defined(CONFIG_SMP) && !defined(CONFIG_PTE_64BIT)
-       pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte) & ~_PAGE_HASHPTE);
-#elif defined(CONFIG_PTE_64BIT) && defined(CONFIG_SMP)
-#if _PAGE_HASHPTE != 0
-       if (pte_val(*ptep) & _PAGE_HASHPTE)
-               flush_hash_entry(mm, ptep, addr);
-#endif
-       __asm__ __volatile__("\
-               stw%U0%X0 %2,%0\n\
-               eieio\n\
-               stw%U0%X0 %L2,%1"
-       : "=m" (*ptep), "=m" (*((unsigned char *)ptep+4))
-       : "r" (pte) : "memory");
-#else
-       *ptep = __pte((pte_val(*ptep) & _PAGE_HASHPTE)
-                     | (pte_val(pte) & ~_PAGE_HASHPTE));
-#endif
-}
-
-
-static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
-                             pte_t *ptep, pte_t pte)
-{
-#if defined(CONFIG_PTE_64BIT) && defined(CONFIG_SMP) && defined(CONFIG_DEBUG_VM)
-       WARN_ON(pte_present(*ptep));
-#endif
-       __set_pte_at(mm, addr, ptep, pte);
-}
-
 /*
  * 2.6 calls this without flushing the TLB entry; this is wrong
  * for our hash-based implementation, we fix that up here.
@@ -745,24 +242,14 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
 }
 
 
-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
-static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
+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_DIRTY | _PAGE_ACCESSED | _PAGE_RW |
+                _PAGE_HWEXEC | _PAGE_EXEC);
        pte_update(ptep, 0, bits);
 }
 
-#define  ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
-({                                                                        \
-       int __changed = !pte_same(*(__ptep), __entry);                     \
-       if (__changed) {                                                   \
-               __ptep_set_access_flags(__ptep, __entry, __dirty);         \
-               flush_tlb_page_nohash(__vma, __address);                   \
-       }                                                                  \
-       __changed;                                                         \
-})
-
 #define __HAVE_ARCH_PTE_SAME
 #define pte_same(A,B)  (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HASHPTE) == 0)
 
similarity index 57%
rename from arch/powerpc/include/asm/pgtable-4k.h
rename to arch/powerpc/include/asm/pgtable-ppc64-4k.h
index 1dbca4e7de67d70b1d28ed52c370312f81c2e041..6eefdcffa359fc7dd01d6abfa9d932f3c8c69605 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _ASM_POWERPC_PGTABLE_4K_H
-#define _ASM_POWERPC_PGTABLE_4K_H
+#ifndef _ASM_POWERPC_PGTABLE_PPC64_4K_H
+#define _ASM_POWERPC_PGTABLE_PPC64_4K_H
 /*
  * Entries per page directory level.  The PTE level must use a 64b record
  * for each page table entry.  The PMD and PGD level use a 32b record for
 #define PGDIR_SIZE     (1UL << PGDIR_SHIFT)
 #define PGDIR_MASK     (~(PGDIR_SIZE-1))
 
-/* PTE bits */
-#define _PAGE_HASHPTE  0x0400 /* software: pte has an associated HPTE */
-#define _PAGE_SECONDARY 0x8000 /* software: HPTE is in secondary group */
-#define _PAGE_GROUP_IX  0x7000 /* software: HPTE index within group */
-#define _PAGE_F_SECOND  _PAGE_SECONDARY
-#define _PAGE_F_GIX     _PAGE_GROUP_IX
-#define _PAGE_SPECIAL  0x10000 /* software: special page */
-#define __HAVE_ARCH_PTE_SPECIAL
-
-/* PTE flags to conserve for HPTE identification */
-#define _PAGE_HPTEFLAGS (_PAGE_BUSY | _PAGE_HASHPTE | \
-                        _PAGE_SECONDARY | _PAGE_GROUP_IX)
-
-/* There is no 4K PFN hack on 4K pages */
-#define _PAGE_4K_PFN   0
-
-/* PAGE_MASK gives the right answer below, but only by accident */
-/* It should be preserving the high 48 bits and then specifically */
-/* preserving _PAGE_SECONDARY | _PAGE_GROUP_IX */
-#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | \
-                         _PAGE_HPTEFLAGS | _PAGE_SPECIAL)
-
 /* Bits to mask out from a PMD to get to the PTE page */
 #define PMD_MASKED_BITS                0
 /* Bits to mask out from a PUD to get to the PMD page */
 /* Bits to mask out from a PGD to get to the PUD page */
 #define PGD_MASKED_BITS                0
 
-/* shift to put page number into pte */
-#define PTE_RPN_SHIFT  (17)
-
-#ifdef STRICT_MM_TYPECHECKS
-#define __real_pte(e,p)                ((real_pte_t){(e)})
-#define __rpte_to_pte(r)       ((r).pte)
-#else
-#define __real_pte(e,p)                (e)
-#define __rpte_to_pte(r)       (__pte(r))
-#endif
-#define __rpte_to_hidx(r,index)        (pte_val(__rpte_to_pte(r)) >> 12)
-
-#define pte_iterate_hashed_subpages(rpte, psize, va, index, shift)       \
-       do {                                                             \
-               index = 0;                                               \
-               shift = mmu_psize_defs[psize].shift;                     \
-
-#define pte_iterate_hashed_end() } while(0)
-
-#ifdef CONFIG_PPC_HAS_HASH_64K
-#define pte_pagesize_index(mm, addr, pte)      get_slice_psize(mm, addr)
-#else
-#define pte_pagesize_index(mm, addr, pte)      MMU_PAGE_4K
-#endif
 
 /*
  * 4-level page tables related bits
 #define pud_ERROR(e) \
        printk("%s:%d: bad pud %08lx.\n", __FILE__, __LINE__, pud_val(e))
 
+/*
+ * On all 4K setups, remap_4k_pfn() equates to remap_pfn_range() */
 #define remap_4k_pfn(vma, addr, pfn, prot)     \
        remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, (prot))
-#endif /* _ASM_POWERPC_PGTABLE_4K_H */
+
+#endif /* _ASM_POWERPC_PGTABLE_PPC64_4K_H */
diff --git a/arch/powerpc/include/asm/pgtable-ppc64-64k.h b/arch/powerpc/include/asm/pgtable-ppc64-64k.h
new file mode 100644 (file)
index 0000000..6cc085b
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef _ASM_POWERPC_PGTABLE_PPC64_64K_H
+#define _ASM_POWERPC_PGTABLE_PPC64_64K_H
+
+#include <asm-generic/pgtable-nopud.h>
+
+
+#define PTE_INDEX_SIZE  12
+#define PMD_INDEX_SIZE  12
+#define PUD_INDEX_SIZE 0
+#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)
+
+#define PTRS_PER_PTE   (1 << PTE_INDEX_SIZE)
+#define PTRS_PER_PMD   (1 << PMD_INDEX_SIZE)
+#define PTRS_PER_PGD   (1 << PGD_INDEX_SIZE)
+
+/* With 4k base page size, hugepage PTEs go at the PMD level */
+#define MIN_HUGEPTE_SHIFT      PAGE_SHIFT
+
+/* PMD_SHIFT determines what a second-level page table entry can map */
+#define PMD_SHIFT      (PAGE_SHIFT + PTE_INDEX_SIZE)
+#define PMD_SIZE       (1UL << PMD_SHIFT)
+#define PMD_MASK       (~(PMD_SIZE-1))
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define PGDIR_SHIFT    (PMD_SHIFT + PMD_INDEX_SIZE)
+#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 */
+#define PUD_MASKED_BITS                0x1ff
+
+#endif /* _ASM_POWERPC_PGTABLE_PPC64_64K_H */
index b0f18be81d9fbde440a17ccf52e785cfb3b7a408..c40db05f21e000a3682bf5a828ede9612cb710ec 100644 (file)
@@ -11,9 +11,9 @@
 #endif /* __ASSEMBLY__ */
 
 #ifdef CONFIG_PPC_64K_PAGES
-#include <asm/pgtable-64k.h>
+#include <asm/pgtable-ppc64-64k.h>
 #else
-#include <asm/pgtable-4k.h>
+#include <asm/pgtable-ppc64-4k.h>
 #endif
 
 #define FIRST_USER_ADDRESS     0
@@ -25,6 +25,8 @@
                            PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)
 #define PGTABLE_RANGE (ASM_CONST(1) << PGTABLE_EADDR_SIZE)
 
+
+/* Some sanity checking */
 #if TASK_SIZE_USER64 > PGTABLE_RANGE
 #error TASK_SIZE_USER64 exceeds pagetable range
 #endif
@@ -33,7 +35,6 @@
 #error TASK_SIZE_USER64 exceeds user VSID range
 #endif
 
-
 /*
  * Define the address range of the vmalloc VM area.
  */
 
 
 /*
- * Common bits in a linux-style PTE.  These match the bits in the
- * (hardware-defined) PowerPC PTE as closely as possible. Additional
- * bits may be defined in pgtable-*.h
+ * Include the PTE bits definitions
  */
-#define _PAGE_PRESENT  0x0001 /* software: pte contains a translation */
-#define _PAGE_USER     0x0002 /* matches one of the PP bits */
-#define _PAGE_FILE     0x0002 /* (!present only) software: pte holds file offset */
-#define _PAGE_EXEC     0x0004 /* No execute on POWER4 and newer (we invert) */
-#define _PAGE_GUARDED  0x0008
-#define _PAGE_COHERENT 0x0010 /* M: enforce memory coherence (SMP systems) */
-#define _PAGE_NO_CACHE 0x0020 /* I: cache inhibit */
-#define _PAGE_WRITETHRU        0x0040 /* W: cache write-through */
-#define _PAGE_DIRTY    0x0080 /* C: page changed */
-#define _PAGE_ACCESSED 0x0100 /* R: page referenced */
-#define _PAGE_RW       0x0200 /* software: user write access allowed */
-#define _PAGE_BUSY     0x0800 /* software: PTE & hash are busy */
-
-/* Strong Access Ordering */
-#define _PAGE_SAO      (_PAGE_WRITETHRU | _PAGE_NO_CACHE | _PAGE_COHERENT)
-
-#define _PAGE_BASE     (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT)
-
-#define _PAGE_WRENABLE (_PAGE_RW | _PAGE_DIRTY)
-
-/* __pgprot defined in arch/powerpc/include/asm/page.h */
-#define PAGE_NONE      __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
-
-#define PAGE_SHARED    __pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER)
-#define PAGE_SHARED_X  __pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER | _PAGE_EXEC)
-#define PAGE_COPY      __pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_COPY_X    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
-#define PAGE_READONLY  __pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_READONLY_X        __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
-#define PAGE_KERNEL    __pgprot(_PAGE_BASE | _PAGE_WRENABLE)
-#define PAGE_KERNEL_CI __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
-                              _PAGE_WRENABLE | _PAGE_NO_CACHE | _PAGE_GUARDED)
-#define PAGE_KERNEL_EXEC __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_EXEC)
-
-#define PAGE_AGP       __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_NO_CACHE)
-#define HAVE_PAGE_AGP
-
-#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | \
-                        _PAGE_NO_CACHE | _PAGE_WRITETHRU |             \
-                        _PAGE_4K_PFN | _PAGE_RW | _PAGE_USER |         \
-                        _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_EXEC)
-/* PTEIDX nibble */
-#define _PTEIDX_SECONDARY      0x8
-#define _PTEIDX_GROUP_IX       0x7
+#include <asm/pte-hash64.h>
+#include <asm/pte-common.h>
 
 
-/*
- * POWER4 and newer have per page execute protection, older chips can only
- * do this on a segment (256MB) basis.
- *
- * Also, write permissions imply read permissions.
- * This is the closest we can get..
- *
- * Note due to the way vm flags are laid out, the bits are XWR
- */
-#define __P000 PAGE_NONE
-#define __P001 PAGE_READONLY
-#define __P010 PAGE_COPY
-#define __P011 PAGE_COPY
-#define __P100 PAGE_READONLY_X
-#define __P101 PAGE_READONLY_X
-#define __P110 PAGE_COPY_X
-#define __P111 PAGE_COPY_X
-
-#define __S000 PAGE_NONE
-#define __S001 PAGE_READONLY
-#define __S010 PAGE_SHARED
-#define __S011 PAGE_SHARED
-#define __S100 PAGE_READONLY_X
-#define __S101 PAGE_READONLY_X
-#define __S110 PAGE_SHARED_X
-#define __S111 PAGE_SHARED_X
-
 #ifdef CONFIG_PPC_MM_SLICES
 #define HAVE_ARCH_UNMAPPED_AREA
 #define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
 #ifndef __ASSEMBLY__
 
 /*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- *
- * mk_pte takes a (struct page *) as input
+ * This is the default implementation of various PTE accessors, it's
+ * used in all cases except Book3S with 64K pages where we have a
+ * concept of sub-pages
  */
-#define mk_pte(page, pgprot)   pfn_pte(page_to_pfn(page), (pgprot))
+#ifndef __real_pte
 
-static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
-{
-       pte_t pte;
+#ifdef STRICT_MM_TYPECHECKS
+#define __real_pte(e,p)                ((real_pte_t){(e)})
+#define __rpte_to_pte(r)       ((r).pte)
+#else
+#define __real_pte(e,p)                (e)
+#define __rpte_to_pte(r)       (__pte(r))
+#endif
+#define __rpte_to_hidx(r,index)        (pte_val(__rpte_to_pte(r)) >> 12)
 
+#define pte_iterate_hashed_subpages(rpte, psize, va, index, shift)       \
+       do {                                                             \
+               index = 0;                                               \
+               shift = mmu_psize_defs[psize].shift;                     \
 
-       pte_val(pte) = (pfn << PTE_RPN_SHIFT) | pgprot_val(pgprot);
-       return pte;
-}
+#define pte_iterate_hashed_end() } while(0)
 
-#define pte_modify(_pte, newprot) \
-  (__pte((pte_val(_pte) & _PAGE_CHG_MASK) | pgprot_val(newprot)))
+#ifdef CONFIG_PPC_HAS_HASH_64K
+#define pte_pagesize_index(mm, addr, pte)      get_slice_psize(mm, addr)
+#else
+#define pte_pagesize_index(mm, addr, pte)      MMU_PAGE_4K
+#endif
 
-#define pte_none(pte)          ((pte_val(pte) & ~_PAGE_HPTEFLAGS) == 0)
-#define pte_present(pte)       (pte_val(pte) & _PAGE_PRESENT)
+#endif /* __real_pte */
 
-/* pte_clear moved to later in this file */
 
-#define pte_pfn(x)             ((unsigned long)((pte_val(x)>>PTE_RPN_SHIFT)))
-#define pte_page(x)            pfn_to_page(pte_pfn(x))
+/* pte_clear moved to later in this file */
 
 #define PMD_BAD_BITS           (PTE_TABLE_SIZE-1)
 #define PUD_BAD_BITS           (PMD_TABLE_SIZE-1)
@@ -235,36 +171,6 @@ static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
 /* This now only contains the vmalloc pages */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
- */
-static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW;}
-static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
-static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
-static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE;}
-static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; }
-
-static inline pte_t pte_wrprotect(pte_t pte) {
-       pte_val(pte) &= ~(_PAGE_RW); return pte; }
-static inline pte_t pte_mkclean(pte_t pte) {
-       pte_val(pte) &= ~(_PAGE_DIRTY); return pte; }
-static inline pte_t pte_mkold(pte_t pte) {
-       pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
-static inline pte_t pte_mkwrite(pte_t pte) {
-       pte_val(pte) |= _PAGE_RW; return pte; }
-static inline pte_t pte_mkdirty(pte_t pte) {
-       pte_val(pte) |= _PAGE_DIRTY; return pte; }
-static inline pte_t pte_mkyoung(pte_t pte) {
-       pte_val(pte) |= _PAGE_ACCESSED; return pte; }
-static inline pte_t pte_mkhuge(pte_t pte) {
-       return pte; }
-static inline pte_t pte_mkspecial(pte_t pte) {
-       pte_val(pte) |= _PAGE_SPECIAL; return pte; }
-static inline pgprot_t pte_pgprot(pte_t pte)
-{
-       return __pgprot(pte_val(pte) & PAGE_PROT_BITS);
-}
 
 /* Atomic PTE updates */
 static inline unsigned long pte_update(struct mm_struct *mm,
@@ -272,6 +178,7 @@ static inline unsigned long pte_update(struct mm_struct *mm,
                                       pte_t *ptep, unsigned long clr,
                                       int huge)
 {
+#ifdef PTE_ATOMIC_UPDATES
        unsigned long old, tmp;
 
        __asm__ __volatile__(
@@ -284,6 +191,13 @@ static inline unsigned long pte_update(struct mm_struct *mm,
        : "=&r" (old), "=&r" (tmp), "=m" (*ptep)
        : "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY)
        : "cc" );
+#else
+       unsigned long old = pte_val(*ptep);
+       *ptep = __pte(old & ~clr);
+#endif
+       /* huge pages use the old page table lock */
+       if (!huge)
+               assert_pte_locked(mm, addr);
 
        if (old & _PAGE_HASHPTE)
                hpte_need_flush(mm, addr, ptep, old, huge);
@@ -359,26 +273,17 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
        pte_update(mm, addr, ptep, ~0UL, 0);
 }
 
-/*
- * set_pte stores a linux PTE into the linux page table.
- */
-static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
-                             pte_t *ptep, pte_t pte)
-{
-       if (pte_present(*ptep))
-               pte_clear(mm, addr, ptep);
-       pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
-       *ptep = pte;
-}
 
 /* Set the dirty and/or accessed bits atomically in a linux PTE, this
  * function doesn't need to flush the hash entry
  */
-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
-static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
+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_DIRTY | _PAGE_ACCESSED | _PAGE_RW |
+                _PAGE_EXEC | _PAGE_HWEXEC);
+
+#ifdef PTE_ATOMIC_UPDATES
        unsigned long old, tmp;
 
        __asm__ __volatile__(
@@ -391,16 +296,11 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
        :"=&r" (old), "=&r" (tmp), "=m" (*ptep)
        :"r" (bits), "r" (ptep), "m" (*ptep), "i" (_PAGE_BUSY)
        :"cc");
+#else
+       unsigned long old = pte_val(*ptep);
+       *ptep = __pte(old | bits);
+#endif
 }
-#define  ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
-({                                                                        \
-       int __changed = !pte_same(*(__ptep), __entry);                     \
-       if (__changed) {                                                   \
-               __ptep_set_access_flags(__ptep, __entry, __dirty);         \
-               flush_tlb_page_nohash(__vma, __address);                   \
-       }                                                                  \
-       __changed;                                                         \
-})
 
 #define __HAVE_ARCH_PTE_SAME
 #define pte_same(A,B)  (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)
index 07f55e6016962c4af3c9acc34fd9b54f04f44a8b..eb17da7811289a6279f858c10281aacf496990a5 100644 (file)
@@ -6,7 +6,17 @@
 #include <asm/processor.h>             /* For TASK_SIZE */
 #include <asm/mmu.h>
 #include <asm/page.h>
+
 struct mm_struct;
+
+#ifdef CONFIG_DEBUG_VM
+extern void assert_pte_locked(struct mm_struct *mm, unsigned long addr);
+#else /* CONFIG_DEBUG_VM */
+static inline void assert_pte_locked(struct mm_struct *mm, unsigned long addr)
+{
+}
+#endif /* !CONFIG_DEBUG_VM */
+
 #endif /* !__ASSEMBLY__ */
 
 #if defined(CONFIG_PPC64)
@@ -17,6 +27,130 @@ struct mm_struct;
 
 #ifndef __ASSEMBLY__
 
+/* Generic accessors to PTE bits */
+static inline int pte_write(pte_t pte)         { return pte_val(pte) & _PAGE_RW; }
+static inline int pte_dirty(pte_t pte)         { return pte_val(pte) & _PAGE_DIRTY; }
+static inline int pte_young(pte_t pte)         { return pte_val(pte) & _PAGE_ACCESSED; }
+static inline int pte_file(pte_t pte)          { return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_special(pte_t pte)       { return pte_val(pte) & _PAGE_SPECIAL; }
+static inline int pte_present(pte_t pte)       { return pte_val(pte) & _PAGE_PRESENT; }
+static inline int pte_none(pte_t pte)          { return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; }
+static inline pgprot_t pte_pgprot(pte_t pte)   { return __pgprot(pte_val(pte) & PAGE_PROT_BITS); }
+
+/* Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ *
+ * Even if PTEs can be unsigned long long, a PFN is always an unsigned
+ * long for now.
+ */
+static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot) {
+       return __pte(((pte_basic_t)(pfn) << PTE_RPN_SHIFT) |
+                    pgprot_val(pgprot)); }
+static inline unsigned long pte_pfn(pte_t pte) {
+       return pte_val(pte) >> PTE_RPN_SHIFT; }
+
+/* Keep these as a macros to avoid include dependency mess */
+#define pte_page(x)            pfn_to_page(pte_pfn(x))
+#define mk_pte(page, pgprot)   pfn_pte(page_to_pfn(page), (pgprot))
+
+/* Generic modifiers for PTE bits */
+static inline pte_t pte_wrprotect(pte_t pte) {
+       pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; }
+static inline pte_t pte_mkclean(pte_t pte) {
+       pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; }
+static inline pte_t pte_mkold(pte_t pte) {
+       pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkwrite(pte_t pte) {
+       pte_val(pte) |= _PAGE_RW; return pte; }
+static inline pte_t pte_mkdirty(pte_t pte) {
+       pte_val(pte) |= _PAGE_DIRTY; return pte; }
+static inline pte_t pte_mkyoung(pte_t pte) {
+       pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkspecial(pte_t pte) {
+       pte_val(pte) |= _PAGE_SPECIAL; return pte; }
+static inline pte_t pte_mkhuge(pte_t pte) {
+       return pte; }
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+       pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
+       return pte;
+}
+
+
+/* Insert a PTE, top-level function is out of line. It uses an inline
+ * low level function in the respective pgtable-* files
+ */
+extern void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
+                      pte_t pte);
+
+/* This low level function performs the actual PTE insertion
+ * Setting the PTE depends on the MMU type and other factors. It's
+ * an horrible mess that I'm not going to try to clean up now but
+ * I'm keeping it in one place rather than spread around
+ */
+static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
+                               pte_t *ptep, pte_t pte, int percpu)
+{
+#if defined(CONFIG_PPC_STD_MMU_32) && defined(CONFIG_SMP) && !defined(CONFIG_PTE_64BIT)
+       /* First case is 32-bit Hash MMU in SMP mode with 32-bit PTEs. We use the
+        * helper pte_update() which does an atomic update. We need to do that
+        * because a concurrent invalidation can clear _PAGE_HASHPTE. If it's a
+        * per-CPU PTE such as a kmap_atomic, we do a simple update preserving
+        * the hash bits instead (ie, same as the non-SMP case)
+        */
+       if (percpu)
+               *ptep = __pte((pte_val(*ptep) & _PAGE_HASHPTE)
+                             | (pte_val(pte) & ~_PAGE_HASHPTE));
+       else
+               pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte));
+
+#elif defined(CONFIG_PPC32) && defined(CONFIG_PTE_64BIT) && defined(CONFIG_SMP)
+       /* Second case is 32-bit with 64-bit PTE in SMP mode. In this case, we
+        * can just store as long as we do the two halves in the right order
+        * with a barrier in between. This is possible because we take care,
+        * in the hash code, to pre-invalidate if the PTE was already hashed,
+        * which synchronizes us with any concurrent invalidation.
+        * In the percpu case, we also fallback to the simple update preserving
+        * the hash bits
+        */
+       if (percpu) {
+               *ptep = __pte((pte_val(*ptep) & _PAGE_HASHPTE)
+                             | (pte_val(pte) & ~_PAGE_HASHPTE));
+               return;
+       }
+#if _PAGE_HASHPTE != 0
+       if (pte_val(*ptep) & _PAGE_HASHPTE)
+               flush_hash_entry(mm, ptep, addr);
+#endif
+       __asm__ __volatile__("\
+               stw%U0%X0 %2,%0\n\
+               eieio\n\
+               stw%U0%X0 %L2,%1"
+       : "=m" (*ptep), "=m" (*((unsigned char *)ptep+4))
+       : "r" (pte) : "memory");
+
+#elif defined(CONFIG_PPC_STD_MMU_32)
+       /* Third case is 32-bit hash table in UP mode, we need to preserve
+        * the _PAGE_HASHPTE bit since we may not have invalidated the previous
+        * translation in the hash yet (done in a subsequent flush_tlb_xxx())
+        * and see we need to keep track that this PTE needs invalidating
+        */
+       *ptep = __pte((pte_val(*ptep) & _PAGE_HASHPTE)
+                     | (pte_val(pte) & ~_PAGE_HASHPTE));
+
+#else
+       /* Anything else just stores the PTE normally. That covers all 64-bit
+        * cases, and 32-bit non-hash with 64-bit PTEs in UP mode
+        */
+       *ptep = pte;
+#endif
+}
+
+
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+extern int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
+                                pte_t *ptep, pte_t entry, int dirty);
+
 /*
  * Macro to mark a page protection value as "uncacheable".
  */
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
new file mode 100644 (file)
index 0000000..f4a4db8
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2009 Freescale Semicondutor, 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.
+ *
+ * provides masks and opcode images for use by code generation, emulation
+ * and for instructions that older assemblers might not know about
+ */
+#ifndef _ASM_POWERPC_PPC_OPCODE_H
+#define _ASM_POWERPC_PPC_OPCODE_H
+
+#include <linux/stringify.h>
+#include <asm/asm-compat.h>
+
+/* sorted alphabetically */
+#define PPC_INST_DCBA                  0x7c0005ec
+#define PPC_INST_DCBA_MASK             0xfc0007fe
+#define PPC_INST_DCBAL                 0x7c2005ec
+#define PPC_INST_DCBZL                 0x7c2007ec
+#define PPC_INST_ISEL                  0x7c00001e
+#define PPC_INST_ISEL_MASK             0xfc00003e
+#define PPC_INST_LSWI                  0x7c0004aa
+#define PPC_INST_LSWX                  0x7c00042a
+#define PPC_INST_LWSYNC                        0x7c2004ac
+#define PPC_INST_MCRXR                 0x7c000400
+#define PPC_INST_MCRXR_MASK            0xfc0007fe
+#define PPC_INST_MFSPR_PVR             0x7c1f42a6
+#define PPC_INST_MFSPR_PVR_MASK                0xfc1fffff
+#define PPC_INST_MSGSND                        0x7c00019c
+#define PPC_INST_NOP                   0x60000000
+#define PPC_INST_POPCNTB               0x7c0000f4
+#define PPC_INST_POPCNTB_MASK          0xfc0007fe
+#define PPC_INST_RFCI                  0x4c000066
+#define PPC_INST_RFDI                  0x4c00004e
+#define PPC_INST_RFMCI                 0x4c00004c
+
+#define PPC_INST_STRING                        0x7c00042a
+#define PPC_INST_STRING_MASK           0xfc0007fe
+#define PPC_INST_STRING_GEN_MASK       0xfc00067e
+
+#define PPC_INST_STSWI                 0x7c0005aa
+#define PPC_INST_STSWX                 0x7c00052a
+#define PPC_INST_TLBILX                        0x7c000626
+#define PPC_INST_WAIT                  0x7c00007c
+
+/* macros to insert fields into opcodes */
+#define __PPC_RA(a)    ((a & 0x1f) << 16)
+#define __PPC_RB(b)    ((b & 0x1f) << 11)
+#define __PPC_T_TLB(t) ((t & 0x3) << 21)
+#define __PPC_WC(w)    ((w & 0x3) << 21)
+
+/* Deal with instructions that older assemblers aren't aware of */
+#define        PPC_DCBAL(a, b)         stringify_in_c(.long PPC_INST_DCBAL | \
+                                       __PPC_RA(a) | __PPC_RB(b))
+#define        PPC_DCBZL(a, b)         stringify_in_c(.long PPC_INST_DCBZL | \
+                                       __PPC_RA(a) | __PPC_RB(b))
+#define PPC_MSGSND(b)          stringify_in_c(.long PPC_INST_MSGSND | \
+                                       __PPC_RB(b))
+#define PPC_RFCI               stringify_in_c(.long PPC_INST_RFCI)
+#define PPC_RFDI               stringify_in_c(.long PPC_INST_RFDI)
+#define PPC_RFMCI              stringify_in_c(.long PPC_INST_RFMCI)
+#define PPC_TLBILX(t, a, b)    stringify_in_c(.long PPC_INST_TLBILX | \
+                                       __PPC_T_TLB(t) | __PPC_RA(a) | __PPC_RB(b))
+#define PPC_TLBILX_ALL(a, b)   PPC_TLBILX(0, a, b)
+#define PPC_TLBILX_PID(a, b)   PPC_TLBILX(1, a, b)
+#define PPC_TLBILX_VA(a, b)    PPC_TLBILX(3, a, b)
+#define PPC_WAIT(w)            stringify_in_c(.long PPC_INST_WAIT | \
+                                       __PPC_WC(w))
+
+#endif /* _ASM_POWERPC_PPC_OPCODE_H */
index 1a0d628eb114bc0f1a6a930ee1a171c91c1eae06..f59a66684aed56ad82d4ecac33696784edab18f7 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/stringify.h>
 #include <asm/asm-compat.h>
 #include <asm/processor.h>
+#include <asm/ppc-opcode.h>
 
 #ifndef __ASSEMBLY__
 #error __FILE__ should only be used in assembler files
@@ -167,11 +168,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_PURR);                                       \
 #define HMT_MEDIUM_HIGH or     5,5,5           # medium high priority
 #define HMT_HIGH       or      3,3,3
 
-/* handle instructions that older assemblers may not know */
-#define RFCI           .long 0x4c000066        /* rfci instruction */
-#define RFDI           .long 0x4c00004e        /* rfdi instruction */
-#define RFMCI          .long 0x4c00004c        /* rfmci instruction */
-
 #ifdef __KERNEL__
 #ifdef CONFIG_PPC64
 
index d3466490104a557de496a0c531430948384e6264..9eed29eee604713957dc9cd64c933c0262928eb6 100644 (file)
@@ -313,6 +313,25 @@ static inline void prefetchw(const void *x)
 #define HAVE_ARCH_PICK_MMAP_LAYOUT
 #endif
 
+#ifdef CONFIG_PPC64
+static inline unsigned long get_clean_sp(struct pt_regs *regs, int is_32)
+{
+       unsigned long sp;
+
+       if (is_32)
+               sp = regs->gpr[1] & 0x0ffffffffUL;
+       else
+               sp = regs->gpr[1];
+
+       return sp;
+}
+#else
+static inline unsigned long get_clean_sp(struct pt_regs *regs, int is_32)
+{
+       return regs->gpr[1];
+}
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
 #endif /* _ASM_POWERPC_PROCESSOR_H */
index cd24ac16660a2d595f7679694a7e800c92c2a7f3..0427b0b53d2dbf045bca882d2802b5a56ad373b4 100644 (file)
@@ -730,7 +730,7 @@ extern int ps3av_cmd_av_get_hw_conf(struct ps3av_pkt_av_get_hw_conf *);
 extern int ps3av_cmd_video_get_monitor_info(struct ps3av_pkt_av_get_monitor_info *,
                                            u32);
 
-extern int ps3av_set_video_mode(u32);
+extern int ps3av_set_video_mode(int);
 extern int ps3av_set_audio_mode(u32, u32, u32, u32, u32);
 extern int ps3av_get_auto_mode(void);
 extern int ps3av_get_mode(void);
index e7233a849680ce4595f8b9afc345593b9431d6ce..90dbefb8cfc4a01528c1700f123e870c160decab 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <linux/types.h>
 #include <linux/ioctl.h>
+#include <linux/types.h>
 
 /* ioctl */
 #define PS3FB_IOCTL_SETMODE       _IOW('r',  1, int) /* set video mode */
diff --git a/arch/powerpc/include/asm/pte-40x.h b/arch/powerpc/include/asm/pte-40x.h
new file mode 100644 (file)
index 0000000..07630fa
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef _ASM_POWERPC_PTE_40x_H
+#define _ASM_POWERPC_PTE_40x_H
+#ifdef __KERNEL__
+
+/*
+ * At present, all PowerPC 400-class processors share a similar TLB
+ * architecture. The instruction and data sides share a unified,
+ * 64-entry, fully-associative TLB which is maintained totally under
+ * software control. In addition, the instruction side has a
+ * hardware-managed, 4-entry, fully-associative TLB which serves as a
+ * first level to the shared TLB. These two TLBs are known as the UTLB
+ * and ITLB, respectively (see "mmu.h" for definitions).
+ *
+ * There are several potential gotchas here.  The 40x hardware TLBLO
+ * field looks like this:
+ *
+ * 0  1  2  3  4  ... 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+ * RPN.....................  0  0 EX WR ZSEL.......  W  I  M  G
+ *
+ * Where possible we make the Linux PTE bits match up with this
+ *
+ * - bits 20 and 21 must be cleared, because we use 4k pages (40x can
+ *   support down to 1k pages), this is done in the TLBMiss exception
+ *   handler.
+ * - We use only zones 0 (for kernel pages) and 1 (for user pages)
+ *   of the 16 available.  Bit 24-26 of the TLB are cleared in the TLB
+ *   miss handler.  Bit 27 is PAGE_USER, thus selecting the correct
+ *   zone.
+ * - PRESENT *must* be in the bottom two bits because swap cache
+ *   entries use the top 30 bits.  Because 40x doesn't support SMP
+ *   anyway, M is irrelevant so we borrow it for PAGE_PRESENT.  Bit 30
+ *   is cleared in the TLB miss handler before the TLB entry is loaded.
+ * - All other bits of the PTE are loaded into TLBLO without
+ *   modification, leaving us only the bits 20, 21, 24, 25, 26, 30 for
+ *   software PTE bits.  We actually use use bits 21, 24, 25, and
+ *   30 respectively for the software bits: ACCESSED, DIRTY, RW, and
+ *   PRESENT.
+ */
+
+#define        _PAGE_GUARDED   0x001   /* G: page is guarded from prefetch */
+#define _PAGE_FILE     0x001   /* when !present: nonlinear file mapping */
+#define _PAGE_PRESENT  0x002   /* software: PTE contains a translation */
+#define        _PAGE_NO_CACHE  0x004   /* I: caching is inhibited */
+#define        _PAGE_WRITETHRU 0x008   /* W: caching is write-through */
+#define        _PAGE_USER      0x010   /* matches one of the zone permission bits */
+#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_ACCESSED 0x400   /* software: R: page referenced */
+
+#define _PMD_PRESENT   0x400   /* PMD points to page of PTEs */
+#define _PMD_BAD       0x802
+#define _PMD_SIZE      0x0e0   /* size field, != 0 for large-page PMD entry */
+#define _PMD_SIZE_4M   0x0c0
+#define _PMD_SIZE_16M  0x0e0
+
+#define PMD_PAGE_SIZE(pmdval)  (1024 << (((pmdval) & _PMD_SIZE) >> 4))
+
+/* Until my rework is finished, 40x still needs atomic PTE updates */
+#define PTE_ATOMIC_UPDATES     1
+
+#endif /* __KERNEL__ */
+#endif /*  _ASM_POWERPC_PTE_40x_H */
diff --git a/arch/powerpc/include/asm/pte-44x.h b/arch/powerpc/include/asm/pte-44x.h
new file mode 100644 (file)
index 0000000..37e98bc
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef _ASM_POWERPC_PTE_44x_H
+#define _ASM_POWERPC_PTE_44x_H
+#ifdef __KERNEL__
+
+/*
+ * Definitions for PPC440
+ *
+ * Because of the 3 word TLB entries to support 36-bit addressing,
+ * the attribute are difficult to map in such a fashion that they
+ * are easily loaded during exception processing.  I decided to
+ * organize the entry so the ERPN is the only portion in the
+ * upper word of the PTE and the attribute bits below are packed
+ * in as sensibly as they can be in the area below a 4KB page size
+ * oriented RPN.  This at least makes it easy to load the RPN and
+ * ERPN fields in the TLB. -Matt
+ *
+ * This isn't entirely true anymore, at least some bits are now
+ * easier to move into the TLB from the PTE. -BenH.
+ *
+ * Note that these bits preclude future use of a page size
+ * less than 4KB.
+ *
+ *
+ * PPC 440 core has following TLB attribute fields;
+ *
+ *   TLB1:
+ *   0  1  2  3  4  ... 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+ *   RPN.................................  -  -  -  -  -  - ERPN.......
+ *
+ *   TLB2:
+ *   0  1  2  3  4  ... 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+ *   -  -  -  -  -    - U0 U1 U2 U3 W  I  M  G  E   - UX UW UR SX SW SR
+ *
+ * Newer 440 cores (440x6 as used on AMCC 460EX/460GT) have additional
+ * TLB2 storage attibute fields. Those are:
+ *
+ *   TLB2:
+ *   0...10    11   12   13   14   15   16...31
+ *   no change WL1  IL1I IL1D IL2I IL2D no change
+ *
+ * There are some constrains and options, to decide mapping software bits
+ * into TLB entry.
+ *
+ *   - PRESENT *must* be in the bottom three bits because swap cache
+ *     entries use the top 29 bits for TLB2.
+ *
+ *   - FILE *must* be in the bottom three bits because swap cache
+ *     entries use the top 29 bits for TLB2.
+ *
+ *   - CACHE COHERENT bit (M) has no effect on original PPC440 cores,
+ *     because it doesn't support SMP. However, some later 460 variants
+ *     have -some- form of SMP support and so I keep the bit there for
+ *     future use
+ *
+ * With the PPC 44x Linux implementation, the 0-11th LSBs of the PTE are used
+ * for memory protection related functions (see PTE structure in
+ * include/asm-ppc/mmu.h).  The _PAGE_XXX definitions in this file map to the
+ * above bits.  Note that the bit values are CPU specific, not architecture
+ * specific.
+ *
+ * The kernel PTE entry holds an arch-dependent swp_entry structure under
+ * certain situations. In other words, in such situations some portion of
+ * the PTE bits are used as a swp_entry. In the PPC implementation, the
+ * 3-24th LSB are shared with swp_entry, however the 0-2nd three LSB still
+ * hold protection values. That means the three protection bits are
+ * reserved for both PTE and SWAP entry at the most significant three
+ * LSBs.
+ *
+ * There are three protection bits available for SWAP entry:
+ *     _PAGE_PRESENT
+ *     _PAGE_FILE
+ *     _PAGE_HASHPTE (if HW has)
+ *
+ * So those three bits have to be inside of 0-2nd LSB of PTE.
+ *
+ */
+
+#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_ACCESSED 0x00000008              /* S: Page referenced */
+#define _PAGE_DIRTY    0x00000010              /* S: Page dirty */
+#define _PAGE_SPECIAL  0x00000020              /* S: Special page */
+#define _PAGE_USER     0x00000040              /* S: User page */
+#define _PAGE_ENDIAN   0x00000080              /* H: E bit */
+#define _PAGE_GUARDED  0x00000100              /* H: G bit */
+#define _PAGE_COHERENT 0x00000200              /* H: M bit */
+#define _PAGE_NO_CACHE 0x00000400              /* H: I bit */
+#define _PAGE_WRITETHRU        0x00000800              /* H: W bit */
+
+/* TODO: Add large page lowmem mapping support */
+#define _PMD_PRESENT   0
+#define _PMD_PRESENT_MASK (PAGE_MASK)
+#define _PMD_BAD       (~PAGE_MASK)
+
+/* ERPN in a PTE never gets cleared, ignore it */
+#define _PTE_NONE_MASK 0xffffffff00000000ULL
+
+
+#endif /* __KERNEL__ */
+#endif /*  _ASM_POWERPC_PTE_44x_H */
diff --git a/arch/powerpc/include/asm/pte-8xx.h b/arch/powerpc/include/asm/pte-8xx.h
new file mode 100644 (file)
index 0000000..8c6e312
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef _ASM_POWERPC_PTE_8xx_H
+#define _ASM_POWERPC_PTE_8xx_H
+#ifdef __KERNEL__
+
+/*
+ * The PowerPC MPC8xx uses a TLB with hardware assisted, software tablewalk.
+ * We also use the two level tables, but we can put the real bits in them
+ * needed for the TLB and tablewalk.  These definitions require Mx_CTR.PPM = 0,
+ * Mx_CTR.PPCS = 0, and MD_CTR.TWAM = 1.  The level 2 descriptor has
+ * additional page protection (when Mx_CTR.PPCS = 1) that allows TLB hit
+ * based upon user/super access.  The TLB does not have accessed nor write
+ * protect.  We assume that if the TLB get loaded with an entry it is
+ * accessed, and overload the changed bit for write protect.  We use
+ * two bits in the software pte that are supposed to be set to zero in
+ * the TLB entry (24 and 25) for these indicators.  Although the level 1
+ * descriptor contains the guarded and writethrough/copyback bits, we can
+ * set these at the page level since they get copied from the Mx_TWC
+ * register when the TLB entry is loaded.  We will use bit 27 for guard, since
+ * that is where it exists in the MD_TWC, and bit 26 for writethrough.
+ * These will get masked from the level 2 descriptor at TLB load time, and
+ * copied to the MD_TWC before it gets loaded.
+ * Large page sizes added.  We currently support two sizes, 4K and 8M.
+ * This also allows a TLB hander optimization because we can directly
+ * load the PMD into MD_TWC.  The 8M pages are only used for kernel
+ * mapping of well known areas.  The PMD (PGD) entries contain control
+ * flags in addition to the address, so care must be taken that the
+ * software no longer assumes these are only pointers.
+ */
+
+/* Definitions for 8xx embedded chips. */
+#define _PAGE_PRESENT  0x0001  /* Page is valid */
+#define _PAGE_FILE     0x0002  /* when !present: nonlinear file mapping */
+#define _PAGE_NO_CACHE 0x0002  /* I: cache inhibit */
+#define _PAGE_SHARED   0x0004  /* No ASID (context) compare */
+
+/* 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 */
+#define _PAGE_ACCESSED 0x0080  /* software: page referenced */
+
+/* Setting any bits in the nibble with the follow two controls will
+ * require a TLB exception handler change.  It is assumed unused bits
+ * are always zero.
+ */
+#define _PAGE_HWWRITE  0x0100  /* h/w write enable: never set in Linux PTE */
+#define _PAGE_USER     0x0800  /* One of the PP bits, the other is USER&~RW */
+
+#define _PMD_PRESENT   0x0001
+#define _PMD_BAD       0x0ff0
+#define _PMD_PAGE_MASK 0x000c
+#define _PMD_PAGE_8M   0x000c
+
+#define _PTE_NONE_MASK _PAGE_ACCESSED
+
+/* Until my rework is finished, 8xx still needs atomic PTE updates */
+#define PTE_ATOMIC_UPDATES     1
+
+/* We need to add _PAGE_SHARED to kernel pages */
+#define _PAGE_KERNEL_RO        (_PAGE_SHARED)
+#define _PAGE_KERNEL_RW        (_PAGE_DIRTY | _PAGE_RW | _PAGE_HWWRITE)
+
+#endif /* __KERNEL__ */
+#endif /*  _ASM_POWERPC_PTE_8xx_H */
diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h
new file mode 100644 (file)
index 0000000..d9740e8
--- /dev/null
@@ -0,0 +1,180 @@
+/* Included from asm/pgtable-*.h only ! */
+
+/*
+ * Some bits are only used on some cpu families... Make sure that all
+ * the undefined gets a sensible default
+ */
+#ifndef _PAGE_HASHPTE
+#define _PAGE_HASHPTE  0
+#endif
+#ifndef _PAGE_SHARED
+#define _PAGE_SHARED   0
+#endif
+#ifndef _PAGE_HWWRITE
+#define _PAGE_HWWRITE  0
+#endif
+#ifndef _PAGE_HWEXEC
+#define _PAGE_HWEXEC   0
+#endif
+#ifndef _PAGE_EXEC
+#define _PAGE_EXEC     0
+#endif
+#ifndef _PAGE_ENDIAN
+#define _PAGE_ENDIAN   0
+#endif
+#ifndef _PAGE_COHERENT
+#define _PAGE_COHERENT 0
+#endif
+#ifndef _PAGE_WRITETHRU
+#define _PAGE_WRITETHRU        0
+#endif
+#ifndef _PAGE_SPECIAL
+#define _PAGE_SPECIAL  0
+#endif
+#ifndef _PAGE_4K_PFN
+#define _PAGE_4K_PFN           0
+#endif
+#ifndef _PAGE_PSIZE
+#define _PAGE_PSIZE            0
+#endif
+#ifndef _PMD_PRESENT_MASK
+#define _PMD_PRESENT_MASK      _PMD_PRESENT
+#endif
+#ifndef _PMD_SIZE
+#define _PMD_SIZE      0
+#define PMD_PAGE_SIZE(pmd)     bad_call_to_PMD_PAGE_SIZE()
+#endif
+#ifndef _PAGE_KERNEL_RO
+#define _PAGE_KERNEL_RO        0
+#endif
+#ifndef _PAGE_KERNEL_RW
+#define _PAGE_KERNEL_RW        (_PAGE_DIRTY | _PAGE_RW | _PAGE_HWWRITE)
+#endif
+#ifndef _PAGE_HPTEFLAGS
+#define _PAGE_HPTEFLAGS _PAGE_HASHPTE
+#endif
+#ifndef _PTE_NONE_MASK
+#define _PTE_NONE_MASK _PAGE_HPTEFLAGS
+#endif
+
+/* Make sure we get a link error if PMD_PAGE_SIZE is ever called on a
+ * kernel without large page PMD support
+ */
+#ifndef __ASSEMBLY__
+extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
+#endif /* __ASSEMBLY__ */
+
+/* Location of the PFN in the PTE. Most 32-bit platforms use the same
+ * as _PAGE_SHIFT here (ie, naturally aligned).
+ * Platform who don't just pre-define the value so we don't override it here
+ */
+#ifndef PTE_RPN_SHIFT
+#define PTE_RPN_SHIFT  (PAGE_SHIFT)
+#endif
+
+/* The mask convered by the RPN must be a ULL on 32-bit platforms with
+ * 64-bit PTEs
+ */
+#if defined(CONFIG_PPC32) && defined(CONFIG_PTE_64BIT)
+#define PTE_RPN_MAX    (1ULL << (64 - PTE_RPN_SHIFT))
+#define PTE_RPN_MASK   (~((1ULL<<PTE_RPN_SHIFT)-1))
+#else
+#define PTE_RPN_MAX    (1UL << (32 - PTE_RPN_SHIFT))
+#define PTE_RPN_MASK   (~((1UL<<PTE_RPN_SHIFT)-1))
+#endif
+
+/* _PAGE_CHG_MASK masks of bits that are to be preserved accross
+ * pgprot changes
+ */
+#define _PAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HPTEFLAGS | _PAGE_DIRTY | \
+                         _PAGE_ACCESSED | _PAGE_SPECIAL)
+
+/* Mask of bits returned by pte_pgprot() */
+#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)
+
+/*
+ * We define 2 sets of base prot bits, one for basic pages (ie,
+ * cacheable kernel and user pages) and one for non cacheable
+ * pages. We always set _PAGE_COHERENT when SMP is enabled or
+ * the processor might need it for DMA coherency.
+ */
+#define _PAGE_BASE_NC  (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_PSIZE)
+#if defined(CONFIG_SMP) || defined(CONFIG_PPC_STD_MMU)
+#define _PAGE_BASE     (_PAGE_BASE_NC | _PAGE_COHERENT)
+#else
+#define _PAGE_BASE     (_PAGE_BASE_NC)
+#endif
+
+/* Permission masks used to generate the __P and __S table,
+ *
+ * Note:__pgprot is defined in arch/powerpc/include/asm/page.h
+ *
+ * Write permissions imply read permissions for now (we could make write-only
+ * pages on BookE but we don't bother for now). Execute permission control is
+ * possible on platforms that define _PAGE_EXEC
+ *
+ * Note due to the way vm flags are laid out, the bits are XWR
+ */
+#define PAGE_NONE      __pgprot(_PAGE_BASE)
+#define PAGE_SHARED    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
+#define PAGE_SHARED_X  __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC)
+#define PAGE_COPY      __pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_COPY_X    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#define PAGE_READONLY  __pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_READONLY_X        __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+
+#define __P000 PAGE_NONE
+#define __P001 PAGE_READONLY
+#define __P010 PAGE_COPY
+#define __P011 PAGE_COPY
+#define __P100 PAGE_READONLY_X
+#define __P101 PAGE_READONLY_X
+#define __P110 PAGE_COPY_X
+#define __P111 PAGE_COPY_X
+
+#define __S000 PAGE_NONE
+#define __S001 PAGE_READONLY
+#define __S010 PAGE_SHARED
+#define __S011 PAGE_SHARED
+#define __S100 PAGE_READONLY_X
+#define __S101 PAGE_READONLY_X
+#define __S110 PAGE_SHARED_X
+#define __S111 PAGE_SHARED_X
+
+/* Permission masks used for kernel mappings */
+#define PAGE_KERNEL    __pgprot(_PAGE_BASE | _PAGE_KERNEL_RW)
+#define PAGE_KERNEL_NC __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | \
+                                _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)
+#define PAGE_KERNEL_RO __pgprot(_PAGE_BASE | _PAGE_KERNEL_RO)
+#define PAGE_KERNEL_ROX        __pgprot(_PAGE_BASE | _PAGE_KERNEL_RO | _PAGE_EXEC)
+
+/* Protection used for kernel text. We want the debuggers to be able to
+ * set breakpoints anywhere, so don't write protect the kernel text
+ * on platforms where such control is possible.
+ */
+#if defined(CONFIG_KGDB) || defined(CONFIG_XMON) || defined(CONFIG_BDI_SWITCH) ||\
+       defined(CONFIG_KPROBES)
+#define PAGE_KERNEL_TEXT       PAGE_KERNEL_X
+#else
+#define PAGE_KERNEL_TEXT       PAGE_KERNEL_ROX
+#endif
+
+/* Make modules code happy. We don't set RO yet */
+#define PAGE_KERNEL_EXEC       PAGE_KERNEL_X
+
+/* Advertise special mapping type for AGP */
+#define PAGE_AGP               (PAGE_KERNEL_NC)
+#define HAVE_PAGE_AGP
+
+/* Advertise support for _PAGE_SPECIAL */
+#ifdef _PAGE_SPECIAL
+#define __HAVE_ARCH_PTE_SPECIAL
+#endif
+
diff --git a/arch/powerpc/include/asm/pte-fsl-booke.h b/arch/powerpc/include/asm/pte-fsl-booke.h
new file mode 100644 (file)
index 0000000..10820f5
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef _ASM_POWERPC_PTE_FSL_BOOKE_H
+#define _ASM_POWERPC_PTE_FSL_BOOKE_H
+#ifdef __KERNEL__
+
+/* PTE bit definitions for Freescale BookE SW loaded TLB MMU based
+ * processors
+ *
+   MMU Assist Register 3:
+
+   32 33 34 35 36  ... 50 51 52 53 54 55 56 57 58 59 60 61 62 63
+   RPN......................  0  0 U0 U1 U2 U3 UX SX UW SW UR SR
+
+   - PRESENT *must* be in the bottom three bits because swap cache
+     entries use the top 29 bits.
+
+   - FILE *must* be in the bottom three bits because swap cache
+     entries use the top 29 bits.
+*/
+
+/* Definitions for FSL Book-E Cores */
+#define _PAGE_PRESENT  0x00001 /* S: PTE contains a translation */
+#define _PAGE_USER     0x00002 /* S: User page (maps to UR) */
+#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_ACCESSED 0x00020 /* S: Page referenced */
+
+#define _PAGE_ENDIAN   0x00040 /* H: E bit */
+#define _PAGE_GUARDED  0x00080 /* H: G bit */
+#define _PAGE_COHERENT 0x00100 /* H: M bit */
+#define _PAGE_NO_CACHE 0x00200 /* H: I 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)
+
+#endif /* __KERNEL__ */
+#endif /*  _ASM_POWERPC_PTE_FSL_BOOKE_H */
diff --git a/arch/powerpc/include/asm/pte-hash32.h b/arch/powerpc/include/asm/pte-hash32.h
new file mode 100644 (file)
index 0000000..16e571c
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef _ASM_POWERPC_PTE_HASH32_H
+#define _ASM_POWERPC_PTE_HASH32_H
+#ifdef __KERNEL__
+
+/*
+ * The "classic" 32-bit implementation of the PowerPC MMU uses a hash
+ * table containing PTEs, together with a set of 16 segment registers,
+ * to define the virtual to physical address mapping.
+ *
+ * We use the hash table as an extended TLB, i.e. a cache of currently
+ * active mappings.  We maintain a two-level page table tree, much
+ * like that used by the i386, for the sake of the Linux memory
+ * management code.  Low-level assembler code in hash_low_32.S
+ * (procedure hash_page) is responsible for extracting ptes from the
+ * tree and putting them into the hash table when necessary, and
+ * updating the accessed and modified bits in the page table tree.
+ */
+
+#define _PAGE_PRESENT  0x001   /* software: pte contains a translation */
+#define _PAGE_HASHPTE  0x002   /* hash_page has made an HPTE for this pte */
+#define _PAGE_FILE     0x004   /* when !present: nonlinear file mapping */
+#define _PAGE_USER     0x004   /* usermode access allowed */
+#define _PAGE_GUARDED  0x008   /* G: prohibit speculative access */
+#define _PAGE_COHERENT 0x010   /* M: enforce memory coherence (SMP systems) */
+#define _PAGE_NO_CACHE 0x020   /* I: cache inhibit */
+#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 */
+
+#ifdef CONFIG_PTE_64BIT
+/* We never clear the high word of the pte */
+#define _PTE_NONE_MASK (0xffffffff00000000ULL | _PAGE_HASHPTE)
+#else
+#define _PTE_NONE_MASK _PAGE_HASHPTE
+#endif
+
+#define _PMD_PRESENT   0
+#define _PMD_PRESENT_MASK (PAGE_MASK)
+#define _PMD_BAD       (~PAGE_MASK)
+
+/* Hash table based platforms need atomic updates of the linux PTE */
+#define PTE_ATOMIC_UPDATES     1
+
+#endif /* __KERNEL__ */
+#endif /*  _ASM_POWERPC_PTE_HASH32_H */
diff --git a/arch/powerpc/include/asm/pte-hash64-4k.h b/arch/powerpc/include/asm/pte-hash64-4k.h
new file mode 100644 (file)
index 0000000..c134e80
--- /dev/null
@@ -0,0 +1,17 @@
+/* To be include by pgtable-hash64.h only */
+
+/* PTE bits */
+#define _PAGE_HASHPTE  0x0400 /* software: pte has an associated HPTE */
+#define _PAGE_SECONDARY 0x8000 /* software: HPTE is in secondary group */
+#define _PAGE_GROUP_IX  0x7000 /* software: HPTE index within group */
+#define _PAGE_F_SECOND  _PAGE_SECONDARY
+#define _PAGE_F_GIX     _PAGE_GROUP_IX
+#define _PAGE_SPECIAL  0x10000 /* software: special page */
+
+/* PTE flags to conserve for HPTE identification */
+#define _PAGE_HPTEFLAGS (_PAGE_BUSY | _PAGE_HASHPTE | \
+                        _PAGE_SECONDARY | _PAGE_GROUP_IX)
+
+/* shift to put page number into pte */
+#define PTE_RPN_SHIFT  (17)
+
similarity index 73%
rename from arch/powerpc/include/asm/pgtable-64k.h
rename to arch/powerpc/include/asm/pte-hash64-64k.h
index 7389003349a693a4f021f0144fc56d9d2e3fe4d2..e05d26fa372fc84ae833799e072dca5a39a94d37 100644 (file)
@@ -1,76 +1,6 @@
-#ifndef _ASM_POWERPC_PGTABLE_64K_H
-#define _ASM_POWERPC_PGTABLE_64K_H
-
-#include <asm-generic/pgtable-nopud.h>
-
-
-#define PTE_INDEX_SIZE  12
-#define PMD_INDEX_SIZE  12
-#define PUD_INDEX_SIZE 0
-#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)
-
-#define PTRS_PER_PTE   (1 << PTE_INDEX_SIZE)
-#define PTRS_PER_PMD   (1 << PMD_INDEX_SIZE)
-#define PTRS_PER_PGD   (1 << PGD_INDEX_SIZE)
-
-#ifdef CONFIG_PPC_SUBPAGE_PROT
-/*
- * For the sub-page protection option, we extend the PGD with one of
- * these.  Basically we have a 3-level tree, with the top level being
- * the protptrs array.  To optimize speed and memory consumption when
- * only addresses < 4GB are being protected, pointers to the first
- * four pages of sub-page protection words are stored in the low_prot
- * array.
- * Each page of sub-page protection words protects 1GB (4 bytes
- * protects 64k).  For the 3-level tree, each page of pointers then
- * protects 8TB.
- */
-struct subpage_prot_table {
-       unsigned long maxaddr;  /* only addresses < this are protected */
-       unsigned int **protptrs[2];
-       unsigned int *low_prot[4];
-};
-
-#undef PGD_TABLE_SIZE
-#define PGD_TABLE_SIZE         ((sizeof(pgd_t) << PGD_INDEX_SIZE) + \
-                                sizeof(struct subpage_prot_table))
-
-#define SBP_L1_BITS            (PAGE_SHIFT - 2)
-#define SBP_L2_BITS            (PAGE_SHIFT - 3)
-#define SBP_L1_COUNT           (1 << SBP_L1_BITS)
-#define SBP_L2_COUNT           (1 << SBP_L2_BITS)
-#define SBP_L2_SHIFT           (PAGE_SHIFT + SBP_L1_BITS)
-#define SBP_L3_SHIFT           (SBP_L2_SHIFT + SBP_L2_BITS)
-
-extern void subpage_prot_free(pgd_t *pgd);
-
-static inline struct subpage_prot_table *pgd_subpage_prot(pgd_t *pgd)
-{
-       return (struct subpage_prot_table *)(pgd + PTRS_PER_PGD);
-}
-#endif /* CONFIG_PPC_SUBPAGE_PROT */
-#endif /* __ASSEMBLY__ */
-
-/* With 4k base page size, hugepage PTEs go at the PMD level */
-#define MIN_HUGEPTE_SHIFT      PAGE_SHIFT
-
-/* PMD_SHIFT determines what a second-level page table entry can map */
-#define PMD_SHIFT      (PAGE_SHIFT + PTE_INDEX_SIZE)
-#define PMD_SIZE       (1UL << PMD_SHIFT)
-#define PMD_MASK       (~(PMD_SIZE-1))
-
-/* PGDIR_SHIFT determines what a third-level page table entry can map */
-#define PGDIR_SHIFT    (PMD_SHIFT + PMD_INDEX_SIZE)
-#define PGDIR_SIZE     (1UL << PGDIR_SHIFT)
-#define PGDIR_MASK     (~(PGDIR_SIZE-1))
+/* To be include by pgtable-hash64.h only */
 
 /* Additional PTE bits (don't change without checking asm in hash_low.S) */
-#define __HAVE_ARCH_PTE_SPECIAL
 #define _PAGE_SPECIAL  0x00000400 /* software: special page */
 #define _PAGE_HPTE_SUB 0x0ffff000 /* combo only: sub pages HPTE bits */
 #define _PAGE_HPTE_SUB0        0x08000000 /* combo only: first sub page */
@@ -107,21 +37,15 @@ static inline struct subpage_prot_table *pgd_subpage_prot(pgd_t *pgd)
  * of addressable physical space, or 46 bits for the special 4k PFNs.
  */
 #define PTE_RPN_SHIFT  (30)
-#define PTE_RPN_MAX    (1UL << (64 - PTE_RPN_SHIFT))
-#define PTE_RPN_MASK   (~((1UL<<PTE_RPN_SHIFT)-1))
-
-/* _PAGE_CHG_MASK masks of bits that are to be preserved accross
- * pgprot changes
- */
-#define _PAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HPTEFLAGS | _PAGE_DIRTY | \
-                         _PAGE_ACCESSED | _PAGE_SPECIAL)
 
-/* 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 */
-#define PUD_MASKED_BITS                0x1ff
+#ifndef __ASSEMBLY__
 
-/* Manipulate "rpte" values */
+/*
+ * With 64K pages on hash table, we have a special PTE format that
+ * uses a second "half" of the page table to encode sub-page information
+ * in order to deal with 64K made of 4K HW pages. Thus we override the
+ * generic accessors and iterators here
+ */
 #define __real_pte(e,p)        ((real_pte_t) { \
        (e), pte_val(*((p) + PTRS_PER_PTE)) })
 #define __rpte_to_hidx(r,index)        ((pte_val((r).pte) & _PAGE_COMBO) ? \
@@ -130,7 +54,6 @@ static inline struct subpage_prot_table *pgd_subpage_prot(pgd_t *pgd)
 #define __rpte_sub_valid(rpte, index) \
        (pte_val(rpte.pte) & (_PAGE_HPTE_SUB0 >> (index)))
 
-
 /* Trick: we set __end to va + 64k, which happens works for
  * a 16M page as well as we want only one iteration
  */
@@ -152,4 +75,41 @@ static inline struct subpage_prot_table *pgd_subpage_prot(pgd_t *pgd)
        remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE,                \
                        __pgprot(pgprot_val((prot)) | _PAGE_4K_PFN))
 
-#endif /* _ASM_POWERPC_PGTABLE_64K_H */
+
+#ifdef CONFIG_PPC_SUBPAGE_PROT
+/*
+ * For the sub-page protection option, we extend the PGD with one of
+ * these.  Basically we have a 3-level tree, with the top level being
+ * the protptrs array.  To optimize speed and memory consumption when
+ * only addresses < 4GB are being protected, pointers to the first
+ * four pages of sub-page protection words are stored in the low_prot
+ * array.
+ * Each page of sub-page protection words protects 1GB (4 bytes
+ * protects 64k).  For the 3-level tree, each page of pointers then
+ * protects 8TB.
+ */
+struct subpage_prot_table {
+       unsigned long maxaddr;  /* only addresses < this are protected */
+       unsigned int **protptrs[2];
+       unsigned int *low_prot[4];
+};
+
+#undef PGD_TABLE_SIZE
+#define PGD_TABLE_SIZE         ((sizeof(pgd_t) << PGD_INDEX_SIZE) + \
+                                sizeof(struct subpage_prot_table))
+
+#define SBP_L1_BITS            (PAGE_SHIFT - 2)
+#define SBP_L2_BITS            (PAGE_SHIFT - 3)
+#define SBP_L1_COUNT           (1 << SBP_L1_BITS)
+#define SBP_L2_COUNT           (1 << SBP_L2_BITS)
+#define SBP_L2_SHIFT           (PAGE_SHIFT + SBP_L1_BITS)
+#define SBP_L3_SHIFT           (SBP_L2_SHIFT + SBP_L2_BITS)
+
+extern void subpage_prot_free(pgd_t *pgd);
+
+static inline struct subpage_prot_table *pgd_subpage_prot(pgd_t *pgd)
+{
+       return (struct subpage_prot_table *)(pgd + PTRS_PER_PGD);
+}
+#endif /* CONFIG_PPC_SUBPAGE_PROT */
+#endif /* __ASSEMBLY__ */
diff --git a/arch/powerpc/include/asm/pte-hash64.h b/arch/powerpc/include/asm/pte-hash64.h
new file mode 100644 (file)
index 0000000..0419eeb
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef _ASM_POWERPC_PTE_HASH64_H
+#define _ASM_POWERPC_PTE_HASH64_H
+#ifdef __KERNEL__
+
+/*
+ * Common bits between 4K and 64K pages in a linux-style PTE.
+ * These match the bits in the (hardware-defined) PowerPC PTE as closely
+ * as possible. Additional bits may be defined in pgtable-hash64-*.h
+ *
+ * Note: We only support user read/write permissions. Supervisor always
+ * have full read/write to pages above PAGE_OFFSET (pages below that
+ * always use the user access permissions).
+ *
+ * We could create separate kernel read-only if we used the 3 PP bits
+ * combinations that newer processors provide but we currently don't.
+ */
+#define _PAGE_PRESENT          0x0001 /* software: pte contains a translation */
+#define _PAGE_USER             0x0002 /* matches one of the PP bits */
+#define _PAGE_FILE             0x0002 /* (!present only) software: pte holds file offset */
+#define _PAGE_EXEC             0x0004 /* No execute on POWER4 and newer (we invert) */
+#define _PAGE_GUARDED          0x0008
+#define _PAGE_COHERENT         0x0010 /* M: enforce memory coherence (SMP systems) */
+#define _PAGE_NO_CACHE         0x0020 /* I: cache inhibit */
+#define _PAGE_WRITETHRU                0x0040 /* W: cache write-through */
+#define _PAGE_DIRTY            0x0080 /* C: page changed */
+#define _PAGE_ACCESSED         0x0100 /* R: page referenced */
+#define _PAGE_RW               0x0200 /* software: user write access allowed */
+#define _PAGE_BUSY             0x0800 /* software: PTE & hash are busy */
+
+/* No separate kernel read-only */
+#define _PAGE_KERNEL_RW                (_PAGE_RW | _PAGE_DIRTY) /* user access blocked by key */
+#define _PAGE_KERNEL_RO                 _PAGE_KERNEL_RW
+
+/* Strong Access Ordering */
+#define _PAGE_SAO              (_PAGE_WRITETHRU | _PAGE_NO_CACHE | _PAGE_COHERENT)
+
+/* No page size encoding in the linux PTE */
+#define _PAGE_PSIZE            0
+
+/* PTEIDX nibble */
+#define _PTEIDX_SECONDARY      0x8
+#define _PTEIDX_GROUP_IX       0x7
+
+/* Hash table based platforms need atomic updates of the linux PTE */
+#define PTE_ATOMIC_UPDATES     1
+
+#ifdef CONFIG_PPC_64K_PAGES
+#include <asm/pte-hash64-64k.h>
+#else
+#include <asm/pte-hash64-4k.h>
+#endif
+
+#endif /* __KERNEL__ */
+#endif /*  _ASM_POWERPC_PTE_HASH64_H */
index f484a343efba4b8f1372f2c6a8c92af1335d6b69..c9ff1ec97479d0d7002c7ade3f6e65a811e1e9ff 100644 (file)
 #define   CTRL_RUNLATCH        0x1
 #define SPRN_DABR      0x3F5   /* Data Address Breakpoint Register */
 #define   DABR_TRANSLATION     (1UL << 2)
+#define   DABR_DATA_WRITE      (1UL << 1)
+#define   DABR_DATA_READ       (1UL << 0)
 #define SPRN_DABR2     0x13D   /* e300 */
 #define SPRN_DABRX     0x3F7   /* Data Address Breakpoint Register Extension */
 #define   DABRX_USER   (1UL << 0)
index 67453766bff1f7b6593fb1c3e75aca686e4c23c6..a56f4d61aa7264c27ec60e9008c92e464a28a6f0 100644 (file)
@@ -10,6 +10,7 @@
 #define __ASM_POWERPC_REG_BOOKE_H__
 
 /* Machine State Register (MSR) Fields */
+#define MSR_GS         (1<<28) /* Guest state */
 #define MSR_UCLE       (1<<26) /* User-mode cache lock enable */
 #define MSR_SPE                (1<<25) /* Enable SPE */
 #define MSR_DWE                (1<<10) /* Debug Wait Enable */
 #define SPRN_L1CSR0    0x3F2   /* L1 Cache Control and Status Register 0 */
 #define SPRN_L1CSR1    0x3F3   /* L1 Cache Control and Status Register 1 */
 #define SPRN_MMUCSR0   0x3F4   /* MMU Control and Status Register 0 */
+#define SPRN_MMUCFG    0x3F7   /* MMU Configuration Register */
 #define SPRN_PIT       0x3DB   /* Programmable Interval Timer */
 #define SPRN_BUCSR     0x3F5   /* Branch Unit Control and Status */
 #define SPRN_L2CSR0    0x3F9   /* L2 Data Cache Control and Status Register 0 */
index 36864364e601cb22b6221fb824929973a2b2e688..c3b193121f81724a0a28d69eeb7b5be8c7c0b1a8 100644 (file)
@@ -287,6 +287,9 @@ static inline void __raw_write_unlock(raw_rwlock_t *rw)
        rw->lock = 0;
 }
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
 #define _raw_spin_relax(lock)  __spin_yield(lock)
 #define _raw_read_relax(lock)  __rw_yield(lock)
 #define _raw_write_relax(lock) __rw_yield(lock)
index cbf2c9404c37b4ac90431dfa864f29c5d1006071..c6efc3466aa6b84c4666cfec79ec319c38862804 100644 (file)
@@ -3,7 +3,4 @@
 
 static inline int arch_prepare_suspend(void) { return 0; }
 
-void save_processor_state(void);
-void restore_processor_state(void);
-
 #endif /* __ASM_POWERPC_SUSPEND_H */
index 2a4be19a92c43275343fb5ed808667c92117bb92..f612798e1c9353f0a0044a9c7e6203e10da11b43 100644 (file)
@@ -531,7 +531,7 @@ __cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
 #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
 #endif
 
-#define arch_align_stack(x) (x)
+extern unsigned long arch_align_stack(unsigned long sp);
 
 /* Used in very early kernel initialization. */
 extern unsigned long reloc_offset(void);
index 9665a26a253aaef0c118b644ec6635f96b84a83f..9aba5a38a7c4f32a011c6af5c3bd22e28e88d8a6 100644 (file)
 
 /* We have 8k stacks on ppc32 and 16k on ppc64 */
 
-#ifdef CONFIG_PPC64
+#if defined(CONFIG_PPC64)
 #define THREAD_SHIFT           14
+#elif defined(CONFIG_PPC_256K_PAGES)
+#define THREAD_SHIFT           15
 #else
 #define THREAD_SHIFT           13
 #endif
@@ -154,6 +156,13 @@ static inline void set_restore_sigmask(void)
        ti->local_flags |= _TLF_RESTORE_SIGMASK;
        set_bit(TIF_SIGPENDING, &ti->flags);
 }
+
+#ifdef CONFIG_PPC64
+#define is_32bit_task()        (test_thread_flag(TIF_32BIT))
+#else
+#define is_32bit_task()        (1)
+#endif
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index 375258559ae64fa26e09452c4e80ca978b2a3fe3..054a16d68082a852c460d96436e9f3b7bb3ce41c 100644 (file)
@@ -24,11 +24,6 @@ static inline cpumask_t node_to_cpumask(int node)
 
 #define cpumask_of_node(node) (&numa_cpumask_lookup_table[node])
 
-static inline int node_to_first_cpu(int node)
-{
-       return cpumask_first(cpumask_of_node(node));
-}
-
 int of_node_to_nid(struct device_node *device);
 
 struct pci_bus;
index 6418ceea44b70f27d69027b3a30ee85d8bd4b3fd..cd21e5e6b04f975e09c7ae7d4feb32a862940501 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 
 extern void (*udbg_putc)(char c);
+extern void (*udbg_flush)(void);
 extern int (*udbg_getc)(void);
 extern int (*udbg_getc_poll)(void);
 
index 8d1a419df35d784a65168090a2dce93bb63ef1fc..71901fbda4a5649d737e7f37177da4fa46c3a666 100644 (file)
@@ -18,12 +18,10 @@ CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog
 CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog
 CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog
 CFLAGS_REMOVE_prom.o = -pg -mno-sched-epilog
-
-ifdef CONFIG_DYNAMIC_FTRACE
-# dynamic ftrace setup.
+# do not trace tracer code
 CFLAGS_REMOVE_ftrace.o = -pg -mno-sched-epilog
-endif
-
+# timers used by tracing
+CFLAGS_REMOVE_time.o = -pg -mno-sched-epilog
 endif
 
 obj-y                          := cputable.o ptrace.o syscalls.o \
@@ -61,6 +59,7 @@ obj-$(CONFIG_HIBERNATION)     += swsusp.o suspend.o \
 obj64-$(CONFIG_HIBERNATION)    += swsusp_asm64.o
 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
@@ -76,7 +75,7 @@ obj-y                         += time.o prom.o traps.o setup-common.o \
 obj-$(CONFIG_PPC32)            += entry_32.o setup_32.o
 obj-$(CONFIG_PPC64)            += dma-iommu.o iommu.o
 obj-$(CONFIG_KGDB)             += kgdb.o
-obj-$(CONFIG_PPC_MULTIPLATFORM)        += prom_init.o
+obj-$(CONFIG_PPC_OF_BOOT_TRAMPOLINE)   += prom_init.o
 obj-$(CONFIG_MODULES)          += ppc_ksyms.o
 obj-$(CONFIG_BOOTX_TEXT)       += btext.o
 obj-$(CONFIG_SMP)              += smp.o
@@ -94,6 +93,7 @@ obj-$(CONFIG_AUDIT)           += audit.o
 obj64-$(CONFIG_AUDIT)          += compat_audit.o
 
 obj-$(CONFIG_DYNAMIC_FTRACE)   += ftrace.o
+obj-$(CONFIG_FUNCTION_GRAPH_TRACER)    += ftrace.o
 
 obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o
 
index 73cb6a3229ae40f3da6a5b080f8757f486325872..5ffcfaa77d6acf49d9902e2ab2aed650ab1fdc85 100644 (file)
@@ -187,7 +187,7 @@ static struct aligninfo aligninfo[128] = {
        { 4, ST+F+S+U },        /* 11 1 1010: stfsux */
        { 8, ST+F+U },          /* 11 1 1011: stfdux */
        INVALID,                /* 11 1 1100 */
-       INVALID,                /* 11 1 1101 */
+       { 4, LD+F },            /* 11 1 1101: lfiwzx */
        INVALID,                /* 11 1 1110 */
        INVALID,                /* 11 1 1111 */
 };
index 42fe4da4e8ae8e555572a40535d1adb5cb4cb0b6..1e40bc0539464602451071c88109f5c9be2282fd 100644 (file)
@@ -284,9 +284,6 @@ int main(void)
 #endif /* ! CONFIG_PPC64 */
 
        /* About the CPU features table */
-       DEFINE(CPU_SPEC_ENTRY_SIZE, sizeof(struct cpu_spec));
-       DEFINE(CPU_SPEC_PVR_MASK, offsetof(struct cpu_spec, pvr_mask));
-       DEFINE(CPU_SPEC_PVR_VALUE, offsetof(struct cpu_spec, pvr_value));
        DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features));
        DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup));
        DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore));
index 10b4ab1008afe66914f4a5115868b4c2ef6cf038..7d606f89a8396311c5019fc65ba7fa66f6d720b3 100644 (file)
@@ -34,6 +34,7 @@ _GLOBAL(__setup_cpu_440grx)
        blr
 _GLOBAL(__setup_cpu_460ex)
 _GLOBAL(__setup_cpu_460gt)
+_GLOBAL(__setup_cpu_460sx)
        mflr    r4
        bl      __init_fpu_44x
        bl      __fixup_440A_mcheck
index 72d1d739525425e023ee719f45ce2ee3f1da6646..54f767e31a1a7101ff6bdd4e2030e4a4f3406719 100644 (file)
 #include <asm/ppc_asm.h>
 #include <asm/asm-offsets.h>
 #include <asm/cache.h>
+#include <asm/mmu.h>
 
 _GLOBAL(__setup_cpu_603)
        mflr    r4
+BEGIN_MMU_FTR_SECTION
+       li      r10,0
+       mtspr   SPRN_SPRG4,r10          /* init SW LRU tracking */
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)
 BEGIN_FTR_SECTION
        bl      __init_fpu_registers
 END_FTR_SECTION_IFCLR(CPU_FTR_FPU_UNAVAILABLE)
diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
new file mode 100644 (file)
index 0000000..eb4b9ad
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * This file contains low level CPU setup functions.
+ * Kumar Gala <galak@kernel.crashing.org>
+ * Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * Based on cpu_setup_6xx code by
+ * Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <asm/processor.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+
+_GLOBAL(__setup_cpu_e200)
+       /* enable dedicated debug exception handling resources (Debug APU) */
+       mfspr   r3,SPRN_HID0
+       ori     r3,r3,HID0_DAPUEN@l
+       mtspr   SPRN_HID0,r3
+       b       __setup_e200_ivors
+_GLOBAL(__setup_cpu_e500v1)
+_GLOBAL(__setup_cpu_e500v2)
+       b       __setup_e500_ivors
+_GLOBAL(__setup_cpu_e500mc)
+       b       __setup_e500mc_ivors
+
index 923f87aff20a4522f44d1e01f487938b598604ff..cd1b687544f30e4d74b9cf5ebd76c4c10bcbb718 100644 (file)
@@ -35,6 +35,10 @@ const char *powerpc_base_platform;
  * and ppc64
  */
 #ifdef CONFIG_PPC32
+extern void __setup_cpu_e200(unsigned long offset, struct cpu_spec* spec);
+extern void __setup_cpu_e500v1(unsigned long offset, struct cpu_spec* spec);
+extern void __setup_cpu_e500v2(unsigned long offset, struct cpu_spec* spec);
+extern void __setup_cpu_e500mc(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_440ep(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_440epx(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_440gx(unsigned long offset, struct cpu_spec* spec);
@@ -43,6 +47,7 @@ extern void __setup_cpu_440spe(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_440x5(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_460ex(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_460gt(unsigned long offset, struct cpu_spec* spec);
+extern void __setup_cpu_460sx(unsigned long offset, struct cpu_spec *spec);
 extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_604(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_750(unsigned long offset, struct cpu_spec* spec);
@@ -726,6 +731,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_setup              = __setup_cpu_750,
                .machine_check          = machine_check_generic,
                .platform               = "ppc750",
+               .oprofile_cpu_type      = "ppc/750",
+               .oprofile_type          = PPC_OPROFILE_G4,
        },
        {       /* 750FX rev 2.0 must disable HID0[DPM] */
                .pvr_mask               = 0xffffffff,
@@ -741,6 +748,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_setup              = __setup_cpu_750,
                .machine_check          = machine_check_generic,
                .platform               = "ppc750",
+               .oprofile_cpu_type      = "ppc/750",
+               .oprofile_type          = PPC_OPROFILE_G4,
        },
        {       /* 750FX (All revs except 2.0) */
                .pvr_mask               = 0xffff0000,
@@ -756,6 +765,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_setup              = __setup_cpu_750fx,
                .machine_check          = machine_check_generic,
                .platform               = "ppc750",
+               .oprofile_cpu_type      = "ppc/750",
+               .oprofile_type          = PPC_OPROFILE_G4,
        },
        {       /* 750GX */
                .pvr_mask               = 0xffff0000,
@@ -771,6 +782,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_setup              = __setup_cpu_750fx,
                .machine_check          = machine_check_generic,
                .platform               = "ppc750",
+               .oprofile_cpu_type      = "ppc/750",
+               .oprofile_type          = PPC_OPROFILE_G4,
        },
        {       /* 740/750 (L2CR bit need fixup for 740) */
                .pvr_mask               = 0xffff0000,
@@ -1077,7 +1090,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_name               = "e300c2",
                .cpu_features           = CPU_FTRS_E300C2,
                .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
-               .mmu_features           = MMU_FTR_USE_HIGH_BATS,
+               .mmu_features           = MMU_FTR_USE_HIGH_BATS |
+                       MMU_FTR_NEED_DTLB_SW_LRU,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .cpu_setup              = __setup_cpu_603,
@@ -1090,7 +1104,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_name               = "e300c3",
                .cpu_features           = CPU_FTRS_E300,
                .cpu_user_features      = COMMON_USER,
-               .mmu_features           = MMU_FTR_USE_HIGH_BATS,
+               .mmu_features           = MMU_FTR_USE_HIGH_BATS |
+                       MMU_FTR_NEED_DTLB_SW_LRU,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .cpu_setup              = __setup_cpu_603,
@@ -1105,7 +1120,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_name               = "e300c4",
                .cpu_features           = CPU_FTRS_E300,
                .cpu_user_features      = COMMON_USER,
-               .mmu_features           = MMU_FTR_USE_HIGH_BATS,
+               .mmu_features           = MMU_FTR_USE_HIGH_BATS |
+                       MMU_FTR_NEED_DTLB_SW_LRU,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .cpu_setup              = __setup_cpu_603,
@@ -1634,6 +1650,19 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .machine_check          = machine_check_440A,
                .platform               = "ppc440",
        },
+       { /* 460SX */
+               .pvr_mask               = 0xffffff00,
+               .pvr_value              = 0x13541800,
+               .cpu_name               = "460SX",
+               .cpu_features           = CPU_FTRS_44X,
+               .cpu_user_features      = COMMON_USER_BOOKE,
+               .mmu_features           = MMU_FTR_TYPE_44x,
+               .icache_bsize           = 32,
+               .dcache_bsize           = 32,
+               .cpu_setup              = __setup_cpu_460sx,
+               .machine_check          = machine_check_440A,
+               .platform               = "ppc440",
+       },
        {       /* default match */
                .pvr_mask               = 0x00000000,
                .pvr_value              = 0x00000000,
@@ -1687,6 +1716,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                        PPC_FEATURE_UNIFIED_CACHE,
                .mmu_features           = MMU_FTR_TYPE_FSL_E,
                .dcache_bsize           = 32,
+               .cpu_setup              = __setup_cpu_e200,
                .machine_check          = machine_check_e200,
                .platform               = "ppc5554",
        }
@@ -1706,6 +1736,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .num_pmcs               = 4,
                .oprofile_cpu_type      = "ppc/e500",
                .oprofile_type          = PPC_OPROFILE_FSL_EMB,
+               .cpu_setup              = __setup_cpu_e500v1,
                .machine_check          = machine_check_e500,
                .platform               = "ppc8540",
        },
@@ -1724,6 +1755,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .num_pmcs               = 4,
                .oprofile_cpu_type      = "ppc/e500",
                .oprofile_type          = PPC_OPROFILE_FSL_EMB,
+               .cpu_setup              = __setup_cpu_e500v2,
                .machine_check          = machine_check_e500,
                .platform               = "ppc8548",
        },
@@ -1733,12 +1765,14 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_name               = "e500mc",
                .cpu_features           = CPU_FTRS_E500MC,
                .cpu_user_features      = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
-               .mmu_features           = MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS,
+               .mmu_features           = MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS |
+                       MMU_FTR_USE_TLBILX,
                .icache_bsize           = 64,
                .dcache_bsize           = 64,
                .num_pmcs               = 4,
                .oprofile_cpu_type      = "ppc/e500", /* xxx - galak, e500mc? */
                .oprofile_type          = PPC_OPROFILE_FSL_EMB,
+               .cpu_setup              = __setup_cpu_e500mc,
                .machine_check          = machine_check_e500,
                .platform               = "ppce500mc",
        },
@@ -1762,74 +1796,84 @@ static struct cpu_spec __initdata cpu_specs[] = {
 
 static struct cpu_spec the_cpu_spec;
 
-struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr)
+static void __init setup_cpu_spec(unsigned long offset, struct cpu_spec *s)
 {
-       struct cpu_spec *s = cpu_specs;
        struct cpu_spec *t = &the_cpu_spec;
-       int i;
+       struct cpu_spec old;
 
-       s = PTRRELOC(s);
        t = PTRRELOC(t);
+       old = *t;
 
-       for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++)
-               if ((pvr & s->pvr_mask) == s->pvr_value) {
-                       /*
-                        * If we are overriding a previous value derived
-                        * from the real PVR with a new value obtained
-                        * using a logical PVR value, don't modify the
-                        * performance monitor fields.
-                        */
-                       if (t->num_pmcs && !s->num_pmcs) {
-                               t->cpu_name = s->cpu_name;
-                               t->cpu_features = s->cpu_features;
-                               t->cpu_user_features = s->cpu_user_features;
-                               t->icache_bsize = s->icache_bsize;
-                               t->dcache_bsize = s->dcache_bsize;
-                               t->cpu_setup = s->cpu_setup;
-                               t->cpu_restore = s->cpu_restore;
-                               t->platform = s->platform;
-                               /*
-                                * If we have passed through this logic once
-                                * before and have pulled the default case
-                                * because the real PVR was not found inside
-                                * cpu_specs[], then we are possibly running in
-                                * compatibility mode. In that case, let the
-                                * oprofiler know which set of compatibility
-                                * counters to pull from by making sure the
-                                * oprofile_cpu_type string is set to that of
-                                * compatibility mode. If the oprofile_cpu_type
-                                * already has a value, then we are possibly
-                                * overriding a real PVR with a logical one, and,
-                                * in that case, keep the current value for
-                                * oprofile_cpu_type.
-                                */
-                               if (t->oprofile_cpu_type == NULL)
-                                       t->oprofile_cpu_type = s->oprofile_cpu_type;
-                       } else
-                               *t = *s;
-                       *PTRRELOC(&cur_cpu_spec) = &the_cpu_spec;
+       /* Copy everything, then do fixups */
+       *t = *s;
+
+       /*
+        * If we are overriding a previous value derived from the real
+        * PVR with a new value obtained using a logical PVR value,
+        * don't modify the performance monitor fields.
+        */
+       if (old.num_pmcs && !s->num_pmcs) {
+               t->num_pmcs = old.num_pmcs;
+               t->pmc_type = old.pmc_type;
+               t->oprofile_type = old.oprofile_type;
+               t->oprofile_mmcra_sihv = old.oprofile_mmcra_sihv;
+               t->oprofile_mmcra_sipr = old.oprofile_mmcra_sipr;
+               t->oprofile_mmcra_clear = old.oprofile_mmcra_clear;
+
+               /*
+                * If we have passed through this logic once before and
+                * have pulled the default case because the real PVR was
+                * not found inside cpu_specs[], then we are possibly
+                * running in compatibility mode. In that case, let the
+                * oprofiler know which set of compatibility counters to
+                * pull from by making sure the oprofile_cpu_type string
+                * is set to that of compatibility mode. If the
+                * oprofile_cpu_type already has a value, then we are
+                * possibly overriding a real PVR with a logical one,
+                * and, in that case, keep the current value for
+                * oprofile_cpu_type.
+                */
+               if (old.oprofile_cpu_type == NULL)
+                       t->oprofile_cpu_type = s->oprofile_cpu_type;
+       }
 
-                       /*
-                        * Set the base platform string once; assumes
-                        * we're called with real pvr first.
-                        */
-                       if (*PTRRELOC(&powerpc_base_platform) == NULL)
-                               *PTRRELOC(&powerpc_base_platform) = t->platform;
+       *PTRRELOC(&cur_cpu_spec) = &the_cpu_spec;
+
+       /*
+        * Set the base platform string once; assumes
+        * we're called with real pvr first.
+        */
+       if (*PTRRELOC(&powerpc_base_platform) == NULL)
+               *PTRRELOC(&powerpc_base_platform) = t->platform;
 
 #if defined(CONFIG_PPC64) || defined(CONFIG_BOOKE)
-                       /* ppc64 and booke expect identify_cpu to also call
-                        * setup_cpu for that processor. I will consolidate
-                        * that at a later time, for now, just use #ifdef.
-                        * we also don't need to PTRRELOC the function pointer
-                        * on ppc64 and booke as we are running at 0 in real
-                        * mode on ppc64 and reloc_offset is always 0 on booke.
-                        */
-                       if (s->cpu_setup) {
-                               s->cpu_setup(offset, s);
-                       }
+       /* ppc64 and booke expect identify_cpu to also call setup_cpu for
+        * that processor. I will consolidate that at a later time, for now,
+        * just use #ifdef. We also don't need to PTRRELOC the function
+        * pointer on ppc64 and booke as we are running at 0 in real mode
+        * on ppc64 and reloc_offset is always 0 on booke.
+        */
+       if (s->cpu_setup) {
+               s->cpu_setup(offset, s);
+       }
 #endif /* CONFIG_PPC64 || CONFIG_BOOKE */
+}
+
+struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr)
+{
+       struct cpu_spec *s = cpu_specs;
+       int i;
+
+       s = PTRRELOC(s);
+
+       for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) {
+               if ((pvr & s->pvr_mask) == s->pvr_value) {
+                       setup_cpu_spec(offset, s);
                        return s;
                }
+       }
+
        BUG();
+
        return NULL;
 }
index 19671aca659137ca8a6f62ac80585d969203a6f9..5fb667a60894dd6238b51db9c13b1caf93fc0253 100644 (file)
@@ -48,7 +48,7 @@ static void __init create_trampoline(unsigned long addr)
         * branch to "addr" we jump to ("addr" + 32 MB). Although it requires
         * two instructions it doesn't require any registers.
         */
-       patch_instruction(p, PPC_NOP_INSTR);
+       patch_instruction(p, PPC_INST_NOP);
        patch_branch(++p, addr + PHYSICAL_START, 0);
 }
 
diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c
new file mode 100644 (file)
index 0000000..1493734
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Author: Kumar Gala <galak@kernel.crashing.org>
+ *
+ * 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/smp.h>
+#include <linux/threads.h>
+
+#include <asm/dbell.h>
+
+#ifdef CONFIG_SMP
+unsigned long dbell_smp_message[NR_CPUS];
+
+void smp_dbell_message_pass(int target, int msg)
+{
+       int i;
+
+       if(target < NR_CPUS) {
+               set_bit(msg, &dbell_smp_message[target]);
+               ppc_msgsnd(PPC_DBELL, 0, target);
+       }
+       else if(target == MSG_ALL_BUT_SELF) {
+               for_each_online_cpu(i) {
+                       if (i == smp_processor_id())
+                               continue;
+                       set_bit(msg, &dbell_smp_message[i]);
+                       ppc_msgsnd(PPC_DBELL, 0, i);
+               }
+       }
+       else { /* target == MSG_ALL */
+               for_each_online_cpu(i)
+                       set_bit(msg, &dbell_smp_message[i]);
+               ppc_msgsnd(PPC_DBELL, PPC_DBELL_MSG_BRDCAST, 0);
+       }
+}
+#endif
index 6f7eb7e00c79eb3df9c6eba5ad61087e36427015..4dd38f129153f7c90340cde840774dc11da22500 100644 (file)
@@ -63,7 +63,7 @@ debug_transfer_to_handler:
 
        .globl  crit_transfer_to_handler
 crit_transfer_to_handler:
-#ifdef CONFIG_FSL_BOOKE
+#ifdef CONFIG_PPC_BOOK3E_MMU
        mfspr   r0,SPRN_MAS0
        stw     r0,MAS0(r11)
        mfspr   r0,SPRN_MAS1
@@ -78,7 +78,7 @@ crit_transfer_to_handler:
        mfspr   r0,SPRN_MAS7
        stw     r0,MAS7(r11)
 #endif /* CONFIG_PHYS_64BIT */
-#endif /* CONFIG_FSL_BOOKE */
+#endif /* CONFIG_PPC_BOOK3E_MMU */
 #ifdef CONFIG_44x
        mfspr   r0,SPRN_MMUCR
        stw     r0,MMUCR(r11)
@@ -914,7 +914,7 @@ exc_exit_restart_end:
        mtspr   SPRN_##exc_lvl_srr0,r9;                                 \
        mtspr   SPRN_##exc_lvl_srr1,r10;
 
-#if defined(CONFIG_FSL_BOOKE)
+#if defined(CONFIG_PPC_BOOK3E_MMU)
 #ifdef CONFIG_PHYS_64BIT
 #define        RESTORE_MAS7                                                    \
        lwz     r11,MAS7(r1);                                           \
@@ -956,7 +956,7 @@ ret_from_crit_exc:
        lwz     r10,crit_srr1@l(r10);
        mtspr   SPRN_SRR0,r9;
        mtspr   SPRN_SRR1,r10;
-       RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI)
+       RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, PPC_RFCI)
 #endif /* CONFIG_40x */
 
 #ifdef CONFIG_BOOKE
@@ -967,7 +967,7 @@ ret_from_crit_exc:
        stw     r10,KSP_LIMIT(r9)
        RESTORE_xSRR(SRR0,SRR1);
        RESTORE_MMU_REGS;
-       RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI)
+       RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, PPC_RFCI)
 
        .globl  ret_from_debug_exc
 ret_from_debug_exc:
@@ -981,7 +981,7 @@ ret_from_debug_exc:
        RESTORE_xSRR(SRR0,SRR1);
        RESTORE_xSRR(CSRR0,CSRR1);
        RESTORE_MMU_REGS;
-       RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, RFDI)
+       RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, PPC_RFDI)
 
        .globl  ret_from_mcheck_exc
 ret_from_mcheck_exc:
@@ -992,7 +992,7 @@ ret_from_mcheck_exc:
        RESTORE_xSRR(CSRR0,CSRR1);
        RESTORE_xSRR(DSRR0,DSRR1);
        RESTORE_MMU_REGS;
-       RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI)
+       RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, PPC_RFMCI)
 #endif /* CONFIG_BOOKE */
 
 /*
@@ -1176,59 +1176,27 @@ _GLOBAL(_mcount)
        bctr
 
 _GLOBAL(ftrace_caller)
-       /* Based off of objdump optput from glibc */
-       stwu    r1,-48(r1)
-       stw     r3, 12(r1)
-       stw     r4, 16(r1)
-       stw     r5, 20(r1)
-       stw     r6, 24(r1)
-       mflr    r3
-       lwz     r4, 52(r1)
-       mfcr    r5
-       stw     r7, 28(r1)
-       stw     r8, 32(r1)
-       stw     r9, 36(r1)
-       stw     r10,40(r1)
-       stw     r3, 44(r1)
-       stw     r5, 8(r1)
+       MCOUNT_SAVE_FRAME
+       /* r3 ends up with link register */
        subi    r3, r3, MCOUNT_INSN_SIZE
 .globl ftrace_call
 ftrace_call:
        bl      ftrace_stub
        nop
-       lwz     r6, 8(r1)
-       lwz     r0, 44(r1)
-       lwz     r3, 12(r1)
-       mtctr   r0
-       lwz     r4, 16(r1)
-       mtcr    r6
-       lwz     r5, 20(r1)
-       lwz     r6, 24(r1)
-       lwz     r0, 52(r1)
-       lwz     r7, 28(r1)
-       lwz     r8, 32(r1)
-       mtlr    r0
-       lwz     r9, 36(r1)
-       lwz     r10,40(r1)
-       addi    r1, r1, 48
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+.globl ftrace_graph_call
+ftrace_graph_call:
+       b       ftrace_graph_stub
+_GLOBAL(ftrace_graph_stub)
+#endif
+       MCOUNT_RESTORE_FRAME
+       /* old link register ends up in ctr reg */
        bctr
 #else
 _GLOBAL(mcount)
 _GLOBAL(_mcount)
-       stwu    r1,-48(r1)
-       stw     r3, 12(r1)
-       stw     r4, 16(r1)
-       stw     r5, 20(r1)
-       stw     r6, 24(r1)
-       mflr    r3
-       lwz     r4, 52(r1)
-       mfcr    r5
-       stw     r7, 28(r1)
-       stw     r8, 32(r1)
-       stw     r9, 36(r1)
-       stw     r10,40(r1)
-       stw     r3, 44(r1)
-       stw     r5, 8(r1)
+
+       MCOUNT_SAVE_FRAME
 
        subi    r3, r3, MCOUNT_INSN_SIZE
        LOAD_REG_ADDR(r5, ftrace_trace_function)
@@ -1236,28 +1204,55 @@ _GLOBAL(_mcount)
 
        mtctr   r5
        bctrl
-
        nop
 
-       lwz     r6, 8(r1)
-       lwz     r0, 44(r1)
-       lwz     r3, 12(r1)
-       mtctr   r0
-       lwz     r4, 16(r1)
-       mtcr    r6
-       lwz     r5, 20(r1)
-       lwz     r6, 24(r1)
-       lwz     r0, 52(r1)
-       lwz     r7, 28(r1)
-       lwz     r8, 32(r1)
-       mtlr    r0
-       lwz     r9, 36(r1)
-       lwz     r10,40(r1)
-       addi    r1, r1, 48
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       b       ftrace_graph_caller
+#endif
+       MCOUNT_RESTORE_FRAME
        bctr
 #endif
 
 _GLOBAL(ftrace_stub)
        blr
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+_GLOBAL(ftrace_graph_caller)
+       /* load r4 with local address */
+       lwz     r4, 44(r1)
+       subi    r4, r4, MCOUNT_INSN_SIZE
+
+       /* get the parent address */
+       addi    r3, r1, 52
+
+       bl      prepare_ftrace_return
+       nop
+
+       MCOUNT_RESTORE_FRAME
+       /* old link register ends up in ctr reg */
+       bctr
+
+_GLOBAL(return_to_handler)
+       /* need to save return values */
+       stwu    r1, -32(r1)
+       stw     r3, 20(r1)
+       stw     r4, 16(r1)
+       stw     r31, 12(r1)
+       mr      r31, r1
+
+       bl      ftrace_return_to_handler
+       nop
+
+       /* return value has real return address */
+       mtlr    r3
+
+       lwz     r3, 20(r1)
+       lwz     r4, 16(r1)
+       lwz     r31,12(r1)
+       lwz     r1, 0(r1)
+
+       /* Jump back to real return address */
+       blr
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
 #endif /* CONFIG_MCOUNT */
index 383ed6eb00850d2a7ab89b3b54b4677a3b9b1478..abfc3233047900ac675559928adc73b52466f75b 100644 (file)
@@ -908,6 +908,12 @@ _GLOBAL(ftrace_caller)
 ftrace_call:
        bl      ftrace_stub
        nop
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+.globl ftrace_graph_call
+ftrace_graph_call:
+       b       ftrace_graph_stub
+_GLOBAL(ftrace_graph_stub)
+#endif
        ld      r0, 128(r1)
        mtlr    r0
        addi    r1, r1, 112
@@ -931,13 +937,90 @@ _GLOBAL(_mcount)
        ld      r5,0(r5)
        mtctr   r5
        bctrl
-
        nop
+
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       b       ftrace_graph_caller
+#endif
        ld      r0, 128(r1)
        mtlr    r0
        addi    r1, r1, 112
 _GLOBAL(ftrace_stub)
        blr
 
-#endif
-#endif
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+_GLOBAL(ftrace_graph_caller)
+       /* load r4 with local address */
+       ld      r4, 128(r1)
+       subi    r4, r4, MCOUNT_INSN_SIZE
+
+       /* get the parent address */
+       ld      r11, 112(r1)
+       addi    r3, r11, 16
+
+       bl      .prepare_ftrace_return
+       nop
+
+       ld      r0, 128(r1)
+       mtlr    r0
+       addi    r1, r1, 112
+       blr
+
+_GLOBAL(return_to_handler)
+       /* need to save return values */
+       std     r4,  -24(r1)
+       std     r3,  -16(r1)
+       std     r31, -8(r1)
+       mr      r31, r1
+       stdu    r1, -112(r1)
+
+       bl      .ftrace_return_to_handler
+       nop
+
+       /* return value has real return address */
+       mtlr    r3
+
+       ld      r1, 0(r1)
+       ld      r4,  -24(r1)
+       ld      r3,  -16(r1)
+       ld      r31, -8(r1)
+
+       /* Jump back to real return address */
+       blr
+
+_GLOBAL(mod_return_to_handler)
+       /* need to save return values */
+       std     r4,  -32(r1)
+       std     r3,  -24(r1)
+       /* save TOC */
+       std     r2,  -16(r1)
+       std     r31, -8(r1)
+       mr      r31, r1
+       stdu    r1, -112(r1)
+
+       /*
+        * We are in a module using the module's TOC.
+        * Switch to our TOC to run inside the core kernel.
+        */
+       LOAD_REG_IMMEDIATE(r4,ftrace_return_to_handler)
+       ld      r2, 8(r4)
+
+       bl      .ftrace_return_to_handler
+       nop
+
+       /* return value has real return address */
+       mtlr    r3
+
+       ld      r1, 0(r1)
+       ld      r4,  -32(r1)
+       ld      r3,  -24(r1)
+       ld      r2,  -16(r1)
+       ld      r31, -8(r1)
+
+       /* Jump back to real return address */
+       blr
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+#endif /* CONFIG_FUNCTION_TRACER */
index 60c60ccf5e3c83cdd3f9d02fe2b0d48c88edf66b..5b5d16b2cac86b0dad038cdcc13c2cc686bd41a2 100644 (file)
@@ -5,6 +5,9 @@
  *
  * Thanks goes out to P.A. Semi, Inc for supplying me with a PPC64 box.
  *
+ * Added function graph tracer code, taken from x86 that was written
+ * by Frederic Weisbecker, and ported to PPC by Steven Rostedt.
+ *
  */
 
 #include <linux/spinlock.h>
 #include <asm/code-patching.h>
 #include <asm/ftrace.h>
 
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(fmt , ...)      do { } while (0)
-#endif
-
-static unsigned int ftrace_nop = PPC_NOP_INSTR;
-
 #ifdef CONFIG_PPC32
 # define GET_ADDR(addr) addr
 #else
@@ -35,37 +30,23 @@ static unsigned int ftrace_nop = PPC_NOP_INSTR;
 # define GET_ADDR(addr) (*(unsigned long *)addr)
 #endif
 
-
-static unsigned int ftrace_calc_offset(long ip, long addr)
+#ifdef CONFIG_DYNAMIC_FTRACE
+static unsigned int ftrace_nop_replace(void)
 {
-       return (int)(addr - ip);
+       return PPC_INST_NOP;
 }
 
-static unsigned char *ftrace_nop_replace(void)
+static unsigned int
+ftrace_call_replace(unsigned long ip, unsigned long addr, int link)
 {
-       return (char *)&ftrace_nop;
-}
-
-static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
-{
-       static unsigned int op;
+       unsigned int op;
 
-       /*
-        * It would be nice to just use create_function_call, but that will
-        * update the code itself. Here we need to just return the
-        * instruction that is going to be modified, without modifying the
-        * code.
-        */
        addr = GET_ADDR(addr);
 
-       /* Set to "bl addr" */
-       op = 0x48000001 | (ftrace_calc_offset(ip, addr) & 0x03fffffc);
+       /* if (link) set op to 'bl' else 'b' */
+       op = create_branch((unsigned int *)ip, addr, link ? 1 : 0);
 
-       /*
-        * No locking needed, this must be called via kstop_machine
-        * which in essence is like running on a uniprocessor machine.
-        */
-       return (unsigned char *)&op;
+       return op;
 }
 
 #ifdef CONFIG_PPC64
@@ -77,10 +58,9 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
 #endif
 
 static int
-ftrace_modify_code(unsigned long ip, unsigned char *old_code,
-                  unsigned char *new_code)
+ftrace_modify_code(unsigned long ip, unsigned int old, unsigned int new)
 {
-       unsigned char replaced[MCOUNT_INSN_SIZE];
+       unsigned int replaced;
 
        /*
         * Note: Due to modules and __init, code can
@@ -93,15 +73,15 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
         */
 
        /* read the text we want to modify */
-       if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
+       if (probe_kernel_read(&replaced, (void *)ip, MCOUNT_INSN_SIZE))
                return -EFAULT;
 
        /* Make sure it is what we expect it to be */
-       if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)
+       if (replaced != old)
                return -EINVAL;
 
        /* replace the text with the new text */
-       if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE))
+       if (probe_kernel_write((void *)ip, &new, MCOUNT_INSN_SIZE))
                return -EPERM;
 
        flush_icache_range(ip, ip + 8);
@@ -119,6 +99,8 @@ static int test_24bit_addr(unsigned long ip, unsigned long addr)
        return create_branch((unsigned int *)ip, addr, 0);
 }
 
+#ifdef CONFIG_MODULES
+
 static int is_bl_op(unsigned int op)
 {
        return (op & 0xfc000003) == 0x48000001;
@@ -175,7 +157,7 @@ __ftrace_make_nop(struct module *mod,
         * 0xe8, 0x4c, 0x00, 0x28,    ld      r2,40(r12)
         */
 
-       DEBUGP("ip:%lx jumps to %lx r2: %lx", ip, tramp, mod->arch.toc);
+       pr_debug("ip:%lx jumps to %lx r2: %lx", ip, tramp, mod->arch.toc);
 
        /* Find where the trampoline jumps to */
        if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) {
@@ -183,7 +165,7 @@ __ftrace_make_nop(struct module *mod,
                return -EFAULT;
        }
 
-       DEBUGP(" %08x %08x", jmp[0], jmp[1]);
+       pr_debug(" %08x %08x", jmp[0], jmp[1]);
 
        /* verify that this is what we expect it to be */
        if (((jmp[0] & 0xffff0000) != 0x3d820000) ||
@@ -199,18 +181,18 @@ __ftrace_make_nop(struct module *mod,
        offset = ((unsigned)((unsigned short)jmp[0]) << 16) +
                (int)((short)jmp[1]);
 
-       DEBUGP(" %x ", offset);
+       pr_debug(" %x ", offset);
 
        /* get the address this jumps too */
        tramp = mod->arch.toc + offset + 32;
-       DEBUGP("toc: %lx", tramp);
+       pr_debug("toc: %lx", tramp);
 
        if (probe_kernel_read(jmp, (void *)tramp, 8)) {
                printk(KERN_ERR "Failed to read %lx\n", tramp);
                return -EFAULT;
        }
 
-       DEBUGP(" %08x %08x\n", jmp[0], jmp[1]);
+       pr_debug(" %08x %08x\n", jmp[0], jmp[1]);
 
        ptr = ((unsigned long)jmp[0] << 32) + jmp[1];
 
@@ -287,7 +269,7 @@ __ftrace_make_nop(struct module *mod,
         *  0x4e, 0x80, 0x04, 0x20  bctr
         */
 
-       DEBUGP("ip:%lx jumps to %lx", ip, tramp);
+       pr_debug("ip:%lx jumps to %lx", ip, tramp);
 
        /* Find where the trampoline jumps to */
        if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) {
@@ -295,7 +277,7 @@ __ftrace_make_nop(struct module *mod,
                return -EFAULT;
        }
 
-       DEBUGP(" %08x %08x ", jmp[0], jmp[1]);
+       pr_debug(" %08x %08x ", jmp[0], jmp[1]);
 
        /* verify that this is what we expect it to be */
        if (((jmp[0] & 0xffff0000) != 0x3d600000) ||
@@ -311,7 +293,7 @@ __ftrace_make_nop(struct module *mod,
        if (tramp & 0x8000)
                tramp -= 0x10000;
 
-       DEBUGP(" %x ", tramp);
+       pr_debug(" %x ", tramp);
 
        if (tramp != addr) {
                printk(KERN_ERR
@@ -320,7 +302,7 @@ __ftrace_make_nop(struct module *mod,
                return -EINVAL;
        }
 
-       op = PPC_NOP_INSTR;
+       op = PPC_INST_NOP;
 
        if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE))
                return -EPERM;
@@ -330,12 +312,13 @@ __ftrace_make_nop(struct module *mod,
        return 0;
 }
 #endif /* PPC64 */
+#endif /* CONFIG_MODULES */
 
 int ftrace_make_nop(struct module *mod,
                    struct dyn_ftrace *rec, unsigned long addr)
 {
-       unsigned char *old, *new;
        unsigned long ip = rec->ip;
+       unsigned int old, new;
 
        /*
         * If the calling address is more that 24 bits away,
@@ -344,11 +327,12 @@ int ftrace_make_nop(struct module *mod,
         */
        if (test_24bit_addr(ip, addr)) {
                /* within range */
-               old = ftrace_call_replace(ip, addr);
+               old = ftrace_call_replace(ip, addr, 1);
                new = ftrace_nop_replace();
                return ftrace_modify_code(ip, old, new);
        }
 
+#ifdef CONFIG_MODULES
        /*
         * Out of range jumps are called from modules.
         * We should either already have a pointer to the module
@@ -373,9 +357,13 @@ int ftrace_make_nop(struct module *mod,
                mod = rec->arch.mod;
 
        return __ftrace_make_nop(mod, rec, addr);
-
+#else
+       /* We should not get here without modules */
+       return -EINVAL;
+#endif /* CONFIG_MODULES */
 }
 
+#ifdef CONFIG_MODULES
 #ifdef CONFIG_PPC64
 static int
 __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
@@ -392,7 +380,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
         *  b +8; ld r2,40(r1)
         */
        if (((op[0] != 0x48000008) || (op[1] != 0xe8410028)) &&
-           ((op[0] != PPC_NOP_INSTR) || (op[1] != PPC_NOP_INSTR))) {
+           ((op[0] != PPC_INST_NOP) || (op[1] != PPC_INST_NOP))) {
                printk(KERN_ERR "Expected NOPs but have %x %x\n", op[0], op[1]);
                return -EINVAL;
        }
@@ -414,7 +402,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
        /* ld r2,40(r1) */
        op[1] = 0xe8410028;
 
-       DEBUGP("write to %lx\n", rec->ip);
+       pr_debug("write to %lx\n", rec->ip);
 
        if (probe_kernel_write((void *)ip, op, MCOUNT_INSN_SIZE * 2))
                return -EPERM;
@@ -435,7 +423,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
                return -EFAULT;
 
        /* It should be pointing to a nop */
-       if (op != PPC_NOP_INSTR) {
+       if (op != PPC_INST_NOP) {
                printk(KERN_ERR "Expected NOP but have %x\n", op);
                return -EINVAL;
        }
@@ -454,7 +442,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
                return -EINVAL;
        }
 
-       DEBUGP("write to %lx\n", rec->ip);
+       pr_debug("write to %lx\n", rec->ip);
 
        if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE))
                return -EPERM;
@@ -464,11 +452,12 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
        return 0;
 }
 #endif /* CONFIG_PPC64 */
+#endif /* CONFIG_MODULES */
 
 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 {
-       unsigned char *old, *new;
        unsigned long ip = rec->ip;
+       unsigned int old, new;
 
        /*
         * If the calling address is more that 24 bits away,
@@ -478,10 +467,11 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
        if (test_24bit_addr(ip, addr)) {
                /* within range */
                old = ftrace_nop_replace();
-               new = ftrace_call_replace(ip, addr);
+               new = ftrace_call_replace(ip, addr, 1);
                return ftrace_modify_code(ip, old, new);
        }
 
+#ifdef CONFIG_MODULES
        /*
         * Out of range jumps are called from modules.
         * Being that we are converting from nop, it had better
@@ -493,16 +483,20 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
        }
 
        return __ftrace_make_call(rec, addr);
+#else
+       /* We should not get here without modules */
+       return -EINVAL;
+#endif /* CONFIG_MODULES */
 }
 
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
        unsigned long ip = (unsigned long)(&ftrace_call);
-       unsigned char old[MCOUNT_INSN_SIZE], *new;
+       unsigned int old, new;
        int ret;
 
-       memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE);
-       new = ftrace_call_replace(ip, (unsigned long)func);
+       old = *(unsigned int *)&ftrace_call;
+       new = ftrace_call_replace(ip, (unsigned long)func, 1);
        ret = ftrace_modify_code(ip, old, new);
 
        return ret;
@@ -517,3 +511,115 @@ int __init ftrace_dyn_arch_init(void *data)
 
        return 0;
 }
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+extern void ftrace_graph_call(void);
+extern void ftrace_graph_stub(void);
+
+int ftrace_enable_ftrace_graph_caller(void)
+{
+       unsigned long ip = (unsigned long)(&ftrace_graph_call);
+       unsigned long addr = (unsigned long)(&ftrace_graph_caller);
+       unsigned long stub = (unsigned long)(&ftrace_graph_stub);
+       unsigned int old, new;
+
+       old = ftrace_call_replace(ip, stub, 0);
+       new = ftrace_call_replace(ip, addr, 0);
+
+       return ftrace_modify_code(ip, old, new);
+}
+
+int ftrace_disable_ftrace_graph_caller(void)
+{
+       unsigned long ip = (unsigned long)(&ftrace_graph_call);
+       unsigned long addr = (unsigned long)(&ftrace_graph_caller);
+       unsigned long stub = (unsigned long)(&ftrace_graph_stub);
+       unsigned int old, new;
+
+       old = ftrace_call_replace(ip, addr, 0);
+       new = ftrace_call_replace(ip, stub, 0);
+
+       return ftrace_modify_code(ip, old, new);
+}
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#ifdef CONFIG_PPC64
+extern void mod_return_to_handler(void);
+#endif
+
+/*
+ * Hook the return address and push it in the stack of return addrs
+ * in current thread info.
+ */
+void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
+{
+       unsigned long old;
+       unsigned long long calltime;
+       int faulted;
+       struct ftrace_graph_ent trace;
+       unsigned long return_hooker = (unsigned long)&return_to_handler;
+
+       if (unlikely(atomic_read(&current->tracing_graph_pause)))
+               return;
+
+#if CONFIG_PPC64
+       /* non core kernel code needs to save and restore the TOC */
+       if (REGION_ID(self_addr) != KERNEL_REGION_ID)
+               return_hooker = (unsigned long)&mod_return_to_handler;
+#endif
+
+       return_hooker = GET_ADDR(return_hooker);
+
+       /*
+        * Protect against fault, even if it shouldn't
+        * happen. This tool is too much intrusive to
+        * ignore such a protection.
+        */
+       asm volatile(
+               "1: " PPC_LL "%[old], 0(%[parent])\n"
+               "2: " PPC_STL "%[return_hooker], 0(%[parent])\n"
+               "   li %[faulted], 0\n"
+               "3:\n"
+
+               ".section .fixup, \"ax\"\n"
+               "4: li %[faulted], 1\n"
+               "   b 3b\n"
+               ".previous\n"
+
+               ".section __ex_table,\"a\"\n"
+                       PPC_LONG_ALIGN "\n"
+                       PPC_LONG "1b,4b\n"
+                       PPC_LONG "2b,4b\n"
+               ".previous"
+
+               : [old] "=r" (old), [faulted] "=r" (faulted)
+               : [parent] "r" (parent), [return_hooker] "r" (return_hooker)
+               : "memory"
+       );
+
+       if (unlikely(faulted)) {
+               ftrace_graph_stop();
+               WARN_ON(1);
+               return;
+       }
+
+       calltime = cpu_clock(raw_smp_processor_id());
+
+       if (ftrace_push_return_trace(old, calltime,
+                               self_addr, &trace.depth) == -EBUSY) {
+               *parent = old;
+               return;
+       }
+
+       trace.func = self_addr;
+
+       /* Only trace if the calling function expects to */
+       if (!ftrace_graph_entry(&trace)) {
+               current->curr_ret_stack--;
+               *parent = old;
+       }
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
index d794a637e421ffaf59dad48cdbbe95e832f3952b..54e68c11ae15971b38ced3d570ebc973d45c250c 100644 (file)
@@ -108,18 +108,21 @@ __start:
  * because OF may have I/O devices mapped into that area
  * (particularly on CHRP).
  */
-#ifdef CONFIG_PPC_MULTIPLATFORM
        cmpwi   0,r5,0
        beq     1f
 
+#ifdef CONFIG_PPC_OF_BOOT_TRAMPOLINE
        /* find out where we are now */
        bcl     20,31,$+4
 0:     mflr    r8                      /* r8 = runtime addr here */
        addis   r8,r8,(_stext - 0b)@ha
        addi    r8,r8,(_stext - 0b)@l   /* current runtime base addr */
        bl      prom_init
+#endif /* CONFIG_PPC_OF_BOOT_TRAMPOLINE */
+
+       /* We never return. We also hit that trap if trying to boot
+        * from OF while CONFIG_PPC_OF_BOOT_TRAMPOLINE isn't selected */
        trap
-#endif
 
 /*
  * Check for BootX signature when supporting PowerMac and branch to
@@ -472,12 +475,11 @@ SystemCall:
        . = 0x1000
 InstructionTLBMiss:
 /*
- * r0: stored ctr
+ * r0: scratch
  * r1: linux style pte ( later becomes ppc hardware pte )
  * r2: ptr to linux-style pte
  * r3: scratch
  */
-       mfctr   r0
        /* Get PTE (linux-style) and check access */
        mfspr   r3,SPRN_IMISS
        lis     r1,PAGE_OFFSET@h                /* check if kernel address */
@@ -496,28 +498,27 @@ InstructionTLBMiss:
        rlwinm. r2,r2,0,0,19            /* extract address of pte page */
        beq-    InstructionAddressInvalid       /* return if no mapping */
        rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
-       lwz     r3,0(r2)                /* get linux-style pte */
-       andc.   r1,r1,r3                /* check access & ~permission */
+       lwz     r0,0(r2)                /* get linux-style pte */
+       andc.   r1,r1,r0                /* check access & ~permission */
        bne-    InstructionAddressInvalid /* return if access not permitted */
-       ori     r3,r3,_PAGE_ACCESSED    /* set _PAGE_ACCESSED in pte */
+       ori     r0,r0,_PAGE_ACCESSED    /* set _PAGE_ACCESSED in pte */
        /*
         * NOTE! We are assuming this is not an SMP system, otherwise
         * we would need to update the pte atomically with lwarx/stwcx.
         */
-       stw     r3,0(r2)                /* update PTE (accessed bit) */
+       stw     r0,0(r2)                /* update PTE (accessed bit) */
        /* Convert linux-style PTE to low word of PPC-style PTE */
-       rlwinm  r1,r3,32-10,31,31       /* _PAGE_RW -> PP lsb */
-       rlwinm  r2,r3,32-7,31,31        /* _PAGE_DIRTY -> PP lsb */
+       rlwinm  r1,r0,32-10,31,31       /* _PAGE_RW -> PP lsb */
+       rlwinm  r2,r0,32-7,31,31        /* _PAGE_DIRTY -> PP lsb */
        and     r1,r1,r2                /* writable if _RW and _DIRTY */
-       rlwimi  r3,r3,32-1,30,30        /* _PAGE_USER -> PP msb */
-       rlwimi  r3,r3,32-1,31,31        /* _PAGE_USER -> PP lsb */
+       rlwimi  r0,r0,32-1,30,30        /* _PAGE_USER -> PP msb */
+       rlwimi  r0,r0,32-1,31,31        /* _PAGE_USER -> PP lsb */
        ori     r1,r1,0xe04             /* clear out reserved bits */
-       andc    r1,r3,r1                /* PP = user? (rw&dirty? 2: 3): 0 */
+       andc    r1,r0,r1                /* PP = user? (rw&dirty? 2: 3): 0 */
 BEGIN_FTR_SECTION
        rlwinm  r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
 END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
        mtspr   SPRN_RPA,r1
-       mfspr   r3,SPRN_IMISS
        tlbli   r3
        mfspr   r3,SPRN_SRR1            /* Need to restore CR0 */
        mtcrf   0x80,r3
@@ -528,7 +529,6 @@ InstructionAddressInvalid:
 
        addis   r1,r1,0x2000
        mtspr   SPRN_DSISR,r1   /* (shouldn't be needed) */
-       mtctr   r0              /* Restore CTR */
        andi.   r2,r3,0xFFFF    /* Clear upper bits of SRR1 */
        or      r2,r2,r1
        mtspr   SPRN_SRR1,r2
@@ -549,12 +549,11 @@ InstructionAddressInvalid:
        . = 0x1100
 DataLoadTLBMiss:
 /*
- * r0: stored ctr
+ * r0: scratch
  * r1: linux style pte ( later becomes ppc hardware pte )
  * r2: ptr to linux-style pte
  * r3: scratch
  */
-       mfctr   r0
        /* Get PTE (linux-style) and check access */
        mfspr   r3,SPRN_DMISS
        lis     r1,PAGE_OFFSET@h                /* check if kernel address */
@@ -573,38 +572,48 @@ DataLoadTLBMiss:
        rlwinm. r2,r2,0,0,19            /* extract address of pte page */
        beq-    DataAddressInvalid      /* return if no mapping */
        rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
-       lwz     r3,0(r2)                /* get linux-style pte */
-       andc.   r1,r1,r3                /* check access & ~permission */
+       lwz     r0,0(r2)                /* get linux-style pte */
+       andc.   r1,r1,r0                /* check access & ~permission */
        bne-    DataAddressInvalid      /* return if access not permitted */
-       ori     r3,r3,_PAGE_ACCESSED    /* set _PAGE_ACCESSED in pte */
+       ori     r0,r0,_PAGE_ACCESSED    /* set _PAGE_ACCESSED in pte */
        /*
         * NOTE! We are assuming this is not an SMP system, otherwise
         * we would need to update the pte atomically with lwarx/stwcx.
         */
-       stw     r3,0(r2)                /* update PTE (accessed bit) */
+       stw     r0,0(r2)                /* update PTE (accessed bit) */
        /* Convert linux-style PTE to low word of PPC-style PTE */
-       rlwinm  r1,r3,32-10,31,31       /* _PAGE_RW -> PP lsb */
-       rlwinm  r2,r3,32-7,31,31        /* _PAGE_DIRTY -> PP lsb */
+       rlwinm  r1,r0,32-10,31,31       /* _PAGE_RW -> PP lsb */
+       rlwinm  r2,r0,32-7,31,31        /* _PAGE_DIRTY -> PP lsb */
        and     r1,r1,r2                /* writable if _RW and _DIRTY */
-       rlwimi  r3,r3,32-1,30,30        /* _PAGE_USER -> PP msb */
-       rlwimi  r3,r3,32-1,31,31        /* _PAGE_USER -> PP lsb */
+       rlwimi  r0,r0,32-1,30,30        /* _PAGE_USER -> PP msb */
+       rlwimi  r0,r0,32-1,31,31        /* _PAGE_USER -> PP lsb */
        ori     r1,r1,0xe04             /* clear out reserved bits */
-       andc    r1,r3,r1                /* PP = user? (rw&dirty? 2: 3): 0 */
+       andc    r1,r0,r1                /* PP = user? (rw&dirty? 2: 3): 0 */
 BEGIN_FTR_SECTION
        rlwinm  r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
 END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
        mtspr   SPRN_RPA,r1
-       mfspr   r3,SPRN_DMISS
+       mfspr   r2,SPRN_SRR1            /* Need to restore CR0 */
+       mtcrf   0x80,r2
+BEGIN_MMU_FTR_SECTION
+       li      r0,1
+       mfspr   r1,SPRN_SPRG4
+       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
+       mfspr   r2,SPRN_SRR1
+       rlwimi  r2,r0,31-14,14,14
+       mtspr   SPRN_SRR1,r2
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)
        tlbld   r3
-       mfspr   r3,SPRN_SRR1            /* Need to restore CR0 */
-       mtcrf   0x80,r3
        rfi
 DataAddressInvalid:
        mfspr   r3,SPRN_SRR1
        rlwinm  r1,r3,9,6,6     /* Get load/store bit */
        addis   r1,r1,0x2000
        mtspr   SPRN_DSISR,r1
-       mtctr   r0              /* Restore CTR */
        andi.   r2,r3,0xFFFF    /* Clear upper bits of SRR1 */
        mtspr   SPRN_SRR1,r2
        mfspr   r1,SPRN_DMISS   /* Get failing address */
@@ -624,12 +633,11 @@ DataAddressInvalid:
        . = 0x1200
 DataStoreTLBMiss:
 /*
- * r0: stored ctr
+ * r0: scratch
  * r1: linux style pte ( later becomes ppc hardware pte )
  * r2: ptr to linux-style pte
  * r3: scratch
  */
-       mfctr   r0
        /* Get PTE (linux-style) and check access */
        mfspr   r3,SPRN_DMISS
        lis     r1,PAGE_OFFSET@h                /* check if kernel address */
@@ -648,27 +656,38 @@ DataStoreTLBMiss:
        rlwinm. r2,r2,0,0,19            /* extract address of pte page */
        beq-    DataAddressInvalid      /* return if no mapping */
        rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
-       lwz     r3,0(r2)                /* get linux-style pte */
-       andc.   r1,r1,r3                /* check access & ~permission */
+       lwz     r0,0(r2)                /* get linux-style pte */
+       andc.   r1,r1,r0                /* check access & ~permission */
        bne-    DataAddressInvalid      /* return if access not permitted */
-       ori     r3,r3,_PAGE_ACCESSED|_PAGE_DIRTY
+       ori     r0,r0,_PAGE_ACCESSED|_PAGE_DIRTY
        /*
         * NOTE! We are assuming this is not an SMP system, otherwise
         * we would need to update the pte atomically with lwarx/stwcx.
         */
-       stw     r3,0(r2)                /* update PTE (accessed/dirty bits) */
+       stw     r0,0(r2)                /* update PTE (accessed/dirty bits) */
        /* Convert linux-style PTE to low word of PPC-style PTE */
-       rlwimi  r3,r3,32-1,30,30        /* _PAGE_USER -> PP msb */
+       rlwimi  r0,r0,32-1,30,30        /* _PAGE_USER -> PP msb */
        li      r1,0xe05                /* clear out reserved bits & PP lsb */
-       andc    r1,r3,r1                /* PP = user? 2: 0 */
+       andc    r1,r0,r1                /* PP = user? 2: 0 */
 BEGIN_FTR_SECTION
        rlwinm  r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
 END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
        mtspr   SPRN_RPA,r1
-       mfspr   r3,SPRN_DMISS
+       mfspr   r2,SPRN_SRR1            /* Need to restore CR0 */
+       mtcrf   0x80,r2
+BEGIN_MMU_FTR_SECTION
+       li      r0,1
+       mfspr   r1,SPRN_SPRG4
+       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
+       mfspr   r2,SPRN_SRR1
+       rlwimi  r2,r0,31-14,14,14
+       mtspr   SPRN_SRR1,r2
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)
        tlbld   r3
-       mfspr   r3,SPRN_SRR1            /* Need to restore CR0 */
-       mtcrf   0x80,r3
        rfi
 
 #ifndef CONFIG_ALTIVEC
index ebaedafc8e67403efe716703d6110825d589a77d..50ef505b8fb6d0c9bedf58b22978292391ee83fa 100644 (file)
@@ -1360,6 +1360,7 @@ _GLOBAL(__start_initialization_multiplatform)
        b       .__after_prom_start
 
 _INIT_STATIC(__boot_from_prom)
+#ifdef CONFIG_PPC_OF_BOOT_TRAMPOLINE
        /* Save parameters */
        mr      r31,r3
        mr      r30,r4
@@ -1390,7 +1391,10 @@ _INIT_STATIC(__boot_from_prom)
        /* Do all of the interaction with OF client interface */
        mr      r8,r26
        bl      .prom_init
-       /* We never return */
+#endif /* #CONFIG_PPC_OF_BOOT_TRAMPOLINE */
+
+       /* We never return. We also hit that trap if trying to boot
+        * from OF while CONFIG_PPC_OF_BOOT_TRAMPOLINE isn't selected */
        trap
 
 _STATIC(__after_prom_start)
index fce2df988504d6e8962b31656ceec6dceff7ac44..95f39f1e68d449036b0206735936513c60533cdc 100644 (file)
                mtspr   SPRN_IVOR##vector_number,r26;   \
                sync
 
+#if (THREAD_SHIFT < 15)
+#define ALLOC_STACK_FRAME(reg, val)                    \
+       addi reg,reg,val
+#else
+#define ALLOC_STACK_FRAME(reg, val)                    \
+       addis   reg,reg,val@ha;                         \
+       addi    reg,reg,val@l
+#endif
+
 #define NORMAL_EXCEPTION_PROLOG                                                     \
        mtspr   SPRN_SPRG0,r10;         /* save two registers to work with */\
        mtspr   SPRN_SPRG1,r11;                                              \
@@ -20,7 +29,7 @@
        beq     1f;                                                          \
        mfspr   r1,SPRN_SPRG3;          /* if from user, start at top of   */\
        lwz     r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack   */\
-       addi    r1,r1,THREAD_SIZE;                                           \
+       ALLOC_STACK_FRAME(r1, THREAD_SIZE);                                  \
 1:     subi    r1,r1,INT_FRAME_SIZE;   /* Allocate an exception frame     */\
        mr      r11,r1;                                                      \
        stw     r10,_CCR(r11);          /* save various registers          */\
 
 /* only on e500mc/e200 */
 #define DEBUG_STACK_BASE       dbgirq_ctx
-#ifdef CONFIG_PPC_E500MC
-#define DEBUG_SPRG             SPRN_SPRG9
-#else
+#ifdef CONFIG_E200
 #define DEBUG_SPRG             SPRN_SPRG6W
+#else
+#define DEBUG_SPRG             SPRN_SPRG9
 #endif
 
 #define EXC_LVL_FRAME_OVERHEAD (THREAD_SIZE - INT_FRAME_SIZE - EXC_LVL_SIZE)
@@ -279,7 +288,7 @@ label:
        lwz     r11,GPR11(r8);                                                \
        mfspr   r8,DEBUG_SPRG;                                                \
                                                                              \
-       RFDI;                                                                 \
+       PPC_RFDI;                                                                     \
        b       .;                                                            \
                                                                              \
        /* continue normal handling for a debug exception... */               \
index 36ffb3504a4fc23ce356de9b8b97c65b1abb169e..4c22620d009bf91a5abcd430fe72943771748f05 100644 (file)
@@ -103,10 +103,15 @@ invstr:   mflr    r6                              /* Make it accessible */
        or      r7,r7,r4
        mtspr   SPRN_MAS6,r7
        tlbsx   0,r6                            /* search MSR[IS], SPID=PID0 */
-#ifndef CONFIG_E200
        mfspr   r7,SPRN_MAS1
        andis.  r7,r7,MAS1_VALID@h
        bne     match_TLB
+
+       mfspr   r7,SPRN_MMUCFG
+       rlwinm  r7,r7,21,28,31                  /* extract MMUCFG[NPIDS] */
+       cmpwi   r7,3
+       bne     match_TLB                       /* skip if NPIDS != 3 */
+
        mfspr   r7,SPRN_PID1
        slwi    r7,r7,16
        or      r7,r7,r4
@@ -120,7 +125,7 @@ invstr:     mflr    r6                              /* Make it accessible */
        or      r7,r7,r4
        mtspr   SPRN_MAS6,r7
        tlbsx   0,r6                            /* Fall through, we had to match */
-#endif
+
 match_TLB:
        mfspr   r7,SPRN_MAS0
        rlwinm  r3,r7,16,20,31                  /* Extract MAS0(Entry) */
@@ -168,7 +173,7 @@ skpinv:     addi    r6,r6,1                         /* Increment */
 
        /* grab and fixup the RPN */
        mfspr   r6,SPRN_MAS1    /* extract MAS1[SIZE] */
-       rlwinm  r6,r6,25,27,30
+       rlwinm  r6,r6,25,27,31
        li      r8,-1
        addi    r6,r6,10
        slw     r6,r8,r6        /* convert to mask */
@@ -194,7 +199,7 @@ skpinv:     addi    r6,r6,1                         /* Increment */
        xori    r6,r4,1         /* Setup TMP mapping in the other Address space */
        slwi    r6,r6,12
        oris    r6,r6,(MAS1_VALID|MAS1_IPROT)@h
-       ori     r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_4K))@l
+       ori     r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_4K))@l
        mtspr   SPRN_MAS1,r6
        mfspr   r6,SPRN_MAS2
        li      r7,0            /* temp EPN = 0 */
@@ -215,14 +220,19 @@ skpinv:   addi    r6,r6,1                         /* Increment */
 
 /* 4. Clear out PIDs & Search info */
        li      r6,0
+       mtspr   SPRN_MAS6,r6
        mtspr   SPRN_PID0,r6
-#ifndef CONFIG_E200
+
+       mfspr   r7,SPRN_MMUCFG
+       rlwinm  r7,r7,21,28,31                  /* extract MMUCFG[NPIDS] */
+       cmpwi   r7,3
+       bne     2f                              /* skip if NPIDS != 3 */
+
        mtspr   SPRN_PID1,r6
        mtspr   SPRN_PID2,r6
-#endif
-       mtspr   SPRN_MAS6,r6
 
 /* 5. Invalidate mapping we started in */
+2:
        lis     r7,0x1000       /* Set MAS0(TLBSEL) = 1 */
        rlwimi  r7,r3,16,4,15   /* Setup MAS0 = TLBSEL | ESEL(r3) */
        mtspr   SPRN_MAS0,r7
@@ -247,10 +257,10 @@ skpinv:   addi    r6,r6,1                         /* Increment */
        lis     r6,0x1000               /* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */
        mtspr   SPRN_MAS0,r6
        lis     r6,(MAS1_VALID|MAS1_IPROT)@h
-       ori     r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_64M))@l
+       ori     r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_64M))@l
        mtspr   SPRN_MAS1,r6
-       lis     r6,MAS2_VAL(PAGE_OFFSET, BOOKE_PAGESZ_64M, M_IF_SMP)@h
-       ori     r6,r6,MAS2_VAL(PAGE_OFFSET, BOOKE_PAGESZ_64M, M_IF_SMP)@l
+       lis     r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@h
+       ori     r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@l
        mtspr   SPRN_MAS2,r6
        mtspr   SPRN_MAS3,r8
        tlbwe
@@ -298,26 +308,14 @@ skpinv:   addi    r6,r6,1                         /* Increment */
        SET_IVOR(12, WatchdogTimer);
        SET_IVOR(13, DataTLBError);
        SET_IVOR(14, InstructionTLBError);
-       SET_IVOR(15, DebugDebug);
-#if defined(CONFIG_E500) && !defined(CONFIG_PPC_E500MC)
        SET_IVOR(15, DebugCrit);
-#endif
-       SET_IVOR(32, SPEUnavailable);
-       SET_IVOR(33, SPEFloatingPointData);
-       SET_IVOR(34, SPEFloatingPointRound);
-#ifndef CONFIG_E200
-       SET_IVOR(35, PerformanceMonitor);
-#endif
-#ifdef CONFIG_PPC_E500MC
-       SET_IVOR(36, Doorbell);
-#endif
 
        /* Establish the interrupt vector base */
        lis     r4,interrupt_base@h     /* IVPR only uses the high 16-bits */
        mtspr   SPRN_IVPR,r4
 
        /* Setup the defaults for TLB entries */
-       li      r2,(MAS4_TSIZED(BOOKE_PAGESZ_4K))@l
+       li      r2,(MAS4_TSIZED(BOOK3E_PAGESZ_4K))@l
 #ifdef CONFIG_E200
        oris    r2,r2,MAS4_TLBSELD(1)@h
 #endif
@@ -329,12 +327,6 @@ skpinv:    addi    r6,r6,1                         /* Increment */
        oris    r2,r2,HID0_DOZE@h
        mtspr   SPRN_HID0, r2
 #endif
-#ifdef CONFIG_E200
-       /* enable dedicated debug exception handling resources (Debug APU) */
-       mfspr   r2,SPRN_HID0
-       ori     r2,r2,HID0_DAPUEN@l
-       mtspr   SPRN_HID0,r2
-#endif
 
 #if !defined(CONFIG_BDI_SWITCH)
        /*
@@ -706,15 +698,13 @@ interrupt_base:
        /* Performance Monitor */
        EXCEPTION(0x2060, PerformanceMonitor, performance_monitor_exception, EXC_XFER_STD)
 
-#ifdef CONFIG_PPC_E500MC
-       EXCEPTION(0x2070, Doorbell, unknown_exception, EXC_XFER_STD)
-#endif
+       EXCEPTION(0x2070, Doorbell, doorbell_exception, EXC_XFER_STD)
+
+       CRITICAL_EXCEPTION(0x2080, CriticalDoorbell, unknown_exception)
 
        /* Debug Interrupt */
        DEBUG_DEBUG_EXCEPTION
-#if defined(CONFIG_E500) && !defined(CONFIG_PPC_E500MC)
        DEBUG_CRIT_EXCEPTION
-#endif
 
 /*
  * Local functions
@@ -897,6 +887,47 @@ KernelSPE:
  * Global functions
  */
 
+/* Adjust or setup IVORs for e200 */
+_GLOBAL(__setup_e200_ivors)
+       li      r3,DebugDebug@l
+       mtspr   SPRN_IVOR15,r3
+       li      r3,SPEUnavailable@l
+       mtspr   SPRN_IVOR32,r3
+       li      r3,SPEFloatingPointData@l
+       mtspr   SPRN_IVOR33,r3
+       li      r3,SPEFloatingPointRound@l
+       mtspr   SPRN_IVOR34,r3
+       sync
+       blr
+
+/* Adjust or setup IVORs for e500v1/v2 */
+_GLOBAL(__setup_e500_ivors)
+       li      r3,DebugCrit@l
+       mtspr   SPRN_IVOR15,r3
+       li      r3,SPEUnavailable@l
+       mtspr   SPRN_IVOR32,r3
+       li      r3,SPEFloatingPointData@l
+       mtspr   SPRN_IVOR33,r3
+       li      r3,SPEFloatingPointRound@l
+       mtspr   SPRN_IVOR34,r3
+       li      r3,PerformanceMonitor@l
+       mtspr   SPRN_IVOR35,r3
+       sync
+       blr
+
+/* Adjust or setup IVORs for e500mc */
+_GLOBAL(__setup_e500mc_ivors)
+       li      r3,DebugDebug@l
+       mtspr   SPRN_IVOR15,r3
+       li      r3,PerformanceMonitor@l
+       mtspr   SPRN_IVOR35,r3
+       li      r3,Doorbell@l
+       mtspr   SPRN_IVOR36,r3
+       li      r3,CriticalDoorbell@l
+       mtspr   SPRN_IVOR37,r3
+       sync
+       blr
+
 /*
  * extern void loadcam_entry(unsigned int index)
  *
@@ -1089,7 +1120,7 @@ __secondary_start:
        mtspr   SPRN_SPRG3,r4
 
        /* Setup the defaults for TLB entries */
-       li      r4,(MAS4_TSIZED(BOOKE_PAGESZ_4K))@l
+       li      r4,(MAS4_TSIZED(BOOK3E_PAGESZ_4K))@l
        mtspr   SPRN_MAS4,r4
 
        /* Jump to start_secondary */
index 1b55ffdf002652d09376ce7e1a22d32c1101610f..5576147e57b63d5e7c54c359e31fbdf71b2ca5dd 100644 (file)
@@ -171,7 +171,7 @@ int show_interrupts(struct seq_file *p, void *v)
 {
        int i = *(loff_t *)v, j;
        struct irqaction *action;
-       irq_desc_t *desc;
+       struct irq_desc *desc;
        unsigned long flags;
 
        if (i == 0) {
@@ -1038,7 +1038,7 @@ arch_initcall(irq_late_init);
 static int virq_debug_show(struct seq_file *m, void *private)
 {
        unsigned long flags;
-       irq_desc_t *desc;
+       struct irq_desc *desc;
        const char *p;
        char none[] = "none";
        int i;
index 8992b031a7b6a6cc54433453b6b991d1610cb5d6..8fbb12508bf3a25b54401ef1907d3930bc30522e 100644 (file)
@@ -329,7 +329,7 @@ static unsigned long stub_for_addr(Elf64_Shdr *sechdrs,
    restore r2. */
 static int restore_r2(u32 *instruction, struct module *me)
 {
-       if (*instruction != PPC_NOP_INSTR) {
+       if (*instruction != PPC_INST_NOP) {
                printk("%s: Expect noop after relocate, got %08x\n",
                       me->name, *instruction);
                return 0;
index 3bb7d3dd28be9e20d6e013127426e8c9c96e4861..8bbc12d20f5c9a11346874bb336fac33c7dcc6bc 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/kernel.h>
 #include <linux/msi.h>
+#include <linux/pci.h>
 
 #include <asm/machdep.h>
 
@@ -19,6 +20,10 @@ int arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
                return -ENOSYS;
        }
 
+       /* PowerPC doesn't support multiple MSI yet */
+       if (type == PCI_CAP_ID_MSI && nvec > 1)
+               return 1;
+
        if (ppc_md.msi_check_device) {
                pr_debug("msi: Using platform check routine.\n");
                return ppc_md.msi_check_device(dev, nvec, type);
index 0f418127231155e8c0589ab7d0c990e2851e5c7e..9c69e7e145c5588f6aad7f361b3381f451291456 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/eeh.h>
 
 static DEFINE_SPINLOCK(hose_spinlock);
+LIST_HEAD(hose_list);
 
 /* XXX kill that some day ... */
 static int global_phb_number;          /* Global phb counter */
@@ -49,7 +50,7 @@ resource_size_t isa_mem_base;
 unsigned int ppc_pci_flags = 0;
 
 
-static struct dma_mapping_ops *pci_dma_ops;
+static struct dma_mapping_ops *pci_dma_ops = &dma_direct_ops;
 
 void set_pci_dma_ops(struct dma_mapping_ops *dma_ops)
 {
@@ -113,19 +114,24 @@ void pcibios_free_controller(struct pci_controller *phb)
                kfree(phb);
 }
 
+static resource_size_t pcibios_io_size(const struct pci_controller *hose)
+{
+#ifdef CONFIG_PPC64
+       return hose->pci_io_size;
+#else
+       return hose->io_resource.end - hose->io_resource.start + 1;
+#endif
+}
+
 int pcibios_vaddr_is_ioport(void __iomem *address)
 {
        int ret = 0;
        struct pci_controller *hose;
-       unsigned long size;
+       resource_size_t size;
 
        spin_lock(&hose_spinlock);
        list_for_each_entry(hose, &hose_list, list_node) {
-#ifdef CONFIG_PPC64
-               size = hose->pci_io_size;
-#else
-               size = hose->io_resource.end - hose->io_resource.start + 1;
-#endif
+               size = pcibios_io_size(hose);
                if (address >= hose->io_base_virt &&
                    address < (hose->io_base_virt + size)) {
                        ret = 1;
@@ -136,6 +142,29 @@ int pcibios_vaddr_is_ioport(void __iomem *address)
        return ret;
 }
 
+unsigned long pci_address_to_pio(phys_addr_t address)
+{
+       struct pci_controller *hose;
+       resource_size_t size;
+       unsigned long ret = ~0;
+
+       spin_lock(&hose_spinlock);
+       list_for_each_entry(hose, &hose_list, list_node) {
+               size = pcibios_io_size(hose);
+               if (address >= hose->io_base_phys &&
+                   address < (hose->io_base_phys + size)) {
+                       unsigned long base =
+                               (unsigned long)hose->io_base_virt - _IO_BASE;
+                       ret = base + (address - hose->io_base_phys);
+                       break;
+               }
+       }
+       spin_unlock(&hose_spinlock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pci_address_to_pio);
+
 /*
  * Return the domain number for this bus.
  */
@@ -1453,7 +1482,7 @@ void __init pcibios_resource_survey(void)
         * we proceed to assigning things that were left unassigned
         */
        if (!(ppc_pci_flags & PPC_PCI_PROBE_ONLY)) {
-               pr_debug("PCI: Assigning unassigned resouces...\n");
+               pr_debug("PCI: Assigning unassigned resources...\n");
                pci_assign_unassigned_resources();
        }
 
index 132cd80afa21575fe1ee52db1a4afb68083afe99..d473634e39e3cf63e10de5d3f8aef5075eafd9a8 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/prom.h>
 #include <asm/sections.h>
 #include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 #include <asm/machdep.h>
@@ -43,8 +44,6 @@ static u8* pci_to_OF_bus_map;
  */
 static int pci_assign_all_buses;
 
-LIST_HEAD(hose_list);
-
 static int pci_bus_count;
 
 /* This will remain NULL for now, until isa-bridge.c is made common
@@ -219,16 +218,23 @@ scan_OF_pci_childs(struct device_node *parent, pci_OF_scan_iterator filter, void
 static struct device_node *scan_OF_for_pci_dev(struct device_node *parent,
                                               unsigned int devfn)
 {
-       struct device_node *np;
+       struct device_node *np, *cnp;
        const u32 *reg;
        unsigned int psize;
 
        for_each_child_of_node(parent, np) {
                reg = of_get_property(np, "reg", &psize);
-               if (reg == NULL || psize < 4)
-                       continue;
-               if (((reg[0] >> 8) & 0xff) == devfn)
+                if (reg && psize >= 4 && ((reg[0] >> 8) & 0xff) == devfn)
                        return np;
+
+               /* Note: some OFs create a parent node "multifunc-device" as
+                * a fake root for all functions of a multi-function device,
+                * we go down them as well. */
+                if (!strcmp(np->name, "multifunc-device")) {
+                        cnp = scan_OF_for_pci_dev(np, devfn);
+                        if (cnp)
+                                return cnp;
+                }
        }
        return NULL;
 }
@@ -491,24 +497,6 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
        return result;
 }
 
-unsigned long pci_address_to_pio(phys_addr_t address)
-{
-       struct pci_controller *hose, *tmp;
-
-       list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
-               unsigned int size = hose->io_resource.end -
-                       hose->io_resource.start + 1;
-               if (address >= hose->io_base_phys &&
-                   address < (hose->io_base_phys + size)) {
-                       unsigned long base =
-                               (unsigned long)hose->io_base_virt - _IO_BASE;
-                       return base + (address - hose->io_base_phys);
-               }
-       }
-       return (unsigned int)-1;
-}
-EXPORT_SYMBOL(pci_address_to_pio);
-
 /*
  * Null PCI config access functions, for the case when we can't
  * find a hose.
index ea8eda8c87cf2900564864983a26be3ec679747f..be574fc0d92fd679bb2f25eb7809f65728a0b74f 100644 (file)
@@ -43,8 +43,6 @@ unsigned long pci_probe_only = 1;
 unsigned long pci_io_base = ISA_IO_BASE;
 EXPORT_SYMBOL(pci_io_base);
 
-LIST_HEAD(hose_list);
-
 static void fixup_broken_pcnet32(struct pci_dev* dev)
 {
        if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) {
@@ -524,23 +522,6 @@ int __devinit pcibios_map_io_space(struct pci_bus *bus)
 }
 EXPORT_SYMBOL_GPL(pcibios_map_io_space);
 
-unsigned long pci_address_to_pio(phys_addr_t address)
-{
-       struct pci_controller *hose, *tmp;
-
-       list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
-               if (address >= hose->io_base_phys &&
-                   address < (hose->io_base_phys + hose->pci_io_size)) {
-                       unsigned long base =
-                               (unsigned long)hose->io_base_virt - _IO_BASE;
-                       return base + (address - hose->io_base_phys);
-               }
-       }
-       return (unsigned int)-1;
-}
-EXPORT_SYMBOL_GPL(pci_address_to_pio);
-
-
 #define IOBASE_BRIDGE_NUMBER   0
 #define IOBASE_MEMORY          1
 #define IOBASE_IO              2
index fb7049c054c061765feae824d635da3477d1b624..7b44a33f03c230a07381f876f25da1fdb7871c6a 100644 (file)
 #include <linux/mqueue.h>
 #include <linux/hardirq.h>
 #include <linux/utsname.h>
+#include <linux/ftrace.h>
 #include <linux/kernel_stat.h>
+#include <linux/personality.h>
+#include <linux/random.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -595,7 +598,7 @@ void prepare_to_copy(struct task_struct *tsk)
 /*
  * Copy a thread..
  */
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(unsigned long clone_flags, unsigned long usp,
                unsigned long unused, struct task_struct *p,
                struct pt_regs *regs)
 {
@@ -1008,6 +1011,14 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)
        unsigned long sp, ip, lr, newsp;
        int count = 0;
        int firstframe = 1;
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       int curr_frame = current->curr_ret_stack;
+       extern void return_to_handler(void);
+       unsigned long addr = (unsigned long)return_to_handler;
+#ifdef CONFIG_PPC64
+       addr = *(unsigned long*)addr;
+#endif
+#endif
 
        sp = (unsigned long) stack;
        if (tsk == NULL)
@@ -1030,6 +1041,13 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)
                ip = stack[STACK_FRAME_LR_SAVE];
                if (!firstframe || ip != lr) {
                        printk("["REG"] ["REG"] %pS", sp, ip, (void *)ip);
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+                       if (ip == addr && curr_frame >= 0) {
+                               printk(" (%pS)",
+                                      (void *)current->ret_stack[curr_frame].ret);
+                               curr_frame--;
+                       }
+#endif
                        if (firstframe)
                                printk(" (unreliable)");
                        printk("\n");
@@ -1122,3 +1140,43 @@ void thread_info_cache_init(void)
 }
 
 #endif /* THREAD_SHIFT < PAGE_SHIFT */
+
+unsigned long arch_align_stack(unsigned long sp)
+{
+       if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+               sp -= get_random_int() & ~PAGE_MASK;
+       return sp & ~0xf;
+}
+
+static inline unsigned long brk_rnd(void)
+{
+        unsigned long rnd = 0;
+
+       /* 8MB for 32bit, 1GB for 64bit */
+       if (is_32bit_task())
+               rnd = (long)(get_random_int() % (1<<(23-PAGE_SHIFT)));
+       else
+               rnd = (long)(get_random_int() % (1<<(30-PAGE_SHIFT)));
+
+       return rnd << PAGE_SHIFT;
+}
+
+unsigned long arch_randomize_brk(struct mm_struct *mm)
+{
+       unsigned long ret = PAGE_ALIGN(mm->brk + brk_rnd());
+
+       if (ret < mm->brk)
+               return mm->brk;
+
+       return ret;
+}
+
+unsigned long randomize_et_dyn(unsigned long base)
+{
+       unsigned long ret = PAGE_ALIGN(base + brk_rnd());
+
+       if (ret < base)
+               return base;
+
+       return ret;
+}
index f00f83109ab309bbe38cca6a989155795413d4a7..5ec6a9e239337e6170cf6d0ededaf0c687b78282 100644 (file)
@@ -1075,11 +1075,6 @@ static void __init early_reserve_mem(void)
                DBG("reserving: %llx -> %llx\n", base, size);
                lmb_reserve(base, size);
        }
-
-#if 0
-       DBG("memory reserved, lmbs :\n");
-       lmb_dump_all();
-#endif
 }
 
 #ifdef CONFIG_PHYP_DUMP
@@ -1221,6 +1216,7 @@ void __init early_init_devtree(void *params)
        lmb_enforce_memory_limit(limit);
 
        lmb_analyze();
+       lmb_dump_all();
 
        DBG("Phys. mem: %lx\n", lmb_phys_mem_size());
 
index 7f1b33d5e30d9baf51ddba748f1b0a0573daf754..2e026c0407d4c2b69bed464cc28d3621a1d77f53 100644 (file)
@@ -2283,6 +2283,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
         */
        prom_init_stdout();
 
+       prom_printf("Preparing to boot %s", RELOC(linux_banner));
+
        /*
         * Get default machine type. At this point, we do not differentiate
         * between pSeries SMP and pSeries LPAR
index ea3a2ec03ffafe1a00a946895ee77db5c39b650d..1ac136b128f01fb700e86bcb609863376458336f 100644 (file)
@@ -20,7 +20,7 @@ WHITELIST="add_reloc_offset __bss_start __bss_stop copy_and_flush
 _end enter_prom memcpy memset reloc_offset __secondary_hold
 __secondary_hold_acknowledge __secondary_hold_spinloop __start
 strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224
-reloc_got2 kernstart_addr memstart_addr"
+reloc_got2 kernstart_addr memstart_addr linux_banner"
 
 NM="$1"
 OBJ="$2"
index fdfe14c4bdefc735640745625cb559fc4908a2fa..ee4c7609b649e29222209cc666b0f28532844b51 100644 (file)
@@ -46,6 +46,7 @@ EXPORT_SYMBOL(rtas);
 
 struct rtas_suspend_me_data {
        atomic_t working; /* number of cpus accessing this struct */
+       atomic_t done;
        int token; /* ibm,suspend-me */
        int error;
        struct completion *complete; /* wait on this until working == 0 */
@@ -689,7 +690,7 @@ static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE;
 #ifdef CONFIG_PPC_PSERIES
 static void rtas_percpu_suspend_me(void *info)
 {
-       long rc;
+       long rc = H_SUCCESS;
        unsigned long msr_save;
        int cpu;
        struct rtas_suspend_me_data *data =
@@ -701,7 +702,8 @@ static void rtas_percpu_suspend_me(void *info)
        msr_save = mfmsr();
        mtmsr(msr_save & ~(MSR_EE));
 
-       rc = plpar_hcall_norets(H_JOIN);
+       while (rc == H_SUCCESS && !atomic_read(&data->done))
+               rc = plpar_hcall_norets(H_JOIN);
 
        mtmsr(msr_save);
 
@@ -724,6 +726,9 @@ static void rtas_percpu_suspend_me(void *info)
                       smp_processor_id(), rc);
                data->error = rc;
        }
+
+       atomic_set(&data->done, 1);
+
        /* This cpu did the suspend or got an error; in either case,
         * we need to prod all other other cpus out of join state.
         * Extra prods are harmless.
@@ -766,6 +771,7 @@ static int rtas_ibm_suspend_me(struct rtas_args *args)
        }
 
        atomic_set(&data.working, 0);
+       atomic_set(&data.done, 0);
        data.token = rtas_token("ibm,suspend-me");
        data.error = 0;
        data.complete = &done;
index 149cb112cd1ad398357d33ae766e3add6c6cfc01..13011a96a9779b274e77447dd5b72dae4e56142a 100644 (file)
@@ -669,7 +669,6 @@ static void remove_flash_pde(struct proc_dir_entry *dp)
 {
        if (dp) {
                kfree(dp->data);
-               dp->owner = NULL;
                remove_proc_entry(dp->name, dp->parent);
        }
 }
index 705fc4bf3800af690b9d3edff25c915b52d811c6..9774f9fed96e52c5bde8cf8dce8e069ed8fc02a4 100644 (file)
@@ -35,6 +35,8 @@
 #include <linux/debugfs.h>
 #include <linux/percpu.h>
 #include <linux/lmb.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/processor.h>
@@ -669,3 +671,37 @@ static int powerpc_debugfs_init(void)
 }
 arch_initcall(powerpc_debugfs_init);
 #endif
+
+static int ppc_dflt_bus_notify(struct notifier_block *nb,
+                               unsigned long action, void *data)
+{
+       struct device *dev = data;
+
+       /* We are only intereted in device addition */
+       if (action != BUS_NOTIFY_ADD_DEVICE)
+               return 0;
+
+       set_dma_ops(dev, &dma_direct_ops);
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block ppc_dflt_plat_bus_notifier = {
+       .notifier_call = ppc_dflt_bus_notify,
+       .priority = INT_MAX,
+};
+
+static struct notifier_block ppc_dflt_of_bus_notifier = {
+       .notifier_call = ppc_dflt_bus_notify,
+       .priority = INT_MAX,
+};
+
+static int __init setup_bus_notifier(void)
+{
+       bus_register_notifier(&platform_bus_type, &ppc_dflt_plat_bus_notifier);
+       bus_register_notifier(&of_platform_bus_type, &ppc_dflt_of_bus_notifier);
+
+       return 0;
+}
+
+arch_initcall(setup_bus_notifier);
index 2d34196bba8cce3403ba0674297d063932f10c80..c410c606955da7770acacbaa1737a163db4c749d 100644 (file)
@@ -202,8 +202,6 @@ void __init early_setup(unsigned long dt_ptr)
 
        /* Fix up paca fields required for the boot cpu */
        get_paca()->cpu_start = 1;
-       get_paca()->stab_real = __pa((u64)&initial_stab);
-       get_paca()->stab_addr = (u64)&initial_stab;
 
        /* Probe the machine type */
        probe_machine();
@@ -212,20 +210,8 @@ void __init early_setup(unsigned long dt_ptr)
 
        DBG("Found, Initializing memory management...\n");
 
-       /*
-        * Initialize the MMU Hash table and create the linear mapping
-        * of memory. Has to be done before stab/slb initialization as
-        * this is currently where the page size encoding is obtained
-        */
-       htab_initialize();
-
-       /*
-        * Initialize stab / SLB management except on iSeries
-        */
-       if (cpu_has_feature(CPU_FTR_SLB))
-               slb_initialize();
-       else if (!firmware_has_feature(FW_FEATURE_ISERIES))
-               stab_initialize(get_paca()->stab_real);
+       /* Initialize the hash table or TLB handling */
+       early_init_mmu();
 
        DBG(" <- early_setup()\n");
 }
@@ -233,22 +219,11 @@ void __init early_setup(unsigned long dt_ptr)
 #ifdef CONFIG_SMP
 void early_setup_secondary(void)
 {
-       struct paca_struct *lpaca = get_paca();
-
        /* Mark interrupts enabled in PACA */
-       lpaca->soft_enabled = 0;
+       get_paca()->soft_enabled = 0;
 
-       /* Initialize hash table for that CPU */
-       htab_initialize_secondary();
-
-       /* Initialize STAB/SLB. We use a virtual address as it works
-        * in real mode on pSeries and we want a virutal address on
-        * iSeries anyway
-        */
-       if (cpu_has_feature(CPU_FTR_SLB))
-               slb_initialize();
-       else
-               stab_initialize(lpaca->stab_addr);
+       /* Initialize the hash table or TLB handling */
+       early_init_mmu_secondary();
 }
 
 #endif /* CONFIG_SMP */
@@ -578,13 +553,6 @@ void ppc64_boot_msg(unsigned int src, const char *msg)
        printk("[boot]%04x %s\n", src, msg);
 }
 
-/* Print a termination message (print only -- does not stop the kernel) */
-void ppc64_terminate_msg(unsigned int src, const char *msg)
-{
-       ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg);
-       printk("[terminate]%04x %s\n", src, msg);
-}
-
 void cpu_die(void)
 {
        if (ppc_md.cpu_die)
index a54405ebd7b0c35236cafedb3edee13bcfb67fb3..00b5078da9a3f10f2e34ba160c72db098f67c612 100644 (file)
@@ -26,12 +26,12 @@ int show_unhandled_signals = 0;
  * Allocate space for the signal frame
  */
 void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
-                          size_t frame_size)
+                          size_t frame_size, int is_32)
 {
         unsigned long oldsp, newsp;
 
         /* Default to using normal stack */
-        oldsp = regs->gpr[1];
+        oldsp = get_clean_sp(regs, is_32);
 
        /* Check for alt stack */
        if ((ka->sa.sa_flags & SA_ONSTACK) &&
index b427bf8e1d8fa440b714f730240ceca78ef7b850..6c0ddfc0603e80fa29c5a4b3408fa393d90e8f62 100644 (file)
@@ -15,7 +15,7 @@
 extern void do_signal(struct pt_regs *regs, unsigned long thread_info_flags);
 
 extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
-                                 size_t frame_size);
+                                 size_t frame_size, int is_32);
 extern void restore_sigmask(sigset_t *set);
 
 extern int handle_signal32(unsigned long sig, struct k_sigaction *ka,
@@ -39,22 +39,12 @@ extern unsigned long copy_vsx_from_user(struct task_struct *task,
 
 #ifdef CONFIG_PPC64
 
-static inline int is_32bit_task(void)
-{
-       return test_thread_flag(TIF_32BIT);
-}
-
 extern int handle_rt_signal64(int signr, struct k_sigaction *ka,
                              siginfo_t *info, sigset_t *set,
                              struct pt_regs *regs);
 
 #else /* CONFIG_PPC64 */
 
-static inline int is_32bit_task(void)
-{
-       return 1;
-}
-
 static inline int handle_rt_signal64(int signr, struct k_sigaction *ka,
                                     siginfo_t *info, sigset_t *set,
                                     struct pt_regs *regs)
index b13abf305996353735f0b1ec841fd8998da2e793..d670429a1608fe32a37a0b645df09aff7b904107 100644 (file)
@@ -836,7 +836,7 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
 
        /* Set up Signal Frame */
        /* Put a Real Time Context onto stack */
-       rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf));
+       rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf), 1);
        addr = rt_sf;
        if (unlikely(rt_sf == NULL))
                goto badframe;
@@ -1182,7 +1182,7 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
        unsigned long newsp = 0;
 
        /* Set up Signal Frame */
-       frame = get_sigframe(ka, regs, sizeof(*frame));
+       frame = get_sigframe(ka, regs, sizeof(*frame), 1);
        if (unlikely(frame == NULL))
                goto badframe;
        sc = (struct sigcontext __user *) &frame->sctx;
index e132891d3cea00e947750aa53ec97288a6f4c839..2fe6fc64b614ef9d1b935a472487eaf161967fd9 100644 (file)
@@ -402,7 +402,7 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info,
        unsigned long newsp = 0;
        long err = 0;
 
-       frame = get_sigframe(ka, regs, sizeof(*frame));
+       frame = get_sigframe(ka, regs, sizeof(*frame), 0);
        if (unlikely(frame == NULL))
                goto badframe;
 
index 4a2ee08af6a7f6c2448a45f71e51cbb973238ebd..f41aec85aa497b1dd90c6da64d9e8389c22c80e1 100644 (file)
@@ -134,44 +134,23 @@ void ppc_enable_pmcs(void)
 }
 EXPORT_SYMBOL(ppc_enable_pmcs);
 
-#if defined(CONFIG_6xx) || defined(CONFIG_PPC64)
-/* XXX convert to rusty's on_one_cpu */
-static unsigned long run_on_cpu(unsigned long cpu,
-                               unsigned long (*func)(unsigned long),
-                               unsigned long arg)
-{
-       cpumask_t old_affinity = current->cpus_allowed;
-       unsigned long ret;
-
-       /* should return -EINVAL to userspace */
-       if (set_cpus_allowed(current, cpumask_of_cpu(cpu)))
-               return 0;
-
-       ret = func(arg);
-
-       set_cpus_allowed(current, old_affinity);
-
-       return ret;
-}
-#endif
-
 #define SYSFS_PMCSETUP(NAME, ADDRESS) \
-static unsigned long read_##NAME(unsigned long junk) \
+static void read_##NAME(void *val) \
 { \
-       return mfspr(ADDRESS); \
+       *(unsigned long *)val = mfspr(ADDRESS); \
 } \
-static unsigned long write_##NAME(unsigned long val) \
+static void write_##NAME(void *val) \
 { \
        ppc_enable_pmcs(); \
-       mtspr(ADDRESS, val); \
-       return 0; \
+       mtspr(ADDRESS, *(unsigned long *)val);  \
 } \
 static ssize_t show_##NAME(struct sys_device *dev, \
                        struct sysdev_attribute *attr, \
                        char *buf) \
 { \
        struct cpu *cpu = container_of(dev, struct cpu, sysdev); \
-       unsigned long val = run_on_cpu(cpu->sysdev.id, read_##NAME, 0); \
+       unsigned long val; \
+       smp_call_function_single(cpu->sysdev.id, read_##NAME, &val, 1); \
        return sprintf(buf, "%lx\n", val); \
 } \
 static ssize_t __used \
@@ -183,7 +162,7 @@ static ssize_t __used \
        int ret = sscanf(buf, "%lx", &val); \
        if (ret != 1) \
                return -EINVAL; \
-       run_on_cpu(cpu->sysdev.id, write_##NAME, val); \
+       smp_call_function_single(cpu->sysdev.id, write_##NAME, &val, 1); \
        return count; \
 }
 
index 5457e9575685291a5a84dcad525cd89b009c9e1e..678fbff0d206e8fdc47db0c6450be09bd8bfffb1 100644 (file)
 #include <asm/processor.h>
 #endif
 #include <asm/kexec.h>
+#include <asm/ppc-opcode.h>
+#ifdef CONFIG_FSL_BOOKE
+#include <asm/dbell.h>
+#endif
 
 #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
 int (*__debugger)(struct pt_regs *regs);
@@ -637,29 +641,6 @@ static void parse_fpe(struct pt_regs *regs)
  * bits is faster and easier.
  *
  */
-#define INST_MFSPR_PVR         0x7c1f42a6
-#define INST_MFSPR_PVR_MASK    0xfc1fffff
-
-#define INST_DCBA              0x7c0005ec
-#define INST_DCBA_MASK         0xfc0007fe
-
-#define INST_MCRXR             0x7c000400
-#define INST_MCRXR_MASK                0xfc0007fe
-
-#define INST_STRING            0x7c00042a
-#define INST_STRING_MASK       0xfc0007fe
-#define INST_STRING_GEN_MASK   0xfc00067e
-#define INST_LSWI              0x7c0004aa
-#define INST_LSWX              0x7c00042a
-#define INST_STSWI             0x7c0005aa
-#define INST_STSWX             0x7c00052a
-
-#define INST_POPCNTB           0x7c0000f4
-#define INST_POPCNTB_MASK      0xfc0007fe
-
-#define INST_ISEL              0x7c00001e
-#define INST_ISEL_MASK         0xfc00003e
-
 static int emulate_string_inst(struct pt_regs *regs, u32 instword)
 {
        u8 rT = (instword >> 21) & 0x1f;
@@ -670,20 +651,20 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword)
        int pos = 0;
 
        /* Early out if we are an invalid form of lswx */
-       if ((instword & INST_STRING_MASK) == INST_LSWX)
+       if ((instword & PPC_INST_STRING_MASK) == PPC_INST_LSWX)
                if ((rT == rA) || (rT == NB_RB))
                        return -EINVAL;
 
        EA = (rA == 0) ? 0 : regs->gpr[rA];
 
-       switch (instword & INST_STRING_MASK) {
-               case INST_LSWX:
-               case INST_STSWX:
+       switch (instword & PPC_INST_STRING_MASK) {
+               case PPC_INST_LSWX:
+               case PPC_INST_STSWX:
                        EA += NB_RB;
                        num_bytes = regs->xer & 0x7f;
                        break;
-               case INST_LSWI:
-               case INST_STSWI:
+               case PPC_INST_LSWI:
+               case PPC_INST_STSWI:
                        num_bytes = (NB_RB == 0) ? 32 : NB_RB;
                        break;
                default:
@@ -695,9 +676,9 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword)
                u8 val;
                u32 shift = 8 * (3 - (pos & 0x3));
 
-               switch ((instword & INST_STRING_MASK)) {
-                       case INST_LSWX:
-                       case INST_LSWI:
+               switch ((instword & PPC_INST_STRING_MASK)) {
+                       case PPC_INST_LSWX:
+                       case PPC_INST_LSWI:
                                if (get_user(val, (u8 __user *)EA))
                                        return -EFAULT;
                                /* first time updating this reg,
@@ -706,8 +687,8 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword)
                                        regs->gpr[rT] = 0;
                                regs->gpr[rT] |= val << shift;
                                break;
-                       case INST_STSWI:
-                       case INST_STSWX:
+                       case PPC_INST_STSWI:
+                       case PPC_INST_STSWX:
                                val = regs->gpr[rT] >> shift;
                                if (put_user(val, (u8 __user *)EA))
                                        return -EFAULT;
@@ -775,18 +756,18 @@ static int emulate_instruction(struct pt_regs *regs)
                return -EFAULT;
 
        /* Emulate the mfspr rD, PVR. */
-       if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) {
+       if ((instword & PPC_INST_MFSPR_PVR_MASK) == PPC_INST_MFSPR_PVR) {
                rd = (instword >> 21) & 0x1f;
                regs->gpr[rd] = mfspr(SPRN_PVR);
                return 0;
        }
 
        /* Emulating the dcba insn is just a no-op.  */
-       if ((instword & INST_DCBA_MASK) == INST_DCBA)
+       if ((instword & PPC_INST_DCBA_MASK) == PPC_INST_DCBA)
                return 0;
 
        /* Emulate the mcrxr insn.  */
-       if ((instword & INST_MCRXR_MASK) == INST_MCRXR) {
+       if ((instword & PPC_INST_MCRXR_MASK) == PPC_INST_MCRXR) {
                int shift = (instword >> 21) & 0x1c;
                unsigned long msk = 0xf0000000UL >> shift;
 
@@ -796,16 +777,16 @@ static int emulate_instruction(struct pt_regs *regs)
        }
 
        /* Emulate load/store string insn. */
-       if ((instword & INST_STRING_GEN_MASK) == INST_STRING)
+       if ((instword & PPC_INST_STRING_GEN_MASK) == PPC_INST_STRING)
                return emulate_string_inst(regs, instword);
 
        /* Emulate the popcntb (Population Count Bytes) instruction. */
-       if ((instword & INST_POPCNTB_MASK) == INST_POPCNTB) {
+       if ((instword & PPC_INST_POPCNTB_MASK) == PPC_INST_POPCNTB) {
                return emulate_popcntb_inst(regs, instword);
        }
 
        /* Emulate isel (Integer Select) instruction */
-       if ((instword & INST_ISEL_MASK) == INST_ISEL) {
+       if ((instword & PPC_INST_ISEL_MASK) == PPC_INST_ISEL) {
                return emulate_isel(regs, instword);
        }
 
@@ -1144,6 +1125,24 @@ void vsx_assist_exception(struct pt_regs *regs)
 #endif /* CONFIG_VSX */
 
 #ifdef CONFIG_FSL_BOOKE
+
+void doorbell_exception(struct pt_regs *regs)
+{
+#ifdef CONFIG_SMP
+       int cpu = smp_processor_id();
+       int msg;
+
+       if (num_online_cpus() < 2)
+               return;
+
+       for (msg = 0; msg < 4; msg++)
+               if (test_and_clear_bit(msg, &dbell_smp_message[cpu]))
+                       smp_message_recv(msg);
+#else
+       printk(KERN_WARNING "Received doorbell on non-smp system\n");
+#endif
+}
+
 void CacheLockingException(struct pt_regs *regs, unsigned long address,
                           unsigned long error_code)
 {
index 7d6c9bb8c77fe4f6f220b81d82b282f70e26b83f..fc9af47e21285f7a10872849c88930d0218bcb44 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/udbg.h>
 
 void (*udbg_putc)(char c);
+void (*udbg_flush)(void);
 int (*udbg_getc)(void);
 int (*udbg_getc_poll)(void);
 
@@ -76,6 +77,9 @@ void udbg_puts(const char *s)
                        while ((c = *s++) != '\0')
                                udbg_putc(c);
                }
+
+               if (udbg_flush)
+                       udbg_flush();
        }
 #if 0
        else {
@@ -98,6 +102,9 @@ int udbg_write(const char *s, int n)
                }
        }
 
+       if (udbg_flush)
+               udbg_flush();
+
        return n - remain;
 }
 
index 7b7da8cfd5e862364feb391e4a3cc68447cfdec2..0362a891e54ee3736707ae0b4066237fd529fadd 100644 (file)
@@ -48,14 +48,21 @@ struct NS16550 {
 
 static struct NS16550 __iomem *udbg_comport;
 
-static void udbg_550_putc(char c)
+static void udbg_550_flush(void)
 {
        if (udbg_comport) {
                while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
                        /* wait for idle */;
-               out_8(&udbg_comport->thr, c);
+       }
+}
+
+static void udbg_550_putc(char c)
+{
+       if (udbg_comport) {
                if (c == '\n')
                        udbg_550_putc('\r');
+               udbg_550_flush();
+               out_8(&udbg_comport->thr, c);
        }
 }
 
@@ -108,6 +115,7 @@ void udbg_init_uart(void __iomem *comport, unsigned int speed,
                /* Clear & enable FIFOs */
                out_8(&udbg_comport->fcr ,0x07);
                udbg_putc = udbg_550_putc;
+               udbg_flush = udbg_550_flush;
                udbg_getc = udbg_550_getc;
                udbg_getc_poll = udbg_550_getc_poll;
        }
@@ -149,14 +157,21 @@ unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock)
 }
 
 #ifdef CONFIG_PPC_MAPLE
-void udbg_maple_real_putc(char c)
+void udbg_maple_real_flush(void)
 {
        if (udbg_comport) {
                while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
                        /* wait for idle */;
-               real_writeb(c, &udbg_comport->thr); eieio();
+       }
+}
+
+void udbg_maple_real_putc(char c)
+{
+       if (udbg_comport) {
                if (c == '\n')
                        udbg_maple_real_putc('\r');
+               udbg_maple_real_flush();
+               real_writeb(c, &udbg_comport->thr); eieio();
        }
 }
 
@@ -165,20 +180,28 @@ void __init udbg_init_maple_realmode(void)
        udbg_comport = (struct NS16550 __iomem *)0xf40003f8;
 
        udbg_putc = udbg_maple_real_putc;
+       udbg_flush = udbg_maple_real_flush;
        udbg_getc = NULL;
        udbg_getc_poll = NULL;
 }
 #endif /* CONFIG_PPC_MAPLE */
 
 #ifdef CONFIG_PPC_PASEMI
-void udbg_pas_real_putc(char c)
+void udbg_pas_real_flush(void)
 {
        if (udbg_comport) {
                while ((real_205_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
                        /* wait for idle */;
-               real_205_writeb(c, &udbg_comport->thr); eieio();
+       }
+}
+
+void udbg_pas_real_putc(char c)
+{
+       if (udbg_comport) {
                if (c == '\n')
                        udbg_pas_real_putc('\r');
+               udbg_pas_real_flush();
+               real_205_writeb(c, &udbg_comport->thr); eieio();
        }
 }
 
@@ -187,6 +210,7 @@ void udbg_init_pas_realmode(void)
        udbg_comport = (struct NS16550 __iomem *)0xfcff03f8UL;
 
        udbg_putc = udbg_pas_real_putc;
+       udbg_flush = udbg_pas_real_flush;
        udbg_getc = NULL;
        udbg_getc_poll = NULL;
 }
@@ -195,14 +219,21 @@ void udbg_init_pas_realmode(void)
 #ifdef CONFIG_PPC_EARLY_DEBUG_44x
 #include <platforms/44x/44x.h>
 
-static void udbg_44x_as1_putc(char c)
+static int udbg_44x_as1_flush(void)
 {
        if (udbg_comport) {
                while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
                        /* wait for idle */;
-               as1_writeb(c, &udbg_comport->thr); eieio();
+       }
+}
+
+static void udbg_44x_as1_putc(char c)
+{
+       if (udbg_comport) {
                if (c == '\n')
                        udbg_44x_as1_putc('\r');
+               udbg_44x_as1_flush();
+               as1_writeb(c, &udbg_comport->thr); eieio();
        }
 }
 
@@ -222,19 +253,27 @@ void __init udbg_init_44x_as1(void)
                (struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR;
 
        udbg_putc = udbg_44x_as1_putc;
+       udbg_flush = udbg_44x_as1_flush;
        udbg_getc = udbg_44x_as1_getc;
 }
 #endif /* CONFIG_PPC_EARLY_DEBUG_44x */
 
 #ifdef CONFIG_PPC_EARLY_DEBUG_40x
-static void udbg_40x_real_putc(char c)
+static void udbg_40x_real_flush(void)
 {
        if (udbg_comport) {
                while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
                        /* wait for idle */;
-               real_writeb(c, &udbg_comport->thr); eieio();
+       }
+}
+
+static void udbg_40x_real_putc(char c)
+{
+       if (udbg_comport) {
                if (c == '\n')
                        udbg_40x_real_putc('\r');
+               udbg_40x_real_flush();
+               real_writeb(c, &udbg_comport->thr); eieio();
        }
 }
 
@@ -254,6 +293,7 @@ void __init udbg_init_40x_realmode(void)
                CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR;
 
        udbg_putc = udbg_40x_real_putc;
+       udbg_flush = udbg_40x_real_flush;
        udbg_getc = udbg_40x_real_getc;
        udbg_getc_poll = NULL;
 }
index d3694498f3af517264d64a332f85733a5b1fbf73..819e59f6f7c7c31b680080bdcffe1171d4026058 100644 (file)
@@ -482,7 +482,7 @@ static void vio_cmo_balance(struct work_struct *work)
        cmo->excess.size = cmo->entitled - cmo->reserve.size;
        cmo->excess.free = cmo->excess.size - need;
 
-       cancel_delayed_work(container_of(work, struct delayed_work, work));
+       cancel_delayed_work(to_delayed_work(work));
        spin_unlock_irqrestore(&vio_cmo.lock, flags);
 }
 
index 67f07f453385f5ef99357052c6780537a945b495..b9ef1644a7228d1113494fb270dc369d20299600 100644 (file)
@@ -58,6 +58,7 @@ SECTIONS
                SCHED_TEXT
                LOCK_TEXT
                KPROBES_TEXT
+               IRQENTRY_TEXT
 
 #ifdef CONFIG_PPC32
                *(.got1)
index b7dc4c19f58211641d2bb1db44dea62315a3d641..005a28d380af9c94528437d7f6c0940c08085744 100644 (file)
 #include <linux/types.h>
 #include <linux/highmem.h>
 #include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
 
 #include <asm/tlbflush.h>
 
-/*
- * This address range defaults to a value that is safe for all
- * platforms which currently set CONFIG_NOT_COHERENT_CACHE. It
- * can be further configured for specific applications under
- * the "Advanced Setup" menu. -Matt
- */
-#define CONSISTENT_BASE        (CONFIG_CONSISTENT_START)
-#define CONSISTENT_END (CONFIG_CONSISTENT_START + CONFIG_CONSISTENT_SIZE)
-#define CONSISTENT_OFFSET(x)   (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT)
-
-/*
- * This is the page table (2MB) covering uncached, DMA consistent allocations
- */
-static pte_t *consistent_pte;
-static DEFINE_SPINLOCK(consistent_lock);
-
-/*
- * VM region handling support.
- *
- * This should become something generic, handling VM region allocations for
- * vmalloc and similar (ioremap, module space, etc).
- *
- * I envisage vmalloc()'s supporting vm_struct becoming:
- *
- *  struct vm_struct {
- *    struct vm_region region;
- *    unsigned long    flags;
- *    struct page      **pages;
- *    unsigned int     nr_pages;
- *    unsigned long    phys_addr;
- *  };
- *
- * get_vm_area() would then call vm_region_alloc with an appropriate
- * struct vm_region head (eg):
- *
- *  struct vm_region vmalloc_head = {
- *     .vm_list        = LIST_HEAD_INIT(vmalloc_head.vm_list),
- *     .vm_start       = VMALLOC_START,
- *     .vm_end         = VMALLOC_END,
- *  };
- *
- * However, vmalloc_head.vm_start is variable (typically, it is dependent on
- * the amount of RAM found at boot time.)  I would imagine that get_vm_area()
- * would have to initialise this each time prior to calling vm_region_alloc().
- */
-struct ppc_vm_region {
-       struct list_head        vm_list;
-       unsigned long           vm_start;
-       unsigned long           vm_end;
-};
-
-static struct ppc_vm_region consistent_head = {
-       .vm_list        = LIST_HEAD_INIT(consistent_head.vm_list),
-       .vm_start       = CONSISTENT_BASE,
-       .vm_end         = CONSISTENT_END,
-};
-
-static struct ppc_vm_region *
-ppc_vm_region_alloc(struct ppc_vm_region *head, size_t size, gfp_t gfp)
-{
-       unsigned long addr = head->vm_start, end = head->vm_end - size;
-       unsigned long flags;
-       struct ppc_vm_region *c, *new;
-
-       new = kmalloc(sizeof(struct ppc_vm_region), gfp);
-       if (!new)
-               goto out;
-
-       spin_lock_irqsave(&consistent_lock, flags);
-
-       list_for_each_entry(c, &head->vm_list, vm_list) {
-               if ((addr + size) < addr)
-                       goto nospc;
-               if ((addr + size) <= c->vm_start)
-                       goto found;
-               addr = c->vm_end;
-               if (addr > end)
-                       goto nospc;
-       }
-
- found:
-       /*
-        * Insert this entry _before_ the one we found.
-        */
-       list_add_tail(&new->vm_list, &c->vm_list);
-       new->vm_start = addr;
-       new->vm_end = addr + size;
-
-       spin_unlock_irqrestore(&consistent_lock, flags);
-       return new;
-
- nospc:
-       spin_unlock_irqrestore(&consistent_lock, flags);
-       kfree(new);
- out:
-       return NULL;
-}
-
-static struct ppc_vm_region *ppc_vm_region_find(struct ppc_vm_region *head, unsigned long addr)
-{
-       struct ppc_vm_region *c;
-
-       list_for_each_entry(c, &head->vm_list, vm_list) {
-               if (c->vm_start == addr)
-                       goto out;
-       }
-       c = NULL;
- out:
-       return c;
-}
-
 /*
  * Allocate DMA-coherent memory space and return both the kernel remapped
  * virtual and bus address for that space.
@@ -151,21 +41,21 @@ void *
 __dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp)
 {
        struct page *page;
-       struct ppc_vm_region *c;
        unsigned long order;
+       int i;
+       unsigned int nr_pages = PAGE_ALIGN(size)>>PAGE_SHIFT;
+       unsigned int array_size = nr_pages * sizeof(struct page *);
+       struct page **pages;
+       struct page *end;
        u64 mask = 0x00ffffff, limit; /* ISA default */
+       struct vm_struct *area;
 
-       if (!consistent_pte) {
-               printk(KERN_ERR "%s: not initialised\n", __func__);
-               dump_stack();
-               return NULL;
-       }
-
+       BUG_ON(!mem_init_done);
        size = PAGE_ALIGN(size);
        limit = (mask + 1) & ~mask;
-       if ((limit && size >= limit) || size >= (CONSISTENT_END - CONSISTENT_BASE)) {
-               printk(KERN_WARNING "coherent allocation too big (requested %#x mask %#Lx)\n",
-                      size, mask);
+       if (limit && size >= limit) {
+               printk(KERN_WARNING "coherent allocation too big (requested "
+                               "%#x mask %#Lx)\n", size, mask);
                return NULL;
        }
 
@@ -178,6 +68,8 @@ __dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp)
        if (!page)
                goto no_page;
 
+       end = page + (1 << order);
+
        /*
         * Invalidate any data that might be lurking in the
         * kernel direct-mapped region for device DMA.
@@ -188,48 +80,59 @@ __dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp)
                flush_dcache_range(kaddr, kaddr + size);
        }
 
+       split_page(page, order);
+
        /*
-        * Allocate a virtual address in the consistent mapping region.
+        * Set the "dma handle"
         */
-       c = ppc_vm_region_alloc(&consistent_head, size,
-                           gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
-       if (c) {
-               unsigned long vaddr = c->vm_start;
-               pte_t *pte = consistent_pte + CONSISTENT_OFFSET(vaddr);
-               struct page *end = page + (1 << order);
-
-               split_page(page, order);
-
-               /*
-                * Set the "dma handle"
-                */
-               *handle = page_to_phys(page);
+       *handle = page_to_phys(page);
+
+       area = get_vm_area_caller(size, VM_IOREMAP,
+                       __builtin_return_address(1));
+       if (!area)
+               goto out_free_pages;
+
+       if (array_size > PAGE_SIZE) {
+               pages = vmalloc(array_size);
+               area->flags |= VM_VPAGES;
+       } else {
+               pages = kmalloc(array_size, GFP_KERNEL);
+       }
+       if (!pages)
+               goto out_free_area;
 
-               do {
-                       BUG_ON(!pte_none(*pte));
+       area->pages = pages;
+       area->nr_pages = nr_pages;
 
-                       SetPageReserved(page);
-                       set_pte_at(&init_mm, vaddr,
-                                  pte, mk_pte(page, pgprot_noncached(PAGE_KERNEL)));
-                       page++;
-                       pte++;
-                       vaddr += PAGE_SIZE;
-               } while (size -= PAGE_SIZE);
+       for (i = 0; i < nr_pages; i++)
+               pages[i] = page + i;
 
-               /*
-                * Free the otherwise unused pages.
-                */
-               while (page < end) {
-                       __free_page(page);
-                       page++;
-               }
+       if (map_vm_area(area, pgprot_noncached(PAGE_KERNEL), &pages))
+               goto out_unmap;
 
-               return (void *)c->vm_start;
+       /*
+        * Free the otherwise unused pages.
+        */
+       page += nr_pages;
+       while (page < end) {
+               __free_page(page);
+               page++;
        }
 
+       return area->addr;
+out_unmap:
+       vunmap(area->addr);
+       if (array_size > PAGE_SIZE)
+               vfree(pages);
+       else
+               kfree(pages);
+       goto out_free_pages;
+out_free_area:
+       free_vm_area(area);
+out_free_pages:
        if (page)
                __free_pages(page, order);
- no_page:
+no_page:
        return NULL;
 }
 EXPORT_SYMBOL(__dma_alloc_coherent);
@@ -239,103 +142,11 @@ EXPORT_SYMBOL(__dma_alloc_coherent);
  */
 void __dma_free_coherent(size_t size, void *vaddr)
 {
-       struct ppc_vm_region *c;
-       unsigned long flags, addr;
-       pte_t *ptep;
-
-       size = PAGE_ALIGN(size);
-
-       spin_lock_irqsave(&consistent_lock, flags);
-
-       c = ppc_vm_region_find(&consistent_head, (unsigned long)vaddr);
-       if (!c)
-               goto no_area;
-
-       if ((c->vm_end - c->vm_start) != size) {
-               printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
-                      __func__, c->vm_end - c->vm_start, size);
-               dump_stack();
-               size = c->vm_end - c->vm_start;
-       }
-
-       ptep = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
-       addr = c->vm_start;
-       do {
-               pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep);
-               unsigned long pfn;
-
-               ptep++;
-               addr += PAGE_SIZE;
+       vfree(vaddr);
 
-               if (!pte_none(pte) && pte_present(pte)) {
-                       pfn = pte_pfn(pte);
-
-                       if (pfn_valid(pfn)) {
-                               struct page *page = pfn_to_page(pfn);
-                               ClearPageReserved(page);
-
-                               __free_page(page);
-                               continue;
-                       }
-               }
-
-               printk(KERN_CRIT "%s: bad page in kernel page table\n",
-                      __func__);
-       } while (size -= PAGE_SIZE);
-
-       flush_tlb_kernel_range(c->vm_start, c->vm_end);
-
-       list_del(&c->vm_list);
-
-       spin_unlock_irqrestore(&consistent_lock, flags);
-
-       kfree(c);
-       return;
-
- no_area:
-       spin_unlock_irqrestore(&consistent_lock, flags);
-       printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
-              __func__, vaddr);
-       dump_stack();
 }
 EXPORT_SYMBOL(__dma_free_coherent);
 
-/*
- * Initialise the consistent memory allocation.
- */
-static int __init dma_alloc_init(void)
-{
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *pte;
-       int ret = 0;
-
-       do {
-               pgd = pgd_offset(&init_mm, CONSISTENT_BASE);
-               pud = pud_alloc(&init_mm, pgd, CONSISTENT_BASE);
-               pmd = pmd_alloc(&init_mm, pud, CONSISTENT_BASE);
-               if (!pmd) {
-                       printk(KERN_ERR "%s: no pmd tables\n", __func__);
-                       ret = -ENOMEM;
-                       break;
-               }
-
-               pte = pte_alloc_kernel(pmd, CONSISTENT_BASE);
-               if (!pte) {
-                       printk(KERN_ERR "%s: no pte tables\n", __func__);
-                       ret = -ENOMEM;
-                       break;
-               }
-
-               consistent_pte = pte;
-       } while (0);
-
-       return ret;
-}
-
-core_initcall(dma_alloc_init);
-
 /*
  * make an area consistent.
  */
index 8c5a03be31e07766d123460cf8b273ed6dab6d0b..7e8865bcd683a5291861f3d31e07d75d9e98277d 100644 (file)
@@ -85,7 +85,7 @@ static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
        }
 
        for (; dest < end; dest++)
-               patch_instruction(dest, PPC_NOP_INSTR);
+               patch_instruction(dest, PPC_INST_NOP);
 
        return 0;
 }
@@ -122,7 +122,7 @@ void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
 
        for (; start < end; start++) {
                dest = (void *)start + *start;
-               patch_instruction(dest, PPC_LWSYNC_INSTR);
+               patch_instruction(dest, PPC_INST_LWSYNC);
        }
 }
 
index f9e506a735ae2e0d833bb0d0197b7d323679a67c..0c16ab947f1f3f04990874562b604209012c60dc 100644 (file)
@@ -1,6 +1,4 @@
 
-obj-y                          := math.o fmr.o lfd.o stfd.o
-
 obj-$(CONFIG_MATH_EMULATION)   += fabs.o fadd.o fadds.o fcmpo.o fcmpu.o \
                                        fctiw.o fctiwz.o fdiv.o fdivs.o \
                                        fmadd.o fmadds.o fmsub.o fmsubs.o \
@@ -9,7 +7,8 @@ obj-$(CONFIG_MATH_EMULATION)    += fabs.o fadd.o fadds.o fcmpo.o fcmpu.o \
                                        fres.o frsp.o frsqrte.o fsel.o lfs.o \
                                        fsqrt.o fsqrts.o fsub.o fsubs.o \
                                        mcrfs.o mffs.o mtfsb0.o mtfsb1.o \
-                                       mtfsf.o mtfsfi.o stfiwx.o stfs.o
+                                       mtfsf.o mtfsfi.o stfiwx.o stfs.o \
+                                       math.o fmr.o lfd.o stfd.o
 
 obj-$(CONFIG_SPE)              += math_efp.o
 
index 953cc4a1cde56061bccdc347ff0e347930eb052b..17290bcedc5e6b0850cc961d0e99d4ca615adf4e 100644 (file)
@@ -6,7 +6,7 @@ ifeq ($(CONFIG_PPC64),y)
 EXTRA_CFLAGS   += -mno-minimal-toc
 endif
 
-obj-y                          := fault.o mem.o pgtable.o \
+obj-y                          := fault.o mem.o pgtable.o gup.o \
                                   init_$(CONFIG_WORD_SIZE).o \
                                   pgtable_$(CONFIG_WORD_SIZE).o
 obj-$(CONFIG_PPC_MMU_NOHASH)   += mmu_context_nohash.o tlb_nohash.o \
@@ -14,7 +14,7 @@ obj-$(CONFIG_PPC_MMU_NOHASH)  += mmu_context_nohash.o tlb_nohash.o \
 hash-$(CONFIG_PPC_NATIVE)      := hash_native_64.o
 obj-$(CONFIG_PPC64)            += hash_utils_64.o \
                                   slb_low.o slb.o stab.o \
-                                  gup.o mmap.o $(hash-y)
+                                  mmap_64.o $(hash-y)
 obj-$(CONFIG_PPC_STD_MMU_32)   += ppc_mmu_32.o
 obj-$(CONFIG_PPC_STD_MMU)      += hash_low_$(CONFIG_WORD_SIZE).o \
                                   tlb_hash$(CONFIG_WORD_SIZE).o \
index 91c7b8636b8a751ba160a7791df929be25d32543..76993941cac95a12f7c95972eb55f9e0b00fe769 100644 (file)
@@ -253,45 +253,33 @@ good_area:
 #endif /* CONFIG_8xx */
 
        if (is_exec) {
-#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
-               /* protection fault */
+#ifdef CONFIG_PPC_STD_MMU
+               /* Protection fault on exec go straight to failure on
+                * Hash based MMUs as they either don't support per-page
+                * execute permission, or if they do, it's handled already
+                * at the hash level. This test would probably have to
+                * be removed if we change the way this works to make hash
+                * processors use the same I/D cache coherency mechanism
+                * as embedded.
+                */
                if (error_code & DSISR_PROTFAULT)
                        goto bad_area;
+#endif /* CONFIG_PPC_STD_MMU */
+
                /*
                 * Allow execution from readable areas if the MMU does not
                 * provide separate controls over reading and executing.
+                *
+                * Note: That code used to not be enabled for 4xx/BookE.
+                * It is now as I/D cache coherency for these is done at
+                * set_pte_at() time and I see no reason why the test
+                * below wouldn't be valid on those processors. This -may-
+                * break programs compiled with a really old ABI though.
                 */
                if (!(vma->vm_flags & VM_EXEC) &&
                    (cpu_has_feature(CPU_FTR_NOEXECUTE) ||
                     !(vma->vm_flags & (VM_READ | VM_WRITE))))
                        goto bad_area;
-#else
-               pte_t *ptep;
-               pmd_t *pmdp;
-
-               /* Since 4xx/Book-E supports per-page execute permission,
-                * we lazily flush dcache to icache. */
-               ptep = NULL;
-               if (get_pteptr(mm, address, &ptep, &pmdp)) {
-                       spinlock_t *ptl = pte_lockptr(mm, pmdp);
-                       spin_lock(ptl);
-                       if (pte_present(*ptep)) {
-                               struct page *page = pte_page(*ptep);
-
-                               if (!test_bit(PG_arch_1, &page->flags)) {
-                                       flush_dcache_icache_page(page);
-                                       set_bit(PG_arch_1, &page->flags);
-                               }
-                               pte_update(ptep, 0, _PAGE_HWEXEC |
-                                          _PAGE_ACCESSED);
-                               local_flush_tlb_page(vma, address);
-                               pte_unmap_unlock(ptep, ptl);
-                               up_read(&mm->mmap_sem);
-                               return 0;
-                       }
-                       pte_unmap_unlock(ptep, ptl);
-               }
-#endif
        /* a write */
        } else if (is_write) {
                if (!(vma->vm_flags & VM_WRITE))
index ea6e41e39d9fc60ff38c2cb911952f9f013d3ef3..bb3d65998e6b514028d8c3af7b6c9c036047ba0d 100644 (file)
 
 extern void loadcam_entry(unsigned int index);
 unsigned int tlbcam_index;
-static unsigned long __cam0, __cam1, __cam2;
+static unsigned long cam[CONFIG_LOWMEM_CAM_NUM];
 
 #define NUM_TLBCAMS    (16)
 
+#if defined(CONFIG_LOWMEM_CAM_NUM_BOOL) && (CONFIG_LOWMEM_CAM_NUM >= NUM_TLBCAMS)
+#error "LOWMEM_CAM_NUM must be less than NUM_TLBCAMS"
+#endif
+
 struct tlbcam TLBCAM[NUM_TLBCAMS];
 
 struct tlbcamrange {
@@ -107,7 +111,7 @@ void settlbcam(int index, unsigned long virt, phys_addr_t phys,
        unsigned int tsize, lz;
 
        asm ("cntlzw %0,%1" : "=r" (lz) : "r" (size));
-       tsize = (21 - lz) / 2;
+       tsize = 21 - lz;
 
 #ifdef CONFIG_SMP
        if ((flags & _PAGE_NO_CACHE) == 0)
@@ -152,19 +156,19 @@ void invalidate_tlbcam_entry(int index)
        loadcam_entry(index);
 }
 
-void __init cam_mapin_ram(unsigned long cam0, unsigned long cam1,
-               unsigned long cam2)
+unsigned long __init mmu_mapin_ram(void)
 {
-       settlbcam(0, PAGE_OFFSET, memstart_addr, cam0, _PAGE_KERNEL, 0);
-       tlbcam_index++;
-       if (cam1) {
-               tlbcam_index++;
-               settlbcam(1, PAGE_OFFSET+cam0, memstart_addr+cam0, cam1, _PAGE_KERNEL, 0);
-       }
-       if (cam2) {
+       unsigned long virt = PAGE_OFFSET;
+       phys_addr_t phys = memstart_addr;
+
+       while (cam[tlbcam_index] && tlbcam_index < ARRAY_SIZE(cam)) {
+               settlbcam(tlbcam_index, virt, phys, cam[tlbcam_index], PAGE_KERNEL_X, 0);
+               virt += cam[tlbcam_index];
+               phys += cam[tlbcam_index];
                tlbcam_index++;
-               settlbcam(2, PAGE_OFFSET+cam0+cam1, memstart_addr+cam0+cam1, cam2, _PAGE_KERNEL, 0);
        }
+
+       return virt - PAGE_OFFSET;
 }
 
 /*
@@ -175,51 +179,46 @@ void __init MMU_init_hw(void)
        flush_instruction_cache();
 }
 
-unsigned long __init mmu_mapin_ram(void)
-{
-       cam_mapin_ram(__cam0, __cam1, __cam2);
-
-       return __cam0 + __cam1 + __cam2;
-}
-
-
 void __init
 adjust_total_lowmem(void)
 {
-       phys_addr_t max_lowmem_size = __max_low_memory;
-       phys_addr_t cam_max_size = 0x10000000;
        phys_addr_t ram;
+       unsigned int max_cam = (mfspr(SPRN_TLB1CFG) >> 16) & 0xff;
+       char buf[ARRAY_SIZE(cam) * 5 + 1], *p = buf;
+       int i;
+       unsigned long virt = PAGE_OFFSET & 0xffffffffUL;
+       unsigned long phys = memstart_addr & 0xffffffffUL;
 
-       /* adjust CAM size to max_lowmem_size */
-       if (max_lowmem_size < cam_max_size)
-               cam_max_size = max_lowmem_size;
+       /* Convert (4^max) kB to (2^max) bytes */
+       max_cam = max_cam * 2 + 10;
 
-       /* adjust lowmem size to max_lowmem_size */
-       ram = min(max_lowmem_size, total_lowmem);
+       /* adjust lowmem size to __max_low_memory */
+       ram = min((phys_addr_t)__max_low_memory, (phys_addr_t)total_lowmem);
 
        /* Calculate CAM values */
-       __cam0 = 1UL << 2 * (__ilog2(ram) / 2);
-       if (__cam0 > cam_max_size)
-               __cam0 = cam_max_size;
-       ram -= __cam0;
-       if (ram) {
-               __cam1 = 1UL << 2 * (__ilog2(ram) / 2);
-               if (__cam1 > cam_max_size)
-                       __cam1 = cam_max_size;
-               ram -= __cam1;
-       }
-       if (ram) {
-               __cam2 = 1UL << 2 * (__ilog2(ram) / 2);
-               if (__cam2 > cam_max_size)
-                       __cam2 = cam_max_size;
-               ram -= __cam2;
+       __max_low_memory = 0;
+       for (i = 0; ram && i < ARRAY_SIZE(cam); i++) {
+               unsigned int camsize = __ilog2(ram) & ~1U;
+               unsigned int align = __ffs(virt | phys) & ~1U;
+
+               if (camsize > align)
+                       camsize = align;
+               if (camsize > max_cam)
+                       camsize = max_cam;
+
+               cam[i] = 1UL << camsize;
+               ram -= cam[i];
+               __max_low_memory += cam[i];
+               virt += cam[i];
+               phys += cam[i];
+
+               p += sprintf(p, "%lu/", cam[i] >> 20);
        }
+       for (; i < ARRAY_SIZE(cam); i++)
+               p += sprintf(p, "0/");
+       p[-1] = '\0';
 
-       printk(KERN_INFO "Memory CAM mapping: CAM0=%ldMb, CAM1=%ldMb,"
-                       " CAM2=%ldMb residual: %ldMb\n",
-                       __cam0 >> 20, __cam1 >> 20, __cam2 >> 20,
-                       (long int)((total_lowmem - __cam0 - __cam1 - __cam2)
-                                  >> 20));
-       __max_low_memory = __cam0 + __cam1 + __cam2;
+       pr_info("Memory CAM mapping: %s Mb, residual: %dMb\n", buf,
+               (unsigned int)((total_lowmem - __max_low_memory) >> 20));
        __initial_memory_limit_addr = memstart_addr + __max_low_memory;
 }
index 28a114db3ba0d9a405fbd743b3b6b86359201795..bc400c78c97fb4030b28cbd6c7b4794bba70b199 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/rwsem.h>
 #include <asm/pgtable.h>
 
+#ifdef __HAVE_ARCH_PTE_SPECIAL
+
 /*
  * The performance critical leaf functions are made noinline otherwise gcc
  * inlines everything into a single function which results in too much
@@ -151,8 +153,11 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
        unsigned long addr, len, end;
        unsigned long next;
        pgd_t *pgdp;
-       int psize, nr = 0;
+       int nr = 0;
+#ifdef CONFIG_PPC64
        unsigned int shift;
+       int psize;
+#endif
 
        pr_debug("%s(%lx,%x,%s)\n", __func__, start, nr_pages, write ? "write" : "read");
 
@@ -205,8 +210,13 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
         */
        local_irq_disable();
 
+#ifdef CONFIG_PPC64
+       /* Those bits are related to hugetlbfs implementation and only exist
+        * on 64-bit for now
+        */
        psize = get_slice_psize(mm, addr);
        shift = mmu_psize_defs[psize].shift;
+#endif /* CONFIG_PPC64 */
 
 #ifdef CONFIG_HUGETLB_PAGE
        if (unlikely(mmu_huge_psizes[psize])) {
@@ -236,7 +246,9 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
                do {
                        pgd_t pgd = *pgdp;
 
+#ifdef CONFIG_PPC64
                        VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, addr)].shift);
+#endif
                        pr_debug("  %016lx: normal pgd %p\n", addr,
                                 (void *)pgd_val(pgd));
                        next = pgd_addr_end(addr, end);
@@ -279,3 +291,5 @@ slow_irqon:
                return ret;
        }
 }
+
+#endif /* __HAVE_ARCH_PTE_SPECIAL */
index 8d5b4758c13a5f47508c814ed9e279266bffead3..db556d25c3a78f82d4d5379b990386c415541b4f 100644 (file)
@@ -516,7 +516,7 @@ static int __init htab_dt_scan_pftsize(unsigned long node,
 
 static unsigned long __init htab_get_table_size(void)
 {
-       unsigned long mem_size, rnd_mem_size, pteg_count;
+       unsigned long mem_size, rnd_mem_size, pteg_count, psize;
 
        /* If hash size isn't already provided by the platform, we try to
         * retrieve it from the device-tree. If it's not there neither, we
@@ -534,7 +534,8 @@ static unsigned long __init htab_get_table_size(void)
                rnd_mem_size <<= 1;
 
        /* # pages / 2 */
-       pteg_count = max(rnd_mem_size >> (12 + 1), 1UL << 11);
+       psize = mmu_psize_defs[mmu_virtual_psize].shift;
+       pteg_count = max(rnd_mem_size >> (psize + 1), 1UL << 11);
 
        return pteg_count << 7;
 }
@@ -589,7 +590,7 @@ static void __init htab_finish_init(void)
        make_bl(htab_call_hpte_updatepp, ppc_md.hpte_updatepp);
 }
 
-void __init htab_initialize(void)
+static void __init htab_initialize(void)
 {
        unsigned long table;
        unsigned long pteg_count;
@@ -731,11 +732,43 @@ void __init htab_initialize(void)
 #undef KB
 #undef MB
 
-void htab_initialize_secondary(void)
+void __init early_init_mmu(void)
 {
+       /* Setup initial STAB address in the PACA */
+       get_paca()->stab_real = __pa((u64)&initial_stab);
+       get_paca()->stab_addr = (u64)&initial_stab;
+
+       /* Initialize the MMU Hash table and create the linear mapping
+        * of memory. Has to be done before stab/slb initialization as
+        * this is currently where the page size encoding is obtained
+        */
+       htab_initialize();
+
+       /* Initialize stab / SLB management except on iSeries
+        */
+       if (cpu_has_feature(CPU_FTR_SLB))
+               slb_initialize();
+       else if (!firmware_has_feature(FW_FEATURE_ISERIES))
+               stab_initialize(get_paca()->stab_real);
+}
+
+#ifdef CONFIG_SMP
+void __init early_init_mmu_secondary(void)
+{
+       /* Initialize hash table for that CPU */
        if (!firmware_has_feature(FW_FEATURE_LPAR))
                mtspr(SPRN_SDR1, _SDR1);
+
+       /* Initialize STAB/SLB. We use a virtual address as it works
+        * in real mode on pSeries and we want a virutal address on
+        * iSeries anyway
+        */
+       if (cpu_has_feature(CPU_FTR_SLB))
+               slb_initialize();
+       else
+               stab_initialize(get_paca()->stab_addr);
 }
+#endif /* CONFIG_SMP */
 
 /*
  * Called by asm hashtable.S for doing lazy icache flush
@@ -858,7 +891,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
        unsigned long vsid;
        struct mm_struct *mm;
        pte_t *ptep;
-       cpumask_t tmp;
+       const struct cpumask *tmp;
        int rc, user_region = 0, local = 0;
        int psize, ssize;
 
@@ -906,8 +939,8 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
                return 1;
 
        /* Check CPU locality */
-       tmp = cpumask_of_cpu(smp_processor_id());
-       if (user_region && cpus_equal(mm->cpu_vm_mask, tmp))
+       tmp = cpumask_of(smp_processor_id());
+       if (user_region && cpumask_equal(mm_cpumask(mm), tmp))
                local = 1;
 
 #ifdef CONFIG_HUGETLB_PAGE
@@ -1023,7 +1056,6 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
        unsigned long vsid;
        void *pgdir;
        pte_t *ptep;
-       cpumask_t mask;
        unsigned long flags;
        int local = 0;
        int ssize;
@@ -1066,8 +1098,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
        local_irq_save(flags);
 
        /* Is that local to this CPU ? */
-       mask = cpumask_of_cpu(smp_processor_id());
-       if (cpus_equal(mm->cpu_vm_mask, mask))
+       if (cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id())))
                local = 1;
 
        /* Hash it in */
index f00f09a77f12f3d628d0b0f51c1a56ebccbadb75..f668fa9ba804c150d3498c521429ea14f3639d07 100644 (file)
@@ -472,40 +472,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
 {
 #ifdef CONFIG_PPC_STD_MMU
        unsigned long access = 0, trap;
-#endif
-       unsigned long pfn = pte_pfn(pte);
-
-       /* handle i-cache coherency */
-       if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE) &&
-           !cpu_has_feature(CPU_FTR_NOEXECUTE) &&
-           pfn_valid(pfn)) {
-               struct page *page = pfn_to_page(pfn);
-#ifdef CONFIG_8xx
-               /* On 8xx, cache control instructions (particularly
-                * "dcbst" from flush_dcache_icache) fault as write
-                * operation if there is an unpopulated TLB entry
-                * for the address in question. To workaround that,
-                * we invalidate the TLB here, thus avoiding dcbst
-                * misbehaviour.
-                */
-               _tlbil_va(address, 0 /* 8xx doesn't care about PID */);
-#endif
-               /* The _PAGE_USER test should really be _PAGE_EXEC, but
-                * older glibc versions execute some code from no-exec
-                * pages, which for now we are supporting.  If exec-only
-                * pages are ever implemented, this will have to change.
-                */
-               if (!PageReserved(page) && (pte_val(pte) & _PAGE_USER)
-                   && !test_bit(PG_arch_1, &page->flags)) {
-                       if (vma->vm_mm == current->active_mm) {
-                               __flush_dcache_icache((void *) address);
-                       } else
-                               flush_dcache_icache_page(page);
-                       set_bit(PG_arch_1, &page->flags);
-               }
-       }
 
-#ifdef CONFIG_PPC_STD_MMU
        /* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */
        if (!pte_young(pte) || address >= TASK_SIZE)
                return;
similarity index 65%
rename from arch/powerpc/mm/mmap.c
rename to arch/powerpc/mm/mmap_64.c
index 86010fc7d3b17accc427c12f00606a0d1f4bbc70..0d957a4c70feda668078a7b412bb29adbd67a5fb 100644 (file)
 
 #include <linux/personality.h>
 #include <linux/mm.h>
+#include <linux/random.h>
 #include <linux/sched.h>
 
 /*
  * Top of mmap area (just below the process stack).
  *
- * Leave an at least ~128 MB hole.
+ * Leave at least a ~128 MB hole on 32bit applications.
+ *
+ * On 64bit applications we randomise the stack by 1GB so we need to
+ * space our mmap start address by a further 1GB, otherwise there is a
+ * chance the mmap area will end up closer to the stack than our ulimit
+ * requires.
  */
-#define MIN_GAP (128*1024*1024)
+#define MIN_GAP32 (128*1024*1024)
+#define MIN_GAP64 ((128 + 1024)*1024*1024UL)
+#define MIN_GAP ((is_32bit_task()) ? MIN_GAP32 : MIN_GAP64)
 #define MAX_GAP (TASK_SIZE/6*5)
 
-static inline unsigned long mmap_base(void)
-{
-       unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
-
-       if (gap < MIN_GAP)
-               gap = MIN_GAP;
-       else if (gap > MAX_GAP)
-               gap = MAX_GAP;
-
-       return TASK_SIZE - (gap & PAGE_MASK);
-}
-
 static inline int mmap_is_legacy(void)
 {
-       /*
-        * Force standard allocation for 64 bit programs.
-        */
-       if (!test_thread_flag(TIF_32BIT))
-               return 1;
-
        if (current->personality & ADDR_COMPAT_LAYOUT)
                return 1;
 
@@ -63,6 +53,40 @@ static inline int mmap_is_legacy(void)
        return sysctl_legacy_va_layout;
 }
 
+/*
+ * Since get_random_int() returns the same value within a 1 jiffy window,
+ * we will almost always get the same randomisation for the stack and mmap
+ * region. This will mean the relative distance between stack and mmap will
+ * be the same.
+ *
+ * To avoid this we can shift the randomness by 1 bit.
+ */
+static unsigned long mmap_rnd(void)
+{
+       unsigned long rnd = 0;
+
+       if (current->flags & PF_RANDOMIZE) {
+               /* 8MB for 32bit, 1GB for 64bit */
+               if (is_32bit_task())
+                       rnd = (long)(get_random_int() % (1<<(22-PAGE_SHIFT)));
+               else
+                       rnd = (long)(get_random_int() % (1<<(29-PAGE_SHIFT)));
+       }
+       return (rnd << PAGE_SHIFT) * 2;
+}
+
+static inline unsigned long mmap_base(void)
+{
+       unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
+
+       if (gap < MIN_GAP)
+               gap = MIN_GAP;
+       else if (gap > MAX_GAP)
+               gap = MAX_GAP;
+
+       return PAGE_ALIGN(TASK_SIZE - gap - mmap_rnd());
+}
+
 /*
  * This function, called very early during the creation of a new
  * process VM image, sets up which VM layout function to use:
index 52a0cfc38b6488eecd50374d56271f1fc3a83553..a70e311bd457d83991895b2a519411f9ead6499d 100644 (file)
@@ -97,7 +97,7 @@ static unsigned int steal_context_smp(unsigned int id)
                mm->context.id = MMU_NO_CONTEXT;
 
                /* Mark it stale on all CPUs that used this mm */
-               for_each_cpu_mask_nr(cpu, mm->cpu_vm_mask)
+               for_each_cpu(cpu, mm_cpumask(mm))
                        __set_bit(id, stale_map[cpu]);
                return id;
        }
@@ -380,7 +380,7 @@ void __init mmu_context_init(void)
 #endif
 
        printk(KERN_INFO
-              "MMU: Allocated %d bytes of context maps for %d contexts\n",
+              "MMU: Allocated %zu bytes of context maps for %d contexts\n",
               2 * CTX_MAP_SIZE + (sizeof(void *) * (last_context + 1)),
               last_context - first_context + 1);
 
index 5ac08b8ab654f50391ebc8087c57a2b84c48aa52..9047145095aa81ef8e04147ed92ea96155e08b1a 100644 (file)
@@ -158,35 +158,6 @@ static void unmap_cpu_from_node(unsigned long cpu)
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
-static struct device_node * __cpuinit find_cpu_node(unsigned int cpu)
-{
-       unsigned int hw_cpuid = get_hard_smp_processor_id(cpu);
-       struct device_node *cpu_node = NULL;
-       const unsigned int *interrupt_server, *reg;
-       int len;
-
-       while ((cpu_node = of_find_node_by_type(cpu_node, "cpu")) != NULL) {
-               /* Try interrupt server first */
-               interrupt_server = of_get_property(cpu_node,
-                                       "ibm,ppc-interrupt-server#s", &len);
-
-               len = len / sizeof(u32);
-
-               if (interrupt_server && (len > 0)) {
-                       while (len--) {
-                               if (interrupt_server[len] == hw_cpuid)
-                                       return cpu_node;
-                       }
-               } else {
-                       reg = of_get_property(cpu_node, "reg", &len);
-                       if (reg && (len > 0) && (reg[0] == hw_cpuid))
-                               return cpu_node;
-               }
-       }
-
-       return NULL;
-}
-
 /* must hold reference to node during call */
 static const int *of_get_associativity(struct device_node *dev)
 {
@@ -290,7 +261,7 @@ static int __init find_min_common_depth(void)
        ref_points = of_get_property(rtas_root,
                        "ibm,associativity-reference-points", &len);
 
-       if ((len >= 1) && ref_points) {
+       if ((len >= 2 * sizeof(unsigned int)) && ref_points) {
                depth = ref_points[1];
        } else {
                dbg("NUMA: ibm,associativity-reference-points not found.\n");
@@ -470,7 +441,7 @@ static int of_drconf_to_nid_single(struct of_drconf_cell *drmem,
 static int __cpuinit numa_setup_cpu(unsigned long lcpu)
 {
        int nid = 0;
-       struct device_node *cpu = find_cpu_node(lcpu);
+       struct device_node *cpu = of_get_cpu_node(lcpu, NULL);
 
        if (!cpu) {
                WARN_ON(1);
@@ -652,7 +623,7 @@ static int __init parse_numa_properties(void)
        for_each_present_cpu(i) {
                int nid;
 
-               cpu = find_cpu_node(i);
+               cpu = of_get_cpu_node(i, NULL);
                BUG_ON(!cpu);
                nid = of_node_to_nid_single(cpu);
                of_node_put(cpu);
@@ -1041,57 +1012,32 @@ early_param("numa", early_numa);
 
 #ifdef CONFIG_MEMORY_HOTPLUG
 /*
- * Validate the node associated with the memory section we are
- * trying to add.
- */
-int valid_hot_add_scn(int *nid, unsigned long start, u32 lmb_size,
-                     unsigned long scn_addr)
-{
-       nodemask_t nodes;
-
-       if (*nid < 0 || !node_online(*nid))
-               *nid = any_online_node(NODE_MASK_ALL);
-
-       if ((scn_addr >= start) && (scn_addr < (start + lmb_size))) {
-               nodes_setall(nodes);
-               while (NODE_DATA(*nid)->node_spanned_pages == 0) {
-                       node_clear(*nid, nodes);
-                       *nid = any_online_node(nodes);
-               }
-
-               return 1;
-       }
-
-       return 0;
-}
-
-/*
- * Find the node associated with a hot added memory section represented
- * by the ibm,dynamic-reconfiguration-memory node.
+ * Find the node associated with a hot added memory section for
+ * memory represented in the device tree by the property
+ * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory.
  */
 static int hot_add_drconf_scn_to_nid(struct device_node *memory,
                                     unsigned long scn_addr)
 {
        const u32 *dm;
-       unsigned int n, rc;
+       unsigned int drconf_cell_cnt, rc;
        unsigned long lmb_size;
-       int default_nid = any_online_node(NODE_MASK_ALL);
-       int nid;
        struct assoc_arrays aa;
+       int nid = -1;
 
-       n = of_get_drconf_memory(memory, &dm);
-       if (!n)
-               return default_nid;;
+       drconf_cell_cnt = of_get_drconf_memory(memory, &dm);
+       if (!drconf_cell_cnt)
+               return -1;
 
        lmb_size = of_get_lmb_size(memory);
        if (!lmb_size)
-               return default_nid;
+               return -1;
 
        rc = of_get_assoc_arrays(memory, &aa);
        if (rc)
-               return default_nid;
+               return -1;
 
-       for (; n != 0; --n) {
+       for (; drconf_cell_cnt != 0; --drconf_cell_cnt) {
                struct of_drconf_cell drmem;
 
                read_drconf_cell(&drmem, &dm);
@@ -1102,15 +1048,57 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory,
                    || !(drmem.flags & DRCONF_MEM_ASSIGNED))
                        continue;
 
+               if ((scn_addr < drmem.base_addr)
+                   || (scn_addr >= (drmem.base_addr + lmb_size)))
+                       continue;
+
                nid = of_drconf_to_nid_single(&drmem, &aa);
+               break;
+       }
+
+       return nid;
+}
 
-               if (valid_hot_add_scn(&nid, drmem.base_addr, lmb_size,
-                                     scn_addr))
-                       return nid;
+/*
+ * Find the node associated with a hot added memory section for memory
+ * represented in the device tree as a node (i.e. memory@XXXX) for
+ * each lmb.
+ */
+int hot_add_node_scn_to_nid(unsigned long scn_addr)
+{
+       struct device_node *memory = NULL;
+       int nid = -1;
+
+       while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
+               unsigned long start, size;
+               int ranges;
+               const unsigned int *memcell_buf;
+               unsigned int len;
+
+               memcell_buf = of_get_property(memory, "reg", &len);
+               if (!memcell_buf || len <= 0)
+                       continue;
+
+               /* ranges in cell */
+               ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells);
+
+               while (ranges--) {
+                       start = read_n_cells(n_mem_addr_cells, &memcell_buf);
+                       size = read_n_cells(n_mem_size_cells, &memcell_buf);
+
+                       if ((scn_addr < start) || (scn_addr >= (start + size)))
+                               continue;
+
+                       nid = of_node_to_nid_single(memory);
+                       break;
+               }
+
+               of_node_put(memory);
+               if (nid >= 0)
+                       break;
        }
 
-       BUG();  /* section address should be found above */
-       return 0;
+       return nid;
 }
 
 /*
@@ -1121,7 +1109,7 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory,
 int hot_add_scn_to_nid(unsigned long scn_addr)
 {
        struct device_node *memory = NULL;
-       int nid;
+       int nid, found = 0;
 
        if (!numa_enabled || (min_common_depth < 0))
                return any_online_node(NODE_MASK_ALL);
@@ -1130,35 +1118,25 @@ int hot_add_scn_to_nid(unsigned long scn_addr)
        if (memory) {
                nid = hot_add_drconf_scn_to_nid(memory, scn_addr);
                of_node_put(memory);
-               return nid;
+       } else {
+               nid = hot_add_node_scn_to_nid(scn_addr);
        }
 
-       while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
-               unsigned long start, size;
-               int ranges;
-               const unsigned int *memcell_buf;
-               unsigned int len;
-
-               memcell_buf = of_get_property(memory, "reg", &len);
-               if (!memcell_buf || len <= 0)
-                       continue;
+       if (nid < 0 || !node_online(nid))
+               nid = any_online_node(NODE_MASK_ALL);
 
-               /* ranges in cell */
-               ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells);
-ha_new_range:
-               start = read_n_cells(n_mem_addr_cells, &memcell_buf);
-               size = read_n_cells(n_mem_size_cells, &memcell_buf);
-               nid = of_node_to_nid_single(memory);
+       if (NODE_DATA(nid)->node_spanned_pages)
+               return nid;
 
-               if (valid_hot_add_scn(&nid, start, size, scn_addr)) {
-                       of_node_put(memory);
-                       return nid;
+       for_each_online_node(nid) {
+               if (NODE_DATA(nid)->node_spanned_pages) {
+                       found = 1;
+                       break;
                }
-
-               if (--ranges)           /* process all ranges in cell */
-                       goto ha_new_range;
        }
-       BUG();  /* section address should be found above */
-       return 0;
+
+       BUG_ON(!found);
+       return nid;
 }
+
 #endif /* CONFIG_MEMORY_HOTPLUG */
index 6d94116fdea171b6683fc938e7639dfe92ba1caf..f5c6fd42265c795a00e6244a9b694d282832bb06 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * This file contains common routines for dealing with free of page tables
+ * Along with common page table handling code
  *
  *  Derived from arch/powerpc/mm/tlb_64.c:
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -81,11 +82,10 @@ static void pte_free_submit(struct pte_freelist_batch *batch)
 void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf)
 {
        /* This is safe since tlb_gather_mmu has disabled preemption */
-        cpumask_t local_cpumask = cpumask_of_cpu(smp_processor_id());
        struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
 
        if (atomic_read(&tlb->mm->mm_users) < 2 ||
-           cpus_equal(tlb->mm->cpu_vm_mask, local_cpumask)) {
+           cpumask_equal(mm_cpumask(tlb->mm), cpumask_of(smp_processor_id()))){
                pgtable_free(pgf);
                return;
        }
@@ -115,3 +115,133 @@ void pte_free_finish(void)
        pte_free_submit(*batchp);
        *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_debug("do_dcache_icache_coherency... flushing\n");
+               flush_dcache_icache_page(page);
+               set_bit(PG_arch_1, &page->flags);
+       }
+       else
+               pr_debug("do_dcache_icache_coherency... already clean\n");
+       return __pte(pte_val(pte) | _PAGE_HWEXEC);
+}
+
+static inline int is_exec_fault(void)
+{
+       return current->thread.regs && TRAP(current->thread.regs) == 0x400;
+}
+
+/* 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
+ */
+static inline int pte_looks_normal(pte_t pte)
+{
+       return (pte_val(pte) &
+               (_PAGE_PRESENT | _PAGE_SPECIAL | _PAGE_NO_CACHE)) ==
+               (_PAGE_PRESENT);
+}
+
+#if defined(CONFIG_PPC_STD_MMU)
+/* 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.
+ */
+static inline int pte_need_exec_flush(pte_t pte, int set_pte)
+{
+       return set_pte && pte_looks_normal(pte) &&
+               !(cpu_has_feature(CPU_FTR_COHERENT_ICACHE) ||
+                 cpu_has_feature(CPU_FTR_NOEXECUTE));
+}
+#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)
+{
+       return set_pte && pte_looks_normal(pte);
+}
+#else
+/* Other embedded CPUs with HW exec support per-page, we flush on exec
+ * fault if HWEXEC is not set
+ */
+static inline int pte_need_exec_flush(pte_t pte, int set_pte)
+{
+       return pte_looks_normal(pte) && is_exec_fault() &&
+               !(pte_val(pte) & _PAGE_HWEXEC);
+}
+#endif
+
+/*
+ * 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)
+{
+#ifdef CONFIG_DEBUG_VM
+       WARN_ON(pte_present(*ptep));
+#endif
+       /* Note: mm->context.id might not yet have been assigned as
+        * 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);
+
+       /* Perform the setting of the PTE */
+       __set_pte_at(mm, addr, ptep, pte, 0);
+}
+
+/*
+ * This is called when relaxing access to a PTE. It's also called in the page
+ * fault path when we don't hit any of the major fault cases, ie, a minor
+ * update of _PAGE_ACCESSED, _PAGE_DIRTY, etc... The generic code will have
+ * handled those two for us, we additionally deal with missing execute
+ * permission here on some processors
+ */
+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);
+       changed = !pte_same(*(ptep), entry);
+       if (changed) {
+               assert_pte_locked(vma->vm_mm, address);
+               __ptep_set_access_flags(ptep, entry);
+               flush_tlb_page_nohash(vma, address);
+       }
+       return changed;
+}
+
+#ifdef CONFIG_DEBUG_VM
+void assert_pte_locked(struct mm_struct *mm, unsigned long addr)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+
+       if (mm == &init_mm)
+               return;
+       pgd = mm->pgd + pgd_index(addr);
+       BUG_ON(pgd_none(*pgd));
+       pud = pud_offset(pgd, 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)));
+}
+#endif /* CONFIG_DEBUG_VM */
+
index 58bcaeba728d6b6a57355f1736d8737e6f0bbd3b..430d0908fa506341b3133ca6e7eca467f77ce7ef 100644 (file)
@@ -129,7 +129,8 @@ pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
 void __iomem *
 ioremap(phys_addr_t addr, unsigned long size)
 {
-       return __ioremap(addr, size, _PAGE_NO_CACHE | _PAGE_GUARDED);
+       return __ioremap_caller(addr, size, _PAGE_NO_CACHE | _PAGE_GUARDED,
+                               __builtin_return_address(0));
 }
 EXPORT_SYMBOL(ioremap);
 
@@ -143,12 +144,19 @@ ioremap_flags(phys_addr_t addr, unsigned long size, unsigned long flags)
        /* we don't want to let _PAGE_USER and _PAGE_EXEC leak out */
        flags &= ~(_PAGE_USER | _PAGE_EXEC | _PAGE_HWEXEC);
 
-       return __ioremap(addr, size, flags);
+       return __ioremap_caller(addr, size, flags, __builtin_return_address(0));
 }
 EXPORT_SYMBOL(ioremap_flags);
 
 void __iomem *
 __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
+{
+       return __ioremap_caller(addr, size, flags, __builtin_return_address(0));
+}
+
+void __iomem *
+__ioremap_caller(phys_addr_t addr, unsigned long size, unsigned long flags,
+                void *caller)
 {
        unsigned long v, i;
        phys_addr_t p;
@@ -156,7 +164,7 @@ __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
 
        /* Make sure we have the base flags */
        if ((flags & _PAGE_PRESENT) == 0)
-               flags |= _PAGE_KERNEL;
+               flags |= PAGE_KERNEL;
 
        /* Non-cacheable page cannot be coherent */
        if (flags & _PAGE_NO_CACHE)
@@ -212,7 +220,7 @@ __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
 
        if (mem_init_done) {
                struct vm_struct *area;
-               area = get_vm_area(size, VM_IOREMAP);
+               area = get_vm_area_caller(size, VM_IOREMAP, caller);
                if (area == 0)
                        return NULL;
                v = (unsigned long) area->addr;
@@ -288,7 +296,7 @@ void __init mapin_ram(void)
        p = memstart_addr + s;
        for (; s < total_lowmem; s += PAGE_SIZE) {
                ktext = ((char *) v >= _stext && (char *) v < etext);
-               f = ktext ?_PAGE_RAM_TEXT : _PAGE_RAM;
+               f = ktext ? PAGE_KERNEL_TEXT : PAGE_KERNEL;
                map_page(v, p, f);
 #ifdef CONFIG_PPC_STD_MMU_32
                if (ktext)
index 365e61ae5dbcf54f7f4789d2cfed5bb7072201e3..bfa7db6b2fd5446e193669a1afd02d09f7f9aab9 100644 (file)
@@ -144,8 +144,8 @@ void __iounmap_at(void *ea, unsigned long size)
        unmap_kernel_range((unsigned long)ea, size);
 }
 
-void __iomem * __ioremap(phys_addr_t addr, unsigned long size,
-                        unsigned long flags)
+void __iomem * __ioremap_caller(phys_addr_t addr, unsigned long size,
+                               unsigned long flags, void *caller)
 {
        phys_addr_t paligned;
        void __iomem *ret;
@@ -168,8 +168,9 @@ void __iomem * __ioremap(phys_addr_t addr, unsigned long size,
        if (mem_init_done) {
                struct vm_struct *area;
 
-               area = __get_vm_area(size, VM_IOREMAP,
-                                    ioremap_bot, IOREMAP_END);
+               area = __get_vm_area_caller(size, VM_IOREMAP,
+                                           ioremap_bot, IOREMAP_END,
+                                           caller);
                if (area == NULL)
                        return NULL;
                ret = __ioremap_at(paligned, area->addr, size, flags);
@@ -186,19 +187,27 @@ void __iomem * __ioremap(phys_addr_t addr, unsigned long size,
        return ret;
 }
 
+void __iomem * __ioremap(phys_addr_t addr, unsigned long size,
+                        unsigned long flags)
+{
+       return __ioremap_caller(addr, size, flags, __builtin_return_address(0));
+}
 
 void __iomem * ioremap(phys_addr_t addr, unsigned long size)
 {
        unsigned long flags = _PAGE_NO_CACHE | _PAGE_GUARDED;
+       void *caller = __builtin_return_address(0);
 
        if (ppc_md.ioremap)
-               return ppc_md.ioremap(addr, size, flags);
-       return __ioremap(addr, size, flags);
+               return ppc_md.ioremap(addr, size, flags, caller);
+       return __ioremap_caller(addr, size, flags, caller);
 }
 
 void __iomem * ioremap_flags(phys_addr_t addr, unsigned long size,
                             unsigned long flags)
 {
+       void *caller = __builtin_return_address(0);
+
        /* writeable implies dirty for kernel addresses */
        if (flags & _PAGE_RW)
                flags |= _PAGE_DIRTY;
@@ -207,8 +216,8 @@ void __iomem * ioremap_flags(phys_addr_t addr, unsigned long size,
        flags &= ~(_PAGE_USER | _PAGE_EXEC);
 
        if (ppc_md.ioremap)
-               return ppc_md.ioremap(addr, size, flags);
-       return __ioremap(addr, size, flags);
+               return ppc_md.ioremap(addr, size, flags, caller);
+       return __ioremap_caller(addr, size, flags, caller);
 }
 
 
index fe65c405412c55018f9d71e0f6a437e292a1dcf5..2d2a87e101549bea39f4775b61f13153cb5256a3 100644 (file)
@@ -74,9 +74,6 @@ unsigned long p_mapped_by_bats(phys_addr_t pa)
 
 unsigned long __init mmu_mapin_ram(void)
 {
-#ifdef CONFIG_POWER4
-       return 0;
-#else
        unsigned long tot, bl, done;
        unsigned long max_size = (256<<20);
 
@@ -95,7 +92,7 @@ unsigned long __init mmu_mapin_ram(void)
                        break;
        }
 
-       setbat(2, PAGE_OFFSET, 0, bl, _PAGE_RAM);
+       setbat(2, PAGE_OFFSET, 0, bl, PAGE_KERNEL_X);
        done = (unsigned long)bat_addrs[2].limit - PAGE_OFFSET + 1;
        if ((done < tot) && !bat_addrs[3].limit) {
                /* use BAT3 to cover a bit more */
@@ -103,12 +100,11 @@ unsigned long __init mmu_mapin_ram(void)
                for (bl = 128<<10; bl < max_size; bl <<= 1)
                        if (bl * 2 > tot)
                                break;
-               setbat(3, PAGE_OFFSET+done, done, bl, _PAGE_RAM);
+               setbat(3, PAGE_OFFSET+done, done, bl, PAGE_KERNEL_X);
                done = (unsigned long)bat_addrs[3].limit - PAGE_OFFSET + 1;
        }
 
        return done;
-#endif
 }
 
 /*
@@ -136,9 +132,7 @@ void __init setbat(int index, unsigned long virt, phys_addr_t phys,
                wimgxpp |= (flags & _PAGE_RW)? BPP_RW: BPP_RX;
                bat[1].batu = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
                bat[1].batl = BAT_PHYS_ADDR(phys) | wimgxpp;
-#ifndef CONFIG_KGDB /* want user access for breakpoints */
                if (flags & _PAGE_USER)
-#endif
                        bat[1].batu |= 1;       /* Vp = 1 */
                if (flags & _PAGE_GUARDED) {
                        /* G bit must be zero in IBATs */
index c931bc7d1079bec0e9241620781aa5eb5251aba6..1be1b5e597962727bf41607684d6767b98548238 100644 (file)
@@ -139,12 +139,12 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
  */
 void __flush_tlb_pending(struct ppc64_tlb_batch *batch)
 {
-       cpumask_t tmp;
+       const struct cpumask *tmp;
        int i, local = 0;
 
        i = batch->index;
-       tmp = cpumask_of_cpu(smp_processor_id());
-       if (cpus_equal(batch->mm->cpu_vm_mask, tmp))
+       tmp = cpumask_of(smp_processor_id());
+       if (cpumask_equal(mm_cpumask(batch->mm), tmp))
                local = 1;
        if (i == 1)
                flush_hash_page(batch->vaddr[0], batch->pte[0],
index 39ac22b13c73ddaa10a0379129e8b2c279f97c95..7af72970faed2c8b33c3e4d63e2b61b297621f36 100644 (file)
@@ -132,11 +132,11 @@ void flush_tlb_mm(struct mm_struct *mm)
        pid = mm->context.id;
        if (unlikely(pid == MMU_NO_CONTEXT))
                goto no_context;
-       cpu_mask = mm->cpu_vm_mask;
-       cpu_clear(smp_processor_id(), cpu_mask);
-       if (!cpus_empty(cpu_mask)) {
+       if (!cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
                struct tlb_flush_param p = { .pid = pid };
-               smp_call_function_mask(cpu_mask, do_flush_tlb_mm_ipi, &p, 1);
+               /* Ignores smp_processor_id() even if set. */
+               smp_call_function_many(mm_cpumask(mm),
+                                      do_flush_tlb_mm_ipi, &p, 1);
        }
        _tlbil_pid(pid);
  no_context:
@@ -146,16 +146,15 @@ EXPORT_SYMBOL(flush_tlb_mm);
 
 void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
 {
-       cpumask_t cpu_mask;
+       struct cpumask *cpu_mask;
        unsigned int pid;
 
        preempt_disable();
        pid = vma ? vma->vm_mm->context.id : 0;
        if (unlikely(pid == MMU_NO_CONTEXT))
                goto bail;
-       cpu_mask = vma->vm_mm->cpu_vm_mask;
-       cpu_clear(smp_processor_id(), cpu_mask);
-       if (!cpus_empty(cpu_mask)) {
+       cpu_mask = mm_cpumask(vma->vm_mm);
+       if (!cpumask_equal(cpu_mask, cpumask_of(smp_processor_id()))) {
                /* 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);
@@ -167,7 +166,8 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
                        goto bail;
                } else {
                        struct tlb_flush_param p = { .pid = pid, .addr = vmaddr };
-                       smp_call_function_mask(cpu_mask,
+                       /* Ignores smp_processor_id() even if set in cpu_mask */
+                       smp_call_function_many(cpu_mask,
                                               do_flush_tlb_page_ipi, &p, 1);
                }
        }
index f900a39e6ec409f9a6c7789a5fbf5747777e6ffc..788b87c36f7795922ef312d8a305c46a6c512a0f 100644 (file)
@@ -118,25 +118,50 @@ _GLOBAL(_tlbil_pid)
 
 #elif defined(CONFIG_FSL_BOOKE)
 /*
- * FSL BookE implementations. Currently _pid and _all are the
- * same. This will change when tlbilx is actually supported and
- * performs invalidate-by-PID. This change will be driven by
- * mmu_features conditional
+ * FSL BookE implementations.
+ *
+ * Since feature sections are using _SECTION_ELSE we need
+ * 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
  */
-_GLOBAL(_tlbil_pid)
 _GLOBAL(_tlbil_all)
-#define MMUCSR0_TLBFI  (MMUCSR0_TLB0FI | MMUCSR0_TLB1FI | \
-                        MMUCSR0_TLB2FI | MMUCSR0_TLB3FI)
+BEGIN_MMU_FTR_SECTION
+       li      r3,(MMUCSR0_TLBFI)@l
+       mtspr   SPRN_MMUCSR0, r3
+1:
+       mfspr   r3,SPRN_MMUCSR0
+       andi.   r3,r3,MMUCSR0_TLBFI@l
+       bne     1b
+MMU_FTR_SECTION_ELSE
+       PPC_TLBILX_ALL(0,0)
+ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_USE_TLBILX)
+       msync
+       isync
+       blr
+
+_GLOBAL(_tlbil_pid)
+BEGIN_MMU_FTR_SECTION
+       slwi    r3,r3,16
+       mfmsr   r10
+       wrteei  0
+       mfspr   r4,SPRN_MAS6    /* save MAS6 */
+       mtspr   SPRN_MAS6,r3
+       PPC_TLBILX_PID(0,0)
+       mtspr   SPRN_MAS6,r4    /* restore MAS6 */
+       wrtee   r10
+MMU_FTR_SECTION_ELSE
        li      r3,(MMUCSR0_TLBFI)@l
        mtspr   SPRN_MMUCSR0, r3
 1:
        mfspr   r3,SPRN_MMUCSR0
        andi.   r3,r3,MMUCSR0_TLBFI@l
        bne     1b
+ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_USE_TLBILX)
        msync
        isync
        blr
@@ -149,7 +174,9 @@ _GLOBAL(_tlbil_va)
        mfmsr   r10
        wrteei  0
        slwi    r4,r4,16
+       ori     r4,r4,(MAS6_ISIZE(BOOK3E_PAGESZ_4K))@l
        mtspr   SPRN_MAS6,r4            /* assume AS=0 for now */
+BEGIN_MMU_FTR_SECTION
        tlbsx   0,r3
        mfspr   r4,SPRN_MAS1            /* check valid */
        andis.  r3,r4,MAS1_VALID@h
@@ -157,6 +184,9 @@ _GLOBAL(_tlbil_va)
        rlwinm  r4,r4,0,1,31
        mtspr   SPRN_MAS1,r4
        tlbwe
+MMU_FTR_SECTION_ELSE
+       PPC_TLBILX_VA(0,r3)
+ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_USE_TLBILX)
        msync
        isync
 1:     wrtee   r10
index cc599eb8768b3eac6bbbe1a1ad862d1d80db2283..f8d36f940e88697c698b02f089d4a0d9c0f98670 100644 (file)
@@ -29,7 +29,7 @@
 static unsigned long reset_value[OP_MAX_COUNTER];
 
 static int oprofile_running;
-static u32 mmcr0_val, mmcr1_val, mmcr2_val;
+static u32 mmcr0_val, mmcr1_val, mmcr2_val, num_pmcs;
 
 #define MMCR0_PMC1_SHIFT       6
 #define MMCR0_PMC2_SHIFT       0
@@ -88,13 +88,12 @@ static int fsl7450_cpu_setup(struct op_counter_config *ctr)
 
        mtspr(SPRN_MMCR0, mmcr0_val);
        mtspr(SPRN_MMCR1, mmcr1_val);
-       mtspr(SPRN_MMCR2, mmcr2_val);
+       if (num_pmcs > 4)
+               mtspr(SPRN_MMCR2, mmcr2_val);
 
        return 0;
 }
 
-#define NUM_CTRS 6
-
 /* Configures the global settings for the countes on all CPUs. */
 static int fsl7450_reg_setup(struct op_counter_config *ctr,
                             struct op_system_config *sys,
@@ -102,12 +101,13 @@ static int fsl7450_reg_setup(struct op_counter_config *ctr,
 {
        int i;
 
+       num_pmcs = num_ctrs;
        /* Our counters count up, and "count" refers to
         * how much before the next interrupt, and we interrupt
         * on overflow.  So we calculate the starting value
         * which will give us "count" until overflow.
         * Then we set the events on the enabled counters */
-       for (i = 0; i < NUM_CTRS; ++i)
+       for (i = 0; i < num_ctrs; ++i)
                reset_value[i] = 0x80000000UL - ctr[i].count;
 
        /* Set events for Counters 1 & 2 */
@@ -123,9 +123,10 @@ static int fsl7450_reg_setup(struct op_counter_config *ctr,
 
        /* Set events for Counters 3-6 */
        mmcr1_val = mmcr1_event3(ctr[2].event)
-               | mmcr1_event4(ctr[3].event)
-               | mmcr1_event5(ctr[4].event)
-               | mmcr1_event6(ctr[5].event);
+               | mmcr1_event4(ctr[3].event);
+       if (num_ctrs > 4)
+               mmcr1_val |= mmcr1_event5(ctr[4].event)
+                       | mmcr1_event6(ctr[5].event);
 
        mmcr2_val = 0;
 
@@ -139,7 +140,7 @@ static int fsl7450_start(struct op_counter_config *ctr)
 
        mtmsr(mfmsr() | MSR_PMM);
 
-       for (i = 0; i < NUM_CTRS; ++i) {
+       for (i = 0; i < num_pmcs; ++i) {
                if (ctr[i].enabled)
                        classic_ctr_write(i, reset_value[i]);
                else
@@ -184,7 +185,7 @@ static void fsl7450_handle_interrupt(struct pt_regs *regs,
        pc = mfspr(SPRN_SIAR);
        is_kernel = is_kernel_addr(pc);
 
-       for (i = 0; i < NUM_CTRS; ++i) {
+       for (i = 0; i < num_pmcs; ++i) {
                val = classic_ctr_read(i);
                if (val < 0) {
                        if (oprofile_running && ctr[i].enabled) {
index 3496bc05058ed63bef9773f843b97fb4b16fd642..bf5c7ff2e6e5fdc3da7867f567eb58e4ccb07ee2 100644 (file)
@@ -118,6 +118,17 @@ config GLACIER
        help
          This option enables support for the AMCC PPC460GT evaluation board.
 
+config REDWOOD
+       bool "Redwood"
+       depends on 44x
+       default n
+       select PPC44x_SIMPLE
+       select 460SX
+       select PCI
+       select PPC4xx_PCI_EXPRESS
+       help
+         This option enables support for the AMCC PPC460SX Redwood board.
+
 config YOSEMITE
        bool "Yosemite"
        depends on 44x
@@ -220,6 +231,14 @@ config 460EX
        select IBM_NEW_EMAC_EMAC4
        select IBM_NEW_EMAC_TAH
 
+config 460SX
+       bool
+       select PPC_FPU
+       select IBM_NEW_EMAC_EMAC4
+       select IBM_NEW_EMAC_RGMII
+       select IBM_NEW_EMAC_ZMII
+       select IBM_NEW_EMAC_TAH
+
 # 44x errata/workaround config symbols, selected by the CPU models above
 config IBM440EP_ERR42
        bool
index 76fdc51dac8b64091f2a9fcf6d1b51ef1c02efe5..5bcd441885e83c5fb4f62a488c012710a397b916 100644 (file)
@@ -57,6 +57,7 @@ static char *board[] __initdata = {
        "ibm,ebony",
        "amcc,katmai",
        "amcc,rainier",
+       "amcc,redwood",
        "amcc,sequoia",
        "amcc,taishan",
        "amcc,yosemite"
index 326852c78b8fa79caf1349f0e1776b955285a26c..4dac9b0525a458337c353bf0e95dba28ffd327e0 100644 (file)
@@ -12,7 +12,7 @@ config PPC_MPC5121
 
 config MPC5121_ADS
        bool "Freescale MPC5121E ADS"
-       depends on PPC_MULTIPLATFORM && PPC32
+       depends on 6xx
        select DEFAULT_UIMAGE
        select PPC_MPC5121
        select MPC5121_ADS_CPLD
@@ -21,7 +21,7 @@ config MPC5121_ADS
 
 config MPC5121_GENERIC
        bool "Generic support for simple MPC5121 based boards"
-       depends on PPC_MULTIPLATFORM && PPC32
+       depends on 6xx
        select DEFAULT_UIMAGE
        select PPC_MPC5121
        help
index 696a5ee4962d20c81737b5a36db3ece5a13041bd..8b8e9560a315ed51127625b8544edc8a2f24b667 100644 (file)
@@ -1,6 +1,6 @@
 config PPC_MPC52xx
        bool "52xx-based boards"
-       depends on PPC_MULTIPLATFORM && PPC32
+       depends on 6xx
        select PPC_CLOCK
        select PPC_PCI_CHOICE
 
@@ -21,7 +21,13 @@ config PPC_MPC5200_SIMPLE
            and if there is a PCI bus node defined in the device tree.
 
          Boards that are compatible with this generic platform support
-         are: 'tqc,tqm5200', 'promess,motionpro', 'schindler,cm5200'.
+         are:
+            intercontrol,digsy-mtc
+            phytec,pcm030
+            phytec,pcm032
+            promess,motionpro
+            schindler,cm5200
+            tqc,tqm5200
 
 config PPC_EFIKA
        bool "bPlan Efika 5k2. MPC5200B based computer"
@@ -35,6 +41,11 @@ config PPC_LITE5200
        depends on PPC_MPC52xx
        select DEFAULT_UIMAGE
 
+config PPC_MEDIA5200
+       bool "Freescale Media5200 Eval Board"
+       depends on PPC_MPC52xx
+       select DEFAULT_UIMAGE
+
 config PPC_MPC5200_BUGFIX
        bool "MPC5200 (L25R) bugfix support"
        depends on PPC_MPC52xx
index b8a52062738ac0f28345d0c3cd1ba4f350e38b33..bfd4f52cf3dd785a3827e78bffcb7fcc6a168f5e 100644 (file)
@@ -1,12 +1,13 @@
 #
 # Makefile for 52xx based boards
 #
-obj-y                          += mpc52xx_pic.o mpc52xx_common.o
+obj-y                          += mpc52xx_pic.o mpc52xx_common.o mpc52xx_gpt.o
 obj-$(CONFIG_PCI)              += mpc52xx_pci.o
 
 obj-$(CONFIG_PPC_MPC5200_SIMPLE) += mpc5200_simple.o
 obj-$(CONFIG_PPC_EFIKA)                += efika.o
 obj-$(CONFIG_PPC_LITE5200)     += lite5200.o
+obj-$(CONFIG_PPC_MEDIA5200)    += media5200.o
 
 obj-$(CONFIG_PM)               += mpc52xx_sleep.o mpc52xx_pm.o
 ifeq ($(CONFIG_PPC_LITE5200),y)
diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c
new file mode 100644 (file)
index 0000000..68e4f16
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Support for 'media5200-platform' compatible boards.
+ *
+ * Copyright (C) 2008 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 as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * Description:
+ * This code implements support for the Freescape Media5200 platform
+ * (built around the MPC5200 SoC).
+ *
+ * Notable characteristic of the Media5200 is the presence of an FPGA
+ * that has all external IRQ lines routed through it.  This file implements
+ * a cascaded interrupt controller driver which attaches itself to the
+ * Virtual IRQ subsystem after the primary mpc5200 interrupt controller
+ * is initialized.
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <asm/time.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/mpc52xx.h>
+
+static struct of_device_id mpc5200_gpio_ids[] __initdata = {
+       { .compatible = "fsl,mpc5200-gpio", },
+       { .compatible = "mpc5200-gpio", },
+       {}
+};
+
+/* FPGA register set */
+#define MEDIA5200_IRQ_ENABLE (0x40c)
+#define MEDIA5200_IRQ_STATUS (0x410)
+#define MEDIA5200_NUM_IRQS   (6)
+#define MEDIA5200_IRQ_SHIFT  (32 - MEDIA5200_NUM_IRQS)
+
+struct media5200_irq {
+       void __iomem *regs;
+       spinlock_t lock;
+       struct irq_host *irqhost;
+};
+struct media5200_irq media5200_irq;
+
+static void media5200_irq_unmask(unsigned int virq)
+{
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&media5200_irq.lock, flags);
+       val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE);
+       val |= 1 << (MEDIA5200_IRQ_SHIFT + irq_map[virq].hwirq);
+       out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val);
+       spin_unlock_irqrestore(&media5200_irq.lock, flags);
+}
+
+static void media5200_irq_mask(unsigned int virq)
+{
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&media5200_irq.lock, flags);
+       val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE);
+       val &= ~(1 << (MEDIA5200_IRQ_SHIFT + irq_map[virq].hwirq));
+       out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val);
+       spin_unlock_irqrestore(&media5200_irq.lock, flags);
+}
+
+static struct irq_chip media5200_irq_chip = {
+       .typename = "Media5200 FPGA",
+       .unmask = media5200_irq_unmask,
+       .mask = media5200_irq_mask,
+       .mask_ack = media5200_irq_mask,
+};
+
+void media5200_irq_cascade(unsigned int virq, struct irq_desc *desc)
+{
+       int sub_virq, val;
+       u32 status, enable;
+
+       /* Mask off the cascaded IRQ */
+       spin_lock(&desc->lock);
+       desc->chip->mask(virq);
+       spin_unlock(&desc->lock);
+
+       /* Ask the FPGA for IRQ status.  If 'val' is 0, then no irqs
+        * are pending.  'ffs()' is 1 based */
+       status = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE);
+       enable = in_be32(media5200_irq.regs + MEDIA5200_IRQ_STATUS);
+       val = ffs((status & enable) >> MEDIA5200_IRQ_SHIFT);
+       if (val) {
+               sub_virq = irq_linear_revmap(media5200_irq.irqhost, val - 1);
+               /* pr_debug("%s: virq=%i s=%.8x e=%.8x hwirq=%i subvirq=%i\n",
+                *          __func__, virq, status, enable, val - 1, sub_virq);
+                */
+               generic_handle_irq(sub_virq);
+       }
+
+       /* Processing done; can reenable the cascade now */
+       spin_lock(&desc->lock);
+       desc->chip->ack(virq);
+       if (!(desc->status & IRQ_DISABLED))
+               desc->chip->unmask(virq);
+       spin_unlock(&desc->lock);
+}
+
+static int media5200_irq_map(struct irq_host *h, unsigned int virq,
+                            irq_hw_number_t hw)
+{
+       struct irq_desc *desc = get_irq_desc(virq);
+
+       pr_debug("%s: h=%p, virq=%i, hwirq=%i\n", __func__, h, virq, (int)hw);
+       set_irq_chip_data(virq, &media5200_irq);
+       set_irq_chip_and_handler(virq, &media5200_irq_chip, handle_level_irq);
+       set_irq_type(virq, IRQ_TYPE_LEVEL_LOW);
+       desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
+       desc->status |= IRQ_TYPE_LEVEL_LOW | IRQ_LEVEL;
+
+       return 0;
+}
+
+static int media5200_irq_xlate(struct irq_host *h, struct device_node *ct,
+                                u32 *intspec, unsigned int intsize,
+                                irq_hw_number_t *out_hwirq,
+                                unsigned int *out_flags)
+{
+       if (intsize != 2)
+               return -1;
+
+       pr_debug("%s: bank=%i, number=%i\n", __func__, intspec[0], intspec[1]);
+       *out_hwirq = intspec[1];
+       *out_flags = IRQ_TYPE_NONE;
+       return 0;
+}
+
+static struct irq_host_ops media5200_irq_ops = {
+       .map = media5200_irq_map,
+       .xlate = media5200_irq_xlate,
+};
+
+/*
+ * Setup Media5200 IRQ mapping
+ */
+static void __init media5200_init_irq(void)
+{
+       struct device_node *fpga_np;
+       int cascade_virq;
+
+       /* First setup the regular MPC5200 interrupt controller */
+       mpc52xx_init_irq();
+
+       /* Now find the FPGA IRQ */
+       fpga_np = of_find_compatible_node(NULL, NULL, "fsl,media5200-fpga");
+       if (!fpga_np)
+               goto out;
+       pr_debug("%s: found fpga node: %s\n", __func__, fpga_np->full_name);
+
+       media5200_irq.regs = of_iomap(fpga_np, 0);
+       if (!media5200_irq.regs)
+               goto out;
+       pr_debug("%s: mapped to %p\n", __func__, media5200_irq.regs);
+
+       cascade_virq = irq_of_parse_and_map(fpga_np, 0);
+       if (!cascade_virq)
+               goto out;
+       pr_debug("%s: cascaded on virq=%i\n", __func__, cascade_virq);
+
+       /* Disable all FPGA IRQs */
+       out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, 0);
+
+       spin_lock_init(&media5200_irq.lock);
+
+       media5200_irq.irqhost = irq_alloc_host(fpga_np, IRQ_HOST_MAP_LINEAR,
+                                              MEDIA5200_NUM_IRQS,
+                                              &media5200_irq_ops, -1);
+       if (!media5200_irq.irqhost)
+               goto out;
+       pr_debug("%s: allocated irqhost\n", __func__);
+
+       media5200_irq.irqhost->host_data = &media5200_irq;
+
+       set_irq_data(cascade_virq, &media5200_irq);
+       set_irq_chained_handler(cascade_virq, media5200_irq_cascade);
+
+       return;
+
+ out:
+       pr_err("Could not find Media5200 FPGA; PCI interrupts will not work\n");
+}
+
+/*
+ * Setup the architecture
+ */
+static void __init media5200_setup_arch(void)
+{
+
+       struct device_node *np;
+       struct mpc52xx_gpio __iomem *gpio;
+       u32 port_config;
+
+       if (ppc_md.progress)
+               ppc_md.progress("media5200_setup_arch()", 0);
+
+       /* Map important registers from the internal memory map */
+       mpc52xx_map_common_devices();
+
+       /* Some mpc5200 & mpc5200b related configuration */
+       mpc5200_setup_xlb_arbiter();
+
+       mpc52xx_setup_pci();
+
+       np = of_find_matching_node(NULL, mpc5200_gpio_ids);
+       gpio = of_iomap(np, 0);
+       of_node_put(np);
+       if (!gpio) {
+               printk(KERN_ERR "%s() failed. expect abnormal behavior\n",
+                      __func__);
+               return;
+       }
+
+       /* Set port config */
+       port_config = in_be32(&gpio->port_config);
+
+       port_config &= ~0x03000000;     /* ATA CS is on csb_4/5         */
+       port_config |=  0x01000000;
+
+       out_be32(&gpio->port_config, port_config);
+
+       /* Unmap zone */
+       iounmap(gpio);
+
+}
+
+/* list of the supported boards */
+static char *board[] __initdata = {
+       "fsl,media5200",
+       NULL
+};
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init media5200_probe(void)
+{
+       unsigned long node = of_get_flat_dt_root();
+       int i = 0;
+
+       while (board[i]) {
+               if (of_flat_dt_is_compatible(node, board[i]))
+                       break;
+               i++;
+       }
+
+       return (board[i] != NULL);
+}
+
+define_machine(media5200_platform) {
+       .name           = "media5200-platform",
+       .probe          = media5200_probe,
+       .setup_arch     = media5200_setup_arch,
+       .init           = mpc52xx_declare_of_platform_devices,
+       .init_IRQ       = media5200_init_irq,
+       .get_irq        = mpc52xx_get_irq,
+       .restart        = mpc52xx_restart,
+       .calibrate_decr = generic_calibrate_decr,
+};
index a3bda0b9f1ff791fcb259699dba91f82fe61cc9a..c31e5b534f0aab0304a9d8dee70b5730dd8e5f81 100644 (file)
@@ -50,8 +50,10 @@ static void __init mpc5200_simple_setup_arch(void)
 
 /* list of the supported boards */
 static char *board[] __initdata = {
-       "promess,motionpro",
+       "intercontrol,digsy-mtc",
        "phytec,pcm030",
+       "phytec,pcm032",
+       "promess,motionpro",
        "schindler,cm5200",
        "tqc,tqm5200",
        NULL
index 98367a0255f34aee02c47b7d308ef7f03eaf6364..8e3dd5a0f228d67fc305731ebddf12fbe2f80b39 100644 (file)
@@ -28,9 +28,10 @@ static struct of_device_id mpc52xx_xlb_ids[] __initdata = {
 static struct of_device_id mpc52xx_bus_ids[] __initdata = {
        { .compatible = "fsl,mpc5200-immr", },
        { .compatible = "fsl,mpc5200b-immr", },
-       { .compatible = "fsl,lpb", },
+       { .compatible = "simple-bus", },
 
        /* depreciated matches; shouldn't be used in new device trees */
+       { .compatible = "fsl,lpb", },
        { .type = "builtin", .compatible = "mpc5200", }, /* efika */
        { .type = "soc", .compatible = "mpc5200", }, /* lite5200 */
        {}
@@ -204,6 +205,43 @@ int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv)
 }
 EXPORT_SYMBOL(mpc52xx_set_psc_clkdiv);
 
+/**
+ * mpc52xx_get_xtal_freq - Get SYS_XTAL_IN frequency for a device
+ *
+ * @node: device node
+ *
+ * Returns the frequency of the external oscillator clock connected
+ * to the SYS_XTAL_IN pin, or 0 if it cannot be determined.
+ */
+unsigned int mpc52xx_get_xtal_freq(struct device_node *node)
+{
+       u32 val;
+       unsigned int freq;
+
+       if (!mpc52xx_cdm)
+               return 0;
+
+       freq = mpc52xx_find_ipb_freq(node);
+       if (!freq)
+               return 0;
+
+       if (in_8(&mpc52xx_cdm->ipb_clk_sel) & 0x1)
+               freq *= 2;
+
+       val  = in_be32(&mpc52xx_cdm->rstcfg);
+       if (val & (1 << 5))
+               freq *= 8;
+       else
+               freq *= 4;
+       if (val & (1 << 6))
+               freq /= 12;
+       else
+               freq /= 16;
+
+       return freq;
+}
+EXPORT_SYMBOL(mpc52xx_get_xtal_freq);
+
 /**
  * mpc52xx_restart: ppc_md->restart hook for mpc5200 using the watchdog timer
  */
index 07f89ae46d04b1953bc9d1d45f6cce0cd5b844f0..2b8d8ef32e4eb2175fd822df0b942a35aebb24e4 100644 (file)
@@ -354,88 +354,6 @@ static struct of_platform_driver mpc52xx_simple_gpiochip_driver = {
        .remove = mpc52xx_gpiochip_remove,
 };
 
-/*
- * GPIO LIB API implementation for gpt GPIOs.
- *
- * Each gpt only has a single GPIO.
- */
-static int mpc52xx_gpt_gpio_get(struct gpio_chip *gc, unsigned int gpio)
-{
-       struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-       struct mpc52xx_gpt __iomem *regs = mm_gc->regs;
-
-       return (in_be32(&regs->status) & (1 << (31 - 23))) ? 1 : 0;
-}
-
-static void
-mpc52xx_gpt_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
-{
-       struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-       struct mpc52xx_gpt __iomem *regs = mm_gc->regs;
-
-       if (val)
-               out_be32(&regs->mode, 0x34);
-       else
-               out_be32(&regs->mode, 0x24);
-
-       pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
-}
-
-static int mpc52xx_gpt_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
-{
-       struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-       struct mpc52xx_gpt __iomem *regs = mm_gc->regs;
-
-       out_be32(&regs->mode, 0x04);
-
-       return 0;
-}
-
-static int
-mpc52xx_gpt_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
-{
-       mpc52xx_gpt_gpio_set(gc, gpio, val);
-       pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
-
-       return 0;
-}
-
-static int __devinit mpc52xx_gpt_gpiochip_probe(struct of_device *ofdev,
-                                       const struct of_device_id *match)
-{
-       struct of_mm_gpio_chip *mmchip;
-       struct of_gpio_chip *chip;
-
-       mmchip = kzalloc(sizeof(*mmchip), GFP_KERNEL);
-       if (!mmchip)
-               return -ENOMEM;
-
-       chip = &mmchip->of_gc;
-
-       chip->gpio_cells          = 2;
-       chip->gc.ngpio            = 1;
-       chip->gc.direction_input  = mpc52xx_gpt_gpio_dir_in;
-       chip->gc.direction_output = mpc52xx_gpt_gpio_dir_out;
-       chip->gc.get              = mpc52xx_gpt_gpio_get;
-       chip->gc.set              = mpc52xx_gpt_gpio_set;
-
-       return of_mm_gpiochip_add(ofdev->node, mmchip);
-}
-
-static const struct of_device_id mpc52xx_gpt_gpiochip_match[] = {
-       {
-               .compatible = "fsl,mpc5200-gpt-gpio",
-       },
-       {}
-};
-
-static struct of_platform_driver mpc52xx_gpt_gpiochip_driver = {
-       .name = "gpio_gpt",
-       .match_table = mpc52xx_gpt_gpiochip_match,
-       .probe = mpc52xx_gpt_gpiochip_probe,
-       .remove = mpc52xx_gpiochip_remove,
-};
-
 static int __init mpc52xx_gpio_init(void)
 {
        if (of_register_platform_driver(&mpc52xx_wkup_gpiochip_driver))
@@ -444,9 +362,6 @@ static int __init mpc52xx_gpio_init(void)
        if (of_register_platform_driver(&mpc52xx_simple_gpiochip_driver))
                printk(KERN_ERR "Unable to register simple GPIO driver\n");
 
-       if (of_register_platform_driver(&mpc52xx_gpt_gpiochip_driver))
-               printk(KERN_ERR "Unable to register gpt GPIO driver\n");
-
        return 0;
 }
 
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
new file mode 100644 (file)
index 0000000..bfbcd41
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * MPC5200 General Purpose Timer device driver
+ *
+ * Copyright (c) 2009 Secret Lab Technologies Ltd.
+ * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This file is a driver for the the General Purpose Timer (gpt) devices
+ * found on the MPC5200 SoC.  Each timer has an IO pin which can be used
+ * for GPIO or can be used to raise interrupts.  The timer function can
+ * be used independently from the IO pin, or it can be used to control
+ * output signals or measure input signals.
+ *
+ * This driver supports the GPIO and IRQ controller functions of the GPT
+ * device.  Timer functions are not yet supported, nor is the watchdog
+ * timer.
+ *
+ * To use the GPIO function, the following two properties must be added
+ * to the device tree node for the gpt device (typically in the .dts file
+ * for the board):
+ *     gpio-controller;
+ *     #gpio-cells = < 2 >;
+ * This driver will register the GPIO pin if it finds the gpio-controller
+ * property in the device tree.
+ *
+ * To use the IRQ controller function, the following two properties must
+ * be added to the device tree node for the gpt device:
+ *     interrupt-controller;
+ *     #interrupt-cells = < 1 >;
+ * The IRQ controller binding only uses one cell to specify the interrupt,
+ * and the IRQ flags are encoded in the cell.  A cell is not used to encode
+ * the IRQ number because the GPT only has a single IRQ source.  For flags,
+ * a value of '1' means rising edge sensitive and '2' means falling edge.
+ *
+ * The GPIO and the IRQ controller functions can be used at the same time,
+ * but in this use case the IO line will only work as an input.  Trying to
+ * use it as a GPIO output will not work.
+ *
+ * When using the GPIO line as an output, it can either be driven as normal
+ * IO, or it can be an Open Collector (OC) output.  At the moment it is the
+ * responsibility of either the bootloader or the platform setup code to set
+ * the output mode.  This driver does not change the output mode setting.
+ */
+
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/kernel.h>
+#include <asm/mpc52xx.h>
+
+MODULE_DESCRIPTION("Freescale MPC52xx gpt driver");
+MODULE_AUTHOR("Sascha Hauer, Grant Likely");
+MODULE_LICENSE("GPL");
+
+/**
+ * struct mpc52xx_gpt - Private data structure for MPC52xx GPT driver
+ * @dev: pointer to device structure
+ * @regs: virtual address of GPT registers
+ * @lock: spinlock to coordinate between different functions.
+ * @of_gc: of_gpio_chip instance structure; used when GPIO is enabled
+ * @irqhost: Pointer to irq_host instance; used when IRQ mode is supported
+ */
+struct mpc52xx_gpt_priv {
+       struct device *dev;
+       struct mpc52xx_gpt __iomem *regs;
+       spinlock_t lock;
+       struct irq_host *irqhost;
+
+#if defined(CONFIG_GPIOLIB)
+       struct of_gpio_chip of_gc;
+#endif
+};
+
+#define MPC52xx_GPT_MODE_MS_MASK       (0x07)
+#define MPC52xx_GPT_MODE_MS_IC         (0x01)
+#define MPC52xx_GPT_MODE_MS_OC         (0x02)
+#define MPC52xx_GPT_MODE_MS_PWM                (0x03)
+#define MPC52xx_GPT_MODE_MS_GPIO       (0x04)
+
+#define MPC52xx_GPT_MODE_GPIO_MASK     (0x30)
+#define MPC52xx_GPT_MODE_GPIO_OUT_LOW  (0x20)
+#define MPC52xx_GPT_MODE_GPIO_OUT_HIGH (0x30)
+
+#define MPC52xx_GPT_MODE_IRQ_EN                (0x0100)
+
+#define MPC52xx_GPT_MODE_ICT_MASK      (0x030000)
+#define MPC52xx_GPT_MODE_ICT_RISING    (0x010000)
+#define MPC52xx_GPT_MODE_ICT_FALLING   (0x020000)
+#define MPC52xx_GPT_MODE_ICT_TOGGLE    (0x030000)
+
+#define MPC52xx_GPT_STATUS_IRQMASK     (0x000f)
+
+/* ---------------------------------------------------------------------
+ * Cascaded interrupt controller hooks
+ */
+
+static void mpc52xx_gpt_irq_unmask(unsigned int virq)
+{
+       struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq);
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpt->lock, flags);
+       setbits32(&gpt->regs->mode, MPC52xx_GPT_MODE_IRQ_EN);
+       spin_unlock_irqrestore(&gpt->lock, flags);
+}
+
+static void mpc52xx_gpt_irq_mask(unsigned int virq)
+{
+       struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq);
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpt->lock, flags);
+       clrbits32(&gpt->regs->mode, MPC52xx_GPT_MODE_IRQ_EN);
+       spin_unlock_irqrestore(&gpt->lock, flags);
+}
+
+static void mpc52xx_gpt_irq_ack(unsigned int virq)
+{
+       struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq);
+
+       out_be32(&gpt->regs->status, MPC52xx_GPT_STATUS_IRQMASK);
+}
+
+static int mpc52xx_gpt_irq_set_type(unsigned int virq, unsigned int flow_type)
+{
+       struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq);
+       unsigned long flags;
+       u32 reg;
+
+       dev_dbg(gpt->dev, "%s: virq=%i type=%x\n", __func__, virq, flow_type);
+
+       spin_lock_irqsave(&gpt->lock, flags);
+       reg = in_be32(&gpt->regs->mode) & ~MPC52xx_GPT_MODE_ICT_MASK;
+       if (flow_type & IRQF_TRIGGER_RISING)
+               reg |= MPC52xx_GPT_MODE_ICT_RISING;
+       if (flow_type & IRQF_TRIGGER_FALLING)
+               reg |= MPC52xx_GPT_MODE_ICT_FALLING;
+       out_be32(&gpt->regs->mode, reg);
+       spin_unlock_irqrestore(&gpt->lock, flags);
+
+       return 0;
+}
+
+static struct irq_chip mpc52xx_gpt_irq_chip = {
+       .typename = "MPC52xx GPT",
+       .unmask = mpc52xx_gpt_irq_unmask,
+       .mask = mpc52xx_gpt_irq_mask,
+       .ack = mpc52xx_gpt_irq_ack,
+       .set_type = mpc52xx_gpt_irq_set_type,
+};
+
+void mpc52xx_gpt_irq_cascade(unsigned int virq, struct irq_desc *desc)
+{
+       struct mpc52xx_gpt_priv *gpt = get_irq_data(virq);
+       int sub_virq;
+       u32 status;
+
+       status = in_be32(&gpt->regs->status) & MPC52xx_GPT_STATUS_IRQMASK;
+       if (status) {
+               sub_virq = irq_linear_revmap(gpt->irqhost, 0);
+               generic_handle_irq(sub_virq);
+       }
+}
+
+static int mpc52xx_gpt_irq_map(struct irq_host *h, unsigned int virq,
+                              irq_hw_number_t hw)
+{
+       struct mpc52xx_gpt_priv *gpt = h->host_data;
+
+       dev_dbg(gpt->dev, "%s: h=%p, virq=%i\n", __func__, h, virq);
+       set_irq_chip_data(virq, gpt);
+       set_irq_chip_and_handler(virq, &mpc52xx_gpt_irq_chip, handle_edge_irq);
+
+       return 0;
+}
+
+static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct,
+                                u32 *intspec, unsigned int intsize,
+                                irq_hw_number_t *out_hwirq,
+                                unsigned int *out_flags)
+{
+       struct mpc52xx_gpt_priv *gpt = h->host_data;
+
+       dev_dbg(gpt->dev, "%s: flags=%i\n", __func__, intspec[0]);
+
+       if ((intsize < 1) || (intspec[0] < 1) || (intspec[0] > 3)) {
+               dev_err(gpt->dev, "bad irq specifier in %s\n", ct->full_name);
+               return -EINVAL;
+       }
+
+       *out_hwirq = 0; /* The GPT only has 1 IRQ line */
+       *out_flags = intspec[0];
+
+       return 0;
+}
+
+static struct irq_host_ops mpc52xx_gpt_irq_ops = {
+       .map = mpc52xx_gpt_irq_map,
+       .xlate = mpc52xx_gpt_irq_xlate,
+};
+
+static void
+mpc52xx_gpt_irq_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node)
+{
+       int cascade_virq;
+       unsigned long flags;
+
+       /* Only setup cascaded IRQ if device tree claims the GPT is
+        * an interrupt controller */
+       if (!of_find_property(node, "interrupt-controller", NULL))
+               return;
+
+       cascade_virq = irq_of_parse_and_map(node, 0);
+
+       gpt->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, 1,
+                                     &mpc52xx_gpt_irq_ops, -1);
+       if (!gpt->irqhost) {
+               dev_err(gpt->dev, "irq_alloc_host() failed\n");
+               return;
+       }
+
+       gpt->irqhost->host_data = gpt;
+
+       set_irq_data(cascade_virq, gpt);
+       set_irq_chained_handler(cascade_virq, mpc52xx_gpt_irq_cascade);
+
+       /* Set to Input Capture mode */
+       spin_lock_irqsave(&gpt->lock, flags);
+       clrsetbits_be32(&gpt->regs->mode, MPC52xx_GPT_MODE_MS_MASK,
+                       MPC52xx_GPT_MODE_MS_IC);
+       spin_unlock_irqrestore(&gpt->lock, flags);
+
+       dev_dbg(gpt->dev, "%s() complete. virq=%i\n", __func__, cascade_virq);
+}
+
+
+/* ---------------------------------------------------------------------
+ * GPIOLIB hooks
+ */
+#if defined(CONFIG_GPIOLIB)
+static inline struct mpc52xx_gpt_priv *gc_to_mpc52xx_gpt(struct gpio_chip *gc)
+{
+       return container_of(to_of_gpio_chip(gc), struct mpc52xx_gpt_priv,of_gc);
+}
+
+static int mpc52xx_gpt_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+       struct mpc52xx_gpt_priv *gpt = gc_to_mpc52xx_gpt(gc);
+
+       return (in_be32(&gpt->regs->status) >> 8) & 1;
+}
+
+static void
+mpc52xx_gpt_gpio_set(struct gpio_chip *gc, unsigned int gpio, int v)
+{
+       struct mpc52xx_gpt_priv *gpt = gc_to_mpc52xx_gpt(gc);
+       unsigned long flags;
+       u32 r;
+
+       dev_dbg(gpt->dev, "%s: gpio:%d v:%d\n", __func__, gpio, v);
+       r = v ? MPC52xx_GPT_MODE_GPIO_OUT_HIGH : MPC52xx_GPT_MODE_GPIO_OUT_LOW;
+
+       spin_lock_irqsave(&gpt->lock, flags);
+       clrsetbits_be32(&gpt->regs->mode, MPC52xx_GPT_MODE_GPIO_MASK, r);
+       spin_unlock_irqrestore(&gpt->lock, flags);
+}
+
+static int mpc52xx_gpt_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+       struct mpc52xx_gpt_priv *gpt = gc_to_mpc52xx_gpt(gc);
+       unsigned long flags;
+
+       dev_dbg(gpt->dev, "%s: gpio:%d\n", __func__, gpio);
+
+       spin_lock_irqsave(&gpt->lock, flags);
+       clrbits32(&gpt->regs->mode, MPC52xx_GPT_MODE_GPIO_MASK);
+       spin_unlock_irqrestore(&gpt->lock, flags);
+
+       return 0;
+}
+
+static int
+mpc52xx_gpt_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+       mpc52xx_gpt_gpio_set(gc, gpio, val);
+       return 0;
+}
+
+static void
+mpc52xx_gpt_gpio_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node)
+{
+       int rc;
+
+       /* Only setup GPIO if the device tree claims the GPT is
+        * a GPIO controller */
+       if (!of_find_property(node, "gpio-controller", NULL))
+               return;
+
+       gpt->of_gc.gc.label = kstrdup(node->full_name, GFP_KERNEL);
+       if (!gpt->of_gc.gc.label) {
+               dev_err(gpt->dev, "out of memory\n");
+               return;
+       }
+
+       gpt->of_gc.gpio_cells = 2;
+       gpt->of_gc.gc.ngpio = 1;
+       gpt->of_gc.gc.direction_input  = mpc52xx_gpt_gpio_dir_in;
+       gpt->of_gc.gc.direction_output = mpc52xx_gpt_gpio_dir_out;
+       gpt->of_gc.gc.get = mpc52xx_gpt_gpio_get;
+       gpt->of_gc.gc.set = mpc52xx_gpt_gpio_set;
+       gpt->of_gc.gc.base = -1;
+       gpt->of_gc.xlate = of_gpio_simple_xlate;
+       node->data = &gpt->of_gc;
+       of_node_get(node);
+
+       /* Setup external pin in GPIO mode */
+       clrsetbits_be32(&gpt->regs->mode, MPC52xx_GPT_MODE_MS_MASK,
+                       MPC52xx_GPT_MODE_MS_GPIO);
+
+       rc = gpiochip_add(&gpt->of_gc.gc);
+       if (rc)
+               dev_err(gpt->dev, "gpiochip_add() failed; rc=%i\n", rc);
+
+       dev_dbg(gpt->dev, "%s() complete.\n", __func__);
+}
+#else /* defined(CONFIG_GPIOLIB) */
+static void
+mpc52xx_gpt_gpio_setup(struct mpc52xx_gpt_priv *p, struct device_node *np) { }
+#endif /* defined(CONFIG_GPIOLIB) */
+
+/* ---------------------------------------------------------------------
+ * of_platform bus binding code
+ */
+static int __devinit mpc52xx_gpt_probe(struct of_device *ofdev,
+                                      const struct of_device_id *match)
+{
+       struct mpc52xx_gpt_priv *gpt;
+
+       gpt = kzalloc(sizeof *gpt, GFP_KERNEL);
+       if (!gpt)
+               return -ENOMEM;
+
+       spin_lock_init(&gpt->lock);
+       gpt->dev = &ofdev->dev;
+       gpt->regs = of_iomap(ofdev->node, 0);
+       if (!gpt->regs) {
+               kfree(gpt);
+               return -ENOMEM;
+       }
+
+       dev_set_drvdata(&ofdev->dev, gpt);
+
+       mpc52xx_gpt_gpio_setup(gpt, ofdev->node);
+       mpc52xx_gpt_irq_setup(gpt, ofdev->node);
+
+       return 0;
+}
+
+static int mpc52xx_gpt_remove(struct of_device *ofdev)
+{
+       return -EBUSY;
+}
+
+static const struct of_device_id mpc52xx_gpt_match[] = {
+       { .compatible = "fsl,mpc5200-gpt", },
+
+       /* Depreciated compatible values; don't use for new dts files */
+       { .compatible = "fsl,mpc5200-gpt-gpio", },
+       { .compatible = "mpc5200-gpt", },
+       {}
+};
+
+static struct of_platform_driver mpc52xx_gpt_driver = {
+       .name = "mpc52xx-gpt",
+       .match_table = mpc52xx_gpt_match,
+       .probe = mpc52xx_gpt_probe,
+       .remove = mpc52xx_gpt_remove,
+};
+
+static int __init mpc52xx_gpt_init(void)
+{
+       if (of_register_platform_driver(&mpc52xx_gpt_driver))
+               pr_err("error registering MPC52xx GPT driver\n");
+
+       return 0;
+}
+
+/* Make sure GPIOs and IRQs get set up before anyone tries to use them */
+subsys_initcall(mpc52xx_gpt_init);
index 0a093f03c75898ca6b4c1b4e7943d2dc7759819f..480f806fd0a9ce0f2818aecd4cb795ed8ab4610f 100644 (file)
@@ -163,8 +163,6 @@ static void mpc52xx_extirq_mask(unsigned int virq)
        irq = irq_map[virq].hwirq;
        l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
-       pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
-
        io_be_clrbit(&intr->ctrl, 11 - l2irq);
 }
 
@@ -176,8 +174,6 @@ static void mpc52xx_extirq_unmask(unsigned int virq)
        irq = irq_map[virq].hwirq;
        l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
-       pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
-
        io_be_setbit(&intr->ctrl, 11 - l2irq);
 }
 
@@ -189,17 +185,15 @@ static void mpc52xx_extirq_ack(unsigned int virq)
        irq = irq_map[virq].hwirq;
        l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
-       pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
-
        io_be_setbit(&intr->ctrl, 27-l2irq);
 }
 
 static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type)
 {
-       struct irq_desc *desc = get_irq_desc(virq);
        u32 ctrl_reg, type;
        int irq;
        int l2irq;
+       void *handler = handle_level_irq;
 
        irq = irq_map[virq].hwirq;
        l2irq = irq & MPC52xx_IRQ_L2_MASK;
@@ -207,32 +201,21 @@ static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type)
        pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, irq, l2irq, flow_type);
 
        switch (flow_type) {
-       case IRQF_TRIGGER_HIGH:
-               type = 0;
-               break;
-       case IRQF_TRIGGER_RISING:
-               type = 1;
-               break;
-       case IRQF_TRIGGER_FALLING:
-               type = 2;
-               break;
-       case IRQF_TRIGGER_LOW:
-               type = 3;
-               break;
+       case IRQF_TRIGGER_HIGH: type = 0; break;
+       case IRQF_TRIGGER_RISING: type = 1; handler = handle_edge_irq; break;
+       case IRQF_TRIGGER_FALLING: type = 2; handler = handle_edge_irq; break;
+       case IRQF_TRIGGER_LOW: type = 3; break;
        default:
                type = 0;
        }
 
-       desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
-       desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
-       if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
-               desc->status |= IRQ_LEVEL;
-
        ctrl_reg = in_be32(&intr->ctrl);
        ctrl_reg &= ~(0x3 << (22 - (l2irq * 2)));
        ctrl_reg |= (type << (22 - (l2irq * 2)));
        out_be32(&intr->ctrl, ctrl_reg);
 
+       __set_irq_handler_unlocked(virq, handler);
+
        return 0;
 }
 
@@ -247,6 +230,11 @@ static struct irq_chip mpc52xx_extirq_irqchip = {
 /*
  * Main interrupt irq_chip
  */
+static int mpc52xx_null_set_type(unsigned int virq, unsigned int flow_type)
+{
+       return 0; /* Do nothing so that the sense mask will get updated */
+}
+
 static void mpc52xx_main_mask(unsigned int virq)
 {
        int irq;
@@ -255,8 +243,6 @@ static void mpc52xx_main_mask(unsigned int virq)
        irq = irq_map[virq].hwirq;
        l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
-       pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
-
        io_be_setbit(&intr->main_mask, 16 - l2irq);
 }
 
@@ -268,8 +254,6 @@ static void mpc52xx_main_unmask(unsigned int virq)
        irq = irq_map[virq].hwirq;
        l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
-       pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
-
        io_be_clrbit(&intr->main_mask, 16 - l2irq);
 }
 
@@ -278,6 +262,7 @@ static struct irq_chip mpc52xx_main_irqchip = {
        .mask = mpc52xx_main_mask,
        .mask_ack = mpc52xx_main_mask,
        .unmask = mpc52xx_main_unmask,
+       .set_type = mpc52xx_null_set_type,
 };
 
 /*
@@ -291,8 +276,6 @@ static void mpc52xx_periph_mask(unsigned int virq)
        irq = irq_map[virq].hwirq;
        l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
-       pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
-
        io_be_setbit(&intr->per_mask, 31 - l2irq);
 }
 
@@ -304,8 +287,6 @@ static void mpc52xx_periph_unmask(unsigned int virq)
        irq = irq_map[virq].hwirq;
        l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
-       pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
-
        io_be_clrbit(&intr->per_mask, 31 - l2irq);
 }
 
@@ -314,6 +295,7 @@ static struct irq_chip mpc52xx_periph_irqchip = {
        .mask = mpc52xx_periph_mask,
        .mask_ack = mpc52xx_periph_mask,
        .unmask = mpc52xx_periph_unmask,
+       .set_type = mpc52xx_null_set_type,
 };
 
 /*
@@ -327,8 +309,6 @@ static void mpc52xx_sdma_mask(unsigned int virq)
        irq = irq_map[virq].hwirq;
        l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
-       pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
-
        io_be_setbit(&sdma->IntMask, l2irq);
 }
 
@@ -340,8 +320,6 @@ static void mpc52xx_sdma_unmask(unsigned int virq)
        irq = irq_map[virq].hwirq;
        l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
-       pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
-
        io_be_clrbit(&sdma->IntMask, l2irq);
 }
 
@@ -353,8 +331,6 @@ static void mpc52xx_sdma_ack(unsigned int virq)
        irq = irq_map[virq].hwirq;
        l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
-       pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
-
        out_be32(&sdma->IntPend, 1 << l2irq);
 }
 
@@ -363,8 +339,18 @@ static struct irq_chip mpc52xx_sdma_irqchip = {
        .mask = mpc52xx_sdma_mask,
        .unmask = mpc52xx_sdma_unmask,
        .ack = mpc52xx_sdma_ack,
+       .set_type = mpc52xx_null_set_type,
 };
 
+/**
+ * mpc52xx_is_extirq - Returns true if hwirq number is for an external IRQ
+ */
+static int mpc52xx_is_extirq(int l1, int l2)
+{
+       return ((l1 == 0) && (l2 == 0)) ||
+              ((l1 == 1) && (l2 >= 1) && (l2 <= 3));
+}
+
 /**
  * mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property
  */
@@ -383,37 +369,22 @@ static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,
 
        intrvect_l1 = (int)intspec[0];
        intrvect_l2 = (int)intspec[1];
-       intrvect_type = (int)intspec[2];
+       intrvect_type = (int)intspec[2] & 0x3;
 
        intrvect_linux = (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) &
                         MPC52xx_IRQ_L1_MASK;
        intrvect_linux |= intrvect_l2 & MPC52xx_IRQ_L2_MASK;
 
-       pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1,
-                intrvect_l2);
-
        *out_hwirq = intrvect_linux;
-       *out_flags = mpc52xx_map_senses[intrvect_type];
+       *out_flags = IRQ_TYPE_LEVEL_LOW;
+       if (mpc52xx_is_extirq(intrvect_l1, intrvect_l2))
+               *out_flags = mpc52xx_map_senses[intrvect_type];
 
+       pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1,
+                intrvect_l2);
        return 0;
 }
 
-/**
- * mpc52xx_irqx_gettype - determine the IRQ sense type (level/edge)
- *
- * Only external IRQs need this.
- */
-static int mpc52xx_irqx_gettype(int irq)
-{
-       int type;
-       u32 ctrl_reg;
-
-       ctrl_reg = in_be32(&intr->ctrl);
-       type = (ctrl_reg >> (22 - irq * 2)) & 0x3;
-
-       return mpc52xx_map_senses[type];
-}
-
 /**
  * mpc52xx_irqhost_map - Hook to map from virq to an irq_chip structure
  */
@@ -422,68 +393,46 @@ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,
 {
        int l1irq;
        int l2irq;
-       struct irq_chip *good_irqchip;
-       void *good_handle;
+       struct irq_chip *irqchip;
+       void *hndlr;
        int type;
+       u32 reg;
 
        l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET;
        l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
        /*
-        * Most of ours IRQs will be level low
-        * Only external IRQs on some platform may be others
+        * External IRQs are handled differently by the hardware so they are
+        * handled by a dedicated irq_chip structure.
         */
-       type = IRQ_TYPE_LEVEL_LOW;
+       if (mpc52xx_is_extirq(l1irq, l2irq)) {
+               reg = in_be32(&intr->ctrl);
+               type = mpc52xx_map_senses[(reg >> (22 - l2irq * 2)) & 0x3];
+               if ((type == IRQ_TYPE_EDGE_FALLING) ||
+                   (type == IRQ_TYPE_EDGE_RISING))
+                       hndlr = handle_edge_irq;
+               else
+                       hndlr = handle_level_irq;
+
+               set_irq_chip_and_handler(virq, &mpc52xx_extirq_irqchip, hndlr);
+               pr_debug("%s: External IRQ%i virq=%x, hw=%x. type=%x\n",
+                        __func__, l2irq, virq, (int)irq, type);
+               return 0;
+       }
 
+       /* It is an internal SOC irq.  Choose the correct irq_chip */
        switch (l1irq) {
-       case MPC52xx_IRQ_L1_CRIT:
-               pr_debug("%s: Critical. l2=%x\n", __func__, l2irq);
-
-               BUG_ON(l2irq != 0);
-
-               type = mpc52xx_irqx_gettype(l2irq);
-               good_irqchip = &mpc52xx_extirq_irqchip;
-               break;
-
-       case MPC52xx_IRQ_L1_MAIN:
-               pr_debug("%s: Main IRQ[1-3] l2=%x\n", __func__, l2irq);
-
-               if ((l2irq >= 1) && (l2irq <= 3)) {
-                       type = mpc52xx_irqx_gettype(l2irq);
-                       good_irqchip = &mpc52xx_extirq_irqchip;
-               } else {
-                       good_irqchip = &mpc52xx_main_irqchip;
-               }
-               break;
-
-       case MPC52xx_IRQ_L1_PERP:
-               pr_debug("%s: Peripherals. l2=%x\n", __func__, l2irq);
-               good_irqchip = &mpc52xx_periph_irqchip;
-               break;
-
-       case MPC52xx_IRQ_L1_SDMA:
-               pr_debug("%s: SDMA. l2=%x\n", __func__, l2irq);
-               good_irqchip = &mpc52xx_sdma_irqchip;
-               break;
-
+       case MPC52xx_IRQ_L1_MAIN: irqchip = &mpc52xx_main_irqchip; break;
+       case MPC52xx_IRQ_L1_PERP: irqchip = &mpc52xx_periph_irqchip; break;
+       case MPC52xx_IRQ_L1_SDMA: irqchip = &mpc52xx_sdma_irqchip; break;
        default:
-               pr_err("%s: invalid virq requested (0x%x)\n", __func__, virq);
+               pr_err("%s: invalid irq: virq=%i, l1=%i, l2=%i\n",
+                      __func__, virq, l1irq, l2irq);
                return -EINVAL;
        }
 
-       switch (type) {
-       case IRQ_TYPE_EDGE_FALLING:
-       case IRQ_TYPE_EDGE_RISING:
-               good_handle = handle_edge_irq;
-               break;
-       default:
-               good_handle = handle_level_irq;
-       }
-
-       set_irq_chip_and_handler(virq, good_irqchip, good_handle);
-
-       pr_debug("%s: virq=%x, hw=%x. type=%x\n", __func__, virq,
-                (int)irq, type);
+       set_irq_chip_and_handler(virq, irqchip, handle_level_irq);
+       pr_debug("%s: virq=%x, l1=%i, l2=%i\n", __func__, virq, l1irq, l2irq);
 
        return 0;
 }
@@ -522,6 +471,8 @@ void __init mpc52xx_init_irq(void)
                panic(__FILE__  ": find_and_map failed on 'mpc5200-bestcomm'. "
                                "Check node !");
 
+       pr_debug("MPC5200 IRQ controller mapped to 0x%p\n", intr);
+
        /* Disable all interrupt sources. */
        out_be32(&sdma->IntPend, 0xffffffff);   /* 1 means clear pending */
        out_be32(&sdma->IntMask, 0xffffffff);   /* 1 means disabled */
@@ -613,8 +564,5 @@ unsigned int mpc52xx_get_irq(void)
                }
        }
 
-       pr_debug("%s: irq=%x. virq=%d\n", __func__, irq,
-                irq_linear_revmap(mpc52xx_irqhost, irq));
-
        return irq_linear_revmap(mpc52xx_irqhost, irq);
 }
index 30f008b2f92e825f64cd518defc8bab99a9bb892..7c7df40038207b28ca1eaeb745ad725689cc400a 100644 (file)
@@ -1,6 +1,6 @@
 menuconfig PPC_82xx
        bool "82xx-based boards (PQ II)"
-       depends on 6xx && PPC_MULTIPLATFORM
+       depends on 6xx
 
 if PPC_82xx
 
index 83c664afc897c76023d65e7e4b231e9fa26c0310..437d29a59d725c379569253b4ef400bae1734287 100644 (file)
@@ -1,6 +1,6 @@
 menuconfig PPC_83xx
        bool "83xx-based boards"
-       depends on 6xx && PPC_MULTIPLATFORM
+       depends on 6xx
        select PPC_UDBG_16550
        select PPC_PCI_CHOICE
        select FSL_PCI if PCI
index bb30d67ad0a28dfd2aa86a75114f402a6e368445..aa0d84d22585639bf5f42d22416305180450e844 100644 (file)
@@ -58,6 +58,7 @@ static struct __initdata of_device_id asp8347_ids[] = {
        { .type = "soc", },
        { .compatible = "soc", },
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index 91a2c80b9d72902cb5a23bbdc16214c261586137..0b4f883b20eb05684c2da893d636ab3d9014daf9 100644 (file)
@@ -38,6 +38,8 @@ static void __init mpc831x_rdb_setup_arch(void)
 #ifdef CONFIG_PCI
        for_each_compatible_node(np, "pci", "fsl,mpc8349-pci")
                mpc83xx_add_bridge(np);
+       for_each_compatible_node(np, "pci", "fsl,mpc8314-pcie")
+               mpc83xx_add_bridge(np);
 #endif
        mpc831x_usb_cfg();
 }
index 2a1295f1983254c7a4083b65b83694ef83bf6129..567ded7c3b9be5fc3689be002e3e6163cdce3e8f 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/spi/mmc_spi.h>
 #include <linux/mmc/host.h>
 #include <linux/of_platform.h>
+#include <linux/fsl_devices.h>
 
 #include <asm/time.h>
 #include <asm/ipic.h>
 #endif
 
 #ifdef CONFIG_QUICC_ENGINE
-static void mpc83xx_spi_activate_cs(u8 cs, u8 polarity)
+static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk,
+                                  struct spi_board_info *board_infos,
+                                  unsigned int num_board_infos,
+                                  void (*cs_control)(struct spi_device *dev,
+                                                     bool on))
 {
-       pr_debug("%s %d %d\n", __func__, cs, polarity);
-       par_io_data_set(3, 13, polarity);
+       struct device_node *np;
+       unsigned int i = 0;
+
+       for_each_compatible_node(np, type, compatible) {
+               int ret;
+               unsigned int j;
+               const void *prop;
+               struct resource res[2];
+               struct platform_device *pdev;
+               struct fsl_spi_platform_data pdata = {
+                       .cs_control = cs_control,
+               };
+
+               memset(res, 0, sizeof(res));
+
+               pdata.sysclk = sysclk;
+
+               prop = of_get_property(np, "reg", NULL);
+               if (!prop)
+                       goto err;
+               pdata.bus_num = *(u32 *)prop;
+
+               prop = of_get_property(np, "cell-index", NULL);
+               if (prop)
+                       i = *(u32 *)prop;
+
+               prop = of_get_property(np, "mode", NULL);
+               if (prop && !strcmp(prop, "cpu-qe"))
+                       pdata.qe_mode = 1;
+
+               for (j = 0; j < num_board_infos; j++) {
+                       if (board_infos[j].bus_num == pdata.bus_num)
+                               pdata.max_chipselect++;
+               }
+
+               if (!pdata.max_chipselect)
+                       continue;
+
+               ret = of_address_to_resource(np, 0, &res[0]);
+               if (ret)
+                       goto err;
+
+               ret = of_irq_to_resource(np, 0, &res[1]);
+               if (ret == NO_IRQ)
+                       goto err;
+
+               pdev = platform_device_alloc("mpc83xx_spi", i);
+               if (!pdev)
+                       goto err;
+
+               ret = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+               if (ret)
+                       goto unreg;
+
+               ret = platform_device_add_resources(pdev, res,
+                                                   ARRAY_SIZE(res));
+               if (ret)
+                       goto unreg;
+
+               ret = platform_device_add(pdev);
+               if (ret)
+                       goto unreg;
+
+               goto next;
+unreg:
+               platform_device_del(pdev);
+err:
+               pr_err("%s: registration failed\n", np->full_name);
+next:
+               i++;
+       }
+
+       return i;
 }
 
-static void mpc83xx_spi_deactivate_cs(u8 cs, u8 polarity)
+static int __init fsl_spi_init(struct spi_board_info *board_infos,
+                              unsigned int num_board_infos,
+                              void (*cs_control)(struct spi_device *spi,
+                                                 bool on))
 {
-       pr_debug("%s %d %d\n", __func__, cs, polarity);
-       par_io_data_set(3, 13, !polarity);
+       u32 sysclk = -1;
+       int ret;
+
+       /* SPI controller is either clocked from QE or SoC clock */
+       sysclk = get_brgfreq();
+       if (sysclk == -1) {
+               sysclk = fsl_get_sys_freq();
+               if (sysclk == -1)
+                       return -ENODEV;
+       }
+
+       ret = of_fsl_spi_probe(NULL, "fsl,spi", sysclk, board_infos,
+                              num_board_infos, cs_control);
+       if (!ret)
+               of_fsl_spi_probe("spi", "fsl_spi", sysclk, board_infos,
+                                num_board_infos, cs_control);
+
+       return spi_register_board_info(board_infos, num_board_infos);
+}
+
+static void mpc83xx_spi_cs_control(struct spi_device *spi, bool on)
+{
+       pr_debug("%s %d %d\n", __func__, spi->chip_select, on);
+       par_io_data_set(3, 13, on);
 }
 
 static struct mmc_spi_platform_data mpc832x_mmc_pdata = {
@@ -74,9 +175,13 @@ static int __init mpc832x_spi_init(void)
        par_io_config_pin(3, 14, 2, 0, 0, 0); /* SD_INSERT, I */
        par_io_config_pin(3, 15, 2, 0, 0, 0); /* SD_PROTECT,I */
 
-       return fsl_spi_init(&mpc832x_spi_boardinfo, 1,
-                           mpc83xx_spi_activate_cs,
-                           mpc83xx_spi_deactivate_cs);
+       /*
+        * Don't bother with legacy stuff when device tree contains
+        * mmc-spi-slot node.
+        */
+       if (of_find_compatible_node(NULL, NULL, "mmc-spi-slot"))
+               return 0;
+       return fsl_spi_init(&mpc832x_spi_boardinfo, 1, mpc83xx_spi_cs_control);
 }
 machine_device_initcall(mpc832x_rdb, mpc832x_spi_init);
 #endif /* CONFIG_QUICC_ENGINE */
index 76092d37c7d901fdf9cc713a98d21873f8060bff..81e44fa1c644bb00b34bc9d5a055708eb9c2feb0 100644 (file)
@@ -42,6 +42,7 @@
 static struct of_device_id __initdata mpc834x_itx_ids[] = {
        { .compatible = "fsl,pq2pro-localbus", },
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index fc3f2ed1f3e927c722d5243956c6304fe6940f91..d0a634b056ca549040d79f0112de75e6062dbadf 100644 (file)
@@ -112,6 +112,7 @@ static struct of_device_id mpc834x_ids[] = {
        { .type = "soc", },
        { .compatible = "soc", },
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index 530ef990ca7c778ff72cb2bc2342498d594da407..51df7e7546985b044893a6380fcd748588c978dc 100644 (file)
@@ -84,14 +84,10 @@ static void __init mpc837x_mds_setup_arch(void)
                ppc_md.progress("mpc837x_mds_setup_arch()", 0);
 
 #ifdef CONFIG_PCI
-       for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") {
-               if (!of_device_is_available(np)) {
-                       pr_warning("%s: disabled by the firmware.\n",
-                                  np->full_name);
-                       continue;
-               }
+       for_each_compatible_node(np, "pci", "fsl,mpc8349-pci")
+               mpc83xx_add_bridge(np);
+       for_each_compatible_node(np, "pci", "fsl,mpc8314-pcie")
                mpc83xx_add_bridge(np);
-       }
 #endif
        mpc837xmds_usb_cfg();
 }
@@ -100,6 +96,7 @@ static struct of_device_id mpc837x_ids[] = {
        { .type = "soc", },
        { .compatible = "soc", },
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index 1d096545322b04ceecdbec07088affb82d92aa9c..76f3b32a155ed4c9da1bf7a99d95d7629fe26ea3 100644 (file)
@@ -38,6 +38,8 @@ static void __init mpc837x_rdb_setup_arch(void)
 #ifdef CONFIG_PCI
        for_each_compatible_node(np, "pci", "fsl,mpc8349-pci")
                mpc83xx_add_bridge(np);
+       for_each_compatible_node(np, "pci", "fsl,mpc8314-pcie")
+               mpc83xx_add_bridge(np);
 #endif
        mpc837x_usb_cfg();
 }
@@ -46,6 +48,7 @@ static struct of_device_id mpc837x_ids[] = {
        { .type = "soc", },
        { .compatible = "soc", },
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index 156c4e21800993b63f2c32de5625011e603620b6..49023dbe15763c9188f7ffb73f7e8341137bfaa8 100644 (file)
@@ -84,6 +84,7 @@ static struct __initdata of_device_id sbc834x_ids[] = {
        { .type = "soc", },
        { .compatible = "soc", },
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index cc99c280aad943ea93631a51de1399db5a90565a..11e1fac17c7ffff030aeba316051c062bafd0da4 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/of.h>
 
 #include <asm/io.h>
 #include <asm/prom.h>
@@ -210,7 +211,7 @@ int mpc837x_usb_cfg(void)
        int ret = 0;
 
        np = of_find_compatible_node(NULL, NULL, "fsl-usb2-dr");
-       if (!np)
+       if (!np || !of_device_is_available(np))
                return -ENODEV;
        prop = of_get_property(np, "phy_type", NULL);
 
index b79dc710ed346483d8201a68984fe06cfecb6dbe..7f066adc068cba54149af23479ce091bed8b61d4 100644 (file)
@@ -51,6 +51,12 @@ config MPC85xx_DS
        help
          This option enables support for the MPC85xx DS (MPC8544 DS) board
 
+config SOCRATES
+       bool "Socrates"
+       select DEFAULT_UIMAGE
+       help
+         This option enables support for the Socrates board.
+
 config KSI8560
         bool "Emerson KSI8560"
         select DEFAULT_UIMAGE
index f0798c09980fe340e3431bc70e226fa67c9dc128..a857b35b9828604b6869181e53e582f72feb078c 100644 (file)
@@ -13,4 +13,5 @@ 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
index 81cee7bbf2d231b2a35bdc963e7e7df71b79d2b3..f4d36b5a2e0099650d2b718fbbb3cf73fecdd90c 100644 (file)
@@ -106,8 +106,6 @@ static void __init ksi8560_pic_init(void)
        cpm2_pic_init(np);
        of_node_put(np);
        set_irq_chained_handler(irq, cpm2_cascade);
-
-       setup_irq(0, NULL);
 #endif
 }
 
@@ -221,6 +219,7 @@ static struct of_device_id __initdata of_bus_ids[] = {
        { .type = "simple-bus", },
        { .name = "cpm", },
        { .name = "localbus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index 1bf5aefdfeb1e0df594cc4c0dc822a13c9241492..63efca20d7bd12d0de6d143f02b227d290209efc 100644 (file)
@@ -92,6 +92,7 @@ static struct of_device_id __initdata mpc8536_ds_ids[] = {
        { .type = "soc", },
        { .compatible = "soc", },
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index 21f009023e2611b4b98c4ac06eff94da05b44eef..9438a892afc4c152992a3498bf9f006a9a55b996 100644 (file)
@@ -226,6 +226,7 @@ static struct of_device_id __initdata of_bus_ids[] = {
        { .name = "cpm", },
        { .name = "localbus", },
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index aeb6a5bc55222a26ed4333cb503adf7f0cfc3846..458d91fba91d5f80ba7296c55752b0960eaca11d 100644 (file)
@@ -179,7 +179,6 @@ static irqreturn_t mpc85xx_8259_cascade_action(int irq, void *dev_id)
 static struct irqaction mpc85xxcds_8259_irqaction = {
        .handler = mpc85xx_8259_cascade_action,
        .flags = IRQF_SHARED,
-       .mask = CPU_MASK_NONE,
        .name = "8259 cascade",
 };
 #endif /* PPC_I8259 */
@@ -336,6 +335,7 @@ static struct of_device_id __initdata of_bus_ids[] = {
        { .type = "soc", },
        { .compatible = "soc", },
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index 7326d904202c1e8ec8bac7e6a52382a3e141b51d..de66de7a9ca2876a7bd27bd27e619cceac36c0ec 100644 (file)
@@ -204,6 +204,7 @@ static struct of_device_id __initdata mpc85xxds_ids[] = {
        { .type = "soc", },
        { .compatible = "soc", },
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index 658a36fab3ab8a44c9963d5c6512b8e7d20d437a..7dd029034aec78e57338c54b10e42fae0550da42 100644 (file)
@@ -265,6 +265,7 @@ static struct of_device_id mpc85xx_ids[] = {
        { .compatible = "simple-bus", },
        { .type = "qe", },
        { .compatible = "fsl,qe", },
+       { .compatible = "gianfar", },
        {},
 };
 
index 7ec77ce12dadb632f912eac544e7dc03b34bcf82..ecdd8c09e4ed7c874ae7e7e58449196bbb4fb19b 100644 (file)
@@ -154,6 +154,7 @@ static struct of_device_id __initdata of_bus_ids[] = {
        { .name = "soc", },
        { .type = "soc", },
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index 472f254a19d2480e32c84f22aa7b85cdb420ec25..cc27807a8b64ab657a789d0b41ba2b111ef0d952 100644 (file)
@@ -213,6 +213,7 @@ static struct of_device_id __initdata of_bus_ids[] = {
        { .name = "cpm", },
        { .name = "localbus", },
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index 79a0df17078bbb2e141d29035994d5cfa40fd600..cc0b0db8a6f31bc54f0fd8c483afcc8c67e68786 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/page.h>
 #include <asm/mpic.h>
 #include <asm/cacheflush.h>
+#include <asm/dbell.h>
 
 #include <sysdev/fsl_soc.h>
 
@@ -80,10 +81,8 @@ smp_85xx_kick_cpu(int nr)
 }
 
 static void __init
-smp_85xx_setup_cpu(int cpu_nr)
+smp_85xx_basic_setup(int cpu_nr)
 {
-       mpic_setup_this_cpu();
-
        /* Clear any pending timer interrupts */
        mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
 
@@ -91,15 +90,43 @@ smp_85xx_setup_cpu(int cpu_nr)
        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 = {
-       .message_pass = smp_mpic_message_pass,
-       .probe = smp_mpic_probe,
        .kick_cpu = smp_85xx_kick_cpu,
-       .setup_cpu = smp_85xx_setup_cpu,
 };
 
-void __init
-mpc85xx_smp_init(void)
+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))
+               smp_85xx_ops.message_pass = smp_dbell_message_pass;
+
+       BUG_ON(!smp_85xx_ops.message_pass);
+
        smp_ops = &smp_85xx_ops;
 }
diff --git a/arch/powerpc/platforms/85xx/socrates.c b/arch/powerpc/platforms/85xx/socrates.c
new file mode 100644 (file)
index 0000000..d0e8443
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2008 Emcraft Systems
+ * Sergei Poselenov <sposelenov@emcraft.com>
+ *
+ * Based on MPC8560 ADS and arch/ppc tqm85xx ports
+ *
+ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
+ *
+ * Copyright 2008 Freescale Semiconductor Inc.
+ *
+ * Copyright (c) 2005-2006 DENX Software Engineering
+ * Stefan Roese <sr@denx.de>
+ *
+ * Based on original work by
+ *     Kumar Gala <kumar.gala@freescale.com>
+ *      Copyright 2004 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/of_platform.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpic.h>
+#include <asm/prom.h>
+#include <mm/mmu_decl.h>
+#include <asm/udbg.h>
+
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+
+#include "socrates_fpga_pic.h"
+
+static void __init socrates_pic_init(void)
+{
+       struct mpic *mpic;
+       struct resource r;
+       struct device_node *np;
+
+       np = of_find_node_by_type(NULL, "open-pic");
+       if (!np) {
+               printk(KERN_ERR "Could not find open-pic node\n");
+               return;
+       }
+
+       if (of_address_to_resource(np, 0, &r)) {
+               printk(KERN_ERR "Could not map mpic register space\n");
+               of_node_put(np);
+               return;
+       }
+
+       mpic = mpic_alloc(np, r.start,
+                       MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+                       0, 256, " OpenPIC  ");
+       BUG_ON(mpic == NULL);
+       of_node_put(np);
+
+       mpic_init(mpic);
+
+       np = of_find_compatible_node(NULL, NULL, "abb,socrates-fpga-pic");
+       if (!np) {
+               printk(KERN_ERR "Could not find socrates-fpga-pic node\n");
+               return;
+       }
+       socrates_fpga_pic_init(np);
+       of_node_put(np);
+}
+
+/*
+ * Setup the architecture
+ */
+static void __init socrates_setup_arch(void)
+{
+#ifdef CONFIG_PCI
+       struct device_node *np;
+#endif
+
+       if (ppc_md.progress)
+               ppc_md.progress("socrates_setup_arch()", 0);
+
+#ifdef CONFIG_PCI
+       for_each_compatible_node(np, "pci", "fsl,mpc8540-pci")
+               fsl_add_bridge(np, 1);
+#endif
+}
+
+static struct of_device_id __initdata socrates_of_bus_ids[] = {
+       { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
+       {},
+};
+
+static void __init socrates_init(void)
+{
+       of_platform_bus_probe(NULL, socrates_of_bus_ids, NULL);
+}
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init socrates_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       if (of_flat_dt_is_compatible(root, "abb,socrates"))
+               return 1;
+
+       return 0;
+}
+
+define_machine(socrates) {
+       .name                   = "Socrates",
+       .probe                  = socrates_probe,
+       .setup_arch             = socrates_setup_arch,
+       .init                   = socrates_init,
+       .init_IRQ               = socrates_pic_init,
+       .get_irq                = mpic_get_irq,
+       .restart                = fsl_rstcr_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
new file mode 100644 (file)
index 0000000..60edf63
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ *  Copyright (C) 2008 Ilya Yanok, Emcraft Systems
+ *
+ *
+ * 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/irq.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+
+/*
+ * The FPGA supports 9 interrupt sources, which can be routed to 3
+ * interrupt request lines of the MPIC. The line to be used can be
+ * specified through the third cell of FDT property  "interrupts".
+ */
+
+#define SOCRATES_FPGA_NUM_IRQS 9
+
+#define FPGA_PIC_IRQCFG                (0x0)
+#define FPGA_PIC_IRQMASK(n)    (0x4 + 0x4 * (n))
+
+#define SOCRATES_FPGA_IRQ_MASK ((1 << SOCRATES_FPGA_NUM_IRQS) - 1)
+
+struct socrates_fpga_irq_info {
+       unsigned int irq_line;
+       int type;
+};
+
+/*
+ * Interrupt routing and type table
+ *
+ * IRQ_TYPE_NONE means the interrupt type is configurable,
+ * otherwise it's fixed to the specified value.
+ */
+static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = {
+       [0] = {0, IRQ_TYPE_NONE},
+       [1] = {0, IRQ_TYPE_LEVEL_HIGH},
+       [2] = {0, IRQ_TYPE_LEVEL_LOW},
+       [3] = {0, IRQ_TYPE_NONE},
+       [4] = {0, IRQ_TYPE_NONE},
+       [5] = {0, IRQ_TYPE_NONE},
+       [6] = {0, IRQ_TYPE_NONE},
+       [7] = {0, IRQ_TYPE_NONE},
+       [8] = {0, IRQ_TYPE_LEVEL_HIGH},
+};
+
+#define socrates_fpga_irq_to_hw(virq)    ((unsigned int)irq_map[virq].hwirq)
+
+static DEFINE_SPINLOCK(socrates_fpga_pic_lock);
+
+static void __iomem *socrates_fpga_pic_iobase;
+static struct irq_host *socrates_fpga_pic_irq_host;
+static unsigned int socrates_fpga_irqs[3];
+
+static inline uint32_t socrates_fpga_pic_read(int reg)
+{
+       return in_be32(socrates_fpga_pic_iobase + reg);
+}
+
+static inline void socrates_fpga_pic_write(int reg, uint32_t val)
+{
+       out_be32(socrates_fpga_pic_iobase + reg, val);
+}
+
+static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq)
+{
+       uint32_t cause;
+       unsigned long flags;
+       int i;
+
+       /* Check irq line routed to the MPIC */
+       for (i = 0; i < 3; i++) {
+               if (irq == socrates_fpga_irqs[i])
+                       break;
+       }
+       if (i == 3)
+               return NO_IRQ;
+
+       spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
+       cause = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(i));
+       spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
+       for (i = SOCRATES_FPGA_NUM_IRQS - 1; i >= 0; i--) {
+               if (cause >> (i + 16))
+                       break;
+       }
+       return irq_linear_revmap(socrates_fpga_pic_irq_host,
+                       (irq_hw_number_t)i);
+}
+
+void socrates_fpga_pic_cascade(unsigned int irq, struct irq_desc *desc)
+{
+       unsigned int cascade_irq;
+
+       /*
+        * See if we actually have an interrupt, call generic handling code if
+        * we do.
+        */
+       cascade_irq = socrates_fpga_pic_get_irq(irq);
+
+       if (cascade_irq != NO_IRQ)
+               generic_handle_irq(cascade_irq);
+       desc->chip->eoi(irq);
+
+}
+
+static void socrates_fpga_pic_ack(unsigned int virq)
+{
+       unsigned long flags;
+       unsigned int hwirq, irq_line;
+       uint32_t mask;
+
+       hwirq = socrates_fpga_irq_to_hw(virq);
+
+       irq_line = fpga_irqs[hwirq].irq_line;
+       spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
+       mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
+               & SOCRATES_FPGA_IRQ_MASK;
+       mask |= (1 << (hwirq + 16));
+       socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
+       spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
+}
+
+static void socrates_fpga_pic_mask(unsigned int virq)
+{
+       unsigned long flags;
+       unsigned int hwirq;
+       int irq_line;
+       u32 mask;
+
+       hwirq = socrates_fpga_irq_to_hw(virq);
+
+       irq_line = fpga_irqs[hwirq].irq_line;
+       spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
+       mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
+               & SOCRATES_FPGA_IRQ_MASK;
+       mask &= ~(1 << hwirq);
+       socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
+       spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
+}
+
+static void socrates_fpga_pic_mask_ack(unsigned int virq)
+{
+       unsigned long flags;
+       unsigned int hwirq;
+       int irq_line;
+       u32 mask;
+
+       hwirq = socrates_fpga_irq_to_hw(virq);
+
+       irq_line = fpga_irqs[hwirq].irq_line;
+       spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
+       mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
+               & SOCRATES_FPGA_IRQ_MASK;
+       mask &= ~(1 << hwirq);
+       mask |= (1 << (hwirq + 16));
+       socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
+       spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
+}
+
+static void socrates_fpga_pic_unmask(unsigned int virq)
+{
+       unsigned long flags;
+       unsigned int hwirq;
+       int irq_line;
+       u32 mask;
+
+       hwirq = socrates_fpga_irq_to_hw(virq);
+
+       irq_line = fpga_irqs[hwirq].irq_line;
+       spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
+       mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
+               & SOCRATES_FPGA_IRQ_MASK;
+       mask |= (1 << hwirq);
+       socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
+       spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
+}
+
+static void socrates_fpga_pic_eoi(unsigned int virq)
+{
+       unsigned long flags;
+       unsigned int hwirq;
+       int irq_line;
+       u32 mask;
+
+       hwirq = socrates_fpga_irq_to_hw(virq);
+
+       irq_line = fpga_irqs[hwirq].irq_line;
+       spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
+       mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
+               & SOCRATES_FPGA_IRQ_MASK;
+       mask |= (1 << (hwirq + 16));
+       socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
+       spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
+}
+
+static int socrates_fpga_pic_set_type(unsigned int virq,
+               unsigned int flow_type)
+{
+       unsigned long flags;
+       unsigned int hwirq;
+       int polarity;
+       u32 mask;
+
+       hwirq = socrates_fpga_irq_to_hw(virq);
+
+       if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
+               return -EINVAL;
+
+       switch (flow_type & IRQ_TYPE_SENSE_MASK) {
+       case IRQ_TYPE_LEVEL_HIGH:
+               polarity = 1;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               polarity = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+       spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
+       mask = socrates_fpga_pic_read(FPGA_PIC_IRQCFG);
+       if (polarity)
+               mask |= (1 << hwirq);
+       else
+               mask &= ~(1 << hwirq);
+       socrates_fpga_pic_write(FPGA_PIC_IRQCFG, mask);
+       spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
+       return 0;
+}
+
+static struct irq_chip socrates_fpga_pic_chip = {
+       .typename       = " FPGA-PIC ",
+       .ack            = socrates_fpga_pic_ack,
+       .mask           = socrates_fpga_pic_mask,
+       .mask_ack       = socrates_fpga_pic_mask_ack,
+       .unmask         = socrates_fpga_pic_unmask,
+       .eoi            = socrates_fpga_pic_eoi,
+       .set_type       = socrates_fpga_pic_set_type,
+};
+
+static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq,
+               irq_hw_number_t hwirq)
+{
+       /* All interrupts are LEVEL sensitive */
+       get_irq_desc(virq)->status |= IRQ_LEVEL;
+       set_irq_chip_and_handler(virq, &socrates_fpga_pic_chip,
+                       handle_fasteoi_irq);
+
+       return 0;
+}
+
+static int socrates_fpga_pic_host_xlate(struct irq_host *h,
+               struct device_node *ct, u32 *intspec, unsigned int intsize,
+               irq_hw_number_t *out_hwirq, unsigned int *out_flags)
+{
+       struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]];
+
+       *out_hwirq = intspec[0];
+       if  (fpga_irq->type == IRQ_TYPE_NONE) {
+               /* type is configurable */
+               if (intspec[1] != IRQ_TYPE_LEVEL_LOW &&
+                   intspec[1] != IRQ_TYPE_LEVEL_HIGH) {
+                       pr_warning("FPGA PIC: invalid irq type, "
+                                  "setting default active low\n");
+                       *out_flags = IRQ_TYPE_LEVEL_LOW;
+               } else {
+                       *out_flags = intspec[1];
+               }
+       } else {
+               /* type is fixed */
+               *out_flags = fpga_irq->type;
+       }
+
+       /* Use specified interrupt routing */
+       if (intspec[2] <= 2)
+               fpga_irq->irq_line = intspec[2];
+       else
+               pr_warning("FPGA PIC: invalid irq routing\n");
+
+       return 0;
+}
+
+static struct irq_host_ops socrates_fpga_pic_host_ops = {
+       .map    = socrates_fpga_pic_host_map,
+       .xlate  = socrates_fpga_pic_host_xlate,
+};
+
+void socrates_fpga_pic_init(struct device_node *pic)
+{
+       unsigned long flags;
+       int i;
+
+       /* Setup an irq_host structure */
+       socrates_fpga_pic_irq_host = irq_alloc_host(pic, IRQ_HOST_MAP_LINEAR,
+                       SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops,
+                       SOCRATES_FPGA_NUM_IRQS);
+       if (socrates_fpga_pic_irq_host == NULL) {
+               pr_err("FPGA PIC: Unable to allocate host\n");
+               return;
+       }
+
+       for (i = 0; i < 3; i++) {
+               socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i);
+               if (socrates_fpga_irqs[i] == NO_IRQ) {
+                       pr_warning("FPGA PIC: can't get irq%d.\n", i);
+                       continue;
+               }
+               set_irq_chained_handler(socrates_fpga_irqs[i],
+                               socrates_fpga_pic_cascade);
+       }
+
+       socrates_fpga_pic_iobase = of_iomap(pic, 0);
+
+       spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
+       socrates_fpga_pic_write(FPGA_PIC_IRQMASK(0),
+                       SOCRATES_FPGA_IRQ_MASK << 16);
+       socrates_fpga_pic_write(FPGA_PIC_IRQMASK(1),
+                       SOCRATES_FPGA_IRQ_MASK << 16);
+       socrates_fpga_pic_write(FPGA_PIC_IRQMASK(2),
+                       SOCRATES_FPGA_IRQ_MASK << 16);
+       spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
+
+       pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n");
+}
diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.h b/arch/powerpc/platforms/85xx/socrates_fpga_pic.h
new file mode 100644 (file)
index 0000000..21d7d8e
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ *  Copyright (C) 2008 Ilya Yanok, Emcraft Systems
+ *
+ *
+ * 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.
+ *
+ */
+
+#ifndef SOCRATES_FPGA_PIC_H
+#define SOCRATES_FPGA_PIC_H
+
+void socrates_fpga_pic_init(struct device_node *pic);
+
+#endif
index 0cca8f5cb272534e326db9cc1cf8d450c8d1a04a..f559918f3c6ff7485606032c0abfabf5c2543f36 100644 (file)
@@ -145,6 +145,7 @@ static void stx_gp3_show_cpuinfo(struct seq_file *m)
 
 static struct of_device_id __initdata of_bus_ids[] = {
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index 2933a8e827d9a5c8bbd259e41864fa158fa43cd7..5b0ab9966e907f656105e6f10387531dc26b8f93 100644 (file)
@@ -153,6 +153,7 @@ static void tqm85xx_show_cpuinfo(struct seq_file *m)
 
 static struct of_device_id __initdata of_bus_ids[] = {
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index 8e5693935975f27cf4c4addb308c9f6e28c0f592..fdaf4ddaa955c90c2a263afd62d4ba63fff0b249 100644 (file)
@@ -1,7 +1,7 @@
 config PPC_86xx
 menuconfig PPC_86xx
        bool "86xx-based boards"
-       depends on 6xx && PPC_MULTIPLATFORM
+       depends on 6xx
        select FSL_SOC
        select ALTIVEC
        help
@@ -31,6 +31,22 @@ config MPC8610_HPCD
        help
          This option enables support for the MPC8610 HPCD board.
 
+config GEF_PPC9A
+       bool "GE Fanuc PPC9A"
+       select DEFAULT_UIMAGE
+       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       help
+         This option enables support for GE Fanuc's PPC9A.
+
+config GEF_SBC310
+       bool "GE Fanuc SBC310"
+       select DEFAULT_UIMAGE
+       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       help
+         This option enables support for GE Fanuc's SBC310.
+
 config GEF_SBC610
        bool "GE Fanuc SBC610"
        select DEFAULT_UIMAGE
@@ -48,7 +64,7 @@ config MPC8641
        select FSL_PCI if PCI
        select PPC_UDBG_16550
        select MPIC
-       default y if MPC8641_HPCN || SBC8641D || GEF_SBC610
+       default y if MPC8641_HPCN || SBC8641D || GEF_SBC610 || GEF_SBC310 || GEF_PPC9A
 
 config MPC8610
        bool
index 31e540c2ebbc559a7a790a3edc6ca078d57c951c..4b0d7b1aa0056bd45d5f80dfd95a150a4844f3d4 100644 (file)
@@ -9,3 +9,5 @@ obj-$(CONFIG_SBC8641D)          += sbc8641d.o
 obj-$(CONFIG_MPC8610_HPCD)     += mpc8610_hpcd.o
 gef-gpio-$(CONFIG_GPIOLIB)     += gef_gpio.o
 obj-$(CONFIG_GEF_SBC610)       += gef_sbc610.o gef_pic.o $(gef-gpio-y)
+obj-$(CONFIG_GEF_SBC310)       += gef_sbc310.o gef_pic.o $(gef-gpio-y)
+obj-$(CONFIG_GEF_PPC9A)                += gef_ppc9a.o gef_pic.o $(gef-gpio-y)
index 85b2800f4cb71b18ec622805a98fa29c180c7355..b2ea8875adbaf02c2f30cfc4989f9697aec1a685 100644 (file)
@@ -37,8 +37,6 @@
 #define GEF_GPIO_OVERRUN       0x1C
 #define GEF_GPIO_MODE          0x20
 
-#define NUM_GPIO 19
-
 static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value)
 {
        unsigned int data;
@@ -103,10 +101,10 @@ static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 static int __init gef_gpio_init(void)
 {
        struct device_node *np;
+       int retval;
+       struct of_mm_gpio_chip *gef_gpio_chip;
 
        for_each_compatible_node(np, NULL, "gef,sbc610-gpio") {
-               int retval;
-               struct of_mm_gpio_chip *gef_gpio_chip;
 
                pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
 
@@ -120,7 +118,35 @@ static int __init gef_gpio_init(void)
 
                /* Setup pointers to chip functions */
                gef_gpio_chip->of_gc.gpio_cells = 2;
-               gef_gpio_chip->of_gc.gc.ngpio = NUM_GPIO;
+               gef_gpio_chip->of_gc.gc.ngpio = 19;
+               gef_gpio_chip->of_gc.gc.direction_input = gef_gpio_dir_in;
+               gef_gpio_chip->of_gc.gc.direction_output = gef_gpio_dir_out;
+               gef_gpio_chip->of_gc.gc.get = gef_gpio_get;
+               gef_gpio_chip->of_gc.gc.set = gef_gpio_set;
+
+               /* This function adds a memory mapped GPIO chip */
+               retval = of_mm_gpiochip_add(np, gef_gpio_chip);
+               if (retval) {
+                       kfree(gef_gpio_chip);
+                       pr_err("%s: Unable to add GPIO\n", np->full_name);
+               }
+       }
+
+       for_each_compatible_node(np, NULL, "gef,sbc310-gpio") {
+
+               pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
+
+               /* Allocate chip structure */
+               gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
+               if (!gef_gpio_chip) {
+                       pr_err("%s: Unable to allocate structure\n",
+                               np->full_name);
+                       continue;
+               }
+
+               /* Setup pointers to chip functions */
+               gef_gpio_chip->of_gc.gpio_cells = 2;
+               gef_gpio_chip->of_gc.gc.ngpio = 6;
                gef_gpio_chip->of_gc.gc.direction_input = gef_gpio_dir_in;
                gef_gpio_chip->of_gc.gc.direction_output = gef_gpio_dir_out;
                gef_gpio_chip->of_gc.gc.get = gef_gpio_get;
diff --git a/arch/powerpc/platforms/86xx/gef_ppc9a.c b/arch/powerpc/platforms/86xx/gef_ppc9a.c
new file mode 100644 (file)
index 0000000..d791046
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * GE Fanuc PPC9A board support
+ *
+ * Author: Martyn Welch <martyn.welch@gefanuc.com>
+ *
+ * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, 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.
+ *
+ * Based on: mpc86xx_hpcn.c (MPC86xx HPCN board specific routines)
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * NEC fixup adapted from arch/mips/pci/fixup-lm2e.c
+ */
+
+#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/of_platform.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc86xx.h>
+#include <asm/prom.h>
+#include <mm/mmu_decl.h>
+#include <asm/udbg.h>
+
+#include <asm/mpic.h>
+
+#include <sysdev/fsl_pci.h>
+#include <sysdev/fsl_soc.h>
+
+#include "mpc86xx.h"
+#include "gef_pic.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG (fmt...) do { printk(KERN_ERR "PPC9A: " fmt); } while (0)
+#else
+#define DBG (fmt...) do { } while (0)
+#endif
+
+void __iomem *ppc9a_regs;
+
+static void __init gef_ppc9a_init_irq(void)
+{
+       struct device_node *cascade_node = NULL;
+
+       mpc86xx_init_irq();
+
+       /*
+        * There is a simple interrupt handler in the main FPGA, this needs
+        * to be cascaded into the MPIC
+        */
+       cascade_node = of_find_compatible_node(NULL, NULL, "gef,fpga-pic-1.00");
+       if (!cascade_node) {
+               printk(KERN_WARNING "PPC9A: No FPGA PIC\n");
+               return;
+       }
+
+       gef_pic_init(cascade_node);
+       of_node_put(cascade_node);
+}
+
+static void __init gef_ppc9a_setup_arch(void)
+{
+       struct device_node *regs;
+#ifdef CONFIG_PCI
+       struct device_node *np;
+
+       for_each_compatible_node(np, "pci", "fsl,mpc8641-pcie") {
+               fsl_add_bridge(np, 1);
+       }
+#endif
+
+       printk(KERN_INFO "GE Fanuc Intelligent Platforms PPC9A 6U VME SBC\n");
+
+#ifdef CONFIG_SMP
+       mpc86xx_smp_init();
+#endif
+
+       /* Remap basic board registers */
+       regs = of_find_compatible_node(NULL, NULL, "gef,ppc9a-fpga-regs");
+       if (regs) {
+               ppc9a_regs = of_iomap(regs, 0);
+               if (ppc9a_regs == NULL)
+                       printk(KERN_WARNING "Unable to map board registers\n");
+               of_node_put(regs);
+       }
+}
+
+/* Return the PCB revision */
+static unsigned int gef_ppc9a_get_pcb_rev(void)
+{
+       unsigned int reg;
+
+       reg = ioread32(ppc9a_regs);
+       return (reg >> 8) & 0xff;
+}
+
+/* Return the board (software) revision */
+static unsigned int gef_ppc9a_get_board_rev(void)
+{
+       unsigned int reg;
+
+       reg = ioread32(ppc9a_regs);
+       return (reg >> 16) & 0xff;
+}
+
+/* Return the FPGA revision */
+static unsigned int gef_ppc9a_get_fpga_rev(void)
+{
+       unsigned int reg;
+
+       reg = ioread32(ppc9a_regs);
+       return (reg >> 24) & 0xf;
+}
+
+static void gef_ppc9a_show_cpuinfo(struct seq_file *m)
+{
+       uint svid = mfspr(SPRN_SVR);
+
+       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));
+       seq_printf(m, "FPGA Revision\t: %u\n", gef_ppc9a_get_fpga_rev());
+
+       seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+}
+
+static void __init gef_ppc9a_nec_fixup(struct pci_dev *pdev)
+{
+       unsigned int val;
+
+       /* Do not do the fixup on other platforms! */
+       if (!machine_is(gef_ppc9a))
+               return;
+
+       printk(KERN_INFO "Running NEC uPD720101 Fixup\n");
+
+       /* Ensure ports 1, 2, 3, 4 & 5 are enabled */
+       pci_read_config_dword(pdev, 0xe0, &val);
+       pci_write_config_dword(pdev, 0xe0, (val & ~7) | 0x5);
+
+       /* System clock is 48-MHz Oscillator and EHCI Enabled. */
+       pci_write_config_dword(pdev, 0xe4, 1 << 5);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB,
+       gef_ppc9a_nec_fixup);
+
+/*
+ * Called very early, device-tree isn't unflattened
+ *
+ * This function is called to determine whether the BSP is compatible with the
+ * supplied device-tree, which is assumed to be the correct one for the actual
+ * board. It is expected thati, in the future, a kernel may support multiple
+ * boards.
+ */
+static int __init gef_ppc9a_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       if (of_flat_dt_is_compatible(root, "gef,ppc9a"))
+               return 1;
+
+       return 0;
+}
+
+static long __init mpc86xx_time_init(void)
+{
+       unsigned int temp;
+
+       /* Set the time base to zero */
+       mtspr(SPRN_TBWL, 0);
+       mtspr(SPRN_TBWU, 0);
+
+       temp = mfspr(SPRN_HID0);
+       temp |= HID0_TBEN;
+       mtspr(SPRN_HID0, temp);
+       asm volatile("isync");
+
+       return 0;
+}
+
+static __initdata struct of_device_id of_bus_ids[] = {
+       { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
+       {},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+       printk(KERN_DEBUG "Probe platform devices\n");
+       of_platform_bus_probe(NULL, of_bus_ids, NULL);
+
+       return 0;
+}
+machine_device_initcall(gef_ppc9a, declare_of_platform_devices);
+
+define_machine(gef_ppc9a) {
+       .name                   = "GE Fanuc PPC9A",
+       .probe                  = gef_ppc9a_probe,
+       .setup_arch             = gef_ppc9a_setup_arch,
+       .init_IRQ               = gef_ppc9a_init_irq,
+       .show_cpuinfo           = gef_ppc9a_show_cpuinfo,
+       .get_irq                = mpic_get_irq,
+       .restart                = fsl_rstcr_restart,
+       .time_init              = mpc86xx_time_init,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+#ifdef CONFIG_PCI
+       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
+};
diff --git a/arch/powerpc/platforms/86xx/gef_sbc310.c b/arch/powerpc/platforms/86xx/gef_sbc310.c
new file mode 100644 (file)
index 0000000..af14f85
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * GE Fanuc SBC310 board support
+ *
+ * Author: Martyn Welch <martyn.welch@gefanuc.com>
+ *
+ * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, 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.
+ *
+ * Based on: mpc86xx_hpcn.c (MPC86xx HPCN board specific routines)
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * NEC fixup adapted from arch/mips/pci/fixup-lm2e.c
+ */
+
+#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/of_platform.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc86xx.h>
+#include <asm/prom.h>
+#include <mm/mmu_decl.h>
+#include <asm/udbg.h>
+
+#include <asm/mpic.h>
+
+#include <sysdev/fsl_pci.h>
+#include <sysdev/fsl_soc.h>
+
+#include "mpc86xx.h"
+#include "gef_pic.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG (fmt...) do { printk(KERN_ERR "SBC310: " fmt); } while (0)
+#else
+#define DBG (fmt...) do { } while (0)
+#endif
+
+void __iomem *sbc310_regs;
+
+static void __init gef_sbc310_init_irq(void)
+{
+       struct device_node *cascade_node = NULL;
+
+       mpc86xx_init_irq();
+
+       /*
+        * There is a simple interrupt handler in the main FPGA, this needs
+        * to be cascaded into the MPIC
+        */
+       cascade_node = of_find_compatible_node(NULL, NULL, "gef,fpga-pic");
+       if (!cascade_node) {
+               printk(KERN_WARNING "SBC310: No FPGA PIC\n");
+               return;
+       }
+
+       gef_pic_init(cascade_node);
+       of_node_put(cascade_node);
+}
+
+static void __init gef_sbc310_setup_arch(void)
+{
+       struct device_node *regs;
+#ifdef CONFIG_PCI
+       struct device_node *np;
+
+       for_each_compatible_node(np, "pci", "fsl,mpc8641-pcie") {
+               fsl_add_bridge(np, 1);
+       }
+#endif
+
+       printk(KERN_INFO "GE Fanuc Intelligent Platforms SBC310 6U VPX SBC\n");
+
+#ifdef CONFIG_SMP
+       mpc86xx_smp_init();
+#endif
+
+       /* Remap basic board registers */
+       regs = of_find_compatible_node(NULL, NULL, "gef,fpga-regs");
+       if (regs) {
+               sbc310_regs = of_iomap(regs, 0);
+               if (sbc310_regs == NULL)
+                       printk(KERN_WARNING "Unable to map board registers\n");
+               of_node_put(regs);
+       }
+}
+
+/* Return the PCB revision */
+static unsigned int gef_sbc310_get_board_id(void)
+{
+       unsigned int reg;
+
+       reg = ioread32(sbc310_regs);
+       return reg & 0xff;
+}
+
+/* Return the PCB revision */
+static unsigned int gef_sbc310_get_pcb_rev(void)
+{
+       unsigned int reg;
+
+       reg = ioread32(sbc310_regs);
+       return (reg >> 8) & 0xff;
+}
+
+/* Return the board (software) revision */
+static unsigned int gef_sbc310_get_board_rev(void)
+{
+       unsigned int reg;
+
+       reg = ioread32(sbc310_regs);
+       return (reg >> 16) & 0xff;
+}
+
+/* Return the FPGA revision */
+static unsigned int gef_sbc310_get_fpga_rev(void)
+{
+       unsigned int reg;
+
+       reg = ioread32(sbc310_regs);
+       return (reg >> 24) & 0xf;
+}
+
+static void gef_sbc310_show_cpuinfo(struct seq_file *m)
+{
+       uint svid = mfspr(SPRN_SVR);
+
+       seq_printf(m, "Vendor\t\t: GE Fanuc Intelligent Platforms\n");
+
+       seq_printf(m, "Board ID\t: 0x%2.2x\n", gef_sbc310_get_board_id());
+       seq_printf(m, "Revision\t: %u%c\n", gef_sbc310_get_pcb_rev(),
+               ('A' + gef_sbc310_get_board_rev() - 1));
+       seq_printf(m, "FPGA Revision\t: %u\n", gef_sbc310_get_fpga_rev());
+
+       seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+
+}
+
+static void __init gef_sbc310_nec_fixup(struct pci_dev *pdev)
+{
+       unsigned int val;
+
+       /* Do not do the fixup on other platforms! */
+       if (!machine_is(gef_sbc310))
+               return;
+
+       printk(KERN_INFO "Running NEC uPD720101 Fixup\n");
+
+       /* Ensure only ports 1 & 2 are enabled */
+       pci_read_config_dword(pdev, 0xe0, &val);
+       pci_write_config_dword(pdev, 0xe0, (val & ~7) | 0x2);
+
+       /* System clock is 48-MHz Oscillator and EHCI Enabled. */
+       pci_write_config_dword(pdev, 0xe4, 1 << 5);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB,
+       gef_sbc310_nec_fixup);
+
+/*
+ * Called very early, device-tree isn't unflattened
+ *
+ * This function is called to determine whether the BSP is compatible with the
+ * supplied device-tree, which is assumed to be the correct one for the actual
+ * board. It is expected thati, in the future, a kernel may support multiple
+ * boards.
+ */
+static int __init gef_sbc310_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       if (of_flat_dt_is_compatible(root, "gef,sbc310"))
+               return 1;
+
+       return 0;
+}
+
+static long __init mpc86xx_time_init(void)
+{
+       unsigned int temp;
+
+       /* Set the time base to zero */
+       mtspr(SPRN_TBWL, 0);
+       mtspr(SPRN_TBWU, 0);
+
+       temp = mfspr(SPRN_HID0);
+       temp |= HID0_TBEN;
+       mtspr(SPRN_HID0, temp);
+       asm volatile("isync");
+
+       return 0;
+}
+
+static __initdata struct of_device_id of_bus_ids[] = {
+       { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
+       {},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+       printk(KERN_DEBUG "Probe platform devices\n");
+       of_platform_bus_probe(NULL, of_bus_ids, NULL);
+
+       return 0;
+}
+machine_device_initcall(gef_sbc310, declare_of_platform_devices);
+
+define_machine(gef_sbc310) {
+       .name                   = "GE Fanuc SBC310",
+       .probe                  = gef_sbc310_probe,
+       .setup_arch             = gef_sbc310_setup_arch,
+       .init_IRQ               = gef_sbc310_init_irq,
+       .show_cpuinfo           = gef_sbc310_show_cpuinfo,
+       .get_irq                = mpic_get_irq,
+       .restart                = fsl_rstcr_restart,
+       .time_init              = mpc86xx_time_init,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+#ifdef CONFIG_PCI
+       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
+};
index d6b772ba3b8f8238ea3ecd5d27c2b77843b9dcda..ea2360639652dbbfc7f46d07a2211e2acfd42902 100644 (file)
@@ -194,6 +194,7 @@ static long __init mpc86xx_time_init(void)
 
 static __initdata struct of_device_id of_bus_ids[] = {
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index e8d54ac5292c3ec972497fc1ee1b4178915e0345..3f49a6f893a30188de25da57470525f41ebdcb98 100644 (file)
@@ -46,6 +46,7 @@ static unsigned char *pixis_bdcfg0, *pixis_arch;
 static struct of_device_id __initdata mpc8610_ids[] = {
        { .compatible = "fsl,mpc8610-immr", },
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {}
 };
 
index 27e0e682d8e1231949d94e5f9cfaa12b1b8b7b36..c4ec49b5f7f8e3c394b5997a2654bab460abba93 100644 (file)
@@ -148,6 +148,7 @@ mpc86xx_time_init(void)
 static __initdata struct of_device_id of_bus_ids[] = {
        { .compatible = "simple-bus", },
        { .compatible = "fsl,rapidio-delta", },
+       { .compatible = "gianfar", },
        {},
 };
 
index 5fd7ed40986f58d6ecdac6ad31b52bc0029e6de7..2886a36fc0856f6b378300551ea4ad5fef5ce561 100644 (file)
@@ -103,6 +103,7 @@ mpc86xx_time_init(void)
 
 static __initdata struct of_device_id of_bus_ids[] = {
        { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
        {},
 };
 
index 0d9f75c74f8cdf22e83f13ba342c45f5b12a0d66..385acfc48397b8f2d2577326b78b49bb68b100f1 100644 (file)
@@ -44,7 +44,6 @@ static irqreturn_t timebase_interrupt(int irq, void *dev)
 
 static struct irqaction tbint_irqaction = {
        .handler = timebase_interrupt,
-       .mask = CPU_MASK_NONE,
        .name = "tbint",
 };
 
index 200b9cb900ea4b34280d270b51bebe773ca142b4..ffa2a9fd53d03d0a8eace5eff8496d77a95e9cd0 100644 (file)
@@ -1,14 +1,5 @@
 menu "Platform support"
 
-config PPC_MULTIPLATFORM
-       bool
-       depends on PPC64 || 6xx
-       default y
-
-config CLASSIC32
-       def_bool y
-       depends on 6xx && PPC_MULTIPLATFORM
-
 source "arch/powerpc/platforms/pseries/Kconfig"
 source "arch/powerpc/platforms/iseries/Kconfig"
 source "arch/powerpc/platforms/chrp/Kconfig"
@@ -28,15 +19,28 @@ source "arch/powerpc/platforms/86xx/Kconfig"
 source "arch/powerpc/platforms/embedded6xx/Kconfig"
 source "arch/powerpc/platforms/44x/Kconfig"
 source "arch/powerpc/platforms/40x/Kconfig"
+source "arch/powerpc/platforms/amigaone/Kconfig"
 
 config PPC_NATIVE
        bool
-       depends on PPC_MULTIPLATFORM
+       depends on 6xx || PPC64
        help
          Support for running natively on the hardware, i.e. without
          a hypervisor. This option is not user-selectable but should
          be selected by all platforms that need it.
 
+config PPC_OF_BOOT_TRAMPOLINE
+       bool "Support booting from Open Firmware or yaboot"
+       depends on 6xx || PPC64
+       default y
+       help
+         Support from booting from Open Firmware or yaboot using an
+         Open Firmware client interface. This enables the kernel to
+         communicate with open firmware to retrieve system informations
+         such as the device tree.
+
+         In case of doubt, say Y
+
 config UDBG_RTAS_CONSOLE
        bool "RTAS based debug console"
        depends on PPC_RTAS
@@ -70,7 +74,7 @@ config PPC_I8259
 
 config U3_DART
        bool
-       depends on PPC_MULTIPLATFORM && PPC64
+       depends on PPC64
        default n
 
 config PPC_RTAS
@@ -91,15 +95,6 @@ config RTAS_FLASH
        tristate "Firmware flash interface"
        depends on PPC64 && RTAS_PROC
 
-config PPC_PMI
-       tristate "Support for PMI"
-       depends on PPC_IBM_CELL_BLADE
-       help
-         PMI (Platform Management Interrupt) is a way to
-         communicate with the BMC (Baseboard Management Controller).
-         It is used in some IBM Cell blades.
-       default m
-
 config MMIO_NVRAM
        bool
        default n
@@ -196,7 +191,7 @@ config PPC601_SYNC_FIX
 
 config TAU
        bool "On-chip CPU temperature sensor support"
-       depends on CLASSIC32
+       depends on 6xx
        help
          G3 and G4 processors have an on-chip temperature sensor called the
          'Thermal Assist Unit (TAU)', which, in theory, can measure the on-die
@@ -274,7 +269,7 @@ config CPM2
 
 config AXON_RAM
        tristate "Axon DDR2 memory device driver"
-       depends on PPC_IBM_CELL_BLADE
+       depends on PPC_IBM_CELL_BLADE && BLOCK
        default m
        help
          It registers one block device per Axon's DDR2 memory bank found
index e868b5c50723d348cbf2357e8adb3c9ec28998b5..9da795e49337d0ae14e0357ba00aae37d4f41df1 100644 (file)
@@ -57,9 +57,17 @@ config E200
 
 endchoice
 
+# Until we have a choice of exclusive CPU types on 64-bit, we always
+# use PPC_BOOK3S. On 32-bit, this is equivalent to 6xx which is
+# "classic" MMU
+
+config PPC_BOOK3S
+       def_bool y
+       depends on PPC64 || 6xx
+
 config POWER4_ONLY
        bool "Optimize for POWER4"
-       depends on PPC64
+       depends on PPC64 && PPC_BOOK3S
        default n
        ---help---
          Cause the compiler to optimize for POWER4/POWER5/PPC970 processors.
@@ -68,16 +76,16 @@ config POWER4_ONLY
 
 config POWER3
        bool
-       depends on PPC64
+       depends on PPC64 && PPC_BOOK3S
        default y if !POWER4_ONLY
 
 config POWER4
-       depends on PPC64
+       depends on PPC64 && PPC_BOOK3S
        def_bool y
 
 config TUNE_CELL
        bool "Optimize for Cell Broadband Engine"
-       depends on PPC64
+       depends on PPC64 && PPC_BOOK3S
        help
          Cause the compiler to optimize for the PPE of the Cell Broadband
          Engine. This will make the code run considerably faster on Cell
@@ -147,7 +155,7 @@ config PHYS_64BIT
 
 config ALTIVEC
        bool "AltiVec Support"
-       depends on CLASSIC32 || POWER4
+       depends on 6xx || POWER4
        ---help---
          This option enables kernel support for the Altivec extensions to the
          PowerPC processor. The kernel currently supports saving and restoring
@@ -210,6 +218,10 @@ config PPC_MMU_NOHASH
        def_bool y
        depends on !PPC_STD_MMU
 
+config PPC_BOOK3E_MMU
+       def_bool y
+       depends on FSL_BOOKE
+
 config PPC_MM_SLICES
        bool
        default y if HUGETLB_PAGE || (PPC_STD_MMU_64 && PPC_64K_PAGES)
index 8079e0b4fd69a14a0bde12cd2dfed65732b3bdbd..f7419198e63531aec1138b4852c4525fb198e60e 100644 (file)
@@ -19,3 +19,4 @@ obj-$(CONFIG_PPC_PASEMI)      += pasemi/
 obj-$(CONFIG_PPC_CELL)         += cell/
 obj-$(CONFIG_PPC_PS3)          += ps3/
 obj-$(CONFIG_EMBEDDED6xx)      += embedded6xx/
+obj-$(CONFIG_AMIGAONE)         += amigaone/
diff --git a/arch/powerpc/platforms/amigaone/Kconfig b/arch/powerpc/platforms/amigaone/Kconfig
new file mode 100644 (file)
index 0000000..0224767
--- /dev/null
@@ -0,0 +1,18 @@
+config AMIGAONE
+       bool "Eyetech AmigaOne/MAI Teron"
+       depends on 6xx && BROKEN_ON_SMP
+       select PPC_I8259
+       select PPC_INDIRECT_PCI
+       select PPC_UDBG_16550
+       select PCI
+       select NOT_COHERENT_CACHE
+       select CHECK_CACHE_COHERENCY
+       select DEFAULT_UIMAGE
+       select PCSPKR_PLATFORM
+       help
+       Select AmigaOne for the following machines:
+       - AmigaOne SE/Teron CX (G3 only)
+       - AmigaOne XE/Teron PX
+       - uA1/Teron mini
+         More information is available at:
+         <http://amigaone-linux.sourceforge.net/>.
diff --git a/arch/powerpc/platforms/amigaone/Makefile b/arch/powerpc/platforms/amigaone/Makefile
new file mode 100644 (file)
index 0000000..e6885b3
--- /dev/null
@@ -0,0 +1 @@
+obj-y  += setup.o
diff --git a/arch/powerpc/platforms/amigaone/setup.c b/arch/powerpc/platforms/amigaone/setup.c
new file mode 100644 (file)
index 0000000..4430353
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * AmigaOne platform setup
+ *
+ * Copyright 2008 Gerhard Pircher (gerhard_pircher@gmx.net)
+ *
+ *   Based on original amigaone_setup.c source code
+ * Copyright 2003 by Hans-Joerg Frieden and Thomas Frieden
+ *
+ * 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/kernel.h>
+#include <linux/seq_file.h>
+#include <linux/utsrelease.h>
+
+#include <asm/machdep.h>
+#include <asm/cputable.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/i8259.h>
+#include <asm/time.h>
+#include <asm/udbg.h>
+
+extern void __flush_disable_L1(void);
+
+void amigaone_show_cpuinfo(struct seq_file *m)
+{
+       seq_printf(m, "vendor\t\t: Eyetech Ltd.\n");
+}
+
+static int __init amigaone_add_bridge(struct device_node *dev)
+{
+       const u32 *cfg_addr, *cfg_data;
+       int len;
+       const int *bus_range;
+       struct pci_controller *hose;
+
+       printk(KERN_INFO "Adding PCI host bridge %s\n", dev->full_name);
+
+       cfg_addr = of_get_address(dev, 0, NULL, NULL);
+       cfg_data = of_get_address(dev, 1, NULL, NULL);
+       if ((cfg_addr == NULL) || (cfg_data == NULL))
+               return -ENODEV;
+
+       bus_range = of_get_property(dev, "bus-range", &len);
+       if ((bus_range == NULL) || (len < 2 * sizeof(int)))
+               printk(KERN_WARNING "Can't get bus-range for %s, assume"
+                      " bus 0\n", dev->full_name);
+
+       hose = pcibios_alloc_controller(dev);
+       if (hose == NULL)
+               return -ENOMEM;
+
+       hose->first_busno = bus_range ? bus_range[0] : 0;
+       hose->last_busno = bus_range ? bus_range[1] : 0xff;
+
+       setup_indirect_pci(hose, cfg_addr[0], cfg_data[0], 0);
+
+       /* Interpret the "ranges" property */
+       /* This also maps the I/O region and sets isa_io/mem_base */
+       pci_process_bridge_OF_ranges(hose, dev, 1);
+
+       return 0;
+}
+
+void __init amigaone_setup_arch(void)
+{
+       struct device_node *np;
+       int phb = -ENODEV;
+
+       /* Lookup PCI host bridges. */
+       for_each_compatible_node(np, "pci", "mai-logic,articia-s")
+               phb = amigaone_add_bridge(np);
+
+       BUG_ON(phb != 0);
+
+       if (ppc_md.progress)
+               ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0);
+}
+
+void __init amigaone_init_IRQ(void)
+{
+       struct device_node *pic, *np = NULL;
+       const unsigned long *prop = NULL;
+       unsigned long int_ack = 0;
+
+       /* Search for ISA interrupt controller. */
+       pic = of_find_compatible_node(NULL, "interrupt-controller",
+                                     "pnpPNP,000");
+       BUG_ON(pic == NULL);
+
+       /* Look for interrupt acknowledge address in the PCI root node. */
+       np = of_find_compatible_node(NULL, "pci", "mai-logic,articia-s");
+       if (np) {
+               prop = of_get_property(np, "8259-interrupt-acknowledge", NULL);
+               if (prop)
+                       int_ack = prop[0];
+               of_node_put(np);
+       }
+
+       if (int_ack == 0)
+               printk(KERN_WARNING "Cannot find PCI interrupt acknowledge"
+                      " address, polling\n");
+
+       i8259_init(pic, int_ack);
+       ppc_md.get_irq = i8259_irq;
+       irq_set_default_host(i8259_get_host());
+}
+
+void __init amigaone_init(void)
+{
+       request_region(0x00, 0x20, "dma1");
+       request_region(0x40, 0x20, "timer");
+       request_region(0x80, 0x10, "dma page reg");
+       request_region(0xc0, 0x20, "dma2");
+}
+
+void amigaone_restart(char *cmd)
+{
+       local_irq_disable();
+
+       /* Flush and disable caches. */
+       __flush_disable_L1();
+
+        /* Set SRR0 to the reset vector and turn on MSR_IP. */
+       mtspr(SPRN_SRR0, 0xfff00100);
+       mtspr(SPRN_SRR1, MSR_IP);
+
+       /* Do an rfi to jump back to firmware. */
+       __asm__ __volatile__("rfi" : : : "memory");
+
+       /* Not reached. */
+       while (1);
+}
+
+static int __init amigaone_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       if (of_flat_dt_is_compatible(root, "eyetech,amigaone")) {
+               /*
+                * Coherent memory access cause complete system lockup! Thus
+                * disable this CPU feature, even if the CPU needs it.
+                */
+               cur_cpu_spec->cpu_features &= ~CPU_FTR_NEED_COHERENT;
+
+               ISA_DMA_THRESHOLD = 0x00ffffff;
+               DMA_MODE_READ = 0x44;
+               DMA_MODE_WRITE = 0x48;
+
+               return 1;
+       }
+
+       return 0;
+}
+
+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,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+};
index 5cc3279559a4e50275db5bc5b545c6e377fa7e5a..40e24c39ad0671e2ce945ccbff1240dd885ba2ba 100644 (file)
@@ -23,7 +23,7 @@ config PPC_CELL_NATIVE
 
 config PPC_IBM_CELL_BLADE
        bool "IBM Cell Blade"
-       depends on PPC_MULTIPLATFORM && PPC64
+       depends on PPC64 && PPC_BOOK3S
        select PPC_CELL_NATIVE
        select MMIO_NVRAM
        select PPC_UDBG_16550
@@ -31,7 +31,7 @@ config PPC_IBM_CELL_BLADE
 
 config PPC_CELLEB
        bool "Toshiba's Cell Reference Set 'Celleb' Architecture"
-       depends on PPC_MULTIPLATFORM && PPC64
+       depends on PPC64 && PPC_BOOK3S
        select PPC_CELL_NATIVE
        select HAS_TXX9_SERIAL
        select PPC_UDBG_BEAT
@@ -40,9 +40,14 @@ config PPC_CELLEB
 
 config PPC_CELL_QPACE
        bool "IBM Cell - QPACE"
-       depends on PPC_MULTIPLATFORM && PPC64
+       depends on PPC64 && PPC_BOOK3S
        select PPC_CELL_COMMON
 
+config AXON_MSI
+       bool
+       depends on PPC_IBM_CELL_BLADE && PCI_MSI
+       default y
+
 menu "Cell Broadband Engine options"
        depends on PPC_CELL
 
@@ -98,7 +103,7 @@ config PPC_IBM_CELL_RESETBUTTON
 
 config PPC_IBM_CELL_POWERBUTTON
        tristate "IBM Cell Blade power button"
-       depends on PPC_IBM_CELL_BLADE && PPC_PMI && INPUT_EVDEV
+       depends on PPC_IBM_CELL_BLADE && INPUT_EVDEV
        default y
        help
          Support Powerbutton on IBM Cell blades.
@@ -118,9 +123,9 @@ config CBE_CPUFREQ
          For details, take a look at <file:Documentation/cpu-freq/>.
          If you don't have such processor, say N
 
-config CBE_CPUFREQ_PMI
-       tristate "CBE frequency scaling using PMI interface"
-       depends on CBE_CPUFREQ && PPC_PMI && EXPERIMENTAL
+config CBE_CPUFREQ_PMI_ENABLE
+       bool "CBE frequency scaling using PMI interface"
+       depends on CBE_CPUFREQ && EXPERIMENTAL
        default n
        help
          Select this, if you want to use the PMI interface
@@ -128,6 +133,20 @@ config CBE_CPUFREQ_PMI
          processor will not only be able to run at lower speed,
          but also at lower core voltage.
 
+config CBE_CPUFREQ_PMI
+       tristate
+       depends on CBE_CPUFREQ_PMI_ENABLE
+       default CBE_CPUFREQ
+
+config PPC_PMI
+       tristate
+       default y
+       depends on CBE_CPUFREQ_PMI || PPC_IBM_CELL_POWERBUTTON
+       help
+         PMI (Platform Management Interrupt) is a way to
+         communicate with the BMC (Baseboard Management Controller).
+         It is used in some IBM Cell blades.
+
 config CBE_CPUFREQ_SPU_GOVERNOR
        tristate "CBE frequency scaling based on SPU usage"
        depends on SPU_FS && CPU_FREQ
index 43eccb27030121936175256f409804b55f4c82f5..83fafe92264143437eac0f9c5be256701658cb5d 100644 (file)
@@ -28,7 +28,7 @@ obj-$(CONFIG_SPU_BASE)                        += spu_callbacks.o spu_base.o \
                                           $(spu-manage-y) \
                                           spufs/
 
-obj-$(CONFIG_PCI_MSI)                  += axon_msi.o
+obj-$(CONFIG_AXON_MSI)                 += axon_msi.o
 
 # qpace setup
 obj-$(CONFIG_PPC_CELL_QPACE)           += qpace_setup.o
index 059cad6c3f694864901ce067d2409fc33ce6d6f8..5c1118e31940bf39d3a88926a16fc883c4f30d5f 100644 (file)
@@ -131,10 +131,10 @@ static const struct ppc_pci_io __devinitconst iowa_pci_io = {
 };
 
 static void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size,
-                                               unsigned long flags)
+                                 unsigned long flags, void *caller)
 {
        struct iowa_bus *bus;
-       void __iomem *res = __ioremap(addr, size, flags);
+       void __iomem *res = __ioremap_caller(addr, size, flags, caller);
        int busno;
 
        bus = iowa_pci_find(0, (unsigned long)addr);
index ee5033eddf019de7a31b5ac8c3de1ec25e646d55..5744527a7f2ac777bd9c94985c71e47ff4afd146 100644 (file)
@@ -74,7 +74,7 @@
 #define IOC_IO_ExcpStat_V              0x8000000000000000ul
 #define IOC_IO_ExcpStat_SPF_Mask       0x6000000000000000ul
 #define IOC_IO_ExcpStat_SPF_S          0x6000000000000000ul
-#define IOC_IO_ExcpStat_SPF_P          0x4000000000000000ul
+#define IOC_IO_ExcpStat_SPF_P          0x2000000000000000ul
 #define IOC_IO_ExcpStat_ADDR_Mask      0x00000007fffff000ul
 #define IOC_IO_ExcpStat_RW_Mask                0x0000000000000800ul
 #define IOC_IO_ExcpStat_IOID_Mask      0x00000000000007fful
@@ -247,17 +247,18 @@ static void tce_free_cell(struct iommu_table *tbl, long index, long npages)
 
 static irqreturn_t ioc_interrupt(int irq, void *data)
 {
-       unsigned long stat;
+       unsigned long stat, spf;
        struct cbe_iommu *iommu = data;
 
        stat = in_be64(iommu->xlate_regs + IOC_IO_ExcpStat);
+       spf = stat & IOC_IO_ExcpStat_SPF_Mask;
 
        /* Might want to rate limit it */
        printk(KERN_ERR "iommu: DMA exception 0x%016lx\n", stat);
        printk(KERN_ERR "  V=%d, SPF=[%c%c], RW=%s, IOID=0x%04x\n",
               !!(stat & IOC_IO_ExcpStat_V),
-              (stat & IOC_IO_ExcpStat_SPF_S) ? 'S' : ' ',
-              (stat & IOC_IO_ExcpStat_SPF_P) ? 'P' : ' ',
+              (spf == IOC_IO_ExcpStat_SPF_S) ? 'S' : ' ',
+              (spf == IOC_IO_ExcpStat_SPF_P) ? 'P' : ' ',
               (stat & IOC_IO_ExcpStat_RW_Mask) ? "Read" : "Write",
               (unsigned int)(stat & IOC_IO_ExcpStat_IOID_Mask));
        printk(KERN_ERR "  page=0x%016lx\n",
index be84e6a16b30cf36b170c7cc39834f7412cc85d2..c5ce02e84c8e421ae032fad6ad4ca569f03c8f6a 100644 (file)
@@ -81,16 +81,6 @@ static int __init qpace_publish_devices(void)
 }
 machine_subsys_initcall(qpace, qpace_publish_devices);
 
-extern int qpace_notify(struct device *dev)
-{
-       /* set dma_ops for of_platform bus */
-       if (dev->bus && dev->bus->name
-                       && !strcmp(dev->bus->name, "of_platform"))
-               set_dma_ops(dev, &dma_direct_ops);
-
-       return 0;
-}
-
 static void __init qpace_setup_arch(void)
 {
 #ifdef CONFIG_SPU_BASE
@@ -115,9 +105,6 @@ static void __init qpace_setup_arch(void)
 #ifdef CONFIG_DUMMY_CONSOLE
        conswitchp = &dummy_con;
 #endif
-
-       /* set notifier function */
-       platform_notify = &qpace_notify;
 }
 
 static int __init qpace_probe(void)
@@ -141,6 +128,8 @@ define_machine(qpace) {
        .power_off              = rtas_power_off,
        .halt                   = rtas_halt,
        .get_boot_time          = rtas_get_boot_time,
+       .get_rtc_time           = rtas_get_rtc_time,
+       .set_rtc_time           = rtas_set_rtc_time,
        .calibrate_decr         = generic_calibrate_decr,
        .progress               = qpace_progress,
        .init_IRQ               = iic_init_IRQ,
index e487ad68ac1113882db05b88142dd1542b67cdd4..9abd210d87c1362f831b7a50bae27bb78d6c31f7 100644 (file)
@@ -114,7 +114,7 @@ static inline void mm_needs_global_tlbie(struct mm_struct *mm)
        int nr = (NR_CPUS > 1) ? NR_CPUS : NR_CPUS + 1;
 
        /* Global TLBIE broadcast required with SPEs. */
-       __cpus_setall(&mm->cpu_vm_mask, nr);
+       bitmap_fill(cpumask_bits(mm_cpumask(mm)), nr);
 }
 
 void spu_associate_mm(struct spu *spu, struct mm_struct *mm)
index c8b1cd42905d92aaac51085e57b0686185fbff48..95d8dadf2d87f5daa01f1cdf9121fa4e06c6fdce 100644 (file)
@@ -39,60 +39,56 @@ int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea,
        unsigned long is_write;
        int ret;
 
-#if 0
-       if (!IS_VALID_EA(ea)) {
+       if (mm == NULL)
                return -EFAULT;
-       }
-#endif /* XXX */
-       if (mm == NULL) {
-               return -EFAULT;
-       }
-       if (mm->pgd == NULL) {
+
+       if (mm->pgd == NULL)
                return -EFAULT;
-       }
 
        down_read(&mm->mmap_sem);
+       ret = -EFAULT;
        vma = find_vma(mm, ea);
        if (!vma)
-               goto bad_area;
-       if (vma->vm_start <= ea)
-               goto good_area;
-       if (!(vma->vm_flags & VM_GROWSDOWN))
-               goto bad_area;
-       if (expand_stack(vma, ea))
-               goto bad_area;
-good_area:
+               goto out_unlock;
+
+       if (ea < vma->vm_start) {
+               if (!(vma->vm_flags & VM_GROWSDOWN))
+                       goto out_unlock;
+               if (expand_stack(vma, ea))
+                       goto out_unlock;
+       }
+
        is_write = dsisr & MFC_DSISR_ACCESS_PUT;
        if (is_write) {
                if (!(vma->vm_flags & VM_WRITE))
-                       goto bad_area;
+                       goto out_unlock;
        } else {
                if (dsisr & MFC_DSISR_ACCESS_DENIED)
-                       goto bad_area;
+                       goto out_unlock;
                if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
-                       goto bad_area;
+                       goto out_unlock;
        }
+
        ret = 0;
        *flt = handle_mm_fault(mm, vma, ea, is_write);
        if (unlikely(*flt & VM_FAULT_ERROR)) {
                if (*flt & VM_FAULT_OOM) {
                        ret = -ENOMEM;
-                       goto bad_area;
+                       goto out_unlock;
                } else if (*flt & VM_FAULT_SIGBUS) {
                        ret = -EFAULT;
-                       goto bad_area;
+                       goto out_unlock;
                }
                BUG();
        }
+
        if (*flt & VM_FAULT_MAJOR)
                current->maj_flt++;
        else
                current->min_flt++;
-       up_read(&mm->mmap_sem);
-       return ret;
 
-bad_area:
+out_unlock:
        up_read(&mm->mmap_sem);
-       return -EFAULT;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(spu_handle_mm_fault);
index 6653ddbed0483c4679755ee23b132fbc57091cb3..db5398c0339f4a1bbb6bccaccf59c4cc97c6b9a3 100644 (file)
@@ -35,6 +35,8 @@ atomic_t nr_spu_contexts = ATOMIC_INIT(0);
 struct spu_context *alloc_spu_context(struct spu_gang *gang)
 {
        struct spu_context *ctx;
+       struct timespec ts;
+
        ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
        if (!ctx)
                goto out;
@@ -64,6 +66,8 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang)
        __spu_update_sched_info(ctx);
        spu_set_timeslice(ctx);
        ctx->stats.util_state = SPU_UTIL_IDLE_LOADED;
+       ktime_get_ts(&ts);
+       ctx->stats.tstamp = timespec_to_ns(&ts);
 
        atomic_inc(&nr_spu_contexts);
        goto out;
index 0da7f2bf5ee195320398cb7eb3ce07d86c0935e0..d6a519e6e1c1a0682efcb077e79178e0f1f425ce 100644 (file)
@@ -568,16 +568,17 @@ spufs_regs_write(struct file *file, const char __user *buffer,
        struct spu_lscsa *lscsa = ctx->csa.lscsa;
        int ret;
 
-       size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size);
-       if (size <= 0)
+       if (*pos >= sizeof(lscsa->gprs))
                return -EFBIG;
+
+       size = min_t(ssize_t, sizeof(lscsa->gprs) - *pos, size);
        *pos += size;
 
        ret = spu_acquire_saved(ctx);
        if (ret)
                return ret;
 
-       ret = copy_from_user(lscsa->gprs + *pos - size,
+       ret = copy_from_user((char *)lscsa->gprs + *pos - size,
                             buffer, size) ? -EFAULT : size;
 
        spu_release_saved(ctx);
@@ -623,10 +624,11 @@ spufs_fpcr_write(struct file *file, const char __user * buffer,
        struct spu_lscsa *lscsa = ctx->csa.lscsa;
        int ret;
 
-       size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size);
-       if (size <= 0)
+       if (*pos >= sizeof(lscsa->fpcr))
                return -EFBIG;
 
+       size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size);
+
        ret = spu_acquire_saved(ctx);
        if (ret)
                return ret;
@@ -2665,7 +2667,7 @@ static const struct file_operations spufs_ctx_fops = {
        .release        = single_release,
 };
 
-struct spufs_tree_descr spufs_dir_contents[] = {
+const struct spufs_tree_descr spufs_dir_contents[] = {
        { "capabilities", &spufs_caps_fops, 0444, },
        { "mem",  &spufs_mem_fops,  0666, LS_SIZE, },
        { "regs", &spufs_regs_fops,  0666, sizeof(struct spu_reg128[128]), },
@@ -2706,7 +2708,7 @@ struct spufs_tree_descr spufs_dir_contents[] = {
        {},
 };
 
-struct spufs_tree_descr spufs_dir_nosched_contents[] = {
+const struct spufs_tree_descr spufs_dir_nosched_contents[] = {
        { "capabilities", &spufs_caps_fops, 0444, },
        { "mem",  &spufs_mem_fops,  0666, LS_SIZE, },
        { "mbox", &spufs_mbox_fops, 0444, },
@@ -2731,12 +2733,12 @@ struct spufs_tree_descr spufs_dir_nosched_contents[] = {
        {},
 };
 
-struct spufs_tree_descr spufs_dir_debug_contents[] = {
+const struct spufs_tree_descr spufs_dir_debug_contents[] = {
        { ".ctx", &spufs_ctx_fops, 0444, },
        {},
 };
 
-struct spufs_coredump_reader spufs_coredump_read[] = {
+const struct spufs_coredump_reader spufs_coredump_read[] = {
        { "regs", __spufs_regs_read, NULL, sizeof(struct spu_reg128[128])},
        { "fpcr", __spufs_fpcr_read, NULL, sizeof(struct spu_reg128) },
        { "lslr", NULL, spufs_lslr_get, 19 },
index e309ef70a53140b4e156fbfb1f38f06863b7eee2..64f068540d0dab1f33c21e2518f8aef23040239c 100644 (file)
@@ -186,8 +186,9 @@ static int spufs_rmdir(struct inode *parent, struct dentry *dir)
        return simple_rmdir(parent, dir);
 }
 
-static int spufs_fill_dir(struct dentry *dir, struct spufs_tree_descr *files,
-                         int mode, struct spu_context *ctx)
+static int spufs_fill_dir(struct dentry *dir,
+               const struct spufs_tree_descr *files, int mode,
+               struct spu_context *ctx)
 {
        struct dentry *dentry, *tmp;
        int ret;
index c58bd36b0c5b1045c170c7135a2e30f884f204fa..4ddf769a64e589adbfdba180b86021b357730897 100644 (file)
@@ -117,6 +117,9 @@ static int spu_setup_isolated(struct spu_context *ctx)
                cond_resched();
        }
 
+       /* clear purge status */
+       out_be64(mfc_cntl, 0);
+
        /* put the SPE in kernel mode to allow access to the loader */
        sr1 = spu_mfc_sr1_get(ctx->spu);
        sr1 &= ~MFC_STATE1_PROBLEM_STATE_MASK;
index 3bf908e2873adb9216f48df40e0481787fb4bab3..ae31573bea4a3027377d9f13f77e1508e9cb30a1 100644 (file)
@@ -241,9 +241,9 @@ struct spufs_tree_descr {
        size_t size;
 };
 
-extern struct spufs_tree_descr spufs_dir_contents[];
-extern struct spufs_tree_descr spufs_dir_nosched_contents[];
-extern struct spufs_tree_descr spufs_dir_debug_contents[];
+extern const struct spufs_tree_descr spufs_dir_contents[];
+extern const struct spufs_tree_descr spufs_dir_nosched_contents[];
+extern const struct spufs_tree_descr spufs_dir_debug_contents[];
 
 /* system call implementation */
 extern struct spufs_calls spufs_calls;
@@ -358,7 +358,7 @@ struct spufs_coredump_reader {
        u64 (*get)(struct spu_context *ctx);
        size_t size;
 };
-extern struct spufs_coredump_reader spufs_coredump_read[];
+extern const struct spufs_coredump_reader spufs_coredump_read[];
 extern int spufs_coredump_num_notes;
 
 extern int spu_init_csa(struct spu_state *csa);
index 22b4b4e3b6f020e6e1625980f92dcd7c97cc7133..37d438bd5b7a10f29a9b40eafc8f2edf1cc5ffe1 100644 (file)
@@ -1,6 +1,6 @@
 config PPC_CHRP
        bool "Common Hardware Reference Platform (CHRP) based machines"
-       depends on PPC_MULTIPLATFORM && PPC32
+       depends on 6xx
        select MPIC
        select PPC_I8259
        select PPC_INDIRECT_PCI
index 130ff72d99dd4366bfe5062d3842e894f04b9883..039fc8e821997d3273e717db46001184f3f00917 100644 (file)
@@ -21,8 +21,8 @@
 #define PEGASOS2_SRAM_BASE                     (0xf2000000)
 #define PEGASOS2_SRAM_SIZE                     (256*1024)
 
-#define PEGASOS2_SRAM_BASE_ETH0                        (PEGASOS2_SRAM_BASE)
-#define PEGASOS2_SRAM_BASE_ETH1                        (PEGASOS2_SRAM_BASE_ETH0 + (PEGASOS2_SRAM_SIZE / 2) )
+#define PEGASOS2_SRAM_BASE_ETH_PORT0                   (PEGASOS2_SRAM_BASE)
+#define PEGASOS2_SRAM_BASE_ETH_PORT1                   (PEGASOS2_SRAM_BASE_ETH_PORT0 + (PEGASOS2_SRAM_SIZE / 2) )
 
 
 #define PEGASOS2_SRAM_RXRING_SIZE              (PEGASOS2_SRAM_SIZE/4)
@@ -47,75 +47,42 @@ static struct platform_device mv643xx_eth_shared_device = {
        .resource       = mv643xx_eth_shared_resources,
 };
 
-static struct resource mv643xx_eth0_resources[] = {
+static struct resource mv643xx_eth_port1_resources[] = {
        [0] = {
-               .name   = "eth0 irq",
+               .name   = "eth port1 irq",
                .start  = 9,
                .end    = 9,
                .flags  = IORESOURCE_IRQ,
        },
 };
 
-
-static struct mv643xx_eth_platform_data eth0_pd = {
-       .shared         = &mv643xx_eth_shared_device,
-       .port_number    = 0,
-
-       .tx_sram_addr = PEGASOS2_SRAM_BASE_ETH0,
-       .tx_sram_size = PEGASOS2_SRAM_TXRING_SIZE,
-       .tx_queue_size = PEGASOS2_SRAM_TXRING_SIZE/16,
-
-       .rx_sram_addr = PEGASOS2_SRAM_BASE_ETH0 + PEGASOS2_SRAM_TXRING_SIZE,
-       .rx_sram_size = PEGASOS2_SRAM_RXRING_SIZE,
-       .rx_queue_size = PEGASOS2_SRAM_RXRING_SIZE/16,
-};
-
-static struct platform_device eth0_device = {
-       .name           = MV643XX_ETH_NAME,
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(mv643xx_eth0_resources),
-       .resource       = mv643xx_eth0_resources,
-       .dev = {
-               .platform_data = &eth0_pd,
-       },
-};
-
-static struct resource mv643xx_eth1_resources[] = {
-       [0] = {
-               .name   = "eth1 irq",
-               .start  = 9,
-               .end    = 9,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct mv643xx_eth_platform_data eth1_pd = {
+static struct mv643xx_eth_platform_data eth_port1_pd = {
        .shared         = &mv643xx_eth_shared_device,
        .port_number    = 1,
+       .phy_addr       = MV643XX_ETH_PHY_ADDR(7),
 
-       .tx_sram_addr = PEGASOS2_SRAM_BASE_ETH1,
+       .tx_sram_addr = PEGASOS2_SRAM_BASE_ETH_PORT1,
        .tx_sram_size = PEGASOS2_SRAM_TXRING_SIZE,
        .tx_queue_size = PEGASOS2_SRAM_TXRING_SIZE/16,
 
-       .rx_sram_addr = PEGASOS2_SRAM_BASE_ETH1 + PEGASOS2_SRAM_TXRING_SIZE,
+       .rx_sram_addr = PEGASOS2_SRAM_BASE_ETH_PORT1 + PEGASOS2_SRAM_TXRING_SIZE,
        .rx_sram_size = PEGASOS2_SRAM_RXRING_SIZE,
        .rx_queue_size = PEGASOS2_SRAM_RXRING_SIZE/16,
 };
 
-static struct platform_device eth1_device = {
+static struct platform_device eth_port1_device = {
        .name           = MV643XX_ETH_NAME,
        .id             = 1,
-       .num_resources  = ARRAY_SIZE(mv643xx_eth1_resources),
-       .resource       = mv643xx_eth1_resources,
+       .num_resources  = ARRAY_SIZE(mv643xx_eth_port1_resources),
+       .resource       = mv643xx_eth_port1_resources,
        .dev = {
-               .platform_data = &eth1_pd,
+               .platform_data = &eth_port1_pd,
        },
 };
 
 static struct platform_device *mv643xx_eth_pd_devs[] __initdata = {
        &mv643xx_eth_shared_device,
-       &eth0_device,
-       &eth1_device,
+       &eth_port1_device,
 };
 
 /***********/
@@ -191,15 +158,10 @@ static int __init mv643xx_eth_add_pds(void)
 
                if ( Enable_SRAM() < 0)
                {
-                       eth0_pd.tx_sram_addr = 0;
-                       eth0_pd.tx_sram_size = 0;
-                       eth0_pd.rx_sram_addr = 0;
-                       eth0_pd.rx_sram_size = 0;
-
-                       eth1_pd.tx_sram_addr = 0;
-                       eth1_pd.tx_sram_size = 0;
-                       eth1_pd.rx_sram_addr = 0;
-                       eth1_pd.rx_sram_size = 0;
+                       eth_port1_pd.tx_sram_addr = 0;
+                       eth_port1_pd.tx_sram_size = 0;
+                       eth_port1_pd.rx_sram_addr = 0;
+                       eth_port1_pd.rx_sram_size = 0;
 
 #ifdef BE_VERBOSE
                        printk("Pegasos II/Marvell MV64361: Can't enable the "
index 272d79a8d2896ade7f8f36e22f2b6279077f6793..cd4ad9aea760d966505a977d9d92e5a7f1f33e38 100644 (file)
@@ -472,7 +472,6 @@ static void __init chrp_find_openpic(void)
 #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON)
 static struct irqaction xmon_irqaction = {
        .handler = xmon_irq,
-       .mask = CPU_MASK_NONE,
        .name = "XMON break",
 };
 #endif
index 4f9f8184d164146a577727e67ab1999f74a9e963..291ac9d8cbee09d4966fa0a46b846bebdb2c71df 100644 (file)
@@ -1,6 +1,6 @@
 config EMBEDDED6xx
        bool "Embedded 6xx/7xx/7xxx-based boards"
-       depends on PPC32 && BROKEN_ON_SMP && PPC_MULTIPLATFORM
+       depends on 6xx && BROKEN_ON_SMP
 
 config LINKSTATION
        bool "Linkstation / Kurobox(HG) from Buffalo"
index 7ddd0a2c80276e3538088dc6e290a881285e2788..647e87787437e43d058278a078ac52372410b2fb 100644 (file)
@@ -1,6 +1,6 @@
 config PPC_ISERIES
        bool "IBM Legacy iSeries"
-       depends on PPC_MULTIPLATFORM && PPC64
+       depends on PPC64 && PPC_BOOK3S
        select PPC_INDIRECT_IO
        select PPC_PCI_CHOICE if EMBEDDED
 
index 701d9297c207fac27848f1b96a2d9ceaa083d5cd..94f44475883685cdb6a6c2a940baac2c24c53622 100644 (file)
@@ -214,7 +214,7 @@ void __init iSeries_activate_IRQs()
        unsigned long flags;
 
        for_each_irq (irq) {
-               irq_desc_t *desc = get_irq_desc(irq);
+               struct irq_desc *desc = get_irq_desc(irq);
 
                if (desc && desc->chip && desc->chip->startup) {
                        spin_lock_irqsave(&desc->lock, flags);
index 24519b96d6ad07b22bf1d64cd419fb603076aa61..a6cd3394feaa4d5baa313a51475209ae0382cd98 100644 (file)
@@ -617,7 +617,7 @@ static void iseries_dedicated_idle(void)
 }
 
 static void __iomem *iseries_ioremap(phys_addr_t address, unsigned long size,
-                                    unsigned long flags)
+                                    unsigned long flags, void *caller)
 {
        return (void __iomem *)address;
 }
index a6467a5591fa921a3ac4faa0ea5b6450c08f5ea2..1ea621a94c3b37b7be099b5e54bb36fbee0c6dcc 100644 (file)
@@ -1,5 +1,5 @@
 config PPC_MAPLE
-       depends on PPC_MULTIPLATFORM && PPC64
+       depends on PPC64 && PPC_BOOK3S
        bool "Maple 970FX Evaluation Board"
        select PCI
        select MPIC
index 348e0619e3e53cd085e37c820b9732fde2e7ab94..a2aeb327d185a4c1d1e4bbb77c117f1a22558736 100644 (file)
@@ -1,5 +1,5 @@
 config PPC_PASEMI
-       depends on PPC_MULTIPLATFORM && PPC64
+       depends on PPC64 && PPC_BOOK3S
        bool "PA Semi SoC-based platforms"
        default n
        select MPIC
index 055990ca8ce6cb989d43c384fb3ca1c17502bed6..1e1a0873e1ddfe47c6427ebddecb024e17054291 100644 (file)
@@ -1,6 +1,6 @@
 config PPC_PMAC
        bool "Apple PowerMac based machines"
-       depends on PPC_MULTIPLATFORM
+       depends on PPC_BOOK3S
        select MPIC
        select PCI
        select PPC_INDIRECT_PCI if PPC32
index beb38333b6d2b9fc22e3acd9559cb4112eb5cb2b..22ecfbe7183dec52e8f907a4ef9a8b23fdfe6a71 100644 (file)
@@ -86,6 +86,7 @@ static int (*g5_query_freq)(void);
 
 static DEFINE_MUTEX(g5_switch_mutex);
 
+static unsigned long transition_latency;
 
 #ifdef CONFIG_PMAC_SMU
 
@@ -357,7 +358,7 @@ static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
 
 static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-       policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+       policy->cpuinfo.transition_latency = transition_latency;
        policy->cur = g5_cpu_freqs[g5_query_freq()].frequency;
        /* secondary CPUs are tied to the primary one by the
         * cpufreq core if in the secondary policy we tell it that
@@ -500,6 +501,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
        g5_cpu_freqs[1].frequency = max_freq/2;
 
        /* Set callbacks */
+       transition_latency = 12000;
        g5_switch_freq = g5_scom_switch_freq;
        g5_query_freq = g5_scom_query_freq;
        freq_method = "SCOM";
@@ -675,6 +677,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
        g5_cpu_freqs[1].frequency = min_freq;
 
        /* Set callbacks */
+       transition_latency = CPUFREQ_ETERNAL;
        g5_switch_volt = g5_pfunc_switch_volt;
        g5_switch_freq = g5_pfunc_switch_freq;
        g5_query_freq = g5_pfunc_query_freq;
index 6d149ae8ffa71c02928e3bdf52d9b6573e65283b..7039d8f1d3baa1dfdd73e2f9ac80a15fb1c9fb11 100644 (file)
@@ -266,7 +266,6 @@ static unsigned int pmac_pic_get_irq(void)
 static struct irqaction xmon_action = {
        .handler        = xmon_irq,
        .flags          = 0,
-       .mask           = CPU_MASK_NONE,
        .name           = "NMI - XMON"
 };
 #endif
@@ -274,7 +273,6 @@ static struct irqaction xmon_action = {
 static struct irqaction gatwick_cascade_action = {
        .handler        = gatwick_action,
        .flags          = IRQF_DISABLED,
-       .mask           = CPU_MASK_NONE,
        .name           = "cascade",
 };
 
index c44c89f5e532177fb005a3a647bb0dd5574f33c5..d622a8345aaa2029375e7a2fcebfac25797e43c5 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <linux/irq.h>
 
-extern struct hw_interrupt_type pmac_pic;
+extern struct irq_chip pmac_pic;
 
 extern void pmac_pic_init(void);
 extern int pmac_get_irq(void);
index 9b78f5300c2478196287f78f9d7ccdbf28f71c4d..45936c9ed0ec5a1db19ee11d84facdcd85412740 100644 (file)
@@ -746,4 +746,7 @@ define_machine(powermac) {
 #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64)
        .cpu_die                = pmac_cpu_die,
 #endif
+#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32)
+       .cpu_die                = generic_mach_cpu_die,
+#endif
 };
index bd8817b00fa4a80f3d2ab4649e6ef917ec9db8aa..cf1dbe758890df60d441cfbd79421db63e40834f 100644 (file)
@@ -385,7 +385,6 @@ static void __init psurge_dual_sync_tb(int cpu_nr)
 static struct irqaction psurge_irqaction = {
        .handler = psurge_primary_intr,
        .flags = IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "primary IPI",
 };
 
index 29d411279b0cbbde12e7c93cd6524b6b27fd8365..bf8330ef2e768771a0be8004ee40b06a411d1c10 100644 (file)
@@ -1,6 +1,6 @@
 config PPC_PREP
        bool "PowerPC Reference Platform (PReP) based machines"
-       depends on PPC_MULTIPLATFORM && PPC32 && BROKEN
+       depends on 6xx && BROKEN
        select MPIC
        select PPC_I8259
        select PPC_INDIRECT_PCI
index 740ef56a1550c75af26e8cf551655e03906aa08e..dfe316b161a9a16c658632da5002135e5443af97 100644 (file)
@@ -1,6 +1,6 @@
 config PPC_PS3
        bool "Sony PS3"
-       depends on PPC_MULTIPLATFORM && PPC64
+       depends on PPC64 && PPC_BOOK3S
        select PPC_CELL
        select USB_ARCH_HAS_OHCI
        select USB_OHCI_LITTLE_ENDIAN
index d281cc0bca712fd24553ca34b9477d5c8e47b68e..9a2b6d948610c003485e38ded9e561f6514760fa 100644 (file)
@@ -311,7 +311,7 @@ static int __init ps3_mm_add_memory(void)
        result = add_memory(0, start_addr, map.r1.size);
 
        if (result) {
-               DBG("%s:%d: add_memory failed: (%d)\n",
+               pr_err("%s:%d: add_memory failed: (%d)\n",
                        __func__, __LINE__, result);
                return result;
        }
@@ -322,7 +322,7 @@ static int __init ps3_mm_add_memory(void)
        result = online_pages(start_pfn, nr_pages);
 
        if (result)
-               DBG("%s:%d: online_pages failed: (%d)\n",
+               pr_err("%s:%d: online_pages failed: (%d)\n",
                        __func__, __LINE__, result);
 
        return result;
index ddc2a307cd50c354e8488de69ec01048e171e94c..f0e6f28427bdb00bf30d0164bbc751ad964b4c3b 100644 (file)
@@ -1,5 +1,5 @@
 config PPC_PSERIES
-       depends on PPC_MULTIPLATFORM && PPC64
+       depends on PPC64 && PPC_BOOK3S
        bool "IBM pSeries & new (POWER5-based) iSeries"
        select MPIC
        select PPC_I8259
@@ -25,6 +25,11 @@ config EEH
        depends on PPC_PSERIES && PCI
        default y if !EMBEDDED
 
+config PSERIES_MSI
+       bool
+       depends on PCI_MSI && EEH
+       default y
+
 config SCANLOG
        tristate "Scanlog dump interface"
        depends on RTAS_PROC && PPC_PSERIES
@@ -63,3 +68,13 @@ config CMM
          makes sense for a system running in an LPAR where the unused pages
          will be reused for other LPARs. The interface allows firmware to
          balance memory across many LPARs.
+
+config DTL
+       bool "Dispatch Trace Log"
+       depends on PPC_SPLPAR && DEBUG_FS
+       help
+         SPLPAR machines can log hypervisor preempt & dispatch events to a
+         kernel buffer. Saying Y here will enable logging these events,
+         which are accessible through a debugfs file.
+
+         Say N if you are unsure.
index dfe574af2dc090bd5ce3aaac503fef02e8bddb91..790c0b872d4fc617594ba826dcbeab9fb1d3d837 100644 (file)
@@ -15,7 +15,7 @@ obj-$(CONFIG_SCANLOG) += scanlog.o
 obj-$(CONFIG_EEH)      += eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o
 obj-$(CONFIG_KEXEC)    += kexec.o
 obj-$(CONFIG_PCI)      += pci.o pci_dlpar.o
-obj-$(CONFIG_PCI_MSI)  += msi.o
+obj-$(CONFIG_PSERIES_MSI)      += msi.o
 
 obj-$(CONFIG_HOTPLUG_CPU)      += hotplug-cpu.o
 obj-$(CONFIG_MEMORY_HOTPLUG)   += hotplug-memory.o
@@ -25,3 +25,4 @@ obj-$(CONFIG_HVCS)            += hvcserver.o
 obj-$(CONFIG_HCALL_STATS)      += hvCall_inst.o
 obj-$(CONFIG_PHYP_DUMP)        += phyp_dump.o
 obj-$(CONFIG_CMM)              += cmm.o
+obj-$(CONFIG_DTL)              += dtl.o
diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c
new file mode 100644 (file)
index 0000000..fafcaa0
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Virtual Processor Dispatch Trace Log
+ *
+ * (C) Copyright IBM Corporation 2009
+ *
+ * Author: Jeremy Kerr <jk@ozlabs.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <asm/smp.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include "plpar_wrappers.h"
+
+/*
+ * Layout of entries in the hypervisor's DTL buffer. Although we don't
+ * actually access the internals of an entry (we only need to know the size),
+ * we might as well define it here for reference.
+ */
+struct dtl_entry {
+       u8      dispatch_reason;
+       u8      preempt_reason;
+       u16     processor_id;
+       u32     enqueue_to_dispatch_time;
+       u32     ready_to_enqueue_time;
+       u32     waiting_to_ready_time;
+       u64     timebase;
+       u64     fault_addr;
+       u64     srr0;
+       u64     srr1;
+};
+
+struct dtl {
+       struct dtl_entry        *buf;
+       struct dentry           *file;
+       int                     cpu;
+       int                     buf_entries;
+       u64                     last_idx;
+};
+static DEFINE_PER_CPU(struct dtl, dtl);
+
+/*
+ * Dispatch trace log event mask:
+ * 0x7: 0x1: voluntary virtual processor waits
+ *      0x2: time-slice preempts
+ *      0x4: virtual partition memory page faults
+ */
+static u8 dtl_event_mask = 0x7;
+
+
+/*
+ * Size of per-cpu log buffers. Default is just under 16 pages worth.
+ */
+static int dtl_buf_entries = (16 * 85);
+
+
+static int dtl_enable(struct dtl *dtl)
+{
+       unsigned long addr;
+       int ret, hwcpu;
+
+       /* only allow one reader */
+       if (dtl->buf)
+               return -EBUSY;
+
+       /* we need to store the original allocation size for use during read */
+       dtl->buf_entries = dtl_buf_entries;
+
+       dtl->buf = kmalloc_node(dtl->buf_entries * sizeof(struct dtl_entry),
+                       GFP_KERNEL, cpu_to_node(dtl->cpu));
+       if (!dtl->buf) {
+               printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n",
+                               __func__, dtl->cpu);
+               return -ENOMEM;
+       }
+
+       /* Register our dtl buffer with the hypervisor. The HV expects the
+        * buffer size to be passed in the second word of the buffer */
+       ((u32 *)dtl->buf)[1] = dtl->buf_entries * sizeof(struct dtl_entry);
+
+       hwcpu = get_hard_smp_processor_id(dtl->cpu);
+       addr = __pa(dtl->buf);
+       ret = register_dtl(hwcpu, addr);
+       if (ret) {
+               printk(KERN_WARNING "%s: DTL registration for cpu %d (hw %d) "
+                      "failed with %d\n", __func__, dtl->cpu, hwcpu, ret);
+               kfree(dtl->buf);
+               return -EIO;
+       }
+
+       /* set our initial buffer indices */
+       dtl->last_idx = lppaca[dtl->cpu].dtl_idx = 0;
+
+       /* ensure that our updates to the lppaca fields have occurred before
+        * we actually enable the logging */
+       smp_wmb();
+
+       /* enable event logging */
+       lppaca[dtl->cpu].dtl_enable_mask = dtl_event_mask;
+
+       return 0;
+}
+
+static void dtl_disable(struct dtl *dtl)
+{
+       int hwcpu = get_hard_smp_processor_id(dtl->cpu);
+
+       lppaca[dtl->cpu].dtl_enable_mask = 0x0;
+
+       unregister_dtl(hwcpu, __pa(dtl->buf));
+
+       kfree(dtl->buf);
+       dtl->buf = NULL;
+       dtl->buf_entries = 0;
+}
+
+/* file interface */
+
+static int dtl_file_open(struct inode *inode, struct file *filp)
+{
+       struct dtl *dtl = inode->i_private;
+       int rc;
+
+       rc = dtl_enable(dtl);
+       if (rc)
+               return rc;
+
+       filp->private_data = dtl;
+       return 0;
+}
+
+static int dtl_file_release(struct inode *inode, struct file *filp)
+{
+       struct dtl *dtl = inode->i_private;
+       dtl_disable(dtl);
+       return 0;
+}
+
+static ssize_t dtl_file_read(struct file *filp, char __user *buf, size_t len,
+               loff_t *pos)
+{
+       int rc, cur_idx, last_idx, n_read, n_req, read_size;
+       struct dtl *dtl;
+
+       if ((len % sizeof(struct dtl_entry)) != 0)
+               return -EINVAL;
+
+       dtl = filp->private_data;
+
+       /* requested number of entries to read */
+       n_req = len / sizeof(struct dtl_entry);
+
+       /* actual number of entries read */
+       n_read = 0;
+
+       cur_idx = lppaca[dtl->cpu].dtl_idx;
+       last_idx = dtl->last_idx;
+
+       if (cur_idx - last_idx > dtl->buf_entries) {
+               pr_debug("%s: hv buffer overflow for cpu %d, samples lost\n",
+                               __func__, dtl->cpu);
+       }
+
+       cur_idx  %= dtl->buf_entries;
+       last_idx %= dtl->buf_entries;
+
+       /* read the tail of the buffer if we've wrapped */
+       if (last_idx > cur_idx) {
+               read_size = min(n_req, dtl->buf_entries - last_idx);
+
+               rc = copy_to_user(buf, &dtl->buf[last_idx],
+                               read_size * sizeof(struct dtl_entry));
+               if (rc)
+                       return -EFAULT;
+
+               last_idx = 0;
+               n_req -= read_size;
+               n_read += read_size;
+               buf += read_size * sizeof(struct dtl_entry);
+       }
+
+       /* .. and now the head */
+       read_size = min(n_req, cur_idx - last_idx);
+       rc = copy_to_user(buf, &dtl->buf[last_idx],
+                       read_size * sizeof(struct dtl_entry));
+       if (rc)
+               return -EFAULT;
+
+       n_read += read_size;
+       dtl->last_idx += n_read;
+
+       return n_read * sizeof(struct dtl_entry);
+}
+
+static struct file_operations dtl_fops = {
+       .open           = dtl_file_open,
+       .release        = dtl_file_release,
+       .read           = dtl_file_read,
+       .llseek         = no_llseek,
+};
+
+static struct dentry *dtl_dir;
+
+static int dtl_setup_file(struct dtl *dtl)
+{
+       char name[10];
+
+       sprintf(name, "cpu-%d", dtl->cpu);
+
+       dtl->file = debugfs_create_file(name, 0400, dtl_dir, dtl, &dtl_fops);
+       if (!dtl->file)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static int dtl_init(void)
+{
+       struct dentry *event_mask_file, *buf_entries_file;
+       int rc, i;
+
+       if (!firmware_has_feature(FW_FEATURE_SPLPAR))
+               return -ENODEV;
+
+       /* set up common debugfs structure */
+
+       rc = -ENOMEM;
+       dtl_dir = debugfs_create_dir("dtl", powerpc_debugfs_root);
+       if (!dtl_dir) {
+               printk(KERN_WARNING "%s: can't create dtl root dir\n",
+                               __func__);
+               goto err;
+       }
+
+       event_mask_file = debugfs_create_x8("dtl_event_mask", 0600,
+                               dtl_dir, &dtl_event_mask);
+       buf_entries_file = debugfs_create_u32("dtl_buf_entries", 0600,
+                               dtl_dir, &dtl_buf_entries);
+
+       if (!event_mask_file || !buf_entries_file) {
+               printk(KERN_WARNING "%s: can't create dtl files\n", __func__);
+               goto err_remove_dir;
+       }
+
+       /* set up the per-cpu log structures */
+       for_each_possible_cpu(i) {
+               struct dtl *dtl = &per_cpu(dtl, i);
+               dtl->cpu = i;
+
+               rc = dtl_setup_file(dtl);
+               if (rc)
+                       goto err_remove_dir;
+       }
+
+       return 0;
+
+err_remove_dir:
+       debugfs_remove_recursive(dtl_dir);
+err:
+       return rc;
+}
+arch_initcall(dtl_init);
index 0ad56ff7b4a04cdd2c024fd4414a39d0f6ac5196..380420f8c4001925eb53e679964d903d5031d3f0 100644 (file)
@@ -79,6 +79,40 @@ static int irq_in_use(unsigned int irq)
        return rc;
 }
 
+/**
+ * eeh_disable_irq - disable interrupt for the recovering device
+ */
+static void eeh_disable_irq(struct pci_dev *dev)
+{
+       struct device_node *dn = pci_device_to_OF_node(dev);
+
+       /* Don't disable MSI and MSI-X interrupts. They are
+        * effectively disabled by the DMA Stopped state
+        * when an EEH error occurs.
+       */
+       if (dev->msi_enabled || dev->msix_enabled)
+               return;
+
+       if (!irq_in_use(dev->irq))
+               return;
+
+       PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED;
+       disable_irq_nosync(dev->irq);
+}
+
+/**
+ * eeh_enable_irq - enable interrupt for the recovering device
+ */
+static void eeh_enable_irq(struct pci_dev *dev)
+{
+       struct device_node *dn = pci_device_to_OF_node(dev);
+
+       if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
+               PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
+               enable_irq(dev->irq);
+       }
+}
+
 /* ------------------------------------------------------- */
 /**
  * eeh_report_error - report pci error to each device driver
@@ -98,11 +132,8 @@ static void eeh_report_error(struct pci_dev *dev, void *userdata)
        if (!driver)
                return;
 
-       if (irq_in_use (dev->irq)) {
-               struct device_node *dn = pci_device_to_OF_node(dev);
-               PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED;
-               disable_irq_nosync(dev->irq);
-       }
+       eeh_disable_irq(dev);
+
        if (!driver->err_handler ||
            !driver->err_handler->error_detected)
                return;
@@ -147,15 +178,12 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
 {
        enum pci_ers_result rc, *res = userdata;
        struct pci_driver *driver = dev->driver;
-       struct device_node *dn = pci_device_to_OF_node(dev);
 
        if (!driver)
                return;
 
-       if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
-               PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
-               enable_irq(dev->irq);
-       }
+       eeh_enable_irq(dev);
+
        if (!driver->err_handler ||
            !driver->err_handler->slot_reset)
                return;
@@ -174,17 +202,14 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
 static void eeh_report_resume(struct pci_dev *dev, void *userdata)
 {
        struct pci_driver *driver = dev->driver;
-       struct device_node *dn = pci_device_to_OF_node(dev);
 
        dev->error_state = pci_channel_io_normal;
 
        if (!driver)
                return;
 
-       if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
-               PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
-               enable_irq(dev->irq);
-       }
+       eeh_enable_irq(dev);
+
        if (!driver->err_handler ||
            !driver->err_handler->resume)
                return;
@@ -208,15 +233,12 @@ static void eeh_report_failure(struct pci_dev *dev, void *userdata)
        if (!driver)
                return;
 
-       if (irq_in_use (dev->irq)) {
-               struct device_node *dn = pci_device_to_OF_node(dev);
-               PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED;
-               disable_irq_nosync(dev->irq);
-       }
-       if (!driver->err_handler)
-               return;
-       if (!driver->err_handler->error_detected)
+       eeh_disable_irq(dev);
+
+       if (!driver->err_handler ||
+           !driver->err_handler->error_detected)
                return;
+
        driver->err_handler->error_detected(dev, pci_channel_io_perm_failure);
 }
 
index f15222bbe136a1020de443d3ff6c434c152c8d4b..bf2e1ac41308edce15461fd6fb3aee4832ad83fd 100644 (file)
@@ -71,11 +71,13 @@ static int rtas_change_msi(struct pci_dn *pdn, u32 func, u32 num_irqs)
        } while (rtas_busy_delay(rc));
 
        /*
-        * If the RTAS call succeeded, check the number of irqs is actually
-        * what we asked for. If not, return an error.
+        * If the RTAS call succeeded, return the number of irqs allocated.
+        * If not, make sure we return a negative error code.
         */
-       if (rc == 0 && rtas_ret[0] != num_irqs)
-               rc = -ENOSPC;
+       if (rc == 0)
+               rc = rtas_ret[0];
+       else if (rc > 0)
+               rc = -rc;
 
        pr_debug("rtas_msi: ibm,change_msi(func=%d,num=%d), got %d rc = %d\n",
                 func, num_irqs, rtas_ret[0], rc);
@@ -91,7 +93,7 @@ static void rtas_disable_msi(struct pci_dev *pdev)
        if (!pdn)
                return;
 
-       if (rtas_change_msi(pdn, RTAS_CHANGE_FN, 0))
+       if (rtas_change_msi(pdn, RTAS_CHANGE_FN, 0) != 0)
                pr_debug("rtas_msi: Setting MSIs to 0 failed!\n");
 }
 
@@ -132,7 +134,7 @@ static void rtas_teardown_msi_irqs(struct pci_dev *pdev)
        rtas_disable_msi(pdev);
 }
 
-static int check_req_msi(struct pci_dev *pdev, int nvec)
+static int check_req(struct pci_dev *pdev, int nvec, char *prop_name)
 {
        struct device_node *dn;
        struct pci_dn *pdn;
@@ -144,26 +146,235 @@ static int check_req_msi(struct pci_dev *pdev, int nvec)
 
        dn = pdn->node;
 
-       req_msi = of_get_property(dn, "ibm,req#msi", NULL);
+       req_msi = of_get_property(dn, prop_name, NULL);
        if (!req_msi) {
-               pr_debug("rtas_msi: No ibm,req#msi on %s\n", dn->full_name);
+               pr_debug("rtas_msi: No %s on %s\n", prop_name, dn->full_name);
                return -ENOENT;
        }
 
        if (*req_msi < nvec) {
-               pr_debug("rtas_msi: ibm,req#msi requests < %d MSIs\n", nvec);
-               return -ENOSPC;
+               pr_debug("rtas_msi: %s requests < %d MSIs\n", prop_name, nvec);
+
+               if (*req_msi == 0) /* Be paranoid */
+                       return -ENOSPC;
+
+               return *req_msi;
        }
 
        return 0;
 }
 
+static int check_req_msi(struct pci_dev *pdev, int nvec)
+{
+       return check_req(pdev, nvec, "ibm,req#msi");
+}
+
+static int check_req_msix(struct pci_dev *pdev, int nvec)
+{
+       return check_req(pdev, nvec, "ibm,req#msi-x");
+}
+
+/* Quota calculation */
+
+static struct device_node *find_pe_total_msi(struct pci_dev *dev, int *total)
+{
+       struct device_node *dn;
+       const u32 *p;
+
+       dn = of_node_get(pci_device_to_OF_node(dev));
+       while (dn) {
+               p = of_get_property(dn, "ibm,pe-total-#msi", NULL);
+               if (p) {
+                       pr_debug("rtas_msi: found prop on dn %s\n",
+                               dn->full_name);
+                       *total = *p;
+                       return dn;
+               }
+
+               dn = of_get_next_parent(dn);
+       }
+
+       return NULL;
+}
+
+static struct device_node *find_pe_dn(struct pci_dev *dev, int *total)
+{
+       struct device_node *dn;
+
+       /* Found our PE and assume 8 at that point. */
+
+       dn = pci_device_to_OF_node(dev);
+       if (!dn)
+               return NULL;
+
+       dn = find_device_pe(dn);
+       if (!dn)
+               return NULL;
+
+       /* We actually want the parent */
+       dn = of_get_parent(dn);
+       if (!dn)
+               return NULL;
+
+       /* Hardcode of 8 for old firmwares */
+       *total = 8;
+       pr_debug("rtas_msi: using PE dn %s\n", dn->full_name);
+
+       return dn;
+}
+
+struct msi_counts {
+       struct device_node *requestor;
+       int num_devices;
+       int request;
+       int quota;
+       int spare;
+       int over_quota;
+};
+
+static void *count_non_bridge_devices(struct device_node *dn, void *data)
+{
+       struct msi_counts *counts = data;
+       const u32 *p;
+       u32 class;
+
+       pr_debug("rtas_msi: counting %s\n", dn->full_name);
+
+       p = of_get_property(dn, "class-code", NULL);
+       class = p ? *p : 0;
+
+       if ((class >> 8) != PCI_CLASS_BRIDGE_PCI)
+               counts->num_devices++;
+
+       return NULL;
+}
+
+static void *count_spare_msis(struct device_node *dn, void *data)
+{
+       struct msi_counts *counts = data;
+       const u32 *p;
+       int req;
+
+       if (dn == counts->requestor)
+               req = counts->request;
+       else {
+               /* We don't know if a driver will try to use MSI or MSI-X,
+                * so we just have to punt and use the larger of the two. */
+               req = 0;
+               p = of_get_property(dn, "ibm,req#msi", NULL);
+               if (p)
+                       req = *p;
+
+               p = of_get_property(dn, "ibm,req#msi-x", NULL);
+               if (p)
+                       req = max(req, (int)*p);
+       }
+
+       if (req < counts->quota)
+               counts->spare += counts->quota - req;
+       else if (req > counts->quota)
+               counts->over_quota++;
+
+       return NULL;
+}
+
+static int msi_quota_for_device(struct pci_dev *dev, int request)
+{
+       struct device_node *pe_dn;
+       struct msi_counts counts;
+       int total;
+
+       pr_debug("rtas_msi: calc quota for %s, request %d\n", pci_name(dev),
+                 request);
+
+       pe_dn = find_pe_total_msi(dev, &total);
+       if (!pe_dn)
+               pe_dn = find_pe_dn(dev, &total);
+
+       if (!pe_dn) {
+               pr_err("rtas_msi: couldn't find PE for %s\n", pci_name(dev));
+               goto out;
+       }
+
+       pr_debug("rtas_msi: found PE %s\n", pe_dn->full_name);
+
+       memset(&counts, 0, sizeof(struct msi_counts));
+
+       /* Work out how many devices we have below this PE */
+       traverse_pci_devices(pe_dn, count_non_bridge_devices, &counts);
+
+       if (counts.num_devices == 0) {
+               pr_err("rtas_msi: found 0 devices under PE for %s\n",
+                       pci_name(dev));
+               goto out;
+       }
+
+       counts.quota = total / counts.num_devices;
+       if (request <= counts.quota)
+               goto out;
+
+       /* else, we have some more calculating to do */
+       counts.requestor = pci_device_to_OF_node(dev);
+       counts.request = request;
+       traverse_pci_devices(pe_dn, count_spare_msis, &counts);
+
+       /* If the quota isn't an integer multiple of the total, we can
+        * use the remainder as spare MSIs for anyone that wants them. */
+       counts.spare += total % counts.num_devices;
+
+       /* Divide any spare by the number of over-quota requestors */
+       if (counts.over_quota)
+               counts.quota += counts.spare / counts.over_quota;
+
+       /* And finally clamp the request to the possibly adjusted quota */
+       request = min(counts.quota, request);
+
+       pr_debug("rtas_msi: request clamped to quota %d\n", request);
+out:
+       of_node_put(pe_dn);
+
+       return request;
+}
+
 static int rtas_msi_check_device(struct pci_dev *pdev, int nvec, int type)
 {
+       int quota, rc;
+
        if (type == PCI_CAP_ID_MSIX)
-               pr_debug("rtas_msi: MSI-X untested, trying anyway.\n");
+               rc = check_req_msix(pdev, nvec);
+       else
+               rc = check_req_msi(pdev, nvec);
+
+       if (rc)
+               return rc;
+
+       quota = msi_quota_for_device(pdev, nvec);
 
-       return check_req_msi(pdev, nvec);
+       if (quota && quota < nvec)
+               return quota;
+
+       return 0;
+}
+
+static int check_msix_entries(struct pci_dev *pdev)
+{
+       struct msi_desc *entry;
+       int expected;
+
+       /* There's no way for us to express to firmware that we want
+        * a discontiguous, or non-zero based, range of MSI-X entries.
+        * So we must reject such requests. */
+
+       expected = 0;
+       list_for_each_entry(entry, &pdev->msi_list, list) {
+               if (entry->msi_attrib.entry_nr != expected) {
+                       pr_debug("rtas_msi: bad MSI-X entries.\n");
+                       return -EINVAL;
+               }
+               expected++;
+       }
+
+       return 0;
 }
 
 static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
@@ -177,6 +388,9 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
        if (!pdn)
                return -ENODEV;
 
+       if (type == PCI_CAP_ID_MSIX && check_msix_entries(pdev))
+               return -EINVAL;
+
        /*
         * Try the new more explicit firmware interface, if that fails fall
         * back to the old interface. The old interface is known to never
@@ -185,21 +399,21 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
        if (type == PCI_CAP_ID_MSI) {
                rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec);
 
-               if (rc) {
+               if (rc < 0) {
                        pr_debug("rtas_msi: trying the old firmware call.\n");
                        rc = rtas_change_msi(pdn, RTAS_CHANGE_FN, nvec);
                }
        } else
                rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec);
 
-       if (rc) {
+       if (rc != nvec) {
                pr_debug("rtas_msi: rtas_change_msi() failed\n");
                return rc;
        }
 
        i = 0;
        list_for_each_entry(entry, &pdev->msi_list, list) {
-               hwirq = rtas_query_irq_number(pdn, i);
+               hwirq = rtas_query_irq_number(pdn, i++);
                if (hwirq < 0) {
                        pr_debug("rtas_msi: error (%d) getting hwirq\n", rc);
                        return hwirq;
@@ -234,8 +448,8 @@ static void rtas_msi_pci_irq_fixup(struct pci_dev *pdev)
        }
 
        /* No MSI -> MSIs can't have been assigned by fw, leave LSI */
-       if (check_req_msi(pdev, 1)) {
-               dev_dbg(&pdev->dev, "rtas_msi: no req#msi, nothing to do.\n");
+       if (check_req_msi(pdev, 1) && check_req_msix(pdev, 1)) {
+               dev_dbg(&pdev->dev, "rtas_msi: no req#msi/x, nothing to do.\n");
                return;
        }
 
index 5e1ed3d60ee501a3a78b03b82aa90e0ba9ffd25b..ad152a0e39469da2af3ed2cece1dad816dbadc80 100644 (file)
@@ -137,11 +137,9 @@ EXPORT_SYMBOL_GPL(pcibios_add_pci_devices);
 struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
 {
        struct pci_controller *phb;
-       int primary;
 
        pr_debug("PCI: Initializing new hotplug PHB %s\n", dn->full_name);
 
-       primary = list_empty(&hose_list);
        phb = pcibios_alloc_controller(dn);
        if (!phb)
                return NULL;
index d967c1893ab5f1a8093f3fea1225ff240124ec12..a24a6b2333b2388521989ac5ac2b38365a61e6ab 100644 (file)
@@ -43,6 +43,16 @@ static inline long register_slb_shadow(unsigned long cpu, unsigned long vpa)
        return vpa_call(0x3, cpu, vpa);
 }
 
+static inline long unregister_dtl(unsigned long cpu, unsigned long vpa)
+{
+       return vpa_call(0x6, cpu, vpa);
+}
+
+static inline long register_dtl(unsigned long cpu, unsigned long vpa)
+{
+       return vpa_call(0x2, cpu, vpa);
+}
+
 static inline long plpar_page_set_loaned(unsigned long vpa)
 {
        unsigned long cmo_page_sz = cmo_get_page_size();
index c591a25b0b0d816d7e3f3c206c205ece673ea871..b6f1b137d427e68de2ea6c4e95dfa63a30e80760 100644 (file)
@@ -468,9 +468,13 @@ static int do_update_property(char *buf, size_t bufsize)
 
                rc = blocking_notifier_call_chain(&pSeries_reconfig_chain,
                                                  action, value);
+               if (rc == NOTIFY_BAD) {
+                       rc = prom_update_property(np, oldprop, newprop);
+                       return -ENOMEM;
+               }
        }
 
-       return rc;
+       return 0;
 }
 
 /**
index 490473ce81030475fbfa6075a2c76612dcd48b0e..82424cd7e1287bcc009b81f2327b078229a6050f 100644 (file)
@@ -119,7 +119,6 @@ static irqreturn_t cpm_error_interrupt(int irq, void *dev)
 
 static struct irqaction cpm_error_irqaction = {
        .handler = cpm_error_interrupt,
-       .mask = CPU_MASK_NONE,
        .name = "error",
 };
 
index f1c3395633b9aedebda4c1979e6801f659c9fa40..fd969f0e31214615bec76854e79b7d67c86a3cd3 100644 (file)
@@ -52,6 +52,7 @@ cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor space */
  * the communication processor devices.
  */
 cpm2_map_t __iomem *cpm2_immr;
+EXPORT_SYMBOL(cpm2_immr);
 
 #define CPM_MAP_SIZE   (0x40000)       /* 256k - the PQ3 reserve this amount
                                           of space for CPM as it is larger
@@ -129,7 +130,8 @@ void __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src)
                brg -= 4;
        }
        bp += brg;
-       val = (((clk / rate) - 1) << 1) | CPM_BRG_EN | src;
+       /* Round the clock divider to the nearest integer. */
+       val = (((clk * 2 / rate) - 1) & ~1) | CPM_BRG_EN | src;
        if (div16)
                val |= CPM_BRG_DIV16;
 
index 00d3d17c84a386b8cdfa7529db8b57137c5ba6b0..e4b6d66d93dedfe610193950ac74021dc797048d 100644 (file)
@@ -56,7 +56,7 @@ void __init udbg_init_cpm(void)
 {
        if (cpm_udbg_txdesc) {
 #ifdef CONFIG_CPM2
-               setbat(1, 0xf0000000, 0xf0000000, 1024*1024, _PAGE_IO);
+               setbat(1, 0xf0000000, 0xf0000000, 1024*1024, PAGE_KERNEL_NCG);
 #endif
                udbg_putc = udbg_putc_cpm;
        }
index 9817f63723dd592d933c0dcf9de53b6a51805b8d..78021d8afc53dc7b5c7d50112eb70ca50d2dd320 100644 (file)
@@ -1,12 +1,16 @@
 /*
  * MPC83xx/85xx/86xx PCI/PCIE support routing.
  *
- * Copyright 2007,2008 Freescale Semiconductor, Inc
+ * Copyright 2007-2009 Freescale Semiconductor, Inc.
+ * Copyright 2008-2009 MontaVista Software, Inc.
  *
  * Initial author: Xianghua Xiao <x.xiao@freescale.com>
  * Recode: ZHANG WEI <wei.zhang@freescale.com>
  * Rewrite the routing for Frescale PCI and PCI Express
  *     Roy Zang <tie-fei.zang@freescale.com>
+ * MPC83xx PCI-Express support:
+ *     Tony Li <tony.li@freescale.com>
+ *     Anton Vorontsov <avorontsov@ru.mvista.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
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
 
+static int fsl_pcie_bus_fixup;
+
+static void __init quirk_fsl_pcie_header(struct pci_dev *dev)
+{
+       /* if we aren't a PCIe don't bother */
+       if (!pci_find_capability(dev, PCI_CAP_ID_EXP))
+               return;
+
+       dev->class = PCI_CLASS_BRIDGE_PCI << 8;
+       fsl_pcie_bus_fixup = 1;
+       return;
+}
+
+static int __init fsl_pcie_check_link(struct pci_controller *hose)
+{
+       u32 val;
+
+       early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val);
+       if (val < PCIE_LTSSM_L0)
+               return 1;
+       return 0;
+}
+
 #if defined(CONFIG_PPC_85xx) || defined(CONFIG_PPC_86xx)
 static int __init setup_one_atmu(struct ccsr_pci __iomem *pci,
        unsigned int index, const struct resource *res,
@@ -159,28 +186,6 @@ static void __init setup_pci_pcsrbar(struct pci_controller *hose)
 #endif
 }
 
-static int fsl_pcie_bus_fixup;
-
-static void __init quirk_fsl_pcie_header(struct pci_dev *dev)
-{
-       /* if we aren't a PCIe don't bother */
-       if (!pci_find_capability(dev, PCI_CAP_ID_EXP))
-               return ;
-
-       dev->class = PCI_CLASS_BRIDGE_PCI << 8;
-       fsl_pcie_bus_fixup = 1;
-       return ;
-}
-
-static int __init fsl_pcie_check_link(struct pci_controller *hose)
-{
-       u32 val;
-       early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val);
-       if (val < PCIE_LTSSM_L0)
-               return 1;
-       return 0;
-}
-
 void fsl_pcibios_fixup_bus(struct pci_bus *bus)
 {
        struct pci_controller *hose = (struct pci_controller *) bus->sysdata;
@@ -294,8 +299,184 @@ DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8610, quirk_fsl_pcie_header);
 #endif /* CONFIG_PPC_85xx || CONFIG_PPC_86xx */
 
 #if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x)
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8314E, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8314, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8315E, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8315, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8377E, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8377, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8378E, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8378, quirk_fsl_pcie_header);
+
+struct mpc83xx_pcie_priv {
+       void __iomem *cfg_type0;
+       void __iomem *cfg_type1;
+       u32 dev_base;
+};
+
+/*
+ * With the convention of u-boot, the PCIE outbound window 0 serves
+ * as configuration transactions outbound.
+ */
+#define PEX_OUTWIN0_BAR                0xCA4
+#define PEX_OUTWIN0_TAL                0xCA8
+#define PEX_OUTWIN0_TAH                0xCAC
+
+static int mpc83xx_pcie_exclude_device(struct pci_bus *bus, unsigned int devfn)
+{
+       struct pci_controller *hose = bus->sysdata;
+
+       if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       /*
+        * Workaround for the HW bug: for Type 0 configure transactions the
+        * PCI-E controller does not check the device number bits and just
+        * assumes that the device number bits are 0.
+        */
+       if (bus->number == hose->first_busno ||
+                       bus->primary == hose->first_busno) {
+               if (devfn & 0xf8)
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+       }
+
+       if (ppc_md.pci_exclude_device) {
+               if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+       }
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static void __iomem *mpc83xx_pcie_remap_cfg(struct pci_bus *bus,
+                                           unsigned int devfn, int offset)
+{
+       struct pci_controller *hose = bus->sysdata;
+       struct mpc83xx_pcie_priv *pcie = hose->dn->data;
+       u8 bus_no = bus->number - hose->first_busno;
+       u32 dev_base = bus_no << 24 | devfn << 16;
+       int ret;
+
+       ret = mpc83xx_pcie_exclude_device(bus, devfn);
+       if (ret)
+               return NULL;
+
+       offset &= 0xfff;
+
+       /* Type 0 */
+       if (bus->number == hose->first_busno)
+               return pcie->cfg_type0 + offset;
+
+       if (pcie->dev_base == dev_base)
+               goto mapped;
+
+       out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAL, dev_base);
+
+       pcie->dev_base = dev_base;
+mapped:
+       return pcie->cfg_type1 + offset;
+}
+
+static int mpc83xx_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
+                                   int offset, int len, u32 *val)
+{
+       void __iomem *cfg_addr;
+
+       cfg_addr = mpc83xx_pcie_remap_cfg(bus, devfn, offset);
+       if (!cfg_addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       switch (len) {
+       case 1:
+               *val = in_8(cfg_addr);
+               break;
+       case 2:
+               *val = in_le16(cfg_addr);
+               break;
+       default:
+               *val = in_le32(cfg_addr);
+               break;
+       }
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int mpc83xx_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
+                                    int offset, int len, u32 val)
+{
+       void __iomem *cfg_addr;
+
+       cfg_addr = mpc83xx_pcie_remap_cfg(bus, devfn, offset);
+       if (!cfg_addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       switch (len) {
+       case 1:
+               out_8(cfg_addr, val);
+               break;
+       case 2:
+               out_le16(cfg_addr, val);
+               break;
+       default:
+               out_le32(cfg_addr, val);
+               break;
+       }
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops mpc83xx_pcie_ops = {
+       .read = mpc83xx_pcie_read_config,
+       .write = mpc83xx_pcie_write_config,
+};
+
+static int __init mpc83xx_pcie_setup(struct pci_controller *hose,
+                                    struct resource *reg)
+{
+       struct mpc83xx_pcie_priv *pcie;
+       u32 cfg_bar;
+       int ret = -ENOMEM;
+
+       pcie = zalloc_maybe_bootmem(sizeof(*pcie), GFP_KERNEL);
+       if (!pcie)
+               return ret;
+
+       pcie->cfg_type0 = ioremap(reg->start, resource_size(reg));
+       if (!pcie->cfg_type0)
+               goto err0;
+
+       cfg_bar = in_le32(pcie->cfg_type0 + PEX_OUTWIN0_BAR);
+       if (!cfg_bar) {
+               /* PCI-E isn't configured. */
+               ret = -ENODEV;
+               goto err1;
+       }
+
+       pcie->cfg_type1 = ioremap(cfg_bar, 0x1000);
+       if (!pcie->cfg_type1)
+               goto err1;
+
+       WARN_ON(hose->dn->data);
+       hose->dn->data = pcie;
+       hose->ops = &mpc83xx_pcie_ops;
+
+       out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAH, 0);
+       out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAL, 0);
+
+       if (fsl_pcie_check_link(hose))
+               hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
+
+       return 0;
+err1:
+       iounmap(pcie->cfg_type0);
+err0:
+       kfree(pcie);
+       return ret;
+
+}
+
 int __init mpc83xx_add_bridge(struct device_node *dev)
 {
+       int ret;
        int len;
        struct pci_controller *hose;
        struct resource rsrc_reg;
@@ -303,6 +484,11 @@ int __init mpc83xx_add_bridge(struct device_node *dev)
        const int *bus_range;
        int primary;
 
+       if (!of_device_is_available(dev)) {
+               pr_warning("%s: disabled by the firmware.\n",
+                          dev->full_name);
+               return -ENODEV;
+       }
        pr_debug("Adding PCI host bridge %s\n", dev->full_name);
 
        /* Fetch host bridge registers address */
@@ -350,7 +536,14 @@ int __init mpc83xx_add_bridge(struct device_node *dev)
        hose->first_busno = bus_range ? bus_range[0] : 0;
        hose->last_busno = bus_range ? bus_range[1] : 0xff;
 
-       setup_indirect_pci(hose, rsrc_cfg.start, rsrc_cfg.start + 4, 0);
+       if (of_device_is_compatible(dev, "fsl,mpc8314-pcie")) {
+               ret = mpc83xx_pcie_setup(hose, &rsrc_reg);
+               if (ret)
+                       goto err0;
+       } else {
+               setup_indirect_pci(hose, rsrc_cfg.start,
+                                  rsrc_cfg.start + 4, 0);
+       }
 
        printk(KERN_INFO "Found FSL PCI host bridge at 0x%016llx. "
               "Firmware bus number: %d->%d\n",
@@ -365,5 +558,8 @@ int __init mpc83xx_add_bridge(struct device_node *dev)
        pci_process_bridge_OF_ranges(hose, dev, primary);
 
        return 0;
+err0:
+       pcibios_free_controller(hose);
+       return ret;
 }
 #endif /* CONFIG_PPC_83xx */
index 115cb16351fd97b3dfcac78fca07634f0f0ba8eb..afe8dbc964aa14cf3390dbd991878caeba1262d6 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/phy.h>
 #include <linux/phy_fixed.h>
@@ -328,6 +329,9 @@ static int __init fsl_usb_of_init(void)
                struct fsl_usb2_platform_data usb_data;
                const unsigned char *prop = NULL;
 
+               if (!of_device_is_available(np))
+                       continue;
+
                memset(&r, 0, sizeof(r));
                memset(&usb_data, 0, sizeof(usb_data));
 
@@ -413,115 +417,6 @@ err:
 
 arch_initcall(fsl_usb_of_init);
 
-static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk,
-                                  struct spi_board_info *board_infos,
-                                  unsigned int num_board_infos,
-                                  void (*activate_cs)(u8 cs, u8 polarity),
-                                  void (*deactivate_cs)(u8 cs, u8 polarity))
-{
-       struct device_node *np;
-       unsigned int i = 0;
-
-       for_each_compatible_node(np, type, compatible) {
-               int ret;
-               unsigned int j;
-               const void *prop;
-               struct resource res[2];
-               struct platform_device *pdev;
-               struct fsl_spi_platform_data pdata = {
-                       .activate_cs = activate_cs,
-                       .deactivate_cs = deactivate_cs,
-               };
-
-               memset(res, 0, sizeof(res));
-
-               pdata.sysclk = sysclk;
-
-               prop = of_get_property(np, "reg", NULL);
-               if (!prop)
-                       goto err;
-               pdata.bus_num = *(u32 *)prop;
-
-               prop = of_get_property(np, "cell-index", NULL);
-               if (prop)
-                       i = *(u32 *)prop;
-
-               prop = of_get_property(np, "mode", NULL);
-               if (prop && !strcmp(prop, "cpu-qe"))
-                       pdata.qe_mode = 1;
-
-               for (j = 0; j < num_board_infos; j++) {
-                       if (board_infos[j].bus_num == pdata.bus_num)
-                               pdata.max_chipselect++;
-               }
-
-               if (!pdata.max_chipselect)
-                       continue;
-
-               ret = of_address_to_resource(np, 0, &res[0]);
-               if (ret)
-                       goto err;
-
-               ret = of_irq_to_resource(np, 0, &res[1]);
-               if (ret == NO_IRQ)
-                       goto err;
-
-               pdev = platform_device_alloc("mpc83xx_spi", i);
-               if (!pdev)
-                       goto err;
-
-               ret = platform_device_add_data(pdev, &pdata, sizeof(pdata));
-               if (ret)
-                       goto unreg;
-
-               ret = platform_device_add_resources(pdev, res,
-                                                   ARRAY_SIZE(res));
-               if (ret)
-                       goto unreg;
-
-               ret = platform_device_add(pdev);
-               if (ret)
-                       goto unreg;
-
-               goto next;
-unreg:
-               platform_device_del(pdev);
-err:
-               pr_err("%s: registration failed\n", np->full_name);
-next:
-               i++;
-       }
-
-       return i;
-}
-
-int __init fsl_spi_init(struct spi_board_info *board_infos,
-                       unsigned int num_board_infos,
-                       void (*activate_cs)(u8 cs, u8 polarity),
-                       void (*deactivate_cs)(u8 cs, u8 polarity))
-{
-       u32 sysclk = -1;
-       int ret;
-
-#ifdef CONFIG_QUICC_ENGINE
-       /* SPI controller is either clocked from QE or SoC clock */
-       sysclk = get_brgfreq();
-#endif
-       if (sysclk == -1) {
-               sysclk = fsl_get_sys_freq();
-               if (sysclk == -1)
-                       return -ENODEV;
-       }
-
-       ret = of_fsl_spi_probe(NULL, "fsl,spi", sysclk, board_infos,
-                              num_board_infos, activate_cs, deactivate_cs);
-       if (!ret)
-               of_fsl_spi_probe("spi", "fsl_spi", sysclk, board_infos,
-                                num_board_infos, activate_cs, deactivate_cs);
-
-       return spi_register_board_info(board_infos, num_board_infos);
-}
-
 #if defined(CONFIG_PPC_85xx) || defined(CONFIG_PPC_86xx)
 static __be32 __iomem *rstcr;
 
index 9c744e4285a023c21fe7d7e12876e4443fc43a51..42381bb6cd5155297432fba52ff955af8989f05e 100644 (file)
@@ -4,6 +4,8 @@
 
 #include <asm/mmu.h>
 
+struct spi_device;
+
 extern phys_addr_t get_immrbase(void);
 #if defined(CONFIG_CPM2) || defined(CONFIG_QUICC_ENGINE) || defined(CONFIG_8xx)
 extern u32 get_brgfreq(void);
@@ -17,11 +19,6 @@ extern u32 fsl_get_sys_freq(void);
 struct spi_board_info;
 struct device_node;
 
-extern int fsl_spi_init(struct spi_board_info *board_infos,
-                       unsigned int num_board_infos,
-                       void (*activate_cs)(u8 cs, u8 polarity),
-                       void (*deactivate_cs)(u8 cs, u8 polarity));
-
 extern void fsl_rstcr_restart(char *cmd);
 
 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
index 9a89cd3e80a25d914c481c3d0067810cccc7941f..a86d3ce01ead98293dcb0e28a14bf943163b40a2 100644 (file)
@@ -568,8 +568,7 @@ static void ipic_ack_irq(unsigned int virq)
 
        spin_lock_irqsave(&ipic_lock, flags);
 
-       temp = ipic_read(ipic->regs, ipic_info[src].ack);
-       temp |= (1 << (31 - ipic_info[src].bit));
+       temp = 1 << (31 - ipic_info[src].bit);
        ipic_write(ipic->regs, ipic_info[src].ack, temp);
 
        /* mb() can't guarantee that ack is finished.  But it does finish
@@ -592,8 +591,7 @@ static void ipic_mask_irq_and_ack(unsigned int virq)
        temp &= ~(1 << (31 - ipic_info[src].bit));
        ipic_write(ipic->regs, ipic_info[src].mask, temp);
 
-       temp = ipic_read(ipic->regs, ipic_info[src].ack);
-       temp |= (1 << (31 - ipic_info[src].bit));
+       temp = 1 << (31 - ipic_info[src].bit);
        ipic_write(ipic->regs, ipic_info[src].ack, temp);
 
        /* mb() can't guarantee that ack is finished.  But it does finish
index f84217b8863a4e11d6b3bba3a7c1eb0a295ca6fb..5a32cbef9b6c25b2adb34b7165e12d9398b05587 100644 (file)
@@ -141,7 +141,7 @@ void msi_bitmap_free(struct msi_bitmap *bmp)
 #define check(x)       \
        if (!(x)) printk("msi_bitmap: test failed at line %d\n", __LINE__);
 
-void test_basics(void)
+void __init test_basics(void)
 {
        struct msi_bitmap bmp;
        int i, size = 512;
@@ -186,7 +186,7 @@ void test_basics(void)
        kfree(bmp.bitmap);
 }
 
-void test_of_node(void)
+void __init test_of_node(void)
 {
        u32 prop_data[] = { 10, 10, 25, 3, 40, 1, 100, 100, 200, 20 };
        const char *expected_str = "0-9,20-24,28-39,41-99,220-255";
@@ -234,7 +234,7 @@ void test_of_node(void)
        kfree(bmp.bitmap);
 }
 
-int msi_bitmap_selftest(void)
+int __init msi_bitmap_selftest(void)
 {
        printk(KERN_DEBUG "Running MSI bitmap self-tests ...\n");
 
index c858749263e019e0641af6475341740993077741..aaa915998eb630cdb0492427a67ac40816e67a68 100644 (file)
@@ -50,7 +50,7 @@ struct pmi_data {
 
 static struct pmi_data *data;
 
-static int pmi_irq_handler(int irq, void *dev_id)
+static irqreturn_t pmi_irq_handler(int irq, void *dev_id)
 {
        u8 type;
        int rc;
index 5558d932b4d5c87b84f5a3826577607fa5220514..6a2d473c345a35595a58e5a2a4b1dd637b3dbb84 100644 (file)
@@ -1839,6 +1839,8 @@ static int __init ppc4xx_pci_find_bridges(void)
 {
        struct device_node *np;
 
+       ppc_pci_flags |= PPC_PCI_ENABLE_PROC_DOMAINS | PPC_PCI_COMPAT_DOMAIN_0;
+
 #ifdef CONFIG_PPC4xx_PCI_EXPRESS
        for_each_compatible_node(np, NULL, "ibm,plb-pciex")
                ppc4xx_probe_pciex_bridge(np);
index 2a8af5e16345d45f778e657a2f4c24363946edf3..dcb667c4375af26cb873710fde1bd0508ee18b35 100644 (file)
@@ -72,6 +72,9 @@ config PGSTE
 config VIRT_CPU_ACCOUNTING
        def_bool y
 
+config ARCH_SUPPORTS_DEBUG_PAGEALLOC
+       def_bool y
+
 mainmenu "Linux Kernel Configuration"
 
 config S390
index 4599fa06bd82a759d322dcd25a85bbfb6edfb369..2283933a9a93eef48b2de37aefe944540af03ff4 100644 (file)
@@ -6,12 +6,4 @@ config TRACE_IRQFLAGS_SUPPORT
 
 source "lib/Kconfig.debug"
 
-config DEBUG_PAGEALLOC
-       bool "Debug page memory allocations"
-       depends on DEBUG_KERNEL
-       help
-         Unmap pages from the kernel linear mapping after free_pages().
-         This results in a slowdown, but helps to find certain types of
-         memory corruptions.
-
 endmenu
index b1e892a43816974660b7fc73f8ecd085a83b41de..704dd396257b4c168b4082d5888c517ca7c378b4 100644 (file)
@@ -12,6 +12,8 @@
 
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/gfp.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <asm/ebcdic.h>
index 6dccb071aec3df5158f84b4b4d1afce3ce5cd354..619bf94b11f16f5214b15695fb7fd4e1331a7443 100644 (file)
@@ -456,6 +456,8 @@ struct ciw {
 #define CIO_OPER       0x0004
 /* Sick revalidation of device. */
 #define CIO_REVALIDATE 0x0008
+/* Device did not respond in time. */
+#define CIO_BOXED      0x0010
 
 /**
  * struct ccw_dev_id - unique identifier for ccw devices
index df84ae96915f5342b4f86a76d0ac09651e12c4bd..f3861b09ebb08a2ef2a1081f623f59429b1c6049 100644 (file)
@@ -172,6 +172,9 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
        return _raw_write_trylock_retry(rw);
 }
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
 
index b48e961a38f6ee08f0a12b5e7ffc1348fd7c4dcb..a3acd8e60aff70886b058afdc8bce0a441b60e62 100644 (file)
@@ -160,7 +160,7 @@ void release_thread(struct task_struct *dead_task)
 {
 }
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
+int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
                unsigned long unused,
                struct task_struct *p, struct pt_regs *regs)
 {
index a64e38841c496448139c2f1e3ac3c05e9c52a094..e27655b8a98ded83d3549e816e9255e2e2aaf059 100644 (file)
@@ -310,7 +310,8 @@ static struct platform_device camera_device = {
 
 static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
        .flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH |
-       SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8,
+       SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER |
+       SOCAM_DATAWIDTH_8,
 };
 
 static struct resource ceu_resources[] = {
index bc35b4cae6b3678f4e7062b8af0a5bf45c9e2194..4fd6a727873cd99dee8ff55337fb1e46b31e1b5b 100644 (file)
@@ -352,8 +352,9 @@ static int tw9910_power(struct device *dev, int mode)
 }
 
 static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
-       .flags = SOCAM_MASTER | SOCAM_DATAWIDTH_8 | SOCAM_PCLK_SAMPLE_RISING \
-       | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH,
+       .flags = SOCAM_MASTER | SOCAM_DATAWIDTH_8 | SOCAM_PCLK_SAMPLE_RISING
+       | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH
+       | SOCAM_DATA_ACTIVE_HIGH,
 };
 
 static struct resource migor_ceu_resources[] = {
index e793181d64da33395ee432189d112fd6b821c0cc..60283565f89b56a83582053a8624cf49fec801b3 100644 (file)
@@ -216,6 +216,9 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
        return (oldval > (RW_LOCK_BIAS - 1));
 }
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
index 066f0fba590e228e0467681dd8b1c4c5c22f6e36..a3f239545897ea5ed72b68714bfc1f8d2f9426c1 100644 (file)
@@ -33,7 +33,6 @@
 
 #define node_to_cpumask(node)  ((void)node, cpu_online_map)
 #define cpumask_of_node(node)  ((void)node, cpu_online_mask)
-#define node_to_first_cpu(node)        ((void)(node),0)
 
 #define pcibus_to_node(bus)    ((void)(bus), -1)
 #define pcibus_to_cpumask(bus) (pcibus_to_node(bus) == -1 ? \
index ddafbbbab2abe041dbdca39aa000dc4637f21137..694bc15f84fdd9ddbc14839999e7bb6c9f27b9e5 100644 (file)
@@ -170,7 +170,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 
 asmlinkage void ret_from_fork(void);
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(unsigned long clone_flags, unsigned long usp,
                unsigned long unused,
                struct task_struct *p, struct pt_regs *regs)
 {
index c90c7e5e5feee930fc641d3a97403958d2992ea3..96be839040f88f4fe5e606af0eb06ce7d0986626 100644 (file)
@@ -425,7 +425,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 
 asmlinkage void ret_from_fork(void);
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(unsigned long clone_flags, unsigned long usp,
                unsigned long unused,
                struct task_struct *p, struct pt_regs *regs)
 {
index 59d2a03e8b3c475763ff1d228e6177454f27fe1d..988c77c3723124507ca8f772c1139cefc0925140 100644 (file)
@@ -284,7 +284,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 static struct irqaction irq0  = {
        .handler = timer_interrupt,
        .flags = IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "timer",
 };
 
index c127293271e1f4072140e334697346bb0ab24779..9aa348658ae33905fe8b821bc3066d5e90a00d79 100644 (file)
@@ -109,7 +109,6 @@ static struct irqaction cmt_irq = {
        .name           = "timer",
        .handler        = cmt_timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-       .mask           = CPU_MASK_NONE,
 };
 
 static void cmt_clk_init(struct clk *clk)
index 9a77ae86b403132a0483c964d2bf83af53794f72..9b0ef01264794f6c2a04054b06a906dcb547c2c0 100644 (file)
@@ -115,7 +115,6 @@ static struct irqaction mtu2_irq = {
        .name           = "timer",
        .handler        = mtu2_timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-       .mask           = CPU_MASK_NONE,
 };
 
 static unsigned int divisors[] = { 1, 4, 16, 64, 1, 1, 256 };
index 10b5a6f17cc0a197341458412ba4d5bc906295ac..c5d3396f596012941853134d726244f504887939 100644 (file)
@@ -162,7 +162,6 @@ static struct irqaction tmu0_irq = {
        .name           = "periodic/oneshot timer",
        .handler        = tmu_timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-       .mask           = CPU_MASK_NONE,
 };
 
 static void __init tmu_clk_init(struct clk *clk)
index c3ea215334f60cd372b158efded8bb87502d1cfb..cc12cd48bbc51a41bc157681de49a2b1eeb102d3 100644 (file)
@@ -124,6 +124,9 @@ config ARCH_NO_VIRT_TO_BUS
 config OF
        def_bool y
 
+config ARCH_SUPPORTS_DEBUG_PAGEALLOC
+       def_bool y if SPARC64
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
index b8a15e271bfaacc2e6ce0e789fcb501b792f27b9..90d5fe223a7458953e866aa376ebd8e5591f244b 100644 (file)
@@ -22,14 +22,6 @@ config DEBUG_DCFLUSH
 config STACK_DEBUG
        bool "Stack Overflow Detection Support"
 
-config DEBUG_PAGEALLOC
-       bool "Debug page memory allocations"
-       depends on SPARC64 && DEBUG_KERNEL && !HIBERNATION
-       help
-         Unmap pages from the kernel linear mapping after free_pages().
-         This results in a large slowdown, but helps to find certain types
-         of memory corruptions.
-
 config MCOUNT
        bool
        depends on SPARC64
index 5693ab4826067056873803b6324b437e6275453f..666a73fef28dad76765a89eab95bb93c3eee232c 100644 (file)
@@ -121,8 +121,8 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str
         * local TLB.
         */
        cpu = smp_processor_id();
-       if (!ctx_valid || !cpu_isset(cpu, mm->cpu_vm_mask)) {
-               cpu_set(cpu, mm->cpu_vm_mask);
+       if (!ctx_valid || !cpumask_test_cpu(cpu, mm_cpumask(mm))) {
+               cpumask_set_cpu(cpu, mm_cpumask(mm));
                __flush_tlb_mm(CTX_HWBITS(mm->context),
                               SECONDARY_CONTEXT);
        }
@@ -141,8 +141,8 @@ static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm
        if (!CTX_VALID(mm->context))
                get_new_mmu_context(mm);
        cpu = smp_processor_id();
-       if (!cpu_isset(cpu, mm->cpu_vm_mask))
-               cpu_set(cpu, mm->cpu_vm_mask);
+       if (!cpumask_test_cpu(cpu, mm_cpumask(mm)))
+               cpumask_set_cpu(cpu, mm_cpumask(mm));
 
        load_secondary_context(mm);
        __flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT);
index 57224dd37b3a59967bdf5ee7e527f551ec700229..becb6bf353a9c36de3b40c3d7dcbc4b80a5e6c47 100644 (file)
@@ -35,7 +35,8 @@ extern cpumask_t cpu_core_map[NR_CPUS];
 extern int sparc64_multi_core;
 
 extern void arch_send_call_function_single_ipi(int cpu);
-extern void arch_send_call_function_ipi(cpumask_t mask);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
+#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
 
 /*
  *     General functions that each host system must provide.
index bf2d532593e3900ed9838fdf4334d0a2ae5b91db..46f91ab66a50d6ae792ef5d8d260cea30a54bd39 100644 (file)
@@ -177,6 +177,8 @@ static inline int __read_trylock(raw_rwlock_t *rw)
 #define __raw_write_unlock(rw) do { (rw)->lock = 0; } while(0)
 
 #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+#define __raw_read_lock_flags(rw, flags)   __raw_read_lock(rw)
+#define __raw_write_lock_flags(rw, flags)  __raw_write_lock(rw)
 
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
index c4d274d330e98b848489c3aeb64cf8516f6f7b4f..f6b2b92ad8d29a7864298024c00092dcb21d934c 100644 (file)
@@ -211,9 +211,11 @@ static int inline __write_trylock(raw_rwlock_t *lock)
 }
 
 #define __raw_read_lock(p)     __read_lock(p)
+#define __raw_read_lock_flags(p, f) __read_lock(p)
 #define __raw_read_trylock(p)  __read_trylock(p)
 #define __raw_read_unlock(p)   __read_unlock(p)
 #define __raw_write_lock(p)    __write_lock(p)
+#define __raw_write_lock_flags(p, f) __write_lock(p)
 #define __raw_write_unlock(p)  __write_unlock(p)
 #define __raw_write_trylock(p) __write_trylock(p)
 
index 79c1ae2b42a346ec11aa284a9719a926212741f3..751c8c17f5a037df797dbb148cf72d39f0521c93 100644 (file)
@@ -126,7 +126,7 @@ extern void flushw_all(void);
 #define switch_to(prev, next, last) do {                                               \
        SWITCH_ENTER(prev);                                                             \
        SWITCH_DO_LAZY_FPU(next);                                                       \
-       cpu_set(smp_processor_id(), next->active_mm->cpu_vm_mask);                      \
+       cpumask_set_cpu(smp_processor_id(), mm_cpumask(next->active_mm));               \
        __asm__ __volatile__(                                                           \
        "sethi  %%hi(here - 0x8), %%o7\n\t"                                             \
        "mov    %%g6, %%g3\n\t"                                                         \
index 5bc0b8fd63744f477f7ade478e42922175649c28..e5ea8d332421d1ad1441541c8e013d62d099e444 100644 (file)
@@ -28,11 +28,6 @@ static inline cpumask_t node_to_cpumask(int node)
 #define node_to_cpumask_ptr_next(v, node)      \
                           v = &(numa_cpumask_lookup_table[node])
 
-static inline int node_to_first_cpu(int node)
-{
-       return cpumask_first(cpumask_of_node(node));
-}
-
 struct pci_bus;
 #ifdef CONFIG_PCI
 extern int pcibus_to_node(struct pci_bus *pbus);
@@ -43,13 +38,9 @@ static inline int pcibus_to_node(struct pci_bus *pbus)
 }
 #endif
 
-#define pcibus_to_cpumask(bus) \
-       (pcibus_to_node(bus) == -1 ? \
-        CPU_MASK_ALL : \
-        node_to_cpumask(pcibus_to_node(bus)))
 #define cpumask_of_pcibus(bus) \
        (pcibus_to_node(bus) == -1 ? \
-        CPU_MASK_ALL_PTR : \
+        cpu_all_mask : \
         cpumask_of_node(pcibus_to_node(bus)))
 
 #define SD_NODE_INIT (struct sched_domain) {           \
@@ -89,7 +80,6 @@ static inline int pcibus_to_node(struct pci_bus *pbus)
 #define smt_capable()                          (sparc64_multi_core)
 #endif /* CONFIG_SMP */
 
-#define cpu_coregroup_map(cpu)                 (cpu_core_map[cpu])
 #define cpu_coregroup_mask(cpu)                        (&cpu_core_map[cpu])
 
 #endif /* _ASM_SPARC64_TOPOLOGY_H */
index 57c39843fb2a446c68849e5326496d4e5756cd0d..90350f838f05efa92a9739d4e4a03079f5f0ae55 100644 (file)
@@ -653,7 +653,7 @@ static void __cpuinit dr_cpu_data(struct ds_info *dp,
                if (cpu_list[i] == CPU_SENTINEL)
                        continue;
 
-               if (cpu_list[i] < NR_CPUS)
+               if (cpu_list[i] < nr_cpu_ids)
                        cpu_set(cpu_list[i], mask);
        }
 
index 44dd5ee64339219257a2457d85afd364f2526f58..ad800b80c718285e046d47d8c652c54aa22049da 100644 (file)
@@ -439,7 +439,6 @@ static int request_fast_irq(unsigned int irq,
        flush_cache_all();
 
        action->flags = irqflags;
-       cpus_clear(action->mask);
        action->name = devname;
        action->dev_id = NULL;
        action->next = NULL;
@@ -574,7 +573,6 @@ int request_irq(unsigned int irq,
 
        action->handler = handler;
        action->flags = irqflags;
-       cpus_clear(action->mask);
        action->name = devname;
        action->next = NULL;
        action->dev_id = dev_id;
index d0d6a515499ac952f487a49e389b2bdd5519bd02..5deabe921a47b6ebdcd5f6371faf7eaab3c135e4 100644 (file)
@@ -266,12 +266,12 @@ static int irq_choose_cpu(unsigned int virt_irq)
                spin_lock_irqsave(&irq_rover_lock, flags);
 
                while (!cpu_online(irq_rover)) {
-                       if (++irq_rover >= NR_CPUS)
+                       if (++irq_rover >= nr_cpu_ids)
                                irq_rover = 0;
                }
                cpuid = irq_rover;
                do {
-                       if (++irq_rover >= NR_CPUS)
+                       if (++irq_rover >= nr_cpu_ids)
                                irq_rover = 0;
                } while (!cpu_online(irq_rover));
 
index adaaed4ea2fb6821ca2a85c7afe61d2a07208f1d..00d034ea2164d63148d7b0ff04538420b163c513 100644 (file)
@@ -126,7 +126,6 @@ static int __init led_init(void)
        led = proc_create("led", 0, NULL, &led_proc_fops);
        if (!led)
                return -ENOMEM;
-       led->owner = THIS_MODULE;
 
        printk(KERN_INFO
               "led: version %s, Lars Kotthoff <metalhead@metalhead.ws>\n",
index 3f79f0c23a084d4a80ae572be79db9e0f747d66c..f0e6ed23a468ec10c6b7ba78ad8d5890295f7f82 100644 (file)
@@ -567,7 +567,7 @@ static void __init report_platform_properties(void)
                        max_cpu = NR_CPUS;
                }
                for (i = 0; i < max_cpu; i++)
-                       cpu_set(i, cpu_possible_map);
+                       set_cpu_possible(i, true);
        }
 #endif
 
index f3577223c8630e2d40002c72026755c72bb3bcfe..2c0cc72d295b079cfab695197eff38fcbd54d586 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/kprobes.h>
 #include <linux/kernel_stat.h>
+#include <linux/reboot.h>
 #include <linux/slab.h>
 #include <linux/kdebug.h>
 #include <linux/delay.h>
@@ -206,13 +207,33 @@ void nmi_adjust_hz(unsigned int new_hz)
 }
 EXPORT_SYMBOL_GPL(nmi_adjust_hz);
 
+static int nmi_shutdown(struct notifier_block *nb, unsigned long cmd, void *p)
+{
+       on_each_cpu(stop_watchdog, NULL, 1);
+       return 0;
+}
+
+static struct notifier_block nmi_reboot_notifier = {
+       .notifier_call = nmi_shutdown,
+};
+
 int __init nmi_init(void)
 {
+       int err;
+
        nmi_usable = 1;
 
        on_each_cpu(start_watchdog, NULL, 1);
 
-       return check_nmi_watchdog();
+       err = check_nmi_watchdog();
+       if (!err) {
+               err = register_reboot_notifier(&nmi_reboot_notifier);
+               if (err) {
+                       nmi_usable = 0;
+                       on_each_cpu(stop_watchdog, NULL, 1);
+               }
+       }
+       return err;
 }
 
 static int __init setup_nmi_watchdog(char *str)
index f4bee35a1b46a4dc5ff7446eba219190f0d39098..2830b415e2147ecfda36acc99d620408472128bd 100644 (file)
@@ -455,7 +455,7 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags,
  */
 extern void ret_from_fork(void);
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+int copy_thread(unsigned long clone_flags, unsigned long sp,
                unsigned long unused,
                struct task_struct *p, struct pt_regs *regs)
 {
index a73954b87f0a511ad7431b4b33f82216f22e2b7c..4041f94e7724f89de745f2be540342c7ab3ade40 100644 (file)
@@ -561,7 +561,7 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags,
  * Parent -->  %o0 == childs  pid, %o1 == 0
  * Child  -->  %o0 == parents pid, %o1 == 1
  */
-int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+int copy_thread(unsigned long clone_flags, unsigned long sp,
                unsigned long unused,
                struct task_struct *p, struct pt_regs *regs)
 {
index edecca7b811655546a7aba9d108414ae36c31703..ca55c7012f7751d4338a1c6fc1153124ef0f6966 100644 (file)
@@ -518,8 +518,8 @@ void __init of_fill_in_cpu_data(void)
                }
 
 #ifdef CONFIG_SMP
-               cpu_set(cpuid, cpu_present_map);
-               cpu_set(cpuid, cpu_possible_map);
+               set_cpu_present(cpuid, true);
+               set_cpu_possible(cpuid, true);
 #endif
        }
 
index 1e5ac4e282e1285030aaa43380b91c01b7bcff48..132d81fb26162657b0391a11e56e23fce9bf604d 100644 (file)
@@ -70,13 +70,12 @@ void __init smp_cpus_done(unsigned int max_cpus)
        extern void smp4m_smp_done(void);
        extern void smp4d_smp_done(void);
        unsigned long bogosum = 0;
-       int cpu, num;
+       int cpu, num = 0;
 
-       for (cpu = 0, num = 0; cpu < NR_CPUS; cpu++)
-               if (cpu_online(cpu)) {
-                       num++;
-                       bogosum += cpu_data(cpu).udelay_val;
-               }
+       for_each_online_cpu(cpu) {
+               num++;
+               bogosum += cpu_data(cpu).udelay_val;
+       }
 
        printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
                num, bogosum/(500000/HZ),
@@ -144,7 +143,7 @@ void smp_flush_tlb_all(void)
 void smp_flush_cache_mm(struct mm_struct *mm)
 {
        if(mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpumask_t cpu_mask = *mm_cpumask(mm);
                cpu_clear(smp_processor_id(), cpu_mask);
                if (!cpus_empty(cpu_mask))
                        xc1((smpfunc_t) BTFIXUP_CALL(local_flush_cache_mm), (unsigned long) mm);
@@ -155,12 +154,13 @@ void smp_flush_cache_mm(struct mm_struct *mm)
 void smp_flush_tlb_mm(struct mm_struct *mm)
 {
        if(mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpumask_t cpu_mask = *mm_cpumask(mm);
                cpu_clear(smp_processor_id(), cpu_mask);
                if (!cpus_empty(cpu_mask)) {
                        xc1((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_mm), (unsigned long) mm);
                        if(atomic_read(&mm->mm_users) == 1 && current->active_mm == mm)
-                               mm->cpu_vm_mask = cpumask_of_cpu(smp_processor_id());
+                               cpumask_copy(mm_cpumask(mm),
+                                            cpumask_of(smp_processor_id()));
                }
                local_flush_tlb_mm(mm);
        }
@@ -172,7 +172,7 @@ void smp_flush_cache_range(struct vm_area_struct *vma, unsigned long start,
        struct mm_struct *mm = vma->vm_mm;
 
        if (mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpumask_t cpu_mask = *mm_cpumask(mm);
                cpu_clear(smp_processor_id(), cpu_mask);
                if (!cpus_empty(cpu_mask))
                        xc3((smpfunc_t) BTFIXUP_CALL(local_flush_cache_range), (unsigned long) vma, start, end);
@@ -186,7 +186,7 @@ void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
        struct mm_struct *mm = vma->vm_mm;
 
        if (mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpumask_t cpu_mask = *mm_cpumask(mm);
                cpu_clear(smp_processor_id(), cpu_mask);
                if (!cpus_empty(cpu_mask))
                        xc3((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_range), (unsigned long) vma, start, end);
@@ -199,7 +199,7 @@ void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
        struct mm_struct *mm = vma->vm_mm;
 
        if(mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpumask_t cpu_mask = *mm_cpumask(mm);
                cpu_clear(smp_processor_id(), cpu_mask);
                if (!cpus_empty(cpu_mask))
                        xc2((smpfunc_t) BTFIXUP_CALL(local_flush_cache_page), (unsigned long) vma, page);
@@ -212,7 +212,7 @@ void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
        struct mm_struct *mm = vma->vm_mm;
 
        if(mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpumask_t cpu_mask = *mm_cpumask(mm);
                cpu_clear(smp_processor_id(), cpu_mask);
                if (!cpus_empty(cpu_mask))
                        xc2((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_page), (unsigned long) vma, page);
@@ -241,7 +241,7 @@ void smp_flush_page_to_ram(unsigned long page)
 
 void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
 {
-       cpumask_t cpu_mask = mm->cpu_vm_mask;
+       cpumask_t cpu_mask = *mm_cpumask(mm);
        cpu_clear(smp_processor_id(), cpu_mask);
        if (!cpus_empty(cpu_mask))
                xc2((smpfunc_t) BTFIXUP_CALL(local_flush_sig_insns), (unsigned long) mm, insn_addr);
@@ -332,8 +332,8 @@ void __init smp_setup_cpu_possible_map(void)
        instance = 0;
        while (!cpu_find_by_instance(instance, NULL, &mid)) {
                if (mid < NR_CPUS) {
-                       cpu_set(mid, cpu_possible_map);
-                       cpu_set(mid, cpu_present_map);
+                       set_cpu_possible(mid, true);
+                       set_cpu_present(mid, true);
                }
                instance++;
        }
@@ -351,8 +351,8 @@ void __init smp_prepare_boot_cpu(void)
                printk("boot cpu id != 0, this could work but is untested\n");
 
        current_thread_info()->cpu = cpuid;
-       cpu_set(cpuid, cpu_online_map);
-       cpu_set(cpuid, cpu_possible_map);
+       set_cpu_online(cpuid, true);
+       set_cpu_possible(cpuid, true);
 }
 
 int __cpuinit __cpu_up(unsigned int cpu)
index 79457f682b5ac05b693d185223ddd7ea8f9335b6..708e12a26b0528919065429d66c1bdf32ab4a5aa 100644 (file)
@@ -808,9 +808,9 @@ static void smp_start_sync_tick_client(int cpu)
 
 extern unsigned long xcall_call_function;
 
-void arch_send_call_function_ipi(cpumask_t mask)
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
 {
-       xcall_deliver((u64) &xcall_call_function, 0, 0, &mask);
+       xcall_deliver((u64) &xcall_call_function, 0, 0, mask);
 }
 
 extern unsigned long xcall_call_function_single;
@@ -850,7 +850,7 @@ static void tsb_sync(void *info)
 
 void smp_tsb_sync(struct mm_struct *mm)
 {
-       smp_call_function_mask(mm->cpu_vm_mask, tsb_sync, mm, 1);
+       smp_call_function_many(mm_cpumask(mm), tsb_sync, mm, 1);
 }
 
 extern unsigned long xcall_flush_tlb_mm;
@@ -1055,13 +1055,13 @@ void smp_flush_tlb_mm(struct mm_struct *mm)
        int cpu = get_cpu();
 
        if (atomic_read(&mm->mm_users) == 1) {
-               mm->cpu_vm_mask = cpumask_of_cpu(cpu);
+               cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));
                goto local_flush_and_out;
        }
 
        smp_cross_call_masked(&xcall_flush_tlb_mm,
                              ctx, 0, 0,
-                             &mm->cpu_vm_mask);
+                             mm_cpumask(mm));
 
 local_flush_and_out:
        __flush_tlb_mm(ctx, SECONDARY_CONTEXT);
@@ -1075,11 +1075,11 @@ void smp_flush_tlb_pending(struct mm_struct *mm, unsigned long nr, unsigned long
        int cpu = get_cpu();
 
        if (mm == current->mm && atomic_read(&mm->mm_users) == 1)
-               mm->cpu_vm_mask = cpumask_of_cpu(cpu);
+               cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));
        else
                smp_cross_call_masked(&xcall_flush_tlb_pending,
                                      ctx, nr, (unsigned long) vaddrs,
-                                     &mm->cpu_vm_mask);
+                                     mm_cpumask(mm));
 
        __flush_tlb_pending(ctx, nr, vaddrs);
 
index 3369fef5b4b3acd2749ddcbefd1befd37df2e15b..ab036a72de5a16460cdb8b548dbcf15bb2e04db6 100644 (file)
@@ -326,7 +326,6 @@ int sun4d_request_irq(unsigned int irq,
 
        action->handler = handler;
        action->flags = irqflags;
-       cpus_clear(action->mask);
        action->name = devname;
        action->next = NULL;
        action->dev_id = dev_id;
index 50afaed99c8a13d74b4e873eca58c5528563ba48..54fb02468f0d57ef00ce78c610609ba43d0c1702 100644 (file)
@@ -150,7 +150,7 @@ void __cpuinit smp4d_callin(void)
        spin_lock_irqsave(&sun4d_imsk_lock, flags);
        cc_set_imsk(cc_get_imsk() & ~0x4000); /* Allow PIL 14 as well */
        spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
-       cpu_set(cpuid, cpu_online_map);
+       set_cpu_online(cpuid, true);
 
 }
 
@@ -228,11 +228,10 @@ void __init smp4d_smp_done(void)
        /* setup cpu list for irq rotation */
        first = 0;
        prev = &first;
-       for (i = 0; i < NR_CPUS; i++)
-               if (cpu_online(i)) {
-                       *prev = i;
-                       prev = &cpu_data(i).next;
-               }
+       for_each_online_cpu(i) {
+               *prev = i;
+               prev = &cpu_data(i).next;
+       }
        *prev = first;
        local_flush_cache_all();
 
index 8040376c4890cc11c95e7c783f331abc7becb456..960b113d0006f4ff61de665c2383dd4b522a4622 100644 (file)
@@ -113,7 +113,7 @@ void __cpuinit smp4m_callin(void)
 
        local_irq_enable();
 
-       cpu_set(cpuid, cpu_online_map);
+       set_cpu_online(cpuid, true);
 }
 
 /*
@@ -186,11 +186,9 @@ void __init smp4m_smp_done(void)
        /* setup cpu list for irq rotation */
        first = 0;
        prev = &first;
-       for (i = 0; i < NR_CPUS; i++) {
-               if (cpu_online(i)) {
-                       *prev = i;
-                       prev = &cpu_data(i).next;
-               }
+       for_each_online_cpu(i) {
+               *prev = i;
+               prev = &cpu_data(i).next;
        }
        *prev = first;
        local_flush_cache_all();
index 752d0c9fb54469e464271bac8c56371197fd8938..7916feba6e4a03a0e1f5c203932e3cb856593b8f 100644 (file)
@@ -39,6 +39,7 @@ void *kmap_atomic(struct page *page, enum km_type type)
        if (!PageHighMem(page))
                return page_address(page);
 
+       debug_kmap_atomic(type);
        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 
index 00373ce2d8fbd872f838ece2de6cd49afd6e45a7..2c8dfeb7ab04b24634bba62532f6ac62a510059b 100644 (file)
@@ -1092,7 +1092,7 @@ static void __init numa_parse_mdesc_group_cpus(struct mdesc_handle *md,
                if (strcmp(name, "cpu"))
                        continue;
                id = mdesc_get_property(md, target, "id", NULL);
-               if (*id < NR_CPUS)
+               if (*id < nr_cpu_ids)
                        cpu_set(*id, *mask);
        }
 }
index fe7ed08390bb720e1c4be141aa5a072f58b843ec..06c9a7d98206f0256c23a281381bf2d6ab7ca441 100644 (file)
@@ -1425,7 +1425,7 @@ static void __init init_vac_layout(void)
                                min_line_size = vac_line_size;
                        //FIXME: cpus not contiguous!!
                        cpu++;
-                       if (cpu >= NR_CPUS || !cpu_online(cpu))
+                       if (cpu >= nr_cpu_ids || !cpu_online(cpu))
                                break;
 #else
                        break;
index 434224e2229ff6afde1556b5541b83200466c99e..434ba121e3c59a30009117fd6f1c146f516270a6 100644 (file)
@@ -757,7 +757,7 @@ static int uml_inetaddr_event(struct notifier_block *this, unsigned long event,
        void (*proc)(unsigned char *, unsigned char *, void *);
        unsigned char addr_buf[4], netmask_buf[4];
 
-       if (dev->open != uml_net_open)
+       if (dev->netdev_ops->ndo_open != uml_net_open)
                return NOTIFY_DONE;
 
        lp = netdev_priv(dev);
index 96b80b565eeb7950296d3633b85df8a8eeb7b16b..d8ba6153f9125bb2d749d850e8630bae6fb80a7b 100644 (file)
@@ -19,13 +19,3 @@ extern const struct net_user_info pcap_user_info;
 
 extern int pcap_user_read(int fd, void *buf, int len, struct pcap_data *pri);
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 9117609a575dd60bbcd5e2ae86950b3a4433567b..372a80c0556a275cdf5454b638efa7057d80007d 100644 (file)
@@ -18,13 +18,3 @@ extern void port_remove_dev(void *d);
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 98412aa6660722aa3d3d1138b4a49ba4abf81752..314d17725ce6b1c2892ce29f868118af6ddadde4 100644 (file)
@@ -11,13 +11,3 @@ extern void ssl_receive_char(int line, char ch);
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 505a3d5bea5eb5ce51b4c0a88cc11a8d55da6dad..6d8275f71fd40a0c752370ece8ae2c5548d4d110 100644 (file)
@@ -9,13 +9,3 @@
 extern void save_console_flags(void);
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 0a868118cf06b2bb2aece4afbbd89d18228d43dc..d42f826a8ab9f009fe5f06d5133e0e8d578799f1 100644 (file)
@@ -17,7 +17,6 @@
  * James McMechan
  */
 
-#define MAJOR_NR UBD_MAJOR
 #define UBD_SHIFT 4
 
 #include "linux/kernel.h"
@@ -115,7 +114,7 @@ static struct block_device_operations ubd_blops = {
 };
 
 /* Protected by ubd_lock */
-static int fake_major = MAJOR_NR;
+static int fake_major = UBD_MAJOR;
 static struct gendisk *ubd_gendisk[MAX_DEV];
 static struct gendisk *fake_gendisk[MAX_DEV];
 
@@ -299,7 +298,7 @@ static int ubd_setup_common(char *str, int *index_out, char **error_out)
                }
 
                mutex_lock(&ubd_lock);
-               if(fake_major != MAJOR_NR){
+               if (fake_major != UBD_MAJOR) {
                        *error_out = "Can't assign a fake major twice";
                        goto out1;
                }
@@ -818,13 +817,13 @@ static int ubd_disk_register(int major, u64 size, int unit,
        disk->first_minor = unit << UBD_SHIFT;
        disk->fops = &ubd_blops;
        set_capacity(disk, size / 512);
-       if(major == MAJOR_NR)
+       if (major == UBD_MAJOR)
                sprintf(disk->disk_name, "ubd%c", 'a' + unit);
        else
                sprintf(disk->disk_name, "ubd_fake%d", unit);
 
        /* sysfs register (not for ide fake devices) */
-       if (major == MAJOR_NR) {
+       if (major == UBD_MAJOR) {
                ubd_devs[unit].pdev.id   = unit;
                ubd_devs[unit].pdev.name = DRIVER_NAME;
                ubd_devs[unit].pdev.dev.release = ubd_device_release;
@@ -871,13 +870,13 @@ static int ubd_add(int n, char **error_out)
        ubd_dev->queue->queuedata = ubd_dev;
 
        blk_queue_max_hw_segments(ubd_dev->queue, MAX_SG);
-       err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]);
+       err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
        if(err){
                *error_out = "Failed to register device";
                goto out_cleanup;
        }
 
-       if(fake_major != MAJOR_NR)
+       if (fake_major != UBD_MAJOR)
                ubd_disk_register(fake_major, ubd_dev->size, n,
                                  &fake_gendisk[n]);
 
@@ -1059,10 +1058,10 @@ static int __init ubd_init(void)
        char *error;
        int i, err;
 
-       if (register_blkdev(MAJOR_NR, "ubd"))
+       if (register_blkdev(UBD_MAJOR, "ubd"))
                return -1;
 
-       if (fake_major != MAJOR_NR) {
+       if (fake_major != UBD_MAJOR) {
                char name[sizeof("ubd_nnn\0")];
 
                snprintf(name, sizeof(name), "ubd_%d", fake_major);
index f33a6e77b18619b9ef3245a216a251563b8da6b4..56b9c4aba423b0b57b64d049d85cb43260f67e5a 100644 (file)
@@ -10,13 +10,3 @@ extern int xterm_fd(int socket, int *pid_out);
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 62ddba6fc73393b82b39ac6569f0f0639577c873..272a81e0ce149853c03a1bed918232a957c82505 100644 (file)
@@ -8,13 +8,3 @@
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 2cf35c21d6940aee79c0dedfc5115c00e438247b..cf259de5153160be38b8d2073d0fe111e05a4f4c 100644 (file)
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 0d8bf33ffd4235287a2028b9c9d90fcf1e0dfc54..ddcd774fc2a06f3887d5a24ffaa25f2055edd034 100644 (file)
@@ -19,13 +19,3 @@ extern struct foo me;
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 9062a6e72241f60235b0c6f4c2bd41dd9c00ab6d..718984359f8c8876d84a2a902fa0b6fa6b4cb933 100644 (file)
@@ -60,13 +60,3 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 0446f456b428687b07ba689899cbefe4151d3fe7..084de4a9fc701412492b315e4162e693884beb8b 100644 (file)
@@ -134,13 +134,3 @@ static inline pmd_t pfn_pmd(pfn_t page_nr, pgprot_t pgprot)
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index ce9514f5721125cd1bc8a0c383933ada72c7907b..76078490c2581c92a2c40cc039419e918f8b6f9d 100644 (file)
@@ -20,13 +20,3 @@ extern int setup_signal_stack_si(unsigned long stack_top, int sig,
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 439b9a8149859ebac6da333313fcf005c22975c5..22673bcc273d1747c618d864e9d660d344ac1f4f 100644 (file)
@@ -10,13 +10,3 @@ extern int load_initrd(char *filename, void *buf, int size);
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index fba3895274f9ba9e2834cdb063b76f1cf295f5e9..b05d22f3d84e2450420a38adf8f641a106d5e236 100644 (file)
@@ -16,13 +16,3 @@ extern int um_request_irq(unsigned int irq, int fd, int type,
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index cb7e196d366b57ff4f4370e184d08274a71dc83e..69be0fd0ce4b93c2a920dbd8e7460f9102f84c07 100644 (file)
@@ -18,13 +18,3 @@ extern void register_remapper(struct remapper *info);
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index bb66517f0739e655057ff20dab63ed300cf48341..3845051f1b10a34bbd83a96bad9a23bab30b057d 100644 (file)
@@ -14,13 +14,3 @@ extern int kernel_fd;
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 499e5e95e60937c887c36a50ce91081e0de462bd..388ec0a3ea9b0f57cfffe0ad14eb411934069df5 100644 (file)
@@ -28,7 +28,7 @@ $(obj)/config.tmp: $(objtree)/.config FORCE
        $(call if_changed,quote1)
 
 quiet_cmd_quote1 = QUOTE   $@
-      cmd_quote1 = sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' \
+      cmd_quote1 = sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n",/' \
                   $< > $@
 
 $(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE
@@ -36,9 +36,9 @@ $(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE
 
 quiet_cmd_quote2 = QUOTE   $@
       cmd_quote2 = sed -e '/CONFIG/{'          \
-                 -e 's/"CONFIG"\;/""/'        \
+                 -e 's/"CONFIG"//'            \
                  -e 'r $(obj)/config.tmp'     \
                  -e 'a \'                     \
-                 -e '""\;'                    \
+                 -e '""'                      \
                  -e '}'                       \
                  $< > $@
index c062cbfe386e22a153ab43833bffa96932eac874..b7a43feafde773aeb4998675be30074ee5613c32 100644 (file)
@@ -7,11 +7,15 @@
 #include <stdlib.h>
 #include "init.h"
 
-static __initdata char *config = "CONFIG";
+static __initdata const char *config[] = {
+"CONFIG"
+};
 
 static int __init print_config(char *line, int *add)
 {
-       printf("%s", config);
+       int i;
+       for (i = 0; i < sizeof(config)/sizeof(config[0]); i++)
+               printf("%s", config[i]);
        exit(0);
 }
 
@@ -20,13 +24,3 @@ __uml_setup("--showconfig", print_config,
 "    Prints the config file that this UML binary was generated from.\n\n"
 );
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index a1c6d07cac3e46b2f3460e04729cf6a2ca203571..4a28a1568d856c7b1605743ca33c143921caacd4 100644 (file)
@@ -179,7 +179,7 @@ void fork_handler(void)
        userspace(&current->thread.regs.regs);
 }
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+int copy_thread(unsigned long clone_flags, unsigned long sp,
                unsigned long stack_top, struct task_struct * p,
                struct pt_regs *regs)
 {
index c4df705b835937f9256cafe43fcd92c9830eba59..a4625c7b2bf990a78dc49f5785b48393dba00baf 100644 (file)
@@ -127,7 +127,8 @@ int kernel_execve(const char *filename, char *const argv[], char *const envp[])
 
        fs = get_fs();
        set_fs(KERNEL_DS);
-       ret = um_execve(filename, argv, envp);
+       ret = um_execve((char *)filename, (char __user *__user *)argv,
+                       (char __user *__user *) envp);
        set_fs(fs);
 
        return ret;
index 183db26d01bf2050bddb5c7db862ed4dd2b6927d..02ee9adff54ad2a8913e94aee9bf927723194e58 100644 (file)
@@ -244,7 +244,7 @@ static void __init check_sysemu(void)
 
        if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
                   (void *) PTRACE_O_TRACESYSGOOD) < 0))
-               fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed");
+               fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed");
 
        while (1) {
                count++;
@@ -252,12 +252,12 @@ static void __init check_sysemu(void)
                        goto fail;
                CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
                if (n < 0)
-                       fatal_perror("check_ptrace : wait failed");
+                       fatal_perror("check_sysemu: wait failed");
 
                if (WIFSTOPPED(status) &&
                    (WSTOPSIG(status) == (SIGTRAP|0x80))) {
                        if (!count) {
-                               non_fatal("check_ptrace : SYSEMU_SINGLESTEP "
+                               non_fatal("check_sysemu: SYSEMU_SINGLESTEP "
                                          "doesn't singlestep");
                                goto fail;
                        }
@@ -271,7 +271,7 @@ static void __init check_sysemu(void)
                else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
                        count++;
                else {
-                       non_fatal("check_ptrace : expected SIGTRAP or "
+                       non_fatal("check_sysemu: expected SIGTRAP or "
                                  "(SIGTRAP | 0x80), got status = %d\n",
                                  status);
                        goto fail;
index 93fd723344e54fef2cc64c12b10023cc3538d61f..2a18a884ca1bcf903849b97457bf01bbe351bd61 100644 (file)
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 0cb4645cbeb8fc69ad454ddc328e91d3002bf5fc..ed47445f3905f9b71f4f5cbb367e45d4bba555f0 100644 (file)
@@ -199,13 +199,3 @@ static __inline__ __wsum csum_and_copy_to_user(const void *src,
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 00e5f5203eea337abd3a3e0ee115d6795ab0e4d3..c6260dd6ebb9f3338eee3b7f7242fe419e096b64 100644 (file)
@@ -9,6 +9,17 @@
 
 #define old_mmap old_mmap_i386
 
+#define ptregs_fork sys_fork
+#define ptregs_execve sys_execve
+#define ptregs_iopl sys_iopl
+#define ptregs_vm86old sys_vm86old
+#define ptregs_sigreturn sys_sigreturn
+#define ptregs_clone sys_clone
+#define ptregs_vm86 sys_vm86
+#define ptregs_rt_sigreturn sys_rt_sigreturn
+#define ptregs_sigaltstack sys_sigaltstack
+#define ptregs_vfork sys_vfork
+
 .section .rodata,"a"
 
 #include "../../x86/kernel/syscall_table_32.S"
index 42dd8fb6f2f94b844f4216d2f9f644ebf6a5e9cb..0f0f4e6fd334f9a5152758c7697728d7148ade6d 100644 (file)
@@ -14,13 +14,3 @@ struct sys_pt_regs {
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index f15fb25260ba0c9cc47be5c41cd6b512e464cf83..76b43161e7795415209463441a66ee12bfb01531 100644 (file)
@@ -8,13 +8,3 @@
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 4a1f46ef1ebc3e1cb1d3931f315ce2a0983b6570..5f6700c415584e5d54d9350d85e9848ee3772dc6 100644 (file)
@@ -8,13 +8,3 @@
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 373061c50129b8796e8deb05221e1528eb79e431..1c11aed9c719646795ddc2e45824ee8dac053170 100644 (file)
@@ -40,14 +40,3 @@ void shove_aux_table(unsigned long sp)
 }
 /* END stuff taken from arch/ppc/kernel/process.c */
 
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 8e71b47f2b8ed86f9bee12696b773c3e99f011e8..66ef155248f1d1b8365e511524d21c7067c5d888 100644 (file)
@@ -56,13 +56,3 @@ int peek_user(struct task_struct *child, long addr, long data)
        return put_user(tmp, (unsigned long *) data);
 }
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index ff0b9c077a13c037d6daf60ce7ae2ecf8afa04fb..224d2403c37bb243bbb47c364e725d690d8e44fc 100644 (file)
@@ -27,13 +27,3 @@ int ptrace_setregs(long pid, unsigned long *regs_in)
     }
     return 0;
 }
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index df2397dba3e5282f63b134cab7d59719b1b5461a..0e3230e937e14fd3260f5dad2d1e6167c0b3c975 100644 (file)
@@ -91,13 +91,3 @@ extern void shove_aux_table(unsigned long sp);
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index f20d965de9c72af3eb930b167825a09753623ab2..b7286f0a1e00dd40a7221e02322389b7e5812201 100644 (file)
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 679df351e19b6b82f06cf4c1f632732181f359cc..1ff81552251c7571d7b3fdda6a640d64def977f1 100644 (file)
@@ -41,13 +41,3 @@ int old_mmap(unsigned long addr, unsigned long len,
 
 #define LAST_ARCH_SYSCALL __NR_fadvise64
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 4bdc15c89eddd3ddd3109404313baf87cffdcd67..40694d0f3d15ab6d8db6f415c9c1509e722044f9 100644 (file)
@@ -2,13 +2,3 @@
 #include "asm/sigcontext.h"
 #include "sysdep/ptrace.h"
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 270ed9586b68542563e3d94cf8dc49d9d7a99256..6c083663b8d9d084d83587da921412ccbef3bd54 100644 (file)
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 35b5491d3e96b77888d035e84bae59d36dc44f72..8eb79c2d07d583d55835700c1bd6c7193156a008 100644 (file)
@@ -18,13 +18,3 @@ struct mod_arch_specific
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 3f59a0a4f156044eec4ffe943306428f0da2d99f..3f8df8abf34738cc28a7214a830f05b9276a7fb5 100644 (file)
@@ -14,12 +14,3 @@ unsigned long vm_data_default_flags = __VM_DATA_DEFAULT_FLAGS;
 unsigned long vm_data_default_flags32 = __VM_DATA_DEFAULT_FLAGS;
 unsigned long vm_force_exec32 = PROT_EXEC;
 
-/* Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 06c02c00d7d9b040a95c477570a66555325a3df7..748e50a1a15257ac6226eca13869b47e32a59de2 100644 (file)
@@ -40,6 +40,7 @@ config X86
        select HAVE_GENERIC_DMA_COHERENT if X86_32
        select HAVE_EFFICIENT_UNALIGNED_ACCESS
        select USER_STACKTRACE_SUPPORT
+       select HAVE_DMA_API_DEBUG
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_LZMA
@@ -164,6 +165,9 @@ config AUDIT_ARCH
 config ARCH_SUPPORTS_OPTIMIZED_INLINING
        def_bool y
 
+config ARCH_SUPPORTS_DEBUG_PAGEALLOC
+       def_bool y
+
 # Use the generic interrupt handling code in kernel/irq/:
 config GENERIC_HARDIRQS
        bool
@@ -786,6 +790,11 @@ config X86_MCE_AMD
           Additional support for AMD specific MCE features such as
           the DRAM Error Threshold.
 
+config X86_MCE_THRESHOLD
+       depends on X86_MCE_AMD || X86_MCE_INTEL
+       bool
+       default y
+
 config X86_MCE_NONFATAL
        tristate "Check for non-fatal errors on AMD Athlon/Duron / Intel Pentium 4"
        depends on X86_32 && X86_MCE
@@ -929,6 +938,12 @@ config X86_CPUID
          with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to
          /dev/cpu/31/cpuid.
 
+config X86_CPU_DEBUG
+       tristate "/sys/kernel/debug/x86/cpu/* - CPU Debug support"
+       ---help---
+         If you select this option, this will provide various x86 CPUs
+         information through debugfs.
+
 choice
        prompt "High Memory Support"
        default HIGHMEM4G if !X86_NUMAQ
@@ -1121,7 +1136,7 @@ config NUMA_EMU
 
 config NODES_SHIFT
        int "Maximum NUMA Nodes (as a power of 2)" if !MAXSMP
-       range 1 9   if X86_64
+       range 1 9
        default "9" if MAXSMP
        default "6" if X86_64
        default "4" if X86_NUMAQ
@@ -1429,7 +1444,7 @@ config CRASH_DUMP
 config KEXEC_JUMP
        bool "kexec jump (EXPERIMENTAL)"
        depends on EXPERIMENTAL
-       depends on KEXEC && HIBERNATION && X86_32
+       depends on KEXEC && HIBERNATION
        ---help---
          Jump between original kernel and kexeced kernel and invoke
          code in physical address mode via KEXEC
index a95eaf0e582ada3e141ee0ae35fa5d17eb056f1b..924e156a85abdf61627336e41e97283393e8709f 100644 (file)
@@ -456,24 +456,9 @@ config CPU_SUP_AMD
 
          If unsure, say N.
 
-config CPU_SUP_CENTAUR_32
+config CPU_SUP_CENTAUR
        default y
        bool "Support Centaur processors" if PROCESSOR_SELECT
-       depends on !64BIT
-       ---help---
-         This enables detection, tunings and quirks for Centaur processors
-
-         You need this enabled if you want your kernel to run on a
-         Centaur CPU. Disabling this option on other types of CPUs
-         makes the kernel a tiny bit smaller. Disabling it on a Centaur
-         CPU might render the kernel unbootable.
-
-         If unsure, say N.
-
-config CPU_SUP_CENTAUR_64
-       default y
-       bool "Support Centaur processors" if PROCESSOR_SELECT
-       depends on 64BIT
        ---help---
          This enables detection, tunings and quirks for Centaur processors
 
index fdb45df608b627c4efd79bba410ab4a0cb0f9b4a..d8359e73317f8dfb8b929f15f555f5593469e7fd 100644 (file)
@@ -72,14 +72,6 @@ config DEBUG_STACK_USAGE
 
          This option will slow down process creation somewhat.
 
-config DEBUG_PAGEALLOC
-       bool "Debug page memory allocations"
-       depends on DEBUG_KERNEL
-       ---help---
-         Unmap pages from the kernel linear mapping after free_pages().
-         This results in a large slowdown, but helps to find certain types
-         of memory corruptions.
-
 config DEBUG_PER_CPU_MAPS
        bool "Debug access to per_cpu maps"
        depends on DEBUG_KERNEL
index 1836191839ee3f6f35f32203cbf6e7556518d97f..f05d8c91d9e51ed29b21a6b99588398182879bb2 100644 (file)
@@ -153,34 +153,23 @@ endif
 
 boot := arch/x86/boot
 
-PHONY += zImage bzImage compressed zlilo bzlilo \
-         zdisk bzdisk fdimage fdimage144 fdimage288 isoimage install
+BOOT_TARGETS = bzlilo bzdisk fdimage fdimage144 fdimage288 isoimage install
+
+PHONY += bzImage $(BOOT_TARGETS)
 
 # Default kernel to build
 all: bzImage
 
 # KBUILD_IMAGE specify target image being built
-                    KBUILD_IMAGE := $(boot)/bzImage
-zImage zlilo zdisk: KBUILD_IMAGE := $(boot)/zImage
+KBUILD_IMAGE := $(boot)/bzImage
 
-zImage bzImage: vmlinux
+bzImage: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)
        $(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/boot
        $(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boot/$@
 
-compressed: zImage
-
-zlilo bzlilo: vmlinux
-       $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) zlilo
-
-zdisk bzdisk: vmlinux
-       $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) zdisk
-
-fdimage fdimage144 fdimage288 isoimage: vmlinux
-       $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) $@
-
-install:
-       $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
+$(BOOT_TARGETS): vmlinux
+       $(Q)$(MAKE) $(build)=$(boot) $@
 
 PHONY += vdso_install
 vdso_install:
@@ -205,7 +194,3 @@ define archhelp
   echo  '                  FDARGS="..."  arguments for the booted kernel'
   echo  '                  FDINITRD=file initrd for the booted kernel'
 endef
-
-CLEAN_FILES += arch/x86/boot/fdimage \
-              arch/x86/boot/image.iso \
-              arch/x86/boot/mtools.conf
index c70eff69a1fb7b6a8708c5acd193a2f1a8a163e4..fb737ce5888dfbd7213c171bf07ea43f88e66f6f 100644 (file)
@@ -6,26 +6,24 @@
 # for more details.
 #
 # Copyright (C) 1994 by Linus Torvalds
+# Changed by many, many contributors over the years.
 #
 
 # ROOT_DEV specifies the default root-device when making the image.
 # This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case
 # the default of FLOPPY is used by 'build'.
 
-ROOT_DEV := CURRENT
+ROOT_DEV       := CURRENT
 
 # If you want to preset the SVGA mode, uncomment the next line and
 # set SVGA_MODE to whatever number you want.
 # Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode.
 # The number is the same as you would ordinarily press at bootup.
 
-SVGA_MODE := -DSVGA_MODE=NORMAL_VGA
+SVGA_MODE      := -DSVGA_MODE=NORMAL_VGA
 
-# If you want the RAM disk device, define this to be the size in blocks.
-
-#RAMDISK := -DRAMDISK=512
-
-targets                := vmlinux.bin setup.bin setup.elf zImage bzImage
+targets                := vmlinux.bin setup.bin setup.elf bzImage
+targets                += fdimage fdimage144 fdimage288 image.iso mtools.conf
 subdir-                := compressed
 
 setup-y                += a20.o cmdline.o copy.o cpu.o cpucheck.o edd.o
@@ -71,17 +69,13 @@ KBUILD_CFLAGS       := $(LINUXINCLUDE) -g -Os -D_SETUP -D__KERNEL__ \
 KBUILD_CFLAGS +=   $(call cc-option,-m32)
 KBUILD_AFLAGS  := $(KBUILD_CFLAGS) -D__ASSEMBLY__
 
-$(obj)/zImage:  asflags-y := $(SVGA_MODE) $(RAMDISK)
-$(obj)/bzImage: ccflags-y := -D__BIG_KERNEL__
-$(obj)/bzImage: asflags-y := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
-$(obj)/bzImage: BUILDFLAGS   := -b
+$(obj)/bzImage: asflags-y  := $(SVGA_MODE)
 
 quiet_cmd_image = BUILD   $@
-cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/setup.bin \
-           $(obj)/vmlinux.bin $(ROOT_DEV) > $@
+cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin \
+       $(ROOT_DEV) > $@
 
-$(obj)/zImage $(obj)/bzImage: $(obj)/setup.bin \
-                             $(obj)/vmlinux.bin $(obj)/tools/build FORCE
+$(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE
        $(call if_changed,image)
        @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
 
@@ -116,9 +110,11 @@ $(obj)/setup.bin: $(obj)/setup.elf FORCE
 $(obj)/compressed/vmlinux: FORCE
        $(Q)$(MAKE) $(build)=$(obj)/compressed $@
 
-# Set this if you want to pass append arguments to the zdisk/fdimage/isoimage kernel
+# Set this if you want to pass append arguments to the
+# bzdisk/fdimage/isoimage kernel
 FDARGS =
-# Set this if you want an initrd included with the zdisk/fdimage/isoimage kernel
+# Set this if you want an initrd included with the
+# bzdisk/fdimage/isoimage kernel
 FDINITRD =
 
 image_cmdline = default linux $(FDARGS) $(if $(FDINITRD),initrd=initrd.img,)
@@ -127,7 +123,7 @@ $(obj)/mtools.conf: $(src)/mtools.conf.in
        sed -e 's|@OBJ@|$(obj)|g' < $< > $@
 
 # This requires write access to /dev/fd0
-zdisk: $(BOOTIMAGE) $(obj)/mtools.conf
+bzdisk: $(obj)/bzImage $(obj)/mtools.conf
        MTOOLSRC=$(obj)/mtools.conf mformat a:                  ; sync
        syslinux /dev/fd0                                       ; sync
        echo '$(image_cmdline)' | \
@@ -135,10 +131,10 @@ zdisk: $(BOOTIMAGE) $(obj)/mtools.conf
        if [ -f '$(FDINITRD)' ] ; then \
                MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' a:initrd.img ; \
        fi
-       MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) a:linux  ; sync
+       MTOOLSRC=$(obj)/mtools.conf mcopy $(obj)/bzImage a:linux        ; sync
 
 # These require being root or having syslinux 2.02 or higher installed
-fdimage fdimage144: $(BOOTIMAGE) $(obj)/mtools.conf
+fdimage fdimage144: $(obj)/bzImage $(obj)/mtools.conf
        dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=1440
        MTOOLSRC=$(obj)/mtools.conf mformat v:                  ; sync
        syslinux $(obj)/fdimage                                 ; sync
@@ -147,9 +143,9 @@ fdimage fdimage144: $(BOOTIMAGE) $(obj)/mtools.conf
        if [ -f '$(FDINITRD)' ] ; then \
                MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' v:initrd.img ; \
        fi
-       MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) v:linux  ; sync
+       MTOOLSRC=$(obj)/mtools.conf mcopy $(obj)/bzImage v:linux        ; sync
 
-fdimage288: $(BOOTIMAGE) $(obj)/mtools.conf
+fdimage288: $(obj)/bzImage $(obj)/mtools.conf
        dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=2880
        MTOOLSRC=$(obj)/mtools.conf mformat w:                  ; sync
        syslinux $(obj)/fdimage                                 ; sync
@@ -158,9 +154,9 @@ fdimage288: $(BOOTIMAGE) $(obj)/mtools.conf
        if [ -f '$(FDINITRD)' ] ; then \
                MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' w:initrd.img ; \
        fi
-       MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) w:linux  ; sync
+       MTOOLSRC=$(obj)/mtools.conf mcopy $(obj)/bzImage w:linux        ; sync
 
-isoimage: $(BOOTIMAGE)
+isoimage: $(obj)/bzImage
        -rm -rf $(obj)/isoimage
        mkdir $(obj)/isoimage
        for i in lib lib64 share end ; do \
@@ -170,7 +166,7 @@ isoimage: $(BOOTIMAGE)
                fi ; \
                if [ $$i = end ] ; then exit 1 ; fi ; \
        done
-       cp $(BOOTIMAGE) $(obj)/isoimage/linux
+       cp $(obj)/bzImage $(obj)/isoimage/linux
        echo '$(image_cmdline)' > $(obj)/isoimage/isolinux.cfg
        if [ -f '$(FDINITRD)' ] ; then \
                cp '$(FDINITRD)' $(obj)/isoimage/initrd.img ; \
@@ -181,12 +177,13 @@ isoimage: $(BOOTIMAGE)
        isohybrid $(obj)/image.iso 2>/dev/null || true
        rm -rf $(obj)/isoimage
 
-zlilo: $(BOOTIMAGE)
+bzlilo: $(obj)/bzImage
        if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
        if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
-       cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz
+       cat $(obj)/bzImage > $(INSTALL_PATH)/vmlinuz
        cp System.map $(INSTALL_PATH)/
        if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
 
 install:
-       sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)"
+       sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(obj)/bzImage \
+               System.map "$(INSTALL_PATH)"
index 7ccff4884a23e03c1a2ef59bf15de9b146401369..5d84d1c74e4c6d2a84666c7b7125641b00a1dcad 100644 (file)
 #include "boot.h"
 #include "offsets.h"
 
-SETUPSECTS     = 4                     /* default nr of setup-sectors */
 BOOTSEG                = 0x07C0                /* original address of boot-sector */
-SYSSEG         = DEF_SYSSEG            /* system loaded at 0x10000 (65536) */
-SYSSIZE                = DEF_SYSSIZE           /* system size: # of 16-byte clicks */
-                                       /* to be loaded */
-ROOT_DEV       = 0                     /* ROOT_DEV is now written by "build" */
+SYSSEG         = 0x1000                /* historical load address >> 4 */
 
 #ifndef SVGA_MODE
 #define SVGA_MODE ASK_VGA
@@ -97,12 +93,12 @@ bugger_off_msg:
        .section ".header", "a"
        .globl  hdr
 hdr:
-setup_sects:   .byte SETUPSECTS
+setup_sects:   .byte 0                 /* Filled in by build.c */
 root_flags:    .word ROOT_RDONLY
-syssize:       .long SYSSIZE
-ram_size:      .word RAMDISK
+syssize:       .long 0                 /* Filled in by build.c */
+ram_size:      .word 0                 /* Obsolete */
 vid_mode:      .word SVGA_MODE
-root_dev:      .word ROOT_DEV
+root_dev:      .word 0                 /* Filled in by build.c */
 boot_flag:     .word 0xAA55
 
        # offset 512, entry point
@@ -123,14 +119,15 @@ _start:
                                        # or else old loadlin-1.5 will fail)
                .globl realmode_swtch
 realmode_swtch:        .word   0, 0            # default_switch, SETUPSEG
-start_sys_seg: .word   SYSSEG
+start_sys_seg: .word   SYSSEG          # obsolete and meaningless, but just
+                                       # in case something decided to "use" it
                .word   kernel_version-512 # pointing to kernel version string
                                        # above section of header is compatible
                                        # with loadlin-1.5 (header v1.5). Don't
                                        # change it.
 
-type_of_loader:        .byte   0               # = 0, old one (LILO, Loadlin,
-                                       #      Bootlin, SYSLX, bootsect...)
+type_of_loader:        .byte   0               # 0 means ancient bootloader, newer
+                                       # bootloaders know to change this.
                                        # See Documentation/i386/boot.txt for
                                        # assigned ids
 
@@ -142,11 +139,7 @@ CAN_USE_HEAP       = 0x80                  # If set, the loader also has set
                                        # space behind setup.S can be used for
                                        # heap purposes.
                                        # Only the loader knows what is free
-#ifndef __BIG_KERNEL__
-               .byte   0
-#else
                .byte   LOADED_HIGH
-#endif
 
 setup_move_size: .word  0x8000         # size to move, when setup is not
                                        # loaded at 0x90000. We will move setup
@@ -157,11 +150,7 @@ setup_move_size: .word  0x8000             # size to move, when setup is not
 
 code32_start:                          # here loaders can put a different
                                        # start address for 32-bit code.
-#ifndef __BIG_KERNEL__
-               .long   0x1000          #   0x1000 = default for zImage
-#else
                .long   0x100000        # 0x100000 = default for big kernel
-#endif
 
 ramdisk_image: .long   0               # address of loaded ramdisk image
                                        # Here the loader puts the 32-bit
index 8c3c25f35578a00c140440131a69ae539038f950..5054c2ddd1a03471b4423e7c9eb1719dca667901 100644 (file)
@@ -2,6 +2,7 @@
  *
  *   Copyright (C) 1991, 1992 Linus Torvalds
  *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *   Copyright 2009 Intel Corporation; author H. Peter Anvin
  *
  *   This file is part of the Linux kernel, and is made available under
  *   the terms of the GNU General Public License version 2.
 
 #define SMAP   0x534d4150      /* ASCII "SMAP" */
 
+struct e820_ext_entry {
+       struct e820entry std;
+       u32 ext_flags;
+} __attribute__((packed));
+
 static int detect_memory_e820(void)
 {
        int count = 0;
        u32 next = 0;
-       u32 size, id;
+       u32 size, id, edi;
        u8 err;
        struct e820entry *desc = boot_params.e820_map;
+       static struct e820_ext_entry buf; /* static so it is zeroed */
+
+       /*
+        * Set this here so that if the BIOS doesn't change this field
+        * but still doesn't change %ecx, we're still okay...
+        */
+       buf.ext_flags = 1;
 
        do {
-               size = sizeof(struct e820entry);
+               size = sizeof buf;
 
-               /* Important: %edx is clobbered by some BIOSes,
-                  so it must be either used for the error output
-                  or explicitly marked clobbered. */
-               asm("int $0x15; setc %0"
+               /* Important: %edx and %esi are clobbered by some BIOSes,
+                  so they must be either used for the error output
+                  or explicitly marked clobbered.  Given that, assume there
+                  is something out there clobbering %ebp and %edi, too. */
+               asm("pushl %%ebp; int $0x15; popl %%ebp; setc %0"
                    : "=d" (err), "+b" (next), "=a" (id), "+c" (size),
-                     "=m" (*desc)
-                   : "D" (desc), "d" (SMAP), "a" (0xe820));
+                     "=D" (edi), "+m" (buf)
+                   : "D" (&buf), "d" (SMAP), "a" (0xe820)
+                   : "esi");
 
                /* BIOSes which terminate the chain with CF = 1 as opposed
                   to %ebx = 0 don't always report the SMAP signature on
@@ -51,8 +66,14 @@ static int detect_memory_e820(void)
                        break;
                }
 
+               /* ACPI 3.0 added the extended flags support.  If bit 0
+                  in the extended flags is zero, we're supposed to simply
+                  ignore the entry -- a backwards incompatible change! */
+               if (size > 20 && !(buf.ext_flags & 1))
+                       continue;
+
+               *desc++ = buf.std;
                count++;
-               desc++;
        } while (next && count < ARRAY_SIZE(boot_params.e820_map));
 
        return boot_params.e820_entries = count;
index 85a1cd8a8ff8a4daee99ee11d86176bd7a97c166..8062f89152504b19babbd9e293791356ac2791aa 100644 (file)
@@ -32,47 +32,6 @@ static void realmode_switch_hook(void)
        }
 }
 
-/*
- * A zImage kernel is loaded at 0x10000 but wants to run at 0x1000.
- * A bzImage kernel is loaded and runs at 0x100000.
- */
-static void move_kernel_around(void)
-{
-       /* Note: rely on the compile-time option here rather than
-          the LOADED_HIGH flag.  The Qemu kernel loader unconditionally
-          sets the loadflags to zero. */
-#ifndef __BIG_KERNEL__
-       u16 dst_seg, src_seg;
-       u32 syssize;
-
-       dst_seg =  0x1000 >> 4;
-       src_seg = 0x10000 >> 4;
-       syssize = boot_params.hdr.syssize; /* Size in 16-byte paragraphs */
-
-       while (syssize) {
-               int paras  = (syssize >= 0x1000) ? 0x1000 : syssize;
-               int dwords = paras << 2;
-
-               asm volatile("pushw %%es ; "
-                            "pushw %%ds ; "
-                            "movw %1,%%es ; "
-                            "movw %2,%%ds ; "
-                            "xorw %%di,%%di ; "
-                            "xorw %%si,%%si ; "
-                            "rep;movsl ; "
-                            "popw %%ds ; "
-                            "popw %%es"
-                            : "+c" (dwords)
-                            : "r" (dst_seg), "r" (src_seg)
-                            : "esi", "edi");
-
-               syssize -= paras;
-               dst_seg += paras;
-               src_seg += paras;
-       }
-#endif
-}
-
 /*
  * Disable all interrupts at the legacy PIC.
  */
@@ -147,9 +106,6 @@ void go_to_protected_mode(void)
        /* Hook before leaving real mode, also disables interrupts */
        realmode_switch_hook();
 
-       /* Move the kernel/setup to their final resting places */
-       move_kernel_around();
-
        /* Enable the A20 gate */
        if (enable_a20()) {
                puts("A20 gate not responding, unable to boot...\n");
index 019c17a7585115a7cfdb0c27696544b8127599b5..3e0edc6d2a2079892e1a655ef2e7a35a013c4ef3 100644 (file)
@@ -47,6 +47,7 @@ GLOBAL(protected_mode_jump)
 ENDPROC(protected_mode_jump)
 
        .code32
+       .section ".text32","ax"
 GLOBAL(in_pm32)
        # Set up data segments for flat 32-bit mode
        movl    %ecx, %ds
index df9234b3a5e07f6f0dd0bd10a2ad19065306097b..bb8dc2de796936c6a21d0b1bfbd934ca8a3e5877 100644 (file)
@@ -17,7 +17,8 @@ SECTIONS
        .header         : { *(.header) }
        .inittext       : { *(.inittext) }
        .initdata       : { *(.initdata) }
-       .text           : { *(.text*) }
+       .text           : { *(.text) }
+       .text32         : { *(.text32) }
 
        . = ALIGN(16);
        .rodata         : { *(.rodata*) }
index 44dc1923c0e3eb277a90c582addb524cd4163629..ee3a4ea923ace82fc0c1f4aa07e4c1adc32ee318 100644 (file)
@@ -130,7 +130,7 @@ static void die(const char * str, ...)
 
 static void usage(void)
 {
-       die("Usage: build [-b] setup system [rootdev] [> image]");
+       die("Usage: build setup system [rootdev] [> image]");
 }
 
 int main(int argc, char ** argv)
@@ -145,11 +145,6 @@ int main(int argc, char ** argv)
        void *kernel;
        u32 crc = 0xffffffffUL;
 
-       if (argc > 2 && !strcmp(argv[1], "-b"))
-         {
-           is_big_kernel = 1;
-           argc--, argv++;
-         }
        if ((argc < 3) || (argc > 4))
                usage();
        if (argc > 3) {
@@ -216,8 +211,6 @@ int main(int argc, char ** argv)
                die("Unable to mmap '%s': %m", argv[2]);
        /* Number of 16-byte paragraphs, including space for a 4-byte CRC */
        sys_size = (sz + 15 + 4) / 16;
-       if (!is_big_kernel && sys_size > DEF_SYSSIZE)
-               die("System is too big. Try using bzImage or modules.");
 
        /* Patch the setup code with the appropriate size parameters */
        buf[0x1f1] = setup_sectors-1;
index 5d4742ed4aa21dd83d968798a1c7ff92447907a1..95d86ce0421c84dd647f26f34cd65fc9f0143d3e 100644 (file)
@@ -129,41 +129,45 @@ u16 vga_crtc(void)
        return (inb(0x3cc) & 1) ? 0x3d4 : 0x3b4;
 }
 
-static void vga_set_480_scanlines(int end)
+static void vga_set_480_scanlines(int lines)
 {
-       u16 crtc;
-       u8  csel;
+       u16 crtc;               /* CRTC base address */
+       u8  csel;               /* CRTC miscellaneous output register */
+       u8  ovfw;               /* CRTC overflow register */
+       int end = lines-1;
 
        crtc = vga_crtc();
 
+       ovfw = 0x3c | ((end >> (8-1)) & 0x02) | ((end >> (9-6)) & 0x40);
+
        out_idx(0x0c, crtc, 0x11); /* Vertical sync end, unlock CR0-7 */
        out_idx(0x0b, crtc, 0x06); /* Vertical total */
-       out_idx(0x3e, crtc, 0x07); /* Vertical overflow */
+       out_idx(ovfw, crtc, 0x07); /* Vertical overflow */
        out_idx(0xea, crtc, 0x10); /* Vertical sync start */
-       out_idx(end, crtc, 0x12); /* Vertical display end */
+       out_idx(end,  crtc, 0x12); /* Vertical display end */
        out_idx(0xe7, crtc, 0x15); /* Vertical blank start */
        out_idx(0x04, crtc, 0x16); /* Vertical blank end */
        csel = inb(0x3cc);
        csel &= 0x0d;
        csel |= 0xe2;
-       outb(csel, 0x3cc);
+       outb(csel, 0x3c2);
 }
 
 static void vga_set_80x30(void)
 {
-       vga_set_480_scanlines(0xdf);
+       vga_set_480_scanlines(30*16);
 }
 
 static void vga_set_80x34(void)
 {
        vga_set_14font();
-       vga_set_480_scanlines(0xdb);
+       vga_set_480_scanlines(34*14);
 }
 
 static void vga_set_80x60(void)
 {
        vga_set_8font();
-       vga_set_480_scanlines(0xdf);
+       vga_set_480_scanlines(60*8);
 }
 
 static int vga_set_mode(struct mode_info *mode)
index db0c803170ab9e925dbfe2a22c17d0be23824d6e..a505202086e8741a916e696ccfb664d3f3e0f8ef 100644 (file)
@@ -828,4 +828,6 @@ ia32_sys_call_table:
        .quad sys_dup3                  /* 330 */
        .quad sys_pipe2
        .quad sys_inotify_init1
+       .quad compat_sys_preadv
+       .quad compat_sys_pwritev
 ia32_syscall_end:
index 4ef949c1972e6bfacb80d477fefc427cadfecd8f..df8a300dfe6c380b5fdcf60e379ef9fb855d67ae 100644 (file)
@@ -75,7 +75,7 @@ static inline void default_inquire_remote_apic(int apicid)
 #define setup_secondary_clock setup_secondary_APIC_clock
 #endif
 
-#ifdef CONFIG_X86_VSMP
+#ifdef CONFIG_X86_64
 extern int is_vsmp_box(void);
 #else
 static inline int is_vsmp_box(void)
@@ -108,6 +108,16 @@ extern void native_apic_icr_write(u32 low, u32 id);
 extern u64 native_apic_icr_read(void);
 
 #ifdef CONFIG_X86_X2APIC
+/*
+ * Make previous memory operations globally visible before
+ * sending the IPI through x2apic wrmsr. We need a serializing instruction or
+ * mfence for this.
+ */
+static inline void x2apic_wrmsr_fence(void)
+{
+       asm volatile("mfence" : : : "memory");
+}
+
 static inline void native_apic_msr_write(u32 reg, u32 v)
 {
        if (reg == APIC_DFR || reg == APIC_ID || reg == APIC_LDR ||
@@ -184,6 +194,9 @@ static inline int x2apic_enabled(void)
 {
        return 0;
 }
+
+#define        x2apic  0
+
 #endif
 
 extern int get_physical_broadcast(void);
@@ -379,6 +392,7 @@ static inline u32 safe_apic_wait_icr_idle(void)
 
 static inline void ack_APIC_irq(void)
 {
+#ifdef CONFIG_X86_LOCAL_APIC
        /*
         * ack_APIC_irq() actually gets compiled as a single instruction
         * ... yummie.
@@ -386,6 +400,7 @@ static inline void ack_APIC_irq(void)
 
        /* Docs say use 0 for future compatibility */
        apic_write(APIC_EOI, 0);
+#endif
 }
 
 static inline unsigned default_get_apic_id(unsigned long x)
@@ -474,10 +489,19 @@ static inline int default_apic_id_registered(void)
        return physid_isset(read_apic_id(), phys_cpu_present_map);
 }
 
+static inline int default_phys_pkg_id(int cpuid_apic, int index_msb)
+{
+       return cpuid_apic >> index_msb;
+}
+
+extern int default_apicid_to_node(int logical_apicid);
+
+#endif
+
 static inline unsigned int
 default_cpu_mask_to_apicid(const struct cpumask *cpumask)
 {
-       return cpumask_bits(cpumask)[0];
+       return cpumask_bits(cpumask)[0] & APIC_ALL_CPUS;
 }
 
 static inline unsigned int
@@ -491,15 +515,6 @@ default_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
        return (unsigned int)(mask1 & mask2 & mask3);
 }
 
-static inline int default_phys_pkg_id(int cpuid_apic, int index_msb)
-{
-       return cpuid_apic >> index_msb;
-}
-
-extern int default_apicid_to_node(int logical_apicid);
-
-#endif
-
 static inline unsigned long default_check_apicid_used(physid_mask_t bitmap, int apicid)
 {
        return physid_isset(apicid, bitmap);
index 63134e31e8b933acb973ee2e66f62a2f815bb326..bc9514fb3b13f70d75b11f037546eca8e43d07fd 100644 (file)
@@ -53,6 +53,7 @@
 #define                APIC_ESR_SENDILL        0x00020
 #define                APIC_ESR_RECVILL        0x00040
 #define                APIC_ESR_ILLREGA        0x00080
+#define        APIC_LVTCMCI    0x2f0
 #define        APIC_ICR        0x300
 #define                APIC_DEST_SELF          0x40000
 #define                APIC_DEST_ALLINC        0x80000
index 6526cf08b0e4604583b1b3e8c972e0f31fe1b44e..6ba23dd9fc9216de96b9cb52d1954b9bb7ae2b99 100644 (file)
@@ -1,10 +1,6 @@
 #ifndef _ASM_X86_BOOT_H
 #define _ASM_X86_BOOT_H
 
-/* Don't touch these, unless you really know what you're doing. */
-#define DEF_SYSSEG     0x1000
-#define DEF_SYSSIZE    0x7F00
-
 /* Internal svga startup constants */
 #define NORMAL_VGA     0xffff          /* 80x25 mode */
 #define EXTENDED_VGA   0xfffe          /* 80x50 mode */
index 5b301b7ff5f4bcac4854caaed6dc4877a389814b..b3894bf52fcddf68f8d16a38e2705fc1b3ec519d 100644 (file)
@@ -90,6 +90,9 @@ int set_memory_4k(unsigned long addr, int numpages);
 int set_memory_array_uc(unsigned long *addr, int addrinarray);
 int set_memory_array_wb(unsigned long *addr, int addrinarray);
 
+int set_pages_array_uc(struct page **pages, int addrinarray);
+int set_pages_array_wb(struct page **pages, int addrinarray);
+
 /*
  * For legacy compatibility with the old APIs, a few functions
  * are provided that work on a "struct page".
diff --git a/arch/x86/include/asm/cpu_debug.h b/arch/x86/include/asm/cpu_debug.h
new file mode 100755 (executable)
index 0000000..2228020
--- /dev/null
@@ -0,0 +1,226 @@
+#ifndef _ASM_X86_CPU_DEBUG_H
+#define _ASM_X86_CPU_DEBUG_H
+
+/*
+ * CPU x86 architecture debug
+ *
+ * Copyright(C) 2009 Jaswinder Singh Rajput
+ */
+
+/* Register flags */
+enum cpu_debug_bit {
+/* Model Specific Registers (MSRs)                                     */
+       CPU_MC_BIT,                             /* Machine Check        */
+       CPU_MONITOR_BIT,                        /* Monitor              */
+       CPU_TIME_BIT,                           /* Time                 */
+       CPU_PMC_BIT,                            /* Performance Monitor  */
+       CPU_PLATFORM_BIT,                       /* Platform             */
+       CPU_APIC_BIT,                           /* APIC                 */
+       CPU_POWERON_BIT,                        /* Power-on             */
+       CPU_CONTROL_BIT,                        /* Control              */
+       CPU_FEATURES_BIT,                       /* Features control     */
+       CPU_LBRANCH_BIT,                        /* Last Branch          */
+       CPU_BIOS_BIT,                           /* BIOS                 */
+       CPU_FREQ_BIT,                           /* Frequency            */
+       CPU_MTTR_BIT,                           /* MTRR                 */
+       CPU_PERF_BIT,                           /* Performance          */
+       CPU_CACHE_BIT,                          /* Cache                */
+       CPU_SYSENTER_BIT,                       /* Sysenter             */
+       CPU_THERM_BIT,                          /* Thermal              */
+       CPU_MISC_BIT,                           /* Miscellaneous        */
+       CPU_DEBUG_BIT,                          /* Debug                */
+       CPU_PAT_BIT,                            /* PAT                  */
+       CPU_VMX_BIT,                            /* VMX                  */
+       CPU_CALL_BIT,                           /* System Call          */
+       CPU_BASE_BIT,                           /* BASE Address         */
+       CPU_VER_BIT,                            /* Version ID           */
+       CPU_CONF_BIT,                           /* Configuration        */
+       CPU_SMM_BIT,                            /* System mgmt mode     */
+       CPU_SVM_BIT,                            /*Secure Virtual Machine*/
+       CPU_OSVM_BIT,                           /* OS-Visible Workaround*/
+/* Standard Registers                                                  */
+       CPU_TSS_BIT,                            /* Task Stack Segment   */
+       CPU_CR_BIT,                             /* Control Registers    */
+       CPU_DT_BIT,                             /* Descriptor Table     */
+/* End of Registers flags                                              */
+       CPU_REG_ALL_BIT,                        /* Select all Registers */
+};
+
+#define        CPU_REG_ALL             (~0)            /* Select all Registers */
+
+#define        CPU_MC                  (1 << CPU_MC_BIT)
+#define        CPU_MONITOR             (1 << CPU_MONITOR_BIT)
+#define        CPU_TIME                (1 << CPU_TIME_BIT)
+#define        CPU_PMC                 (1 << CPU_PMC_BIT)
+#define        CPU_PLATFORM            (1 << CPU_PLATFORM_BIT)
+#define        CPU_APIC                (1 << CPU_APIC_BIT)
+#define        CPU_POWERON             (1 << CPU_POWERON_BIT)
+#define        CPU_CONTROL             (1 << CPU_CONTROL_BIT)
+#define        CPU_FEATURES            (1 << CPU_FEATURES_BIT)
+#define        CPU_LBRANCH             (1 << CPU_LBRANCH_BIT)
+#define        CPU_BIOS                (1 << CPU_BIOS_BIT)
+#define        CPU_FREQ                (1 << CPU_FREQ_BIT)
+#define        CPU_MTRR                (1 << CPU_MTTR_BIT)
+#define        CPU_PERF                (1 << CPU_PERF_BIT)
+#define        CPU_CACHE               (1 << CPU_CACHE_BIT)
+#define        CPU_SYSENTER            (1 << CPU_SYSENTER_BIT)
+#define        CPU_THERM               (1 << CPU_THERM_BIT)
+#define        CPU_MISC                (1 << CPU_MISC_BIT)
+#define        CPU_DEBUG               (1 << CPU_DEBUG_BIT)
+#define        CPU_PAT                 (1 << CPU_PAT_BIT)
+#define        CPU_VMX                 (1 << CPU_VMX_BIT)
+#define        CPU_CALL                (1 << CPU_CALL_BIT)
+#define        CPU_BASE                (1 << CPU_BASE_BIT)
+#define        CPU_VER                 (1 << CPU_VER_BIT)
+#define        CPU_CONF                (1 << CPU_CONF_BIT)
+#define        CPU_SMM                 (1 << CPU_SMM_BIT)
+#define        CPU_SVM                 (1 << CPU_SVM_BIT)
+#define        CPU_OSVM                (1 << CPU_OSVM_BIT)
+#define        CPU_TSS                 (1 << CPU_TSS_BIT)
+#define        CPU_CR                  (1 << CPU_CR_BIT)
+#define        CPU_DT                  (1 << CPU_DT_BIT)
+
+/* Register file flags */
+enum cpu_file_bit {
+       CPU_INDEX_BIT,                          /* index                */
+       CPU_VALUE_BIT,                          /* value                */
+};
+
+#define        CPU_FILE_VALUE                  (1 << CPU_VALUE_BIT)
+
+/*
+ * DisplayFamily_DisplayModel  Processor Families/Processor Number Series
+ * --------------------------  ------------------------------------------
+ * 05_01, 05_02, 05_04         Pentium, Pentium with MMX
+ *
+ * 06_01                       Pentium Pro
+ * 06_03, 06_05                        Pentium II Xeon, Pentium II
+ * 06_07, 06_08, 06_0A, 06_0B  Pentium III Xeon, Pentum III
+ *
+ * 06_09, 060D                 Pentium M
+ *
+ * 06_0E                       Core Duo, Core Solo
+ *
+ * 06_0F                       Xeon 3000, 3200, 5100, 5300, 7300 series,
+ *                             Core 2 Quad, Core 2 Extreme, Core 2 Duo,
+ *                             Pentium dual-core
+ * 06_17                       Xeon 5200, 5400 series, Core 2 Quad Q9650
+ *
+ * 06_1C                       Atom
+ *
+ * 0F_00, 0F_01, 0F_02         Xeon, Xeon MP, Pentium 4
+ * 0F_03, 0F_04                        Xeon, Xeon MP, Pentium 4, Pentium D
+ *
+ * 0F_06                       Xeon 7100, 5000 Series, Xeon MP,
+ *                             Pentium 4, Pentium D
+ */
+
+/* Register processors bits */
+enum cpu_processor_bit {
+       CPU_NONE,
+/* Intel */
+       CPU_INTEL_PENTIUM_BIT,
+       CPU_INTEL_P6_BIT,
+       CPU_INTEL_PENTIUM_M_BIT,
+       CPU_INTEL_CORE_BIT,
+       CPU_INTEL_CORE2_BIT,
+       CPU_INTEL_ATOM_BIT,
+       CPU_INTEL_XEON_P4_BIT,
+       CPU_INTEL_XEON_MP_BIT,
+/* AMD */
+       CPU_AMD_K6_BIT,
+       CPU_AMD_K7_BIT,
+       CPU_AMD_K8_BIT,
+       CPU_AMD_0F_BIT,
+       CPU_AMD_10_BIT,
+       CPU_AMD_11_BIT,
+};
+
+#define        CPU_INTEL_PENTIUM       (1 << CPU_INTEL_PENTIUM_BIT)
+#define        CPU_INTEL_P6            (1 << CPU_INTEL_P6_BIT)
+#define        CPU_INTEL_PENTIUM_M     (1 << CPU_INTEL_PENTIUM_M_BIT)
+#define        CPU_INTEL_CORE          (1 << CPU_INTEL_CORE_BIT)
+#define        CPU_INTEL_CORE2         (1 << CPU_INTEL_CORE2_BIT)
+#define        CPU_INTEL_ATOM          (1 << CPU_INTEL_ATOM_BIT)
+#define        CPU_INTEL_XEON_P4       (1 << CPU_INTEL_XEON_P4_BIT)
+#define        CPU_INTEL_XEON_MP       (1 << CPU_INTEL_XEON_MP_BIT)
+
+#define        CPU_INTEL_PX            (CPU_INTEL_P6 | CPU_INTEL_PENTIUM_M)
+#define        CPU_INTEL_COREX         (CPU_INTEL_CORE | CPU_INTEL_CORE2)
+#define        CPU_INTEL_XEON          (CPU_INTEL_XEON_P4 | CPU_INTEL_XEON_MP)
+#define        CPU_CO_AT               (CPU_INTEL_CORE | CPU_INTEL_ATOM)
+#define        CPU_C2_AT               (CPU_INTEL_CORE2 | CPU_INTEL_ATOM)
+#define        CPU_CX_AT               (CPU_INTEL_COREX | CPU_INTEL_ATOM)
+#define        CPU_CX_XE               (CPU_INTEL_COREX | CPU_INTEL_XEON)
+#define        CPU_P6_XE               (CPU_INTEL_P6 | CPU_INTEL_XEON)
+#define        CPU_PM_CO_AT            (CPU_INTEL_PENTIUM_M | CPU_CO_AT)
+#define        CPU_C2_AT_XE            (CPU_C2_AT | CPU_INTEL_XEON)
+#define        CPU_CX_AT_XE            (CPU_CX_AT | CPU_INTEL_XEON)
+#define        CPU_P6_CX_AT            (CPU_INTEL_P6 | CPU_CX_AT)
+#define        CPU_P6_CX_XE            (CPU_P6_XE | CPU_INTEL_COREX)
+#define        CPU_P6_CX_AT_XE         (CPU_INTEL_P6 | CPU_CX_AT_XE)
+#define        CPU_PM_CX_AT_XE         (CPU_INTEL_PENTIUM_M | CPU_CX_AT_XE)
+#define        CPU_PM_CX_AT            (CPU_INTEL_PENTIUM_M | CPU_CX_AT)
+#define        CPU_PM_CX_XE            (CPU_INTEL_PENTIUM_M | CPU_CX_XE)
+#define        CPU_PX_CX_AT            (CPU_INTEL_PX | CPU_CX_AT)
+#define        CPU_PX_CX_AT_XE         (CPU_INTEL_PX | CPU_CX_AT_XE)
+
+/* Select all supported Intel CPUs */
+#define        CPU_INTEL_ALL           (CPU_INTEL_PENTIUM | CPU_PX_CX_AT_XE)
+
+#define        CPU_AMD_K6              (1 << CPU_AMD_K6_BIT)
+#define        CPU_AMD_K7              (1 << CPU_AMD_K7_BIT)
+#define        CPU_AMD_K8              (1 << CPU_AMD_K8_BIT)
+#define        CPU_AMD_0F              (1 << CPU_AMD_0F_BIT)
+#define        CPU_AMD_10              (1 << CPU_AMD_10_BIT)
+#define        CPU_AMD_11              (1 << CPU_AMD_11_BIT)
+
+#define        CPU_K10_PLUS            (CPU_AMD_10 | CPU_AMD_11)
+#define        CPU_K0F_PLUS            (CPU_AMD_0F | CPU_K10_PLUS)
+#define        CPU_K8_PLUS             (CPU_AMD_K8 | CPU_K0F_PLUS)
+#define        CPU_K7_PLUS             (CPU_AMD_K7 | CPU_K8_PLUS)
+
+/* Select all supported AMD CPUs */
+#define        CPU_AMD_ALL             (CPU_AMD_K6 | CPU_K7_PLUS)
+
+/* Select all supported CPUs */
+#define        CPU_ALL                 (CPU_INTEL_ALL | CPU_AMD_ALL)
+
+#define MAX_CPU_FILES          512
+
+struct cpu_private {
+       unsigned                cpu;
+       unsigned                type;
+       unsigned                reg;
+       unsigned                file;
+};
+
+struct cpu_debug_base {
+       char                    *name;          /* Register name        */
+       unsigned                flag;           /* Register flag        */
+       unsigned                write;          /* Register write flag  */
+};
+
+/*
+ * Currently it looks similar to cpu_debug_base but once we add more files
+ * cpu_file_base will go in different direction
+ */
+struct cpu_file_base {
+       char                    *name;          /* Register file name   */
+       unsigned                flag;           /* Register file flag   */
+       unsigned                write;          /* Register write flag  */
+};
+
+struct cpu_cpuX_base {
+       struct dentry           *dentry;        /* Register dentry      */
+       int                     init;           /* Register index file  */
+};
+
+struct cpu_debug_range {
+       unsigned                min;            /* Register range min   */
+       unsigned                max;            /* Register range max   */
+       unsigned                flag;           /* Supported flags      */
+       unsigned                model;          /* Supported models     */
+};
+
+#endif /* _ASM_X86_CPU_DEBUG_H */
index dc27705f5443268cc69857590fde7e1d369f97a2..5623c50d67b268a00c10dc60f8a5013f04bb28aa 100644 (file)
@@ -91,7 +91,6 @@ static inline int desc_empty(const void *ptr)
 #define store_gdt(dtr) native_store_gdt(dtr)
 #define store_idt(dtr) native_store_idt(dtr)
 #define store_tr(tr) (tr = native_store_tr())
-#define store_ldt(ldt) asm("sldt %0":"=m" (ldt))
 
 #define load_TLS(t, cpu) native_load_tls(t, cpu)
 #define set_ldt native_set_ldt
@@ -112,6 +111,8 @@ static inline void paravirt_free_ldt(struct desc_struct *ldt, unsigned entries)
 }
 #endif /* CONFIG_PARAVIRT */
 
+#define store_ldt(ldt) asm("sldt %0" : "=m"(ldt))
+
 static inline void native_write_idt_entry(gate_desc *idt, int entry,
                                          const gate_desc *gate)
 {
index 3c034f48fdb0a12f5a3fefe1499d014b68e6f4a2..4994a20acbcbf66aee788ebcb275eac4a2edd442 100644 (file)
@@ -6,7 +6,7 @@ struct dev_archdata {
        void    *acpi_handle;
 #endif
 #ifdef CONFIG_X86_64
-struct dma_mapping_ops *dma_ops;
+struct dma_map_ops *dma_ops;
 #endif
 #ifdef CONFIG_DMAR
        void *iommu; /* hook for IOMMU specific extension */
index 132a134d12f24432a310f66485f6586387f618dd..cea7b74963e9758e9338c7c739c02bb53e9d63e2 100644 (file)
@@ -7,6 +7,8 @@
  */
 
 #include <linux/scatterlist.h>
+#include <linux/dma-debug.h>
+#include <linux/dma-attrs.h>
 #include <asm/io.h>
 #include <asm/swiotlb.h>
 #include <asm-generic/dma-coherent.h>
@@ -16,47 +18,9 @@ extern int iommu_merge;
 extern struct device x86_dma_fallback_dev;
 extern int panic_on_overflow;
 
-struct dma_mapping_ops {
-       int             (*mapping_error)(struct device *dev,
-                                        dma_addr_t dma_addr);
-       void*           (*alloc_coherent)(struct device *dev, size_t size,
-                               dma_addr_t *dma_handle, gfp_t gfp);
-       void            (*free_coherent)(struct device *dev, size_t size,
-                               void *vaddr, dma_addr_t dma_handle);
-       dma_addr_t      (*map_single)(struct device *hwdev, phys_addr_t ptr,
-                               size_t size, int direction);
-       void            (*unmap_single)(struct device *dev, dma_addr_t addr,
-                               size_t size, int direction);
-       void            (*sync_single_for_cpu)(struct device *hwdev,
-                               dma_addr_t dma_handle, size_t size,
-                               int direction);
-       void            (*sync_single_for_device)(struct device *hwdev,
-                               dma_addr_t dma_handle, size_t size,
-                               int direction);
-       void            (*sync_single_range_for_cpu)(struct device *hwdev,
-                               dma_addr_t dma_handle, unsigned long offset,
-                               size_t size, int direction);
-       void            (*sync_single_range_for_device)(struct device *hwdev,
-                               dma_addr_t dma_handle, unsigned long offset,
-                               size_t size, int direction);
-       void            (*sync_sg_for_cpu)(struct device *hwdev,
-                               struct scatterlist *sg, int nelems,
-                               int direction);
-       void            (*sync_sg_for_device)(struct device *hwdev,
-                               struct scatterlist *sg, int nelems,
-                               int direction);
-       int             (*map_sg)(struct device *hwdev, struct scatterlist *sg,
-                               int nents, int direction);
-       void            (*unmap_sg)(struct device *hwdev,
-                               struct scatterlist *sg, int nents,
-                               int direction);
-       int             (*dma_supported)(struct device *hwdev, u64 mask);
-       int             is_phys;
-};
-
-extern struct dma_mapping_ops *dma_ops;
-
-static inline struct dma_mapping_ops *get_dma_ops(struct device *dev)
+extern struct dma_map_ops *dma_ops;
+
+static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 {
 #ifdef CONFIG_X86_32
        return dma_ops;
@@ -71,7 +35,7 @@ static inline struct dma_mapping_ops *get_dma_ops(struct device *dev)
 /* Make sure we keep the same behaviour */
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(dev);
+       struct dma_map_ops *ops = get_dma_ops(dev);
        if (ops->mapping_error)
                return ops->mapping_error(dev, dma_addr);
 
@@ -90,137 +54,167 @@ extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
 
 static inline dma_addr_t
 dma_map_single(struct device *hwdev, void *ptr, size_t size,
-              int direction)
+              enum dma_data_direction dir)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(hwdev);
-
-       BUG_ON(!valid_dma_direction(direction));
-       return ops->map_single(hwdev, virt_to_phys(ptr), size, direction);
+       struct dma_map_ops *ops = get_dma_ops(hwdev);
+       dma_addr_t addr;
+
+       BUG_ON(!valid_dma_direction(dir));
+       addr = ops->map_page(hwdev, virt_to_page(ptr),
+                            (unsigned long)ptr & ~PAGE_MASK, size,
+                            dir, NULL);
+       debug_dma_map_page(hwdev, virt_to_page(ptr),
+                          (unsigned long)ptr & ~PAGE_MASK, size,
+                          dir, addr, true);
+       return addr;
 }
 
 static inline void
 dma_unmap_single(struct device *dev, dma_addr_t addr, size_t size,
-                int direction)
+                enum dma_data_direction dir)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(dev);
+       struct dma_map_ops *ops = get_dma_ops(dev);
 
-       BUG_ON(!valid_dma_direction(direction));
-       if (ops->unmap_single)
-               ops->unmap_single(dev, addr, size, direction);
+       BUG_ON(!valid_dma_direction(dir));
+       if (ops->unmap_page)
+               ops->unmap_page(dev, addr, size, dir, NULL);
+       debug_dma_unmap_page(dev, addr, size, dir, true);
 }
 
 static inline int
 dma_map_sg(struct device *hwdev, struct scatterlist *sg,
-          int nents, int direction)
+          int nents, enum dma_data_direction dir)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(hwdev);
+       struct dma_map_ops *ops = get_dma_ops(hwdev);
+       int ents;
+
+       BUG_ON(!valid_dma_direction(dir));
+       ents = ops->map_sg(hwdev, sg, nents, dir, NULL);
+       debug_dma_map_sg(hwdev, sg, nents, ents, dir);
 
-       BUG_ON(!valid_dma_direction(direction));
-       return ops->map_sg(hwdev, sg, nents, direction);
+       return ents;
 }
 
 static inline void
 dma_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents,
-            int direction)
+            enum dma_data_direction dir)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(hwdev);
+       struct dma_map_ops *ops = get_dma_ops(hwdev);
 
-       BUG_ON(!valid_dma_direction(direction));
+       BUG_ON(!valid_dma_direction(dir));
+       debug_dma_unmap_sg(hwdev, sg, nents, dir);
        if (ops->unmap_sg)
-               ops->unmap_sg(hwdev, sg, nents, direction);
+               ops->unmap_sg(hwdev, sg, nents, dir, NULL);
 }
 
 static inline void
 dma_sync_single_for_cpu(struct device *hwdev, dma_addr_t dma_handle,
-                       size_t size, int direction)
+                       size_t size, enum dma_data_direction dir)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(hwdev);
+       struct dma_map_ops *ops = get_dma_ops(hwdev);
 
-       BUG_ON(!valid_dma_direction(direction));
+       BUG_ON(!valid_dma_direction(dir));
        if (ops->sync_single_for_cpu)
-               ops->sync_single_for_cpu(hwdev, dma_handle, size, direction);
+               ops->sync_single_for_cpu(hwdev, dma_handle, size, dir);
+       debug_dma_sync_single_for_cpu(hwdev, dma_handle, size, dir);
        flush_write_buffers();
 }
 
 static inline void
 dma_sync_single_for_device(struct device *hwdev, dma_addr_t dma_handle,
-                          size_t size, int direction)
+                          size_t size, enum dma_data_direction dir)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(hwdev);
+       struct dma_map_ops *ops = get_dma_ops(hwdev);
 
-       BUG_ON(!valid_dma_direction(direction));
+       BUG_ON(!valid_dma_direction(dir));
        if (ops->sync_single_for_device)
-               ops->sync_single_for_device(hwdev, dma_handle, size, direction);
+               ops->sync_single_for_device(hwdev, dma_handle, size, dir);
+       debug_dma_sync_single_for_device(hwdev, dma_handle, size, dir);
        flush_write_buffers();
 }
 
 static inline void
 dma_sync_single_range_for_cpu(struct device *hwdev, dma_addr_t dma_handle,
-                             unsigned long offset, size_t size, int direction)
+                             unsigned long offset, size_t size,
+                             enum dma_data_direction dir)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(hwdev);
+       struct dma_map_ops *ops = get_dma_ops(hwdev);
 
-       BUG_ON(!valid_dma_direction(direction));
+       BUG_ON(!valid_dma_direction(dir));
        if (ops->sync_single_range_for_cpu)
                ops->sync_single_range_for_cpu(hwdev, dma_handle, offset,
-                                              size, direction);
+                                              size, dir);
+       debug_dma_sync_single_range_for_cpu(hwdev, dma_handle,
+                                           offset, size, dir);
        flush_write_buffers();
 }
 
 static inline void
 dma_sync_single_range_for_device(struct device *hwdev, dma_addr_t dma_handle,
                                 unsigned long offset, size_t size,
-                                int direction)
+                                enum dma_data_direction dir)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(hwdev);
+       struct dma_map_ops *ops = get_dma_ops(hwdev);
 
-       BUG_ON(!valid_dma_direction(direction));
+       BUG_ON(!valid_dma_direction(dir));
        if (ops->sync_single_range_for_device)
                ops->sync_single_range_for_device(hwdev, dma_handle,
-                                                 offset, size, direction);
+                                                 offset, size, dir);
+       debug_dma_sync_single_range_for_device(hwdev, dma_handle,
+                                              offset, size, dir);
        flush_write_buffers();
 }
 
 static inline void
 dma_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg,
-                   int nelems, int direction)
+                   int nelems, enum dma_data_direction dir)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(hwdev);
+       struct dma_map_ops *ops = get_dma_ops(hwdev);
 
-       BUG_ON(!valid_dma_direction(direction));
+       BUG_ON(!valid_dma_direction(dir));
        if (ops->sync_sg_for_cpu)
-               ops->sync_sg_for_cpu(hwdev, sg, nelems, direction);
+               ops->sync_sg_for_cpu(hwdev, sg, nelems, dir);
+       debug_dma_sync_sg_for_cpu(hwdev, sg, nelems, dir);
        flush_write_buffers();
 }
 
 static inline void
 dma_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
-                      int nelems, int direction)
+                      int nelems, enum dma_data_direction dir)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(hwdev);
+       struct dma_map_ops *ops = get_dma_ops(hwdev);
 
-       BUG_ON(!valid_dma_direction(direction));
+       BUG_ON(!valid_dma_direction(dir));
        if (ops->sync_sg_for_device)
-               ops->sync_sg_for_device(hwdev, sg, nelems, direction);
+               ops->sync_sg_for_device(hwdev, sg, nelems, dir);
+       debug_dma_sync_sg_for_device(hwdev, sg, nelems, dir);
 
        flush_write_buffers();
 }
 
 static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
                                      size_t offset, size_t size,
-                                     int direction)
+                                     enum dma_data_direction dir)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(dev);
+       struct dma_map_ops *ops = get_dma_ops(dev);
+       dma_addr_t addr;
 
-       BUG_ON(!valid_dma_direction(direction));
-       return ops->map_single(dev, page_to_phys(page) + offset,
-                              size, direction);
+       BUG_ON(!valid_dma_direction(dir));
+       addr = ops->map_page(dev, page, offset, size, dir, NULL);
+       debug_dma_map_page(dev, page, offset, size, dir, addr, false);
+
+       return addr;
 }
 
 static inline void dma_unmap_page(struct device *dev, dma_addr_t addr,
-                                 size_t size, int direction)
+                                 size_t size, enum dma_data_direction dir)
 {
-       dma_unmap_single(dev, addr, size, direction);
+       struct dma_map_ops *ops = get_dma_ops(dev);
+
+       BUG_ON(!valid_dma_direction(dir));
+       if (ops->unmap_page)
+               ops->unmap_page(dev, addr, size, dir, NULL);
+       debug_dma_unmap_page(dev, addr, size, dir, false);
 }
 
 static inline void
@@ -266,7 +260,7 @@ static inline void *
 dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
                gfp_t gfp)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(dev);
+       struct dma_map_ops *ops = get_dma_ops(dev);
        void *memory;
 
        gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
@@ -285,20 +279,24 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
        if (!ops->alloc_coherent)
                return NULL;
 
-       return ops->alloc_coherent(dev, size, dma_handle,
-                                  dma_alloc_coherent_gfp_flags(dev, gfp));
+       memory = ops->alloc_coherent(dev, size, dma_handle,
+                                    dma_alloc_coherent_gfp_flags(dev, gfp));
+       debug_dma_alloc_coherent(dev, size, *dma_handle, memory);
+
+       return memory;
 }
 
 static inline void dma_free_coherent(struct device *dev, size_t size,
                                     void *vaddr, dma_addr_t bus)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(dev);
+       struct dma_map_ops *ops = get_dma_ops(dev);
 
        WARN_ON(irqs_disabled());       /* for portability */
 
        if (dma_release_from_coherent(dev, get_order(size), vaddr))
                return;
 
+       debug_dma_free_coherent(dev, size, vaddr, bus);
        if (ops->free_coherent)
                ops->free_coherent(dev, size, vaddr, bus);
 }
index bc68212c6bc0097f66ae21b936c0af59e4c3f705..fd8f9e2ca35f16ffdac6b9e609be0086ae055803 100644 (file)
@@ -1,22 +1,15 @@
 #ifndef _ASM_X86_DMI_H
 #define _ASM_X86_DMI_H
 
-#include <asm/io.h>
-
-#define DMI_MAX_DATA 2048
+#include <linux/compiler.h>
+#include <linux/init.h>
 
-extern int dmi_alloc_index;
-extern char dmi_alloc_data[DMI_MAX_DATA];
+#include <asm/io.h>
+#include <asm/setup.h>
 
-/* This is so early that there is no good way to allocate dynamic memory.
-   Allocate data in an BSS array. */
-static inline void *dmi_alloc(unsigned len)
+static __always_inline __init void *dmi_alloc(unsigned len)
 {
-       int idx = dmi_alloc_index;
-       if ((dmi_alloc_index + len) > DMI_MAX_DATA)
-               return NULL;
-       dmi_alloc_index += len;
-       return dmi_alloc_data + idx;
+       return extend_brk(len, sizeof(int));
 }
 
 /* Use early IO mappings for DMI because it's initialized early */
index 00d41ce4c84453b4cbdf3659ab91a2d49176eba1..7ecba4d85089d58400ad8694c6b4024d85029eee 100644 (file)
@@ -72,7 +72,7 @@ extern int e820_all_mapped(u64 start, u64 end, unsigned type);
 extern void e820_add_region(u64 start, u64 size, int type);
 extern void e820_print_map(char *who);
 extern int
-sanitize_e820_map(struct e820entry *biosmap, int max_nr_map, int *pnr_map);
+sanitize_e820_map(struct e820entry *biosmap, int max_nr_map, u32 *pnr_map);
 extern u64 e820_update_range(u64 start, u64 size, unsigned old_type,
                               unsigned new_type);
 extern u64 e820_remove_range(u64 start, u64 size, unsigned old_type,
index 854d538ae85797a27601df6ff051ac3c44fe38f5..c2e6bedaf25873b75df79f6a0f809b4ad9070787 100644 (file)
@@ -33,6 +33,8 @@ BUILD_INTERRUPT3(invalidate_interrupt7,INVALIDATE_TLB_VECTOR_START+7,
                 smp_invalidate_interrupt)
 #endif
 
+BUILD_INTERRUPT(generic_interrupt, GENERIC_INTERRUPT_VECTOR)
+
 /*
  * every pentium local APIC has two 'local interrupts', with a
  * soft-definable vector attached to both interrupts, one of
index b55b4a7fbefd365b76813e86e71259f799bfdb59..db24c2278be04c7400f6f5057904d49642fa75e9 100644 (file)
@@ -55,29 +55,4 @@ struct dyn_arch_ftrace {
 #endif /* __ASSEMBLY__ */
 #endif /* CONFIG_FUNCTION_TRACER */
 
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-
-#ifndef __ASSEMBLY__
-
-/*
- * Stack of return addresses for functions
- * of a thread.
- * Used in struct thread_info
- */
-struct ftrace_ret_stack {
-       unsigned long ret;
-       unsigned long func;
-       unsigned long long calltime;
-};
-
-/*
- * Primary handler of a function return.
- * It relays on ftrace_return_to_handler.
- * Defined in entry_32/64.S
- */
-extern void return_to_handler(void);
-
-#endif /* __ASSEMBLY__ */
-#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
-
 #endif /* _ASM_X86_FTRACE_H */
index 176f058e715947cbd7b803b90654e14b307dc8ea..039db6aa8e0271951706ee20bd9b819098f8002a 100644 (file)
@@ -12,6 +12,7 @@ typedef struct {
        unsigned int apic_timer_irqs;   /* arch dependent */
        unsigned int irq_spurious_count;
 #endif
+       unsigned int generic_irqs;      /* arch dependent */
 #ifdef CONFIG_SMP
        unsigned int irq_resched_count;
        unsigned int irq_call_count;
index bf9276bea6602fca7bf2b93e6aa640a083e57f99..014c2b85ae45eae61201dcf19da9e04f2940e721 100644 (file)
@@ -63,6 +63,7 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot);
 void *kmap_atomic(struct page *page, enum km_type type);
 void kunmap_atomic(void *kvaddr, enum km_type type);
 void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
+void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
 struct page *kmap_atomic_to_page(void *ptr);
 
 #ifndef CONFIG_PARAVIRT
index 370e1c83bb49a27048d4641546bef5f76efd0faa..b762ea49bd703ab3b28958cf83b6908e825e57a4 100644 (file)
@@ -27,6 +27,7 @@
 
 /* Interrupt handlers registered during init_IRQ */
 extern void apic_timer_interrupt(void);
+extern void generic_interrupt(void);
 extern void error_interrupt(void);
 extern void spurious_interrupt(void);
 extern void thermal_interrupt(void);
diff --git a/arch/x86/include/asm/init.h b/arch/x86/include/asm/init.h
new file mode 100644 (file)
index 0000000..36fb1a6
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _ASM_X86_INIT_32_H
+#define _ASM_X86_INIT_32_H
+
+#ifdef CONFIG_X86_32
+extern void __init early_ioremap_page_table_range_init(void);
+#endif
+
+extern unsigned long __init
+kernel_physical_mapping_init(unsigned long start,
+                            unsigned long end,
+                            unsigned long page_size_mask);
+
+
+extern unsigned long __initdata e820_table_start;
+extern unsigned long __meminitdata e820_table_end;
+extern unsigned long __meminitdata e820_table_top;
+
+#endif /* _ASM_X86_INIT_32_H */
index 59cb4a1317b774b0f89a87890355bf70157a016b..373cc2bbcad2cdfb17ef4e0448921da892691d0e 100644 (file)
@@ -162,7 +162,8 @@ extern int (*ioapic_renumber_irq)(int ioapic, int irq);
 extern void ioapic_init_mappings(void);
 
 #ifdef CONFIG_X86_64
-extern int save_mask_IO_APIC_setup(void);
+extern int save_IO_APIC_setup(void);
+extern void mask_IO_APIC_setup(void);
 extern void restore_IO_APIC_setup(void);
 extern void reinit_intr_remapped_IO_APIC(int);
 #endif
@@ -172,7 +173,7 @@ extern void probe_nr_irqs_gsi(void);
 extern int setup_ioapic_entry(int apic, int irq,
                              struct IO_APIC_route_entry *entry,
                              unsigned int destination, int trigger,
-                             int polarity, int vector);
+                             int polarity, int vector, int pin);
 extern void ioapic_write_entry(int apic, int pin,
                               struct IO_APIC_route_entry e);
 #else  /* !CONFIG_X86_IO_APIC */
index a6ee9e6f530f89cc2e86a5607ceff6597c9d1757..af326a2975b5c71d6df7e27954310368a1e36813 100644 (file)
@@ -3,7 +3,7 @@
 
 extern void pci_iommu_shutdown(void);
 extern void no_iommu_init(void);
-extern struct dma_mapping_ops nommu_dma_ops;
+extern struct dma_map_ops nommu_dma_ops;
 extern int force_iommu, no_iommu;
 extern int iommu_detected;
 
index 107eb2196691134cd4f8bc2944e953a47e58805d..f38481bcd45538f26d640a2c460a3510246510d2 100644 (file)
@@ -36,6 +36,7 @@ static inline int irq_canonicalize(int irq)
 extern void fixup_irqs(void);
 #endif
 
+extern void (*generic_interrupt_extension)(void);
 extern void init_IRQ(void);
 extern void native_init_IRQ(void);
 extern bool handle_irq(unsigned irq, struct pt_regs *regs);
index 20e1fd588dbfbfefc30b567b35625098002f105c..0396760fccb85be05de0d5666c6019316d386d55 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _ASM_X86_IRQ_REMAPPING_H
 #define _ASM_X86_IRQ_REMAPPING_H
 
-extern int x2apic;
-
 #define IRTE_DEST(dest) ((x2apic) ? dest : dest << 8)
 
 #endif /* _ASM_X86_IRQ_REMAPPING_H */
index 8a285f356f8aef9e0e64b1210303c7d82acdfa19..3cbd79bbb47c82613341fca01ee6e174319342fe 100644 (file)
  */
 #define LOCAL_PERF_VECTOR              0xee
 
+/*
+ * Generic system vector for platform specific use
+ */
+#define GENERIC_INTERRUPT_VECTOR       0xed
+
 /*
  * First APIC vector available to drivers: (vectors 0x30-0xee) we
  * start at 0x31(0x41) to spread out vectors evenly between priority
index 0ceb6d19ed30a3285f6536799ef1cabe4af1cba9..317ff1703d0b0a5e7eaf17b94fd93640b8e62997 100644 (file)
@@ -9,13 +9,13 @@
 # define PAGES_NR              4
 #else
 # define PA_CONTROL_PAGE       0
-# define PA_TABLE_PAGE         1
-# define PAGES_NR              2
+# define VA_CONTROL_PAGE       1
+# define PA_TABLE_PAGE         2
+# define PA_SWAP_PAGE          3
+# define PAGES_NR              4
 #endif
 
-#ifdef CONFIG_X86_32
 # define KEXEC_CONTROL_CODE_MAX_SIZE   2048
-#endif
 
 #ifndef __ASSEMBLY__
 
@@ -136,10 +136,11 @@ relocate_kernel(unsigned long indirection_page,
                unsigned int has_pae,
                unsigned int preserve_context);
 #else
-NORET_TYPE void
+unsigned long
 relocate_kernel(unsigned long indirection_page,
                unsigned long page_list,
-               unsigned long start_address) ATTRIB_NORET;
+               unsigned long start_address,
+               unsigned int preserve_context);
 #endif
 
 #define ARCH_HAS_KIMAGE_ARCH
index 43894428c3c2a7d871bd5d49bcc0b2e136405e13..0f4ee7148afe2e0b7648ab8f89a544508bdf3309 100644 (file)
 
 #ifndef __ASSEMBLY__
 #include <asm/hw_irq.h>
+#include <asm/kvm_para.h>
 
 /*G:031 But first, how does our Guest contact the Host to ask for privileged
  * operations?  There are two ways: the direct way is to make a "hypercall",
  * to make requests of the Host Itself.
  *
- * Our hypercall mechanism uses the highest unused trap code (traps 32 and
- * above are used by real hardware interrupts).  Fifteen hypercalls are
+ * We use the KVM hypercall mechanism. Eighteen hypercalls are
  * available: the hypercall number is put in the %eax register, and the
- * arguments (when required) are placed in %edx, %ebx and %ecx.  If a return
+ * arguments (when required) are placed in %ebx, %ecx and %edx.  If a return
  * value makes sense, it's returned in %eax.
  *
  * Grossly invalid calls result in Sudden Death at the hands of the vengeful
  * Host, rather than returning failure.  This reflects Winston Churchill's
  * definition of a gentleman: "someone who is only rude intentionally". */
-static inline unsigned long
-hcall(unsigned long call,
-      unsigned long arg1, unsigned long arg2, unsigned long arg3)
-{
-       /* "int" is the Intel instruction to trigger a trap. */
-       asm volatile("int $" __stringify(LGUEST_TRAP_ENTRY)
-                    /* The call in %eax (aka "a") might be overwritten */
-                    : "=a"(call)
-                      /* The arguments are in %eax, %edx, %ebx & %ecx */
-                    : "a"(call), "d"(arg1), "b"(arg2), "c"(arg3)
-                      /* "memory" means this might write somewhere in memory.
-                       * This isn't true for all calls, but it's safe to tell
-                       * gcc that it might happen so it doesn't get clever. */
-                    : "memory");
-       return call;
-}
 /*:*/
 
 /* Can't use our min() macro here: needs to be a constant */
@@ -64,7 +48,7 @@ hcall(unsigned long call,
 #define LHCALL_RING_SIZE 64
 struct hcall_args {
        /* These map directly onto eax, ebx, ecx, edx in struct lguest_regs */
-       unsigned long arg0, arg2, arg3, arg1;
+       unsigned long arg0, arg1, arg2, arg3;
 };
 
 #endif /* !__ASSEMBLY__ */
index 9320e2a8a26a46e99aa2c5eae5a6bd381cc90610..12d55e773eb605ff85c67c8cbf8d453697e01871 100644 (file)
@@ -1,14 +1,11 @@
 #ifndef _ASM_X86_LINKAGE_H
 #define _ASM_X86_LINKAGE_H
 
+#include <linux/stringify.h>
+
 #undef notrace
 #define notrace __attribute__((no_instrument_function))
 
-#ifdef CONFIG_X86_64
-#define __ALIGN .p2align 4,,15
-#define __ALIGN_STR ".p2align 4,,15"
-#endif
-
 #ifdef CONFIG_X86_32
 #define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
 /*
        __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3), \
                              "g" (arg4), "g" (arg5), "g" (arg6))
 
-#endif
+#endif /* CONFIG_X86_32 */
+
+#ifdef __ASSEMBLY__
 
 #define GLOBAL(name)   \
        .globl name;    \
        name:
 
-#ifdef CONFIG_X86_ALIGNMENT_16
-#define __ALIGN .align 16,0x90
-#define __ALIGN_STR ".align 16,0x90"
+#if defined(CONFIG_X86_64) || defined(CONFIG_X86_ALIGNMENT_16)
+#define __ALIGN                .p2align 4, 0x90
+#define __ALIGN_STR    __stringify(__ALIGN)
 #endif
 
+#endif /* __ASSEMBLY__ */
+
 #endif /* _ASM_X86_LINKAGE_H */
 
index 32c6e17b960b7aed994078dc1d5c1fb4e547b2a4..563933e06a35fa48f6c828d3884f9b35886ab4eb 100644 (file)
@@ -11,6 +11,8 @@
  */
 
 #define MCG_CTL_P       (1UL<<8)   /* MCG_CAP register available */
+#define MCG_EXT_P       (1ULL<<9)   /* Extended registers available */
+#define MCG_CMCI_P      (1ULL<<10)  /* CMCI supported */
 
 #define MCG_STATUS_RIPV  (1UL<<0)   /* restart ip valid */
 #define MCG_STATUS_EIPV  (1UL<<1)   /* ip points to correct instruction */
@@ -90,14 +92,29 @@ extern int mce_disabled;
 
 #include <asm/atomic.h>
 
+void mce_setup(struct mce *m);
 void mce_log(struct mce *m);
 DECLARE_PER_CPU(struct sys_device, device_mce);
 extern void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu);
 
+/*
+ * To support more than 128 would need to escape the predefined
+ * Linux defined extended banks first.
+ */
+#define MAX_NR_BANKS (MCE_EXTENDED_BANK - 1)
+
 #ifdef CONFIG_X86_MCE_INTEL
 void mce_intel_feature_init(struct cpuinfo_x86 *c);
+void cmci_clear(void);
+void cmci_reenable(void);
+void cmci_rediscover(int dying);
+void cmci_recheck(void);
 #else
 static inline void mce_intel_feature_init(struct cpuinfo_x86 *c) { }
+static inline void cmci_clear(void) {}
+static inline void cmci_reenable(void) {}
+static inline void cmci_rediscover(int dying) {}
+static inline void cmci_recheck(void) {}
 #endif
 
 #ifdef CONFIG_X86_MCE_AMD
@@ -106,11 +123,23 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c);
 static inline void mce_amd_feature_init(struct cpuinfo_x86 *c) { }
 #endif
 
-void mce_log_therm_throt_event(unsigned int cpu, __u64 status);
+extern int mce_available(struct cpuinfo_x86 *c);
+
+void mce_log_therm_throt_event(__u64 status);
 
 extern atomic_t mce_entry;
 
 extern void do_machine_check(struct pt_regs *, long);
+
+typedef DECLARE_BITMAP(mce_banks_t, MAX_NR_BANKS);
+DECLARE_PER_CPU(mce_banks_t, mce_poll_banks);
+
+enum mcp_flags {
+       MCP_TIMESTAMP = (1 << 0),       /* log time stamp */
+       MCP_UC = (1 << 1),              /* log uncorrected errors */
+};
+extern void machine_check_poll(enum mcp_flags flags, mce_banks_t *b);
+
 extern int mce_notify_user(void);
 
 #endif /* !CONFIG_X86_32 */
@@ -120,8 +149,8 @@ extern void mcheck_init(struct cpuinfo_x86 *c);
 #else
 #define mcheck_init(c) do { } while (0)
 #endif
-extern void stop_mce(void);
-extern void restart_mce(void);
+
+extern void (*mce_threshold_vector)(void);
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_X86_MCE_H */
index 6706b3006f13296ee02c5a4455268a967ca1c5f3..4cc48af23fefa3e9bec1da781d13ea5beaebd379 100644 (file)
@@ -47,6 +47,7 @@
 #define         MSI_ADDR_DEST_ID_MASK          0x00ffff0
 #define  MSI_ADDR_DEST_ID(dest)                (((dest) << MSI_ADDR_DEST_ID_SHIFT) & \
                                         MSI_ADDR_DEST_ID_MASK)
+#define MSI_ADDR_EXT_DEST_ID(dest)     ((dest) & 0xffffff00)
 
 #define MSI_ADDR_IR_EXT_INT            (1 << 4)
 #define MSI_ADDR_IR_SHV                        (1 << 3)
index f4e505f286bc85cf828679dd91b4a743c582edde..ec41fc16c167cb19ef617f9a5e7ec2dda6f88bd1 100644 (file)
 #define MSR_IA32_MC0_ADDR              0x00000402
 #define MSR_IA32_MC0_MISC              0x00000403
 
+/* These are consecutive and not in the normal 4er MCE bank block */
+#define MSR_IA32_MC0_CTL2              0x00000280
+#define CMCI_EN                        (1ULL << 30)
+#define CMCI_THRESHOLD_MASK            0xffffULL
+
 #define MSR_P6_PERFCTR0                        0x000000c1
 #define MSR_P6_PERFCTR1                        0x000000c2
 #define MSR_P6_EVNTSEL0                        0x00000186
index f1e4a79a6e415702ab6930cedce937afc3e71d54..0f915ae649a717e99ebdfc079652b25fda315e72 100644 (file)
 #define __VIRTUAL_MASK_SHIFT   32
 #endif /* CONFIG_X86_PAE */
 
+/*
+ * Kernel image size is limited to 512 MB (see in arch/x86/kernel/head_32.S)
+ */
+#define KERNEL_IMAGE_SIZE      (512 * 1024 * 1024)
+
 #ifndef __ASSEMBLY__
 
 /*
index 2d625da6603c36958cd51a130f6ae41ce2df0f3d..826ad37006ab1a075993ddbe69bd3281412b7f09 100644 (file)
 
 #ifndef __ASSEMBLY__
 
-struct pgprot;
-
 extern int page_is_ram(unsigned long pagenr);
 extern int devmem_is_allowed(unsigned long pagenr);
-extern void map_devmem(unsigned long pfn, unsigned long size,
-                      struct pgprot vma_prot);
-extern void unmap_devmem(unsigned long pfn, unsigned long size,
-                        struct pgprot vma_prot);
 
 extern unsigned long max_low_pfn_mapped;
 extern unsigned long max_pfn_mapped;
index 0617d5cc9712d00a3ca61ad80f515484cb7798e5..7727aa8b7dda99087ca5ced1046a92046ab7c4d5 100644 (file)
@@ -317,8 +317,6 @@ struct pv_mmu_ops {
 #if PAGETABLE_LEVELS >= 3
 #ifdef CONFIG_X86_PAE
        void (*set_pte_atomic)(pte_t *ptep, pte_t pteval);
-       void (*set_pte_present)(struct mm_struct *mm, unsigned long addr,
-                               pte_t *ptep, pte_t pte);
        void (*pte_clear)(struct mm_struct *mm, unsigned long addr,
                          pte_t *ptep);
        void (*pmd_clear)(pmd_t *pmdp);
@@ -389,7 +387,7 @@ extern struct pv_lock_ops pv_lock_ops;
 
 #define paravirt_type(op)                              \
        [paravirt_typenum] "i" (PARAVIRT_PATCH(op)),    \
-       [paravirt_opptr] "m" (op)
+       [paravirt_opptr] "i" (&(op))
 #define paravirt_clobber(clobber)              \
        [paravirt_clobber] "i" (clobber)
 
@@ -443,7 +441,7 @@ int paravirt_disable_iospace(void);
  * offset into the paravirt_patch_template structure, and can therefore be
  * freely converted back into a structure offset.
  */
-#define PARAVIRT_CALL  "call *%[paravirt_opptr];"
+#define PARAVIRT_CALL  "call *%c[paravirt_opptr];"
 
 /*
  * These macros are intended to wrap calls through one of the paravirt
@@ -1365,13 +1363,6 @@ static inline void set_pte_atomic(pte_t *ptep, pte_t pte)
                    pte.pte, pte.pte >> 32);
 }
 
-static inline void set_pte_present(struct mm_struct *mm, unsigned long addr,
-                                  pte_t *ptep, pte_t pte)
-{
-       /* 5 arg words */
-       pv_mmu_ops.set_pte_present(mm, addr, ptep, pte);
-}
-
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
                             pte_t *ptep)
 {
@@ -1388,12 +1379,6 @@ static inline void set_pte_atomic(pte_t *ptep, pte_t pte)
        set_pte(ptep, pte);
 }
 
-static inline void set_pte_present(struct mm_struct *mm, unsigned long addr,
-                                  pte_t *ptep, pte_t pte)
-{
-       set_pte(ptep, pte);
-}
-
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
                             pte_t *ptep)
 {
index b0e70056838e9d49c4e530f0396926c91abef1fb..2cd07b9422f49cbe8b87e561e140f0f31c28e77f 100644 (file)
@@ -2,6 +2,7 @@
 #define _ASM_X86_PAT_H
 
 #include <linux/types.h>
+#include <asm/pgtable_types.h>
 
 #ifdef CONFIG_X86_PAT
 extern int pat_enabled;
@@ -17,5 +18,9 @@ extern int free_memtype(u64 start, u64 end);
 
 extern int kernel_map_sync_memtype(u64 base, unsigned long size,
                unsigned long flag);
+extern void map_devmem(unsigned long pfn, unsigned long size,
+                      struct pgprot vma_prot);
+extern void unmap_devmem(unsigned long pfn, unsigned long size,
+                        struct pgprot vma_prot);
 
 #endif /* _ASM_X86_PAT_H */
index a977de23cb4d83320e5255de21ffc073a0859403..a0301bfeb954d457eaf080a14ee0f2a872ccc519 100644 (file)
@@ -86,6 +86,9 @@ static inline void early_quirks(void) { }
 
 extern void pci_iommu_alloc(void);
 
+/* MSI arch hook */
+#define arch_setup_msi_irqs arch_setup_msi_irqs
+
 #endif  /* __KERNEL__ */
 
 #ifdef CONFIG_X86_32
index c1774ac9da7a90f30dd47da6ac99e7b9b98494fd..2334982b339ebcb08e92846c54e2aeb375917984 100644 (file)
@@ -26,13 +26,6 @@ static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte)
        native_set_pte(ptep, pte);
 }
 
-static inline void native_set_pte_present(struct mm_struct *mm,
-                                         unsigned long addr,
-                                         pte_t *ptep, pte_t pte)
-{
-       native_set_pte(ptep, pte);
-}
-
 static inline void native_pmd_clear(pmd_t *pmdp)
 {
        native_set_pmd(pmdp, __pmd(0));
index 3f13cdf61156b4ed330ca60ea717b2044bc9faa6..177b0165ea01fa8aeeb1f8749252d422de52b3a6 100644 (file)
@@ -31,23 +31,6 @@ static inline void native_set_pte(pte_t *ptep, pte_t pte)
        ptep->pte_low = pte.pte_low;
 }
 
-/*
- * Since this is only called on user PTEs, and the page fault handler
- * must handle the already racy situation of simultaneous page faults,
- * we are justified in merely clearing the PTE present bit, followed
- * by a set.  The ordering here is important.
- */
-static inline void native_set_pte_present(struct mm_struct *mm,
-                                         unsigned long addr,
-                                         pte_t *ptep, pte_t pte)
-{
-       ptep->pte_low = 0;
-       smp_wmb();
-       ptep->pte_high = pte.pte_high;
-       smp_wmb();
-       ptep->pte_low = pte.pte_low;
-}
-
 static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte)
 {
        set_64bit((unsigned long long *)(ptep), native_pte_val(pte));
index d0812e155f1d60da04c614bee8b97e2e33869876..29d96d168bc097195e9cbe66ab723c90929e1116 100644 (file)
@@ -31,8 +31,6 @@ extern struct list_head pgd_list;
 #define set_pte(ptep, pte)             native_set_pte(ptep, pte)
 #define set_pte_at(mm, addr, ptep, pte)        native_set_pte_at(mm, addr, ptep, pte)
 
-#define set_pte_present(mm, addr, ptep, pte)                           \
-       native_set_pte_present(mm, addr, ptep, pte)
 #define set_pte_atomic(ptep, pte)                                      \
        native_set_pte_atomic(ptep, pte)
 
index 97612fc7632f0ef95ebb3afecd3886bfe1b176ae..31bd120cf2a2ec10469929c43a110ea559f2adf7 100644 (file)
@@ -42,9 +42,6 @@ extern void set_pmd_pfn(unsigned long, unsigned long, pgprot_t);
  */
 #undef TEST_ACCESS_OK
 
-/* The boot page tables (all created as a single array) */
-extern unsigned long pg0[];
-
 #ifdef CONFIG_X86_PAE
 # include <asm/pgtable-3level.h>
 #else
index bd8df3b2fe04fc61fc0912569ebbf498969a028f..2733fad45f989bfd5a775c99e5decb35cfe8014a 100644 (file)
  * area for the same reason. ;)
  */
 #define VMALLOC_OFFSET (8 * 1024 * 1024)
+
+#ifndef __ASSEMBLER__
+extern bool __vmalloc_start_set; /* set once high_memory is set */
+#endif
+
 #define VMALLOC_START  ((unsigned long)high_memory + VMALLOC_OFFSET)
 #ifdef CONFIG_X86_PAE
 #define LAST_PKMAP 512
index 4d258ad76a0fc04925ac484c1fa9b0bfc47a1cb9..b8238dc8786d9f6b4291c2d7f912abbc0ea04e18 100644 (file)
@@ -273,6 +273,7 @@ typedef struct page *pgtable_t;
 
 extern pteval_t __supported_pte_mask;
 extern int nx_enabled;
+extern void set_nx(void);
 
 #define pgprot_writecombine    pgprot_writecombine
 extern pgprot_t pgprot_writecombine(pgprot_t prot);
index 76139506c3e4f489d6252edd272e98d0e8637ead..ae85a8d66a30601a1a22c3b6b84f3df6d3056477 100644 (file)
@@ -75,9 +75,9 @@ struct cpuinfo_x86 {
 #else
        /* Number of 4K pages in DTLB/ITLB combined(in pages): */
        int                     x86_tlbsize;
+#endif
        __u8                    x86_virt_bits;
        __u8                    x86_phys_bits;
-#endif
        /* CPUID returned core id bits: */
        __u8                    x86_coreid_bits;
        /* Max extended CPUID function supported: */
@@ -391,6 +391,9 @@ DECLARE_PER_CPU(union irq_stack_union, irq_stack_union);
 DECLARE_INIT_PER_CPU(irq_stack_union);
 
 DECLARE_PER_CPU(char *, irq_stack_ptr);
+DECLARE_PER_CPU(unsigned int, irq_count);
+extern unsigned long kernel_eflags;
+extern asmlinkage void ignore_sysret(void);
 #else  /* X86_64 */
 #ifdef CONFIG_CC_STACKPROTECTOR
 DECLARE_PER_CPU(unsigned long, stack_canary);
index 2b8c5160388fb4863f05c33c15e42e22c53fc7a2..1b7ee5d673c23552514e7f6d6466bbcaa10ebeda 100644 (file)
@@ -1 +1,8 @@
+#ifndef _ASM_X86_SECTIONS_H
+#define _ASM_X86_SECTIONS_H
+
 #include <asm-generic/sections.h>
+
+extern char __brk_base[], __brk_limit[];
+
+#endif /* _ASM_X86_SECTIONS_H */
index 05c6f6b11fd5d25354ddcd7d3d07cf7cf7bf3fe5..bdc2ada05ae06056ad95e79bd8d6434d73510f5a 100644 (file)
@@ -64,7 +64,7 @@ extern void x86_quirk_time_init(void);
 #include <asm/bootparam.h>
 
 /* Interrupt control for vSMPowered x86_64 systems */
-#ifdef CONFIG_X86_VSMP
+#ifdef CONFIG_X86_64
 void vsmp_init(void);
 #else
 static inline void vsmp_init(void) { }
@@ -100,20 +100,51 @@ extern struct boot_params boot_params;
  */
 #define LOWMEMSIZE()   (0x9f000)
 
+/* exceedingly early brk-like allocator */
+extern unsigned long _brk_end;
+void *extend_brk(size_t size, size_t align);
+
+/*
+ * Reserve space in the brk section.  The name must be unique within
+ * the file, and somewhat descriptive.  The size is in bytes.  Must be
+ * used at file scope.
+ *
+ * (This uses a temp function to wrap the asm so we can pass it the
+ * size parameter; otherwise we wouldn't be able to.  We can't use a
+ * "section" attribute on a normal variable because it always ends up
+ * being @progbits, which ends up allocating space in the vmlinux
+ * executable.)
+ */
+#define RESERVE_BRK(name,sz)                                           \
+       static void __section(.discard) __used                          \
+       __brk_reservation_fn_##name##__(void) {                         \
+               asm volatile (                                          \
+                       ".pushsection .brk_reservation,\"aw\",@nobits;" \
+                       ".brk." #name ":"                               \
+                       " 1:.skip %c0;"                                 \
+                       " .size .brk." #name ", . - 1b;"                \
+                       " .popsection"                                  \
+                       : : "i" (sz));                                  \
+       }
+
 #ifdef __i386__
 
 void __init i386_start_kernel(void);
 extern void probe_roms(void);
 
-extern unsigned long init_pg_tables_start;
-extern unsigned long init_pg_tables_end;
-
 #else
 void __init x86_64_start_kernel(char *real_mode);
 void __init x86_64_start_reservations(char *real_mode_data);
 
 #endif /* __i386__ */
 #endif /* _SETUP */
+#else
+#define RESERVE_BRK(name,sz)                           \
+       .pushsection .brk_reservation,"aw",@nobits;     \
+.brk.name:                                             \
+1:     .skip sz;                                       \
+       .size .brk.name,.-1b;                           \
+       .popsection
 #endif /* __ASSEMBLY__ */
 #endif  /*  __KERNEL__  */
 
index 3a569665668020755ac910307ee21114f7f7a7ca..e5e6caffec87ab61063cd8c356ebd8f59523b00b 100644 (file)
@@ -295,6 +295,9 @@ static inline void __raw_write_unlock(raw_rwlock_t *rw)
                     : "+m" (rw->lock) : "i" (RW_LOCK_BIAS) : "memory");
 }
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
index a5074bd0f8be5a268888237d14668b5ea9eb4ab4..48dcfa62ea07eb5985ef61c526ed767da3795283 100644 (file)
@@ -24,28 +24,4 @@ struct saved_context {
        unsigned long return_address;
 } __attribute__((packed));
 
-#ifdef CONFIG_ACPI
-extern unsigned long saved_eip;
-extern unsigned long saved_esp;
-extern unsigned long saved_ebp;
-extern unsigned long saved_ebx;
-extern unsigned long saved_esi;
-extern unsigned long saved_edi;
-
-static inline void acpi_save_register_state(unsigned long return_point)
-{
-       saved_eip = return_point;
-       asm volatile("movl %%esp,%0" : "=m" (saved_esp));
-       asm volatile("movl %%ebp,%0" : "=m" (saved_ebp));
-       asm volatile("movl %%ebx,%0" : "=m" (saved_ebx));
-       asm volatile("movl %%edi,%0" : "=m" (saved_edi));
-       asm volatile("movl %%esi,%0" : "=m" (saved_esi));
-}
-
-#define acpi_restore_register_state()  do {} while (0)
-
-/* routines for saving/restoring kernel state */
-extern int acpi_save_state_mem(void);
-#endif
-
 #endif /* _ASM_X86_SUSPEND_32_H */
index a81195eaa2b3dc3d4378d523ee79c256ca752e52..bd37ed444a21fe18af14826fef924ac0ec2bd5e5 100644 (file)
@@ -12,9 +12,9 @@ unsigned long native_calibrate_tsc(void);
 
 #ifdef CONFIG_X86_32
 extern int timer_ack;
-extern int recalibrate_cpu_khz(void);
 extern irqreturn_t timer_interrupt(int irq, void *dev_id);
 #endif /* CONFIG_X86_32 */
+extern int recalibrate_cpu_khz(void);
 
 extern int no_timer_check;
 
index 77cfb2cfb386d5b1a1727807b2a7c84ee8fc4c6c..744299c0b7749829a2af79dc76eb10f0fbfa6a55 100644 (file)
@@ -217,10 +217,6 @@ static inline cpumask_t node_to_cpumask(int node)
 {
        return cpu_online_map;
 }
-static inline int node_to_first_cpu(int node)
-{
-       return first_cpu(cpu_online_map);
-}
 
 static inline void setup_node_to_cpumask_map(void) { }
 
@@ -237,14 +233,6 @@ static inline void setup_node_to_cpumask_map(void) { }
 
 #include <asm-generic/topology.h>
 
-#ifdef CONFIG_NUMA
-/* Returns the number of the first CPU on Node 'node'. */
-static inline int node_to_first_cpu(int node)
-{
-       return cpumask_first(cpumask_of_node(node));
-}
-#endif
-
 extern cpumask_t cpu_coregroup_map(int cpu);
 extern const struct cpumask *cpu_coregroup_mask(int cpu);
 
index f2bba78430a4d2628ca83203e193dcb6ee78a247..6e72d74cf8dc74b7720f5cb79ba355a926e7fa6e 100644 (file)
 #define __NR_dup3              330
 #define __NR_pipe2             331
 #define __NR_inotify_init1     332
+#define __NR_preadv            333
+#define __NR_pwritev           334
 
 #ifdef __KERNEL__
 
index d2e415e6666f63d314270ef57a26dae73e3fac01..f81829462325f6328a6e6d9c3667da02e9f616d0 100644 (file)
@@ -653,6 +653,10 @@ __SYSCALL(__NR_dup3, sys_dup3)
 __SYSCALL(__NR_pipe2, sys_pipe2)
 #define __NR_inotify_init1                     294
 __SYSCALL(__NR_inotify_init1, sys_inotify_init1)
+#define __NR_preadv                            295
+__SYSCALL(__NR_preadv, sys_preadv)
+#define __NR_pwritev                           296
+__SYSCALL(__NR_pwritev, sys_pwritev)
 
 
 #ifndef __NO_STUBS
index 777327ef05c19f0887c0b9b089a6f71135395e94..d3a98ea1062ef936c7825f1387a4d2f4b83c65b9 100644 (file)
 #ifndef _ASM_X86_UV_UV_HUB_H
 #define _ASM_X86_UV_UV_HUB_H
 
+#ifdef CONFIG_X86_64
 #include <linux/numa.h>
 #include <linux/percpu.h>
 #include <linux/timer.h>
 #include <asm/types.h>
 #include <asm/percpu.h>
+#include <asm/uv/uv_mmrs.h>
 
 
 /*
@@ -199,6 +201,10 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
 #define SCIR_CPU_ACTIVITY      0x02    /* not idle */
 #define SCIR_CPU_HB_INTERVAL   (HZ)    /* once per second */
 
+/* Loop through all installed blades */
+#define for_each_possible_blade(bid)           \
+       for ((bid) = 0; (bid) < uv_num_possible_blades(); (bid)++)
+
 /*
  * Macros for converting between kernel virtual addresses, socket local physical
  * addresses, and UV global physical addresses.
@@ -393,6 +399,7 @@ static inline void uv_set_scir_bits(unsigned char value)
                uv_write_local_mmr8(uv_hub_info->scir.offset, value);
        }
 }
+
 static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value)
 {
        if (uv_cpu_hub_info(cpu)->scir.state != value) {
@@ -401,4 +408,15 @@ static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value)
        }
 }
 
+static inline void uv_hub_send_ipi(int pnode, int apicid, int vector)
+{
+       unsigned long val;
+
+       val = (1UL << UVH_IPI_INT_SEND_SHFT) |
+                       ((apicid & 0x3f) << UVH_IPI_INT_APIC_ID_SHFT) |
+                       (vector << UVH_IPI_INT_VECTOR_SHFT);
+       uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
+}
+
+#endif /* CONFIG_X86_64 */
 #endif /* _ASM_X86_UV_UV_HUB_H */
index dd627793a23444d109fa966cda31bc43d14a83e2..db68ac8a5ac285207b4f274ede74622e8a7e23c6 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -242,6 +243,158 @@ union uvh_event_occurred0_u {
 #define UVH_EVENT_OCCURRED0_ALIAS 0x0000000000070008UL
 #define UVH_EVENT_OCCURRED0_ALIAS_32 0x005f0
 
+/* ========================================================================= */
+/*                         UVH_GR0_TLB_INT0_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR0_TLB_INT0_CONFIG 0x61b00UL
+
+#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_SHFT 0
+#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_GR0_TLB_INT0_CONFIG_DM_SHFT 8
+#define UVH_GR0_TLB_INT0_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_GR0_TLB_INT0_CONFIG_DESTMODE_SHFT 11
+#define UVH_GR0_TLB_INT0_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_GR0_TLB_INT0_CONFIG_STATUS_SHFT 12
+#define UVH_GR0_TLB_INT0_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_GR0_TLB_INT0_CONFIG_P_SHFT 13
+#define UVH_GR0_TLB_INT0_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_GR0_TLB_INT0_CONFIG_T_SHFT 15
+#define UVH_GR0_TLB_INT0_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_GR0_TLB_INT0_CONFIG_M_SHFT 16
+#define UVH_GR0_TLB_INT0_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_GR0_TLB_INT0_CONFIG_APIC_ID_SHFT 32
+#define UVH_GR0_TLB_INT0_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_gr0_tlb_int0_config_u {
+    unsigned long      v;
+    struct uvh_gr0_tlb_int0_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                         UVH_GR0_TLB_INT1_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR0_TLB_INT1_CONFIG 0x61b40UL
+
+#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_SHFT 0
+#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_GR0_TLB_INT1_CONFIG_DM_SHFT 8
+#define UVH_GR0_TLB_INT1_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_GR0_TLB_INT1_CONFIG_DESTMODE_SHFT 11
+#define UVH_GR0_TLB_INT1_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_GR0_TLB_INT1_CONFIG_STATUS_SHFT 12
+#define UVH_GR0_TLB_INT1_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_GR0_TLB_INT1_CONFIG_P_SHFT 13
+#define UVH_GR0_TLB_INT1_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_GR0_TLB_INT1_CONFIG_T_SHFT 15
+#define UVH_GR0_TLB_INT1_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_GR0_TLB_INT1_CONFIG_M_SHFT 16
+#define UVH_GR0_TLB_INT1_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_GR0_TLB_INT1_CONFIG_APIC_ID_SHFT 32
+#define UVH_GR0_TLB_INT1_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_gr0_tlb_int1_config_u {
+    unsigned long      v;
+    struct uvh_gr0_tlb_int1_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                         UVH_GR1_TLB_INT0_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR1_TLB_INT0_CONFIG 0x61f00UL
+
+#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_SHFT 0
+#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_GR1_TLB_INT0_CONFIG_DM_SHFT 8
+#define UVH_GR1_TLB_INT0_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_GR1_TLB_INT0_CONFIG_DESTMODE_SHFT 11
+#define UVH_GR1_TLB_INT0_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_GR1_TLB_INT0_CONFIG_STATUS_SHFT 12
+#define UVH_GR1_TLB_INT0_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_GR1_TLB_INT0_CONFIG_P_SHFT 13
+#define UVH_GR1_TLB_INT0_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_GR1_TLB_INT0_CONFIG_T_SHFT 15
+#define UVH_GR1_TLB_INT0_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_GR1_TLB_INT0_CONFIG_M_SHFT 16
+#define UVH_GR1_TLB_INT0_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_GR1_TLB_INT0_CONFIG_APIC_ID_SHFT 32
+#define UVH_GR1_TLB_INT0_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_gr1_tlb_int0_config_u {
+    unsigned long      v;
+    struct uvh_gr1_tlb_int0_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                         UVH_GR1_TLB_INT1_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR1_TLB_INT1_CONFIG 0x61f40UL
+
+#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_SHFT 0
+#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_GR1_TLB_INT1_CONFIG_DM_SHFT 8
+#define UVH_GR1_TLB_INT1_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_GR1_TLB_INT1_CONFIG_DESTMODE_SHFT 11
+#define UVH_GR1_TLB_INT1_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_GR1_TLB_INT1_CONFIG_STATUS_SHFT 12
+#define UVH_GR1_TLB_INT1_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_GR1_TLB_INT1_CONFIG_P_SHFT 13
+#define UVH_GR1_TLB_INT1_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_GR1_TLB_INT1_CONFIG_T_SHFT 15
+#define UVH_GR1_TLB_INT1_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_GR1_TLB_INT1_CONFIG_M_SHFT 16
+#define UVH_GR1_TLB_INT1_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_GR1_TLB_INT1_CONFIG_APIC_ID_SHFT 32
+#define UVH_GR1_TLB_INT1_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_gr1_tlb_int1_config_u {
+    unsigned long      v;
+    struct uvh_gr1_tlb_int1_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
 /* ========================================================================= */
 /*                               UVH_INT_CMPB                                */
 /* ========================================================================= */
index 5e79ca694326cdeb85886d371565ad506fe6f0af..9c371e4a9fa6e122a25b6cf745fde11b027ba313 100644 (file)
@@ -296,6 +296,8 @@ HYPERVISOR_get_debugreg(int reg)
 static inline int
 HYPERVISOR_update_descriptor(u64 ma, u64 desc)
 {
+       if (sizeof(u64) == sizeof(long))
+               return _hypercall2(int, update_descriptor, ma, desc);
        return _hypercall4(int, update_descriptor, ma, ma>>32, desc, desc>>32);
 }
 
index 95f216bbfaf16f6b8572c40c4cdfa756758f6be5..c611ad64137f67c1fc06789049e8093365bf1ed7 100644 (file)
@@ -70,7 +70,6 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER)   += ftrace.o
 obj-$(CONFIG_KEXEC)            += machine_kexec_$(BITS).o
 obj-$(CONFIG_KEXEC)            += relocate_kernel_$(BITS).o crash.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump_$(BITS).o
-obj-$(CONFIG_X86_VSMP)         += vsmp_64.o
 obj-$(CONFIG_KPROBES)          += kprobes.o
 obj-$(CONFIG_MODULES)          += module_$(BITS).o
 obj-$(CONFIG_EFI)              += efi.o efi_$(BITS).o efi_stub_$(BITS).o
@@ -106,12 +105,12 @@ obj-$(CONFIG_MICROCODE)                   += microcode.o
 
 obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
 
-obj-$(CONFIG_SWIOTLB)                  += pci-swiotlb_64.o # NB rename without _64
+obj-$(CONFIG_SWIOTLB)                  += pci-swiotlb.o
 
 ###
 # 64 bit specific files
 ifeq ($(CONFIG_X86_64),y)
-       obj-$(CONFIG_X86_UV)            += tlb_uv.o bios_uv.o uv_irq.o uv_sysfs.o
+       obj-$(CONFIG_X86_UV)            += tlb_uv.o bios_uv.o uv_irq.o uv_sysfs.o uv_time.o
        obj-$(CONFIG_X86_PM_TIMER)      += pmtimer_64.o
        obj-$(CONFIG_AUDIT)             += audit_64.o
 
@@ -120,4 +119,5 @@ ifeq ($(CONFIG_X86_64),y)
        obj-$(CONFIG_AMD_IOMMU)         += amd_iommu_init.o amd_iommu.o
 
        obj-$(CONFIG_PCI_MMCONFIG)      += mmconf-fam10h_64.o
+       obj-y                           += vsmp_64.o
 endif
index 6907b8e85d52c580083d47971e4fa9192259c7f9..4c80f15574335d6b02bc93a7ed797c088c1da6c2 100644 (file)
@@ -414,9 +414,17 @@ void __init alternative_instructions(void)
           that might execute the to be patched code.
           Other CPUs are not running. */
        stop_nmi();
-#ifdef CONFIG_X86_MCE
-       stop_mce();
-#endif
+
+       /*
+        * Don't stop machine check exceptions while patching.
+        * MCEs only happen when something got corrupted and in this
+        * case we must do something about the corruption.
+        * Ignoring it is worse than a unlikely patching race.
+        * Also machine checks tend to be broadcast and if one CPU
+        * goes into machine check the others follow quickly, so we don't
+        * expect a machine check to cause undue problems during to code
+        * patching.
+        */
 
        apply_alternatives(__alt_instructions, __alt_instructions_end);
 
@@ -456,9 +464,6 @@ void __init alternative_instructions(void)
                                (unsigned long)__smp_locks_end);
 
        restart_nmi();
-#ifdef CONFIG_X86_MCE
-       restart_mce();
-#endif
 }
 
 /**
index 5113c080f0c442093db228b759946766f59afb06..c5962fe3796fbabe71024e3892354e8297d23a5f 100644 (file)
 #include <linux/bitops.h>
 #include <linux/debugfs.h>
 #include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
 #include <linux/iommu-helper.h>
-#ifdef CONFIG_IOMMU_API
 #include <linux/iommu.h>
-#endif
 #include <asm/proto.h>
 #include <asm/iommu.h>
 #include <asm/gart.h>
@@ -1297,8 +1296,10 @@ static void __unmap_single(struct amd_iommu *iommu,
 /*
  * The exported map_single function for dma_ops.
  */
-static dma_addr_t map_single(struct device *dev, phys_addr_t paddr,
-                            size_t size, int dir)
+static dma_addr_t map_page(struct device *dev, struct page *page,
+                          unsigned long offset, size_t size,
+                          enum dma_data_direction dir,
+                          struct dma_attrs *attrs)
 {
        unsigned long flags;
        struct amd_iommu *iommu;
@@ -1306,6 +1307,7 @@ static dma_addr_t map_single(struct device *dev, phys_addr_t paddr,
        u16 devid;
        dma_addr_t addr;
        u64 dma_mask;
+       phys_addr_t paddr = page_to_phys(page) + offset;
 
        INC_STATS_COUNTER(cnt_map_single);
 
@@ -1340,8 +1342,8 @@ out:
 /*
  * The exported unmap_single function for dma_ops.
  */
-static void unmap_single(struct device *dev, dma_addr_t dma_addr,
-                        size_t size, int dir)
+static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
+                      enum dma_data_direction dir, struct dma_attrs *attrs)
 {
        unsigned long flags;
        struct amd_iommu *iommu;
@@ -1390,7 +1392,8 @@ static int map_sg_no_iommu(struct device *dev, struct scatterlist *sglist,
  * lists).
  */
 static int map_sg(struct device *dev, struct scatterlist *sglist,
-                 int nelems, int dir)
+                 int nelems, enum dma_data_direction dir,
+                 struct dma_attrs *attrs)
 {
        unsigned long flags;
        struct amd_iommu *iommu;
@@ -1457,7 +1460,8 @@ unmap:
  * lists).
  */
 static void unmap_sg(struct device *dev, struct scatterlist *sglist,
-                    int nelems, int dir)
+                    int nelems, enum dma_data_direction dir,
+                    struct dma_attrs *attrs)
 {
        unsigned long flags;
        struct amd_iommu *iommu;
@@ -1644,11 +1648,11 @@ static void prealloc_protection_domains(void)
        }
 }
 
-static struct dma_mapping_ops amd_iommu_dma_ops = {
+static struct dma_map_ops amd_iommu_dma_ops = {
        .alloc_coherent = alloc_coherent,
        .free_coherent = free_coherent,
-       .map_single = map_single,
-       .unmap_single = unmap_single,
+       .map_page = map_page,
+       .unmap_page = unmap_page,
        .map_sg = map_sg,
        .unmap_sg = unmap_sg,
        .dma_supported = amd_iommu_dma_supported,
index f9cecdfd05c5523cb6298a27a3d03706e92fb21a..85eb8e100818d2dfef0bae935684e6fe0253c888 100644 (file)
@@ -46,6 +46,7 @@
 #include <asm/idle.h>
 #include <asm/mtrr.h>
 #include <asm/smp.h>
+#include <asm/mce.h>
 
 unsigned int num_processors;
 
@@ -808,7 +809,7 @@ void clear_local_APIC(void)
        u32 v;
 
        /* APIC hasn't been mapped yet */
-       if (!apic_phys)
+       if (!x2apic && !apic_phys)
                return;
 
        maxlvt = lapic_get_maxlvt();
@@ -842,6 +843,14 @@ void clear_local_APIC(void)
                apic_write(APIC_LVTTHMR, v | APIC_LVT_MASKED);
        }
 #endif
+#ifdef CONFIG_X86_MCE_INTEL
+       if (maxlvt >= 6) {
+               v = apic_read(APIC_LVTCMCI);
+               if (!(v & APIC_LVT_MASKED))
+                       apic_write(APIC_LVTCMCI, v | APIC_LVT_MASKED);
+       }
+#endif
+
        /*
         * Clean APIC state for other OSs:
         */
@@ -1241,6 +1250,12 @@ void __cpuinit setup_local_APIC(void)
        apic_write(APIC_LVT1, value);
 
        preempt_enable();
+
+#ifdef CONFIG_X86_MCE_INTEL
+       /* Recheck CMCI information after local APIC is up on CPU #0 */
+       if (smp_processor_id() == 0)
+               cmci_recheck();
+#endif
 }
 
 void __cpuinit end_local_APIC_setup(void)
@@ -1319,15 +1334,16 @@ void __init enable_IR_x2apic(void)
                return;
        }
 
-       local_irq_save(flags);
-       mask_8259A();
-
-       ret = save_mask_IO_APIC_setup();
+       ret = save_IO_APIC_setup();
        if (ret) {
                pr_info("Saving IO-APIC state failed: %d\n", ret);
                goto end;
        }
 
+       local_irq_save(flags);
+       mask_IO_APIC_setup();
+       mask_8259A();
+
        ret = enable_intr_remapping(1);
 
        if (ret && x2apic_preenabled) {
@@ -1352,10 +1368,10 @@ end_restore:
        else
                reinit_intr_remapped_IO_APIC(x2apic_preenabled);
 
-end:
        unmask_8259A();
        local_irq_restore(flags);
 
+end:
        if (!ret) {
                if (!x2apic_preenabled)
                        pr_info("Enabled x2apic and interrupt-remapping\n");
@@ -1508,12 +1524,10 @@ void __init early_init_lapic_mapping(void)
  */
 void __init init_apic_mappings(void)
 {
-#ifdef CONFIG_X86_X2APIC
        if (x2apic) {
                boot_cpu_physical_apicid = read_apic_id();
                return;
        }
-#endif
 
        /*
         * If no local APIC can be found then set up a fake all
@@ -1957,12 +1971,9 @@ static int lapic_resume(struct sys_device *dev)
 
        local_irq_save(flags);
 
-#ifdef CONFIG_X86_X2APIC
        if (x2apic)
                enable_x2apic();
-       else
-#endif
-       {
+       else {
                /*
                 * Make sure the APICBASE points to the right address
                 *
index f933822dba188fa8cac62e5b404ead77becf4b78..0014714ea97b6e58f8ceeb012aa0a1ae0d9e0975 100644 (file)
@@ -159,20 +159,6 @@ static int flat_apic_id_registered(void)
        return physid_isset(read_xapic_id(), phys_cpu_present_map);
 }
 
-static unsigned int flat_cpu_mask_to_apicid(const struct cpumask *cpumask)
-{
-       return cpumask_bits(cpumask)[0] & APIC_ALL_CPUS;
-}
-
-static unsigned int flat_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-                                               const struct cpumask *andmask)
-{
-       unsigned long mask1 = cpumask_bits(cpumask)[0] & APIC_ALL_CPUS;
-       unsigned long mask2 = cpumask_bits(andmask)[0] & APIC_ALL_CPUS;
-
-       return mask1 & mask2;
-}
-
 static int flat_phys_pkg_id(int initial_apic_id, int index_msb)
 {
        return hard_smp_processor_id() >> index_msb;
@@ -213,8 +199,8 @@ struct apic apic_flat =  {
        .set_apic_id                    = set_apic_id,
        .apic_id_mask                   = 0xFFu << 24,
 
-       .cpu_mask_to_apicid             = flat_cpu_mask_to_apicid,
-       .cpu_mask_to_apicid_and         = flat_cpu_mask_to_apicid_and,
+       .cpu_mask_to_apicid             = default_cpu_mask_to_apicid,
+       .cpu_mask_to_apicid_and         = default_cpu_mask_to_apicid_and,
 
        .send_IPI_mask                  = flat_send_IPI_mask,
        .send_IPI_mask_allbutself       = flat_send_IPI_mask_allbutself,
index 00e6071cefc436a792a71acf571860fe324a1ff6..1bb5c6cee3ebb140e30e421c05615bf94b001936 100644 (file)
@@ -389,6 +389,8 @@ struct io_apic {
        unsigned int index;
        unsigned int unused[3];
        unsigned int data;
+       unsigned int unused2[11];
+       unsigned int eoi;
 };
 
 static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
@@ -397,6 +399,12 @@ static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
                + (mp_ioapics[idx].apicaddr & ~PAGE_MASK);
 }
 
+static inline void io_apic_eoi(unsigned int apic, unsigned int vector)
+{
+       struct io_apic __iomem *io_apic = io_apic_base(apic);
+       writel(vector, &io_apic->eoi);
+}
+
 static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
 {
        struct io_apic __iomem *io_apic = io_apic_base(apic);
@@ -546,16 +554,12 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq
 
                apic = entry->apic;
                pin = entry->pin;
-#ifdef CONFIG_INTR_REMAP
                /*
                 * With interrupt-remapping, destination information comes
                 * from interrupt-remapping table entry.
                 */
                if (!irq_remapped(irq))
                        io_apic_write(apic, 0x11 + pin*2, dest);
-#else
-               io_apic_write(apic, 0x11 + pin*2, dest);
-#endif
                reg = io_apic_read(apic, 0x10 + pin*2);
                reg &= ~IO_APIC_REDIR_VECTOR_MASK;
                reg |= vector;
@@ -588,10 +592,12 @@ set_desc_affinity(struct irq_desc *desc, const struct cpumask *mask)
        if (assign_irq_vector(irq, cfg, mask))
                return BAD_APICID;
 
-       cpumask_and(desc->affinity, cfg->domain, mask);
+       /* check that before desc->addinity get updated */
        set_extra_move_desc(desc, mask);
 
-       return apic->cpu_mask_to_apicid_and(desc->affinity, cpu_online_mask);
+       cpumask_copy(desc->affinity, mask);
+
+       return apic->cpu_mask_to_apicid_and(desc->affinity, cfg->domain);
 }
 
 static void
@@ -849,9 +855,9 @@ __setup("pirq=", ioapic_pirq_setup);
 static struct IO_APIC_route_entry *early_ioapic_entries[MAX_IO_APICS];
 
 /*
- * Saves and masks all the unmasked IO-APIC RTE's
+ * Saves all the IO-APIC RTE's
  */
-int save_mask_IO_APIC_setup(void)
+int save_IO_APIC_setup(void)
 {
        union IO_APIC_reg_01 reg_01;
        unsigned long flags;
@@ -876,16 +882,9 @@ int save_mask_IO_APIC_setup(void)
        }
 
        for (apic = 0; apic < nr_ioapics; apic++)
-               for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
-                       struct IO_APIC_route_entry entry;
-
-                       entry = early_ioapic_entries[apic][pin] =
+               for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
+                       early_ioapic_entries[apic][pin] =
                                ioapic_read_entry(apic, pin);
-                       if (!entry.mask) {
-                               entry.mask = 1;
-                               ioapic_write_entry(apic, pin, entry);
-                       }
-               }
 
        return 0;
 
@@ -898,6 +897,25 @@ nomem:
        return -ENOMEM;
 }
 
+void mask_IO_APIC_setup(void)
+{
+       int apic, pin;
+
+       for (apic = 0; apic < nr_ioapics; apic++) {
+               if (!early_ioapic_entries[apic])
+                       break;
+               for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+                       struct IO_APIC_route_entry entry;
+
+                       entry = early_ioapic_entries[apic][pin];
+                       if (!entry.mask) {
+                               entry.mask = 1;
+                               ioapic_write_entry(apic, pin, entry);
+                       }
+               }
+       }
+}
+
 void restore_IO_APIC_setup(void)
 {
        int apic, pin;
@@ -1411,9 +1429,7 @@ void __setup_vector_irq(int cpu)
 }
 
 static struct irq_chip ioapic_chip;
-#ifdef CONFIG_INTR_REMAP
 static struct irq_chip ir_ioapic_chip;
-#endif
 
 #define IOAPIC_AUTO     -1
 #define IOAPIC_EDGE     0
@@ -1452,7 +1468,6 @@ static void ioapic_register_intr(int irq, struct irq_desc *desc, unsigned long t
        else
                desc->status &= ~IRQ_LEVEL;
 
-#ifdef CONFIG_INTR_REMAP
        if (irq_remapped(irq)) {
                desc->status |= IRQ_MOVE_PCNTXT;
                if (trigger)
@@ -1464,7 +1479,7 @@ static void ioapic_register_intr(int irq, struct irq_desc *desc, unsigned long t
                                                      handle_edge_irq, "edge");
                return;
        }
-#endif
+
        if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
            trigger == IOAPIC_LEVEL)
                set_irq_chip_and_handler_name(irq, &ioapic_chip,
@@ -1478,14 +1493,13 @@ static void ioapic_register_intr(int irq, struct irq_desc *desc, unsigned long t
 int setup_ioapic_entry(int apic_id, int irq,
                       struct IO_APIC_route_entry *entry,
                       unsigned int destination, int trigger,
-                      int polarity, int vector)
+                      int polarity, int vector, int pin)
 {
        /*
         * add it to the IO-APIC irq-routing table:
         */
        memset(entry,0,sizeof(*entry));
 
-#ifdef CONFIG_INTR_REMAP
        if (intr_remapping_enabled) {
                struct intel_iommu *iommu = map_ioapic_to_ir(apic_id);
                struct irte irte;
@@ -1504,7 +1518,14 @@ int setup_ioapic_entry(int apic_id, int irq,
 
                irte.present = 1;
                irte.dst_mode = apic->irq_dest_mode;
-               irte.trigger_mode = trigger;
+               /*
+                * Trigger mode in the IRTE will always be edge, and the
+                * actual level or edge trigger will be setup in the IO-APIC
+                * RTE. This will help simplify level triggered irq migration.
+                * For more details, see the comments above explainig IO-APIC
+                * irq migration in the presence of interrupt-remapping.
+                */
+               irte.trigger_mode = 0;
                irte.dlvry_mode = apic->irq_delivery_mode;
                irte.vector = vector;
                irte.dest_id = IRTE_DEST(destination);
@@ -1515,18 +1536,21 @@ int setup_ioapic_entry(int apic_id, int irq,
                ir_entry->zero = 0;
                ir_entry->format = 1;
                ir_entry->index = (index & 0x7fff);
-       } else
-#endif
-       {
+               /*
+                * IO-APIC RTE will be configured with virtual vector.
+                * irq handler will do the explicit EOI to the io-apic.
+                */
+               ir_entry->vector = pin;
+       } else {
                entry->delivery_mode = apic->irq_delivery_mode;
                entry->dest_mode = apic->irq_dest_mode;
                entry->dest = destination;
+               entry->vector = vector;
        }
 
        entry->mask = 0;                                /* enable IRQ */
        entry->trigger = trigger;
        entry->polarity = polarity;
-       entry->vector = vector;
 
        /* Mask level triggered irqs.
         * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
@@ -1561,7 +1585,7 @@ static void setup_IO_APIC_irq(int apic_id, int pin, unsigned int irq, struct irq
 
 
        if (setup_ioapic_entry(mp_ioapics[apic_id].apicid, irq, &entry,
-                              dest, trigger, polarity, cfg->vector)) {
+                              dest, trigger, polarity, cfg->vector, pin)) {
                printk("Failed to setup ioapic entry for ioapic  %d, pin %d\n",
                       mp_ioapics[apic_id].apicid, pin);
                __clear_irq_vector(irq, cfg);
@@ -1642,10 +1666,8 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic_id, unsigned int pin,
 {
        struct IO_APIC_route_entry entry;
 
-#ifdef CONFIG_INTR_REMAP
        if (intr_remapping_enabled)
                return;
-#endif
 
        memset(&entry, 0, sizeof(entry));
 
@@ -2040,8 +2062,13 @@ void disable_IO_APIC(void)
         * If the i8259 is routed through an IOAPIC
         * Put that IOAPIC in virtual wire mode
         * so legacy interrupts can be delivered.
+        *
+        * With interrupt-remapping, for now we will use virtual wire A mode,
+        * as virtual wire B is little complex (need to configure both
+        * IOAPIC RTE aswell as interrupt-remapping table entry).
+        * As this gets called during crash dump, keep this simple for now.
         */
-       if (ioapic_i8259.pin != -1) {
+       if (ioapic_i8259.pin != -1 && !intr_remapping_enabled) {
                struct IO_APIC_route_entry entry;
 
                memset(&entry, 0, sizeof(entry));
@@ -2061,7 +2088,10 @@ void disable_IO_APIC(void)
                ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry);
        }
 
-       disconnect_bsp_APIC(ioapic_i8259.pin != -1);
+       /*
+        * Use virtual wire A mode when interrupt remapping is enabled.
+        */
+       disconnect_bsp_APIC(!intr_remapping_enabled && ioapic_i8259.pin != -1);
 }
 
 #ifdef CONFIG_X86_32
@@ -2303,37 +2333,24 @@ static int ioapic_retrigger_irq(unsigned int irq)
 #ifdef CONFIG_SMP
 
 #ifdef CONFIG_INTR_REMAP
-static void ir_irq_migration(struct work_struct *work);
-
-static DECLARE_DELAYED_WORK(ir_migration_work, ir_irq_migration);
 
 /*
  * Migrate the IO-APIC irq in the presence of intr-remapping.
  *
- * For edge triggered, irq migration is a simple atomic update(of vector
- * and cpu destination) of IRTE and flush the hardware cache.
- *
- * For level triggered, we need to modify the io-apic RTE aswell with the update
- * vector information, along with modifying IRTE with vector and destination.
- * So irq migration for level triggered is little  bit more complex compared to
- * edge triggered migration. But the good news is, we use the same algorithm
- * for level triggered migration as we have today, only difference being,
- * we now initiate the irq migration from process context instead of the
- * interrupt context.
+ * For both level and edge triggered, irq migration is a simple atomic
+ * update(of vector and cpu destination) of IRTE and flush the hardware cache.
  *
- * In future, when we do a directed EOI (combined with cpu EOI broadcast
- * suppression) to the IO-APIC, level triggered irq migration will also be
- * as simple as edge triggered migration and we can do the irq migration
- * with a simple atomic update to IO-APIC RTE.
+ * For level triggered, we eliminate the io-apic RTE modification (with the
+ * updated vector information), by using a virtual vector (io-apic pin number).
+ * Real vector that is used for interrupting cpu will be coming from
+ * the interrupt-remapping table entry.
  */
 static void
 migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
 {
        struct irq_cfg *cfg;
        struct irte irte;
-       int modify_ioapic_rte;
        unsigned int dest;
-       unsigned long flags;
        unsigned int irq;
 
        if (!cpumask_intersects(mask, cpu_online_mask))
@@ -2351,13 +2368,6 @@ migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
 
        dest = apic->cpu_mask_to_apicid_and(cfg->domain, mask);
 
-       modify_ioapic_rte = desc->status & IRQ_LEVEL;
-       if (modify_ioapic_rte) {
-               spin_lock_irqsave(&ioapic_lock, flags);
-               __target_IO_APIC_irq(irq, dest, cfg);
-               spin_unlock_irqrestore(&ioapic_lock, flags);
-       }
-
        irte.vector = cfg->vector;
        irte.dest_id = IRTE_DEST(dest);
 
@@ -2372,73 +2382,12 @@ migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
        cpumask_copy(desc->affinity, mask);
 }
 
-static int migrate_irq_remapped_level_desc(struct irq_desc *desc)
-{
-       int ret = -1;
-       struct irq_cfg *cfg = desc->chip_data;
-
-       mask_IO_APIC_irq_desc(desc);
-
-       if (io_apic_level_ack_pending(cfg)) {
-               /*
-                * Interrupt in progress. Migrating irq now will change the
-                * vector information in the IO-APIC RTE and that will confuse
-                * the EOI broadcast performed by cpu.
-                * So, delay the irq migration to the next instance.
-                */
-               schedule_delayed_work(&ir_migration_work, 1);
-               goto unmask;
-       }
-
-       /* everthing is clear. we have right of way */
-       migrate_ioapic_irq_desc(desc, desc->pending_mask);
-
-       ret = 0;
-       desc->status &= ~IRQ_MOVE_PENDING;
-       cpumask_clear(desc->pending_mask);
-
-unmask:
-       unmask_IO_APIC_irq_desc(desc);
-
-       return ret;
-}
-
-static void ir_irq_migration(struct work_struct *work)
-{
-       unsigned int irq;
-       struct irq_desc *desc;
-
-       for_each_irq_desc(irq, desc) {
-               if (desc->status & IRQ_MOVE_PENDING) {
-                       unsigned long flags;
-
-                       spin_lock_irqsave(&desc->lock, flags);
-                       if (!desc->chip->set_affinity ||
-                           !(desc->status & IRQ_MOVE_PENDING)) {
-                               desc->status &= ~IRQ_MOVE_PENDING;
-                               spin_unlock_irqrestore(&desc->lock, flags);
-                               continue;
-                       }
-
-                       desc->chip->set_affinity(irq, desc->pending_mask);
-                       spin_unlock_irqrestore(&desc->lock, flags);
-               }
-       }
-}
-
 /*
  * Migrates the IRQ destination in the process context.
  */
 static void set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
                                            const struct cpumask *mask)
 {
-       if (desc->status & IRQ_LEVEL) {
-               desc->status |= IRQ_MOVE_PENDING;
-               cpumask_copy(desc->pending_mask, mask);
-               migrate_irq_remapped_level_desc(desc);
-               return;
-       }
-
        migrate_ioapic_irq_desc(desc, mask);
 }
 static void set_ir_ioapic_affinity_irq(unsigned int irq,
@@ -2448,6 +2397,11 @@ static void set_ir_ioapic_affinity_irq(unsigned int irq,
 
        set_ir_ioapic_affinity_irq_desc(desc, mask);
 }
+#else
+static inline void set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
+                                                  const struct cpumask *mask)
+{
+}
 #endif
 
 asmlinkage void smp_irq_move_cleanup_interrupt(void)
@@ -2461,6 +2415,7 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void)
        me = smp_processor_id();
        for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
                unsigned int irq;
+               unsigned int irr;
                struct irq_desc *desc;
                struct irq_cfg *cfg;
                irq = __get_cpu_var(vector_irq)[vector];
@@ -2480,6 +2435,18 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void)
                if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
                        goto unlock;
 
+               irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
+               /*
+                * Check if the vector that needs to be cleanedup is
+                * registered at the cpu's IRR. If so, then this is not
+                * the best time to clean it up. Lets clean it up in the
+                * next attempt by sending another IRQ_MOVE_CLEANUP_VECTOR
+                * to myself.
+                */
+               if (irr  & (1 << (vector % 32))) {
+                       apic->send_IPI_self(IRQ_MOVE_CLEANUP_VECTOR);
+                       goto unlock;
+               }
                __get_cpu_var(vector_irq)[vector] = -1;
                cfg->move_cleanup_count--;
 unlock:
@@ -2529,9 +2496,44 @@ static inline void irq_complete_move(struct irq_desc **descp) {}
 #endif
 
 #ifdef CONFIG_INTR_REMAP
+static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
+{
+       int apic, pin;
+       struct irq_pin_list *entry;
+
+       entry = cfg->irq_2_pin;
+       for (;;) {
+
+               if (!entry)
+                       break;
+
+               apic = entry->apic;
+               pin = entry->pin;
+               io_apic_eoi(apic, pin);
+               entry = entry->next;
+       }
+}
+
+static void
+eoi_ioapic_irq(struct irq_desc *desc)
+{
+       struct irq_cfg *cfg;
+       unsigned long flags;
+       unsigned int irq;
+
+       irq = desc->irq;
+       cfg = desc->chip_data;
+
+       spin_lock_irqsave(&ioapic_lock, flags);
+       __eoi_ioapic_irq(irq, cfg);
+       spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
 static void ack_x2apic_level(unsigned int irq)
 {
+       struct irq_desc *desc = irq_to_desc(irq);
        ack_x2APIC_irq();
+       eoi_ioapic_irq(desc);
 }
 
 static void ack_x2apic_edge(unsigned int irq)
@@ -2662,20 +2664,20 @@ static struct irq_chip ioapic_chip __read_mostly = {
        .retrigger      = ioapic_retrigger_irq,
 };
 
-#ifdef CONFIG_INTR_REMAP
 static struct irq_chip ir_ioapic_chip __read_mostly = {
        .name           = "IR-IO-APIC",
        .startup        = startup_ioapic_irq,
        .mask           = mask_IO_APIC_irq,
        .unmask         = unmask_IO_APIC_irq,
+#ifdef CONFIG_INTR_REMAP
        .ack            = ack_x2apic_edge,
        .eoi            = ack_x2apic_level,
 #ifdef CONFIG_SMP
        .set_affinity   = set_ir_ioapic_affinity_irq,
+#endif
 #endif
        .retrigger      = ioapic_retrigger_irq,
 };
-#endif
 
 static inline void init_IO_APIC_traps(void)
 {
@@ -2901,10 +2903,8 @@ static inline void __init check_timer(void)
         * 8259A.
         */
        if (pin1 == -1) {
-#ifdef CONFIG_INTR_REMAP
                if (intr_remapping_enabled)
                        panic("BIOS bug: timer not connected to IO-APIC");
-#endif
                pin1 = pin2;
                apic1 = apic2;
                no_pin1 = 1;
@@ -2940,10 +2940,8 @@ static inline void __init check_timer(void)
                                clear_IO_APIC_pin(0, pin1);
                        goto out;
                }
-#ifdef CONFIG_INTR_REMAP
                if (intr_remapping_enabled)
                        panic("timer doesn't work through Interrupt-remapped IO-APIC");
-#endif
                local_irq_disable();
                clear_IO_APIC_pin(apic1, pin1);
                if (!no_pin1)
@@ -3237,9 +3235,7 @@ void destroy_irq(unsigned int irq)
        if (desc)
                desc->chip_data = cfg;
 
-#ifdef CONFIG_INTR_REMAP
        free_irte(irq);
-#endif
        spin_lock_irqsave(&vector_lock, flags);
        __clear_irq_vector(irq, cfg);
        spin_unlock_irqrestore(&vector_lock, flags);
@@ -3265,7 +3261,6 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
 
        dest = apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus());
 
-#ifdef CONFIG_INTR_REMAP
        if (irq_remapped(irq)) {
                struct irte irte;
                int ir_index;
@@ -3291,10 +3286,13 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
                                  MSI_ADDR_IR_SHV |
                                  MSI_ADDR_IR_INDEX1(ir_index) |
                                  MSI_ADDR_IR_INDEX2(ir_index);
-       } else
-#endif
-       {
-               msg->address_hi = MSI_ADDR_BASE_HI;
+       } else {
+               if (x2apic_enabled())
+                       msg->address_hi = MSI_ADDR_BASE_HI |
+                                         MSI_ADDR_EXT_DEST_ID(dest);
+               else
+                       msg->address_hi = MSI_ADDR_BASE_HI;
+
                msg->address_lo =
                        MSI_ADDR_BASE_LO |
                        ((apic->irq_dest_mode == 0) ?
@@ -3394,14 +3392,15 @@ static struct irq_chip msi_chip = {
        .retrigger      = ioapic_retrigger_irq,
 };
 
-#ifdef CONFIG_INTR_REMAP
 static struct irq_chip msi_ir_chip = {
        .name           = "IR-PCI-MSI",
        .unmask         = unmask_msi_irq,
        .mask           = mask_msi_irq,
+#ifdef CONFIG_INTR_REMAP
        .ack            = ack_x2apic_edge,
 #ifdef CONFIG_SMP
        .set_affinity   = ir_set_msi_irq_affinity,
+#endif
 #endif
        .retrigger      = ioapic_retrigger_irq,
 };
@@ -3432,7 +3431,6 @@ static int msi_alloc_irte(struct pci_dev *dev, int irq, int nvec)
        }
        return index;
 }
-#endif
 
 static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
 {
@@ -3446,7 +3444,6 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
        set_irq_msi(irq, msidesc);
        write_msi_msg(irq, &msg);
 
-#ifdef CONFIG_INTR_REMAP
        if (irq_remapped(irq)) {
                struct irq_desc *desc = irq_to_desc(irq);
                /*
@@ -3455,7 +3452,6 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
                desc->status |= IRQ_MOVE_PCNTXT;
                set_irq_chip_and_handler_name(irq, &msi_ir_chip, handle_edge_irq, "edge");
        } else
-#endif
                set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
 
        dev_printk(KERN_DEBUG, &dev->dev, "irq %d for MSI/MSI-X\n", irq);
@@ -3469,11 +3465,12 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
        int ret, sub_handle;
        struct msi_desc *msidesc;
        unsigned int irq_want;
-
-#ifdef CONFIG_INTR_REMAP
-       struct intel_iommu *iommu = 0;
+       struct intel_iommu *iommu = NULL;
        int index = 0;
-#endif
+
+       /* x86 doesn't support multiple MSI yet */
+       if (type == PCI_CAP_ID_MSI && nvec > 1)
+               return 1;
 
        irq_want = nr_irqs_gsi;
        sub_handle = 0;
@@ -3482,7 +3479,6 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
                if (irq == 0)
                        return -1;
                irq_want = irq + 1;
-#ifdef CONFIG_INTR_REMAP
                if (!intr_remapping_enabled)
                        goto no_ir;
 
@@ -3510,7 +3506,6 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
                        set_irte_irq(irq, iommu, index, sub_handle);
                }
 no_ir:
-#endif
                ret = setup_msi_irq(dev, msidesc, irq);
                if (ret < 0)
                        goto error;
@@ -3528,7 +3523,7 @@ void arch_teardown_msi_irq(unsigned int irq)
        destroy_irq(irq);
 }
 
-#ifdef CONFIG_DMAR
+#if defined (CONFIG_DMAR) || defined (CONFIG_INTR_REMAP)
 #ifdef CONFIG_SMP
 static void dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
 {
@@ -3609,7 +3604,7 @@ static void hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
 
 #endif /* CONFIG_SMP */
 
-struct irq_chip hpet_msi_type = {
+static struct irq_chip hpet_msi_type = {
        .name = "HPET_MSI",
        .unmask = hpet_msi_unmask,
        .mask = hpet_msi_mask,
@@ -4045,11 +4040,9 @@ void __init setup_ioapic_dest(void)
                        else
                                mask = apic->target_cpus();
 
-#ifdef CONFIG_INTR_REMAP
                        if (intr_remapping_enabled)
                                set_ir_ioapic_affinity_irq_desc(desc, mask);
                        else
-#endif
                                set_ioapic_affinity_irq_desc(desc, mask);
                }
 
@@ -4142,9 +4135,12 @@ static int __init ioapic_insert_resources(void)
        struct resource *r = ioapic_resources;
 
        if (!r) {
-               printk(KERN_ERR
-                      "IO APIC resources could be not be allocated.\n");
-               return -1;
+               if (nr_ioapics > 0) {
+                       printk(KERN_ERR
+                               "IO APIC resources couldn't be allocated.\n");
+                       return -1;
+               }
+               return 0;
        }
 
        for (i = 0; i < nr_ioapics; i++) {
index 8d7748efe6a801859e2cda4c96354a57d69237ea..1783652bb0e56c8140e411a4ba5643a64ab4d0fc 100644 (file)
@@ -68,6 +68,13 @@ void __init default_setup_apic_routing(void)
                        apic = &apic_physflat;
                printk(KERN_INFO "Setting APIC routing to %s\n", apic->name);
        }
+
+       /*
+        * Now that apic routing model is selected, configure the
+        * fault handling for intr remapping.
+        */
+       if (intr_remapping_enabled)
+               enable_drhd_fault_handling();
 }
 
 /* Same for both flat and physical. */
index 8fb87b6dd63330c193890ac3ae5d704eda096ba2..4a903e2f0d179d68d6a30f5afe7c1b0543a45870 100644 (file)
@@ -57,6 +57,8 @@ static void x2apic_send_IPI_mask(const struct cpumask *mask, int vector)
        unsigned long query_cpu;
        unsigned long flags;
 
+       x2apic_wrmsr_fence();
+
        local_irq_save(flags);
        for_each_cpu(query_cpu, mask) {
                __x2apic_send_IPI_dest(
@@ -73,6 +75,8 @@ static void
        unsigned long query_cpu;
        unsigned long flags;
 
+       x2apic_wrmsr_fence();
+
        local_irq_save(flags);
        for_each_cpu(query_cpu, mask) {
                if (query_cpu == this_cpu)
@@ -90,6 +94,8 @@ static void x2apic_send_IPI_allbutself(int vector)
        unsigned long query_cpu;
        unsigned long flags;
 
+       x2apic_wrmsr_fence();
+
        local_irq_save(flags);
        for_each_online_cpu(query_cpu) {
                if (query_cpu == this_cpu)
index 23625b9f98b28530657ca7d572cf4b7a4a60a378..a284359627e7fe23ed8a84ab00be47e0a24ae9bf 100644 (file)
@@ -58,6 +58,8 @@ static void x2apic_send_IPI_mask(const struct cpumask *mask, int vector)
        unsigned long query_cpu;
        unsigned long flags;
 
+       x2apic_wrmsr_fence();
+
        local_irq_save(flags);
        for_each_cpu(query_cpu, mask) {
                __x2apic_send_IPI_dest(per_cpu(x86_cpu_to_apicid, query_cpu),
@@ -73,6 +75,8 @@ static void
        unsigned long query_cpu;
        unsigned long flags;
 
+       x2apic_wrmsr_fence();
+
        local_irq_save(flags);
        for_each_cpu(query_cpu, mask) {
                if (query_cpu != this_cpu)
@@ -89,6 +93,8 @@ static void x2apic_send_IPI_allbutself(int vector)
        unsigned long query_cpu;
        unsigned long flags;
 
+       x2apic_wrmsr_fence();
+
        local_irq_save(flags);
        for_each_online_cpu(query_cpu) {
                if (query_cpu == this_cpu)
index 1bd6da1f8fadba5b0fd96c97355122629e9cc30d..1248318436e8903b7ac3527ee1bbe59203325d24 100644 (file)
@@ -118,17 +118,12 @@ static int uv_wakeup_secondary(int phys_apicid, unsigned long start_rip)
 
 static void uv_send_IPI_one(int cpu, int vector)
 {
-       unsigned long val, apicid;
+       unsigned long apicid;
        int pnode;
 
        apicid = per_cpu(x86_cpu_to_apicid, cpu);
        pnode = uv_apicid_to_pnode(apicid);
-
-       val = (1UL << UVH_IPI_INT_SEND_SHFT) |
-             (apicid << UVH_IPI_INT_APIC_ID_SHFT) |
-             (vector << UVH_IPI_INT_VECTOR_SHFT);
-
-       uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
+       uv_hub_send_ipi(pnode, apicid, vector);
 }
 
 static void uv_send_IPI_mask(const struct cpumask *mask, int vector)
index 10033fe718e0ad574f57a4f54c9d67efb72cb23e..ac7783a6743230693540178af6c13e9bfa98a383 100644 (file)
@@ -1190,8 +1190,10 @@ static int suspend(int vetoable)
        struct apm_user *as;
 
        device_suspend(PMSG_SUSPEND);
-       local_irq_disable();
+
        device_power_down(PMSG_SUSPEND);
+
+       local_irq_disable();
        sysdev_suspend(PMSG_SUSPEND);
 
        local_irq_enable();
@@ -1209,9 +1211,12 @@ static int suspend(int vetoable)
        if (err != APM_SUCCESS)
                apm_error("suspend", err);
        err = (err == APM_SUCCESS) ? 0 : -EIO;
+
        sysdev_resume();
-       device_power_up(PMSG_RESUME);
        local_irq_enable();
+
+       device_power_up(PMSG_RESUME);
+
        device_resume(PMSG_RESUME);
        queue_event(APM_NORMAL_RESUME, NULL);
        spin_lock(&user_list_lock);
@@ -1228,8 +1233,9 @@ static void standby(void)
 {
        int err;
 
-       local_irq_disable();
        device_power_down(PMSG_SUSPEND);
+
+       local_irq_disable();
        sysdev_suspend(PMSG_SUSPEND);
        local_irq_enable();
 
@@ -1239,8 +1245,9 @@ static void standby(void)
 
        local_irq_disable();
        sysdev_resume();
-       device_power_up(PMSG_RESUME);
        local_irq_enable();
+
+       device_power_up(PMSG_RESUME);
 }
 
 static apm_event_t get_event(void)
index fbf2f33e3080c24c3b17db173fd023fcc66527ae..5a6aa1c1162f06492a27cee3ac754b16e7fa57e0 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/thread_info.h>
 #include <asm/bootparam.h>
 #include <asm/elf.h>
+#include <asm/suspend.h>
 
 #include <xen/interface/xen.h>
 
index 8793ab33e2c16406632513ecdc2febefe26c66a3..e72f062fb4b5fd841617a3e7f7c766e64bf4428f 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/thread_info.h>
 #include <asm/ia32.h>
 #include <asm/bootparam.h>
+#include <asm/suspend.h>
 
 #include <xen/interface/xen.h>
 
index 2ac0ab71412a59f9c9e0b025d88f0acf9e7e39ff..fc999e6fc46a34cf1417cd600c11a0e07af1acfd 100644 (file)
@@ -83,15 +83,15 @@ void __init setup_bios_corruption_check(void)
                u64 size;
                addr = find_e820_area_size(addr, &size, PAGE_SIZE);
 
-               if (addr == 0)
+               if (!(addr + 1))
+                       break;
+
+               if (addr >= corruption_check_size)
                        break;
 
                if ((addr + size) > corruption_check_size)
                        size = corruption_check_size - addr;
 
-               if (size == 0)
-                       break;
-
                e820_update_range(addr, size, E820_RAM, E820_RESERVED);
                scan_areas[num_scan_areas].addr = addr;
                scan_areas[num_scan_areas].size = size;
index 82db7f45e2de655430009b58fb776c11fc9b74de..4e242f9a06e43a3bc479e40237997b3c0e1a53c4 100644 (file)
@@ -14,11 +14,12 @@ obj-y                       += vmware.o hypervisor.o
 obj-$(CONFIG_X86_32)   += bugs.o cmpxchg.o
 obj-$(CONFIG_X86_64)   += bugs_64.o
 
+obj-$(CONFIG_X86_CPU_DEBUG)            += cpu_debug.o
+
 obj-$(CONFIG_CPU_SUP_INTEL)            += intel.o
 obj-$(CONFIG_CPU_SUP_AMD)              += amd.o
 obj-$(CONFIG_CPU_SUP_CYRIX_32)         += cyrix.o
-obj-$(CONFIG_CPU_SUP_CENTAUR_32)       += centaur.o
-obj-$(CONFIG_CPU_SUP_CENTAUR_64)       += centaur_64.o
+obj-$(CONFIG_CPU_SUP_CENTAUR)          += centaur.o
 obj-$(CONFIG_CPU_SUP_TRANSMETA_32)     += transmeta.o
 obj-$(CONFIG_CPU_SUP_UMC_32)           += umc.o
 
index 6882a735d9c0ad70b0c6386d11f53d5d50673d40..8220ae69849d4aa3e5405a412a6bca2b03c4b958 100644 (file)
@@ -29,7 +29,7 @@ void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c)
        u32 regs[4];
        const struct cpuid_bit *cb;
 
-       static const struct cpuid_bit cpuid_bits[] = {
+       static const struct cpuid_bit __cpuinitconst cpuid_bits[] = {
                { X86_FEATURE_IDA, CR_EAX, 1, 0x00000006 },
                { 0, 0, 0, 0 }
        };
index 25423a5b80ed28a7058bd01cf3f5f0358fb167b4..7e4a459daa644f30309f50e9ca65ece4be85fad7 100644 (file)
@@ -5,6 +5,7 @@
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/apic.h>
+#include <asm/cpu.h>
 
 #ifdef CONFIG_X86_64
 # include <asm/numa_64.h>
@@ -141,6 +142,55 @@ static void __cpuinit init_amd_k6(struct cpuinfo_x86 *c)
        }
 }
 
+static void __cpuinit amd_k7_smp_check(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_SMP
+       /* calling is from identify_secondary_cpu() ? */
+       if (c->cpu_index == boot_cpu_id)
+               return;
+
+       /*
+        * Certain Athlons might work (for various values of 'work') in SMP
+        * but they are not certified as MP capable.
+        */
+       /* Athlon 660/661 is valid. */
+       if ((c->x86_model == 6) && ((c->x86_mask == 0) ||
+           (c->x86_mask == 1)))
+               goto valid_k7;
+
+       /* Duron 670 is valid */
+       if ((c->x86_model == 7) && (c->x86_mask == 0))
+               goto valid_k7;
+
+       /*
+        * Athlon 662, Duron 671, and Athlon >model 7 have capability
+        * bit. It's worth noting that the A5 stepping (662) of some
+        * Athlon XP's have the MP bit set.
+        * See http://www.heise.de/newsticker/data/jow-18.10.01-000 for
+        * more.
+        */
+       if (((c->x86_model == 6) && (c->x86_mask >= 2)) ||
+           ((c->x86_model == 7) && (c->x86_mask >= 1)) ||
+            (c->x86_model > 7))
+               if (cpu_has_mp)
+                       goto valid_k7;
+
+       /* If we get here, not a certified SMP capable AMD system. */
+
+       /*
+        * Don't taint if we are running SMP kernel on a single non-MP
+        * approved Athlon
+        */
+       WARN_ONCE(1, "WARNING: This combination of AMD"
+               "processors is not suitable for SMP.\n");
+       if (!test_taint(TAINT_UNSAFE_SMP))
+               add_taint(TAINT_UNSAFE_SMP);
+
+valid_k7:
+       ;
+#endif
+}
+
 static void __cpuinit init_amd_k7(struct cpuinfo_x86 *c)
 {
        u32 l, h;
@@ -175,6 +225,8 @@ static void __cpuinit init_amd_k7(struct cpuinfo_x86 *c)
        }
 
        set_cpu_cap(c, X86_FEATURE_K7);
+
+       amd_k7_smp_check(c);
 }
 #endif
 
@@ -450,7 +502,7 @@ static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c, unsigned int
 }
 #endif
 
-static struct cpu_dev amd_cpu_dev __cpuinitdata = {
+static const struct cpu_dev __cpuinitconst amd_cpu_dev = {
        .c_vendor       = "AMD",
        .c_ident        = { "AuthenticAMD" },
 #ifdef CONFIG_X86_32
index 89bfdd9cacc69a363fc0d9f024dc45b97310bf9e..c95e831bb0954d8c5c50520c27aa4c0e4819f548 100644 (file)
@@ -1,11 +1,11 @@
+#include <linux/bitops.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/bitops.h>
 
 #include <asm/processor.h>
-#include <asm/msr.h>
 #include <asm/e820.h>
 #include <asm/mtrr.h>
+#include <asm/msr.h>
 
 #include "cpu.h"
 
@@ -276,7 +276,7 @@ static void __cpuinit init_c3(struct cpuinfo_x86 *c)
                 */
                c->x86_capability[5] = cpuid_edx(0xC0000001);
        }
-
+#ifdef CONFIG_X86_32
        /* Cyrix III family needs CX8 & PGE explicitly enabled. */
        if (c->x86_model >= 6 && c->x86_model <= 9) {
                rdmsr(MSR_VIA_FCR, lo, hi);
@@ -288,6 +288,11 @@ static void __cpuinit init_c3(struct cpuinfo_x86 *c)
        /* Before Nehemiah, the C3's had 3dNOW! */
        if (c->x86_model >= 6 && c->x86_model < 9)
                set_cpu_cap(c, X86_FEATURE_3DNOW);
+#endif
+       if (c->x86 == 0x6 && c->x86_model >= 0xf) {
+               c->x86_cache_alignment = c->x86_clflush_size * 2;
+               set_cpu_cap(c, X86_FEATURE_REP_GOOD);
+       }
 
        display_cacheinfo(c);
 }
@@ -316,16 +321,25 @@ enum {
 static void __cpuinit early_init_centaur(struct cpuinfo_x86 *c)
 {
        switch (c->x86) {
+#ifdef CONFIG_X86_32
        case 5:
                /* Emulate MTRRs using Centaur's MCR. */
                set_cpu_cap(c, X86_FEATURE_CENTAUR_MCR);
                break;
+#endif
+       case 6:
+               if (c->x86_model >= 0xf)
+                       set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
+               break;
        }
+#ifdef CONFIG_X86_64
+       set_cpu_cap(c, X86_FEATURE_SYSENTER32);
+#endif
 }
 
 static void __cpuinit init_centaur(struct cpuinfo_x86 *c)
 {
-
+#ifdef CONFIG_X86_32
        char *name;
        u32  fcr_set = 0;
        u32  fcr_clr = 0;
@@ -337,8 +351,10 @@ static void __cpuinit init_centaur(struct cpuinfo_x86 *c)
         * 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway
         */
        clear_cpu_cap(c, 0*32+31);
-
+#endif
+       early_init_centaur(c);
        switch (c->x86) {
+#ifdef CONFIG_X86_32
        case 5:
                switch (c->x86_model) {
                case 4:
@@ -442,16 +458,20 @@ static void __cpuinit init_centaur(struct cpuinfo_x86 *c)
                }
                sprintf(c->x86_model_id, "WinChip %s", name);
                break;
-
+#endif
        case 6:
                init_c3(c);
                break;
        }
+#ifdef CONFIG_X86_64
+       set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
+#endif
 }
 
 static unsigned int __cpuinit
 centaur_size_cache(struct cpuinfo_x86 *c, unsigned int size)
 {
+#ifdef CONFIG_X86_32
        /* VIA C3 CPUs (670-68F) need further shifting. */
        if ((c->x86 == 6) && ((c->x86_model == 7) || (c->x86_model == 8)))
                size >>= 8;
@@ -464,11 +484,11 @@ centaur_size_cache(struct cpuinfo_x86 *c, unsigned int size)
        if ((c->x86 == 6) && (c->x86_model == 9) &&
                                (c->x86_mask == 1) && (size == 65))
                size -= 1;
-
+#endif
        return size;
 }
 
-static struct cpu_dev centaur_cpu_dev __cpuinitdata = {
+static const struct cpu_dev __cpuinitconst centaur_cpu_dev = {
        .c_vendor       = "Centaur",
        .c_ident        = { "CentaurHauls" },
        .c_early_init   = early_init_centaur,
diff --git a/arch/x86/kernel/cpu/centaur_64.c b/arch/x86/kernel/cpu/centaur_64.c
deleted file mode 100644 (file)
index a1625f5..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#include <linux/init.h>
-#include <linux/smp.h>
-
-#include <asm/cpufeature.h>
-#include <asm/processor.h>
-
-#include "cpu.h"
-
-static void __cpuinit early_init_centaur(struct cpuinfo_x86 *c)
-{
-       if (c->x86 == 0x6 && c->x86_model >= 0xf)
-               set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
-
-       set_cpu_cap(c, X86_FEATURE_SYSENTER32);
-}
-
-static void __cpuinit init_centaur(struct cpuinfo_x86 *c)
-{
-       early_init_centaur(c);
-
-       if (c->x86 == 0x6 && c->x86_model >= 0xf) {
-               c->x86_cache_alignment = c->x86_clflush_size * 2;
-               set_cpu_cap(c, X86_FEATURE_REP_GOOD);
-       }
-       set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
-}
-
-static struct cpu_dev centaur_cpu_dev __cpuinitdata = {
-       .c_vendor       = "Centaur",
-       .c_ident        = { "CentaurHauls" },
-       .c_early_init   = early_init_centaur,
-       .c_init         = init_centaur,
-       .c_x86_vendor   = X86_VENDOR_CENTAUR,
-};
-
-cpu_dev_register(centaur_cpu_dev);
-
index 826d5c87627826911ac393f215c0cecb03f50ef9..e2962cc1e27b742965f6af45a8cfdcf9b4c1a0b8 100644 (file)
@@ -1,52 +1,52 @@
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
 #include <linux/bootmem.h>
+#include <linux/linkage.h>
 #include <linux/bitops.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/kgdb.h>
-#include <linux/topology.h>
+#include <linux/percpu.h>
+#include <linux/string.h>
 #include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/kgdb.h>
 #include <linux/smp.h>
-#include <linux/percpu.h>
-#include <asm/i387.h>
-#include <asm/msr.h>
-#include <asm/io.h>
-#include <asm/linkage.h>
+#include <linux/io.h>
+
+#include <asm/stackprotector.h>
 #include <asm/mmu_context.h>
+#include <asm/hypervisor.h>
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/topology.h>
+#include <asm/cpumask.h>
+#include <asm/pgtable.h>
+#include <asm/atomic.h>
+#include <asm/proto.h>
+#include <asm/setup.h>
+#include <asm/apic.h>
+#include <asm/desc.h>
+#include <asm/i387.h>
 #include <asm/mtrr.h>
+#include <asm/numa.h>
+#include <asm/asm.h>
+#include <asm/cpu.h>
 #include <asm/mce.h>
+#include <asm/msr.h>
 #include <asm/pat.h>
-#include <asm/asm.h>
-#include <asm/numa.h>
 #include <asm/smp.h>
-#include <asm/cpu.h>
-#include <asm/cpumask.h>
-#include <asm/apic.h>
 
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/uv/uv.h>
 #endif
 
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-#include <asm/desc.h>
-#include <asm/atomic.h>
-#include <asm/proto.h>
-#include <asm/sections.h>
-#include <asm/setup.h>
-#include <asm/hypervisor.h>
-#include <asm/stackprotector.h>
-
 #include "cpu.h"
 
 #ifdef CONFIG_X86_64
 
 /* all of these masks are initialized in setup_cpu_local_masks() */
-cpumask_var_t cpu_callin_mask;
-cpumask_var_t cpu_callout_mask;
 cpumask_var_t cpu_initialized_mask;
+cpumask_var_t cpu_callout_mask;
+cpumask_var_t cpu_callin_mask;
 
 /* representing cpus for which sibling maps can be computed */
 cpumask_var_t cpu_sibling_setup_mask;
@@ -62,15 +62,15 @@ void __init setup_cpu_local_masks(void)
 
 #else /* CONFIG_X86_32 */
 
-cpumask_t cpu_callin_map;
+cpumask_t cpu_sibling_setup_map;
 cpumask_t cpu_callout_map;
 cpumask_t cpu_initialized;
-cpumask_t cpu_sibling_setup_map;
+cpumask_t cpu_callin_map;
 
 #endif /* CONFIG_X86_32 */
 
 
-static struct cpu_dev *this_cpu __cpuinitdata;
+static const struct cpu_dev *this_cpu __cpuinitdata;
 
 DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = {
 #ifdef CONFIG_X86_64
@@ -79,48 +79,48 @@ DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = {
         * IRET will check the segment types  kkeil 2000/10/28
         * Also sysret mandates a special GDT layout
         *
-        * The TLS descriptors are currently at a different place compared to i386.
+        * TLS descriptors are currently at a different place compared to i386.
         * Hopefully nobody expects them at a fixed place (Wine?)
         */
-       [GDT_ENTRY_KERNEL32_CS] = { { { 0x0000ffff, 0x00cf9b00 } } },
-       [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00af9b00 } } },
-       [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9300 } } },
-       [GDT_ENTRY_DEFAULT_USER32_CS] = { { { 0x0000ffff, 0x00cffb00 } } },
-       [GDT_ENTRY_DEFAULT_USER_DS] = { { { 0x0000ffff, 0x00cff300 } } },
-       [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00affb00 } } },
+       [GDT_ENTRY_KERNEL32_CS]         = { { { 0x0000ffff, 0x00cf9b00 } } },
+       [GDT_ENTRY_KERNEL_CS]           = { { { 0x0000ffff, 0x00af9b00 } } },
+       [GDT_ENTRY_KERNEL_DS]           = { { { 0x0000ffff, 0x00cf9300 } } },
+       [GDT_ENTRY_DEFAULT_USER32_CS]   = { { { 0x0000ffff, 0x00cffb00 } } },
+       [GDT_ENTRY_DEFAULT_USER_DS]     = { { { 0x0000ffff, 0x00cff300 } } },
+       [GDT_ENTRY_DEFAULT_USER_CS]     = { { { 0x0000ffff, 0x00affb00 } } },
 #else
-       [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00cf9a00 } } },
-       [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9200 } } },
-       [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00cffa00 } } },
-       [GDT_ENTRY_DEFAULT_USER_DS] = { { { 0x0000ffff, 0x00cff200 } } },
+       [GDT_ENTRY_KERNEL_CS]           = { { { 0x0000ffff, 0x00cf9a00 } } },
+       [GDT_ENTRY_KERNEL_DS]           = { { { 0x0000ffff, 0x00cf9200 } } },
+       [GDT_ENTRY_DEFAULT_USER_CS]     = { { { 0x0000ffff, 0x00cffa00 } } },
+       [GDT_ENTRY_DEFAULT_USER_DS]     = { { { 0x0000ffff, 0x00cff200 } } },
        /*
         * Segments used for calling PnP BIOS have byte granularity.
         * They code segments and data segments have fixed 64k limits,
         * the transfer segment sizes are set at run time.
         */
        /* 32-bit code */
-       [GDT_ENTRY_PNPBIOS_CS32] = { { { 0x0000ffff, 0x00409a00 } } },
+       [GDT_ENTRY_PNPBIOS_CS32]        = { { { 0x0000ffff, 0x00409a00 } } },
        /* 16-bit code */
-       [GDT_ENTRY_PNPBIOS_CS16] = { { { 0x0000ffff, 0x00009a00 } } },
+       [GDT_ENTRY_PNPBIOS_CS16]        = { { { 0x0000ffff, 0x00009a00 } } },
        /* 16-bit data */
-       [GDT_ENTRY_PNPBIOS_DS] = { { { 0x0000ffff, 0x00009200 } } },
+       [GDT_ENTRY_PNPBIOS_DS]          = { { { 0x0000ffff, 0x00009200 } } },
        /* 16-bit data */
-       [GDT_ENTRY_PNPBIOS_TS1] = { { { 0x00000000, 0x00009200 } } },
+       [GDT_ENTRY_PNPBIOS_TS1]         = { { { 0x00000000, 0x00009200 } } },
        /* 16-bit data */
-       [GDT_ENTRY_PNPBIOS_TS2] = { { { 0x00000000, 0x00009200 } } },
+       [GDT_ENTRY_PNPBIOS_TS2]         = { { { 0x00000000, 0x00009200 } } },
        /*
         * The APM segments have byte granularity and their bases
         * are set at run time.  All have 64k limits.
         */
        /* 32-bit code */
-       [GDT_ENTRY_APMBIOS_BASE] = { { { 0x0000ffff, 0x00409a00 } } },
+       [GDT_ENTRY_APMBIOS_BASE]        = { { { 0x0000ffff, 0x00409a00 } } },
        /* 16-bit code */
-       [GDT_ENTRY_APMBIOS_BASE+1] = { { { 0x0000ffff, 0x00009a00 } } },
+       [GDT_ENTRY_APMBIOS_BASE+1]      = { { { 0x0000ffff, 0x00009a00 } } },
        /* data */
-       [GDT_ENTRY_APMBIOS_BASE+2] = { { { 0x0000ffff, 0x00409200 } } },
+       [GDT_ENTRY_APMBIOS_BASE+2]      = { { { 0x0000ffff, 0x00409200 } } },
 
-       [GDT_ENTRY_ESPFIX_SS] = { { { 0x00000000, 0x00c09200 } } },
-       [GDT_ENTRY_PERCPU] = { { { 0x0000ffff, 0x00cf9200 } } },
+       [GDT_ENTRY_ESPFIX_SS]           = { { { 0x00000000, 0x00c09200 } } },
+       [GDT_ENTRY_PERCPU]              = { { { 0x0000ffff, 0x00cf9200 } } },
        GDT_STACK_CANARY_INIT
 #endif
 } };
@@ -164,16 +164,17 @@ static inline int flag_is_changeable_p(u32 flag)
         * the CPUID. Add "volatile" to not allow gcc to
         * optimize the subsequent calls to this function.
         */
-       asm volatile ("pushfl\n\t"
-                     "pushfl\n\t"
-                     "popl %0\n\t"
-                     "movl %0,%1\n\t"
-                     "xorl %2,%0\n\t"
-                     "pushl %0\n\t"
-                     "popfl\n\t"
-                     "pushfl\n\t"
-                     "popl %0\n\t"
-                     "popfl\n\t"
+       asm volatile ("pushfl           \n\t"
+                     "pushfl           \n\t"
+                     "popl %0          \n\t"
+                     "movl %0, %1      \n\t"
+                     "xorl %2, %0      \n\t"
+                     "pushl %0         \n\t"
+                     "popfl            \n\t"
+                     "pushfl           \n\t"
+                     "popl %0          \n\t"
+                     "popfl            \n\t"
+
                      : "=&r" (f1), "=&r" (f2)
                      : "ir" (flag));
 
@@ -188,18 +189,22 @@ static int __cpuinit have_cpuid_p(void)
 
 static void __cpuinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
 {
-       if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr) {
-               /* Disable processor serial number */
-               unsigned long lo, hi;
-               rdmsr(MSR_IA32_BBL_CR_CTL, lo, hi);
-               lo |= 0x200000;
-               wrmsr(MSR_IA32_BBL_CR_CTL, lo, hi);
-               printk(KERN_NOTICE "CPU serial number disabled.\n");
-               clear_cpu_cap(c, X86_FEATURE_PN);
-
-               /* Disabling the serial number may affect the cpuid level */
-               c->cpuid_level = cpuid_eax(0);
-       }
+       unsigned long lo, hi;
+
+       if (!cpu_has(c, X86_FEATURE_PN) || !disable_x86_serial_nr)
+               return;
+
+       /* Disable processor serial number: */
+
+       rdmsr(MSR_IA32_BBL_CR_CTL, lo, hi);
+       lo |= 0x200000;
+       wrmsr(MSR_IA32_BBL_CR_CTL, lo, hi);
+
+       printk(KERN_NOTICE "CPU serial number disabled.\n");
+       clear_cpu_cap(c, X86_FEATURE_PN);
+
+       /* Disabling the serial number may affect the cpuid level */
+       c->cpuid_level = cpuid_eax(0);
 }
 
 static int __init x86_serial_nr_setup(char *s)
@@ -232,6 +237,7 @@ struct cpuid_dependent_feature {
        u32 feature;
        u32 level;
 };
+
 static const struct cpuid_dependent_feature __cpuinitconst
 cpuid_dependent_features[] = {
        { X86_FEATURE_MWAIT,            0x00000005 },
@@ -243,7 +249,11 @@ cpuid_dependent_features[] = {
 static void __cpuinit filter_cpuid_features(struct cpuinfo_x86 *c, bool warn)
 {
        const struct cpuid_dependent_feature *df;
+
        for (df = cpuid_dependent_features; df->feature; df++) {
+
+               if (!cpu_has(c, df->feature))
+                       continue;
                /*
                 * Note: cpuid_level is set to -1 if unavailable, but
                 * extended_extended_level is set to 0 if unavailable
@@ -251,32 +261,32 @@ static void __cpuinit filter_cpuid_features(struct cpuinfo_x86 *c, bool warn)
                 * when signed; hence the weird messing around with
                 * signs here...
                 */
-               if (cpu_has(c, df->feature) &&
-                   ((s32)df->level < 0 ?
+               if (!((s32)df->level < 0 ?
                     (u32)df->level > (u32)c->extended_cpuid_level :
-                    (s32)df->level > (s32)c->cpuid_level)) {
-                       clear_cpu_cap(c, df->feature);
-                       if (warn)
-                               printk(KERN_WARNING
-                                      "CPU: CPU feature %s disabled "
-                                      "due to lack of CPUID level 0x%x\n",
-                                      x86_cap_flags[df->feature],
-                                      df->level);
-               }
+                    (s32)df->level > (s32)c->cpuid_level))
+                       continue;
+
+               clear_cpu_cap(c, df->feature);
+               if (!warn)
+                       continue;
+
+               printk(KERN_WARNING
+                      "CPU: CPU feature %s disabled, no CPUID level 0x%x\n",
+                               x86_cap_flags[df->feature], df->level);
        }
 }
 
 /*
  * Naming convention should be: <Name> [(<Codename>)]
  * This table only is used unless init_<vendor>() below doesn't set it;
- * in particular, if CPUID levels 0x80000002..4 are supported, this isn't used
- *
+ * in particular, if CPUID levels 0x80000002..4 are supported, this
+ * isn't used
  */
 
 /* Look up CPU names by table lookup. */
-static char __cpuinit *table_lookup_model(struct cpuinfo_x86 *c)
+static const char *__cpuinit table_lookup_model(struct cpuinfo_x86 *c)
 {
-       struct cpu_model_info *info;
+       const struct cpu_model_info *info;
 
        if (c->x86_model >= 16)
                return NULL;    /* Range check */
@@ -307,8 +317,10 @@ void load_percpu_segment(int cpu)
        load_stack_canary_segment();
 }
 
-/* Current gdt points %fs at the "master" per-cpu area: after this,
- * it's on the real one. */
+/*
+ * Current gdt points %fs at the "master" per-cpu area: after this,
+ * it's on the real one.
+ */
 void switch_to_new_gdt(int cpu)
 {
        struct desc_ptr gdt_descr;
@@ -321,7 +333,7 @@ void switch_to_new_gdt(int cpu)
        load_percpu_segment(cpu);
 }
 
-static struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
+static const struct cpu_dev *__cpuinitdata cpu_devs[X86_VENDOR_NUM] = {};
 
 static void __cpuinit default_init(struct cpuinfo_x86 *c)
 {
@@ -340,7 +352,7 @@ static void __cpuinit default_init(struct cpuinfo_x86 *c)
 #endif
 }
 
-static struct cpu_dev __cpuinitdata default_cpu = {
+static const struct cpu_dev __cpuinitconst default_cpu = {
        .c_init = default_init,
        .c_vendor = "Unknown",
        .c_x86_vendor = X86_VENDOR_UNKNOWN,
@@ -354,22 +366,24 @@ static void __cpuinit get_model_name(struct cpuinfo_x86 *c)
        if (c->extended_cpuid_level < 0x80000004)
                return;
 
-       v = (unsigned int *) c->x86_model_id;
+       v = (unsigned int *)c->x86_model_id;
        cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
        cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
        cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
        c->x86_model_id[48] = 0;
 
-       /* Intel chips right-justify this string for some dumb reason;
-          undo that brain damage */
+       /*
+        * Intel chips right-justify this string for some dumb reason;
+        * undo that brain damage:
+        */
        p = q = &c->x86_model_id[0];
        while (*p == ' ')
-            p++;
+               p++;
        if (p != q) {
-            while (*p)
-                 *q++ = *p++;
-            while (q <= &c->x86_model_id[48])
-                 *q++ = '\0';  /* Zero-pad the rest */
+               while (*p)
+                       *q++ = *p++;
+               while (q <= &c->x86_model_id[48])
+                       *q++ = '\0';    /* Zero-pad the rest */
        }
 }
 
@@ -438,27 +452,30 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c)
 
        if (smp_num_siblings == 1) {
                printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
-       } else if (smp_num_siblings > 1) {
+               goto out;
+       }
 
-               if (smp_num_siblings > nr_cpu_ids) {
-                       printk(KERN_WARNING "CPU: Unsupported number of siblings %d",
-                                       smp_num_siblings);
-                       smp_num_siblings = 1;
-                       return;
-               }
+       if (smp_num_siblings <= 1)
+               goto out;
+
+       if (smp_num_siblings > nr_cpu_ids) {
+               pr_warning("CPU: Unsupported number of siblings %d",
+                          smp_num_siblings);
+               smp_num_siblings = 1;
+               return;
+       }
 
-               index_msb = get_count_order(smp_num_siblings);
-               c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid, index_msb);
+       index_msb = get_count_order(smp_num_siblings);
+       c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid, index_msb);
 
-               smp_num_siblings = smp_num_siblings / c->x86_max_cores;
+       smp_num_siblings = smp_num_siblings / c->x86_max_cores;
 
-               index_msb = get_count_order(smp_num_siblings);
+       index_msb = get_count_order(smp_num_siblings);
 
-               core_bits = get_count_order(c->x86_max_cores);
+       core_bits = get_count_order(c->x86_max_cores);
 
-               c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid, index_msb) &
-                                              ((1 << core_bits) - 1);
-       }
+       c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid, index_msb) &
+                                      ((1 << core_bits) - 1);
 
 out:
        if ((c->x86_max_cores * smp_num_siblings) > 1) {
@@ -473,8 +490,8 @@ out:
 static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
 {
        char *v = c->x86_vendor_id;
-       int i;
        static int printed;
+       int i;
 
        for (i = 0; i < X86_VENDOR_NUM; i++) {
                if (!cpu_devs[i])
@@ -483,6 +500,7 @@ static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
                if (!strcmp(v, cpu_devs[i]->c_ident[0]) ||
                    (cpu_devs[i]->c_ident[1] &&
                     !strcmp(v, cpu_devs[i]->c_ident[1]))) {
+
                        this_cpu = cpu_devs[i];
                        c->x86_vendor = this_cpu->c_x86_vendor;
                        return;
@@ -491,7 +509,9 @@ static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
 
        if (!printed) {
                printed++;
-               printk(KERN_ERR "CPU: vendor_id '%s' unknown, using generic init.\n", v);
+               printk(KERN_ERR
+                   "CPU: vendor_id '%s' unknown, using generic init.\n", v);
+
                printk(KERN_ERR "CPU: Your system may be unstable.\n");
        }
 
@@ -511,14 +531,17 @@ void __cpuinit cpu_detect(struct cpuinfo_x86 *c)
        /* Intel-defined flags: level 0x00000001 */
        if (c->cpuid_level >= 0x00000001) {
                u32 junk, tfms, cap0, misc;
+
                cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
                c->x86 = (tfms >> 8) & 0xf;
                c->x86_model = (tfms >> 4) & 0xf;
                c->x86_mask = tfms & 0xf;
+
                if (c->x86 == 0xf)
                        c->x86 += (tfms >> 20) & 0xff;
                if (c->x86 >= 0x6)
                        c->x86_model += ((tfms >> 16) & 0xf) << 4;
+
                if (cap0 & (1<<19)) {
                        c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
                        c->x86_cache_alignment = c->x86_clflush_size;
@@ -534,6 +557,7 @@ static void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c)
        /* Intel-defined flags: level 0x00000001 */
        if (c->cpuid_level >= 0x00000001) {
                u32 capability, excap;
+
                cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
                c->x86_capability[0] = capability;
                c->x86_capability[4] = excap;
@@ -542,6 +566,7 @@ static void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c)
        /* AMD-defined flags: level 0x80000001 */
        xlvl = cpuid_eax(0x80000000);
        c->extended_cpuid_level = xlvl;
+
        if ((xlvl & 0xffff0000) == 0x80000000) {
                if (xlvl >= 0x80000001) {
                        c->x86_capability[1] = cpuid_edx(0x80000001);
@@ -549,13 +574,15 @@ static void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c)
                }
        }
 
-#ifdef CONFIG_X86_64
        if (c->extended_cpuid_level >= 0x80000008) {
                u32 eax = cpuid_eax(0x80000008);
 
                c->x86_virt_bits = (eax >> 8) & 0xff;
                c->x86_phys_bits = eax & 0xff;
        }
+#ifdef CONFIG_X86_32
+       else if (cpu_has(c, X86_FEATURE_PAE) || cpu_has(c, X86_FEATURE_PSE36))
+               c->x86_phys_bits = 36;
 #endif
 
        if (c->extended_cpuid_level >= 0x80000007)
@@ -602,8 +629,12 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_X86_64
        c->x86_clflush_size = 64;
+       c->x86_phys_bits = 36;
+       c->x86_virt_bits = 48;
 #else
        c->x86_clflush_size = 32;
+       c->x86_phys_bits = 32;
+       c->x86_virt_bits = 32;
 #endif
        c->x86_cache_alignment = c->x86_clflush_size;
 
@@ -634,12 +665,12 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 
 void __init early_cpu_init(void)
 {
-       struct cpu_dev **cdev;
+       const struct cpu_dev *const *cdev;
        int count = 0;
 
-       printk("KERNEL supported cpus:\n");
+       printk(KERN_INFO "KERNEL supported cpus:\n");
        for (cdev = __x86_cpu_dev_start; cdev < __x86_cpu_dev_end; cdev++) {
-               struct cpu_dev *cpudev = *cdev;
+               const struct cpu_dev *cpudev = *cdev;
                unsigned int j;
 
                if (count >= X86_VENDOR_NUM)
@@ -650,7 +681,7 @@ void __init early_cpu_init(void)
                for (j = 0; j < 2; j++) {
                        if (!cpudev->c_ident[j])
                                continue;
-                       printk("  %s %s\n", cpudev->c_vendor,
+                       printk(KERN_INFO "  %s %s\n", cpudev->c_vendor,
                                cpudev->c_ident[j]);
                }
        }
@@ -726,9 +757,13 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
        c->x86_coreid_bits = 0;
 #ifdef CONFIG_X86_64
        c->x86_clflush_size = 64;
+       c->x86_phys_bits = 36;
+       c->x86_virt_bits = 48;
 #else
        c->cpuid_level = -1;    /* CPUID not detected */
        c->x86_clflush_size = 32;
+       c->x86_phys_bits = 32;
+       c->x86_virt_bits = 32;
 #endif
        c->x86_cache_alignment = c->x86_clflush_size;
        memset(&c->x86_capability, 0, sizeof c->x86_capability);
@@ -759,8 +794,8 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
        squash_the_stupid_serial_number(c);
 
        /*
-        * The vendor-specific functions might have changed features.  Now
-        * we do "generic changes."
+        * The vendor-specific functions might have changed features.
+        * Now we do "generic changes."
         */
 
        /* Filter out anything that depends on CPUID levels we don't have */
@@ -768,7 +803,7 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
 
        /* If the model name is still unset, do table lookup. */
        if (!c->x86_model_id[0]) {
-               char *p;
+               const char *p;
                p = table_lookup_model(c);
                if (p)
                        strcpy(c->x86_model_id, p);
@@ -843,11 +878,11 @@ void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
 }
 
 struct msr_range {
-       unsigned min;
-       unsigned max;
+       unsigned        min;
+       unsigned        max;
 };
 
-static struct msr_range msr_range_array[] __cpuinitdata = {
+static const struct msr_range msr_range_array[] __cpuinitconst = {
        { 0x00000000, 0x00000418},
        { 0xc0000000, 0xc000040b},
        { 0xc0010000, 0xc0010142},
@@ -856,14 +891,15 @@ static struct msr_range msr_range_array[] __cpuinitdata = {
 
 static void __cpuinit print_cpu_msr(void)
 {
+       unsigned index_min, index_max;
        unsigned index;
        u64 val;
        int i;
-       unsigned index_min, index_max;
 
        for (i = 0; i < ARRAY_SIZE(msr_range_array); i++) {
                index_min = msr_range_array[i].min;
                index_max = msr_range_array[i].max;
+
                for (index = index_min; index < index_max; index++) {
                        if (rdmsrl_amd_safe(index, &val))
                                continue;
@@ -873,6 +909,7 @@ static void __cpuinit print_cpu_msr(void)
 }
 
 static int show_msr __cpuinitdata;
+
 static __init int setup_show_msr(char *arg)
 {
        int num;
@@ -894,12 +931,14 @@ __setup("noclflush", setup_noclflush);
 
 void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
 {
-       char *vendor = NULL;
+       const char *vendor = NULL;
 
-       if (c->x86_vendor < X86_VENDOR_NUM)
+       if (c->x86_vendor < X86_VENDOR_NUM) {
                vendor = this_cpu->c_vendor;
-       else if (c->cpuid_level >= 0)
-               vendor = c->x86_vendor_id;
+       } else {
+               if (c->cpuid_level >= 0)
+                       vendor = c->x86_vendor_id;
+       }
 
        if (vendor && !strstr(c->x86_model_id, vendor))
                printk(KERN_CONT "%s ", vendor);
@@ -926,10 +965,12 @@ void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
 static __init int setup_disablecpuid(char *arg)
 {
        int bit;
+
        if (get_option(&arg, &bit) && bit < NCAPINTS*32)
                setup_clear_cpu_cap(bit);
        else
                return 0;
+
        return 1;
 }
 __setup("clearcpuid=", setup_disablecpuid);
@@ -939,6 +980,7 @@ struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table };
 
 DEFINE_PER_CPU_FIRST(union irq_stack_union,
                     irq_stack_union) __aligned(PAGE_SIZE);
+
 DEFINE_PER_CPU(char *, irq_stack_ptr) =
        init_per_cpu_var(irq_stack_union.irq_stack) + IRQ_STACK_SIZE - 64;
 
@@ -948,12 +990,21 @@ EXPORT_PER_CPU_SYMBOL(kernel_stack);
 
 DEFINE_PER_CPU(unsigned int, irq_count) = -1;
 
+/*
+ * Special IST stacks which the CPU switches to when it calls
+ * an IST-marked descriptor entry. Up to 7 stacks (hardware
+ * limit), all of them are 4K, except the debug stack which
+ * is 8K.
+ */
+static const unsigned int exception_stack_sizes[N_EXCEPTION_STACKS] = {
+         [0 ... N_EXCEPTION_STACKS - 1]        = EXCEPTION_STKSZ,
+         [DEBUG_STACK - 1]                     = DEBUG_STKSZ
+};
+
 static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks
        [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ])
        __aligned(PAGE_SIZE);
 
-extern asmlinkage void ignore_sysret(void);
-
 /* May not be marked __init: used by software suspend */
 void syscall_init(void)
 {
@@ -983,7 +1034,7 @@ unsigned long kernel_eflags;
  */
 DEFINE_PER_CPU(struct orig_ist, orig_ist);
 
-#else  /* x86_64 */
+#else  /* CONFIG_X86_64 */
 
 #ifdef CONFIG_CC_STACKPROTECTOR
 DEFINE_PER_CPU(unsigned long, stack_canary);
@@ -995,9 +1046,26 @@ struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
        memset(regs, 0, sizeof(struct pt_regs));
        regs->fs = __KERNEL_PERCPU;
        regs->gs = __KERNEL_STACK_CANARY;
+
        return regs;
 }
-#endif /* x86_64 */
+#endif /* CONFIG_X86_64 */
+
+/*
+ * Clear all 6 debug registers:
+ */
+static void clear_all_debug_regs(void)
+{
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               /* Ignore db4, db5 */
+               if ((i == 4) || (i == 5))
+                       continue;
+
+               set_debugreg(0, i);
+       }
+}
 
 /*
  * cpu_init() initializes state that is per-CPU. Some data is already
@@ -1007,15 +1075,20 @@ struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
  * A lot of state is already set up in PDA init for 64 bit
  */
 #ifdef CONFIG_X86_64
+
 void __cpuinit cpu_init(void)
 {
-       int cpu = stack_smp_processor_id();
-       struct tss_struct *t = &per_cpu(init_tss, cpu);
-       struct orig_ist *orig_ist = &per_cpu(orig_ist, cpu);
-       unsigned long v;
+       struct orig_ist *orig_ist;
        struct task_struct *me;
+       struct tss_struct *t;
+       unsigned long v;
+       int cpu;
        int i;
 
+       cpu = stack_smp_processor_id();
+       t = &per_cpu(init_tss, cpu);
+       orig_ist = &per_cpu(orig_ist, cpu);
+
 #ifdef CONFIG_NUMA
        if (cpu != 0 && percpu_read(node_number) == 0 &&
            cpu_to_node(cpu) != NUMA_NO_NODE)
@@ -1056,19 +1129,17 @@ void __cpuinit cpu_init(void)
         * set up and load the per-CPU TSS
         */
        if (!orig_ist->ist[0]) {
-               static const unsigned int sizes[N_EXCEPTION_STACKS] = {
-                 [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STKSZ,
-                 [DEBUG_STACK - 1] = DEBUG_STKSZ
-               };
                char *estacks = per_cpu(exception_stacks, cpu);
+
                for (v = 0; v < N_EXCEPTION_STACKS; v++) {
-                       estacks += sizes[v];
+                       estacks += exception_stack_sizes[v];
                        orig_ist->ist[v] = t->x86_tss.ist[v] =
                                        (unsigned long)estacks;
                }
        }
 
        t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap);
+
        /*
         * <= is required because the CPU will access up to
         * 8 bits beyond the end of the IO permission bitmap.
@@ -1078,8 +1149,7 @@ void __cpuinit cpu_init(void)
 
        atomic_inc(&init_mm.mm_count);
        me->active_mm = &init_mm;
-       if (me->mm)
-               BUG();
+       BUG_ON(me->mm);
        enter_lazy_tlb(&init_mm, me);
 
        load_sp0(t, &current->thread);
@@ -1098,17 +1168,7 @@ void __cpuinit cpu_init(void)
                arch_kgdb_ops.correct_hw_break();
        else
 #endif
-       {
-               /*
-                * Clear all 6 debug registers:
-                */
-               set_debugreg(0UL, 0);
-               set_debugreg(0UL, 1);
-               set_debugreg(0UL, 2);
-               set_debugreg(0UL, 3);
-               set_debugreg(0UL, 6);
-               set_debugreg(0UL, 7);
-       }
+               clear_all_debug_regs();
 
        fpu_init();
 
@@ -1129,7 +1189,8 @@ void __cpuinit cpu_init(void)
 
        if (cpumask_test_and_set_cpu(cpu, cpu_initialized_mask)) {
                printk(KERN_WARNING "CPU#%d already initialized!\n", cpu);
-               for (;;) local_irq_enable();
+               for (;;)
+                       local_irq_enable();
        }
 
        printk(KERN_INFO "Initializing CPU#%d\n", cpu);
@@ -1145,8 +1206,7 @@ void __cpuinit cpu_init(void)
         */
        atomic_inc(&init_mm.mm_count);
        curr->active_mm = &init_mm;
-       if (curr->mm)
-               BUG();
+       BUG_ON(curr->mm);
        enter_lazy_tlb(&init_mm, curr);
 
        load_sp0(t, thread);
@@ -1159,13 +1219,7 @@ void __cpuinit cpu_init(void)
        __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss);
 #endif
 
-       /* Clear all 6 debug registers: */
-       set_debugreg(0, 0);
-       set_debugreg(0, 1);
-       set_debugreg(0, 2);
-       set_debugreg(0, 3);
-       set_debugreg(0, 6);
-       set_debugreg(0, 7);
+       clear_all_debug_regs();
 
        /*
         * Force FPU initialization:
@@ -1185,6 +1239,4 @@ void __cpuinit cpu_init(void)
 
        xsave_init();
 }
-
-
 #endif
index de4094a3921071b94b9b71a1bcd2d85158c6c957..6de9a908e4008bf6d99e56cb8a9ef909b1f3949c 100644 (file)
@@ -3,33 +3,34 @@
 #define ARCH_X86_CPU_H
 
 struct cpu_model_info {
-       int vendor;
-       int family;
-       char *model_names[16];
+       int             vendor;
+       int             family;
+       const char      *model_names[16];
 };
 
 /* attempt to consolidate cpu attributes */
 struct cpu_dev {
-       char    * c_vendor;
+       const char      *c_vendor;
 
        /* some have two possibilities for cpuid string */
-       char    * c_ident[2];   
+       const char      *c_ident[2];
 
        struct          cpu_model_info c_models[4];
 
-       void            (*c_early_init)(struct cpuinfo_x86 *c);
-       void            (*c_init)(struct cpuinfo_x86 * c);
-       void            (*c_identify)(struct cpuinfo_x86 * c);
-       unsigned int    (*c_size_cache)(struct cpuinfo_x86 * c, unsigned int size);
-       int     c_x86_vendor;
+       void            (*c_early_init)(struct cpuinfo_x86 *);
+       void            (*c_init)(struct cpuinfo_x86 *);
+       void            (*c_identify)(struct cpuinfo_x86 *);
+       unsigned int    (*c_size_cache)(struct cpuinfo_x86 *, unsigned int);
+       int             c_x86_vendor;
 };
 
 #define cpu_dev_register(cpu_devX) \
-       static struct cpu_dev *__cpu_dev_##cpu_devX __used \
+       static const struct cpu_dev *const __cpu_dev_##cpu_devX __used \
        __attribute__((__section__(".x86_cpu_dev.init"))) = \
        &cpu_devX;
 
-extern struct cpu_dev *__x86_cpu_dev_start[], *__x86_cpu_dev_end[];
+extern const struct cpu_dev *const __x86_cpu_dev_start[],
+                           *const __x86_cpu_dev_end[];
 
 extern void display_cacheinfo(struct cpuinfo_x86 *c);
 
diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c
new file mode 100755 (executable)
index 0000000..46e29ab
--- /dev/null
@@ -0,0 +1,901 @@
+/*
+ * CPU x86 architecture debug code
+ *
+ * Copyright(C) 2009 Jaswinder Singh Rajput
+ *
+ * For licencing details see kernel-base/COPYING
+ */
+
+#include <linux/interrupt.h>
+#include <linux/compiler.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/kprobes.h>
+#include <linux/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+
+#include <asm/cpu_debug.h>
+#include <asm/paravirt.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#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(unsigned, cpu_modelflag);
+static DEFINE_PER_CPU(int, cpu_priv_count);
+static DEFINE_PER_CPU(unsigned, cpu_model);
+
+static DEFINE_MUTEX(cpu_debug_lock);
+
+static struct dentry *cpu_debugfs_dir;
+
+static struct cpu_debug_base cpu_base[] = {
+       { "mc",         CPU_MC,         0       },
+       { "monitor",    CPU_MONITOR,    0       },
+       { "time",       CPU_TIME,       0       },
+       { "pmc",        CPU_PMC,        1       },
+       { "platform",   CPU_PLATFORM,   0       },
+       { "apic",       CPU_APIC,       0       },
+       { "poweron",    CPU_POWERON,    0       },
+       { "control",    CPU_CONTROL,    0       },
+       { "features",   CPU_FEATURES,   0       },
+       { "lastbranch", CPU_LBRANCH,    0       },
+       { "bios",       CPU_BIOS,       0       },
+       { "freq",       CPU_FREQ,       0       },
+       { "mtrr",       CPU_MTRR,       0       },
+       { "perf",       CPU_PERF,       0       },
+       { "cache",      CPU_CACHE,      0       },
+       { "sysenter",   CPU_SYSENTER,   0       },
+       { "therm",      CPU_THERM,      0       },
+       { "misc",       CPU_MISC,       0       },
+       { "debug",      CPU_DEBUG,      0       },
+       { "pat",        CPU_PAT,        0       },
+       { "vmx",        CPU_VMX,        0       },
+       { "call",       CPU_CALL,       0       },
+       { "base",       CPU_BASE,       0       },
+       { "ver",        CPU_VER,        0       },
+       { "conf",       CPU_CONF,       0       },
+       { "smm",        CPU_SMM,        0       },
+       { "svm",        CPU_SVM,        0       },
+       { "osvm",       CPU_OSVM,       0       },
+       { "tss",        CPU_TSS,        0       },
+       { "cr",         CPU_CR,         0       },
+       { "dt",         CPU_DT,         0       },
+       { "registers",  CPU_REG_ALL,    0       },
+};
+
+static struct cpu_file_base cpu_file[] = {
+       { "index",      CPU_REG_ALL,    0       },
+       { "value",      CPU_REG_ALL,    1       },
+};
+
+/* Intel Registers Range */
+static struct cpu_debug_range cpu_intel_range[] = {
+       { 0x00000000, 0x00000001, CPU_MC,       CPU_INTEL_ALL           },
+       { 0x00000006, 0x00000007, CPU_MONITOR,  CPU_CX_AT_XE            },
+       { 0x00000010, 0x00000010, CPU_TIME,     CPU_INTEL_ALL           },
+       { 0x00000011, 0x00000013, CPU_PMC,      CPU_INTEL_PENTIUM       },
+       { 0x00000017, 0x00000017, CPU_PLATFORM, CPU_PX_CX_AT_XE         },
+       { 0x0000001B, 0x0000001B, CPU_APIC,     CPU_P6_CX_AT_XE         },
+
+       { 0x0000002A, 0x0000002A, CPU_POWERON,  CPU_PX_CX_AT_XE         },
+       { 0x0000002B, 0x0000002B, CPU_POWERON,  CPU_INTEL_XEON          },
+       { 0x0000002C, 0x0000002C, CPU_FREQ,     CPU_INTEL_XEON          },
+       { 0x0000003A, 0x0000003A, CPU_CONTROL,  CPU_CX_AT_XE            },
+
+       { 0x00000040, 0x00000043, CPU_LBRANCH,  CPU_PM_CX_AT_XE         },
+       { 0x00000044, 0x00000047, CPU_LBRANCH,  CPU_PM_CO_AT            },
+       { 0x00000060, 0x00000063, CPU_LBRANCH,  CPU_C2_AT               },
+       { 0x00000064, 0x00000067, CPU_LBRANCH,  CPU_INTEL_ATOM          },
+
+       { 0x00000079, 0x00000079, CPU_BIOS,     CPU_P6_CX_AT_XE         },
+       { 0x00000088, 0x0000008A, CPU_CACHE,    CPU_INTEL_P6            },
+       { 0x0000008B, 0x0000008B, CPU_BIOS,     CPU_P6_CX_AT_XE         },
+       { 0x0000009B, 0x0000009B, CPU_MONITOR,  CPU_INTEL_XEON          },
+
+       { 0x000000C1, 0x000000C2, CPU_PMC,      CPU_P6_CX_AT            },
+       { 0x000000CD, 0x000000CD, CPU_FREQ,     CPU_CX_AT               },
+       { 0x000000E7, 0x000000E8, CPU_PERF,     CPU_CX_AT               },
+       { 0x000000FE, 0x000000FE, CPU_MTRR,     CPU_P6_CX_XE            },
+
+       { 0x00000116, 0x00000116, CPU_CACHE,    CPU_INTEL_P6            },
+       { 0x00000118, 0x00000118, CPU_CACHE,    CPU_INTEL_P6            },
+       { 0x00000119, 0x00000119, CPU_CACHE,    CPU_INTEL_PX            },
+       { 0x0000011A, 0x0000011B, CPU_CACHE,    CPU_INTEL_P6            },
+       { 0x0000011E, 0x0000011E, CPU_CACHE,    CPU_PX_CX_AT            },
+
+       { 0x00000174, 0x00000176, CPU_SYSENTER, CPU_P6_CX_AT_XE         },
+       { 0x00000179, 0x0000017A, CPU_MC,       CPU_PX_CX_AT_XE         },
+       { 0x0000017B, 0x0000017B, CPU_MC,       CPU_P6_XE               },
+       { 0x00000186, 0x00000187, CPU_PMC,      CPU_P6_CX_AT            },
+       { 0x00000198, 0x00000199, CPU_PERF,     CPU_PM_CX_AT_XE         },
+       { 0x0000019A, 0x0000019A, CPU_TIME,     CPU_PM_CX_AT_XE         },
+       { 0x0000019B, 0x0000019D, CPU_THERM,    CPU_PM_CX_AT_XE         },
+       { 0x000001A0, 0x000001A0, CPU_MISC,     CPU_PM_CX_AT_XE         },
+
+       { 0x000001C9, 0x000001C9, CPU_LBRANCH,  CPU_PM_CX_AT            },
+       { 0x000001D7, 0x000001D8, CPU_LBRANCH,  CPU_INTEL_XEON          },
+       { 0x000001D9, 0x000001D9, CPU_DEBUG,    CPU_CX_AT_XE            },
+       { 0x000001DA, 0x000001DA, CPU_LBRANCH,  CPU_INTEL_XEON          },
+       { 0x000001DB, 0x000001DB, CPU_LBRANCH,  CPU_P6_XE               },
+       { 0x000001DC, 0x000001DC, CPU_LBRANCH,  CPU_INTEL_P6            },
+       { 0x000001DD, 0x000001DE, CPU_LBRANCH,  CPU_PX_CX_AT_XE         },
+       { 0x000001E0, 0x000001E0, CPU_LBRANCH,  CPU_INTEL_P6            },
+
+       { 0x00000200, 0x0000020F, CPU_MTRR,     CPU_P6_CX_XE            },
+       { 0x00000250, 0x00000250, CPU_MTRR,     CPU_P6_CX_XE            },
+       { 0x00000258, 0x00000259, CPU_MTRR,     CPU_P6_CX_XE            },
+       { 0x00000268, 0x0000026F, CPU_MTRR,     CPU_P6_CX_XE            },
+       { 0x00000277, 0x00000277, CPU_PAT,      CPU_C2_AT_XE            },
+       { 0x000002FF, 0x000002FF, CPU_MTRR,     CPU_P6_CX_XE            },
+
+       { 0x00000300, 0x00000308, CPU_PMC,      CPU_INTEL_XEON          },
+       { 0x00000309, 0x0000030B, CPU_PMC,      CPU_C2_AT_XE            },
+       { 0x0000030C, 0x00000311, CPU_PMC,      CPU_INTEL_XEON          },
+       { 0x00000345, 0x00000345, CPU_PMC,      CPU_C2_AT               },
+       { 0x00000360, 0x00000371, CPU_PMC,      CPU_INTEL_XEON          },
+       { 0x0000038D, 0x00000390, CPU_PMC,      CPU_C2_AT               },
+       { 0x000003A0, 0x000003BE, CPU_PMC,      CPU_INTEL_XEON          },
+       { 0x000003C0, 0x000003CD, CPU_PMC,      CPU_INTEL_XEON          },
+       { 0x000003E0, 0x000003E1, CPU_PMC,      CPU_INTEL_XEON          },
+       { 0x000003F0, 0x000003F0, CPU_PMC,      CPU_INTEL_XEON          },
+       { 0x000003F1, 0x000003F1, CPU_PMC,      CPU_C2_AT_XE            },
+       { 0x000003F2, 0x000003F2, CPU_PMC,      CPU_INTEL_XEON          },
+
+       { 0x00000400, 0x00000402, CPU_MC,       CPU_PM_CX_AT_XE         },
+       { 0x00000403, 0x00000403, CPU_MC,       CPU_INTEL_XEON          },
+       { 0x00000404, 0x00000406, CPU_MC,       CPU_PM_CX_AT_XE         },
+       { 0x00000407, 0x00000407, CPU_MC,       CPU_INTEL_XEON          },
+       { 0x00000408, 0x0000040A, CPU_MC,       CPU_PM_CX_AT_XE         },
+       { 0x0000040B, 0x0000040B, CPU_MC,       CPU_INTEL_XEON          },
+       { 0x0000040C, 0x0000040E, CPU_MC,       CPU_PM_CX_XE            },
+       { 0x0000040F, 0x0000040F, CPU_MC,       CPU_INTEL_XEON          },
+       { 0x00000410, 0x00000412, CPU_MC,       CPU_PM_CX_AT_XE         },
+       { 0x00000413, 0x00000417, CPU_MC,       CPU_CX_AT_XE            },
+       { 0x00000480, 0x0000048B, CPU_VMX,      CPU_CX_AT_XE            },
+
+       { 0x00000600, 0x00000600, CPU_DEBUG,    CPU_PM_CX_AT_XE         },
+       { 0x00000680, 0x0000068F, CPU_LBRANCH,  CPU_INTEL_XEON          },
+       { 0x000006C0, 0x000006CF, CPU_LBRANCH,  CPU_INTEL_XEON          },
+
+       { 0x000107CC, 0x000107D3, CPU_PMC,      CPU_INTEL_XEON_MP       },
+
+       { 0xC0000080, 0xC0000080, CPU_FEATURES, CPU_INTEL_XEON          },
+       { 0xC0000081, 0xC0000082, CPU_CALL,     CPU_INTEL_XEON          },
+       { 0xC0000084, 0xC0000084, CPU_CALL,     CPU_INTEL_XEON          },
+       { 0xC0000100, 0xC0000102, CPU_BASE,     CPU_INTEL_XEON          },
+};
+
+/* AMD Registers Range */
+static struct cpu_debug_range cpu_amd_range[] = {
+       { 0x00000000, 0x00000001, CPU_MC,       CPU_K10_PLUS,           },
+       { 0x00000010, 0x00000010, CPU_TIME,     CPU_K8_PLUS,            },
+       { 0x0000001B, 0x0000001B, CPU_APIC,     CPU_K8_PLUS,            },
+       { 0x0000002A, 0x0000002A, CPU_POWERON,  CPU_K7_PLUS             },
+       { 0x0000008B, 0x0000008B, CPU_VER,      CPU_K8_PLUS             },
+       { 0x000000FE, 0x000000FE, CPU_MTRR,     CPU_K8_PLUS,            },
+
+       { 0x00000174, 0x00000176, CPU_SYSENTER, CPU_K8_PLUS,            },
+       { 0x00000179, 0x0000017B, CPU_MC,       CPU_K8_PLUS,            },
+       { 0x000001D9, 0x000001D9, CPU_DEBUG,    CPU_K8_PLUS,            },
+       { 0x000001DB, 0x000001DE, CPU_LBRANCH,  CPU_K8_PLUS,            },
+
+       { 0x00000200, 0x0000020F, CPU_MTRR,     CPU_K8_PLUS,            },
+       { 0x00000250, 0x00000250, CPU_MTRR,     CPU_K8_PLUS,            },
+       { 0x00000258, 0x00000259, CPU_MTRR,     CPU_K8_PLUS,            },
+       { 0x00000268, 0x0000026F, CPU_MTRR,     CPU_K8_PLUS,            },
+       { 0x00000277, 0x00000277, CPU_PAT,      CPU_K8_PLUS,            },
+       { 0x000002FF, 0x000002FF, CPU_MTRR,     CPU_K8_PLUS,            },
+
+       { 0x00000400, 0x00000413, CPU_MC,       CPU_K8_PLUS,            },
+
+       { 0xC0000080, 0xC0000080, CPU_FEATURES, CPU_AMD_ALL,            },
+       { 0xC0000081, 0xC0000084, CPU_CALL,     CPU_K8_PLUS,            },
+       { 0xC0000100, 0xC0000102, CPU_BASE,     CPU_K8_PLUS,            },
+       { 0xC0000103, 0xC0000103, CPU_TIME,     CPU_K10_PLUS,           },
+
+       { 0xC0010000, 0xC0010007, CPU_PMC,      CPU_K8_PLUS,            },
+       { 0xC0010010, 0xC0010010, CPU_CONF,     CPU_K7_PLUS,            },
+       { 0xC0010015, 0xC0010015, CPU_CONF,     CPU_K7_PLUS,            },
+       { 0xC0010016, 0xC001001A, CPU_MTRR,     CPU_K8_PLUS,            },
+       { 0xC001001D, 0xC001001D, CPU_MTRR,     CPU_K8_PLUS,            },
+       { 0xC001001F, 0xC001001F, CPU_CONF,     CPU_K8_PLUS,            },
+       { 0xC0010030, 0xC0010035, CPU_BIOS,     CPU_K8_PLUS,            },
+       { 0xC0010044, 0xC0010048, CPU_MC,       CPU_K8_PLUS,            },
+       { 0xC0010050, 0xC0010056, CPU_SMM,      CPU_K0F_PLUS,           },
+       { 0xC0010058, 0xC0010058, CPU_CONF,     CPU_K10_PLUS,           },
+       { 0xC0010060, 0xC0010060, CPU_CACHE,    CPU_AMD_11,             },
+       { 0xC0010061, 0xC0010068, CPU_SMM,      CPU_K10_PLUS,           },
+       { 0xC0010069, 0xC001006B, CPU_SMM,      CPU_AMD_11,             },
+       { 0xC0010070, 0xC0010071, CPU_SMM,      CPU_K10_PLUS,           },
+       { 0xC0010111, 0xC0010113, CPU_SMM,      CPU_K8_PLUS,            },
+       { 0xC0010114, 0xC0010118, CPU_SVM,      CPU_K10_PLUS,           },
+       { 0xC0010140, 0xC0010141, CPU_OSVM,     CPU_K10_PLUS,           },
+       { 0xC0011022, 0xC0011023, CPU_CONF,     CPU_K10_PLUS,           },
+};
+
+
+/* Intel */
+static int get_intel_modelflag(unsigned model)
+{
+       int flag;
+
+       switch (model) {
+       case 0x0501:
+       case 0x0502:
+       case 0x0504:
+               flag = CPU_INTEL_PENTIUM;
+               break;
+       case 0x0601:
+       case 0x0603:
+       case 0x0605:
+       case 0x0607:
+       case 0x0608:
+       case 0x060A:
+       case 0x060B:
+               flag = CPU_INTEL_P6;
+               break;
+       case 0x0609:
+       case 0x060D:
+               flag = CPU_INTEL_PENTIUM_M;
+               break;
+       case 0x060E:
+               flag = CPU_INTEL_CORE;
+               break;
+       case 0x060F:
+       case 0x0617:
+               flag = CPU_INTEL_CORE2;
+               break;
+       case 0x061C:
+               flag = CPU_INTEL_ATOM;
+               break;
+       case 0x0F00:
+       case 0x0F01:
+       case 0x0F02:
+       case 0x0F03:
+       case 0x0F04:
+               flag = CPU_INTEL_XEON_P4;
+               break;
+       case 0x0F06:
+               flag = CPU_INTEL_XEON_MP;
+               break;
+       default:
+               flag = CPU_NONE;
+               break;
+       }
+
+       return flag;
+}
+
+/* AMD */
+static int get_amd_modelflag(unsigned model)
+{
+       int flag;
+
+       switch (model >> 8) {
+       case 0x6:
+               flag = CPU_AMD_K6;
+               break;
+       case 0x7:
+               flag = CPU_AMD_K7;
+               break;
+       case 0x8:
+               flag = CPU_AMD_K8;
+               break;
+       case 0xf:
+               flag = CPU_AMD_0F;
+               break;
+       case 0x10:
+               flag = CPU_AMD_10;
+               break;
+       case 0x11:
+               flag = CPU_AMD_11;
+               break;
+       default:
+               flag = CPU_NONE;
+               break;
+       }
+
+       return flag;
+}
+
+static int get_cpu_modelflag(unsigned cpu)
+{
+       int flag;
+
+       flag = per_cpu(cpu_model, cpu);
+
+       switch (flag >> 16) {
+       case X86_VENDOR_INTEL:
+               flag = get_intel_modelflag(flag);
+               break;
+       case X86_VENDOR_AMD:
+               flag = get_amd_modelflag(flag & 0xffff);
+               break;
+       default:
+               flag = CPU_NONE;
+               break;
+       }
+
+       return flag;
+}
+
+static int get_cpu_range_count(unsigned cpu)
+{
+       int index;
+
+       switch (per_cpu(cpu_model, cpu) >> 16) {
+       case X86_VENDOR_INTEL:
+               index = ARRAY_SIZE(cpu_intel_range);
+               break;
+       case X86_VENDOR_AMD:
+               index = ARRAY_SIZE(cpu_amd_range);
+               break;
+       default:
+               index = 0;
+               break;
+       }
+
+       return index;
+}
+
+static int is_typeflag_valid(unsigned cpu, unsigned flag)
+{
+       unsigned vendor, modelflag;
+       int i, index;
+
+       /* Standard Registers should be always valid */
+       if (flag >= CPU_TSS)
+               return 1;
+
+       modelflag = per_cpu(cpu_modelflag, cpu);
+       vendor = per_cpu(cpu_model, cpu) >> 16;
+       index = get_cpu_range_count(cpu);
+
+       for (i = 0; i < index; i++) {
+               switch (vendor) {
+               case X86_VENDOR_INTEL:
+                       if ((cpu_intel_range[i].model & modelflag) &&
+                           (cpu_intel_range[i].flag & flag))
+                               return 1;
+                       break;
+               case X86_VENDOR_AMD:
+                       if ((cpu_amd_range[i].model & modelflag) &&
+                           (cpu_amd_range[i].flag & flag))
+                               return 1;
+                       break;
+               }
+       }
+
+       /* Invalid */
+       return 0;
+}
+
+static unsigned get_cpu_range(unsigned cpu, unsigned *min, unsigned *max,
+                             int index, unsigned flag)
+{
+       unsigned modelflag;
+
+       modelflag = per_cpu(cpu_modelflag, cpu);
+       *max = 0;
+       switch (per_cpu(cpu_model, cpu) >> 16) {
+       case X86_VENDOR_INTEL:
+               if ((cpu_intel_range[index].model & modelflag) &&
+                   (cpu_intel_range[index].flag & flag)) {
+                       *min = cpu_intel_range[index].min;
+                       *max = cpu_intel_range[index].max;
+               }
+               break;
+       case X86_VENDOR_AMD:
+               if ((cpu_amd_range[index].model & modelflag) &&
+                   (cpu_amd_range[index].flag & flag)) {
+                       *min = cpu_amd_range[index].min;
+                       *max = cpu_amd_range[index].max;
+               }
+               break;
+       }
+
+       return *max;
+}
+
+/* This function can also be called with seq = NULL for printk */
+static void print_cpu_data(struct seq_file *seq, unsigned type,
+                          u32 low, u32 high)
+{
+       struct cpu_private *priv;
+       u64 val = high;
+
+       if (seq) {
+               priv = seq->private;
+               if (priv->file) {
+                       val = (val << 32) | low;
+                       seq_printf(seq, "0x%llx\n", val);
+               } else
+                       seq_printf(seq, " %08x: %08x_%08x\n",
+                                  type, high, low);
+       } else
+               printk(KERN_INFO " %08x: %08x_%08x\n", type, high, low);
+}
+
+/* This function can also be called with seq = NULL for printk */
+static void print_msr(struct seq_file *seq, unsigned cpu, unsigned flag)
+{
+       unsigned msr, msr_min, msr_max;
+       struct cpu_private *priv;
+       u32 low, high;
+       int i, range;
+
+       if (seq) {
+               priv = seq->private;
+               if (priv->file) {
+                       if (!rdmsr_safe_on_cpu(priv->cpu, priv->reg,
+                                              &low, &high))
+                               print_cpu_data(seq, priv->reg, low, high);
+                       return;
+               }
+       }
+
+       range = get_cpu_range_count(cpu);
+
+       for (i = 0; i < range; i++) {
+               if (!get_cpu_range(cpu, &msr_min, &msr_max, i, flag))
+                       continue;
+
+               for (msr = msr_min; msr <= msr_max; msr++) {
+                       if (rdmsr_safe_on_cpu(cpu, msr, &low, &high))
+                               continue;
+                       print_cpu_data(seq, msr, low, high);
+               }
+       }
+}
+
+static void print_tss(void *arg)
+{
+       struct pt_regs *regs = task_pt_regs(current);
+       struct seq_file *seq = arg;
+       unsigned int seg;
+
+       seq_printf(seq, " RAX\t: %016lx\n", regs->ax);
+       seq_printf(seq, " RBX\t: %016lx\n", regs->bx);
+       seq_printf(seq, " RCX\t: %016lx\n", regs->cx);
+       seq_printf(seq, " RDX\t: %016lx\n", regs->dx);
+
+       seq_printf(seq, " RSI\t: %016lx\n", regs->si);
+       seq_printf(seq, " RDI\t: %016lx\n", regs->di);
+       seq_printf(seq, " RBP\t: %016lx\n", regs->bp);
+       seq_printf(seq, " ESP\t: %016lx\n", regs->sp);
+
+#ifdef CONFIG_X86_64
+       seq_printf(seq, " R08\t: %016lx\n", regs->r8);
+       seq_printf(seq, " R09\t: %016lx\n", regs->r9);
+       seq_printf(seq, " R10\t: %016lx\n", regs->r10);
+       seq_printf(seq, " R11\t: %016lx\n", regs->r11);
+       seq_printf(seq, " R12\t: %016lx\n", regs->r12);
+       seq_printf(seq, " R13\t: %016lx\n", regs->r13);
+       seq_printf(seq, " R14\t: %016lx\n", regs->r14);
+       seq_printf(seq, " R15\t: %016lx\n", regs->r15);
+#endif
+
+       asm("movl %%cs,%0" : "=r" (seg));
+       seq_printf(seq, " CS\t:             %04x\n", seg);
+       asm("movl %%ds,%0" : "=r" (seg));
+       seq_printf(seq, " DS\t:             %04x\n", seg);
+       seq_printf(seq, " SS\t:             %04lx\n", regs->ss & 0xffff);
+       asm("movl %%es,%0" : "=r" (seg));
+       seq_printf(seq, " ES\t:             %04x\n", seg);
+       asm("movl %%fs,%0" : "=r" (seg));
+       seq_printf(seq, " FS\t:             %04x\n", seg);
+       asm("movl %%gs,%0" : "=r" (seg));
+       seq_printf(seq, " GS\t:             %04x\n", seg);
+
+       seq_printf(seq, " EFLAGS\t: %016lx\n", regs->flags);
+
+       seq_printf(seq, " EIP\t: %016lx\n", regs->ip);
+}
+
+static void print_cr(void *arg)
+{
+       struct seq_file *seq = arg;
+
+       seq_printf(seq, " cr0\t: %016lx\n", read_cr0());
+       seq_printf(seq, " cr2\t: %016lx\n", read_cr2());
+       seq_printf(seq, " cr3\t: %016lx\n", read_cr3());
+       seq_printf(seq, " cr4\t: %016lx\n", read_cr4_safe());
+#ifdef CONFIG_X86_64
+       seq_printf(seq, " cr8\t: %016lx\n", read_cr8());
+#endif
+}
+
+static void print_desc_ptr(char *str, struct seq_file *seq, struct desc_ptr dt)
+{
+       seq_printf(seq, " %s\t: %016llx\n", str, (u64)(dt.address | dt.size));
+}
+
+static void print_dt(void *seq)
+{
+       struct desc_ptr dt;
+       unsigned long ldt;
+
+       /* IDT */
+       store_idt((struct desc_ptr *)&dt);
+       print_desc_ptr("IDT", seq, dt);
+
+       /* GDT */
+       store_gdt((struct desc_ptr *)&dt);
+       print_desc_ptr("GDT", seq, dt);
+
+       /* LDT */
+       store_ldt(ldt);
+       seq_printf(seq, " LDT\t: %016lx\n", ldt);
+
+       /* TR */
+       store_tr(ldt);
+       seq_printf(seq, " TR\t: %016lx\n", ldt);
+}
+
+static void print_dr(void *arg)
+{
+       struct seq_file *seq = arg;
+       unsigned long dr;
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               /* Ignore db4, db5 */
+               if ((i == 4) || (i == 5))
+                       continue;
+               get_debugreg(dr, i);
+               seq_printf(seq, " dr%d\t: %016lx\n", i, dr);
+       }
+
+       seq_printf(seq, "\n MSR\t:\n");
+}
+
+static void print_apic(void *arg)
+{
+       struct seq_file *seq = arg;
+
+#ifdef CONFIG_X86_LOCAL_APIC
+       seq_printf(seq, " LAPIC\t:\n");
+       seq_printf(seq, " ID\t\t: %08x\n",  apic_read(APIC_ID) >> 24);
+       seq_printf(seq, " LVR\t\t: %08x\n",  apic_read(APIC_LVR));
+       seq_printf(seq, " TASKPRI\t: %08x\n",  apic_read(APIC_TASKPRI));
+       seq_printf(seq, " ARBPRI\t\t: %08x\n",  apic_read(APIC_ARBPRI));
+       seq_printf(seq, " PROCPRI\t: %08x\n",  apic_read(APIC_PROCPRI));
+       seq_printf(seq, " LDR\t\t: %08x\n",  apic_read(APIC_LDR));
+       seq_printf(seq, " DFR\t\t: %08x\n",  apic_read(APIC_DFR));
+       seq_printf(seq, " SPIV\t\t: %08x\n",  apic_read(APIC_SPIV));
+       seq_printf(seq, " ISR\t\t: %08x\n",  apic_read(APIC_ISR));
+       seq_printf(seq, " ESR\t\t: %08x\n",  apic_read(APIC_ESR));
+       seq_printf(seq, " ICR\t\t: %08x\n",  apic_read(APIC_ICR));
+       seq_printf(seq, " ICR2\t\t: %08x\n",  apic_read(APIC_ICR2));
+       seq_printf(seq, " LVTT\t\t: %08x\n",  apic_read(APIC_LVTT));
+       seq_printf(seq, " LVTTHMR\t: %08x\n",  apic_read(APIC_LVTTHMR));
+       seq_printf(seq, " LVTPC\t\t: %08x\n",  apic_read(APIC_LVTPC));
+       seq_printf(seq, " LVT0\t\t: %08x\n",  apic_read(APIC_LVT0));
+       seq_printf(seq, " LVT1\t\t: %08x\n",  apic_read(APIC_LVT1));
+       seq_printf(seq, " LVTERR\t\t: %08x\n",  apic_read(APIC_LVTERR));
+       seq_printf(seq, " TMICT\t\t: %08x\n",  apic_read(APIC_TMICT));
+       seq_printf(seq, " TMCCT\t\t: %08x\n",  apic_read(APIC_TMCCT));
+       seq_printf(seq, " TDCR\t\t: %08x\n",  apic_read(APIC_TDCR));
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+       seq_printf(seq, "\n MSR\t:\n");
+}
+
+static int cpu_seq_show(struct seq_file *seq, void *v)
+{
+       struct cpu_private *priv = seq->private;
+
+       if (priv == NULL)
+               return -EINVAL;
+
+       switch (cpu_base[priv->type].flag) {
+       case CPU_TSS:
+               smp_call_function_single(priv->cpu, print_tss, seq, 1);
+               break;
+       case CPU_CR:
+               smp_call_function_single(priv->cpu, print_cr, seq, 1);
+               break;
+       case CPU_DT:
+               smp_call_function_single(priv->cpu, print_dt, seq, 1);
+               break;
+       case CPU_DEBUG:
+               if (priv->file == CPU_INDEX_BIT)
+                       smp_call_function_single(priv->cpu, print_dr, seq, 1);
+               print_msr(seq, priv->cpu, cpu_base[priv->type].flag);
+               break;
+       case CPU_APIC:
+               if (priv->file == CPU_INDEX_BIT)
+                       smp_call_function_single(priv->cpu, print_apic, seq, 1);
+               print_msr(seq, priv->cpu, cpu_base[priv->type].flag);
+               break;
+
+       default:
+               print_msr(seq, priv->cpu, cpu_base[priv->type].flag);
+               break;
+       }
+       seq_printf(seq, "\n");
+
+       return 0;
+}
+
+static void *cpu_seq_start(struct seq_file *seq, loff_t *pos)
+{
+       if (*pos == 0) /* One time is enough ;-) */
+               return seq;
+
+       return NULL;
+}
+
+static void *cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       (*pos)++;
+
+       return cpu_seq_start(seq, pos);
+}
+
+static void cpu_seq_stop(struct seq_file *seq, void *v)
+{
+}
+
+static const struct seq_operations cpu_seq_ops = {
+       .start          = cpu_seq_start,
+       .next           = cpu_seq_next,
+       .stop           = cpu_seq_stop,
+       .show           = cpu_seq_show,
+};
+
+static int cpu_seq_open(struct inode *inode, struct file *file)
+{
+       struct cpu_private *priv = inode->i_private;
+       struct seq_file *seq;
+       int err;
+
+       err = seq_open(file, &cpu_seq_ops);
+       if (!err) {
+               seq = file->private_data;
+               seq->private = priv;
+       }
+
+       return err;
+}
+
+static int write_msr(struct cpu_private *priv, u64 val)
+{
+       u32 low, high;
+
+       high = (val >> 32) & 0xffffffff;
+       low = val & 0xffffffff;
+
+       if (!wrmsr_safe_on_cpu(priv->cpu, priv->reg, low, high))
+               return 0;
+
+       return -EPERM;
+}
+
+static int write_cpu_register(struct cpu_private *priv, const char *buf)
+{
+       int ret = -EPERM;
+       u64 val;
+
+       ret = strict_strtoull(buf, 0, &val);
+       if (ret < 0)
+               return ret;
+
+       /* Supporting only MSRs */
+       if (priv->type < CPU_TSS_BIT)
+               return write_msr(priv, val);
+
+       return ret;
+}
+
+static ssize_t cpu_write(struct file *file, const char __user *ubuf,
+                            size_t count, loff_t *off)
+{
+       struct seq_file *seq = file->private_data;
+       struct cpu_private *priv = seq->private;
+       char buf[19];
+
+       if ((priv == NULL) || (count >= sizeof(buf)))
+               return -EINVAL;
+
+       if (copy_from_user(&buf, ubuf, count))
+               return -EFAULT;
+
+       buf[count] = 0;
+
+       if ((cpu_base[priv->type].write) && (cpu_file[priv->file].write))
+               if (!write_cpu_register(priv, buf))
+                       return count;
+
+       return -EACCES;
+}
+
+static const struct file_operations cpu_fops = {
+       .owner          = THIS_MODULE,
+       .open           = cpu_seq_open,
+       .read           = seq_read,
+       .write          = cpu_write,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+static int cpu_create_file(unsigned cpu, unsigned type, unsigned reg,
+                          unsigned file, struct dentry *dentry)
+{
+       struct cpu_private *priv = NULL;
+
+       /* Already intialized */
+       if (file == CPU_INDEX_BIT)
+               if (per_cpu(cpu_arr[type].init, cpu))
+                       return 0;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+
+       priv->cpu = cpu;
+       priv->type = type;
+       priv->reg = reg;
+       priv->file = file;
+       mutex_lock(&cpu_debug_lock);
+       per_cpu(priv_arr[type], cpu) = priv;
+       per_cpu(cpu_priv_count, cpu)++;
+       mutex_unlock(&cpu_debug_lock);
+
+       if (file)
+               debugfs_create_file(cpu_file[file].name, S_IRUGO,
+                                   dentry, (void *)priv, &cpu_fops);
+       else {
+               debugfs_create_file(cpu_base[type].name, S_IRUGO,
+                                   per_cpu(cpu_arr[type].dentry, cpu),
+                                   (void *)priv, &cpu_fops);
+               mutex_lock(&cpu_debug_lock);
+               per_cpu(cpu_arr[type].init, cpu) = 1;
+               mutex_unlock(&cpu_debug_lock);
+       }
+
+       return 0;
+}
+
+static int cpu_init_regfiles(unsigned cpu, unsigned int type, unsigned reg,
+                            struct dentry *dentry)
+{
+       unsigned file;
+       int err = 0;
+
+       for (file = 0; file <  ARRAY_SIZE(cpu_file); file++) {
+               err = cpu_create_file(cpu, type, reg, file, dentry);
+               if (err)
+                       return err;
+       }
+
+       return err;
+}
+
+static int cpu_init_msr(unsigned cpu, unsigned type, struct dentry *dentry)
+{
+       struct dentry *cpu_dentry = NULL;
+       unsigned reg, reg_min, reg_max;
+       int i, range, err = 0;
+       char reg_dir[12];
+       u32 low, high;
+
+       range = get_cpu_range_count(cpu);
+
+       for (i = 0; i < range; i++) {
+               if (!get_cpu_range(cpu, &reg_min, &reg_max, i,
+                                  cpu_base[type].flag))
+                       continue;
+
+               for (reg = reg_min; reg <= reg_max; reg++) {
+                       if (rdmsr_safe_on_cpu(cpu, reg, &low, &high))
+                               continue;
+
+                       sprintf(reg_dir, "0x%x", reg);
+                       cpu_dentry = debugfs_create_dir(reg_dir, dentry);
+                       err = cpu_init_regfiles(cpu, type, reg, cpu_dentry);
+                       if (err)
+                               return err;
+               }
+       }
+
+       return err;
+}
+
+static int cpu_init_allreg(unsigned cpu, struct dentry *dentry)
+{
+       struct dentry *cpu_dentry = NULL;
+       unsigned type;
+       int err = 0;
+
+       for (type = 0; type <  ARRAY_SIZE(cpu_base) - 1; type++) {
+               if (!is_typeflag_valid(cpu, cpu_base[type].flag))
+                       continue;
+               cpu_dentry = debugfs_create_dir(cpu_base[type].name, dentry);
+               per_cpu(cpu_arr[type].dentry, cpu) = cpu_dentry;
+
+               if (type < CPU_TSS_BIT)
+                       err = cpu_init_msr(cpu, type, cpu_dentry);
+               else
+                       err = cpu_create_file(cpu, type, 0, CPU_INDEX_BIT,
+                                             cpu_dentry);
+               if (err)
+                       return err;
+       }
+
+       return err;
+}
+
+static int cpu_init_cpu(void)
+{
+       struct dentry *cpu_dentry = NULL;
+       struct cpuinfo_x86 *cpui;
+       char cpu_dir[12];
+       unsigned cpu;
+       int err = 0;
+
+       for (cpu = 0; cpu < nr_cpu_ids; cpu++) {
+               cpui = &cpu_data(cpu);
+               if (!cpu_has(cpui, X86_FEATURE_MSR))
+                       continue;
+               per_cpu(cpu_model, cpu) = ((cpui->x86_vendor << 16) |
+                                          (cpui->x86 << 8) |
+                                          (cpui->x86_model));
+               per_cpu(cpu_modelflag, cpu) = get_cpu_modelflag(cpu);
+
+               sprintf(cpu_dir, "cpu%d", cpu);
+               cpu_dentry = debugfs_create_dir(cpu_dir, cpu_debugfs_dir);
+               err = cpu_init_allreg(cpu, cpu_dentry);
+
+               pr_info("cpu%d(%d) debug files %d\n",
+                       cpu, nr_cpu_ids, per_cpu(cpu_priv_count, cpu));
+               if (per_cpu(cpu_priv_count, cpu) > MAX_CPU_FILES) {
+                       pr_err("Register files count %d exceeds limit %d\n",
+                               per_cpu(cpu_priv_count, cpu), MAX_CPU_FILES);
+                       per_cpu(cpu_priv_count, cpu) = MAX_CPU_FILES;
+                       err = -ENFILE;
+               }
+               if (err)
+                       return err;
+       }
+
+       return err;
+}
+
+static int __init cpu_debug_init(void)
+{
+       cpu_debugfs_dir = debugfs_create_dir("cpu", arch_debugfs_dir);
+
+       return cpu_init_cpu();
+}
+
+static void __exit cpu_debug_exit(void)
+{
+       int i, cpu;
+
+       if (cpu_debugfs_dir)
+               debugfs_remove_recursive(cpu_debugfs_dir);
+
+       for (cpu = 0; cpu <  nr_cpu_ids; cpu++)
+               for (i = 0; i < per_cpu(cpu_priv_count, cpu); i++)
+                       kfree(per_cpu(priv_arr[i], cpu));
+}
+
+module_init(cpu_debug_init);
+module_exit(cpu_debug_exit);
+
+MODULE_AUTHOR("Jaswinder Singh Rajput");
+MODULE_DESCRIPTION("CPU Debug module");
+MODULE_LICENSE("GPL");
index ffd0f5ed071a705e5f55e279ac12f0c2d0cf9419..593171e967ef2009a8f109e8a1f9f81f63c469c5 100644 (file)
@@ -61,23 +61,23 @@ static void __cpuinit do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
  */
 static unsigned char Cx86_dir0_msb __cpuinitdata = 0;
 
-static char Cx86_model[][9] __cpuinitdata = {
+static const char __cpuinitconst Cx86_model[][9] = {
        "Cx486", "Cx486", "5x86 ", "6x86", "MediaGX ", "6x86MX ",
        "M II ", "Unknown"
 };
-static char Cx486_name[][5] __cpuinitdata = {
+static const char __cpuinitconst Cx486_name[][5] = {
        "SLC", "DLC", "SLC2", "DLC2", "SRx", "DRx",
        "SRx2", "DRx2"
 };
-static char Cx486S_name[][4] __cpuinitdata = {
+static const char __cpuinitconst Cx486S_name[][4] = {
        "S", "S2", "Se", "S2e"
 };
-static char Cx486D_name[][4] __cpuinitdata = {
+static const char __cpuinitconst Cx486D_name[][4] = {
        "DX", "DX2", "?", "?", "?", "DX4"
 };
 static char Cx86_cb[] __cpuinitdata = "?.5x Core/Bus Clock";
-static char cyrix_model_mult1[] __cpuinitdata = "12??43";
-static char cyrix_model_mult2[] __cpuinitdata = "12233445";
+static const char __cpuinitconst cyrix_model_mult1[] = "12??43";
+static const char __cpuinitconst cyrix_model_mult2[] = "12233445";
 
 /*
  * Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old
@@ -435,7 +435,7 @@ static void __cpuinit cyrix_identify(struct cpuinfo_x86 *c)
        }
 }
 
-static struct cpu_dev cyrix_cpu_dev __cpuinitdata = {
+static const struct cpu_dev __cpuinitconst cyrix_cpu_dev = {
        .c_vendor       = "Cyrix",
        .c_ident        = { "CyrixInstead" },
        .c_early_init   = early_init_cyrix,
@@ -446,7 +446,7 @@ static struct cpu_dev cyrix_cpu_dev __cpuinitdata = {
 
 cpu_dev_register(cyrix_cpu_dev);
 
-static struct cpu_dev nsc_cpu_dev __cpuinitdata = {
+static const struct cpu_dev __cpuinitconst nsc_cpu_dev = {
        .c_vendor       = "NSC",
        .c_ident        = { "Geode by NSC" },
        .c_init         = init_nsc,
index 1a89a2b68d1539a92939e4d33747a1bcd916390c..7437fa133c02dfdde137ca7201fb9734888a85bc 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/uaccess.h>
 #include <asm/ds.h>
 #include <asm/bugs.h>
+#include <asm/cpu.h>
 
 #ifdef CONFIG_X86_64
 #include <asm/topology.h>
@@ -54,6 +55,11 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
                c->x86_cache_alignment = 128;
 #endif
 
+       /* CPUID workaround for 0F33/0F34 CPU */
+       if (c->x86 == 0xF && c->x86_model == 0x3
+           && (c->x86_mask == 0x3 || c->x86_mask == 0x4))
+               c->x86_phys_bits = 36;
+
        /*
         * c->x86_power is 8000_0007 edx. Bit 8 is TSC runs at constant rate
         * with P/T states and does not stop in deep C-states.
@@ -116,6 +122,28 @@ static void __cpuinit trap_init_f00f_bug(void)
 }
 #endif
 
+static void __cpuinit intel_smp_check(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_SMP
+       /* calling is from identify_secondary_cpu() ? */
+       if (c->cpu_index == boot_cpu_id)
+               return;
+
+       /*
+        * Mask B, Pentium, but not Pentium MMX
+        */
+       if (c->x86 == 5 &&
+           c->x86_mask >= 1 && c->x86_mask <= 4 &&
+           c->x86_model <= 3) {
+               /*
+                * Remember we have B step Pentia with bugs
+                */
+               WARN_ONCE(1, "WARNING: SMP operation may be unreliable"
+                                   "with B stepping processors.\n");
+       }
+#endif
+}
+
 static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c)
 {
        unsigned long lo, hi;
@@ -192,6 +220,8 @@ static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c)
 #ifdef CONFIG_X86_NUMAQ
        numaq_tsc_disable();
 #endif
+
+       intel_smp_check(c);
 }
 #else
 static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c)
@@ -391,7 +421,7 @@ static unsigned int __cpuinit intel_size_cache(struct cpuinfo_x86 *c, unsigned i
 }
 #endif
 
-static struct cpu_dev intel_cpu_dev __cpuinitdata = {
+static const struct cpu_dev __cpuinitconst intel_cpu_dev = {
        .c_vendor       = "Intel",
        .c_ident        = { "GenuineIntel" },
 #ifdef CONFIG_X86_32
index 7293508d8f5c82e4cd4f196c59e28ca332747bad..c471eb1a389cc02c4f788d5a828f3f4bfe56c93d 100644 (file)
@@ -32,7 +32,7 @@ struct _cache_table
 };
 
 /* all the cache descriptor types we care about (no TLB or trace cache entries) */
-static struct _cache_table cache_table[] __cpuinitdata =
+static const struct _cache_table __cpuinitconst cache_table[] =
 {
        { 0x06, LVL_1_INST, 8 },        /* 4-way set assoc, 32 byte line size */
        { 0x08, LVL_1_INST, 16 },       /* 4-way set assoc, 32 byte line size */
@@ -206,15 +206,15 @@ union l3_cache {
        unsigned val;
 };
 
-static unsigned short assocs[] __cpuinitdata = {
+static const unsigned short __cpuinitconst assocs[] = {
        [1] = 1, [2] = 2, [4] = 4, [6] = 8,
        [8] = 16, [0xa] = 32, [0xb] = 48,
        [0xc] = 64,
        [0xf] = 0xffff // ??
 };
 
-static unsigned char levels[] __cpuinitdata = { 1, 1, 2, 3 };
-static unsigned char types[] __cpuinitdata = { 1, 2, 3, 3 };
+static const unsigned char __cpuinitconst levels[] = { 1, 1, 2, 3 };
+static const unsigned char __cpuinitconst types[] = { 1, 2, 3, 3 };
 
 static void __cpuinit
 amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
index d7d2323bbb6976ffa603246bd06845d280150371..b2f89829bbe824d2cecfd74d8c09b2923406493b 100644 (file)
@@ -4,3 +4,4 @@ obj-$(CONFIG_X86_32)            += k7.o p4.o p5.o p6.o winchip.o
 obj-$(CONFIG_X86_MCE_INTEL)    += mce_intel_64.o
 obj-$(CONFIG_X86_MCE_AMD)      += mce_amd_64.o
 obj-$(CONFIG_X86_MCE_NONFATAL) += non-fatal.o
+obj-$(CONFIG_X86_MCE_THRESHOLD) += threshold.o
index dfaebce3633e3f9b8415e79f29ad9f012276825a..3552119b091da51e65ce933c9852eee694920b9b 100644 (file)
@@ -60,20 +60,6 @@ void mcheck_init(struct cpuinfo_x86 *c)
        }
 }
 
-static unsigned long old_cr4 __initdata;
-
-void __init stop_mce(void)
-{
-       old_cr4 = read_cr4();
-       clear_in_cr4(X86_CR4_MCE);
-}
-
-void __init restart_mce(void)
-{
-       if (old_cr4 & X86_CR4_MCE)
-               set_in_cr4(X86_CR4_MCE);
-}
-
 static int __init mcheck_disable(char *str)
 {
        mce_disabled = 1;
index fe79985ce0f2f6fb4ae23f3bc92a791994ed9f62..ca14604611ec7ccc6217afc008e50d88af6ad88f 100644 (file)
@@ -3,6 +3,8 @@
  * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs.
  * Rest from unknown author(s).
  * 2004 Andi Kleen. Rewrote most of it.
+ * Copyright 2008 Intel Corporation
+ * Author: Andi Kleen
  */
 
 #include <linux/init.h>
@@ -24,6 +26,9 @@
 #include <linux/ctype.h>
 #include <linux/kmod.h>
 #include <linux/kdebug.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/ratelimit.h>
 #include <asm/processor.h>
 #include <asm/msr.h>
 #include <asm/mce.h>
@@ -32,7 +37,6 @@
 #include <asm/idle.h>
 
 #define MISC_MCELOG_MINOR 227
-#define NR_SYSFS_BANKS 6
 
 atomic_t mce_entry;
 
@@ -47,7 +51,7 @@ static int mce_dont_init;
  */
 static int tolerant = 1;
 static int banks;
-static unsigned long bank[NR_SYSFS_BANKS] = { [0 ... NR_SYSFS_BANKS-1] = ~0UL };
+static u64 *bank;
 static unsigned long notify_user;
 static int rip_msr;
 static int mce_bootlog = -1;
@@ -58,6 +62,19 @@ static char *trigger_argv[2] = { trigger, NULL };
 
 static DECLARE_WAIT_QUEUE_HEAD(mce_wait);
 
+/* MCA banks polled by the period polling timer for corrected events */
+DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
+       [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL
+};
+
+/* Do initial initialization of a struct mce */
+void mce_setup(struct mce *m)
+{
+       memset(m, 0, sizeof(struct mce));
+       m->cpu = smp_processor_id();
+       rdtscll(m->tsc);
+}
+
 /*
  * Lockless MCE logging infrastructure.
  * This avoids deadlocks on printk locks without having to break locks. Also
@@ -119,11 +136,11 @@ static void print_mce(struct mce *m)
                        print_symbol("{%s}", m->ip);
                printk("\n");
        }
-       printk(KERN_EMERG "TSC %Lx ", m->tsc);
+       printk(KERN_EMERG "TSC %llx ", m->tsc);
        if (m->addr)
-               printk("ADDR %Lx ", m->addr);
+               printk("ADDR %llx ", m->addr);
        if (m->misc)
-               printk("MISC %Lx ", m->misc);
+               printk("MISC %llx ", m->misc);
        printk("\n");
        printk(KERN_EMERG "This is not a software problem!\n");
        printk(KERN_EMERG "Run through mcelog --ascii to decode "
@@ -149,8 +166,10 @@ static void mce_panic(char *msg, struct mce *backup, unsigned long start)
        panic(msg);
 }
 
-static int mce_available(struct cpuinfo_x86 *c)
+int mce_available(struct cpuinfo_x86 *c)
 {
+       if (mce_dont_init)
+               return 0;
        return cpu_has(c, X86_FEATURE_MCE) && cpu_has(c, X86_FEATURE_MCA);
 }
 
@@ -172,7 +191,77 @@ static inline void mce_get_rip(struct mce *m, struct pt_regs *regs)
 }
 
 /*
- * The actual machine check handler
+ * Poll for corrected events or events that happened before reset.
+ * Those are just logged through /dev/mcelog.
+ *
+ * This is executed in standard interrupt context.
+ */
+void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
+{
+       struct mce m;
+       int i;
+
+       mce_setup(&m);
+
+       rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
+       for (i = 0; i < banks; i++) {
+               if (!bank[i] || !test_bit(i, *b))
+                       continue;
+
+               m.misc = 0;
+               m.addr = 0;
+               m.bank = i;
+               m.tsc = 0;
+
+               barrier();
+               rdmsrl(MSR_IA32_MC0_STATUS + i*4, m.status);
+               if (!(m.status & MCI_STATUS_VAL))
+                       continue;
+
+               /*
+                * Uncorrected events are handled by the exception handler
+                * when it is enabled. But when the exception is disabled log
+                * everything.
+                *
+                * TBD do the same check for MCI_STATUS_EN here?
+                */
+               if ((m.status & MCI_STATUS_UC) && !(flags & MCP_UC))
+                       continue;
+
+               if (m.status & MCI_STATUS_MISCV)
+                       rdmsrl(MSR_IA32_MC0_MISC + i*4, m.misc);
+               if (m.status & MCI_STATUS_ADDRV)
+                       rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr);
+
+               if (!(flags & MCP_TIMESTAMP))
+                       m.tsc = 0;
+               /*
+                * Don't get the IP here because it's unlikely to
+                * have anything to do with the actual error location.
+                */
+
+               mce_log(&m);
+               add_taint(TAINT_MACHINE_CHECK);
+
+               /*
+                * Clear state for this bank.
+                */
+               wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
+       }
+
+       /*
+        * Don't clear MCG_STATUS here because it's only defined for
+        * exceptions.
+        */
+}
+
+/*
+ * The actual machine check handler. This only handles real
+ * exceptions when something got corrupted coming in through int 18.
+ *
+ * This is executed in NMI context not subject to normal locking rules. This
+ * implies that most kernel services cannot be safely used. Don't even
+ * think about putting a printk in there!
  */
 void do_machine_check(struct pt_regs * regs, long error_code)
 {
@@ -190,17 +279,18 @@ void do_machine_check(struct pt_regs * regs, long error_code)
         * error.
         */
        int kill_it = 0;
+       DECLARE_BITMAP(toclear, MAX_NR_BANKS);
 
        atomic_inc(&mce_entry);
 
-       if ((regs
-            && notify_die(DIE_NMI, "machine check", regs, error_code,
+       if (notify_die(DIE_NMI, "machine check", regs, error_code,
                           18, SIGKILL) == NOTIFY_STOP)
-           || !banks)
+               goto out2;
+       if (!banks)
                goto out2;
 
-       memset(&m, 0, sizeof(struct mce));
-       m.cpu = smp_processor_id();
+       mce_setup(&m);
+
        rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
        /* if the restart IP is not valid, we're done for */
        if (!(m.mcgstatus & MCG_STATUS_RIPV))
@@ -210,18 +300,32 @@ void do_machine_check(struct pt_regs * regs, long error_code)
        barrier();
 
        for (i = 0; i < banks; i++) {
-               if (i < NR_SYSFS_BANKS && !bank[i])
+               __clear_bit(i, toclear);
+               if (!bank[i])
                        continue;
 
                m.misc = 0;
                m.addr = 0;
                m.bank = i;
-               m.tsc = 0;
 
                rdmsrl(MSR_IA32_MC0_STATUS + i*4, m.status);
                if ((m.status & MCI_STATUS_VAL) == 0)
                        continue;
 
+               /*
+                * Non uncorrected errors are handled by machine_check_poll
+                * Leave them alone.
+                */
+               if ((m.status & MCI_STATUS_UC) == 0)
+                       continue;
+
+               /*
+                * Set taint even when machine check was not enabled.
+                */
+               add_taint(TAINT_MACHINE_CHECK);
+
+               __set_bit(i, toclear);
+
                if (m.status & MCI_STATUS_EN) {
                        /* if PCC was set, there's no way out */
                        no_way_out |= !!(m.status & MCI_STATUS_PCC);
@@ -235,6 +339,12 @@ void do_machine_check(struct pt_regs * regs, long error_code)
                                        no_way_out = 1;
                                kill_it = 1;
                        }
+               } else {
+                       /*
+                        * Machine check event was not enabled. Clear, but
+                        * ignore.
+                        */
+                       continue;
                }
 
                if (m.status & MCI_STATUS_MISCV)
@@ -243,10 +353,7 @@ void do_machine_check(struct pt_regs * regs, long error_code)
                        rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr);
 
                mce_get_rip(&m, regs);
-               if (error_code >= 0)
-                       rdtscll(m.tsc);
-               if (error_code != -2)
-                       mce_log(&m);
+               mce_log(&m);
 
                /* Did this bank cause the exception? */
                /* Assume that the bank with uncorrectable errors did it,
@@ -255,14 +362,8 @@ void do_machine_check(struct pt_regs * regs, long error_code)
                        panicm = m;
                        panicm_found = 1;
                }
-
-               add_taint(TAINT_MACHINE_CHECK);
        }
 
-       /* Never do anything final in the polling timer */
-       if (!regs)
-               goto out;
-
        /* If we didn't find an uncorrectable error, pick
           the last one (shouldn't happen, just being safe). */
        if (!panicm_found)
@@ -309,10 +410,11 @@ void do_machine_check(struct pt_regs * regs, long error_code)
        /* notify userspace ASAP */
        set_thread_flag(TIF_MCE_NOTIFY);
 
- out:
        /* the last thing we do is clear state */
-       for (i = 0; i < banks; i++)
-               wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
+       for (i = 0; i < banks; i++) {
+               if (test_bit(i, toclear))
+                       wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
+       }
        wrmsrl(MSR_IA32_MCG_STATUS, 0);
  out2:
        atomic_dec(&mce_entry);
@@ -332,15 +434,13 @@ void do_machine_check(struct pt_regs * regs, long error_code)
  * and historically has been the register value of the
  * MSR_IA32_THERMAL_STATUS (Intel) msr.
  */
-void mce_log_therm_throt_event(unsigned int cpu, __u64 status)
+void mce_log_therm_throt_event(__u64 status)
 {
        struct mce m;
 
-       memset(&m, 0, sizeof(m));
-       m.cpu = cpu;
+       mce_setup(&m);
        m.bank = MCE_THERMAL_BANK;
        m.status = status;
-       rdtscll(m.tsc);
        mce_log(&m);
 }
 #endif /* CONFIG_X86_MCE_INTEL */
@@ -353,18 +453,18 @@ void mce_log_therm_throt_event(unsigned int cpu, __u64 status)
 
 static int check_interval = 5 * 60; /* 5 minutes */
 static int next_interval; /* in jiffies */
-static void mcheck_timer(struct work_struct *work);
-static DECLARE_DELAYED_WORK(mcheck_work, mcheck_timer);
+static void mcheck_timer(unsigned long);
+static DEFINE_PER_CPU(struct timer_list, mce_timer);
 
-static void mcheck_check_cpu(void *info)
+static void mcheck_timer(unsigned long data)
 {
-       if (mce_available(&current_cpu_data))
-               do_machine_check(NULL, 0);
-}
+       struct timer_list *t = &per_cpu(mce_timer, data);
 
-static void mcheck_timer(struct work_struct *work)
-{
-       on_each_cpu(mcheck_check_cpu, NULL, 1);
+       WARN_ON(smp_processor_id() != data);
+
+       if (mce_available(&current_cpu_data))
+               machine_check_poll(MCP_TIMESTAMP,
+                               &__get_cpu_var(mce_poll_banks));
 
        /*
         * Alert userspace if needed.  If we logged an MCE, reduce the
@@ -377,31 +477,41 @@ static void mcheck_timer(struct work_struct *work)
                                (int)round_jiffies_relative(check_interval*HZ));
        }
 
-       schedule_delayed_work(&mcheck_work, next_interval);
+       t->expires = jiffies + next_interval;
+       add_timer(t);
+}
+
+static void mce_do_trigger(struct work_struct *work)
+{
+       call_usermodehelper(trigger, trigger_argv, NULL, UMH_NO_WAIT);
 }
 
+static DECLARE_WORK(mce_trigger_work, mce_do_trigger);
+
 /*
- * This is only called from process context.  This is where we do
- * anything we need to alert userspace about new MCEs.  This is called
- * directly from the poller and also from entry.S and idle, thanks to
- * TIF_MCE_NOTIFY.
+ * Notify the user(s) about new machine check events.
+ * Can be called from interrupt context, but not from machine check/NMI
+ * context.
  */
 int mce_notify_user(void)
 {
+       /* Not more than two messages every minute */
+       static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2);
+
        clear_thread_flag(TIF_MCE_NOTIFY);
        if (test_and_clear_bit(0, &notify_user)) {
-               static unsigned long last_print;
-               unsigned long now = jiffies;
-
                wake_up_interruptible(&mce_wait);
-               if (trigger[0])
-                       call_usermodehelper(trigger, trigger_argv, NULL,
-                                               UMH_NO_WAIT);
 
-               if (time_after_eq(now, last_print + (check_interval*HZ))) {
-                       last_print = now;
+               /*
+                * There is no risk of missing notifications because
+                * work_pending is always cleared before the function is
+                * executed.
+                */
+               if (trigger[0] && !work_pending(&mce_trigger_work))
+                       schedule_work(&mce_trigger_work);
+
+               if (__ratelimit(&ratelimit))
                        printk(KERN_INFO "Machine check events logged\n");
-               }
 
                return 1;
        }
@@ -425,63 +535,78 @@ static struct notifier_block mce_idle_notifier = {
 
 static __init int periodic_mcheck_init(void)
 {
-       next_interval = check_interval * HZ;
-       if (next_interval)
-               schedule_delayed_work(&mcheck_work,
-                                     round_jiffies_relative(next_interval));
-       idle_notifier_register(&mce_idle_notifier);
-       return 0;
+       idle_notifier_register(&mce_idle_notifier);
+       return 0;
 }
 __initcall(periodic_mcheck_init);
 
-
 /*
  * Initialize Machine Checks for a CPU.
  */
-static void mce_init(void *dummy)
+static int mce_cap_init(void)
 {
        u64 cap;
-       int i;
+       unsigned b;
 
        rdmsrl(MSR_IA32_MCG_CAP, cap);
-       banks = cap & 0xff;
-       if (banks > MCE_EXTENDED_BANK) {
-               banks = MCE_EXTENDED_BANK;
-               printk(KERN_INFO "MCE: warning: using only %d banks\n",
-                      MCE_EXTENDED_BANK);
+       b = cap & 0xff;
+       if (b > MAX_NR_BANKS) {
+               printk(KERN_WARNING
+                      "MCE: Using only %u machine check banks out of %u\n",
+                       MAX_NR_BANKS, b);
+               b = MAX_NR_BANKS;
        }
+
+       /* Don't support asymmetric configurations today */
+       WARN_ON(banks != 0 && b != banks);
+       banks = b;
+       if (!bank) {
+               bank = kmalloc(banks * sizeof(u64), GFP_KERNEL);
+               if (!bank)
+                       return -ENOMEM;
+               memset(bank, 0xff, banks * sizeof(u64));
+       }
+
        /* Use accurate RIP reporting if available. */
        if ((cap & (1<<9)) && ((cap >> 16) & 0xff) >= 9)
                rip_msr = MSR_IA32_MCG_EIP;
 
-       /* Log the machine checks left over from the previous reset.
-          This also clears all registers */
-       do_machine_check(NULL, mce_bootlog ? -1 : -2);
+       return 0;
+}
+
+static void mce_init(void *dummy)
+{
+       u64 cap;
+       int i;
+       mce_banks_t all_banks;
+
+       /*
+        * Log the machine checks left over from the previous reset.
+        */
+       bitmap_fill(all_banks, MAX_NR_BANKS);
+       machine_check_poll(MCP_UC, &all_banks);
 
        set_in_cr4(X86_CR4_MCE);
 
+       rdmsrl(MSR_IA32_MCG_CAP, cap);
        if (cap & MCG_CTL_P)
                wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
 
        for (i = 0; i < banks; i++) {
-               if (i < NR_SYSFS_BANKS)
-                       wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]);
-               else
-                       wrmsrl(MSR_IA32_MC0_CTL+4*i, ~0UL);
-
+               wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]);
                wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
        }
 }
 
 /* Add per CPU specific workarounds here */
-static void __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c)
+static void mce_cpu_quirks(struct cpuinfo_x86 *c)
 {
        /* This should be disabled by the BIOS, but isn't always */
        if (c->x86_vendor == X86_VENDOR_AMD) {
-               if(c->x86 == 15)
+               if (c->x86 == 15 && banks > 4)
                        /* disable GART TBL walk error reporting, which trips off
                           incorrectly with the IOMMU & 3ware & Cerberus. */
-                       clear_bit(10, &bank[4]);
+                       clear_bit(10, (unsigned long *)&bank[4]);
                if(c->x86 <= 17 && mce_bootlog < 0)
                        /* Lots of broken BIOS around that don't clear them
                           by default and leave crap in there. Don't log. */
@@ -504,20 +629,38 @@ static void mce_cpu_features(struct cpuinfo_x86 *c)
        }
 }
 
+static void mce_init_timer(void)
+{
+       struct timer_list *t = &__get_cpu_var(mce_timer);
+
+       /* data race harmless because everyone sets to the same value */
+       if (!next_interval)
+               next_interval = check_interval * HZ;
+       if (!next_interval)
+               return;
+       setup_timer(t, mcheck_timer, smp_processor_id());
+       t->expires = round_jiffies(jiffies + next_interval);
+       add_timer(t);
+}
+
 /*
  * Called for each booted CPU to set up machine checks.
  * Must be called with preempt off.
  */
 void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
 {
-       mce_cpu_quirks(c);
+       if (!mce_available(c))
+               return;
 
-       if (mce_dont_init ||
-           !mce_available(c))
+       if (mce_cap_init() < 0) {
+               mce_dont_init = 1;
                return;
+       }
+       mce_cpu_quirks(c);
 
        mce_init(NULL);
        mce_cpu_features(c);
+       mce_init_timer();
 }
 
 /*
@@ -573,7 +716,7 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize,
 {
        unsigned long *cpu_tsc;
        static DEFINE_MUTEX(mce_read_mutex);
-       unsigned next;
+       unsigned prev, next;
        char __user *buf = ubuf;
        int i, err;
 
@@ -592,25 +735,32 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize,
        }
 
        err = 0;
-       for (i = 0; i < next; i++) {
-               unsigned long start = jiffies;
-
-               while (!mcelog.entry[i].finished) {
-                       if (time_after_eq(jiffies, start + 2)) {
-                               memset(mcelog.entry + i,0, sizeof(struct mce));
-                               goto timeout;
+       prev = 0;
+       do {
+               for (i = prev; i < next; i++) {
+                       unsigned long start = jiffies;
+
+                       while (!mcelog.entry[i].finished) {
+                               if (time_after_eq(jiffies, start + 2)) {
+                                       memset(mcelog.entry + i, 0,
+                                              sizeof(struct mce));
+                                       goto timeout;
+                               }
+                               cpu_relax();
                        }
-                       cpu_relax();
+                       smp_rmb();
+                       err |= copy_to_user(buf, mcelog.entry + i,
+                                           sizeof(struct mce));
+                       buf += sizeof(struct mce);
+timeout:
+                       ;
                }
-               smp_rmb();
-               err |= copy_to_user(buf, mcelog.entry + i, sizeof(struct mce));
-               buf += sizeof(struct mce);
- timeout:
-               ;
-       }
 
-       memset(mcelog.entry, 0, next * sizeof(struct mce));
-       mcelog.next = 0;
+               memset(mcelog.entry + prev, 0,
+                      (next - prev) * sizeof(struct mce));
+               prev = next;
+               next = cmpxchg(&mcelog.next, prev, 0);
+       } while (next != prev);
 
        synchronize_sched();
 
@@ -680,20 +830,6 @@ static struct miscdevice mce_log_device = {
        &mce_chrdev_ops,
 };
 
-static unsigned long old_cr4 __initdata;
-
-void __init stop_mce(void)
-{
-       old_cr4 = read_cr4();
-       clear_in_cr4(X86_CR4_MCE);
-}
-
-void __init restart_mce(void)
-{
-       if (old_cr4 & X86_CR4_MCE)
-               set_in_cr4(X86_CR4_MCE);
-}
-
 /*
  * Old style boot options parsing. Only for compatibility.
  */
@@ -703,8 +839,7 @@ static int __init mcheck_disable(char *str)
        return 1;
 }
 
-/* mce=off disables machine check. Note you can re-enable it later
-   using sysfs.
+/* mce=off disables machine check.
    mce=TOLERANCELEVEL (number, see above)
    mce=bootlog Log MCEs from before booting. Disabled by default on AMD.
    mce=nobootlog Don't log MCEs from before booting. */
@@ -728,6 +863,29 @@ __setup("mce=", mcheck_enable);
  * Sysfs support
  */
 
+/*
+ * Disable machine checks on suspend and shutdown. We can't really handle
+ * them later.
+ */
+static int mce_disable(void)
+{
+       int i;
+
+       for (i = 0; i < banks; i++)
+               wrmsrl(MSR_IA32_MC0_CTL + i*4, 0);
+       return 0;
+}
+
+static int mce_suspend(struct sys_device *dev, pm_message_t state)
+{
+       return mce_disable();
+}
+
+static int mce_shutdown(struct sys_device *dev)
+{
+       return mce_disable();
+}
+
 /* On resume clear all MCE state. Don't want to see leftovers from the BIOS.
    Only one CPU is active at this time, the others get readded later using
    CPU hotplug. */
@@ -738,20 +896,24 @@ static int mce_resume(struct sys_device *dev)
        return 0;
 }
 
+static void mce_cpu_restart(void *data)
+{
+       del_timer_sync(&__get_cpu_var(mce_timer));
+       if (mce_available(&current_cpu_data))
+               mce_init(NULL);
+       mce_init_timer();
+}
+
 /* Reinit MCEs after user configuration changes */
 static void mce_restart(void)
 {
-       if (next_interval)
-               cancel_delayed_work(&mcheck_work);
-       /* Timer race is harmless here */
-       on_each_cpu(mce_init, NULL, 1);
        next_interval = check_interval * HZ;
-       if (next_interval)
-               schedule_delayed_work(&mcheck_work,
-                                     round_jiffies_relative(next_interval));
+       on_each_cpu(mce_cpu_restart, NULL, 1);
 }
 
 static struct sysdev_class mce_sysclass = {
+       .suspend = mce_suspend,
+       .shutdown = mce_shutdown,
        .resume = mce_resume,
        .name = "machinecheck",
 };
@@ -778,16 +940,26 @@ void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu) __cpuinit
        }                                                               \
        static SYSDEV_ATTR(name, 0644, show_ ## name, set_ ## name);
 
-/*
- * TBD should generate these dynamically based on number of available banks.
- * Have only 6 contol banks in /sysfs until then.
- */
-ACCESSOR(bank0ctl,bank[0],mce_restart())
-ACCESSOR(bank1ctl,bank[1],mce_restart())
-ACCESSOR(bank2ctl,bank[2],mce_restart())
-ACCESSOR(bank3ctl,bank[3],mce_restart())
-ACCESSOR(bank4ctl,bank[4],mce_restart())
-ACCESSOR(bank5ctl,bank[5],mce_restart())
+static struct sysdev_attribute *bank_attrs;
+
+static ssize_t show_bank(struct sys_device *s, struct sysdev_attribute *attr,
+                        char *buf)
+{
+       u64 b = bank[attr - bank_attrs];
+       return sprintf(buf, "%llx\n", b);
+}
+
+static ssize_t set_bank(struct sys_device *s, struct sysdev_attribute *attr,
+                       const char *buf, size_t siz)
+{
+       char *end;
+       u64 new = simple_strtoull(buf, &end, 0);
+       if (end == buf)
+               return -EINVAL;
+       bank[attr - bank_attrs] = new;
+       mce_restart();
+       return end-buf;
+}
 
 static ssize_t show_trigger(struct sys_device *s, struct sysdev_attribute *attr,
                                char *buf)
@@ -814,8 +986,6 @@ static SYSDEV_ATTR(trigger, 0644, show_trigger, set_trigger);
 static SYSDEV_INT_ATTR(tolerant, 0644, tolerant);
 ACCESSOR(check_interval,check_interval,mce_restart())
 static struct sysdev_attribute *mce_attributes[] = {
-       &attr_bank0ctl, &attr_bank1ctl, &attr_bank2ctl,
-       &attr_bank3ctl, &attr_bank4ctl, &attr_bank5ctl,
        &attr_tolerant.attr, &attr_check_interval, &attr_trigger,
        NULL
 };
@@ -845,11 +1015,22 @@ static __cpuinit int mce_create_device(unsigned int cpu)
                if (err)
                        goto error;
        }
+       for (i = 0; i < banks; i++) {
+               err = sysdev_create_file(&per_cpu(device_mce, cpu),
+                                       &bank_attrs[i]);
+               if (err)
+                       goto error2;
+       }
        cpu_set(cpu, mce_device_initialized);
 
        return 0;
+error2:
+       while (--i >= 0) {
+               sysdev_remove_file(&per_cpu(device_mce, cpu),
+                                       &bank_attrs[i]);
+       }
 error:
-       while (i--) {
+       while (--i >= 0) {
                sysdev_remove_file(&per_cpu(device_mce,cpu),
                                   mce_attributes[i]);
        }
@@ -868,15 +1049,46 @@ static __cpuinit void mce_remove_device(unsigned int cpu)
        for (i = 0; mce_attributes[i]; i++)
                sysdev_remove_file(&per_cpu(device_mce,cpu),
                        mce_attributes[i]);
+       for (i = 0; i < banks; i++)
+               sysdev_remove_file(&per_cpu(device_mce, cpu),
+                       &bank_attrs[i]);
        sysdev_unregister(&per_cpu(device_mce,cpu));
        cpu_clear(cpu, mce_device_initialized);
 }
 
+/* Make sure there are no machine checks on offlined CPUs. */
+static void mce_disable_cpu(void *h)
+{
+       int i;
+       unsigned long action = *(unsigned long *)h;
+
+       if (!mce_available(&current_cpu_data))
+               return;
+       if (!(action & CPU_TASKS_FROZEN))
+               cmci_clear();
+       for (i = 0; i < banks; i++)
+               wrmsrl(MSR_IA32_MC0_CTL + i*4, 0);
+}
+
+static void mce_reenable_cpu(void *h)
+{
+       int i;
+       unsigned long action = *(unsigned long *)h;
+
+       if (!mce_available(&current_cpu_data))
+               return;
+       if (!(action & CPU_TASKS_FROZEN))
+               cmci_reenable();
+       for (i = 0; i < banks; i++)
+               wrmsrl(MSR_IA32_MC0_CTL + i*4, bank[i]);
+}
+
 /* Get notified when a cpu comes on/off. Be hotplug friendly. */
 static int __cpuinit mce_cpu_callback(struct notifier_block *nfb,
                                      unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
+       struct timer_list *t = &per_cpu(mce_timer, cpu);
 
        switch (action) {
        case CPU_ONLINE:
@@ -891,6 +1103,21 @@ static int __cpuinit mce_cpu_callback(struct notifier_block *nfb,
                        threshold_cpu_callback(action, cpu);
                mce_remove_device(cpu);
                break;
+       case CPU_DOWN_PREPARE:
+       case CPU_DOWN_PREPARE_FROZEN:
+               del_timer_sync(t);
+               smp_call_function_single(cpu, mce_disable_cpu, &action, 1);
+               break;
+       case CPU_DOWN_FAILED:
+       case CPU_DOWN_FAILED_FROZEN:
+               t->expires = round_jiffies(jiffies + next_interval);
+               add_timer_on(t, cpu);
+               smp_call_function_single(cpu, mce_reenable_cpu, &action, 1);
+               break;
+       case CPU_POST_DEAD:
+               /* intentionally ignoring frozen here */
+               cmci_rediscover(cpu);
+               break;
        }
        return NOTIFY_OK;
 }
@@ -899,6 +1126,34 @@ static struct notifier_block mce_cpu_notifier __cpuinitdata = {
        .notifier_call = mce_cpu_callback,
 };
 
+static __init int mce_init_banks(void)
+{
+       int i;
+
+       bank_attrs = kzalloc(sizeof(struct sysdev_attribute) * banks,
+                               GFP_KERNEL);
+       if (!bank_attrs)
+               return -ENOMEM;
+
+       for (i = 0; i < banks; i++) {
+               struct sysdev_attribute *a = &bank_attrs[i];
+               a->attr.name = kasprintf(GFP_KERNEL, "bank%d", i);
+               if (!a->attr.name)
+                       goto nomem;
+               a->attr.mode = 0644;
+               a->show = show_bank;
+               a->store = set_bank;
+       }
+       return 0;
+
+nomem:
+       while (--i >= 0)
+               kfree(bank_attrs[i].attr.name);
+       kfree(bank_attrs);
+       bank_attrs = NULL;
+       return -ENOMEM;
+}
+
 static __init int mce_init_device(void)
 {
        int err;
@@ -906,6 +1161,11 @@ static __init int mce_init_device(void)
 
        if (!mce_available(&boot_cpu_data))
                return -EIO;
+
+       err = mce_init_banks();
+       if (err)
+               return err;
+
        err = sysdev_class_register(&mce_sysclass);
        if (err)
                return err;
index 9817506dd4698c6578646f04100836dd6ad435c8..7d01be868870d1a7922c7ec18fc7a8b666ddb25b 100644 (file)
@@ -79,6 +79,8 @@ static unsigned char shared_bank[NR_BANKS] = {
 
 static DEFINE_PER_CPU(unsigned char, bank_map);        /* see which banks are on */
 
+static void amd_threshold_interrupt(void);
+
 /*
  * CPU Initialization
  */
@@ -90,7 +92,8 @@ struct thresh_restart {
 };
 
 /* must be called with correct cpu affinity */
-static long threshold_restart_bank(void *_tr)
+/* Called via smp_call_function_single() */
+static void threshold_restart_bank(void *_tr)
 {
        struct thresh_restart *tr = _tr;
        u32 mci_misc_hi, mci_misc_lo;
@@ -117,7 +120,6 @@ static long threshold_restart_bank(void *_tr)
 
        mci_misc_hi |= MASK_COUNT_EN_HI;
        wrmsr(tr->b->address, mci_misc_lo, mci_misc_hi);
-       return 0;
 }
 
 /* cpu init entry point, called from mce.c with preempt off */
@@ -174,6 +176,8 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
                        tr.reset = 0;
                        tr.old_limit = 0;
                        threshold_restart_bank(&tr);
+
+                       mce_threshold_vector = amd_threshold_interrupt;
                }
        }
 }
@@ -187,19 +191,13 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
  * the interrupt goes off when error_count reaches threshold_limit.
  * the handler will simply log mcelog w/ software defined bank number.
  */
-asmlinkage void mce_threshold_interrupt(void)
+static void amd_threshold_interrupt(void)
 {
        unsigned int bank, block;
        struct mce m;
        u32 low = 0, high = 0, address = 0;
 
-       ack_APIC_irq();
-       exit_idle();
-       irq_enter();
-
-       memset(&m, 0, sizeof(m));
-       rdtscll(m.tsc);
-       m.cpu = smp_processor_id();
+       mce_setup(&m);
 
        /* assume first bank caused it */
        for (bank = 0; bank < NR_BANKS; ++bank) {
@@ -233,7 +231,8 @@ asmlinkage void mce_threshold_interrupt(void)
 
                        /* Log the machine check that caused the threshold
                           event. */
-                       do_machine_check(NULL, 0);
+                       machine_check_poll(MCP_TIMESTAMP,
+                                       &__get_cpu_var(mce_poll_banks));
 
                        if (high & MASK_OVERFLOW_HI) {
                                rdmsrl(address, m.misc);
@@ -243,13 +242,10 @@ asmlinkage void mce_threshold_interrupt(void)
                                       + bank * NR_BLOCKS
                                       + block;
                                mce_log(&m);
-                               goto out;
+                               return;
                        }
                }
        }
-out:
-       inc_irq_stat(irq_threshold_count);
-       irq_exit();
 }
 
 /*
@@ -283,7 +279,7 @@ static ssize_t store_interrupt_enable(struct threshold_block *b,
        tr.b = b;
        tr.reset = 0;
        tr.old_limit = 0;
-       work_on_cpu(b->cpu, threshold_restart_bank, &tr);
+       smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1);
 
        return end - buf;
 }
@@ -305,23 +301,32 @@ static ssize_t store_threshold_limit(struct threshold_block *b,
        tr.b = b;
        tr.reset = 0;
 
-       work_on_cpu(b->cpu, threshold_restart_bank, &tr);
+       smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1);
 
        return end - buf;
 }
 
-static long local_error_count(void *_b)
+struct threshold_block_cross_cpu {
+       struct threshold_block *tb;
+       long retval;
+};
+
+static void local_error_count_handler(void *_tbcc)
 {
-       struct threshold_block *b = _b;
+       struct threshold_block_cross_cpu *tbcc = _tbcc;
+       struct threshold_block *b = tbcc->tb;
        u32 low, high;
 
        rdmsr(b->address, low, high);
-       return (high & 0xFFF) - (THRESHOLD_MAX - b->threshold_limit);
+       tbcc->retval = (high & 0xFFF) - (THRESHOLD_MAX - b->threshold_limit);
 }
 
 static ssize_t show_error_count(struct threshold_block *b, char *buf)
 {
-       return sprintf(buf, "%lx\n", work_on_cpu(b->cpu, local_error_count, b));
+       struct threshold_block_cross_cpu tbcc = { .tb = b, };
+
+       smp_call_function_single(b->cpu, local_error_count_handler, &tbcc, 1);
+       return sprintf(buf, "%lx\n", tbcc.retval);
 }
 
 static ssize_t store_error_count(struct threshold_block *b,
@@ -329,7 +334,7 @@ static ssize_t store_error_count(struct threshold_block *b,
 {
        struct thresh_restart tr = { .b = b, .reset = 1, .old_limit = 0 };
 
-       work_on_cpu(b->cpu, threshold_restart_bank, &tr);
+       smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1);
        return 1;
 }
 
@@ -398,7 +403,7 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
        if ((bank >= NR_BANKS) || (block >= NR_BLOCKS))
                return 0;
 
-       if (rdmsr_safe(address, &low, &high))
+       if (rdmsr_safe_on_cpu(cpu, address, &low, &high))
                return 0;
 
        if (!(high & MASK_VALID_HI)) {
@@ -462,12 +467,11 @@ out_free:
        return err;
 }
 
-static __cpuinit long local_allocate_threshold_blocks(void *_bank)
+static __cpuinit long
+local_allocate_threshold_blocks(int cpu, unsigned int bank)
 {
-       unsigned int *bank = _bank;
-
-       return allocate_threshold_blocks(smp_processor_id(), *bank, 0,
-                                        MSR_IA32_MC0_MISC + *bank * 4);
+       return allocate_threshold_blocks(cpu, bank, 0,
+                                        MSR_IA32_MC0_MISC + bank * 4);
 }
 
 /* symlinks sibling shared banks to first core.  first core owns dir/files. */
@@ -530,7 +534,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
 
        per_cpu(threshold_banks, cpu)[bank] = b;
 
-       err = work_on_cpu(cpu, local_allocate_threshold_blocks, &bank);
+       err = local_allocate_threshold_blocks(cpu, bank);
        if (err)
                goto out_free;
 
index aa5e287c98e01334565a241d7b89e768c403985f..57df3d383470bb158a7d64bccb7948d45ec9e4ac 100644 (file)
@@ -1,6 +1,8 @@
 /*
  * Intel specific MCE features.
  * Copyright 2004 Zwane Mwaikambo <zwane@linuxpower.ca>
+ * Copyright (C) 2008, 2009 Intel Corporation
+ * Author: Andi Kleen
  */
 
 #include <linux/init.h>
@@ -13,6 +15,7 @@
 #include <asm/hw_irq.h>
 #include <asm/idle.h>
 #include <asm/therm_throt.h>
+#include <asm/apic.h>
 
 asmlinkage void smp_thermal_interrupt(void)
 {
@@ -25,7 +28,7 @@ asmlinkage void smp_thermal_interrupt(void)
 
        rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
        if (therm_throt_process(msr_val & 1))
-               mce_log_therm_throt_event(smp_processor_id(), msr_val);
+               mce_log_therm_throt_event(msr_val);
 
        inc_irq_stat(irq_thermal_count);
        irq_exit();
@@ -85,7 +88,209 @@ static void intel_init_thermal(struct cpuinfo_x86 *c)
        return;
 }
 
+/*
+ * Support for Intel Correct Machine Check Interrupts. This allows
+ * the CPU to raise an interrupt when a corrected machine check happened.
+ * Normally we pick those up using a regular polling timer.
+ * Also supports reliable discovery of shared banks.
+ */
+
+static DEFINE_PER_CPU(mce_banks_t, mce_banks_owned);
+
+/*
+ * cmci_discover_lock protects against parallel discovery attempts
+ * which could race against each other.
+ */
+static DEFINE_SPINLOCK(cmci_discover_lock);
+
+#define CMCI_THRESHOLD 1
+
+static int cmci_supported(int *banks)
+{
+       u64 cap;
+
+       /*
+        * Vendor check is not strictly needed, but the initial
+        * initialization is vendor keyed and this
+        * makes sure none of the backdoors are entered otherwise.
+        */
+       if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+               return 0;
+       if (!cpu_has_apic || lapic_get_maxlvt() < 6)
+               return 0;
+       rdmsrl(MSR_IA32_MCG_CAP, cap);
+       *banks = min_t(unsigned, MAX_NR_BANKS, cap & 0xff);
+       return !!(cap & MCG_CMCI_P);
+}
+
+/*
+ * The interrupt handler. This is called on every event.
+ * Just call the poller directly to log any events.
+ * This could in theory increase the threshold under high load,
+ * but doesn't for now.
+ */
+static void intel_threshold_interrupt(void)
+{
+       machine_check_poll(MCP_TIMESTAMP, &__get_cpu_var(mce_banks_owned));
+       mce_notify_user();
+}
+
+static void print_update(char *type, int *hdr, int num)
+{
+       if (*hdr == 0)
+               printk(KERN_INFO "CPU %d MCA banks", smp_processor_id());
+       *hdr = 1;
+       printk(KERN_CONT " %s:%d", type, num);
+}
+
+/*
+ * Enable CMCI (Corrected Machine Check Interrupt) for available MCE banks
+ * on this CPU. Use the algorithm recommended in the SDM to discover shared
+ * banks.
+ */
+static void cmci_discover(int banks, int boot)
+{
+       unsigned long *owned = (void *)&__get_cpu_var(mce_banks_owned);
+       int hdr = 0;
+       int i;
+
+       spin_lock(&cmci_discover_lock);
+       for (i = 0; i < banks; i++) {
+               u64 val;
+
+               if (test_bit(i, owned))
+                       continue;
+
+               rdmsrl(MSR_IA32_MC0_CTL2 + i, val);
+
+               /* Already owned by someone else? */
+               if (val & CMCI_EN) {
+                       if (test_and_clear_bit(i, owned) || boot)
+                               print_update("SHD", &hdr, i);
+                       __clear_bit(i, __get_cpu_var(mce_poll_banks));
+                       continue;
+               }
+
+               val |= CMCI_EN | CMCI_THRESHOLD;
+               wrmsrl(MSR_IA32_MC0_CTL2 + i, val);
+               rdmsrl(MSR_IA32_MC0_CTL2 + i, val);
+
+               /* Did the enable bit stick? -- the bank supports CMCI */
+               if (val & CMCI_EN) {
+                       if (!test_and_set_bit(i, owned) || boot)
+                               print_update("CMCI", &hdr, i);
+                       __clear_bit(i, __get_cpu_var(mce_poll_banks));
+               } else {
+                       WARN_ON(!test_bit(i, __get_cpu_var(mce_poll_banks)));
+               }
+       }
+       spin_unlock(&cmci_discover_lock);
+       if (hdr)
+               printk(KERN_CONT "\n");
+}
+
+/*
+ * Just in case we missed an event during initialization check
+ * all the CMCI owned banks.
+ */
+void cmci_recheck(void)
+{
+       unsigned long flags;
+       int banks;
+
+       if (!mce_available(&current_cpu_data) || !cmci_supported(&banks))
+               return;
+       local_irq_save(flags);
+       machine_check_poll(MCP_TIMESTAMP, &__get_cpu_var(mce_banks_owned));
+       local_irq_restore(flags);
+}
+
+/*
+ * Disable CMCI on this CPU for all banks it owns when it goes down.
+ * This allows other CPUs to claim the banks on rediscovery.
+ */
+void cmci_clear(void)
+{
+       int i;
+       int banks;
+       u64 val;
+
+       if (!cmci_supported(&banks))
+               return;
+       spin_lock(&cmci_discover_lock);
+       for (i = 0; i < banks; i++) {
+               if (!test_bit(i, __get_cpu_var(mce_banks_owned)))
+                       continue;
+               /* Disable CMCI */
+               rdmsrl(MSR_IA32_MC0_CTL2 + i, val);
+               val &= ~(CMCI_EN|CMCI_THRESHOLD_MASK);
+               wrmsrl(MSR_IA32_MC0_CTL2 + i, val);
+               __clear_bit(i, __get_cpu_var(mce_banks_owned));
+       }
+       spin_unlock(&cmci_discover_lock);
+}
+
+/*
+ * After a CPU went down cycle through all the others and rediscover
+ * Must run in process context.
+ */
+void cmci_rediscover(int dying)
+{
+       int banks;
+       int cpu;
+       cpumask_var_t old;
+
+       if (!cmci_supported(&banks))
+               return;
+       if (!alloc_cpumask_var(&old, GFP_KERNEL))
+               return;
+       cpumask_copy(old, &current->cpus_allowed);
+
+       for_each_online_cpu (cpu) {
+               if (cpu == dying)
+                       continue;
+               if (set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)))
+                       continue;
+               /* Recheck banks in case CPUs don't all have the same */
+               if (cmci_supported(&banks))
+                       cmci_discover(banks, 0);
+       }
+
+       set_cpus_allowed_ptr(current, old);
+       free_cpumask_var(old);
+}
+
+/*
+ * Reenable CMCI on this CPU in case a CPU down failed.
+ */
+void cmci_reenable(void)
+{
+       int banks;
+       if (cmci_supported(&banks))
+               cmci_discover(banks, 0);
+}
+
+static void intel_init_cmci(void)
+{
+       int banks;
+
+       if (!cmci_supported(&banks))
+               return;
+
+       mce_threshold_vector = intel_threshold_interrupt;
+       cmci_discover(banks, 1);
+       /*
+        * For CPU #0 this runs with still disabled APIC, but that's
+        * ok because only the vector is set up. We still do another
+        * check for the banks later for CPU #0 just to make sure
+        * to not miss any events.
+        */
+       apic_write(APIC_LVTCMCI, THRESHOLD_APIC_VECTOR|APIC_DM_FIXED);
+       cmci_recheck();
+}
+
 void mce_intel_feature_init(struct cpuinfo_x86 *c)
 {
        intel_init_thermal(c);
+       intel_init_cmci();
 }
diff --git a/arch/x86/kernel/cpu/mcheck/threshold.c b/arch/x86/kernel/cpu/mcheck/threshold.c
new file mode 100644 (file)
index 0000000..23ee9e7
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Common corrected MCE threshold handler code:
+ */
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+
+#include <asm/irq_vectors.h>
+#include <asm/apic.h>
+#include <asm/idle.h>
+#include <asm/mce.h>
+
+static void default_threshold_interrupt(void)
+{
+       printk(KERN_ERR "Unexpected threshold interrupt at vector %x\n",
+                        THRESHOLD_APIC_VECTOR);
+}
+
+void (*mce_threshold_vector)(void) = default_threshold_interrupt;
+
+asmlinkage void mce_threshold_interrupt(void)
+{
+       exit_idle();
+       irq_enter();
+       inc_irq_stat(irq_threshold_count);
+       mce_threshold_vector();
+       irq_exit();
+       /* Ack only at the end to avoid potential reentry */
+       ack_APIC_irq();
+}
index 191fc05336494bcb30c38c1a3e76d452030cd5d7..f4361b56f8e92efab75d05b1f361f1416d9aec03 100644 (file)
@@ -1,3 +1,3 @@
-obj-y          := main.o if.o generic.o state.o
+obj-y          := main.o if.o generic.o state.o cleanup.o
 obj-$(CONFIG_X86_32) += amd.o cyrix.o centaur.o
 
diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c
new file mode 100644 (file)
index 0000000..ce0fe4b
--- /dev/null
@@ -0,0 +1,1101 @@
+/*  MTRR (Memory Type Range Register) cleanup
+
+    Copyright (C) 2009 Yinghai Lu
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; 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/pci.h>
+#include <linux/smp.h>
+#include <linux/cpu.h>
+#include <linux/mutex.h>
+#include <linux/sort.h>
+
+#include <asm/e820.h>
+#include <asm/mtrr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/kvm_para.h>
+#include "mtrr.h"
+
+/* should be related to MTRR_VAR_RANGES nums */
+#define RANGE_NUM 256
+
+struct res_range {
+       unsigned long start;
+       unsigned long end;
+};
+
+static int __init
+add_range(struct res_range *range, int nr_range, unsigned long start,
+                             unsigned long end)
+{
+       /* out of slots */
+       if (nr_range >= RANGE_NUM)
+               return nr_range;
+
+       range[nr_range].start = start;
+       range[nr_range].end = end;
+
+       nr_range++;
+
+       return nr_range;
+}
+
+static int __init
+add_range_with_merge(struct res_range *range, int nr_range, unsigned long start,
+                             unsigned long end)
+{
+       int i;
+
+       /* try to merge it with old one */
+       for (i = 0; i < nr_range; i++) {
+               unsigned long final_start, final_end;
+               unsigned long common_start, common_end;
+
+               if (!range[i].end)
+                       continue;
+
+               common_start = max(range[i].start, start);
+               common_end = min(range[i].end, end);
+               if (common_start > common_end + 1)
+                       continue;
+
+               final_start = min(range[i].start, start);
+               final_end = max(range[i].end, end);
+
+               range[i].start = final_start;
+               range[i].end =  final_end;
+               return nr_range;
+       }
+
+       /* need to add that */
+       return add_range(range, nr_range, start, end);
+}
+
+static void __init
+subtract_range(struct res_range *range, unsigned long start, unsigned long end)
+{
+       int i, j;
+
+       for (j = 0; j < RANGE_NUM; j++) {
+               if (!range[j].end)
+                       continue;
+
+               if (start <= range[j].start && end >= range[j].end) {
+                       range[j].start = 0;
+                       range[j].end = 0;
+                       continue;
+               }
+
+               if (start <= range[j].start && end < range[j].end &&
+                   range[j].start < end + 1) {
+                       range[j].start = end + 1;
+                       continue;
+               }
+
+
+               if (start > range[j].start && end >= range[j].end &&
+                   range[j].end > start - 1) {
+                       range[j].end = start - 1;
+                       continue;
+               }
+
+               if (start > range[j].start && end < range[j].end) {
+                       /* find the new spare */
+                       for (i = 0; i < RANGE_NUM; i++) {
+                               if (range[i].end == 0)
+                                       break;
+                       }
+                       if (i < RANGE_NUM) {
+                               range[i].end = range[j].end;
+                               range[i].start = end + 1;
+                       } else {
+                               printk(KERN_ERR "run of slot in ranges\n");
+                       }
+                       range[j].end = start - 1;
+                       continue;
+               }
+       }
+}
+
+static int __init cmp_range(const void *x1, const void *x2)
+{
+       const struct res_range *r1 = x1;
+       const struct res_range *r2 = x2;
+       long start1, start2;
+
+       start1 = r1->start;
+       start2 = r2->start;
+
+       return start1 - start2;
+}
+
+struct var_mtrr_range_state {
+       unsigned long base_pfn;
+       unsigned long size_pfn;
+       mtrr_type type;
+};
+
+static struct var_mtrr_range_state __initdata range_state[RANGE_NUM];
+static int __initdata debug_print;
+
+static int __init
+x86_get_mtrr_mem_range(struct res_range *range, int nr_range,
+                      unsigned long extra_remove_base,
+                      unsigned long extra_remove_size)
+{
+       unsigned long base, size;
+       mtrr_type type;
+       int i;
+
+       for (i = 0; i < num_var_ranges; i++) {
+               type = range_state[i].type;
+               if (type != MTRR_TYPE_WRBACK)
+                       continue;
+               base = range_state[i].base_pfn;
+               size = range_state[i].size_pfn;
+               nr_range = add_range_with_merge(range, nr_range, base,
+                                               base + size - 1);
+       }
+       if (debug_print) {
+               printk(KERN_DEBUG "After WB checking\n");
+               for (i = 0; i < nr_range; i++)
+                       printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
+                                range[i].start, range[i].end + 1);
+       }
+
+       /* take out UC ranges */
+       for (i = 0; i < num_var_ranges; i++) {
+               type = range_state[i].type;
+               if (type != MTRR_TYPE_UNCACHABLE &&
+                   type != MTRR_TYPE_WRPROT)
+                       continue;
+               size = range_state[i].size_pfn;
+               if (!size)
+                       continue;
+               base = range_state[i].base_pfn;
+               if (base < (1<<(20-PAGE_SHIFT)) && mtrr_state.have_fixed &&
+                   (mtrr_state.enabled & 1)) {
+                       /* Var MTRR contains UC entry below 1M? Skip it: */
+                       printk(KERN_WARNING "WARNING: BIOS bug: VAR MTRR %d "
+                               "contains strange UC entry under 1M, check "
+                               "with your system vendor!\n", i);
+                       if (base + size <= (1<<(20-PAGE_SHIFT)))
+                               continue;
+                       size -= (1<<(20-PAGE_SHIFT)) - base;
+                       base = 1<<(20-PAGE_SHIFT);
+               }
+               subtract_range(range, base, base + size - 1);
+       }
+       if (extra_remove_size)
+               subtract_range(range, extra_remove_base,
+                                extra_remove_base + extra_remove_size  - 1);
+
+       /* get new range num */
+       nr_range = 0;
+       for (i = 0; i < RANGE_NUM; i++) {
+               if (!range[i].end)
+                       continue;
+               nr_range++;
+       }
+       if  (debug_print) {
+               printk(KERN_DEBUG "After UC checking\n");
+               for (i = 0; i < nr_range; i++)
+                       printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
+                                range[i].start, range[i].end + 1);
+       }
+
+       /* sort the ranges */
+       sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
+       if  (debug_print) {
+               printk(KERN_DEBUG "After sorting\n");
+               for (i = 0; i < nr_range; i++)
+                       printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
+                                range[i].start, range[i].end + 1);
+       }
+
+       /* clear those is not used */
+       for (i = nr_range; i < RANGE_NUM; i++)
+               memset(&range[i], 0, sizeof(range[i]));
+
+       return nr_range;
+}
+
+static struct res_range __initdata range[RANGE_NUM];
+static int __initdata nr_range;
+
+#ifdef CONFIG_MTRR_SANITIZER
+
+static unsigned long __init sum_ranges(struct res_range *range, int nr_range)
+{
+       unsigned long sum;
+       int i;
+
+       sum = 0;
+       for (i = 0; i < nr_range; i++)
+               sum += range[i].end + 1 - range[i].start;
+
+       return sum;
+}
+
+static int enable_mtrr_cleanup __initdata =
+       CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT;
+
+static int __init disable_mtrr_cleanup_setup(char *str)
+{
+       enable_mtrr_cleanup = 0;
+       return 0;
+}
+early_param("disable_mtrr_cleanup", disable_mtrr_cleanup_setup);
+
+static int __init enable_mtrr_cleanup_setup(char *str)
+{
+       enable_mtrr_cleanup = 1;
+       return 0;
+}
+early_param("enable_mtrr_cleanup", enable_mtrr_cleanup_setup);
+
+static int __init mtrr_cleanup_debug_setup(char *str)
+{
+       debug_print = 1;
+       return 0;
+}
+early_param("mtrr_cleanup_debug", mtrr_cleanup_debug_setup);
+
+struct var_mtrr_state {
+       unsigned long   range_startk;
+       unsigned long   range_sizek;
+       unsigned long   chunk_sizek;
+       unsigned long   gran_sizek;
+       unsigned int    reg;
+};
+
+static void __init
+set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
+               unsigned char type, unsigned int address_bits)
+{
+       u32 base_lo, base_hi, mask_lo, mask_hi;
+       u64 base, mask;
+
+       if (!sizek) {
+               fill_mtrr_var_range(reg, 0, 0, 0, 0);
+               return;
+       }
+
+       mask = (1ULL << address_bits) - 1;
+       mask &= ~((((u64)sizek) << 10) - 1);
+
+       base  = ((u64)basek) << 10;
+
+       base |= type;
+       mask |= 0x800;
+
+       base_lo = base & ((1ULL<<32) - 1);
+       base_hi = base >> 32;
+
+       mask_lo = mask & ((1ULL<<32) - 1);
+       mask_hi = mask >> 32;
+
+       fill_mtrr_var_range(reg, base_lo, base_hi, mask_lo, mask_hi);
+}
+
+static void __init
+save_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
+               unsigned char type)
+{
+       range_state[reg].base_pfn = basek >> (PAGE_SHIFT - 10);
+       range_state[reg].size_pfn = sizek >> (PAGE_SHIFT - 10);
+       range_state[reg].type = type;
+}
+
+static void __init
+set_var_mtrr_all(unsigned int address_bits)
+{
+       unsigned long basek, sizek;
+       unsigned char type;
+       unsigned int reg;
+
+       for (reg = 0; reg < num_var_ranges; reg++) {
+               basek = range_state[reg].base_pfn << (PAGE_SHIFT - 10);
+               sizek = range_state[reg].size_pfn << (PAGE_SHIFT - 10);
+               type = range_state[reg].type;
+
+               set_var_mtrr(reg, basek, sizek, type, address_bits);
+       }
+}
+
+static unsigned long to_size_factor(unsigned long sizek, char *factorp)
+{
+       char factor;
+       unsigned long base = sizek;
+
+       if (base & ((1<<10) - 1)) {
+               /* not MB alignment */
+               factor = 'K';
+       } else if (base & ((1<<20) - 1)) {
+               factor = 'M';
+               base >>= 10;
+       } else {
+               factor = 'G';
+               base >>= 20;
+       }
+
+       *factorp = factor;
+
+       return base;
+}
+
+static unsigned int __init
+range_to_mtrr(unsigned int reg, unsigned long range_startk,
+             unsigned long range_sizek, unsigned char type)
+{
+       if (!range_sizek || (reg >= num_var_ranges))
+               return reg;
+
+       while (range_sizek) {
+               unsigned long max_align, align;
+               unsigned long sizek;
+
+               /* Compute the maximum size I can make a range */
+               if (range_startk)
+                       max_align = ffs(range_startk) - 1;
+               else
+                       max_align = 32;
+               align = fls(range_sizek) - 1;
+               if (align > max_align)
+                       align = max_align;
+
+               sizek = 1 << align;
+               if (debug_print) {
+                       char start_factor = 'K', size_factor = 'K';
+                       unsigned long start_base, size_base;
+
+                       start_base = to_size_factor(range_startk,
+                                                        &start_factor),
+                       size_base = to_size_factor(sizek, &size_factor),
+
+                       printk(KERN_DEBUG "Setting variable MTRR %d, "
+                               "base: %ld%cB, range: %ld%cB, type %s\n",
+                               reg, start_base, start_factor,
+                               size_base, size_factor,
+                               (type == MTRR_TYPE_UNCACHABLE) ? "UC" :
+                                  ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other")
+                               );
+               }
+               save_var_mtrr(reg++, range_startk, sizek, type);
+               range_startk += sizek;
+               range_sizek -= sizek;
+               if (reg >= num_var_ranges)
+                       break;
+       }
+       return reg;
+}
+
+static unsigned __init
+range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek,
+                       unsigned long sizek)
+{
+       unsigned long hole_basek, hole_sizek;
+       unsigned long second_basek, second_sizek;
+       unsigned long range0_basek, range0_sizek;
+       unsigned long range_basek, range_sizek;
+       unsigned long chunk_sizek;
+       unsigned long gran_sizek;
+
+       hole_basek = 0;
+       hole_sizek = 0;
+       second_basek = 0;
+       second_sizek = 0;
+       chunk_sizek = state->chunk_sizek;
+       gran_sizek = state->gran_sizek;
+
+       /* align with gran size, prevent small block used up MTRRs */
+       range_basek = ALIGN(state->range_startk, gran_sizek);
+       if ((range_basek > basek) && basek)
+               return second_sizek;
+       state->range_sizek -= (range_basek - state->range_startk);
+       range_sizek = ALIGN(state->range_sizek, gran_sizek);
+
+       while (range_sizek > state->range_sizek) {
+               range_sizek -= gran_sizek;
+               if (!range_sizek)
+                       return 0;
+       }
+       state->range_sizek = range_sizek;
+
+       /* try to append some small hole */
+       range0_basek = state->range_startk;
+       range0_sizek = ALIGN(state->range_sizek, chunk_sizek);
+
+       /* no increase */
+       if (range0_sizek == state->range_sizek) {
+               if (debug_print)
+                       printk(KERN_DEBUG "rangeX: %016lx - %016lx\n",
+                               range0_basek<<10,
+                               (range0_basek + state->range_sizek)<<10);
+               state->reg = range_to_mtrr(state->reg, range0_basek,
+                               state->range_sizek, MTRR_TYPE_WRBACK);
+               return 0;
+       }
+
+       /* only cut back, when it is not the last */
+       if (sizek) {
+               while (range0_basek + range0_sizek > (basek + sizek)) {
+                       if (range0_sizek >= chunk_sizek)
+                               range0_sizek -= chunk_sizek;
+                       else
+                               range0_sizek = 0;
+
+                       if (!range0_sizek)
+                               break;
+               }
+       }
+
+second_try:
+       range_basek = range0_basek + range0_sizek;
+
+       /* one hole in the middle */
+       if (range_basek > basek && range_basek <= (basek + sizek))
+               second_sizek = range_basek - basek;
+
+       if (range0_sizek > state->range_sizek) {
+
+               /* one hole in middle or at end */
+               hole_sizek = range0_sizek - state->range_sizek - second_sizek;
+
+               /* hole size should be less than half of range0 size */
+               if (hole_sizek >= (range0_sizek >> 1) &&
+                   range0_sizek >= chunk_sizek) {
+                       range0_sizek -= chunk_sizek;
+                       second_sizek = 0;
+                       hole_sizek = 0;
+
+                       goto second_try;
+               }
+       }
+
+       if (range0_sizek) {
+               if (debug_print)
+                       printk(KERN_DEBUG "range0: %016lx - %016lx\n",
+                               range0_basek<<10,
+                               (range0_basek + range0_sizek)<<10);
+               state->reg = range_to_mtrr(state->reg, range0_basek,
+                               range0_sizek, MTRR_TYPE_WRBACK);
+       }
+
+       if (range0_sizek < state->range_sizek) {
+               /* need to handle left over */
+               range_sizek = state->range_sizek - range0_sizek;
+
+               if (debug_print)
+                       printk(KERN_DEBUG "range: %016lx - %016lx\n",
+                                range_basek<<10,
+                                (range_basek + range_sizek)<<10);
+               state->reg = range_to_mtrr(state->reg, range_basek,
+                                range_sizek, MTRR_TYPE_WRBACK);
+       }
+
+       if (hole_sizek) {
+               hole_basek = range_basek - hole_sizek - second_sizek;
+               if (debug_print)
+                       printk(KERN_DEBUG "hole: %016lx - %016lx\n",
+                                hole_basek<<10,
+                                (hole_basek + hole_sizek)<<10);
+               state->reg = range_to_mtrr(state->reg, hole_basek,
+                                hole_sizek, MTRR_TYPE_UNCACHABLE);
+       }
+
+       return second_sizek;
+}
+
+static void __init
+set_var_mtrr_range(struct var_mtrr_state *state, unsigned long base_pfn,
+                  unsigned long size_pfn)
+{
+       unsigned long basek, sizek;
+       unsigned long second_sizek = 0;
+
+       if (state->reg >= num_var_ranges)
+               return;
+
+       basek = base_pfn << (PAGE_SHIFT - 10);
+       sizek = size_pfn << (PAGE_SHIFT - 10);
+
+       /* See if I can merge with the last range */
+       if ((basek <= 1024) ||
+           (state->range_startk + state->range_sizek == basek)) {
+               unsigned long endk = basek + sizek;
+               state->range_sizek = endk - state->range_startk;
+               return;
+       }
+       /* Write the range mtrrs */
+       if (state->range_sizek != 0)
+               second_sizek = range_to_mtrr_with_hole(state, basek, sizek);
+
+       /* Allocate an msr */
+       state->range_startk = basek + second_sizek;
+       state->range_sizek  = sizek - second_sizek;
+}
+
+/* mininum size of mtrr block that can take hole */
+static u64 mtrr_chunk_size __initdata = (256ULL<<20);
+
+static int __init parse_mtrr_chunk_size_opt(char *p)
+{
+       if (!p)
+               return -EINVAL;
+       mtrr_chunk_size = memparse(p, &p);
+       return 0;
+}
+early_param("mtrr_chunk_size", parse_mtrr_chunk_size_opt);
+
+/* granity of mtrr of block */
+static u64 mtrr_gran_size __initdata;
+
+static int __init parse_mtrr_gran_size_opt(char *p)
+{
+       if (!p)
+               return -EINVAL;
+       mtrr_gran_size = memparse(p, &p);
+       return 0;
+}
+early_param("mtrr_gran_size", parse_mtrr_gran_size_opt);
+
+static int nr_mtrr_spare_reg __initdata =
+                                CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT;
+
+static int __init parse_mtrr_spare_reg(char *arg)
+{
+       if (arg)
+               nr_mtrr_spare_reg = simple_strtoul(arg, NULL, 0);
+       return 0;
+}
+
+early_param("mtrr_spare_reg_nr", parse_mtrr_spare_reg);
+
+static int __init
+x86_setup_var_mtrrs(struct res_range *range, int nr_range,
+                   u64 chunk_size, u64 gran_size)
+{
+       struct var_mtrr_state var_state;
+       int i;
+       int num_reg;
+
+       var_state.range_startk  = 0;
+       var_state.range_sizek   = 0;
+       var_state.reg           = 0;
+       var_state.chunk_sizek   = chunk_size >> 10;
+       var_state.gran_sizek    = gran_size >> 10;
+
+       memset(range_state, 0, sizeof(range_state));
+
+       /* Write the range etc */
+       for (i = 0; i < nr_range; i++)
+               set_var_mtrr_range(&var_state, range[i].start,
+                                  range[i].end - range[i].start + 1);
+
+       /* Write the last range */
+       if (var_state.range_sizek != 0)
+               range_to_mtrr_with_hole(&var_state, 0, 0);
+
+       num_reg = var_state.reg;
+       /* Clear out the extra MTRR's */
+       while (var_state.reg < num_var_ranges) {
+               save_var_mtrr(var_state.reg, 0, 0, 0);
+               var_state.reg++;
+       }
+
+       return num_reg;
+}
+
+struct mtrr_cleanup_result {
+       unsigned long gran_sizek;
+       unsigned long chunk_sizek;
+       unsigned long lose_cover_sizek;
+       unsigned int num_reg;
+       int bad;
+};
+
+/*
+ * gran_size: 64K, 128K, 256K, 512K, 1M, 2M, ..., 2G
+ * chunk size: gran_size, ..., 2G
+ * so we need (1+16)*8
+ */
+#define NUM_RESULT     136
+#define PSHIFT         (PAGE_SHIFT - 10)
+
+static struct mtrr_cleanup_result __initdata result[NUM_RESULT];
+static unsigned long __initdata min_loss_pfn[RANGE_NUM];
+
+static void __init print_out_mtrr_range_state(void)
+{
+       int i;
+       char start_factor = 'K', size_factor = 'K';
+       unsigned long start_base, size_base;
+       mtrr_type type;
+
+       for (i = 0; i < num_var_ranges; i++) {
+
+               size_base = range_state[i].size_pfn << (PAGE_SHIFT - 10);
+               if (!size_base)
+                       continue;
+
+               size_base = to_size_factor(size_base, &size_factor),
+               start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10);
+               start_base = to_size_factor(start_base, &start_factor),
+               type = range_state[i].type;
+
+               printk(KERN_DEBUG "reg %d, base: %ld%cB, range: %ld%cB, type %s\n",
+                       i, start_base, start_factor,
+                       size_base, size_factor,
+                       (type == MTRR_TYPE_UNCACHABLE) ? "UC" :
+                           ((type == MTRR_TYPE_WRPROT) ? "WP" :
+                            ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other"))
+                       );
+       }
+}
+
+static int __init mtrr_need_cleanup(void)
+{
+       int i;
+       mtrr_type type;
+       unsigned long size;
+       /* extra one for all 0 */
+       int num[MTRR_NUM_TYPES + 1];
+
+       /* check entries number */
+       memset(num, 0, sizeof(num));
+       for (i = 0; i < num_var_ranges; i++) {
+               type = range_state[i].type;
+               size = range_state[i].size_pfn;
+               if (type >= MTRR_NUM_TYPES)
+                       continue;
+               if (!size)
+                       type = MTRR_NUM_TYPES;
+               if (type == MTRR_TYPE_WRPROT)
+                       type = MTRR_TYPE_UNCACHABLE;
+               num[type]++;
+       }
+
+       /* check if we got UC entries */
+       if (!num[MTRR_TYPE_UNCACHABLE])
+               return 0;
+
+       /* check if we only had WB and UC */
+       if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
+               num_var_ranges - num[MTRR_NUM_TYPES])
+               return 0;
+
+       return 1;
+}
+
+static unsigned long __initdata range_sums;
+static void __init mtrr_calc_range_state(u64 chunk_size, u64 gran_size,
+                                        unsigned long extra_remove_base,
+                                        unsigned long extra_remove_size,
+                                        int i)
+{
+       int num_reg;
+       static struct res_range range_new[RANGE_NUM];
+       static int nr_range_new;
+       unsigned long range_sums_new;
+
+       /* convert ranges to var ranges state */
+       num_reg = x86_setup_var_mtrrs(range, nr_range,
+                                               chunk_size, gran_size);
+
+       /* we got new setting in range_state, check it */
+       memset(range_new, 0, sizeof(range_new));
+       nr_range_new = x86_get_mtrr_mem_range(range_new, 0,
+                               extra_remove_base, extra_remove_size);
+       range_sums_new = sum_ranges(range_new, nr_range_new);
+
+       result[i].chunk_sizek = chunk_size >> 10;
+       result[i].gran_sizek = gran_size >> 10;
+       result[i].num_reg = num_reg;
+       if (range_sums < range_sums_new) {
+               result[i].lose_cover_sizek =
+                       (range_sums_new - range_sums) << PSHIFT;
+               result[i].bad = 1;
+       } else
+               result[i].lose_cover_sizek =
+                       (range_sums - range_sums_new) << PSHIFT;
+
+       /* double check it */
+       if (!result[i].bad && !result[i].lose_cover_sizek) {
+               if (nr_range_new != nr_range ||
+                       memcmp(range, range_new, sizeof(range)))
+                               result[i].bad = 1;
+       }
+
+       if (!result[i].bad && (range_sums - range_sums_new <
+                               min_loss_pfn[num_reg])) {
+               min_loss_pfn[num_reg] =
+                       range_sums - range_sums_new;
+       }
+}
+
+static void __init mtrr_print_out_one_result(int i)
+{
+       char gran_factor, chunk_factor, lose_factor;
+       unsigned long gran_base, chunk_base, lose_base;
+
+       gran_base = to_size_factor(result[i].gran_sizek, &gran_factor),
+       chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor),
+       lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor),
+       printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t",
+                       result[i].bad ? "*BAD*" : " ",
+                       gran_base, gran_factor, chunk_base, chunk_factor);
+       printk(KERN_CONT "num_reg: %d  \tlose cover RAM: %s%ld%c\n",
+                       result[i].num_reg, result[i].bad ? "-" : "",
+                       lose_base, lose_factor);
+}
+
+static int __init mtrr_search_optimal_index(void)
+{
+       int i;
+       int num_reg_good;
+       int index_good;
+
+       if (nr_mtrr_spare_reg >= num_var_ranges)
+               nr_mtrr_spare_reg = num_var_ranges - 1;
+       num_reg_good = -1;
+       for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) {
+               if (!min_loss_pfn[i])
+                       num_reg_good = i;
+       }
+
+       index_good = -1;
+       if (num_reg_good != -1) {
+               for (i = 0; i < NUM_RESULT; i++) {
+                       if (!result[i].bad &&
+                           result[i].num_reg == num_reg_good &&
+                           !result[i].lose_cover_sizek) {
+                               index_good = i;
+                               break;
+                       }
+               }
+       }
+
+       return index_good;
+}
+
+
+int __init mtrr_cleanup(unsigned address_bits)
+{
+       unsigned long extra_remove_base, extra_remove_size;
+       unsigned long base, size, def, dummy;
+       mtrr_type type;
+       u64 chunk_size, gran_size;
+       int index_good;
+       int i;
+
+       if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1)
+               return 0;
+       rdmsr(MTRRdefType_MSR, def, dummy);
+       def &= 0xff;
+       if (def != MTRR_TYPE_UNCACHABLE)
+               return 0;
+
+       /* get it and store it aside */
+       memset(range_state, 0, sizeof(range_state));
+       for (i = 0; i < num_var_ranges; i++) {
+               mtrr_if->get(i, &base, &size, &type);
+               range_state[i].base_pfn = base;
+               range_state[i].size_pfn = size;
+               range_state[i].type = type;
+       }
+
+       /* check if we need handle it and can handle it */
+       if (!mtrr_need_cleanup())
+               return 0;
+
+       /* print original var MTRRs at first, for debugging: */
+       printk(KERN_DEBUG "original variable MTRRs\n");
+       print_out_mtrr_range_state();
+
+       memset(range, 0, sizeof(range));
+       extra_remove_size = 0;
+       extra_remove_base = 1 << (32 - PAGE_SHIFT);
+       if (mtrr_tom2)
+               extra_remove_size =
+                       (mtrr_tom2 >> PAGE_SHIFT) - extra_remove_base;
+       nr_range = x86_get_mtrr_mem_range(range, 0, extra_remove_base,
+                                         extra_remove_size);
+       /*
+        * [0, 1M) should always be coverred by var mtrr with WB
+        * and fixed mtrrs should take effective before var mtrr for it
+        */
+       nr_range = add_range_with_merge(range, nr_range, 0,
+                                       (1ULL<<(20 - PAGE_SHIFT)) - 1);
+       /* sort the ranges */
+       sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
+
+       range_sums = sum_ranges(range, nr_range);
+       printk(KERN_INFO "total RAM coverred: %ldM\n",
+              range_sums >> (20 - PAGE_SHIFT));
+
+       if (mtrr_chunk_size && mtrr_gran_size) {
+               i = 0;
+               mtrr_calc_range_state(mtrr_chunk_size, mtrr_gran_size,
+                                     extra_remove_base, extra_remove_size, i);
+
+               mtrr_print_out_one_result(i);
+
+               if (!result[i].bad) {
+                       set_var_mtrr_all(address_bits);
+                       printk(KERN_DEBUG "New variable MTRRs\n");
+                       print_out_mtrr_range_state();
+                       return 1;
+               }
+               printk(KERN_INFO "invalid mtrr_gran_size or mtrr_chunk_size, "
+                      "will find optimal one\n");
+       }
+
+       i = 0;
+       memset(min_loss_pfn, 0xff, sizeof(min_loss_pfn));
+       memset(result, 0, sizeof(result));
+       for (gran_size = (1ULL<<16); gran_size < (1ULL<<32); gran_size <<= 1) {
+
+               for (chunk_size = gran_size; chunk_size < (1ULL<<32);
+                    chunk_size <<= 1) {
+
+                       if (i >= NUM_RESULT)
+                               continue;
+
+                       mtrr_calc_range_state(chunk_size, gran_size,
+                                     extra_remove_base, extra_remove_size, i);
+                       if (debug_print) {
+                               mtrr_print_out_one_result(i);
+                               printk(KERN_INFO "\n");
+                       }
+
+                       i++;
+               }
+       }
+
+       /* try to find the optimal index */
+       index_good = mtrr_search_optimal_index();
+
+       if (index_good != -1) {
+               printk(KERN_INFO "Found optimal setting for mtrr clean up\n");
+               i = index_good;
+               mtrr_print_out_one_result(i);
+
+               /* convert ranges to var ranges state */
+               chunk_size = result[i].chunk_sizek;
+               chunk_size <<= 10;
+               gran_size = result[i].gran_sizek;
+               gran_size <<= 10;
+               x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size);
+               set_var_mtrr_all(address_bits);
+               printk(KERN_DEBUG "New variable MTRRs\n");
+               print_out_mtrr_range_state();
+               return 1;
+       } else {
+               /* print out all */
+               for (i = 0; i < NUM_RESULT; i++)
+                       mtrr_print_out_one_result(i);
+       }
+
+       printk(KERN_INFO "mtrr_cleanup: can not find optimal value\n");
+       printk(KERN_INFO "please specify mtrr_gran_size/mtrr_chunk_size\n");
+
+       return 0;
+}
+#else
+int __init mtrr_cleanup(unsigned address_bits)
+{
+       return 0;
+}
+#endif
+
+static int disable_mtrr_trim;
+
+static int __init disable_mtrr_trim_setup(char *str)
+{
+       disable_mtrr_trim = 1;
+       return 0;
+}
+early_param("disable_mtrr_trim", disable_mtrr_trim_setup);
+
+/*
+ * Newer AMD K8s and later CPUs have a special magic MSR way to force WB
+ * for memory >4GB. Check for that here.
+ * Note this won't check if the MTRRs < 4GB where the magic bit doesn't
+ * apply to are wrong, but so far we don't know of any such case in the wild.
+ */
+#define Tom2Enabled (1U << 21)
+#define Tom2ForceMemTypeWB (1U << 22)
+
+int __init amd_special_default_mtrr(void)
+{
+       u32 l, h;
+
+       if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+               return 0;
+       if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11)
+               return 0;
+       /* In case some hypervisor doesn't pass SYSCFG through */
+       if (rdmsr_safe(MSR_K8_SYSCFG, &l, &h) < 0)
+               return 0;
+       /*
+        * Memory between 4GB and top of mem is forced WB by this magic bit.
+        * Reserved before K8RevF, but should be zero there.
+        */
+       if ((l & (Tom2Enabled | Tom2ForceMemTypeWB)) ==
+                (Tom2Enabled | Tom2ForceMemTypeWB))
+               return 1;
+       return 0;
+}
+
+static u64 __init real_trim_memory(unsigned long start_pfn,
+                                  unsigned long limit_pfn)
+{
+       u64 trim_start, trim_size;
+       trim_start = start_pfn;
+       trim_start <<= PAGE_SHIFT;
+       trim_size = limit_pfn;
+       trim_size <<= PAGE_SHIFT;
+       trim_size -= trim_start;
+
+       return e820_update_range(trim_start, trim_size, E820_RAM,
+                               E820_RESERVED);
+}
+/**
+ * mtrr_trim_uncached_memory - trim RAM not covered by MTRRs
+ * @end_pfn: ending page frame number
+ *
+ * Some buggy BIOSes don't setup the MTRRs properly for systems with certain
+ * memory configurations.  This routine checks that the highest MTRR matches
+ * the end of memory, to make sure the MTRRs having a write back type cover
+ * all of the memory the kernel is intending to use. If not, it'll trim any
+ * memory off the end by adjusting end_pfn, removing it from the kernel's
+ * allocation pools, warning the user with an obnoxious message.
+ */
+int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
+{
+       unsigned long i, base, size, highest_pfn = 0, def, dummy;
+       mtrr_type type;
+       u64 total_trim_size;
+
+       /* extra one for all 0 */
+       int num[MTRR_NUM_TYPES + 1];
+       /*
+        * Make sure we only trim uncachable memory on machines that
+        * support the Intel MTRR architecture:
+        */
+       if (!is_cpu(INTEL) || disable_mtrr_trim)
+               return 0;
+       rdmsr(MTRRdefType_MSR, def, dummy);
+       def &= 0xff;
+       if (def != MTRR_TYPE_UNCACHABLE)
+               return 0;
+
+       /* get it and store it aside */
+       memset(range_state, 0, sizeof(range_state));
+       for (i = 0; i < num_var_ranges; i++) {
+               mtrr_if->get(i, &base, &size, &type);
+               range_state[i].base_pfn = base;
+               range_state[i].size_pfn = size;
+               range_state[i].type = type;
+       }
+
+       /* Find highest cached pfn */
+       for (i = 0; i < num_var_ranges; i++) {
+               type = range_state[i].type;
+               if (type != MTRR_TYPE_WRBACK)
+                       continue;
+               base = range_state[i].base_pfn;
+               size = range_state[i].size_pfn;
+               if (highest_pfn < base + size)
+                       highest_pfn = base + size;
+       }
+
+       /* kvm/qemu doesn't have mtrr set right, don't trim them all */
+       if (!highest_pfn) {
+               printk(KERN_INFO "CPU MTRRs all blank - virtualized system.\n");
+               return 0;
+       }
+
+       /* check entries number */
+       memset(num, 0, sizeof(num));
+       for (i = 0; i < num_var_ranges; i++) {
+               type = range_state[i].type;
+               if (type >= MTRR_NUM_TYPES)
+                       continue;
+               size = range_state[i].size_pfn;
+               if (!size)
+                       type = MTRR_NUM_TYPES;
+               num[type]++;
+       }
+
+       /* no entry for WB? */
+       if (!num[MTRR_TYPE_WRBACK])
+               return 0;
+
+       /* check if we only had WB and UC */
+       if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
+               num_var_ranges - num[MTRR_NUM_TYPES])
+               return 0;
+
+       memset(range, 0, sizeof(range));
+       nr_range = 0;
+       if (mtrr_tom2) {
+               range[nr_range].start = (1ULL<<(32 - PAGE_SHIFT));
+               range[nr_range].end = (mtrr_tom2 >> PAGE_SHIFT) - 1;
+               if (highest_pfn < range[nr_range].end + 1)
+                       highest_pfn = range[nr_range].end + 1;
+               nr_range++;
+       }
+       nr_range = x86_get_mtrr_mem_range(range, nr_range, 0, 0);
+
+       total_trim_size = 0;
+       /* check the head */
+       if (range[0].start)
+               total_trim_size += real_trim_memory(0, range[0].start);
+       /* check the holes */
+       for (i = 0; i < nr_range - 1; i++) {
+               if (range[i].end + 1 < range[i+1].start)
+                       total_trim_size += real_trim_memory(range[i].end + 1,
+                                                           range[i+1].start);
+       }
+       /* check the top */
+       i = nr_range - 1;
+       if (range[i].end + 1 < end_pfn)
+               total_trim_size += real_trim_memory(range[i].end + 1,
+                                                        end_pfn);
+
+       if (total_trim_size) {
+               printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover"
+                       " all of memory, losing %lluMB of RAM.\n",
+                       total_trim_size >> 20);
+
+               if (!changed_by_mtrr_cleanup)
+                       WARN_ON(1);
+
+               printk(KERN_INFO "update e820 for mtrr\n");
+               update_e820();
+
+               return 1;
+       }
+
+       return 0;
+}
+
index 0c0a455fe95c0b9468c6f59e350603ba30f32e68..37f28fc7cf959674151839b73a600a01e6a3e27f 100644 (file)
@@ -33,13 +33,31 @@ u64 mtrr_tom2;
 struct mtrr_state_type mtrr_state = {};
 EXPORT_SYMBOL_GPL(mtrr_state);
 
-static int __initdata mtrr_show;
-static int __init mtrr_debug(char *opt)
+/**
+ * BIOS is expected to clear MtrrFixDramModEn bit, see for example
+ * "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD
+ * Opteron Processors" (26094 Rev. 3.30 February 2006), section
+ * "13.2.1.2 SYSCFG Register": "The MtrrFixDramModEn bit should be set
+ * to 1 during BIOS initalization of the fixed MTRRs, then cleared to
+ * 0 for operation."
+ */
+static inline void k8_check_syscfg_dram_mod_en(void)
 {
-       mtrr_show = 1;
-       return 0;
+       u32 lo, hi;
+
+       if (!((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
+             (boot_cpu_data.x86 >= 0x0f)))
+               return;
+
+       rdmsr(MSR_K8_SYSCFG, lo, hi);
+       if (lo & K8_MTRRFIXRANGE_DRAM_MODIFY) {
+               printk(KERN_ERR FW_WARN "MTRR: CPU %u: SYSCFG[MtrrFixDramModEn]"
+                      " not cleared by BIOS, clearing this bit\n",
+                      smp_processor_id());
+               lo &= ~K8_MTRRFIXRANGE_DRAM_MODIFY;
+               mtrr_wrmsr(MSR_K8_SYSCFG, lo, hi);
+       }
 }
-early_param("mtrr.show", mtrr_debug);
 
 /*
  * Returns the effective MTRR type for the region
@@ -174,6 +192,8 @@ get_fixed_ranges(mtrr_type * frs)
        unsigned int *p = (unsigned int *) frs;
        int i;
 
+       k8_check_syscfg_dram_mod_en();
+
        rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
 
        for (i = 0; i < 2; i++)
@@ -188,18 +208,94 @@ void mtrr_save_fixed_ranges(void *info)
                get_fixed_ranges(mtrr_state.fixed_ranges);
 }
 
-static void print_fixed(unsigned base, unsigned step, const mtrr_type*types)
+static unsigned __initdata last_fixed_start;
+static unsigned __initdata last_fixed_end;
+static mtrr_type __initdata last_fixed_type;
+
+static void __init print_fixed_last(void)
+{
+       if (!last_fixed_end)
+               return;
+
+       printk(KERN_DEBUG "  %05X-%05X %s\n", last_fixed_start,
+               last_fixed_end - 1, mtrr_attrib_to_str(last_fixed_type));
+
+       last_fixed_end = 0;
+}
+
+static void __init update_fixed_last(unsigned base, unsigned end,
+                                      mtrr_type type)
+{
+       last_fixed_start = base;
+       last_fixed_end = end;
+       last_fixed_type = type;
+}
+
+static void __init print_fixed(unsigned base, unsigned step,
+                              const mtrr_type *types)
 {
        unsigned i;
 
-       for (i = 0; i < 8; ++i, ++types, base += step)
-               printk(KERN_INFO "MTRR %05X-%05X %s\n",
-                       base, base + step - 1, mtrr_attrib_to_str(*types));
+       for (i = 0; i < 8; ++i, ++types, base += step) {
+               if (last_fixed_end == 0) {
+                       update_fixed_last(base, base + step, *types);
+                       continue;
+               }
+               if (last_fixed_end == base && last_fixed_type == *types) {
+                       last_fixed_end = base + step;
+                       continue;
+               }
+               /* new segments: gap or different type */
+               print_fixed_last();
+               update_fixed_last(base, base + step, *types);
+       }
 }
 
 static void prepare_set(void);
 static void post_set(void);
 
+static void __init print_mtrr_state(void)
+{
+       unsigned int i;
+       int high_width;
+
+       printk(KERN_DEBUG "MTRR default type: %s\n",
+                        mtrr_attrib_to_str(mtrr_state.def_type));
+       if (mtrr_state.have_fixed) {
+               printk(KERN_DEBUG "MTRR fixed ranges %sabled:\n",
+                      mtrr_state.enabled & 1 ? "en" : "dis");
+               print_fixed(0x00000, 0x10000, mtrr_state.fixed_ranges + 0);
+               for (i = 0; i < 2; ++i)
+                       print_fixed(0x80000 + i * 0x20000, 0x04000, mtrr_state.fixed_ranges + (i + 1) * 8);
+               for (i = 0; i < 8; ++i)
+                       print_fixed(0xC0000 + i * 0x08000, 0x01000, mtrr_state.fixed_ranges + (i + 3) * 8);
+
+               /* tail */
+               print_fixed_last();
+       }
+       printk(KERN_DEBUG "MTRR variable ranges %sabled:\n",
+              mtrr_state.enabled & 2 ? "en" : "dis");
+       high_width = ((size_or_mask ? ffs(size_or_mask) - 1 : 32) - (32 - PAGE_SHIFT) + 3) / 4;
+       for (i = 0; i < num_var_ranges; ++i) {
+               if (mtrr_state.var_ranges[i].mask_lo & (1 << 11))
+                       printk(KERN_DEBUG "  %u base %0*X%05X000 mask %0*X%05X000 %s\n",
+                              i,
+                              high_width,
+                              mtrr_state.var_ranges[i].base_hi,
+                              mtrr_state.var_ranges[i].base_lo >> 12,
+                              high_width,
+                              mtrr_state.var_ranges[i].mask_hi,
+                              mtrr_state.var_ranges[i].mask_lo >> 12,
+                              mtrr_attrib_to_str(mtrr_state.var_ranges[i].base_lo & 0xff));
+               else
+                       printk(KERN_DEBUG "  %u disabled\n", i);
+       }
+       if (mtrr_tom2) {
+               printk(KERN_DEBUG "TOM2: %016llx aka %lldM\n",
+                                 mtrr_tom2, mtrr_tom2>>20);
+       }
+}
+
 /*  Grab all of the MTRR state for this CPU into *state  */
 void __init get_mtrr_state(void)
 {
@@ -231,41 +327,9 @@ void __init get_mtrr_state(void)
                mtrr_tom2 |= low;
                mtrr_tom2 &= 0xffffff800000ULL;
        }
-       if (mtrr_show) {
-               int high_width;
-
-               printk(KERN_INFO "MTRR default type: %s\n", mtrr_attrib_to_str(mtrr_state.def_type));
-               if (mtrr_state.have_fixed) {
-                       printk(KERN_INFO "MTRR fixed ranges %sabled:\n",
-                              mtrr_state.enabled & 1 ? "en" : "dis");
-                       print_fixed(0x00000, 0x10000, mtrr_state.fixed_ranges + 0);
-                       for (i = 0; i < 2; ++i)
-                               print_fixed(0x80000 + i * 0x20000, 0x04000, mtrr_state.fixed_ranges + (i + 1) * 8);
-                       for (i = 0; i < 8; ++i)
-                               print_fixed(0xC0000 + i * 0x08000, 0x01000, mtrr_state.fixed_ranges + (i + 3) * 8);
-               }
-               printk(KERN_INFO "MTRR variable ranges %sabled:\n",
-                      mtrr_state.enabled & 2 ? "en" : "dis");
-               high_width = ((size_or_mask ? ffs(size_or_mask) - 1 : 32) - (32 - PAGE_SHIFT) + 3) / 4;
-               for (i = 0; i < num_var_ranges; ++i) {
-                       if (mtrr_state.var_ranges[i].mask_lo & (1 << 11))
-                               printk(KERN_INFO "MTRR %u base %0*X%05X000 mask %0*X%05X000 %s\n",
-                                      i,
-                                      high_width,
-                                      mtrr_state.var_ranges[i].base_hi,
-                                      mtrr_state.var_ranges[i].base_lo >> 12,
-                                      high_width,
-                                      mtrr_state.var_ranges[i].mask_hi,
-                                      mtrr_state.var_ranges[i].mask_lo >> 12,
-                                      mtrr_attrib_to_str(mtrr_state.var_ranges[i].base_lo & 0xff));
-                       else
-                               printk(KERN_INFO "MTRR %u disabled\n", i);
-               }
-               if (mtrr_tom2) {
-                       printk(KERN_INFO "TOM2: %016llx aka %lldM\n",
-                                         mtrr_tom2, mtrr_tom2>>20);
-               }
-       }
+
+       print_mtrr_state();
+
        mtrr_state_set = 1;
 
        /* PAT setup for BP. We need to go through sync steps here */
@@ -307,28 +371,11 @@ void mtrr_wrmsr(unsigned msr, unsigned a, unsigned b)
                        smp_processor_id(), msr, a, b);
 }
 
-/**
- * Enable and allow read/write of extended fixed-range MTRR bits on K8 CPUs
- * see AMD publication no. 24593, chapter 3.2.1 for more information
- */
-static inline void k8_enable_fixed_iorrs(void)
-{
-       unsigned lo, hi;
-
-       rdmsr(MSR_K8_SYSCFG, lo, hi);
-       mtrr_wrmsr(MSR_K8_SYSCFG, lo
-                               | K8_MTRRFIXRANGE_DRAM_ENABLE
-                               | K8_MTRRFIXRANGE_DRAM_MODIFY, hi);
-}
-
 /**
  * set_fixed_range - checks & updates a fixed-range MTRR if it differs from the value it should have
  * @msr: MSR address of the MTTR which should be checked and updated
  * @changed: pointer which indicates whether the MTRR needed to be changed
  * @msrwords: pointer to the MSR values which the MSR should have
- *
- * If K8 extentions are wanted, update the K8 SYSCFG MSR also.
- * See AMD publication no. 24593, chapter 7.8.1, page 233 for more information.
  */
 static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords)
 {
@@ -337,10 +384,6 @@ static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords)
        rdmsr(msr, lo, hi);
 
        if (lo != msrwords[0] || hi != msrwords[1]) {
-               if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
-                   (boot_cpu_data.x86 >= 0x0f && boot_cpu_data.x86 <= 0x11) &&
-                   ((msrwords[0] | msrwords[1]) & K8_MTRR_RDMEM_WRMEM_MASK))
-                       k8_enable_fixed_iorrs();
                mtrr_wrmsr(msr, msrwords[0], msrwords[1]);
                *changed = true;
        }
@@ -376,22 +419,31 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base,
 {
        unsigned int mask_lo, mask_hi, base_lo, base_hi;
        unsigned int tmp, hi;
+       int cpu;
+
+       /*
+        * get_mtrr doesn't need to update mtrr_state, also it could be called
+        * from any cpu, so try to print it out directly.
+        */
+       cpu = get_cpu();
 
        rdmsr(MTRRphysMask_MSR(reg), mask_lo, mask_hi);
+
        if ((mask_lo & 0x800) == 0) {
                /*  Invalid (i.e. free) range  */
                *base = 0;
                *size = 0;
                *type = 0;
-               return;
+               goto out_put_cpu;
        }
 
        rdmsr(MTRRphysBase_MSR(reg), base_lo, base_hi);
 
-       /* Work out the shifted address mask. */
+       /* Work out the shifted address mask: */
        tmp = mask_hi << (32 - PAGE_SHIFT) | mask_lo >> PAGE_SHIFT;
        mask_lo = size_or_mask | tmp;
-       /* Expand tmp with high bits to all 1s*/
+
+       /* Expand tmp with high bits to all 1s: */
        hi = fls(tmp);
        if (hi > 0) {
                tmp |= ~((1<<(hi - 1)) - 1);
@@ -402,11 +454,19 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base,
                }
        }
 
-       /* This works correctly if size is a power of two, i.e. a
-          contiguous range. */
+       /*
+        * This works correctly if size is a power of two, i.e. a
+        * contiguous range:
+        */
        *size = -mask_lo;
        *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;
        *type = base_lo & 0xff;
+
+       printk(KERN_DEBUG "  get_mtrr: cpu%d reg%02d base=%010lx size=%010lx %s\n",
+                       cpu, reg, *base, *size,
+                       mtrr_attrib_to_str(*type & 0xff));
+out_put_cpu:
+       put_cpu();
 }
 
 /**
@@ -419,6 +479,8 @@ static int set_fixed_ranges(mtrr_type * frs)
        bool changed = false;
        int block=-1, range;
 
+       k8_check_syscfg_dram_mod_en();
+
        while (fixed_range_blocks[++block].ranges)
            for (range=0; range < fixed_range_blocks[block].ranges; range++)
                set_fixed_range(fixed_range_blocks[block].base_msr + range,
index 4c4214690dd10a4c32fc787e03bce6e7cba315d9..fb73a52913a4f883ca42010de302e3e909189fe7 100644 (file)
@@ -377,10 +377,6 @@ static const struct file_operations mtrr_fops = {
        .release = mtrr_close,
 };
 
-
-static struct proc_dir_entry *proc_root_mtrr;
-
-
 static int mtrr_seq_show(struct seq_file *seq, void *offset)
 {
        char factor;
@@ -423,11 +419,7 @@ static int __init mtrr_if_init(void)
            (!cpu_has(c, X86_FEATURE_CENTAUR_MCR)))
                return -ENODEV;
 
-       proc_root_mtrr =
-               proc_create("mtrr", S_IWUSR | S_IRUGO, NULL, &mtrr_fops);
-
-       if (proc_root_mtrr)
-               proc_root_mtrr->owner = THIS_MODULE;
+       proc_create("mtrr", S_IWUSR | S_IRUGO, NULL, &mtrr_fops);
        return 0;
 }
 
index 236a401b82597b0d48217db77ea5c10e692e9b2e..03cda01f57c7125173a8b348d92105d5bcd5dd28 100644 (file)
@@ -574,7 +574,7 @@ struct mtrr_value {
        unsigned long   lsize;
 };
 
-static struct mtrr_value mtrr_state[MTRR_MAX_VAR_RANGES];
+static struct mtrr_value mtrr_value[MTRR_MAX_VAR_RANGES];
 
 static int mtrr_save(struct sys_device * sysdev, pm_message_t state)
 {
@@ -582,9 +582,9 @@ static int mtrr_save(struct sys_device * sysdev, pm_message_t state)
 
        for (i = 0; i < num_var_ranges; i++) {
                mtrr_if->get(i,
-                            &mtrr_state[i].lbase,
-                            &mtrr_state[i].lsize,
-                            &mtrr_state[i].ltype);
+                            &mtrr_value[i].lbase,
+                            &mtrr_value[i].lsize,
+                            &mtrr_value[i].ltype);
        }
        return 0;
 }
@@ -594,11 +594,11 @@ static int mtrr_restore(struct sys_device * sysdev)
        int i;
 
        for (i = 0; i < num_var_ranges; i++) {
-               if (mtrr_state[i].lsize) 
+               if (mtrr_value[i].lsize)
                        set_mtrr(i,
-                                mtrr_state[i].lbase,
-                                mtrr_state[i].lsize,
-                                mtrr_state[i].ltype);
+                                mtrr_value[i].lbase,
+                                mtrr_value[i].lsize,
+                                mtrr_value[i].ltype);
        }
        return 0;
 }
@@ -610,1058 +610,7 @@ static struct sysdev_driver mtrr_sysdev_driver = {
        .resume         = mtrr_restore,
 };
 
-/* should be related to MTRR_VAR_RANGES nums */
-#define RANGE_NUM 256
-
-struct res_range {
-       unsigned long start;
-       unsigned long end;
-};
-
-static int __init
-add_range(struct res_range *range, int nr_range, unsigned long start,
-                             unsigned long end)
-{
-       /* out of slots */
-       if (nr_range >= RANGE_NUM)
-               return nr_range;
-
-       range[nr_range].start = start;
-       range[nr_range].end = end;
-
-       nr_range++;
-
-       return nr_range;
-}
-
-static int __init
-add_range_with_merge(struct res_range *range, int nr_range, unsigned long start,
-                             unsigned long end)
-{
-       int i;
-
-       /* try to merge it with old one */
-       for (i = 0; i < nr_range; i++) {
-               unsigned long final_start, final_end;
-               unsigned long common_start, common_end;
-
-               if (!range[i].end)
-                       continue;
-
-               common_start = max(range[i].start, start);
-               common_end = min(range[i].end, end);
-               if (common_start > common_end + 1)
-                       continue;
-
-               final_start = min(range[i].start, start);
-               final_end = max(range[i].end, end);
-
-               range[i].start = final_start;
-               range[i].end =  final_end;
-               return nr_range;
-       }
-
-       /* need to add that */
-       return add_range(range, nr_range, start, end);
-}
-
-static void __init
-subtract_range(struct res_range *range, unsigned long start, unsigned long end)
-{
-       int i, j;
-
-       for (j = 0; j < RANGE_NUM; j++) {
-               if (!range[j].end)
-                       continue;
-
-               if (start <= range[j].start && end >= range[j].end) {
-                       range[j].start = 0;
-                       range[j].end = 0;
-                       continue;
-               }
-
-               if (start <= range[j].start && end < range[j].end &&
-                   range[j].start < end + 1) {
-                       range[j].start = end + 1;
-                       continue;
-               }
-
-
-               if (start > range[j].start && end >= range[j].end &&
-                   range[j].end > start - 1) {
-                       range[j].end = start - 1;
-                       continue;
-               }
-
-               if (start > range[j].start && end < range[j].end) {
-                       /* find the new spare */
-                       for (i = 0; i < RANGE_NUM; i++) {
-                               if (range[i].end == 0)
-                                       break;
-                       }
-                       if (i < RANGE_NUM) {
-                               range[i].end = range[j].end;
-                               range[i].start = end + 1;
-                       } else {
-                               printk(KERN_ERR "run of slot in ranges\n");
-                       }
-                       range[j].end = start - 1;
-                       continue;
-               }
-       }
-}
-
-static int __init cmp_range(const void *x1, const void *x2)
-{
-       const struct res_range *r1 = x1;
-       const struct res_range *r2 = x2;
-       long start1, start2;
-
-       start1 = r1->start;
-       start2 = r2->start;
-
-       return start1 - start2;
-}
-
-struct var_mtrr_range_state {
-       unsigned long base_pfn;
-       unsigned long size_pfn;
-       mtrr_type type;
-};
-
-static struct var_mtrr_range_state __initdata range_state[RANGE_NUM];
-static int __initdata debug_print;
-
-static int __init
-x86_get_mtrr_mem_range(struct res_range *range, int nr_range,
-                      unsigned long extra_remove_base,
-                      unsigned long extra_remove_size)
-{
-       unsigned long i, base, size;
-       mtrr_type type;
-
-       for (i = 0; i < num_var_ranges; i++) {
-               type = range_state[i].type;
-               if (type != MTRR_TYPE_WRBACK)
-                       continue;
-               base = range_state[i].base_pfn;
-               size = range_state[i].size_pfn;
-               nr_range = add_range_with_merge(range, nr_range, base,
-                                               base + size - 1);
-       }
-       if (debug_print) {
-               printk(KERN_DEBUG "After WB checking\n");
-               for (i = 0; i < nr_range; i++)
-                       printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
-                                range[i].start, range[i].end + 1);
-       }
-
-       /* take out UC ranges */
-       for (i = 0; i < num_var_ranges; i++) {
-               type = range_state[i].type;
-               if (type != MTRR_TYPE_UNCACHABLE &&
-                   type != MTRR_TYPE_WRPROT)
-                       continue;
-               size = range_state[i].size_pfn;
-               if (!size)
-                       continue;
-               base = range_state[i].base_pfn;
-               subtract_range(range, base, base + size - 1);
-       }
-       if (extra_remove_size)
-               subtract_range(range, extra_remove_base,
-                                extra_remove_base + extra_remove_size  - 1);
-
-       /* get new range num */
-       nr_range = 0;
-       for (i = 0; i < RANGE_NUM; i++) {
-               if (!range[i].end)
-                       continue;
-               nr_range++;
-       }
-       if  (debug_print) {
-               printk(KERN_DEBUG "After UC checking\n");
-               for (i = 0; i < nr_range; i++)
-                       printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
-                                range[i].start, range[i].end + 1);
-       }
-
-       /* sort the ranges */
-       sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
-       if  (debug_print) {
-               printk(KERN_DEBUG "After sorting\n");
-               for (i = 0; i < nr_range; i++)
-                       printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
-                                range[i].start, range[i].end + 1);
-       }
-
-       /* clear those is not used */
-       for (i = nr_range; i < RANGE_NUM; i++)
-               memset(&range[i], 0, sizeof(range[i]));
-
-       return nr_range;
-}
-
-static struct res_range __initdata range[RANGE_NUM];
-static int __initdata nr_range;
-
-#ifdef CONFIG_MTRR_SANITIZER
-
-static unsigned long __init sum_ranges(struct res_range *range, int nr_range)
-{
-       unsigned long sum;
-       int i;
-
-       sum = 0;
-       for (i = 0; i < nr_range; i++)
-               sum += range[i].end + 1 - range[i].start;
-
-       return sum;
-}
-
-static int enable_mtrr_cleanup __initdata =
-       CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT;
-
-static int __init disable_mtrr_cleanup_setup(char *str)
-{
-       enable_mtrr_cleanup = 0;
-       return 0;
-}
-early_param("disable_mtrr_cleanup", disable_mtrr_cleanup_setup);
-
-static int __init enable_mtrr_cleanup_setup(char *str)
-{
-       enable_mtrr_cleanup = 1;
-       return 0;
-}
-early_param("enable_mtrr_cleanup", enable_mtrr_cleanup_setup);
-
-static int __init mtrr_cleanup_debug_setup(char *str)
-{
-       debug_print = 1;
-       return 0;
-}
-early_param("mtrr_cleanup_debug", mtrr_cleanup_debug_setup);
-
-struct var_mtrr_state {
-       unsigned long   range_startk;
-       unsigned long   range_sizek;
-       unsigned long   chunk_sizek;
-       unsigned long   gran_sizek;
-       unsigned int    reg;
-};
-
-static void __init
-set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
-               unsigned char type, unsigned int address_bits)
-{
-       u32 base_lo, base_hi, mask_lo, mask_hi;
-       u64 base, mask;
-
-       if (!sizek) {
-               fill_mtrr_var_range(reg, 0, 0, 0, 0);
-               return;
-       }
-
-       mask = (1ULL << address_bits) - 1;
-       mask &= ~((((u64)sizek) << 10) - 1);
-
-       base  = ((u64)basek) << 10;
-
-       base |= type;
-       mask |= 0x800;
-
-       base_lo = base & ((1ULL<<32) - 1);
-       base_hi = base >> 32;
-
-       mask_lo = mask & ((1ULL<<32) - 1);
-       mask_hi = mask >> 32;
-
-       fill_mtrr_var_range(reg, base_lo, base_hi, mask_lo, mask_hi);
-}
-
-static void __init
-save_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
-               unsigned char type)
-{
-       range_state[reg].base_pfn = basek >> (PAGE_SHIFT - 10);
-       range_state[reg].size_pfn = sizek >> (PAGE_SHIFT - 10);
-       range_state[reg].type = type;
-}
-
-static void __init
-set_var_mtrr_all(unsigned int address_bits)
-{
-       unsigned long basek, sizek;
-       unsigned char type;
-       unsigned int reg;
-
-       for (reg = 0; reg < num_var_ranges; reg++) {
-               basek = range_state[reg].base_pfn << (PAGE_SHIFT - 10);
-               sizek = range_state[reg].size_pfn << (PAGE_SHIFT - 10);
-               type = range_state[reg].type;
-
-               set_var_mtrr(reg, basek, sizek, type, address_bits);
-       }
-}
-
-static unsigned long to_size_factor(unsigned long sizek, char *factorp)
-{
-       char factor;
-       unsigned long base = sizek;
-
-       if (base & ((1<<10) - 1)) {
-               /* not MB alignment */
-               factor = 'K';
-       } else if (base & ((1<<20) - 1)){
-               factor = 'M';
-               base >>= 10;
-       } else {
-               factor = 'G';
-               base >>= 20;
-       }
-
-       *factorp = factor;
-
-       return base;
-}
-
-static unsigned int __init
-range_to_mtrr(unsigned int reg, unsigned long range_startk,
-             unsigned long range_sizek, unsigned char type)
-{
-       if (!range_sizek || (reg >= num_var_ranges))
-               return reg;
-
-       while (range_sizek) {
-               unsigned long max_align, align;
-               unsigned long sizek;
-
-               /* Compute the maximum size I can make a range */
-               if (range_startk)
-                       max_align = ffs(range_startk) - 1;
-               else
-                       max_align = 32;
-               align = fls(range_sizek) - 1;
-               if (align > max_align)
-                       align = max_align;
-
-               sizek = 1 << align;
-               if (debug_print) {
-                       char start_factor = 'K', size_factor = 'K';
-                       unsigned long start_base, size_base;
-
-                       start_base = to_size_factor(range_startk, &start_factor),
-                       size_base = to_size_factor(sizek, &size_factor),
-
-                       printk(KERN_DEBUG "Setting variable MTRR %d, "
-                               "base: %ld%cB, range: %ld%cB, type %s\n",
-                               reg, start_base, start_factor,
-                               size_base, size_factor,
-                               (type == MTRR_TYPE_UNCACHABLE)?"UC":
-                                   ((type == MTRR_TYPE_WRBACK)?"WB":"Other")
-                               );
-               }
-               save_var_mtrr(reg++, range_startk, sizek, type);
-               range_startk += sizek;
-               range_sizek -= sizek;
-               if (reg >= num_var_ranges)
-                       break;
-       }
-       return reg;
-}
-
-static unsigned __init
-range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek,
-                       unsigned long sizek)
-{
-       unsigned long hole_basek, hole_sizek;
-       unsigned long second_basek, second_sizek;
-       unsigned long range0_basek, range0_sizek;
-       unsigned long range_basek, range_sizek;
-       unsigned long chunk_sizek;
-       unsigned long gran_sizek;
-
-       hole_basek = 0;
-       hole_sizek = 0;
-       second_basek = 0;
-       second_sizek = 0;
-       chunk_sizek = state->chunk_sizek;
-       gran_sizek = state->gran_sizek;
-
-       /* align with gran size, prevent small block used up MTRRs */
-       range_basek = ALIGN(state->range_startk, gran_sizek);
-       if ((range_basek > basek) && basek)
-               return second_sizek;
-       state->range_sizek -= (range_basek - state->range_startk);
-       range_sizek = ALIGN(state->range_sizek, gran_sizek);
-
-       while (range_sizek > state->range_sizek) {
-               range_sizek -= gran_sizek;
-               if (!range_sizek)
-                       return 0;
-       }
-       state->range_sizek = range_sizek;
-
-       /* try to append some small hole */
-       range0_basek = state->range_startk;
-       range0_sizek = ALIGN(state->range_sizek, chunk_sizek);
-
-       /* no increase */
-       if (range0_sizek == state->range_sizek) {
-               if (debug_print)
-                       printk(KERN_DEBUG "rangeX: %016lx - %016lx\n",
-                               range0_basek<<10,
-                               (range0_basek + state->range_sizek)<<10);
-               state->reg = range_to_mtrr(state->reg, range0_basek,
-                               state->range_sizek, MTRR_TYPE_WRBACK);
-               return 0;
-       }
-
-       /* only cut back, when it is not the last */
-       if (sizek) {
-               while (range0_basek + range0_sizek > (basek + sizek)) {
-                       if (range0_sizek >= chunk_sizek)
-                               range0_sizek -= chunk_sizek;
-                       else
-                               range0_sizek = 0;
-
-                       if (!range0_sizek)
-                               break;
-               }
-       }
-
-second_try:
-       range_basek = range0_basek + range0_sizek;
-
-       /* one hole in the middle */
-       if (range_basek > basek && range_basek <= (basek + sizek))
-               second_sizek = range_basek - basek;
-
-       if (range0_sizek > state->range_sizek) {
-
-               /* one hole in middle or at end */
-               hole_sizek = range0_sizek - state->range_sizek - second_sizek;
-
-               /* hole size should be less than half of range0 size */
-               if (hole_sizek >= (range0_sizek >> 1) &&
-                   range0_sizek >= chunk_sizek) {
-                       range0_sizek -= chunk_sizek;
-                       second_sizek = 0;
-                       hole_sizek = 0;
-
-                       goto second_try;
-               }
-       }
-
-       if (range0_sizek) {
-               if (debug_print)
-                       printk(KERN_DEBUG "range0: %016lx - %016lx\n",
-                               range0_basek<<10,
-                               (range0_basek + range0_sizek)<<10);
-               state->reg = range_to_mtrr(state->reg, range0_basek,
-                               range0_sizek, MTRR_TYPE_WRBACK);
-       }
-
-       if (range0_sizek < state->range_sizek) {
-               /* need to handle left over */
-               range_sizek = state->range_sizek - range0_sizek;
-
-               if (debug_print)
-                       printk(KERN_DEBUG "range: %016lx - %016lx\n",
-                                range_basek<<10,
-                                (range_basek + range_sizek)<<10);
-               state->reg = range_to_mtrr(state->reg, range_basek,
-                                range_sizek, MTRR_TYPE_WRBACK);
-       }
-
-       if (hole_sizek) {
-               hole_basek = range_basek - hole_sizek - second_sizek;
-               if (debug_print)
-                       printk(KERN_DEBUG "hole: %016lx - %016lx\n",
-                                hole_basek<<10,
-                                (hole_basek + hole_sizek)<<10);
-               state->reg = range_to_mtrr(state->reg, hole_basek,
-                                hole_sizek, MTRR_TYPE_UNCACHABLE);
-       }
-
-       return second_sizek;
-}
-
-static void __init
-set_var_mtrr_range(struct var_mtrr_state *state, unsigned long base_pfn,
-                  unsigned long size_pfn)
-{
-       unsigned long basek, sizek;
-       unsigned long second_sizek = 0;
-
-       if (state->reg >= num_var_ranges)
-               return;
-
-       basek = base_pfn << (PAGE_SHIFT - 10);
-       sizek = size_pfn << (PAGE_SHIFT - 10);
-
-       /* See if I can merge with the last range */
-       if ((basek <= 1024) ||
-           (state->range_startk + state->range_sizek == basek)) {
-               unsigned long endk = basek + sizek;
-               state->range_sizek = endk - state->range_startk;
-               return;
-       }
-       /* Write the range mtrrs */
-       if (state->range_sizek != 0)
-               second_sizek = range_to_mtrr_with_hole(state, basek, sizek);
-
-       /* Allocate an msr */
-       state->range_startk = basek + second_sizek;
-       state->range_sizek  = sizek - second_sizek;
-}
-
-/* mininum size of mtrr block that can take hole */
-static u64 mtrr_chunk_size __initdata = (256ULL<<20);
-
-static int __init parse_mtrr_chunk_size_opt(char *p)
-{
-       if (!p)
-               return -EINVAL;
-       mtrr_chunk_size = memparse(p, &p);
-       return 0;
-}
-early_param("mtrr_chunk_size", parse_mtrr_chunk_size_opt);
-
-/* granity of mtrr of block */
-static u64 mtrr_gran_size __initdata;
-
-static int __init parse_mtrr_gran_size_opt(char *p)
-{
-       if (!p)
-               return -EINVAL;
-       mtrr_gran_size = memparse(p, &p);
-       return 0;
-}
-early_param("mtrr_gran_size", parse_mtrr_gran_size_opt);
-
-static int nr_mtrr_spare_reg __initdata =
-                                CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT;
-
-static int __init parse_mtrr_spare_reg(char *arg)
-{
-       if (arg)
-               nr_mtrr_spare_reg = simple_strtoul(arg, NULL, 0);
-       return 0;
-}
-
-early_param("mtrr_spare_reg_nr", parse_mtrr_spare_reg);
-
-static int __init
-x86_setup_var_mtrrs(struct res_range *range, int nr_range,
-                   u64 chunk_size, u64 gran_size)
-{
-       struct var_mtrr_state var_state;
-       int i;
-       int num_reg;
-
-       var_state.range_startk  = 0;
-       var_state.range_sizek   = 0;
-       var_state.reg           = 0;
-       var_state.chunk_sizek   = chunk_size >> 10;
-       var_state.gran_sizek    = gran_size >> 10;
-
-       memset(range_state, 0, sizeof(range_state));
-
-       /* Write the range etc */
-       for (i = 0; i < nr_range; i++)
-               set_var_mtrr_range(&var_state, range[i].start,
-                                  range[i].end - range[i].start + 1);
-
-       /* Write the last range */
-       if (var_state.range_sizek != 0)
-               range_to_mtrr_with_hole(&var_state, 0, 0);
-
-       num_reg = var_state.reg;
-       /* Clear out the extra MTRR's */
-       while (var_state.reg < num_var_ranges) {
-               save_var_mtrr(var_state.reg, 0, 0, 0);
-               var_state.reg++;
-       }
-
-       return num_reg;
-}
-
-struct mtrr_cleanup_result {
-       unsigned long gran_sizek;
-       unsigned long chunk_sizek;
-       unsigned long lose_cover_sizek;
-       unsigned int num_reg;
-       int bad;
-};
-
-/*
- * gran_size: 64K, 128K, 256K, 512K, 1M, 2M, ..., 2G
- * chunk size: gran_size, ..., 2G
- * so we need (1+16)*8
- */
-#define NUM_RESULT     136
-#define PSHIFT         (PAGE_SHIFT - 10)
-
-static struct mtrr_cleanup_result __initdata result[NUM_RESULT];
-static unsigned long __initdata min_loss_pfn[RANGE_NUM];
-
-static void __init print_out_mtrr_range_state(void)
-{
-       int i;
-       char start_factor = 'K', size_factor = 'K';
-       unsigned long start_base, size_base;
-       mtrr_type type;
-
-       for (i = 0; i < num_var_ranges; i++) {
-
-               size_base = range_state[i].size_pfn << (PAGE_SHIFT - 10);
-               if (!size_base)
-                       continue;
-
-               size_base = to_size_factor(size_base, &size_factor),
-               start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10);
-               start_base = to_size_factor(start_base, &start_factor),
-               type = range_state[i].type;
-
-               printk(KERN_DEBUG "reg %d, base: %ld%cB, range: %ld%cB, type %s\n",
-                       i, start_base, start_factor,
-                       size_base, size_factor,
-                       (type == MTRR_TYPE_UNCACHABLE) ? "UC" :
-                           ((type == MTRR_TYPE_WRPROT) ? "WP" :
-                            ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other"))
-                       );
-       }
-}
-
-static int __init mtrr_need_cleanup(void)
-{
-       int i;
-       mtrr_type type;
-       unsigned long size;
-       /* extra one for all 0 */
-       int num[MTRR_NUM_TYPES + 1];
-
-       /* check entries number */
-       memset(num, 0, sizeof(num));
-       for (i = 0; i < num_var_ranges; i++) {
-               type = range_state[i].type;
-               size = range_state[i].size_pfn;
-               if (type >= MTRR_NUM_TYPES)
-                       continue;
-               if (!size)
-                       type = MTRR_NUM_TYPES;
-               if (type == MTRR_TYPE_WRPROT)
-                       type = MTRR_TYPE_UNCACHABLE;
-               num[type]++;
-       }
-
-       /* check if we got UC entries */
-       if (!num[MTRR_TYPE_UNCACHABLE])
-               return 0;
-
-       /* check if we only had WB and UC */
-       if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
-               num_var_ranges - num[MTRR_NUM_TYPES])
-               return 0;
-
-       return 1;
-}
-
-static unsigned long __initdata range_sums;
-static void __init mtrr_calc_range_state(u64 chunk_size, u64 gran_size,
-                                        unsigned long extra_remove_base,
-                                        unsigned long extra_remove_size,
-                                        int i)
-{
-       int num_reg;
-       static struct res_range range_new[RANGE_NUM];
-       static int nr_range_new;
-       unsigned long range_sums_new;
-
-       /* convert ranges to var ranges state */
-       num_reg = x86_setup_var_mtrrs(range, nr_range,
-                                               chunk_size, gran_size);
-
-       /* we got new setting in range_state, check it */
-       memset(range_new, 0, sizeof(range_new));
-       nr_range_new = x86_get_mtrr_mem_range(range_new, 0,
-                               extra_remove_base, extra_remove_size);
-       range_sums_new = sum_ranges(range_new, nr_range_new);
-
-       result[i].chunk_sizek = chunk_size >> 10;
-       result[i].gran_sizek = gran_size >> 10;
-       result[i].num_reg = num_reg;
-       if (range_sums < range_sums_new) {
-               result[i].lose_cover_sizek =
-                       (range_sums_new - range_sums) << PSHIFT;
-               result[i].bad = 1;
-       } else
-               result[i].lose_cover_sizek =
-                       (range_sums - range_sums_new) << PSHIFT;
-
-       /* double check it */
-       if (!result[i].bad && !result[i].lose_cover_sizek) {
-               if (nr_range_new != nr_range ||
-                       memcmp(range, range_new, sizeof(range)))
-                               result[i].bad = 1;
-       }
-
-       if (!result[i].bad && (range_sums - range_sums_new <
-                               min_loss_pfn[num_reg])) {
-               min_loss_pfn[num_reg] =
-                       range_sums - range_sums_new;
-       }
-}
-
-static void __init mtrr_print_out_one_result(int i)
-{
-       char gran_factor, chunk_factor, lose_factor;
-       unsigned long gran_base, chunk_base, lose_base;
-
-       gran_base = to_size_factor(result[i].gran_sizek, &gran_factor),
-       chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor),
-       lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor),
-       printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t",
-                       result[i].bad ? "*BAD*" : " ",
-                       gran_base, gran_factor, chunk_base, chunk_factor);
-       printk(KERN_CONT "num_reg: %d  \tlose cover RAM: %s%ld%c\n",
-                       result[i].num_reg, result[i].bad ? "-" : "",
-                       lose_base, lose_factor);
-}
-
-static int __init mtrr_search_optimal_index(void)
-{
-       int i;
-       int num_reg_good;
-       int index_good;
-
-       if (nr_mtrr_spare_reg >= num_var_ranges)
-               nr_mtrr_spare_reg = num_var_ranges - 1;
-       num_reg_good = -1;
-       for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) {
-               if (!min_loss_pfn[i])
-                       num_reg_good = i;
-       }
-
-       index_good = -1;
-       if (num_reg_good != -1) {
-               for (i = 0; i < NUM_RESULT; i++) {
-                       if (!result[i].bad &&
-                           result[i].num_reg == num_reg_good &&
-                           !result[i].lose_cover_sizek) {
-                               index_good = i;
-                               break;
-                       }
-               }
-       }
-
-       return index_good;
-}
-
-
-static int __init mtrr_cleanup(unsigned address_bits)
-{
-       unsigned long extra_remove_base, extra_remove_size;
-       unsigned long base, size, def, dummy;
-       mtrr_type type;
-       u64 chunk_size, gran_size;
-       int index_good;
-       int i;
-
-       if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1)
-               return 0;
-       rdmsr(MTRRdefType_MSR, def, dummy);
-       def &= 0xff;
-       if (def != MTRR_TYPE_UNCACHABLE)
-               return 0;
-
-       /* get it and store it aside */
-       memset(range_state, 0, sizeof(range_state));
-       for (i = 0; i < num_var_ranges; i++) {
-               mtrr_if->get(i, &base, &size, &type);
-               range_state[i].base_pfn = base;
-               range_state[i].size_pfn = size;
-               range_state[i].type = type;
-       }
-
-       /* check if we need handle it and can handle it */
-       if (!mtrr_need_cleanup())
-               return 0;
-
-       /* print original var MTRRs at first, for debugging: */
-       printk(KERN_DEBUG "original variable MTRRs\n");
-       print_out_mtrr_range_state();
-
-       memset(range, 0, sizeof(range));
-       extra_remove_size = 0;
-       extra_remove_base = 1 << (32 - PAGE_SHIFT);
-       if (mtrr_tom2)
-               extra_remove_size =
-                       (mtrr_tom2 >> PAGE_SHIFT) - extra_remove_base;
-       nr_range = x86_get_mtrr_mem_range(range, 0, extra_remove_base,
-                                         extra_remove_size);
-       /*
-        * [0, 1M) should always be coverred by var mtrr with WB
-        * and fixed mtrrs should take effective before var mtrr for it
-        */
-       nr_range = add_range_with_merge(range, nr_range, 0,
-                                       (1ULL<<(20 - PAGE_SHIFT)) - 1);
-       /* sort the ranges */
-       sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
-
-       range_sums = sum_ranges(range, nr_range);
-       printk(KERN_INFO "total RAM coverred: %ldM\n",
-              range_sums >> (20 - PAGE_SHIFT));
-
-       if (mtrr_chunk_size && mtrr_gran_size) {
-               i = 0;
-               mtrr_calc_range_state(mtrr_chunk_size, mtrr_gran_size,
-                                     extra_remove_base, extra_remove_size, i);
-
-               mtrr_print_out_one_result(i);
-
-               if (!result[i].bad) {
-                       set_var_mtrr_all(address_bits);
-                       return 1;
-               }
-               printk(KERN_INFO "invalid mtrr_gran_size or mtrr_chunk_size, "
-                      "will find optimal one\n");
-       }
-
-       i = 0;
-       memset(min_loss_pfn, 0xff, sizeof(min_loss_pfn));
-       memset(result, 0, sizeof(result));
-       for (gran_size = (1ULL<<16); gran_size < (1ULL<<32); gran_size <<= 1) {
-
-               for (chunk_size = gran_size; chunk_size < (1ULL<<32);
-                    chunk_size <<= 1) {
-
-                       if (i >= NUM_RESULT)
-                               continue;
-
-                       mtrr_calc_range_state(chunk_size, gran_size,
-                                     extra_remove_base, extra_remove_size, i);
-                       if (debug_print) {
-                               mtrr_print_out_one_result(i);
-                               printk(KERN_INFO "\n");
-                       }
-
-                       i++;
-               }
-       }
-
-       /* try to find the optimal index */
-       index_good = mtrr_search_optimal_index();
-
-       if (index_good != -1) {
-               printk(KERN_INFO "Found optimal setting for mtrr clean up\n");
-               i = index_good;
-               mtrr_print_out_one_result(i);
-
-               /* convert ranges to var ranges state */
-               chunk_size = result[i].chunk_sizek;
-               chunk_size <<= 10;
-               gran_size = result[i].gran_sizek;
-               gran_size <<= 10;
-               x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size);
-               set_var_mtrr_all(address_bits);
-               printk(KERN_DEBUG "New variable MTRRs\n");
-               print_out_mtrr_range_state();
-               return 1;
-       } else {
-               /* print out all */
-               for (i = 0; i < NUM_RESULT; i++)
-                       mtrr_print_out_one_result(i);
-       }
-
-       printk(KERN_INFO "mtrr_cleanup: can not find optimal value\n");
-       printk(KERN_INFO "please specify mtrr_gran_size/mtrr_chunk_size\n");
-
-       return 0;
-}
-#else
-static int __init mtrr_cleanup(unsigned address_bits)
-{
-       return 0;
-}
-#endif
-
-static int __initdata changed_by_mtrr_cleanup;
-
-static int disable_mtrr_trim;
-
-static int __init disable_mtrr_trim_setup(char *str)
-{
-       disable_mtrr_trim = 1;
-       return 0;
-}
-early_param("disable_mtrr_trim", disable_mtrr_trim_setup);
-
-/*
- * Newer AMD K8s and later CPUs have a special magic MSR way to force WB
- * for memory >4GB. Check for that here.
- * Note this won't check if the MTRRs < 4GB where the magic bit doesn't
- * apply to are wrong, but so far we don't know of any such case in the wild.
- */
-#define Tom2Enabled (1U << 21)
-#define Tom2ForceMemTypeWB (1U << 22)
-
-int __init amd_special_default_mtrr(void)
-{
-       u32 l, h;
-
-       if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
-               return 0;
-       if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11)
-               return 0;
-       /* In case some hypervisor doesn't pass SYSCFG through */
-       if (rdmsr_safe(MSR_K8_SYSCFG, &l, &h) < 0)
-               return 0;
-       /*
-        * Memory between 4GB and top of mem is forced WB by this magic bit.
-        * Reserved before K8RevF, but should be zero there.
-        */
-       if ((l & (Tom2Enabled | Tom2ForceMemTypeWB)) ==
-                (Tom2Enabled | Tom2ForceMemTypeWB))
-               return 1;
-       return 0;
-}
-
-static u64 __init real_trim_memory(unsigned long start_pfn,
-                                  unsigned long limit_pfn)
-{
-       u64 trim_start, trim_size;
-       trim_start = start_pfn;
-       trim_start <<= PAGE_SHIFT;
-       trim_size = limit_pfn;
-       trim_size <<= PAGE_SHIFT;
-       trim_size -= trim_start;
-
-       return e820_update_range(trim_start, trim_size, E820_RAM,
-                               E820_RESERVED);
-}
-/**
- * mtrr_trim_uncached_memory - trim RAM not covered by MTRRs
- * @end_pfn: ending page frame number
- *
- * Some buggy BIOSes don't setup the MTRRs properly for systems with certain
- * memory configurations.  This routine checks that the highest MTRR matches
- * the end of memory, to make sure the MTRRs having a write back type cover
- * all of the memory the kernel is intending to use. If not, it'll trim any
- * memory off the end by adjusting end_pfn, removing it from the kernel's
- * allocation pools, warning the user with an obnoxious message.
- */
-int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
-{
-       unsigned long i, base, size, highest_pfn = 0, def, dummy;
-       mtrr_type type;
-       u64 total_trim_size;
-
-       /* extra one for all 0 */
-       int num[MTRR_NUM_TYPES + 1];
-       /*
-        * Make sure we only trim uncachable memory on machines that
-        * support the Intel MTRR architecture:
-        */
-       if (!is_cpu(INTEL) || disable_mtrr_trim)
-               return 0;
-       rdmsr(MTRRdefType_MSR, def, dummy);
-       def &= 0xff;
-       if (def != MTRR_TYPE_UNCACHABLE)
-               return 0;
-
-       /* get it and store it aside */
-       memset(range_state, 0, sizeof(range_state));
-       for (i = 0; i < num_var_ranges; i++) {
-               mtrr_if->get(i, &base, &size, &type);
-               range_state[i].base_pfn = base;
-               range_state[i].size_pfn = size;
-               range_state[i].type = type;
-       }
-
-       /* Find highest cached pfn */
-       for (i = 0; i < num_var_ranges; i++) {
-               type = range_state[i].type;
-               if (type != MTRR_TYPE_WRBACK)
-                       continue;
-               base = range_state[i].base_pfn;
-               size = range_state[i].size_pfn;
-               if (highest_pfn < base + size)
-                       highest_pfn = base + size;
-       }
-
-       /* kvm/qemu doesn't have mtrr set right, don't trim them all */
-       if (!highest_pfn) {
-               printk(KERN_INFO "CPU MTRRs all blank - virtualized system.\n");
-               return 0;
-       }
-
-       /* check entries number */
-       memset(num, 0, sizeof(num));
-       for (i = 0; i < num_var_ranges; i++) {
-               type = range_state[i].type;
-               if (type >= MTRR_NUM_TYPES)
-                       continue;
-               size = range_state[i].size_pfn;
-               if (!size)
-                       type = MTRR_NUM_TYPES;
-               num[type]++;
-       }
-
-       /* no entry for WB? */
-       if (!num[MTRR_TYPE_WRBACK])
-               return 0;
-
-       /* check if we only had WB and UC */
-       if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
-               num_var_ranges - num[MTRR_NUM_TYPES])
-               return 0;
-
-       memset(range, 0, sizeof(range));
-       nr_range = 0;
-       if (mtrr_tom2) {
-               range[nr_range].start = (1ULL<<(32 - PAGE_SHIFT));
-               range[nr_range].end = (mtrr_tom2 >> PAGE_SHIFT) - 1;
-               if (highest_pfn < range[nr_range].end + 1)
-                       highest_pfn = range[nr_range].end + 1;
-               nr_range++;
-       }
-       nr_range = x86_get_mtrr_mem_range(range, nr_range, 0, 0);
-
-       total_trim_size = 0;
-       /* check the head */
-       if (range[0].start)
-               total_trim_size += real_trim_memory(0, range[0].start);
-       /* check the holes */
-       for (i = 0; i < nr_range - 1; i++) {
-               if (range[i].end + 1 < range[i+1].start)
-                       total_trim_size += real_trim_memory(range[i].end + 1,
-                                                           range[i+1].start);
-       }
-       /* check the top */
-       i = nr_range - 1;
-       if (range[i].end + 1 < end_pfn)
-               total_trim_size += real_trim_memory(range[i].end + 1,
-                                                        end_pfn);
-
-       if (total_trim_size) {
-               printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover"
-                       " all of memory, losing %lluMB of RAM.\n",
-                       total_trim_size >> 20);
-
-               if (!changed_by_mtrr_cleanup)
-                       WARN_ON(1);
-
-               printk(KERN_INFO "update e820 for mtrr\n");
-               update_e820();
-
-               return 1;
-       }
-
-       return 0;
-}
+int __initdata changed_by_mtrr_cleanup;
 
 /**
  * mtrr_bp_init - initialize mtrrs on the boot CPU
index ffd60409cc6d410ee16eac82d76f4f83badab39e..77f67f7b347a3a97a093b1094c5da86a2ca9ad35 100644 (file)
@@ -79,6 +79,7 @@ extern struct mtrr_ops * mtrr_if;
 
 extern unsigned int num_var_ranges;
 extern u64 mtrr_tom2;
+extern struct mtrr_state_type mtrr_state;
 
 void mtrr_state_warn(void);
 const char *mtrr_attrib_to_str(int x);
@@ -88,3 +89,6 @@ void mtrr_wrmsr(unsigned, unsigned, unsigned);
 int amd_init_mtrr(void);
 int cyrix_init_mtrr(void);
 int centaur_init_mtrr(void);
+
+extern int changed_by_mtrr_cleanup;
+extern int mtrr_cleanup(unsigned address_bits);
index 52b3fefbd5af13c78b037b70f0e6bbeb6bbc780a..bb62b3e5caadca0faba5e489fb874bf563e0073c 100644 (file)
@@ -98,7 +98,7 @@ static void __cpuinit init_transmeta(struct cpuinfo_x86 *c)
 #endif
 }
 
-static struct cpu_dev transmeta_cpu_dev __cpuinitdata = {
+static const struct cpu_dev __cpuinitconst transmeta_cpu_dev = {
        .c_vendor       = "Transmeta",
        .c_ident        = { "GenuineTMx86", "TransmetaCPU" },
        .c_early_init   = early_init_transmeta,
index e777f79e0960d29fdaae20d800098569746450fe..fd2c37bf7acb6c6cc9a322600dc2c9dade028dbb 100644 (file)
@@ -8,7 +8,7 @@
  * so no special init takes place.
  */
 
-static struct cpu_dev umc_cpu_dev __cpuinitdata = {
+static const struct cpu_dev __cpuinitconst umc_cpu_dev = {
        .c_vendor       = "UMC",
        .c_ident        = { "UMC UMC UMC" },
        .c_models = {
index 87d103ded1c325a71d0ba65126bfd81996f78915..dd2130b0fb3e4ac183e1d62a979242db6b78f22e 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/kdebug.h>
 #include <linux/module.h>
 #include <linux/ptrace.h>
+#include <linux/ftrace.h>
 #include <linux/kexec.h>
 #include <linux/bug.h>
 #include <linux/nmi.h>
index 508bec1cee27af03844337a32497cd84a29f80ce..ef2c3563357d52c6f7d314a1df2cd018bbdca000 100644 (file)
@@ -110,19 +110,50 @@ int __init e820_all_mapped(u64 start, u64 end, unsigned type)
 /*
  * Add a memory region to the kernel e820 map.
  */
-void __init e820_add_region(u64 start, u64 size, int type)
+static void __init __e820_add_region(struct e820map *e820x, u64 start, u64 size,
+                                        int type)
 {
-       int x = e820.nr_map;
+       int x = e820x->nr_map;
 
-       if (x == ARRAY_SIZE(e820.map)) {
+       if (x == ARRAY_SIZE(e820x->map)) {
                printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
                return;
        }
 
-       e820.map[x].addr = start;
-       e820.map[x].size = size;
-       e820.map[x].type = type;
-       e820.nr_map++;
+       e820x->map[x].addr = start;
+       e820x->map[x].size = size;
+       e820x->map[x].type = type;
+       e820x->nr_map++;
+}
+
+void __init e820_add_region(u64 start, u64 size, int type)
+{
+       __e820_add_region(&e820, start, size, type);
+}
+
+static void __init e820_print_type(u32 type)
+{
+       switch (type) {
+       case E820_RAM:
+       case E820_RESERVED_KERN:
+               printk(KERN_CONT "(usable)");
+               break;
+       case E820_RESERVED:
+               printk(KERN_CONT "(reserved)");
+               break;
+       case E820_ACPI:
+               printk(KERN_CONT "(ACPI data)");
+               break;
+       case E820_NVS:
+               printk(KERN_CONT "(ACPI NVS)");
+               break;
+       case E820_UNUSABLE:
+               printk(KERN_CONT "(unusable)");
+               break;
+       default:
+               printk(KERN_CONT "type %u", type);
+               break;
+       }
 }
 
 void __init e820_print_map(char *who)
@@ -134,27 +165,8 @@ void __init e820_print_map(char *who)
                       (unsigned long long) e820.map[i].addr,
                       (unsigned long long)
                       (e820.map[i].addr + e820.map[i].size));
-               switch (e820.map[i].type) {
-               case E820_RAM:
-               case E820_RESERVED_KERN:
-                       printk(KERN_CONT "(usable)\n");
-                       break;
-               case E820_RESERVED:
-                       printk(KERN_CONT "(reserved)\n");
-                       break;
-               case E820_ACPI:
-                       printk(KERN_CONT "(ACPI data)\n");
-                       break;
-               case E820_NVS:
-                       printk(KERN_CONT "(ACPI NVS)\n");
-                       break;
-               case E820_UNUSABLE:
-                       printk("(unusable)\n");
-                       break;
-               default:
-                       printk(KERN_CONT "type %u\n", e820.map[i].type);
-                       break;
-               }
+               e820_print_type(e820.map[i].type);
+               printk(KERN_CONT "\n");
        }
 }
 
@@ -221,7 +233,7 @@ void __init e820_print_map(char *who)
  */
 
 int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map,
-                               int *pnr_map)
+                            u32 *pnr_map)
 {
        struct change_member {
                struct e820entry *pbios; /* pointer to original bios entry */
@@ -417,11 +429,12 @@ static int __init append_e820_map(struct e820entry *biosmap, int nr_map)
        return __append_e820_map(biosmap, nr_map);
 }
 
-static u64 __init e820_update_range_map(struct e820map *e820x, u64 start,
+static u64 __init __e820_update_range(struct e820map *e820x, u64 start,
                                        u64 size, unsigned old_type,
                                        unsigned new_type)
 {
-       int i;
+       u64 end;
+       unsigned int i;
        u64 real_updated_size = 0;
 
        BUG_ON(old_type == new_type);
@@ -429,27 +442,55 @@ static u64 __init e820_update_range_map(struct e820map *e820x, u64 start,
        if (size > (ULLONG_MAX - start))
                size = ULLONG_MAX - start;
 
-       for (i = 0; i < e820.nr_map; i++) {
+       end = start + size;
+       printk(KERN_DEBUG "e820 update range: %016Lx - %016Lx ",
+                      (unsigned long long) start,
+                      (unsigned long long) end);
+       e820_print_type(old_type);
+       printk(KERN_CONT " ==> ");
+       e820_print_type(new_type);
+       printk(KERN_CONT "\n");
+
+       for (i = 0; i < e820x->nr_map; i++) {
                struct e820entry *ei = &e820x->map[i];
                u64 final_start, final_end;
+               u64 ei_end;
+
                if (ei->type != old_type)
                        continue;
-               /* totally covered? */
-               if (ei->addr >= start &&
-                   (ei->addr + ei->size) <= (start + size)) {
+
+               ei_end = ei->addr + ei->size;
+               /* totally covered by new range? */
+               if (ei->addr >= start && ei_end <= end) {
                        ei->type = new_type;
                        real_updated_size += ei->size;
                        continue;
                }
+
+               /* new range is totally covered? */
+               if (ei->addr < start && ei_end > end) {
+                       __e820_add_region(e820x, start, size, new_type);
+                       __e820_add_region(e820x, end, ei_end - end, ei->type);
+                       ei->size = start - ei->addr;
+                       real_updated_size += size;
+                       continue;
+               }
+
                /* partially covered */
                final_start = max(start, ei->addr);
-               final_end = min(start + size, ei->addr + ei->size);
+               final_end = min(end, ei_end);
                if (final_start >= final_end)
                        continue;
-               e820_add_region(final_start, final_end - final_start,
-                                        new_type);
+
+               __e820_add_region(e820x, final_start, final_end - final_start,
+                                 new_type);
+
                real_updated_size += final_end - final_start;
 
+               /*
+                * left range could be head or tail, so need to update
+                * size at first.
+                */
                ei->size -= final_end - final_start;
                if (ei->addr < final_start)
                        continue;
@@ -461,13 +502,13 @@ static u64 __init e820_update_range_map(struct e820map *e820x, u64 start,
 u64 __init e820_update_range(u64 start, u64 size, unsigned old_type,
                             unsigned new_type)
 {
-       return e820_update_range_map(&e820, start, size, old_type, new_type);
+       return __e820_update_range(&e820, start, size, old_type, new_type);
 }
 
 static u64 __init e820_update_range_saved(u64 start, u64 size,
                                          unsigned old_type, unsigned new_type)
 {
-       return e820_update_range_map(&e820_saved, start, size, old_type,
+       return __e820_update_range(&e820_saved, start, size, old_type,
                                     new_type);
 }
 
@@ -511,7 +552,7 @@ u64 __init e820_remove_range(u64 start, u64 size, unsigned old_type,
 
 void __init update_e820(void)
 {
-       int nr_map;
+       u32 nr_map;
 
        nr_map = e820.nr_map;
        if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr_map))
@@ -522,7 +563,7 @@ void __init update_e820(void)
 }
 static void __init update_e820_saved(void)
 {
-       int nr_map;
+       u32 nr_map;
 
        nr_map = e820_saved.nr_map;
        if (sanitize_e820_map(e820_saved.map, ARRAY_SIZE(e820_saved.map), &nr_map))
@@ -1020,8 +1061,8 @@ u64 __init find_e820_area_size(u64 start, u64 *sizep, u64 align)
                        continue;
                return addr;
        }
-       return -1UL;
 
+       return -1ULL;
 }
 
 /*
@@ -1034,13 +1075,22 @@ u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align)
        u64 start;
 
        start = startt;
-       while (size < sizet)
+       while (size < sizet && (start + 1))
                start = find_e820_area_size(start, &size, align);
 
        if (size < sizet)
                return 0;
 
+#ifdef CONFIG_X86_32
+       if (start >= MAXMEM)
+               return 0;
+       if (start + size > MAXMEM)
+               size = MAXMEM - start;
+#endif
+
        addr = round_down(start + size - sizet, align);
+       if (addr < start)
+               return 0;
        e820_update_range(addr, sizet, E820_RAM, E820_RESERVED);
        e820_update_range_saved(addr, sizet, E820_RAM, E820_RESERVED);
        printk(KERN_INFO "update e820 for early_reserve_e820\n");
@@ -1253,7 +1303,7 @@ early_param("memmap", parse_memmap_opt);
 void __init finish_e820_parsing(void)
 {
        if (userdef) {
-               int nr = e820.nr_map;
+               u32 nr = e820.nr_map;
 
                if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr) < 0)
                        early_panic("Invalid user supplied memory map");
@@ -1336,7 +1386,7 @@ void __init e820_reserve_resources_late(void)
 char *__init default_machine_specific_memory_setup(void)
 {
        char *who = "BIOS-e820";
-       int new_nr;
+       u32 new_nr;
        /*
         * Try to copy the BIOS-supplied E820-map.
         *
index 639ad98238a2b395344b680e07ad6aa717ed9f45..335f049d110f5b095793cb6832a3571ee1d2586c 100644 (file)
@@ -250,7 +250,7 @@ static int dbgp_wait_until_complete(void)
        return (ctrl & DBGP_ERROR) ? -DBGP_ERRCODE(ctrl) : DBGP_LEN(ctrl);
 }
 
-static void dbgp_mdelay(int ms)
+static void __init dbgp_mdelay(int ms)
 {
        int i;
 
@@ -311,7 +311,7 @@ static void dbgp_set_data(const void *buf, int size)
        writel(hi, &ehci_debug->data47);
 }
 
-static void dbgp_get_data(void *buf, int size)
+static void __init dbgp_get_data(void *buf, int size)
 {
        unsigned char *bytes = buf;
        u32 lo, hi;
@@ -355,7 +355,7 @@ static int dbgp_bulk_write(unsigned devnum, unsigned endpoint,
        return ret;
 }
 
-static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
+static int __init dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
                                 int size)
 {
        u32 pids, addr, ctrl;
@@ -386,8 +386,8 @@ static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
        return ret;
 }
 
-static int dbgp_control_msg(unsigned devnum, int requesttype, int request,
-       int value, int index, void *data, int size)
+static int __init dbgp_control_msg(unsigned devnum, int requesttype,
+       int request, int value, int index, void *data, int size)
 {
        u32 pids, addr, ctrl;
        struct usb_ctrlrequest req;
@@ -489,7 +489,7 @@ static u32 __init find_dbgp(int ehci_num, u32 *rbus, u32 *rslot, u32 *rfunc)
        return 0;
 }
 
-static int ehci_reset_port(int port)
+static int __init ehci_reset_port(int port)
 {
        u32 portsc;
        u32 delay_time, delay;
@@ -532,7 +532,7 @@ static int ehci_reset_port(int port)
        return -EBUSY;
 }
 
-static int ehci_wait_for_port(int port)
+static int __init ehci_wait_for_port(int port)
 {
        u32 status;
        int ret, reps;
@@ -557,13 +557,13 @@ static inline void dbgp_printk(const char *fmt, ...) { }
 
 typedef void (*set_debug_port_t)(int port);
 
-static void default_set_debug_port(int port)
+static void __init default_set_debug_port(int port)
 {
 }
 
-static set_debug_port_t set_debug_port = default_set_debug_port;
+static set_debug_port_t __initdata set_debug_port = default_set_debug_port;
 
-static void nvidia_set_debug_port(int port)
+static void __init nvidia_set_debug_port(int port)
 {
        u32 dword;
        dword = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
index 899e8938e79f3d571cb207d6205b14800b2aa713..c929add475c9caf073f97c11b15ff6d645226126 100644 (file)
@@ -442,8 +442,7 @@ sysenter_past_esp:
 
        GET_THREAD_INFO(%ebp)
 
-       /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
-       testw $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
+       testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
        jnz sysenter_audit
 sysenter_do_call:
        cmpl $(nr_syscalls), %eax
@@ -454,7 +453,7 @@ sysenter_do_call:
        DISABLE_INTERRUPTS(CLBR_ANY)
        TRACE_IRQS_OFF
        movl TI_flags(%ebp), %ecx
-       testw $_TIF_ALLWORK_MASK, %cx
+       testl $_TIF_ALLWORK_MASK, %ecx
        jne sysexit_audit
 sysenter_exit:
 /* if something modifies registers it must also disable sysexit */
@@ -468,7 +467,7 @@ sysenter_exit:
 
 #ifdef CONFIG_AUDITSYSCALL
 sysenter_audit:
-       testw $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+       testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
        jnz syscall_trace_entry
        addl $4,%esp
        CFI_ADJUST_CFA_OFFSET -4
@@ -485,7 +484,7 @@ sysenter_audit:
        jmp sysenter_do_call
 
 sysexit_audit:
-       testw $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %cx
+       testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %ecx
        jne syscall_exit_work
        TRACE_IRQS_ON
        ENABLE_INTERRUPTS(CLBR_ANY)
@@ -498,7 +497,7 @@ sysexit_audit:
        DISABLE_INTERRUPTS(CLBR_ANY)
        TRACE_IRQS_OFF
        movl TI_flags(%ebp), %ecx
-       testw $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %cx
+       testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %ecx
        jne syscall_exit_work
        movl PT_EAX(%esp),%eax  /* reload syscall return value */
        jmp sysenter_exit
@@ -523,8 +522,7 @@ ENTRY(system_call)
        SAVE_ALL
        GET_THREAD_INFO(%ebp)
                                        # system call tracing in operation / emulation
-       /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
-       testw $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
+       testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
        jnz syscall_trace_entry
        cmpl $(nr_syscalls), %eax
        jae syscall_badsys
@@ -538,7 +536,7 @@ syscall_exit:
                                        # between sampling and the iret
        TRACE_IRQS_OFF
        movl TI_flags(%ebp), %ecx
-       testw $_TIF_ALLWORK_MASK, %cx   # current->work
+       testl $_TIF_ALLWORK_MASK, %ecx  # current->work
        jne syscall_exit_work
 
 restore_all:
@@ -673,7 +671,7 @@ END(syscall_trace_entry)
        # perform syscall exit tracing
        ALIGN
 syscall_exit_work:
-       testb $_TIF_WORK_SYSCALL_EXIT, %cl
+       testl $_TIF_WORK_SYSCALL_EXIT, %ecx
        jz work_pending
        TRACE_IRQS_ON
        ENABLE_INTERRUPTS(CLBR_ANY)     # could let syscall_trace_leave() call
index 83d1836b9467e74069d71805a65a53dbbcbce1b2..a331ec38af9ebb5d186685623448ac2e5263fd31 100644 (file)
@@ -368,6 +368,7 @@ ENTRY(save_rest)
 END(save_rest)
 
 /* save complete stack frame */
+       .pushsection .kprobes.text, "ax"
 ENTRY(save_paranoid)
        XCPT_FRAME 1 RDI+8
        cld
@@ -396,6 +397,7 @@ ENTRY(save_paranoid)
 1:     ret
        CFI_ENDPROC
 END(save_paranoid)
+       .popsection
 
 /*
  * A newly forked process directly context switches into this address.
@@ -416,7 +418,6 @@ ENTRY(ret_from_fork)
 
        GET_THREAD_INFO(%rcx)
 
-       CFI_REMEMBER_STATE
        RESTORE_REST
 
        testl $3, CS-ARGOFFSET(%rsp)            # from kernel_thread?
@@ -428,7 +429,6 @@ ENTRY(ret_from_fork)
        RESTORE_TOP_OF_STACK %rdi, -ARGOFFSET
        jmp ret_from_sys_call                   # go to the SYSRET fastpath
 
-       CFI_RESTORE_STATE
        CFI_ENDPROC
 END(ret_from_fork)
 
@@ -984,6 +984,8 @@ apicinterrupt UV_BAU_MESSAGE \
 #endif
 apicinterrupt LOCAL_TIMER_VECTOR \
        apic_timer_interrupt smp_apic_timer_interrupt
+apicinterrupt GENERIC_INTERRUPT_VECTOR \
+       generic_interrupt smp_generic_interrupt
 
 #ifdef CONFIG_SMP
 apicinterrupt INVALIDATE_TLB_VECTOR_START+0 \
index 231bdd3c5b1c710131dbdb2624f3f84cb8eeb6c8..76f7141e0f91ff9c4a55469b11c52146ea924c6a 100644 (file)
@@ -389,79 +389,6 @@ void ftrace_nmi_exit(void)
 
 #endif /* !CONFIG_DYNAMIC_FTRACE */
 
-/* Add a function return address to the trace stack on thread info.*/
-static int push_return_trace(unsigned long ret, unsigned long long time,
-                               unsigned long func, int *depth)
-{
-       int index;
-
-       if (!current->ret_stack)
-               return -EBUSY;
-
-       /* The return trace stack is full */
-       if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) {
-               atomic_inc(&current->trace_overrun);
-               return -EBUSY;
-       }
-
-       index = ++current->curr_ret_stack;
-       barrier();
-       current->ret_stack[index].ret = ret;
-       current->ret_stack[index].func = func;
-       current->ret_stack[index].calltime = time;
-       *depth = index;
-
-       return 0;
-}
-
-/* Retrieve a function return address to the trace stack on thread info.*/
-static void pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret)
-{
-       int index;
-
-       index = current->curr_ret_stack;
-
-       if (unlikely(index < 0)) {
-               ftrace_graph_stop();
-               WARN_ON(1);
-               /* Might as well panic, otherwise we have no where to go */
-               *ret = (unsigned long)panic;
-               return;
-       }
-
-       *ret = current->ret_stack[index].ret;
-       trace->func = current->ret_stack[index].func;
-       trace->calltime = current->ret_stack[index].calltime;
-       trace->overrun = atomic_read(&current->trace_overrun);
-       trace->depth = index;
-       barrier();
-       current->curr_ret_stack--;
-
-}
-
-/*
- * Send the trace to the ring-buffer.
- * @return the original return address.
- */
-unsigned long ftrace_return_to_handler(void)
-{
-       struct ftrace_graph_ret trace;
-       unsigned long ret;
-
-       pop_return_trace(&trace, &ret);
-       trace.rettime = cpu_clock(raw_smp_processor_id());
-       ftrace_graph_return(&trace);
-
-       if (unlikely(!ret)) {
-               ftrace_graph_stop();
-               WARN_ON(1);
-               /* Might as well panic. What else to do? */
-               ret = (unsigned long)panic;
-       }
-
-       return ret;
-}
-
 /*
  * Hook the return address and push it in the stack of return addrs
  * in current thread info.
@@ -521,7 +448,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
 
        calltime = cpu_clock(raw_smp_processor_id());
 
-       if (push_return_trace(old, calltime,
+       if (ftrace_push_return_trace(old, calltime,
                                self_addr, &trace.depth) == -EBUSY) {
                *parent = old;
                return;
index ac108d1fe182a44abcd0da75f18aae5fde32e1c0..3f8579f8d42cfa52710cc2331494542b1d1942dc 100644 (file)
@@ -18,7 +18,7 @@ void __init i386_start_kernel(void)
 {
        reserve_trampoline_memory();
 
-       reserve_early(__pa_symbol(&_text), __pa_symbol(&_end), "TEXT DATA BSS");
+       reserve_early(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS");
 
 #ifdef CONFIG_BLK_DEV_INITRD
        /* Reserve INITRD */
@@ -29,9 +29,6 @@ void __init i386_start_kernel(void)
                reserve_early(ramdisk_image, ramdisk_end, "RAMDISK");
        }
 #endif
-       reserve_early(init_pg_tables_start, init_pg_tables_end,
-                       "INIT_PG_TABLE");
-
        reserve_ebda_region();
 
        /*
index f5b2722476907bcd3fe7ace735238330c604b9e9..70eaa852c732a2db3ae5c809f56f27b9c0f42dc1 100644 (file)
@@ -100,7 +100,7 @@ void __init x86_64_start_reservations(char *real_mode_data)
 
        reserve_trampoline_memory();
 
-       reserve_early(__pa_symbol(&_text), __pa_symbol(&_end), "TEXT DATA BSS");
+       reserve_early(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS");
 
 #ifdef CONFIG_BLK_DEV_INITRD
        /* Reserve INITRD */
index c32ca19d591a5de88057d2d9534168332fa7bf77..30683883e0cdcf0bd669cb439206fefaf74301f2 100644 (file)
 #define X86_VENDOR_ID  new_cpu_data+CPUINFO_x86_vendor_id
 
 /*
- * This is how much memory *in addition to the memory covered up to
- * and including _end* we need mapped initially.
+ * This is how much memory in addition to the memory covered up to
+ * and including _end we need mapped initially.
  * We need:
- *  - one bit for each possible page, but only in low memory, which means
- *     2^32/4096/8 = 128K worst case (4G/4G split.)
- *  - enough space to map all low memory, which means
- *     (2^32/4096) / 1024 pages (worst case, non PAE)
- *     (2^32/4096) / 512 + 4 pages (worst case for PAE)
- *  - a few pages for allocator use before the kernel pagetable has
- *     been set up
+ *     (KERNEL_IMAGE_SIZE/4096) / 1024 pages (worst case, non PAE)
+ *     (KERNEL_IMAGE_SIZE/4096) / 512 + 4 pages (worst case for PAE)
  *
  * Modulo rounding, each megabyte assigned here requires a kilobyte of
  * memory, which is currently unreclaimed.
  *
  * This should be a multiple of a page.
+ *
+ * KERNEL_IMAGE_SIZE should be greater than pa(_end)
+ * and small than max_low_pfn, otherwise will waste some page table entries
  */
-LOW_PAGES = 1<<(32-PAGE_SHIFT_asm)
-
-/*
- * To preserve the DMA pool in PAGEALLOC kernels, we'll allocate
- * pagetables from above the 16MB DMA limit, so we'll have to set
- * up pagetables 16MB more (worst-case):
- */
-#ifdef CONFIG_DEBUG_PAGEALLOC
-LOW_PAGES = LOW_PAGES + 0x1000000
-#endif
 
 #if PTRS_PER_PMD > 1
-PAGE_TABLE_SIZE = (LOW_PAGES / PTRS_PER_PMD) + PTRS_PER_PGD
+#define PAGE_TABLE_SIZE(pages) (((pages) / PTRS_PER_PMD) + PTRS_PER_PGD)
 #else
-PAGE_TABLE_SIZE = (LOW_PAGES / PTRS_PER_PGD)
+#define PAGE_TABLE_SIZE(pages) ((pages) / PTRS_PER_PGD)
 #endif
-BOOTBITMAP_SIZE = LOW_PAGES / 8
-ALLOCATOR_SLOP = 4
 
-INIT_MAP_BEYOND_END = BOOTBITMAP_SIZE + (PAGE_TABLE_SIZE + ALLOCATOR_SLOP)*PAGE_SIZE_asm
+/* Enough space to fit pagetables for the low memory linear map */
+MAPPING_BEYOND_END = \
+       PAGE_TABLE_SIZE(((1<<32) - __PAGE_OFFSET) >> PAGE_SHIFT) << PAGE_SHIFT
+
+/*
+ * Worst-case size of the kernel mapping we need to make:
+ * the worst-case size of the kernel itself, plus the extra we need
+ * to map for the linear map.
+ */
+KERNEL_PAGES = (KERNEL_IMAGE_SIZE + MAPPING_BEYOND_END)>>PAGE_SHIFT
+
+INIT_MAP_SIZE = PAGE_TABLE_SIZE(KERNEL_PAGES) * PAGE_SIZE_asm
+RESERVE_BRK(pagetables, INIT_MAP_SIZE)
 
 /*
  * 32-bit kernel entrypoint; only used by the boot CPU.  On entry,
@@ -166,10 +164,10 @@ num_subarch_entries = (. - subarch_entries) / 4
 
 /*
  * Initialize page tables.  This creates a PDE and a set of page
- * tables, which are located immediately beyond _end.  The variable
- * init_pg_tables_end is set up to point to the first "safe" location.
+ * tables, which are located immediately beyond __brk_base.  The variable
+ * _brk_end is set up to point to the first "safe" location.
  * Mappings are created both at virtual address 0 (identity mapping)
- * and PAGE_OFFSET for up to _end+sizeof(page tables)+INIT_MAP_BEYOND_END.
+ * and PAGE_OFFSET for up to _end.
  *
  * Note that the stack is not yet set up!
  */
@@ -190,8 +188,7 @@ default_entry:
 
        xorl %ebx,%ebx                          /* %ebx is kept at zero */
 
-       movl $pa(pg0), %edi
-       movl %edi, pa(init_pg_tables_start)
+       movl $pa(__brk_base), %edi
        movl $pa(swapper_pg_pmd), %edx
        movl $PTE_IDENT_ATTR, %eax
 10:
@@ -209,14 +206,14 @@ default_entry:
        loop 11b
 
        /*
-        * End condition: we must map up to and including INIT_MAP_BEYOND_END
-        * bytes beyond the end of our own page tables.
+        * End condition: we must map up to the end + MAPPING_BEYOND_END.
         */
-       leal (INIT_MAP_BEYOND_END+PTE_IDENT_ATTR)(%edi),%ebp
+       movl $pa(_end) + MAPPING_BEYOND_END + PTE_IDENT_ATTR, %ebp
        cmpl %ebp,%eax
        jb 10b
 1:
-       movl %edi,pa(init_pg_tables_end)
+       addl $__PAGE_OFFSET, %edi
+       movl %edi, pa(_brk_end)
        shrl $12, %eax
        movl %eax, pa(max_pfn_mapped)
 
@@ -227,8 +224,7 @@ default_entry:
 
 page_pde_offset = (__PAGE_OFFSET >> 20);
 
-       movl $pa(pg0), %edi
-       movl %edi, pa(init_pg_tables_start)
+       movl $pa(__brk_base), %edi
        movl $pa(swapper_pg_dir), %edx
        movl $PTE_IDENT_ATTR, %eax
 10:
@@ -242,14 +238,13 @@ page_pde_offset = (__PAGE_OFFSET >> 20);
        addl $0x1000,%eax
        loop 11b
        /*
-        * End condition: we must map up to and including INIT_MAP_BEYOND_END
-        * bytes beyond the end of our own page tables; the +0x007 is
-        * the attribute bits
+        * End condition: we must map up to the end + MAPPING_BEYOND_END.
         */
-       leal (INIT_MAP_BEYOND_END+PTE_IDENT_ATTR)(%edi),%ebp
+       movl $pa(_end) + MAPPING_BEYOND_END + PTE_IDENT_ATTR, %ebp
        cmpl %ebp,%eax
        jb 10b
-       movl %edi,pa(init_pg_tables_end)
+       addl $__PAGE_OFFSET, %edi
+       movl %edi, pa(_brk_end)
        shrl $12, %eax
        movl %eax, pa(max_pfn_mapped)
 
@@ -636,6 +631,7 @@ swapper_pg_fixmap:
        .fill 1024,4,0
 ENTRY(empty_zero_page)
        .fill 4096,1,0
+
 /*
  * This starts the data section.
  */
index 10f92fb532f34e1c0e0c6a93059fa845eed7049c..3475440baa549b00c9666a67da874d47efa23ef9 100644 (file)
@@ -3,17 +3,17 @@
  *
  */
 #include <linux/clockchips.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/spinlock.h>
 #include <linux/jiffies.h>
 #include <linux/module.h>
-#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
 
-#include <asm/smp.h>
-#include <asm/delay.h>
 #include <asm/i8253.h>
-#include <asm/io.h>
 #include <asm/hpet.h>
+#include <asm/smp.h>
 
 DEFINE_SPINLOCK(i8253_lock);
 EXPORT_SYMBOL(i8253_lock);
@@ -40,7 +40,7 @@ static void init_pit_timer(enum clock_event_mode mode,
 {
        spin_lock(&i8253_lock);
 
-       switch(mode) {
+       switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
                /* binary, mode 2, LSB/MSB, ch 0 */
                outb_pit(0x34, PIT_MODE);
@@ -95,7 +95,7 @@ static int pit_next_event(unsigned long delta, struct clock_event_device *evt)
  * registered. This mechanism replaces the previous #ifdef LOCAL_APIC -
  * !using_apic_timer decisions in do_timer_interrupt_hook()
  */
-static struct clock_event_device pit_clockevent = {
+static struct clock_event_device pit_ce = {
        .name           = "pit",
        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
        .set_mode       = init_pit_timer,
@@ -114,15 +114,13 @@ void __init setup_pit_timer(void)
         * Start pit with the boot cpu mask and make it global after the
         * IO_APIC has been initialized.
         */
-       pit_clockevent.cpumask = cpumask_of(smp_processor_id());
-       pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
-                                    pit_clockevent.shift);
-       pit_clockevent.max_delta_ns =
-               clockevent_delta2ns(0x7FFF, &pit_clockevent);
-       pit_clockevent.min_delta_ns =
-               clockevent_delta2ns(0xF, &pit_clockevent);
-       clockevents_register_device(&pit_clockevent);
-       global_clock_event = &pit_clockevent;
+       pit_ce.cpumask = cpumask_of(smp_processor_id());
+       pit_ce.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, pit_ce.shift);
+       pit_ce.max_delta_ns = clockevent_delta2ns(0x7FFF, &pit_ce);
+       pit_ce.min_delta_ns = clockevent_delta2ns(0xF, &pit_ce);
+
+       clockevents_register_device(&pit_ce);
+       global_clock_event = &pit_ce;
 }
 
 #ifndef CONFIG_X86_64
@@ -133,11 +131,11 @@ void __init setup_pit_timer(void)
  */
 static cycle_t pit_read(void)
 {
+       static int old_count;
+       static u32 old_jifs;
        unsigned long flags;
        int count;
        u32 jifs;
-       static int old_count;
-       static u32 old_jifs;
 
        spin_lock_irqsave(&i8253_lock, flags);
        /*
@@ -179,9 +177,9 @@ static cycle_t pit_read(void)
         * Previous attempts to handle these cases intelligently were
         * buggy, so we just do the simple thing now.
         */
-       if (count > old_count && jifs == old_jifs) {
+       if (count > old_count && jifs == old_jifs)
                count = old_count;
-       }
+
        old_count = count;
        old_jifs = jifs;
 
@@ -192,13 +190,13 @@ static cycle_t pit_read(void)
        return (cycle_t)(jifs * LATCH) + count;
 }
 
-static struct clocksource clocksource_pit = {
-       .name   = "pit",
-       .rating = 110,
-       .read   = pit_read,
-       .mask   = CLOCKSOURCE_MASK(32),
-       .mult   = 0,
-       .shift  = 20,
+static struct clocksource pit_cs = {
+       .name           = "pit",
+       .rating         = 110,
+       .read           = pit_read,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .mult           = 0,
+       .shift          = 20,
 };
 
 static void pit_disable_clocksource(void)
@@ -206,9 +204,9 @@ static void pit_disable_clocksource(void)
        /*
         * Use mult to check whether it is registered or not
         */
-       if (clocksource_pit.mult) {
-               clocksource_unregister(&clocksource_pit);
-               clocksource_pit.mult = 0;
+       if (pit_cs.mult) {
+               clocksource_unregister(&pit_cs);
+               pit_cs.mult = 0;
        }
 }
 
@@ -222,13 +220,13 @@ static int __init init_pit_clocksource(void)
          * - when local APIC timer is active (PIT is switched off)
          */
        if (num_possible_cpus() > 1 || is_hpet_enabled() ||
-           pit_clockevent.mode != CLOCK_EVT_MODE_PERIODIC)
+           pit_ce.mode != CLOCK_EVT_MODE_PERIODIC)
                return 0;
 
-       clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE,
-                                                  clocksource_pit.shift);
-       return clocksource_register(&clocksource_pit);
+       pit_cs.mult = clocksource_hz2mult(CLOCK_TICK_RATE, pit_cs.shift);
+
+       return clocksource_register(&pit_cs);
 }
 arch_initcall(init_pit_clocksource);
 
-#endif
+#endif /* !CONFIG_X86_64 */
index 720d2607aacbc2bee985b00289b8bc5c70cb4fb5..a979b5bd2fc06ee5d07e2eb6a292caa773113f1a 100644 (file)
@@ -7,10 +7,10 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 #include <linux/dmi.h>
-#include <asm/io.h>
+#include <linux/io.h>
 
 int io_delay_type __read_mostly = CONFIG_DEFAULT_IO_DELAY_TYPE;
 
@@ -47,8 +47,7 @@ EXPORT_SYMBOL(native_io_delay);
 static int __init dmi_io_delay_0xed_port(const struct dmi_system_id *id)
 {
        if (io_delay_type == CONFIG_IO_DELAY_TYPE_0X80) {
-               printk(KERN_NOTICE "%s: using 0xed I/O delay port\n",
-                       id->ident);
+               pr_notice("%s: using 0xed I/O delay port\n", id->ident);
                io_delay_type = CONFIG_IO_DELAY_TYPE_0XED;
        }
 
@@ -64,40 +63,40 @@ static struct dmi_system_id __initdata io_delay_0xed_port_dmi_table[] = {
                .callback       = dmi_io_delay_0xed_port,
                .ident          = "Compaq Presario V6000",
                .matches        = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
-                       DMI_MATCH(DMI_BOARD_NAME, "30B7")
+                       DMI_MATCH(DMI_BOARD_VENDOR,     "Quanta"),
+                       DMI_MATCH(DMI_BOARD_NAME,       "30B7")
                }
        },
        {
                .callback       = dmi_io_delay_0xed_port,
                .ident          = "HP Pavilion dv9000z",
                .matches        = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
-                       DMI_MATCH(DMI_BOARD_NAME, "30B9")
+                       DMI_MATCH(DMI_BOARD_VENDOR,     "Quanta"),
+                       DMI_MATCH(DMI_BOARD_NAME,       "30B9")
                }
        },
        {
                .callback       = dmi_io_delay_0xed_port,
                .ident          = "HP Pavilion dv6000",
                .matches        = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
-                       DMI_MATCH(DMI_BOARD_NAME, "30B8")
+                       DMI_MATCH(DMI_BOARD_VENDOR,     "Quanta"),
+                       DMI_MATCH(DMI_BOARD_NAME,       "30B8")
                }
        },
        {
                .callback       = dmi_io_delay_0xed_port,
                .ident          = "HP Pavilion tx1000",
                .matches        = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
-                       DMI_MATCH(DMI_BOARD_NAME, "30BF")
+                       DMI_MATCH(DMI_BOARD_VENDOR,     "Quanta"),
+                       DMI_MATCH(DMI_BOARD_NAME,       "30BF")
                }
        },
        {
                .callback       = dmi_io_delay_0xed_port,
                .ident          = "Presario F700",
                .matches        = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
-                       DMI_MATCH(DMI_BOARD_NAME, "30D3")
+                       DMI_MATCH(DMI_BOARD_VENDOR,     "Quanta"),
+                       DMI_MATCH(DMI_BOARD_NAME,       "30D3")
                }
        },
        { }
index f13ca1650aafce84b1ecf5c1e665f1bbf4a9f5c6..3aaf7b9e3a8bd19405575502a2fbe9faaffba5b2 100644 (file)
@@ -15,6 +15,9 @@
 
 atomic_t irq_err_count;
 
+/* Function pointer for generic interrupt vector handling */
+void (*generic_interrupt_extension)(void) = NULL;
+
 /*
  * 'what should we do if we get a hw irq event on an illegal vector'.
  * each architecture has to answer this themselves.
@@ -42,55 +45,60 @@ void ack_bad_irq(unsigned int irq)
 /*
  * /proc/interrupts printing:
  */
-static int show_other_interrupts(struct seq_file *p)
+static int show_other_interrupts(struct seq_file *p, int prec)
 {
        int j;
 
-       seq_printf(p, "NMI: ");
+       seq_printf(p, "%*s: ", prec, "NMI");
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", irq_stats(j)->__nmi_count);
        seq_printf(p, "  Non-maskable interrupts\n");
 #ifdef CONFIG_X86_LOCAL_APIC
-       seq_printf(p, "LOC: ");
+       seq_printf(p, "%*s: ", prec, "LOC");
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", irq_stats(j)->apic_timer_irqs);
        seq_printf(p, "  Local timer interrupts\n");
+
+       seq_printf(p, "%*s: ", prec, "SPU");
+       for_each_online_cpu(j)
+               seq_printf(p, "%10u ", irq_stats(j)->irq_spurious_count);
+       seq_printf(p, "  Spurious interrupts\n");
 #endif
+       if (generic_interrupt_extension) {
+               seq_printf(p, "PLT: ");
+               for_each_online_cpu(j)
+                       seq_printf(p, "%10u ", irq_stats(j)->generic_irqs);
+               seq_printf(p, "  Platform interrupts\n");
+       }
 #ifdef CONFIG_SMP
-       seq_printf(p, "RES: ");
+       seq_printf(p, "%*s: ", prec, "RES");
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", irq_stats(j)->irq_resched_count);
        seq_printf(p, "  Rescheduling interrupts\n");
-       seq_printf(p, "CAL: ");
+       seq_printf(p, "%*s: ", prec, "CAL");
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", irq_stats(j)->irq_call_count);
        seq_printf(p, "  Function call interrupts\n");
-       seq_printf(p, "TLB: ");
+       seq_printf(p, "%*s: ", prec, "TLB");
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", irq_stats(j)->irq_tlb_count);
        seq_printf(p, "  TLB shootdowns\n");
 #endif
 #ifdef CONFIG_X86_MCE
-       seq_printf(p, "TRM: ");
+       seq_printf(p, "%*s: ", prec, "TRM");
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", irq_stats(j)->irq_thermal_count);
        seq_printf(p, "  Thermal event interrupts\n");
 # ifdef CONFIG_X86_64
-       seq_printf(p, "THR: ");
+       seq_printf(p, "%*s: ", prec, "THR");
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", irq_stats(j)->irq_threshold_count);
        seq_printf(p, "  Threshold APIC interrupts\n");
 # endif
 #endif
-#ifdef CONFIG_X86_LOCAL_APIC
-       seq_printf(p, "SPU: ");
-       for_each_online_cpu(j)
-               seq_printf(p, "%10u ", irq_stats(j)->irq_spurious_count);
-       seq_printf(p, "  Spurious interrupts\n");
-#endif
-       seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
+       seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
 #if defined(CONFIG_X86_IO_APIC)
-       seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
+       seq_printf(p, "%*s: %10u\n", prec, "MIS", atomic_read(&irq_mis_count));
 #endif
        return 0;
 }
@@ -98,19 +106,22 @@ static int show_other_interrupts(struct seq_file *p)
 int show_interrupts(struct seq_file *p, void *v)
 {
        unsigned long flags, any_count = 0;
-       int i = *(loff_t *) v, j;
+       int i = *(loff_t *) v, j, prec;
        struct irqaction *action;
        struct irq_desc *desc;
 
        if (i > nr_irqs)
                return 0;
 
+       for (prec = 3, j = 1000; prec < 10 && j <= nr_irqs; ++prec)
+               j *= 10;
+
        if (i == nr_irqs)
-               return show_other_interrupts(p);
+               return show_other_interrupts(p, prec);
 
        /* print header */
        if (i == 0) {
-               seq_printf(p, "           ");
+               seq_printf(p, "%*s", prec + 8, "");
                for_each_online_cpu(j)
                        seq_printf(p, "CPU%-8d", j);
                seq_putc(p, '\n');
@@ -121,23 +132,15 @@ int show_interrupts(struct seq_file *p, void *v)
                return 0;
 
        spin_lock_irqsave(&desc->lock, flags);
-#ifndef CONFIG_SMP
-       any_count = kstat_irqs(i);
-#else
        for_each_online_cpu(j)
                any_count |= kstat_irqs_cpu(i, j);
-#endif
        action = desc->action;
        if (!action && !any_count)
                goto out;
 
-       seq_printf(p, "%3d: ", i);
-#ifndef CONFIG_SMP
-       seq_printf(p, "%10u ", kstat_irqs(i));
-#else
+       seq_printf(p, "%*d: ", prec, i);
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
-#endif
        seq_printf(p, " %8s", desc->chip->name);
        seq_printf(p, "-%-8s", desc->name);
 
@@ -162,7 +165,10 @@ u64 arch_irq_stat_cpu(unsigned int cpu)
 
 #ifdef CONFIG_X86_LOCAL_APIC
        sum += irq_stats(cpu)->apic_timer_irqs;
+       sum += irq_stats(cpu)->irq_spurious_count;
 #endif
+       if (generic_interrupt_extension)
+               sum += irq_stats(cpu)->generic_irqs;
 #ifdef CONFIG_SMP
        sum += irq_stats(cpu)->irq_resched_count;
        sum += irq_stats(cpu)->irq_call_count;
@@ -173,9 +179,6 @@ u64 arch_irq_stat_cpu(unsigned int cpu)
 # ifdef CONFIG_X86_64
        sum += irq_stats(cpu)->irq_threshold_count;
 #endif
-#endif
-#ifdef CONFIG_X86_LOCAL_APIC
-       sum += irq_stats(cpu)->irq_spurious_count;
 #endif
        return sum;
 }
@@ -226,4 +229,27 @@ unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
        return 1;
 }
 
+/*
+ * Handler for GENERIC_INTERRUPT_VECTOR.
+ */
+void smp_generic_interrupt(struct pt_regs *regs)
+{
+       struct pt_regs *old_regs = set_irq_regs(regs);
+
+       ack_APIC_irq();
+
+       exit_idle();
+
+       irq_enter();
+
+       inc_irq_stat(generic_irqs);
+
+       if (generic_interrupt_extension)
+               generic_interrupt_extension();
+
+       irq_exit();
+
+       set_irq_regs(old_regs);
+}
+
 EXPORT_SYMBOL_GPL(vector_used_by_percpu_irq);
index 50b8c3a3006cb6f22ae0aa0f0cf3a50071475154..368b0a8836f902be69531754a72fb75e7b9a4e24 100644 (file)
@@ -50,7 +50,6 @@ static irqreturn_t math_error_irq(int cpl, void *dev_id)
  */
 static struct irqaction fpu_irq = {
        .handler = math_error_irq,
-       .mask = CPU_MASK_NONE,
        .name = "fpu",
 };
 
@@ -83,7 +82,6 @@ void __init init_ISA_irqs(void)
  */
 static struct irqaction irq2 = {
        .handler = no_action,
-       .mask = CPU_MASK_NONE,
        .name = "cascade",
 };
 
@@ -175,6 +173,9 @@ void __init native_init_IRQ(void)
        /* self generated IPI for local APIC timer */
        alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
 
+       /* generic IPI for platform specific use */
+       alloc_intr_gate(GENERIC_INTERRUPT_VECTOR, generic_interrupt);
+
        /* IPI vectors for APIC spurious and error interrupts */
        alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
        alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
index da481a1e3f303f8fe3bf10995e8e218cc556f2d4..8cd10537fd46f7480b6db9807db276ada5b390af 100644 (file)
@@ -45,7 +45,6 @@
 
 static struct irqaction irq2 = {
        .handler = no_action,
-       .mask = CPU_MASK_NONE,
        .name = "cascade",
 };
 DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
@@ -147,6 +146,9 @@ static void __init apic_intr_init(void)
        /* self generated IPI for local APIC timer */
        alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
 
+       /* generic IPI for platform specific use */
+       alloc_intr_gate(GENERIC_INTERRUPT_VECTOR, generic_interrupt);
+
        /* IPI vectors for APIC spurious and error interrupts */
        alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
        alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
index ff7d3b0124f1db07bbb0750ec0fe0e9237f66574..e444357375ce1421e137d6731adc3edba30def28 100644 (file)
@@ -8,11 +8,11 @@
  */
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
-#include <linux/stat.h>
+#include <linux/module.h>
 #include <linux/init.h>
+#include <linux/stat.h>
 #include <linux/io.h>
 #include <linux/mm.h>
-#include <linux/module.h>
 
 #include <asm/setup.h>
 
@@ -26,9 +26,8 @@ struct setup_data_node {
        u32 len;
 };
 
-static ssize_t
-setup_data_read(struct file *file, char __user *user_buf, size_t count,
-               loff_t *ppos)
+static ssize_t setup_data_read(struct file *file, char __user *user_buf,
+                              size_t count, loff_t *ppos)
 {
        struct setup_data_node *node = file->private_data;
        unsigned long remain;
@@ -39,20 +38,21 @@ setup_data_read(struct file *file, char __user *user_buf, size_t count,
 
        if (pos < 0)
                return -EINVAL;
+
        if (pos >= node->len)
                return 0;
 
        if (count > node->len - pos)
                count = node->len - pos;
+
        pa = node->paddr + sizeof(struct setup_data) + pos;
        pg = pfn_to_page((pa + count - 1) >> PAGE_SHIFT);
        if (PageHighMem(pg)) {
                p = ioremap_cache(pa, count);
                if (!p)
                        return -ENXIO;
-       } else {
+       } else
                p = __va(pa);
-       }
 
        remain = copy_to_user(user_buf, p, count);
 
@@ -70,12 +70,13 @@ setup_data_read(struct file *file, char __user *user_buf, size_t count,
 static int setup_data_open(struct inode *inode, struct file *file)
 {
        file->private_data = inode->i_private;
+
        return 0;
 }
 
 static const struct file_operations fops_setup_data = {
-       .read =         setup_data_read,
-       .open =         setup_data_open,
+       .read           = setup_data_read,
+       .open           = setup_data_open,
 };
 
 static int __init
@@ -84,57 +85,50 @@ create_setup_data_node(struct dentry *parent, int no,
 {
        struct dentry *d, *type, *data;
        char buf[16];
-       int error;
 
        sprintf(buf, "%d", no);
        d = debugfs_create_dir(buf, parent);
-       if (!d) {
-               error = -ENOMEM;
-               goto err_return;
-       }
+       if (!d)
+               return -ENOMEM;
+
        type = debugfs_create_x32("type", S_IRUGO, d, &node->type);
-       if (!type) {
-               error = -ENOMEM;
+       if (!type)
                goto err_dir;
-       }
+
        data = debugfs_create_file("data", S_IRUGO, d, node, &fops_setup_data);
-       if (!data) {
-               error = -ENOMEM;
+       if (!data)
                goto err_type;
-       }
+
        return 0;
 
 err_type:
        debugfs_remove(type);
 err_dir:
        debugfs_remove(d);
-err_return:
-       return error;
+       return -ENOMEM;
 }
 
 static int __init create_setup_data_nodes(struct dentry *parent)
 {
        struct setup_data_node *node;
        struct setup_data *data;
-       int error, no = 0;
+       int error = -ENOMEM;
        struct dentry *d;
        struct page *pg;
        u64 pa_data;
+       int no = 0;
 
        d = debugfs_create_dir("setup_data", parent);
-       if (!d) {
-               error = -ENOMEM;
-               goto err_return;
-       }
+       if (!d)
+               return -ENOMEM;
 
        pa_data = boot_params.hdr.setup_data;
 
        while (pa_data) {
                node = kmalloc(sizeof(*node), GFP_KERNEL);
-               if (!node) {
-                       error = -ENOMEM;
+               if (!node)
                        goto err_dir;
-               }
+
                pg = pfn_to_page((pa_data+sizeof(*data)-1) >> PAGE_SHIFT);
                if (PageHighMem(pg)) {
                        data = ioremap_cache(pa_data, sizeof(*data));
@@ -143,9 +137,8 @@ static int __init create_setup_data_nodes(struct dentry *parent)
                                error = -ENXIO;
                                goto err_dir;
                        }
-               } else {
+               } else
                        data = __va(pa_data);
-               }
 
                node->paddr = pa_data;
                node->type = data->type;
@@ -159,11 +152,11 @@ static int __init create_setup_data_nodes(struct dentry *parent)
                        goto err_dir;
                no++;
        }
+
        return 0;
 
 err_dir:
        debugfs_remove(d);
-err_return:
        return error;
 }
 
@@ -175,28 +168,26 @@ static struct debugfs_blob_wrapper boot_params_blob = {
 static int __init boot_params_kdebugfs_init(void)
 {
        struct dentry *dbp, *version, *data;
-       int error;
+       int error = -ENOMEM;
 
        dbp = debugfs_create_dir("boot_params", NULL);
-       if (!dbp) {
-               error = -ENOMEM;
-               goto err_return;
-       }
+       if (!dbp)
+               return -ENOMEM;
+
        version = debugfs_create_x16("version", S_IRUGO, dbp,
                                     &boot_params.hdr.version);
-       if (!version) {
-               error = -ENOMEM;
+       if (!version)
                goto err_dir;
-       }
+
        data = debugfs_create_blob("data", S_IRUGO, dbp,
                                   &boot_params_blob);
-       if (!data) {
-               error = -ENOMEM;
+       if (!data)
                goto err_version;
-       }
+
        error = create_setup_data_nodes(dbp);
        if (error)
                goto err_data;
+
        return 0;
 
 err_data:
@@ -205,10 +196,9 @@ err_version:
        debugfs_remove(version);
 err_dir:
        debugfs_remove(dbp);
-err_return:
        return error;
 }
-#endif
+#endif /* CONFIG_DEBUG_BOOT_PARAMS */
 
 static int __init arch_kdebugfs_init(void)
 {
index 4558dd3918cf3ec66263d7ac8e705acb4a5ea5a9..55b94614e34845cbab6e340754295e0d74462fa8 100644 (file)
@@ -193,7 +193,7 @@ static int __kprobes can_boost(kprobe_opcode_t *opcodes)
        kprobe_opcode_t opcode;
        kprobe_opcode_t *orig_opcodes = opcodes;
 
-       if (search_exception_tables(opcodes))
+       if (search_exception_tables((unsigned long)opcodes))
                return 0;       /* Page fault may occur on this address. */
 
 retry:
index 478bca986eca0d5213f3fe992cdb409db3670ce7..33019ddb56b452ce736f4b70fcb5d4efe8d0ae9d 100644 (file)
@@ -138,12 +138,6 @@ static void kvm_set_pte_atomic(pte_t *ptep, pte_t pte)
        kvm_mmu_write(ptep, pte_val(pte));
 }
 
-static void kvm_set_pte_present(struct mm_struct *mm, unsigned long addr,
-                               pte_t *ptep, pte_t pte)
-{
-       kvm_mmu_write(ptep, pte_val(pte));
-}
-
 static void kvm_pte_clear(struct mm_struct *mm,
                          unsigned long addr, pte_t *ptep)
 {
@@ -220,7 +214,6 @@ static void paravirt_ops_setup(void)
 #if PAGETABLE_LEVELS >= 3
 #ifdef CONFIG_X86_PAE
                pv_mmu_ops.set_pte_atomic = kvm_set_pte_atomic;
-               pv_mmu_ops.set_pte_present = kvm_set_pte_present;
                pv_mmu_ops.pte_clear = kvm_pte_clear;
                pv_mmu_ops.pmd_clear = kvm_pmd_clear;
 #endif
index f5fc8c781a62f5dcc41d5ef7213b24203d273213..e7368c1da01dfa26eeedc563390e8191eb6eb08f 100644 (file)
 #include <linux/ftrace.h>
 #include <linux/suspend.h>
 #include <linux/gfp.h>
+#include <linux/io.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
-#include <asm/io.h>
 #include <asm/apic.h>
 #include <asm/cpufeature.h>
 #include <asm/desc.h>
@@ -63,7 +63,7 @@ static void load_segments(void)
                "\tmovl %%eax,%%fs\n"
                "\tmovl %%eax,%%gs\n"
                "\tmovl %%eax,%%ss\n"
-               ::: "eax", "memory");
+               : : : "eax", "memory");
 #undef STR
 #undef __STR
 }
@@ -205,7 +205,8 @@ void machine_kexec(struct kimage *image)
 
        if (image->preserve_context) {
 #ifdef CONFIG_X86_IO_APIC
-               /* We need to put APICs in legacy mode so that we can
+               /*
+                * We need to put APICs in legacy mode so that we can
                 * get timer interrupts in second kernel. kexec/kdump
                 * paths already have calls to disable_IO_APIC() in
                 * one form or other. kexec jump path also need
@@ -227,7 +228,8 @@ void machine_kexec(struct kimage *image)
                page_list[PA_SWAP_PAGE] = (page_to_pfn(image->swap_page)
                                                << PAGE_SHIFT);
 
-       /* The segment registers are funny things, they have both a
+       /*
+        * The segment registers are funny things, they have both a
         * visible and an invisible part.  Whenever the visible part is
         * set to a specific selector, the invisible part is loaded
         * with from a table in memory.  At no other time is the
@@ -237,11 +239,12 @@ void machine_kexec(struct kimage *image)
         * segments, before I zap the gdt with an invalid value.
         */
        load_segments();
-       /* The gdt & idt are now invalid.
+       /*
+        * The gdt & idt are now invalid.
         * If you want to load them you must set up your own idt & gdt.
         */
-       set_gdt(phys_to_virt(0),0);
-       set_idt(phys_to_virt(0),0);
+       set_gdt(phys_to_virt(0), 0);
+       set_idt(phys_to_virt(0), 0);
 
        /* now call it */
        image->start = relocate_kernel_ptr((unsigned long)image->head,
index 6993d51b7fd819bd72fae83545490c870538f50e..89cea4d44679641146411bbce9e3e94b9b2bff84 100644 (file)
 #include <linux/reboot.h>
 #include <linux/numa.h>
 #include <linux/ftrace.h>
+#include <linux/io.h>
+#include <linux/suspend.h>
 
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
-#include <asm/io.h>
+
+static int init_one_level2_page(struct kimage *image, pgd_t *pgd,
+                               unsigned long addr)
+{
+       pud_t *pud;
+       pmd_t *pmd;
+       struct page *page;
+       int result = -ENOMEM;
+
+       addr &= PMD_MASK;
+       pgd += pgd_index(addr);
+       if (!pgd_present(*pgd)) {
+               page = kimage_alloc_control_pages(image, 0);
+               if (!page)
+                       goto out;
+               pud = (pud_t *)page_address(page);
+               memset(pud, 0, PAGE_SIZE);
+               set_pgd(pgd, __pgd(__pa(pud) | _KERNPG_TABLE));
+       }
+       pud = pud_offset(pgd, addr);
+       if (!pud_present(*pud)) {
+               page = kimage_alloc_control_pages(image, 0);
+               if (!page)
+                       goto out;
+               pmd = (pmd_t *)page_address(page);
+               memset(pmd, 0, PAGE_SIZE);
+               set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE));
+       }
+       pmd = pmd_offset(pud, addr);
+       if (!pmd_present(*pmd))
+               set_pmd(pmd, __pmd(addr | __PAGE_KERNEL_LARGE_EXEC));
+       result = 0;
+out:
+       return result;
+}
 
 static void init_level2_page(pmd_t *level2p, unsigned long addr)
 {
@@ -83,9 +119,8 @@ static int init_level4_page(struct kimage *image, pgd_t *level4p,
                }
                level3p = (pud_t *)page_address(page);
                result = init_level3_page(image, level3p, addr, last_addr);
-               if (result) {
+               if (result)
                        goto out;
-               }
                set_pgd(level4p++, __pgd(__pa(level3p) | _KERNPG_TABLE));
                addr += PGDIR_SIZE;
        }
@@ -154,6 +189,13 @@ static int init_pgtable(struct kimage *image, unsigned long start_pgtable)
        int result;
        level4p = (pgd_t *)__va(start_pgtable);
        result = init_level4_page(image, level4p, 0, max_pfn << PAGE_SHIFT);
+       if (result)
+               return result;
+       /*
+        * image->start may be outside 0 ~ max_pfn, for example when
+        * jump back to original kernel from kexeced kernel
+        */
+       result = init_one_level2_page(image, level4p, image->start);
        if (result)
                return result;
        return init_transition_pgtable(image, level4p);
@@ -229,20 +271,45 @@ void machine_kexec(struct kimage *image)
 {
        unsigned long page_list[PAGES_NR];
        void *control_page;
+       int save_ftrace_enabled;
 
-       tracer_disable();
+#ifdef CONFIG_KEXEC_JUMP
+       if (kexec_image->preserve_context)
+               save_processor_state();
+#endif
+
+       save_ftrace_enabled = __ftrace_enabled_save();
 
        /* Interrupts aren't acceptable while we reboot */
        local_irq_disable();
 
+       if (image->preserve_context) {
+#ifdef CONFIG_X86_IO_APIC
+               /*
+                * We need to put APICs in legacy mode so that we can
+                * get timer interrupts in second kernel. kexec/kdump
+                * paths already have calls to disable_IO_APIC() in
+                * one form or other. kexec jump path also need
+                * one.
+                */
+               disable_IO_APIC();
+#endif
+       }
+
        control_page = page_address(image->control_code_page) + PAGE_SIZE;
-       memcpy(control_page, relocate_kernel, PAGE_SIZE);
+       memcpy(control_page, relocate_kernel, KEXEC_CONTROL_CODE_MAX_SIZE);
 
        page_list[PA_CONTROL_PAGE] = virt_to_phys(control_page);
+       page_list[VA_CONTROL_PAGE] = (unsigned long)control_page;
        page_list[PA_TABLE_PAGE] =
          (unsigned long)__pa(page_address(image->control_code_page));
 
-       /* The segment registers are funny things, they have both a
+       if (image->type == KEXEC_TYPE_DEFAULT)
+               page_list[PA_SWAP_PAGE] = (page_to_pfn(image->swap_page)
+                                               << PAGE_SHIFT);
+
+       /*
+        * The segment registers are funny things, they have both a
         * visible and an invisible part.  Whenever the visible part is
         * set to a specific selector, the invisible part is loaded
         * with from a table in memory.  At no other time is the
@@ -252,15 +319,25 @@ void machine_kexec(struct kimage *image)
         * segments, before I zap the gdt with an invalid value.
         */
        load_segments();
-       /* The gdt & idt are now invalid.
+       /*
+        * The gdt & idt are now invalid.
         * If you want to load them you must set up your own idt & gdt.
         */
-       set_gdt(phys_to_virt(0),0);
-       set_idt(phys_to_virt(0),0);
+       set_gdt(phys_to_virt(0), 0);
+       set_idt(phys_to_virt(0), 0);
 
        /* now call it */
-       relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
-                       image->start);
+       image->start = relocate_kernel((unsigned long)image->head,
+                                      (unsigned long)page_list,
+                                      image->start,
+                                      image->preserve_context);
+
+#ifdef CONFIG_KEXEC_JUMP
+       if (kexec_image->preserve_context)
+               restore_processor_state();
+#endif
+
+       __ftrace_enabled_restore(save_ftrace_enabled);
 }
 
 void arch_crash_save_vmcoreinfo(void)
index 8815f3c7fec75e5d4a4d1cb17609ef0eed004515..846510b78a092324bfa7adc61ee72ee25e8792cc 100644 (file)
@@ -348,7 +348,6 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id)
 static struct irqaction mfgptirq  = {
        .handler = mfgpt_tick,
        .flags = IRQF_DISABLED | IRQF_NOBALANCING,
-       .mask = CPU_MASK_NONE,
        .name = "mfgpt-timer"
 };
 
index 666e43df51f99ce58b92c844149e1f8efcfa258f..712d15fdc416f9cd84139208434644ee887400a1 100644 (file)
@@ -226,7 +226,7 @@ static int __devinit set_check_enable_amd_mmconf(const struct dmi_system_id *d)
         return 0;
 }
 
-static struct dmi_system_id __devinitdata mmconf_dmi_table[] = {
+static const struct dmi_system_id __cpuinitconst mmconf_dmi_table[] = {
         {
                 .callback = set_check_enable_amd_mmconf,
                 .ident = "Sun Microsystems Machine",
index 37cb1bda1baf98fc9fd591aeb6d9ad26049517a1..dce99dca6cf876401149e3108e0ea9c34f8ef388 100644 (file)
@@ -109,9 +109,6 @@ static void __init MP_bus_info(struct mpc_bus *m)
        } else
                printk(KERN_WARNING "Unknown bustype %s - ignoring\n", str);
 }
-#endif
-
-#ifdef CONFIG_X86_IO_APIC
 
 static int bad_ioapic(unsigned long address)
 {
@@ -224,8 +221,12 @@ static void __init MP_intsrc_info(struct mpc_intsrc *m)
        if (++mp_irq_entries == MAX_IRQ_SOURCES)
                panic("Max # of irq sources exceeded!!\n");
 }
+#else /* CONFIG_X86_IO_APIC */
+static inline void __init MP_bus_info(struct mpc_bus *m) {}
+static inline void __init MP_ioapic_info(struct mpc_ioapic *m) {}
+static inline void __init MP_intsrc_info(struct mpc_intsrc *m) {}
+#endif /* CONFIG_X86_IO_APIC */
 
-#endif
 
 static void __init MP_lintsrc_info(struct mpc_lintsrc *m)
 {
@@ -275,6 +276,20 @@ static int __init smp_check_mpc(struct mpc_table *mpc, char *oem, char *str)
        return 1;
 }
 
+static void skip_entry(unsigned char **ptr, int *count, int size)
+{
+       *ptr += size;
+       *count += size;
+}
+
+static void __init smp_dump_mptable(struct mpc_table *mpc, unsigned char *mpt)
+{
+       printk(KERN_ERR "Your mptable is wrong, contact your HW vendor!\n"
+               "type %x\n", *mpt);
+       print_hex_dump(KERN_ERR, "  ", DUMP_PREFIX_ADDRESS, 16,
+                       1, mpc, mpc->length, 1);
+}
+
 static int __init smp_read_mpc(struct mpc_table *mpc, unsigned early)
 {
        char str[16];
@@ -310,61 +325,30 @@ static int __init smp_read_mpc(struct mpc_table *mpc, unsigned early)
        while (count < mpc->length) {
                switch (*mpt) {
                case MP_PROCESSOR:
-                       {
-                               struct mpc_cpu *m = (struct mpc_cpu *)mpt;
-                               /* ACPI may have already provided this data */
-                               if (!acpi_lapic)
-                                       MP_processor_info(m);
-                               mpt += sizeof(*m);
-                               count += sizeof(*m);
-                               break;
-                       }
+                       /* ACPI may have already provided this data */
+                       if (!acpi_lapic)
+                               MP_processor_info((struct mpc_cpu *)mpt);
+                       skip_entry(&mpt, &count, sizeof(struct mpc_cpu));
+                       break;
                case MP_BUS:
-                       {
-                               struct mpc_bus *m = (struct mpc_bus *)mpt;
-#ifdef CONFIG_X86_IO_APIC
-                               MP_bus_info(m);
-#endif
-                               mpt += sizeof(*m);
-                               count += sizeof(*m);
-                               break;
-                       }
+                       MP_bus_info((struct mpc_bus *)mpt);
+                       skip_entry(&mpt, &count, sizeof(struct mpc_bus));
+                       break;
                case MP_IOAPIC:
-                       {
-#ifdef CONFIG_X86_IO_APIC
-                               struct mpc_ioapic *m = (struct mpc_ioapic *)mpt;
-                               MP_ioapic_info(m);
-#endif
-                               mpt += sizeof(struct mpc_ioapic);
-                               count += sizeof(struct mpc_ioapic);
-                               break;
-                       }
+                       MP_ioapic_info((struct mpc_ioapic *)mpt);
+                       skip_entry(&mpt, &count, sizeof(struct mpc_ioapic));
+                       break;
                case MP_INTSRC:
-                       {
-#ifdef CONFIG_X86_IO_APIC
-                               struct mpc_intsrc *m = (struct mpc_intsrc *)mpt;
-
-                               MP_intsrc_info(m);
-#endif
-                               mpt += sizeof(struct mpc_intsrc);
-                               count += sizeof(struct mpc_intsrc);
-                               break;
-                       }
+                       MP_intsrc_info((struct mpc_intsrc *)mpt);
+                       skip_entry(&mpt, &count, sizeof(struct mpc_intsrc));
+                       break;
                case MP_LINTSRC:
-                       {
-                               struct mpc_lintsrc *m =
-                                   (struct mpc_lintsrc *)mpt;
-                               MP_lintsrc_info(m);
-                               mpt += sizeof(*m);
-                               count += sizeof(*m);
-                               break;
-                       }
+                       MP_lintsrc_info((struct mpc_lintsrc *)mpt);
+                       skip_entry(&mpt, &count, sizeof(struct mpc_lintsrc));
+                       break;
                default:
                        /* wrong mptable */
-                       printk(KERN_ERR "Your mptable is wrong, contact your HW vendor!\n");
-                       printk(KERN_ERR "type %x\n", *mpt);
-                       print_hex_dump(KERN_ERR, "  ", DUMP_PREFIX_ADDRESS, 16,
-                                       1, mpc, mpc->length, 1);
+                       smp_dump_mptable(mpc, mpt);
                        count = mpc->length;
                        break;
                }
@@ -558,6 +542,68 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type)
 
 static struct mpf_intel *mpf_found;
 
+static unsigned long __init get_mpc_size(unsigned long physptr)
+{
+       struct mpc_table *mpc;
+       unsigned long size;
+
+       mpc = early_ioremap(physptr, PAGE_SIZE);
+       size = mpc->length;
+       early_iounmap(mpc, PAGE_SIZE);
+       apic_printk(APIC_VERBOSE, "  mpc: %lx-%lx\n", physptr, physptr + size);
+
+       return size;
+}
+
+static int __init check_physptr(struct mpf_intel *mpf, unsigned int early)
+{
+       struct mpc_table *mpc;
+       unsigned long size;
+
+       size = get_mpc_size(mpf->physptr);
+       mpc = early_ioremap(mpf->physptr, size);
+       /*
+        * Read the physical hardware table.  Anything here will
+        * override the defaults.
+        */
+       if (!smp_read_mpc(mpc, early)) {
+#ifdef CONFIG_X86_LOCAL_APIC
+               smp_found_config = 0;
+#endif
+               printk(KERN_ERR "BIOS bug, MP table errors detected!...\n"
+                       "... disabling SMP support. (tell your hw vendor)\n");
+               early_iounmap(mpc, size);
+               return -1;
+       }
+       early_iounmap(mpc, size);
+
+       if (early)
+               return -1;
+
+#ifdef CONFIG_X86_IO_APIC
+       /*
+        * If there are no explicit MP IRQ entries, then we are
+        * broken.  We set up most of the low 16 IO-APIC pins to
+        * ISA defaults and hope it will work.
+        */
+       if (!mp_irq_entries) {
+               struct mpc_bus bus;
+
+               printk(KERN_ERR "BIOS bug, no explicit IRQ entries, "
+                      "using default mptable. (tell your hw vendor)\n");
+
+               bus.type = MP_BUS;
+               bus.busid = 0;
+               memcpy(bus.bustype, "ISA   ", 6);
+               MP_bus_info(&bus);
+
+               construct_default_ioirq_mptable(0);
+       }
+#endif
+
+       return 0;
+}
+
 /*
  * Scan the memory blocks for an SMP configuration block.
  */
@@ -611,45 +657,8 @@ static void __init __get_smp_config(unsigned int early)
                construct_default_ISA_mptable(mpf->feature1);
 
        } else if (mpf->physptr) {
-
-               /*
-                * Read the physical hardware table.  Anything here will
-                * override the defaults.
-                */
-               if (!smp_read_mpc(phys_to_virt(mpf->physptr), early)) {
-#ifdef CONFIG_X86_LOCAL_APIC
-                       smp_found_config = 0;
-#endif
-                       printk(KERN_ERR
-                              "BIOS bug, MP table errors detected!...\n");
-                       printk(KERN_ERR "... disabling SMP support. "
-                              "(tell your hw vendor)\n");
-                       return;
-               }
-
-               if (early)
+               if (check_physptr(mpf, early))
                        return;
-#ifdef CONFIG_X86_IO_APIC
-               /*
-                * If there are no explicit MP IRQ entries, then we are
-                * broken.  We set up most of the low 16 IO-APIC pins to
-                * ISA defaults and hope it will work.
-                */
-               if (!mp_irq_entries) {
-                       struct mpc_bus bus;
-
-                       printk(KERN_ERR "BIOS bug, no explicit IRQ entries, "
-                              "using default mptable. "
-                              "(tell your hw vendor)\n");
-
-                       bus.type = MP_BUS;
-                       bus.busid = 0;
-                       memcpy(bus.bustype, "ISA   ", 6);
-                       MP_bus_info(&bus);
-
-                       construct_default_ioirq_mptable(0);
-               }
-#endif
        } else
                BUG();
 
@@ -670,6 +679,31 @@ void __init get_smp_config(void)
        __get_smp_config(0);
 }
 
+static void smp_reserve_bootmem(struct mpf_intel *mpf)
+{
+       unsigned long size = get_mpc_size(mpf->physptr);
+#ifdef CONFIG_X86_32
+       /*
+        * We cannot access to MPC table to compute table size yet,
+        * as only few megabytes from the bottom is mapped now.
+        * PC-9800's MPC table places on the very last of physical
+        * memory; so that simply reserving PAGE_SIZE from mpf->physptr
+        * yields BUG() in reserve_bootmem.
+        * also need to make sure physptr is below than max_low_pfn
+        * we don't need reserve the area above max_low_pfn
+        */
+       unsigned long end = max_low_pfn * PAGE_SIZE;
+
+       if (mpf->physptr < end) {
+               if (mpf->physptr + size > end)
+                       size = end - mpf->physptr;
+               reserve_bootmem_generic(mpf->physptr, size, BOOTMEM_DEFAULT);
+       }
+#else
+       reserve_bootmem_generic(mpf->physptr, size, BOOTMEM_DEFAULT);
+#endif
+}
+
 static int __init smp_scan_config(unsigned long base, unsigned long length,
                                  unsigned reserve)
 {
@@ -697,36 +731,10 @@ static int __init smp_scan_config(unsigned long base, unsigned long length,
 
                        if (!reserve)
                                return 1;
-                       reserve_bootmem_generic(virt_to_phys(mpf), PAGE_SIZE,
-                                       BOOTMEM_DEFAULT);
-                       if (mpf->physptr) {
-                               unsigned long size = PAGE_SIZE;
-#ifdef CONFIG_X86_32
-                               /*
-                                * We cannot access to MPC table to compute
-                                * table size yet, as only few megabytes from
-                                * the bottom is mapped now.
-                                * PC-9800's MPC table places on the very last
-                                * of physical memory; so that simply reserving
-                                * PAGE_SIZE from mpf->physptr yields BUG()
-                                * in reserve_bootmem.
-                                * also need to make sure physptr is below than
-                                * max_low_pfn
-                                * we don't need reserve the area above max_low_pfn
-                                */
-                               unsigned long end = max_low_pfn * PAGE_SIZE;
-
-                               if (mpf->physptr < end) {
-                                       if (mpf->physptr + size > end)
-                                               size = end - mpf->physptr;
-                                       reserve_bootmem_generic(mpf->physptr, size,
-                                                       BOOTMEM_DEFAULT);
-                               }
-#else
-                               reserve_bootmem_generic(mpf->physptr, size,
+                       reserve_bootmem_generic(virt_to_phys(mpf), sizeof(*mpf),
                                                BOOTMEM_DEFAULT);
-#endif
-                       }
+                       if (mpf->physptr)
+                               smp_reserve_bootmem(mpf);
 
                        return 1;
                }
@@ -829,7 +837,57 @@ static int  __init get_MP_intsrc_index(struct mpc_intsrc *m)
 #define SPARE_SLOT_NUM 20
 
 static struct mpc_intsrc __initdata *m_spare[SPARE_SLOT_NUM];
-#endif
+
+static void check_irq_src(struct mpc_intsrc *m, int *nr_m_spare)
+{
+       int i;
+
+       apic_printk(APIC_VERBOSE, "OLD ");
+       print_MP_intsrc_info(m);
+
+       i = get_MP_intsrc_index(m);
+       if (i > 0) {
+               assign_to_mpc_intsrc(&mp_irqs[i], m);
+               apic_printk(APIC_VERBOSE, "NEW ");
+               print_mp_irq_info(&mp_irqs[i]);
+               return;
+       }
+       if (!i) {
+               /* legacy, do nothing */
+               return;
+       }
+       if (*nr_m_spare < SPARE_SLOT_NUM) {
+               /*
+                * not found (-1), or duplicated (-2) are invalid entries,
+                * we need to use the slot later
+                */
+               m_spare[*nr_m_spare] = m;
+               *nr_m_spare += 1;
+       }
+}
+#else /* CONFIG_X86_IO_APIC */
+static inline void check_irq_src(struct mpc_intsrc *m, int *nr_m_spare) {}
+#endif /* CONFIG_X86_IO_APIC */
+
+static int check_slot(unsigned long mpc_new_phys, unsigned long mpc_new_length,
+                     int count)
+{
+       if (!mpc_new_phys) {
+               pr_info("No spare slots, try to append...take your risk, "
+                       "new mpc_length %x\n", count);
+       } else {
+               if (count <= mpc_new_length)
+                       pr_info("No spare slots, try to append..., "
+                               "new mpc_length %x\n", count);
+               else {
+                       pr_err("mpc_new_length %lx is too small\n",
+                               mpc_new_length);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
 
 static int  __init replace_intsrc_all(struct mpc_table *mpc,
                                        unsigned long mpc_new_phys,
@@ -837,77 +895,33 @@ static int  __init replace_intsrc_all(struct mpc_table *mpc,
 {
 #ifdef CONFIG_X86_IO_APIC
        int i;
-       int nr_m_spare = 0;
 #endif
-
        int count = sizeof(*mpc);
+       int nr_m_spare = 0;
        unsigned char *mpt = ((unsigned char *)mpc) + count;
 
        printk(KERN_INFO "mpc_length %x\n", mpc->length);
        while (count < mpc->length) {
                switch (*mpt) {
                case MP_PROCESSOR:
-                       {
-                               struct mpc_cpu *m = (struct mpc_cpu *)mpt;
-                               mpt += sizeof(*m);
-                               count += sizeof(*m);
-                               break;
-                       }
+                       skip_entry(&mpt, &count, sizeof(struct mpc_cpu));
+                       break;
                case MP_BUS:
-                       {
-                               struct mpc_bus *m = (struct mpc_bus *)mpt;
-                               mpt += sizeof(*m);
-                               count += sizeof(*m);
-                               break;
-                       }
+                       skip_entry(&mpt, &count, sizeof(struct mpc_bus));
+                       break;
                case MP_IOAPIC:
-                       {
-                               mpt += sizeof(struct mpc_ioapic);
-                               count += sizeof(struct mpc_ioapic);
-                               break;
-                       }
+                       skip_entry(&mpt, &count, sizeof(struct mpc_ioapic));
+                       break;
                case MP_INTSRC:
-                       {
-#ifdef CONFIG_X86_IO_APIC
-                               struct mpc_intsrc *m = (struct mpc_intsrc *)mpt;
-
-                               printk(KERN_INFO "OLD ");
-                               print_MP_intsrc_info(m);
-                               i = get_MP_intsrc_index(m);
-                               if (i > 0) {
-                                       assign_to_mpc_intsrc(&mp_irqs[i], m);
-                                       printk(KERN_INFO "NEW ");
-                                       print_mp_irq_info(&mp_irqs[i]);
-                               } else if (!i) {
-                                       /* legacy, do nothing */
-                               } else if (nr_m_spare < SPARE_SLOT_NUM) {
-                                       /*
-                                        * not found (-1), or duplicated (-2)
-                                        * are invalid entries,
-                                        * we need to use the slot  later
-                                        */
-                                       m_spare[nr_m_spare] = m;
-                                       nr_m_spare++;
-                               }
-#endif
-                               mpt += sizeof(struct mpc_intsrc);
-                               count += sizeof(struct mpc_intsrc);
-                               break;
-                       }
+                       check_irq_src((struct mpc_intsrc *)mpt, &nr_m_spare);
+                       skip_entry(&mpt, &count, sizeof(struct mpc_intsrc));
+                       break;
                case MP_LINTSRC:
-                       {
-                               struct mpc_lintsrc *m =
-                                   (struct mpc_lintsrc *)mpt;
-                               mpt += sizeof(*m);
-                               count += sizeof(*m);
-                               break;
-                       }
+                       skip_entry(&mpt, &count, sizeof(struct mpc_lintsrc));
+                       break;
                default:
                        /* wrong mptable */
-                       printk(KERN_ERR "Your mptable is wrong, contact your HW vendor!\n");
-                       printk(KERN_ERR "type %x\n", *mpt);
-                       print_hex_dump(KERN_ERR, "  ", DUMP_PREFIX_ADDRESS, 16,
-                                       1, mpc, mpc->length, 1);
+                       smp_dump_mptable(mpc, mpt);
                        goto out;
                }
        }
@@ -924,23 +938,15 @@ static int  __init replace_intsrc_all(struct mpc_table *mpc,
                        continue;
 
                if (nr_m_spare > 0) {
-                       printk(KERN_INFO "*NEW* found ");
+                       apic_printk(APIC_VERBOSE, "*NEW* found\n");
                        nr_m_spare--;
                        assign_to_mpc_intsrc(&mp_irqs[i], m_spare[nr_m_spare]);
                        m_spare[nr_m_spare] = NULL;
                } else {
                        struct mpc_intsrc *m = (struct mpc_intsrc *)mpt;
                        count += sizeof(struct mpc_intsrc);
-                       if (!mpc_new_phys) {
-                               printk(KERN_INFO "No spare slots, try to append...take your risk, new mpc_length %x\n", count);
-                       } else {
-                               if (count <= mpc_new_length)
-                                       printk(KERN_INFO "No spare slots, try to append..., new mpc_length %x\n", count);
-                               else {
-                                       printk(KERN_ERR "mpc_new_length %lx is too small\n", mpc_new_length);
-                                       goto out;
-                               }
-                       }
+                       if (!check_slot(mpc_new_phys, mpc_new_length, count))
+                               goto out;
                        assign_to_mpc_intsrc(&mp_irqs[i], m);
                        mpc->length = count;
                        mpt += sizeof(struct mpc_intsrc);
index 63dd358d8ee13be0708c0139bf348d5d237aecfb..8e45f4464880ccdba671ea5248c5e2bea4f9b297 100644 (file)
@@ -470,7 +470,6 @@ struct pv_mmu_ops pv_mmu_ops = {
 #if PAGETABLE_LEVELS >= 3
 #ifdef CONFIG_X86_PAE
        .set_pte_atomic = native_set_pte_atomic,
-       .set_pte_present = native_set_pte_present,
        .pte_clear = native_pte_clear,
        .pmd_clear = native_pmd_clear,
 #endif
index d28bbdc35e4e5dec064bd1f9e5e7fbc548deaf4e..755c21e906f3f04821755c703bb99e26b118e0f7 100644 (file)
@@ -380,8 +380,9 @@ static inline struct iommu_table *find_iommu_table(struct device *dev)
        return tbl;
 }
 
-static void calgary_unmap_sg(struct device *dev,
-       struct scatterlist *sglist, int nelems, int direction)
+static void calgary_unmap_sg(struct device *dev, struct scatterlist *sglist,
+                            int nelems,enum dma_data_direction dir,
+                            struct dma_attrs *attrs)
 {
        struct iommu_table *tbl = find_iommu_table(dev);
        struct scatterlist *s;
@@ -404,7 +405,8 @@ static void calgary_unmap_sg(struct device *dev,
 }
 
 static int calgary_map_sg(struct device *dev, struct scatterlist *sg,
-       int nelems, int direction)
+                         int nelems, enum dma_data_direction dir,
+                         struct dma_attrs *attrs)
 {
        struct iommu_table *tbl = find_iommu_table(dev);
        struct scatterlist *s;
@@ -429,15 +431,14 @@ static int calgary_map_sg(struct device *dev, struct scatterlist *sg,
                s->dma_address = (entry << PAGE_SHIFT) | s->offset;
 
                /* insert into HW table */
-               tce_build(tbl, entry, npages, vaddr & PAGE_MASK,
-                         direction);
+               tce_build(tbl, entry, npages, vaddr & PAGE_MASK, dir);
 
                s->dma_length = s->length;
        }
 
        return nelems;
 error:
-       calgary_unmap_sg(dev, sg, nelems, direction);
+       calgary_unmap_sg(dev, sg, nelems, dir, NULL);
        for_each_sg(sg, s, nelems, i) {
                sg->dma_address = bad_dma_address;
                sg->dma_length = 0;
@@ -445,10 +446,12 @@ error:
        return 0;
 }
 
-static dma_addr_t calgary_map_single(struct device *dev, phys_addr_t paddr,
-       size_t size, int direction)
+static dma_addr_t calgary_map_page(struct device *dev, struct page *page,
+                                  unsigned long offset, size_t size,
+                                  enum dma_data_direction dir,
+                                  struct dma_attrs *attrs)
 {
-       void *vaddr = phys_to_virt(paddr);
+       void *vaddr = page_address(page) + offset;
        unsigned long uaddr;
        unsigned int npages;
        struct iommu_table *tbl = find_iommu_table(dev);
@@ -456,17 +459,18 @@ static dma_addr_t calgary_map_single(struct device *dev, phys_addr_t paddr,
        uaddr = (unsigned long)vaddr;
        npages = iommu_num_pages(uaddr, size, PAGE_SIZE);
 
-       return iommu_alloc(dev, tbl, vaddr, npages, direction);
+       return iommu_alloc(dev, tbl, vaddr, npages, dir);
 }
 
-static void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle,
-       size_t size, int direction)
+static void calgary_unmap_page(struct device *dev, dma_addr_t dma_addr,
+                              size_t size, enum dma_data_direction dir,
+                              struct dma_attrs *attrs)
 {
        struct iommu_table *tbl = find_iommu_table(dev);
        unsigned int npages;
 
-       npages = iommu_num_pages(dma_handle, size, PAGE_SIZE);
-       iommu_free(tbl, dma_handle, npages);
+       npages = iommu_num_pages(dma_addr, size, PAGE_SIZE);
+       iommu_free(tbl, dma_addr, npages);
 }
 
 static void* calgary_alloc_coherent(struct device *dev, size_t size,
@@ -515,13 +519,13 @@ static void calgary_free_coherent(struct device *dev, size_t size,
        free_pages((unsigned long)vaddr, get_order(size));
 }
 
-static struct dma_mapping_ops calgary_dma_ops = {
+static struct dma_map_ops calgary_dma_ops = {
        .alloc_coherent = calgary_alloc_coherent,
        .free_coherent = calgary_free_coherent,
-       .map_single = calgary_map_single,
-       .unmap_single = calgary_unmap_single,
        .map_sg = calgary_map_sg,
        .unmap_sg = calgary_unmap_sg,
+       .map_page = calgary_map_page,
+       .unmap_page = calgary_unmap_page,
 };
 
 static inline void __iomem * busno_to_bbar(unsigned char num)
index b25428533141a5a73fb8787268864b774c5e9752..90f5b9ef5defbd44c6bb2d0ad0489bdafb1cca08 100644 (file)
@@ -1,4 +1,5 @@
 #include <linux/dma-mapping.h>
+#include <linux/dma-debug.h>
 #include <linux/dmar.h>
 #include <linux/bootmem.h>
 #include <linux/pci.h>
@@ -12,7 +13,7 @@
 
 static int forbid_dac __read_mostly;
 
-struct dma_mapping_ops *dma_ops;
+struct dma_map_ops *dma_ops;
 EXPORT_SYMBOL(dma_ops);
 
 static int iommu_sac_force __read_mostly;
@@ -44,6 +45,9 @@ struct device x86_dma_fallback_dev = {
 };
 EXPORT_SYMBOL(x86_dma_fallback_dev);
 
+/* Number of entries preallocated for DMA-API debugging */
+#define PREALLOC_DMA_DEBUG_ENTRIES       32768
+
 int dma_set_mask(struct device *dev, u64 mask)
 {
        if (!dev->dma_mask || !dma_supported(dev, mask))
@@ -224,7 +228,7 @@ early_param("iommu", iommu_setup);
 
 int dma_supported(struct device *dev, u64 mask)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(dev);
+       struct dma_map_ops *ops = get_dma_ops(dev);
 
 #ifdef CONFIG_PCI
        if (mask > 0xffffffff && forbid_dac > 0) {
@@ -265,6 +269,12 @@ EXPORT_SYMBOL(dma_supported);
 
 static int __init pci_iommu_init(void)
 {
+       dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
+
+#ifdef CONFIG_PCI
+       dma_debug_add_bus(&pci_bus_type);
+#endif
+
        calgary_iommu_init();
 
        intel_iommu_init();
@@ -290,8 +300,7 @@ fs_initcall(pci_iommu_init);
 static __devinit void via_no_dac(struct pci_dev *dev)
 {
        if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && forbid_dac == 0) {
-               printk(KERN_INFO
-                       "PCI: VIA PCI bridge detected. Disabling DAC.\n");
+               dev_info(&dev->dev, "disabling DAC on VIA PCI bridge\n");
                forbid_dac = 1;
        }
 }
index d5768b1af08041160e52ea6b70a2f6cd4bb6e476..b284b58c035ccdd8fc850604cced3557ae7de2c5 100644 (file)
@@ -255,10 +255,13 @@ static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem,
 }
 
 /* Map a single area into the IOMMU */
-static dma_addr_t
-gart_map_single(struct device *dev, phys_addr_t paddr, size_t size, int dir)
+static dma_addr_t gart_map_page(struct device *dev, struct page *page,
+                               unsigned long offset, size_t size,
+                               enum dma_data_direction dir,
+                               struct dma_attrs *attrs)
 {
        unsigned long bus;
+       phys_addr_t paddr = page_to_phys(page) + offset;
 
        if (!dev)
                dev = &x86_dma_fallback_dev;
@@ -275,8 +278,9 @@ gart_map_single(struct device *dev, phys_addr_t paddr, size_t size, int dir)
 /*
  * Free a DMA mapping.
  */
-static void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
-                             size_t size, int direction)
+static void gart_unmap_page(struct device *dev, dma_addr_t dma_addr,
+                           size_t size, enum dma_data_direction dir,
+                           struct dma_attrs *attrs)
 {
        unsigned long iommu_page;
        int npages;
@@ -298,8 +302,8 @@ static void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
 /*
  * Wrapper for pci_unmap_single working with scatterlists.
  */
-static void
-gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
+static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
+                         enum dma_data_direction dir, struct dma_attrs *attrs)
 {
        struct scatterlist *s;
        int i;
@@ -307,7 +311,7 @@ gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
        for_each_sg(sg, s, nents, i) {
                if (!s->dma_length || !s->length)
                        break;
-               gart_unmap_single(dev, s->dma_address, s->dma_length, dir);
+               gart_unmap_page(dev, s->dma_address, s->dma_length, dir, NULL);
        }
 }
 
@@ -329,7 +333,7 @@ static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg,
                        addr = dma_map_area(dev, addr, s->length, dir, 0);
                        if (addr == bad_dma_address) {
                                if (i > 0)
-                                       gart_unmap_sg(dev, sg, i, dir);
+                                       gart_unmap_sg(dev, sg, i, dir, NULL);
                                nents = 0;
                                sg[0].dma_length = 0;
                                break;
@@ -400,8 +404,8 @@ dma_map_cont(struct device *dev, struct scatterlist *start, int nelems,
  * DMA map all entries in a scatterlist.
  * Merge chunks that have page aligned sizes into a continuous mapping.
  */
-static int
-gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
+static int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+                      enum dma_data_direction dir, struct dma_attrs *attrs)
 {
        struct scatterlist *s, *ps, *start_sg, *sgmap;
        int need = 0, nextneed, i, out, start;
@@ -468,7 +472,7 @@ gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
 
 error:
        flush_gart();
-       gart_unmap_sg(dev, sg, out, dir);
+       gart_unmap_sg(dev, sg, out, dir, NULL);
 
        /* When it was forced or merged try again in a dumb way */
        if (force_iommu || iommu_merge) {
@@ -521,7 +525,7 @@ static void
 gart_free_coherent(struct device *dev, size_t size, void *vaddr,
                   dma_addr_t dma_addr)
 {
-       gart_unmap_single(dev, dma_addr, size, DMA_BIDIRECTIONAL);
+       gart_unmap_page(dev, dma_addr, size, DMA_BIDIRECTIONAL, NULL);
        free_pages((unsigned long)vaddr, get_order(size));
 }
 
@@ -707,11 +711,11 @@ static __init int init_k8_gatt(struct agp_kern_info *info)
        return -1;
 }
 
-static struct dma_mapping_ops gart_dma_ops = {
-       .map_single                     = gart_map_single,
-       .unmap_single                   = gart_unmap_single,
+static struct dma_map_ops gart_dma_ops = {
        .map_sg                         = gart_map_sg,
        .unmap_sg                       = gart_unmap_sg,
+       .map_page                       = gart_map_page,
+       .unmap_page                     = gart_unmap_page,
        .alloc_coherent                 = gart_alloc_coherent,
        .free_coherent                  = gart_free_coherent,
 };
index c70ab5a5d4c886a0856de8e0f313a97048d2c328..c6d703b393261c2e5f45002b188b4d56638bc530 100644 (file)
@@ -1,14 +1,14 @@
 /* Fallback functions when the main IOMMU code is not compiled in. This
    code is roughly equivalent to i386. */
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/string.h>
 #include <linux/dma-mapping.h>
 #include <linux/scatterlist.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/mm.h>
 
-#include <asm/iommu.h>
 #include <asm/processor.h>
+#include <asm/iommu.h>
 #include <asm/dma.h>
 
 static int
@@ -25,19 +25,19 @@ check_addr(char *name, struct device *hwdev, dma_addr_t bus, size_t size)
        return 1;
 }
 
-static dma_addr_t
-nommu_map_single(struct device *hwdev, phys_addr_t paddr, size_t size,
-              int direction)
+static dma_addr_t nommu_map_page(struct device *dev, struct page *page,
+                                unsigned long offset, size_t size,
+                                enum dma_data_direction dir,
+                                struct dma_attrs *attrs)
 {
-       dma_addr_t bus = paddr;
+       dma_addr_t bus = page_to_phys(page) + offset;
        WARN_ON(size == 0);
-       if (!check_addr("map_single", hwdev, bus, size))
-                               return bad_dma_address;
+       if (!check_addr("map_single", dev, bus, size))
+               return bad_dma_address;
        flush_write_buffers();
        return bus;
 }
 
-
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scatter-gather version of the
  * above pci_map_single interface.  Here the scatter gather list
@@ -54,7 +54,8 @@ nommu_map_single(struct device *hwdev, phys_addr_t paddr, size_t size,
  * the same here.
  */
 static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
-              int nents, int direction)
+                       int nents, enum dma_data_direction dir,
+                       struct dma_attrs *attrs)
 {
        struct scatterlist *s;
        int i;
@@ -78,12 +79,12 @@ static void nommu_free_coherent(struct device *dev, size_t size, void *vaddr,
        free_pages((unsigned long)vaddr, get_order(size));
 }
 
-struct dma_mapping_ops nommu_dma_ops = {
-       .alloc_coherent = dma_generic_alloc_coherent,
-       .free_coherent = nommu_free_coherent,
-       .map_single = nommu_map_single,
-       .map_sg = nommu_map_sg,
-       .is_phys = 1,
+struct dma_map_ops nommu_dma_ops = {
+       .alloc_coherent = dma_generic_alloc_coherent,
+       .free_coherent  = nommu_free_coherent,
+       .map_sg         = nommu_map_sg,
+       .map_page       = nommu_map_page,
+       .is_phys        = 1,
 };
 
 void __init no_iommu_init(void)
similarity index 81%
rename from arch/x86/kernel/pci-swiotlb_64.c
rename to arch/x86/kernel/pci-swiotlb.c
index d59c9174766586c01f3377a13a7763cb716eceeb..34f12e9996ed84126ff95b0eb9c0975d56ef9a73 100644 (file)
@@ -33,18 +33,11 @@ phys_addr_t swiotlb_bus_to_phys(dma_addr_t baddr)
        return baddr;
 }
 
-int __weak swiotlb_arch_range_needs_mapping(void *ptr, size_t size)
+int __weak swiotlb_arch_range_needs_mapping(phys_addr_t paddr, size_t size)
 {
        return 0;
 }
 
-static dma_addr_t
-swiotlb_map_single_phys(struct device *hwdev, phys_addr_t paddr, size_t size,
-                       int direction)
-{
-       return swiotlb_map_single(hwdev, phys_to_virt(paddr), size, direction);
-}
-
 static void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                                        dma_addr_t *dma_handle, gfp_t flags)
 {
@@ -57,20 +50,20 @@ static void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
        return swiotlb_alloc_coherent(hwdev, size, dma_handle, flags);
 }
 
-struct dma_mapping_ops swiotlb_dma_ops = {
+struct dma_map_ops swiotlb_dma_ops = {
        .mapping_error = swiotlb_dma_mapping_error,
        .alloc_coherent = x86_swiotlb_alloc_coherent,
        .free_coherent = swiotlb_free_coherent,
-       .map_single = swiotlb_map_single_phys,
-       .unmap_single = swiotlb_unmap_single,
        .sync_single_for_cpu = swiotlb_sync_single_for_cpu,
        .sync_single_for_device = swiotlb_sync_single_for_device,
        .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,
-       .map_sg = swiotlb_map_sg,
-       .unmap_sg = swiotlb_unmap_sg,
+       .map_sg = swiotlb_map_sg_attrs,
+       .unmap_sg = swiotlb_unmap_sg_attrs,
+       .map_page = swiotlb_map_page,
+       .unmap_page = swiotlb_unmap_page,
        .dma_supported = NULL,
 };
 
index 6afa5232dbb739f99c07ff0641cc265428db74eb..156f87582c6cd5e0fcb677b7c685d92c68443d72 100644 (file)
@@ -65,11 +65,11 @@ void exit_thread(void)
 {
        struct task_struct *me = current;
        struct thread_struct *t = &me->thread;
+       unsigned long *bp = t->io_bitmap_ptr;
 
-       if (me->thread.io_bitmap_ptr) {
+       if (bp) {
                struct tss_struct *tss = &per_cpu(init_tss, get_cpu());
 
-               kfree(t->io_bitmap_ptr);
                t->io_bitmap_ptr = NULL;
                clear_thread_flag(TIF_IO_BITMAP);
                /*
@@ -78,6 +78,7 @@ void exit_thread(void)
                memset(tss->io_bitmap, 0xff, t->io_bitmap_max);
                t->io_bitmap_max = 0;
                put_cpu();
+               kfree(bp);
        }
 
        ds_exit_thread(current);
index 14014d766cadba461c27705a0626560dc308bb70..76f8f84043a2a4693123648d92d08c22ca7f5f25 100644 (file)
@@ -245,7 +245,7 @@ void prepare_to_copy(struct task_struct *tsk)
        unlazy_fpu(tsk);
 }
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+int copy_thread(unsigned long clone_flags, unsigned long sp,
        unsigned long unused,
        struct task_struct *p, struct pt_regs *regs)
 {
index abb7e6a7f0c62c813de2331349c5aa4a348d14b1..b751a41392b1b997d3c9a3235ba85b2372bdf7a3 100644 (file)
@@ -278,7 +278,7 @@ void prepare_to_copy(struct task_struct *tsk)
        unlazy_fpu(tsk);
 }
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+int copy_thread(unsigned long clone_flags, unsigned long sp,
                unsigned long unused,
        struct task_struct *p, struct pt_regs *regs)
 {
index 3d9672e59c16aeb0b16d0be4d0aae5f1b362f61c..b7cc21bc6ae0e43b1a3f2fb406a60cd4d005a246 100644 (file)
@@ -685,9 +685,8 @@ static int ptrace_bts_config(struct task_struct *child,
                if (!cfg.signal)
                        return -EINVAL;
 
-               return -EOPNOTSUPP;
-
                child->thread.bts_ovfl_signal = cfg.signal;
+               return -EOPNOTSUPP;
        }
 
        if ((cfg.flags & PTRACE_BTS_O_ALLOC) &&
@@ -1456,6 +1455,6 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs)
         * system call instruction.
         */
        if (test_thread_flag(TIF_SINGLESTEP) &&
-           tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL))
+           tracehook_consider_fatal_signal(current, SIGTRAP))
                send_sigtrap(current, regs, 0, TRAP_BRKPT);
 }
index 697d1b78cfbf702eb6ab9cc556bb9e94bc6d357b..e95022e4f5d5e19c6048edd188a29942e1dce49c 100644 (file)
@@ -74,8 +74,7 @@ static void ich_force_hpet_resume(void)
        if (!force_hpet_address)
                return;
 
-       if (rcba_base == NULL)
-               BUG();
+       BUG_ON(rcba_base == NULL);
 
        /* read the Function Disable register, dword mode only */
        val = readl(rcba_base + 0x3404);
index 2064d0aa8d28842f235600428c3c2958f8313723..41235531b11ca894c809f9ae97f4d3c4f14791a4 100644 (file)
@@ -17,7 +17,8 @@
 
 #define PTR(x) (x << 2)
 
-/* control_page + KEXEC_CONTROL_CODE_MAX_SIZE
+/*
+ * control_page + KEXEC_CONTROL_CODE_MAX_SIZE
  * ~ control_page + PAGE_SIZE are used as data storage and stack for
  * jumping back
  */
@@ -76,8 +77,10 @@ relocate_kernel:
        movl    %eax, CP_PA_SWAP_PAGE(%edi)
        movl    %ebx, CP_PA_BACKUP_PAGES_MAP(%edi)
 
-       /* get physical address of control page now */
-       /* this is impossible after page table switch */
+       /*
+        * get physical address of control page now
+        * this is impossible after page table switch
+        */
        movl    PTR(PA_CONTROL_PAGE)(%ebp), %edi
 
        /* switch to new set of page tables */
@@ -97,7 +100,8 @@ identity_mapped:
        /* store the start address on the stack */
        pushl   %edx
 
-       /* Set cr0 to a known state:
+       /*
+        * Set cr0 to a known state:
         *  - Paging disabled
         *  - Alignment check disabled
         *  - Write protect disabled
@@ -113,7 +117,8 @@ identity_mapped:
        /* clear cr4 if applicable */
        testl   %ecx, %ecx
        jz      1f
-       /* Set cr4 to a known state:
+       /*
+        * Set cr4 to a known state:
         * Setting everything to zero seems safe.
         */
        xorl    %eax, %eax
@@ -132,15 +137,18 @@ identity_mapped:
        call    swap_pages
        addl    $8, %esp
 
-       /* To be certain of avoiding problems with self-modifying code
+       /*
+        * To be certain of avoiding problems with self-modifying code
         * I need to execute a serializing instruction here.
         * So I flush the TLB, it's handy, and not processor dependent.
         */
        xorl    %eax, %eax
        movl    %eax, %cr3
 
-       /* set all of the registers to known values */
-       /* leave %esp alone */
+       /*
+        * set all of the registers to known values
+        * leave %esp alone
+        */
 
        testl   %esi, %esi
        jnz 1f
index d32cfb27a479ecbf32be5dca3c87e5a220e59261..4de8f5b3d476ca0aa544e025568cf00cb6c25ebb 100644 (file)
 #define PTR(x) (x << 3)
 #define PAGE_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
 
+/*
+ * control_page + KEXEC_CONTROL_CODE_MAX_SIZE
+ * ~ control_page + PAGE_SIZE are used as data storage and stack for
+ * jumping back
+ */
+#define DATA(offset)           (KEXEC_CONTROL_CODE_MAX_SIZE+(offset))
+
+/* Minimal CPU state */
+#define RSP                    DATA(0x0)
+#define CR0                    DATA(0x8)
+#define CR3                    DATA(0x10)
+#define CR4                    DATA(0x18)
+
+/* other data */
+#define CP_PA_TABLE_PAGE       DATA(0x20)
+#define CP_PA_SWAP_PAGE                DATA(0x28)
+#define CP_PA_BACKUP_PAGES_MAP DATA(0x30)
+
        .text
        .align PAGE_SIZE
        .code64
        .globl relocate_kernel
 relocate_kernel:
-       /* %rdi indirection_page
+       /*
+        * %rdi indirection_page
         * %rsi page_list
         * %rdx start address
+        * %rcx preserve_context
         */
 
+       /* Save the CPU context, used for jumping back */
+       pushq %rbx
+       pushq %rbp
+       pushq %r12
+       pushq %r13
+       pushq %r14
+       pushq %r15
+       pushf
+
+       movq    PTR(VA_CONTROL_PAGE)(%rsi), %r11
+       movq    %rsp, RSP(%r11)
+       movq    %cr0, %rax
+       movq    %rax, CR0(%r11)
+       movq    %cr3, %rax
+       movq    %rax, CR3(%r11)
+       movq    %cr4, %rax
+       movq    %rax, CR4(%r11)
+
        /* zero out flags, and disable interrupts */
        pushq $0
        popfq
 
-       /* get physical address of control page now */
-       /* this is impossible after page table switch */
+       /*
+        * get physical address of control page now
+        * this is impossible after page table switch
+        */
        movq    PTR(PA_CONTROL_PAGE)(%rsi), %r8
 
        /* get physical address of page table now too */
-       movq    PTR(PA_TABLE_PAGE)(%rsi), %rcx
+       movq    PTR(PA_TABLE_PAGE)(%rsi), %r9
+
+       /* get physical address of swap page now */
+       movq    PTR(PA_SWAP_PAGE)(%rsi), %r10
+
+       /* save some information for jumping back */
+       movq    %r9, CP_PA_TABLE_PAGE(%r11)
+       movq    %r10, CP_PA_SWAP_PAGE(%r11)
+       movq    %rdi, CP_PA_BACKUP_PAGES_MAP(%r11)
 
        /* Switch to the identity mapped page tables */
-       movq    %rcx, %cr3
+       movq    %r9, %cr3
 
        /* setup a new stack at the end of the physical control page */
        lea     PAGE_SIZE(%r8), %rsp
@@ -55,7 +103,8 @@ identity_mapped:
        /* store the start address on the stack */
        pushq   %rdx
 
-       /* Set cr0 to a known state:
+       /*
+        * Set cr0 to a known state:
         *  - Paging enabled
         *  - Alignment check disabled
         *  - Write protect disabled
@@ -68,7 +117,8 @@ identity_mapped:
        orl     $(X86_CR0_PG | X86_CR0_PE), %eax
        movq    %rax, %cr0
 
-       /* Set cr4 to a known state:
+       /*
+        * Set cr4 to a known state:
         *  - physical address extension enabled
         */
        movq    $X86_CR4_PAE, %rax
@@ -78,9 +128,87 @@ identity_mapped:
 1:
 
        /* Flush the TLB (needed?) */
-       movq    %rcx, %cr3
+       movq    %r9, %cr3
+
+       movq    %rcx, %r11
+       call    swap_pages
+
+       /*
+        * To be certain of avoiding problems with self-modifying code
+        * I need to execute a serializing instruction here.
+        * So I flush the TLB by reloading %cr3 here, it's handy,
+        * and not processor dependent.
+        */
+       movq    %cr3, %rax
+       movq    %rax, %cr3
+
+       /*
+        * set all of the registers to known values
+        * leave %rsp alone
+        */
+
+       testq   %r11, %r11
+       jnz 1f
+       xorq    %rax, %rax
+       xorq    %rbx, %rbx
+       xorq    %rcx, %rcx
+       xorq    %rdx, %rdx
+       xorq    %rsi, %rsi
+       xorq    %rdi, %rdi
+       xorq    %rbp, %rbp
+       xorq    %r8,  %r8
+       xorq    %r9,  %r9
+       xorq    %r10, %r9
+       xorq    %r11, %r11
+       xorq    %r12, %r12
+       xorq    %r13, %r13
+       xorq    %r14, %r14
+       xorq    %r15, %r15
+
+       ret
+
+1:
+       popq    %rdx
+       leaq    PAGE_SIZE(%r10), %rsp
+       call    *%rdx
+
+       /* get the re-entry point of the peer system */
+       movq    0(%rsp), %rbp
+       call    1f
+1:
+       popq    %r8
+       subq    $(1b - relocate_kernel), %r8
+       movq    CP_PA_SWAP_PAGE(%r8), %r10
+       movq    CP_PA_BACKUP_PAGES_MAP(%r8), %rdi
+       movq    CP_PA_TABLE_PAGE(%r8), %rax
+       movq    %rax, %cr3
+       lea     PAGE_SIZE(%r8), %rsp
+       call    swap_pages
+       movq    $virtual_mapped, %rax
+       pushq   %rax
+       ret
+
+virtual_mapped:
+       movq    RSP(%r8), %rsp
+       movq    CR4(%r8), %rax
+       movq    %rax, %cr4
+       movq    CR3(%r8), %rax
+       movq    CR0(%r8), %r8
+       movq    %rax, %cr3
+       movq    %r8, %cr0
+       movq    %rbp, %rax
+
+       popf
+       popq    %r15
+       popq    %r14
+       popq    %r13
+       popq    %r12
+       popq    %rbp
+       popq    %rbx
+       ret
 
        /* Do the copies */
+swap_pages:
        movq    %rdi, %rcx      /* Put the page_list in %rcx */
        xorq    %rdi, %rdi
        xorq    %rsi, %rsi
@@ -112,36 +240,27 @@ identity_mapped:
        movq    %rcx,   %rsi  /* For ever source page do a copy */
        andq    $0xfffffffffffff000, %rsi
 
+       movq    %rdi, %rdx
+       movq    %rsi, %rax
+
+       movq    %r10, %rdi
        movq    $512,   %rcx
        rep ; movsq
-       jmp     0b
-3:
-
-       /* To be certain of avoiding problems with self-modifying code
-        * I need to execute a serializing instruction here.
-        * So I flush the TLB by reloading %cr3 here, it's handy,
-        * and not processor dependent.
-        */
-       movq    %cr3, %rax
-       movq    %rax, %cr3
 
-       /* set all of the registers to known values */
-       /* leave %rsp alone */
+       movq    %rax, %rdi
+       movq    %rdx, %rsi
+       movq    $512,   %rcx
+       rep ; movsq
 
-       xorq    %rax, %rax
-       xorq    %rbx, %rbx
-       xorq    %rcx, %rcx
-       xorq    %rdx, %rdx
-       xorq    %rsi, %rsi
-       xorq    %rdi, %rdi
-       xorq    %rbp, %rbp
-       xorq    %r8,  %r8
-       xorq    %r9,  %r9
-       xorq    %r10, %r9
-       xorq    %r11, %r11
-       xorq    %r12, %r12
-       xorq    %r13, %r13
-       xorq    %r14, %r14
-       xorq    %r15, %r15
+       movq    %rdx, %rdi
+       movq    %r10, %rsi
+       movq    $512,   %rcx
+       rep ; movsq
 
+       lea     PAGE_SIZE(%rax), %rsi
+       jmp     0b
+3:
        ret
+
+       .globl kexec_control_code_size
+.set kexec_control_code_size, . - relocate_kernel
index dd6f2b71561bfbdc245e78cae8cfac30d44d425e..5d465b207e72c3bfae75b29f6d0e1dcb3365e6b4 100644 (file)
@@ -1,14 +1,14 @@
 /*
  * RTC related functions
  */
+#include <linux/platform_device.h>
+#include <linux/mc146818rtc.h>
 #include <linux/acpi.h>
 #include <linux/bcd.h>
-#include <linux/mc146818rtc.h>
-#include <linux/platform_device.h>
 #include <linux/pnp.h>
 
-#include <asm/time.h>
 #include <asm/vsyscall.h>
+#include <asm/time.h>
 
 #ifdef CONFIG_X86_32
 /*
@@ -16,9 +16,9 @@
  * register we are working with.  It is required for NMI access to the
  * CMOS/RTC registers.  See include/asm-i386/mc146818rtc.h for details.
  */
-volatile unsigned long cmos_lock = 0;
+volatile unsigned long cmos_lock;
 EXPORT_SYMBOL(cmos_lock);
-#endif
+#endif /* CONFIG_X86_32 */
 
 /* For two digit years assume time is always after that */
 #define CMOS_YEARS_OFFS 2000
@@ -38,9 +38,9 @@ EXPORT_SYMBOL(rtc_lock);
  */
 int mach_set_rtc_mmss(unsigned long nowtime)
 {
-       int retval = 0;
        int real_seconds, real_minutes, cmos_minutes;
        unsigned char save_control, save_freq_select;
+       int retval = 0;
 
         /* tell the clock it's being set */
        save_control = CMOS_READ(RTC_CONTROL);
@@ -72,8 +72,8 @@ int mach_set_rtc_mmss(unsigned long nowtime)
                        real_seconds = bin2bcd(real_seconds);
                        real_minutes = bin2bcd(real_minutes);
                }
-               CMOS_WRITE(real_seconds,RTC_SECONDS);
-               CMOS_WRITE(real_minutes,RTC_MINUTES);
+               CMOS_WRITE(real_seconds, RTC_SECONDS);
+               CMOS_WRITE(real_minutes, RTC_MINUTES);
        } else {
                printk(KERN_WARNING
                       "set_rtc_mmss: can't update from %d to %d\n",
@@ -151,6 +151,7 @@ unsigned char rtc_cmos_read(unsigned char addr)
        outb(addr, RTC_PORT(0));
        val = inb(RTC_PORT(1));
        lock_cmos_suffix(addr);
+
        return val;
 }
 EXPORT_SYMBOL(rtc_cmos_read);
@@ -166,8 +167,8 @@ EXPORT_SYMBOL(rtc_cmos_write);
 
 static int set_rtc_mmss(unsigned long nowtime)
 {
-       int retval;
        unsigned long flags;
+       int retval;
 
        spin_lock_irqsave(&rtc_lock, flags);
        retval = set_wallclock(nowtime);
@@ -242,6 +243,7 @@ static __init int add_rtc_cmos(void)
        platform_device_register(&rtc_device);
        dev_info(&rtc_device.dev,
                 "registered platform RTC device (no PNP device found)\n");
+
        return 0;
 }
 device_initcall(add_rtc_cmos);
index b746deb9ebc649685c4c167f50e525541b8da292..b4158439bf634d254852cceab2c30d26f943f7ea 100644 (file)
 #define ARCH_SETUP
 #endif
 
+RESERVE_BRK(dmi_alloc, 65536);
+
 unsigned int boot_cpu_id __read_mostly;
 
+static __initdata unsigned long _brk_start = (unsigned long)__brk_base;
+unsigned long _brk_end = (unsigned long)__brk_base;
+
 #ifdef CONFIG_X86_64
 int default_cpu_present_to_apicid(int mps_cpu)
 {
@@ -158,12 +163,6 @@ static struct resource bss_resource = {
 
 
 #ifdef CONFIG_X86_32
-/* This value is set up by the early boot code to point to the value
-   immediately after the boot time page tables.  It contains a *physical*
-   address, and must not be in the .bss segment! */
-unsigned long init_pg_tables_start __initdata = ~0UL;
-unsigned long init_pg_tables_end __initdata = ~0UL;
-
 static struct resource video_ram_resource = {
        .name   = "Video RAM area",
        .start  = 0xa0000,
@@ -202,7 +201,9 @@ struct ist_info ist_info;
 #endif
 
 #else
-struct cpuinfo_x86 boot_cpu_data __read_mostly;
+struct cpuinfo_x86 boot_cpu_data __read_mostly = {
+       .x86_phys_bits = MAX_PHYSMEM_BITS,
+};
 EXPORT_SYMBOL(boot_cpu_data);
 #endif
 
@@ -216,12 +217,6 @@ unsigned long mmu_cr4_features = X86_CR4_PAE;
 /* Boot loader ID as an integer, for the benefit of proc_dointvec */
 int bootloader_type;
 
-/*
- * Early DMI memory
- */
-int dmi_alloc_index;
-char dmi_alloc_data[DMI_MAX_DATA];
-
 /*
  * Setup options
  */
@@ -267,6 +262,35 @@ static inline void copy_edd(void)
 }
 #endif
 
+void * __init extend_brk(size_t size, size_t align)
+{
+       size_t mask = align - 1;
+       void *ret;
+
+       BUG_ON(_brk_start == 0);
+       BUG_ON(align & mask);
+
+       _brk_end = (_brk_end + mask) & ~mask;
+       BUG_ON((char *)(_brk_end + size) > __brk_limit);
+
+       ret = (void *)_brk_end;
+       _brk_end += size;
+
+       memset(ret, 0, size);
+
+       return ret;
+}
+
+static void __init reserve_brk(void)
+{
+       if (_brk_end > _brk_start)
+               reserve_early(__pa(_brk_start), __pa(_brk_end), "BRK");
+
+       /* Mark brk area as locked down and no longer taking any
+          new allocations */
+       _brk_start = 0;
+}
+
 #ifdef CONFIG_BLK_DEV_INITRD
 
 #ifdef CONFIG_X86_32
@@ -715,11 +739,7 @@ void __init setup_arch(char **cmdline_p)
        init_mm.start_code = (unsigned long) _text;
        init_mm.end_code = (unsigned long) _etext;
        init_mm.end_data = (unsigned long) _edata;
-#ifdef CONFIG_X86_32
-       init_mm.brk = init_pg_tables_end + PAGE_OFFSET;
-#else
-       init_mm.brk = (unsigned long) &_end;
-#endif
+       init_mm.brk = _brk_end;
 
        code_resource.start = virt_to_phys(_text);
        code_resource.end = virt_to_phys(_etext)-1;
@@ -840,6 +860,8 @@ void __init setup_arch(char **cmdline_p)
        setup_bios_corruption_check();
 #endif
 
+       reserve_brk();
+
        /* max_pfn_mapped is updated here */
        max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT);
        max_pfn_mapped = max_low_pfn_mapped;
@@ -1027,7 +1049,6 @@ void __init x86_quirk_trap_init(void)
 static struct irqaction irq0  = {
        .handler = timer_interrupt,
        .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
-       .mask = CPU_MASK_NONE,
        .name = "timer"
 };
 
index d2cc6428c5875a6103a00757eeeec9ff0831508f..dfcc74ab0ab64f922c12717ada6a248408593a75 100644 (file)
@@ -211,31 +211,27 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
 {
        /* Default to using normal stack */
        unsigned long sp = regs->sp;
+       int onsigstack = on_sig_stack(sp);
 
 #ifdef CONFIG_X86_64
        /* redzone */
        sp -= 128;
 #endif /* CONFIG_X86_64 */
 
-       /*
-        * If we are on the alternate signal stack and would overflow it, don't.
-        * Return an always-bogus address instead so we will die with SIGSEGV.
-        */
-       if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size)))
-               return (void __user *) -1L;
-
-       /* This is the X/Open sanctioned signal stack switching.  */
-       if (ka->sa.sa_flags & SA_ONSTACK) {
-               if (sas_ss_flags(sp) == 0)
-                       sp = current->sas_ss_sp + current->sas_ss_size;
-       } else {
+       if (!onsigstack) {
+               /* This is the X/Open sanctioned signal stack switching.  */
+               if (ka->sa.sa_flags & SA_ONSTACK) {
+                       if (sas_ss_flags(sp) == 0)
+                               sp = current->sas_ss_sp + current->sas_ss_size;
+               } else {
 #ifdef CONFIG_X86_32
-               /* This is the legacy signal stack switching. */
-               if ((regs->ss & 0xffff) != __USER_DS &&
-                       !(ka->sa.sa_flags & SA_RESTORER) &&
-                               ka->sa.sa_restorer)
-                       sp = (unsigned long) ka->sa.sa_restorer;
+                       /* This is the legacy signal stack switching. */
+                       if ((regs->ss & 0xffff) != __USER_DS &&
+                               !(ka->sa.sa_flags & SA_RESTORER) &&
+                                       ka->sa.sa_restorer)
+                               sp = (unsigned long) ka->sa.sa_restorer;
 #endif /* CONFIG_X86_32 */
+               }
        }
 
        if (used_math()) {
@@ -244,12 +240,22 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
                sp = round_down(sp, 64);
 #endif /* CONFIG_X86_64 */
                *fpstate = (void __user *)sp;
-
-               if (save_i387_xstate(*fpstate) < 0)
-                       return (void __user *)-1L;
        }
 
-       return (void __user *)align_sigframe(sp - frame_size);
+       sp = align_sigframe(sp - frame_size);
+
+       /*
+        * If we are on the alternate signal stack and would overflow it, don't.
+        * Return an always-bogus address instead so we will die with SIGSEGV.
+        */
+       if (onsigstack && !likely(on_sig_stack(sp)))
+               return (void __user *)-1L;
+
+       /* save i387 state */
+       if (used_math() && save_i387_xstate(*fpstate) < 0)
+               return (void __user *)-1L;
+
+       return (void __user *)sp;
 }
 
 #ifdef CONFIG_X86_32
index 249334f5080a16d2e5a6e2c4fb67a8c19be88891..ef7d10170c30d1e98291cfdb0b4d0f17eda49b28 100644 (file)
@@ -114,10 +114,6 @@ EXPORT_PER_CPU_SYMBOL(cpu_info);
 
 atomic_t init_deasserted;
 
-
-/* Set if we find a B stepping CPU */
-static int __cpuinitdata smp_b_stepping;
-
 #if defined(CONFIG_NUMA) && defined(CONFIG_X86_32)
 
 /* which logical CPUs are on which nodes */
@@ -271,8 +267,6 @@ static void __cpuinit smp_callin(void)
        cpumask_set_cpu(cpuid, cpu_callin_mask);
 }
 
-static int __cpuinitdata unsafe_smp;
-
 /*
  * Activate a secondary processor.
  */
@@ -340,76 +334,6 @@ notrace static void __cpuinit start_secondary(void *unused)
        cpu_idle();
 }
 
-static void __cpuinit smp_apply_quirks(struct cpuinfo_x86 *c)
-{
-       /*
-        * Mask B, Pentium, but not Pentium MMX
-        */
-       if (c->x86_vendor == X86_VENDOR_INTEL &&
-           c->x86 == 5 &&
-           c->x86_mask >= 1 && c->x86_mask <= 4 &&
-           c->x86_model <= 3)
-               /*
-                * Remember we have B step Pentia with bugs
-                */
-               smp_b_stepping = 1;
-
-       /*
-        * Certain Athlons might work (for various values of 'work') in SMP
-        * but they are not certified as MP capable.
-        */
-       if ((c->x86_vendor == X86_VENDOR_AMD) && (c->x86 == 6)) {
-
-               if (num_possible_cpus() == 1)
-                       goto valid_k7;
-
-               /* Athlon 660/661 is valid. */
-               if ((c->x86_model == 6) && ((c->x86_mask == 0) ||
-                   (c->x86_mask == 1)))
-                       goto valid_k7;
-
-               /* Duron 670 is valid */
-               if ((c->x86_model == 7) && (c->x86_mask == 0))
-                       goto valid_k7;
-
-               /*
-                * Athlon 662, Duron 671, and Athlon >model 7 have capability
-                * bit. It's worth noting that the A5 stepping (662) of some
-                * Athlon XP's have the MP bit set.
-                * See http://www.heise.de/newsticker/data/jow-18.10.01-000 for
-                * more.
-                */
-               if (((c->x86_model == 6) && (c->x86_mask >= 2)) ||
-                   ((c->x86_model == 7) && (c->x86_mask >= 1)) ||
-                    (c->x86_model > 7))
-                       if (cpu_has_mp)
-                               goto valid_k7;
-
-               /* If we get here, not a certified SMP capable AMD system. */
-               unsafe_smp = 1;
-       }
-
-valid_k7:
-       ;
-}
-
-static void __cpuinit smp_checks(void)
-{
-       if (smp_b_stepping)
-               printk(KERN_WARNING "WARNING: SMP operation may be unreliable"
-                                   "with B stepping processors.\n");
-
-       /*
-        * Don't taint if we are running SMP kernel on a single non-MP
-        * approved Athlon
-        */
-       if (unsafe_smp && num_online_cpus() > 1) {
-               printk(KERN_INFO "WARNING: This combination of AMD"
-                       "processors is not suitable for SMP.\n");
-               add_taint(TAINT_UNSAFE_SMP);
-       }
-}
-
 /*
  * The bootstrap kernel entry code has set these up. Save them for
  * a given CPU
@@ -423,7 +347,6 @@ void __cpuinit smp_store_cpu_info(int id)
        c->cpu_index = id;
        if (id != 0)
                identify_secondary_cpu(c);
-       smp_apply_quirks(c);
 }
 
 
@@ -1193,7 +1116,6 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
        pr_debug("Boot done.\n");
 
        impress_friends();
-       smp_checks();
 #ifdef CONFIG_X86_IO_APIC
        setup_ioapic_dest();
 #endif
index 3bdb64829b82718f42bafed884f55d1dbe9e65a2..ff5c8736b491b8ff2c4835c5a19a51ad63633de1 100644 (file)
@@ -332,3 +332,5 @@ ENTRY(sys_call_table)
        .long sys_dup3                  /* 330 */
        .long sys_pipe2
        .long sys_inotify_init1
+       .long sys_preadv
+       .long sys_pwritev
index 241ec3923f611bf03cb266362409924daabf1f6f..5ba343e6184449775c51f21717ef985f8d7249d0 100644 (file)
@@ -116,7 +116,6 @@ unsigned long __init calibrate_cpu(void)
 static struct irqaction irq0 = {
        .handler        = timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING | IRQF_TIMER,
-       .mask           = CPU_MASK_NONE,
        .name           = "timer"
 };
 
@@ -125,7 +124,6 @@ void __init hpet_time_init(void)
        if (!hpet_enable())
                setup_pit_timer();
 
-       irq0.mask = cpumask_of_cpu(0);
        setup_irq(0, &irq0);
 }
 
index d038b9c45cf89597e10ab05d1814b2557b606994..79c073247284cbdb334cf2a03b4e7ffaae8d0bcd 100644 (file)
@@ -750,7 +750,7 @@ static int __init uv_bau_init(void)
        int node;
        int nblades;
        int last_blade;
-       int cur_cpu = 0;
+       int cur_cpu;
 
        if (!is_uv_system())
                return 0;
@@ -760,6 +760,7 @@ static int __init uv_bau_init(void)
        uv_mmask = (1UL << uv_hub_info->n_val) - 1;
        nblades = 0;
        last_blade = -1;
+       cur_cpu = 0;
        for_each_online_node(node) {
                blade = uv_node_to_blade_id(node);
                if (blade == last_blade)
index 0fcc95a354f7c28d980bf45fffd777c01a3ace25..7e4515957a1c89ad4980f7aa119120ee4d7cfa2a 100644 (file)
  *
  * Send feedback to <colpatch@us.ibm.com>
  */
-#include <linux/init.h>
-#include <linux/smp.h>
 #include <linux/nodemask.h>
 #include <linux/mmzone.h>
+#include <linux/init.h>
+#include <linux/smp.h>
 #include <asm/cpu.h>
 
 static DEFINE_PER_CPU(struct x86_cpu, cpu_devices);
@@ -47,6 +47,7 @@ int __ref arch_register_cpu(int num)
         */
        if (num)
                per_cpu(cpu_devices, num).cpu.hotpluggable = 1;
+
        return register_cpu(&per_cpu(cpu_devices, num).cpu, num);
 }
 EXPORT_SYMBOL(arch_register_cpu);
@@ -56,12 +57,13 @@ void arch_unregister_cpu(int num)
        unregister_cpu(&per_cpu(cpu_devices, num).cpu);
 }
 EXPORT_SYMBOL(arch_unregister_cpu);
-#else
+#else /* CONFIG_HOTPLUG_CPU */
+
 static int __init arch_register_cpu(int num)
 {
        return register_cpu(&per_cpu(cpu_devices, num).cpu, num);
 }
-#endif /*CONFIG_HOTPLUG_CPU*/
+#endif /* CONFIG_HOTPLUG_CPU */
 
 static int __init topology_init(void)
 {
@@ -70,11 +72,11 @@ static int __init topology_init(void)
 #ifdef CONFIG_NUMA
        for_each_online_node(i)
                register_one_node(i);
-#endif /* CONFIG_NUMA */
+#endif
 
        for_each_present_cpu(i)
                arch_register_cpu(i);
+
        return 0;
 }
-
 subsys_initcall(topology_init);
diff --git a/arch/x86/kernel/uv_time.c b/arch/x86/kernel/uv_time.c
new file mode 100644 (file)
index 0000000..2ffb6c5
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * SGI RTC clock/timer routines.
+ *
+ *  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
+ *
+ *  Copyright (c) 2009 Silicon Graphics, Inc.  All Rights Reserved.
+ *  Copyright (c) Dimitri Sivanich
+ */
+#include <linux/clockchips.h>
+
+#include <asm/uv/uv_mmrs.h>
+#include <asm/uv/uv_hub.h>
+#include <asm/uv/bios.h>
+#include <asm/uv/uv.h>
+#include <asm/apic.h>
+#include <asm/cpu.h>
+
+#define RTC_NAME               "sgi_rtc"
+
+static cycle_t uv_read_rtc(void);
+static int uv_rtc_next_event(unsigned long, struct clock_event_device *);
+static void uv_rtc_timer_setup(enum clock_event_mode,
+                               struct clock_event_device *);
+
+static struct clocksource clocksource_uv = {
+       .name           = RTC_NAME,
+       .rating         = 400,
+       .read           = uv_read_rtc,
+       .mask           = (cycle_t)UVH_RTC_REAL_TIME_CLOCK_MASK,
+       .shift          = 10,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static struct clock_event_device clock_event_device_uv = {
+       .name           = RTC_NAME,
+       .features       = CLOCK_EVT_FEAT_ONESHOT,
+       .shift          = 20,
+       .rating         = 400,
+       .irq            = -1,
+       .set_next_event = uv_rtc_next_event,
+       .set_mode       = uv_rtc_timer_setup,
+       .event_handler  = NULL,
+};
+
+static DEFINE_PER_CPU(struct clock_event_device, cpu_ced);
+
+/* There is one of these allocated per node */
+struct uv_rtc_timer_head {
+       spinlock_t      lock;
+       /* next cpu waiting for timer, local node relative: */
+       int             next_cpu;
+       /* number of cpus on this node: */
+       int             ncpus;
+       struct {
+               int     lcpu;           /* systemwide logical cpu number */
+               u64     expires;        /* next timer expiration for this cpu */
+       } cpu[1];
+};
+
+/*
+ * Access to uv_rtc_timer_head via blade id.
+ */
+static struct uv_rtc_timer_head                **blade_info __read_mostly;
+
+static int                             uv_rtc_enable;
+
+/*
+ * Hardware interface routines
+ */
+
+/* Send IPIs to another node */
+static void uv_rtc_send_IPI(int cpu)
+{
+       unsigned long apicid, val;
+       int pnode;
+
+       apicid = cpu_physical_id(cpu);
+       pnode = uv_apicid_to_pnode(apicid);
+       val = (1UL << UVH_IPI_INT_SEND_SHFT) |
+             (apicid << UVH_IPI_INT_APIC_ID_SHFT) |
+             (GENERIC_INTERRUPT_VECTOR << UVH_IPI_INT_VECTOR_SHFT);
+
+       uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
+}
+
+/* Check for an RTC interrupt pending */
+static int uv_intr_pending(int pnode)
+{
+       return uv_read_global_mmr64(pnode, UVH_EVENT_OCCURRED0) &
+               UVH_EVENT_OCCURRED0_RTC1_MASK;
+}
+
+/* Setup interrupt and return non-zero if early expiration occurred. */
+static int uv_setup_intr(int cpu, u64 expires)
+{
+       u64 val;
+       int pnode = uv_cpu_to_pnode(cpu);
+
+       uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG,
+               UVH_RTC1_INT_CONFIG_M_MASK);
+       uv_write_global_mmr64(pnode, UVH_INT_CMPB, -1L);
+
+       uv_write_global_mmr64(pnode, UVH_EVENT_OCCURRED0_ALIAS,
+               UVH_EVENT_OCCURRED0_RTC1_MASK);
+
+       val = (GENERIC_INTERRUPT_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) |
+               ((u64)cpu_physical_id(cpu) << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT);
+
+       /* Set configuration */
+       uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG, val);
+       /* Initialize comparator value */
+       uv_write_global_mmr64(pnode, UVH_INT_CMPB, expires);
+
+       return (expires < uv_read_rtc() && !uv_intr_pending(pnode));
+}
+
+/*
+ * Per-cpu timer tracking routines
+ */
+
+static __init void uv_rtc_deallocate_timers(void)
+{
+       int bid;
+
+       for_each_possible_blade(bid) {
+               kfree(blade_info[bid]);
+       }
+       kfree(blade_info);
+}
+
+/* Allocate per-node list of cpu timer expiration times. */
+static __init int uv_rtc_allocate_timers(void)
+{
+       int cpu;
+
+       blade_info = kmalloc(uv_possible_blades * sizeof(void *), GFP_KERNEL);
+       if (!blade_info)
+               return -ENOMEM;
+       memset(blade_info, 0, uv_possible_blades * sizeof(void *));
+
+       for_each_present_cpu(cpu) {
+               int nid = cpu_to_node(cpu);
+               int bid = uv_cpu_to_blade_id(cpu);
+               int bcpu = uv_cpu_hub_info(cpu)->blade_processor_id;
+               struct uv_rtc_timer_head *head = blade_info[bid];
+
+               if (!head) {
+                       head = kmalloc_node(sizeof(struct uv_rtc_timer_head) +
+                               (uv_blade_nr_possible_cpus(bid) *
+                                       2 * sizeof(u64)),
+                               GFP_KERNEL, nid);
+                       if (!head) {
+                               uv_rtc_deallocate_timers();
+                               return -ENOMEM;
+                       }
+                       spin_lock_init(&head->lock);
+                       head->ncpus = uv_blade_nr_possible_cpus(bid);
+                       head->next_cpu = -1;
+                       blade_info[bid] = head;
+               }
+
+               head->cpu[bcpu].lcpu = cpu;
+               head->cpu[bcpu].expires = ULLONG_MAX;
+       }
+
+       return 0;
+}
+
+/* Find and set the next expiring timer.  */
+static void uv_rtc_find_next_timer(struct uv_rtc_timer_head *head, int pnode)
+{
+       u64 lowest = ULLONG_MAX;
+       int c, bcpu = -1;
+
+       head->next_cpu = -1;
+       for (c = 0; c < head->ncpus; c++) {
+               u64 exp = head->cpu[c].expires;
+               if (exp < lowest) {
+                       bcpu = c;
+                       lowest = exp;
+               }
+       }
+       if (bcpu >= 0) {
+               head->next_cpu = bcpu;
+               c = head->cpu[bcpu].lcpu;
+               if (uv_setup_intr(c, lowest))
+                       /* If we didn't set it up in time, trigger */
+                       uv_rtc_send_IPI(c);
+       } else {
+               uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG,
+                       UVH_RTC1_INT_CONFIG_M_MASK);
+       }
+}
+
+/*
+ * Set expiration time for current cpu.
+ *
+ * Returns 1 if we missed the expiration time.
+ */
+static int uv_rtc_set_timer(int cpu, u64 expires)
+{
+       int pnode = uv_cpu_to_pnode(cpu);
+       int bid = uv_cpu_to_blade_id(cpu);
+       struct uv_rtc_timer_head *head = blade_info[bid];
+       int bcpu = uv_cpu_hub_info(cpu)->blade_processor_id;
+       u64 *t = &head->cpu[bcpu].expires;
+       unsigned long flags;
+       int next_cpu;
+
+       spin_lock_irqsave(&head->lock, flags);
+
+       next_cpu = head->next_cpu;
+       *t = expires;
+       /* Will this one be next to go off? */
+       if (next_cpu < 0 || bcpu == next_cpu ||
+                       expires < head->cpu[next_cpu].expires) {
+               head->next_cpu = bcpu;
+               if (uv_setup_intr(cpu, expires)) {
+                       *t = ULLONG_MAX;
+                       uv_rtc_find_next_timer(head, pnode);
+                       spin_unlock_irqrestore(&head->lock, flags);
+                       return 1;
+               }
+       }
+
+       spin_unlock_irqrestore(&head->lock, flags);
+       return 0;
+}
+
+/*
+ * Unset expiration time for current cpu.
+ *
+ * Returns 1 if this timer was pending.
+ */
+static int uv_rtc_unset_timer(int cpu)
+{
+       int pnode = uv_cpu_to_pnode(cpu);
+       int bid = uv_cpu_to_blade_id(cpu);
+       struct uv_rtc_timer_head *head = blade_info[bid];
+       int bcpu = uv_cpu_hub_info(cpu)->blade_processor_id;
+       u64 *t = &head->cpu[bcpu].expires;
+       unsigned long flags;
+       int rc = 0;
+
+       spin_lock_irqsave(&head->lock, flags);
+
+       if (head->next_cpu == bcpu && uv_read_rtc() >= *t)
+               rc = 1;
+
+       *t = ULLONG_MAX;
+
+       /* Was the hardware setup for this timer? */
+       if (head->next_cpu == bcpu)
+               uv_rtc_find_next_timer(head, pnode);
+
+       spin_unlock_irqrestore(&head->lock, flags);
+
+       return rc;
+}
+
+
+/*
+ * Kernel interface routines.
+ */
+
+/*
+ * Read the RTC.
+ */
+static cycle_t uv_read_rtc(void)
+{
+       return (cycle_t)uv_read_local_mmr(UVH_RTC);
+}
+
+/*
+ * Program the next event, relative to now
+ */
+static int uv_rtc_next_event(unsigned long delta,
+                            struct clock_event_device *ced)
+{
+       int ced_cpu = cpumask_first(ced->cpumask);
+
+       return uv_rtc_set_timer(ced_cpu, delta + uv_read_rtc());
+}
+
+/*
+ * Setup the RTC timer in oneshot mode
+ */
+static void uv_rtc_timer_setup(enum clock_event_mode mode,
+                              struct clock_event_device *evt)
+{
+       int ced_cpu = cpumask_first(evt->cpumask);
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+       case CLOCK_EVT_MODE_ONESHOT:
+       case CLOCK_EVT_MODE_RESUME:
+               /* Nothing to do here yet */
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               uv_rtc_unset_timer(ced_cpu);
+               break;
+       }
+}
+
+static void uv_rtc_interrupt(void)
+{
+       struct clock_event_device *ced = &__get_cpu_var(cpu_ced);
+       int cpu = smp_processor_id();
+
+       if (!ced || !ced->event_handler)
+               return;
+
+       if (uv_rtc_unset_timer(cpu) != 1)
+               return;
+
+       ced->event_handler(ced);
+}
+
+static int __init uv_enable_rtc(char *str)
+{
+       uv_rtc_enable = 1;
+
+       return 1;
+}
+__setup("uvrtc", uv_enable_rtc);
+
+static __init void uv_rtc_register_clockevents(struct work_struct *dummy)
+{
+       struct clock_event_device *ced = &__get_cpu_var(cpu_ced);
+
+       *ced = clock_event_device_uv;
+       ced->cpumask = cpumask_of(smp_processor_id());
+       clockevents_register_device(ced);
+}
+
+static __init int uv_rtc_setup_clock(void)
+{
+       int rc;
+
+       if (!uv_rtc_enable || !is_uv_system() || generic_interrupt_extension)
+               return -ENODEV;
+
+       generic_interrupt_extension = uv_rtc_interrupt;
+
+       clocksource_uv.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
+                               clocksource_uv.shift);
+
+       rc = clocksource_register(&clocksource_uv);
+       if (rc) {
+               generic_interrupt_extension = NULL;
+               return rc;
+       }
+
+       /* Setup and register clockevents */
+       rc = uv_rtc_allocate_timers();
+       if (rc) {
+               clocksource_unregister(&clocksource_uv);
+               generic_interrupt_extension = NULL;
+               return rc;
+       }
+
+       clock_event_device_uv.mult = div_sc(sn_rtc_cycles_per_second,
+                               NSEC_PER_SEC, clock_event_device_uv.shift);
+
+       clock_event_device_uv.min_delta_ns = NSEC_PER_SEC /
+                                               sn_rtc_cycles_per_second;
+
+       clock_event_device_uv.max_delta_ns = clocksource_uv.mask *
+                               (NSEC_PER_SEC / sn_rtc_cycles_per_second);
+
+       rc = schedule_on_each_cpu(uv_rtc_register_clockevents);
+       if (rc) {
+               clocksource_unregister(&clocksource_uv);
+               generic_interrupt_extension = NULL;
+               uv_rtc_deallocate_timers();
+       }
+
+       return rc;
+}
+arch_initcall(uv_rtc_setup_clock);
index 191a876e9e879cf2e63a374605421cb0f223628e..31ffc24eec4d6f7e3a84cd7d5a11cc8a5b6e18d2 100644 (file)
@@ -578,7 +578,7 @@ static struct irq_chip piix4_virtual_irq_type = {
 static irqreturn_t piix4_master_intr(int irq, void *dev_id)
 {
        int realirq;
-       irq_desc_t *desc;
+       struct irq_desc *desc;
        unsigned long flags;
 
        spin_lock_irqsave(&i8259A_lock, flags);
index 2cc4a90e2cb3ae35e0b81425ef3f41e159f0a1a3..95deb9f2211e98decb5572e4757bc2cc48f3da18 100644 (file)
@@ -395,11 +395,6 @@ static void vmi_set_pte_atomic(pte_t *ptep, pte_t pteval)
        vmi_ops.update_pte(ptep, VMI_PAGE_PT);
 }
 
-static void vmi_set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
-{
-       vmi_ops.set_pte(pte, ptep, vmi_flags_addr_defer(mm, addr, VMI_PAGE_PT, 1));
-}
-
 static void vmi_set_pud(pud_t *pudp, pud_t pudval)
 {
        /* Um, eww */
@@ -750,7 +745,6 @@ static inline int __init activate_vmi(void)
                pv_mmu_ops.set_pmd = vmi_set_pmd;
 #ifdef CONFIG_X86_PAE
                pv_mmu_ops.set_pte_atomic = vmi_set_pte_atomic;
-               pv_mmu_ops.set_pte_present = vmi_set_pte_present;
                pv_mmu_ops.set_pud = vmi_set_pud;
                pv_mmu_ops.pte_clear = vmi_pte_clear;
                pv_mmu_ops.pmd_clear = vmi_pmd_clear;
index 33a788d5879c3186182201736330723fa3669164..d303369a7baddc48966443fff136f2266f010810 100644 (file)
@@ -202,7 +202,6 @@ static struct irqaction vmi_clock_action  = {
        .name           = "vmi-timer",
        .handler        = vmi_timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
-       .mask           = CPU_MASK_ALL,
 };
 
 static void __devinit vmi_time_init_clockevent(void)
index 0d860963f268f5a79c1198a6dffba0fee22f897d..62ad500d55f3e18bb2a405624a5890836f805398 100644 (file)
@@ -189,15 +189,24 @@ SECTIONS
        *(.bss)
        . = ALIGN(4);
        __bss_stop = .;
-       _end = . ;
-       /* This is where the kernel creates the early boot page tables */
+  }
+
+  .brk : AT(ADDR(.brk) - LOAD_OFFSET) {
        . = ALIGN(PAGE_SIZE);
-       pg0 = . ;
+       __brk_base = . ;
+       . += 64 * 1024 ;        /* 64k alignment slop space */
+       *(.brk_reservation)     /* areas brk users have reserved */
+       __brk_limit = . ;
+  }
+
+  .end : AT(ADDR(.end) - LOAD_OFFSET) {
+       _end = . ;
   }
 
   /* Sections to be discarded */
   /DISCARD/ : {
        *(.exitcall.exit)
+       *(.discard)
        }
 
   STABS_DEBUG
@@ -205,6 +214,12 @@ SECTIONS
   DWARF_DEBUG
 }
 
+/*
+ * Build-time check on the image size:
+ */
+ASSERT((_end - LOAD_OFFSET <= KERNEL_IMAGE_SIZE),
+       "kernel image bigger than KERNEL_IMAGE_SIZE")
+
 #ifdef CONFIG_KEXEC
 /* Link time checks */
 #include <asm/kexec.h>
index fbfced6f6800c11052a7f640fd4edd1d32a2b3a5..c8742507b030bec22bb90fcdcfc12d5dcdb35da7 100644 (file)
@@ -29,8 +29,8 @@ SECTIONS
 {
   . = __START_KERNEL;
   phys_startup_64 = startup_64 - LOAD_OFFSET;
-  _text = .;                   /* Text and read-only data */
   .text :  AT(ADDR(.text) - LOAD_OFFSET) {
+       _text = .;                      /* Text and read-only data */
        /* First the code that has to be first for bootstrapping */
        *(.text.head)
        _stext = .;
@@ -61,13 +61,13 @@ SECTIONS
   .data : AT(ADDR(.data) - LOAD_OFFSET) {
        DATA_DATA
        CONSTRUCTORS
+       _edata = .;                     /* End of data section */
        } :data
 
-  _edata = .;                  /* End of data section */
 
-  . = ALIGN(PAGE_SIZE);
-  . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
   .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
+       . = ALIGN(PAGE_SIZE);
+       . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
        *(.data.cacheline_aligned)
   }
   . = ALIGN(CONFIG_X86_INTERNODE_CACHE_BYTES);
@@ -125,29 +125,29 @@ SECTIONS
 #undef VVIRT_OFFSET
 #undef VVIRT
 
-  . = ALIGN(THREAD_SIZE);      /* init_task */
   .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
+       . = ALIGN(THREAD_SIZE); /* init_task */
        *(.data.init_task)
   }:data.init
 
-  . = ALIGN(PAGE_SIZE);
   .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
+       . = ALIGN(PAGE_SIZE);
        *(.data.page_aligned)
   }
 
-  /* might get freed after init */
-  . = ALIGN(PAGE_SIZE);
-  __smp_alt_begin = .;
-  __smp_locks = .;
   .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
+       /* might get freed after init */
+       . = ALIGN(PAGE_SIZE);
+       __smp_alt_begin = .;
+       __smp_locks = .;
        *(.smp_locks)
+       __smp_locks_end = .;
+       . = ALIGN(PAGE_SIZE);
+       __smp_alt_end = .;
   }
-  __smp_locks_end = .;
-  . = ALIGN(PAGE_SIZE);
-  __smp_alt_end = .;
 
   . = ALIGN(PAGE_SIZE);                /* Init code and data */
-  __init_begin = .;
+  __init_begin = .;    /* paired with __init_end */
   .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
        _sinittext = .;
        INIT_TEXT
@@ -159,40 +159,42 @@ SECTIONS
        __initdata_end = .;
    }
 
-  . = ALIGN(16);
-  __setup_start = .;
-  .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { *(.init.setup) }
-  __setup_end = .;
-  __initcall_start = .;
+  .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) {
+       . = ALIGN(16);
+       __setup_start = .;
+       *(.init.setup)
+       __setup_end = .;
+  }
   .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
+       __initcall_start = .;
        INITCALLS
+       __initcall_end = .;
   }
-  __initcall_end = .;
-  __con_initcall_start = .;
   .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
+       __con_initcall_start = .;
        *(.con_initcall.init)
+       __con_initcall_end = .;
   }
-  __con_initcall_end = .;
-  __x86_cpu_dev_start = .;
   .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
+       __x86_cpu_dev_start = .;
        *(.x86_cpu_dev.init)
+       __x86_cpu_dev_end = .;
   }
-  __x86_cpu_dev_end = .;
   SECURITY_INIT
 
   . = ALIGN(8);
   .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) {
-  __parainstructions = .;
+       __parainstructions = .;
        *(.parainstructions)
-  __parainstructions_end = .;
+       __parainstructions_end = .;
   }
 
-  . = ALIGN(8);
-  __alt_instructions = .;
   .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
+       . = ALIGN(8);
+       __alt_instructions = .;
        *(.altinstructions)
+       __alt_instructions_end = .;
   }
-  __alt_instructions_end = .;
   .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
        *(.altinstr_replacement)
   }
@@ -207,9 +209,11 @@ SECTIONS
 
 #ifdef CONFIG_BLK_DEV_INITRD
   . = ALIGN(PAGE_SIZE);
-  __initramfs_start = .;
-  .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) }
-  __initramfs_end = .;
+  .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
+       __initramfs_start = .;
+       *(.init.ramfs)
+       __initramfs_end = .;
+  }
 #endif
 
 #ifdef CONFIG_SMP
@@ -229,20 +233,29 @@ SECTIONS
   . = ALIGN(PAGE_SIZE);
   __init_end = .;
 
-  . = ALIGN(PAGE_SIZE);
-  __nosave_begin = .;
   .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) {
-      *(.data.nosave)
+       . = ALIGN(PAGE_SIZE);
+       __nosave_begin = .;
+       *(.data.nosave)
+       . = ALIGN(PAGE_SIZE);
+       __nosave_end = .;
   } :data.init2 /* use another section data.init2, see PERCPU_VADDR() above */
-  . = ALIGN(PAGE_SIZE);
-  __nosave_end = .;
 
-  __bss_start = .;             /* BSS */
   .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
+       . = ALIGN(PAGE_SIZE);
+       __bss_start = .;                /* BSS */
        *(.bss.page_aligned)
        *(.bss)
-       }
-  __bss_stop = .;
+       __bss_stop = .;
+  }
+
+  .brk : AT(ADDR(.brk) - LOAD_OFFSET) {
+       . = ALIGN(PAGE_SIZE);
+       __brk_base = . ;
+       . += 64 * 1024 ;        /* 64k alignment slop space */
+       *(.brk_reservation)     /* areas brk users have reserved */
+       __brk_limit = . ;
+  }
 
   _end = . ;
 
@@ -250,6 +263,7 @@ SECTIONS
   /DISCARD/ : {
        *(.exitcall.exit)
        *(.eh_frame)
+       *(.discard)
        }
 
   STABS_DEBUG
@@ -275,3 +289,10 @@ ASSERT((_end - _text <= KERNEL_IMAGE_SIZE),
 ASSERT((per_cpu__irq_stack_union == 0),
         "irq_stack_union is not at start of per-cpu area");
 #endif
+
+#ifdef CONFIG_KEXEC
+#include <asm/kexec.h>
+
+ASSERT(kexec_control_code_size <= KEXEC_CONTROL_CODE_MAX_SIZE,
+       "kexec control code size is too big")
+#endif
index 74de562812ccc0e3e4886c18d945d669d282c48c..a1d804bcd48357554cc017f4b63c217eb2b84eaa 100644 (file)
@@ -22,7 +22,7 @@
 #include <asm/paravirt.h>
 #include <asm/setup.h>
 
-#ifdef CONFIG_PARAVIRT
+#if defined CONFIG_PCI && defined CONFIG_PARAVIRT
 /*
  * Interrupt control on vSMPowered systems:
  * ~AC is a shadow of IF.  If IF is 'on' AC should be 'off'
@@ -114,6 +114,7 @@ static void __init set_vsmp_pv_ops(void)
 }
 #endif
 
+#ifdef CONFIG_PCI
 static int is_vsmp = -1;
 
 static void __init detect_vsmp_box(void)
@@ -139,6 +140,15 @@ int is_vsmp_box(void)
        }
 }
 
+#else
+static void __init detect_vsmp_box(void)
+{
+}
+int is_vsmp_box(void)
+{
+       return 0;
+}
+#endif
 void __init vsmp_init(void)
 {
        detect_vsmp_box();
index 9fe4ddaa8f6ff1fc53bbe09443d32d733876131c..e94a11e42f9864a35e197d9fdf7919accc8ba095 100644 (file)
@@ -107,7 +107,7 @@ static void async_hcall(unsigned long call, unsigned long arg1,
        local_irq_save(flags);
        if (lguest_data.hcall_status[next_call] != 0xFF) {
                /* Table full, so do normal hcall which will flush table. */
-               hcall(call, arg1, arg2, arg3);
+               kvm_hypercall3(call, arg1, arg2, arg3);
        } else {
                lguest_data.hcalls[next_call].arg0 = call;
                lguest_data.hcalls[next_call].arg1 = arg1;
@@ -134,13 +134,32 @@ static void async_hcall(unsigned long call, unsigned long arg1,
  *
  * So, when we're in lazy mode, we call async_hcall() to store the call for
  * future processing: */
-static void lazy_hcall(unsigned long call,
+static void lazy_hcall1(unsigned long call,
+                      unsigned long arg1)
+{
+       if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
+               kvm_hypercall1(call, arg1);
+       else
+               async_hcall(call, arg1, 0, 0);
+}
+
+static void lazy_hcall2(unsigned long call,
+                      unsigned long arg1,
+                      unsigned long arg2)
+{
+       if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
+               kvm_hypercall2(call, arg1, arg2);
+       else
+               async_hcall(call, arg1, arg2, 0);
+}
+
+static void lazy_hcall3(unsigned long call,
                       unsigned long arg1,
                       unsigned long arg2,
                       unsigned long arg3)
 {
        if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
-               hcall(call, arg1, arg2, arg3);
+               kvm_hypercall3(call, arg1, arg2, arg3);
        else
                async_hcall(call, arg1, arg2, arg3);
 }
@@ -150,7 +169,7 @@ static void lazy_hcall(unsigned long call,
 static void lguest_leave_lazy_mode(void)
 {
        paravirt_leave_lazy(paravirt_get_lazy_mode());
-       hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0);
+       kvm_hypercall0(LHCALL_FLUSH_ASYNC);
 }
 
 /*G:033
@@ -229,7 +248,7 @@ static void lguest_write_idt_entry(gate_desc *dt,
        /* Keep the local copy up to date. */
        native_write_idt_entry(dt, entrynum, g);
        /* Tell Host about this new entry. */
-       hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1]);
+       kvm_hypercall3(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1]);
 }
 
 /* Changing to a different IDT is very rare: we keep the IDT up-to-date every
@@ -241,7 +260,7 @@ static void lguest_load_idt(const struct desc_ptr *desc)
        struct desc_struct *idt = (void *)desc->address;
 
        for (i = 0; i < (desc->size+1)/8; i++)
-               hcall(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b);
+               kvm_hypercall3(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b);
 }
 
 /*
@@ -261,8 +280,8 @@ static void lguest_load_idt(const struct desc_ptr *desc)
  */
 static void lguest_load_gdt(const struct desc_ptr *desc)
 {
-       BUG_ON((desc->size+1)/8 != GDT_ENTRIES);
-       hcall(LHCALL_LOAD_GDT, __pa(desc->address), GDT_ENTRIES, 0);
+       BUG_ON((desc->size + 1) / 8 != GDT_ENTRIES);
+       kvm_hypercall2(LHCALL_LOAD_GDT, __pa(desc->address), GDT_ENTRIES);
 }
 
 /* For a single GDT entry which changes, we do the lazy thing: alter our GDT,
@@ -272,7 +291,7 @@ static void lguest_write_gdt_entry(struct desc_struct *dt, int entrynum,
                                   const void *desc, int type)
 {
        native_write_gdt_entry(dt, entrynum, desc, type);
-       hcall(LHCALL_LOAD_GDT, __pa(dt), GDT_ENTRIES, 0);
+       kvm_hypercall2(LHCALL_LOAD_GDT, __pa(dt), GDT_ENTRIES);
 }
 
 /* OK, I lied.  There are three "thread local storage" GDT entries which change
@@ -284,7 +303,7 @@ static void lguest_load_tls(struct thread_struct *t, unsigned int cpu)
         * can't handle us removing entries we're currently using.  So we clear
         * the GS register here: if it's needed it'll be reloaded anyway. */
        lazy_load_gs(0);
-       lazy_hcall(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu, 0);
+       lazy_hcall2(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu);
 }
 
 /*G:038 That's enough excitement for now, back to ploughing through each of
@@ -382,7 +401,7 @@ static void lguest_cpuid(unsigned int *ax, unsigned int *bx,
 static unsigned long current_cr0;
 static void lguest_write_cr0(unsigned long val)
 {
-       lazy_hcall(LHCALL_TS, val & X86_CR0_TS, 0, 0);
+       lazy_hcall1(LHCALL_TS, val & X86_CR0_TS);
        current_cr0 = val;
 }
 
@@ -396,7 +415,7 @@ static unsigned long lguest_read_cr0(void)
  * the vowels have been optimized out. */
 static void lguest_clts(void)
 {
-       lazy_hcall(LHCALL_TS, 0, 0, 0);
+       lazy_hcall1(LHCALL_TS, 0);
        current_cr0 &= ~X86_CR0_TS;
 }
 
@@ -418,7 +437,7 @@ static bool cr3_changed = false;
 static void lguest_write_cr3(unsigned long cr3)
 {
        lguest_data.pgdir = cr3;
-       lazy_hcall(LHCALL_NEW_PGTABLE, cr3, 0, 0);
+       lazy_hcall1(LHCALL_NEW_PGTABLE, cr3);
        cr3_changed = true;
 }
 
@@ -490,11 +509,17 @@ static void lguest_write_cr4(unsigned long val)
  * into a process' address space.  We set the entry then tell the Host the
  * toplevel and address this corresponds to.  The Guest uses one pagetable per
  * process, so we need to tell the Host which one we're changing (mm->pgd). */
+static void lguest_pte_update(struct mm_struct *mm, unsigned long addr,
+                              pte_t *ptep)
+{
+       lazy_hcall3(LHCALL_SET_PTE, __pa(mm->pgd), addr, ptep->pte_low);
+}
+
 static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep, pte_t pteval)
 {
        *ptep = pteval;
-       lazy_hcall(LHCALL_SET_PTE, __pa(mm->pgd), addr, pteval.pte_low);
+       lguest_pte_update(mm, addr, ptep);
 }
 
 /* The Guest calls this to set a top-level entry.  Again, we set the entry then
@@ -503,8 +528,8 @@ static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr,
 static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
 {
        *pmdp = pmdval;
-       lazy_hcall(LHCALL_SET_PMD, __pa(pmdp)&PAGE_MASK,
-                  (__pa(pmdp)&(PAGE_SIZE-1))/4, 0);
+       lazy_hcall2(LHCALL_SET_PMD, __pa(pmdp) & PAGE_MASK,
+                  (__pa(pmdp) & (PAGE_SIZE - 1)) / 4);
 }
 
 /* There are a couple of legacy places where the kernel sets a PTE, but we
@@ -520,7 +545,7 @@ static void lguest_set_pte(pte_t *ptep, pte_t pteval)
 {
        *ptep = pteval;
        if (cr3_changed)
-               lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0);
+               lazy_hcall1(LHCALL_FLUSH_TLB, 1);
 }
 
 /* Unfortunately for Lguest, the pv_mmu_ops for page tables were based on
@@ -536,7 +561,7 @@ static void lguest_set_pte(pte_t *ptep, pte_t pteval)
 static void lguest_flush_tlb_single(unsigned long addr)
 {
        /* Simply set it to zero: if it was not, it will fault back in. */
-       lazy_hcall(LHCALL_SET_PTE, lguest_data.pgdir, addr, 0);
+       lazy_hcall3(LHCALL_SET_PTE, lguest_data.pgdir, addr, 0);
 }
 
 /* This is what happens after the Guest has removed a large number of entries.
@@ -544,7 +569,7 @@ static void lguest_flush_tlb_single(unsigned long addr)
  * have changed, ie. virtual addresses below PAGE_OFFSET. */
 static void lguest_flush_tlb_user(void)
 {
-       lazy_hcall(LHCALL_FLUSH_TLB, 0, 0, 0);
+       lazy_hcall1(LHCALL_FLUSH_TLB, 0);
 }
 
 /* This is called when the kernel page tables have changed.  That's not very
@@ -552,7 +577,7 @@ static void lguest_flush_tlb_user(void)
  * slow), so it's worth separating this from the user flushing above. */
 static void lguest_flush_tlb_kernel(void)
 {
-       lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0);
+       lazy_hcall1(LHCALL_FLUSH_TLB, 1);
 }
 
 /*
@@ -689,7 +714,7 @@ static int lguest_clockevent_set_next_event(unsigned long delta,
        }
 
        /* Please wake us this far in the future. */
-       hcall(LHCALL_SET_CLOCKEVENT, delta, 0, 0);
+       kvm_hypercall1(LHCALL_SET_CLOCKEVENT, delta);
        return 0;
 }
 
@@ -700,7 +725,7 @@ static void lguest_clockevent_set_mode(enum clock_event_mode mode,
        case CLOCK_EVT_MODE_UNUSED:
        case CLOCK_EVT_MODE_SHUTDOWN:
                /* A 0 argument shuts the clock down. */
-               hcall(LHCALL_SET_CLOCKEVENT, 0, 0, 0);
+               kvm_hypercall0(LHCALL_SET_CLOCKEVENT);
                break;
        case CLOCK_EVT_MODE_ONESHOT:
                /* This is what we expect. */
@@ -775,8 +800,8 @@ static void lguest_time_init(void)
 static void lguest_load_sp0(struct tss_struct *tss,
                            struct thread_struct *thread)
 {
-       lazy_hcall(LHCALL_SET_STACK, __KERNEL_DS|0x1, thread->sp0,
-                  THREAD_SIZE/PAGE_SIZE);
+       lazy_hcall3(LHCALL_SET_STACK, __KERNEL_DS | 0x1, thread->sp0,
+                  THREAD_SIZE / PAGE_SIZE);
 }
 
 /* Let's just say, I wouldn't do debugging under a Guest. */
@@ -849,7 +874,7 @@ static void set_lguest_basic_apic_ops(void)
 /* STOP!  Until an interrupt comes in. */
 static void lguest_safe_halt(void)
 {
-       hcall(LHCALL_HALT, 0, 0, 0);
+       kvm_hypercall0(LHCALL_HALT);
 }
 
 /* The SHUTDOWN hypercall takes a string to describe what's happening, and
@@ -859,7 +884,8 @@ static void lguest_safe_halt(void)
  * rather than virtual addresses, so we use __pa() here. */
 static void lguest_power_off(void)
 {
-       hcall(LHCALL_SHUTDOWN, __pa("Power down"), LGUEST_SHUTDOWN_POWEROFF, 0);
+       kvm_hypercall2(LHCALL_SHUTDOWN, __pa("Power down"),
+                                       LGUEST_SHUTDOWN_POWEROFF);
 }
 
 /*
@@ -869,7 +895,7 @@ static void lguest_power_off(void)
  */
 static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p)
 {
-       hcall(LHCALL_SHUTDOWN, __pa(p), LGUEST_SHUTDOWN_POWEROFF, 0);
+       kvm_hypercall2(LHCALL_SHUTDOWN, __pa(p), LGUEST_SHUTDOWN_POWEROFF);
        /* The hcall won't return, but to keep gcc happy, we're "done". */
        return NOTIFY_DONE;
 }
@@ -910,7 +936,7 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count)
                len = sizeof(scratch) - 1;
        scratch[len] = '\0';
        memcpy(scratch, buf, len);
-       hcall(LHCALL_NOTIFY, __pa(scratch), 0, 0);
+       kvm_hypercall1(LHCALL_NOTIFY, __pa(scratch));
 
        /* This routine returns the number of bytes actually written. */
        return len;
@@ -920,7 +946,7 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count)
  * Launcher to reboot us. */
 static void lguest_restart(char *reason)
 {
-       hcall(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART, 0);
+       kvm_hypercall2(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART);
 }
 
 /*G:050
@@ -1040,6 +1066,8 @@ __init void lguest_init(void)
        pv_mmu_ops.read_cr3 = lguest_read_cr3;
        pv_mmu_ops.lazy_mode.enter = paravirt_enter_lazy_mmu;
        pv_mmu_ops.lazy_mode.leave = lguest_leave_lazy_mode;
+       pv_mmu_ops.pte_update = lguest_pte_update;
+       pv_mmu_ops.pte_update_defer = lguest_pte_update;
 
 #ifdef CONFIG_X86_LOCAL_APIC
        /* apic read/write intercepts */
@@ -1058,14 +1086,6 @@ __init void lguest_init(void)
         * lguest_init() where the rest of the fairly chaotic boot setup
         * occurs. */
 
-       /* The native boot code sets up initial page tables immediately after
-        * the kernel itself, and sets init_pg_tables_end so they're not
-        * clobbered.  The Launcher places our initial pagetables somewhere at
-        * the top of our physical memory, so we don't need extra space: set
-        * init_pg_tables_end to the end of the kernel. */
-       init_pg_tables_start = __pa(pg0);
-       init_pg_tables_end = __pa(pg0);
-
        /* As described in head_32.S, we map the first 128M of memory. */
        max_pfn_mapped = (128*1024*1024) >> PAGE_SHIFT;
 
index 10b9bd35a8ff9fbfb233883f23b970264eeb34d9..f795419894718796d48050f80a6b279a6a875dff 100644 (file)
@@ -27,8 +27,8 @@ ENTRY(lguest_entry)
        /* We make the "initialization" hypercall now to tell the Host about
         * us, and also find out where it put our page tables. */
        movl $LHCALL_LGUEST_INIT, %eax
-       movl $lguest_data - __PAGE_OFFSET, %edx
-       int $LGUEST_TRAP_ENTRY
+       movl $lguest_data - __PAGE_OFFSET, %ebx
+       .byte 0x0f,0x01,0xc1 /* KVM_HYPERCALL */
 
        /* Set up the initial stack so we can run C code. */
        movl $(init_thread_union+THREAD_SIZE),%esp
index c22981fa2f3a95240f3a4c99d00da41d1b7392ec..ad5441ed1b57fdfffe6822dede52cad626ae2b39 100644 (file)
@@ -1,30 +1,38 @@
 /* Copyright 2002 Andi Kleen */
 
 #include <linux/linkage.h>
-#include <asm/dwarf2.h>
+
 #include <asm/cpufeature.h>
+#include <asm/dwarf2.h>
 
 /*
  * memcpy - Copy a memory block.
  *
- * Input:      
- * rdi destination
- * rsi source
- * rdx count
- * 
+ * Input:
+ *  rdi destination
+ *  rsi source
+ *  rdx count
+ *
  * Output:
  * rax original destination
- */    
+ */
 
+/*
+ * memcpy_c() - fast string ops (REP MOVSQ) based variant.
+ *
+ * Calls to this get patched into the kernel image via the
+ * alternative instructions framework:
+ */
        ALIGN
 memcpy_c:
        CFI_STARTPROC
-       movq %rdi,%rax
-       movl %edx,%ecx
-       shrl $3,%ecx
-       andl $7,%edx
+       movq %rdi, %rax
+
+       movl %edx, %ecx
+       shrl $3, %ecx
+       andl $7, %edx
        rep movsq
-       movl %edx,%ecx
+       movl %edx, %ecx
        rep movsb
        ret
        CFI_ENDPROC
@@ -33,99 +41,110 @@ ENDPROC(memcpy_c)
 ENTRY(__memcpy)
 ENTRY(memcpy)
        CFI_STARTPROC
-       pushq %rbx
-       CFI_ADJUST_CFA_OFFSET 8
-       CFI_REL_OFFSET rbx, 0
-       movq %rdi,%rax
 
-       movl %edx,%ecx
-       shrl $6,%ecx
+       /*
+        * Put the number of full 64-byte blocks into %ecx.
+        * Tail portion is handled at the end:
+        */
+       movq %rdi, %rax
+       movl %edx, %ecx
+       shrl   $6, %ecx
        jz .Lhandle_tail
 
        .p2align 4
 .Lloop_64:
+       /*
+        * We decrement the loop index here - and the zero-flag is
+        * checked at the end of the loop (instructions inbetween do
+        * not change the zero flag):
+        */
        decl %ecx
 
-       movq (%rsi),%r11
-       movq 8(%rsi),%r8
+       /*
+        * Move in blocks of 4x16 bytes:
+        */
+       movq 0*8(%rsi),         %r11
+       movq 1*8(%rsi),         %r8
+       movq %r11,              0*8(%rdi)
+       movq %r8,               1*8(%rdi)
 
-       movq %r11,(%rdi)
-       movq %r8,1*8(%rdi)
+       movq 2*8(%rsi),         %r9
+       movq 3*8(%rsi),         %r10
+       movq %r9,               2*8(%rdi)
+       movq %r10,              3*8(%rdi)
 
-       movq 2*8(%rsi),%r9
-       movq 3*8(%rsi),%r10
+       movq 4*8(%rsi),         %r11
+       movq 5*8(%rsi),         %r8
+       movq %r11,              4*8(%rdi)
+       movq %r8,               5*8(%rdi)
 
-       movq %r9,2*8(%rdi)
-       movq %r10,3*8(%rdi)
+       movq 6*8(%rsi),         %r9
+       movq 7*8(%rsi),         %r10
+       movq %r9,               6*8(%rdi)
+       movq %r10,              7*8(%rdi)
 
-       movq 4*8(%rsi),%r11
-       movq 5*8(%rsi),%r8
+       leaq 64(%rsi), %rsi
+       leaq 64(%rdi), %rdi
 
-       movq %r11,4*8(%rdi)
-       movq %r8,5*8(%rdi)
-
-       movq 6*8(%rsi),%r9
-       movq 7*8(%rsi),%r10
-
-       movq %r9,6*8(%rdi)
-       movq %r10,7*8(%rdi)
-
-       leaq 64(%rsi),%rsi
-       leaq 64(%rdi),%rdi
        jnz  .Lloop_64
 
 .Lhandle_tail:
-       movl %edx,%ecx
-       andl $63,%ecx
-       shrl $3,%ecx
+       movl %edx, %ecx
+       andl  $63, %ecx
+       shrl   $3, %ecx
        jz   .Lhandle_7
+
        .p2align 4
 .Lloop_8:
        decl %ecx
-       movq (%rsi),%r8
-       movq %r8,(%rdi)
-       leaq 8(%rdi),%rdi
-       leaq 8(%rsi),%rsi
+       movq (%rsi),            %r8
+       movq %r8,               (%rdi)
+       leaq 8(%rdi),           %rdi
+       leaq 8(%rsi),           %rsi
        jnz  .Lloop_8
 
 .Lhandle_7:
-       movl %edx,%ecx
-       andl $7,%ecx
-       jz .Lende
+       movl %edx, %ecx
+       andl $7, %ecx
+       jz .Lend
+
        .p2align 4
 .Lloop_1:
-       movb (%rsi),%r8b
-       movb %r8b,(%rdi)
+       movb (%rsi), %r8b
+       movb %r8b, (%rdi)
        incq %rdi
        incq %rsi
        decl %ecx
        jnz .Lloop_1
 
-.Lende:
-       popq %rbx
-       CFI_ADJUST_CFA_OFFSET -8
-       CFI_RESTORE rbx
+.Lend:
        ret
-.Lfinal:
        CFI_ENDPROC
 ENDPROC(memcpy)
 ENDPROC(__memcpy)
 
-       /* Some CPUs run faster using the string copy instructions.
-          It is also a lot simpler. Use this when possible */
+       /*
+        * Some CPUs run faster using the string copy instructions.
+        * It is also a lot simpler. Use this when possible:
+        */
 
-       .section .altinstr_replacement,"ax"
+       .section .altinstr_replacement, "ax"
 1:     .byte 0xeb                              /* jmp <disp8> */
        .byte (memcpy_c - memcpy) - (2f - 1b)   /* offset */
 2:
        .previous
-       .section .altinstructions,"a"
+
+       .section .altinstructions, "a"
        .align 8
        .quad memcpy
        .quad 1b
        .byte X86_FEATURE_REP_GOOD
-       /* Replace only beginning, memcpy is used to apply alternatives, so it
-        * is silly to overwrite itself with nops - reboot is only outcome... */
+
+       /*
+        * Replace only beginning, memcpy is used to apply alternatives,
+        * so it is silly to overwrite itself with nops - reboot is the
+        * only outcome...
+        */
        .byte 2b - 1b
        .byte 2b - 1b
        .previous
index 00f127c80b0e38fa50eec531e8e85c8d1f18fd6d..5bc5d1688c1c771730ba6fa1ecdea1bafe959767 100644 (file)
@@ -19,49 +19,6 @@ void kunmap(struct page *page)
        kunmap_high(page);
 }
 
-static void debug_kmap_atomic_prot(enum km_type type)
-{
-#ifdef CONFIG_DEBUG_HIGHMEM
-       static unsigned warn_count = 10;
-
-       if (unlikely(warn_count == 0))
-               return;
-
-       if (unlikely(in_interrupt())) {
-               if (in_irq()) {
-                       if (type != KM_IRQ0 && type != KM_IRQ1 &&
-                           type != KM_BIO_SRC_IRQ && type != KM_BIO_DST_IRQ &&
-                           type != KM_BOUNCE_READ) {
-                               WARN_ON(1);
-                               warn_count--;
-                       }
-               } else if (!irqs_disabled()) {  /* softirq */
-                       if (type != KM_IRQ0 && type != KM_IRQ1 &&
-                           type != KM_SOFTIRQ0 && type != KM_SOFTIRQ1 &&
-                           type != KM_SKB_SUNRPC_DATA &&
-                           type != KM_SKB_DATA_SOFTIRQ &&
-                           type != KM_BOUNCE_READ) {
-                               WARN_ON(1);
-                               warn_count--;
-                       }
-               }
-       }
-
-       if (type == KM_IRQ0 || type == KM_IRQ1 || type == KM_BOUNCE_READ ||
-                       type == KM_BIO_SRC_IRQ || type == KM_BIO_DST_IRQ) {
-               if (!irqs_disabled()) {
-                       WARN_ON(1);
-                       warn_count--;
-               }
-       } else if (type == KM_SOFTIRQ0 || type == KM_SOFTIRQ1) {
-               if (irq_count() == 0 && !irqs_disabled()) {
-                       WARN_ON(1);
-                       warn_count--;
-               }
-       }
-#endif
-}
-
 /*
  * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because
  * no global lock is needed and because the kmap code must perform a global TLB
@@ -81,8 +38,9 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
        if (!PageHighMem(page))
                return page_address(page);
 
-       debug_kmap_atomic_prot(type);
+       debug_kmap_atomic(type);
 
+       debug_kmap_atomic(type);
        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
        BUG_ON(!pte_none(*(kmap_pte-idx)));
@@ -121,22 +79,13 @@ void kunmap_atomic(void *kvaddr, enum km_type type)
        pagefault_enable();
 }
 
-/* This is the same as kmap_atomic() but can map memory that doesn't
+/*
+ * This is the same as kmap_atomic() but can map memory that doesn't
  * have a struct page associated with it.
  */
 void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
 {
-       enum fixed_addresses idx;
-       unsigned long vaddr;
-
-       pagefault_disable();
-
-       idx = type + KM_TYPE_NR*smp_processor_id();
-       vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
-       set_pte(kmap_pte-idx, pfn_pte(pfn, kmap_prot));
-       arch_flush_lazy_mmu_mode();
-
-       return (void*) vaddr;
+       return kmap_atomic_prot_pfn(pfn, type, kmap_prot);
 }
 EXPORT_SYMBOL_GPL(kmap_atomic_pfn); /* temporarily in use by i915 GEM until vmap */
 
@@ -158,7 +107,6 @@ EXPORT_SYMBOL(kunmap);
 EXPORT_SYMBOL(kmap_atomic);
 EXPORT_SYMBOL(kunmap_atomic);
 
-#ifdef CONFIG_NUMA
 void __init set_highmem_pages_init(void)
 {
        struct zone *zone;
@@ -182,11 +130,3 @@ void __init set_highmem_pages_init(void)
        }
        totalram_pages += totalhigh_pages;
 }
-#else
-void __init set_highmem_pages_init(void)
-{
-       add_highpages_with_active_regions(0, highstart_pfn, highend_pfn);
-
-       totalram_pages += totalhigh_pages;
-}
-#endif /* CONFIG_NUMA */
index ce6a722587d8fa6cfd8343c3931866ce93eda13b..fd3da1dda1c9e5033af44cbdaf432239784558f2 100644 (file)
@@ -1,8 +1,345 @@
+#include <linux/ioport.h>
 #include <linux/swap.h>
+
 #include <asm/cacheflush.h>
+#include <asm/e820.h>
+#include <asm/init.h>
 #include <asm/page.h>
+#include <asm/page_types.h>
 #include <asm/sections.h>
 #include <asm/system.h>
+#include <asm/tlbflush.h>
+
+unsigned long __initdata e820_table_start;
+unsigned long __meminitdata e820_table_end;
+unsigned long __meminitdata e820_table_top;
+
+int after_bootmem;
+
+int direct_gbpages
+#ifdef CONFIG_DIRECT_GBPAGES
+                               = 1
+#endif
+;
+
+static void __init find_early_table_space(unsigned long end, int use_pse,
+                                         int use_gbpages)
+{
+       unsigned long puds, pmds, ptes, tables, start;
+
+       puds = (end + PUD_SIZE - 1) >> PUD_SHIFT;
+       tables = roundup(puds * sizeof(pud_t), PAGE_SIZE);
+
+       if (use_gbpages) {
+               unsigned long extra;
+
+               extra = end - ((end>>PUD_SHIFT) << PUD_SHIFT);
+               pmds = (extra + PMD_SIZE - 1) >> PMD_SHIFT;
+       } else
+               pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT;
+
+       tables += roundup(pmds * sizeof(pmd_t), PAGE_SIZE);
+
+       if (use_pse) {
+               unsigned long extra;
+
+               extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT);
+#ifdef CONFIG_X86_32
+               extra += PMD_SIZE;
+#endif
+               ptes = (extra + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       } else
+               ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+       tables += roundup(ptes * sizeof(pte_t), PAGE_SIZE);
+
+#ifdef CONFIG_X86_32
+       /* for fixmap */
+       tables += roundup(__end_of_fixed_addresses * sizeof(pte_t), PAGE_SIZE);
+#endif
+
+       /*
+        * RED-PEN putting page tables only on node 0 could
+        * cause a hotspot and fill up ZONE_DMA. The page tables
+        * need roughly 0.5KB per GB.
+        */
+#ifdef CONFIG_X86_32
+       start = 0x7000;
+       e820_table_start = find_e820_area(start, max_pfn_mapped<<PAGE_SHIFT,
+                                       tables, PAGE_SIZE);
+#else /* CONFIG_X86_64 */
+       start = 0x8000;
+       e820_table_start = find_e820_area(start, end, tables, PAGE_SIZE);
+#endif
+       if (e820_table_start == -1UL)
+               panic("Cannot find space for the kernel page tables");
+
+       e820_table_start >>= PAGE_SHIFT;
+       e820_table_end = e820_table_start;
+       e820_table_top = e820_table_start + (tables >> PAGE_SHIFT);
+
+       printk(KERN_DEBUG "kernel direct mapping tables up to %lx @ %lx-%lx\n",
+               end, e820_table_start << PAGE_SHIFT, e820_table_top << PAGE_SHIFT);
+}
+
+struct map_range {
+       unsigned long start;
+       unsigned long end;
+       unsigned page_size_mask;
+};
+
+#ifdef CONFIG_X86_32
+#define NR_RANGE_MR 3
+#else /* CONFIG_X86_64 */
+#define NR_RANGE_MR 5
+#endif
+
+static int __meminit save_mr(struct map_range *mr, int nr_range,
+                            unsigned long start_pfn, unsigned long end_pfn,
+                            unsigned long page_size_mask)
+{
+       if (start_pfn < end_pfn) {
+               if (nr_range >= NR_RANGE_MR)
+                       panic("run out of range for init_memory_mapping\n");
+               mr[nr_range].start = start_pfn<<PAGE_SHIFT;
+               mr[nr_range].end   = end_pfn<<PAGE_SHIFT;
+               mr[nr_range].page_size_mask = page_size_mask;
+               nr_range++;
+       }
+
+       return nr_range;
+}
+
+#ifdef CONFIG_X86_64
+static void __init init_gbpages(void)
+{
+       if (direct_gbpages && cpu_has_gbpages)
+               printk(KERN_INFO "Using GB pages for direct mapping\n");
+       else
+               direct_gbpages = 0;
+}
+#else
+static inline void init_gbpages(void)
+{
+}
+#endif
+
+/*
+ * Setup the direct mapping of the physical memory at PAGE_OFFSET.
+ * This runs before bootmem is initialized and gets pages directly from
+ * the physical memory. To access them they are temporarily mapped.
+ */
+unsigned long __init_refok init_memory_mapping(unsigned long start,
+                                              unsigned long end)
+{
+       unsigned long page_size_mask = 0;
+       unsigned long start_pfn, end_pfn;
+       unsigned long ret = 0;
+       unsigned long pos;
+
+       struct map_range mr[NR_RANGE_MR];
+       int nr_range, i;
+       int use_pse, use_gbpages;
+
+       printk(KERN_INFO "init_memory_mapping: %016lx-%016lx\n", start, end);
+
+       if (!after_bootmem)
+               init_gbpages();
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+       /*
+        * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages.
+        * This will simplify cpa(), which otherwise needs to support splitting
+        * large pages into small in interrupt context, etc.
+        */
+       use_pse = use_gbpages = 0;
+#else
+       use_pse = cpu_has_pse;
+       use_gbpages = direct_gbpages;
+#endif
+
+#ifdef CONFIG_X86_32
+#ifdef CONFIG_X86_PAE
+       set_nx();
+       if (nx_enabled)
+               printk(KERN_INFO "NX (Execute Disable) protection: active\n");
+#endif
+
+       /* Enable PSE if available */
+       if (cpu_has_pse)
+               set_in_cr4(X86_CR4_PSE);
+
+       /* Enable PGE if available */
+       if (cpu_has_pge) {
+               set_in_cr4(X86_CR4_PGE);
+               __supported_pte_mask |= _PAGE_GLOBAL;
+       }
+#endif
+
+       if (use_gbpages)
+               page_size_mask |= 1 << PG_LEVEL_1G;
+       if (use_pse)
+               page_size_mask |= 1 << PG_LEVEL_2M;
+
+       memset(mr, 0, sizeof(mr));
+       nr_range = 0;
+
+       /* head if not big page alignment ? */
+       start_pfn = start >> PAGE_SHIFT;
+       pos = start_pfn << PAGE_SHIFT;
+#ifdef CONFIG_X86_32
+       /*
+        * Don't use a large page for the first 2/4MB of memory
+        * because there are often fixed size MTRRs in there
+        * and overlapping MTRRs into large pages can cause
+        * slowdowns.
+        */
+       if (pos == 0)
+               end_pfn = 1<<(PMD_SHIFT - PAGE_SHIFT);
+       else
+               end_pfn = ((pos + (PMD_SIZE - 1))>>PMD_SHIFT)
+                                << (PMD_SHIFT - PAGE_SHIFT);
+#else /* CONFIG_X86_64 */
+       end_pfn = ((pos + (PMD_SIZE - 1)) >> PMD_SHIFT)
+                       << (PMD_SHIFT - PAGE_SHIFT);
+#endif
+       if (end_pfn > (end >> PAGE_SHIFT))
+               end_pfn = end >> PAGE_SHIFT;
+       if (start_pfn < end_pfn) {
+               nr_range = save_mr(mr, nr_range, start_pfn, end_pfn, 0);
+               pos = end_pfn << PAGE_SHIFT;
+       }
+
+       /* big page (2M) range */
+       start_pfn = ((pos + (PMD_SIZE - 1))>>PMD_SHIFT)
+                        << (PMD_SHIFT - PAGE_SHIFT);
+#ifdef CONFIG_X86_32
+       end_pfn = (end>>PMD_SHIFT) << (PMD_SHIFT - PAGE_SHIFT);
+#else /* CONFIG_X86_64 */
+       end_pfn = ((pos + (PUD_SIZE - 1))>>PUD_SHIFT)
+                        << (PUD_SHIFT - PAGE_SHIFT);
+       if (end_pfn > ((end>>PMD_SHIFT)<<(PMD_SHIFT - PAGE_SHIFT)))
+               end_pfn = ((end>>PMD_SHIFT)<<(PMD_SHIFT - PAGE_SHIFT));
+#endif
+
+       if (start_pfn < end_pfn) {
+               nr_range = save_mr(mr, nr_range, start_pfn, end_pfn,
+                               page_size_mask & (1<<PG_LEVEL_2M));
+               pos = end_pfn << PAGE_SHIFT;
+       }
+
+#ifdef CONFIG_X86_64
+       /* big page (1G) range */
+       start_pfn = ((pos + (PUD_SIZE - 1))>>PUD_SHIFT)
+                        << (PUD_SHIFT - PAGE_SHIFT);
+       end_pfn = (end >> PUD_SHIFT) << (PUD_SHIFT - PAGE_SHIFT);
+       if (start_pfn < end_pfn) {
+               nr_range = save_mr(mr, nr_range, start_pfn, end_pfn,
+                               page_size_mask &
+                                ((1<<PG_LEVEL_2M)|(1<<PG_LEVEL_1G)));
+               pos = end_pfn << PAGE_SHIFT;
+       }
+
+       /* tail is not big page (1G) alignment */
+       start_pfn = ((pos + (PMD_SIZE - 1))>>PMD_SHIFT)
+                        << (PMD_SHIFT - PAGE_SHIFT);
+       end_pfn = (end >> PMD_SHIFT) << (PMD_SHIFT - PAGE_SHIFT);
+       if (start_pfn < end_pfn) {
+               nr_range = save_mr(mr, nr_range, start_pfn, end_pfn,
+                               page_size_mask & (1<<PG_LEVEL_2M));
+               pos = end_pfn << PAGE_SHIFT;
+       }
+#endif
+
+       /* tail is not big page (2M) alignment */
+       start_pfn = pos>>PAGE_SHIFT;
+       end_pfn = end>>PAGE_SHIFT;
+       nr_range = save_mr(mr, nr_range, start_pfn, end_pfn, 0);
+
+       /* try to merge same page size and continuous */
+       for (i = 0; nr_range > 1 && i < nr_range - 1; i++) {
+               unsigned long old_start;
+               if (mr[i].end != mr[i+1].start ||
+                   mr[i].page_size_mask != mr[i+1].page_size_mask)
+                       continue;
+               /* move it */
+               old_start = mr[i].start;
+               memmove(&mr[i], &mr[i+1],
+                       (nr_range - 1 - i) * sizeof(struct map_range));
+               mr[i--].start = old_start;
+               nr_range--;
+       }
+
+       for (i = 0; i < nr_range; i++)
+               printk(KERN_DEBUG " %010lx - %010lx page %s\n",
+                               mr[i].start, mr[i].end,
+                       (mr[i].page_size_mask & (1<<PG_LEVEL_1G))?"1G":(
+                        (mr[i].page_size_mask & (1<<PG_LEVEL_2M))?"2M":"4k"));
+
+       /*
+        * Find space for the kernel direct mapping tables.
+        *
+        * Later we should allocate these tables in the local node of the
+        * memory mapped. Unfortunately this is done currently before the
+        * nodes are discovered.
+        */
+       if (!after_bootmem)
+               find_early_table_space(end, use_pse, use_gbpages);
+
+#ifdef CONFIG_X86_32
+       for (i = 0; i < nr_range; i++)
+               kernel_physical_mapping_init(mr[i].start, mr[i].end,
+                                            mr[i].page_size_mask);
+       ret = end;
+#else /* CONFIG_X86_64 */
+       for (i = 0; i < nr_range; i++)
+               ret = kernel_physical_mapping_init(mr[i].start, mr[i].end,
+                                                  mr[i].page_size_mask);
+#endif
+
+#ifdef CONFIG_X86_32
+       early_ioremap_page_table_range_init();
+
+       load_cr3(swapper_pg_dir);
+#endif
+
+#ifdef CONFIG_X86_64
+       if (!after_bootmem)
+               mmu_cr4_features = read_cr4();
+#endif
+       __flush_tlb_all();
+
+       if (!after_bootmem && e820_table_end > e820_table_start)
+               reserve_early(e820_table_start << PAGE_SHIFT,
+                                e820_table_end << PAGE_SHIFT, "PGTABLE");
+
+       if (!after_bootmem)
+               early_memtest(start, end);
+
+       return ret >> PAGE_SHIFT;
+}
+
+
+/*
+ * devmem_is_allowed() checks to see if /dev/mem access to a certain address
+ * is valid. The argument is a physical page number.
+ *
+ *
+ * On x86, access has to be given to the first megabyte of ram because that area
+ * contains bios code and data regions used by X and dosemu and similar apps.
+ * Access has to be given to non-kernel-ram areas as well, these contain the PCI
+ * mmio resources as well as potential bios/acpi data regions.
+ */
+int devmem_is_allowed(unsigned long pagenr)
+{
+       if (pagenr <= 256)
+               return 1;
+       if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
+               return 0;
+       if (!page_is_ram(pagenr))
+               return 1;
+       return 0;
+}
 
 void free_init_pages(char *what, unsigned long begin, unsigned long end)
 {
@@ -47,3 +384,10 @@ void free_initmem(void)
                        (unsigned long)(&__init_begin),
                        (unsigned long)(&__init_end));
 }
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+       free_init_pages("initrd memory", start, end);
+}
+#endif
index 47df0e1bbeb9aca5a30c9b2d858431518263ad11..db81e9a8556b3b0bba854aeba5740bd0cc039039 100644 (file)
@@ -49,6 +49,7 @@
 #include <asm/paravirt.h>
 #include <asm/setup.h>
 #include <asm/cacheflush.h>
+#include <asm/init.h>
 
 unsigned long max_low_pfn_mapped;
 unsigned long max_pfn_mapped;
@@ -58,19 +59,14 @@ unsigned long highstart_pfn, highend_pfn;
 
 static noinline int do_test_wp_bit(void);
 
-
-static unsigned long __initdata table_start;
-static unsigned long __meminitdata table_end;
-static unsigned long __meminitdata table_top;
-
-static int __initdata after_init_bootmem;
+bool __read_mostly __vmalloc_start_set = false;
 
 static __init void *alloc_low_page(void)
 {
-       unsigned long pfn = table_end++;
+       unsigned long pfn = e820_table_end++;
        void *adr;
 
-       if (pfn >= table_top)
+       if (pfn >= e820_table_top)
                panic("alloc_low_page: ran out of memory");
 
        adr = __va(pfn * PAGE_SIZE);
@@ -90,7 +86,7 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd)
 
 #ifdef CONFIG_X86_PAE
        if (!(pgd_val(*pgd) & _PAGE_PRESENT)) {
-               if (after_init_bootmem)
+               if (after_bootmem)
                        pmd_table = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
                else
                        pmd_table = (pmd_t *)alloc_low_page();
@@ -117,7 +113,7 @@ static pte_t * __init one_page_table_init(pmd_t *pmd)
        if (!(pmd_val(*pmd) & _PAGE_PRESENT)) {
                pte_t *page_table = NULL;
 
-               if (after_init_bootmem) {
+               if (after_bootmem) {
 #ifdef CONFIG_DEBUG_PAGEALLOC
                        page_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
 #endif
@@ -168,12 +164,12 @@ static pte_t *__init page_table_kmap_check(pte_t *pte, pmd_t *pmd,
        if (pmd_idx_kmap_begin != pmd_idx_kmap_end
            && (vaddr >> PMD_SHIFT) >= pmd_idx_kmap_begin
            && (vaddr >> PMD_SHIFT) <= pmd_idx_kmap_end
-           && ((__pa(pte) >> PAGE_SHIFT) < table_start
-               || (__pa(pte) >> PAGE_SHIFT) >= table_end)) {
+           && ((__pa(pte) >> PAGE_SHIFT) < e820_table_start
+               || (__pa(pte) >> PAGE_SHIFT) >= e820_table_end)) {
                pte_t *newpte;
                int i;
 
-               BUG_ON(after_init_bootmem);
+               BUG_ON(after_bootmem);
                newpte = alloc_low_page();
                for (i = 0; i < PTRS_PER_PTE; i++)
                        set_pte(newpte + i, pte[i]);
@@ -242,11 +238,14 @@ static inline int is_kernel_text(unsigned long addr)
  * of max_low_pfn pages, by creating page tables starting from address
  * PAGE_OFFSET:
  */
-static void __init kernel_physical_mapping_init(pgd_t *pgd_base,
-                                               unsigned long start_pfn,
-                                               unsigned long end_pfn,
-                                               int use_pse)
+unsigned long __init
+kernel_physical_mapping_init(unsigned long start,
+                            unsigned long end,
+                            unsigned long page_size_mask)
 {
+       int use_pse = page_size_mask == (1<<PG_LEVEL_2M);
+       unsigned long start_pfn, end_pfn;
+       pgd_t *pgd_base = swapper_pg_dir;
        int pgd_idx, pmd_idx, pte_ofs;
        unsigned long pfn;
        pgd_t *pgd;
@@ -255,6 +254,9 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base,
        unsigned pages_2m, pages_4k;
        int mapping_iter;
 
+       start_pfn = start >> PAGE_SHIFT;
+       end_pfn = end >> PAGE_SHIFT;
+
        /*
         * First iteration will setup identity mapping using large/small pages
         * based on use_pse, with other attributes same as set by
@@ -369,26 +371,6 @@ repeat:
                mapping_iter = 2;
                goto repeat;
        }
-}
-
-/*
- * devmem_is_allowed() checks to see if /dev/mem access to a certain address
- * is valid. The argument is a physical page number.
- *
- *
- * On x86, access has to be given to the first megabyte of ram because that area
- * contains bios code and data regions used by X and dosemu and similar apps.
- * Access has to be given to non-kernel-ram areas as well, these contain the PCI
- * mmio resources as well as potential bios/acpi data regions.
- */
-int devmem_is_allowed(unsigned long pagenr)
-{
-       if (pagenr <= 256)
-               return 1;
-       if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
-               return 0;
-       if (!page_is_ram(pagenr))
-               return 1;
        return 0;
 }
 
@@ -545,8 +527,9 @@ void __init native_pagetable_setup_done(pgd_t *base)
  * be partially populated, and so it avoids stomping on any existing
  * mappings.
  */
-static void __init early_ioremap_page_table_range_init(pgd_t *pgd_base)
+void __init early_ioremap_page_table_range_init(void)
 {
+       pgd_t *pgd_base = swapper_pg_dir;
        unsigned long vaddr, end;
 
        /*
@@ -641,7 +624,7 @@ static int __init noexec_setup(char *str)
 }
 early_param("noexec", noexec_setup);
 
-static void __init set_nx(void)
+void __init set_nx(void)
 {
        unsigned int v[4], l, h;
 
@@ -793,6 +776,8 @@ void __init initmem_init(unsigned long start_pfn,
 #ifdef CONFIG_FLATMEM
        max_mapnr = num_physpages;
 #endif
+       __vmalloc_start_set = true;
+
        printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
                        pages_to_mb(max_low_pfn));
 
@@ -814,176 +799,66 @@ static void __init zone_sizes_init(void)
        free_area_init_nodes(max_zone_pfns);
 }
 
+static unsigned long __init setup_node_bootmem(int nodeid,
+                                unsigned long start_pfn,
+                                unsigned long end_pfn,
+                                unsigned long bootmap)
+{
+       unsigned long bootmap_size;
+
+       /* don't touch min_low_pfn */
+       bootmap_size = init_bootmem_node(NODE_DATA(nodeid),
+                                        bootmap >> PAGE_SHIFT,
+                                        start_pfn, end_pfn);
+       printk(KERN_INFO "  node %d low ram: %08lx - %08lx\n",
+               nodeid, start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
+       printk(KERN_INFO "  node %d bootmap %08lx - %08lx\n",
+                nodeid, bootmap, bootmap + bootmap_size);
+       free_bootmem_with_active_regions(nodeid, end_pfn);
+       early_res_to_bootmem(start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
+
+       return bootmap + bootmap_size;
+}
+
 void __init setup_bootmem_allocator(void)
 {
-       int i;
+       int nodeid;
        unsigned long bootmap_size, bootmap;
        /*
         * Initialize the boot-time allocator (with low memory only):
         */
        bootmap_size = bootmem_bootmap_pages(max_low_pfn)<<PAGE_SHIFT;
-       bootmap = find_e820_area(min_low_pfn<<PAGE_SHIFT,
-                                max_pfn_mapped<<PAGE_SHIFT, bootmap_size,
+       bootmap = find_e820_area(0, max_pfn_mapped<<PAGE_SHIFT, bootmap_size,
                                 PAGE_SIZE);
        if (bootmap == -1L)
                panic("Cannot find bootmem map of size %ld\n", bootmap_size);
        reserve_early(bootmap, bootmap + bootmap_size, "BOOTMAP");
 
-       /* don't touch min_low_pfn */
-       bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap >> PAGE_SHIFT,
-                                        min_low_pfn, max_low_pfn);
        printk(KERN_INFO "  mapped low ram: 0 - %08lx\n",
                 max_pfn_mapped<<PAGE_SHIFT);
-       printk(KERN_INFO "  low ram: %08lx - %08lx\n",
-                min_low_pfn<<PAGE_SHIFT, max_low_pfn<<PAGE_SHIFT);
-       printk(KERN_INFO "  bootmap %08lx - %08lx\n",
-                bootmap, bootmap + bootmap_size);
-       for_each_online_node(i)
-               free_bootmem_with_active_regions(i, max_low_pfn);
-       early_res_to_bootmem(0, max_low_pfn<<PAGE_SHIFT);
-
-       after_init_bootmem = 1;
-}
-
-static void __init find_early_table_space(unsigned long end, int use_pse)
-{
-       unsigned long puds, pmds, ptes, tables, start;
+       printk(KERN_INFO "  low ram: 0 - %08lx\n", max_low_pfn<<PAGE_SHIFT);
 
-       puds = (end + PUD_SIZE - 1) >> PUD_SHIFT;
-       tables = roundup(puds * sizeof(pud_t), PAGE_SIZE);
+       for_each_online_node(nodeid) {
+                unsigned long start_pfn, end_pfn;
 
-       pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT;
-       tables += roundup(pmds * sizeof(pmd_t), PAGE_SIZE);
-
-       if (use_pse) {
-               unsigned long extra;
-
-               extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT);
-               extra += PMD_SIZE;
-               ptes = (extra + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       } else
-               ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT;
-
-       tables += roundup(ptes * sizeof(pte_t), PAGE_SIZE);
-
-       /* for fixmap */
-       tables += roundup(__end_of_fixed_addresses * sizeof(pte_t), PAGE_SIZE);
-
-       /*
-        * RED-PEN putting page tables only on node 0 could
-        * cause a hotspot and fill up ZONE_DMA. The page tables
-        * need roughly 0.5KB per GB.
-        */
-       start = 0x7000;
-       table_start = find_e820_area(start, max_pfn_mapped<<PAGE_SHIFT,
-                                       tables, PAGE_SIZE);
-       if (table_start == -1UL)
-               panic("Cannot find space for the kernel page tables");
-
-       table_start >>= PAGE_SHIFT;
-       table_end = table_start;
-       table_top = table_start + (tables>>PAGE_SHIFT);
-
-       printk(KERN_DEBUG "kernel direct mapping tables up to %lx @ %lx-%lx\n",
-               end, table_start << PAGE_SHIFT,
-               (table_start << PAGE_SHIFT) + tables);
-}
-
-unsigned long __init_refok init_memory_mapping(unsigned long start,
-                                               unsigned long end)
-{
-       pgd_t *pgd_base = swapper_pg_dir;
-       unsigned long start_pfn, end_pfn;
-       unsigned long big_page_start;
-#ifdef CONFIG_DEBUG_PAGEALLOC
-       /*
-        * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages.
-        * This will simplify cpa(), which otherwise needs to support splitting
-        * large pages into small in interrupt context, etc.
-        */
-       int use_pse = 0;
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+               start_pfn = node_start_pfn[nodeid];
+               end_pfn = node_end_pfn[nodeid];
+               if (start_pfn > max_low_pfn)
+                       continue;
+               if (end_pfn > max_low_pfn)
+                       end_pfn = max_low_pfn;
 #else
-       int use_pse = cpu_has_pse;
+               start_pfn = 0;
+               end_pfn = max_low_pfn;
 #endif
-
-       /*
-        * Find space for the kernel direct mapping tables.
-        */
-       if (!after_init_bootmem)
-               find_early_table_space(end, use_pse);
-
-#ifdef CONFIG_X86_PAE
-       set_nx();
-       if (nx_enabled)
-               printk(KERN_INFO "NX (Execute Disable) protection: active\n");
-#endif
-
-       /* Enable PSE if available */
-       if (cpu_has_pse)
-               set_in_cr4(X86_CR4_PSE);
-
-       /* Enable PGE if available */
-       if (cpu_has_pge) {
-               set_in_cr4(X86_CR4_PGE);
-               __supported_pte_mask |= _PAGE_GLOBAL;
-       }
-
-       /*
-        * Don't use a large page for the first 2/4MB of memory
-        * because there are often fixed size MTRRs in there
-        * and overlapping MTRRs into large pages can cause
-        * slowdowns.
-        */
-       big_page_start = PMD_SIZE;
-
-       if (start < big_page_start) {
-               start_pfn = start >> PAGE_SHIFT;
-               end_pfn = min(big_page_start>>PAGE_SHIFT, end>>PAGE_SHIFT);
-       } else {
-               /* head is not big page alignment ? */
-               start_pfn = start >> PAGE_SHIFT;
-               end_pfn = ((start + (PMD_SIZE - 1))>>PMD_SHIFT)
-                                << (PMD_SHIFT - PAGE_SHIFT);
+               bootmap = setup_node_bootmem(nodeid, start_pfn, end_pfn,
+                                                bootmap);
        }
-       if (start_pfn < end_pfn)
-               kernel_physical_mapping_init(pgd_base, start_pfn, end_pfn, 0);
-
-       /* big page range */
-       start_pfn = ((start + (PMD_SIZE - 1))>>PMD_SHIFT)
-                        << (PMD_SHIFT - PAGE_SHIFT);
-       if (start_pfn < (big_page_start >> PAGE_SHIFT))
-               start_pfn =  big_page_start >> PAGE_SHIFT;
-       end_pfn = (end>>PMD_SHIFT) << (PMD_SHIFT - PAGE_SHIFT);
-       if (start_pfn < end_pfn)
-               kernel_physical_mapping_init(pgd_base, start_pfn, end_pfn,
-                                            use_pse);
-
-       /* tail is not big page alignment ? */
-       start_pfn = end_pfn;
-       if (start_pfn > (big_page_start>>PAGE_SHIFT)) {
-               end_pfn = end >> PAGE_SHIFT;
-               if (start_pfn < end_pfn)
-                       kernel_physical_mapping_init(pgd_base, start_pfn,
-                                                        end_pfn, 0);
-       }
-
-       early_ioremap_page_table_range_init(pgd_base);
 
-       load_cr3(swapper_pg_dir);
-
-       __flush_tlb_all();
-
-       if (!after_init_bootmem)
-               reserve_early(table_start << PAGE_SHIFT,
-                                table_end << PAGE_SHIFT, "PGTABLE");
-
-       if (!after_init_bootmem)
-               early_memtest(start, end);
-
-       return end >> PAGE_SHIFT;
+       after_bootmem = 1;
 }
 
-
 /*
  * paging_init() sets up the page tables - note that the first 8MB are
  * already mapped by head.S.
@@ -1217,13 +1092,6 @@ void mark_rodata_ro(void)
 }
 #endif
 
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_init_pages("initrd memory", start, end);
-}
-#endif
-
 int __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
                                   int flags)
 {
index 07f44d491df16d9b392fdaa09e3bdf4143f3c236..54efa57d1c039b648d6eb77bef1878c10e9cdb0b 100644 (file)
@@ -48,6 +48,7 @@
 #include <asm/kdebug.h>
 #include <asm/numa.h>
 #include <asm/cacheflush.h>
+#include <asm/init.h>
 
 /*
  * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries.
@@ -61,12 +62,6 @@ static unsigned long dma_reserve __initdata;
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
-int direct_gbpages
-#ifdef CONFIG_DIRECT_GBPAGES
-                               = 1
-#endif
-;
-
 static int __init parse_direct_gbpages_off(char *arg)
 {
        direct_gbpages = 0;
@@ -87,12 +82,10 @@ early_param("gbpages", parse_direct_gbpages_on);
  * around without checking the pgd every time.
  */
 
-int after_bootmem;
-
 pteval_t __supported_pte_mask __read_mostly = ~_PAGE_IOMAP;
 EXPORT_SYMBOL_GPL(__supported_pte_mask);
 
-static int do_not_nx __cpuinitdata;
+static int disable_nx __cpuinitdata;
 
 /*
  * noexec=on|off
@@ -107,9 +100,9 @@ static int __init nonx_setup(char *str)
                return -EINVAL;
        if (!strncmp(str, "on", 2)) {
                __supported_pte_mask |= _PAGE_NX;
-               do_not_nx = 0;
+               disable_nx = 0;
        } else if (!strncmp(str, "off", 3)) {
-               do_not_nx = 1;
+               disable_nx = 1;
                __supported_pte_mask &= ~_PAGE_NX;
        }
        return 0;
@@ -121,7 +114,7 @@ void __cpuinit check_efer(void)
        unsigned long efer;
 
        rdmsrl(MSR_EFER, efer);
-       if (!(efer & EFER_NX) || do_not_nx)
+       if (!(efer & EFER_NX) || disable_nx)
                __supported_pte_mask &= ~_PAGE_NX;
 }
 
@@ -325,13 +318,9 @@ void __init cleanup_highmap(void)
        }
 }
 
-static unsigned long __initdata table_start;
-static unsigned long __meminitdata table_end;
-static unsigned long __meminitdata table_top;
-
 static __ref void *alloc_low_page(unsigned long *phys)
 {
-       unsigned long pfn = table_end++;
+       unsigned long pfn = e820_table_end++;
        void *adr;
 
        if (after_bootmem) {
@@ -341,7 +330,7 @@ static __ref void *alloc_low_page(unsigned long *phys)
                return adr;
        }
 
-       if (pfn >= table_top)
+       if (pfn >= e820_table_top)
                panic("alloc_low_page: ran out of memory");
 
        adr = early_memremap(pfn * PAGE_SIZE, PAGE_SIZE);
@@ -581,58 +570,10 @@ phys_pud_update(pgd_t *pgd, unsigned long addr, unsigned long end,
        return phys_pud_init(pud, addr, end, page_size_mask);
 }
 
-static void __init find_early_table_space(unsigned long end, int use_pse,
-                                         int use_gbpages)
-{
-       unsigned long puds, pmds, ptes, tables, start;
-
-       puds = (end + PUD_SIZE - 1) >> PUD_SHIFT;
-       tables = roundup(puds * sizeof(pud_t), PAGE_SIZE);
-       if (use_gbpages) {
-               unsigned long extra;
-               extra = end - ((end>>PUD_SHIFT) << PUD_SHIFT);
-               pmds = (extra + PMD_SIZE - 1) >> PMD_SHIFT;
-       } else
-               pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT;
-       tables += roundup(pmds * sizeof(pmd_t), PAGE_SIZE);
-
-       if (use_pse) {
-               unsigned long extra;
-               extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT);
-               ptes = (extra + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       } else
-               ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       tables += roundup(ptes * sizeof(pte_t), PAGE_SIZE);
-
-       /*
-        * RED-PEN putting page tables only on node 0 could
-        * cause a hotspot and fill up ZONE_DMA. The page tables
-        * need roughly 0.5KB per GB.
-        */
-       start = 0x8000;
-       table_start = find_e820_area(start, end, tables, PAGE_SIZE);
-       if (table_start == -1UL)
-               panic("Cannot find space for the kernel page tables");
-
-       table_start >>= PAGE_SHIFT;
-       table_end = table_start;
-       table_top = table_start + (tables >> PAGE_SHIFT);
-
-       printk(KERN_DEBUG "kernel direct mapping tables up to %lx @ %lx-%lx\n",
-               end, table_start << PAGE_SHIFT, table_top << PAGE_SHIFT);
-}
-
-static void __init init_gbpages(void)
-{
-       if (direct_gbpages && cpu_has_gbpages)
-               printk(KERN_INFO "Using GB pages for direct mapping\n");
-       else
-               direct_gbpages = 0;
-}
-
-static unsigned long __meminit kernel_physical_mapping_init(unsigned long start,
-                                               unsigned long end,
-                                               unsigned long page_size_mask)
+unsigned long __init
+kernel_physical_mapping_init(unsigned long start,
+                            unsigned long end,
+                            unsigned long page_size_mask)
 {
 
        unsigned long next, last_map_addr = end;
@@ -669,176 +610,6 @@ static unsigned long __meminit kernel_physical_mapping_init(unsigned long start,
        return last_map_addr;
 }
 
-struct map_range {
-       unsigned long start;
-       unsigned long end;
-       unsigned page_size_mask;
-};
-
-#define NR_RANGE_MR 5
-
-static int save_mr(struct map_range *mr, int nr_range,
-                  unsigned long start_pfn, unsigned long end_pfn,
-                  unsigned long page_size_mask)
-{
-
-       if (start_pfn < end_pfn) {
-               if (nr_range >= NR_RANGE_MR)
-                       panic("run out of range for init_memory_mapping\n");
-               mr[nr_range].start = start_pfn<<PAGE_SHIFT;
-               mr[nr_range].end   = end_pfn<<PAGE_SHIFT;
-               mr[nr_range].page_size_mask = page_size_mask;
-               nr_range++;
-       }
-
-       return nr_range;
-}
-
-/*
- * Setup the direct mapping of the physical memory at PAGE_OFFSET.
- * This runs before bootmem is initialized and gets pages directly from
- * the physical memory. To access them they are temporarily mapped.
- */
-unsigned long __init_refok init_memory_mapping(unsigned long start,
-                                              unsigned long end)
-{
-       unsigned long last_map_addr = 0;
-       unsigned long page_size_mask = 0;
-       unsigned long start_pfn, end_pfn;
-       unsigned long pos;
-
-       struct map_range mr[NR_RANGE_MR];
-       int nr_range, i;
-       int use_pse, use_gbpages;
-
-       printk(KERN_INFO "init_memory_mapping: %016lx-%016lx\n", start, end);
-
-       /*
-        * Find space for the kernel direct mapping tables.
-        *
-        * Later we should allocate these tables in the local node of the
-        * memory mapped. Unfortunately this is done currently before the
-        * nodes are discovered.
-        */
-       if (!after_bootmem)
-               init_gbpages();
-
-#ifdef CONFIG_DEBUG_PAGEALLOC
-       /*
-        * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages.
-        * This will simplify cpa(), which otherwise needs to support splitting
-        * large pages into small in interrupt context, etc.
-        */
-       use_pse = use_gbpages = 0;
-#else
-       use_pse = cpu_has_pse;
-       use_gbpages = direct_gbpages;
-#endif
-
-       if (use_gbpages)
-               page_size_mask |= 1 << PG_LEVEL_1G;
-       if (use_pse)
-               page_size_mask |= 1 << PG_LEVEL_2M;
-
-       memset(mr, 0, sizeof(mr));
-       nr_range = 0;
-
-       /* head if not big page alignment ?*/
-       start_pfn = start >> PAGE_SHIFT;
-       pos = start_pfn << PAGE_SHIFT;
-       end_pfn = ((pos + (PMD_SIZE - 1)) >> PMD_SHIFT)
-                       << (PMD_SHIFT - PAGE_SHIFT);
-       if (end_pfn > (end >> PAGE_SHIFT))
-               end_pfn = end >> PAGE_SHIFT;
-       if (start_pfn < end_pfn) {
-               nr_range = save_mr(mr, nr_range, start_pfn, end_pfn, 0);
-               pos = end_pfn << PAGE_SHIFT;
-       }
-
-       /* big page (2M) range*/
-       start_pfn = ((pos + (PMD_SIZE - 1))>>PMD_SHIFT)
-                        << (PMD_SHIFT - PAGE_SHIFT);
-       end_pfn = ((pos + (PUD_SIZE - 1))>>PUD_SHIFT)
-                        << (PUD_SHIFT - PAGE_SHIFT);
-       if (end_pfn > ((end>>PMD_SHIFT)<<(PMD_SHIFT - PAGE_SHIFT)))
-               end_pfn = ((end>>PMD_SHIFT)<<(PMD_SHIFT - PAGE_SHIFT));
-       if (start_pfn < end_pfn) {
-               nr_range = save_mr(mr, nr_range, start_pfn, end_pfn,
-                               page_size_mask & (1<<PG_LEVEL_2M));
-               pos = end_pfn << PAGE_SHIFT;
-       }
-
-       /* big page (1G) range */
-       start_pfn = ((pos + (PUD_SIZE - 1))>>PUD_SHIFT)
-                        << (PUD_SHIFT - PAGE_SHIFT);
-       end_pfn = (end >> PUD_SHIFT) << (PUD_SHIFT - PAGE_SHIFT);
-       if (start_pfn < end_pfn) {
-               nr_range = save_mr(mr, nr_range, start_pfn, end_pfn,
-                               page_size_mask &
-                                ((1<<PG_LEVEL_2M)|(1<<PG_LEVEL_1G)));
-               pos = end_pfn << PAGE_SHIFT;
-       }
-
-       /* tail is not big page (1G) alignment */
-       start_pfn = ((pos + (PMD_SIZE - 1))>>PMD_SHIFT)
-                        << (PMD_SHIFT - PAGE_SHIFT);
-       end_pfn = (end >> PMD_SHIFT) << (PMD_SHIFT - PAGE_SHIFT);
-       if (start_pfn < end_pfn) {
-               nr_range = save_mr(mr, nr_range, start_pfn, end_pfn,
-                               page_size_mask & (1<<PG_LEVEL_2M));
-               pos = end_pfn << PAGE_SHIFT;
-       }
-
-       /* tail is not big page (2M) alignment */
-       start_pfn = pos>>PAGE_SHIFT;
-       end_pfn = end>>PAGE_SHIFT;
-       nr_range = save_mr(mr, nr_range, start_pfn, end_pfn, 0);
-
-       /* try to merge same page size and continuous */
-       for (i = 0; nr_range > 1 && i < nr_range - 1; i++) {
-               unsigned long old_start;
-               if (mr[i].end != mr[i+1].start ||
-                   mr[i].page_size_mask != mr[i+1].page_size_mask)
-                       continue;
-               /* move it */
-               old_start = mr[i].start;
-               memmove(&mr[i], &mr[i+1],
-                        (nr_range - 1 - i) * sizeof (struct map_range));
-               mr[i--].start = old_start;
-               nr_range--;
-       }
-
-       for (i = 0; i < nr_range; i++)
-               printk(KERN_DEBUG " %010lx - %010lx page %s\n",
-                               mr[i].start, mr[i].end,
-                       (mr[i].page_size_mask & (1<<PG_LEVEL_1G))?"1G":(
-                        (mr[i].page_size_mask & (1<<PG_LEVEL_2M))?"2M":"4k"));
-
-       if (!after_bootmem)
-               find_early_table_space(end, use_pse, use_gbpages);
-
-       for (i = 0; i < nr_range; i++)
-               last_map_addr = kernel_physical_mapping_init(
-                                       mr[i].start, mr[i].end,
-                                       mr[i].page_size_mask);
-
-       if (!after_bootmem)
-               mmu_cr4_features = read_cr4();
-       __flush_tlb_all();
-
-       if (!after_bootmem && table_end > table_start)
-               reserve_early(table_start << PAGE_SHIFT,
-                                table_end << PAGE_SHIFT, "PGTABLE");
-
-       printk(KERN_INFO "last_map_addr: %lx end: %lx\n",
-                        last_map_addr, end);
-
-       if (!after_bootmem)
-               early_memtest(start, end);
-
-       return last_map_addr >> PAGE_SHIFT;
-}
-
 #ifndef CONFIG_NUMA
 void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn)
 {
@@ -910,28 +681,6 @@ EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
 
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
-/*
- * devmem_is_allowed() checks to see if /dev/mem access to a certain address
- * is valid. The argument is a physical page number.
- *
- *
- * On x86, access has to be given to the first megabyte of ram because that area
- * contains bios code and data regions used by X and dosemu and similar apps.
- * Access has to be given to non-kernel-ram areas as well, these contain the PCI
- * mmio resources as well as potential bios/acpi data regions.
- */
-int devmem_is_allowed(unsigned long pagenr)
-{
-       if (pagenr <= 256)
-               return 1;
-       if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
-               return 0;
-       if (!page_is_ram(pagenr))
-               return 1;
-       return 0;
-}
-
-
 static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel,
                         kcore_modules, kcore_vsyscall;
 
@@ -1019,13 +768,6 @@ void mark_rodata_ro(void)
 
 #endif
 
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_init_pages("initrd memory", start, end);
-}
-#endif
-
 int __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
                                   int flags)
 {
index 04102d42ff4250873a519620958855e9b50770ff..bff0c9032f8c6f7045518d9fdd2bd417a3be7634 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/iomap.h>
 #include <asm/pat.h>
 #include <linux/module.h>
+#include <linux/highmem.h>
 
 int is_io_mapping_possible(resource_size_t base, unsigned long size)
 {
@@ -31,16 +32,27 @@ int is_io_mapping_possible(resource_size_t base, unsigned long size)
 }
 EXPORT_SYMBOL_GPL(is_io_mapping_possible);
 
-/* Map 'pfn' using fixed map 'type' and protections 'prot'
- */
-void *
-iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
+void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
 {
        enum fixed_addresses idx;
        unsigned long vaddr;
 
        pagefault_disable();
 
+       idx = type + KM_TYPE_NR * smp_processor_id();
+       vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+       set_pte(kmap_pte - idx, pfn_pte(pfn, prot));
+       arch_flush_lazy_mmu_mode();
+
+       return (void *)vaddr;
+}
+
+/*
+ * Map 'pfn' using fixed map 'type' and protections 'prot'
+ */
+void *
+iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
+{
        /*
         * For non-PAT systems, promote PAGE_KERNEL_WC to PAGE_KERNEL_UC_MINUS.
         * PAGE_KERNEL_WC maps to PWT, which translates to uncached if the
@@ -50,12 +62,7 @@ iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
        if (!pat_enabled && pgprot_val(prot) == pgprot_val(PAGE_KERNEL_WC))
                prot = PAGE_KERNEL_UC_MINUS;
 
-       idx = type + KM_TYPE_NR*smp_processor_id();
-       vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
-       set_pte(kmap_pte-idx, pfn_pte(pfn, prot));
-       arch_flush_lazy_mmu_mode();
-
-       return (void*) vaddr;
+       return kmap_atomic_prot_pfn(pfn, type, prot);
 }
 EXPORT_SYMBOL_GPL(iomap_atomic_prot_pfn);
 
@@ -65,6 +72,7 @@ iounmap_atomic(void *kvaddr, enum km_type type)
        unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
        enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
 
+       debug_kmap_atomic(type);
        /*
         * Force other mappings to Oops if they'll try to access this pte
         * without first remap it.  Keeping stale mappings around is a bad idea
index 433f7bd4648af4206fbc4afb0b2fd6b6dab59b6e..0dfa09d69e80236ee47a94d6de8e7f8b8f0663c3 100644 (file)
 #include <asm/pgalloc.h>
 #include <asm/pat.h>
 
-#ifdef CONFIG_X86_64
-
-static inline int phys_addr_valid(unsigned long addr)
+static inline int phys_addr_valid(resource_size_t addr)
 {
-       return addr < (1UL << boot_cpu_data.x86_phys_bits);
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+       return !(addr >> boot_cpu_data.x86_phys_bits);
+#else
+       return 1;
+#endif
 }
 
+#ifdef CONFIG_X86_64
+
 unsigned long __phys_addr(unsigned long x)
 {
        if (x >= __START_KERNEL_map) {
@@ -38,8 +42,7 @@ unsigned long __phys_addr(unsigned long x)
        } else {
                VIRTUAL_BUG_ON(x < PAGE_OFFSET);
                x -= PAGE_OFFSET;
-               VIRTUAL_BUG_ON(system_state == SYSTEM_BOOTING ? x > MAXMEM :
-                                       !phys_addr_valid(x));
+               VIRTUAL_BUG_ON(!phys_addr_valid(x));
        }
        return x;
 }
@@ -56,10 +59,8 @@ bool __virt_addr_valid(unsigned long x)
                if (x < PAGE_OFFSET)
                        return false;
                x -= PAGE_OFFSET;
-               if (system_state == SYSTEM_BOOTING ?
-                               x > MAXMEM : !phys_addr_valid(x)) {
+               if (!phys_addr_valid(x))
                        return false;
-               }
        }
 
        return pfn_valid(x >> PAGE_SHIFT);
@@ -68,18 +69,12 @@ EXPORT_SYMBOL(__virt_addr_valid);
 
 #else
 
-static inline int phys_addr_valid(unsigned long addr)
-{
-       return 1;
-}
-
 #ifdef CONFIG_DEBUG_VIRTUAL
 unsigned long __phys_addr(unsigned long x)
 {
-       /* VMALLOC_* aren't constants; not available at the boot time */
+       /* VMALLOC_* aren't constants  */
        VIRTUAL_BUG_ON(x < PAGE_OFFSET);
-       VIRTUAL_BUG_ON(system_state != SYSTEM_BOOTING &&
-               is_vmalloc_addr((void *) x));
+       VIRTUAL_BUG_ON(__vmalloc_start_set && is_vmalloc_addr((void *) x));
        return x - PAGE_OFFSET;
 }
 EXPORT_SYMBOL(__phys_addr);
@@ -89,7 +84,9 @@ bool __virt_addr_valid(unsigned long x)
 {
        if (x < PAGE_OFFSET)
                return false;
-       if (system_state != SYSTEM_BOOTING && is_vmalloc_addr((void *) x))
+       if (__vmalloc_start_set && is_vmalloc_addr((void *) x))
+               return false;
+       if (x >= FIXADDR_START)
                return false;
        return pfn_valid((x - PAGE_OFFSET) >> PAGE_SHIFT);
 }
@@ -508,13 +505,19 @@ static inline pte_t * __init early_ioremap_pte(unsigned long addr)
        return &bm_pte[pte_index(addr)];
 }
 
+static unsigned long slot_virt[FIX_BTMAPS_SLOTS] __initdata;
+
 void __init early_ioremap_init(void)
 {
        pmd_t *pmd;
+       int i;
 
        if (early_ioremap_debug)
                printk(KERN_INFO "early_ioremap_init()\n");
 
+       for (i = 0; i < FIX_BTMAPS_SLOTS; i++)
+               slot_virt[i] = __fix_to_virt(FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*i);
+
        pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN));
        memset(bm_pte, 0, sizeof(bm_pte));
        pmd_populate_kernel(&init_mm, pmd, bm_pte);
@@ -581,6 +584,7 @@ static inline void __init early_clear_fixmap(enum fixed_addresses idx)
 
 static void __iomem *prev_map[FIX_BTMAPS_SLOTS] __initdata;
 static unsigned long prev_size[FIX_BTMAPS_SLOTS] __initdata;
+
 static int __init check_early_ioremap_leak(void)
 {
        int count = 0;
@@ -602,7 +606,8 @@ static int __init check_early_ioremap_leak(void)
 }
 late_initcall(check_early_ioremap_leak);
 
-static void __init __iomem *__early_ioremap(unsigned long phys_addr, unsigned long size, pgprot_t prot)
+static void __init __iomem *
+__early_ioremap(unsigned long phys_addr, unsigned long size, pgprot_t prot)
 {
        unsigned long offset, last_addr;
        unsigned int nrpages;
@@ -668,9 +673,9 @@ static void __init __iomem *__early_ioremap(unsigned long phys_addr, unsigned lo
                --nrpages;
        }
        if (early_ioremap_debug)
-               printk(KERN_CONT "%08lx + %08lx\n", offset, fix_to_virt(idx0));
+               printk(KERN_CONT "%08lx + %08lx\n", offset, slot_virt[slot]);
 
-       prev_map[slot] = (void __iomem *)(offset + fix_to_virt(idx0));
+       prev_map[slot] = (void __iomem *)(offset + slot_virt[slot]);
        return prev_map[slot];
 }
 
@@ -738,8 +743,3 @@ void __init early_iounmap(void __iomem *addr, unsigned long size)
        }
        prev_map[slot] = NULL;
 }
-
-void __this_fixmap_does_not_exist(void)
-{
-       WARN_ON(1);
-}
index 6a518dd08a36511661df2842815781c94a680fbd..4f115e00486bc1fe50fc8c1987298df3b8ac1266 100644 (file)
@@ -310,7 +310,7 @@ static int post_kmmio_handler(unsigned long condition, struct pt_regs *regs)
        struct kmmio_context *ctx = &get_cpu_var(kmmio_ctx);
 
        if (!ctx->active) {
-               pr_warning("kmmio: spurious debug trap on CPU %d.\n",
+               pr_debug("kmmio: spurious debug trap on CPU %d.\n",
                                                        smp_processor_id());
                goto out;
        }
index 0bcd7883d036d68e1943f49529c3e96c7a70fd62..605c8be06217b0da36344abd5f23d06326bcd87a 100644 (file)
@@ -100,6 +100,9 @@ static int __init parse_memtest(char *arg)
 {
        if (arg)
                memtest_pattern = simple_strtoul(arg, NULL, 0);
+       else
+               memtest_pattern = ARRAY_SIZE(patterns);
+
        return 0;
 }
 
index 451fe95a0352b3d63634231ea31c4eea016b2550..3daefa04ace535f693b07e5700e0470e17ca93b8 100644 (file)
@@ -416,10 +416,11 @@ void __init initmem_init(unsigned long start_pfn,
        for_each_online_node(nid)
                propagate_e820_map_node(nid);
 
-       for_each_online_node(nid)
+       for_each_online_node(nid) {
                memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
+               NODE_DATA(nid)->bdata = &bootmem_node_data[nid];
+       }
 
-       NODE_DATA(0)->bdata = &bootmem_node_data[0];
        setup_bootmem_allocator();
 }
 
index 9c4294986af779ed62ab088af0dae0f0048eb0c9..d71e1b636ce69167515c0a6bd3b47d3807b49175 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/processor.h>
 #include <asm/tlbflush.h>
 #include <asm/sections.h>
+#include <asm/setup.h>
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 #include <asm/proto.h>
@@ -33,6 +34,7 @@ struct cpa_data {
        unsigned long   pfn;
        unsigned        force_split : 1;
        int             curpage;
+       struct page     **pages;
 };
 
 /*
@@ -45,6 +47,7 @@ static DEFINE_SPINLOCK(cpa_lock);
 
 #define CPA_FLUSHTLB 1
 #define CPA_ARRAY 2
+#define CPA_PAGES_ARRAY 4
 
 #ifdef CONFIG_PROC_FS
 static unsigned long direct_pages_count[PG_LEVEL_NUM];
@@ -95,7 +98,7 @@ static inline unsigned long highmap_start_pfn(void)
 
 static inline unsigned long highmap_end_pfn(void)
 {
-       return __pa(roundup((unsigned long)_end, PMD_SIZE)) >> PAGE_SHIFT;
+       return __pa(roundup(_brk_end, PMD_SIZE)) >> PAGE_SHIFT;
 }
 
 #endif
@@ -201,10 +204,10 @@ static void cpa_flush_range(unsigned long start, int numpages, int cache)
        }
 }
 
-static void cpa_flush_array(unsigned long *start, int numpages, int cache)
+static void cpa_flush_array(unsigned long *start, int numpages, int cache,
+                           int in_flags, struct page **pages)
 {
        unsigned int i, level;
-       unsigned long *addr;
 
        BUG_ON(irqs_disabled());
 
@@ -225,14 +228,22 @@ static void cpa_flush_array(unsigned long *start, int numpages, int cache)
         * will cause all other CPUs to flush the same
         * cachelines:
         */
-       for (i = 0, addr = start; i < numpages; i++, addr++) {
-               pte_t *pte = lookup_address(*addr, &level);
+       for (i = 0; i < numpages; i++) {
+               unsigned long addr;
+               pte_t *pte;
+
+               if (in_flags & CPA_PAGES_ARRAY)
+                       addr = (unsigned long)page_address(pages[i]);
+               else
+                       addr = start[i];
+
+               pte = lookup_address(addr, &level);
 
                /*
                 * Only flush present addresses:
                 */
                if (pte && (pte_val(*pte) & _PAGE_PRESENT))
-                       clflush_cache_range((void *) *addr, PAGE_SIZE);
+                       clflush_cache_range((void *)addr, PAGE_SIZE);
        }
 }
 
@@ -584,7 +595,9 @@ static int __change_page_attr(struct cpa_data *cpa, int primary)
        unsigned int level;
        pte_t *kpte, old_pte;
 
-       if (cpa->flags & CPA_ARRAY)
+       if (cpa->flags & CPA_PAGES_ARRAY)
+               address = (unsigned long)page_address(cpa->pages[cpa->curpage]);
+       else if (cpa->flags & CPA_ARRAY)
                address = cpa->vaddr[cpa->curpage];
        else
                address = *cpa->vaddr;
@@ -687,7 +700,9 @@ static int cpa_process_alias(struct cpa_data *cpa)
         * No need to redo, when the primary call touched the direct
         * mapping already:
         */
-       if (cpa->flags & CPA_ARRAY)
+       if (cpa->flags & CPA_PAGES_ARRAY)
+               vaddr = (unsigned long)page_address(cpa->pages[cpa->curpage]);
+       else if (cpa->flags & CPA_ARRAY)
                vaddr = cpa->vaddr[cpa->curpage];
        else
                vaddr = *cpa->vaddr;
@@ -698,7 +713,7 @@ static int cpa_process_alias(struct cpa_data *cpa)
                alias_cpa = *cpa;
                temp_cpa_vaddr = (unsigned long) __va(cpa->pfn << PAGE_SHIFT);
                alias_cpa.vaddr = &temp_cpa_vaddr;
-               alias_cpa.flags &= ~CPA_ARRAY;
+               alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
 
 
                ret = __change_page_attr_set_clr(&alias_cpa, 0);
@@ -711,7 +726,7 @@ static int cpa_process_alias(struct cpa_data *cpa)
         * No need to redo, when the primary call touched the high
         * mapping already:
         */
-       if (within(vaddr, (unsigned long) _text, (unsigned long) _end))
+       if (within(vaddr, (unsigned long) _text, _brk_end))
                return 0;
 
        /*
@@ -724,7 +739,7 @@ static int cpa_process_alias(struct cpa_data *cpa)
        alias_cpa = *cpa;
        temp_cpa_vaddr = (cpa->pfn << PAGE_SHIFT) + __START_KERNEL_map - phys_base;
        alias_cpa.vaddr = &temp_cpa_vaddr;
-       alias_cpa.flags &= ~CPA_ARRAY;
+       alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
 
        /*
         * The high mapping range is imprecise, so ignore the return value.
@@ -745,7 +760,7 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias)
                 */
                cpa->numpages = numpages;
                /* for array changes, we can't use large page */
-               if (cpa->flags & CPA_ARRAY)
+               if (cpa->flags & (CPA_ARRAY | CPA_PAGES_ARRAY))
                        cpa->numpages = 1;
 
                if (!debug_pagealloc)
@@ -769,7 +784,7 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias)
                 */
                BUG_ON(cpa->numpages > numpages);
                numpages -= cpa->numpages;
-               if (cpa->flags & CPA_ARRAY)
+               if (cpa->flags & (CPA_PAGES_ARRAY | CPA_ARRAY))
                        cpa->curpage++;
                else
                        *cpa->vaddr += cpa->numpages * PAGE_SIZE;
@@ -786,7 +801,8 @@ static inline int cache_attr(pgprot_t attr)
 
 static int change_page_attr_set_clr(unsigned long *addr, int numpages,
                                    pgprot_t mask_set, pgprot_t mask_clr,
-                                   int force_split, int array)
+                                   int force_split, int in_flag,
+                                   struct page **pages)
 {
        struct cpa_data cpa;
        int ret, cache, checkalias;
@@ -801,15 +817,7 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
                return 0;
 
        /* Ensure we are PAGE_SIZE aligned */
-       if (!array) {
-               if (*addr & ~PAGE_MASK) {
-                       *addr &= PAGE_MASK;
-                       /*
-                        * People should not be passing in unaligned addresses:
-                        */
-                       WARN_ON_ONCE(1);
-               }
-       } else {
+       if (in_flag & CPA_ARRAY) {
                int i;
                for (i = 0; i < numpages; i++) {
                        if (addr[i] & ~PAGE_MASK) {
@@ -817,6 +825,18 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
                                WARN_ON_ONCE(1);
                        }
                }
+       } else if (!(in_flag & CPA_PAGES_ARRAY)) {
+               /*
+                * in_flag of CPA_PAGES_ARRAY implies it is aligned.
+                * No need to cehck in that case
+                */
+               if (*addr & ~PAGE_MASK) {
+                       *addr &= PAGE_MASK;
+                       /*
+                        * People should not be passing in unaligned addresses:
+                        */
+                       WARN_ON_ONCE(1);
+               }
        }
 
        /* Must avoid aliasing mappings in the highmem code */
@@ -832,6 +852,7 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
        arch_flush_lazy_mmu_mode();
 
        cpa.vaddr = addr;
+       cpa.pages = pages;
        cpa.numpages = numpages;
        cpa.mask_set = mask_set;
        cpa.mask_clr = mask_clr;
@@ -839,8 +860,8 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
        cpa.curpage = 0;
        cpa.force_split = force_split;
 
-       if (array)
-               cpa.flags |= CPA_ARRAY;
+       if (in_flag & (CPA_ARRAY | CPA_PAGES_ARRAY))
+               cpa.flags |= in_flag;
 
        /* No alias checking for _NX bit modifications */
        checkalias = (pgprot_val(mask_set) | pgprot_val(mask_clr)) != _PAGE_NX;
@@ -866,9 +887,10 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
         * wbindv):
         */
        if (!ret && cpu_has_clflush) {
-               if (cpa.flags & CPA_ARRAY)
-                       cpa_flush_array(addr, numpages, cache);
-               else
+               if (cpa.flags & (CPA_PAGES_ARRAY | CPA_ARRAY)) {
+                       cpa_flush_array(addr, numpages, cache,
+                                       cpa.flags, pages);
+               } else
                        cpa_flush_range(*addr, numpages, cache);
        } else
                cpa_flush_all(cache);
@@ -888,14 +910,28 @@ static inline int change_page_attr_set(unsigned long *addr, int numpages,
                                       pgprot_t mask, int array)
 {
        return change_page_attr_set_clr(addr, numpages, mask, __pgprot(0), 0,
-               array);
+               (array ? CPA_ARRAY : 0), NULL);
 }
 
 static inline int change_page_attr_clear(unsigned long *addr, int numpages,
                                         pgprot_t mask, int array)
 {
        return change_page_attr_set_clr(addr, numpages, __pgprot(0), mask, 0,
-               array);
+               (array ? CPA_ARRAY : 0), NULL);
+}
+
+static inline int cpa_set_pages_array(struct page **pages, int numpages,
+                                      pgprot_t mask)
+{
+       return change_page_attr_set_clr(NULL, numpages, mask, __pgprot(0), 0,
+               CPA_PAGES_ARRAY, pages);
+}
+
+static inline int cpa_clear_pages_array(struct page **pages, int numpages,
+                                        pgprot_t mask)
+{
+       return change_page_attr_set_clr(NULL, numpages, __pgprot(0), mask, 0,
+               CPA_PAGES_ARRAY, pages);
 }
 
 int _set_memory_uc(unsigned long addr, int numpages)
@@ -1043,7 +1079,7 @@ int set_memory_np(unsigned long addr, int numpages)
 int set_memory_4k(unsigned long addr, int numpages)
 {
        return change_page_attr_set_clr(&addr, numpages, __pgprot(0),
-                                       __pgprot(0), 1, 0);
+                                       __pgprot(0), 1, 0, NULL);
 }
 
 int set_pages_uc(struct page *page, int numpages)
@@ -1054,6 +1090,35 @@ int set_pages_uc(struct page *page, int numpages)
 }
 EXPORT_SYMBOL(set_pages_uc);
 
+int set_pages_array_uc(struct page **pages, int addrinarray)
+{
+       unsigned long start;
+       unsigned long end;
+       int i;
+       int free_idx;
+
+       for (i = 0; i < addrinarray; i++) {
+               start = (unsigned long)page_address(pages[i]);
+               end = start + PAGE_SIZE;
+               if (reserve_memtype(start, end, _PAGE_CACHE_UC_MINUS, NULL))
+                       goto err_out;
+       }
+
+       if (cpa_set_pages_array(pages, addrinarray,
+                       __pgprot(_PAGE_CACHE_UC_MINUS)) == 0) {
+               return 0; /* Success */
+       }
+err_out:
+       free_idx = i;
+       for (i = 0; i < free_idx; i++) {
+               start = (unsigned long)page_address(pages[i]);
+               end = start + PAGE_SIZE;
+               free_memtype(start, end);
+       }
+       return -EINVAL;
+}
+EXPORT_SYMBOL(set_pages_array_uc);
+
 int set_pages_wb(struct page *page, int numpages)
 {
        unsigned long addr = (unsigned long)page_address(page);
@@ -1062,6 +1127,26 @@ int set_pages_wb(struct page *page, int numpages)
 }
 EXPORT_SYMBOL(set_pages_wb);
 
+int set_pages_array_wb(struct page **pages, int addrinarray)
+{
+       int retval;
+       unsigned long start;
+       unsigned long end;
+       int i;
+
+       retval = cpa_clear_pages_array(pages, addrinarray,
+                       __pgprot(_PAGE_CACHE_MASK));
+
+       for (i = 0; i < addrinarray; i++) {
+               start = (unsigned long)page_address(pages[i]);
+               end = start + PAGE_SIZE;
+               free_memtype(start, end);
+       }
+
+       return retval;
+}
+EXPORT_SYMBOL(set_pages_array_wb);
+
 int set_pages_x(struct page *page, int numpages)
 {
        unsigned long addr = (unsigned long)page_address(page);
index 2ed37158012dc0017879730c9cd4d00e4a45d8cf..640339ee4fb2ae7ab79c02302cf26d0647966344 100644 (file)
@@ -677,10 +677,11 @@ 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.
+        * reserve_pfn_range() doesn't support RAM pages. Maintain the current
+        * behavior with RAM pages by returning success.
         */
        if (is_ram != 0)
-               return -EINVAL;
+               return 0;
 
        ret = reserve_memtype(paddr, paddr + size, want_flags, &flags);
        if (ret)
index f2e477c91c1b85d72bb3d7ec0659e647c67c968c..46c8834aedc0fe3c16e5c88d70012f62f436a3c3 100644 (file)
@@ -50,7 +50,7 @@ void set_pte_vaddr(unsigned long vaddr, pte_t pteval)
        }
        pte = pte_offset_kernel(pmd, vaddr);
        if (pte_val(pteval))
-               set_pte_present(&init_mm, vaddr, pte, pteval);
+               set_pte_at(&init_mm, vaddr, pte, pteval);
        else
                pte_clear(&init_mm, vaddr, pte);
 
index a654d59e448327e640d239698625afaf9944d34e..821e97017e954a8a8e74a607950c583061412d7a 100644 (file)
@@ -186,11 +186,6 @@ static void flush_tlb_others_ipi(const struct cpumask *cpumask,
        cpumask_andnot(to_cpumask(f->flush_cpumask),
                       cpumask, cpumask_of(smp_processor_id()));
 
-       /*
-        * Make the above memory operations globally visible before
-        * sending the IPI.
-        */
-       smp_mb();
        /*
         * We have to send the IPI only to
         * CPUs affected.
index 82d22fc601ae3acc0ebb83df9d116e95ec66ea96..8c362b96b644953f018b2001541714dbbfab0c29 100644 (file)
@@ -90,7 +90,7 @@ static int __devinit can_skip_ioresource_align(const struct dmi_system_id *d)
        return 0;
 }
 
-static struct dmi_system_id can_skip_pciprobe_dmi_table[] __devinitdata = {
+static const struct dmi_system_id can_skip_pciprobe_dmi_table[] __devinitconst = {
 /*
  * Systems where PCI IO resource ISA alignment can be skipped
  * when the ISA enable bit in the bridge control is not set
@@ -183,7 +183,7 @@ static int __devinit assign_all_busses(const struct dmi_system_id *d)
 }
 #endif
 
-static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
+static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = {
 #ifdef __i386__
 /*
  * Laptops which need pci=assign-busses to see Cardbus cards
index f6adf2c6d7514148eb7e6221dea010f55158f97d..aaf26ae58cd5cadb73ae168cd7f46edf9cc2b4f3 100644 (file)
@@ -69,11 +69,12 @@ void early_dump_pci_device(u8 bus, u8 slot, u8 func)
        int j;
        u32 val;
 
-       printk(KERN_INFO "PCI: %02x:%02x:%02x", bus, slot, func);
+       printk(KERN_INFO "pci 0000:%02x:%02x.%d config space:",
+              bus, slot, func);
 
        for (i = 0; i < 256; i += 4) {
                if (!(i & 0x0f))
-                       printk("\n%04x:",i);
+                       printk("\n  %02x:",i);
 
                val = read_pci_config(bus, slot, func, i);
                for (j = 0; j < 4; j++) {
@@ -96,20 +97,22 @@ void early_dump_pci_devices(void)
                        for (func = 0; func < 8; func++) {
                                u32 class;
                                u8 type;
+
                                class = read_pci_config(bus, slot, func,
                                                        PCI_CLASS_REVISION);
                                if (class == 0xffffffff)
-                                       break;
+                                       continue;
 
                                early_dump_pci_device(bus, slot, func);
 
-                               /* No multi-function device? */
-                               type = read_pci_config_byte(bus, slot, func,
+                               if (func == 0) {
+                                       type = read_pci_config_byte(bus, slot,
+                                                                   func,
                                                               PCI_HEADER_TYPE);
-                               if (!(type & 0x80))
-                                       break;
+                                       if (!(type & 0x80))
+                                               break;
+                               }
                        }
                }
        }
 }
-
index 7d388d5cf54852136da06d0ca08b04c646fc7199..6dd89555fbfa9bdddd8f797f6fe48231ef773be9 100644 (file)
@@ -356,7 +356,7 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev)
 DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
 
 
-static struct dmi_system_id __devinitdata msi_k8t_dmi_table[] = {
+static const struct dmi_system_id __devinitconst msi_k8t_dmi_table[] = {
        {
                .ident = "MSI-K8T-Neo2Fir",
                .matches = {
@@ -413,7 +413,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237,
  */
 static u16 toshiba_line_size;
 
-static struct dmi_system_id __devinitdata toshiba_ohci1394_dmi_table[] = {
+static const struct dmi_system_id __devinitconst toshiba_ohci1394_dmi_table[] = {
        {
                .ident = "Toshiba PS5 based laptop",
                .matches = {
@@ -494,26 +494,6 @@ static void __devinit pci_siemens_interrupt_controller(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SIEMENS, 0x0015,
                          pci_siemens_interrupt_controller);
 
-/*
- * Regular PCI devices have 256 bytes, but AMD Family 10h/11h CPUs have
- * 4096 bytes configuration space for each function of their processor
- * configuration space.
- */
-static void amd_cpu_pci_cfg_space_size(struct pci_dev *dev)
-{
-       dev->cfg_size = pci_cfg_space_size_ext(dev);
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1200, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1201, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1202, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1203, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1204, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1300, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1301, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1302, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1303, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1304, amd_cpu_pci_cfg_space_size);
-
 /*
  * SB600: Disable BAR1 on device 14.0 to avoid HPET resources from
  * confusing the PCI engine:
index 5ead808dd70c3ec34dbd34da39600851b9c30619..f234a37bd428c73aa0e8623079bfbe5e06923948 100644 (file)
@@ -319,6 +319,9 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                        return -EINVAL;
                }
                flags = new_flags;
+               vma->vm_page_prot = __pgprot(
+                       (pgprot_val(vma->vm_page_prot) & ~_PAGE_CACHE_MASK) |
+                       flags);
        }
 
        if (((vma->vm_pgoff < max_low_pfn_mapped) ||
index f1065b129e9cf981fa52c374dcf3bf2c4987fe36..4061bb0f267de399ef8d05720a8c735712be8299 100644 (file)
@@ -50,8 +50,6 @@ static int __init pci_legacy_init(void)
        if (pci_root_bus)
                pci_bus_add_devices(pci_root_bus);
 
-       pcibios_fixup_peer_bridges();
-
        return 0;
 }
 
@@ -67,6 +65,7 @@ int __init pci_subsys_init(void)
        pci_visws_init();
 #endif
        pci_legacy_init();
+       pcibios_fixup_peer_bridges();
        pcibios_irq_init();
        pcibios_init();
 
index 89bf9242c80a3b068fa2c1fcf3f6cba4b447193d..905bb526b13350e88e258c69162240f5e99fbee3 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/acpi.h>
 #include <linux/bitmap.h>
+#include <linux/sort.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
 
 /* Indicate if the mmcfg resources have been placed into the resource table. */
 static int __initdata pci_mmcfg_resources_inserted;
 
+static __init int extend_mmcfg(int num)
+{
+       struct acpi_mcfg_allocation *new;
+       int new_num = pci_mmcfg_config_num + num;
+
+       new = kzalloc(sizeof(pci_mmcfg_config[0]) * new_num, GFP_KERNEL);
+       if (!new)
+               return -1;
+
+       if (pci_mmcfg_config) {
+               memcpy(new, pci_mmcfg_config,
+                        sizeof(pci_mmcfg_config[0]) * new_num);
+               kfree(pci_mmcfg_config);
+       }
+       pci_mmcfg_config = new;
+
+       return 0;
+}
+
+static __init void fill_one_mmcfg(u64 addr, int segment, int start, int end)
+{
+       int i = pci_mmcfg_config_num;
+
+       pci_mmcfg_config_num++;
+       pci_mmcfg_config[i].address = addr;
+       pci_mmcfg_config[i].pci_segment = segment;
+       pci_mmcfg_config[i].start_bus_number = start;
+       pci_mmcfg_config[i].end_bus_number = end;
+}
+
 static const char __init *pci_mmcfg_e7520(void)
 {
        u32 win;
        raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0xce, 2, &win);
 
        win = win & 0xf000;
-       if(win == 0x0000 || win == 0xf000)
-               pci_mmcfg_config_num = 0;
-       else {
-               pci_mmcfg_config_num = 1;
-               pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
-               if (!pci_mmcfg_config)
-                       return NULL;
-               pci_mmcfg_config[0].address = win << 16;
-               pci_mmcfg_config[0].pci_segment = 0;
-               pci_mmcfg_config[0].start_bus_number = 0;
-               pci_mmcfg_config[0].end_bus_number = 255;
-       }
+       if (win == 0x0000 || win == 0xf000)
+               return NULL;
+
+       if (extend_mmcfg(1) == -1)
+               return NULL;
+
+       fill_one_mmcfg(win << 16, 0, 0, 255);
 
        return "Intel Corporation E7520 Memory Controller Hub";
 }
@@ -50,13 +76,11 @@ static const char __init *pci_mmcfg_intel_945(void)
 {
        u32 pciexbar, mask = 0, len = 0;
 
-       pci_mmcfg_config_num = 1;
-
        raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0x48, 4, &pciexbar);
 
        /* Enable bit */
        if (!(pciexbar & 1))
-               pci_mmcfg_config_num = 0;
+               return NULL;
 
        /* Size bits */
        switch ((pciexbar >> 1) & 3) {
@@ -73,28 +97,23 @@ static const char __init *pci_mmcfg_intel_945(void)
                len  = 0x04000000U;
                break;
        default:
-               pci_mmcfg_config_num = 0;
+               return NULL;
        }
 
        /* Errata #2, things break when not aligned on a 256Mb boundary */
        /* Can only happen in 64M/128M mode */
 
        if ((pciexbar & mask) & 0x0fffffffU)
-               pci_mmcfg_config_num = 0;
+               return NULL;
 
        /* Don't hit the APIC registers and their friends */
        if ((pciexbar & mask) >= 0xf0000000U)
-               pci_mmcfg_config_num = 0;
-
-       if (pci_mmcfg_config_num) {
-               pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
-               if (!pci_mmcfg_config)
-                       return NULL;
-               pci_mmcfg_config[0].address = pciexbar & mask;
-               pci_mmcfg_config[0].pci_segment = 0;
-               pci_mmcfg_config[0].start_bus_number = 0;
-               pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1;
-       }
+               return NULL;
+
+       if (extend_mmcfg(1) == -1)
+               return NULL;
+
+       fill_one_mmcfg(pciexbar & mask, 0, 0, (len >> 20) - 1);
 
        return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
 }
@@ -138,22 +157,77 @@ static const char __init *pci_mmcfg_amd_fam10h(void)
                busnbits = 8;
        }
 
-       pci_mmcfg_config_num = (1 << segnbits);
-       pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]) *
-                                  pci_mmcfg_config_num, GFP_KERNEL);
-       if (!pci_mmcfg_config)
+       if (extend_mmcfg(1 << segnbits) == -1)
                return NULL;
 
-       for (i = 0; i < (1 << segnbits); i++) {
-               pci_mmcfg_config[i].address = base + (1<<28) * i;
-               pci_mmcfg_config[i].pci_segment = i;
-               pci_mmcfg_config[i].start_bus_number = 0;
-               pci_mmcfg_config[i].end_bus_number = (1 << busnbits) - 1;
-       }
+       for (i = 0; i < (1 << segnbits); i++)
+               fill_one_mmcfg(base + (1<<28) * i, i, 0, (1 << busnbits) - 1);
 
        return "AMD Family 10h NB";
 }
 
+static bool __initdata mcp55_checked;
+static const char __init *pci_mmcfg_nvidia_mcp55(void)
+{
+       int bus;
+       int mcp55_mmconf_found = 0;
+
+       static const u32 extcfg_regnum          = 0x90;
+       static const u32 extcfg_regsize         = 4;
+       static const u32 extcfg_enable_mask     = 1<<31;
+       static const u32 extcfg_start_mask      = 0xff<<16;
+       static const int extcfg_start_shift     = 16;
+       static const u32 extcfg_size_mask       = 0x3<<28;
+       static const int extcfg_size_shift      = 28;
+       static const int extcfg_sizebus[]       = {0x100, 0x80, 0x40, 0x20};
+       static const u32 extcfg_base_mask[]     = {0x7ff8, 0x7ffc, 0x7ffe, 0x7fff};
+       static const int extcfg_base_lshift     = 25;
+
+       /*
+        * do check if amd fam10h already took over
+        */
+       if (!acpi_disabled || pci_mmcfg_config_num || mcp55_checked)
+               return NULL;
+
+       mcp55_checked = true;
+       for (bus = 0; bus < 256; bus++) {
+               u64 base;
+               u32 l, extcfg;
+               u16 vendor, device;
+               int start, size_index, end;
+
+               raw_pci_ops->read(0, bus, PCI_DEVFN(0, 0), 0, 4, &l);
+               vendor = l & 0xffff;
+               device = (l >> 16) & 0xffff;
+
+               if (PCI_VENDOR_ID_NVIDIA != vendor || 0x0369 != device)
+                       continue;
+
+               raw_pci_ops->read(0, bus, PCI_DEVFN(0, 0), extcfg_regnum,
+                                 extcfg_regsize, &extcfg);
+
+               if (!(extcfg & extcfg_enable_mask))
+                       continue;
+
+               if (extend_mmcfg(1) == -1)
+                       continue;
+
+               size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift;
+               base = extcfg & extcfg_base_mask[size_index];
+               /* base could > 4G */
+               base <<= extcfg_base_lshift;
+               start = (extcfg & extcfg_start_mask) >> extcfg_start_shift;
+               end = start + extcfg_sizebus[size_index] - 1;
+               fill_one_mmcfg(base, 0, start, end);
+               mcp55_mmconf_found++;
+       }
+
+       if (!mcp55_mmconf_found)
+               return NULL;
+
+       return "nVidia MCP55";
+}
+
 struct pci_mmcfg_hostbridge_probe {
        u32 bus;
        u32 devfn;
@@ -171,8 +245,52 @@ static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
          0x1200, pci_mmcfg_amd_fam10h },
        { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD,
          0x1200, pci_mmcfg_amd_fam10h },
+       { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_NVIDIA,
+         0x0369, pci_mmcfg_nvidia_mcp55 },
 };
 
+static int __init cmp_mmcfg(const void *x1, const void *x2)
+{
+       const typeof(pci_mmcfg_config[0]) *m1 = x1;
+       const typeof(pci_mmcfg_config[0]) *m2 = x2;
+       int start1, start2;
+
+       start1 = m1->start_bus_number;
+       start2 = m2->start_bus_number;
+
+       return start1 - start2;
+}
+
+static void __init pci_mmcfg_check_end_bus_number(void)
+{
+       int i;
+       typeof(pci_mmcfg_config[0]) *cfg, *cfgx;
+
+       /* sort them at first */
+       sort(pci_mmcfg_config, pci_mmcfg_config_num,
+                sizeof(pci_mmcfg_config[0]), cmp_mmcfg, NULL);
+
+       /* last one*/
+       if (pci_mmcfg_config_num > 0) {
+               i = pci_mmcfg_config_num - 1;
+               cfg = &pci_mmcfg_config[i];
+               if (cfg->end_bus_number < cfg->start_bus_number)
+                       cfg->end_bus_number = 255;
+       }
+
+       /* don't overlap please */
+       for (i = 0; i < pci_mmcfg_config_num - 1; i++) {
+               cfg = &pci_mmcfg_config[i];
+               cfgx = &pci_mmcfg_config[i+1];
+
+               if (cfg->end_bus_number < cfg->start_bus_number)
+                       cfg->end_bus_number = 255;
+
+               if (cfg->end_bus_number >= cfgx->start_bus_number)
+                       cfg->end_bus_number = cfgx->start_bus_number - 1;
+       }
+}
+
 static int __init pci_mmcfg_check_hostbridge(void)
 {
        u32 l;
@@ -186,31 +304,33 @@ static int __init pci_mmcfg_check_hostbridge(void)
 
        pci_mmcfg_config_num = 0;
        pci_mmcfg_config = NULL;
-       name = NULL;
 
-       for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
+       for (i = 0; i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
                bus =  pci_mmcfg_probes[i].bus;
                devfn = pci_mmcfg_probes[i].devfn;
                raw_pci_ops->read(0, bus, devfn, 0, 4, &l);
                vendor = l & 0xffff;
                device = (l >> 16) & 0xffff;
 
+               name = NULL;
                if (pci_mmcfg_probes[i].vendor == vendor &&
                    pci_mmcfg_probes[i].device == device)
                        name = pci_mmcfg_probes[i].probe();
-       }
 
-       if (name) {
-               printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n",
-                      name, pci_mmcfg_config_num ? "with" : "without");
+               if (name)
+                       printk(KERN_INFO "PCI: Found %s with MMCONFIG support.\n",
+                              name);
        }
 
-       return name != NULL;
+       /* some end_bus_number is crazy, fix it */
+       pci_mmcfg_check_end_bus_number();
+
+       return pci_mmcfg_config_num != 0;
 }
 
 static void __init pci_mmcfg_insert_resources(void)
 {
-#define PCI_MMCFG_RESOURCE_NAME_LEN 19
+#define PCI_MMCFG_RESOURCE_NAME_LEN 24
        int i;
        struct resource *res;
        char *names;
@@ -228,9 +348,10 @@ static void __init pci_mmcfg_insert_resources(void)
                struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i];
                num_buses = cfg->end_bus_number - cfg->start_bus_number + 1;
                res->name = names;
-               snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u",
-                        cfg->pci_segment);
-               res->start = cfg->address;
+               snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN,
+                        "PCI MMCONFIG %u [%02x-%02x]", cfg->pci_segment,
+                        cfg->start_bus_number, cfg->end_bus_number);
+               res->start = cfg->address + (cfg->start_bus_number << 20);
                res->end = res->start + (num_buses << 20) - 1;
                res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
                insert_resource(&iomem_resource, res);
@@ -354,8 +475,6 @@ static void __init pci_mmcfg_reject_broken(int early)
            (pci_mmcfg_config[0].address == 0))
                return;
 
-       cfg = &pci_mmcfg_config[0];
-
        for (i = 0; i < pci_mmcfg_config_num; i++) {
                int valid = 0;
                u64 addr, size;
@@ -423,10 +542,10 @@ static void __init __pci_mmcfg_init(int early)
                        known_bridge = 1;
        }
 
-       if (!known_bridge) {
+       if (!known_bridge)
                acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
-               pci_mmcfg_reject_broken(early);
-       }
+
+       pci_mmcfg_reject_broken(early);
 
        if ((pci_mmcfg_config_num == 0) ||
            (pci_mmcfg_config == NULL) ||
index 30007ffc8e11d203922d2c8304c5d0bdb909ef33..94349f8b2f964b969f7cc576ad92a50cfac75049 100644 (file)
@@ -112,13 +112,18 @@ static struct pci_raw_ops pci_mmcfg = {
 static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg)
 {
        void __iomem *addr;
-       u32 size;
-
-       size = (cfg->end_bus_number + 1) << 20;
-       addr = ioremap_nocache(cfg->address, size);
+       u64 start, size;
+
+       start = cfg->start_bus_number;
+       start <<= 20;
+       start += cfg->address;
+       size = cfg->end_bus_number + 1 - cfg->start_bus_number;
+       size <<= 20;
+       addr = ioremap_nocache(start, size);
        if (addr) {
                printk(KERN_INFO "PCI: Using MMCONFIG at %Lx - %Lx\n",
-                      cfg->address, cfg->address + size - 1);
+                      start, start + size - 1);
+               addr -= cfg->start_bus_number << 20;
        }
        return addr;
 }
@@ -157,7 +162,7 @@ void __init pci_mmcfg_arch_free(void)
 
        for (i = 0; i < pci_mmcfg_config_num; ++i) {
                if (pci_mmcfg_virt[i].virt) {
-                       iounmap(pci_mmcfg_virt[i].virt);
+                       iounmap(pci_mmcfg_virt[i].virt + (pci_mmcfg_virt[i].cfg->start_bus_number << 20));
                        pci_mmcfg_virt[i].virt = NULL;
                        pci_mmcfg_virt[i].cfg = NULL;
                }
index 274d06082f4851bfcf71c621f7a62db447e54876..ce702c5b3a2c13fded43ab9629c6210352b3772a 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/mtrr.h>
 #include <asm/mce.h>
 #include <asm/xcr.h>
+#include <asm/suspend.h>
 
 static struct saved_context saved_context;
 
index e3b6cf70d62c504d42f757980ddf562a5cc1ac30..5343540f26074bac105a66790733e66723e1e615 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/pgtable.h>
 #include <asm/mtrr.h>
 #include <asm/xcr.h>
+#include <asm/suspend.h>
 
 static void fix_processor_context(void);
 
index 6dd000dd793394c398a8d02dd9254d6a68fd963b..65fdc86e923fd92175b95bfef56ad1c82d64bc2d 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/mtrr.h>
+#include <asm/suspend.h>
 
 /* References to section boundaries */
 extern const void __nosave_begin, __nosave_end;
index cb6afa4ec95c524ce8e95fa20b47b88a2f65dac9..db3802fb7b8470082aac4ba2884e6a588bda694d 100644 (file)
@@ -1723,9 +1723,9 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
 {
        pmd_t *kernel_pmd;
 
-       init_pg_tables_start = __pa(pgd);
-       init_pg_tables_end = __pa(pgd) + xen_start_info->nr_pt_frames*PAGE_SIZE;
-       max_pfn_mapped = PFN_DOWN(init_pg_tables_end + 512*1024);
+       max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->pt_base) +
+                                 xen_start_info->nr_pt_frames * PAGE_SIZE +
+                                 512*1024);
 
        kernel_pmd = m2v(pgd[KERNEL_PGD_BOUNDARY].pgd);
        memcpy(level2_kernel_pgt, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD);
@@ -1870,7 +1870,6 @@ const struct pv_mmu_ops xen_mmu_ops __initdata = {
 
 #ifdef CONFIG_X86_PAE
        .set_pte_atomic = xen_set_pte_atomic,
-       .set_pte_present = xen_set_pte_at,
        .pte_clear = xen_pte_clear,
        .pmd_clear = xen_pmd_clear,
 #endif /* CONFIG_X86_PAE */
index 9185597eb6a046b1ccc5f17ad6a9c216a12f0815..031f36685710d087d4b5b7f8426542ea97bc3178 100644 (file)
@@ -172,7 +172,7 @@ void prepare_to_copy(struct task_struct *tsk)
  *       childregs.
  */
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(unsigned long clone_flags, unsigned long usp,
                unsigned long unused,
                 struct task_struct * p, struct pt_regs * regs)
 {
index 25d46c84eb0836c4933a451c632099ae68759a77..4c559cf7da2d8c13c0a0529f5ae2e458b65257d1 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/major.h>
 #include <linux/param.h>
+#include <linux/seq_file.h>
 #include <linux/serial.h>
 #include <linux/serialP.h>
 
@@ -176,22 +177,24 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
        /* Stub, once again.. */
 }
 
-static int rs_read_proc(char *page, char **start, off_t off, int count,
-                       int *eof, void *data)
+static int rs_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0;
-       off_t begin = 0;
-
-       len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
-       *eof = 1;
-
-       if (off >= len + begin)
-               return 0;
+       seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version);
+       return 0;
+}
 
-       *start = page + (off - begin);
-       return ((count < begin + len - off) ? count : begin + len - off);
+static int rs_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, rs_proc_show, NULL);
 }
 
+static const struct file_operations rs_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = rs_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
 static struct tty_operations serial_ops = {
        .open = rs_open,
@@ -203,7 +206,7 @@ static struct tty_operations serial_ops = {
        .chars_in_buffer = rs_chars_in_buffer,
        .hangup = rs_hangup,
        .wait_until_sent = rs_wait_until_sent,
-       .read_proc = rs_read_proc
+       .proc_fops = &rs_proc_fops,
 };
 
 int __init rs_init(void)
index 9b917dac77322b4aa397549aa4874ed0c4ad8dab..88e42abf5d881b8bf443ecc4f58e3b4e76b3ecd3 100644 (file)
@@ -191,7 +191,6 @@ static int acpi_ac_add_fs(struct acpi_device *device)
                                                     acpi_ac_dir);
                if (!acpi_device_dir(device))
                        return -ENODEV;
-               acpi_device_dir(device)->owner = THIS_MODULE;
        }
 
        /* 'state' [R] */
index 69cbc57c2d1cd248e7431bb40661e9ea139efbb7..3bcb5bfc45d3366645bfdf6a417d6c140e30107d 100644 (file)
@@ -760,7 +760,6 @@ static int acpi_battery_add_fs(struct acpi_device *device)
                                                     acpi_battery_dir);
                if (!acpi_device_dir(device))
                        return -ENODEV;
-               acpi_device_dir(device)->owner = THIS_MODULE;
        }
 
        for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
index 171fd914f43533f46bf417dd4d4a7b6936fc6e50..c2f06069dcd40d614a20c0a5e3a2883d47535a9a 100644 (file)
@@ -200,12 +200,10 @@ static int acpi_button_add_fs(struct acpi_device *device)
 
        if (!entry)
                return -ENODEV;
-       entry->owner = THIS_MODULE;
 
        acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry);
        if (!acpi_device_dir(device))
                return -ENODEV;
-       acpi_device_dir(device)->owner = THIS_MODULE;
 
        /* 'info' [R] */
        entry = proc_create_data(ACPI_BUTTON_FILE_INFO,
@@ -522,7 +520,6 @@ static int __init acpi_button_init(void)
        acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
        if (!acpi_button_dir)
                return -ENODEV;
-       acpi_button_dir->owner = THIS_MODULE;
        result = acpi_bus_register_driver(&acpi_button_driver);
        if (result < 0) {
                remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
index eaaee1660bdf41ec490696b812b2c17869daffe9..8a02944bf92d687e4b1cf5c3e79b8efce59c9d6a 100644 (file)
@@ -193,7 +193,6 @@ static int acpi_fan_add_fs(struct acpi_device *device)
                                                     acpi_fan_dir);
                if (!acpi_device_dir(device))
                        return -ENODEV;
-               acpi_device_dir(device)->owner = THIS_MODULE;
        }
 
        /* 'status' [R/W] */
@@ -347,7 +346,6 @@ static int __init acpi_fan_init(void)
        acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir);
        if (!acpi_fan_dir)
                return -ENODEV;
-       acpi_fan_dir->owner = THIS_MODULE;
 #endif
 
        result = acpi_bus_register_driver(&acpi_fan_driver);
index 5b38a026d1220113aec9c88cbb08f325537012d3..196f97d00956aa379b95b8fbe8e5a6cb6ddd10eb 100644 (file)
@@ -66,11 +66,18 @@ struct acpi_pci_root {
        struct acpi_device * device;
        struct acpi_pci_id id;
        struct pci_bus *bus;
+
+       u32 osc_support_set;    /* _OSC state of support bits */
+       u32 osc_control_set;    /* _OSC state of control bits */
+       u32 osc_control_qry;    /* the latest _OSC query result */
+
+       u32 osc_queried:1;      /* has _OSC control been queried? */
 };
 
 static LIST_HEAD(acpi_pci_roots);
 
 static struct acpi_pci_driver *sub_driver;
+static DEFINE_MUTEX(osc_lock);
 
 int acpi_pci_register_driver(struct acpi_pci_driver *driver)
 {
@@ -185,6 +192,175 @@ static void acpi_pci_bridge_scan(struct acpi_device *device)
                }
 }
 
+static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40,
+                         0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66};
+
+static acpi_status acpi_pci_run_osc(acpi_handle handle,
+                                   const u32 *capbuf, u32 *retval)
+{
+       acpi_status status;
+       struct acpi_object_list input;
+       union acpi_object in_params[4];
+       struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
+       union acpi_object *out_obj;
+       u32 errors;
+
+       /* Setting up input parameters */
+       input.count = 4;
+       input.pointer = in_params;
+       in_params[0].type               = ACPI_TYPE_BUFFER;
+       in_params[0].buffer.length      = 16;
+       in_params[0].buffer.pointer     = OSC_UUID;
+       in_params[1].type               = ACPI_TYPE_INTEGER;
+       in_params[1].integer.value      = 1;
+       in_params[2].type               = ACPI_TYPE_INTEGER;
+       in_params[2].integer.value      = 3;
+       in_params[3].type               = ACPI_TYPE_BUFFER;
+       in_params[3].buffer.length      = 12;
+       in_params[3].buffer.pointer     = (u8 *)capbuf;
+
+       status = acpi_evaluate_object(handle, "_OSC", &input, &output);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       if (!output.length)
+               return AE_NULL_OBJECT;
+
+       out_obj = output.pointer;
+       if (out_obj->type != ACPI_TYPE_BUFFER) {
+               printk(KERN_DEBUG "_OSC evaluation returned wrong type\n");
+               status = AE_TYPE;
+               goto out_kfree;
+       }
+       /* Need to ignore the bit0 in result code */
+       errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
+       if (errors) {
+               if (errors & OSC_REQUEST_ERROR)
+                       printk(KERN_DEBUG "_OSC request failed\n");
+               if (errors & OSC_INVALID_UUID_ERROR)
+                       printk(KERN_DEBUG "_OSC invalid UUID\n");
+               if (errors & OSC_INVALID_REVISION_ERROR)
+                       printk(KERN_DEBUG "_OSC invalid revision\n");
+               if (errors & OSC_CAPABILITIES_MASK_ERROR) {
+                       if (capbuf[OSC_QUERY_TYPE] & OSC_QUERY_ENABLE)
+                               goto out_success;
+                       printk(KERN_DEBUG
+                              "Firmware did not grant requested _OSC control\n");
+                       status = AE_SUPPORT;
+                       goto out_kfree;
+               }
+               status = AE_ERROR;
+               goto out_kfree;
+       }
+out_success:
+       *retval = *((u32 *)(out_obj->buffer.pointer + 8));
+       status = AE_OK;
+
+out_kfree:
+       kfree(output.pointer);
+       return status;
+}
+
+static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags)
+{
+       acpi_status status;
+       u32 support_set, result, capbuf[3];
+
+       /* do _OSC query for all possible controls */
+       support_set = root->osc_support_set | (flags & OSC_SUPPORT_MASKS);
+       capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
+       capbuf[OSC_SUPPORT_TYPE] = support_set;
+       capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
+
+       status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
+       if (ACPI_SUCCESS(status)) {
+               root->osc_support_set = support_set;
+               root->osc_control_qry = result;
+               root->osc_queried = 1;
+       }
+       return status;
+}
+
+static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags)
+{
+       acpi_status status;
+       acpi_handle tmp;
+
+       status = acpi_get_handle(root->device->handle, "_OSC", &tmp);
+       if (ACPI_FAILURE(status))
+               return status;
+       mutex_lock(&osc_lock);
+       status = acpi_pci_query_osc(root, flags);
+       mutex_unlock(&osc_lock);
+       return status;
+}
+
+static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
+{
+       struct acpi_pci_root *root;
+       list_for_each_entry(root, &acpi_pci_roots, node) {
+               if (root->device->handle == handle)
+                       return root;
+       }
+       return NULL;
+}
+
+/**
+ * acpi_pci_osc_control_set - commit requested control to Firmware
+ * @handle: acpi_handle for the target ACPI object
+ * @flags: driver's requested control bits
+ *
+ * Attempt to take control from Firmware on requested control bits.
+ **/
+acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
+{
+       acpi_status status;
+       u32 control_req, result, capbuf[3];
+       acpi_handle tmp;
+       struct acpi_pci_root *root;
+
+       status = acpi_get_handle(handle, "_OSC", &tmp);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       control_req = (flags & OSC_CONTROL_MASKS);
+       if (!control_req)
+               return AE_TYPE;
+
+       root = acpi_pci_find_root(handle);
+       if (!root)
+               return AE_NOT_EXIST;
+
+       mutex_lock(&osc_lock);
+       /* No need to evaluate _OSC if the control was already granted. */
+       if ((root->osc_control_set & control_req) == control_req)
+               goto out;
+
+       /* Need to query controls first before requesting them */
+       if (!root->osc_queried) {
+               status = acpi_pci_query_osc(root, root->osc_support_set);
+               if (ACPI_FAILURE(status))
+                       goto out;
+       }
+       if ((root->osc_control_qry & control_req) != control_req) {
+               printk(KERN_DEBUG
+                      "Firmware did not grant requested _OSC control\n");
+               status = AE_SUPPORT;
+               goto out;
+       }
+
+       capbuf[OSC_QUERY_TYPE] = 0;
+       capbuf[OSC_SUPPORT_TYPE] = root->osc_support_set;
+       capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req;
+       status = acpi_pci_run_osc(handle, capbuf, &result);
+       if (ACPI_SUCCESS(status))
+               root->osc_control_set = result;
+out:
+       mutex_unlock(&osc_lock);
+       return status;
+}
+EXPORT_SYMBOL(acpi_pci_osc_control_set);
+
 static int __devinit acpi_pci_root_add(struct acpi_device *device)
 {
        int result = 0;
@@ -217,7 +393,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
         * PCI domains, so we indicate this in _OSC support capabilities.
         */
        flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
-       pci_acpi_osc_support(device->handle, flags);
+       acpi_pci_osc_support(root, flags);
 
        /* 
         * Segment
@@ -353,7 +529,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
        if (pci_msi_enabled())
                flags |= OSC_MSI_SUPPORT;
        if (flags != base_flags)
-               pci_acpi_osc_support(device->handle, flags);
+               acpi_pci_osc_support(root, flags);
 
       end:
        if (result) {
index 0cc2fd31e3765f7c9b945460345533dfebf1424b..fa2f7422d23de1e2bec5ee3702fa15e2a5ca284c 100644 (file)
@@ -359,7 +359,6 @@ static int acpi_processor_add_fs(struct acpi_device *device)
                if (!acpi_device_dir(device))
                        return -ENODEV;
        }
-       acpi_device_dir(device)->owner = THIS_MODULE;
 
        /* 'info' [R] */
        entry = proc_create_data(ACPI_PROCESSOR_FILE_INFO,
@@ -1137,7 +1136,6 @@ static int __init acpi_processor_init(void)
        acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
        if (!acpi_processor_dir)
                return -ENOMEM;
-       acpi_processor_dir->owner = THIS_MODULE;
 
        /*
         * Check whether the system is DMI table. If yes, OSPM
index 6050ce4818731fd2bcf8c6891d5a343414d0133a..59afd52ccc121aace5b3d47b56442d718901a090 100644 (file)
@@ -488,7 +488,6 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir,
                if (!*dir) {
                        return -ENODEV;
                }
-               (*dir)->owner = THIS_MODULE;
        }
 
        /* 'info' [R] */
index 99e6f1f8ea457677e1b989c711e37e1b339e60c3..c11f9aeca706f88b164d932d15e88886b070615b 100644 (file)
@@ -1506,7 +1506,6 @@ static int acpi_thermal_add_fs(struct acpi_device *device)
                                                     acpi_thermal_dir);
                if (!acpi_device_dir(device))
                        return -ENODEV;
-               acpi_device_dir(device)->owner = THIS_MODULE;
        }
 
        /* 'state' [R] */
@@ -1875,7 +1874,6 @@ static int __init acpi_thermal_init(void)
        acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir);
        if (!acpi_thermal_dir)
                return -ENODEV;
-       acpi_thermal_dir->owner = THIS_MODULE;
 
        result = acpi_bus_register_driver(&acpi_thermal_driver);
        if (result < 0) {
index bb5ed059114aa296e826b91f8b35083ccc773028..67cc36dc9b82fe94b7430628076191e3a6246894 100644 (file)
@@ -1125,8 +1125,6 @@ static int acpi_video_device_add_fs(struct acpi_device *device)
        if (!device_dir)
                return -ENOMEM;
 
-       device_dir->owner = THIS_MODULE;
-
        /* 'info' [R] */
        entry = proc_create_data("info", S_IRUGO, device_dir,
                        &acpi_video_device_info_fops, acpi_driver_data(device));
@@ -1403,8 +1401,6 @@ static int acpi_video_bus_add_fs(struct acpi_device *device)
        if (!device_dir)
                return -ENOMEM;
 
-       device_dir->owner = THIS_MODULE;
-
        /* 'info' [R] */
        entry = proc_create_data("info", S_IRUGO, device_dir,
                                 &acpi_video_bus_info_fops,
@@ -2131,7 +2127,6 @@ static int __init acpi_video_init(void)
        acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
        if (!acpi_video_dir)
                return -ENODEV;
-       acpi_video_dir->owner = THIS_MODULE;
 
        result = acpi_bus_register_driver(&acpi_video_bus);
        if (result < 0) {
index 14b9d5f4c203d28d3bcc639e6f1f8580d77093f0..c07e725ea93db3ffdffb933917b0be456911b724 100644 (file)
@@ -6,7 +6,6 @@
 #
 
 menuconfig AUXDISPLAY
-       depends on PARPORT
        bool "Auxiliary Display support"
        ---help---
          Say Y here to get to see options for auxiliary display drivers.
@@ -14,7 +13,7 @@ menuconfig AUXDISPLAY
 
          If you say N, all options in this submenu will be skipped and disabled.
 
-if AUXDISPLAY && PARPORT
+if AUXDISPLAY
 
 config KS0108
        tristate "KS0108 LCD Controller"
index 5b257a57bc57ae60e369950b60126f3d43f43e04..e62a4ccea54d0c4a3dc6dcd84eb107e557bcb54c 100644 (file)
@@ -119,7 +119,7 @@ static ssize_t print_cpus_map(char *buf, const struct cpumask *map)
 #define        print_cpus_func(type) \
 static ssize_t print_cpus_##type(struct sysdev_class *class, char *buf)        \
 {                                                                      \
-       return print_cpus_map(buf, &cpu_##type##_map);                  \
+       return print_cpus_map(buf, cpu_##type##_mask);                  \
 }                                                                      \
 static struct sysdev_class_attribute attr_##type##_map =               \
        _SYSDEV_CLASS_ATTR(type, 0444, print_cpus_##type, NULL)
index 5e039d4f877c206e26052bde2e2e5e7564f86d35..c2d1eed903767484304b1f3208c27719b5ec3195 100644 (file)
@@ -31,7 +31,7 @@ void register_iommu(struct iommu_ops *ops)
        iommu_ops = ops;
 }
 
-bool iommu_found()
+bool iommu_found(void)
 {
        return iommu_ops != NULL;
 }
index e255341682c88d4a0955f1151595c1334e005dd5..69b4ddb7de3b8c00d59a34fd16af5dc789e7b109 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/pm.h>
 #include <linux/resume-trace.h>
 #include <linux/rwsem.h>
+#include <linux/interrupt.h>
 
 #include "../base.h"
 #include "power.h"
@@ -349,7 +350,8 @@ static int resume_device_noirq(struct device *dev, pm_message_t state)
  *     Execute the appropriate "noirq resume" callback for all devices marked
  *     as DPM_OFF_IRQ.
  *
- *     Must be called with interrupts disabled and only one CPU running.
+ *     Must be called under dpm_list_mtx.  Device drivers should not receive
+ *     interrupts while it's being executed.
  */
 static void dpm_power_up(pm_message_t state)
 {
@@ -370,14 +372,13 @@ static void dpm_power_up(pm_message_t state)
  *     device_power_up - Turn on all devices that need special attention.
  *     @state: PM transition of the system being carried out.
  *
- *     Power on system devices, then devices that required we shut them down
- *     with interrupts disabled.
- *
- *     Must be called with interrupts disabled.
+ *     Call the "early" resume handlers and enable device drivers to receive
+ *     interrupts.
  */
 void device_power_up(pm_message_t state)
 {
        dpm_power_up(state);
+       resume_device_irqs();
 }
 EXPORT_SYMBOL_GPL(device_power_up);
 
@@ -602,16 +603,17 @@ static int suspend_device_noirq(struct device *dev, pm_message_t state)
  *     device_power_down - Shut down special devices.
  *     @state: PM transition of the system being carried out.
  *
- *     Power down devices that require interrupts to be disabled.
- *     Then power down system devices.
+ *     Prevent device drivers from receiving interrupts and call the "late"
+ *     suspend handlers.
  *
- *     Must be called with interrupts disabled and only one CPU running.
+ *     Must be called under dpm_list_mtx.
  */
 int device_power_down(pm_message_t state)
 {
        struct device *dev;
        int error = 0;
 
+       suspend_device_irqs();
        list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
                error = suspend_device_noirq(dev, state);
                if (error) {
@@ -621,7 +623,7 @@ int device_power_down(pm_message_t state)
                dev->power.status = DPM_OFF_IRQ;
        }
        if (error)
-               dpm_power_up(resume_event(state));
+               device_power_up(resume_event(state));
        return error;
 }
 EXPORT_SYMBOL_GPL(device_power_down);
index cbd36cf59a0f2e2af74ddc9255f64380299a6666..76ce75bad91eb56e897012494a0bdbafde24b9a6 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/pm.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
+#include <linux/interrupt.h>
 
 #include "base.h"
 
@@ -369,6 +370,13 @@ int sysdev_suspend(pm_message_t state)
        struct sysdev_driver *drv, *err_drv;
        int ret;
 
+       pr_debug("Checking wake-up interrupts\n");
+
+       /* Return error code if there are any wake-up interrupts pending */
+       ret = check_wakeup_irqs();
+       if (ret)
+               return ret;
+
        pr_debug("Suspending System Devices\n");
 
        list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
index c2c95e614506761a98ace446e02219203e5530dd..1300df6f1642a9a84fb345c22f9f88850cd1fe29 100644 (file)
@@ -177,6 +177,7 @@ static int print_unex = 1;
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
 #include <linux/buffer_head.h> /* for invalidate_buffers() */
 #include <linux/mutex.h>
 
@@ -4597,6 +4598,13 @@ MODULE_AUTHOR("Alain L. Knaff");
 MODULE_SUPPORTED_DEVICE("fd");
 MODULE_LICENSE("GPL");
 
+/* This doesn't actually get used other than for module information */
+static const struct pnp_device_id floppy_pnpids[] = {
+       { "PNP0700", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
+
 #else
 
 __setup("floppy=", floppy_setup);
index 2621ed2ce6d299c186391ddfb19635fc3470bf73..40b17d3b55a1b2559b0f69cd2f507dae5e243bd1 100644 (file)
@@ -1192,6 +1192,30 @@ loop_get_status64(struct loop_device *lo, struct loop_info64 __user *arg) {
        return err;
 }
 
+static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev)
+{
+       int err;
+       sector_t sec;
+       loff_t sz;
+
+       err = -ENXIO;
+       if (unlikely(lo->lo_state != Lo_bound))
+               goto out;
+       err = figure_loop_size(lo);
+       if (unlikely(err))
+               goto out;
+       sec = get_capacity(lo->lo_disk);
+       /* the width of sector_t may be narrow for bit-shift */
+       sz = sec;
+       sz <<= 9;
+       mutex_lock(&bdev->bd_mutex);
+       bd_set_size(bdev, sz);
+       mutex_unlock(&bdev->bd_mutex);
+
+ out:
+       return err;
+}
+
 static int lo_ioctl(struct block_device *bdev, fmode_t mode,
        unsigned int cmd, unsigned long arg)
 {
@@ -1224,6 +1248,11 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
        case LOOP_GET_STATUS64:
                err = loop_get_status64(lo, (struct loop_info64 __user *) arg);
                break;
+       case LOOP_SET_CAPACITY:
+               err = -EPERM;
+               if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
+                       err = loop_set_capacity(lo, bdev);
+               break;
        default:
                err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
        }
@@ -1371,6 +1400,7 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode,
                        lo, (struct compat_loop_info __user *) arg);
                mutex_unlock(&lo->lo_ctl_mutex);
                break;
+       case LOOP_SET_CAPACITY:
        case LOOP_CLR_FD:
        case LOOP_GET_STATUS64:
        case LOOP_SET_STATUS64:
index 8299e2d3b61163b2d2d82bb8b00ea4495e3000f9..4d6de4f15ccb34dd4039ed4bf3e53b5993751958 100644 (file)
@@ -4,7 +4,7 @@
  * Note that you can not swap over this thing, yet. Seems to work but
  * deadlocks sometimes - you can not swap over TCP in general.
  * 
- * Copyright 1997-2000 Pavel Machek <pavel@ucw.cz>
+ * Copyright 1997-2000, 2008 Pavel Machek <pavel@suse.cz>
  * Parts copyright 2001 Steven Whitehouse <steve@chygwyn.com>
  *
  * This file is released under GPLv2 or later.
@@ -276,7 +276,7 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req)
        return 0;
 
 error_out:
-       return 1;
+       return -EIO;
 }
 
 static struct request *nbd_find_request(struct nbd_device *lo,
@@ -467,9 +467,7 @@ static void nbd_handle_req(struct nbd_device *lo, struct request *req)
                mutex_unlock(&lo->tx_lock);
                printk(KERN_ERR "%s: Attempted send on closed socket\n",
                       lo->disk->disk_name);
-               req->errors++;
-               nbd_end_request(req);
-               return;
+               goto error_out;
        }
 
        lo->active_req = req;
@@ -531,7 +529,7 @@ static int nbd_thread(void *data)
  *   { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); }
  */
 
-static void do_nbd_request(struct request_queue * q)
+static void do_nbd_request(struct request_queue *q)
 {
        struct request *req;
        
@@ -568,27 +566,17 @@ static void do_nbd_request(struct request_queue * q)
        }
 }
 
-static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
-                    unsigned int cmd, unsigned long arg)
-{
-       struct nbd_device *lo = bdev->bd_disk->private_data;
-       struct file *file;
-       int error;
-       struct request sreq ;
-       struct task_struct *thread;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       BUG_ON(lo->magic != LO_MAGIC);
-
-       /* Anyone capable of this syscall can do *real bad* things */
-       dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",
-                       lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
+/* Must be called with tx_lock held */
 
+static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
+                      unsigned int cmd, unsigned long arg)
+{
        switch (cmd) {
-       case NBD_DISCONNECT:
+       case NBD_DISCONNECT: {
+               struct request sreq;
+
                printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name);
+
                blk_rq_init(NULL, &sreq);
                sreq.cmd_type = REQ_TYPE_SPECIAL;
                nbd_cmd(&sreq) = NBD_CMD_DISC;
@@ -599,29 +587,29 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
                 */
                sreq.sector = 0;
                sreq.nr_sectors = 0;
-                if (!lo->sock)
+               if (!lo->sock)
                        return -EINVAL;
-               mutex_lock(&lo->tx_lock);
-                nbd_send_req(lo, &sreq);
-               mutex_unlock(&lo->tx_lock);
+               nbd_send_req(lo, &sreq);
                 return 0;
+       }
  
-       case NBD_CLEAR_SOCK:
-               error = 0;
-               mutex_lock(&lo->tx_lock);
+       case NBD_CLEAR_SOCK: {
+               struct file *file;
+
                lo->sock = NULL;
-               mutex_unlock(&lo->tx_lock);
                file = lo->file;
                lo->file = NULL;
                nbd_clear_que(lo);
                BUG_ON(!list_empty(&lo->queue_head));
                if (file)
                        fput(file);
-               return error;
-       case NBD_SET_SOCK:
+               return 0;
+       }
+
+       case NBD_SET_SOCK: {
+               struct file *file;
                if (lo->file)
                        return -EBUSY;
-               error = -EINVAL;
                file = fget(arg);
                if (file) {
                        struct inode *inode = file->f_path.dentry->d_inode;
@@ -630,12 +618,14 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
                                lo->sock = SOCKET_I(inode);
                                if (max_part > 0)
                                        bdev->bd_invalidated = 1;
-                               error = 0;
+                               return 0;
                        } else {
                                fput(file);
                        }
                }
-               return error;
+               return -EINVAL;
+       }
+
        case NBD_SET_BLKSIZE:
                lo->blksize = arg;
                lo->bytesize &= ~(lo->blksize-1);
@@ -643,35 +633,50 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
                set_blocksize(bdev, lo->blksize);
                set_capacity(lo->disk, lo->bytesize >> 9);
                return 0;
+
        case NBD_SET_SIZE:
                lo->bytesize = arg & ~(lo->blksize-1);
                bdev->bd_inode->i_size = lo->bytesize;
                set_blocksize(bdev, lo->blksize);
                set_capacity(lo->disk, lo->bytesize >> 9);
                return 0;
+
        case NBD_SET_TIMEOUT:
                lo->xmit_timeout = arg * HZ;
                return 0;
+
        case NBD_SET_SIZE_BLOCKS:
                lo->bytesize = ((u64) arg) * lo->blksize;
                bdev->bd_inode->i_size = lo->bytesize;
                set_blocksize(bdev, lo->blksize);
                set_capacity(lo->disk, lo->bytesize >> 9);
                return 0;
-       case NBD_DO_IT:
+
+       case NBD_DO_IT: {
+               struct task_struct *thread;
+               struct file *file;
+               int error;
+
                if (lo->pid)
                        return -EBUSY;
                if (!lo->file)
                        return -EINVAL;
+
+               mutex_unlock(&lo->tx_lock);
+
                thread = kthread_create(nbd_thread, lo, lo->disk->disk_name);
-               if (IS_ERR(thread))
+               if (IS_ERR(thread)) {
+                       mutex_lock(&lo->tx_lock);
                        return PTR_ERR(thread);
+               }
                wake_up_process(thread);
                error = nbd_do_it(lo);
                kthread_stop(thread);
+
+               mutex_lock(&lo->tx_lock);
                if (error)
                        return error;
-               sock_shutdown(lo, 1);
+               sock_shutdown(lo, 0);
                file = lo->file;
                lo->file = NULL;
                nbd_clear_que(lo);
@@ -684,6 +689,8 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
                if (max_part > 0)
                        ioctl_by_bdev(bdev, BLKRRPART, 0);
                return lo->harderror;
+       }
+
        case NBD_CLEAR_QUE:
                /*
                 * This is for compatibility only.  The queue is always cleared
@@ -691,6 +698,7 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
                 */
                BUG_ON(!lo->sock && !list_empty(&lo->queue_head));
                return 0;
+
        case NBD_PRINT_DEBUG:
                printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n",
                        bdev->bd_disk->disk_name,
@@ -698,7 +706,29 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
                        &lo->queue_head);
                return 0;
        }
-       return -EINVAL;
+       return -ENOTTY;
+}
+
+static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
+                    unsigned int cmd, unsigned long arg)
+{
+       struct nbd_device *lo = bdev->bd_disk->private_data;
+       int error;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       BUG_ON(lo->magic != LO_MAGIC);
+
+       /* Anyone capable of this syscall can do *real bad* things */
+       dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",
+                       lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
+
+       mutex_lock(&lo->tx_lock);
+       error = __nbd_ioctl(bdev, lo, cmd, arg);
+       mutex_unlock(&lo->tx_lock);
+
+       return error;
 }
 
 static struct block_device_operations nbd_fops =
index 393ed6760d783c155a2a0846d8de03c505167057..8eddef373a9197d9db8834d5ba15d1f743b85ee2 100644 (file)
@@ -551,8 +551,6 @@ static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev)
                dev_warn(&dev->core, "failed to create /proc entry\n");
                return;
        }
-
-       pde->owner = THIS_MODULE;
        pde->data = priv;
 }
 
index a58869ea8513826d32af82688c661b50fdd90071..fd3ebd1be570f98062ae3761bf6a51d3b1145427 100644 (file)
@@ -79,6 +79,7 @@ static char *serial_version = "4.30";
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
@@ -1825,14 +1826,13 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
  * /proc fs routines....
  */
 
-static inline int line_info(char *buf, struct serial_state *state)
+static inline void line_info(struct seq_file *m, struct serial_state *state)
 {
        struct async_struct *info = state->info, scr_info;
        char    stat_buf[30], control, status;
-       int     ret;
        unsigned long flags;
 
-       ret = sprintf(buf, "%d: uart:amiga_builtin",state->line);
+       seq_printf(m, "%d: uart:amiga_builtin",state->line);
 
        /*
         * Figure out the current RS-232 lines
@@ -1864,55 +1864,49 @@ static inline int line_info(char *buf, struct serial_state *state)
                strcat(stat_buf, "|CD");
 
        if (info->quot) {
-               ret += sprintf(buf+ret, " baud:%d",
-                              state->baud_base / info->quot);
+               seq_printf(m, " baud:%d", state->baud_base / info->quot);
        }
 
-       ret += sprintf(buf+ret, " tx:%d rx:%d",
-                     state->icount.tx, state->icount.rx);
+       seq_printf(m, " tx:%d rx:%d", state->icount.tx, state->icount.rx);
 
        if (state->icount.frame)
-               ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
+               seq_printf(m, " fe:%d", state->icount.frame);
 
        if (state->icount.parity)
-               ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
+               seq_printf(m, " pe:%d", state->icount.parity);
 
        if (state->icount.brk)
-               ret += sprintf(buf+ret, " brk:%d", state->icount.brk);
+               seq_printf(m, " brk:%d", state->icount.brk);
 
        if (state->icount.overrun)
-               ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
+               seq_printf(m, " oe:%d", state->icount.overrun);
 
        /*
         * Last thing is the RS-232 status lines
         */
-       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
-       return ret;
+       seq_printf(m, " %s\n", stat_buf+1);
 }
 
-static int rs_read_proc(char *page, char **start, off_t off, int count,
-                       int *eof, void *data)
+static int rs_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0, l;
-       off_t   begin = 0;
-
-       len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
-       l = line_info(page + len, &rs_table[0]);
-       len += l;
-       if (len+begin > off+count)
-         goto done;
-       if (len+begin < off) {
-         begin += len;
-         len = 0;
-       }
-       *eof = 1;
-done:
-       if (off >= len+begin)
-               return 0;
-       *start = page + (off-begin);
-       return ((count < begin+len-off) ? count : begin+len-off);
+       seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version);
+       line_info(m, &rs_table[0]);
+       return 0;
 }
 
+static int rs_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, rs_proc_show, NULL);
+}
+
+static const struct file_operations rs_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = rs_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*
  * ---------------------------------------------------------------------
  * rs_init() and friends
@@ -1951,9 +1945,9 @@ static const struct tty_operations serial_ops = {
        .break_ctl = rs_break,
        .send_xchar = rs_send_xchar,
        .wait_until_sent = rs_wait_until_sent,
-       .read_proc = rs_read_proc,
        .tiocmget = rs_tiocmget,
        .tiocmset = rs_tiocmset,
+       .proc_fops = &rs_proc_fops,
 };
 
 /*
index 6a59f72a9c2157697de1a3228a19296e1fc89fb2..272db0e2b491188103f8658ed77e02671004f782 100644 (file)
 
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 
 static void cy_throttle(struct tty_struct *tty);
 static void cy_send_xchar(struct tty_struct *tty, char ch);
@@ -868,8 +869,6 @@ static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
 static unsigned detect_isa_irq(void __iomem *);
 #endif                         /* CONFIG_ISA */
 
-static int cyclades_get_proc_info(char *, char **, off_t, int, int *, void *);
-
 #ifndef CONFIG_CYZ_INTR
 static void cyz_poll(unsigned long);
 
@@ -5216,31 +5215,22 @@ static struct pci_driver cy_pci_driver = {
 };
 #endif
 
-static int
-cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
-               int *eof, void *data)
+static int cyclades_proc_show(struct seq_file *m, void *v)
 {
        struct cyclades_port *info;
        unsigned int i, j;
-       int len = 0;
-       off_t begin = 0;
-       off_t pos = 0;
-       int size;
        __u32 cur_jifs = jiffies;
 
-       size = sprintf(buf, "Dev TimeOpen   BytesOut  IdleOut    BytesIn   "
+       seq_puts(m, "Dev TimeOpen   BytesOut  IdleOut    BytesIn   "
                        "IdleIn  Overruns  Ldisc\n");
 
-       pos += size;
-       len += size;
-
        /* Output one line for each known port */
        for (i = 0; i < NR_CARDS; i++)
                for (j = 0; j < cy_card[i].nports; j++) {
                        info = &cy_card[i].ports[j];
 
                        if (info->port.count)
-                               size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
+                               seq_printf(m, "%3d %8lu %10lu %8lu "
                                        "%10lu %8lu %9lu %6ld\n", info->line,
                                        (cur_jifs - info->idle_stats.in_use) /
                                        HZ, info->idle_stats.xmit_bytes,
@@ -5251,30 +5241,26 @@ cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
                                        /* FIXME: double check locking */
                                        (long)info->port.tty->ldisc.ops->num);
                        else
-                               size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
+                               seq_printf(m, "%3d %8lu %10lu %8lu "
                                        "%10lu %8lu %9lu %6ld\n",
                                        info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
-                       len += size;
-                       pos = begin + len;
-
-                       if (pos < offset) {
-                               len = 0;
-                               begin = pos;
-                       }
-                       if (pos > offset + length)
-                               goto done;
                }
-       *eof = 1;
-done:
-       *start = buf + (offset - begin);        /* Start of wanted data */
-       len -= (offset - begin);        /* Start slop */
-       if (len > length)
-               len = length;   /* Ending slop */
-       if (len < 0)
-               len = 0;
-       return len;
+       return 0;
+}
+
+static int cyclades_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, cyclades_proc_show, NULL);
 }
 
+static const struct file_operations cyclades_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = cyclades_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /* The serial driver boot-time initialization code!
     Hardware I/O ports are mapped to character special devices on a
     first found, first allocated manner.  That is, this code searches
@@ -5311,9 +5297,9 @@ static const struct tty_operations cy_ops = {
        .hangup = cy_hangup,
        .break_ctl = cy_break,
        .wait_until_sent = cy_wait_until_sent,
-       .read_proc = cyclades_get_proc_info,
        .tiocmget = cy_tiocmget,
        .tiocmset = cy_tiocmset,
+       .proc_fops = &cyclades_proc_fops,
 };
 
 static int __init cy_init(void)
index 32b8bbf5003e17678a996e50ccb2c9b38d018886..50dfa3bc71cee00de3eeb20858416ce4a4941bfd 100644 (file)
@@ -713,7 +713,7 @@ static struct ctl_table_header *sysctl_header;
  */
 #define        TICK_CALIBRATE  (1000UL)
 
-static unsigned long hpet_calibrate(struct hpets *hpetp)
+static unsigned long __hpet_calibrate(struct hpets *hpetp)
 {
        struct hpet_timer __iomem *timer = NULL;
        unsigned long t, m, count, i, flags, start;
@@ -750,6 +750,26 @@ static unsigned long hpet_calibrate(struct hpets *hpetp)
        return (m - start) / i;
 }
 
+static unsigned long hpet_calibrate(struct hpets *hpetp)
+{
+       unsigned long ret = -1;
+       unsigned long tmp;
+
+       /*
+        * Try to calibrate until return value becomes stable small value.
+        * If SMI interruption occurs in calibration loop, the return value
+        * will be big. This avoids its impact.
+        */
+       for ( ; ; ) {
+               tmp = __hpet_calibrate(hpetp);
+               if (ret <= tmp)
+                       break;
+               ret = tmp;
+       }
+
+       return ret;
+}
+
 int hpet_alloc(struct hpet_data *hdp)
 {
        u64 cap, mcfg;
index 70e0ebc30bd08d5b9e034b2b22c341475c761252..afd9247cf082d15e2cb6f1e8273c72fba9317ba5 100644 (file)
 #include <linux/seq_file.h>
 
 static const struct file_operations ip2mem_proc_fops;
-static int ip2_read_proc(char *, char **, off_t, int, int *, void * );
+static const struct file_operations ip2_proc_fops;
 
 /********************/
 /* Type Definitions */
@@ -446,9 +446,9 @@ static const struct tty_operations ip2_ops = {
        .stop            = ip2_stop,
        .start           = ip2_start,
        .hangup          = ip2_hangup,
-       .read_proc       = ip2_read_proc,
        .tiocmget        = ip2_tiocmget,
        .tiocmset        = ip2_tiocmset,
+       .proc_fops       = &ip2_proc_fops,
 };
 
 /******************************************************************************/
@@ -3029,19 +3029,17 @@ static const struct file_operations ip2mem_proc_fops = {
  * different sources including ip2mkdev.c and a couple of other drivers.
  * The bugs are all mine.  :-) =mhw=
  */
-static int ip2_read_proc(char *page, char **start, off_t off,
-                               int count, int *eof, void *data)
+static int ip2_proc_show(struct seq_file *m, void *v)
 {
        int     i, j, box;
-       int     len = 0;
        int     boxes = 0;
        int     ports = 0;
        int     tports = 0;
-       off_t   begin = 0;
        i2eBordStrPtr  pB;
+       char *sep;
 
-       len += sprintf(page, "ip2info: 1.0 driver: %s\n", pcVersion );
-       len += sprintf(page+len, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n",
+       seq_printf(m, "ip2info: 1.0 driver: %s\n", pcVersion);
+       seq_printf(m, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n",
                        IP2_TTY_MAJOR, IP2_CALLOUT_MAJOR, IP2_IPL_MAJOR,
                        IP2_MAX_BOARDS, ABS_MAX_BOXES, ABS_BIGGEST_BOX);
 
@@ -3053,7 +3051,8 @@ static int ip2_read_proc(char *page, char **start, off_t off,
                        switch( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) 
                        {
                        case POR_ID_FIIEX:
-                               len += sprintf( page+len, "Board %d: EX ports=", i );
+                               seq_printf(m, "Board %d: EX ports=", i);
+                               sep = "";
                                for( box = 0; box < ABS_MAX_BOXES; ++box )
                                {
                                        ports = 0;
@@ -3065,79 +3064,74 @@ static int ip2_read_proc(char *page, char **start, off_t off,
                                                        ++ports;
                                                }
                                        }
-                                       len += sprintf( page+len, "%d,", ports );
+                                       seq_printf(m, "%s%d", sep, ports);
+                                       sep = ",";
                                        tports += ports;
                                }
-
-                               --len;  /* Backup over that last comma */
-
-                               len += sprintf( page+len, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8 );
+                               seq_printf(m, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8);
                                break;
 
                        case POR_ID_II_4:
-                               len += sprintf(page+len, "Board %d: ISA-4 ports=4 boxes=1", i );
+                               seq_printf(m, "Board %d: ISA-4 ports=4 boxes=1", i);
                                tports = ports = 4;
                                break;
 
                        case POR_ID_II_8:
-                               len += sprintf(page+len, "Board %d: ISA-8-std ports=8 boxes=1", i );
+                               seq_printf(m, "Board %d: ISA-8-std ports=8 boxes=1", i);
                                tports = ports = 8;
                                break;
 
                        case POR_ID_II_8R:
-                               len += sprintf(page+len, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i );
+                               seq_printf(m, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i);
                                tports = ports = 8;
                                break;
 
                        default:
-                               len += sprintf(page+len, "Board %d: unknown", i );
+                               seq_printf(m, "Board %d: unknown", i);
                                /* Don't try and probe for minor numbers */
                                tports = ports = 0;
                        }
 
                } else {
                        /* Don't try and probe for minor numbers */
-                       len += sprintf(page+len, "Board %d: vacant", i );
+                       seq_printf(m, "Board %d: vacant", i);
                        tports = ports = 0;
                }
 
                if( tports ) {
-                       len += sprintf(page+len, " minors=" );
-
+                       seq_puts(m, " minors=");
+                       sep = "";
                        for ( box = 0; box < ABS_MAX_BOXES; ++box )
                        {
                                for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
                                {
                                        if ( pB->i2eChannelMap[box] & (1 << j) )
                                        {
-                                               len += sprintf (page+len,"%d,",
+                                               seq_printf(m, "%s%d", sep,
                                                        j + ABS_BIGGEST_BOX *
                                                        (box+i*ABS_MAX_BOXES));
+                                               sep = ",";
                                        }
                                }
                        }
-
-                       page[ len - 1 ] = '\n'; /* Overwrite that last comma */
-               } else {
-                       len += sprintf (page+len,"\n" );
-               }
-
-               if (len+begin > off+count)
-                       break;
-               if (len+begin < off) {
-                       begin += len;
-                       len = 0;
                }
+               seq_putc(m, '\n');
        }
+       return 0;
+ }
 
-       if (i >= IP2_MAX_BOARDS)
-               *eof = 1;
-       if (off >= len+begin)
-               return 0;
+static int ip2_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ip2_proc_show, NULL);
+}
 
-       *start = page + (off-begin);
-       return ((count < begin+len-off) ? count : begin+len-off);
- }
+static const struct file_operations ip2_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ip2_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
  
 /******************************************************************************/
 /* Function:   ip2trace()                                                     */
index 7a88dfd4427b136c6e034b06d4f6e6e3a416cd39..e93fc8d22fb2b839413dacd50fda823c060f7989 100644 (file)
@@ -1944,7 +1944,7 @@ static int stat_file_read_proc(char *page, char **start, off_t off,
 
 int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
                            read_proc_t *read_proc,
-                           void *data, struct module *owner)
+                           void *data)
 {
        int                    rv = 0;
 #ifdef CONFIG_PROC_FS
@@ -1970,7 +1970,6 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
        } else {
                file->data = data;
                file->read_proc = read_proc;
-               file->owner = owner;
 
                mutex_lock(&smi->proc_entry_lock);
                /* Stick it on the list. */
@@ -1993,23 +1992,21 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
        smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
        if (!smi->proc_dir)
                rv = -ENOMEM;
-       else
-               smi->proc_dir->owner = THIS_MODULE;
 
        if (rv == 0)
                rv = ipmi_smi_add_proc_entry(smi, "stats",
                                             stat_file_read_proc,
-                                            smi, THIS_MODULE);
+                                            smi);
 
        if (rv == 0)
                rv = ipmi_smi_add_proc_entry(smi, "ipmb",
                                             ipmb_file_read_proc,
-                                            smi, THIS_MODULE);
+                                            smi);
 
        if (rv == 0)
                rv = ipmi_smi_add_proc_entry(smi, "version",
                                             version_file_read_proc,
-                                            smi, THIS_MODULE);
+                                            smi);
 #endif /* CONFIG_PROC_FS */
 
        return rv;
@@ -4265,7 +4262,6 @@ static int ipmi_init_msghandler(void)
            return -ENOMEM;
        }
 
-       proc_ipmi_root->owner = THIS_MODULE;
 #endif /* CONFIG_PROC_FS */
 
        setup_timer(&ipmi_timer, ipmi_timeout, 0);
index 3000135f2ead3bcd98cd505b7fa89f11d0d2ab5e..e58ea4cd55ce02a101f282dd5977be4417b41bf4 100644 (file)
@@ -2899,7 +2899,7 @@ static int try_smi_init(struct smi_info *new_smi)
 
        rv = ipmi_smi_add_proc_entry(new_smi->intf, "type",
                                     type_file_read_proc,
-                                    new_smi, THIS_MODULE);
+                                    new_smi);
        if (rv) {
                printk(KERN_ERR
                       "ipmi_si: Unable to create proc entry: %d\n",
@@ -2909,7 +2909,7 @@ static int try_smi_init(struct smi_info *new_smi)
 
        rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats",
                                     stat_file_read_proc,
-                                    new_smi, THIS_MODULE);
+                                    new_smi);
        if (rv) {
                printk(KERN_ERR
                       "ipmi_si: Unable to create proc entry: %d\n",
@@ -2919,7 +2919,7 @@ static int try_smi_init(struct smi_info *new_smi)
 
        rv = ipmi_smi_add_proc_entry(new_smi->intf, "params",
                                     param_read_proc,
-                                    new_smi, THIS_MODULE);
+                                    new_smi);
        if (rv) {
                printk(KERN_ERR
                       "ipmi_si: Unable to create proc entry: %d\n",
index 5c3dc6b8411c88d62ec800f082678dc6f66ec3d8..fff19f7e29d25eac8c7cfbb4903638107dd8561c 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
+#include <linux/seq_file.h>
 #include <linux/cdk.h>
 #include <linux/comstats.h>
 #include <linux/istallion.h>
@@ -613,7 +614,6 @@ static int  stli_breakctl(struct tty_struct *tty, int state);
 static void    stli_waituntilsent(struct tty_struct *tty, int timeout);
 static void    stli_sendxchar(struct tty_struct *tty, char ch);
 static void    stli_hangup(struct tty_struct *tty);
-static int     stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portnr, char *pos);
 
 static int     stli_brdinit(struct stlibrd *brdp);
 static int     stli_startbrd(struct stlibrd *brdp);
@@ -1893,20 +1893,10 @@ static void stli_sendxchar(struct tty_struct *tty, char ch)
        stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);
 }
 
-/*****************************************************************************/
-
-#define        MAXLINE         80
-
-/*
- *     Format info for a specified port. The line is deliberately limited
- *     to 80 characters. (If it is too long it will be truncated, if too
- *     short then padded with spaces).
- */
-
-static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portnr, char *pos)
+static void stli_portinfo(struct seq_file *m, struct stlibrd *brdp, struct stliport *portp, int portnr)
 {
-       char *sp, *uart;
-       int rc, cnt;
+       char *uart;
+       int rc;
 
        rc = stli_portcmdstats(NULL, portp);
 
@@ -1918,44 +1908,50 @@ static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portn
                default:uart = "CD1400"; break;
                }
        }
-
-       sp = pos;
-       sp += sprintf(sp, "%d: uart:%s ", portnr, uart);
+       seq_printf(m, "%d: uart:%s ", portnr, uart);
 
        if ((brdp->state & BST_STARTED) && (rc >= 0)) {
-               sp += sprintf(sp, "tx:%d rx:%d", (int) stli_comstats.txtotal,
+               char sep;
+
+               seq_printf(m, "tx:%d rx:%d", (int) stli_comstats.txtotal,
                        (int) stli_comstats.rxtotal);
 
                if (stli_comstats.rxframing)
-                       sp += sprintf(sp, " fe:%d",
+                       seq_printf(m, " fe:%d",
                                (int) stli_comstats.rxframing);
                if (stli_comstats.rxparity)
-                       sp += sprintf(sp, " pe:%d",
+                       seq_printf(m, " pe:%d",
                                (int) stli_comstats.rxparity);
                if (stli_comstats.rxbreaks)
-                       sp += sprintf(sp, " brk:%d",
+                       seq_printf(m, " brk:%d",
                                (int) stli_comstats.rxbreaks);
                if (stli_comstats.rxoverrun)
-                       sp += sprintf(sp, " oe:%d",
+                       seq_printf(m, " oe:%d",
                                (int) stli_comstats.rxoverrun);
 
-               cnt = sprintf(sp, "%s%s%s%s%s ",
-                       (stli_comstats.signals & TIOCM_RTS) ? "|RTS" : "",
-                       (stli_comstats.signals & TIOCM_CTS) ? "|CTS" : "",
-                       (stli_comstats.signals & TIOCM_DTR) ? "|DTR" : "",
-                       (stli_comstats.signals & TIOCM_CD) ? "|DCD" : "",
-                       (stli_comstats.signals & TIOCM_DSR) ? "|DSR" : "");
-               *sp = ' ';
-               sp += cnt;
+               sep = ' ';
+               if (stli_comstats.signals & TIOCM_RTS) {
+                       seq_printf(m, "%c%s", sep, "RTS");
+                       sep = '|';
+               }
+               if (stli_comstats.signals & TIOCM_CTS) {
+                       seq_printf(m, "%c%s", sep, "CTS");
+                       sep = '|';
+               }
+               if (stli_comstats.signals & TIOCM_DTR) {
+                       seq_printf(m, "%c%s", sep, "DTR");
+                       sep = '|';
+               }
+               if (stli_comstats.signals & TIOCM_CD) {
+                       seq_printf(m, "%c%s", sep, "DCD");
+                       sep = '|';
+               }
+               if (stli_comstats.signals & TIOCM_DSR) {
+                       seq_printf(m, "%c%s", sep, "DSR");
+                       sep = '|';
+               }
        }
-
-       for (cnt = (sp - pos); (cnt < (MAXLINE - 1)); cnt++)
-               *sp++ = ' ';
-       if (cnt >= MAXLINE)
-               pos[(MAXLINE - 2)] = '+';
-       pos[(MAXLINE - 1)] = '\n';
-
-       return(MAXLINE);
+       seq_putc(m, '\n');
 }
 
 /*****************************************************************************/
@@ -1964,26 +1960,15 @@ static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portn
  *     Port info, read from the /proc file system.
  */
 
-static int stli_readproc(char *page, char **start, off_t off, int count, int *eof, void *data)
+static int stli_proc_show(struct seq_file *m, void *v)
 {
        struct stlibrd *brdp;
        struct stliport *portp;
        unsigned int brdnr, portnr, totalport;
-       int curoff, maxoff;
-       char *pos;
 
-       pos = page;
        totalport = 0;
-       curoff = 0;
-
-       if (off == 0) {
-               pos += sprintf(pos, "%s: version %s", stli_drvtitle,
-                       stli_drvversion);
-               while (pos < (page + MAXLINE - 1))
-                       *pos++ = ' ';
-               *pos++ = '\n';
-       }
-       curoff =  MAXLINE;
+
+       seq_printf(m, "%s: version %s\n", stli_drvtitle, stli_drvversion);
 
 /*
  *     We scan through for each board, panel and port. The offset is
@@ -1996,33 +1981,31 @@ static int stli_readproc(char *page, char **start, off_t off, int count, int *eo
                if (brdp->state == 0)
                        continue;
 
-               maxoff = curoff + (brdp->nrports * MAXLINE);
-               if (off >= maxoff) {
-                       curoff = maxoff;
-                       continue;
-               }
-
                totalport = brdnr * STL_MAXPORTS;
                for (portnr = 0; (portnr < brdp->nrports); portnr++,
                    totalport++) {
                        portp = brdp->ports[portnr];
                        if (portp == NULL)
                                continue;
-                       if (off >= (curoff += MAXLINE))
-                               continue;
-                       if ((pos - page + MAXLINE) > count)
-                               goto stli_readdone;
-                       pos += stli_portinfo(brdp, portp, totalport, pos);
+                       stli_portinfo(m, brdp, portp, totalport);
                }
        }
+       return 0;
+}
 
-       *eof = 1;
-
-stli_readdone:
-       *start = page;
-       return(pos - page);
+static int stli_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, stli_proc_show, NULL);
 }
 
+static const struct file_operations stli_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = stli_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*****************************************************************************/
 
 /*
@@ -4427,9 +4410,9 @@ static const struct tty_operations stli_ops = {
        .break_ctl = stli_breakctl,
        .wait_until_sent = stli_waituntilsent,
        .send_xchar = stli_sendxchar,
-       .read_proc = stli_readproc,
        .tiocmget = stli_tiocmget,
        .tiocmset = stli_tiocmset,
+       .proc_fops = &stli_proc_fops,
 };
 
 static const struct tty_port_operations stli_port_ops = {
index 5608a1e5a3b3416fa44e44e504c9a2817d1c3c2c..19d79fc54461c592111fbce5d0e68e395e10dcd4 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/netdevice.h>
 #include <linux/vmalloc.h>
@@ -2619,13 +2620,12 @@ cleanup:
  * /proc fs routines....
  */
 
-static inline int line_info(char *buf, MGSLPC_INFO *info)
+static inline void line_info(struct seq_file *m, MGSLPC_INFO *info)
 {
        char    stat_buf[30];
-       int     ret;
        unsigned long flags;
 
-       ret = sprintf(buf, "%s:io:%04X irq:%d",
+       seq_printf(m, "%s:io:%04X irq:%d",
                      info->device_name, info->io_base, info->irq_level);
 
        /* output current serial signal states */
@@ -2649,75 +2649,70 @@ static inline int line_info(char *buf, MGSLPC_INFO *info)
                strcat(stat_buf, "|RI");
 
        if (info->params.mode == MGSL_MODE_HDLC) {
-               ret += sprintf(buf+ret, " HDLC txok:%d rxok:%d",
+               seq_printf(m, " HDLC txok:%d rxok:%d",
                              info->icount.txok, info->icount.rxok);
                if (info->icount.txunder)
-                       ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder);
+                       seq_printf(m, " txunder:%d", info->icount.txunder);
                if (info->icount.txabort)
-                       ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);
+                       seq_printf(m, " txabort:%d", info->icount.txabort);
                if (info->icount.rxshort)
-                       ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);
+                       seq_printf(m, " rxshort:%d", info->icount.rxshort);
                if (info->icount.rxlong)
-                       ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);
+                       seq_printf(m, " rxlong:%d", info->icount.rxlong);
                if (info->icount.rxover)
-                       ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);
+                       seq_printf(m, " rxover:%d", info->icount.rxover);
                if (info->icount.rxcrc)
-                       ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc);
+                       seq_printf(m, " rxcrc:%d", info->icount.rxcrc);
        } else {
-               ret += sprintf(buf+ret, " ASYNC tx:%d rx:%d",
+               seq_printf(m, " ASYNC tx:%d rx:%d",
                              info->icount.tx, info->icount.rx);
                if (info->icount.frame)
-                       ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+                       seq_printf(m, " fe:%d", info->icount.frame);
                if (info->icount.parity)
-                       ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+                       seq_printf(m, " pe:%d", info->icount.parity);
                if (info->icount.brk)
-                       ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
+                       seq_printf(m, " brk:%d", info->icount.brk);
                if (info->icount.overrun)
-                       ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+                       seq_printf(m, " oe:%d", info->icount.overrun);
        }
 
        /* Append serial signal status to end */
-       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+       seq_printf(m, " %s\n", stat_buf+1);
 
-       ret += sprintf(buf+ret, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
+       seq_printf(m, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
                       info->tx_active,info->bh_requested,info->bh_running,
                       info->pending_bh);
-
-       return ret;
 }
 
 /* Called to print information about devices
  */
-static int mgslpc_read_proc(char *page, char **start, off_t off, int count,
-                int *eof, void *data)
+static int mgslpc_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0, l;
-       off_t   begin = 0;
        MGSLPC_INFO *info;
 
-       len += sprintf(page, "synclink driver:%s\n", driver_version);
+       seq_printf(m, "synclink driver:%s\n", driver_version);
 
        info = mgslpc_device_list;
        while( info ) {
-               l = line_info(page + len, info);
-               len += l;
-               if (len+begin > off+count)
-                       goto done;
-               if (len+begin < off) {
-                       begin += len;
-                       len = 0;
-               }
+               line_info(m, info);
                info = info->next_device;
        }
+       return 0;
+}
 
-       *eof = 1;
-done:
-       if (off >= len+begin)
-               return 0;
-       *start = page + (off-begin);
-       return ((count < begin+len-off) ? count : begin+len-off);
+static int mgslpc_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, mgslpc_proc_show, NULL);
 }
 
+static const struct file_operations mgslpc_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = mgslpc_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static int rx_alloc_buffers(MGSLPC_INFO *info)
 {
        /* each buffer has header and data */
@@ -2861,13 +2856,13 @@ static const struct tty_operations mgslpc_ops = {
        .send_xchar = mgslpc_send_xchar,
        .break_ctl = mgslpc_break,
        .wait_until_sent = mgslpc_wait_until_sent,
-       .read_proc = mgslpc_read_proc,
        .set_termios = mgslpc_set_termios,
        .stop = tx_pause,
        .start = tx_release,
        .hangup = mgslpc_hangup,
        .tiocmget = tiocmget,
        .tiocmset = tiocmset,
+       .proc_fops = &mgslpc_proc_fops,
 };
 
 static void synclink_cs_cleanup(void)
index 7c43ae782b26e385e1b0c96efacd7e82846b794b..f824ef8a9273d7d46e63b113fa83ea03249f95e1 100644 (file)
@@ -1488,7 +1488,8 @@ static void rekey_seq_generator(struct work_struct *work)
        keyptr->count = (ip_cnt & COUNT_MASK) << HASH_BITS;
        smp_wmb();
        ip_cnt++;
-       schedule_delayed_work(&rekey_work, REKEY_INTERVAL);
+       schedule_delayed_work(&rekey_work,
+                             round_jiffies_relative(REKEY_INTERVAL));
 }
 
 static inline struct keydata *get_keyptr(void)
index 96adf28a17e43b309d8af6858d695015c84cc6d1..20d90e6a6e50fb41dfdd2601b1ae6617c40a6070 100644 (file)
@@ -90,6 +90,7 @@ out1:
        blkdev_put(bdev, filp->f_mode);
 out:
        mutex_unlock(&raw_mutex);
+       unlock_kernel();
        return err;
 }
 
index e1e0dd89ac9aa309e2f92c9183618948b09b6900..2ad813a801dc391cc8bca62a4cc847b16ea0d4d1 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
+#include <linux/seq_file.h>
 #include <linux/cd1400.h>
 #include <linux/sc26198.h>
 #include <linux/comstats.h>
@@ -1379,52 +1380,47 @@ static void stl_sendxchar(struct tty_struct *tty, char ch)
                stl_putchar(tty, ch);
 }
 
-/*****************************************************************************/
-
-#define        MAXLINE         80
-
-/*
- *     Format info for a specified port. The line is deliberately limited
- *     to 80 characters. (If it is too long it will be truncated, if too
- *     short then padded with spaces).
- */
-
-static int stl_portinfo(struct stlport *portp, int portnr, char *pos)
+static void stl_portinfo(struct seq_file *m, struct stlport *portp, int portnr)
 {
-       char    *sp;
-       int     sigs, cnt;
+       int     sigs;
+       char sep;
 
-       sp = pos;
-       sp += sprintf(sp, "%d: uart:%s tx:%d rx:%d",
+       seq_printf(m, "%d: uart:%s tx:%d rx:%d",
                portnr, (portp->hwid == 1) ? "SC26198" : "CD1400",
                (int) portp->stats.txtotal, (int) portp->stats.rxtotal);
 
        if (portp->stats.rxframing)
-               sp += sprintf(sp, " fe:%d", (int) portp->stats.rxframing);
+               seq_printf(m, " fe:%d", (int) portp->stats.rxframing);
        if (portp->stats.rxparity)
-               sp += sprintf(sp, " pe:%d", (int) portp->stats.rxparity);
+               seq_printf(m, " pe:%d", (int) portp->stats.rxparity);
        if (portp->stats.rxbreaks)
-               sp += sprintf(sp, " brk:%d", (int) portp->stats.rxbreaks);
+               seq_printf(m, " brk:%d", (int) portp->stats.rxbreaks);
        if (portp->stats.rxoverrun)
-               sp += sprintf(sp, " oe:%d", (int) portp->stats.rxoverrun);
+               seq_printf(m, " oe:%d", (int) portp->stats.rxoverrun);
 
        sigs = stl_getsignals(portp);
-       cnt = sprintf(sp, "%s%s%s%s%s ",
-               (sigs & TIOCM_RTS) ? "|RTS" : "",
-               (sigs & TIOCM_CTS) ? "|CTS" : "",
-               (sigs & TIOCM_DTR) ? "|DTR" : "",
-               (sigs & TIOCM_CD) ? "|DCD" : "",
-               (sigs & TIOCM_DSR) ? "|DSR" : "");
-       *sp = ' ';
-       sp += cnt;
-
-       for (cnt = sp - pos; cnt < (MAXLINE - 1); cnt++)
-               *sp++ = ' ';
-       if (cnt >= MAXLINE)
-               pos[(MAXLINE - 2)] = '+';
-       pos[(MAXLINE - 1)] = '\n';
-
-       return MAXLINE;
+       sep = ' ';
+       if (sigs & TIOCM_RTS) {
+               seq_printf(m, "%c%s", sep, "RTS");
+               sep = '|';
+       }
+       if (sigs & TIOCM_CTS) {
+               seq_printf(m, "%c%s", sep, "CTS");
+               sep = '|';
+       }
+       if (sigs & TIOCM_DTR) {
+               seq_printf(m, "%c%s", sep, "DTR");
+               sep = '|';
+       }
+       if (sigs & TIOCM_CD) {
+               seq_printf(m, "%c%s", sep, "DCD");
+               sep = '|';
+       }
+       if (sigs & TIOCM_DSR) {
+               seq_printf(m, "%c%s", sep, "DSR");
+               sep = '|';
+       }
+       seq_putc(m, '\n');
 }
 
 /*****************************************************************************/
@@ -1433,30 +1429,17 @@ static int stl_portinfo(struct stlport *portp, int portnr, char *pos)
  *     Port info, read from the /proc file system.
  */
 
-static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data)
+static int stl_proc_show(struct seq_file *m, void *v)
 {
        struct stlbrd   *brdp;
        struct stlpanel *panelp;
        struct stlport  *portp;
        unsigned int    brdnr, panelnr, portnr;
-       int             totalport, curoff, maxoff;
-       char            *pos;
+       int             totalport;
 
-       pr_debug("stl_readproc(page=%p,start=%p,off=%lx,count=%d,eof=%p,"
-               "data=%p\n", page, start, off, count, eof, data);
-
-       pos = page;
        totalport = 0;
-       curoff = 0;
-
-       if (off == 0) {
-               pos += sprintf(pos, "%s: version %s", stl_drvtitle,
-                       stl_drvversion);
-               while (pos < (page + MAXLINE - 1))
-                       *pos++ = ' ';
-               *pos++ = '\n';
-       }
-       curoff =  MAXLINE;
+
+       seq_printf(m, "%s: version %s\n", stl_drvtitle, stl_drvversion);
 
 /*
  *     We scan through for each board, panel and port. The offset is
@@ -1469,46 +1452,37 @@ static int stl_readproc(char *page, char **start, off_t off, int count, int *eof
                if (brdp->state == 0)
                        continue;
 
-               maxoff = curoff + (brdp->nrports * MAXLINE);
-               if (off >= maxoff) {
-                       curoff = maxoff;
-                       continue;
-               }
-
                totalport = brdnr * STL_MAXPORTS;
                for (panelnr = 0; panelnr < brdp->nrpanels; panelnr++) {
                        panelp = brdp->panels[panelnr];
                        if (panelp == NULL)
                                continue;
 
-                       maxoff = curoff + (panelp->nrports * MAXLINE);
-                       if (off >= maxoff) {
-                               curoff = maxoff;
-                               totalport += panelp->nrports;
-                               continue;
-                       }
-
                        for (portnr = 0; portnr < panelp->nrports; portnr++,
                            totalport++) {
                                portp = panelp->ports[portnr];
                                if (portp == NULL)
                                        continue;
-                               if (off >= (curoff += MAXLINE))
-                                       continue;
-                               if ((pos - page + MAXLINE) > count)
-                                       goto stl_readdone;
-                               pos += stl_portinfo(portp, totalport, pos);
+                               stl_portinfo(m, portp, totalport);
                        }
                }
        }
+       return 0;
+}
 
-       *eof = 1;
-
-stl_readdone:
-       *start = page;
-       return pos - page;
+static int stl_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, stl_proc_show, NULL);
 }
 
+static const struct file_operations stl_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = stl_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*****************************************************************************/
 
 /*
@@ -2566,9 +2540,9 @@ static const struct tty_operations stl_ops = {
        .break_ctl = stl_breakctl,
        .wait_until_sent = stl_waituntilsent,
        .send_xchar = stl_sendxchar,
-       .read_proc = stl_readproc,
        .tiocmget = stl_tiocmget,
        .tiocmset = stl_tiocmset,
+       .proc_fops = &stl_proc_fops,
 };
 
 static const struct tty_port_operations stl_port_ops = {
index 0057a8f58cb1261c71b48db67f1562d74282ee59..afd0b26ca05681210edd0cc0f22b01497eea3e37 100644 (file)
@@ -79,6 +79,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
@@ -3459,18 +3460,17 @@ cleanup:
  * /proc fs routines....
  */
 
-static inline int line_info(char *buf, struct mgsl_struct *info)
+static inline void line_info(struct seq_file *m, struct mgsl_struct *info)
 {
        char    stat_buf[30];
-       int     ret;
        unsigned long flags;
 
        if (info->bus_type == MGSL_BUS_TYPE_PCI) {
-               ret = sprintf(buf, "%s:PCI io:%04X irq:%d mem:%08X lcr:%08X",
+               seq_printf(m, "%s:PCI io:%04X irq:%d mem:%08X lcr:%08X",
                        info->device_name, info->io_base, info->irq_level,
                        info->phys_memory_base, info->phys_lcr_base);
        } else {
-               ret = sprintf(buf, "%s:(E)ISA io:%04X irq:%d dma:%d",
+               seq_printf(m, "%s:(E)ISA io:%04X irq:%d dma:%d",
                        info->device_name, info->io_base, 
                        info->irq_level, info->dma_level);
        }
@@ -3497,37 +3497,37 @@ static inline int line_info(char *buf, struct mgsl_struct *info)
 
        if (info->params.mode == MGSL_MODE_HDLC ||
            info->params.mode == MGSL_MODE_RAW ) {
-               ret += sprintf(buf+ret, " HDLC txok:%d rxok:%d",
+               seq_printf(m, " HDLC txok:%d rxok:%d",
                              info->icount.txok, info->icount.rxok);
                if (info->icount.txunder)
-                       ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder);
+                       seq_printf(m, " txunder:%d", info->icount.txunder);
                if (info->icount.txabort)
-                       ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);
+                       seq_printf(m, " txabort:%d", info->icount.txabort);
                if (info->icount.rxshort)
-                       ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);   
+                       seq_printf(m, " rxshort:%d", info->icount.rxshort);
                if (info->icount.rxlong)
-                       ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);
+                       seq_printf(m, " rxlong:%d", info->icount.rxlong);
                if (info->icount.rxover)
-                       ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);
+                       seq_printf(m, " rxover:%d", info->icount.rxover);
                if (info->icount.rxcrc)
-                       ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc);
+                       seq_printf(m, " rxcrc:%d", info->icount.rxcrc);
        } else {
-               ret += sprintf(buf+ret, " ASYNC tx:%d rx:%d",
+               seq_printf(m, " ASYNC tx:%d rx:%d",
                              info->icount.tx, info->icount.rx);
                if (info->icount.frame)
-                       ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+                       seq_printf(m, " fe:%d", info->icount.frame);
                if (info->icount.parity)
-                       ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+                       seq_printf(m, " pe:%d", info->icount.parity);
                if (info->icount.brk)
-                       ret += sprintf(buf+ret, " brk:%d", info->icount.brk);   
+                       seq_printf(m, " brk:%d", info->icount.brk);
                if (info->icount.overrun)
-                       ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+                       seq_printf(m, " oe:%d", info->icount.overrun);
        }
        
        /* Append serial signal status to end */
-       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+       seq_printf(m, " %s\n", stat_buf+1);
        
-       ret += sprintf(buf+ret, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
+       seq_printf(m, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
         info->tx_active,info->bh_requested,info->bh_running,
         info->pending_bh);
         
@@ -3544,60 +3544,40 @@ static inline int line_info(char *buf, struct mgsl_struct *info)
        u16 Tmr = usc_InReg( info, TMR );
        u16 Tccr = usc_InReg( info, TCCR );
        u16 Ccar = inw( info->io_base + CCAR );
-       ret += sprintf(buf+ret, "tcsr=%04X tdmr=%04X ticr=%04X rcsr=%04X rdmr=%04X\n"
+       seq_printf(m, "tcsr=%04X tdmr=%04X ticr=%04X rcsr=%04X rdmr=%04X\n"
                         "ricr=%04X icr =%04X dccr=%04X tmr=%04X tccr=%04X ccar=%04X\n",
                        Tcsr,Tdmr,Ticr,Rscr,Rdmr,Ricr,Icr,Dccr,Tmr,Tccr,Ccar );
        }
        spin_unlock_irqrestore(&info->irq_spinlock,flags);
-       
-       return ret;
-       
-}      /* end of line_info() */
+}
 
-/* mgsl_read_proc()
- * 
- * Called to print information about devices
- * 
- * Arguments:
- *     page    page of memory to hold returned info
- *     start   
- *     off
- *     count
- *     eof
- *     data
- *     
- * Return Value:
- */
-static int mgsl_read_proc(char *page, char **start, off_t off, int count,
-                int *eof, void *data)
+/* Called to print information about devices */
+static int mgsl_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0, l;
-       off_t   begin = 0;
        struct mgsl_struct *info;
        
-       len += sprintf(page, "synclink driver:%s\n", driver_version);
+       seq_printf(m, "synclink driver:%s\n", driver_version);
        
        info = mgsl_device_list;
        while( info ) {
-               l = line_info(page + len, info);
-               len += l;
-               if (len+begin > off+count)
-                       goto done;
-               if (len+begin < off) {
-                       begin += len;
-                       len = 0;
-               }
+               line_info(m, info);
                info = info->next_device;
        }
+       return 0;
+}
 
-       *eof = 1;
-done:
-       if (off >= len+begin)
-               return 0;
-       *start = page + (off-begin);
-       return ((count < begin+len-off) ? count : begin+len-off);
-       
-}      /* end of mgsl_read_proc() */
+static int mgsl_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, mgsl_proc_show, NULL);
+}
+
+static const struct file_operations mgsl_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = mgsl_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
 /* mgsl_allocate_dma_buffers()
  * 
@@ -4335,13 +4315,13 @@ static const struct tty_operations mgsl_ops = {
        .send_xchar = mgsl_send_xchar,
        .break_ctl = mgsl_break,
        .wait_until_sent = mgsl_wait_until_sent,
-       .read_proc = mgsl_read_proc,
        .set_termios = mgsl_set_termios,
        .stop = mgsl_stop,
        .start = mgsl_start,
        .hangup = mgsl_hangup,
        .tiocmget = tiocmget,
        .tiocmset = tiocmset,
+       .proc_fops = &mgsl_proc_fops,
 };
 
 /*
index efb3dc928a43a7b6fe26bcfc551511f84d601772..5e256494686a8413734db27db5b9826069e36847 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/netdevice.h>
 #include <linux/vmalloc.h>
@@ -154,7 +155,6 @@ static void tx_hold(struct tty_struct *tty);
 static void tx_release(struct tty_struct *tty);
 
 static int  ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
-static int  read_proc(char *page, char **start, off_t off, int count,int *eof, void *data);
 static int  chars_in_buffer(struct tty_struct *tty);
 static void throttle(struct tty_struct * tty);
 static void unthrottle(struct tty_struct * tty);
@@ -298,6 +298,7 @@ struct slgt_info {
 
        unsigned int rbuf_fill_level;
        unsigned int if_mode;
+       unsigned int base_clock;
 
        /* device status */
 
@@ -1156,22 +1157,26 @@ static long set_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *ne
                return -EFAULT;
 
        spin_lock(&info->lock);
-       info->params.mode            = tmp_params.mode;
-       info->params.loopback        = tmp_params.loopback;
-       info->params.flags           = tmp_params.flags;
-       info->params.encoding        = tmp_params.encoding;
-       info->params.clock_speed     = tmp_params.clock_speed;
-       info->params.addr_filter     = tmp_params.addr_filter;
-       info->params.crc_type        = tmp_params.crc_type;
-       info->params.preamble_length = tmp_params.preamble_length;
-       info->params.preamble        = tmp_params.preamble;
-       info->params.data_rate       = tmp_params.data_rate;
-       info->params.data_bits       = tmp_params.data_bits;
-       info->params.stop_bits       = tmp_params.stop_bits;
-       info->params.parity          = tmp_params.parity;
+       if (tmp_params.mode == MGSL_MODE_BASE_CLOCK) {
+               info->base_clock = tmp_params.clock_speed;
+       } else {
+               info->params.mode            = tmp_params.mode;
+               info->params.loopback        = tmp_params.loopback;
+               info->params.flags           = tmp_params.flags;
+               info->params.encoding        = tmp_params.encoding;
+               info->params.clock_speed     = tmp_params.clock_speed;
+               info->params.addr_filter     = tmp_params.addr_filter;
+               info->params.crc_type        = tmp_params.crc_type;
+               info->params.preamble_length = tmp_params.preamble_length;
+               info->params.preamble        = tmp_params.preamble;
+               info->params.data_rate       = tmp_params.data_rate;
+               info->params.data_bits       = tmp_params.data_bits;
+               info->params.stop_bits       = tmp_params.stop_bits;
+               info->params.parity          = tmp_params.parity;
+       }
        spin_unlock(&info->lock);
 
-       change_params(info);
+       program_hw(info);
 
        return 0;
 }
@@ -1229,13 +1234,12 @@ static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file,
 /*
  * proc fs support
  */
-static inline int line_info(char *buf, struct slgt_info *info)
+static inline void line_info(struct seq_file *m, struct slgt_info *info)
 {
        char stat_buf[30];
-       int ret;
        unsigned long flags;
 
-       ret = sprintf(buf, "%s: IO=%08X IRQ=%d MaxFrameSize=%u\n",
+       seq_printf(m, "%s: IO=%08X IRQ=%d MaxFrameSize=%u\n",
                      info->device_name, info->phys_reg_addr,
                      info->irq_level, info->max_frame_size);
 
@@ -1260,75 +1264,70 @@ static inline int line_info(char *buf, struct slgt_info *info)
                strcat(stat_buf, "|RI");
 
        if (info->params.mode != MGSL_MODE_ASYNC) {
-               ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d",
+               seq_printf(m, "\tHDLC txok:%d rxok:%d",
                               info->icount.txok, info->icount.rxok);
                if (info->icount.txunder)
-                       ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder);
+                       seq_printf(m, " txunder:%d", info->icount.txunder);
                if (info->icount.txabort)
-                       ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);
+                       seq_printf(m, " txabort:%d", info->icount.txabort);
                if (info->icount.rxshort)
-                       ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);
+                       seq_printf(m, " rxshort:%d", info->icount.rxshort);
                if (info->icount.rxlong)
-                       ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);
+                       seq_printf(m, " rxlong:%d", info->icount.rxlong);
                if (info->icount.rxover)
-                       ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);
+                       seq_printf(m, " rxover:%d", info->icount.rxover);
                if (info->icount.rxcrc)
-                       ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc);
+                       seq_printf(m, " rxcrc:%d", info->icount.rxcrc);
        } else {
-               ret += sprintf(buf+ret, "\tASYNC tx:%d rx:%d",
+               seq_printf(m, "\tASYNC tx:%d rx:%d",
                               info->icount.tx, info->icount.rx);
                if (info->icount.frame)
-                       ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+                       seq_printf(m, " fe:%d", info->icount.frame);
                if (info->icount.parity)
-                       ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+                       seq_printf(m, " pe:%d", info->icount.parity);
                if (info->icount.brk)
-                       ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
+                       seq_printf(m, " brk:%d", info->icount.brk);
                if (info->icount.overrun)
-                       ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+                       seq_printf(m, " oe:%d", info->icount.overrun);
        }
 
        /* Append serial signal status to end */
-       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+       seq_printf(m, " %s\n", stat_buf+1);
 
-       ret += sprintf(buf+ret, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
+       seq_printf(m, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
                       info->tx_active,info->bh_requested,info->bh_running,
                       info->pending_bh);
-
-       return ret;
 }
 
 /* Called to print information about devices
  */
-static int read_proc(char *page, char **start, off_t off, int count,
-                    int *eof, void *data)
+static int synclink_gt_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0, l;
-       off_t   begin = 0;
        struct slgt_info *info;
 
-       len += sprintf(page, "synclink_gt driver\n");
+       seq_puts(m, "synclink_gt driver\n");
 
        info = slgt_device_list;
        while( info ) {
-               l = line_info(page + len, info);
-               len += l;
-               if (len+begin > off+count)
-                       goto done;
-               if (len+begin < off) {
-                       begin += len;
-                       len = 0;
-               }
+               line_info(m, info);
                info = info->next_device;
        }
+       return 0;
+}
 
-       *eof = 1;
-done:
-       if (off >= len+begin)
-               return 0;
-       *start = page + (off-begin);
-       return ((count < begin+len-off) ? count : begin+len-off);
+static int synclink_gt_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, synclink_gt_proc_show, NULL);
 }
 
+static const struct file_operations synclink_gt_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = synclink_gt_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*
  * return count of bytes in transmit buffer
  */
@@ -2565,10 +2564,13 @@ static int set_params(struct slgt_info *info, MGSL_PARAMS __user *new_params)
                return -EFAULT;
 
        spin_lock_irqsave(&info->lock, flags);
-       memcpy(&info->params, &tmp_params, sizeof(MGSL_PARAMS));
+       if (tmp_params.mode == MGSL_MODE_BASE_CLOCK)
+               info->base_clock = tmp_params.clock_speed;
+       else
+               memcpy(&info->params, &tmp_params, sizeof(MGSL_PARAMS));
        spin_unlock_irqrestore(&info->lock, flags);
 
-       change_params(info);
+       program_hw(info);
 
        return 0;
 }
@@ -3438,6 +3440,7 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev
                info->magic = MGSL_MAGIC;
                INIT_WORK(&info->task, bh_handler);
                info->max_frame_size = 4096;
+               info->base_clock = 14745600;
                info->rbuf_fill_level = DMABUFSIZE;
                info->port.close_delay = 5*HZ/10;
                info->port.closing_wait = 30*HZ;
@@ -3562,13 +3565,13 @@ static const struct tty_operations ops = {
        .send_xchar = send_xchar,
        .break_ctl = set_break,
        .wait_until_sent = wait_until_sent,
-       .read_proc = read_proc,
        .set_termios = set_termios,
        .stop = tx_hold,
        .start = tx_release,
        .hangup = hangup,
        .tiocmget = tiocmget,
        .tiocmset = tiocmset,
+       .proc_fops = &synclink_gt_proc_fops,
 };
 
 static void slgt_cleanup(void)
@@ -3785,7 +3788,7 @@ static void enable_loopback(struct slgt_info *info)
 static void set_rate(struct slgt_info *info, u32 rate)
 {
        unsigned int div;
-       static unsigned int osc = 14745600;
+       unsigned int osc = info->base_clock;
 
        /* div = osc/rate - 1
         *
@@ -4089,18 +4092,27 @@ static void async_mode(struct slgt_info *info)
         * 06  CTS      IRQ enable
         * 05  DCD      IRQ enable
         * 04  RI       IRQ enable
-        * 03  reserved, must be zero
+        * 03  0=16x sampling, 1=8x sampling
         * 02  1=txd->rxd internal loopback enable
         * 01  reserved, must be zero
         * 00  1=master IRQ enable
         */
        val = BIT15 + BIT14 + BIT0;
+       /* JCR[8] : 1 = x8 async mode feature available */
+       if ((rd_reg32(info, JCR) & BIT8) && info->params.data_rate &&
+           ((info->base_clock < (info->params.data_rate * 16)) ||
+            (info->base_clock % (info->params.data_rate * 16)))) {
+               /* use 8x sampling */
+               val |= BIT3;
+               set_rate(info, info->params.data_rate * 8);
+       } else {
+               /* use 16x sampling */
+               set_rate(info, info->params.data_rate * 16);
+       }
        wr_reg16(info, SCR, val);
 
        slgt_irq_on(info, IRQ_RXBREAK | IRQ_RXOVER);
 
-       set_rate(info, info->params.data_rate * 16);
-
        if (info->params.loopback)
                enable_loopback(info);
 }
index 8eb6c89a980ec1cb674eef7fe83e42142ea4d5cf..26de60efe4b247162c3be863bb3a3c66d86d6c49 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/netdevice.h>
 #include <linux/vmalloc.h>
@@ -520,7 +521,6 @@ static void tx_hold(struct tty_struct *tty);
 static void tx_release(struct tty_struct *tty);
 
 static int  ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
-static int  read_proc(char *page, char **start, off_t off, int count,int *eof, void *data);
 static int  chars_in_buffer(struct tty_struct *tty);
 static void throttle(struct tty_struct * tty);
 static void unthrottle(struct tty_struct * tty);
@@ -1354,13 +1354,12 @@ static int ioctl(struct tty_struct *tty, struct file *file,
  * /proc fs routines....
  */
 
-static inline int line_info(char *buf, SLMP_INFO *info)
+static inline void line_info(struct seq_file *m, SLMP_INFO *info)
 {
        char    stat_buf[30];
-       int     ret;
        unsigned long flags;
 
-       ret = sprintf(buf, "%s: SCABase=%08x Mem=%08X StatusControl=%08x LCR=%08X\n"
+       seq_printf(m, "%s: SCABase=%08x Mem=%08X StatusControl=%08x LCR=%08X\n"
                       "\tIRQ=%d MaxFrameSize=%u\n",
                info->device_name,
                info->phys_sca_base,
@@ -1391,75 +1390,70 @@ static inline int line_info(char *buf, SLMP_INFO *info)
                strcat(stat_buf, "|RI");
 
        if (info->params.mode == MGSL_MODE_HDLC) {
-               ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d",
+               seq_printf(m, "\tHDLC txok:%d rxok:%d",
                              info->icount.txok, info->icount.rxok);
                if (info->icount.txunder)
-                       ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder);
+                       seq_printf(m, " txunder:%d", info->icount.txunder);
                if (info->icount.txabort)
-                       ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);
+                       seq_printf(m, " txabort:%d", info->icount.txabort);
                if (info->icount.rxshort)
-                       ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);
+                       seq_printf(m, " rxshort:%d", info->icount.rxshort);
                if (info->icount.rxlong)
-                       ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);
+                       seq_printf(m, " rxlong:%d", info->icount.rxlong);
                if (info->icount.rxover)
-                       ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);
+                       seq_printf(m, " rxover:%d", info->icount.rxover);
                if (info->icount.rxcrc)
-                       ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxcrc);
+                       seq_printf(m, " rxlong:%d", info->icount.rxcrc);
        } else {
-               ret += sprintf(buf+ret, "\tASYNC tx:%d rx:%d",
+               seq_printf(m, "\tASYNC tx:%d rx:%d",
                              info->icount.tx, info->icount.rx);
                if (info->icount.frame)
-                       ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+                       seq_printf(m, " fe:%d", info->icount.frame);
                if (info->icount.parity)
-                       ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+                       seq_printf(m, " pe:%d", info->icount.parity);
                if (info->icount.brk)
-                       ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
+                       seq_printf(m, " brk:%d", info->icount.brk);
                if (info->icount.overrun)
-                       ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+                       seq_printf(m, " oe:%d", info->icount.overrun);
        }
 
        /* Append serial signal status to end */
-       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+       seq_printf(m, " %s\n", stat_buf+1);
 
-       ret += sprintf(buf+ret, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
+       seq_printf(m, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
         info->tx_active,info->bh_requested,info->bh_running,
         info->pending_bh);
-
-       return ret;
 }
 
 /* Called to print information about devices
  */
-static int read_proc(char *page, char **start, off_t off, int count,
-             int *eof, void *data)
+static int synclinkmp_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0, l;
-       off_t   begin = 0;
        SLMP_INFO *info;
 
-       len += sprintf(page, "synclinkmp driver:%s\n", driver_version);
+       seq_printf(m, "synclinkmp driver:%s\n", driver_version);
 
        info = synclinkmp_device_list;
        while( info ) {
-               l = line_info(page + len, info);
-               len += l;
-               if (len+begin > off+count)
-                       goto done;
-               if (len+begin < off) {
-                       begin += len;
-                       len = 0;
-               }
+               line_info(m, info);
                info = info->next_device;
        }
+       return 0;
+}
 
-       *eof = 1;
-done:
-       if (off >= len+begin)
-               return 0;
-       *start = page + (off-begin);
-       return ((count < begin+len-off) ? count : begin+len-off);
+static int synclinkmp_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, synclinkmp_proc_show, NULL);
 }
 
+static const struct file_operations synclinkmp_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = synclinkmp_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /* Return the count of bytes in transmit buffer
  */
 static int chars_in_buffer(struct tty_struct *tty)
@@ -3905,13 +3899,13 @@ static const struct tty_operations ops = {
        .send_xchar = send_xchar,
        .break_ctl = set_break,
        .wait_until_sent = wait_until_sent,
-       .read_proc = read_proc,
        .set_termios = set_termios,
        .stop = tx_hold,
        .start = tx_release,
        .hangup = hangup,
        .tiocmget = tiocmget,
        .tiocmset = tiocmset,
+       .proc_fops = &synclinkmp_proc_fops,
 };
 
 
index 33a9351c896dfbaff7dbf9afb5515d998bbb943e..ebea9b2c30a583737a0e7800122217ff4eaf273c 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/vt_kern.h>
 #include <linux/workqueue.h>
 #include <linux/kexec.h>
-#include <linux/irq.h>
+#include <linux/interrupt.h>
 #include <linux/hrtimer.h>
 #include <linux/oom.h>
 
@@ -346,6 +346,19 @@ static struct sysrq_key_op sysrq_moom_op = {
        .enable_mask    = SYSRQ_ENABLE_SIGNAL,
 };
 
+#ifdef CONFIG_BLOCK
+static void sysrq_handle_thaw(int key, struct tty_struct *tty)
+{
+       emergency_thaw_all();
+}
+static struct sysrq_key_op sysrq_thaw_op = {
+       .handler        = sysrq_handle_thaw,
+       .help_msg       = "thaw-filesystems(J)",
+       .action_msg     = "Emergency Thaw of all frozen filesystems",
+       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
+};
+#endif
+
 static void sysrq_handle_kill(int key, struct tty_struct *tty)
 {
        send_sig_all(SIGKILL);
@@ -396,9 +409,13 @@ static struct sysrq_key_op *sysrq_key_table[36] = {
        &sysrq_moom_op,                 /* f */
        /* g: May be registered by ppc for kgdb */
        NULL,                           /* g */
-       NULL,                           /* h */
+       NULL,                           /* h - reserved for help */
        &sysrq_kill_op,                 /* i */
+#ifdef CONFIG_BLOCK
+       &sysrq_thaw_op,                 /* j */
+#else
        NULL,                           /* j */
+#endif
        &sysrq_SAK_op,                  /* k */
 #ifdef CONFIG_SMP
        &sysrq_showallcpus_op,          /* l */
index 224f271d8cbe06868d69ce415339efa30f110d55..66b99a2049e373cacca62d54d1d689daed2417e2 100644 (file)
@@ -464,7 +464,7 @@ void tty_wakeup(struct tty_struct *tty)
                        tty_ldisc_deref(ld);
                }
        }
-       wake_up_interruptible(&tty->write_wait);
+       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
 }
 
 EXPORT_SYMBOL_GPL(tty_wakeup);
@@ -587,8 +587,8 @@ static void do_tty_hangup(struct work_struct *work)
         * FIXME: Once we trust the LDISC code better we can wait here for
         * ldisc completion and fix the driver call race
         */
-       wake_up_interruptible(&tty->write_wait);
-       wake_up_interruptible(&tty->read_wait);
+       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
+       wake_up_interruptible_poll(&tty->read_wait, POLLIN);
        /*
         * Shutdown the current line discipline, and reset it to
         * N_TTY.
@@ -879,7 +879,7 @@ void stop_tty(struct tty_struct *tty)
        if (tty->link && tty->link->packet) {
                tty->ctrl_status &= ~TIOCPKT_START;
                tty->ctrl_status |= TIOCPKT_STOP;
-               wake_up_interruptible(&tty->link->read_wait);
+               wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
        }
        spin_unlock_irqrestore(&tty->ctrl_lock, flags);
        if (tty->ops->stop)
@@ -913,7 +913,7 @@ void start_tty(struct tty_struct *tty)
        if (tty->link && tty->link->packet) {
                tty->ctrl_status &= ~TIOCPKT_STOP;
                tty->ctrl_status |= TIOCPKT_START;
-               wake_up_interruptible(&tty->link->read_wait);
+               wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
        }
        spin_unlock_irqrestore(&tty->ctrl_lock, flags);
        if (tty->ops->start)
@@ -970,7 +970,7 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
 void tty_write_unlock(struct tty_struct *tty)
 {
        mutex_unlock(&tty->atomic_write_lock);
-       wake_up_interruptible(&tty->write_wait);
+       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
 }
 
 int tty_write_lock(struct tty_struct *tty, int ndelay)
@@ -1623,21 +1623,21 @@ void tty_release_dev(struct file *filp)
 
                if (tty_closing) {
                        if (waitqueue_active(&tty->read_wait)) {
-                               wake_up(&tty->read_wait);
+                               wake_up_poll(&tty->read_wait, POLLIN);
                                do_sleep++;
                        }
                        if (waitqueue_active(&tty->write_wait)) {
-                               wake_up(&tty->write_wait);
+                               wake_up_poll(&tty->write_wait, POLLOUT);
                                do_sleep++;
                        }
                }
                if (o_tty_closing) {
                        if (waitqueue_active(&o_tty->read_wait)) {
-                               wake_up(&o_tty->read_wait);
+                               wake_up_poll(&o_tty->read_wait, POLLIN);
                                do_sleep++;
                        }
                        if (waitqueue_active(&o_tty->write_wait)) {
-                               wake_up(&o_tty->write_wait);
+                               wake_up_poll(&o_tty->write_wait, POLLOUT);
                                do_sleep++;
                        }
                }
@@ -1758,7 +1758,7 @@ static int __tty_open(struct inode *inode, struct file *filp)
        struct tty_driver *driver;
        int index;
        dev_t device = inode->i_rdev;
-       unsigned short saved_flags = filp->f_flags;
+       unsigned saved_flags = filp->f_flags;
 
        nonseekable_open(inode, filp);
 
@@ -2681,7 +2681,7 @@ void __do_SAK(struct tty_struct *tty)
        /* Kill the entire session */
        do_each_pid_task(session, PIDTYPE_SID, p) {
                printk(KERN_NOTICE "SAK: killed process %d"
-                       " (%s): task_session_nr(p)==tty->session\n",
+                       " (%s): task_session(p)==tty->session\n",
                        task_pid_nr(p), p->comm);
                send_sig(SIGKILL, p, 1);
        } while_each_pid_task(session, PIDTYPE_SID, p);
@@ -2691,7 +2691,7 @@ void __do_SAK(struct tty_struct *tty)
        do_each_thread(g, p) {
                if (p->signal->tty == tty) {
                        printk(KERN_NOTICE "SAK: killed process %d"
-                           " (%s): task_session_nr(p)==tty->session\n",
+                           " (%s): task_session(p)==tty->session\n",
                            task_pid_nr(p), p->comm);
                        send_sig(SIGKILL, p, 1);
                        continue;
index 0c79fe7f15673563257fe6a3a01a0c451f6dd997..4d85402a9e4a0990d2db5afdfac0c66376b1af09 100644 (file)
@@ -1882,7 +1882,7 @@ static void hifn_clear_rings(struct hifn_device *dev, int error)
 
 static void hifn_work(struct work_struct *work)
 {
-       struct delayed_work *dw = container_of(work, struct delayed_work, work);
+       struct delayed_work *dw = to_delayed_work(work);
        struct hifn_device *dev = container_of(dw, struct hifn_device, work);
        unsigned long flags;
        int reset = 0;
index eee47fd16d79866899f7438fcdaea321a524d1f8..e5f5c5a8ba6c9bf61616a01afde3bbfe22ac25c1 100644 (file)
@@ -1,13 +1,12 @@
 #
 #      EDAC Kconfig
-#      Copyright (c) 2003 Linux Networx
+#      Copyright (c) 2008 Doug Thompson www.softwarebitmaker.com
 #      Licensed and distributed under the GPL
 #
 
 menuconfig EDAC
-       bool "EDAC - error detection and reporting (EXPERIMENTAL)"
+       bool "EDAC - error detection and reporting"
        depends on HAS_IOMEM
-       depends on EXPERIMENTAL
        depends on X86 || PPC
        help
          EDAC is designed to report errors in the core system.
@@ -40,6 +39,14 @@ config EDAC_DEBUG
          there're four debug levels (x=0,1,2,3 from low to high).
          Usually you should select 'N'.
 
+config EDAC_DEBUG_VERBOSE
+       bool "More verbose debugging"
+       depends on EDAC_DEBUG
+       help
+         This option makes debugging information more verbose.
+         Source file name and line number where debugging message
+         printed will be added to debugging message.
+
 config EDAC_MM_EDAC
        tristate "Main Memory EDAC (Error Detection And Correction) reporting"
        default y
@@ -174,4 +181,27 @@ config EDAC_CELL
          Cell Broadband Engine internal memory controller
          on platform without a hypervisor
 
+config EDAC_PPC4XX
+       tristate "PPC4xx IBM DDR2 Memory Controller"
+       depends on EDAC_MM_EDAC && 4xx
+       help
+         This enables support for EDAC on the ECC memory used
+         with the IBM DDR2 memory controller found in various
+         PowerPC 4xx embedded processors such as the 405EX[r],
+         440SP, 440SPe, 460EX, 460GT and 460SX.
+
+config EDAC_AMD8131
+       tristate "AMD8131 HyperTransport PCI-X Tunnel"
+       depends on EDAC_MM_EDAC && PCI
+       help
+         Support for error detection and correction on the
+         AMD8131 HyperTransport PCI-X Tunnel chip.
+
+config EDAC_AMD8111
+       tristate "AMD8111 HyperTransport I/O Hub"
+       depends on EDAC_MM_EDAC && PCI
+       help
+         Support for error detection and correction on the
+         AMD8111 HyperTransport I/O Hub chip.
+
 endif # EDAC
index b75196927de37901424bf58a6c009702ef7f1850..a5fdcf02f591d586a33c37bd1d9337798d99bd42 100644 (file)
@@ -34,4 +34,4 @@ obj-$(CONFIG_EDAC_PASEMI)             += pasemi_edac.o
 obj-$(CONFIG_EDAC_MPC85XX)             += mpc85xx_edac.o
 obj-$(CONFIG_EDAC_MV64X60)             += mv64x60_edac.o
 obj-$(CONFIG_EDAC_CELL)                        += cell_edac.o
-
+obj-$(CONFIG_EDAC_PPC4XX)              += ppc4xx_edac.o
diff --git a/drivers/edac/amd8111_edac.c b/drivers/edac/amd8111_edac.c
new file mode 100644 (file)
index 0000000..6146921
--- /dev/null
@@ -0,0 +1,595 @@
+/*
+ * amd8111_edac.c, AMD8111 Hyper Transport chip EDAC kernel module
+ *
+ * Copyright (c) 2008 Wind River Systems, Inc.
+ *
+ * Authors:    Cao Qingtao <qingtao.cao@windriver.com>
+ *             Benjamin Walsh <benjamin.walsh@windriver.com>
+ *             Hu Yongqi <yongqi.hu@windriver.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/edac.h>
+#include <linux/pci_ids.h>
+#include <asm/io.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+#include "amd8111_edac.h"
+
+#define AMD8111_EDAC_REVISION  " Ver: 1.0.0 " __DATE__
+#define AMD8111_EDAC_MOD_STR   "amd8111_edac"
+
+#define PCI_DEVICE_ID_AMD_8111_PCI     0x7460
+static int edac_dev_idx;
+
+enum amd8111_edac_devs {
+       LPC_BRIDGE = 0,
+};
+
+enum amd8111_edac_pcis {
+       PCI_BRIDGE = 0,
+};
+
+/* Wrapper functions for accessing PCI configuration space */
+static int edac_pci_read_dword(struct pci_dev *dev, int reg, u32 *val32)
+{
+       int ret;
+
+       ret = pci_read_config_dword(dev, reg, val32);
+       if (ret != 0)
+               printk(KERN_ERR AMD8111_EDAC_MOD_STR
+                       " PCI Access Read Error at 0x%x\n", reg);
+
+       return ret;
+}
+
+static void edac_pci_read_byte(struct pci_dev *dev, int reg, u8 *val8)
+{
+       int ret;
+
+       ret = pci_read_config_byte(dev, reg, val8);
+       if (ret != 0)
+               printk(KERN_ERR AMD8111_EDAC_MOD_STR
+                       " PCI Access Read Error at 0x%x\n", reg);
+}
+
+static void edac_pci_write_dword(struct pci_dev *dev, int reg, u32 val32)
+{
+       int ret;
+
+       ret = pci_write_config_dword(dev, reg, val32);
+       if (ret != 0)
+               printk(KERN_ERR AMD8111_EDAC_MOD_STR
+                       " PCI Access Write Error at 0x%x\n", reg);
+}
+
+static void edac_pci_write_byte(struct pci_dev *dev, int reg, u8 val8)
+{
+       int ret;
+
+       ret = pci_write_config_byte(dev, reg, val8);
+       if (ret != 0)
+               printk(KERN_ERR AMD8111_EDAC_MOD_STR
+                       " PCI Access Write Error at 0x%x\n", reg);
+}
+
+/*
+ * device-specific methods for amd8111 PCI Bridge Controller
+ *
+ * Error Reporting and Handling for amd8111 chipset could be found
+ * in its datasheet 3.1.2 section, P37
+ */
+static void amd8111_pci_bridge_init(struct amd8111_pci_info *pci_info)
+{
+       u32 val32;
+       struct pci_dev *dev = pci_info->dev;
+
+       /* First clear error detection flags on the host interface */
+
+       /* Clear SSE/SMA/STA flags in the global status register*/
+       edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
+       if (val32 & PCI_STSCMD_CLEAR_MASK)
+               edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);
+
+       /* Clear CRC and Link Fail flags in HT Link Control reg */
+       edac_pci_read_dword(dev, REG_HT_LINK, &val32);
+       if (val32 & HT_LINK_CLEAR_MASK)
+               edac_pci_write_dword(dev, REG_HT_LINK, val32);
+
+       /* Second clear all fault on the secondary interface */
+
+       /* Clear error flags in the memory-base limit reg. */
+       edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
+       if (val32 & MEM_LIMIT_CLEAR_MASK)
+               edac_pci_write_dword(dev, REG_MEM_LIM, val32);
+
+       /* Clear Discard Timer Expired flag in Interrupt/Bridge Control reg */
+       edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
+       if (val32 & PCI_INTBRG_CTRL_CLEAR_MASK)
+               edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
+
+       /* Last enable error detections */
+       if (edac_op_state == EDAC_OPSTATE_POLL) {
+               /* Enable System Error reporting in global status register */
+               edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
+               val32 |= PCI_STSCMD_SERREN;
+               edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);
+
+               /* Enable CRC Sync flood packets to HyperTransport Link */
+               edac_pci_read_dword(dev, REG_HT_LINK, &val32);
+               val32 |= HT_LINK_CRCFEN;
+               edac_pci_write_dword(dev, REG_HT_LINK, val32);
+
+               /* Enable SSE reporting etc in Interrupt control reg */
+               edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
+               val32 |= PCI_INTBRG_CTRL_POLL_MASK;
+               edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
+       }
+}
+
+static void amd8111_pci_bridge_exit(struct amd8111_pci_info *pci_info)
+{
+       u32 val32;
+       struct pci_dev *dev = pci_info->dev;
+
+       if (edac_op_state == EDAC_OPSTATE_POLL) {
+               /* Disable System Error reporting */
+               edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
+               val32 &= ~PCI_STSCMD_SERREN;
+               edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);
+
+               /* Disable CRC flood packets */
+               edac_pci_read_dword(dev, REG_HT_LINK, &val32);
+               val32 &= ~HT_LINK_CRCFEN;
+               edac_pci_write_dword(dev, REG_HT_LINK, val32);
+
+               /* Disable DTSERREN/MARSP/SERREN in Interrupt Control reg */
+               edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
+               val32 &= ~PCI_INTBRG_CTRL_POLL_MASK;
+               edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
+       }
+}
+
+static void amd8111_pci_bridge_check(struct edac_pci_ctl_info *edac_dev)
+{
+       struct amd8111_pci_info *pci_info = edac_dev->pvt_info;
+       struct pci_dev *dev = pci_info->dev;
+       u32 val32;
+
+       /* Check out PCI Bridge Status and Command Register */
+       edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
+       if (val32 & PCI_STSCMD_CLEAR_MASK) {
+               printk(KERN_INFO "Error(s) in PCI bridge status and command"
+                       "register on device %s\n", pci_info->ctl_name);
+               printk(KERN_INFO "SSE: %d, RMA: %d, RTA: %d\n",
+                       (val32 & PCI_STSCMD_SSE) != 0,
+                       (val32 & PCI_STSCMD_RMA) != 0,
+                       (val32 & PCI_STSCMD_RTA) != 0);
+
+               val32 |= PCI_STSCMD_CLEAR_MASK;
+               edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);
+
+               edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+       }
+
+       /* Check out HyperTransport Link Control Register */
+       edac_pci_read_dword(dev, REG_HT_LINK, &val32);
+       if (val32 & HT_LINK_LKFAIL) {
+               printk(KERN_INFO "Error(s) in hypertransport link control"
+                       "register on device %s\n", pci_info->ctl_name);
+               printk(KERN_INFO "LKFAIL: %d\n",
+                       (val32 & HT_LINK_LKFAIL) != 0);
+
+               val32 |= HT_LINK_LKFAIL;
+               edac_pci_write_dword(dev, REG_HT_LINK, val32);
+
+               edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+       }
+
+       /* Check out PCI Interrupt and Bridge Control Register */
+       edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
+       if (val32 & PCI_INTBRG_CTRL_DTSTAT) {
+               printk(KERN_INFO "Error(s) in PCI interrupt and bridge control"
+                       "register on device %s\n", pci_info->ctl_name);
+               printk(KERN_INFO "DTSTAT: %d\n",
+                       (val32 & PCI_INTBRG_CTRL_DTSTAT) != 0);
+
+               val32 |= PCI_INTBRG_CTRL_DTSTAT;
+               edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
+
+               edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+       }
+
+       /* Check out PCI Bridge Memory Base-Limit Register */
+       edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
+       if (val32 & MEM_LIMIT_CLEAR_MASK) {
+               printk(KERN_INFO
+                       "Error(s) in mem limit register on %s device\n",
+                       pci_info->ctl_name);
+               printk(KERN_INFO "DPE: %d, RSE: %d, RMA: %d\n"
+                       "RTA: %d, STA: %d, MDPE: %d\n",
+                       (val32 & MEM_LIMIT_DPE)  != 0,
+                       (val32 & MEM_LIMIT_RSE)  != 0,
+                       (val32 & MEM_LIMIT_RMA)  != 0,
+                       (val32 & MEM_LIMIT_RTA)  != 0,
+                       (val32 & MEM_LIMIT_STA)  != 0,
+                       (val32 & MEM_LIMIT_MDPE) != 0);
+
+               val32 |= MEM_LIMIT_CLEAR_MASK;
+               edac_pci_write_dword(dev, REG_MEM_LIM, val32);
+
+               edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+       }
+}
+
+static struct resource *legacy_io_res;
+static int at_compat_reg_broken;
+#define LEGACY_NR_PORTS        1
+
+/* device-specific methods for amd8111 LPC Bridge device */
+static void amd8111_lpc_bridge_init(struct amd8111_dev_info *dev_info)
+{
+       u8 val8;
+       struct pci_dev *dev = dev_info->dev;
+
+       /* First clear REG_AT_COMPAT[SERR, IOCHK] if necessary */
+       legacy_io_res = request_region(REG_AT_COMPAT, LEGACY_NR_PORTS,
+                                       AMD8111_EDAC_MOD_STR);
+       if (!legacy_io_res)
+               printk(KERN_INFO "%s: failed to request legacy I/O region "
+                       "start %d, len %d\n", __func__,
+                       REG_AT_COMPAT, LEGACY_NR_PORTS);
+       else {
+               val8 = __do_inb(REG_AT_COMPAT);
+               if (val8 == 0xff) { /* buggy port */
+                       printk(KERN_INFO "%s: port %d is buggy, not supported"
+                               " by hardware?\n", __func__, REG_AT_COMPAT);
+                       at_compat_reg_broken = 1;
+                       release_region(REG_AT_COMPAT, LEGACY_NR_PORTS);
+                       legacy_io_res = NULL;
+               } else {
+                       u8 out8 = 0;
+                       if (val8 & AT_COMPAT_SERR)
+                               out8 = AT_COMPAT_CLRSERR;
+                       if (val8 & AT_COMPAT_IOCHK)
+                               out8 |= AT_COMPAT_CLRIOCHK;
+                       if (out8 > 0)
+                               __do_outb(out8, REG_AT_COMPAT);
+               }
+       }
+
+       /* Second clear error flags on LPC bridge */
+       edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8);
+       if (val8 & IO_CTRL_1_CLEAR_MASK)
+               edac_pci_write_byte(dev, REG_IO_CTRL_1, val8);
+}
+
+static void amd8111_lpc_bridge_exit(struct amd8111_dev_info *dev_info)
+{
+       if (legacy_io_res)
+               release_region(REG_AT_COMPAT, LEGACY_NR_PORTS);
+}
+
+static void amd8111_lpc_bridge_check(struct edac_device_ctl_info *edac_dev)
+{
+       struct amd8111_dev_info *dev_info = edac_dev->pvt_info;
+       struct pci_dev *dev = dev_info->dev;
+       u8 val8;
+
+       edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8);
+       if (val8 & IO_CTRL_1_CLEAR_MASK) {
+               printk(KERN_INFO
+                       "Error(s) in IO control register on %s device\n",
+                       dev_info->ctl_name);
+               printk(KERN_INFO "LPC ERR: %d, PW2LPC: %d\n",
+                       (val8 & IO_CTRL_1_LPC_ERR) != 0,
+                       (val8 & IO_CTRL_1_PW2LPC) != 0);
+
+               val8 |= IO_CTRL_1_CLEAR_MASK;
+               edac_pci_write_byte(dev, REG_IO_CTRL_1, val8);
+
+               edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
+       }
+
+       if (at_compat_reg_broken == 0) {
+               u8 out8 = 0;
+               val8 = __do_inb(REG_AT_COMPAT);
+               if (val8 & AT_COMPAT_SERR)
+                       out8 = AT_COMPAT_CLRSERR;
+               if (val8 & AT_COMPAT_IOCHK)
+                       out8 |= AT_COMPAT_CLRIOCHK;
+               if (out8 > 0) {
+                       __do_outb(out8, REG_AT_COMPAT);
+                       edac_device_handle_ue(edac_dev, 0, 0,
+                                               edac_dev->ctl_name);
+               }
+       }
+}
+
+/* General devices represented by edac_device_ctl_info */
+static struct amd8111_dev_info amd8111_devices[] = {
+       [LPC_BRIDGE] = {
+               .err_dev = PCI_DEVICE_ID_AMD_8111_LPC,
+               .ctl_name = "lpc",
+               .init = amd8111_lpc_bridge_init,
+               .exit = amd8111_lpc_bridge_exit,
+               .check = amd8111_lpc_bridge_check,
+       },
+       {0},
+};
+
+/* PCI controllers represented by edac_pci_ctl_info */
+static struct amd8111_pci_info amd8111_pcis[] = {
+       [PCI_BRIDGE] = {
+               .err_dev = PCI_DEVICE_ID_AMD_8111_PCI,
+               .ctl_name = "AMD8111_PCI_Controller",
+               .init = amd8111_pci_bridge_init,
+               .exit = amd8111_pci_bridge_exit,
+               .check = amd8111_pci_bridge_check,
+       },
+       {0},
+};
+
+static int amd8111_dev_probe(struct pci_dev *dev,
+                               const struct pci_device_id *id)
+{
+       struct amd8111_dev_info *dev_info = &amd8111_devices[id->driver_data];
+
+       dev_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,
+                                       dev_info->err_dev, NULL);
+
+       if (!dev_info->dev) {
+               printk(KERN_ERR "EDAC device not found:"
+                       "vendor %x, device %x, name %s\n",
+                       PCI_VENDOR_ID_AMD, dev_info->err_dev,
+                       dev_info->ctl_name);
+               return -ENODEV;
+       }
+
+       if (pci_enable_device(dev_info->dev)) {
+               pci_dev_put(dev_info->dev);
+               printk(KERN_ERR "failed to enable:"
+                       "vendor %x, device %x, name %s\n",
+                       PCI_VENDOR_ID_AMD, dev_info->err_dev,
+                       dev_info->ctl_name);
+               return -ENODEV;
+       }
+
+       /*
+        * we do not allocate extra private structure for
+        * edac_device_ctl_info, but make use of existing
+        * one instead.
+       */
+       dev_info->edac_idx = edac_dev_idx++;
+       dev_info->edac_dev =
+               edac_device_alloc_ctl_info(0, dev_info->ctl_name, 1,
+                                          NULL, 0, 0,
+                                          NULL, 0, dev_info->edac_idx);
+       if (!dev_info->edac_dev)
+               return -ENOMEM;
+
+       dev_info->edac_dev->pvt_info = dev_info;
+       dev_info->edac_dev->dev = &dev_info->dev->dev;
+       dev_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR;
+       dev_info->edac_dev->ctl_name = dev_info->ctl_name;
+       dev_info->edac_dev->dev_name = dev_info->dev->dev.bus_id;
+
+       if (edac_op_state == EDAC_OPSTATE_POLL)
+               dev_info->edac_dev->edac_check = dev_info->check;
+
+       if (dev_info->init)
+               dev_info->init(dev_info);
+
+       if (edac_device_add_device(dev_info->edac_dev) > 0) {
+               printk(KERN_ERR "failed to add edac_dev for %s\n",
+                       dev_info->ctl_name);
+               edac_device_free_ctl_info(dev_info->edac_dev);
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO "added one edac_dev on AMD8111 "
+               "vendor %x, device %x, name %s\n",
+               PCI_VENDOR_ID_AMD, dev_info->err_dev,
+               dev_info->ctl_name);
+
+       return 0;
+}
+
+static void amd8111_dev_remove(struct pci_dev *dev)
+{
+       struct amd8111_dev_info *dev_info;
+
+       for (dev_info = amd8111_devices; dev_info->err_dev; dev_info++)
+               if (dev_info->dev->device == dev->device)
+                       break;
+
+       if (!dev_info->err_dev) /* should never happen */
+               return;
+
+       if (dev_info->edac_dev) {
+               edac_device_del_device(dev_info->edac_dev->dev);
+               edac_device_free_ctl_info(dev_info->edac_dev);
+       }
+
+       if (dev_info->exit)
+               dev_info->exit(dev_info);
+
+       pci_dev_put(dev_info->dev);
+}
+
+static int amd8111_pci_probe(struct pci_dev *dev,
+                               const struct pci_device_id *id)
+{
+       struct amd8111_pci_info *pci_info = &amd8111_pcis[id->driver_data];
+
+       pci_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,
+                                       pci_info->err_dev, NULL);
+
+       if (!pci_info->dev) {
+               printk(KERN_ERR "EDAC device not found:"
+                       "vendor %x, device %x, name %s\n",
+                       PCI_VENDOR_ID_AMD, pci_info->err_dev,
+                       pci_info->ctl_name);
+               return -ENODEV;
+       }
+
+       if (pci_enable_device(pci_info->dev)) {
+               pci_dev_put(pci_info->dev);
+               printk(KERN_ERR "failed to enable:"
+                       "vendor %x, device %x, name %s\n",
+                       PCI_VENDOR_ID_AMD, pci_info->err_dev,
+                       pci_info->ctl_name);
+               return -ENODEV;
+       }
+
+       /*
+        * we do not allocate extra private structure for
+        * edac_pci_ctl_info, but make use of existing
+        * one instead.
+       */
+       pci_info->edac_idx = edac_pci_alloc_index();
+       pci_info->edac_dev = edac_pci_alloc_ctl_info(0, pci_info->ctl_name);
+       if (!pci_info->edac_dev)
+               return -ENOMEM;
+
+       pci_info->edac_dev->pvt_info = pci_info;
+       pci_info->edac_dev->dev = &pci_info->dev->dev;
+       pci_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR;
+       pci_info->edac_dev->ctl_name = pci_info->ctl_name;
+       pci_info->edac_dev->dev_name = pci_info->dev->dev.bus_id;
+
+       if (edac_op_state == EDAC_OPSTATE_POLL)
+               pci_info->edac_dev->edac_check = pci_info->check;
+
+       if (pci_info->init)
+               pci_info->init(pci_info);
+
+       if (edac_pci_add_device(pci_info->edac_dev, pci_info->edac_idx) > 0) {
+               printk(KERN_ERR "failed to add edac_pci for %s\n",
+                       pci_info->ctl_name);
+               edac_pci_free_ctl_info(pci_info->edac_dev);
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO "added one edac_pci on AMD8111 "
+               "vendor %x, device %x, name %s\n",
+               PCI_VENDOR_ID_AMD, pci_info->err_dev,
+               pci_info->ctl_name);
+
+       return 0;
+}
+
+static void amd8111_pci_remove(struct pci_dev *dev)
+{
+       struct amd8111_pci_info *pci_info;
+
+       for (pci_info = amd8111_pcis; pci_info->err_dev; pci_info++)
+               if (pci_info->dev->device == dev->device)
+                       break;
+
+       if (!pci_info->err_dev) /* should never happen */
+               return;
+
+       if (pci_info->edac_dev) {
+               edac_pci_del_device(pci_info->edac_dev->dev);
+               edac_pci_free_ctl_info(pci_info->edac_dev);
+       }
+
+       if (pci_info->exit)
+               pci_info->exit(pci_info);
+
+       pci_dev_put(pci_info->dev);
+}
+
+/* PCI Device ID talbe for general EDAC device */
+static const struct pci_device_id amd8111_edac_dev_tbl[] = {
+       {
+       PCI_VEND_DEV(AMD, 8111_LPC),
+       .subvendor = PCI_ANY_ID,
+       .subdevice = PCI_ANY_ID,
+       .class = 0,
+       .class_mask = 0,
+       .driver_data = LPC_BRIDGE,
+       },
+       {
+       0,
+       }                       /* table is NULL-terminated */
+};
+MODULE_DEVICE_TABLE(pci, amd8111_edac_dev_tbl);
+
+static struct pci_driver amd8111_edac_dev_driver = {
+       .name = "AMD8111_EDAC_DEV",
+       .probe = amd8111_dev_probe,
+       .remove = amd8111_dev_remove,
+       .id_table = amd8111_edac_dev_tbl,
+};
+
+/* PCI Device ID table for EDAC PCI controller */
+static const struct pci_device_id amd8111_edac_pci_tbl[] = {
+       {
+       PCI_VEND_DEV(AMD, 8111_PCI),
+       .subvendor = PCI_ANY_ID,
+       .subdevice = PCI_ANY_ID,
+       .class = 0,
+       .class_mask = 0,
+       .driver_data = PCI_BRIDGE,
+       },
+       {
+       0,
+       }                       /* table is NULL-terminated */
+};
+MODULE_DEVICE_TABLE(pci, amd8111_edac_pci_tbl);
+
+static struct pci_driver amd8111_edac_pci_driver = {
+       .name = "AMD8111_EDAC_PCI",
+       .probe = amd8111_pci_probe,
+       .remove = amd8111_pci_remove,
+       .id_table = amd8111_edac_pci_tbl,
+};
+
+static int __init amd8111_edac_init(void)
+{
+       int val;
+
+       printk(KERN_INFO "AMD8111 EDAC driver " AMD8111_EDAC_REVISION "\n");
+       printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n");
+
+       /* Only POLL mode supported so far */
+       edac_op_state = EDAC_OPSTATE_POLL;
+
+       val = pci_register_driver(&amd8111_edac_dev_driver);
+       val |= pci_register_driver(&amd8111_edac_pci_driver);
+
+       return val;
+}
+
+static void __exit amd8111_edac_exit(void)
+{
+       pci_unregister_driver(&amd8111_edac_pci_driver);
+       pci_unregister_driver(&amd8111_edac_dev_driver);
+}
+
+
+module_init(amd8111_edac_init);
+module_exit(amd8111_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>\n");
+MODULE_DESCRIPTION("AMD8111 HyperTransport I/O Hub EDAC kernel module");
diff --git a/drivers/edac/amd8111_edac.h b/drivers/edac/amd8111_edac.h
new file mode 100644 (file)
index 0000000..3579433
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * amd8111_edac.h, EDAC defs for AMD8111 hypertransport chip
+ *
+ * Copyright (c) 2008 Wind River Systems, Inc.
+ *
+ * Authors:    Cao Qingtao <qingtao.cao@windriver.com>
+ *             Benjamin Walsh <benjamin.walsh@windriver.com>
+ *             Hu Yongqi <yongqi.hu@windriver.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.
+ *
+ * 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 _AMD8111_EDAC_H_
+#define _AMD8111_EDAC_H_
+
+/************************************************************
+ *     PCI Bridge Status and Command Register, DevA:0x04
+ ************************************************************/
+#define REG_PCI_STSCMD 0x04
+enum pci_stscmd_bits {
+       PCI_STSCMD_SSE          = BIT(30),
+       PCI_STSCMD_RMA          = BIT(29),
+       PCI_STSCMD_RTA          = BIT(28),
+       PCI_STSCMD_SERREN       = BIT(8),
+       PCI_STSCMD_CLEAR_MASK   = (PCI_STSCMD_SSE |
+                                  PCI_STSCMD_RMA |
+                                  PCI_STSCMD_RTA)
+};
+
+/************************************************************
+ *     PCI Bridge Memory Base-Limit Register, DevA:0x1c
+ ************************************************************/
+#define REG_MEM_LIM     0x1c
+enum mem_limit_bits {
+       MEM_LIMIT_DPE   = BIT(31),
+       MEM_LIMIT_RSE   = BIT(30),
+       MEM_LIMIT_RMA   = BIT(29),
+       MEM_LIMIT_RTA   = BIT(28),
+       MEM_LIMIT_STA   = BIT(27),
+       MEM_LIMIT_MDPE  = BIT(24),
+       MEM_LIMIT_CLEAR_MASK  = (MEM_LIMIT_DPE |
+                                MEM_LIMIT_RSE |
+                                MEM_LIMIT_RMA |
+                                MEM_LIMIT_RTA |
+                                MEM_LIMIT_STA |
+                                MEM_LIMIT_MDPE)
+};
+
+/************************************************************
+ *     HyperTransport Link Control Register, DevA:0xc4
+ ************************************************************/
+#define REG_HT_LINK    0xc4
+enum ht_link_bits {
+       HT_LINK_LKFAIL  = BIT(4),
+       HT_LINK_CRCFEN  = BIT(1),
+       HT_LINK_CLEAR_MASK = (HT_LINK_LKFAIL)
+};
+
+/************************************************************
+ *     PCI Bridge Interrupt and Bridge Control, DevA:0x3c
+ ************************************************************/
+#define REG_PCI_INTBRG_CTRL    0x3c
+enum pci_intbrg_ctrl_bits {
+       PCI_INTBRG_CTRL_DTSERREN        = BIT(27),
+       PCI_INTBRG_CTRL_DTSTAT          = BIT(26),
+       PCI_INTBRG_CTRL_MARSP           = BIT(21),
+       PCI_INTBRG_CTRL_SERREN          = BIT(17),
+       PCI_INTBRG_CTRL_PEREN           = BIT(16),
+       PCI_INTBRG_CTRL_CLEAR_MASK      = (PCI_INTBRG_CTRL_DTSTAT),
+       PCI_INTBRG_CTRL_POLL_MASK       = (PCI_INTBRG_CTRL_DTSERREN |
+                                          PCI_INTBRG_CTRL_MARSP |
+                                          PCI_INTBRG_CTRL_SERREN)
+};
+
+/************************************************************
+ *             I/O Control 1 Register, DevB:0x40
+ ************************************************************/
+#define REG_IO_CTRL_1 0x40
+enum io_ctrl_1_bits {
+       IO_CTRL_1_NMIONERR      = BIT(7),
+       IO_CTRL_1_LPC_ERR       = BIT(6),
+       IO_CTRL_1_PW2LPC        = BIT(1),
+       IO_CTRL_1_CLEAR_MASK    = (IO_CTRL_1_LPC_ERR | IO_CTRL_1_PW2LPC)
+};
+
+/************************************************************
+ *             Legacy I/O Space Registers
+ ************************************************************/
+#define REG_AT_COMPAT 0x61
+enum at_compat_bits {
+       AT_COMPAT_SERR          = BIT(7),
+       AT_COMPAT_IOCHK         = BIT(6),
+       AT_COMPAT_CLRIOCHK      = BIT(3),
+       AT_COMPAT_CLRSERR       = BIT(2),
+};
+
+struct amd8111_dev_info {
+       u16 err_dev;    /* PCI Device ID */
+       struct pci_dev *dev;
+       int edac_idx;   /* device index */
+       char *ctl_name;
+       struct edac_device_ctl_info *edac_dev;
+       void (*init)(struct amd8111_dev_info *dev_info);
+       void (*exit)(struct amd8111_dev_info *dev_info);
+       void (*check)(struct edac_device_ctl_info *edac_dev);
+};
+
+struct amd8111_pci_info {
+       u16 err_dev;    /* PCI Device ID */
+       struct pci_dev *dev;
+       int edac_idx;   /* pci index */
+       const char *ctl_name;
+       struct edac_pci_ctl_info *edac_dev;
+       void (*init)(struct amd8111_pci_info *dev_info);
+       void (*exit)(struct amd8111_pci_info *dev_info);
+       void (*check)(struct edac_pci_ctl_info *edac_dev);
+};
+
+#endif /* _AMD8111_EDAC_H_ */
diff --git a/drivers/edac/amd8131_edac.c b/drivers/edac/amd8131_edac.c
new file mode 100644 (file)
index 0000000..c083b31
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * amd8131_edac.c, AMD8131 hypertransport chip EDAC kernel module
+ *
+ * Copyright (c) 2008 Wind River Systems, Inc.
+ *
+ * Authors:    Cao Qingtao <qingtao.cao@windriver.com>
+ *             Benjamin Walsh <benjamin.walsh@windriver.com>
+ *             Hu Yongqi <yongqi.hu@windriver.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/edac.h>
+#include <linux/pci_ids.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+#include "amd8131_edac.h"
+
+#define AMD8131_EDAC_REVISION  " Ver: 1.0.0 " __DATE__
+#define AMD8131_EDAC_MOD_STR   "amd8131_edac"
+
+/* Wrapper functions for accessing PCI configuration space */
+static void edac_pci_read_dword(struct pci_dev *dev, int reg, u32 *val32)
+{
+       int ret;
+
+       ret = pci_read_config_dword(dev, reg, val32);
+       if (ret != 0)
+               printk(KERN_ERR AMD8131_EDAC_MOD_STR
+                       " PCI Access Read Error at 0x%x\n", reg);
+}
+
+static void edac_pci_write_dword(struct pci_dev *dev, int reg, u32 val32)
+{
+       int ret;
+
+       ret = pci_write_config_dword(dev, reg, val32);
+       if (ret != 0)
+               printk(KERN_ERR AMD8131_EDAC_MOD_STR
+                       " PCI Access Write Error at 0x%x\n", reg);
+}
+
+static char * const bridge_str[] = {
+       [NORTH_A] = "NORTH A",
+       [NORTH_B] = "NORTH B",
+       [SOUTH_A] = "SOUTH A",
+       [SOUTH_B] = "SOUTH B",
+       [NO_BRIDGE] = "NO BRIDGE",
+};
+
+/* Support up to two AMD8131 chipsets on a platform */
+static struct amd8131_dev_info amd8131_devices[] = {
+       {
+       .inst = NORTH_A,
+       .devfn = DEVFN_PCIX_BRIDGE_NORTH_A,
+       .ctl_name = "AMD8131_PCIX_NORTH_A",
+       },
+       {
+       .inst = NORTH_B,
+       .devfn = DEVFN_PCIX_BRIDGE_NORTH_B,
+       .ctl_name = "AMD8131_PCIX_NORTH_B",
+       },
+       {
+       .inst = SOUTH_A,
+       .devfn = DEVFN_PCIX_BRIDGE_SOUTH_A,
+       .ctl_name = "AMD8131_PCIX_SOUTH_A",
+       },
+       {
+       .inst = SOUTH_B,
+       .devfn = DEVFN_PCIX_BRIDGE_SOUTH_B,
+       .ctl_name = "AMD8131_PCIX_SOUTH_B",
+       },
+       {.inst = NO_BRIDGE,},
+};
+
+static void amd8131_pcix_init(struct amd8131_dev_info *dev_info)
+{
+       u32 val32;
+       struct pci_dev *dev = dev_info->dev;
+
+       /* First clear error detection flags */
+       edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
+       if (val32 & MEM_LIMIT_MASK)
+               edac_pci_write_dword(dev, REG_MEM_LIM, val32);
+
+       /* Clear Discard Timer Timedout flag */
+       edac_pci_read_dword(dev, REG_INT_CTLR, &val32);
+       if (val32 & INT_CTLR_DTS)
+               edac_pci_write_dword(dev, REG_INT_CTLR, val32);
+
+       /* Clear CRC Error flag on link side A */
+       edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32);
+       if (val32 & LNK_CTRL_CRCERR_A)
+               edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32);
+
+       /* Clear CRC Error flag on link side B */
+       edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
+       if (val32 & LNK_CTRL_CRCERR_B)
+               edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
+
+       /*
+        * Then enable all error detections.
+        *
+        * Setup Discard Timer Sync Flood Enable,
+        * System Error Enable and Parity Error Enable.
+        */
+       edac_pci_read_dword(dev, REG_INT_CTLR, &val32);
+       val32 |= INT_CTLR_PERR | INT_CTLR_SERR | INT_CTLR_DTSE;
+       edac_pci_write_dword(dev, REG_INT_CTLR, val32);
+
+       /* Enable overall SERR Error detection */
+       edac_pci_read_dword(dev, REG_STS_CMD, &val32);
+       val32 |= STS_CMD_SERREN;
+       edac_pci_write_dword(dev, REG_STS_CMD, val32);
+
+       /* Setup CRC Flood Enable for link side A */
+       edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32);
+       val32 |= LNK_CTRL_CRCFEN;
+       edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32);
+
+       /* Setup CRC Flood Enable for link side B */
+       edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
+       val32 |= LNK_CTRL_CRCFEN;
+       edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
+}
+
+static void amd8131_pcix_exit(struct amd8131_dev_info *dev_info)
+{
+       u32 val32;
+       struct pci_dev *dev = dev_info->dev;
+
+       /* Disable SERR, PERR and DTSE Error detection */
+       edac_pci_read_dword(dev, REG_INT_CTLR, &val32);
+       val32 &= ~(INT_CTLR_PERR | INT_CTLR_SERR | INT_CTLR_DTSE);
+       edac_pci_write_dword(dev, REG_INT_CTLR, val32);
+
+       /* Disable overall System Error detection */
+       edac_pci_read_dword(dev, REG_STS_CMD, &val32);
+       val32 &= ~STS_CMD_SERREN;
+       edac_pci_write_dword(dev, REG_STS_CMD, val32);
+
+       /* Disable CRC Sync Flood on link side A */
+       edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32);
+       val32 &= ~LNK_CTRL_CRCFEN;
+       edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32);
+
+       /* Disable CRC Sync Flood on link side B */
+       edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
+       val32 &= ~LNK_CTRL_CRCFEN;
+       edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
+}
+
+static void amd8131_pcix_check(struct edac_pci_ctl_info *edac_dev)
+{
+       struct amd8131_dev_info *dev_info = edac_dev->pvt_info;
+       struct pci_dev *dev = dev_info->dev;
+       u32 val32;
+
+       /* Check PCI-X Bridge Memory Base-Limit Register for errors */
+       edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
+       if (val32 & MEM_LIMIT_MASK) {
+               printk(KERN_INFO "Error(s) in mem limit register "
+                       "on %s bridge\n", dev_info->ctl_name);
+               printk(KERN_INFO "DPE: %d, RSE: %d, RMA: %d\n"
+                       "RTA: %d, STA: %d, MDPE: %d\n",
+                       val32 & MEM_LIMIT_DPE,
+                       val32 & MEM_LIMIT_RSE,
+                       val32 & MEM_LIMIT_RMA,
+                       val32 & MEM_LIMIT_RTA,
+                       val32 & MEM_LIMIT_STA,
+                       val32 & MEM_LIMIT_MDPE);
+
+               val32 |= MEM_LIMIT_MASK;
+               edac_pci_write_dword(dev, REG_MEM_LIM, val32);
+
+               edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+       }
+
+       /* Check if Discard Timer timed out */
+       edac_pci_read_dword(dev, REG_INT_CTLR, &val32);
+       if (val32 & INT_CTLR_DTS) {
+               printk(KERN_INFO "Error(s) in interrupt and control register "
+                       "on %s bridge\n", dev_info->ctl_name);
+               printk(KERN_INFO "DTS: %d\n", val32 & INT_CTLR_DTS);
+
+               val32 |= INT_CTLR_DTS;
+               edac_pci_write_dword(dev, REG_INT_CTLR, val32);
+
+               edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+       }
+
+       /* Check if CRC error happens on link side A */
+       edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32);
+       if (val32 & LNK_CTRL_CRCERR_A) {
+               printk(KERN_INFO "Error(s) in link conf and control register "
+                       "on %s bridge\n", dev_info->ctl_name);
+               printk(KERN_INFO "CRCERR: %d\n", val32 & LNK_CTRL_CRCERR_A);
+
+               val32 |= LNK_CTRL_CRCERR_A;
+               edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32);
+
+               edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+       }
+
+       /* Check if CRC error happens on link side B */
+       edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
+       if (val32 & LNK_CTRL_CRCERR_B) {
+               printk(KERN_INFO "Error(s) in link conf and control register "
+                       "on %s bridge\n", dev_info->ctl_name);
+               printk(KERN_INFO "CRCERR: %d\n", val32 & LNK_CTRL_CRCERR_B);
+
+               val32 |= LNK_CTRL_CRCERR_B;
+               edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
+
+               edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+       }
+}
+
+static struct amd8131_info amd8131_chipset = {
+       .err_dev = PCI_DEVICE_ID_AMD_8131_APIC,
+       .devices = amd8131_devices,
+       .init = amd8131_pcix_init,
+       .exit = amd8131_pcix_exit,
+       .check = amd8131_pcix_check,
+};
+
+/*
+ * There are 4 PCIX Bridges on ATCA-6101 that share the same PCI Device ID,
+ * so amd8131_probe() would be called by kernel 4 times, with different
+ * address of pci_dev for each of them each time.
+ */
+static int amd8131_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       struct amd8131_dev_info *dev_info;
+
+       for (dev_info = amd8131_chipset.devices; dev_info->inst != NO_BRIDGE;
+               dev_info++)
+               if (dev_info->devfn == dev->devfn)
+                       break;
+
+       if (dev_info->inst == NO_BRIDGE) /* should never happen */
+               return -ENODEV;
+
+       /*
+        * We can't call pci_get_device() as we are used to do because
+        * there are 4 of them but pci_dev_get() instead.
+        */
+       dev_info->dev = pci_dev_get(dev);
+
+       if (pci_enable_device(dev_info->dev)) {
+               pci_dev_put(dev_info->dev);
+               printk(KERN_ERR "failed to enable:"
+                       "vendor %x, device %x, devfn %x, name %s\n",
+                       PCI_VENDOR_ID_AMD, amd8131_chipset.err_dev,
+                       dev_info->devfn, dev_info->ctl_name);
+               return -ENODEV;
+       }
+
+       /*
+        * we do not allocate extra private structure for
+        * edac_pci_ctl_info, but make use of existing
+        * one instead.
+        */
+       dev_info->edac_idx = edac_pci_alloc_index();
+       dev_info->edac_dev = edac_pci_alloc_ctl_info(0, dev_info->ctl_name);
+       if (!dev_info->edac_dev)
+               return -ENOMEM;
+
+       dev_info->edac_dev->pvt_info = dev_info;
+       dev_info->edac_dev->dev = &dev_info->dev->dev;
+       dev_info->edac_dev->mod_name = AMD8131_EDAC_MOD_STR;
+       dev_info->edac_dev->ctl_name = dev_info->ctl_name;
+       dev_info->edac_dev->dev_name = dev_info->dev->dev.bus_id;
+
+       if (edac_op_state == EDAC_OPSTATE_POLL)
+               dev_info->edac_dev->edac_check = amd8131_chipset.check;
+
+       if (amd8131_chipset.init)
+               amd8131_chipset.init(dev_info);
+
+       if (edac_pci_add_device(dev_info->edac_dev, dev_info->edac_idx) > 0) {
+               printk(KERN_ERR "failed edac_pci_add_device() for %s\n",
+                       dev_info->ctl_name);
+               edac_pci_free_ctl_info(dev_info->edac_dev);
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO "added one device on AMD8131 "
+               "vendor %x, device %x, devfn %x, name %s\n",
+               PCI_VENDOR_ID_AMD, amd8131_chipset.err_dev,
+               dev_info->devfn, dev_info->ctl_name);
+
+       return 0;
+}
+
+static void amd8131_remove(struct pci_dev *dev)
+{
+       struct amd8131_dev_info *dev_info;
+
+       for (dev_info = amd8131_chipset.devices; dev_info->inst != NO_BRIDGE;
+               dev_info++)
+               if (dev_info->devfn == dev->devfn)
+                       break;
+
+       if (dev_info->inst == NO_BRIDGE) /* should never happen */
+               return;
+
+       if (dev_info->edac_dev) {
+               edac_pci_del_device(dev_info->edac_dev->dev);
+               edac_pci_free_ctl_info(dev_info->edac_dev);
+       }
+
+       if (amd8131_chipset.exit)
+               amd8131_chipset.exit(dev_info);
+
+       pci_dev_put(dev_info->dev);
+}
+
+static const struct pci_device_id amd8131_edac_pci_tbl[] = {
+       {
+       PCI_VEND_DEV(AMD, 8131_BRIDGE),
+       .subvendor = PCI_ANY_ID,
+       .subdevice = PCI_ANY_ID,
+       .class = 0,
+       .class_mask = 0,
+       .driver_data = 0,
+       },
+       {
+       0,
+       }                       /* table is NULL-terminated */
+};
+MODULE_DEVICE_TABLE(pci, amd8131_edac_pci_tbl);
+
+static struct pci_driver amd8131_edac_driver = {
+       .name = AMD8131_EDAC_MOD_STR,
+       .probe = amd8131_probe,
+       .remove = amd8131_remove,
+       .id_table = amd8131_edac_pci_tbl,
+};
+
+static int __init amd8131_edac_init(void)
+{
+       printk(KERN_INFO "AMD8131 EDAC driver " AMD8131_EDAC_REVISION "\n");
+       printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n");
+
+       /* Only POLL mode supported so far */
+       edac_op_state = EDAC_OPSTATE_POLL;
+
+       return pci_register_driver(&amd8131_edac_driver);
+}
+
+static void __exit amd8131_edac_exit(void)
+{
+       pci_unregister_driver(&amd8131_edac_driver);
+}
+
+module_init(amd8131_edac_init);
+module_exit(amd8131_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>\n");
+MODULE_DESCRIPTION("AMD8131 HyperTransport PCI-X Tunnel EDAC kernel module");
diff --git a/drivers/edac/amd8131_edac.h b/drivers/edac/amd8131_edac.h
new file mode 100644 (file)
index 0000000..60e0d1c
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * amd8131_edac.h, EDAC defs for AMD8131 hypertransport chip
+ *
+ * Copyright (c) 2008 Wind River Systems, Inc.
+ *
+ * Authors:    Cao Qingtao <qingtao.cao@windriver.com>
+ *             Benjamin Walsh <benjamin.walsh@windriver.com>
+ *             Hu Yongqi <yongqi.hu@windriver.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.
+ *
+ * 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 _AMD8131_EDAC_H_
+#define _AMD8131_EDAC_H_
+
+#define DEVFN_PCIX_BRIDGE_NORTH_A      8
+#define DEVFN_PCIX_BRIDGE_NORTH_B      16
+#define DEVFN_PCIX_BRIDGE_SOUTH_A      24
+#define DEVFN_PCIX_BRIDGE_SOUTH_B      32
+
+/************************************************************
+ *     PCI-X Bridge Status and Command Register, DevA:0x04
+ ************************************************************/
+#define REG_STS_CMD    0x04
+enum sts_cmd_bits {
+       STS_CMD_SSE     = BIT(30),
+       STS_CMD_SERREN  = BIT(8)
+};
+
+/************************************************************
+ *     PCI-X Bridge Interrupt and Bridge Control Register,
+ ************************************************************/
+#define REG_INT_CTLR   0x3c
+enum int_ctlr_bits {
+       INT_CTLR_DTSE   = BIT(27),
+       INT_CTLR_DTS    = BIT(26),
+       INT_CTLR_SERR   = BIT(17),
+       INT_CTLR_PERR   = BIT(16)
+};
+
+/************************************************************
+ *     PCI-X Bridge Memory Base-Limit Register, DevA:0x1C
+ ************************************************************/
+#define REG_MEM_LIM    0x1c
+enum mem_limit_bits {
+       MEM_LIMIT_DPE   = BIT(31),
+       MEM_LIMIT_RSE   = BIT(30),
+       MEM_LIMIT_RMA   = BIT(29),
+       MEM_LIMIT_RTA   = BIT(28),
+       MEM_LIMIT_STA   = BIT(27),
+       MEM_LIMIT_MDPE  = BIT(24),
+       MEM_LIMIT_MASK  = MEM_LIMIT_DPE|MEM_LIMIT_RSE|MEM_LIMIT_RMA|
+                               MEM_LIMIT_RTA|MEM_LIMIT_STA|MEM_LIMIT_MDPE
+};
+
+/************************************************************
+ *     Link Configuration And Control Register, side A
+ ************************************************************/
+#define REG_LNK_CTRL_A 0xc4
+
+/************************************************************
+ *     Link Configuration And Control Register, side B
+ ************************************************************/
+#define REG_LNK_CTRL_B  0xc8
+
+enum lnk_ctrl_bits {
+       LNK_CTRL_CRCERR_A       = BIT(9),
+       LNK_CTRL_CRCERR_B       = BIT(8),
+       LNK_CTRL_CRCFEN         = BIT(1)
+};
+
+enum pcix_bridge_inst {
+       NORTH_A = 0,
+       NORTH_B = 1,
+       SOUTH_A = 2,
+       SOUTH_B = 3,
+       NO_BRIDGE = 4
+};
+
+struct amd8131_dev_info {
+       int devfn;
+       enum pcix_bridge_inst inst;
+       struct pci_dev *dev;
+       int edac_idx;   /* pci device index */
+       char *ctl_name;
+       struct edac_pci_ctl_info *edac_dev;
+};
+
+/*
+ * AMD8131 chipset has two pairs of PCIX Bridge and related IOAPIC
+ * Controler, and ATCA-6101 has two AMD8131 chipsets, so there are
+ * four PCIX Bridges on ATCA-6101 altogether.
+ *
+ * These PCIX Bridges share the same PCI Device ID and are all of
+ * Function Zero, they could be discrimated by their pci_dev->devfn.
+ * They share the same set of init/check/exit methods, and their
+ * private structures are collected in the devices[] array.
+ */
+struct amd8131_info {
+       u16 err_dev;    /* PCI Device ID for AMD8131 APIC*/
+       struct amd8131_dev_info *devices;
+       void (*init)(struct amd8131_dev_info *dev_info);
+       void (*exit)(struct amd8131_dev_info *dev_info);
+       void (*check)(struct edac_pci_ctl_info *edac_dev);
+};
+
+#endif /* _AMD8131_EDAC_H_ */
+
index 4b55ec607a88f622bf6e81e24aad7812a401d76a..28f2c3f959b5a3b0776c9993cf92f6bc9dcc4a96 100644 (file)
 #define edac_printk(level, prefix, fmt, arg...) \
        printk(level "EDAC " prefix ": " fmt, ##arg)
 
+#define edac_printk_verbose(level, prefix, fmt, arg...) \
+       printk(level "EDAC " prefix ": " "in %s, line at %d: " fmt,     \
+              __FILE__, __LINE__, ##arg)
+
 #define edac_mc_printk(mci, level, fmt, arg...) \
        printk(level "EDAC MC%d: " fmt, mci->mc_idx, ##arg)
 
 #ifdef CONFIG_EDAC_DEBUG
 extern int edac_debug_level;
 
+#ifndef CONFIG_EDAC_DEBUG_VERBOSE
 #define edac_debug_printk(level, fmt, arg...)                            \
        do {                                                             \
                if (level <= edac_debug_level)                           \
                        edac_printk(KERN_DEBUG, EDAC_DEBUG, fmt, ##arg); \
-       } while(0)
+       } while (0)
+#else  /* CONFIG_EDAC_DEBUG_VERBOSE */
+#define edac_debug_printk(level, fmt, arg...)                            \
+       do {                                                             \
+               if (level <= edac_debug_level)                           \
+                       edac_printk_verbose(KERN_DEBUG, EDAC_DEBUG, fmt, \
+                                           ##arg);                     \
+       } while (0)
+#endif
 
 #define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ )
 #define debugf1( ... ) edac_debug_printk(1, __VA_ARGS__ )
@@ -831,6 +844,7 @@ extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci);
 extern void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
                                unsigned long value);
 
+extern int edac_pci_alloc_index(void);
 extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx);
 extern struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev);
 
index 5d3c8083a40ebdee27dd34fb260038fcca01ad53..5b150aea703a3fb89b8fb0af40d3f29f5dd01a58 100644 (file)
@@ -30,6 +30,7 @@
 
 static DEFINE_MUTEX(edac_pci_ctls_mutex);
 static LIST_HEAD(edac_pci_list);
+static atomic_t pci_indexes = ATOMIC_INIT(0);
 
 /*
  * edac_pci_alloc_ctl_info
@@ -317,6 +318,19 @@ void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
 }
 EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period);
 
+/*
+ * edac_pci_alloc_index: Allocate a unique PCI index number
+ *
+ * Return:
+ *      allocated index number
+ *
+ */
+int edac_pci_alloc_index(void)
+{
+       return atomic_inc_return(&pci_indexes) - 1;
+}
+EXPORT_SYMBOL_GPL(edac_pci_alloc_index);
+
 /*
  * edac_pci_add_device: Insert the 'edac_dev' structure into the
  * edac_pci global list and create sysfs entries associated with
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c
new file mode 100644 (file)
index 0000000..11f2172
--- /dev/null
@@ -0,0 +1,1448 @@
+/*
+ * Copyright (c) 2008 Nuovation System Designs, LLC
+ *   Grant Erickson <gerickson@nuovations.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; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/edac.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/types.h>
+
+#include <asm/dcr.h>
+
+#include "edac_core.h"
+#include "ppc4xx_edac.h"
+
+/*
+ * This file implements a driver for monitoring and handling events
+ * associated with the IMB DDR2 ECC controller found in the AMCC/IBM
+ * 405EX[r], 440SP, 440SPe, 460EX, 460GT and 460SX.
+ *
+ * As realized in the 405EX[r], this controller features:
+ *
+ *   - Support for registered- and non-registered DDR1 and DDR2 memory.
+ *   - 32-bit or 16-bit memory interface with optional ECC.
+ *
+ *     o ECC support includes:
+ *
+ *       - 4-bit SEC/DED
+ *       - Aligned-nibble error detect
+ *       - Bypass mode
+ *
+ *   - Two (2) memory banks/ranks.
+ *   - Up to 1 GiB per bank/rank in 32-bit mode and up to 512 MiB per
+ *     bank/rank in 16-bit mode.
+ *
+ * As realized in the 440SP and 440SPe, this controller changes/adds:
+ *
+ *   - 64-bit or 32-bit memory interface with optional ECC.
+ *
+ *     o ECC support includes:
+ *
+ *       - 8-bit SEC/DED
+ *       - Aligned-nibble error detect
+ *       - Bypass mode
+ *
+ *   - Up to 4 GiB per bank/rank in 64-bit mode and up to 2 GiB
+ *     per bank/rank in 32-bit mode.
+ *
+ * As realized in the 460EX and 460GT, this controller changes/adds:
+ *
+ *   - 64-bit or 32-bit memory interface with optional ECC.
+ *
+ *     o ECC support includes:
+ *
+ *       - 8-bit SEC/DED
+ *       - Aligned-nibble error detect
+ *       - Bypass mode
+ *
+ *   - Four (4) memory banks/ranks.
+ *   - Up to 16 GiB per bank/rank in 64-bit mode and up to 8 GiB
+ *     per bank/rank in 32-bit mode.
+ *
+ * At present, this driver has ONLY been tested against the controller
+ * realization in the 405EX[r] on the AMCC Kilauea and Haleakala
+ * boards (256 MiB w/o ECC memory soldered onto the board) and a
+ * proprietary board based on those designs (128 MiB ECC memory, also
+ * soldered onto the board).
+ *
+ * Dynamic feature detection and handling needs to be added for the
+ * other realizations of this controller listed above.
+ *
+ * Eventually, this driver will likely be adapted to the above variant
+ * realizations of this controller as well as broken apart to handle
+ * the other known ECC-capable controllers prevalent in other 4xx
+ * processors:
+ *
+ *   - IBM SDRAM (405GP, 405CR and 405EP) "ibm,sdram-4xx"
+ *   - IBM DDR1 (440GP, 440GX, 440EP and 440GR) "ibm,sdram-4xx-ddr"
+ *   - Denali DDR1/DDR2 (440EPX and 440GRX) "denali,sdram-4xx-ddr2"
+ *
+ * For this controller, unfortunately, correctable errors report
+ * nothing more than the beat/cycle and byte/lane the correction
+ * occurred on and the check bit group that covered the error.
+ *
+ * In contrast, uncorrectable errors also report the failing address,
+ * the bus master and the transaction direction (i.e. read or write)
+ *
+ * Regardless of whether the error is a CE or a UE, we report the
+ * following pieces of information in the driver-unique message to the
+ * EDAC subsystem:
+ *
+ *   - Device tree path
+ *   - Bank(s)
+ *   - Check bit error group
+ *   - Beat(s)/lane(s)
+ */
+
+/* Preprocessor Definitions */
+
+#define EDAC_OPSTATE_INT_STR           "interrupt"
+#define EDAC_OPSTATE_POLL_STR          "polled"
+#define EDAC_OPSTATE_UNKNOWN_STR       "unknown"
+
+#define PPC4XX_EDAC_MODULE_NAME                "ppc4xx_edac"
+#define PPC4XX_EDAC_MODULE_REVISION    "v1.0.0 " __DATE__
+
+#define PPC4XX_EDAC_MESSAGE_SIZE       256
+
+/*
+ * Kernel logging without an EDAC instance
+ */
+#define ppc4xx_edac_printk(level, fmt, arg...) \
+       edac_printk(level, "PPC4xx MC", fmt, ##arg)
+
+/*
+ * Kernel logging with an EDAC instance
+ */
+#define ppc4xx_edac_mc_printk(level, mci, fmt, arg...) \
+       edac_mc_chipset_printk(mci, level, "PPC4xx", fmt, ##arg)
+
+/*
+ * Macros to convert bank configuration size enumerations into MiB and
+ * page values.
+ */
+#define SDRAM_MBCF_SZ_MiB_MIN          4
+#define SDRAM_MBCF_SZ_TO_MiB(n)                (SDRAM_MBCF_SZ_MiB_MIN \
+                                        << (SDRAM_MBCF_SZ_DECODE(n)))
+#define SDRAM_MBCF_SZ_TO_PAGES(n)      (SDRAM_MBCF_SZ_MiB_MIN \
+                                        << (20 - PAGE_SHIFT + \
+                                            SDRAM_MBCF_SZ_DECODE(n)))
+
+/*
+ * The ibm,sdram-4xx-ddr2 Device Control Registers (DCRs) are
+ * indirectly acccessed and have a base and length defined by the
+ * device tree. The base can be anything; however, we expect the
+ * length to be precisely two registers, the first for the address
+ * window and the second for the data window.
+ */
+#define SDRAM_DCR_RESOURCE_LEN         2
+#define SDRAM_DCR_ADDR_OFFSET          0
+#define SDRAM_DCR_DATA_OFFSET          1
+
+/*
+ * Device tree interrupt indices
+ */
+#define INTMAP_ECCDED_INDEX            0       /* Double-bit Error Detect */
+#define INTMAP_ECCSEC_INDEX            1       /* Single-bit Error Correct */
+
+/* Type Definitions */
+
+/*
+ * PPC4xx SDRAM memory controller private instance data
+ */
+struct ppc4xx_edac_pdata {
+       dcr_host_t dcr_host;    /* Indirect DCR address/data window mapping */
+       struct {
+               int sec;        /* Single-bit correctable error IRQ assigned */
+               int ded;        /* Double-bit detectable error IRQ assigned */
+       } irqs;
+};
+
+/*
+ * Various status data gathered and manipulated when checking and
+ * reporting ECC status.
+ */
+struct ppc4xx_ecc_status {
+       u32 ecces;
+       u32 besr;
+       u32 bearh;
+       u32 bearl;
+       u32 wmirq;
+};
+
+/* Function Prototypes */
+
+static int ppc4xx_edac_probe(struct of_device *device,
+                            const struct of_device_id *device_id);
+static int ppc4xx_edac_remove(struct of_device *device);
+
+/* Global Variables */
+
+/*
+ * Device tree node type and compatible tuples this driver can match
+ * on.
+ */
+static struct of_device_id ppc4xx_edac_match[] = {
+       {
+               .compatible     = "ibm,sdram-4xx-ddr2"
+       },
+       { }
+};
+
+static struct of_platform_driver ppc4xx_edac_driver = {
+       .match_table            = ppc4xx_edac_match,
+       .probe                  = ppc4xx_edac_probe,
+       .remove                 = ppc4xx_edac_remove,
+       .driver                 = {
+               .owner  = THIS_MODULE,
+               .name   = PPC4XX_EDAC_MODULE_NAME
+       }
+};
+
+/*
+ * TODO: The row and channel parameters likely need to be dynamically
+ * set based on the aforementioned variant controller realizations.
+ */
+static const unsigned ppc4xx_edac_nr_csrows = 2;
+static const unsigned ppc4xx_edac_nr_chans = 1;
+
+/*
+ * Strings associated with PLB master IDs capable of being posted in
+ * SDRAM_BESR or SDRAM_WMIRQ on uncorrectable ECC errors.
+ */
+static const char * const ppc4xx_plb_masters[9] = {
+       [SDRAM_PLB_M0ID_ICU]    = "ICU",
+       [SDRAM_PLB_M0ID_PCIE0]  = "PCI-E 0",
+       [SDRAM_PLB_M0ID_PCIE1]  = "PCI-E 1",
+       [SDRAM_PLB_M0ID_DMA]    = "DMA",
+       [SDRAM_PLB_M0ID_DCU]    = "DCU",
+       [SDRAM_PLB_M0ID_OPB]    = "OPB",
+       [SDRAM_PLB_M0ID_MAL]    = "MAL",
+       [SDRAM_PLB_M0ID_SEC]    = "SEC",
+       [SDRAM_PLB_M0ID_AHB]    = "AHB"
+};
+
+/**
+ * mfsdram - read and return controller register data
+ * @dcr_host: A pointer to the DCR mapping.
+ * @idcr_n: The indirect DCR register to read.
+ *
+ * This routine reads and returns the data associated with the
+ * controller's specified indirect DCR register.
+ *
+ * Returns the read data.
+ */
+static inline u32
+mfsdram(const dcr_host_t *dcr_host, unsigned int idcr_n)
+{
+       return __mfdcri(dcr_host->base + SDRAM_DCR_ADDR_OFFSET,
+                       dcr_host->base + SDRAM_DCR_DATA_OFFSET,
+                       idcr_n);
+}
+
+/**
+ * mtsdram - write controller register data
+ * @dcr_host: A pointer to the DCR mapping.
+ * @idcr_n: The indirect DCR register to write.
+ * @value: The data to write.
+ *
+ * This routine writes the provided data to the controller's specified
+ * indirect DCR register.
+ */
+static inline void
+mtsdram(const dcr_host_t *dcr_host, unsigned int idcr_n, u32 value)
+{
+       return __mtdcri(dcr_host->base + SDRAM_DCR_ADDR_OFFSET,
+                       dcr_host->base + SDRAM_DCR_DATA_OFFSET,
+                       idcr_n,
+                       value);
+}
+
+/**
+ * ppc4xx_edac_check_bank_error - check a bank for an ECC bank error
+ * @status: A pointer to the ECC status structure to check for an
+ *          ECC bank error.
+ * @bank: The bank to check for an ECC error.
+ *
+ * This routine determines whether the specified bank has an ECC
+ * error.
+ *
+ * Returns true if the specified bank has an ECC error; otherwise,
+ * false.
+ */
+static bool
+ppc4xx_edac_check_bank_error(const struct ppc4xx_ecc_status *status,
+                            unsigned int bank)
+{
+       switch (bank) {
+       case 0:
+               return status->ecces & SDRAM_ECCES_BK0ER;
+       case 1:
+               return status->ecces & SDRAM_ECCES_BK1ER;
+       default:
+               return false;
+       }
+}
+
+/**
+ * ppc4xx_edac_generate_bank_message - generate interpretted bank status message
+ * @mci: A pointer to the EDAC memory controller instance associated
+ *       with the bank message being generated.
+ * @status: A pointer to the ECC status structure to generate the
+ *          message from.
+ * @buffer: A pointer to the buffer in which to generate the
+ *          message.
+ * @size: The size, in bytes, of space available in buffer.
+ *
+ * This routine generates to the provided buffer the portion of the
+ * driver-unique report message associated with the ECCESS[BKNER]
+ * field of the specified ECC status.
+ *
+ * Returns the number of characters generated on success; otherwise, <
+ * 0 on error.
+ */
+static int
+ppc4xx_edac_generate_bank_message(const struct mem_ctl_info *mci,
+                                 const struct ppc4xx_ecc_status *status,
+                                 char *buffer,
+                                 size_t size)
+{
+       int n, total = 0;
+       unsigned int row, rows;
+
+       n = snprintf(buffer, size, "%s: Banks: ", mci->dev_name);
+
+       if (n < 0 || n >= size)
+               goto fail;
+
+       buffer += n;
+       size -= n;
+       total += n;
+
+       for (rows = 0, row = 0; row < mci->nr_csrows; row++) {
+               if (ppc4xx_edac_check_bank_error(status, row)) {
+                       n = snprintf(buffer, size, "%s%u",
+                                       (rows++ ? ", " : ""), row);
+
+                       if (n < 0 || n >= size)
+                               goto fail;
+
+                       buffer += n;
+                       size -= n;
+                       total += n;
+               }
+       }
+
+       n = snprintf(buffer, size, "%s; ", rows ? "" : "None");
+
+       if (n < 0 || n >= size)
+               goto fail;
+
+       buffer += n;
+       size -= n;
+       total += n;
+
+ fail:
+       return total;
+}
+
+/**
+ * ppc4xx_edac_generate_checkbit_message - generate interpretted checkbit message
+ * @mci: A pointer to the EDAC memory controller instance associated
+ *       with the checkbit message being generated.
+ * @status: A pointer to the ECC status structure to generate the
+ *          message from.
+ * @buffer: A pointer to the buffer in which to generate the
+ *          message.
+ * @size: The size, in bytes, of space available in buffer.
+ *
+ * This routine generates to the provided buffer the portion of the
+ * driver-unique report message associated with the ECCESS[CKBER]
+ * field of the specified ECC status.
+ *
+ * Returns the number of characters generated on success; otherwise, <
+ * 0 on error.
+ */
+static int
+ppc4xx_edac_generate_checkbit_message(const struct mem_ctl_info *mci,
+                                     const struct ppc4xx_ecc_status *status,
+                                     char *buffer,
+                                     size_t size)
+{
+       const struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
+       const char *ckber = NULL;
+
+       switch (status->ecces & SDRAM_ECCES_CKBER_MASK) {
+       case SDRAM_ECCES_CKBER_NONE:
+               ckber = "None";
+               break;
+       case SDRAM_ECCES_CKBER_32_ECC_0_3:
+               ckber = "ECC0:3";
+               break;
+       case SDRAM_ECCES_CKBER_32_ECC_4_8:
+               switch (mfsdram(&pdata->dcr_host, SDRAM_MCOPT1) &
+                       SDRAM_MCOPT1_WDTH_MASK) {
+               case SDRAM_MCOPT1_WDTH_16:
+                       ckber = "ECC0:3";
+                       break;
+               case SDRAM_MCOPT1_WDTH_32:
+                       ckber = "ECC4:8";
+                       break;
+               default:
+                       ckber = "Unknown";
+                       break;
+               }
+               break;
+       case SDRAM_ECCES_CKBER_32_ECC_0_8:
+               ckber = "ECC0:8";
+               break;
+       default:
+               ckber = "Unknown";
+               break;
+       }
+
+       return snprintf(buffer, size, "Checkbit Error: %s", ckber);
+}
+
+/**
+ * ppc4xx_edac_generate_lane_message - generate interpretted byte lane message
+ * @mci: A pointer to the EDAC memory controller instance associated
+ *       with the byte lane message being generated.
+ * @status: A pointer to the ECC status structure to generate the
+ *          message from.
+ * @buffer: A pointer to the buffer in which to generate the
+ *          message.
+ * @size: The size, in bytes, of space available in buffer.
+ *
+ * This routine generates to the provided buffer the portion of the
+ * driver-unique report message associated with the ECCESS[BNCE]
+ * field of the specified ECC status.
+ *
+ * Returns the number of characters generated on success; otherwise, <
+ * 0 on error.
+ */
+static int
+ppc4xx_edac_generate_lane_message(const struct mem_ctl_info *mci,
+                                 const struct ppc4xx_ecc_status *status,
+                                 char *buffer,
+                                 size_t size)
+{
+       int n, total = 0;
+       unsigned int lane, lanes;
+       const unsigned int first_lane = 0;
+       const unsigned int lane_count = 16;
+
+       n = snprintf(buffer, size, "; Byte Lane Errors: ");
+
+       if (n < 0 || n >= size)
+               goto fail;
+
+       buffer += n;
+       size -= n;
+       total += n;
+
+       for (lanes = 0, lane = first_lane; lane < lane_count; lane++) {
+               if ((status->ecces & SDRAM_ECCES_BNCE_ENCODE(lane)) != 0) {
+                       n = snprintf(buffer, size,
+                                    "%s%u",
+                                    (lanes++ ? ", " : ""), lane);
+
+                       if (n < 0 || n >= size)
+                               goto fail;
+
+                       buffer += n;
+                       size -= n;
+                       total += n;
+               }
+       }
+
+       n = snprintf(buffer, size, "%s; ", lanes ? "" : "None");
+
+       if (n < 0 || n >= size)
+               goto fail;
+
+       buffer += n;
+       size -= n;
+       total += n;
+
+ fail:
+       return total;
+}
+
+/**
+ * ppc4xx_edac_generate_ecc_message - generate interpretted ECC status message
+ * @mci: A pointer to the EDAC memory controller instance associated
+ *       with the ECCES message being generated.
+ * @status: A pointer to the ECC status structure to generate the
+ *          message from.
+ * @buffer: A pointer to the buffer in which to generate the
+ *          message.
+ * @size: The size, in bytes, of space available in buffer.
+ *
+ * This routine generates to the provided buffer the portion of the
+ * driver-unique report message associated with the ECCESS register of
+ * the specified ECC status.
+ *
+ * Returns the number of characters generated on success; otherwise, <
+ * 0 on error.
+ */
+static int
+ppc4xx_edac_generate_ecc_message(const struct mem_ctl_info *mci,
+                                const struct ppc4xx_ecc_status *status,
+                                char *buffer,
+                                size_t size)
+{
+       int n, total = 0;
+
+       n = ppc4xx_edac_generate_bank_message(mci, status, buffer, size);
+
+       if (n < 0 || n >= size)
+               goto fail;
+
+       buffer += n;
+       size -= n;
+       total += n;
+
+       n = ppc4xx_edac_generate_checkbit_message(mci, status, buffer, size);
+
+       if (n < 0 || n >= size)
+               goto fail;
+
+       buffer += n;
+       size -= n;
+       total += n;
+
+       n = ppc4xx_edac_generate_lane_message(mci, status, buffer, size);
+
+       if (n < 0 || n >= size)
+               goto fail;
+
+       buffer += n;
+       size -= n;
+       total += n;
+
+ fail:
+       return total;
+}
+
+/**
+ * ppc4xx_edac_generate_plb_message - generate interpretted PLB status message
+ * @mci: A pointer to the EDAC memory controller instance associated
+ *       with the PLB message being generated.
+ * @status: A pointer to the ECC status structure to generate the
+ *          message from.
+ * @buffer: A pointer to the buffer in which to generate the
+ *          message.
+ * @size: The size, in bytes, of space available in buffer.
+ *
+ * This routine generates to the provided buffer the portion of the
+ * driver-unique report message associated with the PLB-related BESR
+ * and/or WMIRQ registers of the specified ECC status.
+ *
+ * Returns the number of characters generated on success; otherwise, <
+ * 0 on error.
+ */
+static int
+ppc4xx_edac_generate_plb_message(const struct mem_ctl_info *mci,
+                                const struct ppc4xx_ecc_status *status,
+                                char *buffer,
+                                size_t size)
+{
+       unsigned int master;
+       bool read;
+
+       if ((status->besr & SDRAM_BESR_MASK) == 0)
+               return 0;
+
+       if ((status->besr & SDRAM_BESR_M0ET_MASK) == SDRAM_BESR_M0ET_NONE)
+               return 0;
+
+       read = ((status->besr & SDRAM_BESR_M0RW_MASK) == SDRAM_BESR_M0RW_READ);
+
+       master = SDRAM_BESR_M0ID_DECODE(status->besr);
+
+       return snprintf(buffer, size,
+                       "%s error w/ PLB master %u \"%s\"; ",
+                       (read ? "Read" : "Write"),
+                       master,
+                       (((master >= SDRAM_PLB_M0ID_FIRST) &&
+                         (master <= SDRAM_PLB_M0ID_LAST)) ?
+                        ppc4xx_plb_masters[master] : "UNKNOWN"));
+}
+
+/**
+ * ppc4xx_edac_generate_message - generate interpretted status message
+ * @mci: A pointer to the EDAC memory controller instance associated
+ *       with the driver-unique message being generated.
+ * @status: A pointer to the ECC status structure to generate the
+ *          message from.
+ * @buffer: A pointer to the buffer in which to generate the
+ *          message.
+ * @size: The size, in bytes, of space available in buffer.
+ *
+ * This routine generates to the provided buffer the driver-unique
+ * EDAC report message from the specified ECC status.
+ */
+static void
+ppc4xx_edac_generate_message(const struct mem_ctl_info *mci,
+                            const struct ppc4xx_ecc_status *status,
+                            char *buffer,
+                            size_t size)
+{
+       int n;
+
+       if (buffer == NULL || size == 0)
+               return;
+
+       n = ppc4xx_edac_generate_ecc_message(mci, status, buffer, size);
+
+       if (n < 0 || n >= size)
+               return;
+
+       buffer += n;
+       size -= n;
+
+       ppc4xx_edac_generate_plb_message(mci, status, buffer, size);
+}
+
+#ifdef DEBUG
+/**
+ * ppc4xx_ecc_dump_status - dump controller ECC status registers
+ * @mci: A pointer to the EDAC memory controller instance
+ *       associated with the status being dumped.
+ * @status: A pointer to the ECC status structure to generate the
+ *          dump from.
+ *
+ * This routine dumps to the kernel log buffer the raw and
+ * interpretted specified ECC status.
+ */
+static void
+ppc4xx_ecc_dump_status(const struct mem_ctl_info *mci,
+                      const struct ppc4xx_ecc_status *status)
+{
+       char message[PPC4XX_EDAC_MESSAGE_SIZE];
+
+       ppc4xx_edac_generate_message(mci, status, message, sizeof(message));
+
+       ppc4xx_edac_mc_printk(KERN_INFO, mci,
+                             "\n"
+                             "\tECCES: 0x%08x\n"
+                             "\tWMIRQ: 0x%08x\n"
+                             "\tBESR:  0x%08x\n"
+                             "\tBEAR:  0x%08x%08x\n"
+                             "\t%s\n",
+                             status->ecces,
+                             status->wmirq,
+                             status->besr,
+                             status->bearh,
+                             status->bearl,
+                             message);
+}
+#endif /* DEBUG */
+
+/**
+ * ppc4xx_ecc_get_status - get controller ECC status
+ * @mci: A pointer to the EDAC memory controller instance
+ *       associated with the status being retrieved.
+ * @status: A pointer to the ECC status structure to populate the
+ *          ECC status with.
+ *
+ * This routine reads and masks, as appropriate, all the relevant
+ * status registers that deal with ibm,sdram-4xx-ddr2 ECC errors.
+ * While we read all of them, for correctable errors, we only expect
+ * to deal with ECCES. For uncorrectable errors, we expect to deal
+ * with all of them.
+ */
+static void
+ppc4xx_ecc_get_status(const struct mem_ctl_info *mci,
+                     struct ppc4xx_ecc_status *status)
+{
+       const struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
+       const dcr_host_t *dcr_host = &pdata->dcr_host;
+
+       status->ecces = mfsdram(dcr_host, SDRAM_ECCES) & SDRAM_ECCES_MASK;
+       status->wmirq = mfsdram(dcr_host, SDRAM_WMIRQ) & SDRAM_WMIRQ_MASK;
+       status->besr  = mfsdram(dcr_host, SDRAM_BESR)  & SDRAM_BESR_MASK;
+       status->bearl = mfsdram(dcr_host, SDRAM_BEARL);
+       status->bearh = mfsdram(dcr_host, SDRAM_BEARH);
+}
+
+/**
+ * ppc4xx_ecc_clear_status - clear controller ECC status
+ * @mci: A pointer to the EDAC memory controller instance
+ *       associated with the status being cleared.
+ * @status: A pointer to the ECC status structure containing the
+ *          values to write to clear the ECC status.
+ *
+ * This routine clears--by writing the masked (as appropriate) status
+ * values back to--the status registers that deal with
+ * ibm,sdram-4xx-ddr2 ECC errors.
+ */
+static void
+ppc4xx_ecc_clear_status(const struct mem_ctl_info *mci,
+                       const struct ppc4xx_ecc_status *status)
+{
+       const struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
+       const dcr_host_t *dcr_host = &pdata->dcr_host;
+
+       mtsdram(dcr_host, SDRAM_ECCES,  status->ecces & SDRAM_ECCES_MASK);
+       mtsdram(dcr_host, SDRAM_WMIRQ,  status->wmirq & SDRAM_WMIRQ_MASK);
+       mtsdram(dcr_host, SDRAM_BESR,   status->besr & SDRAM_BESR_MASK);
+       mtsdram(dcr_host, SDRAM_BEARL,  0);
+       mtsdram(dcr_host, SDRAM_BEARH,  0);
+}
+
+/**
+ * ppc4xx_edac_handle_ce - handle controller correctable ECC error (CE)
+ * @mci: A pointer to the EDAC memory controller instance
+ *       associated with the correctable error being handled and reported.
+ * @status: A pointer to the ECC status structure associated with
+ *          the correctable error being handled and reported.
+ *
+ * This routine handles an ibm,sdram-4xx-ddr2 controller ECC
+ * correctable error. Per the aforementioned discussion, there's not
+ * enough status available to use the full EDAC correctable error
+ * interface, so we just pass driver-unique message to the "no info"
+ * interface.
+ */
+static void
+ppc4xx_edac_handle_ce(struct mem_ctl_info *mci,
+                     const struct ppc4xx_ecc_status *status)
+{
+       int row;
+       char message[PPC4XX_EDAC_MESSAGE_SIZE];
+
+       ppc4xx_edac_generate_message(mci, status, message, sizeof(message));
+
+       for (row = 0; row < mci->nr_csrows; row++)
+               if (ppc4xx_edac_check_bank_error(status, row))
+                       edac_mc_handle_ce_no_info(mci, message);
+}
+
+/**
+ * ppc4xx_edac_handle_ue - handle controller uncorrectable ECC error (UE)
+ * @mci: A pointer to the EDAC memory controller instance
+ *       associated with the uncorrectable error being handled and
+ *       reported.
+ * @status: A pointer to the ECC status structure associated with
+ *          the uncorrectable error being handled and reported.
+ *
+ * This routine handles an ibm,sdram-4xx-ddr2 controller ECC
+ * uncorrectable error.
+ */
+static void
+ppc4xx_edac_handle_ue(struct mem_ctl_info *mci,
+                     const struct ppc4xx_ecc_status *status)
+{
+       const u64 bear = ((u64)status->bearh << 32 | status->bearl);
+       const unsigned long page = bear >> PAGE_SHIFT;
+       const unsigned long offset = bear & ~PAGE_MASK;
+       int row;
+       char message[PPC4XX_EDAC_MESSAGE_SIZE];
+
+       ppc4xx_edac_generate_message(mci, status, message, sizeof(message));
+
+       for (row = 0; row < mci->nr_csrows; row++)
+               if (ppc4xx_edac_check_bank_error(status, row))
+                       edac_mc_handle_ue(mci, page, offset, row, message);
+}
+
+/**
+ * ppc4xx_edac_check - check controller for ECC errors
+ * @mci: A pointer to the EDAC memory controller instance
+ *       associated with the ibm,sdram-4xx-ddr2 controller being
+ *       checked.
+ *
+ * This routine is used to check and post ECC errors and is called by
+ * both the EDAC polling thread and this driver's CE and UE interrupt
+ * handler.
+ */
+static void
+ppc4xx_edac_check(struct mem_ctl_info *mci)
+{
+#ifdef DEBUG
+       static unsigned int count;
+#endif
+       struct ppc4xx_ecc_status status;
+
+       ppc4xx_ecc_get_status(mci, &status);
+
+#ifdef DEBUG
+       if (count++ % 30 == 0)
+               ppc4xx_ecc_dump_status(mci, &status);
+#endif
+
+       if (status.ecces & SDRAM_ECCES_UE)
+               ppc4xx_edac_handle_ue(mci, &status);
+
+       if (status.ecces & SDRAM_ECCES_CE)
+               ppc4xx_edac_handle_ce(mci, &status);
+
+       ppc4xx_ecc_clear_status(mci, &status);
+}
+
+/**
+ * ppc4xx_edac_isr - SEC (CE) and DED (UE) interrupt service routine
+ * @irq:    The virtual interrupt number being serviced.
+ * @dev_id: A pointer to the EDAC memory controller instance
+ *          associated with the interrupt being handled.
+ *
+ * This routine implements the interrupt handler for both correctable
+ * (CE) and uncorrectable (UE) ECC errors for the ibm,sdram-4xx-ddr2
+ * controller. It simply calls through to the same routine used during
+ * polling to check, report and clear the ECC status.
+ *
+ * Unconditionally returns IRQ_HANDLED.
+ */
+static irqreturn_t
+ppc4xx_edac_isr(int irq, void *dev_id)
+{
+       struct mem_ctl_info *mci = dev_id;
+
+       ppc4xx_edac_check(mci);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * ppc4xx_edac_get_dtype - return the controller memory width
+ * @mcopt1: The 32-bit Memory Controller Option 1 register value
+ *          currently set for the controller, from which the width
+ *          is derived.
+ *
+ * This routine returns the EDAC device type width appropriate for the
+ * current controller configuration.
+ *
+ * TODO: This needs to be conditioned dynamically through feature
+ * flags or some such when other controller variants are supported as
+ * the 405EX[r] is 16-/32-bit and the others are 32-/64-bit with the
+ * 16- and 64-bit field definition/value/enumeration (b1) overloaded
+ * among them.
+ *
+ * Returns a device type width enumeration.
+ */
+static enum dev_type __devinit
+ppc4xx_edac_get_dtype(u32 mcopt1)
+{
+       switch (mcopt1 & SDRAM_MCOPT1_WDTH_MASK) {
+       case SDRAM_MCOPT1_WDTH_16:
+               return DEV_X2;
+       case SDRAM_MCOPT1_WDTH_32:
+               return DEV_X4;
+       default:
+               return DEV_UNKNOWN;
+       }
+}
+
+/**
+ * ppc4xx_edac_get_mtype - return controller memory type
+ * @mcopt1: The 32-bit Memory Controller Option 1 register value
+ *          currently set for the controller, from which the memory type
+ *          is derived.
+ *
+ * This routine returns the EDAC memory type appropriate for the
+ * current controller configuration.
+ *
+ * Returns a memory type enumeration.
+ */
+static enum mem_type __devinit
+ppc4xx_edac_get_mtype(u32 mcopt1)
+{
+       bool rden = ((mcopt1 & SDRAM_MCOPT1_RDEN_MASK) == SDRAM_MCOPT1_RDEN);
+
+       switch (mcopt1 & SDRAM_MCOPT1_DDR_TYPE_MASK) {
+       case SDRAM_MCOPT1_DDR2_TYPE:
+               return rden ? MEM_RDDR2 : MEM_DDR2;
+       case SDRAM_MCOPT1_DDR1_TYPE:
+               return rden ? MEM_RDDR : MEM_DDR;
+       default:
+               return MEM_UNKNOWN;
+       }
+}
+
+/**
+ * ppc4xx_edac_init_csrows - intialize driver instance rows
+ * @mci: A pointer to the EDAC memory controller instance
+ *       associated with the ibm,sdram-4xx-ddr2 controller for which
+ *       the csrows (i.e. banks/ranks) are being initialized.
+ * @mcopt1: The 32-bit Memory Controller Option 1 register value
+ *          currently set for the controller, from which bank width
+ *          and memory typ information is derived.
+ *
+ * This routine intializes the virtual "chip select rows" associated
+ * with the EDAC memory controller instance. An ibm,sdram-4xx-ddr2
+ * controller bank/rank is mapped to a row.
+ *
+ * Returns 0 if OK; otherwise, -EINVAL if the memory bank size
+ * configuration cannot be determined.
+ */
+static int __devinit
+ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1)
+{
+       const struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
+       int status = 0;
+       enum mem_type mtype;
+       enum dev_type dtype;
+       enum edac_type edac_mode;
+       int row;
+       u32 mbxcf, size;
+       static u32 ppc4xx_last_page;
+
+       /* Establish the memory type and width */
+
+       mtype = ppc4xx_edac_get_mtype(mcopt1);
+       dtype = ppc4xx_edac_get_dtype(mcopt1);
+
+       /* Establish EDAC mode */
+
+       if (mci->edac_cap & EDAC_FLAG_SECDED)
+               edac_mode = EDAC_SECDED;
+       else if (mci->edac_cap & EDAC_FLAG_EC)
+               edac_mode = EDAC_EC;
+       else
+               edac_mode = EDAC_NONE;
+
+       /*
+        * Initialize each chip select row structure which correspond
+        * 1:1 with a controller bank/rank.
+        */
+
+       for (row = 0; row < mci->nr_csrows; row++) {
+               struct csrow_info *csi = &mci->csrows[row];
+
+               /*
+                * Get the configuration settings for this
+                * row/bank/rank and skip disabled banks.
+                */
+
+               mbxcf = mfsdram(&pdata->dcr_host, SDRAM_MBXCF(row));
+
+               if ((mbxcf & SDRAM_MBCF_BE_MASK) != SDRAM_MBCF_BE_ENABLE)
+                       continue;
+
+               /* Map the bank configuration size setting to pages. */
+
+               size = mbxcf & SDRAM_MBCF_SZ_MASK;
+
+               switch (size) {
+               case SDRAM_MBCF_SZ_4MB:
+               case SDRAM_MBCF_SZ_8MB:
+               case SDRAM_MBCF_SZ_16MB:
+               case SDRAM_MBCF_SZ_32MB:
+               case SDRAM_MBCF_SZ_64MB:
+               case SDRAM_MBCF_SZ_128MB:
+               case SDRAM_MBCF_SZ_256MB:
+               case SDRAM_MBCF_SZ_512MB:
+               case SDRAM_MBCF_SZ_1GB:
+               case SDRAM_MBCF_SZ_2GB:
+               case SDRAM_MBCF_SZ_4GB:
+               case SDRAM_MBCF_SZ_8GB:
+                       csi->nr_pages = SDRAM_MBCF_SZ_TO_PAGES(size);
+                       break;
+               default:
+                       ppc4xx_edac_mc_printk(KERN_ERR, mci,
+                                             "Unrecognized memory bank %d "
+                                             "size 0x%08x\n",
+                                             row, SDRAM_MBCF_SZ_DECODE(size));
+                       status = -EINVAL;
+                       goto done;
+               }
+
+               csi->first_page = ppc4xx_last_page;
+               csi->last_page  = csi->first_page + csi->nr_pages - 1;
+               csi->page_mask  = 0;
+
+               /*
+                * It's unclear exactly what grain should be set to
+                * here. The SDRAM_ECCES register allows resolution of
+                * an error down to a nibble which would potentially
+                * argue for a grain of '1' byte, even though we only
+                * know the associated address for uncorrectable
+                * errors. This value is not used at present for
+                * anything other than error reporting so getting it
+                * wrong should be of little consequence. Other
+                * possible values would be the PLB width (16), the
+                * page size (PAGE_SIZE) or the memory width (2 or 4).
+                */
+
+               csi->grain      = 1;
+
+               csi->mtype      = mtype;
+               csi->dtype      = dtype;
+
+               csi->edac_mode  = edac_mode;
+
+               ppc4xx_last_page += csi->nr_pages;
+       }
+
+ done:
+       return status;
+}
+
+/**
+ * ppc4xx_edac_mc_init - intialize driver instance
+ * @mci: A pointer to the EDAC memory controller instance being
+ *       initialized.
+ * @op: A pointer to the OpenFirmware device tree node associated
+ *      with the controller this EDAC instance is bound to.
+ * @match: A pointer to the OpenFirmware device tree match
+ *         information associated with the controller this EDAC instance
+ *         is bound to.
+ * @dcr_host: A pointer to the DCR data containing the DCR mapping
+ *            for this controller instance.
+ * @mcopt1: The 32-bit Memory Controller Option 1 register value
+ *          currently set for the controller, from which ECC capabilities
+ *          and scrub mode are derived.
+ *
+ * This routine performs initialization of the EDAC memory controller
+ * instance and related driver-private data associated with the
+ * ibm,sdram-4xx-ddr2 memory controller the instance is bound to.
+ *
+ * Returns 0 if OK; otherwise, < 0 on error.
+ */
+static int __devinit
+ppc4xx_edac_mc_init(struct mem_ctl_info *mci,
+                   struct of_device *op,
+                   const struct of_device_id *match,
+                   const dcr_host_t *dcr_host,
+                   u32 mcopt1)
+{
+       int status = 0;
+       const u32 memcheck = (mcopt1 & SDRAM_MCOPT1_MCHK_MASK);
+       struct ppc4xx_edac_pdata *pdata = NULL;
+       const struct device_node *np = op->node;
+
+       if (match == NULL)
+               return -EINVAL;
+
+       /* Initial driver pointers and private data */
+
+       mci->dev                = &op->dev;
+
+       dev_set_drvdata(mci->dev, mci);
+
+       pdata                   = mci->pvt_info;
+
+       pdata->dcr_host         = *dcr_host;
+       pdata->irqs.sec         = NO_IRQ;
+       pdata->irqs.ded         = NO_IRQ;
+
+       /* Initialize controller capabilities and configuration */
+
+       mci->mtype_cap          = (MEM_FLAG_DDR | MEM_FLAG_RDDR |
+                                  MEM_FLAG_DDR2 | MEM_FLAG_RDDR2);
+
+       mci->edac_ctl_cap       = (EDAC_FLAG_NONE |
+                                  EDAC_FLAG_EC |
+                                  EDAC_FLAG_SECDED);
+
+       mci->scrub_cap          = SCRUB_NONE;
+       mci->scrub_mode         = SCRUB_NONE;
+
+       /*
+        * Update the actual capabilites based on the MCOPT1[MCHK]
+        * settings. Scrubbing is only useful if reporting is enabled.
+        */
+
+       switch (memcheck) {
+       case SDRAM_MCOPT1_MCHK_CHK:
+               mci->edac_cap   = EDAC_FLAG_EC;
+               break;
+       case SDRAM_MCOPT1_MCHK_CHK_REP:
+               mci->edac_cap   = (EDAC_FLAG_EC | EDAC_FLAG_SECDED);
+               mci->scrub_mode = SCRUB_SW_SRC;
+               break;
+       default:
+               mci->edac_cap   = EDAC_FLAG_NONE;
+               break;
+       }
+
+       /* Initialize strings */
+
+       mci->mod_name           = PPC4XX_EDAC_MODULE_NAME;
+       mci->mod_ver            = PPC4XX_EDAC_MODULE_REVISION;
+       mci->ctl_name           = match->compatible,
+       mci->dev_name           = np->full_name;
+
+       /* Initialize callbacks */
+
+       mci->edac_check         = ppc4xx_edac_check;
+       mci->ctl_page_to_phys   = NULL;
+
+       /* Initialize chip select rows */
+
+       status = ppc4xx_edac_init_csrows(mci, mcopt1);
+
+       if (status)
+               ppc4xx_edac_mc_printk(KERN_ERR, mci,
+                                     "Failed to initialize rows!\n");
+
+       return status;
+}
+
+/**
+ * ppc4xx_edac_register_irq - setup and register controller interrupts
+ * @op: A pointer to the OpenFirmware device tree node associated
+ *      with the controller this EDAC instance is bound to.
+ * @mci: A pointer to the EDAC memory controller instance
+ *       associated with the ibm,sdram-4xx-ddr2 controller for which
+ *       interrupts are being registered.
+ *
+ * This routine parses the correctable (CE) and uncorrectable error (UE)
+ * interrupts from the device tree node and maps and assigns them to
+ * the associated EDAC memory controller instance.
+ *
+ * Returns 0 if OK; otherwise, -ENODEV if the interrupts could not be
+ * mapped and assigned.
+ */
+static int __devinit
+ppc4xx_edac_register_irq(struct of_device *op, struct mem_ctl_info *mci)
+{
+       int status = 0;
+       int ded_irq, sec_irq;
+       struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
+       struct device_node *np = op->node;
+
+       ded_irq = irq_of_parse_and_map(np, INTMAP_ECCDED_INDEX);
+       sec_irq = irq_of_parse_and_map(np, INTMAP_ECCSEC_INDEX);
+
+       if (ded_irq == NO_IRQ || sec_irq == NO_IRQ) {
+               ppc4xx_edac_mc_printk(KERN_ERR, mci,
+                                     "Unable to map interrupts.\n");
+               status = -ENODEV;
+               goto fail;
+       }
+
+       status = request_irq(ded_irq,
+                            ppc4xx_edac_isr,
+                            IRQF_DISABLED,
+                            "[EDAC] MC ECCDED",
+                            mci);
+
+       if (status < 0) {
+               ppc4xx_edac_mc_printk(KERN_ERR, mci,
+                                     "Unable to request irq %d for ECC DED",
+                                     ded_irq);
+               status = -ENODEV;
+               goto fail1;
+       }
+
+       status = request_irq(sec_irq,
+                            ppc4xx_edac_isr,
+                            IRQF_DISABLED,
+                            "[EDAC] MC ECCSEC",
+                            mci);
+
+       if (status < 0) {
+               ppc4xx_edac_mc_printk(KERN_ERR, mci,
+                                     "Unable to request irq %d for ECC SEC",
+                                     sec_irq);
+               status = -ENODEV;
+               goto fail2;
+       }
+
+       ppc4xx_edac_mc_printk(KERN_INFO, mci, "ECCDED irq is %d\n", ded_irq);
+       ppc4xx_edac_mc_printk(KERN_INFO, mci, "ECCSEC irq is %d\n", sec_irq);
+
+       pdata->irqs.ded = ded_irq;
+       pdata->irqs.sec = sec_irq;
+
+       return 0;
+
+ fail2:
+       free_irq(sec_irq, mci);
+
+ fail1:
+       free_irq(ded_irq, mci);
+
+ fail:
+       return status;
+}
+
+/**
+ * ppc4xx_edac_map_dcrs - locate and map controller registers
+ * @np: A pointer to the device tree node containing the DCR
+ *      resources to map.
+ * @dcr_host: A pointer to the DCR data to populate with the
+ *            DCR mapping.
+ *
+ * This routine attempts to locate in the device tree and map the DCR
+ * register resources associated with the controller's indirect DCR
+ * address and data windows.
+ *
+ * Returns 0 if the DCRs were successfully mapped; otherwise, < 0 on
+ * error.
+ */
+static int __devinit
+ppc4xx_edac_map_dcrs(const struct device_node *np, dcr_host_t *dcr_host)
+{
+       unsigned int dcr_base, dcr_len;
+
+       if (np == NULL || dcr_host == NULL)
+               return -EINVAL;
+
+       /* Get the DCR resource extent and sanity check the values. */
+
+       dcr_base = dcr_resource_start(np, 0);
+       dcr_len = dcr_resource_len(np, 0);
+
+       if (dcr_base == 0 || dcr_len == 0) {
+               ppc4xx_edac_printk(KERN_ERR,
+                                  "Failed to obtain DCR property.\n");
+               return -ENODEV;
+       }
+
+       if (dcr_len != SDRAM_DCR_RESOURCE_LEN) {
+               ppc4xx_edac_printk(KERN_ERR,
+                                  "Unexpected DCR length %d, expected %d.\n",
+                                  dcr_len, SDRAM_DCR_RESOURCE_LEN);
+               return -ENODEV;
+       }
+
+       /*  Attempt to map the DCR extent. */
+
+       *dcr_host = dcr_map(np, dcr_base, dcr_len);
+
+       if (!DCR_MAP_OK(*dcr_host)) {
+               ppc4xx_edac_printk(KERN_INFO, "Failed to map DCRs.\n");
+                   return -ENODEV;
+       }
+
+       return 0;
+}
+
+/**
+ * ppc4xx_edac_probe - check controller and bind driver
+ * @op: A pointer to the OpenFirmware device tree node associated
+ *      with the controller being probed for driver binding.
+ * @match: A pointer to the OpenFirmware device tree match
+ *         information associated with the controller being probed
+ *         for driver binding.
+ *
+ * This routine probes a specific ibm,sdram-4xx-ddr2 controller
+ * instance for binding with the driver.
+ *
+ * Returns 0 if the controller instance was successfully bound to the
+ * driver; otherwise, < 0 on error.
+ */
+static int __devinit
+ppc4xx_edac_probe(struct of_device *op, const struct of_device_id *match)
+{
+       int status = 0;
+       u32 mcopt1, memcheck;
+       dcr_host_t dcr_host;
+       const struct device_node *np = op->node;
+       struct mem_ctl_info *mci = NULL;
+       static int ppc4xx_edac_instance;
+
+       /*
+        * At this point, we only support the controller realized on
+        * the AMCC PPC 405EX[r]. Reject anything else.
+        */
+
+       if (!of_device_is_compatible(np, "ibm,sdram-405ex") &&
+           !of_device_is_compatible(np, "ibm,sdram-405exr")) {
+               ppc4xx_edac_printk(KERN_NOTICE,
+                                  "Only the PPC405EX[r] is supported.\n");
+               return -ENODEV;
+       }
+
+       /*
+        * Next, get the DCR property and attempt to map it so that we
+        * can probe the controller.
+        */
+
+       status = ppc4xx_edac_map_dcrs(np, &dcr_host);
+
+       if (status)
+               return status;
+
+       /*
+        * First determine whether ECC is enabled at all. If not,
+        * there is no useful checking or monitoring that can be done
+        * for this controller.
+        */
+
+       mcopt1 = mfsdram(&dcr_host, SDRAM_MCOPT1);
+       memcheck = (mcopt1 & SDRAM_MCOPT1_MCHK_MASK);
+
+       if (memcheck == SDRAM_MCOPT1_MCHK_NON) {
+               ppc4xx_edac_printk(KERN_INFO, "%s: No ECC memory detected or "
+                                  "ECC is disabled.\n", np->full_name);
+               status = -ENODEV;
+               goto done;
+       }
+
+       /*
+        * At this point, we know ECC is enabled, allocate an EDAC
+        * controller instance and perform the appropriate
+        * initialization.
+        */
+
+       mci = edac_mc_alloc(sizeof(struct ppc4xx_edac_pdata),
+                           ppc4xx_edac_nr_csrows,
+                           ppc4xx_edac_nr_chans,
+                           ppc4xx_edac_instance);
+
+       if (mci == NULL) {
+               ppc4xx_edac_printk(KERN_ERR, "%s: "
+                                  "Failed to allocate EDAC MC instance!\n",
+                                  np->full_name);
+               status = -ENOMEM;
+               goto done;
+       }
+
+       status = ppc4xx_edac_mc_init(mci, op, match, &dcr_host, mcopt1);
+
+       if (status) {
+               ppc4xx_edac_mc_printk(KERN_ERR, mci,
+                                     "Failed to initialize instance!\n");
+               goto fail;
+       }
+
+       /*
+        * We have a valid, initialized EDAC instance bound to the
+        * controller. Attempt to register it with the EDAC subsystem
+        * and, if necessary, register interrupts.
+        */
+
+       if (edac_mc_add_mc(mci)) {
+               ppc4xx_edac_mc_printk(KERN_ERR, mci,
+                                     "Failed to add instance!\n");
+               status = -ENODEV;
+               goto fail;
+       }
+
+       if (edac_op_state == EDAC_OPSTATE_INT) {
+               status = ppc4xx_edac_register_irq(op, mci);
+
+               if (status)
+                       goto fail1;
+       }
+
+       ppc4xx_edac_instance++;
+
+       return 0;
+
+ fail1:
+       edac_mc_del_mc(mci->dev);
+
+ fail:
+       edac_mc_free(mci);
+
+ done:
+       return status;
+}
+
+/**
+ * ppc4xx_edac_remove - unbind driver from controller
+ * @op: A pointer to the OpenFirmware device tree node associated
+ *      with the controller this EDAC instance is to be unbound/removed
+ *      from.
+ *
+ * This routine unbinds the EDAC memory controller instance associated
+ * with the specified ibm,sdram-4xx-ddr2 controller described by the
+ * OpenFirmware device tree node passed as a parameter.
+ *
+ * Unconditionally returns 0.
+ */
+static int
+ppc4xx_edac_remove(struct of_device *op)
+{
+       struct mem_ctl_info *mci = dev_get_drvdata(&op->dev);
+       struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
+
+       if (edac_op_state == EDAC_OPSTATE_INT) {
+               free_irq(pdata->irqs.sec, mci);
+               free_irq(pdata->irqs.ded, mci);
+       }
+
+       dcr_unmap(pdata->dcr_host, SDRAM_DCR_RESOURCE_LEN);
+
+       edac_mc_del_mc(mci->dev);
+       edac_mc_free(mci);
+
+       return 0;
+}
+
+/**
+ * ppc4xx_edac_opstate_init - initialize EDAC reporting method
+ *
+ * This routine ensures that the EDAC memory controller reporting
+ * method is mapped to a sane value as the EDAC core defines the value
+ * to EDAC_OPSTATE_INVAL by default. We don't call the global
+ * opstate_init as that defaults to polling and we want interrupt as
+ * the default.
+ */
+static inline void __init
+ppc4xx_edac_opstate_init(void)
+{
+       switch (edac_op_state) {
+       case EDAC_OPSTATE_POLL:
+       case EDAC_OPSTATE_INT:
+               break;
+       default:
+               edac_op_state = EDAC_OPSTATE_INT;
+               break;
+       }
+
+       ppc4xx_edac_printk(KERN_INFO, "Reporting type: %s\n",
+                          ((edac_op_state == EDAC_OPSTATE_POLL) ?
+                           EDAC_OPSTATE_POLL_STR :
+                           ((edac_op_state == EDAC_OPSTATE_INT) ?
+                            EDAC_OPSTATE_INT_STR :
+                            EDAC_OPSTATE_UNKNOWN_STR)));
+}
+
+/**
+ * ppc4xx_edac_init - driver/module insertion entry point
+ *
+ * This routine is the driver/module insertion entry point. It
+ * initializes the EDAC memory controller reporting state and
+ * registers the driver as an OpenFirmware device tree platform
+ * driver.
+ */
+static int __init
+ppc4xx_edac_init(void)
+{
+       ppc4xx_edac_printk(KERN_INFO, PPC4XX_EDAC_MODULE_REVISION "\n");
+
+       ppc4xx_edac_opstate_init();
+
+       return of_register_platform_driver(&ppc4xx_edac_driver);
+}
+
+/**
+ * ppc4xx_edac_exit - driver/module removal entry point
+ *
+ * This routine is the driver/module removal entry point. It
+ * unregisters the driver as an OpenFirmware device tree platform
+ * driver.
+ */
+static void __exit
+ppc4xx_edac_exit(void)
+{
+       of_unregister_platform_driver(&ppc4xx_edac_driver);
+}
+
+module_init(ppc4xx_edac_init);
+module_exit(ppc4xx_edac_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Grant Erickson <gerickson@nuovations.com>");
+MODULE_DESCRIPTION("EDAC MC Driver for the PPC4xx IBM DDR2 Memory Controller");
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting State: "
+                "0=" EDAC_OPSTATE_POLL_STR ", 2=" EDAC_OPSTATE_INT_STR);
diff --git a/drivers/edac/ppc4xx_edac.h b/drivers/edac/ppc4xx_edac.h
new file mode 100644 (file)
index 0000000..d315476
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2008 Nuovation System Designs, LLC
+ *   Grant Erickson <gerickson@nuovations.com>
+ *
+ * This file defines processor mnemonics for accessing and managing
+ * the IBM DDR1/DDR2 ECC controller found in the 405EX[r], 440SP,
+ * 440SPe, 460EX, 460GT and 460SX.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#ifndef __PPC4XX_EDAC_H
+#define __PPC4XX_EDAC_H
+
+#include <linux/types.h>
+
+/*
+ * Macro for generating register field mnemonics
+ */
+#define PPC_REG_BITS                   32
+#define PPC_REG_VAL(bit, val)          ((val) << ((PPC_REG_BITS - 1) - (bit)))
+#define PPC_REG_DECODE(bit, val)       ((val) >> ((PPC_REG_BITS - 1) - (bit)))
+
+/*
+ * IBM 4xx DDR1/DDR2 SDRAM memory controller registers (at least those
+ * relevant to ECC)
+ */
+#define SDRAM_BESR                     0x00    /* Error status (read/clear) */
+#define SDRAM_BESRT                    0x01    /* Error statuss (test/set)  */
+#define SDRAM_BEARL                    0x02    /* Error address low         */
+#define SDRAM_BEARH                    0x03    /* Error address high        */
+#define SDRAM_WMIRQ                    0x06    /* Write master (read/clear) */
+#define SDRAM_WMIRQT                   0x07    /* Write master (test/set)   */
+#define SDRAM_MCOPT1                   0x20    /* Controller options 1      */
+#define SDRAM_MBXCF_BASE               0x40    /* Bank n configuration base */
+#define        SDRAM_MBXCF(n)                  (SDRAM_MBXCF_BASE + (4 * (n)))
+#define SDRAM_MB0CF                    SDRAM_MBXCF(0)
+#define SDRAM_MB1CF                    SDRAM_MBXCF(1)
+#define SDRAM_MB2CF                    SDRAM_MBXCF(2)
+#define SDRAM_MB3CF                    SDRAM_MBXCF(3)
+#define SDRAM_ECCCR                    0x98    /* ECC error status          */
+#define SDRAM_ECCES                    SDRAM_ECCCR
+
+/*
+ * PLB Master IDs
+ */
+#define        SDRAM_PLB_M0ID_FIRST            0
+#define        SDRAM_PLB_M0ID_ICU              SDRAM_PLB_M0ID_FIRST
+#define        SDRAM_PLB_M0ID_PCIE0            1
+#define        SDRAM_PLB_M0ID_PCIE1            2
+#define        SDRAM_PLB_M0ID_DMA              3
+#define        SDRAM_PLB_M0ID_DCU              4
+#define        SDRAM_PLB_M0ID_OPB              5
+#define        SDRAM_PLB_M0ID_MAL              6
+#define        SDRAM_PLB_M0ID_SEC              7
+#define        SDRAM_PLB_M0ID_AHB              8
+#define SDRAM_PLB_M0ID_LAST            SDRAM_PLB_M0ID_AHB
+#define SDRAM_PLB_M0ID_COUNT           (SDRAM_PLB_M0ID_LAST - \
+                                        SDRAM_PLB_M0ID_FIRST + 1)
+
+/*
+ * Memory Controller Bus Error Status Register
+ */
+#define SDRAM_BESR_MASK                        PPC_REG_VAL(7, 0xFF)
+#define SDRAM_BESR_M0ID_MASK           PPC_REG_VAL(3, 0xF)
+#define        SDRAM_BESR_M0ID_DECODE(n)       PPC_REG_DECODE(3, n)
+#define SDRAM_BESR_M0ID_ICU            PPC_REG_VAL(3, SDRAM_PLB_M0ID_ICU)
+#define SDRAM_BESR_M0ID_PCIE0          PPC_REG_VAL(3, SDRAM_PLB_M0ID_PCIE0)
+#define SDRAM_BESR_M0ID_PCIE1          PPC_REG_VAL(3, SDRAM_PLB_M0ID_PCIE1)
+#define SDRAM_BESR_M0ID_DMA            PPC_REG_VAL(3, SDRAM_PLB_M0ID_DMA)
+#define SDRAM_BESR_M0ID_DCU            PPC_REG_VAL(3, SDRAM_PLB_M0ID_DCU)
+#define SDRAM_BESR_M0ID_OPB            PPC_REG_VAL(3, SDRAM_PLB_M0ID_OPB)
+#define SDRAM_BESR_M0ID_MAL            PPC_REG_VAL(3, SDRAM_PLB_M0ID_MAL)
+#define SDRAM_BESR_M0ID_SEC            PPC_REG_VAL(3, SDRAM_PLB_M0ID_SEC)
+#define SDRAM_BESR_M0ID_AHB            PPC_REG_VAL(3, SDRAM_PLB_M0ID_AHB)
+#define SDRAM_BESR_M0ET_MASK           PPC_REG_VAL(6, 0x7)
+#define SDRAM_BESR_M0ET_NONE           PPC_REG_VAL(6, 0)
+#define SDRAM_BESR_M0ET_ECC            PPC_REG_VAL(6, 1)
+#define SDRAM_BESR_M0RW_MASK           PPC_REG_VAL(7, 1)
+#define SDRAM_BESR_M0RW_WRITE          PPC_REG_VAL(7, 0)
+#define SDRAM_BESR_M0RW_READ           PPC_REG_VAL(7, 1)
+
+/*
+ * Memory Controller PLB Write Master Interrupt Register
+ */
+#define SDRAM_WMIRQ_MASK               PPC_REG_VAL(8, 0x1FF)
+#define        SDRAM_WMIRQ_ENCODE(id)          PPC_REG_VAL((id % \
+                                                    SDRAM_PLB_M0ID_COUNT), 1)
+#define SDRAM_WMIRQ_ICU                        PPC_REG_VAL(SDRAM_PLB_M0ID_ICU, 1)
+#define SDRAM_WMIRQ_PCIE0              PPC_REG_VAL(SDRAM_PLB_M0ID_PCIE0, 1)
+#define SDRAM_WMIRQ_PCIE1              PPC_REG_VAL(SDRAM_PLB_M0ID_PCIE1, 1)
+#define SDRAM_WMIRQ_DMA                        PPC_REG_VAL(SDRAM_PLB_M0ID_DMA, 1)
+#define SDRAM_WMIRQ_DCU                        PPC_REG_VAL(SDRAM_PLB_M0ID_DCU, 1)
+#define SDRAM_WMIRQ_OPB                        PPC_REG_VAL(SDRAM_PLB_M0ID_OPB, 1)
+#define SDRAM_WMIRQ_MAL                        PPC_REG_VAL(SDRAM_PLB_M0ID_MAL, 1)
+#define SDRAM_WMIRQ_SEC                        PPC_REG_VAL(SDRAM_PLB_M0ID_SEC, 1)
+#define SDRAM_WMIRQ_AHB                        PPC_REG_VAL(SDRAM_PLB_M0ID_AHB, 1)
+
+/*
+ * Memory Controller Options 1 Register
+ */
+#define SDRAM_MCOPT1_MCHK_MASK     PPC_REG_VAL(3, 0x3)  /* ECC mask         */
+#define SDRAM_MCOPT1_MCHK_NON      PPC_REG_VAL(3, 0x0)  /* No ECC gen       */
+#define SDRAM_MCOPT1_MCHK_GEN      PPC_REG_VAL(3, 0x2)  /* ECC gen          */
+#define SDRAM_MCOPT1_MCHK_CHK      PPC_REG_VAL(3, 0x1)  /* ECC gen and chk  */
+#define SDRAM_MCOPT1_MCHK_CHK_REP   PPC_REG_VAL(3, 0x3)         /* ECC gen/chk/rpt  */
+#define SDRAM_MCOPT1_MCHK_DECODE(n) ((((u32)(n)) >> 28) & 0x3)
+#define SDRAM_MCOPT1_RDEN_MASK     PPC_REG_VAL(4, 0x1)  /* Rgstrd DIMM mask */
+#define SDRAM_MCOPT1_RDEN          PPC_REG_VAL(4, 0x1)  /* Rgstrd DIMM enbl */
+#define SDRAM_MCOPT1_WDTH_MASK     PPC_REG_VAL(7, 0x1)  /* Width mask       */
+#define SDRAM_MCOPT1_WDTH_32       PPC_REG_VAL(7, 0x0)  /* 32 bits          */
+#define SDRAM_MCOPT1_WDTH_16       PPC_REG_VAL(7, 0x1)  /* 16 bits          */
+#define SDRAM_MCOPT1_DDR_TYPE_MASK  PPC_REG_VAL(11, 0x1) /* DDR type mask    */
+#define SDRAM_MCOPT1_DDR1_TYPE     PPC_REG_VAL(11, 0x0) /* DDR1 type        */
+#define SDRAM_MCOPT1_DDR2_TYPE     PPC_REG_VAL(11, 0x1) /* DDR2 type        */
+
+/*
+ * Memory Bank 0 - n Configuration Register
+ */
+#define SDRAM_MBCF_BA_MASK             PPC_REG_VAL(12, 0x1FFF)
+#define SDRAM_MBCF_SZ_MASK             PPC_REG_VAL(19, 0xF)
+#define SDRAM_MBCF_SZ_DECODE(mbxcf)    PPC_REG_DECODE(19, mbxcf)
+#define SDRAM_MBCF_SZ_4MB              PPC_REG_VAL(19, 0x0)
+#define SDRAM_MBCF_SZ_8MB              PPC_REG_VAL(19, 0x1)
+#define SDRAM_MBCF_SZ_16MB             PPC_REG_VAL(19, 0x2)
+#define SDRAM_MBCF_SZ_32MB             PPC_REG_VAL(19, 0x3)
+#define SDRAM_MBCF_SZ_64MB             PPC_REG_VAL(19, 0x4)
+#define SDRAM_MBCF_SZ_128MB            PPC_REG_VAL(19, 0x5)
+#define SDRAM_MBCF_SZ_256MB            PPC_REG_VAL(19, 0x6)
+#define SDRAM_MBCF_SZ_512MB            PPC_REG_VAL(19, 0x7)
+#define SDRAM_MBCF_SZ_1GB              PPC_REG_VAL(19, 0x8)
+#define SDRAM_MBCF_SZ_2GB              PPC_REG_VAL(19, 0x9)
+#define SDRAM_MBCF_SZ_4GB              PPC_REG_VAL(19, 0xA)
+#define SDRAM_MBCF_SZ_8GB              PPC_REG_VAL(19, 0xB)
+#define SDRAM_MBCF_AM_MASK             PPC_REG_VAL(23, 0xF)
+#define SDRAM_MBCF_AM_MODE0            PPC_REG_VAL(23, 0x0)
+#define SDRAM_MBCF_AM_MODE1            PPC_REG_VAL(23, 0x1)
+#define SDRAM_MBCF_AM_MODE2            PPC_REG_VAL(23, 0x2)
+#define SDRAM_MBCF_AM_MODE3            PPC_REG_VAL(23, 0x3)
+#define SDRAM_MBCF_AM_MODE4            PPC_REG_VAL(23, 0x4)
+#define SDRAM_MBCF_AM_MODE5            PPC_REG_VAL(23, 0x5)
+#define SDRAM_MBCF_AM_MODE6            PPC_REG_VAL(23, 0x6)
+#define SDRAM_MBCF_AM_MODE7            PPC_REG_VAL(23, 0x7)
+#define SDRAM_MBCF_AM_MODE8            PPC_REG_VAL(23, 0x8)
+#define SDRAM_MBCF_AM_MODE9            PPC_REG_VAL(23, 0x9)
+#define SDRAM_MBCF_BE_MASK             PPC_REG_VAL(31, 0x1)
+#define SDRAM_MBCF_BE_DISABLE          PPC_REG_VAL(31, 0x0)
+#define SDRAM_MBCF_BE_ENABLE           PPC_REG_VAL(31, 0x1)
+
+/*
+ * ECC Error Status
+ */
+#define SDRAM_ECCES_MASK               PPC_REG_VAL(21, 0x3FFFFF)
+#define SDRAM_ECCES_BNCE_MASK          PPC_REG_VAL(15, 0xFFFF)
+#define SDRAM_ECCES_BNCE_ENCODE(lane)  PPC_REG_VAL(((lane) & 0xF), 1)
+#define SDRAM_ECCES_CKBER_MASK         PPC_REG_VAL(17, 0x3)
+#define SDRAM_ECCES_CKBER_NONE         PPC_REG_VAL(17, 0)
+#define SDRAM_ECCES_CKBER_16_ECC_0_3   PPC_REG_VAL(17, 2)
+#define SDRAM_ECCES_CKBER_32_ECC_0_3   PPC_REG_VAL(17, 1)
+#define SDRAM_ECCES_CKBER_32_ECC_4_8   PPC_REG_VAL(17, 2)
+#define SDRAM_ECCES_CKBER_32_ECC_0_8   PPC_REG_VAL(17, 3)
+#define SDRAM_ECCES_CE                 PPC_REG_VAL(18, 1)
+#define SDRAM_ECCES_UE                 PPC_REG_VAL(19, 1)
+#define SDRAM_ECCES_BKNER_MASK         PPC_REG_VAL(21, 0x3)
+#define SDRAM_ECCES_BK0ER              PPC_REG_VAL(20, 1)
+#define SDRAM_ECCES_BK1ER              PPC_REG_VAL(21, 1)
+
+#endif /* __PPC4XX_EDAC_H */
index 8f0f7c44930540aa6829fdbe92b085d7c4009a46..5f1b5400d96abf6cd741165ffc9bfcf1d781406e 100644 (file)
@@ -68,7 +68,8 @@ static char * __init dmi_string(const struct dmi_header *dm, u8 s)
  *     pointing to completely the wrong place for example
  */
 static void dmi_table(u8 *buf, int len, int num,
-                     void (*decode)(const struct dmi_header *))
+                     void (*decode)(const struct dmi_header *, void *),
+                     void *private_data)
 {
        u8 *data = buf;
        int i = 0;
@@ -89,7 +90,7 @@ static void dmi_table(u8 *buf, int len, int num,
                while ((data - buf < len - 1) && (data[0] || data[1]))
                        data++;
                if (data - buf < len - 1)
-                       decode(dm);
+                       decode(dm, private_data);
                data += 2;
                i++;
        }
@@ -99,7 +100,8 @@ static u32 dmi_base;
 static u16 dmi_len;
 static u16 dmi_num;
 
-static int __init dmi_walk_early(void (*decode)(const struct dmi_header *))
+static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
+               void *))
 {
        u8 *buf;
 
@@ -107,7 +109,7 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *))
        if (buf == NULL)
                return -1;
 
-       dmi_table(buf, dmi_len, dmi_num, decode);
+       dmi_table(buf, dmi_len, dmi_num, decode, NULL);
 
        dmi_iounmap(buf, dmi_len);
        return 0;
@@ -295,7 +297,7 @@ static void __init dmi_save_extended_devices(const struct dmi_header *dm)
  *     and machine entries. For 2.5 we should pull the smbus controller info
  *     out of here.
  */
-static void __init dmi_decode(const struct dmi_header *dm)
+static void __init dmi_decode(const struct dmi_header *dm, void *dummy)
 {
        switch(dm->type) {
        case 0:         /* BIOS Information */
@@ -598,10 +600,12 @@ int dmi_get_year(int field)
 /**
  *     dmi_walk - Walk the DMI table and get called back for every record
  *     @decode: Callback function
+ *     @private_data: Private data to be passed to the callback function
  *
  *     Returns -1 when the DMI table can't be reached, 0 on success.
  */
-int dmi_walk(void (*decode)(const struct dmi_header *))
+int dmi_walk(void (*decode)(const struct dmi_header *, void *),
+            void *private_data)
 {
        u8 *buf;
 
@@ -612,7 +616,7 @@ int dmi_walk(void (*decode)(const struct dmi_header *))
        if (buf == NULL)
                return -1;
 
-       dmi_table(buf, dmi_len, dmi_num, decode);
+       dmi_table(buf, dmi_len, dmi_num, decode, private_data);
 
        iounmap(buf);
        return 0;
index 42fb2fd24c0c03cd20b21dab5038fde07d3be30c..51a8d4103be53beb3dd90bd1328d89935cf6573c 100644 (file)
@@ -69,20 +69,24 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
  * those calls have no teeth) we can't avoid autorequesting.  This nag
  * message should motivate switching to explicit requests... so should
  * the weaker cleanup after faults, compared to gpio_request().
+ *
+ * NOTE: the autorequest mechanism is going away; at this point it's
+ * only "legal" in the sense that (old) code using it won't break yet,
+ * but instead only triggers a WARN() stack dump.
  */
 static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset)
 {
-       if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
-               struct gpio_chip *chip = desc->chip;
-               int gpio = chip->base + offset;
+       const struct gpio_chip *chip = desc->chip;
+       const int gpio = chip->base + offset;
 
+       if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0,
+                       "autorequest GPIO-%d\n", gpio)) {
                if (!try_module_get(chip->owner)) {
                        pr_err("GPIO-%d: module can't be gotten \n", gpio);
                        clear_bit(FLAG_REQUESTED, &desc->flags);
                        /* lose */
                        return -EIO;
                }
-               pr_warning("GPIO-%d autorequested\n", gpio);
                desc_set_label(desc, "[auto]");
                /* caller must chip->request() w/o spinlock */
                if (chip->request)
@@ -438,6 +442,7 @@ int gpio_export(unsigned gpio, bool direction_may_change)
        unsigned long           flags;
        struct gpio_desc        *desc;
        int                     status = -EINVAL;
+       char                    *ioname = NULL;
 
        /* can't export until sysfs is available ... */
        if (!gpio_class.p) {
@@ -461,11 +466,14 @@ int gpio_export(unsigned gpio, bool direction_may_change)
        }
        spin_unlock_irqrestore(&gpio_lock, flags);
 
+       if (desc->chip->names && desc->chip->names[gpio - desc->chip->base])
+               ioname = desc->chip->names[gpio - desc->chip->base];
+
        if (status == 0) {
                struct device   *dev;
 
                dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
-                                       desc, "gpio%d", gpio);
+                                   desc, ioname ? ioname : "gpio%d", gpio);
                if (dev) {
                        if (direction_may_change)
                                status = sysfs_create_group(&dev->kobj,
@@ -513,6 +521,7 @@ void gpio_unexport(unsigned gpio)
        mutex_lock(&sysfs_lock);
 
        desc = &gpio_desc[gpio];
+
        if (test_bit(FLAG_EXPORT, &desc->flags)) {
                struct device   *dev = NULL;
 
index c533d0c9ec616ba38aaf13211dee1bca48cc36c9..628eae3e9b8354a14ba1f74c2e6c21f01039085f 100644 (file)
@@ -77,7 +77,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info
                        if (!entry->busaddr[i])
                                break;
                        pci_unmap_page(dev->pdev, entry->busaddr[i],
-                                        PAGE_SIZE, PCI_DMA_TODEVICE);
+                                        PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
                }
 
                if (gart_info->gart_table_location == DRM_ATI_GART_MAIN)
@@ -95,13 +95,14 @@ EXPORT_SYMBOL(drm_ati_pcigart_cleanup);
 
 int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info)
 {
+       struct drm_local_map *map = &gart_info->mapping;
        struct drm_sg_mem *entry = dev->sg;
        void *address = NULL;
        unsigned long pages;
-       u32 *pci_gart, page_base;
+       u32 *pci_gart = NULL, page_base, gart_idx;
        dma_addr_t bus_address = 0;
        int i, j, ret = 0;
-       int max_pages;
+       int max_ati_pages, max_real_pages;
 
        if (!entry) {
                DRM_ERROR("no scatter/gather memory!\n");
@@ -117,6 +118,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga
                        goto done;
                }
 
+               pci_gart = gart_info->table_handle->vaddr;
                address = gart_info->table_handle->vaddr;
                bus_address = gart_info->table_handle->busaddr;
        } else {
@@ -127,18 +129,23 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga
                          (unsigned long)address);
        }
 
-       pci_gart = (u32 *) address;
 
-       max_pages = (gart_info->table_size / sizeof(u32));
-       pages = (entry->pages <= max_pages)
-           ? entry->pages : max_pages;
+       max_ati_pages = (gart_info->table_size / sizeof(u32));
+       max_real_pages = max_ati_pages / (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE);
+       pages = (entry->pages <= max_real_pages)
+           ? entry->pages : max_real_pages;
 
-       memset(pci_gart, 0, max_pages * sizeof(u32));
+       if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
+               memset(pci_gart, 0, max_ati_pages * sizeof(u32));
+       } else {
+               memset_io((void __iomem *)map->handle, 0, max_ati_pages * sizeof(u32));
+       }
 
+       gart_idx = 0;
        for (i = 0; i < pages; i++) {
                /* we need to support large memory configurations */
                entry->busaddr[i] = pci_map_page(dev->pdev, entry->pagelist[i],
-                                                0, PAGE_SIZE, PCI_DMA_TODEVICE);
+                                                0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
                if (entry->busaddr[i] == 0) {
                        DRM_ERROR("unable to map PCIGART pages!\n");
                        drm_ati_pcigart_cleanup(dev, gart_info);
@@ -149,19 +156,26 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga
                page_base = (u32) entry->busaddr[i];
 
                for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
+                       u32 val;
+
                        switch(gart_info->gart_reg_if) {
                        case DRM_ATI_GART_IGP:
-                               *pci_gart = cpu_to_le32((page_base) | 0xc);
+                               val = page_base | 0xc;
                                break;
                        case DRM_ATI_GART_PCIE:
-                               *pci_gart = cpu_to_le32((page_base >> 8) | 0xc);
+                               val = (page_base >> 8) | 0xc;
                                break;
                        default:
                        case DRM_ATI_GART_PCI:
-                               *pci_gart = cpu_to_le32(page_base);
+                               val = page_base;
                                break;
                        }
-                       pci_gart++;
+                       if (gart_info->gart_table_location ==
+                           DRM_ATI_GART_MAIN)
+                               pci_gart[gart_idx] = cpu_to_le32(val);
+                       else
+                               DRM_WRITE32(map, gart_idx * sizeof(u32), val);
+                       gart_idx++;
                        page_base += ATI_PCIGART_PAGE_SIZE;
                }
        }
index 12715d3c078d6e9d111c265fe96b5ccc63961d3e..6d80d17f1e96f9b6d137cfd7ec553378620ca6e2 100644 (file)
  */
 
 #include <linux/vmalloc.h>
+#include <linux/log2.h>
+#include <asm/shmparam.h>
 #include "drmP.h"
 
-unsigned long drm_get_resource_start(struct drm_device *dev, unsigned int resource)
+resource_size_t drm_get_resource_start(struct drm_device *dev, unsigned int resource)
 {
        return pci_resource_start(dev->pdev, resource);
 }
 EXPORT_SYMBOL(drm_get_resource_start);
 
-unsigned long drm_get_resource_len(struct drm_device *dev, unsigned int resource)
+resource_size_t drm_get_resource_len(struct drm_device *dev, unsigned int resource)
 {
        return pci_resource_len(dev->pdev, resource);
 }
@@ -50,24 +52,44 @@ unsigned long drm_get_resource_len(struct drm_device *dev, unsigned int resource
 EXPORT_SYMBOL(drm_get_resource_len);
 
 static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
-                                            drm_local_map_t *map)
+                                                 struct drm_local_map *map)
 {
        struct drm_map_list *entry;
        list_for_each_entry(entry, &dev->maplist, head) {
-               if (entry->map && (entry->master == dev->primary->master) && (map->type == entry->map->type) &&
-                   ((entry->map->offset == map->offset) ||
-                    ((map->type == _DRM_SHM) && (map->flags&_DRM_CONTAINS_LOCK)))) {
+               /*
+                * Because the kernel-userspace ABI is fixed at a 32-bit offset
+                * while PCI resources may live above that, we ignore the map
+                * offset for maps of type _DRM_FRAMEBUFFER or _DRM_REGISTERS.
+                * It is assumed that each driver will have only one resource of
+                * each type.
+                */
+               if (!entry->map ||
+                   map->type != entry->map->type ||
+                   entry->master != dev->primary->master)
+                       continue;
+               switch (map->type) {
+               case _DRM_SHM:
+                       if (map->flags != _DRM_CONTAINS_LOCK)
+                               break;
+               case _DRM_REGISTERS:
+               case _DRM_FRAME_BUFFER:
                        return entry;
+               default: /* Make gcc happy */
+                       ;
                }
+               if (entry->map->offset == map->offset)
+                       return entry;
        }
 
        return NULL;
 }
 
 static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash,
-                         unsigned long user_token, int hashed_handle)
+                         unsigned long user_token, int hashed_handle, int shm)
 {
-       int use_hashed_handle;
+       int use_hashed_handle, shift;
+       unsigned long add;
+
 #if (BITS_PER_LONG == 64)
        use_hashed_handle = ((user_token & 0xFFFFFFFF00000000UL) || hashed_handle);
 #elif (BITS_PER_LONG == 32)
@@ -83,30 +105,47 @@ static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash,
                if (ret != -EINVAL)
                        return ret;
        }
+
+       shift = 0;
+       add = DRM_MAP_HASH_OFFSET >> PAGE_SHIFT;
+       if (shm && (SHMLBA > PAGE_SIZE)) {
+               int bits = ilog2(SHMLBA >> PAGE_SHIFT) + 1;
+
+               /* For shared memory, we have to preserve the SHMLBA
+                * bits of the eventual vma->vm_pgoff value during
+                * mmap().  Otherwise we run into cache aliasing problems
+                * on some platforms.  On these platforms, the pgoff of
+                * a mmap() request is used to pick a suitable virtual
+                * address for the mmap() region such that it will not
+                * cause cache aliasing problems.
+                *
+                * Therefore, make sure the SHMLBA relevant bits of the
+                * hash value we use are equal to those in the original
+                * kernel virtual address.
+                */
+               shift = bits;
+               add |= ((user_token >> PAGE_SHIFT) & ((1UL << bits) - 1UL));
+       }
+
        return drm_ht_just_insert_please(&dev->map_hash, hash,
                                         user_token, 32 - PAGE_SHIFT - 3,
-                                        0, DRM_MAP_HASH_OFFSET >> PAGE_SHIFT);
+                                        shift, add);
 }
 
 /**
- * Ioctl to specify a range of memory that is available for mapping by a non-root process.
- *
- * \param inode device inode.
- * \param file_priv DRM file private.
- * \param cmd command.
- * \param arg pointer to a drm_map structure.
- * \return zero on success or a negative value on error.
+ * Core function to create a range of memory available for mapping by a
+ * non-root process.
  *
  * Adjusts the memory offset to its absolute value according to the mapping
  * type.  Adds the map to the map list drm_device::maplist. Adds MTRR's where
  * applicable and if supported by the kernel.
  */
-static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
+static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
                           unsigned int size, enum drm_map_type type,
                           enum drm_map_flags flags,
                           struct drm_map_list ** maplist)
 {
-       struct drm_map *map;
+       struct drm_local_map *map;
        struct drm_map_list *list;
        drm_dma_handle_t *dmah;
        unsigned long user_token;
@@ -129,9 +168,9 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
                drm_free(map, sizeof(*map), DRM_MEM_MAPS);
                return -EINVAL;
        }
-       DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n",
-                 map->offset, map->size, map->type);
-       if ((map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK))) {
+       DRM_DEBUG("offset = 0x%08llx, size = 0x%08lx, type = %d\n",
+                 (unsigned long long)map->offset, map->size, map->type);
+       if ((map->offset & (~(resource_size_t)PAGE_MASK)) || (map->size & (~PAGE_MASK))) {
                drm_free(map, sizeof(*map), DRM_MEM_MAPS);
                return -EINVAL;
        }
@@ -259,7 +298,8 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
                        drm_free(map, sizeof(*map), DRM_MEM_MAPS);
                        return -EPERM;
                }
-               DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", map->offset, map->size);
+               DRM_DEBUG("AGP offset = 0x%08llx, size = 0x%08lx\n",
+                         (unsigned long long)map->offset, map->size);
 
                break;
        case _DRM_GEM:
@@ -309,7 +349,8 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
        /* We do it here so that dev->struct_mutex protects the increment */
        user_token = (map->type == _DRM_SHM) ? (unsigned long)map->handle :
                map->offset;
-       ret = drm_map_handle(dev, &list->hash, user_token, 0);
+       ret = drm_map_handle(dev, &list->hash, user_token, 0,
+                            (map->type == _DRM_SHM));
        if (ret) {
                if (map->type == _DRM_REGISTERS)
                        iounmap(map->handle);
@@ -327,9 +368,9 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
        return 0;
        }
 
-int drm_addmap(struct drm_device * dev, unsigned int offset,
+int drm_addmap(struct drm_device * dev, resource_size_t offset,
               unsigned int size, enum drm_map_type type,
-              enum drm_map_flags flags, drm_local_map_t ** map_ptr)
+              enum drm_map_flags flags, struct drm_local_map ** map_ptr)
 {
        struct drm_map_list *list;
        int rc;
@@ -342,6 +383,17 @@ int drm_addmap(struct drm_device * dev, unsigned int offset,
 
 EXPORT_SYMBOL(drm_addmap);
 
+/**
+ * Ioctl to specify a range of memory that is available for mapping by a
+ * non-root process.
+ *
+ * \param inode device inode.
+ * \param file_priv DRM file private.
+ * \param cmd command.
+ * \param arg pointer to a drm_map structure.
+ * \return zero on success or a negative value on error.
+ *
+ */
 int drm_addmap_ioctl(struct drm_device *dev, void *data,
                     struct drm_file *file_priv)
 {
@@ -367,19 +419,13 @@ int drm_addmap_ioctl(struct drm_device *dev, void *data,
  * Remove a map private from list and deallocate resources if the mapping
  * isn't in use.
  *
- * \param inode device inode.
- * \param file_priv DRM file private.
- * \param cmd command.
- * \param arg pointer to a struct drm_map structure.
- * \return zero on success or a negative value on error.
- *
  * Searches the map on drm_device::maplist, removes it from the list, see if
  * its being used, and free any associate resource (such as MTRR's) if it's not
  * being on use.
  *
  * \sa drm_addmap
  */
-int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)
+int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map)
 {
        struct drm_map_list *r_list = NULL, *list_t;
        drm_dma_handle_t dmah;
@@ -442,7 +488,7 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)
 }
 EXPORT_SYMBOL(drm_rmmap_locked);
 
-int drm_rmmap(struct drm_device *dev, drm_local_map_t *map)
+int drm_rmmap(struct drm_device *dev, struct drm_local_map *map)
 {
        int ret;
 
@@ -462,12 +508,18 @@ EXPORT_SYMBOL(drm_rmmap);
  * One use case might be after addmap is allowed for normal users for SHM and
  * gets used by drivers that the server doesn't need to care about.  This seems
  * unlikely.
+ *
+ * \param inode device inode.
+ * \param file_priv DRM file private.
+ * \param cmd command.
+ * \param arg pointer to a struct drm_map structure.
+ * \return zero on success or a negative value on error.
  */
 int drm_rmmap_ioctl(struct drm_device *dev, void *data,
                    struct drm_file *file_priv)
 {
        struct drm_map *request = data;
-       drm_local_map_t *map = NULL;
+       struct drm_local_map *map = NULL;
        struct drm_map_list *r_list;
        int ret;
 
@@ -1534,7 +1586,7 @@ int drm_mapbufs(struct drm_device *dev, void *data,
                        && (dma->flags & _DRM_DMA_USE_SG))
                    || (drm_core_check_feature(dev, DRIVER_FB_DMA)
                        && (dma->flags & _DRM_DMA_USE_FB))) {
-                       struct drm_map *map = dev->agp_buffer_map;
+                       struct drm_local_map *map = dev->agp_buffer_map;
                        unsigned long token = dev->agp_buffer_token;
 
                        if (!map) {
index 809ec0f034524506ef0b4cef13e4d60b89fa10d3..7d1e53c10d4bf131eb346695bb131226ce442f28 100644 (file)
@@ -143,7 +143,7 @@ int drm_getsareactx(struct drm_device *dev, void *data,
                    struct drm_file *file_priv)
 {
        struct drm_ctx_priv_map *request = data;
-       struct drm_map *map;
+       struct drm_local_map *map;
        struct drm_map_list *_entry;
 
        mutex_lock(&dev->struct_mutex);
@@ -186,7 +186,7 @@ int drm_setsareactx(struct drm_device *dev, void *data,
                    struct drm_file *file_priv)
 {
        struct drm_ctx_priv_map *request = data;
-       struct drm_map *map = NULL;
+       struct drm_local_map *map = NULL;
        struct drm_map_list *r_list = NULL;
 
        mutex_lock(&dev->struct_mutex);
index ed32edb17166b218498bbd428d164a60ec855d0c..c4ada8b6295be28ab60b3edc6f3958fd68e6f66b 100644 (file)
@@ -254,15 +254,19 @@ int drm_lastclose(struct drm_device * dev)
 int drm_init(struct drm_driver *driver)
 {
        struct pci_dev *pdev = NULL;
-       struct pci_device_id *pid;
+       const struct pci_device_id *pid;
        int i;
 
        DRM_DEBUG("\n");
 
        INIT_LIST_HEAD(&driver->device_list);
 
+       if (driver->driver_features & DRIVER_MODESET)
+               return pci_register_driver(&driver->pci_driver);
+
+       /* If not using KMS, fall back to stealth mode manual scanning. */
        for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) {
-               pid = (struct pci_device_id *)&driver->pci_driver.id_table[i];
+               pid = &driver->pci_driver.id_table[i];
 
                /* Loop around setting up a DRM device for each PCI device
                 * matching our ID and device class.  If we had the internal
@@ -287,68 +291,17 @@ int drm_init(struct drm_driver *driver)
 
 EXPORT_SYMBOL(drm_init);
 
-/**
- * Called via cleanup_module() at module unload time.
- *
- * Cleans up all DRM device, calling drm_lastclose().
- *
- * \sa drm_init
- */
-static void drm_cleanup(struct drm_device * dev)
-{
-       struct drm_map_list *r_list, *list_temp;
-       DRM_DEBUG("\n");
-
-       if (!dev) {
-               DRM_ERROR("cleanup called no dev\n");
-               return;
-       }
-
-       drm_vblank_cleanup(dev);
-
-       drm_lastclose(dev);
-
-       if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
-           dev->agp && dev->agp->agp_mtrr >= 0) {
-               int retval;
-               retval = mtrr_del(dev->agp->agp_mtrr,
-                                 dev->agp->agp_info.aper_base,
-                                 dev->agp->agp_info.aper_size * 1024 * 1024);
-               DRM_DEBUG("mtrr_del=%d\n", retval);
-       }
-
-       if (dev->driver->unload)
-               dev->driver->unload(dev);
-
-       if (drm_core_has_AGP(dev) && dev->agp) {
-               drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
-               dev->agp = NULL;
-       }
-
-       drm_ht_remove(&dev->map_hash);
-       drm_ctxbitmap_cleanup(dev);
-
-       list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
-               drm_rmmap(dev, r_list->map);
-
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               drm_put_minor(&dev->control);
-
-       if (dev->driver->driver_features & DRIVER_GEM)
-               drm_gem_destroy(dev);
-
-       drm_put_minor(&dev->primary);
-       if (drm_put_dev(dev))
-               DRM_ERROR("Cannot unload module\n");
-}
-
 void drm_exit(struct drm_driver *driver)
 {
        struct drm_device *dev, *tmp;
        DRM_DEBUG("\n");
 
-       list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
-               drm_cleanup(dev);
+       if (driver->driver_features & DRIVER_MODESET) {
+               pci_unregister_driver(&driver->pci_driver);
+       } else {
+               list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
+                       drm_put_dev(dev);
+       }
 
        DRM_INFO("Module unloaded\n");
 }
@@ -468,6 +421,7 @@ int drm_ioctl(struct inode *inode, struct file *filp,
        drm_ioctl_t *func;
        unsigned int nr = DRM_IOCTL_NR(cmd);
        int retcode = -EINVAL;
+       char stack_kdata[128];
        char *kdata = NULL;
 
        atomic_inc(&dev->ioctl_count);
@@ -506,10 +460,14 @@ int drm_ioctl(struct inode *inode, struct file *filp,
                retcode = -EACCES;
        } else {
                if (cmd & (IOC_IN | IOC_OUT)) {
-                       kdata = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
-                       if (!kdata) {
-                               retcode = -ENOMEM;
-                               goto err_i1;
+                       if (_IOC_SIZE(cmd) <= sizeof(stack_kdata)) {
+                               kdata = stack_kdata;
+                       } else {
+                               kdata = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
+                               if (!kdata) {
+                                       retcode = -ENOMEM;
+                                       goto err_i1;
+                               }
                        }
                }
 
@@ -530,7 +488,7 @@ int drm_ioctl(struct inode *inode, struct file *filp,
        }
 
       err_i1:
-       if (kdata)
+       if (kdata != stack_kdata)
                kfree(kdata);
        atomic_dec(&dev->ioctl_count);
        if (retcode)
@@ -540,7 +498,7 @@ int drm_ioctl(struct inode *inode, struct file *filp,
 
 EXPORT_SYMBOL(drm_ioctl);
 
-drm_local_map_t *drm_getsarea(struct drm_device *dev)
+struct drm_local_map *drm_getsarea(struct drm_device *dev)
 {
        struct drm_map_list *entry;
 
index a839a28d8ee606763ad213d9dc785bc4dde0dd6c..c67400067b8573c9be015391601152dc4acd6f90 100644 (file)
@@ -550,11 +550,20 @@ static int add_detailed_info(struct drm_connector *connector,
 }
 
 #define DDC_ADDR 0x50
-
-unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter)
+/**
+ * Get EDID information via I2C.
+ *
+ * \param adapter : i2c device adaptor
+ * \param buf     : EDID data buffer to be filled
+ * \param len     : EDID data buffer length
+ * \return 0 on success or -1 on failure.
+ *
+ * Try to fetch EDID information by calling i2c driver function.
+ */
+int drm_do_probe_ddc_edid(struct i2c_adapter *adapter,
+                         unsigned char *buf, int len)
 {
        unsigned char start = 0x0;
-       unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
        struct i2c_msg msgs[] = {
                {
                        .addr   = DDC_ADDR,
@@ -564,31 +573,36 @@ unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter)
                }, {
                        .addr   = DDC_ADDR,
                        .flags  = I2C_M_RD,
-                       .len    = EDID_LENGTH,
+                       .len    = len,
                        .buf    = buf,
                }
        };
 
-       if (!buf) {
-               dev_warn(&adapter->dev, "unable to allocate memory for EDID "
-                        "block.\n");
-               return NULL;
-       }
-
        if (i2c_transfer(adapter, msgs, 2) == 2)
-               return buf;
+               return 0;
 
        dev_info(&adapter->dev, "unable to read EDID block.\n");
-       kfree(buf);
-       return NULL;
+       return -1;
 }
 EXPORT_SYMBOL(drm_do_probe_ddc_edid);
 
-static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
+/**
+ * Get EDID information.
+ *
+ * \param adapter : i2c device adaptor.
+ * \param buf     : EDID data buffer to be filled
+ * \param len     : EDID data buffer length
+ * \return 0 on success or -1 on failure.
+ *
+ * Initialize DDC, then fetch EDID information
+ * by calling drm_do_probe_ddc_edid function.
+ */
+static int drm_ddc_read(struct i2c_adapter *adapter,
+                       unsigned char *buf, int len)
 {
        struct i2c_algo_bit_data *algo_data = adapter->algo_data;
-       unsigned char *edid = NULL;
        int i, j;
+       int ret = -1;
 
        algo_data->setscl(algo_data->data, 1);
 
@@ -616,7 +630,7 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
                msleep(15);
 
                /* Do the real work */
-               edid = drm_do_probe_ddc_edid(adapter);
+               ret = drm_do_probe_ddc_edid(adapter, buf, len);
                algo_data->setsda(algo_data->data, 0);
                algo_data->setscl(algo_data->data, 0);
                msleep(15);
@@ -632,7 +646,7 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
                msleep(15);
                algo_data->setscl(algo_data->data, 0);
                algo_data->setsda(algo_data->data, 0);
-               if (edid)
+               if (ret == 0)
                        break;
        }
        /* Release the DDC lines when done or the Apple Cinema HD display
@@ -641,9 +655,31 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
        algo_data->setsda(algo_data->data, 1);
        algo_data->setscl(algo_data->data, 1);
 
-       return edid;
+       return ret;
 }
 
+static int drm_ddc_read_edid(struct drm_connector *connector,
+                            struct i2c_adapter *adapter,
+                            char *buf, int len)
+{
+       int ret;
+
+       ret = drm_ddc_read(adapter, buf, len);
+       if (ret != 0) {
+               dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n",
+                        drm_get_connector_name(connector));
+               goto end;
+       }
+       if (!edid_is_valid((struct edid *)buf)) {
+               dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
+                        drm_get_connector_name(connector));
+               ret = -1;
+       }
+end:
+       return ret;
+}
+
+#define MAX_EDID_EXT_NUM 4
 /**
  * drm_get_edid - get EDID data, if available
  * @connector: connector we're probing
@@ -656,27 +692,118 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
 struct edid *drm_get_edid(struct drm_connector *connector,
                          struct i2c_adapter *adapter)
 {
+       int ret;
        struct edid *edid;
 
-       edid = (struct edid *)drm_ddc_read(adapter);
-       if (!edid) {
-               dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n",
-                        drm_get_connector_name(connector));
-               return NULL;
+       edid = kmalloc(EDID_LENGTH * (MAX_EDID_EXT_NUM + 1),
+                      GFP_KERNEL);
+       if (edid == NULL) {
+               dev_warn(&connector->dev->pdev->dev,
+                        "Failed to allocate EDID\n");
+               goto end;
        }
-       if (!edid_is_valid(edid)) {
-               dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
-                        drm_get_connector_name(connector));
-               kfree(edid);
-               return NULL;
+
+       /* Read first EDID block */
+       ret = drm_ddc_read_edid(connector, adapter,
+                               (unsigned char *)edid, EDID_LENGTH);
+       if (ret != 0)
+               goto clean_up;
+
+       /* There are EDID extensions to be read */
+       if (edid->extensions != 0) {
+               int edid_ext_num = edid->extensions;
+
+               if (edid_ext_num > MAX_EDID_EXT_NUM) {
+                       dev_warn(&connector->dev->pdev->dev,
+                                "The number of extension(%d) is "
+                                "over max (%d), actually read number (%d)\n",
+                                edid_ext_num, MAX_EDID_EXT_NUM,
+                                MAX_EDID_EXT_NUM);
+                       /* Reset EDID extension number to be read */
+                       edid_ext_num = MAX_EDID_EXT_NUM;
+               }
+               /* Read EDID including extensions too */
+               ret = drm_ddc_read_edid(connector, adapter, (char *)edid,
+                                       EDID_LENGTH * (edid_ext_num + 1));
+               if (ret != 0)
+                       goto clean_up;
+
        }
 
        connector->display_info.raw_edid = (char *)edid;
+       goto end;
 
+clean_up:
+       kfree(edid);
+       edid = NULL;
+end:
        return edid;
+
 }
 EXPORT_SYMBOL(drm_get_edid);
 
+#define HDMI_IDENTIFIER 0x000C03
+#define VENDOR_BLOCK    0x03
+/**
+ * drm_detect_hdmi_monitor - detect whether monitor is hdmi.
+ * @edid: monitor EDID information
+ *
+ * Parse the CEA extension according to CEA-861-B.
+ * Return true if HDMI, false if not or unknown.
+ */
+bool drm_detect_hdmi_monitor(struct edid *edid)
+{
+       char *edid_ext = NULL;
+       int i, hdmi_id, edid_ext_num;
+       int start_offset, end_offset;
+       bool is_hdmi = false;
+
+       /* No EDID or EDID extensions */
+       if (edid == NULL || edid->extensions == 0)
+               goto end;
+
+       /* Chose real EDID extension number */
+       edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ?
+                      MAX_EDID_EXT_NUM : edid->extensions;
+
+       /* Find CEA extension */
+       for (i = 0; i < edid_ext_num; i++) {
+               edid_ext = (char *)edid + EDID_LENGTH * (i + 1);
+               /* This block is CEA extension */
+               if (edid_ext[0] == 0x02)
+                       break;
+       }
+
+       if (i == edid_ext_num)
+               goto end;
+
+       /* Data block offset in CEA extension block */
+       start_offset = 4;
+       end_offset = edid_ext[2];
+
+       /*
+        * Because HDMI identifier is in Vendor Specific Block,
+        * search it from all data blocks of CEA extension.
+        */
+       for (i = start_offset; i < end_offset;
+               /* Increased by data block len */
+               i += ((edid_ext[i] & 0x1f) + 1)) {
+               /* Find vendor specific block */
+               if ((edid_ext[i] >> 5) == VENDOR_BLOCK) {
+                       hdmi_id = edid_ext[i + 1] | (edid_ext[i + 2] << 8) |
+                                 edid_ext[i + 3] << 16;
+                       /* Find HDMI identifier */
+                       if (hdmi_id == HDMI_IDENTIFIER)
+                               is_hdmi = true;
+                       break;
+               }
+       }
+
+end:
+       return is_hdmi;
+}
+EXPORT_SYMBOL(drm_detect_hdmi_monitor);
+
 /**
  * drm_add_edid_modes - add modes from EDID data, if available
  * @connector: connector we're probing
index e13cb62bbaee24bc2c2a2cd2f0475d2412f474cd..09a3571c990889ab3d408512f11175fa17590924 100644 (file)
@@ -274,6 +274,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
                /* create a new master */
                priv->minor->master = drm_master_create(priv->minor);
                if (!priv->minor->master) {
+                       mutex_unlock(&dev->struct_mutex);
                        ret = -ENOMEM;
                        goto out_free;
                }
index 88d3368ffddd946974ba9a42ac273810f9c68c21..c1173d8c4588fbe4fed12152b5345f4f6911c9b4 100644 (file)
@@ -502,7 +502,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
        struct drm_file *priv = filp->private_data;
        struct drm_device *dev = priv->minor->dev;
        struct drm_gem_mm *mm = dev->mm_private;
-       struct drm_map *map = NULL;
+       struct drm_local_map *map = NULL;
        struct drm_gem_object *obj;
        struct drm_hash_item *hash;
        unsigned long prot;
index 1b699768ccfb5a196ce194bcf96280bd52dd05a9..f0f6c6b93f3a235a4a667bcac27a56f5667b4562 100644 (file)
@@ -72,7 +72,7 @@ int drm_vm_info(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
-       struct drm_map *map;
+       struct drm_local_map *map;
        struct drm_map_list *r_list;
 
        /* Hardcoded from _DRM_FRAME_BUFFER,
@@ -94,9 +94,9 @@ int drm_vm_info(struct seq_file *m, void *data)
                else
                        type = types[map->type];
 
-               seq_printf(m, "%4d 0x%08lx 0x%08lx %4.4s  0x%02x 0x%08lx ",
+               seq_printf(m, "%4d 0x%016llx 0x%08lx %4.4s  0x%02x 0x%08lx ",
                           i,
-                          map->offset,
+                          (unsigned long long)map->offset,
                           map->size, type, map->flags,
                           (unsigned long) r_list->user_token);
                if (map->mtrr < 0)
index 920b72fbc958f30eb097f7effcbb7935a881dfe4..282d9fdf9f4efadce5ac77a59e34f1aa71d071fb 100644 (file)
@@ -954,6 +954,7 @@ static int compat_drm_sg_free(struct file *file, unsigned int cmd,
                         DRM_IOCTL_SG_FREE, (unsigned long)request);
 }
 
+#if defined(CONFIG_X86) || defined(CONFIG_IA64)
 typedef struct drm_update_draw32 {
        drm_drawable_t handle;
        unsigned int type;
@@ -984,6 +985,7 @@ static int compat_drm_update_draw(struct file *file, unsigned int cmd,
                        DRM_IOCTL_UPDATE_DRAW, (unsigned long)request);
        return err;
 }
+#endif
 
 struct drm_wait_vblank_request32 {
        enum drm_vblank_seq_type type;
@@ -1066,7 +1068,9 @@ drm_ioctl_compat_t *drm_compat_ioctls[] = {
 #endif
        [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC32)] = compat_drm_sg_alloc,
        [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE32)] = compat_drm_sg_free,
+#if defined(CONFIG_X86) || defined(CONFIG_IA64)
        [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW32)] = compat_drm_update_draw,
+#endif
        [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK32)] = compat_drm_wait_vblank,
 };
 
index bcc869bc409260c2add316ecead05fb68568d747..0c707f533eab16604dd8235c61220914c3cd886c 100644 (file)
@@ -159,7 +159,7 @@ static inline void *agp_remap(unsigned long offset, unsigned long size,
 
 #endif                         /* debug_memory */
 
-void drm_core_ioremap(struct drm_map *map, struct drm_device *dev)
+void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev)
 {
        if (drm_core_has_AGP(dev) &&
            dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
@@ -169,7 +169,7 @@ void drm_core_ioremap(struct drm_map *map, struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_core_ioremap);
 
-void drm_core_ioremap_wc(struct drm_map *map, struct drm_device *dev)
+void drm_core_ioremap_wc(struct drm_local_map *map, struct drm_device *dev)
 {
        if (drm_core_has_AGP(dev) &&
            dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
@@ -179,7 +179,7 @@ void drm_core_ioremap_wc(struct drm_map *map, struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_core_ioremap_wc);
 
-void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev)
+void drm_core_ioremapfree(struct drm_local_map *map, struct drm_device *dev)
 {
        if (!map->handle || !map->size)
                return;
index 9b3c5af61e98f4b8173421f28b1ce93827135fe7..bae5391165ac838e058ee7c9667261651e548e16 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/seq_file.h>
 #include "drmP.h"
 
-
 /***************************************************
  * Initialization, etc.
  **************************************************/
index 48f33be8fd0fd649776e0e2e75280de3ebc2d81e..d009661781bcd9a3207032a0dad312eb01123ce8 100644 (file)
@@ -381,6 +381,7 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
        }
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               pci_set_drvdata(pdev, dev);
                ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
                if (ret)
                        goto err_g2;
@@ -404,9 +405,9 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
 
        list_add_tail(&dev->driver_item, &driver->device_list);
 
-       DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+       DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
                 driver->name, driver->major, driver->minor, driver->patchlevel,
-                driver->date, dev->primary->index);
+                driver->date, pci_name(pdev), dev->primary->index);
 
        return 0;
 
@@ -418,29 +419,7 @@ err_g1:
        drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
        return ret;
 }
-
-/**
- * Put a device minor number.
- *
- * \param dev device data structure
- * \return always zero
- *
- * Cleans up the proc resources. If it is the last minor then release the foreign
- * "drm" data, otherwise unregisters the "drm" data, frees the dev list and
- * unregisters the character device.
- */
-int drm_put_dev(struct drm_device * dev)
-{
-       DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name);
-
-       if (dev->devname) {
-               drm_free(dev->devname, strlen(dev->devname) + 1,
-                        DRM_MEM_DRIVER);
-               dev->devname = NULL;
-       }
-       drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
-       return 0;
-}
+EXPORT_SYMBOL(drm_get_dev);
 
 /**
  * Put a secondary minor number.
@@ -472,3 +451,67 @@ int drm_put_minor(struct drm_minor **minor_p)
        *minor_p = NULL;
        return 0;
 }
+
+/**
+ * Called via drm_exit() at module unload time or when pci device is
+ * unplugged.
+ *
+ * Cleans up all DRM device, calling drm_lastclose().
+ *
+ * \sa drm_init
+ */
+void drm_put_dev(struct drm_device *dev)
+{
+       struct drm_driver *driver = dev->driver;
+       struct drm_map_list *r_list, *list_temp;
+
+       DRM_DEBUG("\n");
+
+       if (!dev) {
+               DRM_ERROR("cleanup called no dev\n");
+               return;
+       }
+
+       drm_vblank_cleanup(dev);
+
+       drm_lastclose(dev);
+
+       if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
+           dev->agp && dev->agp->agp_mtrr >= 0) {
+               int retval;
+               retval = mtrr_del(dev->agp->agp_mtrr,
+                                 dev->agp->agp_info.aper_base,
+                                 dev->agp->agp_info.aper_size * 1024 * 1024);
+               DRM_DEBUG("mtrr_del=%d\n", retval);
+       }
+
+       if (dev->driver->unload)
+               dev->driver->unload(dev);
+
+       if (drm_core_has_AGP(dev) && dev->agp) {
+               drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
+               dev->agp = NULL;
+       }
+
+       drm_ht_remove(&dev->map_hash);
+       drm_ctxbitmap_cleanup(dev);
+
+       list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
+               drm_rmmap(dev, r_list->map);
+
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               drm_put_minor(&dev->control);
+
+       if (driver->driver_features & DRIVER_GEM)
+               drm_gem_destroy(dev);
+
+       drm_put_minor(&dev->primary);
+
+       if (dev->devname) {
+               drm_free(dev->devname, strlen(dev->devname) + 1,
+                        DRM_MEM_DRIVER);
+               dev->devname = NULL;
+       }
+       drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
+}
+EXPORT_SYMBOL(drm_put_dev);
index 186d08159d4871560291e8cf8eccfffd6ebcfa0e..5de573a981cb19d5da7789270bfd0b05bdf8006f 100644 (file)
@@ -35,7 +35,9 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
        struct drm_minor *drm_minor = to_drm_minor(dev);
        struct drm_device *drm_dev = drm_minor->dev;
 
-       if (drm_minor->type == DRM_MINOR_LEGACY && drm_dev->driver->suspend)
+       if (drm_minor->type == DRM_MINOR_LEGACY &&
+           !drm_core_check_feature(drm_dev, DRIVER_MODESET) &&
+           drm_dev->driver->suspend)
                return drm_dev->driver->suspend(drm_dev, state);
 
        return 0;
@@ -53,7 +55,9 @@ static int drm_sysfs_resume(struct device *dev)
        struct drm_minor *drm_minor = to_drm_minor(dev);
        struct drm_device *drm_dev = drm_minor->dev;
 
-       if (drm_minor->type == DRM_MINOR_LEGACY && drm_dev->driver->resume)
+       if (drm_minor->type == DRM_MINOR_LEGACY &&
+           !drm_core_check_feature(drm_dev, DRIVER_MODESET) &&
+           drm_dev->driver->resume)
                return drm_dev->driver->resume(drm_dev);
 
        return 0;
@@ -118,20 +122,6 @@ void drm_sysfs_destroy(void)
        class_destroy(drm_class);
 }
 
-static ssize_t show_dri(struct device *device, struct device_attribute *attr,
-                       char *buf)
-{
-       struct drm_minor *drm_minor = to_drm_minor(device);
-       struct drm_device *drm_dev = drm_minor->dev;
-       if (drm_dev->driver->dri_library_name)
-               return drm_dev->driver->dri_library_name(drm_dev, buf);
-       return snprintf(buf, PAGE_SIZE, "%s\n", drm_dev->driver->pci_driver.name);
-}
-
-static struct device_attribute device_attrs[] = {
-       __ATTR(dri_library_name, S_IRUGO, show_dri, NULL),
-};
-
 /**
  * drm_sysfs_device_release - do nothing
  * @dev: Linux device
@@ -474,7 +464,6 @@ void drm_sysfs_hotplug_event(struct drm_device *dev)
 int drm_sysfs_device_add(struct drm_minor *minor)
 {
        int err;
-       int i, j;
        char *minor_str;
 
        minor->kdev.parent = &minor->dev->pdev->dev;
@@ -496,18 +485,8 @@ int drm_sysfs_device_add(struct drm_minor *minor)
                goto err_out;
        }
 
-       for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
-               err = device_create_file(&minor->kdev, &device_attrs[i]);
-               if (err)
-                       goto err_out_files;
-       }
-
        return 0;
 
-err_out_files:
-       if (i > 0)
-               for (j = 0; j < i; j++)
-                       device_remove_file(&minor->kdev, &device_attrs[j]);
        device_unregister(&minor->kdev);
 err_out:
 
@@ -523,9 +502,5 @@ err_out:
  */
 void drm_sysfs_device_remove(struct drm_minor *minor)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
-               device_remove_file(&minor->kdev, &device_attrs[i]);
        device_unregister(&minor->kdev);
 }
index 3ffae021d28052173898a3ed449adbc6e96d61d1..22f76567ac7d8fa40cee2180d36084f62cb8f0e3 100644 (file)
@@ -91,7 +91,7 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct drm_file *priv = vma->vm_file->private_data;
        struct drm_device *dev = priv->minor->dev;
-       struct drm_map *map = NULL;
+       struct drm_local_map *map = NULL;
        struct drm_map_list *r_list;
        struct drm_hash_item *hash;
 
@@ -115,9 +115,9 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                 * Using vm_pgoff as a selector forces us to use this unusual
                 * addressing scheme.
                 */
-               unsigned long offset = (unsigned long)vmf->virtual_address -
-                                                               vma->vm_start;
-               unsigned long baddr = map->offset + offset;
+               resource_size_t offset = (unsigned long)vmf->virtual_address -
+                       vma->vm_start;
+               resource_size_t baddr = map->offset + offset;
                struct drm_agp_mem *agpmem;
                struct page *page;
 
@@ -149,8 +149,10 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                vmf->page = page;
 
                DRM_DEBUG
-                   ("baddr = 0x%lx page = 0x%p, offset = 0x%lx, count=%d\n",
-                    baddr, __va(agpmem->memory->memory[offset]), offset,
+                   ("baddr = 0x%llx page = 0x%p, offset = 0x%llx, count=%d\n",
+                    (unsigned long long)baddr,
+                    __va(agpmem->memory->memory[offset]),
+                    (unsigned long long)offset,
                     page_count(page));
                return 0;
        }
@@ -176,7 +178,7 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
  */
 static int drm_do_vm_shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
-       struct drm_map *map = (struct drm_map *) vma->vm_private_data;
+       struct drm_local_map *map = vma->vm_private_data;
        unsigned long offset;
        unsigned long i;
        struct page *page;
@@ -209,7 +211,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
        struct drm_file *priv = vma->vm_file->private_data;
        struct drm_device *dev = priv->minor->dev;
        struct drm_vma_entry *pt, *temp;
-       struct drm_map *map;
+       struct drm_local_map *map;
        struct drm_map_list *r_list;
        int found_maps = 0;
 
@@ -322,7 +324,7 @@ static int drm_do_vm_dma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
  */
 static int drm_do_vm_sg_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
-       struct drm_map *map = (struct drm_map *) vma->vm_private_data;
+       struct drm_local_map *map = vma->vm_private_data;
        struct drm_file *priv = vma->vm_file->private_data;
        struct drm_device *dev = priv->minor->dev;
        struct drm_sg_mem *entry = dev->sg;
@@ -512,14 +514,14 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
        return 0;
 }
 
-unsigned long drm_core_get_map_ofs(struct drm_map * map)
+resource_size_t drm_core_get_map_ofs(struct drm_local_map * map)
 {
        return map->offset;
 }
 
 EXPORT_SYMBOL(drm_core_get_map_ofs);
 
-unsigned long drm_core_get_reg_ofs(struct drm_device *dev)
+resource_size_t drm_core_get_reg_ofs(struct drm_device *dev)
 {
 #ifdef __alpha__
        return dev->hose->dense_mem_base - dev->hose->mem_space->start;
@@ -547,8 +549,8 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
 {
        struct drm_file *priv = filp->private_data;
        struct drm_device *dev = priv->minor->dev;
-       struct drm_map *map = NULL;
-       unsigned long offset = 0;
+       struct drm_local_map *map = NULL;
+       resource_size_t offset = 0;
        struct drm_hash_item *hash;
 
        DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
@@ -623,9 +625,9 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
                                       vma->vm_page_prot))
                        return -EAGAIN;
                DRM_DEBUG("   Type = %d; start = 0x%lx, end = 0x%lx,"
-                         " offset = 0x%lx\n",
+                         " offset = 0x%llx\n",
                          map->type,
-                         vma->vm_start, vma->vm_end, map->offset + offset);
+                         vma->vm_start, vma->vm_end, (unsigned long long)(map->offset + offset));
                vma->vm_ops = &drm_vm_ops;
                break;
        case _DRM_CONSISTENT:
index 0118849a567218632bc954e03c2c283a9d37e6a4..21e2691f28f953c2ab84234b65c4bae0a1bc11bb 100644 (file)
@@ -77,8 +77,8 @@ typedef struct _drm_i810_ring_buffer {
 } drm_i810_ring_buffer_t;
 
 typedef struct drm_i810_private {
-       struct drm_map *sarea_map;
-       struct drm_map *mmio_map;
+       struct drm_local_map *sarea_map;
+       struct drm_local_map *mmio_map;
 
        drm_i810_sarea_t *sarea_priv;
        drm_i810_ring_buffer_t ring;
index b5bf8cc0fdaa5845387962584ef92af28b78011a..da82afe4ded5664734bc8869b055206dcb245a1c 100644 (file)
@@ -84,8 +84,8 @@ typedef struct _drm_i830_ring_buffer {
 } drm_i830_ring_buffer_t;
 
 typedef struct drm_i830_private {
-       struct drm_map *sarea_map;
-       struct drm_map *mmio_map;
+       struct drm_local_map *sarea_map;
+       struct drm_local_map *mmio_map;
 
        drm_i830_sarea_t *sarea_priv;
        drm_i830_ring_buffer_t ring;
index a818b377e1f73207e6e25c35d09babe0d0b82a1f..85549f615b1f23560f78831c550c3d1747a4358f 100644 (file)
@@ -1099,7 +1099,7 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master)
 int i915_driver_load(struct drm_device *dev, unsigned long flags)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long base, size;
+       resource_size_t base, size;
        int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1;
 
        /* i915 has 4 more counters */
index dcb91f5df6e33037f189d956ea8dfd09bd5c3fd9..2c016769345020b58a9e49f525308a7af9ad3b04 100644 (file)
@@ -42,6 +42,8 @@ module_param_named(modeset, i915_modeset, int, 0400);
 unsigned int i915_fbpercrtc = 0;
 module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
 
+static struct drm_driver driver;
+
 static struct pci_device_id pciidlist[] = {
        i915_PCI_IDS
 };
@@ -117,6 +119,36 @@ static int i915_resume(struct drm_device *dev)
        return ret;
 }
 
+static int __devinit
+i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       return drm_get_dev(pdev, ent, &driver);
+}
+
+static void
+i915_pci_remove(struct pci_dev *pdev)
+{
+       struct drm_device *dev = pci_get_drvdata(pdev);
+
+       drm_put_dev(dev);
+}
+
+static int
+i915_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct drm_device *dev = pci_get_drvdata(pdev);
+
+       return i915_suspend(dev, state);
+}
+
+static int
+i915_pci_resume(struct pci_dev *pdev)
+{
+       struct drm_device *dev = pci_get_drvdata(pdev);
+
+       return i915_resume(dev);
+}
+
 static struct vm_operations_struct i915_gem_vm_ops = {
        .fault = i915_gem_fault,
        .open = drm_gem_vm_open,
@@ -174,6 +206,12 @@ static struct drm_driver driver = {
        .pci_driver = {
                 .name = DRIVER_NAME,
                 .id_table = pciidlist,
+                .probe = i915_pci_probe,
+                .remove = i915_pci_remove,
+#ifdef CONFIG_PM
+                .resume = i915_pci_resume,
+                .suspend = i915_pci_suspend,
+#endif
        },
 
        .name = DRIVER_NAME,
index b52cba0f16d2c6339fd875adeecc1f46078328b4..e0389ad1477d22f48d24931509fd522f4ac1b6ff 100644 (file)
@@ -446,13 +446,16 @@ fast_shmem_write(struct page **pages,
                 int length)
 {
        char __iomem *vaddr;
+       unsigned long unwritten;
 
        vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT], KM_USER0);
        if (vaddr == NULL)
                return -ENOMEM;
-       __copy_from_user_inatomic(vaddr + page_offset, data, length);
+       unwritten = __copy_from_user_inatomic(vaddr + page_offset, data, length);
        kunmap_atomic(vaddr, KM_USER0);
 
+       if (unwritten)
+               return -EFAULT;
        return 0;
 }
 
@@ -1093,7 +1096,7 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj)
        struct drm_gem_mm *mm = dev->mm_private;
        struct drm_i915_gem_object *obj_priv = obj->driver_private;
        struct drm_map_list *list;
-       struct drm_map *map;
+       struct drm_local_map *map;
        int ret = 0;
 
        /* Set the object up for mmap'ing */
index b49c5ff29585d3533b9b915b6c65cc5f9904c68f..7a6bf9ffc5a30dff795e33cda956da8243c4ef4a 100644 (file)
@@ -148,8 +148,8 @@ void mga_do_dma_flush(drm_mga_private_t * dev_priv)
                primary->space = head - tail;
        }
 
-       DRM_DEBUG("   head = 0x%06lx\n", head - dev_priv->primary->offset);
-       DRM_DEBUG("   tail = 0x%06lx\n", tail - dev_priv->primary->offset);
+       DRM_DEBUG("   head = 0x%06lx\n", (unsigned long)(head - dev_priv->primary->offset));
+       DRM_DEBUG("   tail = 0x%06lx\n", (unsigned long)(tail - dev_priv->primary->offset));
        DRM_DEBUG("  space = 0x%06x\n", primary->space);
 
        mga_flush_write_combine();
@@ -187,7 +187,7 @@ void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv)
                primary->space = head - dev_priv->primary->offset;
        }
 
-       DRM_DEBUG("   head = 0x%06lx\n", head - dev_priv->primary->offset);
+       DRM_DEBUG("   head = 0x%06lx\n", (unsigned long)(head - dev_priv->primary->offset));
        DRM_DEBUG("   tail = 0x%06x\n", primary->tail);
        DRM_DEBUG("   wrap = %d\n", primary->last_wrap);
        DRM_DEBUG("  space = 0x%06x\n", primary->space);
@@ -239,7 +239,7 @@ static void mga_freelist_print(struct drm_device * dev)
        for (entry = dev_priv->head->next; entry; entry = entry->next) {
                DRM_INFO("   %p   idx=%2d  age=0x%x 0x%06lx\n",
                         entry, entry->buf->idx, entry->age.head,
-                        entry->age.head - dev_priv->primary->offset);
+                        (unsigned long)(entry->age.head - dev_priv->primary->offset));
        }
        DRM_INFO("\n");
 }
@@ -340,10 +340,10 @@ static struct drm_buf *mga_freelist_get(struct drm_device * dev)
 
        DRM_DEBUG("   tail=0x%06lx %d\n",
                  tail->age.head ?
-                 tail->age.head - dev_priv->primary->offset : 0,
+                 (unsigned long)(tail->age.head - dev_priv->primary->offset) : 0,
                  tail->age.wrap);
        DRM_DEBUG("   head=0x%06lx %d\n",
-                 head - dev_priv->primary->offset, wrap);
+                 (unsigned long)(head - dev_priv->primary->offset), wrap);
 
        if (TEST_AGE(&tail->age, head, wrap)) {
                prev = dev_priv->tail->prev;
@@ -366,8 +366,9 @@ int mga_freelist_put(struct drm_device * dev, struct drm_buf * buf)
        drm_mga_freelist_t *head, *entry, *prev;
 
        DRM_DEBUG("age=0x%06lx wrap=%d\n",
-                 buf_priv->list_entry->age.head -
-                 dev_priv->primary->offset, buf_priv->list_entry->age.wrap);
+                 (unsigned long)(buf_priv->list_entry->age.head -
+                                 dev_priv->primary->offset),
+                 buf_priv->list_entry->age.wrap);
 
        entry = buf_priv->list_entry;
        head = dev_priv->head;
index 88257c276eb9f640f4d5b3399acfe099900ed569..3d264f288237451857505c0136423698764ee36c 100644 (file)
@@ -113,8 +113,8 @@ typedef struct drm_mga_private {
         * \sa drm_mga_private_t::mmio
         */
        /*@{ */
-       u32 mmio_base;             /**< Bus address of base of MMIO. */
-       u32 mmio_size;             /**< Size of the MMIO region. */
+       resource_size_t mmio_base;         /**< Bus address of base of MMIO. */
+       resource_size_t mmio_size;         /**< Size of the MMIO region. */
        /*@} */
 
        u32 clear_cmd;
@@ -317,8 +317,8 @@ do {                                                                        \
                DRM_INFO( "\n" );                                       \
                DRM_INFO( "   tail=0x%06x head=0x%06lx\n",              \
                          dev_priv->prim.tail,                          \
-                         MGA_READ( MGA_PRIMADDRESS ) -                 \
-                         dev_priv->primary->offset );                  \
+                         (unsigned long)(MGA_READ(MGA_PRIMADDRESS) -   \
+                                         dev_priv->primary->offset));  \
        }                                                               \
        if ( !test_bit( 0, &dev_priv->prim.wrapped ) ) {                \
                if ( dev_priv->prim.space <                             \
index c31afbde62e72d8fdadb31b5255a34918c64d2f1..32de4cedc3631e7c2d3419b5f9a8f5fc977321fb 100644 (file)
@@ -525,11 +525,12 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
        } else
 #endif
        {
-               dev_priv->cce_ring->handle = (void *)dev_priv->cce_ring->offset;
+               dev_priv->cce_ring->handle =
+                       (void *)(unsigned long)dev_priv->cce_ring->offset;
                dev_priv->ring_rptr->handle =
-                   (void *)dev_priv->ring_rptr->offset;
+                       (void *)(unsigned long)dev_priv->ring_rptr->offset;
                dev->agp_buffer_map->handle =
-                   (void *)dev->agp_buffer_map->offset;
+                       (void *)(unsigned long)dev->agp_buffer_map->offset;
        }
 
 #if __OS_HAS_AGP
index feb521ebc3935522d869de263927151c763a1424..52ce439a0f2e77d5562056b6f58180cc90e7e5ca 100644 (file)
@@ -3,7 +3,7 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 ccflags-y := -Iinclude/drm
-radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o
+radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o r600_cp.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 
index cace3964feebb4288dae0a822bb03284043ffda7..cb2e470f97d4d100e073cf953b170a72ae1d6d51 100644 (file)
@@ -37,6 +37,8 @@
 #include "radeon_drv.h"
 #include "r300_reg.h"
 
+#include <asm/unaligned.h>
+
 #define R300_SIMULTANEOUS_CLIPRECTS            4
 
 /* Values for R300_RE_CLIPRECT_CNTL depending on the number of cliprects
@@ -205,6 +207,10 @@ void r300_init_reg_flags(struct drm_device *dev)
        ADD_RANGE(0x42C0, 2);
        ADD_RANGE(R300_RS_CNTL_0, 2);
 
+       ADD_RANGE(R300_SU_REG_DEST, 1);
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV530)
+               ADD_RANGE(RV530_FG_ZBREG_DEST, 1);
+
        ADD_RANGE(R300_SC_HYPERZ, 2);
        ADD_RANGE(0x43E8, 1);
 
@@ -230,6 +236,7 @@ void r300_init_reg_flags(struct drm_device *dev)
        ADD_RANGE(R300_ZB_DEPTHPITCH, 1);
        ADD_RANGE(R300_ZB_DEPTHCLEARVALUE, 1);
        ADD_RANGE(R300_ZB_ZMASK_OFFSET, 13);
+       ADD_RANGE(R300_ZB_ZPASS_DATA, 2); /* ZB_ZPASS_DATA, ZB_ZPASS_ADDR */
 
        ADD_RANGE(R300_TX_FILTER_0, 16);
        ADD_RANGE(R300_TX_FILTER1_0, 16);
@@ -917,6 +924,7 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
 {
        u32 *ref_age_base;
        u32 i, buf_idx, h_pending;
+       u64 ptr_addr;
        RING_LOCALS;
 
        if (cmdbuf->bufsz <
@@ -930,7 +938,8 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
 
        dev_priv->scratch_ages[header.scratch.reg]++;
 
-       ref_age_base =  (u32 *)(unsigned long)*((uint64_t *)cmdbuf->buf);
+       ptr_addr = get_unaligned((u64 *)cmdbuf->buf);
+       ref_age_base = (u32 *)(unsigned long)ptr_addr;
 
        cmdbuf->buf += sizeof(u64);
        cmdbuf->bufsz -= sizeof(u64);
index ee6f811599a3c15c1a4b83103e59609750c2dfaa..bdbc95fa6721907e26d7f53a40a6e1f59657f39b 100644 (file)
@@ -1770,4 +1770,9 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #define R500_RB3D_COLOR_CLEAR_VALUE_AR  0x46c0
 #define R500_RB3D_CONSTANT_COLOR_AR     0x4ef8
 
+#define R300_SU_REG_DEST                0x42c8
+#define RV530_FG_ZBREG_DEST             0x4be8
+#define R300_ZB_ZPASS_DATA              0x4f58
+#define R300_ZB_ZPASS_ADDR              0x4f5c
+
 #endif /* _R300_REG_H */
diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c
new file mode 100644 (file)
index 0000000..9d14eee
--- /dev/null
@@ -0,0 +1,2253 @@
+/*
+ * Copyright 2008-2009 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Dave Airlie <airlied@redhat.com>
+ *     Alex Deucher <alexander.deucher@amd.com>
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_drm.h"
+#include "radeon_drv.h"
+
+#include "r600_microcode.h"
+
+# define ATI_PCIGART_PAGE_SIZE         4096    /**< PCI GART page size */
+# define ATI_PCIGART_PAGE_MASK         (~(ATI_PCIGART_PAGE_SIZE-1))
+
+#define R600_PTE_VALID     (1 << 0)
+#define R600_PTE_SYSTEM    (1 << 1)
+#define R600_PTE_SNOOPED   (1 << 2)
+#define R600_PTE_READABLE  (1 << 5)
+#define R600_PTE_WRITEABLE (1 << 6)
+
+/* MAX values used for gfx init */
+#define R6XX_MAX_SH_GPRS           256
+#define R6XX_MAX_TEMP_GPRS         16
+#define R6XX_MAX_SH_THREADS        256
+#define R6XX_MAX_SH_STACK_ENTRIES  4096
+#define R6XX_MAX_BACKENDS          8
+#define R6XX_MAX_BACKENDS_MASK     0xff
+#define R6XX_MAX_SIMDS             8
+#define R6XX_MAX_SIMDS_MASK        0xff
+#define R6XX_MAX_PIPES             8
+#define R6XX_MAX_PIPES_MASK        0xff
+
+#define R7XX_MAX_SH_GPRS           256
+#define R7XX_MAX_TEMP_GPRS         16
+#define R7XX_MAX_SH_THREADS        256
+#define R7XX_MAX_SH_STACK_ENTRIES  4096
+#define R7XX_MAX_BACKENDS          8
+#define R7XX_MAX_BACKENDS_MASK     0xff
+#define R7XX_MAX_SIMDS             16
+#define R7XX_MAX_SIMDS_MASK        0xffff
+#define R7XX_MAX_PIPES             8
+#define R7XX_MAX_PIPES_MASK        0xff
+
+static int r600_do_wait_for_fifo(drm_radeon_private_t *dev_priv, int entries)
+{
+       int i;
+
+       dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
+
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               int slots;
+               if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
+                       slots = (RADEON_READ(R600_GRBM_STATUS)
+                                & R700_CMDFIFO_AVAIL_MASK);
+               else
+                       slots = (RADEON_READ(R600_GRBM_STATUS)
+                                & R600_CMDFIFO_AVAIL_MASK);
+               if (slots >= entries)
+                       return 0;
+               DRM_UDELAY(1);
+       }
+       DRM_INFO("wait for fifo failed status : 0x%08X 0x%08X\n",
+                RADEON_READ(R600_GRBM_STATUS),
+                RADEON_READ(R600_GRBM_STATUS2));
+
+       return -EBUSY;
+}
+
+static int r600_do_wait_for_idle(drm_radeon_private_t *dev_priv)
+{
+       int i, ret;
+
+       dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
+
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
+               ret = r600_do_wait_for_fifo(dev_priv, 8);
+       else
+               ret = r600_do_wait_for_fifo(dev_priv, 16);
+       if (ret)
+               return ret;
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               if (!(RADEON_READ(R600_GRBM_STATUS) & R600_GUI_ACTIVE))
+                       return 0;
+               DRM_UDELAY(1);
+       }
+       DRM_INFO("wait idle failed status : 0x%08X 0x%08X\n",
+                RADEON_READ(R600_GRBM_STATUS),
+                RADEON_READ(R600_GRBM_STATUS2));
+
+       return -EBUSY;
+}
+
+void r600_page_table_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info)
+{
+       struct drm_sg_mem *entry = dev->sg;
+       int max_pages;
+       int pages;
+       int i;
+
+       if (!entry)
+               return;
+
+       if (gart_info->bus_addr) {
+               max_pages = (gart_info->table_size / sizeof(u64));
+               pages = (entry->pages <= max_pages)
+                 ? entry->pages : max_pages;
+
+               for (i = 0; i < pages; i++) {
+                       if (!entry->busaddr[i])
+                               break;
+                       pci_unmap_page(dev->pdev, entry->busaddr[i],
+                                      PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+               }
+               if (gart_info->gart_table_location == DRM_ATI_GART_MAIN)
+                       gart_info->bus_addr = 0;
+       }
+}
+
+/* R600 has page table setup */
+int r600_page_table_init(struct drm_device *dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       struct drm_ati_pcigart_info *gart_info = &dev_priv->gart_info;
+       struct drm_local_map *map = &gart_info->mapping;
+       struct drm_sg_mem *entry = dev->sg;
+       int ret = 0;
+       int i, j;
+       int pages;
+       u64 page_base;
+       dma_addr_t entry_addr;
+       int max_ati_pages, max_real_pages, gart_idx;
+
+       /* okay page table is available - lets rock */
+       max_ati_pages = (gart_info->table_size / sizeof(u64));
+       max_real_pages = max_ati_pages / (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE);
+
+       pages = (entry->pages <= max_real_pages) ?
+               entry->pages : max_real_pages;
+
+       memset_io((void __iomem *)map->handle, 0, max_ati_pages * sizeof(u64));
+
+       gart_idx = 0;
+       for (i = 0; i < pages; i++) {
+               entry->busaddr[i] = pci_map_page(dev->pdev,
+                                                entry->pagelist[i], 0,
+                                                PAGE_SIZE,
+                                                PCI_DMA_BIDIRECTIONAL);
+               if (entry->busaddr[i] == 0) {
+                       DRM_ERROR("unable to map PCIGART pages!\n");
+                       r600_page_table_cleanup(dev, gart_info);
+                       goto done;
+               }
+               entry_addr = entry->busaddr[i];
+               for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
+                       page_base = (u64) entry_addr & ATI_PCIGART_PAGE_MASK;
+                       page_base |= R600_PTE_VALID | R600_PTE_SYSTEM | R600_PTE_SNOOPED;
+                       page_base |= R600_PTE_READABLE | R600_PTE_WRITEABLE;
+
+                       DRM_WRITE64(map, gart_idx * sizeof(u64), page_base);
+
+                       gart_idx++;
+
+                       if ((i % 128) == 0)
+                               DRM_DEBUG("page entry %d: 0x%016llx\n",
+                                   i, (unsigned long long)page_base);
+                       entry_addr += ATI_PCIGART_PAGE_SIZE;
+               }
+       }
+       ret = 1;
+done:
+       return ret;
+}
+
+static void r600_vm_flush_gart_range(struct drm_device *dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       u32 resp, countdown = 1000;
+       RADEON_WRITE(R600_VM_CONTEXT0_INVALIDATION_LOW_ADDR, dev_priv->gart_vm_start >> 12);
+       RADEON_WRITE(R600_VM_CONTEXT0_INVALIDATION_HIGH_ADDR, (dev_priv->gart_vm_start + dev_priv->gart_size - 1) >> 12);
+       RADEON_WRITE(R600_VM_CONTEXT0_REQUEST_RESPONSE, 2);
+
+       do {
+               resp = RADEON_READ(R600_VM_CONTEXT0_REQUEST_RESPONSE);
+               countdown--;
+               DRM_UDELAY(1);
+       } while (((resp & 0xf0) == 0) && countdown);
+}
+
+static void r600_vm_init(struct drm_device *dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       /* initialise the VM to use the page table we constructed up there */
+       u32 vm_c0, i;
+       u32 mc_rd_a;
+       u32 vm_l2_cntl, vm_l2_cntl3;
+       /* okay set up the PCIE aperture type thingo */
+       RADEON_WRITE(R600_MC_VM_SYSTEM_APERTURE_LOW_ADDR, dev_priv->gart_vm_start >> 12);
+       RADEON_WRITE(R600_MC_VM_SYSTEM_APERTURE_HIGH_ADDR, (dev_priv->gart_vm_start + dev_priv->gart_size - 1) >> 12);
+       RADEON_WRITE(R600_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0);
+
+       /* setup MC RD a */
+       mc_rd_a = R600_MCD_L1_TLB | R600_MCD_L1_FRAG_PROC | R600_MCD_SYSTEM_ACCESS_MODE_IN_SYS |
+               R600_MCD_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU | R600_MCD_EFFECTIVE_L1_TLB_SIZE(5) |
+               R600_MCD_EFFECTIVE_L1_QUEUE_SIZE(5) | R600_MCD_WAIT_L2_QUERY;
+
+       RADEON_WRITE(R600_MCD_RD_A_CNTL, mc_rd_a);
+       RADEON_WRITE(R600_MCD_RD_B_CNTL, mc_rd_a);
+
+       RADEON_WRITE(R600_MCD_WR_A_CNTL, mc_rd_a);
+       RADEON_WRITE(R600_MCD_WR_B_CNTL, mc_rd_a);
+
+       RADEON_WRITE(R600_MCD_RD_GFX_CNTL, mc_rd_a);
+       RADEON_WRITE(R600_MCD_WR_GFX_CNTL, mc_rd_a);
+
+       RADEON_WRITE(R600_MCD_RD_SYS_CNTL, mc_rd_a);
+       RADEON_WRITE(R600_MCD_WR_SYS_CNTL, mc_rd_a);
+
+       RADEON_WRITE(R600_MCD_RD_HDP_CNTL, mc_rd_a | R600_MCD_L1_STRICT_ORDERING);
+       RADEON_WRITE(R600_MCD_WR_HDP_CNTL, mc_rd_a /*| R600_MCD_L1_STRICT_ORDERING*/);
+
+       RADEON_WRITE(R600_MCD_RD_PDMA_CNTL, mc_rd_a);
+       RADEON_WRITE(R600_MCD_WR_PDMA_CNTL, mc_rd_a);
+
+       RADEON_WRITE(R600_MCD_RD_SEM_CNTL, mc_rd_a | R600_MCD_SEMAPHORE_MODE);
+       RADEON_WRITE(R600_MCD_WR_SEM_CNTL, mc_rd_a);
+
+       vm_l2_cntl = R600_VM_L2_CACHE_EN | R600_VM_L2_FRAG_PROC | R600_VM_ENABLE_PTE_CACHE_LRU_W;
+       vm_l2_cntl |= R600_VM_L2_CNTL_QUEUE_SIZE(7);
+       RADEON_WRITE(R600_VM_L2_CNTL, vm_l2_cntl);
+
+       RADEON_WRITE(R600_VM_L2_CNTL2, 0);
+       vm_l2_cntl3 = (R600_VM_L2_CNTL3_BANK_SELECT_0(0) |
+                      R600_VM_L2_CNTL3_BANK_SELECT_1(1) |
+                      R600_VM_L2_CNTL3_CACHE_UPDATE_MODE(2));
+       RADEON_WRITE(R600_VM_L2_CNTL3, vm_l2_cntl3);
+
+       vm_c0 = R600_VM_ENABLE_CONTEXT | R600_VM_PAGE_TABLE_DEPTH_FLAT;
+
+       RADEON_WRITE(R600_VM_CONTEXT0_CNTL, vm_c0);
+
+       vm_c0 &= ~R600_VM_ENABLE_CONTEXT;
+
+       /* disable all other contexts */
+       for (i = 1; i < 8; i++)
+               RADEON_WRITE(R600_VM_CONTEXT0_CNTL + (i * 4), vm_c0);
+
+       RADEON_WRITE(R600_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, dev_priv->gart_info.bus_addr >> 12);
+       RADEON_WRITE(R600_VM_CONTEXT0_PAGE_TABLE_START_ADDR, dev_priv->gart_vm_start >> 12);
+       RADEON_WRITE(R600_VM_CONTEXT0_PAGE_TABLE_END_ADDR, (dev_priv->gart_vm_start + dev_priv->gart_size - 1) >> 12);
+
+       r600_vm_flush_gart_range(dev);
+}
+
+/* load r600 microcode */
+static void r600_cp_load_microcode(drm_radeon_private_t *dev_priv)
+{
+       int i;
+
+       r600_do_cp_stop(dev_priv);
+
+       RADEON_WRITE(R600_CP_RB_CNTL,
+                    R600_RB_NO_UPDATE |
+                    R600_RB_BLKSZ(15) |
+                    R600_RB_BUFSZ(3));
+
+       RADEON_WRITE(R600_GRBM_SOFT_RESET, R600_SOFT_RESET_CP);
+       RADEON_READ(R600_GRBM_SOFT_RESET);
+       DRM_UDELAY(15000);
+       RADEON_WRITE(R600_GRBM_SOFT_RESET, 0);
+
+       RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
+
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R600)) {
+               DRM_INFO("Loading R600 CP Microcode\n");
+               for (i = 0; i < PM4_UCODE_SIZE; i++) {
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    R600_cp_microcode[i][0]);
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    R600_cp_microcode[i][1]);
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    R600_cp_microcode[i][2]);
+               }
+
+               RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
+               DRM_INFO("Loading R600 PFP Microcode\n");
+               for (i = 0; i < PFP_UCODE_SIZE; i++)
+                       RADEON_WRITE(R600_CP_PFP_UCODE_DATA, R600_pfp_microcode[i]);
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610)) {
+               DRM_INFO("Loading RV610 CP Microcode\n");
+               for (i = 0; i < PM4_UCODE_SIZE; i++) {
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV610_cp_microcode[i][0]);
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV610_cp_microcode[i][1]);
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV610_cp_microcode[i][2]);
+               }
+
+               RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
+               DRM_INFO("Loading RV610 PFP Microcode\n");
+               for (i = 0; i < PFP_UCODE_SIZE; i++)
+                       RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV610_pfp_microcode[i]);
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV630)) {
+               DRM_INFO("Loading RV630 CP Microcode\n");
+               for (i = 0; i < PM4_UCODE_SIZE; i++) {
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV630_cp_microcode[i][0]);
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV630_cp_microcode[i][1]);
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV630_cp_microcode[i][2]);
+               }
+
+               RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
+               DRM_INFO("Loading RV630 PFP Microcode\n");
+               for (i = 0; i < PFP_UCODE_SIZE; i++)
+                       RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV630_pfp_microcode[i]);
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620)) {
+               DRM_INFO("Loading RV620 CP Microcode\n");
+               for (i = 0; i < PM4_UCODE_SIZE; i++) {
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV620_cp_microcode[i][0]);
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV620_cp_microcode[i][1]);
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV620_cp_microcode[i][2]);
+               }
+
+               RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
+               DRM_INFO("Loading RV620 PFP Microcode\n");
+               for (i = 0; i < PFP_UCODE_SIZE; i++)
+                       RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV620_pfp_microcode[i]);
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV635)) {
+               DRM_INFO("Loading RV635 CP Microcode\n");
+               for (i = 0; i < PM4_UCODE_SIZE; i++) {
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV635_cp_microcode[i][0]);
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV635_cp_microcode[i][1]);
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV635_cp_microcode[i][2]);
+               }
+
+               RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
+               DRM_INFO("Loading RV635 PFP Microcode\n");
+               for (i = 0; i < PFP_UCODE_SIZE; i++)
+                       RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV635_pfp_microcode[i]);
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV670)) {
+               DRM_INFO("Loading RV670 CP Microcode\n");
+               for (i = 0; i < PM4_UCODE_SIZE; i++) {
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV670_cp_microcode[i][0]);
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV670_cp_microcode[i][1]);
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV670_cp_microcode[i][2]);
+               }
+
+               RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
+               DRM_INFO("Loading RV670 PFP Microcode\n");
+               for (i = 0; i < PFP_UCODE_SIZE; i++)
+                       RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV670_pfp_microcode[i]);
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780)) {
+               DRM_INFO("Loading RS780 CP Microcode\n");
+               for (i = 0; i < PM4_UCODE_SIZE; i++) {
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV670_cp_microcode[i][0]);
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV670_cp_microcode[i][1]);
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA,
+                                    RV670_cp_microcode[i][2]);
+               }
+
+               RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
+               DRM_INFO("Loading RS780 PFP Microcode\n");
+               for (i = 0; i < PFP_UCODE_SIZE; i++)
+                       RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV670_pfp_microcode[i]);
+       }
+       RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
+       RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
+       RADEON_WRITE(R600_CP_ME_RAM_RADDR, 0);
+
+}
+
+static void r700_vm_init(struct drm_device *dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       /* initialise the VM to use the page table we constructed up there */
+       u32 vm_c0, i;
+       u32 mc_vm_md_l1;
+       u32 vm_l2_cntl, vm_l2_cntl3;
+       /* okay set up the PCIE aperture type thingo */
+       RADEON_WRITE(R700_MC_VM_SYSTEM_APERTURE_LOW_ADDR, dev_priv->gart_vm_start >> 12);
+       RADEON_WRITE(R700_MC_VM_SYSTEM_APERTURE_HIGH_ADDR, (dev_priv->gart_vm_start + dev_priv->gart_size - 1) >> 12);
+       RADEON_WRITE(R700_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0);
+
+       mc_vm_md_l1 = R700_ENABLE_L1_TLB |
+           R700_ENABLE_L1_FRAGMENT_PROCESSING |
+           R700_SYSTEM_ACCESS_MODE_IN_SYS |
+           R700_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU |
+           R700_EFFECTIVE_L1_TLB_SIZE(5) |
+           R700_EFFECTIVE_L1_QUEUE_SIZE(5);
+
+       RADEON_WRITE(R700_MC_VM_MD_L1_TLB0_CNTL, mc_vm_md_l1);
+       RADEON_WRITE(R700_MC_VM_MD_L1_TLB1_CNTL, mc_vm_md_l1);
+       RADEON_WRITE(R700_MC_VM_MD_L1_TLB2_CNTL, mc_vm_md_l1);
+       RADEON_WRITE(R700_MC_VM_MB_L1_TLB0_CNTL, mc_vm_md_l1);
+       RADEON_WRITE(R700_MC_VM_MB_L1_TLB1_CNTL, mc_vm_md_l1);
+       RADEON_WRITE(R700_MC_VM_MB_L1_TLB2_CNTL, mc_vm_md_l1);
+       RADEON_WRITE(R700_MC_VM_MB_L1_TLB3_CNTL, mc_vm_md_l1);
+
+       vm_l2_cntl = R600_VM_L2_CACHE_EN | R600_VM_L2_FRAG_PROC | R600_VM_ENABLE_PTE_CACHE_LRU_W;
+       vm_l2_cntl |= R700_VM_L2_CNTL_QUEUE_SIZE(7);
+       RADEON_WRITE(R600_VM_L2_CNTL, vm_l2_cntl);
+
+       RADEON_WRITE(R600_VM_L2_CNTL2, 0);
+       vm_l2_cntl3 = R700_VM_L2_CNTL3_BANK_SELECT(0) | R700_VM_L2_CNTL3_CACHE_UPDATE_MODE(2);
+       RADEON_WRITE(R600_VM_L2_CNTL3, vm_l2_cntl3);
+
+       vm_c0 = R600_VM_ENABLE_CONTEXT | R600_VM_PAGE_TABLE_DEPTH_FLAT;
+
+       RADEON_WRITE(R600_VM_CONTEXT0_CNTL, vm_c0);
+
+       vm_c0 &= ~R600_VM_ENABLE_CONTEXT;
+
+       /* disable all other contexts */
+       for (i = 1; i < 8; i++)
+               RADEON_WRITE(R600_VM_CONTEXT0_CNTL + (i * 4), vm_c0);
+
+       RADEON_WRITE(R700_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, dev_priv->gart_info.bus_addr >> 12);
+       RADEON_WRITE(R700_VM_CONTEXT0_PAGE_TABLE_START_ADDR, dev_priv->gart_vm_start >> 12);
+       RADEON_WRITE(R700_VM_CONTEXT0_PAGE_TABLE_END_ADDR, (dev_priv->gart_vm_start + dev_priv->gart_size - 1) >> 12);
+
+       r600_vm_flush_gart_range(dev);
+}
+
+/* load r600 microcode */
+static void r700_cp_load_microcode(drm_radeon_private_t *dev_priv)
+{
+       int i;
+
+       r600_do_cp_stop(dev_priv);
+
+       RADEON_WRITE(R600_CP_RB_CNTL,
+                    R600_RB_NO_UPDATE |
+                    (15 << 8) |
+                    (3 << 0));
+
+       RADEON_WRITE(R600_GRBM_SOFT_RESET, R600_SOFT_RESET_CP);
+       RADEON_READ(R600_GRBM_SOFT_RESET);
+       DRM_UDELAY(15000);
+       RADEON_WRITE(R600_GRBM_SOFT_RESET, 0);
+
+
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV770)) {
+               RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
+               DRM_INFO("Loading RV770 PFP Microcode\n");
+               for (i = 0; i < R700_PFP_UCODE_SIZE; i++)
+                       RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV770_pfp_microcode[i]);
+               RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
+
+               RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
+               DRM_INFO("Loading RV770 CP Microcode\n");
+               for (i = 0; i < R700_PM4_UCODE_SIZE; i++)
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA, RV770_cp_microcode[i]);
+               RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
+
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV730)) {
+               RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
+               DRM_INFO("Loading RV730 PFP Microcode\n");
+               for (i = 0; i < R700_PFP_UCODE_SIZE; i++)
+                       RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV730_pfp_microcode[i]);
+               RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
+
+               RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
+               DRM_INFO("Loading RV730 CP Microcode\n");
+               for (i = 0; i < R700_PM4_UCODE_SIZE; i++)
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA, RV730_cp_microcode[i]);
+               RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
+
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV710)) {
+               RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
+               DRM_INFO("Loading RV710 PFP Microcode\n");
+               for (i = 0; i < R700_PFP_UCODE_SIZE; i++)
+                       RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV710_pfp_microcode[i]);
+               RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
+
+               RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
+               DRM_INFO("Loading RV710 CP Microcode\n");
+               for (i = 0; i < R700_PM4_UCODE_SIZE; i++)
+                       RADEON_WRITE(R600_CP_ME_RAM_DATA, RV710_cp_microcode[i]);
+               RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
+
+       }
+       RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
+       RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
+       RADEON_WRITE(R600_CP_ME_RAM_RADDR, 0);
+
+}
+
+static void r600_test_writeback(drm_radeon_private_t *dev_priv)
+{
+       u32 tmp;
+
+       /* Start with assuming that writeback doesn't work */
+       dev_priv->writeback_works = 0;
+
+       /* Writeback doesn't seem to work everywhere, test it here and possibly
+        * enable it if it appears to work
+        */
+       radeon_write_ring_rptr(dev_priv, R600_SCRATCHOFF(1), 0);
+
+       RADEON_WRITE(R600_SCRATCH_REG1, 0xdeadbeef);
+
+       for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) {
+               u32 val;
+
+               val = radeon_read_ring_rptr(dev_priv, R600_SCRATCHOFF(1));
+               if (val == 0xdeadbeef)
+                       break;
+               DRM_UDELAY(1);
+       }
+
+       if (tmp < dev_priv->usec_timeout) {
+               dev_priv->writeback_works = 1;
+               DRM_INFO("writeback test succeeded in %d usecs\n", tmp);
+       } else {
+               dev_priv->writeback_works = 0;
+               DRM_INFO("writeback test failed\n");
+       }
+       if (radeon_no_wb == 1) {
+               dev_priv->writeback_works = 0;
+               DRM_INFO("writeback forced off\n");
+       }
+
+       if (!dev_priv->writeback_works) {
+               /* Disable writeback to avoid unnecessary bus master transfer */
+               RADEON_WRITE(R600_CP_RB_CNTL, RADEON_READ(R600_CP_RB_CNTL) |
+                            RADEON_RB_NO_UPDATE);
+               RADEON_WRITE(R600_SCRATCH_UMSK, 0);
+       }
+}
+
+int r600_do_engine_reset(struct drm_device *dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       u32 cp_ptr, cp_me_cntl, cp_rb_cntl;
+
+       DRM_INFO("Resetting GPU\n");
+
+       cp_ptr = RADEON_READ(R600_CP_RB_WPTR);
+       cp_me_cntl = RADEON_READ(R600_CP_ME_CNTL);
+       RADEON_WRITE(R600_CP_ME_CNTL, R600_CP_ME_HALT);
+
+       RADEON_WRITE(R600_GRBM_SOFT_RESET, 0x7fff);
+       RADEON_READ(R600_GRBM_SOFT_RESET);
+       DRM_UDELAY(50);
+       RADEON_WRITE(R600_GRBM_SOFT_RESET, 0);
+       RADEON_READ(R600_GRBM_SOFT_RESET);
+
+       RADEON_WRITE(R600_CP_RB_WPTR_DELAY, 0);
+       cp_rb_cntl = RADEON_READ(R600_CP_RB_CNTL);
+       RADEON_WRITE(R600_CP_RB_CNTL, R600_RB_RPTR_WR_ENA);
+
+       RADEON_WRITE(R600_CP_RB_RPTR_WR, cp_ptr);
+       RADEON_WRITE(R600_CP_RB_WPTR, cp_ptr);
+       RADEON_WRITE(R600_CP_RB_CNTL, cp_rb_cntl);
+       RADEON_WRITE(R600_CP_ME_CNTL, cp_me_cntl);
+
+       /* Reset the CP ring */
+       r600_do_cp_reset(dev_priv);
+
+       /* The CP is no longer running after an engine reset */
+       dev_priv->cp_running = 0;
+
+       /* Reset any pending vertex, indirect buffers */
+       radeon_freelist_reset(dev);
+
+       return 0;
+
+}
+
+static u32 r600_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
+                                            u32 num_backends,
+                                            u32 backend_disable_mask)
+{
+       u32 backend_map = 0;
+       u32 enabled_backends_mask;
+       u32 enabled_backends_count;
+       u32 cur_pipe;
+       u32 swizzle_pipe[R6XX_MAX_PIPES];
+       u32 cur_backend;
+       u32 i;
+
+       if (num_tile_pipes > R6XX_MAX_PIPES)
+               num_tile_pipes = R6XX_MAX_PIPES;
+       if (num_tile_pipes < 1)
+               num_tile_pipes = 1;
+       if (num_backends > R6XX_MAX_BACKENDS)
+               num_backends = R6XX_MAX_BACKENDS;
+       if (num_backends < 1)
+               num_backends = 1;
+
+       enabled_backends_mask = 0;
+       enabled_backends_count = 0;
+       for (i = 0; i < R6XX_MAX_BACKENDS; ++i) {
+               if (((backend_disable_mask >> i) & 1) == 0) {
+                       enabled_backends_mask |= (1 << i);
+                       ++enabled_backends_count;
+               }
+               if (enabled_backends_count == num_backends)
+                       break;
+       }
+
+       if (enabled_backends_count == 0) {
+               enabled_backends_mask = 1;
+               enabled_backends_count = 1;
+       }
+
+       if (enabled_backends_count != num_backends)
+               num_backends = enabled_backends_count;
+
+       memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * R6XX_MAX_PIPES);
+       switch (num_tile_pipes) {
+       case 1:
+               swizzle_pipe[0] = 0;
+               break;
+       case 2:
+               swizzle_pipe[0] = 0;
+               swizzle_pipe[1] = 1;
+               break;
+       case 3:
+               swizzle_pipe[0] = 0;
+               swizzle_pipe[1] = 1;
+               swizzle_pipe[2] = 2;
+               break;
+       case 4:
+               swizzle_pipe[0] = 0;
+               swizzle_pipe[1] = 1;
+               swizzle_pipe[2] = 2;
+               swizzle_pipe[3] = 3;
+               break;
+       case 5:
+               swizzle_pipe[0] = 0;
+               swizzle_pipe[1] = 1;
+               swizzle_pipe[2] = 2;
+               swizzle_pipe[3] = 3;
+               swizzle_pipe[4] = 4;
+               break;
+       case 6:
+               swizzle_pipe[0] = 0;
+               swizzle_pipe[1] = 2;
+               swizzle_pipe[2] = 4;
+               swizzle_pipe[3] = 5;
+               swizzle_pipe[4] = 1;
+               swizzle_pipe[5] = 3;
+               break;
+       case 7:
+               swizzle_pipe[0] = 0;
+               swizzle_pipe[1] = 2;
+               swizzle_pipe[2] = 4;
+               swizzle_pipe[3] = 6;
+               swizzle_pipe[4] = 1;
+               swizzle_pipe[5] = 3;
+               swizzle_pipe[6] = 5;
+               break;
+       case 8:
+               swizzle_pipe[0] = 0;
+               swizzle_pipe[1] = 2;
+               swizzle_pipe[2] = 4;
+               swizzle_pipe[3] = 6;
+               swizzle_pipe[4] = 1;
+               swizzle_pipe[5] = 3;
+               swizzle_pipe[6] = 5;
+               swizzle_pipe[7] = 7;
+               break;
+       }
+
+       cur_backend = 0;
+       for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) {
+               while (((1 << cur_backend) & enabled_backends_mask) == 0)
+                       cur_backend = (cur_backend + 1) % R6XX_MAX_BACKENDS;
+
+               backend_map |= (u32)(((cur_backend & 3) << (swizzle_pipe[cur_pipe] * 2)));
+
+               cur_backend = (cur_backend + 1) % R6XX_MAX_BACKENDS;
+       }
+
+       return backend_map;
+}
+
+static int r600_count_pipe_bits(uint32_t val)
+{
+       int i, ret = 0;
+       for (i = 0; i < 32; i++) {
+               ret += val & 1;
+               val >>= 1;
+       }
+       return ret;
+}
+
+static void r600_gfx_init(struct drm_device *dev,
+                         drm_radeon_private_t *dev_priv)
+{
+       int i, j, num_qd_pipes;
+       u32 sx_debug_1;
+       u32 tc_cntl;
+       u32 arb_pop;
+       u32 num_gs_verts_per_thread;
+       u32 vgt_gs_per_es;
+       u32 gs_prim_buffer_depth = 0;
+       u32 sq_ms_fifo_sizes;
+       u32 sq_config;
+       u32 sq_gpr_resource_mgmt_1 = 0;
+       u32 sq_gpr_resource_mgmt_2 = 0;
+       u32 sq_thread_resource_mgmt = 0;
+       u32 sq_stack_resource_mgmt_1 = 0;
+       u32 sq_stack_resource_mgmt_2 = 0;
+       u32 hdp_host_path_cntl;
+       u32 backend_map;
+       u32 gb_tiling_config = 0;
+       u32 cc_rb_backend_disable = 0;
+       u32 cc_gc_shader_pipe_config = 0;
+       u32 ramcfg;
+
+       /* setup chip specs */
+       switch (dev_priv->flags & RADEON_FAMILY_MASK) {
+       case CHIP_R600:
+               dev_priv->r600_max_pipes = 4;
+               dev_priv->r600_max_tile_pipes = 8;
+               dev_priv->r600_max_simds = 4;
+               dev_priv->r600_max_backends = 4;
+               dev_priv->r600_max_gprs = 256;
+               dev_priv->r600_max_threads = 192;
+               dev_priv->r600_max_stack_entries = 256;
+               dev_priv->r600_max_hw_contexts = 8;
+               dev_priv->r600_max_gs_threads = 16;
+               dev_priv->r600_sx_max_export_size = 128;
+               dev_priv->r600_sx_max_export_pos_size = 16;
+               dev_priv->r600_sx_max_export_smx_size = 128;
+               dev_priv->r600_sq_num_cf_insts = 2;
+               break;
+       case CHIP_RV630:
+       case CHIP_RV635:
+               dev_priv->r600_max_pipes = 2;
+               dev_priv->r600_max_tile_pipes = 2;
+               dev_priv->r600_max_simds = 3;
+               dev_priv->r600_max_backends = 1;
+               dev_priv->r600_max_gprs = 128;
+               dev_priv->r600_max_threads = 192;
+               dev_priv->r600_max_stack_entries = 128;
+               dev_priv->r600_max_hw_contexts = 8;
+               dev_priv->r600_max_gs_threads = 4;
+               dev_priv->r600_sx_max_export_size = 128;
+               dev_priv->r600_sx_max_export_pos_size = 16;
+               dev_priv->r600_sx_max_export_smx_size = 128;
+               dev_priv->r600_sq_num_cf_insts = 2;
+               break;
+       case CHIP_RV610:
+       case CHIP_RS780:
+       case CHIP_RV620:
+               dev_priv->r600_max_pipes = 1;
+               dev_priv->r600_max_tile_pipes = 1;
+               dev_priv->r600_max_simds = 2;
+               dev_priv->r600_max_backends = 1;
+               dev_priv->r600_max_gprs = 128;
+               dev_priv->r600_max_threads = 192;
+               dev_priv->r600_max_stack_entries = 128;
+               dev_priv->r600_max_hw_contexts = 4;
+               dev_priv->r600_max_gs_threads = 4;
+               dev_priv->r600_sx_max_export_size = 128;
+               dev_priv->r600_sx_max_export_pos_size = 16;
+               dev_priv->r600_sx_max_export_smx_size = 128;
+               dev_priv->r600_sq_num_cf_insts = 1;
+               break;
+       case CHIP_RV670:
+               dev_priv->r600_max_pipes = 4;
+               dev_priv->r600_max_tile_pipes = 4;
+               dev_priv->r600_max_simds = 4;
+               dev_priv->r600_max_backends = 4;
+               dev_priv->r600_max_gprs = 192;
+               dev_priv->r600_max_threads = 192;
+               dev_priv->r600_max_stack_entries = 256;
+               dev_priv->r600_max_hw_contexts = 8;
+               dev_priv->r600_max_gs_threads = 16;
+               dev_priv->r600_sx_max_export_size = 128;
+               dev_priv->r600_sx_max_export_pos_size = 16;
+               dev_priv->r600_sx_max_export_smx_size = 128;
+               dev_priv->r600_sq_num_cf_insts = 2;
+               break;
+       default:
+               break;
+       }
+
+       /* Initialize HDP */
+       j = 0;
+       for (i = 0; i < 32; i++) {
+               RADEON_WRITE((0x2c14 + j), 0x00000000);
+               RADEON_WRITE((0x2c18 + j), 0x00000000);
+               RADEON_WRITE((0x2c1c + j), 0x00000000);
+               RADEON_WRITE((0x2c20 + j), 0x00000000);
+               RADEON_WRITE((0x2c24 + j), 0x00000000);
+               j += 0x18;
+       }
+
+       RADEON_WRITE(R600_GRBM_CNTL, R600_GRBM_READ_TIMEOUT(0xff));
+
+       /* setup tiling, simd, pipe config */
+       ramcfg = RADEON_READ(R600_RAMCFG);
+
+       switch (dev_priv->r600_max_tile_pipes) {
+       case 1:
+               gb_tiling_config |= R600_PIPE_TILING(0);
+               break;
+       case 2:
+               gb_tiling_config |= R600_PIPE_TILING(1);
+               break;
+       case 4:
+               gb_tiling_config |= R600_PIPE_TILING(2);
+               break;
+       case 8:
+               gb_tiling_config |= R600_PIPE_TILING(3);
+               break;
+       default:
+               break;
+       }
+
+       gb_tiling_config |= R600_BANK_TILING((ramcfg >> R600_NOOFBANK_SHIFT) & R600_NOOFBANK_MASK);
+
+       gb_tiling_config |= R600_GROUP_SIZE(0);
+
+       if (((ramcfg >> R600_NOOFROWS_SHIFT) & R600_NOOFROWS_MASK) > 3) {
+               gb_tiling_config |= R600_ROW_TILING(3);
+               gb_tiling_config |= R600_SAMPLE_SPLIT(3);
+       } else {
+               gb_tiling_config |=
+                       R600_ROW_TILING(((ramcfg >> R600_NOOFROWS_SHIFT) & R600_NOOFROWS_MASK));
+               gb_tiling_config |=
+                       R600_SAMPLE_SPLIT(((ramcfg >> R600_NOOFROWS_SHIFT) & R600_NOOFROWS_MASK));
+       }
+
+       gb_tiling_config |= R600_BANK_SWAPS(1);
+
+       backend_map = r600_get_tile_pipe_to_backend_map(dev_priv->r600_max_tile_pipes,
+                                                       dev_priv->r600_max_backends,
+                                                       (0xff << dev_priv->r600_max_backends) & 0xff);
+       gb_tiling_config |= R600_BACKEND_MAP(backend_map);
+
+       cc_gc_shader_pipe_config =
+               R600_INACTIVE_QD_PIPES((R6XX_MAX_PIPES_MASK << dev_priv->r600_max_pipes) & R6XX_MAX_PIPES_MASK);
+       cc_gc_shader_pipe_config |=
+               R600_INACTIVE_SIMDS((R6XX_MAX_SIMDS_MASK << dev_priv->r600_max_simds) & R6XX_MAX_SIMDS_MASK);
+
+       cc_rb_backend_disable =
+               R600_BACKEND_DISABLE((R6XX_MAX_BACKENDS_MASK << dev_priv->r600_max_backends) & R6XX_MAX_BACKENDS_MASK);
+
+       RADEON_WRITE(R600_GB_TILING_CONFIG,      gb_tiling_config);
+       RADEON_WRITE(R600_DCP_TILING_CONFIG,    (gb_tiling_config & 0xffff));
+       RADEON_WRITE(R600_HDP_TILING_CONFIG,    (gb_tiling_config & 0xffff));
+
+       RADEON_WRITE(R600_CC_RB_BACKEND_DISABLE,      cc_rb_backend_disable);
+       RADEON_WRITE(R600_CC_GC_SHADER_PIPE_CONFIG,   cc_gc_shader_pipe_config);
+       RADEON_WRITE(R600_GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
+
+       num_qd_pipes =
+               R6XX_MAX_BACKENDS - r600_count_pipe_bits(cc_gc_shader_pipe_config & R600_INACTIVE_QD_PIPES_MASK);
+       RADEON_WRITE(R600_VGT_OUT_DEALLOC_CNTL, (num_qd_pipes * 4) & R600_DEALLOC_DIST_MASK);
+       RADEON_WRITE(R600_VGT_VERTEX_REUSE_BLOCK_CNTL, ((num_qd_pipes * 4) - 2) & R600_VTX_REUSE_DEPTH_MASK);
+
+       /* set HW defaults for 3D engine */
+       RADEON_WRITE(R600_CP_QUEUE_THRESHOLDS, (R600_ROQ_IB1_START(0x16) |
+                                               R600_ROQ_IB2_START(0x2b)));
+
+       RADEON_WRITE(R600_CP_MEQ_THRESHOLDS, (R600_MEQ_END(0x40) |
+                                             R600_ROQ_END(0x40)));
+
+       RADEON_WRITE(R600_TA_CNTL_AUX, (R600_DISABLE_CUBE_ANISO |
+                                       R600_SYNC_GRADIENT |
+                                       R600_SYNC_WALKER |
+                                       R600_SYNC_ALIGNER));
+
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV670)
+               RADEON_WRITE(R600_ARB_GDEC_RD_CNTL, 0x00000021);
+
+       sx_debug_1 = RADEON_READ(R600_SX_DEBUG_1);
+       sx_debug_1 |= R600_SMX_EVENT_RELEASE;
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_R600))
+               sx_debug_1 |= R600_ENABLE_NEW_SMX_ADDRESS;
+       RADEON_WRITE(R600_SX_DEBUG_1, sx_debug_1);
+
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R600) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV630) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780))
+               RADEON_WRITE(R600_DB_DEBUG, R600_PREZ_MUST_WAIT_FOR_POSTZ_DONE);
+       else
+               RADEON_WRITE(R600_DB_DEBUG, 0);
+
+       RADEON_WRITE(R600_DB_WATERMARKS, (R600_DEPTH_FREE(4) |
+                                         R600_DEPTH_FLUSH(16) |
+                                         R600_DEPTH_PENDING_FREE(4) |
+                                         R600_DEPTH_CACHELINE_FREE(16)));
+       RADEON_WRITE(R600_PA_SC_MULTI_CHIP_CNTL, 0);
+       RADEON_WRITE(R600_VGT_NUM_INSTANCES, 0);
+
+       RADEON_WRITE(R600_SPI_CONFIG_CNTL, R600_GPR_WRITE_PRIORITY(0));
+       RADEON_WRITE(R600_SPI_CONFIG_CNTL_1, R600_VTX_DONE_DELAY(0));
+
+       sq_ms_fifo_sizes = RADEON_READ(R600_SQ_MS_FIFO_SIZES);
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780)) {
+               sq_ms_fifo_sizes = (R600_CACHE_FIFO_SIZE(0xa) |
+                                   R600_FETCH_FIFO_HIWATER(0xa) |
+                                   R600_DONE_FIFO_HIWATER(0xe0) |
+                                   R600_ALU_UPDATE_FIFO_HIWATER(0x8));
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R600) ||
+                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV630)) {
+               sq_ms_fifo_sizes &= ~R600_DONE_FIFO_HIWATER(0xff);
+               sq_ms_fifo_sizes |= R600_DONE_FIFO_HIWATER(0x4);
+       }
+       RADEON_WRITE(R600_SQ_MS_FIFO_SIZES, sq_ms_fifo_sizes);
+
+       /* SQ_CONFIG, SQ_GPR_RESOURCE_MGMT, SQ_THREAD_RESOURCE_MGMT, SQ_STACK_RESOURCE_MGMT
+        * should be adjusted as needed by the 2D/3D drivers.  This just sets default values
+        */
+       sq_config = RADEON_READ(R600_SQ_CONFIG);
+       sq_config &= ~(R600_PS_PRIO(3) |
+                      R600_VS_PRIO(3) |
+                      R600_GS_PRIO(3) |
+                      R600_ES_PRIO(3));
+       sq_config |= (R600_DX9_CONSTS |
+                     R600_VC_ENABLE |
+                     R600_PS_PRIO(0) |
+                     R600_VS_PRIO(1) |
+                     R600_GS_PRIO(2) |
+                     R600_ES_PRIO(3));
+
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R600) {
+               sq_gpr_resource_mgmt_1 = (R600_NUM_PS_GPRS(124) |
+                                         R600_NUM_VS_GPRS(124) |
+                                         R600_NUM_CLAUSE_TEMP_GPRS(4));
+               sq_gpr_resource_mgmt_2 = (R600_NUM_GS_GPRS(0) |
+                                         R600_NUM_ES_GPRS(0));
+               sq_thread_resource_mgmt = (R600_NUM_PS_THREADS(136) |
+                                          R600_NUM_VS_THREADS(48) |
+                                          R600_NUM_GS_THREADS(4) |
+                                          R600_NUM_ES_THREADS(4));
+               sq_stack_resource_mgmt_1 = (R600_NUM_PS_STACK_ENTRIES(128) |
+                                           R600_NUM_VS_STACK_ENTRIES(128));
+               sq_stack_resource_mgmt_2 = (R600_NUM_GS_STACK_ENTRIES(0) |
+                                           R600_NUM_ES_STACK_ENTRIES(0));
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||
+                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) ||
+                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780)) {
+               /* no vertex cache */
+               sq_config &= ~R600_VC_ENABLE;
+
+               sq_gpr_resource_mgmt_1 = (R600_NUM_PS_GPRS(44) |
+                                         R600_NUM_VS_GPRS(44) |
+                                         R600_NUM_CLAUSE_TEMP_GPRS(2));
+               sq_gpr_resource_mgmt_2 = (R600_NUM_GS_GPRS(17) |
+                                         R600_NUM_ES_GPRS(17));
+               sq_thread_resource_mgmt = (R600_NUM_PS_THREADS(79) |
+                                          R600_NUM_VS_THREADS(78) |
+                                          R600_NUM_GS_THREADS(4) |
+                                          R600_NUM_ES_THREADS(31));
+               sq_stack_resource_mgmt_1 = (R600_NUM_PS_STACK_ENTRIES(40) |
+                                           R600_NUM_VS_STACK_ENTRIES(40));
+               sq_stack_resource_mgmt_2 = (R600_NUM_GS_STACK_ENTRIES(32) |
+                                           R600_NUM_ES_STACK_ENTRIES(16));
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV630) ||
+                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV635)) {
+               sq_gpr_resource_mgmt_1 = (R600_NUM_PS_GPRS(44) |
+                                         R600_NUM_VS_GPRS(44) |
+                                         R600_NUM_CLAUSE_TEMP_GPRS(2));
+               sq_gpr_resource_mgmt_2 = (R600_NUM_GS_GPRS(18) |
+                                         R600_NUM_ES_GPRS(18));
+               sq_thread_resource_mgmt = (R600_NUM_PS_THREADS(79) |
+                                          R600_NUM_VS_THREADS(78) |
+                                          R600_NUM_GS_THREADS(4) |
+                                          R600_NUM_ES_THREADS(31));
+               sq_stack_resource_mgmt_1 = (R600_NUM_PS_STACK_ENTRIES(40) |
+                                           R600_NUM_VS_STACK_ENTRIES(40));
+               sq_stack_resource_mgmt_2 = (R600_NUM_GS_STACK_ENTRIES(32) |
+                                           R600_NUM_ES_STACK_ENTRIES(16));
+       } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV670) {
+               sq_gpr_resource_mgmt_1 = (R600_NUM_PS_GPRS(44) |
+                                         R600_NUM_VS_GPRS(44) |
+                                         R600_NUM_CLAUSE_TEMP_GPRS(2));
+               sq_gpr_resource_mgmt_2 = (R600_NUM_GS_GPRS(17) |
+                                         R600_NUM_ES_GPRS(17));
+               sq_thread_resource_mgmt = (R600_NUM_PS_THREADS(79) |
+                                          R600_NUM_VS_THREADS(78) |
+                                          R600_NUM_GS_THREADS(4) |
+                                          R600_NUM_ES_THREADS(31));
+               sq_stack_resource_mgmt_1 = (R600_NUM_PS_STACK_ENTRIES(64) |
+                                           R600_NUM_VS_STACK_ENTRIES(64));
+               sq_stack_resource_mgmt_2 = (R600_NUM_GS_STACK_ENTRIES(64) |
+                                           R600_NUM_ES_STACK_ENTRIES(64));
+       }
+
+       RADEON_WRITE(R600_SQ_CONFIG, sq_config);
+       RADEON_WRITE(R600_SQ_GPR_RESOURCE_MGMT_1,  sq_gpr_resource_mgmt_1);
+       RADEON_WRITE(R600_SQ_GPR_RESOURCE_MGMT_2,  sq_gpr_resource_mgmt_2);
+       RADEON_WRITE(R600_SQ_THREAD_RESOURCE_MGMT, sq_thread_resource_mgmt);
+       RADEON_WRITE(R600_SQ_STACK_RESOURCE_MGMT_1, sq_stack_resource_mgmt_1);
+       RADEON_WRITE(R600_SQ_STACK_RESOURCE_MGMT_2, sq_stack_resource_mgmt_2);
+
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780))
+               RADEON_WRITE(R600_VGT_CACHE_INVALIDATION, R600_CACHE_INVALIDATION(R600_TC_ONLY));
+       else
+               RADEON_WRITE(R600_VGT_CACHE_INVALIDATION, R600_CACHE_INVALIDATION(R600_VC_AND_TC));
+
+       RADEON_WRITE(R600_PA_SC_AA_SAMPLE_LOCS_2S, (R600_S0_X(0xc) |
+                                                   R600_S0_Y(0x4) |
+                                                   R600_S1_X(0x4) |
+                                                   R600_S1_Y(0xc)));
+       RADEON_WRITE(R600_PA_SC_AA_SAMPLE_LOCS_4S, (R600_S0_X(0xe) |
+                                                   R600_S0_Y(0xe) |
+                                                   R600_S1_X(0x2) |
+                                                   R600_S1_Y(0x2) |
+                                                   R600_S2_X(0xa) |
+                                                   R600_S2_Y(0x6) |
+                                                   R600_S3_X(0x6) |
+                                                   R600_S3_Y(0xa)));
+       RADEON_WRITE(R600_PA_SC_AA_SAMPLE_LOCS_8S_WD0, (R600_S0_X(0xe) |
+                                                       R600_S0_Y(0xb) |
+                                                       R600_S1_X(0x4) |
+                                                       R600_S1_Y(0xc) |
+                                                       R600_S2_X(0x1) |
+                                                       R600_S2_Y(0x6) |
+                                                       R600_S3_X(0xa) |
+                                                       R600_S3_Y(0xe)));
+       RADEON_WRITE(R600_PA_SC_AA_SAMPLE_LOCS_8S_WD1, (R600_S4_X(0x6) |
+                                                       R600_S4_Y(0x1) |
+                                                       R600_S5_X(0x0) |
+                                                       R600_S5_Y(0x0) |
+                                                       R600_S6_X(0xb) |
+                                                       R600_S6_Y(0x4) |
+                                                       R600_S7_X(0x7) |
+                                                       R600_S7_Y(0x8)));
+
+
+       switch (dev_priv->flags & RADEON_FAMILY_MASK) {
+       case CHIP_R600:
+       case CHIP_RV630:
+       case CHIP_RV635:
+               gs_prim_buffer_depth = 0;
+               break;
+       case CHIP_RV610:
+       case CHIP_RS780:
+       case CHIP_RV620:
+               gs_prim_buffer_depth = 32;
+               break;
+       case CHIP_RV670:
+               gs_prim_buffer_depth = 128;
+               break;
+       default:
+               break;
+       }
+
+       num_gs_verts_per_thread = dev_priv->r600_max_pipes * 16;
+       vgt_gs_per_es = gs_prim_buffer_depth + num_gs_verts_per_thread;
+       /* Max value for this is 256 */
+       if (vgt_gs_per_es > 256)
+               vgt_gs_per_es = 256;
+
+       RADEON_WRITE(R600_VGT_ES_PER_GS, 128);
+       RADEON_WRITE(R600_VGT_GS_PER_ES, vgt_gs_per_es);
+       RADEON_WRITE(R600_VGT_GS_PER_VS, 2);
+       RADEON_WRITE(R600_VGT_GS_VERTEX_REUSE, 16);
+
+       /* more default values. 2D/3D driver should adjust as needed */
+       RADEON_WRITE(R600_PA_SC_LINE_STIPPLE_STATE, 0);
+       RADEON_WRITE(R600_VGT_STRMOUT_EN, 0);
+       RADEON_WRITE(R600_SX_MISC, 0);
+       RADEON_WRITE(R600_PA_SC_MODE_CNTL, 0);
+       RADEON_WRITE(R600_PA_SC_AA_CONFIG, 0);
+       RADEON_WRITE(R600_PA_SC_LINE_STIPPLE, 0);
+       RADEON_WRITE(R600_SPI_INPUT_Z, 0);
+       RADEON_WRITE(R600_SPI_PS_IN_CONTROL_0, R600_NUM_INTERP(2));
+       RADEON_WRITE(R600_CB_COLOR7_FRAG, 0);
+
+       /* clear render buffer base addresses */
+       RADEON_WRITE(R600_CB_COLOR0_BASE, 0);
+       RADEON_WRITE(R600_CB_COLOR1_BASE, 0);
+       RADEON_WRITE(R600_CB_COLOR2_BASE, 0);
+       RADEON_WRITE(R600_CB_COLOR3_BASE, 0);
+       RADEON_WRITE(R600_CB_COLOR4_BASE, 0);
+       RADEON_WRITE(R600_CB_COLOR5_BASE, 0);
+       RADEON_WRITE(R600_CB_COLOR6_BASE, 0);
+       RADEON_WRITE(R600_CB_COLOR7_BASE, 0);
+
+       switch (dev_priv->flags & RADEON_FAMILY_MASK) {
+       case CHIP_RV610:
+       case CHIP_RS780:
+       case CHIP_RV620:
+               tc_cntl = R600_TC_L2_SIZE(8);
+               break;
+       case CHIP_RV630:
+       case CHIP_RV635:
+               tc_cntl = R600_TC_L2_SIZE(4);
+               break;
+       case CHIP_R600:
+               tc_cntl = R600_TC_L2_SIZE(0) | R600_L2_DISABLE_LATE_HIT;
+               break;
+       default:
+               tc_cntl = R600_TC_L2_SIZE(0);
+               break;
+       }
+
+       RADEON_WRITE(R600_TC_CNTL, tc_cntl);
+
+       hdp_host_path_cntl = RADEON_READ(R600_HDP_HOST_PATH_CNTL);
+       RADEON_WRITE(R600_HDP_HOST_PATH_CNTL, hdp_host_path_cntl);
+
+       arb_pop = RADEON_READ(R600_ARB_POP);
+       arb_pop |= R600_ENABLE_TC128;
+       RADEON_WRITE(R600_ARB_POP, arb_pop);
+
+       RADEON_WRITE(R600_PA_SC_MULTI_CHIP_CNTL, 0);
+       RADEON_WRITE(R600_PA_CL_ENHANCE, (R600_CLIP_VTX_REORDER_ENA |
+                                         R600_NUM_CLIP_SEQ(3)));
+       RADEON_WRITE(R600_PA_SC_ENHANCE, R600_FORCE_EOV_MAX_CLK_CNT(4095));
+
+}
+
+static u32 r700_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
+                                            u32 num_backends,
+                                            u32 backend_disable_mask)
+{
+       u32 backend_map = 0;
+       u32 enabled_backends_mask;
+       u32 enabled_backends_count;
+       u32 cur_pipe;
+       u32 swizzle_pipe[R7XX_MAX_PIPES];
+       u32 cur_backend;
+       u32 i;
+
+       if (num_tile_pipes > R7XX_MAX_PIPES)
+               num_tile_pipes = R7XX_MAX_PIPES;
+       if (num_tile_pipes < 1)
+               num_tile_pipes = 1;
+       if (num_backends > R7XX_MAX_BACKENDS)
+               num_backends = R7XX_MAX_BACKENDS;
+       if (num_backends < 1)
+               num_backends = 1;
+
+       enabled_backends_mask = 0;
+       enabled_backends_count = 0;
+       for (i = 0; i < R7XX_MAX_BACKENDS; ++i) {
+               if (((backend_disable_mask >> i) & 1) == 0) {
+                       enabled_backends_mask |= (1 << i);
+                       ++enabled_backends_count;
+               }
+               if (enabled_backends_count == num_backends)
+                       break;
+       }
+
+       if (enabled_backends_count == 0) {
+               enabled_backends_mask = 1;
+               enabled_backends_count = 1;
+       }
+
+       if (enabled_backends_count != num_backends)
+               num_backends = enabled_backends_count;
+
+       memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * R7XX_MAX_PIPES);
+       switch (num_tile_pipes) {
+       case 1:
+               swizzle_pipe[0] = 0;
+               break;
+       case 2:
+               swizzle_pipe[0] = 0;
+               swizzle_pipe[1] = 1;
+               break;
+       case 3:
+               swizzle_pipe[0] = 0;
+               swizzle_pipe[1] = 2;
+               swizzle_pipe[2] = 1;
+               break;
+       case 4:
+               swizzle_pipe[0] = 0;
+               swizzle_pipe[1] = 2;
+               swizzle_pipe[2] = 3;
+               swizzle_pipe[3] = 1;
+               break;
+       case 5:
+               swizzle_pipe[0] = 0;
+               swizzle_pipe[1] = 2;
+               swizzle_pipe[2] = 4;
+               swizzle_pipe[3] = 1;
+               swizzle_pipe[4] = 3;
+               break;
+       case 6:
+               swizzle_pipe[0] = 0;
+               swizzle_pipe[1] = 2;
+               swizzle_pipe[2] = 4;
+               swizzle_pipe[3] = 5;
+               swizzle_pipe[4] = 3;
+               swizzle_pipe[5] = 1;
+               break;
+       case 7:
+               swizzle_pipe[0] = 0;
+               swizzle_pipe[1] = 2;
+               swizzle_pipe[2] = 4;
+               swizzle_pipe[3] = 6;
+               swizzle_pipe[4] = 3;
+               swizzle_pipe[5] = 1;
+               swizzle_pipe[6] = 5;
+               break;
+       case 8:
+               swizzle_pipe[0] = 0;
+               swizzle_pipe[1] = 2;
+               swizzle_pipe[2] = 4;
+               swizzle_pipe[3] = 6;
+               swizzle_pipe[4] = 3;
+               swizzle_pipe[5] = 1;
+               swizzle_pipe[6] = 7;
+               swizzle_pipe[7] = 5;
+               break;
+       }
+
+       cur_backend = 0;
+       for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) {
+               while (((1 << cur_backend) & enabled_backends_mask) == 0)
+                       cur_backend = (cur_backend + 1) % R7XX_MAX_BACKENDS;
+
+               backend_map |= (u32)(((cur_backend & 3) << (swizzle_pipe[cur_pipe] * 2)));
+
+               cur_backend = (cur_backend + 1) % R7XX_MAX_BACKENDS;
+       }
+
+       return backend_map;
+}
+
+static void r700_gfx_init(struct drm_device *dev,
+                         drm_radeon_private_t *dev_priv)
+{
+       int i, j, num_qd_pipes;
+       u32 sx_debug_1;
+       u32 smx_dc_ctl0;
+       u32 num_gs_verts_per_thread;
+       u32 vgt_gs_per_es;
+       u32 gs_prim_buffer_depth = 0;
+       u32 sq_ms_fifo_sizes;
+       u32 sq_config;
+       u32 sq_thread_resource_mgmt;
+       u32 hdp_host_path_cntl;
+       u32 sq_dyn_gpr_size_simd_ab_0;
+       u32 backend_map;
+       u32 gb_tiling_config = 0;
+       u32 cc_rb_backend_disable = 0;
+       u32 cc_gc_shader_pipe_config = 0;
+       u32 mc_arb_ramcfg;
+       u32 db_debug4;
+
+       /* setup chip specs */
+       switch (dev_priv->flags & RADEON_FAMILY_MASK) {
+       case CHIP_RV770:
+               dev_priv->r600_max_pipes = 4;
+               dev_priv->r600_max_tile_pipes = 8;
+               dev_priv->r600_max_simds = 10;
+               dev_priv->r600_max_backends = 4;
+               dev_priv->r600_max_gprs = 256;
+               dev_priv->r600_max_threads = 248;
+               dev_priv->r600_max_stack_entries = 512;
+               dev_priv->r600_max_hw_contexts = 8;
+               dev_priv->r600_max_gs_threads = 16 * 2;
+               dev_priv->r600_sx_max_export_size = 128;
+               dev_priv->r600_sx_max_export_pos_size = 16;
+               dev_priv->r600_sx_max_export_smx_size = 112;
+               dev_priv->r600_sq_num_cf_insts = 2;
+
+               dev_priv->r700_sx_num_of_sets = 7;
+               dev_priv->r700_sc_prim_fifo_size = 0xF9;
+               dev_priv->r700_sc_hiz_tile_fifo_size = 0x30;
+               dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130;
+               break;
+       case CHIP_RV730:
+               dev_priv->r600_max_pipes = 2;
+               dev_priv->r600_max_tile_pipes = 4;
+               dev_priv->r600_max_simds = 8;
+               dev_priv->r600_max_backends = 2;
+               dev_priv->r600_max_gprs = 128;
+               dev_priv->r600_max_threads = 248;
+               dev_priv->r600_max_stack_entries = 256;
+               dev_priv->r600_max_hw_contexts = 8;
+               dev_priv->r600_max_gs_threads = 16 * 2;
+               dev_priv->r600_sx_max_export_size = 256;
+               dev_priv->r600_sx_max_export_pos_size = 32;
+               dev_priv->r600_sx_max_export_smx_size = 224;
+               dev_priv->r600_sq_num_cf_insts = 2;
+
+               dev_priv->r700_sx_num_of_sets = 7;
+               dev_priv->r700_sc_prim_fifo_size = 0xf9;
+               dev_priv->r700_sc_hiz_tile_fifo_size = 0x30;
+               dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130;
+               break;
+       case CHIP_RV710:
+               dev_priv->r600_max_pipes = 2;
+               dev_priv->r600_max_tile_pipes = 2;
+               dev_priv->r600_max_simds = 2;
+               dev_priv->r600_max_backends = 1;
+               dev_priv->r600_max_gprs = 256;
+               dev_priv->r600_max_threads = 192;
+               dev_priv->r600_max_stack_entries = 256;
+               dev_priv->r600_max_hw_contexts = 4;
+               dev_priv->r600_max_gs_threads = 8 * 2;
+               dev_priv->r600_sx_max_export_size = 128;
+               dev_priv->r600_sx_max_export_pos_size = 16;
+               dev_priv->r600_sx_max_export_smx_size = 112;
+               dev_priv->r600_sq_num_cf_insts = 1;
+
+               dev_priv->r700_sx_num_of_sets = 7;
+               dev_priv->r700_sc_prim_fifo_size = 0x40;
+               dev_priv->r700_sc_hiz_tile_fifo_size = 0x30;
+               dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130;
+               break;
+       default:
+               break;
+       }
+
+       /* Initialize HDP */
+       j = 0;
+       for (i = 0; i < 32; i++) {
+               RADEON_WRITE((0x2c14 + j), 0x00000000);
+               RADEON_WRITE((0x2c18 + j), 0x00000000);
+               RADEON_WRITE((0x2c1c + j), 0x00000000);
+               RADEON_WRITE((0x2c20 + j), 0x00000000);
+               RADEON_WRITE((0x2c24 + j), 0x00000000);
+               j += 0x18;
+       }
+
+       RADEON_WRITE(R600_GRBM_CNTL, R600_GRBM_READ_TIMEOUT(0xff));
+
+       /* setup tiling, simd, pipe config */
+       mc_arb_ramcfg = RADEON_READ(R700_MC_ARB_RAMCFG);
+
+       switch (dev_priv->r600_max_tile_pipes) {
+       case 1:
+               gb_tiling_config |= R600_PIPE_TILING(0);
+               break;
+       case 2:
+               gb_tiling_config |= R600_PIPE_TILING(1);
+               break;
+       case 4:
+               gb_tiling_config |= R600_PIPE_TILING(2);
+               break;
+       case 8:
+               gb_tiling_config |= R600_PIPE_TILING(3);
+               break;
+       default:
+               break;
+       }
+
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV770)
+               gb_tiling_config |= R600_BANK_TILING(1);
+       else
+               gb_tiling_config |= R600_BANK_TILING((mc_arb_ramcfg >> R700_NOOFBANK_SHIFT) & R700_NOOFBANK_MASK);
+
+       gb_tiling_config |= R600_GROUP_SIZE(0);
+
+       if (((mc_arb_ramcfg >> R700_NOOFROWS_SHIFT) & R700_NOOFROWS_MASK) > 3) {
+               gb_tiling_config |= R600_ROW_TILING(3);
+               gb_tiling_config |= R600_SAMPLE_SPLIT(3);
+       } else {
+               gb_tiling_config |=
+                       R600_ROW_TILING(((mc_arb_ramcfg >> R700_NOOFROWS_SHIFT) & R700_NOOFROWS_MASK));
+               gb_tiling_config |=
+                       R600_SAMPLE_SPLIT(((mc_arb_ramcfg >> R700_NOOFROWS_SHIFT) & R700_NOOFROWS_MASK));
+       }
+
+       gb_tiling_config |= R600_BANK_SWAPS(1);
+
+       backend_map = r700_get_tile_pipe_to_backend_map(dev_priv->r600_max_tile_pipes,
+                                                       dev_priv->r600_max_backends,
+                                                       (0xff << dev_priv->r600_max_backends) & 0xff);
+       gb_tiling_config |= R600_BACKEND_MAP(backend_map);
+
+       cc_gc_shader_pipe_config =
+               R600_INACTIVE_QD_PIPES((R7XX_MAX_PIPES_MASK << dev_priv->r600_max_pipes) & R7XX_MAX_PIPES_MASK);
+       cc_gc_shader_pipe_config |=
+               R600_INACTIVE_SIMDS((R7XX_MAX_SIMDS_MASK << dev_priv->r600_max_simds) & R7XX_MAX_SIMDS_MASK);
+
+       cc_rb_backend_disable =
+               R600_BACKEND_DISABLE((R7XX_MAX_BACKENDS_MASK << dev_priv->r600_max_backends) & R7XX_MAX_BACKENDS_MASK);
+
+       RADEON_WRITE(R600_GB_TILING_CONFIG,      gb_tiling_config);
+       RADEON_WRITE(R600_DCP_TILING_CONFIG,    (gb_tiling_config & 0xffff));
+       RADEON_WRITE(R600_HDP_TILING_CONFIG,    (gb_tiling_config & 0xffff));
+
+       RADEON_WRITE(R600_CC_RB_BACKEND_DISABLE,      cc_rb_backend_disable);
+       RADEON_WRITE(R600_CC_GC_SHADER_PIPE_CONFIG,   cc_gc_shader_pipe_config);
+       RADEON_WRITE(R600_GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
+
+       RADEON_WRITE(R700_CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable);
+       RADEON_WRITE(R700_CGTS_SYS_TCC_DISABLE, 0);
+       RADEON_WRITE(R700_CGTS_TCC_DISABLE, 0);
+       RADEON_WRITE(R700_CGTS_USER_SYS_TCC_DISABLE, 0);
+       RADEON_WRITE(R700_CGTS_USER_TCC_DISABLE, 0);
+
+       num_qd_pipes =
+               R7XX_MAX_BACKENDS - r600_count_pipe_bits(cc_gc_shader_pipe_config & R600_INACTIVE_QD_PIPES_MASK);
+       RADEON_WRITE(R600_VGT_OUT_DEALLOC_CNTL, (num_qd_pipes * 4) & R600_DEALLOC_DIST_MASK);
+       RADEON_WRITE(R600_VGT_VERTEX_REUSE_BLOCK_CNTL, ((num_qd_pipes * 4) - 2) & R600_VTX_REUSE_DEPTH_MASK);
+
+       /* set HW defaults for 3D engine */
+       RADEON_WRITE(R600_CP_QUEUE_THRESHOLDS, (R600_ROQ_IB1_START(0x16) |
+                                               R600_ROQ_IB2_START(0x2b)));
+
+       RADEON_WRITE(R600_CP_MEQ_THRESHOLDS, R700_STQ_SPLIT(0x30));
+
+       RADEON_WRITE(R600_TA_CNTL_AUX, (R600_DISABLE_CUBE_ANISO |
+                                       R600_SYNC_GRADIENT |
+                                       R600_SYNC_WALKER |
+                                       R600_SYNC_ALIGNER));
+
+       sx_debug_1 = RADEON_READ(R700_SX_DEBUG_1);
+       sx_debug_1 |= R700_ENABLE_NEW_SMX_ADDRESS;
+       RADEON_WRITE(R700_SX_DEBUG_1, sx_debug_1);
+
+       smx_dc_ctl0 = RADEON_READ(R600_SMX_DC_CTL0);
+       smx_dc_ctl0 &= ~R700_CACHE_DEPTH(0x1ff);
+       smx_dc_ctl0 |= R700_CACHE_DEPTH((dev_priv->r700_sx_num_of_sets * 64) - 1);
+       RADEON_WRITE(R600_SMX_DC_CTL0, smx_dc_ctl0);
+
+       RADEON_WRITE(R700_SMX_EVENT_CTL, (R700_ES_FLUSH_CTL(4) |
+                                         R700_GS_FLUSH_CTL(4) |
+                                         R700_ACK_FLUSH_CTL(3) |
+                                         R700_SYNC_FLUSH_CTL));
+
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV770)
+               RADEON_WRITE(R700_DB_DEBUG3, R700_DB_CLK_OFF_DELAY(0x1f));
+       else {
+               db_debug4 = RADEON_READ(RV700_DB_DEBUG4);
+               db_debug4 |= RV700_DISABLE_TILE_COVERED_FOR_PS_ITER;
+               RADEON_WRITE(RV700_DB_DEBUG4, db_debug4);
+       }
+
+       RADEON_WRITE(R600_SX_EXPORT_BUFFER_SIZES, (R600_COLOR_BUFFER_SIZE((dev_priv->r600_sx_max_export_size / 4) - 1) |
+                                                  R600_POSITION_BUFFER_SIZE((dev_priv->r600_sx_max_export_pos_size / 4) - 1) |
+                                                  R600_SMX_BUFFER_SIZE((dev_priv->r600_sx_max_export_smx_size / 4) - 1)));
+
+       RADEON_WRITE(R700_PA_SC_FIFO_SIZE_R7XX, (R700_SC_PRIM_FIFO_SIZE(dev_priv->r700_sc_prim_fifo_size) |
+                                                R700_SC_HIZ_TILE_FIFO_SIZE(dev_priv->r700_sc_hiz_tile_fifo_size) |
+                                                R700_SC_EARLYZ_TILE_FIFO_SIZE(dev_priv->r700_sc_earlyz_tile_fifo_fize)));
+
+       RADEON_WRITE(R600_PA_SC_MULTI_CHIP_CNTL, 0);
+
+       RADEON_WRITE(R600_VGT_NUM_INSTANCES, 1);
+
+       RADEON_WRITE(R600_SPI_CONFIG_CNTL, R600_GPR_WRITE_PRIORITY(0));
+
+       RADEON_WRITE(R600_SPI_CONFIG_CNTL_1, R600_VTX_DONE_DELAY(4));
+
+       RADEON_WRITE(R600_CP_PERFMON_CNTL, 0);
+
+       sq_ms_fifo_sizes = (R600_CACHE_FIFO_SIZE(16 * dev_priv->r600_sq_num_cf_insts) |
+                           R600_DONE_FIFO_HIWATER(0xe0) |
+                           R600_ALU_UPDATE_FIFO_HIWATER(0x8));
+       switch (dev_priv->flags & RADEON_FAMILY_MASK) {
+       case CHIP_RV770:
+               sq_ms_fifo_sizes |= R600_FETCH_FIFO_HIWATER(0x1);
+               break;
+       case CHIP_RV730:
+       case CHIP_RV710:
+       default:
+               sq_ms_fifo_sizes |= R600_FETCH_FIFO_HIWATER(0x4);
+               break;
+       }
+       RADEON_WRITE(R600_SQ_MS_FIFO_SIZES, sq_ms_fifo_sizes);
+
+       /* SQ_CONFIG, SQ_GPR_RESOURCE_MGMT, SQ_THREAD_RESOURCE_MGMT, SQ_STACK_RESOURCE_MGMT
+        * should be adjusted as needed by the 2D/3D drivers.  This just sets default values
+        */
+       sq_config = RADEON_READ(R600_SQ_CONFIG);
+       sq_config &= ~(R600_PS_PRIO(3) |
+                      R600_VS_PRIO(3) |
+                      R600_GS_PRIO(3) |
+                      R600_ES_PRIO(3));
+       sq_config |= (R600_DX9_CONSTS |
+                     R600_VC_ENABLE |
+                     R600_EXPORT_SRC_C |
+                     R600_PS_PRIO(0) |
+                     R600_VS_PRIO(1) |
+                     R600_GS_PRIO(2) |
+                     R600_ES_PRIO(3));
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV710)
+               /* no vertex cache */
+               sq_config &= ~R600_VC_ENABLE;
+
+       RADEON_WRITE(R600_SQ_CONFIG, sq_config);
+
+       RADEON_WRITE(R600_SQ_GPR_RESOURCE_MGMT_1,  (R600_NUM_PS_GPRS((dev_priv->r600_max_gprs * 24)/64) |
+                                                   R600_NUM_VS_GPRS((dev_priv->r600_max_gprs * 24)/64) |
+                                                   R600_NUM_CLAUSE_TEMP_GPRS(((dev_priv->r600_max_gprs * 24)/64)/2)));
+
+       RADEON_WRITE(R600_SQ_GPR_RESOURCE_MGMT_2,  (R600_NUM_GS_GPRS((dev_priv->r600_max_gprs * 7)/64) |
+                                                   R600_NUM_ES_GPRS((dev_priv->r600_max_gprs * 7)/64)));
+
+       sq_thread_resource_mgmt = (R600_NUM_PS_THREADS((dev_priv->r600_max_threads * 4)/8) |
+                                  R600_NUM_VS_THREADS((dev_priv->r600_max_threads * 2)/8) |
+                                  R600_NUM_ES_THREADS((dev_priv->r600_max_threads * 1)/8));
+       if (((dev_priv->r600_max_threads * 1) / 8) > dev_priv->r600_max_gs_threads)
+               sq_thread_resource_mgmt |= R600_NUM_GS_THREADS(dev_priv->r600_max_gs_threads);
+       else
+               sq_thread_resource_mgmt |= R600_NUM_GS_THREADS((dev_priv->r600_max_gs_threads * 1)/8);
+       RADEON_WRITE(R600_SQ_THREAD_RESOURCE_MGMT, sq_thread_resource_mgmt);
+
+       RADEON_WRITE(R600_SQ_STACK_RESOURCE_MGMT_1, (R600_NUM_PS_STACK_ENTRIES((dev_priv->r600_max_stack_entries * 1)/4) |
+                                                    R600_NUM_VS_STACK_ENTRIES((dev_priv->r600_max_stack_entries * 1)/4)));
+
+       RADEON_WRITE(R600_SQ_STACK_RESOURCE_MGMT_2, (R600_NUM_GS_STACK_ENTRIES((dev_priv->r600_max_stack_entries * 1)/4) |
+                                                    R600_NUM_ES_STACK_ENTRIES((dev_priv->r600_max_stack_entries * 1)/4)));
+
+       sq_dyn_gpr_size_simd_ab_0 = (R700_SIMDA_RING0((dev_priv->r600_max_gprs * 38)/64) |
+                                    R700_SIMDA_RING1((dev_priv->r600_max_gprs * 38)/64) |
+                                    R700_SIMDB_RING0((dev_priv->r600_max_gprs * 38)/64) |
+                                    R700_SIMDB_RING1((dev_priv->r600_max_gprs * 38)/64));
+
+       RADEON_WRITE(R700_SQ_DYN_GPR_SIZE_SIMD_AB_0, sq_dyn_gpr_size_simd_ab_0);
+       RADEON_WRITE(R700_SQ_DYN_GPR_SIZE_SIMD_AB_1, sq_dyn_gpr_size_simd_ab_0);
+       RADEON_WRITE(R700_SQ_DYN_GPR_SIZE_SIMD_AB_2, sq_dyn_gpr_size_simd_ab_0);
+       RADEON_WRITE(R700_SQ_DYN_GPR_SIZE_SIMD_AB_3, sq_dyn_gpr_size_simd_ab_0);
+       RADEON_WRITE(R700_SQ_DYN_GPR_SIZE_SIMD_AB_4, sq_dyn_gpr_size_simd_ab_0);
+       RADEON_WRITE(R700_SQ_DYN_GPR_SIZE_SIMD_AB_5, sq_dyn_gpr_size_simd_ab_0);
+       RADEON_WRITE(R700_SQ_DYN_GPR_SIZE_SIMD_AB_6, sq_dyn_gpr_size_simd_ab_0);
+       RADEON_WRITE(R700_SQ_DYN_GPR_SIZE_SIMD_AB_7, sq_dyn_gpr_size_simd_ab_0);
+
+       RADEON_WRITE(R700_PA_SC_FORCE_EOV_MAX_CNTS, (R700_FORCE_EOV_MAX_CLK_CNT(4095) |
+                                                    R700_FORCE_EOV_MAX_REZ_CNT(255)));
+
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV710)
+               RADEON_WRITE(R600_VGT_CACHE_INVALIDATION, (R600_CACHE_INVALIDATION(R600_TC_ONLY) |
+                                                          R700_AUTO_INVLD_EN(R700_ES_AND_GS_AUTO)));
+       else
+               RADEON_WRITE(R600_VGT_CACHE_INVALIDATION, (R600_CACHE_INVALIDATION(R600_VC_AND_TC) |
+                                                          R700_AUTO_INVLD_EN(R700_ES_AND_GS_AUTO)));
+
+       switch (dev_priv->flags & RADEON_FAMILY_MASK) {
+       case CHIP_RV770:
+       case CHIP_RV730:
+               gs_prim_buffer_depth = 384;
+               break;
+       case CHIP_RV710:
+               gs_prim_buffer_depth = 128;
+               break;
+       default:
+               break;
+       }
+
+       num_gs_verts_per_thread = dev_priv->r600_max_pipes * 16;
+       vgt_gs_per_es = gs_prim_buffer_depth + num_gs_verts_per_thread;
+       /* Max value for this is 256 */
+       if (vgt_gs_per_es > 256)
+               vgt_gs_per_es = 256;
+
+       RADEON_WRITE(R600_VGT_ES_PER_GS, 128);
+       RADEON_WRITE(R600_VGT_GS_PER_ES, vgt_gs_per_es);
+       RADEON_WRITE(R600_VGT_GS_PER_VS, 2);
+
+       /* more default values. 2D/3D driver should adjust as needed */
+       RADEON_WRITE(R600_VGT_GS_VERTEX_REUSE, 16);
+       RADEON_WRITE(R600_PA_SC_LINE_STIPPLE_STATE, 0);
+       RADEON_WRITE(R600_VGT_STRMOUT_EN, 0);
+       RADEON_WRITE(R600_SX_MISC, 0);
+       RADEON_WRITE(R600_PA_SC_MODE_CNTL, 0);
+       RADEON_WRITE(R700_PA_SC_EDGERULE, 0xaaaaaaaa);
+       RADEON_WRITE(R600_PA_SC_AA_CONFIG, 0);
+       RADEON_WRITE(R600_PA_SC_CLIPRECT_RULE, 0xffff);
+       RADEON_WRITE(R600_PA_SC_LINE_STIPPLE, 0);
+       RADEON_WRITE(R600_SPI_INPUT_Z, 0);
+       RADEON_WRITE(R600_SPI_PS_IN_CONTROL_0, R600_NUM_INTERP(2));
+       RADEON_WRITE(R600_CB_COLOR7_FRAG, 0);
+
+       /* clear render buffer base addresses */
+       RADEON_WRITE(R600_CB_COLOR0_BASE, 0);
+       RADEON_WRITE(R600_CB_COLOR1_BASE, 0);
+       RADEON_WRITE(R600_CB_COLOR2_BASE, 0);
+       RADEON_WRITE(R600_CB_COLOR3_BASE, 0);
+       RADEON_WRITE(R600_CB_COLOR4_BASE, 0);
+       RADEON_WRITE(R600_CB_COLOR5_BASE, 0);
+       RADEON_WRITE(R600_CB_COLOR6_BASE, 0);
+       RADEON_WRITE(R600_CB_COLOR7_BASE, 0);
+
+       RADEON_WRITE(R700_TCP_CNTL, 0);
+
+       hdp_host_path_cntl = RADEON_READ(R600_HDP_HOST_PATH_CNTL);
+       RADEON_WRITE(R600_HDP_HOST_PATH_CNTL, hdp_host_path_cntl);
+
+       RADEON_WRITE(R600_PA_SC_MULTI_CHIP_CNTL, 0);
+
+       RADEON_WRITE(R600_PA_CL_ENHANCE, (R600_CLIP_VTX_REORDER_ENA |
+                                         R600_NUM_CLIP_SEQ(3)));
+
+}
+
+static void r600_cp_init_ring_buffer(struct drm_device *dev,
+                                      drm_radeon_private_t *dev_priv,
+                                      struct drm_file *file_priv)
+{
+       struct drm_radeon_master_private *master_priv;
+       u32 ring_start;
+       u64 rptr_addr;
+
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770))
+               r700_gfx_init(dev, dev_priv);
+       else
+               r600_gfx_init(dev, dev_priv);
+
+       RADEON_WRITE(R600_GRBM_SOFT_RESET, R600_SOFT_RESET_CP);
+       RADEON_READ(R600_GRBM_SOFT_RESET);
+       DRM_UDELAY(15000);
+       RADEON_WRITE(R600_GRBM_SOFT_RESET, 0);
+
+
+       /* Set ring buffer size */
+#ifdef __BIG_ENDIAN
+       RADEON_WRITE(R600_CP_RB_CNTL,
+                    RADEON_BUF_SWAP_32BIT |
+                    RADEON_RB_NO_UPDATE |
+                    (dev_priv->ring.rptr_update_l2qw << 8) |
+                    dev_priv->ring.size_l2qw);
+#else
+       RADEON_WRITE(R600_CP_RB_CNTL,
+                    RADEON_RB_NO_UPDATE |
+                    (dev_priv->ring.rptr_update_l2qw << 8) |
+                    dev_priv->ring.size_l2qw);
+#endif
+
+       RADEON_WRITE(R600_CP_SEM_WAIT_TIMER, 0x4);
+
+       /* Set the write pointer delay */
+       RADEON_WRITE(R600_CP_RB_WPTR_DELAY, 0);
+
+#ifdef __BIG_ENDIAN
+       RADEON_WRITE(R600_CP_RB_CNTL,
+                    RADEON_BUF_SWAP_32BIT |
+                    RADEON_RB_NO_UPDATE |
+                    RADEON_RB_RPTR_WR_ENA |
+                    (dev_priv->ring.rptr_update_l2qw << 8) |
+                    dev_priv->ring.size_l2qw);
+#else
+       RADEON_WRITE(R600_CP_RB_CNTL,
+                    RADEON_RB_NO_UPDATE |
+                    RADEON_RB_RPTR_WR_ENA |
+                    (dev_priv->ring.rptr_update_l2qw << 8) |
+                    dev_priv->ring.size_l2qw);
+#endif
+
+       /* Initialize the ring buffer's read and write pointers */
+       RADEON_WRITE(R600_CP_RB_RPTR_WR, 0);
+       RADEON_WRITE(R600_CP_RB_WPTR, 0);
+       SET_RING_HEAD(dev_priv, 0);
+       dev_priv->ring.tail = 0;
+
+#if __OS_HAS_AGP
+       if (dev_priv->flags & RADEON_IS_AGP) {
+               rptr_addr = dev_priv->ring_rptr->offset
+                       - dev->agp->base +
+                       dev_priv->gart_vm_start;
+       } else
+#endif
+       {
+               rptr_addr = dev_priv->ring_rptr->offset
+                       - ((unsigned long) dev->sg->virtual)
+                       + dev_priv->gart_vm_start;
+       }
+       RADEON_WRITE(R600_CP_RB_RPTR_ADDR,
+                    rptr_addr & 0xffffffff);
+       RADEON_WRITE(R600_CP_RB_RPTR_ADDR_HI,
+                    upper_32_bits(rptr_addr));
+
+#ifdef __BIG_ENDIAN
+       RADEON_WRITE(R600_CP_RB_CNTL,
+                    RADEON_BUF_SWAP_32BIT |
+                    (dev_priv->ring.rptr_update_l2qw << 8) |
+                    dev_priv->ring.size_l2qw);
+#else
+       RADEON_WRITE(R600_CP_RB_CNTL,
+                    (dev_priv->ring.rptr_update_l2qw << 8) |
+                    dev_priv->ring.size_l2qw);
+#endif
+
+#if __OS_HAS_AGP
+       if (dev_priv->flags & RADEON_IS_AGP) {
+               /* XXX */
+               radeon_write_agp_base(dev_priv, dev->agp->base);
+
+               /* XXX */
+               radeon_write_agp_location(dev_priv,
+                            (((dev_priv->gart_vm_start - 1 +
+                               dev_priv->gart_size) & 0xffff0000) |
+                             (dev_priv->gart_vm_start >> 16)));
+
+               ring_start = (dev_priv->cp_ring->offset
+                             - dev->agp->base
+                             + dev_priv->gart_vm_start);
+       } else
+#endif
+               ring_start = (dev_priv->cp_ring->offset
+                             - (unsigned long)dev->sg->virtual
+                             + dev_priv->gart_vm_start);
+
+       RADEON_WRITE(R600_CP_RB_BASE, ring_start >> 8);
+
+       RADEON_WRITE(R600_CP_ME_CNTL, 0xff);
+
+       RADEON_WRITE(R600_CP_DEBUG, (1 << 27) | (1 << 28));
+
+       /* Initialize the scratch register pointer.  This will cause
+        * the scratch register values to be written out to memory
+        * whenever they are updated.
+        *
+        * We simply put this behind the ring read pointer, this works
+        * with PCI GART as well as (whatever kind of) AGP GART
+        */
+       {
+               u64 scratch_addr;
+
+               scratch_addr = RADEON_READ(R600_CP_RB_RPTR_ADDR);
+               scratch_addr |= ((u64)RADEON_READ(R600_CP_RB_RPTR_ADDR_HI)) << 32;
+               scratch_addr += R600_SCRATCH_REG_OFFSET;
+               scratch_addr >>= 8;
+               scratch_addr &= 0xffffffff;
+
+               RADEON_WRITE(R600_SCRATCH_ADDR, (uint32_t)scratch_addr);
+       }
+
+       RADEON_WRITE(R600_SCRATCH_UMSK, 0x7);
+
+       /* Turn on bus mastering */
+       radeon_enable_bm(dev_priv);
+
+       radeon_write_ring_rptr(dev_priv, R600_SCRATCHOFF(0), 0);
+       RADEON_WRITE(R600_LAST_FRAME_REG, 0);
+
+       radeon_write_ring_rptr(dev_priv, R600_SCRATCHOFF(1), 0);
+       RADEON_WRITE(R600_LAST_DISPATCH_REG, 0);
+
+       radeon_write_ring_rptr(dev_priv, R600_SCRATCHOFF(2), 0);
+       RADEON_WRITE(R600_LAST_CLEAR_REG, 0);
+
+       /* reset sarea copies of these */
+       master_priv = file_priv->master->driver_priv;
+       if (master_priv->sarea_priv) {
+               master_priv->sarea_priv->last_frame = 0;
+               master_priv->sarea_priv->last_dispatch = 0;
+               master_priv->sarea_priv->last_clear = 0;
+       }
+
+       r600_do_wait_for_idle(dev_priv);
+
+}
+
+int r600_do_cleanup_cp(struct drm_device *dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       DRM_DEBUG("\n");
+
+       /* Make sure interrupts are disabled here because the uninstall ioctl
+        * may not have been called from userspace and after dev_private
+        * is freed, it's too late.
+        */
+       if (dev->irq_enabled)
+               drm_irq_uninstall(dev);
+
+#if __OS_HAS_AGP
+       if (dev_priv->flags & RADEON_IS_AGP) {
+               if (dev_priv->cp_ring != NULL) {
+                       drm_core_ioremapfree(dev_priv->cp_ring, dev);
+                       dev_priv->cp_ring = NULL;
+               }
+               if (dev_priv->ring_rptr != NULL) {
+                       drm_core_ioremapfree(dev_priv->ring_rptr, dev);
+                       dev_priv->ring_rptr = NULL;
+               }
+               if (dev->agp_buffer_map != NULL) {
+                       drm_core_ioremapfree(dev->agp_buffer_map, dev);
+                       dev->agp_buffer_map = NULL;
+               }
+       } else
+#endif
+       {
+
+               if (dev_priv->gart_info.bus_addr)
+                       r600_page_table_cleanup(dev, &dev_priv->gart_info);
+
+               if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB) {
+                       drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev);
+                       dev_priv->gart_info.addr = NULL;
+               }
+       }
+       /* only clear to the start of flags */
+       memset(dev_priv, 0, offsetof(drm_radeon_private_t, flags));
+
+       return 0;
+}
+
+int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
+                   struct drm_file *file_priv)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
+
+       DRM_DEBUG("\n");
+
+       /* if we require new memory map but we don't have it fail */
+       if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) {
+               DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n");
+               r600_do_cleanup_cp(dev);
+               return -EINVAL;
+       }
+
+       if (init->is_pci && (dev_priv->flags & RADEON_IS_AGP)) {
+               DRM_DEBUG("Forcing AGP card to PCI mode\n");
+               dev_priv->flags &= ~RADEON_IS_AGP;
+               /* The writeback test succeeds, but when writeback is enabled,
+                * the ring buffer read ptr update fails after first 128 bytes.
+                */
+               radeon_no_wb = 1;
+       } else if (!(dev_priv->flags & (RADEON_IS_AGP | RADEON_IS_PCI | RADEON_IS_PCIE))
+                && !init->is_pci) {
+               DRM_DEBUG("Restoring AGP flag\n");
+               dev_priv->flags |= RADEON_IS_AGP;
+       }
+
+       dev_priv->usec_timeout = init->usec_timeout;
+       if (dev_priv->usec_timeout < 1 ||
+           dev_priv->usec_timeout > RADEON_MAX_USEC_TIMEOUT) {
+               DRM_DEBUG("TIMEOUT problem!\n");
+               r600_do_cleanup_cp(dev);
+               return -EINVAL;
+       }
+
+       /* Enable vblank on CRTC1 for older X servers
+        */
+       dev_priv->vblank_crtc = DRM_RADEON_VBLANK_CRTC1;
+
+       dev_priv->cp_mode = init->cp_mode;
+
+       /* We don't support anything other than bus-mastering ring mode,
+        * but the ring can be in either AGP or PCI space for the ring
+        * read pointer.
+        */
+       if ((init->cp_mode != RADEON_CSQ_PRIBM_INDDIS) &&
+           (init->cp_mode != RADEON_CSQ_PRIBM_INDBM)) {
+               DRM_DEBUG("BAD cp_mode (%x)!\n", init->cp_mode);
+               r600_do_cleanup_cp(dev);
+               return -EINVAL;
+       }
+
+       switch (init->fb_bpp) {
+       case 16:
+               dev_priv->color_fmt = RADEON_COLOR_FORMAT_RGB565;
+               break;
+       case 32:
+       default:
+               dev_priv->color_fmt = RADEON_COLOR_FORMAT_ARGB8888;
+               break;
+       }
+       dev_priv->front_offset = init->front_offset;
+       dev_priv->front_pitch = init->front_pitch;
+       dev_priv->back_offset = init->back_offset;
+       dev_priv->back_pitch = init->back_pitch;
+
+       dev_priv->ring_offset = init->ring_offset;
+       dev_priv->ring_rptr_offset = init->ring_rptr_offset;
+       dev_priv->buffers_offset = init->buffers_offset;
+       dev_priv->gart_textures_offset = init->gart_textures_offset;
+
+       master_priv->sarea = drm_getsarea(dev);
+       if (!master_priv->sarea) {
+               DRM_ERROR("could not find sarea!\n");
+               r600_do_cleanup_cp(dev);
+               return -EINVAL;
+       }
+
+       dev_priv->cp_ring = drm_core_findmap(dev, init->ring_offset);
+       if (!dev_priv->cp_ring) {
+               DRM_ERROR("could not find cp ring region!\n");
+               r600_do_cleanup_cp(dev);
+               return -EINVAL;
+       }
+       dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);
+       if (!dev_priv->ring_rptr) {
+               DRM_ERROR("could not find ring read pointer!\n");
+               r600_do_cleanup_cp(dev);
+               return -EINVAL;
+       }
+       dev->agp_buffer_token = init->buffers_offset;
+       dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
+       if (!dev->agp_buffer_map) {
+               DRM_ERROR("could not find dma buffer region!\n");
+               r600_do_cleanup_cp(dev);
+               return -EINVAL;
+       }
+
+       if (init->gart_textures_offset) {
+               dev_priv->gart_textures =
+                   drm_core_findmap(dev, init->gart_textures_offset);
+               if (!dev_priv->gart_textures) {
+                       DRM_ERROR("could not find GART texture region!\n");
+                       r600_do_cleanup_cp(dev);
+                       return -EINVAL;
+               }
+       }
+
+#if __OS_HAS_AGP
+       /* XXX */
+       if (dev_priv->flags & RADEON_IS_AGP) {
+               drm_core_ioremap_wc(dev_priv->cp_ring, dev);
+               drm_core_ioremap_wc(dev_priv->ring_rptr, dev);
+               drm_core_ioremap_wc(dev->agp_buffer_map, dev);
+               if (!dev_priv->cp_ring->handle ||
+                   !dev_priv->ring_rptr->handle ||
+                   !dev->agp_buffer_map->handle) {
+                       DRM_ERROR("could not find ioremap agp regions!\n");
+                       r600_do_cleanup_cp(dev);
+                       return -EINVAL;
+               }
+       } else
+#endif
+       {
+               dev_priv->cp_ring->handle = (void *)dev_priv->cp_ring->offset;
+               dev_priv->ring_rptr->handle =
+                   (void *)dev_priv->ring_rptr->offset;
+               dev->agp_buffer_map->handle =
+                   (void *)dev->agp_buffer_map->offset;
+
+               DRM_DEBUG("dev_priv->cp_ring->handle %p\n",
+                         dev_priv->cp_ring->handle);
+               DRM_DEBUG("dev_priv->ring_rptr->handle %p\n",
+                         dev_priv->ring_rptr->handle);
+               DRM_DEBUG("dev->agp_buffer_map->handle %p\n",
+                         dev->agp_buffer_map->handle);
+       }
+
+       dev_priv->fb_location = (radeon_read_fb_location(dev_priv) & 0xffff) << 24;
+       dev_priv->fb_size =
+               (((radeon_read_fb_location(dev_priv) & 0xffff0000u) << 8) + 0x1000000)
+               - dev_priv->fb_location;
+
+       dev_priv->front_pitch_offset = (((dev_priv->front_pitch / 64) << 22) |
+                                       ((dev_priv->front_offset
+                                         + dev_priv->fb_location) >> 10));
+
+       dev_priv->back_pitch_offset = (((dev_priv->back_pitch / 64) << 22) |
+                                      ((dev_priv->back_offset
+                                        + dev_priv->fb_location) >> 10));
+
+       dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch / 64) << 22) |
+                                       ((dev_priv->depth_offset
+                                         + dev_priv->fb_location) >> 10));
+
+       dev_priv->gart_size = init->gart_size;
+
+       /* New let's set the memory map ... */
+       if (dev_priv->new_memmap) {
+               u32 base = 0;
+
+               DRM_INFO("Setting GART location based on new memory map\n");
+
+               /* If using AGP, try to locate the AGP aperture at the same
+                * location in the card and on the bus, though we have to
+                * align it down.
+                */
+#if __OS_HAS_AGP
+               /* XXX */
+               if (dev_priv->flags & RADEON_IS_AGP) {
+                       base = dev->agp->base;
+                       /* Check if valid */
+                       if ((base + dev_priv->gart_size - 1) >= dev_priv->fb_location &&
+                           base < (dev_priv->fb_location + dev_priv->fb_size - 1)) {
+                               DRM_INFO("Can't use AGP base @0x%08lx, won't fit\n",
+                                        dev->agp->base);
+                               base = 0;
+                       }
+               }
+#endif
+               /* If not or if AGP is at 0 (Macs), try to put it elsewhere */
+               if (base == 0) {
+                       base = dev_priv->fb_location + dev_priv->fb_size;
+                       if (base < dev_priv->fb_location ||
+                           ((base + dev_priv->gart_size) & 0xfffffffful) < base)
+                               base = dev_priv->fb_location
+                                       - dev_priv->gart_size;
+               }
+               dev_priv->gart_vm_start = base & 0xffc00000u;
+               if (dev_priv->gart_vm_start != base)
+                       DRM_INFO("GART aligned down from 0x%08x to 0x%08x\n",
+                                base, dev_priv->gart_vm_start);
+       }
+
+#if __OS_HAS_AGP
+       /* XXX */
+       if (dev_priv->flags & RADEON_IS_AGP)
+               dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset
+                                                - dev->agp->base
+                                                + dev_priv->gart_vm_start);
+       else
+#endif
+               dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset
+                                                - (unsigned long)dev->sg->virtual
+                                                + dev_priv->gart_vm_start);
+
+       DRM_DEBUG("fb 0x%08x size %d\n",
+                 (unsigned int) dev_priv->fb_location,
+                 (unsigned int) dev_priv->fb_size);
+       DRM_DEBUG("dev_priv->gart_size %d\n", dev_priv->gart_size);
+       DRM_DEBUG("dev_priv->gart_vm_start 0x%08x\n",
+                 (unsigned int) dev_priv->gart_vm_start);
+       DRM_DEBUG("dev_priv->gart_buffers_offset 0x%08lx\n",
+                 dev_priv->gart_buffers_offset);
+
+       dev_priv->ring.start = (u32 *) dev_priv->cp_ring->handle;
+       dev_priv->ring.end = ((u32 *) dev_priv->cp_ring->handle
+                             + init->ring_size / sizeof(u32));
+       dev_priv->ring.size = init->ring_size;
+       dev_priv->ring.size_l2qw = drm_order(init->ring_size / 8);
+
+       dev_priv->ring.rptr_update = /* init->rptr_update */ 4096;
+       dev_priv->ring.rptr_update_l2qw = drm_order(/* init->rptr_update */ 4096 / 8);
+
+       dev_priv->ring.fetch_size = /* init->fetch_size */ 32;
+       dev_priv->ring.fetch_size_l2ow = drm_order(/* init->fetch_size */ 32 / 16);
+
+       dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;
+
+       dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;
+
+#if __OS_HAS_AGP
+       if (dev_priv->flags & RADEON_IS_AGP) {
+               /* XXX turn off pcie gart */
+       } else
+#endif
+       {
+               dev_priv->gart_info.table_mask = DMA_BIT_MASK(32);
+               /* if we have an offset set from userspace */
+               if (!dev_priv->pcigart_offset_set) {
+                       DRM_ERROR("Need gart offset from userspace\n");
+                       r600_do_cleanup_cp(dev);
+                       return -EINVAL;
+               }
+
+               DRM_DEBUG("Using gart offset 0x%08lx\n", dev_priv->pcigart_offset);
+
+               dev_priv->gart_info.bus_addr =
+                       dev_priv->pcigart_offset + dev_priv->fb_location;
+               dev_priv->gart_info.mapping.offset =
+                       dev_priv->pcigart_offset + dev_priv->fb_aper_offset;
+               dev_priv->gart_info.mapping.size =
+                       dev_priv->gart_info.table_size;
+
+               drm_core_ioremap_wc(&dev_priv->gart_info.mapping, dev);
+               if (!dev_priv->gart_info.mapping.handle) {
+                       DRM_ERROR("ioremap failed.\n");
+                       r600_do_cleanup_cp(dev);
+                       return -EINVAL;
+               }
+
+               dev_priv->gart_info.addr =
+                       dev_priv->gart_info.mapping.handle;
+
+               DRM_DEBUG("Setting phys_pci_gart to %p %08lX\n",
+                         dev_priv->gart_info.addr,
+                         dev_priv->pcigart_offset);
+
+               if (!r600_page_table_init(dev)) {
+                       DRM_ERROR("Failed to init GART table\n");
+                       r600_do_cleanup_cp(dev);
+                       return -EINVAL;
+               }
+
+               if (((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770))
+                       r700_vm_init(dev);
+               else
+                       r600_vm_init(dev);
+       }
+
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770))
+               r700_cp_load_microcode(dev_priv);
+       else
+               r600_cp_load_microcode(dev_priv);
+
+       r600_cp_init_ring_buffer(dev, dev_priv, file_priv);
+
+       dev_priv->last_buf = 0;
+
+       r600_do_engine_reset(dev);
+       r600_test_writeback(dev_priv);
+
+       return 0;
+}
+
+int r600_do_resume_cp(struct drm_device *dev, struct drm_file *file_priv)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       DRM_DEBUG("\n");
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)) {
+               r700_vm_init(dev);
+               r700_cp_load_microcode(dev_priv);
+       } else {
+               r600_vm_init(dev);
+               r600_cp_load_microcode(dev_priv);
+       }
+       r600_cp_init_ring_buffer(dev, dev_priv, file_priv);
+       r600_do_engine_reset(dev);
+
+       return 0;
+}
+
+/* Wait for the CP to go idle.
+ */
+int r600_do_cp_idle(drm_radeon_private_t *dev_priv)
+{
+       RING_LOCALS;
+       DRM_DEBUG("\n");
+
+       BEGIN_RING(5);
+       OUT_RING(CP_PACKET3(R600_IT_EVENT_WRITE, 0));
+       OUT_RING(R600_CACHE_FLUSH_AND_INV_EVENT);
+       /* wait for 3D idle clean */
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1));
+       OUT_RING((R600_WAIT_UNTIL - R600_SET_CONFIG_REG_OFFSET) >> 2);
+       OUT_RING(RADEON_WAIT_3D_IDLE | RADEON_WAIT_3D_IDLECLEAN);
+
+       ADVANCE_RING();
+       COMMIT_RING();
+
+       return r600_do_wait_for_idle(dev_priv);
+}
+
+/* Start the Command Processor.
+ */
+void r600_do_cp_start(drm_radeon_private_t *dev_priv)
+{
+       u32 cp_me;
+       RING_LOCALS;
+       DRM_DEBUG("\n");
+
+       BEGIN_RING(7);
+       OUT_RING(CP_PACKET3(R600_IT_ME_INITIALIZE, 5));
+       OUT_RING(0x00000001);
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_RV770))
+               OUT_RING(0x00000003);
+       else
+               OUT_RING(0x00000000);
+       OUT_RING((dev_priv->r600_max_hw_contexts - 1));
+       OUT_RING(R600_ME_INITIALIZE_DEVICE_ID(1));
+       OUT_RING(0x00000000);
+       OUT_RING(0x00000000);
+       ADVANCE_RING();
+       COMMIT_RING();
+
+       /* set the mux and reset the halt bit */
+       cp_me = 0xff;
+       RADEON_WRITE(R600_CP_ME_CNTL, cp_me);
+
+       dev_priv->cp_running = 1;
+
+}
+
+void r600_do_cp_reset(drm_radeon_private_t *dev_priv)
+{
+       u32 cur_read_ptr;
+       DRM_DEBUG("\n");
+
+       cur_read_ptr = RADEON_READ(R600_CP_RB_RPTR);
+       RADEON_WRITE(R600_CP_RB_WPTR, cur_read_ptr);
+       SET_RING_HEAD(dev_priv, cur_read_ptr);
+       dev_priv->ring.tail = cur_read_ptr;
+}
+
+void r600_do_cp_stop(drm_radeon_private_t *dev_priv)
+{
+       uint32_t cp_me;
+
+       DRM_DEBUG("\n");
+
+       cp_me = 0xff | R600_CP_ME_HALT;
+
+       RADEON_WRITE(R600_CP_ME_CNTL, cp_me);
+
+       dev_priv->cp_running = 0;
+}
+
+int r600_cp_dispatch_indirect(struct drm_device *dev,
+                             struct drm_buf *buf, int start, int end)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       RING_LOCALS;
+
+       if (start != end) {
+               unsigned long offset = (dev_priv->gart_buffers_offset
+                                       + buf->offset + start);
+               int dwords = (end - start + 3) / sizeof(u32);
+
+               DRM_DEBUG("dwords:%d\n", dwords);
+               DRM_DEBUG("offset 0x%lx\n", offset);
+
+
+               /* Indirect buffer data must be a multiple of 16 dwords.
+                * pad the data with a Type-2 CP packet.
+                */
+               while (dwords & 0xf) {
+                       u32 *data = (u32 *)
+                           ((char *)dev->agp_buffer_map->handle
+                            + buf->offset + start);
+                       data[dwords++] = RADEON_CP_PACKET2;
+               }
+
+               /* Fire off the indirect buffer */
+               BEGIN_RING(4);
+               OUT_RING(CP_PACKET3(R600_IT_INDIRECT_BUFFER, 2));
+               OUT_RING((offset & 0xfffffffc));
+               OUT_RING((upper_32_bits(offset) & 0xff));
+               OUT_RING(dwords);
+               ADVANCE_RING();
+       }
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/radeon/r600_microcode.h b/drivers/gpu/drm/radeon/r600_microcode.h
new file mode 100644 (file)
index 0000000..778c8b4
--- /dev/null
@@ -0,0 +1,23297 @@
+/*
+ * Copyright 2008-2009 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef R600_MICROCODE_H
+#define R600_MICROCODE_H
+
+static const int ME_JUMP_TABLE_START = 1764;
+static const int ME_JUMP_TABLE_END   = 1792;
+
+#define PFP_UCODE_SIZE 576
+#define PM4_UCODE_SIZE 1792
+#define R700_PFP_UCODE_SIZE 848
+#define R700_PM4_UCODE_SIZE 1360
+
+static const u32 R600_cp_microcode[][3] = {
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0000ffff, 0x00284621, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00000000, 0x00e00000, 0x000 },
+    { 0x00010000, 0xc0294620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x614 },
+    { 0x00000000, 0x00600000, 0x5b2 },
+    { 0x00000000, 0x00600000, 0x5c5 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000f00, 0x00281622, 0x000 },
+    { 0x00000008, 0x00211625, 0x000 },
+    { 0x00000020, 0x00203625, 0x000 },
+    { 0x8d000000, 0x00204411, 0x000 },
+    { 0x00000004, 0x002f0225, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x018 },
+    { 0x00412000, 0x00404811, 0x019 },
+    { 0x00422000, 0x00204811, 0x000 },
+    { 0x8e000000, 0x00204411, 0x000 },
+    { 0x00000031, 0x00204a2d, 0x000 },
+    { 0x90000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x0000000c, 0x00211622, 0x000 },
+    { 0x00000003, 0x00281625, 0x000 },
+    { 0x00000019, 0x00211a22, 0x000 },
+    { 0x00000004, 0x00281a26, 0x000 },
+    { 0x00000000, 0x002914c5, 0x000 },
+    { 0x00000021, 0x00203625, 0x000 },
+    { 0x00000000, 0x003a1402, 0x000 },
+    { 0x00000016, 0x00211625, 0x000 },
+    { 0x00000003, 0x00281625, 0x000 },
+    { 0x0000001d, 0x00200e2d, 0x000 },
+    { 0xfffffffc, 0x00280e23, 0x000 },
+    { 0x00000000, 0x002914a3, 0x000 },
+    { 0x0000001d, 0x00203625, 0x000 },
+    { 0x00008000, 0x00280e22, 0x000 },
+    { 0x00000007, 0x00220e23, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x20000000, 0x00280e22, 0x000 },
+    { 0x00000006, 0x00210e23, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x00000000, 0x00220222, 0x000 },
+    { 0x00000000, 0x14e00000, 0x038 },
+    { 0x00000000, 0x2ee00000, 0x035 },
+    { 0x00000000, 0x2ce00000, 0x037 },
+    { 0x00000000, 0x00400e2d, 0x039 },
+    { 0x00000008, 0x00200e2d, 0x000 },
+    { 0x00000009, 0x0040122d, 0x046 },
+    { 0x00000001, 0x00400e2d, 0x039 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x003ffffc, 0x00281223, 0x000 },
+    { 0x00000002, 0x00221224, 0x000 },
+    { 0x0000001f, 0x00211e23, 0x000 },
+    { 0x00000000, 0x14e00000, 0x03e },
+    { 0x00000008, 0x00401c11, 0x041 },
+    { 0x0000000d, 0x00201e2d, 0x000 },
+    { 0x0000000f, 0x00281e27, 0x000 },
+    { 0x00000003, 0x00221e27, 0x000 },
+    { 0x7fc00000, 0x00281a23, 0x000 },
+    { 0x00000014, 0x00211a26, 0x000 },
+    { 0x00000001, 0x00331a26, 0x000 },
+    { 0x00000008, 0x00221a26, 0x000 },
+    { 0x00000000, 0x00290cc7, 0x000 },
+    { 0x00000030, 0x00203624, 0x000 },
+    { 0x00007f00, 0x00281221, 0x000 },
+    { 0x00001400, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x04b },
+    { 0x00000001, 0x00290e23, 0x000 },
+    { 0x00000010, 0x00203623, 0x000 },
+    { 0x0000e000, 0x00204411, 0x000 },
+    { 0xfff80000, 0x00294a23, 0x000 },
+    { 0x00000000, 0x003a2c02, 0x000 },
+    { 0x00000002, 0x00220e2b, 0x000 },
+    { 0xfc000000, 0x00280e23, 0x000 },
+    { 0x00000011, 0x00203623, 0x000 },
+    { 0x00001fff, 0x00294a23, 0x000 },
+    { 0x00000030, 0x00204a2d, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000032, 0x00200e2d, 0x000 },
+    { 0x060a0200, 0x00294a23, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00210222, 0x000 },
+    { 0x00000000, 0x14e00000, 0x061 },
+    { 0x00000000, 0x2ee00000, 0x05f },
+    { 0x00000000, 0x2ce00000, 0x05e },
+    { 0x00000000, 0x00400e2d, 0x062 },
+    { 0x00000001, 0x00400e2d, 0x062 },
+    { 0x0000000a, 0x00200e2d, 0x000 },
+    { 0x0000000b, 0x0040122d, 0x06a },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x003ffffc, 0x00281223, 0x000 },
+    { 0x00000002, 0x00221224, 0x000 },
+    { 0x7fc00000, 0x00281623, 0x000 },
+    { 0x00000014, 0x00211625, 0x000 },
+    { 0x00000001, 0x00331625, 0x000 },
+    { 0x80000000, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00290ca3, 0x000 },
+    { 0x3ffffc00, 0x00290e23, 0x000 },
+    { 0x0000001f, 0x00211e23, 0x000 },
+    { 0x00000000, 0x14e00000, 0x06d },
+    { 0x00000100, 0x00401c11, 0x070 },
+    { 0x0000000d, 0x00201e2d, 0x000 },
+    { 0x000000f0, 0x00281e27, 0x000 },
+    { 0x00000004, 0x00221e27, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000d, 0x00204811, 0x000 },
+    { 0xfffff0ff, 0x00281a30, 0x000 },
+    { 0x0000a028, 0x00204411, 0x000 },
+    { 0x00000000, 0x002948e6, 0x000 },
+    { 0x0000a018, 0x00204411, 0x000 },
+    { 0x3fffffff, 0x00284a23, 0x000 },
+    { 0x0000a010, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x0000002d, 0x0020162d, 0x000 },
+    { 0x00000000, 0x002f00a3, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x080 },
+    { 0x0000002e, 0x0020162d, 0x000 },
+    { 0x00000000, 0x002f00a4, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x081 },
+    { 0x00000000, 0x00400000, 0x087 },
+    { 0x0000002d, 0x00203623, 0x000 },
+    { 0x0000002e, 0x00203624, 0x000 },
+    { 0x0000001d, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x087 },
+    { 0x00000000, 0x00600000, 0x5ed },
+    { 0x00000000, 0x00600000, 0x5e1 },
+    { 0x00000002, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x08a },
+    { 0x00000018, 0xc0403620, 0x090 },
+    { 0x00000000, 0x2ee00000, 0x08e },
+    { 0x00000000, 0x2ce00000, 0x08d },
+    { 0x00000002, 0x00400e2d, 0x08f },
+    { 0x00000003, 0x00400e2d, 0x08f },
+    { 0x0000000c, 0x00200e2d, 0x000 },
+    { 0x00000018, 0x00203623, 0x000 },
+    { 0x00000003, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x095 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x09d },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x2ee00000, 0x09b },
+    { 0x00000000, 0x2ce00000, 0x09a },
+    { 0x00000002, 0x00400e2d, 0x09c },
+    { 0x00000003, 0x00400e2d, 0x09c },
+    { 0x0000000c, 0x00200e2d, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000000, 0x003a0c02, 0x000 },
+    { 0x003f0000, 0x00280e23, 0x000 },
+    { 0x00000010, 0x00210e23, 0x000 },
+    { 0x00000013, 0x00203623, 0x000 },
+    { 0x0000001e, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0a4 },
+    { 0x0000001c, 0xc0203620, 0x000 },
+    { 0x0000001f, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0a7 },
+    { 0x0000001b, 0xc0203620, 0x000 },
+    { 0x00000008, 0x00210e2b, 0x000 },
+    { 0x0000007f, 0x00280e23, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0db },
+    { 0x00000000, 0x27000000, 0x000 },
+    { 0x00000000, 0x00600000, 0x28c },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x0000000c, 0x00221e30, 0x000 },
+    { 0x99800000, 0x00204411, 0x000 },
+    { 0x00000004, 0x0020122d, 0x000 },
+    { 0x00000008, 0x00221224, 0x000 },
+    { 0x00000010, 0x00201811, 0x000 },
+    { 0x00000000, 0x00291ce4, 0x000 },
+    { 0x00000000, 0x00604807, 0x128 },
+    { 0x9b000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x9c000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x0033146f, 0x000 },
+    { 0x00000001, 0x00333e23, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0x00203c05, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x00000000, 0x00201010, 0x000 },
+    { 0x0000e007, 0x00204411, 0x000 },
+    { 0x0000000f, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0c5 },
+    { 0x00f8ff08, 0x00204811, 0x000 },
+    { 0x98000000, 0x00404811, 0x0d6 },
+    { 0x000000f0, 0x00280e22, 0x000 },
+    { 0x000000a0, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x0d4 },
+    { 0x00000013, 0x00200e2d, 0x000 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0cf },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0ce },
+    { 0x00003f00, 0x00400c11, 0x0d0 },
+    { 0x00001f00, 0x00400c11, 0x0d0 },
+    { 0x00000f00, 0x00200c11, 0x000 },
+    { 0x00380009, 0x00294a23, 0x000 },
+    { 0x3f000000, 0x00280e2b, 0x000 },
+    { 0x00000002, 0x00220e23, 0x000 },
+    { 0x00000007, 0x00494a23, 0x0d6 },
+    { 0x00380f09, 0x00204811, 0x000 },
+    { 0x68000007, 0x00204811, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a24, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000a202, 0x00204411, 0x000 },
+    { 0x00ff0000, 0x00284a22, 0x000 },
+    { 0x00000030, 0x00200e2d, 0x000 },
+    { 0x0000002e, 0x0020122d, 0x000 },
+    { 0x00000000, 0x002f0083, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0e3 },
+    { 0x00000000, 0x00600000, 0x5e7 },
+    { 0x00000000, 0x00400000, 0x0e4 },
+    { 0x00000000, 0x00600000, 0x5ea },
+    { 0x00000007, 0x0020222d, 0x000 },
+    { 0x00000005, 0x00220e22, 0x000 },
+    { 0x00100000, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00292068, 0x000 },
+    { 0x00000000, 0x003a0c02, 0x000 },
+    { 0x000000ef, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00292068, 0x000 },
+    { 0x0000001d, 0x00200e2d, 0x000 },
+    { 0x00000003, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x0f1 },
+    { 0x0000000b, 0x00210228, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0f1 },
+    { 0x00000400, 0x00292228, 0x000 },
+    { 0x0000001a, 0x00203628, 0x000 },
+    { 0x0000001c, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0f6 },
+    { 0x0000a30c, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000001e, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x104 },
+    { 0x0000a30f, 0x00204411, 0x000 },
+    { 0x00000013, 0x00200e2d, 0x000 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x0fd },
+    { 0xffffffff, 0x00404811, 0x104 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x100 },
+    { 0x0000ffff, 0x00404811, 0x104 },
+    { 0x00000004, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x103 },
+    { 0x000000ff, 0x00404811, 0x104 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0002c400, 0x00204411, 0x000 },
+    { 0x0000001f, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x10b },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x00000019, 0x00203623, 0x000 },
+    { 0x00000018, 0x40224a20, 0x000 },
+    { 0x00000010, 0xc0424a20, 0x10d },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x00000019, 0x00203623, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000000a, 0x00201011, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x114 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00531224, 0x110 },
+    { 0xffbfffff, 0x00283a2e, 0x000 },
+    { 0x0000001b, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x127 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000d, 0x00204811, 0x000 },
+    { 0x00000018, 0x00220e30, 0x000 },
+    { 0xfc000000, 0x00280e23, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x00000000, 0x00201010, 0x000 },
+    { 0x0000e00e, 0x00204411, 0x000 },
+    { 0x07f8ff08, 0x00204811, 0x000 },
+    { 0x00000000, 0x00294a23, 0x000 },
+    { 0x00000024, 0x00201e2d, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a24, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x00800000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204806, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x614 },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x613 },
+    { 0x00000004, 0x00404c11, 0x12e },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x2fe },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x19f },
+    { 0x00000000, 0x00600000, 0x151 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000ffff, 0x40280620, 0x000 },
+    { 0x00000010, 0xc0210a20, 0x000 },
+    { 0x00000000, 0x00341461, 0x000 },
+    { 0x00000000, 0x00741882, 0x2a4 },
+    { 0x0001a1fd, 0x00604411, 0x2c9 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x138 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x2fe },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x19f },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x151 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x00000010, 0x40211620, 0x000 },
+    { 0x0000ffff, 0xc0681a20, 0x2a4 },
+    { 0x0001a1fd, 0x00604411, 0x2c9 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x149 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000001, 0x00300a2f, 0x000 },
+    { 0x00000001, 0x00210a22, 0x000 },
+    { 0x00000003, 0x00384a22, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001a, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600000, 0x17c },
+    { 0x00000000, 0x00600000, 0x18d },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00202c08, 0x000 },
+    { 0x00000000, 0x00202411, 0x000 },
+    { 0x00000000, 0x00202811, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000002, 0x00221e29, 0x000 },
+    { 0x00000000, 0x007048eb, 0x189 },
+    { 0x00000000, 0x00600000, 0x2a4 },
+    { 0x00000001, 0x40330620, 0x000 },
+    { 0x00000000, 0xc0302409, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x28c },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x173 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000001, 0x00530621, 0x16f },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0604800, 0x184 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000013, 0x0020062d, 0x000 },
+    { 0x00000000, 0x0078042a, 0x2e4 },
+    { 0x00000000, 0x00202809, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x165 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000210, 0x00600411, 0x2fe },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x181 },
+    { 0x0000001b, 0xc0203620, 0x000 },
+    { 0x0000001c, 0xc0203620, 0x000 },
+    { 0x3f800000, 0x00200411, 0x000 },
+    { 0x46000000, 0x00600811, 0x19f },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x188 },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000021, 0x00804811, 0x000 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000ffff, 0x40281620, 0x000 },
+    { 0x00000010, 0xc0811a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000008, 0x00221e30, 0x000 },
+    { 0x00000032, 0x00201a2d, 0x000 },
+    { 0x0000e000, 0x00204411, 0x000 },
+    { 0xfffbff09, 0x00204811, 0x000 },
+    { 0x00000011, 0x0020222d, 0x000 },
+    { 0x00001fff, 0x00294a28, 0x000 },
+    { 0x00000006, 0x0020222d, 0x000 },
+    { 0x00000000, 0x002920e8, 0x000 },
+    { 0x00000000, 0x00204808, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a26, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000100, 0x00201811, 0x000 },
+    { 0x00000008, 0x00621e28, 0x128 },
+    { 0x00000008, 0x00822228, 0x000 },
+    { 0x0002c000, 0x00204411, 0x000 },
+    { 0x0000001b, 0x00600e2d, 0x1aa },
+    { 0x0000001c, 0x00600e2d, 0x1aa },
+    { 0x0000c008, 0x00204411, 0x000 },
+    { 0x0000001d, 0x00200e2d, 0x000 },
+    { 0x00000000, 0x14c00000, 0x1a6 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0x39000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00804802, 0x000 },
+    { 0x00000020, 0x00202e2d, 0x000 },
+    { 0x00000000, 0x003b0d63, 0x000 },
+    { 0x00000008, 0x00224a23, 0x000 },
+    { 0x00000010, 0x00224a23, 0x000 },
+    { 0x00000018, 0x00224a23, 0x000 },
+    { 0x00000000, 0x00804803, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00001000, 0x00600411, 0x2fe },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x19f },
+    { 0x00000007, 0x0021062f, 0x000 },
+    { 0x00000019, 0x00200a2d, 0x000 },
+    { 0x00000001, 0x00202c11, 0x000 },
+    { 0x0000ffff, 0x40282220, 0x000 },
+    { 0x0000000f, 0x00262228, 0x000 },
+    { 0x00000010, 0x40212620, 0x000 },
+    { 0x0000000f, 0x00262629, 0x000 },
+    { 0x00000000, 0x00202802, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001b, 0x00204811, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1cd },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000081, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000080, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f0227, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1c9 },
+    { 0x00000000, 0x00600000, 0x1d6 },
+    { 0x00000001, 0x00531e27, 0x1c5 },
+    { 0x00000001, 0x00202c11, 0x000 },
+    { 0x0000001f, 0x00280a22, 0x000 },
+    { 0x0000001f, 0x00282a2a, 0x000 },
+    { 0x00000001, 0x00530621, 0x1be },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000002, 0x00304a2f, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000001, 0x00301e2f, 0x000 },
+    { 0x00000000, 0x002f0227, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x1d6 },
+    { 0x00000001, 0x00531e27, 0x1d2 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x0000000f, 0x00260e23, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000000f, 0x00261224, 0x000 },
+    { 0x00000000, 0x00201411, 0x000 },
+    { 0x00000000, 0x00601811, 0x2a4 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022b, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1e5 },
+    { 0x00000010, 0x00221628, 0x000 },
+    { 0xffff0000, 0x00281625, 0x000 },
+    { 0x0000ffff, 0x00281a29, 0x000 },
+    { 0x00000000, 0x002948c5, 0x000 },
+    { 0x00000000, 0x0020480a, 0x000 },
+    { 0x00000000, 0x00202c11, 0x000 },
+    { 0x00000010, 0x00221623, 0x000 },
+    { 0xffff0000, 0x00281625, 0x000 },
+    { 0x0000ffff, 0x00281a24, 0x000 },
+    { 0x00000000, 0x002948c5, 0x000 },
+    { 0x00000000, 0x00731503, 0x1f2 },
+    { 0x00000000, 0x00201805, 0x000 },
+    { 0x00000000, 0x00731524, 0x1f2 },
+    { 0x00000000, 0x002d14c5, 0x000 },
+    { 0x00000000, 0x003008a2, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00202802, 0x000 },
+    { 0x00000000, 0x00202003, 0x000 },
+    { 0x00000000, 0x00802404, 0x000 },
+    { 0x0000000f, 0x00210225, 0x000 },
+    { 0x00000000, 0x14c00000, 0x613 },
+    { 0x00000000, 0x002b1405, 0x000 },
+    { 0x00000001, 0x00901625, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x2fe },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x19f },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001a, 0x00294a22, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00384a21, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000ffff, 0x40281220, 0x000 },
+    { 0x00000010, 0xc0211a20, 0x000 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211620, 0x000 },
+    { 0x00000000, 0x00741465, 0x2a4 },
+    { 0x0001a1fd, 0x00604411, 0x2c9 },
+    { 0x00000001, 0x00330621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x206 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x1ff },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x5c5 },
+    { 0x00000000, 0x0040040f, 0x200 },
+    { 0x00000000, 0x00600000, 0x5b2 },
+    { 0x00000000, 0x00600000, 0x5c5 },
+    { 0x00000210, 0x00600411, 0x2fe },
+    { 0x00000000, 0x00600000, 0x18d },
+    { 0x00000000, 0x00600000, 0x189 },
+    { 0x00000000, 0x00600000, 0x2a4 },
+    { 0x00000000, 0x00600000, 0x28c },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204808, 0x000 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x21f },
+    { 0x00000000, 0xc0404800, 0x21c },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x00600411, 0x2e4 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x5b2 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000018, 0x40210a20, 0x000 },
+    { 0x00000003, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x235 },
+    { 0x0000001a, 0x0020222d, 0x000 },
+    { 0x00080101, 0x00292228, 0x000 },
+    { 0x0000001a, 0x00203628, 0x000 },
+    { 0x0000a30c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x23a },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000010, 0x00600411, 0x2fe },
+    { 0x3f800000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x19f },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x00000000, 0x00600000, 0x265 },
+    { 0x0000001d, 0x00201e2d, 0x000 },
+    { 0x00000001, 0x00211e27, 0x000 },
+    { 0x00000000, 0x14e00000, 0x253 },
+    { 0x00000018, 0x00201e2d, 0x000 },
+    { 0x0000ffff, 0x00281e27, 0x000 },
+    { 0x00000000, 0x00341c27, 0x000 },
+    { 0x00000000, 0x12c00000, 0x248 },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f00e5, 0x000 },
+    { 0x00000000, 0x08c00000, 0x24b },
+    { 0x00000000, 0x00201407, 0x000 },
+    { 0x00000018, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00211e27, 0x000 },
+    { 0x00000000, 0x00341c47, 0x000 },
+    { 0x00000000, 0x12c00000, 0x250 },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f00e6, 0x000 },
+    { 0x00000000, 0x08c00000, 0x253 },
+    { 0x00000000, 0x00201807, 0x000 },
+    { 0x00000000, 0x00600000, 0x2aa },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000000, 0x00342023, 0x000 },
+    { 0x00000000, 0x12c00000, 0x25b },
+    { 0x00000000, 0x00342044, 0x000 },
+    { 0x00000000, 0x12c00000, 0x25a },
+    { 0x00000016, 0x00404811, 0x25f },
+    { 0x00000018, 0x00404811, 0x25f },
+    { 0x00000000, 0x00342044, 0x000 },
+    { 0x00000000, 0x12c00000, 0x25e },
+    { 0x00000017, 0x00404811, 0x25f },
+    { 0x00000019, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0x00604411, 0x2d2 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x23f },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000010, 0x40210620, 0x000 },
+    { 0x0000ffff, 0xc0280a20, 0x000 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x00000010, 0x40211620, 0x000 },
+    { 0x0000ffff, 0xc0881a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x614 },
+    { 0x00000000, 0x00600000, 0x5b2 },
+    { 0x00000000, 0xc0600000, 0x28c },
+    { 0x00000005, 0x00200a2d, 0x000 },
+    { 0x00000008, 0x00220a22, 0x000 },
+    { 0x00000034, 0x00201a2d, 0x000 },
+    { 0x00000024, 0x00201e2d, 0x000 },
+    { 0x00007000, 0x00281e27, 0x000 },
+    { 0x00000000, 0x00311ce6, 0x000 },
+    { 0x00000033, 0x00201a2d, 0x000 },
+    { 0x0000000c, 0x00221a26, 0x000 },
+    { 0x00000000, 0x002f00e6, 0x000 },
+    { 0x00000000, 0x06e00000, 0x27b },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x00000034, 0x00203623, 0x000 },
+    { 0x00000010, 0x00201811, 0x000 },
+    { 0x00000000, 0x00691ce2, 0x128 },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x286 },
+    { 0x00000001, 0x00333e2f, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000024, 0x00403627, 0x000 },
+    { 0x0000000c, 0xc0220a20, 0x000 },
+    { 0x00000032, 0x00203622, 0x000 },
+    { 0x00000031, 0xc0403620, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000009, 0x00204811, 0x000 },
+    { 0xa1000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000029, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002c1ce3, 0x000 },
+    { 0x00000029, 0x00203627, 0x000 },
+    { 0x0000002a, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002c1ce4, 0x000 },
+    { 0x0000002a, 0x00203627, 0x000 },
+    { 0x0000002b, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120a3, 0x000 },
+    { 0x00000000, 0x002d1d07, 0x000 },
+    { 0x0000002b, 0x00203627, 0x000 },
+    { 0x0000002c, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x00000000, 0x002d1d07, 0x000 },
+    { 0x0000002c, 0x00803627, 0x000 },
+    { 0x00000029, 0x00203623, 0x000 },
+    { 0x0000002a, 0x00203624, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x0000002b, 0x00203627, 0x000 },
+    { 0x00000000, 0x00311cc4, 0x000 },
+    { 0x0000002c, 0x00803627, 0x000 },
+    { 0x00000022, 0x00203627, 0x000 },
+    { 0x00000023, 0x00203628, 0x000 },
+    { 0x0000001d, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14c00000, 0x2c5 },
+    { 0x00000000, 0x00400000, 0x2c2 },
+    { 0x00000022, 0x00203627, 0x000 },
+    { 0x00000023, 0x00203628, 0x000 },
+    { 0x0000001d, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x2c2 },
+    { 0x00000003, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x2c5 },
+    { 0x0000002b, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002e00e1, 0x000 },
+    { 0x00000000, 0x02c00000, 0x2c5 },
+    { 0x00000029, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120a1, 0x000 },
+    { 0x00000000, 0x002e00e8, 0x000 },
+    { 0x00000000, 0x06c00000, 0x2c5 },
+    { 0x0000002c, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002e00e2, 0x000 },
+    { 0x00000000, 0x02c00000, 0x2c5 },
+    { 0x0000002a, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120c2, 0x000 },
+    { 0x00000000, 0x002e00e8, 0x000 },
+    { 0x00000000, 0x06c00000, 0x2c5 },
+    { 0x00000000, 0x00600000, 0x5ed },
+    { 0x00000000, 0x00600000, 0x29e },
+    { 0x00000000, 0x00400000, 0x2c7 },
+    { 0x00000000, 0x00600000, 0x29e },
+    { 0x00000000, 0x00600000, 0x5e4 },
+    { 0x00000000, 0x00400000, 0x2c7 },
+    { 0x00000000, 0x00600000, 0x290 },
+    { 0x00000000, 0x00400000, 0x2c7 },
+    { 0x00000022, 0x00201e2d, 0x000 },
+    { 0x00000023, 0x0080222d, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000010, 0x00221e21, 0x000 },
+    { 0x00000000, 0x00294847, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000000, 0x00311ca1, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294847, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000010, 0x00221e21, 0x000 },
+    { 0x00000000, 0x003120c2, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000001, 0x00220a21, 0x000 },
+    { 0x00000000, 0x003308a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000001, 0x00220a21, 0x000 },
+    { 0x00000000, 0x003008a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x003808c5, 0x000 },
+    { 0x00000000, 0x00300841, 0x000 },
+    { 0x00000001, 0x00220a22, 0x000 },
+    { 0x00000000, 0x003308a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x0000001d, 0x0020222d, 0x000 },
+    { 0x00000000, 0x14c00000, 0x301 },
+    { 0xffffffef, 0x00280621, 0x000 },
+    { 0x0000001a, 0x0020222d, 0x000 },
+    { 0x0000f8e0, 0x00204411, 0x000 },
+    { 0x00000000, 0x00294901, 0x000 },
+    { 0x00000000, 0x00894901, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00804811, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x97000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0xc0204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00002257, 0x00204411, 0x000 },
+    { 0x00000003, 0xc0484a20, 0x000 },
+    { 0x0000225d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0x00600000, 0x5c5 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00384a22, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x40204800, 0x000 },
+    { 0x00000001, 0x40304a20, 0x000 },
+    { 0x00000002, 0xc0304a20, 0x000 },
+    { 0x00000001, 0x00530a22, 0x334 },
+    { 0x0000003f, 0xc0280a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000017, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x614 },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x33d },
+    { 0x00000014, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x351 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000016, 0x00604811, 0x35e },
+    { 0x00002100, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x00000004, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x355 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00404811, 0x349 },
+    { 0x00000028, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x349 },
+    { 0x00002104, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x00000035, 0x00203626, 0x000 },
+    { 0x00000049, 0x00201811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00331a26, 0x000 },
+    { 0x00000000, 0x002f0226, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x360 },
+    { 0x00000035, 0x00801a2d, 0x000 },
+    { 0x0000003f, 0xc0280a20, 0x000 },
+    { 0x00000015, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x376 },
+    { 0x0000001e, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x380 },
+    { 0x00000020, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x38c },
+    { 0x0000000f, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x398 },
+    { 0x00000010, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x398 },
+    { 0x00000006, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x39a },
+    { 0x00000016, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x39f },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x08000000, 0x00290a22, 0x000 },
+    { 0x00000003, 0x40210e20, 0x000 },
+    { 0x0000000c, 0xc0211220, 0x000 },
+    { 0x00080000, 0x00281224, 0x000 },
+    { 0x00000014, 0xc0221620, 0x000 },
+    { 0x00000000, 0x002914a4, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x002948a2, 0x000 },
+    { 0x0000a1fe, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404803, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000015, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x614 },
+    { 0x00000015, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x382 },
+    { 0x0000210e, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x614 },
+    { 0x00000003, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x38e },
+    { 0x00002108, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00404811, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000006, 0x00404811, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000016, 0x00604811, 0x35e },
+    { 0x00000016, 0x00404811, 0x000 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x0000001d, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x3b9 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000017, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x614 },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x3ab },
+    { 0x00002100, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0xbabecafe, 0x00204811, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000004, 0x00404811, 0x000 },
+    { 0x00002170, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000a, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3be },
+    { 0x8c000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00003fff, 0x40280a20, 0x000 },
+    { 0x80000000, 0x40280e20, 0x000 },
+    { 0x40000000, 0xc0281220, 0x000 },
+    { 0x00040000, 0x00694622, 0x614 },
+    { 0x00000000, 0x00201410, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x3cc },
+    { 0x00000000, 0xc0401800, 0x3cf },
+    { 0x00003fff, 0xc0281a20, 0x000 },
+    { 0x00040000, 0x00694626, 0x614 },
+    { 0x00000000, 0x00201810, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x3d2 },
+    { 0x00000000, 0xc0401c00, 0x3d5 },
+    { 0x00003fff, 0xc0281e20, 0x000 },
+    { 0x00040000, 0x00694627, 0x614 },
+    { 0x00000000, 0x00201c10, 0x000 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0x002820c5, 0x000 },
+    { 0x00000000, 0x004948e8, 0x000 },
+    { 0xa5800000, 0x00200811, 0x000 },
+    { 0x00002000, 0x00200c11, 0x000 },
+    { 0x83000000, 0x00604411, 0x3fd },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x40204800, 0x000 },
+    { 0x0000001f, 0xc0210220, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3e2 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0000ffff, 0xc0481220, 0x3ea },
+    { 0xa7800000, 0x00200811, 0x000 },
+    { 0x0000a000, 0x00200c11, 0x000 },
+    { 0x83000000, 0x00604411, 0x3fd },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x83000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00304883, 0x000 },
+    { 0x84000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x1d000000, 0x000 },
+    { 0x83000000, 0x00604411, 0x3fd },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0xa9800000, 0x00200811, 0x000 },
+    { 0x0000c000, 0x00400c11, 0x3e5 },
+    { 0xab800000, 0x00200811, 0x000 },
+    { 0x0000f8e0, 0x00400c11, 0x3e5 },
+    { 0xad800000, 0x00200811, 0x000 },
+    { 0x0000f880, 0x00400c11, 0x3e5 },
+    { 0xb3800000, 0x00200811, 0x000 },
+    { 0x0000f3fc, 0x00400c11, 0x3e5 },
+    { 0xaf800000, 0x00200811, 0x000 },
+    { 0x0000e000, 0x00400c11, 0x3e5 },
+    { 0xb1800000, 0x00200811, 0x000 },
+    { 0x0000f000, 0x00400c11, 0x3e5 },
+    { 0x83000000, 0x00204411, 0x000 },
+    { 0x00002148, 0x00204811, 0x000 },
+    { 0x84000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x1d000000, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00182000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0018a000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0018c000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0018f8e0, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0018f880, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0018e000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0018f000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0018f3fc, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x86000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404801, 0x000 },
+    { 0x85000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404801, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x614 },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000000, 0x00404c02, 0x42e },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x00000000, 0xc0201000, 0x000 },
+    { 0x00000000, 0xc0201400, 0x000 },
+    { 0x00000000, 0xc0201800, 0x000 },
+    { 0x00000000, 0xc0201c00, 0x000 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x43c },
+    { 0x00000000, 0xc0202000, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x00000010, 0x00280a23, 0x000 },
+    { 0x00000010, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x444 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00040000, 0x00694624, 0x614 },
+    { 0x00000000, 0x00400000, 0x44d },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x00000000, 0x1ac00000, 0x449 },
+    { 0x9e000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000000, 0x1ae00000, 0x44c },
+    { 0x00000000, 0x002824f0, 0x000 },
+    { 0x00000007, 0x00280a23, 0x000 },
+    { 0x00000001, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x454 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x04e00000, 0x46d },
+    { 0x00000000, 0x00400000, 0x47a },
+    { 0x00000002, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x459 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x02e00000, 0x46d },
+    { 0x00000000, 0x00400000, 0x47a },
+    { 0x00000003, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x45e },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x46d },
+    { 0x00000000, 0x00400000, 0x47a },
+    { 0x00000004, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x463 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x46d },
+    { 0x00000000, 0x00400000, 0x47a },
+    { 0x00000005, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x468 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x06e00000, 0x46d },
+    { 0x00000000, 0x00400000, 0x47a },
+    { 0x00000006, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x46d },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x08e00000, 0x46d },
+    { 0x00000000, 0x00400000, 0x47a },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x000 },
+    { 0x00000008, 0x00210a23, 0x000 },
+    { 0x00000000, 0x14c00000, 0x477 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x00000000, 0xc0204400, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x480 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0400000, 0x000 },
+    { 0x00000000, 0x00404c08, 0x43c },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x00000011, 0x40211220, 0x000 },
+    { 0x00000012, 0x40211620, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00210225, 0x000 },
+    { 0x00000000, 0x14e00000, 0x48a },
+    { 0x00040000, 0xc0494a20, 0x48b },
+    { 0xfffbffff, 0xc0284a20, 0x000 },
+    { 0x00000000, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x497 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x00210224, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000c, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x493 },
+    { 0xa0000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000004, 0x00204811, 0x000 },
+    { 0x0000216b, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204810, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000005, 0x00204811, 0x000 },
+    { 0x0000216c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204810, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00400000, 0x491 },
+    { 0x00000000, 0xc0210a20, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4ae },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x1ac00000, 0x4a9 },
+    { 0x9e000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000000, 0x1ae00000, 0x4ac },
+    { 0x00000000, 0x00400000, 0x4b2 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00040000, 0xc0294620, 0x000 },
+    { 0x00000000, 0xc0600000, 0x614 },
+    { 0x00000001, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4b9 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x00000000, 0xc0204400, 0x000 },
+    { 0x00000000, 0xc0404810, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x0000000d, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x614 },
+    { 0x00000000, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4bb },
+    { 0x00002180, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000003, 0x00333e2f, 0x000 },
+    { 0x00000001, 0x00210221, 0x000 },
+    { 0x00000000, 0x14e00000, 0x4eb },
+    { 0x00000035, 0x00200a2d, 0x000 },
+    { 0x00040000, 0x18e00c11, 0x4da },
+    { 0x00000001, 0x00333e2f, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xd8c04800, 0x4ce },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000036, 0x0020122d, 0x000 },
+    { 0x00000000, 0x00290c83, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000011, 0x00210224, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000000, 0x00400000, 0x491 },
+    { 0x00000035, 0xc0203620, 0x000 },
+    { 0x00000036, 0xc0403620, 0x000 },
+    { 0x0000304a, 0x00204411, 0x000 },
+    { 0xe0000000, 0xc0484a20, 0x000 },
+    { 0x0000000f, 0x00210221, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4f2 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0xd9000000, 0x000 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000002, 0x00204811, 0x000 },
+    { 0x000000ff, 0x00280e30, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x4f6 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0x14c00000, 0x50b },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x00000024, 0x00203623, 0x000 },
+    { 0x00000034, 0x00203623, 0x000 },
+    { 0x00000032, 0x00203623, 0x000 },
+    { 0x00000031, 0x00203623, 0x000 },
+    { 0x0000001d, 0x00203623, 0x000 },
+    { 0x0000002d, 0x00203623, 0x000 },
+    { 0x0000002e, 0x00203623, 0x000 },
+    { 0x0000001b, 0x00203623, 0x000 },
+    { 0x0000001c, 0x00203623, 0x000 },
+    { 0xffffe000, 0x00200c11, 0x000 },
+    { 0x00000029, 0x00203623, 0x000 },
+    { 0x0000002a, 0x00203623, 0x000 },
+    { 0x00001fff, 0x00200c11, 0x000 },
+    { 0x0000002b, 0x00203623, 0x000 },
+    { 0x0000002c, 0x00203623, 0x000 },
+    { 0xf1ffffff, 0x00283a2e, 0x000 },
+    { 0x0000001a, 0xc0220e20, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000033, 0x40203620, 0x000 },
+    { 0x87000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1f4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x9d000000, 0x00204411, 0x000 },
+    { 0x0000001f, 0x40214a20, 0x000 },
+    { 0x96000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x00000000, 0xc0201000, 0x000 },
+    { 0x0000001f, 0x00211624, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000025, 0x00203623, 0x000 },
+    { 0x00000003, 0x00281e23, 0x000 },
+    { 0x00000008, 0x00222223, 0x000 },
+    { 0xfffff000, 0x00282228, 0x000 },
+    { 0x00000000, 0x002920e8, 0x000 },
+    { 0x00000027, 0x00203628, 0x000 },
+    { 0x00000018, 0x00211e23, 0x000 },
+    { 0x00000028, 0x00203627, 0x000 },
+    { 0x00000002, 0x00221624, 0x000 },
+    { 0x00000000, 0x003014a8, 0x000 },
+    { 0x00000026, 0x00203625, 0x000 },
+    { 0x00000003, 0x00211a24, 0x000 },
+    { 0x10000000, 0x00281a26, 0x000 },
+    { 0xefffffff, 0x00283a2e, 0x000 },
+    { 0x00000000, 0x004938ce, 0x602 },
+    { 0x00000001, 0x40280a20, 0x000 },
+    { 0x00000006, 0x40280e20, 0x000 },
+    { 0x00000300, 0xc0281220, 0x000 },
+    { 0x00000008, 0x00211224, 0x000 },
+    { 0x00000000, 0xc0201620, 0x000 },
+    { 0x00000000, 0xc0201a20, 0x000 },
+    { 0x00000000, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x541 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00002258, 0x00300a24, 0x000 },
+    { 0x00040000, 0x00694622, 0x614 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x00020000, 0x00294a26, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x549 },
+    { 0x00000000, 0xc0201c10, 0x000 },
+    { 0x00000000, 0xc0400000, 0x55b },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x549 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00002258, 0x00300a24, 0x000 },
+    { 0x00040000, 0x00694622, 0x614 },
+    { 0x00000000, 0xc0201c10, 0x000 },
+    { 0x00000000, 0xc0400000, 0x55b },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x54d },
+    { 0x00000000, 0xc0201c00, 0x000 },
+    { 0x00000000, 0xc0400000, 0x55b },
+    { 0x00000004, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x559 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x1ac00000, 0x554 },
+    { 0x9e000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000000, 0x1ae00000, 0x557 },
+    { 0x00000000, 0x00401c10, 0x55b },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0400000, 0x000 },
+    { 0x00000000, 0x0ee00000, 0x55d },
+    { 0x00000000, 0x00600000, 0x5a4 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x56d },
+    { 0x0000a2b7, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2b6, 0x00604411, 0x614 },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x0000a2c4, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x56b },
+    { 0x0000a2d1, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d1, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x00000001, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x57d },
+    { 0x0000a2bb, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2ba, 0x00604411, 0x614 },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x0000a2c5, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x57b },
+    { 0x0000a2d2, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d2, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x00000002, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x58d },
+    { 0x0000a2bf, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2be, 0x00604411, 0x614 },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x0000a2c6, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x58b },
+    { 0x0000a2d3, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d3, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x0000a2c3, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2c2, 0x00604411, 0x614 },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x0000a2c7, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x599 },
+    { 0x0000a2d4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d4, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x85000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0x0000304a, 0x00204411, 0x000 },
+    { 0x01000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00400000, 0x59f },
+    { 0xa4000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0xc0600000, 0x5a4 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000005, 0x00204811, 0x000 },
+    { 0x0000a1f4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x88000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0xff000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000002, 0x00804811, 0x000 },
+    { 0x00000000, 0x0ee00000, 0x5b7 },
+    { 0x00001000, 0x00200811, 0x000 },
+    { 0x00000034, 0x00203622, 0x000 },
+    { 0x00000000, 0x00600000, 0x5bb },
+    { 0x00000000, 0x00600000, 0x5a4 },
+    { 0x98000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00804811, 0x000 },
+    { 0x00000000, 0xc0600000, 0x5bb },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000022, 0x00204811, 0x000 },
+    { 0x89000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0xff000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000002, 0x00804811, 0x000 },
+    { 0x0000217a, 0xc0204411, 0x000 },
+    { 0x00000000, 0x00404811, 0x000 },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0xff000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000002, 0x00804811, 0x000 },
+    { 0x00000000, 0x00600000, 0x5e1 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0xc0204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000016, 0x00604811, 0x35e },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00010000, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x09800000, 0x00204811, 0x000 },
+    { 0xffffffff, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x614 },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000004, 0x00404c11, 0x5dc },
+    { 0x0000001d, 0x00201e2d, 0x000 },
+    { 0x00000004, 0x00291e27, 0x000 },
+    { 0x0000001d, 0x00803627, 0x000 },
+    { 0x0000001d, 0x00201e2d, 0x000 },
+    { 0xfffffffb, 0x00281e27, 0x000 },
+    { 0x0000001d, 0x00803627, 0x000 },
+    { 0x0000001d, 0x00201e2d, 0x000 },
+    { 0x00000008, 0x00291e27, 0x000 },
+    { 0x0000001d, 0x00803627, 0x000 },
+    { 0x0000001d, 0x00201e2d, 0x000 },
+    { 0xfffffff7, 0x00281e27, 0x000 },
+    { 0x0000001d, 0x00803627, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000016, 0x00604811, 0x35e },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00010000, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x01800000, 0x00204811, 0x000 },
+    { 0x00ffffff, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004217f, 0x00604411, 0x614 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x613 },
+    { 0x00000010, 0x00404c11, 0x5f9 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x38c00000, 0x000 },
+    { 0x00000025, 0x00200a2d, 0x000 },
+    { 0x00000026, 0x00200e2d, 0x000 },
+    { 0x00000027, 0x0020122d, 0x000 },
+    { 0x00000028, 0x0020162d, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000004, 0x00301224, 0x000 },
+    { 0x00000000, 0x002f0064, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x612 },
+    { 0x00000003, 0x00281a22, 0x000 },
+    { 0x00000008, 0x00221222, 0x000 },
+    { 0xfffff000, 0x00281224, 0x000 },
+    { 0x00000000, 0x002910c4, 0x000 },
+    { 0x00000027, 0x00403624, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x1ac00000, 0x614 },
+    { 0x9f000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000000, 0x1ae00000, 0x617 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00001000, 0x00600411, 0x2fe },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x19f },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001b, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0xc0204411, 0x000 },
+    { 0x00000029, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x0000002c, 0x0020222d, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000002a, 0x0020222d, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000002b, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00404811, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x013304ef, 0x059b0239, 0x000 },
+    { 0x01b00159, 0x0425059b, 0x000 },
+    { 0x021201f6, 0x02390142, 0x000 },
+    { 0x0210022e, 0x0289022a, 0x000 },
+    { 0x03c2059b, 0x059b059b, 0x000 },
+    { 0x05cd05ce, 0x0308059b, 0x000 },
+    { 0x059b05a0, 0x03090329, 0x000 },
+    { 0x0313026b, 0x032b031d, 0x000 },
+    { 0x059b059b, 0x059b059b, 0x000 },
+    { 0x059b052c, 0x059b059b, 0x000 },
+    { 0x03a5059b, 0x04a2032d, 0x000 },
+    { 0x04810433, 0x0423059b, 0x000 },
+    { 0x04bb04ed, 0x042704c8, 0x000 },
+    { 0x043304f4, 0x033a0365, 0x000 },
+    { 0x059b059b, 0x059b059b, 0x000 },
+    { 0x059b059b, 0x059b059b, 0x000 },
+    { 0x059b059b, 0x05b905a2, 0x000 },
+    { 0x059b059b, 0x0007059b, 0x000 },
+    { 0x059b059b, 0x059b059b, 0x000 },
+    { 0x059b059b, 0x059b059b, 0x000 },
+    { 0x03e303d8, 0x03f303f1, 0x000 },
+    { 0x03f903f5, 0x03f703fb, 0x000 },
+    { 0x04070403, 0x040f040b, 0x000 },
+    { 0x04170413, 0x041f041b, 0x000 },
+    { 0x059b059b, 0x059b059b, 0x000 },
+    { 0x059b059b, 0x059b059b, 0x000 },
+    { 0x059b059b, 0x059b059b, 0x000 },
+    { 0x00020600, 0x06190006, 0x000 },
+};
+
+static const u32 R600_pfp_microcode[] = {
+0xd40071,
+0xd40072,
+0xca0400,
+0xa00000,
+0x7e828b,
+0x800003,
+0xca0400,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xc41838,
+0xca2400,
+0xca2800,
+0x9581a8,
+0xc41c3a,
+0xc3c000,
+0xca0800,
+0xca0c00,
+0x7c744b,
+0xc20005,
+0x99c000,
+0xc41c3a,
+0x7c744c,
+0xc0fff0,
+0x042c04,
+0x309002,
+0x7d2500,
+0x351402,
+0x7d350b,
+0x255403,
+0x7cd580,
+0x259c03,
+0x95c004,
+0xd5001b,
+0x7eddc1,
+0x7d9d80,
+0xd6801b,
+0xd5801b,
+0xd4401e,
+0xd5401e,
+0xd6401e,
+0xd6801e,
+0xd4801e,
+0xd4c01e,
+0x9783d4,
+0xd5c01e,
+0xca0800,
+0x80001b,
+0xca0c00,
+0xe4011e,
+0xd4001e,
+0x80000d,
+0xc41838,
+0xe4013e,
+0xd4001e,
+0x80000d,
+0xc41838,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4013e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca1800,
+0xd4401e,
+0xd5801e,
+0x800054,
+0xd40073,
+0xd4401e,
+0xca0800,
+0xca0c00,
+0xca1000,
+0xd48019,
+0xd4c018,
+0xd50017,
+0xd4801e,
+0xd4c01e,
+0xd5001e,
+0xe2001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca0800,
+0xd48060,
+0xd4401e,
+0x800002,
+0xd4801e,
+0xca0800,
+0xd48061,
+0xd4401e,
+0x800002,
+0xd4801e,
+0xca0800,
+0xca0c00,
+0xd4401e,
+0xd48016,
+0xd4c016,
+0xd4801e,
+0x8001b9,
+0xd4c01e,
+0xc6083e,
+0xca0c00,
+0xca1000,
+0x948004,
+0xca1400,
+0xe420f3,
+0xd42013,
+0xd56065,
+0xd4e01c,
+0xd5201c,
+0xd5601c,
+0x800002,
+0x062001,
+0xc6083e,
+0xca0c00,
+0xca1000,
+0x9483f7,
+0xca1400,
+0xe420f3,
+0x80007a,
+0xd42013,
+0xc6083e,
+0xca0c00,
+0xca1000,
+0x9883ef,
+0xca1400,
+0xd40064,
+0x80008e,
+0x000000,
+0xc41432,
+0xc6183e,
+0xc4082f,
+0x954005,
+0xc40c30,
+0xd4401e,
+0x800002,
+0xee001e,
+0x9583f5,
+0xc41031,
+0xd44033,
+0xd52065,
+0xd4a01c,
+0xd4e01c,
+0xd5201c,
+0xd40073,
+0xe4015e,
+0xd4001e,
+0x8001b9,
+0x062001,
+0x0a2001,
+0xd60074,
+0xc40836,
+0xc61040,
+0x988007,
+0xcc3835,
+0x95010f,
+0xd4001f,
+0xd46062,
+0x800002,
+0xd42062,
+0xcc1433,
+0x8401bc,
+0xd40070,
+0xd5401e,
+0x800002,
+0xee001e,
+0xca0c00,
+0xca1000,
+0xd4c01a,
+0x8401bc,
+0xd5001a,
+0xcc0443,
+0x35101f,
+0x2c9401,
+0x7d098b,
+0x984005,
+0x7d15cb,
+0xd4001a,
+0x8001b9,
+0xd4006d,
+0x344401,
+0xcc0c44,
+0x98403a,
+0xcc2c46,
+0x958004,
+0xcc0445,
+0x8001b9,
+0xd4001a,
+0xd4c01a,
+0x282801,
+0x8400f3,
+0xcc1003,
+0x98801b,
+0x04380c,
+0x8400f3,
+0xcc1003,
+0x988017,
+0x043808,
+0x8400f3,
+0xcc1003,
+0x988013,
+0x043804,
+0x8400f3,
+0xcc1003,
+0x988014,
+0xcc1047,
+0x9a8009,
+0xcc1448,
+0x9840da,
+0xd4006d,
+0xcc1844,
+0xd5001a,
+0xd5401a,
+0x8000cc,
+0xd5801a,
+0x96c0d3,
+0xd4006d,
+0x8001b9,
+0xd4006e,
+0x9ac003,
+0xd4006d,
+0xd4006e,
+0x800002,
+0xec007f,
+0x9ac0ca,
+0xd4006d,
+0x8001b9,
+0xd4006e,
+0xcc1403,
+0xcc1803,
+0xcc1c03,
+0x7d9103,
+0x7dd583,
+0x7d190c,
+0x35cc1f,
+0x35701f,
+0x7cf0cb,
+0x7cd08b,
+0x880000,
+0x7e8e8b,
+0x95c004,
+0xd4006e,
+0x8001b9,
+0xd4001a,
+0xd4c01a,
+0xcc0803,
+0xcc0c03,
+0xcc1003,
+0xcc1403,
+0xcc1803,
+0xcc1c03,
+0xcc2403,
+0xcc2803,
+0x35c41f,
+0x36b01f,
+0x7c704b,
+0x34f01f,
+0x7c704b,
+0x35701f,
+0x7c704b,
+0x7d8881,
+0x7dccc1,
+0x7e5101,
+0x7e9541,
+0x7c9082,
+0x7cd4c2,
+0x7c848b,
+0x9ac003,
+0x7c8c8b,
+0x2c8801,
+0x98809c,
+0xd4006d,
+0x98409a,
+0xd4006e,
+0xcc0847,
+0xcc0c48,
+0xcc1044,
+0xd4801a,
+0xd4c01a,
+0x800104,
+0xd5001a,
+0xcc0832,
+0xd40032,
+0x9482d8,
+0xca0c00,
+0xd4401e,
+0x800002,
+0xd4001e,
+0xe4011e,
+0xd4001e,
+0xca0800,
+0xca0c00,
+0xca1000,
+0xd4401e,
+0xca1400,
+0xd4801e,
+0xd4c01e,
+0xd5001e,
+0xd5401e,
+0xd54034,
+0x800002,
+0xee001e,
+0x280404,
+0xe2001a,
+0xe2001a,
+0xd4401a,
+0xca3800,
+0xcc0803,
+0xcc0c03,
+0xcc0c03,
+0xcc0c03,
+0x9882bc,
+0x000000,
+0x8401bc,
+0xd7806f,
+0x800002,
+0xee001f,
+0xca0400,
+0xc2ff00,
+0xcc0834,
+0xc13fff,
+0x7c74cb,
+0x7cc90b,
+0x7d010f,
+0x9902af,
+0x7c738b,
+0x8401bc,
+0xd7806f,
+0x800002,
+0xee001f,
+0xca0800,
+0x281900,
+0x7d898b,
+0x958014,
+0x281404,
+0xca0c00,
+0xca1000,
+0xca1c00,
+0xca2400,
+0xe2001f,
+0xd4c01a,
+0xd5001a,
+0xd5401a,
+0xcc1803,
+0xcc2c03,
+0xcc2c03,
+0xcc2c03,
+0x7da58b,
+0x7d9c47,
+0x984296,
+0x000000,
+0x800164,
+0xd4c01a,
+0xd4401e,
+0xd4801e,
+0x800002,
+0xee001e,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4013e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca0800,
+0x248c06,
+0x0ccc06,
+0x98c006,
+0xcc1049,
+0x990004,
+0xd40071,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xd4801e,
+0x800002,
+0xee001e,
+0xca0800,
+0xca0c00,
+0x34d018,
+0x251001,
+0x95001f,
+0xc17fff,
+0xca1000,
+0xca1400,
+0xca1800,
+0xd4801d,
+0xd4c01d,
+0x7db18b,
+0xc14202,
+0xc2c001,
+0xd5801d,
+0x34dc0e,
+0x7d5d4c,
+0x7f734c,
+0xd7401e,
+0xd5001e,
+0xd5401e,
+0xc14200,
+0xc2c000,
+0x099c01,
+0x31dc10,
+0x7f5f4c,
+0x7f734c,
+0x7d8380,
+0xd5806f,
+0xd58066,
+0xd7401e,
+0xec005e,
+0xc82402,
+0x8001b9,
+0xd60074,
+0xd4401e,
+0xd4801e,
+0xd4c01e,
+0x800002,
+0xee001e,
+0x800002,
+0xee001f,
+0xd4001f,
+0x800002,
+0xd4001f,
+0xd4001f,
+0x880000,
+0xd4001f,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x010174,
+0x02017b,
+0x030090,
+0x040080,
+0x050005,
+0x060040,
+0x070033,
+0x08012f,
+0x090047,
+0x0a0037,
+0x1001b7,
+0x1700a4,
+0x22013d,
+0x23014c,
+0x2000b5,
+0x240128,
+0x27004e,
+0x28006b,
+0x2a0061,
+0x2b0053,
+0x2f0066,
+0x320088,
+0x340182,
+0x3c0159,
+0x3f0073,
+0x41018f,
+0x440131,
+0x550176,
+0x56017d,
+0x60000c,
+0x610035,
+0x620039,
+0x630039,
+0x640039,
+0x650039,
+0x660039,
+0x670039,
+0x68003b,
+0x690042,
+0x6a0049,
+0x6b0049,
+0x6c0049,
+0x6d0049,
+0x6e0049,
+0x6f0049,
+0x7301b7,
+0x000007,
+0x000007,
+0x000007,
+0x000007,
+0x000007,
+0x000007,
+0x000007,
+0x000007,
+0x000007,
+0x000007,
+0x000007,
+0x000007,
+0x000007,
+0x000007,
+0x000007,
+0x000007,
+0x000007,
+0x000007,
+};
+
+static const u32 RV610_cp_microcode[][3] = {
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0000ffff, 0x00284621, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00000000, 0x00e00000, 0x000 },
+    { 0x00010000, 0xc0294620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x00000000, 0x00600000, 0x631 },
+    { 0x00000000, 0x00600000, 0x645 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000f00, 0x00281622, 0x000 },
+    { 0x00000008, 0x00211625, 0x000 },
+    { 0x00000018, 0x00203625, 0x000 },
+    { 0x8d000000, 0x00204411, 0x000 },
+    { 0x00000004, 0x002f0225, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x018 },
+    { 0x00412000, 0x00404811, 0x019 },
+    { 0x00422000, 0x00204811, 0x000 },
+    { 0x8e000000, 0x00204411, 0x000 },
+    { 0x00000028, 0x00204a2d, 0x000 },
+    { 0x90000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x0000000c, 0x00211622, 0x000 },
+    { 0x00000003, 0x00281625, 0x000 },
+    { 0x00000019, 0x00211a22, 0x000 },
+    { 0x00000004, 0x00281a26, 0x000 },
+    { 0x00000000, 0x002914c5, 0x000 },
+    { 0x00000019, 0x00203625, 0x000 },
+    { 0x00000000, 0x003a1402, 0x000 },
+    { 0x00000016, 0x00211625, 0x000 },
+    { 0x00000003, 0x00281625, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0xfffffffc, 0x00280e23, 0x000 },
+    { 0x00000000, 0x002914a3, 0x000 },
+    { 0x00000017, 0x00203625, 0x000 },
+    { 0x00008000, 0x00280e22, 0x000 },
+    { 0x00000007, 0x00220e23, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x20000000, 0x00280e22, 0x000 },
+    { 0x00000006, 0x00210e23, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x00000000, 0x00220222, 0x000 },
+    { 0x00000000, 0x14e00000, 0x038 },
+    { 0x00000000, 0x2ee00000, 0x035 },
+    { 0x00000000, 0x2ce00000, 0x037 },
+    { 0x00000000, 0x00400e2d, 0x039 },
+    { 0x00000008, 0x00200e2d, 0x000 },
+    { 0x00000009, 0x0040122d, 0x046 },
+    { 0x00000001, 0x00400e2d, 0x039 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x003ffffc, 0x00281223, 0x000 },
+    { 0x00000002, 0x00221224, 0x000 },
+    { 0x0000001f, 0x00211e23, 0x000 },
+    { 0x00000000, 0x14e00000, 0x03e },
+    { 0x00000008, 0x00401c11, 0x041 },
+    { 0x0000000d, 0x00201e2d, 0x000 },
+    { 0x0000000f, 0x00281e27, 0x000 },
+    { 0x00000003, 0x00221e27, 0x000 },
+    { 0x7fc00000, 0x00281a23, 0x000 },
+    { 0x00000014, 0x00211a26, 0x000 },
+    { 0x00000001, 0x00331a26, 0x000 },
+    { 0x00000008, 0x00221a26, 0x000 },
+    { 0x00000000, 0x00290cc7, 0x000 },
+    { 0x00000027, 0x00203624, 0x000 },
+    { 0x00007f00, 0x00281221, 0x000 },
+    { 0x00001400, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x04b },
+    { 0x00000001, 0x00290e23, 0x000 },
+    { 0x0000000e, 0x00203623, 0x000 },
+    { 0x0000e000, 0x00204411, 0x000 },
+    { 0xfff80000, 0x00294a23, 0x000 },
+    { 0x00000000, 0x003a2c02, 0x000 },
+    { 0x00000002, 0x00220e2b, 0x000 },
+    { 0xfc000000, 0x00280e23, 0x000 },
+    { 0x0000000f, 0x00203623, 0x000 },
+    { 0x00001fff, 0x00294a23, 0x000 },
+    { 0x00000027, 0x00204a2d, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000029, 0x00200e2d, 0x000 },
+    { 0x060a0200, 0x00294a23, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00210222, 0x000 },
+    { 0x00000000, 0x14e00000, 0x061 },
+    { 0x00000000, 0x2ee00000, 0x05f },
+    { 0x00000000, 0x2ce00000, 0x05e },
+    { 0x00000000, 0x00400e2d, 0x062 },
+    { 0x00000001, 0x00400e2d, 0x062 },
+    { 0x0000000a, 0x00200e2d, 0x000 },
+    { 0x0000000b, 0x0040122d, 0x06a },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x003ffffc, 0x00281223, 0x000 },
+    { 0x00000002, 0x00221224, 0x000 },
+    { 0x7fc00000, 0x00281623, 0x000 },
+    { 0x00000014, 0x00211625, 0x000 },
+    { 0x00000001, 0x00331625, 0x000 },
+    { 0x80000000, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00290ca3, 0x000 },
+    { 0x3ffffc00, 0x00290e23, 0x000 },
+    { 0x0000001f, 0x00211e23, 0x000 },
+    { 0x00000000, 0x14e00000, 0x06d },
+    { 0x00000100, 0x00401c11, 0x070 },
+    { 0x0000000d, 0x00201e2d, 0x000 },
+    { 0x000000f0, 0x00281e27, 0x000 },
+    { 0x00000004, 0x00221e27, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000d, 0x00204811, 0x000 },
+    { 0xfffff0ff, 0x00281a30, 0x000 },
+    { 0x0000a028, 0x00204411, 0x000 },
+    { 0x00000000, 0x002948e6, 0x000 },
+    { 0x0000a018, 0x00204411, 0x000 },
+    { 0x3fffffff, 0x00284a23, 0x000 },
+    { 0x0000a010, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000030, 0x0020162d, 0x000 },
+    { 0x00000002, 0x00291625, 0x000 },
+    { 0x00000030, 0x00203625, 0x000 },
+    { 0x00000025, 0x0020162d, 0x000 },
+    { 0x00000000, 0x002f00a3, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x083 },
+    { 0x00000026, 0x0020162d, 0x000 },
+    { 0x00000000, 0x002f00a4, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x084 },
+    { 0x00000000, 0x00400000, 0x08a },
+    { 0x00000025, 0x00203623, 0x000 },
+    { 0x00000026, 0x00203624, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x08a },
+    { 0x00000000, 0x00600000, 0x668 },
+    { 0x00000000, 0x00600000, 0x65c },
+    { 0x00000002, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x08d },
+    { 0x00000012, 0xc0403620, 0x093 },
+    { 0x00000000, 0x2ee00000, 0x091 },
+    { 0x00000000, 0x2ce00000, 0x090 },
+    { 0x00000002, 0x00400e2d, 0x092 },
+    { 0x00000003, 0x00400e2d, 0x092 },
+    { 0x0000000c, 0x00200e2d, 0x000 },
+    { 0x00000012, 0x00203623, 0x000 },
+    { 0x00000003, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x098 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x0a0 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x2ee00000, 0x09e },
+    { 0x00000000, 0x2ce00000, 0x09d },
+    { 0x00000002, 0x00400e2d, 0x09f },
+    { 0x00000003, 0x00400e2d, 0x09f },
+    { 0x0000000c, 0x00200e2d, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000000, 0x003a0c02, 0x000 },
+    { 0x003f0000, 0x00280e23, 0x000 },
+    { 0x00000010, 0x00210e23, 0x000 },
+    { 0x00000011, 0x00203623, 0x000 },
+    { 0x0000001e, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0a7 },
+    { 0x00000016, 0xc0203620, 0x000 },
+    { 0x0000001f, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0aa },
+    { 0x00000015, 0xc0203620, 0x000 },
+    { 0x00000008, 0x00210e2b, 0x000 },
+    { 0x0000007f, 0x00280e23, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0e1 },
+    { 0x00000000, 0x27000000, 0x000 },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x0b3 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x0000000c, 0x00221e30, 0x000 },
+    { 0x99800000, 0x00204411, 0x000 },
+    { 0x00000004, 0x0020122d, 0x000 },
+    { 0x00000008, 0x00221224, 0x000 },
+    { 0x00000010, 0x00201811, 0x000 },
+    { 0x00000000, 0x00291ce4, 0x000 },
+    { 0x00000000, 0x00604807, 0x12f },
+    { 0x9b000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x9c000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x0033146f, 0x000 },
+    { 0x00000001, 0x00333e23, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0x00203c05, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x00000000, 0x00201010, 0x000 },
+    { 0x0000e007, 0x00204411, 0x000 },
+    { 0x0000000f, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0cb },
+    { 0x00f8ff08, 0x00204811, 0x000 },
+    { 0x98000000, 0x00404811, 0x0dc },
+    { 0x000000f0, 0x00280e22, 0x000 },
+    { 0x000000a0, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x0da },
+    { 0x00000011, 0x00200e2d, 0x000 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0d5 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0d4 },
+    { 0x00003f00, 0x00400c11, 0x0d6 },
+    { 0x00001f00, 0x00400c11, 0x0d6 },
+    { 0x00000f00, 0x00200c11, 0x000 },
+    { 0x00380009, 0x00294a23, 0x000 },
+    { 0x3f000000, 0x00280e2b, 0x000 },
+    { 0x00000002, 0x00220e23, 0x000 },
+    { 0x00000007, 0x00494a23, 0x0dc },
+    { 0x00380f09, 0x00204811, 0x000 },
+    { 0x68000007, 0x00204811, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a24, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000a202, 0x00204411, 0x000 },
+    { 0x00ff0000, 0x00280e22, 0x000 },
+    { 0x00000080, 0x00294a23, 0x000 },
+    { 0x00000027, 0x00200e2d, 0x000 },
+    { 0x00000026, 0x0020122d, 0x000 },
+    { 0x00000000, 0x002f0083, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0ea },
+    { 0x00000000, 0x00600000, 0x662 },
+    { 0x00000000, 0x00400000, 0x0eb },
+    { 0x00000000, 0x00600000, 0x665 },
+    { 0x00000007, 0x0020222d, 0x000 },
+    { 0x00000005, 0x00220e22, 0x000 },
+    { 0x00100000, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00292068, 0x000 },
+    { 0x00000000, 0x003a0c02, 0x000 },
+    { 0x000000ef, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00292068, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0x00000003, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x0f8 },
+    { 0x0000000b, 0x00210228, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0f8 },
+    { 0x00000400, 0x00292228, 0x000 },
+    { 0x00000014, 0x00203628, 0x000 },
+    { 0x0000001c, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0fd },
+    { 0x0000a30c, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000001e, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x10b },
+    { 0x0000a30f, 0x00204411, 0x000 },
+    { 0x00000011, 0x00200e2d, 0x000 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x104 },
+    { 0xffffffff, 0x00404811, 0x10b },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x107 },
+    { 0x0000ffff, 0x00404811, 0x10b },
+    { 0x00000004, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x10a },
+    { 0x000000ff, 0x00404811, 0x10b },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0002c400, 0x00204411, 0x000 },
+    { 0x0000001f, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x112 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x00000013, 0x00203623, 0x000 },
+    { 0x00000018, 0x40224a20, 0x000 },
+    { 0x00000010, 0xc0424a20, 0x114 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x00000013, 0x00203623, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000000a, 0x00201011, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x11b },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00531224, 0x117 },
+    { 0xffbfffff, 0x00283a2e, 0x000 },
+    { 0x0000001b, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x12e },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000d, 0x00204811, 0x000 },
+    { 0x00000018, 0x00220e30, 0x000 },
+    { 0xfc000000, 0x00280e23, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x00000000, 0x00201010, 0x000 },
+    { 0x0000e00e, 0x00204411, 0x000 },
+    { 0x07f8ff08, 0x00204811, 0x000 },
+    { 0x00000000, 0x00294a23, 0x000 },
+    { 0x0000001c, 0x00201e2d, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a24, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x00800000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204806, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x68d },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x68c },
+    { 0x00000004, 0x00404c11, 0x135 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x0000001c, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68d },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x13c },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00000000, 0x00600000, 0x160 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000ffff, 0x40280620, 0x000 },
+    { 0x00000010, 0xc0210a20, 0x000 },
+    { 0x00000000, 0x00341461, 0x000 },
+    { 0x00000000, 0x00741882, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x147 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x160 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x00000010, 0x40211620, 0x000 },
+    { 0x0000ffff, 0xc0681a20, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x158 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000001, 0x00300a2f, 0x000 },
+    { 0x00000001, 0x00210a22, 0x000 },
+    { 0x00000003, 0x00384a22, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001a, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600000, 0x18f },
+    { 0x00000000, 0x00600000, 0x1a0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00202c08, 0x000 },
+    { 0x00000000, 0x00202411, 0x000 },
+    { 0x00000000, 0x00202811, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000002, 0x00221e29, 0x000 },
+    { 0x00000000, 0x007048eb, 0x19c },
+    { 0x00000000, 0x00600000, 0x2bb },
+    { 0x00000001, 0x40330620, 0x000 },
+    { 0x00000000, 0xc0302409, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x181 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x00000000, 0x00400000, 0x186 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x186 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000001, 0x00530621, 0x182 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0604800, 0x197 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000011, 0x0020062d, 0x000 },
+    { 0x00000000, 0x0078042a, 0x2fb },
+    { 0x00000000, 0x00202809, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x174 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000210, 0x00600411, 0x315 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x194 },
+    { 0x00000015, 0xc0203620, 0x000 },
+    { 0x00000016, 0xc0203620, 0x000 },
+    { 0x3f800000, 0x00200411, 0x000 },
+    { 0x46000000, 0x00600811, 0x1b2 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x19b },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000021, 0x00804811, 0x000 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000ffff, 0x40281620, 0x000 },
+    { 0x00000010, 0xc0811a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000008, 0x00221e30, 0x000 },
+    { 0x00000029, 0x00201a2d, 0x000 },
+    { 0x0000e000, 0x00204411, 0x000 },
+    { 0xfffbff09, 0x00204811, 0x000 },
+    { 0x0000000f, 0x0020222d, 0x000 },
+    { 0x00001fff, 0x00294a28, 0x000 },
+    { 0x00000006, 0x0020222d, 0x000 },
+    { 0x00000000, 0x002920e8, 0x000 },
+    { 0x00000000, 0x00204808, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a26, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000100, 0x00201811, 0x000 },
+    { 0x00000008, 0x00621e28, 0x12f },
+    { 0x00000008, 0x00822228, 0x000 },
+    { 0x0002c000, 0x00204411, 0x000 },
+    { 0x00000015, 0x00600e2d, 0x1bd },
+    { 0x00000016, 0x00600e2d, 0x1bd },
+    { 0x0000c008, 0x00204411, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0x00000000, 0x14c00000, 0x1b9 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0x39000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00804802, 0x000 },
+    { 0x00000018, 0x00202e2d, 0x000 },
+    { 0x00000000, 0x003b0d63, 0x000 },
+    { 0x00000008, 0x00224a23, 0x000 },
+    { 0x00000010, 0x00224a23, 0x000 },
+    { 0x00000018, 0x00224a23, 0x000 },
+    { 0x00000000, 0x00804803, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00001000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00000007, 0x0021062f, 0x000 },
+    { 0x00000013, 0x00200a2d, 0x000 },
+    { 0x00000001, 0x00202c11, 0x000 },
+    { 0x0000ffff, 0x40282220, 0x000 },
+    { 0x0000000f, 0x00262228, 0x000 },
+    { 0x00000010, 0x40212620, 0x000 },
+    { 0x0000000f, 0x00262629, 0x000 },
+    { 0x00000000, 0x00202802, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001b, 0x00204811, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1e0 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000081, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000080, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f0227, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1dc },
+    { 0x00000000, 0x00600000, 0x1e9 },
+    { 0x00000001, 0x00531e27, 0x1d8 },
+    { 0x00000001, 0x00202c11, 0x000 },
+    { 0x0000001f, 0x00280a22, 0x000 },
+    { 0x0000001f, 0x00282a2a, 0x000 },
+    { 0x00000001, 0x00530621, 0x1d1 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000002, 0x00304a2f, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000001, 0x00301e2f, 0x000 },
+    { 0x00000000, 0x002f0227, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x1e9 },
+    { 0x00000001, 0x00531e27, 0x1e5 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x0000000f, 0x00260e23, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000000f, 0x00261224, 0x000 },
+    { 0x00000000, 0x00201411, 0x000 },
+    { 0x00000000, 0x00601811, 0x2bb },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022b, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1f8 },
+    { 0x00000010, 0x00221628, 0x000 },
+    { 0xffff0000, 0x00281625, 0x000 },
+    { 0x0000ffff, 0x00281a29, 0x000 },
+    { 0x00000000, 0x002948c5, 0x000 },
+    { 0x00000000, 0x0020480a, 0x000 },
+    { 0x00000000, 0x00202c11, 0x000 },
+    { 0x00000010, 0x00221623, 0x000 },
+    { 0xffff0000, 0x00281625, 0x000 },
+    { 0x0000ffff, 0x00281a24, 0x000 },
+    { 0x00000000, 0x002948c5, 0x000 },
+    { 0x00000000, 0x00731503, 0x205 },
+    { 0x00000000, 0x00201805, 0x000 },
+    { 0x00000000, 0x00731524, 0x205 },
+    { 0x00000000, 0x002d14c5, 0x000 },
+    { 0x00000000, 0x003008a2, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00202802, 0x000 },
+    { 0x00000000, 0x00202003, 0x000 },
+    { 0x00000000, 0x00802404, 0x000 },
+    { 0x0000000f, 0x00210225, 0x000 },
+    { 0x00000000, 0x14c00000, 0x68c },
+    { 0x00000000, 0x002b1405, 0x000 },
+    { 0x00000001, 0x00901625, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001a, 0x00294a22, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00384a21, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000ffff, 0x40281220, 0x000 },
+    { 0x00000010, 0xc0211a20, 0x000 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211620, 0x000 },
+    { 0x00000000, 0x00741465, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00000001, 0x00330621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x219 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x212 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x645 },
+    { 0x00000000, 0x0040040f, 0x213 },
+    { 0x00000000, 0x00600000, 0x631 },
+    { 0x00000000, 0x00600000, 0x645 },
+    { 0x00000210, 0x00600411, 0x315 },
+    { 0x00000000, 0x00600000, 0x1a0 },
+    { 0x00000000, 0x00600000, 0x19c },
+    { 0x00000000, 0x00600000, 0x2bb },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204808, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x232 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x00000000, 0x00400000, 0x236 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x236 },
+    { 0x00000000, 0xc0404800, 0x233 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x00600411, 0x2fb },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x631 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000018, 0x40210a20, 0x000 },
+    { 0x00000003, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x24c },
+    { 0x00000014, 0x0020222d, 0x000 },
+    { 0x00080101, 0x00292228, 0x000 },
+    { 0x00000014, 0x00203628, 0x000 },
+    { 0x0000a30c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x251 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000010, 0x00600411, 0x315 },
+    { 0x3f800000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x00000000, 0x00600000, 0x27c },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000001, 0x00211e27, 0x000 },
+    { 0x00000000, 0x14e00000, 0x26a },
+    { 0x00000012, 0x00201e2d, 0x000 },
+    { 0x0000ffff, 0x00281e27, 0x000 },
+    { 0x00000000, 0x00341c27, 0x000 },
+    { 0x00000000, 0x12c00000, 0x25f },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f00e5, 0x000 },
+    { 0x00000000, 0x08c00000, 0x262 },
+    { 0x00000000, 0x00201407, 0x000 },
+    { 0x00000012, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00211e27, 0x000 },
+    { 0x00000000, 0x00341c47, 0x000 },
+    { 0x00000000, 0x12c00000, 0x267 },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f00e6, 0x000 },
+    { 0x00000000, 0x08c00000, 0x26a },
+    { 0x00000000, 0x00201807, 0x000 },
+    { 0x00000000, 0x00600000, 0x2c1 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000000, 0x00342023, 0x000 },
+    { 0x00000000, 0x12c00000, 0x272 },
+    { 0x00000000, 0x00342044, 0x000 },
+    { 0x00000000, 0x12c00000, 0x271 },
+    { 0x00000016, 0x00404811, 0x276 },
+    { 0x00000018, 0x00404811, 0x276 },
+    { 0x00000000, 0x00342044, 0x000 },
+    { 0x00000000, 0x12c00000, 0x275 },
+    { 0x00000017, 0x00404811, 0x276 },
+    { 0x00000019, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0x00604411, 0x2e9 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x256 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000010, 0x40210620, 0x000 },
+    { 0x0000ffff, 0xc0280a20, 0x000 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x00000010, 0x40211620, 0x000 },
+    { 0x0000ffff, 0xc0881a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x00000000, 0x00600000, 0x631 },
+    { 0x00000000, 0xc0600000, 0x2a3 },
+    { 0x00000005, 0x00200a2d, 0x000 },
+    { 0x00000008, 0x00220a22, 0x000 },
+    { 0x0000002b, 0x00201a2d, 0x000 },
+    { 0x0000001c, 0x00201e2d, 0x000 },
+    { 0x00007000, 0x00281e27, 0x000 },
+    { 0x00000000, 0x00311ce6, 0x000 },
+    { 0x0000002a, 0x00201a2d, 0x000 },
+    { 0x0000000c, 0x00221a26, 0x000 },
+    { 0x00000000, 0x002f00e6, 0x000 },
+    { 0x00000000, 0x06e00000, 0x292 },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x0000002b, 0x00203623, 0x000 },
+    { 0x00000010, 0x00201811, 0x000 },
+    { 0x00000000, 0x00691ce2, 0x12f },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x29d },
+    { 0x00000001, 0x00333e2f, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000001c, 0x00403627, 0x000 },
+    { 0x0000000c, 0xc0220a20, 0x000 },
+    { 0x00000029, 0x00203622, 0x000 },
+    { 0x00000028, 0xc0403620, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000009, 0x00204811, 0x000 },
+    { 0xa1000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002c1ce3, 0x000 },
+    { 0x00000021, 0x00203627, 0x000 },
+    { 0x00000022, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002c1ce4, 0x000 },
+    { 0x00000022, 0x00203627, 0x000 },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120a3, 0x000 },
+    { 0x00000000, 0x002d1d07, 0x000 },
+    { 0x00000023, 0x00203627, 0x000 },
+    { 0x00000024, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x00000000, 0x002d1d07, 0x000 },
+    { 0x00000024, 0x00803627, 0x000 },
+    { 0x00000021, 0x00203623, 0x000 },
+    { 0x00000022, 0x00203624, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000023, 0x00203627, 0x000 },
+    { 0x00000000, 0x00311cc4, 0x000 },
+    { 0x00000024, 0x00803627, 0x000 },
+    { 0x0000001a, 0x00203627, 0x000 },
+    { 0x0000001b, 0x00203628, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14c00000, 0x2dc },
+    { 0x00000000, 0x00400000, 0x2d9 },
+    { 0x0000001a, 0x00203627, 0x000 },
+    { 0x0000001b, 0x00203628, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x2d9 },
+    { 0x00000003, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x2dc },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002e00e1, 0x000 },
+    { 0x00000000, 0x02c00000, 0x2dc },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120a1, 0x000 },
+    { 0x00000000, 0x002e00e8, 0x000 },
+    { 0x00000000, 0x06c00000, 0x2dc },
+    { 0x00000024, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002e00e2, 0x000 },
+    { 0x00000000, 0x02c00000, 0x2dc },
+    { 0x00000022, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120c2, 0x000 },
+    { 0x00000000, 0x002e00e8, 0x000 },
+    { 0x00000000, 0x06c00000, 0x2dc },
+    { 0x00000000, 0x00600000, 0x668 },
+    { 0x00000000, 0x00600000, 0x2b5 },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x00000000, 0x00600000, 0x2b5 },
+    { 0x00000000, 0x00600000, 0x65f },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x00000000, 0x00600000, 0x2a7 },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x0000001a, 0x00201e2d, 0x000 },
+    { 0x0000001b, 0x0080222d, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000010, 0x00221e21, 0x000 },
+    { 0x00000000, 0x00294847, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000000, 0x00311ca1, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294847, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000010, 0x00221e21, 0x000 },
+    { 0x00000000, 0x003120c2, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000001, 0x00220a21, 0x000 },
+    { 0x00000000, 0x003308a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000001, 0x00220a21, 0x000 },
+    { 0x00000000, 0x003008a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x003808c5, 0x000 },
+    { 0x00000000, 0x00300841, 0x000 },
+    { 0x00000001, 0x00220a22, 0x000 },
+    { 0x00000000, 0x003308a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000017, 0x0020222d, 0x000 },
+    { 0x00000000, 0x14c00000, 0x318 },
+    { 0xffffffef, 0x00280621, 0x000 },
+    { 0x00000014, 0x0020222d, 0x000 },
+    { 0x0000f8e0, 0x00204411, 0x000 },
+    { 0x00000000, 0x00294901, 0x000 },
+    { 0x00000000, 0x00894901, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00804811, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x97000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0xc0204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00002257, 0x00204411, 0x000 },
+    { 0x00000003, 0xc0484a20, 0x000 },
+    { 0x0000225d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0x00600000, 0x645 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00384a22, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x40204800, 0x000 },
+    { 0x00000001, 0x40304a20, 0x000 },
+    { 0x00000002, 0xc0304a20, 0x000 },
+    { 0x00000001, 0x00530a22, 0x34b },
+    { 0x0000003f, 0xc0280a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000018, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68d },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x354 },
+    { 0x00000014, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x364 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00604802, 0x36e },
+    { 0x00002100, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000004, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x36a },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x35f },
+    { 0x00000028, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5c0 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x35f },
+    { 0x0000002c, 0x00203626, 0x000 },
+    { 0x00000049, 0x00201811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x00000001, 0x00331a26, 0x000 },
+    { 0x00000000, 0x002f0226, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x370 },
+    { 0x0000002c, 0x00801a2d, 0x000 },
+    { 0x0000003f, 0xc0280a20, 0x000 },
+    { 0x00000015, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x386 },
+    { 0x00000006, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3b1 },
+    { 0x00000016, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3b5 },
+    { 0x00000020, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x39c },
+    { 0x0000000f, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3a8 },
+    { 0x00000010, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3a8 },
+    { 0x0000001e, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x390 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x08000000, 0x00290a22, 0x000 },
+    { 0x00000003, 0x40210e20, 0x000 },
+    { 0x0000000c, 0xc0211220, 0x000 },
+    { 0x00080000, 0x00281224, 0x000 },
+    { 0x00000014, 0xc0221620, 0x000 },
+    { 0x00000000, 0x002914a4, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x002948a2, 0x000 },
+    { 0x0000a1fe, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404803, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68d },
+    { 0x00000015, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x392 },
+    { 0x0000210e, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000017, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68d },
+    { 0x00000003, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x39e },
+    { 0x00002108, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x80000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000010, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3ae },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000006, 0x00404811, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x36e },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x0000001d, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x3ce },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000018, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68d },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x3c0 },
+    { 0x00002100, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0xbabecafe, 0x00204811, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000004, 0x00404811, 0x000 },
+    { 0x00002170, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000a, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3d3 },
+    { 0x8c000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00003fff, 0x40280a20, 0x000 },
+    { 0x80000000, 0x40280e20, 0x000 },
+    { 0x40000000, 0xc0281220, 0x000 },
+    { 0x00040000, 0x00694622, 0x68d },
+    { 0x00000000, 0x00201410, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x3e1 },
+    { 0x00000000, 0xc0401800, 0x3e4 },
+    { 0x00003fff, 0xc0281a20, 0x000 },
+    { 0x00040000, 0x00694626, 0x68d },
+    { 0x00000000, 0x00201810, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x3e7 },
+    { 0x00000000, 0xc0401c00, 0x3ea },
+    { 0x00003fff, 0xc0281e20, 0x000 },
+    { 0x00040000, 0x00694627, 0x68d },
+    { 0x00000000, 0x00201c10, 0x000 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0x002820c5, 0x000 },
+    { 0x00000000, 0x004948e8, 0x000 },
+    { 0xa5800000, 0x00200811, 0x000 },
+    { 0x00002000, 0x00200c11, 0x000 },
+    { 0x83000000, 0x00604411, 0x412 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x40204800, 0x000 },
+    { 0x0000001f, 0xc0210220, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3f7 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0000ffff, 0xc0481220, 0x3ff },
+    { 0xa7800000, 0x00200811, 0x000 },
+    { 0x0000a000, 0x00200c11, 0x000 },
+    { 0x83000000, 0x00604411, 0x412 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x83000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00304883, 0x000 },
+    { 0x84000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x1d000000, 0x000 },
+    { 0x83000000, 0x00604411, 0x412 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0xa9800000, 0x00200811, 0x000 },
+    { 0x0000c000, 0x00400c11, 0x3fa },
+    { 0xab800000, 0x00200811, 0x000 },
+    { 0x0000f8e0, 0x00400c11, 0x3fa },
+    { 0xad800000, 0x00200811, 0x000 },
+    { 0x0000f880, 0x00400c11, 0x3fa },
+    { 0xb3800000, 0x00200811, 0x000 },
+    { 0x0000f3fc, 0x00400c11, 0x3fa },
+    { 0xaf800000, 0x00200811, 0x000 },
+    { 0x0000e000, 0x00400c11, 0x3fa },
+    { 0xb1800000, 0x00200811, 0x000 },
+    { 0x0000f000, 0x00400c11, 0x3fa },
+    { 0x83000000, 0x00204411, 0x000 },
+    { 0x00002148, 0x00204811, 0x000 },
+    { 0x84000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x1d000000, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x01182000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0218a000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0318c000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0418f8e0, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0518f880, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0618e000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0718f000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0818f3fc, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00000030, 0x00200a2d, 0x000 },
+    { 0x00000000, 0xc0290c40, 0x000 },
+    { 0x00000030, 0x00203623, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x86000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404801, 0x000 },
+    { 0x85000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0x00404801, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x00000018, 0x40210220, 0x000 },
+    { 0x00000000, 0x14c00000, 0x445 },
+    { 0x00800000, 0xc0494a20, 0x446 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x68d },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000000, 0x00404c02, 0x44b },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x00000000, 0xc0201000, 0x000 },
+    { 0x00000000, 0xc0201400, 0x000 },
+    { 0x00000000, 0xc0201800, 0x000 },
+    { 0x00000000, 0xc0201c00, 0x000 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x459 },
+    { 0x00000000, 0xc0202000, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x00000010, 0x00280a23, 0x000 },
+    { 0x00000010, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x461 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00040000, 0x00694624, 0x68d },
+    { 0x00000000, 0x00400000, 0x466 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000000, 0x00604805, 0x692 },
+    { 0x00000000, 0x002824f0, 0x000 },
+    { 0x00000007, 0x00280a23, 0x000 },
+    { 0x00000001, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x46d },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x04e00000, 0x486 },
+    { 0x00000000, 0x00400000, 0x493 },
+    { 0x00000002, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x472 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x02e00000, 0x486 },
+    { 0x00000000, 0x00400000, 0x493 },
+    { 0x00000003, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x477 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x486 },
+    { 0x00000000, 0x00400000, 0x493 },
+    { 0x00000004, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x47c },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x486 },
+    { 0x00000000, 0x00400000, 0x493 },
+    { 0x00000005, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x481 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x06e00000, 0x486 },
+    { 0x00000000, 0x00400000, 0x493 },
+    { 0x00000006, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x486 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x08e00000, 0x486 },
+    { 0x00000000, 0x00400000, 0x493 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x000 },
+    { 0x00000008, 0x00210a23, 0x000 },
+    { 0x00000000, 0x14c00000, 0x490 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x00000000, 0xc0204400, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x499 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0400000, 0x000 },
+    { 0x00000000, 0x00404c08, 0x459 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x00000011, 0x40211220, 0x000 },
+    { 0x00000012, 0x40211620, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00210225, 0x000 },
+    { 0x00000000, 0x14e00000, 0x4a3 },
+    { 0x00040000, 0xc0494a20, 0x4a4 },
+    { 0xfffbffff, 0xc0284a20, 0x000 },
+    { 0x00000000, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x4b0 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x00210224, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000c, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4ac },
+    { 0xa0000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000004, 0x00204811, 0x000 },
+    { 0x0000216b, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204810, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000005, 0x00204811, 0x000 },
+    { 0x0000216c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204810, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00400000, 0x4aa },
+    { 0x00000000, 0xc0210a20, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4c3 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0604800, 0x692 },
+    { 0x00000000, 0x00400000, 0x4c7 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00040000, 0xc0294620, 0x000 },
+    { 0x00000000, 0xc0600000, 0x68d },
+    { 0x00000001, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4ce },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x00000000, 0xc0204400, 0x000 },
+    { 0x00000000, 0xc0404810, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68d },
+    { 0x00000000, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4d0 },
+    { 0x00002180, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000003, 0x00333e2f, 0x000 },
+    { 0x00000001, 0x00210221, 0x000 },
+    { 0x00000000, 0x14e00000, 0x500 },
+    { 0x0000002c, 0x00200a2d, 0x000 },
+    { 0x00040000, 0x18e00c11, 0x4ef },
+    { 0x00000001, 0x00333e2f, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xd8c04800, 0x4e3 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000002d, 0x0020122d, 0x000 },
+    { 0x00000000, 0x00290c83, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000011, 0x00210224, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000000, 0x00400000, 0x4aa },
+    { 0x0000002c, 0xc0203620, 0x000 },
+    { 0x0000002d, 0xc0403620, 0x000 },
+    { 0x0000000f, 0x00210221, 0x000 },
+    { 0x00000000, 0x14c00000, 0x505 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0xd9000000, 0x000 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0xb5000000, 0x00204411, 0x000 },
+    { 0x00002000, 0x00204811, 0x000 },
+    { 0xb6000000, 0x00204411, 0x000 },
+    { 0x0000a000, 0x00204811, 0x000 },
+    { 0xb7000000, 0x00204411, 0x000 },
+    { 0x0000c000, 0x00204811, 0x000 },
+    { 0xb8000000, 0x00204411, 0x000 },
+    { 0x0000f8e0, 0x00204811, 0x000 },
+    { 0xb9000000, 0x00204411, 0x000 },
+    { 0x0000f880, 0x00204811, 0x000 },
+    { 0xba000000, 0x00204411, 0x000 },
+    { 0x0000e000, 0x00204811, 0x000 },
+    { 0xbb000000, 0x00204411, 0x000 },
+    { 0x0000f000, 0x00204811, 0x000 },
+    { 0xbc000000, 0x00204411, 0x000 },
+    { 0x0000f3fc, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000002, 0x00204811, 0x000 },
+    { 0x000000ff, 0x00280e30, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x519 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0x14c00000, 0x52e },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x0000001c, 0x00203623, 0x000 },
+    { 0x0000002b, 0x00203623, 0x000 },
+    { 0x00000029, 0x00203623, 0x000 },
+    { 0x00000028, 0x00203623, 0x000 },
+    { 0x00000017, 0x00203623, 0x000 },
+    { 0x00000025, 0x00203623, 0x000 },
+    { 0x00000026, 0x00203623, 0x000 },
+    { 0x00000015, 0x00203623, 0x000 },
+    { 0x00000016, 0x00203623, 0x000 },
+    { 0xffffe000, 0x00200c11, 0x000 },
+    { 0x00000021, 0x00203623, 0x000 },
+    { 0x00000022, 0x00203623, 0x000 },
+    { 0x00001fff, 0x00200c11, 0x000 },
+    { 0x00000023, 0x00203623, 0x000 },
+    { 0x00000024, 0x00203623, 0x000 },
+    { 0xf1ffffff, 0x00283a2e, 0x000 },
+    { 0x0000001a, 0xc0220e20, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x0000002a, 0x40203620, 0x000 },
+    { 0x87000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1f4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x00000030, 0x00203623, 0x000 },
+    { 0x9d000000, 0x00204411, 0x000 },
+    { 0x0000001f, 0x40214a20, 0x000 },
+    { 0x96000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x00000000, 0xc0201000, 0x000 },
+    { 0x0000001f, 0x00211624, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x0000001d, 0x00203623, 0x000 },
+    { 0x00000003, 0x00281e23, 0x000 },
+    { 0x00000008, 0x00222223, 0x000 },
+    { 0xfffff000, 0x00282228, 0x000 },
+    { 0x00000000, 0x002920e8, 0x000 },
+    { 0x0000001f, 0x00203628, 0x000 },
+    { 0x00000018, 0x00211e23, 0x000 },
+    { 0x00000020, 0x00203627, 0x000 },
+    { 0x00000002, 0x00221624, 0x000 },
+    { 0x00000000, 0x003014a8, 0x000 },
+    { 0x0000001e, 0x00203625, 0x000 },
+    { 0x00000003, 0x00211a24, 0x000 },
+    { 0x10000000, 0x00281a26, 0x000 },
+    { 0xefffffff, 0x00283a2e, 0x000 },
+    { 0x00000000, 0x004938ce, 0x67b },
+    { 0x00000001, 0x40280a20, 0x000 },
+    { 0x00000006, 0x40280e20, 0x000 },
+    { 0x00000300, 0xc0281220, 0x000 },
+    { 0x00000008, 0x00211224, 0x000 },
+    { 0x00000000, 0xc0201620, 0x000 },
+    { 0x00000000, 0xc0201a20, 0x000 },
+    { 0x00000000, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x566 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00002258, 0x00300a24, 0x000 },
+    { 0x00040000, 0x00694622, 0x68d },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x00020000, 0x00294a26, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x56e },
+    { 0x00000000, 0xc0201c10, 0x000 },
+    { 0x00000000, 0xc0400000, 0x57c },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x56e },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00002258, 0x00300a24, 0x000 },
+    { 0x00040000, 0x00694622, 0x68d },
+    { 0x00000000, 0xc0201c10, 0x000 },
+    { 0x00000000, 0xc0400000, 0x57c },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x572 },
+    { 0x00000000, 0xc0201c00, 0x000 },
+    { 0x00000000, 0xc0400000, 0x57c },
+    { 0x00000004, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x57a },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0604800, 0x692 },
+    { 0x00000000, 0x00401c10, 0x57c },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0400000, 0x000 },
+    { 0x00000000, 0x0ee00000, 0x57e },
+    { 0x00000000, 0x00600000, 0x5c9 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x58f },
+    { 0x0000a2b7, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2b6, 0x00604411, 0x68d },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x0000a2c4, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x58d },
+    { 0x0000a2d1, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d1, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x00000001, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5a0 },
+    { 0x0000a2bb, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2ba, 0x00604411, 0x68d },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x0000a2c5, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x59e },
+    { 0x0000a2d2, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d2, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x00000002, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5b1 },
+    { 0x0000a2bf, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2be, 0x00604411, 0x68d },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x0000a2c6, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x5af },
+    { 0x0000a2d3, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d3, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x0000a2c3, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2c2, 0x00604411, 0x68d },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x0000a2c7, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x5be },
+    { 0x0000a2d4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d4, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x85000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0x0000304a, 0x00204411, 0x000 },
+    { 0x01000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00400000, 0x5c4 },
+    { 0xa4000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0xc0600000, 0x5c9 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000002c, 0x00203621, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000000, 0x002f0230, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5d0 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000030, 0x00403621, 0x5e3 },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x00007e00, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x5e3 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a092, 0x00604411, 0x68d },
+    { 0x00000031, 0x00203630, 0x000 },
+    { 0x0004a093, 0x00604411, 0x68d },
+    { 0x00000032, 0x00203630, 0x000 },
+    { 0x0004a2b6, 0x00604411, 0x68d },
+    { 0x00000033, 0x00203630, 0x000 },
+    { 0x0004a2ba, 0x00604411, 0x68d },
+    { 0x00000034, 0x00203630, 0x000 },
+    { 0x0004a2be, 0x00604411, 0x68d },
+    { 0x00000035, 0x00203630, 0x000 },
+    { 0x0004a2c2, 0x00604411, 0x68d },
+    { 0x00000036, 0x00203630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x00000005, 0x00204811, 0x000 },
+    { 0x0000a1f4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x88000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000001, 0x002f0230, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x62c },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x62c },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00007e00, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x605 },
+    { 0x0000a092, 0x00204411, 0x000 },
+    { 0x00000031, 0x00204a2d, 0x000 },
+    { 0x0000a093, 0x00204411, 0x000 },
+    { 0x00000032, 0x00204a2d, 0x000 },
+    { 0x0000a2b6, 0x00204411, 0x000 },
+    { 0x00000033, 0x00204a2d, 0x000 },
+    { 0x0000a2ba, 0x00204411, 0x000 },
+    { 0x00000034, 0x00204a2d, 0x000 },
+    { 0x0000a2be, 0x00204411, 0x000 },
+    { 0x00000035, 0x00204a2d, 0x000 },
+    { 0x0000a2c2, 0x00204411, 0x000 },
+    { 0x00000036, 0x00204a2d, 0x000 },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x000001ff, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x62b },
+    { 0x00000000, 0x00210221, 0x000 },
+    { 0x00000000, 0x14c00000, 0x60e },
+    { 0x0004a003, 0x00604411, 0x68d },
+    { 0x0000a003, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00000001, 0x00210621, 0x000 },
+    { 0x00000000, 0x14c00000, 0x613 },
+    { 0x0004a010, 0x00604411, 0x68d },
+    { 0x0000a010, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00000001, 0x00210621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x62b },
+    { 0x0004a011, 0x00604411, 0x68d },
+    { 0x0000a011, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a012, 0x00604411, 0x68d },
+    { 0x0000a012, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a013, 0x00604411, 0x68d },
+    { 0x0000a013, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a014, 0x00604411, 0x68d },
+    { 0x0000a014, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a015, 0x00604411, 0x68d },
+    { 0x0000a015, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a016, 0x00604411, 0x68d },
+    { 0x0000a016, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a017, 0x00604411, 0x68d },
+    { 0x0000a017, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x0000002c, 0x0080062d, 0x000 },
+    { 0xff000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000002, 0x00804811, 0x000 },
+    { 0x00000000, 0x0ee00000, 0x63d },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x00000002, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x63b },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x00001000, 0x00200811, 0x000 },
+    { 0x0000002b, 0x00203622, 0x000 },
+    { 0x00000000, 0x00600000, 0x641 },
+    { 0x00000000, 0x00600000, 0x5c9 },
+    { 0x98000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00804811, 0x000 },
+    { 0x00000000, 0xc0600000, 0x641 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000022, 0x00204811, 0x000 },
+    { 0x89000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00404811, 0x62d },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404811, 0x62d },
+    { 0x00000000, 0x00600000, 0x65c },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0xc0204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x36e },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00010000, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x09800000, 0x00204811, 0x000 },
+    { 0xffffffff, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x68d },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000004, 0x00404c11, 0x656 },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000004, 0x00291e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0xfffffffb, 0x00281e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000008, 0x00291e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0xfffffff7, 0x00281e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x36e },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00010000, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x01800000, 0x00204811, 0x000 },
+    { 0xffffffff, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004217f, 0x00604411, 0x68d },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x68c },
+    { 0x00000010, 0x00404c11, 0x672 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x38c00000, 0x000 },
+    { 0x0000001d, 0x00200a2d, 0x000 },
+    { 0x0000001e, 0x00200e2d, 0x000 },
+    { 0x0000001f, 0x0020122d, 0x000 },
+    { 0x00000020, 0x0020162d, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000004, 0x00301224, 0x000 },
+    { 0x00000000, 0x002f0064, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x68b },
+    { 0x00000003, 0x00281a22, 0x000 },
+    { 0x00000008, 0x00221222, 0x000 },
+    { 0xfffff000, 0x00281224, 0x000 },
+    { 0x00000000, 0x002910c4, 0x000 },
+    { 0x0000001f, 0x00403624, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x1ac00000, 0x68d },
+    { 0x9f000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000000, 0x1ae00000, 0x690 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x1ac00000, 0x692 },
+    { 0x9e000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000000, 0x1ae00000, 0x695 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00001000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001b, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0xc0204411, 0x000 },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000024, 0x0020222d, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000022, 0x0020222d, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00404811, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x01420502, 0x05c00250, 0x000 },
+    { 0x01c30168, 0x043f05c0, 0x000 },
+    { 0x02250209, 0x02500151, 0x000 },
+    { 0x02230245, 0x02a00241, 0x000 },
+    { 0x03d705c0, 0x05c005c0, 0x000 },
+    { 0x0649064a, 0x031f05c0, 0x000 },
+    { 0x05c005c5, 0x03200340, 0x000 },
+    { 0x032a0282, 0x03420334, 0x000 },
+    { 0x05c005c0, 0x05c005c0, 0x000 },
+    { 0x05c00551, 0x05c005c0, 0x000 },
+    { 0x03ba05c0, 0x04bb0344, 0x000 },
+    { 0x049a0450, 0x043d05c0, 0x000 },
+    { 0x04d005c0, 0x044104dd, 0x000 },
+    { 0x04500507, 0x03510375, 0x000 },
+    { 0x05c005c0, 0x05c005c0, 0x000 },
+    { 0x05c005c0, 0x05c005c0, 0x000 },
+    { 0x05c005c0, 0x063f05c7, 0x000 },
+    { 0x05c005c0, 0x000705c0, 0x000 },
+    { 0x05c005c0, 0x05c005c0, 0x000 },
+    { 0x05c005c0, 0x05c005c0, 0x000 },
+    { 0x03f803ed, 0x04080406, 0x000 },
+    { 0x040e040a, 0x040c0410, 0x000 },
+    { 0x041c0418, 0x04240420, 0x000 },
+    { 0x042c0428, 0x04340430, 0x000 },
+    { 0x05c005c0, 0x043805c0, 0x000 },
+    { 0x05c005c0, 0x05c005c0, 0x000 },
+    { 0x05c005c0, 0x05c005c0, 0x000 },
+    { 0x00020679, 0x06970006, 0x000 },
+};
+
+static const u32 RV610_pfp_microcode[] = {
+0xca0400,
+0xa00000,
+0x7e828b,
+0x7c038b,
+0x8001b8,
+0x7c038b,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xc41838,
+0xca2400,
+0xca2800,
+0x9581a8,
+0xc41c3a,
+0xc3c000,
+0xca0800,
+0xca0c00,
+0x7c744b,
+0xc20005,
+0x99c000,
+0xc41c3a,
+0x7c744c,
+0xc0fff0,
+0x042c04,
+0x309002,
+0x7d2500,
+0x351402,
+0x7d350b,
+0x255403,
+0x7cd580,
+0x259c03,
+0x95c004,
+0xd5001b,
+0x7eddc1,
+0x7d9d80,
+0xd6801b,
+0xd5801b,
+0xd4401e,
+0xd5401e,
+0xd6401e,
+0xd6801e,
+0xd4801e,
+0xd4c01e,
+0x9783d3,
+0xd5c01e,
+0xca0800,
+0x80001a,
+0xca0c00,
+0xe4011e,
+0xd4001e,
+0x80000c,
+0xc41838,
+0xe4013e,
+0xd4001e,
+0x80000c,
+0xc41838,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4013e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca1800,
+0xd4401e,
+0xd5801e,
+0x800053,
+0xd40075,
+0xd4401e,
+0xca0800,
+0xca0c00,
+0xca1000,
+0xd48019,
+0xd4c018,
+0xd50017,
+0xd4801e,
+0xd4c01e,
+0xd5001e,
+0xe2001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca0800,
+0xd48060,
+0xd4401e,
+0x800000,
+0xd4801e,
+0xca0800,
+0xd48061,
+0xd4401e,
+0x800000,
+0xd4801e,
+0xca0800,
+0xca0c00,
+0xd4401e,
+0xd48016,
+0xd4c016,
+0xd4801e,
+0x8001b8,
+0xd4c01e,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x948004,
+0xca1400,
+0xe420f3,
+0xd42013,
+0xd56065,
+0xd4e01c,
+0xd5201c,
+0xd5601c,
+0x800000,
+0x062001,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x9483f7,
+0xca1400,
+0xe420f3,
+0x800079,
+0xd42013,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x9883ef,
+0xca1400,
+0xd40064,
+0x80008d,
+0x000000,
+0xc41432,
+0xc61843,
+0xc4082f,
+0x954005,
+0xc40c30,
+0xd4401e,
+0x800000,
+0xee001e,
+0x9583f5,
+0xc41031,
+0xd44033,
+0xd52065,
+0xd4a01c,
+0xd4e01c,
+0xd5201c,
+0xe4015e,
+0xd4001e,
+0x800000,
+0x062001,
+0xca1800,
+0x0a2001,
+0xd60076,
+0xc40836,
+0x988007,
+0xc61045,
+0x950110,
+0xd4001f,
+0xd46062,
+0x800000,
+0xd42062,
+0xcc3835,
+0xcc1433,
+0x8401bb,
+0xd40072,
+0xd5401e,
+0x800000,
+0xee001e,
+0xe2001a,
+0x8401bb,
+0xe2001a,
+0xcc104b,
+0xcc0447,
+0x2c9401,
+0x7d098b,
+0x984005,
+0x7d15cb,
+0xd4001a,
+0x8001b8,
+0xd4006d,
+0x344401,
+0xcc0c48,
+0x98403a,
+0xcc2c4a,
+0x958004,
+0xcc0449,
+0x8001b8,
+0xd4001a,
+0xd4c01a,
+0x282801,
+0x8400f0,
+0xcc1003,
+0x98801b,
+0x04380c,
+0x8400f0,
+0xcc1003,
+0x988017,
+0x043808,
+0x8400f0,
+0xcc1003,
+0x988013,
+0x043804,
+0x8400f0,
+0xcc1003,
+0x988014,
+0xcc104c,
+0x9a8009,
+0xcc144d,
+0x9840dc,
+0xd4006d,
+0xcc1848,
+0xd5001a,
+0xd5401a,
+0x8000c9,
+0xd5801a,
+0x96c0d5,
+0xd4006d,
+0x8001b8,
+0xd4006e,
+0x9ac003,
+0xd4006d,
+0xd4006e,
+0x800000,
+0xec007f,
+0x9ac0cc,
+0xd4006d,
+0x8001b8,
+0xd4006e,
+0xcc1403,
+0xcc1803,
+0xcc1c03,
+0x7d9103,
+0x7dd583,
+0x7d190c,
+0x35cc1f,
+0x35701f,
+0x7cf0cb,
+0x7cd08b,
+0x880000,
+0x7e8e8b,
+0x95c004,
+0xd4006e,
+0x8001b8,
+0xd4001a,
+0xd4c01a,
+0xcc0803,
+0xcc0c03,
+0xcc1003,
+0xcc1403,
+0xcc1803,
+0xcc1c03,
+0xcc2403,
+0xcc2803,
+0x35c41f,
+0x36b01f,
+0x7c704b,
+0x34f01f,
+0x7c704b,
+0x35701f,
+0x7c704b,
+0x7d8881,
+0x7dccc1,
+0x7e5101,
+0x7e9541,
+0x7c9082,
+0x7cd4c2,
+0x7c848b,
+0x9ac003,
+0x7c8c8b,
+0x2c8801,
+0x98809e,
+0xd4006d,
+0x98409c,
+0xd4006e,
+0xcc084c,
+0xcc0c4d,
+0xcc1048,
+0xd4801a,
+0xd4c01a,
+0x800101,
+0xd5001a,
+0xcc0832,
+0xd40032,
+0x9482d9,
+0xca0c00,
+0xd4401e,
+0x800000,
+0xd4001e,
+0xe4011e,
+0xd4001e,
+0xca0800,
+0xca0c00,
+0xca1000,
+0xd4401e,
+0xca1400,
+0xd4801e,
+0xd4c01e,
+0xd5001e,
+0xd5401e,
+0xd54034,
+0x800000,
+0xee001e,
+0x280404,
+0xe2001a,
+0xe2001a,
+0xd4401a,
+0xca3800,
+0xcc0803,
+0xcc0c03,
+0xcc0c03,
+0xcc0c03,
+0x9882bd,
+0x000000,
+0x8401bb,
+0xd7a06f,
+0x800000,
+0xee001f,
+0xca0400,
+0xc2ff00,
+0xcc0834,
+0xc13fff,
+0x7c74cb,
+0x7cc90b,
+0x7d010f,
+0x9902b0,
+0x7c738b,
+0x8401bb,
+0xd7a06f,
+0x800000,
+0xee001f,
+0xca0800,
+0x281900,
+0x7d898b,
+0x958014,
+0x281404,
+0xca0c00,
+0xca1000,
+0xca1c00,
+0xca2400,
+0xe2001f,
+0xd4c01a,
+0xd5001a,
+0xd5401a,
+0xcc1803,
+0xcc2c03,
+0xcc2c03,
+0xcc2c03,
+0x7da58b,
+0x7d9c47,
+0x984297,
+0x000000,
+0x800161,
+0xd4c01a,
+0xd4401e,
+0xd4801e,
+0x800000,
+0xee001e,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4013e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca0800,
+0x248c06,
+0x0ccc06,
+0x98c006,
+0xcc104e,
+0x990004,
+0xd40073,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xd4801e,
+0x800000,
+0xee001e,
+0xca0800,
+0xca0c00,
+0x34d018,
+0x251001,
+0x950021,
+0xc17fff,
+0xca1000,
+0xca1400,
+0xca1800,
+0xd4801d,
+0xd4c01d,
+0x7db18b,
+0xc14202,
+0xc2c001,
+0xd5801d,
+0x34dc0e,
+0x7d5d4c,
+0x7f734c,
+0xd7401e,
+0xd5001e,
+0xd5401e,
+0xc14200,
+0xc2c000,
+0x099c01,
+0x31dc10,
+0x7f5f4c,
+0x7f734c,
+0x042802,
+0x7d8380,
+0xd5a86f,
+0xd58066,
+0xd7401e,
+0xec005e,
+0xc82402,
+0xc82402,
+0x8001b8,
+0xd60076,
+0xd4401e,
+0xd4801e,
+0xd4c01e,
+0x800000,
+0xee001e,
+0x800000,
+0xee001f,
+0xd4001f,
+0x800000,
+0xd4001f,
+0xd4001f,
+0x880000,
+0xd4001f,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x010171,
+0x020178,
+0x03008f,
+0x04007f,
+0x050003,
+0x06003f,
+0x070032,
+0x08012c,
+0x090046,
+0x0a0036,
+0x1001b6,
+0x1700a2,
+0x22013a,
+0x230149,
+0x2000b4,
+0x240125,
+0x27004d,
+0x28006a,
+0x2a0060,
+0x2b0052,
+0x2f0065,
+0x320087,
+0x34017f,
+0x3c0156,
+0x3f0072,
+0x41018c,
+0x44012e,
+0x550173,
+0x56017a,
+0x60000b,
+0x610034,
+0x620038,
+0x630038,
+0x640038,
+0x650038,
+0x660038,
+0x670038,
+0x68003a,
+0x690041,
+0x6a0048,
+0x6b0048,
+0x6c0048,
+0x6d0048,
+0x6e0048,
+0x6f0048,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+};
+
+static const u32 RV620_cp_microcode[][3] = {
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0000ffff, 0x00284621, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00000000, 0x00e00000, 0x000 },
+    { 0x00010000, 0xc0294620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x00000000, 0x00600000, 0x631 },
+    { 0x00000000, 0x00600000, 0x645 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000f00, 0x00281622, 0x000 },
+    { 0x00000008, 0x00211625, 0x000 },
+    { 0x00000018, 0x00203625, 0x000 },
+    { 0x8d000000, 0x00204411, 0x000 },
+    { 0x00000004, 0x002f0225, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x018 },
+    { 0x00412000, 0x00404811, 0x019 },
+    { 0x00422000, 0x00204811, 0x000 },
+    { 0x8e000000, 0x00204411, 0x000 },
+    { 0x00000028, 0x00204a2d, 0x000 },
+    { 0x90000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x0000000c, 0x00211622, 0x000 },
+    { 0x00000003, 0x00281625, 0x000 },
+    { 0x00000019, 0x00211a22, 0x000 },
+    { 0x00000004, 0x00281a26, 0x000 },
+    { 0x00000000, 0x002914c5, 0x000 },
+    { 0x00000019, 0x00203625, 0x000 },
+    { 0x00000000, 0x003a1402, 0x000 },
+    { 0x00000016, 0x00211625, 0x000 },
+    { 0x00000003, 0x00281625, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0xfffffffc, 0x00280e23, 0x000 },
+    { 0x00000000, 0x002914a3, 0x000 },
+    { 0x00000017, 0x00203625, 0x000 },
+    { 0x00008000, 0x00280e22, 0x000 },
+    { 0x00000007, 0x00220e23, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x20000000, 0x00280e22, 0x000 },
+    { 0x00000006, 0x00210e23, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x00000000, 0x00220222, 0x000 },
+    { 0x00000000, 0x14e00000, 0x038 },
+    { 0x00000000, 0x2ee00000, 0x035 },
+    { 0x00000000, 0x2ce00000, 0x037 },
+    { 0x00000000, 0x00400e2d, 0x039 },
+    { 0x00000008, 0x00200e2d, 0x000 },
+    { 0x00000009, 0x0040122d, 0x046 },
+    { 0x00000001, 0x00400e2d, 0x039 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x003ffffc, 0x00281223, 0x000 },
+    { 0x00000002, 0x00221224, 0x000 },
+    { 0x0000001f, 0x00211e23, 0x000 },
+    { 0x00000000, 0x14e00000, 0x03e },
+    { 0x00000008, 0x00401c11, 0x041 },
+    { 0x0000000d, 0x00201e2d, 0x000 },
+    { 0x0000000f, 0x00281e27, 0x000 },
+    { 0x00000003, 0x00221e27, 0x000 },
+    { 0x7fc00000, 0x00281a23, 0x000 },
+    { 0x00000014, 0x00211a26, 0x000 },
+    { 0x00000001, 0x00331a26, 0x000 },
+    { 0x00000008, 0x00221a26, 0x000 },
+    { 0x00000000, 0x00290cc7, 0x000 },
+    { 0x00000027, 0x00203624, 0x000 },
+    { 0x00007f00, 0x00281221, 0x000 },
+    { 0x00001400, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x04b },
+    { 0x00000001, 0x00290e23, 0x000 },
+    { 0x0000000e, 0x00203623, 0x000 },
+    { 0x0000e000, 0x00204411, 0x000 },
+    { 0xfff80000, 0x00294a23, 0x000 },
+    { 0x00000000, 0x003a2c02, 0x000 },
+    { 0x00000002, 0x00220e2b, 0x000 },
+    { 0xfc000000, 0x00280e23, 0x000 },
+    { 0x0000000f, 0x00203623, 0x000 },
+    { 0x00001fff, 0x00294a23, 0x000 },
+    { 0x00000027, 0x00204a2d, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000029, 0x00200e2d, 0x000 },
+    { 0x060a0200, 0x00294a23, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00210222, 0x000 },
+    { 0x00000000, 0x14e00000, 0x061 },
+    { 0x00000000, 0x2ee00000, 0x05f },
+    { 0x00000000, 0x2ce00000, 0x05e },
+    { 0x00000000, 0x00400e2d, 0x062 },
+    { 0x00000001, 0x00400e2d, 0x062 },
+    { 0x0000000a, 0x00200e2d, 0x000 },
+    { 0x0000000b, 0x0040122d, 0x06a },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x003ffffc, 0x00281223, 0x000 },
+    { 0x00000002, 0x00221224, 0x000 },
+    { 0x7fc00000, 0x00281623, 0x000 },
+    { 0x00000014, 0x00211625, 0x000 },
+    { 0x00000001, 0x00331625, 0x000 },
+    { 0x80000000, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00290ca3, 0x000 },
+    { 0x3ffffc00, 0x00290e23, 0x000 },
+    { 0x0000001f, 0x00211e23, 0x000 },
+    { 0x00000000, 0x14e00000, 0x06d },
+    { 0x00000100, 0x00401c11, 0x070 },
+    { 0x0000000d, 0x00201e2d, 0x000 },
+    { 0x000000f0, 0x00281e27, 0x000 },
+    { 0x00000004, 0x00221e27, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000d, 0x00204811, 0x000 },
+    { 0xfffff0ff, 0x00281a30, 0x000 },
+    { 0x0000a028, 0x00204411, 0x000 },
+    { 0x00000000, 0x002948e6, 0x000 },
+    { 0x0000a018, 0x00204411, 0x000 },
+    { 0x3fffffff, 0x00284a23, 0x000 },
+    { 0x0000a010, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000030, 0x0020162d, 0x000 },
+    { 0x00000002, 0x00291625, 0x000 },
+    { 0x00000030, 0x00203625, 0x000 },
+    { 0x00000025, 0x0020162d, 0x000 },
+    { 0x00000000, 0x002f00a3, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x083 },
+    { 0x00000026, 0x0020162d, 0x000 },
+    { 0x00000000, 0x002f00a4, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x084 },
+    { 0x00000000, 0x00400000, 0x08a },
+    { 0x00000025, 0x00203623, 0x000 },
+    { 0x00000026, 0x00203624, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x08a },
+    { 0x00000000, 0x00600000, 0x668 },
+    { 0x00000000, 0x00600000, 0x65c },
+    { 0x00000002, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x08d },
+    { 0x00000012, 0xc0403620, 0x093 },
+    { 0x00000000, 0x2ee00000, 0x091 },
+    { 0x00000000, 0x2ce00000, 0x090 },
+    { 0x00000002, 0x00400e2d, 0x092 },
+    { 0x00000003, 0x00400e2d, 0x092 },
+    { 0x0000000c, 0x00200e2d, 0x000 },
+    { 0x00000012, 0x00203623, 0x000 },
+    { 0x00000003, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x098 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x0a0 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x2ee00000, 0x09e },
+    { 0x00000000, 0x2ce00000, 0x09d },
+    { 0x00000002, 0x00400e2d, 0x09f },
+    { 0x00000003, 0x00400e2d, 0x09f },
+    { 0x0000000c, 0x00200e2d, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000000, 0x003a0c02, 0x000 },
+    { 0x003f0000, 0x00280e23, 0x000 },
+    { 0x00000010, 0x00210e23, 0x000 },
+    { 0x00000011, 0x00203623, 0x000 },
+    { 0x0000001e, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0a7 },
+    { 0x00000016, 0xc0203620, 0x000 },
+    { 0x0000001f, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0aa },
+    { 0x00000015, 0xc0203620, 0x000 },
+    { 0x00000008, 0x00210e2b, 0x000 },
+    { 0x0000007f, 0x00280e23, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0e1 },
+    { 0x00000000, 0x27000000, 0x000 },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x0b3 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x0000000c, 0x00221e30, 0x000 },
+    { 0x99800000, 0x00204411, 0x000 },
+    { 0x00000004, 0x0020122d, 0x000 },
+    { 0x00000008, 0x00221224, 0x000 },
+    { 0x00000010, 0x00201811, 0x000 },
+    { 0x00000000, 0x00291ce4, 0x000 },
+    { 0x00000000, 0x00604807, 0x12f },
+    { 0x9b000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x9c000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x0033146f, 0x000 },
+    { 0x00000001, 0x00333e23, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0x00203c05, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x00000000, 0x00201010, 0x000 },
+    { 0x0000e007, 0x00204411, 0x000 },
+    { 0x0000000f, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0cb },
+    { 0x00f8ff08, 0x00204811, 0x000 },
+    { 0x98000000, 0x00404811, 0x0dc },
+    { 0x000000f0, 0x00280e22, 0x000 },
+    { 0x000000a0, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x0da },
+    { 0x00000011, 0x00200e2d, 0x000 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0d5 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0d4 },
+    { 0x00003f00, 0x00400c11, 0x0d6 },
+    { 0x00001f00, 0x00400c11, 0x0d6 },
+    { 0x00000f00, 0x00200c11, 0x000 },
+    { 0x00380009, 0x00294a23, 0x000 },
+    { 0x3f000000, 0x00280e2b, 0x000 },
+    { 0x00000002, 0x00220e23, 0x000 },
+    { 0x00000007, 0x00494a23, 0x0dc },
+    { 0x00380f09, 0x00204811, 0x000 },
+    { 0x68000007, 0x00204811, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a24, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000a202, 0x00204411, 0x000 },
+    { 0x00ff0000, 0x00280e22, 0x000 },
+    { 0x00000080, 0x00294a23, 0x000 },
+    { 0x00000027, 0x00200e2d, 0x000 },
+    { 0x00000026, 0x0020122d, 0x000 },
+    { 0x00000000, 0x002f0083, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0ea },
+    { 0x00000000, 0x00600000, 0x662 },
+    { 0x00000000, 0x00400000, 0x0eb },
+    { 0x00000000, 0x00600000, 0x665 },
+    { 0x00000007, 0x0020222d, 0x000 },
+    { 0x00000005, 0x00220e22, 0x000 },
+    { 0x00100000, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00292068, 0x000 },
+    { 0x00000000, 0x003a0c02, 0x000 },
+    { 0x000000ef, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00292068, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0x00000003, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x0f8 },
+    { 0x0000000b, 0x00210228, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0f8 },
+    { 0x00000400, 0x00292228, 0x000 },
+    { 0x00000014, 0x00203628, 0x000 },
+    { 0x0000001c, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0fd },
+    { 0x0000a30c, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000001e, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x10b },
+    { 0x0000a30f, 0x00204411, 0x000 },
+    { 0x00000011, 0x00200e2d, 0x000 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x104 },
+    { 0xffffffff, 0x00404811, 0x10b },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x107 },
+    { 0x0000ffff, 0x00404811, 0x10b },
+    { 0x00000004, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x10a },
+    { 0x000000ff, 0x00404811, 0x10b },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0002c400, 0x00204411, 0x000 },
+    { 0x0000001f, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x112 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x00000013, 0x00203623, 0x000 },
+    { 0x00000018, 0x40224a20, 0x000 },
+    { 0x00000010, 0xc0424a20, 0x114 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x00000013, 0x00203623, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000000a, 0x00201011, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x11b },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00531224, 0x117 },
+    { 0xffbfffff, 0x00283a2e, 0x000 },
+    { 0x0000001b, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x12e },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000d, 0x00204811, 0x000 },
+    { 0x00000018, 0x00220e30, 0x000 },
+    { 0xfc000000, 0x00280e23, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x00000000, 0x00201010, 0x000 },
+    { 0x0000e00e, 0x00204411, 0x000 },
+    { 0x07f8ff08, 0x00204811, 0x000 },
+    { 0x00000000, 0x00294a23, 0x000 },
+    { 0x0000001c, 0x00201e2d, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a24, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x00800000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204806, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x68d },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x68c },
+    { 0x00000004, 0x00404c11, 0x135 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x0000001c, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68d },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x13c },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00000000, 0x00600000, 0x160 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000ffff, 0x40280620, 0x000 },
+    { 0x00000010, 0xc0210a20, 0x000 },
+    { 0x00000000, 0x00341461, 0x000 },
+    { 0x00000000, 0x00741882, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x147 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x160 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x00000010, 0x40211620, 0x000 },
+    { 0x0000ffff, 0xc0681a20, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x158 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000001, 0x00300a2f, 0x000 },
+    { 0x00000001, 0x00210a22, 0x000 },
+    { 0x00000003, 0x00384a22, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001a, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600000, 0x18f },
+    { 0x00000000, 0x00600000, 0x1a0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00202c08, 0x000 },
+    { 0x00000000, 0x00202411, 0x000 },
+    { 0x00000000, 0x00202811, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000002, 0x00221e29, 0x000 },
+    { 0x00000000, 0x007048eb, 0x19c },
+    { 0x00000000, 0x00600000, 0x2bb },
+    { 0x00000001, 0x40330620, 0x000 },
+    { 0x00000000, 0xc0302409, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x181 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x00000000, 0x00400000, 0x186 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x186 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000001, 0x00530621, 0x182 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0604800, 0x197 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000011, 0x0020062d, 0x000 },
+    { 0x00000000, 0x0078042a, 0x2fb },
+    { 0x00000000, 0x00202809, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x174 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000210, 0x00600411, 0x315 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x194 },
+    { 0x00000015, 0xc0203620, 0x000 },
+    { 0x00000016, 0xc0203620, 0x000 },
+    { 0x3f800000, 0x00200411, 0x000 },
+    { 0x46000000, 0x00600811, 0x1b2 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x19b },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000021, 0x00804811, 0x000 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000ffff, 0x40281620, 0x000 },
+    { 0x00000010, 0xc0811a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000008, 0x00221e30, 0x000 },
+    { 0x00000029, 0x00201a2d, 0x000 },
+    { 0x0000e000, 0x00204411, 0x000 },
+    { 0xfffbff09, 0x00204811, 0x000 },
+    { 0x0000000f, 0x0020222d, 0x000 },
+    { 0x00001fff, 0x00294a28, 0x000 },
+    { 0x00000006, 0x0020222d, 0x000 },
+    { 0x00000000, 0x002920e8, 0x000 },
+    { 0x00000000, 0x00204808, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a26, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000100, 0x00201811, 0x000 },
+    { 0x00000008, 0x00621e28, 0x12f },
+    { 0x00000008, 0x00822228, 0x000 },
+    { 0x0002c000, 0x00204411, 0x000 },
+    { 0x00000015, 0x00600e2d, 0x1bd },
+    { 0x00000016, 0x00600e2d, 0x1bd },
+    { 0x0000c008, 0x00204411, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0x00000000, 0x14c00000, 0x1b9 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0x39000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00804802, 0x000 },
+    { 0x00000018, 0x00202e2d, 0x000 },
+    { 0x00000000, 0x003b0d63, 0x000 },
+    { 0x00000008, 0x00224a23, 0x000 },
+    { 0x00000010, 0x00224a23, 0x000 },
+    { 0x00000018, 0x00224a23, 0x000 },
+    { 0x00000000, 0x00804803, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00001000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00000007, 0x0021062f, 0x000 },
+    { 0x00000013, 0x00200a2d, 0x000 },
+    { 0x00000001, 0x00202c11, 0x000 },
+    { 0x0000ffff, 0x40282220, 0x000 },
+    { 0x0000000f, 0x00262228, 0x000 },
+    { 0x00000010, 0x40212620, 0x000 },
+    { 0x0000000f, 0x00262629, 0x000 },
+    { 0x00000000, 0x00202802, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001b, 0x00204811, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1e0 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000081, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000080, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f0227, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1dc },
+    { 0x00000000, 0x00600000, 0x1e9 },
+    { 0x00000001, 0x00531e27, 0x1d8 },
+    { 0x00000001, 0x00202c11, 0x000 },
+    { 0x0000001f, 0x00280a22, 0x000 },
+    { 0x0000001f, 0x00282a2a, 0x000 },
+    { 0x00000001, 0x00530621, 0x1d1 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000002, 0x00304a2f, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000001, 0x00301e2f, 0x000 },
+    { 0x00000000, 0x002f0227, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x1e9 },
+    { 0x00000001, 0x00531e27, 0x1e5 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x0000000f, 0x00260e23, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000000f, 0x00261224, 0x000 },
+    { 0x00000000, 0x00201411, 0x000 },
+    { 0x00000000, 0x00601811, 0x2bb },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022b, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1f8 },
+    { 0x00000010, 0x00221628, 0x000 },
+    { 0xffff0000, 0x00281625, 0x000 },
+    { 0x0000ffff, 0x00281a29, 0x000 },
+    { 0x00000000, 0x002948c5, 0x000 },
+    { 0x00000000, 0x0020480a, 0x000 },
+    { 0x00000000, 0x00202c11, 0x000 },
+    { 0x00000010, 0x00221623, 0x000 },
+    { 0xffff0000, 0x00281625, 0x000 },
+    { 0x0000ffff, 0x00281a24, 0x000 },
+    { 0x00000000, 0x002948c5, 0x000 },
+    { 0x00000000, 0x00731503, 0x205 },
+    { 0x00000000, 0x00201805, 0x000 },
+    { 0x00000000, 0x00731524, 0x205 },
+    { 0x00000000, 0x002d14c5, 0x000 },
+    { 0x00000000, 0x003008a2, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00202802, 0x000 },
+    { 0x00000000, 0x00202003, 0x000 },
+    { 0x00000000, 0x00802404, 0x000 },
+    { 0x0000000f, 0x00210225, 0x000 },
+    { 0x00000000, 0x14c00000, 0x68c },
+    { 0x00000000, 0x002b1405, 0x000 },
+    { 0x00000001, 0x00901625, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001a, 0x00294a22, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00384a21, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000ffff, 0x40281220, 0x000 },
+    { 0x00000010, 0xc0211a20, 0x000 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211620, 0x000 },
+    { 0x00000000, 0x00741465, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00000001, 0x00330621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x219 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x212 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x645 },
+    { 0x00000000, 0x0040040f, 0x213 },
+    { 0x00000000, 0x00600000, 0x631 },
+    { 0x00000000, 0x00600000, 0x645 },
+    { 0x00000210, 0x00600411, 0x315 },
+    { 0x00000000, 0x00600000, 0x1a0 },
+    { 0x00000000, 0x00600000, 0x19c },
+    { 0x00000000, 0x00600000, 0x2bb },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204808, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x232 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x00000000, 0x00400000, 0x236 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x236 },
+    { 0x00000000, 0xc0404800, 0x233 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x00600411, 0x2fb },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x631 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000018, 0x40210a20, 0x000 },
+    { 0x00000003, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x24c },
+    { 0x00000014, 0x0020222d, 0x000 },
+    { 0x00080101, 0x00292228, 0x000 },
+    { 0x00000014, 0x00203628, 0x000 },
+    { 0x0000a30c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x251 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000010, 0x00600411, 0x315 },
+    { 0x3f800000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x00000000, 0x00600000, 0x27c },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000001, 0x00211e27, 0x000 },
+    { 0x00000000, 0x14e00000, 0x26a },
+    { 0x00000012, 0x00201e2d, 0x000 },
+    { 0x0000ffff, 0x00281e27, 0x000 },
+    { 0x00000000, 0x00341c27, 0x000 },
+    { 0x00000000, 0x12c00000, 0x25f },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f00e5, 0x000 },
+    { 0x00000000, 0x08c00000, 0x262 },
+    { 0x00000000, 0x00201407, 0x000 },
+    { 0x00000012, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00211e27, 0x000 },
+    { 0x00000000, 0x00341c47, 0x000 },
+    { 0x00000000, 0x12c00000, 0x267 },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f00e6, 0x000 },
+    { 0x00000000, 0x08c00000, 0x26a },
+    { 0x00000000, 0x00201807, 0x000 },
+    { 0x00000000, 0x00600000, 0x2c1 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000000, 0x00342023, 0x000 },
+    { 0x00000000, 0x12c00000, 0x272 },
+    { 0x00000000, 0x00342044, 0x000 },
+    { 0x00000000, 0x12c00000, 0x271 },
+    { 0x00000016, 0x00404811, 0x276 },
+    { 0x00000018, 0x00404811, 0x276 },
+    { 0x00000000, 0x00342044, 0x000 },
+    { 0x00000000, 0x12c00000, 0x275 },
+    { 0x00000017, 0x00404811, 0x276 },
+    { 0x00000019, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0x00604411, 0x2e9 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x256 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000010, 0x40210620, 0x000 },
+    { 0x0000ffff, 0xc0280a20, 0x000 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x00000010, 0x40211620, 0x000 },
+    { 0x0000ffff, 0xc0881a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x00000000, 0x00600000, 0x631 },
+    { 0x00000000, 0xc0600000, 0x2a3 },
+    { 0x00000005, 0x00200a2d, 0x000 },
+    { 0x00000008, 0x00220a22, 0x000 },
+    { 0x0000002b, 0x00201a2d, 0x000 },
+    { 0x0000001c, 0x00201e2d, 0x000 },
+    { 0x00007000, 0x00281e27, 0x000 },
+    { 0x00000000, 0x00311ce6, 0x000 },
+    { 0x0000002a, 0x00201a2d, 0x000 },
+    { 0x0000000c, 0x00221a26, 0x000 },
+    { 0x00000000, 0x002f00e6, 0x000 },
+    { 0x00000000, 0x06e00000, 0x292 },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x0000002b, 0x00203623, 0x000 },
+    { 0x00000010, 0x00201811, 0x000 },
+    { 0x00000000, 0x00691ce2, 0x12f },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x29d },
+    { 0x00000001, 0x00333e2f, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000001c, 0x00403627, 0x000 },
+    { 0x0000000c, 0xc0220a20, 0x000 },
+    { 0x00000029, 0x00203622, 0x000 },
+    { 0x00000028, 0xc0403620, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000009, 0x00204811, 0x000 },
+    { 0xa1000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002c1ce3, 0x000 },
+    { 0x00000021, 0x00203627, 0x000 },
+    { 0x00000022, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002c1ce4, 0x000 },
+    { 0x00000022, 0x00203627, 0x000 },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120a3, 0x000 },
+    { 0x00000000, 0x002d1d07, 0x000 },
+    { 0x00000023, 0x00203627, 0x000 },
+    { 0x00000024, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x00000000, 0x002d1d07, 0x000 },
+    { 0x00000024, 0x00803627, 0x000 },
+    { 0x00000021, 0x00203623, 0x000 },
+    { 0x00000022, 0x00203624, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000023, 0x00203627, 0x000 },
+    { 0x00000000, 0x00311cc4, 0x000 },
+    { 0x00000024, 0x00803627, 0x000 },
+    { 0x0000001a, 0x00203627, 0x000 },
+    { 0x0000001b, 0x00203628, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14c00000, 0x2dc },
+    { 0x00000000, 0x00400000, 0x2d9 },
+    { 0x0000001a, 0x00203627, 0x000 },
+    { 0x0000001b, 0x00203628, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x2d9 },
+    { 0x00000003, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x2dc },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002e00e1, 0x000 },
+    { 0x00000000, 0x02c00000, 0x2dc },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120a1, 0x000 },
+    { 0x00000000, 0x002e00e8, 0x000 },
+    { 0x00000000, 0x06c00000, 0x2dc },
+    { 0x00000024, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002e00e2, 0x000 },
+    { 0x00000000, 0x02c00000, 0x2dc },
+    { 0x00000022, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120c2, 0x000 },
+    { 0x00000000, 0x002e00e8, 0x000 },
+    { 0x00000000, 0x06c00000, 0x2dc },
+    { 0x00000000, 0x00600000, 0x668 },
+    { 0x00000000, 0x00600000, 0x2b5 },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x00000000, 0x00600000, 0x2b5 },
+    { 0x00000000, 0x00600000, 0x65f },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x00000000, 0x00600000, 0x2a7 },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x0000001a, 0x00201e2d, 0x000 },
+    { 0x0000001b, 0x0080222d, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000010, 0x00221e21, 0x000 },
+    { 0x00000000, 0x00294847, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000000, 0x00311ca1, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294847, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000010, 0x00221e21, 0x000 },
+    { 0x00000000, 0x003120c2, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000001, 0x00220a21, 0x000 },
+    { 0x00000000, 0x003308a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000001, 0x00220a21, 0x000 },
+    { 0x00000000, 0x003008a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x003808c5, 0x000 },
+    { 0x00000000, 0x00300841, 0x000 },
+    { 0x00000001, 0x00220a22, 0x000 },
+    { 0x00000000, 0x003308a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000017, 0x0020222d, 0x000 },
+    { 0x00000000, 0x14c00000, 0x318 },
+    { 0xffffffef, 0x00280621, 0x000 },
+    { 0x00000014, 0x0020222d, 0x000 },
+    { 0x0000f8e0, 0x00204411, 0x000 },
+    { 0x00000000, 0x00294901, 0x000 },
+    { 0x00000000, 0x00894901, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00804811, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x97000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0xc0204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00002257, 0x00204411, 0x000 },
+    { 0x00000003, 0xc0484a20, 0x000 },
+    { 0x0000225d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0x00600000, 0x645 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00384a22, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x40204800, 0x000 },
+    { 0x00000001, 0x40304a20, 0x000 },
+    { 0x00000002, 0xc0304a20, 0x000 },
+    { 0x00000001, 0x00530a22, 0x34b },
+    { 0x0000003f, 0xc0280a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000018, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68d },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x354 },
+    { 0x00000014, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x364 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00604802, 0x36e },
+    { 0x00002100, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000004, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x36a },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x35f },
+    { 0x00000028, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5c0 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x35f },
+    { 0x0000002c, 0x00203626, 0x000 },
+    { 0x00000049, 0x00201811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x00000001, 0x00331a26, 0x000 },
+    { 0x00000000, 0x002f0226, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x370 },
+    { 0x0000002c, 0x00801a2d, 0x000 },
+    { 0x0000003f, 0xc0280a20, 0x000 },
+    { 0x00000015, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x386 },
+    { 0x00000006, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3b1 },
+    { 0x00000016, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3b5 },
+    { 0x00000020, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x39c },
+    { 0x0000000f, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3a8 },
+    { 0x00000010, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3a8 },
+    { 0x0000001e, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x390 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x08000000, 0x00290a22, 0x000 },
+    { 0x00000003, 0x40210e20, 0x000 },
+    { 0x0000000c, 0xc0211220, 0x000 },
+    { 0x00080000, 0x00281224, 0x000 },
+    { 0x00000014, 0xc0221620, 0x000 },
+    { 0x00000000, 0x002914a4, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x002948a2, 0x000 },
+    { 0x0000a1fe, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404803, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68d },
+    { 0x00000015, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x392 },
+    { 0x0000210e, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000017, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68d },
+    { 0x00000003, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x39e },
+    { 0x00002108, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x80000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000010, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3ae },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000006, 0x00404811, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x36e },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x0000001d, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x3ce },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000018, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68d },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x3c0 },
+    { 0x00002100, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0xbabecafe, 0x00204811, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000004, 0x00404811, 0x000 },
+    { 0x00002170, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000a, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3d3 },
+    { 0x8c000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00003fff, 0x40280a20, 0x000 },
+    { 0x80000000, 0x40280e20, 0x000 },
+    { 0x40000000, 0xc0281220, 0x000 },
+    { 0x00040000, 0x00694622, 0x68d },
+    { 0x00000000, 0x00201410, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x3e1 },
+    { 0x00000000, 0xc0401800, 0x3e4 },
+    { 0x00003fff, 0xc0281a20, 0x000 },
+    { 0x00040000, 0x00694626, 0x68d },
+    { 0x00000000, 0x00201810, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x3e7 },
+    { 0x00000000, 0xc0401c00, 0x3ea },
+    { 0x00003fff, 0xc0281e20, 0x000 },
+    { 0x00040000, 0x00694627, 0x68d },
+    { 0x00000000, 0x00201c10, 0x000 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0x002820c5, 0x000 },
+    { 0x00000000, 0x004948e8, 0x000 },
+    { 0xa5800000, 0x00200811, 0x000 },
+    { 0x00002000, 0x00200c11, 0x000 },
+    { 0x83000000, 0x00604411, 0x412 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x40204800, 0x000 },
+    { 0x0000001f, 0xc0210220, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3f7 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0000ffff, 0xc0481220, 0x3ff },
+    { 0xa7800000, 0x00200811, 0x000 },
+    { 0x0000a000, 0x00200c11, 0x000 },
+    { 0x83000000, 0x00604411, 0x412 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x83000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00304883, 0x000 },
+    { 0x84000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x1d000000, 0x000 },
+    { 0x83000000, 0x00604411, 0x412 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0xa9800000, 0x00200811, 0x000 },
+    { 0x0000c000, 0x00400c11, 0x3fa },
+    { 0xab800000, 0x00200811, 0x000 },
+    { 0x0000f8e0, 0x00400c11, 0x3fa },
+    { 0xad800000, 0x00200811, 0x000 },
+    { 0x0000f880, 0x00400c11, 0x3fa },
+    { 0xb3800000, 0x00200811, 0x000 },
+    { 0x0000f3fc, 0x00400c11, 0x3fa },
+    { 0xaf800000, 0x00200811, 0x000 },
+    { 0x0000e000, 0x00400c11, 0x3fa },
+    { 0xb1800000, 0x00200811, 0x000 },
+    { 0x0000f000, 0x00400c11, 0x3fa },
+    { 0x83000000, 0x00204411, 0x000 },
+    { 0x00002148, 0x00204811, 0x000 },
+    { 0x84000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x1d000000, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x01182000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0218a000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0318c000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0418f8e0, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0518f880, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0618e000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0718f000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0818f3fc, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00000030, 0x00200a2d, 0x000 },
+    { 0x00000000, 0xc0290c40, 0x000 },
+    { 0x00000030, 0x00203623, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x86000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404801, 0x000 },
+    { 0x85000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0x00404801, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x00000018, 0x40210220, 0x000 },
+    { 0x00000000, 0x14c00000, 0x445 },
+    { 0x00800000, 0xc0494a20, 0x446 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x68d },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000000, 0x00404c02, 0x44b },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x00000000, 0xc0201000, 0x000 },
+    { 0x00000000, 0xc0201400, 0x000 },
+    { 0x00000000, 0xc0201800, 0x000 },
+    { 0x00000000, 0xc0201c00, 0x000 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x459 },
+    { 0x00000000, 0xc0202000, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x00000010, 0x00280a23, 0x000 },
+    { 0x00000010, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x461 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00040000, 0x00694624, 0x68d },
+    { 0x00000000, 0x00400000, 0x466 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000000, 0x00604805, 0x692 },
+    { 0x00000000, 0x002824f0, 0x000 },
+    { 0x00000007, 0x00280a23, 0x000 },
+    { 0x00000001, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x46d },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x04e00000, 0x486 },
+    { 0x00000000, 0x00400000, 0x493 },
+    { 0x00000002, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x472 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x02e00000, 0x486 },
+    { 0x00000000, 0x00400000, 0x493 },
+    { 0x00000003, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x477 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x486 },
+    { 0x00000000, 0x00400000, 0x493 },
+    { 0x00000004, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x47c },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x486 },
+    { 0x00000000, 0x00400000, 0x493 },
+    { 0x00000005, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x481 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x06e00000, 0x486 },
+    { 0x00000000, 0x00400000, 0x493 },
+    { 0x00000006, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x486 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x08e00000, 0x486 },
+    { 0x00000000, 0x00400000, 0x493 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x000 },
+    { 0x00000008, 0x00210a23, 0x000 },
+    { 0x00000000, 0x14c00000, 0x490 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x00000000, 0xc0204400, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x499 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0400000, 0x000 },
+    { 0x00000000, 0x00404c08, 0x459 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x00000011, 0x40211220, 0x000 },
+    { 0x00000012, 0x40211620, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00210225, 0x000 },
+    { 0x00000000, 0x14e00000, 0x4a3 },
+    { 0x00040000, 0xc0494a20, 0x4a4 },
+    { 0xfffbffff, 0xc0284a20, 0x000 },
+    { 0x00000000, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x4b0 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x00210224, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000c, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4ac },
+    { 0xa0000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000004, 0x00204811, 0x000 },
+    { 0x0000216b, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204810, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000005, 0x00204811, 0x000 },
+    { 0x0000216c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204810, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00400000, 0x4aa },
+    { 0x00000000, 0xc0210a20, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4c3 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0604800, 0x692 },
+    { 0x00000000, 0x00400000, 0x4c7 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00040000, 0xc0294620, 0x000 },
+    { 0x00000000, 0xc0600000, 0x68d },
+    { 0x00000001, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4ce },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x00000000, 0xc0204400, 0x000 },
+    { 0x00000000, 0xc0404810, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68d },
+    { 0x00000000, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4d0 },
+    { 0x00002180, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000003, 0x00333e2f, 0x000 },
+    { 0x00000001, 0x00210221, 0x000 },
+    { 0x00000000, 0x14e00000, 0x500 },
+    { 0x0000002c, 0x00200a2d, 0x000 },
+    { 0x00040000, 0x18e00c11, 0x4ef },
+    { 0x00000001, 0x00333e2f, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xd8c04800, 0x4e3 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000002d, 0x0020122d, 0x000 },
+    { 0x00000000, 0x00290c83, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000011, 0x00210224, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000000, 0x00400000, 0x4aa },
+    { 0x0000002c, 0xc0203620, 0x000 },
+    { 0x0000002d, 0xc0403620, 0x000 },
+    { 0x0000000f, 0x00210221, 0x000 },
+    { 0x00000000, 0x14c00000, 0x505 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0xd9000000, 0x000 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0xb5000000, 0x00204411, 0x000 },
+    { 0x00002000, 0x00204811, 0x000 },
+    { 0xb6000000, 0x00204411, 0x000 },
+    { 0x0000a000, 0x00204811, 0x000 },
+    { 0xb7000000, 0x00204411, 0x000 },
+    { 0x0000c000, 0x00204811, 0x000 },
+    { 0xb8000000, 0x00204411, 0x000 },
+    { 0x0000f8e0, 0x00204811, 0x000 },
+    { 0xb9000000, 0x00204411, 0x000 },
+    { 0x0000f880, 0x00204811, 0x000 },
+    { 0xba000000, 0x00204411, 0x000 },
+    { 0x0000e000, 0x00204811, 0x000 },
+    { 0xbb000000, 0x00204411, 0x000 },
+    { 0x0000f000, 0x00204811, 0x000 },
+    { 0xbc000000, 0x00204411, 0x000 },
+    { 0x0000f3fc, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000002, 0x00204811, 0x000 },
+    { 0x000000ff, 0x00280e30, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x519 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0x14c00000, 0x52e },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x0000001c, 0x00203623, 0x000 },
+    { 0x0000002b, 0x00203623, 0x000 },
+    { 0x00000029, 0x00203623, 0x000 },
+    { 0x00000028, 0x00203623, 0x000 },
+    { 0x00000017, 0x00203623, 0x000 },
+    { 0x00000025, 0x00203623, 0x000 },
+    { 0x00000026, 0x00203623, 0x000 },
+    { 0x00000015, 0x00203623, 0x000 },
+    { 0x00000016, 0x00203623, 0x000 },
+    { 0xffffe000, 0x00200c11, 0x000 },
+    { 0x00000021, 0x00203623, 0x000 },
+    { 0x00000022, 0x00203623, 0x000 },
+    { 0x00001fff, 0x00200c11, 0x000 },
+    { 0x00000023, 0x00203623, 0x000 },
+    { 0x00000024, 0x00203623, 0x000 },
+    { 0xf1ffffff, 0x00283a2e, 0x000 },
+    { 0x0000001a, 0xc0220e20, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x0000002a, 0x40203620, 0x000 },
+    { 0x87000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1f4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x00000030, 0x00203623, 0x000 },
+    { 0x9d000000, 0x00204411, 0x000 },
+    { 0x0000001f, 0x40214a20, 0x000 },
+    { 0x96000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x00000000, 0xc0201000, 0x000 },
+    { 0x0000001f, 0x00211624, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x0000001d, 0x00203623, 0x000 },
+    { 0x00000003, 0x00281e23, 0x000 },
+    { 0x00000008, 0x00222223, 0x000 },
+    { 0xfffff000, 0x00282228, 0x000 },
+    { 0x00000000, 0x002920e8, 0x000 },
+    { 0x0000001f, 0x00203628, 0x000 },
+    { 0x00000018, 0x00211e23, 0x000 },
+    { 0x00000020, 0x00203627, 0x000 },
+    { 0x00000002, 0x00221624, 0x000 },
+    { 0x00000000, 0x003014a8, 0x000 },
+    { 0x0000001e, 0x00203625, 0x000 },
+    { 0x00000003, 0x00211a24, 0x000 },
+    { 0x10000000, 0x00281a26, 0x000 },
+    { 0xefffffff, 0x00283a2e, 0x000 },
+    { 0x00000000, 0x004938ce, 0x67b },
+    { 0x00000001, 0x40280a20, 0x000 },
+    { 0x00000006, 0x40280e20, 0x000 },
+    { 0x00000300, 0xc0281220, 0x000 },
+    { 0x00000008, 0x00211224, 0x000 },
+    { 0x00000000, 0xc0201620, 0x000 },
+    { 0x00000000, 0xc0201a20, 0x000 },
+    { 0x00000000, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x566 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00002258, 0x00300a24, 0x000 },
+    { 0x00040000, 0x00694622, 0x68d },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x00020000, 0x00294a26, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x56e },
+    { 0x00000000, 0xc0201c10, 0x000 },
+    { 0x00000000, 0xc0400000, 0x57c },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x56e },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00002258, 0x00300a24, 0x000 },
+    { 0x00040000, 0x00694622, 0x68d },
+    { 0x00000000, 0xc0201c10, 0x000 },
+    { 0x00000000, 0xc0400000, 0x57c },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x572 },
+    { 0x00000000, 0xc0201c00, 0x000 },
+    { 0x00000000, 0xc0400000, 0x57c },
+    { 0x00000004, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x57a },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0604800, 0x692 },
+    { 0x00000000, 0x00401c10, 0x57c },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0400000, 0x000 },
+    { 0x00000000, 0x0ee00000, 0x57e },
+    { 0x00000000, 0x00600000, 0x5c9 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x58f },
+    { 0x0000a2b7, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2b6, 0x00604411, 0x68d },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x0000a2c4, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x58d },
+    { 0x0000a2d1, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d1, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x00000001, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5a0 },
+    { 0x0000a2bb, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2ba, 0x00604411, 0x68d },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x0000a2c5, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x59e },
+    { 0x0000a2d2, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d2, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x00000002, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5b1 },
+    { 0x0000a2bf, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2be, 0x00604411, 0x68d },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x0000a2c6, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x5af },
+    { 0x0000a2d3, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d3, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x0000a2c3, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2c2, 0x00604411, 0x68d },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x0000a2c7, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x5be },
+    { 0x0000a2d4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d4, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x85000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0x0000304a, 0x00204411, 0x000 },
+    { 0x01000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00400000, 0x5c4 },
+    { 0xa4000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0xc0600000, 0x5c9 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000002c, 0x00203621, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000000, 0x002f0230, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5d0 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000030, 0x00403621, 0x5e3 },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x00007e00, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x5e3 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a092, 0x00604411, 0x68d },
+    { 0x00000031, 0x00203630, 0x000 },
+    { 0x0004a093, 0x00604411, 0x68d },
+    { 0x00000032, 0x00203630, 0x000 },
+    { 0x0004a2b6, 0x00604411, 0x68d },
+    { 0x00000033, 0x00203630, 0x000 },
+    { 0x0004a2ba, 0x00604411, 0x68d },
+    { 0x00000034, 0x00203630, 0x000 },
+    { 0x0004a2be, 0x00604411, 0x68d },
+    { 0x00000035, 0x00203630, 0x000 },
+    { 0x0004a2c2, 0x00604411, 0x68d },
+    { 0x00000036, 0x00203630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x00000005, 0x00204811, 0x000 },
+    { 0x0000a1f4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x88000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000001, 0x002f0230, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x62c },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x62c },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00007e00, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x605 },
+    { 0x0000a092, 0x00204411, 0x000 },
+    { 0x00000031, 0x00204a2d, 0x000 },
+    { 0x0000a093, 0x00204411, 0x000 },
+    { 0x00000032, 0x00204a2d, 0x000 },
+    { 0x0000a2b6, 0x00204411, 0x000 },
+    { 0x00000033, 0x00204a2d, 0x000 },
+    { 0x0000a2ba, 0x00204411, 0x000 },
+    { 0x00000034, 0x00204a2d, 0x000 },
+    { 0x0000a2be, 0x00204411, 0x000 },
+    { 0x00000035, 0x00204a2d, 0x000 },
+    { 0x0000a2c2, 0x00204411, 0x000 },
+    { 0x00000036, 0x00204a2d, 0x000 },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x000001ff, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x62b },
+    { 0x00000000, 0x00210221, 0x000 },
+    { 0x00000000, 0x14c00000, 0x60e },
+    { 0x0004a003, 0x00604411, 0x68d },
+    { 0x0000a003, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00000001, 0x00210621, 0x000 },
+    { 0x00000000, 0x14c00000, 0x613 },
+    { 0x0004a010, 0x00604411, 0x68d },
+    { 0x0000a010, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00000001, 0x00210621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x62b },
+    { 0x0004a011, 0x00604411, 0x68d },
+    { 0x0000a011, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a012, 0x00604411, 0x68d },
+    { 0x0000a012, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a013, 0x00604411, 0x68d },
+    { 0x0000a013, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a014, 0x00604411, 0x68d },
+    { 0x0000a014, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a015, 0x00604411, 0x68d },
+    { 0x0000a015, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a016, 0x00604411, 0x68d },
+    { 0x0000a016, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a017, 0x00604411, 0x68d },
+    { 0x0000a017, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x0000002c, 0x0080062d, 0x000 },
+    { 0xff000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000002, 0x00804811, 0x000 },
+    { 0x00000000, 0x0ee00000, 0x63d },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x00000002, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x63b },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x68d },
+    { 0x00001000, 0x00200811, 0x000 },
+    { 0x0000002b, 0x00203622, 0x000 },
+    { 0x00000000, 0x00600000, 0x641 },
+    { 0x00000000, 0x00600000, 0x5c9 },
+    { 0x98000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00804811, 0x000 },
+    { 0x00000000, 0xc0600000, 0x641 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000022, 0x00204811, 0x000 },
+    { 0x89000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00404811, 0x62d },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404811, 0x62d },
+    { 0x00000000, 0x00600000, 0x65c },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0xc0204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x36e },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00010000, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x09800000, 0x00204811, 0x000 },
+    { 0xffffffff, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x68d },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000004, 0x00404c11, 0x656 },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000004, 0x00291e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0xfffffffb, 0x00281e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000008, 0x00291e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0xfffffff7, 0x00281e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x36e },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00010000, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x01800000, 0x00204811, 0x000 },
+    { 0xffffffff, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004217f, 0x00604411, 0x68d },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x68c },
+    { 0x00000010, 0x00404c11, 0x672 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x38c00000, 0x000 },
+    { 0x0000001d, 0x00200a2d, 0x000 },
+    { 0x0000001e, 0x00200e2d, 0x000 },
+    { 0x0000001f, 0x0020122d, 0x000 },
+    { 0x00000020, 0x0020162d, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000004, 0x00301224, 0x000 },
+    { 0x00000000, 0x002f0064, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x68b },
+    { 0x00000003, 0x00281a22, 0x000 },
+    { 0x00000008, 0x00221222, 0x000 },
+    { 0xfffff000, 0x00281224, 0x000 },
+    { 0x00000000, 0x002910c4, 0x000 },
+    { 0x0000001f, 0x00403624, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x1ac00000, 0x68d },
+    { 0x9f000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000000, 0x1ae00000, 0x690 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x1ac00000, 0x692 },
+    { 0x9e000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000000, 0x1ae00000, 0x695 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00001000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001b, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0xc0204411, 0x000 },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000024, 0x0020222d, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000022, 0x0020222d, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00404811, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x01420502, 0x05c00250, 0x000 },
+    { 0x01c30168, 0x043f05c0, 0x000 },
+    { 0x02250209, 0x02500151, 0x000 },
+    { 0x02230245, 0x02a00241, 0x000 },
+    { 0x03d705c0, 0x05c005c0, 0x000 },
+    { 0x0649064a, 0x031f05c0, 0x000 },
+    { 0x05c005c5, 0x03200340, 0x000 },
+    { 0x032a0282, 0x03420334, 0x000 },
+    { 0x05c005c0, 0x05c005c0, 0x000 },
+    { 0x05c00551, 0x05c005c0, 0x000 },
+    { 0x03ba05c0, 0x04bb0344, 0x000 },
+    { 0x049a0450, 0x043d05c0, 0x000 },
+    { 0x04d005c0, 0x044104dd, 0x000 },
+    { 0x04500507, 0x03510375, 0x000 },
+    { 0x05c005c0, 0x05c005c0, 0x000 },
+    { 0x05c005c0, 0x05c005c0, 0x000 },
+    { 0x05c005c0, 0x063f05c7, 0x000 },
+    { 0x05c005c0, 0x000705c0, 0x000 },
+    { 0x05c005c0, 0x05c005c0, 0x000 },
+    { 0x05c005c0, 0x05c005c0, 0x000 },
+    { 0x03f803ed, 0x04080406, 0x000 },
+    { 0x040e040a, 0x040c0410, 0x000 },
+    { 0x041c0418, 0x04240420, 0x000 },
+    { 0x042c0428, 0x04340430, 0x000 },
+    { 0x05c005c0, 0x043805c0, 0x000 },
+    { 0x05c005c0, 0x05c005c0, 0x000 },
+    { 0x05c005c0, 0x05c005c0, 0x000 },
+    { 0x00020679, 0x06970006, 0x000 },
+};
+
+static const u32 RV620_pfp_microcode[] = {
+0xca0400,
+0xa00000,
+0x7e828b,
+0x7c038b,
+0x8001b8,
+0x7c038b,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xc41838,
+0xca2400,
+0xca2800,
+0x9581a8,
+0xc41c3a,
+0xc3c000,
+0xca0800,
+0xca0c00,
+0x7c744b,
+0xc20005,
+0x99c000,
+0xc41c3a,
+0x7c744c,
+0xc0fff0,
+0x042c04,
+0x309002,
+0x7d2500,
+0x351402,
+0x7d350b,
+0x255403,
+0x7cd580,
+0x259c03,
+0x95c004,
+0xd5001b,
+0x7eddc1,
+0x7d9d80,
+0xd6801b,
+0xd5801b,
+0xd4401e,
+0xd5401e,
+0xd6401e,
+0xd6801e,
+0xd4801e,
+0xd4c01e,
+0x9783d3,
+0xd5c01e,
+0xca0800,
+0x80001a,
+0xca0c00,
+0xe4011e,
+0xd4001e,
+0x80000c,
+0xc41838,
+0xe4013e,
+0xd4001e,
+0x80000c,
+0xc41838,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4013e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca1800,
+0xd4401e,
+0xd5801e,
+0x800053,
+0xd40075,
+0xd4401e,
+0xca0800,
+0xca0c00,
+0xca1000,
+0xd48019,
+0xd4c018,
+0xd50017,
+0xd4801e,
+0xd4c01e,
+0xd5001e,
+0xe2001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca0800,
+0xd48060,
+0xd4401e,
+0x800000,
+0xd4801e,
+0xca0800,
+0xd48061,
+0xd4401e,
+0x800000,
+0xd4801e,
+0xca0800,
+0xca0c00,
+0xd4401e,
+0xd48016,
+0xd4c016,
+0xd4801e,
+0x8001b8,
+0xd4c01e,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x948004,
+0xca1400,
+0xe420f3,
+0xd42013,
+0xd56065,
+0xd4e01c,
+0xd5201c,
+0xd5601c,
+0x800000,
+0x062001,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x9483f7,
+0xca1400,
+0xe420f3,
+0x800079,
+0xd42013,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x9883ef,
+0xca1400,
+0xd40064,
+0x80008d,
+0x000000,
+0xc41432,
+0xc61843,
+0xc4082f,
+0x954005,
+0xc40c30,
+0xd4401e,
+0x800000,
+0xee001e,
+0x9583f5,
+0xc41031,
+0xd44033,
+0xd52065,
+0xd4a01c,
+0xd4e01c,
+0xd5201c,
+0xe4015e,
+0xd4001e,
+0x800000,
+0x062001,
+0xca1800,
+0x0a2001,
+0xd60076,
+0xc40836,
+0x988007,
+0xc61045,
+0x950110,
+0xd4001f,
+0xd46062,
+0x800000,
+0xd42062,
+0xcc3835,
+0xcc1433,
+0x8401bb,
+0xd40072,
+0xd5401e,
+0x800000,
+0xee001e,
+0xe2001a,
+0x8401bb,
+0xe2001a,
+0xcc104b,
+0xcc0447,
+0x2c9401,
+0x7d098b,
+0x984005,
+0x7d15cb,
+0xd4001a,
+0x8001b8,
+0xd4006d,
+0x344401,
+0xcc0c48,
+0x98403a,
+0xcc2c4a,
+0x958004,
+0xcc0449,
+0x8001b8,
+0xd4001a,
+0xd4c01a,
+0x282801,
+0x8400f0,
+0xcc1003,
+0x98801b,
+0x04380c,
+0x8400f0,
+0xcc1003,
+0x988017,
+0x043808,
+0x8400f0,
+0xcc1003,
+0x988013,
+0x043804,
+0x8400f0,
+0xcc1003,
+0x988014,
+0xcc104c,
+0x9a8009,
+0xcc144d,
+0x9840dc,
+0xd4006d,
+0xcc1848,
+0xd5001a,
+0xd5401a,
+0x8000c9,
+0xd5801a,
+0x96c0d5,
+0xd4006d,
+0x8001b8,
+0xd4006e,
+0x9ac003,
+0xd4006d,
+0xd4006e,
+0x800000,
+0xec007f,
+0x9ac0cc,
+0xd4006d,
+0x8001b8,
+0xd4006e,
+0xcc1403,
+0xcc1803,
+0xcc1c03,
+0x7d9103,
+0x7dd583,
+0x7d190c,
+0x35cc1f,
+0x35701f,
+0x7cf0cb,
+0x7cd08b,
+0x880000,
+0x7e8e8b,
+0x95c004,
+0xd4006e,
+0x8001b8,
+0xd4001a,
+0xd4c01a,
+0xcc0803,
+0xcc0c03,
+0xcc1003,
+0xcc1403,
+0xcc1803,
+0xcc1c03,
+0xcc2403,
+0xcc2803,
+0x35c41f,
+0x36b01f,
+0x7c704b,
+0x34f01f,
+0x7c704b,
+0x35701f,
+0x7c704b,
+0x7d8881,
+0x7dccc1,
+0x7e5101,
+0x7e9541,
+0x7c9082,
+0x7cd4c2,
+0x7c848b,
+0x9ac003,
+0x7c8c8b,
+0x2c8801,
+0x98809e,
+0xd4006d,
+0x98409c,
+0xd4006e,
+0xcc084c,
+0xcc0c4d,
+0xcc1048,
+0xd4801a,
+0xd4c01a,
+0x800101,
+0xd5001a,
+0xcc0832,
+0xd40032,
+0x9482d9,
+0xca0c00,
+0xd4401e,
+0x800000,
+0xd4001e,
+0xe4011e,
+0xd4001e,
+0xca0800,
+0xca0c00,
+0xca1000,
+0xd4401e,
+0xca1400,
+0xd4801e,
+0xd4c01e,
+0xd5001e,
+0xd5401e,
+0xd54034,
+0x800000,
+0xee001e,
+0x280404,
+0xe2001a,
+0xe2001a,
+0xd4401a,
+0xca3800,
+0xcc0803,
+0xcc0c03,
+0xcc0c03,
+0xcc0c03,
+0x9882bd,
+0x000000,
+0x8401bb,
+0xd7a06f,
+0x800000,
+0xee001f,
+0xca0400,
+0xc2ff00,
+0xcc0834,
+0xc13fff,
+0x7c74cb,
+0x7cc90b,
+0x7d010f,
+0x9902b0,
+0x7c738b,
+0x8401bb,
+0xd7a06f,
+0x800000,
+0xee001f,
+0xca0800,
+0x281900,
+0x7d898b,
+0x958014,
+0x281404,
+0xca0c00,
+0xca1000,
+0xca1c00,
+0xca2400,
+0xe2001f,
+0xd4c01a,
+0xd5001a,
+0xd5401a,
+0xcc1803,
+0xcc2c03,
+0xcc2c03,
+0xcc2c03,
+0x7da58b,
+0x7d9c47,
+0x984297,
+0x000000,
+0x800161,
+0xd4c01a,
+0xd4401e,
+0xd4801e,
+0x800000,
+0xee001e,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4013e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca0800,
+0x248c06,
+0x0ccc06,
+0x98c006,
+0xcc104e,
+0x990004,
+0xd40073,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xd4801e,
+0x800000,
+0xee001e,
+0xca0800,
+0xca0c00,
+0x34d018,
+0x251001,
+0x950021,
+0xc17fff,
+0xca1000,
+0xca1400,
+0xca1800,
+0xd4801d,
+0xd4c01d,
+0x7db18b,
+0xc14202,
+0xc2c001,
+0xd5801d,
+0x34dc0e,
+0x7d5d4c,
+0x7f734c,
+0xd7401e,
+0xd5001e,
+0xd5401e,
+0xc14200,
+0xc2c000,
+0x099c01,
+0x31dc10,
+0x7f5f4c,
+0x7f734c,
+0x042802,
+0x7d8380,
+0xd5a86f,
+0xd58066,
+0xd7401e,
+0xec005e,
+0xc82402,
+0xc82402,
+0x8001b8,
+0xd60076,
+0xd4401e,
+0xd4801e,
+0xd4c01e,
+0x800000,
+0xee001e,
+0x800000,
+0xee001f,
+0xd4001f,
+0x800000,
+0xd4001f,
+0xd4001f,
+0x880000,
+0xd4001f,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x010171,
+0x020178,
+0x03008f,
+0x04007f,
+0x050003,
+0x06003f,
+0x070032,
+0x08012c,
+0x090046,
+0x0a0036,
+0x1001b6,
+0x1700a2,
+0x22013a,
+0x230149,
+0x2000b4,
+0x240125,
+0x27004d,
+0x28006a,
+0x2a0060,
+0x2b0052,
+0x2f0065,
+0x320087,
+0x34017f,
+0x3c0156,
+0x3f0072,
+0x41018c,
+0x44012e,
+0x550173,
+0x56017a,
+0x60000b,
+0x610034,
+0x620038,
+0x630038,
+0x640038,
+0x650038,
+0x660038,
+0x670038,
+0x68003a,
+0x690041,
+0x6a0048,
+0x6b0048,
+0x6c0048,
+0x6d0048,
+0x6e0048,
+0x6f0048,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+};
+
+static const u32 RV630_cp_microcode[][3] = {
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0000ffff, 0x00284621, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00000000, 0x00e00000, 0x000 },
+    { 0x00010000, 0xc0294620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x00000000, 0x00600000, 0x62e },
+    { 0x00000000, 0x00600000, 0x642 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000f00, 0x00281622, 0x000 },
+    { 0x00000008, 0x00211625, 0x000 },
+    { 0x00000018, 0x00203625, 0x000 },
+    { 0x8d000000, 0x00204411, 0x000 },
+    { 0x00000004, 0x002f0225, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x018 },
+    { 0x00412000, 0x00404811, 0x019 },
+    { 0x00422000, 0x00204811, 0x000 },
+    { 0x8e000000, 0x00204411, 0x000 },
+    { 0x00000028, 0x00204a2d, 0x000 },
+    { 0x90000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x0000000c, 0x00211622, 0x000 },
+    { 0x00000003, 0x00281625, 0x000 },
+    { 0x00000019, 0x00211a22, 0x000 },
+    { 0x00000004, 0x00281a26, 0x000 },
+    { 0x00000000, 0x002914c5, 0x000 },
+    { 0x00000019, 0x00203625, 0x000 },
+    { 0x00000000, 0x003a1402, 0x000 },
+    { 0x00000016, 0x00211625, 0x000 },
+    { 0x00000003, 0x00281625, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0xfffffffc, 0x00280e23, 0x000 },
+    { 0x00000000, 0x002914a3, 0x000 },
+    { 0x00000017, 0x00203625, 0x000 },
+    { 0x00008000, 0x00280e22, 0x000 },
+    { 0x00000007, 0x00220e23, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x20000000, 0x00280e22, 0x000 },
+    { 0x00000006, 0x00210e23, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x00000000, 0x00220222, 0x000 },
+    { 0x00000000, 0x14e00000, 0x038 },
+    { 0x00000000, 0x2ee00000, 0x035 },
+    { 0x00000000, 0x2ce00000, 0x037 },
+    { 0x00000000, 0x00400e2d, 0x039 },
+    { 0x00000008, 0x00200e2d, 0x000 },
+    { 0x00000009, 0x0040122d, 0x046 },
+    { 0x00000001, 0x00400e2d, 0x039 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x003ffffc, 0x00281223, 0x000 },
+    { 0x00000002, 0x00221224, 0x000 },
+    { 0x0000001f, 0x00211e23, 0x000 },
+    { 0x00000000, 0x14e00000, 0x03e },
+    { 0x00000008, 0x00401c11, 0x041 },
+    { 0x0000000d, 0x00201e2d, 0x000 },
+    { 0x0000000f, 0x00281e27, 0x000 },
+    { 0x00000003, 0x00221e27, 0x000 },
+    { 0x7fc00000, 0x00281a23, 0x000 },
+    { 0x00000014, 0x00211a26, 0x000 },
+    { 0x00000001, 0x00331a26, 0x000 },
+    { 0x00000008, 0x00221a26, 0x000 },
+    { 0x00000000, 0x00290cc7, 0x000 },
+    { 0x00000027, 0x00203624, 0x000 },
+    { 0x00007f00, 0x00281221, 0x000 },
+    { 0x00001400, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x04b },
+    { 0x00000001, 0x00290e23, 0x000 },
+    { 0x0000000e, 0x00203623, 0x000 },
+    { 0x0000e000, 0x00204411, 0x000 },
+    { 0xfff80000, 0x00294a23, 0x000 },
+    { 0x00000000, 0x003a2c02, 0x000 },
+    { 0x00000002, 0x00220e2b, 0x000 },
+    { 0xfc000000, 0x00280e23, 0x000 },
+    { 0x0000000f, 0x00203623, 0x000 },
+    { 0x00001fff, 0x00294a23, 0x000 },
+    { 0x00000027, 0x00204a2d, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000029, 0x00200e2d, 0x000 },
+    { 0x060a0200, 0x00294a23, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00210222, 0x000 },
+    { 0x00000000, 0x14e00000, 0x061 },
+    { 0x00000000, 0x2ee00000, 0x05f },
+    { 0x00000000, 0x2ce00000, 0x05e },
+    { 0x00000000, 0x00400e2d, 0x062 },
+    { 0x00000001, 0x00400e2d, 0x062 },
+    { 0x0000000a, 0x00200e2d, 0x000 },
+    { 0x0000000b, 0x0040122d, 0x06a },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x003ffffc, 0x00281223, 0x000 },
+    { 0x00000002, 0x00221224, 0x000 },
+    { 0x7fc00000, 0x00281623, 0x000 },
+    { 0x00000014, 0x00211625, 0x000 },
+    { 0x00000001, 0x00331625, 0x000 },
+    { 0x80000000, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00290ca3, 0x000 },
+    { 0x3ffffc00, 0x00290e23, 0x000 },
+    { 0x0000001f, 0x00211e23, 0x000 },
+    { 0x00000000, 0x14e00000, 0x06d },
+    { 0x00000100, 0x00401c11, 0x070 },
+    { 0x0000000d, 0x00201e2d, 0x000 },
+    { 0x000000f0, 0x00281e27, 0x000 },
+    { 0x00000004, 0x00221e27, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000d, 0x00204811, 0x000 },
+    { 0xfffff0ff, 0x00281a30, 0x000 },
+    { 0x0000a028, 0x00204411, 0x000 },
+    { 0x00000000, 0x002948e6, 0x000 },
+    { 0x0000a018, 0x00204411, 0x000 },
+    { 0x3fffffff, 0x00284a23, 0x000 },
+    { 0x0000a010, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000030, 0x0020162d, 0x000 },
+    { 0x00000002, 0x00291625, 0x000 },
+    { 0x00000030, 0x00203625, 0x000 },
+    { 0x00000025, 0x0020162d, 0x000 },
+    { 0x00000000, 0x002f00a3, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x083 },
+    { 0x00000026, 0x0020162d, 0x000 },
+    { 0x00000000, 0x002f00a4, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x084 },
+    { 0x00000000, 0x00400000, 0x08a },
+    { 0x00000025, 0x00203623, 0x000 },
+    { 0x00000026, 0x00203624, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x08a },
+    { 0x00000000, 0x00600000, 0x665 },
+    { 0x00000000, 0x00600000, 0x659 },
+    { 0x00000002, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x08d },
+    { 0x00000012, 0xc0403620, 0x093 },
+    { 0x00000000, 0x2ee00000, 0x091 },
+    { 0x00000000, 0x2ce00000, 0x090 },
+    { 0x00000002, 0x00400e2d, 0x092 },
+    { 0x00000003, 0x00400e2d, 0x092 },
+    { 0x0000000c, 0x00200e2d, 0x000 },
+    { 0x00000012, 0x00203623, 0x000 },
+    { 0x00000003, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x098 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x0a0 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x2ee00000, 0x09e },
+    { 0x00000000, 0x2ce00000, 0x09d },
+    { 0x00000002, 0x00400e2d, 0x09f },
+    { 0x00000003, 0x00400e2d, 0x09f },
+    { 0x0000000c, 0x00200e2d, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000000, 0x003a0c02, 0x000 },
+    { 0x003f0000, 0x00280e23, 0x000 },
+    { 0x00000010, 0x00210e23, 0x000 },
+    { 0x00000011, 0x00203623, 0x000 },
+    { 0x0000001e, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0a7 },
+    { 0x00000016, 0xc0203620, 0x000 },
+    { 0x0000001f, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0aa },
+    { 0x00000015, 0xc0203620, 0x000 },
+    { 0x00000008, 0x00210e2b, 0x000 },
+    { 0x0000007f, 0x00280e23, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0e1 },
+    { 0x00000000, 0x27000000, 0x000 },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x0b3 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x0000000c, 0x00221e30, 0x000 },
+    { 0x99800000, 0x00204411, 0x000 },
+    { 0x00000004, 0x0020122d, 0x000 },
+    { 0x00000008, 0x00221224, 0x000 },
+    { 0x00000010, 0x00201811, 0x000 },
+    { 0x00000000, 0x00291ce4, 0x000 },
+    { 0x00000000, 0x00604807, 0x12f },
+    { 0x9b000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x9c000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x0033146f, 0x000 },
+    { 0x00000001, 0x00333e23, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0x00203c05, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x00000000, 0x00201010, 0x000 },
+    { 0x0000e007, 0x00204411, 0x000 },
+    { 0x0000000f, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0cb },
+    { 0x00f8ff08, 0x00204811, 0x000 },
+    { 0x98000000, 0x00404811, 0x0dc },
+    { 0x000000f0, 0x00280e22, 0x000 },
+    { 0x000000a0, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x0da },
+    { 0x00000011, 0x00200e2d, 0x000 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0d5 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0d4 },
+    { 0x00003f00, 0x00400c11, 0x0d6 },
+    { 0x00001f00, 0x00400c11, 0x0d6 },
+    { 0x00000f00, 0x00200c11, 0x000 },
+    { 0x00380009, 0x00294a23, 0x000 },
+    { 0x3f000000, 0x00280e2b, 0x000 },
+    { 0x00000002, 0x00220e23, 0x000 },
+    { 0x00000007, 0x00494a23, 0x0dc },
+    { 0x00380f09, 0x00204811, 0x000 },
+    { 0x68000007, 0x00204811, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a24, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000a202, 0x00204411, 0x000 },
+    { 0x00ff0000, 0x00280e22, 0x000 },
+    { 0x00000080, 0x00294a23, 0x000 },
+    { 0x00000027, 0x00200e2d, 0x000 },
+    { 0x00000026, 0x0020122d, 0x000 },
+    { 0x00000000, 0x002f0083, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0ea },
+    { 0x00000000, 0x00600000, 0x65f },
+    { 0x00000000, 0x00400000, 0x0eb },
+    { 0x00000000, 0x00600000, 0x662 },
+    { 0x00000007, 0x0020222d, 0x000 },
+    { 0x00000005, 0x00220e22, 0x000 },
+    { 0x00100000, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00292068, 0x000 },
+    { 0x00000000, 0x003a0c02, 0x000 },
+    { 0x000000ef, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00292068, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0x00000003, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x0f8 },
+    { 0x0000000b, 0x00210228, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0f8 },
+    { 0x00000400, 0x00292228, 0x000 },
+    { 0x00000014, 0x00203628, 0x000 },
+    { 0x0000001c, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0fd },
+    { 0x0000a30c, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000001e, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x10b },
+    { 0x0000a30f, 0x00204411, 0x000 },
+    { 0x00000011, 0x00200e2d, 0x000 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x104 },
+    { 0xffffffff, 0x00404811, 0x10b },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x107 },
+    { 0x0000ffff, 0x00404811, 0x10b },
+    { 0x00000004, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x10a },
+    { 0x000000ff, 0x00404811, 0x10b },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0002c400, 0x00204411, 0x000 },
+    { 0x0000001f, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x112 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x00000013, 0x00203623, 0x000 },
+    { 0x00000018, 0x40224a20, 0x000 },
+    { 0x00000010, 0xc0424a20, 0x114 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x00000013, 0x00203623, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000000a, 0x00201011, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x11b },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00531224, 0x117 },
+    { 0xffbfffff, 0x00283a2e, 0x000 },
+    { 0x0000001b, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x12e },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000d, 0x00204811, 0x000 },
+    { 0x00000018, 0x00220e30, 0x000 },
+    { 0xfc000000, 0x00280e23, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x00000000, 0x00201010, 0x000 },
+    { 0x0000e00e, 0x00204411, 0x000 },
+    { 0x07f8ff08, 0x00204811, 0x000 },
+    { 0x00000000, 0x00294a23, 0x000 },
+    { 0x0000001c, 0x00201e2d, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a24, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x00800000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204806, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x68a },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x689 },
+    { 0x00000004, 0x00404c11, 0x135 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x0000001c, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68a },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x13c },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00000000, 0x00600000, 0x160 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000ffff, 0x40280620, 0x000 },
+    { 0x00000010, 0xc0210a20, 0x000 },
+    { 0x00000000, 0x00341461, 0x000 },
+    { 0x00000000, 0x00741882, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x147 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x160 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x00000010, 0x40211620, 0x000 },
+    { 0x0000ffff, 0xc0681a20, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x158 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000001, 0x00300a2f, 0x000 },
+    { 0x00000001, 0x00210a22, 0x000 },
+    { 0x00000003, 0x00384a22, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001a, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600000, 0x18f },
+    { 0x00000000, 0x00600000, 0x1a0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00202c08, 0x000 },
+    { 0x00000000, 0x00202411, 0x000 },
+    { 0x00000000, 0x00202811, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000002, 0x00221e29, 0x000 },
+    { 0x00000000, 0x007048eb, 0x19c },
+    { 0x00000000, 0x00600000, 0x2bb },
+    { 0x00000001, 0x40330620, 0x000 },
+    { 0x00000000, 0xc0302409, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x181 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x00000000, 0x00400000, 0x186 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x186 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000001, 0x00530621, 0x182 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0604800, 0x197 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000011, 0x0020062d, 0x000 },
+    { 0x00000000, 0x0078042a, 0x2fb },
+    { 0x00000000, 0x00202809, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x174 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000210, 0x00600411, 0x315 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x194 },
+    { 0x00000015, 0xc0203620, 0x000 },
+    { 0x00000016, 0xc0203620, 0x000 },
+    { 0x3f800000, 0x00200411, 0x000 },
+    { 0x46000000, 0x00600811, 0x1b2 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x19b },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000021, 0x00804811, 0x000 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000ffff, 0x40281620, 0x000 },
+    { 0x00000010, 0xc0811a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000008, 0x00221e30, 0x000 },
+    { 0x00000029, 0x00201a2d, 0x000 },
+    { 0x0000e000, 0x00204411, 0x000 },
+    { 0xfffbff09, 0x00204811, 0x000 },
+    { 0x0000000f, 0x0020222d, 0x000 },
+    { 0x00001fff, 0x00294a28, 0x000 },
+    { 0x00000006, 0x0020222d, 0x000 },
+    { 0x00000000, 0x002920e8, 0x000 },
+    { 0x00000000, 0x00204808, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a26, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000100, 0x00201811, 0x000 },
+    { 0x00000008, 0x00621e28, 0x12f },
+    { 0x00000008, 0x00822228, 0x000 },
+    { 0x0002c000, 0x00204411, 0x000 },
+    { 0x00000015, 0x00600e2d, 0x1bd },
+    { 0x00000016, 0x00600e2d, 0x1bd },
+    { 0x0000c008, 0x00204411, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0x00000000, 0x14c00000, 0x1b9 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0x39000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00804802, 0x000 },
+    { 0x00000018, 0x00202e2d, 0x000 },
+    { 0x00000000, 0x003b0d63, 0x000 },
+    { 0x00000008, 0x00224a23, 0x000 },
+    { 0x00000010, 0x00224a23, 0x000 },
+    { 0x00000018, 0x00224a23, 0x000 },
+    { 0x00000000, 0x00804803, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00001000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00000007, 0x0021062f, 0x000 },
+    { 0x00000013, 0x00200a2d, 0x000 },
+    { 0x00000001, 0x00202c11, 0x000 },
+    { 0x0000ffff, 0x40282220, 0x000 },
+    { 0x0000000f, 0x00262228, 0x000 },
+    { 0x00000010, 0x40212620, 0x000 },
+    { 0x0000000f, 0x00262629, 0x000 },
+    { 0x00000000, 0x00202802, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001b, 0x00204811, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1e0 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000081, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000080, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f0227, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1dc },
+    { 0x00000000, 0x00600000, 0x1e9 },
+    { 0x00000001, 0x00531e27, 0x1d8 },
+    { 0x00000001, 0x00202c11, 0x000 },
+    { 0x0000001f, 0x00280a22, 0x000 },
+    { 0x0000001f, 0x00282a2a, 0x000 },
+    { 0x00000001, 0x00530621, 0x1d1 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000002, 0x00304a2f, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000001, 0x00301e2f, 0x000 },
+    { 0x00000000, 0x002f0227, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x1e9 },
+    { 0x00000001, 0x00531e27, 0x1e5 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x0000000f, 0x00260e23, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000000f, 0x00261224, 0x000 },
+    { 0x00000000, 0x00201411, 0x000 },
+    { 0x00000000, 0x00601811, 0x2bb },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022b, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1f8 },
+    { 0x00000010, 0x00221628, 0x000 },
+    { 0xffff0000, 0x00281625, 0x000 },
+    { 0x0000ffff, 0x00281a29, 0x000 },
+    { 0x00000000, 0x002948c5, 0x000 },
+    { 0x00000000, 0x0020480a, 0x000 },
+    { 0x00000000, 0x00202c11, 0x000 },
+    { 0x00000010, 0x00221623, 0x000 },
+    { 0xffff0000, 0x00281625, 0x000 },
+    { 0x0000ffff, 0x00281a24, 0x000 },
+    { 0x00000000, 0x002948c5, 0x000 },
+    { 0x00000000, 0x00731503, 0x205 },
+    { 0x00000000, 0x00201805, 0x000 },
+    { 0x00000000, 0x00731524, 0x205 },
+    { 0x00000000, 0x002d14c5, 0x000 },
+    { 0x00000000, 0x003008a2, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00202802, 0x000 },
+    { 0x00000000, 0x00202003, 0x000 },
+    { 0x00000000, 0x00802404, 0x000 },
+    { 0x0000000f, 0x00210225, 0x000 },
+    { 0x00000000, 0x14c00000, 0x689 },
+    { 0x00000000, 0x002b1405, 0x000 },
+    { 0x00000001, 0x00901625, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001a, 0x00294a22, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00384a21, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000ffff, 0x40281220, 0x000 },
+    { 0x00000010, 0xc0211a20, 0x000 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211620, 0x000 },
+    { 0x00000000, 0x00741465, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00000001, 0x00330621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x219 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x212 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x642 },
+    { 0x00000000, 0x0040040f, 0x213 },
+    { 0x00000000, 0x00600000, 0x62e },
+    { 0x00000000, 0x00600000, 0x642 },
+    { 0x00000210, 0x00600411, 0x315 },
+    { 0x00000000, 0x00600000, 0x1a0 },
+    { 0x00000000, 0x00600000, 0x19c },
+    { 0x00000000, 0x00600000, 0x2bb },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204808, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x232 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x00000000, 0x00400000, 0x236 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x236 },
+    { 0x00000000, 0xc0404800, 0x233 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x00600411, 0x2fb },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x62e },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000018, 0x40210a20, 0x000 },
+    { 0x00000003, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x24c },
+    { 0x00000014, 0x0020222d, 0x000 },
+    { 0x00080101, 0x00292228, 0x000 },
+    { 0x00000014, 0x00203628, 0x000 },
+    { 0x0000a30c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x251 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000010, 0x00600411, 0x315 },
+    { 0x3f800000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x00000000, 0x00600000, 0x27c },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000001, 0x00211e27, 0x000 },
+    { 0x00000000, 0x14e00000, 0x26a },
+    { 0x00000012, 0x00201e2d, 0x000 },
+    { 0x0000ffff, 0x00281e27, 0x000 },
+    { 0x00000000, 0x00341c27, 0x000 },
+    { 0x00000000, 0x12c00000, 0x25f },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f00e5, 0x000 },
+    { 0x00000000, 0x08c00000, 0x262 },
+    { 0x00000000, 0x00201407, 0x000 },
+    { 0x00000012, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00211e27, 0x000 },
+    { 0x00000000, 0x00341c47, 0x000 },
+    { 0x00000000, 0x12c00000, 0x267 },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f00e6, 0x000 },
+    { 0x00000000, 0x08c00000, 0x26a },
+    { 0x00000000, 0x00201807, 0x000 },
+    { 0x00000000, 0x00600000, 0x2c1 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000000, 0x00342023, 0x000 },
+    { 0x00000000, 0x12c00000, 0x272 },
+    { 0x00000000, 0x00342044, 0x000 },
+    { 0x00000000, 0x12c00000, 0x271 },
+    { 0x00000016, 0x00404811, 0x276 },
+    { 0x00000018, 0x00404811, 0x276 },
+    { 0x00000000, 0x00342044, 0x000 },
+    { 0x00000000, 0x12c00000, 0x275 },
+    { 0x00000017, 0x00404811, 0x276 },
+    { 0x00000019, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0x00604411, 0x2e9 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x256 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000010, 0x40210620, 0x000 },
+    { 0x0000ffff, 0xc0280a20, 0x000 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x00000010, 0x40211620, 0x000 },
+    { 0x0000ffff, 0xc0881a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x00000000, 0x00600000, 0x62e },
+    { 0x00000000, 0xc0600000, 0x2a3 },
+    { 0x00000005, 0x00200a2d, 0x000 },
+    { 0x00000008, 0x00220a22, 0x000 },
+    { 0x0000002b, 0x00201a2d, 0x000 },
+    { 0x0000001c, 0x00201e2d, 0x000 },
+    { 0x00007000, 0x00281e27, 0x000 },
+    { 0x00000000, 0x00311ce6, 0x000 },
+    { 0x0000002a, 0x00201a2d, 0x000 },
+    { 0x0000000c, 0x00221a26, 0x000 },
+    { 0x00000000, 0x002f00e6, 0x000 },
+    { 0x00000000, 0x06e00000, 0x292 },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x0000002b, 0x00203623, 0x000 },
+    { 0x00000010, 0x00201811, 0x000 },
+    { 0x00000000, 0x00691ce2, 0x12f },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x29d },
+    { 0x00000001, 0x00333e2f, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000001c, 0x00403627, 0x000 },
+    { 0x0000000c, 0xc0220a20, 0x000 },
+    { 0x00000029, 0x00203622, 0x000 },
+    { 0x00000028, 0xc0403620, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000009, 0x00204811, 0x000 },
+    { 0xa1000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002c1ce3, 0x000 },
+    { 0x00000021, 0x00203627, 0x000 },
+    { 0x00000022, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002c1ce4, 0x000 },
+    { 0x00000022, 0x00203627, 0x000 },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120a3, 0x000 },
+    { 0x00000000, 0x002d1d07, 0x000 },
+    { 0x00000023, 0x00203627, 0x000 },
+    { 0x00000024, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x00000000, 0x002d1d07, 0x000 },
+    { 0x00000024, 0x00803627, 0x000 },
+    { 0x00000021, 0x00203623, 0x000 },
+    { 0x00000022, 0x00203624, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000023, 0x00203627, 0x000 },
+    { 0x00000000, 0x00311cc4, 0x000 },
+    { 0x00000024, 0x00803627, 0x000 },
+    { 0x0000001a, 0x00203627, 0x000 },
+    { 0x0000001b, 0x00203628, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14c00000, 0x2dc },
+    { 0x00000000, 0x00400000, 0x2d9 },
+    { 0x0000001a, 0x00203627, 0x000 },
+    { 0x0000001b, 0x00203628, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x2d9 },
+    { 0x00000003, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x2dc },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002e00e1, 0x000 },
+    { 0x00000000, 0x02c00000, 0x2dc },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120a1, 0x000 },
+    { 0x00000000, 0x002e00e8, 0x000 },
+    { 0x00000000, 0x06c00000, 0x2dc },
+    { 0x00000024, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002e00e2, 0x000 },
+    { 0x00000000, 0x02c00000, 0x2dc },
+    { 0x00000022, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120c2, 0x000 },
+    { 0x00000000, 0x002e00e8, 0x000 },
+    { 0x00000000, 0x06c00000, 0x2dc },
+    { 0x00000000, 0x00600000, 0x665 },
+    { 0x00000000, 0x00600000, 0x2b5 },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x00000000, 0x00600000, 0x2b5 },
+    { 0x00000000, 0x00600000, 0x65c },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x00000000, 0x00600000, 0x2a7 },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x0000001a, 0x00201e2d, 0x000 },
+    { 0x0000001b, 0x0080222d, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000010, 0x00221e21, 0x000 },
+    { 0x00000000, 0x00294847, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000000, 0x00311ca1, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294847, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000010, 0x00221e21, 0x000 },
+    { 0x00000000, 0x003120c2, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000001, 0x00220a21, 0x000 },
+    { 0x00000000, 0x003308a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000001, 0x00220a21, 0x000 },
+    { 0x00000000, 0x003008a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x003808c5, 0x000 },
+    { 0x00000000, 0x00300841, 0x000 },
+    { 0x00000001, 0x00220a22, 0x000 },
+    { 0x00000000, 0x003308a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000017, 0x0020222d, 0x000 },
+    { 0x00000000, 0x14c00000, 0x318 },
+    { 0xffffffef, 0x00280621, 0x000 },
+    { 0x00000014, 0x0020222d, 0x000 },
+    { 0x0000f8e0, 0x00204411, 0x000 },
+    { 0x00000000, 0x00294901, 0x000 },
+    { 0x00000000, 0x00894901, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00804811, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x97000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0xc0204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00002257, 0x00204411, 0x000 },
+    { 0x00000003, 0xc0484a20, 0x000 },
+    { 0x0000225d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0x00600000, 0x642 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00384a22, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x40204800, 0x000 },
+    { 0x00000001, 0x40304a20, 0x000 },
+    { 0x00000002, 0xc0304a20, 0x000 },
+    { 0x00000001, 0x00530a22, 0x34b },
+    { 0x0000003f, 0xc0280a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000018, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68a },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x354 },
+    { 0x00000014, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x364 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00604802, 0x36e },
+    { 0x00002100, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000004, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x36a },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x35f },
+    { 0x00000028, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5bd },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x35f },
+    { 0x0000002c, 0x00203626, 0x000 },
+    { 0x00000049, 0x00201811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x00000001, 0x00331a26, 0x000 },
+    { 0x00000000, 0x002f0226, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x370 },
+    { 0x0000002c, 0x00801a2d, 0x000 },
+    { 0x0000003f, 0xc0280a20, 0x000 },
+    { 0x00000015, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x386 },
+    { 0x00000006, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3b1 },
+    { 0x00000016, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3b5 },
+    { 0x00000020, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x39c },
+    { 0x0000000f, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3a8 },
+    { 0x00000010, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3a8 },
+    { 0x0000001e, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x390 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x08000000, 0x00290a22, 0x000 },
+    { 0x00000003, 0x40210e20, 0x000 },
+    { 0x0000000c, 0xc0211220, 0x000 },
+    { 0x00080000, 0x00281224, 0x000 },
+    { 0x00000014, 0xc0221620, 0x000 },
+    { 0x00000000, 0x002914a4, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x002948a2, 0x000 },
+    { 0x0000a1fe, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404803, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68a },
+    { 0x00000015, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x392 },
+    { 0x0000210e, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000017, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68a },
+    { 0x00000003, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x39e },
+    { 0x00002108, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x80000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000010, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3ae },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000006, 0x00404811, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x36e },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x0000001d, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x3ce },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000018, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68a },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x3c0 },
+    { 0x00002100, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0xbabecafe, 0x00204811, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000004, 0x00404811, 0x000 },
+    { 0x00002170, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000a, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3d3 },
+    { 0x8c000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00003fff, 0x40280a20, 0x000 },
+    { 0x80000000, 0x40280e20, 0x000 },
+    { 0x40000000, 0xc0281220, 0x000 },
+    { 0x00040000, 0x00694622, 0x68a },
+    { 0x00000000, 0x00201410, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x3e1 },
+    { 0x00000000, 0xc0401800, 0x3e4 },
+    { 0x00003fff, 0xc0281a20, 0x000 },
+    { 0x00040000, 0x00694626, 0x68a },
+    { 0x00000000, 0x00201810, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x3e7 },
+    { 0x00000000, 0xc0401c00, 0x3ea },
+    { 0x00003fff, 0xc0281e20, 0x000 },
+    { 0x00040000, 0x00694627, 0x68a },
+    { 0x00000000, 0x00201c10, 0x000 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0x002820c5, 0x000 },
+    { 0x00000000, 0x004948e8, 0x000 },
+    { 0xa5800000, 0x00200811, 0x000 },
+    { 0x00002000, 0x00200c11, 0x000 },
+    { 0x83000000, 0x00604411, 0x412 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x40204800, 0x000 },
+    { 0x0000001f, 0xc0210220, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3f7 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0000ffff, 0xc0481220, 0x3ff },
+    { 0xa7800000, 0x00200811, 0x000 },
+    { 0x0000a000, 0x00200c11, 0x000 },
+    { 0x83000000, 0x00604411, 0x412 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x83000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00304883, 0x000 },
+    { 0x84000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x1d000000, 0x000 },
+    { 0x83000000, 0x00604411, 0x412 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0xa9800000, 0x00200811, 0x000 },
+    { 0x0000c000, 0x00400c11, 0x3fa },
+    { 0xab800000, 0x00200811, 0x000 },
+    { 0x0000f8e0, 0x00400c11, 0x3fa },
+    { 0xad800000, 0x00200811, 0x000 },
+    { 0x0000f880, 0x00400c11, 0x3fa },
+    { 0xb3800000, 0x00200811, 0x000 },
+    { 0x0000f3fc, 0x00400c11, 0x3fa },
+    { 0xaf800000, 0x00200811, 0x000 },
+    { 0x0000e000, 0x00400c11, 0x3fa },
+    { 0xb1800000, 0x00200811, 0x000 },
+    { 0x0000f000, 0x00400c11, 0x3fa },
+    { 0x83000000, 0x00204411, 0x000 },
+    { 0x00002148, 0x00204811, 0x000 },
+    { 0x84000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x1d000000, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x01182000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0218a000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0318c000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0418f8e0, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0518f880, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0618e000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0718f000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0818f3fc, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00000030, 0x00200a2d, 0x000 },
+    { 0x00000000, 0xc0290c40, 0x000 },
+    { 0x00000030, 0x00203623, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x86000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404801, 0x000 },
+    { 0x85000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0x00404801, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x68a },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000000, 0x00404c02, 0x448 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x00000000, 0xc0201000, 0x000 },
+    { 0x00000000, 0xc0201400, 0x000 },
+    { 0x00000000, 0xc0201800, 0x000 },
+    { 0x00000000, 0xc0201c00, 0x000 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x456 },
+    { 0x00000000, 0xc0202000, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x00000010, 0x00280a23, 0x000 },
+    { 0x00000010, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x45e },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00040000, 0x00694624, 0x68a },
+    { 0x00000000, 0x00400000, 0x463 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000000, 0x00604805, 0x68f },
+    { 0x00000000, 0x002824f0, 0x000 },
+    { 0x00000007, 0x00280a23, 0x000 },
+    { 0x00000001, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x46a },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x04e00000, 0x483 },
+    { 0x00000000, 0x00400000, 0x490 },
+    { 0x00000002, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x46f },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x02e00000, 0x483 },
+    { 0x00000000, 0x00400000, 0x490 },
+    { 0x00000003, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x474 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x483 },
+    { 0x00000000, 0x00400000, 0x490 },
+    { 0x00000004, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x479 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x483 },
+    { 0x00000000, 0x00400000, 0x490 },
+    { 0x00000005, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x47e },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x06e00000, 0x483 },
+    { 0x00000000, 0x00400000, 0x490 },
+    { 0x00000006, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x483 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x08e00000, 0x483 },
+    { 0x00000000, 0x00400000, 0x490 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x000 },
+    { 0x00000008, 0x00210a23, 0x000 },
+    { 0x00000000, 0x14c00000, 0x48d },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x00000000, 0xc0204400, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x496 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0400000, 0x000 },
+    { 0x00000000, 0x00404c08, 0x456 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x00000011, 0x40211220, 0x000 },
+    { 0x00000012, 0x40211620, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00210225, 0x000 },
+    { 0x00000000, 0x14e00000, 0x4a0 },
+    { 0x00040000, 0xc0494a20, 0x4a1 },
+    { 0xfffbffff, 0xc0284a20, 0x000 },
+    { 0x00000000, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x4ad },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x00210224, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000c, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4a9 },
+    { 0xa0000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000004, 0x00204811, 0x000 },
+    { 0x0000216b, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204810, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000005, 0x00204811, 0x000 },
+    { 0x0000216c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204810, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00400000, 0x4a7 },
+    { 0x00000000, 0xc0210a20, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4c0 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0604800, 0x68f },
+    { 0x00000000, 0x00400000, 0x4c4 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00040000, 0xc0294620, 0x000 },
+    { 0x00000000, 0xc0600000, 0x68a },
+    { 0x00000001, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4cb },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x00000000, 0xc0204400, 0x000 },
+    { 0x00000000, 0xc0404810, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68a },
+    { 0x00000000, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4cd },
+    { 0x00002180, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000003, 0x00333e2f, 0x000 },
+    { 0x00000001, 0x00210221, 0x000 },
+    { 0x00000000, 0x14e00000, 0x4fd },
+    { 0x0000002c, 0x00200a2d, 0x000 },
+    { 0x00040000, 0x18e00c11, 0x4ec },
+    { 0x00000001, 0x00333e2f, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xd8c04800, 0x4e0 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000002d, 0x0020122d, 0x000 },
+    { 0x00000000, 0x00290c83, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000011, 0x00210224, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000000, 0x00400000, 0x4a7 },
+    { 0x0000002c, 0xc0203620, 0x000 },
+    { 0x0000002d, 0xc0403620, 0x000 },
+    { 0x0000000f, 0x00210221, 0x000 },
+    { 0x00000000, 0x14c00000, 0x502 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0xd9000000, 0x000 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0xb5000000, 0x00204411, 0x000 },
+    { 0x00002000, 0x00204811, 0x000 },
+    { 0xb6000000, 0x00204411, 0x000 },
+    { 0x0000a000, 0x00204811, 0x000 },
+    { 0xb7000000, 0x00204411, 0x000 },
+    { 0x0000c000, 0x00204811, 0x000 },
+    { 0xb8000000, 0x00204411, 0x000 },
+    { 0x0000f8e0, 0x00204811, 0x000 },
+    { 0xb9000000, 0x00204411, 0x000 },
+    { 0x0000f880, 0x00204811, 0x000 },
+    { 0xba000000, 0x00204411, 0x000 },
+    { 0x0000e000, 0x00204811, 0x000 },
+    { 0xbb000000, 0x00204411, 0x000 },
+    { 0x0000f000, 0x00204811, 0x000 },
+    { 0xbc000000, 0x00204411, 0x000 },
+    { 0x0000f3fc, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000002, 0x00204811, 0x000 },
+    { 0x000000ff, 0x00280e30, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x516 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0x14c00000, 0x52b },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x0000001c, 0x00203623, 0x000 },
+    { 0x0000002b, 0x00203623, 0x000 },
+    { 0x00000029, 0x00203623, 0x000 },
+    { 0x00000028, 0x00203623, 0x000 },
+    { 0x00000017, 0x00203623, 0x000 },
+    { 0x00000025, 0x00203623, 0x000 },
+    { 0x00000026, 0x00203623, 0x000 },
+    { 0x00000015, 0x00203623, 0x000 },
+    { 0x00000016, 0x00203623, 0x000 },
+    { 0xffffe000, 0x00200c11, 0x000 },
+    { 0x00000021, 0x00203623, 0x000 },
+    { 0x00000022, 0x00203623, 0x000 },
+    { 0x00001fff, 0x00200c11, 0x000 },
+    { 0x00000023, 0x00203623, 0x000 },
+    { 0x00000024, 0x00203623, 0x000 },
+    { 0xf1ffffff, 0x00283a2e, 0x000 },
+    { 0x0000001a, 0xc0220e20, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x0000002a, 0x40203620, 0x000 },
+    { 0x87000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1f4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x00000030, 0x00203623, 0x000 },
+    { 0x9d000000, 0x00204411, 0x000 },
+    { 0x0000001f, 0x40214a20, 0x000 },
+    { 0x96000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x00000000, 0xc0201000, 0x000 },
+    { 0x0000001f, 0x00211624, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x0000001d, 0x00203623, 0x000 },
+    { 0x00000003, 0x00281e23, 0x000 },
+    { 0x00000008, 0x00222223, 0x000 },
+    { 0xfffff000, 0x00282228, 0x000 },
+    { 0x00000000, 0x002920e8, 0x000 },
+    { 0x0000001f, 0x00203628, 0x000 },
+    { 0x00000018, 0x00211e23, 0x000 },
+    { 0x00000020, 0x00203627, 0x000 },
+    { 0x00000002, 0x00221624, 0x000 },
+    { 0x00000000, 0x003014a8, 0x000 },
+    { 0x0000001e, 0x00203625, 0x000 },
+    { 0x00000003, 0x00211a24, 0x000 },
+    { 0x10000000, 0x00281a26, 0x000 },
+    { 0xefffffff, 0x00283a2e, 0x000 },
+    { 0x00000000, 0x004938ce, 0x678 },
+    { 0x00000001, 0x40280a20, 0x000 },
+    { 0x00000006, 0x40280e20, 0x000 },
+    { 0x00000300, 0xc0281220, 0x000 },
+    { 0x00000008, 0x00211224, 0x000 },
+    { 0x00000000, 0xc0201620, 0x000 },
+    { 0x00000000, 0xc0201a20, 0x000 },
+    { 0x00000000, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x563 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00002258, 0x00300a24, 0x000 },
+    { 0x00040000, 0x00694622, 0x68a },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x00020000, 0x00294a26, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x56b },
+    { 0x00000000, 0xc0201c10, 0x000 },
+    { 0x00000000, 0xc0400000, 0x579 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x56b },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00002258, 0x00300a24, 0x000 },
+    { 0x00040000, 0x00694622, 0x68a },
+    { 0x00000000, 0xc0201c10, 0x000 },
+    { 0x00000000, 0xc0400000, 0x579 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x56f },
+    { 0x00000000, 0xc0201c00, 0x000 },
+    { 0x00000000, 0xc0400000, 0x579 },
+    { 0x00000004, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x577 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0604800, 0x68f },
+    { 0x00000000, 0x00401c10, 0x579 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0400000, 0x000 },
+    { 0x00000000, 0x0ee00000, 0x57b },
+    { 0x00000000, 0x00600000, 0x5c6 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x58c },
+    { 0x0000a2b7, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2b6, 0x00604411, 0x68a },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x0000a2c4, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x58a },
+    { 0x0000a2d1, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d1, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x00000001, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x59d },
+    { 0x0000a2bb, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2ba, 0x00604411, 0x68a },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x0000a2c5, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x59b },
+    { 0x0000a2d2, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d2, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x00000002, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5ae },
+    { 0x0000a2bf, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2be, 0x00604411, 0x68a },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x0000a2c6, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x5ac },
+    { 0x0000a2d3, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d3, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x0000a2c3, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2c2, 0x00604411, 0x68a },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x0000a2c7, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x5bb },
+    { 0x0000a2d4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d4, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x85000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0x0000304a, 0x00204411, 0x000 },
+    { 0x01000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00400000, 0x5c1 },
+    { 0xa4000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0xc0600000, 0x5c6 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000002c, 0x00203621, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000000, 0x002f0230, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5cd },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000030, 0x00403621, 0x5e0 },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x00007e00, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x5e0 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a092, 0x00604411, 0x68a },
+    { 0x00000031, 0x00203630, 0x000 },
+    { 0x0004a093, 0x00604411, 0x68a },
+    { 0x00000032, 0x00203630, 0x000 },
+    { 0x0004a2b6, 0x00604411, 0x68a },
+    { 0x00000033, 0x00203630, 0x000 },
+    { 0x0004a2ba, 0x00604411, 0x68a },
+    { 0x00000034, 0x00203630, 0x000 },
+    { 0x0004a2be, 0x00604411, 0x68a },
+    { 0x00000035, 0x00203630, 0x000 },
+    { 0x0004a2c2, 0x00604411, 0x68a },
+    { 0x00000036, 0x00203630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x00000005, 0x00204811, 0x000 },
+    { 0x0000a1f4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x88000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000001, 0x002f0230, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x629 },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x629 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00007e00, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x602 },
+    { 0x0000a092, 0x00204411, 0x000 },
+    { 0x00000031, 0x00204a2d, 0x000 },
+    { 0x0000a093, 0x00204411, 0x000 },
+    { 0x00000032, 0x00204a2d, 0x000 },
+    { 0x0000a2b6, 0x00204411, 0x000 },
+    { 0x00000033, 0x00204a2d, 0x000 },
+    { 0x0000a2ba, 0x00204411, 0x000 },
+    { 0x00000034, 0x00204a2d, 0x000 },
+    { 0x0000a2be, 0x00204411, 0x000 },
+    { 0x00000035, 0x00204a2d, 0x000 },
+    { 0x0000a2c2, 0x00204411, 0x000 },
+    { 0x00000036, 0x00204a2d, 0x000 },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x000001ff, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x628 },
+    { 0x00000000, 0x00210221, 0x000 },
+    { 0x00000000, 0x14c00000, 0x60b },
+    { 0x0004a003, 0x00604411, 0x68a },
+    { 0x0000a003, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00000001, 0x00210621, 0x000 },
+    { 0x00000000, 0x14c00000, 0x610 },
+    { 0x0004a010, 0x00604411, 0x68a },
+    { 0x0000a010, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00000001, 0x00210621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x628 },
+    { 0x0004a011, 0x00604411, 0x68a },
+    { 0x0000a011, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a012, 0x00604411, 0x68a },
+    { 0x0000a012, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a013, 0x00604411, 0x68a },
+    { 0x0000a013, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a014, 0x00604411, 0x68a },
+    { 0x0000a014, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a015, 0x00604411, 0x68a },
+    { 0x0000a015, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a016, 0x00604411, 0x68a },
+    { 0x0000a016, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a017, 0x00604411, 0x68a },
+    { 0x0000a017, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x0000002c, 0x0080062d, 0x000 },
+    { 0xff000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000002, 0x00804811, 0x000 },
+    { 0x00000000, 0x0ee00000, 0x63a },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x00000002, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x638 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x00001000, 0x00200811, 0x000 },
+    { 0x0000002b, 0x00203622, 0x000 },
+    { 0x00000000, 0x00600000, 0x63e },
+    { 0x00000000, 0x00600000, 0x5c6 },
+    { 0x98000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00804811, 0x000 },
+    { 0x00000000, 0xc0600000, 0x63e },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000022, 0x00204811, 0x000 },
+    { 0x89000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00404811, 0x62a },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404811, 0x62a },
+    { 0x00000000, 0x00600000, 0x659 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0xc0204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x36e },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00010000, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x09800000, 0x00204811, 0x000 },
+    { 0xffffffff, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x68a },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000004, 0x00404c11, 0x653 },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000004, 0x00291e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0xfffffffb, 0x00281e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000008, 0x00291e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0xfffffff7, 0x00281e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x36e },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00010000, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x01800000, 0x00204811, 0x000 },
+    { 0xffffffff, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004217f, 0x00604411, 0x68a },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x689 },
+    { 0x00000010, 0x00404c11, 0x66f },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x38c00000, 0x000 },
+    { 0x0000001d, 0x00200a2d, 0x000 },
+    { 0x0000001e, 0x00200e2d, 0x000 },
+    { 0x0000001f, 0x0020122d, 0x000 },
+    { 0x00000020, 0x0020162d, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000004, 0x00301224, 0x000 },
+    { 0x00000000, 0x002f0064, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x688 },
+    { 0x00000003, 0x00281a22, 0x000 },
+    { 0x00000008, 0x00221222, 0x000 },
+    { 0xfffff000, 0x00281224, 0x000 },
+    { 0x00000000, 0x002910c4, 0x000 },
+    { 0x0000001f, 0x00403624, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x1ac00000, 0x68a },
+    { 0x9f000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000000, 0x1ae00000, 0x68d },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x1ac00000, 0x68f },
+    { 0x9e000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000000, 0x1ae00000, 0x692 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00001000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001b, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0xc0204411, 0x000 },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000024, 0x0020222d, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000022, 0x0020222d, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00404811, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x014204ff, 0x05bd0250, 0x000 },
+    { 0x01c30168, 0x043f05bd, 0x000 },
+    { 0x02250209, 0x02500151, 0x000 },
+    { 0x02230245, 0x02a00241, 0x000 },
+    { 0x03d705bd, 0x05bd05bd, 0x000 },
+    { 0x06460647, 0x031f05bd, 0x000 },
+    { 0x05bd05c2, 0x03200340, 0x000 },
+    { 0x032a0282, 0x03420334, 0x000 },
+    { 0x05bd05bd, 0x05bd05bd, 0x000 },
+    { 0x05bd054e, 0x05bd05bd, 0x000 },
+    { 0x03ba05bd, 0x04b80344, 0x000 },
+    { 0x0497044d, 0x043d05bd, 0x000 },
+    { 0x04cd05bd, 0x044104da, 0x000 },
+    { 0x044d0504, 0x03510375, 0x000 },
+    { 0x05bd05bd, 0x05bd05bd, 0x000 },
+    { 0x05bd05bd, 0x05bd05bd, 0x000 },
+    { 0x05bd05bd, 0x063c05c4, 0x000 },
+    { 0x05bd05bd, 0x000705bd, 0x000 },
+    { 0x05bd05bd, 0x05bd05bd, 0x000 },
+    { 0x05bd05bd, 0x05bd05bd, 0x000 },
+    { 0x03f803ed, 0x04080406, 0x000 },
+    { 0x040e040a, 0x040c0410, 0x000 },
+    { 0x041c0418, 0x04240420, 0x000 },
+    { 0x042c0428, 0x04340430, 0x000 },
+    { 0x05bd05bd, 0x043805bd, 0x000 },
+    { 0x05bd05bd, 0x05bd05bd, 0x000 },
+    { 0x05bd05bd, 0x05bd05bd, 0x000 },
+    { 0x00020676, 0x06940006, 0x000 },
+};
+
+static const u32 RV630_pfp_microcode[] = {
+0xca0400,
+0xa00000,
+0x7e828b,
+0x7c038b,
+0x8001b8,
+0x7c038b,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xc41838,
+0xca2400,
+0xca2800,
+0x9581a8,
+0xc41c3a,
+0xc3c000,
+0xca0800,
+0xca0c00,
+0x7c744b,
+0xc20005,
+0x99c000,
+0xc41c3a,
+0x7c744c,
+0xc0fff0,
+0x042c04,
+0x309002,
+0x7d2500,
+0x351402,
+0x7d350b,
+0x255403,
+0x7cd580,
+0x259c03,
+0x95c004,
+0xd5001b,
+0x7eddc1,
+0x7d9d80,
+0xd6801b,
+0xd5801b,
+0xd4401e,
+0xd5401e,
+0xd6401e,
+0xd6801e,
+0xd4801e,
+0xd4c01e,
+0x9783d3,
+0xd5c01e,
+0xca0800,
+0x80001a,
+0xca0c00,
+0xe4011e,
+0xd4001e,
+0x80000c,
+0xc41838,
+0xe4013e,
+0xd4001e,
+0x80000c,
+0xc41838,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4013e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca1800,
+0xd4401e,
+0xd5801e,
+0x800053,
+0xd40075,
+0xd4401e,
+0xca0800,
+0xca0c00,
+0xca1000,
+0xd48019,
+0xd4c018,
+0xd50017,
+0xd4801e,
+0xd4c01e,
+0xd5001e,
+0xe2001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca0800,
+0xd48060,
+0xd4401e,
+0x800000,
+0xd4801e,
+0xca0800,
+0xd48061,
+0xd4401e,
+0x800000,
+0xd4801e,
+0xca0800,
+0xca0c00,
+0xd4401e,
+0xd48016,
+0xd4c016,
+0xd4801e,
+0x8001b8,
+0xd4c01e,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x948004,
+0xca1400,
+0xe420f3,
+0xd42013,
+0xd56065,
+0xd4e01c,
+0xd5201c,
+0xd5601c,
+0x800000,
+0x062001,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x9483f7,
+0xca1400,
+0xe420f3,
+0x800079,
+0xd42013,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x9883ef,
+0xca1400,
+0xd40064,
+0x80008d,
+0x000000,
+0xc41432,
+0xc61843,
+0xc4082f,
+0x954005,
+0xc40c30,
+0xd4401e,
+0x800000,
+0xee001e,
+0x9583f5,
+0xc41031,
+0xd44033,
+0xd52065,
+0xd4a01c,
+0xd4e01c,
+0xd5201c,
+0xe4015e,
+0xd4001e,
+0x800000,
+0x062001,
+0xca1800,
+0x0a2001,
+0xd60076,
+0xc40836,
+0x988007,
+0xc61045,
+0x950110,
+0xd4001f,
+0xd46062,
+0x800000,
+0xd42062,
+0xcc3835,
+0xcc1433,
+0x8401bb,
+0xd40072,
+0xd5401e,
+0x800000,
+0xee001e,
+0xe2001a,
+0x8401bb,
+0xe2001a,
+0xcc104b,
+0xcc0447,
+0x2c9401,
+0x7d098b,
+0x984005,
+0x7d15cb,
+0xd4001a,
+0x8001b8,
+0xd4006d,
+0x344401,
+0xcc0c48,
+0x98403a,
+0xcc2c4a,
+0x958004,
+0xcc0449,
+0x8001b8,
+0xd4001a,
+0xd4c01a,
+0x282801,
+0x8400f0,
+0xcc1003,
+0x98801b,
+0x04380c,
+0x8400f0,
+0xcc1003,
+0x988017,
+0x043808,
+0x8400f0,
+0xcc1003,
+0x988013,
+0x043804,
+0x8400f0,
+0xcc1003,
+0x988014,
+0xcc104c,
+0x9a8009,
+0xcc144d,
+0x9840dc,
+0xd4006d,
+0xcc1848,
+0xd5001a,
+0xd5401a,
+0x8000c9,
+0xd5801a,
+0x96c0d5,
+0xd4006d,
+0x8001b8,
+0xd4006e,
+0x9ac003,
+0xd4006d,
+0xd4006e,
+0x800000,
+0xec007f,
+0x9ac0cc,
+0xd4006d,
+0x8001b8,
+0xd4006e,
+0xcc1403,
+0xcc1803,
+0xcc1c03,
+0x7d9103,
+0x7dd583,
+0x7d190c,
+0x35cc1f,
+0x35701f,
+0x7cf0cb,
+0x7cd08b,
+0x880000,
+0x7e8e8b,
+0x95c004,
+0xd4006e,
+0x8001b8,
+0xd4001a,
+0xd4c01a,
+0xcc0803,
+0xcc0c03,
+0xcc1003,
+0xcc1403,
+0xcc1803,
+0xcc1c03,
+0xcc2403,
+0xcc2803,
+0x35c41f,
+0x36b01f,
+0x7c704b,
+0x34f01f,
+0x7c704b,
+0x35701f,
+0x7c704b,
+0x7d8881,
+0x7dccc1,
+0x7e5101,
+0x7e9541,
+0x7c9082,
+0x7cd4c2,
+0x7c848b,
+0x9ac003,
+0x7c8c8b,
+0x2c8801,
+0x98809e,
+0xd4006d,
+0x98409c,
+0xd4006e,
+0xcc084c,
+0xcc0c4d,
+0xcc1048,
+0xd4801a,
+0xd4c01a,
+0x800101,
+0xd5001a,
+0xcc0832,
+0xd40032,
+0x9482d9,
+0xca0c00,
+0xd4401e,
+0x800000,
+0xd4001e,
+0xe4011e,
+0xd4001e,
+0xca0800,
+0xca0c00,
+0xca1000,
+0xd4401e,
+0xca1400,
+0xd4801e,
+0xd4c01e,
+0xd5001e,
+0xd5401e,
+0xd54034,
+0x800000,
+0xee001e,
+0x280404,
+0xe2001a,
+0xe2001a,
+0xd4401a,
+0xca3800,
+0xcc0803,
+0xcc0c03,
+0xcc0c03,
+0xcc0c03,
+0x9882bd,
+0x000000,
+0x8401bb,
+0xd7a06f,
+0x800000,
+0xee001f,
+0xca0400,
+0xc2ff00,
+0xcc0834,
+0xc13fff,
+0x7c74cb,
+0x7cc90b,
+0x7d010f,
+0x9902b0,
+0x7c738b,
+0x8401bb,
+0xd7a06f,
+0x800000,
+0xee001f,
+0xca0800,
+0x281900,
+0x7d898b,
+0x958014,
+0x281404,
+0xca0c00,
+0xca1000,
+0xca1c00,
+0xca2400,
+0xe2001f,
+0xd4c01a,
+0xd5001a,
+0xd5401a,
+0xcc1803,
+0xcc2c03,
+0xcc2c03,
+0xcc2c03,
+0x7da58b,
+0x7d9c47,
+0x984297,
+0x000000,
+0x800161,
+0xd4c01a,
+0xd4401e,
+0xd4801e,
+0x800000,
+0xee001e,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4013e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca0800,
+0x248c06,
+0x0ccc06,
+0x98c006,
+0xcc104e,
+0x990004,
+0xd40073,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xd4801e,
+0x800000,
+0xee001e,
+0xca0800,
+0xca0c00,
+0x34d018,
+0x251001,
+0x950021,
+0xc17fff,
+0xca1000,
+0xca1400,
+0xca1800,
+0xd4801d,
+0xd4c01d,
+0x7db18b,
+0xc14202,
+0xc2c001,
+0xd5801d,
+0x34dc0e,
+0x7d5d4c,
+0x7f734c,
+0xd7401e,
+0xd5001e,
+0xd5401e,
+0xc14200,
+0xc2c000,
+0x099c01,
+0x31dc10,
+0x7f5f4c,
+0x7f734c,
+0x042802,
+0x7d8380,
+0xd5a86f,
+0xd58066,
+0xd7401e,
+0xec005e,
+0xc82402,
+0xc82402,
+0x8001b8,
+0xd60076,
+0xd4401e,
+0xd4801e,
+0xd4c01e,
+0x800000,
+0xee001e,
+0x800000,
+0xee001f,
+0xd4001f,
+0x800000,
+0xd4001f,
+0xd4001f,
+0x880000,
+0xd4001f,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x010171,
+0x020178,
+0x03008f,
+0x04007f,
+0x050003,
+0x06003f,
+0x070032,
+0x08012c,
+0x090046,
+0x0a0036,
+0x1001b6,
+0x1700a2,
+0x22013a,
+0x230149,
+0x2000b4,
+0x240125,
+0x27004d,
+0x28006a,
+0x2a0060,
+0x2b0052,
+0x2f0065,
+0x320087,
+0x34017f,
+0x3c0156,
+0x3f0072,
+0x41018c,
+0x44012e,
+0x550173,
+0x56017a,
+0x60000b,
+0x610034,
+0x620038,
+0x630038,
+0x640038,
+0x650038,
+0x660038,
+0x670038,
+0x68003a,
+0x690041,
+0x6a0048,
+0x6b0048,
+0x6c0048,
+0x6d0048,
+0x6e0048,
+0x6f0048,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+};
+
+static const u32 RV635_cp_microcode[][3] = {
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0000ffff, 0x00284621, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00000000, 0x00e00000, 0x000 },
+    { 0x00010000, 0xc0294620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x00000000, 0x00600000, 0x62e },
+    { 0x00000000, 0x00600000, 0x642 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000f00, 0x00281622, 0x000 },
+    { 0x00000008, 0x00211625, 0x000 },
+    { 0x00000018, 0x00203625, 0x000 },
+    { 0x8d000000, 0x00204411, 0x000 },
+    { 0x00000004, 0x002f0225, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x018 },
+    { 0x00412000, 0x00404811, 0x019 },
+    { 0x00422000, 0x00204811, 0x000 },
+    { 0x8e000000, 0x00204411, 0x000 },
+    { 0x00000028, 0x00204a2d, 0x000 },
+    { 0x90000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x0000000c, 0x00211622, 0x000 },
+    { 0x00000003, 0x00281625, 0x000 },
+    { 0x00000019, 0x00211a22, 0x000 },
+    { 0x00000004, 0x00281a26, 0x000 },
+    { 0x00000000, 0x002914c5, 0x000 },
+    { 0x00000019, 0x00203625, 0x000 },
+    { 0x00000000, 0x003a1402, 0x000 },
+    { 0x00000016, 0x00211625, 0x000 },
+    { 0x00000003, 0x00281625, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0xfffffffc, 0x00280e23, 0x000 },
+    { 0x00000000, 0x002914a3, 0x000 },
+    { 0x00000017, 0x00203625, 0x000 },
+    { 0x00008000, 0x00280e22, 0x000 },
+    { 0x00000007, 0x00220e23, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x20000000, 0x00280e22, 0x000 },
+    { 0x00000006, 0x00210e23, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x00000000, 0x00220222, 0x000 },
+    { 0x00000000, 0x14e00000, 0x038 },
+    { 0x00000000, 0x2ee00000, 0x035 },
+    { 0x00000000, 0x2ce00000, 0x037 },
+    { 0x00000000, 0x00400e2d, 0x039 },
+    { 0x00000008, 0x00200e2d, 0x000 },
+    { 0x00000009, 0x0040122d, 0x046 },
+    { 0x00000001, 0x00400e2d, 0x039 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x003ffffc, 0x00281223, 0x000 },
+    { 0x00000002, 0x00221224, 0x000 },
+    { 0x0000001f, 0x00211e23, 0x000 },
+    { 0x00000000, 0x14e00000, 0x03e },
+    { 0x00000008, 0x00401c11, 0x041 },
+    { 0x0000000d, 0x00201e2d, 0x000 },
+    { 0x0000000f, 0x00281e27, 0x000 },
+    { 0x00000003, 0x00221e27, 0x000 },
+    { 0x7fc00000, 0x00281a23, 0x000 },
+    { 0x00000014, 0x00211a26, 0x000 },
+    { 0x00000001, 0x00331a26, 0x000 },
+    { 0x00000008, 0x00221a26, 0x000 },
+    { 0x00000000, 0x00290cc7, 0x000 },
+    { 0x00000027, 0x00203624, 0x000 },
+    { 0x00007f00, 0x00281221, 0x000 },
+    { 0x00001400, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x04b },
+    { 0x00000001, 0x00290e23, 0x000 },
+    { 0x0000000e, 0x00203623, 0x000 },
+    { 0x0000e000, 0x00204411, 0x000 },
+    { 0xfff80000, 0x00294a23, 0x000 },
+    { 0x00000000, 0x003a2c02, 0x000 },
+    { 0x00000002, 0x00220e2b, 0x000 },
+    { 0xfc000000, 0x00280e23, 0x000 },
+    { 0x0000000f, 0x00203623, 0x000 },
+    { 0x00001fff, 0x00294a23, 0x000 },
+    { 0x00000027, 0x00204a2d, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000029, 0x00200e2d, 0x000 },
+    { 0x060a0200, 0x00294a23, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00210222, 0x000 },
+    { 0x00000000, 0x14e00000, 0x061 },
+    { 0x00000000, 0x2ee00000, 0x05f },
+    { 0x00000000, 0x2ce00000, 0x05e },
+    { 0x00000000, 0x00400e2d, 0x062 },
+    { 0x00000001, 0x00400e2d, 0x062 },
+    { 0x0000000a, 0x00200e2d, 0x000 },
+    { 0x0000000b, 0x0040122d, 0x06a },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x003ffffc, 0x00281223, 0x000 },
+    { 0x00000002, 0x00221224, 0x000 },
+    { 0x7fc00000, 0x00281623, 0x000 },
+    { 0x00000014, 0x00211625, 0x000 },
+    { 0x00000001, 0x00331625, 0x000 },
+    { 0x80000000, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00290ca3, 0x000 },
+    { 0x3ffffc00, 0x00290e23, 0x000 },
+    { 0x0000001f, 0x00211e23, 0x000 },
+    { 0x00000000, 0x14e00000, 0x06d },
+    { 0x00000100, 0x00401c11, 0x070 },
+    { 0x0000000d, 0x00201e2d, 0x000 },
+    { 0x000000f0, 0x00281e27, 0x000 },
+    { 0x00000004, 0x00221e27, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000d, 0x00204811, 0x000 },
+    { 0xfffff0ff, 0x00281a30, 0x000 },
+    { 0x0000a028, 0x00204411, 0x000 },
+    { 0x00000000, 0x002948e6, 0x000 },
+    { 0x0000a018, 0x00204411, 0x000 },
+    { 0x3fffffff, 0x00284a23, 0x000 },
+    { 0x0000a010, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000030, 0x0020162d, 0x000 },
+    { 0x00000002, 0x00291625, 0x000 },
+    { 0x00000030, 0x00203625, 0x000 },
+    { 0x00000025, 0x0020162d, 0x000 },
+    { 0x00000000, 0x002f00a3, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x083 },
+    { 0x00000026, 0x0020162d, 0x000 },
+    { 0x00000000, 0x002f00a4, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x084 },
+    { 0x00000000, 0x00400000, 0x08a },
+    { 0x00000025, 0x00203623, 0x000 },
+    { 0x00000026, 0x00203624, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x08a },
+    { 0x00000000, 0x00600000, 0x665 },
+    { 0x00000000, 0x00600000, 0x659 },
+    { 0x00000002, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x08d },
+    { 0x00000012, 0xc0403620, 0x093 },
+    { 0x00000000, 0x2ee00000, 0x091 },
+    { 0x00000000, 0x2ce00000, 0x090 },
+    { 0x00000002, 0x00400e2d, 0x092 },
+    { 0x00000003, 0x00400e2d, 0x092 },
+    { 0x0000000c, 0x00200e2d, 0x000 },
+    { 0x00000012, 0x00203623, 0x000 },
+    { 0x00000003, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x098 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x0a0 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x2ee00000, 0x09e },
+    { 0x00000000, 0x2ce00000, 0x09d },
+    { 0x00000002, 0x00400e2d, 0x09f },
+    { 0x00000003, 0x00400e2d, 0x09f },
+    { 0x0000000c, 0x00200e2d, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000000, 0x003a0c02, 0x000 },
+    { 0x003f0000, 0x00280e23, 0x000 },
+    { 0x00000010, 0x00210e23, 0x000 },
+    { 0x00000011, 0x00203623, 0x000 },
+    { 0x0000001e, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0a7 },
+    { 0x00000016, 0xc0203620, 0x000 },
+    { 0x0000001f, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0aa },
+    { 0x00000015, 0xc0203620, 0x000 },
+    { 0x00000008, 0x00210e2b, 0x000 },
+    { 0x0000007f, 0x00280e23, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0e1 },
+    { 0x00000000, 0x27000000, 0x000 },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x0b3 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x0000000c, 0x00221e30, 0x000 },
+    { 0x99800000, 0x00204411, 0x000 },
+    { 0x00000004, 0x0020122d, 0x000 },
+    { 0x00000008, 0x00221224, 0x000 },
+    { 0x00000010, 0x00201811, 0x000 },
+    { 0x00000000, 0x00291ce4, 0x000 },
+    { 0x00000000, 0x00604807, 0x12f },
+    { 0x9b000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x9c000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x0033146f, 0x000 },
+    { 0x00000001, 0x00333e23, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0x00203c05, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x00000000, 0x00201010, 0x000 },
+    { 0x0000e007, 0x00204411, 0x000 },
+    { 0x0000000f, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0cb },
+    { 0x00f8ff08, 0x00204811, 0x000 },
+    { 0x98000000, 0x00404811, 0x0dc },
+    { 0x000000f0, 0x00280e22, 0x000 },
+    { 0x000000a0, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x0da },
+    { 0x00000011, 0x00200e2d, 0x000 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0d5 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0d4 },
+    { 0x00003f00, 0x00400c11, 0x0d6 },
+    { 0x00001f00, 0x00400c11, 0x0d6 },
+    { 0x00000f00, 0x00200c11, 0x000 },
+    { 0x00380009, 0x00294a23, 0x000 },
+    { 0x3f000000, 0x00280e2b, 0x000 },
+    { 0x00000002, 0x00220e23, 0x000 },
+    { 0x00000007, 0x00494a23, 0x0dc },
+    { 0x00380f09, 0x00204811, 0x000 },
+    { 0x68000007, 0x00204811, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a24, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000a202, 0x00204411, 0x000 },
+    { 0x00ff0000, 0x00280e22, 0x000 },
+    { 0x00000080, 0x00294a23, 0x000 },
+    { 0x00000027, 0x00200e2d, 0x000 },
+    { 0x00000026, 0x0020122d, 0x000 },
+    { 0x00000000, 0x002f0083, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0ea },
+    { 0x00000000, 0x00600000, 0x65f },
+    { 0x00000000, 0x00400000, 0x0eb },
+    { 0x00000000, 0x00600000, 0x662 },
+    { 0x00000007, 0x0020222d, 0x000 },
+    { 0x00000005, 0x00220e22, 0x000 },
+    { 0x00100000, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00292068, 0x000 },
+    { 0x00000000, 0x003a0c02, 0x000 },
+    { 0x000000ef, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00292068, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0x00000003, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x0f8 },
+    { 0x0000000b, 0x00210228, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0f8 },
+    { 0x00000400, 0x00292228, 0x000 },
+    { 0x00000014, 0x00203628, 0x000 },
+    { 0x0000001c, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0fd },
+    { 0x0000a30c, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000001e, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x10b },
+    { 0x0000a30f, 0x00204411, 0x000 },
+    { 0x00000011, 0x00200e2d, 0x000 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x104 },
+    { 0xffffffff, 0x00404811, 0x10b },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x107 },
+    { 0x0000ffff, 0x00404811, 0x10b },
+    { 0x00000004, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x10a },
+    { 0x000000ff, 0x00404811, 0x10b },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0002c400, 0x00204411, 0x000 },
+    { 0x0000001f, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x112 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x00000013, 0x00203623, 0x000 },
+    { 0x00000018, 0x40224a20, 0x000 },
+    { 0x00000010, 0xc0424a20, 0x114 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x00000013, 0x00203623, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000000a, 0x00201011, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x11b },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00531224, 0x117 },
+    { 0xffbfffff, 0x00283a2e, 0x000 },
+    { 0x0000001b, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x12e },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000d, 0x00204811, 0x000 },
+    { 0x00000018, 0x00220e30, 0x000 },
+    { 0xfc000000, 0x00280e23, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x00000000, 0x00201010, 0x000 },
+    { 0x0000e00e, 0x00204411, 0x000 },
+    { 0x07f8ff08, 0x00204811, 0x000 },
+    { 0x00000000, 0x00294a23, 0x000 },
+    { 0x0000001c, 0x00201e2d, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a24, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x00800000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204806, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x68a },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x689 },
+    { 0x00000004, 0x00404c11, 0x135 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x0000001c, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68a },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x13c },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00000000, 0x00600000, 0x160 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000ffff, 0x40280620, 0x000 },
+    { 0x00000010, 0xc0210a20, 0x000 },
+    { 0x00000000, 0x00341461, 0x000 },
+    { 0x00000000, 0x00741882, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x147 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x160 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x00000010, 0x40211620, 0x000 },
+    { 0x0000ffff, 0xc0681a20, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x158 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000001, 0x00300a2f, 0x000 },
+    { 0x00000001, 0x00210a22, 0x000 },
+    { 0x00000003, 0x00384a22, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001a, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600000, 0x18f },
+    { 0x00000000, 0x00600000, 0x1a0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00202c08, 0x000 },
+    { 0x00000000, 0x00202411, 0x000 },
+    { 0x00000000, 0x00202811, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000002, 0x00221e29, 0x000 },
+    { 0x00000000, 0x007048eb, 0x19c },
+    { 0x00000000, 0x00600000, 0x2bb },
+    { 0x00000001, 0x40330620, 0x000 },
+    { 0x00000000, 0xc0302409, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x181 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x00000000, 0x00400000, 0x186 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x186 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000001, 0x00530621, 0x182 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0604800, 0x197 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000011, 0x0020062d, 0x000 },
+    { 0x00000000, 0x0078042a, 0x2fb },
+    { 0x00000000, 0x00202809, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x174 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000210, 0x00600411, 0x315 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x194 },
+    { 0x00000015, 0xc0203620, 0x000 },
+    { 0x00000016, 0xc0203620, 0x000 },
+    { 0x3f800000, 0x00200411, 0x000 },
+    { 0x46000000, 0x00600811, 0x1b2 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x19b },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000021, 0x00804811, 0x000 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000ffff, 0x40281620, 0x000 },
+    { 0x00000010, 0xc0811a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000008, 0x00221e30, 0x000 },
+    { 0x00000029, 0x00201a2d, 0x000 },
+    { 0x0000e000, 0x00204411, 0x000 },
+    { 0xfffbff09, 0x00204811, 0x000 },
+    { 0x0000000f, 0x0020222d, 0x000 },
+    { 0x00001fff, 0x00294a28, 0x000 },
+    { 0x00000006, 0x0020222d, 0x000 },
+    { 0x00000000, 0x002920e8, 0x000 },
+    { 0x00000000, 0x00204808, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a26, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000100, 0x00201811, 0x000 },
+    { 0x00000008, 0x00621e28, 0x12f },
+    { 0x00000008, 0x00822228, 0x000 },
+    { 0x0002c000, 0x00204411, 0x000 },
+    { 0x00000015, 0x00600e2d, 0x1bd },
+    { 0x00000016, 0x00600e2d, 0x1bd },
+    { 0x0000c008, 0x00204411, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0x00000000, 0x14c00000, 0x1b9 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0x39000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00804802, 0x000 },
+    { 0x00000018, 0x00202e2d, 0x000 },
+    { 0x00000000, 0x003b0d63, 0x000 },
+    { 0x00000008, 0x00224a23, 0x000 },
+    { 0x00000010, 0x00224a23, 0x000 },
+    { 0x00000018, 0x00224a23, 0x000 },
+    { 0x00000000, 0x00804803, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00001000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00000007, 0x0021062f, 0x000 },
+    { 0x00000013, 0x00200a2d, 0x000 },
+    { 0x00000001, 0x00202c11, 0x000 },
+    { 0x0000ffff, 0x40282220, 0x000 },
+    { 0x0000000f, 0x00262228, 0x000 },
+    { 0x00000010, 0x40212620, 0x000 },
+    { 0x0000000f, 0x00262629, 0x000 },
+    { 0x00000000, 0x00202802, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001b, 0x00204811, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1e0 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000081, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000080, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f0227, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1dc },
+    { 0x00000000, 0x00600000, 0x1e9 },
+    { 0x00000001, 0x00531e27, 0x1d8 },
+    { 0x00000001, 0x00202c11, 0x000 },
+    { 0x0000001f, 0x00280a22, 0x000 },
+    { 0x0000001f, 0x00282a2a, 0x000 },
+    { 0x00000001, 0x00530621, 0x1d1 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000002, 0x00304a2f, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000001, 0x00301e2f, 0x000 },
+    { 0x00000000, 0x002f0227, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x1e9 },
+    { 0x00000001, 0x00531e27, 0x1e5 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x0000000f, 0x00260e23, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000000f, 0x00261224, 0x000 },
+    { 0x00000000, 0x00201411, 0x000 },
+    { 0x00000000, 0x00601811, 0x2bb },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022b, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1f8 },
+    { 0x00000010, 0x00221628, 0x000 },
+    { 0xffff0000, 0x00281625, 0x000 },
+    { 0x0000ffff, 0x00281a29, 0x000 },
+    { 0x00000000, 0x002948c5, 0x000 },
+    { 0x00000000, 0x0020480a, 0x000 },
+    { 0x00000000, 0x00202c11, 0x000 },
+    { 0x00000010, 0x00221623, 0x000 },
+    { 0xffff0000, 0x00281625, 0x000 },
+    { 0x0000ffff, 0x00281a24, 0x000 },
+    { 0x00000000, 0x002948c5, 0x000 },
+    { 0x00000000, 0x00731503, 0x205 },
+    { 0x00000000, 0x00201805, 0x000 },
+    { 0x00000000, 0x00731524, 0x205 },
+    { 0x00000000, 0x002d14c5, 0x000 },
+    { 0x00000000, 0x003008a2, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00202802, 0x000 },
+    { 0x00000000, 0x00202003, 0x000 },
+    { 0x00000000, 0x00802404, 0x000 },
+    { 0x0000000f, 0x00210225, 0x000 },
+    { 0x00000000, 0x14c00000, 0x689 },
+    { 0x00000000, 0x002b1405, 0x000 },
+    { 0x00000001, 0x00901625, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001a, 0x00294a22, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00384a21, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000ffff, 0x40281220, 0x000 },
+    { 0x00000010, 0xc0211a20, 0x000 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211620, 0x000 },
+    { 0x00000000, 0x00741465, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00000001, 0x00330621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x219 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x212 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x642 },
+    { 0x00000000, 0x0040040f, 0x213 },
+    { 0x00000000, 0x00600000, 0x62e },
+    { 0x00000000, 0x00600000, 0x642 },
+    { 0x00000210, 0x00600411, 0x315 },
+    { 0x00000000, 0x00600000, 0x1a0 },
+    { 0x00000000, 0x00600000, 0x19c },
+    { 0x00000000, 0x00600000, 0x2bb },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204808, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x232 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x00000000, 0x00400000, 0x236 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x236 },
+    { 0x00000000, 0xc0404800, 0x233 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x00600411, 0x2fb },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x62e },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000018, 0x40210a20, 0x000 },
+    { 0x00000003, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x24c },
+    { 0x00000014, 0x0020222d, 0x000 },
+    { 0x00080101, 0x00292228, 0x000 },
+    { 0x00000014, 0x00203628, 0x000 },
+    { 0x0000a30c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x251 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000010, 0x00600411, 0x315 },
+    { 0x3f800000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x00000000, 0x00600000, 0x27c },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000001, 0x00211e27, 0x000 },
+    { 0x00000000, 0x14e00000, 0x26a },
+    { 0x00000012, 0x00201e2d, 0x000 },
+    { 0x0000ffff, 0x00281e27, 0x000 },
+    { 0x00000000, 0x00341c27, 0x000 },
+    { 0x00000000, 0x12c00000, 0x25f },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f00e5, 0x000 },
+    { 0x00000000, 0x08c00000, 0x262 },
+    { 0x00000000, 0x00201407, 0x000 },
+    { 0x00000012, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00211e27, 0x000 },
+    { 0x00000000, 0x00341c47, 0x000 },
+    { 0x00000000, 0x12c00000, 0x267 },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f00e6, 0x000 },
+    { 0x00000000, 0x08c00000, 0x26a },
+    { 0x00000000, 0x00201807, 0x000 },
+    { 0x00000000, 0x00600000, 0x2c1 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000000, 0x00342023, 0x000 },
+    { 0x00000000, 0x12c00000, 0x272 },
+    { 0x00000000, 0x00342044, 0x000 },
+    { 0x00000000, 0x12c00000, 0x271 },
+    { 0x00000016, 0x00404811, 0x276 },
+    { 0x00000018, 0x00404811, 0x276 },
+    { 0x00000000, 0x00342044, 0x000 },
+    { 0x00000000, 0x12c00000, 0x275 },
+    { 0x00000017, 0x00404811, 0x276 },
+    { 0x00000019, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0x00604411, 0x2e9 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x256 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000010, 0x40210620, 0x000 },
+    { 0x0000ffff, 0xc0280a20, 0x000 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x00000010, 0x40211620, 0x000 },
+    { 0x0000ffff, 0xc0881a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x00000000, 0x00600000, 0x62e },
+    { 0x00000000, 0xc0600000, 0x2a3 },
+    { 0x00000005, 0x00200a2d, 0x000 },
+    { 0x00000008, 0x00220a22, 0x000 },
+    { 0x0000002b, 0x00201a2d, 0x000 },
+    { 0x0000001c, 0x00201e2d, 0x000 },
+    { 0x00007000, 0x00281e27, 0x000 },
+    { 0x00000000, 0x00311ce6, 0x000 },
+    { 0x0000002a, 0x00201a2d, 0x000 },
+    { 0x0000000c, 0x00221a26, 0x000 },
+    { 0x00000000, 0x002f00e6, 0x000 },
+    { 0x00000000, 0x06e00000, 0x292 },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x0000002b, 0x00203623, 0x000 },
+    { 0x00000010, 0x00201811, 0x000 },
+    { 0x00000000, 0x00691ce2, 0x12f },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x29d },
+    { 0x00000001, 0x00333e2f, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000001c, 0x00403627, 0x000 },
+    { 0x0000000c, 0xc0220a20, 0x000 },
+    { 0x00000029, 0x00203622, 0x000 },
+    { 0x00000028, 0xc0403620, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000009, 0x00204811, 0x000 },
+    { 0xa1000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002c1ce3, 0x000 },
+    { 0x00000021, 0x00203627, 0x000 },
+    { 0x00000022, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002c1ce4, 0x000 },
+    { 0x00000022, 0x00203627, 0x000 },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120a3, 0x000 },
+    { 0x00000000, 0x002d1d07, 0x000 },
+    { 0x00000023, 0x00203627, 0x000 },
+    { 0x00000024, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x00000000, 0x002d1d07, 0x000 },
+    { 0x00000024, 0x00803627, 0x000 },
+    { 0x00000021, 0x00203623, 0x000 },
+    { 0x00000022, 0x00203624, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000023, 0x00203627, 0x000 },
+    { 0x00000000, 0x00311cc4, 0x000 },
+    { 0x00000024, 0x00803627, 0x000 },
+    { 0x0000001a, 0x00203627, 0x000 },
+    { 0x0000001b, 0x00203628, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14c00000, 0x2dc },
+    { 0x00000000, 0x00400000, 0x2d9 },
+    { 0x0000001a, 0x00203627, 0x000 },
+    { 0x0000001b, 0x00203628, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x2d9 },
+    { 0x00000003, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x2dc },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002e00e1, 0x000 },
+    { 0x00000000, 0x02c00000, 0x2dc },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120a1, 0x000 },
+    { 0x00000000, 0x002e00e8, 0x000 },
+    { 0x00000000, 0x06c00000, 0x2dc },
+    { 0x00000024, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002e00e2, 0x000 },
+    { 0x00000000, 0x02c00000, 0x2dc },
+    { 0x00000022, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120c2, 0x000 },
+    { 0x00000000, 0x002e00e8, 0x000 },
+    { 0x00000000, 0x06c00000, 0x2dc },
+    { 0x00000000, 0x00600000, 0x665 },
+    { 0x00000000, 0x00600000, 0x2b5 },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x00000000, 0x00600000, 0x2b5 },
+    { 0x00000000, 0x00600000, 0x65c },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x00000000, 0x00600000, 0x2a7 },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x0000001a, 0x00201e2d, 0x000 },
+    { 0x0000001b, 0x0080222d, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000010, 0x00221e21, 0x000 },
+    { 0x00000000, 0x00294847, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000000, 0x00311ca1, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294847, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000010, 0x00221e21, 0x000 },
+    { 0x00000000, 0x003120c2, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000001, 0x00220a21, 0x000 },
+    { 0x00000000, 0x003308a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000001, 0x00220a21, 0x000 },
+    { 0x00000000, 0x003008a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x003808c5, 0x000 },
+    { 0x00000000, 0x00300841, 0x000 },
+    { 0x00000001, 0x00220a22, 0x000 },
+    { 0x00000000, 0x003308a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000017, 0x0020222d, 0x000 },
+    { 0x00000000, 0x14c00000, 0x318 },
+    { 0xffffffef, 0x00280621, 0x000 },
+    { 0x00000014, 0x0020222d, 0x000 },
+    { 0x0000f8e0, 0x00204411, 0x000 },
+    { 0x00000000, 0x00294901, 0x000 },
+    { 0x00000000, 0x00894901, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00804811, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x97000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0xc0204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00002257, 0x00204411, 0x000 },
+    { 0x00000003, 0xc0484a20, 0x000 },
+    { 0x0000225d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0x00600000, 0x642 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00384a22, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x40204800, 0x000 },
+    { 0x00000001, 0x40304a20, 0x000 },
+    { 0x00000002, 0xc0304a20, 0x000 },
+    { 0x00000001, 0x00530a22, 0x34b },
+    { 0x0000003f, 0xc0280a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000018, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68a },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x354 },
+    { 0x00000014, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x364 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00604802, 0x36e },
+    { 0x00002100, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000004, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x36a },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x35f },
+    { 0x00000028, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5bd },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x35f },
+    { 0x0000002c, 0x00203626, 0x000 },
+    { 0x00000049, 0x00201811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x00000001, 0x00331a26, 0x000 },
+    { 0x00000000, 0x002f0226, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x370 },
+    { 0x0000002c, 0x00801a2d, 0x000 },
+    { 0x0000003f, 0xc0280a20, 0x000 },
+    { 0x00000015, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x386 },
+    { 0x00000006, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3b1 },
+    { 0x00000016, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3b5 },
+    { 0x00000020, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x39c },
+    { 0x0000000f, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3a8 },
+    { 0x00000010, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3a8 },
+    { 0x0000001e, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x390 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x08000000, 0x00290a22, 0x000 },
+    { 0x00000003, 0x40210e20, 0x000 },
+    { 0x0000000c, 0xc0211220, 0x000 },
+    { 0x00080000, 0x00281224, 0x000 },
+    { 0x00000014, 0xc0221620, 0x000 },
+    { 0x00000000, 0x002914a4, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x002948a2, 0x000 },
+    { 0x0000a1fe, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404803, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68a },
+    { 0x00000015, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x392 },
+    { 0x0000210e, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000017, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68a },
+    { 0x00000003, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x39e },
+    { 0x00002108, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x80000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000010, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3ae },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000006, 0x00404811, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x36e },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x0000001d, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x3ce },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000018, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68a },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x3c0 },
+    { 0x00002100, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0xbabecafe, 0x00204811, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000004, 0x00404811, 0x000 },
+    { 0x00002170, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000a, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3d3 },
+    { 0x8c000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00003fff, 0x40280a20, 0x000 },
+    { 0x80000000, 0x40280e20, 0x000 },
+    { 0x40000000, 0xc0281220, 0x000 },
+    { 0x00040000, 0x00694622, 0x68a },
+    { 0x00000000, 0x00201410, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x3e1 },
+    { 0x00000000, 0xc0401800, 0x3e4 },
+    { 0x00003fff, 0xc0281a20, 0x000 },
+    { 0x00040000, 0x00694626, 0x68a },
+    { 0x00000000, 0x00201810, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x3e7 },
+    { 0x00000000, 0xc0401c00, 0x3ea },
+    { 0x00003fff, 0xc0281e20, 0x000 },
+    { 0x00040000, 0x00694627, 0x68a },
+    { 0x00000000, 0x00201c10, 0x000 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0x002820c5, 0x000 },
+    { 0x00000000, 0x004948e8, 0x000 },
+    { 0xa5800000, 0x00200811, 0x000 },
+    { 0x00002000, 0x00200c11, 0x000 },
+    { 0x83000000, 0x00604411, 0x412 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x40204800, 0x000 },
+    { 0x0000001f, 0xc0210220, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3f7 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0000ffff, 0xc0481220, 0x3ff },
+    { 0xa7800000, 0x00200811, 0x000 },
+    { 0x0000a000, 0x00200c11, 0x000 },
+    { 0x83000000, 0x00604411, 0x412 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x83000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00304883, 0x000 },
+    { 0x84000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x1d000000, 0x000 },
+    { 0x83000000, 0x00604411, 0x412 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0xa9800000, 0x00200811, 0x000 },
+    { 0x0000c000, 0x00400c11, 0x3fa },
+    { 0xab800000, 0x00200811, 0x000 },
+    { 0x0000f8e0, 0x00400c11, 0x3fa },
+    { 0xad800000, 0x00200811, 0x000 },
+    { 0x0000f880, 0x00400c11, 0x3fa },
+    { 0xb3800000, 0x00200811, 0x000 },
+    { 0x0000f3fc, 0x00400c11, 0x3fa },
+    { 0xaf800000, 0x00200811, 0x000 },
+    { 0x0000e000, 0x00400c11, 0x3fa },
+    { 0xb1800000, 0x00200811, 0x000 },
+    { 0x0000f000, 0x00400c11, 0x3fa },
+    { 0x83000000, 0x00204411, 0x000 },
+    { 0x00002148, 0x00204811, 0x000 },
+    { 0x84000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x1d000000, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x01182000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0218a000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0318c000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0418f8e0, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0518f880, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0618e000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0718f000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0818f3fc, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00000030, 0x00200a2d, 0x000 },
+    { 0x00000000, 0xc0290c40, 0x000 },
+    { 0x00000030, 0x00203623, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x86000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404801, 0x000 },
+    { 0x85000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0x00404801, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x68a },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000000, 0x00404c02, 0x448 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x00000000, 0xc0201000, 0x000 },
+    { 0x00000000, 0xc0201400, 0x000 },
+    { 0x00000000, 0xc0201800, 0x000 },
+    { 0x00000000, 0xc0201c00, 0x000 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x456 },
+    { 0x00000000, 0xc0202000, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x00000010, 0x00280a23, 0x000 },
+    { 0x00000010, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x45e },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00040000, 0x00694624, 0x68a },
+    { 0x00000000, 0x00400000, 0x463 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000000, 0x00604805, 0x68f },
+    { 0x00000000, 0x002824f0, 0x000 },
+    { 0x00000007, 0x00280a23, 0x000 },
+    { 0x00000001, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x46a },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x04e00000, 0x483 },
+    { 0x00000000, 0x00400000, 0x490 },
+    { 0x00000002, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x46f },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x02e00000, 0x483 },
+    { 0x00000000, 0x00400000, 0x490 },
+    { 0x00000003, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x474 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x483 },
+    { 0x00000000, 0x00400000, 0x490 },
+    { 0x00000004, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x479 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x483 },
+    { 0x00000000, 0x00400000, 0x490 },
+    { 0x00000005, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x47e },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x06e00000, 0x483 },
+    { 0x00000000, 0x00400000, 0x490 },
+    { 0x00000006, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x483 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x08e00000, 0x483 },
+    { 0x00000000, 0x00400000, 0x490 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x000 },
+    { 0x00000008, 0x00210a23, 0x000 },
+    { 0x00000000, 0x14c00000, 0x48d },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x00000000, 0xc0204400, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x496 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0400000, 0x000 },
+    { 0x00000000, 0x00404c08, 0x456 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x00000011, 0x40211220, 0x000 },
+    { 0x00000012, 0x40211620, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00210225, 0x000 },
+    { 0x00000000, 0x14e00000, 0x4a0 },
+    { 0x00040000, 0xc0494a20, 0x4a1 },
+    { 0xfffbffff, 0xc0284a20, 0x000 },
+    { 0x00000000, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x4ad },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x00210224, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000c, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4a9 },
+    { 0xa0000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000004, 0x00204811, 0x000 },
+    { 0x0000216b, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204810, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000005, 0x00204811, 0x000 },
+    { 0x0000216c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204810, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00400000, 0x4a7 },
+    { 0x00000000, 0xc0210a20, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4c0 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0604800, 0x68f },
+    { 0x00000000, 0x00400000, 0x4c4 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00040000, 0xc0294620, 0x000 },
+    { 0x00000000, 0xc0600000, 0x68a },
+    { 0x00000001, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4cb },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x00000000, 0xc0204400, 0x000 },
+    { 0x00000000, 0xc0404810, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x68a },
+    { 0x00000000, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4cd },
+    { 0x00002180, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000003, 0x00333e2f, 0x000 },
+    { 0x00000001, 0x00210221, 0x000 },
+    { 0x00000000, 0x14e00000, 0x4fd },
+    { 0x0000002c, 0x00200a2d, 0x000 },
+    { 0x00040000, 0x18e00c11, 0x4ec },
+    { 0x00000001, 0x00333e2f, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xd8c04800, 0x4e0 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000002d, 0x0020122d, 0x000 },
+    { 0x00000000, 0x00290c83, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000011, 0x00210224, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000000, 0x00400000, 0x4a7 },
+    { 0x0000002c, 0xc0203620, 0x000 },
+    { 0x0000002d, 0xc0403620, 0x000 },
+    { 0x0000000f, 0x00210221, 0x000 },
+    { 0x00000000, 0x14c00000, 0x502 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0xd9000000, 0x000 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0xb5000000, 0x00204411, 0x000 },
+    { 0x00002000, 0x00204811, 0x000 },
+    { 0xb6000000, 0x00204411, 0x000 },
+    { 0x0000a000, 0x00204811, 0x000 },
+    { 0xb7000000, 0x00204411, 0x000 },
+    { 0x0000c000, 0x00204811, 0x000 },
+    { 0xb8000000, 0x00204411, 0x000 },
+    { 0x0000f8e0, 0x00204811, 0x000 },
+    { 0xb9000000, 0x00204411, 0x000 },
+    { 0x0000f880, 0x00204811, 0x000 },
+    { 0xba000000, 0x00204411, 0x000 },
+    { 0x0000e000, 0x00204811, 0x000 },
+    { 0xbb000000, 0x00204411, 0x000 },
+    { 0x0000f000, 0x00204811, 0x000 },
+    { 0xbc000000, 0x00204411, 0x000 },
+    { 0x0000f3fc, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000002, 0x00204811, 0x000 },
+    { 0x000000ff, 0x00280e30, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x516 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0x14c00000, 0x52b },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x0000001c, 0x00203623, 0x000 },
+    { 0x0000002b, 0x00203623, 0x000 },
+    { 0x00000029, 0x00203623, 0x000 },
+    { 0x00000028, 0x00203623, 0x000 },
+    { 0x00000017, 0x00203623, 0x000 },
+    { 0x00000025, 0x00203623, 0x000 },
+    { 0x00000026, 0x00203623, 0x000 },
+    { 0x00000015, 0x00203623, 0x000 },
+    { 0x00000016, 0x00203623, 0x000 },
+    { 0xffffe000, 0x00200c11, 0x000 },
+    { 0x00000021, 0x00203623, 0x000 },
+    { 0x00000022, 0x00203623, 0x000 },
+    { 0x00001fff, 0x00200c11, 0x000 },
+    { 0x00000023, 0x00203623, 0x000 },
+    { 0x00000024, 0x00203623, 0x000 },
+    { 0xf1ffffff, 0x00283a2e, 0x000 },
+    { 0x0000001a, 0xc0220e20, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x0000002a, 0x40203620, 0x000 },
+    { 0x87000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1f4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x00000030, 0x00203623, 0x000 },
+    { 0x9d000000, 0x00204411, 0x000 },
+    { 0x0000001f, 0x40214a20, 0x000 },
+    { 0x96000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x00000000, 0xc0201000, 0x000 },
+    { 0x0000001f, 0x00211624, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x0000001d, 0x00203623, 0x000 },
+    { 0x00000003, 0x00281e23, 0x000 },
+    { 0x00000008, 0x00222223, 0x000 },
+    { 0xfffff000, 0x00282228, 0x000 },
+    { 0x00000000, 0x002920e8, 0x000 },
+    { 0x0000001f, 0x00203628, 0x000 },
+    { 0x00000018, 0x00211e23, 0x000 },
+    { 0x00000020, 0x00203627, 0x000 },
+    { 0x00000002, 0x00221624, 0x000 },
+    { 0x00000000, 0x003014a8, 0x000 },
+    { 0x0000001e, 0x00203625, 0x000 },
+    { 0x00000003, 0x00211a24, 0x000 },
+    { 0x10000000, 0x00281a26, 0x000 },
+    { 0xefffffff, 0x00283a2e, 0x000 },
+    { 0x00000000, 0x004938ce, 0x678 },
+    { 0x00000001, 0x40280a20, 0x000 },
+    { 0x00000006, 0x40280e20, 0x000 },
+    { 0x00000300, 0xc0281220, 0x000 },
+    { 0x00000008, 0x00211224, 0x000 },
+    { 0x00000000, 0xc0201620, 0x000 },
+    { 0x00000000, 0xc0201a20, 0x000 },
+    { 0x00000000, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x563 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00002258, 0x00300a24, 0x000 },
+    { 0x00040000, 0x00694622, 0x68a },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x00020000, 0x00294a26, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x56b },
+    { 0x00000000, 0xc0201c10, 0x000 },
+    { 0x00000000, 0xc0400000, 0x579 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x56b },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00002258, 0x00300a24, 0x000 },
+    { 0x00040000, 0x00694622, 0x68a },
+    { 0x00000000, 0xc0201c10, 0x000 },
+    { 0x00000000, 0xc0400000, 0x579 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x56f },
+    { 0x00000000, 0xc0201c00, 0x000 },
+    { 0x00000000, 0xc0400000, 0x579 },
+    { 0x00000004, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x577 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0604800, 0x68f },
+    { 0x00000000, 0x00401c10, 0x579 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0400000, 0x000 },
+    { 0x00000000, 0x0ee00000, 0x57b },
+    { 0x00000000, 0x00600000, 0x5c6 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x58c },
+    { 0x0000a2b7, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2b6, 0x00604411, 0x68a },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x0000a2c4, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x58a },
+    { 0x0000a2d1, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d1, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x00000001, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x59d },
+    { 0x0000a2bb, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2ba, 0x00604411, 0x68a },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x0000a2c5, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x59b },
+    { 0x0000a2d2, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d2, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x00000002, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5ae },
+    { 0x0000a2bf, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2be, 0x00604411, 0x68a },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x0000a2c6, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x5ac },
+    { 0x0000a2d3, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d3, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x0000a2c3, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2c2, 0x00604411, 0x68a },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x0000a2c7, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x5bb },
+    { 0x0000a2d4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d4, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x85000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0x0000304a, 0x00204411, 0x000 },
+    { 0x01000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00400000, 0x5c1 },
+    { 0xa4000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0xc0600000, 0x5c6 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000002c, 0x00203621, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000000, 0x002f0230, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5cd },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000030, 0x00403621, 0x5e0 },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x00007e00, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x5e0 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a092, 0x00604411, 0x68a },
+    { 0x00000031, 0x00203630, 0x000 },
+    { 0x0004a093, 0x00604411, 0x68a },
+    { 0x00000032, 0x00203630, 0x000 },
+    { 0x0004a2b6, 0x00604411, 0x68a },
+    { 0x00000033, 0x00203630, 0x000 },
+    { 0x0004a2ba, 0x00604411, 0x68a },
+    { 0x00000034, 0x00203630, 0x000 },
+    { 0x0004a2be, 0x00604411, 0x68a },
+    { 0x00000035, 0x00203630, 0x000 },
+    { 0x0004a2c2, 0x00604411, 0x68a },
+    { 0x00000036, 0x00203630, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x00000005, 0x00204811, 0x000 },
+    { 0x0000a1f4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x88000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000001, 0x002f0230, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x629 },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x629 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00007e00, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x602 },
+    { 0x0000a092, 0x00204411, 0x000 },
+    { 0x00000031, 0x00204a2d, 0x000 },
+    { 0x0000a093, 0x00204411, 0x000 },
+    { 0x00000032, 0x00204a2d, 0x000 },
+    { 0x0000a2b6, 0x00204411, 0x000 },
+    { 0x00000033, 0x00204a2d, 0x000 },
+    { 0x0000a2ba, 0x00204411, 0x000 },
+    { 0x00000034, 0x00204a2d, 0x000 },
+    { 0x0000a2be, 0x00204411, 0x000 },
+    { 0x00000035, 0x00204a2d, 0x000 },
+    { 0x0000a2c2, 0x00204411, 0x000 },
+    { 0x00000036, 0x00204a2d, 0x000 },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x000001ff, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x628 },
+    { 0x00000000, 0x00210221, 0x000 },
+    { 0x00000000, 0x14c00000, 0x60b },
+    { 0x0004a003, 0x00604411, 0x68a },
+    { 0x0000a003, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00000001, 0x00210621, 0x000 },
+    { 0x00000000, 0x14c00000, 0x610 },
+    { 0x0004a010, 0x00604411, 0x68a },
+    { 0x0000a010, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00000001, 0x00210621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x628 },
+    { 0x0004a011, 0x00604411, 0x68a },
+    { 0x0000a011, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a012, 0x00604411, 0x68a },
+    { 0x0000a012, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a013, 0x00604411, 0x68a },
+    { 0x0000a013, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a014, 0x00604411, 0x68a },
+    { 0x0000a014, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a015, 0x00604411, 0x68a },
+    { 0x0000a015, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a016, 0x00604411, 0x68a },
+    { 0x0000a016, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a017, 0x00604411, 0x68a },
+    { 0x0000a017, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x0000002c, 0x0080062d, 0x000 },
+    { 0xff000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000002, 0x00804811, 0x000 },
+    { 0x00000000, 0x0ee00000, 0x63a },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x00000002, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x638 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x68a },
+    { 0x00001000, 0x00200811, 0x000 },
+    { 0x0000002b, 0x00203622, 0x000 },
+    { 0x00000000, 0x00600000, 0x63e },
+    { 0x00000000, 0x00600000, 0x5c6 },
+    { 0x98000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00804811, 0x000 },
+    { 0x00000000, 0xc0600000, 0x63e },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000022, 0x00204811, 0x000 },
+    { 0x89000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00404811, 0x62a },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404811, 0x62a },
+    { 0x00000000, 0x00600000, 0x659 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0xc0204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x36e },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00010000, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x09800000, 0x00204811, 0x000 },
+    { 0xffffffff, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x68a },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000004, 0x00404c11, 0x653 },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000004, 0x00291e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0xfffffffb, 0x00281e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000008, 0x00291e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0xfffffff7, 0x00281e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x36e },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00010000, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x01800000, 0x00204811, 0x000 },
+    { 0xffffffff, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004217f, 0x00604411, 0x68a },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x689 },
+    { 0x00000010, 0x00404c11, 0x66f },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x38c00000, 0x000 },
+    { 0x0000001d, 0x00200a2d, 0x000 },
+    { 0x0000001e, 0x00200e2d, 0x000 },
+    { 0x0000001f, 0x0020122d, 0x000 },
+    { 0x00000020, 0x0020162d, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000004, 0x00301224, 0x000 },
+    { 0x00000000, 0x002f0064, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x688 },
+    { 0x00000003, 0x00281a22, 0x000 },
+    { 0x00000008, 0x00221222, 0x000 },
+    { 0xfffff000, 0x00281224, 0x000 },
+    { 0x00000000, 0x002910c4, 0x000 },
+    { 0x0000001f, 0x00403624, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x1ac00000, 0x68a },
+    { 0x9f000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000000, 0x1ae00000, 0x68d },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x1ac00000, 0x68f },
+    { 0x9e000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000000, 0x1ae00000, 0x692 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00001000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001b, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0xc0204411, 0x000 },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000024, 0x0020222d, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000022, 0x0020222d, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00404811, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x014204ff, 0x05bd0250, 0x000 },
+    { 0x01c30168, 0x043f05bd, 0x000 },
+    { 0x02250209, 0x02500151, 0x000 },
+    { 0x02230245, 0x02a00241, 0x000 },
+    { 0x03d705bd, 0x05bd05bd, 0x000 },
+    { 0x06460647, 0x031f05bd, 0x000 },
+    { 0x05bd05c2, 0x03200340, 0x000 },
+    { 0x032a0282, 0x03420334, 0x000 },
+    { 0x05bd05bd, 0x05bd05bd, 0x000 },
+    { 0x05bd054e, 0x05bd05bd, 0x000 },
+    { 0x03ba05bd, 0x04b80344, 0x000 },
+    { 0x0497044d, 0x043d05bd, 0x000 },
+    { 0x04cd05bd, 0x044104da, 0x000 },
+    { 0x044d0504, 0x03510375, 0x000 },
+    { 0x05bd05bd, 0x05bd05bd, 0x000 },
+    { 0x05bd05bd, 0x05bd05bd, 0x000 },
+    { 0x05bd05bd, 0x063c05c4, 0x000 },
+    { 0x05bd05bd, 0x000705bd, 0x000 },
+    { 0x05bd05bd, 0x05bd05bd, 0x000 },
+    { 0x05bd05bd, 0x05bd05bd, 0x000 },
+    { 0x03f803ed, 0x04080406, 0x000 },
+    { 0x040e040a, 0x040c0410, 0x000 },
+    { 0x041c0418, 0x04240420, 0x000 },
+    { 0x042c0428, 0x04340430, 0x000 },
+    { 0x05bd05bd, 0x043805bd, 0x000 },
+    { 0x05bd05bd, 0x05bd05bd, 0x000 },
+    { 0x05bd05bd, 0x05bd05bd, 0x000 },
+    { 0x00020676, 0x06940006, 0x000 },
+};
+
+static const u32 RV635_pfp_microcode[] = {
+0xca0400,
+0xa00000,
+0x7e828b,
+0x7c038b,
+0x8001b8,
+0x7c038b,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xc41838,
+0xca2400,
+0xca2800,
+0x9581a8,
+0xc41c3a,
+0xc3c000,
+0xca0800,
+0xca0c00,
+0x7c744b,
+0xc20005,
+0x99c000,
+0xc41c3a,
+0x7c744c,
+0xc0fff0,
+0x042c04,
+0x309002,
+0x7d2500,
+0x351402,
+0x7d350b,
+0x255403,
+0x7cd580,
+0x259c03,
+0x95c004,
+0xd5001b,
+0x7eddc1,
+0x7d9d80,
+0xd6801b,
+0xd5801b,
+0xd4401e,
+0xd5401e,
+0xd6401e,
+0xd6801e,
+0xd4801e,
+0xd4c01e,
+0x9783d3,
+0xd5c01e,
+0xca0800,
+0x80001a,
+0xca0c00,
+0xe4011e,
+0xd4001e,
+0x80000c,
+0xc41838,
+0xe4013e,
+0xd4001e,
+0x80000c,
+0xc41838,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4013e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca1800,
+0xd4401e,
+0xd5801e,
+0x800053,
+0xd40075,
+0xd4401e,
+0xca0800,
+0xca0c00,
+0xca1000,
+0xd48019,
+0xd4c018,
+0xd50017,
+0xd4801e,
+0xd4c01e,
+0xd5001e,
+0xe2001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca0800,
+0xd48060,
+0xd4401e,
+0x800000,
+0xd4801e,
+0xca0800,
+0xd48061,
+0xd4401e,
+0x800000,
+0xd4801e,
+0xca0800,
+0xca0c00,
+0xd4401e,
+0xd48016,
+0xd4c016,
+0xd4801e,
+0x8001b8,
+0xd4c01e,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x948004,
+0xca1400,
+0xe420f3,
+0xd42013,
+0xd56065,
+0xd4e01c,
+0xd5201c,
+0xd5601c,
+0x800000,
+0x062001,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x9483f7,
+0xca1400,
+0xe420f3,
+0x800079,
+0xd42013,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x9883ef,
+0xca1400,
+0xd40064,
+0x80008d,
+0x000000,
+0xc41432,
+0xc61843,
+0xc4082f,
+0x954005,
+0xc40c30,
+0xd4401e,
+0x800000,
+0xee001e,
+0x9583f5,
+0xc41031,
+0xd44033,
+0xd52065,
+0xd4a01c,
+0xd4e01c,
+0xd5201c,
+0xe4015e,
+0xd4001e,
+0x800000,
+0x062001,
+0xca1800,
+0x0a2001,
+0xd60076,
+0xc40836,
+0x988007,
+0xc61045,
+0x950110,
+0xd4001f,
+0xd46062,
+0x800000,
+0xd42062,
+0xcc3835,
+0xcc1433,
+0x8401bb,
+0xd40072,
+0xd5401e,
+0x800000,
+0xee001e,
+0xe2001a,
+0x8401bb,
+0xe2001a,
+0xcc104b,
+0xcc0447,
+0x2c9401,
+0x7d098b,
+0x984005,
+0x7d15cb,
+0xd4001a,
+0x8001b8,
+0xd4006d,
+0x344401,
+0xcc0c48,
+0x98403a,
+0xcc2c4a,
+0x958004,
+0xcc0449,
+0x8001b8,
+0xd4001a,
+0xd4c01a,
+0x282801,
+0x8400f0,
+0xcc1003,
+0x98801b,
+0x04380c,
+0x8400f0,
+0xcc1003,
+0x988017,
+0x043808,
+0x8400f0,
+0xcc1003,
+0x988013,
+0x043804,
+0x8400f0,
+0xcc1003,
+0x988014,
+0xcc104c,
+0x9a8009,
+0xcc144d,
+0x9840dc,
+0xd4006d,
+0xcc1848,
+0xd5001a,
+0xd5401a,
+0x8000c9,
+0xd5801a,
+0x96c0d5,
+0xd4006d,
+0x8001b8,
+0xd4006e,
+0x9ac003,
+0xd4006d,
+0xd4006e,
+0x800000,
+0xec007f,
+0x9ac0cc,
+0xd4006d,
+0x8001b8,
+0xd4006e,
+0xcc1403,
+0xcc1803,
+0xcc1c03,
+0x7d9103,
+0x7dd583,
+0x7d190c,
+0x35cc1f,
+0x35701f,
+0x7cf0cb,
+0x7cd08b,
+0x880000,
+0x7e8e8b,
+0x95c004,
+0xd4006e,
+0x8001b8,
+0xd4001a,
+0xd4c01a,
+0xcc0803,
+0xcc0c03,
+0xcc1003,
+0xcc1403,
+0xcc1803,
+0xcc1c03,
+0xcc2403,
+0xcc2803,
+0x35c41f,
+0x36b01f,
+0x7c704b,
+0x34f01f,
+0x7c704b,
+0x35701f,
+0x7c704b,
+0x7d8881,
+0x7dccc1,
+0x7e5101,
+0x7e9541,
+0x7c9082,
+0x7cd4c2,
+0x7c848b,
+0x9ac003,
+0x7c8c8b,
+0x2c8801,
+0x98809e,
+0xd4006d,
+0x98409c,
+0xd4006e,
+0xcc084c,
+0xcc0c4d,
+0xcc1048,
+0xd4801a,
+0xd4c01a,
+0x800101,
+0xd5001a,
+0xcc0832,
+0xd40032,
+0x9482d9,
+0xca0c00,
+0xd4401e,
+0x800000,
+0xd4001e,
+0xe4011e,
+0xd4001e,
+0xca0800,
+0xca0c00,
+0xca1000,
+0xd4401e,
+0xca1400,
+0xd4801e,
+0xd4c01e,
+0xd5001e,
+0xd5401e,
+0xd54034,
+0x800000,
+0xee001e,
+0x280404,
+0xe2001a,
+0xe2001a,
+0xd4401a,
+0xca3800,
+0xcc0803,
+0xcc0c03,
+0xcc0c03,
+0xcc0c03,
+0x9882bd,
+0x000000,
+0x8401bb,
+0xd7a06f,
+0x800000,
+0xee001f,
+0xca0400,
+0xc2ff00,
+0xcc0834,
+0xc13fff,
+0x7c74cb,
+0x7cc90b,
+0x7d010f,
+0x9902b0,
+0x7c738b,
+0x8401bb,
+0xd7a06f,
+0x800000,
+0xee001f,
+0xca0800,
+0x281900,
+0x7d898b,
+0x958014,
+0x281404,
+0xca0c00,
+0xca1000,
+0xca1c00,
+0xca2400,
+0xe2001f,
+0xd4c01a,
+0xd5001a,
+0xd5401a,
+0xcc1803,
+0xcc2c03,
+0xcc2c03,
+0xcc2c03,
+0x7da58b,
+0x7d9c47,
+0x984297,
+0x000000,
+0x800161,
+0xd4c01a,
+0xd4401e,
+0xd4801e,
+0x800000,
+0xee001e,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4013e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca0800,
+0x248c06,
+0x0ccc06,
+0x98c006,
+0xcc104e,
+0x990004,
+0xd40073,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xd4801e,
+0x800000,
+0xee001e,
+0xca0800,
+0xca0c00,
+0x34d018,
+0x251001,
+0x950021,
+0xc17fff,
+0xca1000,
+0xca1400,
+0xca1800,
+0xd4801d,
+0xd4c01d,
+0x7db18b,
+0xc14202,
+0xc2c001,
+0xd5801d,
+0x34dc0e,
+0x7d5d4c,
+0x7f734c,
+0xd7401e,
+0xd5001e,
+0xd5401e,
+0xc14200,
+0xc2c000,
+0x099c01,
+0x31dc10,
+0x7f5f4c,
+0x7f734c,
+0x042802,
+0x7d8380,
+0xd5a86f,
+0xd58066,
+0xd7401e,
+0xec005e,
+0xc82402,
+0xc82402,
+0x8001b8,
+0xd60076,
+0xd4401e,
+0xd4801e,
+0xd4c01e,
+0x800000,
+0xee001e,
+0x800000,
+0xee001f,
+0xd4001f,
+0x800000,
+0xd4001f,
+0xd4001f,
+0x880000,
+0xd4001f,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x010171,
+0x020178,
+0x03008f,
+0x04007f,
+0x050003,
+0x06003f,
+0x070032,
+0x08012c,
+0x090046,
+0x0a0036,
+0x1001b6,
+0x1700a2,
+0x22013a,
+0x230149,
+0x2000b4,
+0x240125,
+0x27004d,
+0x28006a,
+0x2a0060,
+0x2b0052,
+0x2f0065,
+0x320087,
+0x34017f,
+0x3c0156,
+0x3f0072,
+0x41018c,
+0x44012e,
+0x550173,
+0x56017a,
+0x60000b,
+0x610034,
+0x620038,
+0x630038,
+0x640038,
+0x650038,
+0x660038,
+0x670038,
+0x68003a,
+0x690041,
+0x6a0048,
+0x6b0048,
+0x6c0048,
+0x6d0048,
+0x6e0048,
+0x6f0048,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+};
+
+static const u32 RV670_cp_microcode[][3] = {
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0000ffff, 0x00284621, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00000000, 0x00e00000, 0x000 },
+    { 0x00010000, 0xc0294620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x67c },
+    { 0x00000000, 0x00600000, 0x624 },
+    { 0x00000000, 0x00600000, 0x638 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000f00, 0x00281622, 0x000 },
+    { 0x00000008, 0x00211625, 0x000 },
+    { 0x00000018, 0x00203625, 0x000 },
+    { 0x8d000000, 0x00204411, 0x000 },
+    { 0x00000004, 0x002f0225, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x018 },
+    { 0x00412000, 0x00404811, 0x019 },
+    { 0x00422000, 0x00204811, 0x000 },
+    { 0x8e000000, 0x00204411, 0x000 },
+    { 0x00000028, 0x00204a2d, 0x000 },
+    { 0x90000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x0000000c, 0x00211622, 0x000 },
+    { 0x00000003, 0x00281625, 0x000 },
+    { 0x00000019, 0x00211a22, 0x000 },
+    { 0x00000004, 0x00281a26, 0x000 },
+    { 0x00000000, 0x002914c5, 0x000 },
+    { 0x00000019, 0x00203625, 0x000 },
+    { 0x00000000, 0x003a1402, 0x000 },
+    { 0x00000016, 0x00211625, 0x000 },
+    { 0x00000003, 0x00281625, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0xfffffffc, 0x00280e23, 0x000 },
+    { 0x00000000, 0x002914a3, 0x000 },
+    { 0x00000017, 0x00203625, 0x000 },
+    { 0x00008000, 0x00280e22, 0x000 },
+    { 0x00000007, 0x00220e23, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x20000000, 0x00280e22, 0x000 },
+    { 0x00000006, 0x00210e23, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x00000000, 0x00220222, 0x000 },
+    { 0x00000000, 0x14e00000, 0x038 },
+    { 0x00000000, 0x2ee00000, 0x035 },
+    { 0x00000000, 0x2ce00000, 0x037 },
+    { 0x00000000, 0x00400e2d, 0x039 },
+    { 0x00000008, 0x00200e2d, 0x000 },
+    { 0x00000009, 0x0040122d, 0x046 },
+    { 0x00000001, 0x00400e2d, 0x039 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x003ffffc, 0x00281223, 0x000 },
+    { 0x00000002, 0x00221224, 0x000 },
+    { 0x0000001f, 0x00211e23, 0x000 },
+    { 0x00000000, 0x14e00000, 0x03e },
+    { 0x00000008, 0x00401c11, 0x041 },
+    { 0x0000000d, 0x00201e2d, 0x000 },
+    { 0x0000000f, 0x00281e27, 0x000 },
+    { 0x00000003, 0x00221e27, 0x000 },
+    { 0x7fc00000, 0x00281a23, 0x000 },
+    { 0x00000014, 0x00211a26, 0x000 },
+    { 0x00000001, 0x00331a26, 0x000 },
+    { 0x00000008, 0x00221a26, 0x000 },
+    { 0x00000000, 0x00290cc7, 0x000 },
+    { 0x00000027, 0x00203624, 0x000 },
+    { 0x00007f00, 0x00281221, 0x000 },
+    { 0x00001400, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x04b },
+    { 0x00000001, 0x00290e23, 0x000 },
+    { 0x0000000e, 0x00203623, 0x000 },
+    { 0x0000e000, 0x00204411, 0x000 },
+    { 0xfff80000, 0x00294a23, 0x000 },
+    { 0x00000000, 0x003a2c02, 0x000 },
+    { 0x00000002, 0x00220e2b, 0x000 },
+    { 0xfc000000, 0x00280e23, 0x000 },
+    { 0x0000000f, 0x00203623, 0x000 },
+    { 0x00001fff, 0x00294a23, 0x000 },
+    { 0x00000027, 0x00204a2d, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000029, 0x00200e2d, 0x000 },
+    { 0x060a0200, 0x00294a23, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00210222, 0x000 },
+    { 0x00000000, 0x14e00000, 0x061 },
+    { 0x00000000, 0x2ee00000, 0x05f },
+    { 0x00000000, 0x2ce00000, 0x05e },
+    { 0x00000000, 0x00400e2d, 0x062 },
+    { 0x00000001, 0x00400e2d, 0x062 },
+    { 0x0000000a, 0x00200e2d, 0x000 },
+    { 0x0000000b, 0x0040122d, 0x06a },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x003ffffc, 0x00281223, 0x000 },
+    { 0x00000002, 0x00221224, 0x000 },
+    { 0x7fc00000, 0x00281623, 0x000 },
+    { 0x00000014, 0x00211625, 0x000 },
+    { 0x00000001, 0x00331625, 0x000 },
+    { 0x80000000, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00290ca3, 0x000 },
+    { 0x3ffffc00, 0x00290e23, 0x000 },
+    { 0x0000001f, 0x00211e23, 0x000 },
+    { 0x00000000, 0x14e00000, 0x06d },
+    { 0x00000100, 0x00401c11, 0x070 },
+    { 0x0000000d, 0x00201e2d, 0x000 },
+    { 0x000000f0, 0x00281e27, 0x000 },
+    { 0x00000004, 0x00221e27, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000d, 0x00204811, 0x000 },
+    { 0xfffff0ff, 0x00281a30, 0x000 },
+    { 0x0000a028, 0x00204411, 0x000 },
+    { 0x00000000, 0x002948e6, 0x000 },
+    { 0x0000a018, 0x00204411, 0x000 },
+    { 0x3fffffff, 0x00284a23, 0x000 },
+    { 0x0000a010, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000030, 0x0020162d, 0x000 },
+    { 0x00000002, 0x00291625, 0x000 },
+    { 0x00000030, 0x00203625, 0x000 },
+    { 0x00000025, 0x0020162d, 0x000 },
+    { 0x00000000, 0x002f00a3, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x083 },
+    { 0x00000026, 0x0020162d, 0x000 },
+    { 0x00000000, 0x002f00a4, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x084 },
+    { 0x00000000, 0x00400000, 0x08a },
+    { 0x00000025, 0x00203623, 0x000 },
+    { 0x00000026, 0x00203624, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x08a },
+    { 0x00000000, 0x00600000, 0x659 },
+    { 0x00000000, 0x00600000, 0x64d },
+    { 0x00000002, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x08d },
+    { 0x00000012, 0xc0403620, 0x093 },
+    { 0x00000000, 0x2ee00000, 0x091 },
+    { 0x00000000, 0x2ce00000, 0x090 },
+    { 0x00000002, 0x00400e2d, 0x092 },
+    { 0x00000003, 0x00400e2d, 0x092 },
+    { 0x0000000c, 0x00200e2d, 0x000 },
+    { 0x00000012, 0x00203623, 0x000 },
+    { 0x00000003, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x098 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x0a0 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x2ee00000, 0x09e },
+    { 0x00000000, 0x2ce00000, 0x09d },
+    { 0x00000002, 0x00400e2d, 0x09f },
+    { 0x00000003, 0x00400e2d, 0x09f },
+    { 0x0000000c, 0x00200e2d, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000000, 0x003a0c02, 0x000 },
+    { 0x003f0000, 0x00280e23, 0x000 },
+    { 0x00000010, 0x00210e23, 0x000 },
+    { 0x00000011, 0x00203623, 0x000 },
+    { 0x0000001e, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0a7 },
+    { 0x00000016, 0xc0203620, 0x000 },
+    { 0x0000001f, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0aa },
+    { 0x00000015, 0xc0203620, 0x000 },
+    { 0x00000008, 0x00210e2b, 0x000 },
+    { 0x0000007f, 0x00280e23, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0e1 },
+    { 0x00000000, 0x27000000, 0x000 },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x0b3 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x0000000c, 0x00221e30, 0x000 },
+    { 0x99800000, 0x00204411, 0x000 },
+    { 0x00000004, 0x0020122d, 0x000 },
+    { 0x00000008, 0x00221224, 0x000 },
+    { 0x00000010, 0x00201811, 0x000 },
+    { 0x00000000, 0x00291ce4, 0x000 },
+    { 0x00000000, 0x00604807, 0x12f },
+    { 0x9b000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x9c000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x0033146f, 0x000 },
+    { 0x00000001, 0x00333e23, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0x00203c05, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x00000000, 0x00201010, 0x000 },
+    { 0x0000e007, 0x00204411, 0x000 },
+    { 0x0000000f, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0cb },
+    { 0x00f8ff08, 0x00204811, 0x000 },
+    { 0x98000000, 0x00404811, 0x0dc },
+    { 0x000000f0, 0x00280e22, 0x000 },
+    { 0x000000a0, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x0da },
+    { 0x00000011, 0x00200e2d, 0x000 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0d5 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0d4 },
+    { 0x00003f00, 0x00400c11, 0x0d6 },
+    { 0x00001f00, 0x00400c11, 0x0d6 },
+    { 0x00000f00, 0x00200c11, 0x000 },
+    { 0x00380009, 0x00294a23, 0x000 },
+    { 0x3f000000, 0x00280e2b, 0x000 },
+    { 0x00000002, 0x00220e23, 0x000 },
+    { 0x00000007, 0x00494a23, 0x0dc },
+    { 0x00380f09, 0x00204811, 0x000 },
+    { 0x68000007, 0x00204811, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a24, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000a202, 0x00204411, 0x000 },
+    { 0x00ff0000, 0x00280e22, 0x000 },
+    { 0x00000080, 0x00294a23, 0x000 },
+    { 0x00000027, 0x00200e2d, 0x000 },
+    { 0x00000026, 0x0020122d, 0x000 },
+    { 0x00000000, 0x002f0083, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0ea },
+    { 0x00000000, 0x00600000, 0x653 },
+    { 0x00000000, 0x00400000, 0x0eb },
+    { 0x00000000, 0x00600000, 0x656 },
+    { 0x00000007, 0x0020222d, 0x000 },
+    { 0x00000005, 0x00220e22, 0x000 },
+    { 0x00100000, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00292068, 0x000 },
+    { 0x00000000, 0x003a0c02, 0x000 },
+    { 0x000000ef, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00292068, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0x00000003, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x0f8 },
+    { 0x0000000b, 0x00210228, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0f8 },
+    { 0x00000400, 0x00292228, 0x000 },
+    { 0x00000014, 0x00203628, 0x000 },
+    { 0x0000001c, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0fd },
+    { 0x0000a30c, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000001e, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x10b },
+    { 0x0000a30f, 0x00204411, 0x000 },
+    { 0x00000011, 0x00200e2d, 0x000 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x104 },
+    { 0xffffffff, 0x00404811, 0x10b },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x107 },
+    { 0x0000ffff, 0x00404811, 0x10b },
+    { 0x00000004, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x10a },
+    { 0x000000ff, 0x00404811, 0x10b },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0002c400, 0x00204411, 0x000 },
+    { 0x0000001f, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x112 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x00000013, 0x00203623, 0x000 },
+    { 0x00000018, 0x40224a20, 0x000 },
+    { 0x00000010, 0xc0424a20, 0x114 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x00000013, 0x00203623, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000000a, 0x00201011, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x11b },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00531224, 0x117 },
+    { 0xffbfffff, 0x00283a2e, 0x000 },
+    { 0x0000001b, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x12e },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000d, 0x00204811, 0x000 },
+    { 0x00000018, 0x00220e30, 0x000 },
+    { 0xfc000000, 0x00280e23, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x00000000, 0x00201010, 0x000 },
+    { 0x0000e00e, 0x00204411, 0x000 },
+    { 0x07f8ff08, 0x00204811, 0x000 },
+    { 0x00000000, 0x00294a23, 0x000 },
+    { 0x0000001c, 0x00201e2d, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a24, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x00800000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204806, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x67c },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x67b },
+    { 0x00000004, 0x00404c11, 0x135 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x0000001c, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x67c },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x13c },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00000000, 0x00600000, 0x160 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000ffff, 0x40280620, 0x000 },
+    { 0x00000010, 0xc0210a20, 0x000 },
+    { 0x00000000, 0x00341461, 0x000 },
+    { 0x00000000, 0x00741882, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x147 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x160 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x00000010, 0x40211620, 0x000 },
+    { 0x0000ffff, 0xc0681a20, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x158 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000001, 0x00300a2f, 0x000 },
+    { 0x00000001, 0x00210a22, 0x000 },
+    { 0x00000003, 0x00384a22, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001a, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600000, 0x18f },
+    { 0x00000000, 0x00600000, 0x1a0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00202c08, 0x000 },
+    { 0x00000000, 0x00202411, 0x000 },
+    { 0x00000000, 0x00202811, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000002, 0x00221e29, 0x000 },
+    { 0x00000000, 0x007048eb, 0x19c },
+    { 0x00000000, 0x00600000, 0x2bb },
+    { 0x00000001, 0x40330620, 0x000 },
+    { 0x00000000, 0xc0302409, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x181 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x00000000, 0x00400000, 0x186 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x186 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000001, 0x00530621, 0x182 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0604800, 0x197 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000011, 0x0020062d, 0x000 },
+    { 0x00000000, 0x0078042a, 0x2fb },
+    { 0x00000000, 0x00202809, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x174 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000210, 0x00600411, 0x315 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x194 },
+    { 0x00000015, 0xc0203620, 0x000 },
+    { 0x00000016, 0xc0203620, 0x000 },
+    { 0x3f800000, 0x00200411, 0x000 },
+    { 0x46000000, 0x00600811, 0x1b2 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x19b },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000021, 0x00804811, 0x000 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000ffff, 0x40281620, 0x000 },
+    { 0x00000010, 0xc0811a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000008, 0x00221e30, 0x000 },
+    { 0x00000029, 0x00201a2d, 0x000 },
+    { 0x0000e000, 0x00204411, 0x000 },
+    { 0xfffbff09, 0x00204811, 0x000 },
+    { 0x0000000f, 0x0020222d, 0x000 },
+    { 0x00001fff, 0x00294a28, 0x000 },
+    { 0x00000006, 0x0020222d, 0x000 },
+    { 0x00000000, 0x002920e8, 0x000 },
+    { 0x00000000, 0x00204808, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a26, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000100, 0x00201811, 0x000 },
+    { 0x00000008, 0x00621e28, 0x12f },
+    { 0x00000008, 0x00822228, 0x000 },
+    { 0x0002c000, 0x00204411, 0x000 },
+    { 0x00000015, 0x00600e2d, 0x1bd },
+    { 0x00000016, 0x00600e2d, 0x1bd },
+    { 0x0000c008, 0x00204411, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0x00000000, 0x14c00000, 0x1b9 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0x39000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00804802, 0x000 },
+    { 0x00000018, 0x00202e2d, 0x000 },
+    { 0x00000000, 0x003b0d63, 0x000 },
+    { 0x00000008, 0x00224a23, 0x000 },
+    { 0x00000010, 0x00224a23, 0x000 },
+    { 0x00000018, 0x00224a23, 0x000 },
+    { 0x00000000, 0x00804803, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00001000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00000007, 0x0021062f, 0x000 },
+    { 0x00000013, 0x00200a2d, 0x000 },
+    { 0x00000001, 0x00202c11, 0x000 },
+    { 0x0000ffff, 0x40282220, 0x000 },
+    { 0x0000000f, 0x00262228, 0x000 },
+    { 0x00000010, 0x40212620, 0x000 },
+    { 0x0000000f, 0x00262629, 0x000 },
+    { 0x00000000, 0x00202802, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001b, 0x00204811, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1e0 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000081, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000080, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f0227, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1dc },
+    { 0x00000000, 0x00600000, 0x1e9 },
+    { 0x00000001, 0x00531e27, 0x1d8 },
+    { 0x00000001, 0x00202c11, 0x000 },
+    { 0x0000001f, 0x00280a22, 0x000 },
+    { 0x0000001f, 0x00282a2a, 0x000 },
+    { 0x00000001, 0x00530621, 0x1d1 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000002, 0x00304a2f, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000001, 0x00301e2f, 0x000 },
+    { 0x00000000, 0x002f0227, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x1e9 },
+    { 0x00000001, 0x00531e27, 0x1e5 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x0000000f, 0x00260e23, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000000f, 0x00261224, 0x000 },
+    { 0x00000000, 0x00201411, 0x000 },
+    { 0x00000000, 0x00601811, 0x2bb },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022b, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1f8 },
+    { 0x00000010, 0x00221628, 0x000 },
+    { 0xffff0000, 0x00281625, 0x000 },
+    { 0x0000ffff, 0x00281a29, 0x000 },
+    { 0x00000000, 0x002948c5, 0x000 },
+    { 0x00000000, 0x0020480a, 0x000 },
+    { 0x00000000, 0x00202c11, 0x000 },
+    { 0x00000010, 0x00221623, 0x000 },
+    { 0xffff0000, 0x00281625, 0x000 },
+    { 0x0000ffff, 0x00281a24, 0x000 },
+    { 0x00000000, 0x002948c5, 0x000 },
+    { 0x00000000, 0x00731503, 0x205 },
+    { 0x00000000, 0x00201805, 0x000 },
+    { 0x00000000, 0x00731524, 0x205 },
+    { 0x00000000, 0x002d14c5, 0x000 },
+    { 0x00000000, 0x003008a2, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00202802, 0x000 },
+    { 0x00000000, 0x00202003, 0x000 },
+    { 0x00000000, 0x00802404, 0x000 },
+    { 0x0000000f, 0x00210225, 0x000 },
+    { 0x00000000, 0x14c00000, 0x67b },
+    { 0x00000000, 0x002b1405, 0x000 },
+    { 0x00000001, 0x00901625, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001a, 0x00294a22, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00384a21, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000ffff, 0x40281220, 0x000 },
+    { 0x00000010, 0xc0211a20, 0x000 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211620, 0x000 },
+    { 0x00000000, 0x00741465, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00000001, 0x00330621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x219 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x212 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x638 },
+    { 0x00000000, 0x0040040f, 0x213 },
+    { 0x00000000, 0x00600000, 0x624 },
+    { 0x00000000, 0x00600000, 0x638 },
+    { 0x00000210, 0x00600411, 0x315 },
+    { 0x00000000, 0x00600000, 0x1a0 },
+    { 0x00000000, 0x00600000, 0x19c },
+    { 0x00000000, 0x00600000, 0x2bb },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204808, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x232 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x00000000, 0x00400000, 0x236 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x236 },
+    { 0x00000000, 0xc0404800, 0x233 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x00600411, 0x2fb },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x624 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000018, 0x40210a20, 0x000 },
+    { 0x00000003, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x24c },
+    { 0x00000014, 0x0020222d, 0x000 },
+    { 0x00080101, 0x00292228, 0x000 },
+    { 0x00000014, 0x00203628, 0x000 },
+    { 0x0000a30c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x251 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000010, 0x00600411, 0x315 },
+    { 0x3f800000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x00000000, 0x00600000, 0x27c },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000001, 0x00211e27, 0x000 },
+    { 0x00000000, 0x14e00000, 0x26a },
+    { 0x00000012, 0x00201e2d, 0x000 },
+    { 0x0000ffff, 0x00281e27, 0x000 },
+    { 0x00000000, 0x00341c27, 0x000 },
+    { 0x00000000, 0x12c00000, 0x25f },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f00e5, 0x000 },
+    { 0x00000000, 0x08c00000, 0x262 },
+    { 0x00000000, 0x00201407, 0x000 },
+    { 0x00000012, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00211e27, 0x000 },
+    { 0x00000000, 0x00341c47, 0x000 },
+    { 0x00000000, 0x12c00000, 0x267 },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f00e6, 0x000 },
+    { 0x00000000, 0x08c00000, 0x26a },
+    { 0x00000000, 0x00201807, 0x000 },
+    { 0x00000000, 0x00600000, 0x2c1 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000000, 0x00342023, 0x000 },
+    { 0x00000000, 0x12c00000, 0x272 },
+    { 0x00000000, 0x00342044, 0x000 },
+    { 0x00000000, 0x12c00000, 0x271 },
+    { 0x00000016, 0x00404811, 0x276 },
+    { 0x00000018, 0x00404811, 0x276 },
+    { 0x00000000, 0x00342044, 0x000 },
+    { 0x00000000, 0x12c00000, 0x275 },
+    { 0x00000017, 0x00404811, 0x276 },
+    { 0x00000019, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0x00604411, 0x2e9 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x256 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000010, 0x40210620, 0x000 },
+    { 0x0000ffff, 0xc0280a20, 0x000 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x00000010, 0x40211620, 0x000 },
+    { 0x0000ffff, 0xc0881a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x67c },
+    { 0x00000000, 0x00600000, 0x624 },
+    { 0x00000000, 0xc0600000, 0x2a3 },
+    { 0x00000005, 0x00200a2d, 0x000 },
+    { 0x00000008, 0x00220a22, 0x000 },
+    { 0x0000002b, 0x00201a2d, 0x000 },
+    { 0x0000001c, 0x00201e2d, 0x000 },
+    { 0x00007000, 0x00281e27, 0x000 },
+    { 0x00000000, 0x00311ce6, 0x000 },
+    { 0x0000002a, 0x00201a2d, 0x000 },
+    { 0x0000000c, 0x00221a26, 0x000 },
+    { 0x00000000, 0x002f00e6, 0x000 },
+    { 0x00000000, 0x06e00000, 0x292 },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x0000002b, 0x00203623, 0x000 },
+    { 0x00000010, 0x00201811, 0x000 },
+    { 0x00000000, 0x00691ce2, 0x12f },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x29d },
+    { 0x00000001, 0x00333e2f, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000001c, 0x00403627, 0x000 },
+    { 0x0000000c, 0xc0220a20, 0x000 },
+    { 0x00000029, 0x00203622, 0x000 },
+    { 0x00000028, 0xc0403620, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000009, 0x00204811, 0x000 },
+    { 0xa1000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002c1ce3, 0x000 },
+    { 0x00000021, 0x00203627, 0x000 },
+    { 0x00000022, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002c1ce4, 0x000 },
+    { 0x00000022, 0x00203627, 0x000 },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120a3, 0x000 },
+    { 0x00000000, 0x002d1d07, 0x000 },
+    { 0x00000023, 0x00203627, 0x000 },
+    { 0x00000024, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x00000000, 0x002d1d07, 0x000 },
+    { 0x00000024, 0x00803627, 0x000 },
+    { 0x00000021, 0x00203623, 0x000 },
+    { 0x00000022, 0x00203624, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000023, 0x00203627, 0x000 },
+    { 0x00000000, 0x00311cc4, 0x000 },
+    { 0x00000024, 0x00803627, 0x000 },
+    { 0x0000001a, 0x00203627, 0x000 },
+    { 0x0000001b, 0x00203628, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14c00000, 0x2dc },
+    { 0x00000000, 0x00400000, 0x2d9 },
+    { 0x0000001a, 0x00203627, 0x000 },
+    { 0x0000001b, 0x00203628, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x2d9 },
+    { 0x00000003, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x2dc },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002e00e1, 0x000 },
+    { 0x00000000, 0x02c00000, 0x2dc },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120a1, 0x000 },
+    { 0x00000000, 0x002e00e8, 0x000 },
+    { 0x00000000, 0x06c00000, 0x2dc },
+    { 0x00000024, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002e00e2, 0x000 },
+    { 0x00000000, 0x02c00000, 0x2dc },
+    { 0x00000022, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120c2, 0x000 },
+    { 0x00000000, 0x002e00e8, 0x000 },
+    { 0x00000000, 0x06c00000, 0x2dc },
+    { 0x00000000, 0x00600000, 0x659 },
+    { 0x00000000, 0x00600000, 0x2b5 },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x00000000, 0x00600000, 0x2b5 },
+    { 0x00000000, 0x00600000, 0x650 },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x00000000, 0x00600000, 0x2a7 },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x0000001a, 0x00201e2d, 0x000 },
+    { 0x0000001b, 0x0080222d, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000010, 0x00221e21, 0x000 },
+    { 0x00000000, 0x00294847, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000000, 0x00311ca1, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294847, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000010, 0x00221e21, 0x000 },
+    { 0x00000000, 0x003120c2, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000001, 0x00220a21, 0x000 },
+    { 0x00000000, 0x003308a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000001, 0x00220a21, 0x000 },
+    { 0x00000000, 0x003008a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x003808c5, 0x000 },
+    { 0x00000000, 0x00300841, 0x000 },
+    { 0x00000001, 0x00220a22, 0x000 },
+    { 0x00000000, 0x003308a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000017, 0x0020222d, 0x000 },
+    { 0x00000000, 0x14c00000, 0x318 },
+    { 0xffffffef, 0x00280621, 0x000 },
+    { 0x00000014, 0x0020222d, 0x000 },
+    { 0x0000f8e0, 0x00204411, 0x000 },
+    { 0x00000000, 0x00294901, 0x000 },
+    { 0x00000000, 0x00894901, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00804811, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x97000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0xc0204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00002257, 0x00204411, 0x000 },
+    { 0x00000003, 0xc0484a20, 0x000 },
+    { 0x0000225d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0x00600000, 0x638 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00384a22, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x40204800, 0x000 },
+    { 0x00000001, 0x40304a20, 0x000 },
+    { 0x00000002, 0xc0304a20, 0x000 },
+    { 0x00000001, 0x00530a22, 0x34b },
+    { 0x0000003f, 0xc0280a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000018, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x67c },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x354 },
+    { 0x00000014, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x362 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00604802, 0x36a },
+    { 0x00002100, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000004, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x366 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x35d },
+    { 0x00000028, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5b3 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x35d },
+    { 0x0000002c, 0x00203626, 0x000 },
+    { 0x00000049, 0x00201811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x00000001, 0x00331a26, 0x000 },
+    { 0x00000000, 0x002f0226, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x36c },
+    { 0x0000002c, 0x00801a2d, 0x000 },
+    { 0x0000003f, 0xc0280a20, 0x000 },
+    { 0x00000015, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x382 },
+    { 0x00000006, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3ad },
+    { 0x00000016, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3af },
+    { 0x00000020, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x398 },
+    { 0x0000000f, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3a4 },
+    { 0x00000010, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3a4 },
+    { 0x0000001e, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x38c },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x08000000, 0x00290a22, 0x000 },
+    { 0x00000003, 0x40210e20, 0x000 },
+    { 0x0000000c, 0xc0211220, 0x000 },
+    { 0x00080000, 0x00281224, 0x000 },
+    { 0x00000014, 0xc0221620, 0x000 },
+    { 0x00000000, 0x002914a4, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x002948a2, 0x000 },
+    { 0x0000a1fe, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404803, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x67c },
+    { 0x00000015, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x38e },
+    { 0x0000210e, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000017, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x67c },
+    { 0x00000003, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x39a },
+    { 0x00002108, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x80000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000010, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3aa },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000006, 0x00404811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x36a },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x0000001d, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x3c4 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000018, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x67c },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x3b8 },
+    { 0x00002100, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0xbabecafe, 0x00204811, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000004, 0x00404811, 0x000 },
+    { 0x00002170, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000a, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3c9 },
+    { 0x8c000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00003fff, 0x40280a20, 0x000 },
+    { 0x80000000, 0x40280e20, 0x000 },
+    { 0x40000000, 0xc0281220, 0x000 },
+    { 0x00040000, 0x00694622, 0x67c },
+    { 0x00000000, 0x00201410, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x3d7 },
+    { 0x00000000, 0xc0401800, 0x3da },
+    { 0x00003fff, 0xc0281a20, 0x000 },
+    { 0x00040000, 0x00694626, 0x67c },
+    { 0x00000000, 0x00201810, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x3dd },
+    { 0x00000000, 0xc0401c00, 0x3e0 },
+    { 0x00003fff, 0xc0281e20, 0x000 },
+    { 0x00040000, 0x00694627, 0x67c },
+    { 0x00000000, 0x00201c10, 0x000 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0x002820c5, 0x000 },
+    { 0x00000000, 0x004948e8, 0x000 },
+    { 0xa5800000, 0x00200811, 0x000 },
+    { 0x00002000, 0x00200c11, 0x000 },
+    { 0x83000000, 0x00604411, 0x408 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x40204800, 0x000 },
+    { 0x0000001f, 0xc0210220, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3ed },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0000ffff, 0xc0481220, 0x3f5 },
+    { 0xa7800000, 0x00200811, 0x000 },
+    { 0x0000a000, 0x00200c11, 0x000 },
+    { 0x83000000, 0x00604411, 0x408 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x83000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00304883, 0x000 },
+    { 0x84000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x1d000000, 0x000 },
+    { 0x83000000, 0x00604411, 0x408 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0xa9800000, 0x00200811, 0x000 },
+    { 0x0000c000, 0x00400c11, 0x3f0 },
+    { 0xab800000, 0x00200811, 0x000 },
+    { 0x0000f8e0, 0x00400c11, 0x3f0 },
+    { 0xad800000, 0x00200811, 0x000 },
+    { 0x0000f880, 0x00400c11, 0x3f0 },
+    { 0xb3800000, 0x00200811, 0x000 },
+    { 0x0000f3fc, 0x00400c11, 0x3f0 },
+    { 0xaf800000, 0x00200811, 0x000 },
+    { 0x0000e000, 0x00400c11, 0x3f0 },
+    { 0xb1800000, 0x00200811, 0x000 },
+    { 0x0000f000, 0x00400c11, 0x3f0 },
+    { 0x83000000, 0x00204411, 0x000 },
+    { 0x00002148, 0x00204811, 0x000 },
+    { 0x84000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x1d000000, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x01182000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0218a000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0318c000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0418f8e0, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0518f880, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0618e000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0718f000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0818f3fc, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00000030, 0x00200a2d, 0x000 },
+    { 0x00000000, 0xc0290c40, 0x000 },
+    { 0x00000030, 0x00203623, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x86000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404801, 0x000 },
+    { 0x85000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0x00404801, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x67c },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000000, 0x00404c02, 0x43e },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x00000000, 0xc0201000, 0x000 },
+    { 0x00000000, 0xc0201400, 0x000 },
+    { 0x00000000, 0xc0201800, 0x000 },
+    { 0x00000000, 0xc0201c00, 0x000 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x44c },
+    { 0x00000000, 0xc0202000, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x00000010, 0x00280a23, 0x000 },
+    { 0x00000010, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x454 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00040000, 0x00694624, 0x67c },
+    { 0x00000000, 0x00400000, 0x459 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000000, 0x00604805, 0x681 },
+    { 0x00000000, 0x002824f0, 0x000 },
+    { 0x00000007, 0x00280a23, 0x000 },
+    { 0x00000001, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x460 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x04e00000, 0x479 },
+    { 0x00000000, 0x00400000, 0x486 },
+    { 0x00000002, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x465 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x02e00000, 0x479 },
+    { 0x00000000, 0x00400000, 0x486 },
+    { 0x00000003, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x46a },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x479 },
+    { 0x00000000, 0x00400000, 0x486 },
+    { 0x00000004, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x46f },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x479 },
+    { 0x00000000, 0x00400000, 0x486 },
+    { 0x00000005, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x474 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x06e00000, 0x479 },
+    { 0x00000000, 0x00400000, 0x486 },
+    { 0x00000006, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x479 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x08e00000, 0x479 },
+    { 0x00000000, 0x00400000, 0x486 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x000 },
+    { 0x00000008, 0x00210a23, 0x000 },
+    { 0x00000000, 0x14c00000, 0x483 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x00000000, 0xc0204400, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x48c },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0400000, 0x000 },
+    { 0x00000000, 0x00404c08, 0x44c },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x00000011, 0x40211220, 0x000 },
+    { 0x00000012, 0x40211620, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00210225, 0x000 },
+    { 0x00000000, 0x14e00000, 0x496 },
+    { 0x00040000, 0xc0494a20, 0x497 },
+    { 0xfffbffff, 0xc0284a20, 0x000 },
+    { 0x00000000, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x4a3 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x00210224, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000c, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x49f },
+    { 0xa0000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000004, 0x00204811, 0x000 },
+    { 0x0000216b, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204810, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000005, 0x00204811, 0x000 },
+    { 0x0000216c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204810, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00400000, 0x49d },
+    { 0x00000000, 0xc0210a20, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4b6 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0604800, 0x681 },
+    { 0x00000000, 0x00400000, 0x4ba },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00040000, 0xc0294620, 0x000 },
+    { 0x00000000, 0xc0600000, 0x67c },
+    { 0x00000001, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4c1 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x00000000, 0xc0204400, 0x000 },
+    { 0x00000000, 0xc0404810, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x67c },
+    { 0x00000000, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4c3 },
+    { 0x00002180, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000003, 0x00333e2f, 0x000 },
+    { 0x00000001, 0x00210221, 0x000 },
+    { 0x00000000, 0x14e00000, 0x4f3 },
+    { 0x0000002c, 0x00200a2d, 0x000 },
+    { 0x00040000, 0x18e00c11, 0x4e2 },
+    { 0x00000001, 0x00333e2f, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xd8c04800, 0x4d6 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000002d, 0x0020122d, 0x000 },
+    { 0x00000000, 0x00290c83, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000011, 0x00210224, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000000, 0x00400000, 0x49d },
+    { 0x0000002c, 0xc0203620, 0x000 },
+    { 0x0000002d, 0xc0403620, 0x000 },
+    { 0x0000000f, 0x00210221, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4f8 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0xd9000000, 0x000 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0xb5000000, 0x00204411, 0x000 },
+    { 0x00002000, 0x00204811, 0x000 },
+    { 0xb6000000, 0x00204411, 0x000 },
+    { 0x0000a000, 0x00204811, 0x000 },
+    { 0xb7000000, 0x00204411, 0x000 },
+    { 0x0000c000, 0x00204811, 0x000 },
+    { 0xb8000000, 0x00204411, 0x000 },
+    { 0x0000f8e0, 0x00204811, 0x000 },
+    { 0xb9000000, 0x00204411, 0x000 },
+    { 0x0000f880, 0x00204811, 0x000 },
+    { 0xba000000, 0x00204411, 0x000 },
+    { 0x0000e000, 0x00204811, 0x000 },
+    { 0xbb000000, 0x00204411, 0x000 },
+    { 0x0000f000, 0x00204811, 0x000 },
+    { 0xbc000000, 0x00204411, 0x000 },
+    { 0x0000f3fc, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000002, 0x00204811, 0x000 },
+    { 0x000000ff, 0x00280e30, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x50c },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0x14c00000, 0x521 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x0000001c, 0x00203623, 0x000 },
+    { 0x0000002b, 0x00203623, 0x000 },
+    { 0x00000029, 0x00203623, 0x000 },
+    { 0x00000028, 0x00203623, 0x000 },
+    { 0x00000017, 0x00203623, 0x000 },
+    { 0x00000025, 0x00203623, 0x000 },
+    { 0x00000026, 0x00203623, 0x000 },
+    { 0x00000015, 0x00203623, 0x000 },
+    { 0x00000016, 0x00203623, 0x000 },
+    { 0xffffe000, 0x00200c11, 0x000 },
+    { 0x00000021, 0x00203623, 0x000 },
+    { 0x00000022, 0x00203623, 0x000 },
+    { 0x00001fff, 0x00200c11, 0x000 },
+    { 0x00000023, 0x00203623, 0x000 },
+    { 0x00000024, 0x00203623, 0x000 },
+    { 0xf1ffffff, 0x00283a2e, 0x000 },
+    { 0x0000001a, 0xc0220e20, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x0000002a, 0x40203620, 0x000 },
+    { 0x87000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1f4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x00000030, 0x00203623, 0x000 },
+    { 0x9d000000, 0x00204411, 0x000 },
+    { 0x0000001f, 0x40214a20, 0x000 },
+    { 0x96000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x00000000, 0xc0201000, 0x000 },
+    { 0x0000001f, 0x00211624, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x0000001d, 0x00203623, 0x000 },
+    { 0x00000003, 0x00281e23, 0x000 },
+    { 0x00000008, 0x00222223, 0x000 },
+    { 0xfffff000, 0x00282228, 0x000 },
+    { 0x00000000, 0x002920e8, 0x000 },
+    { 0x0000001f, 0x00203628, 0x000 },
+    { 0x00000018, 0x00211e23, 0x000 },
+    { 0x00000020, 0x00203627, 0x000 },
+    { 0x00000002, 0x00221624, 0x000 },
+    { 0x00000000, 0x003014a8, 0x000 },
+    { 0x0000001e, 0x00203625, 0x000 },
+    { 0x00000003, 0x00211a24, 0x000 },
+    { 0x10000000, 0x00281a26, 0x000 },
+    { 0xefffffff, 0x00283a2e, 0x000 },
+    { 0x00000000, 0x004938ce, 0x66a },
+    { 0x00000001, 0x40280a20, 0x000 },
+    { 0x00000006, 0x40280e20, 0x000 },
+    { 0x00000300, 0xc0281220, 0x000 },
+    { 0x00000008, 0x00211224, 0x000 },
+    { 0x00000000, 0xc0201620, 0x000 },
+    { 0x00000000, 0xc0201a20, 0x000 },
+    { 0x00000000, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x559 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00002258, 0x00300a24, 0x000 },
+    { 0x00040000, 0x00694622, 0x67c },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x00020000, 0x00294a26, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x561 },
+    { 0x00000000, 0xc0201c10, 0x000 },
+    { 0x00000000, 0xc0400000, 0x56f },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x561 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00002258, 0x00300a24, 0x000 },
+    { 0x00040000, 0x00694622, 0x67c },
+    { 0x00000000, 0xc0201c10, 0x000 },
+    { 0x00000000, 0xc0400000, 0x56f },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x565 },
+    { 0x00000000, 0xc0201c00, 0x000 },
+    { 0x00000000, 0xc0400000, 0x56f },
+    { 0x00000004, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x56d },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0604800, 0x681 },
+    { 0x00000000, 0x00401c10, 0x56f },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0400000, 0x000 },
+    { 0x00000000, 0x0ee00000, 0x571 },
+    { 0x00000000, 0x00600000, 0x5bc },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x582 },
+    { 0x0000a2b7, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2b6, 0x00604411, 0x67c },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x67c },
+    { 0x0000a2c4, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x580 },
+    { 0x0000a2d1, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d1, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x00000001, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x593 },
+    { 0x0000a2bb, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2ba, 0x00604411, 0x67c },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x67c },
+    { 0x0000a2c5, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x591 },
+    { 0x0000a2d2, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d2, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x00000002, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5a4 },
+    { 0x0000a2bf, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2be, 0x00604411, 0x67c },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x67c },
+    { 0x0000a2c6, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x5a2 },
+    { 0x0000a2d3, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d3, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x0000a2c3, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a2c2, 0x00604411, 0x67c },
+    { 0x0000001a, 0x00212230, 0x000 },
+    { 0x00000006, 0x00222630, 0x000 },
+    { 0x00042004, 0x00604411, 0x67c },
+    { 0x0000a2c7, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x5b1 },
+    { 0x0000a2d4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d4, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x85000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0x0000304a, 0x00204411, 0x000 },
+    { 0x01000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00400000, 0x5b7 },
+    { 0xa4000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0xc0600000, 0x5bc },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000002c, 0x00203621, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000000, 0x002f0230, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5c3 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000030, 0x00403621, 0x5d6 },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x00007e00, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x5d6 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004a092, 0x00604411, 0x67c },
+    { 0x00000031, 0x00203630, 0x000 },
+    { 0x0004a093, 0x00604411, 0x67c },
+    { 0x00000032, 0x00203630, 0x000 },
+    { 0x0004a2b6, 0x00604411, 0x67c },
+    { 0x00000033, 0x00203630, 0x000 },
+    { 0x0004a2ba, 0x00604411, 0x67c },
+    { 0x00000034, 0x00203630, 0x000 },
+    { 0x0004a2be, 0x00604411, 0x67c },
+    { 0x00000035, 0x00203630, 0x000 },
+    { 0x0004a2c2, 0x00604411, 0x67c },
+    { 0x00000036, 0x00203630, 0x000 },
+    { 0x00042004, 0x00604411, 0x67c },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x00000005, 0x00204811, 0x000 },
+    { 0x0000a1f4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x88000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000001, 0x002f0230, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x61f },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x61f },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00007e00, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x5f8 },
+    { 0x0000a092, 0x00204411, 0x000 },
+    { 0x00000031, 0x00204a2d, 0x000 },
+    { 0x0000a093, 0x00204411, 0x000 },
+    { 0x00000032, 0x00204a2d, 0x000 },
+    { 0x0000a2b6, 0x00204411, 0x000 },
+    { 0x00000033, 0x00204a2d, 0x000 },
+    { 0x0000a2ba, 0x00204411, 0x000 },
+    { 0x00000034, 0x00204a2d, 0x000 },
+    { 0x0000a2be, 0x00204411, 0x000 },
+    { 0x00000035, 0x00204a2d, 0x000 },
+    { 0x0000a2c2, 0x00204411, 0x000 },
+    { 0x00000036, 0x00204a2d, 0x000 },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x000001ff, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x61e },
+    { 0x00000000, 0x00210221, 0x000 },
+    { 0x00000000, 0x14c00000, 0x601 },
+    { 0x0004a003, 0x00604411, 0x67c },
+    { 0x0000a003, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00000001, 0x00210621, 0x000 },
+    { 0x00000000, 0x14c00000, 0x606 },
+    { 0x0004a010, 0x00604411, 0x67c },
+    { 0x0000a010, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00000001, 0x00210621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x61e },
+    { 0x0004a011, 0x00604411, 0x67c },
+    { 0x0000a011, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a012, 0x00604411, 0x67c },
+    { 0x0000a012, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a013, 0x00604411, 0x67c },
+    { 0x0000a013, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a014, 0x00604411, 0x67c },
+    { 0x0000a014, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a015, 0x00604411, 0x67c },
+    { 0x0000a015, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a016, 0x00604411, 0x67c },
+    { 0x0000a016, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x0004a017, 0x00604411, 0x67c },
+    { 0x0000a017, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x00042004, 0x00604411, 0x67c },
+    { 0x0000002c, 0x0080062d, 0x000 },
+    { 0xff000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000002, 0x00804811, 0x000 },
+    { 0x00000000, 0x0ee00000, 0x630 },
+    { 0x00000030, 0x0020062d, 0x000 },
+    { 0x00000002, 0x00280621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x62e },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x67c },
+    { 0x00001000, 0x00200811, 0x000 },
+    { 0x0000002b, 0x00203622, 0x000 },
+    { 0x00000000, 0x00600000, 0x634 },
+    { 0x00000000, 0x00600000, 0x5bc },
+    { 0x98000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00804811, 0x000 },
+    { 0x00000000, 0xc0600000, 0x634 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000022, 0x00204811, 0x000 },
+    { 0x89000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00404811, 0x620 },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404811, 0x620 },
+    { 0x00000000, 0x00600000, 0x64d },
+    { 0x0001a2a4, 0xc0204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x36a },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00010000, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x09800000, 0x00204811, 0x000 },
+    { 0xffffffff, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x67c },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000004, 0x00404c11, 0x647 },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000004, 0x00291e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0xfffffffb, 0x00281e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000008, 0x00291e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0xfffffff7, 0x00281e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x36a },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00010000, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x01800000, 0x00204811, 0x000 },
+    { 0xffffffff, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004217f, 0x00604411, 0x67c },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x67b },
+    { 0x00000010, 0x00404c11, 0x661 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x38c00000, 0x000 },
+    { 0x0000001d, 0x00200a2d, 0x000 },
+    { 0x0000001e, 0x00200e2d, 0x000 },
+    { 0x0000001f, 0x0020122d, 0x000 },
+    { 0x00000020, 0x0020162d, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000004, 0x00301224, 0x000 },
+    { 0x00000000, 0x002f0064, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x67a },
+    { 0x00000003, 0x00281a22, 0x000 },
+    { 0x00000008, 0x00221222, 0x000 },
+    { 0xfffff000, 0x00281224, 0x000 },
+    { 0x00000000, 0x002910c4, 0x000 },
+    { 0x0000001f, 0x00403624, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x1ac00000, 0x67c },
+    { 0x9f000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000000, 0x1ae00000, 0x67f },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x1ac00000, 0x681 },
+    { 0x9e000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000000, 0x1ae00000, 0x684 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00001000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001b, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0xc0204411, 0x000 },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000024, 0x0020222d, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000022, 0x0020222d, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00404811, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x014204f5, 0x05b30250, 0x000 },
+    { 0x01c30168, 0x043505b3, 0x000 },
+    { 0x02250209, 0x02500151, 0x000 },
+    { 0x02230245, 0x02a00241, 0x000 },
+    { 0x03cd05b3, 0x05b305b3, 0x000 },
+    { 0x063c063d, 0x031f05b3, 0x000 },
+    { 0x05b305b8, 0x03200340, 0x000 },
+    { 0x032a0282, 0x03420334, 0x000 },
+    { 0x05b305b3, 0x05b305b3, 0x000 },
+    { 0x05b30544, 0x05b305b3, 0x000 },
+    { 0x03b205b3, 0x04ae0344, 0x000 },
+    { 0x048d0443, 0x043305b3, 0x000 },
+    { 0x04c305b3, 0x043704d0, 0x000 },
+    { 0x044304fa, 0x03510371, 0x000 },
+    { 0x05b305b3, 0x05b305b3, 0x000 },
+    { 0x05b305b3, 0x05b305b3, 0x000 },
+    { 0x05b305b3, 0x063205ba, 0x000 },
+    { 0x05b305b3, 0x000705b3, 0x000 },
+    { 0x05b305b3, 0x05b305b3, 0x000 },
+    { 0x05b305b3, 0x05b305b3, 0x000 },
+    { 0x03ee03e3, 0x03fe03fc, 0x000 },
+    { 0x04040400, 0x04020406, 0x000 },
+    { 0x0412040e, 0x041a0416, 0x000 },
+    { 0x0422041e, 0x042a0426, 0x000 },
+    { 0x05b305b3, 0x042e05b3, 0x000 },
+    { 0x05b305b3, 0x05b305b3, 0x000 },
+    { 0x05b305b3, 0x05b305b3, 0x000 },
+    { 0x00020668, 0x06860006, 0x000 },
+};
+
+static const u32 RV670_pfp_microcode[] = {
+0xca0400,
+0xa00000,
+0x7e828b,
+0x7c038b,
+0x8001b8,
+0x7c038b,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xc41838,
+0xca2400,
+0xca2800,
+0x9581a8,
+0xc41c3a,
+0xc3c000,
+0xca0800,
+0xca0c00,
+0x7c744b,
+0xc20005,
+0x99c000,
+0xc41c3a,
+0x7c744c,
+0xc0fff0,
+0x042c04,
+0x309002,
+0x7d2500,
+0x351402,
+0x7d350b,
+0x255403,
+0x7cd580,
+0x259c03,
+0x95c004,
+0xd5001b,
+0x7eddc1,
+0x7d9d80,
+0xd6801b,
+0xd5801b,
+0xd4401e,
+0xd5401e,
+0xd6401e,
+0xd6801e,
+0xd4801e,
+0xd4c01e,
+0x9783d3,
+0xd5c01e,
+0xca0800,
+0x80001a,
+0xca0c00,
+0xe4011e,
+0xd4001e,
+0x80000c,
+0xc41838,
+0xe4013e,
+0xd4001e,
+0x80000c,
+0xc41838,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4013e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca1800,
+0xd4401e,
+0xd5801e,
+0x800053,
+0xd40075,
+0xd4401e,
+0xca0800,
+0xca0c00,
+0xca1000,
+0xd48019,
+0xd4c018,
+0xd50017,
+0xd4801e,
+0xd4c01e,
+0xd5001e,
+0xe2001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca0800,
+0xd48060,
+0xd4401e,
+0x800000,
+0xd4801e,
+0xca0800,
+0xd48061,
+0xd4401e,
+0x800000,
+0xd4801e,
+0xca0800,
+0xca0c00,
+0xd4401e,
+0xd48016,
+0xd4c016,
+0xd4801e,
+0x8001b8,
+0xd4c01e,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x948004,
+0xca1400,
+0xe420f3,
+0xd42013,
+0xd56065,
+0xd4e01c,
+0xd5201c,
+0xd5601c,
+0x800000,
+0x062001,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x9483f7,
+0xca1400,
+0xe420f3,
+0x800079,
+0xd42013,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x9883ef,
+0xca1400,
+0xd40064,
+0x80008d,
+0x000000,
+0xc41432,
+0xc61843,
+0xc4082f,
+0x954005,
+0xc40c30,
+0xd4401e,
+0x800000,
+0xee001e,
+0x9583f5,
+0xc41031,
+0xd44033,
+0xd52065,
+0xd4a01c,
+0xd4e01c,
+0xd5201c,
+0xe4015e,
+0xd4001e,
+0x800000,
+0x062001,
+0xca1800,
+0x0a2001,
+0xd60076,
+0xc40836,
+0x988007,
+0xc61045,
+0x950110,
+0xd4001f,
+0xd46062,
+0x800000,
+0xd42062,
+0xcc3835,
+0xcc1433,
+0x8401bb,
+0xd40072,
+0xd5401e,
+0x800000,
+0xee001e,
+0xe2001a,
+0x8401bb,
+0xe2001a,
+0xcc104b,
+0xcc0447,
+0x2c9401,
+0x7d098b,
+0x984005,
+0x7d15cb,
+0xd4001a,
+0x8001b8,
+0xd4006d,
+0x344401,
+0xcc0c48,
+0x98403a,
+0xcc2c4a,
+0x958004,
+0xcc0449,
+0x8001b8,
+0xd4001a,
+0xd4c01a,
+0x282801,
+0x8400f0,
+0xcc1003,
+0x98801b,
+0x04380c,
+0x8400f0,
+0xcc1003,
+0x988017,
+0x043808,
+0x8400f0,
+0xcc1003,
+0x988013,
+0x043804,
+0x8400f0,
+0xcc1003,
+0x988014,
+0xcc104c,
+0x9a8009,
+0xcc144d,
+0x9840dc,
+0xd4006d,
+0xcc1848,
+0xd5001a,
+0xd5401a,
+0x8000c9,
+0xd5801a,
+0x96c0d5,
+0xd4006d,
+0x8001b8,
+0xd4006e,
+0x9ac003,
+0xd4006d,
+0xd4006e,
+0x800000,
+0xec007f,
+0x9ac0cc,
+0xd4006d,
+0x8001b8,
+0xd4006e,
+0xcc1403,
+0xcc1803,
+0xcc1c03,
+0x7d9103,
+0x7dd583,
+0x7d190c,
+0x35cc1f,
+0x35701f,
+0x7cf0cb,
+0x7cd08b,
+0x880000,
+0x7e8e8b,
+0x95c004,
+0xd4006e,
+0x8001b8,
+0xd4001a,
+0xd4c01a,
+0xcc0803,
+0xcc0c03,
+0xcc1003,
+0xcc1403,
+0xcc1803,
+0xcc1c03,
+0xcc2403,
+0xcc2803,
+0x35c41f,
+0x36b01f,
+0x7c704b,
+0x34f01f,
+0x7c704b,
+0x35701f,
+0x7c704b,
+0x7d8881,
+0x7dccc1,
+0x7e5101,
+0x7e9541,
+0x7c9082,
+0x7cd4c2,
+0x7c848b,
+0x9ac003,
+0x7c8c8b,
+0x2c8801,
+0x98809e,
+0xd4006d,
+0x98409c,
+0xd4006e,
+0xcc084c,
+0xcc0c4d,
+0xcc1048,
+0xd4801a,
+0xd4c01a,
+0x800101,
+0xd5001a,
+0xcc0832,
+0xd40032,
+0x9482d9,
+0xca0c00,
+0xd4401e,
+0x800000,
+0xd4001e,
+0xe4011e,
+0xd4001e,
+0xca0800,
+0xca0c00,
+0xca1000,
+0xd4401e,
+0xca1400,
+0xd4801e,
+0xd4c01e,
+0xd5001e,
+0xd5401e,
+0xd54034,
+0x800000,
+0xee001e,
+0x280404,
+0xe2001a,
+0xe2001a,
+0xd4401a,
+0xca3800,
+0xcc0803,
+0xcc0c03,
+0xcc0c03,
+0xcc0c03,
+0x9882bd,
+0x000000,
+0x8401bb,
+0xd7a06f,
+0x800000,
+0xee001f,
+0xca0400,
+0xc2ff00,
+0xcc0834,
+0xc13fff,
+0x7c74cb,
+0x7cc90b,
+0x7d010f,
+0x9902b0,
+0x7c738b,
+0x8401bb,
+0xd7a06f,
+0x800000,
+0xee001f,
+0xca0800,
+0x281900,
+0x7d898b,
+0x958014,
+0x281404,
+0xca0c00,
+0xca1000,
+0xca1c00,
+0xca2400,
+0xe2001f,
+0xd4c01a,
+0xd5001a,
+0xd5401a,
+0xcc1803,
+0xcc2c03,
+0xcc2c03,
+0xcc2c03,
+0x7da58b,
+0x7d9c47,
+0x984297,
+0x000000,
+0x800161,
+0xd4c01a,
+0xd4401e,
+0xd4801e,
+0x800000,
+0xee001e,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4013e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca0800,
+0x248c06,
+0x0ccc06,
+0x98c006,
+0xcc104e,
+0x990004,
+0xd40073,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xd4801e,
+0x800000,
+0xee001e,
+0xca0800,
+0xca0c00,
+0x34d018,
+0x251001,
+0x950021,
+0xc17fff,
+0xca1000,
+0xca1400,
+0xca1800,
+0xd4801d,
+0xd4c01d,
+0x7db18b,
+0xc14202,
+0xc2c001,
+0xd5801d,
+0x34dc0e,
+0x7d5d4c,
+0x7f734c,
+0xd7401e,
+0xd5001e,
+0xd5401e,
+0xc14200,
+0xc2c000,
+0x099c01,
+0x31dc10,
+0x7f5f4c,
+0x7f734c,
+0x042802,
+0x7d8380,
+0xd5a86f,
+0xd58066,
+0xd7401e,
+0xec005e,
+0xc82402,
+0xc82402,
+0x8001b8,
+0xd60076,
+0xd4401e,
+0xd4801e,
+0xd4c01e,
+0x800000,
+0xee001e,
+0x800000,
+0xee001f,
+0xd4001f,
+0x800000,
+0xd4001f,
+0xd4001f,
+0x880000,
+0xd4001f,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x010171,
+0x020178,
+0x03008f,
+0x04007f,
+0x050003,
+0x06003f,
+0x070032,
+0x08012c,
+0x090046,
+0x0a0036,
+0x1001b6,
+0x1700a2,
+0x22013a,
+0x230149,
+0x2000b4,
+0x240125,
+0x27004d,
+0x28006a,
+0x2a0060,
+0x2b0052,
+0x2f0065,
+0x320087,
+0x34017f,
+0x3c0156,
+0x3f0072,
+0x41018c,
+0x44012e,
+0x550173,
+0x56017a,
+0x60000b,
+0x610034,
+0x620038,
+0x630038,
+0x640038,
+0x650038,
+0x660038,
+0x670038,
+0x68003a,
+0x690041,
+0x6a0048,
+0x6b0048,
+0x6c0048,
+0x6d0048,
+0x6e0048,
+0x6f0048,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+};
+
+static const u32 RS780_cp_microcode[][3] = {
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0000ffff, 0x00284621, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00000000, 0x00e00000, 0x000 },
+    { 0x00010000, 0xc0294620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x622 },
+    { 0x00000000, 0x00600000, 0x5d1 },
+    { 0x00000000, 0x00600000, 0x5de },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000f00, 0x00281622, 0x000 },
+    { 0x00000008, 0x00211625, 0x000 },
+    { 0x00000018, 0x00203625, 0x000 },
+    { 0x8d000000, 0x00204411, 0x000 },
+    { 0x00000004, 0x002f0225, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x018 },
+    { 0x00412000, 0x00404811, 0x019 },
+    { 0x00422000, 0x00204811, 0x000 },
+    { 0x8e000000, 0x00204411, 0x000 },
+    { 0x00000028, 0x00204a2d, 0x000 },
+    { 0x90000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x0000000c, 0x00211622, 0x000 },
+    { 0x00000003, 0x00281625, 0x000 },
+    { 0x00000019, 0x00211a22, 0x000 },
+    { 0x00000004, 0x00281a26, 0x000 },
+    { 0x00000000, 0x002914c5, 0x000 },
+    { 0x00000019, 0x00203625, 0x000 },
+    { 0x00000000, 0x003a1402, 0x000 },
+    { 0x00000016, 0x00211625, 0x000 },
+    { 0x00000003, 0x00281625, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0xfffffffc, 0x00280e23, 0x000 },
+    { 0x00000000, 0x002914a3, 0x000 },
+    { 0x00000017, 0x00203625, 0x000 },
+    { 0x00008000, 0x00280e22, 0x000 },
+    { 0x00000007, 0x00220e23, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x20000000, 0x00280e22, 0x000 },
+    { 0x00000006, 0x00210e23, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x00000000, 0x00220222, 0x000 },
+    { 0x00000000, 0x14e00000, 0x038 },
+    { 0x00000000, 0x2ee00000, 0x035 },
+    { 0x00000000, 0x2ce00000, 0x037 },
+    { 0x00000000, 0x00400e2d, 0x039 },
+    { 0x00000008, 0x00200e2d, 0x000 },
+    { 0x00000009, 0x0040122d, 0x046 },
+    { 0x00000001, 0x00400e2d, 0x039 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x003ffffc, 0x00281223, 0x000 },
+    { 0x00000002, 0x00221224, 0x000 },
+    { 0x0000001f, 0x00211e23, 0x000 },
+    { 0x00000000, 0x14e00000, 0x03e },
+    { 0x00000008, 0x00401c11, 0x041 },
+    { 0x0000000d, 0x00201e2d, 0x000 },
+    { 0x0000000f, 0x00281e27, 0x000 },
+    { 0x00000003, 0x00221e27, 0x000 },
+    { 0x7fc00000, 0x00281a23, 0x000 },
+    { 0x00000014, 0x00211a26, 0x000 },
+    { 0x00000001, 0x00331a26, 0x000 },
+    { 0x00000008, 0x00221a26, 0x000 },
+    { 0x00000000, 0x00290cc7, 0x000 },
+    { 0x00000027, 0x00203624, 0x000 },
+    { 0x00007f00, 0x00281221, 0x000 },
+    { 0x00001400, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x04b },
+    { 0x00000001, 0x00290e23, 0x000 },
+    { 0x0000000e, 0x00203623, 0x000 },
+    { 0x0000e000, 0x00204411, 0x000 },
+    { 0xfff80000, 0x00294a23, 0x000 },
+    { 0x00000000, 0x003a2c02, 0x000 },
+    { 0x00000002, 0x00220e2b, 0x000 },
+    { 0xfc000000, 0x00280e23, 0x000 },
+    { 0x0000000f, 0x00203623, 0x000 },
+    { 0x00001fff, 0x00294a23, 0x000 },
+    { 0x00000027, 0x00204a2d, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000029, 0x00200e2d, 0x000 },
+    { 0x060a0200, 0x00294a23, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00210222, 0x000 },
+    { 0x00000000, 0x14e00000, 0x061 },
+    { 0x00000000, 0x2ee00000, 0x05f },
+    { 0x00000000, 0x2ce00000, 0x05e },
+    { 0x00000000, 0x00400e2d, 0x062 },
+    { 0x00000001, 0x00400e2d, 0x062 },
+    { 0x0000000a, 0x00200e2d, 0x000 },
+    { 0x0000000b, 0x0040122d, 0x06a },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x003ffffc, 0x00281223, 0x000 },
+    { 0x00000002, 0x00221224, 0x000 },
+    { 0x7fc00000, 0x00281623, 0x000 },
+    { 0x00000014, 0x00211625, 0x000 },
+    { 0x00000001, 0x00331625, 0x000 },
+    { 0x80000000, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00290ca3, 0x000 },
+    { 0x3ffffc00, 0x00290e23, 0x000 },
+    { 0x0000001f, 0x00211e23, 0x000 },
+    { 0x00000000, 0x14e00000, 0x06d },
+    { 0x00000100, 0x00401c11, 0x070 },
+    { 0x0000000d, 0x00201e2d, 0x000 },
+    { 0x000000f0, 0x00281e27, 0x000 },
+    { 0x00000004, 0x00221e27, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000d, 0x00204811, 0x000 },
+    { 0xfffff0ff, 0x00281a30, 0x000 },
+    { 0x0000a028, 0x00204411, 0x000 },
+    { 0x00000000, 0x002948e6, 0x000 },
+    { 0x0000a018, 0x00204411, 0x000 },
+    { 0x3fffffff, 0x00284a23, 0x000 },
+    { 0x0000a010, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000030, 0x0020162d, 0x000 },
+    { 0x00000002, 0x00291625, 0x000 },
+    { 0x00000030, 0x00203625, 0x000 },
+    { 0x00000025, 0x0020162d, 0x000 },
+    { 0x00000000, 0x002f00a3, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x083 },
+    { 0x00000026, 0x0020162d, 0x000 },
+    { 0x00000000, 0x002f00a4, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x084 },
+    { 0x00000000, 0x00400000, 0x08a },
+    { 0x00000025, 0x00203623, 0x000 },
+    { 0x00000026, 0x00203624, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x08a },
+    { 0x00000000, 0x00600000, 0x5ff },
+    { 0x00000000, 0x00600000, 0x5f3 },
+    { 0x00000002, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x08d },
+    { 0x00000012, 0xc0403620, 0x093 },
+    { 0x00000000, 0x2ee00000, 0x091 },
+    { 0x00000000, 0x2ce00000, 0x090 },
+    { 0x00000002, 0x00400e2d, 0x092 },
+    { 0x00000003, 0x00400e2d, 0x092 },
+    { 0x0000000c, 0x00200e2d, 0x000 },
+    { 0x00000012, 0x00203623, 0x000 },
+    { 0x00000003, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x098 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x0a0 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x2ee00000, 0x09e },
+    { 0x00000000, 0x2ce00000, 0x09d },
+    { 0x00000002, 0x00400e2d, 0x09f },
+    { 0x00000003, 0x00400e2d, 0x09f },
+    { 0x0000000c, 0x00200e2d, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000000, 0x003a0c02, 0x000 },
+    { 0x003f0000, 0x00280e23, 0x000 },
+    { 0x00000010, 0x00210e23, 0x000 },
+    { 0x00000011, 0x00203623, 0x000 },
+    { 0x0000001e, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0a7 },
+    { 0x00000016, 0xc0203620, 0x000 },
+    { 0x0000001f, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0aa },
+    { 0x00000015, 0xc0203620, 0x000 },
+    { 0x00000008, 0x00210e2b, 0x000 },
+    { 0x0000007f, 0x00280e23, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0e1 },
+    { 0x00000000, 0x27000000, 0x000 },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x0b3 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x0000000c, 0x00221e30, 0x000 },
+    { 0x99800000, 0x00204411, 0x000 },
+    { 0x00000004, 0x0020122d, 0x000 },
+    { 0x00000008, 0x00221224, 0x000 },
+    { 0x00000010, 0x00201811, 0x000 },
+    { 0x00000000, 0x00291ce4, 0x000 },
+    { 0x00000000, 0x00604807, 0x12f },
+    { 0x9b000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x9c000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x0033146f, 0x000 },
+    { 0x00000001, 0x00333e23, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0x00203c05, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x00000000, 0x00201010, 0x000 },
+    { 0x0000e007, 0x00204411, 0x000 },
+    { 0x0000000f, 0x0021022b, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0cb },
+    { 0x00f8ff08, 0x00204811, 0x000 },
+    { 0x98000000, 0x00404811, 0x0dc },
+    { 0x000000f0, 0x00280e22, 0x000 },
+    { 0x000000a0, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x0da },
+    { 0x00000011, 0x00200e2d, 0x000 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0d5 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0d4 },
+    { 0x00003f00, 0x00400c11, 0x0d6 },
+    { 0x00001f00, 0x00400c11, 0x0d6 },
+    { 0x00000f00, 0x00200c11, 0x000 },
+    { 0x00380009, 0x00294a23, 0x000 },
+    { 0x3f000000, 0x00280e2b, 0x000 },
+    { 0x00000002, 0x00220e23, 0x000 },
+    { 0x00000007, 0x00494a23, 0x0dc },
+    { 0x00380f09, 0x00204811, 0x000 },
+    { 0x68000007, 0x00204811, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a24, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000a202, 0x00204411, 0x000 },
+    { 0x00ff0000, 0x00280e22, 0x000 },
+    { 0x00000080, 0x00294a23, 0x000 },
+    { 0x00000027, 0x00200e2d, 0x000 },
+    { 0x00000026, 0x0020122d, 0x000 },
+    { 0x00000000, 0x002f0083, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x0ea },
+    { 0x00000000, 0x00600000, 0x5f9 },
+    { 0x00000000, 0x00400000, 0x0eb },
+    { 0x00000000, 0x00600000, 0x5fc },
+    { 0x00000007, 0x0020222d, 0x000 },
+    { 0x00000005, 0x00220e22, 0x000 },
+    { 0x00100000, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00292068, 0x000 },
+    { 0x00000000, 0x003a0c02, 0x000 },
+    { 0x000000ef, 0x00280e23, 0x000 },
+    { 0x00000000, 0x00292068, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0x00000003, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x0f8 },
+    { 0x0000000b, 0x00210228, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0f8 },
+    { 0x00000400, 0x00292228, 0x000 },
+    { 0x00000014, 0x00203628, 0x000 },
+    { 0x0000001c, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x0fd },
+    { 0x0000a30c, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000001e, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x10b },
+    { 0x0000a30f, 0x00204411, 0x000 },
+    { 0x00000011, 0x00200e2d, 0x000 },
+    { 0x00000001, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x104 },
+    { 0xffffffff, 0x00404811, 0x10b },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x107 },
+    { 0x0000ffff, 0x00404811, 0x10b },
+    { 0x00000004, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x10a },
+    { 0x000000ff, 0x00404811, 0x10b },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0002c400, 0x00204411, 0x000 },
+    { 0x0000001f, 0x00210e22, 0x000 },
+    { 0x00000000, 0x14c00000, 0x112 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x00000013, 0x00203623, 0x000 },
+    { 0x00000018, 0x40224a20, 0x000 },
+    { 0x00000010, 0xc0424a20, 0x114 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x00000013, 0x00203623, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000000a, 0x00201011, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x11b },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00531224, 0x117 },
+    { 0xffbfffff, 0x00283a2e, 0x000 },
+    { 0x0000001b, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x12e },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000d, 0x00204811, 0x000 },
+    { 0x00000018, 0x00220e30, 0x000 },
+    { 0xfc000000, 0x00280e23, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x00000000, 0x00201010, 0x000 },
+    { 0x0000e00e, 0x00204411, 0x000 },
+    { 0x07f8ff08, 0x00204811, 0x000 },
+    { 0x00000000, 0x00294a23, 0x000 },
+    { 0x0000001c, 0x00201e2d, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a24, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x00800000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204806, 0x000 },
+    { 0x00000008, 0x00214a27, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x622 },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x621 },
+    { 0x00000004, 0x00404c11, 0x135 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x0000001c, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x622 },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x13c },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00000000, 0x00600000, 0x160 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000ffff, 0x40280620, 0x000 },
+    { 0x00000010, 0xc0210a20, 0x000 },
+    { 0x00000000, 0x00341461, 0x000 },
+    { 0x00000000, 0x00741882, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x147 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x160 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x00000010, 0x40211620, 0x000 },
+    { 0x0000ffff, 0xc0681a20, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x158 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000001, 0x00300a2f, 0x000 },
+    { 0x00000001, 0x00210a22, 0x000 },
+    { 0x00000003, 0x00384a22, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001a, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600000, 0x18f },
+    { 0x00000000, 0x00600000, 0x1a0 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00202c08, 0x000 },
+    { 0x00000000, 0x00202411, 0x000 },
+    { 0x00000000, 0x00202811, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000002, 0x00221e29, 0x000 },
+    { 0x00000000, 0x007048eb, 0x19c },
+    { 0x00000000, 0x00600000, 0x2bb },
+    { 0x00000001, 0x40330620, 0x000 },
+    { 0x00000000, 0xc0302409, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x181 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x00000000, 0x00400000, 0x186 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x186 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000001, 0x00530621, 0x182 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0604800, 0x197 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000011, 0x0020062d, 0x000 },
+    { 0x00000000, 0x0078042a, 0x2fb },
+    { 0x00000000, 0x00202809, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x174 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000210, 0x00600411, 0x315 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x194 },
+    { 0x00000015, 0xc0203620, 0x000 },
+    { 0x00000016, 0xc0203620, 0x000 },
+    { 0x3f800000, 0x00200411, 0x000 },
+    { 0x46000000, 0x00600811, 0x1b2 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x19b },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000021, 0x00804811, 0x000 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000ffff, 0x40281620, 0x000 },
+    { 0x00000010, 0xc0811a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x00000008, 0x00221e30, 0x000 },
+    { 0x00000029, 0x00201a2d, 0x000 },
+    { 0x0000e000, 0x00204411, 0x000 },
+    { 0xfffbff09, 0x00204811, 0x000 },
+    { 0x0000000f, 0x0020222d, 0x000 },
+    { 0x00001fff, 0x00294a28, 0x000 },
+    { 0x00000006, 0x0020222d, 0x000 },
+    { 0x00000000, 0x002920e8, 0x000 },
+    { 0x00000000, 0x00204808, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00294a26, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000100, 0x00201811, 0x000 },
+    { 0x00000008, 0x00621e28, 0x12f },
+    { 0x00000008, 0x00822228, 0x000 },
+    { 0x0002c000, 0x00204411, 0x000 },
+    { 0x00000015, 0x00600e2d, 0x1bd },
+    { 0x00000016, 0x00600e2d, 0x1bd },
+    { 0x0000c008, 0x00204411, 0x000 },
+    { 0x00000017, 0x00200e2d, 0x000 },
+    { 0x00000000, 0x14c00000, 0x1b9 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0x39000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00804802, 0x000 },
+    { 0x00000018, 0x00202e2d, 0x000 },
+    { 0x00000000, 0x003b0d63, 0x000 },
+    { 0x00000008, 0x00224a23, 0x000 },
+    { 0x00000010, 0x00224a23, 0x000 },
+    { 0x00000018, 0x00224a23, 0x000 },
+    { 0x00000000, 0x00804803, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00001000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00000007, 0x0021062f, 0x000 },
+    { 0x00000013, 0x00200a2d, 0x000 },
+    { 0x00000001, 0x00202c11, 0x000 },
+    { 0x0000ffff, 0x40282220, 0x000 },
+    { 0x0000000f, 0x00262228, 0x000 },
+    { 0x00000010, 0x40212620, 0x000 },
+    { 0x0000000f, 0x00262629, 0x000 },
+    { 0x00000000, 0x00202802, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001b, 0x00204811, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1e0 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000081, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000080, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f0227, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1dc },
+    { 0x00000000, 0x00600000, 0x1e9 },
+    { 0x00000001, 0x00531e27, 0x1d8 },
+    { 0x00000001, 0x00202c11, 0x000 },
+    { 0x0000001f, 0x00280a22, 0x000 },
+    { 0x0000001f, 0x00282a2a, 0x000 },
+    { 0x00000001, 0x00530621, 0x1d1 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000002, 0x00304a2f, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000001, 0x00301e2f, 0x000 },
+    { 0x00000000, 0x002f0227, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00600000, 0x1e9 },
+    { 0x00000001, 0x00531e27, 0x1e5 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x0000000f, 0x00260e23, 0x000 },
+    { 0x00000010, 0xc0211220, 0x000 },
+    { 0x0000000f, 0x00261224, 0x000 },
+    { 0x00000000, 0x00201411, 0x000 },
+    { 0x00000000, 0x00601811, 0x2bb },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022b, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x1f8 },
+    { 0x00000010, 0x00221628, 0x000 },
+    { 0xffff0000, 0x00281625, 0x000 },
+    { 0x0000ffff, 0x00281a29, 0x000 },
+    { 0x00000000, 0x002948c5, 0x000 },
+    { 0x00000000, 0x0020480a, 0x000 },
+    { 0x00000000, 0x00202c11, 0x000 },
+    { 0x00000010, 0x00221623, 0x000 },
+    { 0xffff0000, 0x00281625, 0x000 },
+    { 0x0000ffff, 0x00281a24, 0x000 },
+    { 0x00000000, 0x002948c5, 0x000 },
+    { 0x00000000, 0x00731503, 0x205 },
+    { 0x00000000, 0x00201805, 0x000 },
+    { 0x00000000, 0x00731524, 0x205 },
+    { 0x00000000, 0x002d14c5, 0x000 },
+    { 0x00000000, 0x003008a2, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00202802, 0x000 },
+    { 0x00000000, 0x00202003, 0x000 },
+    { 0x00000000, 0x00802404, 0x000 },
+    { 0x0000000f, 0x00210225, 0x000 },
+    { 0x00000000, 0x14c00000, 0x621 },
+    { 0x00000000, 0x002b1405, 0x000 },
+    { 0x00000001, 0x00901625, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001a, 0x00294a22, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00384a21, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000ffff, 0x40281220, 0x000 },
+    { 0x00000010, 0xc0211a20, 0x000 },
+    { 0x0000ffff, 0x40280e20, 0x000 },
+    { 0x00000010, 0xc0211620, 0x000 },
+    { 0x00000000, 0x00741465, 0x2bb },
+    { 0x0001a1fd, 0x00604411, 0x2e0 },
+    { 0x00000001, 0x00330621, 0x000 },
+    { 0x00000000, 0x002f0221, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x219 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x212 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x5de },
+    { 0x00000000, 0x0040040f, 0x213 },
+    { 0x00000000, 0x00600000, 0x5d1 },
+    { 0x00000000, 0x00600000, 0x5de },
+    { 0x00000210, 0x00600411, 0x315 },
+    { 0x00000000, 0x00600000, 0x1a0 },
+    { 0x00000000, 0x00600000, 0x19c },
+    { 0x00000000, 0x00600000, 0x2bb },
+    { 0x00000000, 0x00600000, 0x2a3 },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204808, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x232 },
+    { 0x00000000, 0x00600000, 0x13a },
+    { 0x00000000, 0x00400000, 0x236 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x236 },
+    { 0x00000000, 0xc0404800, 0x233 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x00600411, 0x2fb },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000000, 0x00600000, 0x5d1 },
+    { 0x0000a00c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000018, 0x40210a20, 0x000 },
+    { 0x00000003, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x24c },
+    { 0x00000014, 0x0020222d, 0x000 },
+    { 0x00080101, 0x00292228, 0x000 },
+    { 0x00000014, 0x00203628, 0x000 },
+    { 0x0000a30c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x251 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000010, 0x00600411, 0x315 },
+    { 0x3f800000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x00000000, 0x00600000, 0x27c },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000001, 0x00211e27, 0x000 },
+    { 0x00000000, 0x14e00000, 0x26a },
+    { 0x00000012, 0x00201e2d, 0x000 },
+    { 0x0000ffff, 0x00281e27, 0x000 },
+    { 0x00000000, 0x00341c27, 0x000 },
+    { 0x00000000, 0x12c00000, 0x25f },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f00e5, 0x000 },
+    { 0x00000000, 0x08c00000, 0x262 },
+    { 0x00000000, 0x00201407, 0x000 },
+    { 0x00000012, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00211e27, 0x000 },
+    { 0x00000000, 0x00341c47, 0x000 },
+    { 0x00000000, 0x12c00000, 0x267 },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x002f00e6, 0x000 },
+    { 0x00000000, 0x08c00000, 0x26a },
+    { 0x00000000, 0x00201807, 0x000 },
+    { 0x00000000, 0x00600000, 0x2c1 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x00000000, 0x00342023, 0x000 },
+    { 0x00000000, 0x12c00000, 0x272 },
+    { 0x00000000, 0x00342044, 0x000 },
+    { 0x00000000, 0x12c00000, 0x271 },
+    { 0x00000016, 0x00404811, 0x276 },
+    { 0x00000018, 0x00404811, 0x276 },
+    { 0x00000000, 0x00342044, 0x000 },
+    { 0x00000000, 0x12c00000, 0x275 },
+    { 0x00000017, 0x00404811, 0x276 },
+    { 0x00000019, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0x00604411, 0x2e9 },
+    { 0x00003fff, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x256 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x00000010, 0x40210620, 0x000 },
+    { 0x0000ffff, 0xc0280a20, 0x000 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x00000010, 0x40211620, 0x000 },
+    { 0x0000ffff, 0xc0881a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00042004, 0x00604411, 0x622 },
+    { 0x00000000, 0x00600000, 0x5d1 },
+    { 0x00000000, 0xc0600000, 0x2a3 },
+    { 0x00000005, 0x00200a2d, 0x000 },
+    { 0x00000008, 0x00220a22, 0x000 },
+    { 0x0000002b, 0x00201a2d, 0x000 },
+    { 0x0000001c, 0x00201e2d, 0x000 },
+    { 0x00007000, 0x00281e27, 0x000 },
+    { 0x00000000, 0x00311ce6, 0x000 },
+    { 0x0000002a, 0x00201a2d, 0x000 },
+    { 0x0000000c, 0x00221a26, 0x000 },
+    { 0x00000000, 0x002f00e6, 0x000 },
+    { 0x00000000, 0x06e00000, 0x292 },
+    { 0x00000000, 0x00201c11, 0x000 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x0000002b, 0x00203623, 0x000 },
+    { 0x00000010, 0x00201811, 0x000 },
+    { 0x00000000, 0x00691ce2, 0x12f },
+    { 0x93800000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x95000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f022f, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x29d },
+    { 0x00000001, 0x00333e2f, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x92000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000001c, 0x00403627, 0x000 },
+    { 0x0000000c, 0xc0220a20, 0x000 },
+    { 0x00000029, 0x00203622, 0x000 },
+    { 0x00000028, 0xc0403620, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000009, 0x00204811, 0x000 },
+    { 0xa1000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00804811, 0x000 },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002c1ce3, 0x000 },
+    { 0x00000021, 0x00203627, 0x000 },
+    { 0x00000022, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002c1ce4, 0x000 },
+    { 0x00000022, 0x00203627, 0x000 },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120a3, 0x000 },
+    { 0x00000000, 0x002d1d07, 0x000 },
+    { 0x00000023, 0x00203627, 0x000 },
+    { 0x00000024, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x00000000, 0x002d1d07, 0x000 },
+    { 0x00000024, 0x00803627, 0x000 },
+    { 0x00000021, 0x00203623, 0x000 },
+    { 0x00000022, 0x00203624, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000023, 0x00203627, 0x000 },
+    { 0x00000000, 0x00311cc4, 0x000 },
+    { 0x00000024, 0x00803627, 0x000 },
+    { 0x0000001a, 0x00203627, 0x000 },
+    { 0x0000001b, 0x00203628, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14c00000, 0x2dc },
+    { 0x00000000, 0x00400000, 0x2d9 },
+    { 0x0000001a, 0x00203627, 0x000 },
+    { 0x0000001b, 0x00203628, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000002, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x2d9 },
+    { 0x00000003, 0x00210227, 0x000 },
+    { 0x00000000, 0x14e00000, 0x2dc },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002e00e1, 0x000 },
+    { 0x00000000, 0x02c00000, 0x2dc },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120a1, 0x000 },
+    { 0x00000000, 0x002e00e8, 0x000 },
+    { 0x00000000, 0x06c00000, 0x2dc },
+    { 0x00000024, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x002e00e2, 0x000 },
+    { 0x00000000, 0x02c00000, 0x2dc },
+    { 0x00000022, 0x00201e2d, 0x000 },
+    { 0x00000000, 0x003120c2, 0x000 },
+    { 0x00000000, 0x002e00e8, 0x000 },
+    { 0x00000000, 0x06c00000, 0x2dc },
+    { 0x00000000, 0x00600000, 0x5ff },
+    { 0x00000000, 0x00600000, 0x2b5 },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x00000000, 0x00600000, 0x2b5 },
+    { 0x00000000, 0x00600000, 0x5f6 },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x00000000, 0x00600000, 0x2a7 },
+    { 0x00000000, 0x00400000, 0x2de },
+    { 0x0000001a, 0x00201e2d, 0x000 },
+    { 0x0000001b, 0x0080222d, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000010, 0x00221e21, 0x000 },
+    { 0x00000000, 0x00294847, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000000, 0x00311ca1, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294847, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000010, 0x00221e21, 0x000 },
+    { 0x00000000, 0x003120c2, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000001, 0x00220a21, 0x000 },
+    { 0x00000000, 0x003308a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00311ca3, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294887, 0x000 },
+    { 0x00000001, 0x00220a21, 0x000 },
+    { 0x00000000, 0x003008a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000010, 0x00221e23, 0x000 },
+    { 0x00000000, 0x003120c4, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x003808c5, 0x000 },
+    { 0x00000000, 0x00300841, 0x000 },
+    { 0x00000001, 0x00220a22, 0x000 },
+    { 0x00000000, 0x003308a2, 0x000 },
+    { 0x00000010, 0x00221e22, 0x000 },
+    { 0x00000010, 0x00212222, 0x000 },
+    { 0x00000000, 0x00894907, 0x000 },
+    { 0x00000017, 0x0020222d, 0x000 },
+    { 0x00000000, 0x14c00000, 0x318 },
+    { 0xffffffef, 0x00280621, 0x000 },
+    { 0x00000014, 0x0020222d, 0x000 },
+    { 0x0000f8e0, 0x00204411, 0x000 },
+    { 0x00000000, 0x00294901, 0x000 },
+    { 0x00000000, 0x00894901, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x060a0200, 0x00804811, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x97000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0xc0204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x97000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0xc0204811, 0x000 },
+    { 0x8a000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00002257, 0x00204411, 0x000 },
+    { 0x00000003, 0xc0484a20, 0x000 },
+    { 0x0000225d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0x00600000, 0x5de },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00384a22, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0001a1fd, 0x00204411, 0x000 },
+    { 0x00000000, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x40204800, 0x000 },
+    { 0x00000001, 0x40304a20, 0x000 },
+    { 0x00000002, 0xc0304a20, 0x000 },
+    { 0x00000001, 0x00530a22, 0x355 },
+    { 0x0000003f, 0xc0280a20, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000018, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x622 },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x35e },
+    { 0x00000014, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x36c },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00604802, 0x374 },
+    { 0x00002100, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000004, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x370 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x367 },
+    { 0x00000028, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5ba },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x367 },
+    { 0x0000002c, 0x00203626, 0x000 },
+    { 0x00000049, 0x00201811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x00000001, 0x00331a26, 0x000 },
+    { 0x00000000, 0x002f0226, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x376 },
+    { 0x0000002c, 0x00801a2d, 0x000 },
+    { 0x0000003f, 0xc0280a20, 0x000 },
+    { 0x00000015, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x38c },
+    { 0x00000006, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3b7 },
+    { 0x00000016, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3b9 },
+    { 0x00000020, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3a2 },
+    { 0x0000000f, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3ae },
+    { 0x00000010, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x3ae },
+    { 0x0000001e, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x396 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x08000000, 0x00290a22, 0x000 },
+    { 0x00000003, 0x40210e20, 0x000 },
+    { 0x0000000c, 0xc0211220, 0x000 },
+    { 0x00080000, 0x00281224, 0x000 },
+    { 0x00000014, 0xc0221620, 0x000 },
+    { 0x00000000, 0x002914a4, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x002948a2, 0x000 },
+    { 0x0000a1fe, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404803, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000016, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x622 },
+    { 0x00000015, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x398 },
+    { 0x0000210e, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000017, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x622 },
+    { 0x00000003, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x3a4 },
+    { 0x00002108, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404802, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x80000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000010, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3b4 },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000006, 0x00404811, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x374 },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x0000001d, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x3ce },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x00000018, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x622 },
+    { 0x00000011, 0x00210230, 0x000 },
+    { 0x00000000, 0x14e00000, 0x3c2 },
+    { 0x00002100, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0xbabecafe, 0x00204811, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000004, 0x00404811, 0x000 },
+    { 0x00002170, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000a, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3d3 },
+    { 0x8c000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00003fff, 0x40280a20, 0x000 },
+    { 0x80000000, 0x40280e20, 0x000 },
+    { 0x40000000, 0xc0281220, 0x000 },
+    { 0x00040000, 0x00694622, 0x622 },
+    { 0x00000000, 0x00201410, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x3e1 },
+    { 0x00000000, 0xc0401800, 0x3e4 },
+    { 0x00003fff, 0xc0281a20, 0x000 },
+    { 0x00040000, 0x00694626, 0x622 },
+    { 0x00000000, 0x00201810, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x3e7 },
+    { 0x00000000, 0xc0401c00, 0x3ea },
+    { 0x00003fff, 0xc0281e20, 0x000 },
+    { 0x00040000, 0x00694627, 0x622 },
+    { 0x00000000, 0x00201c10, 0x000 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0x002820c5, 0x000 },
+    { 0x00000000, 0x004948e8, 0x000 },
+    { 0xa5800000, 0x00200811, 0x000 },
+    { 0x00002000, 0x00200c11, 0x000 },
+    { 0x83000000, 0x00604411, 0x412 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x40204800, 0x000 },
+    { 0x0000001f, 0xc0210220, 0x000 },
+    { 0x00000000, 0x14c00000, 0x3f7 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00008000, 0x00204811, 0x000 },
+    { 0x0000ffff, 0xc0481220, 0x3ff },
+    { 0xa7800000, 0x00200811, 0x000 },
+    { 0x0000a000, 0x00200c11, 0x000 },
+    { 0x83000000, 0x00604411, 0x412 },
+    { 0x00000000, 0x00204402, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000ffff, 0xc0281220, 0x000 },
+    { 0x83000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00304883, 0x000 },
+    { 0x84000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x1d000000, 0x000 },
+    { 0x83000000, 0x00604411, 0x412 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0xa9800000, 0x00200811, 0x000 },
+    { 0x0000c000, 0x00400c11, 0x3fa },
+    { 0xab800000, 0x00200811, 0x000 },
+    { 0x0000f8e0, 0x00400c11, 0x3fa },
+    { 0xad800000, 0x00200811, 0x000 },
+    { 0x0000f880, 0x00400c11, 0x3fa },
+    { 0xb3800000, 0x00200811, 0x000 },
+    { 0x0000f3fc, 0x00400c11, 0x3fa },
+    { 0xaf800000, 0x00200811, 0x000 },
+    { 0x0000e000, 0x00400c11, 0x3fa },
+    { 0xb1800000, 0x00200811, 0x000 },
+    { 0x0000f000, 0x00400c11, 0x3fa },
+    { 0x83000000, 0x00204411, 0x000 },
+    { 0x00002148, 0x00204811, 0x000 },
+    { 0x84000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x1d000000, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x01182000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0218a000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0318c000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0418f8e0, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0518f880, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0618e000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0718f000, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x0818f3fc, 0xc0304620, 0x000 },
+    { 0x00000000, 0xd9004800, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x00000033, 0xc0300a20, 0x000 },
+    { 0x00000000, 0xc0403440, 0x000 },
+    { 0x00000030, 0x00200a2d, 0x000 },
+    { 0x00000000, 0xc0290c40, 0x000 },
+    { 0x00000030, 0x00203623, 0x000 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x00a0000a, 0x000 },
+    { 0x86000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404801, 0x000 },
+    { 0x85000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0x00404801, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x00000018, 0x40210220, 0x000 },
+    { 0x00000000, 0x14c00000, 0x447 },
+    { 0x00800000, 0xc0494a20, 0x448 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000004, 0x002f0222, 0x000 },
+    { 0x00000000, 0x06e00000, 0x450 },
+    { 0x00000004, 0x00200811, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x622 },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000000, 0x00404c02, 0x450 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x00000000, 0xc0201000, 0x000 },
+    { 0x00000000, 0xc0201400, 0x000 },
+    { 0x00000000, 0xc0201800, 0x000 },
+    { 0x00000000, 0xc0201c00, 0x000 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x461 },
+    { 0x00000000, 0xc0202000, 0x000 },
+    { 0x00000004, 0x002f0228, 0x000 },
+    { 0x00000000, 0x06e00000, 0x461 },
+    { 0x00000004, 0x00202011, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x00000010, 0x00280a23, 0x000 },
+    { 0x00000010, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x469 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00040000, 0x00694624, 0x622 },
+    { 0x00000000, 0x00400000, 0x46e },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000000, 0x00604805, 0x627 },
+    { 0x00000000, 0x002824f0, 0x000 },
+    { 0x00000007, 0x00280a23, 0x000 },
+    { 0x00000001, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x475 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x04e00000, 0x48e },
+    { 0x00000000, 0x00400000, 0x49b },
+    { 0x00000002, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x47a },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x02e00000, 0x48e },
+    { 0x00000000, 0x00400000, 0x49b },
+    { 0x00000003, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x47f },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x48e },
+    { 0x00000000, 0x00400000, 0x49b },
+    { 0x00000004, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x484 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x48e },
+    { 0x00000000, 0x00400000, 0x49b },
+    { 0x00000005, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x489 },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x06e00000, 0x48e },
+    { 0x00000000, 0x00400000, 0x49b },
+    { 0x00000006, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x48e },
+    { 0x00000000, 0x002f00c9, 0x000 },
+    { 0x00000000, 0x08e00000, 0x48e },
+    { 0x00000000, 0x00400000, 0x49b },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x000 },
+    { 0x00000008, 0x00210a23, 0x000 },
+    { 0x00000000, 0x14c00000, 0x498 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x00000000, 0xc0204400, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00007f00, 0x00280a21, 0x000 },
+    { 0x00004500, 0x002f0222, 0x000 },
+    { 0x00000000, 0x0ae00000, 0x4a1 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0400000, 0x000 },
+    { 0x00000000, 0x00404c08, 0x461 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000010, 0x40210e20, 0x000 },
+    { 0x00000011, 0x40211220, 0x000 },
+    { 0x00000012, 0x40211620, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00210225, 0x000 },
+    { 0x00000000, 0x14e00000, 0x4ab },
+    { 0x00040000, 0xc0494a20, 0x4ac },
+    { 0xfffbffff, 0xc0284a20, 0x000 },
+    { 0x00000000, 0x00210223, 0x000 },
+    { 0x00000000, 0x14e00000, 0x4b8 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x00210224, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x0000000c, 0x00204811, 0x000 },
+    { 0x00000000, 0x00200010, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4b4 },
+    { 0xa0000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000004, 0x00204811, 0x000 },
+    { 0x0000216b, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204810, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000005, 0x00204811, 0x000 },
+    { 0x0000216c, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204810, 0x000 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0ce00000, 0x000 },
+    { 0x00000000, 0x00400000, 0x4b2 },
+    { 0x00000000, 0xc0210a20, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4cb },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0604800, 0x627 },
+    { 0x00000000, 0x00400000, 0x4cf },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00040000, 0xc0294620, 0x000 },
+    { 0x00000000, 0xc0600000, 0x622 },
+    { 0x00000001, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4d6 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0xcafebabe, 0x00404811, 0x000 },
+    { 0x00000000, 0xc0204400, 0x000 },
+    { 0x00000000, 0xc0404810, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x000021f8, 0x00204411, 0x000 },
+    { 0x0000000e, 0x00204811, 0x000 },
+    { 0x000421f9, 0x00604411, 0x622 },
+    { 0x00000000, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x4d8 },
+    { 0x00002180, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000003, 0x00333e2f, 0x000 },
+    { 0x00000001, 0x00210221, 0x000 },
+    { 0x00000000, 0x14e00000, 0x508 },
+    { 0x0000002c, 0x00200a2d, 0x000 },
+    { 0x00040000, 0x18e00c11, 0x4f7 },
+    { 0x00000001, 0x00333e2f, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xd8c04800, 0x4eb },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000002d, 0x0020122d, 0x000 },
+    { 0x00000000, 0x00290c83, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204802, 0x000 },
+    { 0x00000000, 0x00204803, 0x000 },
+    { 0x00000008, 0x00300a22, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000011, 0x00210224, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000000, 0x00400000, 0x4b2 },
+    { 0x0000002c, 0xc0203620, 0x000 },
+    { 0x0000002d, 0xc0403620, 0x000 },
+    { 0x0000000f, 0x00210221, 0x000 },
+    { 0x00000000, 0x14c00000, 0x50d },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00000000, 0xd9000000, 0x000 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0xb5000000, 0x00204411, 0x000 },
+    { 0x00002000, 0x00204811, 0x000 },
+    { 0xb6000000, 0x00204411, 0x000 },
+    { 0x0000a000, 0x00204811, 0x000 },
+    { 0xb7000000, 0x00204411, 0x000 },
+    { 0x0000c000, 0x00204811, 0x000 },
+    { 0xb8000000, 0x00204411, 0x000 },
+    { 0x0000f8e0, 0x00204811, 0x000 },
+    { 0xb9000000, 0x00204411, 0x000 },
+    { 0x0000f880, 0x00204811, 0x000 },
+    { 0xba000000, 0x00204411, 0x000 },
+    { 0x0000e000, 0x00204811, 0x000 },
+    { 0xbb000000, 0x00204411, 0x000 },
+    { 0x0000f000, 0x00204811, 0x000 },
+    { 0xbc000000, 0x00204411, 0x000 },
+    { 0x0000f3fc, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000002, 0x00204811, 0x000 },
+    { 0x000000ff, 0x00280e30, 0x000 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x521 },
+    { 0x00000000, 0xc0200800, 0x000 },
+    { 0x00000000, 0x14c00000, 0x536 },
+    { 0x00000000, 0x00200c11, 0x000 },
+    { 0x0000001c, 0x00203623, 0x000 },
+    { 0x0000002b, 0x00203623, 0x000 },
+    { 0x00000029, 0x00203623, 0x000 },
+    { 0x00000028, 0x00203623, 0x000 },
+    { 0x00000017, 0x00203623, 0x000 },
+    { 0x00000025, 0x00203623, 0x000 },
+    { 0x00000026, 0x00203623, 0x000 },
+    { 0x00000015, 0x00203623, 0x000 },
+    { 0x00000016, 0x00203623, 0x000 },
+    { 0xffffe000, 0x00200c11, 0x000 },
+    { 0x00000021, 0x00203623, 0x000 },
+    { 0x00000022, 0x00203623, 0x000 },
+    { 0x00001fff, 0x00200c11, 0x000 },
+    { 0x00000023, 0x00203623, 0x000 },
+    { 0x00000024, 0x00203623, 0x000 },
+    { 0xf1ffffff, 0x00283a2e, 0x000 },
+    { 0x0000001a, 0xc0220e20, 0x000 },
+    { 0x00000000, 0x0029386e, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000006, 0x00204811, 0x000 },
+    { 0x0000002a, 0x40203620, 0x000 },
+    { 0x87000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x0000a1f4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0x9d000000, 0x00204411, 0x000 },
+    { 0x0000001f, 0x40214a20, 0x000 },
+    { 0x96000000, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0200c00, 0x000 },
+    { 0x00000000, 0xc0201000, 0x000 },
+    { 0x0000001f, 0x00211624, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x0000001d, 0x00203623, 0x000 },
+    { 0x00000003, 0x00281e23, 0x000 },
+    { 0x00000008, 0x00222223, 0x000 },
+    { 0xfffff000, 0x00282228, 0x000 },
+    { 0x00000000, 0x002920e8, 0x000 },
+    { 0x0000001f, 0x00203628, 0x000 },
+    { 0x00000018, 0x00211e23, 0x000 },
+    { 0x00000020, 0x00203627, 0x000 },
+    { 0x00000002, 0x00221624, 0x000 },
+    { 0x00000000, 0x003014a8, 0x000 },
+    { 0x0000001e, 0x00203625, 0x000 },
+    { 0x00000003, 0x00211a24, 0x000 },
+    { 0x10000000, 0x00281a26, 0x000 },
+    { 0xefffffff, 0x00283a2e, 0x000 },
+    { 0x00000000, 0x004938ce, 0x610 },
+    { 0x00000001, 0x40280a20, 0x000 },
+    { 0x00000006, 0x40280e20, 0x000 },
+    { 0x00000300, 0xc0281220, 0x000 },
+    { 0x00000008, 0x00211224, 0x000 },
+    { 0x00000000, 0xc0201620, 0x000 },
+    { 0x00000000, 0xc0201a20, 0x000 },
+    { 0x00000000, 0x00210222, 0x000 },
+    { 0x00000000, 0x14c00000, 0x56c },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00002258, 0x00300a24, 0x000 },
+    { 0x00040000, 0x00694622, 0x622 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x00020000, 0x00294a26, 0x000 },
+    { 0x00000000, 0x00204810, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x574 },
+    { 0x00000000, 0xc0201c10, 0x000 },
+    { 0x00000000, 0xc0400000, 0x582 },
+    { 0x00000002, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x574 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00002258, 0x00300a24, 0x000 },
+    { 0x00040000, 0x00694622, 0x622 },
+    { 0x00000000, 0xc0201c10, 0x000 },
+    { 0x00000000, 0xc0400000, 0x582 },
+    { 0x00000000, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x578 },
+    { 0x00000000, 0xc0201c00, 0x000 },
+    { 0x00000000, 0xc0400000, 0x582 },
+    { 0x00000004, 0x002f0223, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x580 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x0000216d, 0x00204411, 0x000 },
+    { 0x00000000, 0xc0204800, 0x000 },
+    { 0x00000000, 0xc0604800, 0x627 },
+    { 0x00000000, 0x00401c10, 0x582 },
+    { 0x00000000, 0xc0200000, 0x000 },
+    { 0x00000000, 0xc0400000, 0x000 },
+    { 0x00000000, 0x0ee00000, 0x584 },
+    { 0x00000000, 0x00600000, 0x5c3 },
+    { 0x00000000, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x592 },
+    { 0x0000a2b7, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x00000033, 0x0020262d, 0x000 },
+    { 0x0000001a, 0x00212229, 0x000 },
+    { 0x00000006, 0x00222629, 0x000 },
+    { 0x0000a2c4, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x590 },
+    { 0x0000a2d1, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d1, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x00000001, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5a0 },
+    { 0x0000a2bb, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x00000034, 0x0020262d, 0x000 },
+    { 0x0000001a, 0x00212229, 0x000 },
+    { 0x00000006, 0x00222629, 0x000 },
+    { 0x0000a2c5, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x59e },
+    { 0x0000a2d2, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d2, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x00000002, 0x002f0224, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x5ae },
+    { 0x0000a2bf, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x00000035, 0x0020262d, 0x000 },
+    { 0x0000001a, 0x00212229, 0x000 },
+    { 0x00000006, 0x00222629, 0x000 },
+    { 0x0000a2c6, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x5ac },
+    { 0x0000a2d3, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d3, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x0000a2c3, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204807, 0x000 },
+    { 0x00000036, 0x0020262d, 0x000 },
+    { 0x0000001a, 0x00212229, 0x000 },
+    { 0x00000006, 0x00222629, 0x000 },
+    { 0x0000a2c7, 0x00204411, 0x000 },
+    { 0x00000000, 0x003048e9, 0x000 },
+    { 0x00000000, 0x00e00000, 0x5b8 },
+    { 0x0000a2d4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404808, 0x000 },
+    { 0x0000a2d4, 0x00204411, 0x000 },
+    { 0x00000001, 0x00504a28, 0x000 },
+    { 0x85000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0x0000304a, 0x00204411, 0x000 },
+    { 0x01000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x00400000, 0x5be },
+    { 0xa4000000, 0xc0204411, 0x000 },
+    { 0x00000000, 0xc0404800, 0x000 },
+    { 0x00000000, 0xc0600000, 0x5c3 },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x0000003f, 0x00204811, 0x000 },
+    { 0x00000005, 0x00204811, 0x000 },
+    { 0x0000a1f4, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x88000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0xff000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x00000002, 0x00804811, 0x000 },
+    { 0x00000000, 0x0ee00000, 0x5d6 },
+    { 0x00001000, 0x00200811, 0x000 },
+    { 0x0000002b, 0x00203622, 0x000 },
+    { 0x00000000, 0x00600000, 0x5da },
+    { 0x00000000, 0x00600000, 0x5c3 },
+    { 0x98000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00804811, 0x000 },
+    { 0x00000000, 0xc0600000, 0x5da },
+    { 0x00000000, 0xc0400400, 0x001 },
+    { 0x0000a2a4, 0x00204411, 0x000 },
+    { 0x00000022, 0x00204811, 0x000 },
+    { 0x89000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00404811, 0x5cd },
+    { 0x97000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x8a000000, 0x00204411, 0x000 },
+    { 0x00000000, 0x00404811, 0x5cd },
+    { 0x00000000, 0x00600000, 0x5f3 },
+    { 0x0001a2a4, 0xc0204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x374 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00010000, 0x00204811, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x09800000, 0x00204811, 0x000 },
+    { 0xffffffff, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x0004217f, 0x00604411, 0x622 },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x000 },
+    { 0x00000004, 0x00404c11, 0x5ed },
+    { 0x00000000, 0x00400000, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000004, 0x00291e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0xfffffffb, 0x00281e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0x00000008, 0x00291e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x00000017, 0x00201e2d, 0x000 },
+    { 0xfffffff7, 0x00281e27, 0x000 },
+    { 0x00000017, 0x00803627, 0x000 },
+    { 0x0001a2a4, 0x00204411, 0x000 },
+    { 0x00000016, 0x00604811, 0x374 },
+    { 0x00002010, 0x00204411, 0x000 },
+    { 0x00010000, 0x00204811, 0x000 },
+    { 0x0000217c, 0x00204411, 0x000 },
+    { 0x01800000, 0x00204811, 0x000 },
+    { 0xffffffff, 0x00204811, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000000, 0x17000000, 0x000 },
+    { 0x81000000, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0004217f, 0x00604411, 0x622 },
+    { 0x0000001f, 0x00210230, 0x000 },
+    { 0x00000000, 0x14c00000, 0x621 },
+    { 0x00000010, 0x00404c11, 0x607 },
+    { 0x00000000, 0xc0200400, 0x000 },
+    { 0x00000000, 0x38c00000, 0x000 },
+    { 0x0000001d, 0x00200a2d, 0x000 },
+    { 0x0000001e, 0x00200e2d, 0x000 },
+    { 0x0000001f, 0x0020122d, 0x000 },
+    { 0x00000020, 0x0020162d, 0x000 },
+    { 0x00002169, 0x00204411, 0x000 },
+    { 0x00000000, 0x00204804, 0x000 },
+    { 0x00000000, 0x00204805, 0x000 },
+    { 0x00000000, 0x00204801, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000004, 0x00301224, 0x000 },
+    { 0x00000000, 0x002f0064, 0x000 },
+    { 0x00000000, 0x0cc00000, 0x620 },
+    { 0x00000003, 0x00281a22, 0x000 },
+    { 0x00000008, 0x00221222, 0x000 },
+    { 0xfffff000, 0x00281224, 0x000 },
+    { 0x00000000, 0x002910c4, 0x000 },
+    { 0x0000001f, 0x00403624, 0x000 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x1ac00000, 0x622 },
+    { 0x9f000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000000, 0x1ae00000, 0x625 },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x1ac00000, 0x627 },
+    { 0x9e000000, 0x00204411, 0x000 },
+    { 0xcafebabe, 0x00204811, 0x000 },
+    { 0x00000000, 0x1ae00000, 0x62a },
+    { 0x00000000, 0x00800000, 0x000 },
+    { 0x00000000, 0x00600000, 0x00b },
+    { 0x00001000, 0x00600411, 0x315 },
+    { 0x00000000, 0x00200411, 0x000 },
+    { 0x00000000, 0x00600811, 0x1b2 },
+    { 0x0000225c, 0x00204411, 0x000 },
+    { 0x00000003, 0x00204811, 0x000 },
+    { 0x00002256, 0x00204411, 0x000 },
+    { 0x0000001b, 0x00204811, 0x000 },
+    { 0x0000a1fc, 0x00204411, 0x000 },
+    { 0x00000001, 0x00204811, 0x000 },
+    { 0x0001a1fd, 0xc0204411, 0x000 },
+    { 0x00000021, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000024, 0x0020222d, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000022, 0x0020222d, 0x000 },
+    { 0x0000ffff, 0x00282228, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00204811, 0x000 },
+    { 0x00000023, 0x00201e2d, 0x000 },
+    { 0x00000010, 0x00221e27, 0x000 },
+    { 0x00000000, 0x00294907, 0x000 },
+    { 0x00000000, 0x00404811, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x00000000, 0x00000000, 0x000 },
+    { 0x0142050a, 0x05ba0250, 0x000 },
+    { 0x01c30168, 0x044105ba, 0x000 },
+    { 0x02250209, 0x02500151, 0x000 },
+    { 0x02230245, 0x02a00241, 0x000 },
+    { 0x03d705ba, 0x05ba05ba, 0x000 },
+    { 0x05e205e3, 0x031f05ba, 0x000 },
+    { 0x032005bf, 0x0320034a, 0x000 },
+    { 0x03340282, 0x034c033e, 0x000 },
+    { 0x05ba05ba, 0x05ba05ba, 0x000 },
+    { 0x05ba0557, 0x05ba032a, 0x000 },
+    { 0x03bc05ba, 0x04c3034e, 0x000 },
+    { 0x04a20455, 0x043f05ba, 0x000 },
+    { 0x04d805ba, 0x044304e5, 0x000 },
+    { 0x0455050f, 0x035b037b, 0x000 },
+    { 0x05ba05ba, 0x05ba05ba, 0x000 },
+    { 0x05ba05ba, 0x05ba05ba, 0x000 },
+    { 0x05ba05ba, 0x05d805c1, 0x000 },
+    { 0x05ba05ba, 0x000705ba, 0x000 },
+    { 0x05ba05ba, 0x05ba05ba, 0x000 },
+    { 0x05ba05ba, 0x05ba05ba, 0x000 },
+    { 0x03f803ed, 0x04080406, 0x000 },
+    { 0x040e040a, 0x040c0410, 0x000 },
+    { 0x041c0418, 0x04240420, 0x000 },
+    { 0x042c0428, 0x04340430, 0x000 },
+    { 0x05ba05ba, 0x043a0438, 0x000 },
+    { 0x05ba05ba, 0x05ba05ba, 0x000 },
+    { 0x05ba05ba, 0x05ba05ba, 0x000 },
+    { 0x0002060e, 0x062c0006, 0x000 },
+};
+
+static const u32 RS780_pfp_microcode[] = {
+0xca0400,
+0xa00000,
+0x7e828b,
+0x7c038b,
+0x8001db,
+0x7c038b,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xc41838,
+0xca2400,
+0xca2800,
+0x9581cb,
+0xc41c3a,
+0xc3c000,
+0xca0800,
+0xca0c00,
+0x7c744b,
+0xc20005,
+0x99c000,
+0xc41c3a,
+0x7c744c,
+0xc0ffe0,
+0x042c08,
+0x309002,
+0x7d2500,
+0x351402,
+0x7d350b,
+0x255407,
+0x7cd580,
+0x259c07,
+0x95c004,
+0xd5001b,
+0x7eddc1,
+0x7d9d80,
+0xd6801b,
+0xd5801b,
+0xd4401e,
+0xd5401e,
+0xd6401e,
+0xd6801e,
+0xd4801e,
+0xd4c01e,
+0x9783d3,
+0xd5c01e,
+0xca0800,
+0x80001a,
+0xca0c00,
+0xe4011e,
+0xd4001e,
+0x80000c,
+0xc41838,
+0xe4013e,
+0xd4001e,
+0x80000c,
+0xc41838,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4013e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca0800,
+0xca0c00,
+0x8001db,
+0xd48024,
+0xca0800,
+0x7c00c0,
+0xc81425,
+0xc81824,
+0x7c9488,
+0x7c9880,
+0xc20003,
+0xd40075,
+0x7c744c,
+0x800064,
+0xd4401e,
+0xca1800,
+0xd4401e,
+0xd5801e,
+0x800062,
+0xd40075,
+0xd4401e,
+0xca0800,
+0xca0c00,
+0xca1000,
+0xd48019,
+0xd4c018,
+0xd50017,
+0xd4801e,
+0xd4c01e,
+0xd5001e,
+0xe2001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xd40075,
+0xd4401e,
+0xca0800,
+0xca0c00,
+0xca1000,
+0xd48019,
+0xd4c018,
+0xd50017,
+0xd4801e,
+0xd4c01e,
+0xd5001e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca0800,
+0x248c01,
+0xd48060,
+0x94c003,
+0x041001,
+0x041002,
+0xd50025,
+0xd4401e,
+0x800000,
+0xd4801e,
+0xca0800,
+0xd48061,
+0xd4401e,
+0x800000,
+0xd4801e,
+0xca0800,
+0xca0c00,
+0xd4401e,
+0xd48016,
+0xd4c016,
+0xd4801e,
+0x8001db,
+0xd4c01e,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x948004,
+0xca1400,
+0xe420f3,
+0xd42013,
+0xd56065,
+0xd4e01c,
+0xd5201c,
+0xd5601c,
+0x800000,
+0x062001,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x9483f7,
+0xca1400,
+0xe420f3,
+0x80009c,
+0xd42013,
+0xc60843,
+0xca0c00,
+0xca1000,
+0x9883ef,
+0xca1400,
+0xd40064,
+0x8000b0,
+0x000000,
+0xc41432,
+0xc61843,
+0xc4082f,
+0x954005,
+0xc40c30,
+0xd4401e,
+0x800000,
+0xee001e,
+0x9583f5,
+0xc41031,
+0xd44033,
+0xd52065,
+0xd4a01c,
+0xd4e01c,
+0xd5201c,
+0xe4015e,
+0xd4001e,
+0x800000,
+0x062001,
+0xca1800,
+0x0a2001,
+0xd60076,
+0xc40836,
+0x988007,
+0xc61045,
+0x950110,
+0xd4001f,
+0xd46062,
+0x800000,
+0xd42062,
+0xcc3835,
+0xcc1433,
+0x8401de,
+0xd40072,
+0xd5401e,
+0x800000,
+0xee001e,
+0xe2001a,
+0x8401de,
+0xe2001a,
+0xcc104b,
+0xcc0447,
+0x2c9401,
+0x7d098b,
+0x984005,
+0x7d15cb,
+0xd4001a,
+0x8001db,
+0xd4006d,
+0x344401,
+0xcc0c48,
+0x98403a,
+0xcc2c4a,
+0x958004,
+0xcc0449,
+0x8001db,
+0xd4001a,
+0xd4c01a,
+0x282801,
+0x840113,
+0xcc1003,
+0x98801b,
+0x04380c,
+0x840113,
+0xcc1003,
+0x988017,
+0x043808,
+0x840113,
+0xcc1003,
+0x988013,
+0x043804,
+0x840113,
+0xcc1003,
+0x988014,
+0xcc104c,
+0x9a8009,
+0xcc144d,
+0x9840dc,
+0xd4006d,
+0xcc1848,
+0xd5001a,
+0xd5401a,
+0x8000ec,
+0xd5801a,
+0x96c0d5,
+0xd4006d,
+0x8001db,
+0xd4006e,
+0x9ac003,
+0xd4006d,
+0xd4006e,
+0x800000,
+0xec007f,
+0x9ac0cc,
+0xd4006d,
+0x8001db,
+0xd4006e,
+0xcc1403,
+0xcc1803,
+0xcc1c03,
+0x7d9103,
+0x7dd583,
+0x7d190c,
+0x35cc1f,
+0x35701f,
+0x7cf0cb,
+0x7cd08b,
+0x880000,
+0x7e8e8b,
+0x95c004,
+0xd4006e,
+0x8001db,
+0xd4001a,
+0xd4c01a,
+0xcc0803,
+0xcc0c03,
+0xcc1003,
+0xcc1403,
+0xcc1803,
+0xcc1c03,
+0xcc2403,
+0xcc2803,
+0x35c41f,
+0x36b01f,
+0x7c704b,
+0x34f01f,
+0x7c704b,
+0x35701f,
+0x7c704b,
+0x7d8881,
+0x7dccc1,
+0x7e5101,
+0x7e9541,
+0x7c9082,
+0x7cd4c2,
+0x7c848b,
+0x9ac003,
+0x7c8c8b,
+0x2c8801,
+0x98809e,
+0xd4006d,
+0x98409c,
+0xd4006e,
+0xcc084c,
+0xcc0c4d,
+0xcc1048,
+0xd4801a,
+0xd4c01a,
+0x800124,
+0xd5001a,
+0xcc0832,
+0xd40032,
+0x9482b6,
+0xca0c00,
+0xd4401e,
+0x800000,
+0xd4001e,
+0xe4011e,
+0xd4001e,
+0xca0800,
+0xca0c00,
+0xca1000,
+0xd4401e,
+0xca1400,
+0xd4801e,
+0xd4c01e,
+0xd5001e,
+0xd5401e,
+0xd54034,
+0x800000,
+0xee001e,
+0x280404,
+0xe2001a,
+0xe2001a,
+0xd4401a,
+0xca3800,
+0xcc0803,
+0xcc0c03,
+0xcc0c03,
+0xcc0c03,
+0x98829a,
+0x000000,
+0x8401de,
+0xd7a06f,
+0x800000,
+0xee001f,
+0xca0400,
+0xc2ff00,
+0xcc0834,
+0xc13fff,
+0x7c74cb,
+0x7cc90b,
+0x7d010f,
+0x99028d,
+0x7c738b,
+0x8401de,
+0xd7a06f,
+0x800000,
+0xee001f,
+0xca0800,
+0x281900,
+0x7d898b,
+0x958014,
+0x281404,
+0xca0c00,
+0xca1000,
+0xca1c00,
+0xca2400,
+0xe2001f,
+0xd4c01a,
+0xd5001a,
+0xd5401a,
+0xcc1803,
+0xcc2c03,
+0xcc2c03,
+0xcc2c03,
+0x7da58b,
+0x7d9c47,
+0x984274,
+0x000000,
+0x800184,
+0xd4c01a,
+0xd4401e,
+0xd4801e,
+0x800000,
+0xee001e,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xe4013e,
+0xd4001e,
+0xd4401e,
+0xee001e,
+0xca0400,
+0xa00000,
+0x7e828b,
+0xca0800,
+0x248c06,
+0x0ccc06,
+0x98c006,
+0xcc104e,
+0x990004,
+0xd40073,
+0xe4011e,
+0xd4001e,
+0xd4401e,
+0xd4801e,
+0x800000,
+0xee001e,
+0xca0800,
+0xca0c00,
+0x34d018,
+0x251001,
+0x950021,
+0xc17fff,
+0xca1000,
+0xca1400,
+0xca1800,
+0xd4801d,
+0xd4c01d,
+0x7db18b,
+0xc14202,
+0xc2c001,
+0xd5801d,
+0x34dc0e,
+0x7d5d4c,
+0x7f734c,
+0xd7401e,
+0xd5001e,
+0xd5401e,
+0xc14200,
+0xc2c000,
+0x099c01,
+0x31dc10,
+0x7f5f4c,
+0x7f734c,
+0x042802,
+0x7d8380,
+0xd5a86f,
+0xd58066,
+0xd7401e,
+0xec005e,
+0xc82402,
+0xc82402,
+0x8001db,
+0xd60076,
+0xd4401e,
+0xd4801e,
+0xd4c01e,
+0x800000,
+0xee001e,
+0x800000,
+0xee001f,
+0xd4001f,
+0x800000,
+0xd4001f,
+0xd4001f,
+0x880000,
+0xd4001f,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x000000,
+0x010194,
+0x02019b,
+0x0300b2,
+0x0400a2,
+0x050003,
+0x06003f,
+0x070032,
+0x08014f,
+0x090046,
+0x0a0036,
+0x1001d9,
+0x1700c5,
+0x22015d,
+0x23016c,
+0x2000d7,
+0x240148,
+0x26004d,
+0x27005c,
+0x28008d,
+0x290051,
+0x2a007e,
+0x2b0061,
+0x2f0088,
+0x3200aa,
+0x3401a2,
+0x36006f,
+0x3c0179,
+0x3f0095,
+0x4101af,
+0x440151,
+0x550196,
+0x56019d,
+0x60000b,
+0x610034,
+0x620038,
+0x630038,
+0x640038,
+0x650038,
+0x660038,
+0x670038,
+0x68003a,
+0x690041,
+0x6a0048,
+0x6b0048,
+0x6c0048,
+0x6d0048,
+0x6e0048,
+0x6f0048,
+0x7301d9,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+0x000006,
+};
+
+static const u32 RV770_cp_microcode[] = {
+0xcc0003ea,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x80000001,
+0xd040007f,
+0x80000001,
+0xcc400041,
+0x7c40c000,
+0xc0160004,
+0x30d03fff,
+0x7d15000c,
+0xcc110000,
+0x28d8001e,
+0x31980001,
+0x28dc001f,
+0xc8200004,
+0x95c00006,
+0x7c424000,
+0xcc000062,
+0x7e56800c,
+0xcc290000,
+0xc8240004,
+0x7e26000b,
+0x95800006,
+0x7c42c000,
+0xcc000062,
+0x7ed7000c,
+0xcc310000,
+0xc82c0004,
+0x7e2e000c,
+0xcc000062,
+0x31103fff,
+0x80000001,
+0xce110000,
+0x7c40c000,
+0x80000001,
+0xcc400040,
+0x80000001,
+0xcc412257,
+0x7c418000,
+0xcc400045,
+0xcc400048,
+0xcc41225c,
+0xcc41a1fc,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xcc400045,
+0xcc400048,
+0x7c40c000,
+0xcc41225c,
+0xcc41a1fc,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xcc000045,
+0xcc000048,
+0xcc41225c,
+0xcc41a1fc,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x040ca1fd,
+0xc0120001,
+0xcc000045,
+0xcc000048,
+0x7cd0c00c,
+0xcc41225c,
+0xcc41a1fc,
+0xd04d0000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x80000001,
+0xcc41225d,
+0x7c408000,
+0x7c40c000,
+0xc02a0002,
+0x7c410000,
+0x7d29000c,
+0x30940001,
+0x30980006,
+0x309c0300,
+0x29dc0008,
+0x7c420000,
+0x7c424000,
+0x9540000f,
+0xc02e0004,
+0x05f02258,
+0x7f2f000c,
+0xcc310000,
+0xc8280004,
+0xccc12169,
+0xcd01216a,
+0xce81216b,
+0x0db40002,
+0xcc01216c,
+0x9740000e,
+0x0db40000,
+0x8000007b,
+0xc834000a,
+0x0db40002,
+0x97400009,
+0x0db40000,
+0xc02e0004,
+0x05f02258,
+0x7f2f000c,
+0xcc310000,
+0xc8280004,
+0x8000007b,
+0xc834000a,
+0x97400004,
+0x7e028000,
+0x8000007b,
+0xc834000a,
+0x0db40004,
+0x9740ff8c,
+0x00000000,
+0xce01216d,
+0xce41216e,
+0xc8280003,
+0xc834000a,
+0x9b400004,
+0x043c0005,
+0x8400026d,
+0xcc000062,
+0x0df40000,
+0x9740000b,
+0xc82c03e6,
+0xce81a2b7,
+0xc0300006,
+0x7ef34028,
+0xc0300020,
+0x7f6b8020,
+0x7fb3c029,
+0xcf81a2c4,
+0x80000001,
+0xcfc1a2d1,
+0x0df40001,
+0x9740000b,
+0xc82c03e7,
+0xce81a2bb,
+0xc0300006,
+0x7ef34028,
+0xc0300020,
+0x7f6b8020,
+0x7fb3c029,
+0xcf81a2c5,
+0x80000001,
+0xcfc1a2d2,
+0x0df40002,
+0x9740000b,
+0xc82c03e8,
+0xce81a2bf,
+0xc0300006,
+0x7ef34028,
+0xc0300020,
+0x7f6b8020,
+0x7fb3c029,
+0xcf81a2c6,
+0x80000001,
+0xcfc1a2d3,
+0xc82c03e9,
+0xce81a2c3,
+0xc0300006,
+0x7ef34028,
+0xc0300020,
+0x7f6b8020,
+0x7fb3c029,
+0xcf81a2c7,
+0x80000001,
+0xcfc1a2d4,
+0x80000001,
+0xcc400042,
+0x7c40c000,
+0x7c410000,
+0x2914001d,
+0x31540001,
+0x9940000d,
+0x31181000,
+0xc81c0011,
+0x09dc0001,
+0x95c0ffff,
+0xc81c0011,
+0xccc12100,
+0xcd012101,
+0xccc12102,
+0xcd012103,
+0x04180004,
+0x8000039f,
+0xcd81a2a4,
+0xc02a0004,
+0x95800008,
+0x36a821a3,
+0xcc290000,
+0xc8280004,
+0xc81c0011,
+0x0de40040,
+0x9640ffff,
+0xc81c0011,
+0xccc12170,
+0xcd012171,
+0xc8200012,
+0x96000000,
+0xc8200012,
+0x8000039f,
+0xcc000064,
+0x7c40c000,
+0x7c410000,
+0xcc000045,
+0xcc000048,
+0x40d40003,
+0xcd41225c,
+0xcd01a1fc,
+0xc01a0001,
+0x041ca1fd,
+0x7dd9c00c,
+0x7c420000,
+0x08cc0001,
+0x06240001,
+0x06280002,
+0xce1d0000,
+0xce5d0000,
+0x98c0fffa,
+0xce9d0000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x7c40c000,
+0x30d00001,
+0x28cc0001,
+0x7c414000,
+0x95000006,
+0x7c418000,
+0xcd41216d,
+0xcd81216e,
+0x800000f3,
+0xc81c0003,
+0xc0220004,
+0x7e16000c,
+0xcc210000,
+0xc81c0004,
+0x7c424000,
+0x98c00004,
+0x7c428000,
+0x80000001,
+0xcde50000,
+0xce412169,
+0xce81216a,
+0xcdc1216b,
+0x80000001,
+0xcc01216c,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0x7c41c000,
+0x28a40008,
+0x326400ff,
+0x0e68003c,
+0x9680000a,
+0x7c020000,
+0x7c420000,
+0x1e300003,
+0xcc00006a,
+0x9b000003,
+0x42200005,
+0x04200040,
+0x80000110,
+0x7c024000,
+0x7e024000,
+0x9a400000,
+0x0a640001,
+0x30ec0010,
+0x9ac0000a,
+0xcc000062,
+0xc02a0004,
+0xc82c0021,
+0x7e92800c,
+0xcc000041,
+0xcc290000,
+0xcec00021,
+0x80000120,
+0xc8300004,
+0xcd01216d,
+0xcd41216e,
+0xc8300003,
+0x7f1f000b,
+0x30f40007,
+0x27780001,
+0x9740002a,
+0x07b80125,
+0x9f800000,
+0x00000000,
+0x80000135,
+0x7f1b8004,
+0x80000139,
+0x7f1b8005,
+0x8000013d,
+0x7f1b8002,
+0x80000141,
+0x7f1b8003,
+0x80000145,
+0x7f1b8007,
+0x80000149,
+0x7f1b8006,
+0x8000014e,
+0x28a40008,
+0x9b800019,
+0x28a40008,
+0x8000015e,
+0x326400ff,
+0x9b800015,
+0x28a40008,
+0x8000015e,
+0x326400ff,
+0x9b800011,
+0x28a40008,
+0x8000015e,
+0x326400ff,
+0x9b80000d,
+0x28a40008,
+0x8000015e,
+0x326400ff,
+0x9b800009,
+0x28a40008,
+0x8000015e,
+0x326400ff,
+0x9b800005,
+0x28a40008,
+0x8000015e,
+0x326400ff,
+0x28a40008,
+0x326400ff,
+0x0e68003c,
+0x9a80feb1,
+0x28ec0008,
+0x7c434000,
+0x7c438000,
+0x7c43c000,
+0x96c00007,
+0xcc000062,
+0xcf412169,
+0xcf81216a,
+0xcfc1216b,
+0x80000001,
+0xcc01216c,
+0x80000001,
+0xcff50000,
+0xcc00006b,
+0x840003a2,
+0x0e68003c,
+0x9a800004,
+0xc8280015,
+0x80000001,
+0xd040007f,
+0x9680ffab,
+0x7e024000,
+0x8400023b,
+0xc00e0002,
+0xcc000041,
+0x80000239,
+0xccc1304a,
+0x7c40c000,
+0x7c410000,
+0xc01e0001,
+0x29240012,
+0xc0220002,
+0x96400005,
+0xc0260004,
+0xc027fffb,
+0x7d25000b,
+0xc0260000,
+0x7dd2800b,
+0x7e12c00b,
+0x7d25000c,
+0x7c414000,
+0x7c418000,
+0xccc12169,
+0x9a80000a,
+0xcd01216a,
+0xcd41216b,
+0x96c0fe82,
+0xcd81216c,
+0xc8300018,
+0x97000000,
+0xc8300018,
+0x80000001,
+0xcc000018,
+0x840003a2,
+0xcc00007f,
+0xc8140013,
+0xc8180014,
+0xcd41216b,
+0x96c0fe76,
+0xcd81216c,
+0x80000182,
+0xc8300018,
+0xc80c0008,
+0x98c00000,
+0xc80c0008,
+0x7c410000,
+0x95000002,
+0x00000000,
+0x7c414000,
+0xc8200009,
+0xcc400043,
+0xce01a1f4,
+0xcc400044,
+0xc00e8000,
+0x7c424000,
+0x7c428000,
+0x2aac001f,
+0x96c0fe63,
+0xc035f000,
+0xce4003e2,
+0x32780003,
+0x267c0008,
+0x7ff7c00b,
+0x7ffbc00c,
+0x2a780018,
+0xcfc003e3,
+0xcf8003e4,
+0x26b00002,
+0x7f3f0000,
+0xcf0003e5,
+0x8000031f,
+0x7c80c000,
+0x7c40c000,
+0x28d00008,
+0x3110000f,
+0x9500000f,
+0x25280001,
+0x06a801b3,
+0x9e800000,
+0x00000000,
+0x800001d4,
+0xc0120800,
+0x800001e2,
+0xc814000f,
+0x800001e9,
+0xc8140010,
+0x800001f0,
+0xccc1a2a4,
+0x800001f9,
+0xc8140011,
+0x30d0003f,
+0x0d280015,
+0x9a800012,
+0x0d28001e,
+0x9a80001e,
+0x0d280020,
+0x9a800023,
+0x0d24000f,
+0x0d280010,
+0x7e6a800c,
+0x9a800026,
+0x0d200004,
+0x0d240014,
+0x0d280028,
+0x7e62400c,
+0x7ea6800c,
+0x9a80002a,
+0xc8140011,
+0x80000001,
+0xccc1a2a4,
+0xc0120800,
+0x7c414000,
+0x7d0cc00c,
+0xc0120008,
+0x29580003,
+0x295c000c,
+0x7c420000,
+0x7dd1c00b,
+0x26200014,
+0x7e1e400c,
+0x7e4e800c,
+0xce81a2a4,
+0x80000001,
+0xcd81a1fe,
+0xc814000f,
+0x0410210e,
+0x95400000,
+0xc814000f,
+0xd0510000,
+0x80000001,
+0xccc1a2a4,
+0xc8140010,
+0x04102108,
+0x95400000,
+0xc8140010,
+0xd0510000,
+0x80000001,
+0xccc1a2a4,
+0xccc1a2a4,
+0x04100001,
+0xcd000019,
+0x840003a2,
+0xcc00007f,
+0xc8100019,
+0x99000000,
+0xc8100019,
+0x80000002,
+0x7c408000,
+0x04102100,
+0x09540001,
+0x9540ffff,
+0xc8140011,
+0xd0510000,
+0x8000039f,
+0xccc1a2a4,
+0x7c40c000,
+0xcc40000d,
+0x94c0fdff,
+0xcc40000e,
+0x7c410000,
+0x95000005,
+0x08cc0001,
+0xc8140005,
+0x99400014,
+0x00000000,
+0x98c0fffb,
+0x7c410000,
+0x80000002,
+0x7d008000,
+0xc8140005,
+0x7c40c000,
+0x9940000c,
+0xc818000c,
+0x7c410000,
+0x9580fdee,
+0xc820000e,
+0xc81c000d,
+0x66200020,
+0x7e1e002c,
+0x25240002,
+0x7e624020,
+0x80000001,
+0xcce60000,
+0x7c410000,
+0xcc00006c,
+0xcc00006d,
+0xc818001f,
+0xc81c001e,
+0x65980020,
+0x7dd9c02c,
+0x7cd4c00c,
+0xccde0000,
+0x45dc0004,
+0xc8280017,
+0x9680000f,
+0xc00e0001,
+0x28680008,
+0x2aac0016,
+0x32a800ff,
+0x0eb00049,
+0x7f2f000b,
+0x97000006,
+0x00000000,
+0xc8140005,
+0x7c40c000,
+0x80000223,
+0x7c410000,
+0x80000226,
+0xd040007f,
+0x8400023b,
+0xcc000041,
+0xccc1304a,
+0x94000000,
+0xc83c001a,
+0x043c0005,
+0xcfc1a2a4,
+0xc0361f90,
+0xc0387fff,
+0x7c03c010,
+0x7f7b400c,
+0xcf41217c,
+0xcfc1217d,
+0xcc01217e,
+0xc03a0004,
+0x0434217f,
+0x7f7b400c,
+0xcc350000,
+0xc83c0004,
+0x2bfc001f,
+0x04380020,
+0x97c00005,
+0xcc000062,
+0x9b800000,
+0x0bb80001,
+0x80000247,
+0xcc000071,
+0xcc01a1f4,
+0x04380016,
+0xc0360002,
+0xcf81a2a4,
+0x88000000,
+0xcf412010,
+0x7c40c000,
+0x28d0001c,
+0x95000005,
+0x04d40001,
+0xcd400065,
+0x80000001,
+0xcd400068,
+0x09540002,
+0x80000001,
+0xcd400066,
+0x8400026c,
+0xc81803ea,
+0x7c40c000,
+0x9980fd9d,
+0xc8140016,
+0x08d00001,
+0x9940002b,
+0xcd000068,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x043c0005,
+0xcfc1a2a4,
+0xcc01a1f4,
+0x840003a2,
+0xcc000046,
+0x88000000,
+0xcc00007f,
+0x8400027e,
+0xc81803ea,
+0x7c40c000,
+0x9980fd8b,
+0xc8140016,
+0x08d00001,
+0x99400019,
+0xcd000068,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x043c0022,
+0xcfc1a2a4,
+0x840003a2,
+0xcc000047,
+0x88000000,
+0xcc00007f,
+0xc8100016,
+0x9900000d,
+0xcc400067,
+0x80000002,
+0x7c408000,
+0xc81803ea,
+0x9980fd77,
+0x7c40c000,
+0x94c00003,
+0xc8100016,
+0x99000004,
+0xccc00068,
+0x80000002,
+0x7c408000,
+0x8400023b,
+0xc0148000,
+0xcc000041,
+0xcd41304a,
+0xc0148000,
+0x99000000,
+0xc8100016,
+0x80000002,
+0x7c408000,
+0xc0120001,
+0x7c51400c,
+0x80000001,
+0xd0550000,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0x291c001f,
+0xccc0004a,
+0xcd00004b,
+0x95c00003,
+0xc01c8000,
+0xcdc12010,
+0xdd830000,
+0x055c2000,
+0xcc000062,
+0x80000001,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc0004c,
+0xcd00004d,
+0xdd830000,
+0x055ca000,
+0x80000001,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc0004e,
+0xcd00004f,
+0xdd830000,
+0x055cc000,
+0x80000001,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc00050,
+0xcd000051,
+0xdd830000,
+0x055cf8e0,
+0x80000001,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc00052,
+0xcd000053,
+0xdd830000,
+0x055cf880,
+0x80000001,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc00054,
+0xcd000055,
+0xdd830000,
+0x055ce000,
+0x80000001,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc00056,
+0xcd000057,
+0xdd830000,
+0x055cf000,
+0x80000001,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc00058,
+0xcd000059,
+0xdd830000,
+0x055cf3fc,
+0x80000001,
+0xd81f4100,
+0xd0432000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043a000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043c000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043f8e0,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043f880,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043e000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043f000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043f3fc,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xc81403e0,
+0xcc430000,
+0xcc430000,
+0xcc430000,
+0x7d45c000,
+0xcdc30000,
+0xd0430000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x7c40c000,
+0xc81003e2,
+0xc81403e5,
+0xc81803e3,
+0xc81c03e4,
+0xcd812169,
+0xcdc1216a,
+0xccc1216b,
+0xcc01216c,
+0x04200004,
+0x7da18000,
+0x7d964002,
+0x9640fcd7,
+0xcd8003e3,
+0x31280003,
+0xc02df000,
+0x25180008,
+0x7dad800b,
+0x7da9800c,
+0x80000001,
+0xcd8003e3,
+0x308cffff,
+0xd04d0000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x7c40c000,
+0x7c410000,
+0x29240018,
+0x32640001,
+0x9a400013,
+0xc8140020,
+0x15580002,
+0x9580ffff,
+0xc8140020,
+0xcc00006e,
+0xccc12180,
+0xcd01218d,
+0xcc412181,
+0x2914001f,
+0x34588000,
+0xcd81218c,
+0x9540fcb9,
+0xcc412182,
+0xc8140020,
+0x9940ffff,
+0xc8140020,
+0x80000002,
+0x7c408000,
+0x7c414000,
+0x7c418000,
+0x7c41c000,
+0x65b40020,
+0x7f57402c,
+0xd4378100,
+0x47740004,
+0xd4378100,
+0x47740004,
+0xd4378100,
+0x47740004,
+0x09dc0004,
+0xd4378100,
+0x99c0fff8,
+0x47740004,
+0x2924001f,
+0xc0380019,
+0x9640fca1,
+0xc03e0004,
+0xcf8121f8,
+0x37e021f9,
+0xcc210000,
+0xc8200004,
+0x2a200018,
+0x32200001,
+0x9a00fffb,
+0xcf8121f8,
+0x80000002,
+0x7c408000,
+0x7c40c000,
+0x28d00018,
+0x31100001,
+0xc0160080,
+0x95000003,
+0xc02a0004,
+0x7cd4c00c,
+0xccc1217c,
+0xcc41217d,
+0xcc41217e,
+0x7c418000,
+0x1db00003,
+0x36a0217f,
+0x9b000003,
+0x419c0005,
+0x041c0040,
+0x99c00000,
+0x09dc0001,
+0xcc210000,
+0xc8240004,
+0x2a6c001f,
+0x419c0005,
+0x9ac0fffa,
+0xcc800062,
+0x80000002,
+0x7c408000,
+0x7c40c000,
+0x04d403e6,
+0x80000001,
+0xcc540000,
+0x8000039f,
+0xcc4003ea,
+0xc01c8000,
+0x044ca000,
+0xcdc12010,
+0x7c410000,
+0xc8140009,
+0x04180000,
+0x041c0008,
+0xcd800071,
+0x09dc0001,
+0x05980001,
+0xcd0d0000,
+0x99c0fffc,
+0xcc800062,
+0x8000039f,
+0xcd400071,
+0xc00e0100,
+0xcc000041,
+0xccc1304a,
+0xc83c007f,
+0xcc00007f,
+0x80000001,
+0xcc00007f,
+0xcc00007f,
+0x88000000,
+0xcc00007f,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00010333,
+0x00100004,
+0x00170006,
+0x00210008,
+0x00270028,
+0x00280023,
+0x00290029,
+0x002a0026,
+0x002b0029,
+0x002d0038,
+0x002e003f,
+0x002f004a,
+0x0034004c,
+0x00360030,
+0x003900af,
+0x003a00d0,
+0x003b00e5,
+0x003c00fd,
+0x003d016c,
+0x003f00ad,
+0x00410338,
+0x0043036c,
+0x0044018f,
+0x004500fd,
+0x004601ad,
+0x004701ad,
+0x00480200,
+0x0049020e,
+0x004a0257,
+0x004b0284,
+0x00520261,
+0x00530273,
+0x00540289,
+0x0057029b,
+0x0060029f,
+0x006102ae,
+0x006202b8,
+0x006302c2,
+0x006402cc,
+0x006502d6,
+0x006602e0,
+0x006702ea,
+0x006802f4,
+0x006902f8,
+0x006a02fc,
+0x006b0300,
+0x006c0304,
+0x006d0308,
+0x006e030c,
+0x006f0310,
+0x00700314,
+0x00720386,
+0x0074038c,
+0x0079038a,
+0x007c031e,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+0x000f039b,
+};
+
+static const u32 RV770_pfp_microcode[] = {
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0x80000000,
+0xdc030000,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xc818000e,
+0x31980001,
+0x7c424000,
+0x95800252,
+0x7c428000,
+0xc81c001c,
+0xc037c000,
+0x7c40c000,
+0x7c410000,
+0x7cb4800b,
+0xc0360003,
+0x99c00000,
+0xc81c001c,
+0x7cb4800c,
+0x24d40002,
+0x7d654000,
+0xcd400043,
+0xce800043,
+0xcd000043,
+0xcc800040,
+0xce400040,
+0xce800040,
+0xccc00040,
+0xdc3a0000,
+0x9780ffde,
+0xcd000040,
+0x7c40c000,
+0x80000018,
+0x7c410000,
+0xd4000340,
+0xd4000fc0,
+0xd4000fa2,
+0xc818000e,
+0x8000000c,
+0x31980002,
+0xd40003c0,
+0xd4000fc0,
+0xd4000fa2,
+0xc818000e,
+0x288c0008,
+0x30cc000f,
+0x34100001,
+0x7d0d0008,
+0x8000000c,
+0x7d91800b,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xd4000340,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xd40003c0,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xcc4003f9,
+0x80000261,
+0xcc4003f8,
+0xc82003f8,
+0xc81c03f9,
+0xc81803fb,
+0xc037ffff,
+0x7c414000,
+0xcf41a29e,
+0x66200020,
+0x7de1c02c,
+0x7d58c008,
+0x7cdcc020,
+0x68d00020,
+0xc0360003,
+0xcc000054,
+0x7cb4800c,
+0x8000006a,
+0xcc800040,
+0x7c418000,
+0xcd81a29e,
+0xcc800040,
+0xcd800040,
+0x80000068,
+0xcc000054,
+0xc019ffff,
+0xcc800040,
+0xcd81a29e,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0xccc1a1fa,
+0xcd01a1f9,
+0xcd41a29d,
+0xccc00040,
+0xcd000040,
+0xcd400040,
+0xcc400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xcc000054,
+0xcc800040,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0xccc1a1fa,
+0xcd01a1f9,
+0xcd41a29d,
+0xccc00040,
+0xcd000040,
+0xcd400040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0x7c40c000,
+0x30d00001,
+0xccc1a29f,
+0x95000003,
+0x04140001,
+0x04140002,
+0xcd4003fb,
+0xcc800040,
+0x80000000,
+0xccc00040,
+0x7c40c000,
+0xcc800040,
+0xccc1a2a2,
+0x80000000,
+0xccc00040,
+0x7c40c000,
+0x28d4001f,
+0xcc800040,
+0x95400003,
+0x7c410000,
+0xccc00057,
+0x2918001f,
+0xccc00040,
+0x95800003,
+0xcd000040,
+0xcd000058,
+0x80000261,
+0xcc00007f,
+0xc8200017,
+0xc8300022,
+0x9a000006,
+0x0e280001,
+0xc824001e,
+0x0a640001,
+0xd4001240,
+0xce400040,
+0xc036c000,
+0x96800007,
+0x37747900,
+0x041c0001,
+0xcf400040,
+0xcdc00040,
+0xcf0003fa,
+0x7c030000,
+0xca0c0010,
+0x7c410000,
+0x94c00004,
+0x7c414000,
+0xd42002c4,
+0xcde00044,
+0x9b00000b,
+0x7c418000,
+0xcc00004b,
+0xcda00049,
+0xcd200041,
+0xcd600041,
+0xcda00041,
+0x06200001,
+0xce000056,
+0x80000261,
+0xcc00007f,
+0xc8280020,
+0xc82c0021,
+0xcc000063,
+0x7eea4001,
+0x65740020,
+0x7f53402c,
+0x269c0002,
+0x7df5c020,
+0x69f80020,
+0xce80004b,
+0xce600049,
+0xcde00041,
+0xcfa00041,
+0xce600041,
+0x271c0002,
+0x7df5c020,
+0x69f80020,
+0x7db24001,
+0xcf00004b,
+0xce600049,
+0xcde00041,
+0xcfa00041,
+0x800000bd,
+0xce600041,
+0xc8200017,
+0xc8300022,
+0x9a000006,
+0x0e280001,
+0xc824001e,
+0x0a640001,
+0xd4001240,
+0xce400040,
+0xca0c0010,
+0x7c410000,
+0x94c0000b,
+0xc036c000,
+0x96800007,
+0x37747900,
+0x041c0001,
+0xcf400040,
+0xcdc00040,
+0xcf0003fa,
+0x7c030000,
+0x800000b6,
+0x7c414000,
+0xcc000048,
+0x800000ef,
+0x00000000,
+0xc8200017,
+0xc81c0023,
+0x0e240002,
+0x99c00015,
+0x7c418000,
+0x0a200001,
+0xce000056,
+0xd4000440,
+0xcc000040,
+0xc036c000,
+0xca140013,
+0x96400007,
+0x37747900,
+0xcf400040,
+0xcc000040,
+0xc83003fa,
+0x80000104,
+0xcf000022,
+0xcc000022,
+0x9540015d,
+0xcc00007f,
+0xcca00046,
+0x80000000,
+0xcc200046,
+0x80000261,
+0xcc000064,
+0xc8200017,
+0xc810001f,
+0x96000005,
+0x09100001,
+0xd4000440,
+0xcd000040,
+0xcd000022,
+0xcc800040,
+0xd0400040,
+0xc80c0025,
+0x94c0feeb,
+0xc8100008,
+0xcd000040,
+0xd4000fc0,
+0x80000000,
+0xd4000fa2,
+0x7c40c000,
+0x7c410000,
+0xccc003fd,
+0xcd0003fc,
+0xccc00042,
+0xcd000042,
+0x2914001f,
+0x29180010,
+0x31980007,
+0x3b5c0001,
+0x7d76000b,
+0x99800005,
+0x7d5e400b,
+0xcc000042,
+0x80000261,
+0xcc00004d,
+0x29980001,
+0x292c0008,
+0x9980003d,
+0x32ec0001,
+0x96000004,
+0x2930000c,
+0x80000261,
+0xcc000042,
+0x04140010,
+0xcd400042,
+0x33300001,
+0x34280001,
+0x8400015e,
+0xc8140003,
+0x9b40001b,
+0x0438000c,
+0x8400015e,
+0xc8140003,
+0x9b400017,
+0x04380008,
+0x8400015e,
+0xc8140003,
+0x9b400013,
+0x04380004,
+0x8400015e,
+0xc8140003,
+0x9b400015,
+0xc80c03fd,
+0x9a800009,
+0xc81003fc,
+0x9b000118,
+0xcc00004d,
+0x04140010,
+0xccc00042,
+0xcd000042,
+0x80000136,
+0xcd400042,
+0x96c00111,
+0xcc00004d,
+0x80000261,
+0xcc00004e,
+0x9ac00003,
+0xcc00004d,
+0xcc00004e,
+0xdf830000,
+0x80000000,
+0xd80301ff,
+0x9ac00107,
+0xcc00004d,
+0x80000261,
+0xcc00004e,
+0xc8180003,
+0xc81c0003,
+0xc8200003,
+0x7d5d4003,
+0x7da1c003,
+0x7d5d400c,
+0x2a10001f,
+0x299c001f,
+0x7d1d000b,
+0x7d17400b,
+0x88000000,
+0x7e92800b,
+0x96400004,
+0xcc00004e,
+0x80000261,
+0xcc000042,
+0x04380008,
+0xcf800042,
+0xc8080003,
+0xc80c0003,
+0xc8100003,
+0xc8140003,
+0xc8180003,
+0xc81c0003,
+0xc8240003,
+0xc8280003,
+0x29fc001f,
+0x2ab0001f,
+0x7ff3c00b,
+0x28f0001f,
+0x7ff3c00b,
+0x2970001f,
+0x7ff3c00b,
+0x7d888001,
+0x7dccc001,
+0x7e510001,
+0x7e954001,
+0x7c908002,
+0x7cd4c002,
+0x7cbc800b,
+0x9ac00003,
+0x7c8f400b,
+0x38b40001,
+0x9b4000d8,
+0xcc00004d,
+0x9bc000d6,
+0xcc00004e,
+0xc80c03fd,
+0xc81003fc,
+0xccc00042,
+0x8000016f,
+0xcd000042,
+0xd4000340,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xcc400040,
+0xcc400040,
+0xcc400040,
+0x7c40c000,
+0xccc00040,
+0xccc0000d,
+0x80000000,
+0xd0400040,
+0x7c40c000,
+0x7c410000,
+0x65140020,
+0x7d4d402c,
+0x24580002,
+0x7d598020,
+0x7c41c000,
+0xcd800042,
+0x69980020,
+0xcd800042,
+0xcdc00042,
+0xc023c000,
+0x05e40002,
+0x7ca0800b,
+0x26640010,
+0x7ca4800c,
+0xcc800040,
+0xcdc00040,
+0xccc00040,
+0x95c0000e,
+0xcd000040,
+0x09dc0001,
+0xc8280003,
+0x96800008,
+0xce800040,
+0xc834001d,
+0x97400000,
+0xc834001d,
+0x26a80008,
+0x84000264,
+0xcc2b0000,
+0x99c0fff7,
+0x09dc0001,
+0xdc3a0000,
+0x97800004,
+0x7c418000,
+0x800001a3,
+0x25980002,
+0xa0000000,
+0x7d808000,
+0xc818001d,
+0x7c40c000,
+0x64d00008,
+0x95800000,
+0xc818001d,
+0xcc130000,
+0xcc800040,
+0xccc00040,
+0x80000000,
+0xcc400040,
+0xc810001f,
+0x7c40c000,
+0xcc800040,
+0x7cd1400c,
+0xcd400040,
+0x05180001,
+0x80000000,
+0xcd800022,
+0x7c40c000,
+0x64500020,
+0x84000264,
+0xcc000061,
+0x7cd0c02c,
+0xc8200017,
+0xc8d60000,
+0x99400008,
+0x7c438000,
+0xdf830000,
+0xcfa0004f,
+0x84000264,
+0xcc000062,
+0x80000000,
+0xd040007f,
+0x80000261,
+0xcc000062,
+0x84000264,
+0xcc000061,
+0xc8200017,
+0x7c40c000,
+0xc036ff00,
+0xc810000d,
+0xc0303fff,
+0x7cf5400b,
+0x7d51800b,
+0x7d81800f,
+0x99800008,
+0x7cf3800b,
+0xdf830000,
+0xcfa0004f,
+0x84000264,
+0xcc000062,
+0x80000000,
+0xd040007f,
+0x80000261,
+0xcc000062,
+0x84000264,
+0x7c40c000,
+0x28dc0008,
+0x95c00019,
+0x30dc0010,
+0x7c410000,
+0x99c00004,
+0x64540020,
+0x80000209,
+0xc91d0000,
+0x7d15002c,
+0xc91e0000,
+0x7c420000,
+0x7c424000,
+0x7c418000,
+0x7de5c00b,
+0x7de28007,
+0x9a80000e,
+0x41ac0005,
+0x9ac00000,
+0x0aec0001,
+0x30dc0010,
+0x99c00004,
+0x00000000,
+0x8000020c,
+0xc91d0000,
+0x8000020c,
+0xc91e0000,
+0xcc800040,
+0xccc00040,
+0xd0400040,
+0xc80c0025,
+0x94c0fde3,
+0xc8100008,
+0xcd000040,
+0xd4000fc0,
+0x80000000,
+0xd4000fa2,
+0xd4000340,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xd40003c0,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0x7c40c000,
+0x30d00006,
+0x0d100006,
+0x99000007,
+0xc8140015,
+0x99400005,
+0xcc000052,
+0xd4000340,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xccc00040,
+0x80000000,
+0xd0400040,
+0x7c40c000,
+0xcc4d0000,
+0xdc3a0000,
+0x9780fdbc,
+0x04cc0001,
+0x80000243,
+0xcc4d0000,
+0x7c40c000,
+0x7c410000,
+0x29240018,
+0x32640001,
+0x9640000f,
+0xcc800040,
+0x7c414000,
+0x7c418000,
+0x7c41c000,
+0xccc00043,
+0xcd000043,
+0x31dc7fff,
+0xcdc00043,
+0xccc00040,
+0xcd000040,
+0xcd400040,
+0xcd800040,
+0x80000000,
+0xcdc00040,
+0xccc00040,
+0xcd000040,
+0x80000000,
+0xd0400040,
+0x80000000,
+0xd040007f,
+0xcc00007f,
+0x80000000,
+0xcc00007f,
+0xcc00007f,
+0x88000000,
+0xcc00007f,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00030223,
+0x0004022b,
+0x000500a0,
+0x00020003,
+0x0006003c,
+0x00070027,
+0x00080192,
+0x00090044,
+0x000a002d,
+0x0010025f,
+0x001700f1,
+0x002201d8,
+0x002301e9,
+0x0026004c,
+0x0027005f,
+0x0020011b,
+0x00280093,
+0x0029004f,
+0x002a0084,
+0x002b0065,
+0x002f008e,
+0x003200d9,
+0x00340233,
+0x00360075,
+0x0039010b,
+0x003c01fd,
+0x003f00a0,
+0x00410248,
+0x00440195,
+0x0048019e,
+0x004901c6,
+0x004a01d0,
+0x00550226,
+0x0056022e,
+0x0060000a,
+0x0061002a,
+0x00620030,
+0x00630030,
+0x00640030,
+0x00650030,
+0x00660030,
+0x00670030,
+0x00680037,
+0x0069003f,
+0x006a0047,
+0x006b0047,
+0x006c0047,
+0x006d0047,
+0x006e0047,
+0x006f0047,
+0x00700047,
+0x0073025f,
+0x007b0241,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+};
+
+static const u32 RV730_pfp_microcode[] = {
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0x80000000,
+0xdc030000,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xc818000e,
+0x31980001,
+0x7c424000,
+0x9580023a,
+0x7c428000,
+0xc81c001c,
+0xc037c000,
+0x7c40c000,
+0x7c410000,
+0x7cb4800b,
+0xc0360003,
+0x99c00000,
+0xc81c001c,
+0x7cb4800c,
+0x24d40002,
+0x7d654000,
+0xcd400043,
+0xce800043,
+0xcd000043,
+0xcc800040,
+0xce400040,
+0xce800040,
+0xccc00040,
+0xdc3a0000,
+0x9780ffde,
+0xcd000040,
+0x7c40c000,
+0x80000018,
+0x7c410000,
+0xd4000340,
+0xd4000fc0,
+0xd4000fa2,
+0xc818000e,
+0x8000000c,
+0x31980002,
+0xd40003c0,
+0xd4000fc0,
+0xd4000fa2,
+0xc818000e,
+0x288c0008,
+0x30cc000f,
+0x34100001,
+0x7d0d0008,
+0x8000000c,
+0x7d91800b,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xd4000340,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xd40003c0,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xcc4003f9,
+0x80000249,
+0xcc4003f8,
+0xc037ffff,
+0x7c414000,
+0xcf41a29e,
+0xc82003f8,
+0xc81c03f9,
+0x66200020,
+0xc81803fb,
+0x7de1c02c,
+0x7d58c008,
+0x7cdcc020,
+0x69100020,
+0xc0360003,
+0xcc000054,
+0x7cb4800c,
+0x80000069,
+0xcc800040,
+0x7c418000,
+0xcd81a29e,
+0xcc800040,
+0x80000067,
+0xcd800040,
+0xc019ffff,
+0xcc800040,
+0xcd81a29e,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0xccc1a1fa,
+0xcd01a1f9,
+0xcd41a29d,
+0xccc00040,
+0xcd000040,
+0xcd400040,
+0xcc400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xcc000054,
+0xcc800040,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0xccc1a1fa,
+0xcd01a1f9,
+0xcd41a29d,
+0xccc00040,
+0xcd000040,
+0xcd400040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0x7c40c000,
+0x30d00001,
+0xccc1a29f,
+0x95000003,
+0x04140001,
+0x04140002,
+0xcd4003fb,
+0xcc800040,
+0x80000000,
+0xccc00040,
+0x7c40c000,
+0xcc800040,
+0xccc1a2a2,
+0x80000000,
+0xccc00040,
+0x7c40c000,
+0x28d4001f,
+0xcc800040,
+0x95400003,
+0x7c410000,
+0xccc00057,
+0x2918001f,
+0xccc00040,
+0x95800003,
+0xcd000040,
+0xcd000058,
+0x80000249,
+0xcc00007f,
+0xc8200017,
+0xc8300022,
+0x9a000006,
+0x0e280001,
+0xc824001e,
+0x0a640001,
+0xd4001240,
+0xce400040,
+0xc036c000,
+0x96800007,
+0x37747900,
+0x041c0001,
+0xcf400040,
+0xcdc00040,
+0xcf0003fa,
+0x7c030000,
+0xca0c0010,
+0x7c410000,
+0x94c00004,
+0x7c414000,
+0xd42002c4,
+0xcde00044,
+0x9b00000b,
+0x7c418000,
+0xcc00004b,
+0xcda00049,
+0xcd200041,
+0xcd600041,
+0xcda00041,
+0x06200001,
+0xce000056,
+0x80000249,
+0xcc00007f,
+0xc8280020,
+0xc82c0021,
+0xcc000063,
+0x7eea4001,
+0x65740020,
+0x7f53402c,
+0x269c0002,
+0x7df5c020,
+0x69f80020,
+0xce80004b,
+0xce600049,
+0xcde00041,
+0xcfa00041,
+0xce600041,
+0x271c0002,
+0x7df5c020,
+0x69f80020,
+0x7db24001,
+0xcf00004b,
+0xce600049,
+0xcde00041,
+0xcfa00041,
+0x800000bc,
+0xce600041,
+0xc8200017,
+0xc8300022,
+0x9a000006,
+0x0e280001,
+0xc824001e,
+0x0a640001,
+0xd4001240,
+0xce400040,
+0xca0c0010,
+0x7c410000,
+0x94c0000b,
+0xc036c000,
+0x96800007,
+0x37747900,
+0x041c0001,
+0xcf400040,
+0xcdc00040,
+0xcf0003fa,
+0x7c030000,
+0x800000b5,
+0x7c414000,
+0xcc000048,
+0x800000ee,
+0x00000000,
+0xc8200017,
+0xc81c0023,
+0x0e240002,
+0x99c00015,
+0x7c418000,
+0x0a200001,
+0xce000056,
+0xd4000440,
+0xcc000040,
+0xc036c000,
+0xca140013,
+0x96400007,
+0x37747900,
+0xcf400040,
+0xcc000040,
+0xc83003fa,
+0x80000103,
+0xcf000022,
+0xcc000022,
+0x95400146,
+0xcc00007f,
+0xcca00046,
+0x80000000,
+0xcc200046,
+0x80000249,
+0xcc000064,
+0xc8200017,
+0xc810001f,
+0x96000005,
+0x09100001,
+0xd4000440,
+0xcd000040,
+0xcd000022,
+0xcc800040,
+0xd0400040,
+0xc80c0025,
+0x94c0feec,
+0xc8100008,
+0xcd000040,
+0xd4000fc0,
+0x80000000,
+0xd4000fa2,
+0x7c40c000,
+0x7c410000,
+0xccc003fd,
+0xcd0003fc,
+0xccc00042,
+0xcd000042,
+0x2914001f,
+0x29180010,
+0x31980007,
+0x3b5c0001,
+0x7d76000b,
+0x99800005,
+0x7d5e400b,
+0xcc000042,
+0x80000249,
+0xcc00004d,
+0x29980001,
+0x292c0008,
+0x9980003d,
+0x32ec0001,
+0x96000004,
+0x2930000c,
+0x80000249,
+0xcc000042,
+0x04140010,
+0xcd400042,
+0x33300001,
+0x34280001,
+0x8400015d,
+0xc8140003,
+0x9b40001b,
+0x0438000c,
+0x8400015d,
+0xc8140003,
+0x9b400017,
+0x04380008,
+0x8400015d,
+0xc8140003,
+0x9b400013,
+0x04380004,
+0x8400015d,
+0xc8140003,
+0x9b400015,
+0xc80c03fd,
+0x9a800009,
+0xc81003fc,
+0x9b000101,
+0xcc00004d,
+0x04140010,
+0xccc00042,
+0xcd000042,
+0x80000135,
+0xcd400042,
+0x96c000fa,
+0xcc00004d,
+0x80000249,
+0xcc00004e,
+0x9ac00003,
+0xcc00004d,
+0xcc00004e,
+0xdf830000,
+0x80000000,
+0xd80301ff,
+0x9ac000f0,
+0xcc00004d,
+0x80000249,
+0xcc00004e,
+0xc8180003,
+0xc81c0003,
+0xc8200003,
+0x7d5d4003,
+0x7da1c003,
+0x7d5d400c,
+0x2a10001f,
+0x299c001f,
+0x7d1d000b,
+0x7d17400b,
+0x88000000,
+0x7e92800b,
+0x96400004,
+0xcc00004e,
+0x80000249,
+0xcc000042,
+0x04380008,
+0xcf800042,
+0xc8080003,
+0xc80c0003,
+0xc8100003,
+0xc8140003,
+0xc8180003,
+0xc81c0003,
+0xc8240003,
+0xc8280003,
+0x29fc001f,
+0x2ab0001f,
+0x7ff3c00b,
+0x28f0001f,
+0x7ff3c00b,
+0x2970001f,
+0x7ff3c00b,
+0x7d888001,
+0x7dccc001,
+0x7e510001,
+0x7e954001,
+0x7c908002,
+0x7cd4c002,
+0x7cbc800b,
+0x9ac00003,
+0x7c8f400b,
+0x38b40001,
+0x9b4000c1,
+0xcc00004d,
+0x9bc000bf,
+0xcc00004e,
+0xc80c03fd,
+0xc81003fc,
+0xccc00042,
+0x8000016e,
+0xcd000042,
+0xd4000340,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xcc400040,
+0xcc400040,
+0xcc400040,
+0x7c40c000,
+0xccc00040,
+0xccc0000d,
+0x80000000,
+0xd0400040,
+0x7c40c000,
+0x7c410000,
+0x65140020,
+0x7d4d402c,
+0x24580002,
+0x7d598020,
+0x7c41c000,
+0xcd800042,
+0x69980020,
+0xcd800042,
+0xcdc00042,
+0xc023c000,
+0x05e40002,
+0x7ca0800b,
+0x26640010,
+0x7ca4800c,
+0xcc800040,
+0xcdc00040,
+0xccc00040,
+0x95c0000e,
+0xcd000040,
+0x09dc0001,
+0xc8280003,
+0x96800008,
+0xce800040,
+0xc834001d,
+0x97400000,
+0xc834001d,
+0x26a80008,
+0x8400024c,
+0xcc2b0000,
+0x99c0fff7,
+0x09dc0001,
+0xdc3a0000,
+0x97800004,
+0x7c418000,
+0x800001a2,
+0x25980002,
+0xa0000000,
+0x7d808000,
+0xc818001d,
+0x7c40c000,
+0x64d00008,
+0x95800000,
+0xc818001d,
+0xcc130000,
+0xcc800040,
+0xccc00040,
+0x80000000,
+0xcc400040,
+0xc810001f,
+0x7c40c000,
+0xcc800040,
+0x7cd1400c,
+0xcd400040,
+0x05180001,
+0x80000000,
+0xcd800022,
+0x7c40c000,
+0x64500020,
+0x8400024c,
+0xcc000061,
+0x7cd0c02c,
+0xc8200017,
+0xc8d60000,
+0x99400008,
+0x7c438000,
+0xdf830000,
+0xcfa0004f,
+0x8400024c,
+0xcc000062,
+0x80000000,
+0xd040007f,
+0x80000249,
+0xcc000062,
+0x8400024c,
+0xcc000061,
+0xc8200017,
+0x7c40c000,
+0xc036ff00,
+0xc810000d,
+0xc0303fff,
+0x7cf5400b,
+0x7d51800b,
+0x7d81800f,
+0x99800008,
+0x7cf3800b,
+0xdf830000,
+0xcfa0004f,
+0x8400024c,
+0xcc000062,
+0x80000000,
+0xd040007f,
+0x80000249,
+0xcc000062,
+0x8400024c,
+0x7c40c000,
+0x28dc0008,
+0x95c00019,
+0x30dc0010,
+0x7c410000,
+0x99c00004,
+0x64540020,
+0x80000208,
+0xc91d0000,
+0x7d15002c,
+0xc91e0000,
+0x7c420000,
+0x7c424000,
+0x7c418000,
+0x7de5c00b,
+0x7de28007,
+0x9a80000e,
+0x41ac0005,
+0x9ac00000,
+0x0aec0001,
+0x30dc0010,
+0x99c00004,
+0x00000000,
+0x8000020b,
+0xc91d0000,
+0x8000020b,
+0xc91e0000,
+0xcc800040,
+0xccc00040,
+0xd0400040,
+0xc80c0025,
+0x94c0fde4,
+0xc8100008,
+0xcd000040,
+0xd4000fc0,
+0x80000000,
+0xd4000fa2,
+0xd4000340,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xd40003c0,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0x7c40c000,
+0x30d00006,
+0x0d100006,
+0x99000007,
+0xc8140015,
+0x99400005,
+0xcc000052,
+0xd4000340,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xccc00040,
+0x80000000,
+0xd0400040,
+0x7c40c000,
+0xcc4d0000,
+0xdc3a0000,
+0x9780fdbd,
+0x04cc0001,
+0x80000242,
+0xcc4d0000,
+0x80000000,
+0xd040007f,
+0xcc00007f,
+0x80000000,
+0xcc00007f,
+0xcc00007f,
+0x88000000,
+0xcc00007f,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00030222,
+0x0004022a,
+0x0005009f,
+0x00020003,
+0x0006003c,
+0x00070027,
+0x00080191,
+0x00090044,
+0x000a002d,
+0x00100247,
+0x001700f0,
+0x002201d7,
+0x002301e8,
+0x0026004c,
+0x0027005f,
+0x0020011a,
+0x00280092,
+0x0029004f,
+0x002a0083,
+0x002b0064,
+0x002f008d,
+0x003200d8,
+0x00340232,
+0x00360074,
+0x0039010a,
+0x003c01fc,
+0x003f009f,
+0x00410005,
+0x00440194,
+0x0048019d,
+0x004901c5,
+0x004a01cf,
+0x00550225,
+0x0056022d,
+0x0060000a,
+0x0061002a,
+0x00620030,
+0x00630030,
+0x00640030,
+0x00650030,
+0x00660030,
+0x00670030,
+0x00680037,
+0x0069003f,
+0x006a0047,
+0x006b0047,
+0x006c0047,
+0x006d0047,
+0x006e0047,
+0x006f0047,
+0x00700047,
+0x00730247,
+0x007b0240,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+};
+
+static const u32 RV730_cp_microcode[] = {
+0xcc0003ea,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x80000001,
+0xd040007f,
+0x80000001,
+0xcc400041,
+0x7c40c000,
+0xc0160004,
+0x30d03fff,
+0x7d15000c,
+0xcc110000,
+0x28d8001e,
+0x31980001,
+0x28dc001f,
+0xc8200004,
+0x95c00006,
+0x7c424000,
+0xcc000062,
+0x7e56800c,
+0xcc290000,
+0xc8240004,
+0x7e26000b,
+0x95800006,
+0x7c42c000,
+0xcc000062,
+0x7ed7000c,
+0xcc310000,
+0xc82c0004,
+0x7e2e000c,
+0xcc000062,
+0x31103fff,
+0x80000001,
+0xce110000,
+0x7c40c000,
+0x80000001,
+0xcc400040,
+0x80000001,
+0xcc412257,
+0x7c418000,
+0xcc400045,
+0xcc400048,
+0xcc41225c,
+0xcc41a1fc,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xcc400045,
+0xcc400048,
+0x7c40c000,
+0xcc41225c,
+0xcc41a1fc,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xcc000045,
+0xcc000048,
+0xcc41225c,
+0xcc41a1fc,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x040ca1fd,
+0xc0120001,
+0xcc000045,
+0xcc000048,
+0x7cd0c00c,
+0xcc41225c,
+0xcc41a1fc,
+0xd04d0000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x80000001,
+0xcc41225d,
+0x7c408000,
+0x7c40c000,
+0xc02a0002,
+0x7c410000,
+0x7d29000c,
+0x30940001,
+0x30980006,
+0x309c0300,
+0x29dc0008,
+0x7c420000,
+0x7c424000,
+0x9540000f,
+0xc02e0004,
+0x05f02258,
+0x7f2f000c,
+0xcc310000,
+0xc8280004,
+0xccc12169,
+0xcd01216a,
+0xce81216b,
+0x0db40002,
+0xcc01216c,
+0x9740000e,
+0x0db40000,
+0x8000007b,
+0xc834000a,
+0x0db40002,
+0x97400009,
+0x0db40000,
+0xc02e0004,
+0x05f02258,
+0x7f2f000c,
+0xcc310000,
+0xc8280004,
+0x8000007b,
+0xc834000a,
+0x97400004,
+0x7e028000,
+0x8000007b,
+0xc834000a,
+0x0db40004,
+0x9740ff8c,
+0x00000000,
+0xce01216d,
+0xce41216e,
+0xc8280003,
+0xc834000a,
+0x9b400004,
+0x043c0005,
+0x8400026b,
+0xcc000062,
+0x0df40000,
+0x9740000b,
+0xc82c03e6,
+0xce81a2b7,
+0xc0300006,
+0x7ef34028,
+0xc0300020,
+0x7f6b8020,
+0x7fb3c029,
+0xcf81a2c4,
+0x80000001,
+0xcfc1a2d1,
+0x0df40001,
+0x9740000b,
+0xc82c03e7,
+0xce81a2bb,
+0xc0300006,
+0x7ef34028,
+0xc0300020,
+0x7f6b8020,
+0x7fb3c029,
+0xcf81a2c5,
+0x80000001,
+0xcfc1a2d2,
+0x0df40002,
+0x9740000b,
+0xc82c03e8,
+0xce81a2bf,
+0xc0300006,
+0x7ef34028,
+0xc0300020,
+0x7f6b8020,
+0x7fb3c029,
+0xcf81a2c6,
+0x80000001,
+0xcfc1a2d3,
+0xc82c03e9,
+0xce81a2c3,
+0xc0300006,
+0x7ef34028,
+0xc0300020,
+0x7f6b8020,
+0x7fb3c029,
+0xcf81a2c7,
+0x80000001,
+0xcfc1a2d4,
+0x80000001,
+0xcc400042,
+0x7c40c000,
+0x7c410000,
+0x2914001d,
+0x31540001,
+0x9940000c,
+0x31181000,
+0xc81c0011,
+0x95c00000,
+0xc81c0011,
+0xccc12100,
+0xcd012101,
+0xccc12102,
+0xcd012103,
+0x04180004,
+0x8000037c,
+0xcd81a2a4,
+0xc02a0004,
+0x95800008,
+0x36a821a3,
+0xcc290000,
+0xc8280004,
+0xc81c0011,
+0x0de40040,
+0x9640ffff,
+0xc81c0011,
+0xccc12170,
+0xcd012171,
+0xc8200012,
+0x96000000,
+0xc8200012,
+0x8000037c,
+0xcc000064,
+0x7c40c000,
+0x7c410000,
+0xcc000045,
+0xcc000048,
+0x40d40003,
+0xcd41225c,
+0xcd01a1fc,
+0xc01a0001,
+0x041ca1fd,
+0x7dd9c00c,
+0x7c420000,
+0x08cc0001,
+0x06240001,
+0x06280002,
+0xce1d0000,
+0xce5d0000,
+0x98c0fffa,
+0xce9d0000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x7c40c000,
+0x30d00001,
+0x28cc0001,
+0x7c414000,
+0x95000006,
+0x7c418000,
+0xcd41216d,
+0xcd81216e,
+0x800000f2,
+0xc81c0003,
+0xc0220004,
+0x7e16000c,
+0xcc210000,
+0xc81c0004,
+0x7c424000,
+0x98c00004,
+0x7c428000,
+0x80000001,
+0xcde50000,
+0xce412169,
+0xce81216a,
+0xcdc1216b,
+0x80000001,
+0xcc01216c,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0x7c41c000,
+0x28a40008,
+0x326400ff,
+0x0e68003c,
+0x9680000a,
+0x7c020000,
+0x7c420000,
+0x1e300003,
+0xcc00006a,
+0x9b000003,
+0x42200005,
+0x04200040,
+0x8000010f,
+0x7c024000,
+0x7e024000,
+0x9a400000,
+0x0a640001,
+0x30ec0010,
+0x9ac0000a,
+0xcc000062,
+0xc02a0004,
+0xc82c0021,
+0x7e92800c,
+0xcc000041,
+0xcc290000,
+0xcec00021,
+0x8000011f,
+0xc8300004,
+0xcd01216d,
+0xcd41216e,
+0xc8300003,
+0x7f1f000b,
+0x30f40007,
+0x27780001,
+0x9740002a,
+0x07b80124,
+0x9f800000,
+0x00000000,
+0x80000134,
+0x7f1b8004,
+0x80000138,
+0x7f1b8005,
+0x8000013c,
+0x7f1b8002,
+0x80000140,
+0x7f1b8003,
+0x80000144,
+0x7f1b8007,
+0x80000148,
+0x7f1b8006,
+0x8000014d,
+0x28a40008,
+0x9b800019,
+0x28a40008,
+0x8000015d,
+0x326400ff,
+0x9b800015,
+0x28a40008,
+0x8000015d,
+0x326400ff,
+0x9b800011,
+0x28a40008,
+0x8000015d,
+0x326400ff,
+0x9b80000d,
+0x28a40008,
+0x8000015d,
+0x326400ff,
+0x9b800009,
+0x28a40008,
+0x8000015d,
+0x326400ff,
+0x9b800005,
+0x28a40008,
+0x8000015d,
+0x326400ff,
+0x28a40008,
+0x326400ff,
+0x0e68003c,
+0x9a80feb2,
+0x28ec0008,
+0x7c434000,
+0x7c438000,
+0x7c43c000,
+0x96c00007,
+0xcc000062,
+0xcf412169,
+0xcf81216a,
+0xcfc1216b,
+0x80000001,
+0xcc01216c,
+0x80000001,
+0xcff50000,
+0xcc00006b,
+0x8400037f,
+0x0e68003c,
+0x9a800004,
+0xc8280015,
+0x80000001,
+0xd040007f,
+0x9680ffab,
+0x7e024000,
+0x84000239,
+0xc00e0002,
+0xcc000041,
+0x80000237,
+0xccc1304a,
+0x7c40c000,
+0x7c410000,
+0xc01e0001,
+0x29240012,
+0xc0220002,
+0x96400005,
+0xc0260004,
+0xc027fffb,
+0x7d25000b,
+0xc0260000,
+0x7dd2800b,
+0x7e12c00b,
+0x7d25000c,
+0x7c414000,
+0x7c418000,
+0xccc12169,
+0x9a80000a,
+0xcd01216a,
+0xcd41216b,
+0x96c0fe83,
+0xcd81216c,
+0xc8300018,
+0x97000000,
+0xc8300018,
+0x80000001,
+0xcc000018,
+0x8400037f,
+0xcc00007f,
+0xc8140013,
+0xc8180014,
+0xcd41216b,
+0x96c0fe77,
+0xcd81216c,
+0x80000181,
+0xc8300018,
+0xc80c0008,
+0x98c00000,
+0xc80c0008,
+0x7c410000,
+0x95000002,
+0x00000000,
+0x7c414000,
+0xc8200009,
+0xcc400043,
+0xce01a1f4,
+0xcc400044,
+0xc00e8000,
+0x7c424000,
+0x7c428000,
+0x2aac001f,
+0x96c0fe64,
+0xc035f000,
+0xce4003e2,
+0x32780003,
+0x267c0008,
+0x7ff7c00b,
+0x7ffbc00c,
+0x2a780018,
+0xcfc003e3,
+0xcf8003e4,
+0x26b00002,
+0x7f3f0000,
+0xcf0003e5,
+0x8000031d,
+0x7c80c000,
+0x7c40c000,
+0x28d00008,
+0x3110000f,
+0x9500000f,
+0x25280001,
+0x06a801b2,
+0x9e800000,
+0x00000000,
+0x800001d3,
+0xc0120800,
+0x800001e1,
+0xc814000f,
+0x800001e8,
+0xc8140010,
+0x800001ef,
+0xccc1a2a4,
+0x800001f8,
+0xc8140011,
+0x30d0003f,
+0x0d280015,
+0x9a800012,
+0x0d28001e,
+0x9a80001e,
+0x0d280020,
+0x9a800023,
+0x0d24000f,
+0x0d280010,
+0x7e6a800c,
+0x9a800026,
+0x0d200004,
+0x0d240014,
+0x0d280028,
+0x7e62400c,
+0x7ea6800c,
+0x9a80002a,
+0xc8140011,
+0x80000001,
+0xccc1a2a4,
+0xc0120800,
+0x7c414000,
+0x7d0cc00c,
+0xc0120008,
+0x29580003,
+0x295c000c,
+0x7c420000,
+0x7dd1c00b,
+0x26200014,
+0x7e1e400c,
+0x7e4e800c,
+0xce81a2a4,
+0x80000001,
+0xcd81a1fe,
+0xc814000f,
+0x0410210e,
+0x95400000,
+0xc814000f,
+0xd0510000,
+0x80000001,
+0xccc1a2a4,
+0xc8140010,
+0x04102108,
+0x95400000,
+0xc8140010,
+0xd0510000,
+0x80000001,
+0xccc1a2a4,
+0xccc1a2a4,
+0x04100001,
+0xcd000019,
+0x8400037f,
+0xcc00007f,
+0xc8100019,
+0x99000000,
+0xc8100019,
+0x80000002,
+0x7c408000,
+0x04102100,
+0x95400000,
+0xc8140011,
+0xd0510000,
+0x8000037c,
+0xccc1a2a4,
+0x7c40c000,
+0xcc40000d,
+0x94c0fe01,
+0xcc40000e,
+0x7c410000,
+0x95000005,
+0x08cc0001,
+0xc8140005,
+0x99400014,
+0x00000000,
+0x98c0fffb,
+0x7c410000,
+0x80000002,
+0x7d008000,
+0xc8140005,
+0x7c40c000,
+0x9940000c,
+0xc818000c,
+0x7c410000,
+0x9580fdf0,
+0xc820000e,
+0xc81c000d,
+0x66200020,
+0x7e1e002c,
+0x25240002,
+0x7e624020,
+0x80000001,
+0xcce60000,
+0x7c410000,
+0xcc00006c,
+0xcc00006d,
+0xc818001f,
+0xc81c001e,
+0x65980020,
+0x7dd9c02c,
+0x7cd4c00c,
+0xccde0000,
+0x45dc0004,
+0xc8280017,
+0x9680000f,
+0xc00e0001,
+0x28680008,
+0x2aac0016,
+0x32a800ff,
+0x0eb00049,
+0x7f2f000b,
+0x97000006,
+0x00000000,
+0xc8140005,
+0x7c40c000,
+0x80000221,
+0x7c410000,
+0x80000224,
+0xd040007f,
+0x84000239,
+0xcc000041,
+0xccc1304a,
+0x94000000,
+0xc83c001a,
+0x043c0005,
+0xcfc1a2a4,
+0xc0361f90,
+0xc0387fff,
+0x7c03c010,
+0x7f7b400c,
+0xcf41217c,
+0xcfc1217d,
+0xcc01217e,
+0xc03a0004,
+0x0434217f,
+0x7f7b400c,
+0xcc350000,
+0xc83c0004,
+0x2bfc001f,
+0x04380020,
+0x97c00005,
+0xcc000062,
+0x9b800000,
+0x0bb80001,
+0x80000245,
+0xcc000071,
+0xcc01a1f4,
+0x04380016,
+0xc0360002,
+0xcf81a2a4,
+0x88000000,
+0xcf412010,
+0x7c40c000,
+0x28d0001c,
+0x95000005,
+0x04d40001,
+0xcd400065,
+0x80000001,
+0xcd400068,
+0x09540002,
+0x80000001,
+0xcd400066,
+0x8400026a,
+0xc81803ea,
+0x7c40c000,
+0x9980fd9f,
+0xc8140016,
+0x08d00001,
+0x9940002b,
+0xcd000068,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x043c0005,
+0xcfc1a2a4,
+0xcc01a1f4,
+0x8400037f,
+0xcc000046,
+0x88000000,
+0xcc00007f,
+0x8400027c,
+0xc81803ea,
+0x7c40c000,
+0x9980fd8d,
+0xc8140016,
+0x08d00001,
+0x99400019,
+0xcd000068,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x043c0022,
+0xcfc1a2a4,
+0x8400037f,
+0xcc000047,
+0x88000000,
+0xcc00007f,
+0xc8100016,
+0x9900000d,
+0xcc400067,
+0x80000002,
+0x7c408000,
+0xc81803ea,
+0x9980fd79,
+0x7c40c000,
+0x94c00003,
+0xc8100016,
+0x99000004,
+0xccc00068,
+0x80000002,
+0x7c408000,
+0x84000239,
+0xc0148000,
+0xcc000041,
+0xcd41304a,
+0xc0148000,
+0x99000000,
+0xc8100016,
+0x80000002,
+0x7c408000,
+0xc0120001,
+0x7c51400c,
+0x80000001,
+0xd0550000,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0x291c001f,
+0xccc0004a,
+0xcd00004b,
+0x95c00003,
+0xc01c8000,
+0xcdc12010,
+0xdd830000,
+0x055c2000,
+0xcc000062,
+0x80000001,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc0004c,
+0xcd00004d,
+0xdd830000,
+0x055ca000,
+0x80000001,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc0004e,
+0xcd00004f,
+0xdd830000,
+0x055cc000,
+0x80000001,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc00050,
+0xcd000051,
+0xdd830000,
+0x055cf8e0,
+0x80000001,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc00052,
+0xcd000053,
+0xdd830000,
+0x055cf880,
+0x80000001,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc00054,
+0xcd000055,
+0xdd830000,
+0x055ce000,
+0x80000001,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc00056,
+0xcd000057,
+0xdd830000,
+0x055cf000,
+0x80000001,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc00058,
+0xcd000059,
+0xdd830000,
+0x055cf3fc,
+0x80000001,
+0xd81f4100,
+0xd0432000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043a000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043c000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043f8e0,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043f880,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043e000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043f000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043f3fc,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xc81403e0,
+0xcc430000,
+0xcc430000,
+0xcc430000,
+0x7d45c000,
+0xcdc30000,
+0xd0430000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x7c40c000,
+0xc81003e2,
+0xc81403e5,
+0xc81803e3,
+0xc81c03e4,
+0xcd812169,
+0xcdc1216a,
+0xccc1216b,
+0xcc01216c,
+0x04200004,
+0x7da18000,
+0x7d964002,
+0x9640fcd9,
+0xcd8003e3,
+0x31280003,
+0xc02df000,
+0x25180008,
+0x7dad800b,
+0x7da9800c,
+0x80000001,
+0xcd8003e3,
+0x308cffff,
+0xd04d0000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xc8140020,
+0x15580002,
+0x9580ffff,
+0xc8140020,
+0xcc00006e,
+0xcc412180,
+0x7c40c000,
+0xccc1218d,
+0xcc412181,
+0x28d0001f,
+0x34588000,
+0xcd81218c,
+0x9500fcbf,
+0xcc412182,
+0xc8140020,
+0x9940ffff,
+0xc8140020,
+0x80000002,
+0x7c408000,
+0x7c40c000,
+0x28d00018,
+0x31100001,
+0xc0160080,
+0x95000003,
+0xc02a0004,
+0x7cd4c00c,
+0xccc1217c,
+0xcc41217d,
+0xcc41217e,
+0x7c418000,
+0x1db00003,
+0x36a0217f,
+0x9b000003,
+0x419c0005,
+0x041c0040,
+0x99c00000,
+0x09dc0001,
+0xcc210000,
+0xc8240004,
+0x2a6c001f,
+0x419c0005,
+0x9ac0fffa,
+0xcc800062,
+0x80000002,
+0x7c408000,
+0x7c40c000,
+0x04d403e6,
+0x80000001,
+0xcc540000,
+0x8000037c,
+0xcc4003ea,
+0xc01c8000,
+0x044ca000,
+0xcdc12010,
+0x7c410000,
+0xc8140009,
+0x04180000,
+0x041c0008,
+0xcd800071,
+0x09dc0001,
+0x05980001,
+0xcd0d0000,
+0x99c0fffc,
+0xcc800062,
+0x8000037c,
+0xcd400071,
+0xc00e0100,
+0xcc000041,
+0xccc1304a,
+0xc83c007f,
+0xcc00007f,
+0x80000001,
+0xcc00007f,
+0xcc00007f,
+0x88000000,
+0xcc00007f,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00010331,
+0x00100004,
+0x00170006,
+0x00210008,
+0x00270028,
+0x00280023,
+0x00290029,
+0x002a0026,
+0x002b0029,
+0x002d0038,
+0x002e003f,
+0x002f004a,
+0x0034004c,
+0x00360030,
+0x003900af,
+0x003a00cf,
+0x003b00e4,
+0x003c00fc,
+0x003d016b,
+0x003f00ad,
+0x00410336,
+0x00430349,
+0x0044018e,
+0x004500fc,
+0x004601ac,
+0x004701ac,
+0x004801fe,
+0x0049020c,
+0x004a0255,
+0x004b0282,
+0x0052025f,
+0x00530271,
+0x00540287,
+0x00570299,
+0x0060029d,
+0x006102ac,
+0x006202b6,
+0x006302c0,
+0x006402ca,
+0x006502d4,
+0x006602de,
+0x006702e8,
+0x006802f2,
+0x006902f6,
+0x006a02fa,
+0x006b02fe,
+0x006c0302,
+0x006d0306,
+0x006e030a,
+0x006f030e,
+0x00700312,
+0x00720363,
+0x00740369,
+0x00790367,
+0x007c031c,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+0x000f0378,
+};
+
+static const u32 RV710_pfp_microcode[] = {
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0x80000000,
+0xdc030000,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xc818000e,
+0x31980001,
+0x7c424000,
+0x9580023a,
+0x7c428000,
+0xc81c001c,
+0xc037c000,
+0x7c40c000,
+0x7c410000,
+0x7cb4800b,
+0xc0360003,
+0x99c00000,
+0xc81c001c,
+0x7cb4800c,
+0x24d40002,
+0x7d654000,
+0xcd400043,
+0xce800043,
+0xcd000043,
+0xcc800040,
+0xce400040,
+0xce800040,
+0xccc00040,
+0xdc3a0000,
+0x9780ffde,
+0xcd000040,
+0x7c40c000,
+0x80000018,
+0x7c410000,
+0xd4000340,
+0xd4000fc0,
+0xd4000fa2,
+0xc818000e,
+0x8000000c,
+0x31980002,
+0xd40003c0,
+0xd4000fc0,
+0xd4000fa2,
+0xc818000e,
+0x288c0008,
+0x30cc000f,
+0x34100001,
+0x7d0d0008,
+0x8000000c,
+0x7d91800b,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xd4000340,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xd40003c0,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xcc4003f9,
+0x80000249,
+0xcc4003f8,
+0xc037ffff,
+0x7c414000,
+0xcf41a29e,
+0xc82003f8,
+0xc81c03f9,
+0x66200020,
+0xc81803fb,
+0x7de1c02c,
+0x7d58c008,
+0x7cdcc020,
+0x69100020,
+0xc0360003,
+0xcc000054,
+0x7cb4800c,
+0x80000069,
+0xcc800040,
+0x7c418000,
+0xcd81a29e,
+0xcc800040,
+0x80000067,
+0xcd800040,
+0xc019ffff,
+0xcc800040,
+0xcd81a29e,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0xccc1a1fa,
+0xcd01a1f9,
+0xcd41a29d,
+0xccc00040,
+0xcd000040,
+0xcd400040,
+0xcc400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xcc000054,
+0xcc800040,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0xccc1a1fa,
+0xcd01a1f9,
+0xcd41a29d,
+0xccc00040,
+0xcd000040,
+0xcd400040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0x7c40c000,
+0x30d00001,
+0xccc1a29f,
+0x95000003,
+0x04140001,
+0x04140002,
+0xcd4003fb,
+0xcc800040,
+0x80000000,
+0xccc00040,
+0x7c40c000,
+0xcc800040,
+0xccc1a2a2,
+0x80000000,
+0xccc00040,
+0x7c40c000,
+0x28d4001f,
+0xcc800040,
+0x95400003,
+0x7c410000,
+0xccc00057,
+0x2918001f,
+0xccc00040,
+0x95800003,
+0xcd000040,
+0xcd000058,
+0x80000249,
+0xcc00007f,
+0xc8200017,
+0xc8300022,
+0x9a000006,
+0x0e280001,
+0xc824001e,
+0x0a640001,
+0xd4001240,
+0xce400040,
+0xc036c000,
+0x96800007,
+0x37747900,
+0x041c0001,
+0xcf400040,
+0xcdc00040,
+0xcf0003fa,
+0x7c030000,
+0xca0c0010,
+0x7c410000,
+0x94c00004,
+0x7c414000,
+0xd42002c4,
+0xcde00044,
+0x9b00000b,
+0x7c418000,
+0xcc00004b,
+0xcda00049,
+0xcd200041,
+0xcd600041,
+0xcda00041,
+0x06200001,
+0xce000056,
+0x80000249,
+0xcc00007f,
+0xc8280020,
+0xc82c0021,
+0xcc000063,
+0x7eea4001,
+0x65740020,
+0x7f53402c,
+0x269c0002,
+0x7df5c020,
+0x69f80020,
+0xce80004b,
+0xce600049,
+0xcde00041,
+0xcfa00041,
+0xce600041,
+0x271c0002,
+0x7df5c020,
+0x69f80020,
+0x7db24001,
+0xcf00004b,
+0xce600049,
+0xcde00041,
+0xcfa00041,
+0x800000bc,
+0xce600041,
+0xc8200017,
+0xc8300022,
+0x9a000006,
+0x0e280001,
+0xc824001e,
+0x0a640001,
+0xd4001240,
+0xce400040,
+0xca0c0010,
+0x7c410000,
+0x94c0000b,
+0xc036c000,
+0x96800007,
+0x37747900,
+0x041c0001,
+0xcf400040,
+0xcdc00040,
+0xcf0003fa,
+0x7c030000,
+0x800000b5,
+0x7c414000,
+0xcc000048,
+0x800000ee,
+0x00000000,
+0xc8200017,
+0xc81c0023,
+0x0e240002,
+0x99c00015,
+0x7c418000,
+0x0a200001,
+0xce000056,
+0xd4000440,
+0xcc000040,
+0xc036c000,
+0xca140013,
+0x96400007,
+0x37747900,
+0xcf400040,
+0xcc000040,
+0xc83003fa,
+0x80000103,
+0xcf000022,
+0xcc000022,
+0x95400146,
+0xcc00007f,
+0xcca00046,
+0x80000000,
+0xcc200046,
+0x80000249,
+0xcc000064,
+0xc8200017,
+0xc810001f,
+0x96000005,
+0x09100001,
+0xd4000440,
+0xcd000040,
+0xcd000022,
+0xcc800040,
+0xd0400040,
+0xc80c0025,
+0x94c0feec,
+0xc8100008,
+0xcd000040,
+0xd4000fc0,
+0x80000000,
+0xd4000fa2,
+0x7c40c000,
+0x7c410000,
+0xccc003fd,
+0xcd0003fc,
+0xccc00042,
+0xcd000042,
+0x2914001f,
+0x29180010,
+0x31980007,
+0x3b5c0001,
+0x7d76000b,
+0x99800005,
+0x7d5e400b,
+0xcc000042,
+0x80000249,
+0xcc00004d,
+0x29980001,
+0x292c0008,
+0x9980003d,
+0x32ec0001,
+0x96000004,
+0x2930000c,
+0x80000249,
+0xcc000042,
+0x04140010,
+0xcd400042,
+0x33300001,
+0x34280001,
+0x8400015d,
+0xc8140003,
+0x9b40001b,
+0x0438000c,
+0x8400015d,
+0xc8140003,
+0x9b400017,
+0x04380008,
+0x8400015d,
+0xc8140003,
+0x9b400013,
+0x04380004,
+0x8400015d,
+0xc8140003,
+0x9b400015,
+0xc80c03fd,
+0x9a800009,
+0xc81003fc,
+0x9b000101,
+0xcc00004d,
+0x04140010,
+0xccc00042,
+0xcd000042,
+0x80000135,
+0xcd400042,
+0x96c000fa,
+0xcc00004d,
+0x80000249,
+0xcc00004e,
+0x9ac00003,
+0xcc00004d,
+0xcc00004e,
+0xdf830000,
+0x80000000,
+0xd80301ff,
+0x9ac000f0,
+0xcc00004d,
+0x80000249,
+0xcc00004e,
+0xc8180003,
+0xc81c0003,
+0xc8200003,
+0x7d5d4003,
+0x7da1c003,
+0x7d5d400c,
+0x2a10001f,
+0x299c001f,
+0x7d1d000b,
+0x7d17400b,
+0x88000000,
+0x7e92800b,
+0x96400004,
+0xcc00004e,
+0x80000249,
+0xcc000042,
+0x04380008,
+0xcf800042,
+0xc8080003,
+0xc80c0003,
+0xc8100003,
+0xc8140003,
+0xc8180003,
+0xc81c0003,
+0xc8240003,
+0xc8280003,
+0x29fc001f,
+0x2ab0001f,
+0x7ff3c00b,
+0x28f0001f,
+0x7ff3c00b,
+0x2970001f,
+0x7ff3c00b,
+0x7d888001,
+0x7dccc001,
+0x7e510001,
+0x7e954001,
+0x7c908002,
+0x7cd4c002,
+0x7cbc800b,
+0x9ac00003,
+0x7c8f400b,
+0x38b40001,
+0x9b4000c1,
+0xcc00004d,
+0x9bc000bf,
+0xcc00004e,
+0xc80c03fd,
+0xc81003fc,
+0xccc00042,
+0x8000016e,
+0xcd000042,
+0xd4000340,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xcc400040,
+0xcc400040,
+0xcc400040,
+0x7c40c000,
+0xccc00040,
+0xccc0000d,
+0x80000000,
+0xd0400040,
+0x7c40c000,
+0x7c410000,
+0x65140020,
+0x7d4d402c,
+0x24580002,
+0x7d598020,
+0x7c41c000,
+0xcd800042,
+0x69980020,
+0xcd800042,
+0xcdc00042,
+0xc023c000,
+0x05e40002,
+0x7ca0800b,
+0x26640010,
+0x7ca4800c,
+0xcc800040,
+0xcdc00040,
+0xccc00040,
+0x95c0000e,
+0xcd000040,
+0x09dc0001,
+0xc8280003,
+0x96800008,
+0xce800040,
+0xc834001d,
+0x97400000,
+0xc834001d,
+0x26a80008,
+0x8400024c,
+0xcc2b0000,
+0x99c0fff7,
+0x09dc0001,
+0xdc3a0000,
+0x97800004,
+0x7c418000,
+0x800001a2,
+0x25980002,
+0xa0000000,
+0x7d808000,
+0xc818001d,
+0x7c40c000,
+0x64d00008,
+0x95800000,
+0xc818001d,
+0xcc130000,
+0xcc800040,
+0xccc00040,
+0x80000000,
+0xcc400040,
+0xc810001f,
+0x7c40c000,
+0xcc800040,
+0x7cd1400c,
+0xcd400040,
+0x05180001,
+0x80000000,
+0xcd800022,
+0x7c40c000,
+0x64500020,
+0x8400024c,
+0xcc000061,
+0x7cd0c02c,
+0xc8200017,
+0xc8d60000,
+0x99400008,
+0x7c438000,
+0xdf830000,
+0xcfa0004f,
+0x8400024c,
+0xcc000062,
+0x80000000,
+0xd040007f,
+0x80000249,
+0xcc000062,
+0x8400024c,
+0xcc000061,
+0xc8200017,
+0x7c40c000,
+0xc036ff00,
+0xc810000d,
+0xc0303fff,
+0x7cf5400b,
+0x7d51800b,
+0x7d81800f,
+0x99800008,
+0x7cf3800b,
+0xdf830000,
+0xcfa0004f,
+0x8400024c,
+0xcc000062,
+0x80000000,
+0xd040007f,
+0x80000249,
+0xcc000062,
+0x8400024c,
+0x7c40c000,
+0x28dc0008,
+0x95c00019,
+0x30dc0010,
+0x7c410000,
+0x99c00004,
+0x64540020,
+0x80000208,
+0xc91d0000,
+0x7d15002c,
+0xc91e0000,
+0x7c420000,
+0x7c424000,
+0x7c418000,
+0x7de5c00b,
+0x7de28007,
+0x9a80000e,
+0x41ac0005,
+0x9ac00000,
+0x0aec0001,
+0x30dc0010,
+0x99c00004,
+0x00000000,
+0x8000020b,
+0xc91d0000,
+0x8000020b,
+0xc91e0000,
+0xcc800040,
+0xccc00040,
+0xd0400040,
+0xc80c0025,
+0x94c0fde4,
+0xc8100008,
+0xcd000040,
+0xd4000fc0,
+0x80000000,
+0xd4000fa2,
+0xd4000340,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0xd40003c0,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xd0400040,
+0x7c408000,
+0xa0000000,
+0x7e82800b,
+0x7c40c000,
+0x30d00006,
+0x0d100006,
+0x99000007,
+0xc8140015,
+0x99400005,
+0xcc000052,
+0xd4000340,
+0xd4000fc0,
+0xd4000fa2,
+0xcc800040,
+0xccc00040,
+0x80000000,
+0xd0400040,
+0x7c40c000,
+0xcc4d0000,
+0xdc3a0000,
+0x9780fdbd,
+0x04cc0001,
+0x80000242,
+0xcc4d0000,
+0x80000000,
+0xd040007f,
+0xcc00007f,
+0x80000000,
+0xcc00007f,
+0xcc00007f,
+0x88000000,
+0xcc00007f,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00030222,
+0x0004022a,
+0x0005009f,
+0x00020003,
+0x0006003c,
+0x00070027,
+0x00080191,
+0x00090044,
+0x000a002d,
+0x00100247,
+0x001700f0,
+0x002201d7,
+0x002301e8,
+0x0026004c,
+0x0027005f,
+0x0020011a,
+0x00280092,
+0x0029004f,
+0x002a0083,
+0x002b0064,
+0x002f008d,
+0x003200d8,
+0x00340232,
+0x00360074,
+0x0039010a,
+0x003c01fc,
+0x003f009f,
+0x00410005,
+0x00440194,
+0x0048019d,
+0x004901c5,
+0x004a01cf,
+0x00550225,
+0x0056022d,
+0x0060000a,
+0x0061002a,
+0x00620030,
+0x00630030,
+0x00640030,
+0x00650030,
+0x00660030,
+0x00670030,
+0x00680037,
+0x0069003f,
+0x006a0047,
+0x006b0047,
+0x006c0047,
+0x006d0047,
+0x006e0047,
+0x006f0047,
+0x00700047,
+0x00730247,
+0x007b0240,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+0x00000005,
+};
+
+static const u32 RV710_cp_microcode[] = {
+0xcc0003ea,
+0x04080003,
+0xcc800043,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x80000003,
+0xd040007f,
+0x80000003,
+0xcc400041,
+0x7c40c000,
+0xc0160004,
+0x30d03fff,
+0x7d15000c,
+0xcc110000,
+0x28d8001e,
+0x31980001,
+0x28dc001f,
+0xc8200004,
+0x95c00006,
+0x7c424000,
+0xcc000062,
+0x7e56800c,
+0xcc290000,
+0xc8240004,
+0x7e26000b,
+0x95800006,
+0x7c42c000,
+0xcc000062,
+0x7ed7000c,
+0xcc310000,
+0xc82c0004,
+0x7e2e000c,
+0xcc000062,
+0x31103fff,
+0x80000003,
+0xce110000,
+0x7c40c000,
+0x80000003,
+0xcc400040,
+0x80000003,
+0xcc412257,
+0x7c418000,
+0xcc400045,
+0xcc400048,
+0xcc41225c,
+0xcc41a1fc,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xcc400045,
+0xcc400048,
+0x7c40c000,
+0xcc41225c,
+0xcc41a1fc,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xcc000045,
+0xcc000048,
+0xcc41225c,
+0xcc41a1fc,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x040ca1fd,
+0xc0120001,
+0xcc000045,
+0xcc000048,
+0x7cd0c00c,
+0xcc41225c,
+0xcc41a1fc,
+0xd04d0000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x80000003,
+0xcc41225d,
+0x7c408000,
+0x7c40c000,
+0xc02a0002,
+0x7c410000,
+0x7d29000c,
+0x30940001,
+0x30980006,
+0x309c0300,
+0x29dc0008,
+0x7c420000,
+0x7c424000,
+0x9540000f,
+0xc02e0004,
+0x05f02258,
+0x7f2f000c,
+0xcc310000,
+0xc8280004,
+0xccc12169,
+0xcd01216a,
+0xce81216b,
+0x0db40002,
+0xcc01216c,
+0x9740000e,
+0x0db40000,
+0x8000007d,
+0xc834000a,
+0x0db40002,
+0x97400009,
+0x0db40000,
+0xc02e0004,
+0x05f02258,
+0x7f2f000c,
+0xcc310000,
+0xc8280004,
+0x8000007d,
+0xc834000a,
+0x97400004,
+0x7e028000,
+0x8000007d,
+0xc834000a,
+0x0db40004,
+0x9740ff8c,
+0x00000000,
+0xce01216d,
+0xce41216e,
+0xc8280003,
+0xc834000a,
+0x9b400004,
+0x043c0005,
+0x8400026d,
+0xcc000062,
+0x0df40000,
+0x9740000b,
+0xc82c03e6,
+0xce81a2b7,
+0xc0300006,
+0x7ef34028,
+0xc0300020,
+0x7f6b8020,
+0x7fb3c029,
+0xcf81a2c4,
+0x80000003,
+0xcfc1a2d1,
+0x0df40001,
+0x9740000b,
+0xc82c03e7,
+0xce81a2bb,
+0xc0300006,
+0x7ef34028,
+0xc0300020,
+0x7f6b8020,
+0x7fb3c029,
+0xcf81a2c5,
+0x80000003,
+0xcfc1a2d2,
+0x0df40002,
+0x9740000b,
+0xc82c03e8,
+0xce81a2bf,
+0xc0300006,
+0x7ef34028,
+0xc0300020,
+0x7f6b8020,
+0x7fb3c029,
+0xcf81a2c6,
+0x80000003,
+0xcfc1a2d3,
+0xc82c03e9,
+0xce81a2c3,
+0xc0300006,
+0x7ef34028,
+0xc0300020,
+0x7f6b8020,
+0x7fb3c029,
+0xcf81a2c7,
+0x80000003,
+0xcfc1a2d4,
+0x80000003,
+0xcc400042,
+0x7c40c000,
+0x7c410000,
+0x2914001d,
+0x31540001,
+0x9940000c,
+0x31181000,
+0xc81c0011,
+0x95c00000,
+0xc81c0011,
+0xccc12100,
+0xcd012101,
+0xccc12102,
+0xcd012103,
+0x04180004,
+0x8000037e,
+0xcd81a2a4,
+0xc02a0004,
+0x95800008,
+0x36a821a3,
+0xcc290000,
+0xc8280004,
+0xc81c0011,
+0x0de40040,
+0x9640ffff,
+0xc81c0011,
+0xccc12170,
+0xcd012171,
+0xc8200012,
+0x96000000,
+0xc8200012,
+0x8000037e,
+0xcc000064,
+0x7c40c000,
+0x7c410000,
+0xcc000045,
+0xcc000048,
+0x40d40003,
+0xcd41225c,
+0xcd01a1fc,
+0xc01a0001,
+0x041ca1fd,
+0x7dd9c00c,
+0x7c420000,
+0x08cc0001,
+0x06240001,
+0x06280002,
+0xce1d0000,
+0xce5d0000,
+0x98c0fffa,
+0xce9d0000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x7c40c000,
+0x30d00001,
+0x28cc0001,
+0x7c414000,
+0x95000006,
+0x7c418000,
+0xcd41216d,
+0xcd81216e,
+0x800000f4,
+0xc81c0003,
+0xc0220004,
+0x7e16000c,
+0xcc210000,
+0xc81c0004,
+0x7c424000,
+0x98c00004,
+0x7c428000,
+0x80000003,
+0xcde50000,
+0xce412169,
+0xce81216a,
+0xcdc1216b,
+0x80000003,
+0xcc01216c,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0x7c41c000,
+0x28a40008,
+0x326400ff,
+0x0e68003c,
+0x9680000a,
+0x7c020000,
+0x7c420000,
+0x1e300003,
+0xcc00006a,
+0x9b000003,
+0x42200005,
+0x04200040,
+0x80000111,
+0x7c024000,
+0x7e024000,
+0x9a400000,
+0x0a640001,
+0x30ec0010,
+0x9ac0000a,
+0xcc000062,
+0xc02a0004,
+0xc82c0021,
+0x7e92800c,
+0xcc000041,
+0xcc290000,
+0xcec00021,
+0x80000121,
+0xc8300004,
+0xcd01216d,
+0xcd41216e,
+0xc8300003,
+0x7f1f000b,
+0x30f40007,
+0x27780001,
+0x9740002a,
+0x07b80126,
+0x9f800000,
+0x00000000,
+0x80000136,
+0x7f1b8004,
+0x8000013a,
+0x7f1b8005,
+0x8000013e,
+0x7f1b8002,
+0x80000142,
+0x7f1b8003,
+0x80000146,
+0x7f1b8007,
+0x8000014a,
+0x7f1b8006,
+0x8000014f,
+0x28a40008,
+0x9b800019,
+0x28a40008,
+0x8000015f,
+0x326400ff,
+0x9b800015,
+0x28a40008,
+0x8000015f,
+0x326400ff,
+0x9b800011,
+0x28a40008,
+0x8000015f,
+0x326400ff,
+0x9b80000d,
+0x28a40008,
+0x8000015f,
+0x326400ff,
+0x9b800009,
+0x28a40008,
+0x8000015f,
+0x326400ff,
+0x9b800005,
+0x28a40008,
+0x8000015f,
+0x326400ff,
+0x28a40008,
+0x326400ff,
+0x0e68003c,
+0x9a80feb2,
+0x28ec0008,
+0x7c434000,
+0x7c438000,
+0x7c43c000,
+0x96c00007,
+0xcc000062,
+0xcf412169,
+0xcf81216a,
+0xcfc1216b,
+0x80000003,
+0xcc01216c,
+0x80000003,
+0xcff50000,
+0xcc00006b,
+0x84000381,
+0x0e68003c,
+0x9a800004,
+0xc8280015,
+0x80000003,
+0xd040007f,
+0x9680ffab,
+0x7e024000,
+0x8400023b,
+0xc00e0002,
+0xcc000041,
+0x80000239,
+0xccc1304a,
+0x7c40c000,
+0x7c410000,
+0xc01e0001,
+0x29240012,
+0xc0220002,
+0x96400005,
+0xc0260004,
+0xc027fffb,
+0x7d25000b,
+0xc0260000,
+0x7dd2800b,
+0x7e12c00b,
+0x7d25000c,
+0x7c414000,
+0x7c418000,
+0xccc12169,
+0x9a80000a,
+0xcd01216a,
+0xcd41216b,
+0x96c0fe83,
+0xcd81216c,
+0xc8300018,
+0x97000000,
+0xc8300018,
+0x80000003,
+0xcc000018,
+0x84000381,
+0xcc00007f,
+0xc8140013,
+0xc8180014,
+0xcd41216b,
+0x96c0fe77,
+0xcd81216c,
+0x80000183,
+0xc8300018,
+0xc80c0008,
+0x98c00000,
+0xc80c0008,
+0x7c410000,
+0x95000002,
+0x00000000,
+0x7c414000,
+0xc8200009,
+0xcc400043,
+0xce01a1f4,
+0xcc400044,
+0xc00e8000,
+0x7c424000,
+0x7c428000,
+0x2aac001f,
+0x96c0fe64,
+0xc035f000,
+0xce4003e2,
+0x32780003,
+0x267c0008,
+0x7ff7c00b,
+0x7ffbc00c,
+0x2a780018,
+0xcfc003e3,
+0xcf8003e4,
+0x26b00002,
+0x7f3f0000,
+0xcf0003e5,
+0x8000031f,
+0x7c80c000,
+0x7c40c000,
+0x28d00008,
+0x3110000f,
+0x9500000f,
+0x25280001,
+0x06a801b4,
+0x9e800000,
+0x00000000,
+0x800001d5,
+0xc0120800,
+0x800001e3,
+0xc814000f,
+0x800001ea,
+0xc8140010,
+0x800001f1,
+0xccc1a2a4,
+0x800001fa,
+0xc8140011,
+0x30d0003f,
+0x0d280015,
+0x9a800012,
+0x0d28001e,
+0x9a80001e,
+0x0d280020,
+0x9a800023,
+0x0d24000f,
+0x0d280010,
+0x7e6a800c,
+0x9a800026,
+0x0d200004,
+0x0d240014,
+0x0d280028,
+0x7e62400c,
+0x7ea6800c,
+0x9a80002a,
+0xc8140011,
+0x80000003,
+0xccc1a2a4,
+0xc0120800,
+0x7c414000,
+0x7d0cc00c,
+0xc0120008,
+0x29580003,
+0x295c000c,
+0x7c420000,
+0x7dd1c00b,
+0x26200014,
+0x7e1e400c,
+0x7e4e800c,
+0xce81a2a4,
+0x80000003,
+0xcd81a1fe,
+0xc814000f,
+0x0410210e,
+0x95400000,
+0xc814000f,
+0xd0510000,
+0x80000003,
+0xccc1a2a4,
+0xc8140010,
+0x04102108,
+0x95400000,
+0xc8140010,
+0xd0510000,
+0x80000003,
+0xccc1a2a4,
+0xccc1a2a4,
+0x04100001,
+0xcd000019,
+0x84000381,
+0xcc00007f,
+0xc8100019,
+0x99000000,
+0xc8100019,
+0x80000004,
+0x7c408000,
+0x04102100,
+0x95400000,
+0xc8140011,
+0xd0510000,
+0x8000037e,
+0xccc1a2a4,
+0x7c40c000,
+0xcc40000d,
+0x94c0fe01,
+0xcc40000e,
+0x7c410000,
+0x95000005,
+0x08cc0001,
+0xc8140005,
+0x99400014,
+0x00000000,
+0x98c0fffb,
+0x7c410000,
+0x80000004,
+0x7d008000,
+0xc8140005,
+0x7c40c000,
+0x9940000c,
+0xc818000c,
+0x7c410000,
+0x9580fdf0,
+0xc820000e,
+0xc81c000d,
+0x66200020,
+0x7e1e002c,
+0x25240002,
+0x7e624020,
+0x80000003,
+0xcce60000,
+0x7c410000,
+0xcc00006c,
+0xcc00006d,
+0xc818001f,
+0xc81c001e,
+0x65980020,
+0x7dd9c02c,
+0x7cd4c00c,
+0xccde0000,
+0x45dc0004,
+0xc8280017,
+0x9680000f,
+0xc00e0001,
+0x28680008,
+0x2aac0016,
+0x32a800ff,
+0x0eb00049,
+0x7f2f000b,
+0x97000006,
+0x00000000,
+0xc8140005,
+0x7c40c000,
+0x80000223,
+0x7c410000,
+0x80000226,
+0xd040007f,
+0x8400023b,
+0xcc000041,
+0xccc1304a,
+0x94000000,
+0xc83c001a,
+0x043c0005,
+0xcfc1a2a4,
+0xc0361f90,
+0xc0387fff,
+0x7c03c010,
+0x7f7b400c,
+0xcf41217c,
+0xcfc1217d,
+0xcc01217e,
+0xc03a0004,
+0x0434217f,
+0x7f7b400c,
+0xcc350000,
+0xc83c0004,
+0x2bfc001f,
+0x04380020,
+0x97c00005,
+0xcc000062,
+0x9b800000,
+0x0bb80001,
+0x80000247,
+0xcc000071,
+0xcc01a1f4,
+0x04380016,
+0xc0360002,
+0xcf81a2a4,
+0x88000000,
+0xcf412010,
+0x7c40c000,
+0x28d0001c,
+0x95000005,
+0x04d40001,
+0xcd400065,
+0x80000003,
+0xcd400068,
+0x09540002,
+0x80000003,
+0xcd400066,
+0x8400026c,
+0xc81803ea,
+0x7c40c000,
+0x9980fd9f,
+0xc8140016,
+0x08d00001,
+0x9940002b,
+0xcd000068,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x043c0005,
+0xcfc1a2a4,
+0xcc01a1f4,
+0x84000381,
+0xcc000046,
+0x88000000,
+0xcc00007f,
+0x8400027e,
+0xc81803ea,
+0x7c40c000,
+0x9980fd8d,
+0xc8140016,
+0x08d00001,
+0x99400019,
+0xcd000068,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x043c0022,
+0xcfc1a2a4,
+0x84000381,
+0xcc000047,
+0x88000000,
+0xcc00007f,
+0xc8100016,
+0x9900000d,
+0xcc400067,
+0x80000004,
+0x7c408000,
+0xc81803ea,
+0x9980fd79,
+0x7c40c000,
+0x94c00003,
+0xc8100016,
+0x99000004,
+0xccc00068,
+0x80000004,
+0x7c408000,
+0x8400023b,
+0xc0148000,
+0xcc000041,
+0xcd41304a,
+0xc0148000,
+0x99000000,
+0xc8100016,
+0x80000004,
+0x7c408000,
+0xc0120001,
+0x7c51400c,
+0x80000003,
+0xd0550000,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0x291c001f,
+0xccc0004a,
+0xcd00004b,
+0x95c00003,
+0xc01c8000,
+0xcdc12010,
+0xdd830000,
+0x055c2000,
+0xcc000062,
+0x80000003,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc0004c,
+0xcd00004d,
+0xdd830000,
+0x055ca000,
+0x80000003,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc0004e,
+0xcd00004f,
+0xdd830000,
+0x055cc000,
+0x80000003,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc00050,
+0xcd000051,
+0xdd830000,
+0x055cf8e0,
+0x80000003,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc00052,
+0xcd000053,
+0xdd830000,
+0x055cf880,
+0x80000003,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc00054,
+0xcd000055,
+0xdd830000,
+0x055ce000,
+0x80000003,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc00056,
+0xcd000057,
+0xdd830000,
+0x055cf000,
+0x80000003,
+0xd81f4100,
+0x7c40c000,
+0x7c410000,
+0x7c414000,
+0x7c418000,
+0xccc00058,
+0xcd000059,
+0xdd830000,
+0x055cf3fc,
+0x80000003,
+0xd81f4100,
+0xd0432000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043a000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043c000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043f8e0,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043f880,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043e000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043f000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xd043f3fc,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xc81403e0,
+0xcc430000,
+0xcc430000,
+0xcc430000,
+0x7d45c000,
+0xcdc30000,
+0xd0430000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0x7c40c000,
+0xc81003e2,
+0xc81403e5,
+0xc81803e3,
+0xc81c03e4,
+0xcd812169,
+0xcdc1216a,
+0xccc1216b,
+0xcc01216c,
+0x04200004,
+0x7da18000,
+0x7d964002,
+0x9640fcd9,
+0xcd8003e3,
+0x31280003,
+0xc02df000,
+0x25180008,
+0x7dad800b,
+0x7da9800c,
+0x80000003,
+0xcd8003e3,
+0x308cffff,
+0xd04d0000,
+0x7c408000,
+0xa0000000,
+0xcc800062,
+0xc8140020,
+0x15580002,
+0x9580ffff,
+0xc8140020,
+0xcc00006e,
+0xcc412180,
+0x7c40c000,
+0xccc1218d,
+0xcc412181,
+0x28d0001f,
+0x34588000,
+0xcd81218c,
+0x9500fcbf,
+0xcc412182,
+0xc8140020,
+0x9940ffff,
+0xc8140020,
+0x80000004,
+0x7c408000,
+0x7c40c000,
+0x28d00018,
+0x31100001,
+0xc0160080,
+0x95000003,
+0xc02a0004,
+0x7cd4c00c,
+0xccc1217c,
+0xcc41217d,
+0xcc41217e,
+0x7c418000,
+0x1db00003,
+0x36a0217f,
+0x9b000003,
+0x419c0005,
+0x041c0040,
+0x99c00000,
+0x09dc0001,
+0xcc210000,
+0xc8240004,
+0x2a6c001f,
+0x419c0005,
+0x9ac0fffa,
+0xcc800062,
+0x80000004,
+0x7c408000,
+0x7c40c000,
+0x04d403e6,
+0x80000003,
+0xcc540000,
+0x8000037e,
+0xcc4003ea,
+0xc01c8000,
+0x044ca000,
+0xcdc12010,
+0x7c410000,
+0xc8140009,
+0x04180000,
+0x041c0008,
+0xcd800071,
+0x09dc0001,
+0x05980001,
+0xcd0d0000,
+0x99c0fffc,
+0xcc800062,
+0x8000037e,
+0xcd400071,
+0xc00e0100,
+0xcc000041,
+0xccc1304a,
+0xc83c007f,
+0xcc00007f,
+0x80000003,
+0xcc00007f,
+0xcc00007f,
+0x88000000,
+0xcc00007f,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00010333,
+0x00100006,
+0x00170008,
+0x0021000a,
+0x0027002a,
+0x00280025,
+0x0029002b,
+0x002a0028,
+0x002b002b,
+0x002d003a,
+0x002e0041,
+0x002f004c,
+0x0034004e,
+0x00360032,
+0x003900b1,
+0x003a00d1,
+0x003b00e6,
+0x003c00fe,
+0x003d016d,
+0x003f00af,
+0x00410338,
+0x0043034b,
+0x00440190,
+0x004500fe,
+0x004601ae,
+0x004701ae,
+0x00480200,
+0x0049020e,
+0x004a0257,
+0x004b0284,
+0x00520261,
+0x00530273,
+0x00540289,
+0x0057029b,
+0x0060029f,
+0x006102ae,
+0x006202b8,
+0x006302c2,
+0x006402cc,
+0x006502d6,
+0x006602e0,
+0x006702ea,
+0x006802f4,
+0x006902f8,
+0x006a02fc,
+0x006b0300,
+0x006c0304,
+0x006d0308,
+0x006e030c,
+0x006f0310,
+0x00700314,
+0x00720365,
+0x0074036b,
+0x00790369,
+0x007c031e,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+0x000f037a,
+};
+
+#endif
index 92965dbb3c147a7b46c3cf248466765f2d08f5e8..77a7a4d846508f8e2f1e89aee9b0f3ff812cd84a 100644 (file)
 static int radeon_do_cleanup_cp(struct drm_device * dev);
 static void radeon_do_cp_start(drm_radeon_private_t * dev_priv);
 
+u32 radeon_read_ring_rptr(drm_radeon_private_t *dev_priv, u32 off)
+{
+       u32 val;
+
+       if (dev_priv->flags & RADEON_IS_AGP) {
+               val = DRM_READ32(dev_priv->ring_rptr, off);
+       } else {
+               val = *(((volatile u32 *)
+                        dev_priv->ring_rptr->handle) +
+                       (off / sizeof(u32)));
+               val = le32_to_cpu(val);
+       }
+       return val;
+}
+
+u32 radeon_get_ring_head(drm_radeon_private_t *dev_priv)
+{
+       if (dev_priv->writeback_works)
+               return radeon_read_ring_rptr(dev_priv, 0);
+       else {
+               if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+                       return RADEON_READ(R600_CP_RB_RPTR);
+               else
+                       return RADEON_READ(RADEON_CP_RB_RPTR);
+       }
+}
+
+void radeon_write_ring_rptr(drm_radeon_private_t *dev_priv, u32 off, u32 val)
+{
+       if (dev_priv->flags & RADEON_IS_AGP)
+               DRM_WRITE32(dev_priv->ring_rptr, off, val);
+       else
+               *(((volatile u32 *) dev_priv->ring_rptr->handle) +
+                 (off / sizeof(u32))) = cpu_to_le32(val);
+}
+
+void radeon_set_ring_head(drm_radeon_private_t *dev_priv, u32 val)
+{
+       radeon_write_ring_rptr(dev_priv, 0, val);
+}
+
+u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index)
+{
+       if (dev_priv->writeback_works) {
+               if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+                       return radeon_read_ring_rptr(dev_priv,
+                                                    R600_SCRATCHOFF(index));
+               else
+                       return radeon_read_ring_rptr(dev_priv,
+                                                    RADEON_SCRATCHOFF(index));
+       } else {
+               if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+                       return RADEON_READ(R600_SCRATCH_REG0 + 4*index);
+               else
+                       return RADEON_READ(RADEON_SCRATCH_REG0 + 4*index);
+       }
+}
+
+u32 RADEON_READ_MM(drm_radeon_private_t *dev_priv, int addr)
+{
+       u32 ret;
+
+       if (addr < 0x10000)
+               ret = DRM_READ32(dev_priv->mmio, addr);
+       else {
+               DRM_WRITE32(dev_priv->mmio, RADEON_MM_INDEX, addr);
+               ret = DRM_READ32(dev_priv->mmio, RADEON_MM_DATA);
+       }
+
+       return ret;
+}
+
 static u32 R500_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
 {
        u32 ret;
@@ -70,11 +142,22 @@ static u32 RS690_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
        return ret;
 }
 
+static u32 RS600_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
+{
+       u32 ret;
+       RADEON_WRITE(RS600_MC_INDEX, ((addr & RS600_MC_ADDR_MASK) |
+                                     RS600_MC_IND_CITF_ARB0));
+       ret = RADEON_READ(RS600_MC_DATA);
+       return ret;
+}
+
 static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
 {
        if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
            ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
                return RS690_READ_MCIND(dev_priv, addr);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
+               return RS600_READ_MCIND(dev_priv, addr);
        else
                return RS480_READ_MCIND(dev_priv, addr);
 }
@@ -82,11 +165,17 @@ static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
 u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
 {
 
-       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
+               return RADEON_READ(R700_MC_VM_FB_LOCATION);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               return RADEON_READ(R600_MC_VM_FB_LOCATION);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
                return R500_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION);
        else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
                 ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
                return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
+               return RS600_READ_MCIND(dev_priv, RS600_MC_FB_LOCATION);
        else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
                return R500_READ_MCIND(dev_priv, R520_MC_FB_LOCATION);
        else
@@ -95,42 +184,66 @@ u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
 
 static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc)
 {
-       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
+               RADEON_WRITE(R700_MC_VM_FB_LOCATION, fb_loc);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               RADEON_WRITE(R600_MC_VM_FB_LOCATION, fb_loc);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
                R500_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc);
        else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
                 ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
                RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
+               RS600_WRITE_MCIND(RS600_MC_FB_LOCATION, fb_loc);
        else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
                R500_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc);
        else
                RADEON_WRITE(RADEON_MC_FB_LOCATION, fb_loc);
 }
 
-static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc)
+void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc)
 {
-       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
+       /*R6xx/R7xx: AGP_TOP and BOT are actually 18 bits each */
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) {
+               RADEON_WRITE(R700_MC_VM_AGP_BOT, agp_loc & 0xffff); /* FIX ME */
+               RADEON_WRITE(R700_MC_VM_AGP_TOP, (agp_loc >> 16) & 0xffff);
+       } else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
+               RADEON_WRITE(R600_MC_VM_AGP_BOT, agp_loc & 0xffff); /* FIX ME */
+               RADEON_WRITE(R600_MC_VM_AGP_TOP, (agp_loc >> 16) & 0xffff);
+       } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
                R500_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc);
        else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
                 ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
                RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
+               RS600_WRITE_MCIND(RS600_MC_AGP_LOCATION, agp_loc);
        else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
                R500_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc);
        else
                RADEON_WRITE(RADEON_MC_AGP_LOCATION, agp_loc);
 }
 
-static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
+void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
 {
        u32 agp_base_hi = upper_32_bits(agp_base);
        u32 agp_base_lo = agp_base & 0xffffffff;
-
-       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) {
+       u32 r6xx_agp_base = (agp_base >> 22) & 0x3ffff;
+
+       /* R6xx/R7xx must be aligned to a 4MB boundry */
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
+               RADEON_WRITE(R700_MC_VM_AGP_BASE, r6xx_agp_base);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               RADEON_WRITE(R600_MC_VM_AGP_BASE, r6xx_agp_base);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) {
                R500_WRITE_MCIND(RV515_MC_AGP_BASE, agp_base_lo);
                R500_WRITE_MCIND(RV515_MC_AGP_BASE_2, agp_base_hi);
        } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
                 ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
                RS690_WRITE_MCIND(RS690_MC_AGP_BASE, agp_base_lo);
                RS690_WRITE_MCIND(RS690_MC_AGP_BASE_2, agp_base_hi);
+       } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) {
+               RS600_WRITE_MCIND(RS600_AGP_BASE, agp_base_lo);
+               RS600_WRITE_MCIND(RS600_AGP_BASE_2, agp_base_hi);
        } else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) {
                R500_WRITE_MCIND(R520_MC_AGP_BASE, agp_base_lo);
                R500_WRITE_MCIND(R520_MC_AGP_BASE_2, agp_base_hi);
@@ -145,6 +258,25 @@ static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
        }
 }
 
+void radeon_enable_bm(struct drm_radeon_private *dev_priv)
+{
+       u32 tmp;
+       /* Turn on bus mastering */
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
+               /* rs600/rs690/rs740 */
+               tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS;
+               RADEON_WRITE(RADEON_BUS_CNTL, tmp);
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV350) ||
+                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
+                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
+                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
+               /* r1xx, r2xx, r300, r(v)350, r420/r481, rs400/rs480 */
+               tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
+               RADEON_WRITE(RADEON_BUS_CNTL, tmp);
+       } /* PCIE cards appears to not need this */
+}
+
 static int RADEON_READ_PLL(struct drm_device * dev, int addr)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -302,7 +434,7 @@ static void radeon_init_pipes(drm_radeon_private_t *dev_priv)
 
        if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) {
                RADEON_WRITE_PLL(R500_DYN_SCLK_PWMEM_PIPE, (1 | ((gb_pipe_sel >> 8) & 0xf) << 4));
-               RADEON_WRITE(R500_SU_REG_DEST, ((1 << dev_priv->num_gb_pipes) - 1));
+               RADEON_WRITE(R300_SU_REG_DEST, ((1 << dev_priv->num_gb_pipes) - 1));
        }
        RADEON_WRITE(R300_GB_TILE_CONFIG, gb_tile_config);
        radeon_do_wait_for_idle(dev_priv);
@@ -382,6 +514,14 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
                        RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
                                     RS690_cp_microcode[i][0]);
                }
+       } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) {
+               DRM_INFO("Loading RS600 Microcode\n");
+               for (i = 0; i < 256; i++) {
+                       RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
+                                    RS600_cp_microcode[i][1]);
+                       RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
+                                    RS600_cp_microcode[i][0]);
+               }
        } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) ||
                   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R520) ||
                   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV530) ||
@@ -562,7 +702,6 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
 {
        struct drm_radeon_master_private *master_priv;
        u32 ring_start, cur_read_ptr;
-       u32 tmp;
 
        /* Initialize the memory controller. With new memory map, the fb location
         * is not changed, it should have been properly initialized already. Part
@@ -611,17 +750,10 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
        } else
 #endif
        {
-               struct drm_sg_mem *entry = dev->sg;
-               unsigned long tmp_ofs, page_ofs;
-
-               tmp_ofs = dev_priv->ring_rptr->offset -
-                               (unsigned long)dev->sg->virtual;
-               page_ofs = tmp_ofs >> PAGE_SHIFT;
-
-               RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, entry->busaddr[page_ofs]);
-               DRM_DEBUG("ring rptr: offset=0x%08lx handle=0x%08lx\n",
-                         (unsigned long)entry->busaddr[page_ofs],
-                         entry->handle + tmp_ofs);
+               RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR,
+                            dev_priv->ring_rptr->offset
+                            - ((unsigned long) dev->sg->virtual)
+                            + dev_priv->gart_vm_start);
        }
 
        /* Set ring buffer size */
@@ -649,34 +781,17 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
        RADEON_WRITE(RADEON_SCRATCH_ADDR, RADEON_READ(RADEON_CP_RB_RPTR_ADDR)
                     + RADEON_SCRATCH_REG_OFFSET);
 
-       dev_priv->scratch = ((__volatile__ u32 *)
-                            dev_priv->ring_rptr->handle +
-                            (RADEON_SCRATCH_REG_OFFSET / sizeof(u32)));
-
        RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7);
 
-       /* Turn on bus mastering */
-       if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
-           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
-               /* rs600/rs690/rs740 */
-               tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS;
-               RADEON_WRITE(RADEON_BUS_CNTL, tmp);
-       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV350) ||
-                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
-                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
-                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
-               /* r1xx, r2xx, r300, r(v)350, r420/r481, rs400/rs480 */
-               tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
-               RADEON_WRITE(RADEON_BUS_CNTL, tmp);
-       } /* PCIE cards appears to not need this */
+       radeon_enable_bm(dev_priv);
 
-       dev_priv->scratch[0] = 0;
+       radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(0), 0);
        RADEON_WRITE(RADEON_LAST_FRAME_REG, 0);
 
-       dev_priv->scratch[1] = 0;
+       radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1), 0);
        RADEON_WRITE(RADEON_LAST_DISPATCH_REG, 0);
 
-       dev_priv->scratch[2] = 0;
+       radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(2), 0);
        RADEON_WRITE(RADEON_LAST_CLEAR_REG, 0);
 
        /* reset sarea copies of these */
@@ -708,12 +823,15 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv)
        /* Writeback doesn't seem to work everywhere, test it here and possibly
         * enable it if it appears to work
         */
-       DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0);
+       radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1), 0);
+
        RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef);
 
        for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) {
-               if (DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1)) ==
-                   0xdeadbeef)
+               u32 val;
+
+               val = radeon_read_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1));
+               if (val == 0xdeadbeef)
                        break;
                DRM_UDELAY(1);
        }
@@ -809,6 +927,82 @@ static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on)
        }
 }
 
+/* Enable or disable IGP GART on the chip */
+static void rs600_set_igpgart(drm_radeon_private_t *dev_priv, int on)
+{
+       u32 temp;
+       int i;
+
+       if (on) {
+               DRM_DEBUG("programming igp gart %08X %08lX %08X\n",
+                        dev_priv->gart_vm_start,
+                        (long)dev_priv->gart_info.bus_addr,
+                        dev_priv->gart_size);
+
+               IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, (RS600_EFFECTIVE_L2_CACHE_SIZE(6) |
+                                                   RS600_EFFECTIVE_L2_QUEUE_SIZE(6)));
+
+               for (i = 0; i < 19; i++)
+                       IGP_WRITE_MCIND(RS600_MC_PT0_CLIENT0_CNTL + i,
+                                       (RS600_ENABLE_TRANSLATION_MODE_OVERRIDE |
+                                        RS600_SYSTEM_ACCESS_MODE_IN_SYS |
+                                        RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASSTHROUGH |
+                                        RS600_EFFECTIVE_L1_CACHE_SIZE(3) |
+                                        RS600_ENABLE_FRAGMENT_PROCESSING |
+                                        RS600_EFFECTIVE_L1_QUEUE_SIZE(3)));
+
+               IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_CNTL, (RS600_ENABLE_PAGE_TABLE |
+                                                            RS600_PAGE_TABLE_TYPE_FLAT));
+
+               /* disable all other contexts */
+               for (i = 1; i < 8; i++)
+                       IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_CNTL + i, 0);
+
+               /* setup the page table aperture */
+               IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_BASE_ADDR,
+                               dev_priv->gart_info.bus_addr);
+               IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_START_ADDR,
+                               dev_priv->gart_vm_start);
+               IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_END_ADDR,
+                               (dev_priv->gart_vm_start + dev_priv->gart_size - 1));
+               IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR, 0);
+
+               /* setup the system aperture */
+               IGP_WRITE_MCIND(RS600_MC_PT0_SYSTEM_APERTURE_LOW_ADDR,
+                               dev_priv->gart_vm_start);
+               IGP_WRITE_MCIND(RS600_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR,
+                               (dev_priv->gart_vm_start + dev_priv->gart_size - 1));
+
+               /* enable page tables */
+               temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
+               IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, (temp | RS600_ENABLE_PT));
+
+               temp = IGP_READ_MCIND(dev_priv, RS600_MC_CNTL1);
+               IGP_WRITE_MCIND(RS600_MC_CNTL1, (temp | RS600_ENABLE_PAGE_TABLES));
+
+               /* invalidate the cache */
+               temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
+
+               temp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE);
+               IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, temp);
+               temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
+
+               temp |= RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE;
+               IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, temp);
+               temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
+
+               temp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE);
+               IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, temp);
+               temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
+
+       } else {
+               IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, 0);
+               temp = IGP_READ_MCIND(dev_priv, RS600_MC_CNTL1);
+               temp &= ~RS600_ENABLE_PAGE_TABLES;
+               IGP_WRITE_MCIND(RS600_MC_CNTL1, temp);
+       }
+}
+
 static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on)
 {
        u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL);
@@ -850,6 +1044,11 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
                return;
        }
 
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) {
+               rs600_set_igpgart(dev_priv, on);
+               return;
+       }
+
        if (dev_priv->flags & RADEON_IS_PCIE) {
                radeon_set_pciegart(dev_priv, on);
                return;
@@ -881,6 +1080,46 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
        }
 }
 
+static int radeon_setup_pcigart_surface(drm_radeon_private_t *dev_priv)
+{
+       struct drm_ati_pcigart_info *gart_info = &dev_priv->gart_info;
+       struct radeon_virt_surface *vp;
+       int i;
+
+       for (i = 0; i < RADEON_MAX_SURFACES * 2; i++) {
+               if (!dev_priv->virt_surfaces[i].file_priv ||
+                   dev_priv->virt_surfaces[i].file_priv == PCIGART_FILE_PRIV)
+                       break;
+       }
+       if (i >= 2 * RADEON_MAX_SURFACES)
+               return -ENOMEM;
+       vp = &dev_priv->virt_surfaces[i];
+
+       for (i = 0; i < RADEON_MAX_SURFACES; i++) {
+               struct radeon_surface *sp = &dev_priv->surfaces[i];
+               if (sp->refcount)
+                       continue;
+
+               vp->surface_index = i;
+               vp->lower = gart_info->bus_addr;
+               vp->upper = vp->lower + gart_info->table_size;
+               vp->flags = 0;
+               vp->file_priv = PCIGART_FILE_PRIV;
+
+               sp->refcount = 1;
+               sp->lower = vp->lower;
+               sp->upper = vp->upper;
+               sp->flags = 0;
+
+               RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * i, sp->flags);
+               RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * i, sp->lower);
+               RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * i, sp->upper);
+               return 0;
+       }
+
+       return -ENOMEM;
+}
+
 static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
                             struct drm_file *file_priv)
 {
@@ -1062,11 +1301,12 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
        } else
 #endif
        {
-               dev_priv->cp_ring->handle = (void *)dev_priv->cp_ring->offset;
+               dev_priv->cp_ring->handle =
+                       (void *)(unsigned long)dev_priv->cp_ring->offset;
                dev_priv->ring_rptr->handle =
-                   (void *)dev_priv->ring_rptr->offset;
+                       (void *)(unsigned long)dev_priv->ring_rptr->offset;
                dev->agp_buffer_map->handle =
-                   (void *)dev->agp_buffer_map->offset;
+                       (void *)(unsigned long)dev->agp_buffer_map->offset;
 
                DRM_DEBUG("dev_priv->cp_ring->handle %p\n",
                          dev_priv->cp_ring->handle);
@@ -1173,11 +1413,14 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
        } else
 #endif
        {
+               u32 sctrl;
+               int ret;
+
                dev_priv->gart_info.table_mask = DMA_BIT_MASK(32);
                /* if we have an offset set from userspace */
                if (dev_priv->pcigart_offset_set) {
                        dev_priv->gart_info.bus_addr =
-                           dev_priv->pcigart_offset + dev_priv->fb_location;
+                               (resource_size_t)dev_priv->pcigart_offset + dev_priv->fb_location;
                        dev_priv->gart_info.mapping.offset =
                            dev_priv->pcigart_offset + dev_priv->fb_aper_offset;
                        dev_priv->gart_info.mapping.size =
@@ -1214,12 +1457,31 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
                        }
                }
 
-               if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
+               sctrl = RADEON_READ(RADEON_SURFACE_CNTL);
+               RADEON_WRITE(RADEON_SURFACE_CNTL, 0);
+               if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
+                       ret = r600_page_table_init(dev);
+               else
+                       ret = drm_ati_pcigart_init(dev, &dev_priv->gart_info);
+               RADEON_WRITE(RADEON_SURFACE_CNTL, sctrl);
+
+               if (!ret) {
                        DRM_ERROR("failed to init PCI GART!\n");
                        radeon_do_cleanup_cp(dev);
                        return -ENOMEM;
                }
 
+               ret = radeon_setup_pcigart_surface(dev_priv);
+               if (ret) {
+                       DRM_ERROR("failed to setup GART surface!\n");
+                       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
+                               r600_page_table_cleanup(dev, &dev_priv->gart_info);
+                       else
+                               drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info);
+                       radeon_do_cleanup_cp(dev);
+                       return ret;
+               }
+
                /* Turn on PCI GART */
                radeon_set_pcigart(dev_priv, 1);
        }
@@ -1268,14 +1530,18 @@ static int radeon_do_cleanup_cp(struct drm_device * dev)
                if (dev_priv->gart_info.bus_addr) {
                        /* Turn off PCI GART */
                        radeon_set_pcigart(dev_priv, 0);
-                       if (!drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info))
-                               DRM_ERROR("failed to cleanup PCI GART!\n");
+                       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
+                               r600_page_table_cleanup(dev, &dev_priv->gart_info);
+                       else {
+                               if (!drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info))
+                                       DRM_ERROR("failed to cleanup PCI GART!\n");
+                       }
                }
 
                if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB)
                {
                        drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev);
-                       dev_priv->gart_info.addr = 0;
+                       dev_priv->gart_info.addr = NULL;
                }
        }
        /* only clear to the start of flags */
@@ -1326,6 +1592,7 @@ static int radeon_do_resume_cp(struct drm_device *dev, struct drm_file *file_pri
 
 int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
+       drm_radeon_private_t *dev_priv = dev->dev_private;
        drm_radeon_init_t *init = data;
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
@@ -1338,8 +1605,13 @@ int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_pri
        case RADEON_INIT_R200_CP:
        case RADEON_INIT_R300_CP:
                return radeon_do_init_cp(dev, init, file_priv);
+       case RADEON_INIT_R600_CP:
+               return r600_do_init_cp(dev, init, file_priv);
        case RADEON_CLEANUP_CP:
-               return radeon_do_cleanup_cp(dev);
+               if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+                       return r600_do_cleanup_cp(dev);
+               else
+                       return radeon_do_cleanup_cp(dev);
        }
 
        return -EINVAL;
@@ -1362,7 +1634,10 @@ int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_pr
                return 0;
        }
 
-       radeon_do_cp_start(dev_priv);
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               r600_do_cp_start(dev_priv);
+       else
+               radeon_do_cp_start(dev_priv);
 
        return 0;
 }
@@ -1393,7 +1668,10 @@ int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_pri
         * code so that the DRM ioctl wrapper can try again.
         */
        if (stop->idle) {
-               ret = radeon_do_cp_idle(dev_priv);
+               if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+                       ret = r600_do_cp_idle(dev_priv);
+               else
+                       ret = radeon_do_cp_idle(dev_priv);
                if (ret)
                        return ret;
        }
@@ -1402,10 +1680,16 @@ int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_pri
         * we will get some dropped triangles as they won't be fully
         * rendered before the CP is shut down.
         */
-       radeon_do_cp_stop(dev_priv);
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               r600_do_cp_stop(dev_priv);
+       else
+               radeon_do_cp_stop(dev_priv);
 
        /* Reset the engine */
-       radeon_do_engine_reset(dev);
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               r600_do_engine_reset(dev);
+       else
+               radeon_do_engine_reset(dev);
 
        return 0;
 }
@@ -1418,29 +1702,47 @@ void radeon_do_release(struct drm_device * dev)
        if (dev_priv) {
                if (dev_priv->cp_running) {
                        /* Stop the cp */
-                       while ((ret = radeon_do_cp_idle(dev_priv)) != 0) {
-                               DRM_DEBUG("radeon_do_cp_idle %d\n", ret);
+                       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
+                               while ((ret = r600_do_cp_idle(dev_priv)) != 0) {
+                                       DRM_DEBUG("radeon_do_cp_idle %d\n", ret);
+#ifdef __linux__
+                                       schedule();
+#else
+                                       tsleep(&ret, PZERO, "rdnrel", 1);
+#endif
+                               }
+                       } else {
+                               while ((ret = radeon_do_cp_idle(dev_priv)) != 0) {
+                                       DRM_DEBUG("radeon_do_cp_idle %d\n", ret);
 #ifdef __linux__
-                               schedule();
+                                       schedule();
 #else
-                               tsleep(&ret, PZERO, "rdnrel", 1);
+                                       tsleep(&ret, PZERO, "rdnrel", 1);
 #endif
+                               }
+                       }
+                       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
+                               r600_do_cp_stop(dev_priv);
+                               r600_do_engine_reset(dev);
+                       } else {
+                               radeon_do_cp_stop(dev_priv);
+                               radeon_do_engine_reset(dev);
                        }
-                       radeon_do_cp_stop(dev_priv);
-                       radeon_do_engine_reset(dev);
                }
 
-               /* Disable *all* interrupts */
-               if (dev_priv->mmio)     /* remove this after permanent addmaps */
-                       RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
-
-               if (dev_priv->mmio) {   /* remove all surfaces */
-                       for (i = 0; i < RADEON_MAX_SURFACES; i++) {
-                               RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * i, 0);
-                               RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND +
-                                            16 * i, 0);
-                               RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND +
-                                            16 * i, 0);
+               if ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_R600) {
+                       /* Disable *all* interrupts */
+                       if (dev_priv->mmio)     /* remove this after permanent addmaps */
+                               RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
+
+                       if (dev_priv->mmio) {   /* remove all surfaces */
+                               for (i = 0; i < RADEON_MAX_SURFACES; i++) {
+                                       RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * i, 0);
+                                       RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND +
+                                                    16 * i, 0);
+                                       RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND +
+                                                    16 * i, 0);
+                               }
                        }
                }
 
@@ -1449,7 +1751,10 @@ void radeon_do_release(struct drm_device * dev)
                radeon_mem_takedown(&(dev_priv->fb_heap));
 
                /* deallocate kernel resources */
-               radeon_do_cleanup_cp(dev);
+               if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+                       r600_do_cleanup_cp(dev);
+               else
+                       radeon_do_cleanup_cp(dev);
        }
 }
 
@@ -1467,7 +1772,10 @@ int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_pr
                return -EINVAL;
        }
 
-       radeon_do_cp_reset(dev_priv);
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               r600_do_cp_reset(dev_priv);
+       else
+               radeon_do_cp_reset(dev_priv);
 
        /* The CP is no longer running after an engine reset */
        dev_priv->cp_running = 0;
@@ -1482,23 +1790,36 @@ int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_pri
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       return radeon_do_cp_idle(dev_priv);
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               return r600_do_cp_idle(dev_priv);
+       else
+               return radeon_do_cp_idle(dev_priv);
 }
 
 /* Added by Charl P. Botha to call radeon_do_resume_cp().
  */
 int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       return radeon_do_resume_cp(dev, file_priv);
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       DRM_DEBUG("\n");
+
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               return r600_do_resume_cp(dev, file_priv);
+       else
+               return radeon_do_resume_cp(dev, file_priv);
 }
 
 int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
+       drm_radeon_private_t *dev_priv = dev->dev_private;
        DRM_DEBUG("\n");
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       return radeon_do_engine_reset(dev);
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               return r600_do_engine_reset(dev);
+       else
+               return radeon_do_engine_reset(dev);
 }
 
 /* ================================================================
@@ -1548,7 +1869,7 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
        start = dev_priv->last_buf;
 
        for (t = 0; t < dev_priv->usec_timeout; t++) {
-               u32 done_age = GET_SCRATCH(1);
+               u32 done_age = GET_SCRATCH(dev_priv, 1);
                DRM_DEBUG("done_age = %d\n", done_age);
                for (i = start; i < dma->buf_count; i++) {
                        buf = dma->buflist[i];
@@ -1582,8 +1903,9 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
        struct drm_buf *buf;
        int i, t;
        int start;
-       u32 done_age = DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1));
+       u32 done_age;
 
+       done_age = radeon_read_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1));
        if (++dev_priv->last_buf >= dma->buf_count)
                dev_priv->last_buf = 0;
 
@@ -1854,3 +2176,41 @@ int radeon_driver_unload(struct drm_device *dev)
        dev->dev_private = NULL;
        return 0;
 }
+
+void radeon_commit_ring(drm_radeon_private_t *dev_priv)
+{
+       int i;
+       u32 *ring;
+       int tail_aligned;
+
+       /* check if the ring is padded out to 16-dword alignment */
+
+       tail_aligned = dev_priv->ring.tail & 0xf;
+       if (tail_aligned) {
+               int num_p2 = 16 - tail_aligned;
+
+               ring = dev_priv->ring.start;
+               /* pad with some CP_PACKET2 */
+               for (i = 0; i < num_p2; i++)
+                       ring[dev_priv->ring.tail + i] = CP_PACKET2();
+
+               dev_priv->ring.tail += i;
+
+               dev_priv->ring.space -= num_p2 * sizeof(u32);
+       }
+
+       dev_priv->ring.tail &= dev_priv->ring.tail_mask;
+
+       DRM_MEMORYBARRIER();
+       GET_RING_HEAD( dev_priv );
+
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
+               RADEON_WRITE(R600_CP_RB_WPTR, dev_priv->ring.tail);
+               /* read from PCI bus to ensure correct posting */
+               RADEON_READ(R600_CP_RB_RPTR);
+       } else {
+               RADEON_WRITE(RADEON_CP_RB_WPTR, dev_priv->ring.tail);
+               /* read from PCI bus to ensure correct posting */
+               RADEON_READ(RADEON_CP_RB_RPTR);
+       }
+}
index fef207881f45eeb34d5149c571b80fefbb2e47b2..13a60f4d42275f772c81a360d0c2d60fd83f8c17 100644 (file)
@@ -41,23 +41,15 @@ int radeon_no_wb;
 MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
 module_param_named(no_wb, radeon_no_wb, int, 0444);
 
-static int dri_library_name(struct drm_device *dev, char *buf)
-{
-       drm_radeon_private_t *dev_priv = dev->dev_private;
-       int family = dev_priv->flags & RADEON_FAMILY_MASK;
-
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       (family < CHIP_R200) ? "radeon" :
-                       ((family < CHIP_R300) ? "r200" :
-                       "r300"));
-}
-
 static int radeon_suspend(struct drm_device *dev, pm_message_t state)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
 
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               return 0;
+
        /* Disable *all* interrupts */
-       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600)
                RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
        RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
        return 0;
@@ -67,8 +59,11 @@ static int radeon_resume(struct drm_device *dev)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
 
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               return 0;
+
        /* Restore interrupt registers */
-       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600)
                RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg);
        RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
        return 0;
@@ -95,7 +90,6 @@ static struct drm_driver driver = {
        .get_vblank_counter = radeon_get_vblank_counter,
        .enable_vblank = radeon_enable_vblank,
        .disable_vblank = radeon_disable_vblank,
-       .dri_library_name = dri_library_name,
        .master_create = radeon_master_create,
        .master_destroy = radeon_master_destroy,
        .irq_preinstall = radeon_driver_irq_preinstall,
index 490bc7ceef60fe21dcaa8bb800fdc18fdbe1aea1..ed4d27e6ee6f14a30cfc5c860c40f730630c9655 100644 (file)
@@ -126,6 +126,7 @@ enum radeon_family {
        CHIP_RV410,
        CHIP_RS400,
        CHIP_RS480,
+       CHIP_RS600,
        CHIP_RS690,
        CHIP_RS740,
        CHIP_RV515,
@@ -134,6 +135,16 @@ enum radeon_family {
        CHIP_RV560,
        CHIP_RV570,
        CHIP_R580,
+       CHIP_R600,
+       CHIP_RV610,
+       CHIP_RV630,
+       CHIP_RV620,
+       CHIP_RV635,
+       CHIP_RV670,
+       CHIP_RS780,
+       CHIP_RV770,
+       CHIP_RV730,
+       CHIP_RV710,
        CHIP_LAST,
 };
 
@@ -160,10 +171,6 @@ enum radeon_chip_flags {
        RADEON_IS_IGPGART = 0x01000000UL,
 };
 
-#define GET_RING_HEAD(dev_priv)        (dev_priv->writeback_works ? \
-        DRM_READ32(  (dev_priv)->ring_rptr, 0 ) : RADEON_READ(RADEON_CP_RB_RPTR))
-#define SET_RING_HEAD(dev_priv,val)    DRM_WRITE32( (dev_priv)->ring_rptr, 0, (val) )
-
 typedef struct drm_radeon_freelist {
        unsigned int age;
        struct drm_buf *buf;
@@ -221,10 +228,11 @@ struct radeon_virt_surface {
        u32 upper;
        u32 flags;
        struct drm_file *file_priv;
+#define PCIGART_FILE_PRIV      ((void *) -1L)
 };
 
-#define RADEON_FLUSH_EMITED    (1 < 0)
-#define RADEON_PURGE_EMITED    (1 < 1)
+#define RADEON_FLUSH_EMITED    (1 << 0)
+#define RADEON_PURGE_EMITED    (1 << 1)
 
 struct drm_radeon_master_private {
        drm_local_map_t *sarea;
@@ -248,7 +256,6 @@ typedef struct drm_radeon_private {
        drm_radeon_freelist_t *head;
        drm_radeon_freelist_t *tail;
        int last_buf;
-       volatile u32 *scratch;
        int writeback_works;
 
        int usec_timeout;
@@ -316,11 +323,31 @@ typedef struct drm_radeon_private {
 
        /* starting from here on, data is preserved accross an open */
        uint32_t flags;         /* see radeon_chip_flags */
-       unsigned long fb_aper_offset;
+       resource_size_t fb_aper_offset;
 
        int num_gb_pipes;
        int track_flush;
        drm_local_map_t *mmio;
+
+       /* r6xx/r7xx pipe/shader config */
+       int r600_max_pipes;
+       int r600_max_tile_pipes;
+       int r600_max_simds;
+       int r600_max_backends;
+       int r600_max_gprs;
+       int r600_max_threads;
+       int r600_max_stack_entries;
+       int r600_max_hw_contexts;
+       int r600_max_gs_threads;
+       int r600_sx_max_export_size;
+       int r600_sx_max_export_pos_size;
+       int r600_sx_max_export_smx_size;
+       int r600_sq_num_cf_insts;
+       int r700_sx_num_of_sets;
+       int r700_sc_prim_fifo_size;
+       int r700_sc_hiz_tile_fifo_size;
+       int r700_sc_earlyz_tile_fifo_fize;
+
 } drm_radeon_private_t;
 
 typedef struct drm_radeon_buf_priv {
@@ -338,6 +365,12 @@ extern int radeon_no_wb;
 extern struct drm_ioctl_desc radeon_ioctls[];
 extern int radeon_max_ioctl;
 
+extern u32 radeon_get_ring_head(drm_radeon_private_t *dev_priv);
+extern void radeon_set_ring_head(drm_radeon_private_t *dev_priv, u32 val);
+
+#define GET_RING_HEAD(dev_priv)        radeon_get_ring_head(dev_priv)
+#define SET_RING_HEAD(dev_priv, val) radeon_set_ring_head(dev_priv, val)
+
 /* Check whether the given hardware address is inside the framebuffer or the
  * GART area.
  */
@@ -364,6 +397,9 @@ extern int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_fi
 extern int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);
 extern int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
 extern u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv);
+extern void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc);
+extern void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base);
+extern u32 RADEON_READ_MM(drm_radeon_private_t *dev_priv, int addr);
 
 extern void radeon_freelist_reset(struct drm_device * dev);
 extern struct drm_buf *radeon_freelist_get(struct drm_device * dev);
@@ -383,6 +419,10 @@ extern void radeon_mem_takedown(struct mem_block **heap);
 extern void radeon_mem_release(struct drm_file *file_priv,
                               struct mem_block *heap);
 
+extern void radeon_enable_bm(struct drm_radeon_private *dev_priv);
+extern u32 radeon_read_ring_rptr(drm_radeon_private_t *dev_priv, u32 off);
+extern void radeon_write_ring_rptr(drm_radeon_private_t *dev_priv, u32 off, u32 val);
+
                                /* radeon_irq.c */
 extern void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state);
 extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv);
@@ -423,6 +463,21 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
                             struct drm_file *file_priv,
                             drm_radeon_kcmd_buffer_t *cmdbuf);
 
+/* r600_cp.c */
+extern int r600_do_engine_reset(struct drm_device *dev);
+extern int r600_do_cleanup_cp(struct drm_device *dev);
+extern int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
+                          struct drm_file *file_priv);
+extern int r600_do_resume_cp(struct drm_device *dev, struct drm_file *file_priv);
+extern int r600_do_cp_idle(drm_radeon_private_t *dev_priv);
+extern void r600_do_cp_start(drm_radeon_private_t *dev_priv);
+extern void r600_do_cp_reset(drm_radeon_private_t *dev_priv);
+extern void r600_do_cp_stop(drm_radeon_private_t *dev_priv);
+extern int r600_cp_dispatch_indirect(struct drm_device *dev,
+                                    struct drm_buf *buf, int start, int end);
+extern int r600_page_table_init(struct drm_device *dev);
+extern void r600_page_table_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info);
+
 /* Flags for stats.boxes
  */
 #define RADEON_BOX_DMA_IDLE      0x1
@@ -434,6 +489,8 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
 /* Register definitions, register access macros and drmAddMap constants
  * for Radeon kernel driver.
  */
+#define RADEON_MM_INDEX                        0x0000
+#define RADEON_MM_DATA                 0x0004
 
 #define RADEON_AGP_COMMAND             0x0f60
 #define RADEON_AGP_COMMAND_PCI_CONFIG   0x0060 /* offset in PCI config */
@@ -556,6 +613,56 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
 #define RS690_MC_AGP_BASE               0x102
 #define RS690_MC_AGP_BASE_2             0x103
 
+#define RS600_MC_INDEX                          0x70
+#       define RS600_MC_ADDR_MASK               0xffff
+#       define RS600_MC_IND_SEQ_RBS_0           (1 << 16)
+#       define RS600_MC_IND_SEQ_RBS_1           (1 << 17)
+#       define RS600_MC_IND_SEQ_RBS_2           (1 << 18)
+#       define RS600_MC_IND_SEQ_RBS_3           (1 << 19)
+#       define RS600_MC_IND_AIC_RBS             (1 << 20)
+#       define RS600_MC_IND_CITF_ARB0           (1 << 21)
+#       define RS600_MC_IND_CITF_ARB1           (1 << 22)
+#       define RS600_MC_IND_WR_EN               (1 << 23)
+#define RS600_MC_DATA                           0x74
+
+#define RS600_MC_STATUS                         0x0
+#       define RS600_MC_IDLE                    (1 << 1)
+#define RS600_MC_FB_LOCATION                    0x4
+#define RS600_MC_AGP_LOCATION                   0x5
+#define RS600_AGP_BASE                          0x6
+#define RS600_AGP_BASE_2                        0x7
+#define RS600_MC_CNTL1                          0x9
+#       define RS600_ENABLE_PAGE_TABLES         (1 << 26)
+#define RS600_MC_PT0_CNTL                       0x100
+#       define RS600_ENABLE_PT                  (1 << 0)
+#       define RS600_EFFECTIVE_L2_CACHE_SIZE(x) ((x) << 15)
+#       define RS600_EFFECTIVE_L2_QUEUE_SIZE(x) ((x) << 21)
+#       define RS600_INVALIDATE_ALL_L1_TLBS     (1 << 28)
+#       define RS600_INVALIDATE_L2_CACHE        (1 << 29)
+#define RS600_MC_PT0_CONTEXT0_CNTL              0x102
+#       define RS600_ENABLE_PAGE_TABLE          (1 << 0)
+#       define RS600_PAGE_TABLE_TYPE_FLAT       (0 << 1)
+#define RS600_MC_PT0_SYSTEM_APERTURE_LOW_ADDR   0x112
+#define RS600_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR  0x114
+#define RS600_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR 0x11c
+#define RS600_MC_PT0_CONTEXT0_FLAT_BASE_ADDR    0x12c
+#define RS600_MC_PT0_CONTEXT0_FLAT_START_ADDR   0x13c
+#define RS600_MC_PT0_CONTEXT0_FLAT_END_ADDR     0x14c
+#define RS600_MC_PT0_CLIENT0_CNTL               0x16c
+#       define RS600_ENABLE_TRANSLATION_MODE_OVERRIDE       (1 << 0)
+#       define RS600_TRANSLATION_MODE_OVERRIDE              (1 << 1)
+#       define RS600_SYSTEM_ACCESS_MODE_MASK                (3 << 8)
+#       define RS600_SYSTEM_ACCESS_MODE_PA_ONLY             (0 << 8)
+#       define RS600_SYSTEM_ACCESS_MODE_USE_SYS_MAP         (1 << 8)
+#       define RS600_SYSTEM_ACCESS_MODE_IN_SYS              (2 << 8)
+#       define RS600_SYSTEM_ACCESS_MODE_NOT_IN_SYS          (3 << 8)
+#       define RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASSTHROUGH        (0 << 10)
+#       define RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_DEFAULT_PAGE       (1 << 10)
+#       define RS600_EFFECTIVE_L1_CACHE_SIZE(x) ((x) << 11)
+#       define RS600_ENABLE_FRAGMENT_PROCESSING (1 << 14)
+#       define RS600_EFFECTIVE_L1_QUEUE_SIZE(x) ((x) << 15)
+#       define RS600_INVALIDATE_L1_TLB          (1 << 20)
+
 #define R520_MC_IND_INDEX 0x70
 #define R520_MC_IND_WR_EN (1 << 24)
 #define R520_MC_IND_DATA  0x74
@@ -580,7 +687,6 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
 /* pipe config regs */
 #define R400_GB_PIPE_SELECT             0x402c
 #define R500_DYN_SCLK_PWMEM_PIPE        0x000d /* PLL */
-#define R500_SU_REG_DEST                0x42c8
 #define R300_GB_TILE_CONFIG             0x4018
 #       define R300_ENABLE_TILING       (1 << 0)
 #       define R300_PIPE_COUNT_RV350    (0 << 1)
@@ -639,9 +745,22 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
 
 #define RADEON_SCRATCHOFF( x )         (RADEON_SCRATCH_REG_OFFSET + 4*(x))
 
-#define GET_SCRATCH( x )       (dev_priv->writeback_works                      \
-                               ? DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(x) ) \
-                               : RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) )
+extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index);
+
+#define GET_SCRATCH(dev_priv, x) radeon_get_scratch(dev_priv, x)
+
+#define R600_SCRATCH_REG0              0x8500
+#define R600_SCRATCH_REG1              0x8504
+#define R600_SCRATCH_REG2              0x8508
+#define R600_SCRATCH_REG3              0x850c
+#define R600_SCRATCH_REG4              0x8510
+#define R600_SCRATCH_REG5              0x8514
+#define R600_SCRATCH_REG6              0x8518
+#define R600_SCRATCH_REG7              0x851c
+#define R600_SCRATCH_UMSK              0x8540
+#define R600_SCRATCH_ADDR              0x8544
+
+#define R600_SCRATCHOFF(x)             (R600_SCRATCH_REG_OFFSET + 4*(x))
 
 #define RADEON_GEN_INT_CNTL            0x0040
 #      define RADEON_CRTC_VBLANK_MASK          (1 << 0)
@@ -922,6 +1041,7 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
 #define RADEON_CP_RB_CNTL              0x0704
 #      define RADEON_BUF_SWAP_32BIT            (2 << 16)
 #      define RADEON_RB_NO_UPDATE              (1 << 27)
+#      define RADEON_RB_RPTR_WR_ENA            (1 << 31)
 #define RADEON_CP_RB_RPTR_ADDR         0x070c
 #define RADEON_CP_RB_RPTR              0x0710
 #define RADEON_CP_RB_WPTR              0x0714
@@ -983,6 +1103,14 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
 #      define RADEON_CNTL_BITBLT_MULTI         0x00009B00
 #      define RADEON_CNTL_SET_SCISSORS         0xC0001E00
 
+#      define R600_IT_INDIRECT_BUFFER          0x00003200
+#      define R600_IT_ME_INITIALIZE            0x00004400
+#             define R600_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16)
+#      define R600_IT_EVENT_WRITE              0x00004600
+#      define R600_IT_SET_CONFIG_REG           0x00006800
+#      define R600_SET_CONFIG_REG_OFFSET       0x00008000
+#      define R600_SET_CONFIG_REG_END          0x0000ac00
+
 #define RADEON_CP_PACKET_MASK          0xC0000000
 #define RADEON_CP_PACKET_COUNT_MASK    0x3fff0000
 #define RADEON_CP_PACKET0_REG_MASK     0x000007ff
@@ -1181,6 +1309,422 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
 #define R500_D1_VBLANK_INTERRUPT (1 << 4)
 #define R500_D2_VBLANK_INTERRUPT (1 << 5)
 
+/* R6xx/R7xx registers */
+#define R600_MC_VM_FB_LOCATION                                 0x2180
+#define R600_MC_VM_AGP_TOP                                     0x2184
+#define R600_MC_VM_AGP_BOT                                     0x2188
+#define R600_MC_VM_AGP_BASE                                    0x218c
+#define R600_MC_VM_SYSTEM_APERTURE_LOW_ADDR                    0x2190
+#define R600_MC_VM_SYSTEM_APERTURE_HIGH_ADDR                   0x2194
+#define R600_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR                0x2198
+
+#define R700_MC_VM_FB_LOCATION                                 0x2024
+#define R700_MC_VM_AGP_TOP                                     0x2028
+#define R700_MC_VM_AGP_BOT                                     0x202c
+#define R700_MC_VM_AGP_BASE                                    0x2030
+#define R700_MC_VM_SYSTEM_APERTURE_LOW_ADDR                    0x2034
+#define R700_MC_VM_SYSTEM_APERTURE_HIGH_ADDR                   0x2038
+#define R700_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR                0x203c
+
+#define R600_MCD_RD_A_CNTL                                     0x219c
+#define R600_MCD_RD_B_CNTL                                     0x21a0
+
+#define R600_MCD_WR_A_CNTL                                     0x21a4
+#define R600_MCD_WR_B_CNTL                                     0x21a8
+
+#define R600_MCD_RD_SYS_CNTL                                   0x2200
+#define R600_MCD_WR_SYS_CNTL                                   0x2214
+
+#define R600_MCD_RD_GFX_CNTL                                   0x21fc
+#define R600_MCD_RD_HDP_CNTL                                   0x2204
+#define R600_MCD_RD_PDMA_CNTL                                  0x2208
+#define R600_MCD_RD_SEM_CNTL                                   0x220c
+#define R600_MCD_WR_GFX_CNTL                                   0x2210
+#define R600_MCD_WR_HDP_CNTL                                   0x2218
+#define R600_MCD_WR_PDMA_CNTL                                  0x221c
+#define R600_MCD_WR_SEM_CNTL                                   0x2220
+
+#       define R600_MCD_L1_TLB                                 (1 << 0)
+#       define R600_MCD_L1_FRAG_PROC                           (1 << 1)
+#       define R600_MCD_L1_STRICT_ORDERING                     (1 << 2)
+
+#       define R600_MCD_SYSTEM_ACCESS_MODE_MASK                (3 << 6)
+#       define R600_MCD_SYSTEM_ACCESS_MODE_PA_ONLY             (0 << 6)
+#       define R600_MCD_SYSTEM_ACCESS_MODE_USE_SYS_MAP         (1 << 6)
+#       define R600_MCD_SYSTEM_ACCESS_MODE_IN_SYS              (2 << 6)
+#       define R600_MCD_SYSTEM_ACCESS_MODE_NOT_IN_SYS          (3 << 6)
+
+#       define R600_MCD_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU    (0 << 8)
+#       define R600_MCD_SYSTEM_APERTURE_UNMAPPED_ACCESS_DEFAULT_PAGE (1 << 8)
+
+#       define R600_MCD_SEMAPHORE_MODE                         (1 << 10)
+#       define R600_MCD_WAIT_L2_QUERY                          (1 << 11)
+#       define R600_MCD_EFFECTIVE_L1_TLB_SIZE(x)               ((x) << 12)
+#       define R600_MCD_EFFECTIVE_L1_QUEUE_SIZE(x)             ((x) << 15)
+
+#define R700_MC_VM_MD_L1_TLB0_CNTL                             0x2654
+#define R700_MC_VM_MD_L1_TLB1_CNTL                             0x2658
+#define R700_MC_VM_MD_L1_TLB2_CNTL                             0x265c
+
+#define R700_MC_VM_MB_L1_TLB0_CNTL                             0x2234
+#define R700_MC_VM_MB_L1_TLB1_CNTL                             0x2238
+#define R700_MC_VM_MB_L1_TLB2_CNTL                             0x223c
+#define R700_MC_VM_MB_L1_TLB3_CNTL                             0x2240
+
+#       define R700_ENABLE_L1_TLB                              (1 << 0)
+#       define R700_ENABLE_L1_FRAGMENT_PROCESSING              (1 << 1)
+#       define R700_SYSTEM_ACCESS_MODE_IN_SYS                  (2 << 3)
+#       define R700_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU  (0 << 5)
+#       define R700_EFFECTIVE_L1_TLB_SIZE(x)                   ((x) << 15)
+#       define R700_EFFECTIVE_L1_QUEUE_SIZE(x)                 ((x) << 18)
+
+#define R700_MC_ARB_RAMCFG                                     0x2760
+#       define R700_NOOFBANK_SHIFT                             0
+#       define R700_NOOFBANK_MASK                              0x3
+#       define R700_NOOFRANK_SHIFT                             2
+#       define R700_NOOFRANK_MASK                              0x1
+#       define R700_NOOFROWS_SHIFT                             3
+#       define R700_NOOFROWS_MASK                              0x7
+#       define R700_NOOFCOLS_SHIFT                             6
+#       define R700_NOOFCOLS_MASK                              0x3
+#       define R700_CHANSIZE_SHIFT                             8
+#       define R700_CHANSIZE_MASK                              0x1
+#       define R700_BURSTLENGTH_SHIFT                          9
+#       define R700_BURSTLENGTH_MASK                           0x1
+#define R600_RAMCFG                                            0x2408
+#       define R600_NOOFBANK_SHIFT                             0
+#       define R600_NOOFBANK_MASK                              0x1
+#       define R600_NOOFRANK_SHIFT                             1
+#       define R600_NOOFRANK_MASK                              0x1
+#       define R600_NOOFROWS_SHIFT                             2
+#       define R600_NOOFROWS_MASK                              0x7
+#       define R600_NOOFCOLS_SHIFT                             5
+#       define R600_NOOFCOLS_MASK                              0x3
+#       define R600_CHANSIZE_SHIFT                             7
+#       define R600_CHANSIZE_MASK                              0x1
+#       define R600_BURSTLENGTH_SHIFT                          8
+#       define R600_BURSTLENGTH_MASK                           0x1
+
+#define R600_VM_L2_CNTL                                        0x1400
+#       define R600_VM_L2_CACHE_EN                             (1 << 0)
+#       define R600_VM_L2_FRAG_PROC                            (1 << 1)
+#       define R600_VM_ENABLE_PTE_CACHE_LRU_W                  (1 << 9)
+#       define R600_VM_L2_CNTL_QUEUE_SIZE(x)                   ((x) << 13)
+#       define R700_VM_L2_CNTL_QUEUE_SIZE(x)                   ((x) << 14)
+
+#define R600_VM_L2_CNTL2                                       0x1404
+#       define R600_VM_L2_CNTL2_INVALIDATE_ALL_L1_TLBS         (1 << 0)
+#       define R600_VM_L2_CNTL2_INVALIDATE_L2_CACHE            (1 << 1)
+#define R600_VM_L2_CNTL3                                       0x1408
+#       define R600_VM_L2_CNTL3_BANK_SELECT_0(x)               ((x) << 0)
+#       define R600_VM_L2_CNTL3_BANK_SELECT_1(x)               ((x) << 5)
+#       define R600_VM_L2_CNTL3_CACHE_UPDATE_MODE(x)           ((x) << 10)
+#       define R700_VM_L2_CNTL3_BANK_SELECT(x)                 ((x) << 0)
+#       define R700_VM_L2_CNTL3_CACHE_UPDATE_MODE(x)           ((x) << 6)
+
+#define R600_VM_L2_STATUS                                      0x140c
+
+#define R600_VM_CONTEXT0_CNTL                                  0x1410
+#       define R600_VM_ENABLE_CONTEXT                          (1 << 0)
+#       define R600_VM_PAGE_TABLE_DEPTH_FLAT                   (0 << 1)
+
+#define R600_VM_CONTEXT0_CNTL2                                 0x1430
+#define R600_VM_CONTEXT0_REQUEST_RESPONSE                      0x1470
+#define R600_VM_CONTEXT0_INVALIDATION_LOW_ADDR                 0x1490
+#define R600_VM_CONTEXT0_INVALIDATION_HIGH_ADDR                0x14b0
+#define R600_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR                  0x1574
+#define R600_VM_CONTEXT0_PAGE_TABLE_START_ADDR                 0x1594
+#define R600_VM_CONTEXT0_PAGE_TABLE_END_ADDR                   0x15b4
+
+#define R700_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR                  0x153c
+#define R700_VM_CONTEXT0_PAGE_TABLE_START_ADDR                 0x155c
+#define R700_VM_CONTEXT0_PAGE_TABLE_END_ADDR                   0x157c
+
+#define R600_HDP_HOST_PATH_CNTL                                0x2c00
+
+#define R600_GRBM_CNTL                                         0x8000
+#       define R600_GRBM_READ_TIMEOUT(x)                       ((x) << 0)
+
+#define R600_GRBM_STATUS                                       0x8010
+#       define R600_CMDFIFO_AVAIL_MASK                         0x1f
+#       define R700_CMDFIFO_AVAIL_MASK                         0xf
+#       define R600_GUI_ACTIVE                                 (1 << 31)
+#define R600_GRBM_STATUS2                                      0x8014
+#define R600_GRBM_SOFT_RESET                                   0x8020
+#       define R600_SOFT_RESET_CP                              (1 << 0)
+#define R600_WAIT_UNTIL                                               0x8040
+
+#define R600_CP_SEM_WAIT_TIMER                                 0x85bc
+#define R600_CP_ME_CNTL                                        0x86d8
+#       define R600_CP_ME_HALT                                 (1 << 28)
+#define R600_CP_QUEUE_THRESHOLDS                               0x8760
+#       define R600_ROQ_IB1_START(x)                           ((x) << 0)
+#       define R600_ROQ_IB2_START(x)                           ((x) << 8)
+#define R600_CP_MEQ_THRESHOLDS                                 0x8764
+#       define R700_STQ_SPLIT(x)                               ((x) << 0)
+#       define R600_MEQ_END(x)                                 ((x) << 16)
+#       define R600_ROQ_END(x)                                 ((x) << 24)
+#define R600_CP_PERFMON_CNTL                                   0x87fc
+#define R600_CP_RB_BASE                                        0xc100
+#define R600_CP_RB_CNTL                                        0xc104
+#       define R600_RB_BUFSZ(x)                                ((x) << 0)
+#       define R600_RB_BLKSZ(x)                                ((x) << 8)
+#       define R600_RB_NO_UPDATE                               (1 << 27)
+#       define R600_RB_RPTR_WR_ENA                             (1 << 31)
+#define R600_CP_RB_RPTR_WR                                     0xc108
+#define R600_CP_RB_RPTR_ADDR                                   0xc10c
+#define R600_CP_RB_RPTR_ADDR_HI                                0xc110
+#define R600_CP_RB_WPTR                                        0xc114
+#define R600_CP_RB_WPTR_ADDR                                   0xc118
+#define R600_CP_RB_WPTR_ADDR_HI                                0xc11c
+#define R600_CP_RB_RPTR                                        0x8700
+#define R600_CP_RB_WPTR_DELAY                                  0x8704
+#define R600_CP_PFP_UCODE_ADDR                                 0xc150
+#define R600_CP_PFP_UCODE_DATA                                 0xc154
+#define R600_CP_ME_RAM_RADDR                                   0xc158
+#define R600_CP_ME_RAM_WADDR                                   0xc15c
+#define R600_CP_ME_RAM_DATA                                    0xc160
+#define R600_CP_DEBUG                                          0xc1fc
+
+#define R600_PA_CL_ENHANCE                                     0x8a14
+#       define R600_CLIP_VTX_REORDER_ENA                       (1 << 0)
+#       define R600_NUM_CLIP_SEQ(x)                            ((x) << 1)
+#define R600_PA_SC_LINE_STIPPLE_STATE                          0x8b10
+#define R600_PA_SC_MULTI_CHIP_CNTL                             0x8b20
+#define R700_PA_SC_FORCE_EOV_MAX_CNTS                          0x8b24
+#       define R700_FORCE_EOV_MAX_CLK_CNT(x)                   ((x) << 0)
+#       define R700_FORCE_EOV_MAX_REZ_CNT(x)                   ((x) << 16)
+#define R600_PA_SC_AA_SAMPLE_LOCS_2S                           0x8b40
+#define R600_PA_SC_AA_SAMPLE_LOCS_4S                           0x8b44
+#define R600_PA_SC_AA_SAMPLE_LOCS_8S_WD0                       0x8b48
+#define R600_PA_SC_AA_SAMPLE_LOCS_8S_WD1                       0x8b4c
+#       define R600_S0_X(x)                                    ((x) << 0)
+#       define R600_S0_Y(x)                                    ((x) << 4)
+#       define R600_S1_X(x)                                    ((x) << 8)
+#       define R600_S1_Y(x)                                    ((x) << 12)
+#       define R600_S2_X(x)                                    ((x) << 16)
+#       define R600_S2_Y(x)                                    ((x) << 20)
+#       define R600_S3_X(x)                                    ((x) << 24)
+#       define R600_S3_Y(x)                                    ((x) << 28)
+#       define R600_S4_X(x)                                    ((x) << 0)
+#       define R600_S4_Y(x)                                    ((x) << 4)
+#       define R600_S5_X(x)                                    ((x) << 8)
+#       define R600_S5_Y(x)                                    ((x) << 12)
+#       define R600_S6_X(x)                                    ((x) << 16)
+#       define R600_S6_Y(x)                                    ((x) << 20)
+#       define R600_S7_X(x)                                    ((x) << 24)
+#       define R600_S7_Y(x)                                    ((x) << 28)
+#define R600_PA_SC_FIFO_SIZE                                   0x8bd0
+#       define R600_SC_PRIM_FIFO_SIZE(x)                       ((x) << 0)
+#       define R600_SC_HIZ_TILE_FIFO_SIZE(x)                   ((x) << 8)
+#       define R600_SC_EARLYZ_TILE_FIFO_SIZE(x)                ((x) << 16)
+#define R700_PA_SC_FIFO_SIZE_R7XX                              0x8bcc
+#       define R700_SC_PRIM_FIFO_SIZE(x)                       ((x) << 0)
+#       define R700_SC_HIZ_TILE_FIFO_SIZE(x)                   ((x) << 12)
+#       define R700_SC_EARLYZ_TILE_FIFO_SIZE(x)                ((x) << 20)
+#define R600_PA_SC_ENHANCE                                     0x8bf0
+#       define R600_FORCE_EOV_MAX_CLK_CNT(x)                   ((x) << 0)
+#       define R600_FORCE_EOV_MAX_TILE_CNT(x)                  ((x) << 12)
+#define R600_PA_SC_CLIPRECT_RULE                               0x2820c
+#define R700_PA_SC_EDGERULE                                    0x28230
+#define R600_PA_SC_LINE_STIPPLE                                0x28a0c
+#define R600_PA_SC_MODE_CNTL                                   0x28a4c
+#define R600_PA_SC_AA_CONFIG                                   0x28c04
+
+#define R600_SX_EXPORT_BUFFER_SIZES                            0x900c
+#       define R600_COLOR_BUFFER_SIZE(x)                       ((x) << 0)
+#       define R600_POSITION_BUFFER_SIZE(x)                    ((x) << 8)
+#       define R600_SMX_BUFFER_SIZE(x)                         ((x) << 16)
+#define R600_SX_DEBUG_1                                        0x9054
+#       define R600_SMX_EVENT_RELEASE                          (1 << 0)
+#       define R600_ENABLE_NEW_SMX_ADDRESS                     (1 << 16)
+#define R700_SX_DEBUG_1                                        0x9058
+#       define R700_ENABLE_NEW_SMX_ADDRESS                     (1 << 16)
+#define R600_SX_MISC                                           0x28350
+
+#define R600_DB_DEBUG                                          0x9830
+#       define R600_PREZ_MUST_WAIT_FOR_POSTZ_DONE              (1 << 31)
+#define R600_DB_WATERMARKS                                     0x9838
+#       define R600_DEPTH_FREE(x)                              ((x) << 0)
+#       define R600_DEPTH_FLUSH(x)                             ((x) << 5)
+#       define R600_DEPTH_PENDING_FREE(x)                      ((x) << 15)
+#       define R600_DEPTH_CACHELINE_FREE(x)                    ((x) << 20)
+#define R700_DB_DEBUG3                                         0x98b0
+#       define R700_DB_CLK_OFF_DELAY(x)                        ((x) << 11)
+#define RV700_DB_DEBUG4                                        0x9b8c
+#       define RV700_DISABLE_TILE_COVERED_FOR_PS_ITER          (1 << 6)
+
+#define R600_VGT_CACHE_INVALIDATION                            0x88c4
+#       define R600_CACHE_INVALIDATION(x)                      ((x) << 0)
+#       define R600_VC_ONLY                                    0
+#       define R600_TC_ONLY                                    1
+#       define R600_VC_AND_TC                                  2
+#       define R700_AUTO_INVLD_EN(x)                           ((x) << 6)
+#       define R700_NO_AUTO                                    0
+#       define R700_ES_AUTO                                    1
+#       define R700_GS_AUTO                                    2
+#       define R700_ES_AND_GS_AUTO                             3
+#define R600_VGT_GS_PER_ES                                     0x88c8
+#define R600_VGT_ES_PER_GS                                     0x88cc
+#define R600_VGT_GS_PER_VS                                     0x88e8
+#define R600_VGT_GS_VERTEX_REUSE                               0x88d4
+#define R600_VGT_NUM_INSTANCES                                 0x8974
+#define R600_VGT_STRMOUT_EN                                    0x28ab0
+#define R600_VGT_EVENT_INITIATOR                               0x28a90
+#       define R600_CACHE_FLUSH_AND_INV_EVENT                  (0x16 << 0)
+#define R600_VGT_VERTEX_REUSE_BLOCK_CNTL                       0x28c58
+#       define R600_VTX_REUSE_DEPTH_MASK                       0xff
+#define R600_VGT_OUT_DEALLOC_CNTL                              0x28c5c
+#       define R600_DEALLOC_DIST_MASK                          0x7f
+
+#define R600_CB_COLOR0_BASE                                    0x28040
+#define R600_CB_COLOR1_BASE                                    0x28044
+#define R600_CB_COLOR2_BASE                                    0x28048
+#define R600_CB_COLOR3_BASE                                    0x2804c
+#define R600_CB_COLOR4_BASE                                    0x28050
+#define R600_CB_COLOR5_BASE                                    0x28054
+#define R600_CB_COLOR6_BASE                                    0x28058
+#define R600_CB_COLOR7_BASE                                    0x2805c
+#define R600_CB_COLOR7_FRAG                                    0x280fc
+
+#define R600_TC_CNTL                                           0x9608
+#       define R600_TC_L2_SIZE(x)                              ((x) << 5)
+#       define R600_L2_DISABLE_LATE_HIT                        (1 << 9)
+
+#define R600_ARB_POP                                           0x2418
+#       define R600_ENABLE_TC128                               (1 << 30)
+#define R600_ARB_GDEC_RD_CNTL                                  0x246c
+
+#define R600_TA_CNTL_AUX                                       0x9508
+#       define R600_DISABLE_CUBE_WRAP                          (1 << 0)
+#       define R600_DISABLE_CUBE_ANISO                         (1 << 1)
+#       define R700_GETLOD_SELECT(x)                           ((x) << 2)
+#       define R600_SYNC_GRADIENT                              (1 << 24)
+#       define R600_SYNC_WALKER                                (1 << 25)
+#       define R600_SYNC_ALIGNER                               (1 << 26)
+#       define R600_BILINEAR_PRECISION_6_BIT                   (0 << 31)
+#       define R600_BILINEAR_PRECISION_8_BIT                   (1 << 31)
+
+#define R700_TCP_CNTL                                          0x9610
+
+#define R600_SMX_DC_CTL0                                       0xa020
+#       define R700_USE_HASH_FUNCTION                          (1 << 0)
+#       define R700_CACHE_DEPTH(x)                             ((x) << 1)
+#       define R700_FLUSH_ALL_ON_EVENT                         (1 << 10)
+#       define R700_STALL_ON_EVENT                             (1 << 11)
+#define R700_SMX_EVENT_CTL                                     0xa02c
+#       define R700_ES_FLUSH_CTL(x)                            ((x) << 0)
+#       define R700_GS_FLUSH_CTL(x)                            ((x) << 3)
+#       define R700_ACK_FLUSH_CTL(x)                           ((x) << 6)
+#       define R700_SYNC_FLUSH_CTL                             (1 << 8)
+
+#define R600_SQ_CONFIG                                         0x8c00
+#       define R600_VC_ENABLE                                  (1 << 0)
+#       define R600_EXPORT_SRC_C                               (1 << 1)
+#       define R600_DX9_CONSTS                                 (1 << 2)
+#       define R600_ALU_INST_PREFER_VECTOR                     (1 << 3)
+#       define R600_DX10_CLAMP                                 (1 << 4)
+#       define R600_CLAUSE_SEQ_PRIO(x)                         ((x) << 8)
+#       define R600_PS_PRIO(x)                                 ((x) << 24)
+#       define R600_VS_PRIO(x)                                 ((x) << 26)
+#       define R600_GS_PRIO(x)                                 ((x) << 28)
+#       define R600_ES_PRIO(x)                                 ((x) << 30)
+#define R600_SQ_GPR_RESOURCE_MGMT_1                            0x8c04
+#       define R600_NUM_PS_GPRS(x)                             ((x) << 0)
+#       define R600_NUM_VS_GPRS(x)                             ((x) << 16)
+#       define R700_DYN_GPR_ENABLE                             (1 << 27)
+#       define R600_NUM_CLAUSE_TEMP_GPRS(x)                    ((x) << 28)
+#define R600_SQ_GPR_RESOURCE_MGMT_2                            0x8c08
+#       define R600_NUM_GS_GPRS(x)                             ((x) << 0)
+#       define R600_NUM_ES_GPRS(x)                             ((x) << 16)
+#define R600_SQ_THREAD_RESOURCE_MGMT                           0x8c0c
+#       define R600_NUM_PS_THREADS(x)                          ((x) << 0)
+#       define R600_NUM_VS_THREADS(x)                          ((x) << 8)
+#       define R600_NUM_GS_THREADS(x)                          ((x) << 16)
+#       define R600_NUM_ES_THREADS(x)                          ((x) << 24)
+#define R600_SQ_STACK_RESOURCE_MGMT_1                          0x8c10
+#       define R600_NUM_PS_STACK_ENTRIES(x)                    ((x) << 0)
+#       define R600_NUM_VS_STACK_ENTRIES(x)                    ((x) << 16)
+#define R600_SQ_STACK_RESOURCE_MGMT_2                          0x8c14
+#       define R600_NUM_GS_STACK_ENTRIES(x)                    ((x) << 0)
+#       define R600_NUM_ES_STACK_ENTRIES(x)                    ((x) << 16)
+#define R600_SQ_MS_FIFO_SIZES                                  0x8cf0
+#       define R600_CACHE_FIFO_SIZE(x)                         ((x) << 0)
+#       define R600_FETCH_FIFO_HIWATER(x)                      ((x) << 8)
+#       define R600_DONE_FIFO_HIWATER(x)                       ((x) << 16)
+#       define R600_ALU_UPDATE_FIFO_HIWATER(x)                 ((x) << 24)
+#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_0                         0x8db0
+#       define R700_SIMDA_RING0(x)                             ((x) << 0)
+#       define R700_SIMDA_RING1(x)                             ((x) << 8)
+#       define R700_SIMDB_RING0(x)                             ((x) << 16)
+#       define R700_SIMDB_RING1(x)                             ((x) << 24)
+#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_1                         0x8db4
+#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_2                         0x8db8
+#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_3                         0x8dbc
+#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_4                         0x8dc0
+#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_5                         0x8dc4
+#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_6                         0x8dc8
+#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_7                         0x8dcc
+
+#define R600_SPI_PS_IN_CONTROL_0                               0x286cc
+#       define R600_NUM_INTERP(x)                              ((x) << 0)
+#       define R600_POSITION_ENA                               (1 << 8)
+#       define R600_POSITION_CENTROID                          (1 << 9)
+#       define R600_POSITION_ADDR(x)                           ((x) << 10)
+#       define R600_PARAM_GEN(x)                               ((x) << 15)
+#       define R600_PARAM_GEN_ADDR(x)                          ((x) << 19)
+#       define R600_BARYC_SAMPLE_CNTL(x)                       ((x) << 26)
+#       define R600_PERSP_GRADIENT_ENA                         (1 << 28)
+#       define R600_LINEAR_GRADIENT_ENA                        (1 << 29)
+#       define R600_POSITION_SAMPLE                            (1 << 30)
+#       define R600_BARYC_AT_SAMPLE_ENA                        (1 << 31)
+#define R600_SPI_PS_IN_CONTROL_1                               0x286d0
+#       define R600_GEN_INDEX_PIX                              (1 << 0)
+#       define R600_GEN_INDEX_PIX_ADDR(x)                      ((x) << 1)
+#       define R600_FRONT_FACE_ENA                             (1 << 8)
+#       define R600_FRONT_FACE_CHAN(x)                         ((x) << 9)
+#       define R600_FRONT_FACE_ALL_BITS                        (1 << 11)
+#       define R600_FRONT_FACE_ADDR(x)                         ((x) << 12)
+#       define R600_FOG_ADDR(x)                                ((x) << 17)
+#       define R600_FIXED_PT_POSITION_ENA                      (1 << 24)
+#       define R600_FIXED_PT_POSITION_ADDR(x)                  ((x) << 25)
+#       define R700_POSITION_ULC                               (1 << 30)
+#define R600_SPI_INPUT_Z                                       0x286d8
+
+#define R600_SPI_CONFIG_CNTL                                   0x9100
+#       define R600_GPR_WRITE_PRIORITY(x)                      ((x) << 0)
+#       define R600_DISABLE_INTERP_1                           (1 << 5)
+#define R600_SPI_CONFIG_CNTL_1                                 0x913c
+#       define R600_VTX_DONE_DELAY(x)                          ((x) << 0)
+#       define R600_INTERP_ONE_PRIM_PER_ROW                    (1 << 4)
+
+#define R600_GB_TILING_CONFIG                                  0x98f0
+#       define R600_PIPE_TILING(x)                             ((x) << 1)
+#       define R600_BANK_TILING(x)                             ((x) << 4)
+#       define R600_GROUP_SIZE(x)                              ((x) << 6)
+#       define R600_ROW_TILING(x)                              ((x) << 8)
+#       define R600_BANK_SWAPS(x)                              ((x) << 11)
+#       define R600_SAMPLE_SPLIT(x)                            ((x) << 14)
+#       define R600_BACKEND_MAP(x)                             ((x) << 16)
+#define R600_DCP_TILING_CONFIG                                 0x6ca0
+#define R600_HDP_TILING_CONFIG                                 0x2f3c
+
+#define R600_CC_RB_BACKEND_DISABLE                             0x98f4
+#define R700_CC_SYS_RB_BACKEND_DISABLE                         0x3f88
+#       define R600_BACKEND_DISABLE(x)                         ((x) << 16)
+
+#define R600_CC_GC_SHADER_PIPE_CONFIG                          0x8950
+#define R600_GC_USER_SHADER_PIPE_CONFIG                        0x8954
+#       define R600_INACTIVE_QD_PIPES(x)                       ((x) << 8)
+#       define R600_INACTIVE_QD_PIPES_MASK                     (0xff << 8)
+#       define R600_INACTIVE_SIMDS(x)                          ((x) << 16)
+#       define R600_INACTIVE_SIMDS_MASK                        (0xff << 16)
+
+#define R700_CGTS_SYS_TCC_DISABLE                              0x3f90
+#define R700_CGTS_USER_SYS_TCC_DISABLE                         0x3f94
+#define R700_CGTS_TCC_DISABLE                                  0x9148
+#define R700_CGTS_USER_TCC_DISABLE                             0x914c
+
 /* Constants */
 #define RADEON_MAX_USEC_TIMEOUT                100000  /* 100 ms */
 
@@ -1190,6 +1734,11 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
 #define RADEON_LAST_SWI_REG            RADEON_SCRATCH_REG3
 #define RADEON_LAST_DISPATCH           1
 
+#define R600_LAST_FRAME_REG            R600_SCRATCH_REG0
+#define R600_LAST_DISPATCH_REG         R600_SCRATCH_REG1
+#define R600_LAST_CLEAR_REG            R600_SCRATCH_REG2
+#define R600_LAST_SWI_REG              R600_SCRATCH_REG3
+
 #define RADEON_MAX_VB_AGE              0x7fffffff
 #define RADEON_MAX_VB_VERTS            (0xffff)
 
@@ -1198,7 +1747,15 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
 #define RADEON_PCIGART_TABLE_SIZE      (32*1024)
 
 #define RADEON_READ(reg)       DRM_READ32(  dev_priv->mmio, (reg) )
-#define RADEON_WRITE(reg,val)  DRM_WRITE32( dev_priv->mmio, (reg), (val) )
+#define RADEON_WRITE(reg, val)                                          \
+do {                                                                   \
+       if (reg < 0x10000) {                                            \
+               DRM_WRITE32(dev_priv->mmio, (reg), (val));              \
+       } else {                                                        \
+               DRM_WRITE32(dev_priv->mmio, RADEON_MM_INDEX, (reg));    \
+               DRM_WRITE32(dev_priv->mmio, RADEON_MM_DATA, (val));     \
+       }                                                               \
+} while (0)
 #define RADEON_READ8(reg)      DRM_READ8(  dev_priv->mmio, (reg) )
 #define RADEON_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) )
 
@@ -1238,11 +1795,19 @@ do {                                                            \
        RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK);    \
 } while (0)
 
+#define RS600_WRITE_MCIND(addr, val)                           \
+do {                                                           \
+       RADEON_WRITE(RS600_MC_INDEX, RS600_MC_IND_WR_EN | RS600_MC_IND_CITF_ARB0 | ((addr) & RS600_MC_ADDR_MASK)); \
+       RADEON_WRITE(RS600_MC_DATA, val);                       \
+} while (0)
+
 #define IGP_WRITE_MCIND(addr, val)                             \
 do {                                                                   \
        if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||   \
            ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))      \
                RS690_WRITE_MCIND(addr, val);                           \
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)  \
+               RS600_WRITE_MCIND(addr, val);                           \
        else                                                            \
                RS480_WRITE_MCIND(addr, val);                           \
 } while (0)
@@ -1346,7 +1911,11 @@ do {                                                             \
        struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; \
        drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;       \
        if ( sarea_priv->last_dispatch >= RADEON_MAX_VB_AGE ) {         \
-               int __ret = radeon_do_cp_idle( dev_priv );              \
+               int __ret;                                              \
+               if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) \
+                       __ret = r600_do_cp_idle(dev_priv);              \
+               else                                                    \
+                       __ret = radeon_do_cp_idle(dev_priv);            \
                if ( __ret ) return __ret;                              \
                sarea_priv->last_dispatch = 0;                          \
                radeon_freelist_reset( dev );                           \
@@ -1368,21 +1937,40 @@ do {                                                            \
        OUT_RING( age );                                                \
 } while (0)
 
+#define R600_DISPATCH_AGE(age) do {                                    \
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1));                \
+       OUT_RING((R600_LAST_DISPATCH_REG - R600_SET_CONFIG_REG_OFFSET) >> 2);  \
+       OUT_RING(age);                                                  \
+} while (0)
+
+#define R600_FRAME_AGE(age) do {                                       \
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1));                \
+       OUT_RING((R600_LAST_FRAME_REG - R600_SET_CONFIG_REG_OFFSET) >> 2);  \
+       OUT_RING(age);                                                  \
+} while (0)
+
+#define R600_CLEAR_AGE(age) do {                                       \
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1));                \
+       OUT_RING((R600_LAST_CLEAR_REG - R600_SET_CONFIG_REG_OFFSET) >> 2);  \
+       OUT_RING(age);                                                  \
+} while (0)
+
 /* ================================================================
  * Ring control
  */
 
 #define RADEON_VERBOSE 0
 
-#define RING_LOCALS    int write, _nr; unsigned int mask; u32 *ring;
+#define RING_LOCALS    int write, _nr, _align_nr; unsigned int mask; u32 *ring;
 
 #define BEGIN_RING( n ) do {                                           \
        if ( RADEON_VERBOSE ) {                                         \
                DRM_INFO( "BEGIN_RING( %d )\n", (n));                   \
        }                                                               \
-       if ( dev_priv->ring.space <= (n) * sizeof(u32) ) {              \
+       _align_nr = (n + 0xf) & ~0xf;                                   \
+       if (dev_priv->ring.space <= (_align_nr * sizeof(u32))) {        \
                 COMMIT_RING();                                         \
-               radeon_wait_ring( dev_priv, (n) * sizeof(u32) );        \
+               radeon_wait_ring( dev_priv, _align_nr * sizeof(u32));   \
        }                                                               \
        _nr = n; dev_priv->ring.space -= (n) * sizeof(u32);             \
        ring = dev_priv->ring.start;                                    \
@@ -1399,19 +1987,16 @@ do {                                                            \
                DRM_ERROR(                                              \
                        "ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n",        \
                        ((dev_priv->ring.tail + _nr) & mask),           \
-                       write, __LINE__);                                               \
+                       write, __LINE__);                               \
        } else                                                          \
                dev_priv->ring.tail = write;                            \
 } while (0)
 
+extern void radeon_commit_ring(drm_radeon_private_t *dev_priv);
+
 #define COMMIT_RING() do {                                             \
-       /* Flush writes to ring */                                      \
-       DRM_MEMORYBARRIER();                                            \
-       GET_RING_HEAD( dev_priv );                                      \
-       RADEON_WRITE( RADEON_CP_RB_WPTR, dev_priv->ring.tail );         \
-       /* read from PCI bus to ensure correct posting */               \
-       RADEON_READ( RADEON_CP_RB_RPTR );                               \
-} while (0)
+               radeon_commit_ring(dev_priv);                           \
+       } while(0)
 
 #define OUT_RING( x ) do {                                             \
        if ( RADEON_VERBOSE ) {                                         \
index 8289e16419a8d24566559223489037860809ec54..9836c705a952994f17cc1a9f6dedda5d9bf685aa 100644 (file)
@@ -65,7 +65,7 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
 
-       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) {
                switch (crtc) {
                case 0:
                        r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 1);
@@ -100,7 +100,7 @@ void radeon_disable_vblank(struct drm_device *dev, int crtc)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
 
-       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) {
                switch (crtc) {
                case 0:
                        r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 0);
@@ -135,7 +135,7 @@ static inline u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r
        u32 irq_mask = RADEON_SW_INT_TEST;
 
        *r500_disp_int = 0;
-       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) {
                /* vbl interrupts in a different place */
 
                if (irqs & R500_DISPLAY_INT_STATUS) {
@@ -202,7 +202,7 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
                DRM_WAKEUP(&dev_priv->swi_queue);
 
        /* VBLANK interrupt */
-       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) {
                if (r500_disp_int & R500_D1_VBLANK_INTERRUPT)
                        drm_handle_vblank(dev, 0);
                if (r500_disp_int & R500_D2_VBLANK_INTERRUPT)
@@ -265,7 +265,7 @@ u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
                return -EINVAL;
        }
 
-       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) {
                if (crtc == 0)
                        return RADEON_READ(R500_D1CRTC_FRAME_COUNT);
                else
@@ -327,7 +327,7 @@ void radeon_driver_irq_preinstall(struct drm_device * dev)
        u32 dummy;
 
        /* Disable *all* interrupts */
-       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600)
                RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
        RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
 
@@ -357,7 +357,7 @@ void radeon_driver_irq_uninstall(struct drm_device * dev)
        if (!dev_priv)
                return;
 
-       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600)
                RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
        /* Disable *all* interrupts */
        RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
index ef940a079dcbbb8488a1cc977f2c328e3e79d4a4..fa728ec6ed34c18bb66a8c78505467d9918ef7b0 100644 (file)
@@ -1556,9 +1556,15 @@ static void radeon_cp_discard_buffer(struct drm_device *dev, struct drm_master *
        buf_priv->age = ++master_priv->sarea_priv->last_dispatch;
 
        /* Emit the vertex buffer age */
-       BEGIN_RING(2);
-       RADEON_DISPATCH_AGE(buf_priv->age);
-       ADVANCE_RING();
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
+               BEGIN_RING(3);
+               R600_DISPATCH_AGE(buf_priv->age);
+               ADVANCE_RING();
+       } else {
+               BEGIN_RING(2);
+               RADEON_DISPATCH_AGE(buf_priv->age);
+               ADVANCE_RING();
+       }
 
        buf->pending = 1;
        buf->used = 0;
@@ -1980,7 +1986,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
 
        /* find a virtual surface */
        for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++)
-               if (dev_priv->virt_surfaces[i].file_priv == 0)
+               if (dev_priv->virt_surfaces[i].file_priv == NULL)
                        break;
        if (i == 2 * RADEON_MAX_SURFACES) {
                return -1;
@@ -2473,24 +2479,25 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil
 
        buf->used = indirect->end;
 
-       /* Wait for the 3D stream to idle before the indirect buffer
-        * containing 2D acceleration commands is processed.
-        */
-       BEGIN_RING(2);
-
-       RADEON_WAIT_UNTIL_3D_IDLE();
-
-       ADVANCE_RING();
-
        /* Dispatch the indirect buffer full of commands from the
         * X server.  This is insecure and is thus only available to
         * privileged clients.
         */
-       radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
-       if (indirect->discard) {
-               radeon_cp_discard_buffer(dev, file_priv->master, buf);
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               r600_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
+       else {
+               /* Wait for the 3D stream to idle before the indirect buffer
+                * containing 2D acceleration commands is processed.
+                */
+               BEGIN_RING(2);
+               RADEON_WAIT_UNTIL_3D_IDLE();
+               ADVANCE_RING();
+               radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
        }
 
+       if (indirect->discard)
+               radeon_cp_discard_buffer(dev, file_priv->master, buf);
+
        COMMIT_RING();
        return 0;
 }
@@ -3010,14 +3017,14 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
                break;
        case RADEON_PARAM_LAST_FRAME:
                dev_priv->stats.last_frame_reads++;
-               value = GET_SCRATCH(0);
+               value = GET_SCRATCH(dev_priv, 0);
                break;
        case RADEON_PARAM_LAST_DISPATCH:
-               value = GET_SCRATCH(1);
+               value = GET_SCRATCH(dev_priv, 1);
                break;
        case RADEON_PARAM_LAST_CLEAR:
                dev_priv->stats.last_clear_reads++;
-               value = GET_SCRATCH(2);
+               value = GET_SCRATCH(dev_priv, 2);
                break;
        case RADEON_PARAM_IRQ_NR:
                value = drm_dev_to_irq(dev);
@@ -3052,7 +3059,10 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
        case RADEON_PARAM_SCRATCH_OFFSET:
                if (!dev_priv->writeback_works)
                        return -EINVAL;
-               value = RADEON_SCRATCH_REG_OFFSET;
+               if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+                       value = R600_SCRATCH_REG_OFFSET;
+               else
+                       value = RADEON_SCRATCH_REG_OFFSET;
                break;
        case RADEON_PARAM_CARD_TYPE:
                if (dev_priv->flags & RADEON_IS_PCIE)
@@ -3155,6 +3165,7 @@ void radeon_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
 
 void radeon_driver_lastclose(struct drm_device *dev)
 {
+       radeon_surfaces_release(PCIGART_FILE_PRIV, dev->dev_private);
        radeon_do_release(dev);
 }
 
index d465b2f9c1cdb999a3ec168d910a0c60db5580fa..456cd040f31a285e732d0d1752bc5cc8e8a506bb 100644 (file)
@@ -599,8 +599,8 @@ int savage_driver_firstopen(struct drm_device *dev)
                            drm_mtrr_add(dev_priv->mtrr[2].base,
                                         dev_priv->mtrr[2].size, DRM_MTRR_WC);
                } else {
-                       DRM_ERROR("strange pci_resource_len %08lx\n",
-                                 drm_get_resource_len(dev, 0));
+                       DRM_ERROR("strange pci_resource_len %08llx\n",
+                                 (unsigned long long)drm_get_resource_len(dev, 0));
                }
        } else if (dev_priv->chipset != S3_SUPERSAVAGE &&
                   dev_priv->chipset != S3_SAVAGE2000) {
@@ -620,8 +620,8 @@ int savage_driver_firstopen(struct drm_device *dev)
                            drm_mtrr_add(dev_priv->mtrr[0].base,
                                         dev_priv->mtrr[0].size, DRM_MTRR_WC);
                } else {
-                       DRM_ERROR("strange pci_resource_len %08lx\n",
-                                 drm_get_resource_len(dev, 1));
+                       DRM_ERROR("strange pci_resource_len %08llx\n",
+                                 (unsigned long long)drm_get_resource_len(dev, 1));
                }
        } else {
                mmio_base = drm_get_resource_start(dev, 0);
index 0993b441fc426c1f6e39b0c0ef5ec28c30660fde..bc2f518430050adb0495933e7221d6cb59c941ee 100644 (file)
 
 #include "drm_pciids.h"
 
-static int dri_library_name(struct drm_device *dev, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "unichrome");
-}
-
 static struct pci_device_id pciidlist[] = {
        viadrv_PCI_IDS
 };
@@ -52,7 +47,6 @@ static struct drm_driver driver = {
        .irq_uninstall = via_driver_irq_uninstall,
        .irq_handler = via_driver_irq_handler,
        .dma_quiescent = via_driver_dma_quiescent,
-       .dri_library_name = dri_library_name,
        .reclaim_buffers = drm_core_reclaim_buffers,
        .reclaim_buffers_locked = NULL,
        .reclaim_buffers_idlelocked = via_reclaim_buffers_locked,
index b4eea0292c1a240cc8d7c71cfd6772baaa51537b..ce52bf2f235ed541660fe4a76d728272203ea816 100644 (file)
@@ -343,12 +343,13 @@ config SENSORS_FSCPOS
          will be called fscpos.
 
 config SENSORS_FSCHMD
-       tristate "FSC Poseidon, Scylla, Hermes, Heimdall and Heracles"
+       tristate "Fujitsu Siemens Computers sensor chips"
        depends on X86 && I2C
        help
-         If you say yes here you get support for various Fujitsu Siemens
-         Computers sensor chips, including support for the integrated
-         watchdog.
+         If you say yes here you get support for the following Fujitsu
+         Siemens Computers (FSC) sensor chips: Poseidon, Scylla, Hermes,
+         Heimdall, Heracles, Hades and Syleus including support for the
+         integrated watchdog.
 
          This is a merged driver for FSC sensor chips replacing the fscpos,
          fscscy and fscher drivers and adding support for several other FSC
@@ -570,6 +571,17 @@ config SENSORS_LM93
          This driver can also be built as a module.  If so, the module
          will be called lm93.
 
+config SENSORS_LTC4215
+       tristate "Linear Technology LTC4215"
+       depends on I2C && EXPERIMENTAL
+       default n
+       help
+         If you say yes here you get support for Linear Technology LTC4215
+         Hot Swap Controller I2C interface.
+
+         This driver can also be built as a module. If so, the module will
+         be called ltc4215.
+
 config SENSORS_LTC4245
        tristate "Linear Technology LTC4245"
        depends on I2C && EXPERIMENTAL
@@ -581,6 +593,15 @@ config SENSORS_LTC4245
          This driver can also be built as a module. If so, the module will
          be called ltc4245.
 
+config SENSORS_LM95241
+       tristate "National Semiconductor LM95241 sensor chip"
+       depends on I2C
+       help
+         If you say yes here you get support for LM95241 sensor chip.
+
+         This driver can also be built as a module.  If so, the module
+         will be called lm95241.
+
 config SENSORS_MAX1111
        tristate "Maxim MAX1111 Multichannel, Serial 8-bit ADC chip"
        depends on SPI_MASTER
@@ -635,6 +656,20 @@ config SENSORS_PC87427
          This driver can also be built as a module.  If so, the module
          will be called pc87427.
 
+config SENSORS_PCF8591
+       tristate "Philips PCF8591 ADC/DAC"
+       depends on I2C
+       default n
+       help
+         If you say yes here you get support for Philips PCF8591 4-channel
+         ADC, 1-channel DAC chips.
+
+         This driver can also be built as a module.  If so, the module
+         will be called pcf8591.
+
+         These devices are hard to detect and rarely found on mainstream
+         hardware.  If unsure, say N.
+
 config SENSORS_SIS5595
        tristate "Silicon Integrated Systems Corp. SiS5595"
        depends on PCI
@@ -827,7 +862,7 @@ config SENSORS_W83627HF
          will be called w83627hf.
 
 config SENSORS_W83627EHF
-       tristate "Winbond W83627EHF/DHG"
+       tristate "Winbond W83627EHF/EHG/DHG, W83667HG"
        select HWMON_VID
        help
          If you say yes here you get support for the hardware
@@ -838,6 +873,8 @@ config SENSORS_W83627EHF
          chip suited for specific Intel processors that use PECI such as
          the Core 2 Duo.
 
+         This driver also supports the W83667HG chip.
+
          This driver can also be built as a module.  If so, the module
          will be called w83627ehf.
 
@@ -895,6 +932,22 @@ config SENSORS_LIS3LV02D
          Say Y here if you have an applicable laptop and want to experience
          the awesome power of lis3lv02d.
 
+config SENSORS_LIS3_SPI
+       tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
+       depends on !ACPI && SPI_MASTER && INPUT
+       default n
+       help
+         This driver provides support for the LIS3LV02Dx accelerometer connected
+         via SPI. The accelerometer data is readable via
+         /sys/devices/platform/lis3lv02d.
+
+         This driver also provides an absolute input class device, allowing
+         the laptop to act as a pinball machine-esque joystick.
+
+         This driver can also be built as modules.  If so, the core module
+         will be called lis3lv02d and a specific module for the SPI transport
+         is called lis3lv02d_spi.
+
 config SENSORS_APPLESMC
        tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
        depends on INPUT && X86
index 2e80f37f39eb4e03676b21ae20ec6e0db1b6a0ed..3a6b1f06f8f4a50bd7440da3e7dbc34a0aee7567 100644 (file)
@@ -52,6 +52,7 @@ obj-$(CONFIG_SENSORS_IBMPEX)  += ibmpex.o
 obj-$(CONFIG_SENSORS_IT87)     += it87.o
 obj-$(CONFIG_SENSORS_K8TEMP)   += k8temp.o
 obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o
+obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d.o lis3lv02d_spi.o
 obj-$(CONFIG_SENSORS_LM63)     += lm63.o
 obj-$(CONFIG_SENSORS_LM70)     += lm70.o
 obj-$(CONFIG_SENSORS_LM75)     += lm75.o
@@ -64,12 +65,15 @@ obj-$(CONFIG_SENSORS_LM87)  += lm87.o
 obj-$(CONFIG_SENSORS_LM90)     += lm90.o
 obj-$(CONFIG_SENSORS_LM92)     += lm92.o
 obj-$(CONFIG_SENSORS_LM93)     += lm93.o
+obj-$(CONFIG_SENSORS_LM95241)  += lm95241.o
+obj-$(CONFIG_SENSORS_LTC4215)  += ltc4215.o
 obj-$(CONFIG_SENSORS_LTC4245)  += ltc4245.o
 obj-$(CONFIG_SENSORS_MAX1111)  += max1111.o
 obj-$(CONFIG_SENSORS_MAX1619)  += max1619.o
 obj-$(CONFIG_SENSORS_MAX6650)  += max6650.o
 obj-$(CONFIG_SENSORS_PC87360)  += pc87360.o
 obj-$(CONFIG_SENSORS_PC87427)  += pc87427.o
+obj-$(CONFIG_SENSORS_PCF8591)  += pcf8591.o
 obj-$(CONFIG_SENSORS_SIS5595)  += sis5595.o
 obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
 obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
index 7415381601c3f40fdc77481485553606712728d2..53f88f5118167a8e3ebfb392ed199fb3f3c31175 100644 (file)
@@ -81,71 +81,84 @@ struct ds1621_data {
        u8 conf;                        /* Register encoding, combined */
 };
 
-static int ds1621_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id);
-static int ds1621_detect(struct i2c_client *client, int kind,
-                        struct i2c_board_info *info);
-static void ds1621_init_client(struct i2c_client *client);
-static int ds1621_remove(struct i2c_client *client);
-static struct ds1621_data *ds1621_update_client(struct device *dev);
-
-static const struct i2c_device_id ds1621_id[] = {
-       { "ds1621", ds1621 },
-       { "ds1625", ds1621 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, ds1621_id);
-
-/* This is the driver that will be inserted */
-static struct i2c_driver ds1621_driver = {
-       .class          = I2C_CLASS_HWMON,
-       .driver = {
-               .name   = "ds1621",
-       },
-       .probe          = ds1621_probe,
-       .remove         = ds1621_remove,
-       .id_table       = ds1621_id,
-       .detect         = ds1621_detect,
-       .address_data   = &addr_data,
-};
-
-/* All registers are word-sized, except for the configuration register.
+/* Temperature registers are word-sized.
    DS1621 uses a high-byte first convention, which is exactly opposite to
    the SMBus standard. */
-static int ds1621_read_value(struct i2c_client *client, u8 reg)
+static int ds1621_read_temp(struct i2c_client *client, u8 reg)
 {
-       if (reg == DS1621_REG_CONF)
-               return i2c_smbus_read_byte_data(client, reg);
-       else
-               return swab16(i2c_smbus_read_word_data(client, reg));
+       int ret;
+
+       ret = i2c_smbus_read_word_data(client, reg);
+       if (ret < 0)
+               return ret;
+       return swab16(ret);
 }
 
-static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value)
+static int ds1621_write_temp(struct i2c_client *client, u8 reg, u16 value)
 {
-       if (reg == DS1621_REG_CONF)
-               return i2c_smbus_write_byte_data(client, reg, value);
-       else
-               return i2c_smbus_write_word_data(client, reg, swab16(value));
+       return i2c_smbus_write_word_data(client, reg, swab16(value));
 }
 
 static void ds1621_init_client(struct i2c_client *client)
 {
-       int reg = ds1621_read_value(client, DS1621_REG_CONF);
+       u8 conf, new_conf;
+
+       new_conf = conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
        /* switch to continuous conversion mode */
-       reg &= ~ DS1621_REG_CONFIG_1SHOT;
+       new_conf &= ~DS1621_REG_CONFIG_1SHOT;
 
        /* setup output polarity */
        if (polarity == 0)
-               reg &= ~DS1621_REG_CONFIG_POLARITY;
+               new_conf &= ~DS1621_REG_CONFIG_POLARITY;
        else if (polarity == 1)
-               reg |= DS1621_REG_CONFIG_POLARITY;
+               new_conf |= DS1621_REG_CONFIG_POLARITY;
        
-       ds1621_write_value(client, DS1621_REG_CONF, reg);
+       if (conf != new_conf)
+               i2c_smbus_write_byte_data(client, DS1621_REG_CONF, new_conf);
        
        /* start conversion */
        i2c_smbus_write_byte(client, DS1621_COM_START);
 }
 
+static struct ds1621_data *ds1621_update_client(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ds1621_data *data = i2c_get_clientdata(client);
+       u8 new_conf;
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+           || !data->valid) {
+               int i;
+
+               dev_dbg(&client->dev, "Starting ds1621 update\n");
+
+               data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
+
+               for (i = 0; i < ARRAY_SIZE(data->temp); i++)
+                       data->temp[i] = ds1621_read_temp(client,
+                                                        DS1621_REG_TEMP[i]);
+
+               /* reset alarms if necessary */
+               new_conf = data->conf;
+               if (data->temp[0] > data->temp[1])      /* input > min */
+                       new_conf &= ~DS1621_ALARM_TEMP_LOW;
+               if (data->temp[0] < data->temp[2])      /* input < max */
+                       new_conf &= ~DS1621_ALARM_TEMP_HIGH;
+               if (data->conf != new_conf)
+                       i2c_smbus_write_byte_data(client, DS1621_REG_CONF,
+                                                 new_conf);
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
 static ssize_t show_temp(struct device *dev, struct device_attribute *da,
                         char *buf)
 {
@@ -160,13 +173,13 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
        struct i2c_client *client = to_i2c_client(dev);
-       struct ds1621_data *data = ds1621_update_client(dev);
+       struct ds1621_data *data = i2c_get_clientdata(client);
        u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10));
 
        mutex_lock(&data->update_lock);
        data->temp[attr->index] = val;
-       ds1621_write_value(client, DS1621_REG_TEMP[attr->index],
-                          data->temp[attr->index]);
+       ds1621_write_temp(client, DS1621_REG_TEMP[attr->index],
+                         data->temp[attr->index]);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -228,13 +241,14 @@ static int ds1621_detect(struct i2c_client *client, int kind,
                /* The NVB bit should be low if no EEPROM write has been 
                   requested during the latest 10ms, which is highly 
                   improbable in our case. */
-               conf = ds1621_read_value(client, DS1621_REG_CONF);
-               if (conf & DS1621_REG_CONFIG_NVB)
+               conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
+               if (conf < 0 || conf & DS1621_REG_CONFIG_NVB)
                        return -ENODEV;
                /* The 7 lowest bits of a temperature should always be 0. */
                for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) {
-                       temp = ds1621_read_value(client, DS1621_REG_TEMP[i]);
-                       if (temp & 0x007f)
+                       temp = i2c_smbus_read_word_data(client,
+                                                       DS1621_REG_TEMP[i]);
+                       if (temp < 0 || (temp & 0x7f00))
                                return -ENODEV;
                }
        }
@@ -294,45 +308,25 @@ static int ds1621_remove(struct i2c_client *client)
        return 0;
 }
 
+static const struct i2c_device_id ds1621_id[] = {
+       { "ds1621", ds1621 },
+       { "ds1625", ds1621 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ds1621_id);
 
-static struct ds1621_data *ds1621_update_client(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct ds1621_data *data = i2c_get_clientdata(client);
-       u8 new_conf;
-
-       mutex_lock(&data->update_lock);
-
-       if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
-           || !data->valid) {
-               int i;
-
-               dev_dbg(&client->dev, "Starting ds1621 update\n");
-
-               data->conf = ds1621_read_value(client, DS1621_REG_CONF);
-
-               for (i = 0; i < ARRAY_SIZE(data->temp); i++)
-                       data->temp[i] = ds1621_read_value(client,
-                                                         DS1621_REG_TEMP[i]);
-
-               /* reset alarms if necessary */
-               new_conf = data->conf;
-               if (data->temp[0] > data->temp[1])      /* input > min */
-                       new_conf &= ~DS1621_ALARM_TEMP_LOW;
-               if (data->temp[0] < data->temp[2])      /* input < max */
-                       new_conf &= ~DS1621_ALARM_TEMP_HIGH;
-               if (data->conf != new_conf)
-                       ds1621_write_value(client, DS1621_REG_CONF,
-                                          new_conf);
-
-               data->last_updated = jiffies;
-               data->valid = 1;
-       }
-
-       mutex_unlock(&data->update_lock);
-
-       return data;
-}
+/* This is the driver that will be inserted */
+static struct i2c_driver ds1621_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "ds1621",
+       },
+       .probe          = ds1621_probe,
+       .remove         = ds1621_remove,
+       .id_table       = ds1621_id,
+       .detect         = ds1621_detect,
+       .address_data   = &addr_data,
+};
 
 static int __init ds1621_init(void)
 {
index d07f4ef750923ca728556ed353ca6eb8ae052873..ea955edde87e5127fc4c7f57d7d0c0b51ed3b1e4 100644 (file)
@@ -1,6 +1,6 @@
 /* fschmd.c
  *
- * Copyright (C) 2007,2008 Hans de Goede <hdegoede@redhat.com>
+ * Copyright (C) 2007 - 2009 Hans de Goede <hdegoede@redhat.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
@@ -19,7 +19,7 @@
 
 /*
  *  Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes,
- *  Scylla, Heracles and Heimdall chips
+ *  Scylla, Heracles, Heimdall, Hades and Syleus chips
  *
  *  Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6
  *  (candidate) fschmd drivers:
@@ -56,7 +56,7 @@ static int nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
+I2C_CLIENT_INSMOD_7(fscpos, fscher, fscscy, fschrc, fschmd, fschds, fscsyl);
 
 /*
  * The FSCHMD registers and other defines
@@ -75,9 +75,12 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
 #define FSCHMD_CONTROL_ALERT_LED       0x01
 
 /* watchdog */
-#define FSCHMD_REG_WDOG_PRESET         0x28
-#define FSCHMD_REG_WDOG_STATE          0x23
-#define FSCHMD_REG_WDOG_CONTROL                0x21
+static const u8 FSCHMD_REG_WDOG_CONTROL[7] =
+       { 0x21, 0x21, 0x21, 0x21, 0x21, 0x28, 0x28 };
+static const u8 FSCHMD_REG_WDOG_STATE[7] =
+       { 0x23, 0x23, 0x23, 0x23, 0x23, 0x29, 0x29 };
+static const u8 FSCHMD_REG_WDOG_PRESET[7] =
+       { 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x2a };
 
 #define FSCHMD_WDOG_CONTROL_TRIGGER    0x10
 #define FSCHMD_WDOG_CONTROL_STARTED    0x10 /* the same as trigger */
@@ -87,70 +90,95 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
 #define FSCHMD_WDOG_STATE_CARDRESET    0x02
 
 /* voltages, weird order is to keep the same order as the old drivers */
-static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 };
+static const u8 FSCHMD_REG_VOLT[7][6] = {
+       { 0x45, 0x42, 0x48 },                           /* pos */
+       { 0x45, 0x42, 0x48 },                           /* her */
+       { 0x45, 0x42, 0x48 },                           /* scy */
+       { 0x45, 0x42, 0x48 },                           /* hrc */
+       { 0x45, 0x42, 0x48 },                           /* hmd */
+       { 0x21, 0x20, 0x22 },                           /* hds */
+       { 0x21, 0x20, 0x22, 0x23, 0x24, 0x25 },         /* syl */
+};
+
+static const int FSCHMD_NO_VOLT_SENSORS[7] = { 3, 3, 3, 3, 3, 3, 6 };
 
 /* minimum pwm at which the fan is driven (pwm can by increased depending on
    the temp. Notice that for the scy some fans share there minimum speed.
    Also notice that with the scy the sensor order is different than with the
    other chips, this order was in the 2.4 driver and kept for consistency. */
-static const u8 FSCHMD_REG_FAN_MIN[5][6] = {
+static const u8 FSCHMD_REG_FAN_MIN[7][7] = {
        { 0x55, 0x65 },                                 /* pos */
        { 0x55, 0x65, 0xb5 },                           /* her */
        { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 },         /* scy */
        { 0x55, 0x65, 0xa5, 0xb5 },                     /* hrc */
        { 0x55, 0x65, 0xa5, 0xb5, 0xc5 },               /* hmd */
+       { 0x55, 0x65, 0xa5, 0xb5, 0xc5 },               /* hds */
+       { 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb4 },   /* syl */
 };
 
 /* actual fan speed */
-static const u8 FSCHMD_REG_FAN_ACT[5][6] = {
+static const u8 FSCHMD_REG_FAN_ACT[7][7] = {
        { 0x0e, 0x6b, 0xab },                           /* pos */
        { 0x0e, 0x6b, 0xbb },                           /* her */
        { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb },         /* scy */
        { 0x0e, 0x6b, 0xab, 0xbb },                     /* hrc */
        { 0x5b, 0x6b, 0xab, 0xbb, 0xcb },               /* hmd */
+       { 0x5b, 0x6b, 0xab, 0xbb, 0xcb },               /* hds */
+       { 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7 },   /* syl */
 };
 
 /* fan status registers */
-static const u8 FSCHMD_REG_FAN_STATE[5][6] = {
+static const u8 FSCHMD_REG_FAN_STATE[7][7] = {
        { 0x0d, 0x62, 0xa2 },                           /* pos */
        { 0x0d, 0x62, 0xb2 },                           /* her */
        { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 },         /* scy */
        { 0x0d, 0x62, 0xa2, 0xb2 },                     /* hrc */
        { 0x52, 0x62, 0xa2, 0xb2, 0xc2 },               /* hmd */
+       { 0x52, 0x62, 0xa2, 0xb2, 0xc2 },               /* hds */
+       { 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0 },   /* syl */
 };
 
 /* fan ripple / divider registers */
-static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = {
+static const u8 FSCHMD_REG_FAN_RIPPLE[7][7] = {
        { 0x0f, 0x6f, 0xaf },                           /* pos */
        { 0x0f, 0x6f, 0xbf },                           /* her */
        { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf },         /* scy */
        { 0x0f, 0x6f, 0xaf, 0xbf },                     /* hrc */
        { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf },               /* hmd */
+       { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf },               /* hds */
+       { 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6 },   /* syl */
 };
 
-static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 };
+static const int FSCHMD_NO_FAN_SENSORS[7] = { 3, 3, 6, 4, 5, 5, 7 };
 
 /* Fan status register bitmasks */
 #define FSCHMD_FAN_ALARM       0x04 /* called fault by FSC! */
-#define FSCHMD_FAN_NOT_PRESENT 0x08 /* not documented */
+#define FSCHMD_FAN_NOT_PRESENT 0x08
+#define FSCHMD_FAN_DISABLED    0x80
 
 
 /* actual temperature registers */
-static const u8 FSCHMD_REG_TEMP_ACT[5][5] = {
+static const u8 FSCHMD_REG_TEMP_ACT[7][11] = {
        { 0x64, 0x32, 0x35 },                           /* pos */
        { 0x64, 0x32, 0x35 },                           /* her */
        { 0x64, 0xD0, 0x32, 0x35 },                     /* scy */
        { 0x64, 0x32, 0x35 },                           /* hrc */
        { 0x70, 0x80, 0x90, 0xd0, 0xe0 },               /* hmd */
+       { 0x70, 0x80, 0x90, 0xd0, 0xe0 },               /* hds */
+       { 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8,           /* syl */
+         0xb8, 0xc8, 0xd8, 0xe8, 0xf8 },
 };
 
 /* temperature state registers */
-static const u8 FSCHMD_REG_TEMP_STATE[5][5] = {
+static const u8 FSCHMD_REG_TEMP_STATE[7][11] = {
        { 0x71, 0x81, 0x91 },                           /* pos */
        { 0x71, 0x81, 0x91 },                           /* her */
        { 0x71, 0xd1, 0x81, 0x91 },                     /* scy */
        { 0x71, 0x81, 0x91 },                           /* hrc */
        { 0x71, 0x81, 0x91, 0xd1, 0xe1 },               /* hmd */
+       { 0x71, 0x81, 0x91, 0xd1, 0xe1 },               /* hds */
+       { 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9,           /* syl */
+         0xb9, 0xc9, 0xd9, 0xe9, 0xf9 },
 };
 
 /* temperature high limit registers, FSC does not document these. Proven to be
@@ -158,24 +186,31 @@ static const u8 FSCHMD_REG_TEMP_STATE[5][5] = {
    in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers
    at these addresses, but doesn't want to confirm they are the same as with
    the fscher?? */
-static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = {
+static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = {
        { 0, 0, 0 },                                    /* pos */
        { 0x76, 0x86, 0x96 },                           /* her */
        { 0x76, 0xd6, 0x86, 0x96 },                     /* scy */
        { 0x76, 0x86, 0x96 },                           /* hrc */
        { 0x76, 0x86, 0x96, 0xd6, 0xe6 },               /* hmd */
+       { 0x76, 0x86, 0x96, 0xd6, 0xe6 },               /* hds */
+       { 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa,           /* syl */
+         0xba, 0xca, 0xda, 0xea, 0xfa },
 };
 
 /* These were found through experimenting with an fscher, currently they are
    not used, but we keep them around for future reference.
+   On the fscsyl AUTOP1 lives at 0x#c (so 0x5c for fan1, 0x6c for fan2, etc),
+   AUTOP2 lives at 0x#e, and 0x#1 is a bitmask defining which temps influence
+   the fan speed.
 static const u8 FSCHER_REG_TEMP_AUTOP1[] =     { 0x73, 0x83, 0x93 };
 static const u8 FSCHER_REG_TEMP_AUTOP2[] =     { 0x75, 0x85, 0x95 }; */
 
-static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 };
+static const int FSCHMD_NO_TEMP_SENSORS[7] = { 3, 3, 4, 3, 5, 5, 11 };
 
 /* temp status register bitmasks */
 #define FSCHMD_TEMP_WORKING    0x01
 #define FSCHMD_TEMP_ALERT      0x02
+#define FSCHMD_TEMP_DISABLED   0x80
 /* there only really is an alarm if the sensor is working and alert == 1 */
 #define FSCHMD_TEMP_ALARM_MASK \
        (FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT)
@@ -201,6 +236,8 @@ static const struct i2c_device_id fschmd_id[] = {
        { "fscscy", fscscy },
        { "fschrc", fschrc },
        { "fschmd", fschmd },
+       { "fschds", fschds },
+       { "fscsyl", fscsyl },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, fschmd_id);
@@ -242,14 +279,14 @@ struct fschmd_data {
        u8 watchdog_control;    /* watchdog control register */
        u8 watchdog_state;      /* watchdog status register */
        u8 watchdog_preset;     /* watchdog counter preset on trigger val */
-       u8 volt[3];             /* 12, 5, battery voltage */
-       u8 temp_act[5];         /* temperature */
-       u8 temp_status[5];      /* status of sensor */
-       u8 temp_max[5];         /* high temp limit, notice: undocumented! */
-       u8 fan_act[6];          /* fans revolutions per second */
-       u8 fan_status[6];       /* fan status */
-       u8 fan_min[6];          /* fan min value for rps */
-       u8 fan_ripple[6];       /* divider for rps */
+       u8 volt[6];             /* voltage */
+       u8 temp_act[11];        /* temperature */
+       u8 temp_status[11];     /* status of sensor */
+       u8 temp_max[11];        /* high temp limit, notice: undocumented! */
+       u8 fan_act[7];          /* fans revolutions per second */
+       u8 fan_status[7];       /* fan status */
+       u8 fan_min[7];          /* fan min value for rps */
+       u8 fan_ripple[7];       /* divider for rps */
 };
 
 /* Global variables to hold information read from special DMI tables, which are
@@ -257,8 +294,8 @@ struct fschmd_data {
    protect these with a lock as they are only modified from our attach function
    which always gets called with the i2c-core lock held and never accessed
    before the attach function is done with them. */
-static int dmi_mult[3] = { 490, 200, 100 };
-static int dmi_offset[3] = { 0, 0, 0 };
+static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 };
+static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 };
 static int dmi_vref = -1;
 
 /* Somewhat ugly :( global data pointer list with all fschmd devices, so that
@@ -450,10 +487,11 @@ static ssize_t show_pwm_auto_point1_pwm(struct device *dev,
        struct device_attribute *devattr, char *buf)
 {
        int index = to_sensor_dev_attr(devattr)->index;
-       int val = fschmd_update_device(dev)->fan_min[index];
+       struct fschmd_data *data = fschmd_update_device(dev);
+       int val = data->fan_min[index];
 
-       /* 0 = allow turning off, 1-255 = 50-100% */
-       if (val)
+       /* 0 = allow turning off (except on the syl), 1-255 = 50-100% */
+       if (val || data->kind == fscsyl - 1)
                val = val / 2 + 128;
 
        return sprintf(buf, "%d\n", val);
@@ -466,8 +504,8 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
        struct fschmd_data *data = dev_get_drvdata(dev);
        unsigned long v = simple_strtoul(buf, NULL, 10);
 
-       /* register: 0 = allow turning off, 1-255 = 50-100% */
-       if (v) {
+       /* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */
+       if (v || data->kind == fscsyl - 1) {
                v = SENSORS_LIMIT(v, 128, 255);
                v = (v - 128) * 2 + 1;
        }
@@ -522,11 +560,15 @@ static ssize_t store_alert_led(struct device *dev,
        return count;
 }
 
+static DEVICE_ATTR(alert_led, 0644, show_alert_led, store_alert_led);
+
 static struct sensor_device_attribute fschmd_attr[] = {
        SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0),
        SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1),
        SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2),
-       SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0),
+       SENSOR_ATTR(in3_input, 0444, show_in_value, NULL, 3),
+       SENSOR_ATTR(in4_input, 0444, show_in_value, NULL, 4),
+       SENSOR_ATTR(in5_input, 0444, show_in_value, NULL, 5),
 };
 
 static struct sensor_device_attribute fschmd_temp_attr[] = {
@@ -550,6 +592,30 @@ static struct sensor_device_attribute fschmd_temp_attr[] = {
        SENSOR_ATTR(temp5_max,   0644, show_temp_max, store_temp_max, 4),
        SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4),
        SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4),
+       SENSOR_ATTR(temp6_input, 0444, show_temp_value, NULL, 5),
+       SENSOR_ATTR(temp6_max,   0644, show_temp_max, store_temp_max, 5),
+       SENSOR_ATTR(temp6_fault, 0444, show_temp_fault, NULL, 5),
+       SENSOR_ATTR(temp6_alarm, 0444, show_temp_alarm, NULL, 5),
+       SENSOR_ATTR(temp7_input, 0444, show_temp_value, NULL, 6),
+       SENSOR_ATTR(temp7_max,   0644, show_temp_max, store_temp_max, 6),
+       SENSOR_ATTR(temp7_fault, 0444, show_temp_fault, NULL, 6),
+       SENSOR_ATTR(temp7_alarm, 0444, show_temp_alarm, NULL, 6),
+       SENSOR_ATTR(temp8_input, 0444, show_temp_value, NULL, 7),
+       SENSOR_ATTR(temp8_max,   0644, show_temp_max, store_temp_max, 7),
+       SENSOR_ATTR(temp8_fault, 0444, show_temp_fault, NULL, 7),
+       SENSOR_ATTR(temp8_alarm, 0444, show_temp_alarm, NULL, 7),
+       SENSOR_ATTR(temp9_input, 0444, show_temp_value, NULL, 8),
+       SENSOR_ATTR(temp9_max,   0644, show_temp_max, store_temp_max, 8),
+       SENSOR_ATTR(temp9_fault, 0444, show_temp_fault, NULL, 8),
+       SENSOR_ATTR(temp9_alarm, 0444, show_temp_alarm, NULL, 8),
+       SENSOR_ATTR(temp10_input, 0444, show_temp_value, NULL, 9),
+       SENSOR_ATTR(temp10_max,   0644, show_temp_max, store_temp_max, 9),
+       SENSOR_ATTR(temp10_fault, 0444, show_temp_fault, NULL, 9),
+       SENSOR_ATTR(temp10_alarm, 0444, show_temp_alarm, NULL, 9),
+       SENSOR_ATTR(temp11_input, 0444, show_temp_value, NULL, 10),
+       SENSOR_ATTR(temp11_max,   0644, show_temp_max, store_temp_max, 10),
+       SENSOR_ATTR(temp11_fault, 0444, show_temp_fault, NULL, 10),
+       SENSOR_ATTR(temp11_alarm, 0444, show_temp_alarm, NULL, 10),
 };
 
 static struct sensor_device_attribute fschmd_fan_attr[] = {
@@ -589,6 +655,12 @@ static struct sensor_device_attribute fschmd_fan_attr[] = {
        SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5),
        SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
                store_pwm_auto_point1_pwm, 5),
+       SENSOR_ATTR(fan7_input, 0444, show_fan_value, NULL, 6),
+       SENSOR_ATTR(fan7_div,   0644, show_fan_div, store_fan_div, 6),
+       SENSOR_ATTR(fan7_alarm, 0444, show_fan_alarm, NULL, 6),
+       SENSOR_ATTR(fan7_fault, 0444, show_fan_fault, NULL, 6),
+       SENSOR_ATTR(pwm7_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+               store_pwm_auto_point1_pwm, 6),
 };
 
 
@@ -624,10 +696,11 @@ static int watchdog_set_timeout(struct fschmd_data *data, int timeout)
        data->watchdog_preset = DIV_ROUND_UP(timeout, resolution);
 
        /* Write new timeout value */
-       i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_PRESET,
-               data->watchdog_preset);
+       i2c_smbus_write_byte_data(data->client,
+               FSCHMD_REG_WDOG_PRESET[data->kind], data->watchdog_preset);
        /* Write new control register, do not trigger! */
-       i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL,
+       i2c_smbus_write_byte_data(data->client,
+               FSCHMD_REG_WDOG_CONTROL[data->kind],
                data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER);
 
        ret = data->watchdog_preset * resolution;
@@ -662,8 +735,9 @@ static int watchdog_trigger(struct fschmd_data *data)
        }
 
        data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER;
-       i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL,
-                                       data->watchdog_control);
+       i2c_smbus_write_byte_data(data->client,
+                                 FSCHMD_REG_WDOG_CONTROL[data->kind],
+                                 data->watchdog_control);
 leave:
        mutex_unlock(&data->watchdog_lock);
        return ret;
@@ -682,7 +756,8 @@ static int watchdog_stop(struct fschmd_data *data)
        data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED;
        /* Don't store the stop flag in our watchdog control register copy, as
           its a write only bit (read always returns 0) */
-       i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL,
+       i2c_smbus_write_byte_data(data->client,
+               FSCHMD_REG_WDOG_CONTROL[data->kind],
                data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP);
 leave:
        mutex_unlock(&data->watchdog_lock);
@@ -856,7 +931,7 @@ static struct file_operations watchdog_fops = {
 
 /* DMI decode routine to read voltage scaling factors from special DMI tables,
    which are available on FSC machines with an fscher or later chip. */
-static void fschmd_dmi_decode(const struct dmi_header *header)
+static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy)
 {
        int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0;
 
@@ -912,6 +987,15 @@ static void fschmd_dmi_decode(const struct dmi_header *header)
                        dmi_mult[i] = mult[i] * 10;
                        dmi_offset[i] = offset[i] * 10;
                }
+               /* According to the docs there should be separate dmi entries
+                  for the mult's and offsets of in3-5 of the syl, but on
+                  my test machine these are not present */
+               dmi_mult[3] = dmi_mult[2];
+               dmi_mult[4] = dmi_mult[1];
+               dmi_mult[5] = dmi_mult[2];
+               dmi_offset[3] = dmi_offset[2];
+               dmi_offset[4] = dmi_offset[1];
+               dmi_offset[5] = dmi_offset[2];
                dmi_vref = vref;
        }
 }
@@ -920,8 +1004,6 @@ static int fschmd_detect(struct i2c_client *client, int kind,
                         struct i2c_board_info *info)
 {
        struct i2c_adapter *adapter = client->adapter;
-       const char * const client_names[5] = { "fscpos", "fscher", "fscscy",
-                                               "fschrc", "fschmd" };
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
@@ -948,11 +1030,15 @@ static int fschmd_detect(struct i2c_client *client, int kind,
                        kind = fschrc;
                else if (!strcmp(id, "HMD"))
                        kind = fschmd;
+               else if (!strcmp(id, "HDS"))
+                       kind = fschds;
+               else if (!strcmp(id, "SYL"))
+                       kind = fscsyl;
                else
                        return -ENODEV;
        }
 
-       strlcpy(info->type, client_names[kind - 1], I2C_NAME_SIZE);
+       strlcpy(info->type, fschmd_id[kind - 1].name, I2C_NAME_SIZE);
 
        return 0;
 }
@@ -961,8 +1047,8 @@ static int fschmd_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        struct fschmd_data *data;
-       const char * const names[5] = { "Poseidon", "Hermes", "Scylla",
-                                       "Heracles", "Heimdall" };
+       const char * const names[7] = { "Poseidon", "Hermes", "Scylla",
+                               "Heracles", "Heimdall", "Hades", "Syleus" };
        const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
        int i, err;
        enum chips kind = id->driver_data;
@@ -991,7 +1077,7 @@ static int fschmd_probe(struct i2c_client *client,
 
        /* Read the special DMI table for fscher and newer chips */
        if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) {
-               dmi_walk(fschmd_dmi_decode);
+               dmi_walk(fschmd_dmi_decode, NULL);
                if (dmi_vref == -1) {
                        dev_warn(&client->dev,
                                "Couldn't get voltage scaling factors from "
@@ -1000,21 +1086,25 @@ static int fschmd_probe(struct i2c_client *client,
                }
        }
 
+       /* i2c kind goes from 1-6, we want from 0-5 to address arrays */
+       data->kind = kind - 1;
+
        /* Read in some never changing registers */
        data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
        data->global_control = i2c_smbus_read_byte_data(client,
                                        FSCHMD_REG_CONTROL);
        data->watchdog_control = i2c_smbus_read_byte_data(client,
-                                       FSCHMD_REG_WDOG_CONTROL);
+                                       FSCHMD_REG_WDOG_CONTROL[data->kind]);
        data->watchdog_state = i2c_smbus_read_byte_data(client,
-                                       FSCHMD_REG_WDOG_STATE);
+                                       FSCHMD_REG_WDOG_STATE[data->kind]);
        data->watchdog_preset = i2c_smbus_read_byte_data(client,
-                                       FSCHMD_REG_WDOG_PRESET);
+                                       FSCHMD_REG_WDOG_PRESET[data->kind]);
 
-       /* i2c kind goes from 1-5, we want from 0-4 to address arrays */
-       data->kind = kind - 1;
+       err = device_create_file(&client->dev, &dev_attr_alert_led);
+       if (err)
+               goto exit_detach;
 
-       for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) {
+       for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) {
                err = device_create_file(&client->dev,
                                        &fschmd_attr[i].dev_attr);
                if (err)
@@ -1027,6 +1117,16 @@ static int fschmd_probe(struct i2c_client *client,
                                show_temp_max)
                        continue;
 
+               if (kind == fscsyl) {
+                       if (i % 4 == 0)
+                               data->temp_status[i / 4] =
+                                       i2c_smbus_read_byte_data(client,
+                                               FSCHMD_REG_TEMP_STATE
+                                               [data->kind][i / 4]);
+                       if (data->temp_status[i / 4] & FSCHMD_TEMP_DISABLED)
+                               continue;
+               }
+
                err = device_create_file(&client->dev,
                                        &fschmd_temp_attr[i].dev_attr);
                if (err)
@@ -1040,6 +1140,16 @@ static int fschmd_probe(struct i2c_client *client,
                                        "pwm3_auto_point1_pwm"))
                        continue;
 
+               if (kind == fscsyl) {
+                       if (i % 5 == 0)
+                               data->fan_status[i / 5] =
+                                       i2c_smbus_read_byte_data(client,
+                                               FSCHMD_REG_FAN_STATE
+                                               [data->kind][i / 5]);
+                       if (data->fan_status[i / 5] & FSCHMD_FAN_DISABLED)
+                               continue;
+               }
+
                err = device_create_file(&client->dev,
                                        &fschmd_fan_attr[i].dev_attr);
                if (err)
@@ -1126,7 +1236,8 @@ static int fschmd_remove(struct i2c_client *client)
        if (data->hwmon_dev)
                hwmon_device_unregister(data->hwmon_dev);
 
-       for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++)
+       device_remove_file(&client->dev, &dev_attr_alert_led);
+       for (i = 0; i < (FSCHMD_NO_VOLT_SENSORS[data->kind]); i++)
                device_remove_file(&client->dev, &fschmd_attr[i].dev_attr);
        for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++)
                device_remove_file(&client->dev,
@@ -1171,7 +1282,7 @@ static struct fschmd_data *fschmd_update_device(struct device *dev)
                                        data->temp_act[i] < data->temp_max[i])
                                i2c_smbus_write_byte_data(client,
                                        FSCHMD_REG_TEMP_STATE[data->kind][i],
-                                       FSCHMD_TEMP_ALERT);
+                                       data->temp_status[i]);
                }
 
                for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) {
@@ -1193,12 +1304,12 @@ static struct fschmd_data *fschmd_update_device(struct device *dev)
                                        data->fan_act[i])
                                i2c_smbus_write_byte_data(client,
                                        FSCHMD_REG_FAN_STATE[data->kind][i],
-                                       FSCHMD_FAN_ALARM);
+                                       data->fan_status[i]);
                }
 
-               for (i = 0; i < 3; i++)
+               for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++)
                        data->volt[i] = i2c_smbus_read_byte_data(client,
-                                               FSCHMD_REG_VOLT[i]);
+                                              FSCHMD_REG_VOLT[data->kind][i]);
 
                data->last_updated = jiffies;
                data->valid = 1;
@@ -1220,8 +1331,8 @@ static void __exit fschmd_exit(void)
 }
 
 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
-MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and "
-                       "Heimdall driver");
+MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall, Hades "
+                       "and Syleus driver");
 MODULE_LICENSE("GPL");
 
 module_init(fschmd_init);
index a4d92d246d52620e1efb09288df69fdcbf352303..d3612a1f198135d1a719428fc5f77e417674e671 100644 (file)
 #define HDAPS_INPUT_FUZZ       4       /* input event threshold */
 #define HDAPS_INPUT_FLAT       4
 
+#define HDAPS_X_AXIS           (1 << 0)
+#define HDAPS_Y_AXIS           (1 << 1)
+#define HDAPS_BOTH_AXES                (HDAPS_X_AXIS | HDAPS_Y_AXIS)
+
 static struct platform_device *pdev;
 static struct input_polled_dev *hdaps_idev;
 static unsigned int hdaps_invert;
@@ -182,11 +186,11 @@ static int __hdaps_read_pair(unsigned int port1, unsigned int port2,
        km_activity = inb(HDAPS_PORT_KMACT);
        __device_complete();
 
-       /* if hdaps_invert is set, negate the two values */
-       if (hdaps_invert) {
+       /* hdaps_invert is a bitvector to negate the axes */
+       if (hdaps_invert & HDAPS_X_AXIS)
                *x = -*x;
+       if (hdaps_invert & HDAPS_Y_AXIS)
                *y = -*y;
-       }
 
        return 0;
 }
@@ -436,7 +440,8 @@ static ssize_t hdaps_invert_store(struct device *dev,
 {
        int invert;
 
-       if (sscanf(buf, "%d", &invert) != 1 || (invert != 1 && invert != 0))
+       if (sscanf(buf, "%d", &invert) != 1 ||
+           invert < 0 || invert > HDAPS_BOTH_AXES)
                return -EINVAL;
 
        hdaps_invert = invert;
@@ -483,56 +488,52 @@ static int __init hdaps_dmi_match(const struct dmi_system_id *id)
 /* hdaps_dmi_match_invert - found an inverted match. */
 static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id)
 {
-       hdaps_invert = 1;
-       printk(KERN_INFO "hdaps: inverting axis readings.\n");
+       hdaps_invert = (unsigned long)id->driver_data;
+       printk(KERN_INFO "hdaps: inverting axis (%u) readings.\n",
+              hdaps_invert);
        return hdaps_dmi_match(id);
 }
 
-#define HDAPS_DMI_MATCH_NORMAL(vendor, model) {                \
-       .ident = vendor " " model,                      \
-       .callback = hdaps_dmi_match,                    \
-       .matches = {                                    \
-               DMI_MATCH(DMI_BOARD_VENDOR, vendor),    \
-               DMI_MATCH(DMI_PRODUCT_VERSION, model)   \
-       }                                               \
-}
-
-#define HDAPS_DMI_MATCH_INVERT(vendor, model) {                \
+#define HDAPS_DMI_MATCH_INVERT(vendor, model, axes) {  \
        .ident = vendor " " model,                      \
        .callback = hdaps_dmi_match_invert,             \
+       .driver_data = (void *)axes,                    \
        .matches = {                                    \
                DMI_MATCH(DMI_BOARD_VENDOR, vendor),    \
                DMI_MATCH(DMI_PRODUCT_VERSION, model)   \
        }                                               \
 }
 
+#define HDAPS_DMI_MATCH_NORMAL(vendor, model)          \
+       HDAPS_DMI_MATCH_INVERT(vendor, model, 0)
+
 /* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match
    "ThinkPad T42p", so the order of the entries matters.
    If your ThinkPad is not recognized, please update to latest
    BIOS. This is especially the case for some R52 ThinkPads. */
 static struct dmi_system_id __initdata hdaps_whitelist[] = {
-       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p"),
+       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p", HDAPS_BOTH_AXES),
        HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R50"),
        HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"),
        HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61"),
-       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p"),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p", HDAPS_BOTH_AXES),
        HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T41"),
-       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p"),
+       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p", HDAPS_BOTH_AXES),
        HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T42"),
        HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T43"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61"),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61", HDAPS_BOTH_AXES),
        HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"),
-       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X41"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61"),
+       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad X41", HDAPS_Y_AXIS),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61", HDAPS_BOTH_AXES),
        HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p"),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p", HDAPS_BOTH_AXES),
        { .ident = NULL }
 };
 
@@ -627,8 +628,9 @@ static void __exit hdaps_exit(void)
 module_init(hdaps_init);
 module_exit(hdaps_exit);
 
-module_param_named(invert, hdaps_invert, bool, 0);
-MODULE_PARM_DESC(invert, "invert data along each axis");
+module_param_named(invert, hdaps_invert, int, 0);
+MODULE_PARM_DESC(invert, "invert data along each axis. 1 invert x-axis, "
+                "2 invert y-axis, 3 invert both axes.");
 
 MODULE_AUTHOR("Robert Love");
 MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver");
index 29c83b5b96974bb88cbeb67d896ba46ee71469f2..55d3dc565be6cbd4209762aa40815c7c37a02a35 100644 (file)
@@ -85,25 +85,31 @@ MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids);
 
 /**
  * lis3lv02d_acpi_init - ACPI _INI method: initialize the device.
- * @handle: the handle of the device
+ * @lis3: pointer to the device struct
  *
- * Returns AE_OK on success.
+ * Returns 0 on success.
  */
-acpi_status lis3lv02d_acpi_init(acpi_handle handle)
+int lis3lv02d_acpi_init(struct lis3lv02d *lis3)
 {
-       return acpi_evaluate_object(handle, METHOD_NAME__INI, NULL, NULL);
+       struct acpi_device *dev = lis3->bus_priv;
+       if (acpi_evaluate_object(dev->handle, METHOD_NAME__INI,
+                                NULL, NULL) != AE_OK)
+               return -EINVAL;
+
+       return 0;
 }
 
 /**
  * lis3lv02d_acpi_read - ACPI ALRD method: read a register
- * @handle: the handle of the device
+ * @lis3: pointer to the device struct
  * @reg:    the register to read
  * @ret:    result of the operation
  *
- * Returns AE_OK on success.
+ * Returns 0 on success.
  */
-acpi_status lis3lv02d_acpi_read(acpi_handle handle, int reg, u8 *ret)
+int lis3lv02d_acpi_read(struct lis3lv02d *lis3, int reg, u8 *ret)
 {
+       struct acpi_device *dev = lis3->bus_priv;
        union acpi_object arg0 = { ACPI_TYPE_INTEGER };
        struct acpi_object_list args = { 1, &arg0 };
        unsigned long long lret;
@@ -111,21 +117,22 @@ acpi_status lis3lv02d_acpi_read(acpi_handle handle, int reg, u8 *ret)
 
        arg0.integer.value = reg;
 
-       status = acpi_evaluate_integer(handle, "ALRD", &args, &lret);
+       status = acpi_evaluate_integer(dev->handle, "ALRD", &args, &lret);
        *ret = lret;
-       return status;
+       return (status != AE_OK) ? -EINVAL : 0;
 }
 
 /**
  * lis3lv02d_acpi_write - ACPI ALWR method: write to a register
- * @handle: the handle of the device
+ * @lis3: pointer to the device struct
  * @reg:    the register to write to
  * @val:    the value to write
  *
- * Returns AE_OK on success.
+ * Returns 0 on success.
  */
-acpi_status lis3lv02d_acpi_write(acpi_handle handle, int reg, u8 val)
+int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val)
 {
+       struct acpi_device *dev = lis3->bus_priv;
        unsigned long long ret; /* Not used when writting */
        union acpi_object in_obj[2];
        struct acpi_object_list args = { 2, in_obj };
@@ -135,12 +142,15 @@ acpi_status lis3lv02d_acpi_write(acpi_handle handle, int reg, u8 val)
        in_obj[1].type          = ACPI_TYPE_INTEGER;
        in_obj[1].integer.value = val;
 
-       return acpi_evaluate_integer(handle, "ALWR", &args, &ret);
+       if (acpi_evaluate_integer(dev->handle, "ALWR", &args, &ret) != AE_OK)
+               return -EINVAL;
+
+       return 0;
 }
 
 static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
 {
-       adev.ac = *((struct axis_conversion *)dmi->driver_data);
+       lis3_dev.ac = *((struct axis_conversion *)dmi->driver_data);
        printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident);
 
        return 1;
@@ -187,6 +197,7 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
        AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted),
        AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted),
        AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left),
+       AXIS_DMI_MATCH("HP2140", "HP 2140", xy_swap_inverted),
        AXIS_DMI_MATCH("NC653x", "HP Compaq 653", xy_rotated_left_usd),
        AXIS_DMI_MATCH("NC673x", "HP Compaq 673", xy_rotated_left_usd),
        AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right),
@@ -201,6 +212,8 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
                        PRODUCT_NAME, "HP Pavilion dv5",
                        BOARD_NAME, "3600",
                        y_inverted),
+       AXIS_DMI_MATCH("DV7", "HP Pavilion dv7", x_inverted),
+       AXIS_DMI_MATCH("HP8710", "HP Compaq 8710", y_inverted),
        { NULL, }
 /* Laptop models without axis info (yet):
  * "NC6910" "HP Compaq 6910"
@@ -214,7 +227,7 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
 
 static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness value)
 {
-       acpi_handle handle = adev.device->handle;
+       struct acpi_device *dev = lis3_dev.bus_priv;
        unsigned long long ret; /* Not used when writing */
        union acpi_object in_obj[1];
        struct acpi_object_list args = { 1, in_obj };
@@ -222,7 +235,7 @@ static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness
        in_obj[0].type          = ACPI_TYPE_INTEGER;
        in_obj[0].integer.value = !!value;
 
-       acpi_evaluate_integer(handle, "ALED", &args, &ret);
+       acpi_evaluate_integer(dev->handle, "ALED", &args, &ret);
 }
 
 static struct delayed_led_classdev hpled_led = {
@@ -254,28 +267,11 @@ static void lis3lv02d_enum_resources(struct acpi_device *device)
        acpi_status status;
 
        status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
-                                       lis3lv02d_get_resource, &adev.irq);
+                                       lis3lv02d_get_resource, &lis3_dev.irq);
        if (ACPI_FAILURE(status))
                printk(KERN_DEBUG DRIVER_NAME ": Error getting resources\n");
 }
 
-static s16 lis3lv02d_read_16(acpi_handle handle, int reg)
-{
-       u8 lo, hi;
-
-       adev.read(handle, reg - 1, &lo);
-       adev.read(handle, reg, &hi);
-       /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */
-       return (s16)((hi << 8) | lo);
-}
-
-static s16 lis3lv02d_read_8(acpi_handle handle, int reg)
-{
-       s8 lo;
-       adev.read(handle, reg, &lo);
-       return lo;
-}
-
 static int lis3lv02d_add(struct acpi_device *device)
 {
        int ret;
@@ -283,51 +279,35 @@ static int lis3lv02d_add(struct acpi_device *device)
        if (!device)
                return -EINVAL;
 
-       adev.device = device;
-       adev.init = lis3lv02d_acpi_init;
-       adev.read = lis3lv02d_acpi_read;
-       adev.write = lis3lv02d_acpi_write;
+       lis3_dev.bus_priv = device;
+       lis3_dev.init = lis3lv02d_acpi_init;
+       lis3_dev.read = lis3lv02d_acpi_read;
+       lis3_dev.write = lis3lv02d_acpi_write;
        strcpy(acpi_device_name(device), DRIVER_NAME);
        strcpy(acpi_device_class(device), ACPI_MDPS_CLASS);
-       device->driver_data = &adev;
-
-       lis3lv02d_acpi_read(device->handle, WHO_AM_I, &adev.whoami);
-       switch (adev.whoami) {
-       case LIS_DOUBLE_ID:
-               printk(KERN_INFO DRIVER_NAME ": 2-byte sensor found\n");
-               adev.read_data = lis3lv02d_read_16;
-               adev.mdps_max_val = 2048;
-               break;
-       case LIS_SINGLE_ID:
-               printk(KERN_INFO DRIVER_NAME ": 1-byte sensor found\n");
-               adev.read_data = lis3lv02d_read_8;
-               adev.mdps_max_val = 128;
-               break;
-       default:
-               printk(KERN_ERR DRIVER_NAME
-                       ": unknown sensor type 0x%X\n", adev.whoami);
-               return -EINVAL;
-       }
+       device->driver_data = &lis3_dev;
+
+       /* obtain IRQ number of our device from ACPI */
+       lis3lv02d_enum_resources(device);
 
        /* If possible use a "standard" axes order */
        if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
                printk(KERN_INFO DRIVER_NAME ": laptop model unknown, "
                                 "using default axes configuration\n");
-               adev.ac = lis3lv02d_axis_normal;
+               lis3_dev.ac = lis3lv02d_axis_normal;
        }
 
-       INIT_WORK(&hpled_led.work, delayed_set_status_worker);
-       ret = led_classdev_register(NULL, &hpled_led.led_classdev);
+       /* call the core layer do its init */
+       ret = lis3lv02d_init_device(&lis3_dev);
        if (ret)
                return ret;
 
-       /* obtain IRQ number of our device from ACPI */
-       lis3lv02d_enum_resources(adev.device);
-
-       ret = lis3lv02d_init_device(&adev);
+       INIT_WORK(&hpled_led.work, delayed_set_status_worker);
+       ret = led_classdev_register(NULL, &hpled_led.led_classdev);
        if (ret) {
+               lis3lv02d_joystick_disable();
+               lis3lv02d_poweroff(&lis3_dev);
                flush_work(&hpled_led.work);
-               led_classdev_unregister(&hpled_led.led_classdev);
                return ret;
        }
 
@@ -340,7 +320,7 @@ static int lis3lv02d_remove(struct acpi_device *device, int type)
                return -EINVAL;
 
        lis3lv02d_joystick_disable();
-       lis3lv02d_poweroff(device->handle);
+       lis3lv02d_poweroff(&lis3_dev);
 
        flush_work(&hpled_led.work);
        led_classdev_unregister(&hpled_led.led_classdev);
@@ -353,19 +333,19 @@ static int lis3lv02d_remove(struct acpi_device *device, int type)
 static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state)
 {
        /* make sure the device is off when we suspend */
-       lis3lv02d_poweroff(device->handle);
+       lis3lv02d_poweroff(&lis3_dev);
        return 0;
 }
 
 static int lis3lv02d_resume(struct acpi_device *device)
 {
        /* put back the device in the right state (ACPI might turn it on) */
-       mutex_lock(&adev.lock);
-       if (adev.usage > 0)
-               lis3lv02d_poweron(device->handle);
+       mutex_lock(&lis3_dev.lock);
+       if (lis3_dev.usage > 0)
+               lis3lv02d_poweron(&lis3_dev);
        else
-               lis3lv02d_poweroff(device->handle);
-       mutex_unlock(&adev.lock);
+               lis3lv02d_poweroff(&lis3_dev);
+       mutex_unlock(&lis3_dev.lock);
        return 0;
 }
 #else
index 8bb2158f0453c01f3c089ffaa88d8eea2927fd9d..778eb77959837eed9c1172cfe4524d0273434b54 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/freezer.h>
 #include <linux/uaccess.h>
 #include <linux/miscdevice.h>
-#include <acpi/acpi_drivers.h>
 #include <asm/atomic.h>
 #include "lis3lv02d.h"
 
  * joystick.
  */
 
-struct acpi_lis3lv02d adev = {
-       .misc_wait   = __WAIT_QUEUE_HEAD_INITIALIZER(adev.misc_wait),
+struct lis3lv02d lis3_dev = {
+       .misc_wait   = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait),
 };
 
-EXPORT_SYMBOL_GPL(adev);
+EXPORT_SYMBOL_GPL(lis3_dev);
 
-static int lis3lv02d_add_fs(struct acpi_device *device);
+static s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg)
+{
+       s8 lo;
+       if (lis3->read(lis3, reg, &lo) < 0)
+               return 0;
+
+       return lo;
+}
+
+static s16 lis3lv02d_read_16(struct lis3lv02d *lis3, int reg)
+{
+       u8 lo, hi;
+
+       lis3->read(lis3, reg - 1, &lo);
+       lis3->read(lis3, reg, &hi);
+       /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */
+       return (s16)((hi << 8) | lo);
+}
 
 /**
  * lis3lv02d_get_axis - For the given axis, give the value converted
@@ -78,36 +94,36 @@ static inline int lis3lv02d_get_axis(s8 axis, int hw_values[3])
 
 /**
  * lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer
- * @handle: the handle to the device
- * @x:      where to store the X axis value
- * @y:      where to store the Y axis value
- * @z:      where to store the Z axis value
+ * @lis3: pointer to the device struct
+ * @x:    where to store the X axis value
+ * @y:    where to store the Y axis value
+ * @z:    where to store the Z axis value
  *
  * Note that 40Hz input device can eat up about 10% CPU at 800MHZ
  */
-static void lis3lv02d_get_xyz(acpi_handle handle, int *x, int *y, int *z)
+static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
 {
        int position[3];
 
-       position[0] = adev.read_data(handle, OUTX);
-       position[1] = adev.read_data(handle, OUTY);
-       position[2] = adev.read_data(handle, OUTZ);
+       position[0] = lis3_dev.read_data(lis3, OUTX);
+       position[1] = lis3_dev.read_data(lis3, OUTY);
+       position[2] = lis3_dev.read_data(lis3, OUTZ);
 
-       *x = lis3lv02d_get_axis(adev.ac.x, position);
-       *y = lis3lv02d_get_axis(adev.ac.y, position);
-       *z = lis3lv02d_get_axis(adev.ac.z, position);
+       *x = lis3lv02d_get_axis(lis3_dev.ac.x, position);
+       *y = lis3lv02d_get_axis(lis3_dev.ac.y, position);
+       *z = lis3lv02d_get_axis(lis3_dev.ac.z, position);
 }
 
-void lis3lv02d_poweroff(acpi_handle handle)
+void lis3lv02d_poweroff(struct lis3lv02d *lis3)
 {
-       adev.is_on = 0;
+       lis3_dev.is_on = 0;
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_poweroff);
 
-void lis3lv02d_poweron(acpi_handle handle)
+void lis3lv02d_poweron(struct lis3lv02d *lis3)
 {
-       adev.is_on = 1;
-       adev.init(handle);
+       lis3_dev.is_on = 1;
+       lis3_dev.init(lis3);
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
 
@@ -116,13 +132,13 @@ EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
  * device will always be on until a call to lis3lv02d_decrease_use(). Not to be
  * used from interrupt context.
  */
-static void lis3lv02d_increase_use(struct acpi_lis3lv02d *dev)
+static void lis3lv02d_increase_use(struct lis3lv02d *dev)
 {
        mutex_lock(&dev->lock);
        dev->usage++;
        if (dev->usage == 1) {
                if (!dev->is_on)
-                       lis3lv02d_poweron(dev->device->handle);
+                       lis3lv02d_poweron(dev);
        }
        mutex_unlock(&dev->lock);
 }
@@ -131,12 +147,12 @@ static void lis3lv02d_increase_use(struct acpi_lis3lv02d *dev)
  * To be called whenever a usage of the device is stopped.
  * It will make sure to turn off the device when there is not usage.
  */
-static void lis3lv02d_decrease_use(struct acpi_lis3lv02d *dev)
+static void lis3lv02d_decrease_use(struct lis3lv02d *dev)
 {
        mutex_lock(&dev->lock);
        dev->usage--;
        if (dev->usage == 0)
-               lis3lv02d_poweroff(dev->device->handle);
+               lis3lv02d_poweroff(dev);
        mutex_unlock(&dev->lock);
 }
 
@@ -147,10 +163,10 @@ static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
         * the lid is closed. This leads to interrupts as soon as a little move
         * is done.
         */
-       atomic_inc(&adev.count);
+       atomic_inc(&lis3_dev.count);
 
-       wake_up_interruptible(&adev.misc_wait);
-       kill_fasync(&adev.async_queue, SIGIO, POLL_IN);
+       wake_up_interruptible(&lis3_dev.misc_wait);
+       kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN);
        return IRQ_HANDLED;
 }
 
@@ -158,10 +174,10 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
 {
        int ret;
 
-       if (test_and_set_bit(0, &adev.misc_opened))
+       if (test_and_set_bit(0, &lis3_dev.misc_opened))
                return -EBUSY; /* already open */
 
-       atomic_set(&adev.count, 0);
+       atomic_set(&lis3_dev.count, 0);
 
        /*
         * The sensor can generate interrupts for free-fall and direction
@@ -174,25 +190,25 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
         * io-apic is not configurable (and generates a warning) but I keep it
         * in case of support for other hardware.
         */
-       ret = request_irq(adev.irq, lis302dl_interrupt, IRQF_TRIGGER_RISING,
-                         DRIVER_NAME, &adev);
+       ret = request_irq(lis3_dev.irq, lis302dl_interrupt, IRQF_TRIGGER_RISING,
+                         DRIVER_NAME, &lis3_dev);
 
        if (ret) {
-               clear_bit(0, &adev.misc_opened);
-               printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", adev.irq);
+               clear_bit(0, &lis3_dev.misc_opened);
+               printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", lis3_dev.irq);
                return -EBUSY;
        }
-       lis3lv02d_increase_use(&adev);
-       printk("lis3: registered interrupt %d\n", adev.irq);
+       lis3lv02d_increase_use(&lis3_dev);
+       printk("lis3: registered interrupt %d\n", lis3_dev.irq);
        return 0;
 }
 
 static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
 {
-       fasync_helper(-1, file, 0, &adev.async_queue);
-       lis3lv02d_decrease_use(&adev);
-       free_irq(adev.irq, &adev);
-       clear_bit(0, &adev.misc_opened); /* release the device */
+       fasync_helper(-1, file, 0, &lis3_dev.async_queue);
+       lis3lv02d_decrease_use(&lis3_dev);
+       free_irq(lis3_dev.irq, &lis3_dev);
+       clear_bit(0, &lis3_dev.misc_opened); /* release the device */
        return 0;
 }
 
@@ -207,10 +223,10 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
        if (count < 1)
                return -EINVAL;
 
-       add_wait_queue(&adev.misc_wait, &wait);
+       add_wait_queue(&lis3_dev.misc_wait, &wait);
        while (true) {
                set_current_state(TASK_INTERRUPTIBLE);
-               data = atomic_xchg(&adev.count, 0);
+               data = atomic_xchg(&lis3_dev.count, 0);
                if (data)
                        break;
 
@@ -240,22 +256,22 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
 
 out:
        __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&adev.misc_wait, &wait);
+       remove_wait_queue(&lis3_dev.misc_wait, &wait);
 
        return retval;
 }
 
 static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait)
 {
-       poll_wait(file, &adev.misc_wait, wait);
-       if (atomic_read(&adev.count))
+       poll_wait(file, &lis3_dev.misc_wait, wait);
+       if (atomic_read(&lis3_dev.count))
                return POLLIN | POLLRDNORM;
        return 0;
 }
 
 static int lis3lv02d_misc_fasync(int fd, struct file *file, int on)
 {
-       return fasync_helper(fd, file, on, &adev.async_queue);
+       return fasync_helper(fd, file, on, &lis3_dev.async_queue);
 }
 
 static const struct file_operations lis3lv02d_misc_fops = {
@@ -283,12 +299,12 @@ static int lis3lv02d_joystick_kthread(void *data)
        int x, y, z;
 
        while (!kthread_should_stop()) {
-               lis3lv02d_get_xyz(adev.device->handle, &x, &y, &z);
-               input_report_abs(adev.idev, ABS_X, x - adev.xcalib);
-               input_report_abs(adev.idev, ABS_Y, y - adev.ycalib);
-               input_report_abs(adev.idev, ABS_Z, z - adev.zcalib);
+               lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
+               input_report_abs(lis3_dev.idev, ABS_X, x - lis3_dev.xcalib);
+               input_report_abs(lis3_dev.idev, ABS_Y, y - lis3_dev.ycalib);
+               input_report_abs(lis3_dev.idev, ABS_Z, z - lis3_dev.zcalib);
 
-               input_sync(adev.idev);
+               input_sync(lis3_dev.idev);
 
                try_to_freeze();
                msleep_interruptible(MDPS_POLL_INTERVAL);
@@ -299,11 +315,11 @@ static int lis3lv02d_joystick_kthread(void *data)
 
 static int lis3lv02d_joystick_open(struct input_dev *input)
 {
-       lis3lv02d_increase_use(&adev);
-       adev.kthread = kthread_run(lis3lv02d_joystick_kthread, NULL, "klis3lv02d");
-       if (IS_ERR(adev.kthread)) {
-               lis3lv02d_decrease_use(&adev);
-               return PTR_ERR(adev.kthread);
+       lis3lv02d_increase_use(&lis3_dev);
+       lis3_dev.kthread = kthread_run(lis3lv02d_joystick_kthread, NULL, "klis3lv02d");
+       if (IS_ERR(lis3_dev.kthread)) {
+               lis3lv02d_decrease_use(&lis3_dev);
+               return PTR_ERR(lis3_dev.kthread);
        }
 
        return 0;
@@ -311,45 +327,46 @@ static int lis3lv02d_joystick_open(struct input_dev *input)
 
 static void lis3lv02d_joystick_close(struct input_dev *input)
 {
-       kthread_stop(adev.kthread);
-       lis3lv02d_decrease_use(&adev);
+       kthread_stop(lis3_dev.kthread);
+       lis3lv02d_decrease_use(&lis3_dev);
 }
 
 static inline void lis3lv02d_calibrate_joystick(void)
 {
-       lis3lv02d_get_xyz(adev.device->handle, &adev.xcalib, &adev.ycalib, &adev.zcalib);
+       lis3lv02d_get_xyz(&lis3_dev,
+               &lis3_dev.xcalib, &lis3_dev.ycalib, &lis3_dev.zcalib);
 }
 
 int lis3lv02d_joystick_enable(void)
 {
        int err;
 
-       if (adev.idev)
+       if (lis3_dev.idev)
                return -EINVAL;
 
-       adev.idev = input_allocate_device();
-       if (!adev.idev)
+       lis3_dev.idev = input_allocate_device();
+       if (!lis3_dev.idev)
                return -ENOMEM;
 
        lis3lv02d_calibrate_joystick();
 
-       adev.idev->name       = "ST LIS3LV02DL Accelerometer";
-       adev.idev->phys       = DRIVER_NAME "/input0";
-       adev.idev->id.bustype = BUS_HOST;
-       adev.idev->id.vendor  = 0;
-       adev.idev->dev.parent = &adev.pdev->dev;
-       adev.idev->open       = lis3lv02d_joystick_open;
-       adev.idev->close      = lis3lv02d_joystick_close;
+       lis3_dev.idev->name       = "ST LIS3LV02DL Accelerometer";
+       lis3_dev.idev->phys       = DRIVER_NAME "/input0";
+       lis3_dev.idev->id.bustype = BUS_HOST;
+       lis3_dev.idev->id.vendor  = 0;
+       lis3_dev.idev->dev.parent = &lis3_dev.pdev->dev;
+       lis3_dev.idev->open       = lis3lv02d_joystick_open;
+       lis3_dev.idev->close      = lis3lv02d_joystick_close;
 
-       set_bit(EV_ABS, adev.idev->evbit);
-       input_set_abs_params(adev.idev, ABS_X, -adev.mdps_max_val, adev.mdps_max_val, 3, 3);
-       input_set_abs_params(adev.idev, ABS_Y, -adev.mdps_max_val, adev.mdps_max_val, 3, 3);
-       input_set_abs_params(adev.idev, ABS_Z, -adev.mdps_max_val, adev.mdps_max_val, 3, 3);
+       set_bit(EV_ABS, lis3_dev.idev->evbit);
+       input_set_abs_params(lis3_dev.idev, ABS_X, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
+       input_set_abs_params(lis3_dev.idev, ABS_Y, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
+       input_set_abs_params(lis3_dev.idev, ABS_Z, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
 
-       err = input_register_device(adev.idev);
+       err = input_register_device(lis3_dev.idev);
        if (err) {
-               input_free_device(adev.idev);
-               adev.idev = NULL;
+               input_free_device(lis3_dev.idev);
+               lis3_dev.idev = NULL;
        }
 
        return err;
@@ -358,71 +375,40 @@ EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable);
 
 void lis3lv02d_joystick_disable(void)
 {
-       if (!adev.idev)
+       if (!lis3_dev.idev)
                return;
 
        misc_deregister(&lis3lv02d_misc_device);
-       input_unregister_device(adev.idev);
-       adev.idev = NULL;
+       input_unregister_device(lis3_dev.idev);
+       lis3_dev.idev = NULL;
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
 
-/*
- * Initialise the accelerometer and the various subsystems.
- * Should be rather independant of the bus system.
- */
-int lis3lv02d_init_device(struct acpi_lis3lv02d *dev)
-{
-       mutex_init(&dev->lock);
-       lis3lv02d_add_fs(dev->device);
-       lis3lv02d_increase_use(dev);
-
-       if (lis3lv02d_joystick_enable())
-               printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n");
-
-       printk("lis3_init_device: irq %d\n", dev->irq);
-
-       /* if we did not get an IRQ from ACPI - we have nothing more to do */
-       if (!dev->irq) {
-               printk(KERN_ERR DRIVER_NAME
-                       ": No IRQ in ACPI. Disabling /dev/freefall\n");
-               goto out;
-       }
-
-       printk("lis3: registering device\n");
-       if (misc_register(&lis3lv02d_misc_device))
-               printk(KERN_ERR DRIVER_NAME ": misc_register failed\n");
-out:
-       lis3lv02d_decrease_use(dev);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(lis3lv02d_init_device);
-
 /* Sysfs stuff */
 static ssize_t lis3lv02d_position_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
        int x, y, z;
 
-       lis3lv02d_increase_use(&adev);
-       lis3lv02d_get_xyz(adev.device->handle, &x, &y, &z);
-       lis3lv02d_decrease_use(&adev);
+       lis3lv02d_increase_use(&lis3_dev);
+       lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
+       lis3lv02d_decrease_use(&lis3_dev);
        return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
 }
 
 static ssize_t lis3lv02d_calibrate_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       return sprintf(buf, "(%d,%d,%d)\n", adev.xcalib, adev.ycalib, adev.zcalib);
+       return sprintf(buf, "(%d,%d,%d)\n", lis3_dev.xcalib, lis3_dev.ycalib, lis3_dev.zcalib);
 }
 
 static ssize_t lis3lv02d_calibrate_store(struct device *dev,
                                struct device_attribute *attr,
                                const char *buf, size_t count)
 {
-       lis3lv02d_increase_use(&adev);
+       lis3lv02d_increase_use(&lis3_dev);
        lis3lv02d_calibrate_joystick();
-       lis3lv02d_decrease_use(&adev);
+       lis3lv02d_decrease_use(&lis3_dev);
        return count;
 }
 
@@ -434,9 +420,9 @@ static ssize_t lis3lv02d_rate_show(struct device *dev,
        u8 ctrl;
        int val;
 
-       lis3lv02d_increase_use(&adev);
-       adev.read(adev.device->handle, CTRL_REG1, &ctrl);
-       lis3lv02d_decrease_use(&adev);
+       lis3lv02d_increase_use(&lis3_dev);
+       lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
+       lis3lv02d_decrease_use(&lis3_dev);
        val = (ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4;
        return sprintf(buf, "%d\n", lis3lv02dl_df_val[val]);
 }
@@ -458,23 +444,73 @@ static struct attribute_group lis3lv02d_attribute_group = {
 };
 
 
-static int lis3lv02d_add_fs(struct acpi_device *device)
+static int lis3lv02d_add_fs(struct lis3lv02d *lis3)
 {
-       adev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
-       if (IS_ERR(adev.pdev))
-               return PTR_ERR(adev.pdev);
+       lis3_dev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
+       if (IS_ERR(lis3_dev.pdev))
+               return PTR_ERR(lis3_dev.pdev);
 
-       return sysfs_create_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group);
+       return sysfs_create_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group);
 }
 
 int lis3lv02d_remove_fs(void)
 {
-       sysfs_remove_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group);
-       platform_device_unregister(adev.pdev);
+       sysfs_remove_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group);
+       platform_device_unregister(lis3_dev.pdev);
        return 0;
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
 
+/*
+ * Initialise the accelerometer and the various subsystems.
+ * Should be rather independant of the bus system.
+ */
+int lis3lv02d_init_device(struct lis3lv02d *dev)
+{
+       dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I);
+
+       switch (dev->whoami) {
+       case LIS_DOUBLE_ID:
+               printk(KERN_INFO DRIVER_NAME ": 2-byte sensor found\n");
+               dev->read_data = lis3lv02d_read_16;
+               dev->mdps_max_val = 2048;
+               break;
+       case LIS_SINGLE_ID:
+               printk(KERN_INFO DRIVER_NAME ": 1-byte sensor found\n");
+               dev->read_data = lis3lv02d_read_8;
+               dev->mdps_max_val = 128;
+               break;
+       default:
+               printk(KERN_ERR DRIVER_NAME
+                       ": unknown sensor type 0x%X\n", lis3_dev.whoami);
+               return -EINVAL;
+       }
+
+       mutex_init(&dev->lock);
+       lis3lv02d_add_fs(dev);
+       lis3lv02d_increase_use(dev);
+
+       if (lis3lv02d_joystick_enable())
+               printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n");
+
+       printk("lis3_init_device: irq %d\n", dev->irq);
+
+       /* bail if we did not get an IRQ from the bus layer */
+       if (!dev->irq) {
+               printk(KERN_ERR DRIVER_NAME
+                       ": No IRQ. Disabling /dev/freefall\n");
+               goto out;
+       }
+
+       printk("lis3: registering device\n");
+       if (misc_register(&lis3lv02d_misc_device))
+               printk(KERN_ERR DRIVER_NAME ": misc_register failed\n");
+out:
+       lis3lv02d_decrease_use(dev);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(lis3lv02d_init_device);
+
 MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver");
 MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek");
 MODULE_LICENSE("GPL");
index 75972bf372ff474a2fd1a43cdaf85db9ddddebd4..745ec96806d485a0f93f33932e2a588e6a8ab546 100644 (file)
@@ -159,14 +159,14 @@ struct axis_conversion {
        s8      z;
 };
 
-struct acpi_lis3lv02d {
-       struct acpi_device      *device;   /* The ACPI device */
-       acpi_status (*init) (acpi_handle handle);
-       acpi_status (*write) (acpi_handle handle, int reg, u8 val);
-       acpi_status (*read) (acpi_handle handle, int reg, u8 *ret);
+struct lis3lv02d {
+       void                    *bus_priv; /* used by the bus layer only */
+       int (*init) (struct lis3lv02d *lis3);
+       int (*write) (struct lis3lv02d *lis3, int reg, u8 val);
+       int (*read) (struct lis3lv02d *lis3, int reg, u8 *ret);
 
        u8                      whoami;    /* 3Ah: 2-byte registries, 3Bh: 1-byte registries */
-       s16 (*read_data) (acpi_handle handle, int reg);
+       s16 (*read_data) (struct lis3lv02d *lis3, int reg);
        int                     mdps_max_val;
 
        struct input_dev        *idev;     /* input device */
@@ -187,11 +187,11 @@ struct acpi_lis3lv02d {
        unsigned long           misc_opened; /* bit0: whether the device is open */
 };
 
-int lis3lv02d_init_device(struct acpi_lis3lv02d *dev);
+int lis3lv02d_init_device(struct lis3lv02d *lis3);
 int lis3lv02d_joystick_enable(void);
 void lis3lv02d_joystick_disable(void);
-void lis3lv02d_poweroff(acpi_handle handle);
-void lis3lv02d_poweron(acpi_handle handle);
+void lis3lv02d_poweroff(struct lis3lv02d *lis3);
+void lis3lv02d_poweron(struct lis3lv02d *lis3);
 int lis3lv02d_remove_fs(void);
 
-extern struct acpi_lis3lv02d adev;
+extern struct lis3lv02d lis3_dev;
diff --git a/drivers/hwmon/lis3lv02d_spi.c b/drivers/hwmon/lis3lv02d_spi.c
new file mode 100644 (file)
index 0000000..07ae74b
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * lis3lv02d_spi - SPI glue layer for lis3lv02d
+ *
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  publishhed by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/spi/spi.h>
+
+#include "lis3lv02d.h"
+
+#define DRV_NAME       "lis3lv02d_spi"
+#define LIS3_SPI_READ  0x80
+
+static int lis3_spi_read(struct lis3lv02d *lis3, int reg, u8 *v)
+{
+       struct spi_device *spi = lis3->bus_priv;
+       int ret = spi_w8r8(spi, reg | LIS3_SPI_READ);
+       if (ret < 0)
+               return -EINVAL;
+
+       *v = (u8) ret;
+       return 0;
+}
+
+static int lis3_spi_write(struct lis3lv02d *lis3, int reg, u8 val)
+{
+       u8 tmp[2] = { reg, val };
+       struct spi_device *spi = lis3->bus_priv;
+       return spi_write(spi, tmp, sizeof(tmp));
+}
+
+static int lis3_spi_init(struct lis3lv02d *lis3)
+{
+       u8 reg;
+       int ret;
+
+       /* power up the device */
+       ret = lis3->read(lis3, CTRL_REG1, &reg);
+       if (ret < 0)
+               return ret;
+
+       reg |= CTRL1_PD0;
+       return lis3->write(lis3, CTRL_REG1, reg);
+}
+
+static struct axis_conversion lis3lv02d_axis_normal = { 1, 2, 3 };
+
+static int __devinit lis302dl_spi_probe(struct spi_device *spi)
+{
+       int ret;
+
+       spi->bits_per_word = 8;
+       spi->mode = SPI_MODE_0;
+       ret = spi_setup(spi);
+       if (ret < 0)
+               return ret;
+
+       lis3_dev.bus_priv = spi;
+       lis3_dev.init = lis3_spi_init;
+       lis3_dev.read = lis3_spi_read;
+       lis3_dev.write = lis3_spi_write;
+       lis3_dev.irq = spi->irq;
+       lis3_dev.ac = lis3lv02d_axis_normal;
+       spi_set_drvdata(spi, &lis3_dev);
+
+       ret = lis3lv02d_init_device(&lis3_dev);
+       return ret;
+}
+
+static int __devexit lis302dl_spi_remove(struct spi_device *spi)
+{
+       struct lis3lv02d *lis3 = spi_get_drvdata(spi);
+       lis3lv02d_joystick_disable();
+       lis3lv02d_poweroff(lis3);
+       return 0;
+}
+
+static struct spi_driver lis302dl_spi_driver = {
+       .driver  = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe  = lis302dl_spi_probe,
+       .remove = __devexit_p(lis302dl_spi_remove),
+};
+
+static int __init lis302dl_init(void)
+{
+       return spi_register_driver(&lis302dl_spi_driver);
+}
+
+static void __exit lis302dl_exit(void)
+{
+       spi_unregister_driver(&lis302dl_spi_driver);
+}
+
+module_init(lis302dl_init);
+module_exit(lis302dl_exit);
+
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
+MODULE_DESCRIPTION("lis3lv02d SPI glue layer");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c
new file mode 100644 (file)
index 0000000..091d95f
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ * lm95241.c - Part of lm_sensors, Linux kernel modules for hardware
+ *             monitoring
+ * Copyright (C) 2008 Davide Rizzo <elpa-rizzo@gmail.com>
+ *
+ * Based on the max1619 driver. The LM95241 is a sensor chip made by National
+ *   Semiconductors.
+ * It reports up to three temperatures (its own plus up to
+ * two external ones). Complete datasheet can be
+ * obtained from National's website at:
+ *   http://www.national.com/ds.cgi/LM/LM95241.pdf
+ *
+ * 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/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+static const unsigned short normal_i2c[] = {
+       0x19, 0x2a, 0x2b, I2C_CLIENT_END};
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(lm95241);
+
+/* LM95241 registers */
+#define LM95241_REG_R_MAN_ID           0xFE
+#define LM95241_REG_R_CHIP_ID          0xFF
+#define LM95241_REG_R_STATUS           0x02
+#define LM95241_REG_RW_CONFIG          0x03
+#define LM95241_REG_RW_REM_FILTER      0x06
+#define LM95241_REG_RW_TRUTHERM                0x07
+#define LM95241_REG_W_ONE_SHOT         0x0F
+#define LM95241_REG_R_LOCAL_TEMPH      0x10
+#define LM95241_REG_R_REMOTE1_TEMPH    0x11
+#define LM95241_REG_R_REMOTE2_TEMPH    0x12
+#define LM95241_REG_R_LOCAL_TEMPL      0x20
+#define LM95241_REG_R_REMOTE1_TEMPL    0x21
+#define LM95241_REG_R_REMOTE2_TEMPL    0x22
+#define LM95241_REG_RW_REMOTE_MODEL    0x30
+
+/* LM95241 specific bitfields */
+#define CFG_STOP 0x40
+#define CFG_CR0076 0x00
+#define CFG_CR0182 0x10
+#define CFG_CR1000 0x20
+#define CFG_CR2700 0x30
+#define R1MS_SHIFT 0
+#define R2MS_SHIFT 2
+#define R1MS_MASK (0x01 << (R1MS_SHIFT))
+#define R2MS_MASK (0x01 << (R2MS_SHIFT))
+#define R1DF_SHIFT 1
+#define R2DF_SHIFT 2
+#define R1DF_MASK (0x01 << (R1DF_SHIFT))
+#define R2DF_MASK (0x01 << (R2DF_SHIFT))
+#define R1FE_MASK 0x01
+#define R2FE_MASK 0x05
+#define TT1_SHIFT 0
+#define TT2_SHIFT 4
+#define TT_OFF 0
+#define TT_ON 1
+#define TT_MASK 7
+#define MANUFACTURER_ID 0x01
+#define DEFAULT_REVISION 0xA4
+
+/* Conversions and various macros */
+#define TEMP_FROM_REG(val_h, val_l) (((val_h) & 0x80 ? (val_h) - 0x100 : \
+    (val_h)) * 1000 + (val_l) * 1000 / 256)
+
+/* Functions declaration */
+static int lm95241_attach_adapter(struct i2c_adapter *adapter);
+static int lm95241_detect(struct i2c_adapter *adapter, int address,
+                         int kind);
+static void lm95241_init_client(struct i2c_client *client);
+static int lm95241_detach_client(struct i2c_client *client);
+static struct lm95241_data *lm95241_update_device(struct device *dev);
+
+/* Driver data (common to all clients) */
+static struct i2c_driver lm95241_driver = {
+       .driver = {
+               .name   = "lm95241",
+       },
+       .attach_adapter = lm95241_attach_adapter,
+       .detach_client  = lm95241_detach_client,
+};
+
+/* Client data (each client gets its own) */
+struct lm95241_data {
+       struct i2c_client client;
+       struct device *hwmon_dev;
+       struct mutex update_lock;
+       unsigned long last_updated, rate; /* in jiffies */
+       char valid; /* zero until following fields are valid */
+       /* registers values */
+       u8 local_h, local_l; /* local */
+       u8 remote1_h, remote1_l; /* remote1 */
+       u8 remote2_h, remote2_l; /* remote2 */
+       u8 config, model, trutherm;
+};
+
+/* Sysfs stuff */
+#define show_temp(value) \
+static ssize_t show_##value(struct device *dev, \
+    struct device_attribute *attr, char *buf) \
+{ \
+       struct lm95241_data *data = lm95241_update_device(dev); \
+       snprintf(buf, PAGE_SIZE - 1, "%d\n", \
+               TEMP_FROM_REG(data->value##_h, data->value##_l)); \
+       return strlen(buf); \
+}
+show_temp(local);
+show_temp(remote1);
+show_temp(remote2);
+
+static ssize_t show_rate(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct lm95241_data *data = lm95241_update_device(dev);
+
+       snprintf(buf, PAGE_SIZE - 1, "%lu\n", 1000 * data->rate / HZ);
+       return strlen(buf);
+}
+
+static ssize_t set_rate(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95241_data *data = i2c_get_clientdata(client);
+
+       strict_strtol(buf, 10, &data->rate);
+       data->rate = data->rate * HZ / 1000;
+
+       return count;
+}
+
+#define show_type(flag) \
+static ssize_t show_type##flag(struct device *dev, \
+                                  struct device_attribute *attr, char *buf) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct lm95241_data *data = i2c_get_clientdata(client); \
+\
+       snprintf(buf, PAGE_SIZE - 1, \
+               data->model & R##flag##MS_MASK ? "1\n" : "2\n"); \
+       return strlen(buf); \
+}
+show_type(1);
+show_type(2);
+
+#define show_min(flag) \
+static ssize_t show_min##flag(struct device *dev, \
+    struct device_attribute *attr, char *buf) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct lm95241_data *data = i2c_get_clientdata(client); \
+\
+       snprintf(buf, PAGE_SIZE - 1, \
+               data->config & R##flag##DF_MASK ?       \
+               "-127000\n" : "0\n"); \
+       return strlen(buf); \
+}
+show_min(1);
+show_min(2);
+
+#define show_max(flag) \
+static ssize_t show_max##flag(struct device *dev, \
+    struct device_attribute *attr, char *buf) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct lm95241_data *data = i2c_get_clientdata(client); \
+\
+       snprintf(buf, PAGE_SIZE - 1, \
+               data->config & R##flag##DF_MASK ? \
+               "127000\n" : "255000\n"); \
+       return strlen(buf); \
+}
+show_max(1);
+show_max(2);
+
+#define set_type(flag) \
+static ssize_t set_type##flag(struct device *dev, \
+                                 struct device_attribute *attr, \
+                                 const char *buf, size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct lm95241_data *data = i2c_get_clientdata(client); \
+\
+       long val; \
+       strict_strtol(buf, 10, &val); \
+\
+       if ((val == 1) || (val == 2)) { \
+\
+               mutex_lock(&data->update_lock); \
+\
+               data->trutherm &= ~(TT_MASK << TT##flag##_SHIFT); \
+               if (val == 1) { \
+                       data->model |= R##flag##MS_MASK; \
+                       data->trutherm |= (TT_ON << TT##flag##_SHIFT); \
+               } \
+               else { \
+                       data->model &= ~R##flag##MS_MASK; \
+                       data->trutherm |= (TT_OFF << TT##flag##_SHIFT); \
+               } \
+\
+               data->valid = 0; \
+\
+               i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL, \
+                                         data->model); \
+               i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM, \
+                                         data->trutherm); \
+\
+               mutex_unlock(&data->update_lock); \
+\
+       } \
+       return count; \
+}
+set_type(1);
+set_type(2);
+
+#define set_min(flag) \
+static ssize_t set_min##flag(struct device *dev, \
+       struct device_attribute *devattr, const char *buf, size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct lm95241_data *data = i2c_get_clientdata(client); \
+\
+       long val; \
+       strict_strtol(buf, 10, &val); \
+\
+       mutex_lock(&data->update_lock); \
+\
+       if (val < 0) \
+               data->config |= R##flag##DF_MASK; \
+       else \
+               data->config &= ~R##flag##DF_MASK; \
+\
+       data->valid = 0; \
+\
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \
+               data->config); \
+\
+       mutex_unlock(&data->update_lock); \
+\
+       return count; \
+}
+set_min(1);
+set_min(2);
+
+#define set_max(flag) \
+static ssize_t set_max##flag(struct device *dev, \
+       struct device_attribute *devattr, const char *buf, size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct lm95241_data *data = i2c_get_clientdata(client); \
+\
+       long val; \
+       strict_strtol(buf, 10, &val); \
+\
+       mutex_lock(&data->update_lock); \
+\
+       if (val <= 127000) \
+               data->config |= R##flag##DF_MASK; \
+       else \
+               data->config &= ~R##flag##DF_MASK; \
+\
+       data->valid = 0; \
+\
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \
+               data->config); \
+\
+       mutex_unlock(&data->update_lock); \
+\
+       return count; \
+}
+set_max(1);
+set_max(2);
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_local, NULL);
+static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote1, NULL);
+static DEVICE_ATTR(temp3_input, S_IRUGO, show_remote2, NULL);
+static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type1, set_type1);
+static DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type2, set_type2);
+static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min1, set_min1);
+static DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min2, set_min2);
+static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max1, set_max1);
+static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max2, set_max2);
+static DEVICE_ATTR(rate, S_IWUSR | S_IRUGO, show_rate, set_rate);
+
+static struct attribute *lm95241_attributes[] = {
+       &dev_attr_temp1_input.attr,
+       &dev_attr_temp2_input.attr,
+       &dev_attr_temp3_input.attr,
+       &dev_attr_temp2_type.attr,
+       &dev_attr_temp3_type.attr,
+       &dev_attr_temp2_min.attr,
+       &dev_attr_temp3_min.attr,
+       &dev_attr_temp2_max.attr,
+       &dev_attr_temp3_max.attr,
+       &dev_attr_rate.attr,
+       NULL
+};
+
+static const struct attribute_group lm95241_group = {
+       .attrs = lm95241_attributes,
+};
+
+/* Init/exit code */
+static int lm95241_attach_adapter(struct i2c_adapter *adapter)
+{
+       if (!(adapter->class & I2C_CLASS_HWMON))
+               return 0;
+       return i2c_probe(adapter, &addr_data, lm95241_detect);
+}
+
+/*
+ * The following function does more than just detection. If detection
+ * succeeds, it also registers the new chip.
+ */
+static int lm95241_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+       struct i2c_client *new_client;
+       struct lm95241_data *data;
+       int err = 0;
+       const char *name = "";
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               goto exit;
+
+       data = kzalloc(sizeof(struct lm95241_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       /* The common I2C client data is placed right before the
+          LM95241-specific data. */
+       new_client = &data->client;
+       i2c_set_clientdata(new_client, data);
+       new_client->addr = address;
+       new_client->adapter = adapter;
+       new_client->driver = &lm95241_driver;
+       new_client->flags = 0;
+
+       /*
+        * Now we do the remaining detection. A negative kind means that
+        * the driver was loaded with no force parameter (default), so we
+        * must both detect and identify the chip. A zero kind means that
+        * the driver was loaded with the force parameter, the detection
+        * step shall be skipped. A positive kind means that the driver
+        * was loaded with the force parameter and a given kind of chip is
+        * requested, so both the detection and the identification steps
+        * are skipped.
+        */
+       if (kind < 0) { /* detection */
+               if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID)
+                    != MANUFACTURER_ID)
+               || (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID)
+                   < DEFAULT_REVISION)) {
+                       dev_dbg(&adapter->dev,
+                               "LM95241 detection failed at 0x%02x.\n",
+                               address);
+                       goto exit_free;
+               }
+       }
+
+       if (kind <= 0) { /* identification */
+               if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID)
+                    == MANUFACTURER_ID)
+               && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID)
+                   >= DEFAULT_REVISION)) {
+
+                       kind = lm95241;
+
+                       if (kind <= 0) { /* identification failed */
+                               dev_info(&adapter->dev, "Unsupported chip\n");
+                               goto exit_free;
+                       }
+               }
+       }
+
+       if (kind == lm95241)
+               name = "lm95241";
+
+       /* We can fill in the remaining client fields */
+       strlcpy(new_client->name, name, I2C_NAME_SIZE);
+       data->valid = 0;
+       mutex_init(&data->update_lock);
+
+       /* Tell the I2C layer a new client has arrived */
+       err = i2c_attach_client(new_client);
+       if (err)
+               goto exit_free;
+
+       /* Initialize the LM95241 chip */
+       lm95241_init_client(new_client);
+
+       /* Register sysfs hooks */
+       err = sysfs_create_group(&new_client->dev.kobj, &lm95241_group);
+       if (err)
+               goto exit_detach;
+
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove_files;
+       }
+
+       return 0;
+
+exit_remove_files:
+       sysfs_remove_group(&new_client->dev.kobj, &lm95241_group);
+exit_detach:
+       i2c_detach_client(new_client);
+exit_free:
+       kfree(data);
+exit:
+       return err;
+}
+
+static void lm95241_init_client(struct i2c_client *client)
+{
+       struct lm95241_data *data = i2c_get_clientdata(client);
+
+       data->rate = HZ;    /* 1 sec default */
+       data->valid = 0;
+       data->config = CFG_CR0076;
+       data->model = 0;
+       data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT);
+
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG,
+                                 data->config);
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_REM_FILTER,
+                                 R1FE_MASK | R2FE_MASK);
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM,
+                                 data->trutherm);
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL,
+                                 data->model);
+}
+
+static int lm95241_detach_client(struct i2c_client *client)
+{
+       struct lm95241_data *data = i2c_get_clientdata(client);
+       int err;
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &lm95241_group);
+
+       err = i2c_detach_client(client);
+       if (err)
+               return err;
+
+       kfree(data);
+       return 0;
+}
+
+static struct lm95241_data *lm95241_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95241_data *data = i2c_get_clientdata(client);
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + data->rate) ||
+           !data->valid) {
+               dev_dbg(&client->dev, "Updating lm95241 data.\n");
+               data->local_h =
+                       i2c_smbus_read_byte_data(client,
+                                                LM95241_REG_R_LOCAL_TEMPH);
+               data->local_l =
+                       i2c_smbus_read_byte_data(client,
+                                                LM95241_REG_R_LOCAL_TEMPL);
+               data->remote1_h =
+                       i2c_smbus_read_byte_data(client,
+                                                LM95241_REG_R_REMOTE1_TEMPH);
+               data->remote1_l =
+                       i2c_smbus_read_byte_data(client,
+                                                LM95241_REG_R_REMOTE1_TEMPL);
+               data->remote2_h =
+                       i2c_smbus_read_byte_data(client,
+                                                LM95241_REG_R_REMOTE2_TEMPH);
+               data->remote2_l =
+                       i2c_smbus_read_byte_data(client,
+                                                LM95241_REG_R_REMOTE2_TEMPL);
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+static int __init sensors_lm95241_init(void)
+{
+       return i2c_add_driver(&lm95241_driver);
+}
+
+static void __exit sensors_lm95241_exit(void)
+{
+       i2c_del_driver(&lm95241_driver);
+}
+
+MODULE_AUTHOR("Davide Rizzo <elpa-rizzo@gmail.com>");
+MODULE_DESCRIPTION("LM95241 sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_lm95241_init);
+module_exit(sensors_lm95241_exit);
diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c
new file mode 100644 (file)
index 0000000..9386e2a
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * Driver for Linear Technology LTC4215 I2C Hot Swap Controller
+ *
+ * Copyright (C) 2009 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * Datasheet:
+ * http://www.linear.com/pc/downloadDocument.do?navId=H0,C1,C1003,C1006,C1163,P17572,D12697
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(ltc4215);
+
+/* Here are names of the chip's registers (a.k.a. commands) */
+enum ltc4215_cmd {
+       LTC4215_CONTROL                 = 0x00, /* rw */
+       LTC4215_ALERT                   = 0x01, /* rw */
+       LTC4215_STATUS                  = 0x02, /* ro */
+       LTC4215_FAULT                   = 0x03, /* rw */
+       LTC4215_SENSE                   = 0x04, /* rw */
+       LTC4215_SOURCE                  = 0x05, /* rw */
+       LTC4215_ADIN                    = 0x06, /* rw */
+};
+
+struct ltc4215_data {
+       struct device *hwmon_dev;
+
+       struct mutex update_lock;
+       bool valid;
+       unsigned long last_updated; /* in jiffies */
+
+       /* Registers */
+       u8 regs[7];
+};
+
+static struct ltc4215_data *ltc4215_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ltc4215_data *data = i2c_get_clientdata(client);
+       s32 val;
+       int i;
+
+       mutex_lock(&data->update_lock);
+
+       /* The chip's A/D updates 10 times per second */
+       if (time_after(jiffies, data->last_updated + HZ / 10) || !data->valid) {
+
+               dev_dbg(&client->dev, "Starting ltc4215 update\n");
+
+               /* Read all registers */
+               for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
+                       val = i2c_smbus_read_byte_data(client, i);
+                       if (unlikely(val < 0))
+                               data->regs[i] = 0;
+                       else
+                               data->regs[i] = val;
+               }
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+/* Return the voltage from the given register in millivolts */
+static int ltc4215_get_voltage(struct device *dev, u8 reg)
+{
+       struct ltc4215_data *data = ltc4215_update_device(dev);
+       const u8 regval = data->regs[reg];
+       u32 voltage = 0;
+
+       switch (reg) {
+       case LTC4215_SENSE:
+               /* 151 uV per increment */
+               voltage = regval * 151 / 1000;
+               break;
+       case LTC4215_SOURCE:
+               /* 60.5 mV per increment */
+               voltage = regval * 605 / 10;
+               break;
+       case LTC4215_ADIN:
+               /* The ADIN input is divided by 12.5, and has 4.82 mV
+                * per increment, so we have the additional multiply */
+               voltage = regval * 482 * 125 / 1000;
+               break;
+       default:
+               /* If we get here, the developer messed up */
+               WARN_ON_ONCE(1);
+               break;
+       }
+
+       return voltage;
+}
+
+/* Return the current from the sense resistor in mA */
+static unsigned int ltc4215_get_current(struct device *dev)
+{
+       struct ltc4215_data *data = ltc4215_update_device(dev);
+
+       /* The strange looking conversions that follow are fixed-point
+        * math, since we cannot do floating point in the kernel.
+        *
+        * Step 1: convert sense register to microVolts
+        * Step 2: convert voltage to milliAmperes
+        *
+        * If you play around with the V=IR equation, you come up with
+        * the following: X uV / Y mOhm == Z mA
+        *
+        * With the resistors that are fractions of a milliOhm, we multiply
+        * the voltage and resistance by 10, to shift the decimal point.
+        * Now we can use the normal division operator again.
+        */
+
+       /* Calculate voltage in microVolts (151 uV per increment) */
+       const unsigned int voltage = data->regs[LTC4215_SENSE] * 151;
+
+       /* Calculate current in milliAmperes (4 milliOhm sense resistor) */
+       const unsigned int curr = voltage / 4;
+
+       return curr;
+}
+
+static ssize_t ltc4215_show_voltage(struct device *dev,
+                                   struct device_attribute *da,
+                                   char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       const int voltage = ltc4215_get_voltage(dev, attr->index);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", voltage);
+}
+
+static ssize_t ltc4215_show_current(struct device *dev,
+                                   struct device_attribute *da,
+                                   char *buf)
+{
+       const unsigned int curr = ltc4215_get_current(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", curr);
+}
+
+static ssize_t ltc4215_show_power(struct device *dev,
+                                 struct device_attribute *da,
+                                 char *buf)
+{
+       const unsigned int curr = ltc4215_get_current(dev);
+       const int output_voltage = ltc4215_get_voltage(dev, LTC4215_ADIN);
+
+       /* current in mA * voltage in mV == power in uW */
+       const unsigned int power = abs(output_voltage * curr);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", power);
+}
+
+static ssize_t ltc4215_show_alarm(struct device *dev,
+                                         struct device_attribute *da,
+                                         char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
+       struct ltc4215_data *data = ltc4215_update_device(dev);
+       const u8 reg = data->regs[attr->index];
+       const u32 mask = attr->nr;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", (reg & mask) ? 1 : 0);
+}
+
+/* These macros are used below in constructing device attribute objects
+ * for use with sysfs_create_group() to make a sysfs device file
+ * for each register.
+ */
+
+#define LTC4215_VOLTAGE(name, ltc4215_cmd_idx) \
+       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
+       ltc4215_show_voltage, NULL, ltc4215_cmd_idx)
+
+#define LTC4215_CURRENT(name) \
+       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
+       ltc4215_show_current, NULL, 0);
+
+#define LTC4215_POWER(name) \
+       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
+       ltc4215_show_power, NULL, 0);
+
+#define LTC4215_ALARM(name, mask, reg) \
+       static SENSOR_DEVICE_ATTR_2(name, S_IRUGO, \
+       ltc4215_show_alarm, NULL, (mask), reg)
+
+/* Construct a sensor_device_attribute structure for each register */
+
+/* Current */
+LTC4215_CURRENT(curr1_input);
+LTC4215_ALARM(curr1_max_alarm, (1 << 2),       LTC4215_STATUS);
+
+/* Power (virtual) */
+LTC4215_POWER(power1_input);
+LTC4215_ALARM(power1_alarm,    (1 << 3),       LTC4215_STATUS);
+
+/* Input Voltage */
+LTC4215_VOLTAGE(in1_input,                     LTC4215_ADIN);
+LTC4215_ALARM(in1_max_alarm,   (1 << 0),       LTC4215_STATUS);
+LTC4215_ALARM(in1_min_alarm,   (1 << 1),       LTC4215_STATUS);
+
+/* Output Voltage */
+LTC4215_VOLTAGE(in2_input,                     LTC4215_SOURCE);
+
+/* Finally, construct an array of pointers to members of the above objects,
+ * as required for sysfs_create_group()
+ */
+static struct attribute *ltc4215_attributes[] = {
+       &sensor_dev_attr_curr1_input.dev_attr.attr,
+       &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_power1_input.dev_attr.attr,
+       &sensor_dev_attr_power1_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+
+       NULL,
+};
+
+static const struct attribute_group ltc4215_group = {
+       .attrs = ltc4215_attributes,
+};
+
+static int ltc4215_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct ltc4215_data *data;
+       int ret;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               ret = -ENOMEM;
+               goto out_kzalloc;
+       }
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+
+       /* Initialize the LTC4215 chip */
+       /* TODO */
+
+       /* Register sysfs hooks */
+       ret = sysfs_create_group(&client->dev.kobj, &ltc4215_group);
+       if (ret)
+               goto out_sysfs_create_group;
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               ret = PTR_ERR(data->hwmon_dev);
+               goto out_hwmon_device_register;
+       }
+
+       return 0;
+
+out_hwmon_device_register:
+       sysfs_remove_group(&client->dev.kobj, &ltc4215_group);
+out_sysfs_create_group:
+       kfree(data);
+out_kzalloc:
+       return ret;
+}
+
+static int ltc4215_remove(struct i2c_client *client)
+{
+       struct ltc4215_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &ltc4215_group);
+
+       kfree(data);
+
+       return 0;
+}
+
+static int ltc4215_detect(struct i2c_client *client,
+                         int kind,
+                         struct i2c_board_info *info)
+{
+       struct i2c_adapter *adapter = client->adapter;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       if (kind < 0) {         /* probed detection - check the chip type */
+               s32 v;          /* 8 bits from the chip, or -ERRNO */
+
+               /*
+                * Register 0x01 bit b7 is reserved, expect 0
+                * Register 0x03 bit b6 and b7 are reserved, expect 0
+                */
+               v = i2c_smbus_read_byte_data(client, LTC4215_ALERT);
+               if (v < 0 || (v & (1 << 7)) != 0)
+                       return -ENODEV;
+
+               v = i2c_smbus_read_byte_data(client, LTC4215_FAULT);
+               if (v < 0 || (v & ((1 << 6) | (1 << 7))) != 0)
+                               return -ENODEV;
+       }
+
+       strlcpy(info->type, "ltc4215", I2C_NAME_SIZE);
+       dev_info(&adapter->dev, "ltc4215 %s at address 0x%02x\n",
+                       kind < 0 ? "probed" : "forced",
+                       client->addr);
+
+       return 0;
+}
+
+static const struct i2c_device_id ltc4215_id[] = {
+       { "ltc4215", ltc4215 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ltc4215_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ltc4215_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "ltc4215",
+       },
+       .probe          = ltc4215_probe,
+       .remove         = ltc4215_remove,
+       .id_table       = ltc4215_id,
+       .detect         = ltc4215_detect,
+       .address_data   = &addr_data,
+};
+
+static int __init ltc4215_init(void)
+{
+       return i2c_add_driver(&ltc4215_driver);
+}
+
+static void __exit ltc4215_exit(void)
+{
+       i2c_del_driver(&ltc4215_driver);
+}
+
+MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
+MODULE_DESCRIPTION("LTC4215 driver");
+MODULE_LICENSE("GPL");
+
+module_init(ltc4215_init);
+module_exit(ltc4215_exit);
similarity index 96%
rename from drivers/i2c/chips/pcf8591.c
rename to drivers/hwmon/pcf8591.c
index 16ce3e193776a673b47efbf7af6e50a68878553f..1d7ffebd679d0cce6f25c9e1946d7e9739c1b4b5 100644 (file)
@@ -1,6 +1,6 @@
 /*
     Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net>
-    Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with 
+    Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
     the help of Jean Delvare <khali@linux-fr.org>
 
     This program is free software; you can redistribute it and/or modify
@@ -41,13 +41,13 @@ MODULE_PARM_DESC(input_mode,
        " 3 = two differential inputs\n");
 
 /* The PCF8591 control byte
-      7    6    5    4    3    2    1    0  
+      7    6    5    4    3    2    1    0
    |  0 |AOEF|   AIP   |  0 |AINC|  AICH   | */
 
 /* Analog Output Enable Flag (analog output active if 1) */
 #define PCF8591_CONTROL_AOEF           0x40
-                                       
-/* Analog Input Programming 
+
+/* Analog Input Programming
    0x00 = four single ended inputs
    0x10 = three differential inputs
    0x20 = single ended and differential mixed
@@ -58,7 +58,7 @@ MODULE_PARM_DESC(input_mode,
 #define PCF8591_CONTROL_AINC           0x04
 
 /* Channel selection
-   0x00 = channel 0 
+   0x00 = channel 0
    0x01 = channel 1
    0x02 = channel 2
    0x03 = channel 3 */
@@ -114,7 +114,7 @@ static ssize_t set_out0_output(struct device *dev, struct device_attribute *attr
        return -EINVAL;
 }
 
-static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO, 
+static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO,
                   show_out0_ouput, set_out0_output);
 
 static ssize_t show_out0_enable(struct device *dev, struct device_attribute *attr, char *buf)
@@ -139,7 +139,7 @@ static ssize_t set_out0_enable(struct device *dev, struct device_attribute *attr
        return count;
 }
 
-static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO, 
+static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO,
                   show_out0_enable, set_out0_enable);
 
 static struct attribute *pcf8591_attributes[] = {
@@ -196,7 +196,7 @@ static int pcf8591_probe(struct i2c_client *client,
                err = -ENOMEM;
                goto exit;
        }
-       
+
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
 
@@ -249,8 +249,8 @@ static void pcf8591_init_client(struct i2c_client *client)
        data->aout = PCF8591_INIT_AOUT;
 
        i2c_smbus_write_byte_data(client, data->control, data->aout);
-       
-       /* The first byte transmitted contains the conversion code of the 
+
+       /* The first byte transmitted contains the conversion code of the
           previous read cycle. FLUSH IT! */
        i2c_smbus_read_byte(client);
 }
@@ -267,8 +267,8 @@ static int pcf8591_read_channel(struct device *dev, int channel)
                data->control = (data->control & ~PCF8591_CONTROL_AICH_MASK)
                              | channel;
                i2c_smbus_write_byte(client, data->control);
-       
-               /* The first byte transmitted contains the conversion code of 
+
+               /* The first byte transmitted contains the conversion code of
                   the previous read cycle. FLUSH IT! */
                i2c_smbus_read_byte(client);
        }
index feae743ba99163c2475b0f51663c89fc7e7f1375..e64b42058b219772d0c28ecf0a8780f8ef7ea1ab 100644 (file)
@@ -36,6 +36,7 @@
     w83627ehf   10      5       4       3      0x8850 0x88    0x5ca3
                                                0x8860 0xa1
     w83627dhg    9      5       4       3      0xa020 0xc1    0x5ca3
+    w83667hg     9      5       3       3      0xa510 0xc1    0x5ca3
 */
 
 #include <linux/module.h>
 #include <asm/io.h>
 #include "lm75.h"
 
-enum kinds { w83627ehf, w83627dhg };
+enum kinds { w83627ehf, w83627dhg, w83667hg };
 
 /* used to set data->name = w83627ehf_device_names[data->sio_kind] */
 static const char * w83627ehf_device_names[] = {
        "w83627ehf",
        "w83627dhg",
+       "w83667hg",
 };
 
 static unsigned short force_id;
@@ -71,6 +73,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
  */
 
 #define W83627EHF_LD_HWM       0x0b
+#define W83667HG_LD_VID        0x0d
 
 #define SIO_REG_LDSEL          0x07    /* Logical device select */
 #define SIO_REG_DEVID          0x20    /* Device ID (2 bytes) */
@@ -83,6 +86,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
 #define SIO_W83627EHF_ID       0x8850
 #define SIO_W83627EHG_ID       0x8860
 #define SIO_W83627DHG_ID       0xa020
+#define SIO_W83667HG_ID        0xa510
 #define SIO_ID_MASK            0xFFF0
 
 static inline void
@@ -289,6 +293,7 @@ struct w83627ehf_data {
        u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
        u8 pwm_enable[4]; /* 1->manual
                             2->thermal cruise (also called SmartFan I) */
+       u8 pwm_num;             /* number of pwm */
        u8 pwm[4];
        u8 target_temp[4];
        u8 tolerance[4];
@@ -298,6 +303,9 @@ struct w83627ehf_data {
 
        u8 vid;
        u8 vrm;
+
+       u8 temp3_disable;
+       u8 in6_skip;
 };
 
 struct w83627ehf_sio_data {
@@ -866,25 +874,37 @@ show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
        return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
 }
 
-static struct sensor_device_attribute sda_temp[] = {
+static struct sensor_device_attribute sda_temp_input[] = {
        SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
        SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
        SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
+};
+
+static struct sensor_device_attribute sda_temp_max[] = {
        SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
                    store_temp1_max, 0),
        SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
                    store_temp_max, 0),
        SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
                    store_temp_max, 1),
+};
+
+static struct sensor_device_attribute sda_temp_max_hyst[] = {
        SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
                    store_temp1_max_hyst, 0),
        SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
                    store_temp_max_hyst, 0),
        SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
                    store_temp_max_hyst, 1),
+};
+
+static struct sensor_device_attribute sda_temp_alarm[] = {
        SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
        SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
        SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
+};
+
+static struct sensor_device_attribute sda_temp_type[] = {
        SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
        SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
        SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
@@ -1181,6 +1201,8 @@ static void w83627ehf_device_remove_files(struct device *dev)
        for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
                device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
        for (i = 0; i < data->in_num; i++) {
+               if ((i == 6) && data->in6_skip)
+                       continue;
                device_remove_file(dev, &sda_in_input[i].dev_attr);
                device_remove_file(dev, &sda_in_alarm[i].dev_attr);
                device_remove_file(dev, &sda_in_min[i].dev_attr);
@@ -1192,15 +1214,22 @@ static void w83627ehf_device_remove_files(struct device *dev)
                device_remove_file(dev, &sda_fan_div[i].dev_attr);
                device_remove_file(dev, &sda_fan_min[i].dev_attr);
        }
-       for (i = 0; i < 4; i++) {
+       for (i = 0; i < data->pwm_num; i++) {
                device_remove_file(dev, &sda_pwm[i].dev_attr);
                device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
                device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
                device_remove_file(dev, &sda_target_temp[i].dev_attr);
                device_remove_file(dev, &sda_tolerance[i].dev_attr);
        }
-       for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
-               device_remove_file(dev, &sda_temp[i].dev_attr);
+       for (i = 0; i < 3; i++) {
+               if ((i == 2) && data->temp3_disable)
+                       continue;
+               device_remove_file(dev, &sda_temp_input[i].dev_attr);
+               device_remove_file(dev, &sda_temp_max[i].dev_attr);
+               device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
+               device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
+               device_remove_file(dev, &sda_temp_type[i].dev_attr);
+       }
 
        device_remove_file(dev, &dev_attr_name);
        device_remove_file(dev, &dev_attr_cpu0_vid);
@@ -1222,6 +1251,8 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
        for (i = 0; i < 2; i++) {
                tmp = w83627ehf_read_value(data,
                                           W83627EHF_REG_TEMP_CONFIG[i]);
+               if ((i == 1) && data->temp3_disable)
+                       continue;
                if (tmp & 0x01)
                        w83627ehf_write_value(data,
                                              W83627EHF_REG_TEMP_CONFIG[i],
@@ -1272,8 +1303,17 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
        data->name = w83627ehf_device_names[sio_data->kind];
        platform_set_drvdata(pdev, data);
 
-       /* 627EHG and 627EHF have 10 voltage inputs; DHG has 9 */
-       data->in_num = (sio_data->kind == w83627dhg) ? 9 : 10;
+       /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
+       data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
+       /* 667HG has 3 pwms */
+       data->pwm_num = (sio_data->kind == w83667hg) ? 3 : 4;
+
+       /* Check temp3 configuration bit for 667HG */
+       if (sio_data->kind == w83667hg) {
+               data->temp3_disable = w83627ehf_read_value(data,
+                                       W83627EHF_REG_TEMP_CONFIG[1]) & 0x01;
+               data->in6_skip = !data->temp3_disable;
+       }
 
        /* Initialize the chip */
        w83627ehf_init_device(data);
@@ -1281,44 +1321,64 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
        data->vrm = vid_which_vrm();
        superio_enter(sio_data->sioreg);
        /* Read VID value */
-       superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
-       if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
-               /* Set VID input sensibility if needed. In theory the BIOS
-                  should have set it, but in practice it's not always the
-                  case. We only do it for the W83627EHF/EHG because the
-                  W83627DHG is more complex in this respect. */
-               if (sio_data->kind == w83627ehf) {
-                       en_vrm10 = superio_inb(sio_data->sioreg,
-                                              SIO_REG_EN_VRM10);
-                       if ((en_vrm10 & 0x08) && data->vrm == 90) {
-                               dev_warn(dev, "Setting VID input voltage to "
-                                        "TTL\n");
-                               superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
-                                            en_vrm10 & ~0x08);
-                       } else if (!(en_vrm10 & 0x08) && data->vrm == 100) {
-                               dev_warn(dev, "Setting VID input voltage to "
-                                        "VRM10\n");
-                               superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
-                                            en_vrm10 | 0x08);
-                       }
-               }
-
-               data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA);
-               if (sio_data->kind == w83627ehf) /* 6 VID pins only */
-                       data->vid &= 0x3f;
-
+       if (sio_data->kind == w83667hg) {
+               /* W83667HG has different pins for VID input and output, so
+               we can get the VID input values directly at logical device D
+               0xe3. */
+               superio_select(sio_data->sioreg, W83667HG_LD_VID);
+               data->vid = superio_inb(sio_data->sioreg, 0xe3);
                err = device_create_file(dev, &dev_attr_cpu0_vid);
                if (err)
                        goto exit_release;
        } else {
-               dev_info(dev, "VID pins in output mode, CPU VID not "
-                        "available\n");
+               superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
+               if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
+                       /* Set VID input sensibility if needed. In theory the
+                          BIOS should have set it, but in practice it's not
+                          always the case. We only do it for the W83627EHF/EHG
+                          because the W83627DHG is more complex in this
+                          respect. */
+                       if (sio_data->kind == w83627ehf) {
+                               en_vrm10 = superio_inb(sio_data->sioreg,
+                                                      SIO_REG_EN_VRM10);
+                               if ((en_vrm10 & 0x08) && data->vrm == 90) {
+                                       dev_warn(dev, "Setting VID input "
+                                                "voltage to TTL\n");
+                                       superio_outb(sio_data->sioreg,
+                                                    SIO_REG_EN_VRM10,
+                                                    en_vrm10 & ~0x08);
+                               } else if (!(en_vrm10 & 0x08)
+                                          && data->vrm == 100) {
+                                       dev_warn(dev, "Setting VID input "
+                                                "voltage to VRM10\n");
+                                       superio_outb(sio_data->sioreg,
+                                                    SIO_REG_EN_VRM10,
+                                                    en_vrm10 | 0x08);
+                               }
+                       }
+
+                       data->vid = superio_inb(sio_data->sioreg,
+                                               SIO_REG_VID_DATA);
+                       if (sio_data->kind == w83627ehf) /* 6 VID pins only */
+                               data->vid &= 0x3f;
+
+                       err = device_create_file(dev, &dev_attr_cpu0_vid);
+                       if (err)
+                               goto exit_release;
+               } else {
+                       dev_info(dev, "VID pins in output mode, CPU VID not "
+                                "available\n");
+               }
        }
 
        /* fan4 and fan5 share some pins with the GPIO and serial flash */
-
-       fan5pin = superio_inb(sio_data->sioreg, 0x24) & 0x2;
-       fan4pin = superio_inb(sio_data->sioreg, 0x29) & 0x6;
+       if (sio_data->kind == w83667hg) {
+               fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
+               fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
+       } else {
+               fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
+               fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
+       }
        superio_exit(sio_data->sioreg);
 
        /* It looks like fan4 and fan5 pins can be alternatively used
@@ -1329,9 +1389,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 
        data->has_fan = 0x07; /* fan1, fan2 and fan3 */
        i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
-       if ((i & (1 << 2)) && (!fan4pin))
+       if ((i & (1 << 2)) && fan4pin)
                data->has_fan |= (1 << 3);
-       if (!(i & (1 << 1)) && (!fan5pin))
+       if (!(i & (1 << 1)) && fan5pin)
                data->has_fan |= (1 << 4);
 
        /* Read fan clock dividers immediately */
@@ -1344,14 +1404,16 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
                        goto exit_remove;
 
        /* if fan4 is enabled create the sf3 files for it */
-       if (data->has_fan & (1 << 3))
+       if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
                for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
                        if ((err = device_create_file(dev,
                                &sda_sf3_arrays_fan4[i].dev_attr)))
                                goto exit_remove;
                }
 
-       for (i = 0; i < data->in_num; i++)
+       for (i = 0; i < data->in_num; i++) {
+               if ((i == 6) && data->in6_skip)
+                       continue;
                if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
                        || (err = device_create_file(dev,
                                &sda_in_alarm[i].dev_attr))
@@ -1360,6 +1422,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
                        || (err = device_create_file(dev,
                                &sda_in_max[i].dev_attr)))
                        goto exit_remove;
+       }
 
        for (i = 0; i < 5; i++) {
                if (data->has_fan & (1 << i)) {
@@ -1372,7 +1435,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
                                || (err = device_create_file(dev,
                                        &sda_fan_min[i].dev_attr)))
                                goto exit_remove;
-                       if (i < 4 && /* w83627ehf only has 4 pwm */
+                       if (i < data->pwm_num &&
                                ((err = device_create_file(dev,
                                        &sda_pwm[i].dev_attr))
                                || (err = device_create_file(dev,
@@ -1387,9 +1450,21 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
                }
        }
 
-       for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
-               if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))
+       for (i = 0; i < 3; i++) {
+               if ((i == 2) && data->temp3_disable)
+                       continue;
+               if ((err = device_create_file(dev,
+                               &sda_temp_input[i].dev_attr))
+                       || (err = device_create_file(dev,
+                               &sda_temp_max[i].dev_attr))
+                       || (err = device_create_file(dev,
+                               &sda_temp_max_hyst[i].dev_attr))
+                       || (err = device_create_file(dev,
+                               &sda_temp_alarm[i].dev_attr))
+                       || (err = device_create_file(dev,
+                               &sda_temp_type[i].dev_attr)))
                        goto exit_remove;
+       }
 
        err = device_create_file(dev, &dev_attr_name);
        if (err)
@@ -1442,6 +1517,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
        static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
        static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
        static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
+       static const char __initdata sio_name_W83667HG[] = "W83667HG";
 
        u16 val;
        const char *sio_name;
@@ -1466,6 +1542,10 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
                sio_data->kind = w83627dhg;
                sio_name = sio_name_W83627DHG;
                break;
+       case SIO_W83667HG_ID:
+               sio_data->kind = w83667hg;
+               sio_name = sio_name_W83667HG;
+               break;
        default:
                if (val != 0xffff)
                        pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
index 230238df56c4d238d3fd4e9d184c7e1d1f608968..10411848fd704f58e790cc3587a92e07bd6f22c6 100644 (file)
@@ -65,6 +65,7 @@
 #include <linux/i2c.h>
 #include <linux/acpi.h>
 #include <linux/io.h>
+#include <linux/dmi.h>
 
 /* I801 SMBus address offsets */
 #define SMBHSTSTS      (0 + i801_smba)
@@ -616,10 +617,81 @@ static void __init input_apanel_init(void)
 static void __init input_apanel_init(void) {}
 #endif
 
+#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
+struct dmi_onboard_device_info {
+       const char *name;
+       u8 type;
+       unsigned short i2c_addr;
+       const char *i2c_type;
+};
+
+static struct dmi_onboard_device_info __devinitdata dmi_devices[] = {
+       { "Syleus", DMI_DEV_TYPE_OTHER, 0x73, "fscsyl" },
+       { "Hermes", DMI_DEV_TYPE_OTHER, 0x73, "fscher" },
+       { "Hades",  DMI_DEV_TYPE_OTHER, 0x73, "fschds" },
+};
+
+static void __devinit dmi_check_onboard_device(u8 type, const char *name,
+                                              struct i2c_adapter *adap)
+{
+       int i;
+       struct i2c_board_info info;
+
+       for (i = 0; i < ARRAY_SIZE(dmi_devices); i++) {
+               /* & ~0x80, ignore enabled/disabled bit */
+               if ((type & ~0x80) != dmi_devices[i].type)
+                       continue;
+               if (strcmp(name, dmi_devices[i].name))
+                       continue;
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               info.addr = dmi_devices[i].i2c_addr;
+               strlcpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE);
+               i2c_new_device(adap, &info);
+               break;
+       }
+}
+
+/* We use our own function to check for onboard devices instead of
+   dmi_find_device() as some buggy BIOS's have the devices we are interested
+   in marked as disabled */
+static void __devinit dmi_check_onboard_devices(const struct dmi_header *dm,
+                                               void *adap)
+{
+       int i, count;
+
+       if (dm->type != 10)
+               return;
+
+       count = (dm->length - sizeof(struct dmi_header)) / 2;
+       for (i = 0; i < count; i++) {
+               const u8 *d = (char *)(dm + 1) + (i * 2);
+               const char *name = ((char *) dm) + dm->length;
+               u8 type = d[0];
+               u8 s = d[1];
+
+               if (!s)
+                       continue;
+               s--;
+               while (s > 0 && name[0]) {
+                       name += strlen(name) + 1;
+                       s--;
+               }
+               if (name[0] == 0) /* Bogus string reference */
+                       continue;
+
+               dmi_check_onboard_device(type, name, adap);
+       }
+}
+#endif
+
 static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        unsigned char temp;
        int err;
+#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
+       const char *vendor;
+#endif
 
        I801_dev = dev;
        i801_features = 0;
@@ -712,6 +784,11 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
                i2c_new_device(&i801_adapter, &info);
        }
 #endif
+#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
+       vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+       if (vendor && !strcmp(vendor, "FUJITSU SIEMENS"))
+               dmi_walk(dmi_check_onboard_devices, &i801_adapter);
+#endif
 
        return 0;
 
index 2b847d8759469976513b919e48134e64024e3a44..26bf3701058648ad338847631122101eb37c691f 100644 (file)
@@ -70,7 +70,7 @@ static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
                /* Read again to allow register to stabilise */
                i2c->interrupt = readb(i2c->base + MPC_I2C_SR);
                writeb(0, i2c->base + MPC_I2C_SR);
-               wake_up_interruptible(&i2c->queue);
+               wake_up(&i2c->queue);
        }
        return IRQ_HANDLED;
 }
@@ -115,13 +115,10 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
                writeb(0, i2c->base + MPC_I2C_SR);
        } else {
                /* Interrupt mode */
-               result = wait_event_interruptible_timeout(i2c->queue,
+               result = wait_event_timeout(i2c->queue,
                        (i2c->interrupt & CSR_MIF), timeout);
 
-               if (unlikely(result < 0)) {
-                       pr_debug("I2C: wait interrupted\n");
-                       writeccr(i2c, 0);
-               } else if (unlikely(!(i2c->interrupt & CSR_MIF))) {
+               if (unlikely(!(i2c->interrupt & CSR_MIF))) {
                        pr_debug("I2C: wait timeout\n");
                        writeccr(i2c, 0);
                        result = -ETIMEDOUT;
index c80312c1f38278051f7209745bf170f5d4f35b4e..8f8c81eb0aee750006a7949ed530d10a4257503c 100644 (file)
@@ -64,19 +64,6 @@ config SENSORS_PCA9539
          This driver is deprecated and will be dropped soon. Use
          drivers/gpio/pca953x.c instead.
 
-config SENSORS_PCF8591
-       tristate "Philips PCF8591"
-       depends on EXPERIMENTAL
-       default n
-       help
-         If you say yes here you get support for Philips PCF8591 chips.
-
-         This driver can also be built as a module.  If so, the module
-         will be called pcf8591.
-
-         These devices are hard to detect and rarely found on mainstream
-         hardware.  If unsure, say N.
-
 config SENSORS_MAX6875
        tristate "Maxim MAX6875 Power supply supervisor"
        depends on EXPERIMENTAL
index d142f238a2de43f8af6169811b9a64e86803a9a2..55a37603718332dcceab0ef5c90f38a6cb054a8e 100644 (file)
@@ -15,7 +15,6 @@ obj-$(CONFIG_SENSORS_MAX6875) += max6875.o
 obj-$(CONFIG_SENSORS_PCA9539)  += pca9539.o
 obj-$(CONFIG_SENSORS_PCF8574)  += pcf8574.o
 obj-$(CONFIG_PCF8575)          += pcf8575.o
-obj-$(CONFIG_SENSORS_PCF8591)  += pcf8591.o
 obj-$(CONFIG_SENSORS_TSL2550)  += tsl2550.o
 
 ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
index 640c9920724287a42a5e9bbbd03a63a9aaa57cb3..cf06494bb74453d61f7552108d0fbc6d23e7d275 100644 (file)
@@ -222,7 +222,8 @@ comment "IDE chipset support/bugfixes"
 
 config IDE_GENERIC
        tristate "generic/default IDE chipset support"
-       depends on ALPHA || X86 || IA64 || M32R || MIPS
+       depends on ALPHA || X86 || IA64 || M32R || MIPS || ARCH_RPC || ARCH_SHARK
+       default ARM && (ARCH_RPC || ARCH_SHARK)
        help
          This is the generic IDE driver.  This driver attaches to the
          fixed legacy ports (e.g. on PCs 0x1f0/0x170, 0x1e8/0x168 and
@@ -680,7 +681,7 @@ endif
 # TODO: BLK_DEV_IDEDMA_PCI -> BLK_DEV_IDEDMA_SFF
 config BLK_DEV_IDE_PMAC
        tristate "PowerMac on-board IDE support"
-       depends on PPC_PMAC && IDE=y
+       depends on PPC_PMAC
        select IDE_TIMINGS
        select BLK_DEV_IDEDMA_PCI
        help
@@ -731,11 +732,6 @@ config BLK_DEV_IDE_AT91
        depends on ARM && ARCH_AT91 && !ARCH_AT91RM9200 && !ARCH_AT91X40
        select IDE_TIMINGS
 
-config IDE_ARM
-       tristate "ARM IDE support"
-       depends on ARM && (ARCH_RPC || ARCH_SHARK)
-       default y
-
 config BLK_DEV_IDE_ICSIDE
        tristate "ICS IDE interface support"
        depends on ARM && ARCH_ACORN
@@ -774,27 +770,20 @@ config BLK_DEV_GAYLE
          This includes on-board IDE interfaces on some Amiga models (A600,
          A1200, A4000, and A4000T), and IDE interfaces on the Zorro expansion
          bus (M-Tech E-Matrix 530 expansion card).
-         Say Y if you have an Amiga with a Gayle IDE interface and want to use
-         IDE devices (hard disks, CD-ROM drives, etc.) that are connected to
-         it.
-         Note that you also have to enable Zorro bus support if you want to
-         use Gayle IDE interfaces on the Zorro expansion bus.
 
-config BLK_DEV_IDEDOUBLER
-       bool "Amiga IDE Doubler support (EXPERIMENTAL)"
-       depends on BLK_DEV_GAYLE && EXPERIMENTAL
-       ---help---
-         This feature provides support for the so-called `IDE doublers' (made
+         It also provides support for the so-called `IDE doublers' (made
          by various manufacturers, e.g. Eyetech) that can be connected to
          the on-board IDE interface of some Amiga models. Using such an IDE
          doubler, you can connect up to four instead of two IDE devices to
-         the Amiga's on-board IDE interface.
+         the Amiga's on-board IDE interface. The feature is enabled at kernel
+         runtime using the "gayle.doubler" kernel boot parameter.
 
-         Note that the normal Amiga Gayle IDE driver may not work correctly
-         if you have an IDE doubler and don't enable this feature!
+         Say Y if you have an Amiga with a Gayle IDE interface and want to use
+         IDE devices (hard disks, CD-ROM drives, etc.) that are connected to
+         it.
 
-         Say Y if you have an IDE doubler.  The feature is enabled at kernel
-         runtime using the "gayle.doubler" kernel boot parameter.
+         Note that you also have to enable Zorro bus support if you want to
+         use Gayle IDE interfaces on the Zorro expansion bus.
 
 config BLK_DEV_BUDDHA
        tristate "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
index 9b4bbe1cdc1ad9eeb511fe607853d8a6ba985ba1..81df925f0e8b932c3e821e29dbe2e94d636a2d08 100644 (file)
@@ -21,8 +21,6 @@ ide-core-$(CONFIG_IDE_LEGACY)         += ide-legacy.o
 
 obj-$(CONFIG_IDE)                      += ide-core.o
 
-obj-$(CONFIG_IDE_ARM)                  += ide_arm.o
-
 obj-$(CONFIG_BLK_DEV_ALI14XX)          += ali14xx.o
 obj-$(CONFIG_BLK_DEV_UMC8672)          += umc8672.o
 obj-$(CONFIG_BLK_DEV_DTC2278)          += dtc2278.o
index d3513b6b8530aaa0b82497e0c4ec485c809853e8..537da1cde16d6aa00c21d5b51d9c73aa6a7c71fa 100644 (file)
@@ -189,19 +189,20 @@ static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed)
 }
 
 /**
- *     ali15x3_dma_setup       -       begin a DMA phase
+ *     ali_dma_check   -       DMA check
  *     @drive: target device
+ *     @cmd: command
  *
  *     Returns 1 if the DMA cannot be performed, zero on success.
  */
 
-static int ali15x3_dma_setup(ide_drive_t *drive)
+static int ali_dma_check(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        if (m5229_revision < 0xC2 && drive->media != ide_disk) {
-               if (rq_data_dir(drive->hwif->rq))
+               if (cmd->tf_flags & IDE_TFLAG_WRITE)
                        return 1;       /* try PIO instead of DMA */
        }
-       return ide_dma_setup(drive);
+       return 0;
 }
 
 /**
@@ -502,13 +503,13 @@ static const struct ide_port_ops ali_port_ops = {
 
 static const struct ide_dma_ops ali_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ali15x3_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
+       .dma_setup              = ide_dma_setup,
        .dma_start              = ide_dma_start,
        .dma_end                = ide_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
+       .dma_check              = ali_dma_check,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
index 1bb50f46388d64c97c1ce4288bc41e0cfff9df99..8eda552326e9030db0de6b26eebe46caf39caf48 100644 (file)
@@ -143,7 +143,7 @@ static void apply_timings(const u8 chipselect, const u8 pio,
        set_smc_timings(chipselect, cycle, setup, pulse, data_float, use_iordy);
 }
 
-static void at91_ide_input_data(ide_drive_t *drive, struct request *rq,
+static void at91_ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
                                void *buf, unsigned int len)
 {
        ide_hwif_t *hwif = drive->hwif;
@@ -156,11 +156,11 @@ static void at91_ide_input_data(ide_drive_t *drive, struct request *rq,
        len++;
 
        enter_16bit(chipselect, mode);
-       __ide_mm_insw((void __iomem *) io_ports->data_addr, buf, len / 2);
+       readsw((void __iomem *)io_ports->data_addr, buf, len / 2);
        leave_16bit(chipselect, mode);
 }
 
-static void at91_ide_output_data(ide_drive_t *drive, struct request *rq,
+static void at91_ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
                                 void *buf, unsigned int len)
 {
        ide_hwif_t *hwif = drive->hwif;
@@ -171,7 +171,7 @@ static void at91_ide_output_data(ide_drive_t *drive, struct request *rq,
        pdbg("cs %u buf %p len %d\n", chipselect,  buf, len);
 
        enter_16bit(chipselect, mode);
-       __ide_mm_outsw((void __iomem *) io_ports->data_addr, buf, len / 2);
+       writesw((void __iomem *)io_ports->data_addr, buf, len / 2);
        leave_16bit(chipselect, mode);
 }
 
@@ -185,91 +185,77 @@ static void ide_mm_outb(u8 value, unsigned long port)
        writeb(value, (void __iomem *) port);
 }
 
-static void at91_ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+static void at91_ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct ide_io_ports *io_ports = &hwif->io_ports;
-       struct ide_taskfile *tf = &task->tf;
-       u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+       struct ide_taskfile *tf = &cmd->tf;
+       u8 HIHI = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
 
-       if (task->tf_flags & IDE_TFLAG_FLAGGED)
+       if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
                HIHI = 0xFF;
 
-       if (task->tf_flags & IDE_TFLAG_OUT_DATA) {
-               u16 data = (tf->hob_data << 8) | tf->data;
-
-               at91_ide_output_data(drive, NULL, &data, 2);
-       }
-
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
                ide_mm_outb(tf->hob_feature, io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
                ide_mm_outb(tf->hob_nsect, io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
                ide_mm_outb(tf->hob_lbal, io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
                ide_mm_outb(tf->hob_lbam, io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
                ide_mm_outb(tf->hob_lbah, io_ports->lbah_addr);
 
-       if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_FEATURE)
                ide_mm_outb(tf->feature, io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_NSECT)
                ide_mm_outb(tf->nsect, io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAL)
                ide_mm_outb(tf->lbal, io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAM)
                ide_mm_outb(tf->lbam, io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAH)
                ide_mm_outb(tf->lbah, io_ports->lbah_addr);
 
-       if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_DEVICE)
                ide_mm_outb((tf->device & HIHI) | drive->select, io_ports->device_addr);
 }
 
-static void at91_ide_tf_read(ide_drive_t *drive, ide_task_t *task)
+static void at91_ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct ide_io_ports *io_ports = &hwif->io_ports;
-       struct ide_taskfile *tf = &task->tf;
-
-       if (task->tf_flags & IDE_TFLAG_IN_DATA) {
-               u16 data;
-
-               at91_ide_input_data(drive, NULL, &data, 2);
-               tf->data = data & 0xff;
-               tf->hob_data = (data >> 8) & 0xff;
-       }
+       struct ide_taskfile *tf = &cmd->tf;
 
        /* be sure we're looking at the low order bits */
-       ide_mm_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+       ide_mm_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-       if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
-               tf->feature = ide_mm_inb(io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_IN_ERROR)
+               tf->error  = ide_mm_inb(io_ports->feature_addr);
+       if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
                tf->nsect  = ide_mm_inb(io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
                tf->lbal   = ide_mm_inb(io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAM)
                tf->lbam   = ide_mm_inb(io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAH)
                tf->lbah   = ide_mm_inb(io_ports->lbah_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+       if (cmd->tf_flags & IDE_TFLAG_IN_DEVICE)
                tf->device = ide_mm_inb(io_ports->device_addr);
 
-       if (task->tf_flags & IDE_TFLAG_LBA48) {
-               ide_mm_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
-
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
-                       tf->hob_feature = ide_mm_inb(io_ports->feature_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
-                       tf->hob_nsect   = ide_mm_inb(io_ports->nsect_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
-                       tf->hob_lbal    = ide_mm_inb(io_ports->lbal_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
-                       tf->hob_lbam    = ide_mm_inb(io_ports->lbam_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
-                       tf->hob_lbah    = ide_mm_inb(io_ports->lbah_addr);
+       if (cmd->tf_flags & IDE_TFLAG_LBA48) {
+               ide_mm_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr);
+
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR)
+                       tf->hob_error = ide_mm_inb(io_ports->feature_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+                       tf->hob_nsect = ide_mm_inb(io_ports->nsect_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+                       tf->hob_lbal  = ide_mm_inb(io_ports->lbal_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+                       tf->hob_lbam  = ide_mm_inb(io_ports->lbam_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+                       tf->hob_lbah  = ide_mm_inb(io_ports->lbah_addr);
        }
 }
 
@@ -295,8 +281,9 @@ static const struct ide_tp_ops at91_ide_tp_ops = {
        .exec_command   = ide_exec_command,
        .read_status    = ide_read_status,
        .read_altstatus = ide_read_altstatus,
-       .set_irq        = ide_set_irq,
+       .write_devctl   = ide_write_devctl,
 
+       .dev_select     = ide_dev_select,
        .tf_load        = at91_ide_tf_load,
        .tf_read        = at91_ide_tf_read,
 
index 154ec2cf734f302a4a154ba948b663e3c8b283b9..46013644c965c1638faf8f519cd1578a177d114d 100644 (file)
@@ -50,7 +50,7 @@ static _auide_hwif auide_hwif;
 
 #if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA)
 
-void auide_insw(unsigned long port, void *addr, u32 count)
+static inline void auide_insw(unsigned long port, void *addr, u32 count)
 {
        _auide_hwif *ahwif = &auide_hwif;
        chan_tab_t *ctp;
@@ -68,7 +68,7 @@ void auide_insw(unsigned long port, void *addr, u32 count)
        ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);
 }
 
-void auide_outsw(unsigned long port, void *addr, u32 count)
+static inline void auide_outsw(unsigned long port, void *addr, u32 count)
 {
        _auide_hwif *ahwif = &auide_hwif;
        chan_tab_t *ctp;
@@ -86,13 +86,13 @@ void auide_outsw(unsigned long port, void *addr, u32 count)
        ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);
 }
 
-static void au1xxx_input_data(ide_drive_t *drive, struct request *rq,
+static void au1xxx_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
                              void *buf, unsigned int len)
 {
        auide_insw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
 }
 
-static void au1xxx_output_data(ide_drive_t *drive, struct request *rq,
+static void au1xxx_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
                               void *buf, unsigned int len)
 {
        auide_outsw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
@@ -209,23 +209,17 @@ static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed)
  */
 
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-static int auide_build_dmatable(ide_drive_t *drive)
+static int auide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
 {
-       int i, iswrite, count = 0;
        ide_hwif_t *hwif = drive->hwif;
-       struct request *rq = hwif->rq;
        _auide_hwif *ahwif = &auide_hwif;
        struct scatterlist *sg;
+       int i = cmd->sg_nents, count = 0;
+       int iswrite = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
 
-       iswrite = (rq_data_dir(rq) == WRITE);
        /* Save for interrupt context */
        ahwif->drive = drive;
 
-       hwif->sg_nents = i = ide_build_sglist(drive, rq);
-
-       if (!i)
-               return 0;
-
        /* fill the descriptors */
        sg = hwif->sg_table;
        while (i && sg_dma_len(sg)) {
@@ -242,7 +236,7 @@ static int auide_build_dmatable(ide_drive_t *drive)
                        if (++count >= PRD_ENTRIES) {
                                printk(KERN_WARNING "%s: DMA table too small\n",
                                       drive->name);
-                               goto use_pio_instead;
+                               return 0;
                        }
 
                        /* Lets enable intr for the last descriptor only */
@@ -278,21 +272,11 @@ static int auide_build_dmatable(ide_drive_t *drive)
        if (count)
                return 1;
 
- use_pio_instead:
-       ide_destroy_dmatable(drive);
-
        return 0; /* revert to PIO for this request */
 }
 
 static int auide_dma_end(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif = drive->hwif;
-
-       if (hwif->sg_nents) {
-               ide_destroy_dmatable(drive);
-               hwif->sg_nents = 0;
-       }
-
        return 0;
 }
 
@@ -301,23 +285,11 @@ static void auide_dma_start(ide_drive_t *drive )
 }
 
 
-static void auide_dma_exec_cmd(ide_drive_t *drive, u8 command)
+static int auide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
 {
-       /* issue cmd to drive */
-       ide_execute_command(drive, command, &ide_dma_intr,
-                           (2*WAIT_CMD), NULL);
-}
-
-static int auide_dma_setup(ide_drive_t *drive)
-{
-       struct request *rq = drive->hwif->rq;
-
-       if (!auide_build_dmatable(drive)) {
-               ide_map_sg(drive, rq);
+       if (auide_build_dmatable(drive, cmd) == 0)
                return 1;
-       }
 
-       drive->waiting_for_dma = 1;
        return 0;
 }
 
@@ -342,16 +314,11 @@ static void auide_dma_host_set(ide_drive_t *drive, int on)
 
 static void auide_ddma_tx_callback(int irq, void *param)
 {
-       _auide_hwif *ahwif = (_auide_hwif*)param;
-       ahwif->drive->waiting_for_dma = 0;
 }
 
 static void auide_ddma_rx_callback(int irq, void *param)
 {
-       _auide_hwif *ahwif = (_auide_hwif*)param;
-       ahwif->drive->waiting_for_dma = 0;
 }
-
 #endif /* end CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */
 
 static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize, u32 devwidth, u32 flags)
@@ -369,12 +336,10 @@ static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize, u32 de
 static const struct ide_dma_ops au1xxx_dma_ops = {
        .dma_host_set           = auide_dma_host_set,
        .dma_setup              = auide_dma_setup,
-       .dma_exec_cmd           = auide_dma_exec_cmd,
        .dma_start              = auide_dma_start,
        .dma_end                = auide_dma_end,
        .dma_test_irq           = auide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
 };
 
 static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
@@ -502,9 +467,9 @@ static const struct ide_tp_ops au1xxx_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = ide_tf_load,
        .tf_read                = ide_tf_read,
 
index c5a3c9ef6a5d7df995d7d7fc2deba0b7b7cb7041..d028f8864bc14f7324f24c25abc02c4258f98bb7 100644 (file)
@@ -143,6 +143,11 @@ static void __init buddha_setup_ports(hw_regs_t *hw, unsigned long base,
        hw->chipset = ide_generic;
 }
 
+static const struct ide_port_info buddha_port_info = {
+       .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
+       .irq_flags              = IRQF_SHARED,
+};
+
     /*
      *  Probe for a Buddha or Catweasel IDE interface
      */
@@ -172,10 +177,6 @@ static int __init buddha_init(void)
                
                board = z->resource.start;
 
-/*
- * FIXME: we now have selectable mmio v/s iomio transports.
- */
-
                if(type != BOARD_XSURF) {
                        if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE"))
                                continue;
@@ -224,7 +225,7 @@ fail_base2:
                        hws[i] = &hw[i];
                }
 
-               ide_host_add(NULL, hws, NULL);
+               ide_host_add(&buddha_port_info, hws, NULL);
        }
 
        return 0;
index aeee036b15035594432ff8de3bc5e0c5c9ab4946..80b777e4247b168644ca75691de11ea9d17e6edb 100644 (file)
@@ -318,7 +318,6 @@ static int cmd646_1_dma_end(ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        u8 dma_stat = 0, dma_cmd = 0;
 
-       drive->waiting_for_dma = 0;
        /* get DMA status */
        dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
        /* read DMA command state */
@@ -327,8 +326,6 @@ static int cmd646_1_dma_end(ide_drive_t *drive)
        outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
        /* clear the INTR & ERROR bits */
        outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
-       /* and free any DMA resources */
-       ide_destroy_dmatable(drive);
        /* verify good DMA status */
        return (dma_stat & 7) != 4;
 }
@@ -379,36 +376,33 @@ static const struct ide_port_ops cmd64x_port_ops = {
 static const struct ide_dma_ops cmd64x_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
        .dma_setup              = ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = ide_dma_start,
        .dma_end                = cmd64x_dma_end,
        .dma_test_irq           = cmd64x_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
 static const struct ide_dma_ops cmd646_rev1_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
        .dma_setup              = ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = ide_dma_start,
        .dma_end                = cmd646_1_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
 static const struct ide_dma_ops cmd648_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
        .dma_setup              = ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = ide_dma_start,
        .dma_end                = cmd648_dma_end,
        .dma_test_irq           = cmd648_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
index 8e8b35a899012961aa6967cb5e8dd7115cf0afb4..40bf05eddf6ea1ef55c01e1c87be2ca9f88657b7 100644 (file)
@@ -92,8 +92,7 @@ static u8 cs5530_udma_filter(ide_drive_t *drive)
                if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
                    (mateid[ATA_ID_UDMA_MODES] & 7))
                        goto out;
-               if ((mateid[ATA_ID_FIELD_VALID] & 2) &&
-                   (mateid[ATA_ID_MWDMA_MODES] & 7))
+               if (mateid[ATA_ID_MWDMA_MODES] & 7)
                        mask = 0;
        }
 out:
index 7a62db719a46320e6ab5039cd7ebd27b8b3bc3e4..353a35bbba636dcd1d3a22e1dd275efc7894319e 100644 (file)
@@ -231,12 +231,11 @@ static const struct ide_port_ops cs5536_port_ops = {
 static const struct ide_dma_ops cs5536_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
        .dma_setup              = ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = cs5536_dma_start,
        .dma_end                = cs5536_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
 };
 
 static const struct ide_port_info cs5536_info = {
index bacb1194c9c9e5eb9ed4290fd625a457b60c903f..f153b95619bb372e958f7c51c8ca1dcd1ccf043a 100644 (file)
@@ -66,6 +66,7 @@ static const struct ide_port_info delkin_cb_port_info = {
        .port_ops               = &delkin_cb_port_ops,
        .host_flags             = IDE_HFLAG_IO_32BIT | IDE_HFLAG_UNMASK_IRQS |
                                  IDE_HFLAG_NO_DMA,
+       .irq_flags              = IRQF_SHARED,
        .init_chipset           = delkin_cb_init_chipset,
 };
 
index 689b2e493413412a235202ee5eb742a78440a082..c6b138122981b7474b5f3f1381f4e798da9fb132 100644 (file)
@@ -100,7 +100,8 @@ static const struct ide_port_info dtc2278_port_info __initdata = {
                                  IDE_HFLAG_IO_32BIT |
                                  /* disallow ->io_32bit changes */
                                  IDE_HFLAG_NO_IO_32BIT |
-                                 IDE_HFLAG_NO_DMA,
+                                 IDE_HFLAG_NO_DMA |
+                                 IDE_HFLAG_DTC2278,
        .pio_mask               = ATA_PIO4,
 };
 
index a638e952d67a4b847ec94b4e7c324ef859382850..afa2af9a362beb9464f69b5d79397481f9b2fbd9 100644 (file)
      *  which is shared between several drivers.
      */
 
-int falconide_intr_lock;
-EXPORT_SYMBOL(falconide_intr_lock);
+static int falconide_intr_lock;
 
-static void falconide_input_data(ide_drive_t *drive, struct request *rq,
+static void falconide_release_lock(void)
+{
+       if (falconide_intr_lock == 0) {
+               printk(KERN_ERR "%s: bug\n", __func__);
+               return;
+       }
+       falconide_intr_lock = 0;
+       stdma_release();
+}
+
+static void falconide_get_lock(irq_handler_t handler, void *data)
+{
+       if (falconide_intr_lock == 0) {
+               if (in_interrupt() > 0)
+                       panic("Falcon IDE hasn't ST-DMA lock in interrupt");
+               stdma_lock(handler, data);
+               falconide_intr_lock = 1;
+       }
+}
+
+static void falconide_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
                                 void *buf, unsigned int len)
 {
        unsigned long data_addr = drive->hwif->io_ports.data_addr;
 
-       if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
+       if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS))
                return insw(data_addr, buf, (len + 1) / 2);
 
-       insw_swapw(data_addr, buf, (len + 1) / 2);
+       raw_insw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
 }
 
-static void falconide_output_data(ide_drive_t *drive, struct request *rq,
+static void falconide_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
                                  void *buf, unsigned int len)
 {
        unsigned long data_addr = drive->hwif->io_ports.data_addr;
 
-       if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
+       if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS))
                return outsw(data_addr, buf, (len + 1) / 2);
 
-       outsw_swapw(data_addr, buf, (len + 1) / 2);
+       raw_outsw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
 }
 
 /* Atari has a byte-swapped IDE interface */
@@ -70,9 +89,9 @@ static const struct ide_tp_ops falconide_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = ide_tf_load,
        .tf_read                = ide_tf_read,
 
@@ -81,8 +100,12 @@ static const struct ide_tp_ops falconide_tp_ops = {
 };
 
 static const struct ide_port_info falconide_port_info = {
+       .get_lock               = falconide_get_lock,
+       .release_lock           = falconide_release_lock,
        .tp_ops                 = &falconide_tp_ops,
-       .host_flags             = IDE_HFLAG_NO_DMA | IDE_HFLAG_SERIALIZE,
+       .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE |
+                                 IDE_HFLAG_NO_DMA,
+       .irq_flags              = IRQF_SHARED,
 };
 
 static void __init falconide_setup_ports(hw_regs_t *hw)
@@ -132,9 +155,9 @@ static int __init falconide_init(void)
                goto err;
        }
 
-       ide_get_lock(NULL, NULL);
+       falconide_get_lock(NULL, NULL);
        rc = ide_host_register(host, &falconide_port_info, hws);
-       ide_release_lock();
+       falconide_release_lock();
 
        if (rc)
                goto err_free;
index 59bd0be9dcb3aac5715daf3ed0dec8f8b48b1c94..c7119516c5a7ccaff6029fbacc3e3a7dfe1017ec 100644 (file)
 
 #define GAYLE_NEXT_PORT        0x1000
 
-#ifndef CONFIG_BLK_DEV_IDEDOUBLER
-#define GAYLE_NUM_HWIFS                1
-#define GAYLE_NUM_PROBE_HWIFS  GAYLE_NUM_HWIFS
-#define GAYLE_HAS_CONTROL_REG  1
-#else /* CONFIG_BLK_DEV_IDEDOUBLER */
 #define GAYLE_NUM_HWIFS                2
 #define GAYLE_NUM_PROBE_HWIFS  (ide_doubler ? GAYLE_NUM_HWIFS : \
                                               GAYLE_NUM_HWIFS-1)
@@ -66,8 +61,6 @@
 static int ide_doubler;
 module_param_named(doubler, ide_doubler, bool, 0);
 MODULE_PARM_DESC(doubler, "enable support for IDE doublers");
-#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
-
 
     /*
      *  Check and acknowledge the interrupt status
@@ -118,7 +111,9 @@ static void __init gayle_setup_ports(hw_regs_t *hw, unsigned long base,
 }
 
 static const struct ide_port_info gayle_port_info = {
-       .host_flags             = IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_DMA,
+       .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE |
+                                 IDE_HFLAG_NO_DMA,
+       .irq_flags              = IRQF_SHARED,
 };
 
     /*
@@ -149,10 +144,7 @@ static int __init gayle_init(void)
 found:
        printk(KERN_INFO "ide: Gayle IDE controller (A%d style%s)\n",
                         a4000 ? 4000 : 1200,
-#ifdef CONFIG_BLK_DEV_IDEDOUBLER
-                        ide_doubler ? ", IDE doubler" :
-#endif
-                        "");
+                        ide_doubler ? ", IDE doubler" : "");
 
        if (a4000) {
            phys_base = GAYLE_BASE_4000;
@@ -163,9 +155,6 @@ found:
            irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_1200);
            ack_intr = gayle_ack_intr_a1200;
        }
-/*
- * FIXME: we now have selectable modes between mmio v/s iomio
- */
 
        res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1);
        res_n = GAYLE_IDEREG_SIZE;
index d3b3e824f445e53bae0270152b6bb185d5fb889e..a0eb87f59134141340181afe21c12d615d0a4484 100644 (file)
@@ -835,12 +835,6 @@ static int hpt370_dma_end(ide_drive_t *drive)
        return ide_dma_end(drive);
 }
 
-static void hpt370_dma_timeout(ide_drive_t *drive)
-{
-       hpt370_irq_timeout(drive);
-       ide_dma_timeout(drive);
-}
-
 /* returns 1 if DMA IRQ issued, 0 otherwise */
 static int hpt374_dma_test_irq(ide_drive_t *drive)
 {
@@ -1418,36 +1412,34 @@ static const struct ide_port_ops hpt3xx_port_ops = {
 static const struct ide_dma_ops hpt37x_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
        .dma_setup              = ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = ide_dma_start,
        .dma_end                = hpt374_dma_end,
        .dma_test_irq           = hpt374_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
 static const struct ide_dma_ops hpt370_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
        .dma_setup              = ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = hpt370_dma_start,
        .dma_end                = hpt370_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = hpt370_dma_timeout,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
+       .dma_clear              = hpt370_irq_timeout,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
 static const struct ide_dma_ops hpt36x_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
        .dma_setup              = ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = ide_dma_start,
        .dma_end                = ide_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = hpt366_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
index c7e5c2246b79e1b29836055921e116daacafe102..2fb0f29650099c8c5ccb706c96dae78c85944c21 100644 (file)
 /*
  * This routine is invoked from ide.c to prepare for access to a given drive.
  */
-static void ht6560b_selectproc (ide_drive_t *drive)
+static void ht6560b_dev_select(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        unsigned long flags;
@@ -143,6 +143,8 @@ static void ht6560b_selectproc (ide_drive_t *drive)
 #endif
        }
        local_irq_restore(flags);
+
+       outb(drive->select | ATA_DEVICE_OBS, hwif->io_ports.device_addr);
 }
 
 /*
@@ -305,15 +307,29 @@ static int probe_ht6560b;
 module_param_named(probe, probe_ht6560b, bool, 0);
 MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
 
+static const struct ide_tp_ops ht6560b_tp_ops = {
+       .exec_command           = ide_exec_command,
+       .read_status            = ide_read_status,
+       .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
+
+       .dev_select             = ht6560b_dev_select,
+       .tf_load                = ide_tf_load,
+       .tf_read                = ide_tf_read,
+
+       .input_data             = ide_input_data,
+       .output_data            = ide_output_data,
+};
+
 static const struct ide_port_ops ht6560b_port_ops = {
        .init_dev               = ht6560b_init_dev,
        .set_pio_mode           = ht6560b_set_pio_mode,
-       .selectproc             = ht6560b_selectproc,
 };
 
 static const struct ide_port_info ht6560b_port_info __initdata = {
        .name                   = DRV_NAME,
        .chipset                = ide_ht6560b,
+       .tp_ops                 = &ht6560b_tp_ops,
        .port_ops               = &ht6560b_port_ops,
        .host_flags             = IDE_HFLAG_SERIALIZE | /* is this needed? */
                                  IDE_HFLAG_NO_DMA |
index 415d7e24f2b64784c0d8c887958777bea150078a..4e16ce68b0630988a574f51270b12a4a49bd3dc5 100644 (file)
@@ -287,13 +287,8 @@ static int icside_dma_end(ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        struct expansion_card *ec = ECARD_DEV(hwif->dev);
 
-       drive->waiting_for_dma = 0;
-
        disable_dma(ec->dma);
 
-       /* Teardown mappings after DMA has completed. */
-       ide_destroy_dmatable(drive);
-
        return get_dma_residue(ec->dma) != 0;
 }
 
@@ -307,15 +302,14 @@ static void icside_dma_start(ide_drive_t *drive)
        enable_dma(ec->dma);
 }
 
-static int icside_dma_setup(ide_drive_t *drive)
+static int icside_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct expansion_card *ec = ECARD_DEV(hwif->dev);
        struct icside_state *state = ecard_get_drvdata(ec);
-       struct request *rq = hwif->rq;
        unsigned int dma_mode;
 
-       if (rq_data_dir(rq))
+       if (cmd->tf_flags & IDE_TFLAG_WRITE)
                dma_mode = DMA_MODE_WRITE;
        else
                dma_mode = DMA_MODE_READ;
@@ -325,8 +319,6 @@ static int icside_dma_setup(ide_drive_t *drive)
         */
        BUG_ON(dma_channel_active(ec->dma));
 
-       hwif->sg_nents = ide_build_sglist(drive, rq);
-
        /*
         * Ensure that we have the right interrupt routed.
         */
@@ -346,20 +338,12 @@ static int icside_dma_setup(ide_drive_t *drive)
         * Tell the DMA engine about the SG table and
         * data direction.
         */
-       set_dma_sg(ec->dma, hwif->sg_table, hwif->sg_nents);
+       set_dma_sg(ec->dma, hwif->sg_table, cmd->sg_nents);
        set_dma_mode(ec->dma, dma_mode);
 
-       drive->waiting_for_dma = 1;
-
        return 0;
 }
 
-static void icside_dma_exec_cmd(ide_drive_t *drive, u8 cmd)
-{
-       /* issue cmd to drive */
-       ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD, NULL);
-}
-
 static int icside_dma_test_irq(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
@@ -383,11 +367,9 @@ static int icside_dma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
 static const struct ide_dma_ops icside_v6_dma_ops = {
        .dma_host_set           = icside_dma_host_set,
        .dma_setup              = icside_dma_setup,
-       .dma_exec_cmd           = icside_dma_exec_cmd,
        .dma_start              = icside_dma_start,
        .dma_end                = icside_dma_end,
        .dma_test_irq           = icside_dma_test_irq,
-       .dma_timeout            = ide_dma_timeout,
        .dma_lost_irq           = ide_dma_lost_irq,
 };
 #else
@@ -419,6 +401,10 @@ static void icside_setup_ports(hw_regs_t *hw, void __iomem *base,
        hw->chipset = ide_acorn;
 }
 
+static const struct ide_port_info icside_v5_port_info = {
+       .host_flags             = IDE_HFLAG_NO_DMA,
+};
+
 static int __devinit
 icside_register_v5(struct icside_state *state, struct expansion_card *ec)
 {
@@ -445,7 +431,7 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec)
 
        icside_setup_ports(&hw, base, &icside_cardinfo_v5, ec);
 
-       host = ide_host_alloc(NULL, hws);
+       host = ide_host_alloc(&icside_v5_port_info, hws);
        if (host == NULL)
                return -ENODEV;
 
@@ -453,7 +439,7 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec)
 
        ecard_set_drvdata(ec, state);
 
-       ret = ide_host_register(host, NULL, hws);
+       ret = ide_host_register(host, &icside_v5_port_info, hws);
        if (ret)
                goto err_free;
 
index 9e85b1ec9607604178a6a99419b2449516027f5d..78aca75a2c487ece474e08bcb220c5542caa8b4b 100644 (file)
@@ -23,7 +23,8 @@ static const struct ide_port_ops ide_4drives_port_ops = {
 
 static const struct ide_port_info ide_4drives_port_info = {
        .port_ops               = &ide_4drives_port_ops,
-       .host_flags             = IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_DMA,
+       .host_flags             = IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_DMA |
+                                 IDE_HFLAG_4DRIVES,
 };
 
 static int __init ide_4drives_init(void)
index 5b704f1ea90c901f446897ca21715b8f558bbd64..12f436951bffcf9ace9094a727e7bbabe9bd346a 100644 (file)
@@ -304,7 +304,7 @@ static int do_drive_set_taskfiles(ide_drive_t *drive,
        /* send all taskfile registers (0x1f1-0x1f7) *in*that*order* */
        for (ix = 0; ix < gtf_count; ix++) {
                u8 *gtf = (u8 *)(gtf_address + ix * REGS_PER_GTF);
-               ide_task_t task;
+               struct ide_cmd cmd;
 
                DEBPRINT("(0x1f1-1f7): "
                         "hex: %02x %02x %02x %02x %02x %02x %02x\n",
@@ -317,11 +317,11 @@ static int do_drive_set_taskfiles(ide_drive_t *drive,
                }
 
                /* convert GTF to taskfile */
-               memset(&task, 0, sizeof(ide_task_t));
-               memcpy(&task.tf_array[7], gtf, REGS_PER_GTF);
-               task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+               memset(&cmd, 0, sizeof(cmd));
+               memcpy(&cmd.tf_array[7], gtf, REGS_PER_GTF);
+               cmd.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 
-               err = ide_no_data_taskfile(drive, &task);
+               err = ide_no_data_taskfile(drive, &cmd);
                if (err) {
                        printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n",
                                        __func__, err);
index 6adc5b4a4406808d909e3944e1f1c47f5354ef15..3e43b889dd64ab55422e5b1432831586a21b5cca 100644 (file)
@@ -6,6 +6,8 @@
 #include <linux/cdrom.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
+#include <linux/scatterlist.h>
+
 #include <scsi/scsi.h>
 
 #ifdef DEBUG
@@ -69,56 +71,6 @@ int ide_check_atapi_device(ide_drive_t *drive, const char *s)
 }
 EXPORT_SYMBOL_GPL(ide_check_atapi_device);
 
-/* PIO data transfer routine using the scatter gather table. */
-int ide_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
-                   unsigned int bcount, int write)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-       xfer_func_t *xf = write ? tp_ops->output_data : tp_ops->input_data;
-       struct scatterlist *sg = pc->sg;
-       char *buf;
-       int count, done = 0;
-
-       while (bcount) {
-               count = min(sg->length - pc->b_count, bcount);
-
-               if (PageHighMem(sg_page(sg))) {
-                       unsigned long flags;
-
-                       local_irq_save(flags);
-                       buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
-                       xf(drive, NULL, buf + pc->b_count, count);
-                       kunmap_atomic(buf - sg->offset, KM_IRQ0);
-                       local_irq_restore(flags);
-               } else {
-                       buf = sg_virt(sg);
-                       xf(drive, NULL, buf + pc->b_count, count);
-               }
-
-               bcount -= count;
-               pc->b_count += count;
-               done += count;
-
-               if (pc->b_count == sg->length) {
-                       if (!--pc->sg_cnt)
-                               break;
-                       pc->sg = sg = sg_next(sg);
-                       pc->b_count = 0;
-               }
-       }
-
-       if (bcount) {
-               printk(KERN_ERR "%s: %d leftover bytes, %s\n", drive->name,
-                       bcount, write ? "padding with zeros"
-                                     : "discarding data");
-               ide_pad_transfer(drive, write, bcount);
-       }
-
-       return done;
-}
-EXPORT_SYMBOL_GPL(ide_io_buffers);
-
 void ide_init_pc(struct ide_atapi_pc *pc)
 {
        memset(pc, 0, sizeof(*pc));
@@ -302,16 +254,16 @@ EXPORT_SYMBOL_GPL(ide_cd_get_xferlen);
 
 void ide_read_bcount_and_ireason(ide_drive_t *drive, u16 *bcount, u8 *ireason)
 {
-       ide_task_t task;
+       struct ide_cmd cmd;
 
-       memset(&task, 0, sizeof(task));
-       task.tf_flags = IDE_TFLAG_IN_LBAH | IDE_TFLAG_IN_LBAM |
-                       IDE_TFLAG_IN_NSECT;
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.tf_flags = IDE_TFLAG_IN_LBAH | IDE_TFLAG_IN_LBAM |
+                      IDE_TFLAG_IN_NSECT;
 
-       drive->hwif->tp_ops->tf_read(drive, &task);
+       drive->hwif->tp_ops->tf_read(drive, &cmd);
 
-       *bcount = (task.tf.lbah << 8) | task.tf.lbam;
-       *ireason = task.tf.nsect & 3;
+       *bcount = (cmd.tf.lbah << 8) | cmd.tf.lbam;
+       *ireason = cmd.tf.nsect & 3;
 }
 EXPORT_SYMBOL_GPL(ide_read_bcount_and_ireason);
 
@@ -324,29 +276,31 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
 {
        struct ide_atapi_pc *pc = drive->pc;
        ide_hwif_t *hwif = drive->hwif;
+       struct ide_cmd *cmd = &hwif->cmd;
        struct request *rq = hwif->rq;
        const struct ide_tp_ops *tp_ops = hwif->tp_ops;
        xfer_func_t *xferfunc;
-       unsigned int timeout, temp;
+       unsigned int timeout, done;
        u16 bcount;
        u8 stat, ireason, dsc = 0;
+       u8 write = !!(pc->flags & PC_FLAG_WRITING);
 
        debug_log("Enter %s - interrupt handler\n", __func__);
 
        timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
                                               : WAIT_TAPE_CMD;
 
-       if (pc->flags & PC_FLAG_TIMEDOUT) {
-               drive->pc_callback(drive, 0);
-               return ide_stopped;
-       }
-
        /* Clear the interrupt */
        stat = tp_ops->read_status(hwif);
 
        if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
-               if (hwif->dma_ops->dma_end(drive) ||
-                   (drive->media == ide_tape && (stat & ATA_ERR))) {
+               int rc;
+
+               drive->waiting_for_dma = 0;
+               rc = hwif->dma_ops->dma_end(drive);
+               ide_dma_unmap_sg(drive, cmd);
+
+               if (rc || (drive->media == ide_tape && (stat & ATA_ERR))) {
                        if (drive->media == ide_floppy)
                                printk(KERN_ERR "%s: DMA %s error\n",
                                        drive->name, rq_data_dir(pc->rq)
@@ -362,6 +316,9 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
 
        /* No more interrupts */
        if ((stat & ATA_DRQ) == 0) {
+               int uptodate, error;
+               unsigned int done;
+
                debug_log("Packet command completed, %d bytes transferred\n",
                          pc->xferred);
 
@@ -400,8 +357,31 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
                        dsc = 1;
 
                /* Command finished - Call the callback function */
-               drive->pc_callback(drive, dsc);
+               uptodate = drive->pc_callback(drive, dsc);
+
+               if (uptodate == 0)
+                       drive->failed_pc = NULL;
+
+               if (blk_special_request(rq)) {
+                       rq->errors = 0;
+                       done = blk_rq_bytes(rq);
+                       error = 0;
+               } else {
+
+                       if (blk_fs_request(rq) == 0 && uptodate <= 0) {
+                               if (rq->errors == 0)
+                                       rq->errors = -EIO;
+                       }
+
+                       if (drive->media == ide_tape)
+                               done = ide_rq_bytes(rq); /* FIXME */
+                       else
+                               done = blk_rq_bytes(rq);
 
+                       error = uptodate ? 0 : -EIO;
+               }
+
+               ide_complete_rq(drive, error, done);
                return ide_stopped;
        }
 
@@ -421,8 +401,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
                return ide_do_reset(drive);
        }
 
-       if (((ireason & ATAPI_IO) == ATAPI_IO) ==
-               !!(pc->flags & PC_FLAG_WRITING)) {
+       if (((ireason & ATAPI_IO) == ATAPI_IO) == write) {
                /* Hopefully, we will never get here */
                printk(KERN_ERR "%s: We wanted to %s, but the device wants us "
                                "to %s!\n", drive->name,
@@ -431,78 +410,57 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
                return ide_do_reset(drive);
        }
 
-       if (!(pc->flags & PC_FLAG_WRITING)) {
-               /* Reading - Check that we have enough space */
-               temp = pc->xferred + bcount;
-               if (temp > pc->req_xfer) {
-                       if (temp > pc->buf_size) {
-                               printk(KERN_ERR "%s: The device wants to send "
-                                               "us more data than expected - "
-                                               "discarding data\n",
-                                               drive->name);
-
-                               ide_pad_transfer(drive, 0, bcount);
-                               goto next_irq;
-                       }
-                       debug_log("The device wants to send us more data than "
-                                 "expected - allowing transfer\n");
-               }
-               xferfunc = tp_ops->input_data;
-       } else
-               xferfunc = tp_ops->output_data;
+       xferfunc = write ? tp_ops->output_data : tp_ops->input_data;
 
-       if ((drive->media == ide_floppy && !pc->buf) ||
-           (drive->media == ide_tape && pc->bh)) {
-               int done = drive->pc_io_buffers(drive, pc, bcount,
-                                 !!(pc->flags & PC_FLAG_WRITING));
-
-               /* FIXME: don't do partial completions */
-               if (drive->media == ide_floppy)
-                       ide_end_request(drive, 1, done >> 9);
-       } else
-               xferfunc(drive, NULL, pc->cur_pos, bcount);
+       if (drive->media == ide_floppy && pc->buf == NULL) {
+               done = min_t(unsigned int, bcount, cmd->nleft);
+               ide_pio_bytes(drive, cmd, write, done);
+       } else if (drive->media == ide_tape && pc->bh) {
+               done = drive->pc_io_buffers(drive, pc, bcount, write);
+       } else {
+               done = min_t(unsigned int, bcount, pc->req_xfer - pc->xferred);
+               xferfunc(drive, NULL, pc->cur_pos, done);
+       }
 
        /* Update the current position */
-       pc->xferred += bcount;
-       pc->cur_pos += bcount;
+       pc->xferred += done;
+       pc->cur_pos += done;
+
+       bcount -= done;
+
+       if (bcount)
+               ide_pad_transfer(drive, write, bcount);
+
+       debug_log("[cmd %x] transferred %d bytes, padded %d bytes\n",
+                 rq->cmd[0], done, bcount);
 
-       debug_log("[cmd %x] transferred %d bytes on that intr.\n",
-                 rq->cmd[0], bcount);
-next_irq:
        /* And set the interrupt handler again */
-       ide_set_handler(drive, ide_pc_intr, timeout, NULL);
+       ide_set_handler(drive, ide_pc_intr, timeout);
        return ide_started;
 }
 
-static void ide_pktcmd_tf_load(ide_drive_t *drive, u32 tf_flags, u16 bcount)
+static void ide_init_packet_cmd(struct ide_cmd *cmd, u32 tf_flags,
+                               u16 bcount, u8 dma)
 {
-       ide_hwif_t *hwif = drive->hwif;
-       ide_task_t task;
-       u8 dma = drive->dma;
-
-       memset(&task, 0, sizeof(task));
-       task.tf_flags = IDE_TFLAG_OUT_LBAH | IDE_TFLAG_OUT_LBAM |
-                       IDE_TFLAG_OUT_FEATURE | tf_flags;
-       task.tf.feature = dma;          /* Use PIO/DMA */
-       task.tf.lbam    = bcount & 0xff;
-       task.tf.lbah    = (bcount >> 8) & 0xff;
-
-       ide_tf_dump(drive->name, &task.tf);
-       hwif->tp_ops->set_irq(hwif, 1);
-       SELECT_MASK(drive, 0);
-       hwif->tp_ops->tf_load(drive, &task);
+       cmd->protocol  = dma ? ATAPI_PROT_DMA : ATAPI_PROT_PIO;
+       cmd->tf_flags |= IDE_TFLAG_OUT_LBAH | IDE_TFLAG_OUT_LBAM |
+                        IDE_TFLAG_OUT_FEATURE | tf_flags;
+       cmd->tf.command = ATA_CMD_PACKET;
+       cmd->tf.feature = dma;          /* Use PIO/DMA */
+       cmd->tf.lbam    = bcount & 0xff;
+       cmd->tf.lbah    = (bcount >> 8) & 0xff;
 }
 
 static u8 ide_read_ireason(ide_drive_t *drive)
 {
-       ide_task_t task;
+       struct ide_cmd cmd;
 
-       memset(&task, 0, sizeof(task));
-       task.tf_flags = IDE_TFLAG_IN_NSECT;
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.tf_flags = IDE_TFLAG_IN_NSECT;
 
-       drive->hwif->tp_ops->tf_read(drive, &task);
+       drive->hwif->tp_ops->tf_read(drive, &cmd);
 
-       return task.tf.nsect & 3;
+       return cmd.tf.nsect & 3;
 }
 
 static u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason)
@@ -597,11 +555,17 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
                }
        }
 
+       hwif->expiry = expiry;
+
        /* Set the interrupt routine */
        ide_set_handler(drive,
                        (dev_is_idecd(drive) ? drive->irq_handler
                                             : ide_pc_intr),
-                       timeout, expiry);
+                       timeout);
+
+       /* Send the actual packet */
+       if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0)
+               hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len);
 
        /* Begin DMA, if necessary */
        if (dev_is_idecd(drive)) {
@@ -614,30 +578,28 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
                }
        }
 
-       /* Send the actual packet */
-       if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0)
-               hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len);
-
        return ide_started;
 }
 
-ide_startstop_t ide_issue_pc(ide_drive_t *drive)
+ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        struct ide_atapi_pc *pc;
        ide_hwif_t *hwif = drive->hwif;
        ide_expiry_t *expiry = NULL;
+       struct request *rq = hwif->rq;
        unsigned int timeout;
        u32 tf_flags;
        u16 bcount;
+       u8 drq_int = !!(drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT);
 
        if (dev_is_idecd(drive)) {
                tf_flags = IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL;
-               bcount = ide_cd_get_xferlen(hwif->rq);
+               bcount = ide_cd_get_xferlen(rq);
                expiry = ide_cd_expiry;
                timeout = ATAPI_WAIT_PC;
 
                if (drive->dma)
-                       drive->dma = !hwif->dma_ops->dma_setup(drive);
+                       drive->dma = !ide_dma_prepare(drive, cmd);
        } else {
                pc = drive->pc;
 
@@ -655,9 +617,8 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive)
                        ide_dma_off(drive);
                }
 
-               if ((pc->flags & PC_FLAG_DMA_OK) &&
-                    (drive->dev_flags & IDE_DFLAG_USING_DMA))
-                       drive->dma = !hwif->dma_ops->dma_setup(drive);
+               if (pc->flags & PC_FLAG_DMA_OK)
+                       drive->dma = !ide_dma_prepare(drive, cmd);
 
                if (!drive->dma)
                        pc->flags &= ~PC_FLAG_DMA_OK;
@@ -666,18 +627,18 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive)
                                                       : WAIT_TAPE_CMD;
        }
 
-       ide_pktcmd_tf_load(drive, tf_flags, bcount);
+       ide_init_packet_cmd(cmd, tf_flags, bcount, drive->dma);
 
-       /* Issue the packet command */
-       if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
+       (void)do_rw_taskfile(drive, cmd);
+
+       if (drq_int) {
                if (drive->dma)
                        drive->waiting_for_dma = 0;
-               ide_execute_command(drive, ATA_CMD_PACKET, ide_transfer_pc,
-                                   timeout, expiry);
-               return ide_started;
-       } else {
-               ide_execute_pkt_cmd(drive);
-               return ide_transfer_pc(drive);
+               hwif->expiry = expiry;
        }
+
+       ide_execute_command(drive, cmd, ide_transfer_pc, timeout);
+
+       return drq_int ? ide_started : ide_transfer_pc(drive);
 }
 EXPORT_SYMBOL_GPL(ide_issue_pc);
index 2177cd11664c216a50c927e884a0ba9fa522d8b4..35729a47f797f3d721b8cb26f0ec820cde9927ae 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 1994-1996   Scott Snyder <snyder@fnald0.fnal.gov>
  * Copyright (C) 1996-1998   Erik Andersen <andersee@debian.org>
  * Copyright (C) 1998-2000   Jens Axboe <axboe@suse.de>
- * Copyright (C) 2005, 2007  Bartlomiej Zolnierkiewicz
+ * Copyright (C) 2005, 2007-2009  Bartlomiej Zolnierkiewicz
  *
  * May be copied or modified under the terms of the GNU General Public
  * License.  See linux/COPYING for more information.
  * See Documentation/cdrom/ide-cd for usage information.
  *
  * Suggestions are welcome. Patches that work are more welcome though. ;-)
- * For those wishing to work on this driver, please be sure you download
- * and comply with the latest Mt. Fuji (SFF8090 version 4) and ATAPI
- * (SFF-8020i rev 2.6) standards. These documents can be obtained by
- * anonymous ftp from:
- * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps
- * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r10.pdf
+ *
+ * Documentation:
+ *     Mt. Fuji (SFF8090 version 4) and ATAPI (SFF-8020i rev 2.6) standards.
  *
  * For historical changelog please see:
  *     Documentation/ide/ChangeLog.ide-cd.1994-2004
@@ -100,8 +97,7 @@ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
 {
        int log = 0;
 
-       ide_debug_log(IDE_DBG_SENSE, "Call %s, sense_key: 0x%x\n", __func__,
-                     sense->sense_key);
+       ide_debug_log(IDE_DBG_SENSE, "sense_key: 0x%x", sense->sense_key);
 
        if (!sense || !rq || (rq->cmd_flags & REQ_QUIET))
                return 0;
@@ -151,13 +147,12 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive,
        unsigned long bio_sectors;
        struct cdrom_info *info = drive->driver_data;
 
-       ide_debug_log(IDE_DBG_SENSE, "Call %s, error_code: 0x%x, "
-                       "sense_key: 0x%x\n", __func__, sense->error_code,
-                       sense->sense_key);
+       ide_debug_log(IDE_DBG_SENSE, "error_code: 0x%x, sense_key: 0x%x",
+                                    sense->error_code, sense->sense_key);
 
        if (failed_command)
-               ide_debug_log(IDE_DBG_SENSE, "%s: failed cmd: 0x%x\n",
-                               __func__, failed_command->cmd[0]);
+               ide_debug_log(IDE_DBG_SENSE, "failed cmd: 0x%x",
+                                            failed_command->cmd[0]);
 
        if (!cdrom_log_sense(drive, failed_command, sense))
                return;
@@ -215,9 +210,9 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
                                      struct request *failed_command)
 {
        struct cdrom_info *info         = drive->driver_data;
-       struct request *rq              = &info->request_sense_request;
+       struct request *rq              = &drive->request_sense_rq;
 
-       ide_debug_log(IDE_DBG_SENSE, "Call %s\n", __func__);
+       ide_debug_log(IDE_DBG_SENSE, "enter");
 
        if (sense == NULL)
                sense = &info->sense_data;
@@ -239,79 +234,42 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
        rq->buffer = (void *) failed_command;
 
        if (failed_command)
-               ide_debug_log(IDE_DBG_SENSE, "failed_cmd: 0x%x\n",
-                             failed_command->cmd[0]);
+               ide_debug_log(IDE_DBG_SENSE, "failed_cmd: 0x%x",
+                                            failed_command->cmd[0]);
 
        drive->hwif->rq = NULL;
 
        elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0);
 }
 
-static void cdrom_end_request(ide_drive_t *drive, int uptodate)
+static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq)
 {
-       struct request *rq = drive->hwif->rq;
-       int nsectors = rq->hard_cur_sectors;
-
-       ide_debug_log(IDE_DBG_FUNC, "Call %s, cmd: 0x%x, uptodate: 0x%x, "
-                     "nsectors: %d\n", __func__, rq->cmd[0], uptodate,
-                     nsectors);
-
-       if (blk_sense_request(rq) && uptodate) {
-               /*
-                * For REQ_TYPE_SENSE, "rq->buffer" points to the original
-                * failed request
-                */
-               struct request *failed = (struct request *) rq->buffer;
-               struct cdrom_info *info = drive->driver_data;
-               void *sense = &info->sense_data;
-
-               if (failed) {
-                       if (failed->sense) {
-                               sense = failed->sense;
-                               failed->sense_len = rq->sense_len;
-                       }
-                       cdrom_analyze_sense_data(drive, failed, sense);
-                       /*
-                        * now end the failed request
-                        */
-                       if (blk_fs_request(failed)) {
-                               if (ide_end_dequeued_request(drive, failed, 0,
-                                               failed->hard_nr_sectors))
-                                       BUG();
-                       } else {
-                               if (blk_end_request(failed, -EIO,
-                                                   failed->data_len))
-                                       BUG();
-                       }
-               } else
-                       cdrom_analyze_sense_data(drive, NULL, sense);
-       }
-
-       if (!rq->current_nr_sectors && blk_fs_request(rq))
-               uptodate = 1;
-       /* make sure it's fully ended */
-       if (blk_pc_request(rq))
-               nsectors = (rq->data_len + 511) >> 9;
-       if (!nsectors)
-               nsectors = 1;
-
-       ide_debug_log(IDE_DBG_FUNC, "Exit %s, uptodate: 0x%x, nsectors: %d\n",
-                     __func__, uptodate, nsectors);
+       /*
+        * For REQ_TYPE_SENSE, "rq->buffer" points to the original
+        * failed request
+        */
+       struct request *failed = (struct request *)rq->buffer;
+       struct cdrom_info *info = drive->driver_data;
+       void *sense = &info->sense_data;
 
-       ide_end_request(drive, uptodate, nsectors);
-}
+       if (failed) {
+               if (failed->sense) {
+                       sense = failed->sense;
+                       failed->sense_len = rq->sense_len;
+               }
+               cdrom_analyze_sense_data(drive, failed, sense);
 
-static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 st)
-{
-       if (st & 0x80)
-               return;
-       ide_dump_status(drive, msg, st);
+               if (ide_end_rq(drive, failed, -EIO, blk_rq_bytes(failed)))
+                       BUG();
+       } else
+               cdrom_analyze_sense_data(drive, NULL, sense);
 }
 
 /*
  * Returns:
  * 0: if the request should be continued.
- * 1: if the request was ended.
+ * 1: if the request will be going through error recovery.
+ * 2: if the request should be ended.
  */
 static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
 {
@@ -332,15 +290,10 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
        err = ide_read_error(drive);
        sense_key = err >> 4;
 
-       if (rq == NULL) {
-               printk(KERN_ERR PFX "%s: missing rq in %s\n",
-                               drive->name, __func__);
-               return 1;
-       }
-
-       ide_debug_log(IDE_DBG_RQ, "%s: stat: 0x%x, good_stat: 0x%x, "
-                     "rq->cmd[0]: 0x%x, rq->cmd_type: 0x%x, err: 0x%x\n",
-                     __func__, stat, good_stat, rq->cmd[0], rq->cmd_type, err);
+       ide_debug_log(IDE_DBG_RQ, "stat: 0x%x, good_stat: 0x%x, cmd[0]: 0x%x, "
+                                 "rq->cmd_type: 0x%x, err: 0x%x",
+                                 stat, good_stat, rq->cmd[0], rq->cmd_type,
+                                 err);
 
        if (blk_sense_request(rq)) {
                /*
@@ -349,10 +302,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                 * Just give up.
                 */
                rq->cmd_flags |= REQ_FAILED;
-               cdrom_end_request(drive, 0);
-               ide_error(drive, "request sense failure", stat);
-               return 1;
-
+               return 2;
        } else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) {
                /* All other functions, except for READ. */
 
@@ -455,21 +405,19 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                         * No point in retrying after an illegal request or data
                         * protect error.
                         */
-                       ide_dump_status_no_sense(drive, "command error", stat);
+                       ide_dump_status(drive, "command error", stat);
                        do_end_request = 1;
                } else if (sense_key == MEDIUM_ERROR) {
                        /*
                         * No point in re-trying a zillion times on a bad
                         * sector. If we got here the error is not correctable.
                         */
-                       ide_dump_status_no_sense(drive,
-                                                "media error (bad sector)",
-                                                stat);
+                       ide_dump_status(drive, "media error (bad sector)",
+                                       stat);
                        do_end_request = 1;
                } else if (sense_key == BLANK_CHECK) {
                        /* disk appears blank ?? */
-                       ide_dump_status_no_sense(drive, "media error (blank)",
-                                                stat);
+                       ide_dump_status(drive, "media error (blank)", stat);
                        do_end_request = 1;
                } else if ((err & ~ATA_ABORTED) != 0) {
                        /* go to the default handler for other errors */
@@ -494,14 +442,12 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                 */
                if (stat & ATA_ERR)
                        cdrom_queue_request_sense(drive, NULL, NULL);
+               return 1;
        } else {
                blk_dump_rq_flags(rq, PFX "bad rq");
-               cdrom_end_request(drive, 0);
+               return 2;
        }
 
-       /* retry, or handle the next request */
-       return 1;
-
 end_request:
        if (stat & ATA_ERR) {
                struct request_queue *q = drive->queue;
@@ -514,10 +460,9 @@ end_request:
                hwif->rq = NULL;
 
                cdrom_queue_request_sense(drive, rq->sense, rq);
+               return 1;
        } else
-               cdrom_end_request(drive, 0);
-
-       return 1;
+               return 2;
 }
 
 /*
@@ -530,8 +475,7 @@ static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq,
 {
        ide_hwif_t *hwif = drive->hwif;
 
-       ide_debug_log(IDE_DBG_FUNC, "Call %s, ireason: 0x%x, rw: 0x%x\n",
-                     __func__, ireason, rw);
+       ide_debug_log(IDE_DBG_FUNC, "ireason: 0x%x, rw: 0x%x", ireason, rw);
 
        /*
         * ireason == 0: the drive wants to receive data from us
@@ -562,115 +506,28 @@ static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq,
        if (rq->cmd_type == REQ_TYPE_ATA_PC)
                rq->cmd_flags |= REQ_FAILED;
 
-       cdrom_end_request(drive, 0);
        return -1;
 }
 
-/*
- * Assume that the drive will always provide data in multiples of at least
- * SECTOR_SIZE, as it gets hairy to keep track of the transfers otherwise.
- */
-static int ide_cd_check_transfer_size(ide_drive_t *drive, int len)
-{
-       ide_debug_log(IDE_DBG_FUNC, "Call %s, len: %d\n", __func__, len);
-
-       if ((len % SECTOR_SIZE) == 0)
-               return 0;
-
-       printk(KERN_ERR PFX "%s: %s: Bad transfer size %d\n", drive->name,
-                       __func__, len);
-
-       if (drive->atapi_flags & IDE_AFLAG_LIMIT_NFRAMES)
-               printk(KERN_ERR PFX "This drive is not supported by this "
-                               "version of the driver\n");
-       else {
-               printk(KERN_ERR PFX "Trying to limit transfer sizes\n");
-               drive->atapi_flags |= IDE_AFLAG_LIMIT_NFRAMES;
-       }
-
-       return 1;
-}
-
-static ide_startstop_t ide_cd_prepare_rw_request(ide_drive_t *drive,
-                                                struct request *rq)
+static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd)
 {
-       ide_debug_log(IDE_DBG_RQ, "Call %s: rq->cmd_flags: 0x%x\n", __func__,
-                     rq->cmd_flags);
-
-       if (rq_data_dir(rq) == READ) {
-               unsigned short sectors_per_frame =
-                       queue_hardsect_size(drive->queue) >> SECTOR_BITS;
-               int nskip = rq->sector & (sectors_per_frame - 1);
+       struct request *rq = cmd->rq;
 
-               /*
-                * If the requested sector doesn't start on a frame boundary,
-                * we must adjust the start of the transfer so that it does,
-                * and remember to skip the first few sectors.
-                *
-                * If the rq->current_nr_sectors field is larger than the size
-                * of the buffer, it will mean that we're to skip a number of
-                * sectors equal to the amount by which rq->current_nr_sectors
-                * is larger than the buffer size.
-                */
-               if (nskip > 0) {
-                       /* sanity check... */
-                       if (rq->current_nr_sectors !=
-                           bio_cur_sectors(rq->bio)) {
-                               printk(KERN_ERR PFX "%s: %s: buffer botch (%u)\n",
-                                               drive->name, __func__,
-                                               rq->current_nr_sectors);
-                               cdrom_end_request(drive, 0);
-                               return ide_stopped;
-                       }
-                       rq->current_nr_sectors += nskip;
-               }
-       }
-
-       /* set up the command */
-       rq->timeout = ATAPI_WAIT_PC;
-
-       return ide_started;
-}
-
-/*
- * Fix up a possibly partially-processed request so that we can start it over
- * entirely, or even put it back on the request queue.
- */
-static void ide_cd_restore_request(ide_drive_t *drive, struct request *rq)
-{
-
-       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
-
-       if (rq->buffer != bio_data(rq->bio)) {
-               sector_t n =
-                       (rq->buffer - (char *)bio_data(rq->bio)) / SECTOR_SIZE;
-
-               rq->buffer = bio_data(rq->bio);
-               rq->nr_sectors += n;
-               rq->sector -= n;
-       }
-       rq->current_nr_sectors = bio_cur_sectors(rq->bio);
-       rq->hard_cur_sectors = rq->current_nr_sectors;
-       rq->hard_nr_sectors = rq->nr_sectors;
-       rq->hard_sector = rq->sector;
-       rq->q->prep_rq_fn(rq->q, rq);
-}
-
-static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct request *rq)
-{
-       ide_debug_log(IDE_DBG_FUNC, "Call %s, rq->cmd[0]: 0x%x\n",
-                     __func__, rq->cmd[0]);
+       ide_debug_log(IDE_DBG_FUNC, "rq->cmd[0]: 0x%x", rq->cmd[0]);
 
        /*
         * Some of the trailing request sense fields are optional,
         * and some drives don't send them.  Sigh.
         */
        if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&
-           rq->data_len > 0 && rq->data_len <= 5)
-               while (rq->data_len > 0) {
-                       *(u8 *)rq->data++ = 0;
-                       --rq->data_len;
+           cmd->nleft > 0 && cmd->nleft <= 5) {
+               unsigned int ofs = cmd->nbytes - cmd->nleft;
+
+               while (cmd->nleft > 0) {
+                       *((u8 *)rq->data + ofs++) = 0;
+                       cmd->nleft--;
                }
+       }
 }
 
 int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
@@ -686,9 +543,9 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
        if (!sense)
                sense = &local_sense;
 
-       ide_debug_log(IDE_DBG_PC, "Call %s, cmd[0]: 0x%x, write: 0x%x, "
-                     "timeout: %d, cmd_flags: 0x%x\n", __func__, cmd[0], write,
-                     timeout, cmd_flags);
+       ide_debug_log(IDE_DBG_PC, "cmd[0]: 0x%x, write: 0x%x, timeout: %d, "
+                                 "cmd_flags: 0x%x",
+                                 cmd[0], write, timeout, cmd_flags);
 
        /* start of retry loop */
        do {
@@ -750,36 +607,40 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
        return (flags & REQ_FAILED) ? -EIO : 0;
 }
 
-/*
- * Called from blk_end_request_callback() after the data of the request is
- * completed and before the request itself is completed. By returning value '1',
- * blk_end_request_callback() returns immediately without completing it.
- */
-static int cdrom_newpc_intr_dummy_cb(struct request *rq)
+static void ide_cd_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd)
 {
-       return 1;
+       unsigned int nr_bytes = cmd->nbytes - cmd->nleft;
+
+       if (cmd->tf_flags & IDE_TFLAG_WRITE)
+               nr_bytes -= cmd->last_xfer_len;
+
+       if (nr_bytes > 0)
+               ide_complete_rq(drive, 0, nr_bytes);
 }
 
 static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
+       struct ide_cmd *cmd = &hwif->cmd;
        struct request *rq = hwif->rq;
-       xfer_func_t *xferfunc;
        ide_expiry_t *expiry = NULL;
        int dma_error = 0, dma, stat, thislen, uptodate = 0;
-       int write = (rq_data_dir(rq) == WRITE) ? 1 : 0;
+       int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc, nsectors;
+       int sense = blk_sense_request(rq);
        unsigned int timeout;
        u16 len;
        u8 ireason;
 
-       ide_debug_log(IDE_DBG_PC, "Call %s, rq->cmd[0]: 0x%x, write: 0x%x\n",
-                     __func__, rq->cmd[0], write);
+       ide_debug_log(IDE_DBG_PC, "cmd[0]: 0x%x, write: 0x%x",
+                                 rq->cmd[0], write);
 
        /* check for errors */
        dma = drive->dma;
        if (dma) {
                drive->dma = 0;
+               drive->waiting_for_dma = 0;
                dma_error = hwif->dma_ops->dma_end(drive);
+               ide_dma_unmap_sg(drive, cmd);
                if (dma_error) {
                        printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name,
                                        write ? "write" : "read");
@@ -787,31 +648,29 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                }
        }
 
-       if (cdrom_decode_status(drive, 0, &stat))
+       rc = cdrom_decode_status(drive, 0, &stat);
+       if (rc) {
+               if (rc == 2)
+                       goto out_end;
                return ide_stopped;
+       }
 
        /* using dma, transfer is complete now */
        if (dma) {
                if (dma_error)
                        return ide_error(drive, "dma error", stat);
-               if (blk_fs_request(rq)) {
-                       ide_end_request(drive, 1, rq->nr_sectors);
-                       return ide_stopped;
-               } else if (rq->cmd_type == REQ_TYPE_ATA_PC && !rq->bio) {
-                       ide_end_request(drive, 1, 1);
-                       return ide_stopped;
-               }
-               goto end_request;
+               uptodate = 1;
+               goto out_end;
        }
 
        ide_read_bcount_and_ireason(drive, &len, &ireason);
 
-       thislen = blk_fs_request(rq) ? len : rq->data_len;
+       thislen = blk_fs_request(rq) ? len : cmd->nleft;
        if (thislen > len)
                thislen = len;
 
-       ide_debug_log(IDE_DBG_PC, "%s: DRQ: stat: 0x%x, thislen: %d\n",
-                     __func__, stat, thislen);
+       ide_debug_log(IDE_DBG_PC, "DRQ: stat: 0x%x, thislen: %d",
+                                 stat, thislen);
 
        /* If DRQ is clear, the command has completed. */
        if ((stat & ATA_DRQ) == 0) {
@@ -821,135 +680,62 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                         * Otherwise, complete the command normally.
                         */
                        uptodate = 1;
-                       if (rq->current_nr_sectors > 0) {
+                       if (cmd->nleft > 0) {
                                printk(KERN_ERR PFX "%s: %s: data underrun "
-                                               "(%d blocks)\n",
-                                               drive->name, __func__,
-                                               rq->current_nr_sectors);
+                                       "(%u bytes)\n", drive->name, __func__,
+                                       cmd->nleft);
                                if (!write)
                                        rq->cmd_flags |= REQ_FAILED;
                                uptodate = 0;
                        }
-                       cdrom_end_request(drive, uptodate);
-                       return ide_stopped;
                } else if (!blk_pc_request(rq)) {
-                       ide_cd_request_sense_fixup(drive, rq);
+                       ide_cd_request_sense_fixup(drive, cmd);
                        /* complain if we still have data left to transfer */
-                       uptodate = rq->data_len ? 0 : 1;
+                       uptodate = cmd->nleft ? 0 : 1;
+                       if (uptodate == 0)
+                               rq->cmd_flags |= REQ_FAILED;
                }
-               goto end_request;
+               goto out_end;
        }
 
        /* check which way to transfer data */
-       if (ide_cd_check_ireason(drive, rq, len, ireason, write))
-               return ide_stopped;
+       rc = ide_cd_check_ireason(drive, rq, len, ireason, write);
+       if (rc)
+               goto out_end;
 
-       if (blk_fs_request(rq)) {
-               if (write == 0) {
-                       int nskip;
-
-                       if (ide_cd_check_transfer_size(drive, len)) {
-                               cdrom_end_request(drive, 0);
-                               return ide_stopped;
-                       }
+       cmd->last_xfer_len = 0;
 
-                       /*
-                        * First, figure out if we need to bit-bucket
-                        * any of the leading sectors.
-                        */
-                       nskip = min_t(int, rq->current_nr_sectors
-                                          - bio_cur_sectors(rq->bio),
-                                          thislen >> 9);
-                       if (nskip > 0) {
-                               ide_pad_transfer(drive, write, nskip << 9);
-                               rq->current_nr_sectors -= nskip;
-                               thislen -= (nskip << 9);
-                       }
-               }
-       }
-
-       if (ireason == 0) {
-               write = 1;
-               xferfunc = hwif->tp_ops->output_data;
-       } else {
-               write = 0;
-               xferfunc = hwif->tp_ops->input_data;
-       }
-
-       ide_debug_log(IDE_DBG_PC, "%s: data transfer, rq->cmd_type: 0x%x, "
-                     "ireason: 0x%x\n", __func__, rq->cmd_type, ireason);
+       ide_debug_log(IDE_DBG_PC, "data transfer, rq->cmd_type: 0x%x, "
+                                 "ireason: 0x%x",
+                                 rq->cmd_type, ireason);
 
        /* transfer data */
        while (thislen > 0) {
-               u8 *ptr = blk_fs_request(rq) ? NULL : rq->data;
-               int blen = rq->data_len;
-
-               /* bio backed? */
-               if (rq->bio) {
-                       if (blk_fs_request(rq)) {
-                               ptr = rq->buffer;
-                               blen = rq->current_nr_sectors << 9;
-                       } else {
-                               ptr = bio_data(rq->bio);
-                               blen = bio_iovec(rq->bio)->bv_len;
-                       }
-               }
+               int blen = min_t(int, thislen, cmd->nleft);
 
-               if (!ptr) {
-                       if (blk_fs_request(rq) && !write)
-                               /*
-                                * If the buffers are full, pipe the rest into
-                                * oblivion.
-                                */
-                               ide_pad_transfer(drive, 0, thislen);
-                       else {
-                               printk(KERN_ERR PFX "%s: confused, missing data\n",
-                                               drive->name);
-                               blk_dump_rq_flags(rq, rq_data_dir(rq)
-                                                 ? "cdrom_newpc_intr, write"
-                                                 : "cdrom_newpc_intr, read");
-                       }
+               if (cmd->nleft == 0)
                        break;
-               }
-
-               if (blen > thislen)
-                       blen = thislen;
 
-               xferfunc(drive, NULL, ptr, blen);
+               ide_pio_bytes(drive, cmd, write, blen);
+               cmd->last_xfer_len += blen;
 
                thislen -= blen;
                len -= blen;
 
-               if (blk_fs_request(rq)) {
-                       rq->buffer += blen;
-                       rq->nr_sectors -= (blen >> 9);
-                       rq->current_nr_sectors -= (blen >> 9);
-                       rq->sector += (blen >> 9);
-
-                       if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-                               cdrom_end_request(drive, 1);
-               } else {
-                       rq->data_len -= blen;
-
-                       /*
-                        * The request can't be completed until DRQ is cleared.
-                        * So complete the data, but don't complete the request
-                        * using the dummy function for the callback feature
-                        * of blk_end_request_callback().
-                        */
-                       if (rq->bio)
-                               blk_end_request_callback(rq, 0, blen,
-                                                cdrom_newpc_intr_dummy_cb);
-                       else
-                               rq->data += blen;
-               }
-               if (!write && blk_sense_request(rq))
+               if (sense && write == 0)
                        rq->sense_len += blen;
        }
 
        /* pad, if necessary */
-       if (!blk_fs_request(rq) && len > 0)
-               ide_pad_transfer(drive, write, len);
+       if (len > 0) {
+               if (blk_fs_request(rq) == 0 || write == 0)
+                       ide_pad_transfer(drive, write, len);
+               else {
+                       printk(KERN_ERR PFX "%s: confused, missing data\n",
+                               drive->name);
+                       blk_dump_rq_flags(rq, "cdrom_newpc_intr");
+               }
+       }
 
        if (blk_pc_request(rq)) {
                timeout = rq->timeout;
@@ -959,24 +745,54 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                        expiry = ide_cd_expiry;
        }
 
-       ide_set_handler(drive, cdrom_newpc_intr, timeout, expiry);
+       hwif->expiry = expiry;
+       ide_set_handler(drive, cdrom_newpc_intr, timeout);
        return ide_started;
 
-end_request:
-       if (blk_pc_request(rq)) {
+out_end:
+       if (blk_pc_request(rq) && rc == 0) {
                unsigned int dlen = rq->data_len;
 
-               if (dma)
-                       rq->data_len = 0;
+               rq->data_len = 0;
 
                if (blk_end_request(rq, 0, dlen))
                        BUG();
 
                hwif->rq = NULL;
        } else {
-               if (!uptodate)
-                       rq->cmd_flags |= REQ_FAILED;
-               cdrom_end_request(drive, uptodate);
+               if (sense && uptodate)
+                       ide_cd_complete_failed_rq(drive, rq);
+
+               if (blk_fs_request(rq)) {
+                       if (cmd->nleft == 0)
+                               uptodate = 1;
+               } else {
+                       if (uptodate <= 0 && rq->errors == 0)
+                               rq->errors = -EIO;
+               }
+
+               if (uptodate == 0)
+                       ide_cd_error_cmd(drive, cmd);
+
+               /* make sure it's fully ended */
+               if (blk_pc_request(rq))
+                       nsectors = (rq->data_len + 511) >> 9;
+               else
+                       nsectors = rq->hard_nr_sectors;
+
+               if (nsectors == 0)
+                       nsectors = 1;
+
+               if (blk_fs_request(rq) == 0) {
+                       rq->data_len -= (cmd->nbytes - cmd->nleft);
+                       if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE))
+                               rq->data_len += cmd->last_xfer_len;
+               }
+
+               ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9);
+
+               if (sense && rc == 2)
+                       ide_error(drive, "request sense failure", stat);
        }
        return ide_stopped;
 }
@@ -984,51 +800,48 @@ end_request:
 static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
 {
        struct cdrom_info *cd = drive->driver_data;
+       struct request_queue *q = drive->queue;
        int write = rq_data_dir(rq) == WRITE;
        unsigned short sectors_per_frame =
-               queue_hardsect_size(drive->queue) >> SECTOR_BITS;
+               queue_hardsect_size(q) >> SECTOR_BITS;
 
-       ide_debug_log(IDE_DBG_RQ, "Call %s, rq->cmd[0]: 0x%x, write: 0x%x, "
-                     "secs_per_frame: %u\n",
-                     __func__, rq->cmd[0], write, sectors_per_frame);
+       ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, "
+                                 "secs_per_frame: %u",
+                                 rq->cmd[0], rq->cmd_flags, sectors_per_frame);
 
        if (write) {
                /* disk has become write protected */
-               if (get_disk_ro(cd->disk)) {
-                       cdrom_end_request(drive, 0);
+               if (get_disk_ro(cd->disk))
                        return ide_stopped;
-               }
        } else {
                /*
                 * We may be retrying this request after an error.  Fix up any
                 * weirdness which might be present in the request packet.
                 */
-               ide_cd_restore_request(drive, rq);
+               q->prep_rq_fn(q, rq);
        }
 
-       /* use DMA, if possible / writes *must* be hardware frame aligned */
+       /* fs requests *must* be hardware frame aligned */
        if ((rq->nr_sectors & (sectors_per_frame - 1)) ||
-           (rq->sector & (sectors_per_frame - 1))) {
-               if (write) {
-                       cdrom_end_request(drive, 0);
-                       return ide_stopped;
-               }
-               drive->dma = 0;
-       } else
-               drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
+           (rq->sector & (sectors_per_frame - 1)))
+               return ide_stopped;
+
+       /* use DMA, if possible */
+       drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
 
        if (write)
                cd->devinfo.media_written = 1;
 
+       rq->timeout = ATAPI_WAIT_PC;
+
        return ide_started;
 }
 
 static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
 {
 
-       ide_debug_log(IDE_DBG_PC, "Call %s, rq->cmd[0]: 0x%x, "
-                     "rq->cmd_type: 0x%x\n", __func__, rq->cmd[0],
-                     rq->cmd_type);
+       ide_debug_log(IDE_DBG_PC, "rq->cmd[0]: 0x%x, rq->cmd_type: 0x%x",
+                                 rq->cmd[0], rq->cmd_type);
 
        if (blk_pc_request(rq))
                rq->cmd_flags |= REQ_QUIET;
@@ -1067,17 +880,18 @@ static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
 static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
                                        sector_t block)
 {
-       ide_debug_log(IDE_DBG_RQ, "Call %s, rq->cmd[0]: 0x%x, "
-                     "rq->cmd_type: 0x%x, block: %llu\n",
-                     __func__, rq->cmd[0], rq->cmd_type,
-                     (unsigned long long)block);
+       struct ide_cmd cmd;
+       int uptodate = 0, nsectors;
+
+       ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, block: %llu",
+                                 rq->cmd[0], (unsigned long long)block);
+
+       if (drive->debug_mask & IDE_DBG_RQ)
+               blk_dump_rq_flags(rq, "ide_cd_do_request");
 
        if (blk_fs_request(rq)) {
                if (cdrom_start_rw(drive, rq) == ide_stopped)
-                       return ide_stopped;
-
-               if (ide_cd_prepare_rw_request(drive, rq) == ide_stopped)
-                       return ide_stopped;
+                       goto out_end;
        } else if (blk_sense_request(rq) || blk_pc_request(rq) ||
                   rq->cmd_type == REQ_TYPE_ATA_PC) {
                if (!rq->timeout)
@@ -1086,15 +900,38 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
                cdrom_do_block_pc(drive, rq);
        } else if (blk_special_request(rq)) {
                /* right now this can only be a reset... */
-               cdrom_end_request(drive, 1);
-               return ide_stopped;
+               uptodate = 1;
+               goto out_end;
        } else {
                blk_dump_rq_flags(rq, DRV_NAME " bad flags");
-               cdrom_end_request(drive, 0);
-               return ide_stopped;
+               if (rq->errors == 0)
+                       rq->errors = -EIO;
+               goto out_end;
+       }
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       if (rq_data_dir(rq))
+               cmd.tf_flags |= IDE_TFLAG_WRITE;
+
+       cmd.rq = rq;
+
+       if (blk_fs_request(rq) || rq->data_len) {
+               ide_init_sg_cmd(&cmd, blk_fs_request(rq) ? (rq->nr_sectors << 9)
+                                                        : rq->data_len);
+               ide_map_sg(drive, &cmd);
        }
 
-       return ide_issue_pc(drive);
+       return ide_issue_pc(drive, &cmd);
+out_end:
+       nsectors = rq->hard_nr_sectors;
+
+       if (nsectors == 0)
+               nsectors = 1;
+
+       ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9);
+
+       return ide_stopped;
 }
 
 /*
@@ -1119,7 +956,7 @@ int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
        struct cdrom_device_info *cdi = &info->devinfo;
        unsigned char cmd[BLK_MAX_CDB];
 
-       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "enter");
 
        memset(cmd, 0, BLK_MAX_CDB);
        cmd[0] = GPCMD_TEST_UNIT_READY;
@@ -1147,7 +984,7 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
        unsigned len = sizeof(capbuf);
        u32 blocklen;
 
-       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "enter");
 
        memset(cmd, 0, BLK_MAX_CDB);
        cmd[0] = GPCMD_READ_CDVD_CAPACITY;
@@ -1179,8 +1016,8 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
        *capacity = 1 + be32_to_cpu(capbuf.lba);
        *sectors_per_frame = blocklen >> SECTOR_BITS;
 
-       ide_debug_log(IDE_DBG_PROBE, "%s: cap: %lu, sectors_per_frame: %lu\n",
-                     __func__, *capacity, *sectors_per_frame);
+       ide_debug_log(IDE_DBG_PROBE, "cap: %lu, sectors_per_frame: %lu",
+                                    *capacity, *sectors_per_frame);
 
        return 0;
 }
@@ -1191,7 +1028,7 @@ static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
 {
        unsigned char cmd[BLK_MAX_CDB];
 
-       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "enter");
 
        memset(cmd, 0, BLK_MAX_CDB);
 
@@ -1221,7 +1058,7 @@ int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense)
        long last_written;
        unsigned long sectors_per_frame = SECTORS_PER_FRAME;
 
-       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "enter");
 
        if (toc == NULL) {
                /* try to allocate space */
@@ -1383,7 +1220,7 @@ int ide_cdrom_get_capabilities(ide_drive_t *drive, u8 *buf)
        struct packet_command cgc;
        int stat, attempts = 3, size = ATAPI_CAPABILITIES_PAGE_SIZE;
 
-       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "enter");
 
        if ((drive->atapi_flags & IDE_AFLAG_FULL_CAPS_PAGE) == 0)
                size -= ATAPI_CAPABILITIES_PAGE_PAD_SIZE;
@@ -1403,7 +1240,7 @@ void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf)
        struct cdrom_info *cd = drive->driver_data;
        u16 curspeed, maxspeed;
 
-       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "enter");
 
        if (drive->atapi_flags & IDE_AFLAG_LE_SPEED_FIELDS) {
                curspeed = le16_to_cpup((__le16 *)&buf[8 + 14]);
@@ -1413,8 +1250,8 @@ void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf)
                maxspeed = be16_to_cpup((__be16 *)&buf[8 + 8]);
        }
 
-       ide_debug_log(IDE_DBG_PROBE, "%s: curspeed: %u, maxspeed: %u\n",
-                     __func__, curspeed, maxspeed);
+       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;
@@ -1448,7 +1285,7 @@ static int ide_cdrom_register(ide_drive_t *drive, int nslots)
        struct cdrom_info *info = drive->driver_data;
        struct cdrom_device_info *devinfo = &info->devinfo;
 
-       ide_debug_log(IDE_DBG_PROBE, "Call %s, nslots: %d\n", __func__, nslots);
+       ide_debug_log(IDE_DBG_PROBE, "nslots: %d", nslots);
 
        devinfo->ops = &ide_cdrom_dops;
        devinfo->speed = info->current_speed;
@@ -1471,9 +1308,8 @@ static int ide_cdrom_probe_capabilities(ide_drive_t *drive)
        mechtype_t mechtype;
        int nslots = 1;
 
-       ide_debug_log(IDE_DBG_PROBE, "Call %s, drive->media: 0x%x, "
-                     "drive->atapi_flags: 0x%lx\n", __func__, drive->media,
-                     drive->atapi_flags);
+       ide_debug_log(IDE_DBG_PROBE, "media: 0x%x, atapi_flags: 0x%lx",
+                                    drive->media, drive->atapi_flags);
 
        cdi->mask = (CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R |
                     CDC_DVD_RAM | CDC_SELECT_DISC | CDC_PLAY_AUDIO |
@@ -1687,9 +1523,6 @@ static const struct ide_proc_devset *ide_cd_proc_devsets(ide_drive_t *drive)
 #endif
 
 static const struct cd_list_entry ide_cd_quirks_list[] = {
-       /* Limit transfer size per interrupt. */
-       { "SAMSUNG CD-ROM SCR-2430", NULL,   IDE_AFLAG_LIMIT_NFRAMES         },
-       { "SAMSUNG CD-ROM SCR-2432", NULL,   IDE_AFLAG_LIMIT_NFRAMES         },
        /* SCR-3231 doesn't support the SET_CD_SPEED command. */
        { "SAMSUNG CD-ROM SCR-3231", NULL,   IDE_AFLAG_NO_SPEED_SELECT       },
        /* Old NEC260 (not R) was released before ATAPI 1.2 spec. */
@@ -1750,18 +1583,18 @@ static int ide_cdrom_setup(ide_drive_t *drive)
 {
        struct cdrom_info *cd = drive->driver_data;
        struct cdrom_device_info *cdi = &cd->devinfo;
+       struct request_queue *q = drive->queue;
        u16 *id = drive->id;
        char *fw_rev = (char *)&id[ATA_ID_FW_REV];
        int nslots;
 
-       ide_debug_log(IDE_DBG_PROBE, "Call %s\n", __func__);
+       ide_debug_log(IDE_DBG_PROBE, "enter");
 
-       blk_queue_prep_rq(drive->queue, ide_cdrom_prep_fn);
-       blk_queue_dma_alignment(drive->queue, 31);
-       blk_queue_update_dma_pad(drive->queue, 15);
-       drive->queue->unplug_delay = (1 * HZ) / 1000;
-       if (!drive->queue->unplug_delay)
-               drive->queue->unplug_delay = 1;
+       blk_queue_prep_rq(q, ide_cdrom_prep_fn);
+       blk_queue_dma_alignment(q, 31);
+       blk_queue_update_dma_pad(q, 15);
+
+       q->unplug_delay = max((1 * HZ) / 1000, 1);
 
        drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
        drive->atapi_flags = IDE_AFLAG_NO_EJECT | ide_cd_flags(id);
@@ -1779,8 +1612,7 @@ static int ide_cdrom_setup(ide_drive_t *drive)
 
        nslots = ide_cdrom_probe_capabilities(drive);
 
-       /* set correct block size */
-       blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE);
+       blk_queue_hardsect_size(q, CD_FRAMESIZE);
 
        if (ide_cdrom_register(drive, nslots)) {
                printk(KERN_ERR PFX "%s: %s failed to register device with the"
@@ -1797,7 +1629,7 @@ static void ide_cd_remove(ide_drive_t *drive)
 {
        struct cdrom_info *info = drive->driver_data;
 
-       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "enter");
 
        ide_proc_unregister_driver(drive, info->driver);
        device_del(&info->dev);
@@ -1815,7 +1647,7 @@ static void ide_cd_release(struct device *dev)
        ide_drive_t *drive = info->drive;
        struct gendisk *g = info->disk;
 
-       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "enter");
 
        kfree(info->toc);
        if (devinfo->handle == drive)
@@ -1839,7 +1671,6 @@ static struct ide_driver ide_cdrom_driver = {
        .remove                 = ide_cd_remove,
        .version                = IDECD_VERSION,
        .do_request             = ide_cd_do_request,
-       .end_request            = ide_end_request,
 #ifdef CONFIG_IDE_PROC_FS
        .proc_entries           = ide_cd_proc_entries,
        .proc_devsets           = ide_cd_proc_devsets,
@@ -1960,9 +1791,6 @@ static struct block_device_operations idecd_ops = {
 };
 
 /* module options */
-static char *ignore;
-module_param(ignore, charp, 0400);
-
 static unsigned long debug_mask;
 module_param(debug_mask, ulong, 0644);
 
@@ -1974,9 +1802,8 @@ static int ide_cd_probe(ide_drive_t *drive)
        struct gendisk *g;
        struct request_sense sense;
 
-       ide_debug_log(IDE_DBG_PROBE, "Call %s, drive->driver_req: %s, "
-                     "drive->media: 0x%x\n", __func__, drive->driver_req,
-                     drive->media);
+       ide_debug_log(IDE_DBG_PROBE, "driver_req: %s, media: 0x%x",
+                                    drive->driver_req, drive->media);
 
        if (!strstr("ide-cdrom", drive->driver_req))
                goto failed;
@@ -1984,15 +1811,6 @@ static int ide_cd_probe(ide_drive_t *drive)
        if (drive->media != ide_cdrom && drive->media != ide_optical)
                goto failed;
 
-       /* skip drives that we were told to ignore */
-       if (ignore != NULL) {
-               if (strstr(ignore, drive->name)) {
-                       printk(KERN_INFO PFX "ignoring drive %s\n",
-                                        drive->name);
-                       goto failed;
-               }
-       }
-
        drive->debug_mask = debug_mask;
        drive->irq_handler = cdrom_newpc_intr;
 
index c878bfcf111698430e8f870c0ccbc4e12b6e71ca..1d97101099ce20bab8e0b319f6da278a09bd9afa 100644 (file)
@@ -11,7 +11,7 @@
 #define IDECD_DEBUG_LOG                0
 
 #if IDECD_DEBUG_LOG
-#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, args)
+#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, ## args)
 #else
 #define ide_debug_log(lvl, fmt, args...) do {} while (0)
 #endif
@@ -91,8 +91,6 @@ struct cdrom_info {
           on this device. */
        struct request_sense sense_data;
 
-       struct request request_sense_request;
-
        u8 max_speed;           /* Max speed of the drive. */
        u8 current_speed;       /* Current speed of the drive. */
 
index f50210fe558f1cd7ffff023385508be18029d4a1..9e47f3529d5555685bb829b1e92b7b621c15e624 100644 (file)
@@ -154,6 +154,7 @@ static const struct ide_port_ops idecs_port_ops = {
 static const struct ide_port_info idecs_port_info = {
        .port_ops               = &idecs_port_ops,
        .host_flags             = IDE_HFLAG_NO_DMA,
+       .irq_flags              = IRQF_SHARED,
 };
 
 static struct ide_host *idecs_register(unsigned long io, unsigned long ctl,
index 7c3953414d4703d2cfa502d2ed2c170a71bf0b4c..5bf958e5b1d5fabe5019266448fe623065e69a82 100644 (file)
@@ -183,8 +183,6 @@ ide_startstop_t ide_do_devset(ide_drive_t *drive, struct request *rq)
        err = setfunc(drive, *(int *)&rq->cmd[1]);
        if (err)
                rq->errors = err;
-       else
-               err = 1;
-       ide_end_request(drive, err, 0);
+       ide_complete_rq(drive, err, ide_rq_bytes(rq));
        return ide_stopped;
 }
index 806760d24cefd263e4ab8202a3659053be40f3f9..c998cf8e971a3f7bfbf70e7e42f40091349619eb 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/mutex.h>
 #include <linux/leds.h>
 #include <linux/ide.h>
-#include <linux/hdreg.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -53,33 +52,26 @@ static const u8 ide_rw_cmds[] = {
        ATA_CMD_WRITE_EXT,
 };
 
-static const u8 ide_data_phases[] = {
-       TASKFILE_MULTI_IN,
-       TASKFILE_MULTI_OUT,
-       TASKFILE_IN,
-       TASKFILE_OUT,
-       TASKFILE_IN_DMA,
-       TASKFILE_OUT_DMA,
-};
-
-static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma)
+static void ide_tf_set_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 dma)
 {
        u8 index, lba48, write;
 
-       lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0;
-       write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0;
+       lba48 = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0;
+       write = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0;
 
-       if (dma)
+       if (dma) {
+               cmd->protocol = ATA_PROT_DMA;
                index = 8;
-       else
-               index = drive->mult_count ? 0 : 4;
-
-       task->tf.command = ide_rw_cmds[index + lba48 + write];
-
-       if (dma)
-               index = 8; /* fixup index */
+       } else {
+               cmd->protocol = ATA_PROT_PIO;
+               if (drive->mult_count) {
+                       cmd->tf_flags |= IDE_TFLAG_MULTI_PIO;
+                       index = 0;
+               } else
+                       index = 4;
+       }
 
-       task->data_phase = ide_data_phases[index / 2 + write];
+       cmd->tf.command = ide_rw_cmds[index + lba48 + write];
 }
 
 /*
@@ -93,8 +85,8 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
        u16 nsectors            = (u16)rq->nr_sectors;
        u8 lba48                = !!(drive->dev_flags & IDE_DFLAG_LBA48);
        u8 dma                  = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
-       ide_task_t              task;
-       struct ide_taskfile     *tf = &task.tf;
+       struct ide_cmd          cmd;
+       struct ide_taskfile     *tf = &cmd.tf;
        ide_startstop_t         rc;
 
        if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) {
@@ -104,13 +96,8 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
                        lba48 = 0;
        }
 
-       if (!dma) {
-               ide_init_sg_cmd(drive, rq);
-               ide_map_sg(drive, rq);
-       }
-
-       memset(&task, 0, sizeof(task));
-       task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 
        if (drive->dev_flags & IDE_DFLAG_LBA) {
                if (lba48) {
@@ -129,7 +116,7 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
                        tf->lbam   = (u8)(block >>  8);
                        tf->lbah   = (u8)(block >> 16);
 
-                       task.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
+                       cmd.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
                } else {
                        tf->nsect  = nsectors & 0xff;
                        tf->lbal   = block;
@@ -156,23 +143,27 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
                tf->device = head;
        }
 
+       cmd.tf_flags |= IDE_TFLAG_FS;
+
        if (rq_data_dir(rq))
-               task.tf_flags |= IDE_TFLAG_WRITE;
+               cmd.tf_flags |= IDE_TFLAG_WRITE;
+
+       ide_tf_set_cmd(drive, &cmd, dma);
+       cmd.rq = rq;
 
-       ide_tf_set_cmd(drive, &task, dma);
-       if (!dma)
-               hwif->data_phase = task.data_phase;
-       task.rq = rq;
+       if (dma == 0) {
+               ide_init_sg_cmd(&cmd, nsectors << 9);
+               ide_map_sg(drive, &cmd);
+       }
 
-       rc = do_rw_taskfile(drive, &task);
+       rc = do_rw_taskfile(drive, &cmd);
 
        if (rc == ide_stopped && dma) {
                /* fallback to PIO */
-               task.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK;
-               ide_tf_set_cmd(drive, &task, 0);
-               hwif->data_phase = task.data_phase;
-               ide_init_sg_cmd(drive, rq);
-               rc = do_rw_taskfile(drive, &task);
+               cmd.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK;
+               ide_tf_set_cmd(drive, &cmd, 0);
+               ide_init_sg_cmd(&cmd, nsectors << 9);
+               rc = do_rw_taskfile(drive, &cmd);
        }
 
        return rc;
@@ -193,7 +184,9 @@ static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
 
        if (!blk_fs_request(rq)) {
                blk_dump_rq_flags(rq, "ide_do_rw_disk - bad command");
-               ide_end_request(drive, 0, 0);
+               if (rq->errors == 0)
+                       rq->errors = -EIO;
+               ide_complete_rq(drive, -EIO, ide_rq_bytes(rq));
                return ide_stopped;
        }
 
@@ -216,25 +209,25 @@ static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
  */
 static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48)
 {
-       ide_task_t args;
-       struct ide_taskfile *tf = &args.tf;
+       struct ide_cmd cmd;
+       struct ide_taskfile *tf = &cmd.tf;
        u64 addr = 0;
 
-       /* Create IDE/ATA command request structure */
-       memset(&args, 0, sizeof(ide_task_t));
+       memset(&cmd, 0, sizeof(cmd));
        if (lba48)
                tf->command = ATA_CMD_READ_NATIVE_MAX_EXT;
        else
                tf->command = ATA_CMD_READ_NATIVE_MAX;
        tf->device  = ATA_LBA;
-       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+       cmd.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
        if (lba48)
-               args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
-       /* submit command request */
-       ide_no_data_taskfile(drive, &args);
+               cmd.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
+
+       ide_no_data_taskfile(drive, &cmd);
 
        /* if OK, compute maximum address value */
-       if ((tf->status & 0x01) == 0)
+       if (!(tf->status & ATA_ERR))
                addr = ide_get_lba_addr(tf, lba48) + 1;
 
        return addr;
@@ -246,13 +239,13 @@ static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48)
  */
 static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
 {
-       ide_task_t args;
-       struct ide_taskfile *tf = &args.tf;
+       struct ide_cmd cmd;
+       struct ide_taskfile *tf = &cmd.tf;
        u64 addr_set = 0;
 
        addr_req--;
-       /* Create IDE/ATA command request structure */
-       memset(&args, 0, sizeof(ide_task_t));
+
+       memset(&cmd, 0, sizeof(cmd));
        tf->lbal     = (addr_req >>  0) & 0xff;
        tf->lbam     = (addr_req >>= 8) & 0xff;
        tf->lbah     = (addr_req >>= 8) & 0xff;
@@ -266,13 +259,15 @@ static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
                tf->command  = ATA_CMD_SET_MAX;
        }
        tf->device |= ATA_LBA;
-       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+       cmd.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
        if (lba48)
-               args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
-       /* submit command request */
-       ide_no_data_taskfile(drive, &args);
+               cmd.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
+
+       ide_no_data_taskfile(drive, &cmd);
+
        /* if OK, compute maximum address value */
-       if ((tf->status & 0x01) == 0)
+       if (!(tf->status & ATA_ERR))
                addr_set = ide_get_lba_addr(tf, lba48) + 1;
 
        return addr_set;
@@ -389,24 +384,24 @@ static int ide_disk_get_capacity(ide_drive_t *drive)
 static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
 {
        ide_drive_t *drive = q->queuedata;
-       ide_task_t *task = kmalloc(sizeof(*task), GFP_ATOMIC);
+       struct ide_cmd *cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
 
        /* FIXME: map struct ide_taskfile on rq->cmd[] */
-       BUG_ON(task == NULL);
+       BUG_ON(cmd == NULL);
 
-       memset(task, 0, sizeof(*task));
+       memset(cmd, 0, sizeof(*cmd));
        if (ata_id_flush_ext_enabled(drive->id) &&
            (drive->capacity64 >= (1UL << 28)))
-               task->tf.command = ATA_CMD_FLUSH_EXT;
+               cmd->tf.command = ATA_CMD_FLUSH_EXT;
        else
-               task->tf.command = ATA_CMD_FLUSH;
-       task->tf_flags   = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE |
-                          IDE_TFLAG_DYN;
-       task->data_phase = TASKFILE_NO_DATA;
+               cmd->tf.command = ATA_CMD_FLUSH;
+       cmd->tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE |
+                       IDE_TFLAG_DYN;
+       cmd->protocol = ATA_PROT_NODATA;
 
        rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
        rq->cmd_flags |= REQ_SOFTBARRIER;
-       rq->special = task;
+       rq->special = cmd;
 }
 
 ide_devset_get(multcount, mult_count);
@@ -456,15 +451,15 @@ static int set_nowerr(ide_drive_t *drive, int arg)
 
 static int ide_do_setfeature(ide_drive_t *drive, u8 feature, u8 nsect)
 {
-       ide_task_t task;
+       struct ide_cmd cmd;
 
-       memset(&task, 0, sizeof(task));
-       task.tf.feature = feature;
-       task.tf.nsect   = nsect;
-       task.tf.command = ATA_CMD_SET_FEATURES;
-       task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.tf.feature = feature;
+       cmd.tf.nsect   = nsect;
+       cmd.tf.command = ATA_CMD_SET_FEATURES;
+       cmd.tf_flags   = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 
-       return ide_no_data_taskfile(drive, &task);
+       return ide_no_data_taskfile(drive, &cmd);
 }
 
 static void update_ordered(ide_drive_t *drive)
@@ -531,15 +526,16 @@ static int set_wcache(ide_drive_t *drive, int arg)
 
 static int do_idedisk_flushcache(ide_drive_t *drive)
 {
-       ide_task_t args;
+       struct ide_cmd cmd;
 
-       memset(&args, 0, sizeof(ide_task_t));
+       memset(&cmd, 0, sizeof(cmd));
        if (ata_id_flush_ext_enabled(drive->id))
-               args.tf.command = ATA_CMD_FLUSH_EXT;
+               cmd.tf.command = ATA_CMD_FLUSH_EXT;
        else
-               args.tf.command = ATA_CMD_FLUSH;
-       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-       return ide_no_data_taskfile(drive, &args);
+               cmd.tf.command = ATA_CMD_FLUSH;
+       cmd.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+       return ide_no_data_taskfile(drive, &cmd);
 }
 
 ide_devset_get(acoustic, acoustic);
@@ -711,17 +707,17 @@ static int ide_disk_init_media(ide_drive_t *drive, struct gendisk *disk)
 static int ide_disk_set_doorlock(ide_drive_t *drive, struct gendisk *disk,
                                 int on)
 {
-       ide_task_t task;
+       struct ide_cmd cmd;
        int ret;
 
        if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0)
                return 0;
 
-       memset(&task, 0, sizeof(task));
-       task.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
-       task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
+       cmd.tf_flags   = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 
-       ret = ide_no_data_taskfile(drive, &task);
+       ret = ide_no_data_taskfile(drive, &cmd);
 
        if (ret)
                drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
@@ -737,6 +733,5 @@ const struct ide_disk_ops ide_ata_disk_ops = {
        .init_media     = ide_disk_init_media,
        .set_doorlock   = ide_disk_set_doorlock,
        .do_request     = ide_do_rw_disk,
-       .end_request    = ide_end_request,
        .ioctl          = ide_disk_ioctl,
 };
index 1f86dcbd2b1c83c00eb68ccb6f8ca62164445c63..eaea3bef2073253977282245eb78d440534fa9bf 100644 (file)
@@ -1,38 +1,38 @@
 #include <linux/kernel.h>
 #include <linux/ide.h>
-#include <linux/hdreg.h>
 
 #include "ide-disk.h"
 
 static int smart_enable(ide_drive_t *drive)
 {
-       ide_task_t args;
-       struct ide_taskfile *tf = &args.tf;
+       struct ide_cmd cmd;
+       struct ide_taskfile *tf = &cmd.tf;
 
-       memset(&args, 0, sizeof(ide_task_t));
+       memset(&cmd, 0, sizeof(cmd));
        tf->feature = ATA_SMART_ENABLE;
        tf->lbam    = ATA_SMART_LBAM_PASS;
        tf->lbah    = ATA_SMART_LBAH_PASS;
        tf->command = ATA_CMD_SMART;
-       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-       return ide_no_data_taskfile(drive, &args);
+       cmd.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+       return ide_no_data_taskfile(drive, &cmd);
 }
 
 static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
 {
-       ide_task_t args;
-       struct ide_taskfile *tf = &args.tf;
+       struct ide_cmd cmd;
+       struct ide_taskfile *tf = &cmd.tf;
 
-       memset(&args, 0, sizeof(ide_task_t));
+       memset(&cmd, 0, sizeof(cmd));
        tf->feature = sub_cmd;
        tf->nsect   = 0x01;
        tf->lbam    = ATA_SMART_LBAM_PASS;
        tf->lbah    = ATA_SMART_LBAH_PASS;
        tf->command = ATA_CMD_SMART;
-       args.tf_flags   = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-       args.data_phase = TASKFILE_IN;
-       (void) smart_enable(drive);
-       return ide_raw_taskfile(drive, &args, buf, 1);
+       cmd.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       cmd.protocol = ATA_PROT_PIO;
+
+       return ide_raw_taskfile(drive, &cmd, buf, 1);
 }
 
 static int proc_idedisk_read_cache
@@ -67,6 +67,8 @@ static int proc_idedisk_read_smart(char *page, char **start, off_t off,
        ide_drive_t     *drive = (ide_drive_t *)data;
        int             len = 0, i = 0;
 
+       (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;
index 123d393658afac004bc541532ca02193b6478ee4..16fc46edc32df6390ef7e52d83a06925a25175df 100644 (file)
@@ -38,10 +38,9 @@ int config_drive_for_dma(ide_drive_t *drive)
         * Enable DMA on any drive that has mode2 DMA
         * (multi or single) enabled
         */
-       if (id[ATA_ID_FIELD_VALID] & 2) /* regular DMA */
-               if ((id[ATA_ID_MWDMA_MODES] & 0x404) == 0x404 ||
-                   (id[ATA_ID_SWDMA_MODES] & 0x404) == 0x404)
-                       return 1;
+       if ((id[ATA_ID_MWDMA_MODES] & 0x404) == 0x404 ||
+           (id[ATA_ID_SWDMA_MODES] & 0x404) == 0x404)
+               return 1;
 
        /* Consult the list of known "good" drives */
        if (ide_dma_good_drive(drive))
@@ -111,7 +110,7 @@ EXPORT_SYMBOL_GPL(ide_dma_host_set);
  *     May also be invoked from trm290.c
  */
 
-int ide_build_dmatable(ide_drive_t *drive, struct request *rq)
+int ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        __le32 *table = (__le32 *)hwif->dmatable_cpu;
@@ -120,11 +119,7 @@ int ide_build_dmatable(ide_drive_t *drive, struct request *rq)
        struct scatterlist *sg;
        u8 is_trm290 = !!(hwif->host_flags & IDE_HFLAG_TRM290);
 
-       hwif->sg_nents = ide_build_sglist(drive, rq);
-       if (hwif->sg_nents == 0)
-               return 0;
-
-       for_each_sg(hwif->sg_table, sg, hwif->sg_nents, i) {
+       for_each_sg(hwif->sg_table, sg, cmd->sg_nents, i) {
                u32 cur_addr, cur_len, xcount, bcount;
 
                cur_addr = sg_dma_address(sg);
@@ -170,8 +165,6 @@ use_pio_instead:
        printk(KERN_ERR "%s: %s\n", drive->name,
                count ? "DMA table too small" : "empty DMA table?");
 
-       ide_destroy_dmatable(drive);
-
        return 0; /* revert to PIO for this request */
 }
 EXPORT_SYMBOL_GPL(ide_build_dmatable);
@@ -179,6 +172,7 @@ EXPORT_SYMBOL_GPL(ide_build_dmatable);
 /**
  *     ide_dma_setup   -       begin a DMA phase
  *     @drive: target device
+ *     @cmd: command
  *
  *     Build an IDE DMA PRD (IDE speak for scatter gather table)
  *     and then set up the DMA transfer registers for a device
@@ -189,17 +183,16 @@ EXPORT_SYMBOL_GPL(ide_build_dmatable);
  *     is returned.
  */
 
-int ide_dma_setup(ide_drive_t *drive)
+int ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
-       struct request *rq = hwif->rq;
-       unsigned int reading = rq_data_dir(rq) ? 0 : ATA_DMA_WR;
        u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+       u8 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR;
        u8 dma_stat;
 
        /* fall back to pio! */
-       if (!ide_build_dmatable(drive, rq)) {
-               ide_map_sg(drive, rq);
+       if (ide_build_dmatable(drive, cmd) == 0) {
+               ide_map_sg(drive, cmd);
                return 1;
        }
 
@@ -212,9 +205,9 @@ int ide_dma_setup(ide_drive_t *drive)
 
        /* specify r/w */
        if (mmio)
-               writeb(reading, (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
+               writeb(rw, (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
        else
-               outb(reading, hwif->dma_base + ATA_DMA_CMD);
+               outb(rw, hwif->dma_base + ATA_DMA_CMD);
 
        /* read DMA status for INTR & ERROR flags */
        dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
@@ -222,13 +215,12 @@ int ide_dma_setup(ide_drive_t *drive)
        /* clear INTR & ERROR flags */
        ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR);
 
-       drive->waiting_for_dma = 1;
        return 0;
 }
 EXPORT_SYMBOL_GPL(ide_dma_setup);
 
 /**
- *     dma_timer_expiry        -       handle a DMA timeout
+ *     ide_dma_sff_timer_expiry        -       handle a DMA timeout
  *     @drive: Drive that timed out
  *
  *     An IDE DMA transfer timed out. In the event of an error we ask
@@ -241,7 +233,7 @@ EXPORT_SYMBOL_GPL(ide_dma_setup);
  *     This can occur if an interrupt is lost or due to hang or bugs.
  */
 
-static int dma_timer_expiry(ide_drive_t *drive)
+int ide_dma_sff_timer_expiry(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
@@ -265,14 +257,7 @@ static int dma_timer_expiry(ide_drive_t *drive)
 
        return 0;       /* Status is unknown -- reset the bus */
 }
-
-void ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
-{
-       /* issue cmd to drive */
-       ide_execute_command(drive, command, &ide_dma_intr, 2 * WAIT_CMD,
-                           dma_timer_expiry);
-}
-EXPORT_SYMBOL_GPL(ide_dma_exec_cmd);
+EXPORT_SYMBOL_GPL(ide_dma_sff_timer_expiry);
 
 void ide_dma_start(ide_drive_t *drive)
 {
@@ -303,8 +288,6 @@ int ide_dma_end(ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        u8 dma_stat = 0, dma_cmd = 0, mask;
 
-       drive->waiting_for_dma = 0;
-
        /* stop DMA */
        if (hwif->host_flags & IDE_HFLAG_MMIO) {
                dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
@@ -321,8 +304,6 @@ int ide_dma_end(ide_drive_t *drive)
        /* clear INTR & ERROR bits */
        ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR);
 
-       /* purge DMA mappings */
-       ide_destroy_dmatable(drive);
        wmb();
 
        /* verify good DMA status */
@@ -346,12 +327,11 @@ EXPORT_SYMBOL_GPL(ide_dma_test_irq);
 const struct ide_dma_ops sff_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
        .dma_setup              = ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = ide_dma_start,
        .dma_end                = ide_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
-       .dma_timeout            = ide_dma_timeout,
        .dma_lost_irq           = ide_dma_lost_irq,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 EXPORT_SYMBOL_GPL(sff_dma_ops);
index a878f4734f8129139efc995bd8c65337f6dad0fc..a0b8cab1d9a682249200fce35bc5ea5c8223079f 100644 (file)
@@ -89,16 +89,21 @@ static const struct drive_list_entry drive_blacklist[] = {
 ide_startstop_t ide_dma_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
+       struct ide_cmd *cmd = &hwif->cmd;
        u8 stat = 0, dma_stat = 0;
 
+       drive->waiting_for_dma = 0;
        dma_stat = hwif->dma_ops->dma_end(drive);
+       ide_dma_unmap_sg(drive, cmd);
        stat = hwif->tp_ops->read_status(hwif);
 
        if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat | ATA_DRQ)) {
                if (!dma_stat) {
-                       struct request *rq = hwif->rq;
-
-                       task_end_request(drive, rq, stat);
+                       if ((cmd->tf_flags & IDE_TFLAG_FS) == 0)
+                               ide_finish_cmd(drive, cmd, stat);
+                       else
+                               ide_complete_rq(drive, 0,
+                                               cmd->rq->nr_sectors << 9);
                        return ide_stopped;
                }
                printk(KERN_ERR "%s: %s: bad DMA status (0x%02x)\n",
@@ -106,7 +111,6 @@ ide_startstop_t ide_dma_intr(ide_drive_t *drive)
        }
        return ide_error(drive, "dma_intr", stat);
 }
-EXPORT_SYMBOL_GPL(ide_dma_intr);
 
 int ide_dma_good_drive(ide_drive_t *drive)
 {
@@ -114,9 +118,9 @@ int ide_dma_good_drive(ide_drive_t *drive)
 }
 
 /**
- *     ide_build_sglist        -       map IDE scatter gather for DMA I/O
- *     @drive: the drive to build the DMA table for
- *     @rq: the request holding the sg list
+ *     ide_dma_map_sg  -       map IDE scatter gather for DMA I/O
+ *     @drive: the drive to map the DMA table for
+ *     @cmd: command
  *
  *     Perform the DMA mapping magic necessary to access the source or
  *     target buffers of a request via DMA.  The lower layers of the
@@ -124,31 +128,28 @@ int ide_dma_good_drive(ide_drive_t *drive)
  *     operate in a portable fashion.
  */
 
-int ide_build_sglist(ide_drive_t *drive, struct request *rq)
+static int ide_dma_map_sg(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct scatterlist *sg = hwif->sg_table;
        int i;
 
-       ide_map_sg(drive, rq);
-
-       if (rq_data_dir(rq) == READ)
-               hwif->sg_dma_direction = DMA_FROM_DEVICE;
+       if (cmd->tf_flags & IDE_TFLAG_WRITE)
+               cmd->sg_dma_direction = DMA_TO_DEVICE;
        else
-               hwif->sg_dma_direction = DMA_TO_DEVICE;
+               cmd->sg_dma_direction = DMA_FROM_DEVICE;
 
-       i = dma_map_sg(hwif->dev, sg, hwif->sg_nents, hwif->sg_dma_direction);
+       i = dma_map_sg(hwif->dev, sg, cmd->sg_nents, cmd->sg_dma_direction);
        if (i) {
-               hwif->orig_sg_nents = hwif->sg_nents;
-               hwif->sg_nents = i;
+               cmd->orig_sg_nents = cmd->sg_nents;
+               cmd->sg_nents = i;
        }
 
        return i;
 }
-EXPORT_SYMBOL_GPL(ide_build_sglist);
 
 /**
- *     ide_destroy_dmatable    -       clean up DMA mapping
+ *     ide_dma_unmap_sg        -       clean up DMA mapping
  *     @drive: The drive to unmap
  *
  *     Teardown mappings after DMA has completed. This must be called
@@ -158,14 +159,14 @@ EXPORT_SYMBOL_GPL(ide_build_sglist);
  *     time.
  */
 
-void ide_destroy_dmatable(ide_drive_t *drive)
+void ide_dma_unmap_sg(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
 
-       dma_unmap_sg(hwif->dev, hwif->sg_table, hwif->orig_sg_nents,
-                    hwif->sg_dma_direction);
+       dma_unmap_sg(hwif->dev, hwif->sg_table, cmd->orig_sg_nents,
+                    cmd->sg_dma_direction);
 }
-EXPORT_SYMBOL_GPL(ide_destroy_dmatable);
+EXPORT_SYMBOL_GPL(ide_dma_unmap_sg);
 
 /**
  *     ide_dma_off_quietly     -       Generic DMA kill
@@ -244,12 +245,11 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
        case XFER_UDMA_0:
                if ((id[ATA_ID_FIELD_VALID] & 4) == 0)
                        break;
-
+               mask = id[ATA_ID_UDMA_MODES];
                if (port_ops && port_ops->udma_filter)
-                       mask = port_ops->udma_filter(drive);
+                       mask &= port_ops->udma_filter(drive);
                else
-                       mask = hwif->ultra_mask;
-               mask &= id[ATA_ID_UDMA_MODES];
+                       mask &= hwif->ultra_mask;
 
                /*
                 * avoid false cable warning from eighty_ninty_three()
@@ -260,18 +260,23 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
                }
                break;
        case XFER_MW_DMA_0:
-               if ((id[ATA_ID_FIELD_VALID] & 2) == 0)
-                       break;
+               mask = id[ATA_ID_MWDMA_MODES];
+
+               /* Also look for the CF specific MWDMA modes... */
+               if (ata_id_is_cfa(id) && (id[ATA_ID_CFA_MODES] & 0x38)) {
+                       u8 mode = ((id[ATA_ID_CFA_MODES] & 0x38) >> 3) - 1;
+
+                       mask |= ((2 << mode) - 1) << 3;
+               }
+
                if (port_ops && port_ops->mdma_filter)
-                       mask = port_ops->mdma_filter(drive);
+                       mask &= port_ops->mdma_filter(drive);
                else
-                       mask = hwif->mwdma_mask;
-               mask &= id[ATA_ID_MWDMA_MODES];
+                       mask &= hwif->mwdma_mask;
                break;
        case XFER_SW_DMA_0:
-               if (id[ATA_ID_FIELD_VALID] & 2) {
-                       mask = id[ATA_ID_SWDMA_MODES] & hwif->swdma_mask;
-               } else if (id[ATA_ID_OLD_DMA_MODES] >> 8) {
+               mask = id[ATA_ID_SWDMA_MODES];
+               if (!(mask & ATA_SWDMA2) && (id[ATA_ID_OLD_DMA_MODES] >> 8)) {
                        u8 mode = id[ATA_ID_OLD_DMA_MODES] >> 8;
 
                        /*
@@ -279,8 +284,9 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
                         * (the maximum allowed mode is XFER_SW_DMA_2)
                         */
                        if (mode <= 2)
-                               mask = ((2 << mode) - 1) & hwif->swdma_mask;
+                               mask = (2 << mode) - 1;
                }
+               mask &= hwif->swdma_mask;
                break;
        default:
                BUG();
@@ -397,11 +403,10 @@ int ide_id_dma_bug(ide_drive_t *drive)
                if ((id[ATA_ID_UDMA_MODES] >> 8) &&
                    (id[ATA_ID_MWDMA_MODES] >> 8))
                        goto err_out;
-       } else if (id[ATA_ID_FIELD_VALID] & 2) {
-               if ((id[ATA_ID_MWDMA_MODES] >> 8) &&
-                   (id[ATA_ID_SWDMA_MODES] >> 8))
-                       goto err_out;
-       }
+       } else if ((id[ATA_ID_MWDMA_MODES] >> 8) &&
+                  (id[ATA_ID_SWDMA_MODES] >> 8))
+               goto err_out;
+
        return 0;
 err_out:
        printk(KERN_ERR "%s: bad DMA info in identify block\n", drive->name);
@@ -455,21 +460,6 @@ void ide_dma_lost_irq(ide_drive_t *drive)
 }
 EXPORT_SYMBOL_GPL(ide_dma_lost_irq);
 
-void ide_dma_timeout(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-
-       printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
-
-       if (hwif->dma_ops->dma_test_irq(drive))
-               return;
-
-       ide_dump_status(drive, "DMA timeout", hwif->tp_ops->read_status(hwif));
-
-       hwif->dma_ops->dma_end(drive);
-}
-EXPORT_SYMBOL_GPL(ide_dma_timeout);
-
 /*
  * un-busy the port etc, and clear any pending DMA status. we want to
  * retry the current request in pio mode instead of risking tossing it
@@ -478,6 +468,8 @@ EXPORT_SYMBOL_GPL(ide_dma_timeout);
 ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
 {
        ide_hwif_t *hwif = drive->hwif;
+       const struct ide_dma_ops *dma_ops = hwif->dma_ops;
+       struct ide_cmd *cmd = &hwif->cmd;
        struct request *rq;
        ide_startstop_t ret = ide_stopped;
 
@@ -487,12 +479,23 @@ ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
 
        if (error < 0) {
                printk(KERN_WARNING "%s: DMA timeout error\n", drive->name);
-               (void)hwif->dma_ops->dma_end(drive);
+               drive->waiting_for_dma = 0;
+               (void)dma_ops->dma_end(drive);
+               ide_dma_unmap_sg(drive, cmd);
                ret = ide_error(drive, "dma timeout error",
                                hwif->tp_ops->read_status(hwif));
        } else {
                printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
-               hwif->dma_ops->dma_timeout(drive);
+               if (dma_ops->dma_clear)
+                       dma_ops->dma_clear(drive);
+               printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
+               if (dma_ops->dma_test_irq(drive) == 0) {
+                       ide_dump_status(drive, "DMA timeout",
+                                       hwif->tp_ops->read_status(hwif));
+                       drive->waiting_for_dma = 0;
+                       (void)dma_ops->dma_end(drive);
+                       ide_dma_unmap_sg(drive, cmd);
+               }
        }
 
        /*
@@ -562,3 +565,25 @@ int ide_allocate_dma_engine(ide_hwif_t *hwif)
        return 0;
 }
 EXPORT_SYMBOL_GPL(ide_allocate_dma_engine);
+
+int ide_dma_prepare(ide_drive_t *drive, struct ide_cmd *cmd)
+{
+       const struct ide_dma_ops *dma_ops = drive->hwif->dma_ops;
+
+       if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 ||
+           (dma_ops->dma_check && dma_ops->dma_check(drive, cmd)))
+               goto out;
+       ide_map_sg(drive, cmd);
+       if (ide_dma_map_sg(drive, cmd) == 0)
+               goto out_map;
+       if (dma_ops->dma_setup(drive, cmd))
+               goto out_dma_unmap;
+       drive->waiting_for_dma = 1;
+       return 0;
+out_dma_unmap:
+       ide_dma_unmap_sg(drive, cmd);
+out_map:
+       ide_map_sg(drive, cmd);
+out:
+       return 1;
+}
index 1231b5e486f23973cd7919da81a67fc192b387f1..5d5fb961b5ce8ee83e9e6e5cfc216ca3d0314d65 100644 (file)
@@ -123,8 +123,18 @@ ide_startstop_t ide_error(ide_drive_t *drive, const char *msg, u8 stat)
 
        /* retry only "normal" I/O: */
        if (!blk_fs_request(rq)) {
-               rq->errors = 1;
-               ide_end_drive_cmd(drive, stat, err);
+               if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+                       struct ide_cmd *cmd = rq->special;
+
+                       if (cmd)
+                               ide_complete_cmd(drive, cmd, stat, err);
+               } else if (blk_pm_request(rq)) {
+                       rq->errors = 1;
+                       ide_complete_pm_rq(drive, rq);
+                       return ide_stopped;
+               }
+               rq->errors = err;
+               ide_complete_rq(drive, err ? -EIO : 0, blk_rq_bytes(rq));
                return ide_stopped;
        }
 
@@ -136,8 +146,11 @@ static inline void ide_complete_drive_reset(ide_drive_t *drive, int err)
 {
        struct request *rq = drive->hwif->rq;
 
-       if (rq && blk_special_request(rq) && rq->cmd[0] == REQ_DRIVE_RESET)
-               ide_end_request(drive, err ? err : 1, 0);
+       if (rq && blk_special_request(rq) && rq->cmd[0] == REQ_DRIVE_RESET) {
+               if (err <= 0 && rq->errors == 0)
+                       rq->errors = -EIO;
+               ide_complete_rq(drive, err ? err : 0, ide_rq_bytes(rq));
+       }
 }
 
 /* needed below */
@@ -152,18 +165,18 @@ static ide_startstop_t do_reset1(ide_drive_t *, int);
 static ide_startstop_t atapi_reset_pollfunc(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
+       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
        u8 stat;
 
-       SELECT_DRIVE(drive);
+       tp_ops->dev_select(drive);
        udelay(10);
-       stat = hwif->tp_ops->read_status(hwif);
+       stat = tp_ops->read_status(hwif);
 
        if (OK_STAT(stat, 0, ATA_BUSY))
                printk(KERN_INFO "%s: ATAPI reset complete\n", drive->name);
        else {
                if (time_before(jiffies, hwif->poll_timeout)) {
-                       ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20,
-                                       NULL);
+                       ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20);
                        /* continue polling */
                        return ide_started;
                }
@@ -225,7 +238,7 @@ static ide_startstop_t reset_pollfunc(ide_drive_t *drive)
 
        if (!OK_STAT(tmp, 0, ATA_BUSY)) {
                if (time_before(jiffies, hwif->poll_timeout)) {
-                       ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
+                       ide_set_handler(drive, &reset_pollfunc, HZ/20);
                        /* continue polling */
                        return ide_started;
                }
@@ -336,13 +349,13 @@ static ide_startstop_t do_reset1(ide_drive_t *drive, int do_not_try_atapi)
        /* For an ATAPI device, first try an ATAPI SRST. */
        if (drive->media != ide_disk && !do_not_try_atapi) {
                pre_reset(drive);
-               SELECT_DRIVE(drive);
+               tp_ops->dev_select(drive);
                udelay(20);
                tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
                ndelay(400);
                hwif->poll_timeout = jiffies + WAIT_WORSTCASE;
                hwif->polling = 1;
-               __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
+               __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20);
                spin_unlock_irqrestore(&hwif->lock, flags);
                return ide_started;
        }
@@ -389,20 +402,19 @@ static ide_startstop_t do_reset1(ide_drive_t *drive, int do_not_try_atapi)
         * immediate interrupt due to the edge transition it produces.
         * This single interrupt gives us a "fast poll" for drives that
         * recover from reset very quickly, saving us the first 50ms wait time.
-        *
-        * TODO: add ->softreset method and stop abusing ->set_irq
         */
        /* set SRST and nIEN */
-       tp_ops->set_irq(hwif, 4);
+       tp_ops->write_devctl(hwif, ATA_SRST | ATA_NIEN | ATA_DEVCTL_OBS);
        /* more than enough time */
        udelay(10);
        /* clear SRST, leave nIEN (unless device is on the quirk list) */
-       tp_ops->set_irq(hwif, drive->quirk_list == 2);
+       tp_ops->write_devctl(hwif, (drive->quirk_list == 2 ? 0 : ATA_NIEN) |
+                            ATA_DEVCTL_OBS);
        /* more than enough time */
        udelay(10);
        hwif->poll_timeout = jiffies + WAIT_WORSTCASE;
        hwif->polling = 1;
-       __ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
+       __ide_set_handler(drive, &reset_pollfunc, HZ/20);
 
        /*
         * Some weird controller like resetting themselves to a strange
index 317ec62c33d42428f96e310e774d3c14eb75eb3d..2b4868d95f8b0597de827c36df575cec1375d8f7 100644 (file)
  */
 #define IDEFLOPPY_PC_DELAY     (HZ/20) /* default delay for ZIP 100 (50ms) */
 
-/* Error code returned in rq->errors to the higher part of the driver. */
-#define        IDEFLOPPY_ERROR_GENERAL         101
-
-/*
- * Used to finish servicing a request. For read/write requests, we will call
- * ide_end_request to pass to the next buffer.
- */
-static int ide_floppy_end_request(ide_drive_t *drive, int uptodate, int nsecs)
-{
-       struct ide_disk_obj *floppy = drive->driver_data;
-       struct request *rq = drive->hwif->rq;
-       int error;
-
-       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
-
-       switch (uptodate) {
-       case 0:
-               error = IDEFLOPPY_ERROR_GENERAL;
-               break;
-
-       case 1:
-               error = 0;
-               break;
-
-       default:
-               error = uptodate;
-       }
-
-       if (error)
-               floppy->failed_pc = NULL;
-       /* Why does this happen? */
-       if (!rq)
-               return 0;
-       if (!blk_special_request(rq)) {
-               /* our real local end request function */
-               ide_end_request(drive, uptodate, nsecs);
-               return 0;
-       }
-       rq->errors = error;
-       /* fixme: need to move this local also */
-       ide_end_drive_cmd(drive, 0, 0);
-       return 0;
-}
-
-static void idefloppy_update_buffers(ide_drive_t *drive,
-                               struct ide_atapi_pc *pc)
-{
-       struct request *rq = pc->rq;
-       struct bio *bio = rq->bio;
-
-       while ((bio = rq->bio) != NULL)
-               ide_floppy_end_request(drive, 1, 0);
-}
-
-static void ide_floppy_callback(ide_drive_t *drive, int dsc)
+static int ide_floppy_callback(ide_drive_t *drive, int dsc)
 {
        struct ide_disk_obj *floppy = drive->driver_data;
        struct ide_atapi_pc *pc = drive->pc;
+       struct request *rq = pc->rq;
        int uptodate = pc->error ? 0 : 1;
 
-       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "enter");
 
-       if (floppy->failed_pc == pc)
-               floppy->failed_pc = NULL;
+       if (drive->failed_pc == pc)
+               drive->failed_pc = NULL;
 
        if (pc->c[0] == GPCMD_READ_10 || pc->c[0] == GPCMD_WRITE_10 ||
-           (pc->rq && blk_pc_request(pc->rq)))
+           (rq && blk_pc_request(rq)))
                uptodate = 1; /* FIXME */
        else if (pc->c[0] == GPCMD_REQUEST_SENSE) {
                u8 *buf = pc->buf;
@@ -139,19 +86,22 @@ static void ide_floppy_callback(ide_drive_t *drive, int dsc)
                        floppy->progress_indication = buf[15] & 0x80 ?
                                (u16)get_unaligned((u16 *)&buf[16]) : 0x10000;
 
-                       if (floppy->failed_pc)
-                               ide_debug_log(IDE_DBG_PC, "pc = %x",
-                                             floppy->failed_pc->c[0]);
+                       if (drive->failed_pc)
+                               ide_debug_log(IDE_DBG_PC, "pc = %x",
+                                             drive->failed_pc->c[0]);
 
                        ide_debug_log(IDE_DBG_SENSE, "sense key = %x, asc = %x,"
-                                     "ascq = %x\n", floppy->sense_key,
+                                     "ascq = %x", floppy->sense_key,
                                      floppy->asc, floppy->ascq);
                } else
                        printk(KERN_ERR PFX "Error in REQUEST SENSE itself - "
                               "Aborting request!\n");
        }
 
-       ide_floppy_end_request(drive, uptodate, 0);
+       if (blk_special_request(rq))
+               rq->errors = uptodate ? 0 : IDE_DRV_ERROR_GENERAL;
+
+       return uptodate;
 }
 
 static void ide_floppy_report_error(struct ide_disk_obj *floppy,
@@ -170,14 +120,15 @@ static void ide_floppy_report_error(struct ide_disk_obj *floppy,
 
 }
 
-static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive,
-               struct ide_atapi_pc *pc)
+static ide_startstop_t ide_floppy_issue_pc(ide_drive_t *drive,
+                                          struct ide_cmd *cmd,
+                                          struct ide_atapi_pc *pc)
 {
        struct ide_disk_obj *floppy = drive->driver_data;
 
-       if (floppy->failed_pc == NULL &&
+       if (drive->failed_pc == NULL &&
            pc->c[0] != GPCMD_REQUEST_SENSE)
-               floppy->failed_pc = pc;
+               drive->failed_pc = pc;
 
        /* Set the current packet command */
        drive->pc = pc;
@@ -186,18 +137,18 @@ static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive,
                if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR))
                        ide_floppy_report_error(floppy, pc);
                /* Giving up */
-               pc->error = IDEFLOPPY_ERROR_GENERAL;
+               pc->error = IDE_DRV_ERROR_GENERAL;
 
-               floppy->failed_pc = NULL;
+               drive->failed_pc = NULL;
                drive->pc_callback(drive, 0);
                return ide_stopped;
        }
 
-       ide_debug_log(IDE_DBG_FUNC, "%s: Retry #%d\n", __func__, pc->retries);
+       ide_debug_log(IDE_DBG_FUNC, "retry #%d", pc->retries);
 
        pc->retries++;
 
-       return ide_issue_pc(drive);
+       return ide_issue_pc(drive, cmd);
 }
 
 void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *pc)
@@ -242,8 +193,7 @@ static void idefloppy_create_rw_cmd(ide_drive_t *drive,
        int blocks = rq->nr_sectors / floppy->bs_factor;
        int cmd = rq_data_dir(rq);
 
-       ide_debug_log(IDE_DBG_FUNC, "%s: block: %d, blocks: %d\n", __func__,
-                     block, blocks);
+       ide_debug_log(IDE_DBG_FUNC, "block: %d, blocks: %d", block, blocks);
 
        ide_init_pc(pc);
        pc->c[0] = cmd == READ ? GPCMD_READ_10 : GPCMD_WRITE_10;
@@ -253,7 +203,6 @@ static void idefloppy_create_rw_cmd(ide_drive_t *drive,
        memcpy(rq->cmd, pc->c, 12);
 
        pc->rq = rq;
-       pc->b_count = 0;
        if (rq->cmd_flags & REQ_RW)
                pc->flags |= PC_FLAG_WRITING;
        pc->buf = NULL;
@@ -267,7 +216,6 @@ static void idefloppy_blockpc_cmd(struct ide_disk_obj *floppy,
        ide_init_pc(pc);
        memcpy(pc->c, rq->cmd, sizeof(pc->c));
        pc->rq = rq;
-       pc->b_count = 0;
        if (rq->data_len && rq_data_dir(rq) == WRITE)
                pc->flags |= PC_FLAG_WRITING;
        pc->buf = rq->data;
@@ -284,35 +232,36 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
                                             struct request *rq, sector_t block)
 {
        struct ide_disk_obj *floppy = drive->driver_data;
-       ide_hwif_t *hwif = drive->hwif;
+       struct ide_cmd cmd;
        struct ide_atapi_pc *pc;
 
-       ide_debug_log(IDE_DBG_FUNC, "%s: dev: %s, cmd: 0x%x, cmd_type: %x, "
-                     "errors: %d\n",
-                     __func__, rq->rq_disk ? rq->rq_disk->disk_name : "?",
-                     rq->cmd[0], rq->cmd_type, rq->errors);
+       ide_debug_log(IDE_DBG_FUNC, "enter, cmd: 0x%x\n", rq->cmd[0]);
 
-       ide_debug_log(IDE_DBG_FUNC, "%s: sector: %ld, nr_sectors: %ld, "
-                     "current_nr_sectors: %d\n",
-                     __func__, (long)rq->sector, rq->nr_sectors,
-                     rq->current_nr_sectors);
+       if (drive->debug_mask & IDE_DBG_RQ)
+               blk_dump_rq_flags(rq, (rq->rq_disk
+                                       ? rq->rq_disk->disk_name
+                                       : "dev?"));
 
        if (rq->errors >= ERROR_MAX) {
-               if (floppy->failed_pc)
-                       ide_floppy_report_error(floppy, floppy->failed_pc);
-               else
+               if (drive->failed_pc) {
+                       ide_floppy_report_error(floppy, drive->failed_pc);
+                       drive->failed_pc = NULL;
+               } else
                        printk(KERN_ERR PFX "%s: I/O error\n", drive->name);
 
-               ide_floppy_end_request(drive, 0, 0);
-               return ide_stopped;
+               if (blk_special_request(rq)) {
+                       rq->errors = 0;
+                       ide_complete_rq(drive, 0, blk_rq_bytes(rq));
+                       return ide_stopped;
+               } else
+                       goto out_end;
        }
        if (blk_fs_request(rq)) {
                if (((long)rq->sector % floppy->bs_factor) ||
                    (rq->nr_sectors % floppy->bs_factor)) {
                        printk(KERN_ERR PFX "%s: unsupported r/w rq size\n",
                                drive->name);
-                       ide_floppy_end_request(drive, 0, 0);
-                       return ide_stopped;
+                       goto out_end;
                }
                pc = &floppy->queued_pc;
                idefloppy_create_rw_cmd(drive, pc, rq, (unsigned long)block);
@@ -323,21 +272,30 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
                idefloppy_blockpc_cmd(floppy, pc, rq);
        } else {
                blk_dump_rq_flags(rq, PFX "unsupported command in queue");
-               ide_floppy_end_request(drive, 0, 0);
-               return ide_stopped;
+               goto out_end;
        }
 
+       memset(&cmd, 0, sizeof(cmd));
+
+       if (rq_data_dir(rq))
+               cmd.tf_flags |= IDE_TFLAG_WRITE;
+
+       cmd.rq = rq;
+
        if (blk_fs_request(rq) || pc->req_xfer) {
-               ide_init_sg_cmd(drive, rq);
-               ide_map_sg(drive, rq);
+               ide_init_sg_cmd(&cmd, pc->req_xfer);
+               ide_map_sg(drive, &cmd);
        }
 
-       pc->sg = hwif->sg_table;
-       pc->sg_cnt = hwif->sg_nents;
-
        pc->rq = rq;
 
-       return idefloppy_issue_pc(drive, pc);
+       return ide_floppy_issue_pc(drive, &cmd, pc);
+out_end:
+       drive->failed_pc = NULL;
+       if (blk_fs_request(rq) == 0 && rq->errors == 0)
+               rq->errors = -EIO;
+       ide_complete_rq(drive, -EIO, ide_rq_bytes(rq));
+       return ide_stopped;
 }
 
 /*
@@ -413,9 +371,11 @@ static int ide_floppy_get_capacity(ide_drive_t *drive)
        struct gendisk *disk = floppy->disk;
        struct ide_atapi_pc pc;
        u8 *cap_desc;
-       u8 header_len, desc_cnt;
+       u8 pc_buf[256], header_len, desc_cnt;
        int i, rc = 1, blocks, length;
 
+       ide_debug_log(IDE_DBG_FUNC, "enter");
+
        drive->bios_cyl = 0;
        drive->bios_head = drive->bios_sect = 0;
        floppy->blocks = 0;
@@ -423,6 +383,9 @@ static int ide_floppy_get_capacity(ide_drive_t *drive)
        drive->capacity64 = 0;
 
        ide_floppy_create_read_capacity_cmd(&pc);
+       pc.buf = &pc_buf[0];
+       pc.buf_size = sizeof(pc_buf);
+
        if (ide_queue_pc_tail(drive, disk, &pc)) {
                printk(KERN_ERR PFX "Can't get floppy parameters\n");
                return 1;
@@ -438,8 +401,9 @@ static int ide_floppy_get_capacity(ide_drive_t *drive)
                length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]);
 
                ide_debug_log(IDE_DBG_PROBE, "Descriptor %d: %dkB, %d blocks, "
-                             "%d sector size\n",
-                             i, blocks * length / 1024, blocks, length);
+                                            "%d sector size",
+                                            i, blocks * length / 1024,
+                                            blocks, length);
 
                if (i)
                        continue;
@@ -495,8 +459,8 @@ static int ide_floppy_get_capacity(ide_drive_t *drive)
                                "in drive\n", drive->name);
                        break;
                }
-               ide_debug_log(IDE_DBG_PROBE, "Descriptor 0 Code: %d\n",
-                             pc.buf[desc_start + 4] & 0x03);
+               ide_debug_log(IDE_DBG_PROBE, "Descriptor 0 Code: %d",
+                                            pc.buf[desc_start + 4] & 0x03);
        }
 
        /* Clik! disk does not support get_flexible_disk_page */
@@ -512,8 +476,6 @@ static void ide_floppy_setup(ide_drive_t *drive)
        u16 *id = drive->id;
 
        drive->pc_callback       = ide_floppy_callback;
-       drive->pc_update_buffers = idefloppy_update_buffers;
-       drive->pc_io_buffers     = ide_io_buffers;
 
        /*
         * We used to check revisions here. At this point however I'm giving up.
@@ -575,6 +537,5 @@ const struct ide_disk_ops ide_atapi_disk_ops = {
        .init_media     = ide_floppy_init_media,
        .set_doorlock   = ide_set_media_lock,
        .do_request     = ide_floppy_do_request,
-       .end_request    = ide_floppy_end_request,
        .ioctl          = ide_floppy_ioctl,
 };
index 8f8be8546038d5950d5e944e26871fc7f0186a49..cd8a42027ede72f10c0acd0a96e7c0fb6ad2e4f6 100644 (file)
@@ -36,9 +36,9 @@ static int ide_floppy_get_format_capacities(ide_drive_t *drive,
                                            int __user *arg)
 {
        struct ide_disk_obj *floppy = drive->driver_data;
-       u8 header_len, desc_cnt;
        int i, blocks, length, u_array_size, u_index;
        int __user *argp;
+       u8 pc_buf[256], header_len, desc_cnt;
 
        if (get_user(u_array_size, arg))
                return -EFAULT;
@@ -47,6 +47,9 @@ static int ide_floppy_get_format_capacities(ide_drive_t *drive,
                return -EINVAL;
 
        ide_floppy_create_read_capacity_cmd(pc);
+       pc->buf = &pc_buf[0];
+       pc->buf_size = sizeof(pc_buf);
+
        if (ide_queue_pc_tail(drive, floppy->disk, pc)) {
                printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
                return -EIO;
index 047109419902c0ad6b3f741e68fdaab0e05a1069..1aebdf1a4f5866a4c6d0f430274e66d1ce3e6022 100644 (file)
@@ -145,11 +145,6 @@ static ide_startstop_t ide_gd_do_request(ide_drive_t *drive,
        return drive->disk_ops->do_request(drive, rq, sector);
 }
 
-static int ide_gd_end_request(ide_drive_t *drive, int uptodate, int nrsecs)
-{
-       return drive->disk_ops->end_request(drive, uptodate, nrsecs);
-}
-
 static struct ide_driver ide_gd_driver = {
        .gen_driver = {
                .owner          = THIS_MODULE,
@@ -162,7 +157,6 @@ static struct ide_driver ide_gd_driver = {
        .shutdown               = ide_gd_shutdown,
        .version                = IDE_GD_VERSION,
        .do_request             = ide_gd_do_request,
-       .end_request            = ide_gd_end_request,
 #ifdef CONFIG_IDE_PROC_FS
        .proc_entries           = ide_disk_proc_entries,
        .proc_devsets           = ide_disk_proc_devsets,
@@ -182,7 +176,7 @@ static int ide_gd_open(struct block_device *bdev, fmode_t mode)
 
        drive = idkp->drive;
 
-       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "enter");
 
        idkp->openers++;
 
@@ -232,7 +226,7 @@ static int ide_gd_release(struct gendisk *disk, fmode_t mode)
        struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
        ide_drive_t *drive = idkp->drive;
 
-       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "enter");
 
        if (idkp->openers == 1)
                drive->disk_ops->flush(drive);
index b604bdd318a1294a6e7cb8c9d2addcca68f8759d..55970772bd04cc3e9f83681740ba5de2b2ee0635 100644 (file)
@@ -8,7 +8,7 @@
 #define IDE_GD_DEBUG_LOG       0
 
 #if IDE_GD_DEBUG_LOG
-#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, args)
+#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, ## args)
 #else
 #define ide_debug_log(lvl, fmt, args...) do {} while (0)
 #endif
@@ -20,8 +20,6 @@ struct ide_disk_obj {
        struct device           dev;
        unsigned int            openers;        /* protected by BKL for now */
 
-       /* Last failed packet command */
-       struct ide_atapi_pc *failed_pc;
        /* used for blk_{fs,pc}_request() requests */
        struct ide_atapi_pc queued_pc;
 
index 81a5282ce1eb06e74a93168e33cd94e9d5f1ac52..7812ca0be13beb1c5af1ba98ea8b29b4bd2cbf4b 100644 (file)
@@ -1,27 +1,22 @@
 /*
  * generic/default IDE host driver
  *
- * Copyright (C) 2004, 2008 Bartlomiej Zolnierkiewicz
+ * Copyright (C) 2004, 2008-2009 Bartlomiej Zolnierkiewicz
  * This code was split off from ide.c.  See it for original copyrights.
  *
  * May be copied or modified under the terms of the GNU General Public License.
  */
 
-/*
- * For special cases new interfaces may be added using sysfs, i.e.
- *
- *     echo -n "0x168:0x36e:10" > /sys/class/ide_generic/add
- *
- * will add an interface using I/O ports 0x168-0x16f/0x36e and IRQ 10.
- */
-
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/ide.h>
 #include <linux/pci_ids.h>
 
-/* FIXME: convert m32r to use ide_platform host driver */
+/* FIXME: convert arm and m32r to use ide_platform host driver */
+#ifdef CONFIG_ARM
+#include <asm/irq.h>
+#endif
 #ifdef CONFIG_M32R
 #include <asm/m32r.h>
 #endif
@@ -32,62 +27,15 @@ static int probe_mask;
 module_param(probe_mask, int, 0);
 MODULE_PARM_DESC(probe_mask, "probe mask for legacy ISA IDE ports");
 
-static ssize_t store_add(struct class *cls, const char *buf, size_t n)
-{
-       unsigned int base, ctl;
-       int irq, rc;
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
-
-       if (sscanf(buf, "%x:%x:%d", &base, &ctl, &irq) != 3)
-               return -EINVAL;
-
-       memset(&hw, 0, sizeof(hw));
-       ide_std_init_ports(&hw, base, ctl);
-       hw.irq = irq;
-       hw.chipset = ide_generic;
-
-       rc = ide_host_add(NULL, hws, NULL);
-       if (rc)
-               return rc;
-
-       return n;
-};
-
-static struct class_attribute ide_generic_class_attrs[] = {
-       __ATTR(add, S_IWUSR, NULL, store_add),
-       __ATTR_NULL
+static const struct ide_port_info ide_generic_port_info = {
+       .host_flags             = IDE_HFLAG_NO_DMA,
 };
 
-static void ide_generic_class_release(struct class *cls)
-{
-       kfree(cls);
-}
-
-static int __init ide_generic_sysfs_init(void)
-{
-       struct class *cls;
-       int rc;
-
-       cls = kzalloc(sizeof(*cls), GFP_KERNEL);
-       if (!cls)
-               return -ENOMEM;
-
-       cls->name = DRV_NAME;
-       cls->owner = THIS_MODULE;
-       cls->class_release = ide_generic_class_release;
-       cls->class_attrs = ide_generic_class_attrs;
-
-       rc = class_register(cls);
-       if (rc) {
-               kfree(cls);
-               return rc;
-       }
-
-       return 0;
-}
-
-#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2) \
-       || defined(CONFIG_PLAT_OPSPUT)
+#ifdef CONFIG_ARM
+static const u16 legacy_bases[] = { 0x1f0 };
+static const int legacy_irqs[]  = { IRQ_HARDDISK };
+#elif defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2) || \
+      defined(CONFIG_PLAT_OPSPUT)
 static const u16 legacy_bases[] = { 0x1f0 };
 static const int legacy_irqs[]  = { PLD_IRQ_CFIREQ };
 #elif defined(CONFIG_PLAT_MAPPI3)
@@ -103,11 +51,11 @@ static const int legacy_irqs[]  = { 14, 15, 11, 10, 8, 12 };
 
 static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary)
 {
+#ifdef CONFIG_PCI
        struct pci_dev *p = NULL;
        u16 val;
 
        for_each_pci_dev(p) {
-
                if (pci_resource_start(p, 0) == 0x1f0)
                        *primary = 1;
                if (pci_resource_start(p, 2) == 0x170)
@@ -122,7 +70,6 @@ static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary)
                /* Intel MPIIX - PIO ATA on non PCI side of bridge */
                if (p->vendor == PCI_VENDOR_ID_INTEL &&
                    p->device == PCI_DEVICE_ID_INTEL_82371MX) {
-
                        pci_read_config_word(p, 0x6C, &val);
                        if (val & 0x8000) {
                                /* ATA port enabled */
@@ -133,6 +80,7 @@ static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary)
                        }
                }
        }
+#endif
 }
 
 static int __init ide_generic_init(void)
@@ -164,6 +112,7 @@ static int __init ide_generic_init(void)
                                printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX "
                                                "not free.\n",
                                                DRV_NAME, io_addr, io_addr + 7);
+                               rc = -EBUSY;
                                continue;
                        }
 
@@ -172,6 +121,7 @@ static int __init ide_generic_init(void)
                                                "not free.\n",
                                                DRV_NAME, io_addr + 0x206);
                                release_region(io_addr, 8);
+                               rc = -EBUSY;
                                continue;
                        }
 
@@ -184,7 +134,7 @@ static int __init ide_generic_init(void)
 #endif
                        hw.chipset = ide_generic;
 
-                       rc = ide_host_add(NULL, hws, NULL);
+                       rc = ide_host_add(&ide_generic_port_info, hws, NULL);
                        if (rc) {
                                release_region(io_addr + 0x206, 1);
                                release_region(io_addr, 8);
@@ -192,10 +142,6 @@ static int __init ide_generic_init(void)
                }
        }
 
-       if (ide_generic_sysfs_init())
-               printk(KERN_ERR DRV_NAME ": failed to create ide_generic "
-                                        "class\n");
-
        return rc;
 }
 
index 9270d3255ee04ebcb1fb732928847df5a9712201..dac9a6d44963ecbfe7b5b82cc4619bb8f7681c76 100644 (file)
@@ -44,88 +44,78 @@ static u16 mm_inw(unsigned long a)
        return r;
 }
 
-static void h8300_tf_load(ide_drive_t *drive, ide_task_t *task)
+static void h8300_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct ide_io_ports *io_ports = &hwif->io_ports;
-       struct ide_taskfile *tf = &task->tf;
-       u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+       struct ide_taskfile *tf = &cmd->tf;
+       u8 HIHI = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
 
-       if (task->tf_flags & IDE_TFLAG_FLAGGED)
+       if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
                HIHI = 0xFF;
 
-       if (task->tf_flags & IDE_TFLAG_OUT_DATA)
-               mm_outw((tf->hob_data << 8) | tf->data, io_ports->data_addr);
-
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
                outb(tf->hob_feature, io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
                outb(tf->hob_nsect, io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
                outb(tf->hob_lbal, io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
                outb(tf->hob_lbam, io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
                outb(tf->hob_lbah, io_ports->lbah_addr);
 
-       if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_FEATURE)
                outb(tf->feature, io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_NSECT)
                outb(tf->nsect, io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAL)
                outb(tf->lbal, io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAM)
                outb(tf->lbam, io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAH)
                outb(tf->lbah, io_ports->lbah_addr);
 
-       if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_DEVICE)
                outb((tf->device & HIHI) | drive->select,
                     io_ports->device_addr);
 }
 
-static void h8300_tf_read(ide_drive_t *drive, ide_task_t *task)
+static void h8300_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct ide_io_ports *io_ports = &hwif->io_ports;
-       struct ide_taskfile *tf = &task->tf;
-
-       if (task->tf_flags & IDE_TFLAG_IN_DATA) {
-               u16 data = mm_inw(io_ports->data_addr);
-
-               tf->data = data & 0xff;
-               tf->hob_data = (data >> 8) & 0xff;
-       }
+       struct ide_taskfile *tf = &cmd->tf;
 
        /* be sure we're looking at the low order bits */
-       outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+       outb(ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-       if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
-               tf->feature = inb(io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_IN_ERROR)
+               tf->error  = inb(io_ports->feature_addr);
+       if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
                tf->nsect  = inb(io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
                tf->lbal   = inb(io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAM)
                tf->lbam   = inb(io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAH)
                tf->lbah   = inb(io_ports->lbah_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+       if (cmd->tf_flags & IDE_TFLAG_IN_DEVICE)
                tf->device = inb(io_ports->device_addr);
 
-       if (task->tf_flags & IDE_TFLAG_LBA48) {
-               outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
-
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
-                       tf->hob_feature = inb(io_ports->feature_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
-                       tf->hob_nsect   = inb(io_ports->nsect_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
-                       tf->hob_lbal    = inb(io_ports->lbal_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
-                       tf->hob_lbam    = inb(io_ports->lbam_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
-                       tf->hob_lbah    = inb(io_ports->lbah_addr);
+       if (cmd->tf_flags & IDE_TFLAG_LBA48) {
+               outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr);
+
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR)
+                       tf->hob_error = inb(io_ports->feature_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+                       tf->hob_nsect = inb(io_ports->nsect_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+                       tf->hob_lbal  = inb(io_ports->lbal_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+                       tf->hob_lbam  = inb(io_ports->lbam_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+                       tf->hob_lbah  = inb(io_ports->lbah_addr);
        }
 }
 
@@ -143,13 +133,13 @@ static void mm_insw(unsigned long addr, void *buf, u32 len)
                *bp = bswap(*(volatile u16 *)addr);
 }
 
-static void h8300_input_data(ide_drive_t *drive, struct request *rq,
+static void h8300_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
                             void *buf, unsigned int len)
 {
        mm_insw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
 }
 
-static void h8300_output_data(ide_drive_t *drive, struct request *rq,
+static void h8300_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
                              void *buf, unsigned int len)
 {
        mm_outsw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
@@ -159,9 +149,9 @@ static const struct ide_tp_ops h8300_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = h8300_tf_load,
        .tf_read                = h8300_tf_read,
 
index 45b43dd49cda1ef132f811211ae5775f3bfa95d2..9cac281d82c485857a6f62d9d346c0d51de6de1e 100644 (file)
@@ -2,6 +2,13 @@
 #include <linux/kernel.h>
 #include <linux/ide.h>
 
+#if defined(CONFIG_ARM) || defined(CONFIG_M68K) || defined(CONFIG_MIPS) || \
+    defined(CONFIG_PARISC) || defined(CONFIG_PPC) || defined(CONFIG_SPARC)
+#include <asm/ide.h>
+#else
+#include <asm-generic/ide_iops.h>
+#endif
+
 /*
  *     Conventional PIO operations for ATA devices
  */
@@ -57,83 +64,77 @@ u8 ide_read_altstatus(ide_hwif_t *hwif)
 }
 EXPORT_SYMBOL_GPL(ide_read_altstatus);
 
-void ide_set_irq(ide_hwif_t *hwif, int on)
+void ide_write_devctl(ide_hwif_t *hwif, u8 ctl)
 {
-       u8 ctl = ATA_DEVCTL_OBS;
-
-       if (on == 4) { /* hack for SRST */
-               ctl |= 4;
-               on &= ~4;
-       }
-
-       ctl |= on ? 0 : 2;
-
        if (hwif->host_flags & IDE_HFLAG_MMIO)
                writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr);
        else
                outb(ctl, hwif->io_ports.ctl_addr);
 }
-EXPORT_SYMBOL_GPL(ide_set_irq);
+EXPORT_SYMBOL_GPL(ide_write_devctl);
 
-void ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+void ide_dev_select(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       u8 select = drive->select | ATA_DEVICE_OBS;
+
+       if (hwif->host_flags & IDE_HFLAG_MMIO)
+               writeb(select, (void __iomem *)hwif->io_ports.device_addr);
+       else
+               outb(select, hwif->io_ports.device_addr);
+}
+EXPORT_SYMBOL_GPL(ide_dev_select);
+
+void ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct ide_io_ports *io_ports = &hwif->io_ports;
-       struct ide_taskfile *tf = &task->tf;
+       struct ide_taskfile *tf = &cmd->tf;
        void (*tf_outb)(u8 addr, unsigned long port);
        u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-       u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+       u8 HIHI = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
 
        if (mmio)
                tf_outb = ide_mm_outb;
        else
                tf_outb = ide_outb;
 
-       if (task->tf_flags & IDE_TFLAG_FLAGGED)
+       if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
                HIHI = 0xFF;
 
-       if (task->tf_flags & IDE_TFLAG_OUT_DATA) {
-               u16 data = (tf->hob_data << 8) | tf->data;
-
-               if (mmio)
-                       writew(data, (void __iomem *)io_ports->data_addr);
-               else
-                       outw(data, io_ports->data_addr);
-       }
-
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
                tf_outb(tf->hob_feature, io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
                tf_outb(tf->hob_nsect, io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
                tf_outb(tf->hob_lbal, io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
                tf_outb(tf->hob_lbam, io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
                tf_outb(tf->hob_lbah, io_ports->lbah_addr);
 
-       if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_FEATURE)
                tf_outb(tf->feature, io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_NSECT)
                tf_outb(tf->nsect, io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAL)
                tf_outb(tf->lbal, io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAM)
                tf_outb(tf->lbam, io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAH)
                tf_outb(tf->lbah, io_ports->lbah_addr);
 
-       if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_DEVICE)
                tf_outb((tf->device & HIHI) | drive->select,
                         io_ports->device_addr);
 }
 EXPORT_SYMBOL_GPL(ide_tf_load);
 
-void ide_tf_read(ide_drive_t *drive, ide_task_t *task)
+void ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct ide_io_ports *io_ports = &hwif->io_ports;
-       struct ide_taskfile *tf = &task->tf;
+       struct ide_taskfile *tf = &cmd->tf;
        void (*tf_outb)(u8 addr, unsigned long port);
        u8 (*tf_inb)(unsigned long port);
        u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
@@ -146,47 +147,35 @@ void ide_tf_read(ide_drive_t *drive, ide_task_t *task)
                tf_inb  = ide_inb;
        }
 
-       if (task->tf_flags & IDE_TFLAG_IN_DATA) {
-               u16 data;
-
-               if (mmio)
-                       data = readw((void __iomem *)io_ports->data_addr);
-               else
-                       data = inw(io_ports->data_addr);
-
-               tf->data = data & 0xff;
-               tf->hob_data = (data >> 8) & 0xff;
-       }
-
        /* be sure we're looking at the low order bits */
-       tf_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+       tf_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-       if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
-               tf->feature = tf_inb(io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_IN_ERROR)
+               tf->error  = tf_inb(io_ports->feature_addr);
+       if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
                tf->nsect  = tf_inb(io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
                tf->lbal   = tf_inb(io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAM)
                tf->lbam   = tf_inb(io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAH)
                tf->lbah   = tf_inb(io_ports->lbah_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+       if (cmd->tf_flags & IDE_TFLAG_IN_DEVICE)
                tf->device = tf_inb(io_ports->device_addr);
 
-       if (task->tf_flags & IDE_TFLAG_LBA48) {
-               tf_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
-
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
-                       tf->hob_feature = tf_inb(io_ports->feature_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
-                       tf->hob_nsect   = tf_inb(io_ports->nsect_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
-                       tf->hob_lbal    = tf_inb(io_ports->lbal_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
-                       tf->hob_lbam    = tf_inb(io_ports->lbam_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
-                       tf->hob_lbah    = tf_inb(io_ports->lbah_addr);
+       if (cmd->tf_flags & IDE_TFLAG_LBA48) {
+               tf_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr);
+
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR)
+                       tf->hob_error = tf_inb(io_ports->feature_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+                       tf->hob_nsect = tf_inb(io_ports->nsect_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+                       tf->hob_lbal  = tf_inb(io_ports->lbal_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+                       tf->hob_lbam  = tf_inb(io_ports->lbam_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+                       tf->hob_lbah  = tf_inb(io_ports->lbah_addr);
        }
 }
 EXPORT_SYMBOL_GPL(ide_tf_read);
@@ -212,17 +201,16 @@ static void ata_vlb_sync(unsigned long port)
  * so if an odd len is specified, be sure that there's at least one
  * extra byte allocated for the buffer.
  */
-void ide_input_data(ide_drive_t *drive, struct request *rq, void *buf,
+void ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf,
                    unsigned int len)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct ide_io_ports *io_ports = &hwif->io_ports;
        unsigned long data_addr = io_ports->data_addr;
+       unsigned int words = (len + 1) >> 1;
        u8 io_32bit = drive->io_32bit;
        u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
 
-       len++;
-
        if (io_32bit) {
                unsigned long uninitialized_var(flags);
 
@@ -231,44 +219,42 @@ void ide_input_data(ide_drive_t *drive, struct request *rq, void *buf,
                        ata_vlb_sync(io_ports->nsect_addr);
                }
 
+               words >>= 1;
                if (mmio)
-                       __ide_mm_insl((void __iomem *)data_addr, buf, len / 4);
+                       __ide_mm_insl((void __iomem *)data_addr, buf, words);
                else
-                       insl(data_addr, buf, len / 4);
+                       insl(data_addr, buf, words);
 
                if ((io_32bit & 2) && !mmio)
                        local_irq_restore(flags);
 
-               if ((len & 3) >= 2) {
-                       if (mmio)
-                               __ide_mm_insw((void __iomem *)data_addr,
-                                               (u8 *)buf + (len & ~3), 1);
-                       else
-                               insw(data_addr, (u8 *)buf + (len & ~3), 1);
-               }
-       } else {
-               if (mmio)
-                       __ide_mm_insw((void __iomem *)data_addr, buf, len / 2);
-               else
-                       insw(data_addr, buf, len / 2);
+               if (((len + 1) & 3) < 2)
+                       return;
+
+               buf += len & ~3;
+               words = 1;
        }
+
+       if (mmio)
+               __ide_mm_insw((void __iomem *)data_addr, buf, words);
+       else
+               insw(data_addr, buf, words);
 }
 EXPORT_SYMBOL_GPL(ide_input_data);
 
 /*
  * This is used for most PIO data transfers *to* the IDE interface
  */
-void ide_output_data(ide_drive_t *drive, struct request *rq, void *buf,
+void ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf,
                     unsigned int len)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct ide_io_ports *io_ports = &hwif->io_ports;
        unsigned long data_addr = io_ports->data_addr;
+       unsigned int words = (len + 1) >> 1;
        u8 io_32bit = drive->io_32bit;
        u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
 
-       len++;
-
        if (io_32bit) {
                unsigned long uninitialized_var(flags);
 
@@ -277,27 +263,26 @@ void ide_output_data(ide_drive_t *drive, struct request *rq, void *buf,
                        ata_vlb_sync(io_ports->nsect_addr);
                }
 
+               words >>= 1;
                if (mmio)
-                       __ide_mm_outsl((void __iomem *)data_addr, buf, len / 4);
+                       __ide_mm_outsl((void __iomem *)data_addr, buf, words);
                else
-                       outsl(data_addr, buf, len / 4);
+                       outsl(data_addr, buf, words);
 
                if ((io_32bit & 2) && !mmio)
                        local_irq_restore(flags);
 
-               if ((len & 3) >= 2) {
-                       if (mmio)
-                               __ide_mm_outsw((void __iomem *)data_addr,
-                                                (u8 *)buf + (len & ~3), 1);
-                       else
-                               outsw(data_addr, (u8 *)buf + (len & ~3), 1);
-               }
-       } else {
-               if (mmio)
-                       __ide_mm_outsw((void __iomem *)data_addr, buf, len / 2);
-               else
-                       outsw(data_addr, buf, len / 2);
+               if (((len + 1) & 3) < 2)
+                       return;
+
+               buf += len & ~3;
+               words = 1;
        }
+
+       if (mmio)
+               __ide_mm_outsw((void __iomem *)data_addr, buf, words);
+       else
+               outsw(data_addr, buf, words);
 }
 EXPORT_SYMBOL_GPL(ide_output_data);
 
@@ -305,9 +290,9 @@ const struct ide_tp_ops default_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = ide_tf_load,
        .tf_read                = ide_tf_read,
 
index 2e92497b58aa02501b208562ab498d4f4d6c1e87..1deb6d29b1869f27fcce14cb2501dfded416c46f 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
-#include <linux/hdreg.h>
 #include <linux/completion.h>
 #include <linux/reboot.h>
 #include <linux/cdrom.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-static int __ide_end_request(ide_drive_t *drive, struct request *rq,
-                            int uptodate, unsigned int nr_bytes, int dequeue)
+int ide_end_rq(ide_drive_t *drive, struct request *rq, int error,
+              unsigned int nr_bytes)
 {
-       int ret = 1;
-       int error = 0;
-
-       if (uptodate <= 0)
-               error = uptodate ? uptodate : -EIO;
-
-       /*
-        * if failfast is set on a request, override number of sectors and
-        * complete the whole request right now
-        */
-       if (blk_noretry_request(rq) && error)
-               nr_bytes = rq->hard_nr_sectors << 9;
-
-       if (!blk_fs_request(rq) && error && !rq->errors)
-               rq->errors = -EIO;
-
        /*
         * decide whether to reenable DMA -- 3 is a random magic for now,
         * if we DMA timeout more than 3 times, just stay in PIO
@@ -84,127 +67,96 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
                ide_dma_on(drive);
        }
 
-       if (!blk_end_request(rq, error, nr_bytes))
-               ret = 0;
+       return blk_end_request(rq, error, nr_bytes);
+}
+EXPORT_SYMBOL_GPL(ide_end_rq);
 
-       if (ret == 0 && dequeue)
-               drive->hwif->rq = NULL;
+void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err)
+{
+       const struct ide_tp_ops *tp_ops = drive->hwif->tp_ops;
+       struct ide_taskfile *tf = &cmd->tf;
+       struct request *rq = cmd->rq;
+       u8 tf_cmd = tf->command;
 
-       return ret;
-}
+       tf->error = err;
+       tf->status = stat;
 
-/**
- *     ide_end_request         -       complete an IDE I/O
- *     @drive: IDE device for the I/O
- *     @uptodate:
- *     @nr_sectors: number of sectors completed
- *
- *     This is our end_request wrapper function. We complete the I/O
- *     update random number input and dequeue the request, which if
- *     it was tagged may be out of order.
- */
+       if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) {
+               u8 data[2];
 
-int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
-{
-       unsigned int nr_bytes = nr_sectors << 9;
-       struct request *rq = drive->hwif->rq;
+               tp_ops->input_data(drive, cmd, data, 2);
 
-       if (!nr_bytes) {
-               if (blk_pc_request(rq))
-                       nr_bytes = rq->data_len;
-               else
-                       nr_bytes = rq->hard_cur_sectors << 9;
+               tf->data = data[0];
+               tf->hob_data = data[1];
        }
 
-       return __ide_end_request(drive, rq, uptodate, nr_bytes, 1);
-}
-EXPORT_SYMBOL(ide_end_request);
+       tp_ops->tf_read(drive, cmd);
 
-/**
- *     ide_end_dequeued_request        -       complete an IDE I/O
- *     @drive: IDE device for the I/O
- *     @uptodate:
- *     @nr_sectors: number of sectors completed
- *
- *     Complete an I/O that is no longer on the request queue. This
- *     typically occurs when we pull the request and issue a REQUEST_SENSE.
- *     We must still finish the old request but we must not tamper with the
- *     queue in the meantime.
- *
- *     NOTE: This path does not handle barrier, but barrier is not supported
- *     on ide-cd anyway.
- */
+       if ((cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) &&
+           tf_cmd == ATA_CMD_IDLEIMMEDIATE) {
+               if (tf->lbal != 0xc4) {
+                       printk(KERN_ERR "%s: head unload failed!\n",
+                              drive->name);
+                       ide_tf_dump(drive->name, tf);
+               } else
+                       drive->dev_flags |= IDE_DFLAG_PARKED;
+       }
 
-int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
-                            int uptodate, int nr_sectors)
-{
-       BUG_ON(!blk_rq_started(rq));
+       if (rq && rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
+               memcpy(rq->special, cmd, sizeof(*cmd));
 
-       return __ide_end_request(drive, rq, uptodate, nr_sectors << 9, 0);
+       if (cmd->tf_flags & IDE_TFLAG_DYN)
+               kfree(cmd);
 }
-EXPORT_SYMBOL_GPL(ide_end_dequeued_request);
 
-/**
- *     ide_end_drive_cmd       -       end an explicit drive command
- *     @drive: command 
- *     @stat: status bits
- *     @err: error bits
- *
- *     Clean up after success/failure of an explicit drive command.
- *     These get thrown onto the queue so they are synchronized with
- *     real I/O operations on the drive.
- *
- *     In LBA48 mode we have to read the register set twice to get
- *     all the extra information out.
- */
-void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
+/* obsolete, blk_rq_bytes() should be used instead */
+unsigned int ide_rq_bytes(struct request *rq)
+{
+       if (blk_pc_request(rq))
+               return rq->data_len;
+       else
+               return rq->hard_cur_sectors << 9;
+}
+EXPORT_SYMBOL_GPL(ide_rq_bytes);
+
+int ide_complete_rq(ide_drive_t *drive, int error, unsigned int nr_bytes)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq = hwif->rq;
+       int rc;
 
-       if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-               ide_task_t *task = (ide_task_t *)rq->special;
-
-               if (task) {
-                       struct ide_taskfile *tf = &task->tf;
-
-                       tf->error = err;
-                       tf->status = stat;
-
-                       drive->hwif->tp_ops->tf_read(drive, task);
-
-                       if (task->tf_flags & IDE_TFLAG_DYN)
-                               kfree(task);
-               }
-       } else if (blk_pm_request(rq)) {
-               struct request_pm_state *pm = rq->data;
-
-               ide_complete_power_step(drive, rq);
-               if (pm->pm_step == IDE_PM_COMPLETED)
-                       ide_complete_pm_request(drive, rq);
-               return;
-       }
-
-       hwif->rq = NULL;
+       /*
+        * if failfast is set on a request, override number of sectors
+        * and complete the whole request right now
+        */
+       if (blk_noretry_request(rq) && error <= 0)
+               nr_bytes = rq->hard_nr_sectors << 9;
 
-       rq->errors = err;
+       rc = ide_end_rq(drive, rq, error, nr_bytes);
+       if (rc == 0)
+               hwif->rq = NULL;
 
-       if (unlikely(blk_end_request(rq, (rq->errors ? -EIO : 0),
-                                    blk_rq_bytes(rq))))
-               BUG();
+       return rc;
 }
-EXPORT_SYMBOL(ide_end_drive_cmd);
+EXPORT_SYMBOL(ide_complete_rq);
 
 void ide_kill_rq(ide_drive_t *drive, struct request *rq)
 {
-       if (rq->rq_disk) {
-               struct ide_driver *drv;
+       u8 drv_req = blk_special_request(rq) && rq->rq_disk;
+       u8 media = drive->media;
 
-               drv = *(struct ide_driver **)rq->rq_disk->private_data;
-               drv->end_request(drive, 0, 0);
-       } else
-               ide_end_request(drive, 0, 0);
+       drive->failed_pc = NULL;
+
+       if ((media == ide_floppy || media == ide_tape) && drv_req) {
+               rq->errors = 0;
+               ide_complete_rq(drive, 0, blk_rq_bytes(rq));
+       } else {
+               if (media == ide_tape)
+                       rq->errors = IDE_DRV_ERROR_GENERAL;
+               else if (blk_fs_request(rq) == 0 && rq->errors == 0)
+                       rq->errors = -EIO;
+               ide_complete_rq(drive, -EIO, ide_rq_bytes(rq));
+       }
 }
 
 static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
@@ -232,20 +184,20 @@ static void ide_tf_set_setmult_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
 static ide_startstop_t ide_disk_special(ide_drive_t *drive)
 {
        special_t *s = &drive->special;
-       ide_task_t args;
+       struct ide_cmd cmd;
 
-       memset(&args, 0, sizeof(ide_task_t));
-       args.data_phase = TASKFILE_NO_DATA;
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.protocol = ATA_PROT_NODATA;
 
        if (s->b.set_geometry) {
                s->b.set_geometry = 0;
-               ide_tf_set_specify_cmd(drive, &args.tf);
+               ide_tf_set_specify_cmd(drive, &cmd.tf);
        } else if (s->b.recalibrate) {
                s->b.recalibrate = 0;
-               ide_tf_set_restore_cmd(drive, &args.tf);
+               ide_tf_set_restore_cmd(drive, &cmd.tf);
        } else if (s->b.set_multmode) {
                s->b.set_multmode = 0;
-               ide_tf_set_setmult_cmd(drive, &args.tf);
+               ide_tf_set_setmult_cmd(drive, &cmd.tf);
        } else if (s->all) {
                int special = s->all;
                s->all = 0;
@@ -253,10 +205,10 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive)
                return ide_stopped;
        }
 
-       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE |
-                       IDE_TFLAG_CUSTOM_HANDLER;
+       cmd.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE |
+                      IDE_TFLAG_CUSTOM_HANDLER;
 
-       do_rw_taskfile(drive, &args);
+       do_rw_taskfile(drive, &cmd);
 
        return ide_started;
 }
@@ -286,33 +238,29 @@ static ide_startstop_t do_special (ide_drive_t *drive)
        return ide_stopped;
 }
 
-void ide_map_sg(ide_drive_t *drive, struct request *rq)
+void ide_map_sg(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct scatterlist *sg = hwif->sg_table;
+       struct request *rq = cmd->rq;
 
        if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
                sg_init_one(sg, rq->buffer, rq->nr_sectors * SECTOR_SIZE);
-               hwif->sg_nents = 1;
+               cmd->sg_nents = 1;
        } else if (!rq->bio) {
                sg_init_one(sg, rq->data, rq->data_len);
-               hwif->sg_nents = 1;
-       } else {
-               hwif->sg_nents = blk_rq_map_sg(drive->queue, rq, sg);
-       }
+               cmd->sg_nents = 1;
+       } else
+               cmd->sg_nents = blk_rq_map_sg(drive->queue, rq, sg);
 }
-
 EXPORT_SYMBOL_GPL(ide_map_sg);
 
-void ide_init_sg_cmd(ide_drive_t *drive, struct request *rq)
+void ide_init_sg_cmd(struct ide_cmd *cmd, unsigned int nr_bytes)
 {
-       ide_hwif_t *hwif = drive->hwif;
-
-       hwif->nsect = hwif->nleft = rq->nr_sectors;
-       hwif->cursg_ofs = 0;
-       hwif->cursg = NULL;
+       cmd->nbytes = cmd->nleft = nr_bytes;
+       cmd->cursg_ofs = 0;
+       cmd->cursg = NULL;
 }
-
 EXPORT_SYMBOL_GPL(ide_init_sg_cmd);
 
 /**
@@ -330,24 +278,15 @@ EXPORT_SYMBOL_GPL(ide_init_sg_cmd);
 static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
                struct request *rq)
 {
-       ide_hwif_t *hwif = drive->hwif;
-       ide_task_t *task = rq->special;
-
-       if (task) {
-               hwif->data_phase = task->data_phase;
-
-               switch (hwif->data_phase) {
-               case TASKFILE_MULTI_OUT:
-               case TASKFILE_OUT:
-               case TASKFILE_MULTI_IN:
-               case TASKFILE_IN:
-                       ide_init_sg_cmd(drive, rq);
-                       ide_map_sg(drive, rq);
-               default:
-                       break;
+       struct ide_cmd *cmd = rq->special;
+
+       if (cmd) {
+               if (cmd->protocol == ATA_PROT_PIO) {
+                       ide_init_sg_cmd(cmd, rq->nr_sectors << 9);
+                       ide_map_sg(drive, cmd);
                }
 
-               return do_rw_taskfile(drive, task);
+               return do_rw_taskfile(drive, cmd);
        }
 
        /*
@@ -357,8 +296,8 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
 #ifdef DEBUG
        printk("%s: DRIVE_CMD (null)\n", drive->name);
 #endif
-       ide_end_drive_cmd(drive, hwif->tp_ops->read_status(hwif),
-                         ide_read_error(drive));
+       rq->errors = 0;
+       ide_complete_rq(drive, 0, blk_rq_bytes(rq));
 
        return ide_stopped;
 }
@@ -376,9 +315,7 @@ static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq)
        case REQ_DRIVE_RESET:
                return ide_do_reset(drive);
        default:
-               blk_dump_rq_flags(rq, "ide_special_rq - bad request");
-               ide_end_request(drive, 0, 0);
-               return ide_stopped;
+               BUG();
        }
 }
 
@@ -411,7 +348,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
        if (blk_pm_request(rq))
                ide_check_pm_state(drive, rq);
 
-       SELECT_DRIVE(drive);
+       drive->hwif->tp_ops->dev_select(drive);
        if (ide_wait_stat(&startstop, drive, drive->ready_stat,
                          ATA_BUSY | ATA_DRQ, WAIT_READY)) {
                printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
@@ -438,7 +375,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
                        startstop = ide_start_power_step(drive, rq);
                        if (startstop == ide_stopped &&
                            pm->pm_step == IDE_PM_COMPLETED)
-                               ide_complete_pm_request(drive, rq);
+                               ide_complete_pm_rq(drive, rq);
                        return startstop;
                } else if (!rq->rq_disk && blk_special_request(rq))
                        /*
@@ -501,8 +438,8 @@ static inline int ide_lock_host(struct ide_host *host, ide_hwif_t *hwif)
        if (host->host_flags & IDE_HFLAG_SERIALIZE) {
                rc = test_and_set_bit_lock(IDE_HOST_BUSY, &host->host_busy);
                if (rc == 0) {
-                       /* for atari only */
-                       ide_get_lock(ide_intr, hwif);
+                       if (host->get_lock)
+                               host->get_lock(ide_intr, hwif);
                }
        }
        return rc;
@@ -511,8 +448,8 @@ static inline int ide_lock_host(struct ide_host *host, ide_hwif_t *hwif)
 static inline void ide_unlock_host(struct ide_host *host)
 {
        if (host->host_flags & IDE_HFLAG_SERIALIZE) {
-               /* for atari only */
-               ide_release_lock();
+               if (host->release_lock)
+                       host->release_lock();
                clear_bit_unlock(IDE_HOST_BUSY, &host->host_busy);
        }
 }
@@ -554,11 +491,10 @@ repeat:
                prev_port = hwif->host->cur_port;
                hwif->rq = NULL;
 
-               if (drive->dev_flags & IDE_DFLAG_SLEEPING) {
-                       if (time_before(drive->sleep, jiffies)) {
-                               ide_unlock_port(hwif);
-                               goto plug_device;
-                       }
+               if (drive->dev_flags & IDE_DFLAG_SLEEPING &&
+                   time_after(drive->sleep, jiffies)) {
+                       ide_unlock_port(hwif);
+                       goto plug_device;
                }
 
                if ((hwif->host->host_flags & IDE_HFLAG_SERIALIZE) &&
@@ -568,7 +504,9 @@ repeat:
                         * quirk_list may not like intr setups/cleanups
                         */
                        if (prev_port && prev_port->cur_dev->quirk_list == 0)
-                               prev_port->tp_ops->set_irq(prev_port, 0);
+                               prev_port->tp_ops->write_devctl(prev_port,
+                                                               ATA_NIEN |
+                                                               ATA_DEVCTL_OBS);
 
                        hwif->host->cur_port = hwif;
                }
@@ -724,6 +662,7 @@ void ide_timer_expiry (unsigned long data)
                        }
                }
                hwif->handler = NULL;
+               hwif->expiry = NULL;
                /*
                 * We need to simulate a real interrupt when invoking
                 * the handler() function, which means we need to
@@ -739,7 +678,8 @@ void ide_timer_expiry (unsigned long data)
                } else if (drive_is_ready(drive)) {
                        if (drive->waiting_for_dma)
                                hwif->dma_ops->dma_lost_irq(drive);
-                       (void)ide_ack_intr(hwif);
+                       if (hwif->ack_intr)
+                               hwif->ack_intr(hwif);
                        printk(KERN_WARNING "%s: lost interrupt\n",
                                drive->name);
                        startstop = handler(drive);
@@ -840,6 +780,7 @@ static void unexpected_intr(int irq, ide_hwif_t *hwif)
 irqreturn_t ide_intr (int irq, void *dev_id)
 {
        ide_hwif_t *hwif = (ide_hwif_t *)dev_id;
+       struct ide_host *host = hwif->host;
        ide_drive_t *uninitialized_var(drive);
        ide_handler_t *handler;
        unsigned long flags;
@@ -847,14 +788,14 @@ irqreturn_t ide_intr (int irq, void *dev_id)
        irqreturn_t irq_ret = IRQ_NONE;
        int plug_device = 0;
 
-       if (hwif->host->host_flags & IDE_HFLAG_SERIALIZE) {
-               if (hwif != hwif->host->cur_port)
+       if (host->host_flags & IDE_HFLAG_SERIALIZE) {
+               if (hwif != host->cur_port)
                        goto out_early;
        }
 
        spin_lock_irqsave(&hwif->lock, flags);
 
-       if (!ide_ack_intr(hwif))
+       if (hwif->ack_intr && hwif->ack_intr(hwif) == 0)
                goto out;
 
        handler = hwif->handler;
@@ -871,27 +812,19 @@ irqreturn_t ide_intr (int irq, void *dev_id)
                 *
                 * For PCI, we cannot tell the difference,
                 * so in that case we just ignore it and hope it goes away.
-                *
-                * FIXME: unexpected_intr should be hwif-> then we can
-                * remove all the ifdef PCI crap
                 */
-#ifdef CONFIG_BLK_DEV_IDEPCI
-               if (hwif->chipset != ide_pci)
-#endif /* CONFIG_BLK_DEV_IDEPCI */
-               {
+               if ((host->irq_flags & IRQF_SHARED) == 0) {
                        /*
                         * Probably not a shared PCI interrupt,
                         * so we can safely try to do something about it:
                         */
                        unexpected_intr(irq, hwif);
-#ifdef CONFIG_BLK_DEV_IDEPCI
                } else {
                        /*
                         * Whack the status register, just in case
                         * we have a leftover pending IRQ.
                         */
                        (void)hwif->tp_ops->read_status(hwif);
-#endif /* CONFIG_BLK_DEV_IDEPCI */
                }
                goto out;
        }
@@ -909,6 +842,7 @@ irqreturn_t ide_intr (int irq, void *dev_id)
                goto out;
 
        hwif->handler = NULL;
+       hwif->expiry = NULL;
        hwif->req_gen++;
        del_timer(&hwif->timer);
        spin_unlock(&hwif->lock);
index 1be263eb9c071c3cf7e3b48e0010ec9d4f02f476..770142767437ba5ea390cc2bf04020b998749d64 100644 (file)
@@ -111,13 +111,13 @@ static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg)
        return 0;
 }
 
-static int ide_cmd_ioctl(ide_drive_t *drive, unsigned cmd, unsigned long arg)
+static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
 {
        u8 *buf = NULL;
        int bufsize = 0, err = 0;
        u8 args[4], xfer_rate = 0;
-       ide_task_t tfargs;
-       struct ide_taskfile *tf = &tfargs.tf;
+       struct ide_cmd cmd;
+       struct ide_taskfile *tf = &cmd.tf;
        u16 *id = drive->id;
 
        if (NULL == (void *) arg) {
@@ -134,24 +134,24 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned cmd, unsigned long arg)
        if (copy_from_user(args, (void __user *)arg, 4))
                return -EFAULT;
 
-       memset(&tfargs, 0, sizeof(ide_task_t));
+       memset(&cmd, 0, sizeof(cmd));
        tf->feature = args[2];
        if (args[0] == ATA_CMD_SMART) {
                tf->nsect = args[3];
                tf->lbal  = args[1];
                tf->lbam  = 0x4f;
                tf->lbah  = 0xc2;
-               tfargs.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_IN_NSECT;
+               cmd.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_IN_NSECT;
        } else {
                tf->nsect = args[1];
-               tfargs.tf_flags = IDE_TFLAG_OUT_FEATURE |
-                                 IDE_TFLAG_OUT_NSECT | IDE_TFLAG_IN_NSECT;
+               cmd.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT |
+                              IDE_TFLAG_IN_NSECT;
        }
        tf->command = args[0];
-       tfargs.data_phase = args[3] ? TASKFILE_IN : TASKFILE_NO_DATA;
+       cmd.protocol = args[3] ? ATA_PROT_PIO : ATA_PROT_NODATA;
 
        if (args[3]) {
-               tfargs.tf_flags |= IDE_TFLAG_IO_16BIT;
+               cmd.tf_flags |= IDE_TFLAG_IO_16BIT;
                bufsize = SECTOR_SIZE * args[3];
                buf = kzalloc(bufsize, GFP_KERNEL);
                if (buf == NULL)
@@ -172,7 +172,7 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned cmd, unsigned long arg)
                }
        }
 
-       err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);
+       err = ide_raw_taskfile(drive, &cmd, buf, args[3]);
 
        args[0] = tf->status;
        args[1] = tf->error;
@@ -194,25 +194,25 @@ abort:
        return err;
 }
 
-static int ide_task_ioctl(ide_drive_t *drive, unsigned cmd, unsigned long arg)
+static int ide_task_ioctl(ide_drive_t *drive, unsigned long arg)
 {
        void __user *p = (void __user *)arg;
        int err = 0;
        u8 args[7];
-       ide_task_t task;
+       struct ide_cmd cmd;
 
        if (copy_from_user(args, p, 7))
                return -EFAULT;
 
-       memset(&task, 0, sizeof(task));
-       memcpy(&task.tf_array[7], &args[1], 6);
-       task.tf.command = args[0];
-       task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       memset(&cmd, 0, sizeof(cmd));
+       memcpy(&cmd.tf_array[7], &args[1], 6);
+       cmd.tf.command = args[0];
+       cmd.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 
-       err = ide_no_data_taskfile(drive, &task);
+       err = ide_no_data_taskfile(drive, &cmd);
 
-       args[0] = task.tf.command;
-       memcpy(&args[1], &task.tf_array[7], 6);
+       args[0] = cmd.tf.command;
+       memcpy(&args[1], &cmd.tf_array[7], 6);
 
        if (copy_to_user(p, args, 7))
                err = -EFAULT;
@@ -262,17 +262,17 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
                if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
                        return -EACCES;
                if (drive->media == ide_disk)
-                       return ide_taskfile_ioctl(drive, cmd, arg);
+                       return ide_taskfile_ioctl(drive, arg);
                return -ENOMSG;
 #endif
        case HDIO_DRIVE_CMD:
                if (!capable(CAP_SYS_RAWIO))
                        return -EACCES;
-               return ide_cmd_ioctl(drive, cmd, arg);
+               return ide_cmd_ioctl(drive, arg);
        case HDIO_DRIVE_TASK:
                if (!capable(CAP_SYS_RAWIO))
                        return -EACCES;
-               return ide_task_ioctl(drive, cmd, arg);
+               return ide_task_ioctl(drive, arg);
        case HDIO_DRIVE_RESET:
                if (!capable(CAP_SYS_ADMIN))
                        return -EACCES;
index 317c5dadd7c0220b3021049bc2bb2415eb0e0172..27bb70ddd45929572086b1028d3d6bdb3b56d518 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-void SELECT_DRIVE(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-       ide_task_t task;
-
-       if (port_ops && port_ops->selectproc)
-               port_ops->selectproc(drive);
-
-       memset(&task, 0, sizeof(task));
-       task.tf_flags = IDE_TFLAG_OUT_DEVICE;
-
-       drive->hwif->tp_ops->tf_load(drive, &task);
-}
-
 void SELECT_MASK(ide_drive_t *drive, int mask)
 {
        const struct ide_port_ops *port_ops = drive->hwif->port_ops;
@@ -52,14 +37,14 @@ void SELECT_MASK(ide_drive_t *drive, int mask)
 
 u8 ide_read_error(ide_drive_t *drive)
 {
-       ide_task_t task;
+       struct ide_cmd cmd;
 
-       memset(&task, 0, sizeof(task));
-       task.tf_flags = IDE_TFLAG_IN_FEATURE;
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.tf_flags = IDE_TFLAG_IN_ERROR;
 
-       drive->hwif->tp_ops->tf_read(drive, &task);
+       drive->hwif->tp_ops->tf_read(drive, &cmd);
 
-       return task.tf.error;
+       return cmd.tf.error;
 }
 EXPORT_SYMBOL_GPL(ide_read_error);
 
@@ -306,6 +291,7 @@ int ide_driveid_update(ide_drive_t *drive)
        drive->id[ATA_ID_UDMA_MODES]  = id[ATA_ID_UDMA_MODES];
        drive->id[ATA_ID_MWDMA_MODES] = id[ATA_ID_MWDMA_MODES];
        drive->id[ATA_ID_SWDMA_MODES] = id[ATA_ID_SWDMA_MODES];
+       drive->id[ATA_ID_CFA_MODES]   = id[ATA_ID_CFA_MODES];
        /* anything more ? */
 
        kfree(id);
@@ -329,7 +315,7 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
        u16 *id = drive->id, i;
        int error = 0;
        u8 stat;
-       ide_task_t task;
+       struct ide_cmd cmd;
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
        if (hwif->dma_ops)      /* check if host supports DMA */
@@ -356,22 +342,22 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
        disable_irq_nosync(hwif->irq);
 
        udelay(1);
-       SELECT_DRIVE(drive);
+       tp_ops->dev_select(drive);
        SELECT_MASK(drive, 1);
        udelay(1);
-       tp_ops->set_irq(hwif, 0);
+       tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS);
 
-       memset(&task, 0, sizeof(task));
-       task.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT;
-       task.tf.feature = SETFEATURES_XFER;
-       task.tf.nsect   = speed;
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT;
+       cmd.tf.feature = SETFEATURES_XFER;
+       cmd.tf.nsect   = speed;
 
-       tp_ops->tf_load(drive, &task);
+       tp_ops->tf_load(drive, &cmd);
 
        tp_ops->exec_command(hwif, ATA_CMD_SET_FEATURES);
 
        if (drive->quirk_list == 2)
-               tp_ops->set_irq(hwif, 1);
+               tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
 
        error = __ide_wait_stat(drive, drive->ready_stat,
                                ATA_BUSY | ATA_DRQ | ATA_ERR,
@@ -386,9 +372,14 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
                return error;
        }
 
-       id[ATA_ID_UDMA_MODES]  &= ~0xFF00;
-       id[ATA_ID_MWDMA_MODES] &= ~0x0F00;
-       id[ATA_ID_SWDMA_MODES] &= ~0x0F00;
+       if (speed >= XFER_SW_DMA_0) {
+               id[ATA_ID_UDMA_MODES]  &= ~0xFF00;
+               id[ATA_ID_MWDMA_MODES] &= ~0x0700;
+               id[ATA_ID_SWDMA_MODES] &= ~0x0700;
+               if (ata_id_is_cfa(id))
+                       id[ATA_ID_CFA_MODES] &= ~0x0E00;
+       } else  if (ata_id_is_cfa(id))
+               id[ATA_ID_CFA_MODES] &= ~0x01C0;
 
  skip:
 #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -401,12 +392,18 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
        if (speed >= XFER_UDMA_0) {
                i = 1 << (speed - XFER_UDMA_0);
                id[ATA_ID_UDMA_MODES] |= (i << 8 | i);
+       } else if (ata_id_is_cfa(id) && speed >= XFER_MW_DMA_3) {
+               i = speed - XFER_MW_DMA_2;
+               id[ATA_ID_CFA_MODES] |= i << 9;
        } else if (speed >= XFER_MW_DMA_0) {
                i = 1 << (speed - XFER_MW_DMA_0);
                id[ATA_ID_MWDMA_MODES] |= (i << 8 | i);
        } else if (speed >= XFER_SW_DMA_0) {
                i = 1 << (speed - XFER_SW_DMA_0);
                id[ATA_ID_SWDMA_MODES] |= (i << 8 | i);
+       } else if (ata_id_is_cfa(id) && speed >= XFER_PIO_5) {
+               i = speed - XFER_PIO_4;
+               id[ATA_ID_CFA_MODES] |= i << 6;
        }
 
        if (!drive->init_speed)
@@ -425,26 +422,25 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
  * See also ide_execute_command
  */
 void __ide_set_handler(ide_drive_t *drive, ide_handler_t *handler,
-                      unsigned int timeout, ide_expiry_t *expiry)
+                      unsigned int timeout)
 {
        ide_hwif_t *hwif = drive->hwif;
 
        BUG_ON(hwif->handler);
        hwif->handler           = handler;
-       hwif->expiry            = expiry;
        hwif->timer.expires     = jiffies + timeout;
        hwif->req_gen_timer     = hwif->req_gen;
        add_timer(&hwif->timer);
 }
 
-void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
-                     unsigned int timeout, ide_expiry_t *expiry)
+void ide_set_handler(ide_drive_t *drive, ide_handler_t *handler,
+                    unsigned int timeout)
 {
        ide_hwif_t *hwif = drive->hwif;
        unsigned long flags;
 
        spin_lock_irqsave(&hwif->lock, flags);
-       __ide_set_handler(drive, handler, timeout, expiry);
+       __ide_set_handler(drive, handler, timeout);
        spin_unlock_irqrestore(&hwif->lock, flags);
 }
 EXPORT_SYMBOL(ide_set_handler);
@@ -452,10 +448,9 @@ EXPORT_SYMBOL(ide_set_handler);
 /**
  *     ide_execute_command     -       execute an IDE command
  *     @drive: IDE drive to issue the command against
- *     @command: command byte to write
+ *     @cmd: command
  *     @handler: handler for next phase
  *     @timeout: timeout for command
- *     @expiry:  handler to run on timeout
  *
  *     Helper function to issue an IDE command. This handles the
  *     atomicity requirements, command timing and ensures that the
@@ -463,15 +458,18 @@ EXPORT_SYMBOL(ide_set_handler);
  *     should go via this function or do equivalent locking.
  */
 
-void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler,
-                        unsigned timeout, ide_expiry_t *expiry)
+void ide_execute_command(ide_drive_t *drive, struct ide_cmd *cmd,
+                        ide_handler_t *handler, unsigned timeout)
 {
        ide_hwif_t *hwif = drive->hwif;
        unsigned long flags;
 
        spin_lock_irqsave(&hwif->lock, flags);
-       __ide_set_handler(drive, handler, timeout, expiry);
-       hwif->tp_ops->exec_command(hwif, cmd);
+       if ((cmd->protocol != ATAPI_PROT_DMA &&
+            cmd->protocol != ATAPI_PROT_PIO) ||
+           (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT))
+               __ide_set_handler(drive, handler, timeout);
+       hwif->tp_ops->exec_command(hwif, cmd->tf.command);
        /*
         * Drive takes 400nS to respond, we must avoid the IRQ being
         * serviced before that.
@@ -481,19 +479,6 @@ void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler,
        ndelay(400);
        spin_unlock_irqrestore(&hwif->lock, flags);
 }
-EXPORT_SYMBOL(ide_execute_command);
-
-void ide_execute_pkt_cmd(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hwif->lock, flags);
-       hwif->tp_ops->exec_command(hwif, ATA_CMD_PACKET);
-       ndelay(400);
-       spin_unlock_irqrestore(&hwif->lock, flags);
-}
-EXPORT_SYMBOL_GPL(ide_execute_pkt_cmd);
 
 /*
  * ide_wait_not_busy() waits for the currently selected device on the hwif
index f6c683dd29873bad3ef622e6defe6785ed6f1b39..217b7fdf2b1779f7ea881a140ba6bc84e998cc57 100644 (file)
@@ -34,19 +34,19 @@ void ide_toggle_bounce(ide_drive_t *drive, int on)
 static void ide_dump_opcode(ide_drive_t *drive)
 {
        struct request *rq = drive->hwif->rq;
-       ide_task_t *task = NULL;
+       struct ide_cmd *cmd = NULL;
 
        if (!rq)
                return;
 
        if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
-               task = rq->special;
+               cmd = rq->special;
 
        printk(KERN_ERR "ide: failed opcode was: ");
-       if (task == NULL)
+       if (cmd == NULL)
                printk(KERN_CONT "unknown\n");
        else
-               printk(KERN_CONT "0x%02x\n", task->tf.command);
+               printk(KERN_CONT "0x%02x\n", cmd->tf.command);
 }
 
 u64 ide_get_lba_addr(struct ide_taskfile *tf, int lba48)
@@ -66,18 +66,18 @@ EXPORT_SYMBOL_GPL(ide_get_lba_addr);
 
 static void ide_dump_sector(ide_drive_t *drive)
 {
-       ide_task_t task;
-       struct ide_taskfile *tf = &task.tf;
+       struct ide_cmd cmd;
+       struct ide_taskfile *tf = &cmd.tf;
        u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48);
 
-       memset(&task, 0, sizeof(task));
+       memset(&cmd, 0, sizeof(cmd));
        if (lba48)
-               task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_HOB_LBA |
+               cmd.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_HOB_LBA |
                                IDE_TFLAG_LBA48;
        else
-               task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_DEVICE;
+               cmd.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_DEVICE;
 
-       drive->hwif->tp_ops->tf_read(drive, &task);
+       drive->hwif->tp_ops->tf_read(drive, &cmd);
 
        if (lba48 || (tf->device & ATA_LBA))
                printk(KERN_CONT ", LBAsect=%llu",
index f30e52152fcbf1e2d3609998ef282eaf6b9a5f21..9490b446519f44a3082543adf966eb523c3a6397 100644 (file)
@@ -1,6 +1,5 @@
 #include <linux/kernel.h>
 #include <linux/ide.h>
-#include <linux/hdreg.h>
 #include <linux/jiffies.h>
 #include <linux/blkdev.h>
 
@@ -63,10 +62,10 @@ out:
 
 ide_startstop_t ide_do_park_unpark(ide_drive_t *drive, struct request *rq)
 {
-       ide_task_t task;
-       struct ide_taskfile *tf = &task.tf;
+       struct ide_cmd cmd;
+       struct ide_taskfile *tf = &cmd.tf;
 
-       memset(&task, 0, sizeof(task));
+       memset(&cmd, 0, sizeof(cmd));
        if (rq->cmd[0] == REQ_PARK_HEADS) {
                drive->sleep = *(unsigned long *)rq->special;
                drive->dev_flags |= IDE_DFLAG_SLEEPING;
@@ -75,14 +74,16 @@ ide_startstop_t ide_do_park_unpark(ide_drive_t *drive, struct request *rq)
                tf->lbal = 0x4c;
                tf->lbam = 0x4e;
                tf->lbah = 0x55;
-               task.tf_flags |= IDE_TFLAG_CUSTOM_HANDLER;
+               cmd.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
        } else          /* cmd == REQ_UNPARK_HEADS */
                tf->command = ATA_CMD_CHK_POWER;
 
-       task.tf_flags |= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-       task.rq = rq;
-       drive->hwif->data_phase = task.data_phase = TASKFILE_NO_DATA;
-       return do_rw_taskfile(drive, &task);
+       cmd.tf_flags |= IDE_TFLAG_CUSTOM_HANDLER;
+       cmd.protocol = ATA_PROT_NODATA;
+
+       cmd.rq = rq;
+
+       return do_rw_taskfile(drive, &cmd);
 }
 
 ssize_t ide_park_show(struct device *dev, struct device_attribute *attr,
index 60538d9c84ee17005c4ca1f48a086bdda7be5702..bb7858ebb7d19b5499e96d6f13330adb86617009 100644 (file)
@@ -1,6 +1,5 @@
 #include <linux/kernel.h>
 #include <linux/ide.h>
-#include <linux/hdreg.h>
 
 int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 {
@@ -8,7 +7,7 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq;
        struct request_pm_state rqpm;
-       ide_task_t args;
+       struct ide_cmd cmd;
        int ret;
 
        /* call ACPI _GTM only once */
@@ -16,10 +15,10 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
                ide_acpi_get_timing(hwif);
 
        memset(&rqpm, 0, sizeof(rqpm));
-       memset(&args, 0, sizeof(args));
+       memset(&cmd, 0, sizeof(cmd));
        rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
        rq->cmd_type = REQ_TYPE_PM_SUSPEND;
-       rq->special = &args;
+       rq->special = &cmd;
        rq->data = &rqpm;
        rqpm.pm_step = IDE_PM_START_SUSPEND;
        if (mesg.event == PM_EVENT_PRETHAW)
@@ -42,7 +41,7 @@ int generic_ide_resume(struct device *dev)
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq;
        struct request_pm_state rqpm;
-       ide_task_t args;
+       struct ide_cmd cmd;
        int err;
 
        /* call ACPI _PS0 / _STM only once */
@@ -54,11 +53,11 @@ int generic_ide_resume(struct device *dev)
        ide_acpi_exec_tfs(drive);
 
        memset(&rqpm, 0, sizeof(rqpm));
-       memset(&args, 0, sizeof(args));
+       memset(&cmd, 0, sizeof(cmd));
        rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
        rq->cmd_type = REQ_TYPE_PM_RESUME;
        rq->cmd_flags |= REQ_PREEMPT;
-       rq->special = &args;
+       rq->special = &cmd;
        rq->data = &rqpm;
        rqpm.pm_step = IDE_PM_START_RESUME;
        rqpm.pm_state = PM_EVENT_ON;
@@ -109,9 +108,9 @@ void ide_complete_power_step(ide_drive_t *drive, struct request *rq)
 ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
 {
        struct request_pm_state *pm = rq->data;
-       ide_task_t *args = rq->special;
+       struct ide_cmd *cmd = rq->special;
 
-       memset(args, 0, sizeof(*args));
+       memset(cmd, 0, sizeof(*cmd));
 
        switch (pm->pm_step) {
        case IDE_PM_FLUSH_CACHE:        /* Suspend step 1 (flush cache) */
@@ -124,12 +123,12 @@ ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
                        return ide_stopped;
                }
                if (ata_id_flush_ext_enabled(drive->id))
-                       args->tf.command = ATA_CMD_FLUSH_EXT;
+                       cmd->tf.command = ATA_CMD_FLUSH_EXT;
                else
-                       args->tf.command = ATA_CMD_FLUSH;
+                       cmd->tf.command = ATA_CMD_FLUSH;
                goto out_do_tf;
        case IDE_PM_STANDBY:            /* Suspend step 2 (standby) */
-               args->tf.command = ATA_CMD_STANDBYNOW1;
+               cmd->tf.command = ATA_CMD_STANDBYNOW1;
                goto out_do_tf;
        case IDE_PM_RESTORE_PIO:        /* Resume step 1 (restore PIO) */
                ide_set_max_pio(drive);
@@ -142,7 +141,7 @@ ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
                        ide_complete_power_step(drive, rq);
                return ide_stopped;
        case IDE_PM_IDLE:               /* Resume step 2 (idle) */
-               args->tf.command = ATA_CMD_IDLEIMMEDIATE;
+               cmd->tf.command = ATA_CMD_IDLEIMMEDIATE;
                goto out_do_tf;
        case IDE_PM_RESTORE_DMA:        /* Resume step 3 (restore DMA) */
                /*
@@ -160,27 +159,34 @@ ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
        }
 
        pm->pm_step = IDE_PM_COMPLETED;
+
        return ide_stopped;
 
 out_do_tf:
-       args->tf_flags   = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-       args->data_phase = TASKFILE_NO_DATA;
-       return do_rw_taskfile(drive, args);
+       cmd->tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       cmd->protocol = ATA_PROT_NODATA;
+
+       return do_rw_taskfile(drive, cmd);
 }
 
 /**
- *     ide_complete_pm_request - end the current Power Management request
+ *     ide_complete_pm_rq - end the current Power Management request
  *     @drive: target drive
  *     @rq: request
  *
  *     This function cleans up the current PM request and stops the queue
  *     if necessary.
  */
-void ide_complete_pm_request(ide_drive_t *drive, struct request *rq)
+void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq)
 {
        struct request_queue *q = drive->queue;
+       struct request_pm_state *pm = rq->data;
        unsigned long flags;
 
+       ide_complete_power_step(drive, rq);
+       if (pm->pm_step != IDE_PM_COMPLETED)
+               return;
+
 #ifdef DEBUG_PM
        printk("%s: completing PM request, %s\n", drive->name,
               blk_pm_suspend_request(rq) ? "suspend" : "resume");
@@ -217,6 +223,7 @@ void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
                 * point.
                 */
                ide_hwif_t *hwif = drive->hwif;
+               const struct ide_tp_ops *tp_ops = hwif->tp_ops;
                struct request_queue *q = drive->queue;
                unsigned long flags;
                int rc;
@@ -226,8 +233,8 @@ void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
                rc = ide_wait_not_busy(hwif, 35000);
                if (rc)
                        printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
-               SELECT_DRIVE(drive);
-               hwif->tp_ops->set_irq(hwif, 1);
+               tp_ops->dev_select(drive);
+               tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
                rc = ide_wait_not_busy(hwif, 100000);
                if (rc)
                        printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
index bac9b392b68967dfde75c6344cc8af9c6277e79d..6e80b774e88a8fb538c08d98298775eb3514eee0 100644 (file)
@@ -27,6 +27,10 @@ static struct pnp_device_id idepnp_devices[] = {
        {.id = ""}
 };
 
+static const struct ide_port_info ide_pnp_port_info = {
+       .host_flags             = IDE_HFLAG_NO_DMA,
+};
+
 static int idepnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
 {
        struct ide_host *host;
@@ -60,7 +64,7 @@ static int idepnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
        hw.irq = pnp_irq(dev, 0);
        hw.chipset = ide_generic;
 
-       rc = ide_host_add(NULL, hws, &host);
+       rc = ide_host_add(&ide_pnp_port_info, hws, &host);
        if (rc)
                goto out;
 
index 974067043fba350d0e42656a8860968139791d14..d8c1c3e735bb12ea218527c849d5e6b3d4712cae 100644 (file)
@@ -228,15 +228,9 @@ static void do_identify(ide_drive_t *drive, u8 cmd, u16 *id)
        m[ATA_ID_PROD_LEN - 1] = '\0';
 
        if (strstr(m, "E X A B Y T E N E S T"))
-               goto err_misc;
-
-       drive->dev_flags |= IDE_DFLAG_PRESENT;
-       drive->dev_flags &= ~IDE_DFLAG_DEAD;
-
-       return;
-err_misc:
-       kfree(id);
-       drive->dev_flags &= ~IDE_DFLAG_PRESENT;
+               drive->dev_flags &= ~IDE_DFLAG_PRESENT;
+       else
+               drive->dev_flags |= IDE_DFLAG_PRESENT;
 }
 
 /**
@@ -266,7 +260,7 @@ int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id)
         * during the identify phase that the IRQ handler isn't expecting.
         */
        if (io_ports->ctl_addr)
-               tp_ops->set_irq(hwif, 0);
+               tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS);
 
        /* take a deep breath */
        msleep(50);
@@ -289,13 +283,13 @@ int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id)
         * identify command to be sure of reply
         */
        if (cmd == ATA_CMD_ID_ATAPI) {
-               ide_task_t task;
+               struct ide_cmd cmd;
 
-               memset(&task, 0, sizeof(task));
+               memset(&cmd, 0, sizeof(cmd));
                /* disable DMA & overlap */
-               task.tf_flags = IDE_TFLAG_OUT_FEATURE;
+               cmd.tf_flags = IDE_TFLAG_OUT_FEATURE;
 
-               tp_ops->tf_load(drive, &task);
+               tp_ops->tf_load(drive, &cmd);
        }
 
        /* ask drive for ID */
@@ -343,14 +337,14 @@ int ide_busy_sleep(ide_hwif_t *hwif, unsigned long timeout, int altstatus)
 
 static u8 ide_read_device(ide_drive_t *drive)
 {
-       ide_task_t task;
+       struct ide_cmd cmd;
 
-       memset(&task, 0, sizeof(task));
-       task.tf_flags = IDE_TFLAG_IN_DEVICE;
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.tf_flags = IDE_TFLAG_IN_DEVICE;
 
-       drive->hwif->tp_ops->tf_read(drive, &task);
+       drive->hwif->tp_ops->tf_read(drive, &cmd);
 
-       return task.tf.device;
+       return cmd.tf.device;
 }
 
 /**
@@ -396,13 +390,13 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
         * (e.g. crw9624 as drive0 with disk as slave)
         */
        msleep(50);
-       SELECT_DRIVE(drive);
+       tp_ops->dev_select(drive);
        msleep(50);
 
        if (ide_read_device(drive) != drive->select && present == 0) {
                if (drive->dn & 1) {
                        /* exit with drive0 selected */
-                       SELECT_DRIVE(hwif->devices[0]);
+                       tp_ops->dev_select(hwif->devices[0]);
                        /* allow ATA_BUSY to assert & clear */
                        msleep(50);
                }
@@ -428,7 +422,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
                        printk(KERN_ERR "%s: no response (status = 0x%02x), "
                                        "resetting drive\n", drive->name, stat);
                        msleep(50);
-                       SELECT_DRIVE(drive);
+                       tp_ops->dev_select(drive);
                        msleep(50);
                        tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
                        (void)ide_busy_sleep(hwif, WAIT_WORSTCASE, 0);
@@ -447,7 +441,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
        }
        if (drive->dn & 1) {
                /* exit with drive0 selected */
-               SELECT_DRIVE(hwif->devices[0]);
+               tp_ops->dev_select(hwif->devices[0]);
                msleep(50);
                /* ensure drive irq is clear */
                (void)tp_ops->read_status(hwif);
@@ -505,8 +499,7 @@ static u8 probe_for_drive(ide_drive_t *drive)
                }
 
                if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
-                       /* drive not found */
-                       return 0;
+                       goto out_free;
 
                /* identification failed? */
                if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
@@ -530,7 +523,7 @@ static u8 probe_for_drive(ide_drive_t *drive)
        }
 
        if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
-               return 0;
+               goto out_free;
 
        /* The drive wasn't being helpful. Add generic info only */
        if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
@@ -543,7 +536,10 @@ static u8 probe_for_drive(ide_drive_t *drive)
                ide_disk_init_mult_count(drive);
        }
 
-       return !!(drive->dev_flags & IDE_DFLAG_PRESENT);
+       return 1;
+out_free:
+       kfree(drive->id);
+       return 0;
 }
 
 static void hwif_release_dev(struct device *dev)
@@ -609,6 +605,7 @@ out:
 
 static int ide_port_wait_ready(ide_hwif_t *hwif)
 {
+       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
        ide_drive_t *drive;
        int i, rc;
 
@@ -631,8 +628,8 @@ static int ide_port_wait_ready(ide_hwif_t *hwif)
                /* Ignore disks that we will not probe for later. */
                if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0 ||
                    (drive->dev_flags & IDE_DFLAG_PRESENT)) {
-                       SELECT_DRIVE(drive);
-                       hwif->tp_ops->set_irq(hwif, 1);
+                       tp_ops->dev_select(drive);
+                       tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
                        mdelay(2);
                        rc = ide_wait_not_busy(hwif, 35000);
                        if (rc)
@@ -644,7 +641,7 @@ static int ide_port_wait_ready(ide_hwif_t *hwif)
 out:
        /* Exit function with master reselected (let's be sane) */
        if (i)
-               SELECT_DRIVE(hwif->devices[0]);
+               tp_ops->dev_select(hwif->devices[0]);
 
        return rc;
 }
@@ -841,34 +838,19 @@ static int ide_port_setup_devices(ide_hwif_t *hwif)
 static int init_irq (ide_hwif_t *hwif)
 {
        struct ide_io_ports *io_ports = &hwif->io_ports;
-       irq_handler_t irq_handler;
-       int sa = 0;
+       struct ide_host *host = hwif->host;
+       irq_handler_t irq_handler = host->irq_handler;
+       int sa = host->irq_flags;
 
-       irq_handler = hwif->host->irq_handler;
        if (irq_handler == NULL)
                irq_handler = ide_intr;
 
-#if defined(__mc68000__)
-       sa = IRQF_SHARED;
-#endif /* __mc68000__ */
-
-       if (hwif->chipset == ide_pci)
-               sa = IRQF_SHARED;
-
        if (io_ports->ctl_addr)
-               hwif->tp_ops->set_irq(hwif, 1);
+               hwif->tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
 
        if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif))
                goto out_up;
 
-       if (!hwif->rqsize) {
-               if ((hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
-                   (hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA))
-                       hwif->rqsize = 256;
-               else
-                       hwif->rqsize = 65536;
-       }
-
 #if !defined(__mc68000__)
        printk(KERN_INFO "%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
                io_ports->data_addr, io_ports->status_addr,
@@ -961,20 +943,16 @@ EXPORT_SYMBOL_GPL(ide_init_disk);
 static void drive_release_dev (struct device *dev)
 {
        ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
-       ide_hwif_t *hwif = drive->hwif;
 
        ide_proc_unregister_device(drive);
 
-       spin_lock_irq(&hwif->lock);
+       blk_cleanup_queue(drive->queue);
+       drive->queue = NULL;
+
        kfree(drive->id);
        drive->id = NULL;
+
        drive->dev_flags &= ~IDE_DFLAG_PRESENT;
-       /* Messed up locking ... */
-       spin_unlock_irq(&hwif->lock);
-       blk_cleanup_queue(drive->queue);
-       spin_lock_irq(&hwif->lock);
-       drive->queue = NULL;
-       spin_unlock_irq(&hwif->lock);
 
        complete(&drive->gendev_rel_comp);
 }
@@ -1080,7 +1058,7 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
                hwif->tp_ops = d->tp_ops;
 
        /* ->set_pio_mode for DTC2278 is currently limited to port 0 */
-       if (hwif->chipset != ide_dtc2278 || hwif->channel == 0)
+       if ((hwif->host_flags & IDE_HFLAG_DTC2278) == 0 || hwif->channel == 0)
                hwif->port_ops = d->port_ops;
 
        hwif->swdma_mask = d->swdma_mask;
@@ -1114,6 +1092,13 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
 
        if (d->max_sectors)
                hwif->rqsize = d->max_sectors;
+       else {
+               if ((hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
+                   (hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA))
+                       hwif->rqsize = 256;
+               else
+                       hwif->rqsize = 65536;
+       }
 
        /* call chipset specific routine for each enabled port */
        if (d->init_hwif)
@@ -1326,6 +1311,8 @@ struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws)
 
        if (d) {
                host->init_chipset = d->init_chipset;
+               host->get_lock     = d->get_lock;
+               host->release_lock = d->release_lock;
                host->host_flags = d->host_flags;
        }
 
@@ -1372,20 +1359,15 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
                ide_init_port_hw(hwif, hws[i]);
                ide_port_apply_params(hwif);
 
-               if (d == NULL) {
-                       mate = NULL;
-               } else {
-                       if ((i & 1) && mate) {
-                               hwif->mate = mate;
-                               mate->mate = hwif;
-                       }
-
-                       mate = (i & 1) ? NULL : hwif;
-
-                       ide_init_port(hwif, i & 1, d);
-                       ide_port_cable_detect(hwif);
+               if ((i & 1) && mate) {
+                       hwif->mate = mate;
+                       mate->mate = hwif;
                }
 
+               mate = (i & 1) ? NULL : hwif;
+
+               ide_init_port(hwif, i & 1, d);
+               ide_port_cable_detect(hwif);
                ide_port_init_devices(hwif);
        }
 
@@ -1396,8 +1378,8 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
                if (ide_probe_port(hwif) == 0)
                        hwif->present = 1;
 
-               if (hwif->chipset != ide_4drives || !hwif->mate ||
-                   !hwif->mate->present) {
+               if ((hwif->host_flags & IDE_HFLAG_4DRIVES) == 0 ||
+                   hwif->mate == NULL || hwif->mate->present == 0) {
                        if (ide_register_port(hwif)) {
                                ide_disable_port(hwif);
                                continue;
index 417cde56eafd9766815a067a12480743cb28ea1e..10a88bf3eefa8cfc3bd25dce6ea0f334150af764 100644 (file)
@@ -194,20 +194,20 @@ ide_devset_get(xfer_rate, current_speed);
 
 static int set_xfer_rate (ide_drive_t *drive, int arg)
 {
-       ide_task_t task;
+       struct ide_cmd cmd;
        int err;
 
        if (arg < XFER_PIO_0 || arg > XFER_UDMA_6)
                return -EINVAL;
 
-       memset(&task, 0, sizeof(task));
-       task.tf.command = ATA_CMD_SET_FEATURES;
-       task.tf.feature = SETFEATURES_XFER;
-       task.tf.nsect   = (u8)arg;
-       task.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT |
-                       IDE_TFLAG_IN_NSECT;
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.tf.command = ATA_CMD_SET_FEATURES;
+       cmd.tf.feature = SETFEATURES_XFER;
+       cmd.tf.nsect   = (u8)arg;
+       cmd.tf_flags   = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT |
+                        IDE_TFLAG_IN_NSECT;
 
-       err = ide_no_data_taskfile(drive, &task);
+       err = ide_no_data_taskfile(drive, &cmd);
 
        if (!err) {
                ide_set_xfer_rate(drive, (u8) arg);
index 4e6181c7bbdaf613e18a6fdd461cdfdef60afa83..cb942a9b580f6ee66bd9f6d50998a664719625c8 100644 (file)
@@ -152,11 +152,6 @@ struct idetape_bh {
 #define IDETAPE_LU_RETENSION_MASK      2
 #define IDETAPE_LU_EOT_MASK            4
 
-/* Error codes returned in rq->errors to the higher part of the driver. */
-#define IDETAPE_ERROR_GENERAL          101
-#define IDETAPE_ERROR_FILEMARK         102
-#define IDETAPE_ERROR_EOD              103
-
 /* Structures related to the SELECT SENSE / MODE SENSE packet commands. */
 #define IDETAPE_BLOCK_DESCRIPTOR       0
 #define IDETAPE_CAPABILITIES_PAGE      0x2a
@@ -171,14 +166,6 @@ typedef struct ide_tape_obj {
        struct gendisk          *disk;
        struct device           dev;
 
-       /*
-        *      failed_pc points to the last failed packet command, or contains
-        *      NULL if we do not need to retry any packet command. This is
-        *      required since an additional packet command is needed before the
-        *      retry, to get detailed information on what went wrong.
-        */
-       /* Last failed packet command */
-       struct ide_atapi_pc *failed_pc;
        /* used by REQ_IDETAPE_{READ,WRITE} requests */
        struct ide_atapi_pc queued_pc;
 
@@ -245,9 +232,6 @@ typedef struct ide_tape_obj {
        /* Wasted space in each stage */
        int excess_bh_size;
 
-       /* protects the ide-tape queue */
-       spinlock_t lock;
-
        /* Measures average tape speed */
        unsigned long avg_time;
        int avg_size;
@@ -313,19 +297,15 @@ static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
        return tape;
 }
 
-static void idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
+static int idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
                                  unsigned int bcount)
 {
        struct idetape_bh *bh = pc->bh;
        int count;
 
        while (bcount) {
-               if (bh == NULL) {
-                       printk(KERN_ERR "ide-tape: bh == NULL in "
-                               "idetape_input_buffers\n");
-                       ide_pad_transfer(drive, 0, bcount);
-                       return;
-               }
+               if (bh == NULL)
+                       break;
                count = min(
                        (unsigned int)(bh->b_size - atomic_read(&bh->b_count)),
                        bcount);
@@ -339,21 +319,21 @@ static void idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
                                atomic_set(&bh->b_count, 0);
                }
        }
+
        pc->bh = bh;
+
+       return bcount;
 }
 
-static void idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
+static int idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
                                   unsigned int bcount)
 {
        struct idetape_bh *bh = pc->bh;
        int count;
 
        while (bcount) {
-               if (bh == NULL) {
-                       printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
-                                       __func__);
-                       return;
-               }
+               if (bh == NULL)
+                       break;
                count = min((unsigned int)pc->b_count, (unsigned int)bcount);
                drive->hwif->tp_ops->output_data(drive, NULL, pc->b_data, count);
                bcount -= count;
@@ -368,6 +348,8 @@ static void idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
                        }
                }
        }
+
+       return bcount;
 }
 
 static void idetape_update_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc)
@@ -400,7 +382,7 @@ static void idetape_update_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc)
 static void idetape_analyze_error(ide_drive_t *drive, u8 *sense)
 {
        idetape_tape_t *tape = drive->driver_data;
-       struct ide_atapi_pc *pc = tape->failed_pc;
+       struct ide_atapi_pc *pc = drive->failed_pc;
 
        tape->sense_key = sense[2] & 0xF;
        tape->asc       = sense[12];
@@ -433,19 +415,19 @@ static void idetape_analyze_error(ide_drive_t *drive, u8 *sense)
                }
        }
        if (pc->c[0] == READ_6 && (sense[2] & 0x80)) {
-               pc->error = IDETAPE_ERROR_FILEMARK;
+               pc->error = IDE_DRV_ERROR_FILEMARK;
                pc->flags |= PC_FLAG_ABORT;
        }
        if (pc->c[0] == WRITE_6) {
                if ((sense[2] & 0x40) || (tape->sense_key == 0xd
                     && tape->asc == 0x0 && tape->ascq == 0x2)) {
-                       pc->error = IDETAPE_ERROR_EOD;
+                       pc->error = IDE_DRV_ERROR_EOD;
                        pc->flags |= PC_FLAG_ABORT;
                }
        }
        if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) {
                if (tape->sense_key == 8) {
-                       pc->error = IDETAPE_ERROR_EOD;
+                       pc->error = IDE_DRV_ERROR_EOD;
                        pc->flags |= PC_FLAG_ABORT;
                }
                if (!(pc->flags & PC_FLAG_ABORT) &&
@@ -477,52 +459,23 @@ static void ide_tape_kfree_buffer(idetape_tape_t *tape)
        }
 }
 
-static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
-{
-       struct request *rq = drive->hwif->rq;
-       idetape_tape_t *tape = drive->driver_data;
-       unsigned long flags;
-       int error;
-
-       debug_log(DBG_PROCS, "Enter %s\n", __func__);
-
-       switch (uptodate) {
-       case 0: error = IDETAPE_ERROR_GENERAL; break;
-       case 1: error = 0; break;
-       default: error = uptodate;
-       }
-       rq->errors = error;
-       if (error)
-               tape->failed_pc = NULL;
-
-       if (!blk_special_request(rq)) {
-               ide_end_request(drive, uptodate, nr_sects);
-               return 0;
-       }
-
-       spin_lock_irqsave(&tape->lock, flags);
-
-       ide_end_drive_cmd(drive, 0, 0);
-
-       spin_unlock_irqrestore(&tape->lock, flags);
-       return 0;
-}
-
 static void ide_tape_handle_dsc(ide_drive_t *);
 
-static void ide_tape_callback(ide_drive_t *drive, int dsc)
+static int ide_tape_callback(ide_drive_t *drive, int dsc)
 {
        idetape_tape_t *tape = drive->driver_data;
        struct ide_atapi_pc *pc = drive->pc;
+       struct request *rq = drive->hwif->rq;
        int uptodate = pc->error ? 0 : 1;
+       int err = uptodate ? 0 : IDE_DRV_ERROR_GENERAL;
 
        debug_log(DBG_PROCS, "Enter %s\n", __func__);
 
        if (dsc)
                ide_tape_handle_dsc(drive);
 
-       if (tape->failed_pc == pc)
-               tape->failed_pc = NULL;
+       if (drive->failed_pc == pc)
+               drive->failed_pc = NULL;
 
        if (pc->c[0] == REQUEST_SENSE) {
                if (uptodate)
@@ -531,7 +484,6 @@ static void ide_tape_callback(ide_drive_t *drive, int dsc)
                        printk(KERN_ERR "ide-tape: Error in REQUEST SENSE "
                                        "itself - Aborting request!\n");
        } else if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) {
-               struct request *rq = drive->hwif->rq;
                int blocks = pc->xferred / tape->blk_size;
 
                tape->avg_size += blocks * tape->blk_size;
@@ -546,8 +498,10 @@ static void ide_tape_callback(ide_drive_t *drive, int dsc)
                tape->first_frame += blocks;
                rq->current_nr_sectors -= blocks;
 
-               if (pc->error)
-                       uptodate = pc->error;
+               if (pc->error) {
+                       uptodate = 0;
+                       err = pc->error;
+               }
        } else if (pc->c[0] == READ_POSITION && uptodate) {
                u8 *readpos = pc->buf;
 
@@ -561,6 +515,7 @@ static void ide_tape_callback(ide_drive_t *drive, int dsc)
                                         "to the tape\n");
                        clear_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags);
                        uptodate = 0;
+                       err = IDE_DRV_ERROR_GENERAL;
                } else {
                        debug_log(DBG_SENSE, "Block Location - %u\n",
                                        be32_to_cpup((__be32 *)&readpos[4]));
@@ -571,7 +526,9 @@ static void ide_tape_callback(ide_drive_t *drive, int dsc)
                }
        }
 
-       idetape_end_request(drive, uptodate, 0);
+       rq->errors = err;
+
+       return uptodate;
 }
 
 /*
@@ -604,12 +561,14 @@ static void ide_tape_handle_dsc(ide_drive_t *drive)
 static int ide_tape_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
                                unsigned int bcount, int write)
 {
+       unsigned int bleft;
+
        if (write)
-               idetape_output_buffers(drive, pc, bcount);
+               bleft = idetape_output_buffers(drive, pc, bcount);
        else
-               idetape_input_buffers(drive, pc, bcount);
+               bleft = idetape_input_buffers(drive, pc, bcount);
 
-       return bcount;
+       return bcount - bleft;
 }
 
 /*
@@ -621,7 +580,7 @@ static int ide_tape_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
  *
  * The handling will be done in three stages:
  *
- * 1. idetape_issue_pc will send the packet command to the drive, and will set
+ * 1. ide_tape_issue_pc will send the packet command to the drive, and will set
  * the interrupt handler to ide_pc_intr.
  *
  * 2. On each interrupt, ide_pc_intr will be called. This step will be
@@ -649,8 +608,9 @@ static int ide_tape_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
  * request.
  */
 
-static ide_startstop_t idetape_issue_pc(ide_drive_t *drive,
-               struct ide_atapi_pc *pc)
+static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive,
+                                        struct ide_cmd *cmd,
+                                        struct ide_atapi_pc *pc)
 {
        idetape_tape_t *tape = drive->driver_data;
 
@@ -660,8 +620,8 @@ static ide_startstop_t idetape_issue_pc(ide_drive_t *drive,
                        "Two request sense in serial were issued\n");
        }
 
-       if (tape->failed_pc == NULL && pc->c[0] != REQUEST_SENSE)
-               tape->failed_pc = pc;
+       if (drive->failed_pc == NULL && pc->c[0] != REQUEST_SENSE)
+               drive->failed_pc = pc;
 
        /* Set the current packet command */
        drive->pc = pc;
@@ -685,9 +645,9 @@ static ide_startstop_t idetape_issue_pc(ide_drive_t *drive,
                                                tape->ascq);
                        }
                        /* Giving up */
-                       pc->error = IDETAPE_ERROR_GENERAL;
+                       pc->error = IDE_DRV_ERROR_GENERAL;
                }
-               tape->failed_pc = NULL;
+               drive->failed_pc = NULL;
                drive->pc_callback(drive, 0);
                return ide_stopped;
        }
@@ -695,7 +655,7 @@ static ide_startstop_t idetape_issue_pc(ide_drive_t *drive,
 
        pc->retries++;
 
-       return ide_issue_pc(drive);
+       return ide_issue_pc(drive, cmd);
 }
 
 /* A mode sense command is used to "sense" tape parameters. */
@@ -746,8 +706,8 @@ static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive)
                }
                pc->error = 0;
        } else {
-               pc->error = IDETAPE_ERROR_GENERAL;
-               tape->failed_pc = NULL;
+               pc->error = IDE_DRV_ERROR_GENERAL;
+               drive->failed_pc = NULL;
        }
        drive->pc_callback(drive, 0);
        return ide_stopped;
@@ -790,6 +750,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        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: %lu,"
@@ -801,13 +762,15 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                /* We do not support buffer cache originated requests. */
                printk(KERN_NOTICE "ide-tape: %s: Unsupported request in "
                        "request queue (%d)\n", drive->name, rq->cmd_type);
-               ide_end_request(drive, 0, 0);
+               if (blk_fs_request(rq) == 0 && rq->errors == 0)
+                       rq->errors = -EIO;
+               ide_complete_rq(drive, -EIO, ide_rq_bytes(rq));
                return ide_stopped;
        }
 
        /* Retry a failed packet command */
-       if (tape->failed_pc && drive->pc->c[0] == REQUEST_SENSE) {
-               pc = tape->failed_pc;
+       if (drive->failed_pc && drive->pc->c[0] == REQUEST_SENSE) {
+               pc = drive->failed_pc;
                goto out;
        }
 
@@ -815,7 +778,9 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                if (rq != postponed_rq) {
                        printk(KERN_ERR "ide-tape: ide-tape.c bug - "
                                        "Two DSC requests were queued\n");
-                       idetape_end_request(drive, 0, 0);
+                       drive->failed_pc = NULL;
+                       rq->errors = 0;
+                       ide_complete_rq(drive, 0, blk_rq_bytes(rq));
                        return ide_stopped;
                }
 
@@ -881,7 +846,14 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        BUG();
 
 out:
-       return idetape_issue_pc(drive, pc);
+       memset(&cmd, 0, sizeof(cmd));
+
+       if (rq_data_dir(rq))
+               cmd.tf_flags |= IDE_TFLAG_WRITE;
+
+       cmd.rq = rq;
+
+       return ide_tape_issue_pc(drive, &cmd, pc);
 }
 
 /*
@@ -1226,7 +1198,7 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks,
 
        if (tape->merge_bh)
                idetape_init_merge_buffer(tape);
-       if (errors == IDETAPE_ERROR_GENERAL)
+       if (errors == IDE_DRV_ERROR_GENERAL)
                return -EIO;
        return ret;
 }
@@ -2042,9 +2014,13 @@ static void idetape_get_inquiry_results(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        struct ide_atapi_pc pc;
+       u8 pc_buf[256];
        char fw_rev[4], vendor_id[8], product_id[16];
 
        idetape_create_inquiry_cmd(&pc);
+       pc.buf = &pc_buf[0];
+       pc.buf_size = sizeof(pc_buf);
+
        if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
                printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n",
                                tape->name);
@@ -2192,8 +2168,6 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
        drive->pc_update_buffers = idetape_update_buffers;
        drive->pc_io_buffers     = ide_tape_io_buffers;
 
-       spin_lock_init(&tape->lock);
-
        drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
 
        if (drive->hwif->host_flags & IDE_HFLAG_NO_DSC) {
@@ -2325,7 +2299,6 @@ static struct ide_driver idetape_driver = {
        .remove                 = ide_tape_remove,
        .version                = IDETAPE_VERSION,
        .do_request             = idetape_do_request,
-       .end_request            = idetape_end_request,
 #ifdef CONFIG_IDE_PROC_FS
        .proc_entries           = ide_tape_proc_entries,
        .proc_devsets           = ide_tape_proc_devsets,
index 16138bce84a794c88c027029c8a321ba63191067..243421ce40d02ccee63b211f202017782e4d8262 100644 (file)
@@ -39,88 +39,90 @@ void ide_tf_dump(const char *s, struct ide_taskfile *tf)
 
 int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
 {
-       ide_task_t args;
+       struct ide_cmd cmd;
 
-       memset(&args, 0, sizeof(ide_task_t));
-       args.tf.nsect = 0x01;
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.tf.nsect = 0x01;
        if (drive->media == ide_disk)
-               args.tf.command = ATA_CMD_ID_ATA;
+               cmd.tf.command = ATA_CMD_ID_ATA;
        else
-               args.tf.command = ATA_CMD_ID_ATAPI;
-       args.tf_flags   = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-       args.data_phase = TASKFILE_IN;
-       return ide_raw_taskfile(drive, &args, buf, 1);
+               cmd.tf.command = ATA_CMD_ID_ATAPI;
+       cmd.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       cmd.protocol = ATA_PROT_PIO;
+
+       return ide_raw_taskfile(drive, &cmd, buf, 1);
 }
 
 static ide_startstop_t task_no_data_intr(ide_drive_t *);
-static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *);
-static ide_startstop_t task_in_intr(ide_drive_t *);
+static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct ide_cmd *);
+static ide_startstop_t task_pio_intr(ide_drive_t *);
 
-ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
+ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
-       struct ide_taskfile *tf = &task->tf;
+       struct ide_cmd *cmd = &hwif->cmd;
+       struct ide_taskfile *tf = &cmd->tf;
        ide_handler_t *handler = NULL;
        const struct ide_tp_ops *tp_ops = hwif->tp_ops;
        const struct ide_dma_ops *dma_ops = hwif->dma_ops;
 
-       if (task->data_phase == TASKFILE_MULTI_IN ||
-           task->data_phase == TASKFILE_MULTI_OUT) {
-               if (!drive->mult_count) {
-                       printk(KERN_ERR "%s: multimode not set!\n",
-                                       drive->name);
-                       return ide_stopped;
-               }
+       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);
+               return ide_stopped;
        }
 
-       if (task->tf_flags & IDE_TFLAG_FLAGGED)
-               task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS;
+       if (orig_cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
+               orig_cmd->ftf_flags |= IDE_FTFLAG_SET_IN_FLAGS;
 
-       memcpy(&hwif->task, task, sizeof(*task));
+       memcpy(cmd, orig_cmd, sizeof(*cmd));
 
-       if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
+       if ((cmd->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
                ide_tf_dump(drive->name, tf);
-               tp_ops->set_irq(hwif, 1);
+               tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
                SELECT_MASK(drive, 0);
-               tp_ops->tf_load(drive, task);
+
+               if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) {
+                       u8 data[2] = { tf->data, tf->hob_data };
+
+                       tp_ops->output_data(drive, cmd, data, 2);
+               }
+               tp_ops->tf_load(drive, cmd);
        }
 
-       switch (task->data_phase) {
-       case TASKFILE_MULTI_OUT:
-       case TASKFILE_OUT:
-               tp_ops->exec_command(hwif, tf->command);
-               ndelay(400);    /* FIXME */
-               return pre_task_out_intr(drive, task->rq);
-       case TASKFILE_MULTI_IN:
-       case TASKFILE_IN:
-               handler = task_in_intr;
+       switch (cmd->protocol) {
+       case ATA_PROT_PIO:
+               if (cmd->tf_flags & IDE_TFLAG_WRITE) {
+                       tp_ops->exec_command(hwif, tf->command);
+                       ndelay(400);    /* FIXME */
+                       return pre_task_out_intr(drive, cmd);
+               }
+               handler = task_pio_intr;
                /* fall-through */
-       case TASKFILE_NO_DATA:
+       case ATA_PROT_NODATA:
                if (handler == NULL)
                        handler = task_no_data_intr;
-               ide_execute_command(drive, tf->command, handler,
-                                   WAIT_WORSTCASE, NULL);
+               ide_execute_command(drive, cmd, handler, WAIT_WORSTCASE);
                return ide_started;
-       default:
-               if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 ||
-                   dma_ops->dma_setup(drive))
+       case ATA_PROT_DMA:
+               if (ide_dma_prepare(drive, cmd))
                        return ide_stopped;
-               dma_ops->dma_exec_cmd(drive, tf->command);
+               hwif->expiry = dma_ops->dma_timer_expiry;
+               ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD);
                dma_ops->dma_start(drive);
+       default:
                return ide_started;
        }
 }
 EXPORT_SYMBOL_GPL(do_rw_taskfile);
 
-/*
- * Handler for commands without a data phase
- */
 static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
-       ide_task_t *task = &hwif->task;
-       struct ide_taskfile *tf = &task->tf;
-       int custom = (task->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0;
+       struct ide_cmd *cmd = &hwif->cmd;
+       struct ide_taskfile *tf = &cmd->tf;
+       int custom = (cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0;
        int retries = (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) ? 5 : 1;
        u8 stat;
 
@@ -142,28 +144,26 @@ static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
                } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) {
                        if ((stat & (ATA_ERR | ATA_DRQ)) == 0) {
                                ide_set_handler(drive, &task_no_data_intr,
-                                               WAIT_WORSTCASE, NULL);
+                                               WAIT_WORSTCASE);
                                return ide_started;
                        }
                }
                return ide_error(drive, "task_no_data_intr", stat);
-               /* calls ide_end_drive_cmd */
        }
 
-       if (!custom)
-               ide_end_drive_cmd(drive, stat, ide_read_error(drive));
-       else if (tf->command == ATA_CMD_IDLEIMMEDIATE) {
-               hwif->tp_ops->tf_read(drive, task);
-               if (tf->lbal != 0xc4) {
-                       printk(KERN_ERR "%s: head unload failed!\n",
-                              drive->name);
-                       ide_tf_dump(drive->name, tf);
-               } else
-                       drive->dev_flags |= IDE_DFLAG_PARKED;
-               ide_end_drive_cmd(drive, stat, ide_read_error(drive));
-       } else if (tf->command == ATA_CMD_SET_MULTI)
+       if (custom && tf->command == ATA_CMD_SET_MULTI)
                drive->mult_count = drive->mult_req;
 
+       if (custom == 0 || tf->command == ATA_CMD_IDLEIMMEDIATE ||
+           tf->command == ATA_CMD_CHK_POWER) {
+               struct request *rq = hwif->rq;
+
+               if (blk_pm_request(rq))
+                       ide_complete_pm_rq(drive, rq);
+               else
+                       ide_finish_cmd(drive, cmd, stat);
+       }
+
        return ide_stopped;
 }
 
@@ -192,239 +192,188 @@ static u8 wait_drive_not_busy(ide_drive_t *drive)
        return stat;
 }
 
-static void ide_pio_sector(ide_drive_t *drive, struct request *rq,
-                          unsigned int write)
+void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
+                  unsigned int write, unsigned int len)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct scatterlist *sg = hwif->sg_table;
-       struct scatterlist *cursg = hwif->cursg;
+       struct scatterlist *cursg = cmd->cursg;
        struct page *page;
-#ifdef CONFIG_HIGHMEM
        unsigned long flags;
-#endif
        unsigned int offset;
        u8 *buf;
 
-       cursg = hwif->cursg;
-       if (!cursg) {
-               cursg = sg;
-               hwif->cursg = sg;
-       }
+       cursg = cmd->cursg;
+       if (cursg == NULL)
+               cursg = cmd->cursg = sg;
 
-       page = sg_page(cursg);
-       offset = cursg->offset + hwif->cursg_ofs * SECTOR_SIZE;
+       while (len) {
+               unsigned nr_bytes = min(len, cursg->length - cmd->cursg_ofs);
 
-       /* get the current page and offset */
-       page = nth_page(page, (offset >> PAGE_SHIFT));
-       offset %= PAGE_SIZE;
+               if (nr_bytes > PAGE_SIZE)
+                       nr_bytes = PAGE_SIZE;
 
-#ifdef CONFIG_HIGHMEM
-       local_irq_save(flags);
-#endif
-       buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset;
+               page = sg_page(cursg);
+               offset = cursg->offset + cmd->cursg_ofs;
 
-       hwif->nleft--;
-       hwif->cursg_ofs++;
+               /* get the current page and offset */
+               page = nth_page(page, (offset >> PAGE_SHIFT));
+               offset %= PAGE_SIZE;
 
-       if ((hwif->cursg_ofs * SECTOR_SIZE) == cursg->length) {
-               hwif->cursg = sg_next(hwif->cursg);
-               hwif->cursg_ofs = 0;
-       }
+               if (PageHighMem(page))
+                       local_irq_save(flags);
 
-       /* do the actual data transfer */
-       if (write)
-               hwif->tp_ops->output_data(drive, rq, buf, SECTOR_SIZE);
-       else
-               hwif->tp_ops->input_data(drive, rq, buf, SECTOR_SIZE);
+               buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset;
 
-       kunmap_atomic(buf, KM_BIO_SRC_IRQ);
-#ifdef CONFIG_HIGHMEM
-       local_irq_restore(flags);
-#endif
-}
+               cmd->nleft -= nr_bytes;
+               cmd->cursg_ofs += nr_bytes;
 
-static void ide_pio_multi(ide_drive_t *drive, struct request *rq,
-                         unsigned int write)
-{
-       unsigned int nsect;
+               if (cmd->cursg_ofs == cursg->length) {
+                       cursg = cmd->cursg = sg_next(cmd->cursg);
+                       cmd->cursg_ofs = 0;
+               }
+
+               /* do the actual data transfer */
+               if (write)
+                       hwif->tp_ops->output_data(drive, cmd, buf, nr_bytes);
+               else
+                       hwif->tp_ops->input_data(drive, cmd, buf, nr_bytes);
+
+               kunmap_atomic(buf, KM_BIO_SRC_IRQ);
+
+               if (PageHighMem(page))
+                       local_irq_restore(flags);
 
-       nsect = min_t(unsigned int, drive->hwif->nleft, drive->mult_count);
-       while (nsect--)
-               ide_pio_sector(drive, rq, write);
+               len -= nr_bytes;
+       }
 }
+EXPORT_SYMBOL_GPL(ide_pio_bytes);
 
-static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
-                                    unsigned int write)
+static void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd,
+                             unsigned int write)
 {
-       u8 saved_io_32bit = drive->io_32bit;
+       unsigned int nr_bytes;
 
-       if (rq->bio)    /* fs request */
-               rq->errors = 0;
+       u8 saved_io_32bit = drive->io_32bit;
 
-       if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-               ide_task_t *task = rq->special;
+       if (cmd->tf_flags & IDE_TFLAG_FS)
+               cmd->rq->errors = 0;
 
-               if (task->tf_flags & IDE_TFLAG_IO_16BIT)
-                       drive->io_32bit = 0;
-       }
+       if (cmd->tf_flags & IDE_TFLAG_IO_16BIT)
+               drive->io_32bit = 0;
 
        touch_softlockup_watchdog();
 
-       switch (drive->hwif->data_phase) {
-       case TASKFILE_MULTI_IN:
-       case TASKFILE_MULTI_OUT:
-               ide_pio_multi(drive, rq, write);
-               break;
-       default:
-               ide_pio_sector(drive, rq, write);
-               break;
-       }
+       if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO)
+               nr_bytes = min_t(unsigned, cmd->nleft, drive->mult_count << 9);
+       else
+               nr_bytes = SECTOR_SIZE;
+
+       ide_pio_bytes(drive, cmd, write, nr_bytes);
 
        drive->io_32bit = saved_io_32bit;
 }
 
-static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
-                                 const char *s, u8 stat)
+static void ide_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd)
 {
-       if (rq->bio) {
-               ide_hwif_t *hwif = drive->hwif;
-               int sectors = hwif->nsect - hwif->nleft;
-
-               switch (hwif->data_phase) {
-               case TASKFILE_IN:
-                       if (hwif->nleft)
-                               break;
-                       /* fall through */
-               case TASKFILE_OUT:
-                       sectors--;
-                       break;
-               case TASKFILE_MULTI_IN:
-                       if (hwif->nleft)
-                               break;
-                       /* fall through */
-               case TASKFILE_MULTI_OUT:
-                       sectors -= drive->mult_count;
-               default:
-                       break;
+       if (cmd->tf_flags & IDE_TFLAG_FS) {
+               int nr_bytes = cmd->nbytes - cmd->nleft;
+
+               if (cmd->protocol == ATA_PROT_PIO &&
+                   ((cmd->tf_flags & IDE_TFLAG_WRITE) || cmd->nleft == 0)) {
+                       if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO)
+                               nr_bytes -= drive->mult_count << 9;
+                       else
+                               nr_bytes -= SECTOR_SIZE;
                }
 
-               if (sectors > 0) {
-                       struct ide_driver *drv;
-
-                       drv = *(struct ide_driver **)rq->rq_disk->private_data;
-                       drv->end_request(drive, 1, sectors);
-               }
+               if (nr_bytes > 0)
+                       ide_complete_rq(drive, 0, nr_bytes);
        }
-       return ide_error(drive, s, stat);
 }
 
-void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
+void ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat)
 {
-       if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-               u8 err = ide_read_error(drive);
-
-               ide_end_drive_cmd(drive, stat, err);
-               return;
-       }
-
-       if (rq->rq_disk) {
-               struct ide_driver *drv;
+       struct request *rq = drive->hwif->rq;
+       u8 err = ide_read_error(drive);
 
-               drv = *(struct ide_driver **)rq->rq_disk->private_data;;
-               drv->end_request(drive, 1, rq->nr_sectors);
-       } else
-               ide_end_request(drive, 1, rq->nr_sectors);
+       ide_complete_cmd(drive, cmd, stat, err);
+       rq->errors = err;
+       ide_complete_rq(drive, err ? -EIO : 0, blk_rq_bytes(rq));
 }
 
 /*
- * We got an interrupt on a task_in case, but no errors and no DRQ.
- *
- * It might be a spurious irq (shared irq), but it might be a
- * command that had no output.
+ * Handler for command with PIO data phase.
  */
-static ide_startstop_t task_in_unexpected(ide_drive_t *drive, struct request *rq, u8 stat)
-{
-       /* Command all done? */
-       if (OK_STAT(stat, ATA_DRDY, ATA_BUSY)) {
-               task_end_request(drive, rq, stat);
-               return ide_stopped;
-       }
-
-       /* Assume it was a spurious irq */
-       ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
-       return ide_started;
-}
-
-/*
- * Handler for command with PIO data-in phase (Read/Read Multiple).
- */
-static ide_startstop_t task_in_intr(ide_drive_t *drive)
+static ide_startstop_t task_pio_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
-       struct request *rq = hwif->rq;
+       struct ide_cmd *cmd = &drive->hwif->cmd;
        u8 stat = hwif->tp_ops->read_status(hwif);
+       u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
 
-       /* Error? */
-       if (stat & ATA_ERR)
-               return task_error(drive, rq, __func__, stat);
+       if (write == 0) {
+               /* Error? */
+               if (stat & ATA_ERR)
+                       goto out_err;
 
-       /* Didn't want any data? Odd. */
-       if ((stat & ATA_DRQ) == 0)
-               return task_in_unexpected(drive, rq, stat);
+               /* Didn't want any data? Odd. */
+               if ((stat & ATA_DRQ) == 0) {
+                       /* Command all done? */
+                       if (OK_STAT(stat, ATA_DRDY, ATA_BUSY))
+                               goto out_end;
 
-       ide_pio_datablock(drive, rq, 0);
+                       /* Assume it was a spurious irq */
+                       goto out_wait;
+               }
+       } else {
+               if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat))
+                       goto out_err;
 
-       /* Are we done? Check status and finish transfer. */
-       if (!hwif->nleft) {
-               stat = wait_drive_not_busy(drive);
-               if (!OK_STAT(stat, 0, BAD_STAT))
-                       return task_error(drive, rq, __func__, stat);
-               task_end_request(drive, rq, stat);
-               return ide_stopped;
+               /* Deal with unexpected ATA data phase. */
+               if (((stat & ATA_DRQ) == 0) ^ (cmd->nleft == 0))
+                       goto out_err;
        }
 
-       /* Still data left to transfer. */
-       ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
-
-       return ide_started;
-}
-
-/*
- * Handler for command with PIO data-out phase (Write/Write Multiple).
- */
-static ide_startstop_t task_out_intr (ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct request *rq = hwif->rq;
-       u8 stat = hwif->tp_ops->read_status(hwif);
+       if (write && cmd->nleft == 0)
+               goto out_end;
 
-       if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat))
-               return task_error(drive, rq, __func__, stat);
+       /* Still data left to transfer. */
+       ide_pio_datablock(drive, cmd, write);
 
-       /* Deal with unexpected ATA data phase. */
-       if (((stat & ATA_DRQ) == 0) ^ !hwif->nleft)
-               return task_error(drive, rq, __func__, stat);
+       /* Are we done? Check status and finish transfer. */
+       if (write == 0 && cmd->nleft == 0) {
+               stat = wait_drive_not_busy(drive);
+               if (!OK_STAT(stat, 0, BAD_STAT))
+                       goto out_err;
 
-       if (!hwif->nleft) {
-               task_end_request(drive, rq, stat);
-               return ide_stopped;
+               goto out_end;
        }
-
+out_wait:
        /* Still data left to transfer. */
-       ide_pio_datablock(drive, rq, 1);
-       ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
-
+       ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE);
        return ide_started;
+out_end:
+       if ((cmd->tf_flags & IDE_TFLAG_FS) == 0)
+               ide_finish_cmd(drive, cmd, stat);
+       else
+               ide_complete_rq(drive, 0, cmd->rq->nr_sectors << 9);
+       return ide_stopped;
+out_err:
+       ide_error_cmd(drive, cmd);
+       return ide_error(drive, __func__, stat);
 }
 
-static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
+static ide_startstop_t pre_task_out_intr(ide_drive_t *drive,
+                                        struct ide_cmd *cmd)
 {
        ide_startstop_t startstop;
 
        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, drive->hwif->data_phase ? "MULT" : "",
+                       drive->name,
+                       (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) ? "MULT" : "",
                        (drive->dev_flags & IDE_DFLAG_LBA48) ? "_EXT" : "");
                return startstop;
        }
@@ -432,13 +381,15 @@ static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
        if ((drive->dev_flags & IDE_DFLAG_UNMASK) == 0)
                local_irq_disable();
 
-       ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
-       ide_pio_datablock(drive, rq, 1);
+       ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE);
+
+       ide_pio_datablock(drive, cmd, 1);
 
        return ide_started;
 }
 
-int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect)
+int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf,
+                    u16 nsect)
 {
        struct request *rq;
        int error;
@@ -456,11 +407,11 @@ int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect)
        rq->hard_nr_sectors = rq->nr_sectors = nsect;
        rq->hard_cur_sectors = rq->current_nr_sectors = nsect;
 
-       if (task->tf_flags & IDE_TFLAG_WRITE)
+       if (cmd->tf_flags & IDE_TFLAG_WRITE)
                rq->cmd_flags |= REQ_RW;
 
-       rq->special = task;
-       task->rq = rq;
+       rq->special = cmd;
+       cmd->rq = rq;
 
        error = blk_execute_rq(drive->queue, NULL, rq, 0);
        blk_put_request(rq);
@@ -470,19 +421,19 @@ int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect)
 
 EXPORT_SYMBOL(ide_raw_taskfile);
 
-int ide_no_data_taskfile(ide_drive_t *drive, ide_task_t *task)
+int ide_no_data_taskfile(ide_drive_t *drive, struct ide_cmd *cmd)
 {
-       task->data_phase = TASKFILE_NO_DATA;
+       cmd->protocol = ATA_PROT_NODATA;
 
-       return ide_raw_taskfile(drive, task, NULL, 0);
+       return ide_raw_taskfile(drive, cmd, NULL, 0);
 }
 EXPORT_SYMBOL_GPL(ide_no_data_taskfile);
 
 #ifdef CONFIG_IDE_TASK_IOCTL
-int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+int ide_taskfile_ioctl(ide_drive_t *drive, unsigned long arg)
 {
        ide_task_request_t      *req_task;
-       ide_task_t              args;
+       struct ide_cmd          cmd;
        u8 *outbuf              = NULL;
        u8 *inbuf               = NULL;
        u8 *data_buf            = NULL;
@@ -536,53 +487,63 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
                }
        }
 
-       memset(&args, 0, sizeof(ide_task_t));
+       memset(&cmd, 0, sizeof(cmd));
 
-       memcpy(&args.tf_array[0], req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2);
-       memcpy(&args.tf_array[6], req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
+       memcpy(&cmd.tf_array[0], req_task->hob_ports,
+              HDIO_DRIVE_HOB_HDR_SIZE - 2);
+       memcpy(&cmd.tf_array[6], req_task->io_ports,
+              HDIO_DRIVE_TASK_HDR_SIZE);
 
-       args.data_phase = req_task->data_phase;
+       cmd.tf_flags   = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE |
+                        IDE_TFLAG_IN_TF;
 
-       args.tf_flags = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE |
-                       IDE_TFLAG_IN_TF;
        if (drive->dev_flags & IDE_DFLAG_LBA48)
-               args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB);
+               cmd.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB);
 
        if (req_task->out_flags.all) {
-               args.tf_flags |= IDE_TFLAG_FLAGGED;
+               cmd.ftf_flags |= IDE_FTFLAG_FLAGGED;
 
                if (req_task->out_flags.b.data)
-                       args.tf_flags |= IDE_TFLAG_OUT_DATA;
+                       cmd.ftf_flags |= IDE_FTFLAG_OUT_DATA;
 
                if (req_task->out_flags.b.nsector_hob)
-                       args.tf_flags |= IDE_TFLAG_OUT_HOB_NSECT;
+                       cmd.tf_flags |= IDE_TFLAG_OUT_HOB_NSECT;
                if (req_task->out_flags.b.sector_hob)
-                       args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAL;
+                       cmd.tf_flags |= IDE_TFLAG_OUT_HOB_LBAL;
                if (req_task->out_flags.b.lcyl_hob)
-                       args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAM;
+                       cmd.tf_flags |= IDE_TFLAG_OUT_HOB_LBAM;
                if (req_task->out_flags.b.hcyl_hob)
-                       args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAH;
+                       cmd.tf_flags |= IDE_TFLAG_OUT_HOB_LBAH;
 
                if (req_task->out_flags.b.error_feature)
-                       args.tf_flags |= IDE_TFLAG_OUT_FEATURE;
+                       cmd.tf_flags |= IDE_TFLAG_OUT_FEATURE;
                if (req_task->out_flags.b.nsector)
-                       args.tf_flags |= IDE_TFLAG_OUT_NSECT;
+                       cmd.tf_flags |= IDE_TFLAG_OUT_NSECT;
                if (req_task->out_flags.b.sector)
-                       args.tf_flags |= IDE_TFLAG_OUT_LBAL;
+                       cmd.tf_flags |= IDE_TFLAG_OUT_LBAL;
                if (req_task->out_flags.b.lcyl)
-                       args.tf_flags |= IDE_TFLAG_OUT_LBAM;
+                       cmd.tf_flags |= IDE_TFLAG_OUT_LBAM;
                if (req_task->out_flags.b.hcyl)
-                       args.tf_flags |= IDE_TFLAG_OUT_LBAH;
+                       cmd.tf_flags |= IDE_TFLAG_OUT_LBAH;
        } else {
-               args.tf_flags |= IDE_TFLAG_OUT_TF;
-               if (args.tf_flags & IDE_TFLAG_LBA48)
-                       args.tf_flags |= IDE_TFLAG_OUT_HOB;
+               cmd.tf_flags |= IDE_TFLAG_OUT_TF;
+               if (cmd.tf_flags & IDE_TFLAG_LBA48)
+                       cmd.tf_flags |= IDE_TFLAG_OUT_HOB;
        }
 
        if (req_task->in_flags.b.data)
-               args.tf_flags |= IDE_TFLAG_IN_DATA;
+               cmd.ftf_flags |= IDE_FTFLAG_IN_DATA;
+
+       if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE) {
+               /* fixup data phase if needed */
+               if (req_task->data_phase == TASKFILE_IN_DMAQ ||
+                   req_task->data_phase == TASKFILE_IN_DMA)
+                       cmd.tf_flags |= IDE_TFLAG_WRITE;
+       }
 
-       switch(req_task->data_phase) {
+       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 */
@@ -592,11 +553,14 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
                                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;
@@ -609,8 +573,10 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
                                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:
@@ -618,6 +584,7 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
                        data_buf = inbuf;
                        break;
                case TASKFILE_NO_DATA:
+                       cmd.protocol = ATA_PROT_NODATA;
                        break;
                default:
                        err = -EFAULT;
@@ -627,7 +594,7 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
        if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA)
                nsect = 0;
        else if (!nsect) {
-               nsect = (args.tf.hob_nsect << 8) | args.tf.nsect;
+               nsect = (cmd.tf.hob_nsect << 8) | cmd.tf.nsect;
 
                if (!nsect) {
                        printk(KERN_ERR "%s: in/out command without data\n",
@@ -637,15 +604,14 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
                }
        }
 
-       if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE)
-               args.tf_flags |= IDE_TFLAG_WRITE;
-
-       err = ide_raw_taskfile(drive, &args, data_buf, nsect);
+       err = ide_raw_taskfile(drive, &cmd, data_buf, nsect);
 
-       memcpy(req_task->hob_ports, &args.tf_array[0], HDIO_DRIVE_HOB_HDR_SIZE - 2);
-       memcpy(req_task->io_ports, &args.tf_array[6], HDIO_DRIVE_TASK_HDR_SIZE);
+       memcpy(req_task->hob_ports, &cmd.tf_array[0],
+              HDIO_DRIVE_HOB_HDR_SIZE - 2);
+       memcpy(req_task->io_ports, &cmd.tf_array[6],
+              HDIO_DRIVE_TASK_HDR_SIZE);
 
-       if ((args.tf_flags & IDE_TFLAG_FLAGGED_SET_IN_FLAGS) &&
+       if ((cmd.ftf_flags & IDE_FTFLAG_SET_IN_FLAGS) &&
            req_task->in_flags.all == 0) {
                req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
                if (drive->dev_flags & IDE_DFLAG_LBA48)
index 81f527af8fae75f097d4ba29d80d9d7929a15b74..001a56365be577691ad8227c244d5ee88f01965d 100644 (file)
@@ -43,6 +43,8 @@ static struct ide_timing ide_timing[] = {
        { XFER_UDMA_1,     0,   0,   0,   0,   0,   0,   0,  80 },
        { XFER_UDMA_0,     0,   0,   0,   0,   0,   0,   0, 120 },
 
+       { XFER_MW_DMA_4,  25,   0,   0,   0,  55,  20,  80,   0 },
+       { XFER_MW_DMA_3,  25,   0,   0,   0,  65,  25, 100,   0 },
        { XFER_MW_DMA_2,  25,   0,   0,   0,  70,  25, 120,   0 },
        { XFER_MW_DMA_1,  45,   0,   0,   0,  80,  50, 150,   0 },
        { XFER_MW_DMA_0,  60,   0,   0,   0, 215, 215, 480,   0 },
@@ -51,7 +53,8 @@ static struct ide_timing ide_timing[] = {
        { XFER_SW_DMA_1,  90,   0,   0,   0, 240, 240, 480,   0 },
        { XFER_SW_DMA_0, 120,   0,   0,   0, 480, 480, 960,   0 },
 
-       { XFER_PIO_5,     20,  50,  30, 100,  50,  30, 100,   0 },
+       { XFER_PIO_6,     10,  55,  20,  80,  55,  20,  80,   0 },
+       { XFER_PIO_5,     15,  65,  25, 100,  65,  25, 100,   0 },
        { XFER_PIO_4,     25,  70,  25, 120,  70,  25, 120,   0 },
        { XFER_PIO_3,     30,  80,  70, 180,  80,  70, 180,   0 },
 
@@ -90,6 +93,10 @@ u16 ide_pio_cycle_time(ide_drive_t *drive, u8 pio)
                /* conservative "downgrade" for all pre-ATA2 drives */
                if (pio < 3 && cycle < t->cycle)
                        cycle = 0; /* use standard timing */
+
+               /* Use the standard timing for the CF specific modes too */
+               if (pio > 4 && ata_id_is_cfa(id))
+                       cycle = 0;
        }
 
        return cycle ? cycle : t->cycle;
@@ -161,7 +168,8 @@ int ide_timing_compute(ide_drive_t *drive, u8 speed,
 
                if (speed <= XFER_PIO_2)
                        p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO];
-               else if (speed <= XFER_PIO_5)
+               else if ((speed <= XFER_PIO_4) ||
+                        (speed == XFER_PIO_5 && !ata_id_is_cfa(id)))
                        p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY];
                else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
                        p.cycle = id[ATA_ID_EIDE_DMA_MIN];
index 6910f6a257e86861168996d826e635dca0b009d7..af44be9d546cedf4283cf78458f3eaf2dbaa4136 100644 (file)
@@ -9,11 +9,11 @@ static const char *udma_str[] =
         { "UDMA/16", "UDMA/25",  "UDMA/33",  "UDMA/44",
           "UDMA/66", "UDMA/100", "UDMA/133", "UDMA7" };
 static const char *mwdma_str[] =
-       { "MWDMA0", "MWDMA1", "MWDMA2" };
+       { "MWDMA0", "MWDMA1", "MWDMA2", "MWDMA3", "MWDMA4" };
 static const char *swdma_str[] =
        { "SWDMA0", "SWDMA1", "SWDMA2" };
 static const char *pio_str[] =
-       { "PIO0", "PIO1", "PIO2", "PIO3", "PIO4", "PIO5" };
+       { "PIO0", "PIO1", "PIO2", "PIO3", "PIO4", "PIO5", "PIO6" };
 
 /**
  *     ide_xfer_verbose        -       return IDE mode names
@@ -30,11 +30,11 @@ const char *ide_xfer_verbose(u8 mode)
 
        if (mode >= XFER_UDMA_0 && mode <= XFER_UDMA_7)
                s = udma_str[i];
-       else if (mode >= XFER_MW_DMA_0 && mode <= XFER_MW_DMA_2)
+       else if (mode >= XFER_MW_DMA_0 && mode <= XFER_MW_DMA_4)
                s = mwdma_str[i];
        else if (mode >= XFER_SW_DMA_0 && mode <= XFER_SW_DMA_2)
                s = swdma_str[i];
-       else if (mode >= XFER_PIO_0 && mode <= XFER_PIO_5)
+       else if (mode >= XFER_PIO_0 && mode <= XFER_PIO_6)
                s = pio_str[i & 0x7];
        else if (mode == XFER_PIO_SLOW)
                s = "PIO SLOW";
@@ -79,7 +79,10 @@ u8 ide_get_best_pio_mode(ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
                }
 
                if (id[ATA_ID_FIELD_VALID] & 2) {             /* ATA2? */
-                       if (ata_id_has_iordy(id)) {
+                       if (ata_id_is_cfa(id) && (id[ATA_ID_CFA_MODES] & 7))
+                               pio_mode = 4 + min_t(int, 2,
+                                                    id[ATA_ID_CFA_MODES] & 7);
+                       else if (ata_id_has_iordy(id)) {
                                if (id[ATA_ID_PIO_MODES] & 7) {
                                        overridden = 0;
                                        if (id[ATA_ID_PIO_MODES] & 4)
@@ -239,7 +242,7 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
 
        BUG_ON(rate < XFER_PIO_0);
 
-       if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5)
+       if (rate >= XFER_PIO_0 && rate <= XFER_PIO_6)
                return ide_set_pio_mode(drive, rate);
 
        return ide_set_dma_mode(drive, rate);
diff --git a/drivers/ide/ide_arm.c b/drivers/ide/ide_arm.c
deleted file mode 100644 (file)
index bdcac94..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * ARM default IDE host driver
- *
- * Copyright (C) 2004 Bartlomiej Zolnierkiewicz
- * Based on code by: Russell King, Ian Molton and Alexander Schulz.
- *
- * May be copied or modified under the terms of the GNU General Public License.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/irq.h>
-
-#define DRV_NAME "ide_arm"
-
-#define IDE_ARM_IO     0x1f0
-#define IDE_ARM_IRQ    IRQ_HARDDISK
-
-static int __init ide_arm_init(void)
-{
-       unsigned long base = IDE_ARM_IO, ctl = IDE_ARM_IO + 0x206;
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
-
-       if (!request_region(base, 8, DRV_NAME)) {
-               printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
-                               DRV_NAME, base, base + 7);
-               return -EBUSY;
-       }
-
-       if (!request_region(ctl, 1, DRV_NAME)) {
-               printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
-                               DRV_NAME, ctl);
-               release_region(base, 8);
-               return -EBUSY;
-       }
-
-       memset(&hw, 0, sizeof(hw));
-       ide_std_init_ports(&hw, base, ctl);
-       hw.irq = IDE_ARM_IRQ;
-       hw.chipset = ide_generic;
-
-       return ide_host_add(NULL, hws, NULL);
-}
-
-module_init(ide_arm_init);
-
-MODULE_LICENSE("GPL");
index 6b9fc950b4af7af786e36e2858a3246979ee48a4..51aa745246dcb9551af49161014f533bd4d4e43c 100644 (file)
@@ -508,12 +508,11 @@ static void it821x_quirkproc(ide_drive_t *drive)
 static struct ide_dma_ops it821x_pass_through_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
        .dma_setup              = ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = it821x_dma_start,
        .dma_end                = it821x_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
-       .dma_timeout            = ide_dma_timeout,
        .dma_lost_irq           = ide_dma_lost_irq,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
index 3c60064f1d4f757a3bf06193af4267b9b226ca58..4b1718e832839186c12673f8b589022ba115c55a 100644 (file)
@@ -80,6 +80,11 @@ static void __init macide_setup_ports(hw_regs_t *hw, unsigned long base,
        hw->chipset = ide_generic;
 }
 
+static const struct ide_port_info macide_port_info = {
+       .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
+       .irq_flags              = IRQF_SHARED,
+};
+
 static const char *mac_ide_name[] =
        { "Quadra", "Powerbook", "Powerbook Baboon" };
 
@@ -122,7 +127,7 @@ static int __init macide_init(void)
 
        macide_setup_ports(&hw, base, irq, ack_intr);
 
-       return ide_host_add(NULL, hws, NULL);
+       return ide_host_add(&macide_port_info, hws, NULL);
 }
 
 module_init(macide_init);
index ea48a3ee8063960b3a2b204b99a8d9d639a9541f..71a39fb3856fee4a742646e76ffd6a5cc84b18b8 100644 (file)
@@ -61,57 +61,52 @@ static u8 superio_dma_sff_read_status(ide_hwif_t *hwif)
        return superio_ide_inb(hwif->dma_base + ATA_DMA_STATUS);
 }
 
-static void superio_tf_read(ide_drive_t *drive, ide_task_t *task)
+static void superio_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        struct ide_io_ports *io_ports = &drive->hwif->io_ports;
-       struct ide_taskfile *tf = &task->tf;
-
-       if (task->tf_flags & IDE_TFLAG_IN_DATA) {
-               u16 data = inw(io_ports->data_addr);
-
-               tf->data = data & 0xff;
-               tf->hob_data = (data >> 8) & 0xff;
-       }
+       struct ide_taskfile *tf = &cmd->tf;
 
        /* be sure we're looking at the low order bits */
-       outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+       outb(ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-       if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
-               tf->feature = inb(io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_IN_ERROR)
+               tf->error  = inb(io_ports->feature_addr);
+       if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
                tf->nsect  = inb(io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
                tf->lbal   = inb(io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAM)
                tf->lbam   = inb(io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAH)
                tf->lbah   = inb(io_ports->lbah_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+       if (cmd->tf_flags & IDE_TFLAG_IN_DEVICE)
                tf->device = superio_ide_inb(io_ports->device_addr);
 
-       if (task->tf_flags & IDE_TFLAG_LBA48) {
-               outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
-
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
-                       tf->hob_feature = inb(io_ports->feature_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
-                       tf->hob_nsect   = inb(io_ports->nsect_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
-                       tf->hob_lbal    = inb(io_ports->lbal_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
-                       tf->hob_lbam    = inb(io_ports->lbam_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
-                       tf->hob_lbah    = inb(io_ports->lbah_addr);
+       if (cmd->tf_flags & IDE_TFLAG_LBA48) {
+               outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr);
+
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR)
+                       tf->hob_error = inb(io_ports->feature_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+                       tf->hob_nsect = inb(io_ports->nsect_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+                       tf->hob_lbal  = inb(io_ports->lbal_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+                       tf->hob_lbam  = inb(io_ports->lbam_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+                       tf->hob_lbah  = inb(io_ports->lbah_addr);
        }
 }
 
+static void ns87415_dev_select(ide_drive_t *drive);
+
 static const struct ide_tp_ops superio_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = superio_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ns87415_dev_select,
        .tf_load                = ide_tf_load,
        .tf_read                = superio_tf_read,
 
@@ -190,10 +185,18 @@ static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
        local_irq_restore(flags);
 }
 
-static void ns87415_selectproc (ide_drive_t *drive)
+static void ns87415_dev_select(ide_drive_t *drive)
 {
        ns87415_prepare_drive(drive,
                              !!(drive->dev_flags & IDE_DFLAG_USING_DMA));
+
+       outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
+}
+
+static void ns87415_dma_start(ide_drive_t *drive)
+{
+       ns87415_prepare_drive(drive, 1);
+       ide_dma_start(drive);
 }
 
 static int ns87415_dma_end(ide_drive_t *drive)
@@ -201,7 +204,6 @@ static int ns87415_dma_end(ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        u8 dma_stat = 0, dma_cmd = 0;
 
-       drive->waiting_for_dma = 0;
        dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
        /* get DMA command mode */
        dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
@@ -210,21 +212,11 @@ static int ns87415_dma_end(ide_drive_t *drive)
        /* from ERRATA: clear the INTR & ERROR bits */
        dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
        outb(dma_cmd | 6, hwif->dma_base + ATA_DMA_CMD);
-       /* and free any DMA resources */
-       ide_destroy_dmatable(drive);
-       /* verify good DMA status */
-       return (dma_stat & 7) != 4;
-}
 
-static int ns87415_dma_setup(ide_drive_t *drive)
-{
-       /* select DMA xfer */
-       ns87415_prepare_drive(drive, 1);
-       if (!ide_dma_setup(drive))
-               return 0;
-       /* DMA failed: select PIO xfer */
        ns87415_prepare_drive(drive, 0);
-       return 1;
+
+       /* verify good DMA status */
+       return (dma_stat & 7) != 4;
 }
 
 static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
@@ -242,7 +234,7 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
         * Also, leave IRQ masked during drive probing, to prevent infinite
         * interrupts from a potentially floating INTA..
         *
-        * IRQs get unmasked in selectproc when drive is first used.
+        * IRQs get unmasked in dev_select() when drive is first used.
         */
        (void) pci_read_config_dword(dev, 0x40, &ctrl);
        (void) pci_read_config_byte(dev, 0x09, &progif);
@@ -270,7 +262,7 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
 #ifdef __sparc_v9__
                /*
                 * XXX: Reset the device, if we don't it will not respond to
-                *      SELECT_DRIVE() properly during first ide_probe_port().
+                *      dev_select() properly during first ide_probe_port().
                 */
                timeout = 10000;
                outb(12, hwif->io_ports.ctl_addr);
@@ -294,26 +286,35 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
        outb(0x60, hwif->dma_base + ATA_DMA_STATUS);
 }
 
-static const struct ide_port_ops ns87415_port_ops = {
-       .selectproc             = ns87415_selectproc,
+static const struct ide_tp_ops ns87415_tp_ops = {
+       .exec_command           = ide_exec_command,
+       .read_status            = ide_read_status,
+       .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
+
+       .dev_select             = ns87415_dev_select,
+       .tf_load                = ide_tf_load,
+       .tf_read                = ide_tf_read,
+
+       .input_data             = ide_input_data,
+       .output_data            = ide_output_data,
 };
 
 static const struct ide_dma_ops ns87415_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ns87415_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
-       .dma_start              = ide_dma_start,
+       .dma_setup              = ide_dma_setup,
+       .dma_start              = ns87415_dma_start,
        .dma_end                = ns87415_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_sff_read_status    = superio_dma_sff_read_status,
 };
 
 static const struct ide_port_info ns87415_chipset __devinitdata = {
        .name           = DRV_NAME,
        .init_hwif      = init_hwif_ns87415,
-       .port_ops       = &ns87415_port_ops,
+       .tp_ops         = &ns87415_tp_ops,
        .dma_ops        = &ns87415_dma_ops,
        .host_flags     = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
                          IDE_HFLAG_NO_ATAPI_DMA,
index f38aac78044c77617f19fd3d349a1aaf6dd9e286..c7acca0b8733b6f28a79613bdfd15ffd5b123376 100644 (file)
@@ -347,7 +347,7 @@ static int __init palm_bk3710_probe(struct platform_device *pdev)
        struct clk *clk;
        struct resource *mem, *irq;
        void __iomem *base;
-       unsigned long rate;
+       unsigned long rate, mem_size;
        int i, rc;
        hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
 
@@ -374,13 +374,18 @@ static int __init palm_bk3710_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       if (request_mem_region(mem->start, mem->end - mem->start + 1,
-                              "palm_bk3710") == NULL) {
+       mem_size = mem->end - mem->start + 1;
+       if (request_mem_region(mem->start, mem_size, "palm_bk3710") == NULL) {
                printk(KERN_ERR "failed to request memory region\n");
                return -EBUSY;
        }
 
-       base = IO_ADDRESS(mem->start);
+       base = ioremap(mem->start, mem_size);
+       if (!base) {
+               printk(KERN_ERR "failed to map IO memory\n");
+               release_mem_region(mem->start, mem_size);
+               return -ENOMEM;
+       }
 
        /* Configure the Palm Chip controller */
        palm_bk3710_chipinit(base);
index cba66ebce4e341c977baff6b8d311c56c2074382..248a54bd2386f346e155c19a74f1c635215170a3 100644 (file)
@@ -258,12 +258,6 @@ static void pdc202xx_dma_lost_irq(ide_drive_t *drive)
        ide_dma_lost_irq(drive);
 }
 
-static void pdc202xx_dma_timeout(ide_drive_t *drive)
-{
-       pdc202xx_reset(drive);
-       ide_dma_timeout(drive);
-}
-
 static int init_chipset_pdc202xx(struct pci_dev *dev)
 {
        unsigned long dmabase = pci_resource_start(dev, 4);
@@ -331,24 +325,24 @@ static const struct ide_port_ops pdc2026x_port_ops = {
 static const struct ide_dma_ops pdc20246_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
        .dma_setup              = ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = ide_dma_start,
        .dma_end                = ide_dma_end,
        .dma_test_irq           = pdc202xx_dma_test_irq,
        .dma_lost_irq           = pdc202xx_dma_lost_irq,
-       .dma_timeout            = pdc202xx_dma_timeout,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
+       .dma_clear              = pdc202xx_reset,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
 static const struct ide_dma_ops pdc2026x_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
        .dma_setup              = ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = pdc202xx_dma_start,
        .dma_end                = pdc202xx_dma_end,
        .dma_test_irq           = pdc202xx_dma_test_irq,
        .dma_lost_irq           = pdc202xx_dma_lost_irq,
-       .dma_timeout            = pdc202xx_dma_timeout,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
+       .dma_clear              = pdc202xx_reset,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
index 74625e821a43bc078f6c1efe88312bb438872141..052b9bf1f8fb69bd14a2c0491a2dd5e920cca540 100644 (file)
@@ -404,9 +404,6 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time)
 #define IDE_WAKEUP_DELAY       (1*HZ)
 
 static int pmac_ide_init_dma(ide_hwif_t *, const struct ide_port_info *);
-static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq);
-static void pmac_ide_selectproc(ide_drive_t *drive);
-static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
 
 #define PMAC_IDE_REG(x) \
        ((void __iomem *)((drive)->hwif->io_ports.data_addr + (x)))
@@ -416,8 +413,7 @@ static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
  * timing register when selecting that unit. This version is for
  * ASICs with a single timing register
  */
-static void
-pmac_ide_selectproc(ide_drive_t *drive)
+static void pmac_ide_apply_timings(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        pmac_ide_hwif_t *pmif =
@@ -435,8 +431,7 @@ pmac_ide_selectproc(ide_drive_t *drive)
  * timing register when selecting that unit. This version is for
  * ASICs with a dual timing register (Kauai)
  */
-static void
-pmac_ide_kauai_selectproc(ide_drive_t *drive)
+static void pmac_ide_kauai_apply_timings(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        pmac_ide_hwif_t *pmif =
@@ -465,9 +460,25 @@ pmac_ide_do_update_timings(ide_drive_t *drive)
        if (pmif->kind == controller_sh_ata6 ||
            pmif->kind == controller_un_ata6 ||
            pmif->kind == controller_k2_ata6)
-               pmac_ide_kauai_selectproc(drive);
+               pmac_ide_kauai_apply_timings(drive);
        else
-               pmac_ide_selectproc(drive);
+               pmac_ide_apply_timings(drive);
+}
+
+static void pmac_dev_select(ide_drive_t *drive)
+{
+       pmac_ide_apply_timings(drive);
+
+       writeb(drive->select | ATA_DEVICE_OBS,
+              (void __iomem *)drive->hwif->io_ports.device_addr);
+}
+
+static void pmac_kauai_dev_select(ide_drive_t *drive)
+{
+       pmac_ide_kauai_apply_timings(drive);
+
+       writeb(drive->select | ATA_DEVICE_OBS,
+              (void __iomem *)drive->hwif->io_ports.device_addr);
 }
 
 static void pmac_exec_command(ide_hwif_t *hwif, u8 cmd)
@@ -477,17 +488,8 @@ static void pmac_exec_command(ide_hwif_t *hwif, u8 cmd)
                                     + IDE_TIMING_CONFIG));
 }
 
-static void pmac_set_irq(ide_hwif_t *hwif, int on)
+static void pmac_write_devctl(ide_hwif_t *hwif, u8 ctl)
 {
-       u8 ctl = ATA_DEVCTL_OBS;
-
-       if (on == 4) { /* hack for SRST */
-               ctl |= 4;
-               on &= ~4;
-       }
-
-       ctl |= on ? 0 : 2;
-
        writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr);
        (void)readl((void __iomem *)(hwif->io_ports.data_addr
                                     + IDE_TIMING_CONFIG));
@@ -917,10 +919,18 @@ static u8 pmac_ide_cable_detect(ide_hwif_t *hwif)
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
        struct device_node *np = pmif->node;
        const char *cable = of_get_property(np, "cable-type", NULL);
+       struct device_node *root = of_find_node_by_path("/");
+       const char *model = of_get_property(root, "model", NULL);
 
        /* Get cable type from device-tree. */
-       if (cable && !strncmp(cable, "80-", 3))
-               return ATA_CBL_PATA80;
+       if (cable && !strncmp(cable, "80-", 3)) {
+               /* Some drives fail to detect 80c cable in PowerBook */
+               /* These machine use proprietary short IDE cable anyway */
+               if (!strncmp(model, "PowerBook", 9))
+                       return ATA_CBL_PATA40_SHORT;
+               else
+                       return ATA_CBL_PATA80;
+       }
 
        /*
         * G5's seem to have incorrect cable type in device-tree.
@@ -955,9 +965,9 @@ static const struct ide_tp_ops pmac_tp_ops = {
        .exec_command           = pmac_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = pmac_write_devctl,
 
-       .set_irq                = pmac_set_irq,
-
+       .dev_select             = pmac_dev_select,
        .tf_load                = ide_tf_load,
        .tf_read                = ide_tf_read,
 
@@ -965,19 +975,24 @@ static const struct ide_tp_ops pmac_tp_ops = {
        .output_data            = ide_output_data,
 };
 
-static const struct ide_port_ops pmac_ide_ata6_port_ops = {
-       .init_dev               = pmac_ide_init_dev,
-       .set_pio_mode           = pmac_ide_set_pio_mode,
-       .set_dma_mode           = pmac_ide_set_dma_mode,
-       .selectproc             = pmac_ide_kauai_selectproc,
-       .cable_detect           = pmac_ide_cable_detect,
+static const struct ide_tp_ops pmac_ata6_tp_ops = {
+       .exec_command           = pmac_exec_command,
+       .read_status            = ide_read_status,
+       .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = pmac_write_devctl,
+
+       .dev_select             = pmac_kauai_dev_select,
+       .tf_load                = ide_tf_load,
+       .tf_read                = ide_tf_read,
+
+       .input_data             = ide_input_data,
+       .output_data            = ide_output_data,
 };
 
 static const struct ide_port_ops pmac_ide_ata4_port_ops = {
        .init_dev               = pmac_ide_init_dev,
        .set_pio_mode           = pmac_ide_set_pio_mode,
        .set_dma_mode           = pmac_ide_set_dma_mode,
-       .selectproc             = pmac_ide_selectproc,
        .cable_detect           = pmac_ide_cable_detect,
 };
 
@@ -985,7 +1000,6 @@ static const struct ide_port_ops pmac_ide_port_ops = {
        .init_dev               = pmac_ide_init_dev,
        .set_pio_mode           = pmac_ide_set_pio_mode,
        .set_dma_mode           = pmac_ide_set_dma_mode,
-       .selectproc             = pmac_ide_selectproc,
 };
 
 static const struct ide_dma_ops pmac_dma_ops;
@@ -1022,15 +1036,18 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw)
        pmif->broken_dma = pmif->broken_dma_warn = 0;
        if (of_device_is_compatible(np, "shasta-ata")) {
                pmif->kind = controller_sh_ata6;
-               d.port_ops = &pmac_ide_ata6_port_ops;
+               d.tp_ops = &pmac_ata6_tp_ops;
+               d.port_ops = &pmac_ide_ata4_port_ops;
                d.udma_mask = ATA_UDMA6;
        } else if (of_device_is_compatible(np, "kauai-ata")) {
                pmif->kind = controller_un_ata6;
-               d.port_ops = &pmac_ide_ata6_port_ops;
+               d.tp_ops = &pmac_ata6_tp_ops;
+               d.port_ops = &pmac_ide_ata4_port_ops;
                d.udma_mask = ATA_UDMA5;
        } else if (of_device_is_compatible(np, "K2-UATA")) {
                pmif->kind = controller_k2_ata6;
-               d.port_ops = &pmac_ide_ata6_port_ops;
+               d.tp_ops = &pmac_ata6_tp_ops;
+               d.port_ops = &pmac_ide_ata4_port_ops;
                d.udma_mask = ATA_UDMA5;
        } else if (of_device_is_compatible(np, "keylargo-ata")) {
                if (strcmp(np->name, "ata-4") == 0) {
@@ -1422,17 +1439,16 @@ out:
  * pmac_ide_build_dmatable builds the DBDMA command list
  * for a transfer and sets the DBDMA channel to point to it.
  */
-static int
-pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
+static int pmac_ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        pmac_ide_hwif_t *pmif =
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
        struct dbdma_cmd *table;
-       int i, count = 0;
        volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
        struct scatterlist *sg;
-       int wr = (rq_data_dir(rq) == WRITE);
+       int wr = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
+       int i = cmd->sg_nents, count = 0;
 
        /* DMA table is already aligned */
        table = (struct dbdma_cmd *) pmif->dma_table_cpu;
@@ -1442,11 +1458,6 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
        while (readl(&dma->status) & RUN)
                udelay(1);
 
-       hwif->sg_nents = i = ide_build_sglist(drive, rq);
-
-       if (!i)
-               return 0;
-
        /* Build DBDMA commands list */
        sg = hwif->sg_table;
        while (i && sg_dma_len(sg)) {
@@ -1462,7 +1473,7 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
                                       "switching to PIO on Ohare chipset\n", drive->name);
                                pmif->broken_dma_warn = 1;
                        }
-                       goto use_pio_instead;
+                       return 0;
                }
                while (cur_len) {
                        unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
@@ -1470,7 +1481,7 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
                        if (count++ >= MAX_DCMDS) {
                                printk(KERN_WARNING "%s: DMA table too small\n",
                                       drive->name);
-                               goto use_pio_instead;
+                               return 0;
                        }
                        st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE);
                        st_le16(&table->req_count, tc);
@@ -1499,9 +1510,6 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
 
        printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
 
-use_pio_instead:
-       ide_destroy_dmatable(drive);
-
        return 0; /* revert to PIO for this request */
 }
 
@@ -1509,39 +1517,27 @@ use_pio_instead:
  * Prepare a DMA transfer. We build the DMA table, adjust the timings for
  * a read on KeyLargo ATA/66 and mark us as waiting for DMA completion
  */
-static int
-pmac_ide_dma_setup(ide_drive_t *drive)
+static int pmac_ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        pmac_ide_hwif_t *pmif =
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
-       struct request *rq = hwif->rq;
        u8 unit = drive->dn & 1, ata4 = (pmif->kind == controller_kl_ata4);
+       u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
 
-       if (!pmac_ide_build_dmatable(drive, rq)) {
-               ide_map_sg(drive, rq);
+       if (pmac_ide_build_dmatable(drive, cmd) == 0)
                return 1;
-       }
 
        /* Apple adds 60ns to wrDataSetup on reads */
        if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
-               writel(pmif->timings[unit] + (!rq_data_dir(rq) ? 0x00800000UL : 0),
+               writel(pmif->timings[unit] + (write ? 0 : 0x00800000UL),
                        PMAC_IDE_REG(IDE_TIMING_CONFIG));
                (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG));
        }
 
-       drive->waiting_for_dma = 1;
-
        return 0;
 }
 
-static void
-pmac_ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
-{
-       /* issue cmd to drive */
-       ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, NULL);
-}
-
 /*
  * Kick the DMA controller into life after the DMA command has been issued
  * to the drive.
@@ -1573,12 +1569,9 @@ pmac_ide_dma_end (ide_drive_t *drive)
        volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
        u32 dstat;
 
-       drive->waiting_for_dma = 0;
        dstat = readl(&dma->status);
        writel(((RUN|WAKE|DEAD) << 16), &dma->control);
 
-       ide_destroy_dmatable(drive);
-
        /* verify good dma status. we don't check for ACTIVE beeing 0. We should...
         * in theory, but with ATAPI decices doing buffer underruns, that would
         * cause us to disable DMA, which isn't what we want
@@ -1662,11 +1655,9 @@ pmac_ide_dma_lost_irq (ide_drive_t *drive)
 static const struct ide_dma_ops pmac_dma_ops = {
        .dma_host_set           = pmac_ide_dma_host_set,
        .dma_setup              = pmac_ide_dma_setup,
-       .dma_exec_cmd           = pmac_ide_dma_exec_cmd,
        .dma_start              = pmac_ide_dma_start,
        .dma_end                = pmac_ide_dma_end,
        .dma_test_irq           = pmac_ide_dma_test_irq,
-       .dma_timeout            = ide_dma_timeout,
        .dma_lost_irq           = pmac_ide_dma_lost_irq,
 };
 
index 9f9c0b3cc3a325de1596c625590c9a4161096ba3..d007e7f665980e46b49f8ec7e5285a0caa0ac60b 100644 (file)
@@ -72,26 +72,26 @@ static void q40_ide_setup_ports(hw_regs_t *hw, unsigned long base,
        hw->chipset = ide_generic;
 }
 
-static void q40ide_input_data(ide_drive_t *drive, struct request *rq,
+static void q40ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
                              void *buf, unsigned int len)
 {
        unsigned long data_addr = drive->hwif->io_ports.data_addr;
 
-       if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
+       if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS))
                return insw(data_addr, buf, (len + 1) / 2);
 
-       insw_swapw(data_addr, buf, (len + 1) / 2);
+       raw_insw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
 }
 
-static void q40ide_output_data(ide_drive_t *drive, struct request *rq,
+static void q40ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
                               void *buf, unsigned int len)
 {
        unsigned long data_addr = drive->hwif->io_ports.data_addr;
 
-       if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
+       if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS))
                return outsw(data_addr, buf, (len + 1) / 2);
 
-       outsw_swapw(data_addr, buf, (len + 1) / 2);
+       raw_outsw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
 }
 
 /* Q40 has a byte-swapped IDE interface */
@@ -99,9 +99,9 @@ static const struct ide_tp_ops q40ide_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = ide_tf_load,
        .tf_read                = ide_tf_read,
 
@@ -111,7 +111,8 @@ static const struct ide_tp_ops q40ide_tp_ops = {
 
 static const struct ide_port_info q40ide_port_info = {
        .tp_ops                 = &q40ide_tp_ops,
-       .host_flags             = IDE_HFLAG_NO_DMA,
+       .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
+       .irq_flags              = IRQF_SHARED,
 };
 
 /* 
index 08c4fa35e9b19481df1ac94b4772599b2fe57036..c9a1349868911eb583de495f20e1c73fbf030e1b 100644 (file)
@@ -90,13 +90,15 @@ static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
  * This routine is invoked to prepare for access to a given drive.
  */
 
-static void qd65xx_select(ide_drive_t *drive)
+static void qd65xx_dev_select(ide_drive_t *drive)
 {
        u8 index = ((   (QD_TIMREG(drive)) & 0x80 ) >> 7) |
                        (QD_TIMREG(drive) & 0x02);
 
        if (timings[index] != QD_TIMING(drive))
                outb(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
+
+       outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
 }
 
 /*
@@ -309,20 +311,33 @@ static void __init qd6580_init_dev(ide_drive_t *drive)
        drive->drive_data = (drive->dn & 1) ? t2 : t1;
 }
 
+static const struct ide_tp_ops qd65xx_tp_ops = {
+       .exec_command           = ide_exec_command,
+       .read_status            = ide_read_status,
+       .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
+
+       .dev_select             = qd65xx_dev_select,
+       .tf_load                = ide_tf_load,
+       .tf_read                = ide_tf_read,
+
+       .input_data             = ide_input_data,
+       .output_data            = ide_output_data,
+};
+
 static const struct ide_port_ops qd6500_port_ops = {
        .init_dev               = qd6500_init_dev,
        .set_pio_mode           = qd6500_set_pio_mode,
-       .selectproc             = qd65xx_select,
 };
 
 static const struct ide_port_ops qd6580_port_ops = {
        .init_dev               = qd6580_init_dev,
        .set_pio_mode           = qd6580_set_pio_mode,
-       .selectproc             = qd65xx_select,
 };
 
 static const struct ide_port_info qd65xx_port_info __initdata = {
        .name                   = DRV_NAME,
+       .tp_ops                 = &qd65xx_tp_ops,
        .chipset                = ide_qd65xx,
        .host_flags             = IDE_HFLAG_IO_32BIT |
                                  IDE_HFLAG_NO_DMA,
index dbdd2985a0d8f7f89b58df5cd9a440dc74df9918..d467478d68da96839efd99b665b552e2f7512bbc 100644 (file)
@@ -115,8 +115,7 @@ static u8 sc1200_udma_filter(ide_drive_t *drive)
                if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
                    (mateid[ATA_ID_UDMA_MODES] & 7))
                        goto out;
-               if ((mateid[ATA_ID_FIELD_VALID] & 2) &&
-                   (mateid[ATA_ID_MWDMA_MODES] & 7))
+               if (mateid[ATA_ID_MWDMA_MODES] & 7)
                        mask = 0;
        }
 out:
@@ -183,9 +182,6 @@ static int sc1200_dma_end(ide_drive_t *drive)
        outb(dma_stat|0x1b, dma_base+2);        /* clear the INTR & ERROR bits */
        outb(inb(dma_base)&~1, dma_base);       /* !! DO THIS HERE !! stop DMA */
 
-       drive->waiting_for_dma = 0;
-       ide_destroy_dmatable(drive);            /* purge DMA mappings */
-
        return (dma_stat & 7) != 4;             /* verify good DMA status */
 }
 
@@ -286,12 +282,11 @@ static const struct ide_port_ops sc1200_port_ops = {
 static const struct ide_dma_ops sc1200_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
        .dma_setup              = ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = ide_dma_start,
        .dma_end                = sc1200_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
index 8d2314b6327c7e25af3cb8cbecba902834c03576..6d8dbd9c10bc11e99b28b486d5c74d220d8a9a14 100644 (file)
@@ -148,17 +148,8 @@ static u8 scc_dma_sff_read_status(ide_hwif_t *hwif)
        return (u8)in_be32((void *)(hwif->dma_base + 4));
 }
 
-static void scc_set_irq(ide_hwif_t *hwif, int on)
+static void scc_write_devctl(ide_hwif_t *hwif, u8 ctl)
 {
-       u8 ctl = ATA_DEVCTL_OBS;
-
-       if (on == 4) { /* hack for SRST */
-               ctl |= 4;
-               on &= ~4;
-       }
-
-       ctl |= on ? 0 : 2;
-
        out_be32((void *)hwif->io_ports.ctl_addr, ctl);
        eieio();
        in_be32((void *)(hwif->dma_base + 0x01c));
@@ -303,8 +294,9 @@ static void scc_dma_host_set(ide_drive_t *drive, int on)
 }
 
 /**
- *     scc_ide_dma_setup       -       begin a DMA phase
+ *     scc_dma_setup   -       begin a DMA phase
  *     @drive: target device
+ *     @cmd: command
  *
  *     Build an IDE DMA PRD (IDE speak for scatter gather table)
  *     and then set up the DMA transfer registers.
@@ -313,36 +305,28 @@ static void scc_dma_host_set(ide_drive_t *drive, int on)
  *     is returned.
  */
 
-static int scc_dma_setup(ide_drive_t *drive)
+static int scc_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
-       struct request *rq = hwif->rq;
-       unsigned int reading;
+       u32 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR;
        u8 dma_stat;
 
-       if (rq_data_dir(rq))
-               reading = 0;
-       else
-               reading = 1 << 3;
-
        /* fall back to pio! */
-       if (!ide_build_dmatable(drive, rq)) {
-               ide_map_sg(drive, rq);
+       if (ide_build_dmatable(drive, cmd) == 0)
                return 1;
-       }
 
        /* PRD table */
        out_be32((void __iomem *)(hwif->dma_base + 8), hwif->dmatable_dma);
 
        /* specify r/w */
-       out_be32((void __iomem *)hwif->dma_base, reading);
+       out_be32((void __iomem *)hwif->dma_base, rw);
 
        /* read DMA status for INTR & ERROR flags */
        dma_stat = scc_dma_sff_read_status(hwif);
 
        /* clear INTR & ERROR flags */
        out_be32((void __iomem *)(hwif->dma_base + 4), dma_stat | 6);
-       drive->waiting_for_dma = 1;
+
        return 0;
 }
 
@@ -361,7 +345,6 @@ static int __scc_dma_end(ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        u8 dma_stat, dma_cmd;
 
-       drive->waiting_for_dma = 0;
        /* get DMA command mode */
        dma_cmd = scc_ide_inb(hwif->dma_base);
        /* stop DMA */
@@ -370,8 +353,6 @@ static int __scc_dma_end(ide_drive_t *drive)
        dma_stat = scc_dma_sff_read_status(hwif);
        /* clear the INTR & ERROR bits */
        scc_ide_outb(dma_stat | 6, hwif->dma_base + 4);
-       /* purge DMA mappings */
-       ide_destroy_dmatable(drive);
        /* verify good DMA status */
        wmb();
        return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
@@ -666,91 +647,80 @@ static int __devinit init_setup_scc(struct pci_dev *dev,
        return rc;
 }
 
-static void scc_tf_load(ide_drive_t *drive, ide_task_t *task)
+static void scc_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        struct ide_io_ports *io_ports = &drive->hwif->io_ports;
-       struct ide_taskfile *tf = &task->tf;
-       u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+       struct ide_taskfile *tf = &cmd->tf;
+       u8 HIHI = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
 
-       if (task->tf_flags & IDE_TFLAG_FLAGGED)
+       if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
                HIHI = 0xFF;
 
-       if (task->tf_flags & IDE_TFLAG_OUT_DATA)
-               out_be32((void *)io_ports->data_addr,
-                        (tf->hob_data << 8) | tf->data);
-
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
                scc_ide_outb(tf->hob_feature, io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
                scc_ide_outb(tf->hob_nsect, io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
                scc_ide_outb(tf->hob_lbal, io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
                scc_ide_outb(tf->hob_lbam, io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
                scc_ide_outb(tf->hob_lbah, io_ports->lbah_addr);
 
-       if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_FEATURE)
                scc_ide_outb(tf->feature, io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_NSECT)
                scc_ide_outb(tf->nsect, io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAL)
                scc_ide_outb(tf->lbal, io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAM)
                scc_ide_outb(tf->lbam, io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAH)
                scc_ide_outb(tf->lbah, io_ports->lbah_addr);
 
-       if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_DEVICE)
                scc_ide_outb((tf->device & HIHI) | drive->select,
                             io_ports->device_addr);
 }
 
-static void scc_tf_read(ide_drive_t *drive, ide_task_t *task)
+static void scc_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        struct ide_io_ports *io_ports = &drive->hwif->io_ports;
-       struct ide_taskfile *tf = &task->tf;
-
-       if (task->tf_flags & IDE_TFLAG_IN_DATA) {
-               u16 data = (u16)in_be32((void *)io_ports->data_addr);
-
-               tf->data = data & 0xff;
-               tf->hob_data = (data >> 8) & 0xff;
-       }
+       struct ide_taskfile *tf = &cmd->tf;
 
        /* be sure we're looking at the low order bits */
-       scc_ide_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+       scc_ide_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-       if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
-               tf->feature = scc_ide_inb(io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_IN_ERROR)
+               tf->error  = scc_ide_inb(io_ports->feature_addr);
+       if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
                tf->nsect  = scc_ide_inb(io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
                tf->lbal   = scc_ide_inb(io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAM)
                tf->lbam   = scc_ide_inb(io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAH)
                tf->lbah   = scc_ide_inb(io_ports->lbah_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+       if (cmd->tf_flags & IDE_TFLAG_IN_DEVICE)
                tf->device = scc_ide_inb(io_ports->device_addr);
 
-       if (task->tf_flags & IDE_TFLAG_LBA48) {
-               scc_ide_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
-
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
-                       tf->hob_feature = scc_ide_inb(io_ports->feature_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
-                       tf->hob_nsect   = scc_ide_inb(io_ports->nsect_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
-                       tf->hob_lbal    = scc_ide_inb(io_ports->lbal_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
-                       tf->hob_lbam    = scc_ide_inb(io_ports->lbam_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
-                       tf->hob_lbah    = scc_ide_inb(io_ports->lbah_addr);
+       if (cmd->tf_flags & IDE_TFLAG_LBA48) {
+               scc_ide_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr);
+
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR)
+                       tf->hob_error = scc_ide_inb(io_ports->feature_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+                       tf->hob_nsect = scc_ide_inb(io_ports->nsect_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+                       tf->hob_lbal  = scc_ide_inb(io_ports->lbal_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+                       tf->hob_lbam  = scc_ide_inb(io_ports->lbam_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+                       tf->hob_lbah  = scc_ide_inb(io_ports->lbah_addr);
        }
 }
 
-static void scc_input_data(ide_drive_t *drive, struct request *rq,
+static void scc_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
                           void *buf, unsigned int len)
 {
        unsigned long data_addr = drive->hwif->io_ports.data_addr;
@@ -766,7 +736,7 @@ static void scc_input_data(ide_drive_t *drive, struct request *rq,
                scc_ide_insw(data_addr, buf, len / 2);
 }
 
-static void scc_output_data(ide_drive_t *drive,  struct request *rq,
+static void scc_output_data(ide_drive_t *drive,  struct ide_cmd *cmd,
                            void *buf, unsigned int len)
 {
        unsigned long data_addr = drive->hwif->io_ports.data_addr;
@@ -853,9 +823,9 @@ static const struct ide_tp_ops scc_tp_ops = {
        .exec_command           = scc_exec_command,
        .read_status            = scc_read_status,
        .read_altstatus         = scc_read_altstatus,
+       .write_devctl           = scc_write_devctl,
 
-       .set_irq                = scc_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = scc_tf_load,
        .tf_read                = scc_tf_read,
 
@@ -873,30 +843,25 @@ static const struct ide_port_ops scc_port_ops = {
 static const struct ide_dma_ops scc_dma_ops = {
        .dma_host_set           = scc_dma_host_set,
        .dma_setup              = scc_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = scc_dma_start,
        .dma_end                = scc_dma_end,
        .dma_test_irq           = scc_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_sff_read_status    = scc_dma_sff_read_status,
 };
 
-#define DECLARE_SCC_DEV(name_str)                      \
-  {                                                    \
-      .name            = name_str,                     \
-      .init_iops       = init_iops_scc,                \
-      .init_dma                = scc_init_dma,                 \
-      .init_hwif       = init_hwif_scc,                \
-      .tp_ops          = &scc_tp_ops,          \
-      .port_ops                = &scc_port_ops,                \
-      .dma_ops         = &scc_dma_ops,                 \
-      .host_flags      = IDE_HFLAG_SINGLE,             \
-      .pio_mask                = ATA_PIO4,                     \
-  }
-
-static const struct ide_port_info scc_chipsets[] __devinitdata = {
-       /* 0 */ DECLARE_SCC_DEV("sccIDE"),
+static const struct ide_port_info scc_chipset __devinitdata = {
+       .name           = "sccIDE",
+       .init_iops      = init_iops_scc,
+       .init_dma       = scc_init_dma,
+       .init_hwif      = init_hwif_scc,
+       .tp_ops         = &scc_tp_ops,
+       .port_ops       = &scc_port_ops,
+       .dma_ops        = &scc_dma_ops,
+       .host_flags     = IDE_HFLAG_SINGLE,
+       .irq_flags      = IRQF_SHARED,
+       .pio_mask       = ATA_PIO4,
 };
 
 /**
@@ -910,7 +875,7 @@ static const struct ide_port_info scc_chipsets[] __devinitdata = {
 
 static int __devinit scc_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
-       return init_setup_scc(dev, &scc_chipsets[id->driver_data]);
+       return init_setup_scc(dev, &scc_chipset);
 }
 
 /**
index 24bc884826fcb1f60da0182c6a1180f80ad47c30..a19dbccd76179cd4a234b168e2d18197bf86b18e 100644 (file)
@@ -558,6 +558,8 @@ int ide_pci_init_one(struct pci_dev *dev, const struct ide_port_info *d,
 
        host->host_priv = priv;
 
+       host->irq_flags = IRQF_SHARED;
+
        pci_set_drvdata(dev, host);
 
        ret = do_ide_setup_pci_device(dev, d, 1);
@@ -606,6 +608,8 @@ int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2,
 
        host->host_priv = priv;
 
+       host->irq_flags = IRQF_SHARED;
+
        pci_set_drvdata(pdev[0], host);
        pci_set_drvdata(pdev[1], host);
 
index fdb9d70376949514c567ecd6eadba4a8591a095b..e5d2a48a84de9314133d2b54c49f63aa08f536e4 100644 (file)
@@ -258,9 +258,6 @@ static int sgiioc4_dma_end(ide_drive_t *drive)
                }
        }
 
-       drive->waiting_for_dma = 0;
-       ide_destroy_dmatable(drive);
-
        return dma_stat;
 }
 
@@ -280,10 +277,12 @@ static void sgiioc4_dma_host_set(ide_drive_t *drive, int on)
                sgiioc4_clearirq(drive);
 }
 
-static void
-sgiioc4_resetproc(ide_drive_t * drive)
+static void sgiioc4_resetproc(ide_drive_t *drive)
 {
+       struct ide_cmd *cmd = &drive->hwif->cmd;
+
        sgiioc4_dma_end(drive);
+       ide_dma_unmap_sg(drive, cmd);
        sgiioc4_clearirq(drive);
 }
 
@@ -412,7 +411,6 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive)
        writel(ending_dma_addr, (void __iomem *)(dma_base + IOC4_DMA_END_ADDR * 4));
 
        writel(dma_direction, (void __iomem *)ioc4_dma_addr);
-       drive->waiting_for_dma = 1;
 }
 
 /* IOC4 Scatter Gather list Format                                      */
@@ -424,20 +422,13 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive)
 /* | Upper 32 bits - Zero          |EOL| 15 unused     | 16 Bit Length| */
 /* --------------------------------------------------------------------- */
 /* Creates the scatter gather list, DMA Table */
-static unsigned int
-sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir)
+static int sgiioc4_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        unsigned int *table = hwif->dmatable_cpu;
-       unsigned int count = 0, i = 1;
-       struct scatterlist *sg;
-
-       hwif->sg_nents = i = ide_build_sglist(drive, rq);
-
-       if (!i)
-               return 0;       /* sglist of length Zero */
+       unsigned int count = 0, i = cmd->sg_nents;
+       struct scatterlist *sg = hwif->sg_table;
 
-       sg = hwif->sg_table;
        while (i && sg_dma_len(sg)) {
                dma_addr_t cur_addr;
                int cur_len;
@@ -449,7 +440,7 @@ sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir)
                                printk(KERN_WARNING
                                       "%s: DMA table too small\n",
                                       drive->name);
-                               goto use_pio_instead;
+                               return 0;
                        } else {
                                u32 bcount =
                                    0x10000 - (cur_addr & 0xffff);
@@ -484,30 +475,19 @@ sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir)
                return count;
        }
 
-use_pio_instead:
-       ide_destroy_dmatable(drive);
-
        return 0;               /* revert to PIO for this request */
 }
 
-static int sgiioc4_dma_setup(ide_drive_t *drive)
+static int sgiioc4_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
 {
-       struct request *rq = drive->hwif->rq;
-       unsigned int count = 0;
        int ddir;
+       u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
 
-       if (rq_data_dir(rq))
-               ddir = PCI_DMA_TODEVICE;
-       else
-               ddir = PCI_DMA_FROMDEVICE;
-
-       if (!(count = sgiioc4_build_dma_table(drive, rq, ddir))) {
+       if (sgiioc4_build_dmatable(drive, cmd) == 0)
                /* try PIO instead of DMA */
-               ide_map_sg(drive, rq);
                return 1;
-       }
 
-       if (rq_data_dir(rq))
+       if (write)
                /* Writes TO the IOC4 FROM Main Memory */
                ddir = IOC4_DMA_READ;
        else
@@ -523,9 +503,9 @@ static const struct ide_tp_ops sgiioc4_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = sgiioc4_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = ide_tf_load,
        .tf_read                = ide_tf_read,
 
@@ -546,7 +526,6 @@ static const struct ide_dma_ops sgiioc4_dma_ops = {
        .dma_end                = sgiioc4_dma_end,
        .dma_test_irq           = sgiioc4_dma_test_irq,
        .dma_lost_irq           = sgiioc4_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
 };
 
 static const struct ide_port_info sgiioc4_port_info __devinitconst = {
@@ -557,6 +536,7 @@ static const struct ide_port_info sgiioc4_port_info __devinitconst = {
        .port_ops               = &sgiioc4_port_ops,
        .dma_ops                = &sgiioc4_dma_ops,
        .host_flags             = IDE_HFLAG_MMIO,
+       .irq_flags              = IRQF_SHARED,
        .mwdma_mask             = ATA_MWDMA2_ONLY,
 };
 
index 1811ae9cd8430a60367a93e281f9c7d3c34157f9..e4973cd1fba9e8735191f73e32e3eb9575f1d97d 100644 (file)
@@ -711,11 +711,10 @@ static const struct ide_port_ops sil_sata_port_ops = {
 static const struct ide_dma_ops sil_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
        .dma_setup              = ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = ide_dma_start,
        .dma_end                = ide_dma_end,
        .dma_test_irq           = siimage_dma_test_irq,
-       .dma_timeout            = ide_dma_timeout,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_lost_irq           = ide_dma_lost_irq,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
index dba213c51baa98f293e007a6b69b3a87ccd1607a..b0a460625335c9c469b94ea94a7d4210c305e2ab 100644 (file)
@@ -61,7 +61,8 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio)
        if (cmd_off == 0)
                cmd_off = 1;
 
-       if (pio > 2 || ata_id_has_iordy(drive->id))
+       if ((pio > 2 || ata_id_has_iordy(drive->id)) &&
+           !(pio > 4 && ata_id_is_cfa(drive->id)))
                iordy = 0x40;
 
        return (cmd_on - 1) << 8 | (cmd_off - 1) | iordy;
@@ -189,14 +190,13 @@ static void sl82c105_dma_start(ide_drive_t *drive)
        ide_dma_start(drive);
 }
 
-static void sl82c105_dma_timeout(ide_drive_t *drive)
+static void sl82c105_dma_clear(ide_drive_t *drive)
 {
        struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
 
-       DBG(("sl82c105_dma_timeout(drive:%s)\n", drive->name));
+       DBG(("sl82c105_dma_clear(drive:%s)\n", drive->name));
 
        sl82c105_reset_host(dev);
-       ide_dma_timeout(drive);
 }
 
 static int sl82c105_dma_end(ide_drive_t *drive)
@@ -293,12 +293,12 @@ static const struct ide_port_ops sl82c105_port_ops = {
 static const struct ide_dma_ops sl82c105_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
        .dma_setup              = ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = sl82c105_dma_start,
        .dma_end                = sl82c105_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = sl82c105_dma_lost_irq,
-       .dma_timeout            = sl82c105_dma_timeout,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
+       .dma_clear              = sl82c105_dma_clear,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
index 84109f5a163228989711b073c7a4b5ffc1e741b9..b4cf42dc8a6fcf4cd155ae0bd3f7ad9868a10106 100644 (file)
@@ -182,12 +182,11 @@ static const struct ide_port_ops tc86c001_port_ops = {
 static const struct ide_dma_ops tc86c001_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
        .dma_setup              = ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = tc86c001_dma_start,
        .dma_end                = ide_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
index 1c09e549c423ca06765e127ff91f73cab73f4716..4b42ca091534093a52cefdd5398ba8a6a0726cb6 100644 (file)
@@ -171,58 +171,51 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
        local_irq_restore(flags);
 }
 
-static void trm290_selectproc (ide_drive_t *drive)
+static void trm290_dev_select(ide_drive_t *drive)
 {
        trm290_prepare_drive(drive, !!(drive->dev_flags & IDE_DFLAG_USING_DMA));
-}
 
-static void trm290_dma_exec_cmd(ide_drive_t *drive, u8 command)
-{
-       ide_execute_command(drive, command, &ide_dma_intr, WAIT_CMD, NULL);
+       outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
 }
 
-static int trm290_dma_setup(ide_drive_t *drive)
+static int trm290_dma_check(ide_drive_t *drive, struct ide_cmd *cmd)
 {
-       ide_hwif_t *hwif = drive->hwif;
-       struct request *rq = hwif->rq;
-       unsigned int count, rw;
-
-       if (rq_data_dir(rq)) {
+       if (cmd->tf_flags & IDE_TFLAG_WRITE) {
 #ifdef TRM290_NO_DMA_WRITES
                /* always use PIO for writes */
-               trm290_prepare_drive(drive, 0); /* select PIO xfer */
                return 1;
 #endif
-               rw = 1;
-       } else
-               rw = 2;
+       }
+       return 0;
+}
+
+static int trm290_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       unsigned int count, rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 1 : 2;
 
-       if (!(count = ide_build_dmatable(drive, rq))) {
+       count = ide_build_dmatable(drive, cmd);
+       if (count == 0)
                /* try PIO instead of DMA */
-               trm290_prepare_drive(drive, 0); /* select PIO xfer */
                return 1;
-       }
-       /* select DMA xfer */
-       trm290_prepare_drive(drive, 1);
+
        outl(hwif->dmatable_dma | rw, hwif->dma_base);
-       drive->waiting_for_dma = 1;
        /* start DMA */
        outw(count * 2 - 1, hwif->dma_base + 2);
+
        return 0;
 }
 
 static void trm290_dma_start(ide_drive_t *drive)
 {
+       trm290_prepare_drive(drive, 1);
 }
 
 static int trm290_dma_end(ide_drive_t *drive)
 {
-       u16 status;
+       u16 status = inw(drive->hwif->dma_base + 2);
 
-       drive->waiting_for_dma = 0;
-       /* purge DMA mappings */
-       ide_destroy_dmatable(drive);
-       status = inw(drive->hwif->dma_base + 2);
+       trm290_prepare_drive(drive, 0);
 
        return status != 0x00ff;
 }
@@ -307,25 +300,34 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
 #endif
 }
 
-static const struct ide_port_ops trm290_port_ops = {
-       .selectproc             = trm290_selectproc,
+static const struct ide_tp_ops trm290_tp_ops = {
+       .exec_command           = ide_exec_command,
+       .read_status            = ide_read_status,
+       .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
+
+       .dev_select             = trm290_dev_select,
+       .tf_load                = ide_tf_load,
+       .tf_read                = ide_tf_read,
+
+       .input_data             = ide_input_data,
+       .output_data            = ide_output_data,
 };
 
 static struct ide_dma_ops trm290_dma_ops = {
        .dma_host_set           = trm290_dma_host_set,
        .dma_setup              = trm290_dma_setup,
-       .dma_exec_cmd           = trm290_dma_exec_cmd,
        .dma_start              = trm290_dma_start,
        .dma_end                = trm290_dma_end,
        .dma_test_irq           = trm290_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
+       .dma_check              = trm290_dma_check,
 };
 
 static const struct ide_port_info trm290_chipset __devinitdata = {
        .name           = DRV_NAME,
        .init_hwif      = init_hwif_trm290,
-       .port_ops       = &trm290_port_ops,
+       .tp_ops         = &trm290_tp_ops,
        .dma_ops        = &trm290_dma_ops,
        .host_flags     = IDE_HFLAG_TRM290 |
                          IDE_HFLAG_NO_ATAPI_DMA |
index d9095345f7ca989c02c9fe663636c5ffe5987d7d..4cb79c4c2604e2920c435ff1c97ebe3fb236de0d 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+
+#include <asm/ide.h>
 #include <asm/txx9/tx4938.h>
 
 static void tx4938ide_tune_ebusc(unsigned int ebus_ch,
@@ -80,99 +82,82 @@ static void tx4938ide_outb(u8 value, unsigned long port)
        __raw_writeb(value, (void __iomem *)port);
 }
 
-static void tx4938ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+static void tx4938ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct ide_io_ports *io_ports = &hwif->io_ports;
-       struct ide_taskfile *tf = &task->tf;
-       u8 HIHI = task->tf_flags & IDE_TFLAG_LBA48 ? 0xE0 : 0xEF;
+       struct ide_taskfile *tf = &cmd->tf;
+       u8 HIHI = cmd->tf_flags & IDE_TFLAG_LBA48 ? 0xE0 : 0xEF;
 
-       if (task->tf_flags & IDE_TFLAG_FLAGGED)
+       if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
                HIHI = 0xFF;
 
-       if (task->tf_flags & IDE_TFLAG_OUT_DATA) {
-               u16 data = (tf->hob_data << 8) | tf->data;
-
-               /* no endian swap */
-               __raw_writew(data, (void __iomem *)io_ports->data_addr);
-       }
-
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
                tx4938ide_outb(tf->hob_feature, io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
                tx4938ide_outb(tf->hob_nsect, io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
                tx4938ide_outb(tf->hob_lbal, io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
                tx4938ide_outb(tf->hob_lbam, io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
                tx4938ide_outb(tf->hob_lbah, io_ports->lbah_addr);
 
-       if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_FEATURE)
                tx4938ide_outb(tf->feature, io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_NSECT)
                tx4938ide_outb(tf->nsect, io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAL)
                tx4938ide_outb(tf->lbal, io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAM)
                tx4938ide_outb(tf->lbam, io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAH)
                tx4938ide_outb(tf->lbah, io_ports->lbah_addr);
 
-       if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_DEVICE)
                tx4938ide_outb((tf->device & HIHI) | drive->select,
                               io_ports->device_addr);
 }
 
-static void tx4938ide_tf_read(ide_drive_t *drive, ide_task_t *task)
+static void tx4938ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct ide_io_ports *io_ports = &hwif->io_ports;
-       struct ide_taskfile *tf = &task->tf;
-
-       if (task->tf_flags & IDE_TFLAG_IN_DATA) {
-               u16 data;
-
-               /* no endian swap */
-               data = __raw_readw((void __iomem *)io_ports->data_addr);
-               tf->data = data & 0xff;
-               tf->hob_data = (data >> 8) & 0xff;
-       }
+       struct ide_taskfile *tf = &cmd->tf;
 
        /* be sure we're looking at the low order bits */
-       tx4938ide_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+       tx4938ide_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-       if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
-               tf->feature = tx4938ide_inb(io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_IN_ERROR)
+               tf->error  = tx4938ide_inb(io_ports->feature_addr);
+       if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
                tf->nsect  = tx4938ide_inb(io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
                tf->lbal   = tx4938ide_inb(io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAM)
                tf->lbam   = tx4938ide_inb(io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAH)
                tf->lbah   = tx4938ide_inb(io_ports->lbah_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+       if (cmd->tf_flags & IDE_TFLAG_IN_DEVICE)
                tf->device = tx4938ide_inb(io_ports->device_addr);
 
-       if (task->tf_flags & IDE_TFLAG_LBA48) {
-               tx4938ide_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
-
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
-                       tf->hob_feature =
-                               tx4938ide_inb(io_ports->feature_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
-                       tf->hob_nsect   = tx4938ide_inb(io_ports->nsect_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
-                       tf->hob_lbal    = tx4938ide_inb(io_ports->lbal_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
-                       tf->hob_lbam    = tx4938ide_inb(io_ports->lbam_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
-                       tf->hob_lbah    = tx4938ide_inb(io_ports->lbah_addr);
+       if (cmd->tf_flags & IDE_TFLAG_LBA48) {
+               tx4938ide_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr);
+
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR)
+                       tf->hob_error = tx4938ide_inb(io_ports->feature_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+                       tf->hob_nsect = tx4938ide_inb(io_ports->nsect_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+                       tf->hob_lbal  = tx4938ide_inb(io_ports->lbal_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+                       tf->hob_lbam  = tx4938ide_inb(io_ports->lbam_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+                       tf->hob_lbah  = tx4938ide_inb(io_ports->lbah_addr);
        }
 }
 
-static void tx4938ide_input_data_swap(ide_drive_t *drive, struct request *rq,
+static void tx4938ide_input_data_swap(ide_drive_t *drive, struct ide_cmd *cmd,
                                void *buf, unsigned int len)
 {
        unsigned long port = drive->hwif->io_ports.data_addr;
@@ -184,7 +169,7 @@ static void tx4938ide_input_data_swap(ide_drive_t *drive, struct request *rq,
        __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
 }
 
-static void tx4938ide_output_data_swap(ide_drive_t *drive, struct request *rq,
+static void tx4938ide_output_data_swap(ide_drive_t *drive, struct ide_cmd *cmd,
                                void *buf, unsigned int len)
 {
        unsigned long port = drive->hwif->io_ports.data_addr;
@@ -202,9 +187,9 @@ static const struct ide_tp_ops tx4938ide_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = tx4938ide_tf_load,
        .tf_read                = tx4938ide_tf_read,
 
index 40b0812a045c9e339171af4960ae6ff0ba890c60..0040a9a3e26e81a1ac0712d8f2eb3434f0f6a7fe 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/io.h>
 #include <linux/scatterlist.h>
 
+#include <asm/ide.h>
+
 #define MODNAME        "tx4939ide"
 
 /* ATA Shadow Registers (8-bit except for Data which is 16-bit) */
@@ -230,7 +232,7 @@ static u8 tx4939ide_clear_dma_status(void __iomem *base)
 
 #ifdef __BIG_ENDIAN
 /* custom ide_build_dmatable to handle swapped layout */
-static int tx4939ide_build_dmatable(ide_drive_t *drive, struct request *rq)
+static int tx4939ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        u32 *table = (u32 *)hwif->dmatable_cpu;
@@ -238,11 +240,7 @@ static int tx4939ide_build_dmatable(ide_drive_t *drive, struct request *rq)
        int i;
        struct scatterlist *sg;
 
-       hwif->sg_nents = ide_build_sglist(drive, rq);
-       if (hwif->sg_nents == 0)
-               return 0;
-
-       for_each_sg(hwif->sg_table, sg, hwif->sg_nents, i) {
+       for_each_sg(hwif->sg_table, sg, cmd->sg_nents, i) {
                u32 cur_addr, cur_len, bcount;
 
                cur_addr = sg_dma_address(sg);
@@ -281,48 +279,36 @@ use_pio_instead:
        printk(KERN_ERR "%s: %s\n", drive->name,
                count ? "DMA table too small" : "empty DMA table?");
 
-       ide_destroy_dmatable(drive);
-
        return 0; /* revert to PIO for this request */
 }
 #else
 #define tx4939ide_build_dmatable       ide_build_dmatable
 #endif
 
-static int tx4939ide_dma_setup(ide_drive_t *drive)
+static int tx4939ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        void __iomem *base = TX4939IDE_BASE(hwif);
-       struct request *rq = hwif->rq;
-       u8 reading;
-       int nent;
-
-       if (rq_data_dir(rq))
-               reading = 0;
-       else
-               reading = ATA_DMA_WR;
+       u8 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR;
 
        /* fall back to PIO! */
-       nent = tx4939ide_build_dmatable(drive, rq);
-       if (!nent) {
-               ide_map_sg(drive, rq);
+       if (tx4939ide_build_dmatable(drive, cmd) == 0)
                return 1;
-       }
 
        /* PRD table */
        tx4939ide_writel(hwif->dmatable_dma, base, TX4939IDE_PRD_Ptr);
 
        /* specify r/w */
-       tx4939ide_writeb(reading, base, TX4939IDE_DMA_Cmd);
+       tx4939ide_writeb(rw, base, TX4939IDE_DMA_Cmd);
 
        /* clear INTR & ERROR flags */
        tx4939ide_clear_dma_status(base);
 
-       drive->waiting_for_dma = 1;
-
        tx4939ide_writew(SECTOR_SIZE / 2, base, drive->dn ?
                         TX4939IDE_Xfer_Cnt_2 : TX4939IDE_Xfer_Cnt_1);
-       tx4939ide_writew(rq->nr_sectors, base, TX4939IDE_Sec_Cnt);
+
+       tx4939ide_writew(cmd->rq->nr_sectors, base, TX4939IDE_Sec_Cnt);
+
        return 0;
 }
 
@@ -333,8 +319,6 @@ static int tx4939ide_dma_end(ide_drive_t *drive)
        void __iomem *base = TX4939IDE_BASE(hwif);
        u16 ctl = tx4939ide_readw(base, TX4939IDE_Int_Ctl);
 
-       drive->waiting_for_dma = 0;
-
        /* get DMA command mode */
        dma_cmd = tx4939ide_readb(base, TX4939IDE_DMA_Cmd);
        /* stop DMA */
@@ -343,11 +327,9 @@ static int tx4939ide_dma_end(ide_drive_t *drive)
        /* read and clear the INTR & ERROR bits */
        dma_stat = tx4939ide_clear_dma_status(base);
 
-       /* purge DMA mappings */
-       ide_destroy_dmatable(drive);
-       /* verify good DMA status */
        wmb();
 
+       /* verify good DMA status */
        if ((dma_stat & (ATA_DMA_INTR | ATA_DMA_ERR | ATA_DMA_ACTIVE)) == 0 &&
            (ctl & (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST)) ==
            (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST))
@@ -437,7 +419,7 @@ static int tx4939ide_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
        return ide_allocate_dma_engine(hwif);
 }
 
-static void tx4939ide_tf_load_fixup(ide_drive_t *drive, ide_task_t *task)
+static void tx4939ide_tf_load_fixup(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        void __iomem *base = TX4939IDE_BASE(hwif);
@@ -447,7 +429,7 @@ static void tx4939ide_tf_load_fixup(ide_drive_t *drive, ide_task_t *task)
         * Fix ATA100 CORE System Control Register. (The write to the
         * Device/Head register may write wrong data to the System
         * Control Register)
-        * While Sys_Ctl is written here, selectproc is not needed.
+        * While Sys_Ctl is written here, dev_select() is not needed.
         */
        tx4939ide_writew(sysctl, base, TX4939IDE_Sys_Ctl);
 }
@@ -465,97 +447,80 @@ static void tx4939ide_outb(u8 value, unsigned long port)
        __raw_writeb(value, (void __iomem *)port);
 }
 
-static void tx4939ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+static void tx4939ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct ide_io_ports *io_ports = &hwif->io_ports;
-       struct ide_taskfile *tf = &task->tf;
-       u8 HIHI = task->tf_flags & IDE_TFLAG_LBA48 ? 0xE0 : 0xEF;
+       struct ide_taskfile *tf = &cmd->tf;
+       u8 HIHI = cmd->tf_flags & IDE_TFLAG_LBA48 ? 0xE0 : 0xEF;
 
-       if (task->tf_flags & IDE_TFLAG_FLAGGED)
+       if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
                HIHI = 0xFF;
 
-       if (task->tf_flags & IDE_TFLAG_OUT_DATA) {
-               u16 data = (tf->hob_data << 8) | tf->data;
-
-               /* no endian swap */
-               __raw_writew(data, (void __iomem *)io_ports->data_addr);
-       }
-
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
                tx4939ide_outb(tf->hob_feature, io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
                tx4939ide_outb(tf->hob_nsect, io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
                tx4939ide_outb(tf->hob_lbal, io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
                tx4939ide_outb(tf->hob_lbam, io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
                tx4939ide_outb(tf->hob_lbah, io_ports->lbah_addr);
 
-       if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_FEATURE)
                tx4939ide_outb(tf->feature, io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_NSECT)
                tx4939ide_outb(tf->nsect, io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAL)
                tx4939ide_outb(tf->lbal, io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAM)
                tx4939ide_outb(tf->lbam, io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_OUT_LBAH)
                tx4939ide_outb(tf->lbah, io_ports->lbah_addr);
 
-       if (task->tf_flags & IDE_TFLAG_OUT_DEVICE) {
+       if (cmd->tf_flags & IDE_TFLAG_OUT_DEVICE) {
                tx4939ide_outb((tf->device & HIHI) | drive->select,
                               io_ports->device_addr);
-               tx4939ide_tf_load_fixup(drive, task);
+               tx4939ide_tf_load_fixup(drive);
        }
 }
 
-static void tx4939ide_tf_read(ide_drive_t *drive, ide_task_t *task)
+static void tx4939ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct ide_io_ports *io_ports = &hwif->io_ports;
-       struct ide_taskfile *tf = &task->tf;
-
-       if (task->tf_flags & IDE_TFLAG_IN_DATA) {
-               u16 data;
-
-               /* no endian swap */
-               data = __raw_readw((void __iomem *)io_ports->data_addr);
-               tf->data = data & 0xff;
-               tf->hob_data = (data >> 8) & 0xff;
-       }
+       struct ide_taskfile *tf = &cmd->tf;
 
        /* be sure we're looking at the low order bits */
-       tx4939ide_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+       tx4939ide_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-       if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
-               tf->feature = tx4939ide_inb(io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+       if (cmd->tf_flags & IDE_TFLAG_IN_ERROR)
+               tf->error  = tx4939ide_inb(io_ports->feature_addr);
+       if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
                tf->nsect  = tx4939ide_inb(io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
                tf->lbal   = tx4939ide_inb(io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAM)
                tf->lbam   = tx4939ide_inb(io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+       if (cmd->tf_flags & IDE_TFLAG_IN_LBAH)
                tf->lbah   = tx4939ide_inb(io_ports->lbah_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+       if (cmd->tf_flags & IDE_TFLAG_IN_DEVICE)
                tf->device = tx4939ide_inb(io_ports->device_addr);
 
-       if (task->tf_flags & IDE_TFLAG_LBA48) {
-               tx4939ide_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
-
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
-                       tf->hob_feature =
-                               tx4939ide_inb(io_ports->feature_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
-                       tf->hob_nsect   = tx4939ide_inb(io_ports->nsect_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
-                       tf->hob_lbal    = tx4939ide_inb(io_ports->lbal_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
-                       tf->hob_lbam    = tx4939ide_inb(io_ports->lbam_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
-                       tf->hob_lbah    = tx4939ide_inb(io_ports->lbah_addr);
+       if (cmd->tf_flags & IDE_TFLAG_LBA48) {
+               tx4939ide_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr);
+
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR)
+                       tf->hob_error = tx4939ide_inb(io_ports->feature_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+                       tf->hob_nsect = tx4939ide_inb(io_ports->nsect_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+                       tf->hob_lbal  = tx4939ide_inb(io_ports->lbal_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+                       tf->hob_lbam  = tx4939ide_inb(io_ports->lbam_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+                       tf->hob_lbah  = tx4939ide_inb(io_ports->lbah_addr);
        }
 }
 
@@ -589,9 +554,9 @@ static const struct ide_tp_ops tx4939ide_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = tx4939ide_tf_load,
        .tf_read                = tx4939ide_tf_read,
 
@@ -601,20 +566,21 @@ static const struct ide_tp_ops tx4939ide_tp_ops = {
 
 #else  /* __LITTLE_ENDIAN */
 
-static void tx4939ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+static void tx4939ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
 {
-       ide_tf_load(drive, task);
-       if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
-               tx4939ide_tf_load_fixup(drive, task);
+       ide_tf_load(drive, cmd);
+
+       if (cmd->tf_flags & IDE_TFLAG_OUT_DEVICE)
+               tx4939ide_tf_load_fixup(drive);
 }
 
 static const struct ide_tp_ops tx4939ide_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = tx4939ide_tf_load,
        .tf_read                = ide_tf_read,
 
@@ -634,12 +600,11 @@ static const struct ide_port_ops tx4939ide_port_ops = {
 static const struct ide_dma_ops tx4939ide_dma_ops = {
        .dma_host_set           = tx4939ide_dma_host_set,
        .dma_setup              = tx4939ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = ide_dma_start,
        .dma_end                = tx4939ide_dma_end,
        .dma_test_irq           = tx4939ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_sff_read_status    = tx4939ide_dma_sff_read_status,
 };
 
index 1730d7331a5dff13a6841fd0009066f49cde6666..ec3db3ade1182b01ef663a946c85de10efa54023 100644 (file)
@@ -903,8 +903,6 @@ static int __init input_proc_init(void)
        if (!proc_bus_input_dir)
                return -ENOMEM;
 
-       proc_bus_input_dir->owner = THIS_MODULE;
-
        entry = proc_create("devices", 0, proc_bus_input_dir,
                            &input_devices_fileops);
        if (!entry)
index 81e6ebf323e9b9a8bdfc780afc487e690caf5c2c..55cd0fa6833984c2b025b3115b6ed81bb4adf6ef 100644 (file)
@@ -381,7 +381,7 @@ static void hgpk_disconnect(struct psmouse *psmouse)
 
 static void hgpk_recalib_work(struct work_struct *work)
 {
-       struct delayed_work *w = container_of(work, struct delayed_work, work);
+       struct delayed_work *w = to_delayed_work(work);
        struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq);
        struct psmouse *psmouse = priv->psmouse;
 
index 3e468d2cf730b0467c44de5403b4c7efaab58933..2d8352419c0db445c57f03d80336cf9e1458faf5 100644 (file)
@@ -1331,12 +1331,6 @@ static void capinc_tty_send_xchar(struct tty_struct *tty, char ch)
 #endif
 }
 
-static int capinc_tty_read_proc(char *page, char **start, off_t off,
-                               int count, int *eof, void *data)
-{
-       return 0;
-}
-
 static struct tty_driver *capinc_tty_driver;
 
 static const struct tty_operations capinc_ops = {
@@ -1358,7 +1352,6 @@ static const struct tty_operations capinc_ops = {
        .flush_buffer = capinc_tty_flush_buffer,
        .set_ldisc = capinc_tty_set_ldisc,
        .send_xchar = capinc_tty_send_xchar,
-       .read_proc = capinc_tty_read_proc,
 };
 
 static int capinc_tty_init(void)
index f4969fe0a0554ad5f567268075be2a6e90b34bb1..69e71ebe7841830bf2af1dc68b894186b776cb91 100644 (file)
@@ -118,7 +118,6 @@ static int DIVA_INIT_FUNCTION create_um_idi_proc(void)
                return (0);
 
        um_idi_proc_entry->read_proc = um_idi_proc_read;
-       um_idi_proc_entry->owner = THIS_MODULE;
 
        return (1);
 }
index 60156dfdc608cf5e8d45e40ec34a51d09a084664..4845fb3cf74bd8911dc3a48b8370c722be688512 100644 (file)
@@ -152,8 +152,8 @@ static void unmap_switcher(void)
  * code.  We have to check that the range is below the pfn_limit the Launcher
  * gave us.  We have to make sure that addr + len doesn't give us a false
  * positive by overflowing, too. */
-int lguest_address_ok(const struct lguest *lg,
-                     unsigned long addr, unsigned long len)
+bool lguest_address_ok(const struct lguest *lg,
+                      unsigned long addr, unsigned long len)
 {
        return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr);
 }
index 415fab0125acd8e465e1fe2e6fe8241d75894868..6e99adbe1946e8810951460872fdd59d79985ebf 100644 (file)
@@ -34,7 +34,7 @@ static int idt_type(u32 lo, u32 hi)
 }
 
 /* An IDT entry can't be used unless the "present" bit is set. */
-static int idt_present(u32 lo, u32 hi)
+static bool idt_present(u32 lo, u32 hi)
 {
        return (hi & 0x8000);
 }
@@ -60,7 +60,8 @@ static void push_guest_stack(struct lg_cpu *cpu, unsigned long *gstack, u32 val)
  * We set up the stack just like the CPU does for a real interrupt, so it's
  * identical for the Guest (and the standard "iret" instruction will undo
  * it). */
-static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi, int has_err)
+static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi,
+                               bool has_err)
 {
        unsigned long gstack, origstack;
        u32 eflags, ss, irq_enable;
@@ -184,7 +185,7 @@ void maybe_do_interrupt(struct lg_cpu *cpu)
                /* set_guest_interrupt() takes the interrupt descriptor and a
                 * flag to say whether this interrupt pushes an error code onto
                 * the stack as well: virtual interrupts never do. */
-               set_guest_interrupt(cpu, idt->a, idt->b, 0);
+               set_guest_interrupt(cpu, idt->a, idt->b, false);
        }
 
        /* Every time we deliver an interrupt, we update the timestamp in the
@@ -244,26 +245,26 @@ void free_interrupts(void)
 /*H:220 Now we've got the routines to deliver interrupts, delivering traps like
  * page fault is easy.  The only trick is that Intel decided that some traps
  * should have error codes: */
-static int has_err(unsigned int trap)
+static bool has_err(unsigned int trap)
 {
        return (trap == 8 || (trap >= 10 && trap <= 14) || trap == 17);
 }
 
 /* deliver_trap() returns true if it could deliver the trap. */
-int deliver_trap(struct lg_cpu *cpu, unsigned int num)
+bool deliver_trap(struct lg_cpu *cpu, unsigned int num)
 {
        /* Trap numbers are always 8 bit, but we set an impossible trap number
         * for traps inside the Switcher, so check that here. */
        if (num >= ARRAY_SIZE(cpu->arch.idt))
-               return 0;
+               return false;
 
        /* Early on the Guest hasn't set the IDT entries (or maybe it put a
         * bogus one in): if we fail here, the Guest will be killed. */
        if (!idt_present(cpu->arch.idt[num].a, cpu->arch.idt[num].b))
-               return 0;
+               return false;
        set_guest_interrupt(cpu, cpu->arch.idt[num].a,
                            cpu->arch.idt[num].b, has_err(num));
-       return 1;
+       return true;
 }
 
 /*H:250 Here's the hard part: returning to the Host every time a trap happens
@@ -279,18 +280,19 @@ int deliver_trap(struct lg_cpu *cpu, unsigned int num)
  *
  * This routine indicates if a particular trap number could be delivered
  * directly. */
-static int direct_trap(unsigned int num)
+static bool direct_trap(unsigned int num)
 {
        /* Hardware interrupts don't go to the Guest at all (except system
         * call). */
        if (num >= FIRST_EXTERNAL_VECTOR && !could_be_syscall(num))
-               return 0;
+               return false;
 
        /* The Host needs to see page faults (for shadow paging and to save the
         * fault address), general protection faults (in/out emulation) and
-        * device not available (TS handling), and of course, the hypercall
-        * trap. */
-       return num != 14 && num != 13 && num != 7 && num != LGUEST_TRAP_ENTRY;
+        * device not available (TS handling), invalid opcode fault (kvm hcall),
+        * and of course, the hypercall trap. */
+       return num != 14 && num != 13 && num != 7 &&
+                       num != 6 && num != LGUEST_TRAP_ENTRY;
 }
 /*:*/
 
index f2c641e0bdde508887809176774badcc31519622..ac8a4a3741b831e36d5ca499f85424e90b9d1335 100644 (file)
@@ -109,8 +109,8 @@ struct lguest
 extern struct mutex lguest_lock;
 
 /* core.c: */
-int lguest_address_ok(const struct lguest *lg,
-                     unsigned long addr, unsigned long len);
+bool lguest_address_ok(const struct lguest *lg,
+                      unsigned long addr, unsigned long len);
 void __lgread(struct lg_cpu *, void *, unsigned long, unsigned);
 void __lgwrite(struct lg_cpu *, unsigned long, const void *, unsigned);
 
@@ -140,7 +140,7 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user);
 
 /* interrupts_and_traps.c: */
 void maybe_do_interrupt(struct lg_cpu *cpu);
-int deliver_trap(struct lg_cpu *cpu, unsigned int num);
+bool deliver_trap(struct lg_cpu *cpu, unsigned int num);
 void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int i,
                          u32 low, u32 hi);
 void guest_set_stack(struct lg_cpu *cpu, u32 seg, u32 esp, unsigned int pages);
@@ -173,7 +173,7 @@ void guest_pagetable_flush_user(struct lg_cpu *cpu);
 void guest_set_pte(struct lg_cpu *cpu, unsigned long gpgdir,
                   unsigned long vaddr, pte_t val);
 void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages);
-int demand_page(struct lg_cpu *cpu, unsigned long cr2, int errcode);
+bool demand_page(struct lg_cpu *cpu, unsigned long cr2, int errcode);
 void pin_page(struct lg_cpu *cpu, unsigned long vaddr);
 unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr);
 void page_table_guest_data_init(struct lg_cpu *cpu);
index 8132533d71f9384e3e73aca8092b02295cd75024..df44d962626d327ba26a3b1a2aa83a2bba383390 100644 (file)
@@ -161,7 +161,7 @@ static void set_status(struct virtio_device *vdev, u8 status)
 
        /* We set the status. */
        to_lgdev(vdev)->desc->status = status;
-       hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
+       kvm_hypercall1(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset);
 }
 
 static void lg_set_status(struct virtio_device *vdev, u8 status)
@@ -209,7 +209,7 @@ static void lg_notify(struct virtqueue *vq)
         * virtqueue structure. */
        struct lguest_vq_info *lvq = vq->priv;
 
-       hcall(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT, 0, 0);
+       kvm_hypercall1(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT);
 }
 
 /* An extern declaration inside a C file is bad form.  Don't do it. */
index 576a8318221c9dfe47dc28a660565094c9ef7753..a059cf9980f711b97d2009545b574e63cf79fddc 100644 (file)
@@ -199,7 +199,7 @@ static void check_gpgd(struct lg_cpu *cpu, pgd_t gpgd)
  *
  * If we fixed up the fault (ie. we mapped the address), this routine returns
  * true.  Otherwise, it was a real fault and we need to tell the Guest. */
-int demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
+bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
 {
        pgd_t gpgd;
        pgd_t *spgd;
@@ -211,7 +211,7 @@ int demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
        gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t);
        /* Toplevel not present?  We can't map it in. */
        if (!(pgd_flags(gpgd) & _PAGE_PRESENT))
-               return 0;
+               return false;
 
        /* Now look at the matching shadow entry. */
        spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr);
@@ -222,7 +222,7 @@ int demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
                 * simple for this corner case. */
                if (!ptepage) {
                        kill_guest(cpu, "out of memory allocating pte page");
-                       return 0;
+                       return false;
                }
                /* We check that the Guest pgd is OK. */
                check_gpgd(cpu, gpgd);
@@ -238,16 +238,16 @@ int demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
 
        /* If this page isn't in the Guest page tables, we can't page it in. */
        if (!(pte_flags(gpte) & _PAGE_PRESENT))
-               return 0;
+               return false;
 
        /* Check they're not trying to write to a page the Guest wants
         * read-only (bit 2 of errcode == write). */
        if ((errcode & 2) && !(pte_flags(gpte) & _PAGE_RW))
-               return 0;
+               return false;
 
        /* User access to a kernel-only page? (bit 3 == user access) */
        if ((errcode & 4) && !(pte_flags(gpte) & _PAGE_USER))
-               return 0;
+               return false;
 
        /* Check that the Guest PTE flags are OK, and the page number is below
         * the pfn_limit (ie. not mapping the Launcher binary). */
@@ -283,7 +283,7 @@ int demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
         * manipulated, the result returned and the code complete.  A small
         * delay and a trace of alliteration are the only indications the Guest
         * has that a page fault occurred at all. */
-       return 1;
+       return true;
 }
 
 /*H:360
@@ -296,7 +296,7 @@ int demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
  *
  * This is a quick version which answers the question: is this virtual address
  * mapped by the shadow page tables, and is it writable? */
-static int page_writable(struct lg_cpu *cpu, unsigned long vaddr)
+static bool page_writable(struct lg_cpu *cpu, unsigned long vaddr)
 {
        pgd_t *spgd;
        unsigned long flags;
@@ -304,7 +304,7 @@ static int page_writable(struct lg_cpu *cpu, unsigned long vaddr)
        /* Look at the current top level entry: is it present? */
        spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr);
        if (!(pgd_flags(*spgd) & _PAGE_PRESENT))
-               return 0;
+               return false;
 
        /* Check the flags on the pte entry itself: it must be present and
         * writable. */
@@ -373,8 +373,10 @@ unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
        /* First step: get the top-level Guest page table entry. */
        gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t);
        /* Toplevel not present?  We can't map it in. */
-       if (!(pgd_flags(gpgd) & _PAGE_PRESENT))
+       if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) {
                kill_guest(cpu, "Bad address %#lx", vaddr);
+               return -1UL;
+       }
 
        gpte = lgread(cpu, gpte_addr(gpgd, vaddr), pte_t);
        if (!(pte_flags(gpte) & _PAGE_PRESENT))
index ec6aa3f1c36b349464e946375de109cc606c82a2..4f15439b7f1288c8f0f9462e42e76db4471c199c 100644 (file)
@@ -45,7 +45,7 @@
  * "Task State Segment" which controls all kinds of delicate things.  The
  * LGUEST_CS and LGUEST_DS entries are reserved for the Switcher, and the
  * the Guest can't be trusted to deal with double faults. */
-static int ignored_gdt(unsigned int num)
+static bool ignored_gdt(unsigned int num)
 {
        return (num == GDT_ENTRY_TSS
                || num == GDT_ENTRY_LGUEST_CS
index bf7942327bda5c2f122889e9881e1b7d90acaf44..a6b717644be0d50efc2f257e52e9e543cc545833 100644 (file)
@@ -290,6 +290,57 @@ static int emulate_insn(struct lg_cpu *cpu)
        return 1;
 }
 
+/* Our hypercalls mechanism used to be based on direct software interrupts.
+ * After Anthony's "Refactor hypercall infrastructure" kvm patch, we decided to
+ * change over to using kvm hypercalls.
+ *
+ * KVM_HYPERCALL is actually a "vmcall" instruction, which generates an invalid
+ * opcode fault (fault 6) on non-VT cpus, so the easiest solution seemed to be
+ * an *emulation approach*: if the fault was really produced by an hypercall
+ * (is_hypercall() does exactly this check), we can just call the corresponding
+ * hypercall host implementation function.
+ *
+ * But these invalid opcode faults are notably slower than software interrupts.
+ * So we implemented the *patching (or rewriting) approach*: every time we hit
+ * the KVM_HYPERCALL opcode in Guest code, we patch it to the old "int 0x1f"
+ * opcode, so next time the Guest calls this hypercall it will use the
+ * faster trap mechanism.
+ *
+ * Matias even benchmarked it to convince you: this shows the average cycle
+ * cost of a hypercall.  For each alternative solution mentioned above we've
+ * made 5 runs of the benchmark:
+ *
+ * 1) direct software interrupt: 2915, 2789, 2764, 2721, 2898
+ * 2) emulation technique: 3410, 3681, 3466, 3392, 3780
+ * 3) patching (rewrite) technique: 2977, 2975, 2891, 2637, 2884
+ *
+ * One two-line function is worth a 20% hypercall speed boost!
+ */
+static void rewrite_hypercall(struct lg_cpu *cpu)
+{
+       /* This are the opcodes we use to patch the Guest.  The opcode for "int
+        * $0x1f" is "0xcd 0x1f" but vmcall instruction is 3 bytes long, so we
+        * complete the sequence with a NOP (0x90). */
+       u8 insn[3] = {0xcd, 0x1f, 0x90};
+
+       __lgwrite(cpu, guest_pa(cpu, cpu->regs->eip), insn, sizeof(insn));
+}
+
+static bool is_hypercall(struct lg_cpu *cpu)
+{
+       u8 insn[3];
+
+       /* This must be the Guest kernel trying to do something.
+        * The bottom two bits of the CS segment register are the privilege
+        * level. */
+       if ((cpu->regs->cs & 3) != GUEST_PL)
+               return false;
+
+       /* Is it a vmcall? */
+       __lgread(cpu, insn, guest_pa(cpu, cpu->regs->eip), sizeof(insn));
+       return insn[0] == 0x0f && insn[1] == 0x01 && insn[2] == 0xc1;
+}
+
 /*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */
 void lguest_arch_handle_trap(struct lg_cpu *cpu)
 {
@@ -337,7 +388,7 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu)
                break;
        case 32 ... 255:
                /* These values mean a real interrupt occurred, in which case
-                * the Host handler has already been run.  We just do a
+                * the Host handler has already been run. We just do a
                 * friendly check if another process should now be run, then
                 * return to run the Guest again */
                cond_resched();
@@ -347,6 +398,15 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu)
                 * up the pointer now to indicate a hypercall is pending. */
                cpu->hcall = (struct hcall_args *)cpu->regs;
                return;
+       case 6:
+               /* kvm hypercalls trigger an invalid opcode fault (6).
+                * We need to check if ring == GUEST_PL and
+                * faulting instruction == vmcall. */
+               if (is_hypercall(cpu)) {
+                       rewrite_hypercall(cpu);
+                       return;
+               }
+               break;
        }
 
        /* We didn't handle the trap, so it needs to go to the Guest. */
index 82607add69a9bc6b6b9c1ee306c307c6b72c9cf9..c0621d50c8a0ca1281881b68d587f1c8be81ec96 100644 (file)
@@ -498,8 +498,8 @@ static ssize_t store_##name(struct device *dev, struct device_attribute *attr, c
 #define BUILD_STORE_FUNC_INT(name, data)                       \
 static ssize_t store_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) \
 {                                                              \
-       u32 val;                                                \
-       val = simple_strtoul(buf, NULL, 10);                    \
+       int val;                                                \
+       val = simple_strtol(buf, NULL, 10);                     \
        if (val < 0 || val > 255)                               \
                return -EINVAL;                                 \
        printk(KERN_INFO "Setting specified fan speed to %d\n", val);   \
index 93ea201f426cad53997ee815c69c1679bbe70b39..223c36ede5ae66e3552682c63bc9fc9df4394d57 100644 (file)
@@ -117,7 +117,7 @@ source "drivers/media/dvb/Kconfig"
 config DAB
        boolean "DAB adapters"
        ---help---
-         Allow selecting support for for Digital Audio Broadcasting (DAB)
+         Allow selecting support for Digital Audio Broadcasting (DAB)
          Receiver adapters.
 
 if DAB
index d8229a0e9a9c4754603bb8cf0bfefd05e72ad36e..3fe158ac7bbfdc697ed0dd701f637210169fa636 100644 (file)
@@ -153,6 +153,65 @@ IR_KEYTAB_TYPE ir_codes_avermedia_m135a[IR_KEYTAB_SIZE] = {
 };
 EXPORT_SYMBOL_GPL(ir_codes_avermedia_m135a);
 
+/* 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);
+
 /* Attila Kondoros <attila.kondoros@chello.hu> */
 IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
 
@@ -2452,6 +2511,55 @@ IR_KEYTAB_TYPE ir_codes_kworld_plus_tv_analog[IR_KEYTAB_SIZE] = {
 };
 EXPORT_SYMBOL_GPL(ir_codes_kworld_plus_tv_analog);
 
+/* 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,
@@ -2604,3 +2712,41 @@ IR_KEYTAB_TYPE ir_codes_ati_tv_wonder_hd_600[IR_KEYTAB_SIZE] = {
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_ati_tv_wonder_hd_600);
+
+/* 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);
index d599d360da3fafcbcd26d72c19419683f1f2c4cb..982f000a57ffc896eeeda4c8295db20fdb6ff8c6 100644 (file)
@@ -452,8 +452,6 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
        INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device));
        dev->ext = ext;
 
-       pci_set_drvdata(pci, dev);
-
        mutex_init(&dev->lock);
        spin_lock_init(&dev->int_slock);
        spin_lock_init(&dev->slock);
@@ -477,8 +475,12 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
 
        if (ext->attach(dev, pci_ext)) {
                DEB_D(("ext->attach() failed for %p. skipping device.\n",dev));
-               goto err_unprobe;
+               goto err_free_i2c;
        }
+       /* V4L extensions will set the pci drvdata to the v4l2_device in the
+          attach() above. So for those cards that do not use V4L we have to
+          set it explicitly. */
+       pci_set_drvdata(pci, &dev->v4l2_dev);
 
        INIT_LIST_HEAD(&dev->item);
        list_add_tail(&dev->item,&saa7146_devices);
@@ -488,8 +490,6 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
 out:
        return err;
 
-err_unprobe:
-       pci_set_drvdata(pci, NULL);
 err_free_i2c:
        pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr,
                            dev->d_i2c.dma_handle);
@@ -514,7 +514,8 @@ err_free:
 
 static void saa7146_remove_one(struct pci_dev *pdev)
 {
-       struct saa7146_dev* dev = pci_get_drvdata(pdev);
+       struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+       struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev);
        struct {
                void *addr;
                dma_addr_t dma;
@@ -528,6 +529,8 @@ static void saa7146_remove_one(struct pci_dev *pdev)
        DEB_EE(("dev:%p\n",dev));
 
        dev->ext->detach(dev);
+       /* Zero the PCI drvdata after use. */
+       pci_set_drvdata(pdev, NULL);
 
        /* shut down all video dma transfers */
        saa7146_write(dev, MC1, 0x00ff0000);
index cf06f4d10ad4229332d5d0b0146b630c4342fb09..620f655fa9c5b1e2602755fff2dadf9f7689000b 100644 (file)
@@ -308,14 +308,6 @@ static int fops_release(struct file *file)
        return 0;
 }
 
-static long fops_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-/*
-       DEB_EE(("file:%p, cmd:%d, arg:%li\n", file, cmd, arg));
-*/
-       return video_usercopy(file, cmd, arg, saa7146_video_do_ioctl);
-}
-
 static int fops_mmap(struct file *file, struct vm_area_struct * vma)
 {
        struct saa7146_fh *fh = file->private_data;
@@ -425,7 +417,7 @@ static const struct v4l2_file_operations video_fops =
        .write          = fops_write,
        .poll           = fops_poll,
        .mmap           = fops_mmap,
-       .ioctl          = fops_ioctl,
+       .ioctl          = video_ioctl2,
 };
 
 static void vv_callback(struct saa7146_dev *dev, unsigned long status)
@@ -452,19 +444,22 @@ static void vv_callback(struct saa7146_dev *dev, unsigned long status)
        }
 }
 
-static struct video_device device_template =
-{
-       .fops           = &video_fops,
-       .minor          = -1,
-};
-
 int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
 {
-       struct saa7146_vv *vv = kzalloc (sizeof(struct saa7146_vv),GFP_KERNEL);
-       if( NULL == vv ) {
+       struct saa7146_vv *vv;
+       int err;
+
+       err = v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev);
+       if (err)
+               return err;
+
+       vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
+       if (vv == NULL) {
                ERR(("out of memory. aborting.\n"));
-               return -1;
+               return -ENOMEM;
        }
+       ext_vv->ops = saa7146_video_ioctl_ops;
+       ext_vv->core_ops = &saa7146_video_ioctl_ops;
 
        DEB_EE(("dev:%p\n",dev));
 
@@ -507,6 +502,7 @@ int saa7146_vv_release(struct saa7146_dev* dev)
 
        DEB_EE(("dev:%p\n",dev));
 
+       v4l2_device_unregister(&dev->v4l2_dev);
        pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
        kfree(vv);
        dev->vv_data = NULL;
@@ -521,6 +517,8 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
 {
        struct saa7146_vv *vv = dev->vv_data;
        struct video_device *vfd;
+       int err;
+       int i;
 
        DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type));
 
@@ -529,16 +527,20 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
        if (vfd == NULL)
                return -ENOMEM;
 
-       memcpy(vfd, &device_template, sizeof(struct video_device));
-       strlcpy(vfd->name, name, sizeof(vfd->name));
+       vfd->fops = &video_fops;
+       vfd->ioctl_ops = &dev->ext_vv_data->ops;
        vfd->release = video_device_release;
+       vfd->tvnorms = 0;
+       for (i = 0; i < dev->ext_vv_data->num_stds; i++)
+               vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
+       strlcpy(vfd->name, name, sizeof(vfd->name));
        video_set_drvdata(vfd, dev);
 
-       // fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
-       if (video_register_device(vfd, type, -1) < 0) {
+       err = video_register_device(vfd, type, -1);
+       if (err < 0) {
                ERR(("cannot register v4l2 device. skipping.\n"));
                video_device_release(vfd);
-               return -1;
+               return err;
        }
 
        if( VFL_TYPE_GRABBER == type ) {
index c11da4d09cd0971d17487371fd6d1b7967894ac4..7e8f568159985d4c62a32753e358bfd73b135d8c 100644 (file)
@@ -293,7 +293,6 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
        int i = 0, count = 0;
        __le32 *buffer = dev->d_i2c.cpu_addr;
        int err = 0;
-       int address_err = 0;
        int short_delay = 0;
 
        if (mutex_lock_interruptible(&dev->i2c_lock))
@@ -333,17 +332,10 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
                                   i2c address probing, however, and address errors indicate that a
                                   device is really *not* there. retrying in that case
                                   increases the time the device needs to probe greatly, so
-                                  it should be avoided. because of the fact, that only
-                                  analog based cards use irq based i2c transactions (for dvb
-                                  cards, this screwes up other interrupt sources), we bail out
-                                  completely for analog cards after an address error and trust
-                                  the saa7146 address error detection. */
-                               if ( -EREMOTEIO == err ) {
-                                       if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) {
-                                               goto out;
-                                       }
-                                       address_err++;
-                               }
+                                  it should be avoided. So we bail out in irq mode after an
+                                  address error and trust the saa7146 address error detection. */
+                               if (-EREMOTEIO == err && 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags))
+                                       goto out;
                                DEB_I2C(("error while sending message(s). starting again.\n"));
                                break;
                        }
@@ -358,10 +350,9 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
 
        } while (err != num && retries--);
 
-       /* if every retry had an address error, exit right away */
-       if (address_err == retries) {
+       /* quit if any error occurred */
+       if (err != num)
                goto out;
-       }
 
        /* if any things had to be read, get the results */
        if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer)) {
@@ -390,7 +381,8 @@ out:
 /* utility functions */
 static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num)
 {
-       struct saa7146_dev* dev = i2c_get_adapdata(adapter);
+       struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
+       struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev);
 
        /* use helper function to transfer data */
        return saa7146_i2c_transfer(dev, msg, num, adapter->retries);
@@ -417,9 +409,8 @@ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c
        dev->i2c_bitrate = bitrate;
        saa7146_i2c_reset(dev);
 
-       if( NULL != i2c_adapter ) {
-               BUG_ON(!i2c_adapter->class);
-               i2c_set_adapdata(i2c_adapter,dev);
+       if (i2c_adapter) {
+               i2c_set_adapdata(i2c_adapter, &dev->v4l2_dev);
                i2c_adapter->dev.parent    = &dev->pci->dev;
                i2c_adapter->algo          = &saa7146_algo;
                i2c_adapter->algo_data     = NULL;
index 47fee05eaefbab9a67492f5c97067a5874fa341e..552dab442d78dbe524a8ff354d60bbc4ff42ddec 100644 (file)
@@ -1,4 +1,5 @@
 #include <media/saa7146_vv.h>
+#include <media/v4l2-chip-ident.h>
 
 static int max_memory = 32;
 
@@ -97,172 +98,13 @@ struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc)
        return NULL;
 }
 
-static int g_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
-{
-       struct saa7146_dev *dev = fh->dev;
-       DEB_EE(("dev:%p, fh:%p\n",dev,fh));
-
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               f->fmt.pix = fh->video_fmt;
-               return 0;
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               f->fmt.win = fh->ov.win;
-               return 0;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-       {
-               f->fmt.vbi = fh->vbi_fmt;
-               return 0;
-       }
-       default:
-               DEB_D(("invalid format type '%d'.\n",f->type));
-               return -EINVAL;
-       }
-}
-
-static int try_win(struct saa7146_dev *dev, struct v4l2_window *win)
-{
-       struct saa7146_vv *vv = dev->vv_data;
-       enum v4l2_field field;
-       int maxw, maxh;
-
-       DEB_EE(("dev:%p\n",dev));
-
-       if (NULL == vv->ov_fb.base) {
-               DEB_D(("no fb base set.\n"));
-               return -EINVAL;
-       }
-       if (NULL == vv->ov_fmt) {
-               DEB_D(("no fb fmt set.\n"));
-               return -EINVAL;
-       }
-       if (win->w.width < 48 || win->w.height <  32) {
-               DEB_D(("min width/height. (%d,%d)\n",win->w.width,win->w.height));
-               return -EINVAL;
-       }
-       if (win->clipcount > 16) {
-               DEB_D(("clipcount too big.\n"));
-               return -EINVAL;
-       }
-
-       field = win->field;
-       maxw  = vv->standard->h_max_out;
-       maxh  = vv->standard->v_max_out;
-
-       if (V4L2_FIELD_ANY == field) {
-               field = (win->w.height > maxh/2)
-                       ? V4L2_FIELD_INTERLACED
-                       : V4L2_FIELD_TOP;
-               }
-       switch (field) {
-       case V4L2_FIELD_TOP:
-       case V4L2_FIELD_BOTTOM:
-       case V4L2_FIELD_ALTERNATE:
-               maxh = maxh / 2;
-               break;
-       case V4L2_FIELD_INTERLACED:
-               break;
-       default: {
-               DEB_D(("no known field mode '%d'.\n",field));
-               return -EINVAL;
-       }
-       }
-
-       win->field = field;
-       if (win->w.width > maxw)
-               win->w.width = maxw;
-       if (win->w.height > maxh)
-               win->w.height = maxh;
-
-       return 0;
-}
-
-static int try_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
-{
-       struct saa7146_dev *dev = fh->dev;
-       struct saa7146_vv *vv = dev->vv_data;
-       int err;
-
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-       {
-               struct saa7146_format *fmt;
-               enum v4l2_field field;
-               int maxw, maxh;
-               int calc_bpl;
-
-               DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh));
-
-               fmt = format_by_fourcc(dev,f->fmt.pix.pixelformat);
-               if (NULL == fmt) {
-                       return -EINVAL;
-               }
-
-               field = f->fmt.pix.field;
-               maxw  = vv->standard->h_max_out;
-               maxh  = vv->standard->v_max_out;
-
-               if (V4L2_FIELD_ANY == field) {
-                       field = (f->fmt.pix.height > maxh/2)
-                               ? V4L2_FIELD_INTERLACED
-                               : V4L2_FIELD_BOTTOM;
-               }
-               switch (field) {
-               case V4L2_FIELD_ALTERNATE: {
-                       vv->last_field = V4L2_FIELD_TOP;
-                       maxh = maxh / 2;
-                       break;
-               }
-               case V4L2_FIELD_TOP:
-               case V4L2_FIELD_BOTTOM:
-                       vv->last_field = V4L2_FIELD_INTERLACED;
-                       maxh = maxh / 2;
-                       break;
-               case V4L2_FIELD_INTERLACED:
-                       vv->last_field = V4L2_FIELD_INTERLACED;
-                       break;
-               default: {
-                       DEB_D(("no known field mode '%d'.\n",field));
-                       return -EINVAL;
-               }
-               }
-
-               f->fmt.pix.field = field;
-               if (f->fmt.pix.width > maxw)
-                       f->fmt.pix.width = maxw;
-               if (f->fmt.pix.height > maxh)
-                       f->fmt.pix.height = maxh;
-
-               calc_bpl = (f->fmt.pix.width * fmt->depth)/8;
-
-               if (f->fmt.pix.bytesperline < calc_bpl)
-                       f->fmt.pix.bytesperline = calc_bpl;
-
-               if (f->fmt.pix.bytesperline > (2*PAGE_SIZE * fmt->depth)/8) /* arbitrary constraint */
-                       f->fmt.pix.bytesperline = calc_bpl;
-
-               f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
-               DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n",f->fmt.pix.width,f->fmt.pix.height,f->fmt.pix.bytesperline,f->fmt.pix.sizeimage));
-
-               return 0;
-       }
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n",dev,fh));
-               err = try_win(dev,&f->fmt.win);
-               if (0 != err) {
-                       return err;
-               }
-               return 0;
-       default:
-               DEB_EE(("unknown format type '%d'\n",f->type));
-               return -EINVAL;
-       }
-}
+static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f);
 
 int saa7146_start_preview(struct saa7146_fh *fh)
 {
        struct saa7146_dev *dev = fh->dev;
        struct saa7146_vv *vv = dev->vv_data;
+       struct v4l2_format fmt;
        int ret = 0, err = 0;
 
        DEB_EE(("dev:%p, fh:%p\n",dev,fh));
@@ -294,12 +136,13 @@ int saa7146_start_preview(struct saa7146_fh *fh)
                return -EBUSY;
        }
 
-       err = try_win(dev,&fh->ov.win);
+       fmt.fmt.win = fh->ov.win;
+       err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt);
        if (0 != err) {
                saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
                return -EBUSY;
        }
-
+       fh->ov.win = fmt.fmt.win;
        vv->ov_data = &fh->ov;
 
        DEB_D(("%dx%d+%d+%d %s field=%s\n",
@@ -355,58 +198,6 @@ int saa7146_stop_preview(struct saa7146_fh *fh)
 }
 EXPORT_SYMBOL_GPL(saa7146_stop_preview);
 
-static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
-{
-       struct saa7146_dev *dev = fh->dev;
-       struct saa7146_vv *vv = dev->vv_data;
-
-       int err;
-
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh));
-               if (IS_CAPTURE_ACTIVE(fh) != 0) {
-                       DEB_EE(("streaming capture is active\n"));
-                       return -EBUSY;
-               }
-               err = try_fmt(fh,f);
-               if (0 != err)
-                       return err;
-               fh->video_fmt = f->fmt.pix;
-               DEB_EE(("set to pixelformat '%4.4s'\n",(char *)&fh->video_fmt.pixelformat));
-               return 0;
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n",dev,fh));
-               err = try_win(dev,&f->fmt.win);
-               if (0 != err)
-                       return err;
-               mutex_lock(&dev->lock);
-               fh->ov.win    = f->fmt.win;
-               fh->ov.nclips = f->fmt.win.clipcount;
-               if (fh->ov.nclips > 16)
-                       fh->ov.nclips = 16;
-               if (copy_from_user(fh->ov.clips,f->fmt.win.clips,sizeof(struct v4l2_clip)*fh->ov.nclips)) {
-                       mutex_unlock(&dev->lock);
-                       return -EFAULT;
-               }
-
-               /* fh->ov.fh is used to indicate that we have valid overlay informations, too */
-               fh->ov.fh = fh;
-
-               mutex_unlock(&dev->lock);
-
-               /* check if our current overlay is active */
-               if (IS_OVERLAY_ACTIVE(fh) != 0) {
-                       saa7146_stop_preview(fh);
-                       saa7146_start_preview(fh);
-               }
-               return 0;
-       default:
-               DEB_D(("unknown format type '%d'\n",f->type));
-               return -EINVAL;
-       }
-}
-
 /********************************************************************************/
 /* device controls */
 
@@ -419,6 +210,7 @@ static struct v4l2_queryctrl controls[] = {
                .step           = 1,
                .default_value  = 128,
                .type           = V4L2_CTRL_TYPE_INTEGER,
+               .flags          = V4L2_CTRL_FLAG_SLIDER,
        },{
                .id             = V4L2_CID_CONTRAST,
                .name           = "Contrast",
@@ -427,6 +219,7 @@ static struct v4l2_queryctrl controls[] = {
                .step           = 1,
                .default_value  = 64,
                .type           = V4L2_CTRL_TYPE_INTEGER,
+               .flags          = V4L2_CTRL_FLAG_SLIDER,
        },{
                .id             = V4L2_CID_SATURATION,
                .name           = "Saturation",
@@ -435,15 +228,16 @@ static struct v4l2_queryctrl controls[] = {
                .step           = 1,
                .default_value  = 64,
                .type           = V4L2_CTRL_TYPE_INTEGER,
+               .flags          = V4L2_CTRL_FLAG_SLIDER,
        },{
                .id             = V4L2_CID_VFLIP,
-               .name           = "Vertical flip",
+               .name           = "Vertical Flip",
                .minimum        = 0,
                .maximum        = 1,
                .type           = V4L2_CTRL_TYPE_BOOLEAN,
        },{
                .id             = V4L2_CID_HFLIP,
-               .name           = "Horizontal flip",
+               .name           = "Horizontal Flip",
                .minimum        = 0,
                .maximum        = 1,
                .type           = V4L2_CTRL_TYPE_BOOLEAN,
@@ -463,132 +257,6 @@ static struct v4l2_queryctrl* ctrl_by_id(int id)
        return NULL;
 }
 
-static int get_control(struct saa7146_fh *fh, struct v4l2_control *c)
-{
-       struct saa7146_dev *dev = fh->dev;
-       struct saa7146_vv *vv = dev->vv_data;
-
-       const struct v4l2_queryctrl* ctrl;
-       u32 value = 0;
-
-       ctrl = ctrl_by_id(c->id);
-       if (NULL == ctrl)
-               return -EINVAL;
-       switch (c->id) {
-       case V4L2_CID_BRIGHTNESS:
-               value = saa7146_read(dev, BCS_CTRL);
-               c->value = 0xff & (value >> 24);
-               DEB_D(("V4L2_CID_BRIGHTNESS: %d\n",c->value));
-               break;
-       case V4L2_CID_CONTRAST:
-               value = saa7146_read(dev, BCS_CTRL);
-               c->value = 0x7f & (value >> 16);
-               DEB_D(("V4L2_CID_CONTRAST: %d\n",c->value));
-               break;
-       case V4L2_CID_SATURATION:
-               value = saa7146_read(dev, BCS_CTRL);
-               c->value = 0x7f & (value >> 0);
-               DEB_D(("V4L2_CID_SATURATION: %d\n",c->value));
-               break;
-       case V4L2_CID_VFLIP:
-               c->value = vv->vflip;
-               DEB_D(("V4L2_CID_VFLIP: %d\n",c->value));
-               break;
-       case V4L2_CID_HFLIP:
-               c->value = vv->hflip;
-               DEB_D(("V4L2_CID_HFLIP: %d\n",c->value));
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
-{
-       struct saa7146_dev *dev = fh->dev;
-       struct saa7146_vv *vv = dev->vv_data;
-
-       const struct v4l2_queryctrl* ctrl;
-
-       ctrl = ctrl_by_id(c->id);
-       if (NULL == ctrl) {
-               DEB_D(("unknown control %d\n",c->id));
-               return -EINVAL;
-       }
-
-       mutex_lock(&dev->lock);
-
-       switch (ctrl->type) {
-       case V4L2_CTRL_TYPE_BOOLEAN:
-       case V4L2_CTRL_TYPE_MENU:
-       case V4L2_CTRL_TYPE_INTEGER:
-               if (c->value < ctrl->minimum)
-                       c->value = ctrl->minimum;
-               if (c->value > ctrl->maximum)
-                       c->value = ctrl->maximum;
-               break;
-       default:
-               /* nothing */;
-       };
-
-       switch (c->id) {
-       case V4L2_CID_BRIGHTNESS: {
-               u32 value = saa7146_read(dev, BCS_CTRL);
-               value &= 0x00ffffff;
-               value |= (c->value << 24);
-               saa7146_write(dev, BCS_CTRL, value);
-               saa7146_write(dev, MC2, MASK_22 | MASK_06 );
-               break;
-       }
-       case V4L2_CID_CONTRAST: {
-               u32 value = saa7146_read(dev, BCS_CTRL);
-               value &= 0xff00ffff;
-               value |= (c->value << 16);
-               saa7146_write(dev, BCS_CTRL, value);
-               saa7146_write(dev, MC2, MASK_22 | MASK_06 );
-               break;
-       }
-       case V4L2_CID_SATURATION: {
-               u32 value = saa7146_read(dev, BCS_CTRL);
-               value &= 0xffffff00;
-               value |= (c->value << 0);
-               saa7146_write(dev, BCS_CTRL, value);
-               saa7146_write(dev, MC2, MASK_22 | MASK_06 );
-               break;
-       }
-       case V4L2_CID_HFLIP:
-               /* fixme: we can support changing VFLIP and HFLIP here... */
-               if (IS_CAPTURE_ACTIVE(fh) != 0) {
-                       DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
-                       mutex_unlock(&dev->lock);
-                       return -EINVAL;
-               }
-               vv->hflip = c->value;
-               break;
-       case V4L2_CID_VFLIP:
-               if (IS_CAPTURE_ACTIVE(fh) != 0) {
-                       DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
-                       mutex_unlock(&dev->lock);
-                       return -EINVAL;
-               }
-               vv->vflip = c->value;
-               break;
-       default: {
-               mutex_unlock(&dev->lock);
-               return -EINVAL;
-       }
-       }
-       mutex_unlock(&dev->lock);
-
-       if (IS_OVERLAY_ACTIVE(fh) != 0) {
-               saa7146_stop_preview(fh);
-               saa7146_start_preview(fh);
-       }
-       return 0;
-}
-
 /********************************************************************************/
 /* common pagetable functions */
 
@@ -829,231 +497,446 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
        return 0;
 }
 
-/*
- * This function is _not_ called directly, but from
- * video_generic_ioctl (and maybe others).  userspace
- * copying is done already, arg is a kernel pointer.
- */
+static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+
+       strcpy((char *)cap->driver, "saa7146 v4l2");
+       strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
+       sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci));
+       cap->version = SAA7146_VERSION_CODE;
+       cap->capabilities =
+               V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_VIDEO_OVERLAY |
+               V4L2_CAP_READWRITE |
+               V4L2_CAP_STREAMING;
+       cap->capabilities |= dev->ext_vv_data->capabilities;
+       return 0;
+}
 
-long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
 {
-       struct saa7146_fh *fh  = file->private_data;
-       struct saa7146_dev *dev = fh->dev;
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
        struct saa7146_vv *vv = dev->vv_data;
 
-       long err = 0;
-       int result = 0, ee = 0;
+       *fb = vv->ov_fb;
+       fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+       return 0;
+}
 
-       struct saa7146_use_ops *ops;
-       struct videobuf_queue *q;
+static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct saa7146_vv *vv = dev->vv_data;
+       struct saa7146_format *fmt;
 
-       /* check if extension handles the command */
-       for(ee = 0; dev->ext_vv_data->ioctls[ee].flags != 0; ee++) {
-               if( cmd == dev->ext_vv_data->ioctls[ee].cmd )
-                       break;
-       }
+       DEB_EE(("VIDIOC_S_FBUF\n"));
 
-       if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_EXCLUSIVE) ) {
-               DEB_D(("extension handles ioctl exclusive.\n"));
-               result = dev->ext_vv_data->ioctl(fh, cmd, arg);
-               return result;
-       }
-       if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_BEFORE) ) {
-               DEB_D(("extension handles ioctl before.\n"));
-               result = dev->ext_vv_data->ioctl(fh, cmd, arg);
-               if( -EAGAIN != result ) {
-                       return result;
-               }
-       }
+       if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+               return -EPERM;
 
-       /* fixme: add handle "after" case (is it still needed?) */
+       /* check args */
+       fmt = format_by_fourcc(dev, fb->fmt.pixelformat);
+       if (NULL == fmt)
+               return -EINVAL;
 
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-               ops = &saa7146_video_uops;
-               q = &fh->video_q;
-               break;
-               }
-       case V4L2_BUF_TYPE_VBI_CAPTURE: {
-               ops = &saa7146_vbi_uops;
-               q = &fh->vbi_q;
-               break;
-               }
-       default:
-               BUG();
-               return 0;
+       /* planar formats are not allowed for overlay video, clipping and video dma would clash */
+       if (fmt->flags & FORMAT_IS_PLANAR)
+               DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",
+                                       (char *)&fmt->pixelformat));
+
+       /* check if overlay is running */
+       if (IS_OVERLAY_ACTIVE(fh) != 0) {
+               if (vv->video_fh != fh) {
+                       DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n"));
+                       return -EBUSY;
+               }
        }
 
-       switch (cmd) {
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *cap = arg;
-               memset(cap,0,sizeof(*cap));
-
-               DEB_EE(("VIDIOC_QUERYCAP\n"));
-
-               strcpy((char *)cap->driver, "saa7146 v4l2");
-               strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
-               sprintf((char *)cap->bus_info,"PCI:%s", pci_name(dev->pci));
-               cap->version = SAA7146_VERSION_CODE;
-               cap->capabilities =
-                       V4L2_CAP_VIDEO_CAPTURE |
-                       V4L2_CAP_VIDEO_OVERLAY |
-                       V4L2_CAP_READWRITE |
-                       V4L2_CAP_STREAMING;
-               cap->capabilities |= dev->ext_vv_data->capabilities;
-               return 0;
+       mutex_lock(&dev->lock);
+
+       /* ok, accept it */
+       vv->ov_fb = *fb;
+       vv->ov_fmt = fmt;
+       if (0 == vv->ov_fb.fmt.bytesperline)
+               vv->ov_fb.fmt.bytesperline =
+                       vv->ov_fb.fmt.width * fmt->depth / 8;
+
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+       if (f->index >= NUM_FORMATS)
+               return -EINVAL;
+       strlcpy((char *)f->description, formats[f->index].name,
+                       sizeof(f->description));
+       f->pixelformat = formats[f->index].pixelformat;
+       return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
+{
+       const struct v4l2_queryctrl *ctrl;
+
+       if ((c->id <  V4L2_CID_BASE ||
+            c->id >= V4L2_CID_LASTP1) &&
+           (c->id <  V4L2_CID_PRIVATE_BASE ||
+            c->id >= V4L2_CID_PRIVATE_LASTP1))
+               return -EINVAL;
+
+       ctrl = ctrl_by_id(c->id);
+       if (ctrl == NULL)
+               return -EINVAL;
+
+       DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n", c->id));
+       *c = *ctrl;
+       return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct saa7146_vv *vv = dev->vv_data;
+       const struct v4l2_queryctrl *ctrl;
+       u32 value = 0;
+
+       ctrl = ctrl_by_id(c->id);
+       if (NULL == ctrl)
+               return -EINVAL;
+       switch (c->id) {
+       case V4L2_CID_BRIGHTNESS:
+               value = saa7146_read(dev, BCS_CTRL);
+               c->value = 0xff & (value >> 24);
+               DEB_D(("V4L2_CID_BRIGHTNESS: %d\n", c->value));
+               break;
+       case V4L2_CID_CONTRAST:
+               value = saa7146_read(dev, BCS_CTRL);
+               c->value = 0x7f & (value >> 16);
+               DEB_D(("V4L2_CID_CONTRAST: %d\n", c->value));
+               break;
+       case V4L2_CID_SATURATION:
+               value = saa7146_read(dev, BCS_CTRL);
+               c->value = 0x7f & (value >> 0);
+               DEB_D(("V4L2_CID_SATURATION: %d\n", c->value));
+               break;
+       case V4L2_CID_VFLIP:
+               c->value = vv->vflip;
+               DEB_D(("V4L2_CID_VFLIP: %d\n", c->value));
+               break;
+       case V4L2_CID_HFLIP:
+               c->value = vv->hflip;
+               DEB_D(("V4L2_CID_HFLIP: %d\n", c->value));
+               break;
+       default:
+               return -EINVAL;
        }
-       case VIDIOC_G_FBUF:
-       {
-               struct v4l2_framebuffer *fb = arg;
+       return 0;
+}
 
-               DEB_EE(("VIDIOC_G_FBUF\n"));
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct saa7146_vv *vv = dev->vv_data;
+       const struct v4l2_queryctrl *ctrl;
 
-               *fb = vv->ov_fb;
-               fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
-               return 0;
+       ctrl = ctrl_by_id(c->id);
+       if (NULL == ctrl) {
+               DEB_D(("unknown control %d\n", c->id));
+               return -EINVAL;
        }
-       case VIDIOC_S_FBUF:
-       {
-               struct v4l2_framebuffer *fb = arg;
-               struct saa7146_format *fmt;
 
-               DEB_EE(("VIDIOC_S_FBUF\n"));
+       mutex_lock(&dev->lock);
 
-               if(!capable(CAP_SYS_ADMIN) &&
-                  !capable(CAP_SYS_RAWIO))
-                       return -EPERM;
+       switch (ctrl->type) {
+       case V4L2_CTRL_TYPE_BOOLEAN:
+       case V4L2_CTRL_TYPE_MENU:
+       case V4L2_CTRL_TYPE_INTEGER:
+               if (c->value < ctrl->minimum)
+                       c->value = ctrl->minimum;
+               if (c->value > ctrl->maximum)
+                       c->value = ctrl->maximum;
+               break;
+       default:
+               /* nothing */;
+       }
 
-               /* check args */
-               fmt = format_by_fourcc(dev,fb->fmt.pixelformat);
-               if (NULL == fmt) {
-                       return -EINVAL;
+       switch (c->id) {
+       case V4L2_CID_BRIGHTNESS: {
+               u32 value = saa7146_read(dev, BCS_CTRL);
+               value &= 0x00ffffff;
+               value |= (c->value << 24);
+               saa7146_write(dev, BCS_CTRL, value);
+               saa7146_write(dev, MC2, MASK_22 | MASK_06);
+               break;
+       }
+       case V4L2_CID_CONTRAST: {
+               u32 value = saa7146_read(dev, BCS_CTRL);
+               value &= 0xff00ffff;
+               value |= (c->value << 16);
+               saa7146_write(dev, BCS_CTRL, value);
+               saa7146_write(dev, MC2, MASK_22 | MASK_06);
+               break;
+       }
+       case V4L2_CID_SATURATION: {
+               u32 value = saa7146_read(dev, BCS_CTRL);
+               value &= 0xffffff00;
+               value |= (c->value << 0);
+               saa7146_write(dev, BCS_CTRL, value);
+               saa7146_write(dev, MC2, MASK_22 | MASK_06);
+               break;
+       }
+       case V4L2_CID_HFLIP:
+               /* fixme: we can support changing VFLIP and HFLIP here... */
+               if (IS_CAPTURE_ACTIVE(fh) != 0) {
+                       DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
+                       mutex_unlock(&dev->lock);
+                       return -EBUSY;
                }
-
-               /* planar formats are not allowed for overlay video, clipping and video dma would clash */
-               if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
-                       DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",(char *)&fmt->pixelformat));
+               vv->hflip = c->value;
+               break;
+       case V4L2_CID_VFLIP:
+               if (IS_CAPTURE_ACTIVE(fh) != 0) {
+                       DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
+                       mutex_unlock(&dev->lock);
+                       return -EBUSY;
                }
+               vv->vflip = c->value;
+               break;
+       default:
+               mutex_unlock(&dev->lock);
+               return -EINVAL;
+       }
+       mutex_unlock(&dev->lock);
 
-               /* check if overlay is running */
-               if (IS_OVERLAY_ACTIVE(fh) != 0) {
-                       if (vv->video_fh != fh) {
-                               DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n"));
-                               return -EBUSY;
-                       }
-               }
+       if (IS_OVERLAY_ACTIVE(fh) != 0) {
+               saa7146_stop_preview(fh);
+               saa7146_start_preview(fh);
+       }
+       return 0;
+}
 
-               mutex_lock(&dev->lock);
+static int vidioc_g_parm(struct file *file, void *fh,
+               struct v4l2_streamparm *parm)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct saa7146_vv *vv = dev->vv_data;
 
-               /* ok, accept it */
-               vv->ov_fb = *fb;
-               vv->ov_fmt = fmt;
-               if (0 == vv->ov_fb.fmt.bytesperline)
-                       vv->ov_fb.fmt.bytesperline =
-                               vv->ov_fb.fmt.width*fmt->depth/8;
+       parm->parm.capture.readbuffers = 1;
+       v4l2_video_std_frame_period(vv->standard->id,
+                                   &parm->parm.capture.timeperframe);
+       return 0;
+}
 
-               mutex_unlock(&dev->lock);
+static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+       f->fmt.pix = ((struct saa7146_fh *)fh)->video_fmt;
+       return 0;
+}
 
-               return 0;
-       }
-       case VIDIOC_ENUM_FMT:
-       {
-               struct v4l2_fmtdesc *f = arg;
-
-               switch (f->type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-                       if (f->index >= NUM_FORMATS)
-                               return -EINVAL;
-                       strlcpy((char *)f->description, formats[f->index].name,
-                                       sizeof(f->description));
-                       f->pixelformat = formats[f->index].pixelformat;
-                       f->flags = 0;
-                       memset(f->reserved, 0, sizeof(f->reserved));
-                       break;
-               default:
-                       return -EINVAL;
-               }
+static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
+{
+       f->fmt.win = ((struct saa7146_fh *)fh)->ov.win;
+       return 0;
+}
 
-               DEB_EE(("VIDIOC_ENUM_FMT: type:%d, index:%d\n",f->type,f->index));
-               return 0;
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+       f->fmt.vbi = ((struct saa7146_fh *)fh)->vbi_fmt;
+       return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct saa7146_vv *vv = dev->vv_data;
+       struct saa7146_format *fmt;
+       enum v4l2_field field;
+       int maxw, maxh;
+       int calc_bpl;
+
+       DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh));
+
+       fmt = format_by_fourcc(dev, f->fmt.pix.pixelformat);
+       if (NULL == fmt)
+               return -EINVAL;
+
+       field = f->fmt.pix.field;
+       maxw  = vv->standard->h_max_out;
+       maxh  = vv->standard->v_max_out;
+
+       if (V4L2_FIELD_ANY == field) {
+               field = (f->fmt.pix.height > maxh / 2)
+                       ? V4L2_FIELD_INTERLACED
+                       : V4L2_FIELD_BOTTOM;
+       }
+       switch (field) {
+       case V4L2_FIELD_ALTERNATE:
+               vv->last_field = V4L2_FIELD_TOP;
+               maxh = maxh / 2;
+               break;
+       case V4L2_FIELD_TOP:
+       case V4L2_FIELD_BOTTOM:
+               vv->last_field = V4L2_FIELD_INTERLACED;
+               maxh = maxh / 2;
+               break;
+       case V4L2_FIELD_INTERLACED:
+               vv->last_field = V4L2_FIELD_INTERLACED;
+               break;
+       default:
+               DEB_D(("no known field mode '%d'.\n", field));
+               return -EINVAL;
        }
-       case VIDIOC_QUERYCTRL:
-       {
-               const struct v4l2_queryctrl *ctrl;
-               struct v4l2_queryctrl *c = arg;
 
-               if ((c->id <  V4L2_CID_BASE ||
-                    c->id >= V4L2_CID_LASTP1) &&
-                   (c->id <  V4L2_CID_PRIVATE_BASE ||
-                    c->id >= V4L2_CID_PRIVATE_LASTP1))
-                       return -EINVAL;
+       f->fmt.pix.field = field;
+       if (f->fmt.pix.width > maxw)
+               f->fmt.pix.width = maxw;
+       if (f->fmt.pix.height > maxh)
+               f->fmt.pix.height = maxh;
 
-               ctrl = ctrl_by_id(c->id);
-               if( NULL == ctrl ) {
-                       return -EINVAL;
-/*
-                       c->flags = V4L2_CTRL_FLAG_DISABLED;
-                       return 0;
-*/
-               }
+       calc_bpl = (f->fmt.pix.width * fmt->depth) / 8;
 
-               DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n",c->id));
-               *c = *ctrl;
-               return 0;
+       if (f->fmt.pix.bytesperline < calc_bpl)
+               f->fmt.pix.bytesperline = calc_bpl;
+
+       if (f->fmt.pix.bytesperline > (2 * PAGE_SIZE * fmt->depth) / 8) /* arbitrary constraint */
+               f->fmt.pix.bytesperline = calc_bpl;
+
+       f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
+       DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n", f->fmt.pix.width,
+                       f->fmt.pix.height, f->fmt.pix.bytesperline, f->fmt.pix.sizeimage));
+
+       return 0;
+}
+
+
+static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct saa7146_vv *vv = dev->vv_data;
+       struct v4l2_window *win = &f->fmt.win;
+       enum v4l2_field field;
+       int maxw, maxh;
+
+       DEB_EE(("dev:%p\n", dev));
+
+       if (NULL == vv->ov_fb.base) {
+               DEB_D(("no fb base set.\n"));
+               return -EINVAL;
        }
-       case VIDIOC_G_CTRL: {
-               DEB_EE(("VIDIOC_G_CTRL\n"));
-               return get_control(fh,arg);
+       if (NULL == vv->ov_fmt) {
+               DEB_D(("no fb fmt set.\n"));
+               return -EINVAL;
        }
-       case VIDIOC_S_CTRL:
-       {
-               DEB_EE(("VIDIOC_S_CTRL\n"));
-               err = set_control(fh,arg);
-               return err;
+       if (win->w.width < 48 || win->w.height < 32) {
+               DEB_D(("min width/height. (%d,%d)\n", win->w.width, win->w.height));
+               return -EINVAL;
        }
-       case VIDIOC_G_PARM:
-       {
-               struct v4l2_streamparm *parm = arg;
-               if( parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ) {
-                       return -EINVAL;
-               }
-               memset(&parm->parm.capture,0,sizeof(struct v4l2_captureparm));
-               parm->parm.capture.readbuffers = 1;
-               // fixme: only for PAL!
-               parm->parm.capture.timeperframe.numerator = 1;
-               parm->parm.capture.timeperframe.denominator = 25;
-               return 0;
+       if (win->clipcount > 16) {
+               DEB_D(("clipcount too big.\n"));
+               return -EINVAL;
        }
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format *f = arg;
-               DEB_EE(("VIDIOC_G_FMT\n"));
-               return g_fmt(fh,f);
+
+       field = win->field;
+       maxw  = vv->standard->h_max_out;
+       maxh  = vv->standard->v_max_out;
+
+       if (V4L2_FIELD_ANY == field) {
+               field = (win->w.height > maxh / 2)
+                       ? V4L2_FIELD_INTERLACED
+                       : V4L2_FIELD_TOP;
+               }
+       switch (field) {
+       case V4L2_FIELD_TOP:
+       case V4L2_FIELD_BOTTOM:
+       case V4L2_FIELD_ALTERNATE:
+               maxh = maxh / 2;
+               break;
+       case V4L2_FIELD_INTERLACED:
+               break;
+       default:
+               DEB_D(("no known field mode '%d'.\n", field));
+               return -EINVAL;
        }
-       case VIDIOC_S_FMT:
-       {
-               struct v4l2_format *f = arg;
-               DEB_EE(("VIDIOC_S_FMT\n"));
-               return s_fmt(fh,f);
+
+       win->field = field;
+       if (win->w.width > maxw)
+               win->w.width = maxw;
+       if (win->w.height > maxh)
+               win->w.height = maxh;
+
+       return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_format *f)
+{
+       struct saa7146_fh *fh = __fh;
+       struct saa7146_dev *dev = fh->dev;
+       struct saa7146_vv *vv = dev->vv_data;
+       int err;
+
+       DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh));
+       if (IS_CAPTURE_ACTIVE(fh) != 0) {
+               DEB_EE(("streaming capture is active\n"));
+               return -EBUSY;
        }
-       case VIDIOC_TRY_FMT:
-       {
-               struct v4l2_format *f = arg;
-               DEB_EE(("VIDIOC_TRY_FMT\n"));
-               return try_fmt(fh,f);
+       err = vidioc_try_fmt_vid_cap(file, fh, f);
+       if (0 != err)
+               return err;
+       fh->video_fmt = f->fmt.pix;
+       DEB_EE(("set to pixelformat '%4.4s'\n", (char *)&fh->video_fmt.pixelformat));
+       return 0;
+}
+
+static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_format *f)
+{
+       struct saa7146_fh *fh = __fh;
+       struct saa7146_dev *dev = fh->dev;
+       struct saa7146_vv *vv = dev->vv_data;
+       int err;
+
+       DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh));
+       err = vidioc_try_fmt_vid_overlay(file, fh, f);
+       if (0 != err)
+               return err;
+       mutex_lock(&dev->lock);
+       fh->ov.win    = f->fmt.win;
+       fh->ov.nclips = f->fmt.win.clipcount;
+       if (fh->ov.nclips > 16)
+               fh->ov.nclips = 16;
+       if (copy_from_user(fh->ov.clips, f->fmt.win.clips,
+                               sizeof(struct v4l2_clip) * fh->ov.nclips)) {
+               mutex_unlock(&dev->lock);
+               return -EFAULT;
        }
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *id = arg;
-               DEB_EE(("VIDIOC_G_STD\n"));
-               *id = vv->standard->id;
-               return 0;
+
+       /* fh->ov.fh is used to indicate that we have valid overlay informations, too */
+       fh->ov.fh = fh;
+
+       mutex_unlock(&dev->lock);
+
+       /* check if our current overlay is active */
+       if (IS_OVERLAY_ACTIVE(fh) != 0) {
+               saa7146_stop_preview(fh);
+               saa7146_start_preview(fh);
        }
+       return 0;
+}
+
+static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct saa7146_vv *vv = dev->vv_data;
+
+       *norm = vv->standard->id;
+       return 0;
+}
+
        /* the saa7146 supfhrts (used in conjunction with the saa7111a for example)
           PAL / NTSC / SECAM. if your hardware does not (or does more)
           -- override this function in your extension */
+/*
        case VIDIOC_ENUMSTD:
        {
                struct v4l2_standard *e = arg;
@@ -1066,162 +949,245 @@ long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                }
                return -EINVAL;
        }
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *id = arg;
-               int found = 0;
-               int i;
+       */
 
-               DEB_EE(("VIDIOC_S_STD\n"));
-
-               if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) {
-                       DEB_D(("cannot change video standard while streaming capture is active\n"));
-                       return -EBUSY;
-               }
+static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct saa7146_vv *vv = dev->vv_data;
+       int found = 0;
+       int err, i;
 
-               if ((vv->video_status & STATUS_OVERLAY) != 0) {
-                       vv->ov_suspend = vv->video_fh;
-                       err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
-                       if (0 != err) {
-                               DEB_D(("suspending video failed. aborting\n"));
-                               return err;
-                       }
-               }
+       DEB_EE(("VIDIOC_S_STD\n"));
 
-               mutex_lock(&dev->lock);
+       if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) {
+               DEB_D(("cannot change video standard while streaming capture is active\n"));
+               return -EBUSY;
+       }
 
-               for(i = 0; i < dev->ext_vv_data->num_stds; i++)
-                       if (*id & dev->ext_vv_data->stds[i].id)
-                               break;
-               if (i != dev->ext_vv_data->num_stds) {
-                       vv->standard = &dev->ext_vv_data->stds[i];
-                       if( NULL != dev->ext_vv_data->std_callback )
-                               dev->ext_vv_data->std_callback(dev, vv->standard);
-                       found = 1;
+       if ((vv->video_status & STATUS_OVERLAY) != 0) {
+               vv->ov_suspend = vv->video_fh;
+               err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
+               if (0 != err) {
+                       DEB_D(("suspending video failed. aborting\n"));
+                       return err;
                }
+       }
 
-               mutex_unlock(&dev->lock);
+       mutex_lock(&dev->lock);
 
-               if (vv->ov_suspend != NULL) {
-                       saa7146_start_preview(vv->ov_suspend);
-                       vv->ov_suspend = NULL;
-               }
+       for (i = 0; i < dev->ext_vv_data->num_stds; i++)
+               if (*id & dev->ext_vv_data->stds[i].id)
+                       break;
+       if (i != dev->ext_vv_data->num_stds) {
+               vv->standard = &dev->ext_vv_data->stds[i];
+               if (NULL != dev->ext_vv_data->std_callback)
+                       dev->ext_vv_data->std_callback(dev, vv->standard);
+               found = 1;
+       }
 
-               if( 0 == found ) {
-                       DEB_EE(("VIDIOC_S_STD: standard not found.\n"));
-                       return -EINVAL;
-               }
+       mutex_unlock(&dev->lock);
 
-               DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n",vv->standard->name));
-               return 0;
+       if (vv->ov_suspend != NULL) {
+               saa7146_start_preview(vv->ov_suspend);
+               vv->ov_suspend = NULL;
        }
-       case VIDIOC_OVERLAY:
-       {
-               int on = *(int *)arg;
 
-               DEB_D(("VIDIOC_OVERLAY on:%d\n",on));
-               if (on != 0) {
-                       err = saa7146_start_preview(fh);
-               } else {
-                       err = saa7146_stop_preview(fh);
-               }
-               return err;
-       }
-       case VIDIOC_REQBUFS: {
-               struct v4l2_requestbuffers *req = arg;
-               DEB_D(("VIDIOC_REQBUFS, type:%d\n",req->type));
-               return videobuf_reqbufs(q,req);
-       }
-       case VIDIOC_QUERYBUF: {
-               struct v4l2_buffer *buf = arg;
-               DEB_D(("VIDIOC_QUERYBUF, type:%d, offset:%d\n",buf->type,buf->m.offset));
-               return videobuf_querybuf(q,buf);
-       }
-       case VIDIOC_QBUF: {
-               struct v4l2_buffer *buf = arg;
-               int ret = 0;
-               ret = videobuf_qbuf(q,buf);
-               DEB_D(("VIDIOC_QBUF: ret:%d, index:%d\n",ret,buf->index));
-               return ret;
-       }
-       case VIDIOC_DQBUF: {
-               struct v4l2_buffer *buf = arg;
-               int ret = 0;
-               ret = videobuf_dqbuf(q,buf,file->f_flags & O_NONBLOCK);
-               DEB_D(("VIDIOC_DQBUF: ret:%d, index:%d\n",ret,buf->index));
-               return ret;
+       if (!found) {
+               DEB_EE(("VIDIOC_S_STD: standard not found.\n"));
+               return -EINVAL;
        }
-       case VIDIOC_STREAMON: {
-               int *type = arg;
-               DEB_D(("VIDIOC_STREAMON, type:%d\n",*type));
 
-               err = video_begin(fh);
-               if( 0 != err) {
-                       return err;
-               }
-               err = videobuf_streamon(q);
-               return err;
-       }
-       case VIDIOC_STREAMOFF: {
-               int *type = arg;
+       DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name));
+       return 0;
+}
 
-               DEB_D(("VIDIOC_STREAMOFF, type:%d\n",*type));
+static int vidioc_overlay(struct file *file, void *fh, unsigned int on)
+{
+       int err;
 
-               /* ugly: we need to copy some checks from video_end(),
-                  because videobuf_streamoff() relies on the capture running.
-                  check and fix this */
-               if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
-                       DEB_S(("not capturing.\n"));
-                       return 0;
-               }
+       DEB_D(("VIDIOC_OVERLAY on:%d\n", on));
+       if (on)
+               err = saa7146_start_preview(fh);
+       else
+               err = saa7146_stop_preview(fh);
+       return err;
+}
 
-               if (vv->video_fh != fh) {
-                       DEB_S(("capturing, but in another open.\n"));
-                       return -EBUSY;
-               }
+static int vidioc_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *b)
+{
+       struct saa7146_fh *fh = __fh;
 
-               err = videobuf_streamoff(q);
-               if (0 != err) {
-                       DEB_D(("warning: videobuf_streamoff() failed.\n"));
-                       video_end(fh, file);
-               } else {
-                       err = video_end(fh, file);
-               }
+       if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return videobuf_reqbufs(&fh->video_q, b);
+       if (b->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               return videobuf_reqbufs(&fh->vbi_q, b);
+       return -EINVAL;
+}
+
+static int vidioc_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
+{
+       struct saa7146_fh *fh = __fh;
+
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return videobuf_querybuf(&fh->video_q, buf);
+       if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               return videobuf_querybuf(&fh->vbi_q, buf);
+       return -EINVAL;
+}
+
+static int vidioc_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
+{
+       struct saa7146_fh *fh = __fh;
+
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return videobuf_qbuf(&fh->video_q, buf);
+       if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               return videobuf_qbuf(&fh->vbi_q, buf);
+       return -EINVAL;
+}
+
+static int vidioc_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
+{
+       struct saa7146_fh *fh = __fh;
+
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return videobuf_dqbuf(&fh->video_q, buf, file->f_flags & O_NONBLOCK);
+       if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               return videobuf_dqbuf(&fh->vbi_q, buf, file->f_flags & O_NONBLOCK);
+       return -EINVAL;
+}
+
+static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type type)
+{
+       struct saa7146_fh *fh = __fh;
+       int err;
+
+       DEB_D(("VIDIOC_STREAMON, type:%d\n", type));
+
+       err = video_begin(fh);
+       if (err)
                return err;
+       if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return videobuf_streamon(&fh->video_q);
+       if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               return videobuf_streamon(&fh->vbi_q);
+       return -EINVAL;
+}
+
+static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type)
+{
+       struct saa7146_fh *fh = __fh;
+       struct saa7146_dev *dev = fh->dev;
+       struct saa7146_vv *vv = dev->vv_data;
+       int err;
+
+       DEB_D(("VIDIOC_STREAMOFF, type:%d\n", type));
+
+       /* ugly: we need to copy some checks from video_end(),
+          because videobuf_streamoff() relies on the capture running.
+          check and fix this */
+       if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
+               DEB_S(("not capturing.\n"));
+               return 0;
        }
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       case VIDIOCGMBUF:
-       {
-               struct video_mbuf *mbuf = arg;
-               int i;
 
-               /* fixme: number of capture buffers and sizes for v4l apps */
-               int gbuffers = 2;
-               int gbufsize = 768*576*4;
+       if (vv->video_fh != fh) {
+               DEB_S(("capturing, but in another open.\n"));
+               return -EBUSY;
+       }
 
-               DEB_D(("VIDIOCGMBUF \n"));
+       err = -EINVAL;
+       if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               err = videobuf_streamoff(&fh->video_q);
+       else if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               err = videobuf_streamoff(&fh->vbi_q);
+       if (0 != err) {
+               DEB_D(("warning: videobuf_streamoff() failed.\n"));
+               video_end(fh, file);
+       } else {
+               err = video_end(fh, file);
+       }
+       return err;
+}
 
-               q = &fh->video_q;
-               err = videobuf_mmap_setup(q,gbuffers,gbufsize,
-                                         V4L2_MEMORY_MMAP);
-               if (err < 0)
-                       return err;
+static int vidioc_g_chip_ident(struct file *file, void *__fh,
+               struct v4l2_dbg_chip_ident *chip)
+{
+       struct saa7146_fh *fh = __fh;
+       struct saa7146_dev *dev = fh->dev;
 
-               gbuffers = err;
-               memset(mbuf,0,sizeof(*mbuf));
-               mbuf->frames = gbuffers;
-               mbuf->size   = gbuffers * gbufsize;
-               for (i = 0; i < gbuffers; i++)
-                       mbuf->offsets[i] = i * gbufsize;
+       chip->ident = V4L2_IDENT_NONE;
+       chip->revision = 0;
+       if (chip->match.type == V4L2_CHIP_MATCH_HOST && !chip->match.addr) {
+               chip->ident = V4L2_IDENT_SAA7146;
                return 0;
        }
-#endif
-       default:
-               return v4l_compat_translate_ioctl(file, cmd, arg,
-                                                 saa7146_video_do_ioctl);
-       }
+       return v4l2_device_call_until_err(&dev->v4l2_dev, 0,
+                       core, g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *mbuf)
+{
+       struct saa7146_fh *fh = __fh;
+       struct videobuf_queue *q = &fh->video_q;
+       int err, i;
+
+       /* fixme: number of capture buffers and sizes for v4l apps */
+       int gbuffers = 2;
+       int gbufsize = 768 * 576 * 4;
+
+       DEB_D(("VIDIOCGMBUF \n"));
+
+       q = &fh->video_q;
+       err = videobuf_mmap_setup(q, gbuffers, gbufsize,
+                       V4L2_MEMORY_MMAP);
+       if (err < 0)
+               return err;
+
+       gbuffers = err;
+       memset(mbuf, 0, sizeof(*mbuf));
+       mbuf->frames = gbuffers;
+       mbuf->size   = gbuffers * gbufsize;
+       for (i = 0; i < gbuffers; i++)
+               mbuf->offsets[i] = i * gbufsize;
        return 0;
 }
+#endif
+
+const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
+       .vidioc_querycap             = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap     = vidioc_enum_fmt_vid_cap,
+       .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap        = vidioc_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap      = vidioc_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap        = vidioc_s_fmt_vid_cap,
+       .vidioc_g_fmt_vid_overlay    = vidioc_g_fmt_vid_overlay,
+       .vidioc_try_fmt_vid_overlay  = vidioc_try_fmt_vid_overlay,
+       .vidioc_s_fmt_vid_overlay    = vidioc_s_fmt_vid_overlay,
+       .vidioc_g_fmt_vbi_cap        = vidioc_g_fmt_vbi_cap,
+       .vidioc_g_chip_ident         = vidioc_g_chip_ident,
+
+       .vidioc_overlay              = vidioc_overlay,
+       .vidioc_g_fbuf               = vidioc_g_fbuf,
+       .vidioc_s_fbuf               = vidioc_s_fbuf,
+       .vidioc_reqbufs              = vidioc_reqbufs,
+       .vidioc_querybuf             = vidioc_querybuf,
+       .vidioc_qbuf                 = vidioc_qbuf,
+       .vidioc_dqbuf                = vidioc_dqbuf,
+       .vidioc_g_std                = vidioc_g_std,
+       .vidioc_s_std                = vidioc_s_std,
+       .vidioc_queryctrl            = vidioc_queryctrl,
+       .vidioc_g_ctrl               = vidioc_g_ctrl,
+       .vidioc_s_ctrl               = vidioc_s_ctrl,
+       .vidioc_streamon             = vidioc_streamon,
+       .vidioc_streamoff            = vidioc_streamoff,
+       .vidioc_g_parm               = vidioc_g_parm,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+       .vidiocgmbuf                 = vidiocgmbuf,
+#endif
+};
 
 /*********************************************************************************/
 /* buffer handling functions                                                  */
index 6f92beaa5ac8f11913631c96e87a3defdf2d5a48..52c3f65b12d69362b79c8b386cf0d59c3e04bb02 100644 (file)
@@ -21,16 +21,17 @@ config MEDIA_TUNER
        tristate
        default VIDEO_MEDIA && I2C
        depends on VIDEO_MEDIA && I2C
-       select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMIZE
-
-menuconfig MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
+
+menuconfig MEDIA_TUNER_CUSTOMISE
        bool "Customize analog and hybrid tuner modules to build"
        depends on MEDIA_TUNER
        default n
@@ -43,13 +44,13 @@ menuconfig MEDIA_TUNER_CUSTOMIZE
 
          If unsure say N.
 
-if MEDIA_TUNER_CUSTOMIZE
+if MEDIA_TUNER_CUSTOMISE
 
 config MEDIA_TUNER_SIMPLE
        tristate "Simple tuner support"
        depends on VIDEO_MEDIA && I2C
        select MEDIA_TUNER_TDA9887
-       default m if MEDIA_TUNER_CUSTOMIZE
+       default m if MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to include support for various simple tuners.
 
@@ -58,28 +59,28 @@ config MEDIA_TUNER_TDA8290
        depends on VIDEO_MEDIA && I2C
        select MEDIA_TUNER_TDA827X
        select MEDIA_TUNER_TDA18271
-       default m if MEDIA_TUNER_CUSTOMIZE
+       default m if MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to include support for Philips TDA8290+8275(a) tuner.
 
 config MEDIA_TUNER_TDA827X
        tristate "Philips TDA827X silicon tuner"
        depends on VIDEO_MEDIA && I2C
-       default m if DVB_FE_CUSTOMISE
+       default m if MEDIA_TUNER_CUSTOMISE
        help
          A DVB-T silicon tuner module. Say Y when you want to support this tuner.
 
 config MEDIA_TUNER_TDA18271
        tristate "NXP TDA18271 silicon tuner"
        depends on VIDEO_MEDIA && I2C
-       default m if DVB_FE_CUSTOMISE
+       default m if MEDIA_TUNER_CUSTOMISE
        help
          A silicon tuner module. Say Y when you want to support this tuner.
 
 config MEDIA_TUNER_TDA9887
        tristate "TDA 9885/6/7 analog IF demodulator"
        depends on VIDEO_MEDIA && I2C
-       default m if MEDIA_TUNER_CUSTOMIZE
+       default m if MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to include support for Philips TDA9885/6/7
          analog IF demodulator.
@@ -88,63 +89,63 @@ config MEDIA_TUNER_TEA5761
        tristate "TEA 5761 radio tuner (EXPERIMENTAL)"
        depends on VIDEO_MEDIA && I2C
        depends on EXPERIMENTAL
-       default m if MEDIA_TUNER_CUSTOMIZE
+       default m if MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to include support for the Philips TEA5761 radio tuner.
 
 config MEDIA_TUNER_TEA5767
        tristate "TEA 5767 radio tuner"
        depends on VIDEO_MEDIA && I2C
-       default m if MEDIA_TUNER_CUSTOMIZE
+       default m if MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to include support for the Philips TEA5767 radio tuner.
 
 config MEDIA_TUNER_MT20XX
        tristate "Microtune 2032 / 2050 tuners"
        depends on VIDEO_MEDIA && I2C
-       default m if MEDIA_TUNER_CUSTOMIZE
+       default m if MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to include support for the MT2032 / MT2050 tuner.
 
 config MEDIA_TUNER_MT2060
        tristate "Microtune MT2060 silicon IF tuner"
        depends on VIDEO_MEDIA && I2C
-       default m if DVB_FE_CUSTOMISE
+       default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon IF tuner MT2060 from Microtune.
 
 config MEDIA_TUNER_MT2266
        tristate "Microtune MT2266 silicon tuner"
        depends on VIDEO_MEDIA && I2C
-       default m if DVB_FE_CUSTOMISE
+       default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon baseband tuner MT2266 from Microtune.
 
 config MEDIA_TUNER_MT2131
        tristate "Microtune MT2131 silicon tuner"
        depends on VIDEO_MEDIA && I2C
-       default m if DVB_FE_CUSTOMISE
+       default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon baseband tuner MT2131 from Microtune.
 
 config MEDIA_TUNER_QT1010
        tristate "Quantek QT1010 silicon tuner"
        depends on VIDEO_MEDIA && I2C
-       default m if DVB_FE_CUSTOMISE
+       default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon tuner QT1010 from Quantek.
 
 config MEDIA_TUNER_XC2028
        tristate "XCeive xc2028/xc3028 tuners"
        depends on VIDEO_MEDIA && I2C
-       default m if MEDIA_TUNER_CUSTOMIZE
+       default m if MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to include support for the xc2028/xc3028 tuners.
 
 config MEDIA_TUNER_XC5000
        tristate "Xceive XC5000 silicon tuner"
        depends on VIDEO_MEDIA && I2C
-       default m if DVB_FE_CUSTOMISE
+       default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon tuner XC5000 from Xceive.
          This device is only used inside a SiP called togther with a
@@ -153,15 +154,22 @@ config MEDIA_TUNER_XC5000
 config MEDIA_TUNER_MXL5005S
        tristate "MaxLinear MSL5005S silicon tuner"
        depends on VIDEO_MEDIA && I2C
-       default m if DVB_FE_CUSTOMISE
+       default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon tuner MXL5005S from MaxLinear.
 
 config MEDIA_TUNER_MXL5007T
        tristate "MaxLinear MxL5007T silicon tuner"
        depends on VIDEO_MEDIA && I2C
-       default m if DVB_FE_CUSTOMISE
+       default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon tuner MxL5007T from MaxLinear.
 
-endif # MEDIA_TUNER_CUSTOMIZE
+config MEDIA_TUNER_MC44S803
+       tristate "Freescale MC44S803 Low Power CMOS Broadband tuners"
+       depends on VIDEO_MEDIA && I2C
+       default m if MEDIA_TUNER_CUSTOMISE
+       help
+         Say Y here to support the Freescale MC44S803 based tuners
+
+endif # MEDIA_TUNER_CUSTOMISE
index 4dfbe5b8264ffbfcdb75cae344f8e1b1c0f51dc3..4132b2be79e54b5570ccf815d5bd0bf542e1c511 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o
 obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o
 obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o
 obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
+obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/common/tuners/mc44s803.c b/drivers/media/common/tuners/mc44s803.c
new file mode 100644 (file)
index 0000000..20c4485
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ *  Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
+ *
+ *  Copyright (c) 2009 Jochen Friedrich <jochen@scram.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "mc44s803.h"
+#include "mc44s803_priv.h"
+
+#define mc_printk(level, format, arg...)       \
+       printk(level "mc44s803: " format , ## arg)
+
+/* Writes a single register */
+static int mc44s803_writereg(struct mc44s803_priv *priv, u32 val)
+{
+       u8 buf[3];
+       struct i2c_msg msg = {
+               .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 3
+       };
+
+       buf[0] = (val & 0xff0000) >> 16;
+       buf[1] = (val & 0xff00) >> 8;
+       buf[2] = (val & 0xff);
+
+       if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+               mc_printk(KERN_WARNING, "I2C write failed\n");
+               return -EREMOTEIO;
+       }
+       return 0;
+}
+
+/* Reads a single register */
+static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val)
+{
+       u32 wval;
+       u8 buf[3];
+       int ret;
+       struct i2c_msg msg[] = {
+               { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
+                 .buf = buf, .len = 3 },
+       };
+
+       wval = MC44S803_REG_SM(MC44S803_REG_DATAREG, MC44S803_ADDR) |
+              MC44S803_REG_SM(reg, MC44S803_D);
+
+       ret = mc44s803_writereg(priv, wval);
+       if (ret)
+               return ret;
+
+       if (i2c_transfer(priv->i2c, msg, 1) != 1) {
+               mc_printk(KERN_WARNING, "I2C read failed\n");
+               return -EREMOTEIO;
+       }
+
+       *val = (buf[0] << 16) | (buf[1] << 8) | buf[2];
+
+       return 0;
+}
+
+static int mc44s803_release(struct dvb_frontend *fe)
+{
+       struct mc44s803_priv *priv = fe->tuner_priv;
+
+       fe->tuner_priv = NULL;
+       kfree(priv);
+
+       return 0;
+}
+
+static int mc44s803_init(struct dvb_frontend *fe)
+{
+       struct mc44s803_priv *priv = fe->tuner_priv;
+       u32 val;
+       int err;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+
+/* Reset chip */
+       val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR) |
+             MC44S803_REG_SM(1, MC44S803_RS);
+
+       err = mc44s803_writereg(priv, val);
+       if (err)
+               goto exit;
+
+       val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR);
+
+       err = mc44s803_writereg(priv, val);
+       if (err)
+               goto exit;
+
+/* Power Up and Start Osc */
+
+       val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
+             MC44S803_REG_SM(0xC0, MC44S803_REFOSC) |
+             MC44S803_REG_SM(1, MC44S803_OSCSEL);
+
+       err = mc44s803_writereg(priv, val);
+       if (err)
+               goto exit;
+
+       val = MC44S803_REG_SM(MC44S803_REG_POWER, MC44S803_ADDR) |
+             MC44S803_REG_SM(0x200, MC44S803_POWER);
+
+       err = mc44s803_writereg(priv, val);
+       if (err)
+               goto exit;
+
+       msleep(10);
+
+       val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
+             MC44S803_REG_SM(0x40, MC44S803_REFOSC) |
+             MC44S803_REG_SM(1, MC44S803_OSCSEL);
+
+       err = mc44s803_writereg(priv, val);
+       if (err)
+               goto exit;
+
+       msleep(20);
+
+/* Setup Mixer */
+
+       val = MC44S803_REG_SM(MC44S803_REG_MIXER, MC44S803_ADDR) |
+             MC44S803_REG_SM(1, MC44S803_TRI_STATE) |
+             MC44S803_REG_SM(0x7F, MC44S803_MIXER_RES);
+
+       err = mc44s803_writereg(priv, val);
+       if (err)
+               goto exit;
+
+/* Setup Cirquit Adjust */
+
+       val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
+             MC44S803_REG_SM(1, MC44S803_G1) |
+             MC44S803_REG_SM(1, MC44S803_G3) |
+             MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
+             MC44S803_REG_SM(1, MC44S803_G6) |
+             MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
+             MC44S803_REG_SM(0x3, MC44S803_LP) |
+             MC44S803_REG_SM(1, MC44S803_CLRF) |
+             MC44S803_REG_SM(1, MC44S803_CLIF);
+
+       err = mc44s803_writereg(priv, val);
+       if (err)
+               goto exit;
+
+       val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
+             MC44S803_REG_SM(1, MC44S803_G1) |
+             MC44S803_REG_SM(1, MC44S803_G3) |
+             MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
+             MC44S803_REG_SM(1, MC44S803_G6) |
+             MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
+             MC44S803_REG_SM(0x3, MC44S803_LP);
+
+       err = mc44s803_writereg(priv, val);
+       if (err)
+               goto exit;
+
+/* Setup Digtune */
+
+       val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
+             MC44S803_REG_SM(3, MC44S803_XOD);
+
+       err = mc44s803_writereg(priv, val);
+       if (err)
+               goto exit;
+
+/* Setup AGC */
+
+       val = MC44S803_REG_SM(MC44S803_REG_LNAAGC, MC44S803_ADDR) |
+             MC44S803_REG_SM(1, MC44S803_AT1) |
+             MC44S803_REG_SM(1, MC44S803_AT2) |
+             MC44S803_REG_SM(1, MC44S803_AGC_AN_DIG) |
+             MC44S803_REG_SM(1, MC44S803_AGC_READ_EN) |
+             MC44S803_REG_SM(1, MC44S803_LNA0);
+
+       err = mc44s803_writereg(priv, val);
+       if (err)
+               goto exit;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+       return 0;
+
+exit:
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
+       mc_printk(KERN_WARNING, "I/O Error\n");
+       return err;
+}
+
+static int mc44s803_set_params(struct dvb_frontend *fe,
+                              struct dvb_frontend_parameters *params)
+{
+       struct mc44s803_priv *priv = fe->tuner_priv;
+       u32 r1, r2, n1, n2, lo1, lo2, freq, val;
+       int err;
+
+       priv->frequency = params->frequency;
+
+       r1 = MC44S803_OSC / 1000000;
+       r2 = MC44S803_OSC /  100000;
+
+       n1 = (params->frequency + MC44S803_IF1 + 500000) / 1000000;
+       freq = MC44S803_OSC / r1 * n1;
+       lo1 = ((60 * n1) + (r1 / 2)) / r1;
+       freq = freq - params->frequency;
+
+       n2 = (freq - MC44S803_IF2 + 50000) / 100000;
+       lo2 = ((60 * n2) + (r2 / 2)) / r2;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+
+       val = MC44S803_REG_SM(MC44S803_REG_REFDIV, MC44S803_ADDR) |
+             MC44S803_REG_SM(r1-1, MC44S803_R1) |
+             MC44S803_REG_SM(r2-1, MC44S803_R2) |
+             MC44S803_REG_SM(1, MC44S803_REFBUF_EN);
+
+       err = mc44s803_writereg(priv, val);
+       if (err)
+               goto exit;
+
+       val = MC44S803_REG_SM(MC44S803_REG_LO1, MC44S803_ADDR) |
+             MC44S803_REG_SM(n1-2, MC44S803_LO1);
+
+       err = mc44s803_writereg(priv, val);
+       if (err)
+               goto exit;
+
+       val = MC44S803_REG_SM(MC44S803_REG_LO2, MC44S803_ADDR) |
+             MC44S803_REG_SM(n2-2, MC44S803_LO2);
+
+       err = mc44s803_writereg(priv, val);
+       if (err)
+               goto exit;
+
+       val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
+             MC44S803_REG_SM(1, MC44S803_DA) |
+             MC44S803_REG_SM(lo1, MC44S803_LO_REF) |
+             MC44S803_REG_SM(1, MC44S803_AT);
+
+       err = mc44s803_writereg(priv, val);
+       if (err)
+               goto exit;
+
+       val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
+             MC44S803_REG_SM(2, MC44S803_DA) |
+             MC44S803_REG_SM(lo2, MC44S803_LO_REF) |
+             MC44S803_REG_SM(1, MC44S803_AT);
+
+       err = mc44s803_writereg(priv, val);
+       if (err)
+               goto exit;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
+       return 0;
+
+exit:
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
+       mc_printk(KERN_WARNING, "I/O Error\n");
+       return err;
+}
+
+static int mc44s803_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct mc44s803_priv *priv = fe->tuner_priv;
+       *frequency = priv->frequency;
+       return 0;
+}
+
+static const struct dvb_tuner_ops mc44s803_tuner_ops = {
+       .info = {
+               .name           = "Freescale MC44S803",
+               .frequency_min  =   48000000,
+               .frequency_max  = 1000000000,
+               .frequency_step =     100000,
+       },
+
+       .release       = mc44s803_release,
+       .init          = mc44s803_init,
+       .set_params    = mc44s803_set_params,
+       .get_frequency = mc44s803_get_frequency
+};
+
+/* This functions tries to identify a MC44S803 tuner by reading the ID
+   register. This is hasty. */
+struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
+        struct i2c_adapter *i2c, struct mc44s803_config *cfg)
+{
+       struct mc44s803_priv *priv;
+       u32 reg;
+       u8 id;
+       int ret;
+
+       reg = 0;
+
+       priv = kzalloc(sizeof(struct mc44s803_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return NULL;
+
+       priv->cfg = cfg;
+       priv->i2c = i2c;
+       priv->fe  = fe;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+       ret = mc44s803_readreg(priv, MC44S803_REG_ID, &reg);
+       if (ret)
+               goto error;
+
+       id = MC44S803_REG_MS(reg, MC44S803_ID);
+
+       if (id != 0x14) {
+               mc_printk(KERN_ERR, "unsupported ID "
+                      "(%x should be 0x14)\n", id);
+               goto error;
+       }
+
+       mc_printk(KERN_INFO, "successfully identified (ID = %x)\n", id);
+       memcpy(&fe->ops.tuner_ops, &mc44s803_tuner_ops,
+              sizeof(struct dvb_tuner_ops));
+
+       fe->tuner_priv = priv;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+       return fe;
+
+error:
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+       kfree(priv);
+       return NULL;
+}
+EXPORT_SYMBOL(mc44s803_attach);
+
+MODULE_AUTHOR("Jochen Friedrich");
+MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/mc44s803.h b/drivers/media/common/tuners/mc44s803.h
new file mode 100644 (file)
index 0000000..34f3892
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ *  Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
+ *
+ *  Copyright (c) 2009 Jochen Friedrich <jochen@scram.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef MC44S803_H
+#define MC44S803_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct mc44s803_config {
+       u8 i2c_address;
+       u8 dig_out;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_MC44S803) || \
+    (defined(CONFIG_MEDIA_TUNER_MC44S803_MODULE) && defined(MODULE))
+extern struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
+        struct i2c_adapter *i2c, struct mc44s803_config *cfg);
+#else
+static inline struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
+        struct i2c_adapter *i2c, struct mc44s803_config *cfg)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_MEDIA_TUNER_MC44S803 */
+
+#endif
diff --git a/drivers/media/common/tuners/mc44s803_priv.h b/drivers/media/common/tuners/mc44s803_priv.h
new file mode 100644 (file)
index 0000000..14a9278
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ *  Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
+ *
+ *  Copyright (c) 2009 Jochen Friedrich <jochen@scram.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef MC44S803_PRIV_H
+#define MC44S803_PRIV_H
+
+/* This driver is based on the information available in the datasheet
+   http://www.freescale.com/files/rf_if/doc/data_sheet/MC44S803.pdf
+
+   SPI or I2C Address : 0xc0-0xc6
+
+   Reg.No | Function
+   -------------------------------------------
+       00 | Power Down
+       01 | Reference Oszillator
+       02 | Reference Dividers
+       03 | Mixer and Reference Buffer
+       04 | Reset/Serial Out
+       05 | LO 1
+       06 | LO 2
+       07 | Circuit Adjust
+       08 | Test
+       09 | Digital Tune
+       0A | LNA AGC
+       0B | Data Register Address
+       0C | Regulator Test
+       0D | VCO Test
+       0E | LNA Gain/Input Power
+       0F | ID Bits
+
+*/
+
+#define MC44S803_OSC 26000000  /* 26 MHz */
+#define MC44S803_IF1 1086000000 /* 1086 MHz */
+#define MC44S803_IF2 36125000  /* 36.125 MHz */
+
+#define MC44S803_REG_POWER     0
+#define MC44S803_REG_REFOSC    1
+#define MC44S803_REG_REFDIV    2
+#define MC44S803_REG_MIXER     3
+#define MC44S803_REG_RESET     4
+#define MC44S803_REG_LO1       5
+#define MC44S803_REG_LO2       6
+#define MC44S803_REG_CIRCADJ   7
+#define MC44S803_REG_TEST      8
+#define MC44S803_REG_DIGTUNE   9
+#define MC44S803_REG_LNAAGC    0x0A
+#define MC44S803_REG_DATAREG   0x0B
+#define MC44S803_REG_REGTEST   0x0C
+#define MC44S803_REG_VCOTEST   0x0D
+#define MC44S803_REG_LNAGAIN   0x0E
+#define MC44S803_REG_ID                0x0F
+
+/* Register definitions */
+#define MC44S803_ADDR          0x0F
+#define MC44S803_ADDR_S                0
+/* REG_POWER */
+#define MC44S803_POWER         0xFFFFF0
+#define MC44S803_POWER_S       4
+/* REG_REFOSC */
+#define MC44S803_REFOSC                0x1FF0
+#define MC44S803_REFOSC_S      4
+#define MC44S803_OSCSEL                0x2000
+#define MC44S803_OSCSEL_S      13
+/* REG_REFDIV */
+#define MC44S803_R2            0x1FF0
+#define MC44S803_R2_S          4
+#define MC44S803_REFBUF_EN     0x2000
+#define MC44S803_REFBUF_EN_S   13
+#define MC44S803_R1            0x7C000
+#define MC44S803_R1_S          14
+/* REG_MIXER */
+#define MC44S803_R3            0x70
+#define MC44S803_R3_S          4
+#define MC44S803_MUX3          0x80
+#define MC44S803_MUX3_S                7
+#define MC44S803_MUX4          0x100
+#define MC44S803_MUX4_S                8
+#define MC44S803_OSC_SCR       0x200
+#define MC44S803_OSC_SCR_S     9
+#define MC44S803_TRI_STATE     0x400
+#define MC44S803_TRI_STATE_S   10
+#define MC44S803_BUF_GAIN      0x800
+#define MC44S803_BUF_GAIN_S    11
+#define MC44S803_BUF_IO                0x1000
+#define MC44S803_BUF_IO_S      12
+#define MC44S803_MIXER_RES     0xFE000
+#define MC44S803_MIXER_RES_S   13
+/* REG_RESET */
+#define MC44S803_RS            0x10
+#define MC44S803_RS_S          4
+#define MC44S803_SO            0x20
+#define MC44S803_SO_S          5
+/* REG_LO1 */
+#define MC44S803_LO1           0xFFF0
+#define MC44S803_LO1_S         4
+/* REG_LO2 */
+#define MC44S803_LO2           0x7FFF0
+#define MC44S803_LO2_S         4
+/* REG_CIRCADJ */
+#define MC44S803_G1            0x20
+#define MC44S803_G1_S          5
+#define MC44S803_G3            0x80
+#define MC44S803_G3_S          7
+#define MC44S803_CIRCADJ_RES   0x300
+#define MC44S803_CIRCADJ_RES_S 8
+#define MC44S803_G6            0x400
+#define MC44S803_G6_S          10
+#define MC44S803_G7            0x800
+#define MC44S803_G7_S          11
+#define MC44S803_S1            0x1000
+#define MC44S803_S1_S          12
+#define MC44S803_LP            0x7E000
+#define MC44S803_LP_S          13
+#define MC44S803_CLRF          0x80000
+#define MC44S803_CLRF_S                19
+#define MC44S803_CLIF          0x100000
+#define MC44S803_CLIF_S                20
+/* REG_TEST */
+/* REG_DIGTUNE */
+#define MC44S803_DA            0xF0
+#define MC44S803_DA_S          4
+#define MC44S803_XOD           0x300
+#define MC44S803_XOD_S         8
+#define MC44S803_RST           0x10000
+#define MC44S803_RST_S         16
+#define MC44S803_LO_REF                0x1FFF00
+#define MC44S803_LO_REF_S      8
+#define MC44S803_AT            0x200000
+#define MC44S803_AT_S          21
+#define MC44S803_MT            0x400000
+#define MC44S803_MT_S          22
+/* REG_LNAAGC */
+#define MC44S803_G             0x3F0
+#define MC44S803_G_S           4
+#define MC44S803_AT1           0x400
+#define MC44S803_AT1_S         10
+#define MC44S803_AT2           0x800
+#define MC44S803_AT2_S         11
+#define MC44S803_HL_GR_EN      0x8000
+#define MC44S803_HL_GR_EN_S    15
+#define MC44S803_AGC_AN_DIG    0x10000
+#define MC44S803_AGC_AN_DIG_S  16
+#define MC44S803_ATTEN_EN      0x20000
+#define MC44S803_ATTEN_EN_S    17
+#define MC44S803_AGC_READ_EN   0x40000
+#define MC44S803_AGC_READ_EN_S 18
+#define MC44S803_LNA0          0x80000
+#define MC44S803_LNA0_S                19
+#define MC44S803_AGC_SEL       0x100000
+#define MC44S803_AGC_SEL_S     20
+#define MC44S803_AT0           0x200000
+#define MC44S803_AT0_S         21
+#define MC44S803_B             0xC00000
+#define MC44S803_B_S           22
+/* REG_DATAREG */
+#define MC44S803_D             0xF0
+#define MC44S803_D_S           4
+/* REG_REGTEST */
+/* REG_VCOTEST */
+/* REG_LNAGAIN */
+#define MC44S803_IF_PWR                0x700
+#define MC44S803_IF_PWR_S      8
+#define MC44S803_RF_PWR                0x3800
+#define MC44S803_RF_PWR_S      11
+#define MC44S803_LNA_GAIN      0xFC000
+#define MC44S803_LNA_GAIN_S    14
+/* REG_ID */
+#define MC44S803_ID            0x3E00
+#define MC44S803_ID_S          9
+
+/* Some macros to read/write fields */
+
+/* First shift, then mask */
+#define MC44S803_REG_SM(_val, _reg)                                    \
+       (((_val) << _reg##_S) & (_reg))
+
+/* First mask, then shift */
+#define MC44S803_REG_MS(_val, _reg)                                    \
+       (((_val) & (_reg)) >> _reg##_S)
+
+struct mc44s803_priv {
+       struct mc44s803_config *cfg;
+       struct i2c_adapter *i2c;
+       struct dvb_frontend *fe;
+
+       u32 frequency;
+};
+
+#endif
index 12206d75dd4ee968d96213ebe31f75b55fb14ba5..c7abe3d8f90e1eccdfface5dd7471d3fd0a5fef5 100644 (file)
@@ -278,7 +278,7 @@ static void mt2060_calibrate(struct mt2060_priv *priv)
        while (i++ < 10 && mt2060_readreg(priv, REG_MISC_STAT, &b) == 0 && (b & (1 << 6)) == 0)
                msleep(20);
 
-       if (i < 10) {
+       if (i <= 10) {
                mt2060_readreg(priv, REG_FM_FREQ, &priv->fmfreq); // now find out, what is fmreq used for :)
                dprintk("calibration was successful: %d", (int)priv->fmfreq);
        } else
index 35b763a16d53748abc5aca07905f70981f576267..44608ad4e2d205132e2b9f86cfc62beaddd67fd4 100644 (file)
@@ -6,7 +6,7 @@
  */
 #include <linux/delay.h>
 #include <linux/i2c.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include "tuner-i2c.h"
 #include "mt20xx.h"
 
index 31522d2e318ea23dbb9ca41c4fcba4b2e7141abf..0803dab58fff1783d82a4d45ba188e89dac9d698 100644 (file)
@@ -4003,12 +4003,11 @@ static int mxl5005s_set_params(struct dvb_frontend *fe,
        /* Change tuner for new modulation type if reqd */
        if (req_mode != state->current_mode) {
                switch (req_mode) {
-               case VSB_8:
-               case QAM_64:
-               case QAM_256:
-               case QAM_AUTO:
+               case MXL_ATSC:
+               case MXL_QAM:
                        req_bw  = MXL5005S_BANDWIDTH_6MHZ;
                        break;
+               case MXL_DVBT:
                default:
                        /* Assume DVB-T */
                        switch (params->u.ofdm.bandwidth) {
index 3ec28945c26f21b7e0d7cc8d48c772aba35c384d..2d02698d4f4fd8c9d87c6864b027432e138972c6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner
  *
- *  Copyright (C) 2008 Michael Krufky <mkrufky@linuxtv.org>
+ *  Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -66,22 +66,17 @@ MODULE_PARM_DESC(debug, "set debug level");
 #define MHz 1000000
 
 enum mxl5007t_mode {
-       MxL_MODE_OTA_DVBT_ATSC        =    0,
-       MxL_MODE_OTA_NTSC_PAL_GH      =    1,
-       MxL_MODE_OTA_PAL_IB           =    2,
-       MxL_MODE_OTA_PAL_D_SECAM_KL   =    3,
-       MxL_MODE_OTA_ISDBT            =    4,
-       MxL_MODE_CABLE_DIGITAL        = 0x10,
-       MxL_MODE_CABLE_NTSC_PAL_GH    = 0x11,
-       MxL_MODE_CABLE_PAL_IB         = 0x12,
-       MxL_MODE_CABLE_PAL_D_SECAM_KL = 0x13,
-       MxL_MODE_CABLE_SCTE40         = 0x14,
+       MxL_MODE_ISDBT     =    0,
+       MxL_MODE_DVBT      =    1,
+       MxL_MODE_ATSC      =    2,
+       MxL_MODE_CABLE     = 0x10,
 };
 
 enum mxl5007t_chip_version {
        MxL_UNKNOWN_ID     = 0x00,
        MxL_5007_V1_F1     = 0x11,
        MxL_5007_V1_F2     = 0x12,
+       MxL_5007_V4        = 0x14,
        MxL_5007_V2_100_F1 = 0x21,
        MxL_5007_V2_100_F2 = 0x22,
        MxL_5007_V2_200_F1 = 0x23,
@@ -96,67 +91,61 @@ struct reg_pair_t {
 /* ------------------------------------------------------------------------- */
 
 static struct reg_pair_t init_tab[] = {
-       { 0x0b, 0x44 }, /* XTAL */
-       { 0x0c, 0x60 }, /* IF */
-       { 0x10, 0x00 }, /* MISC */
-       { 0x12, 0xca }, /* IDAC */
-       { 0x16, 0x90 }, /* MODE */
-       { 0x32, 0x38 }, /* MODE Analog/Digital */
-       { 0xd8, 0x18 }, /* CLK_OUT_ENABLE */
-       { 0x2c, 0x34 }, /* OVERRIDE */
-       { 0x4d, 0x40 }, /* OVERRIDE */
-       { 0x7f, 0x02 }, /* OVERRIDE */
-       { 0x9a, 0x52 }, /* OVERRIDE */
-       { 0x48, 0x5a }, /* OVERRIDE */
-       { 0x76, 0x1a }, /* OVERRIDE */
-       { 0x6a, 0x48 }, /* OVERRIDE */
-       { 0x64, 0x28 }, /* OVERRIDE */
-       { 0x66, 0xe6 }, /* OVERRIDE */
-       { 0x35, 0x0e }, /* OVERRIDE */
-       { 0x7e, 0x01 }, /* OVERRIDE */
-       { 0x83, 0x00 }, /* OVERRIDE */
-       { 0x04, 0x0b }, /* OVERRIDE */
-       { 0x05, 0x01 }, /* TOP_MASTER_ENABLE */
+       { 0x02, 0x06 },
+       { 0x03, 0x48 },
+       { 0x05, 0x04 },
+       { 0x06, 0x10 },
+       { 0x2e, 0x15 }, /* OVERRIDE */
+       { 0x30, 0x10 }, /* OVERRIDE */
+       { 0x45, 0x58 }, /* OVERRIDE */
+       { 0x48, 0x19 }, /* OVERRIDE */
+       { 0x52, 0x03 }, /* OVERRIDE */
+       { 0x53, 0x44 }, /* OVERRIDE */
+       { 0x6a, 0x4b }, /* OVERRIDE */
+       { 0x76, 0x00 }, /* OVERRIDE */
+       { 0x78, 0x18 }, /* OVERRIDE */
+       { 0x7a, 0x17 }, /* OVERRIDE */
+       { 0x85, 0x06 }, /* OVERRIDE */
+       { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */
        { 0, 0 }
 };
 
 static struct reg_pair_t init_tab_cable[] = {
-       { 0x0b, 0x44 }, /* XTAL */
-       { 0x0c, 0x60 }, /* IF */
-       { 0x10, 0x00 }, /* MISC */
-       { 0x12, 0xca }, /* IDAC */
-       { 0x16, 0x90 }, /* MODE */
-       { 0x32, 0x38 }, /* MODE A/D */
-       { 0x71, 0x3f }, /* TOP1 */
-       { 0x72, 0x3f }, /* TOP2 */
-       { 0x74, 0x3f }, /* TOP3 */
-       { 0xd8, 0x18 }, /* CLK_OUT_ENABLE */
-       { 0x2c, 0x34 }, /* OVERRIDE */
-       { 0x4d, 0x40 }, /* OVERRIDE */
-       { 0x7f, 0x02 }, /* OVERRIDE */
-       { 0x9a, 0x52 }, /* OVERRIDE */
-       { 0x48, 0x5a }, /* OVERRIDE */
-       { 0x76, 0x1a }, /* OVERRIDE */
-       { 0x6a, 0x48 }, /* OVERRIDE */
-       { 0x64, 0x28 }, /* OVERRIDE */
-       { 0x66, 0xe6 }, /* OVERRIDE */
-       { 0x35, 0x0e }, /* OVERRIDE */
-       { 0x7e, 0x01 }, /* OVERRIDE */
-       { 0x04, 0x0b }, /* OVERRIDE */
-       { 0x68, 0xb4 }, /* OVERRIDE */
-       { 0x36, 0x00 }, /* OVERRIDE */
-       { 0x05, 0x01 }, /* TOP_MASTER_ENABLE */
+       { 0x02, 0x06 },
+       { 0x03, 0x48 },
+       { 0x05, 0x04 },
+       { 0x06, 0x10 },
+       { 0x09, 0x3f },
+       { 0x0a, 0x3f },
+       { 0x0b, 0x3f },
+       { 0x2e, 0x15 }, /* OVERRIDE */
+       { 0x30, 0x10 }, /* OVERRIDE */
+       { 0x45, 0x58 }, /* OVERRIDE */
+       { 0x48, 0x19 }, /* OVERRIDE */
+       { 0x52, 0x03 }, /* OVERRIDE */
+       { 0x53, 0x44 }, /* OVERRIDE */
+       { 0x6a, 0x4b }, /* OVERRIDE */
+       { 0x76, 0x00 }, /* OVERRIDE */
+       { 0x78, 0x18 }, /* OVERRIDE */
+       { 0x7a, 0x17 }, /* OVERRIDE */
+       { 0x85, 0x06 }, /* OVERRIDE */
+       { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */
        { 0, 0 }
 };
 
 /* ------------------------------------------------------------------------- */
 
 static struct reg_pair_t reg_pair_rftune[] = {
-       { 0x11, 0x00 }, /* abort tune */
-       { 0x13, 0x15 },
-       { 0x14, 0x40 },
-       { 0x15, 0x0e },
-       { 0x11, 0x02 }, /* start tune */
+       { 0x0f, 0x00 }, /* abort tune */
+       { 0x0c, 0x15 },
+       { 0x0d, 0x40 },
+       { 0x0e, 0x0e },
+       { 0x1f, 0x87 }, /* OVERRIDE */
+       { 0x20, 0x1f }, /* OVERRIDE */
+       { 0x21, 0x87 }, /* OVERRIDE */
+       { 0x22, 0x1f }, /* OVERRIDE */
+       { 0x80, 0x01 }, /* freq dependent */
+       { 0x0f, 0x01 }, /* start tune */
        { 0, 0 }
 };
 
@@ -227,63 +216,20 @@ static void mxl5007t_set_mode_bits(struct mxl5007t_state *state,
                                   s32 if_diff_out_level)
 {
        switch (mode) {
-       case MxL_MODE_OTA_DVBT_ATSC:
-               set_reg_bits(state->tab_init, 0x32, 0x0f, 0x06);
-               set_reg_bits(state->tab_init, 0x35, 0xff, 0x0e);
+       case MxL_MODE_ATSC:
+               set_reg_bits(state->tab_init, 0x06, 0x1f, 0x12);
                break;
-       case MxL_MODE_OTA_ISDBT:
-               set_reg_bits(state->tab_init, 0x32, 0x0f, 0x06);
-               set_reg_bits(state->tab_init, 0x35, 0xff, 0x12);
+       case MxL_MODE_DVBT:
+               set_reg_bits(state->tab_init, 0x06, 0x1f, 0x11);
                break;
-       case MxL_MODE_OTA_NTSC_PAL_GH:
-               set_reg_bits(state->tab_init, 0x16, 0x70, 0x00);
-               set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
+       case MxL_MODE_ISDBT:
+               set_reg_bits(state->tab_init, 0x06, 0x1f, 0x10);
                break;
-       case MxL_MODE_OTA_PAL_IB:
-               set_reg_bits(state->tab_init, 0x16, 0x70, 0x10);
-               set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
-               break;
-       case MxL_MODE_OTA_PAL_D_SECAM_KL:
-               set_reg_bits(state->tab_init, 0x16, 0x70, 0x20);
-               set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
-               break;
-       case MxL_MODE_CABLE_DIGITAL:
-               set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01);
-               set_reg_bits(state->tab_init_cable, 0x72, 0xff,
-                            8 - if_diff_out_level);
-               set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17);
-               break;
-       case MxL_MODE_CABLE_NTSC_PAL_GH:
-               set_reg_bits(state->tab_init, 0x16, 0x70, 0x00);
-               set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
-               set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01);
-               set_reg_bits(state->tab_init_cable, 0x72, 0xff,
-                            8 - if_diff_out_level);
-               set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17);
-               break;
-       case MxL_MODE_CABLE_PAL_IB:
-               set_reg_bits(state->tab_init, 0x16, 0x70, 0x10);
-               set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
-               set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01);
-               set_reg_bits(state->tab_init_cable, 0x72, 0xff,
+       case MxL_MODE_CABLE:
+               set_reg_bits(state->tab_init_cable, 0x09, 0xff, 0xc1);
+               set_reg_bits(state->tab_init_cable, 0x0a, 0xff,
                             8 - if_diff_out_level);
-               set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17);
-               break;
-       case MxL_MODE_CABLE_PAL_D_SECAM_KL:
-               set_reg_bits(state->tab_init, 0x16, 0x70, 0x20);
-               set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
-               set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01);
-               set_reg_bits(state->tab_init_cable, 0x72, 0xff,
-                            8 - if_diff_out_level);
-               set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17);
-               break;
-       case MxL_MODE_CABLE_SCTE40:
-               set_reg_bits(state->tab_init_cable, 0x36, 0xff, 0x08);
-               set_reg_bits(state->tab_init_cable, 0x68, 0xff, 0xbc);
-               set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01);
-               set_reg_bits(state->tab_init_cable, 0x72, 0xff,
-                            8 - if_diff_out_level);
-               set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17);
+               set_reg_bits(state->tab_init_cable, 0x0b, 0xff, 0x17);
                break;
        default:
                mxl_fail(-EINVAL);
@@ -302,43 +248,43 @@ static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state,
                val = 0x00;
                break;
        case MxL_IF_4_5_MHZ:
-               val = 0x20;
+               val = 0x02;
                break;
        case MxL_IF_4_57_MHZ:
-               val = 0x30;
+               val = 0x03;
                break;
        case MxL_IF_5_MHZ:
-               val = 0x40;
+               val = 0x04;
                break;
        case MxL_IF_5_38_MHZ:
-               val = 0x50;
+               val = 0x05;
                break;
        case MxL_IF_6_MHZ:
-               val = 0x60;
+               val = 0x06;
                break;
        case MxL_IF_6_28_MHZ:
-               val = 0x70;
+               val = 0x07;
                break;
        case MxL_IF_9_1915_MHZ:
-               val = 0x80;
+               val = 0x08;
                break;
        case MxL_IF_35_25_MHZ:
-               val = 0x90;
+               val = 0x09;
                break;
        case MxL_IF_36_15_MHZ:
-               val = 0xa0;
+               val = 0x0a;
                break;
        case MxL_IF_44_MHZ:
-               val = 0xb0;
+               val = 0x0b;
                break;
        default:
                mxl_fail(-EINVAL);
                return;
        }
-       set_reg_bits(state->tab_init, 0x0c, 0xf0, val);
+       set_reg_bits(state->tab_init, 0x02, 0x0f, val);
 
        /* set inverted IF or normal IF */
-       set_reg_bits(state->tab_init, 0x0c, 0x08, invert_if ? 0x08 : 0x00);
+       set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00);
 
        return;
 }
@@ -346,56 +292,68 @@ static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state,
 static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state,
                                        enum mxl5007t_xtal_freq xtal_freq)
 {
-       u8 val;
-
        switch (xtal_freq) {
        case MxL_XTAL_16_MHZ:
-               val = 0x00; /* select xtal freq & Ref Freq */
+               /* select xtal freq & ref freq */
+               set_reg_bits(state->tab_init, 0x03, 0xf0, 0x00);
+               set_reg_bits(state->tab_init, 0x05, 0x0f, 0x00);
                break;
        case MxL_XTAL_20_MHZ:
-               val = 0x11;
+               set_reg_bits(state->tab_init, 0x03, 0xf0, 0x10);
+               set_reg_bits(state->tab_init, 0x05, 0x0f, 0x01);
                break;
        case MxL_XTAL_20_25_MHZ:
-               val = 0x22;
+               set_reg_bits(state->tab_init, 0x03, 0xf0, 0x20);
+               set_reg_bits(state->tab_init, 0x05, 0x0f, 0x02);
                break;
        case MxL_XTAL_20_48_MHZ:
-               val = 0x33;
+               set_reg_bits(state->tab_init, 0x03, 0xf0, 0x30);
+               set_reg_bits(state->tab_init, 0x05, 0x0f, 0x03);
                break;
        case MxL_XTAL_24_MHZ:
-               val = 0x44;
+               set_reg_bits(state->tab_init, 0x03, 0xf0, 0x40);
+               set_reg_bits(state->tab_init, 0x05, 0x0f, 0x04);
                break;
        case MxL_XTAL_25_MHZ:
-               val = 0x55;
+               set_reg_bits(state->tab_init, 0x03, 0xf0, 0x50);
+               set_reg_bits(state->tab_init, 0x05, 0x0f, 0x05);
                break;
        case MxL_XTAL_25_14_MHZ:
-               val = 0x66;
+               set_reg_bits(state->tab_init, 0x03, 0xf0, 0x60);
+               set_reg_bits(state->tab_init, 0x05, 0x0f, 0x06);
                break;
        case MxL_XTAL_27_MHZ:
-               val = 0x77;
+               set_reg_bits(state->tab_init, 0x03, 0xf0, 0x70);
+               set_reg_bits(state->tab_init, 0x05, 0x0f, 0x07);
                break;
        case MxL_XTAL_28_8_MHZ:
-               val = 0x88;
+               set_reg_bits(state->tab_init, 0x03, 0xf0, 0x80);
+               set_reg_bits(state->tab_init, 0x05, 0x0f, 0x08);
                break;
        case MxL_XTAL_32_MHZ:
-               val = 0x99;
+               set_reg_bits(state->tab_init, 0x03, 0xf0, 0x90);
+               set_reg_bits(state->tab_init, 0x05, 0x0f, 0x09);
                break;
        case MxL_XTAL_40_MHZ:
-               val = 0xaa;
+               set_reg_bits(state->tab_init, 0x03, 0xf0, 0xa0);
+               set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0a);
                break;
        case MxL_XTAL_44_MHZ:
-               val = 0xbb;
+               set_reg_bits(state->tab_init, 0x03, 0xf0, 0xb0);
+               set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0b);
                break;
        case MxL_XTAL_48_MHZ:
-               val = 0xcc;
+               set_reg_bits(state->tab_init, 0x03, 0xf0, 0xc0);
+               set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0c);
                break;
        case MxL_XTAL_49_3811_MHZ:
-               val = 0xdd;
+               set_reg_bits(state->tab_init, 0x03, 0xf0, 0xd0);
+               set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0d);
                break;
        default:
                mxl_fail(-EINVAL);
                return;
        }
-       set_reg_bits(state->tab_init, 0x0b, 0xff, val);
 
        return;
 }
@@ -412,16 +370,11 @@ static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state,
        mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if);
        mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz);
 
-       set_reg_bits(state->tab_init, 0x10, 0x40, cfg->loop_thru_enable << 6);
-
-       set_reg_bits(state->tab_init, 0xd8, 0x08, cfg->clk_out_enable << 3);
-
-       set_reg_bits(state->tab_init, 0x10, 0x07, cfg->clk_out_amp);
+       set_reg_bits(state->tab_init, 0x04, 0x01, cfg->loop_thru_enable);
+       set_reg_bits(state->tab_init, 0x03, 0x08, cfg->clk_out_enable << 3);
+       set_reg_bits(state->tab_init, 0x03, 0x07, cfg->clk_out_amp);
 
-       /* set IDAC to automatic mode control by AGC */
-       set_reg_bits(state->tab_init, 0x12, 0x80, 0x00);
-
-       if (mode >= MxL_MODE_CABLE_DIGITAL) {
+       if (mode >= MxL_MODE_CABLE) {
                copy_reg_bits(state->tab_init, state->tab_init_cable);
                return state->tab_init_cable;
        } else
@@ -447,7 +400,7 @@ static void mxl5007t_set_bw_bits(struct mxl5007t_state *state,
                             * and DIG_MODEINDEX_CSF */
                break;
        case MxL_BW_7MHz:
-               val = 0x21;
+               val = 0x2a;
                break;
        case MxL_BW_8MHz:
                val = 0x3f;
@@ -456,7 +409,7 @@ static void mxl5007t_set_bw_bits(struct mxl5007t_state *state,
                mxl_fail(-EINVAL);
                return;
        }
-       set_reg_bits(state->tab_rftune, 0x13, 0x3f, val);
+       set_reg_bits(state->tab_rftune, 0x0c, 0x3f, val);
 
        return;
 }
@@ -493,8 +446,11 @@ reg_pair_t *mxl5007t_calc_rf_tune_regs(struct mxl5007t_state *state,
        if (temp > 7812)
                dig_rf_freq++;
 
-       set_reg_bits(state->tab_rftune, 0x14, 0xff, (u8)dig_rf_freq);
-       set_reg_bits(state->tab_rftune, 0x15, 0xff, (u8)(dig_rf_freq >> 8));
+       set_reg_bits(state->tab_rftune, 0x0d, 0xff, (u8) dig_rf_freq);
+       set_reg_bits(state->tab_rftune, 0x0e, 0xff, (u8) (dig_rf_freq >> 8));
+
+       if (rf_freq >= 333000000)
+               set_reg_bits(state->tab_rftune, 0x80, 0x40, 0x40);
 
        return state->tab_rftune;
 }
@@ -551,9 +507,10 @@ static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val)
 static int mxl5007t_soft_reset(struct mxl5007t_state *state)
 {
        u8 d = 0xff;
-       struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0,
-                              .buf = &d, .len = 1 };
-
+       struct i2c_msg msg = {
+               .addr = state->i2c_props.addr, .flags = 0,
+               .buf = &d, .len = 1
+       };
        int ret = i2c_transfer(state->i2c_props.adap, &msg, 1);
 
        if (ret != 1) {
@@ -580,9 +537,6 @@ static int mxl5007t_tuner_init(struct mxl5007t_state *state,
        if (mxl_fail(ret))
                goto fail;
        mdelay(1);
-
-       ret = mxl5007t_write_reg(state, 0x2c, 0x35);
-       mxl_fail(ret);
 fail:
        return ret;
 }
@@ -615,7 +569,7 @@ static int mxl5007t_synth_lock_status(struct mxl5007t_state *state,
        *rf_locked = 0;
        *ref_locked = 0;
 
-       ret = mxl5007t_read_reg(state, 0xcf, &d);
+       ret = mxl5007t_read_reg(state, 0xd8, &d);
        if (mxl_fail(ret))
                goto fail;
 
@@ -628,37 +582,14 @@ fail:
        return ret;
 }
 
-static int mxl5007t_check_rf_input_power(struct mxl5007t_state *state,
-                                        s32 *rf_input_level)
-{
-       u8 d1, d2;
-       int ret;
-
-       ret = mxl5007t_read_reg(state, 0xb7, &d1);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl5007t_read_reg(state, 0xbf, &d2);
-       if (mxl_fail(ret))
-               goto fail;
-
-       d2 = d2 >> 4;
-       if (d2 > 7)
-               d2 += 0xf0;
-
-       *rf_input_level = (s32)(d1 + d2 - 113);
-fail:
-       return ret;
-}
-
 /* ------------------------------------------------------------------------- */
 
 static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status)
 {
        struct mxl5007t_state *state = fe->tuner_priv;
-       int rf_locked, ref_locked;
-       s32 rf_input_level = 0;
-       int ret;
+       int rf_locked, ref_locked, ret;
+
+       *status = 0;
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
@@ -669,10 +600,8 @@ static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status)
        mxl_debug("%s%s", rf_locked ? "rf locked " : "",
                  ref_locked ? "ref locked" : "");
 
-       ret = mxl5007t_check_rf_input_power(state, &rf_input_level);
-       if (mxl_fail(ret))
-               goto fail;
-       mxl_debug("rf input power: %d", rf_input_level);
+       if ((rf_locked) || (ref_locked))
+               *status |= TUNER_STATUS_LOCKED;
 fail:
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0);
@@ -695,11 +624,11 @@ static int mxl5007t_set_params(struct dvb_frontend *fe,
                switch (params->u.vsb.modulation) {
                case VSB_8:
                case VSB_16:
-                       mode = MxL_MODE_OTA_DVBT_ATSC;
+                       mode = MxL_MODE_ATSC;
                        break;
                case QAM_64:
                case QAM_256:
-                       mode = MxL_MODE_CABLE_DIGITAL;
+                       mode = MxL_MODE_CABLE;
                        break;
                default:
                        mxl_err("modulation not set!");
@@ -721,7 +650,7 @@ static int mxl5007t_set_params(struct dvb_frontend *fe,
                        mxl_err("bandwidth not set!");
                        return -EINVAL;
                }
-               mode = MxL_MODE_OTA_DVBT_ATSC;
+               mode = MxL_MODE_DVBT;
        } else {
                mxl_err("modulation type not supported!");
                return -EINVAL;
@@ -752,96 +681,20 @@ fail:
        return ret;
 }
 
-static int mxl5007t_set_analog_params(struct dvb_frontend *fe,
-                                     struct analog_parameters *params)
-{
-       struct mxl5007t_state *state = fe->tuner_priv;
-       enum mxl5007t_bw_mhz bw = 0; /* FIXME */
-       enum mxl5007t_mode cbl_mode;
-       enum mxl5007t_mode ota_mode;
-       char *mode_name;
-       int ret;
-       u32 freq = params->frequency * 62500;
-
-#define cable 1
-       if (params->std & V4L2_STD_MN) {
-               cbl_mode = MxL_MODE_CABLE_NTSC_PAL_GH;
-               ota_mode = MxL_MODE_OTA_NTSC_PAL_GH;
-               mode_name = "MN";
-       } else if (params->std & V4L2_STD_B) {
-               cbl_mode = MxL_MODE_CABLE_PAL_IB;
-               ota_mode = MxL_MODE_OTA_PAL_IB;
-               mode_name = "B";
-       } else if (params->std & V4L2_STD_GH) {
-               cbl_mode = MxL_MODE_CABLE_NTSC_PAL_GH;
-               ota_mode = MxL_MODE_OTA_NTSC_PAL_GH;
-               mode_name = "GH";
-       } else if (params->std & V4L2_STD_PAL_I) {
-               cbl_mode = MxL_MODE_CABLE_PAL_IB;
-               ota_mode = MxL_MODE_OTA_PAL_IB;
-               mode_name = "I";
-       } else if (params->std & V4L2_STD_DK) {
-               cbl_mode = MxL_MODE_CABLE_PAL_D_SECAM_KL;
-               ota_mode = MxL_MODE_OTA_PAL_D_SECAM_KL;
-               mode_name = "DK";
-       } else if (params->std & V4L2_STD_SECAM_L) {
-               cbl_mode = MxL_MODE_CABLE_PAL_D_SECAM_KL;
-               ota_mode = MxL_MODE_OTA_PAL_D_SECAM_KL;
-               mode_name = "L";
-       } else if (params->std & V4L2_STD_SECAM_LC) {
-               cbl_mode = MxL_MODE_CABLE_PAL_D_SECAM_KL;
-               ota_mode = MxL_MODE_OTA_PAL_D_SECAM_KL;
-               mode_name = "L'";
-       } else {
-               mode_name = "xx";
-               /* FIXME */
-               cbl_mode = MxL_MODE_CABLE_NTSC_PAL_GH;
-               ota_mode = MxL_MODE_OTA_NTSC_PAL_GH;
-       }
-       mxl_debug("setting mxl5007 to system %s", mode_name);
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-
-       mutex_lock(&state->lock);
-
-       ret = mxl5007t_tuner_init(state, cable ? cbl_mode : ota_mode);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl5007t_tuner_rf_tune(state, freq, bw);
-       if (mxl_fail(ret))
-               goto fail;
-
-       state->frequency = freq;
-       state->bandwidth = 0;
-fail:
-       mutex_unlock(&state->lock);
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 0);
-
-       return ret;
-}
-
 /* ------------------------------------------------------------------------- */
 
 static int mxl5007t_init(struct dvb_frontend *fe)
 {
        struct mxl5007t_state *state = fe->tuner_priv;
        int ret;
-       u8 d;
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
 
-       ret = mxl5007t_read_reg(state, 0x05, &d);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl5007t_write_reg(state, 0x05, d | 0x01);
+       /* wake from standby */
+       ret = mxl5007t_write_reg(state, 0x01, 0x01);
        mxl_fail(ret);
-fail:
+
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0);
 
@@ -852,18 +705,16 @@ static int mxl5007t_sleep(struct dvb_frontend *fe)
 {
        struct mxl5007t_state *state = fe->tuner_priv;
        int ret;
-       u8 d;
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
 
-       ret = mxl5007t_read_reg(state, 0x05, &d);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl5007t_write_reg(state, 0x05, d & ~0x01);
+       /* enter standby mode */
+       ret = mxl5007t_write_reg(state, 0x01, 0x00);
        mxl_fail(ret);
-fail:
+       ret = mxl5007t_write_reg(state, 0x0f, 0x00);
+       mxl_fail(ret);
+
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0);
 
@@ -911,7 +762,6 @@ static struct dvb_tuner_ops mxl5007t_tuner_ops = {
        .init              = mxl5007t_init,
        .sleep             = mxl5007t_sleep,
        .set_params        = mxl5007t_set_params,
-       .set_analog_params = mxl5007t_set_analog_params,
        .get_status        = mxl5007t_get_status,
        .get_frequency     = mxl5007t_get_frequency,
        .get_bandwidth     = mxl5007t_get_bandwidth,
@@ -924,7 +774,7 @@ static int mxl5007t_get_chip_id(struct mxl5007t_state *state)
        int ret;
        u8 id;
 
-       ret = mxl5007t_read_reg(state, 0xd3, &id);
+       ret = mxl5007t_read_reg(state, 0xd9, &id);
        if (mxl_fail(ret))
                goto fail;
 
@@ -947,8 +797,12 @@ static int mxl5007t_get_chip_id(struct mxl5007t_state *state)
        case MxL_5007_V2_200_F2:
                name = "MxL5007.v2.200.f2";
                break;
+       case MxL_5007_V4:
+               name = "MxL5007T.v4";
+               break;
        default:
                name = "MxL5007T";
+               printk(KERN_WARNING "%s: unknown rev (%02x)\n", __func__, id);
                id = MxL_UNKNOWN_ID;
        }
        state->chip_id = id;
@@ -975,7 +829,7 @@ struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
        mutex_lock(&mxl5007t_list_mutex);
        instance = hybrid_tuner_request_state(struct mxl5007t_state, state,
                                              hybrid_tuner_instance_list,
-                                             i2c, addr, "mxl5007");
+                                             i2c, addr, "mxl5007t");
        switch (instance) {
        case 0:
                goto fail;
@@ -1018,7 +872,7 @@ EXPORT_SYMBOL_GPL(mxl5007t_attach);
 MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver");
 MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.1");
+MODULE_VERSION("0.2");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
index 6fb5b45865690b3a4279e891d09cf43e222a7dee..fc76c30e24f10818f850c3d1b2b49daf441c1b65 100644 (file)
@@ -490,9 +490,9 @@ int tda18271_set_standby_mode(struct dvb_frontend *fe,
                tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt);
 
        regs[R_EP3]  &= ~0xe0; /* clear sm, sm_lt, sm_xt */
-       regs[R_EP3]  |= sm    ? (1 << 7) : 0 |
-                       sm_lt ? (1 << 6) : 0 |
-                       sm_xt ? (1 << 5) : 0;
+       regs[R_EP3]  |= (sm    ? (1 << 7) : 0) |
+                       (sm_lt ? (1 << 6) : 0) |
+                       (sm_xt ? (1 << 5) : 0);
 
        return tda18271_write_regs(fe, R_EP3, 1);
 }
index 1b48b5d0bf1ef7a708a92131d120684c98750b43..b10935630154f94b4845c15f4abf314cdf9eb4ee 100644 (file)
@@ -818,6 +818,38 @@ fail:
        return ret;
 }
 
+/* ------------------------------------------------------------------ */
+
+static int tda18271_agc(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       int ret = 0;
+
+       switch (priv->config) {
+       case 0:
+               /* no LNA */
+               tda_dbg("no agc configuration provided\n");
+               break;
+       case 3:
+               /* switch with GPIO of saa713x */
+               tda_dbg("invoking callback\n");
+               if (fe->callback)
+                       ret = fe->callback(priv->i2c_props.adap->algo_data,
+                                          DVB_FRONTEND_COMPONENT_TUNER,
+                                          TDA18271_CALLBACK_CMD_AGC_ENABLE,
+                                          priv->mode);
+               break;
+       case 1:
+       case 2:
+       default:
+               /* n/a - currently not supported */
+               tda_err("unsupported configuration: %d\n", priv->config);
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
 static int tda18271_tune(struct dvb_frontend *fe,
                         struct tda18271_std_map_item *map, u32 freq, u32 bw)
 {
@@ -827,6 +859,10 @@ static int tda18271_tune(struct dvb_frontend *fe,
        tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n",
                freq, map->if_freq, bw, map->agc_mode, map->std);
 
+       ret = tda18271_agc(fe);
+       if (tda_fail(ret))
+               tda_warn("failed to configure agc\n");
+
        ret = tda18271_init(fe);
        if (tda_fail(ret))
                goto fail;
@@ -1159,6 +1195,7 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
                /* new tuner instance */
                priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
                priv->role = (cfg) ? cfg->role : TDA18271_MASTER;
+               priv->config = (cfg) ? cfg->config : 0;
                priv->cal_initialized = false;
                mutex_init(&priv->lock);
 
index 81a739365f8c65eb399379bf872fcfd91c42afb2..74beb28806f85bef0cb7ad13cf06bcb0804b1547 100644 (file)
@@ -91,11 +91,6 @@ enum tda18271_pll {
        TDA18271_CAL_PLL,
 };
 
-enum tda18271_mode {
-       TDA18271_ANALOG,
-       TDA18271_DIGITAL,
-};
-
 struct tda18271_map_layout;
 
 enum tda18271_ver {
@@ -114,6 +109,7 @@ struct tda18271_priv {
        enum tda18271_i2c_gate gate;
        enum tda18271_ver id;
 
+       unsigned int config; /* interface to saa713x / tda829x */
        unsigned int tm_rfcal;
        unsigned int cal_initialized:1;
        unsigned int small_i2c:1;
index 7db9831c0cb073a0b75bf04d7bd0e745ec92f10b..53a9892a18d0fd6ca7c19bf0b1979a7a26155d4e 100644 (file)
@@ -79,6 +79,16 @@ struct tda18271_config {
 
        /* some i2c providers cant write all 39 registers at once */
        unsigned int small_i2c:1;
+
+       /* interface to saa713x / tda829x */
+       unsigned int config;
+};
+
+#define TDA18271_CALLBACK_CMD_AGC_ENABLE 0
+
+enum tda18271_mode {
+       TDA18271_ANALOG = 0,
+       TDA18271_DIGITAL,
 };
 
 #if defined(CONFIG_MEDIA_TUNER_TDA18271) || (defined(CONFIG_MEDIA_TUNER_TDA18271_MODULE) && defined(MODULE))
index f4d931f14fad5bae30b8fc73e94aeec3e9891199..36a7bc7585ab6c12473033a12ceeb72cb12e4861 100644 (file)
@@ -132,11 +132,31 @@ static const struct tda827x_data tda827x_table[] = {
        { .lomax =         0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}
 };
 
+static int tuner_transfer(struct dvb_frontend *fe,
+                         struct i2c_msg *msg,
+                         const int size)
+{
+       int rc;
+       struct tda827x_priv *priv = fe->tuner_priv;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       rc = i2c_transfer(priv->i2c_adap, msg, size);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
+       if (rc >= 0 && rc != size)
+               return -EIO;
+
+       return rc;
+}
+
 static int tda827xo_set_params(struct dvb_frontend *fe,
                               struct dvb_frontend_parameters *params)
 {
        struct tda827x_priv *priv = fe->tuner_priv;
        u8 buf[14];
+       int rc;
 
        struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
                               .buf = buf, .len = sizeof(buf) };
@@ -183,27 +203,29 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
        buf[13] = 0x40;
 
        msg.len = 14;
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
-               printk("%s: could not write to tuner at addr: 0x%02x\n",
-                      __func__, priv->i2c_addr << 1);
-               return -EIO;
-       }
+       rc = tuner_transfer(fe, &msg, 1);
+       if (rc < 0)
+               goto err;
+
        msleep(500);
        /* correct CP value */
        buf[0] = 0x30;
        buf[1] = 0x50 + tda827x_table[i].cp;
        msg.len = 2;
 
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       rc = tuner_transfer(fe, &msg, 1);
+       if (rc < 0)
+               goto err;
 
        priv->frequency = params->frequency;
        priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
 
        return 0;
+
+err:
+       printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n",
+              __func__, priv->i2c_addr << 1);
+       return rc;
 }
 
 static int tda827xo_sleep(struct dvb_frontend *fe)
@@ -214,9 +236,7 @@ static int tda827xo_sleep(struct dvb_frontend *fe)
                               .buf = buf, .len = sizeof(buf) };
 
        dprintk("%s:\n", __func__);
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        if (priv->cfg && priv->cfg->sleep)
                priv->cfg->sleep(fe);
@@ -266,44 +286,44 @@ static int tda827xo_set_analog_params(struct dvb_frontend *fe,
 
        msg.buf = tuner_reg;
        msg.len = 8;
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        msg.buf = reg2;
        msg.len = 2;
        reg2[0] = 0x80;
        reg2[1] = 0;
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        reg2[0] = 0x60;
        reg2[1] = 0xbf;
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        reg2[0] = 0x30;
        reg2[1] = tuner_reg[4] + 0x80;
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        msleep(1);
        reg2[0] = 0x30;
        reg2[1] = tuner_reg[4] + 4;
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        msleep(1);
        reg2[0] = 0x30;
        reg2[1] = tuner_reg[4];
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        msleep(550);
        reg2[0] = 0x30;
        reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp;
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        reg2[0] = 0x60;
        reg2[1] = 0x3f;
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        reg2[0] = 0x80;
        reg2[1] = 0x08;   /* Vsync en */
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        priv->frequency = params->frequency;
 
@@ -317,7 +337,7 @@ static void tda827xo_agcf(struct dvb_frontend *fe)
        struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
                               .buf = data, .len = 2};
 
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 }
 
 /* ------------------------------------------------------------------ */
@@ -331,7 +351,7 @@ struct tda827xa_data {
        u8  gc3;
 };
 
-static const struct tda827xa_data tda827xa_dvbt[] = {
+static struct tda827xa_data tda827xa_dvbt[] = {
        { .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1},
        { .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
        { .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
@@ -361,6 +381,36 @@ static const struct tda827xa_data tda827xa_dvbt[] = {
        { .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
 };
 
+static struct tda827xa_data tda827xa_dvbc[] = {
+       { .lomax =  50125000, .svco = 2, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3},
+       { .lomax =  58500000, .svco = 3, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3},
+       { .lomax =  69250000, .svco = 0, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
+       { .lomax =  83625000, .svco = 1, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
+       { .lomax =  97500000, .svco = 2, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
+       { .lomax = 100250000, .svco = 2, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1},
+       { .lomax = 117000000, .svco = 3, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1},
+       { .lomax = 138500000, .svco = 0, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
+       { .lomax = 167250000, .svco = 1, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
+       { .lomax = 187000000, .svco = 2, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
+       { .lomax = 200500000, .svco = 2, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 1},
+       { .lomax = 234000000, .svco = 3, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 3},
+       { .lomax = 277000000, .svco = 0, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 3},
+       { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 1},
+       { .lomax = 334500000, .svco = 1, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3},
+       { .lomax = 401000000, .svco = 2, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3},
+       { .lomax = 468000000, .svco = 3, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 1},
+       { .lomax = 535000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
+       { .lomax = 554000000, .svco = 0, .spd = 0, .scr = 2, .sbs = 3, .gc3 = 1},
+       { .lomax = 638000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
+       { .lomax = 669000000, .svco = 1, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
+       { .lomax = 720000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
+       { .lomax = 802000000, .svco = 2, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
+       { .lomax = 835000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
+       { .lomax = 885000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
+       { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
+       { .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
+};
+
 static struct tda827xa_data tda827xa_analog[] = {
        { .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},
        { .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
@@ -398,13 +448,8 @@ static int tda827xa_sleep(struct dvb_frontend *fe)
                               .buf = buf, .len = sizeof(buf) };
 
        dprintk("%s:\n", __func__);
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
 
-       i2c_transfer(priv->i2c_adap, &msg, 1);
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 0);
+       tuner_transfer(fe, &msg, 1);
 
        if (priv->cfg && priv->cfg->sleep)
                priv->cfg->sleep(fe);
@@ -455,7 +500,7 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
                buf[1] = high ? 0 : 1;
                if (priv->cfg->config == 2)
                        buf[1] = high ? 1 : 0;
-               i2c_transfer(priv->i2c_adap, &msg, 1);
+               tuner_transfer(fe, &msg, 1);
                break;
        case 3: /* switch with GPIO of saa713x */
                if (fe->callback)
@@ -469,12 +514,13 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
                               struct dvb_frontend_parameters *params)
 {
        struct tda827x_priv *priv = fe->tuner_priv;
+       struct tda827xa_data *frequency_map = tda827xa_dvbt;
        u8 buf[11];
 
        struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
                               .buf = buf, .len = sizeof(buf) };
 
-       int i, tuner_freq, if_freq;
+       int i, tuner_freq, if_freq, rc;
        u32 N;
 
        dprintk("%s:\n", __func__);
@@ -495,56 +541,58 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
        }
        tuner_freq = params->frequency + if_freq;
 
+       if (fe->ops.info.type == FE_QAM) {
+               dprintk("%s select tda827xa_dvbc\n", __func__);
+               frequency_map = tda827xa_dvbc;
+       }
+
        i = 0;
-       while (tda827xa_dvbt[i].lomax < tuner_freq) {
-               if(tda827xa_dvbt[i + 1].lomax == 0)
+       while (frequency_map[i].lomax < tuner_freq) {
+               if (frequency_map[i + 1].lomax == 0)
                        break;
                i++;
        }
 
-       N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd;
+       N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd;
        buf[0] = 0;            // subaddress
        buf[1] = N >> 8;
        buf[2] = N & 0xff;
        buf[3] = 0;
        buf[4] = 0x16;
-       buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) +
-                       tda827xa_dvbt[i].sbs;
-       buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4);
+       buf[5] = (frequency_map[i].spd << 5) + (frequency_map[i].svco << 3) +
+                       frequency_map[i].sbs;
+       buf[6] = 0x4b + (frequency_map[i].gc3 << 4);
        buf[7] = 0x1c;
        buf[8] = 0x06;
        buf[9] = 0x24;
        buf[10] = 0x00;
        msg.len = 11;
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
-               printk("%s: could not write to tuner at addr: 0x%02x\n",
-                      __func__, priv->i2c_addr << 1);
-               return -EIO;
-       }
+       rc = tuner_transfer(fe, &msg, 1);
+       if (rc < 0)
+               goto err;
+
        buf[0] = 0x90;
        buf[1] = 0xff;
        buf[2] = 0x60;
        buf[3] = 0x00;
        buf[4] = 0x59;  // lpsel, for 6MHz + 2
        msg.len = 5;
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       rc = tuner_transfer(fe, &msg, 1);
+       if (rc < 0)
+               goto err;
 
        buf[0] = 0xa0;
        buf[1] = 0x40;
        msg.len = 2;
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       rc = tuner_transfer(fe, &msg, 1);
+       if (rc < 0)
+               goto err;
 
        msleep(11);
        msg.flags = I2C_M_RD;
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       rc = tuner_transfer(fe, &msg, 1);
+       if (rc < 0)
+               goto err;
        msg.flags = 0;
 
        buf[1] >>= 4;
@@ -553,49 +601,55 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
                tda827xa_lna_gain(fe, 0, NULL);
                buf[0] = 0x60;
                buf[1] = 0x0c;
-               if (fe->ops.i2c_gate_ctrl)
-                       fe->ops.i2c_gate_ctrl(fe, 1);
-               i2c_transfer(priv->i2c_adap, &msg, 1);
+               rc = tuner_transfer(fe, &msg, 1);
+               if (rc < 0)
+                       goto err;
        }
 
        buf[0] = 0xc0;
        buf[1] = 0x99;    // lpsel, for 6MHz + 2
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       rc = tuner_transfer(fe, &msg, 1);
+       if (rc < 0)
+               goto err;
 
        buf[0] = 0x60;
        buf[1] = 0x3c;
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       rc = tuner_transfer(fe, &msg, 1);
+       if (rc < 0)
+               goto err;
 
        /* correct CP value */
        buf[0] = 0x30;
-       buf[1] = 0x10 + tda827xa_dvbt[i].scr;
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       buf[1] = 0x10 + frequency_map[i].scr;
+       rc = tuner_transfer(fe, &msg, 1);
+       if (rc < 0)
+               goto err;
 
        msleep(163);
        buf[0] = 0xc0;
        buf[1] = 0x39;  // lpsel, for 6MHz + 2
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       rc = tuner_transfer(fe, &msg, 1);
+       if (rc < 0)
+               goto err;
 
        msleep(3);
        /* freeze AGC1 */
        buf[0] = 0x50;
-       buf[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4);
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       buf[1] = 0x4f + (frequency_map[i].gc3 << 4);
+       rc = tuner_transfer(fe, &msg, 1);
+       if (rc < 0)
+               goto err;
 
        priv->frequency = params->frequency;
        priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
 
+
        return 0;
+
+err:
+       printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n",
+              __func__, priv->i2c_addr << 1);
+       return rc;
 }
 
 
@@ -643,7 +697,7 @@ static int tda827xa_set_analog_params(struct dvb_frontend *fe,
        tuner_reg[9] = 0x20;
        tuner_reg[10] = 0x00;
        msg.len = 11;
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        tuner_reg[0] = 0x90;
        tuner_reg[1] = 0xff;
@@ -651,19 +705,19 @@ static int tda827xa_set_analog_params(struct dvb_frontend *fe,
        tuner_reg[3] = 0;
        tuner_reg[4] = 0x99 + (priv->lpsel << 1);
        msg.len = 5;
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        tuner_reg[0] = 0xa0;
        tuner_reg[1] = 0xc0;
        msg.len = 2;
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        tuner_reg[0] = 0x30;
        tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        msg.flags = I2C_M_RD;
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
        msg.flags = 0;
        tuner_reg[1] >>= 4;
        dprintk("AGC2 gain is: %d\n", tuner_reg[1]);
@@ -673,24 +727,24 @@ static int tda827xa_set_analog_params(struct dvb_frontend *fe,
        msleep(100);
        tuner_reg[0] = 0x60;
        tuner_reg[1] = 0x3c;
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        msleep(163);
        tuner_reg[0] = 0x50;
        tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        tuner_reg[0] = 0x80;
        tuner_reg[1] = 0x28;
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        tuner_reg[0] = 0xb0;
        tuner_reg[1] = 0x01;
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        tuner_reg[0] = 0xc0;
        tuner_reg[1] = 0x19 + (priv->lpsel << 1);
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 
        priv->frequency = params->frequency;
 
@@ -703,7 +757,7 @@ static void tda827xa_agcf(struct dvb_frontend *fe)
        unsigned char data[] = {0x80, 0x2c};
        struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0,
                              .buf = data, .len = 2};
-       i2c_transfer(priv->i2c_adap, &msg, 1);
+       tuner_transfer(fe, &msg, 1);
 }
 
 /* ------------------------------------------------------------------ */
@@ -792,16 +846,19 @@ static struct dvb_tuner_ops tda827xa_tuner_ops = {
 };
 
 static int tda827x_probe_version(struct dvb_frontend *fe)
-{      u8 data;
+{
+       u8 data;
+       int rc;
        struct tda827x_priv *priv = fe->tuner_priv;
        struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD,
                               .buf = &data, .len = 1 };
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
+
+       rc = tuner_transfer(fe, &msg, 1);
+
+       if (rc < 0) {
                printk("%s: could not read from tuner at addr: 0x%02x\n",
                       __func__, msg.addr << 1);
-               return -EIO;
+               return rc;
        }
        if ((data & 0x3c) == 0) {
                dprintk("tda827x tuner found\n");
index 4b8662edb7cb48d6b4e73833241bc8b88bacbef1..064d14c8d7b294fbf218b34d0477455868a3fc13 100644 (file)
@@ -22,7 +22,7 @@
 
 #include <linux/i2c.h>
 #include <linux/delay.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include "tuner-i2c.h"
 #include "tda8290.h"
 #include "tda827x.h"
@@ -566,8 +566,11 @@ static int tda829x_find_tuner(struct dvb_frontend *fe)
        u8 data;
        struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 };
 
-       if (NULL == analog_ops->i2c_gate_ctrl)
+       if (!analog_ops->i2c_gate_ctrl) {
+               printk(KERN_ERR "tda8290: no gate control were provided!\n");
+
                return -EINVAL;
+       }
 
        analog_ops->i2c_gate_ctrl(fe, 1);
 
@@ -615,11 +618,13 @@ static int tda829x_find_tuner(struct dvb_frontend *fe)
 
        if (ret != 1) {
                tuner_warn("tuner access failed!\n");
+               analog_ops->i2c_gate_ctrl(fe, 0);
                return -EREMOTEIO;
        }
 
        if ((data == 0x83) || (data == 0x84)) {
                priv->ver |= TDA18271;
+               tda829x_tda18271_config.config = priv->cfg.config;
                dvb_attach(tda18271_attach, fe, priv->tda827x_addr,
                           priv->i2c_props.adap, &tda829x_tda18271_config);
        } else {
index b23dadeecd0528ad74d55405948562981b24c234..60ed872f3d44681c4e85656dcf38b10fbd77105c 100644 (file)
@@ -9,7 +9,7 @@
 
 #include <linux/i2c.h>
 #include <linux/delay.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <media/tuner.h>
 #include "tuner-i2c.h"
 #include "tea5761.h"
index 1f5646334a8ffad1cffeb6183f796abb6c65f711..223a226d20a19e6b137a6316913fca8de46fd5c8 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <linux/i2c.h>
 #include <linux/delay.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include "tuner-i2c.h"
 #include "tea5767.h"
 
index 493ce93caf43538a2580854ab150648cf7dfb059..b54598550dc43da789cc7b6fdbc6acf3792aa5c8 100644 (file)
@@ -739,7 +739,10 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe,
        dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
                __func__, params->frequency);
 
-       priv->rf_mode = XC_RF_MODE_CABLE; /* Fix me: it could be air. */
+       /* Fix me: it could be air. */
+       priv->rf_mode = params->mode;
+       if (params->mode > XC_RF_MODE_CABLE)
+               priv->rf_mode = XC_RF_MODE_CABLE;
 
        /* params->frequency is in units of 62.5khz */
        priv->freq_hz = params->frequency * 62500;
@@ -970,8 +973,6 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
        case 1:
                /* new tuner instance */
                priv->bandwidth = BANDWIDTH_6_MHZ;
-               priv->if_khz = cfg->if_khz;
-
                fe->tuner_priv = priv;
                break;
        default:
@@ -980,6 +981,13 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
                break;
        }
 
+       if (priv->if_khz == 0) {
+               /* If the IF hasn't been set yet, use the value provided by
+                  the caller (occurs in hybrid devices where the analog
+                  call to xc5000_attach occurs before the digital side) */
+               priv->if_khz = cfg->if_khz;
+       }
+
        /* Check if firmware has been loaded. It is possible that another
           instance of the driver has loaded the firmware.
         */
index a8c6249c40999c22e8117f64ba3a967fb33088a7..9e578140074415361f966b4278b57c9fb5546cb3 100644 (file)
@@ -13,7 +13,7 @@ config DVB_B2C2_FLEXCOP
        select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE
        select DVB_ISL6421 if !DVB_FE_CUSTOMISE
        select DVB_CX24123 if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
        select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE
        help
          Support for the digital TV receiver chip made by B2C2 Inc. included in
index d9db066f9854f19a7572848b8834c0c1c29ee6a0..b97cf7208a182a409ac14cdff121a56d91a55f97 100644 (file)
@@ -2,7 +2,6 @@ b2c2-flexcop-objs = flexcop.o flexcop-fe-tuner.o flexcop-i2c.o \
        flexcop-sram.o flexcop-eeprom.o flexcop-misc.o flexcop-hw-filter.o
 obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o
 
-
 ifneq ($(CONFIG_DVB_B2C2_FLEXCOP_PCI),)
 b2c2-flexcop-objs += flexcop-dma.o
 endif
index 8ce06336e76f88372b83bc0297915b5c048238ca..3e1c472092ab238af0e26e1ef89917b220477aa7 100644 (file)
 
 /* Steal from usb.h */
 #undef err
-#define err(format,  arg...) printk(KERN_ERR     FC_LOG_PREFIX ": " format "\n" , ## arg)
+#define err(format, arg...) \
+       printk(KERN_ERR FC_LOG_PREFIX ": " format "\n" , ## arg)
 #undef info
-#define info(format, arg...) printk(KERN_INFO    FC_LOG_PREFIX ": " format "\n" , ## arg)
+#define info(format, arg...) \
+       printk(KERN_INFO FC_LOG_PREFIX ": " format "\n" , ## arg)
 #undef warn
-#define warn(format, arg...) printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg)
+#define warn(format, arg...) \
+       printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg)
 
 struct flexcop_dma {
        struct pci_dev *pdev;
@@ -91,16 +94,14 @@ struct flexcop_device {
        int fullts_streaming_state;
 
        /* bus specific callbacks */
-       flexcop_ibi_value (*read_ibi_reg)  (struct flexcop_device *, flexcop_ibi_register);
-       int               (*write_ibi_reg) (struct flexcop_device *, flexcop_ibi_register, flexcop_ibi_value);
-
-
-       int (*i2c_request) (struct flexcop_i2c_adapter*,
+       flexcop_ibi_value(*read_ibi_reg) (struct flexcop_device *,
+                       flexcop_ibi_register);
+       int (*write_ibi_reg) (struct flexcop_device *,
+                       flexcop_ibi_register, flexcop_ibi_value);
+       int (*i2c_request) (struct flexcop_i2c_adapter *,
                flexcop_access_op_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
-       int (*stream_control) (struct flexcop_device*, int);
-
+       int (*stream_control) (struct flexcop_device *, int);
        int (*get_mac_addr) (struct flexcop_device *fc, int extended);
-
        void *bus_specific;
 };
 
@@ -111,22 +112,28 @@ void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len);
 void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no);
 
 struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len);
-void flexcop_device_kfree(struct flexcop_device*);
+void flexcop_device_kfree(struct flexcop_device *);
 
-int  flexcop_device_initialize(struct flexcop_device*);
+int flexcop_device_initialize(struct flexcop_device *);
 void flexcop_device_exit(struct flexcop_device *fc);
-
 void flexcop_reset_block_300(struct flexcop_device *fc);
 
 /* from flexcop-dma.c */
-int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size);
+int flexcop_dma_allocate(struct pci_dev *pdev,
+               struct flexcop_dma *dma, u32 size);
 void flexcop_dma_free(struct flexcop_dma *dma);
 
-int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
-int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
-int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx);
-int flexcop_dma_xfer_control(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index, int onoff);
-int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles);
+int flexcop_dma_control_timer_irq(struct flexcop_device *fc,
+               flexcop_dma_index_t no, int onoff);
+int flexcop_dma_control_size_irq(struct flexcop_device *fc,
+               flexcop_dma_index_t no, int onoff);
+int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma,
+               flexcop_dma_index_t dma_idx);
+int flexcop_dma_xfer_control(struct flexcop_device *fc,
+               flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index,
+               int onoff);
+int flexcop_dma_config_timer(struct flexcop_device *fc,
+               flexcop_dma_index_t dma_idx, u8 cycles);
 
 /* from flexcop-eeprom.c */
 /* the PCI part uses this call to get the MAC address, the USB part has its own */
@@ -141,13 +148,15 @@ int flexcop_i2c_request(struct flexcop_i2c_adapter*, flexcop_access_op_t,
        u8 chipaddr, u8 addr, u8 *buf, u16 len);
 
 /* from flexcop-sram.c */
-int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target);
+int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest,
+       flexcop_sram_dest_target_t target);
 void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s);
-void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill);
+void flexcop_sram_ctrl(struct flexcop_device *fc,
+               int usb_wan, int sramdma, int maximumfill);
 
 /* global prototypes for the flexcop-chip */
 /* from flexcop-fe-tuner.c */
-int flexcop_frontend_init(struct flexcop_device *card);
+int flexcop_frontend_init(struct flexcop_device *fc);
 void flexcop_frontend_exit(struct flexcop_device *fc);
 
 /* from flexcop-i2c.c */
@@ -159,11 +168,14 @@ int flexcop_sram_init(struct flexcop_device *fc);
 
 /* from flexcop-misc.c */
 void flexcop_determine_revision(struct flexcop_device *fc);
-void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const char *suffix);
-void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num);
+void flexcop_device_name(struct flexcop_device *fc,
+               const char *prefix, const char *suffix);
+void flexcop_dump_reg(struct flexcop_device *fc,
+               flexcop_ibi_register reg, int num);
 
 /* from flexcop-hw-filter.c */
-int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff);
+int flexcop_pid_feed_control(struct flexcop_device *fc,
+               struct dvb_demux_feed *dvbdmxfeed, int onoff);
 void flexcop_hw_filter_init(struct flexcop_device *fc);
 
 void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff);
index 26f0011a507813a0564b741ba7040a7c579fe8fc..2881e0d956ad31ab5411c60b6a014925423ac4b0 100644 (file)
@@ -1,13 +1,12 @@
 /*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
- * flexcop-dma.c - methods for configuring and controlling the DMA of the FlexCop.
- *
- * see flexcop.c for copyright information.
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-dma.c - configuring and controlling the DMA of the FlexCop
+ * see flexcop.c for copyright information
  */
 #include "flexcop.h"
 
-int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size)
+int flexcop_dma_allocate(struct pci_dev *pdev,
+               struct flexcop_dma *dma, u32 size)
 {
        u8 *tcpu;
        dma_addr_t tdma = 0;
@@ -32,7 +31,8 @@ EXPORT_SYMBOL(flexcop_dma_allocate);
 
 void flexcop_dma_free(struct flexcop_dma *dma)
 {
-       pci_free_consistent(dma->pdev, dma->size*2,dma->cpu_addr0, dma->dma_addr0);
+       pci_free_consistent(dma->pdev, dma->size*2,
+                       dma->cpu_addr0, dma->dma_addr0);
        memset(dma,0,sizeof(struct flexcop_dma));
 }
 EXPORT_SYMBOL(flexcop_dma_free);
@@ -44,8 +44,8 @@ int flexcop_dma_config(struct flexcop_device *fc,
        flexcop_ibi_value v0x0,v0x4,v0xc;
        v0x0.raw = v0x4.raw = v0xc.raw = 0;
 
-       v0x0.dma_0x0.dma_address0        = dma->dma_addr0 >> 2;
-       v0xc.dma_0xc.dma_address1        = dma->dma_addr1 >> 2;
+       v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2;
+       v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2;
        v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
 
        if ((dma_idx & FC_DMA_1) == dma_idx) {
@@ -57,7 +57,8 @@ int flexcop_dma_config(struct flexcop_device *fc,
                fc->write_ibi_reg(fc,dma2_014,v0x4);
                fc->write_ibi_reg(fc,dma2_01c,v0xc);
        } else {
-               err("either DMA1 or DMA2 can be configured at the within one flexcop_dma_config call.");
+               err("either DMA1 or DMA2 can be configured within one "
+                       "flexcop_dma_config call.");
                return -EINVAL;
        }
 
@@ -81,7 +82,8 @@ int flexcop_dma_xfer_control(struct flexcop_device *fc,
                r0x0 = dma2_010;
                r0xc = dma2_01c;
        } else {
-               err("either transfer DMA1 or DMA2 can be started within one flexcop_dma_xfer_control call.");
+               err("either transfer DMA1 or DMA2 can be started within one "
+                       "flexcop_dma_xfer_control call.");
                return -EINVAL;
        }
 
@@ -154,8 +156,7 @@ EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
 
 /* 1 cycles = 1.97 msec */
 int flexcop_dma_config_timer(struct flexcop_device *fc,
-               flexcop_dma_index_t dma_idx,
-               u8 cycles)
+               flexcop_dma_index_t dma_idx, u8 cycles)
 {
        flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
        flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
index 8a8ae8a3e6ba6954717739ef59487d8804698297..a25373a9bd8480b48077f0acd8d43961cc0ab969 100644 (file)
@@ -1,9 +1,7 @@
 /*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
- * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading is used)
- *
- * see flexcop.c for copyright information.
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading)
+ * see flexcop.c for copyright information
  */
 #include "flexcop.h"
 
@@ -14,17 +12,17 @@ static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
        return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len);
 }
 
-static int eeprom_lrc_write(struct adapter *adapter, u32 addr, u32 len, u8 *wbuf, u8 *rbuf, int retries)
+static int eeprom_lrc_write(struct adapter *adapter, u32 addr,
+               u32 len, u8 *wbuf, u8 *rbuf, int retries)
 {
-       int i;
+int i;
 
-       for (i = 0; i < retries; i++) {
-               if (eeprom_write(adapter, addr, wbuf, len) == len) {
-                       if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1)
-                               return 1;
+for (i = 0; i < retries; i++) {
+       if (eeprom_write(adapter, addr, wbuf, len) == len) {
+               if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1)
+                       return 1;
                }
        }
-
        return 0;
 }
 
@@ -39,12 +37,10 @@ static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len)
                return 0;
 
        memcpy(wbuf, key, len);
-
        wbuf[16] = 0;
        wbuf[17] = 0;
        wbuf[18] = 0;
        wbuf[19] = calc_lrc(wbuf, 19);
-
        return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4);
 }
 
@@ -59,7 +55,6 @@ static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len)
                return 0;
 
        memcpy(key, buf, len);
-
        return 1;
 }
 
@@ -74,9 +69,7 @@ static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac)
                tmp[3] = mac[5];
                tmp[4] = mac[6];
                tmp[5] = mac[7];
-
        } else {
-
                tmp[0] = mac[0];
                tmp[1] = mac[1];
                tmp[2] = mac[2];
@@ -90,11 +83,11 @@ static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac)
 
        if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8)
                return 1;
-
        return 0;
 }
 
-static int flexcop_eeprom_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len)
+static int flexcop_eeprom_read(struct flexcop_device *fc,
+               u16 addr, u8 *buf, u16 len)
 {
        return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len);
 }
@@ -110,7 +103,8 @@ static u8 calc_lrc(u8 *buf, int len)
        return sum;
 }
 
-static int flexcop_eeprom_request(struct flexcop_device *fc, flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries)
+static int flexcop_eeprom_request(struct flexcop_device *fc,
+       flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries)
 {
        int i,ret = 0;
        u8 chipaddr =  0x50 | ((addr >> 8) & 3);
@@ -123,7 +117,8 @@ static int flexcop_eeprom_request(struct flexcop_device *fc, flexcop_access_op_t
        return ret;
 }
 
-static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len, int retries)
+static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr,
+               u8 *buf, u16 len, int retries)
 {
        int ret = flexcop_eeprom_request(fc, FC_READ, addr, buf, len, retries);
        if (ret == 0)
@@ -133,8 +128,7 @@ static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf,
 }
 
 /* JJ's comment about extended == 1: it is not presently used anywhere but was
- * added to the low-level functions for possible support of EUI64
- */
+ * added to the low-level functions for possible support of EUI64 */
 int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended)
 {
        u8 buf[8];
@@ -142,12 +136,9 @@ int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended)
 
        if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) {
                if (extended != 0) {
-                       err("TODO: extended (EUI64) MAC addresses aren't completely supported yet");
+                       err("TODO: extended (EUI64) MAC addresses aren't "
+                               "completely supported yet");
                        ret = -EINVAL;
-/*                     memcpy(fc->dvb_adapter.proposed_mac,buf,3);
-                       mac[3] = 0xfe;
-                       mac[4] = 0xff;
-                       memcpy(&fc->dvb_adapter.proposed_mac[3],&buf[5],3); */
                } else
                        memcpy(fc->dvb_adapter.proposed_mac,buf,6);
        }
index 5cded370854167b2d3db6ffec80e7914ad7437f1..f7afab5944cfc2395c8b30592dc9740da22325cc 100644 (file)
@@ -592,14 +592,14 @@ int flexcop_frontend_init(struct flexcop_device *fc)
                fc->fe_sleep = ops->sleep;
                ops->sleep = flexcop_sleep;
 
-               fc->dev_type = FC_SKY;
+               fc->dev_type = FC_SKY_REV26;
                goto fe_found;
        }
 
        /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
        fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
        if (fc->fe != NULL) {
-               fc->dev_type = FC_AIR_DVB;
+               fc->dev_type = FC_AIR_DVBT;
                fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
                goto fe_found;
        }
@@ -653,7 +653,7 @@ int flexcop_frontend_init(struct flexcop_device *fc)
                fc->fe_sleep                = ops->sleep;
                ops->sleep                  = flexcop_sleep;
 
-               fc->dev_type                = FC_SKY_OLD;
+               fc->dev_type                = FC_SKY_REV23;
                goto fe_found;
        }
 
index 451974ba32f37adb656356291146716c8358d819..77e45475f4c7d1be3d9f2bbf38a87e27a8d5e440 100644 (file)
@@ -1,33 +1,30 @@
 /*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
- * flexcop-hw-filter.c - pid and mac address filtering and corresponding control functions.
- *
- * see flexcop.c for copyright information.
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-hw-filter.c - pid and mac address filtering and control functions
+ * see flexcop.c for copyright information
  */
 #include "flexcop.h"
 
 static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff)
 {
-       flexcop_set_ibi_value(ctrl_208,Rcv_Data_sig,onoff);
-
-       deb_ts("rcv_data is now: '%s'\n",onoff ? "on" : "off");
+       flexcop_set_ibi_value(ctrl_208, Rcv_Data_sig, onoff);
+       deb_ts("rcv_data is now: '%s'\n", onoff ? "on" : "off");
 }
 
 void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
 {
-       flexcop_set_ibi_value(ctrl_208,SMC_Enable_sig,onoff);
+       flexcop_set_ibi_value(ctrl_208, SMC_Enable_sig, onoff);
 }
 
 static void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff)
 {
-       flexcop_set_ibi_value(ctrl_208,Null_filter_sig,onoff);
+       flexcop_set_ibi_value(ctrl_208, Null_filter_sig, onoff);
 }
 
 void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6])
 {
-       flexcop_ibi_value v418,v41c;
-       v41c = fc->read_ibi_reg(fc,mac_address_41c);
+       flexcop_ibi_value v418, v41c;
+       v41c = fc->read_ibi_reg(fc, mac_address_41c);
 
        v418.mac_address_418.MAC1 = mac[0];
        v418.mac_address_418.MAC2 = mac[1];
@@ -36,27 +33,28 @@ void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6])
        v41c.mac_address_41c.MAC7 = mac[4];
        v41c.mac_address_41c.MAC8 = mac[5];
 
-       fc->write_ibi_reg(fc,mac_address_418,v418);
-       fc->write_ibi_reg(fc,mac_address_41c,v41c);
+       fc->write_ibi_reg(fc, mac_address_418, v418);
+       fc->write_ibi_reg(fc, mac_address_41c, v41c);
 }
 
 void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff)
 {
-       flexcop_set_ibi_value(ctrl_208,MAC_filter_Mode_sig,onoff);
+       flexcop_set_ibi_value(ctrl_208, MAC_filter_Mode_sig, onoff);
 }
 
-static void flexcop_pid_group_filter(struct flexcop_device *fc, u16 pid, u16 mask)
+static void flexcop_pid_group_filter(struct flexcop_device *fc,
+               u16 pid, u16 mask)
 {
        /* index_reg_310.extra_index_reg need to 0 or 7 to work */
        flexcop_ibi_value v30c;
        v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid;
        v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask;
-       fc->write_ibi_reg(fc,pid_filter_30c,v30c);
+       fc->write_ibi_reg(fc, pid_filter_30c, v30c);
 }
 
 static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff)
 {
-       flexcop_set_ibi_value(ctrl_208,Mask_filter_sig,onoff);
+       flexcop_set_ibi_value(ctrl_208, Mask_filter_sig, onoff);
 }
 
 /* this fancy define reduces the code size of the quite similar PID controlling of
@@ -65,91 +63,112 @@ static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff)
 
 #define pid_ctrl(vregname,field,enablefield,trans_field,transval) \
        flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \
-                                         v208 = fc->read_ibi_reg(fc, ctrl_208); \
-\
-       vpid.vregname.field = onoff ? pid : 0x1fff; \
-       vpid.vregname.trans_field = transval; \
-       v208.ctrl_208.enablefield = onoff; \
-\
-       fc->write_ibi_reg(fc,vregname,vpid); \
-       fc->write_ibi_reg(fc,ctrl_208,v208);
+v208 = fc->read_ibi_reg(fc, ctrl_208); \
+vpid.vregname.field = onoff ? pid : 0x1fff; \
+vpid.vregname.trans_field = transval; \
+v208.ctrl_208.enablefield = onoff; \
+fc->write_ibi_reg(fc, vregname, vpid); \
+fc->write_ibi_reg(fc, ctrl_208, v208);
 
-static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc,
+               u16 pid, int onoff)
 {
-       pid_ctrl(pid_filter_300,Stream1_PID,Stream1_filter_sig,Stream1_trans,0);
+       pid_ctrl(pid_filter_300, Stream1_PID, Stream1_filter_sig,
+                       Stream1_trans, 0);
 }
 
-static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc,
+               u16 pid, int onoff)
 {
-       pid_ctrl(pid_filter_300,Stream2_PID,Stream2_filter_sig,Stream2_trans,0);
+       pid_ctrl(pid_filter_300, Stream2_PID, Stream2_filter_sig,
+                       Stream2_trans, 0);
 }
 
-static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc,
+               u16 pid, int onoff)
 {
-       pid_ctrl(pid_filter_304,PCR_PID,PCR_filter_sig,PCR_trans,0);
+       pid_ctrl(pid_filter_304, PCR_PID, PCR_filter_sig, PCR_trans, 0);
 }
 
-static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc,
+               u16 pid, int onoff)
 {
-       pid_ctrl(pid_filter_304,PMT_PID,PMT_filter_sig,PMT_trans,0);
+       pid_ctrl(pid_filter_304, PMT_PID, PMT_filter_sig, PMT_trans, 0);
 }
 
-static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc,
+               u16 pid, int onoff)
 {
-       pid_ctrl(pid_filter_308,EMM_PID,EMM_filter_sig,EMM_trans,0);
+       pid_ctrl(pid_filter_308, EMM_PID, EMM_filter_sig, EMM_trans, 0);
 }
 
-static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc,
+               u16 pid, int onoff)
 {
-       pid_ctrl(pid_filter_308,ECM_PID,ECM_filter_sig,ECM_trans,0);
+       pid_ctrl(pid_filter_308, ECM_PID, ECM_filter_sig, ECM_trans, 0);
 }
 
-static void flexcop_pid_control(struct flexcop_device *fc, int index, u16 pid,int onoff)
+static void flexcop_pid_control(struct flexcop_device *fc,
+               int index, u16 pid, int onoff)
 {
        if (pid == 0x2000)
                return;
 
-       deb_ts("setting pid: %5d %04x at index %d '%s'\n",pid,pid,index,onoff ? "on" : "off");
+       deb_ts("setting pid: %5d %04x at index %d '%s'\n",
+                       pid, pid, index, onoff ? "on" : "off");
 
        /* We could use bit magic here to reduce source code size.
         * I decided against it, but to use the real register names */
        switch (index) {
-               case 0: flexcop_pid_Stream1_PID_ctrl(fc,pid,onoff); break;
-               case 1: flexcop_pid_Stream2_PID_ctrl(fc,pid,onoff); break;
-               case 2: flexcop_pid_PCR_PID_ctrl(fc,pid,onoff); break;
-               case 3: flexcop_pid_PMT_PID_ctrl(fc,pid,onoff); break;
-               case 4: flexcop_pid_EMM_PID_ctrl(fc,pid,onoff); break;
-               case 5: flexcop_pid_ECM_PID_ctrl(fc,pid,onoff); break;
-               default:
-                       if (fc->has_32_hw_pid_filter && index < 38) {
-                               flexcop_ibi_value vpid,vid;
-
-                               /* set the index */
-                               vid = fc->read_ibi_reg(fc,index_reg_310);
-                               vid.index_reg_310.index_reg = index - 6;
-                               fc->write_ibi_reg(fc,index_reg_310, vid);
-
-                               vpid = fc->read_ibi_reg(fc,pid_n_reg_314);
-                               vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff;
-                               vpid.pid_n_reg_314.PID_enable_bit = onoff;
-                               fc->write_ibi_reg(fc,pid_n_reg_314, vpid);
-                       }
-                       break;
+       case 0:
+               flexcop_pid_Stream1_PID_ctrl(fc, pid, onoff);
+               break;
+       case 1:
+               flexcop_pid_Stream2_PID_ctrl(fc, pid, onoff);
+               break;
+       case 2:
+               flexcop_pid_PCR_PID_ctrl(fc, pid, onoff);
+               break;
+       case 3:
+               flexcop_pid_PMT_PID_ctrl(fc, pid, onoff);
+               break;
+       case 4:
+               flexcop_pid_EMM_PID_ctrl(fc, pid, onoff);
+               break;
+       case 5:
+               flexcop_pid_ECM_PID_ctrl(fc, pid, onoff);
+               break;
+       default:
+               if (fc->has_32_hw_pid_filter && index < 38) {
+                       flexcop_ibi_value vpid, vid;
+
+                       /* set the index */
+                       vid = fc->read_ibi_reg(fc, index_reg_310);
+                       vid.index_reg_310.index_reg = index - 6;
+                       fc->write_ibi_reg(fc, index_reg_310, vid);
+
+                       vpid = fc->read_ibi_reg(fc, pid_n_reg_314);
+                       vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff;
+                       vpid.pid_n_reg_314.PID_enable_bit = onoff;
+                       fc->write_ibi_reg(fc, pid_n_reg_314, vpid);
+               }
+               break;
        }
 }
 
-static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc,int onoff)
+static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc, int onoff)
 {
        if (fc->fullts_streaming_state != onoff) {
                deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling");
                flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff));
-               flexcop_pid_group_filter_ctrl(fc,onoff);
+               flexcop_pid_group_filter_ctrl(fc, onoff);
                fc->fullts_streaming_state = onoff;
        }
        return 0;
 }
 
-int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff)
+int flexcop_pid_feed_control(struct flexcop_device *fc,
+               struct dvb_demux_feed *dvbdmxfeed, int onoff)
 {
        int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32;
 
@@ -164,24 +183,25 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d
         *   - or the requested pid is 0x2000 */
 
        if (!fc->pid_filtering && fc->feedcount == onoff)
-               flexcop_toggle_fullts_streaming(fc,onoff);
+               flexcop_toggle_fullts_streaming(fc, onoff);
 
        if (fc->pid_filtering) {
-               flexcop_pid_control(fc,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
+               flexcop_pid_control \
+                       (fc, dvbdmxfeed->index, dvbdmxfeed->pid, onoff);
 
                if (fc->extra_feedcount > 0)
-                       flexcop_toggle_fullts_streaming(fc,1);
+                       flexcop_toggle_fullts_streaming(fc, 1);
                else if (dvbdmxfeed->pid == 0x2000)
-                       flexcop_toggle_fullts_streaming(fc,onoff);
+                       flexcop_toggle_fullts_streaming(fc, onoff);
                else
-                       flexcop_toggle_fullts_streaming(fc,0);
+                       flexcop_toggle_fullts_streaming(fc, 0);
        }
 
        /* if it was the first or last feed request change the stream-status */
        if (fc->feedcount == onoff) {
-               flexcop_rcv_data_ctrl(fc,onoff);
+               flexcop_rcv_data_ctrl(fc, onoff);
                if (fc->stream_control) /* device specific stream control */
-                       fc->stream_control(fc,onoff);
+                       fc->stream_control(fc, onoff);
 
                /* feeding stopped -> reset the flexcop filter*/
                if (onoff == 0) {
@@ -189,7 +209,6 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d
                        flexcop_hw_filter_init(fc);
                }
        }
-
        return 0;
 }
 EXPORT_SYMBOL(flexcop_pid_feed_control);
@@ -199,15 +218,15 @@ void flexcop_hw_filter_init(struct flexcop_device *fc)
        int i;
        flexcop_ibi_value v;
        for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++)
-               flexcop_pid_control(fc,i,0x1fff,0);
+               flexcop_pid_control(fc, i, 0x1fff, 0);
 
        flexcop_pid_group_filter(fc, 0, 0x1fe0);
-       flexcop_pid_group_filter_ctrl(fc,0);
+       flexcop_pid_group_filter_ctrl(fc, 0);
 
-       v = fc->read_ibi_reg(fc,pid_filter_308);
+       v = fc->read_ibi_reg(fc, pid_filter_308);
        v.pid_filter_308.EMM_filter_4 = 1;
        v.pid_filter_308.EMM_filter_6 = 0;
-       fc->write_ibi_reg(fc,pid_filter_308,v);
+       fc->write_ibi_reg(fc, pid_filter_308, v);
 
        flexcop_null_filter_ctrl(fc, 1);
 }
index f13783f08f0f4e09bd054c38806792e1289af3a4..e2bed5076485635b7338fbde2b3f3e1f9aeb0f7b 100644 (file)
@@ -1,17 +1,14 @@
 /*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
  * flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization
- *
- * see flexcop.c for copyright information.
+ * see flexcop.c for copyright information
  */
 #include "flexcop.h"
 
 #define FC_MAX_I2C_RETRIES 100000
 
-/* #define DUMP_I2C_MESSAGES */
-
-static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100)
+static int flexcop_i2c_operation(struct flexcop_device *fc,
+               flexcop_ibi_value *r100)
 {
        int i;
        flexcop_ibi_value r;
@@ -26,7 +23,7 @@ static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r
                r = fc->read_ibi_reg(fc, tw_sm_c_100);
 
                if (!r.tw_sm_c_100.no_base_addr_ack_error) {
-                       if (r.tw_sm_c_100.st_done) {  /* && !r.tw_sm_c_100.working_start */
+                       if (r.tw_sm_c_100.st_done) {
                                *r100 = r;
                                deb_i2c("i2c success\n");
                                return 0;
@@ -36,17 +33,31 @@ static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r
                        return -EREMOTEIO;
                }
        }
-       deb_i2c("tried %d times i2c operation, never finished or too many ack errors.\n",i);
+       deb_i2c("tried %d times i2c operation, "
+                       "never finished or too many ack errors.\n", i);
        return -EREMOTEIO;
 }
 
 static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c,
-       flexcop_ibi_value r100, u8 *buf)
+               flexcop_ibi_value r100, u8 *buf)
 {
        flexcop_ibi_value r104;
-       int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */
+       int len = r100.tw_sm_c_100.total_bytes,
+               /* remember total_bytes is buflen-1 */
                ret;
 
+       /* work-around to have CableStar2 and SkyStar2 rev 2.7 work
+        * correctly:
+        *
+        * the ITD1000 is behind an i2c-gate which closes automatically
+        * after an i2c-transaction the STV0297 needs 2 consecutive reads
+        * one with no_base_addr = 0 and one with 1
+        *
+        * those two work-arounds are conflictin: we check for the card
+        * type, it is set when probing the ITD1000 */
+       if (i2c->fc->dev_type == FC_SKY_REV27)
+               r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
+
        ret = flexcop_i2c_operation(i2c->fc, &r100);
        if (ret != 0) {
                deb_i2c("Retrying operation\n");
@@ -69,11 +80,11 @@ static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c,
                if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg;
                if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg;
        }
-
        return 0;
 }
 
-static int flexcop_i2c_write4(struct flexcop_device *fc, flexcop_ibi_value r100, u8 *buf)
+static int flexcop_i2c_write4(struct flexcop_device *fc,
+               flexcop_ibi_value r100, u8 *buf)
 {
        flexcop_ibi_value r104;
        int len = r100.tw_sm_c_100.total_bytes; /* remember total_bytes is buflen-1 */
@@ -81,7 +92,6 @@ static int flexcop_i2c_write4(struct flexcop_device *fc, flexcop_ibi_value r100,
 
        /* there is at least one byte, otherwise we wouldn't be here */
        r100.tw_sm_c_100.data1_reg = buf[0];
-
        r104.tw_sm_c_104.data2_reg = len > 0 ? buf[1] : 0;
        r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0;
        r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0;
@@ -94,7 +104,7 @@ static int flexcop_i2c_write4(struct flexcop_device *fc, flexcop_ibi_value r100,
 }
 
 int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c,
-       flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
+               flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
 {
        int ret;
 
@@ -117,7 +127,6 @@ int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c,
                printk("rd(");
        else
                printk("wr(");
-
        printk("%02x): %02x ", chipaddr, addr);
 #endif
 
@@ -163,7 +172,8 @@ int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c,
 EXPORT_SYMBOL(flexcop_i2c_request);
 
 /* master xfer callback for demodulator */
-static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
+static int flexcop_master_xfer(struct i2c_adapter *i2c_adap,
+               struct i2c_msg msgs[], int num)
 {
        struct flexcop_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap);
        int i, ret = 0;
@@ -182,12 +192,13 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs
                /* reading */
                if (i+1 < num && (msgs[i+1].flags == I2C_M_RD)) {
                        ret = i2c->fc->i2c_request(i2c, FC_READ, msgs[i].addr,
-                               msgs[i].buf[0], msgs[i+1].buf, msgs[i+1].len);
+                                       msgs[i].buf[0], msgs[i+1].buf,
+                                       msgs[i+1].len);
                        i++; /* skip the following message */
                } else /* writing */
                        ret = i2c->fc->i2c_request(i2c, FC_WRITE, msgs[i].addr,
-                               msgs[i].buf[0], &msgs[i].buf[1],
-                               msgs[i].len - 1);
+                                       msgs[i].buf[0], &msgs[i].buf[1],
+                                       msgs[i].len - 1);
                if (ret < 0) {
                        err("i2c master_xfer failed");
                        break;
@@ -214,23 +225,21 @@ static struct i2c_algorithm flexcop_algo = {
 int flexcop_i2c_init(struct flexcop_device *fc)
 {
        int ret;
-
        mutex_init(&fc->i2c_mutex);
 
        fc->fc_i2c_adap[0].fc = fc;
        fc->fc_i2c_adap[1].fc = fc;
        fc->fc_i2c_adap[2].fc = fc;
-
        fc->fc_i2c_adap[0].port = FC_I2C_PORT_DEMOD;
        fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM;
        fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER;
 
        strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod",
-               sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
+                       sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
        strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom",
-               sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
+                       sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
        strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner",
-               sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
+                       sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
 
        i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]);
        i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
@@ -268,7 +277,6 @@ adap_2_failed:
        i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
 adap_1_failed:
        i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
-
        return ret;
 }
 
@@ -279,6 +287,5 @@ void flexcop_i2c_exit(struct flexcop_device *fc)
                i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
                i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
        }
-
        fc->init_state &= ~FC_STATE_I2C_INIT;
 }
index 93d20e56f909e17c243c8348e81e01047937e213..e56627d2f0f42ddeaafdd38a5730fce0b192e527 100644 (file)
@@ -1,9 +1,7 @@
 /*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
- * flexcop-misc.c - miscellaneous functions.
- *
- * see flexcop.c for copyright information.
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-misc.c - miscellaneous functions
+ * see flexcop.c for copyright information
  */
 #include "flexcop.h"
 
@@ -12,39 +10,43 @@ void flexcop_determine_revision(struct flexcop_device *fc)
        flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204);
 
        switch (v.misc_204.Rev_N_sig_revision_hi) {
-               case 0x2:
-                       deb_info("found a FlexCopII.\n");
-                       fc->rev = FLEXCOP_II;
-                       break;
-               case 0x3:
-                       deb_info("found a FlexCopIIb.\n");
-                       fc->rev = FLEXCOP_IIB;
-                       break;
-               case 0x0:
-                       deb_info("found a FlexCopIII.\n");
-                       fc->rev = FLEXCOP_III;
-                       break;
-               default:
-                       err("unkown FlexCop Revision: %x. Please report the linux-dvb@linuxtv.org.",v.misc_204.Rev_N_sig_revision_hi);
-                       break;
+       case 0x2:
+               deb_info("found a FlexCopII.\n");
+               fc->rev = FLEXCOP_II;
+               break;
+       case 0x3:
+               deb_info("found a FlexCopIIb.\n");
+               fc->rev = FLEXCOP_IIB;
+               break;
+       case 0x0:
+               deb_info("found a FlexCopIII.\n");
+               fc->rev = FLEXCOP_III;
+               break;
+       default:
+               err("unknown FlexCop Revision: %x. Please report this to "
+                               "linux-dvb@linuxtv.org.",
+                               v.misc_204.Rev_N_sig_revision_hi);
+               break;
        }
 
        if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps))
-               deb_info("this FlexCop has the additional 32 hardware pid filter.\n");
+               deb_info("this FlexCop has "
+                               "the additional 32 hardware pid filter.\n");
        else
-               deb_info("this FlexCop has only the 6 basic main hardware pid filter.\n");
+               deb_info("this FlexCop has "
+                               "the 6 basic main hardware pid filter.\n");
        /* bus parts have to decide if hw pid filtering is used or not. */
 }
 
 static const char *flexcop_revision_names[] = {
-       "Unkown chip",
+       "Unknown chip",
        "FlexCopII",
        "FlexCopIIb",
        "FlexCopIII",
 };
 
 static const char *flexcop_device_names[] = {
-       "Unkown device",
+       "Unknown device",
        "Air2PC/AirStar 2 DVB-T",
        "Air2PC/AirStar 2 ATSC 1st generation",
        "Air2PC/AirStar 2 ATSC 2nd generation",
@@ -61,21 +63,23 @@ static const char *flexcop_bus_names[] = {
        "PCI",
 };
 
-void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const
-               char *suffix)
+void flexcop_device_name(struct flexcop_device *fc,
+               const char *prefix, const char *suffix)
 {
-       info("%s '%s' at the '%s' bus controlled by a '%s' %s",prefix,
-                       flexcop_device_names[fc->dev_type],flexcop_bus_names[fc->bus_type],
-                       flexcop_revision_names[fc->rev],suffix);
+       info("%s '%s' at the '%s' bus controlled by a '%s' %s",
+                       prefix, flexcop_device_names[fc->dev_type],
+                       flexcop_bus_names[fc->bus_type],
+                       flexcop_revision_names[fc->rev], suffix);
 }
 
-void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num)
+void flexcop_dump_reg(struct flexcop_device *fc,
+               flexcop_ibi_register reg, int num)
 {
        flexcop_ibi_value v;
        int i;
        for (i = 0; i < num; i++) {
-               v = fc->read_ibi_reg(fc,reg+4*i);
-               deb_rdump("0x%03x: %08x, ",reg+4*i, v.raw);
+               v = fc->read_ibi_reg(fc, reg+4*i);
+               deb_rdump("0x%03x: %08x, ", reg+4*i, v.raw);
        }
        deb_rdump("\n");
 }
index 76e37fd96bb6a3995e1ec301b36d166f507e54d3..227c0200b70a5bd04fb15be61b4150c77b5ae70a 100644 (file)
@@ -1,9 +1,7 @@
 /*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
- * flexcop-pci.c - covers the PCI part including DMA transfers.
- *
- * see flexcop.c for copyright information.
+ * Linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-pci.c - covers the PCI part including DMA transfers
+ * see flexcop.c for copyright information
  */
 
 #define FC_LOG_PREFIX "flexcop-pci"
@@ -11,7 +9,8 @@
 
 static int enable_pid_filtering = 1;
 module_param(enable_pid_filtering, int, 0444);
-MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1");
+MODULE_PARM_DESC(enable_pid_filtering,
+       "enable hardware pid filtering: supported values: 0 (fullts), 1");
 
 static int irq_chk_intv = 100;
 module_param(irq_chk_intv, int, 0644);
@@ -26,17 +25,17 @@ MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ streaming watchdog.");
 #define DEBSTATUS " (debugging is not enabled)"
 #endif
 
-#define deb_info(args...)  dprintk(0x01,args)
-#define deb_reg(args...)   dprintk(0x02,args)
-#define deb_ts(args...)    dprintk(0x04,args)
-#define deb_irq(args...)   dprintk(0x08,args)
-#define deb_chk(args...)   dprintk(0x10,args)
+#define deb_info(args...) dprintk(0x01, args)
+#define deb_reg(args...) dprintk(0x02, args)
+#define deb_ts(args...) dprintk(0x04, args)
+#define deb_irq(args...) dprintk(0x08, args)
+#define deb_chk(args...) dprintk(0x10, args)
 
 static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug,
        "set debug level (1=info,2=regs,4=TS,8=irqdma,16=check (|-able))."
-        DEBSTATUS);
+       DEBSTATUS);
 
 #define DRIVER_VERSION "0.1"
 #define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver"
@@ -51,30 +50,30 @@ struct flexcop_pci {
 
        void __iomem *io_mem;
        u32 irq;
-/* buffersize (at least for DMA1, need to be % 188 == 0,
- * this logic is required */
+       /* buffersize (at least for DMA1, need to be % 188 == 0,
       * this logic is required */
 #define FC_DEFAULT_DMA1_BUFSIZE (1280 * 188)
 #define FC_DEFAULT_DMA2_BUFSIZE (10 * 188)
        struct flexcop_dma dma[2];
 
        int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */
-       u32 last_dma1_cur_pos; /* position of the pointer last time the timer/packet irq occured */
+       u32 last_dma1_cur_pos;
+       /* position of the pointer last time the timer/packet irq occured */
        int count;
        int count_prev;
        int stream_problem;
 
        spinlock_t irq_lock;
-
        unsigned long last_irq;
 
        struct delayed_work irq_check_work;
-
        struct flexcop_device *fc_dev;
 };
 
-static int lastwreg,lastwval,lastrreg,lastrval;
+static int lastwreg, lastwval, lastrreg, lastrval;
 
-static flexcop_ibi_value flexcop_pci_read_ibi_reg (struct flexcop_device *fc, flexcop_ibi_register r)
+static flexcop_ibi_value flexcop_pci_read_ibi_reg(struct flexcop_device *fc,
+               flexcop_ibi_register r)
 {
        struct flexcop_pci *fc_pci = fc->bus_specific;
        flexcop_ibi_value v;
@@ -82,19 +81,20 @@ static flexcop_ibi_value flexcop_pci_read_ibi_reg (struct flexcop_device *fc, fl
 
        if (lastrreg != r || lastrval != v.raw) {
                lastrreg = r; lastrval = v.raw;
-               deb_reg("new rd: %3x: %08x\n",r,v.raw);
+               deb_reg("new rd: %3x: %08x\n", r, v.raw);
        }
 
        return v;
 }
 
-static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register r, flexcop_ibi_value v)
+static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc,
+               flexcop_ibi_register r, flexcop_ibi_value v)
 {
        struct flexcop_pci *fc_pci = fc->bus_specific;
 
        if (lastwreg != r || lastwval != v.raw) {
                lastwreg = r; lastwval = v.raw;
-               deb_reg("new wr: %3x: %08x\n",r,v.raw);
+               deb_reg("new wr: %3x: %08x\n", r, v.raw);
        }
 
        writel(v.raw, fc_pci->io_mem + r);
@@ -113,15 +113,16 @@ static void flexcop_pci_irq_check_work(struct work_struct *work)
                        deb_chk("no IRQ since the last check\n");
                        if (fc_pci->stream_problem++ == 3) {
                                struct dvb_demux_feed *feed;
+                               deb_info("flexcop-pci: stream problem, resetting pid filter\n");
 
                                spin_lock_irq(&fc->demux.lock);
                                list_for_each_entry(feed, &fc->demux.feed_list,
-                                       list_head) {
+                                               list_head) {
                                        flexcop_pid_feed_control(fc, feed, 0);
                                }
 
                                list_for_each_entry(feed, &fc->demux.feed_list,
-                                       list_head) {
+                                               list_head) {
                                        flexcop_pid_feed_control(fc, feed, 1);
                                }
                                spin_unlock_irq(&fc->demux.lock);
@@ -149,11 +150,10 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id)
        flexcop_ibi_value v;
        irqreturn_t ret = IRQ_HANDLED;
 
-       spin_lock_irqsave(&fc_pci->irq_lock,flags);
-
-       v = fc->read_ibi_reg(fc,irq_20c);
+       spin_lock_irqsave(&fc_pci->irq_lock, flags);
+       v = fc->read_ibi_reg(fc, irq_20c);
 
-   /* errors */
+       /* errors */
        if (v.irq_20c.Data_receiver_error)
                deb_chk("data receiver error\n");
        if (v.irq_20c.Continuity_error_flag)
@@ -164,24 +164,29 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id)
                deb_chk("Transport error\n");
 
        if ((fc_pci->count % 1000) == 0)
-               deb_chk("%d valid irq took place so far\n",fc_pci->count);
+               deb_chk("%d valid irq took place so far\n", fc_pci->count);
 
        if (v.irq_20c.DMA1_IRQ_Status == 1) {
                if (fc_pci->active_dma1_addr == 0)
-                       flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr0,fc_pci->dma[0].size / 188);
+                       flexcop_pass_dmx_packets(fc_pci->fc_dev,
+                                       fc_pci->dma[0].cpu_addr0,
+                                       fc_pci->dma[0].size / 188);
                else
-                       flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr1,fc_pci->dma[0].size / 188);
+                       flexcop_pass_dmx_packets(fc_pci->fc_dev,
+                                       fc_pci->dma[0].cpu_addr1,
+                                       fc_pci->dma[0].size / 188);
 
                deb_irq("page change to page: %d\n",!fc_pci->active_dma1_addr);
                fc_pci->active_dma1_addr = !fc_pci->active_dma1_addr;
-       } else if (v.irq_20c.DMA1_Timer_Status == 1) {
                /* for the timer IRQ we only can use buffer dmx feeding, because we don't have
                 * complete TS packets when reading from the DMA memory */
+       } else if (v.irq_20c.DMA1_Timer_Status == 1) {
                dma_addr_t cur_addr =
                        fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2;
                u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0;
 
-               deb_irq("%u irq: %08x cur_addr: %llx: cur_pos: %08x, last_cur_pos: %08x ",
+               deb_irq("%u irq: %08x cur_addr: %llx: cur_pos: %08x, "
+                       "last_cur_pos: %08x ",
                                jiffies_to_usecs(jiffies - fc_pci->last_irq),
                                v.raw, (unsigned long long)cur_addr, cur_pos,
                                fc_pci->last_dma1_cur_pos);
@@ -191,30 +196,36 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id)
                 * pass the data from last_cur_pos to the buffer end to the demux
                 */
                if (cur_pos < fc_pci->last_dma1_cur_pos) {
-                       deb_irq(" end was reached: passing %d bytes ",(fc_pci->dma[0].size*2 - 1) - fc_pci->last_dma1_cur_pos);
+                       deb_irq(" end was reached: passing %d bytes ",
+                               (fc_pci->dma[0].size*2 - 1) -
+                               fc_pci->last_dma1_cur_pos);
                        flexcop_pass_dmx_data(fc_pci->fc_dev,
-                                       fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos,
-                                       (fc_pci->dma[0].size*2) - fc_pci->last_dma1_cur_pos);
+                               fc_pci->dma[0].cpu_addr0 +
+                                       fc_pci->last_dma1_cur_pos,
+                               (fc_pci->dma[0].size*2) -
+                                       fc_pci->last_dma1_cur_pos);
                        fc_pci->last_dma1_cur_pos = 0;
                }
 
                if (cur_pos > fc_pci->last_dma1_cur_pos) {
-                       deb_irq(" passing %d bytes ",cur_pos - fc_pci->last_dma1_cur_pos);
+                       deb_irq(" passing %d bytes ",
+                               cur_pos - fc_pci->last_dma1_cur_pos);
                        flexcop_pass_dmx_data(fc_pci->fc_dev,
-                                       fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos,
-                                       cur_pos - fc_pci->last_dma1_cur_pos);
+                               fc_pci->dma[0].cpu_addr0 +
+                                       fc_pci->last_dma1_cur_pos,
+                               cur_pos - fc_pci->last_dma1_cur_pos);
                }
                deb_irq("\n");
 
                fc_pci->last_dma1_cur_pos = cur_pos;
                fc_pci->count++;
        } else {
-               deb_irq("isr for flexcop called, apparently without reason (%08x)\n",v.raw);
+               deb_irq("isr for flexcop called, "
+                       "apparently without reason (%08x)\n", v.raw);
                ret = IRQ_NONE;
        }
 
-       spin_unlock_irqrestore(&fc_pci->irq_lock,flags);
-
+       spin_unlock_irqrestore(&fc_pci->irq_lock, flags);
        return ret;
 }
 
@@ -222,52 +233,48 @@ static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff)
 {
        struct flexcop_pci *fc_pci = fc->bus_specific;
        if (onoff) {
-               flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1);
-               flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2);
-
-               flexcop_dma_config_timer(fc,FC_DMA_1,0);
-
-               flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,1);
+               flexcop_dma_config(fc, &fc_pci->dma[0], FC_DMA_1);
+               flexcop_dma_config(fc, &fc_pci->dma[1], FC_DMA_2);
+               flexcop_dma_config_timer(fc, FC_DMA_1, 0);
+               flexcop_dma_xfer_control(fc, FC_DMA_1,
+                               FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1, 1);
                deb_irq("DMA xfer enabled\n");
 
                fc_pci->last_dma1_cur_pos = 0;
-               flexcop_dma_control_timer_irq(fc,FC_DMA_1,1);
+               flexcop_dma_control_timer_irq(fc, FC_DMA_1, 1);
                deb_irq("IRQ enabled\n");
-
                fc_pci->count_prev = fc_pci->count;
-
-//             fc_pci->active_dma1_addr = 0;
-//             flexcop_dma_control_size_irq(fc,FC_DMA_1,1);
-
        } else {
-               flexcop_dma_control_timer_irq(fc,FC_DMA_1,0);
+               flexcop_dma_control_timer_irq(fc, FC_DMA_1, 0);
                deb_irq("IRQ disabled\n");
 
-//             flexcop_dma_control_size_irq(fc,FC_DMA_1,0);
-
-               flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,0);
+               flexcop_dma_xfer_control(fc, FC_DMA_1,
+                        FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1, 0);
                deb_irq("DMA xfer disabled\n");
        }
-
        return 0;
 }
 
 static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci)
 {
        int ret;
-       if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[0],FC_DEFAULT_DMA1_BUFSIZE)) != 0)
+       ret = flexcop_dma_allocate(fc_pci->pdev, &fc_pci->dma[0],
+                       FC_DEFAULT_DMA1_BUFSIZE);
+       if (ret != 0)
                return ret;
 
-       if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0) {
+       ret = flexcop_dma_allocate(fc_pci->pdev, &fc_pci->dma[1],
+                       FC_DEFAULT_DMA2_BUFSIZE);
+       if (ret != 0) {
                flexcop_dma_free(&fc_pci->dma[0]);
                return ret;
        }
 
-       flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1);
-       flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO   | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
-
+       flexcop_sram_set_dest(fc_pci->fc_dev, FC_SRAM_DEST_MEDIA |
+                       FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1);
+       flexcop_sram_set_dest(fc_pci->fc_dev, FC_SRAM_DEST_CAO |
+                       FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
        fc_pci->init_state |= FC_PCI_DMA_INIT;
-
        return ret;
 }
 
@@ -290,12 +297,8 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci)
 
        if ((ret = pci_enable_device(fc_pci->pdev)) != 0)
                return ret;
-
        pci_set_master(fc_pci->pdev);
 
-       /* enable interrupts */
-       // pci_write_config_dword(pdev, 0x6c, 0x8000);
-
        if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0)
                goto err_pci_disable_device;
 
@@ -338,8 +341,8 @@ static void flexcop_pci_exit(struct flexcop_pci *fc_pci)
        fc_pci->init_state &= ~FC_PCI_INIT;
 }
 
-
-static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int flexcop_pci_probe(struct pci_dev *pdev,
+               const struct pci_device_id *ent)
 {
        struct flexcop_device *fc;
        struct flexcop_pci *fc_pci;
@@ -350,7 +353,7 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
                return -ENOMEM;
        }
 
-/* general flexcop init */
+       /* general flexcop init */
        fc_pci = fc->bus_specific;
        fc_pci->fc_dev = fc;
 
@@ -358,7 +361,6 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        fc->write_ibi_reg = flexcop_pci_write_ibi_reg;
        fc->i2c_request = flexcop_i2c_request;
        fc->get_mac_addr = flexcop_eeprom_check_mac_addr;
-
        fc->stream_control = flexcop_pci_stream_control;
 
        if (enable_pid_filtering)
@@ -368,29 +370,29 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
        fc->pid_filtering = enable_pid_filtering;
        fc->bus_type = FC_PCI;
-
        fc->dev = &pdev->dev;
        fc->owner = THIS_MODULE;
 
-/* bus specific part */
+       /* bus specific part */
        fc_pci->pdev = pdev;
        if ((ret = flexcop_pci_init(fc_pci)) != 0)
                goto err_kfree;
 
-/* init flexcop */
+       /* init flexcop */
        if ((ret = flexcop_device_initialize(fc)) != 0)
                goto err_pci_exit;
 
-/* init dma */
+       /* init dma */
        if ((ret = flexcop_pci_dma_init(fc_pci)) != 0)
                goto err_fc_exit;
 
        INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work);
 
-               if (irq_chk_intv > 0)
-                       schedule_delayed_work(&fc_pci->irq_check_work,
-               msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
-
+       if (irq_chk_intv > 0)
+               schedule_delayed_work(&fc_pci->irq_check_work,
+                               msecs_to_jiffies(irq_chk_intv < 100 ?
+                                       100 :
+                                       irq_chk_intv));
        return ret;
 
 err_fc_exit:
@@ -420,7 +422,6 @@ static void flexcop_pci_remove(struct pci_dev *pdev)
 
 static struct pci_device_id flexcop_pci_tbl[] = {
        { PCI_DEVICE(0x13d0, 0x2103) },
-/*     { PCI_DEVICE(0x13d0, 0x2200) }, ? */
        { },
 };
 
index 7599fccc1a5b80a438e9cbfd2c8d387c9b526f6c..dc4528dcbb984e50a0cefbedb9b4bb37ce8f0098 100644 (file)
@@ -1,14 +1,11 @@
 /*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
  * flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII
- *
- * see flexcop.c for copyright information.
+ * see flexcop.c for copyright information
  */
 #ifndef __FLEXCOP_REG_H__
 #define __FLEXCOP_REG_H__
 
-
 typedef enum {
        FLEXCOP_UNK = 0,
        FLEXCOP_II,
@@ -18,13 +15,13 @@ typedef enum {
 
 typedef enum {
        FC_UNK = 0,
-       FC_AIR_DVB,
+       FC_CABLE,
+       FC_AIR_DVBT,
        FC_AIR_ATSC1,
        FC_AIR_ATSC2,
-       FC_SKY,
-       FC_SKY_OLD,
-       FC_CABLE,
        FC_AIR_ATSC3,
+       FC_SKY_REV23,
+       FC_SKY_REV26,
        FC_SKY_REV27,
        FC_SKY_REV28,
 } flexcop_device_type_t;
@@ -36,12 +33,12 @@ typedef enum {
 
 /* FlexCop IBI Registers */
 #if defined(__LITTLE_ENDIAN)
-       #include "flexcop_ibi_value_le.h"
+#include "flexcop_ibi_value_le.h"
 #else
 #if defined(__BIG_ENDIAN)
-       #include "flexcop_ibi_value_be.h"
+#include "flexcop_ibi_value_be.h"
 #else
-       #error no endian defined
+#error no endian defined
 #endif
 #endif
 
index cda69528548ac9d0d9757f47786cbf732491a37f..f2199e43e803594253a1ad655d93b196ecffb843 100644 (file)
@@ -1,45 +1,43 @@
 /*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
- * flexcop-sram.c - functions for controlling the SRAM.
- *
- * see flexcop.c for copyright information.
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-sram.c - functions for controlling the SRAM
+ * see flexcop.c for copyright information
  */
 #include "flexcop.h"
 
-static void flexcop_sram_set_chip (struct flexcop_device *fc, flexcop_sram_type_t type)
+static void flexcop_sram_set_chip(struct flexcop_device *fc,
+               flexcop_sram_type_t type)
 {
-       flexcop_set_ibi_value(wan_ctrl_reg_71c,sram_chip,type);
+       flexcop_set_ibi_value(wan_ctrl_reg_71c, sram_chip, type);
 }
 
 int flexcop_sram_init(struct flexcop_device *fc)
 {
        switch (fc->rev) {
-               case FLEXCOP_II:
-               case FLEXCOP_IIB:
-                       flexcop_sram_set_chip(fc,FC_SRAM_1_32KB);
-                       break;
-               case FLEXCOP_III:
-                       flexcop_sram_set_chip(fc,FC_SRAM_1_48KB);
-                       break;
-               default:
-                       return -EINVAL;
+       case FLEXCOP_II:
+       case FLEXCOP_IIB:
+               flexcop_sram_set_chip(fc, FC_SRAM_1_32KB);
+               break;
+       case FLEXCOP_III:
+               flexcop_sram_set_chip(fc, FC_SRAM_1_48KB);
+               break;
+       default:
+               return -EINVAL;
        }
        return 0;
 }
 
-int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target)
+int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest,
+                flexcop_sram_dest_target_t target)
 {
        flexcop_ibi_value v;
-
-       v = fc->read_ibi_reg(fc,sram_dest_reg_714);
+       v = fc->read_ibi_reg(fc, sram_dest_reg_714);
 
        if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) {
                err("SRAM destination target to available on FlexCopII(b)\n");
                return -EINVAL;
        }
-
-       deb_sram("sram dest: %x target: %x\n",dest, target);
+       deb_sram("sram dest: %x target: %x\n", dest, target);
 
        if (dest & FC_SRAM_DEST_NET)
                v.sram_dest_reg_714.NET_Dest = target;
@@ -154,14 +152,12 @@ static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len
                else
                        bank = 0x10000000;
        }
-
        flex_sram_write(adapter, bank, addr & 0x7fff, buf, len);
 }
 
 static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
 {
        u32 bank;
-
        bank = 0;
 
        if (adapter->dw_sram_type == 0x20000) {
@@ -174,26 +170,22 @@ static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
                else
                        bank = 0x10000000;
        }
-
        flex_sram_read(adapter, bank, addr & 0x7fff, buf, len);
 }
 
 static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
 {
        u32 length;
-
        while (len != 0) {
                length = len;
-
-               // check if the address range belongs to the same
-               // 32K memory chip. If not, the data is read from
-               // one chip at a time.
+               /* check if the address range belongs to the same
+                * 32K memory chip. If not, the data is read
+                * from one chip at a time */
                if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
                        length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
                }
 
                sram_read_chunk(adapter, addr, buf, length);
-
                addr = addr + length;
                buf = buf + length;
                len = len - length;
@@ -203,19 +195,17 @@ static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
 static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
 {
        u32 length;
-
        while (len != 0) {
                length = len;
 
-               // check if the address range belongs to the same
-               // 32K memory chip. If not, the data is written to
-               // one chip at a time.
+               /* check if the address range belongs to the same
+                * 32K memory chip. If not, the data is
+                * written to one chip at a time */
                if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
                        length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
                }
 
                sram_write_chunk(adapter, addr, buf, length);
-
                addr = addr + length;
                buf = buf + length;
                len = len - length;
@@ -224,39 +214,29 @@ static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
 
 static void sram_set_size(struct adapter *adapter, u32 mask)
 {
-       write_reg_dw(adapter, 0x71c, (mask | (~0x30000 & read_reg_dw(adapter, 0x71c))));
+       write_reg_dw(adapter, 0x71c,
+                       (mask | (~0x30000 & read_reg_dw(adapter, 0x71c))));
 }
 
 static void sram_init(struct adapter *adapter)
 {
        u32 tmp;
-
        tmp = read_reg_dw(adapter, 0x71c);
-
        write_reg_dw(adapter, 0x71c, 1);
 
        if (read_reg_dw(adapter, 0x71c) != 0) {
                write_reg_dw(adapter, 0x71c, tmp);
-
                adapter->dw_sram_type = tmp & 0x30000;
-
                ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type);
-
        } else {
-
                adapter->dw_sram_type = 0x10000;
-
                ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type);
        }
-
-       /* return value is never used? */
-/*     return adapter->dw_sram_type; */
 }
 
 static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
 {
        u8 tmp1, tmp2;
-
        dprintk("%s: mask = %x, addr = %x\n", __func__, mask, addr);
 
        sram_set_size(adapter, mask);
@@ -269,7 +249,6 @@ static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
        sram_write(adapter, addr + 4, &tmp1, 1);
 
        tmp2 = 0;
-
        mdelay(20);
 
        sram_read(adapter, addr, &tmp2, 1);
@@ -287,7 +266,6 @@ static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
        sram_write(adapter, addr + 4, &tmp1, 1);
 
        tmp2 = 0;
-
        mdelay(20);
 
        sram_read(adapter, addr, &tmp2, 1);
@@ -297,26 +275,24 @@ static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
 
        if (tmp2 != 0x5a)
                return 0;
-
        return 1;
 }
 
 static u32 sram_length(struct adapter *adapter)
 {
        if (adapter->dw_sram_type == 0x10000)
-               return 32768;   //  32K
+               return 32768; /* 32K */
        if (adapter->dw_sram_type == 0x00000)
-               return 65536;   //  64K
+               return 65536; /* 64K */
        if (adapter->dw_sram_type == 0x20000)
-               return 131072;  // 128K
-
-       return 32768;           // 32K
+               return 131072; /* 128K */
+       return 32768; /* 32K */
 }
 
 /* FlexcopII can work with 32K, 64K or 128K of external SRAM memory.
-    - for 128K there are 4x32K chips at bank 0,1,2,3.
-    - for  64K there are 2x32K chips at bank 1,2.
-    - for  32K there is one 32K chip at bank 0.
+   - for 128K there are 4x32K chips at bank 0,1,2,3.
+   - for  64K there are 2x32K chips at bank 1,2.
+   - for  32K there is one 32K chip at bank 0.
 
    FlexCop works only with one bank at a time. The bank is selected
    by bits 28-29 of the 0x700 register.
@@ -324,24 +300,18 @@ static u32 sram_length(struct adapter *adapter)
    bank 0 covers addresses 0x00000-0x07fff
    bank 1 covers addresses 0x08000-0x0ffff
    bank 2 covers addresses 0x10000-0x17fff
-   bank 3 covers addresses 0x18000-0x1ffff
-*/
+   bank 3 covers addresses 0x18000-0x1ffff */
 
 static int flexcop_sram_detect(struct flexcop_device *fc)
 {
-       flexcop_ibi_value r208,r71c_0,vr71c_1;
-
+       flexcop_ibi_value r208, r71c_0, vr71c_1;
        r208 = fc->read_ibi_reg(fc, ctrl_208);
        fc->write_ibi_reg(fc, ctrl_208, ibi_zero);
 
        r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c);
-
        write_reg_dw(adapter, 0x71c, 1);
-
        tmp3 = read_reg_dw(adapter, 0x71c);
-
        dprintk("%s: tmp3 = %x\n", __func__, tmp3);
-
        write_reg_dw(adapter, 0x71c, tmp2);
 
        // check for internal SRAM ???
@@ -350,9 +320,7 @@ static int flexcop_sram_detect(struct flexcop_device *fc)
                sram_set_size(adapter, 0x10000);
                sram_init(adapter);
                write_reg_dw(adapter, 0x208, tmp);
-
                dprintk("%s: sram size = 32K\n", __func__);
-
                return 32;
        }
 
@@ -360,9 +328,7 @@ static int flexcop_sram_detect(struct flexcop_device *fc)
                sram_set_size(adapter, 0x20000);
                sram_init(adapter);
                write_reg_dw(adapter, 0x208, tmp);
-
                dprintk("%s: sram size = 128K\n", __func__);
-
                return 128;
        }
 
@@ -370,9 +336,7 @@ static int flexcop_sram_detect(struct flexcop_device *fc)
                sram_set_size(adapter, 0x00000);
                sram_init(adapter);
                write_reg_dw(adapter, 0x208, tmp);
-
                dprintk("%s: sram size = 64K\n", __func__);
-
                return 64;
        }
 
@@ -380,18 +344,14 @@ static int flexcop_sram_detect(struct flexcop_device *fc)
                sram_set_size(adapter, 0x10000);
                sram_init(adapter);
                write_reg_dw(adapter, 0x208, tmp);
-
                dprintk("%s: sram size = 32K\n", __func__);
-
                return 32;
        }
 
        sram_set_size(adapter, 0x10000);
        sram_init(adapter);
        write_reg_dw(adapter, 0x208, tmp);
-
        dprintk("%s: SRAM detection failed. Set to 32K \n", __func__);
-
        return 0;
 }
 
index ae0d76a5d51d34dd284db2ff450fa70b5d6ea691..bedcfb671624da343e576eb33410be75938db5b6 100644 (file)
@@ -1,11 +1,8 @@
 /*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
- * flexcop-usb.c - covers the USB part.
- *
- * see flexcop.c for copyright information.
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-usb.c - covers the USB part
+ * see flexcop.c for copyright information
  */
-
 #define FC_LOG_PREFIX "flexcop_usb"
 #include "flexcop-usb.h"
 #include "flexcop-common.h"
 /* debug */
 #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
 #define dprintk(level,args...) \
-           do { if ((debug & level)) { printk(args); } } while (0)
-#define debug_dump(b,l,method) {\
+       do { if ((debug & level)) printk(args); } while (0)
+
+#define debug_dump(b, l, method) do {\
        int i; \
-       for (i = 0; i < l; i++) method("%02x ", b[i]); \
-       method("\n");\
-}
+       for (i = 0; i < l; i++) \
+               method("%02x ", b[i]); \
+       method("\n"); \
+} while (0)
 
 #define DEBSTATUS ""
 #else
-#define dprintk(level,args...)
-#define debug_dump(b,l,method)
+#define dprintk(level, args...)
+#define debug_dump(b, l, method)
 #define DEBSTATUS " (debugging is not enabled)"
 #endif
 
 static int debug;
 module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,"
+               "ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS);
 #undef DEBSTATUS
 
-#define deb_info(args...) dprintk(0x01,args)
-#define deb_ts(args...)   dprintk(0x02,args)
-#define deb_ctrl(args...) dprintk(0x04,args)
-#define deb_i2c(args...)  dprintk(0x08,args)
-#define deb_v8(args...)   dprintk(0x10,args)
+#define deb_info(args...) dprintk(0x01, args)
+#define deb_ts(args...) dprintk(0x02, args)
+#define deb_ctrl(args...) dprintk(0x04, args)
+#define deb_i2c(args...) dprintk(0x08, args)
+#define deb_v8(args...) dprintk(0x10, args)
 
 /* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
  * in the IBI address, to make the V8 code simpler.
- * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (these are the six bits used)
+ * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (the six bits used)
  *                  in general: 0000 0HHH 000L LL00
  * IBI ADDRESS FORMAT:                    RHHH BLLL
  *
  * where R is the read(1)/write(0) bit, B is the busy bit
  * and HHH and LLL are the two sets of three bits from the PCI address.
  */
-#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
-#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
+#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) \
+       (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
+#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) \
+       (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
 
 /*
  * DKT 020228
@@ -69,12 +71,13 @@ static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI,
        struct flexcop_usb *fc_usb = fc->bus_specific;
        u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG;
        u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR;
-       u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | (read ? 0x80 : 0);
+       u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) |
+               (read ? 0x80 : 0);
 
        int len = usb_control_msg(fc_usb->udev,
                        read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT,
                        request,
-                       request_type,  /* 0xc0 read or 0x40 write*/
+                       request_type, /* 0xc0 read or 0x40 write */
                        wAddress,
                        0,
                        val,
@@ -82,55 +85,49 @@ static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI,
                        B2C2_WAIT_FOR_OPERATION_RDW * HZ);
 
        if (len != sizeof(u32)) {
-               err("error while %s dword from %d (%d).",read ? "reading" : "writing",
-                       wAddress,wRegOffsPCI);
+               err("error while %s dword from %d (%d).", read ? "reading" :
+                               "writing", wAddress, wRegOffsPCI);
                return -EIO;
        }
        return 0;
 }
-
 /*
  * DKT 010817 - add support for V8 memory read/write and flash update
  */
 static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
                flexcop_usb_request_t req, u8 page, u16 wAddress,
-               u8 *pbBuffer,u32 buflen)
+               u8 *pbBuffer, u32 buflen)
 {
-//     u8 dwRequestType;
        u8 request_type = USB_TYPE_VENDOR;
        u16 wIndex;
-       int nWaitTime,pipe,len;
-
+       int nWaitTime, pipe, len;
        wIndex = page << 8;
 
        switch (req) {
-               case B2C2_USB_READ_V8_MEM:
-                       nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
-                       request_type |= USB_DIR_IN;
-//                     dwRequestType = (u8) RTYPE_READ_V8_MEMORY;
-                       pipe = B2C2_USB_CTRL_PIPE_IN;
+       case B2C2_USB_READ_V8_MEM:
+               nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
+               request_type |= USB_DIR_IN;
+               pipe = B2C2_USB_CTRL_PIPE_IN;
                break;
-               case B2C2_USB_WRITE_V8_MEM:
-                       wIndex |= pbBuffer[0];
-                       request_type |= USB_DIR_OUT;
-                       nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
-//                     dwRequestType = (u8) RTYPE_WRITE_V8_MEMORY;
-                       pipe = B2C2_USB_CTRL_PIPE_OUT;
+       case B2C2_USB_WRITE_V8_MEM:
+               wIndex |= pbBuffer[0];
+               request_type |= USB_DIR_OUT;
+               nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
+               pipe = B2C2_USB_CTRL_PIPE_OUT;
                break;
-               case B2C2_USB_FLASH_BLOCK:
-                       request_type |= USB_DIR_OUT;
-                       nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
-//                     dwRequestType = (u8) RTYPE_WRITE_V8_FLASH;
-                       pipe = B2C2_USB_CTRL_PIPE_OUT;
+       case B2C2_USB_FLASH_BLOCK:
+               request_type |= USB_DIR_OUT;
+               nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
+               pipe = B2C2_USB_CTRL_PIPE_OUT;
                break;
-               default:
-                       deb_info("unsupported request for v8_mem_req %x.\n",req);
+       default:
+               deb_info("unsupported request for v8_mem_req %x.\n", req);
                return -EINVAL;
        }
-       deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n",request_type,req,
-                       wAddress,wIndex,buflen);
+       deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n", request_type, req,
+                       wAddress, wIndex, buflen);
 
-       len = usb_control_msg(fc_usb->udev,pipe,
+       len = usb_control_msg(fc_usb->udev, pipe,
                        req,
                        request_type,
                        wAddress,
@@ -139,39 +136,53 @@ static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
                        buflen,
                        nWaitTime * HZ);
 
-       debug_dump(pbBuffer,len,deb_v8);
-
+       debug_dump(pbBuffer, len, deb_v8);
        return len == buflen ? 0 : -EIO;
 }
 
 #define bytes_left_to_read_on_page(paddr,buflen) \
-                       ((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \
-                       ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)))
+       ((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \
+        ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)))
 
-static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,flexcop_usb_request_t req,
-               flexcop_usb_mem_page_t page_start, u32 addr, int extended, u8 *buf, u32 len)
+static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
+               flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start,
+               u32 addr, int extended, u8 *buf, u32 len)
 {
        int i,ret = 0;
        u16 wMax;
        u32 pagechunk = 0;
 
        switch(req) {
-               case B2C2_USB_READ_V8_MEM:  wMax = USB_MEM_READ_MAX; break;
-               case B2C2_USB_WRITE_V8_MEM:     wMax = USB_MEM_WRITE_MAX; break;
-               case B2C2_USB_FLASH_BLOCK:  wMax = USB_FLASH_MAX; break;
-               default:
-                       return -EINVAL;
+       case B2C2_USB_READ_V8_MEM:
+               wMax = USB_MEM_READ_MAX;
+               break;
+       case B2C2_USB_WRITE_V8_MEM:
+               wMax = USB_MEM_WRITE_MAX;
+               break;
+       case B2C2_USB_FLASH_BLOCK:
+               wMax = USB_FLASH_MAX;
+               break;
+       default:
+               return -EINVAL;
                break;
        }
        for (i = 0; i < len;) {
-               pagechunk = wMax < bytes_left_to_read_on_page(addr,len) ? wMax : bytes_left_to_read_on_page(addr,len);
-               deb_info("%x\n",(addr & V8_MEMORY_PAGE_MASK) | (V8_MEMORY_EXTENDED*extended));
-               if ((ret = flexcop_usb_v8_memory_req(fc_usb,req,
-                               page_start + (addr / V8_MEMORY_PAGE_SIZE), /* actual page */
-                               (addr & V8_MEMORY_PAGE_MASK) | (V8_MEMORY_EXTENDED*extended),
-                               &buf[i],pagechunk)) < 0)
+               pagechunk =
+                       wMax < bytes_left_to_read_on_page(addr, len) ?
+                               wMax :
+                               bytes_left_to_read_on_page(addr, len);
+               deb_info("%x\n",
+                       (addr & V8_MEMORY_PAGE_MASK) |
+                               (V8_MEMORY_EXTENDED*extended));
+
+               ret = flexcop_usb_v8_memory_req(fc_usb, req,
+                       page_start + (addr / V8_MEMORY_PAGE_SIZE),
+                       (addr & V8_MEMORY_PAGE_MASK) |
+                               (V8_MEMORY_EXTENDED*extended),
+                       &buf[i], pagechunk);
+
+               if (ret < 0)
                        return ret;
-
                addr += pagechunk;
                len -= pagechunk;
        }
@@ -180,8 +191,9 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,flexcop_usb_request
 
 static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended)
 {
-       return flexcop_usb_memory_req(fc->bus_specific,B2C2_USB_READ_V8_MEM,
-                       V8_MEMORY_PAGE_FLASH,0x1f010,1,fc->dvb_adapter.proposed_mac,6);
+       return flexcop_usb_memory_req(fc->bus_specific, B2C2_USB_READ_V8_MEM,
+               V8_MEMORY_PAGE_FLASH, 0x1f010, 1,
+               fc->dvb_adapter.proposed_mac, 6);
 }
 
 #if 0
@@ -191,11 +203,8 @@ static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set,
 {
        u16 wValue;
        u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR;
-//     u8 dwRequestType = (u8) RTYPE_GENERIC,
        int nWaitTime = 2,
-               pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN,
-               len;
-
+           pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, len;
        wValue = (func << 8) | extra;
 
        len = usb_control_msg(fc_usb->udev,pipe,
@@ -218,36 +227,35 @@ static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
        struct flexcop_usb *fc_usb = i2c->fc->bus_specific;
        u16 wValue, wIndex;
        int nWaitTime,pipe,len;
-//     u8 dwRequestType;
        u8 request_type = USB_TYPE_VENDOR;
 
        switch (func) {
-               case USB_FUNC_I2C_WRITE:
-               case USB_FUNC_I2C_MULTIWRITE:
-               case USB_FUNC_I2C_REPEATWRITE:
+       case USB_FUNC_I2C_WRITE:
+       case USB_FUNC_I2C_MULTIWRITE:
+       case USB_FUNC_I2C_REPEATWRITE:
                /* DKT 020208 - add this to support special case of DiSEqC */
-               case USB_FUNC_I2C_CHECKWRITE:
-                       pipe = B2C2_USB_CTRL_PIPE_OUT;
-                       nWaitTime = 2;
-//                     dwRequestType = (u8) RTYPE_GENERIC;
-                       request_type |= USB_DIR_OUT;
+       case USB_FUNC_I2C_CHECKWRITE:
+               pipe = B2C2_USB_CTRL_PIPE_OUT;
+               nWaitTime = 2;
+               request_type |= USB_DIR_OUT;
                break;
-               case USB_FUNC_I2C_READ:
-               case USB_FUNC_I2C_REPEATREAD:
-                       pipe = B2C2_USB_CTRL_PIPE_IN;
-                       nWaitTime = 2;
-//                     dwRequestType = (u8) RTYPE_GENERIC;
-                       request_type |= USB_DIR_IN;
+       case USB_FUNC_I2C_READ:
+       case USB_FUNC_I2C_REPEATREAD:
+               pipe = B2C2_USB_CTRL_PIPE_IN;
+               nWaitTime = 2;
+               request_type |= USB_DIR_IN;
                break;
-               default:
-                       deb_info("unsupported function for i2c_req %x\n",func);
-                       return -EINVAL;
+       default:
+               deb_info("unsupported function for i2c_req %x\n", func);
+               return -EINVAL;
        }
        wValue = (func << 8) | (i2c->port << 4);
        wIndex = (chipaddr << 8 ) | addr;
 
-       deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",func,request_type,req,
-               wValue & 0xff, wValue >> 8, wIndex & 0xff, wIndex >> 8);
+       deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",
+                       func, request_type, req,
+                       wValue & 0xff, wValue >> 8,
+                       wIndex & 0xff, wIndex >> 8);
 
        len = usb_control_msg(fc_usb->udev,pipe,
                        req,
@@ -257,44 +265,49 @@ static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
                        buf,
                        buflen,
                        nWaitTime * HZ);
-
        return len == buflen ? 0 : -EREMOTEIO;
 }
 
-/* actual bus specific access functions, make sure prototype are/will be equal to pci */
-static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register reg)
+/* actual bus specific access functions,
+   make sure prototype are/will be equal to pci */
+static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc,
+       flexcop_ibi_register reg)
 {
        flexcop_ibi_value val;
        val.raw = 0;
-       flexcop_usb_readwrite_dw(fc,reg, &val.raw, 1);
+       flexcop_usb_readwrite_dw(fc, reg, &val.raw, 1);
        return val;
 }
 
-static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register reg, flexcop_ibi_value val)
+static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc,
+               flexcop_ibi_register reg, flexcop_ibi_value val)
 {
-       return flexcop_usb_readwrite_dw(fc,reg, &val.raw, 0);
+       return flexcop_usb_readwrite_dw(fc, reg, &val.raw, 0);
 }
 
 static int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c,
-       flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
+               flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
 {
        if (op == FC_READ)
                return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
-                       USB_FUNC_I2C_READ, chipaddr, addr, buf, len);
+                               USB_FUNC_I2C_READ, chipaddr, addr, buf, len);
        else
                return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
-                       USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len);
+                               USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len);
 }
 
-static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, u8 *buffer, int buffer_length)
+static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb,
+       u8 *buffer, int buffer_length)
 {
        u8 *b;
        int l;
 
-       deb_ts("tmp_buffer_length=%d, buffer_length=%d\n", fc_usb->tmp_buffer_length, buffer_length);
+       deb_ts("tmp_buffer_length=%d, buffer_length=%d\n",
+               fc_usb->tmp_buffer_length, buffer_length);
 
        if (fc_usb->tmp_buffer_length > 0) {
-               memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer, buffer_length);
+               memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer,
+                               buffer_length);
                fc_usb->tmp_buffer_length += buffer_length;
                b = fc_usb->tmp_buffer;
                l = fc_usb->tmp_buffer_length;
@@ -304,23 +317,26 @@ static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, u8 *buffer, in
        }
 
        while (l >= 190) {
-               if (*b == 0xff)
+               if (*b == 0xff) {
                        switch (*(b+1) & 0x03) {
-                               case 0x01: /* media packet */
-                                       if ( *(b+2) == 0x47 )
-                                               flexcop_pass_dmx_packets(fc_usb->fc_dev, b+2, 1);
-                                       else
-                                               deb_ts("not ts packet %02x %02x %02x %02x \n", *(b+2), *(b+3), *(b+4), *(b+5) );
-
-                                       b += 190;
-                                       l -= 190;
+                       case 0x01: /* media packet */
+                               if (*(b+2) == 0x47)
+                                       flexcop_pass_dmx_packets(
+                                                       fc_usb->fc_dev, b+2, 1);
+                               else
+                                       deb_ts(
+                                       "not ts packet %02x %02x %02x %02x \n",
+                                               *(b+2), *(b+3),
+                                               *(b+4), *(b+5));
+                               b += 190;
+                               l -= 190;
                                break;
-                               default:
-                                       deb_ts("wrong packet type\n");
-                                       l = 0;
+                       default:
+                               deb_ts("wrong packet type\n");
+                               l = 0;
                                break;
                        }
-               else {
+               else {
                        deb_ts("wrong header\n");
                        l = 0;
                }
@@ -337,23 +353,26 @@ static void flexcop_usb_urb_complete(struct urb *urb)
        int i;
 
        if (urb->actual_length > 0)
-               deb_ts("urb completed, bufsize: %d actlen; %d\n",urb->transfer_buffer_length, urb->actual_length);
+               deb_ts("urb completed, bufsize: %d actlen; %d\n",
+                       urb->transfer_buffer_length, urb->actual_length);
 
        for (i = 0; i < urb->number_of_packets; i++) {
                if (urb->iso_frame_desc[i].status < 0) {
-                       err("iso frame descriptor %d has an error: %d\n",i,urb->iso_frame_desc[i].status);
+                       err("iso frame descriptor %d has an error: %d\n", i,
+                               urb->iso_frame_desc[i].status);
                } else
                        if (urb->iso_frame_desc[i].actual_length > 0) {
-                               deb_ts("passed %d bytes to the demux\n",urb->iso_frame_desc[i].actual_length);
+                               deb_ts("passed %d bytes to the demux\n",
+                                       urb->iso_frame_desc[i].actual_length);
 
                                flexcop_usb_process_frame(fc_usb,
-                                       urb->transfer_buffer + urb->iso_frame_desc[i].offset,
+                                       urb->transfer_buffer +
+                                               urb->iso_frame_desc[i].offset,
                                        urb->iso_frame_desc[i].actual_length);
-               }
+                       }
                urb->iso_frame_desc[i].status = 0;
                urb->iso_frame_desc[i].actual_length = 0;
        }
-
        usb_submit_urb(urb,GFP_ATOMIC);
 }
 
@@ -374,35 +393,47 @@ static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
                }
 
        if (fc_usb->iso_buffer != NULL)
-               pci_free_consistent(NULL,fc_usb->buffer_size, fc_usb->iso_buffer, fc_usb->dma_addr);
+               pci_free_consistent(NULL,
+                       fc_usb->buffer_size, fc_usb->iso_buffer,
+                       fc_usb->dma_addr);
 }
 
 static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
 {
-       u16 frame_size = le16_to_cpu(fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize);
-       int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size,i,j,ret;
+       u16 frame_size = le16_to_cpu(
+               fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize);
+       int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO *
+               frame_size, i, j, ret;
        int buffer_offset = 0;
 
-       deb_ts("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n",
-                       B2C2_USB_NUM_ISO_URB, B2C2_USB_FRAMES_PER_ISO, frame_size,bufsize);
+       deb_ts("creating %d iso-urbs with %d frames "
+                       "each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB,
+                       B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize);
 
-       fc_usb->iso_buffer = pci_alloc_consistent(NULL,bufsize,&fc_usb->dma_addr);
+       fc_usb->iso_buffer = pci_alloc_consistent(NULL,
+                       bufsize, &fc_usb->dma_addr);
        if (fc_usb->iso_buffer == NULL)
                return -ENOMEM;
+
        memset(fc_usb->iso_buffer, 0, bufsize);
        fc_usb->buffer_size = bufsize;
 
        /* creating iso urbs */
-       for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
-               if (!(fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,GFP_ATOMIC))) {
+       for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
+               fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,
+                       GFP_ATOMIC);
+               if (fc_usb->iso_urb[i] == NULL) {
                        ret = -ENOMEM;
                        goto urb_error;
                }
+       }
+
        /* initialising and submitting iso urbs */
        for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
                int frame_offset = 0;
                struct urb *urb = fc_usb->iso_urb[i];
-               deb_ts("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset);
+               deb_ts("initializing and submitting urb no. %d "
+                       "(buf_offset: %d).\n", i, buffer_offset);
 
                urb->dev = fc_usb->udev;
                urb->context = fc_usb;
@@ -416,26 +447,26 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
 
                buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO;
                for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) {
-                       deb_ts("urb no: %d, frame: %d, frame_offset: %d\n",i,j,frame_offset);
+                       deb_ts("urb no: %d, frame: %d, frame_offset: %d\n",
+                                       i, j, frame_offset);
                        urb->iso_frame_desc[j].offset = frame_offset;
                        urb->iso_frame_desc[j].length = frame_size;
                        frame_offset += frame_size;
                }
 
                if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) {
-                       err("submitting urb %d failed with %d.",i,ret);
+                       err("submitting urb %d failed with %d.", i, ret);
                        goto urb_error;
                }
                deb_ts("submitted urb no. %d.\n",i);
        }
 
-/* SRAM */
-
-       flexcop_sram_set_dest(fc_usb->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET |
-                       FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_WAN_USB);
-       flexcop_wan_set_speed(fc_usb->fc_dev,FC_WAN_SPEED_8MBITS);
-       flexcop_sram_ctrl(fc_usb->fc_dev,1,1,1);
-
+       /* SRAM */
+       flexcop_sram_set_dest(fc_usb->fc_dev, FC_SRAM_DEST_MEDIA |
+                       FC_SRAM_DEST_NET | FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI,
+                       FC_SRAM_DEST_TARGET_WAN_USB);
+       flexcop_wan_set_speed(fc_usb->fc_dev, FC_WAN_SPEED_8MBITS);
+       flexcop_sram_ctrl(fc_usb->fc_dev, 1, 1, 1);
        return 0;
 
 urb_error:
@@ -448,20 +479,20 @@ static int flexcop_usb_init(struct flexcop_usb *fc_usb)
        /* use the alternate setting with the larges buffer */
        usb_set_interface(fc_usb->udev,0,1);
        switch (fc_usb->udev->speed) {
-               case USB_SPEED_LOW:
-                       err("cannot handle USB speed because it is to sLOW.");
-                       return -ENODEV;
-                       break;
-               case USB_SPEED_FULL:
-                       info("running at FULL speed.");
-                       break;
-               case USB_SPEED_HIGH:
-                       info("running at HIGH speed.");
-                       break;
-               case USB_SPEED_UNKNOWN: /* fall through */
-               default:
-                       err("cannot handle USB speed because it is unkown.");
-                       return -ENODEV;
+       case USB_SPEED_LOW:
+               err("cannot handle USB speed because it is too slow.");
+               return -ENODEV;
+               break;
+       case USB_SPEED_FULL:
+               info("running at FULL speed.");
+               break;
+       case USB_SPEED_HIGH:
+               info("running at HIGH speed.");
+               break;
+       case USB_SPEED_UNKNOWN: /* fall through */
+       default:
+               err("cannot handle USB speed because it is unknown.");
+               return -ENODEV;
        }
        usb_set_intfdata(fc_usb->uintf, fc_usb);
        return 0;
@@ -485,7 +516,7 @@ static int flexcop_usb_probe(struct usb_interface *intf,
                return -ENOMEM;
        }
 
-/* general flexcop init */
+       /* general flexcop init */
        fc_usb = fc->bus_specific;
        fc_usb->fc_dev = fc;
 
@@ -502,21 +533,21 @@ static int flexcop_usb_probe(struct usb_interface *intf,
        fc->dev = &udev->dev;
        fc->owner = THIS_MODULE;
 
-/* bus specific part */
+       /* bus specific part */
        fc_usb->udev = udev;
        fc_usb->uintf = intf;
        if ((ret = flexcop_usb_init(fc_usb)) != 0)
                goto err_kfree;
 
-/* init flexcop */
+       /* init flexcop */
        if ((ret = flexcop_device_initialize(fc)) != 0)
                goto err_usb_exit;
 
-/* xfer init */
+       /* xfer init */
        if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0)
                goto err_fc_exit;
 
-       info("%s successfully initialized and connected.",DRIVER_NAME);
+       info("%s successfully initialized and connected.", DRIVER_NAME);
        return 0;
 
 err_fc_exit:
@@ -535,12 +566,12 @@ static void flexcop_usb_disconnect(struct usb_interface *intf)
        flexcop_device_exit(fc_usb->fc_dev);
        flexcop_usb_exit(fc_usb);
        flexcop_device_kfree(fc_usb->fc_dev);
-       info("%s successfully deinitialized and disconnected.",DRIVER_NAME);
+       info("%s successfully deinitialized and disconnected.", DRIVER_NAME);
 }
 
 static struct usb_device_id flexcop_usb_table [] = {
-           { USB_DEVICE(0x0af7, 0x0101) },
-           { }
+       { USB_DEVICE(0x0af7, 0x0101) },
+       { }
 };
 MODULE_DEVICE_TABLE (usb, flexcop_usb_table);
 
@@ -557,10 +588,9 @@ static int __init flexcop_usb_module_init(void)
 {
        int result;
        if ((result = usb_register(&flexcop_usb_driver))) {
-               err("usb_register failed. (%d)",result);
+               err("usb_register failed. (%d)", result);
                return result;
        }
-
        return 0;
 }
 
index 630e647a2caa6bba2404787592fd444abc524374..92529a9c4475b71ca5381670ceb16d5ccfcd079c 100644 (file)
@@ -1,15 +1,20 @@
+/*
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-usb.h - header file for the USB part
+ * see flexcop.c for copyright information
+ */
 #ifndef __FLEXCOP_USB_H_INCLUDED__
 #define __FLEXCOP_USB_H_INCLUDED__
 
 #include <linux/usb.h>
 
 /* transfer parameters */
-#define B2C2_USB_FRAMES_PER_ISO                4
-#define B2C2_USB_NUM_ISO_URB           4
+#define B2C2_USB_FRAMES_PER_ISO 4
+#define B2C2_USB_NUM_ISO_URB 4
 
-#define B2C2_USB_CTRL_PIPE_IN          usb_rcvctrlpipe(fc_usb->udev,0)
-#define B2C2_USB_CTRL_PIPE_OUT         usb_sndctrlpipe(fc_usb->udev,0)
-#define B2C2_USB_DATA_PIPE                     usb_rcvisocpipe(fc_usb->udev,0x81)
+#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(fc_usb->udev, 0)
+#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(fc_usb->udev, 0)
+#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev, 0x81)
 
 struct flexcop_usb {
        struct usb_device *udev;
@@ -18,8 +23,8 @@ struct flexcop_usb {
        u8 *iso_buffer;
        int buffer_size;
        dma_addr_t dma_addr;
-       struct urb *iso_urb[B2C2_USB_NUM_ISO_URB];
 
+       struct urb *iso_urb[B2C2_USB_NUM_ISO_URB];
        struct flexcop_device *fc_dev;
 
        u8 tmp_buffer[1023+190];
@@ -30,14 +35,6 @@ struct flexcop_usb {
 /* request types TODO What is its use?*/
 typedef enum {
 
-/* something is wrong with this part
-       RTYPE_READ_DW         = (1 << 6),
-       RTYPE_WRITE_DW_1      = (3 << 6),
-       RTYPE_READ_V8_MEMORY  = (6 << 6),
-       RTYPE_WRITE_V8_MEMORY = (7 << 6),
-       RTYPE_WRITE_V8_FLASH  = (8 << 6),
-       RTYPE_GENERIC         = (9 << 6),
-*/
 } flexcop_usb_request_type_t;
 #endif
 
@@ -47,7 +44,6 @@ typedef enum {
        B2C2_USB_READ_V8_MEM  = 0x05,
        B2C2_USB_READ_REG     = 0x08,
        B2C2_USB_WRITE_REG    = 0x0A,
-/*     B2C2_USB_WRITEREGLO   = 0x0A, */
        B2C2_USB_WRITEREGHI   = 0x0B,
        B2C2_USB_FLASH_BLOCK  = 0x10,
        B2C2_USB_I2C_REQUEST  = 0x11,
@@ -62,15 +58,13 @@ typedef enum {
        USB_FUNC_I2C_REPEATWRITE = 0x04,
        USB_FUNC_GET_DESCRIPTOR  = 0x05,
        USB_FUNC_I2C_REPEATREAD  = 0x06,
-/* DKT 020208 - add this to support special case of DiSEqC */
+       /* DKT 020208 - add this to support special case of DiSEqC */
        USB_FUNC_I2C_CHECKWRITE  = 0x07,
        USB_FUNC_I2C_CHECKRESULT = 0x08,
 } flexcop_usb_i2c_function_t;
 
-/*
- * function definition for UTILITY request 0x12
- * DKT 020304 - new utility function
- */
+/* function definition for UTILITY request 0x12
+ * DKT 020304 - new utility function */
 typedef enum {
        UTILITY_SET_FILTER          = 0x01,
        UTILITY_DATA_ENABLE         = 0x02,
@@ -84,7 +78,7 @@ typedef enum {
        UTILITY_DATA_RESET          = 0x0A,
        UTILITY_GET_DATA_STATUS     = 0x10,
        UTILITY_GET_V8_REG          = 0x11,
-/* DKT 020326 - add function for v1.14 */
+       /* DKT 020326 - add function for v1.14 */
        UTILITY_SRAM_WRITE          = 0x12,
        UTILITY_SRAM_READ           = 0x13,
        UTILITY_SRAM_TESTFILL       = 0x14,
@@ -92,13 +86,13 @@ typedef enum {
        UTILITY_SRAM_TESTVERIFY     = 0x16,
 } flexcop_usb_utility_function_t;
 
-#define B2C2_WAIT_FOR_OPERATION_RW  1*HZ       /* 1 s */
-#define B2C2_WAIT_FOR_OPERATION_RDW 3*HZ       /* 3 s */
-#define B2C2_WAIT_FOR_OPERATION_WDW 1*HZ       /* 1 s */
+#define B2C2_WAIT_FOR_OPERATION_RW (1*HZ)
+#define B2C2_WAIT_FOR_OPERATION_RDW (3*HZ)
+#define B2C2_WAIT_FOR_OPERATION_WDW (1*HZ)
 
-#define B2C2_WAIT_FOR_OPERATION_V8READ   3*HZ  /* 3 s */
-#define B2C2_WAIT_FOR_OPERATION_V8WRITE  3*HZ  /* 3 s */
-#define B2C2_WAIT_FOR_OPERATION_V8FLASH  3*HZ  /* 3 s */
+#define B2C2_WAIT_FOR_OPERATION_V8READ (3*HZ)
+#define B2C2_WAIT_FOR_OPERATION_V8WRITE (3*HZ)
+#define B2C2_WAIT_FOR_OPERATION_V8FLASH (3*HZ)
 
 typedef enum {
        V8_MEMORY_PAGE_DVB_CI = 0x20,
@@ -107,13 +101,11 @@ typedef enum {
        V8_MEMORY_PAGE_FLASH  = 0x80
 } flexcop_usb_mem_page_t;
 
-#define V8_MEMORY_EXTENDED      (1 << 15)
-
-#define USB_MEM_READ_MAX                32
-#define USB_MEM_WRITE_MAX               1
-#define USB_FLASH_MAX                   8
-
-#define V8_MEMORY_PAGE_SIZE     0x8000      // 32K
-#define V8_MEMORY_PAGE_MASK     0x7FFF
+#define V8_MEMORY_EXTENDED (1 << 15)
+#define USB_MEM_READ_MAX   32
+#define USB_MEM_WRITE_MAX   1
+#define USB_FLASH_MAX       8
+#define V8_MEMORY_PAGE_SIZE 0x8000 /* 32K */
+#define V8_MEMORY_PAGE_MASK 0x7FFF
 
 #endif
index 91068952b502b753a349467c78927ae75ce8a670..2df1b0214dcdce8bbb139990c18b74c8f9cc5a7b 100644 (file)
@@ -1,22 +1,20 @@
 /*
- * flexcop.c - driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
- * Copyright (C) 2004-5 Patrick Boettcher <patrick.boettcher@desy.de>
- *
- * based on the skystar2-driver
- * Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop.c - main module part
+ * Copyright (C) 2004-9 Patrick Boettcher <patrick.boettcher@desy.de>
+ * based on skystar2-driver Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
  *
  * Acknowledgements:
- *     John Jurrius from BBTI, Inc. for extensive support with
- *         code examples and data books
- *
- *     Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting)
+ *   John Jurrius from BBTI, Inc. for extensive support
+ *                    with code examples and data books
+ *   Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting)
  *
  * Contributions to the skystar2-driver have been done by
- *     Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes)
- *     Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code)
- *     Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac filtering)
- *
+ *   Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes)
+ *   Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code)
+ *   Uwe Bugla, uwe.bugla at gmx.de (doing tests, restyling code, writing docu)
+ *   Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac
+ *               filtering)
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
 
 int b2c2_flexcop_debug;
 module_param_named(debug, b2c2_flexcop_debug,  int, 0644);
-MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram,32=reg (|-able))." DEBSTATUS);
+MODULE_PARM_DESC(debug,
+               "set debug level (1=info,2=tuner,4=i2c,8=ts,"
+               "16=sram,32=reg (|-able))."
+               DEBSTATUS);
 #undef DEBSTATUS
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@@ -57,37 +58,36 @@ flexcop_ibi_value ibi_zero;
 static int flexcop_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
 {
        struct flexcop_device *fc = dvbdmxfeed->demux->priv;
-       return flexcop_pid_feed_control(fc,dvbdmxfeed,1);
+       return flexcop_pid_feed_control(fc, dvbdmxfeed, 1);
 }
 
 static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
 {
        struct flexcop_device *fc = dvbdmxfeed->demux->priv;
-       return flexcop_pid_feed_control(fc,dvbdmxfeed,0);
+       return flexcop_pid_feed_control(fc, dvbdmxfeed, 0);
 }
 
 static int flexcop_dvb_init(struct flexcop_device *fc)
 {
        int ret = dvb_register_adapter(&fc->dvb_adapter,
-                                      "FlexCop Digital TV device", fc->owner,
-                                      fc->dev, adapter_nr);
+                       "FlexCop Digital TV device", fc->owner,
+                       fc->dev, adapter_nr);
        if (ret < 0) {
                err("error registering DVB adapter");
                return ret;
        }
        fc->dvb_adapter.priv = fc;
 
-       fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+       fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING
+                       | DMX_MEMORY_BASED_FILTERING);
        fc->demux.priv = fc;
-
        fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED;
-
        fc->demux.start_feed = flexcop_dvb_start_feed;
        fc->demux.stop_feed = flexcop_dvb_stop_feed;
        fc->demux.write_to_decoder = NULL;
 
        if ((ret = dvb_dmx_init(&fc->demux)) < 0) {
-               err("dvb_dmx failed: error %d",ret);
+               err("dvb_dmx failed: error %d", ret);
                goto err_dmx;
        }
 
@@ -97,23 +97,23 @@ static int flexcop_dvb_init(struct flexcop_device *fc)
        fc->dmxdev.demux = &fc->demux.dmx;
        fc->dmxdev.capabilities = 0;
        if ((ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter)) < 0) {
-               err("dvb_dmxdev_init failed: error %d",ret);
+               err("dvb_dmxdev_init failed: error %d", ret);
                goto err_dmx_dev;
        }
 
        if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) {
-               err("adding hw_frontend to dmx failed: error %d",ret);
+               err("adding hw_frontend to dmx failed: error %d", ret);
                goto err_dmx_add_hw_frontend;
        }
 
        fc->mem_frontend.source = DMX_MEMORY_FE;
        if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend)) < 0) {
-               err("adding mem_frontend to dmx failed: error %d",ret);
+               err("adding mem_frontend to dmx failed: error %d", ret);
                goto err_dmx_add_mem_frontend;
        }
 
        if ((ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) {
-               err("connect frontend failed: error %d",ret);
+               err("connect frontend failed: error %d", ret);
                goto err_connect_frontend;
        }
 
@@ -123,9 +123,9 @@ static int flexcop_dvb_init(struct flexcop_device *fc)
        return 0;
 
 err_connect_frontend:
-       fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend);
+       fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->mem_frontend);
 err_dmx_add_mem_frontend:
-       fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->hw_frontend);
+       fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->hw_frontend);
 err_dmx_add_hw_frontend:
        dvb_dmxdev_release(&fc->dmxdev);
 err_dmx_dev:
@@ -141,12 +141,13 @@ static void flexcop_dvb_exit(struct flexcop_device *fc)
                dvb_net_release(&fc->dvbnet);
 
                fc->demux.dmx.close(&fc->demux.dmx);
-               fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend);
-               fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->hw_frontend);
+               fc->demux.dmx.remove_frontend(&fc->demux.dmx,
+                       &fc->mem_frontend);
+               fc->demux.dmx.remove_frontend(&fc->demux.dmx,
+                       &fc->hw_frontend);
                dvb_dmxdev_release(&fc->dmxdev);
                dvb_dmx_release(&fc->demux);
                dvb_unregister_adapter(&fc->dvb_adapter);
-
                deb_info("deinitialized dvb stuff\n");
        }
        fc->init_state &= ~FC_STATE_DVB_INIT;
@@ -168,9 +169,9 @@ EXPORT_SYMBOL(flexcop_pass_dmx_packets);
 
 static void flexcop_reset(struct flexcop_device *fc)
 {
-       flexcop_ibi_value v210,v204;
+       flexcop_ibi_value v210, v204;
 
-/* reset the flexcop itself */
+       /* reset the flexcop itself */
        fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
 
        v210.raw = 0;
@@ -183,13 +184,11 @@ static void flexcop_reset(struct flexcop_device *fc)
        v210.sw_reset_210.reset_block_600 = 1;
        v210.sw_reset_210.reset_block_700 = 1;
        v210.sw_reset_210.Block_reset_enable = 0xb2;
-
        v210.sw_reset_210.Special_controls = 0xc259;
-
        fc->write_ibi_reg(fc,sw_reset_210,v210);
        msleep(1);
 
-/* reset the periphical devices */
+       /* reset the periphical devices */
 
        v204 = fc->read_ibi_reg(fc,misc_204);
        v204.misc_204.Per_reset_sig = 0;
@@ -201,25 +200,24 @@ static void flexcop_reset(struct flexcop_device *fc)
 
 void flexcop_reset_block_300(struct flexcop_device *fc)
 {
-       flexcop_ibi_value v208_save = fc->read_ibi_reg(fc,ctrl_208),
-                                         v210 = fc->read_ibi_reg(fc,sw_reset_210);
-
-       deb_rdump("208: %08x, 210: %08x\n",v208_save.raw,v210.raw);
+       flexcop_ibi_value v208_save = fc->read_ibi_reg(fc, ctrl_208),
+                         v210 = fc->read_ibi_reg(fc, sw_reset_210);
 
+       deb_rdump("208: %08x, 210: %08x\n", v208_save.raw, v210.raw);
        fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
 
        v210.sw_reset_210.reset_block_300 = 1;
        v210.sw_reset_210.Block_reset_enable = 0xb2;
 
        fc->write_ibi_reg(fc,sw_reset_210,v210);
-       udelay(1000);
        fc->write_ibi_reg(fc,ctrl_208,v208_save);
 }
 
 struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
 {
        void *bus;
-       struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device), GFP_KERNEL);
+       struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device),
+                               GFP_KERNEL);
        if (!fc) {
                err("no memory");
                return NULL;
@@ -254,7 +252,6 @@ int flexcop_device_initialize(struct flexcop_device *fc)
        flexcop_determine_revision(fc);
        flexcop_sram_init(fc);
        flexcop_hw_filter_init(fc);
-
        flexcop_smc_ctrl(fc, 0);
 
        if ((ret = flexcop_dvb_init(fc)))
@@ -279,7 +276,6 @@ int flexcop_device_initialize(struct flexcop_device *fc)
                goto error;
 
        flexcop_device_name(fc,"initialization of","complete");
-
        return 0;
 
 error:
index 0cebe1d92e0b6fa642efa16882ed99ee83f6b6a7..897b10c85ad9273b75b9cb911b2f0c2853b9a167 100644 (file)
@@ -1,9 +1,7 @@
 /*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
- * flexcop.h - private header file for all flexcop-chip-source files.
- *
- * see flexcop.c for copyright information.
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop.h - private header file for all flexcop-chip-source files
+ * see flexcop.c for copyright information
  */
 #ifndef __FLEXCOP_H__
 #define __FLEXCOP_H___
@@ -21,11 +19,11 @@ extern int b2c2_flexcop_debug;
 #define dprintk(level,args...)
 #endif
 
-#define deb_info(args...)  dprintk(0x01,args)
-#define deb_tuner(args...) dprintk(0x02,args)
-#define deb_i2c(args...)   dprintk(0x04,args)
-#define deb_ts(args...)    dprintk(0x08,args)
-#define deb_sram(args...)  dprintk(0x10,args)
-#define deb_rdump(args...)  dprintk(0x20,args)
+#define deb_info(args...) dprintk(0x01, args)
+#define deb_tuner(args...) dprintk(0x02, args)
+#define deb_i2c(args...) dprintk(0x04, args)
+#define deb_ts(args...) dprintk(0x08, args)
+#define deb_sram(args...) dprintk(0x10, args)
+#define deb_rdump(args...) dprintk(0x20, args)
 
 #endif
index ed9a6756b194e10d5dee27eefb14fa50792ea851..8f64bdbd72bb6ab35791d5a384b41f09541ce346 100644 (file)
@@ -1,10 +1,7 @@
-/* This file is part of linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
+/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
  * register descriptions
- *
- * see flexcop.c for copyright information.
+ * see flexcop.c for copyright information
  */
-
 /* This file is automatically generated, do not edit things here. */
 #ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
 #define __FLEXCOP_IBI_VALUE_INCLUDED__
index 49f2315b6e58b8b992ca7f06645d8bef4ba838fe..c75830d7d94286c6e60524dea8c846847dd18d73 100644 (file)
@@ -1,10 +1,7 @@
-/* This file is part of linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
+/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
  * register descriptions
- *
- * see flexcop.c for copyright information.
+ * see flexcop.c for copyright information
  */
-
 /* This file is automatically generated, do not edit things here. */
 #ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
 #define __FLEXCOP_IBI_VALUE_INCLUDED__
index 27edb0ece58752b0617f9bdb2bd26ef05500f510..8668e634c7ec96da068ed22ba013352e32626ba0 100644 (file)
@@ -8,7 +8,7 @@ config DVB_BT8XX
        select DVB_OR51211 if !DVB_FE_CUSTOMISE
        select DVB_LGDT330X if !DVB_FE_CUSTOMISE
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
        help
          Support for PCI cards based on the Bt8xx PCI bridge. Examples are
          the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
index 0258451423ad876b53e3e2a9b94044cf1b7025c9..4601b059b2b20008b7b277f725ec66d207c83e42 100644 (file)
@@ -552,16 +552,19 @@ free_mem_and_exit:
        return result;
 }
 
-static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long ioctl_arg)
+static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioctl_arg)
 {
-       struct dvb_device* dvbdev = (struct dvb_device*) file->private_data;
-       struct dst_state* state = (struct dst_state*) dvbdev->priv;
+       struct dvb_device *dvbdev;
+       struct dst_state *state;
        struct ca_slot_info *p_ca_slot_info;
        struct ca_caps *p_ca_caps;
        struct ca_msg *p_ca_message;
        void __user *arg = (void __user *)ioctl_arg;
        int result = 0;
 
+       lock_kernel();
+       dvbdev = (struct dvb_device *)file->private_data;
+       state = (struct dst_state *)dvbdev->priv;
        p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
        p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
        p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
@@ -647,6 +650,7 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
        kfree (p_ca_slot_info);
        kfree (p_ca_caps);
 
+       unlock_kernel();
        return result;
 }
 
@@ -682,9 +686,9 @@ static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t
        return 0;
 }
 
-static struct file_operations dst_ca_fops = {
+static const struct file_operations dst_ca_fops = {
        .owner = THIS_MODULE,
-       .ioctl = dst_ca_ioctl,
+       .unlocked_ioctl = dst_ca_ioctl,
        .open = dst_ca_open,
        .release = dst_ca_release,
        .read = dst_ca_read,
index 48762a2b9e42e340c63f94534a171052e5b7f103..b1857c19bbd2c9021cfb25df6b3f63aab49848a0 100644 (file)
@@ -814,7 +814,7 @@ static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
 
        mutex_init(&card->lock);
        card->bttv_nr = sub->core->nr;
-       strncpy(card->card_name, sub->core->name, sizeof(sub->core->name));
+       strlcpy(card->card_name, sub->core->v4l2_dev.name, sizeof(card->card_name));
        card->i2c_adapter = &sub->core->i2c_adap;
 
        switch(sub->core->type) {
index 43f4d44edca6d17ed9b97a3e8226af26caafd71d..de3eeb0a8d6e2e0f45db95b8a4d9068b3a70f8fb 100644 (file)
@@ -8,6 +8,7 @@ config DVB_DM1105
        select DVB_STB6000 if !DVB_FE_CUSTOMISE
        select DVB_CX24116 if !DVB_FE_CUSTOMISE
        select DVB_SI21XX if !DVB_FE_CUSTOMISE
+       select VIDEO_IR
        help
          Support for cards based on the SDMC DM1105 PCI chip like
          DvbWorld 2002
index f48f73aff195ae7d60a918288d15027983a62a8a..5b20cf5a29f02fa056834bca9cdbd7969e291578 100644 (file)
@@ -156,46 +156,12 @@ MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
-static u16 ir_codes_dm1105_nec[128] = {
-       [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*/
-};
-
 /* infrared remote control */
 struct infrared {
-       u16     key_map[128];
        struct input_dev        *input_dev;
+       struct ir_input_state   ir;
        char                    input_phys[32];
-       struct tasklet_struct   ir_tasklet;
+       struct work_struct      work;
        u32                     ir_command;
 };
 
@@ -220,10 +186,14 @@ struct dm1105dvb {
        /* i2c */
        struct i2c_adapter i2c_adap;
 
+       /* irq */
+       struct work_struct work;
+
        /* dma */
        dma_addr_t dma_addr;
        unsigned char *ts_buf;
        u32 wrp;
+       u32 nextwrp;
        u32 buffer_size;
        unsigned int    PacketErrorCount;
        unsigned int dmarst;
@@ -233,8 +203,6 @@ struct dm1105dvb {
 
 #define dm_io_mem(reg) ((unsigned long)(&dm1105dvb->io_mem[reg]))
 
-static struct dm1105dvb *dm1105dvb_local;
-
 static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
                            struct i2c_msg *msgs, int num)
 {
@@ -407,38 +375,61 @@ static int dm1105dvb_stop_feed(struct dvb_demux_feed *f)
        return 0;
 }
 
-/* ir tasklet */
-static void dm1105_emit_key(unsigned long parm)
+/* ir work handler */
+static void dm1105_emit_key(struct work_struct *work)
 {
-       struct infrared *ir = (struct infrared *) parm;
+       struct infrared *ir = container_of(work, struct infrared, work);
        u32 ircom = ir->ir_command;
        u8 data;
-       u16 keycode;
+
+       if (ir_debug)
+               printk(KERN_INFO "%s: received byte 0x%04x\n", __func__, ircom);
 
        data = (ircom >> 8) & 0x7f;
 
-       input_event(ir->input_dev, EV_MSC, MSC_RAW, (0x0000f8 << 16) | data);
-       input_event(ir->input_dev, EV_MSC, MSC_SCAN, data);
-       keycode = ir->key_map[data];
+       ir_input_keydown(ir->input_dev, &ir->ir, data, data);
+       ir_input_nokey(ir->input_dev, &ir->ir);
+}
 
-       if (!keycode)
-               return;
+/* work handler */
+static void dm1105_dmx_buffer(struct work_struct *work)
+{
+       struct dm1105dvb *dm1105dvb =
+                               container_of(work, struct dm1105dvb, work);
+       unsigned int nbpackets;
+       u32 oldwrp = dm1105dvb->wrp;
+       u32 nextwrp = dm1105dvb->nextwrp;
+
+       if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) &&
+                       (dm1105dvb->ts_buf[oldwrp + 188] == 0x47) &&
+                       (dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) {
+               dm1105dvb->PacketErrorCount++;
+               /* bad packet found */
+               if ((dm1105dvb->PacketErrorCount >= 2) &&
+                               (dm1105dvb->dmarst == 0)) {
+                       outb(1, dm_io_mem(DM1105_RST));
+                       dm1105dvb->wrp = 0;
+                       dm1105dvb->PacketErrorCount = 0;
+                       dm1105dvb->dmarst = 0;
+                       return;
+               }
+       }
 
-       input_event(ir->input_dev, EV_KEY, keycode, 1);
-       input_sync(ir->input_dev);
-       input_event(ir->input_dev, EV_KEY, keycode, 0);
-       input_sync(ir->input_dev);
+       if (nextwrp < oldwrp) {
+               memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size,
+                                               dm1105dvb->ts_buf, nextwrp);
+               nbpackets = ((dm1105dvb->buffer_size - oldwrp) + nextwrp) / 188;
+       } else
+               nbpackets = (nextwrp - oldwrp) / 188;
 
+       dm1105dvb->wrp = nextwrp;
+       dvb_dmx_swfilter_packets(&dm1105dvb->demux,
+                                       &dm1105dvb->ts_buf[oldwrp], nbpackets);
 }
 
 static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
 {
        struct dm1105dvb *dm1105dvb = dev_id;
-       unsigned int piece;
-       unsigned int nbpackets;
-       u32 command;
-       u32 nextwrp;
-       u32 oldwrp;
 
        /* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */
        unsigned int intsts = inb(dm_io_mem(DM1105_INTSTS));
@@ -447,71 +438,25 @@ static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
        switch (intsts) {
        case INTSTS_TSIRQ:
        case (INTSTS_TSIRQ | INTSTS_IR):
-               nextwrp = inl(dm_io_mem(DM1105_WRP)) -
-                       inl(dm_io_mem(DM1105_STADR)) ;
-               oldwrp = dm1105dvb->wrp;
-               spin_lock(&dm1105dvb->lock);
-               if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) &&
-                               (dm1105dvb->ts_buf[oldwrp + 188] == 0x47) &&
-                               (dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) {
-                       dm1105dvb->PacketErrorCount++;
-                       /* bad packet found */
-                       if ((dm1105dvb->PacketErrorCount >= 2) &&
-                                       (dm1105dvb->dmarst == 0)) {
-                               outb(1, dm_io_mem(DM1105_RST));
-                               dm1105dvb->wrp = 0;
-                               dm1105dvb->PacketErrorCount = 0;
-                               dm1105dvb->dmarst = 0;
-                               spin_unlock(&dm1105dvb->lock);
-                               return IRQ_HANDLED;
-                       }
-               }
-               if (nextwrp < oldwrp) {
-                       piece = dm1105dvb->buffer_size - oldwrp;
-                       memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size, dm1105dvb->ts_buf, nextwrp);
-                       nbpackets = (piece + nextwrp)/188;
-               } else  {
-                       nbpackets = (nextwrp - oldwrp)/188;
-               }
-               dvb_dmx_swfilter_packets(&dm1105dvb->demux, &dm1105dvb->ts_buf[oldwrp], nbpackets);
-               dm1105dvb->wrp = nextwrp;
-               spin_unlock(&dm1105dvb->lock);
+               dm1105dvb->nextwrp = inl(dm_io_mem(DM1105_WRP)) -
+                                       inl(dm_io_mem(DM1105_STADR));
+               schedule_work(&dm1105dvb->work);
                break;
        case INTSTS_IR:
-               command = inl(dm_io_mem(DM1105_IRCODE));
-               if (ir_debug)
-                       printk("dm1105: received byte 0x%04x\n", command);
-
-               dm1105dvb->ir.ir_command = command;
-               tasklet_schedule(&dm1105dvb->ir.ir_tasklet);
+               dm1105dvb->ir.ir_command = inl(dm_io_mem(DM1105_IRCODE));
+               schedule_work(&dm1105dvb->ir.work);
                break;
        }
-       return IRQ_HANDLED;
-
-
-}
-
-/* register with input layer */
-static void input_register_keys(struct infrared *ir)
-{
-       int i;
 
-       memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit));
-
-       for (i = 0; i < ARRAY_SIZE(ir->key_map); i++)
-                       set_bit(ir->key_map[i], ir->input_dev->keybit);
-
-       ir->input_dev->keycode = ir->key_map;
-       ir->input_dev->keycodesize = sizeof(ir->key_map[0]);
-       ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
+       return IRQ_HANDLED;
 }
 
 int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
 {
        struct input_dev *input_dev;
-       int err;
-
-       dm1105dvb_local = dm1105;
+       IR_KEYTAB_TYPE *ir_codes = ir_codes_dm1105_nec;
+       int ir_type = IR_TYPE_OTHER;
+       int err = -ENOMEM;
 
        input_dev = input_allocate_device();
        if (!input_dev)
@@ -521,12 +466,11 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
        snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys),
                "pci-%s/ir0", pci_name(dm1105->pdev));
 
-       input_dev->evbit[0] = BIT(EV_KEY);
+       ir_input_init(input_dev, &dm1105->ir.ir, ir_type, ir_codes);
        input_dev->name = "DVB on-card IR receiver";
-
        input_dev->phys = dm1105->ir.input_phys;
        input_dev->id.bustype = BUS_PCI;
-       input_dev->id.version = 2;
+       input_dev->id.version = 1;
        if (dm1105->pdev->subsystem_vendor) {
                input_dev->id.vendor = dm1105->pdev->subsystem_vendor;
                input_dev->id.product = dm1105->pdev->subsystem_device;
@@ -534,25 +478,22 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
                input_dev->id.vendor = dm1105->pdev->vendor;
                input_dev->id.product = dm1105->pdev->device;
        }
+
        input_dev->dev.parent = &dm1105->pdev->dev;
-       /* initial keymap */
-       memcpy(dm1105->ir.key_map, ir_codes_dm1105_nec, sizeof dm1105->ir.key_map);
-       input_register_keys(&dm1105->ir);
+
+       INIT_WORK(&dm1105->ir.work, dm1105_emit_key);
+
        err = input_register_device(input_dev);
        if (err) {
                input_free_device(input_dev);
                return err;
        }
 
-       tasklet_init(&dm1105->ir.ir_tasklet, dm1105_emit_key, (unsigned long) &dm1105->ir);
-
        return 0;
 }
 
-
 void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105)
 {
-       tasklet_kill(&dm1105->ir.ir_tasklet);
        input_unregister_device(dm1105->ir.input_dev);
 
 }
@@ -710,7 +651,7 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
 
        dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL);
        if (!dm1105dvb)
-               goto out;
+               return -ENOMEM;
 
        dm1105dvb->pdev = pdev;
        dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES;
@@ -740,13 +681,9 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
        spin_lock_init(&dm1105dvb->lock);
        pci_set_drvdata(pdev, dm1105dvb);
 
-       ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED, DRIVER_NAME, dm1105dvb);
-       if (ret < 0)
-               goto err_pci_iounmap;
-
        ret = dm1105dvb_hw_init(dm1105dvb);
        if (ret < 0)
-               goto err_free_irq;
+               goto err_pci_iounmap;
 
        /* i2c */
        i2c_set_adapdata(&dm1105dvb->i2c_adap, dm1105dvb);
@@ -813,8 +750,15 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
 
        dvb_net_init(dvb_adapter, &dm1105dvb->dvbnet, dmx);
        dm1105_ir_init(dm1105dvb);
-out:
-       return ret;
+
+       INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer);
+
+       ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED,
+                                               DRIVER_NAME, dm1105dvb);
+       if (ret < 0)
+               goto err_free_irq;
+
+       return 0;
 
 err_disconnect_frontend:
        dmx->disconnect_frontend(dmx);
@@ -843,7 +787,7 @@ err_pci_disable_device:
 err_kfree:
        pci_set_drvdata(pdev, NULL);
        kfree(dm1105dvb);
-       goto out;
+       return ret;
 }
 
 static void __devexit dm1105_remove(struct pci_dev *pdev)
index 069d847ba887c39e2f1f83eafdf7c06a07b838a7..c35fbb8d8f4a1b5c8c07cda277ad23f76cb558ab 100644 (file)
@@ -1024,7 +1024,7 @@ static int dvb_demux_release(struct inode *inode, struct file *file)
        return ret;
 }
 
-static struct file_operations dvb_demux_fops = {
+static const struct file_operations dvb_demux_fops = {
        .owner = THIS_MODULE,
        .read = dvb_demux_read,
        .ioctl = dvb_demux_ioctl,
index 7e3aeaa7370f3a6ed3bf45700694e1c6fddae322..cb22da53bfb0fb126a7760a58b95339b0ae76a5a 100644 (file)
@@ -1607,7 +1607,7 @@ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait)
 EXPORT_SYMBOL(dvb_ca_en50221_init);
 
 
-static struct file_operations dvb_ca_fops = {
+static const struct file_operations dvb_ca_fops = {
        .owner = THIS_MODULE,
        .read = dvb_ca_en50221_io_read,
        .write = dvb_ca_en50221_io_write,
index 8dcb3fbf7acd9df47e9dc45e04d33b185e6b3a9d..ebc78157b9b8ced38cf637b9c336a0009f868836 100644 (file)
@@ -1875,7 +1875,7 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
        return ret;
 }
 
-static struct file_operations dvb_frontend_fops = {
+static const struct file_operations dvb_frontend_fops = {
        .owner          = THIS_MODULE,
        .ioctl          = dvb_generic_ioctl,
        .poll           = dvb_frontend_poll,
index f6ba8468858ef34a8f1bbf99e18fab7c6b10df20..8280f8d66a3823264ee8842c106074580b81946b 100644 (file)
@@ -1459,7 +1459,7 @@ static int dvb_net_close(struct inode *inode, struct file *file)
 }
 
 
-static struct file_operations dvb_net_fops = {
+static const struct file_operations dvb_net_fops = {
        .owner = THIS_MODULE,
        .ioctl = dvb_net_ioctl,
        .open = dvb_generic_open,
index 6a32680dbb1b07575f546d75d3132747a34f503f..a454ee8f1e438939ecfd584d7fa90cdd2ec9c7b1 100644 (file)
@@ -228,8 +228,8 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
        dvbdev->fops = dvbdevfops;
        init_waitqueue_head (&dvbdev->wait_queue);
 
-       memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations));
-       dvbdev->fops->owner = adap->module;
+       memcpy(dvbdevfops, template->fops, sizeof(struct file_operations));
+       dvbdevfops->owner = adap->module;
 
        list_add_tail (&dvbdev->list_head, &adap->device_list);
 
index dca49cf962e864c37cefad089669187735f8c524..79927305e84d42e63030e720a43c617c7f493b04 100644 (file)
@@ -71,7 +71,7 @@ struct dvb_adapter {
 
 struct dvb_device {
        struct list_head list_head;
-       struct file_operations *fops;
+       const struct file_operations *fops;
        struct dvb_adapter *adapter;
        int type;
        int minor;
index 49f7b20c25d6f134f883d5c3c1e15cbebeb5a547..6103caad1644917200dca2c6a72c3099b66859da 100644 (file)
@@ -25,7 +25,7 @@ config DVB_USB_A800
        depends on DVB_USB
        select DVB_DIB3000MC
        select DVB_PLL if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
 
@@ -34,7 +34,7 @@ config DVB_USB_DIBUSB_MB
        depends on DVB_USB
        select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_DIB3000MB
-       select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
        help
          Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
          DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
@@ -55,7 +55,7 @@ config DVB_USB_DIBUSB_MC
        tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
        depends on DVB_USB
        select DVB_DIB3000MC
-       select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
        help
          Support for USB2.0 DVB-T receivers based on reference designs made by
          DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
@@ -69,15 +69,17 @@ config DVB_USB_DIBUSB_MC
 config DVB_USB_DIB0700
        tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)"
        depends on DVB_USB
-       select DVB_DIB7000P
-       select DVB_DIB7000M
-       select DVB_DIB3000MC
+       select DVB_DIB7000P if !DVB_FE_CUSTOMISE
+       select DVB_DIB7000M if !DVB_FE_CUSTOMISE
+       select DVB_DIB3000MC if !DVB_FE_CUSTOMISE
        select DVB_S5H1411 if !DVB_FE_CUSTOMISE
-       select DVB_TUNER_DIB0070
-       select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE
+       select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
+       select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
        help
          Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
          USB bridge is also present in devices having the DiB7700 DVB-T-USB
@@ -95,7 +97,8 @@ config DVB_USB_UMT_010
        depends on DVB_USB
        select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_DIB3000MC
-       select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+       select DVB_MT352 if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
 
@@ -108,10 +111,11 @@ config DVB_USB_CXUSB
        select DVB_MT352 if !DVB_FE_CUSTOMISE
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
        select DVB_DIB7000P if !DVB_FE_CUSTOMISE
+       select DVB_LGS8GL5 if !DVB_FE_CUSTOMISE
        select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to support the Conexant USB2.0 hybrid reference design.
          Currently, only DVB and ATSC modes are supported, analog mode
@@ -125,8 +129,8 @@ config DVB_USB_M920X
        depends on DVB_USB
        select DVB_MT352 if !DVB_FE_CUSTOMISE
        select DVB_TDA1004X if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
          Currently, only devices with a product id of
@@ -137,7 +141,7 @@ config DVB_USB_GL861
        tristate "Genesys Logic GL861 USB2.0 support"
        depends on DVB_USB
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
          receiver with USB ID 0db0:5581.
@@ -146,7 +150,7 @@ config DVB_USB_AU6610
        tristate "Alcor Micro AU6610 USB2.0 support"
        depends on DVB_USB
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
 
@@ -199,7 +203,7 @@ config DVB_USB_NOVA_T_USB2
        depends on DVB_USB
        select DVB_DIB3000MC
        select DVB_PLL if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
 
@@ -235,8 +239,8 @@ config DVB_USB_OPERA1
 config DVB_USB_AF9005
        tristate "Afatech AF9005 DVB-T USB1.1 support"
        depends on DVB_USB && EXPERIMENTAL
-       select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
          and the TerraTec Cinergy T USB XE (Rev.1)
@@ -284,7 +288,7 @@ config DVB_USB_DTV5100
        tristate "AME DTV-5100 USB2.0 DVB-T support"
        depends on DVB_USB
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver.
 
@@ -293,9 +297,18 @@ config DVB_USB_AF9015
        depends on DVB_USB && EXPERIMENTAL
        select DVB_AF9013
        select DVB_PLL              if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_MT2060   if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_QT1010   if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_MT2060   if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_QT1010   if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
+
+config DVB_USB_CE6230
+       tristate "Intel CE6230 DVB-T USB2.0 support"
+       depends on DVB_USB && EXPERIMENTAL
+       select DVB_ZL10353
+       select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
+       help
+         Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver
index 3122b7cc2c239b74514339398d29ccd2fbb5809e..f92734ed777a20d4fd6fd78894615212334a9e80 100644 (file)
@@ -76,6 +76,8 @@ obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
 dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o
 obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
 
+dvb-usb-ce6230-objs = ce6230.o
+obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 # due to tuner-xc3028
index 6a97a40d3dfbcf63dc793df361451cb9e0f29607..f0ba8b07b84ff9c144bf02dd6bb303f774128046 100644 (file)
@@ -27,9 +27,7 @@
 #include "qt1010.h"
 #include "tda18271.h"
 #include "mxl5005s.h"
-#if 0
-#include "mc44s80x.h"
-#endif
+#include "mc44s803.h"
 
 static int dvb_usb_af9015_debug;
 module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
@@ -37,9 +35,6 @@ MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
 static int dvb_usb_af9015_remote;
 module_param_named(remote, dvb_usb_af9015_remote, int, 0644);
 MODULE_PARM_DESC(remote, "select remote");
-static int dvb_usb_af9015_dual_mode;
-module_param_named(dual_mode, dvb_usb_af9015_dual_mode, int, 0644);
-MODULE_PARM_DESC(dual_mode, "enable dual mode");
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 static DEFINE_MUTEX(af9015_usb_mutex);
@@ -283,6 +278,21 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
                        req.data = &msg[i+1].buf[0];
                        ret = af9015_ctrl_msg(d, &req);
                        i += 2;
+               } else if (msg[i].flags & I2C_M_RD) {
+                       ret = -EINVAL;
+                       if (msg[i].addr ==
+                               af9015_af9013_config[0].demod_address)
+                               goto error;
+                       else
+                               req.cmd = READ_I2C;
+                       req.i2c_addr = msg[i].addr;
+                       req.addr = addr;
+                       req.mbox = mbox;
+                       req.addr_len = addr_len;
+                       req.data_len = msg[i].len;
+                       req.data = &msg[i].buf[0];
+                       ret = af9015_ctrl_msg(d, &req);
+                       i += 1;
                } else {
                        if (msg[i].addr ==
                                af9015_af9013_config[0].demod_address)
@@ -748,6 +758,16 @@ static int af9015_read_config(struct usb_device *udev)
                                af9015_config.ir_table_size =
                                  ARRAY_SIZE(af9015_ir_table_digittrade);
                                break;
+                       case AF9015_REMOTE_AVERMEDIA_KS:
+                               af9015_properties[i].rc_key_map =
+                                 af9015_rc_keys_avermedia;
+                               af9015_properties[i].rc_key_map_size =
+                                 ARRAY_SIZE(af9015_rc_keys_avermedia);
+                               af9015_config.ir_table =
+                                 af9015_ir_table_avermedia_ks;
+                               af9015_config.ir_table_size =
+                                 ARRAY_SIZE(af9015_ir_table_avermedia_ks);
+                               break;
                        }
                } else {
                        switch (le16_to_cpu(udev->descriptor.idVendor)) {
@@ -836,9 +856,6 @@ static int af9015_read_config(struct usb_device *udev)
                goto error;
        af9015_config.dual_mode = val;
        deb_info("%s: TS mode:%d\n", __func__, af9015_config.dual_mode);
-       /* disable dual mode by default because it is buggy */
-       if (!dvb_usb_af9015_dual_mode)
-               af9015_config.dual_mode = 0;
 
        /* Set adapter0 buffer size according to USB port speed, adapter1 buffer
           size can be static because it is enabled only USB2.0 */
@@ -935,7 +952,6 @@ static int af9015_read_config(struct usb_device *udev)
                switch (val) {
                case AF9013_TUNER_ENV77H11D5:
                case AF9013_TUNER_MT2060:
-               case AF9013_TUNER_MC44S803:
                case AF9013_TUNER_QT1010:
                case AF9013_TUNER_UNKNOWN:
                case AF9013_TUNER_MT2060_2:
@@ -948,6 +964,10 @@ static int af9015_read_config(struct usb_device *udev)
                case AF9013_TUNER_MXL5005R:
                        af9015_af9013_config[i].rf_spec_inv = 0;
                        break;
+               case AF9013_TUNER_MC44S803:
+                       af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO;
+                       af9015_af9013_config[i].rf_spec_inv = 1;
+                       break;
                default:
                        warn("tuner id:%d not supported, please report!", val);
                        return -ENODEV;
@@ -1135,6 +1155,11 @@ static struct mxl5005s_config af9015_mxl5005_config = {
        .AgcMasterByte   = 0x00,
 };
 
+static struct mc44s803_config af9015_mc44s803_config = {
+       .i2c_address = 0xc0,
+       .dig_out = 1,
+};
+
 static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct af9015_state *state = adap->dev->priv;
@@ -1179,15 +1204,8 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
                        DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_MC44S803:
-#if 0
-               ret = dvb_attach(mc44s80x_attach, adap->fe, i2c_adap)
-                       == NULL ? -ENODEV : 0;
-#else
-               ret = -ENODEV;
-               info("Freescale MC44S803 tuner found but no driver for that" \
-                       "tuner. Look at the Linuxtv.org for tuner driver" \
-                       "status.");
-#endif
+               ret = dvb_attach(mc44s803_attach, adap->fe, i2c_adap,
+                       &af9015_mc44s803_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_UNKNOWN:
        default:
@@ -1218,6 +1236,7 @@ static struct usb_device_id af9015_usb_table[] = {
        {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
 /* 15 */{USB_DEVICE(USB_VID_MSI_2,     USB_PID_MSI_DIGI_VOX_MINI_III)},
        {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U)},
+       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_2)},
        {0},
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1417,7 +1436,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                        {
                                .name = "KWorld USB DVB-T TV Stick II " \
                                        "(VS-DVB-T 395U)",
-                               .cold_ids = {&af9015_usb_table[16], NULL},
+                               .cold_ids = {&af9015_usb_table[16],
+                                            &af9015_usb_table[17], NULL},
                                .warm_ids = {NULL},
                        },
                }
index 21c7782f4889c32121d6ac1b3d668319d9e3d961..00e25714662a2ef0ad99ddafeb2273176829466a 100644 (file)
@@ -124,6 +124,7 @@ enum af9015_remote {
        AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
        AF9015_REMOTE_MYGICTV_U718,
        AF9015_REMOTE_DIGITTRADE_DVB_T,
+       AF9015_REMOTE_AVERMEDIA_KS,
 };
 
 /* Leadtek WinFast DTV Dongle Gold */
@@ -597,6 +598,36 @@ static u8 af9015_ir_table_avermedia[] = {
        0x03, 0xfc, 0x03, 0xfc, 0x0e, 0x05, 0x00,
 };
 
+static u8 af9015_ir_table_avermedia_ks[] = {
+       0x05, 0xfa, 0x01, 0xfe, 0x12, 0x05, 0x00,
+       0x05, 0xfa, 0x02, 0xfd, 0x0e, 0x05, 0x00,
+       0x05, 0xfa, 0x03, 0xfc, 0x0d, 0x05, 0x00,
+       0x05, 0xfa, 0x04, 0xfb, 0x2e, 0x05, 0x00,
+       0x05, 0xfa, 0x05, 0xfa, 0x2d, 0x05, 0x00,
+       0x05, 0xfa, 0x06, 0xf9, 0x10, 0x05, 0x00,
+       0x05, 0xfa, 0x07, 0xf8, 0x0f, 0x05, 0x00,
+       0x05, 0xfa, 0x08, 0xf7, 0x3d, 0x05, 0x00,
+       0x05, 0xfa, 0x09, 0xf6, 0x1e, 0x05, 0x00,
+       0x05, 0xfa, 0x0a, 0xf5, 0x1f, 0x05, 0x00,
+       0x05, 0xfa, 0x0b, 0xf4, 0x20, 0x05, 0x00,
+       0x05, 0xfa, 0x0c, 0xf3, 0x21, 0x05, 0x00,
+       0x05, 0xfa, 0x0d, 0xf2, 0x22, 0x05, 0x00,
+       0x05, 0xfa, 0x0e, 0xf1, 0x23, 0x05, 0x00,
+       0x05, 0xfa, 0x0f, 0xf0, 0x24, 0x05, 0x00,
+       0x05, 0xfa, 0x10, 0xef, 0x25, 0x05, 0x00,
+       0x05, 0xfa, 0x11, 0xee, 0x26, 0x05, 0x00,
+       0x05, 0xfa, 0x12, 0xed, 0x27, 0x05, 0x00,
+       0x05, 0xfa, 0x13, 0xec, 0x04, 0x05, 0x00,
+       0x05, 0xfa, 0x15, 0xea, 0x0a, 0x05, 0x00,
+       0x05, 0xfa, 0x16, 0xe9, 0x11, 0x05, 0x00,
+       0x05, 0xfa, 0x17, 0xe8, 0x15, 0x05, 0x00,
+       0x05, 0xfa, 0x18, 0xe7, 0x16, 0x05, 0x00,
+       0x05, 0xfa, 0x1c, 0xe3, 0x05, 0x05, 0x00,
+       0x05, 0xfa, 0x1d, 0xe2, 0x09, 0x05, 0x00,
+       0x05, 0xfa, 0x4d, 0xb2, 0x3f, 0x05, 0x00,
+       0x05, 0xfa, 0x56, 0xa9, 0x3e, 0x05, 0x00
+};
+
 /* Digittrade DVB-T USB Stick */
 static struct dvb_usb_rc_key af9015_rc_keys_digittrade[] = {
        { 0x01, 0x0f, KEY_LAST },       /* RETURN */
diff --git a/drivers/media/dvb/dvb-usb/ce6230.c b/drivers/media/dvb/dvb-usb/ce6230.c
new file mode 100644 (file)
index 0000000..5862820
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ *
+ *    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 "ce6230.h"
+#include "zl10353.h"
+#include "mxl5005s.h"
+
+/* debug */
+static int dvb_usb_ce6230_debug;
+module_param_named(debug, dvb_usb_ce6230_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static struct zl10353_config ce6230_zl10353_config;
+
+static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
+{
+       int ret;
+       unsigned int pipe;
+       u8 request;
+       u8 requesttype;
+       u16 value;
+       u16 index;
+       u8 buf[req->data_len];
+
+       request = req->cmd;
+       value = req->value;
+       index = req->index;
+
+       switch (req->cmd) {
+       case I2C_READ:
+       case DEMOD_READ:
+       case REG_READ:
+               requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+               break;
+       case I2C_WRITE:
+       case DEMOD_WRITE:
+       case REG_WRITE:
+               requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+               break;
+       default:
+               err("unknown command:%02x", req->cmd);
+               ret = -EPERM;
+               goto error;
+       }
+
+       if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
+               /* write */
+               memcpy(buf, req->data, req->data_len);
+               pipe = usb_sndctrlpipe(udev, 0);
+       } else {
+               /* read */
+               pipe = usb_rcvctrlpipe(udev, 0);
+       }
+
+       msleep(1); /* avoid I2C errors */
+
+       ret = usb_control_msg(udev, pipe, request, requesttype, value, index,
+                               buf, sizeof(buf), CE6230_USB_TIMEOUT);
+
+       ce6230_debug_dump(request, requesttype, value, index, buf,
+               req->data_len, deb_xfer);
+
+       if (ret < 0)
+               deb_info("%s: usb_control_msg failed:%d\n", __func__, ret);
+       else
+               ret = 0;
+
+       /* read request, copy returned data to return buf */
+       if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
+               memcpy(req->data, buf, req->data_len);
+
+error:
+       return ret;
+}
+
+static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
+{
+       return ce6230_rw_udev(d->udev, req);
+}
+
+/* I2C */
+static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+                          int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int i = 0;
+       struct req_t req;
+       int ret = 0;
+       memset(&req, 0, sizeof(&req));
+
+       if (num > 2)
+               return -EINVAL;
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       while (i < num) {
+               if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+                       if (msg[i].addr ==
+                               ce6230_zl10353_config.demod_address) {
+                               req.cmd = DEMOD_READ;
+                               req.value = msg[i].addr >> 1;
+                               req.index = msg[i].buf[0];
+                               req.data_len = msg[i+1].len;
+                               req.data = &msg[i+1].buf[0];
+                               ret = ce6230_ctrl_msg(d, &req);
+                       } else {
+                               err("i2c read not implemented");
+                               ret = -EPERM;
+                       }
+                       i += 2;
+               } else {
+                       if (msg[i].addr ==
+                               ce6230_zl10353_config.demod_address) {
+                               req.cmd = DEMOD_WRITE;
+                               req.value = msg[i].addr >> 1;
+                               req.index = msg[i].buf[0];
+                               req.data_len = msg[i].len-1;
+                               req.data = &msg[i].buf[1];
+                               ret = ce6230_ctrl_msg(d, &req);
+                       } else {
+                               req.cmd = I2C_WRITE;
+                               req.value = 0x2000 + (msg[i].addr >> 1);
+                               req.index = 0x0000;
+                               req.data_len = msg[i].len;
+                               req.data = &msg[i].buf[0];
+                               ret = ce6230_ctrl_msg(d, &req);
+                       }
+                       i += 1;
+               }
+               if (ret)
+                       break;
+       }
+
+       mutex_unlock(&d->i2c_mutex);
+       return ret ? ret : i;
+}
+
+static u32 ce6230_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm ce6230_i2c_algo = {
+       .master_xfer   = ce6230_i2c_xfer,
+       .functionality = ce6230_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static struct zl10353_config ce6230_zl10353_config = {
+       .demod_address = 0x1e,
+       .adc_clock = 450000,
+       .if2 = 45700,
+       .no_tuner = 1,
+       .parallel_ts = 1,
+       .clock_ctl_1 = 0x34,
+       .pll_0 = 0x0e,
+};
+
+static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       deb_info("%s:\n", __func__);
+       adap->fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
+               &adap->dev->i2c_adap);
+       if (adap->fe == NULL)
+               return -ENODEV;
+       return 0;
+}
+
+static struct mxl5005s_config ce6230_mxl5003s_config = {
+       .i2c_address     = 0xc6,
+       .if_freq         = IF_FREQ_4570000HZ,
+       .xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+       .agc_mode        = MXL_SINGLE_AGC,
+       .tracking_filter = MXL_TF_DEFAULT,
+       .rssi_enable     = MXL_RSSI_ENABLE,
+       .cap_select      = MXL_CAP_SEL_ENABLE,
+       .div_out         = MXL_DIV_OUT_4,
+       .clock_out       = MXL_CLOCK_OUT_DISABLE,
+       .output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+       .top             = MXL5005S_TOP_25P2,
+       .mod_mode        = MXL_DIGITAL_MODE,
+       .if_mode         = MXL_ZERO_IF,
+       .AgcMasterByte   = 0x00,
+};
+
+static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       int ret;
+       deb_info("%s:\n", __func__);
+       ret = dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap,
+                       &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;
+       return ret;
+}
+
+static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       int ret;
+       deb_info("%s: onoff:%d\n", __func__, onoff);
+
+       /* InterfaceNumber 1 / AlternateSetting 0     idle
+          InterfaceNumber 1 / AlternateSetting 1     streaming */
+       ret = usb_set_interface(d->udev, 1, onoff);
+       if (ret)
+               err("usb_set_interface failed with error:%d", ret);
+
+       return ret;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties ce6230_properties;
+
+static int ce6230_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       int ret = 0;
+       struct dvb_usb_device *d = NULL;
+
+       deb_info("%s: interface:%d\n", __func__,
+               intf->cur_altsetting->desc.bInterfaceNumber);
+
+       if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
+               ret = dvb_usb_device_init(intf, &ce6230_properties, THIS_MODULE,
+                       &d, adapter_nr);
+               if (ret)
+                       err("init failed with error:%d\n", ret);
+       }
+
+       return ret;
+}
+
+static struct usb_device_id ce6230_table[] = {
+       { USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500) },
+       { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, ce6230_table);
+
+static struct dvb_usb_device_properties ce6230_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl = DEVICE_SPECIFIC,
+       .no_reconnect = 1,
+
+       .size_of_priv = 0,
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .frontend_attach  = ce6230_zl10353_frontend_attach,
+                       .tuner_attach     = ce6230_mxl5003s_tuner_attach,
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 6,
+                               .endpoint = 0x82,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 512,
+                                       }
+                               }
+                       },
+               }
+       },
+
+       .power_ctrl = ce6230_power_ctrl,
+
+       .i2c_algo = &ce6230_i2c_algo,
+
+       .num_device_descs = 1,
+       .devices = {
+               {
+                       .name = "Intel CE9500 reference design",
+                       .cold_ids = {NULL},
+                       .warm_ids = {&ce6230_table[0], NULL},
+               },
+       }
+};
+
+static struct usb_driver ce6230_driver = {
+       .name       = "dvb_usb_ce6230",
+       .probe      = ce6230_probe,
+       .disconnect = dvb_usb_device_exit,
+       .id_table   = ce6230_table,
+};
+
+/* module stuff */
+static int __init ce6230_module_init(void)
+{
+       int ret;
+       deb_info("%s:\n", __func__);
+       ret = usb_register(&ce6230_driver);
+       if (ret)
+               err("usb_register failed with error:%d", ret);
+
+       return ret;
+}
+
+static void __exit ce6230_module_exit(void)
+{
+       deb_info("%s:\n", __func__);
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&ce6230_driver);
+}
+
+module_init(ce6230_module_init);
+module_exit(ce6230_module_exit);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Driver for Intel CE6230 DVB-T USB2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/ce6230.h b/drivers/media/dvb/dvb-usb/ce6230.h
new file mode 100644 (file)
index 0000000..97c4248
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ *
+ *    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 _DVB_USB_CE6230_H_
+#define _DVB_USB_CE6230_H_
+
+#define DVB_USB_LOG_PREFIX "ce6230"
+#include "dvb-usb.h"
+
+#define deb_info(args...) dprintk(dvb_usb_ce6230_debug, 0x01, args)
+#define deb_rc(args...)   dprintk(dvb_usb_ce6230_debug, 0x02, args)
+#define deb_xfer(args...) dprintk(dvb_usb_ce6230_debug, 0x04, args)
+#define deb_reg(args...)  dprintk(dvb_usb_ce6230_debug, 0x08, args)
+#define deb_i2c(args...)  dprintk(dvb_usb_ce6230_debug, 0x10, args)
+#define deb_fw(args...)   dprintk(dvb_usb_ce6230_debug, 0x20, args)
+
+#define ce6230_debug_dump(r, t, v, i, b, l, func) { \
+       int loop_; \
+       func("%02x %02x %02x %02x %02x %02x %02x %02x", \
+               t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \
+       if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
+               func(" >>> "); \
+       else \
+               func(" <<< "); \
+       for (loop_ = 0; loop_ < l; loop_++) \
+               func("%02x ", b[loop_]); \
+       func("\n");\
+}
+
+#define CE6230_USB_TIMEOUT 1000
+
+struct req_t {
+       u8  cmd;       /* [1] */
+       u16 value;     /* [2|3] */
+       u16 index;     /* [4|5] */
+       u16 data_len;  /* [6|7] */
+       u8  *data;
+};
+
+enum ce6230_cmd {
+       CONFIG_READ          = 0xd0, /* rd 0 (unclear) */
+       UNKNOWN_WRITE        = 0xc7, /* wr 7 (unclear) */
+       I2C_READ             = 0xd9, /* rd 9 (unclear) */
+       I2C_WRITE            = 0xca, /* wr a */
+       DEMOD_READ           = 0xdb, /* rd b */
+       DEMOD_WRITE          = 0xcc, /* wr c */
+       REG_READ             = 0xde, /* rd e */
+       REG_WRITE            = 0xcf, /* wr f */
+};
+
+#endif
index 200b215f4d8b37f2441bd058b7f9b06f5cb25086..db7f7f79a66ce5796998629fe63ab2e812f34124 100644 (file)
@@ -158,6 +158,10 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
                                err("i2c read error (status = %d)\n", result);
                                break;
                        }
+
+                       deb_data("<<< ");
+                       debug_dump(msg[i].buf, msg[i].len, deb_data);
+
                } else {
                        /* Write request */
                        buf[0] = REQUEST_NEW_I2C_WRITE;
@@ -169,6 +173,9 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
                        /* The Actual i2c payload */
                        memcpy(&buf[4], msg[i].buf, msg[i].len);
 
+                       deb_data(">>> ");
+                       debug_dump(buf, msg[i].len + 4, deb_data);
+
                        result = usb_control_msg(d->udev,
                                                 usb_sndctrlpipe(d->udev, 0),
                                                 REQUEST_NEW_I2C_WRITE,
@@ -211,7 +218,8 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
 
                        /* special thing in the current firmware: when length is zero the read-failed */
                        if ((len = dib0700_ctrl_rd(d, buf, msg[i].len + 2, msg[i+1].buf, msg[i+1].len)) <= 0) {
-                               deb_info("I2C read failed on address %x\n", msg[i].addr);
+                               deb_info("I2C read failed on address 0x%02x\n",
+                                        msg[i].addr);
                                break;
                        }
 
index 635d30a55078d52c76804581cddb6ae4ee0a485c..8ddbadf62194c4733046c3d0e39c702f75c3acb6 100644 (file)
@@ -17,6 +17,8 @@
 #include "xc5000.h"
 #include "s5h1411.h"
 #include "dib0070.h"
+#include "lgdt3305.h"
+#include "mxl5007t.h"
 
 static int force_lna_activation;
 module_param(force_lna_activation, int, 0644);
@@ -262,7 +264,12 @@ static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap)
                msleep(10);
                dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
                msleep(10);
-               dib7000p_i2c_enumeration(&adap->dev->i2c_adap,1,18,stk7700d_dib7000p_mt2266_config);
+               if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+                                            stk7700d_dib7000p_mt2266_config)
+                   != 0) {
+                       err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
+                       return -ENODEV;
+               }
        }
 
        adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1),
@@ -284,7 +291,12 @@ static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
                dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
                msleep(10);
                dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-               dib7000p_i2c_enumeration(&adap->dev->i2c_adap,2,18,stk7700d_dib7000p_mt2266_config);
+               if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18,
+                                            stk7700d_dib7000p_mt2266_config)
+                   != 0) {
+                       err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
+                       return -ENODEV;
+               }
        }
 
        adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1),
@@ -421,8 +433,12 @@ static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap)
        dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
        msleep(10);
 
-       dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
-               &stk7700ph_dib7700_xc3028_config);
+       if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+                                    &stk7700ph_dib7700_xc3028_config) != 0) {
+               err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
+                   __func__);
+               return -ENODEV;
+       }
 
        adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
                &stk7700ph_dib7700_xc3028_config);
@@ -1187,8 +1203,12 @@ static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
        msleep(10);
        dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
 
-       dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
-               &dib7070p_dib7000p_config);
+       if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+                                    &dib7070p_dib7000p_config) != 0) {
+               err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
+                   __func__);
+               return -ENODEV;
+       }
 
        adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
                &dib7070p_dib7000p_config);
@@ -1244,7 +1264,12 @@ static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap)
        msleep(10);
        dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
 
-       dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, stk7070pd_dib7000p_config);
+       if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18,
+                                    stk7070pd_dib7000p_config) != 0) {
+               err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
+                   __func__);
+               return -ENODEV;
+       }
 
        adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]);
        return adap->fe == NULL ? -ENODEV : 0;
@@ -1347,6 +1372,72 @@ static int xc5000_tuner_attach(struct dvb_usb_adapter *adap)
                == NULL ? -ENODEV : 0;
 }
 
+static struct lgdt3305_config hcw_lgdt3305_config = {
+       .i2c_addr           = 0x0e,
+       .mpeg_mode          = LGDT3305_MPEG_PARALLEL,
+       .tpclk_edge         = LGDT3305_TPCLK_FALLING_EDGE,
+       .tpvalid_polarity   = LGDT3305_TP_VALID_LOW,
+       .deny_i2c_rptr      = 0,
+       .spectral_inversion = 1,
+       .qam_if_khz         = 6000,
+       .vsb_if_khz         = 6000,
+       .usref_8vsb         = 0x0500,
+};
+
+static struct mxl5007t_config hcw_mxl5007t_config = {
+       .xtal_freq_hz = MxL_XTAL_25_MHZ,
+       .if_freq_hz = MxL_IF_6_MHZ,
+       .invert_if = 1,
+};
+
+/* TIGER-ATSC map:
+   GPIO0  - LNA_CTR  (H: LNA power enabled, L: LNA power disabled)
+   GPIO1  - ANT_SEL  (H: VPA, L: MCX)
+   GPIO4  - SCL2
+   GPIO6  - EN_TUNER
+   GPIO7  - SDA2
+   GPIO10 - DEM_RST
+
+   MXL is behind LG's i2c repeater.  LG is on SCL2/SDA2 gpios on the DIB
+ */
+static int lgdt3305_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_state *st = adap->dev->priv;
+
+       /* Make use of the new i2c functions from FW 1.20 */
+       st->fw_use_new_i2c_api = 1;
+
+       st->disable_streaming_master_mode = 1;
+
+       /* fe power enable */
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
+       msleep(30);
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+       msleep(30);
+
+       /* demod reset */
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       msleep(30);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+       msleep(30);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       msleep(30);
+
+       adap->fe = dvb_attach(lgdt3305_attach,
+                             &hcw_lgdt3305_config,
+                             &adap->dev->i2c_adap);
+
+       return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static int mxl5007t_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       return dvb_attach(mxl5007t_attach, adap->fe,
+                         &adap->dev->i2c_adap, 0x60,
+                         &hcw_mxl5007t_config) == NULL ? -ENODEV : 0;
+}
+
+
 /* DVB-USB and USB stuff follows */
 struct usb_device_id dib0700_usb_id_table[] = {
 /* 0 */        { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P) },
@@ -1396,6 +1487,12 @@ struct usb_device_id dib0700_usb_id_table[] = {
        { USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_CINERGY_T_EXPRESS) },
        { USB_DEVICE(USB_VID_TERRATEC,
                        USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2) },
+       { USB_DEVICE(USB_VID_SONY,      USB_PID_SONY_PLAYTV) },
+/* 45 */{ USB_DEVICE(USB_VID_YUAN,      USB_PID_YUAN_PD378S) },
+       { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC) },
+       { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC_B210) },
+       { USB_DEVICE(USB_VID_YUAN,      USB_PID_YUAN_MC770) },
+       { USB_DEVICE(USB_VID_ELGATO,    USB_PID_ELGATO_EYETV_DTT) },
        { 0 }           /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -1595,7 +1692,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .num_device_descs = 9,
+               .num_device_descs = 11,
                .devices = {
                        {   "DiBcom STK7070P reference design",
                                { &dib0700_usb_id_table[15], NULL },
@@ -1633,6 +1730,14 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[33], NULL },
                                { NULL },
                        },
+                       {   "Elgato EyeTV DTT",
+                               { &dib0700_usb_id_table[49], NULL },
+                               { NULL },
+                       },
+                       {   "Yuan PD378S",
+                               { &dib0700_usb_id_table[45], NULL },
+                               { NULL },
+                       },
                },
 
                .rc_interval      = DEFAULT_RC_INTERVAL,
@@ -1661,7 +1766,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        }
                },
 
-               .num_device_descs = 5,
+               .num_device_descs = 6,
                .devices = {
                        {   "DiBcom STK7070PD reference design",
                                { &dib0700_usb_id_table[17], NULL },
@@ -1682,8 +1787,16 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        {  "Terratec Cinergy DT USB XS Diversity",
                                { &dib0700_usb_id_table[43], NULL },
                                { NULL },
+                       },
+                       {  "Sony PlayTV",
+                               { &dib0700_usb_id_table[44], NULL },
+                               { NULL },
                        }
-               }
+               },
+               .rc_interval      = DEFAULT_RC_INTERVAL,
+               .rc_key_map       = dib0700_rc_keys,
+               .rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+               .rc_query         = dib0700_rc_query
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
                .num_adapters = 1,
@@ -1699,7 +1812,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .num_device_descs = 5,
+               .num_device_descs = 7,
                .devices = {
                        {   "Terratec Cinergy HT USB XE",
                                { &dib0700_usb_id_table[27], NULL },
@@ -1725,6 +1838,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[39], NULL },
                                { NULL },
                        },
+                       {   "YUAN High-Tech MC770",
+                               { &dib0700_usb_id_table[48], NULL },
+                               { NULL },
+                       },
                },
                .rc_interval      = DEFAULT_RC_INTERVAL,
                .rc_key_map       = dib0700_rc_keys,
@@ -1759,6 +1876,31 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .rc_key_map       = dib0700_rc_keys,
                .rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
                .rc_query         = dib0700_rc_query
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 1,
+               .adapter = {
+                       {
+                               .frontend_attach  = lgdt3305_frontend_attach,
+                               .tuner_attach     = mxl5007t_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+                               .size_of_priv = sizeof(struct
+                                               dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 2,
+               .devices = {
+                       {   "Hauppauge ATSC MiniCard (B200)",
+                               { &dib0700_usb_id_table[46], NULL },
+                               { NULL },
+                       },
+                       {   "Hauppauge ATSC MiniCard (B210)",
+                               { &dib0700_usb_id_table[47], NULL },
+                               { NULL },
+                       },
+               },
        },
 };
 
index 0db0c06ee6f2dcf0783eafb3982a14c37643d110..dc7ea21cd1395ca6b74659be06f2ea9d9a7a6c6b 100644 (file)
 #define USB_VID_DIBCOM                         0x10b8
 #define USB_VID_DPOSH                          0x1498
 #define USB_VID_DVICO                          0x0fe9
+#define USB_VID_ELGATO                         0x0fd9
 #define USB_VID_EMPIA                          0xeb1a
 #define USB_VID_GENPIX                         0x09c0
 #define USB_VID_GRANDTEC                       0x5032
 #define USB_VID_HANFTEK                                0x15f4
 #define USB_VID_HAUPPAUGE                      0x2040
 #define USB_VID_HYPER_PALTEK                   0x1025
+#define USB_VID_INTEL                          0x8086
 #define USB_VID_KWORLD                         0xeb2a
 #define USB_VID_KWORLD_2                       0x1b80
 #define USB_VID_KYE                            0x0458
@@ -48,6 +50,7 @@
 #define USB_VID_TERRATEC                       0x0ccd
 #define USB_VID_TELESTAR                       0x10b9
 #define USB_VID_VISIONPLUS                     0x13d3
+#define USB_VID_SONY                           0x1415
 #define USB_VID_TWINHAN                                0x1822
 #define USB_VID_ULTIMA_ELECTRONIC              0x05d8
 #define USB_VID_UNIWILL                                0x1584
 #define USB_PID_UNIWILL_STK7700P                       0x6003
 #define USB_PID_GRANDTEC_DVBT_USB_COLD                 0x0fa0
 #define USB_PID_GRANDTEC_DVBT_USB_WARM                 0x0fa1
+#define USB_PID_INTEL_CE9500                           0x9500
 #define USB_PID_KWORLD_399U                            0xe399
 #define USB_PID_KWORLD_395U                            0xe396
+#define USB_PID_KWORLD_395U_2                          0xe39b
 #define USB_PID_KWORLD_PC160_2T                                0xc160
 #define USB_PID_KWORLD_VSTREAM_COLD                    0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM                    0x17df
 #define USB_PID_HAUPPAUGE_MYTV_T                       0x7080
 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK                        0x9580
 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009          0x5200
+#define USB_PID_HAUPPAUGE_TIGER_ATSC                   0xb200
+#define USB_PID_HAUPPAUGE_TIGER_ATSC_B210              0xb210
 #define USB_PID_AVERMEDIA_EXPRESS                      0xb568
 #define USB_PID_AVERMEDIA_VOLAR                                0xa807
 #define USB_PID_AVERMEDIA_VOLAR_2                      0xb808
 #define USB_PID_ASUS_U3100                             0x173f
 #define USB_PID_YUAN_EC372S                            0x1edc
 #define USB_PID_YUAN_STK7700PH                         0x1f08
+#define USB_PID_YUAN_PD378S                            0x2edc
+#define USB_PID_YUAN_MC770                             0x0871
 #define USB_PID_DW2102                                 0x2102
 #define USB_PID_XTENSIONS_XD_380                       0x0381
 #define USB_PID_TELESTAR_STARSTICK_2                   0x8000
 #define USB_PID_MSI_DIGI_VOX_MINI_III                   0x8807
+#define USB_PID_SONY_PLAYTV                            0x0003
+#define USB_PID_ELGATO_EYETV_DTT                       0x0021
 
 #endif
index b1de0f7e26e8dce984c41bf6388ed6d2e932bd5d..2d5352e54dc018d05959ab9d83f5634e126d2b83 100644 (file)
@@ -223,7 +223,7 @@ struct dvb_usb_device_properties {
        int generic_bulk_ctrl_endpoint;
 
        int num_device_descs;
-       struct dvb_usb_device_description devices[9];
+       struct dvb_usb_device_description devices[11];
 };
 
 /**
index 32526f103b596290232de5ea652b363074935f21..12f7730184ad32f076060e434d96d450cf6690ca 100644 (file)
@@ -151,7 +151,7 @@ static void debug_fcp(const u8 *data, int length)
                subunit_type = data[1] >> 3;
                subunit_id = data[1] & 7;
                op = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2];
-               printk(KERN_INFO "%ssu=%x.%x l=%d: %-8s - %s\n",
+               printk(KERN_INFO "%ssu=%x.%x l=%zu: %-8s - %s\n",
                       prefix, subunit_type, subunit_id, length,
                       debug_fcp_ctype(data[0]),
                       debug_fcp_opcode(op, data, length));
index 00269560793ae7849d6c320efbd7cfb200a89740..a206cee23f739073b6f6c11e76fd8257a6a9d939 100644 (file)
@@ -1,17 +1,21 @@
-menu "Customise DVB Frontends"
-       depends on DVB_CORE
-
 config DVB_FE_CUSTOMISE
        bool "Customise the frontend modules to build"
+       depends on DVB_CORE
        default N
        help
-         This allows the user to deselect frontend drivers unnecessary
-         for their hardware from the build. Use this option with care
-         as deselecting frontends which are in fact necessary will result
-         in DVB devices which cannot be tuned due to lack of driver support.
+         This allows the user to select/deselect frontend drivers for their
+         hardware from the build.
+
+         Use this option with care as deselecting frontends which are in fact
+         necessary will result in DVB devices which cannot be tuned due to lack
+         of driver support.
 
          If unsure say N.
 
+if DVB_FE_CUSTOMISE
+
+menu "Customise DVB Frontends"
+
 comment "Multistandard (satellite) frontends"
        depends on DVB_CORE
 
@@ -55,6 +59,13 @@ config DVB_MT312
        help
          A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_ZL10036
+       tristate "Zarlink ZL10036 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
@@ -83,6 +94,20 @@ config DVB_STV0299
        help
          A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_STV6110
+       tristate "ST STV6110 silicon tuner"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+         help
+         A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+
+config DVB_STV0900
+       tristate "ST STV0900 based"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-S/S2 demodulator. Say Y when you want to support this frontend.
+
 config DVB_TDA8083
        tristate "Philips TDA8083 based"
        depends on DVB_CORE && I2C
@@ -288,6 +313,13 @@ config DVB_TDA10048
        help
          A DVB-T tuner module. Say Y when you want to support this frontend.
 
+config DVB_AF9013
+       tristate "Afatech AF9013 demodulator"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         Say Y when you want to support this frontend.
+
 comment "DVB-C (cable) frontends"
        depends on DVB_CORE
 
@@ -387,6 +419,14 @@ config DVB_LGDT3304
          An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
          to support this frontend.
 
+config DVB_LGDT3305
+       tristate "LG Electronics LGDT3305 based"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+         to support this frontend.
+
 config DVB_S5H1409
        tristate "Samsung S5H1409 based"
        depends on DVB_CORE && I2C
@@ -397,7 +437,7 @@ config DVB_S5H1409
 
 config DVB_AU8522
        tristate "Auvitek AU8522 based"
-       depends on DVB_CORE && I2C
+       depends on DVB_CORE && I2C && VIDEO_V4L2
        default m if DVB_FE_CUSTOMISE
        help
          An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
@@ -446,11 +486,11 @@ comment "SEC control devices for DVB-S"
        depends on DVB_CORE
 
 config DVB_LNBP21
-       tristate "LNBP21 SEC controller"
+       tristate "LNBP21/LNBH24 SEC controllers"
        depends on DVB_CORE && I2C
        default m if DVB_FE_CUSTOMISE
        help
-         An SEC control chip.
+         An SEC control chips.
 
 config DVB_ISL6405
        tristate "ISL6405 SEC controller"
@@ -478,11 +518,6 @@ comment "Tools to develop new frontends"
 config DVB_DUMMY_FE
        tristate "Dummy frontend driver"
        default n
-
-config DVB_AF9013
-       tristate "Afatech AF9013 demodulator"
-       depends on DVB_CORE && I2C
-       default m if DVB_FE_CUSTOMISE
-       help
-         Say Y when you want to support this frontend.
 endmenu
+
+endif
index af7bdf0ad4c79ae7390d8ae7525e5e04c6f7a51f..65a336aa1db68a79f4466701a6421893917bbf15 100644 (file)
@@ -7,6 +7,8 @@ EXTRA_CFLAGS += -Idrivers/media/common/tuners/
 
 s921-objs := s921_module.o s921_core.o
 stb0899-objs = stb0899_drv.o stb0899_algo.o
+stv0900-objs = stv0900_core.o stv0900_sw.o
+au8522-objs = au8522_dig.o au8522_decoder.o
 
 obj-$(CONFIG_DVB_PLL) += dvb-pll.o
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
@@ -28,6 +30,7 @@ obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
 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_ZL10353) += zl10353.o
 obj-$(CONFIG_DVB_CX22702) += cx22702.o
 obj-$(CONFIG_DVB_DRX397XD) += drx397xD.o
@@ -41,6 +44,7 @@ obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
 obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
 obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
 obj-$(CONFIG_DVB_LGDT3304) += lgdt3304.o
+obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
 obj-$(CONFIG_DVB_CX24123) += cx24123.o
 obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
 obj-$(CONFIG_DVB_ISL6405) += isl6405.o
@@ -64,4 +68,6 @@ obj-$(CONFIG_DVB_SI21XX) += si21xx.o
 obj-$(CONFIG_DVB_STV0288) += stv0288.o
 obj-$(CONFIG_DVB_STB6000) += stb6000.o
 obj-$(CONFIG_DVB_S921) += s921.o
+obj-$(CONFIG_DVB_STV6110) += stv6110.o
+obj-$(CONFIG_DVB_STV0900) += stv0900.o
 
index 7b94f554a09344d02c9bb97122783fe4ca39947b..565dcf31af5767e8891ad64df1a0ce140007ca90 100644 (file)
@@ -74,6 +74,22 @@ struct dvb_frontend *au8522_attach(const struct au8522_config *config,
 }
 #endif /* CONFIG_DVB_AU8522 */
 
+/* Other modes may need to be added later */
+enum au8522_video_input {
+       AU8522_COMPOSITE_CH1 = 1,
+       AU8522_COMPOSITE_CH2,
+       AU8522_COMPOSITE_CH3,
+       AU8522_COMPOSITE_CH4,
+       AU8522_COMPOSITE_CH4_SIF,
+       AU8522_SVIDEO_CH13,
+       AU8522_SVIDEO_CH24,
+};
+
+enum au8522_audio_input {
+       AU8522_AUDIO_NONE,
+       AU8522_AUDIO_SIF,
+};
+
 #endif /* __AU8522_H__ */
 
 /*
diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c
new file mode 100644 (file)
index 0000000..d63e152
--- /dev/null
@@ -0,0 +1,835 @@
+/*
+ * Auvitek AU8522 QAM/8VSB demodulator driver and video decoder
+ *
+ * Copyright (C) 2009 Devin Heitmueller <dheitmueller@linuxtv.org>
+ * Copyright (C) 2005-2008 Auvitek International, Ltd.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/* Developer notes:
+ *
+ * VBI support is not yet working
+ * Saturation and hue setting are not yet working
+ * Enough is implemented here for CVBS and S-Video inputs, but the actual
+ *  analog demodulator code isn't implemented (not needed for xc5000 since it
+ *  has its own demodulator and outputs CVBS)
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
+#include <media/v4l2-device.h>
+#include "au8522.h"
+#include "au8522_priv.h"
+
+MODULE_AUTHOR("Devin Heitmueller");
+MODULE_LICENSE("GPL");
+
+static int au8522_analog_debug;
+
+
+module_param_named(analog_debug, au8522_analog_debug, int, 0644);
+
+MODULE_PARM_DESC(analog_debug,
+                "Analog debugging messages [0=Off (default) 1=On]");
+
+struct au8522_register_config {
+       u16 reg_name;
+       u8 reg_val[8];
+};
+
+
+/* Video Decoder Filter Coefficients
+   The values are as follows from left to right
+   0="ATV RF" 1="ATV RF13" 2="CVBS" 3="S-Video" 4="PAL" 5=CVBS13" 6="SVideo13"
+*/
+struct au8522_register_config filter_coef[] = {
+       {AU8522_FILTER_COEF_R410, {0x25, 0x00, 0x25, 0x25, 0x00, 0x00, 0x00} },
+       {AU8522_FILTER_COEF_R411, {0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00} },
+       {AU8522_FILTER_COEF_R412, {0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00} },
+       {AU8522_FILTER_COEF_R413, {0xe6, 0x00, 0xe6, 0xe6, 0x00, 0x00, 0x00} },
+       {AU8522_FILTER_COEF_R414, {0x40, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00} },
+       {AU8522_FILTER_COEF_R415, {0x1b, 0x00, 0x1b, 0x1b, 0x00, 0x00, 0x00} },
+       {AU8522_FILTER_COEF_R416, {0xc0, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x00} },
+       {AU8522_FILTER_COEF_R417, {0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00} },
+       {AU8522_FILTER_COEF_R418, {0x8c, 0x00, 0x8c, 0x8c, 0x00, 0x00, 0x00} },
+       {AU8522_FILTER_COEF_R419, {0xa0, 0x40, 0xa0, 0xa0, 0x40, 0x40, 0x40} },
+       {AU8522_FILTER_COEF_R41A, {0x21, 0x09, 0x21, 0x21, 0x09, 0x09, 0x09} },
+       {AU8522_FILTER_COEF_R41B, {0x6c, 0x38, 0x6c, 0x6c, 0x38, 0x38, 0x38} },
+       {AU8522_FILTER_COEF_R41C, {0x03, 0xff, 0x03, 0x03, 0xff, 0xff, 0xff} },
+       {AU8522_FILTER_COEF_R41D, {0xbf, 0xc7, 0xbf, 0xbf, 0xc7, 0xc7, 0xc7} },
+       {AU8522_FILTER_COEF_R41E, {0xa0, 0xdf, 0xa0, 0xa0, 0xdf, 0xdf, 0xdf} },
+       {AU8522_FILTER_COEF_R41F, {0x10, 0x06, 0x10, 0x10, 0x06, 0x06, 0x06} },
+       {AU8522_FILTER_COEF_R420, {0xae, 0x30, 0xae, 0xae, 0x30, 0x30, 0x30} },
+       {AU8522_FILTER_COEF_R421, {0xc4, 0x01, 0xc4, 0xc4, 0x01, 0x01, 0x01} },
+       {AU8522_FILTER_COEF_R422, {0x54, 0xdd, 0x54, 0x54, 0xdd, 0xdd, 0xdd} },
+       {AU8522_FILTER_COEF_R423, {0xd0, 0xaf, 0xd0, 0xd0, 0xaf, 0xaf, 0xaf} },
+       {AU8522_FILTER_COEF_R424, {0x1c, 0xf7, 0x1c, 0x1c, 0xf7, 0xf7, 0xf7} },
+       {AU8522_FILTER_COEF_R425, {0x76, 0xdb, 0x76, 0x76, 0xdb, 0xdb, 0xdb} },
+       {AU8522_FILTER_COEF_R426, {0x61, 0xc0, 0x61, 0x61, 0xc0, 0xc0, 0xc0} },
+       {AU8522_FILTER_COEF_R427, {0xd1, 0x2f, 0xd1, 0xd1, 0x2f, 0x2f, 0x2f} },
+       {AU8522_FILTER_COEF_R428, {0x84, 0xd8, 0x84, 0x84, 0xd8, 0xd8, 0xd8} },
+       {AU8522_FILTER_COEF_R429, {0x06, 0xfb, 0x06, 0x06, 0xfb, 0xfb, 0xfb} },
+       {AU8522_FILTER_COEF_R42A, {0x21, 0xd5, 0x21, 0x21, 0xd5, 0xd5, 0xd5} },
+       {AU8522_FILTER_COEF_R42B, {0x0a, 0x3e, 0x0a, 0x0a, 0x3e, 0x3e, 0x3e} },
+       {AU8522_FILTER_COEF_R42C, {0xe6, 0x15, 0xe6, 0xe6, 0x15, 0x15, 0x15} },
+       {AU8522_FILTER_COEF_R42D, {0x01, 0x34, 0x01, 0x01, 0x34, 0x34, 0x34} },
+
+};
+#define NUM_FILTER_COEF (sizeof(filter_coef)\
+                        / sizeof(struct au8522_register_config))
+
+
+/* Registers 0x060b through 0x0652 are the LP Filter coefficients
+   The values are as follows from left to right
+   0="SIF" 1="ATVRF/ATVRF13"
+   Note: the "ATVRF/ATVRF13" mode has never been tested
+*/
+struct au8522_register_config lpfilter_coef[] = {
+       {0x060b, {0x21, 0x0b} },
+       {0x060c, {0xad, 0xad} },
+       {0x060d, {0x70, 0xf0} },
+       {0x060e, {0xea, 0xe9} },
+       {0x060f, {0xdd, 0xdd} },
+       {0x0610, {0x08, 0x64} },
+       {0x0611, {0x60, 0x60} },
+       {0x0612, {0xf8, 0xb2} },
+       {0x0613, {0x01, 0x02} },
+       {0x0614, {0xe4, 0xb4} },
+       {0x0615, {0x19, 0x02} },
+       {0x0616, {0xae, 0x2e} },
+       {0x0617, {0xee, 0xc5} },
+       {0x0618, {0x56, 0x56} },
+       {0x0619, {0x30, 0x58} },
+       {0x061a, {0xf9, 0xf8} },
+       {0x061b, {0x24, 0x64} },
+       {0x061c, {0x07, 0x07} },
+       {0x061d, {0x30, 0x30} },
+       {0x061e, {0xa9, 0xed} },
+       {0x061f, {0x09, 0x0b} },
+       {0x0620, {0x42, 0xc2} },
+       {0x0621, {0x1d, 0x2a} },
+       {0x0622, {0xd6, 0x56} },
+       {0x0623, {0x95, 0x8b} },
+       {0x0624, {0x2b, 0x2b} },
+       {0x0625, {0x30, 0x24} },
+       {0x0626, {0x3e, 0x3e} },
+       {0x0627, {0x62, 0xe2} },
+       {0x0628, {0xe9, 0xf5} },
+       {0x0629, {0x99, 0x19} },
+       {0x062a, {0xd4, 0x11} },
+       {0x062b, {0x03, 0x04} },
+       {0x062c, {0xb5, 0x85} },
+       {0x062d, {0x1e, 0x20} },
+       {0x062e, {0x2a, 0xea} },
+       {0x062f, {0xd7, 0xd2} },
+       {0x0630, {0x15, 0x15} },
+       {0x0631, {0xa3, 0xa9} },
+       {0x0632, {0x1f, 0x1f} },
+       {0x0633, {0xf9, 0xd1} },
+       {0x0634, {0xc0, 0xc3} },
+       {0x0635, {0x4d, 0x8d} },
+       {0x0636, {0x21, 0x31} },
+       {0x0637, {0x83, 0x83} },
+       {0x0638, {0x08, 0x8c} },
+       {0x0639, {0x19, 0x19} },
+       {0x063a, {0x45, 0xa5} },
+       {0x063b, {0xef, 0xec} },
+       {0x063c, {0x8a, 0x8a} },
+       {0x063d, {0xf4, 0xf6} },
+       {0x063e, {0x8f, 0x8f} },
+       {0x063f, {0x44, 0x0c} },
+       {0x0640, {0xef, 0xf0} },
+       {0x0641, {0x66, 0x66} },
+       {0x0642, {0xcc, 0xd2} },
+       {0x0643, {0x41, 0x41} },
+       {0x0644, {0x63, 0x93} },
+       {0x0645, {0x8e, 0x8e} },
+       {0x0646, {0xa2, 0x42} },
+       {0x0647, {0x7b, 0x7b} },
+       {0x0648, {0x04, 0x04} },
+       {0x0649, {0x00, 0x00} },
+       {0x064a, {0x40, 0x40} },
+       {0x064b, {0x8c, 0x98} },
+       {0x064c, {0x00, 0x00} },
+       {0x064d, {0x63, 0xc3} },
+       {0x064e, {0x04, 0x04} },
+       {0x064f, {0x20, 0x20} },
+       {0x0650, {0x00, 0x00} },
+       {0x0651, {0x40, 0x40} },
+       {0x0652, {0x01, 0x01} },
+};
+#define NUM_LPFILTER_COEF (sizeof(lpfilter_coef)\
+                          / sizeof(struct au8522_register_config))
+
+static inline struct au8522_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct au8522_state, sd);
+}
+
+static void setup_vbi(struct au8522_state *state, int aud_input)
+{
+       int i;
+
+       /* These are set to zero regardless of what mode we're in */
+       au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H, 0x00);
+       au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_L_REG018H, 0x00);
+       au8522_writereg(state, AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H, 0x00);
+       au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH, 0x00);
+       au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH, 0x00);
+       au8522_writereg(state, AU8522_TVDEC_VBI_USER_THRESH1_REG01CH, 0x00);
+       au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH, 0x00);
+       au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH, 0x00);
+       au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H, 0x00);
+       au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H,
+                       0x00);
+       au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H,
+                       0x00);
+       au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H,
+                       0x00);
+
+       /* Setup the VBI registers */
+       for (i = 0x30; i < 0x60; i++)
+               au8522_writereg(state, i, 0x40);
+
+       /* For some reason, every register is 0x40 except register 0x44
+          (confirmed via the HVR-950q USB capture) */
+       au8522_writereg(state, 0x44, 0x60);
+
+       /* Enable VBI (we always do this regardless of whether the user is
+          viewing closed caption info) */
+       au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H,
+                       AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON);
+
+}
+
+static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
+{
+       int i;
+       int filter_coef_type;
+
+       /* Provide reasonable defaults for picture tuning values */
+       au8522_writereg(state, AU8522_TVDEC_SHARPNESSREG009H, 0x07);
+       au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, 0xed);
+       state->brightness = 0xed - 128;
+       au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, 0x79);
+       state->contrast = 0x79;
+       au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, 0x80);
+       au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, 0x80);
+       au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, 0x00);
+       au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, 0x00);
+
+       /* Other decoder registers */
+       au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00);
+
+       if (input_mode == 0x23) {
+               /* S-Video input mapping */
+               au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x04);
+       } else {
+               /* All other modes (CVBS/ATVRF etc.) */
+               au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x00);
+       }
+
+       au8522_writereg(state, AU8522_TVDEC_PGA_REG012H,
+                       AU8522_TVDEC_PGA_REG012H_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_COMB_MODE_REG015H,
+                       AU8522_TVDEC_COMB_MODE_REG015H_CVBS);
+       au8522_writereg(state, AU8522_TVDED_DBG_MODE_REG060H,
+                       AU8522_TVDED_DBG_MODE_REG060H_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
+                       AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS13);
+       au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
+                       AU8522_TVDEC_FORMAT_CTRL2_REG062H_CVBS13);
+       au8522_writereg(state, AU8522_TVDEC_VCR_DET_LLIM_REG063H,
+                       AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_VCR_DET_HLIM_REG064H,
+                       AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR1_REG065H,
+                       AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR2_REG066H,
+                       AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR3_REG067H,
+                       AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_COMB_NOTCH_THR_REG068H,
+                       AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR1_REG069H,
+                       AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR2_REG06AH,
+                       AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR3_REG06BH,
+                       AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
+                       AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
+                       AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH,
+                       AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_UV_SEP_THR_REG06FH,
+                       AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H,
+                       AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS);
+       au8522_writereg(state, AU8522_REG071H, AU8522_REG071H_CVBS);
+       au8522_writereg(state, AU8522_REG072H, AU8522_REG072H_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H,
+                       AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS);
+       au8522_writereg(state, AU8522_REG074H, AU8522_REG074H_CVBS);
+       au8522_writereg(state, AU8522_REG075H, AU8522_REG075H_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_DCAGC_CTRL_REG077H,
+                       AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_PIC_START_ADJ_REG078H,
+                       AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H,
+                       AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH,
+                       AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_INTRP_CTRL_REG07BH,
+                       AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS);
+       au8522_writereg(state, AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H,
+                       AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS);
+       au8522_writereg(state, AU8522_TOREGAAGC_REG0E5H,
+                       AU8522_TOREGAAGC_REG0E5H_CVBS);
+       au8522_writereg(state, AU8522_REG016H, AU8522_REG016H_CVBS);
+
+       setup_vbi(state, 0);
+
+       if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
+           input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
+               /* Despite what the table says, for the HVR-950q we still need
+                  to be in CVBS mode for the S-Video input (reason uknown). */
+               /* filter_coef_type = 3; */
+               filter_coef_type = 5;
+       } else {
+               filter_coef_type = 5;
+       }
+
+       /* Load the Video Decoder Filter Coefficients */
+       for (i = 0; i < NUM_FILTER_COEF; i++) {
+               au8522_writereg(state, filter_coef[i].reg_name,
+                               filter_coef[i].reg_val[filter_coef_type]);
+       }
+
+       /* It's not clear what these registers are for, but they are always
+          set to the same value regardless of what mode we're in */
+       au8522_writereg(state, AU8522_REG42EH, 0x87);
+       au8522_writereg(state, AU8522_REG42FH, 0xa2);
+       au8522_writereg(state, AU8522_REG430H, 0xbf);
+       au8522_writereg(state, AU8522_REG431H, 0xcb);
+       au8522_writereg(state, AU8522_REG432H, 0xa1);
+       au8522_writereg(state, AU8522_REG433H, 0x41);
+       au8522_writereg(state, AU8522_REG434H, 0x88);
+       au8522_writereg(state, AU8522_REG435H, 0xc2);
+       au8522_writereg(state, AU8522_REG436H, 0x3c);
+}
+
+static void au8522_setup_cvbs_mode(struct au8522_state *state)
+{
+       /* here we're going to try the pre-programmed route */
+       au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
+                       AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
+
+       au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
+       au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e);
+       au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10);
+
+       au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
+                       AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
+
+       setup_decoder_defaults(state, AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
+
+       au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+                       AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+}
+
+static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state)
+{
+       /* here we're going to try the pre-programmed route */
+       au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
+                       AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
+
+       /* It's not clear why they turn off the PGA before enabling the clamp
+          control, but the Windows trace does it so we will too... */
+       au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
+
+       /* Enable clamping control */
+       au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e);
+
+       /* Turn on the PGA */
+       au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10);
+
+       /* Set input mode to CVBS on channel 4 with SIF audio input enabled */
+       au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
+                       AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF);
+
+       setup_decoder_defaults(state,
+                              AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF);
+
+       au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+                       AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+}
+
+static void au8522_setup_svideo_mode(struct au8522_state *state)
+{
+       au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
+                       AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO);
+
+       /* Set input to Y on Channe1, C on Channel 3 */
+       au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
+                       AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
+
+       /* Disable clamping control (required for S-video) */
+       au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
+
+       setup_decoder_defaults(state,
+                              AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
+
+       au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+                       AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void disable_audio_input(struct au8522_state *state)
+{
+       /* This can probably be optimized */
+       au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
+       au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
+       au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
+       au8522_writereg(state, AU8522_I2C_CONTROL_REG1_REG091H, 0x80);
+       au8522_writereg(state, AU8522_I2C_CONTROL_REG0_REG090H, 0x84);
+
+       au8522_writereg(state, AU8522_ENA_USB_REG101H, 0x00);
+       au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
+       au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
+       au8522_writereg(state, AU8522_REG0F9H, AU8522_REG0F9H_AUDIO);
+       au8522_writereg(state, AU8522_AUDIO_MODE_REG0F1H, 0x40);
+
+       au8522_writereg(state, AU8522_GPIO_DATA_REG0E2H, 0x11);
+       msleep(5);
+       au8522_writereg(state, AU8522_GPIO_DATA_REG0E2H, 0x00);
+
+       au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x04);
+       au8522_writereg(state, AU8522_AUDIOFREQ_REG606H, 0x03);
+       au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0x02);
+
+       au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+                       AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+}
+
+/* 0=disable, 1=SIF */
+static void set_audio_input(struct au8522_state *state, int aud_input)
+{
+       int i;
+
+       /* Note that this function needs to be used in conjunction with setting
+          the input routing via register 0x81 */
+
+       if (aud_input == AU8522_AUDIO_NONE) {
+               disable_audio_input(state);
+               return;
+       }
+
+       if (aud_input != AU8522_AUDIO_SIF) {
+               /* The caller asked for a mode we don't currently support */
+               printk(KERN_ERR "Unsupported audio mode requested! mode=%d\n",
+                      aud_input);
+               return;
+       }
+
+       /* Load the Audio Decoder Filter Coefficients */
+       for (i = 0; i < NUM_LPFILTER_COEF; i++) {
+               au8522_writereg(state, lpfilter_coef[i].reg_name,
+                               lpfilter_coef[i].reg_val[0]);
+       }
+
+       /* Setup audio */
+       au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
+       au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
+       au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
+       au8522_writereg(state, AU8522_I2C_CONTROL_REG1_REG091H, 0x80);
+       au8522_writereg(state, AU8522_I2C_CONTROL_REG0_REG090H, 0x84);
+       msleep(150);
+       au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x00);
+       msleep(1);
+       au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x9d);
+       msleep(50);
+       au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
+       au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
+       au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0xff);
+       msleep(80);
+       au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
+       au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
+       au8522_writereg(state, AU8522_REG0F9H, AU8522_REG0F9H_AUDIO);
+       au8522_writereg(state, AU8522_AUDIO_MODE_REG0F1H, 0x82);
+       msleep(70);
+       au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x09);
+       au8522_writereg(state, AU8522_AUDIOFREQ_REG606H, 0x03);
+       au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0xc2);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int au8522_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct au8522_state *state = to_state(sd);
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               state->brightness = ctrl->value;
+               au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH,
+                               ctrl->value - 128);
+               break;
+       case V4L2_CID_CONTRAST:
+               state->contrast = ctrl->value;
+               au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH,
+                               ctrl->value);
+               break;
+       case V4L2_CID_SATURATION:
+       case V4L2_CID_HUE:
+       case V4L2_CID_AUDIO_VOLUME:
+       case V4L2_CID_AUDIO_BASS:
+       case V4L2_CID_AUDIO_TREBLE:
+       case V4L2_CID_AUDIO_BALANCE:
+       case V4L2_CID_AUDIO_MUTE:
+               /* Not yet implemented */
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct au8522_state *state = to_state(sd);
+
+       /* Note that we are using values cached in the state structure instead
+          of reading the registers due to issues with i2c reads not working
+          properly/consistently yet on the HVR-950q */
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ctrl->value = state->brightness;
+               break;
+       case V4L2_CID_CONTRAST:
+               ctrl->value = state->contrast;
+               break;
+       case V4L2_CID_SATURATION:
+       case V4L2_CID_HUE:
+       case V4L2_CID_AUDIO_VOLUME:
+       case V4L2_CID_AUDIO_BASS:
+       case V4L2_CID_AUDIO_TREBLE:
+       case V4L2_CID_AUDIO_BALANCE:
+       case V4L2_CID_AUDIO_MUTE:
+               /* Not yet supported */
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int au8522_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+       switch (fmt->type) {
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int au8522_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+       switch (fmt->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               /* Not yet implemented */
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int au8522_g_register(struct v4l2_subdev *sd,
+                            struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct au8522_state *state = to_state(sd);
+
+       if (!v4l2_chip_match_i2c_client(client, &reg->match))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       reg->val = au8522_readreg(state, reg->reg & 0xffff);
+       return 0;
+}
+
+static int au8522_s_register(struct v4l2_subdev *sd,
+                            struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct au8522_state *state = to_state(sd);
+
+       if (!v4l2_chip_match_i2c_client(client, &reg->match))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       au8522_writereg(state, reg->reg, reg->val & 0xff);
+       return 0;
+}
+#endif
+
+static int au8522_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct au8522_state *state = to_state(sd);
+
+       if (enable) {
+               au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+                               0x01);
+               msleep(1);
+               au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+                               AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+       } else {
+               /* This does not completely power down the device
+                  (it only reduces it from around 140ma to 80ma) */
+               au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+                               1 << 5);
+       }
+       return 0;
+}
+
+static int au8522_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       switch (qc->id) {
+       case V4L2_CID_CONTRAST:
+               return v4l2_ctrl_query_fill(qc, 0, 255, 1,
+                                           AU8522_TVDEC_CONTRAST_REG00BH_CVBS);
+       case V4L2_CID_BRIGHTNESS:
+               return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
+       case V4L2_CID_SATURATION:
+       case V4L2_CID_HUE:
+               /* Not yet implemented */
+       default:
+               break;
+       }
+
+       qc->type = 0;
+       return -EINVAL;
+}
+
+static int au8522_reset(struct v4l2_subdev *sd, u32 val)
+{
+       struct au8522_state *state = to_state(sd);
+
+       au8522_writereg(state, 0xa4, 1 << 5);
+
+       return 0;
+}
+
+static int au8522_s_video_routing(struct v4l2_subdev *sd,
+                                 const struct v4l2_routing *route)
+{
+       struct au8522_state *state = to_state(sd);
+
+       au8522_reset(sd, 0);
+
+       /* Jam open the i2c gate to the tuner.  We do this here to handle the
+          case where the user went into digital mode (causing the gate to be
+          closed), and then came back to analog mode */
+       au8522_writereg(state, 0x106, 1);
+
+       if (route->input == AU8522_COMPOSITE_CH1) {
+               au8522_setup_cvbs_mode(state);
+       } else if (route->input == AU8522_SVIDEO_CH13) {
+               au8522_setup_svideo_mode(state);
+       } else if (route->input == AU8522_COMPOSITE_CH4_SIF) {
+               au8522_setup_cvbs_tuner_mode(state);
+       } else {
+               printk(KERN_ERR "au8522 mode not currently supported\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int au8522_s_audio_routing(struct v4l2_subdev *sd,
+                                 const struct v4l2_routing *route)
+{
+       struct au8522_state *state = to_state(sd);
+       set_audio_input(state, route->input);
+       return 0;
+}
+
+static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       int val = 0;
+       struct au8522_state *state = to_state(sd);
+       u8 lock_status;
+
+       /* Interrogate the decoder to see if we are getting a real signal */
+       lock_status = au8522_readreg(state, 0x00);
+       if (lock_status == 0xa2)
+               vt->signal = 0x01;
+       else
+               vt->signal = 0x00;
+
+       vt->capability |=
+               V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+               V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+
+       val = V4L2_TUNER_SUB_MONO;
+       vt->rxsubchans = val;
+       vt->audmode = V4L2_TUNER_MODE_STEREO;
+       return 0;
+}
+
+static int au8522_g_chip_ident(struct v4l2_subdev *sd,
+                              struct v4l2_dbg_chip_ident *chip)
+{
+       struct au8522_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev);
+}
+
+static int au8522_log_status(struct v4l2_subdev *sd)
+{
+       /* FIXME: Add some status info here */
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops au8522_core_ops = {
+       .log_status = au8522_log_status,
+       .g_chip_ident = au8522_g_chip_ident,
+       .g_ctrl = au8522_g_ctrl,
+       .s_ctrl = au8522_s_ctrl,
+       .queryctrl = au8522_queryctrl,
+       .reset = au8522_reset,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = au8522_g_register,
+       .s_register = au8522_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops au8522_tuner_ops = {
+       .g_tuner = au8522_g_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops au8522_audio_ops = {
+       .s_routing = au8522_s_audio_routing,
+};
+
+static const struct v4l2_subdev_video_ops au8522_video_ops = {
+       .s_routing = au8522_s_video_routing,
+       .g_fmt = au8522_g_fmt,
+       .s_fmt = au8522_s_fmt,
+       .s_stream = au8522_s_stream,
+};
+
+static const struct v4l2_subdev_ops au8522_ops = {
+       .core = &au8522_core_ops,
+       .tuner = &au8522_tuner_ops,
+       .audio = &au8522_audio_ops,
+       .video = &au8522_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int au8522_probe(struct i2c_client *client,
+                       const struct i2c_device_id *did)
+{
+       struct au8522_state *state;
+       struct v4l2_subdev *sd;
+       int instance;
+       struct au8522_config *demod_config;
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_BYTE_DATA)) {
+               return -EIO;
+       }
+
+       /* allocate memory for the internal state */
+       instance = au8522_get_state(&state, client->adapter, client->addr);
+       switch (instance) {
+       case 0:
+               printk(KERN_ERR "au8522_decoder allocation failed\n");
+               return -EIO;
+       case 1:
+               /* new demod instance */
+               printk(KERN_INFO "au8522_decoder creating new instance...\n");
+               break;
+       default:
+               /* existing demod instance */
+               printk(KERN_INFO "au8522_decoder attach existing instance.\n");
+               break;
+       }
+
+       demod_config = kzalloc(sizeof(struct au8522_config), GFP_KERNEL);
+       demod_config->demod_address = 0x8e >> 1;
+
+       state->config = demod_config;
+       state->i2c = client->adapter;
+
+       sd = &state->sd;
+       v4l2_i2c_subdev_init(sd, client, &au8522_ops);
+
+       state->c = client;
+       state->vid_input = AU8522_COMPOSITE_CH1;
+       state->aud_input = AU8522_AUDIO_NONE;
+       state->id = 8522;
+       state->rev = 0;
+
+       /* Jam open the i2c gate to the tuner */
+       au8522_writereg(state, 0x106, 1);
+
+       return 0;
+}
+
+static int au8522_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       v4l2_device_unregister_subdev(sd);
+       au8522_release_state(to_state(sd));
+       return 0;
+}
+
+static const struct i2c_device_id au8522_id[] = {
+       {"au8522", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, au8522_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "au8522",
+       .probe = au8522_probe,
+       .remove = au8522_remove,
+       .id_table = au8522_id,
+};
similarity index 91%
rename from drivers/media/dvb/frontends/au8522.c
rename to drivers/media/dvb/frontends/au8522_dig.c
index eabf9a68e7ec36362ec3aab2c46f076ebfa54273..35731258bb0a7b6d2025c7df0192c5e5bba8a2d7 100644 (file)
 #include <linux/delay.h>
 #include "dvb_frontend.h"
 #include "au8522.h"
-
-struct au8522_state {
-
-       struct i2c_adapter *i2c;
-
-       /* configuration settings */
-       const struct au8522_config *config;
-
-       struct dvb_frontend frontend;
-
-       u32 current_frequency;
-       fe_modulation_t current_modulation;
-
-       u32 fe_status;
-       unsigned int led_state;
-};
+#include "au8522_priv.h"
 
 static int debug;
 
-#define dprintk(arg...) do {           \
-       if (debug)                      \
-                printk(arg);           \
+/* Despite the name "hybrid_tuner", the framework works just as well for
+   hybrid demodulators as well... */
+static LIST_HEAD(hybrid_tuner_instance_list);
+static DEFINE_MUTEX(au8522_list_mutex);
+
+#define dprintk(arg...)\
+       do { if (debug)\
+               printk(arg);\
        } while (0)
 
 /* 16 bit registers, 8 bit values */
-static int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
+int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
 {
        int ret;
-       u8 buf [] = { reg >> 8, reg & 0xff, data };
+       u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
 
        struct i2c_msg msg = { .addr = state->config->demod_address,
                               .flags = 0, .buf = buf, .len = 3 };
@@ -69,13 +59,13 @@ static int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
        return (ret != 1) ? -1 : 0;
 }
 
-static u8 au8522_readreg(struct au8522_state *state, u16 reg)
+u8 au8522_readreg(struct au8522_state *state, u16 reg)
 {
        int ret;
-       u8 b0 [] = { reg >> 8, reg & 0xff };
-       u8 b1 [] = { 0 };
+       u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
+       u8 b1[] = { 0 };
 
-       struct i2c_msg msg [] = {
+       struct i2c_msg msg[] = {
                { .addr = state->config->demod_address, .flags = 0,
                  .buf = b0, .len = 2 },
                { .addr = state->config->demod_address, .flags = I2C_M_RD,
@@ -528,7 +518,7 @@ static int au8522_set_frontend(struct dvb_frontend *fe,
 
 /* Reset the demod hardware and reset all of the configuration registers
    to a default state. */
-static int au8522_init(struct dvb_frontend *fe)
+int au8522_init(struct dvb_frontend *fe)
 {
        struct au8522_state *state = fe->demodulator_priv;
        dprintk("%s()\n", __func__);
@@ -624,7 +614,7 @@ static int au8522_led_ctrl(struct au8522_state *state, int led)
        return 0;
 }
 
-static int au8522_sleep(struct dvb_frontend *fe)
+int au8522_sleep(struct dvb_frontend *fe)
 {
        struct au8522_state *state = fe->demodulator_priv;
        dprintk("%s()\n", __func__);
@@ -632,6 +622,9 @@ static int au8522_sleep(struct dvb_frontend *fe)
        /* turn off led */
        au8522_led_ctrl(state, 0);
 
+       /* Power down the chip */
+       au8522_writereg(state, 0xa4, 1 << 5);
+
        state->current_frequency = 0;
 
        return 0;
@@ -798,23 +791,58 @@ static int au8522_get_tune_settings(struct dvb_frontend *fe,
        return 0;
 }
 
+static struct dvb_frontend_ops au8522_ops;
+
+int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
+                    u8 client_address)
+{
+       int ret;
+
+       mutex_lock(&au8522_list_mutex);
+       ret = hybrid_tuner_request_state(struct au8522_state, (*state),
+                                        hybrid_tuner_instance_list,
+                                        i2c, client_address, "au8522");
+       mutex_unlock(&au8522_list_mutex);
+
+       return ret;
+}
+
+void au8522_release_state(struct au8522_state *state)
+{
+       mutex_lock(&au8522_list_mutex);
+       if (state != NULL)
+               hybrid_tuner_release_state(state);
+       mutex_unlock(&au8522_list_mutex);
+}
+
+
 static void au8522_release(struct dvb_frontend *fe)
 {
        struct au8522_state *state = fe->demodulator_priv;
-       kfree(state);
+       au8522_release_state(state);
 }
 
-static struct dvb_frontend_ops au8522_ops;
-
 struct dvb_frontend *au8522_attach(const struct au8522_config *config,
                                   struct i2c_adapter *i2c)
 {
        struct au8522_state *state = NULL;
+       int instance;
 
        /* allocate memory for the internal state */
-       state = kmalloc(sizeof(struct au8522_state), GFP_KERNEL);
-       if (state == NULL)
-               goto error;
+       instance = au8522_get_state(&state, i2c, config->demod_address);
+       switch (instance) {
+       case 0:
+               dprintk("%s state allocation failed\n", __func__);
+               break;
+       case 1:
+               /* new demod instance */
+               dprintk("%s using new instance\n", __func__);
+               break;
+       default:
+               /* existing demod instance */
+               dprintk("%s using existing instance\n", __func__);
+               break;
+       }
 
        /* setup the state */
        state->config = config;
@@ -836,7 +864,7 @@ struct dvb_frontend *au8522_attach(const struct au8522_config *config,
        return &state->frontend;
 
 error:
-       kfree(state);
+       au8522_release_state(state);
        return NULL;
 }
 EXPORT_SYMBOL(au8522_attach);
diff --git a/drivers/media/dvb/frontends/au8522_priv.h b/drivers/media/dvb/frontends/au8522_priv.h
new file mode 100644 (file)
index 0000000..f328f2b
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+    Auvitek AU8522 QAM/8VSB demodulator driver
+
+    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+    Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org>
+    Copyright (C) 2005-2008 Auvitek International, Ltd.
+
+    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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+#include "au8522.h"
+#include "tuner-i2c.h"
+
+struct au8522_state {
+       struct i2c_client *c;
+       struct i2c_adapter *i2c;
+
+       /* Used for sharing of the state between analog and digital mode */
+       struct tuner_i2c_props i2c_props;
+       struct list_head hybrid_tuner_instance_list;
+
+       /* configuration settings */
+       const struct au8522_config *config;
+
+       struct dvb_frontend frontend;
+
+       u32 current_frequency;
+       fe_modulation_t current_modulation;
+
+       u32 fe_status;
+       unsigned int led_state;
+
+       /* Analog settings */
+       struct v4l2_subdev sd;
+       v4l2_std_id std;
+       int vid_input;
+       int aud_input;
+       u32 id;
+       u32 rev;
+       u8 brightness;
+       u8 contrast;
+};
+
+/* These are routines shared by both the VSB/QAM demodulator and the analog
+   decoder */
+int au8522_writereg(struct au8522_state *state, u16 reg, u8 data);
+u8 au8522_readreg(struct au8522_state *state, u16 reg);
+int au8522_init(struct dvb_frontend *fe);
+int au8522_sleep(struct dvb_frontend *fe);
+
+int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
+                    u8 client_address);
+void au8522_release_state(struct au8522_state *state);
+
+/* REGISTERS */
+#define AU8522_INPUT_CONTROL_REG081H                   0x081
+#define AU8522_PGA_CONTROL_REG082H                     0x082
+#define AU8522_CLAMPING_CONTROL_REG083H                        0x083
+
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H            0x0A3
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H         0x0A4
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H         0x0A5
+#define AU8522_AGC_CONTROL_RANGE_REG0A6H               0x0A6
+#define AU8522_SYSTEM_GAIN_CONTROL_REG0A7H             0x0A7
+#define AU8522_TUNER_AGC_RF_STOP_REG0A8H               0x0A8
+#define AU8522_TUNER_AGC_RF_START_REG0A9H              0x0A9
+#define AU8522_TUNER_RF_AGC_DEFAULT_REG0AAH            0x0AA
+#define AU8522_TUNER_AGC_IF_STOP_REG0ABH               0x0AB
+#define AU8522_TUNER_AGC_IF_START_REG0ACH              0x0AC
+#define AU8522_TUNER_AGC_IF_DEFAULT_REG0ADH            0x0AD
+#define AU8522_TUNER_AGC_STEP_REG0AEH                  0x0AE
+#define AU8522_TUNER_GAIN_STEP_REG0AFH                 0x0AF
+
+/* Receiver registers */
+#define AU8522_FRMREGTHRD1_REG0B0H                     0x0B0
+#define AU8522_FRMREGAGC1H_REG0B1H                     0x0B1
+#define AU8522_FRMREGSHIFT1_REG0B2H                    0x0B2
+#define AU8522_TOREGAGC1_REG0B3H                       0x0B3
+#define AU8522_TOREGASHIFT1_REG0B4H                    0x0B4
+#define AU8522_FRMREGBBH_REG0B5H                       0x0B5
+#define AU8522_FRMREGBBM_REG0B6H                       0x0B6
+#define AU8522_FRMREGBBL_REG0B7H                       0x0B7
+/* 0xB8 TO 0xD7 are the filter coefficients */
+#define AU8522_FRMREGTHRD2_REG0D8H                     0x0D8
+#define AU8522_FRMREGAGC2H_REG0D9H                     0x0D9
+#define AU8522_TOREGAGC2_REG0DAH                       0x0DA
+#define AU8522_TOREGSHIFT2_REG0DBH                     0x0DB
+#define AU8522_FRMREGPILOTH_REG0DCH                    0x0DC
+#define AU8522_FRMREGPILOTM_REG0DDH                    0x0DD
+#define AU8522_FRMREGPILOTL_REG0DEH                    0x0DE
+#define AU8522_TOREGFREQ_REG0DFH                       0x0DF
+
+#define AU8522_RX_PGA_RFOUT_REG0EBH                    0x0EB
+#define AU8522_RX_PGA_IFOUT_REG0ECH                    0x0EC
+#define AU8522_RX_PGA_PGAOUT_REG0EDH                   0x0ED
+
+#define AU8522_CHIP_MODE_REG0FEH                       0x0FE
+
+/* I2C bus control registers */
+#define AU8522_I2C_CONTROL_REG0_REG090H                0x090
+#define AU8522_I2C_CONTROL_REG1_REG091H                0x091
+#define AU8522_I2C_STATUS_REG092H                      0x092
+#define AU8522_I2C_WR_DATA0_REG093H                    0x093
+#define AU8522_I2C_WR_DATA1_REG094H                    0x094
+#define AU8522_I2C_WR_DATA2_REG095H                    0x095
+#define AU8522_I2C_WR_DATA3_REG096H                    0x096
+#define AU8522_I2C_WR_DATA4_REG097H                    0x097
+#define AU8522_I2C_WR_DATA5_REG098H                    0x098
+#define AU8522_I2C_WR_DATA6_REG099H                    0x099
+#define AU8522_I2C_WR_DATA7_REG09AH                    0x09A
+#define AU8522_I2C_RD_DATA0_REG09BH                    0x09B
+#define AU8522_I2C_RD_DATA1_REG09CH                    0x09C
+#define AU8522_I2C_RD_DATA2_REG09DH                    0x09D
+#define AU8522_I2C_RD_DATA3_REG09EH                    0x09E
+#define AU8522_I2C_RD_DATA4_REG09FH                    0x09F
+#define AU8522_I2C_RD_DATA5_REG0A0H                    0x0A0
+#define AU8522_I2C_RD_DATA6_REG0A1H                    0x0A1
+#define AU8522_I2C_RD_DATA7_REG0A2H                    0x0A2
+
+#define AU8522_ENA_USB_REG101H                         0x101
+
+#define AU8522_I2S_CTRL_0_REG110H                      0x110
+#define AU8522_I2S_CTRL_1_REG111H                      0x111
+#define AU8522_I2S_CTRL_2_REG112H                      0x112
+
+#define AU8522_FRMREGFFECONTROL_REG121H                0x121
+#define AU8522_FRMREGDFECONTROL_REG122H                0x122
+
+#define AU8522_CARRFREQOFFSET0_REG201H                         0x201
+#define AU8522_CARRFREQOFFSET1_REG202H                 0x202
+
+#define AU8522_DECIMATION_GAIN_REG21AH                 0x21A
+#define AU8522_FRMREGIFSLP_REG21BH                     0x21B
+#define AU8522_FRMREGTHRDL2_REG21CH                    0x21C
+#define AU8522_FRMREGSTEP3DB_REG21DH                   0x21D
+#define AU8522_DAGC_GAIN_ADJUSTMENT_REG21EH            0x21E
+#define AU8522_FRMREGPLLMODE_REG21FH                   0x21F
+#define AU8522_FRMREGCSTHRD_REG220H                    0x220
+#define AU8522_FRMREGCRLOCKDMAX_REG221H                0x221
+#define AU8522_FRMREGCRPERIODMASK_REG222H              0x222
+#define AU8522_FRMREGCRLOCK0THH_REG223H                0x223
+#define AU8522_FRMREGCRLOCK1THH_REG224H                0x224
+#define AU8522_FRMREGCRLOCK0THL_REG225H                0x225
+#define AU8522_FRMREGCRLOCK1THL_REG226H                0x226
+#define AU_FRMREGPLLACQPHASESCL_REG227H                        0x227
+#define AU8522_FRMREGFREQFBCTRL_REG228H                0x228
+
+/* Analog TV Decoder */
+#define AU8522_TVDEC_STATUS_REG000H                    0x000
+#define AU8522_TVDEC_INT_STATUS_REG001H                        0x001
+#define AU8522_TVDEC_MACROVISION_STATUS_REG002H        0x002
+#define AU8522_TVDEC_SHARPNESSREG009H                  0x009
+#define AU8522_TVDEC_BRIGHTNESS_REG00AH                        0x00A
+#define AU8522_TVDEC_CONTRAST_REG00BH                  0x00B
+#define AU8522_TVDEC_SATURATION_CB_REG00CH             0x00C
+#define AU8522_TVDEC_SATURATION_CR_REG00DH             0x00D
+#define AU8522_TVDEC_HUE_H_REG00EH                     0x00E
+#define AU8522_TVDEC_HUE_L_REG00FH                     0x00F
+#define AU8522_TVDEC_INT_MASK_REG010H                  0x010
+#define AU8522_VIDEO_MODE_REG011H                      0x011
+#define AU8522_TVDEC_PGA_REG012H                       0x012
+#define AU8522_TVDEC_COMB_MODE_REG015H                 0x015
+#define AU8522_REG016H                                 0x016
+#define AU8522_TVDED_DBG_MODE_REG060H                  0x060
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H              0x061
+#define AU8522_TVDEC_FORMAT_CTRL2_REG062H              0x062
+#define AU8522_TVDEC_VCR_DET_LLIM_REG063H              0x063
+#define AU8522_TVDEC_VCR_DET_HLIM_REG064H              0x064
+#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H            0x065
+#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H            0x066
+#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H            0x067
+#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H            0x068
+#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H            0x069
+#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH            0x06A
+#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH            0x06B
+#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH           0x06C
+#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH           0x06D
+#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH           0x06E
+#define AU8522_TVDEC_UV_SEP_THR_REG06FH                0x06F
+#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H         0x070
+#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H         0x073
+#define AU8522_TVDEC_DCAGC_CTRL_REG077H                        0x077
+#define AU8522_TVDEC_PIC_START_ADJ_REG078H             0x078
+#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H            0x079
+#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH      0x07A
+#define AU8522_TVDEC_INTRP_CTRL_REG07BH                        0x07B
+#define AU8522_TVDEC_PLL_STATUS_REG07EH                        0x07E
+#define AU8522_TVDEC_FSC_FREQ_REG07FH                  0x07F
+
+#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H             0x0E4
+#define AU8522_TOREGAAGC_REG0E5H                       0x0E5
+
+#define AU8522_TVDEC_CHROMA_AGC_REG401H                0x401
+#define AU8522_TVDEC_CHROMA_SFT_REG402H                0x402
+#define AU8522_FILTER_COEF_R410                0x410
+#define AU8522_FILTER_COEF_R411                0x411
+#define AU8522_FILTER_COEF_R412                0x412
+#define AU8522_FILTER_COEF_R413                0x413
+#define AU8522_FILTER_COEF_R414                0x414
+#define AU8522_FILTER_COEF_R415                0x415
+#define AU8522_FILTER_COEF_R416                0x416
+#define AU8522_FILTER_COEF_R417                0x417
+#define AU8522_FILTER_COEF_R418                0x418
+#define AU8522_FILTER_COEF_R419                0x419
+#define AU8522_FILTER_COEF_R41A                0x41A
+#define AU8522_FILTER_COEF_R41B                0x41B
+#define AU8522_FILTER_COEF_R41C                0x41C
+#define AU8522_FILTER_COEF_R41D                0x41D
+#define AU8522_FILTER_COEF_R41E                0x41E
+#define AU8522_FILTER_COEF_R41F                0x41F
+#define AU8522_FILTER_COEF_R420                0x420
+#define AU8522_FILTER_COEF_R421                0x421
+#define AU8522_FILTER_COEF_R422                0x422
+#define AU8522_FILTER_COEF_R423                0x423
+#define AU8522_FILTER_COEF_R424                0x424
+#define AU8522_FILTER_COEF_R425                0x425
+#define AU8522_FILTER_COEF_R426                0x426
+#define AU8522_FILTER_COEF_R427                0x427
+#define AU8522_FILTER_COEF_R428                0x428
+#define AU8522_FILTER_COEF_R429                0x429
+#define AU8522_FILTER_COEF_R42A                0x42A
+#define AU8522_FILTER_COEF_R42B                0x42B
+#define AU8522_FILTER_COEF_R42C                0x42C
+#define AU8522_FILTER_COEF_R42D                0x42D
+
+/* VBI Control Registers */
+#define AU8522_TVDEC_VBI_RX_FIFO_CONTAIN_REG004H       0x004
+#define AU8522_TVDEC_VBI_TX_FIFO_CONTAIN_REG005H       0x005
+#define AU8522_TVDEC_VBI_RX_FIFO_READ_REG006H          0x006
+#define AU8522_TVDEC_VBI_FIFO_STATUS_REG007H           0x007
+#define AU8522_TVDEC_VBI_CTRL_H_REG017H                        0x017
+#define AU8522_TVDEC_VBI_CTRL_L_REG018H                        0x018
+#define AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H       0x019
+#define AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH          0x01A
+#define AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH          0x01B
+#define AU8522_TVDEC_VBI_USER_THRESH1_REG01CH          0x01C
+#define AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH       0x01E
+#define AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH       0x01F
+#define AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H       0x020
+#define AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H      0x021
+#define AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H      0x022
+#define AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H      0x023
+
+#define AU8522_REG071H                                 0x071
+#define AU8522_REG072H                                 0x072
+#define AU8522_REG074H                                 0x074
+#define AU8522_REG075H                                 0x075
+
+/* Digital Demodulator Registers */
+#define AU8522_FRAME_COUNT0_REG084H                    0x084
+#define AU8522_RS_STATUS_G0_REG085H                    0x085
+#define AU8522_RS_STATUS_B0_REG086H                    0x086
+#define AU8522_RS_STATUS_E_REG087H                     0x087
+#define AU8522_DEMODULATION_STATUS_REG088H             0x088
+#define AU8522_TOREGTRESTATUS_REG0E6H                  0x0E6
+#define AU8522_TSPORT_CONTROL_REG10BH                  0x10B
+#define AU8522_TSTHES_REG10CH                          0x10C
+#define AU8522_FRMREGDFEKEEP_REG301H                   0x301
+#define AU8522_DFE_AVERAGE_REG302H                     0x302
+#define AU8522_FRMREGEQLERRWIN_REG303H                 0x303
+#define AU8522_FRMREGFFEKEEP_REG304H                   0x304
+#define AU8522_FRMREGDFECONTROL1_REG305H               0x305
+#define AU8522_FRMREGEQLERRLOW_REG306H                 0x306
+
+#define AU8522_REG42EH                         0x42E
+#define AU8522_REG42FH                         0x42F
+#define AU8522_REG430H                         0x430
+#define AU8522_REG431H                         0x431
+#define AU8522_REG432H                         0x432
+#define AU8522_REG433H                         0x433
+#define AU8522_REG434H                         0x434
+#define AU8522_REG435H                         0x435
+#define AU8522_REG436H                         0x436
+
+/* GPIO Registers */
+#define AU8522_GPIO_CONTROL_REG0E0H                    0x0E0
+#define AU8522_GPIO_STATUS_REG0E1H                     0x0E1
+#define AU8522_GPIO_DATA_REG0E2H                       0x0E2
+
+/* Audio Control Registers */
+#define AU8522_AUDIOAGC_REG0EEH                        0x0EE
+#define AU8522_AUDIO_STATUS_REG0F0H                    0x0F0
+#define AU8522_AUDIO_MODE_REG0F1H                      0x0F1
+#define AU8522_AUDIO_VOLUME_L_REG0F2H                  0x0F2
+#define AU8522_AUDIO_VOLUME_R_REG0F3H                  0x0F3
+#define AU8522_AUDIO_VOLUME_REG0F4H                    0x0F4
+#define AU8522_FRMREGAUPHASE_REG0F7H                   0x0F7
+#define AU8522_REG0F9H                                 0x0F9
+
+#define AU8522_AUDIOAGC2_REG605H                       0x605
+#define AU8522_AUDIOFREQ_REG606H                       0x606
+
+
+/**************************************************************/
+
+#define AU8522_INPUT_CONTROL_REG081H_ATSC                      0xC4
+#define AU8522_INPUT_CONTROL_REG081H_ATVRF                     0xC4
+#define AU8522_INPUT_CONTROL_REG081H_ATVRF13                   0xC4
+#define AU8522_INPUT_CONTROL_REG081H_J83B64                    0xC4
+#define AU8522_INPUT_CONTROL_REG081H_J83B256                   0xC4
+#define AU8522_INPUT_CONTROL_REG081H_CVBS                      0x20
+#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH1                  0xA2
+#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH2                  0xA0
+#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH3                  0x69
+#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4                  0x68
+#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF              0x28
+/* CH1 AS Y,CH3 AS C */
+#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13               0x23
+/* CH2 AS Y,CH4 AS C */
+#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24               0x20
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATSC               0x0C
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B64             0x09
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B256                    0x09
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS               0x12
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF              0x1A
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF13            0x1A
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO             0x02
+
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CLEAR           0x00
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO          0x9C
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS            0x9D
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATSC            0xE8
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B256                 0xCA
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B64                  0xCA
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF                   0xDD
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF13         0xDD
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_PAL             0xDD
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_FM              0xDD
+
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATSC            0x80
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B256                 0x80
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B64                  0x80
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_ATSC     0x40
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B256  0x40
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B64   0x40
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_CLEAR    0x00
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF           0x01
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF13         0x01
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_SVIDEO                  0x04
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_CVBS            0x01
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PWM                     0x03
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_IIS             0x09
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PAL             0x01
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_FM              0x01
+
+/* STILL NEED TO BE REFACTORED @@@@@@@@@@@@@@ */
+#define AU8522_TVDEC_CONTRAST_REG00BH_CVBS                     0x79
+#define AU8522_TVDEC_SATURATION_CB_REG00CH_CVBS                        0x80
+#define AU8522_TVDEC_SATURATION_CR_REG00DH_CVBS                        0x80
+#define AU8522_TVDEC_HUE_H_REG00EH_CVBS                                0x00
+#define AU8522_TVDEC_HUE_L_REG00FH_CVBS                                0x00
+#define AU8522_TVDEC_PGA_REG012H_CVBS                          0x0F
+#define AU8522_TVDEC_COMB_MODE_REG015H_CVBS                    0x00
+#define AU8522_REG016H_CVBS                                    0x00
+#define AU8522_TVDED_DBG_MODE_REG060H_CVBS                     0x00
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS                 0x0B
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS13               0x03
+#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_CVBS13               0x00
+#define AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS                 0x19
+#define AU8522_REG0F9H_AUDIO                                   0x20
+#define AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS                 0xA7
+#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS               0x0A
+#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS               0x32
+#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS               0x19
+#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS               0x23
+#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS               0x41
+#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS               0x0A
+#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS               0x32
+#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS              0x34
+#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS              0x05
+#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS              0x6E
+#define AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS                   0x0F
+#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS            0x80
+#define AU8522_REG071H_CVBS                                    0x18
+#define AU8522_REG072H_CVBS                                    0x30
+#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS            0xF0
+#define AU8522_REG074H_CVBS                                    0x80
+#define AU8522_REG075H_CVBS                                    0xF0
+#define AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS                   0xFB
+#define AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS                        0x04
+#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS               0x00
+#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS         0x00
+#define AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS                   0xEE
+#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS                        0xFE
+#define AU8522_TOREGAAGC_REG0E5H_CVBS                          0x00
+#define AU8522_TVDEC_VBI6A_REG035H_CVBS                                0x40
+
+/* Enables Closed captioning */
+#define AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON                   0x21
index f6e7b0380a5a5c5676db3089145cadc25c6d9b22..e4fd533a427c43dd86c75b6acc667d10692204d4 100644 (file)
@@ -559,7 +559,7 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
                kzalloc(sizeof(struct cx24113_state), GFP_KERNEL);
        int rc;
        if (state == NULL) {
-               err("Unable to kmalloc\n");
+               err("Unable to kzalloc\n");
                goto error;
        }
 
index 28ad609e73f40e95c3b31555aef44a74cc93aa2a..9b9f57264ceff0bd76c7685477ae22486d2a4b5a 100644 (file)
@@ -15,6 +15,9 @@
        September, 9th 2008
            Fixed locking on high symbol rates (>30000).
            Implement MPEG initialization parameter.
+       January, 17th 2009
+           Fill set_voltage with actually control voltage code.
+           Correct set tone to not affect voltage.
 
     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
@@ -146,7 +149,7 @@ enum cmds {
        CMD_GETAGC      = 0x19,
        CMD_LNBCONFIG   = 0x20,
        CMD_LNBSEND     = 0x21, /* Formerly CMD_SEND_DISEQC */
-       CMD_SET_TONEPRE = 0x22,
+       CMD_LNBDCLEVEL  = 0x22,
        CMD_SET_TONE    = 0x23,
        CMD_UPDFWVERS   = 0x35,
        CMD_TUNERSLEEP  = 0x36,
@@ -667,16 +670,6 @@ static int cx24116_load_firmware(struct dvb_frontend *fe,
        return 0;
 }
 
-static int cx24116_set_voltage(struct dvb_frontend *fe,
-       fe_sec_voltage_t voltage)
-{
-       /* The isl6421 module will override this function in the fops. */
-       dprintk("%s() This should never appear if the isl6421 module "
-               "is loaded correctly\n", __func__);
-
-       return -EOPNOTSUPP;
-}
-
 static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
        struct cx24116_state *state = fe->demodulator_priv;
@@ -837,6 +830,34 @@ static int cx24116_wait_for_lnb(struct dvb_frontend *fe)
        return -ETIMEDOUT; /* -EBUSY ? */
 }
 
+static int cx24116_set_voltage(struct dvb_frontend *fe,
+       fe_sec_voltage_t voltage)
+{
+       struct cx24116_cmd cmd;
+       int ret;
+
+       dprintk("%s: %s\n", __func__,
+               voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+               voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
+
+       /* Wait for LNB ready */
+       ret = cx24116_wait_for_lnb(fe);
+       if (ret != 0)
+               return ret;
+
+       /* Wait for voltage/min repeat delay */
+       msleep(100);
+
+       cmd.args[0x00] = CMD_LNBDCLEVEL;
+       cmd.args[0x01] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00);
+       cmd.len = 0x02;
+
+       /* Min delay time before DiSEqC send */
+       msleep(15);
+
+       return cx24116_cmd_execute(fe, &cmd);
+}
+
 static int cx24116_set_tone(struct dvb_frontend *fe,
        fe_sec_tone_mode_t tone)
 {
@@ -857,14 +878,6 @@ static int cx24116_set_tone(struct dvb_frontend *fe,
        /* Min delay time after DiSEqC send */
        msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
 
-       /* This is always done before the tone is set */
-       cmd.args[0x00] = CMD_SET_TONEPRE;
-       cmd.args[0x01] = 0x00;
-       cmd.len = 0x02;
-       ret = cx24116_cmd_execute(fe, &cmd);
-       if (ret != 0)
-               return ret;
-
        /* Now we set the tone */
        cmd.args[0x00] = CMD_SET_TONE;
        cmd.args[0x01] = 0x00;
@@ -1099,13 +1112,10 @@ struct dvb_frontend *cx24116_attach(const struct cx24116_config *config,
        dprintk("%s\n", __func__);
 
        /* allocate memory for the internal state */
-       state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL);
+       state = kzalloc(sizeof(struct cx24116_state), GFP_KERNEL);
        if (state == NULL)
                goto error1;
 
-       /* setup the state */
-       memset(state, 0, sizeof(struct cx24116_state));
-
        state->config = config;
        state->i2c = i2c;
 
@@ -1154,7 +1164,12 @@ static int cx24116_initfe(struct dvb_frontend *fe)
        if (ret != 0)
                return ret;
 
-       return cx24116_diseqc_init(fe);
+       ret = cx24116_diseqc_init(fe);
+       if (ret != 0)
+               return ret;
+
+       /* HVR-4000 needs this */
+       return cx24116_set_voltage(fe, SEC_VOLTAGE_13);
 }
 
 /*
index 1a8c36f76061a83d6df460eec40eae4342bce299..0592f043ea64481228ffc9c26ae0c60929308ec3 100644 (file)
@@ -1069,13 +1069,13 @@ static struct dvb_frontend_ops cx24123_ops;
 struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
                                    struct i2c_adapter *i2c)
 {
+       /* allocate memory for the internal state */
        struct cx24123_state *state =
                kzalloc(sizeof(struct cx24123_state), GFP_KERNEL);
 
        dprintk("\n");
-       /* allocate memory for the internal state */
        if (state == NULL) {
-               err("Unable to kmalloc\n");
+               err("Unable to kzalloc\n");
                goto error;
        }
 
index 21f2c5161af4887c2a8e7ff9dc7b4c98762f01f7..9670f5d20cfbf9bc7a8578a69bf2ab6bacfcd7c3 100644 (file)
@@ -58,6 +58,4 @@ static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe)
 }
 #endif
 
-extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open);
-
 #endif
index 4142ed7a47d02201e1b5aa13deeeb96f0097f38d..d75ffad2d7523ebcef70e851a7669e659a996adb 100644 (file)
@@ -39,19 +39,43 @@ struct dib3000mc_config {
 #define DEFAULT_DIB3000MC_I2C_ADDRESS 16
 #define DEFAULT_DIB3000P_I2C_ADDRESS  24
 
-#if defined(CONFIG_DVB_DIB3000MC) || (defined(CONFIG_DVB_DIB3000MC_MODULE) && defined(MODULE))
-extern struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg);
+#if defined(CONFIG_DVB_DIB3000MC) || (defined(CONFIG_DVB_DIB3000MC_MODULE) && \
+                                     defined(MODULE))
+extern struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap,
+                                            u8 i2c_addr,
+                                            struct dib3000mc_config *cfg);
+extern int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c,
+                                    int no_of_demods, u8 default_addr,
+                                    struct dib3000mc_config cfg[]);
+extern
+struct i2c_adapter *dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod,
+                                                  int gating);
 #else
-static inline struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg)
+static inline
+struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
+                                     struct dib3000mc_config *cfg)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
 }
-#endif // CONFIG_DVB_DIB3000MC
 
-extern int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib3000mc_config cfg[]);
+static inline
+int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c,
+                             int no_of_demods, u8 default_addr,
+                             struct dib3000mc_config cfg[])
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
 
-extern struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating);
+static inline
+struct i2c_adapter *dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod,
+                                                  int gating)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif // CONFIG_DVB_DIB3000MC
 
 extern int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff);
 extern int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff);
index 597e9cc2da62d7342f0adf342795ed780539e43f..113819ce9f0d1f9a1d4d7d7460b487d4c15252c1 100644 (file)
@@ -38,8 +38,32 @@ struct dib7000m_config {
 
 #define DEFAULT_DIB7000M_I2C_ADDRESS 18
 
-extern struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg);
-extern struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
+#if defined(CONFIG_DVB_DIB7000M) || (defined(CONFIG_DVB_DIB7000M_MODULE) && \
+                                    defined(MODULE))
+extern struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap,
+                                           u8 i2c_addr,
+                                           struct dib7000m_config *cfg);
+extern struct i2c_adapter *dib7000m_get_i2c_master(struct dvb_frontend *,
+                                                  enum dibx000_i2c_interface,
+                                                  int);
+#else
+static inline
+struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap,
+                                    u8 i2c_addr, struct dib7000m_config *cfg)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+static inline
+struct i2c_adapter *dib7000m_get_i2c_master(struct dvb_frontend *demod,
+                                           enum dibx000_i2c_interface intf,
+                                           int gating)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
 
 /* TODO
 extern INT dib7000m_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val);
index aab8112e2db20f6658c66c0c83cee0e9ae6fd4f7..02a4c82f0c70c50da6c442772e1198e3c2b414d4 100644 (file)
@@ -37,7 +37,8 @@ struct dib7000p_config {
 
 #define DEFAULT_DIB7000P_I2C_ADDRESS 18
 
-#if defined(CONFIG_DVB_DIB7000P) || (defined(CONFIG_DVB_DIB7000P_MODULE) && defined(MODULE))
+#if defined(CONFIG_DVB_DIB7000P) || (defined(CONFIG_DVB_DIB7000P_MODULE) && \
+                                    defined(MODULE))
 extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
                                            u8 i2c_addr,
                                            struct dib7000p_config *cfg);
@@ -49,10 +50,11 @@ extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
                                    struct dib7000p_config cfg[]);
 extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
 extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
+extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
 #else
-static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
-                                                  u8 i2c_addr,
-                                                  struct dib7000p_config *cfg)
+static inline
+struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
+                                    struct dib7000p_config *cfg)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
@@ -60,36 +62,39 @@ static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
 
 static inline
 struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe,
-                                           enum dibx000_i2c_interface i, int x)
+                                           enum dibx000_i2c_interface i,
+                                           int x)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
 }
 
-static inline
-int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
-                                   int no_of_demods, u8 default_addr,
-                                   struct dib7000p_config cfg[])
+static inline int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
+                                          int no_of_demods, u8 default_addr,
+                                          struct dib7000p_config cfg[])
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return -ENODEV;
 }
 
-static inline
-int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
+static inline int dib7000p_set_gpio(struct dvb_frontend *fe,
+                                   u8 num, u8 dir, u8 val)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return -ENODEV;
 }
 
-static inline
-int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
+static inline int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return -ENODEV;
 }
-#endif
 
-extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
+static inline int dib7000pc_detection(struct i2c_adapter *i2c_adap)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+#endif
 
 #endif
index 8210f19d56ce7460a4b6ecd393660ee0c63f7ca7..1fcb987d6386eae739f3850e2011b1be93a56f3d 100644 (file)
 #include <linux/dvb/frontend.h>
 #include "dvb_frontend.h"
 
+#if defined(CONFIG_DVB_DUMMY_FE) || (defined(CONFIG_DVB_DUMMY_FE_MODULE) && \
+defined(MODULE))
 extern struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void);
 extern struct dvb_frontend* dvb_dummy_fe_qpsk_attach(void);
 extern struct dvb_frontend* dvb_dummy_fe_qam_attach(void);
+#else
+static inline struct dvb_frontend *dvb_dummy_fe_ofdm_attach(void)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+static inline struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+static inline struct dvb_frontend *dvb_dummy_fe_qam_attach(void)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_DUMMY_FE */
 
 #endif // DVB_DUMMY_FE_H
index 8cdc54e5790302c91f844867f7ee250ea0c745c7..08ca851223c9ed92f814b5b98514be3ade4cf4cf 100644 (file)
@@ -31,7 +31,7 @@ struct itd1000_state {
        /* ugly workaround for flexcop's incapable i2c-controller
         * FIXME, if possible
         */
-       u8 shadow[255];
+       u8 shadow[256];
 };
 
 enum itd1000_register {
index 3bb0c4394f8a17ac8ace04405326e8dc1d4c710c..eb72a9866c93769bb4d94715328d32d816f591d6 100644 (file)
@@ -363,7 +363,6 @@ struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
 
        struct lgdt3304_state *state;
        state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL);
-       memset(state, 0x0, sizeof(struct lgdt3304_state));
        state->addr = config->i2c_address;
        state->i2c = i2c;
 
diff --git a/drivers/media/dvb/frontends/lgdt3305.c b/drivers/media/dvb/frontends/lgdt3305.c
new file mode 100644 (file)
index 0000000..d92d055
--- /dev/null
@@ -0,0 +1,1087 @@
+/*
+ *    Support for LGDT3305 - VSB/QAM
+ *
+ *    Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    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/dvb/frontend.h>
+#include "dvb_math.h"
+#include "lgdt3305.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))");
+
+#define DBG_INFO 1
+#define DBG_REG  2
+
+#define lg_printk(kern, fmt, arg...)                                   \
+       printk(kern "%s: " fmt, __func__, ##arg)
+
+#define lg_info(fmt, arg...)   printk(KERN_INFO "lgdt3305: " fmt, ##arg)
+#define lg_warn(fmt, arg...)   lg_printk(KERN_WARNING,       fmt, ##arg)
+#define lg_err(fmt, arg...)    lg_printk(KERN_ERR,           fmt, ##arg)
+#define lg_dbg(fmt, arg...) if (debug & DBG_INFO)                      \
+                               lg_printk(KERN_DEBUG,         fmt, ##arg)
+#define lg_reg(fmt, arg...) if (debug & DBG_REG)                       \
+                               lg_printk(KERN_DEBUG,         fmt, ##arg)
+
+#define lg_fail(ret)                                                   \
+({                                                                     \
+       int __ret;                                                      \
+       __ret = (ret < 0);                                              \
+       if (__ret)                                                      \
+               lg_err("error %d on line %d\n", ret, __LINE__);         \
+       __ret;                                                          \
+})
+
+struct lgdt3305_state {
+       struct i2c_adapter *i2c_adap;
+       const struct lgdt3305_config *cfg;
+
+       struct dvb_frontend frontend;
+
+       fe_modulation_t current_modulation;
+       u32 current_frequency;
+       u32 snr;
+};
+
+/* ------------------------------------------------------------------------ */
+
+#define LGDT3305_GEN_CTRL_1                   0x0000
+#define LGDT3305_GEN_CTRL_2                   0x0001
+#define LGDT3305_GEN_CTRL_3                   0x0002
+#define LGDT3305_GEN_STATUS                   0x0003
+#define LGDT3305_GEN_CONTROL                  0x0007
+#define LGDT3305_GEN_CTRL_4                   0x000a
+#define LGDT3305_DGTL_AGC_REF_1               0x0012
+#define LGDT3305_DGTL_AGC_REF_2               0x0013
+#define LGDT3305_CR_CTR_FREQ_1                0x0106
+#define LGDT3305_CR_CTR_FREQ_2                0x0107
+#define LGDT3305_CR_CTR_FREQ_3                0x0108
+#define LGDT3305_CR_CTR_FREQ_4                0x0109
+#define LGDT3305_CR_MSE_1                     0x011b
+#define LGDT3305_CR_MSE_2                     0x011c
+#define LGDT3305_CR_LOCK_STATUS               0x011d
+#define LGDT3305_CR_CTRL_7                    0x0126
+#define LGDT3305_AGC_POWER_REF_1              0x0300
+#define LGDT3305_AGC_POWER_REF_2              0x0301
+#define LGDT3305_AGC_DELAY_PT_1               0x0302
+#define LGDT3305_AGC_DELAY_PT_2               0x0303
+#define LGDT3305_RFAGC_LOOP_FLTR_BW_1         0x0306
+#define LGDT3305_RFAGC_LOOP_FLTR_BW_2         0x0307
+#define LGDT3305_IFBW_1                       0x0308
+#define LGDT3305_IFBW_2                       0x0309
+#define LGDT3305_AGC_CTRL_1                   0x030c
+#define LGDT3305_AGC_CTRL_4                   0x0314
+#define LGDT3305_EQ_MSE_1                     0x0413
+#define LGDT3305_EQ_MSE_2                     0x0414
+#define LGDT3305_EQ_MSE_3                     0x0415
+#define LGDT3305_PT_MSE_1                     0x0417
+#define LGDT3305_PT_MSE_2                     0x0418
+#define LGDT3305_PT_MSE_3                     0x0419
+#define LGDT3305_FEC_BLOCK_CTRL               0x0504
+#define LGDT3305_FEC_LOCK_STATUS              0x050a
+#define LGDT3305_FEC_PKT_ERR_1                0x050c
+#define LGDT3305_FEC_PKT_ERR_2                0x050d
+#define LGDT3305_TP_CTRL_1                    0x050e
+#define LGDT3305_BERT_PERIOD                  0x0801
+#define LGDT3305_BERT_ERROR_COUNT_1           0x080a
+#define LGDT3305_BERT_ERROR_COUNT_2           0x080b
+#define LGDT3305_BERT_ERROR_COUNT_3           0x080c
+#define LGDT3305_BERT_ERROR_COUNT_4           0x080d
+
+static int lgdt3305_write_reg(struct lgdt3305_state *state, u16 reg, u8 val)
+{
+       int ret;
+       u8 buf[] = { reg >> 8, reg & 0xff, val };
+       struct i2c_msg msg = {
+               .addr = state->cfg->i2c_addr, .flags = 0,
+               .buf = buf, .len = 3,
+       };
+
+       lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val);
+
+       ret = i2c_transfer(state->i2c_adap, &msg, 1);
+
+       if (ret != 1) {
+               lg_err("error (addr %02x %02x <- %02x, err = %i)\n",
+                      msg.buf[0], msg.buf[1], msg.buf[2], ret);
+               if (ret < 0)
+                       return ret;
+               else
+                       return -EREMOTEIO;
+       }
+       return 0;
+}
+
+static int lgdt3305_read_reg(struct lgdt3305_state *state, u16 reg, u8 *val)
+{
+       int ret;
+       u8 reg_buf[] = { reg >> 8, reg & 0xff };
+       struct i2c_msg msg[] = {
+               { .addr = state->cfg->i2c_addr,
+                 .flags = 0, .buf = reg_buf, .len = 2 },
+               { .addr = state->cfg->i2c_addr,
+                 .flags = I2C_M_RD, .buf = val, .len = 1 },
+       };
+
+       lg_reg("reg: 0x%04x\n", reg);
+
+       ret = i2c_transfer(state->i2c_adap, msg, 2);
+
+       if (ret != 2) {
+               lg_err("error (addr %02x reg %04x error (ret == %i)\n",
+                      state->cfg->i2c_addr, reg, ret);
+               if (ret < 0)
+                       return ret;
+               else
+                       return -EREMOTEIO;
+       }
+       return 0;
+}
+
+#define read_reg(state, reg)                                           \
+({                                                                     \
+       u8 __val;                                                       \
+       int ret = lgdt3305_read_reg(state, reg, &__val);                \
+       if (lg_fail(ret))                                               \
+               __val = 0;                                              \
+       __val;                                                          \
+})
+
+static int lgdt3305_set_reg_bit(struct lgdt3305_state *state,
+                               u16 reg, int bit, int onoff)
+{
+       u8 val;
+       int ret;
+
+       lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff);
+
+       ret = lgdt3305_read_reg(state, reg, &val);
+       if (lg_fail(ret))
+               goto fail;
+
+       val &= ~(1 << bit);
+       val |= (onoff & 1) << bit;
+
+       ret = lgdt3305_write_reg(state, reg, val);
+fail:
+       return ret;
+}
+
+struct lgdt3305_reg {
+       u16 reg;
+       u8 val;
+};
+
+static int lgdt3305_write_regs(struct lgdt3305_state *state,
+                              struct lgdt3305_reg *regs, int len)
+{
+       int i, ret;
+
+       lg_reg("writing %d registers...\n", len);
+
+       for (i = 0; i < len - 1; i++) {
+               ret = lgdt3305_write_reg(state, regs[i].reg, regs[i].val);
+               if (lg_fail(ret))
+                       return ret;
+       }
+       return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3305_soft_reset(struct lgdt3305_state *state)
+{
+       int ret;
+
+       lg_dbg("\n");
+
+       ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 0);
+       if (lg_fail(ret))
+               goto fail;
+
+       msleep(20);
+       ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 1);
+fail:
+       return ret;
+}
+
+static inline int lgdt3305_mpeg_mode(struct lgdt3305_state *state,
+                                    enum lgdt3305_mpeg_mode mode)
+{
+       lg_dbg("(%d)\n", mode);
+       return lgdt3305_set_reg_bit(state, LGDT3305_TP_CTRL_1, 5, mode);
+}
+
+static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state,
+                                      enum lgdt3305_tp_clock_edge edge,
+                                      enum lgdt3305_tp_valid_polarity valid)
+{
+       u8 val;
+       int ret;
+
+       lg_dbg("edge = %d, valid = %d\n", edge, valid);
+
+       ret = lgdt3305_read_reg(state, LGDT3305_TP_CTRL_1, &val);
+       if (lg_fail(ret))
+               goto fail;
+
+       val &= ~0x09;
+
+       if (edge)
+               val |= 0x08;
+       if (valid)
+               val |= 0x01;
+
+       ret = lgdt3305_write_reg(state, LGDT3305_TP_CTRL_1, val);
+       if (lg_fail(ret))
+               goto fail;
+
+       ret = lgdt3305_soft_reset(state);
+fail:
+       return ret;
+}
+
+static int lgdt3305_set_modulation(struct lgdt3305_state *state,
+                                  struct dvb_frontend_parameters *param)
+{
+       u8 opermode;
+       int ret;
+
+       lg_dbg("\n");
+
+       ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_1, &opermode);
+       if (lg_fail(ret))
+               goto fail;
+
+       opermode &= ~0x03;
+
+       switch (param->u.vsb.modulation) {
+       case VSB_8:
+               opermode |= 0x03;
+               break;
+       case QAM_64:
+               opermode |= 0x00;
+               break;
+       case QAM_256:
+               opermode |= 0x01;
+               break;
+       default:
+               return -EINVAL;
+       }
+       ret = lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_1, opermode);
+fail:
+       return ret;
+}
+
+static int lgdt3305_set_filter_extension(struct lgdt3305_state *state,
+                                        struct dvb_frontend_parameters *param)
+{
+       int val;
+
+       switch (param->u.vsb.modulation) {
+       case VSB_8:
+               val = 0;
+               break;
+       case QAM_64:
+       case QAM_256:
+               val = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+       lg_dbg("val = %d\n", val);
+
+       return lgdt3305_set_reg_bit(state, 0x043f, 2, val);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state,
+                                        struct dvb_frontend_parameters *param)
+{
+       u16 agc_ref;
+
+       switch (param->u.vsb.modulation) {
+       case VSB_8:
+               agc_ref = 0x32c4;
+               break;
+       case QAM_64:
+               agc_ref = 0x2a00;
+               break;
+       case QAM_256:
+               agc_ref = 0x2a80;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       lg_dbg("agc ref: 0x%04x\n", agc_ref);
+
+       lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_1, agc_ref >> 8);
+       lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_2, agc_ref & 0xff);
+
+       return 0;
+}
+
+static int lgdt3305_rfagc_loop(struct lgdt3305_state *state,
+                              struct dvb_frontend_parameters *param)
+{
+       u16 ifbw, rfbw, agcdelay;
+
+       switch (param->u.vsb.modulation) {
+       case VSB_8:
+               agcdelay = 0x04c0;
+               rfbw     = 0x8000;
+               ifbw     = 0x8000;
+               break;
+       case QAM_64:
+       case QAM_256:
+               agcdelay = 0x046b;
+               rfbw     = 0x8889;
+               ifbw     = 0x8888;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (state->cfg->rf_agc_loop) {
+               lg_dbg("agcdelay: 0x%04x, rfbw: 0x%04x\n", agcdelay, rfbw);
+
+               /* rf agc loop filter bandwidth */
+               lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_1,
+                                  agcdelay >> 8);
+               lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_2,
+                                  agcdelay & 0xff);
+
+               lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_1,
+                                  rfbw >> 8);
+               lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_2,
+                                  rfbw & 0xff);
+       } else {
+               lg_dbg("ifbw: 0x%04x\n", ifbw);
+
+               /* if agc loop filter bandwidth */
+               lgdt3305_write_reg(state, LGDT3305_IFBW_1, ifbw >> 8);
+               lgdt3305_write_reg(state, LGDT3305_IFBW_2, ifbw & 0xff);
+       }
+
+       return 0;
+}
+
+static int lgdt3305_agc_setup(struct lgdt3305_state *state,
+                             struct dvb_frontend_parameters *param)
+{
+       int lockdten, acqen;
+
+       switch (param->u.vsb.modulation) {
+       case VSB_8:
+               lockdten = 0;
+               acqen = 0;
+               break;
+       case QAM_64:
+       case QAM_256:
+               lockdten = 1;
+               acqen = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen);
+
+       /* control agc function */
+       lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);
+       lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);
+
+       return lgdt3305_rfagc_loop(state, param);
+}
+
+static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state,
+                                     struct dvb_frontend_parameters *param)
+{
+       u16 usref = 0;
+
+       switch (param->u.vsb.modulation) {
+       case VSB_8:
+               if (state->cfg->usref_8vsb)
+                       usref = state->cfg->usref_8vsb;
+               break;
+       case QAM_64:
+               if (state->cfg->usref_qam64)
+                       usref = state->cfg->usref_qam64;
+               break;
+       case QAM_256:
+               if (state->cfg->usref_qam256)
+                       usref = state->cfg->usref_qam256;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (usref) {
+               lg_dbg("set manual mode: 0x%04x\n", usref);
+
+               lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 3, 1);
+
+               lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_1,
+                                  0xff & (usref >> 8));
+               lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_2,
+                                  0xff & (usref >> 0));
+       }
+       return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3305_spectral_inversion(struct lgdt3305_state *state,
+                                      struct dvb_frontend_parameters *param,
+                                      int inversion)
+{
+       int ret;
+
+       lg_dbg("(%d)\n", inversion);
+
+       switch (param->u.vsb.modulation) {
+       case VSB_8:
+               ret = lgdt3305_write_reg(state, LGDT3305_CR_CTRL_7,
+                                        inversion ? 0xf9 : 0x79);
+               break;
+       case QAM_64:
+       case QAM_256:
+               ret = lgdt3305_write_reg(state, LGDT3305_FEC_BLOCK_CTRL,
+                                        inversion ? 0xfd : 0xff);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static int lgdt3305_set_if(struct lgdt3305_state *state,
+                          struct dvb_frontend_parameters *param)
+{
+       u16 if_freq_khz;
+       u8 nco1, nco2, nco3, nco4;
+       u64 nco;
+
+       switch (param->u.vsb.modulation) {
+       case VSB_8:
+               if_freq_khz = state->cfg->vsb_if_khz;
+               break;
+       case QAM_64:
+       case QAM_256:
+               if_freq_khz = state->cfg->qam_if_khz;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       nco = if_freq_khz / 10;
+
+#define LGDT3305_64BIT_DIVISION_ENABLED 0
+       /* FIXME: 64bit division disabled to avoid linking error:
+        * WARNING: "__udivdi3" [lgdt3305.ko] undefined!
+        */
+       switch (param->u.vsb.modulation) {
+       case VSB_8:
+#if LGDT3305_64BIT_DIVISION_ENABLED
+               nco <<= 24;
+               nco /= 625;
+#else
+               nco *= ((1 << 24) / 625);
+#endif
+               break;
+       case QAM_64:
+       case QAM_256:
+#if LGDT3305_64BIT_DIVISION_ENABLED
+               nco <<= 28;
+               nco /= 625;
+#else
+               nco *= ((1 << 28) / 625);
+#endif
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       nco1 = (nco >> 24) & 0x3f;
+       nco1 |= 0x40;
+       nco2 = (nco >> 16) & 0xff;
+       nco3 = (nco >> 8) & 0xff;
+       nco4 = nco & 0xff;
+
+       lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, nco1);
+       lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, nco2);
+       lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, nco3);
+       lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, nco4);
+
+       lg_dbg("%d KHz -> [%02x%02x%02x%02x]\n",
+              if_freq_khz, nco1, nco2, nco3, nco4);
+
+       return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3305_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct lgdt3305_state *state = fe->demodulator_priv;
+
+       if (state->cfg->deny_i2c_rptr)
+               return 0;
+
+       lg_dbg("(%d)\n", enable);
+
+       return lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_2, 5,
+                                   enable ? 0 : 1);
+}
+
+static int lgdt3305_sleep(struct dvb_frontend *fe)
+{
+       struct lgdt3305_state *state = fe->demodulator_priv;
+       u8 gen_ctrl_3, gen_ctrl_4;
+
+       lg_dbg("\n");
+
+       gen_ctrl_3 = read_reg(state, LGDT3305_GEN_CTRL_3);
+       gen_ctrl_4 = read_reg(state, LGDT3305_GEN_CTRL_4);
+
+       /* hold in software reset while sleeping */
+       gen_ctrl_3 &= ~0x01;
+       /* tristate the IF-AGC pin */
+       gen_ctrl_3 |=  0x02;
+       /* tristate the RF-AGC pin */
+       gen_ctrl_3 |=  0x04;
+
+       /* disable vsb/qam module */
+       gen_ctrl_4 &= ~0x01;
+       /* disable adc module */
+       gen_ctrl_4 &= ~0x02;
+
+       lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_3, gen_ctrl_3);
+       lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_4, gen_ctrl_4);
+
+       return 0;
+}
+
+static int lgdt3305_init(struct dvb_frontend *fe)
+{
+       struct lgdt3305_state *state = fe->demodulator_priv;
+       int ret;
+
+       static struct lgdt3305_reg lgdt3305_init_data[] = {
+               { .reg = LGDT3305_GEN_CTRL_1,
+                 .val = 0x03, },
+               { .reg = LGDT3305_GEN_CTRL_2,
+                 .val = 0xb0, },
+               { .reg = LGDT3305_GEN_CTRL_3,
+                 .val = 0x01, },
+               { .reg = LGDT3305_GEN_CONTROL,
+                 .val = 0x6f, },
+               { .reg = LGDT3305_GEN_CTRL_4,
+                 .val = 0x03, },
+               { .reg = LGDT3305_DGTL_AGC_REF_1,
+                 .val = 0x32, },
+               { .reg = LGDT3305_DGTL_AGC_REF_2,
+                 .val = 0xc4, },
+               { .reg = LGDT3305_CR_CTR_FREQ_1,
+                 .val = 0x00, },
+               { .reg = LGDT3305_CR_CTR_FREQ_2,
+                 .val = 0x00, },
+               { .reg = LGDT3305_CR_CTR_FREQ_3,
+                 .val = 0x00, },
+               { .reg = LGDT3305_CR_CTR_FREQ_4,
+                 .val = 0x00, },
+               { .reg = LGDT3305_CR_CTRL_7,
+                 .val = 0x79, },
+               { .reg = LGDT3305_AGC_POWER_REF_1,
+                 .val = 0x32, },
+               { .reg = LGDT3305_AGC_POWER_REF_2,
+                 .val = 0xc4, },
+               { .reg = LGDT3305_AGC_DELAY_PT_1,
+                 .val = 0x0d, },
+               { .reg = LGDT3305_AGC_DELAY_PT_2,
+                 .val = 0x30, },
+               { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1,
+                 .val = 0x80, },
+               { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2,
+                 .val = 0x00, },
+               { .reg = LGDT3305_IFBW_1,
+                 .val = 0x80, },
+               { .reg = LGDT3305_IFBW_2,
+                 .val = 0x00, },
+               { .reg = LGDT3305_AGC_CTRL_1,
+                 .val = 0x30, },
+               { .reg = LGDT3305_AGC_CTRL_4,
+                 .val = 0x61, },
+               { .reg = LGDT3305_FEC_BLOCK_CTRL,
+                 .val = 0xff, },
+               { .reg = LGDT3305_TP_CTRL_1,
+                 .val = 0x1b, },
+       };
+
+       lg_dbg("\n");
+
+       ret = lgdt3305_write_regs(state, lgdt3305_init_data,
+                                 ARRAY_SIZE(lgdt3305_init_data));
+       if (lg_fail(ret))
+               goto fail;
+
+       ret = lgdt3305_soft_reset(state);
+fail:
+       return ret;
+}
+
+static int lgdt3305_set_parameters(struct dvb_frontend *fe,
+                                  struct dvb_frontend_parameters *param)
+{
+       struct lgdt3305_state *state = fe->demodulator_priv;
+       int ret;
+
+       lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation);
+
+       if (fe->ops.tuner_ops.set_params) {
+               ret = fe->ops.tuner_ops.set_params(fe, param);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+               if (lg_fail(ret))
+                       goto fail;
+               state->current_frequency = param->frequency;
+       }
+
+       ret = lgdt3305_set_modulation(state, param);
+       if (lg_fail(ret))
+               goto fail;
+
+       ret = lgdt3305_passband_digital_agc(state, param);
+       if (lg_fail(ret))
+               goto fail;
+       ret = lgdt3305_set_agc_power_ref(state, param);
+       if (lg_fail(ret))
+               goto fail;
+       ret = lgdt3305_agc_setup(state, param);
+       if (lg_fail(ret))
+               goto fail;
+
+       /* low if */
+       ret = lgdt3305_write_reg(state, LGDT3305_GEN_CONTROL, 0x2f);
+       if (lg_fail(ret))
+               goto fail;
+       ret = lgdt3305_set_reg_bit(state, LGDT3305_CR_CTR_FREQ_1, 6, 1);
+       if (lg_fail(ret))
+               goto fail;
+
+       ret = lgdt3305_set_if(state, param);
+       if (lg_fail(ret))
+               goto fail;
+       ret = lgdt3305_spectral_inversion(state, param,
+                                         state->cfg->spectral_inversion
+                                         ? 1 : 0);
+       if (lg_fail(ret))
+               goto fail;
+
+       ret = lgdt3305_set_filter_extension(state, param);
+       if (lg_fail(ret))
+               goto fail;
+
+       state->current_modulation = param->u.vsb.modulation;
+
+       ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
+       if (lg_fail(ret))
+               goto fail;
+
+       /* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
+       ret = lgdt3305_mpeg_mode_polarity(state,
+                                         state->cfg->tpclk_edge,
+                                         state->cfg->tpvalid_polarity);
+fail:
+       return ret;
+}
+
+static int lgdt3305_get_frontend(struct dvb_frontend *fe,
+                                struct dvb_frontend_parameters *param)
+{
+       struct lgdt3305_state *state = fe->demodulator_priv;
+
+       lg_dbg("\n");
+
+       param->u.vsb.modulation = state->current_modulation;
+       param->frequency = state->current_frequency;
+       return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3305_read_cr_lock_status(struct lgdt3305_state *state,
+                                       int *locked)
+{
+       u8 val;
+       int ret;
+       char *cr_lock_state = "";
+
+       *locked = 0;
+
+       ret = lgdt3305_read_reg(state, LGDT3305_CR_LOCK_STATUS, &val);
+       if (lg_fail(ret))
+               goto fail;
+
+       switch (state->current_modulation) {
+       case QAM_256:
+       case QAM_64:
+               if (val & (1 << 1))
+                       *locked = 1;
+
+               switch (val & 0x07) {
+               case 0:
+                       cr_lock_state = "QAM UNLOCK";
+                       break;
+               case 4:
+                       cr_lock_state = "QAM 1stLock";
+                       break;
+               case 6:
+                       cr_lock_state = "QAM 2ndLock";
+                       break;
+               case 7:
+                       cr_lock_state = "QAM FinalLock";
+                       break;
+               default:
+                       cr_lock_state = "CLOCKQAM-INVALID!";
+                       break;
+               }
+               break;
+       case VSB_8:
+               if (val & (1 << 7)) {
+                       *locked = 1;
+                       cr_lock_state = "CLOCKVSB";
+               }
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       lg_dbg("(%d) %s\n", *locked, cr_lock_state);
+fail:
+       return ret;
+}
+
+static int lgdt3305_read_fec_lock_status(struct lgdt3305_state *state,
+                                        int *locked)
+{
+       u8 val;
+       int ret, mpeg_lock, fec_lock, viterbi_lock;
+
+       *locked = 0;
+
+       switch (state->current_modulation) {
+       case QAM_256:
+       case QAM_64:
+               ret = lgdt3305_read_reg(state,
+                                       LGDT3305_FEC_LOCK_STATUS, &val);
+               if (lg_fail(ret))
+                       goto fail;
+
+               mpeg_lock    = (val & (1 << 0)) ? 1 : 0;
+               fec_lock     = (val & (1 << 2)) ? 1 : 0;
+               viterbi_lock = (val & (1 << 3)) ? 1 : 0;
+
+               *locked = mpeg_lock && fec_lock && viterbi_lock;
+
+               lg_dbg("(%d) %s%s%s\n", *locked,
+                      mpeg_lock    ? "mpeg lock  "  : "",
+                      fec_lock     ? "fec lock  "   : "",
+                      viterbi_lock ? "viterbi lock" : "");
+               break;
+       case VSB_8:
+       default:
+               ret = -EINVAL;
+       }
+fail:
+       return ret;
+}
+
+static int lgdt3305_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct lgdt3305_state *state = fe->demodulator_priv;
+       u8 val;
+       int ret, signal, inlock, nofecerr, snrgood,
+               cr_lock, fec_lock, sync_lock;
+
+       *status = 0;
+
+       ret = lgdt3305_read_reg(state, LGDT3305_GEN_STATUS, &val);
+       if (lg_fail(ret))
+               goto fail;
+
+       signal    = (val & (1 << 4)) ? 1 : 0;
+       inlock    = (val & (1 << 3)) ? 0 : 1;
+       sync_lock = (val & (1 << 2)) ? 1 : 0;
+       nofecerr  = (val & (1 << 1)) ? 1 : 0;
+       snrgood   = (val & (1 << 0)) ? 1 : 0;
+
+       lg_dbg("%s%s%s%s%s\n",
+              signal    ? "SIGNALEXIST " : "",
+              inlock    ? "INLOCK "      : "",
+              sync_lock ? "SYNCLOCK "    : "",
+              nofecerr  ? "NOFECERR "    : "",
+              snrgood   ? "SNRGOOD "     : "");
+
+       ret = lgdt3305_read_cr_lock_status(state, &cr_lock);
+       if (lg_fail(ret))
+               goto fail;
+
+       if (signal)
+               *status |= FE_HAS_SIGNAL;
+       if (cr_lock)
+               *status |= FE_HAS_CARRIER;
+       if (nofecerr)
+               *status |= FE_HAS_VITERBI;
+       if (sync_lock)
+               *status |= FE_HAS_SYNC;
+
+       switch (state->current_modulation) {
+       case QAM_256:
+       case QAM_64:
+               ret = lgdt3305_read_fec_lock_status(state, &fec_lock);
+               if (lg_fail(ret))
+                       goto fail;
+
+               if (fec_lock)
+                       *status |= FE_HAS_LOCK;
+               break;
+       case VSB_8:
+               if (inlock)
+                       *status |= FE_HAS_LOCK;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+fail:
+       return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* borrowed from lgdt330x.c */
+static u32 calculate_snr(u32 mse, u32 c)
+{
+       if (mse == 0) /* no signal */
+               return 0;
+
+       mse = intlog10(mse);
+       if (mse > c) {
+               /* Negative SNR, which is possible, but realisticly the
+               demod will lose lock before the signal gets this bad.  The
+               API only allows for unsigned values, so just return 0 */
+               return 0;
+       }
+       return 10*(c - mse);
+}
+
+static int lgdt3305_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct lgdt3305_state *state = fe->demodulator_priv;
+       u32 noise;      /* noise value */
+       u32 c;          /* per-modulation SNR calculation constant */
+
+       switch (state->current_modulation) {
+       case VSB_8:
+#ifdef USE_PTMSE
+               /* Use Phase Tracker Mean-Square Error Register */
+               /* SNR for ranges from -13.11 to +44.08 */
+               noise = ((read_reg(state, LGDT3305_PT_MSE_1) & 0x07) << 16) |
+                       (read_reg(state, LGDT3305_PT_MSE_2) << 8) |
+                       (read_reg(state, LGDT3305_PT_MSE_3) & 0xff);
+               c = 73957994; /* log10(25*32^2)*2^24 */
+#else
+               /* Use Equalizer Mean-Square Error Register */
+               /* SNR for ranges from -16.12 to +44.08 */
+               noise = ((read_reg(state, LGDT3305_EQ_MSE_1) & 0x0f) << 16) |
+                       (read_reg(state, LGDT3305_EQ_MSE_2) << 8) |
+                       (read_reg(state, LGDT3305_EQ_MSE_3) & 0xff);
+               c = 73957994; /* log10(25*32^2)*2^24 */
+#endif
+               break;
+       case QAM_64:
+       case QAM_256:
+               noise = (read_reg(state, LGDT3305_CR_MSE_1) << 8) |
+                       (read_reg(state, LGDT3305_CR_MSE_2) & 0xff);
+
+               c = (state->current_modulation == QAM_64) ?
+                       97939837 : 98026066;
+               /* log10(688128)*2^24 and log10(696320)*2^24 */
+               break;
+       default:
+               return -EINVAL;
+       }
+       state->snr = calculate_snr(noise, c);
+       /* report SNR in dB * 10 */
+       *snr = (state->snr / ((1 << 24) / 10));
+       lg_dbg("noise = 0x%08x, snr = %d.%02d dB\n", noise,
+              state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
+
+       return 0;
+}
+
+static int lgdt3305_read_signal_strength(struct dvb_frontend *fe,
+                                        u16 *strength)
+{
+       /* borrowed from lgdt330x.c
+        *
+        * Calculate strength from SNR up to 35dB
+        * Even though the SNR can go higher than 35dB,
+        * there is some comfort factor in having a range of
+        * strong signals that can show at 100%
+        */
+       struct lgdt3305_state *state = fe->demodulator_priv;
+       u16 snr;
+       int ret;
+
+       *strength = 0;
+
+       ret = fe->ops.read_snr(fe, &snr);
+       if (lg_fail(ret))
+               goto fail;
+       /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
+       /* scale the range 0 - 35*2^24 into 0 - 65535 */
+       if (state->snr >= 8960 * 0x10000)
+               *strength = 0xffff;
+       else
+               *strength = state->snr / 8960;
+fail:
+       return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3305_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       *ber = 0;
+       return 0;
+}
+
+static int lgdt3305_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       struct lgdt3305_state *state = fe->demodulator_priv;
+
+       *ucblocks =
+               (read_reg(state, LGDT3305_FEC_PKT_ERR_1) << 8) |
+               (read_reg(state, LGDT3305_FEC_PKT_ERR_2) & 0xff);
+
+       return 0;
+}
+
+static int lgdt3305_get_tune_settings(struct dvb_frontend *fe,
+                                     struct dvb_frontend_tune_settings
+                                       *fe_tune_settings)
+{
+       fe_tune_settings->min_delay_ms = 500;
+       lg_dbg("\n");
+       return 0;
+}
+
+static void lgdt3305_release(struct dvb_frontend *fe)
+{
+       struct lgdt3305_state *state = fe->demodulator_priv;
+       lg_dbg("\n");
+       kfree(state);
+}
+
+static struct dvb_frontend_ops lgdt3305_ops;
+
+struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
+                                    struct i2c_adapter *i2c_adap)
+{
+       struct lgdt3305_state *state = NULL;
+       int ret;
+       u8 val;
+
+       lg_dbg("(%d-%04x)\n",
+              i2c_adap ? i2c_adapter_id(i2c_adap) : 0,
+              config ? config->i2c_addr : 0);
+
+       state = kzalloc(sizeof(struct lgdt3305_state), GFP_KERNEL);
+       if (state == NULL)
+               goto fail;
+
+       state->cfg = config;
+       state->i2c_adap = i2c_adap;
+
+       memcpy(&state->frontend.ops, &lgdt3305_ops,
+              sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+
+       /* verify that we're talking to a lg dt3305 */
+       ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val);
+       if ((lg_fail(ret)) | (val == 0))
+               goto fail;
+       ret = lgdt3305_write_reg(state, 0x0808, 0x80);
+       if (lg_fail(ret))
+               goto fail;
+       ret = lgdt3305_read_reg(state, 0x0808, &val);
+       if ((lg_fail(ret)) | (val != 0x80))
+               goto fail;
+       ret = lgdt3305_write_reg(state, 0x0808, 0x00);
+       if (lg_fail(ret))
+               goto fail;
+
+       state->current_frequency = -1;
+       state->current_modulation = -1;
+
+       return &state->frontend;
+fail:
+       lg_warn("unable to detect LGDT3305 hardware\n");
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(lgdt3305_attach);
+
+static struct dvb_frontend_ops lgdt3305_ops = {
+       .info = {
+               .name = "LG Electronics LGDT3305 VSB/QAM Frontend",
+               .type               = FE_ATSC,
+               .frequency_min      = 54000000,
+               .frequency_max      = 858000000,
+               .frequency_stepsize = 62500,
+               .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+       },
+       .i2c_gate_ctrl        = lgdt3305_i2c_gate_ctrl,
+       .init                 = lgdt3305_init,
+       .sleep                = lgdt3305_sleep,
+       .set_frontend         = lgdt3305_set_parameters,
+       .get_frontend         = lgdt3305_get_frontend,
+       .get_tune_settings    = lgdt3305_get_tune_settings,
+       .read_status          = lgdt3305_read_status,
+       .read_ber             = lgdt3305_read_ber,
+       .read_signal_strength = lgdt3305_read_signal_strength,
+       .read_snr             = lgdt3305_read_snr,
+       .read_ucblocks        = lgdt3305_read_ucblocks,
+       .release              = lgdt3305_release,
+};
+
+MODULE_DESCRIPTION("LG Electronics LGDT3305 ATSC/QAM-B Demodulator Driver");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/lgdt3305.h b/drivers/media/dvb/frontends/lgdt3305.h
new file mode 100644 (file)
index 0000000..4fa6e52
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ *    Support for LGDT3305 - VSB/QAM
+ *
+ *    Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    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 _LGDT3305_H_
+#define _LGDT3305_H_
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+
+enum lgdt3305_mpeg_mode {
+       LGDT3305_MPEG_PARALLEL = 0,
+       LGDT3305_MPEG_SERIAL = 1,
+};
+
+enum lgdt3305_tp_clock_edge {
+       LGDT3305_TPCLK_RISING_EDGE = 0,
+       LGDT3305_TPCLK_FALLING_EDGE = 1,
+};
+
+enum lgdt3305_tp_valid_polarity {
+       LGDT3305_TP_VALID_LOW = 0,
+       LGDT3305_TP_VALID_HIGH = 1,
+};
+
+struct lgdt3305_config {
+       u8 i2c_addr;
+
+       /* user defined IF frequency in KHz */
+       u16 qam_if_khz;
+       u16 vsb_if_khz;
+
+       /* AGC Power reference - defaults are used if left unset */
+       u16 usref_8vsb;   /* default: 0x32c4 */
+       u16 usref_qam64;  /* default: 0x5400 */
+       u16 usref_qam256; /* default: 0x2a80 */
+
+       /* disable i2c repeater - 0:repeater enabled 1:repeater disabled */
+       int deny_i2c_rptr:1;
+
+       /* spectral inversion - 0:disabled 1:enabled */
+       int spectral_inversion:1;
+
+       /* use RF AGC loop - 0:disabled 1:enabled */
+       int rf_agc_loop:1;
+
+       enum lgdt3305_mpeg_mode mpeg_mode;
+       enum lgdt3305_tp_clock_edge tpclk_edge;
+       enum lgdt3305_tp_valid_polarity tpvalid_polarity;
+};
+
+#if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \
+                                    defined(MODULE))
+extern
+struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
+                                    struct i2c_adapter *i2c_adap);
+#else
+static inline
+struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
+                                    struct i2c_adapter *i2c_adap)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_LGDT3305 */
+
+#endif /* _LGDT3305_H_ */
diff --git a/drivers/media/dvb/frontends/lnbh24.h b/drivers/media/dvb/frontends/lnbh24.h
new file mode 100644 (file)
index 0000000..c059b16
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * lnbh24.h - driver for lnb supply and control ic lnbh24
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * 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 _LNBH24_H
+#define _LNBH24_H
+
+/* system register bits */
+#define LNBH24_OLF     0x01
+#define LNBH24_OTF     0x02
+#define LNBH24_EN      0x04
+#define LNBH24_VSEL    0x08
+#define LNBH24_LLC     0x10
+#define LNBH24_TEN     0x20
+#define LNBH24_TTX     0x40
+#define LNBH24_PCL     0x80
+
+#include <linux/dvb/frontend.h>
+
+#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) \
+                                                       && defined(MODULE))
+/* override_set and override_clear control which
+   system register bits (above) to always set & clear */
+extern struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
+                               struct i2c_adapter *i2c, u8 override_set,
+                               u8 override_clear, u8 i2c_addr);
+#else
+static inline struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
+                               struct i2c_adapter *i2c, u8 override_set,
+                               u8 override_clear, u8 i2c_addr)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif
index 76f935d9755a4764ed775f0b26c72bc9d05102e8..1dcc56f32bff71e92a1c1b94e9ef2463bbe4b725 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * lnbp21.h - driver for lnb supply and control ic lnbp21
+ * lnbp21.c - driver for lnb supply and control ic lnbp21
  *
  * Copyright (C) 2006 Oliver Endriss
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 
 #include "dvb_frontend.h"
 #include "lnbp21.h"
+#include "lnbh24.h"
 
 struct lnbp21 {
        u8                      config;
        u8                      override_or;
        u8                      override_and;
        struct i2c_adapter      *i2c;
+       u8                      i2c_addr;
 };
 
-static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+static int lnbp21_set_voltage(struct dvb_frontend *fe,
+                                       fe_sec_voltage_t voltage)
 {
        struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
-       struct i2c_msg msg = {  .addr = 0x08, .flags = 0,
+       struct i2c_msg msg = {  .addr = lnbp21->i2c_addr, .flags = 0,
                                .buf = &lnbp21->config,
                                .len = sizeof(lnbp21->config) };
 
@@ -72,7 +76,7 @@ static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
 {
        struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
-       struct i2c_msg msg = {  .addr = 0x08, .flags = 0,
+       struct i2c_msg msg = {  .addr = lnbp21->i2c_addr, .flags = 0,
                                .buf = &lnbp21->config,
                                .len = sizeof(lnbp21->config) };
 
@@ -97,15 +101,18 @@ static void lnbp21_release(struct dvb_frontend *fe)
        fe->sec_priv = NULL;
 }
 
-struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe,
+                               struct i2c_adapter *i2c, u8 override_set,
+                               u8 override_clear, u8 i2c_addr, u8 config)
 {
        struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
        if (!lnbp21)
                return NULL;
 
        /* default configuration */
-       lnbp21->config = LNBP21_ISEL;
+       lnbp21->config = config;
        lnbp21->i2c = i2c;
+       lnbp21->i2c_addr = i2c_addr;
        fe->sec_priv = lnbp21;
 
        /* bits which should be forced to '1' */
@@ -126,11 +133,29 @@ struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *
        /* override frontend ops */
        fe->ops.set_voltage = lnbp21_set_voltage;
        fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+       printk(KERN_INFO "LNBx2x attached on addr=%x", lnbp21->i2c_addr);
 
        return fe;
 }
+
+struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
+                               struct i2c_adapter *i2c, u8 override_set,
+                               u8 override_clear, u8 i2c_addr)
+{
+       return lnbx2x_attach(fe, i2c, override_set, override_clear,
+                                                       i2c_addr, LNBH24_TTX);
+}
+EXPORT_SYMBOL(lnbh24_attach);
+
+struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
+                               struct i2c_adapter *i2c, u8 override_set,
+                               u8 override_clear)
+{
+       return lnbx2x_attach(fe, i2c, override_set, override_clear,
+                                                       0x08, LNBP21_ISEL);
+}
 EXPORT_SYMBOL(lnbp21_attach);
 
-MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21");
-MODULE_AUTHOR("Oliver Endriss");
+MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21, lnbh24");
+MODULE_AUTHOR("Oliver Endriss, Igor M. Liplianin");
 MODULE_LICENSE("GPL");
index 8fe094bd9689a1e793ce2d553abc5a306c9143c5..fcdf1c650dde094c49010cf05d93d94b2e6f4d9b 100644 (file)
 #define _LNBP21_H
 
 /* system register bits */
+/* [RO] 0=OK; 1=over current limit flag */
 #define LNBP21_OLF     0x01
+/* [RO] 0=OK; 1=over temperature flag (150 C) */
 #define LNBP21_OTF     0x02
+/* [RW] 0=disable LNB power, enable loopthrough
+       1=enable LNB power, disable loopthrough */
 #define LNBP21_EN      0x04
+/* [RW] 0=low voltage (13/14V, vert pol)
+       1=high voltage (18/19V,horiz pol) */
 #define LNBP21_VSEL    0x08
+/* [RW] increase LNB voltage by 1V:
+       0=13/18V; 1=14/19V */
 #define LNBP21_LLC     0x10
+/* [RW] 0=tone controlled by DSQIN pin
+       1=tone enable, disable DSQIN */
 #define LNBP21_TEN     0x20
+/* [RW] current limit select:
+       0:Iout=500-650mA Isc=300mA
+       1:Iout=400-550mA Isc=200mA */
 #define LNBP21_ISEL    0x40
+/* [RW] short-circuit protect:
+       0=pulsed (dynamic) curr limiting
+       1=static curr limiting */
 #define LNBP21_PCL     0x80
 
 #include <linux/dvb/frontend.h>
 
-#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) && defined(MODULE))
-/* override_set and override_clear control which system register bits (above) to always set & clear */
-extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear);
+#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) \
+                                                       && defined(MODULE))
+/* override_set and override_clear control which
+ system register bits (above) to always set & clear */
+extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
+                               struct i2c_adapter *i2c, u8 override_set,
+                               u8 override_clear);
 #else
-static inline struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+static inline struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
+                               struct i2c_adapter *i2c, u8 override_set,
+                               u8 override_clear)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
 }
-#endif // CONFIG_DVB_LNBP21
+#endif
 
-#endif // _LNBP21_H
+#endif
index 892af8c9ed570d3038b0f9f4b040aea3040d629f..3f5a0e1dfdf5dd50918966f6474d4e8b25e01b89 100644 (file)
@@ -169,7 +169,6 @@ struct dvb_frontend* s921_attach(const struct s921_config *config,
 
        struct s921_state *state;
        state = kzalloc(sizeof(struct s921_state), GFP_KERNEL);
-       memset(state, 0x0, sizeof(struct s921_state));
 
        state->addr = config->i2c_address;
        state->i2c = i2c;
index d3133405dc03f7e366eb6481ff3795e6f96217b7..6314d18c797a49ba95ee278ea70149194e97312c 100644 (file)
@@ -36,7 +36,6 @@ static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
                        return err;
                }
                *frequency = t_state.frequency;
-               printk("%s: Frequency=%d\n", __func__, t_state.frequency);
        }
        return 0;
 }
@@ -59,7 +58,6 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
                        return err;
                }
        }
-       printk("%s: Frequency=%d\n", __func__, t_state.frequency);
        return 0;
 }
 
@@ -81,7 +79,6 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
                }
                *bandwidth = t_state.bandwidth;
        }
-       printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
        return 0;
 }
 
@@ -103,6 +100,5 @@ static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
                        return err;
                }
        }
-       printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
        return 0;
 }
diff --git a/drivers/media/dvb/frontends/stv0900.h b/drivers/media/dvb/frontends/stv0900.h
new file mode 100644 (file)
index 0000000..8a1332c
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * stv0900.h
+ *
+ * Driver for ST STV0900 satellite demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * 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 STV0900_H
+#define STV0900_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct stv0900_config {
+       u8 demod_address;
+       u32 xtal;
+       u8 clkmode;/* 0 for CLKI,  2 for XTALI */
+
+       u8 diseqc_mode;
+
+       u8 path1_mode;
+       u8 path2_mode;
+
+       u8 tun1_maddress;/* 0, 1, 2, 3 for 0xc0, 0xc2, 0xc4, 0xc6 */
+       u8 tun2_maddress;
+       u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */
+       u8 tun2_adc;
+};
+
+#if defined(CONFIG_DVB_STV0900) || (defined(CONFIG_DVB_STV0900_MODULE) \
+                                                       && defined(MODULE))
+extern struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
+                                       struct i2c_adapter *i2c, int demod);
+#else
+static inline struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
+                                       struct i2c_adapter *i2c, int demod)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif
+
diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c
new file mode 100644 (file)
index 0000000..8499bcf
--- /dev/null
@@ -0,0 +1,1949 @@
+/*
+ * stv0900_core.c
+ *
+ * Driver for ST STV0900 satellite demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+
+#include "stv0900.h"
+#include "stv0900_reg.h"
+#include "stv0900_priv.h"
+#include "stv0900_init.h"
+
+static int stvdebug = 1;
+module_param_named(debug, stvdebug, int, 0644);
+
+/* internal params node */
+struct stv0900_inode {
+       /* pointer for internal params, one for each pair of demods */
+       struct stv0900_internal         *internal;
+       struct stv0900_inode            *next_inode;
+};
+
+/* first internal params */
+static struct stv0900_inode *stv0900_first_inode;
+
+/* find chip by i2c adapter and i2c address */
+static struct stv0900_inode *find_inode(struct i2c_adapter *i2c_adap,
+                                                       u8 i2c_addr)
+{
+       struct stv0900_inode *temp_chip = stv0900_first_inode;
+
+       if (temp_chip != NULL) {
+               /*
+                Search of the last stv0900 chip or
+                find it by i2c adapter and i2c address */
+               while ((temp_chip != NULL) &&
+                       ((temp_chip->internal->i2c_adap != i2c_adap) ||
+                       (temp_chip->internal->i2c_addr != i2c_addr)))
+
+                       temp_chip = temp_chip->next_inode;
+
+       }
+
+       return temp_chip;
+}
+
+/* deallocating chip */
+static void remove_inode(struct stv0900_internal *internal)
+{
+       struct stv0900_inode *prev_node = stv0900_first_inode;
+       struct stv0900_inode *del_node = find_inode(internal->i2c_adap,
+                                               internal->i2c_addr);
+
+       if (del_node != NULL) {
+               if (del_node == stv0900_first_inode) {
+                       stv0900_first_inode = del_node->next_inode;
+               } else {
+                       while (prev_node->next_inode != del_node)
+                               prev_node = prev_node->next_inode;
+
+                       if (del_node->next_inode == NULL)
+                               prev_node->next_inode = NULL;
+                       else
+                               prev_node->next_inode =
+                                       prev_node->next_inode->next_inode;
+               }
+
+               kfree(del_node);
+       }
+}
+
+/* allocating new chip */
+static struct stv0900_inode *append_internal(struct stv0900_internal *internal)
+{
+       struct stv0900_inode *new_node = stv0900_first_inode;
+
+       if (new_node == NULL) {
+               new_node = kmalloc(sizeof(struct stv0900_inode), GFP_KERNEL);
+               stv0900_first_inode = new_node;
+       } else {
+               while (new_node->next_inode != NULL)
+                       new_node = new_node->next_inode;
+
+               new_node->next_inode = kmalloc(sizeof(struct stv0900_inode), GFP_KERNEL);
+               if (new_node->next_inode != NULL)
+                       new_node = new_node->next_inode;
+               else
+                       new_node = NULL;
+       }
+
+       if (new_node != NULL) {
+               new_node->internal = internal;
+               new_node->next_inode = NULL;
+       }
+
+       return new_node;
+}
+
+s32 ge2comp(s32 a, s32 width)
+{
+       if (width == 32)
+               return a;
+       else
+               return (a >= (1 << (width - 1))) ? (a - (1 << width)) : a;
+}
+
+void stv0900_write_reg(struct stv0900_internal *i_params, u16 reg_addr,
+                                                               u8 reg_data)
+{
+       u8 data[3];
+       int ret;
+       struct i2c_msg i2cmsg = {
+               .addr  = i_params->i2c_addr,
+               .flags = 0,
+               .len   = 3,
+               .buf   = data,
+       };
+
+       data[0] = MSB(reg_addr);
+       data[1] = LSB(reg_addr);
+       data[2] = reg_data;
+
+       ret = i2c_transfer(i_params->i2c_adap, &i2cmsg, 1);
+       if (ret != 1)
+               dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret);
+}
+
+u8 stv0900_read_reg(struct stv0900_internal *i_params, u16 reg_addr)
+{
+       u8 data[2];
+       int ret;
+       struct i2c_msg i2cmsg = {
+               .addr  = i_params->i2c_addr,
+               .flags = 0,
+               .len   = 2,
+               .buf   = data,
+       };
+
+       data[0] = MSB(reg_addr);
+       data[1] = LSB(reg_addr);
+
+       ret = i2c_transfer(i_params->i2c_adap, &i2cmsg, 1);
+       if (ret != 1)
+               dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret);
+
+       i2cmsg.flags = I2C_M_RD;
+       i2cmsg.len = 1;
+       ret = i2c_transfer(i_params->i2c_adap, &i2cmsg, 1);
+       if (ret != 1)
+               dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret);
+
+       return data[0];
+}
+
+void extract_mask_pos(u32 label, u8 *mask, u8 *pos)
+{
+       u8 position = 0, i = 0;
+
+       (*mask) = label & 0xff;
+
+       while ((position == 0) && (i < 8)) {
+               position = ((*mask) >> i) & 0x01;
+               i++;
+       }
+
+       (*pos) = (i - 1);
+}
+
+void stv0900_write_bits(struct stv0900_internal *i_params, u32 label, u8 val)
+{
+       u8 reg, mask, pos;
+
+       reg = stv0900_read_reg(i_params, (label >> 16) & 0xffff);
+       extract_mask_pos(label, &mask, &pos);
+
+       val = mask & (val << pos);
+
+       reg = (reg & (~mask)) | val;
+       stv0900_write_reg(i_params, (label >> 16) & 0xffff, reg);
+
+}
+
+u8 stv0900_get_bits(struct stv0900_internal *i_params, u32 label)
+{
+       u8 val = 0xff;
+       u8 mask, pos;
+
+       extract_mask_pos(label, &mask, &pos);
+
+       val = stv0900_read_reg(i_params, label >> 16);
+       val = (val & mask) >> pos;
+
+       return val;
+}
+
+enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *i_params)
+{
+       s32 i;
+       enum fe_stv0900_error error;
+
+       if (i_params != NULL) {
+               i_params->chip_id = stv0900_read_reg(i_params, R0900_MID);
+               if (i_params->errs == STV0900_NO_ERROR) {
+                       /*Startup sequence*/
+                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x5c);
+                       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_NCOARSE, 0x13);
+                       msleep(3);
+                       stv0900_write_reg(i_params, R0900_I2CCFG, 0x08);
+
+                       switch (i_params->clkmode) {
+                       case 0:
+                       case 2:
+                               stv0900_write_reg(i_params, R0900_SYNTCTRL, 0x20
+                                               | i_params->clkmode);
+                               break;
+                       default:
+                               /* preserve SELOSCI bit */
+                               i = 0x02 & stv0900_read_reg(i_params, R0900_SYNTCTRL);
+                               stv0900_write_reg(i_params, R0900_SYNTCTRL, 0x20 | i);
+                               break;
+                       }
+
+                       msleep(3);
+                       for (i = 0; i < 182; i++)
+                               stv0900_write_reg(i_params, STV0900_InitVal[i][0], STV0900_InitVal[i][1]);
+
+                       if (stv0900_read_reg(i_params, R0900_MID) >= 0x20) {
+                               stv0900_write_reg(i_params, R0900_TSGENERAL, 0x0c);
+                               for (i = 0; i < 32; i++)
+                                       stv0900_write_reg(i_params, STV0900_Cut20_AddOnVal[i][0], STV0900_Cut20_AddOnVal[i][1]);
+                       }
+
+                       stv0900_write_reg(i_params, R0900_P1_FSPYCFG, 0x6c);
+                       stv0900_write_reg(i_params, R0900_P2_FSPYCFG, 0x6c);
+                       stv0900_write_reg(i_params, R0900_TSTRES0, 0x80);
+                       stv0900_write_reg(i_params, R0900_TSTRES0, 0x00);
+               }
+               error = i_params->errs;
+       } else
+               error = STV0900_INVALID_HANDLE;
+
+       return error;
+
+}
+
+u32 stv0900_get_mclk_freq(struct stv0900_internal *i_params, u32 ext_clk)
+{
+       u32 mclk = 90000000, div = 0, ad_div = 0;
+
+       div = stv0900_get_bits(i_params, F0900_M_DIV);
+       ad_div = ((stv0900_get_bits(i_params, F0900_SELX1RATIO) == 1) ? 4 : 6);
+
+       mclk = (div + 1) * ext_clk / ad_div;
+
+       dprintk(KERN_INFO "%s: Calculated Mclk = %d\n", __func__, mclk);
+
+       return mclk;
+}
+
+enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *i_params, u32 mclk)
+{
+       enum fe_stv0900_error error = STV0900_NO_ERROR;
+       u32 m_div, clk_sel;
+
+       dprintk(KERN_INFO "%s: Mclk set to %d, Quartz = %d\n", __func__, mclk,
+                       i_params->quartz);
+
+       if (i_params == NULL)
+               error = STV0900_INVALID_HANDLE;
+       else {
+               if (i_params->errs)
+                       error = STV0900_I2C_ERROR;
+               else {
+                       clk_sel = ((stv0900_get_bits(i_params, F0900_SELX1RATIO) == 1) ? 4 : 6);
+                       m_div = ((clk_sel * mclk) / i_params->quartz) - 1;
+                       stv0900_write_bits(i_params, F0900_M_DIV, m_div);
+                       i_params->mclk = stv0900_get_mclk_freq(i_params,
+                                                       i_params->quartz);
+
+                       /*Set the DiseqC frequency to 22KHz */
+                       /*
+                               Formula:
+                               DiseqC_TX_Freq= MasterClock/(32*F22TX_Reg)
+                               DiseqC_RX_Freq= MasterClock/(32*F22RX_Reg)
+                       */
+                       m_div = i_params->mclk / 704000;
+                       stv0900_write_reg(i_params, R0900_P1_F22TX, m_div);
+                       stv0900_write_reg(i_params, R0900_P1_F22RX, m_div);
+
+                       stv0900_write_reg(i_params, R0900_P2_F22TX, m_div);
+                       stv0900_write_reg(i_params, R0900_P2_F22RX, m_div);
+
+                       if ((i_params->errs))
+                               error = STV0900_I2C_ERROR;
+               }
+       }
+
+       return error;
+}
+
+u32 stv0900_get_err_count(struct stv0900_internal *i_params, int cntr,
+                                       enum fe_stv0900_demod_num demod)
+{
+       u32 lsb, msb, hsb, err_val;
+       s32 err1field_hsb, err1field_msb, err1field_lsb;
+       s32 err2field_hsb, err2field_msb, err2field_lsb;
+
+       dmd_reg(err1field_hsb, F0900_P1_ERR_CNT12, F0900_P2_ERR_CNT12);
+       dmd_reg(err1field_msb, F0900_P1_ERR_CNT11, F0900_P2_ERR_CNT11);
+       dmd_reg(err1field_lsb, F0900_P1_ERR_CNT10, F0900_P2_ERR_CNT10);
+
+       dmd_reg(err2field_hsb, F0900_P1_ERR_CNT22, F0900_P2_ERR_CNT22);
+       dmd_reg(err2field_msb, F0900_P1_ERR_CNT21, F0900_P2_ERR_CNT21);
+       dmd_reg(err2field_lsb, F0900_P1_ERR_CNT20, F0900_P2_ERR_CNT20);
+
+       switch (cntr) {
+       case 0:
+       default:
+               hsb = stv0900_get_bits(i_params, err1field_hsb);
+               msb = stv0900_get_bits(i_params, err1field_msb);
+               lsb = stv0900_get_bits(i_params, err1field_lsb);
+               break;
+       case 1:
+               hsb = stv0900_get_bits(i_params, err2field_hsb);
+               msb = stv0900_get_bits(i_params, err2field_msb);
+               lsb = stv0900_get_bits(i_params, err2field_lsb);
+               break;
+       }
+
+       err_val = (hsb << 16) + (msb << 8) + (lsb);
+
+       return err_val;
+}
+
+static int stv0900_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       enum fe_stv0900_demod_num demod = state->demod;
+
+       u32 fi2c;
+
+       dmd_reg(fi2c, F0900_P1_I2CT_ON, F0900_P2_I2CT_ON);
+       if (enable)
+               stv0900_write_bits(i_params, fi2c, 1);
+
+       return 0;
+}
+
+static void stv0900_set_ts_parallel_serial(struct stv0900_internal *i_params,
+                                       enum fe_stv0900_clock_type path1_ts,
+                                       enum fe_stv0900_clock_type path2_ts)
+{
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       if (i_params->chip_id >= 0x20) {
+               switch (path1_ts) {
+               case STV0900_PARALLEL_PUNCT_CLOCK:
+               case STV0900_DVBCI_CLOCK:
+                       switch (path2_ts) {
+                       case STV0900_SERIAL_PUNCT_CLOCK:
+                       case STV0900_SERIAL_CONT_CLOCK:
+                       default:
+                               stv0900_write_reg(i_params, R0900_TSGENERAL,
+                                                       0x00);
+                               break;
+                       case STV0900_PARALLEL_PUNCT_CLOCK:
+                       case STV0900_DVBCI_CLOCK:
+                               stv0900_write_reg(i_params, R0900_TSGENERAL,
+                                                       0x06);
+                               stv0900_write_bits(i_params,
+                                               F0900_P1_TSFIFO_MANSPEED, 3);
+                               stv0900_write_bits(i_params,
+                                               F0900_P2_TSFIFO_MANSPEED, 0);
+                               stv0900_write_reg(i_params,
+                                               R0900_P1_TSSPEED, 0x14);
+                               stv0900_write_reg(i_params,
+                                               R0900_P2_TSSPEED, 0x28);
+                               break;
+                       }
+                       break;
+               case STV0900_SERIAL_PUNCT_CLOCK:
+               case STV0900_SERIAL_CONT_CLOCK:
+               default:
+                       switch (path2_ts) {
+                       case STV0900_SERIAL_PUNCT_CLOCK:
+                       case STV0900_SERIAL_CONT_CLOCK:
+                       default:
+                               stv0900_write_reg(i_params,
+                                               R0900_TSGENERAL, 0x0C);
+                               break;
+                       case STV0900_PARALLEL_PUNCT_CLOCK:
+                       case STV0900_DVBCI_CLOCK:
+                               stv0900_write_reg(i_params,
+                                               R0900_TSGENERAL, 0x0A);
+                               dprintk(KERN_INFO "%s: 0x0a\n", __func__);
+                               break;
+                       }
+                       break;
+               }
+       } else {
+               switch (path1_ts) {
+               case STV0900_PARALLEL_PUNCT_CLOCK:
+               case STV0900_DVBCI_CLOCK:
+                       switch (path2_ts) {
+                       case STV0900_SERIAL_PUNCT_CLOCK:
+                       case STV0900_SERIAL_CONT_CLOCK:
+                       default:
+                               stv0900_write_reg(i_params, R0900_TSGENERAL1X,
+                                                       0x10);
+                               break;
+                       case STV0900_PARALLEL_PUNCT_CLOCK:
+                       case STV0900_DVBCI_CLOCK:
+                               stv0900_write_reg(i_params, R0900_TSGENERAL1X,
+                                                       0x16);
+                               stv0900_write_bits(i_params,
+                                               F0900_P1_TSFIFO_MANSPEED, 3);
+                               stv0900_write_bits(i_params,
+                                               F0900_P2_TSFIFO_MANSPEED, 0);
+                               stv0900_write_reg(i_params, R0900_P1_TSSPEED,
+                                                       0x14);
+                               stv0900_write_reg(i_params, R0900_P2_TSSPEED,
+                                                       0x28);
+                               break;
+                       }
+
+                       break;
+               case STV0900_SERIAL_PUNCT_CLOCK:
+               case STV0900_SERIAL_CONT_CLOCK:
+               default:
+                       switch (path2_ts) {
+                       case STV0900_SERIAL_PUNCT_CLOCK:
+                       case STV0900_SERIAL_CONT_CLOCK:
+                       default:
+                               stv0900_write_reg(i_params, R0900_TSGENERAL1X,
+                                                       0x14);
+                               break;
+                       case STV0900_PARALLEL_PUNCT_CLOCK:
+                       case STV0900_DVBCI_CLOCK:
+                               stv0900_write_reg(i_params, R0900_TSGENERAL1X,
+                                                       0x12);
+                               dprintk(KERN_INFO "%s: 0x12\n", __func__);
+                               break;
+                       }
+
+                       break;
+               }
+       }
+
+       switch (path1_ts) {
+       case STV0900_PARALLEL_PUNCT_CLOCK:
+               stv0900_write_bits(i_params, F0900_P1_TSFIFO_SERIAL, 0x00);
+               stv0900_write_bits(i_params, F0900_P1_TSFIFO_DVBCI, 0x00);
+               break;
+       case STV0900_DVBCI_CLOCK:
+               stv0900_write_bits(i_params, F0900_P1_TSFIFO_SERIAL, 0x00);
+               stv0900_write_bits(i_params, F0900_P1_TSFIFO_DVBCI, 0x01);
+               break;
+       case STV0900_SERIAL_PUNCT_CLOCK:
+               stv0900_write_bits(i_params, F0900_P1_TSFIFO_SERIAL, 0x01);
+               stv0900_write_bits(i_params, F0900_P1_TSFIFO_DVBCI, 0x00);
+               break;
+       case STV0900_SERIAL_CONT_CLOCK:
+               stv0900_write_bits(i_params, F0900_P1_TSFIFO_SERIAL, 0x01);
+               stv0900_write_bits(i_params, F0900_P1_TSFIFO_DVBCI, 0x01);
+               break;
+       default:
+               break;
+       }
+
+       switch (path2_ts) {
+       case STV0900_PARALLEL_PUNCT_CLOCK:
+               stv0900_write_bits(i_params, F0900_P2_TSFIFO_SERIAL, 0x00);
+               stv0900_write_bits(i_params, F0900_P2_TSFIFO_DVBCI, 0x00);
+               break;
+       case STV0900_DVBCI_CLOCK:
+               stv0900_write_bits(i_params, F0900_P2_TSFIFO_SERIAL, 0x00);
+               stv0900_write_bits(i_params, F0900_P2_TSFIFO_DVBCI, 0x01);
+               break;
+       case STV0900_SERIAL_PUNCT_CLOCK:
+               stv0900_write_bits(i_params, F0900_P2_TSFIFO_SERIAL, 0x01);
+               stv0900_write_bits(i_params, F0900_P2_TSFIFO_DVBCI, 0x00);
+               break;
+       case STV0900_SERIAL_CONT_CLOCK:
+               stv0900_write_bits(i_params, F0900_P2_TSFIFO_SERIAL, 0x01);
+               stv0900_write_bits(i_params, F0900_P2_TSFIFO_DVBCI, 0x01);
+               break;
+       default:
+               break;
+       }
+
+       stv0900_write_bits(i_params, F0900_P2_RST_HWARE, 1);
+       stv0900_write_bits(i_params, F0900_P2_RST_HWARE, 0);
+       stv0900_write_bits(i_params, F0900_P1_RST_HWARE, 1);
+       stv0900_write_bits(i_params, F0900_P1_RST_HWARE, 0);
+}
+
+void stv0900_set_tuner(struct dvb_frontend *fe, u32 frequency,
+                                                       u32 bandwidth)
+{
+       struct dvb_frontend_ops *frontend_ops = NULL;
+       struct dvb_tuner_ops *tuner_ops = NULL;
+
+       if (&fe->ops)
+               frontend_ops = &fe->ops;
+
+       if (&frontend_ops->tuner_ops)
+               tuner_ops = &frontend_ops->tuner_ops;
+
+       if (tuner_ops->set_frequency) {
+               if ((tuner_ops->set_frequency(fe, frequency)) < 0)
+                       dprintk("%s: Invalid parameter\n", __func__);
+               else
+                       dprintk("%s: Frequency=%d\n", __func__, frequency);
+
+       }
+
+       if (tuner_ops->set_bandwidth) {
+               if ((tuner_ops->set_bandwidth(fe, bandwidth)) < 0)
+                       dprintk("%s: Invalid parameter\n", __func__);
+               else
+                       dprintk("%s: Bandwidth=%d\n", __func__, bandwidth);
+
+       }
+}
+
+void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
+{
+       struct dvb_frontend_ops *frontend_ops = NULL;
+       struct dvb_tuner_ops *tuner_ops = NULL;
+
+       if (&fe->ops)
+               frontend_ops = &fe->ops;
+
+       if (&frontend_ops->tuner_ops)
+               tuner_ops = &frontend_ops->tuner_ops;
+
+       if (tuner_ops->set_bandwidth) {
+               if ((tuner_ops->set_bandwidth(fe, bandwidth)) < 0)
+                       dprintk("%s: Invalid parameter\n", __func__);
+               else
+                       dprintk("%s: Bandwidth=%d\n", __func__, bandwidth);
+
+       }
+}
+
+static s32 stv0900_get_rf_level(struct stv0900_internal *i_params,
+                               const struct stv0900_table *lookup,
+                               enum fe_stv0900_demod_num demod)
+{
+       s32 agc_gain = 0,
+               imin,
+               imax,
+               i,
+               rf_lvl = 0;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       if ((lookup != NULL) && lookup->size) {
+               switch (demod) {
+               case STV0900_DEMOD_1:
+               default:
+                       agc_gain = MAKEWORD(stv0900_get_bits(i_params, F0900_P1_AGCIQ_VALUE1),
+                                               stv0900_get_bits(i_params, F0900_P1_AGCIQ_VALUE0));
+                       break;
+               case STV0900_DEMOD_2:
+                       agc_gain = MAKEWORD(stv0900_get_bits(i_params, F0900_P2_AGCIQ_VALUE1),
+                                               stv0900_get_bits(i_params, F0900_P2_AGCIQ_VALUE0));
+                       break;
+               }
+
+               imin = 0;
+               imax = lookup->size - 1;
+               if (INRANGE(lookup->table[imin].regval, agc_gain, lookup->table[imax].regval)) {
+                       while ((imax - imin) > 1) {
+                               i = (imax + imin) >> 1;
+
+                               if (INRANGE(lookup->table[imin].regval, agc_gain, lookup->table[i].regval))
+                                       imax = i;
+                               else
+                                       imin = i;
+                       }
+
+                       rf_lvl = (((s32)agc_gain - lookup->table[imin].regval)
+                                       * (lookup->table[imax].realval - lookup->table[imin].realval)
+                                       / (lookup->table[imax].regval - lookup->table[imin].regval))
+                                       + lookup->table[imin].realval;
+               } else if (agc_gain > lookup->table[0].regval)
+                       rf_lvl = 5;
+               else if (agc_gain < lookup->table[lookup->size-1].regval)
+                       rf_lvl = -100;
+
+       }
+
+       dprintk(KERN_INFO "%s: RFLevel = %d\n", __func__, rf_lvl);
+
+       return rf_lvl;
+}
+
+static int stv0900_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *internal = state->internal;
+       s32 rflevel = stv0900_get_rf_level(internal, &stv0900_rf,
+                                                               state->demod);
+
+       *strength = (rflevel + 100) * (16383 / 105);
+
+       return 0;
+}
+
+
+static s32 stv0900_carr_get_quality(struct dvb_frontend *fe,
+                                       const struct stv0900_table *lookup)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       enum fe_stv0900_demod_num demod = state->demod;
+
+       s32 c_n = -100,
+               regval, imin, imax,
+               i,
+               lock_flag_field,
+               noise_field1,
+               noise_field0;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       dmd_reg(lock_flag_field, F0900_P1_LOCK_DEFINITIF,
+                                       F0900_P2_LOCK_DEFINITIF);
+       if (stv0900_get_standard(fe, demod) == STV0900_DVBS2_STANDARD) {
+               dmd_reg(noise_field1, F0900_P1_NOSPLHT_NORMED1,
+                                       F0900_P2_NOSPLHT_NORMED1);
+               dmd_reg(noise_field0, F0900_P1_NOSPLHT_NORMED0,
+                                       F0900_P2_NOSPLHT_NORMED0);
+       } else {
+               dmd_reg(noise_field1, F0900_P1_NOSDATAT_NORMED1,
+                                       F0900_P2_NOSDATAT_NORMED1);
+               dmd_reg(noise_field0, F0900_P1_NOSDATAT_NORMED0,
+                                       F0900_P2_NOSDATAT_NORMED0);
+       }
+
+       if (stv0900_get_bits(i_params, lock_flag_field)) {
+               if ((lookup != NULL) && lookup->size) {
+                       regval = 0;
+                       msleep(5);
+                       for (i = 0; i < 16; i++) {
+                               regval += MAKEWORD(stv0900_get_bits(i_params,
+                                                               noise_field1),
+                                               stv0900_get_bits(i_params,
+                                                               noise_field0));
+                               msleep(1);
+                       }
+
+                       regval /= 16;
+                       imin = 0;
+                       imax = lookup->size - 1;
+                       if (INRANGE(lookup->table[imin].regval,
+                                       regval,
+                                       lookup->table[imax].regval)) {
+                               while ((imax - imin) > 1) {
+                                       i = (imax + imin) >> 1;
+                                       if (INRANGE(lookup->table[imin].regval,
+                                                   regval,
+                                                   lookup->table[i].regval))
+                                               imax = i;
+                                       else
+                                               imin = i;
+                               }
+
+                               c_n = ((regval - lookup->table[imin].regval)
+                                               * (lookup->table[imax].realval
+                                               - lookup->table[imin].realval)
+                                               / (lookup->table[imax].regval
+                                               - lookup->table[imin].regval))
+                                               + lookup->table[imin].realval;
+                       } else if (regval < lookup->table[imin].regval)
+                               c_n = 1000;
+               }
+       }
+
+       return c_n;
+}
+
+static int stv0900_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       *snr = stv0900_carr_get_quality(fe,
+                       (const struct stv0900_table *)&stv0900_s2_cn);
+       *snr += 30;
+       *snr *= (16383 / 1030);
+
+       return 0;
+}
+
+static u32 stv0900_get_ber(struct stv0900_internal *i_params,
+                               enum fe_stv0900_demod_num demod)
+{
+       u32 ber = 10000000, i;
+       s32 dmd_state_reg;
+       s32 demod_state;
+       s32 vstatus_reg;
+       s32 prvit_field;
+       s32 pdel_status_reg;
+       s32 pdel_lock_field;
+
+       dmd_reg(dmd_state_reg, F0900_P1_HEADER_MODE, F0900_P2_HEADER_MODE);
+       dmd_reg(vstatus_reg, R0900_P1_VSTATUSVIT, R0900_P2_VSTATUSVIT);
+       dmd_reg(prvit_field, F0900_P1_PRFVIT, F0900_P2_PRFVIT);
+       dmd_reg(pdel_status_reg, R0900_P1_PDELSTATUS1, R0900_P2_PDELSTATUS1);
+       dmd_reg(pdel_lock_field, F0900_P1_PKTDELIN_LOCK,
+                               F0900_P2_PKTDELIN_LOCK);
+
+       demod_state = stv0900_get_bits(i_params, dmd_state_reg);
+
+       switch (demod_state) {
+       case STV0900_SEARCH:
+       case STV0900_PLH_DETECTED:
+       default:
+               ber = 10000000;
+               break;
+       case STV0900_DVBS_FOUND:
+               ber = 0;
+               for (i = 0; i < 5; i++) {
+                       msleep(5);
+                       ber += stv0900_get_err_count(i_params, 0, demod);
+               }
+
+               ber /= 5;
+               if (stv0900_get_bits(i_params, prvit_field)) {
+                       ber *= 9766;
+                       ber = ber >> 13;
+               }
+
+               break;
+       case STV0900_DVBS2_FOUND:
+               ber = 0;
+               for (i = 0; i < 5; i++) {
+                       msleep(5);
+                       ber += stv0900_get_err_count(i_params, 0, demod);
+               }
+
+               ber /= 5;
+               if (stv0900_get_bits(i_params, pdel_lock_field)) {
+                       ber *= 9766;
+                       ber = ber >> 13;
+               }
+
+               break;
+       }
+
+       return ber;
+}
+
+static int stv0900_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *internal = state->internal;
+
+       *ber = stv0900_get_ber(internal, state->demod);
+
+       return 0;
+}
+
+int stv0900_get_demod_lock(struct stv0900_internal *i_params,
+                       enum fe_stv0900_demod_num demod, s32 time_out)
+{
+       s32 timer = 0,
+               lock = 0,
+               header_field,
+               lock_field;
+
+       enum fe_stv0900_search_state    dmd_state;
+
+       dmd_reg(header_field, F0900_P1_HEADER_MODE, F0900_P2_HEADER_MODE);
+       dmd_reg(lock_field, F0900_P1_LOCK_DEFINITIF, F0900_P2_LOCK_DEFINITIF);
+       while ((timer < time_out) && (lock == 0)) {
+               dmd_state = stv0900_get_bits(i_params, header_field);
+               dprintk("Demod State = %d\n", dmd_state);
+               switch (dmd_state) {
+               case STV0900_SEARCH:
+               case STV0900_PLH_DETECTED:
+               default:
+                       lock = 0;
+                       break;
+               case STV0900_DVBS2_FOUND:
+               case STV0900_DVBS_FOUND:
+                       lock = stv0900_get_bits(i_params, lock_field);
+                       break;
+               }
+
+               if (lock == 0)
+                       msleep(10);
+
+               timer += 10;
+       }
+
+       if (lock)
+               dprintk("DEMOD LOCK OK\n");
+       else
+               dprintk("DEMOD LOCK FAIL\n");
+
+       return lock;
+}
+
+void stv0900_stop_all_s2_modcod(struct stv0900_internal *i_params,
+                               enum fe_stv0900_demod_num demod)
+{
+       s32 regflist,
+       i;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       dmd_reg(regflist, R0900_P1_MODCODLST0, R0900_P2_MODCODLST0);
+
+       for (i = 0; i < 16; i++)
+               stv0900_write_reg(i_params, regflist + i, 0xff);
+}
+
+void stv0900_activate_s2_modcode(struct stv0900_internal *i_params,
+                               enum fe_stv0900_demod_num demod)
+{
+       u32 matype,
+       mod_code,
+       fmod,
+       reg_index,
+       field_index;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       if (i_params->chip_id <= 0x11) {
+               msleep(5);
+
+               switch (demod) {
+               case STV0900_DEMOD_1:
+               default:
+                       mod_code = stv0900_read_reg(i_params,
+                                                       R0900_P1_PLHMODCOD);
+                       matype = mod_code & 0x3;
+                       mod_code = (mod_code & 0x7f) >> 2;
+
+                       reg_index = R0900_P1_MODCODLSTF - mod_code / 2;
+                       field_index = mod_code % 2;
+                       break;
+               case STV0900_DEMOD_2:
+                       mod_code = stv0900_read_reg(i_params,
+                                                       R0900_P2_PLHMODCOD);
+                       matype = mod_code & 0x3;
+                       mod_code = (mod_code & 0x7f) >> 2;
+
+                       reg_index = R0900_P2_MODCODLSTF - mod_code / 2;
+                       field_index = mod_code % 2;
+                       break;
+               }
+
+
+               switch (matype) {
+               case 0:
+               default:
+                       fmod = 14;
+                       break;
+               case 1:
+                       fmod = 13;
+                       break;
+               case 2:
+                       fmod = 11;
+                       break;
+               case 3:
+                       fmod = 7;
+                       break;
+               }
+
+               if ((INRANGE(STV0900_QPSK_12, mod_code, STV0900_8PSK_910))
+                                                       && (matype <= 1)) {
+                       if (field_index == 0)
+                               stv0900_write_reg(i_params, reg_index,
+                                                       0xf0 | fmod);
+                       else
+                               stv0900_write_reg(i_params, reg_index,
+                                                       (fmod << 4) | 0xf);
+               }
+       } else if (i_params->chip_id >= 0x12) {
+               switch (demod) {
+               case STV0900_DEMOD_1:
+               default:
+                       for (reg_index = 0; reg_index < 7; reg_index++)
+                               stv0900_write_reg(i_params, R0900_P1_MODCODLST0 + reg_index, 0xff);
+
+                       stv0900_write_reg(i_params, R0900_P1_MODCODLSTE, 0xff);
+                       stv0900_write_reg(i_params, R0900_P1_MODCODLSTF, 0xcf);
+                       for (reg_index = 0; reg_index < 8; reg_index++)
+                               stv0900_write_reg(i_params, R0900_P1_MODCODLST7 + reg_index, 0xcc);
+
+                       break;
+               case STV0900_DEMOD_2:
+                       for (reg_index = 0; reg_index < 7; reg_index++)
+                               stv0900_write_reg(i_params, R0900_P2_MODCODLST0 + reg_index, 0xff);
+
+                       stv0900_write_reg(i_params, R0900_P2_MODCODLSTE, 0xff);
+                       stv0900_write_reg(i_params, R0900_P2_MODCODLSTF, 0xcf);
+                       for (reg_index = 0; reg_index < 8; reg_index++)
+                               stv0900_write_reg(i_params, R0900_P2_MODCODLST7 + reg_index, 0xcc);
+
+                       break;
+               }
+
+       }
+}
+
+void stv0900_activate_s2_modcode_single(struct stv0900_internal *i_params,
+                                       enum fe_stv0900_demod_num demod)
+{
+       u32 reg_index;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               stv0900_write_reg(i_params, R0900_P1_MODCODLST0, 0xff);
+               stv0900_write_reg(i_params, R0900_P1_MODCODLST1, 0xf0);
+               stv0900_write_reg(i_params, R0900_P1_MODCODLSTF, 0x0f);
+               for (reg_index = 0; reg_index < 13; reg_index++)
+                       stv0900_write_reg(i_params,
+                                       R0900_P1_MODCODLST2 + reg_index, 0);
+
+               break;
+       case STV0900_DEMOD_2:
+               stv0900_write_reg(i_params, R0900_P2_MODCODLST0, 0xff);
+               stv0900_write_reg(i_params, R0900_P2_MODCODLST1, 0xf0);
+               stv0900_write_reg(i_params, R0900_P2_MODCODLSTF, 0x0f);
+               for (reg_index = 0; reg_index < 13; reg_index++)
+                       stv0900_write_reg(i_params,
+                                       R0900_P2_MODCODLST2 + reg_index, 0);
+
+               break;
+       }
+}
+
+static enum dvbfe_algo stv0900_frontend_algo(struct dvb_frontend *fe)
+{
+       return DVBFE_ALGO_CUSTOM;
+}
+
+static int stb0900_set_property(struct dvb_frontend *fe,
+                               struct dtv_property *tvp)
+{
+       dprintk(KERN_INFO "%s(..)\n", __func__);
+
+       return 0;
+}
+
+static int stb0900_get_property(struct dvb_frontend *fe,
+                               struct dtv_property *tvp)
+{
+       dprintk(KERN_INFO "%s(..)\n", __func__);
+
+       return 0;
+}
+
+void stv0900_start_search(struct stv0900_internal *i_params,
+                               enum fe_stv0900_demod_num demod)
+{
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               stv0900_write_bits(i_params, F0900_P1_I2C_DEMOD_MODE, 0x1f);
+
+               if (i_params->chip_id == 0x10)
+                       stv0900_write_reg(i_params, R0900_P1_CORRELEXP, 0xaa);
+
+               if (i_params->chip_id < 0x20)
+                       stv0900_write_reg(i_params, R0900_P1_CARHDR, 0x55);
+
+               if (i_params->dmd1_symbol_rate <= 5000000) {
+                       stv0900_write_reg(i_params, R0900_P1_CARCFG, 0x44);
+                       stv0900_write_reg(i_params, R0900_P1_CFRUP1, 0x0f);
+                       stv0900_write_reg(i_params, R0900_P1_CFRUP0, 0xff);
+                       stv0900_write_reg(i_params, R0900_P1_CFRLOW1, 0xf0);
+                       stv0900_write_reg(i_params, R0900_P1_CFRLOW0, 0x00);
+                       stv0900_write_reg(i_params, R0900_P1_RTCS2, 0x68);
+               } else {
+                       stv0900_write_reg(i_params, R0900_P1_CARCFG, 0xc4);
+                       stv0900_write_reg(i_params, R0900_P1_RTCS2, 0x44);
+               }
+
+               stv0900_write_reg(i_params, R0900_P1_CFRINIT1, 0);
+               stv0900_write_reg(i_params, R0900_P1_CFRINIT0, 0);
+
+               if (i_params->chip_id >= 0x20) {
+                       stv0900_write_reg(i_params, R0900_P1_EQUALCFG, 0x41);
+                       stv0900_write_reg(i_params, R0900_P1_FFECFG, 0x41);
+
+                       if ((i_params->dmd1_srch_standard == STV0900_SEARCH_DVBS1) || (i_params->dmd1_srch_standard == STV0900_SEARCH_DSS) || (i_params->dmd1_srch_standard == STV0900_AUTO_SEARCH)) {
+                               stv0900_write_reg(i_params, R0900_P1_VITSCALE, 0x82);
+                               stv0900_write_reg(i_params, R0900_P1_VAVSRVIT, 0x0);
+                       }
+               }
+
+               stv0900_write_reg(i_params, R0900_P1_SFRSTEP, 0x00);
+               stv0900_write_reg(i_params, R0900_P1_TMGTHRISE, 0xe0);
+               stv0900_write_reg(i_params, R0900_P1_TMGTHFALL, 0xc0);
+               stv0900_write_bits(i_params, F0900_P1_SCAN_ENABLE, 0);
+               stv0900_write_bits(i_params, F0900_P1_CFR_AUTOSCAN, 0);
+               stv0900_write_bits(i_params, F0900_P1_S1S2_SEQUENTIAL, 0);
+               stv0900_write_reg(i_params, R0900_P1_RTC, 0x88);
+               if (i_params->chip_id >= 0x20) {
+                       if (i_params->dmd1_symbol_rate < 2000000) {
+                               stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0x39);
+                               stv0900_write_reg(i_params, R0900_P1_CARHDR, 0x40);
+                       }
+
+                       if (i_params->dmd1_symbol_rate < 10000000) {
+                               stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0x4c);
+                               stv0900_write_reg(i_params, R0900_P1_CARHDR, 0x20);
+                       } else {
+                               stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0x4b);
+                               stv0900_write_reg(i_params, R0900_P1_CARHDR, 0x20);
+                       }
+
+               } else {
+                       if (i_params->dmd1_symbol_rate < 10000000)
+                               stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0xef);
+                       else
+                               stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0xed);
+               }
+
+               switch (i_params->dmd1_srch_algo) {
+               case STV0900_WARM_START:
+                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1f);
+                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x18);
+                       break;
+               case STV0900_COLD_START:
+                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1f);
+                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x15);
+                       break;
+               default:
+                       break;
+               }
+
+               break;
+       case STV0900_DEMOD_2:
+               stv0900_write_bits(i_params, F0900_P2_I2C_DEMOD_MODE, 0x1f);
+               if (i_params->chip_id == 0x10)
+                       stv0900_write_reg(i_params, R0900_P2_CORRELEXP, 0xaa);
+
+               if (i_params->chip_id < 0x20)
+                       stv0900_write_reg(i_params, R0900_P2_CARHDR, 0x55);
+
+               if (i_params->dmd2_symbol_rate <= 5000000) {
+                       stv0900_write_reg(i_params, R0900_P2_CARCFG, 0x44);
+                       stv0900_write_reg(i_params, R0900_P2_CFRUP1, 0x0f);
+                       stv0900_write_reg(i_params, R0900_P2_CFRUP0, 0xff);
+                       stv0900_write_reg(i_params, R0900_P2_CFRLOW1, 0xf0);
+                       stv0900_write_reg(i_params, R0900_P2_CFRLOW0, 0x00);
+                       stv0900_write_reg(i_params, R0900_P2_RTCS2, 0x68);
+               } else {
+                       stv0900_write_reg(i_params, R0900_P2_CARCFG, 0xc4);
+                       stv0900_write_reg(i_params, R0900_P2_RTCS2, 0x44);
+               }
+
+               stv0900_write_reg(i_params, R0900_P2_CFRINIT1, 0);
+               stv0900_write_reg(i_params, R0900_P2_CFRINIT0, 0);
+
+               if (i_params->chip_id >= 0x20) {
+                       stv0900_write_reg(i_params, R0900_P2_EQUALCFG, 0x41);
+                       stv0900_write_reg(i_params, R0900_P2_FFECFG, 0x41);
+                       if ((i_params->dmd2_srch_stndrd == STV0900_SEARCH_DVBS1) || (i_params->dmd2_srch_stndrd == STV0900_SEARCH_DSS) || (i_params->dmd2_srch_stndrd == STV0900_AUTO_SEARCH)) {
+                               stv0900_write_reg(i_params, R0900_P2_VITSCALE, 0x82);
+                               stv0900_write_reg(i_params, R0900_P2_VAVSRVIT, 0x0);
+                       }
+               }
+
+               stv0900_write_reg(i_params, R0900_P2_SFRSTEP, 0x00);
+               stv0900_write_reg(i_params, R0900_P2_TMGTHRISE, 0xe0);
+               stv0900_write_reg(i_params, R0900_P2_TMGTHFALL, 0xc0);
+               stv0900_write_bits(i_params, F0900_P2_SCAN_ENABLE, 0);
+               stv0900_write_bits(i_params, F0900_P2_CFR_AUTOSCAN, 0);
+               stv0900_write_bits(i_params, F0900_P2_S1S2_SEQUENTIAL, 0);
+               stv0900_write_reg(i_params, R0900_P2_RTC, 0x88);
+               if (i_params->chip_id >= 0x20) {
+                       if (i_params->dmd2_symbol_rate < 2000000) {
+                               stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0x39);
+                               stv0900_write_reg(i_params, R0900_P2_CARHDR, 0x40);
+                       }
+
+                       if (i_params->dmd2_symbol_rate < 10000000) {
+                               stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0x4c);
+                               stv0900_write_reg(i_params, R0900_P2_CARHDR, 0x20);
+                       } else {
+                               stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0x4b);
+                               stv0900_write_reg(i_params, R0900_P2_CARHDR, 0x20);
+                       }
+
+               } else {
+                       if (i_params->dmd2_symbol_rate < 10000000)
+                               stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0xef);
+                       else
+                               stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0xed);
+               }
+
+               switch (i_params->dmd2_srch_algo) {
+               case STV0900_WARM_START:
+                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1f);
+                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x18);
+                       break;
+               case STV0900_COLD_START:
+                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1f);
+                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x15);
+                       break;
+               default:
+                       break;
+               }
+
+               break;
+       }
+}
+
+u8 stv0900_get_optim_carr_loop(s32 srate, enum fe_stv0900_modcode modcode,
+                                                       s32 pilot, u8 chip_id)
+{
+       u8 aclc_value = 0x29;
+       s32     i;
+       const struct stv0900_car_loop_optim *car_loop_s2;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       if (chip_id <= 0x12)
+               car_loop_s2 = FE_STV0900_S2CarLoop;
+       else if (chip_id == 0x20)
+               car_loop_s2 = FE_STV0900_S2CarLoopCut20;
+       else
+               car_loop_s2 = FE_STV0900_S2CarLoop;
+
+       if (modcode < STV0900_QPSK_12) {
+               i = 0;
+               while ((i < 3) && (modcode != FE_STV0900_S2LowQPCarLoopCut20[i].modcode))
+                       i++;
+
+               if (i >= 3)
+                       i = 2;
+       } else {
+               i = 0;
+               while ((i < 14) && (modcode != car_loop_s2[i].modcode))
+                       i++;
+
+               if (i >= 14) {
+                       i = 0;
+                       while ((i < 11) && (modcode != FE_STV0900_S2APSKCarLoopCut20[i].modcode))
+                               i++;
+
+                       if (i >= 11)
+                               i = 10;
+               }
+       }
+
+       if (modcode <= STV0900_QPSK_25) {
+               if (pilot) {
+                       if (srate <= 3000000)
+                               aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_on_2;
+                       else if (srate <= 7000000)
+                               aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_on_5;
+                       else if (srate <= 15000000)
+                               aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_on_10;
+                       else if (srate <= 25000000)
+                               aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_on_20;
+                       else
+                               aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_on_30;
+               } else {
+                       if (srate <= 3000000)
+                               aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_off_2;
+                       else if (srate <= 7000000)
+                               aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_off_5;
+                       else if (srate <= 15000000)
+                               aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_off_10;
+                       else if (srate <= 25000000)
+                               aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_off_20;
+                       else
+                               aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_off_30;
+               }
+
+       } else if (modcode <= STV0900_8PSK_910) {
+               if (pilot) {
+                       if (srate <= 3000000)
+                               aclc_value = car_loop_s2[i].car_loop_pilots_on_2;
+                       else if (srate <= 7000000)
+                               aclc_value = car_loop_s2[i].car_loop_pilots_on_5;
+                       else if (srate <= 15000000)
+                               aclc_value = car_loop_s2[i].car_loop_pilots_on_10;
+                       else if (srate <= 25000000)
+                               aclc_value = car_loop_s2[i].car_loop_pilots_on_20;
+                       else
+                               aclc_value = car_loop_s2[i].car_loop_pilots_on_30;
+               } else {
+                       if (srate <= 3000000)
+                               aclc_value = car_loop_s2[i].car_loop_pilots_off_2;
+                       else if (srate <= 7000000)
+                               aclc_value = car_loop_s2[i].car_loop_pilots_off_5;
+                       else if (srate <= 15000000)
+                               aclc_value = car_loop_s2[i].car_loop_pilots_off_10;
+                       else if (srate <= 25000000)
+                               aclc_value = car_loop_s2[i].car_loop_pilots_off_20;
+                       else
+                               aclc_value = car_loop_s2[i].car_loop_pilots_off_30;
+               }
+
+       } else {
+               if (srate <= 3000000)
+                       aclc_value = FE_STV0900_S2APSKCarLoopCut20[i].car_loop_pilots_on_2;
+               else if (srate <= 7000000)
+                       aclc_value = FE_STV0900_S2APSKCarLoopCut20[i].car_loop_pilots_on_5;
+               else if (srate <= 15000000)
+                       aclc_value = FE_STV0900_S2APSKCarLoopCut20[i].car_loop_pilots_on_10;
+               else if (srate <= 25000000)
+                       aclc_value = FE_STV0900_S2APSKCarLoopCut20[i].car_loop_pilots_on_20;
+               else
+                       aclc_value = FE_STV0900_S2APSKCarLoopCut20[i].car_loop_pilots_on_30;
+       }
+
+       return aclc_value;
+}
+
+u8 stv0900_get_optim_short_carr_loop(s32 srate, enum fe_stv0900_modulation modulation, u8 chip_id)
+{
+       s32 mod_index = 0;
+
+       u8 aclc_value = 0x0b;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       switch (modulation) {
+       case STV0900_QPSK:
+       default:
+               mod_index = 0;
+               break;
+       case STV0900_8PSK:
+               mod_index = 1;
+               break;
+       case STV0900_16APSK:
+               mod_index = 2;
+               break;
+       case STV0900_32APSK:
+               mod_index = 3;
+               break;
+       }
+
+       switch (chip_id) {
+       case 0x20:
+               if (srate <= 3000000)
+                       aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut20_2;
+               else if (srate <= 7000000)
+                       aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut20_5;
+               else if (srate <= 15000000)
+                       aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut20_10;
+               else if (srate <= 25000000)
+                       aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut20_20;
+               else
+                       aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut20_30;
+
+               break;
+       case 0x12:
+       default:
+               if (srate <= 3000000)
+                       aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut12_2;
+               else if (srate <= 7000000)
+                       aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut12_5;
+               else if (srate <= 15000000)
+                       aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut12_10;
+               else if (srate <= 25000000)
+                       aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut12_20;
+               else
+                       aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut12_30;
+
+               break;
+       }
+
+       return aclc_value;
+}
+
+static enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *i_params,
+                                       enum fe_stv0900_demod_mode LDPC_Mode,
+                                       enum fe_stv0900_demod_num demod)
+{
+       enum fe_stv0900_error error = STV0900_NO_ERROR;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       switch (LDPC_Mode) {
+       case STV0900_DUAL:
+       default:
+               if ((i_params->demod_mode != STV0900_DUAL)
+                       || (stv0900_get_bits(i_params, F0900_DDEMOD) != 1)) {
+                       stv0900_write_reg(i_params, R0900_GENCFG, 0x1d);
+
+                       i_params->demod_mode = STV0900_DUAL;
+
+                       stv0900_write_bits(i_params, F0900_FRESFEC, 1);
+                       stv0900_write_bits(i_params, F0900_FRESFEC, 0);
+               }
+
+               break;
+       case STV0900_SINGLE:
+               if (demod == STV0900_DEMOD_2)
+                       stv0900_write_reg(i_params, R0900_GENCFG, 0x06);
+               else
+                       stv0900_write_reg(i_params, R0900_GENCFG, 0x04);
+
+               i_params->demod_mode = STV0900_SINGLE;
+
+               stv0900_write_bits(i_params, F0900_FRESFEC, 1);
+               stv0900_write_bits(i_params, F0900_FRESFEC, 0);
+               stv0900_write_bits(i_params, F0900_P1_ALGOSWRST, 1);
+               stv0900_write_bits(i_params, F0900_P1_ALGOSWRST, 0);
+               stv0900_write_bits(i_params, F0900_P2_ALGOSWRST, 1);
+               stv0900_write_bits(i_params, F0900_P2_ALGOSWRST, 0);
+               break;
+       }
+
+       return error;
+}
+
+static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
+                                       struct stv0900_init_params *p_init)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       enum fe_stv0900_error error = STV0900_NO_ERROR;
+       enum fe_stv0900_error demodError = STV0900_NO_ERROR;
+       int selosci;
+
+       struct stv0900_inode *temp_int = find_inode(state->i2c_adap,
+                                               state->config->demod_address);
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       if (temp_int != NULL) {
+               state->internal = temp_int->internal;
+               (state->internal->dmds_used)++;
+               dprintk(KERN_INFO "%s: Find Internal Structure!\n", __func__);
+               return STV0900_NO_ERROR;
+       } else {
+               state->internal = kmalloc(sizeof(struct stv0900_internal), GFP_KERNEL);
+               temp_int = append_internal(state->internal);
+               state->internal->dmds_used = 1;
+               state->internal->i2c_adap = state->i2c_adap;
+               state->internal->i2c_addr = state->config->demod_address;
+               state->internal->clkmode = state->config->clkmode;
+               state->internal->errs = STV0900_NO_ERROR;
+               dprintk(KERN_INFO "%s: Create New Internal Structure!\n", __func__);
+       }
+
+       if (state->internal != NULL) {
+               demodError = stv0900_initialize(state->internal);
+               if (demodError == STV0900_NO_ERROR) {
+                               error = STV0900_NO_ERROR;
+               } else {
+                       if (demodError == STV0900_INVALID_HANDLE)
+                               error = STV0900_INVALID_HANDLE;
+                       else
+                               error = STV0900_I2C_ERROR;
+               }
+
+               if (state->internal != NULL) {
+                       if (error == STV0900_NO_ERROR) {
+                               state->internal->demod_mode = p_init->demod_mode;
+
+                               stv0900_st_dvbs2_single(state->internal, state->internal->demod_mode, STV0900_DEMOD_1);
+
+                               state->internal->chip_id = stv0900_read_reg(state->internal, R0900_MID);
+                               state->internal->rolloff = p_init->rolloff;
+                               state->internal->quartz = p_init->dmd_ref_clk;
+
+                               stv0900_write_bits(state->internal, F0900_P1_ROLLOFF_CONTROL, p_init->rolloff);
+                               stv0900_write_bits(state->internal, F0900_P2_ROLLOFF_CONTROL, p_init->rolloff);
+
+                               stv0900_set_ts_parallel_serial(state->internal, p_init->path1_ts_clock, p_init->path2_ts_clock);
+                               stv0900_write_bits(state->internal, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress);
+                               switch (p_init->tuner1_adc) {
+                               case 1:
+                                       stv0900_write_reg(state->internal, R0900_TSTTNR1, 0x26);
+                                       break;
+                               default:
+                                       break;
+                               }
+
+                               stv0900_write_bits(state->internal, F0900_P2_TUN_MADDRESS, p_init->tun2_maddress);
+                               switch (p_init->tuner2_adc) {
+                               case 1:
+                                       stv0900_write_reg(state->internal, R0900_TSTTNR3, 0x26);
+                                       break;
+                               default:
+                                       break;
+                               }
+
+                               stv0900_write_bits(state->internal, F0900_P1_TUN_IQSWAP, p_init->tun1_iq_inversion);
+                               stv0900_write_bits(state->internal, F0900_P2_TUN_IQSWAP, p_init->tun2_iq_inversion);
+                               stv0900_set_mclk(state->internal, 135000000);
+                               msleep(3);
+
+                               switch (state->internal->clkmode) {
+                               case 0:
+                               case 2:
+                                       stv0900_write_reg(state->internal, R0900_SYNTCTRL, 0x20 | state->internal->clkmode);
+                                       break;
+                               default:
+                                       selosci = 0x02 & stv0900_read_reg(state->internal, R0900_SYNTCTRL);
+                                       stv0900_write_reg(state->internal, R0900_SYNTCTRL, 0x20 | selosci);
+                                       break;
+                               }
+                               msleep(3);
+
+                               state->internal->mclk = stv0900_get_mclk_freq(state->internal, state->internal->quartz);
+                               if (state->internal->errs)
+                                       error = STV0900_I2C_ERROR;
+                       }
+               } else {
+                       error = STV0900_INVALID_HANDLE;
+               }
+       }
+
+       return error;
+}
+
+static int stv0900_status(struct stv0900_internal *i_params,
+                                       enum fe_stv0900_demod_num demod)
+{
+       enum fe_stv0900_search_state demod_state;
+       s32 mode_field, delin_field, lock_field, fifo_field, lockedvit_field;
+       int locked = FALSE;
+
+       dmd_reg(mode_field, F0900_P1_HEADER_MODE, F0900_P2_HEADER_MODE);
+       dmd_reg(lock_field, F0900_P1_LOCK_DEFINITIF, F0900_P2_LOCK_DEFINITIF);
+       dmd_reg(delin_field, F0900_P1_PKTDELIN_LOCK, F0900_P2_PKTDELIN_LOCK);
+       dmd_reg(fifo_field, F0900_P1_TSFIFO_LINEOK, F0900_P2_TSFIFO_LINEOK);
+       dmd_reg(lockedvit_field, F0900_P1_LOCKEDVIT, F0900_P2_LOCKEDVIT);
+
+       demod_state = stv0900_get_bits(i_params, mode_field);
+       switch (demod_state) {
+       case STV0900_SEARCH:
+       case STV0900_PLH_DETECTED:
+       default:
+               locked = FALSE;
+               break;
+       case STV0900_DVBS2_FOUND:
+               locked = stv0900_get_bits(i_params, lock_field) &&
+                               stv0900_get_bits(i_params, delin_field) &&
+                               stv0900_get_bits(i_params, fifo_field);
+               break;
+       case STV0900_DVBS_FOUND:
+               locked = stv0900_get_bits(i_params, lock_field) &&
+                               stv0900_get_bits(i_params, lockedvit_field) &&
+                               stv0900_get_bits(i_params, fifo_field);
+               break;
+       }
+
+       return locked;
+}
+
+static enum dvbfe_search stv0900_search(struct dvb_frontend *fe,
+                                       struct dvb_frontend_parameters *params)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+       struct stv0900_search_params p_search;
+       struct stv0900_signal_info p_result;
+
+       enum fe_stv0900_error error = STV0900_NO_ERROR;
+
+       dprintk(KERN_INFO "%s: ", __func__);
+
+       p_result.locked = FALSE;
+       p_search.path = state->demod;
+       p_search.frequency = c->frequency;
+       p_search.symbol_rate = c->symbol_rate;
+       p_search.search_range = 10000000;
+       p_search.fec = STV0900_FEC_UNKNOWN;
+       p_search.standard = STV0900_AUTO_SEARCH;
+       p_search.iq_inversion = STV0900_IQ_AUTO;
+       p_search.search_algo = STV0900_BLIND_SEARCH;
+
+       if ((INRANGE(100000, p_search.symbol_rate, 70000000)) &&
+                       (INRANGE(100000, p_search.search_range, 50000000))) {
+               switch (p_search.path) {
+               case STV0900_DEMOD_1:
+               default:
+                       i_params->dmd1_srch_standard = p_search.standard;
+                       i_params->dmd1_symbol_rate = p_search.symbol_rate;
+                       i_params->dmd1_srch_range = p_search.search_range;
+                       i_params->tuner1_freq = p_search.frequency;
+                       i_params->dmd1_srch_algo = p_search.search_algo;
+                       i_params->dmd1_srch_iq_inv = p_search.iq_inversion;
+                       i_params->dmd1_fec = p_search.fec;
+                       break;
+
+               case STV0900_DEMOD_2:
+                       i_params->dmd2_srch_stndrd = p_search.standard;
+                       i_params->dmd2_symbol_rate = p_search.symbol_rate;
+                       i_params->dmd2_srch_range = p_search.search_range;
+                       i_params->tuner2_freq = p_search.frequency;
+                       i_params->dmd2_srch_algo = p_search.search_algo;
+                       i_params->dmd2_srch_iq_inv = p_search.iq_inversion;
+                       i_params->dmd2_fec = p_search.fec;
+                       break;
+               }
+
+               if ((stv0900_algo(fe) == STV0900_RANGEOK) &&
+                                       (i_params->errs == STV0900_NO_ERROR)) {
+                       switch (p_search.path) {
+                       case STV0900_DEMOD_1:
+                       default:
+                               p_result.locked = i_params->dmd1_rslts.locked;
+                               p_result.standard = i_params->dmd1_rslts.standard;
+                               p_result.frequency = i_params->dmd1_rslts.frequency;
+                               p_result.symbol_rate = i_params->dmd1_rslts.symbol_rate;
+                               p_result.fec = i_params->dmd1_rslts.fec;
+                               p_result.modcode = i_params->dmd1_rslts.modcode;
+                               p_result.pilot = i_params->dmd1_rslts.pilot;
+                               p_result.frame_length = i_params->dmd1_rslts.frame_length;
+                               p_result.spectrum = i_params->dmd1_rslts.spectrum;
+                               p_result.rolloff = i_params->dmd1_rslts.rolloff;
+                               p_result.modulation = i_params->dmd1_rslts.modulation;
+                               break;
+                       case STV0900_DEMOD_2:
+                               p_result.locked = i_params->dmd2_rslts.locked;
+                               p_result.standard = i_params->dmd2_rslts.standard;
+                               p_result.frequency = i_params->dmd2_rslts.frequency;
+                               p_result.symbol_rate = i_params->dmd2_rslts.symbol_rate;
+                               p_result.fec = i_params->dmd2_rslts.fec;
+                               p_result.modcode = i_params->dmd2_rslts.modcode;
+                               p_result.pilot = i_params->dmd2_rslts.pilot;
+                               p_result.frame_length = i_params->dmd2_rslts.frame_length;
+                               p_result.spectrum = i_params->dmd2_rslts.spectrum;
+                               p_result.rolloff = i_params->dmd2_rslts.rolloff;
+                               p_result.modulation = i_params->dmd2_rslts.modulation;
+                               break;
+                       }
+
+               } else {
+                       p_result.locked = FALSE;
+                       switch (p_search.path) {
+                       case STV0900_DEMOD_1:
+                               switch (i_params->dmd1_err) {
+                               case STV0900_I2C_ERROR:
+                                       error = STV0900_I2C_ERROR;
+                                       break;
+                               case STV0900_NO_ERROR:
+                               default:
+                                       error = STV0900_SEARCH_FAILED;
+                                       break;
+                               }
+                               break;
+                       case STV0900_DEMOD_2:
+                               switch (i_params->dmd2_err) {
+                               case STV0900_I2C_ERROR:
+                                       error = STV0900_I2C_ERROR;
+                                       break;
+                               case STV0900_NO_ERROR:
+                               default:
+                                       error = STV0900_SEARCH_FAILED;
+                                       break;
+                               }
+                               break;
+                       }
+               }
+
+       } else
+               error = STV0900_BAD_PARAMETER;
+
+       if ((p_result.locked == TRUE) && (error == STV0900_NO_ERROR)) {
+               dprintk(KERN_INFO "Search Success\n");
+               return DVBFE_ALGO_SEARCH_SUCCESS;
+       } else {
+               dprintk(KERN_INFO "Search Fail\n");
+               return DVBFE_ALGO_SEARCH_FAILED;
+       }
+
+       return DVBFE_ALGO_SEARCH_ERROR;
+}
+
+static int stv0900_read_status(struct dvb_frontend *fe, enum fe_status *status)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+
+       dprintk("%s: ", __func__);
+
+       if ((stv0900_status(state->internal, state->demod)) == TRUE) {
+               dprintk("DEMOD LOCK OK\n");
+               *status = FE_HAS_CARRIER
+                       | FE_HAS_VITERBI
+                       | FE_HAS_SYNC
+                       | FE_HAS_LOCK;
+       } else
+               dprintk("DEMOD LOCK FAIL\n");
+
+       return 0;
+}
+
+static int stv0900_track(struct dvb_frontend *fe,
+                       struct dvb_frontend_parameters *p)
+{
+       return 0;
+}
+
+static int stv0900_stop_ts(struct dvb_frontend *fe, int stop_ts)
+{
+
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       enum fe_stv0900_demod_num demod = state->demod;
+       s32 rst_field;
+
+       dmd_reg(rst_field, F0900_P1_RST_HWARE, F0900_P2_RST_HWARE);
+
+       if (stop_ts == TRUE)
+               stv0900_write_bits(i_params, rst_field, 1);
+       else
+               stv0900_write_bits(i_params, rst_field, 0);
+
+       return 0;
+}
+
+static int stv0900_diseqc_init(struct dvb_frontend *fe)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       enum fe_stv0900_demod_num demod = state->demod;
+       s32 mode_field, reset_field;
+
+       dmd_reg(mode_field, F0900_P1_DISTX_MODE, F0900_P2_DISTX_MODE);
+       dmd_reg(reset_field, F0900_P1_DISEQC_RESET, F0900_P2_DISEQC_RESET);
+
+       stv0900_write_bits(i_params, mode_field, state->config->diseqc_mode);
+       stv0900_write_bits(i_params, reset_field, 1);
+       stv0900_write_bits(i_params, reset_field, 0);
+
+       return 0;
+}
+
+static int stv0900_init(struct dvb_frontend *fe)
+{
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       stv0900_stop_ts(fe, 1);
+       stv0900_diseqc_init(fe);
+
+       return 0;
+}
+
+static int stv0900_diseqc_send(struct stv0900_internal *i_params , u8 *Data,
+                               u32 NbData, enum fe_stv0900_demod_num demod)
+{
+       s32 i = 0;
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               stv0900_write_bits(i_params, F0900_P1_DIS_PRECHARGE, 1);
+               while (i < NbData) {
+                       while (stv0900_get_bits(i_params, F0900_P1_FIFO_FULL))
+                               ;/* checkpatch complains */
+                       stv0900_write_reg(i_params, R0900_P1_DISTXDATA, Data[i]);
+                       i++;
+               }
+
+               stv0900_write_bits(i_params, F0900_P1_DIS_PRECHARGE, 0);
+               i = 0;
+               while ((stv0900_get_bits(i_params, F0900_P1_TX_IDLE) != 1) && (i < 10)) {
+                       msleep(10);
+                       i++;
+               }
+
+               break;
+       case STV0900_DEMOD_2:
+               stv0900_write_bits(i_params, F0900_P2_DIS_PRECHARGE, 1);
+
+               while (i < NbData) {
+                       while (stv0900_get_bits(i_params, F0900_P2_FIFO_FULL))
+                               ;/* checkpatch complains */
+                       stv0900_write_reg(i_params, R0900_P2_DISTXDATA, Data[i]);
+                       i++;
+               }
+
+               stv0900_write_bits(i_params, F0900_P2_DIS_PRECHARGE, 0);
+               i = 0;
+               while ((stv0900_get_bits(i_params, F0900_P2_TX_IDLE) != 1) && (i < 10)) {
+                       msleep(10);
+                       i++;
+               }
+
+               break;
+       }
+
+       return 0;
+}
+
+static int stv0900_send_master_cmd(struct dvb_frontend *fe,
+                                       struct dvb_diseqc_master_cmd *cmd)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+
+       return stv0900_diseqc_send(state->internal,
+                               cmd->msg,
+                               cmd->msg_len,
+                               state->demod);
+}
+
+static int stv0900_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       enum fe_stv0900_demod_num demod = state->demod;
+       s32 mode_field;
+       u32 diseqc_fifo;
+
+       dmd_reg(mode_field, F0900_P1_DISTX_MODE, F0900_P2_DISTX_MODE);
+       dmd_reg(diseqc_fifo, R0900_P1_DISTXDATA, R0900_P2_DISTXDATA);
+
+       switch (burst) {
+       case SEC_MINI_A:
+               stv0900_write_bits(i_params, mode_field, 3);/* Unmodulated */
+               stv0900_write_reg(i_params, diseqc_fifo, 0x00);
+               break;
+       case SEC_MINI_B:
+               stv0900_write_bits(i_params, mode_field, 2);/* Modulated */
+               stv0900_write_reg(i_params, diseqc_fifo, 0xff);
+               break;
+       }
+
+       return 0;
+}
+
+static int stv0900_recv_slave_reply(struct dvb_frontend *fe,
+                               struct dvb_diseqc_slave_reply *reply)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       s32 i = 0;
+
+       switch (state->demod) {
+       case STV0900_DEMOD_1:
+       default:
+               reply->msg_len = 0;
+
+               while ((stv0900_get_bits(i_params, F0900_P1_RX_END) != 1) && (i < 10)) {
+                       msleep(10);
+                       i++;
+               }
+
+               if (stv0900_get_bits(i_params, F0900_P1_RX_END)) {
+                       reply->msg_len = stv0900_get_bits(i_params, F0900_P1_FIFO_BYTENBR);
+
+                       for (i = 0; i < reply->msg_len; i++)
+                               reply->msg[i] = stv0900_read_reg(i_params, R0900_P1_DISRXDATA);
+               }
+               break;
+       case STV0900_DEMOD_2:
+               reply->msg_len = 0;
+
+               while ((stv0900_get_bits(i_params, F0900_P2_RX_END) != 1) && (i < 10)) {
+                       msleep(10);
+                       i++;
+               }
+
+               if (stv0900_get_bits(i_params, F0900_P2_RX_END)) {
+                       reply->msg_len = stv0900_get_bits(i_params, F0900_P2_FIFO_BYTENBR);
+
+                       for (i = 0; i < reply->msg_len; i++)
+                               reply->msg[i] = stv0900_read_reg(i_params, R0900_P2_DISRXDATA);
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static int stv0900_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       enum fe_stv0900_demod_num demod = state->demod;
+       s32 mode_field, reset_field;
+
+       dprintk(KERN_INFO "%s: %s\n", __func__, ((tone == 0) ? "Off" : "On"));
+
+       dmd_reg(mode_field, F0900_P1_DISTX_MODE, F0900_P2_DISTX_MODE);
+       dmd_reg(reset_field, F0900_P1_DISEQC_RESET, F0900_P2_DISEQC_RESET);
+
+       if (tone) {
+               /*Set the DiseqC mode to 22Khz continues tone*/
+               stv0900_write_bits(i_params, mode_field, 0);
+               stv0900_write_bits(i_params, reset_field, 1);
+               /*release DiseqC reset to enable the 22KHz tone*/
+               stv0900_write_bits(i_params, reset_field, 0);
+       } else {
+               stv0900_write_bits(i_params, mode_field, 0);
+               /*maintain the DiseqC reset to disable the 22KHz tone*/
+               stv0900_write_bits(i_params, reset_field, 1);
+       }
+
+       return 0;
+}
+
+static void stv0900_release(struct dvb_frontend *fe)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       if ((--(state->internal->dmds_used)) <= 0) {
+
+               dprintk(KERN_INFO "%s: Actually removing\n", __func__);
+
+               remove_inode(state->internal);
+               kfree(state->internal);
+       }
+
+       kfree(state);
+}
+
+static struct dvb_frontend_ops stv0900_ops = {
+
+       .info = {
+               .name                   = "STV0900 frontend",
+               .type                   = FE_QPSK,
+               .frequency_min          = 950000,
+               .frequency_max          = 2150000,
+               .frequency_stepsize     = 125,
+               .frequency_tolerance    = 0,
+               .symbol_rate_min        = 1000000,
+               .symbol_rate_max        = 45000000,
+               .symbol_rate_tolerance  = 500,
+               .caps                   = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+                                         FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
+                                         FE_CAN_FEC_7_8 | FE_CAN_QPSK    |
+                                         FE_CAN_2G_MODULATION |
+                                         FE_CAN_FEC_AUTO
+       },
+       .release                        = stv0900_release,
+       .init                           = stv0900_init,
+       .get_frontend_algo              = stv0900_frontend_algo,
+       .i2c_gate_ctrl                  = stv0900_i2c_gate_ctrl,
+       .diseqc_send_master_cmd         = stv0900_send_master_cmd,
+       .diseqc_send_burst              = stv0900_send_burst,
+       .diseqc_recv_slave_reply        = stv0900_recv_slave_reply,
+       .set_tone                       = stv0900_set_tone,
+       .set_property                   = stb0900_set_property,
+       .get_property                   = stb0900_get_property,
+       .search                         = stv0900_search,
+       .track                          = stv0900_track,
+       .read_status                    = stv0900_read_status,
+       .read_ber                       = stv0900_read_ber,
+       .read_signal_strength           = stv0900_read_signal_strength,
+       .read_snr                       = stv0900_read_snr,
+};
+
+struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
+                                       struct i2c_adapter *i2c,
+                                       int demod)
+{
+       struct stv0900_state *state = NULL;
+       struct stv0900_init_params init_params;
+       enum fe_stv0900_error err_stv0900;
+
+       state = kzalloc(sizeof(struct stv0900_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       state->demod            = demod;
+       state->config           = config;
+       state->i2c_adap         = i2c;
+
+       memcpy(&state->frontend.ops, &stv0900_ops,
+                       sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+
+       switch (demod) {
+       case 0:
+       case 1:
+               init_params.dmd_ref_clk         = config->xtal;
+               init_params.demod_mode          = STV0900_DUAL;
+               init_params.rolloff             = STV0900_35;
+               init_params.path1_ts_clock      = config->path1_mode;
+               init_params.tun1_maddress       = config->tun1_maddress;
+               init_params.tun1_iq_inversion   = STV0900_IQ_NORMAL;
+               init_params.tuner1_adc          = config->tun1_adc;
+               init_params.path2_ts_clock      = config->path2_mode;
+               init_params.tun2_maddress       = config->tun2_maddress;
+               init_params.tuner2_adc          = config->tun2_adc;
+               init_params.tun2_iq_inversion   = STV0900_IQ_SWAPPED;
+
+               err_stv0900 = stv0900_init_internal(&state->frontend,
+                                                       &init_params);
+
+               if (err_stv0900)
+                       goto error;
+
+               break;
+       default:
+               goto error;
+               break;
+       }
+
+       dprintk("%s: Attaching STV0900 demodulator(%d) \n", __func__, demod);
+       return &state->frontend;
+
+error:
+       dprintk("%s: Failed to attach STV0900 demodulator(%d) \n",
+               __func__, demod);
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(stv0900_attach);
+
+MODULE_PARM_DESC(debug, "Set debug");
+
+MODULE_AUTHOR("Igor M. Liplianin");
+MODULE_DESCRIPTION("ST STV0900 frontend");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stv0900_init.h b/drivers/media/dvb/frontends/stv0900_init.h
new file mode 100644 (file)
index 0000000..ff388b4
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * stv0900_init.h
+ *
+ * Driver for ST STV0900 satellite demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * 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 STV0900_INIT_H
+#define STV0900_INIT_H
+
+#include "stv0900_priv.h"
+
+/* DVBS2 C/N Look-Up table */
+static const struct stv0900_table stv0900_s2_cn = {
+       55,
+       {
+               { -30,  13348 }, /*C/N=-3dB*/
+               { -20,  12640 }, /*C/N=-2dB*/
+               { -10,  11883 }, /*C/N=-1dB*/
+               { 0,    11101 }, /*C/N=-0dB*/
+               { 5,    10718 }, /*C/N=0.5dB*/
+               { 10,   10339 }, /*C/N=1.0dB*/
+               { 15,   9947 }, /*C/N=1.5dB*/
+               { 20,   9552 }, /*C/N=2.0dB*/
+               { 25,   9183 }, /*C/N=2.5dB*/
+               { 30,   8799 }, /*C/N=3.0dB*/
+               { 35,   8422 }, /*C/N=3.5dB*/
+               { 40,   8062 }, /*C/N=4.0dB*/
+               { 45,   7707 }, /*C/N=4.5dB*/
+               { 50,   7353 }, /*C/N=5.0dB*/
+               { 55,   7025 }, /*C/N=5.5dB*/
+               { 60,   6684 }, /*C/N=6.0dB*/
+               { 65,   6331 }, /*C/N=6.5dB*/
+               { 70,   6036 }, /*C/N=7.0dB*/
+               { 75,   5727 }, /*C/N=7.5dB*/
+               { 80,   5437 }, /*C/N=8.0dB*/
+               { 85,   5164 }, /*C/N=8.5dB*/
+               { 90,   4902 }, /*C/N=9.0dB*/
+               { 95,   4653 }, /*C/N=9.5dB*/
+               { 100,  4408 }, /*C/N=10.0dB*/
+               { 105,  4187 }, /*C/N=10.5dB*/
+               { 110,  3961 }, /*C/N=11.0dB*/
+               { 115,  3751 }, /*C/N=11.5dB*/
+               { 120,  3558 }, /*C/N=12.0dB*/
+               { 125,  3368 }, /*C/N=12.5dB*/
+               { 130,  3191 }, /*C/N=13.0dB*/
+               { 135,  3017 }, /*C/N=13.5dB*/
+               { 140,  2862 }, /*C/N=14.0dB*/
+               { 145,  2710 }, /*C/N=14.5dB*/
+               { 150,  2565 }, /*C/N=15.0dB*/
+               { 160,  2300 }, /*C/N=16.0dB*/
+               { 170,  2058 }, /*C/N=17.0dB*/
+               { 180,  1849 }, /*C/N=18.0dB*/
+               { 190,  1663 }, /*C/N=19.0dB*/
+               { 200,  1495 }, /*C/N=20.0dB*/
+               { 210,  1349 }, /*C/N=21.0dB*/
+               { 220,  1222 }, /*C/N=22.0dB*/
+               { 230,  1110 }, /*C/N=23.0dB*/
+               { 240,  1011 }, /*C/N=24.0dB*/
+               { 250,  925 }, /*C/N=25.0dB*/
+               { 260,  853 }, /*C/N=26.0dB*/
+               { 270,  789 }, /*C/N=27.0dB*/
+               { 280,  734 }, /*C/N=28.0dB*/
+               { 290,  690 }, /*C/N=29.0dB*/
+               { 300,  650 }, /*C/N=30.0dB*/
+               { 310,  619 }, /*C/N=31.0dB*/
+               { 320,  593 }, /*C/N=32.0dB*/
+               { 330,  571 }, /*C/N=33.0dB*/
+               { 400,  498 }, /*C/N=40.0dB*/
+               { 450,  484 }, /*C/N=45.0dB*/
+               { 500,  481 }  /*C/N=50.0dB*/
+       }
+};
+
+/* RF level C/N Look-Up table */
+static const struct stv0900_table stv0900_rf = {
+       14,
+       {
+               { -5, 0xCAA1 }, /*-5dBm*/
+               { -10, 0xC229 }, /*-10dBm*/
+               { -15, 0xBB08 }, /*-15dBm*/
+               { -20, 0xB4BC }, /*-20dBm*/
+               { -25, 0xAD5A }, /*-25dBm*/
+               { -30, 0xA298 }, /*-30dBm*/
+               { -35, 0x98A8 }, /*-35dBm*/
+               { -40, 0x8389 }, /*-40dBm*/
+               { -45, 0x59BE }, /*-45dBm*/
+               { -50, 0x3A14 }, /*-50dBm*/
+               { -55, 0x2D11 }, /*-55dBm*/
+               { -60, 0x210D }, /*-60dBm*/
+               { -65, 0xA14F }, /*-65dBm*/
+               { -70, 0x7AA }  /*-70dBm*/
+       }
+};
+
+struct stv0900_car_loop_optim {
+       enum fe_stv0900_modcode modcode;
+       u8 car_loop_pilots_on_2;
+       u8 car_loop_pilots_off_2;
+       u8 car_loop_pilots_on_5;
+       u8 car_loop_pilots_off_5;
+       u8 car_loop_pilots_on_10;
+       u8 car_loop_pilots_off_10;
+       u8 car_loop_pilots_on_20;
+       u8 car_loop_pilots_off_20;
+       u8 car_loop_pilots_on_30;
+       u8 car_loop_pilots_off_30;
+
+};
+
+struct stv0900_short_frames_car_loop_optim {
+       enum fe_stv0900_modulation modulation;
+       u8 car_loop_cut12_2;    /* Cut 1.2,   SR<=3msps     */
+       u8 car_loop_cut20_2;    /* Cut 2.0,   SR<3msps      */
+       u8 car_loop_cut12_5;    /* Cut 1.2,   3<SR<=7msps   */
+       u8 car_loop_cut20_5;    /* Cut 2.0,   3<SR<=7msps   */
+       u8 car_loop_cut12_10;   /* Cut 1.2,   7<SR<=15msps  */
+       u8 car_loop_cut20_10;   /* Cut 2.0,   7<SR<=15msps  */
+       u8 car_loop_cut12_20;   /* Cut 1.2,   10<SR<=25msps */
+       u8 car_loop_cut20_20;   /* Cut 2.0,   10<SR<=25msps */
+       u8 car_loop_cut12_30;   /* Cut 1.2,   25<SR<=45msps */
+       u8 car_loop_cut20_30;   /* Cut 2.0,   10<SR<=45msps */
+
+};
+
+/* Cut 1.x Tracking carrier loop carrier QPSK 1/2 to 8PSK 9/10 long Frame */
+static const struct stv0900_car_loop_optim     FE_STV0900_S2CarLoop[14] = {
+       /*Modcod                2MPon   2MPoff  5MPon   5MPoff  10MPon  10MPoff 20MPon  20MPoff 30MPon  30MPoff */
+       { STV0900_QPSK_12,      0x1C,   0x0D,   0x1B,   0x2C,   0x3A,   0x1C,   0x2A,   0x3B,   0x2A,   0x1B },
+       { STV0900_QPSK_35,      0x2C,   0x0D,   0x2B,   0x2C,   0x3A,   0x0C,   0x3A,   0x2B,   0x2A,   0x0B },
+       { STV0900_QPSK_23,      0x2C,   0x0D,   0x2B,   0x2C,   0x0B,   0x0C,   0x3A,   0x1B,   0x2A,   0x3A },
+       { STV0900_QPSK_34,      0x3C,   0x0D,   0x3B,   0x1C,   0x0B,   0x3B,   0x3A,   0x0B,   0x2A,   0x3A },
+       { STV0900_QPSK_45,      0x3C,   0x0D,   0x3B,   0x1C,   0x0B,   0x3B,   0x3A,   0x0B,   0x2A,   0x3A },
+       { STV0900_QPSK_56,      0x0D,   0x0D,   0x3B,   0x1C,   0x0B,   0x3B,   0x3A,   0x0B,   0x2A,   0x3A },
+       { STV0900_QPSK_89,      0x0D,   0x0D,   0x3B,   0x1C,   0x1B,   0x3B,   0x3A,   0x0B,   0x2A,   0x3A },
+       { STV0900_QPSK_910,     0x1D,   0x0D,   0x3B,   0x1C,   0x1B,   0x3B,   0x3A,   0x0B,   0x2A,   0x3A },
+       { STV0900_8PSK_35,      0x29,   0x3B,   0x09,   0x2B,   0x38,   0x0B,   0x18,   0x1A,   0x08,   0x0A },
+       { STV0900_8PSK_23,      0x0A,   0x3B,   0x29,   0x2B,   0x19,   0x0B,   0x38,   0x1A,   0x18,   0x0A },
+       { STV0900_8PSK_34,      0x3A,   0x3B,   0x2A,   0x2B,   0x39,   0x0B,   0x19,   0x1A,   0x38,   0x0A },
+       { STV0900_8PSK_56,      0x1B,   0x3B,   0x0B,   0x2B,   0x1A,   0x0B,   0x39,   0x1A,   0x19,   0x0A },
+       { STV0900_8PSK_89,      0x3B,   0x3B,   0x0B,   0x2B,   0x2A,   0x0B,   0x39,   0x1A,   0x29,   0x39 },
+       { STV0900_8PSK_910,     0x3B,   0x3B,   0x0B,   0x2B,   0x2A,   0x0B,   0x39,   0x1A,   0x29,   0x39 }
+};
+
+
+/* Cut 2.0 Tracking carrier loop carrier QPSK 1/2 to 8PSK 9/10 long Frame */
+static const struct stv0900_car_loop_optim     FE_STV0900_S2CarLoopCut20[14]   = {
+       /* Modcod               2MPon   2MPoff  5MPon   5MPoff  10MPon  10MPoff 20MPon  20MPoff 30MPon  30MPoff */
+       { STV0900_QPSK_12,      0x1F,   0x3F,   0x1E,   0x3F,   0x3D,   0x1F,   0x3D,   0x3E,   0x3D,   0x1E },
+       { STV0900_QPSK_35,      0x2F,   0x3F,   0x2E,   0x2F,   0x3D,   0x0F,   0x0E,   0x2E,   0x3D,   0x0E },
+       { STV0900_QPSK_23,      0x2F,   0x3F,   0x2E,   0x2F,   0x0E,   0x0F,   0x0E,   0x1E,   0x3D,   0x3D },
+       { STV0900_QPSK_34,      0x3F,   0x3F,   0x3E,   0x1F,   0x0E,   0x3E,   0x0E,   0x1E,   0x3D,   0x3D },
+       { STV0900_QPSK_45,      0x3F,   0x3F,   0x3E,   0x1F,   0x0E,   0x3E,   0x0E,   0x1E,   0x3D,   0x3D },
+       { STV0900_QPSK_56,      0x3F,   0x3F,   0x3E,   0x1F,   0x0E,   0x3E,   0x0E,   0x1E,   0x3D,   0x3D },
+       { STV0900_QPSK_89,      0x3F,   0x3F,   0x3E,   0x1F,   0x1E,   0x3E,   0x0E,   0x1E,   0x3D,   0x3D },
+       { STV0900_QPSK_910,     0x3F,   0x3F,   0x3E,   0x1F,   0x1E,   0x3E,   0x0E,   0x1E,   0x3D,   0x3D },
+       { STV0900_8PSK_35,      0x3c,   0x0c,   0x1c,   0x3b,   0x0c,   0x3b,   0x2b,   0x2b,   0x1b,   0x2b },
+       { STV0900_8PSK_23,      0x1d,   0x0c,   0x3c,   0x0c,   0x2c,   0x3b,   0x0c,   0x2b,   0x2b,   0x2b },
+       { STV0900_8PSK_34,      0x0e,   0x1c,   0x3d,   0x0c,   0x0d,   0x3b,   0x2c,   0x3b,   0x0c,   0x2b },
+       { STV0900_8PSK_56,      0x2e,   0x3e,   0x1e,   0x2e,   0x2d,   0x1e,   0x3c,   0x2d,   0x2c,   0x1d },
+       { STV0900_8PSK_89,      0x3e,   0x3e,   0x1e,   0x2e,   0x3d,   0x1e,   0x0d,   0x2d,   0x3c,   0x1d },
+       { STV0900_8PSK_910,     0x3e,   0x3e,   0x1e,   0x2e,   0x3d,   0x1e,   0x1d,   0x2d,   0x0d,   0x1d }
+};
+
+
+
+/* Cut 2.0 Tracking carrier loop carrier 16APSK 2/3 to 32APSK 9/10 long Frame */
+static const struct stv0900_car_loop_optim FE_STV0900_S2APSKCarLoopCut20[11] = {
+       /* Modcod               2MPon   2MPoff  5MPon   5MPoff  10MPon  10MPoff 20MPon  20MPoff 30MPon  30MPoff */
+       { STV0900_16APSK_23,    0x0C,   0x0C,   0x0C,   0x0C,   0x1D,   0x0C,   0x3C,   0x0C,   0x2C,   0x0C },
+       { STV0900_16APSK_34,    0x0C,   0x0C,   0x0C,   0x0C,   0x0E,   0x0C,   0x2D,   0x0C,   0x1D,   0x0C },
+       { STV0900_16APSK_45,    0x0C,   0x0C,   0x0C,   0x0C,   0x1E,   0x0C,   0x3D,   0x0C,   0x2D,   0x0C },
+       { STV0900_16APSK_56,    0x0C,   0x0C,   0x0C,   0x0C,   0x1E,   0x0C,   0x3D,   0x0C,   0x2D,   0x0C },
+       { STV0900_16APSK_89,    0x0C,   0x0C,   0x0C,   0x0C,   0x2E,   0x0C,   0x0E,   0x0C,   0x3D,   0x0C },
+       { STV0900_16APSK_910,   0x0C,   0x0C,   0x0C,   0x0C,   0x2E,   0x0C,   0x0E,   0x0C,   0x3D,   0x0C },
+       { STV0900_32APSK_34,    0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C },
+       { STV0900_32APSK_45,    0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C },
+       { STV0900_32APSK_56,    0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C },
+       { STV0900_32APSK_89,    0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C },
+       { STV0900_32APSK_910,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C }
+};
+
+
+/* Cut 2.0 Tracking carrier loop carrier QPSK 1/4 to QPSK 2/5 long Frame */
+static const struct stv0900_car_loop_optim FE_STV0900_S2LowQPCarLoopCut20[3] = {
+       /* Modcod               2MPon   2MPoff  5MPon   5MPoff  10MPon  10MPoff 20MPon  20MPoff 30MPon  30MPoff */
+       { STV0900_QPSK_14,      0x0F,   0x3F,   0x0E,   0x3F,   0x2D,   0x2F,   0x2D,   0x1F,   0x3D,   0x3E },
+       { STV0900_QPSK_13,      0x0F,   0x3F,   0x0E,   0x3F,   0x2D,   0x2F,   0x3D,   0x0F,   0x3D,   0x2E },
+       { STV0900_QPSK_25,      0x1F,   0x3F,   0x1E,   0x3F,   0x3D,   0x1F,   0x3D,   0x3E,   0x3D,   0x2E }
+};
+
+
+/* Cut 2.0 Tracking carrier loop carrier  short Frame, cut 1.2 and 2.0 */
+static const struct stv0900_short_frames_car_loop_optim FE_STV0900_S2ShortCarLoop[4]   = {
+       /*Mod   2M_cut1.2 2M_cut2.0 5M_cut1.2 5M_cut2.0 10M_cut1.2 10M_cut2.0 20M_cut1.2 20M_cut2.0 30M_cut1.2 30M_cut2.0 */
+       { STV0900_QPSK,         0x3C,   0x2F,   0x2B,   0x2E,   0x0B,   0x0E,   0x3A,   0x0E,   0x2A,   0x3D },
+       { STV0900_8PSK,         0x0B,   0x3E,   0x2A,   0x0E,   0x0A,   0x2D,   0x19,   0x0D,   0x09,   0x3C },
+       { STV0900_16APSK,       0x1B,   0x1E,   0x1B,   0x1E,   0x1B,   0x1E,   0x3A,   0x3D,   0x2A,   0x2D },
+       { STV0900_32APSK,       0x1B,   0x1E,   0x1B,   0x1E,   0x1B,   0x1E,   0x3A,   0x3D,   0x2A,   0x2D }
+};
+
+static const u16 STV0900_InitVal[182][2] = {
+       { R0900_OUTCFG          , 0x00  },
+       { R0900_MODECFG         , 0xff  },
+       { R0900_AGCRF1CFG       , 0x11  },
+       { R0900_AGCRF2CFG       , 0x13  },
+       { R0900_TSGENERAL1X     , 0x14  },
+       { R0900_TSTTNR2         , 0x21  },
+       { R0900_TSTTNR4         , 0x21  },
+       { R0900_P2_DISTXCTL     , 0x22  },
+       { R0900_P2_F22TX        , 0xc0  },
+       { R0900_P2_F22RX        , 0xc0  },
+       { R0900_P2_DISRXCTL     , 0x00  },
+       { R0900_P2_TNRSTEPS     , 0x87  },
+       { R0900_P2_TNRGAIN      , 0x09  },
+       { R0900_P2_DMDCFGMD     , 0xF9  },
+       { R0900_P2_DEMOD        , 0x08  },
+       { R0900_P2_DMDCFG3      , 0xc4  },
+       { R0900_P2_CARFREQ      , 0xed  },
+       { R0900_P2_TNRCFG2      , 0x02  },
+       { R0900_P2_TNRCFG3      , 0x02  },
+       { R0900_P2_LDT          , 0xd0  },
+       { R0900_P2_LDT2         , 0xb8  },
+       { R0900_P2_TMGCFG       , 0xd2  },
+       { R0900_P2_TMGTHRISE    , 0x20  },
+       { R0900_P2_TMGTHFALL    , 0x00  },
+       { R0900_P2_FECSPY       , 0x88  },
+       { R0900_P2_FSPYDATA     , 0x3a  },
+       { R0900_P2_FBERCPT4     , 0x00  },
+       { R0900_P2_FSPYBER      , 0x10  },
+       { R0900_P2_ERRCTRL1     , 0x35  },
+       { R0900_P2_ERRCTRL2     , 0xc1  },
+       { R0900_P2_CFRICFG      , 0xf8  },
+       { R0900_P2_NOSCFG       , 0x1c  },
+       { R0900_P2_DMDT0M       , 0x20  },
+       { R0900_P2_CORRELMANT   , 0x70  },
+       { R0900_P2_CORRELABS    , 0x88  },
+       { R0900_P2_AGC2O        , 0x5b  },
+       { R0900_P2_AGC2REF      , 0x38  },
+       { R0900_P2_CARCFG       , 0xe4  },
+       { R0900_P2_ACLC         , 0x1A  },
+       { R0900_P2_BCLC         , 0x09  },
+       { R0900_P2_CARHDR       , 0x08  },
+       { R0900_P2_KREFTMG      , 0xc1  },
+       { R0900_P2_SFRUPRATIO   , 0xf0  },
+       { R0900_P2_SFRLOWRATIO  , 0x70  },
+       { R0900_P2_SFRSTEP      , 0x58  },
+       { R0900_P2_TMGCFG2      , 0x01  },
+       { R0900_P2_CAR2CFG      , 0x26  },
+       { R0900_P2_BCLC2S2Q     , 0x86  },
+       { R0900_P2_BCLC2S28     , 0x86  },
+       { R0900_P2_SMAPCOEF7    , 0x77  },
+       { R0900_P2_SMAPCOEF6    , 0x85  },
+       { R0900_P2_SMAPCOEF5    , 0x77  },
+       { R0900_P2_TSCFGL       , 0x20  },
+       { R0900_P2_DMDCFG2      , 0x3b  },
+       { R0900_P2_MODCODLST0   , 0xff  },
+       { R0900_P2_MODCODLST1   , 0xff  },
+       { R0900_P2_MODCODLST2   , 0xff  },
+       { R0900_P2_MODCODLST3   , 0xff  },
+       { R0900_P2_MODCODLST4   , 0xff  },
+       { R0900_P2_MODCODLST5   , 0xff  },
+       { R0900_P2_MODCODLST6   , 0xff  },
+       { R0900_P2_MODCODLST7   , 0xcc  },
+       { R0900_P2_MODCODLST8   , 0xcc  },
+       { R0900_P2_MODCODLST9   , 0xcc  },
+       { R0900_P2_MODCODLSTA   , 0xcc  },
+       { R0900_P2_MODCODLSTB   , 0xcc  },
+       { R0900_P2_MODCODLSTC   , 0xcc  },
+       { R0900_P2_MODCODLSTD   , 0xcc  },
+       { R0900_P2_MODCODLSTE   , 0xcc  },
+       { R0900_P2_MODCODLSTF   , 0xcf  },
+       { R0900_P1_DISTXCTL     , 0x22  },
+       { R0900_P1_F22TX        , 0xc0  },
+       { R0900_P1_F22RX        , 0xc0  },
+       { R0900_P1_DISRXCTL     , 0x00  },
+       { R0900_P1_TNRSTEPS     , 0x87  },
+       { R0900_P1_TNRGAIN      , 0x09  },
+       { R0900_P1_DMDCFGMD     , 0xf9  },
+       { R0900_P1_DEMOD        , 0x08  },
+       { R0900_P1_DMDCFG3      , 0xc4  },
+       { R0900_P1_DMDT0M       , 0x20  },
+       { R0900_P1_CARFREQ      , 0xed  },
+       { R0900_P1_TNRCFG2      , 0x82  },
+       { R0900_P1_TNRCFG3      , 0x02  },
+       { R0900_P1_LDT          , 0xd0  },
+       { R0900_P1_LDT2         , 0xb8  },
+       { R0900_P1_TMGCFG       , 0xd2  },
+       { R0900_P1_TMGTHRISE    , 0x20  },
+       { R0900_P1_TMGTHFALL    , 0x00  },
+       { R0900_P1_SFRUPRATIO   , 0xf0  },
+       { R0900_P1_SFRLOWRATIO  , 0x70  },
+       { R0900_P1_TSCFGL       , 0x20  },
+       { R0900_P1_FECSPY       , 0x88  },
+       { R0900_P1_FSPYDATA     , 0x3a  },
+       { R0900_P1_FBERCPT4     , 0x00  },
+       { R0900_P1_FSPYBER      , 0x10  },
+       { R0900_P1_ERRCTRL1     , 0x35  },
+       { R0900_P1_ERRCTRL2     , 0xc1  },
+       { R0900_P1_CFRICFG      , 0xf8  },
+       { R0900_P1_NOSCFG       , 0x1c  },
+       { R0900_P1_CORRELMANT   , 0x70  },
+       { R0900_P1_CORRELABS    , 0x88  },
+       { R0900_P1_AGC2O        , 0x5b  },
+       { R0900_P1_AGC2REF      , 0x38  },
+       { R0900_P1_CARCFG       , 0xe4  },
+       { R0900_P1_ACLC         , 0x1A  },
+       { R0900_P1_BCLC         , 0x09  },
+       { R0900_P1_CARHDR       , 0x08  },
+       { R0900_P1_KREFTMG      , 0xc1  },
+       { R0900_P1_SFRSTEP      , 0x58  },
+       { R0900_P1_TMGCFG2      , 0x01  },
+       { R0900_P1_CAR2CFG      , 0x26  },
+       { R0900_P1_BCLC2S2Q     , 0x86  },
+       { R0900_P1_BCLC2S28     , 0x86  },
+       { R0900_P1_SMAPCOEF7    , 0x77  },
+       { R0900_P1_SMAPCOEF6    , 0x85  },
+       { R0900_P1_SMAPCOEF5    , 0x77  },
+       { R0900_P1_DMDCFG2      , 0x3b  },
+       { R0900_P1_MODCODLST0   , 0xff  },
+       { R0900_P1_MODCODLST1   , 0xff  },
+       { R0900_P1_MODCODLST2   , 0xff  },
+       { R0900_P1_MODCODLST3   , 0xff  },
+       { R0900_P1_MODCODLST4   , 0xff  },
+       { R0900_P1_MODCODLST5   , 0xff  },
+       { R0900_P1_MODCODLST6   , 0xff  },
+       { R0900_P1_MODCODLST7   , 0xcc  },
+       { R0900_P1_MODCODLST8   , 0xcc  },
+       { R0900_P1_MODCODLST9   , 0xcc  },
+       { R0900_P1_MODCODLSTA   , 0xcc  },
+       { R0900_P1_MODCODLSTB   , 0xcc  },
+       { R0900_P1_MODCODLSTC   , 0xcc  },
+       { R0900_P1_MODCODLSTD   , 0xcc  },
+       { R0900_P1_MODCODLSTE   , 0xcc  },
+       { R0900_P1_MODCODLSTF   , 0xcf  },
+       { R0900_GENCFG          , 0x1d  },
+       { R0900_NBITER_NF4      , 0x37  },
+       { R0900_NBITER_NF5      , 0x29  },
+       { R0900_NBITER_NF6      , 0x37  },
+       { R0900_NBITER_NF7      , 0x33  },
+       { R0900_NBITER_NF8      , 0x31  },
+       { R0900_NBITER_NF9      , 0x2f  },
+       { R0900_NBITER_NF10     , 0x39  },
+       { R0900_NBITER_NF11     , 0x3a  },
+       { R0900_NBITER_NF12     , 0x29  },
+       { R0900_NBITER_NF13     , 0x37  },
+       { R0900_NBITER_NF14     , 0x33  },
+       { R0900_NBITER_NF15     , 0x2f  },
+       { R0900_NBITER_NF16     , 0x39  },
+       { R0900_NBITER_NF17     , 0x3a  },
+       { R0900_NBITERNOERR     , 0x04  },
+       { R0900_GAINLLR_NF4     , 0x0C  },
+       { R0900_GAINLLR_NF5     , 0x0F  },
+       { R0900_GAINLLR_NF6     , 0x11  },
+       { R0900_GAINLLR_NF7     , 0x14  },
+       { R0900_GAINLLR_NF8     , 0x17  },
+       { R0900_GAINLLR_NF9     , 0x19  },
+       { R0900_GAINLLR_NF10    , 0x20  },
+       { R0900_GAINLLR_NF11    , 0x21  },
+       { R0900_GAINLLR_NF12    , 0x0D  },
+       { R0900_GAINLLR_NF13    , 0x0F  },
+       { R0900_GAINLLR_NF14    , 0x13  },
+       { R0900_GAINLLR_NF15    , 0x1A  },
+       { R0900_GAINLLR_NF16    , 0x1F  },
+       { R0900_GAINLLR_NF17    , 0x21  },
+       { R0900_RCCFGH          , 0x20  },
+       { R0900_P1_FECM         , 0x01  }, /*disable DSS modes*/
+       { R0900_P2_FECM         , 0x01  }, /*disable DSS modes*/
+       { R0900_P1_PRVIT        , 0x2F  }, /*disable puncture rate 6/7*/
+       { R0900_P2_PRVIT        , 0x2F  }, /*disable puncture rate 6/7*/
+       { R0900_STROUT1CFG      , 0x4c  },
+       { R0900_STROUT2CFG      , 0x4c  },
+       { R0900_CLKOUT1CFG      , 0x50  },
+       { R0900_CLKOUT2CFG      , 0x50  },
+       { R0900_DPN1CFG         , 0x4a  },
+       { R0900_DPN2CFG         , 0x4a  },
+       { R0900_DATA71CFG       , 0x52  },
+       { R0900_DATA72CFG       , 0x52  },
+       { R0900_P1_TSCFGM       , 0xc0  },
+       { R0900_P2_TSCFGM       , 0xc0  },
+       { R0900_P1_TSCFGH       , 0xe0  }, /* DVB-CI timings */
+       { R0900_P2_TSCFGH       , 0xe0  }, /* DVB-CI timings */
+       { R0900_P1_TSSPEED      , 0x40  },
+       { R0900_P2_TSSPEED      , 0x40  },
+};
+
+static const u16 STV0900_Cut20_AddOnVal[32][2] = {
+       { R0900_P2_DMDCFG3      , 0xe8  },
+       { R0900_P2_DMDCFG4      , 0x10  },
+       { R0900_P2_CARFREQ      , 0x38  },
+       { R0900_P2_CARHDR       , 0x20  },
+       { R0900_P2_KREFTMG      , 0x5a  },
+       { R0900_P2_SMAPCOEF7    , 0x06  },
+       { R0900_P2_SMAPCOEF6    , 0x00  },
+       { R0900_P2_SMAPCOEF5    , 0x04  },
+       { R0900_P2_NOSCFG       , 0x0c  },
+       { R0900_P1_DMDCFG3      , 0xe8  },
+       { R0900_P1_DMDCFG4      , 0x10  },
+       { R0900_P1_CARFREQ      , 0x38  },
+       { R0900_P1_CARHDR       , 0x20  },
+       { R0900_P1_KREFTMG      , 0x5a  },
+       { R0900_P1_SMAPCOEF7    , 0x06  },
+       { R0900_P1_SMAPCOEF6    , 0x00  },
+       { R0900_P1_SMAPCOEF5    , 0x04  },
+       { R0900_P1_NOSCFG       , 0x0c  },
+       { R0900_GAINLLR_NF4     , 0x21  },
+       { R0900_GAINLLR_NF5     , 0x21  },
+       { R0900_GAINLLR_NF6     , 0x20  },
+       { R0900_GAINLLR_NF7     , 0x1F  },
+       { R0900_GAINLLR_NF8     , 0x1E  },
+       { R0900_GAINLLR_NF9     , 0x1E  },
+       { R0900_GAINLLR_NF10    , 0x1D  },
+       { R0900_GAINLLR_NF11    , 0x1B  },
+       { R0900_GAINLLR_NF12    , 0x20  },
+       { R0900_GAINLLR_NF13    , 0x20  },
+       { R0900_GAINLLR_NF14    , 0x20  },
+       { R0900_GAINLLR_NF15    , 0x20  },
+       { R0900_GAINLLR_NF16    , 0x20  },
+       { R0900_GAINLLR_NF17    , 0x21  }
+
+};
+
+#endif
diff --git a/drivers/media/dvb/frontends/stv0900_priv.h b/drivers/media/dvb/frontends/stv0900_priv.h
new file mode 100644 (file)
index 0000000..762d5af
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * stv0900_priv.h
+ *
+ * Driver for ST STV0900 satellite demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * 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 STV0900_PRIV_H
+#define STV0900_PRIV_H
+
+#include <linux/i2c.h>
+
+#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X))
+#define INRANGE(X, Y, Z) ((((X) <= (Y)) && ((Y) <= (Z))) \
+               || (((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0)
+
+#ifndef MAKEWORD
+#define MAKEWORD(X, Y) (((X) << 8) + (Y))
+#endif
+
+#define LSB(X) (((X) & 0xFF))
+#define MSB(Y) (((Y) >> 8) & 0xFF)
+
+#ifndef TRUE
+#define TRUE (1 == 1)
+#endif
+#ifndef FALSE
+#define FALSE (!TRUE)
+#endif
+
+#define        dmd_reg(a, b, c) \
+       do { \
+               a = 0; \
+               switch (demod) { \
+               case STV0900_DEMOD_1: \
+               default: \
+                       a = b; \
+                       break; \
+               case STV0900_DEMOD_2: \
+                       a = c; \
+                       break; \
+               } \
+       } while (0)
+
+#define dmd_choose(a, b)       (demod = STV0900_DEMOD_2 ? b : a))
+
+static int stvdebug;
+
+#define dprintk(args...) \
+       do { \
+               if (stvdebug) \
+                       printk(KERN_DEBUG args); \
+       } while (0)
+
+#define STV0900_MAXLOOKUPSIZE 500
+#define STV0900_BLIND_SEARCH_AGC2_TH 700
+
+/* One point of the lookup table */
+struct stv000_lookpoint {
+       s32 realval;/* real value */
+       s32 regval;/* binary value */
+};
+
+/* Lookup table definition */
+struct stv0900_table{
+       s32 size;/* Size of the lookup table */
+       struct stv000_lookpoint table[STV0900_MAXLOOKUPSIZE];/* Lookup table */
+};
+
+enum fe_stv0900_error {
+       STV0900_NO_ERROR = 0,
+       STV0900_INVALID_HANDLE,
+       STV0900_BAD_PARAMETER,
+       STV0900_I2C_ERROR,
+       STV0900_SEARCH_FAILED,
+};
+
+enum fe_stv0900_clock_type {
+       STV0900_USE_REGISTERS_DEFAULT,
+       STV0900_SERIAL_PUNCT_CLOCK,/*Serial punctured clock */
+       STV0900_SERIAL_CONT_CLOCK,/*Serial continues clock */
+       STV0900_PARALLEL_PUNCT_CLOCK,/*Parallel punctured clock */
+       STV0900_DVBCI_CLOCK/*Parallel continues clock : DVBCI */
+};
+
+enum fe_stv0900_search_state {
+       STV0900_SEARCH = 0,
+       STV0900_PLH_DETECTED,
+       STV0900_DVBS2_FOUND,
+       STV0900_DVBS_FOUND
+
+};
+
+enum fe_stv0900_ldpc_state {
+       STV0900_PATH1_OFF_PATH2_OFF = 0,
+       STV0900_PATH1_ON_PATH2_OFF = 1,
+       STV0900_PATH1_OFF_PATH2_ON = 2,
+       STV0900_PATH1_ON_PATH2_ON = 3
+};
+
+enum fe_stv0900_signal_type {
+       STV0900_NOAGC1 = 0,
+       STV0900_AGC1OK,
+       STV0900_NOTIMING,
+       STV0900_ANALOGCARRIER,
+       STV0900_TIMINGOK,
+       STV0900_NOAGC2,
+       STV0900_AGC2OK,
+       STV0900_NOCARRIER,
+       STV0900_CARRIEROK,
+       STV0900_NODATA,
+       STV0900_DATAOK,
+       STV0900_OUTOFRANGE,
+       STV0900_RANGEOK
+};
+
+enum fe_stv0900_demod_num {
+       STV0900_DEMOD_1,
+       STV0900_DEMOD_2
+};
+
+enum fe_stv0900_tracking_standard {
+       STV0900_DVBS1_STANDARD,/* Found Standard*/
+       STV0900_DVBS2_STANDARD,
+       STV0900_DSS_STANDARD,
+       STV0900_TURBOCODE_STANDARD,
+       STV0900_UNKNOWN_STANDARD
+};
+
+enum fe_stv0900_search_standard {
+       STV0900_AUTO_SEARCH,
+       STV0900_SEARCH_DVBS1,/* Search Standard*/
+       STV0900_SEARCH_DVBS2,
+       STV0900_SEARCH_DSS,
+       STV0900_SEARCH_TURBOCODE
+};
+
+enum fe_stv0900_search_algo {
+       STV0900_BLIND_SEARCH,/* offset freq and SR are Unknown */
+       STV0900_COLD_START,/* only the SR is known */
+       STV0900_WARM_START/* offset freq and SR are known */
+};
+
+enum fe_stv0900_modulation {
+       STV0900_QPSK,
+       STV0900_8PSK,
+       STV0900_16APSK,
+       STV0900_32APSK,
+       STV0900_UNKNOWN
+};
+
+enum fe_stv0900_modcode {
+       STV0900_DUMMY_PLF,
+       STV0900_QPSK_14,
+       STV0900_QPSK_13,
+       STV0900_QPSK_25,
+       STV0900_QPSK_12,
+       STV0900_QPSK_35,
+       STV0900_QPSK_23,
+       STV0900_QPSK_34,
+       STV0900_QPSK_45,
+       STV0900_QPSK_56,
+       STV0900_QPSK_89,
+       STV0900_QPSK_910,
+       STV0900_8PSK_35,
+       STV0900_8PSK_23,
+       STV0900_8PSK_34,
+       STV0900_8PSK_56,
+       STV0900_8PSK_89,
+       STV0900_8PSK_910,
+       STV0900_16APSK_23,
+       STV0900_16APSK_34,
+       STV0900_16APSK_45,
+       STV0900_16APSK_56,
+       STV0900_16APSK_89,
+       STV0900_16APSK_910,
+       STV0900_32APSK_34,
+       STV0900_32APSK_45,
+       STV0900_32APSK_56,
+       STV0900_32APSK_89,
+       STV0900_32APSK_910,
+       STV0900_MODCODE_UNKNOWN
+};
+
+enum fe_stv0900_fec {/*DVBS1, DSS and turbo code puncture rate*/
+       STV0900_FEC_1_2 = 0,
+       STV0900_FEC_2_3,
+       STV0900_FEC_3_4,
+       STV0900_FEC_4_5,/*for turbo code only*/
+       STV0900_FEC_5_6,
+       STV0900_FEC_6_7,/*for DSS only */
+       STV0900_FEC_7_8,
+       STV0900_FEC_8_9,/*for turbo code only*/
+       STV0900_FEC_UNKNOWN
+};
+
+enum fe_stv0900_frame_length {
+       STV0900_LONG_FRAME,
+       STV0900_SHORT_FRAME
+};
+
+enum fe_stv0900_pilot {
+       STV0900_PILOTS_OFF,
+       STV0900_PILOTS_ON
+};
+
+enum fe_stv0900_rolloff {
+       STV0900_35,
+       STV0900_25,
+       STV0900_20
+};
+
+enum fe_stv0900_search_iq {
+       STV0900_IQ_AUTO,
+       STV0900_IQ_AUTO_NORMAL_FIRST,
+       STV0900_IQ_FORCE_NORMAL,
+       STV0900_IQ_FORCE_SWAPPED
+};
+
+enum stv0900_iq_inversion {
+       STV0900_IQ_NORMAL,
+       STV0900_IQ_SWAPPED
+};
+
+enum fe_stv0900_diseqc_mode {
+       STV0900_22KHZ_Continues = 0,
+       STV0900_DISEQC_2_3_PWM = 2,
+       STV0900_DISEQC_3_3_PWM = 3,
+       STV0900_DISEQC_2_3_ENVELOP = 4,
+       STV0900_DISEQC_3_3_ENVELOP = 5
+};
+
+enum fe_stv0900_demod_mode {
+       STV0900_SINGLE = 0,
+       STV0900_DUAL
+};
+
+struct stv0900_init_params{
+       u32     dmd_ref_clk;/* Refrence,Input clock for the demod in Hz */
+
+       /* Demodulator Type (single demod or dual demod) */
+       enum fe_stv0900_demod_mode      demod_mode;
+       enum fe_stv0900_rolloff         rolloff;
+       enum fe_stv0900_clock_type      path1_ts_clock;
+
+       u8      tun1_maddress;
+       int     tuner1_adc;
+
+       /* IQ from the tuner1 to the demod */
+       enum stv0900_iq_inversion       tun1_iq_inversion;
+       enum fe_stv0900_clock_type      path2_ts_clock;
+
+       u8      tun2_maddress;
+       int     tuner2_adc;
+
+       /* IQ from the tuner2 to the demod */
+       enum stv0900_iq_inversion       tun2_iq_inversion;
+};
+
+struct stv0900_search_params {
+       enum fe_stv0900_demod_num       path;/* Path Used demod1 or 2 */
+
+       u32     frequency;/* Transponder frequency (in KHz) */
+       u32     symbol_rate;/* Transponder symbol rate  (in bds)*/
+       u32     search_range;/* Range of the search (in Hz) */
+
+       enum fe_stv0900_search_standard standard;
+       enum fe_stv0900_modulation      modulation;
+       enum fe_stv0900_fec             fec;
+       enum fe_stv0900_modcode         modcode;
+       enum fe_stv0900_search_iq       iq_inversion;
+       enum fe_stv0900_search_algo     search_algo;
+
+};
+
+struct stv0900_signal_info {
+       int     locked;/* Transponder locked */
+       u32     frequency;/* Transponder frequency (in KHz) */
+       u32     symbol_rate;/* Transponder symbol rate  (in Mbds) */
+
+       enum fe_stv0900_tracking_standard       standard;
+       enum fe_stv0900_fec                     fec;
+       enum fe_stv0900_modcode                 modcode;
+       enum fe_stv0900_modulation              modulation;
+       enum fe_stv0900_pilot                   pilot;
+       enum fe_stv0900_frame_length            frame_length;
+       enum stv0900_iq_inversion               spectrum;
+       enum fe_stv0900_rolloff                 rolloff;
+
+       s32 Power;/* Power of the RF signal (dBm) */
+       s32 C_N;/* Carrier to noise ratio (dB x10)*/
+       u32 BER;/* Bit error rate (x10^7) */
+
+};
+
+struct stv0900_internal{
+       s32     quartz;
+       s32     mclk;
+       /* manual RollOff for DVBS1/DSS only */
+       enum fe_stv0900_rolloff         rolloff;
+       /* Demodulator use for single demod or for dual demod) */
+       enum fe_stv0900_demod_mode      demod_mode;
+
+       /*Demod 1*/
+       s32     tuner1_freq;
+       s32     tuner1_bw;
+       s32     dmd1_symbol_rate;
+       s32     dmd1_srch_range;
+
+       /* algorithm for search Blind, Cold or Warm*/
+       enum fe_stv0900_search_algo     dmd1_srch_algo;
+       /* search standard: Auto, DVBS1/DSS only or DVBS2 only*/
+       enum fe_stv0900_search_standard dmd1_srch_standard;
+       /* inversion search : auto, auto norma first, normal or inverted */
+       enum fe_stv0900_search_iq       dmd1_srch_iq_inv;
+       enum fe_stv0900_modcode         dmd1_modcode;
+       enum fe_stv0900_modulation      dmd1_modulation;
+       enum fe_stv0900_fec             dmd1_fec;
+
+       struct stv0900_signal_info      dmd1_rslts;
+       enum fe_stv0900_signal_type     dmd1_state;
+
+       enum fe_stv0900_error           dmd1_err;
+
+       /*Demod 2*/
+       s32     tuner2_freq;
+       s32     tuner2_bw;
+       s32     dmd2_symbol_rate;
+       s32     dmd2_srch_range;
+
+       enum fe_stv0900_search_algo     dmd2_srch_algo;
+       enum fe_stv0900_search_standard dmd2_srch_stndrd;
+       /* inversion search : auto, auto normal first, normal or inverted */
+       enum fe_stv0900_search_iq       dmd2_srch_iq_inv;
+       enum fe_stv0900_modcode         dmd2_modcode;
+       enum fe_stv0900_modulation      dmd2_modulation;
+       enum fe_stv0900_fec             dmd2_fec;
+
+       /* results of the search*/
+       struct stv0900_signal_info      dmd2_rslts;
+       /* current state of the search algorithm */
+       enum fe_stv0900_signal_type     dmd2_state;
+
+       enum fe_stv0900_error           dmd2_err;
+
+       struct i2c_adapter      *i2c_adap;
+       u8                      i2c_addr;
+       u8                      clkmode;/* 0 for CLKI, 2 for XTALI */
+       u8                      chip_id;
+       enum fe_stv0900_error   errs;
+       int dmds_used;
+};
+
+/* state for each demod */
+struct stv0900_state {
+       /* pointer for internal params, one for each pair of demods */
+       struct stv0900_internal         *internal;
+       struct i2c_adapter              *i2c_adap;
+       const struct stv0900_config     *config;
+       struct dvb_frontend             frontend;
+       int demod;
+};
+
+extern s32 ge2comp(s32 a, s32 width);
+
+extern void stv0900_write_reg(struct stv0900_internal *i_params,
+                               u16 reg_addr, u8 reg_data);
+
+extern u8 stv0900_read_reg(struct stv0900_internal *i_params,
+                               u16 reg_addr);
+
+extern void stv0900_write_bits(struct stv0900_internal *i_params,
+                               u32 label, u8 val);
+
+extern u8 stv0900_get_bits(struct stv0900_internal *i_params,
+                               u32 label);
+
+extern int stv0900_get_demod_lock(struct stv0900_internal *i_params,
+                               enum fe_stv0900_demod_num demod, s32 time_out);
+extern int stv0900_check_signal_presence(struct stv0900_internal *i_params,
+                               enum fe_stv0900_demod_num demod);
+
+extern enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe);
+
+extern void stv0900_set_tuner(struct dvb_frontend *fe, u32 frequency,
+                               u32 bandwidth);
+extern void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth);
+
+extern void stv0900_start_search(struct stv0900_internal *i_params,
+                               enum fe_stv0900_demod_num demod);
+
+extern u8 stv0900_get_optim_carr_loop(s32 srate,
+                               enum fe_stv0900_modcode modcode,
+                               s32 pilot, u8 chip_id);
+
+extern u8 stv0900_get_optim_short_carr_loop(s32 srate,
+                               enum fe_stv0900_modulation modulation,
+                               u8 chip_id);
+
+extern void stv0900_stop_all_s2_modcod(struct stv0900_internal *i_params,
+                               enum fe_stv0900_demod_num demod);
+
+extern void stv0900_activate_s2_modcode(struct stv0900_internal *i_params,
+                               enum fe_stv0900_demod_num demod);
+
+extern void stv0900_activate_s2_modcode_single(struct stv0900_internal *i_params,
+                               enum fe_stv0900_demod_num demod);
+
+extern enum fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe,
+                               enum fe_stv0900_demod_num demod);
+
+#endif
diff --git a/drivers/media/dvb/frontends/stv0900_reg.h b/drivers/media/dvb/frontends/stv0900_reg.h
new file mode 100644 (file)
index 0000000..264f9cf
--- /dev/null
@@ -0,0 +1,3787 @@
+/*
+ * stv0900_reg.h
+ *
+ * Driver for ST STV0900 satellite demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * 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 STV0900_REG_H
+#define STV0900_REG_H
+
+/*MID*/
+#define R0900_MID  0xf100
+#define F0900_MCHIP_IDENT  0xf10000f0
+#define F0900_MRELEASE  0xf100000f
+
+/*DACR1*/
+#define R0900_DACR1  0xf113
+#define F0900_DAC_MODE  0xf11300e0
+#define F0900_DAC_VALUE1  0xf113000f
+
+/*DACR2*/
+#define R0900_DACR2  0xf114
+#define F0900_DAC_VALUE0  0xf11400ff
+
+/*OUTCFG*/
+#define R0900_OUTCFG  0xf11c
+#define F0900_INV_DATA6  0xf11c0080
+#define F0900_OUTSERRS1_HZ  0xf11c0040
+#define F0900_OUTSERRS2_HZ  0xf11c0020
+#define F0900_OUTSERRS3_HZ  0xf11c0010
+#define F0900_OUTPARRS3_HZ  0xf11c0008
+#define F0900_OUTHZ3_CONTROL  0xf11c0007
+
+/*MODECFG*/
+#define R0900_MODECFG  0xf11d
+#define F0900_FECSPY_SEL_2  0xf11d0020
+#define F0900_HWARE_SEL_2  0xf11d0010
+#define F0900_PKTDEL_SEL_2  0xf11d0008
+#define F0900_DISEQC_SEL_2  0xf11d0004
+#define F0900_VIT_SEL_2  0xf11d0002
+#define F0900_DEMOD_SEL_2  0xf11d0001
+
+/*IRQSTATUS3*/
+#define R0900_IRQSTATUS3  0xf120
+#define F0900_SPLL_LOCK  0xf1200020
+#define F0900_SSTREAM_LCK_3  0xf1200010
+#define F0900_SSTREAM_LCK_2  0xf1200008
+#define F0900_SSTREAM_LCK_1  0xf1200004
+#define F0900_SDVBS1_PRF_2  0xf1200002
+#define F0900_SDVBS1_PRF_1  0xf1200001
+
+/*IRQSTATUS2*/
+#define R0900_IRQSTATUS2  0xf121
+#define F0900_SSPY_ENDSIM_3  0xf1210080
+#define F0900_SSPY_ENDSIM_2  0xf1210040
+#define F0900_SSPY_ENDSIM_1  0xf1210020
+#define F0900_SPKTDEL_ERROR_2  0xf1210010
+#define F0900_SPKTDEL_LOCKB_2  0xf1210008
+#define F0900_SPKTDEL_LOCK_2  0xf1210004
+#define F0900_SPKTDEL_ERROR_1  0xf1210002
+#define F0900_SPKTDEL_LOCKB_1  0xf1210001
+
+/*IRQSTATUS1*/
+#define R0900_IRQSTATUS1  0xf122
+#define F0900_SPKTDEL_LOCK_1  0xf1220080
+#define F0900_SEXTPINB2  0xf1220040
+#define F0900_SEXTPIN2  0xf1220020
+#define F0900_SEXTPINB1  0xf1220010
+#define F0900_SEXTPIN1  0xf1220008
+#define F0900_SDEMOD_LOCKB_2  0xf1220004
+#define F0900_SDEMOD_LOCK_2  0xf1220002
+#define F0900_SDEMOD_IRQ_2  0xf1220001
+
+/*IRQSTATUS0*/
+#define R0900_IRQSTATUS0  0xf123
+#define F0900_SDEMOD_LOCKB_1  0xf1230080
+#define F0900_SDEMOD_LOCK_1  0xf1230040
+#define F0900_SDEMOD_IRQ_1  0xf1230020
+#define F0900_SBCH_ERRFLAG  0xf1230010
+#define F0900_SDISEQC2RX_IRQ  0xf1230008
+#define F0900_SDISEQC2TX_IRQ  0xf1230004
+#define F0900_SDISEQC1RX_IRQ  0xf1230002
+#define F0900_SDISEQC1TX_IRQ  0xf1230001
+
+/*IRQMASK3*/
+#define R0900_IRQMASK3  0xf124
+#define F0900_MPLL_LOCK  0xf1240020
+#define F0900_MSTREAM_LCK_3  0xf1240010
+#define F0900_MSTREAM_LCK_2  0xf1240008
+#define F0900_MSTREAM_LCK_1  0xf1240004
+#define F0900_MDVBS1_PRF_2  0xf1240002
+#define F0900_MDVBS1_PRF_1  0xf1240001
+
+/*IRQMASK2*/
+#define R0900_IRQMASK2  0xf125
+#define F0900_MSPY_ENDSIM_3  0xf1250080
+#define F0900_MSPY_ENDSIM_2  0xf1250040
+#define F0900_MSPY_ENDSIM_1  0xf1250020
+#define F0900_MPKTDEL_ERROR_2  0xf1250010
+#define F0900_MPKTDEL_LOCKB_2  0xf1250008
+#define F0900_MPKTDEL_LOCK_2  0xf1250004
+#define F0900_MPKTDEL_ERROR_1  0xf1250002
+#define F0900_MPKTDEL_LOCKB_1  0xf1250001
+
+/*IRQMASK1*/
+#define R0900_IRQMASK1  0xf126
+#define F0900_MPKTDEL_LOCK_1  0xf1260080
+#define F0900_MEXTPINB2  0xf1260040
+#define F0900_MEXTPIN2  0xf1260020
+#define F0900_MEXTPINB1  0xf1260010
+#define F0900_MEXTPIN1  0xf1260008
+#define F0900_MDEMOD_LOCKB_2  0xf1260004
+#define F0900_MDEMOD_LOCK_2  0xf1260002
+#define F0900_MDEMOD_IRQ_2  0xf1260001
+
+/*IRQMASK0*/
+#define R0900_IRQMASK0  0xf127
+#define F0900_MDEMOD_LOCKB_1  0xf1270080
+#define F0900_MDEMOD_LOCK_1  0xf1270040
+#define F0900_MDEMOD_IRQ_1  0xf1270020
+#define F0900_MBCH_ERRFLAG  0xf1270010
+#define F0900_MDISEQC2RX_IRQ  0xf1270008
+#define F0900_MDISEQC2TX_IRQ  0xf1270004
+#define F0900_MDISEQC1RX_IRQ  0xf1270002
+#define F0900_MDISEQC1TX_IRQ  0xf1270001
+
+/*I2CCFG*/
+#define R0900_I2CCFG  0xf129
+#define F0900_I2C2_FASTMODE  0xf1290080
+#define F0900_STATUS_WR2  0xf1290040
+#define F0900_I2C2ADDR_INC  0xf1290030
+#define F0900_I2C_FASTMODE  0xf1290008
+#define F0900_STATUS_WR  0xf1290004
+#define F0900_I2CADDR_INC  0xf1290003
+
+/*P1_I2CRPT*/
+#define R0900_P1_I2CRPT  0xf12a
+#define F0900_P1_I2CT_ON  0xf12a0080
+#define F0900_P1_ENARPT_LEVEL  0xf12a0070
+#define F0900_P1_SCLT_DELAY  0xf12a0008
+#define F0900_P1_STOP_ENABLE  0xf12a0004
+#define F0900_P1_STOP_SDAT2SDA  0xf12a0002
+
+/*P2_I2CRPT*/
+#define R0900_P2_I2CRPT  0xf12b
+#define F0900_P2_I2CT_ON  0xf12b0080
+#define F0900_P2_ENARPT_LEVEL  0xf12b0070
+#define F0900_P2_SCLT_DELAY  0xf12b0008
+#define F0900_P2_STOP_ENABLE  0xf12b0004
+#define F0900_P2_STOP_SDAT2SDA  0xf12b0002
+
+/*CLKI2CFG*/
+#define R0900_CLKI2CFG  0xf140
+#define F0900_CLKI2_OPD  0xf1400080
+#define F0900_CLKI2_CONFIG  0xf140007e
+#define F0900_CLKI2_XOR  0xf1400001
+
+/*GPIO1CFG*/
+#define R0900_GPIO1CFG  0xf141
+#define F0900_GPIO1_OPD  0xf1410080
+#define F0900_GPIO1_CONFIG  0xf141007e
+#define F0900_GPIO1_XOR  0xf1410001
+
+/*GPIO2CFG*/
+#define R0900_GPIO2CFG  0xf142
+#define F0900_GPIO2_OPD  0xf1420080
+#define F0900_GPIO2_CONFIG  0xf142007e
+#define F0900_GPIO2_XOR  0xf1420001
+
+/*GPIO3CFG*/
+#define R0900_GPIO3CFG  0xf143
+#define F0900_GPIO3_OPD  0xf1430080
+#define F0900_GPIO3_CONFIG  0xf143007e
+#define F0900_GPIO3_XOR  0xf1430001
+
+/*GPIO4CFG*/
+#define R0900_GPIO4CFG  0xf144
+#define F0900_GPIO4_OPD  0xf1440080
+#define F0900_GPIO4_CONFIG  0xf144007e
+#define F0900_GPIO4_XOR  0xf1440001
+
+/*GPIO5CFG*/
+#define R0900_GPIO5CFG  0xf145
+#define F0900_GPIO5_OPD  0xf1450080
+#define F0900_GPIO5_CONFIG  0xf145007e
+#define F0900_GPIO5_XOR  0xf1450001
+
+/*GPIO6CFG*/
+#define R0900_GPIO6CFG  0xf146
+#define F0900_GPIO6_OPD  0xf1460080
+#define F0900_GPIO6_CONFIG  0xf146007e
+#define F0900_GPIO6_XOR  0xf1460001
+
+/*GPIO7CFG*/
+#define R0900_GPIO7CFG  0xf147
+#define F0900_GPIO7_OPD  0xf1470080
+#define F0900_GPIO7_CONFIG  0xf147007e
+#define F0900_GPIO7_XOR  0xf1470001
+
+/*GPIO8CFG*/
+#define R0900_GPIO8CFG  0xf148
+#define F0900_GPIO8_OPD  0xf1480080
+#define F0900_GPIO8_CONFIG  0xf148007e
+#define F0900_GPIO8_XOR  0xf1480001
+
+/*GPIO9CFG*/
+#define R0900_GPIO9CFG  0xf149
+#define F0900_GPIO9_OPD  0xf1490080
+#define F0900_GPIO9_CONFIG  0xf149007e
+#define F0900_GPIO9_XOR  0xf1490001
+
+/*GPIO10CFG*/
+#define R0900_GPIO10CFG  0xf14a
+#define F0900_GPIO10_OPD  0xf14a0080
+#define F0900_GPIO10_CONFIG  0xf14a007e
+#define F0900_GPIO10_XOR  0xf14a0001
+
+/*GPIO11CFG*/
+#define R0900_GPIO11CFG  0xf14b
+#define F0900_GPIO11_OPD  0xf14b0080
+#define F0900_GPIO11_CONFIG  0xf14b007e
+#define F0900_GPIO11_XOR  0xf14b0001
+
+/*GPIO12CFG*/
+#define R0900_GPIO12CFG  0xf14c
+#define F0900_GPIO12_OPD  0xf14c0080
+#define F0900_GPIO12_CONFIG  0xf14c007e
+#define F0900_GPIO12_XOR  0xf14c0001
+
+/*GPIO13CFG*/
+#define R0900_GPIO13CFG  0xf14d
+#define F0900_GPIO13_OPD  0xf14d0080
+#define F0900_GPIO13_CONFIG  0xf14d007e
+#define F0900_GPIO13_XOR  0xf14d0001
+
+/*CS0CFG*/
+#define R0900_CS0CFG  0xf14e
+#define F0900_CS0_OPD  0xf14e0080
+#define F0900_CS0_CONFIG  0xf14e007e
+#define F0900_CS0_XOR  0xf14e0001
+
+/*CS1CFG*/
+#define R0900_CS1CFG  0xf14f
+#define F0900_CS1_OPD  0xf14f0080
+#define F0900_CS1_CONFIG  0xf14f007e
+#define F0900_CS1_XOR  0xf14f0001
+
+/*STDBYCFG*/
+#define R0900_STDBYCFG  0xf150
+#define F0900_STDBY_OPD  0xf1500080
+#define F0900_STDBY_CONFIG  0xf150007e
+#define F0900_STBDY_XOR  0xf1500001
+
+/*DIRCLKCFG*/
+#define R0900_DIRCLKCFG  0xf151
+#define F0900_DIRCLK_OPD  0xf1510080
+#define F0900_DIRCLK_CONFIG  0xf151007e
+#define F0900_DIRCLK_XOR  0xf1510001
+
+/*AGCRF1CFG*/
+#define R0900_AGCRF1CFG  0xf152
+#define F0900_AGCRF1_OPD  0xf1520080
+#define F0900_AGCRF1_CONFIG  0xf152007e
+#define F0900_AGCRF1_XOR  0xf1520001
+
+/*SDAT1CFG*/
+#define R0900_SDAT1CFG  0xf153
+#define F0900_SDAT1_OPD  0xf1530080
+#define F0900_SDAT1_CONFIG  0xf153007e
+#define F0900_SDAT1_XOR  0xf1530001
+
+/*SCLT1CFG*/
+#define R0900_SCLT1CFG  0xf154
+#define F0900_SCLT1_OPD  0xf1540080
+#define F0900_SCLT1_CONFIG  0xf154007e
+#define F0900_SCLT1_XOR  0xf1540001
+
+/*DISEQCO1CFG*/
+#define R0900_DISEQCO1CFG  0xf155
+#define F0900_DISEQCO1_OPD  0xf1550080
+#define F0900_DISEQCO1_CONFIG  0xf155007e
+#define F0900_DISEQC1_XOR  0xf1550001
+
+/*AGCRF2CFG*/
+#define R0900_AGCRF2CFG  0xf156
+#define F0900_AGCRF2_OPD  0xf1560080
+#define F0900_AGCRF2_CONFIG  0xf156007e
+#define F0900_AGCRF2_XOR  0xf1560001
+
+/*SDAT2CFG*/
+#define R0900_SDAT2CFG  0xf157
+#define F0900_SDAT2_OPD  0xf1570080
+#define F0900_SDAT2_CONFIG  0xf157007e
+#define F0900_SDAT2_XOR  0xf1570001
+
+/*SCLT2CFG*/
+#define R0900_SCLT2CFG  0xf158
+#define F0900_SCLT2_OPD  0xf1580080
+#define F0900_SCLT2_CONFIG  0xf158007e
+#define F0900_SCLT2_XOR  0xf1580001
+
+/*DISEQCO2CFG*/
+#define R0900_DISEQCO2CFG  0xf159
+#define F0900_DISEQCO2_OPD  0xf1590080
+#define F0900_DISEQCO2_CONFIG  0xf159007e
+#define F0900_DISEQC2_XOR  0xf1590001
+
+/*CLKOUT27CFG*/
+#define R0900_CLKOUT27CFG  0xf15a
+#define F0900_CLKOUT27_OPD  0xf15a0080
+#define F0900_CLKOUT27_CONFIG  0xf15a007e
+#define F0900_CLKOUT27_XOR  0xf15a0001
+
+/*ERROR1CFG*/
+#define R0900_ERROR1CFG  0xf15b
+#define F0900_ERROR1_OPD  0xf15b0080
+#define F0900_ERROR1_CONFIG  0xf15b007e
+#define F0900_ERROR1_XOR  0xf15b0001
+
+/*DPN1CFG*/
+#define R0900_DPN1CFG  0xf15c
+#define F0900_DPN1_OPD  0xf15c0080
+#define F0900_DPN1_CONFIG  0xf15c007e
+#define F0900_DPN1_XOR  0xf15c0001
+
+/*STROUT1CFG*/
+#define R0900_STROUT1CFG  0xf15d
+#define F0900_STROUT1_OPD  0xf15d0080
+#define F0900_STROUT1_CONFIG  0xf15d007e
+#define F0900_STROUT1_XOR  0xf15d0001
+
+/*CLKOUT1CFG*/
+#define R0900_CLKOUT1CFG  0xf15e
+#define F0900_CLKOUT1_OPD  0xf15e0080
+#define F0900_CLKOUT1_CONFIG  0xf15e007e
+#define F0900_CLKOUT1_XOR  0xf15e0001
+
+/*DATA71CFG*/
+#define R0900_DATA71CFG  0xf15f
+#define F0900_DATA71_OPD  0xf15f0080
+#define F0900_DATA71_CONFIG  0xf15f007e
+#define F0900_DATA71_XOR  0xf15f0001
+
+/*ERROR2CFG*/
+#define R0900_ERROR2CFG  0xf160
+#define F0900_ERROR2_OPD  0xf1600080
+#define F0900_ERROR2_CONFIG  0xf160007e
+#define F0900_ERROR2_XOR  0xf1600001
+
+/*DPN2CFG*/
+#define R0900_DPN2CFG  0xf161
+#define F0900_DPN2_OPD  0xf1610080
+#define F0900_DPN2_CONFIG  0xf161007e
+#define F0900_DPN2_XOR  0xf1610001
+
+/*STROUT2CFG*/
+#define R0900_STROUT2CFG  0xf162
+#define F0900_STROUT2_OPD  0xf1620080
+#define F0900_STROUT2_CONFIG  0xf162007e
+#define F0900_STROUT2_XOR  0xf1620001
+
+/*CLKOUT2CFG*/
+#define R0900_CLKOUT2CFG  0xf163
+#define F0900_CLKOUT2_OPD  0xf1630080
+#define F0900_CLKOUT2_CONFIG  0xf163007e
+#define F0900_CLKOUT2_XOR  0xf1630001
+
+/*DATA72CFG*/
+#define R0900_DATA72CFG  0xf164
+#define F0900_DATA72_OPD  0xf1640080
+#define F0900_DATA72_CONFIG  0xf164007e
+#define F0900_DATA72_XOR  0xf1640001
+
+/*ERROR3CFG*/
+#define R0900_ERROR3CFG  0xf165
+#define F0900_ERROR3_OPD  0xf1650080
+#define F0900_ERROR3_CONFIG  0xf165007e
+#define F0900_ERROR3_XOR  0xf1650001
+
+/*DPN3CFG*/
+#define R0900_DPN3CFG  0xf166
+#define F0900_DPN3_OPD  0xf1660080
+#define F0900_DPN3_CONFIG  0xf166007e
+#define F0900_DPN3_XOR  0xf1660001
+
+/*STROUT3CFG*/
+#define R0900_STROUT3CFG  0xf167
+#define F0900_STROUT3_OPD  0xf1670080
+#define F0900_STROUT3_CONFIG  0xf167007e
+#define F0900_STROUT3_XOR  0xf1670001
+
+/*CLKOUT3CFG*/
+#define R0900_CLKOUT3CFG  0xf168
+#define F0900_CLKOUT3_OPD  0xf1680080
+#define F0900_CLKOUT3_CONFIG  0xf168007e
+#define F0900_CLKOUT3_XOR  0xf1680001
+
+/*DATA73CFG*/
+#define R0900_DATA73CFG  0xf169
+#define F0900_DATA73_OPD  0xf1690080
+#define F0900_DATA73_CONFIG  0xf169007e
+#define F0900_DATA73_XOR  0xf1690001
+
+/*FSKTFC2*/
+#define R0900_FSKTFC2  0xf170
+#define F0900_FSKT_KMOD  0xf17000fc
+#define F0900_FSKT_CAR2  0xf1700003
+
+/*FSKTFC1*/
+#define R0900_FSKTFC1  0xf171
+#define F0900_FSKT_CAR1  0xf17100ff
+
+/*FSKTFC0*/
+#define R0900_FSKTFC0  0xf172
+#define F0900_FSKT_CAR0  0xf17200ff
+
+/*FSKTDELTAF1*/
+#define R0900_FSKTDELTAF1  0xf173
+#define F0900_FSKT_DELTAF1  0xf173000f
+
+/*FSKTDELTAF0*/
+#define R0900_FSKTDELTAF0  0xf174
+#define F0900_FSKT_DELTAF0  0xf17400ff
+
+/*FSKTCTRL*/
+#define R0900_FSKTCTRL  0xf175
+#define F0900_FSKT_EN_SGN  0xf1750040
+#define F0900_FSKT_MOD_SGN  0xf1750020
+#define F0900_FSKT_MOD_EN  0xf175001c
+#define F0900_FSKT_DACMODE  0xf1750003
+
+/*FSKRFC2*/
+#define R0900_FSKRFC2  0xf176
+#define F0900_FSKR_DETSGN  0xf1760040
+#define F0900_FSKR_OUTSGN  0xf1760020
+#define F0900_FSKR_KAGC  0xf176001c
+#define F0900_FSKR_CAR2  0xf1760003
+
+/*FSKRFC1*/
+#define R0900_FSKRFC1  0xf177
+#define F0900_FSKR_CAR1  0xf17700ff
+
+/*FSKRFC0*/
+#define R0900_FSKRFC0  0xf178
+#define F0900_FSKR_CAR0  0xf17800ff
+
+/*FSKRK1*/
+#define R0900_FSKRK1  0xf179
+#define F0900_FSKR_K1_EXP  0xf17900e0
+#define F0900_FSKR_K1_MANT  0xf179001f
+
+/*FSKRK2*/
+#define R0900_FSKRK2  0xf17a
+#define F0900_FSKR_K2_EXP  0xf17a00e0
+#define F0900_FSKR_K2_MANT  0xf17a001f
+
+/*FSKRAGCR*/
+#define R0900_FSKRAGCR  0xf17b
+#define F0900_FSKR_OUTCTL  0xf17b00c0
+#define F0900_FSKR_AGC_REF  0xf17b003f
+
+/*FSKRAGC*/
+#define R0900_FSKRAGC  0xf17c
+#define F0900_FSKR_AGC_ACCU  0xf17c00ff
+
+/*FSKRALPHA*/
+#define R0900_FSKRALPHA  0xf17d
+#define F0900_FSKR_ALPHA_EXP  0xf17d001c
+#define F0900_FSKR_ALPHA_M  0xf17d0003
+
+/*FSKRPLTH1*/
+#define R0900_FSKRPLTH1  0xf17e
+#define F0900_FSKR_BETA  0xf17e00f0
+#define F0900_FSKR_PLL_TRESH1  0xf17e000f
+
+/*FSKRPLTH0*/
+#define R0900_FSKRPLTH0  0xf17f
+#define F0900_FSKR_PLL_TRESH0  0xf17f00ff
+
+/*FSKRDF1*/
+#define R0900_FSKRDF1  0xf180
+#define F0900_FSKR_OUT  0xf1800080
+#define F0900_FSKR_DELTAF1  0xf180001f
+
+/*FSKRDF0*/
+#define R0900_FSKRDF0  0xf181
+#define F0900_FSKR_DELTAF0  0xf18100ff
+
+/*FSKRSTEPP*/
+#define R0900_FSKRSTEPP  0xf182
+#define F0900_FSKR_STEP_PLUS  0xf18200ff
+
+/*FSKRSTEPM*/
+#define R0900_FSKRSTEPM  0xf183
+#define F0900_FSKR_STEP_MINUS  0xf18300ff
+
+/*FSKRDET1*/
+#define R0900_FSKRDET1  0xf184
+#define F0900_FSKR_DETECT  0xf1840080
+#define F0900_FSKR_CARDET_ACCU1  0xf184000f
+
+/*FSKRDET0*/
+#define R0900_FSKRDET0  0xf185
+#define F0900_FSKR_CARDET_ACCU0  0xf18500ff
+
+/*FSKRDTH1*/
+#define R0900_FSKRDTH1  0xf186
+#define F0900_FSKR_CARLOSS_THRESH1  0xf18600f0
+#define F0900_FSKR_CARDET_THRESH1  0xf186000f
+
+/*FSKRDTH0*/
+#define R0900_FSKRDTH0  0xf187
+#define F0900_FSKR_CARDET_THRESH0  0xf18700ff
+
+/*FSKRLOSS*/
+#define R0900_FSKRLOSS  0xf188
+#define F0900_FSKR_CARLOSS_THRESH0  0xf18800ff
+
+/*P2_DISTXCTL*/
+#define R0900_P2_DISTXCTL  0xf190
+#define F0900_P2_TIM_OFF  0xf1900080
+#define F0900_P2_DISEQC_RESET  0xf1900040
+#define F0900_P2_TIM_CMD  0xf1900030
+#define F0900_P2_DIS_PRECHARGE  0xf1900008
+#define F0900_P2_DISTX_MODE  0xf1900007
+
+/*P2_DISRXCTL*/
+#define R0900_P2_DISRXCTL  0xf191
+#define F0900_P2_RECEIVER_ON  0xf1910080
+#define F0900_P2_IGNO_SHORT22K  0xf1910040
+#define F0900_P2_ONECHIP_TRX  0xf1910020
+#define F0900_P2_EXT_ENVELOP  0xf1910010
+#define F0900_P2_PIN_SELECT  0xf191000c
+#define F0900_P2_IRQ_RXEND  0xf1910002
+#define F0900_P2_IRQ_4NBYTES  0xf1910001
+
+/*P2_DISRX_ST0*/
+#define R0900_P2_DISRX_ST0  0xf194
+#define F0900_P2_RX_END  0xf1940080
+#define F0900_P2_RX_ACTIVE  0xf1940040
+#define F0900_P2_SHORT_22KHZ  0xf1940020
+#define F0900_P2_CONT_TONE  0xf1940010
+#define F0900_P2_FIFO_4BREADY  0xf1940008
+#define F0900_P2_FIFO_EMPTY  0xf1940004
+#define F0900_P2_ABORT_DISRX  0xf1940001
+
+/*P2_DISRX_ST1*/
+#define R0900_P2_DISRX_ST1  0xf195
+#define F0900_P2_RX_FAIL  0xf1950080
+#define F0900_P2_FIFO_PARITYFAIL  0xf1950040
+#define F0900_P2_RX_NONBYTE  0xf1950020
+#define F0900_P2_FIFO_OVERFLOW  0xf1950010
+#define F0900_P2_FIFO_BYTENBR  0xf195000f
+
+/*P2_DISRXDATA*/
+#define R0900_P2_DISRXDATA  0xf196
+#define F0900_P2_DISRX_DATA  0xf19600ff
+
+/*P2_DISTXDATA*/
+#define R0900_P2_DISTXDATA  0xf197
+#define F0900_P2_DISEQC_FIFO  0xf19700ff
+
+/*P2_DISTXSTATUS*/
+#define R0900_P2_DISTXSTATUS  0xf198
+#define F0900_P2_TX_FAIL  0xf1980080
+#define F0900_P2_FIFO_FULL  0xf1980040
+#define F0900_P2_TX_IDLE  0xf1980020
+#define F0900_P2_GAP_BURST  0xf1980010
+#define F0900_P2_TXFIFO_BYTES  0xf198000f
+
+/*P2_F22TX*/
+#define R0900_P2_F22TX  0xf199
+#define F0900_P2_F22_REG  0xf19900ff
+
+/*P2_F22RX*/
+#define R0900_P2_F22RX  0xf19a
+#define F0900_P2_F22RX_REG  0xf19a00ff
+
+/*P2_ACRPRESC*/
+#define R0900_P2_ACRPRESC  0xf19c
+#define F0900_P2_ACR_CODFRDY  0xf19c0008
+#define F0900_P2_ACR_PRESC  0xf19c0007
+
+/*P2_ACRDIV*/
+#define R0900_P2_ACRDIV  0xf19d
+#define F0900_P2_ACR_DIV  0xf19d00ff
+
+/*P1_DISTXCTL*/
+#define R0900_P1_DISTXCTL  0xf1a0
+#define F0900_P1_TIM_OFF  0xf1a00080
+#define F0900_P1_DISEQC_RESET  0xf1a00040
+#define F0900_P1_TIM_CMD  0xf1a00030
+#define F0900_P1_DIS_PRECHARGE  0xf1a00008
+#define F0900_P1_DISTX_MODE  0xf1a00007
+
+/*P1_DISRXCTL*/
+#define R0900_P1_DISRXCTL  0xf1a1
+#define F0900_P1_RECEIVER_ON  0xf1a10080
+#define F0900_P1_IGNO_SHORT22K  0xf1a10040
+#define F0900_P1_ONECHIP_TRX  0xf1a10020
+#define F0900_P1_EXT_ENVELOP  0xf1a10010
+#define F0900_P1_PIN_SELECT  0xf1a1000c
+#define F0900_P1_IRQ_RXEND  0xf1a10002
+#define F0900_P1_IRQ_4NBYTES  0xf1a10001
+
+/*P1_DISRX_ST0*/
+#define R0900_P1_DISRX_ST0  0xf1a4
+#define F0900_P1_RX_END  0xf1a40080
+#define F0900_P1_RX_ACTIVE  0xf1a40040
+#define F0900_P1_SHORT_22KHZ  0xf1a40020
+#define F0900_P1_CONT_TONE  0xf1a40010
+#define F0900_P1_FIFO_4BREADY  0xf1a40008
+#define F0900_P1_FIFO_EMPTY  0xf1a40004
+#define F0900_P1_ABORT_DISRX  0xf1a40001
+
+/*P1_DISRX_ST1*/
+#define R0900_P1_DISRX_ST1  0xf1a5
+#define F0900_P1_RX_FAIL  0xf1a50080
+#define F0900_P1_FIFO_PARITYFAIL  0xf1a50040
+#define F0900_P1_RX_NONBYTE  0xf1a50020
+#define F0900_P1_FIFO_OVERFLOW  0xf1a50010
+#define F0900_P1_FIFO_BYTENBR  0xf1a5000f
+
+/*P1_DISRXDATA*/
+#define R0900_P1_DISRXDATA  0xf1a6
+#define F0900_P1_DISRX_DATA  0xf1a600ff
+
+/*P1_DISTXDATA*/
+#define R0900_P1_DISTXDATA  0xf1a7
+#define F0900_P1_DISEQC_FIFO  0xf1a700ff
+
+/*P1_DISTXSTATUS*/
+#define R0900_P1_DISTXSTATUS  0xf1a8
+#define F0900_P1_TX_FAIL  0xf1a80080
+#define F0900_P1_FIFO_FULL  0xf1a80040
+#define F0900_P1_TX_IDLE  0xf1a80020
+#define F0900_P1_GAP_BURST  0xf1a80010
+#define F0900_P1_TXFIFO_BYTES  0xf1a8000f
+
+/*P1_F22TX*/
+#define R0900_P1_F22TX  0xf1a9
+#define F0900_P1_F22_REG  0xf1a900ff
+
+/*P1_F22RX*/
+#define R0900_P1_F22RX  0xf1aa
+#define F0900_P1_F22RX_REG  0xf1aa00ff
+
+/*P1_ACRPRESC*/
+#define R0900_P1_ACRPRESC  0xf1ac
+#define F0900_P1_ACR_CODFRDY  0xf1ac0008
+#define F0900_P1_ACR_PRESC  0xf1ac0007
+
+/*P1_ACRDIV*/
+#define R0900_P1_ACRDIV  0xf1ad
+#define F0900_P1_ACR_DIV  0xf1ad00ff
+
+/*NCOARSE*/
+#define R0900_NCOARSE  0xf1b3
+#define F0900_M_DIV  0xf1b300ff
+
+/*SYNTCTRL*/
+#define R0900_SYNTCTRL  0xf1b6
+#define F0900_STANDBY  0xf1b60080
+#define F0900_BYPASSPLLCORE  0xf1b60040
+#define F0900_SELX1RATIO  0xf1b60020
+#define F0900_I2C_TUD  0xf1b60010
+#define F0900_STOP_PLL  0xf1b60008
+#define F0900_BYPASSPLLFSK  0xf1b60004
+#define F0900_SELOSCI  0xf1b60002
+#define F0900_BYPASSPLLADC  0xf1b60001
+
+/*FILTCTRL*/
+#define R0900_FILTCTRL  0xf1b7
+#define F0900_INV_CLK135  0xf1b70080
+#define F0900_PERM_BYPDIS  0xf1b70040
+#define F0900_SEL_FSKCKDIV  0xf1b70004
+#define F0900_INV_CLKFSK  0xf1b70002
+#define F0900_BYPASS_APPLI  0xf1b70001
+
+/*PLLSTAT*/
+#define R0900_PLLSTAT  0xf1b8
+#define F0900_ACM_SEL  0xf1b80080
+#define F0900_DTV_SEL  0xf1b80040
+#define F0900_PLLLOCK  0xf1b80001
+
+/*STOPCLK1*/
+#define R0900_STOPCLK1  0xf1c2
+#define F0900_STOP_CLKPKDT2  0xf1c20040
+#define F0900_STOP_CLKPKDT1  0xf1c20020
+#define F0900_STOP_CLKFEC  0xf1c20010
+#define F0900_STOP_CLKADCI2  0xf1c20008
+#define F0900_INV_CLKADCI2  0xf1c20004
+#define F0900_STOP_CLKADCI1  0xf1c20002
+#define F0900_INV_CLKADCI1  0xf1c20001
+
+/*STOPCLK2*/
+#define R0900_STOPCLK2  0xf1c3
+#define F0900_STOP_CLKSAMP2  0xf1c30010
+#define F0900_STOP_CLKSAMP1  0xf1c30008
+#define F0900_STOP_CLKVIT2  0xf1c30004
+#define F0900_STOP_CLKVIT1  0xf1c30002
+#define F0900_STOP_CLKTS  0xf1c30001
+
+/*TSTTNR0*/
+#define R0900_TSTTNR0  0xf1df
+#define F0900_SEL_FSK  0xf1df0080
+#define F0900_FSK_PON  0xf1df0004
+#define F0900_FSK_OPENLOOP  0xf1df0002
+
+/*TSTTNR1*/
+#define R0900_TSTTNR1  0xf1e0
+#define F0900_BYPASS_ADC1  0xf1e00080
+#define F0900_INVADC1_CKOUT  0xf1e00040
+#define F0900_SELIQSRC1  0xf1e00030
+#define F0900_ADC1_PON  0xf1e00002
+#define F0900_ADC1_INMODE  0xf1e00001
+
+/*TSTTNR2*/
+#define R0900_TSTTNR2  0xf1e1
+#define F0900_DISEQC1_PON  0xf1e10020
+#define F0900_DISEQC1_TEST  0xf1e1001f
+
+/*TSTTNR3*/
+#define R0900_TSTTNR3  0xf1e2
+#define F0900_BYPASS_ADC2  0xf1e20080
+#define F0900_INVADC2_CKOUT  0xf1e20040
+#define F0900_SELIQSRC2  0xf1e20030
+#define F0900_ADC2_PON  0xf1e20002
+#define F0900_ADC2_INMODE  0xf1e20001
+
+/*TSTTNR4*/
+#define R0900_TSTTNR4  0xf1e3
+#define F0900_DISEQC2_PON  0xf1e30020
+#define F0900_DISEQC2_TEST  0xf1e3001f
+
+/*P2_IQCONST*/
+#define R0900_P2_IQCONST  0xf200
+#define F0900_P2_CONSTEL_SELECT  0xf2000060
+#define F0900_P2_IQSYMB_SEL  0xf200001f
+
+/*P2_NOSCFG*/
+#define R0900_P2_NOSCFG  0xf201
+#define F0900_P2_DUMMYPL_NOSDATA  0xf2010020
+#define F0900_P2_NOSPLH_BETA  0xf2010018
+#define F0900_P2_NOSDATA_BETA  0xf2010007
+
+/*P2_ISYMB*/
+#define R0900_P2_ISYMB  0xf202
+#define F0900_P2_I_SYMBOL  0xf20201ff
+
+/*P2_QSYMB*/
+#define R0900_P2_QSYMB  0xf203
+#define F0900_P2_Q_SYMBOL  0xf20301ff
+
+/*P2_AGC1CFG*/
+#define R0900_P2_AGC1CFG  0xf204
+#define F0900_P2_DC_FROZEN  0xf2040080
+#define F0900_P2_DC_CORRECT  0xf2040040
+#define F0900_P2_AMM_FROZEN  0xf2040020
+#define F0900_P2_AMM_CORRECT  0xf2040010
+#define F0900_P2_QUAD_FROZEN  0xf2040008
+#define F0900_P2_QUAD_CORRECT  0xf2040004
+#define F0900_P2_DCCOMP_SLOW  0xf2040002
+#define F0900_P2_IQMISM_SLOW  0xf2040001
+
+/*P2_AGC1CN*/
+#define R0900_P2_AGC1CN  0xf206
+#define F0900_P2_AGC1_LOCKED  0xf2060080
+#define F0900_P2_AGC1_OVERFLOW  0xf2060040
+#define F0900_P2_AGC1_NOSLOWLK  0xf2060020
+#define F0900_P2_AGC1_MINPOWER  0xf2060010
+#define F0900_P2_AGCOUT_FAST  0xf2060008
+#define F0900_P2_AGCIQ_BETA  0xf2060007
+
+/*P2_AGC1REF*/
+#define R0900_P2_AGC1REF  0xf207
+#define F0900_P2_AGCIQ_REF  0xf20700ff
+
+/*P2_IDCCOMP*/
+#define R0900_P2_IDCCOMP  0xf208
+#define F0900_P2_IAVERAGE_ADJ  0xf20801ff
+
+/*P2_QDCCOMP*/
+#define R0900_P2_QDCCOMP  0xf209
+#define F0900_P2_QAVERAGE_ADJ  0xf20901ff
+
+/*P2_POWERI*/
+#define R0900_P2_POWERI  0xf20a
+#define F0900_P2_POWER_I  0xf20a00ff
+
+/*P2_POWERQ*/
+#define R0900_P2_POWERQ  0xf20b
+#define F0900_P2_POWER_Q  0xf20b00ff
+
+/*P2_AGC1AMM*/
+#define R0900_P2_AGC1AMM  0xf20c
+#define F0900_P2_AMM_VALUE  0xf20c00ff
+
+/*P2_AGC1QUAD*/
+#define R0900_P2_AGC1QUAD  0xf20d
+#define F0900_P2_QUAD_VALUE  0xf20d01ff
+
+/*P2_AGCIQIN1*/
+#define R0900_P2_AGCIQIN1  0xf20e
+#define F0900_P2_AGCIQ_VALUE1  0xf20e00ff
+
+/*P2_AGCIQIN0*/
+#define R0900_P2_AGCIQIN0  0xf20f
+#define F0900_P2_AGCIQ_VALUE0  0xf20f00ff
+
+/*P2_DEMOD*/
+#define R0900_P2_DEMOD  0xf210
+#define F0900_P2_DEMOD_STOP  0xf2100040
+#define F0900_P2_SPECINV_CONTROL  0xf2100030
+#define F0900_P2_FORCE_ENASAMP  0xf2100008
+#define F0900_P2_MANUAL_ROLLOFF  0xf2100004
+#define F0900_P2_ROLLOFF_CONTROL  0xf2100003
+
+/*P2_DMDMODCOD*/
+#define R0900_P2_DMDMODCOD  0xf211
+#define F0900_P2_MANUAL_MODCOD  0xf2110080
+#define F0900_P2_DEMOD_MODCOD  0xf211007c
+#define F0900_P2_DEMOD_TYPE  0xf2110003
+
+/*P2_DSTATUS*/
+#define R0900_P2_DSTATUS  0xf212
+#define F0900_P2_CAR_LOCK  0xf2120080
+#define F0900_P2_TMGLOCK_QUALITY  0xf2120060
+#define F0900_P2_SDVBS1_ENABLE  0xf2120010
+#define F0900_P2_LOCK_DEFINITIF  0xf2120008
+#define F0900_P2_TIMING_IS_LOCKED  0xf2120004
+#define F0900_P2_COARSE_TMGLOCK  0xf2120002
+#define F0900_P2_COARSE_CARLOCK  0xf2120001
+
+/*P2_DSTATUS2*/
+#define R0900_P2_DSTATUS2  0xf213
+#define F0900_P2_DEMOD_DELOCK  0xf2130080
+#define F0900_P2_DEMOD_TIMEOUT  0xf2130040
+#define F0900_P2_MODCODRQ_SYNCTAG  0xf2130020
+#define F0900_P2_POLYPH_SATEVENT  0xf2130010
+#define F0900_P2_AGC1_NOSIGNALACK  0xf2130008
+#define F0900_P2_AGC2_OVERFLOW  0xf2130004
+#define F0900_P2_CFR_OVERFLOW  0xf2130002
+#define F0900_P2_GAMMA_OVERUNDER  0xf2130001
+
+/*P2_DMDCFGMD*/
+#define R0900_P2_DMDCFGMD  0xf214
+#define F0900_P2_DVBS2_ENABLE  0xf2140080
+#define F0900_P2_DVBS1_ENABLE  0xf2140040
+#define F0900_P2_CFR_AUTOSCAN  0xf2140020
+#define F0900_P2_SCAN_ENABLE  0xf2140010
+#define F0900_P2_TUN_AUTOSCAN  0xf2140008
+#define F0900_P2_NOFORCE_RELOCK  0xf2140004
+#define F0900_P2_TUN_RNG  0xf2140003
+
+/*P2_DMDCFG2*/
+#define R0900_P2_DMDCFG2  0xf215
+#define F0900_P2_AGC1_WAITLOCK  0xf2150080
+#define F0900_P2_S1S2_SEQUENTIAL  0xf2150040
+#define F0900_P2_OVERFLOW_TIMEOUT  0xf2150020
+#define F0900_P2_SCANFAIL_TIMEOUT  0xf2150010
+#define F0900_P2_DMDTOUT_BACK  0xf2150008
+#define F0900_P2_CARLOCK_S1ENABLE  0xf2150004
+#define F0900_P2_COARSE_LK3MODE  0xf2150002
+#define F0900_P2_COARSE_LK2MODE  0xf2150001
+
+/*P2_DMDISTATE*/
+#define R0900_P2_DMDISTATE  0xf216
+#define F0900_P2_I2C_NORESETDMODE  0xf2160080
+#define F0900_P2_FORCE_ETAPED  0xf2160040
+#define F0900_P2_SDMDRST_DIRCLK  0xf2160020
+#define F0900_P2_I2C_DEMOD_MODE  0xf216001f
+
+/*P2_DMDT0M*/
+#define R0900_P2_DMDT0M  0xf217
+#define F0900_P2_DMDT0_MIN  0xf21700ff
+
+/*P2_DMDSTATE*/
+#define R0900_P2_DMDSTATE  0xf21b
+#define F0900_P2_DEMOD_LOCKED  0xf21b0080
+#define F0900_P2_HEADER_MODE  0xf21b0060
+#define F0900_P2_DEMOD_MODE  0xf21b001f
+
+/*P2_DMDFLYW*/
+#define R0900_P2_DMDFLYW  0xf21c
+#define F0900_P2_I2C_IRQVAL  0xf21c00f0
+#define F0900_P2_FLYWHEEL_CPT  0xf21c000f
+
+/*P2_DSTATUS3*/
+#define R0900_P2_DSTATUS3  0xf21d
+#define F0900_P2_CFR_ZIGZAG  0xf21d0080
+#define F0900_P2_DEMOD_CFGMODE  0xf21d0060
+#define F0900_P2_GAMMA_LOWBAUDRATE  0xf21d0010
+#define F0900_P2_RELOCK_MODE  0xf21d0008
+#define F0900_P2_DEMOD_FAIL  0xf21d0004
+#define F0900_P2_ETAPE1A_DVBXMEM  0xf21d0003
+
+/*P2_DMDCFG3*/
+#define R0900_P2_DMDCFG3  0xf21e
+#define F0900_P2_DVBS1_TMGWAIT  0xf21e0080
+#define F0900_P2_NO_BWCENTERING  0xf21e0040
+#define F0900_P2_INV_SEQSRCH  0xf21e0020
+#define F0900_P2_DIS_SFRUPLOW_TRK  0xf21e0010
+#define F0900_P2_NOSTOP_FIFOFULL  0xf21e0008
+#define F0900_P2_LOCKTIME_MODE  0xf21e0007
+
+/*P2_DMDCFG4*/
+#define R0900_P2_DMDCFG4  0xf21f
+#define F0900_P2_TUNER_NRELAUNCH  0xf21f0008
+#define F0900_P2_DIS_CLKENABLE  0xf21f0004
+#define F0900_P2_DIS_HDRDIVLOCK  0xf21f0002
+#define F0900_P2_NO_TNRWBINIT  0xf21f0001
+
+/*P2_CORRELMANT*/
+#define R0900_P2_CORRELMANT  0xf220
+#define F0900_P2_CORREL_MANT  0xf22000ff
+
+/*P2_CORRELABS*/
+#define R0900_P2_CORRELABS  0xf221
+#define F0900_P2_CORREL_ABS  0xf22100ff
+
+/*P2_CORRELEXP*/
+#define R0900_P2_CORRELEXP  0xf222
+#define F0900_P2_CORREL_ABSEXP  0xf22200f0
+#define F0900_P2_CORREL_EXP  0xf222000f
+
+/*P2_PLHMODCOD*/
+#define R0900_P2_PLHMODCOD  0xf224
+#define F0900_P2_SPECINV_DEMOD  0xf2240080
+#define F0900_P2_PLH_MODCOD  0xf224007c
+#define F0900_P2_PLH_TYPE  0xf2240003
+
+/*P2_AGCK32*/
+#define R0900_P2_AGCK32  0xf22b
+#define F0900_P2_R3ADJOFF_32APSK  0xf22b0080
+#define F0900_P2_R2ADJOFF_32APSK  0xf22b0040
+#define F0900_P2_R1ADJOFF_32APSK  0xf22b0020
+#define F0900_P2_RADJ_32APSK  0xf22b001f
+
+/*P2_AGC2O*/
+#define R0900_P2_AGC2O  0xf22c
+#define F0900_P2_AGC2REF_ADJUSTING  0xf22c0080
+#define F0900_P2_AGC2_COARSEFAST  0xf22c0040
+#define F0900_P2_AGC2_LKSQRT  0xf22c0020
+#define F0900_P2_AGC2_LKMODE  0xf22c0010
+#define F0900_P2_AGC2_LKEQUA  0xf22c0008
+#define F0900_P2_AGC2_COEF  0xf22c0007
+
+/*P2_AGC2REF*/
+#define R0900_P2_AGC2REF  0xf22d
+#define F0900_P2_AGC2_REF  0xf22d00ff
+
+/*P2_AGC1ADJ*/
+#define R0900_P2_AGC1ADJ  0xf22e
+#define F0900_P2_AGC1ADJ_MANUAL  0xf22e0080
+#define F0900_P2_AGC1_ADJUSTED  0xf22e017f
+
+/*P2_AGC2I1*/
+#define R0900_P2_AGC2I1  0xf236
+#define F0900_P2_AGC2_INTEGRATOR1  0xf23600ff
+
+/*P2_AGC2I0*/
+#define R0900_P2_AGC2I0  0xf237
+#define F0900_P2_AGC2_INTEGRATOR0  0xf23700ff
+
+/*P2_CARCFG*/
+#define R0900_P2_CARCFG  0xf238
+#define F0900_P2_CFRUPLOW_AUTO  0xf2380080
+#define F0900_P2_CFRUPLOW_TEST  0xf2380040
+#define F0900_P2_EN_CAR2CENTER  0xf2380020
+#define F0900_P2_CARHDR_NODIV8  0xf2380010
+#define F0900_P2_I2C_ROTA  0xf2380008
+#define F0900_P2_ROTAON  0xf2380004
+#define F0900_P2_PH_DET_ALGO  0xf2380003
+
+/*P2_ACLC*/
+#define R0900_P2_ACLC  0xf239
+#define F0900_P2_STOP_S2ALPHA  0xf23900c0
+#define F0900_P2_CAR_ALPHA_MANT  0xf2390030
+#define F0900_P2_CAR_ALPHA_EXP  0xf239000f
+
+/*P2_BCLC*/
+#define R0900_P2_BCLC  0xf23a
+#define F0900_P2_STOP_S2BETA  0xf23a00c0
+#define F0900_P2_CAR_BETA_MANT  0xf23a0030
+#define F0900_P2_CAR_BETA_EXP  0xf23a000f
+
+/*P2_CARFREQ*/
+#define R0900_P2_CARFREQ  0xf23d
+#define F0900_P2_KC_COARSE_EXP  0xf23d00f0
+#define F0900_P2_BETA_FREQ  0xf23d000f
+
+/*P2_CARHDR*/
+#define R0900_P2_CARHDR  0xf23e
+#define F0900_P2_K_FREQ_HDR  0xf23e00ff
+
+/*P2_LDT*/
+#define R0900_P2_LDT  0xf23f
+#define F0900_P2_CARLOCK_THRES  0xf23f01ff
+
+/*P2_LDT2*/
+#define R0900_P2_LDT2  0xf240
+#define F0900_P2_CARLOCK_THRES2  0xf24001ff
+
+/*P2_CFRICFG*/
+#define R0900_P2_CFRICFG  0xf241
+#define F0900_P2_CFRINIT_UNVALRNG  0xf2410080
+#define F0900_P2_CFRINIT_LUNVALCPT  0xf2410040
+#define F0900_P2_CFRINIT_ABORTDBL  0xf2410020
+#define F0900_P2_CFRINIT_ABORTPRED  0xf2410010
+#define F0900_P2_CFRINIT_UNVALSKIP  0xf2410008
+#define F0900_P2_CFRINIT_CSTINC  0xf2410004
+#define F0900_P2_NEG_CFRSTEP  0xf2410001
+
+/*P2_CFRUP1*/
+#define R0900_P2_CFRUP1  0xf242
+#define F0900_P2_CFR_UP1  0xf24201ff
+
+/*P2_CFRUP0*/
+#define R0900_P2_CFRUP0  0xf243
+#define F0900_P2_CFR_UP0  0xf24300ff
+
+/*P2_CFRLOW1*/
+#define R0900_P2_CFRLOW1  0xf246
+#define F0900_P2_CFR_LOW1  0xf24601ff
+
+/*P2_CFRLOW0*/
+#define R0900_P2_CFRLOW0  0xf247
+#define F0900_P2_CFR_LOW0  0xf24700ff
+
+/*P2_CFRINIT1*/
+#define R0900_P2_CFRINIT1  0xf248
+#define F0900_P2_CFR_INIT1  0xf24801ff
+
+/*P2_CFRINIT0*/
+#define R0900_P2_CFRINIT0  0xf249
+#define F0900_P2_CFR_INIT0  0xf24900ff
+
+/*P2_CFRINC1*/
+#define R0900_P2_CFRINC1  0xf24a
+#define F0900_P2_MANUAL_CFRINC  0xf24a0080
+#define F0900_P2_CFR_INC1  0xf24a017f
+
+/*P2_CFRINC0*/
+#define R0900_P2_CFRINC0  0xf24b
+#define F0900_P2_CFR_INC0  0xf24b00f0
+
+/*P2_CFR2*/
+#define R0900_P2_CFR2  0xf24c
+#define F0900_P2_CAR_FREQ2  0xf24c01ff
+
+/*P2_CFR1*/
+#define R0900_P2_CFR1  0xf24d
+#define F0900_P2_CAR_FREQ1  0xf24d00ff
+
+/*P2_CFR0*/
+#define R0900_P2_CFR0  0xf24e
+#define F0900_P2_CAR_FREQ0  0xf24e00ff
+
+/*P2_LDI*/
+#define R0900_P2_LDI  0xf24f
+#define F0900_P2_LOCK_DET_INTEGR  0xf24f01ff
+
+/*P2_TMGCFG*/
+#define R0900_P2_TMGCFG  0xf250
+#define F0900_P2_TMGLOCK_BETA  0xf25000c0
+#define F0900_P2_NOTMG_GROUPDELAY  0xf2500020
+#define F0900_P2_DO_TIMING_CORR  0xf2500010
+#define F0900_P2_MANUAL_SCAN  0xf250000c
+#define F0900_P2_TMG_MINFREQ  0xf2500003
+
+/*P2_RTC*/
+#define R0900_P2_RTC  0xf251
+#define F0900_P2_TMGALPHA_EXP  0xf25100f0
+#define F0900_P2_TMGBETA_EXP  0xf251000f
+
+/*P2_RTCS2*/
+#define R0900_P2_RTCS2  0xf252
+#define F0900_P2_TMGALPHAS2_EXP  0xf25200f0
+#define F0900_P2_TMGBETAS2_EXP  0xf252000f
+
+/*P2_TMGTHRISE*/
+#define R0900_P2_TMGTHRISE  0xf253
+#define F0900_P2_TMGLOCK_THRISE  0xf25300ff
+
+/*P2_TMGTHFALL*/
+#define R0900_P2_TMGTHFALL  0xf254
+#define F0900_P2_TMGLOCK_THFALL  0xf25400ff
+
+/*P2_SFRUPRATIO*/
+#define R0900_P2_SFRUPRATIO  0xf255
+#define F0900_P2_SFR_UPRATIO  0xf25500ff
+
+/*P2_SFRLOWRATIO*/
+#define R0900_P2_SFRLOWRATIO  0xf256
+#define F0900_P2_SFR_LOWRATIO  0xf25600ff
+
+/*P2_KREFTMG*/
+#define R0900_P2_KREFTMG  0xf258
+#define F0900_P2_KREF_TMG  0xf25800ff
+
+/*P2_SFRSTEP*/
+#define R0900_P2_SFRSTEP  0xf259
+#define F0900_P2_SFR_SCANSTEP  0xf25900f0
+#define F0900_P2_SFR_CENTERSTEP  0xf259000f
+
+/*P2_TMGCFG2*/
+#define R0900_P2_TMGCFG2  0xf25a
+#define F0900_P2_DIS_AUTOSAMP  0xf25a0008
+#define F0900_P2_SCANINIT_QUART  0xf25a0004
+#define F0900_P2_NOTMG_DVBS1DERAT  0xf25a0002
+#define F0900_P2_SFRRATIO_FINE  0xf25a0001
+
+/*P2_SFRINIT1*/
+#define R0900_P2_SFRINIT1  0xf25e
+#define F0900_P2_SFR_INIT1  0xf25e00ff
+
+/*P2_SFRINIT0*/
+#define R0900_P2_SFRINIT0  0xf25f
+#define F0900_P2_SFR_INIT0  0xf25f00ff
+
+/*P2_SFRUP1*/
+#define R0900_P2_SFRUP1  0xf260
+#define F0900_P2_AUTO_GUP  0xf2600080
+#define F0900_P2_SYMB_FREQ_UP1  0xf260007f
+
+/*P2_SFRUP0*/
+#define R0900_P2_SFRUP0  0xf261
+#define F0900_P2_SYMB_FREQ_UP0  0xf26100ff
+
+/*P2_SFRLOW1*/
+#define R0900_P2_SFRLOW1  0xf262
+#define F0900_P2_AUTO_GLOW  0xf2620080
+#define F0900_P2_SYMB_FREQ_LOW1  0xf262007f
+
+/*P2_SFRLOW0*/
+#define R0900_P2_SFRLOW0  0xf263
+#define F0900_P2_SYMB_FREQ_LOW0  0xf26300ff
+
+/*P2_SFR3*/
+#define R0900_P2_SFR3  0xf264
+#define F0900_P2_SYMB_FREQ3  0xf26400ff
+
+/*P2_SFR2*/
+#define R0900_P2_SFR2  0xf265
+#define F0900_P2_SYMB_FREQ2  0xf26500ff
+
+/*P2_SFR1*/
+#define R0900_P2_SFR1  0xf266
+#define F0900_P2_SYMB_FREQ1  0xf26600ff
+
+/*P2_SFR0*/
+#define R0900_P2_SFR0  0xf267
+#define F0900_P2_SYMB_FREQ0  0xf26700ff
+
+/*P2_TMGREG2*/
+#define R0900_P2_TMGREG2  0xf268
+#define F0900_P2_TMGREG2  0xf26800ff
+
+/*P2_TMGREG1*/
+#define R0900_P2_TMGREG1  0xf269
+#define F0900_P2_TMGREG1  0xf26900ff
+
+/*P2_TMGREG0*/
+#define R0900_P2_TMGREG0  0xf26a
+#define F0900_P2_TMGREG0  0xf26a00ff
+
+/*P2_TMGLOCK1*/
+#define R0900_P2_TMGLOCK1  0xf26b
+#define F0900_P2_TMGLOCK_LEVEL1  0xf26b01ff
+
+/*P2_TMGLOCK0*/
+#define R0900_P2_TMGLOCK0  0xf26c
+#define F0900_P2_TMGLOCK_LEVEL0  0xf26c00ff
+
+/*P2_TMGOBS*/
+#define R0900_P2_TMGOBS  0xf26d
+#define F0900_P2_ROLLOFF_STATUS  0xf26d00c0
+#define F0900_P2_SCAN_SIGN  0xf26d0030
+#define F0900_P2_TMG_SCANNING  0xf26d0008
+#define F0900_P2_CHCENTERING_MODE  0xf26d0004
+#define F0900_P2_TMG_SCANFAIL  0xf26d0002
+
+/*P2_EQUALCFG*/
+#define R0900_P2_EQUALCFG  0xf26f
+#define F0900_P2_NOTMG_NEGALWAIT  0xf26f0080
+#define F0900_P2_EQUAL_ON  0xf26f0040
+#define F0900_P2_SEL_EQUALCOR  0xf26f0038
+#define F0900_P2_MU_EQUALDFE  0xf26f0007
+
+/*P2_EQUAI1*/
+#define R0900_P2_EQUAI1  0xf270
+#define F0900_P2_EQUA_ACCI1  0xf27001ff
+
+/*P2_EQUAQ1*/
+#define R0900_P2_EQUAQ1  0xf271
+#define F0900_P2_EQUA_ACCQ1  0xf27101ff
+
+/*P2_EQUAI2*/
+#define R0900_P2_EQUAI2  0xf272
+#define F0900_P2_EQUA_ACCI2  0xf27201ff
+
+/*P2_EQUAQ2*/
+#define R0900_P2_EQUAQ2  0xf273
+#define F0900_P2_EQUA_ACCQ2  0xf27301ff
+
+/*P2_EQUAI3*/
+#define R0900_P2_EQUAI3  0xf274
+#define F0900_P2_EQUA_ACCI3  0xf27401ff
+
+/*P2_EQUAQ3*/
+#define R0900_P2_EQUAQ3  0xf275
+#define F0900_P2_EQUA_ACCQ3  0xf27501ff
+
+/*P2_EQUAI4*/
+#define R0900_P2_EQUAI4  0xf276
+#define F0900_P2_EQUA_ACCI4  0xf27601ff
+
+/*P2_EQUAQ4*/
+#define R0900_P2_EQUAQ4  0xf277
+#define F0900_P2_EQUA_ACCQ4  0xf27701ff
+
+/*P2_EQUAI5*/
+#define R0900_P2_EQUAI5  0xf278
+#define F0900_P2_EQUA_ACCI5  0xf27801ff
+
+/*P2_EQUAQ5*/
+#define R0900_P2_EQUAQ5  0xf279
+#define F0900_P2_EQUA_ACCQ5  0xf27901ff
+
+/*P2_EQUAI6*/
+#define R0900_P2_EQUAI6  0xf27a
+#define F0900_P2_EQUA_ACCI6  0xf27a01ff
+
+/*P2_EQUAQ6*/
+#define R0900_P2_EQUAQ6  0xf27b
+#define F0900_P2_EQUA_ACCQ6  0xf27b01ff
+
+/*P2_EQUAI7*/
+#define R0900_P2_EQUAI7  0xf27c
+#define F0900_P2_EQUA_ACCI7  0xf27c01ff
+
+/*P2_EQUAQ7*/
+#define R0900_P2_EQUAQ7  0xf27d
+#define F0900_P2_EQUA_ACCQ7  0xf27d01ff
+
+/*P2_EQUAI8*/
+#define R0900_P2_EQUAI8  0xf27e
+#define F0900_P2_EQUA_ACCI8  0xf27e01ff
+
+/*P2_EQUAQ8*/
+#define R0900_P2_EQUAQ8  0xf27f
+#define F0900_P2_EQUA_ACCQ8  0xf27f01ff
+
+/*P2_NNOSDATAT1*/
+#define R0900_P2_NNOSDATAT1  0xf280
+#define F0900_P2_NOSDATAT_NORMED1  0xf28000ff
+
+/*P2_NNOSDATAT0*/
+#define R0900_P2_NNOSDATAT0  0xf281
+#define F0900_P2_NOSDATAT_NORMED0  0xf28100ff
+
+/*P2_NNOSDATA1*/
+#define R0900_P2_NNOSDATA1  0xf282
+#define F0900_P2_NOSDATA_NORMED1  0xf28200ff
+
+/*P2_NNOSDATA0*/
+#define R0900_P2_NNOSDATA0  0xf283
+#define F0900_P2_NOSDATA_NORMED0  0xf28300ff
+
+/*P2_NNOSPLHT1*/
+#define R0900_P2_NNOSPLHT1  0xf284
+#define F0900_P2_NOSPLHT_NORMED1  0xf28400ff
+
+/*P2_NNOSPLHT0*/
+#define R0900_P2_NNOSPLHT0  0xf285
+#define F0900_P2_NOSPLHT_NORMED0  0xf28500ff
+
+/*P2_NNOSPLH1*/
+#define R0900_P2_NNOSPLH1  0xf286
+#define F0900_P2_NOSPLH_NORMED1  0xf28600ff
+
+/*P2_NNOSPLH0*/
+#define R0900_P2_NNOSPLH0  0xf287
+#define F0900_P2_NOSPLH_NORMED0  0xf28700ff
+
+/*P2_NOSDATAT1*/
+#define R0900_P2_NOSDATAT1  0xf288
+#define F0900_P2_NOSDATAT_UNNORMED1  0xf28800ff
+
+/*P2_NOSDATAT0*/
+#define R0900_P2_NOSDATAT0  0xf289
+#define F0900_P2_NOSDATAT_UNNORMED0  0xf28900ff
+
+/*P2_NOSDATA1*/
+#define R0900_P2_NOSDATA1  0xf28a
+#define F0900_P2_NOSDATA_UNNORMED1  0xf28a00ff
+
+/*P2_NOSDATA0*/
+#define R0900_P2_NOSDATA0  0xf28b
+#define F0900_P2_NOSDATA_UNNORMED0  0xf28b00ff
+
+/*P2_NOSPLHT1*/
+#define R0900_P2_NOSPLHT1  0xf28c
+#define F0900_P2_NOSPLHT_UNNORMED1  0xf28c00ff
+
+/*P2_NOSPLHT0*/
+#define R0900_P2_NOSPLHT0  0xf28d
+#define F0900_P2_NOSPLHT_UNNORMED0  0xf28d00ff
+
+/*P2_NOSPLH1*/
+#define R0900_P2_NOSPLH1  0xf28e
+#define F0900_P2_NOSPLH_UNNORMED1  0xf28e00ff
+
+/*P2_NOSPLH0*/
+#define R0900_P2_NOSPLH0  0xf28f
+#define F0900_P2_NOSPLH_UNNORMED0  0xf28f00ff
+
+/*P2_CAR2CFG*/
+#define R0900_P2_CAR2CFG  0xf290
+#define F0900_P2_DESCRAMB_OFF  0xf2900080
+#define F0900_P2_PN4_SELECT  0xf2900040
+#define F0900_P2_CFR2_STOPDVBS1  0xf2900020
+#define F0900_P2_STOP_CFR2UPDATE  0xf2900010
+#define F0900_P2_STOP_NCO2UPDATE  0xf2900008
+#define F0900_P2_ROTA2ON  0xf2900004
+#define F0900_P2_PH_DET_ALGO2  0xf2900003
+
+/*P2_ACLC2*/
+#define R0900_P2_ACLC2  0xf291
+#define F0900_P2_CAR2_PUNCT_ADERAT  0xf2910040
+#define F0900_P2_CAR2_ALPHA_MANT  0xf2910030
+#define F0900_P2_CAR2_ALPHA_EXP  0xf291000f
+
+/*P2_BCLC2*/
+#define R0900_P2_BCLC2  0xf292
+#define F0900_P2_DVBS2_NIP  0xf2920080
+#define F0900_P2_CAR2_PUNCT_BDERAT  0xf2920040
+#define F0900_P2_CAR2_BETA_MANT  0xf2920030
+#define F0900_P2_CAR2_BETA_EXP  0xf292000f
+
+/*P2_CFR22*/
+#define R0900_P2_CFR22  0xf293
+#define F0900_P2_CAR2_FREQ2  0xf29301ff
+
+/*P2_CFR21*/
+#define R0900_P2_CFR21  0xf294
+#define F0900_P2_CAR2_FREQ1  0xf29400ff
+
+/*P2_CFR20*/
+#define R0900_P2_CFR20  0xf295
+#define F0900_P2_CAR2_FREQ0  0xf29500ff
+
+/*P2_ACLC2S2Q*/
+#define R0900_P2_ACLC2S2Q  0xf297
+#define F0900_P2_ENAB_SPSKSYMB  0xf2970080
+#define F0900_P2_CAR2S2_QADERAT  0xf2970040
+#define F0900_P2_CAR2S2_Q_ALPH_M  0xf2970030
+#define F0900_P2_CAR2S2_Q_ALPH_E  0xf297000f
+
+/*P2_ACLC2S28*/
+#define R0900_P2_ACLC2S28  0xf298
+#define F0900_P2_OLDI3Q_MODE  0xf2980080
+#define F0900_P2_CAR2S2_8ADERAT  0xf2980040
+#define F0900_P2_CAR2S2_8_ALPH_M  0xf2980030
+#define F0900_P2_CAR2S2_8_ALPH_E  0xf298000f
+
+/*P2_ACLC2S216A*/
+#define R0900_P2_ACLC2S216A  0xf299
+#define F0900_P2_CAR2S2_16ADERAT  0xf2990040
+#define F0900_P2_CAR2S2_16A_ALPH_M  0xf2990030
+#define F0900_P2_CAR2S2_16A_ALPH_E  0xf299000f
+
+/*P2_ACLC2S232A*/
+#define R0900_P2_ACLC2S232A  0xf29a
+#define F0900_P2_CAR2S2_32ADERAT  0xf29a0040
+#define F0900_P2_CAR2S2_32A_ALPH_M  0xf29a0030
+#define F0900_P2_CAR2S2_32A_ALPH_E  0xf29a000f
+
+/*P2_BCLC2S2Q*/
+#define R0900_P2_BCLC2S2Q  0xf29c
+#define F0900_P2_DVBS2S2Q_NIP  0xf29c0080
+#define F0900_P2_CAR2S2_QBDERAT  0xf29c0040
+#define F0900_P2_CAR2S2_Q_BETA_M  0xf29c0030
+#define F0900_P2_CAR2S2_Q_BETA_E  0xf29c000f
+
+/*P2_BCLC2S28*/
+#define R0900_P2_BCLC2S28  0xf29d
+#define F0900_P2_DVBS2S28_NIP  0xf29d0080
+#define F0900_P2_CAR2S2_8BDERAT  0xf29d0040
+#define F0900_P2_CAR2S2_8_BETA_M  0xf29d0030
+#define F0900_P2_CAR2S2_8_BETA_E  0xf29d000f
+
+/*P2_BCLC2S216A*/
+#define R0900_P2_BCLC2S216A  0xf29e
+#define F0900_P2_DVBS2S216A_NIP  0xf29e0080
+#define F0900_P2_CAR2S2_16BDERAT  0xf29e0040
+#define F0900_P2_CAR2S2_16A_BETA_M  0xf29e0030
+#define F0900_P2_CAR2S2_16A_BETA_E  0xf29e000f
+
+/*P2_BCLC2S232A*/
+#define R0900_P2_BCLC2S232A  0xf29f
+#define F0900_P2_DVBS2S232A_NIP  0xf29f0080
+#define F0900_P2_CAR2S2_32BDERAT  0xf29f0040
+#define F0900_P2_CAR2S2_32A_BETA_M  0xf29f0030
+#define F0900_P2_CAR2S2_32A_BETA_E  0xf29f000f
+
+/*P2_PLROOT2*/
+#define R0900_P2_PLROOT2  0xf2ac
+#define F0900_P2_SHORTFR_DISABLE  0xf2ac0080
+#define F0900_P2_LONGFR_DISABLE  0xf2ac0040
+#define F0900_P2_DUMMYPL_DISABLE  0xf2ac0020
+#define F0900_P2_SHORTFR_AVOID  0xf2ac0010
+#define F0900_P2_PLSCRAMB_MODE  0xf2ac000c
+#define F0900_P2_PLSCRAMB_ROOT2  0xf2ac0003
+
+/*P2_PLROOT1*/
+#define R0900_P2_PLROOT1  0xf2ad
+#define F0900_P2_PLSCRAMB_ROOT1  0xf2ad00ff
+
+/*P2_PLROOT0*/
+#define R0900_P2_PLROOT0  0xf2ae
+#define F0900_P2_PLSCRAMB_ROOT0  0xf2ae00ff
+
+/*P2_MODCODLST0*/
+#define R0900_P2_MODCODLST0  0xf2b0
+#define F0900_P2_EN_TOKEN31  0xf2b00080
+#define F0900_P2_SYNCTAG_SELECT  0xf2b00040
+#define F0900_P2_MODCODRQ_MODE  0xf2b00030
+
+/*P2_MODCODLST1*/
+#define R0900_P2_MODCODLST1  0xf2b1
+#define F0900_P2_DIS_MODCOD29  0xf2b100f0
+#define F0900_P2_DIS_32PSK_9_10  0xf2b1000f
+
+/*P2_MODCODLST2*/
+#define R0900_P2_MODCODLST2  0xf2b2
+#define F0900_P2_DIS_32PSK_8_9  0xf2b200f0
+#define F0900_P2_DIS_32PSK_5_6  0xf2b2000f
+
+/*P2_MODCODLST3*/
+#define R0900_P2_MODCODLST3  0xf2b3
+#define F0900_P2_DIS_32PSK_4_5  0xf2b300f0
+#define F0900_P2_DIS_32PSK_3_4  0xf2b3000f
+
+/*P2_MODCODLST4*/
+#define R0900_P2_MODCODLST4  0xf2b4
+#define F0900_P2_DIS_16PSK_9_10  0xf2b400f0
+#define F0900_P2_DIS_16PSK_8_9  0xf2b4000f
+
+/*P2_MODCODLST5*/
+#define R0900_P2_MODCODLST5  0xf2b5
+#define F0900_P2_DIS_16PSK_5_6  0xf2b500f0
+#define F0900_P2_DIS_16PSK_4_5  0xf2b5000f
+
+/*P2_MODCODLST6*/
+#define R0900_P2_MODCODLST6  0xf2b6
+#define F0900_P2_DIS_16PSK_3_4  0xf2b600f0
+#define F0900_P2_DIS_16PSK_2_3  0xf2b6000f
+
+/*P2_MODCODLST7*/
+#define R0900_P2_MODCODLST7  0xf2b7
+#define F0900_P2_DIS_8P_9_10  0xf2b700f0
+#define F0900_P2_DIS_8P_8_9  0xf2b7000f
+
+/*P2_MODCODLST8*/
+#define R0900_P2_MODCODLST8  0xf2b8
+#define F0900_P2_DIS_8P_5_6  0xf2b800f0
+#define F0900_P2_DIS_8P_3_4  0xf2b8000f
+
+/*P2_MODCODLST9*/
+#define R0900_P2_MODCODLST9  0xf2b9
+#define F0900_P2_DIS_8P_2_3  0xf2b900f0
+#define F0900_P2_DIS_8P_3_5  0xf2b9000f
+
+/*P2_MODCODLSTA*/
+#define R0900_P2_MODCODLSTA  0xf2ba
+#define F0900_P2_DIS_QP_9_10  0xf2ba00f0
+#define F0900_P2_DIS_QP_8_9  0xf2ba000f
+
+/*P2_MODCODLSTB*/
+#define R0900_P2_MODCODLSTB  0xf2bb
+#define F0900_P2_DIS_QP_5_6  0xf2bb00f0
+#define F0900_P2_DIS_QP_4_5  0xf2bb000f
+
+/*P2_MODCODLSTC*/
+#define R0900_P2_MODCODLSTC  0xf2bc
+#define F0900_P2_DIS_QP_3_4  0xf2bc00f0
+#define F0900_P2_DIS_QP_2_3  0xf2bc000f
+
+/*P2_MODCODLSTD*/
+#define R0900_P2_MODCODLSTD  0xf2bd
+#define F0900_P2_DIS_QP_3_5  0xf2bd00f0
+#define F0900_P2_DIS_QP_1_2  0xf2bd000f
+
+/*P2_MODCODLSTE*/
+#define R0900_P2_MODCODLSTE  0xf2be
+#define F0900_P2_DIS_QP_2_5  0xf2be00f0
+#define F0900_P2_DIS_QP_1_3  0xf2be000f
+
+/*P2_MODCODLSTF*/
+#define R0900_P2_MODCODLSTF  0xf2bf
+#define F0900_P2_DIS_QP_1_4  0xf2bf00f0
+#define F0900_P2_DDEMOD_SET  0xf2bf0002
+#define F0900_P2_DDEMOD_MASK  0xf2bf0001
+
+/*P2_DMDRESCFG*/
+#define R0900_P2_DMDRESCFG  0xf2c6
+#define F0900_P2_DMDRES_RESET  0xf2c60080
+#define F0900_P2_DMDRES_NOISESQR  0xf2c60010
+#define F0900_P2_DMDRES_STRALL  0xf2c60008
+#define F0900_P2_DMDRES_NEWONLY  0xf2c60004
+#define F0900_P2_DMDRES_NOSTORE  0xf2c60002
+#define F0900_P2_DMDRES_AGC2MEM  0xf2c60001
+
+/*P2_DMDRESADR*/
+#define R0900_P2_DMDRESADR  0xf2c7
+#define F0900_P2_SUSP_PREDCANAL  0xf2c70080
+#define F0900_P2_DMDRES_VALIDCFR  0xf2c70040
+#define F0900_P2_DMDRES_MEMFULL  0xf2c70030
+#define F0900_P2_DMDRES_RESNBR  0xf2c7000f
+
+/*P2_DMDRESDATA7*/
+#define R0900_P2_DMDRESDATA7  0xf2c8
+#define F0900_P2_DMDRES_DATA7  0xf2c800ff
+
+/*P2_DMDRESDATA6*/
+#define R0900_P2_DMDRESDATA6  0xf2c9
+#define F0900_P2_DMDRES_DATA6  0xf2c900ff
+
+/*P2_DMDRESDATA5*/
+#define R0900_P2_DMDRESDATA5  0xf2ca
+#define F0900_P2_DMDRES_DATA5  0xf2ca00ff
+
+/*P2_DMDRESDATA4*/
+#define R0900_P2_DMDRESDATA4  0xf2cb
+#define F0900_P2_DMDRES_DATA4  0xf2cb00ff
+
+/*P2_DMDRESDATA3*/
+#define R0900_P2_DMDRESDATA3  0xf2cc
+#define F0900_P2_DMDRES_DATA3  0xf2cc00ff
+
+/*P2_DMDRESDATA2*/
+#define R0900_P2_DMDRESDATA2  0xf2cd
+#define F0900_P2_DMDRES_DATA2  0xf2cd00ff
+
+/*P2_DMDRESDATA1*/
+#define R0900_P2_DMDRESDATA1  0xf2ce
+#define F0900_P2_DMDRES_DATA1  0xf2ce00ff
+
+/*P2_DMDRESDATA0*/
+#define R0900_P2_DMDRESDATA0  0xf2cf
+#define F0900_P2_DMDRES_DATA0  0xf2cf00ff
+
+/*P2_FFEI1*/
+#define R0900_P2_FFEI1  0xf2d0
+#define F0900_P2_FFE_ACCI1  0xf2d001ff
+
+/*P2_FFEQ1*/
+#define R0900_P2_FFEQ1  0xf2d1
+#define F0900_P2_FFE_ACCQ1  0xf2d101ff
+
+/*P2_FFEI2*/
+#define R0900_P2_FFEI2  0xf2d2
+#define F0900_P2_FFE_ACCI2  0xf2d201ff
+
+/*P2_FFEQ2*/
+#define R0900_P2_FFEQ2  0xf2d3
+#define F0900_P2_FFE_ACCQ2  0xf2d301ff
+
+/*P2_FFEI3*/
+#define R0900_P2_FFEI3  0xf2d4
+#define F0900_P2_FFE_ACCI3  0xf2d401ff
+
+/*P2_FFEQ3*/
+#define R0900_P2_FFEQ3  0xf2d5
+#define F0900_P2_FFE_ACCQ3  0xf2d501ff
+
+/*P2_FFEI4*/
+#define R0900_P2_FFEI4  0xf2d6
+#define F0900_P2_FFE_ACCI4  0xf2d601ff
+
+/*P2_FFEQ4*/
+#define R0900_P2_FFEQ4  0xf2d7
+#define F0900_P2_FFE_ACCQ4  0xf2d701ff
+
+/*P2_FFECFG*/
+#define R0900_P2_FFECFG  0xf2d8
+#define F0900_P2_EQUALFFE_ON  0xf2d80040
+#define F0900_P2_EQUAL_USEDSYMB  0xf2d80030
+#define F0900_P2_MU_EQUALFFE  0xf2d80007
+
+/*P2_TNRCFG*/
+#define R0900_P2_TNRCFG  0xf2e0
+#define F0900_P2_TUN_ACKFAIL  0xf2e00080
+#define F0900_P2_TUN_TYPE  0xf2e00070
+#define F0900_P2_TUN_SECSTOP  0xf2e00008
+#define F0900_P2_TUN_VCOSRCH  0xf2e00004
+#define F0900_P2_TUN_MADDRESS  0xf2e00003
+
+/*P2_TNRCFG2*/
+#define R0900_P2_TNRCFG2  0xf2e1
+#define F0900_P2_TUN_IQSWAP  0xf2e10080
+#define F0900_P2_STB6110_STEP2MHZ  0xf2e10040
+#define F0900_P2_STB6120_DBLI2C  0xf2e10020
+#define F0900_P2_DIS_FCCK  0xf2e10010
+#define F0900_P2_DIS_LPEN  0xf2e10008
+#define F0900_P2_DIS_BWCALC  0xf2e10004
+#define F0900_P2_SHORT_WAITSTATES  0xf2e10002
+#define F0900_P2_DIS_2BWAGC1  0xf2e10001
+
+/*P2_TNRXTAL*/
+#define R0900_P2_TNRXTAL  0xf2e4
+#define F0900_P2_TUN_MCLKDECIMAL  0xf2e400e0
+#define F0900_P2_TUN_XTALFREQ  0xf2e4001f
+
+/*P2_TNRSTEPS*/
+#define R0900_P2_TNRSTEPS  0xf2e7
+#define F0900_P2_TUNER_BW1P6  0xf2e70080
+#define F0900_P2_BWINC_OFFSET  0xf2e70070
+#define F0900_P2_SOFTSTEP_RNG  0xf2e70008
+#define F0900_P2_TUN_BWOFFSET  0xf2e70107
+
+/*P2_TNRGAIN*/
+#define R0900_P2_TNRGAIN  0xf2e8
+#define F0900_P2_TUN_KDIVEN  0xf2e800c0
+#define F0900_P2_STB6X00_OCK  0xf2e80030
+#define F0900_P2_TUN_GAIN  0xf2e8000f
+
+/*P2_TNRRF1*/
+#define R0900_P2_TNRRF1  0xf2e9
+#define F0900_P2_TUN_RFFREQ2  0xf2e900ff
+
+/*P2_TNRRF0*/
+#define R0900_P2_TNRRF0  0xf2ea
+#define F0900_P2_TUN_RFFREQ1  0xf2ea00ff
+
+/*P2_TNRBW*/
+#define R0900_P2_TNRBW  0xf2eb
+#define F0900_P2_TUN_RFFREQ0  0xf2eb00c0
+#define F0900_P2_TUN_BW  0xf2eb003f
+
+/*P2_TNRADJ*/
+#define R0900_P2_TNRADJ  0xf2ec
+#define F0900_P2_STB61X0_RCLK  0xf2ec0080
+#define F0900_P2_STB61X0_CALTIME  0xf2ec0040
+#define F0900_P2_STB6X00_DLB  0xf2ec0038
+#define F0900_P2_STB6000_FCL  0xf2ec0007
+
+/*P2_TNRCTL2*/
+#define R0900_P2_TNRCTL2  0xf2ed
+#define F0900_P2_STB61X0_LCP1_RCCKOFF  0xf2ed0080
+#define F0900_P2_STB61X0_LCP0  0xf2ed0040
+#define F0900_P2_STB61X0_XTOUT_RFOUTS  0xf2ed0020
+#define F0900_P2_STB61X0_XTON_MCKDV  0xf2ed0010
+#define F0900_P2_STB61X0_CALOFF_DCOFF  0xf2ed0008
+#define F0900_P2_STB6110_LPT  0xf2ed0004
+#define F0900_P2_STB6110_RX  0xf2ed0002
+#define F0900_P2_STB6110_SYN  0xf2ed0001
+
+/*P2_TNRCFG3*/
+#define R0900_P2_TNRCFG3  0xf2ee
+#define F0900_P2_STB6120_DISCTRL1  0xf2ee0080
+#define F0900_P2_STB6120_INVORDER  0xf2ee0040
+#define F0900_P2_STB6120_ENCTRL6  0xf2ee0020
+#define F0900_P2_TUN_PLLFREQ  0xf2ee001c
+#define F0900_P2_TUN_I2CFREQ_MODE  0xf2ee0003
+
+/*P2_TNRLAUNCH*/
+#define R0900_P2_TNRLAUNCH  0xf2f0
+
+/*P2_TNRLD*/
+#define R0900_P2_TNRLD  0xf2f0
+#define F0900_P2_TUNLD_VCOING  0xf2f00080
+#define F0900_P2_TUN_REG1FAIL  0xf2f00040
+#define F0900_P2_TUN_REG2FAIL  0xf2f00020
+#define F0900_P2_TUN_REG3FAIL  0xf2f00010
+#define F0900_P2_TUN_REG4FAIL  0xf2f00008
+#define F0900_P2_TUN_REG5FAIL  0xf2f00004
+#define F0900_P2_TUN_BWING  0xf2f00002
+#define F0900_P2_TUN_LOCKED  0xf2f00001
+
+/*P2_TNROBSL*/
+#define R0900_P2_TNROBSL  0xf2f6
+#define F0900_P2_TUN_I2CABORTED  0xf2f60080
+#define F0900_P2_TUN_LPEN  0xf2f60040
+#define F0900_P2_TUN_FCCK  0xf2f60020
+#define F0900_P2_TUN_I2CLOCKED  0xf2f60010
+#define F0900_P2_TUN_PROGDONE  0xf2f6000c
+#define F0900_P2_TUN_RFRESTE1  0xf2f60003
+
+/*P2_TNRRESTE*/
+#define R0900_P2_TNRRESTE  0xf2f7
+#define F0900_P2_TUN_RFRESTE0  0xf2f700ff
+
+/*P2_SMAPCOEF7*/
+#define R0900_P2_SMAPCOEF7  0xf300
+#define F0900_P2_DIS_QSCALE  0xf3000080
+#define F0900_P2_SMAPCOEF_Q_LLR12  0xf300017f
+
+/*P2_SMAPCOEF6*/
+#define R0900_P2_SMAPCOEF6  0xf301
+#define F0900_P2_DIS_NEWSCALE  0xf3010008
+#define F0900_P2_ADJ_8PSKLLR1  0xf3010004
+#define F0900_P2_OLD_8PSKLLR1  0xf3010002
+#define F0900_P2_DIS_AB8PSK  0xf3010001
+
+/*P2_SMAPCOEF5*/
+#define R0900_P2_SMAPCOEF5  0xf302
+#define F0900_P2_DIS_8SCALE  0xf3020080
+#define F0900_P2_SMAPCOEF_8P_LLR23  0xf302017f
+
+/*P2_DMDPLHSTAT*/
+#define R0900_P2_DMDPLHSTAT  0xf320
+#define F0900_P2_PLH_STATISTIC  0xf32000ff
+
+/*P2_LOCKTIME3*/
+#define R0900_P2_LOCKTIME3  0xf322
+#define F0900_P2_DEMOD_LOCKTIME3  0xf32200ff
+
+/*P2_LOCKTIME2*/
+#define R0900_P2_LOCKTIME2  0xf323
+#define F0900_P2_DEMOD_LOCKTIME2  0xf32300ff
+
+/*P2_LOCKTIME1*/
+#define R0900_P2_LOCKTIME1  0xf324
+#define F0900_P2_DEMOD_LOCKTIME1  0xf32400ff
+
+/*P2_LOCKTIME0*/
+#define R0900_P2_LOCKTIME0  0xf325
+#define F0900_P2_DEMOD_LOCKTIME0  0xf32500ff
+
+/*P2_VITSCALE*/
+#define R0900_P2_VITSCALE  0xf332
+#define F0900_P2_NVTH_NOSRANGE  0xf3320080
+#define F0900_P2_VERROR_MAXMODE  0xf3320040
+#define F0900_P2_KDIV_MODE  0xf3320030
+#define F0900_P2_NSLOWSN_LOCKED  0xf3320008
+#define F0900_P2_DELOCK_PRFLOSS  0xf3320004
+#define F0900_P2_DIS_RSFLOCK  0xf3320002
+
+/*P2_FECM*/
+#define R0900_P2_FECM  0xf333
+#define F0900_P2_DSS_DVB  0xf3330080
+#define F0900_P2_DEMOD_BYPASS  0xf3330040
+#define F0900_P2_CMP_SLOWMODE  0xf3330020
+#define F0900_P2_DSS_SRCH  0xf3330010
+#define F0900_P2_DIFF_MODEVIT  0xf3330004
+#define F0900_P2_SYNCVIT  0xf3330002
+#define F0900_P2_IQINV  0xf3330001
+
+/*P2_VTH12*/
+#define R0900_P2_VTH12  0xf334
+#define F0900_P2_VTH12  0xf33400ff
+
+/*P2_VTH23*/
+#define R0900_P2_VTH23  0xf335
+#define F0900_P2_VTH23  0xf33500ff
+
+/*P2_VTH34*/
+#define R0900_P2_VTH34  0xf336
+#define F0900_P2_VTH34  0xf33600ff
+
+/*P2_VTH56*/
+#define R0900_P2_VTH56  0xf337
+#define F0900_P2_VTH56  0xf33700ff
+
+/*P2_VTH67*/
+#define R0900_P2_VTH67  0xf338
+#define F0900_P2_VTH67  0xf33800ff
+
+/*P2_VTH78*/
+#define R0900_P2_VTH78  0xf339
+#define F0900_P2_VTH78  0xf33900ff
+
+/*P2_VITCURPUN*/
+#define R0900_P2_VITCURPUN  0xf33a
+#define F0900_P2_VIT_MAPPING  0xf33a00e0
+#define F0900_P2_VIT_CURPUN  0xf33a001f
+
+/*P2_VERROR*/
+#define R0900_P2_VERROR  0xf33b
+#define F0900_P2_REGERR_VIT  0xf33b00ff
+
+/*P2_PRVIT*/
+#define R0900_P2_PRVIT  0xf33c
+#define F0900_P2_DIS_VTHLOCK  0xf33c0040
+#define F0900_P2_E7_8VIT  0xf33c0020
+#define F0900_P2_E6_7VIT  0xf33c0010
+#define F0900_P2_E5_6VIT  0xf33c0008
+#define F0900_P2_E3_4VIT  0xf33c0004
+#define F0900_P2_E2_3VIT  0xf33c0002
+#define F0900_P2_E1_2VIT  0xf33c0001
+
+/*P2_VAVSRVIT*/
+#define R0900_P2_VAVSRVIT  0xf33d
+#define F0900_P2_AMVIT  0xf33d0080
+#define F0900_P2_FROZENVIT  0xf33d0040
+#define F0900_P2_SNVIT  0xf33d0030
+#define F0900_P2_TOVVIT  0xf33d000c
+#define F0900_P2_HYPVIT  0xf33d0003
+
+/*P2_VSTATUSVIT*/
+#define R0900_P2_VSTATUSVIT  0xf33e
+#define F0900_P2_VITERBI_ON  0xf33e0080
+#define F0900_P2_END_LOOPVIT  0xf33e0040
+#define F0900_P2_VITERBI_DEPRF  0xf33e0020
+#define F0900_P2_PRFVIT  0xf33e0010
+#define F0900_P2_LOCKEDVIT  0xf33e0008
+#define F0900_P2_VITERBI_DELOCK  0xf33e0004
+#define F0900_P2_VIT_DEMODSEL  0xf33e0002
+#define F0900_P2_VITERBI_COMPOUT  0xf33e0001
+
+/*P2_VTHINUSE*/
+#define R0900_P2_VTHINUSE  0xf33f
+#define F0900_P2_VIT_INUSE  0xf33f00ff
+
+/*P2_KDIV12*/
+#define R0900_P2_KDIV12  0xf340
+#define F0900_P2_KDIV12_MANUAL  0xf3400080
+#define F0900_P2_K_DIVIDER_12  0xf340007f
+
+/*P2_KDIV23*/
+#define R0900_P2_KDIV23  0xf341
+#define F0900_P2_KDIV23_MANUAL  0xf3410080
+#define F0900_P2_K_DIVIDER_23  0xf341007f
+
+/*P2_KDIV34*/
+#define R0900_P2_KDIV34  0xf342
+#define F0900_P2_KDIV34_MANUAL  0xf3420080
+#define F0900_P2_K_DIVIDER_34  0xf342007f
+
+/*P2_KDIV56*/
+#define R0900_P2_KDIV56  0xf343
+#define F0900_P2_KDIV56_MANUAL  0xf3430080
+#define F0900_P2_K_DIVIDER_56  0xf343007f
+
+/*P2_KDIV67*/
+#define R0900_P2_KDIV67  0xf344
+#define F0900_P2_KDIV67_MANUAL  0xf3440080
+#define F0900_P2_K_DIVIDER_67  0xf344007f
+
+/*P2_KDIV78*/
+#define R0900_P2_KDIV78  0xf345
+#define F0900_P2_KDIV78_MANUAL  0xf3450080
+#define F0900_P2_K_DIVIDER_78  0xf345007f
+
+/*P2_PDELCTRL1*/
+#define R0900_P2_PDELCTRL1  0xf350
+#define F0900_P2_INV_MISMASK  0xf3500080
+#define F0900_P2_FORCE_ACCEPTED  0xf3500040
+#define F0900_P2_FILTER_EN  0xf3500020
+#define F0900_P2_FORCE_PKTDELINUSE  0xf3500010
+#define F0900_P2_HYSTEN  0xf3500008
+#define F0900_P2_HYSTSWRST  0xf3500004
+#define F0900_P2_EN_MIS00  0xf3500002
+#define F0900_P2_ALGOSWRST  0xf3500001
+
+/*P2_PDELCTRL2*/
+#define R0900_P2_PDELCTRL2  0xf351
+#define F0900_P2_FORCE_CONTINUOUS  0xf3510080
+#define F0900_P2_RESET_UPKO_COUNT  0xf3510040
+#define F0900_P2_USER_PKTDELIN_NB  0xf3510020
+#define F0900_P2_FORCE_LOCKED  0xf3510010
+#define F0900_P2_DATA_UNBBSCRAM  0xf3510008
+#define F0900_P2_FORCE_LONGPKT  0xf3510004
+#define F0900_P2_FRAME_MODE  0xf3510002
+
+/*P2_HYSTTHRESH*/
+#define R0900_P2_HYSTTHRESH  0xf354
+#define F0900_P2_UNLCK_THRESH  0xf35400f0
+#define F0900_P2_DELIN_LCK_THRESH  0xf354000f
+
+/*P2_ISIENTRY*/
+#define R0900_P2_ISIENTRY  0xf35e
+#define F0900_P2_ISI_ENTRY  0xf35e00ff
+
+/*P2_ISIBITENA*/
+#define R0900_P2_ISIBITENA  0xf35f
+#define F0900_P2_ISI_BIT_EN  0xf35f00ff
+
+/*P2_MATSTR1*/
+#define R0900_P2_MATSTR1  0xf360
+#define F0900_P2_MATYPE_CURRENT1  0xf36000ff
+
+/*P2_MATSTR0*/
+#define R0900_P2_MATSTR0  0xf361
+#define F0900_P2_MATYPE_CURRENT0  0xf36100ff
+
+/*P2_UPLSTR1*/
+#define R0900_P2_UPLSTR1  0xf362
+#define F0900_P2_UPL_CURRENT1  0xf36200ff
+
+/*P2_UPLSTR0*/
+#define R0900_P2_UPLSTR0  0xf363
+#define F0900_P2_UPL_CURRENT0  0xf36300ff
+
+/*P2_DFLSTR1*/
+#define R0900_P2_DFLSTR1  0xf364
+#define F0900_P2_DFL_CURRENT1  0xf36400ff
+
+/*P2_DFLSTR0*/
+#define R0900_P2_DFLSTR0  0xf365
+#define F0900_P2_DFL_CURRENT0  0xf36500ff
+
+/*P2_SYNCSTR*/
+#define R0900_P2_SYNCSTR  0xf366
+#define F0900_P2_SYNC_CURRENT  0xf36600ff
+
+/*P2_SYNCDSTR1*/
+#define R0900_P2_SYNCDSTR1  0xf367
+#define F0900_P2_SYNCD_CURRENT1  0xf36700ff
+
+/*P2_SYNCDSTR0*/
+#define R0900_P2_SYNCDSTR0  0xf368
+#define F0900_P2_SYNCD_CURRENT0  0xf36800ff
+
+/*P2_PDELSTATUS1*/
+#define R0900_P2_PDELSTATUS1  0xf369
+#define F0900_P2_PKTDELIN_DELOCK  0xf3690080
+#define F0900_P2_SYNCDUPDFL_BADDFL  0xf3690040
+#define F0900_P2_CONTINUOUS_STREAM  0xf3690020
+#define F0900_P2_UNACCEPTED_STREAM  0xf3690010
+#define F0900_P2_BCH_ERROR_FLAG  0xf3690008
+#define F0900_P2_BBHCRCKO  0xf3690004
+#define F0900_P2_PKTDELIN_LOCK  0xf3690002
+#define F0900_P2_FIRST_LOCK  0xf3690001
+
+/*P2_PDELSTATUS2*/
+#define R0900_P2_PDELSTATUS2  0xf36a
+#define F0900_P2_PKTDEL_DEMODSEL  0xf36a0080
+#define F0900_P2_FRAME_MODCOD  0xf36a007c
+#define F0900_P2_FRAME_TYPE  0xf36a0003
+
+/*P2_BBFCRCKO1*/
+#define R0900_P2_BBFCRCKO1  0xf36b
+#define F0900_P2_BBHCRC_KOCNT1  0xf36b00ff
+
+/*P2_BBFCRCKO0*/
+#define R0900_P2_BBFCRCKO0  0xf36c
+#define F0900_P2_BBHCRC_KOCNT0  0xf36c00ff
+
+/*P2_UPCRCKO1*/
+#define R0900_P2_UPCRCKO1  0xf36d
+#define F0900_P2_PKTCRC_KOCNT1  0xf36d00ff
+
+/*P2_UPCRCKO0*/
+#define R0900_P2_UPCRCKO0  0xf36e
+#define F0900_P2_PKTCRC_KOCNT0  0xf36e00ff
+
+/*P2_TSSTATEM*/
+#define R0900_P2_TSSTATEM  0xf370
+#define F0900_P2_TSDIL_ON  0xf3700080
+#define F0900_P2_TSSKIPRS_ON  0xf3700040
+#define F0900_P2_TSRS_ON  0xf3700020
+#define F0900_P2_TSDESCRAMB_ON  0xf3700010
+#define F0900_P2_TSFRAME_MODE  0xf3700008
+#define F0900_P2_TS_DISABLE  0xf3700004
+#define F0900_P2_TSACM_MODE  0xf3700002
+#define F0900_P2_TSOUT_NOSYNC  0xf3700001
+
+/*P2_TSCFGH*/
+#define R0900_P2_TSCFGH  0xf372
+#define F0900_P2_TSFIFO_DVBCI  0xf3720080
+#define F0900_P2_TSFIFO_SERIAL  0xf3720040
+#define F0900_P2_TSFIFO_TEIUPDATE  0xf3720020
+#define F0900_P2_TSFIFO_DUTY50  0xf3720010
+#define F0900_P2_TSFIFO_HSGNLOUT  0xf3720008
+#define F0900_P2_TSFIFO_ERRMODE  0xf3720006
+#define F0900_P2_RST_HWARE  0xf3720001
+
+/*P2_TSCFGM*/
+#define R0900_P2_TSCFGM  0xf373
+#define F0900_P2_TSFIFO_MANSPEED  0xf37300c0
+#define F0900_P2_TSFIFO_PERMDATA  0xf3730020
+#define F0900_P2_TSFIFO_NONEWSGNL  0xf3730010
+#define F0900_P2_TSFIFO_BITSPEED  0xf3730008
+#define F0900_P2_NPD_SPECDVBS2  0xf3730004
+#define F0900_P2_TSFIFO_STOPCKDIS  0xf3730002
+#define F0900_P2_TSFIFO_INVDATA  0xf3730001
+
+/*P2_TSCFGL*/
+#define R0900_P2_TSCFGL  0xf374
+#define F0900_P2_TSFIFO_BCLKDEL1CK  0xf37400c0
+#define F0900_P2_BCHERROR_MODE  0xf3740030
+#define F0900_P2_TSFIFO_NSGNL2DATA  0xf3740008
+#define F0900_P2_TSFIFO_EMBINDVB  0xf3740004
+#define F0900_P2_TSFIFO_DPUNACT  0xf3740002
+#define F0900_P2_TSFIFO_NPDOFF  0xf3740001
+
+/*P2_TSINSDELH*/
+#define R0900_P2_TSINSDELH  0xf376
+#define F0900_P2_TSDEL_SYNCBYTE  0xf3760080
+#define F0900_P2_TSDEL_XXHEADER  0xf3760040
+#define F0900_P2_TSDEL_BBHEADER  0xf3760020
+#define F0900_P2_TSDEL_DATAFIELD  0xf3760010
+#define F0900_P2_TSINSDEL_ISCR  0xf3760008
+#define F0900_P2_TSINSDEL_NPD  0xf3760004
+#define F0900_P2_TSINSDEL_RSPARITY  0xf3760002
+#define F0900_P2_TSINSDEL_CRC8  0xf3760001
+
+/*P2_TSSPEED*/
+#define R0900_P2_TSSPEED  0xf380
+#define F0900_P2_TSFIFO_OUTSPEED  0xf38000ff
+
+/*P2_TSSTATUS*/
+#define R0900_P2_TSSTATUS  0xf381
+#define F0900_P2_TSFIFO_LINEOK  0xf3810080
+#define F0900_P2_TSFIFO_ERROR  0xf3810040
+#define F0900_P2_TSFIFO_DATA7  0xf3810020
+#define F0900_P2_TSFIFO_NOSYNC  0xf3810010
+#define F0900_P2_ISCR_INITIALIZED  0xf3810008
+#define F0900_P2_ISCR_UPDATED  0xf3810004
+#define F0900_P2_SOFFIFO_UNREGUL  0xf3810002
+#define F0900_P2_DIL_READY  0xf3810001
+
+/*P2_TSSTATUS2*/
+#define R0900_P2_TSSTATUS2  0xf382
+#define F0900_P2_TSFIFO_DEMODSEL  0xf3820080
+#define F0900_P2_TSFIFOSPEED_STORE  0xf3820040
+#define F0900_P2_DILXX_RESET  0xf3820020
+#define F0900_P2_TSSERIAL_IMPOS  0xf3820010
+#define F0900_P2_TSFIFO_LINENOK  0xf3820008
+#define F0900_P2_BITSPEED_EVENT  0xf3820004
+#define F0900_P2_SCRAMBDETECT  0xf3820002
+#define F0900_P2_ULDTV67_FALSELOCK  0xf3820001
+
+/*P2_TSBITRATE1*/
+#define R0900_P2_TSBITRATE1  0xf383
+#define F0900_P2_TSFIFO_BITRATE1  0xf38300ff
+
+/*P2_TSBITRATE0*/
+#define R0900_P2_TSBITRATE0  0xf384
+#define F0900_P2_TSFIFO_BITRATE0  0xf38400ff
+
+/*P2_ERRCTRL1*/
+#define R0900_P2_ERRCTRL1  0xf398
+#define F0900_P2_ERR_SOURCE1  0xf39800f0
+#define F0900_P2_NUM_EVENT1  0xf3980007
+
+/*P2_ERRCNT12*/
+#define R0900_P2_ERRCNT12  0xf399
+#define F0900_P2_ERRCNT1_OLDVALUE  0xf3990080
+#define F0900_P2_ERR_CNT12  0xf399007f
+
+/*P2_ERRCNT11*/
+#define R0900_P2_ERRCNT11  0xf39a
+#define F0900_P2_ERR_CNT11  0xf39a00ff
+
+/*P2_ERRCNT10*/
+#define R0900_P2_ERRCNT10  0xf39b
+#define F0900_P2_ERR_CNT10  0xf39b00ff
+
+/*P2_ERRCTRL2*/
+#define R0900_P2_ERRCTRL2  0xf39c
+#define F0900_P2_ERR_SOURCE2  0xf39c00f0
+#define F0900_P2_NUM_EVENT2  0xf39c0007
+
+/*P2_ERRCNT22*/
+#define R0900_P2_ERRCNT22  0xf39d
+#define F0900_P2_ERRCNT2_OLDVALUE  0xf39d0080
+#define F0900_P2_ERR_CNT22  0xf39d007f
+
+/*P2_ERRCNT21*/
+#define R0900_P2_ERRCNT21  0xf39e
+#define F0900_P2_ERR_CNT21  0xf39e00ff
+
+/*P2_ERRCNT20*/
+#define R0900_P2_ERRCNT20  0xf39f
+#define F0900_P2_ERR_CNT20  0xf39f00ff
+
+/*P2_FECSPY*/
+#define R0900_P2_FECSPY  0xf3a0
+#define F0900_P2_SPY_ENABLE  0xf3a00080
+#define F0900_P2_NO_SYNCBYTE  0xf3a00040
+#define F0900_P2_SERIAL_MODE  0xf3a00020
+#define F0900_P2_UNUSUAL_PACKET  0xf3a00010
+#define F0900_P2_BER_PACKMODE  0xf3a00008
+#define F0900_P2_BERMETER_LMODE  0xf3a00002
+#define F0900_P2_BERMETER_RESET  0xf3a00001
+
+/*P2_FSPYCFG*/
+#define R0900_P2_FSPYCFG  0xf3a1
+#define F0900_P2_FECSPY_INPUT  0xf3a100c0
+#define F0900_P2_RST_ON_ERROR  0xf3a10020
+#define F0900_P2_ONE_SHOT  0xf3a10010
+#define F0900_P2_I2C_MODE  0xf3a1000c
+#define F0900_P2_SPY_HYSTERESIS  0xf3a10003
+
+/*P2_FSPYDATA*/
+#define R0900_P2_FSPYDATA  0xf3a2
+#define F0900_P2_SPY_STUFFING  0xf3a20080
+#define F0900_P2_NOERROR_PKTJITTER  0xf3a20040
+#define F0900_P2_SPY_CNULLPKT  0xf3a20020
+#define F0900_P2_SPY_OUTDATA_MODE  0xf3a2001f
+
+/*P2_FSPYOUT*/
+#define R0900_P2_FSPYOUT  0xf3a3
+#define F0900_P2_FSPY_DIRECT  0xf3a30080
+#define F0900_P2_SPY_OUTDATA_BUS  0xf3a30038
+#define F0900_P2_STUFF_MODE  0xf3a30007
+
+/*P2_FSTATUS*/
+#define R0900_P2_FSTATUS  0xf3a4
+#define F0900_P2_SPY_ENDSIM  0xf3a40080
+#define F0900_P2_VALID_SIM  0xf3a40040
+#define F0900_P2_FOUND_SIGNAL  0xf3a40020
+#define F0900_P2_DSS_SYNCBYTE  0xf3a40010
+#define F0900_P2_RESULT_STATE  0xf3a4000f
+
+/*P2_FBERCPT4*/
+#define R0900_P2_FBERCPT4  0xf3a8
+#define F0900_P2_FBERMETER_CPT4  0xf3a800ff
+
+/*P2_FBERCPT3*/
+#define R0900_P2_FBERCPT3  0xf3a9
+#define F0900_P2_FBERMETER_CPT3  0xf3a900ff
+
+/*P2_FBERCPT2*/
+#define R0900_P2_FBERCPT2  0xf3aa
+#define F0900_P2_FBERMETER_CPT2  0xf3aa00ff
+
+/*P2_FBERCPT1*/
+#define R0900_P2_FBERCPT1  0xf3ab
+#define F0900_P2_FBERMETER_CPT1  0xf3ab00ff
+
+/*P2_FBERCPT0*/
+#define R0900_P2_FBERCPT0  0xf3ac
+#define F0900_P2_FBERMETER_CPT0  0xf3ac00ff
+
+/*P2_FBERERR2*/
+#define R0900_P2_FBERERR2  0xf3ad
+#define F0900_P2_FBERMETER_ERR2  0xf3ad00ff
+
+/*P2_FBERERR1*/
+#define R0900_P2_FBERERR1  0xf3ae
+#define F0900_P2_FBERMETER_ERR1  0xf3ae00ff
+
+/*P2_FBERERR0*/
+#define R0900_P2_FBERERR0  0xf3af
+#define F0900_P2_FBERMETER_ERR0  0xf3af00ff
+
+/*P2_FSPYBER*/
+#define R0900_P2_FSPYBER  0xf3b2
+#define F0900_P2_FSPYOBS_XORREAD  0xf3b20040
+#define F0900_P2_FSPYBER_OBSMODE  0xf3b20020
+#define F0900_P2_FSPYBER_SYNCBYTE  0xf3b20010
+#define F0900_P2_FSPYBER_UNSYNC  0xf3b20008
+#define F0900_P2_FSPYBER_CTIME  0xf3b20007
+
+/*P1_IQCONST*/
+#define R0900_P1_IQCONST  0xf400
+#define F0900_P1_CONSTEL_SELECT  0xf4000060
+#define F0900_P1_IQSYMB_SEL  0xf400001f
+
+/*P1_NOSCFG*/
+#define R0900_P1_NOSCFG  0xf401
+#define F0900_P1_DUMMYPL_NOSDATA  0xf4010020
+#define F0900_P1_NOSPLH_BETA  0xf4010018
+#define F0900_P1_NOSDATA_BETA  0xf4010007
+
+/*P1_ISYMB*/
+#define R0900_P1_ISYMB  0xf402
+#define F0900_P1_I_SYMBOL  0xf40201ff
+
+/*P1_QSYMB*/
+#define R0900_P1_QSYMB  0xf403
+#define F0900_P1_Q_SYMBOL  0xf40301ff
+
+/*P1_AGC1CFG*/
+#define R0900_P1_AGC1CFG  0xf404
+#define F0900_P1_DC_FROZEN  0xf4040080
+#define F0900_P1_DC_CORRECT  0xf4040040
+#define F0900_P1_AMM_FROZEN  0xf4040020
+#define F0900_P1_AMM_CORRECT  0xf4040010
+#define F0900_P1_QUAD_FROZEN  0xf4040008
+#define F0900_P1_QUAD_CORRECT  0xf4040004
+#define F0900_P1_DCCOMP_SLOW  0xf4040002
+#define F0900_P1_IQMISM_SLOW  0xf4040001
+
+/*P1_AGC1CN*/
+#define R0900_P1_AGC1CN  0xf406
+#define F0900_P1_AGC1_LOCKED  0xf4060080
+#define F0900_P1_AGC1_OVERFLOW  0xf4060040
+#define F0900_P1_AGC1_NOSLOWLK  0xf4060020
+#define F0900_P1_AGC1_MINPOWER  0xf4060010
+#define F0900_P1_AGCOUT_FAST  0xf4060008
+#define F0900_P1_AGCIQ_BETA  0xf4060007
+
+/*P1_AGC1REF*/
+#define R0900_P1_AGC1REF  0xf407
+#define F0900_P1_AGCIQ_REF  0xf40700ff
+
+/*P1_IDCCOMP*/
+#define R0900_P1_IDCCOMP  0xf408
+#define F0900_P1_IAVERAGE_ADJ  0xf40801ff
+
+/*P1_QDCCOMP*/
+#define R0900_P1_QDCCOMP  0xf409
+#define F0900_P1_QAVERAGE_ADJ  0xf40901ff
+
+/*P1_POWERI*/
+#define R0900_P1_POWERI  0xf40a
+#define F0900_P1_POWER_I  0xf40a00ff
+
+/*P1_POWERQ*/
+#define R0900_P1_POWERQ  0xf40b
+#define F0900_P1_POWER_Q  0xf40b00ff
+
+/*P1_AGC1AMM*/
+#define R0900_P1_AGC1AMM  0xf40c
+#define F0900_P1_AMM_VALUE  0xf40c00ff
+
+/*P1_AGC1QUAD*/
+#define R0900_P1_AGC1QUAD  0xf40d
+#define F0900_P1_QUAD_VALUE  0xf40d01ff
+
+/*P1_AGCIQIN1*/
+#define R0900_P1_AGCIQIN1  0xf40e
+#define F0900_P1_AGCIQ_VALUE1  0xf40e00ff
+
+/*P1_AGCIQIN0*/
+#define R0900_P1_AGCIQIN0  0xf40f
+#define F0900_P1_AGCIQ_VALUE0  0xf40f00ff
+
+/*P1_DEMOD*/
+#define R0900_P1_DEMOD  0xf410
+#define F0900_P1_DEMOD_STOP  0xf4100040
+#define F0900_P1_SPECINV_CONTROL  0xf4100030
+#define F0900_P1_FORCE_ENASAMP  0xf4100008
+#define F0900_P1_MANUAL_ROLLOFF  0xf4100004
+#define F0900_P1_ROLLOFF_CONTROL  0xf4100003
+
+/*P1_DMDMODCOD*/
+#define R0900_P1_DMDMODCOD  0xf411
+#define F0900_P1_MANUAL_MODCOD  0xf4110080
+#define F0900_P1_DEMOD_MODCOD  0xf411007c
+#define F0900_P1_DEMOD_TYPE  0xf4110003
+
+/*P1_DSTATUS*/
+#define R0900_P1_DSTATUS  0xf412
+#define F0900_P1_CAR_LOCK  0xf4120080
+#define F0900_P1_TMGLOCK_QUALITY  0xf4120060
+#define F0900_P1_SDVBS1_ENABLE  0xf4120010
+#define F0900_P1_LOCK_DEFINITIF  0xf4120008
+#define F0900_P1_TIMING_IS_LOCKED  0xf4120004
+#define F0900_P1_COARSE_TMGLOCK  0xf4120002
+#define F0900_P1_COARSE_CARLOCK  0xf4120001
+
+/*P1_DSTATUS2*/
+#define R0900_P1_DSTATUS2  0xf413
+#define F0900_P1_DEMOD_DELOCK  0xf4130080
+#define F0900_P1_DEMOD_TIMEOUT  0xf4130040
+#define F0900_P1_MODCODRQ_SYNCTAG  0xf4130020
+#define F0900_P1_POLYPH_SATEVENT  0xf4130010
+#define F0900_P1_AGC1_NOSIGNALACK  0xf4130008
+#define F0900_P1_AGC2_OVERFLOW  0xf4130004
+#define F0900_P1_CFR_OVERFLOW  0xf4130002
+#define F0900_P1_GAMMA_OVERUNDER  0xf4130001
+
+/*P1_DMDCFGMD*/
+#define R0900_P1_DMDCFGMD  0xf414
+#define F0900_P1_DVBS2_ENABLE  0xf4140080
+#define F0900_P1_DVBS1_ENABLE  0xf4140040
+#define F0900_P1_CFR_AUTOSCAN  0xf4140020
+#define F0900_P1_SCAN_ENABLE  0xf4140010
+#define F0900_P1_TUN_AUTOSCAN  0xf4140008
+#define F0900_P1_NOFORCE_RELOCK  0xf4140004
+#define F0900_P1_TUN_RNG  0xf4140003
+
+/*P1_DMDCFG2*/
+#define R0900_P1_DMDCFG2  0xf415
+#define F0900_P1_AGC1_WAITLOCK  0xf4150080
+#define F0900_P1_S1S2_SEQUENTIAL  0xf4150040
+#define F0900_P1_OVERFLOW_TIMEOUT  0xf4150020
+#define F0900_P1_SCANFAIL_TIMEOUT  0xf4150010
+#define F0900_P1_DMDTOUT_BACK  0xf4150008
+#define F0900_P1_CARLOCK_S1ENABLE  0xf4150004
+#define F0900_P1_COARSE_LK3MODE  0xf4150002
+#define F0900_P1_COARSE_LK2MODE  0xf4150001
+
+/*P1_DMDISTATE*/
+#define R0900_P1_DMDISTATE  0xf416
+#define F0900_P1_I2C_NORESETDMODE  0xf4160080
+#define F0900_P1_FORCE_ETAPED  0xf4160040
+#define F0900_P1_SDMDRST_DIRCLK  0xf4160020
+#define F0900_P1_I2C_DEMOD_MODE  0xf416001f
+
+/*P1_DMDT0M*/
+#define R0900_P1_DMDT0M  0xf417
+#define F0900_P1_DMDT0_MIN  0xf41700ff
+
+/*P1_DMDSTATE*/
+#define R0900_P1_DMDSTATE  0xf41b
+#define F0900_P1_DEMOD_LOCKED  0xf41b0080
+#define F0900_P1_HEADER_MODE  0xf41b0060
+#define F0900_P1_DEMOD_MODE  0xf41b001f
+
+/*P1_DMDFLYW*/
+#define R0900_P1_DMDFLYW  0xf41c
+#define F0900_P1_I2C_IRQVAL  0xf41c00f0
+#define F0900_P1_FLYWHEEL_CPT  0xf41c000f
+
+/*P1_DSTATUS3*/
+#define R0900_P1_DSTATUS3  0xf41d
+#define F0900_P1_CFR_ZIGZAG  0xf41d0080
+#define F0900_P1_DEMOD_CFGMODE  0xf41d0060
+#define F0900_P1_GAMMA_LOWBAUDRATE  0xf41d0010
+#define F0900_P1_RELOCK_MODE  0xf41d0008
+#define F0900_P1_DEMOD_FAIL  0xf41d0004
+#define F0900_P1_ETAPE1A_DVBXMEM  0xf41d0003
+
+/*P1_DMDCFG3*/
+#define R0900_P1_DMDCFG3  0xf41e
+#define F0900_P1_DVBS1_TMGWAIT  0xf41e0080
+#define F0900_P1_NO_BWCENTERING  0xf41e0040
+#define F0900_P1_INV_SEQSRCH  0xf41e0020
+#define F0900_P1_DIS_SFRUPLOW_TRK  0xf41e0010
+#define F0900_P1_NOSTOP_FIFOFULL  0xf41e0008
+#define F0900_P1_LOCKTIME_MODE  0xf41e0007
+
+/*P1_DMDCFG4*/
+#define R0900_P1_DMDCFG4  0xf41f
+#define F0900_P1_TUNER_NRELAUNCH  0xf41f0008
+#define F0900_P1_DIS_CLKENABLE  0xf41f0004
+#define F0900_P1_DIS_HDRDIVLOCK  0xf41f0002
+#define F0900_P1_NO_TNRWBINIT  0xf41f0001
+
+/*P1_CORRELMANT*/
+#define R0900_P1_CORRELMANT  0xf420
+#define F0900_P1_CORREL_MANT  0xf42000ff
+
+/*P1_CORRELABS*/
+#define R0900_P1_CORRELABS  0xf421
+#define F0900_P1_CORREL_ABS  0xf42100ff
+
+/*P1_CORRELEXP*/
+#define R0900_P1_CORRELEXP  0xf422
+#define F0900_P1_CORREL_ABSEXP  0xf42200f0
+#define F0900_P1_CORREL_EXP  0xf422000f
+
+/*P1_PLHMODCOD*/
+#define R0900_P1_PLHMODCOD  0xf424
+#define F0900_P1_SPECINV_DEMOD  0xf4240080
+#define F0900_P1_PLH_MODCOD  0xf424007c
+#define F0900_P1_PLH_TYPE  0xf4240003
+
+/*P1_AGCK32*/
+#define R0900_P1_AGCK32  0xf42b
+#define F0900_P1_R3ADJOFF_32APSK  0xf42b0080
+#define F0900_P1_R2ADJOFF_32APSK  0xf42b0040
+#define F0900_P1_R1ADJOFF_32APSK  0xf42b0020
+#define F0900_P1_RADJ_32APSK  0xf42b001f
+
+/*P1_AGC2O*/
+#define R0900_P1_AGC2O  0xf42c
+#define F0900_P1_AGC2REF_ADJUSTING  0xf42c0080
+#define F0900_P1_AGC2_COARSEFAST  0xf42c0040
+#define F0900_P1_AGC2_LKSQRT  0xf42c0020
+#define F0900_P1_AGC2_LKMODE  0xf42c0010
+#define F0900_P1_AGC2_LKEQUA  0xf42c0008
+#define F0900_P1_AGC2_COEF  0xf42c0007
+
+/*P1_AGC2REF*/
+#define R0900_P1_AGC2REF  0xf42d
+#define F0900_P1_AGC2_REF  0xf42d00ff
+
+/*P1_AGC1ADJ*/
+#define R0900_P1_AGC1ADJ  0xf42e
+#define F0900_P1_AGC1ADJ_MANUAL  0xf42e0080
+#define F0900_P1_AGC1_ADJUSTED  0xf42e017f
+
+/*P1_AGC2I1*/
+#define R0900_P1_AGC2I1  0xf436
+#define F0900_P1_AGC2_INTEGRATOR1  0xf43600ff
+
+/*P1_AGC2I0*/
+#define R0900_P1_AGC2I0  0xf437
+#define F0900_P1_AGC2_INTEGRATOR0  0xf43700ff
+
+/*P1_CARCFG*/
+#define R0900_P1_CARCFG  0xf438
+#define F0900_P1_CFRUPLOW_AUTO  0xf4380080
+#define F0900_P1_CFRUPLOW_TEST  0xf4380040
+#define F0900_P1_EN_CAR2CENTER  0xf4380020
+#define F0900_P1_CARHDR_NODIV8  0xf4380010
+#define F0900_P1_I2C_ROTA  0xf4380008
+#define F0900_P1_ROTAON  0xf4380004
+#define F0900_P1_PH_DET_ALGO  0xf4380003
+
+/*P1_ACLC*/
+#define R0900_P1_ACLC  0xf439
+#define F0900_P1_STOP_S2ALPHA  0xf43900c0
+#define F0900_P1_CAR_ALPHA_MANT  0xf4390030
+#define F0900_P1_CAR_ALPHA_EXP  0xf439000f
+
+/*P1_BCLC*/
+#define R0900_P1_BCLC  0xf43a
+#define F0900_P1_STOP_S2BETA  0xf43a00c0
+#define F0900_P1_CAR_BETA_MANT  0xf43a0030
+#define F0900_P1_CAR_BETA_EXP  0xf43a000f
+
+/*P1_CARFREQ*/
+#define R0900_P1_CARFREQ  0xf43d
+#define F0900_P1_KC_COARSE_EXP  0xf43d00f0
+#define F0900_P1_BETA_FREQ  0xf43d000f
+
+/*P1_CARHDR*/
+#define R0900_P1_CARHDR  0xf43e
+#define F0900_P1_K_FREQ_HDR  0xf43e00ff
+
+/*P1_LDT*/
+#define R0900_P1_LDT  0xf43f
+#define F0900_P1_CARLOCK_THRES  0xf43f01ff
+
+/*P1_LDT2*/
+#define R0900_P1_LDT2  0xf440
+#define F0900_P1_CARLOCK_THRES2  0xf44001ff
+
+/*P1_CFRICFG*/
+#define R0900_P1_CFRICFG  0xf441
+#define F0900_P1_CFRINIT_UNVALRNG  0xf4410080
+#define F0900_P1_CFRINIT_LUNVALCPT  0xf4410040
+#define F0900_P1_CFRINIT_ABORTDBL  0xf4410020
+#define F0900_P1_CFRINIT_ABORTPRED  0xf4410010
+#define F0900_P1_CFRINIT_UNVALSKIP  0xf4410008
+#define F0900_P1_CFRINIT_CSTINC  0xf4410004
+#define F0900_P1_NEG_CFRSTEP  0xf4410001
+
+/*P1_CFRUP1*/
+#define R0900_P1_CFRUP1  0xf442
+#define F0900_P1_CFR_UP1  0xf44201ff
+
+/*P1_CFRUP0*/
+#define R0900_P1_CFRUP0  0xf443
+#define F0900_P1_CFR_UP0  0xf44300ff
+
+/*P1_CFRLOW1*/
+#define R0900_P1_CFRLOW1  0xf446
+#define F0900_P1_CFR_LOW1  0xf44601ff
+
+/*P1_CFRLOW0*/
+#define R0900_P1_CFRLOW0  0xf447
+#define F0900_P1_CFR_LOW0  0xf44700ff
+
+/*P1_CFRINIT1*/
+#define R0900_P1_CFRINIT1  0xf448
+#define F0900_P1_CFR_INIT1  0xf44801ff
+
+/*P1_CFRINIT0*/
+#define R0900_P1_CFRINIT0  0xf449
+#define F0900_P1_CFR_INIT0  0xf44900ff
+
+/*P1_CFRINC1*/
+#define R0900_P1_CFRINC1  0xf44a
+#define F0900_P1_MANUAL_CFRINC  0xf44a0080
+#define F0900_P1_CFR_INC1  0xf44a017f
+
+/*P1_CFRINC0*/
+#define R0900_P1_CFRINC0  0xf44b
+#define F0900_P1_CFR_INC0  0xf44b00f0
+
+/*P1_CFR2*/
+#define R0900_P1_CFR2  0xf44c
+#define F0900_P1_CAR_FREQ2  0xf44c01ff
+
+/*P1_CFR1*/
+#define R0900_P1_CFR1  0xf44d
+#define F0900_P1_CAR_FREQ1  0xf44d00ff
+
+/*P1_CFR0*/
+#define R0900_P1_CFR0  0xf44e
+#define F0900_P1_CAR_FREQ0  0xf44e00ff
+
+/*P1_LDI*/
+#define R0900_P1_LDI  0xf44f
+#define F0900_P1_LOCK_DET_INTEGR  0xf44f01ff
+
+/*P1_TMGCFG*/
+#define R0900_P1_TMGCFG  0xf450
+#define F0900_P1_TMGLOCK_BETA  0xf45000c0
+#define F0900_P1_NOTMG_GROUPDELAY  0xf4500020
+#define F0900_P1_DO_TIMING_CORR  0xf4500010
+#define F0900_P1_MANUAL_SCAN  0xf450000c
+#define F0900_P1_TMG_MINFREQ  0xf4500003
+
+/*P1_RTC*/
+#define R0900_P1_RTC  0xf451
+#define F0900_P1_TMGALPHA_EXP  0xf45100f0
+#define F0900_P1_TMGBETA_EXP  0xf451000f
+
+/*P1_RTCS2*/
+#define R0900_P1_RTCS2  0xf452
+#define F0900_P1_TMGALPHAS2_EXP  0xf45200f0
+#define F0900_P1_TMGBETAS2_EXP  0xf452000f
+
+/*P1_TMGTHRISE*/
+#define R0900_P1_TMGTHRISE  0xf453
+#define F0900_P1_TMGLOCK_THRISE  0xf45300ff
+
+/*P1_TMGTHFALL*/
+#define R0900_P1_TMGTHFALL  0xf454
+#define F0900_P1_TMGLOCK_THFALL  0xf45400ff
+
+/*P1_SFRUPRATIO*/
+#define R0900_P1_SFRUPRATIO  0xf455
+#define F0900_P1_SFR_UPRATIO  0xf45500ff
+
+/*P1_SFRLOWRATIO*/
+#define R0900_P1_SFRLOWRATIO  0xf456
+#define F0900_P1_SFR_LOWRATIO  0xf45600ff
+
+/*P1_KREFTMG*/
+#define R0900_P1_KREFTMG  0xf458
+#define F0900_P1_KREF_TMG  0xf45800ff
+
+/*P1_SFRSTEP*/
+#define R0900_P1_SFRSTEP  0xf459
+#define F0900_P1_SFR_SCANSTEP  0xf45900f0
+#define F0900_P1_SFR_CENTERSTEP  0xf459000f
+
+/*P1_TMGCFG2*/
+#define R0900_P1_TMGCFG2  0xf45a
+#define F0900_P1_DIS_AUTOSAMP  0xf45a0008
+#define F0900_P1_SCANINIT_QUART  0xf45a0004
+#define F0900_P1_NOTMG_DVBS1DERAT  0xf45a0002
+#define F0900_P1_SFRRATIO_FINE  0xf45a0001
+
+/*P1_SFRINIT1*/
+#define R0900_P1_SFRINIT1  0xf45e
+#define F0900_P1_SFR_INIT1  0xf45e00ff
+
+/*P1_SFRINIT0*/
+#define R0900_P1_SFRINIT0  0xf45f
+#define F0900_P1_SFR_INIT0  0xf45f00ff
+
+/*P1_SFRUP1*/
+#define R0900_P1_SFRUP1  0xf460
+#define F0900_P1_AUTO_GUP  0xf4600080
+#define F0900_P1_SYMB_FREQ_UP1  0xf460007f
+
+/*P1_SFRUP0*/
+#define R0900_P1_SFRUP0  0xf461
+#define F0900_P1_SYMB_FREQ_UP0  0xf46100ff
+
+/*P1_SFRLOW1*/
+#define R0900_P1_SFRLOW1  0xf462
+#define F0900_P1_AUTO_GLOW  0xf4620080
+#define F0900_P1_SYMB_FREQ_LOW1  0xf462007f
+
+/*P1_SFRLOW0*/
+#define R0900_P1_SFRLOW0  0xf463
+#define F0900_P1_SYMB_FREQ_LOW0  0xf46300ff
+
+/*P1_SFR3*/
+#define R0900_P1_SFR3  0xf464
+#define F0900_P1_SYMB_FREQ3  0xf46400ff
+
+/*P1_SFR2*/
+#define R0900_P1_SFR2  0xf465
+#define F0900_P1_SYMB_FREQ2  0xf46500ff
+
+/*P1_SFR1*/
+#define R0900_P1_SFR1  0xf466
+#define F0900_P1_SYMB_FREQ1  0xf46600ff
+
+/*P1_SFR0*/
+#define R0900_P1_SFR0  0xf467
+#define F0900_P1_SYMB_FREQ0  0xf46700ff
+
+/*P1_TMGREG2*/
+#define R0900_P1_TMGREG2  0xf468
+#define F0900_P1_TMGREG2  0xf46800ff
+
+/*P1_TMGREG1*/
+#define R0900_P1_TMGREG1  0xf469
+#define F0900_P1_TMGREG1  0xf46900ff
+
+/*P1_TMGREG0*/
+#define R0900_P1_TMGREG0  0xf46a
+#define F0900_P1_TMGREG0  0xf46a00ff
+
+/*P1_TMGLOCK1*/
+#define R0900_P1_TMGLOCK1  0xf46b
+#define F0900_P1_TMGLOCK_LEVEL1  0xf46b01ff
+
+/*P1_TMGLOCK0*/
+#define R0900_P1_TMGLOCK0  0xf46c
+#define F0900_P1_TMGLOCK_LEVEL0  0xf46c00ff
+
+/*P1_TMGOBS*/
+#define R0900_P1_TMGOBS  0xf46d
+#define F0900_P1_ROLLOFF_STATUS  0xf46d00c0
+#define F0900_P1_SCAN_SIGN  0xf46d0030
+#define F0900_P1_TMG_SCANNING  0xf46d0008
+#define F0900_P1_CHCENTERING_MODE  0xf46d0004
+#define F0900_P1_TMG_SCANFAIL  0xf46d0002
+
+/*P1_EQUALCFG*/
+#define R0900_P1_EQUALCFG  0xf46f
+#define F0900_P1_NOTMG_NEGALWAIT  0xf46f0080
+#define F0900_P1_EQUAL_ON  0xf46f0040
+#define F0900_P1_SEL_EQUALCOR  0xf46f0038
+#define F0900_P1_MU_EQUALDFE  0xf46f0007
+
+/*P1_EQUAI1*/
+#define R0900_P1_EQUAI1  0xf470
+#define F0900_P1_EQUA_ACCI1  0xf47001ff
+
+/*P1_EQUAQ1*/
+#define R0900_P1_EQUAQ1  0xf471
+#define F0900_P1_EQUA_ACCQ1  0xf47101ff
+
+/*P1_EQUAI2*/
+#define R0900_P1_EQUAI2  0xf472
+#define F0900_P1_EQUA_ACCI2  0xf47201ff
+
+/*P1_EQUAQ2*/
+#define R0900_P1_EQUAQ2  0xf473
+#define F0900_P1_EQUA_ACCQ2  0xf47301ff
+
+/*P1_EQUAI3*/
+#define R0900_P1_EQUAI3  0xf474
+#define F0900_P1_EQUA_ACCI3  0xf47401ff
+
+/*P1_EQUAQ3*/
+#define R0900_P1_EQUAQ3  0xf475
+#define F0900_P1_EQUA_ACCQ3  0xf47501ff
+
+/*P1_EQUAI4*/
+#define R0900_P1_EQUAI4  0xf476
+#define F0900_P1_EQUA_ACCI4  0xf47601ff
+
+/*P1_EQUAQ4*/
+#define R0900_P1_EQUAQ4  0xf477
+#define F0900_P1_EQUA_ACCQ4  0xf47701ff
+
+/*P1_EQUAI5*/
+#define R0900_P1_EQUAI5  0xf478
+#define F0900_P1_EQUA_ACCI5  0xf47801ff
+
+/*P1_EQUAQ5*/
+#define R0900_P1_EQUAQ5  0xf479
+#define F0900_P1_EQUA_ACCQ5  0xf47901ff
+
+/*P1_EQUAI6*/
+#define R0900_P1_EQUAI6  0xf47a
+#define F0900_P1_EQUA_ACCI6  0xf47a01ff
+
+/*P1_EQUAQ6*/
+#define R0900_P1_EQUAQ6  0xf47b
+#define F0900_P1_EQUA_ACCQ6  0xf47b01ff
+
+/*P1_EQUAI7*/
+#define R0900_P1_EQUAI7  0xf47c
+#define F0900_P1_EQUA_ACCI7  0xf47c01ff
+
+/*P1_EQUAQ7*/
+#define R0900_P1_EQUAQ7  0xf47d
+#define F0900_P1_EQUA_ACCQ7  0xf47d01ff
+
+/*P1_EQUAI8*/
+#define R0900_P1_EQUAI8  0xf47e
+#define F0900_P1_EQUA_ACCI8  0xf47e01ff
+
+/*P1_EQUAQ8*/
+#define R0900_P1_EQUAQ8  0xf47f
+#define F0900_P1_EQUA_ACCQ8  0xf47f01ff
+
+/*P1_NNOSDATAT1*/
+#define R0900_P1_NNOSDATAT1  0xf480
+#define F0900_P1_NOSDATAT_NORMED1  0xf48000ff
+
+/*P1_NNOSDATAT0*/
+#define R0900_P1_NNOSDATAT0  0xf481
+#define F0900_P1_NOSDATAT_NORMED0  0xf48100ff
+
+/*P1_NNOSDATA1*/
+#define R0900_P1_NNOSDATA1  0xf482
+#define F0900_P1_NOSDATA_NORMED1  0xf48200ff
+
+/*P1_NNOSDATA0*/
+#define R0900_P1_NNOSDATA0  0xf483
+#define F0900_P1_NOSDATA_NORMED0  0xf48300ff
+
+/*P1_NNOSPLHT1*/
+#define R0900_P1_NNOSPLHT1  0xf484
+#define F0900_P1_NOSPLHT_NORMED1  0xf48400ff
+
+/*P1_NNOSPLHT0*/
+#define R0900_P1_NNOSPLHT0  0xf485
+#define F0900_P1_NOSPLHT_NORMED0  0xf48500ff
+
+/*P1_NNOSPLH1*/
+#define R0900_P1_NNOSPLH1  0xf486
+#define F0900_P1_NOSPLH_NORMED1  0xf48600ff
+
+/*P1_NNOSPLH0*/
+#define R0900_P1_NNOSPLH0  0xf487
+#define F0900_P1_NOSPLH_NORMED0  0xf48700ff
+
+/*P1_NOSDATAT1*/
+#define R0900_P1_NOSDATAT1  0xf488
+#define F0900_P1_NOSDATAT_UNNORMED1  0xf48800ff
+
+/*P1_NOSDATAT0*/
+#define R0900_P1_NOSDATAT0  0xf489
+#define F0900_P1_NOSDATAT_UNNORMED0  0xf48900ff
+
+/*P1_NOSDATA1*/
+#define R0900_P1_NOSDATA1  0xf48a
+#define F0900_P1_NOSDATA_UNNORMED1  0xf48a00ff
+
+/*P1_NOSDATA0*/
+#define R0900_P1_NOSDATA0  0xf48b
+#define F0900_P1_NOSDATA_UNNORMED0  0xf48b00ff
+
+/*P1_NOSPLHT1*/
+#define R0900_P1_NOSPLHT1  0xf48c
+#define F0900_P1_NOSPLHT_UNNORMED1  0xf48c00ff
+
+/*P1_NOSPLHT0*/
+#define R0900_P1_NOSPLHT0  0xf48d
+#define F0900_P1_NOSPLHT_UNNORMED0  0xf48d00ff
+
+/*P1_NOSPLH1*/
+#define R0900_P1_NOSPLH1  0xf48e
+#define F0900_P1_NOSPLH_UNNORMED1  0xf48e00ff
+
+/*P1_NOSPLH0*/
+#define R0900_P1_NOSPLH0  0xf48f
+#define F0900_P1_NOSPLH_UNNORMED0  0xf48f00ff
+
+/*P1_CAR2CFG*/
+#define R0900_P1_CAR2CFG  0xf490
+#define F0900_P1_DESCRAMB_OFF  0xf4900080
+#define F0900_P1_PN4_SELECT  0xf4900040
+#define F0900_P1_CFR2_STOPDVBS1  0xf4900020
+#define F0900_P1_STOP_CFR2UPDATE  0xf4900010
+#define F0900_P1_STOP_NCO2UPDATE  0xf4900008
+#define F0900_P1_ROTA2ON  0xf4900004
+#define F0900_P1_PH_DET_ALGO2  0xf4900003
+
+/*P1_ACLC2*/
+#define R0900_P1_ACLC2  0xf491
+#define F0900_P1_CAR2_PUNCT_ADERAT  0xf4910040
+#define F0900_P1_CAR2_ALPHA_MANT  0xf4910030
+#define F0900_P1_CAR2_ALPHA_EXP  0xf491000f
+
+/*P1_BCLC2*/
+#define R0900_P1_BCLC2  0xf492
+#define F0900_P1_DVBS2_NIP  0xf4920080
+#define F0900_P1_CAR2_PUNCT_BDERAT  0xf4920040
+#define F0900_P1_CAR2_BETA_MANT  0xf4920030
+#define F0900_P1_CAR2_BETA_EXP  0xf492000f
+
+/*P1_CFR22*/
+#define R0900_P1_CFR22  0xf493
+#define F0900_P1_CAR2_FREQ2  0xf49301ff
+
+/*P1_CFR21*/
+#define R0900_P1_CFR21  0xf494
+#define F0900_P1_CAR2_FREQ1  0xf49400ff
+
+/*P1_CFR20*/
+#define R0900_P1_CFR20  0xf495
+#define F0900_P1_CAR2_FREQ0  0xf49500ff
+
+/*P1_ACLC2S2Q*/
+#define R0900_P1_ACLC2S2Q  0xf497
+#define F0900_P1_ENAB_SPSKSYMB  0xf4970080
+#define F0900_P1_CAR2S2_QADERAT  0xf4970040
+#define F0900_P1_CAR2S2_Q_ALPH_M  0xf4970030
+#define F0900_P1_CAR2S2_Q_ALPH_E  0xf497000f
+
+/*P1_ACLC2S28*/
+#define R0900_P1_ACLC2S28  0xf498
+#define F0900_P1_OLDI3Q_MODE  0xf4980080
+#define F0900_P1_CAR2S2_8ADERAT  0xf4980040
+#define F0900_P1_CAR2S2_8_ALPH_M  0xf4980030
+#define F0900_P1_CAR2S2_8_ALPH_E  0xf498000f
+
+/*P1_ACLC2S216A*/
+#define R0900_P1_ACLC2S216A  0xf499
+#define F0900_P1_CAR2S2_16ADERAT  0xf4990040
+#define F0900_P1_CAR2S2_16A_ALPH_M  0xf4990030
+#define F0900_P1_CAR2S2_16A_ALPH_E  0xf499000f
+
+/*P1_ACLC2S232A*/
+#define R0900_P1_ACLC2S232A  0xf49a
+#define F0900_P1_CAR2S2_32ADERAT  0xf49a0040
+#define F0900_P1_CAR2S2_32A_ALPH_M  0xf49a0030
+#define F0900_P1_CAR2S2_32A_ALPH_E  0xf49a000f
+
+/*P1_BCLC2S2Q*/
+#define R0900_P1_BCLC2S2Q  0xf49c
+#define F0900_P1_DVBS2S2Q_NIP  0xf49c0080
+#define F0900_P1_CAR2S2_QBDERAT  0xf49c0040
+#define F0900_P1_CAR2S2_Q_BETA_M  0xf49c0030
+#define F0900_P1_CAR2S2_Q_BETA_E  0xf49c000f
+
+/*P1_BCLC2S28*/
+#define R0900_P1_BCLC2S28  0xf49d
+#define F0900_P1_DVBS2S28_NIP  0xf49d0080
+#define F0900_P1_CAR2S2_8BDERAT  0xf49d0040
+#define F0900_P1_CAR2S2_8_BETA_M  0xf49d0030
+#define F0900_P1_CAR2S2_8_BETA_E  0xf49d000f
+
+/*P1_BCLC2S216A*/
+#define R0900_P1_BCLC2S216A  0xf49e
+#define F0900_P1_DVBS2S216A_NIP  0xf49e0080
+#define F0900_P1_CAR2S2_16BDERAT  0xf49e0040
+#define F0900_P1_CAR2S2_16A_BETA_M  0xf49e0030
+#define F0900_P1_CAR2S2_16A_BETA_E  0xf49e000f
+
+/*P1_BCLC2S232A*/
+#define R0900_P1_BCLC2S232A  0xf49f
+#define F0900_P1_DVBS2S232A_NIP  0xf49f0080
+#define F0900_P1_CAR2S2_32BDERAT  0xf49f0040
+#define F0900_P1_CAR2S2_32A_BETA_M  0xf49f0030
+#define F0900_P1_CAR2S2_32A_BETA_E  0xf49f000f
+
+/*P1_PLROOT2*/
+#define R0900_P1_PLROOT2  0xf4ac
+#define F0900_P1_SHORTFR_DISABLE  0xf4ac0080
+#define F0900_P1_LONGFR_DISABLE  0xf4ac0040
+#define F0900_P1_DUMMYPL_DISABLE  0xf4ac0020
+#define F0900_P1_SHORTFR_AVOID  0xf4ac0010
+#define F0900_P1_PLSCRAMB_MODE  0xf4ac000c
+#define F0900_P1_PLSCRAMB_ROOT2  0xf4ac0003
+
+/*P1_PLROOT1*/
+#define R0900_P1_PLROOT1  0xf4ad
+#define F0900_P1_PLSCRAMB_ROOT1  0xf4ad00ff
+
+/*P1_PLROOT0*/
+#define R0900_P1_PLROOT0  0xf4ae
+#define F0900_P1_PLSCRAMB_ROOT0  0xf4ae00ff
+
+/*P1_MODCODLST0*/
+#define R0900_P1_MODCODLST0  0xf4b0
+#define F0900_P1_EN_TOKEN31  0xf4b00080
+#define F0900_P1_SYNCTAG_SELECT  0xf4b00040
+#define F0900_P1_MODCODRQ_MODE  0xf4b00030
+
+/*P1_MODCODLST1*/
+#define R0900_P1_MODCODLST1  0xf4b1
+#define F0900_P1_DIS_MODCOD29  0xf4b100f0
+#define F0900_P1_DIS_32PSK_9_10  0xf4b1000f
+
+/*P1_MODCODLST2*/
+#define R0900_P1_MODCODLST2  0xf4b2
+#define F0900_P1_DIS_32PSK_8_9  0xf4b200f0
+#define F0900_P1_DIS_32PSK_5_6  0xf4b2000f
+
+/*P1_MODCODLST3*/
+#define R0900_P1_MODCODLST3  0xf4b3
+#define F0900_P1_DIS_32PSK_4_5  0xf4b300f0
+#define F0900_P1_DIS_32PSK_3_4  0xf4b3000f
+
+/*P1_MODCODLST4*/
+#define R0900_P1_MODCODLST4  0xf4b4
+#define F0900_P1_DIS_16PSK_9_10  0xf4b400f0
+#define F0900_P1_DIS_16PSK_8_9  0xf4b4000f
+
+/*P1_MODCODLST5*/
+#define R0900_P1_MODCODLST5  0xf4b5
+#define F0900_P1_DIS_16PSK_5_6  0xf4b500f0
+#define F0900_P1_DIS_16PSK_4_5  0xf4b5000f
+
+/*P1_MODCODLST6*/
+#define R0900_P1_MODCODLST6  0xf4b6
+#define F0900_P1_DIS_16PSK_3_4  0xf4b600f0
+#define F0900_P1_DIS_16PSK_2_3  0xf4b6000f
+
+/*P1_MODCODLST7*/
+#define R0900_P1_MODCODLST7  0xf4b7
+#define F0900_P1_DIS_8P_9_10  0xf4b700f0
+#define F0900_P1_DIS_8P_8_9  0xf4b7000f
+
+/*P1_MODCODLST8*/
+#define R0900_P1_MODCODLST8  0xf4b8
+#define F0900_P1_DIS_8P_5_6  0xf4b800f0
+#define F0900_P1_DIS_8P_3_4  0xf4b8000f
+
+/*P1_MODCODLST9*/
+#define R0900_P1_MODCODLST9  0xf4b9
+#define F0900_P1_DIS_8P_2_3  0xf4b900f0
+#define F0900_P1_DIS_8P_3_5  0xf4b9000f
+
+/*P1_MODCODLSTA*/
+#define R0900_P1_MODCODLSTA  0xf4ba
+#define F0900_P1_DIS_QP_9_10  0xf4ba00f0
+#define F0900_P1_DIS_QP_8_9  0xf4ba000f
+
+/*P1_MODCODLSTB*/
+#define R0900_P1_MODCODLSTB  0xf4bb
+#define F0900_P1_DIS_QP_5_6  0xf4bb00f0
+#define F0900_P1_DIS_QP_4_5  0xf4bb000f
+
+/*P1_MODCODLSTC*/
+#define R0900_P1_MODCODLSTC  0xf4bc
+#define F0900_P1_DIS_QP_3_4  0xf4bc00f0
+#define F0900_P1_DIS_QP_2_3  0xf4bc000f
+
+/*P1_MODCODLSTD*/
+#define R0900_P1_MODCODLSTD  0xf4bd
+#define F0900_P1_DIS_QP_3_5  0xf4bd00f0
+#define F0900_P1_DIS_QP_1_2  0xf4bd000f
+
+/*P1_MODCODLSTE*/
+#define R0900_P1_MODCODLSTE  0xf4be
+#define F0900_P1_DIS_QP_2_5  0xf4be00f0
+#define F0900_P1_DIS_QP_1_3  0xf4be000f
+
+/*P1_MODCODLSTF*/
+#define R0900_P1_MODCODLSTF  0xf4bf
+#define F0900_P1_DIS_QP_1_4  0xf4bf00f0
+#define F0900_P1_DDEMOD_SET  0xf4bf0002
+#define F0900_P1_DDEMOD_MASK  0xf4bf0001
+
+/*P1_DMDRESCFG*/
+#define R0900_P1_DMDRESCFG  0xf4c6
+#define F0900_P1_DMDRES_RESET  0xf4c60080
+#define F0900_P1_DMDRES_NOISESQR  0xf4c60010
+#define F0900_P1_DMDRES_STRALL  0xf4c60008
+#define F0900_P1_DMDRES_NEWONLY  0xf4c60004
+#define F0900_P1_DMDRES_NOSTORE  0xf4c60002
+#define F0900_P1_DMDRES_AGC2MEM  0xf4c60001
+
+/*P1_DMDRESADR*/
+#define R0900_P1_DMDRESADR  0xf4c7
+#define F0900_P1_SUSP_PREDCANAL  0xf4c70080
+#define F0900_P1_DMDRES_VALIDCFR  0xf4c70040
+#define F0900_P1_DMDRES_MEMFULL  0xf4c70030
+#define F0900_P1_DMDRES_RESNBR  0xf4c7000f
+
+/*P1_DMDRESDATA7*/
+#define R0900_P1_DMDRESDATA7  0xf4c8
+#define F0900_P1_DMDRES_DATA7  0xf4c800ff
+
+/*P1_DMDRESDATA6*/
+#define R0900_P1_DMDRESDATA6  0xf4c9
+#define F0900_P1_DMDRES_DATA6  0xf4c900ff
+
+/*P1_DMDRESDATA5*/
+#define R0900_P1_DMDRESDATA5  0xf4ca
+#define F0900_P1_DMDRES_DATA5  0xf4ca00ff
+
+/*P1_DMDRESDATA4*/
+#define R0900_P1_DMDRESDATA4  0xf4cb
+#define F0900_P1_DMDRES_DATA4  0xf4cb00ff
+
+/*P1_DMDRESDATA3*/
+#define R0900_P1_DMDRESDATA3  0xf4cc
+#define F0900_P1_DMDRES_DATA3  0xf4cc00ff
+
+/*P1_DMDRESDATA2*/
+#define R0900_P1_DMDRESDATA2  0xf4cd
+#define F0900_P1_DMDRES_DATA2  0xf4cd00ff
+
+/*P1_DMDRESDATA1*/
+#define R0900_P1_DMDRESDATA1  0xf4ce
+#define F0900_P1_DMDRES_DATA1  0xf4ce00ff
+
+/*P1_DMDRESDATA0*/
+#define R0900_P1_DMDRESDATA0  0xf4cf
+#define F0900_P1_DMDRES_DATA0  0xf4cf00ff
+
+/*P1_FFEI1*/
+#define R0900_P1_FFEI1  0xf4d0
+#define F0900_P1_FFE_ACCI1  0xf4d001ff
+
+/*P1_FFEQ1*/
+#define R0900_P1_FFEQ1  0xf4d1
+#define F0900_P1_FFE_ACCQ1  0xf4d101ff
+
+/*P1_FFEI2*/
+#define R0900_P1_FFEI2  0xf4d2
+#define F0900_P1_FFE_ACCI2  0xf4d201ff
+
+/*P1_FFEQ2*/
+#define R0900_P1_FFEQ2  0xf4d3
+#define F0900_P1_FFE_ACCQ2  0xf4d301ff
+
+/*P1_FFEI3*/
+#define R0900_P1_FFEI3  0xf4d4
+#define F0900_P1_FFE_ACCI3  0xf4d401ff
+
+/*P1_FFEQ3*/
+#define R0900_P1_FFEQ3  0xf4d5
+#define F0900_P1_FFE_ACCQ3  0xf4d501ff
+
+/*P1_FFEI4*/
+#define R0900_P1_FFEI4  0xf4d6
+#define F0900_P1_FFE_ACCI4  0xf4d601ff
+
+/*P1_FFEQ4*/
+#define R0900_P1_FFEQ4  0xf4d7
+#define F0900_P1_FFE_ACCQ4  0xf4d701ff
+
+/*P1_FFECFG*/
+#define R0900_P1_FFECFG  0xf4d8
+#define F0900_P1_EQUALFFE_ON  0xf4d80040
+#define F0900_P1_EQUAL_USEDSYMB  0xf4d80030
+#define F0900_P1_MU_EQUALFFE  0xf4d80007
+
+/*P1_TNRCFG*/
+#define R0900_P1_TNRCFG  0xf4e0
+#define F0900_P1_TUN_ACKFAIL  0xf4e00080
+#define F0900_P1_TUN_TYPE  0xf4e00070
+#define F0900_P1_TUN_SECSTOP  0xf4e00008
+#define F0900_P1_TUN_VCOSRCH  0xf4e00004
+#define F0900_P1_TUN_MADDRESS  0xf4e00003
+
+/*P1_TNRCFG2*/
+#define R0900_P1_TNRCFG2  0xf4e1
+#define F0900_P1_TUN_IQSWAP  0xf4e10080
+#define F0900_P1_STB6110_STEP2MHZ  0xf4e10040
+#define F0900_P1_STB6120_DBLI2C  0xf4e10020
+#define F0900_P1_DIS_FCCK  0xf4e10010
+#define F0900_P1_DIS_LPEN  0xf4e10008
+#define F0900_P1_DIS_BWCALC  0xf4e10004
+#define F0900_P1_SHORT_WAITSTATES  0xf4e10002
+#define F0900_P1_DIS_2BWAGC1  0xf4e10001
+
+/*P1_TNRXTAL*/
+#define R0900_P1_TNRXTAL  0xf4e4
+#define F0900_P1_TUN_MCLKDECIMAL  0xf4e400e0
+#define F0900_P1_TUN_XTALFREQ  0xf4e4001f
+
+/*P1_TNRSTEPS*/
+#define R0900_P1_TNRSTEPS  0xf4e7
+#define F0900_P1_TUNER_BW1P6  0xf4e70080
+#define F0900_P1_BWINC_OFFSET  0xf4e70070
+#define F0900_P1_SOFTSTEP_RNG  0xf4e70008
+#define F0900_P1_TUN_BWOFFSET  0xf4e70107
+
+/*P1_TNRGAIN*/
+#define R0900_P1_TNRGAIN  0xf4e8
+#define F0900_P1_TUN_KDIVEN  0xf4e800c0
+#define F0900_P1_STB6X00_OCK  0xf4e80030
+#define F0900_P1_TUN_GAIN  0xf4e8000f
+
+/*P1_TNRRF1*/
+#define R0900_P1_TNRRF1  0xf4e9
+#define F0900_P1_TUN_RFFREQ2  0xf4e900ff
+
+/*P1_TNRRF0*/
+#define R0900_P1_TNRRF0  0xf4ea
+#define F0900_P1_TUN_RFFREQ1  0xf4ea00ff
+
+/*P1_TNRBW*/
+#define R0900_P1_TNRBW  0xf4eb
+#define F0900_P1_TUN_RFFREQ0  0xf4eb00c0
+#define F0900_P1_TUN_BW  0xf4eb003f
+
+/*P1_TNRADJ*/
+#define R0900_P1_TNRADJ  0xf4ec
+#define F0900_P1_STB61X0_RCLK  0xf4ec0080
+#define F0900_P1_STB61X0_CALTIME  0xf4ec0040
+#define F0900_P1_STB6X00_DLB  0xf4ec0038
+#define F0900_P1_STB6000_FCL  0xf4ec0007
+
+/*P1_TNRCTL2*/
+#define R0900_P1_TNRCTL2  0xf4ed
+#define F0900_P1_STB61X0_LCP1_RCCKOFF  0xf4ed0080
+#define F0900_P1_STB61X0_LCP0  0xf4ed0040
+#define F0900_P1_STB61X0_XTOUT_RFOUTS  0xf4ed0020
+#define F0900_P1_STB61X0_XTON_MCKDV  0xf4ed0010
+#define F0900_P1_STB61X0_CALOFF_DCOFF  0xf4ed0008
+#define F0900_P1_STB6110_LPT  0xf4ed0004
+#define F0900_P1_STB6110_RX  0xf4ed0002
+#define F0900_P1_STB6110_SYN  0xf4ed0001
+
+/*P1_TNRCFG3*/
+#define R0900_P1_TNRCFG3  0xf4ee
+#define F0900_P1_STB6120_DISCTRL1  0xf4ee0080
+#define F0900_P1_STB6120_INVORDER  0xf4ee0040
+#define F0900_P1_STB6120_ENCTRL6  0xf4ee0020
+#define F0900_P1_TUN_PLLFREQ  0xf4ee001c
+#define F0900_P1_TUN_I2CFREQ_MODE  0xf4ee0003
+
+/*P1_TNRLAUNCH*/
+#define R0900_P1_TNRLAUNCH  0xf4f0
+
+/*P1_TNRLD*/
+#define R0900_P1_TNRLD  0xf4f0
+#define F0900_P1_TUNLD_VCOING  0xf4f00080
+#define F0900_P1_TUN_REG1FAIL  0xf4f00040
+#define F0900_P1_TUN_REG2FAIL  0xf4f00020
+#define F0900_P1_TUN_REG3FAIL  0xf4f00010
+#define F0900_P1_TUN_REG4FAIL  0xf4f00008
+#define F0900_P1_TUN_REG5FAIL  0xf4f00004
+#define F0900_P1_TUN_BWING  0xf4f00002
+#define F0900_P1_TUN_LOCKED  0xf4f00001
+
+/*P1_TNROBSL*/
+#define R0900_P1_TNROBSL  0xf4f6
+#define F0900_P1_TUN_I2CABORTED  0xf4f60080
+#define F0900_P1_TUN_LPEN  0xf4f60040
+#define F0900_P1_TUN_FCCK  0xf4f60020
+#define F0900_P1_TUN_I2CLOCKED  0xf4f60010
+#define F0900_P1_TUN_PROGDONE  0xf4f6000c
+#define F0900_P1_TUN_RFRESTE1  0xf4f60003
+
+/*P1_TNRRESTE*/
+#define R0900_P1_TNRRESTE  0xf4f7
+#define F0900_P1_TUN_RFRESTE0  0xf4f700ff
+
+/*P1_SMAPCOEF7*/
+#define R0900_P1_SMAPCOEF7  0xf500
+#define F0900_P1_DIS_QSCALE  0xf5000080
+#define F0900_P1_SMAPCOEF_Q_LLR12  0xf500017f
+
+/*P1_SMAPCOEF6*/
+#define R0900_P1_SMAPCOEF6  0xf501
+#define F0900_P1_DIS_NEWSCALE  0xf5010008
+#define F0900_P1_ADJ_8PSKLLR1  0xf5010004
+#define F0900_P1_OLD_8PSKLLR1  0xf5010002
+#define F0900_P1_DIS_AB8PSK  0xf5010001
+
+/*P1_SMAPCOEF5*/
+#define R0900_P1_SMAPCOEF5  0xf502
+#define F0900_P1_DIS_8SCALE  0xf5020080
+#define F0900_P1_SMAPCOEF_8P_LLR23  0xf502017f
+
+/*P1_DMDPLHSTAT*/
+#define R0900_P1_DMDPLHSTAT  0xf520
+#define F0900_P1_PLH_STATISTIC  0xf52000ff
+
+/*P1_LOCKTIME3*/
+#define R0900_P1_LOCKTIME3  0xf522
+#define F0900_P1_DEMOD_LOCKTIME3  0xf52200ff
+
+/*P1_LOCKTIME2*/
+#define R0900_P1_LOCKTIME2  0xf523
+#define F0900_P1_DEMOD_LOCKTIME2  0xf52300ff
+
+/*P1_LOCKTIME1*/
+#define R0900_P1_LOCKTIME1  0xf524
+#define F0900_P1_DEMOD_LOCKTIME1  0xf52400ff
+
+/*P1_LOCKTIME0*/
+#define R0900_P1_LOCKTIME0  0xf525
+#define F0900_P1_DEMOD_LOCKTIME0  0xf52500ff
+
+/*P1_VITSCALE*/
+#define R0900_P1_VITSCALE  0xf532
+#define F0900_P1_NVTH_NOSRANGE  0xf5320080
+#define F0900_P1_VERROR_MAXMODE  0xf5320040
+#define F0900_P1_KDIV_MODE  0xf5320030
+#define F0900_P1_NSLOWSN_LOCKED  0xf5320008
+#define F0900_P1_DELOCK_PRFLOSS  0xf5320004
+#define F0900_P1_DIS_RSFLOCK  0xf5320002
+
+/*P1_FECM*/
+#define R0900_P1_FECM  0xf533
+#define F0900_P1_DSS_DVB  0xf5330080
+#define F0900_P1_DEMOD_BYPASS  0xf5330040
+#define F0900_P1_CMP_SLOWMODE  0xf5330020
+#define F0900_P1_DSS_SRCH  0xf5330010
+#define F0900_P1_DIFF_MODEVIT  0xf5330004
+#define F0900_P1_SYNCVIT  0xf5330002
+#define F0900_P1_IQINV  0xf5330001
+
+/*P1_VTH12*/
+#define R0900_P1_VTH12  0xf534
+#define F0900_P1_VTH12  0xf53400ff
+
+/*P1_VTH23*/
+#define R0900_P1_VTH23  0xf535
+#define F0900_P1_VTH23  0xf53500ff
+
+/*P1_VTH34*/
+#define R0900_P1_VTH34  0xf536
+#define F0900_P1_VTH34  0xf53600ff
+
+/*P1_VTH56*/
+#define R0900_P1_VTH56  0xf537
+#define F0900_P1_VTH56  0xf53700ff
+
+/*P1_VTH67*/
+#define R0900_P1_VTH67  0xf538
+#define F0900_P1_VTH67  0xf53800ff
+
+/*P1_VTH78*/
+#define R0900_P1_VTH78  0xf539
+#define F0900_P1_VTH78  0xf53900ff
+
+/*P1_VITCURPUN*/
+#define R0900_P1_VITCURPUN  0xf53a
+#define F0900_P1_VIT_MAPPING  0xf53a00e0
+#define F0900_P1_VIT_CURPUN  0xf53a001f
+
+/*P1_VERROR*/
+#define R0900_P1_VERROR  0xf53b
+#define F0900_P1_REGERR_VIT  0xf53b00ff
+
+/*P1_PRVIT*/
+#define R0900_P1_PRVIT  0xf53c
+#define F0900_P1_DIS_VTHLOCK  0xf53c0040
+#define F0900_P1_E7_8VIT  0xf53c0020
+#define F0900_P1_E6_7VIT  0xf53c0010
+#define F0900_P1_E5_6VIT  0xf53c0008
+#define F0900_P1_E3_4VIT  0xf53c0004
+#define F0900_P1_E2_3VIT  0xf53c0002
+#define F0900_P1_E1_2VIT  0xf53c0001
+
+/*P1_VAVSRVIT*/
+#define R0900_P1_VAVSRVIT  0xf53d
+#define F0900_P1_AMVIT  0xf53d0080
+#define F0900_P1_FROZENVIT  0xf53d0040
+#define F0900_P1_SNVIT  0xf53d0030
+#define F0900_P1_TOVVIT  0xf53d000c
+#define F0900_P1_HYPVIT  0xf53d0003
+
+/*P1_VSTATUSVIT*/
+#define R0900_P1_VSTATUSVIT  0xf53e
+#define F0900_P1_VITERBI_ON  0xf53e0080
+#define F0900_P1_END_LOOPVIT  0xf53e0040
+#define F0900_P1_VITERBI_DEPRF  0xf53e0020
+#define F0900_P1_PRFVIT  0xf53e0010
+#define F0900_P1_LOCKEDVIT  0xf53e0008
+#define F0900_P1_VITERBI_DELOCK  0xf53e0004
+#define F0900_P1_VIT_DEMODSEL  0xf53e0002
+#define F0900_P1_VITERBI_COMPOUT  0xf53e0001
+
+/*P1_VTHINUSE*/
+#define R0900_P1_VTHINUSE  0xf53f
+#define F0900_P1_VIT_INUSE  0xf53f00ff
+
+/*P1_KDIV12*/
+#define R0900_P1_KDIV12  0xf540
+#define F0900_P1_KDIV12_MANUAL  0xf5400080
+#define F0900_P1_K_DIVIDER_12  0xf540007f
+
+/*P1_KDIV23*/
+#define R0900_P1_KDIV23  0xf541
+#define F0900_P1_KDIV23_MANUAL  0xf5410080
+#define F0900_P1_K_DIVIDER_23  0xf541007f
+
+/*P1_KDIV34*/
+#define R0900_P1_KDIV34  0xf542
+#define F0900_P1_KDIV34_MANUAL  0xf5420080
+#define F0900_P1_K_DIVIDER_34  0xf542007f
+
+/*P1_KDIV56*/
+#define R0900_P1_KDIV56  0xf543
+#define F0900_P1_KDIV56_MANUAL  0xf5430080
+#define F0900_P1_K_DIVIDER_56  0xf543007f
+
+/*P1_KDIV67*/
+#define R0900_P1_KDIV67  0xf544
+#define F0900_P1_KDIV67_MANUAL  0xf5440080
+#define F0900_P1_K_DIVIDER_67  0xf544007f
+
+/*P1_KDIV78*/
+#define R0900_P1_KDIV78  0xf545
+#define F0900_P1_KDIV78_MANUAL  0xf5450080
+#define F0900_P1_K_DIVIDER_78  0xf545007f
+
+/*P1_PDELCTRL1*/
+#define R0900_P1_PDELCTRL1  0xf550
+#define F0900_P1_INV_MISMASK  0xf5500080
+#define F0900_P1_FORCE_ACCEPTED  0xf5500040
+#define F0900_P1_FILTER_EN  0xf5500020
+#define F0900_P1_FORCE_PKTDELINUSE  0xf5500010
+#define F0900_P1_HYSTEN  0xf5500008
+#define F0900_P1_HYSTSWRST  0xf5500004
+#define F0900_P1_EN_MIS00  0xf5500002
+#define F0900_P1_ALGOSWRST  0xf5500001
+
+/*P1_PDELCTRL2*/
+#define R0900_P1_PDELCTRL2  0xf551
+#define F0900_P1_FORCE_CONTINUOUS  0xf5510080
+#define F0900_P1_RESET_UPKO_COUNT  0xf5510040
+#define F0900_P1_USER_PKTDELIN_NB  0xf5510020
+#define F0900_P1_FORCE_LOCKED  0xf5510010
+#define F0900_P1_DATA_UNBBSCRAM  0xf5510008
+#define F0900_P1_FORCE_LONGPKT  0xf5510004
+#define F0900_P1_FRAME_MODE  0xf5510002
+
+/*P1_HYSTTHRESH*/
+#define R0900_P1_HYSTTHRESH  0xf554
+#define F0900_P1_UNLCK_THRESH  0xf55400f0
+#define F0900_P1_DELIN_LCK_THRESH  0xf554000f
+
+/*P1_ISIENTRY*/
+#define R0900_P1_ISIENTRY  0xf55e
+#define F0900_P1_ISI_ENTRY  0xf55e00ff
+
+/*P1_ISIBITENA*/
+#define R0900_P1_ISIBITENA  0xf55f
+#define F0900_P1_ISI_BIT_EN  0xf55f00ff
+
+/*P1_MATSTR1*/
+#define R0900_P1_MATSTR1  0xf560
+#define F0900_P1_MATYPE_CURRENT1  0xf56000ff
+
+/*P1_MATSTR0*/
+#define R0900_P1_MATSTR0  0xf561
+#define F0900_P1_MATYPE_CURRENT0  0xf56100ff
+
+/*P1_UPLSTR1*/
+#define R0900_P1_UPLSTR1  0xf562
+#define F0900_P1_UPL_CURRENT1  0xf56200ff
+
+/*P1_UPLSTR0*/
+#define R0900_P1_UPLSTR0  0xf563
+#define F0900_P1_UPL_CURRENT0  0xf56300ff
+
+/*P1_DFLSTR1*/
+#define R0900_P1_DFLSTR1  0xf564
+#define F0900_P1_DFL_CURRENT1  0xf56400ff
+
+/*P1_DFLSTR0*/
+#define R0900_P1_DFLSTR0  0xf565
+#define F0900_P1_DFL_CURRENT0  0xf56500ff
+
+/*P1_SYNCSTR*/
+#define R0900_P1_SYNCSTR  0xf566
+#define F0900_P1_SYNC_CURRENT  0xf56600ff
+
+/*P1_SYNCDSTR1*/
+#define R0900_P1_SYNCDSTR1  0xf567
+#define F0900_P1_SYNCD_CURRENT1  0xf56700ff
+
+/*P1_SYNCDSTR0*/
+#define R0900_P1_SYNCDSTR0  0xf568
+#define F0900_P1_SYNCD_CURRENT0  0xf56800ff
+
+/*P1_PDELSTATUS1*/
+#define R0900_P1_PDELSTATUS1  0xf569
+#define F0900_P1_PKTDELIN_DELOCK  0xf5690080
+#define F0900_P1_SYNCDUPDFL_BADDFL  0xf5690040
+#define F0900_P1_CONTINUOUS_STREAM  0xf5690020
+#define F0900_P1_UNACCEPTED_STREAM  0xf5690010
+#define F0900_P1_BCH_ERROR_FLAG  0xf5690008
+#define F0900_P1_BBHCRCKO  0xf5690004
+#define F0900_P1_PKTDELIN_LOCK  0xf5690002
+#define F0900_P1_FIRST_LOCK  0xf5690001
+
+/*P1_PDELSTATUS2*/
+#define R0900_P1_PDELSTATUS2  0xf56a
+#define F0900_P1_PKTDEL_DEMODSEL  0xf56a0080
+#define F0900_P1_FRAME_MODCOD  0xf56a007c
+#define F0900_P1_FRAME_TYPE  0xf56a0003
+
+/*P1_BBFCRCKO1*/
+#define R0900_P1_BBFCRCKO1  0xf56b
+#define F0900_P1_BBHCRC_KOCNT1  0xf56b00ff
+
+/*P1_BBFCRCKO0*/
+#define R0900_P1_BBFCRCKO0  0xf56c
+#define F0900_P1_BBHCRC_KOCNT0  0xf56c00ff
+
+/*P1_UPCRCKO1*/
+#define R0900_P1_UPCRCKO1  0xf56d
+#define F0900_P1_PKTCRC_KOCNT1  0xf56d00ff
+
+/*P1_UPCRCKO0*/
+#define R0900_P1_UPCRCKO0  0xf56e
+#define F0900_P1_PKTCRC_KOCNT0  0xf56e00ff
+
+/*P1_TSSTATEM*/
+#define R0900_P1_TSSTATEM  0xf570
+#define F0900_P1_TSDIL_ON  0xf5700080
+#define F0900_P1_TSSKIPRS_ON  0xf5700040
+#define F0900_P1_TSRS_ON  0xf5700020
+#define F0900_P1_TSDESCRAMB_ON  0xf5700010
+#define F0900_P1_TSFRAME_MODE  0xf5700008
+#define F0900_P1_TS_DISABLE  0xf5700004
+#define F0900_P1_TSACM_MODE  0xf5700002
+#define F0900_P1_TSOUT_NOSYNC  0xf5700001
+
+/*P1_TSCFGH*/
+#define R0900_P1_TSCFGH  0xf572
+#define F0900_P1_TSFIFO_DVBCI  0xf5720080
+#define F0900_P1_TSFIFO_SERIAL  0xf5720040
+#define F0900_P1_TSFIFO_TEIUPDATE  0xf5720020
+#define F0900_P1_TSFIFO_DUTY50  0xf5720010
+#define F0900_P1_TSFIFO_HSGNLOUT  0xf5720008
+#define F0900_P1_TSFIFO_ERRMODE  0xf5720006
+#define F0900_P1_RST_HWARE  0xf5720001
+
+/*P1_TSCFGM*/
+#define R0900_P1_TSCFGM  0xf573
+#define F0900_P1_TSFIFO_MANSPEED  0xf57300c0
+#define F0900_P1_TSFIFO_PERMDATA  0xf5730020
+#define F0900_P1_TSFIFO_NONEWSGNL  0xf5730010
+#define F0900_P1_TSFIFO_BITSPEED  0xf5730008
+#define F0900_P1_NPD_SPECDVBS2  0xf5730004
+#define F0900_P1_TSFIFO_STOPCKDIS  0xf5730002
+#define F0900_P1_TSFIFO_INVDATA  0xf5730001
+
+/*P1_TSCFGL*/
+#define R0900_P1_TSCFGL  0xf574
+#define F0900_P1_TSFIFO_BCLKDEL1CK  0xf57400c0
+#define F0900_P1_BCHERROR_MODE  0xf5740030
+#define F0900_P1_TSFIFO_NSGNL2DATA  0xf5740008
+#define F0900_P1_TSFIFO_EMBINDVB  0xf5740004
+#define F0900_P1_TSFIFO_DPUNACT  0xf5740002
+#define F0900_P1_TSFIFO_NPDOFF  0xf5740001
+
+/*P1_TSINSDELH*/
+#define R0900_P1_TSINSDELH  0xf576
+#define F0900_P1_TSDEL_SYNCBYTE  0xf5760080
+#define F0900_P1_TSDEL_XXHEADER  0xf5760040
+#define F0900_P1_TSDEL_BBHEADER  0xf5760020
+#define F0900_P1_TSDEL_DATAFIELD  0xf5760010
+#define F0900_P1_TSINSDEL_ISCR  0xf5760008
+#define F0900_P1_TSINSDEL_NPD  0xf5760004
+#define F0900_P1_TSINSDEL_RSPARITY  0xf5760002
+#define F0900_P1_TSINSDEL_CRC8  0xf5760001
+
+/*P1_TSSPEED*/
+#define R0900_P1_TSSPEED  0xf580
+#define F0900_P1_TSFIFO_OUTSPEED  0xf58000ff
+
+/*P1_TSSTATUS*/
+#define R0900_P1_TSSTATUS  0xf581
+#define F0900_P1_TSFIFO_LINEOK  0xf5810080
+#define F0900_P1_TSFIFO_ERROR  0xf5810040
+#define F0900_P1_TSFIFO_DATA7  0xf5810020
+#define F0900_P1_TSFIFO_NOSYNC  0xf5810010
+#define F0900_P1_ISCR_INITIALIZED  0xf5810008
+#define F0900_P1_ISCR_UPDATED  0xf5810004
+#define F0900_P1_SOFFIFO_UNREGUL  0xf5810002
+#define F0900_P1_DIL_READY  0xf5810001
+
+/*P1_TSSTATUS2*/
+#define R0900_P1_TSSTATUS2  0xf582
+#define F0900_P1_TSFIFO_DEMODSEL  0xf5820080
+#define F0900_P1_TSFIFOSPEED_STORE  0xf5820040
+#define F0900_P1_DILXX_RESET  0xf5820020
+#define F0900_P1_TSSERIAL_IMPOS  0xf5820010
+#define F0900_P1_TSFIFO_LINENOK  0xf5820008
+#define F0900_P1_BITSPEED_EVENT  0xf5820004
+#define F0900_P1_SCRAMBDETECT  0xf5820002
+#define F0900_P1_ULDTV67_FALSELOCK  0xf5820001
+
+/*P1_TSBITRATE1*/
+#define R0900_P1_TSBITRATE1  0xf583
+#define F0900_P1_TSFIFO_BITRATE1  0xf58300ff
+
+/*P1_TSBITRATE0*/
+#define R0900_P1_TSBITRATE0  0xf584
+#define F0900_P1_TSFIFO_BITRATE0  0xf58400ff
+
+/*P1_ERRCTRL1*/
+#define R0900_P1_ERRCTRL1  0xf598
+#define F0900_P1_ERR_SOURCE1  0xf59800f0
+#define F0900_P1_NUM_EVENT1  0xf5980007
+
+/*P1_ERRCNT12*/
+#define R0900_P1_ERRCNT12  0xf599
+#define F0900_P1_ERRCNT1_OLDVALUE  0xf5990080
+#define F0900_P1_ERR_CNT12  0xf599007f
+
+/*P1_ERRCNT11*/
+#define R0900_P1_ERRCNT11  0xf59a
+#define F0900_P1_ERR_CNT11  0xf59a00ff
+
+/*P1_ERRCNT10*/
+#define R0900_P1_ERRCNT10  0xf59b
+#define F0900_P1_ERR_CNT10  0xf59b00ff
+
+/*P1_ERRCTRL2*/
+#define R0900_P1_ERRCTRL2  0xf59c
+#define F0900_P1_ERR_SOURCE2  0xf59c00f0
+#define F0900_P1_NUM_EVENT2  0xf59c0007
+
+/*P1_ERRCNT22*/
+#define R0900_P1_ERRCNT22  0xf59d
+#define F0900_P1_ERRCNT2_OLDVALUE  0xf59d0080
+#define F0900_P1_ERR_CNT22  0xf59d007f
+
+/*P1_ERRCNT21*/
+#define R0900_P1_ERRCNT21  0xf59e
+#define F0900_P1_ERR_CNT21  0xf59e00ff
+
+/*P1_ERRCNT20*/
+#define R0900_P1_ERRCNT20  0xf59f
+#define F0900_P1_ERR_CNT20  0xf59f00ff
+
+/*P1_FECSPY*/
+#define R0900_P1_FECSPY  0xf5a0
+#define F0900_P1_SPY_ENABLE  0xf5a00080
+#define F0900_P1_NO_SYNCBYTE  0xf5a00040
+#define F0900_P1_SERIAL_MODE  0xf5a00020
+#define F0900_P1_UNUSUAL_PACKET  0xf5a00010
+#define F0900_P1_BER_PACKMODE  0xf5a00008
+#define F0900_P1_BERMETER_LMODE  0xf5a00002
+#define F0900_P1_BERMETER_RESET  0xf5a00001
+
+/*P1_FSPYCFG*/
+#define R0900_P1_FSPYCFG  0xf5a1
+#define F0900_P1_FECSPY_INPUT  0xf5a100c0
+#define F0900_P1_RST_ON_ERROR  0xf5a10020
+#define F0900_P1_ONE_SHOT  0xf5a10010
+#define F0900_P1_I2C_MODE  0xf5a1000c
+#define F0900_P1_SPY_HYSTERESIS  0xf5a10003
+
+/*P1_FSPYDATA*/
+#define R0900_P1_FSPYDATA  0xf5a2
+#define F0900_P1_SPY_STUFFING  0xf5a20080
+#define F0900_P1_NOERROR_PKTJITTER  0xf5a20040
+#define F0900_P1_SPY_CNULLPKT  0xf5a20020
+#define F0900_P1_SPY_OUTDATA_MODE  0xf5a2001f
+
+/*P1_FSPYOUT*/
+#define R0900_P1_FSPYOUT  0xf5a3
+#define F0900_P1_FSPY_DIRECT  0xf5a30080
+#define F0900_P1_SPY_OUTDATA_BUS  0xf5a30038
+#define F0900_P1_STUFF_MODE  0xf5a30007
+
+/*P1_FSTATUS*/
+#define R0900_P1_FSTATUS  0xf5a4
+#define F0900_P1_SPY_ENDSIM  0xf5a40080
+#define F0900_P1_VALID_SIM  0xf5a40040
+#define F0900_P1_FOUND_SIGNAL  0xf5a40020
+#define F0900_P1_DSS_SYNCBYTE  0xf5a40010
+#define F0900_P1_RESULT_STATE  0xf5a4000f
+
+/*P1_FBERCPT4*/
+#define R0900_P1_FBERCPT4  0xf5a8
+#define F0900_P1_FBERMETER_CPT4  0xf5a800ff
+
+/*P1_FBERCPT3*/
+#define R0900_P1_FBERCPT3  0xf5a9
+#define F0900_P1_FBERMETER_CPT3  0xf5a900ff
+
+/*P1_FBERCPT2*/
+#define R0900_P1_FBERCPT2  0xf5aa
+#define F0900_P1_FBERMETER_CPT2  0xf5aa00ff
+
+/*P1_FBERCPT1*/
+#define R0900_P1_FBERCPT1  0xf5ab
+#define F0900_P1_FBERMETER_CPT1  0xf5ab00ff
+
+/*P1_FBERCPT0*/
+#define R0900_P1_FBERCPT0  0xf5ac
+#define F0900_P1_FBERMETER_CPT0  0xf5ac00ff
+
+/*P1_FBERERR2*/
+#define R0900_P1_FBERERR2  0xf5ad
+#define F0900_P1_FBERMETER_ERR2  0xf5ad00ff
+
+/*P1_FBERERR1*/
+#define R0900_P1_FBERERR1  0xf5ae
+#define F0900_P1_FBERMETER_ERR1  0xf5ae00ff
+
+/*P1_FBERERR0*/
+#define R0900_P1_FBERERR0  0xf5af
+#define F0900_P1_FBERMETER_ERR0  0xf5af00ff
+
+/*P1_FSPYBER*/
+#define R0900_P1_FSPYBER  0xf5b2
+#define F0900_P1_FSPYOBS_XORREAD  0xf5b20040
+#define F0900_P1_FSPYBER_OBSMODE  0xf5b20020
+#define F0900_P1_FSPYBER_SYNCBYTE  0xf5b20010
+#define F0900_P1_FSPYBER_UNSYNC  0xf5b20008
+#define F0900_P1_FSPYBER_CTIME  0xf5b20007
+
+/*RCCFGH*/
+#define R0900_RCCFGH  0xf600
+#define F0900_TSRCFIFO_DVBCI  0xf6000080
+#define F0900_TSRCFIFO_SERIAL  0xf6000040
+#define F0900_TSRCFIFO_DISABLE  0xf6000020
+#define F0900_TSFIFO_2TORC  0xf6000010
+#define F0900_TSRCFIFO_HSGNLOUT  0xf6000008
+#define F0900_TSRCFIFO_ERRMODE  0xf6000006
+
+/*TSGENERAL*/
+#define R0900_TSGENERAL  0xf630
+#define F0900_TSFIFO_BCLK1ALL  0xf6300020
+#define F0900_MUXSTREAM_OUTMODE  0xf6300008
+#define F0900_TSFIFO_PERMPARAL  0xf6300006
+#define F0900_RST_REEDSOLO  0xf6300001
+
+/*TSGENERAL1X*/
+#define R0900_TSGENERAL1X  0xf670
+#define F0900_TSFIFO1X_BCLK1ALL  0xf6700020
+#define F0900_MUXSTREAM1X_OUTMODE  0xf6700008
+#define F0900_TSFIFO1X_PERMPARAL  0xf6700006
+#define F0900_RST1X_REEDSOLO  0xf6700001
+
+/*NBITER_NF4*/
+#define R0900_NBITER_NF4  0xfa03
+#define F0900_NBITER_NF_QP_1_2  0xfa0300ff
+
+/*NBITER_NF5*/
+#define R0900_NBITER_NF5  0xfa04
+#define F0900_NBITER_NF_QP_3_5  0xfa0400ff
+
+/*NBITER_NF6*/
+#define R0900_NBITER_NF6  0xfa05
+#define F0900_NBITER_NF_QP_2_3  0xfa0500ff
+
+/*NBITER_NF7*/
+#define R0900_NBITER_NF7  0xfa06
+#define F0900_NBITER_NF_QP_3_4  0xfa0600ff
+
+/*NBITER_NF8*/
+#define R0900_NBITER_NF8  0xfa07
+#define F0900_NBITER_NF_QP_4_5  0xfa0700ff
+
+/*NBITER_NF9*/
+#define R0900_NBITER_NF9  0xfa08
+#define F0900_NBITER_NF_QP_5_6  0xfa0800ff
+
+/*NBITER_NF10*/
+#define R0900_NBITER_NF10  0xfa09
+#define F0900_NBITER_NF_QP_8_9  0xfa0900ff
+
+/*NBITER_NF11*/
+#define R0900_NBITER_NF11  0xfa0a
+#define F0900_NBITER_NF_QP_9_10  0xfa0a00ff
+
+/*NBITER_NF12*/
+#define R0900_NBITER_NF12  0xfa0b
+#define F0900_NBITER_NF_8P_3_5  0xfa0b00ff
+
+/*NBITER_NF13*/
+#define R0900_NBITER_NF13  0xfa0c
+#define F0900_NBITER_NF_8P_2_3  0xfa0c00ff
+
+/*NBITER_NF14*/
+#define R0900_NBITER_NF14  0xfa0d
+#define F0900_NBITER_NF_8P_3_4  0xfa0d00ff
+
+/*NBITER_NF15*/
+#define R0900_NBITER_NF15  0xfa0e
+#define F0900_NBITER_NF_8P_5_6  0xfa0e00ff
+
+/*NBITER_NF16*/
+#define R0900_NBITER_NF16  0xfa0f
+#define F0900_NBITER_NF_8P_8_9  0xfa0f00ff
+
+/*NBITER_NF17*/
+#define R0900_NBITER_NF17  0xfa10
+#define F0900_NBITER_NF_8P_9_10  0xfa1000ff
+
+/*NBITERNOERR*/
+#define R0900_NBITERNOERR  0xfa3f
+#define F0900_NBITER_STOP_CRIT  0xfa3f000f
+
+/*GAINLLR_NF4*/
+#define R0900_GAINLLR_NF4  0xfa43
+#define F0900_GAINLLR_NF_QP_1_2  0xfa43007f
+
+/*GAINLLR_NF5*/
+#define R0900_GAINLLR_NF5  0xfa44
+#define F0900_GAINLLR_NF_QP_3_5  0xfa44007f
+
+/*GAINLLR_NF6*/
+#define R0900_GAINLLR_NF6  0xfa45
+#define F0900_GAINLLR_NF_QP_2_3  0xfa45007f
+
+/*GAINLLR_NF7*/
+#define R0900_GAINLLR_NF7  0xfa46
+#define F0900_GAINLLR_NF_QP_3_4  0xfa46007f
+
+/*GAINLLR_NF8*/
+#define R0900_GAINLLR_NF8  0xfa47
+#define F0900_GAINLLR_NF_QP_4_5  0xfa47007f
+
+/*GAINLLR_NF9*/
+#define R0900_GAINLLR_NF9  0xfa48
+#define F0900_GAINLLR_NF_QP_5_6  0xfa48007f
+
+/*GAINLLR_NF10*/
+#define R0900_GAINLLR_NF10  0xfa49
+#define F0900_GAINLLR_NF_QP_8_9  0xfa49007f
+
+/*GAINLLR_NF11*/
+#define R0900_GAINLLR_NF11  0xfa4a
+#define F0900_GAINLLR_NF_QP_9_10  0xfa4a007f
+
+/*GAINLLR_NF12*/
+#define R0900_GAINLLR_NF12  0xfa4b
+#define F0900_GAINLLR_NF_8P_3_5  0xfa4b007f
+
+/*GAINLLR_NF13*/
+#define R0900_GAINLLR_NF13  0xfa4c
+#define F0900_GAINLLR_NF_8P_2_3  0xfa4c007f
+
+/*GAINLLR_NF14*/
+#define R0900_GAINLLR_NF14  0xfa4d
+#define F0900_GAINLLR_NF_8P_3_4  0xfa4d007f
+
+/*GAINLLR_NF15*/
+#define R0900_GAINLLR_NF15  0xfa4e
+#define F0900_GAINLLR_NF_8P_5_6  0xfa4e007f
+
+/*GAINLLR_NF16*/
+#define R0900_GAINLLR_NF16  0xfa4f
+#define F0900_GAINLLR_NF_8P_8_9  0xfa4f007f
+
+/*GAINLLR_NF17*/
+#define R0900_GAINLLR_NF17  0xfa50
+#define F0900_GAINLLR_NF_8P_9_10  0xfa50007f
+
+/*CFGEXT*/
+#define R0900_CFGEXT  0xfa80
+#define F0900_STAGMODE  0xfa800080
+#define F0900_BYPBCH  0xfa800040
+#define F0900_BYPLDPC  0xfa800020
+#define F0900_LDPCMODE  0xfa800010
+#define F0900_INVLLRSIGN  0xfa800008
+#define F0900_SHORTMULT  0xfa800004
+#define F0900_EXTERNTX  0xfa800001
+
+/*GENCFG*/
+#define R0900_GENCFG  0xfa86
+#define F0900_BROADCAST  0xfa860010
+#define F0900_NOSHFRD2  0xfa860008
+#define F0900_BCHERRFLAG  0xfa860004
+#define F0900_PRIORITY  0xfa860002
+#define F0900_DDEMOD  0xfa860001
+
+/*LDPCERR1*/
+#define R0900_LDPCERR1  0xfa96
+#define F0900_LDPC_ERRORS_COUNTER1  0xfa9600ff
+
+/*LDPCERR0*/
+#define R0900_LDPCERR0  0xfa97
+#define F0900_LDPC_ERRORS_COUNTER0  0xfa9700ff
+
+/*BCHERR*/
+#define R0900_BCHERR  0xfa98
+#define F0900_ERRORFLAG  0xfa980010
+#define F0900_BCH_ERRORS_COUNTER  0xfa98000f
+
+/*TSTRES0*/
+#define R0900_TSTRES0  0xff11
+#define F0900_FRESFEC  0xff110080
+#define F0900_FRESTS  0xff110040
+#define F0900_FRESVIT1  0xff110020
+#define F0900_FRESVIT2  0xff110010
+#define F0900_FRESSYM1  0xff110008
+#define F0900_FRESSYM2  0xff110004
+#define F0900_FRESMAS  0xff110002
+#define F0900_FRESINT  0xff110001
+
+/*P2_TSTDISRX*/
+#define R0900_P2_TSTDISRX  0xff65
+#define F0900_P2_EN_DISRX  0xff650080
+#define F0900_P2_TST_CURRSRC  0xff650040
+#define F0900_P2_IN_DIGSIGNAL  0xff650020
+#define F0900_P2_HIZ_CURRENTSRC  0xff650010
+#define F0900_TST_P2_PIN_SELECT  0xff650008
+#define F0900_P2_TST_DISRX  0xff650007
+
+/*P1_TSTDISRX*/
+#define R0900_P1_TSTDISRX  0xff67
+#define F0900_P1_EN_DISRX  0xff670080
+#define F0900_P1_TST_CURRSRC  0xff670040
+#define F0900_P1_IN_DIGSIGNAL  0xff670020
+#define F0900_P1_HIZ_CURRENTSRC  0xff670010
+#define F0900_TST_P1_PIN_SELECT  0xff670008
+#define F0900_P1_TST_DISRX  0xff670007
+
+#define STV0900_NBREGS         684
+#define STV0900_NBFIELDS               1702
+
+#endif
+
diff --git a/drivers/media/dvb/frontends/stv0900_sw.c b/drivers/media/dvb/frontends/stv0900_sw.c
new file mode 100644 (file)
index 0000000..a5a3153
--- /dev/null
@@ -0,0 +1,2847 @@
+/*
+ * stv0900_sw.c
+ *
+ * Driver for ST STV0900 satellite demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * 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 "stv0900.h"
+#include "stv0900_reg.h"
+#include "stv0900_priv.h"
+
+int stv0900_check_signal_presence(struct stv0900_internal *i_params,
+                                       enum fe_stv0900_demod_num demod)
+{
+       s32 carr_offset,
+       agc2_integr,
+       max_carrier;
+
+       int no_signal;
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               carr_offset = (stv0900_read_reg(i_params, R0900_P1_CFR2) << 8)
+                                               | stv0900_read_reg(i_params,
+                                               R0900_P1_CFR1);
+               carr_offset = ge2comp(carr_offset, 16);
+               agc2_integr = (stv0900_read_reg(i_params, R0900_P1_AGC2I1) << 8)
+                                               | stv0900_read_reg(i_params,
+                                               R0900_P1_AGC2I0);
+               max_carrier = i_params->dmd1_srch_range / 1000;
+               break;
+       case STV0900_DEMOD_2:
+               carr_offset = (stv0900_read_reg(i_params, R0900_P2_CFR2) << 8)
+                                               | stv0900_read_reg(i_params,
+                                               R0900_P2_CFR1);
+               carr_offset = ge2comp(carr_offset, 16);
+               agc2_integr = (stv0900_read_reg(i_params, R0900_P2_AGC2I1) << 8)
+                                               | stv0900_read_reg(i_params,
+                                               R0900_P2_AGC2I0);
+               max_carrier = i_params->dmd2_srch_range / 1000;
+               break;
+       }
+
+       max_carrier += (max_carrier / 10);
+       max_carrier = 65536 * (max_carrier / 2);
+       max_carrier /= i_params->mclk / 1000;
+       if (max_carrier > 0x4000)
+               max_carrier = 0x4000;
+
+       if ((agc2_integr > 0x2000)
+                       || (carr_offset > + 2*max_carrier)
+                       || (carr_offset < -2*max_carrier))
+               no_signal = TRUE;
+       else
+               no_signal = FALSE;
+
+       return no_signal;
+}
+
+static void stv0900_get_sw_loop_params(struct stv0900_internal *i_params,
+                               s32 *frequency_inc, s32 *sw_timeout,
+                               s32 *steps,
+                               enum fe_stv0900_demod_num demod)
+{
+       s32 timeout, freq_inc, max_steps, srate, max_carrier;
+
+       enum fe_stv0900_search_standard standard;
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               srate = i_params->dmd1_symbol_rate;
+               max_carrier = i_params->dmd1_srch_range / 1000;
+               max_carrier += max_carrier / 10;
+               standard = i_params->dmd1_srch_standard;
+               break;
+       case STV0900_DEMOD_2:
+               srate = i_params->dmd2_symbol_rate;
+               max_carrier = i_params->dmd2_srch_range / 1000;
+               max_carrier += max_carrier / 10;
+               standard = i_params->dmd2_srch_stndrd;
+               break;
+       }
+
+       max_carrier = 65536 * (max_carrier / 2);
+       max_carrier /= i_params->mclk / 1000;
+
+       if (max_carrier > 0x4000)
+               max_carrier = 0x4000;
+
+       freq_inc = srate;
+       freq_inc /= i_params->mclk >> 10;
+       freq_inc = freq_inc << 6;
+
+       switch (standard) {
+       case STV0900_SEARCH_DVBS1:
+       case STV0900_SEARCH_DSS:
+               freq_inc *= 3;
+               timeout = 20;
+               break;
+       case STV0900_SEARCH_DVBS2:
+               freq_inc *= 4;
+               timeout = 25;
+               break;
+       case STV0900_AUTO_SEARCH:
+       default:
+               freq_inc *= 3;
+               timeout = 25;
+               break;
+       }
+
+       freq_inc /= 100;
+
+       if ((freq_inc > max_carrier) || (freq_inc < 0))
+               freq_inc = max_carrier / 2;
+
+       timeout *= 27500;
+
+       if (srate > 0)
+               timeout /= srate / 1000;
+
+       if ((timeout > 100) || (timeout < 0))
+               timeout = 100;
+
+       max_steps = (max_carrier / freq_inc) + 1;
+
+       if ((max_steps > 100) || (max_steps < 0)) {
+               max_steps =  100;
+               freq_inc = max_carrier / max_steps;
+       }
+
+       *frequency_inc = freq_inc;
+       *sw_timeout = timeout;
+       *steps = max_steps;
+
+}
+
+static int stv0900_search_carr_sw_loop(struct stv0900_internal *i_params,
+                               s32 FreqIncr, s32 Timeout, int zigzag,
+                               s32 MaxStep, enum fe_stv0900_demod_num demod)
+{
+       int     no_signal,
+               lock = FALSE;
+       s32     stepCpt,
+               freqOffset,
+               max_carrier;
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               max_carrier = i_params->dmd1_srch_range / 1000;
+               max_carrier += (max_carrier / 10);
+               break;
+       case STV0900_DEMOD_2:
+               max_carrier = i_params->dmd2_srch_range / 1000;
+               max_carrier += (max_carrier / 10);
+               break;
+       }
+
+       max_carrier = 65536 * (max_carrier / 2);
+       max_carrier /= i_params->mclk / 1000;
+
+       if (max_carrier > 0x4000)
+               max_carrier = 0x4000;
+
+       if (zigzag == TRUE)
+               freqOffset = 0;
+       else
+               freqOffset = -max_carrier + FreqIncr;
+
+       stepCpt = 0;
+
+       do {
+               switch (demod) {
+               case STV0900_DEMOD_1:
+               default:
+                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1C);
+                       stv0900_write_reg(i_params, R0900_P1_CFRINIT1,
+                                       (freqOffset / 256) & 0xFF);
+                       stv0900_write_reg(i_params, R0900_P1_CFRINIT0,
+                                        freqOffset & 0xFF);
+                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x18);
+                       stv0900_write_bits(i_params, F0900_P1_ALGOSWRST, 1);
+
+                       if (i_params->chip_id == 0x12) {
+                               stv0900_write_bits(i_params,
+                                               F0900_P1_RST_HWARE, 1);
+                               stv0900_write_bits(i_params,
+                                               F0900_P1_RST_HWARE, 0);
+                       }
+                       break;
+               case STV0900_DEMOD_2:
+                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1C);
+                       stv0900_write_reg(i_params, R0900_P2_CFRINIT1,
+                                       (freqOffset / 256) & 0xFF);
+                       stv0900_write_reg(i_params, R0900_P2_CFRINIT0,
+                                       freqOffset & 0xFF);
+                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x18);
+                       stv0900_write_bits(i_params, F0900_P2_ALGOSWRST, 1);
+
+                       if (i_params->chip_id == 0x12) {
+                               stv0900_write_bits(i_params,
+                                               F0900_P2_RST_HWARE, 1);
+                               stv0900_write_bits(i_params,
+                                               F0900_P2_RST_HWARE, 0);
+                       }
+                       break;
+               }
+
+               if (zigzag == TRUE) {
+                       if (freqOffset >= 0)
+                               freqOffset = -freqOffset - 2 * FreqIncr;
+                       else
+                               freqOffset = -freqOffset;
+               } else
+                       freqOffset += + 2 * FreqIncr;
+
+               stepCpt++;
+               lock = stv0900_get_demod_lock(i_params, demod, Timeout);
+               no_signal = stv0900_check_signal_presence(i_params, demod);
+
+       } while ((lock == FALSE)
+                       && (no_signal == FALSE)
+                       && ((freqOffset - FreqIncr) <  max_carrier)
+                       && ((freqOffset + FreqIncr) > -max_carrier)
+                       && (stepCpt < MaxStep));
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               stv0900_write_bits(i_params, F0900_P1_ALGOSWRST, 0);
+               break;
+       case STV0900_DEMOD_2:
+               stv0900_write_bits(i_params, F0900_P2_ALGOSWRST, 0);
+               break;
+       }
+
+       return lock;
+}
+
+int stv0900_sw_algo(struct stv0900_internal *i_params,
+                               enum fe_stv0900_demod_num demod)
+{
+       int lock = FALSE;
+
+       int no_signal,
+       zigzag;
+       s32 dvbs2_fly_wheel;
+
+       s32 freqIncrement, softStepTimeout, trialCounter, max_steps;
+
+       stv0900_get_sw_loop_params(i_params, &freqIncrement, &softStepTimeout,
+                                       &max_steps, demod);
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               switch (i_params->dmd1_srch_standard) {
+               case STV0900_SEARCH_DVBS1:
+               case STV0900_SEARCH_DSS:
+                       if (i_params->chip_id >= 0x20)
+                               stv0900_write_reg(i_params, R0900_P1_CARFREQ,
+                                               0x3B);
+                       else
+                               stv0900_write_reg(i_params, R0900_P1_CARFREQ,
+                                               0xef);
+
+                       stv0900_write_reg(i_params, R0900_P1_DMDCFGMD, 0x49);
+                       zigzag = FALSE;
+                       break;
+               case STV0900_SEARCH_DVBS2:
+                       if (i_params->chip_id >= 0x20)
+                               stv0900_write_reg(i_params, R0900_P1_CORRELABS,
+                                               0x79);
+                       else
+                               stv0900_write_reg(i_params, R0900_P1_CORRELABS,
+                                               0x68);
+
+                       stv0900_write_reg(i_params, R0900_P1_DMDCFGMD,
+                                               0x89);
+
+                       zigzag = TRUE;
+                       break;
+               case STV0900_AUTO_SEARCH:
+               default:
+                       if (i_params->chip_id >= 0x20) {
+                               stv0900_write_reg(i_params, R0900_P1_CARFREQ,
+                                                       0x3B);
+                               stv0900_write_reg(i_params, R0900_P1_CORRELABS,
+                                                       0x79);
+                       } else {
+                               stv0900_write_reg(i_params, R0900_P1_CARFREQ,
+                                                       0xef);
+                               stv0900_write_reg(i_params, R0900_P1_CORRELABS,
+                                                       0x68);
+                       }
+
+                       stv0900_write_reg(i_params, R0900_P1_DMDCFGMD,
+                                                       0xc9);
+                       zigzag = FALSE;
+                       break;
+               }
+
+               trialCounter = 0;
+               do {
+                       lock = stv0900_search_carr_sw_loop(i_params,
+                                                       freqIncrement,
+                                                       softStepTimeout,
+                                                       zigzag,
+                                                       max_steps,
+                                                       demod);
+                       no_signal = stv0900_check_signal_presence(i_params,
+                                                               demod);
+                       trialCounter++;
+                       if ((lock == TRUE)
+                                       || (no_signal == TRUE)
+                                       || (trialCounter == 2)) {
+
+                               if (i_params->chip_id >= 0x20) {
+                                       stv0900_write_reg(i_params,
+                                                       R0900_P1_CARFREQ,
+                                                       0x49);
+                                       stv0900_write_reg(i_params,
+                                                       R0900_P1_CORRELABS,
+                                                       0x9e);
+                               } else {
+                                       stv0900_write_reg(i_params,
+                                                       R0900_P1_CARFREQ,
+                                                       0xed);
+                                       stv0900_write_reg(i_params,
+                                                       R0900_P1_CORRELABS,
+                                                       0x88);
+                               }
+
+                               if ((lock == TRUE) && (stv0900_get_bits(i_params, F0900_P1_HEADER_MODE) == STV0900_DVBS2_FOUND)) {
+                                       msleep(softStepTimeout);
+                                       dvbs2_fly_wheel = stv0900_get_bits(i_params, F0900_P1_FLYWHEEL_CPT);
+
+                                       if (dvbs2_fly_wheel < 0xd) {
+                                               msleep(softStepTimeout);
+                                               dvbs2_fly_wheel = stv0900_get_bits(i_params, F0900_P1_FLYWHEEL_CPT);
+                                       }
+
+                                       if (dvbs2_fly_wheel < 0xd) {
+                                               lock = FALSE;
+
+                                               if (trialCounter < 2) {
+                                                       if (i_params->chip_id >= 0x20)
+                                                               stv0900_write_reg(i_params, R0900_P1_CORRELABS, 0x79);
+                                                       else
+                                                               stv0900_write_reg(i_params, R0900_P1_CORRELABS, 0x68);
+
+                                                       stv0900_write_reg(i_params, R0900_P1_DMDCFGMD, 0x89);
+                                               }
+                                       }
+                               }
+                       }
+
+               } while ((lock == FALSE)
+                       && (trialCounter < 2)
+                       && (no_signal == FALSE));
+
+               break;
+       case STV0900_DEMOD_2:
+               switch (i_params->dmd2_srch_stndrd) {
+               case STV0900_SEARCH_DVBS1:
+               case STV0900_SEARCH_DSS:
+                       if (i_params->chip_id >= 0x20)
+                               stv0900_write_reg(i_params, R0900_P2_CARFREQ,
+                                               0x3b);
+                       else
+                               stv0900_write_reg(i_params, R0900_P2_CARFREQ,
+                                               0xef);
+
+                       stv0900_write_reg(i_params, R0900_P2_DMDCFGMD,
+                                               0x49);
+                       zigzag = FALSE;
+                       break;
+               case STV0900_SEARCH_DVBS2:
+                       if (i_params->chip_id >= 0x20)
+                               stv0900_write_reg(i_params, R0900_P2_CORRELABS,
+                                               0x79);
+                       else
+                               stv0900_write_reg(i_params, R0900_P2_CORRELABS,
+                                               0x68);
+
+                       stv0900_write_reg(i_params, R0900_P2_DMDCFGMD, 0x89);
+                       zigzag = TRUE;
+                       break;
+               case STV0900_AUTO_SEARCH:
+               default:
+                       if (i_params->chip_id >= 0x20) {
+                               stv0900_write_reg(i_params, R0900_P2_CARFREQ,
+                                               0x3b);
+                               stv0900_write_reg(i_params, R0900_P2_CORRELABS,
+                                               0x79);
+                       } else {
+                               stv0900_write_reg(i_params, R0900_P2_CARFREQ,
+                                               0xef);
+                               stv0900_write_reg(i_params, R0900_P2_CORRELABS,
+                                               0x68);
+                       }
+
+                       stv0900_write_reg(i_params, R0900_P2_DMDCFGMD, 0xc9);
+
+                       zigzag = FALSE;
+                       break;
+               }
+
+               trialCounter = 0;
+
+               do {
+                       lock = stv0900_search_carr_sw_loop(i_params,
+                                                       freqIncrement,
+                                                       softStepTimeout,
+                                                       zigzag,
+                                                       max_steps,
+                                                       demod);
+                       no_signal = stv0900_check_signal_presence(i_params,
+                                                               demod);
+                       trialCounter++;
+                       if ((lock == TRUE)
+                                       || (no_signal == TRUE)
+                                       || (trialCounter == 2)) {
+                               if (i_params->chip_id >= 0x20) {
+                                       stv0900_write_reg(i_params,
+                                                       R0900_P2_CARFREQ,
+                                                       0x49);
+                                       stv0900_write_reg(i_params,
+                                                       R0900_P2_CORRELABS,
+                                                       0x9e);
+                               } else {
+                                       stv0900_write_reg(i_params,
+                                                       R0900_P2_CARFREQ,
+                                                       0xed);
+                                       stv0900_write_reg(i_params,
+                                                       R0900_P2_CORRELABS,
+                                                       0x88);
+                               }
+
+                               if ((lock == TRUE) && (stv0900_get_bits(i_params, F0900_P2_HEADER_MODE) == STV0900_DVBS2_FOUND)) {
+                                       msleep(softStepTimeout);
+                                       dvbs2_fly_wheel = stv0900_get_bits(i_params, F0900_P2_FLYWHEEL_CPT);
+                                       if (dvbs2_fly_wheel < 0xd) {
+                                               msleep(softStepTimeout);
+                                               dvbs2_fly_wheel = stv0900_get_bits(i_params, F0900_P2_FLYWHEEL_CPT);
+                                       }
+
+                                       if (dvbs2_fly_wheel < 0xd) {
+                                               lock = FALSE;
+                                               if (trialCounter < 2) {
+                                                       if (i_params->chip_id >= 0x20)
+                                                               stv0900_write_reg(i_params, R0900_P2_CORRELABS, 0x79);
+                                                       else
+                                                               stv0900_write_reg(i_params, R0900_P2_CORRELABS, 0x68);
+
+                                                       stv0900_write_reg(i_params, R0900_P2_DMDCFGMD, 0x89);
+                                               }
+                                       }
+                               }
+                       }
+
+               } while ((lock == FALSE) && (trialCounter < 2) && (no_signal == FALSE));
+
+               break;
+       }
+
+       return lock;
+}
+
+static u32 stv0900_get_symbol_rate(struct stv0900_internal *i_params,
+                                       u32 mclk,
+                                       enum fe_stv0900_demod_num demod)
+{
+       s32 sfr_field3, sfr_field2, sfr_field1, sfr_field0,
+       rem1, rem2, intval1, intval2, srate;
+
+       dmd_reg(sfr_field3, F0900_P1_SYMB_FREQ3, F0900_P2_SYMB_FREQ3);
+       dmd_reg(sfr_field2, F0900_P1_SYMB_FREQ2, F0900_P2_SYMB_FREQ2);
+       dmd_reg(sfr_field1, F0900_P1_SYMB_FREQ1, F0900_P2_SYMB_FREQ1);
+       dmd_reg(sfr_field0, F0900_P1_SYMB_FREQ0, F0900_P2_SYMB_FREQ0);
+
+       srate = (stv0900_get_bits(i_params, sfr_field3) << 24) +
+               (stv0900_get_bits(i_params, sfr_field2) << 16) +
+               (stv0900_get_bits(i_params, sfr_field1) << 8) +
+               (stv0900_get_bits(i_params, sfr_field0));
+       dprintk("lock: srate=%d r0=0x%x r1=0x%x r2=0x%x r3=0x%x \n",
+               srate, stv0900_get_bits(i_params, sfr_field0),
+               stv0900_get_bits(i_params, sfr_field1),
+               stv0900_get_bits(i_params, sfr_field2),
+               stv0900_get_bits(i_params, sfr_field3));
+
+       intval1 = (mclk) >> 16;
+       intval2 = (srate) >> 16;
+
+       rem1 = (mclk) % 0x10000;
+       rem2 = (srate) % 0x10000;
+       srate = (intval1 * intval2) +
+               ((intval1 * rem2) >> 16) +
+               ((intval2 * rem1) >> 16);
+
+       return srate;
+}
+
+static void stv0900_set_symbol_rate(struct stv0900_internal *i_params,
+                                       u32 mclk, u32 srate,
+                                       enum fe_stv0900_demod_num demod)
+{
+       s32 sfr_init_reg;
+       u32 symb;
+
+       dprintk(KERN_INFO "%s: Mclk %d, SR %d, Dmd %d\n", __func__, mclk,
+                                                       srate, demod);
+
+       dmd_reg(sfr_init_reg, R0900_P1_SFRINIT1, R0900_P2_SFRINIT1);
+
+       if (srate > 60000000) {
+               symb = srate << 4;
+               symb /= (mclk >> 12);
+       } else if (srate > 6000000) {
+               symb = srate << 6;
+               symb /= (mclk >> 10);
+       } else {
+               symb = srate << 9;
+               symb /= (mclk >> 7);
+       }
+
+       stv0900_write_reg(i_params, sfr_init_reg, (symb >> 8) & 0x7F);
+       stv0900_write_reg(i_params, sfr_init_reg + 1, (symb & 0xFF));
+}
+
+static void stv0900_set_max_symbol_rate(struct stv0900_internal *i_params,
+                                       u32 mclk, u32 srate,
+                                       enum fe_stv0900_demod_num demod)
+{
+       s32 sfr_max_reg;
+       u32 symb;
+
+       dmd_reg(sfr_max_reg, R0900_P1_SFRUP1, R0900_P2_SFRUP1);
+
+       srate = 105 * (srate / 100);
+
+       if (srate > 60000000) {
+               symb = srate << 4;
+               symb /= (mclk >> 12);
+       } else if (srate > 6000000) {
+               symb = srate << 6;
+               symb /= (mclk >> 10);
+       } else {
+               symb = srate << 9;
+               symb /= (mclk >> 7);
+       }
+
+       if (symb < 0x7fff) {
+               stv0900_write_reg(i_params, sfr_max_reg, (symb >> 8) & 0x7F);
+               stv0900_write_reg(i_params, sfr_max_reg + 1, (symb & 0xFF));
+       } else {
+               stv0900_write_reg(i_params, sfr_max_reg, 0x7F);
+               stv0900_write_reg(i_params, sfr_max_reg + 1, 0xFF);
+       }
+}
+
+static void stv0900_set_min_symbol_rate(struct stv0900_internal *i_params,
+                                       u32 mclk, u32 srate,
+                                       enum fe_stv0900_demod_num demod)
+{
+       s32 sfr_min_reg;
+       u32     symb;
+
+       dmd_reg(sfr_min_reg, R0900_P1_SFRLOW1, R0900_P2_SFRLOW1);
+
+       srate = 95 * (srate / 100);
+       if (srate > 60000000) {
+               symb = srate << 4;
+               symb /= (mclk >> 12);
+
+       } else if (srate > 6000000) {
+               symb = srate << 6;
+               symb /= (mclk >> 10);
+
+       } else {
+               symb = srate << 9;
+               symb /= (mclk >> 7);
+       }
+
+       stv0900_write_reg(i_params, sfr_min_reg, (symb >> 8) & 0xFF);
+       stv0900_write_reg(i_params, sfr_min_reg + 1, (symb & 0xFF));
+}
+
+static s32 stv0900_get_timing_offst(struct stv0900_internal *i_params,
+                                       u32 srate,
+                                       enum fe_stv0900_demod_num demod)
+{
+       s32 tmgreg,
+       timingoffset;
+
+       dmd_reg(tmgreg, R0900_P1_TMGREG2, R0900_P2_TMGREG2);
+
+       timingoffset = (stv0900_read_reg(i_params, tmgreg) << 16) +
+                      (stv0900_read_reg(i_params, tmgreg + 1) << 8) +
+                      (stv0900_read_reg(i_params, tmgreg + 2));
+
+       timingoffset = ge2comp(timingoffset, 24);
+
+
+       if (timingoffset == 0)
+               timingoffset = 1;
+
+       timingoffset = ((s32)srate * 10) / ((s32)0x1000000 / timingoffset);
+       timingoffset /= 320;
+
+       return timingoffset;
+}
+
+static void stv0900_set_dvbs2_rolloff(struct stv0900_internal *i_params,
+                                       enum fe_stv0900_demod_num demod)
+{
+       s32 rolloff, man_fld, matstr_reg, rolloff_ctl_fld;
+
+       dmd_reg(man_fld, F0900_P1_MANUAL_ROLLOFF, F0900_P2_MANUAL_ROLLOFF);
+       dmd_reg(matstr_reg, R0900_P1_MATSTR1, R0900_P2_MATSTR1);
+       dmd_reg(rolloff_ctl_fld, F0900_P1_ROLLOFF_CONTROL,
+                               F0900_P2_ROLLOFF_CONTROL);
+
+       if (i_params->chip_id == 0x10) {
+               stv0900_write_bits(i_params, man_fld, 1);
+               rolloff = stv0900_read_reg(i_params, matstr_reg) & 0x03;
+               stv0900_write_bits(i_params, rolloff_ctl_fld, rolloff);
+       } else
+               stv0900_write_bits(i_params, man_fld, 0);
+}
+
+static u32 stv0900_carrier_width(u32 srate, enum fe_stv0900_rolloff ro)
+{
+       u32 rolloff;
+
+       switch (ro) {
+       case STV0900_20:
+               rolloff = 20;
+               break;
+       case STV0900_25:
+               rolloff = 25;
+               break;
+       case STV0900_35:
+       default:
+               rolloff = 35;
+               break;
+       }
+
+       return srate  + (srate * rolloff) / 100;
+}
+
+static int stv0900_check_timing_lock(struct stv0900_internal *i_params,
+                               enum fe_stv0900_demod_num demod)
+{
+       int timingLock = FALSE;
+       s32 i,
+       timingcpt = 0;
+       u8 carFreq,
+       tmgTHhigh,
+       tmgTHLow;
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               carFreq = stv0900_read_reg(i_params, R0900_P1_CARFREQ);
+               tmgTHhigh = stv0900_read_reg(i_params, R0900_P1_TMGTHRISE);
+               tmgTHLow = stv0900_read_reg(i_params, R0900_P1_TMGTHFALL);
+               stv0900_write_reg(i_params, R0900_P1_TMGTHRISE, 0x20);
+               stv0900_write_reg(i_params, R0900_P1_TMGTHFALL, 0x0);
+               stv0900_write_bits(i_params, F0900_P1_CFR_AUTOSCAN, 0);
+               stv0900_write_reg(i_params, R0900_P1_RTC, 0x80);
+               stv0900_write_reg(i_params, R0900_P1_RTCS2, 0x40);
+               stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0x0);
+               stv0900_write_reg(i_params, R0900_P1_CFRINIT1, 0x0);
+               stv0900_write_reg(i_params, R0900_P1_CFRINIT0, 0x0);
+               stv0900_write_reg(i_params, R0900_P1_AGC2REF, 0x65);
+               stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x18);
+               msleep(7);
+
+               for (i = 0; i < 10; i++) {
+                       if (stv0900_get_bits(i_params, F0900_P1_TMGLOCK_QUALITY) >= 2)
+                               timingcpt++;
+
+                       msleep(1);
+               }
+
+               if (timingcpt >= 3)
+                       timingLock = TRUE;
+
+               stv0900_write_reg(i_params, R0900_P1_AGC2REF, 0x38);
+               stv0900_write_reg(i_params, R0900_P1_RTC, 0x88);
+               stv0900_write_reg(i_params, R0900_P1_RTCS2, 0x68);
+               stv0900_write_reg(i_params, R0900_P1_CARFREQ, carFreq);
+               stv0900_write_reg(i_params, R0900_P1_TMGTHRISE, tmgTHhigh);
+               stv0900_write_reg(i_params, R0900_P1_TMGTHFALL, tmgTHLow);
+               break;
+       case STV0900_DEMOD_2:
+               carFreq = stv0900_read_reg(i_params, R0900_P2_CARFREQ);
+               tmgTHhigh = stv0900_read_reg(i_params, R0900_P2_TMGTHRISE);
+               tmgTHLow = stv0900_read_reg(i_params, R0900_P2_TMGTHFALL);
+               stv0900_write_reg(i_params, R0900_P2_TMGTHRISE, 0x20);
+               stv0900_write_reg(i_params, R0900_P2_TMGTHFALL, 0);
+               stv0900_write_bits(i_params, F0900_P2_CFR_AUTOSCAN, 0);
+               stv0900_write_reg(i_params, R0900_P2_RTC, 0x80);
+               stv0900_write_reg(i_params, R0900_P2_RTCS2, 0x40);
+               stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0x0);
+               stv0900_write_reg(i_params, R0900_P2_CFRINIT1, 0x0);
+               stv0900_write_reg(i_params, R0900_P2_CFRINIT0, 0x0);
+               stv0900_write_reg(i_params, R0900_P2_AGC2REF, 0x65);
+               stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x18);
+               msleep(5);
+               for (i = 0; i < 10; i++) {
+                       if (stv0900_get_bits(i_params, F0900_P2_TMGLOCK_QUALITY) >= 2)
+                               timingcpt++;
+
+                       msleep(1);
+               }
+
+               if (timingcpt >= 3)
+                       timingLock = TRUE;
+
+               stv0900_write_reg(i_params, R0900_P2_AGC2REF, 0x38);
+               stv0900_write_reg(i_params, R0900_P2_RTC, 0x88);
+               stv0900_write_reg(i_params, R0900_P2_RTCS2, 0x68);
+               stv0900_write_reg(i_params, R0900_P2_CARFREQ, carFreq);
+               stv0900_write_reg(i_params, R0900_P2_TMGTHRISE, tmgTHhigh);
+               stv0900_write_reg(i_params, R0900_P2_TMGTHFALL, tmgTHLow);
+               break;
+       }
+
+       return  timingLock;
+}
+
+static int stv0900_get_demod_cold_lock(struct dvb_frontend *fe,
+                                       s32 demod_timeout)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       enum fe_stv0900_demod_num demod = state->demod;
+
+       int lock = FALSE;
+       s32 srate, search_range, locktimeout,
+               currier_step, nb_steps, current_step,
+               direction, tuner_freq, timeout;
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               srate = i_params->dmd1_symbol_rate;
+               search_range = i_params->dmd1_srch_range;
+               break;
+
+       case STV0900_DEMOD_2:
+               srate = i_params->dmd2_symbol_rate;
+               search_range = i_params->dmd2_srch_range;
+               break;
+       }
+
+       if (srate >= 10000000)
+               locktimeout = demod_timeout / 3;
+       else
+               locktimeout = demod_timeout / 2;
+
+       lock = stv0900_get_demod_lock(i_params, demod, locktimeout);
+
+       if (lock == FALSE) {
+               if (srate >= 10000000) {
+                       if (stv0900_check_timing_lock(i_params, demod) == TRUE) {
+                               switch (demod) {
+                               case STV0900_DEMOD_1:
+                               default:
+                                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1f);
+                                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x15);
+                                       break;
+                               case STV0900_DEMOD_2:
+                                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1f);
+                                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x15);
+                                       break;
+                               }
+
+                               lock = stv0900_get_demod_lock(i_params, demod, demod_timeout);
+                       } else
+                               lock = FALSE;
+               } else {
+                       if (srate <= 4000000)
+                               currier_step = 1000;
+                       else if (srate <= 7000000)
+                               currier_step = 2000;
+                       else if (srate <= 10000000)
+                               currier_step = 3000;
+                       else
+                               currier_step = 5000;
+
+                       nb_steps = ((search_range / 1000) / currier_step);
+                       nb_steps /= 2;
+                       nb_steps = (2 * (nb_steps + 1));
+                       if (nb_steps < 0)
+                               nb_steps = 2;
+                       else if (nb_steps > 12)
+                               nb_steps = 12;
+
+                       current_step = 1;
+                       direction = 1;
+                       timeout = (demod_timeout / 3);
+                       if (timeout > 1000)
+                               timeout = 1000;
+
+                       switch (demod) {
+                       case STV0900_DEMOD_1:
+                       default:
+                               if (lock == FALSE) {
+                                       tuner_freq = i_params->tuner1_freq;
+                                       i_params->tuner1_bw = stv0900_carrier_width(i_params->dmd1_symbol_rate, i_params->rolloff) + i_params->dmd1_symbol_rate;
+
+                                       while ((current_step <= nb_steps) && (lock == FALSE)) {
+
+                                               if (direction > 0)
+                                                       tuner_freq += (current_step * currier_step);
+                                               else
+                                                       tuner_freq -= (current_step * currier_step);
+
+                                               stv0900_set_tuner(fe, tuner_freq, i_params->tuner1_bw);
+                                               stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1C);
+                                               if (i_params->dmd1_srch_standard == STV0900_SEARCH_DVBS2) {
+                                                       stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 0);
+                                                       stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 0);
+                                                       stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 1);
+                                                       stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 1);
+                                               }
+
+                                               stv0900_write_reg(i_params, R0900_P1_CFRINIT1, 0);
+                                               stv0900_write_reg(i_params, R0900_P1_CFRINIT0, 0);
+                                               stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1F);
+                                               stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x15);
+                                               lock = stv0900_get_demod_lock(i_params, demod, timeout);
+                                               direction *= -1;
+                                               current_step++;
+                                       }
+                               }
+                               break;
+                       case STV0900_DEMOD_2:
+                               if (lock == FALSE) {
+                                       tuner_freq = i_params->tuner2_freq;
+                                       i_params->tuner2_bw = stv0900_carrier_width(srate, i_params->rolloff) + srate;
+
+                                       while ((current_step <= nb_steps) && (lock == FALSE)) {
+
+                                               if (direction > 0)
+                                                       tuner_freq += (current_step * currier_step);
+                                               else
+                                                       tuner_freq -= (current_step * currier_step);
+
+                                               stv0900_set_tuner(fe, tuner_freq, i_params->tuner2_bw);
+                                               stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1C);
+                                               if (i_params->dmd2_srch_stndrd == STV0900_SEARCH_DVBS2) {
+                                                       stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 0);
+                                                       stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 0);
+                                                       stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 1);
+                                                       stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 1);
+                                               }
+
+                                               stv0900_write_reg(i_params, R0900_P2_CFRINIT1, 0);
+                                               stv0900_write_reg(i_params, R0900_P2_CFRINIT0, 0);
+                                               stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1F);
+                                               stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x15);
+                                               lock = stv0900_get_demod_lock(i_params, demod, timeout);
+                                               direction *= -1;
+                                               current_step++;
+                                       }
+                               }
+                               break;
+                       }
+               }
+       }
+
+       return  lock;
+}
+
+static void stv0900_get_lock_timeout(s32 *demod_timeout, s32 *fec_timeout,
+                                       s32 srate,
+                                       enum fe_stv0900_search_algo algo)
+{
+       switch (algo) {
+       case STV0900_BLIND_SEARCH:
+               if (srate <= 1500000) {
+                       (*demod_timeout) = 1500;
+                       (*fec_timeout) = 400;
+               } else if (srate <= 5000000) {
+                       (*demod_timeout) = 1000;
+                       (*fec_timeout) = 300;
+               } else {
+                       (*demod_timeout) = 700;
+                       (*fec_timeout) = 100;
+               }
+
+               break;
+       case STV0900_COLD_START:
+       case STV0900_WARM_START:
+       default:
+               if (srate <= 1000000) {
+                       (*demod_timeout) = 3000;
+                       (*fec_timeout) = 1700;
+               } else if (srate <= 2000000) {
+                       (*demod_timeout) = 2500;
+                       (*fec_timeout) = 1100;
+               } else if (srate <= 5000000) {
+                       (*demod_timeout) = 1000;
+                       (*fec_timeout) = 550;
+               } else if (srate <= 10000000) {
+                       (*demod_timeout) = 700;
+                       (*fec_timeout) = 250;
+               } else if (srate <= 20000000) {
+                       (*demod_timeout) = 400;
+                       (*fec_timeout) = 130;
+               }
+
+               else {
+                       (*demod_timeout) = 300;
+                       (*fec_timeout) = 100;
+               }
+
+               break;
+
+       }
+
+       if (algo == STV0900_WARM_START)
+               (*demod_timeout) /= 2;
+}
+
+static void stv0900_set_viterbi_tracq(struct stv0900_internal *i_params,
+                                       enum fe_stv0900_demod_num demod)
+{
+
+       s32 vth_reg;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       dmd_reg(vth_reg, R0900_P1_VTH12, R0900_P2_VTH12);
+
+       stv0900_write_reg(i_params, vth_reg++, 0xd0);
+       stv0900_write_reg(i_params, vth_reg++, 0x7d);
+       stv0900_write_reg(i_params, vth_reg++, 0x53);
+       stv0900_write_reg(i_params, vth_reg++, 0x2F);
+       stv0900_write_reg(i_params, vth_reg++, 0x24);
+       stv0900_write_reg(i_params, vth_reg++, 0x1F);
+}
+
+static void stv0900_set_viterbi_standard(struct stv0900_internal *i_params,
+                                  enum fe_stv0900_search_standard Standard,
+                                  enum fe_stv0900_fec PunctureRate,
+                                  enum fe_stv0900_demod_num demod)
+{
+
+       s32 fecmReg,
+       prvitReg;
+
+       dprintk(KERN_INFO "%s: ViterbiStandard = ", __func__);
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               fecmReg = R0900_P1_FECM;
+               prvitReg = R0900_P1_PRVIT;
+               break;
+       case STV0900_DEMOD_2:
+               fecmReg = R0900_P2_FECM;
+               prvitReg = R0900_P2_PRVIT;
+               break;
+       }
+
+       switch (Standard) {
+       case STV0900_AUTO_SEARCH:
+               dprintk("Auto\n");
+               stv0900_write_reg(i_params, fecmReg, 0x10);
+               stv0900_write_reg(i_params, prvitReg, 0x3F);
+               break;
+       case STV0900_SEARCH_DVBS1:
+               dprintk("DVBS1\n");
+               stv0900_write_reg(i_params, fecmReg, 0x00);
+               switch (PunctureRate) {
+               case STV0900_FEC_UNKNOWN:
+               default:
+                       stv0900_write_reg(i_params, prvitReg, 0x2F);
+                       break;
+               case STV0900_FEC_1_2:
+                       stv0900_write_reg(i_params, prvitReg, 0x01);
+                       break;
+               case STV0900_FEC_2_3:
+                       stv0900_write_reg(i_params, prvitReg, 0x02);
+                       break;
+               case STV0900_FEC_3_4:
+                       stv0900_write_reg(i_params, prvitReg, 0x04);
+                       break;
+               case STV0900_FEC_5_6:
+                       stv0900_write_reg(i_params, prvitReg, 0x08);
+                       break;
+               case STV0900_FEC_7_8:
+                       stv0900_write_reg(i_params, prvitReg, 0x20);
+                       break;
+               }
+
+               break;
+       case STV0900_SEARCH_DSS:
+               dprintk("DSS\n");
+               stv0900_write_reg(i_params, fecmReg, 0x80);
+               switch (PunctureRate) {
+               case STV0900_FEC_UNKNOWN:
+               default:
+                       stv0900_write_reg(i_params, prvitReg, 0x13);
+                       break;
+               case STV0900_FEC_1_2:
+                       stv0900_write_reg(i_params, prvitReg, 0x01);
+                       break;
+               case STV0900_FEC_2_3:
+                       stv0900_write_reg(i_params, prvitReg, 0x02);
+                       break;
+               case STV0900_FEC_6_7:
+                       stv0900_write_reg(i_params, prvitReg, 0x10);
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static void stv0900_track_optimization(struct dvb_frontend *fe)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       enum fe_stv0900_demod_num demod = state->demod;
+
+       s32 srate, pilots, aclc, freq1, freq0,
+               i = 0, timed, timef, blindTunSw = 0;
+
+       enum fe_stv0900_rolloff rolloff;
+       enum fe_stv0900_modcode foundModcod;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
+       srate += stv0900_get_timing_offst(i_params, srate, demod);
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               switch (i_params->dmd1_rslts.standard) {
+               case STV0900_DVBS1_STANDARD:
+                       if (i_params->dmd1_srch_standard == STV0900_AUTO_SEARCH) {
+                               stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 1);
+                               stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 0);
+                       }
+
+                       stv0900_write_bits(i_params, F0900_P1_ROLLOFF_CONTROL, i_params->rolloff);
+                       stv0900_write_bits(i_params, F0900_P1_MANUAL_ROLLOFF, 1);
+                       stv0900_write_reg(i_params, R0900_P1_ERRCTRL1, 0x75);
+                       break;
+               case STV0900_DSS_STANDARD:
+                       if (i_params->dmd1_srch_standard == STV0900_AUTO_SEARCH) {
+                               stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 1);
+                               stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 0);
+                       }
+
+                       stv0900_write_bits(i_params, F0900_P1_ROLLOFF_CONTROL, i_params->rolloff);
+                       stv0900_write_bits(i_params, F0900_P1_MANUAL_ROLLOFF, 1);
+                       stv0900_write_reg(i_params, R0900_P1_ERRCTRL1, 0x75);
+                       break;
+               case STV0900_DVBS2_STANDARD:
+                       stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 0);
+                       stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 1);
+                       stv0900_write_reg(i_params, R0900_P1_ACLC, 0);
+                       stv0900_write_reg(i_params, R0900_P1_BCLC, 0);
+                       if (i_params->dmd1_rslts.frame_length == STV0900_LONG_FRAME) {
+                               foundModcod = stv0900_get_bits(i_params, F0900_P1_DEMOD_MODCOD);
+                               pilots = stv0900_get_bits(i_params, F0900_P1_DEMOD_TYPE) & 0x01;
+                               aclc = stv0900_get_optim_carr_loop(srate, foundModcod, pilots, i_params->chip_id);
+                               if (foundModcod <= STV0900_QPSK_910)
+                                       stv0900_write_reg(i_params, R0900_P1_ACLC2S2Q, aclc);
+                               else if (foundModcod <= STV0900_8PSK_910) {
+                                       stv0900_write_reg(i_params, R0900_P1_ACLC2S2Q, 0x2a);
+                                       stv0900_write_reg(i_params, R0900_P1_ACLC2S28, aclc);
+                               }
+
+                               if ((i_params->demod_mode == STV0900_SINGLE) && (foundModcod > STV0900_8PSK_910)) {
+                                       if (foundModcod <= STV0900_16APSK_910) {
+                                               stv0900_write_reg(i_params, R0900_P1_ACLC2S2Q, 0x2a);
+                                               stv0900_write_reg(i_params, R0900_P1_ACLC2S216A, aclc);
+                                       } else if (foundModcod <= STV0900_32APSK_910) {
+                                               stv0900_write_reg(i_params, R0900_P1_ACLC2S2Q, 0x2a);
+                                               stv0900_write_reg(i_params, R0900_P1_ACLC2S232A, aclc);
+                                       }
+                               }
+
+                       } else {
+                               aclc = stv0900_get_optim_short_carr_loop(srate, i_params->dmd1_rslts.modulation, i_params->chip_id);
+                               if (i_params->dmd1_rslts.modulation == STV0900_QPSK)
+                                       stv0900_write_reg(i_params, R0900_P1_ACLC2S2Q, aclc);
+
+                               else if (i_params->dmd1_rslts.modulation == STV0900_8PSK) {
+                                       stv0900_write_reg(i_params, R0900_P1_ACLC2S2Q, 0x2a);
+                                       stv0900_write_reg(i_params, R0900_P1_ACLC2S28, aclc);
+                               } else if (i_params->dmd1_rslts.modulation == STV0900_16APSK) {
+                                       stv0900_write_reg(i_params, R0900_P1_ACLC2S2Q, 0x2a);
+                                       stv0900_write_reg(i_params, R0900_P1_ACLC2S216A, aclc);
+                               } else if (i_params->dmd1_rslts.modulation == STV0900_32APSK) {
+                                       stv0900_write_reg(i_params, R0900_P1_ACLC2S2Q, 0x2a);
+                                       stv0900_write_reg(i_params, R0900_P1_ACLC2S232A, aclc);
+                               }
+
+                       }
+
+                       if (i_params->chip_id <= 0x11) {
+                               if (i_params->demod_mode != STV0900_SINGLE)
+                                       stv0900_activate_s2_modcode(i_params, demod);
+
+                       }
+
+                       stv0900_write_reg(i_params, R0900_P1_ERRCTRL1, 0x67);
+                       break;
+               case STV0900_UNKNOWN_STANDARD:
+               default:
+                       stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 1);
+                       stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 1);
+                       break;
+               }
+
+               freq1 = stv0900_read_reg(i_params, R0900_P1_CFR2);
+               freq0 = stv0900_read_reg(i_params, R0900_P1_CFR1);
+               rolloff = stv0900_get_bits(i_params, F0900_P1_ROLLOFF_STATUS);
+               if (i_params->dmd1_srch_algo == STV0900_BLIND_SEARCH) {
+                       stv0900_write_reg(i_params, R0900_P1_SFRSTEP, 0x00);
+                       stv0900_write_bits(i_params, F0900_P1_SCAN_ENABLE, 0);
+                       stv0900_write_bits(i_params, F0900_P1_CFR_AUTOSCAN, 0);
+                       stv0900_write_reg(i_params, R0900_P1_TMGCFG2, 0x01);
+                       stv0900_set_symbol_rate(i_params, i_params->mclk, srate, demod);
+                       stv0900_set_max_symbol_rate(i_params, i_params->mclk, srate, demod);
+                       stv0900_set_min_symbol_rate(i_params, i_params->mclk, srate, demod);
+                       blindTunSw = 1;
+               }
+
+               if (i_params->chip_id >= 0x20) {
+                       if ((i_params->dmd1_srch_standard == STV0900_SEARCH_DVBS1) || (i_params->dmd1_srch_standard == STV0900_SEARCH_DSS) || (i_params->dmd1_srch_standard == STV0900_AUTO_SEARCH)) {
+                               stv0900_write_reg(i_params, R0900_P1_VAVSRVIT, 0x0a);
+                               stv0900_write_reg(i_params, R0900_P1_VITSCALE, 0x0);
+                       }
+               }
+
+               if (i_params->chip_id < 0x20)
+                       stv0900_write_reg(i_params, R0900_P1_CARHDR, 0x08);
+
+               if (i_params->chip_id == 0x10)
+                       stv0900_write_reg(i_params, R0900_P1_CORRELEXP, 0x0A);
+
+               stv0900_write_reg(i_params, R0900_P1_AGC2REF, 0x38);
+
+               if ((i_params->chip_id >= 0x20) || (blindTunSw == 1) || (i_params->dmd1_symbol_rate < 10000000)) {
+                       stv0900_write_reg(i_params, R0900_P1_CFRINIT1, freq1);
+                       stv0900_write_reg(i_params, R0900_P1_CFRINIT0, freq0);
+                       i_params->tuner1_bw = stv0900_carrier_width(srate, i_params->rolloff) + 10000000;
+
+                       if ((i_params->chip_id >= 0x20) || (blindTunSw == 1)) {
+                               if (i_params->dmd1_srch_algo != STV0900_WARM_START)
+                                       stv0900_set_bandwidth(fe, i_params->tuner1_bw);
+                       }
+
+                       if ((i_params->dmd1_srch_algo == STV0900_BLIND_SEARCH) || (i_params->dmd1_symbol_rate < 10000000))
+                               msleep(50);
+                       else
+                               msleep(5);
+
+                       stv0900_get_lock_timeout(&timed, &timef, srate, STV0900_WARM_START);
+
+                       if (stv0900_get_demod_lock(i_params, demod, timed / 2) == FALSE) {
+                               stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1F);
+                               stv0900_write_reg(i_params, R0900_P1_CFRINIT1, freq1);
+                               stv0900_write_reg(i_params, R0900_P1_CFRINIT0, freq0);
+                               stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x18);
+                               i = 0;
+                               while ((stv0900_get_demod_lock(i_params, demod, timed / 2) == FALSE) && (i <= 2)) {
+                                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1F);
+                                       stv0900_write_reg(i_params, R0900_P1_CFRINIT1, freq1);
+                                       stv0900_write_reg(i_params, R0900_P1_CFRINIT0, freq0);
+                                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x18);
+                                       i++;
+                               }
+                       }
+
+               }
+
+               if (i_params->chip_id >= 0x20)
+                       stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0x49);
+
+               if ((i_params->dmd1_rslts.standard == STV0900_DVBS1_STANDARD) || (i_params->dmd1_rslts.standard == STV0900_DSS_STANDARD))
+                       stv0900_set_viterbi_tracq(i_params, demod);
+
+               break;
+
+       case STV0900_DEMOD_2:
+               switch (i_params->dmd2_rslts.standard) {
+               case STV0900_DVBS1_STANDARD:
+
+                       if (i_params->dmd2_srch_stndrd == STV0900_AUTO_SEARCH) {
+                               stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 1);
+                               stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 0);
+                       }
+
+                       stv0900_write_bits(i_params, F0900_P2_ROLLOFF_CONTROL, i_params->rolloff);
+                       stv0900_write_bits(i_params, F0900_P2_MANUAL_ROLLOFF, 1);
+                       stv0900_write_reg(i_params, R0900_P2_ERRCTRL1, 0x75);
+                       break;
+               case STV0900_DSS_STANDARD:
+                       if (i_params->dmd2_srch_stndrd == STV0900_AUTO_SEARCH) {
+                               stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 1);
+                               stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 0);
+                       }
+
+                       stv0900_write_bits(i_params, F0900_P2_ROLLOFF_CONTROL, i_params->rolloff);
+                       stv0900_write_bits(i_params, F0900_P2_MANUAL_ROLLOFF, 1);
+                       stv0900_write_reg(i_params, R0900_P2_ERRCTRL1, 0x75);
+                       break;
+               case STV0900_DVBS2_STANDARD:
+                       stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 0);
+                       stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 1);
+                       stv0900_write_reg(i_params, R0900_P2_ACLC, 0);
+                       stv0900_write_reg(i_params, R0900_P2_BCLC, 0);
+                       if (i_params->dmd2_rslts.frame_length == STV0900_LONG_FRAME) {
+                               foundModcod = stv0900_get_bits(i_params, F0900_P2_DEMOD_MODCOD);
+                               pilots = stv0900_get_bits(i_params, F0900_P2_DEMOD_TYPE) & 0x01;
+                               aclc = stv0900_get_optim_carr_loop(srate, foundModcod, pilots, i_params->chip_id);
+                               if (foundModcod <= STV0900_QPSK_910)
+                                       stv0900_write_reg(i_params, R0900_P2_ACLC2S2Q, aclc);
+                               else if (foundModcod <= STV0900_8PSK_910) {
+                                       stv0900_write_reg(i_params, R0900_P2_ACLC2S2Q, 0x2a);
+                                       stv0900_write_reg(i_params, R0900_P2_ACLC2S28, aclc);
+                               }
+
+                               if ((i_params->demod_mode == STV0900_SINGLE) && (foundModcod > STV0900_8PSK_910)) {
+                                       if (foundModcod <= STV0900_16APSK_910) {
+                                               stv0900_write_reg(i_params, R0900_P2_ACLC2S2Q, 0x2a);
+                                               stv0900_write_reg(i_params, R0900_P2_ACLC2S216A, aclc);
+                                       } else if (foundModcod <= STV0900_32APSK_910) {
+                                               stv0900_write_reg(i_params, R0900_P2_ACLC2S2Q, 0x2a);
+                                               stv0900_write_reg(i_params, R0900_P2_ACLC2S232A, aclc);
+                                       }
+
+                               }
+
+                       } else {
+                               aclc = stv0900_get_optim_short_carr_loop(srate,
+                                                                       i_params->dmd2_rslts.modulation,
+                                                                       i_params->chip_id);
+
+                               if (i_params->dmd2_rslts.modulation == STV0900_QPSK)
+                                       stv0900_write_reg(i_params, R0900_P2_ACLC2S2Q, aclc);
+
+                               else if (i_params->dmd2_rslts.modulation == STV0900_8PSK) {
+                                       stv0900_write_reg(i_params, R0900_P2_ACLC2S2Q, 0x2a);
+                                       stv0900_write_reg(i_params, R0900_P2_ACLC2S28, aclc);
+                               } else if (i_params->dmd2_rslts.modulation == STV0900_16APSK) {
+                                       stv0900_write_reg(i_params, R0900_P2_ACLC2S2Q, 0x2a);
+                                       stv0900_write_reg(i_params, R0900_P2_ACLC2S216A, aclc);
+                               } else if (i_params->dmd2_rslts.modulation == STV0900_32APSK) {
+                                       stv0900_write_reg(i_params, R0900_P2_ACLC2S2Q, 0x2a);
+                                       stv0900_write_reg(i_params, R0900_P2_ACLC2S232A, aclc);
+                               }
+                       }
+
+                       stv0900_write_reg(i_params, R0900_P2_ERRCTRL1, 0x67);
+
+                       break;
+               case STV0900_UNKNOWN_STANDARD:
+               default:
+                       stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 1);
+                       stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 1);
+                       break;
+               }
+
+               freq1 = stv0900_read_reg(i_params, R0900_P2_CFR2);
+               freq0 = stv0900_read_reg(i_params, R0900_P2_CFR1);
+               rolloff = stv0900_get_bits(i_params, F0900_P2_ROLLOFF_STATUS);
+               if (i_params->dmd2_srch_algo == STV0900_BLIND_SEARCH) {
+                       stv0900_write_reg(i_params, R0900_P2_SFRSTEP, 0x00);
+                       stv0900_write_bits(i_params, F0900_P2_SCAN_ENABLE, 0);
+                       stv0900_write_bits(i_params, F0900_P2_CFR_AUTOSCAN, 0);
+                       stv0900_write_reg(i_params, R0900_P2_TMGCFG2, 0x01);
+                       stv0900_set_symbol_rate(i_params, i_params->mclk, srate, demod);
+                       stv0900_set_max_symbol_rate(i_params, i_params->mclk, srate, demod);
+                       stv0900_set_min_symbol_rate(i_params, i_params->mclk, srate, demod);
+                       blindTunSw = 1;
+               }
+
+               if (i_params->chip_id >= 0x20) {
+                       if ((i_params->dmd2_srch_stndrd == STV0900_SEARCH_DVBS1) || (i_params->dmd2_srch_stndrd == STV0900_SEARCH_DSS) || (i_params->dmd2_srch_stndrd == STV0900_AUTO_SEARCH)) {
+                               stv0900_write_reg(i_params, R0900_P2_VAVSRVIT, 0x0a);
+                               stv0900_write_reg(i_params, R0900_P2_VITSCALE, 0x0);
+                       }
+               }
+
+               if (i_params->chip_id < 0x20)
+                       stv0900_write_reg(i_params, R0900_P2_CARHDR, 0x08);
+
+               if (i_params->chip_id == 0x10)
+                       stv0900_write_reg(i_params, R0900_P2_CORRELEXP, 0x0a);
+
+               stv0900_write_reg(i_params, R0900_P2_AGC2REF, 0x38);
+               if ((i_params->chip_id >= 0x20) || (blindTunSw == 1) || (i_params->dmd2_symbol_rate < 10000000)) {
+                       stv0900_write_reg(i_params, R0900_P2_CFRINIT1, freq1);
+                       stv0900_write_reg(i_params, R0900_P2_CFRINIT0, freq0);
+                       i_params->tuner2_bw = stv0900_carrier_width(srate, i_params->rolloff) + 10000000;
+
+                       if ((i_params->chip_id >= 0x20) || (blindTunSw == 1)) {
+                               if (i_params->dmd2_srch_algo != STV0900_WARM_START)
+                                       stv0900_set_bandwidth(fe, i_params->tuner2_bw);
+                       }
+
+                       if ((i_params->dmd2_srch_algo == STV0900_BLIND_SEARCH) || (i_params->dmd2_symbol_rate < 10000000))
+                               msleep(50);
+                       else
+                               msleep(5);
+
+                       stv0900_get_lock_timeout(&timed, &timef, srate, STV0900_WARM_START);
+                       if (stv0900_get_demod_lock(i_params, demod, timed / 2) == FALSE) {
+                               stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1F);
+                               stv0900_write_reg(i_params, R0900_P2_CFRINIT1, freq1);
+                               stv0900_write_reg(i_params, R0900_P2_CFRINIT0, freq0);
+                               stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x18);
+                               i = 0;
+                               while ((stv0900_get_demod_lock(i_params, demod, timed / 2) == FALSE) && (i <= 2)) {
+                                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1F);
+                                       stv0900_write_reg(i_params, R0900_P2_CFRINIT1, freq1);
+                                       stv0900_write_reg(i_params, R0900_P2_CFRINIT0, freq0);
+                                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x18);
+                                       i++;
+                               }
+                       }
+               }
+
+               if (i_params->chip_id >= 0x20)
+                       stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0x49);
+
+               if ((i_params->dmd2_rslts.standard == STV0900_DVBS1_STANDARD) || (i_params->dmd2_rslts.standard == STV0900_DSS_STANDARD))
+                       stv0900_set_viterbi_tracq(i_params, demod);
+
+               break;
+       }
+}
+
+static int stv0900_get_fec_lock(struct stv0900_internal *i_params, enum fe_stv0900_demod_num demod, s32 time_out)
+{
+       s32 timer = 0, lock = 0, header_field, pktdelin_field, lock_vit_field;
+
+       enum fe_stv0900_search_state dmd_state;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       dmd_reg(header_field, F0900_P1_HEADER_MODE, F0900_P2_HEADER_MODE);
+       dmd_reg(pktdelin_field, F0900_P1_PKTDELIN_LOCK, F0900_P2_PKTDELIN_LOCK);
+       dmd_reg(lock_vit_field, F0900_P1_LOCKEDVIT, F0900_P2_LOCKEDVIT);
+
+       dmd_state = stv0900_get_bits(i_params, header_field);
+
+       while ((timer < time_out) && (lock == 0)) {
+               switch (dmd_state) {
+               case STV0900_SEARCH:
+               case STV0900_PLH_DETECTED:
+               default:
+                       lock = 0;
+                       break;
+               case STV0900_DVBS2_FOUND:
+                       lock = stv0900_get_bits(i_params, pktdelin_field);
+                       break;
+               case STV0900_DVBS_FOUND:
+                       lock = stv0900_get_bits(i_params, lock_vit_field);
+                       break;
+               }
+
+               if (lock == 0) {
+                       msleep(10);
+                       timer += 10;
+               }
+       }
+
+       if (lock)
+               dprintk("DEMOD FEC LOCK OK\n");
+       else
+               dprintk("DEMOD FEC LOCK FAIL\n");
+
+       return lock;
+}
+
+static int stv0900_wait_for_lock(struct stv0900_internal *i_params,
+                               enum fe_stv0900_demod_num demod,
+                               s32 dmd_timeout, s32 fec_timeout)
+{
+
+       s32 timer = 0, lock = 0, str_merg_rst_fld, str_merg_lock_fld;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       dmd_reg(str_merg_rst_fld, F0900_P1_RST_HWARE, F0900_P2_RST_HWARE);
+       dmd_reg(str_merg_lock_fld, F0900_P1_TSFIFO_LINEOK, F0900_P2_TSFIFO_LINEOK);
+
+       lock = stv0900_get_demod_lock(i_params, demod, dmd_timeout);
+
+       if (lock)
+               lock = lock && stv0900_get_fec_lock(i_params, demod, fec_timeout);
+
+       if (lock) {
+               lock = 0;
+
+               dprintk(KERN_INFO "%s: Timer = %d, time_out = %d\n", __func__, timer, fec_timeout);
+
+               while ((timer < fec_timeout) && (lock == 0)) {
+                       lock = stv0900_get_bits(i_params, str_merg_lock_fld);
+                       msleep(1);
+                       timer++;
+               }
+       }
+
+       if (lock)
+               dprintk(KERN_INFO "%s: DEMOD LOCK OK\n", __func__);
+       else
+               dprintk(KERN_INFO "%s: DEMOD LOCK FAIL\n", __func__);
+
+       if (lock)
+               return TRUE;
+       else
+               return FALSE;
+}
+
+enum fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe,
+                                               enum fe_stv0900_demod_num demod)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       enum fe_stv0900_tracking_standard fnd_standard;
+       s32 state_field,
+       dss_dvb_field;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       dmd_reg(state_field, F0900_P1_HEADER_MODE, F0900_P2_HEADER_MODE);
+       dmd_reg(dss_dvb_field, F0900_P1_DSS_DVB, F0900_P2_DSS_DVB);
+
+       if (stv0900_get_bits(i_params, state_field) == 2)
+               fnd_standard = STV0900_DVBS2_STANDARD;
+
+       else if (stv0900_get_bits(i_params, state_field) == 3) {
+               if (stv0900_get_bits(i_params, dss_dvb_field) == 1)
+                       fnd_standard = STV0900_DSS_STANDARD;
+               else
+                       fnd_standard = STV0900_DVBS1_STANDARD;
+       } else
+               fnd_standard = STV0900_UNKNOWN_STANDARD;
+
+       return fnd_standard;
+}
+
+static s32 stv0900_get_carr_freq(struct stv0900_internal *i_params, u32 mclk,
+                                       enum fe_stv0900_demod_num demod)
+{
+       s32 cfr_field2, cfr_field1, cfr_field0,
+               derot, rem1, rem2, intval1, intval2;
+
+       dmd_reg(cfr_field2, F0900_P1_CAR_FREQ2, F0900_P2_CAR_FREQ2);
+       dmd_reg(cfr_field1, F0900_P1_CAR_FREQ1, F0900_P2_CAR_FREQ1);
+       dmd_reg(cfr_field0, F0900_P1_CAR_FREQ0, F0900_P2_CAR_FREQ0);
+
+       derot = (stv0900_get_bits(i_params, cfr_field2) << 16) +
+               (stv0900_get_bits(i_params, cfr_field1) << 8) +
+               (stv0900_get_bits(i_params, cfr_field0));
+
+       derot = ge2comp(derot, 24);
+       intval1 = mclk >> 12;
+       intval2 = derot >> 12;
+       rem1 = mclk % 0x1000;
+       rem2 = derot % 0x1000;
+       derot = (intval1 * intval2) +
+               ((intval1 * rem2) >> 12) +
+               ((intval2 * rem1) >> 12);
+
+       return derot;
+}
+
+static u32 stv0900_get_tuner_freq(struct dvb_frontend *fe)
+{
+       struct dvb_frontend_ops *frontend_ops = NULL;
+       struct dvb_tuner_ops *tuner_ops = NULL;
+       u32 frequency = 0;
+
+       if (&fe->ops)
+               frontend_ops = &fe->ops;
+
+       if (&frontend_ops->tuner_ops)
+               tuner_ops = &frontend_ops->tuner_ops;
+
+       if (tuner_ops->get_frequency) {
+               if ((tuner_ops->get_frequency(fe, &frequency)) < 0)
+                       dprintk("%s: Invalid parameter\n", __func__);
+               else
+                       dprintk("%s: Frequency=%d\n", __func__, frequency);
+
+       }
+
+       return frequency;
+}
+
+static enum fe_stv0900_fec stv0900_get_vit_fec(struct stv0900_internal *i_params,
+                                               enum fe_stv0900_demod_num demod)
+{
+       s32 rate_fld, vit_curpun_fld;
+       enum fe_stv0900_fec prate;
+
+       dmd_reg(vit_curpun_fld, F0900_P1_VIT_CURPUN, F0900_P2_VIT_CURPUN);
+       rate_fld = stv0900_get_bits(i_params, vit_curpun_fld);
+
+       switch (rate_fld) {
+       case 13:
+               prate = STV0900_FEC_1_2;
+               break;
+       case 18:
+               prate = STV0900_FEC_2_3;
+               break;
+       case 21:
+               prate = STV0900_FEC_3_4;
+               break;
+       case 24:
+               prate = STV0900_FEC_5_6;
+               break;
+       case 25:
+               prate = STV0900_FEC_6_7;
+               break;
+       case 26:
+               prate = STV0900_FEC_7_8;
+               break;
+       default:
+               prate = STV0900_FEC_UNKNOWN;
+               break;
+       }
+
+       return prate;
+}
+
+static enum fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       enum fe_stv0900_demod_num demod = state->demod;
+       enum fe_stv0900_signal_type range = STV0900_OUTOFRANGE;
+       s32 offsetFreq,
+       srate_offset,
+       i = 0;
+
+       u8 timing;
+
+       msleep(5);
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               if (i_params->dmd1_srch_algo == STV0900_BLIND_SEARCH) {
+                       timing = stv0900_read_reg(i_params, R0900_P1_TMGREG2);
+                       i = 0;
+                       stv0900_write_reg(i_params, R0900_P1_SFRSTEP, 0x5c);
+
+                       while ((i <= 50) && (timing != 0) && (timing != 0xFF)) {
+                               timing = stv0900_read_reg(i_params, R0900_P1_TMGREG2);
+                               msleep(5);
+                               i += 5;
+                       }
+               }
+
+               i_params->dmd1_rslts.standard = stv0900_get_standard(fe, demod);
+               i_params->dmd1_rslts.frequency = stv0900_get_tuner_freq(fe);
+               offsetFreq = stv0900_get_carr_freq(i_params, i_params->mclk, demod) / 1000;
+               i_params->dmd1_rslts.frequency += offsetFreq;
+               i_params->dmd1_rslts.symbol_rate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
+               srate_offset = stv0900_get_timing_offst(i_params, i_params->dmd1_rslts.symbol_rate, demod);
+               i_params->dmd1_rslts.symbol_rate += srate_offset;
+               i_params->dmd1_rslts.fec = stv0900_get_vit_fec(i_params, demod);
+               i_params->dmd1_rslts.modcode = stv0900_get_bits(i_params, F0900_P1_DEMOD_MODCOD);
+               i_params->dmd1_rslts.pilot = stv0900_get_bits(i_params, F0900_P1_DEMOD_TYPE) & 0x01;
+               i_params->dmd1_rslts.frame_length = ((u32)stv0900_get_bits(i_params, F0900_P1_DEMOD_TYPE)) >> 1;
+               i_params->dmd1_rslts.rolloff = stv0900_get_bits(i_params, F0900_P1_ROLLOFF_STATUS);
+               switch (i_params->dmd1_rslts.standard) {
+               case STV0900_DVBS2_STANDARD:
+                       i_params->dmd1_rslts.spectrum = stv0900_get_bits(i_params, F0900_P1_SPECINV_DEMOD);
+                       if (i_params->dmd1_rslts.modcode <= STV0900_QPSK_910)
+                               i_params->dmd1_rslts.modulation = STV0900_QPSK;
+                       else if (i_params->dmd1_rslts.modcode <= STV0900_8PSK_910)
+                               i_params->dmd1_rslts.modulation = STV0900_8PSK;
+                       else if (i_params->dmd1_rslts.modcode <= STV0900_16APSK_910)
+                               i_params->dmd1_rslts.modulation = STV0900_16APSK;
+                       else if (i_params->dmd1_rslts.modcode <= STV0900_32APSK_910)
+                               i_params->dmd1_rslts.modulation = STV0900_32APSK;
+                       else
+                               i_params->dmd1_rslts.modulation = STV0900_UNKNOWN;
+                       break;
+               case STV0900_DVBS1_STANDARD:
+               case STV0900_DSS_STANDARD:
+                       i_params->dmd1_rslts.spectrum = stv0900_get_bits(i_params, F0900_P1_IQINV);
+                       i_params->dmd1_rslts.modulation = STV0900_QPSK;
+                       break;
+               default:
+                       break;
+               }
+
+               if ((i_params->dmd1_srch_algo == STV0900_BLIND_SEARCH) || (i_params->dmd1_symbol_rate < 10000000)) {
+                       offsetFreq =    i_params->dmd1_rslts.frequency - i_params->tuner1_freq;
+                       i_params->tuner1_freq = stv0900_get_tuner_freq(fe);
+                       if (ABS(offsetFreq) <= ((i_params->dmd1_srch_range / 2000) + 500))
+                               range = STV0900_RANGEOK;
+                       else
+                               if (ABS(offsetFreq) <= (stv0900_carrier_width(i_params->dmd1_rslts.symbol_rate, i_params->dmd1_rslts.rolloff) / 2000))
+                                       range = STV0900_RANGEOK;
+                               else
+                                       range = STV0900_OUTOFRANGE;
+
+               } else {
+                       if (ABS(offsetFreq) <= ((i_params->dmd1_srch_range / 2000) + 500))
+                               range = STV0900_RANGEOK;
+                       else
+                               range = STV0900_OUTOFRANGE;
+               }
+               break;
+       case STV0900_DEMOD_2:
+               if (i_params->dmd2_srch_algo == STV0900_BLIND_SEARCH) {
+                       timing = stv0900_read_reg(i_params, R0900_P2_TMGREG2);
+                       i = 0;
+                       stv0900_write_reg(i_params, R0900_P2_SFRSTEP, 0x5c);
+
+                       while ((i <= 50) && (timing != 0) && (timing != 0xff)) {
+                               timing = stv0900_read_reg(i_params, R0900_P2_TMGREG2);
+                               msleep(5);
+                               i += 5;
+                       }
+               }
+
+               i_params->dmd2_rslts.standard = stv0900_get_standard(fe, demod);
+               i_params->dmd2_rslts.frequency = stv0900_get_tuner_freq(fe);
+               offsetFreq = stv0900_get_carr_freq(i_params, i_params->mclk, demod) / 1000;
+               i_params->dmd2_rslts.frequency += offsetFreq;
+               i_params->dmd2_rslts.symbol_rate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
+               srate_offset = stv0900_get_timing_offst(i_params, i_params->dmd2_rslts.symbol_rate, demod);
+               i_params->dmd2_rslts.symbol_rate += srate_offset;
+               i_params->dmd2_rslts.fec = stv0900_get_vit_fec(i_params, demod);
+               i_params->dmd2_rslts.modcode = stv0900_get_bits(i_params, F0900_P2_DEMOD_MODCOD);
+               i_params->dmd2_rslts.pilot = stv0900_get_bits(i_params, F0900_P2_DEMOD_TYPE) & 0x01;
+               i_params->dmd2_rslts.frame_length = ((u32)stv0900_get_bits(i_params, F0900_P2_DEMOD_TYPE)) >> 1;
+               i_params->dmd2_rslts.rolloff = stv0900_get_bits(i_params, F0900_P2_ROLLOFF_STATUS);
+               switch (i_params->dmd2_rslts.standard) {
+               case STV0900_DVBS2_STANDARD:
+                       i_params->dmd2_rslts.spectrum = stv0900_get_bits(i_params, F0900_P2_SPECINV_DEMOD);
+                       if (i_params->dmd2_rslts.modcode <= STV0900_QPSK_910)
+                               i_params->dmd2_rslts.modulation = STV0900_QPSK;
+                       else if (i_params->dmd2_rslts.modcode <= STV0900_8PSK_910)
+                               i_params->dmd2_rslts.modulation = STV0900_8PSK;
+                       else if (i_params->dmd2_rslts.modcode <= STV0900_16APSK_910)
+                               i_params->dmd2_rslts.modulation = STV0900_16APSK;
+                       else if (i_params->dmd2_rslts.modcode <= STV0900_32APSK_910)
+                               i_params->dmd2_rslts.modulation = STV0900_32APSK;
+                       else
+                               i_params->dmd2_rslts.modulation = STV0900_UNKNOWN;
+                       break;
+               case STV0900_DVBS1_STANDARD:
+               case STV0900_DSS_STANDARD:
+                       i_params->dmd2_rslts.spectrum = stv0900_get_bits(i_params, F0900_P2_IQINV);
+                       i_params->dmd2_rslts.modulation = STV0900_QPSK;
+                       break;
+               default:
+                       break;
+               }
+
+               if ((i_params->dmd2_srch_algo == STV0900_BLIND_SEARCH) || (i_params->dmd2_symbol_rate < 10000000)) {
+                       offsetFreq =    i_params->dmd2_rslts.frequency - i_params->tuner2_freq;
+                       i_params->tuner2_freq = stv0900_get_tuner_freq(fe);
+
+                       if (ABS(offsetFreq) <= ((i_params->dmd2_srch_range / 2000) + 500))
+                               range = STV0900_RANGEOK;
+                       else
+                               if (ABS(offsetFreq) <= (stv0900_carrier_width(i_params->dmd2_rslts.symbol_rate, i_params->dmd2_rslts.rolloff) / 2000))
+                                       range = STV0900_RANGEOK;
+                               else
+                                       range = STV0900_OUTOFRANGE;
+               } else {
+                       if (ABS(offsetFreq) <= ((i_params->dmd2_srch_range / 2000) + 500))
+                               range = STV0900_RANGEOK;
+                       else
+                               range = STV0900_OUTOFRANGE;
+               }
+
+               break;
+       }
+
+       return range;
+}
+
+static enum fe_stv0900_signal_type stv0900_dvbs1_acq_workaround(struct dvb_frontend *fe)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       enum fe_stv0900_demod_num demod = state->demod;
+
+       s32 srate, demod_timeout,
+               fec_timeout, freq1, freq0;
+       enum fe_stv0900_signal_type signal_type = STV0900_NODATA;;
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               i_params->dmd1_rslts.locked = FALSE;
+               if (stv0900_get_bits(i_params, F0900_P1_HEADER_MODE) == STV0900_DVBS_FOUND) {
+                       srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
+                       srate += stv0900_get_timing_offst(i_params, srate, demod);
+                       if (i_params->dmd1_srch_algo == STV0900_BLIND_SEARCH)
+                               stv0900_set_symbol_rate(i_params, i_params->mclk, srate, demod);
+
+                       stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, srate, STV0900_WARM_START);
+                       freq1 = stv0900_read_reg(i_params, R0900_P1_CFR2);
+                       freq0 = stv0900_read_reg(i_params, R0900_P1_CFR1);
+                       stv0900_write_bits(i_params, F0900_P1_CFR_AUTOSCAN, 0);
+                       stv0900_write_bits(i_params, F0900_P1_SPECINV_CONTROL, STV0900_IQ_FORCE_SWAPPED);
+                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1C);
+                       stv0900_write_reg(i_params, R0900_P1_CFRINIT1, freq1);
+                       stv0900_write_reg(i_params, R0900_P1_CFRINIT0, freq0);
+                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x18);
+                       if (stv0900_wait_for_lock(i_params, demod, demod_timeout, fec_timeout) == TRUE) {
+                               i_params->dmd1_rslts.locked = TRUE;
+                               signal_type = stv0900_get_signal_params(fe);
+                               stv0900_track_optimization(fe);
+                       } else {
+                               stv0900_write_bits(i_params, F0900_P1_SPECINV_CONTROL, STV0900_IQ_FORCE_NORMAL);
+                               stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1c);
+                               stv0900_write_reg(i_params, R0900_P1_CFRINIT1, freq1);
+                               stv0900_write_reg(i_params, R0900_P1_CFRINIT0, freq0);
+                               stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x18);
+                               if (stv0900_wait_for_lock(i_params, demod, demod_timeout, fec_timeout) == TRUE) {
+                                       i_params->dmd1_rslts.locked = TRUE;
+                                       signal_type = stv0900_get_signal_params(fe);
+                                       stv0900_track_optimization(fe);
+                               }
+
+                       }
+
+               } else
+                       i_params->dmd1_rslts.locked = FALSE;
+
+               break;
+       case STV0900_DEMOD_2:
+               i_params->dmd2_rslts.locked = FALSE;
+               if (stv0900_get_bits(i_params, F0900_P2_HEADER_MODE) == STV0900_DVBS_FOUND) {
+                       srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
+                       srate += stv0900_get_timing_offst(i_params, srate, demod);
+
+                       if (i_params->dmd2_srch_algo == STV0900_BLIND_SEARCH)
+                               stv0900_set_symbol_rate(i_params, i_params->mclk, srate, demod);
+
+                       stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, srate, STV0900_WARM_START);
+                       freq1 = stv0900_read_reg(i_params, R0900_P2_CFR2);
+                       freq0 = stv0900_read_reg(i_params, R0900_P2_CFR1);
+                       stv0900_write_bits(i_params, F0900_P2_CFR_AUTOSCAN, 0);
+                       stv0900_write_bits(i_params, F0900_P2_SPECINV_CONTROL, STV0900_IQ_FORCE_SWAPPED);
+                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1C);
+                       stv0900_write_reg(i_params, R0900_P2_CFRINIT1, freq1);
+                       stv0900_write_reg(i_params, R0900_P2_CFRINIT0, freq0);
+                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x18);
+
+                       if (stv0900_wait_for_lock(i_params, demod, demod_timeout, fec_timeout) == TRUE) {
+                               i_params->dmd2_rslts.locked = TRUE;
+                               signal_type = stv0900_get_signal_params(fe);
+                               stv0900_track_optimization(fe);
+                       } else {
+                               stv0900_write_bits(i_params, F0900_P2_SPECINV_CONTROL, STV0900_IQ_FORCE_NORMAL);
+                               stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1c);
+                               stv0900_write_reg(i_params, R0900_P2_CFRINIT1, freq1);
+                               stv0900_write_reg(i_params, R0900_P2_CFRINIT0, freq0);
+                               stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x18);
+
+                               if (stv0900_wait_for_lock(i_params, demod, demod_timeout, fec_timeout) == TRUE) {
+                                       i_params->dmd2_rslts.locked = TRUE;
+                                       signal_type = stv0900_get_signal_params(fe);
+                                       stv0900_track_optimization(fe);
+                               }
+
+                       }
+
+               } else
+                       i_params->dmd1_rslts.locked = FALSE;
+
+               break;
+       }
+
+       return signal_type;
+}
+
+static u16 stv0900_blind_check_agc2_min_level(struct stv0900_internal *i_params,
+                                       enum fe_stv0900_demod_num demod)
+{
+       u32 minagc2level = 0xffff,
+               agc2level,
+               init_freq, freq_step;
+
+       s32 i, j, nb_steps, direction;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               stv0900_write_reg(i_params, R0900_P1_AGC2REF, 0x38);
+               stv0900_write_bits(i_params, F0900_P1_SCAN_ENABLE, 1);
+               stv0900_write_bits(i_params, F0900_P1_CFR_AUTOSCAN, 1);
+
+               stv0900_write_reg(i_params, R0900_P1_SFRUP1, 0x83);
+               stv0900_write_reg(i_params, R0900_P1_SFRUP0, 0xc0);
+
+               stv0900_write_reg(i_params, R0900_P1_SFRLOW1, 0x82);
+               stv0900_write_reg(i_params, R0900_P1_SFRLOW0, 0xa0);
+               stv0900_write_reg(i_params, R0900_P1_DMDT0M, 0x0);
+
+               stv0900_set_symbol_rate(i_params, i_params->mclk, 1000000, demod);
+               nb_steps = -1 + (i_params->dmd1_srch_range / 1000000);
+               nb_steps /= 2;
+               nb_steps = (2 * nb_steps) + 1;
+
+               if (nb_steps < 0)
+                       nb_steps = 1;
+
+               direction = 1;
+
+               freq_step = (1000000 << 8) / (i_params->mclk >> 8);
+
+               init_freq = 0;
+
+               for (i = 0; i < nb_steps; i++) {
+                       if (direction > 0)
+                               init_freq = init_freq + (freq_step * i);
+                       else
+                               init_freq = init_freq - (freq_step * i);
+
+                       direction *= -1;
+                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x5C);
+                       stv0900_write_reg(i_params, R0900_P1_CFRINIT1, (init_freq >> 8) & 0xff);
+                       stv0900_write_reg(i_params, R0900_P1_CFRINIT0, init_freq  & 0xff);
+                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x58);
+                       msleep(10);
+                       agc2level = 0;
+
+                       for (j = 0; j < 10; j++)
+                               agc2level += (stv0900_read_reg(i_params, R0900_P1_AGC2I1) << 8)
+                                               | stv0900_read_reg(i_params, R0900_P1_AGC2I0);
+
+                       agc2level /= 10;
+
+                       if (agc2level < minagc2level)
+                               minagc2level = agc2level;
+               }
+               break;
+       case STV0900_DEMOD_2:
+               stv0900_write_reg(i_params, R0900_P2_AGC2REF, 0x38);
+               stv0900_write_bits(i_params, F0900_P2_SCAN_ENABLE, 1);
+               stv0900_write_bits(i_params, F0900_P2_CFR_AUTOSCAN, 1);
+               stv0900_write_reg(i_params, R0900_P2_SFRUP1, 0x83);
+               stv0900_write_reg(i_params, R0900_P2_SFRUP0, 0xc0);
+               stv0900_write_reg(i_params, R0900_P2_SFRLOW1, 0x82);
+               stv0900_write_reg(i_params, R0900_P2_SFRLOW0, 0xa0);
+               stv0900_write_reg(i_params, R0900_P2_DMDT0M, 0x0);
+               stv0900_set_symbol_rate(i_params, i_params->mclk, 1000000, demod);
+               nb_steps = -1 + (i_params->dmd2_srch_range / 1000000);
+               nb_steps /= 2;
+               nb_steps = (2 * nb_steps) + 1;
+
+               if (nb_steps < 0)
+                       nb_steps = 1;
+
+               direction = 1;
+               freq_step = (1000000 << 8) / (i_params->mclk >> 8);
+               init_freq = 0;
+               for (i = 0; i < nb_steps; i++) {
+                       if (direction > 0)
+                               init_freq = init_freq + (freq_step * i);
+                       else
+                               init_freq = init_freq - (freq_step * i);
+
+                       direction *= -1;
+
+                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x5C);
+                       stv0900_write_reg(i_params, R0900_P2_CFRINIT1, (init_freq >> 8) & 0xff);
+                       stv0900_write_reg(i_params, R0900_P2_CFRINIT0, init_freq  & 0xff);
+                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x58);
+
+                       msleep(10);
+                       agc2level = 0;
+                       for (j = 0; j < 10; j++)
+                               agc2level += (stv0900_read_reg(i_params, R0900_P2_AGC2I1) << 8)
+                                               | stv0900_read_reg(i_params, R0900_P2_AGC2I0);
+
+                       agc2level /= 10;
+
+                       if (agc2level < minagc2level)
+                               minagc2level = agc2level;
+               }
+               break;
+       }
+
+       return (u16)minagc2level;
+}
+
+static u32 stv0900_search_srate_coarse(struct dvb_frontend *fe)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       enum fe_stv0900_demod_num demod = state->demod;
+       int timingLock = FALSE;
+       s32 i, timingcpt = 0,
+               direction = 1,
+               nb_steps,
+               current_step = 0,
+               tuner_freq;
+
+       u32 coarse_srate = 0, agc2_integr = 0, currier_step = 1200;
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               stv0900_write_bits(i_params, F0900_P1_I2C_DEMOD_MODE, 0x1F);
+               stv0900_write_reg(i_params, R0900_P1_TMGCFG, 0x12);
+               stv0900_write_reg(i_params, R0900_P1_TMGTHRISE, 0xf0);
+               stv0900_write_reg(i_params, R0900_P1_TMGTHFALL, 0xe0);
+               stv0900_write_bits(i_params, F0900_P1_SCAN_ENABLE, 1);
+               stv0900_write_bits(i_params, F0900_P1_CFR_AUTOSCAN, 1);
+               stv0900_write_reg(i_params, R0900_P1_SFRUP1, 0x83);
+               stv0900_write_reg(i_params, R0900_P1_SFRUP0, 0xc0);
+               stv0900_write_reg(i_params, R0900_P1_SFRLOW1, 0x82);
+               stv0900_write_reg(i_params, R0900_P1_SFRLOW0, 0xa0);
+               stv0900_write_reg(i_params, R0900_P1_DMDT0M, 0x0);
+               stv0900_write_reg(i_params, R0900_P1_AGC2REF, 0x50);
+
+               if (i_params->chip_id >= 0x20) {
+                       stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0x6a);
+                       stv0900_write_reg(i_params, R0900_P1_SFRSTEP, 0x95);
+               } else {
+                       stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0xed);
+                       stv0900_write_reg(i_params, R0900_P1_SFRSTEP, 0x73);
+               }
+
+               if (i_params->dmd1_symbol_rate <= 2000000)
+                       currier_step = 1000;
+               else if (i_params->dmd1_symbol_rate <= 5000000)
+                       currier_step = 2000;
+               else if (i_params->dmd1_symbol_rate <= 12000000)
+                       currier_step = 3000;
+               else
+                       currier_step = 5000;
+
+               nb_steps = -1 + ((i_params->dmd1_srch_range / 1000) / currier_step);
+               nb_steps /= 2;
+               nb_steps = (2 * nb_steps) + 1;
+
+               if (nb_steps < 0)
+                       nb_steps = 1;
+
+               else if (nb_steps > 10) {
+                       nb_steps = 11;
+                       currier_step = (i_params->dmd1_srch_range / 1000) / 10;
+               }
+
+               current_step = 0;
+
+               direction = 1;
+               tuner_freq = i_params->tuner1_freq;
+
+               while ((timingLock == FALSE) && (current_step < nb_steps)) {
+                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x5F);
+                       stv0900_write_bits(i_params, F0900_P1_I2C_DEMOD_MODE, 0x0);
+
+                       msleep(50);
+
+                       for (i = 0; i < 10; i++) {
+                               if (stv0900_get_bits(i_params, F0900_P1_TMGLOCK_QUALITY) >= 2)
+                                       timingcpt++;
+
+                               agc2_integr += (stv0900_read_reg(i_params, R0900_P1_AGC2I1) << 8) | stv0900_read_reg(i_params, R0900_P1_AGC2I0);
+
+                       }
+
+                       agc2_integr /= 10;
+                       coarse_srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
+                       current_step++;
+                       direction *= -1;
+
+                       dprintk("lock: I2C_DEMOD_MODE_FIELD =0. Search started. tuner freq=%d agc2=0x%x srate_coarse=%d tmg_cpt=%d\n", tuner_freq, agc2_integr, coarse_srate, timingcpt);
+
+                       if ((timingcpt >= 5) && (agc2_integr < 0x1F00) && (coarse_srate < 55000000) && (coarse_srate > 850000)) {
+                               timingLock = TRUE;
+                       }
+
+                       else if (current_step < nb_steps) {
+                               if (direction > 0)
+                                       tuner_freq += (current_step * currier_step);
+                               else
+                                       tuner_freq -= (current_step * currier_step);
+
+                               stv0900_set_tuner(fe, tuner_freq, i_params->tuner1_bw);
+                       }
+               }
+
+               if (timingLock == FALSE)
+                       coarse_srate = 0;
+               else
+                       coarse_srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
+               break;
+       case STV0900_DEMOD_2:
+               stv0900_write_bits(i_params, F0900_P2_I2C_DEMOD_MODE, 0x1F);
+               stv0900_write_reg(i_params, R0900_P2_TMGCFG, 0x12);
+               stv0900_write_reg(i_params, R0900_P2_TMGTHRISE, 0xf0);
+               stv0900_write_reg(i_params, R0900_P2_TMGTHFALL, 0xe0);
+               stv0900_write_bits(i_params, F0900_P2_SCAN_ENABLE, 1);
+               stv0900_write_bits(i_params, F0900_P2_CFR_AUTOSCAN, 1);
+               stv0900_write_reg(i_params, R0900_P2_SFRUP1, 0x83);
+               stv0900_write_reg(i_params, R0900_P2_SFRUP0, 0xc0);
+               stv0900_write_reg(i_params, R0900_P2_SFRLOW1, 0x82);
+               stv0900_write_reg(i_params, R0900_P2_SFRLOW0, 0xa0);
+               stv0900_write_reg(i_params, R0900_P2_DMDT0M, 0x0);
+               stv0900_write_reg(i_params, R0900_P2_AGC2REF, 0x50);
+
+               if (i_params->chip_id >= 0x20) {
+                       stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0x6a);
+                       stv0900_write_reg(i_params, R0900_P2_SFRSTEP, 0x95);
+               } else {
+                       stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0xed);
+                       stv0900_write_reg(i_params, R0900_P2_SFRSTEP, 0x73);
+               }
+
+               if (i_params->dmd2_symbol_rate <= 2000000)
+                       currier_step = 1000;
+               else if (i_params->dmd2_symbol_rate <= 5000000)
+                       currier_step = 2000;
+               else if (i_params->dmd2_symbol_rate <= 12000000)
+                       currier_step = 3000;
+               else
+                       currier_step = 5000;
+
+
+               nb_steps = -1 + ((i_params->dmd2_srch_range / 1000) / currier_step);
+               nb_steps /= 2;
+               nb_steps = (2 * nb_steps) + 1;
+
+               if (nb_steps < 0)
+                       nb_steps = 1;
+               else if (nb_steps > 10) {
+                       nb_steps = 11;
+                       currier_step = (i_params->dmd2_srch_range / 1000) / 10;
+               }
+
+               current_step = 0;
+               direction = 1;
+               tuner_freq = i_params->tuner2_freq;
+
+               while ((timingLock == FALSE) && (current_step < nb_steps)) {
+                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x5F);
+                       stv0900_write_bits(i_params, F0900_P2_I2C_DEMOD_MODE, 0x0);
+
+                       msleep(50);
+                       timingcpt = 0;
+
+                       for (i = 0; i < 20; i++) {
+                               if (stv0900_get_bits(i_params, F0900_P2_TMGLOCK_QUALITY) >= 2)
+                                       timingcpt++;
+                               agc2_integr += (stv0900_read_reg(i_params, R0900_P2_AGC2I1) << 8)
+                                                               | stv0900_read_reg(i_params, R0900_P2_AGC2I0);
+                       }
+
+                       agc2_integr /= 20;
+                       coarse_srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
+                       if ((timingcpt >= 10) && (agc2_integr < 0x1F00) && (coarse_srate < 55000000) && (coarse_srate > 850000))
+                               timingLock = TRUE;
+                       else {
+                               current_step++;
+                               direction *= -1;
+
+                               if (direction > 0)
+                                       tuner_freq += (current_step * currier_step);
+                               else
+                                       tuner_freq -= (current_step * currier_step);
+
+                               stv0900_set_tuner(fe, tuner_freq, i_params->tuner2_bw);
+                       }
+               }
+
+               if (timingLock == FALSE)
+                       coarse_srate = 0;
+               else
+                       coarse_srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
+               break;
+       }
+
+       return coarse_srate;
+}
+
+static u32 stv0900_search_srate_fine(struct dvb_frontend *fe)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       enum fe_stv0900_demod_num demod = state->demod;
+       u32 coarse_srate,
+       coarse_freq,
+       symb;
+
+       coarse_srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               coarse_freq = (stv0900_read_reg(i_params, R0900_P1_CFR2) << 8)
+                                               | stv0900_read_reg(i_params, R0900_P1_CFR1);
+               symb = 13 * (coarse_srate / 10);
+
+               if (symb < i_params->dmd1_symbol_rate)
+                       coarse_srate = 0;
+               else {
+                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1F);
+                       stv0900_write_reg(i_params, R0900_P1_TMGCFG2, 0x01);
+                       stv0900_write_reg(i_params, R0900_P1_TMGTHRISE, 0x20);
+                       stv0900_write_reg(i_params, R0900_P1_TMGTHFALL, 0x00);
+                       stv0900_write_reg(i_params, R0900_P1_TMGCFG, 0xd2);
+                       stv0900_write_bits(i_params, F0900_P1_CFR_AUTOSCAN, 0);
+
+                       if (i_params->chip_id >= 0x20)
+                               stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0x49);
+                       else
+                               stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0xed);
+
+                       if (coarse_srate > 3000000) {
+                               symb = 13 * (coarse_srate / 10);
+                               symb = (symb / 1000) * 65536;
+                               symb /= (i_params->mclk / 1000);
+                               stv0900_write_reg(i_params, R0900_P1_SFRUP1, (symb >> 8) & 0x7F);
+                               stv0900_write_reg(i_params, R0900_P1_SFRUP0, (symb & 0xFF));
+
+                               symb = 10 * (coarse_srate / 13);
+                               symb = (symb / 1000) * 65536;
+                               symb /= (i_params->mclk / 1000);
+
+                               stv0900_write_reg(i_params, R0900_P1_SFRLOW1, (symb >> 8) & 0x7F);
+                               stv0900_write_reg(i_params, R0900_P1_SFRLOW0, (symb & 0xFF));
+
+                               symb = (coarse_srate / 1000) * 65536;
+                               symb /= (i_params->mclk / 1000);
+                               stv0900_write_reg(i_params, R0900_P1_SFRINIT1, (symb >> 8) & 0xFF);
+                               stv0900_write_reg(i_params, R0900_P1_SFRINIT0, (symb & 0xFF));
+                       } else {
+                               symb = 13 * (coarse_srate / 10);
+                               symb = (symb / 100) * 65536;
+                               symb /= (i_params->mclk / 100);
+                               stv0900_write_reg(i_params, R0900_P1_SFRUP1, (symb >> 8) & 0x7F);
+                               stv0900_write_reg(i_params, R0900_P1_SFRUP0, (symb & 0xFF));
+
+                               symb = 10 * (coarse_srate / 14);
+                               symb = (symb / 100) * 65536;
+                               symb /= (i_params->mclk / 100);
+                               stv0900_write_reg(i_params, R0900_P1_SFRLOW1, (symb >> 8) & 0x7F);
+                               stv0900_write_reg(i_params, R0900_P1_SFRLOW0, (symb & 0xFF));
+
+                               symb = (coarse_srate / 100) * 65536;
+                               symb /= (i_params->mclk / 100);
+                               stv0900_write_reg(i_params, R0900_P1_SFRINIT1, (symb >> 8) & 0xFF);
+                               stv0900_write_reg(i_params, R0900_P1_SFRINIT0, (symb & 0xFF));
+                       }
+
+                       stv0900_write_reg(i_params, R0900_P1_DMDT0M, 0x20);
+                       stv0900_write_reg(i_params, R0900_P1_CFRINIT1, (coarse_freq >> 8) & 0xff);
+                       stv0900_write_reg(i_params, R0900_P1_CFRINIT0, coarse_freq  & 0xff);
+                       stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x15);
+               }
+               break;
+       case STV0900_DEMOD_2:
+               coarse_freq = (stv0900_read_reg(i_params, R0900_P2_CFR2) << 8)
+                                               | stv0900_read_reg(i_params, R0900_P2_CFR1);
+
+               symb = 13 * (coarse_srate / 10);
+
+               if (symb < i_params->dmd2_symbol_rate)
+                       coarse_srate = 0;
+               else {
+                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1F);
+                       stv0900_write_reg(i_params, R0900_P2_TMGCFG2, 0x01);
+                       stv0900_write_reg(i_params, R0900_P2_TMGTHRISE, 0x20);
+                       stv0900_write_reg(i_params, R0900_P2_TMGTHFALL, 0x00);
+                       stv0900_write_reg(i_params, R0900_P2_TMGCFG, 0xd2);
+                       stv0900_write_bits(i_params, F0900_P2_CFR_AUTOSCAN, 0);
+
+                       if (i_params->chip_id >= 0x20)
+                               stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0x49);
+                       else
+                               stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0xed);
+
+                       if (coarse_srate > 3000000) {
+                               symb = 13 * (coarse_srate / 10);
+                               symb = (symb / 1000) * 65536;
+                               symb /= (i_params->mclk / 1000);
+                               stv0900_write_reg(i_params, R0900_P2_SFRUP1, (symb >> 8) & 0x7F);
+                               stv0900_write_reg(i_params, R0900_P2_SFRUP0, (symb & 0xFF));
+
+                               symb = 10 * (coarse_srate / 13);
+                               symb = (symb / 1000) * 65536;
+                               symb /= (i_params->mclk / 1000);
+
+                               stv0900_write_reg(i_params, R0900_P2_SFRLOW1, (symb >> 8) & 0x7F);
+                               stv0900_write_reg(i_params, R0900_P2_SFRLOW0, (symb & 0xFF));
+
+                               symb = (coarse_srate / 1000) * 65536;
+                               symb /= (i_params->mclk / 1000);
+                               stv0900_write_reg(i_params, R0900_P2_SFRINIT1, (symb >> 8) & 0xFF);
+                               stv0900_write_reg(i_params, R0900_P2_SFRINIT0, (symb & 0xFF));
+                       } else {
+                               symb = 13 * (coarse_srate / 10);
+                               symb = (symb / 100) * 65536;
+                               symb /= (i_params->mclk / 100);
+                               stv0900_write_reg(i_params, R0900_P2_SFRUP1, (symb >> 8) & 0x7F);
+                               stv0900_write_reg(i_params, R0900_P2_SFRUP0, (symb & 0xFF));
+
+                               symb = 10 * (coarse_srate / 14);
+                               symb = (symb / 100) * 65536;
+                               symb /= (i_params->mclk / 100);
+                               stv0900_write_reg(i_params, R0900_P2_SFRLOW1, (symb >> 8) & 0x7F);
+                               stv0900_write_reg(i_params, R0900_P2_SFRLOW0, (symb & 0xFF));
+
+                               symb = (coarse_srate / 100) * 65536;
+                               symb /= (i_params->mclk / 100);
+                               stv0900_write_reg(i_params, R0900_P2_SFRINIT1, (symb >> 8) & 0xFF);
+                               stv0900_write_reg(i_params, R0900_P2_SFRINIT0, (symb & 0xFF));
+                       }
+
+                       stv0900_write_reg(i_params, R0900_P2_DMDT0M, 0x20);
+                       stv0900_write_reg(i_params, R0900_P2_CFRINIT1, (coarse_freq >> 8) & 0xff);
+                       stv0900_write_reg(i_params, R0900_P2_CFRINIT0, coarse_freq  & 0xff);
+                       stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x15);
+               }
+
+               break;
+       }
+
+       return coarse_srate;
+}
+
+static int stv0900_blind_search_algo(struct dvb_frontend *fe)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       enum fe_stv0900_demod_num demod = state->demod;
+       u8 k_ref_tmg, k_ref_tmg_max, k_ref_tmg_min;
+       u32 coarse_srate;
+       int lock = FALSE, coarse_fail = FALSE;
+       s32 demod_timeout = 500, fec_timeout = 50, kref_tmg_reg, fail_cpt, i, agc2_overflow;
+       u16 agc2_integr;
+       u8 dstatus2;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       if (i_params->chip_id < 0x20) {
+               k_ref_tmg_max = 233;
+               k_ref_tmg_min = 143;
+       } else {
+               k_ref_tmg_max = 120;
+               k_ref_tmg_min = 30;
+       }
+
+       agc2_integr = stv0900_blind_check_agc2_min_level(i_params, demod);
+
+       if (agc2_integr > STV0900_BLIND_SEARCH_AGC2_TH) {
+               lock = FALSE;
+
+       } else {
+               switch (demod) {
+               case STV0900_DEMOD_1:
+               default:
+                       if (i_params->chip_id == 0x10)
+                               stv0900_write_reg(i_params, R0900_P1_CORRELEXP, 0xAA);
+
+                       if (i_params->chip_id < 0x20)
+                               stv0900_write_reg(i_params, R0900_P1_CARHDR, 0x55);
+
+                       stv0900_write_reg(i_params, R0900_P1_CARCFG, 0xC4);
+                       stv0900_write_reg(i_params, R0900_P1_RTCS2, 0x44);
+
+                       if (i_params->chip_id >= 0x20) {
+                               stv0900_write_reg(i_params, R0900_P1_EQUALCFG, 0x41);
+                               stv0900_write_reg(i_params, R0900_P1_FFECFG, 0x41);
+                               stv0900_write_reg(i_params, R0900_P1_VITSCALE, 0x82);
+                               stv0900_write_reg(i_params, R0900_P1_VAVSRVIT, 0x0);
+                       }
+
+                       kref_tmg_reg = R0900_P1_KREFTMG;
+                       break;
+               case STV0900_DEMOD_2:
+                       if (i_params->chip_id == 0x10)
+                               stv0900_write_reg(i_params, R0900_P2_CORRELEXP, 0xAA);
+
+                       if (i_params->chip_id < 0x20)
+                               stv0900_write_reg(i_params, R0900_P2_CARHDR, 0x55);
+
+                       stv0900_write_reg(i_params, R0900_P2_CARCFG, 0xC4);
+                       stv0900_write_reg(i_params, R0900_P2_RTCS2, 0x44);
+
+                       if (i_params->chip_id >= 0x20) {
+                               stv0900_write_reg(i_params, R0900_P2_EQUALCFG, 0x41);
+                               stv0900_write_reg(i_params, R0900_P2_FFECFG, 0x41);
+                               stv0900_write_reg(i_params, R0900_P2_VITSCALE, 0x82);
+                               stv0900_write_reg(i_params, R0900_P2_VAVSRVIT, 0x0);
+                       }
+
+                       kref_tmg_reg = R0900_P2_KREFTMG;
+                       break;
+               }
+
+               k_ref_tmg = k_ref_tmg_max;
+
+               do {
+                       stv0900_write_reg(i_params, kref_tmg_reg, k_ref_tmg);
+                       if (stv0900_search_srate_coarse(fe) != 0) {
+                               coarse_srate = stv0900_search_srate_fine(fe);
+
+                               if (coarse_srate != 0) {
+                                       stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, coarse_srate, STV0900_BLIND_SEARCH);
+                                       lock = stv0900_get_demod_lock(i_params, demod, demod_timeout);
+                               } else
+                                       lock = FALSE;
+                       } else {
+                               fail_cpt = 0;
+                               agc2_overflow = 0;
+
+                               switch (demod) {
+                               case STV0900_DEMOD_1:
+                               default:
+                                       for (i = 0; i < 10; i++) {
+                                               agc2_integr = (stv0900_read_reg(i_params, R0900_P1_AGC2I1) << 8)
+                                                               | stv0900_read_reg(i_params, R0900_P1_AGC2I0);
+
+                                               if (agc2_integr >= 0xff00)
+                                                       agc2_overflow++;
+
+                                               dstatus2 = stv0900_read_reg(i_params, R0900_P1_DSTATUS2);
+
+                                               if (((dstatus2 & 0x1) == 0x1) && ((dstatus2 >> 7) == 1))
+                                                       fail_cpt++;
+                                       }
+                                       break;
+                               case STV0900_DEMOD_2:
+                                       for (i = 0; i < 10; i++) {
+                                               agc2_integr = (stv0900_read_reg(i_params, R0900_P2_AGC2I1) << 8)
+                                                               | stv0900_read_reg(i_params, R0900_P2_AGC2I0);
+
+                                               if (agc2_integr >= 0xff00)
+                                                       agc2_overflow++;
+
+                                               dstatus2 = stv0900_read_reg(i_params, R0900_P2_DSTATUS2);
+
+                                               if (((dstatus2 & 0x1) == 0x1) && ((dstatus2 >> 7) == 1))
+                                                       fail_cpt++;
+                                       }
+                                       break;
+                               }
+
+                               if ((fail_cpt > 7) || (agc2_overflow > 7))
+                                       coarse_fail = TRUE;
+
+                               lock = FALSE;
+                       }
+                       k_ref_tmg -= 30;
+               } while ((k_ref_tmg >= k_ref_tmg_min) && (lock == FALSE) && (coarse_fail == FALSE));
+       }
+
+       return lock;
+}
+
+static void stv0900_set_viterbi_acq(struct stv0900_internal *i_params,
+                                       enum fe_stv0900_demod_num demod)
+{
+       s32 vth_reg;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       dmd_reg(vth_reg, R0900_P1_VTH12, R0900_P2_VTH12);
+
+       stv0900_write_reg(i_params, vth_reg++, 0x96);
+       stv0900_write_reg(i_params, vth_reg++, 0x64);
+       stv0900_write_reg(i_params, vth_reg++, 0x36);
+       stv0900_write_reg(i_params, vth_reg++, 0x23);
+       stv0900_write_reg(i_params, vth_reg++, 0x1E);
+       stv0900_write_reg(i_params, vth_reg++, 0x19);
+}
+
+static void stv0900_set_search_standard(struct stv0900_internal *i_params,
+                                       enum fe_stv0900_demod_num demod)
+{
+
+       int sstndrd;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       sstndrd = i_params->dmd1_srch_standard;
+       if (demod == 1)
+               sstndrd = i_params->dmd2_srch_stndrd;
+
+       switch (sstndrd) {
+       case STV0900_SEARCH_DVBS1:
+               dprintk("Search Standard = DVBS1\n");
+               break;
+       case STV0900_SEARCH_DSS:
+               dprintk("Search Standard = DSS\n");
+       case STV0900_SEARCH_DVBS2:
+               break;
+               dprintk("Search Standard = DVBS2\n");
+       case STV0900_AUTO_SEARCH:
+       default:
+               dprintk("Search Standard = AUTO\n");
+               break;
+       }
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               switch (i_params->dmd1_srch_standard) {
+               case STV0900_SEARCH_DVBS1:
+               case STV0900_SEARCH_DSS:
+                       stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 1);
+                       stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 0);
+
+                       stv0900_write_bits(i_params, F0900_STOP_CLKVIT1, 0);
+                       stv0900_write_reg(i_params, R0900_P1_ACLC, 0x1a);
+                       stv0900_write_reg(i_params, R0900_P1_BCLC, 0x09);
+                       stv0900_write_reg(i_params, R0900_P1_CAR2CFG, 0x22);
+
+                       stv0900_set_viterbi_acq(i_params, demod);
+                       stv0900_set_viterbi_standard(i_params,
+                                               i_params->dmd1_srch_standard,
+                                               i_params->dmd1_fec, demod);
+
+                       break;
+               case STV0900_SEARCH_DVBS2:
+                       stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 0);
+                       stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 0);
+                       stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 1);
+                       stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 1);
+                       stv0900_write_bits(i_params, F0900_STOP_CLKVIT1, 1);
+                       stv0900_write_reg(i_params, R0900_P1_ACLC, 0x1a);
+                       stv0900_write_reg(i_params, R0900_P1_BCLC, 0x09);
+                       stv0900_write_reg(i_params, R0900_P1_CAR2CFG, 0x26);
+                       if (i_params->demod_mode != STV0900_SINGLE) {
+                               if (i_params->chip_id <= 0x11)
+                                       stv0900_stop_all_s2_modcod(i_params, demod);
+                               else
+                                       stv0900_activate_s2_modcode(i_params, demod);
+
+                       } else
+                               stv0900_activate_s2_modcode_single(i_params, demod);
+
+                       stv0900_set_viterbi_tracq(i_params, demod);
+
+                       break;
+               case STV0900_AUTO_SEARCH:
+               default:
+                       stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 0);
+                       stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 0);
+                       stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 1);
+                       stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 1);
+                       stv0900_write_bits(i_params, F0900_STOP_CLKVIT1, 0);
+                       stv0900_write_reg(i_params, R0900_P1_ACLC, 0x1a);
+                       stv0900_write_reg(i_params, R0900_P1_BCLC, 0x09);
+                       stv0900_write_reg(i_params, R0900_P1_CAR2CFG, 0x26);
+                       if (i_params->demod_mode != STV0900_SINGLE) {
+                               if (i_params->chip_id <= 0x11)
+                                       stv0900_stop_all_s2_modcod(i_params, demod);
+                               else
+                                       stv0900_activate_s2_modcode(i_params, demod);
+
+                       } else
+                               stv0900_activate_s2_modcode_single(i_params, demod);
+
+                       if (i_params->dmd1_symbol_rate >= 2000000)
+                               stv0900_set_viterbi_acq(i_params, demod);
+                       else
+                               stv0900_set_viterbi_tracq(i_params, demod);
+
+                       stv0900_set_viterbi_standard(i_params, i_params->dmd1_srch_standard, i_params->dmd1_fec, demod);
+
+                       break;
+               }
+               break;
+       case STV0900_DEMOD_2:
+               switch (i_params->dmd2_srch_stndrd) {
+               case STV0900_SEARCH_DVBS1:
+               case STV0900_SEARCH_DSS:
+                       stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 1);
+                       stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 0);
+                       stv0900_write_bits(i_params, F0900_STOP_CLKVIT2, 0);
+                       stv0900_write_reg(i_params, R0900_P2_ACLC, 0x1a);
+                       stv0900_write_reg(i_params, R0900_P2_BCLC, 0x09);
+                       stv0900_write_reg(i_params, R0900_P2_CAR2CFG, 0x22);
+                       stv0900_set_viterbi_acq(i_params, demod);
+                       stv0900_set_viterbi_standard(i_params, i_params->dmd2_srch_stndrd, i_params->dmd2_fec, demod);
+                       break;
+               case STV0900_SEARCH_DVBS2:
+                       stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 0);
+                       stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 0);
+                       stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 1);
+                       stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 1);
+                       stv0900_write_bits(i_params, F0900_STOP_CLKVIT2, 1);
+                       stv0900_write_reg(i_params, R0900_P2_ACLC, 0x1a);
+                       stv0900_write_reg(i_params, R0900_P2_BCLC, 0x09);
+                       stv0900_write_reg(i_params, R0900_P2_CAR2CFG, 0x26);
+                       if (i_params->demod_mode != STV0900_SINGLE)
+                               stv0900_activate_s2_modcode(i_params, demod);
+                       else
+                               stv0900_activate_s2_modcode_single(i_params, demod);
+
+                       stv0900_set_viterbi_tracq(i_params, demod);
+                       break;
+               case STV0900_AUTO_SEARCH:
+               default:
+                       stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 0);
+                       stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 0);
+                       stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 1);
+                       stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 1);
+                       stv0900_write_bits(i_params, F0900_STOP_CLKVIT2, 0);
+                       stv0900_write_reg(i_params, R0900_P2_ACLC, 0x1a);
+                       stv0900_write_reg(i_params, R0900_P2_BCLC, 0x09);
+                       stv0900_write_reg(i_params, R0900_P2_CAR2CFG, 0x26);
+                       if (i_params->demod_mode != STV0900_SINGLE)
+                               stv0900_activate_s2_modcode(i_params, demod);
+                       else
+                               stv0900_activate_s2_modcode_single(i_params, demod);
+
+                       if (i_params->dmd2_symbol_rate >= 2000000)
+                               stv0900_set_viterbi_acq(i_params, demod);
+                       else
+                               stv0900_set_viterbi_tracq(i_params, demod);
+
+                       stv0900_set_viterbi_standard(i_params, i_params->dmd2_srch_stndrd, i_params->dmd2_fec, demod);
+
+                       break;
+               }
+
+               break;
+       }
+}
+
+enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       enum fe_stv0900_demod_num demod = state->demod;
+
+       s32 demod_timeout = 500, fec_timeout = 50, stream_merger_field;
+
+       int lock = FALSE, low_sr = FALSE;
+
+       enum fe_stv0900_signal_type signal_type = STV0900_NOCARRIER;
+       enum fe_stv0900_search_algo algo;
+       int no_signal = FALSE;
+
+       dprintk(KERN_INFO "%s\n", __func__);
+
+       switch (demod) {
+       case STV0900_DEMOD_1:
+       default:
+               algo = i_params->dmd1_srch_algo;
+
+               stv0900_write_bits(i_params, F0900_P1_RST_HWARE, 1);
+               stream_merger_field = F0900_P1_RST_HWARE;
+
+               stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x5C);
+
+               if (i_params->chip_id >= 0x20)
+                       stv0900_write_reg(i_params, R0900_P1_CORRELABS, 0x9e);
+               else
+                       stv0900_write_reg(i_params, R0900_P1_CORRELABS, 0x88);
+
+               stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, i_params->dmd1_symbol_rate, i_params->dmd1_srch_algo);
+
+               if (i_params->dmd1_srch_algo == STV0900_BLIND_SEARCH) {
+                       i_params->tuner1_bw = 2 * 36000000;
+
+                       stv0900_write_reg(i_params, R0900_P1_TMGCFG2, 0x00);
+                       stv0900_write_reg(i_params, R0900_P1_CORRELMANT, 0x70);
+
+                       stv0900_set_symbol_rate(i_params, i_params->mclk, 1000000, demod);
+               } else {
+                       stv0900_write_reg(i_params, R0900_P1_DMDT0M, 0x20);
+                       stv0900_write_reg(i_params, R0900_P1_TMGCFG, 0xd2);
+
+                       if (i_params->dmd1_symbol_rate < 2000000)
+                               stv0900_write_reg(i_params, R0900_P1_CORRELMANT, 0x63);
+                       else
+                               stv0900_write_reg(i_params, R0900_P1_CORRELMANT, 0x70);
+
+                       stv0900_write_reg(i_params, R0900_P1_AGC2REF, 0x38);
+                       if (i_params->chip_id >= 0x20) {
+                               stv0900_write_reg(i_params, R0900_P1_KREFTMG, 0x5a);
+
+                               if (i_params->dmd1_srch_algo == STV0900_COLD_START)
+                                       i_params->tuner1_bw = (15 * (stv0900_carrier_width(i_params->dmd1_symbol_rate, i_params->rolloff) + 10000000)) / 10;
+                               else if (i_params->dmd1_srch_algo == STV0900_WARM_START)
+                                       i_params->tuner1_bw = stv0900_carrier_width(i_params->dmd1_symbol_rate, i_params->rolloff) + 10000000;
+                       } else {
+                               stv0900_write_reg(i_params, R0900_P1_KREFTMG, 0xc1);
+                               i_params->tuner1_bw = (15 * (stv0900_carrier_width(i_params->dmd1_symbol_rate, i_params->rolloff) + 10000000)) / 10;
+                       }
+
+                       stv0900_write_reg(i_params, R0900_P1_TMGCFG2, 0x01);
+
+                       stv0900_set_symbol_rate(i_params, i_params->mclk, i_params->dmd1_symbol_rate, demod);
+                       stv0900_set_max_symbol_rate(i_params, i_params->mclk, i_params->dmd1_symbol_rate, demod);
+                       stv0900_set_min_symbol_rate(i_params, i_params->mclk, i_params->dmd1_symbol_rate, demod);
+                       if (i_params->dmd1_symbol_rate >= 10000000)
+                               low_sr = FALSE;
+                       else
+                               low_sr = TRUE;
+
+               }
+
+               stv0900_set_tuner(fe, i_params->tuner1_freq, i_params->tuner1_bw);
+
+               stv0900_write_bits(i_params, F0900_P1_SPECINV_CONTROL, i_params->dmd1_srch_iq_inv);
+               stv0900_write_bits(i_params, F0900_P1_MANUAL_ROLLOFF, 1);
+
+               stv0900_set_search_standard(i_params, demod);
+
+               if (i_params->dmd1_srch_algo != STV0900_BLIND_SEARCH)
+                       stv0900_start_search(i_params, demod);
+               break;
+       case STV0900_DEMOD_2:
+               algo = i_params->dmd2_srch_algo;
+
+               stv0900_write_bits(i_params, F0900_P2_RST_HWARE, 1);
+
+               stream_merger_field = F0900_P2_RST_HWARE;
+
+               stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x5C);
+
+               if (i_params->chip_id >= 0x20)
+                       stv0900_write_reg(i_params, R0900_P2_CORRELABS, 0x9e);
+               else
+                       stv0900_write_reg(i_params, R0900_P2_CORRELABS, 0x88);
+
+               stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, i_params->dmd2_symbol_rate, i_params->dmd2_srch_algo);
+
+               if (i_params->dmd2_srch_algo == STV0900_BLIND_SEARCH) {
+                       i_params->tuner2_bw = 2 * 36000000;
+
+                       stv0900_write_reg(i_params, R0900_P2_TMGCFG2, 0x00);
+                       stv0900_write_reg(i_params, R0900_P2_CORRELMANT, 0x70);
+
+                       stv0900_set_symbol_rate(i_params, i_params->mclk, 1000000, demod);
+               } else {
+                       stv0900_write_reg(i_params, R0900_P2_DMDT0M, 0x20);
+                       stv0900_write_reg(i_params, R0900_P2_TMGCFG, 0xd2);
+
+                       if (i_params->dmd2_symbol_rate < 2000000)
+                               stv0900_write_reg(i_params, R0900_P2_CORRELMANT, 0x63);
+                       else
+                               stv0900_write_reg(i_params, R0900_P2_CORRELMANT, 0x70);
+
+                       if (i_params->dmd2_symbol_rate >= 10000000)
+                               stv0900_write_reg(i_params, R0900_P2_AGC2REF, 0x38);
+                       else
+                               stv0900_write_reg(i_params, R0900_P2_AGC2REF, 0x60);
+
+                       if (i_params->chip_id >= 0x20) {
+                               stv0900_write_reg(i_params, R0900_P2_KREFTMG, 0x5a);
+
+                               if (i_params->dmd2_srch_algo == STV0900_COLD_START)
+                                       i_params->tuner2_bw = (15 * (stv0900_carrier_width(i_params->dmd2_symbol_rate,
+                                                       i_params->rolloff) + 10000000)) / 10;
+                               else if (i_params->dmd2_srch_algo == STV0900_WARM_START)
+                                       i_params->tuner2_bw = stv0900_carrier_width(i_params->dmd2_symbol_rate,
+                                                       i_params->rolloff) + 10000000;
+                       } else {
+                               stv0900_write_reg(i_params, R0900_P2_KREFTMG, 0xc1);
+                               i_params->tuner2_bw = (15 * (stv0900_carrier_width(i_params->dmd2_symbol_rate,
+                                                                       i_params->rolloff) + 10000000)) / 10;
+                       }
+
+                       stv0900_write_reg(i_params, R0900_P2_TMGCFG2, 0x01);
+
+                       stv0900_set_symbol_rate(i_params, i_params->mclk, i_params->dmd2_symbol_rate, demod);
+                       stv0900_set_max_symbol_rate(i_params, i_params->mclk, i_params->dmd2_symbol_rate, demod);
+                       stv0900_set_min_symbol_rate(i_params, i_params->mclk, i_params->dmd2_symbol_rate, demod);
+                       if (i_params->dmd2_symbol_rate >= 10000000)
+                               low_sr = FALSE;
+                       else
+                               low_sr = TRUE;
+
+               }
+
+               stv0900_set_tuner(fe, i_params->tuner2_freq, i_params->tuner2_bw);
+
+               stv0900_write_bits(i_params, F0900_P2_SPECINV_CONTROL, i_params->dmd2_srch_iq_inv);
+               stv0900_write_bits(i_params, F0900_P2_MANUAL_ROLLOFF, 1);
+
+               stv0900_set_search_standard(i_params, demod);
+
+               if (i_params->dmd2_srch_algo != STV0900_BLIND_SEARCH)
+                       stv0900_start_search(i_params, demod);
+               break;
+       }
+
+       if (i_params->chip_id == 0x12) {
+               stv0900_write_bits(i_params, stream_merger_field, 0);
+               msleep(3);
+               stv0900_write_bits(i_params, stream_merger_field, 1);
+               stv0900_write_bits(i_params, stream_merger_field, 0);
+       }
+
+       if (algo == STV0900_BLIND_SEARCH)
+               lock = stv0900_blind_search_algo(fe);
+       else if (algo == STV0900_COLD_START)
+               lock = stv0900_get_demod_cold_lock(fe, demod_timeout);
+       else if (algo == STV0900_WARM_START)
+               lock = stv0900_get_demod_lock(i_params, demod, demod_timeout);
+
+       if ((lock == FALSE) && (algo == STV0900_COLD_START)) {
+               if (low_sr == FALSE) {
+                       if (stv0900_check_timing_lock(i_params, demod) == TRUE)
+                               lock = stv0900_sw_algo(i_params, demod);
+               }
+       }
+
+       if (lock == TRUE)
+               signal_type = stv0900_get_signal_params(fe);
+
+       if ((lock == TRUE) && (signal_type == STV0900_RANGEOK)) {
+               stv0900_track_optimization(fe);
+               if (i_params->chip_id <= 0x11) {
+                       if ((stv0900_get_standard(fe, STV0900_DEMOD_1) == STV0900_DVBS1_STANDARD) && (stv0900_get_standard(fe, STV0900_DEMOD_2) == STV0900_DVBS1_STANDARD)) {
+                               msleep(20);
+                               stv0900_write_bits(i_params, stream_merger_field, 0);
+                       } else {
+                               stv0900_write_bits(i_params, stream_merger_field, 0);
+                               msleep(3);
+                               stv0900_write_bits(i_params, stream_merger_field, 1);
+                               stv0900_write_bits(i_params, stream_merger_field, 0);
+                       }
+               } else if (i_params->chip_id == 0x20) {
+                       stv0900_write_bits(i_params, stream_merger_field, 0);
+                       msleep(3);
+                       stv0900_write_bits(i_params, stream_merger_field, 1);
+                       stv0900_write_bits(i_params, stream_merger_field, 0);
+               }
+
+               if (stv0900_wait_for_lock(i_params, demod, fec_timeout, fec_timeout) == TRUE) {
+                       lock = TRUE;
+                       switch (demod) {
+                       case STV0900_DEMOD_1:
+                       default:
+                               i_params->dmd1_rslts.locked = TRUE;
+                               if (i_params->dmd1_rslts.standard == STV0900_DVBS2_STANDARD) {
+                                       stv0900_set_dvbs2_rolloff(i_params, demod);
+                                       stv0900_write_reg(i_params, R0900_P1_PDELCTRL2, 0x40);
+                                       stv0900_write_reg(i_params, R0900_P1_PDELCTRL2, 0);
+                                       stv0900_write_reg(i_params, R0900_P1_ERRCTRL1, 0x67);
+                               } else {
+                                       stv0900_write_reg(i_params, R0900_P1_ERRCTRL1, 0x75);
+                               }
+
+                               stv0900_write_reg(i_params, R0900_P1_FBERCPT4, 0);
+                               stv0900_write_reg(i_params, R0900_P1_ERRCTRL2, 0xc1);
+                               break;
+                       case STV0900_DEMOD_2:
+                               i_params->dmd2_rslts.locked = TRUE;
+
+                               if (i_params->dmd2_rslts.standard == STV0900_DVBS2_STANDARD) {
+                                       stv0900_set_dvbs2_rolloff(i_params, demod);
+                                       stv0900_write_reg(i_params, R0900_P2_PDELCTRL2, 0x60);
+                                       stv0900_write_reg(i_params, R0900_P2_PDELCTRL2, 0x20);
+                                       stv0900_write_reg(i_params, R0900_P2_ERRCTRL1, 0x67);
+                               } else {
+                                       stv0900_write_reg(i_params, R0900_P2_ERRCTRL1, 0x75);
+                               }
+
+                               stv0900_write_reg(i_params, R0900_P2_FBERCPT4, 0);
+
+                               stv0900_write_reg(i_params, R0900_P2_ERRCTRL2, 0xc1);
+                               break;
+                       }
+               } else {
+                       lock = FALSE;
+                       signal_type = STV0900_NODATA;
+                       no_signal = stv0900_check_signal_presence(i_params, demod);
+
+                       switch (demod) {
+                       case STV0900_DEMOD_1:
+                       default:
+                               i_params->dmd1_rslts.locked = FALSE;
+                               break;
+                       case STV0900_DEMOD_2:
+                               i_params->dmd2_rslts.locked = FALSE;
+                               break;
+                       }
+               }
+       }
+
+       if ((signal_type == STV0900_NODATA) && (no_signal == FALSE)) {
+               switch (demod) {
+               case STV0900_DEMOD_1:
+               default:
+                       if (i_params->chip_id <= 0x11) {
+                               if ((stv0900_get_bits(i_params, F0900_P1_HEADER_MODE) == STV0900_DVBS_FOUND) &&
+                                               (i_params->dmd1_srch_iq_inv <= STV0900_IQ_AUTO_NORMAL_FIRST))
+                                       signal_type = stv0900_dvbs1_acq_workaround(fe);
+                       } else
+                               i_params->dmd1_rslts.locked = FALSE;
+
+                       break;
+               case STV0900_DEMOD_2:
+                       if (i_params->chip_id <= 0x11) {
+                               if ((stv0900_get_bits(i_params, F0900_P2_HEADER_MODE) == STV0900_DVBS_FOUND) &&
+                                               (i_params->dmd2_srch_iq_inv <= STV0900_IQ_AUTO_NORMAL_FIRST))
+                                       signal_type = stv0900_dvbs1_acq_workaround(fe);
+                       } else
+                               i_params->dmd2_rslts.locked = FALSE;
+                       break;
+               }
+       }
+
+       return signal_type;
+}
+
diff --git a/drivers/media/dvb/frontends/stv6110.c b/drivers/media/dvb/frontends/stv6110.c
new file mode 100644 (file)
index 0000000..70efac8
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * stv6110.c
+ *
+ * Driver for ST STV6110 satellite tuner IC.
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * 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/dvb/frontend.h>
+
+#include <linux/types.h>
+
+#include "stv6110.h"
+
+static int debug;
+
+struct stv6110_priv {
+       int i2c_address;
+       struct i2c_adapter *i2c;
+
+       u32 mclk;
+       u8 regs[8];
+};
+
+#define dprintk(args...) \
+       do { \
+               if (debug) \
+                       printk(KERN_DEBUG args); \
+       } while (0)
+
+static s32 abssub(s32 a, s32 b)
+{
+       if (a > b)
+               return a - b;
+       else
+               return b - a;
+};
+
+static int stv6110_release(struct dvb_frontend *fe)
+{
+       kfree(fe->tuner_priv);
+       fe->tuner_priv = NULL;
+       return 0;
+}
+
+static int stv6110_write_regs(struct dvb_frontend *fe, u8 buf[],
+                                                       int start, int len)
+{
+       struct stv6110_priv *priv = fe->tuner_priv;
+       int rc;
+       u8 cmdbuf[len + 1];
+       struct i2c_msg msg = {
+               .addr   = priv->i2c_address,
+               .flags  = 0,
+               .buf    = cmdbuf,
+               .len    = len + 1
+       };
+
+       dprintk("%s\n", __func__);
+
+       if (start + len > 8)
+               return -EINVAL;
+
+       memcpy(&cmdbuf[1], buf, len);
+       cmdbuf[0] = start;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+
+       rc = i2c_transfer(priv->i2c, &msg, 1);
+       if (rc != 1)
+               dprintk("%s: i2c error\n", __func__);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
+       return 0;
+}
+
+static int stv6110_read_regs(struct dvb_frontend *fe, u8 regs[],
+                                                       int start, int len)
+{
+       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_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)
+               dprintk("%s: i2c error\n", __func__);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
+       memcpy(&priv->regs[start], regs, len);
+
+       return 0;
+}
+
+static int stv6110_read_reg(struct dvb_frontend *fe, int start)
+{
+       u8 buf[] = { 0 };
+       stv6110_read_regs(fe, buf, start, 1);
+
+       return buf[0];
+}
+
+static int stv6110_sleep(struct dvb_frontend *fe)
+{
+       u8 reg[] = { 0 };
+       stv6110_write_regs(fe, reg, 0, 1);
+
+       return 0;
+}
+
+static u32 carrier_width(u32 symbol_rate, fe_rolloff_t rolloff)
+{
+       u32 rlf;
+
+       switch (rolloff) {
+       case ROLLOFF_20:
+               rlf = 20;
+               break;
+       case ROLLOFF_25:
+               rlf = 25;
+               break;
+       default:
+               rlf = 35;
+               break;
+       }
+
+       return symbol_rate  + ((symbol_rate * rlf) / 100);
+}
+
+static int stv6110_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
+{
+       struct stv6110_priv *priv = fe->tuner_priv;
+       u8 r8, ret = 0x04;
+       int i;
+
+       if ((bandwidth / 2) > 36000000) /*BW/2 max=31+5=36 mhz for r8=31*/
+               r8 = 31;
+       else if ((bandwidth / 2) < 5000000) /* BW/2 min=5Mhz for F=0 */
+               r8 = 0;
+       else /*if 5 < BW/2 < 36*/
+               r8 = (bandwidth / 2) / 1000000 - 5;
+
+       /* ctrl3, RCCLKOFF = 0 Activate the calibration Clock */
+       /* ctrl3, CF = r8 Set the LPF value */
+       priv->regs[RSTV6110_CTRL3] &= ~((1 << 6) | 0x1f);
+       priv->regs[RSTV6110_CTRL3] |= (r8 & 0x1f);
+       stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL3], RSTV6110_CTRL3, 1);
+       /* stat1, CALRCSTRT = 1 Start LPF auto calibration*/
+       priv->regs[RSTV6110_STAT1] |= 0x02;
+       stv6110_write_regs(fe, &priv->regs[RSTV6110_STAT1], RSTV6110_STAT1, 1);
+
+       i = 0;
+       /* Wait for CALRCSTRT == 0 */
+       while ((i < 10) && (ret != 0)) {
+               ret = ((stv6110_read_reg(fe, RSTV6110_STAT1)) & 0x02);
+               mdelay(1);      /* wait for LPF auto calibration */
+               i++;
+       }
+
+       /* RCCLKOFF = 1 calibration done, desactivate the calibration Clock */
+       priv->regs[RSTV6110_CTRL3] |= (1 << 6);
+       stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL3], RSTV6110_CTRL3, 1);
+       return 0;
+}
+
+static int stv6110_init(struct dvb_frontend *fe)
+{
+       struct stv6110_priv *priv = fe->tuner_priv;
+       u8 buf0[] = { 0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e };
+
+       memcpy(priv->regs, buf0, 8);
+       /* K = (Reference / 1000000) - 16 */
+       priv->regs[RSTV6110_CTRL1] &= ~(0x1f << 3);
+       priv->regs[RSTV6110_CTRL1] |=
+                               ((((priv->mclk / 1000000) - 16) & 0x1f) << 3);
+
+       stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL1], RSTV6110_CTRL1, 8);
+       msleep(1);
+       stv6110_set_bandwidth(fe, 72000000);
+
+       return 0;
+}
+
+static int stv6110_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct stv6110_priv *priv = fe->tuner_priv;
+       u32 nbsteps, divider, psd2, freq;
+       u8 regs[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+       stv6110_read_regs(fe, regs, 0, 8);
+       /*N*/
+       divider = (priv->regs[RSTV6110_TUNING2] & 0x0f) << 8;
+       divider += priv->regs[RSTV6110_TUNING1];
+
+       /*R*/
+       nbsteps  = (priv->regs[RSTV6110_TUNING2] >> 6) & 3;
+       /*p*/
+       psd2  = (priv->regs[RSTV6110_TUNING2] >> 4) & 1;
+
+       freq = divider * (priv->mclk / 1000);
+       freq /= (1 << (nbsteps + psd2));
+       freq /= 4;
+
+       *frequency = freq;
+
+       return 0;
+}
+
+static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency)
+{
+       struct stv6110_priv *priv = fe->tuner_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u8 ret = 0x04;
+       u32 divider, ref, p, presc, i, result_freq, vco_freq;
+       s32 p_calc, p_calc_opt = 1000, r_div, r_div_opt = 0, p_val;
+       s32 srate; u8 gain;
+
+       dprintk("%s, freq=%d kHz, mclk=%d Hz\n", __func__,
+                                               frequency, priv->mclk);
+
+       /* K = (Reference / 1000000) - 16 */
+       priv->regs[RSTV6110_CTRL1] &= ~(0x1f << 3);
+       priv->regs[RSTV6110_CTRL1] |=
+                               ((((priv->mclk / 1000000) - 16) & 0x1f) << 3);
+
+       /* BB_GAIN = db/2 */
+       if (fe->ops.set_property && fe->ops.get_property) {
+               srate = c->symbol_rate;
+               dprintk("%s: Get Frontend parameters: srate=%d\n",
+                                                       __func__, srate);
+       } else
+               srate = 15000000;
+
+       if (srate >= 15000000)
+               gain = 3; /* +6 dB */
+       else if (srate >= 5000000)
+               gain = 3; /* +6 dB */
+       else
+               gain = 3; /* +6 dB */
+
+       priv->regs[RSTV6110_CTRL2] &= ~0x0f;
+       priv->regs[RSTV6110_CTRL2] |= (gain & 0x0f);
+
+       if (frequency <= 1023000) {
+               p = 1;
+               presc = 0;
+       } else if (frequency <= 1300000) {
+               p = 1;
+               presc = 1;
+       } else if (frequency <= 2046000) {
+               p = 0;
+               presc = 0;
+       } else {
+               p = 0;
+               presc = 1;
+       }
+       /* DIV4SEL = p*/
+       priv->regs[RSTV6110_TUNING2] &= ~(1 << 4);
+       priv->regs[RSTV6110_TUNING2] |= (p << 4);
+
+       /* PRESC32ON = presc */
+       priv->regs[RSTV6110_TUNING2] &= ~(1 << 5);
+       priv->regs[RSTV6110_TUNING2] |= (presc << 5);
+
+       p_val = (int)(1 << (p + 1)) * 10;/* P = 2 or P = 4 */
+       for (r_div = 0; r_div <= 3; r_div++) {
+               p_calc = (priv->mclk / 100000);
+               p_calc /= (1 << (r_div + 1));
+               if ((abssub(p_calc, p_val)) < (abssub(p_calc_opt, p_val)))
+                       r_div_opt = r_div;
+
+               p_calc_opt = (priv->mclk / 100000);
+               p_calc_opt /= (1 << (r_div_opt + 1));
+       }
+
+       ref = priv->mclk / ((1 << (r_div_opt + 1))  * (1 << (p + 1)));
+       divider = (((frequency * 1000) + (ref >> 1)) / ref);
+
+       /* RDIV = r_div_opt */
+       priv->regs[RSTV6110_TUNING2] &= ~(3 << 6);
+       priv->regs[RSTV6110_TUNING2] |= (((r_div_opt) & 3) << 6);
+
+       /* NDIV_MSB = MSB(divider) */
+       priv->regs[RSTV6110_TUNING2] &= ~0x0f;
+       priv->regs[RSTV6110_TUNING2] |= (((divider) >> 8) & 0x0f);
+
+       /* NDIV_LSB, LSB(divider) */
+       priv->regs[RSTV6110_TUNING1] = (divider & 0xff);
+
+       /* CALVCOSTRT = 1 VCO Auto Calibration */
+       priv->regs[RSTV6110_STAT1] |= 0x04;
+       stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL1],
+                                               RSTV6110_CTRL1, 8);
+
+       i = 0;
+       /* Wait for CALVCOSTRT == 0 */
+       while ((i < 10) && (ret != 0)) {
+               ret = ((stv6110_read_reg(fe, RSTV6110_STAT1)) & 0x04);
+               msleep(1); /* wait for VCO auto calibration */
+               i++;
+       }
+
+       ret = stv6110_read_reg(fe, RSTV6110_STAT1);
+       stv6110_get_frequency(fe, &result_freq);
+
+       vco_freq = divider * ((priv->mclk / 1000) / ((1 << (r_div_opt + 1))));
+       dprintk("%s, stat1=%x, lo_freq=%d kHz, vco_frec=%d kHz\n", __func__,
+                                               ret, result_freq, vco_freq);
+
+       return 0;
+}
+
+static int stv6110_set_params(struct dvb_frontend *fe,
+                             struct dvb_frontend_parameters *params)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 bandwidth = carrier_width(c->symbol_rate, c->rolloff);
+
+       stv6110_set_frequency(fe, c->frequency);
+       stv6110_set_bandwidth(fe, bandwidth);
+
+       return 0;
+}
+
+static int stv6110_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+       struct stv6110_priv *priv = fe->tuner_priv;
+       u8 r8 = 0;
+       u8 regs[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+       stv6110_read_regs(fe, regs, 0, 8);
+
+       /* CF */
+       r8 = priv->regs[RSTV6110_CTRL3] & 0x1f;
+       *bandwidth = (r8 + 5) * 2000000;/* x2 for ZIF tuner BW/2 = F+5 Mhz */
+
+       return 0;
+}
+
+static struct dvb_tuner_ops stv6110_tuner_ops = {
+       .info = {
+               .name = "ST STV6110",
+               .frequency_min = 950000,
+               .frequency_max = 2150000,
+               .frequency_step = 1000,
+       },
+       .init = stv6110_init,
+       .release = stv6110_release,
+       .sleep = stv6110_sleep,
+       .set_params = stv6110_set_params,
+       .get_frequency = stv6110_get_frequency,
+       .set_frequency = stv6110_set_frequency,
+       .get_bandwidth = stv6110_get_bandwidth,
+       .set_bandwidth = stv6110_set_bandwidth,
+
+};
+
+struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
+                                       const struct stv6110_config *config,
+                                       struct i2c_adapter *i2c)
+{
+       struct stv6110_priv *priv = NULL;
+       u8 reg0[] = { 0x00, 0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e };
+
+       struct i2c_msg msg[] = {
+               {
+                       .addr = config->i2c_address,
+                       .flags = 0,
+                       .buf = reg0,
+                       .len = 9
+               }
+       };
+       int ret;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+
+       ret = i2c_transfer(i2c, msg, 1);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
+       if (ret != 1)
+               return NULL;
+
+       priv = kzalloc(sizeof(struct stv6110_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return NULL;
+
+       priv->i2c_address = config->i2c_address;
+       priv->i2c = i2c;
+       priv->mclk = config->mclk;
+
+       memcpy(&priv->regs, &reg0[1], 8);
+
+       memcpy(&fe->ops.tuner_ops, &stv6110_tuner_ops,
+                               sizeof(struct dvb_tuner_ops));
+       fe->tuner_priv = priv;
+       printk(KERN_INFO "STV6110 attached on addr=%x!\n", priv->i2c_address);
+
+       return fe;
+}
+EXPORT_SYMBOL(stv6110_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("ST STV6110 driver");
+MODULE_AUTHOR("Igor M. Liplianin");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stv6110.h b/drivers/media/dvb/frontends/stv6110.h
new file mode 100644 (file)
index 0000000..1c0314d
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * stv6110.h
+ *
+ * Driver for ST STV6110 satellite tuner IC.
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * 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 __DVB_STV6110_H__
+#define __DVB_STV6110_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/* registers */
+#define RSTV6110_CTRL1         0
+#define RSTV6110_CTRL2         1
+#define RSTV6110_TUNING1       2
+#define RSTV6110_TUNING2       3
+#define RSTV6110_CTRL3         4
+#define RSTV6110_STAT1         5
+#define RSTV6110_STAT2         6
+#define RSTV6110_STAT3         7
+
+struct stv6110_config {
+       u8 i2c_address;
+       u32 mclk;
+       int iq_wiring;
+};
+
+#if defined(CONFIG_DVB_STV6110) || (defined(CONFIG_DVB_STV6110_MODULE) \
+                                                       && defined(MODULE))
+extern struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
+                                       const struct stv6110_config *config,
+                                       struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
+                                       const struct stv6110_config *config,
+                                       struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif
index 1465ff77b0cb4884a84a2ea168093dc073e30236..4981cef8b444602d5f48a00881e2199843d073d1 100644 (file)
@@ -162,7 +162,7 @@ static int tda1004x_read_byte(struct tda1004x_state *state, int reg)
        if (ret != 2) {
                dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg,
                        ret);
-               return -1;
+               return -EINVAL;
        }
 
        dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__,
@@ -481,16 +481,18 @@ static void tda10046_init_plls(struct dvb_frontend* fe)
 static int tda10046_fwupload(struct dvb_frontend* fe)
 {
        struct tda1004x_state* state = fe->demodulator_priv;
-       int ret;
+       int ret, confc4;
        const struct firmware *fw;
 
        /* reset + wake up chip */
        if (state->config->xtal_freq == TDA10046_XTAL_4M) {
-               tda1004x_write_byteI(state, TDA1004X_CONFC4, 0);
+               confc4 = 0;
        } else {
                dprintk("%s: 16MHz Xtal, reducing I2C speed\n", __func__);
-               tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x80);
+               confc4 = 0x80;
        }
+       tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4);
+
        tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
        /* set GPIO 1 and 3 */
        if (state->config->gpio_config != TDA10046_GPTRI) {
@@ -508,13 +510,29 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
        if (tda1004x_check_upload_ok(state) == 0)
                return 0;
 
+       /*
+          For i2c normal work, we need to slow down the bus speed.
+          However, the slow down breaks the eeprom firmware load.
+          So, use normal speed for eeprom booting and then restore the
+          i2c speed after that. Tested with MSI TV @nyware A/D board,
+          that comes with firmware version 29 inside their eeprom.
+
+          It should also be noticed that no other I2C transfer should
+          be in course while booting from eeprom, otherwise, tda10046
+          goes into an instable state. So, proper locking are needed
+          at the i2c bus master.
+        */
        printk(KERN_INFO "tda1004x: trying to boot from eeprom\n");
-       tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4);
+       tda1004x_write_byteI(state, TDA1004X_CONFC4, 4);
        msleep(300);
-       /* don't re-upload unless necessary */
+       tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4);
+
+       /* Checks if eeprom firmware went without troubles */
        if (tda1004x_check_upload_ok(state) == 0)
                return 0;
 
+       /* eeprom firmware didn't work. Load one manually. */
+
        if (state->config->request_firmware != NULL) {
                /* request the firmware, this will block until someone uploads it */
                printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
diff --git a/drivers/media/dvb/frontends/zl10036.c b/drivers/media/dvb/frontends/zl10036.c
new file mode 100644 (file)
index 0000000..e22a0b3
--- /dev/null
@@ -0,0 +1,519 @@
+/**
+ * Driver for Zarlink zl10036 DVB-S silicon tuner
+ *
+ * Copyright (C) 2006 Tino Reichardt
+ * Copyright (C) 2007-2009 Matthias Schwarzott <zzam@gentoo.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This 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.
+ *
+ **
+ * The data sheet for this tuner can be found at:
+ *    http://www.mcmilk.de/projects/dvb-card/datasheets/ZL10036.pdf
+ *
+ * This one is working: (at my Avermedia DVB-S Pro)
+ * - zl10036 (40pin, FTA)
+ *
+ * A driver for zl10038 should be very similar.
+ */
+
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <asm/types.h>
+
+#include "zl10036.h"
+
+static int zl10036_debug;
+#define dprintk(level, args...) \
+       do { if (zl10036_debug & level) printk(KERN_DEBUG "zl10036: " args); \
+       } while (0)
+
+#define deb_info(args...)  dprintk(0x01, args)
+#define deb_i2c(args...)  dprintk(0x02, args)
+
+struct zl10036_state {
+       struct i2c_adapter *i2c;
+       const struct zl10036_config *config;
+       u32 frequency;
+       u8 br, bf;
+};
+
+
+/* This driver assumes the tuner is driven by a 10.111MHz Cristal */
+#define _XTAL 10111
+
+/* Some of the possible dividers:
+ *   64, (write 0x05 to reg), freq step size   158kHz
+ *   10, (write 0x0a to reg), freq step size 1.011kHz (used here)
+ *    5, (write 0x09 to reg), freq step size 2.022kHz
+ */
+
+#define _RDIV 10
+#define _RDIV_REG 0x0a
+#define _FR   (_XTAL/_RDIV)
+
+#define STATUS_POR 0x80 /* Power on Reset */
+#define STATUS_FL  0x40 /* Frequency & Phase Lock */
+
+/* read/write for zl10036 and zl10038 */
+
+static int zl10036_read_status_reg(struct zl10036_state *state)
+{
+       u8 status;
+       struct i2c_msg msg[1] = {
+               { .addr = state->config->tuner_address, .flags = I2C_M_RD,
+                 .buf = &status, .len = sizeof(status) },
+       };
+
+       if (i2c_transfer(state->i2c, msg, 1) != 1) {
+               printk(KERN_ERR "%s: i2c read failed at addr=%02x\n",
+                       __func__, state->config->tuner_address);
+               return -EIO;
+       }
+
+       deb_i2c("R(status): %02x  [FL=%d]\n", status,
+               (status & STATUS_FL) ? 1 : 0);
+       if (status & STATUS_POR)
+               deb_info("%s: Power-On-Reset bit enabled - "
+                       "need to initialize the tuner\n", __func__);
+
+       return status;
+}
+
+static int zl10036_write(struct zl10036_state *state, u8 buf[], u8 count)
+{
+       struct i2c_msg msg[1] = {
+               { .addr = state->config->tuner_address, .flags = 0,
+                 .buf = buf, .len = count },
+       };
+       u8 reg = 0;
+       int ret;
+
+       if (zl10036_debug & 0x02) {
+               /* every 8bit-value satisifes this!
+                * so only check for debug log */
+               if ((buf[0] & 0x80) == 0x00)
+                       reg = 2;
+               else if ((buf[0] & 0xc0) == 0x80)
+                       reg = 4;
+               else if ((buf[0] & 0xf0) == 0xc0)
+                       reg = 6;
+               else if ((buf[0] & 0xf0) == 0xd0)
+                       reg = 8;
+               else if ((buf[0] & 0xf0) == 0xe0)
+                       reg = 10;
+               else if ((buf[0] & 0xf0) == 0xf0)
+                       reg = 12;
+
+               deb_i2c("W(%d):", reg);
+               {
+                       int i;
+                       for (i = 0; i < count; i++)
+                               printk(KERN_CONT " %02x", buf[i]);
+                       printk(KERN_CONT "\n");
+               }
+       }
+
+       ret = i2c_transfer(state->i2c, msg, 1);
+       if (ret != 1) {
+               printk(KERN_ERR "%s: i2c error, ret=%d\n", __func__, ret);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int zl10036_release(struct dvb_frontend *fe)
+{
+       struct zl10036_state *state = fe->tuner_priv;
+
+       fe->tuner_priv = NULL;
+       kfree(state);
+
+       return 0;
+}
+
+static int zl10036_sleep(struct dvb_frontend *fe)
+{
+       struct zl10036_state *state = fe->tuner_priv;
+       u8 buf[] = { 0xf0, 0x80 }; /* regs 12/13 */
+       int ret;
+
+       deb_info("%s\n", __func__);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+       ret = zl10036_write(state, buf, sizeof(buf));
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+       return ret;
+}
+
+/**
+ * register map of the ZL10036/ZL10038
+ *
+ * reg[default] content
+ *  2[0x00]:   0 | N14 | N13 | N12 | N11 | N10 |  N9 |  N8
+ *  3[0x00]:  N7 |  N6 |  N5 |  N4 |  N3 |  N2 |  N1 |  N0
+ *  4[0x80]:   1 |   0 | RFG | BA1 | BA0 | BG1 | BG0 | LEN
+ *  5[0x00]:  P0 |  C1 |  C0 |  R4 |  R3 |  R2 |  R1 |  R0
+ *  6[0xc0]:   1 |   1 |   0 |   0 | RSD |   0 |   0 |   0
+ *  7[0x20]:  P1 | BF6 | BF5 | BF4 | BF3 | BF2 | BF1 |   0
+ *  8[0xdb]:   1 |   1 |   0 |   1 |   0 |  CC |   1 |   1
+ *  9[0x30]: VSD |  V2 |  V1 |  V0 |  S3 |  S2 |  S1 |  S0
+ * 10[0xe1]:   1 |   1 |   1 |   0 |   0 | LS2 | LS1 | LS0
+ * 11[0xf5]:  WS | WH2 | WH1 | WH0 | WL2 | WL1 | WL0 | WRE
+ * 12[0xf0]:   1 |   1 |   1 |   1 |   0 |   0 |   0 |   0
+ * 13[0x28]:  PD | BR4 | BR3 | BR2 | BR1 | BR0 | CLR |  TL
+ */
+
+static int zl10036_set_frequency(struct zl10036_state *state, u32 frequency)
+{
+       u8 buf[2];
+       u32 div, foffset;
+
+       div = (frequency + _FR/2) / _FR;
+       state->frequency = div * _FR;
+
+       foffset = frequency - state->frequency;
+
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] = (div >> 0) & 0xff;
+
+       deb_info("%s: ftodo=%u fpriv=%u ferr=%d div=%u\n", __func__,
+               frequency, state->frequency, foffset, div);
+
+       return zl10036_write(state, buf, sizeof(buf));
+}
+
+static int zl10036_set_bandwidth(struct zl10036_state *state, u32 fbw)
+{
+       /* fbw is measured in kHz */
+       u8 br, bf;
+       int ret;
+       u8 buf_bf[] = {
+               0xc0, 0x00, /*   6/7: rsd=0 bf=0 */
+       };
+       u8 buf_br[] = {
+               0xf0, 0x00, /* 12/13: br=0xa clr=0 tl=0*/
+       };
+       u8 zl10036_rsd_off[] = { 0xc8 }; /* set RSD=1 */
+
+       /* ensure correct values */
+       if (fbw > 35000)
+               fbw = 35000;
+       if (fbw <  8000)
+               fbw =  8000;
+
+#define _BR_MAXIMUM (_XTAL/575) /* _XTAL / 575kHz = 17 */
+
+       /* <= 28,82 MHz */
+       if (fbw <= 28820) {
+               br = _BR_MAXIMUM;
+       } else {
+               /**
+                *  f(bw)=34,6MHz f(xtal)=10.111MHz
+                *  br = (10111/34600) * 63 * 1/K = 14;
+                */
+               br = ((_XTAL * 21 * 1000) / (fbw * 419));
+       }
+
+       /* ensure correct values */
+       if (br < 4)
+               br = 4;
+       if (br > _BR_MAXIMUM)
+               br = _BR_MAXIMUM;
+
+       /*
+        * k = 1.257
+        * bf = fbw/_XTAL * br * k - 1 */
+
+       bf = (fbw * br * 1257) / (_XTAL * 1000) - 1;
+
+       /* ensure correct values */
+       if (bf > 62)
+               bf = 62;
+
+       buf_bf[1] = (bf << 1) & 0x7e;
+       buf_br[1] = (br << 2) & 0x7c;
+       deb_info("%s: BW=%d br=%u bf=%u\n", __func__, fbw, br, bf);
+
+       if (br != state->br) {
+               ret = zl10036_write(state, buf_br, sizeof(buf_br));
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (bf != state->bf) {
+               ret = zl10036_write(state, buf_bf, sizeof(buf_bf));
+               if (ret < 0)
+                       return ret;
+
+               /* time = br/(32* fxtal) */
+               /* minimal sleep time to be calculated
+                * maximum br is 63 -> max time = 2 /10 MHz = 2e-7 */
+               msleep(1);
+
+               ret = zl10036_write(state, zl10036_rsd_off,
+                       sizeof(zl10036_rsd_off));
+               if (ret < 0)
+                       return ret;
+       }
+
+       state->br = br;
+       state->bf = bf;
+
+       return 0;
+}
+
+static int zl10036_set_gain_params(struct zl10036_state *state,
+       int c)
+{
+       u8 buf[2];
+       u8 rfg, ba, bg;
+
+       /* default values */
+       rfg = 0; /* enable when using an lna */
+       ba = 1;
+       bg = 1;
+
+       /* reg 4 */
+       buf[0] = 0x80 | ((rfg << 5) & 0x20)
+               | ((ba  << 3) & 0x18) | ((bg  << 1) & 0x06);
+
+       if (!state->config->rf_loop_enable)
+               buf[0] |= 0x01;
+
+       /* P0=0 */
+       buf[1] = _RDIV_REG | ((c << 5) & 0x60);
+
+       deb_info("%s: c=%u rfg=%u ba=%u bg=%u\n", __func__, c, rfg, ba, bg);
+       return zl10036_write(state, buf, sizeof(buf));
+}
+
+static int zl10036_set_params(struct dvb_frontend *fe,
+               struct dvb_frontend_parameters *params)
+{
+       struct zl10036_state *state = fe->tuner_priv;
+       int ret = 0;
+       u32 frequency = params->frequency;
+       u32 fbw;
+       int i;
+       u8 c;
+
+       /* ensure correct values
+        * maybe redundant as core already checks this */
+       if ((frequency < fe->ops.info.frequency_min)
+       ||  (frequency > fe->ops.info.frequency_max))
+               return -EINVAL;
+
+       /**
+        * alpha = 1.35 for dvb-s
+        * fBW = (alpha*symbolrate)/(2*0.8)
+        * 1.35 / (2*0.8) = 27 / 32
+        */
+       fbw = (27 * params->u.qpsk.symbol_rate) / 32;
+
+       /* scale to kHz */
+       fbw /= 1000;
+
+       /* Add safe margin of 3MHz */
+       fbw += 3000;
+
+       /* setting the charge pump - guessed values */
+       if (frequency < 950000)
+               return -EINVAL;
+       else if (frequency < 1250000)
+               c = 0;
+       else if (frequency < 1750000)
+               c = 1;
+       else if (frequency < 2175000)
+               c = 2;
+       else
+               return -EINVAL;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+       ret = zl10036_set_gain_params(state, c);
+       if (ret < 0)
+               goto error;
+
+       ret = zl10036_set_frequency(state, params->frequency);
+       if (ret < 0)
+               goto error;
+
+       ret = zl10036_set_bandwidth(state, fbw);
+       if (ret < 0)
+               goto error;
+
+       /* wait for tuner lock - no idea if this is really needed */
+       for (i = 0; i < 20; i++) {
+               ret = zl10036_read_status_reg(state);
+               if (ret < 0)
+                       goto error;
+
+               /* check Frequency & Phase Lock Bit */
+               if (ret & STATUS_FL)
+                       break;
+
+               msleep(10);
+       }
+
+error:
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+       return ret;
+}
+
+static int zl10036_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct zl10036_state *state = fe->tuner_priv;
+
+       *frequency = state->frequency;
+
+       return 0;
+}
+
+static int zl10036_init_regs(struct zl10036_state *state)
+{
+       int ret;
+       int i;
+
+       /* could also be one block from reg 2 to 13 and additional 10/11 */
+       u8 zl10036_init_tab[][2] = {
+               { 0x04, 0x00 },         /*   2/3: div=0x400 - arbitrary value */
+               { 0x8b, _RDIV_REG },    /*   4/5: rfg=0 ba=1 bg=1 len=? */
+                                       /*        p0=0 c=0 r=_RDIV_REG */
+               { 0xc0, 0x20 },         /*   6/7: rsd=0 bf=0x10 */
+               { 0xd3, 0x40 },         /*   8/9: from datasheet */
+               { 0xe3, 0x5b },         /* 10/11: lock window level */
+               { 0xf0, 0x28 },         /* 12/13: br=0xa clr=0 tl=0*/
+               { 0xe3, 0xf9 },         /* 10/11: unlock window level */
+       };
+
+       /* invalid values to trigger writing */
+       state->br = 0xff;
+       state->bf = 0xff;
+
+       if (!state->config->rf_loop_enable)
+               zl10036_init_tab[1][2] |= 0x01;
+
+       deb_info("%s\n", __func__);
+
+       for (i = 0; i < ARRAY_SIZE(zl10036_init_tab); i++) {
+               ret = zl10036_write(state, zl10036_init_tab[i], 2);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int zl10036_init(struct dvb_frontend *fe)
+{
+       struct zl10036_state *state = fe->tuner_priv;
+       int ret = 0;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+       ret = zl10036_read_status_reg(state);
+       if (ret < 0)
+               return ret;
+
+       /* Only init if Power-on-Reset bit is set? */
+       ret = zl10036_init_regs(state);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+       return ret;
+}
+
+static struct dvb_tuner_ops zl10036_tuner_ops = {
+       .info = {
+               .name = "Zarlink ZL10036",
+               .frequency_min = 950000,
+               .frequency_max = 2175000
+       },
+       .init = zl10036_init,
+       .release = zl10036_release,
+       .sleep = zl10036_sleep,
+       .set_params = zl10036_set_params,
+       .get_frequency = zl10036_get_frequency,
+};
+
+struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe,
+                                   const struct zl10036_config *config,
+                                   struct i2c_adapter *i2c)
+{
+       struct zl10036_state *state = NULL;
+       int ret;
+
+       if (NULL == config) {
+               printk(KERN_ERR "%s: no config specified", __func__);
+               goto error;
+       }
+
+       state = kzalloc(sizeof(struct zl10036_state), GFP_KERNEL);
+       if (NULL == state)
+               return NULL;
+
+       state->config = config;
+       state->i2c = i2c;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+       ret = zl10036_read_status_reg(state);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: No zl10036 found\n", __func__);
+               goto error;
+       }
+
+       ret = zl10036_init_regs(state);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: tuner initialization failed\n",
+                       __func__);
+               goto error;
+       }
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+       fe->tuner_priv = state;
+
+       memcpy(&fe->ops.tuner_ops, &zl10036_tuner_ops,
+               sizeof(struct dvb_tuner_ops));
+       printk(KERN_INFO "%s: tuner initialization (%s addr=0x%02x) ok\n",
+               __func__, fe->ops.tuner_ops.info.name, config->tuner_address);
+
+       return fe;
+
+error:
+       zl10036_release(fe);
+       return NULL;
+}
+EXPORT_SYMBOL(zl10036_attach);
+
+module_param_named(debug, zl10036_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+MODULE_DESCRIPTION("DVB ZL10036 driver");
+MODULE_AUTHOR("Tino Reichardt");
+MODULE_AUTHOR("Matthias Schwarzott");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/zl10036.h b/drivers/media/dvb/frontends/zl10036.h
new file mode 100644 (file)
index 0000000..d84b8f8
--- /dev/null
@@ -0,0 +1,53 @@
+/**
+ * Driver for Zarlink ZL10036 DVB-S silicon tuner
+ *
+ * Copyright (C) 2006 Tino Reichardt
+ * Copyright (C) 2007-2009 Matthias Schwarzott <zzam@gentoo.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This 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 DVB_ZL10036_H
+#define DVB_ZL10036_H
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/**
+ * Attach a zl10036 tuner to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param config zl10036_config structure
+ * @return FE pointer on success, NULL on failure.
+ */
+
+struct zl10036_config {
+       u8 tuner_address;
+       int rf_loop_enable;
+};
+
+#if defined(CONFIG_DVB_ZL10036) || \
+       (defined(CONFIG_DVB_ZL10036_MODULE) && defined(MODULE))
+extern struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe,
+       const struct zl10036_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe,
+       const struct zl10036_config *config, struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif /* DVB_ZL10036_H */
index b150ed306696fe1941acebb7747931ae9795c3ea..148b6f7f6cb253534b785ef2e6a95769e236fa45 100644 (file)
@@ -572,6 +572,10 @@ static int zl10353_init(struct dvb_frontend *fe)
                zl10353_dump_regs(fe);
        if (state->config.parallel_ts)
                zl10353_reset_attach[2] &= ~0x20;
+       if (state->config.clock_ctl_1)
+               zl10353_reset_attach[3] = state->config.clock_ctl_1;
+       if (state->config.pll_0)
+               zl10353_reset_attach[4] = state->config.pll_0;
 
        /* Do a "hard" reset if not already done */
        if (zl10353_read_register(state, 0x50) != zl10353_reset_attach[1] ||
@@ -614,6 +618,7 @@ struct dvb_frontend *zl10353_attach(const struct zl10353_config *config,
                                    struct i2c_adapter *i2c)
 {
        struct zl10353_state *state = NULL;
+       int id;
 
        /* allocate memory for the internal state */
        state = kzalloc(sizeof(struct zl10353_state), GFP_KERNEL);
@@ -625,7 +630,8 @@ struct dvb_frontend *zl10353_attach(const struct zl10353_config *config,
        memcpy(&state->config, config, sizeof(struct zl10353_config));
 
        /* check if the demod is there */
-       if (zl10353_read_register(state, CHIP_ID) != ID_ZL10353)
+       id = zl10353_read_register(state, CHIP_ID);
+       if ((id != ID_ZL10353) && (id != ID_CE6230) && (id != ID_CE6231))
                goto error;
 
        /* create dvb_frontend */
index 2287bac46243b5aea2991bd06b737e1c413aea5b..6e3ca9eed0484d3eb9fdcfef9cee080a215a821c 100644 (file)
@@ -41,6 +41,10 @@ struct zl10353_config
 
        /* set if i2c_gate_ctrl disable is required */
        u8 disable_i2c_gate_ctrl:1;
+
+       /* clock control registers (0x51-0x54) */
+       u8 clock_ctl_1;  /* default: 0x46 */
+       u8 pll_0;        /* default: 0x15 */
 };
 
 #if defined(CONFIG_DVB_ZL10353) || (defined(CONFIG_DVB_ZL10353_MODULE) && defined(MODULE))
index 055ff1f7e34909f73470566cef7ae0a5eaf357e1..e0dd1d3e09dd85665483afe9bf347d61ea738310 100644 (file)
@@ -22,7 +22,9 @@
 #ifndef _ZL10353_PRIV_
 #define _ZL10353_PRIV_
 
-#define ID_ZL10353     0x14
+#define ID_ZL10353     0x14 /* Zarlink ZL10353 */
+#define ID_CE6230      0x18 /* Intel CE6230 */
+#define ID_CE6231      0x19 /* Intel CE6231 */
 
 #define msb(x) (((x) >> 8) & 0xff)
 #define lsb(x) ((x) & 0xff)
@@ -50,6 +52,10 @@ enum zl10353_reg_addr {
        TPS_RECEIVED_0     = 0x1E,
        TPS_CURRENT_1      = 0x1F,
        TPS_CURRENT_0      = 0x20,
+       CLOCK_CTL_0        = 0x51,
+       CLOCK_CTL_1        = 0x52,
+       PLL_0              = 0x53,
+       PLL_1              = 0x54,
        RESET              = 0x55,
        AGC_TARGET         = 0x56,
        MCLK_RATIO         = 0x5C,
index d101b304e9b0e7348614ec4ec2c8d28e15a31317..ee89623be85aa32a3a749c1e00217efd9d2d4bcb 100644 (file)
@@ -116,6 +116,7 @@ struct pluto {
 
        /* irq */
        unsigned int overflow;
+       unsigned int dead;
 
        /* dma */
        dma_addr_t dma_addr;
@@ -336,8 +337,10 @@ static irqreturn_t pluto_irq(int irq, void *dev_id)
                return IRQ_NONE;
 
        if (tscr == 0xffffffff) {
-               // FIXME: maybe recover somehow
-               dev_err(&pluto->pdev->dev, "card hung up :(\n");
+               if (pluto->dead == 0)
+                       dev_err(&pluto->pdev->dev, "card has hung or been ejected.\n");
+               /* It's dead Jim */
+               pluto->dead = 1;
                return IRQ_HANDLED;
        }
 
index ee0737af98c0ff3004b9c15b53afbb39a6c8dee9..bcf93f4828b28cbc7dace4c0b27d1bcc27db62e3 100644 (file)
@@ -1,6 +1,8 @@
-sms1xxx-objs := smscoreapi.o smsusb.o smsdvb.o sms-cards.o
+sms1xxx-objs := smscoreapi.o sms-cards.o
 
 obj-$(CONFIG_DVB_SIANO_SMS1XXX) += sms1xxx.o
+obj-$(CONFIG_DVB_SIANO_SMS1XXX) += smsusb.o
+obj-$(CONFIG_DVB_SIANO_SMS1XXX) += smsdvb.o
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 
index 4307e4e8aa34d7cddb232643b371756f2583f078..63e4d0ec6583e95010ab8db2a5e853a1b81c79fb 100644 (file)
 
 #include "sms-cards.h"
 
-struct usb_device_id smsusb_id_table[] = {
-#ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS
-       { USB_DEVICE(0x187f, 0x0010),
-               .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
-       { USB_DEVICE(0x187f, 0x0100),
-               .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
-       { USB_DEVICE(0x187f, 0x0200),
-               .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
-       { USB_DEVICE(0x187f, 0x0201),
-               .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
-       { USB_DEVICE(0x187f, 0x0300),
-               .driver_info = SMS1XXX_BOARD_SIANO_VEGA },
-#endif
-       { USB_DEVICE(0x2040, 0x1700),
-               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
-       { USB_DEVICE(0x2040, 0x1800),
-               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
-       { USB_DEVICE(0x2040, 0x1801),
-               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
-       { USB_DEVICE(0x2040, 0x2000),
-               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
-       { USB_DEVICE(0x2040, 0x2009),
-               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 },
-       { USB_DEVICE(0x2040, 0x200a),
-               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
-       { USB_DEVICE(0x2040, 0x2010),
-               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
-       { USB_DEVICE(0x2040, 0x2019),
-               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
-       { USB_DEVICE(0x2040, 0x5500),
-               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-       { USB_DEVICE(0x2040, 0x5510),
-               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-       { USB_DEVICE(0x2040, 0x5520),
-               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-       { USB_DEVICE(0x2040, 0x5530),
-               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-       { USB_DEVICE(0x2040, 0x5580),
-               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-       { USB_DEVICE(0x2040, 0x5590),
-               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-       { }             /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, smsusb_id_table);
+static int sms_dbg;
+module_param_named(cards_dbg, sms_dbg, int, 0644);
+MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))");
 
 static struct sms_board sms_boards[] = {
        [SMS_BOARD_UNKNOWN] = {
@@ -115,6 +74,7 @@ static struct sms_board sms_boards[] = {
                .type   = SMS_NOVA_B0,
                .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
                .lna_ctrl  = 29,
+               .rf_switch = 17,
        },
        [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
                .name   = "Hauppauge WinTV MiniCard",
@@ -130,6 +90,7 @@ struct sms_board *sms_get_board(int id)
 
        return &sms_boards[id];
 }
+EXPORT_SYMBOL_GPL(sms_get_board);
 
 static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
 {
@@ -182,6 +143,7 @@ int sms_board_setup(struct smscore_device_t *coredev)
        }
        return 0;
 }
+EXPORT_SYMBOL_GPL(sms_board_setup);
 
 int sms_board_power(struct smscore_device_t *coredev, int onoff)
 {
@@ -197,12 +159,13 @@ int sms_board_power(struct smscore_device_t *coredev, int onoff)
        case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
        case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
                /* LNA */
-               sms_set_gpio(coredev,
-                            board->lna_ctrl, onoff ? 1 : 0);
+               if (!onoff)
+                       sms_set_gpio(coredev, board->lna_ctrl, 0);
                break;
        }
        return 0;
 }
+EXPORT_SYMBOL_GPL(sms_board_power);
 
 int sms_board_led_feedback(struct smscore_device_t *coredev, int led)
 {
@@ -225,3 +188,40 @@ int sms_board_led_feedback(struct smscore_device_t *coredev, int led)
        }
        return 0;
 }
+EXPORT_SYMBOL_GPL(sms_board_led_feedback);
+
+int sms_board_lna_control(struct smscore_device_t *coredev, int onoff)
+{
+       int board_id = smscore_get_board_id(coredev);
+       struct sms_board *board = sms_get_board(board_id);
+
+       sms_debug("%s: LNA %s", __func__, onoff ? "enabled" : "disabled");
+
+       switch (board_id) {
+       case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+       case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+               sms_set_gpio(coredev,
+                            board->rf_switch, onoff ? 1 : 0);
+               return sms_set_gpio(coredev,
+                                   board->lna_ctrl, onoff ? 1 : 0);
+       }
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(sms_board_lna_control);
+
+int sms_board_load_modules(int id)
+{
+       switch (id) {
+       case SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT:
+       case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A:
+       case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B:
+       case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+               request_module("smsdvb");
+               break;
+       default:
+               /* do nothing */
+               break;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sms_board_load_modules);
index 8e0fe9fd261011bafc91e1d265b99797aab6cef0..64d74c59c33f9503760207f9dcf1f1a775f1ac1d 100644 (file)
@@ -40,7 +40,7 @@ struct sms_board {
        char *name, *fw[DEVICE_MODE_MAX];
 
        /* gpios */
-       int led_power, led_hi, led_lo, lna_ctrl;
+       int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
 };
 
 struct sms_board *sms_get_board(int id);
@@ -52,7 +52,8 @@ int sms_board_setup(struct smscore_device_t *coredev);
 #define SMS_LED_HI  2
 int sms_board_led_feedback(struct smscore_device_t *coredev, int led);
 int sms_board_power(struct smscore_device_t *coredev, int onoff);
+int sms_board_lna_control(struct smscore_device_t *coredev, int onoff);
 
-extern struct usb_device_id smsusb_id_table[];
+extern int sms_board_load_modules(int id);
 
 #endif /* __SMS_CARDS_H__ */
index cf613f22fb8d84e68203f7de9f7bed5c3b997978..7bd4d1dee2b32022bf52ff5923b95f423bd81e45 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  This file contains implementation for the interface to sms core component
  *
- *  author: Anatoly Greenblat
+ *  author: Uri Shkolnik
  *
  *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
  *
@@ -34,8 +34,8 @@
 #include "smscoreapi.h"
 #include "sms-cards.h"
 
-int sms_debug;
-module_param_named(debug, sms_debug, int, 0644);
+static int sms_dbg;
+module_param_named(debug, sms_dbg, int, 0644);
 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
 
 struct smscore_device_notifyee_t {
@@ -105,11 +105,13 @@ int smscore_led_state(struct smscore_device_t *core, int led)
                core->led_state = led;
        return core->led_state;
 }
+EXPORT_SYMBOL_GPL(smscore_set_board_id);
 
 int smscore_get_board_id(struct smscore_device_t *core)
 {
        return core->board_id;
 }
+EXPORT_SYMBOL_GPL(smscore_get_board_id);
 
 struct smscore_registry_entry_t {
        struct list_head entry;
@@ -170,6 +172,7 @@ int smscore_registry_getmode(char *devpath)
 
        return default_mode;
 }
+EXPORT_SYMBOL_GPL(smscore_registry_getmode);
 
 static enum sms_device_type_st smscore_registry_gettype(char *devpath)
 {
@@ -261,6 +264,7 @@ int smscore_register_hotplug(hotplug_t hotplug)
 
        return rc;
 }
+EXPORT_SYMBOL_GPL(smscore_register_hotplug);
 
 /**
  * unregister a client callback that called when device plugged in/unplugged
@@ -289,6 +293,7 @@ void smscore_unregister_hotplug(hotplug_t hotplug)
 
        kmutex_unlock(&g_smscore_deviceslock);
 }
+EXPORT_SYMBOL_GPL(smscore_unregister_hotplug);
 
 static void smscore_notify_clients(struct smscore_device_t *coredev)
 {
@@ -432,6 +437,7 @@ int smscore_register_device(struct smsdevice_params_t *params,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(smscore_register_device);
 
 /**
  * sets initial device mode and notifies client hotplugs that device is ready
@@ -460,6 +466,7 @@ int smscore_start_device(struct smscore_device_t *coredev)
 
        return rc;
 }
+EXPORT_SYMBOL_GPL(smscore_start_device);
 
 static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
                                        void *buffer, size_t size,
@@ -688,6 +695,7 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
 
        sms_info("device %p destroyed", coredev);
 }
+EXPORT_SYMBOL_GPL(smscore_unregister_device);
 
 static int smscore_detect_mode(struct smscore_device_t *coredev)
 {
@@ -732,7 +740,7 @@ static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
        /*DVBH*/
        {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
        /*TDMB*/
-       {"none", "tdmb_nova_12mhz.inp", "none", "none"},
+       {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
        /*DABIP*/
        {"none", "none", "none", "none"},
        /*BDA*/
@@ -879,6 +887,7 @@ int smscore_get_device_mode(struct smscore_device_t *coredev)
 {
        return coredev->mode;
 }
+EXPORT_SYMBOL_GPL(smscore_get_device_mode);
 
 /**
  * find client by response id & type within the clients list.
@@ -1006,6 +1015,7 @@ void smscore_onresponse(struct smscore_device_t *coredev,
                smscore_putbuffer(coredev, cb);
        }
 }
+EXPORT_SYMBOL_GPL(smscore_onresponse);
 
 /**
  * return pointer to next free buffer descriptor from core pool
@@ -1031,6 +1041,7 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
 
        return cb;
 }
+EXPORT_SYMBOL_GPL(smscore_getbuffer);
 
 /**
  * return buffer descriptor to a pool
@@ -1045,6 +1056,7 @@ void smscore_putbuffer(struct smscore_device_t *coredev,
 {
        list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
 }
+EXPORT_SYMBOL_GPL(smscore_putbuffer);
 
 static int smscore_validate_client(struct smscore_device_t *coredev,
                                   struct smscore_client_t *client,
@@ -1124,6 +1136,7 @@ int smscore_register_client(struct smscore_device_t *coredev,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(smscore_register_client);
 
 /**
  * frees smsclient object and all subclients associated with it
@@ -1154,6 +1167,7 @@ void smscore_unregister_client(struct smscore_client_t *client)
 
        spin_unlock_irqrestore(&coredev->clientslock, flags);
 }
+EXPORT_SYMBOL_GPL(smscore_unregister_client);
 
 /**
  * verifies that source id is not taken by another client,
@@ -1193,6 +1207,7 @@ int smsclient_sendrequest(struct smscore_client_t *client,
 
        return coredev->sendrequest_handler(coredev->context, buffer, size);
 }
+EXPORT_SYMBOL_GPL(smsclient_sendrequest);
 
 
 int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
@@ -1276,12 +1291,12 @@ static int __init smscore_module_init(void)
        INIT_LIST_HEAD(&g_smscore_registry);
        kmutex_init(&g_smscore_registrylock);
 
-       /* USB Register */
-       rc = smsusb_register();
 
-       /* DVB Register */
-       rc = smsdvb_register();
 
+
+
+
+       return rc;
        sms_debug("rc %d", rc);
 
        return rc;
@@ -1290,6 +1305,10 @@ static int __init smscore_module_init(void)
 static void __exit smscore_module_exit(void)
 {
 
+
+
+
+
        kmutex_lock(&g_smscore_deviceslock);
        while (!list_empty(&g_smscore_notifyees)) {
                struct smscore_device_notifyee_t *notifyee =
@@ -1312,18 +1331,12 @@ static void __exit smscore_module_exit(void)
        }
        kmutex_unlock(&g_smscore_registrylock);
 
-       /* DVB UnRegister */
-       smsdvb_unregister();
-
-       /* Unregister USB */
-       smsusb_unregister();
-
        sms_debug("");
 }
 
 module_init(smscore_module_init);
 module_exit(smscore_module_exit);
 
-MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
-MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)");
+MODULE_DESCRIPTION("Siano MDTV Core module");
+MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
 MODULE_LICENSE("GPL");
index 760e233fcbc587594d965479a7ee35de64760c0e..548de9056e8b97b0f567d9cbf948ecb10891b6cc 100644 (file)
 #include <linux/scatterlist.h>
 #include <linux/types.h>
 #include <asm/page.h>
+#include <linux/mutex.h>
 
 #include "dmxdev.h"
 #include "dvbdev.h"
 #include "dvb_demux.h"
 #include "dvb_frontend.h"
 
-#include <linux/mutex.h>
 
 #define kmutex_init(_p_) mutex_init(_p_)
 #define kmutex_lock(_p_) mutex_lock(_p_)
@@ -369,27 +369,6 @@ struct smscore_gpio_config {
        u8 outputdriving;
 };
 
-struct smsdvb_client_t {
-       struct list_head entry;
-
-       struct smscore_device_t *coredev;
-       struct smscore_client_t *smsclient;
-
-       struct dvb_adapter      adapter;
-       struct dvb_demux        demux;
-       struct dmxdev           dmxdev;
-       struct dvb_frontend     frontend;
-
-       fe_status_t             fe_status;
-       int                     fe_ber, fe_snr, fe_unc, fe_signal_strength;
-
-       struct completion       tune_done, stat_done;
-
-       /* todo: save freq/band instead whole struct */
-       struct dvb_frontend_parameters fe_params;
-
-};
-
 extern void smscore_registry_setmode(char *devpath, int mode);
 extern int smscore_registry_getmode(char *devpath);
 
@@ -418,6 +397,13 @@ extern int smsclient_sendrequest(struct smscore_client_t *client,
 extern void smscore_onresponse(struct smscore_device_t *coredev,
                               struct smscore_buffer_t *cb);
 
+extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev);
+extern int smscore_map_common_buffer(struct smscore_device_t *coredev,
+                                     struct vm_area_struct *vma);
+extern int smscore_get_fw_filename(struct smscore_device_t *coredev,
+                                  int mode, char *filename);
+extern int smscore_send_fw_file(struct smscore_device_t *coredev,
+                               u8 *ufwbuf, int size);
 
 extern
 struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
@@ -433,18 +419,9 @@ int smscore_get_board_id(struct smscore_device_t *core);
 
 int smscore_led_state(struct smscore_device_t *core, int led);
 
-/* smsdvb.c */
-int smsdvb_register(void);
-void smsdvb_unregister(void);
-
-/* smsusb.c */
-int smsusb_register(void);
-void smsusb_unregister(void);
 
 /* ------------------------------------------------------------------------ */
 
-extern int sms_debug;
-
 #define DBG_INFO 1
 #define DBG_ADV  2
 
@@ -452,7 +429,7 @@ extern int sms_debug;
        printk(kern "%s: " fmt "\n", __func__, ##arg)
 
 #define dprintk(kern, lvl, fmt, arg...) do {\
-       if (sms_debug & lvl) \
+       if (sms_dbg & lvl) \
                sms_printk(kern, fmt, ##arg); } while (0)
 
 #define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg)
index 2da953a4f4f56cc08d94e9d6d0e0460dc6a9aa31..ba080b95befbf5cda1d3943a4d34eaeab5bf60ee 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Siano SMS1xxx USB dongle
  *
- *  author: Anatoly Greenblat
+ *  Author: Uri Shkolni
  *
  *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
  *
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
+struct smsdvb_client_t {
+       struct list_head entry;
+
+       struct smscore_device_t *coredev;
+       struct smscore_client_t *smsclient;
+
+       struct dvb_adapter      adapter;
+       struct dvb_demux        demux;
+       struct dmxdev           dmxdev;
+       struct dvb_frontend     frontend;
+
+       fe_status_t             fe_status;
+       int                     fe_ber, fe_snr, fe_unc, fe_signal_strength;
+
+       struct completion       tune_done, stat_done;
+
+       /* todo: save freq/band instead whole struct */
+       struct dvb_frontend_parameters fe_params;
+};
+
 static struct list_head g_smsdvb_clients;
 static struct mutex g_smsdvb_clientslock;
 
+static int sms_dbg;
+module_param_named(debug, sms_dbg, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
+
 static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
 {
        struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
@@ -262,6 +286,7 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
                struct SmsMsgHdr_ST     Msg;
                u32             Data[3];
        } Msg;
+       int ret;
 
        Msg.Msg.msgSrcId  = DVBT_BDA_CONTROL_MSG_ID;
        Msg.Msg.msgDstId  = HIF_TASK;
@@ -282,6 +307,24 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
        default: return -EINVAL;
        }
 
+       /* Disable LNA, if any. An error is returned if no LNA is present */
+       ret = sms_board_lna_control(client->coredev, 0);
+       if (ret == 0) {
+               fe_status_t status;
+
+               /* tune with LNA off at first */
+               ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+                                                 &client->tune_done);
+
+               smsdvb_read_status(fe, &status);
+
+               if (status & FE_HAS_LOCK)
+                       return ret;
+
+               /* previous tune didnt lock - enable LNA and tune again */
+               sms_board_lna_control(client->coredev, 1);
+       }
+
        return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
                                           &client->tune_done);
 }
@@ -329,7 +372,7 @@ static void smsdvb_release(struct dvb_frontend *fe)
 
 static struct dvb_frontend_ops smsdvb_fe_ops = {
        .info = {
-               .name                   = "Siano Mobile Digital SMS1xxx",
+               .name                   = "Siano Mobile Digital MDTV Receiver",
                .type                   = FE_OFDM,
                .frequency_min          = 44250000,
                .frequency_max          = 867250000,
@@ -371,7 +414,7 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
        if (!arrival)
                return 0;
 
-       if (smscore_get_device_mode(coredev) != 4) {
+       if (smscore_get_device_mode(coredev) != DEVICE_MODE_DVBT_BDA) {
                sms_err("SMS Device mode is not set for "
                        "DVB operation.");
                return 0;
@@ -473,7 +516,7 @@ adapter_error:
        return rc;
 }
 
-int smsdvb_register(void)
+int smsdvb_module_init(void)
 {
        int rc;
 
@@ -487,7 +530,7 @@ int smsdvb_register(void)
        return rc;
 }
 
-void smsdvb_unregister(void)
+void smsdvb_module_exit(void)
 {
        smscore_unregister_hotplug(smsdvb_hotplug);
 
@@ -499,3 +542,10 @@ void smsdvb_unregister(void)
 
        kmutex_unlock(&g_smsdvb_clientslock);
 }
+
+module_init(smsdvb_module_init);
+module_exit(smsdvb_module_exit);
+
+MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
+MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
+MODULE_LICENSE("GPL");
index 5d7ca341771995941d1810effabf7a104a83224c..71c65f544c072911cb326f8614097378448e2618 100644 (file)
 #include "smscoreapi.h"
 #include "sms-cards.h"
 
+static int sms_dbg;
+module_param_named(debug, sms_dbg, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
+
 #define USB1_BUFFER_SIZE               0x1000
 #define USB2_BUFFER_SIZE               0x4000
 
@@ -424,6 +428,7 @@ static int smsusb_probe(struct usb_interface *intf,
 
        rc = smsusb_init_device(intf, id->driver_info);
        sms_info("rc %d", rc);
+       sms_board_load_modules(id->driver_info);
        return rc;
 }
 
@@ -436,7 +441,7 @@ static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
 {
        struct smsusb_device_t *dev =
                (struct smsusb_device_t *)usb_get_intfdata(intf);
-       printk(KERN_INFO "%s  Entering status %d.\n", __func__, msg.event);
+       printk(KERN_INFO "%s: Entering status %d.\n", __func__, msg.event);
        smsusb_stop_streaming(dev);
        return 0;
 }
@@ -448,7 +453,7 @@ static int smsusb_resume(struct usb_interface *intf)
                (struct smsusb_device_t *)usb_get_intfdata(intf);
        struct usb_device *udev = interface_to_usbdev(intf);
 
-       printk(KERN_INFO "%s  Entering.\n", __func__);
+       printk(KERN_INFO "%s: Entering.\n", __func__);
        usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
        usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
 
@@ -463,9 +468,8 @@ static int smsusb_resume(struct usb_interface *intf)
                                       intf->cur_altsetting->desc.
                                       bInterfaceNumber, 0);
                if (rc < 0) {
-                       printk(KERN_INFO
-                              "%s usb_set_interface failed, rc %d\n",
-                              __func__, rc);
+                       printk(KERN_INFO "%s usb_set_interface failed, "
+                              "rc %d\n", __func__, rc);
                        return rc;
                }
        }
@@ -474,8 +478,55 @@ static int smsusb_resume(struct usb_interface *intf)
        return 0;
 }
 
+struct usb_device_id smsusb_id_table[] = {
+#ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS
+       { USB_DEVICE(0x187f, 0x0010),
+               .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
+       { USB_DEVICE(0x187f, 0x0100),
+               .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
+       { USB_DEVICE(0x187f, 0x0200),
+               .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
+       { USB_DEVICE(0x187f, 0x0201),
+               .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
+       { USB_DEVICE(0x187f, 0x0300),
+               .driver_info = SMS1XXX_BOARD_SIANO_VEGA },
+#endif
+       { USB_DEVICE(0x2040, 0x1700),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
+       { USB_DEVICE(0x2040, 0x1800),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
+       { USB_DEVICE(0x2040, 0x1801),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
+       { USB_DEVICE(0x2040, 0x2000),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+       { USB_DEVICE(0x2040, 0x2009),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 },
+       { USB_DEVICE(0x2040, 0x200a),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+       { USB_DEVICE(0x2040, 0x2010),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+       { USB_DEVICE(0x2040, 0x2011),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+       { USB_DEVICE(0x2040, 0x2019),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+       { USB_DEVICE(0x2040, 0x5500),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+       { USB_DEVICE(0x2040, 0x5510),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+       { USB_DEVICE(0x2040, 0x5520),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+       { USB_DEVICE(0x2040, 0x5530),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+       { USB_DEVICE(0x2040, 0x5580),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+       { USB_DEVICE(0x2040, 0x5590),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+       { }             /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, smsusb_id_table);
+
 static struct usb_driver smsusb_driver = {
-       .name                   = "sms1xxx",
+       .name                   = "smsusb",
        .probe                  = smsusb_probe,
        .disconnect             = smsusb_disconnect,
        .id_table               = smsusb_id_table,
@@ -484,7 +535,7 @@ static struct usb_driver smsusb_driver = {
        .resume                 = smsusb_resume,
 };
 
-int smsusb_register(void)
+int smsusb_module_init(void)
 {
        int rc = usb_register(&smsusb_driver);
        if (rc)
@@ -495,10 +546,16 @@ int smsusb_register(void)
        return rc;
 }
 
-void smsusb_unregister(void)
+void smsusb_module_exit(void)
 {
        sms_debug("");
        /* Regular USB Cleanup */
        usb_deregister(&smsusb_driver);
 }
 
+module_init(smsusb_module_init);
+module_exit(smsusb_module_exit);
+
+MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
+MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
+MODULE_LICENSE("GPL");
index ab0bcd208c78341e454ebafdab9bf21ac1de51b7..772990415f999d83e57f1214e49ed20b1e3b48d2 100644 (file)
@@ -108,7 +108,7 @@ config DVB_BUDGET_CI
        select DVB_STB6100 if !DVB_FE_CUSTOMISE
        select DVB_LNBP21 if !DVB_FE_CUSTOMISE
        select DVB_TDA10023 if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
        select VIDEO_IR
        help
          Support for simple SAA7146 based DVB cards
index aa1ff524256e1397012bcde72919d94113df6f18..4624cee93e749cc6a5c11461ba2a8028f26c281f 100644 (file)
@@ -725,7 +725,7 @@ static int dvb_osd_ioctl(struct inode *inode, struct file *file,
 }
 
 
-static struct file_operations dvb_osd_fops = {
+static const struct file_operations dvb_osd_fops = {
        .owner          = THIS_MODULE,
        .ioctl          = dvb_generic_ioctl,
        .open           = dvb_generic_open,
index bdc62acf2099ea431f5303f1336d6e2a78902bba..e4d0900d5121f0bfa6d343e7ac29de1fb906e542 100644 (file)
@@ -1456,7 +1456,7 @@ static int dvb_audio_release(struct inode *inode, struct file *file)
  * driver registration
  ******************************************************************************/
 
-static struct file_operations dvb_video_fops = {
+static const struct file_operations dvb_video_fops = {
        .owner          = THIS_MODULE,
        .write          = dvb_video_write,
        .ioctl          = dvb_generic_ioctl,
@@ -1474,7 +1474,7 @@ static struct dvb_device dvbdev_video = {
        .kernel_ioctl   = dvb_video_ioctl,
 };
 
-static struct file_operations dvb_audio_fops = {
+static const struct file_operations dvb_audio_fops = {
        .owner          = THIS_MODULE,
        .write          = dvb_audio_write,
        .ioctl          = dvb_generic_ioctl,
index 261135ded4815ecf909875773ddf19c9ceb50836..c7a65b1544a330e34a2e500883981336ba23c6c4 100644 (file)
@@ -345,7 +345,7 @@ static ssize_t dvb_ca_read(struct file *file, char __user *buf,
        return ci_ll_read(&av7110->ci_rbuffer, file, buf, count, ppos);
 }
 
-static struct file_operations dvb_ca_fops = {
+static const struct file_operations dvb_ca_fops = {
        .owner          = THIS_MODULE,
        .read           = dvb_ca_read,
        .write          = dvb_ca_write,
index c5b9c70563dc699eb149ae7c6f7f510228623f77..2210cff738e67a7e47a26d29faddb18633ba0ee1 100644 (file)
@@ -316,253 +316,261 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh)
        return 0;
 }
 
-static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
 {
-       struct saa7146_dev *dev = fh->dev;
-       struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
-       dprintk(4, "saa7146_dev: %p\n", dev);
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+       u16 stereo_det;
+       s8 stereo;
 
-       switch (cmd) {
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
-               u16 stereo_det;
-               s8 stereo;
+       dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index);
 
-               dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index);
+       if (!av7110->analog_tuner_flags || t->index != 0)
+               return -EINVAL;
 
-               if (!av7110->analog_tuner_flags || t->index != 0)
-                       return -EINVAL;
+       memset(t, 0, sizeof(*t));
+       strcpy((char *)t->name, "Television");
+
+       t->type = V4L2_TUNER_ANALOG_TV;
+       t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
+               V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+       t->rangelow = 772;      /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
+       t->rangehigh = 13684;   /* 855.25 MHz / 62.5 kHz = 13684 */
+       /* FIXME: add the real signal strength here */
+       t->signal = 0xffff;
+       t->afc = 0;
+
+       /* FIXME: standard / stereo detection is still broken */
+       msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det);
+       dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
+       msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det);
+       dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det);
+       stereo = (s8)(stereo_det >> 8);
+       if (stereo > 0x10) {
+               /* stereo */
+               t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+               t->audmode = V4L2_TUNER_MODE_STEREO;
+       } else if (stereo < -0x10) {
+               /* bilingual */
+               t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+               t->audmode = V4L2_TUNER_MODE_LANG1;
+       } else /* mono */
+               t->rxsubchans = V4L2_TUNER_SUB_MONO;
 
-               memset(t, 0, sizeof(*t));
-               strcpy((char *)t->name, "Television");
-
-               t->type = V4L2_TUNER_ANALOG_TV;
-               t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
-                       V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
-               t->rangelow = 772;      /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
-               t->rangehigh = 13684;   /* 855.25 MHz / 62.5 kHz = 13684 */
-               /* FIXME: add the real signal strength here */
-               t->signal = 0xffff;
-               t->afc = 0;
-
-               // FIXME: standard / stereo detection is still broken
-               msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det);
-               dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
-               msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det);
-               dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det);
-               stereo = (s8)(stereo_det >> 8);
-               if (stereo > 0x10) {
-                       /* stereo */
-                       t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
-                       t->audmode = V4L2_TUNER_MODE_STEREO;
-               }
-               else if (stereo < -0x10) {
-                       /* bilingual */
-                       t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
-                       t->audmode = V4L2_TUNER_MODE_LANG1;
-               }
-               else /* mono */
-                       t->rxsubchans = V4L2_TUNER_SUB_MONO;
+       return 0;
+}
 
-               return 0;
-       }
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
-               u16 fm_matrix, src;
-               dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index);
+static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+       u16 fm_matrix, src;
+       dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index);
 
-               if (!av7110->analog_tuner_flags || av7110->current_input != 1)
-                       return -EINVAL;
+       if (!av7110->analog_tuner_flags || av7110->current_input != 1)
+               return -EINVAL;
 
-               switch (t->audmode) {
-               case V4L2_TUNER_MODE_STEREO:
-                       dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n");
-                       fm_matrix = 0x3001; // stereo
-                       src = 0x0020;
-                       break;
-               case V4L2_TUNER_MODE_LANG1_LANG2:
-                       dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n");
-                       fm_matrix = 0x3000; // bilingual
-                       src = 0x0020;
-                       break;
-               case V4L2_TUNER_MODE_LANG1:
-                       dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n");
-                       fm_matrix = 0x3000; // mono
-                       src = 0x0000;
-                       break;
-               case V4L2_TUNER_MODE_LANG2:
-                       dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n");
-                       fm_matrix = 0x3000; // mono
-                       src = 0x0010;
-                       break;
-               default: /* case V4L2_TUNER_MODE_MONO: */
-                       dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n");
-                       fm_matrix = 0x3000; // mono
-                       src = 0x0030;
-                       break;
-               }
-               msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix);
-               msp_writereg(av7110, MSP_WR_DSP, 0x0008, src);
-               msp_writereg(av7110, MSP_WR_DSP, 0x0009, src);
-               msp_writereg(av7110, MSP_WR_DSP, 0x000a, src);
-               return 0;
+       switch (t->audmode) {
+       case V4L2_TUNER_MODE_STEREO:
+               dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n");
+               fm_matrix = 0x3001; /* stereo */
+               src = 0x0020;
+               break;
+       case V4L2_TUNER_MODE_LANG1_LANG2:
+               dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n");
+               fm_matrix = 0x3000; /* bilingual */
+               src = 0x0020;
+               break;
+       case V4L2_TUNER_MODE_LANG1:
+               dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n");
+               fm_matrix = 0x3000; /* mono */
+               src = 0x0000;
+               break;
+       case V4L2_TUNER_MODE_LANG2:
+               dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n");
+               fm_matrix = 0x3000; /* mono */
+               src = 0x0010;
+               break;
+       default: /* case V4L2_TUNER_MODE_MONO: */
+               dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n");
+               fm_matrix = 0x3000; /* mono */
+               src = 0x0030;
+               break;
        }
-       case VIDIOC_G_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
+       msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix);
+       msp_writereg(av7110, MSP_WR_DSP, 0x0008, src);
+       msp_writereg(av7110, MSP_WR_DSP, 0x0009, src);
+       msp_writereg(av7110, MSP_WR_DSP, 0x000a, src);
+       return 0;
+}
 
-               dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency);
+static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
 
-               if (!av7110->analog_tuner_flags || av7110->current_input != 1)
-                       return -EINVAL;
+       dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency);
 
-               memset(f, 0, sizeof(*f));
-               f->type = V4L2_TUNER_ANALOG_TV;
-               f->frequency =  av7110->current_freq;
-               return 0;
-       }
-       case VIDIOC_S_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
+       if (!av7110->analog_tuner_flags || av7110->current_input != 1)
+               return -EINVAL;
 
-               dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency);
+       memset(f, 0, sizeof(*f));
+       f->type = V4L2_TUNER_ANALOG_TV;
+       f->frequency =  av7110->current_freq;
+       return 0;
+}
 
-               if (!av7110->analog_tuner_flags || av7110->current_input != 1)
-                       return -EINVAL;
+static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
 
-               if (V4L2_TUNER_ANALOG_TV != f->type)
-                       return -EINVAL;
+       dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency);
 
-               msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); // fast mute
-               msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);
+       if (!av7110->analog_tuner_flags || av7110->current_input != 1)
+               return -EINVAL;
 
-               /* tune in desired frequency */
-               if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
-                       ves1820_set_tv_freq(dev, f->frequency);
-               } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
-                       stv0297_set_tv_freq(dev, f->frequency);
-               }
-               av7110->current_freq = f->frequency;
+       if (V4L2_TUNER_ANALOG_TV != f->type)
+               return -EINVAL;
 
-               msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); // start stereo detection
-               msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000);
-               msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone
-               msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume
-               return 0;
-       }
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *i = arg;
+       msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */
+       msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);
 
-               dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
+       /* tune in desired frequency */
+       if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820)
+               ves1820_set_tv_freq(dev, f->frequency);
+       else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297)
+               stv0297_set_tv_freq(dev, f->frequency);
+       av7110->current_freq = f->frequency;
 
-               if (av7110->analog_tuner_flags) {
-                       if (i->index < 0 || i->index >= 4)
-                               return -EINVAL;
-               } else {
-                       if (i->index != 0)
-                               return -EINVAL;
-               }
+       msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); /* start stereo detection */
+       msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000);
+       msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); /* loudspeaker + headphone */
+       msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); /* SCART 1 volume */
+       return 0;
+}
 
-               memcpy(i, &inputs[i->index], sizeof(struct v4l2_input));
+static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
 
-               return 0;
+       dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
+
+       if (av7110->analog_tuner_flags) {
+               if (i->index < 0 || i->index >= 4)
+                       return -EINVAL;
+       } else {
+               if (i->index != 0)
+                       return -EINVAL;
        }
-       case VIDIOC_G_INPUT:
-       {
-               int *input = (int *)arg;
-               *input = av7110->current_input;
-               dprintk(2, "VIDIOC_G_INPUT: %d\n", *input);
+
+       memcpy(i, &inputs[i->index], sizeof(struct v4l2_input));
+
+       return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+       *input = av7110->current_input;
+       dprintk(2, "VIDIOC_G_INPUT: %d\n", *input);
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+       dprintk(2, "VIDIOC_S_INPUT: %d\n", input);
+
+       if (!av7110->analog_tuner_flags)
                return 0;
-       }
-       case VIDIOC_S_INPUT:
-       {
-               int input = *(int *)arg;
 
-               dprintk(2, "VIDIOC_S_INPUT: %d\n", input);
+       if (input < 0 || input >= 4)
+               return -EINVAL;
 
-               if (!av7110->analog_tuner_flags)
-                       return 0;
+       av7110->current_input = input;
+       return av7110_dvb_c_switch(fh);
+}
 
-               if (input < 0 || input >= 4)
-                       return -EINVAL;
+static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+       dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
+       if (a->index != 0)
+               return -EINVAL;
+       memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio));
+       return 0;
+}
 
-               av7110->current_input = input;
-               return av7110_dvb_c_switch(fh);
-       }
-       case VIDIOC_G_AUDIO:
-       {
-               struct v4l2_audio *a = arg;
+static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+       dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
+       return 0;
+}
 
-               dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
-               if (a->index != 0)
-                       return -EINVAL;
-               memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio));
-               break;
-       }
-       case VIDIOC_S_AUDIO:
-       {
-               struct v4l2_audio *a = arg;
-               dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
-               break;
-       }
-       case VIDIOC_G_SLICED_VBI_CAP:
-       {
-               struct v4l2_sliced_vbi_cap *cap = arg;
-               dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
-               memset(cap, 0, sizeof *cap);
-               if (FW_VERSION(av7110->arm_app) >= 0x2623) {
-                       cap->service_set = V4L2_SLICED_WSS_625;
-                       cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
-               }
-               break;
-       }
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format *f = arg;
-               dprintk(2, "VIDIOC_G_FMT:\n");
-               if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
-                   FW_VERSION(av7110->arm_app) < 0x2623)
-                       return -EAGAIN; /* handled by core driver */
-               memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
-               if (av7110->wssMode) {
-                       f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
-                       f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
-                       f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
-               }
-               break;
+static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh,
+                                       struct v4l2_sliced_vbi_cap *cap)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+       dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
+       if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
+               return -EINVAL;
+       if (FW_VERSION(av7110->arm_app) >= 0x2623) {
+               cap->service_set = V4L2_SLICED_WSS_625;
+               cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
        }
-       case VIDIOC_S_FMT:
-       {
-               struct v4l2_format *f = arg;
-               dprintk(2, "VIDIOC_S_FMT\n");
-               if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
-                   FW_VERSION(av7110->arm_app) < 0x2623)
-                       return -EAGAIN; /* handled by core driver */
-               if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
-                   f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
-                       memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
-                       /* WSS controlled by firmware */
-                       av7110->wssMode = 0;
-                       av7110->wssData = 0;
-                       return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
-                                            SetWSSConfig, 1, 0);
-               } else {
-                       memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
-                       f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
-                       f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
-                       f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
-                       /* WSS controlled by userspace */
-                       av7110->wssMode = 1;
-                       av7110->wssData = 0;
-               }
-               break;
+       return 0;
+}
+
+static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh,
+                                       struct v4l2_format *f)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+       dprintk(2, "VIDIOC_G_FMT:\n");
+       if (FW_VERSION(av7110->arm_app) < 0x2623)
+               return -EINVAL;
+       memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+       if (av7110->wssMode) {
+               f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
+               f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+               f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data);
        }
-       default:
-               printk("no such ioctl\n");
-               return -ENOIOCTLCMD;
+       return 0;
+}
+
+static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh,
+                                       struct v4l2_format *f)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+       dprintk(2, "VIDIOC_S_FMT\n");
+       if (FW_VERSION(av7110->arm_app) < 0x2623)
+               return -EINVAL;
+       if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
+           f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
+               memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
+               /* WSS controlled by firmware */
+               av7110->wssMode = 0;
+               av7110->wssData = 0;
+               return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
+                                    SetWSSConfig, 1, 0);
+       } else {
+               memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
+               f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
+               f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+               f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data);
+               /* WSS controlled by userspace */
+               av7110->wssMode = 1;
+               av7110->wssData = 0;
        }
        return 0;
 }
@@ -609,22 +617,6 @@ static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size
  * INITIALIZATION
  ****************************************************************************/
 
-static struct saa7146_extension_ioctls ioctls[] = {
-       { VIDIOC_ENUMINPUT,     SAA7146_EXCLUSIVE },
-       { VIDIOC_G_INPUT,       SAA7146_EXCLUSIVE },
-       { VIDIOC_S_INPUT,       SAA7146_EXCLUSIVE },
-       { VIDIOC_G_FREQUENCY,   SAA7146_EXCLUSIVE },
-       { VIDIOC_S_FREQUENCY,   SAA7146_EXCLUSIVE },
-       { VIDIOC_G_TUNER,       SAA7146_EXCLUSIVE },
-       { VIDIOC_S_TUNER,       SAA7146_EXCLUSIVE },
-       { VIDIOC_G_AUDIO,       SAA7146_EXCLUSIVE },
-       { VIDIOC_S_AUDIO,       SAA7146_EXCLUSIVE },
-       { VIDIOC_G_SLICED_VBI_CAP, SAA7146_EXCLUSIVE },
-       { VIDIOC_G_FMT,         SAA7146_BEFORE },
-       { VIDIOC_S_FMT,         SAA7146_BEFORE },
-       { 0, 0 }
-};
-
 static u8 saa7113_init_regs[] = {
        0x02, 0xd0,
        0x03, 0x23,
@@ -788,20 +780,34 @@ int av7110_init_analog_module(struct av7110 *av7110)
 int av7110_init_v4l(struct av7110 *av7110)
 {
        struct saa7146_dev* dev = av7110->dev;
+       struct saa7146_ext_vv *vv_data;
        int ret;
 
        /* special case DVB-C: these cards have an analog tuner
           plus need some special handling, so we have separate
           saa7146_ext_vv data for these... */
        if (av7110->analog_tuner_flags)
-               ret = saa7146_vv_init(dev, &av7110_vv_data_c);
+               vv_data = &av7110_vv_data_c;
        else
-               ret = saa7146_vv_init(dev, &av7110_vv_data_st);
+               vv_data = &av7110_vv_data_st;
+       ret = saa7146_vv_init(dev, vv_data);
 
        if (ret) {
                ERR(("cannot init capture device. skipping.\n"));
                return -ENODEV;
        }
+       vv_data->ops.vidioc_enum_input = vidioc_enum_input;
+       vv_data->ops.vidioc_g_input = vidioc_g_input;
+       vv_data->ops.vidioc_s_input = vidioc_s_input;
+       vv_data->ops.vidioc_g_tuner = vidioc_g_tuner;
+       vv_data->ops.vidioc_s_tuner = vidioc_s_tuner;
+       vv_data->ops.vidioc_g_frequency = vidioc_g_frequency;
+       vv_data->ops.vidioc_s_frequency = vidioc_s_frequency;
+       vv_data->ops.vidioc_g_audio = vidioc_g_audio;
+       vv_data->ops.vidioc_s_audio = vidioc_s_audio;
+       vv_data->ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap;
+       vv_data->ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out;
+       vv_data->ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out;
 
        if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
                ERR(("cannot register capture device. skipping.\n"));
@@ -900,9 +906,6 @@ static struct saa7146_ext_vv av7110_vv_data_st = {
        .num_stds       = ARRAY_SIZE(standard),
        .std_callback   = &std_callback,
 
-       .ioctls         = &ioctls[0],
-       .ioctl          = av7110_ioctl,
-
        .vbi_fops.open  = av7110_vbi_reset,
        .vbi_fops.release = av7110_vbi_reset,
        .vbi_fops.write = av7110_vbi_write,
@@ -918,9 +921,6 @@ static struct saa7146_ext_vv av7110_vv_data_c = {
        .num_stds       = ARRAY_SIZE(standard),
        .std_callback   = &std_callback,
 
-       .ioctls         = &ioctls[0],
-       .ioctl          = av7110_ioctl,
-
        .vbi_fops.open  = av7110_vbi_reset,
        .vbi_fops.release = av7110_vbi_reset,
        .vbi_fops.write = av7110_vbi_write,
index 4182121d7e5dcd848ce40d67dc279ffaa076473f..855fe74b640bc85d3c5b1ab69936d8f3b3be0a36 100644 (file)
@@ -1404,6 +1404,41 @@ static int budget_av_detach(struct saa7146_dev *dev)
        return err;
 }
 
+#define KNC1_INPUTS 2
+static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
+       {0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
+       {1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
+};
+
+static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+       dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
+       if (i->index < 0 || i->index >= KNC1_INPUTS)
+               return -EINVAL;
+       memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
+       return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;
+
+       *i = budget_av->cur_input;
+
+       dprintk(1, "VIDIOC_G_INPUT %d.\n", *i);
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;
+
+       dprintk(1, "VIDIOC_S_INPUT %d.\n", input);
+       return saa7113_setinput(budget_av, input);
+}
+
 static struct saa7146_ext_vv vv_data;
 
 static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
@@ -1442,6 +1477,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
                        ERR(("cannot init vv subsystem.\n"));
                        return err;
                }
+               vv_data.ops.vidioc_enum_input = vidioc_enum_input;
+               vv_data.ops.vidioc_g_input = vidioc_g_input;
+               vv_data.ops.vidioc_s_input = vidioc_s_input;
 
                if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
                        /* fixme: proper cleanup here */
@@ -1480,54 +1518,6 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
        return 0;
 }
 
-#define KNC1_INPUTS 2
-static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
-       {0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
-       {1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
-};
-
-static struct saa7146_extension_ioctls ioctls[] = {
-       {VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE},
-       {VIDIOC_G_INPUT, SAA7146_EXCLUSIVE},
-       {VIDIOC_S_INPUT, SAA7146_EXCLUSIVE},
-       {0, 0}
-};
-
-static long av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
-{
-       struct saa7146_dev *dev = fh->dev;
-       struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
-
-       switch (cmd) {
-       case VIDIOC_ENUMINPUT:{
-               struct v4l2_input *i = arg;
-
-               dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
-               if (i->index < 0 || i->index >= KNC1_INPUTS) {
-                       return -EINVAL;
-               }
-               memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
-               return 0;
-       }
-       case VIDIOC_G_INPUT:{
-               int *input = (int *) arg;
-
-               *input = budget_av->cur_input;
-
-               dprintk(1, "VIDIOC_G_INPUT %d.\n", *input);
-               return 0;
-       }
-       case VIDIOC_S_INPUT:{
-               int input = *(int *) arg;
-               dprintk(1, "VIDIOC_S_INPUT %d.\n", input);
-               return saa7113_setinput(budget_av, input);
-       }
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
 static struct saa7146_standard standard[] = {
        {.name = "PAL",.id = V4L2_STD_PAL,
         .v_offset = 0x17,.v_field = 288,
@@ -1546,8 +1536,6 @@ static struct saa7146_ext_vv vv_data = {
        .flags = 0,
        .stds = &standard[0],
        .num_stds = ARRAY_SIZE(standard),
-       .ioctls = &ioctls[0],
-       .ioctl = av_ioctl,
 };
 
 static struct saa7146_extension budget_extension;
index bcbc5d41a0feb0d8a907672786dc043cad5c9320..371a716168106e0698e299504594fe62c242198a 100644 (file)
@@ -1076,6 +1076,10 @@ static struct tda10023_config tda10023_config = {
        .deltaf = 0xa511,
 };
 
+static struct tda827x_config tda827x_config = {
+       .config = 0,
+};
+
 /* TT S2-3200 DVB-S (STB0899) Inittab */
 static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = {
 
@@ -1414,7 +1418,7 @@ static void frontend_init(struct budget_ci *budget_ci)
        case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */
                budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48);
                if (budget_ci->budget.dvb_frontend) {
-                       if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, NULL) == NULL) {
+                       if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, &tda827x_config) == NULL) {
                                printk(KERN_ERR "%s: No tda827x found!\n", __func__);
                                dvb_frontend_detach(budget_ci->budget.dvb_frontend);
                                budget_ci->budget.dvb_frontend = NULL;
index 2014ebc4e984f12cb33f1c1a83f5c9e39b56abda..cc54ed4efc488fb49ad60102e1eb682e86b9ec35 100644 (file)
@@ -390,9 +390,11 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
 static int vidioc_querycap(struct file *file, void *priv,
                                        struct v4l2_capability *v)
 {
+       struct dsbr100_device *radio = video_drvdata(file);
+
        strlcpy(v->driver, "dsbr100", sizeof(v->driver));
        strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
-       sprintf(v->bus_info, "USB");
+       usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
        v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER;
        return 0;
@@ -450,7 +452,10 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        if (radio->removed)
                return -EIO;
 
+       mutex_lock(&radio->lock);
        radio->curfreq = f->frequency;
+       mutex_unlock(&radio->lock);
+
        retval = dsbr100_setfreq(radio, radio->curfreq);
        if (retval < 0)
                dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
@@ -601,7 +606,10 @@ static int usb_dsbr100_close(struct file *file)
        if (!radio)
                return -ENODEV;
 
+       mutex_lock(&radio->lock);
        radio->users = 0;
+       mutex_unlock(&radio->lock);
+
        if (!radio->removed) {
                retval = dsbr100_stop(radio);
                if (retval < 0) {
index bfa13b8b3043b33aeb3c0fdeaae3fe947b06b1f0..ac82e33cb6fcb89bf977d22b7f29bc590957c8d9 100644 (file)
 #include <linux/init.h>                /* Initdata                     */
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
-#include <asm/io.h>            /* outb, outb_p                 */
-#include <asm/uaccess.h>       /* copy to/from user            */
 #include <linux/videodev2.h>   /* kernel radio structs         */
-#include <media/v4l2-common.h>
+#include <linux/version.h>     /* for KERNEL_VERSION MACRO     */
+#include <linux/io.h>          /* outb, outb_p                 */
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 
-#include <linux/version.h>     /* for KERNEL_VERSION MACRO     */
-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+MODULE_AUTHOR("M.Kirkwood");
+MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card.");
+MODULE_LICENSE("GPL");
 
 #ifndef CONFIG_RADIO_RTRACK_PORT
 #define CONFIG_RADIO_RTRACK_PORT -1
 
 static int io = CONFIG_RADIO_RTRACK_PORT;
 static int radio_nr = -1;
-static struct mutex lock;
 
-struct rt_device
+module_param(io, int, 0);
+MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)");
+module_param(radio_nr, int, 0);
+
+#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
+
+struct rtrack
 {
-       unsigned long in_use;
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
        int port;
        int curvol;
        unsigned long curfreq;
        int muted;
+       int io;
+       struct mutex lock;
 };
 
+static struct rtrack rtrack_card;
 
 /* local things */
 
 static void sleep_delay(long n)
 {
        /* Sleep nicely for 'n' uS */
-       int d=n/msecs_to_jiffies(1000);
-       if(!d)
+       int d = n / msecs_to_jiffies(1000);
+       if (!d)
                udelay(n);
        else
                msleep(jiffies_to_msecs(d));
 }
 
-static void rt_decvol(void)
+static void rt_decvol(struct rtrack *rt)
 {
-       outb(0x58, io);         /* volume down + sigstr + on    */
+       outb(0x58, rt->io);             /* volume down + sigstr + on    */
        sleep_delay(100000);
-       outb(0xd8, io);         /* volume steady + sigstr + on  */
+       outb(0xd8, rt->io);             /* volume steady + sigstr + on  */
 }
 
-static void rt_incvol(void)
+static void rt_incvol(struct rtrack *rt)
 {
-       outb(0x98, io);         /* volume up + sigstr + on      */
+       outb(0x98, rt->io);             /* volume up + sigstr + on      */
        sleep_delay(100000);
-       outb(0xd8, io);         /* volume steady + sigstr + on  */
+       outb(0xd8, rt->io);             /* volume steady + sigstr + on  */
 }
 
-static void rt_mute(struct rt_device *dev)
+static void rt_mute(struct rtrack *rt)
 {
-       dev->muted = 1;
-       mutex_lock(&lock);
-       outb(0xd0, io);                 /* volume steady, off           */
-       mutex_unlock(&lock);
+       rt->muted = 1;
+       mutex_lock(&rt->lock);
+       outb(0xd0, rt->io);             /* volume steady, off           */
+       mutex_unlock(&rt->lock);
 }
 
-static int rt_setvol(struct rt_device *dev, int vol)
+static int rt_setvol(struct rtrack *rt, int vol)
 {
        int i;
 
-       mutex_lock(&lock);
+       mutex_lock(&rt->lock);
 
-       if(vol == dev->curvol) {        /* requested volume = current */
-               if (dev->muted) {       /* user is unmuting the card  */
-                       dev->muted = 0;
-                       outb (0xd8, io);        /* enable card */
+       if (vol == rt->curvol) {        /* requested volume = current */
+               if (rt->muted) {        /* user is unmuting the card  */
+                       rt->muted = 0;
+                       outb(0xd8, rt->io);     /* enable card */
                }
-               mutex_unlock(&lock);
+               mutex_unlock(&rt->lock);
                return 0;
        }
 
-       if(vol == 0) {                  /* volume = 0 means mute the card */
-               outb(0x48, io);         /* volume down but still "on"   */
+       if (vol == 0) {                 /* volume = 0 means mute the card */
+               outb(0x48, rt->io);     /* volume down but still "on"   */
                sleep_delay(2000000);   /* make sure it's totally down  */
-               outb(0xd0, io);         /* volume steady, off           */
-               dev->curvol = 0;        /* track the volume state!      */
-               mutex_unlock(&lock);
+               outb(0xd0, rt->io);     /* volume steady, off           */
+               rt->curvol = 0;         /* track the volume state!      */
+               mutex_unlock(&rt->lock);
                return 0;
        }
 
-       dev->muted = 0;
-       if(vol > dev->curvol)
-               for(i = dev->curvol; i < vol; i++)
-                       rt_incvol();
+       rt->muted = 0;
+       if (vol > rt->curvol)
+               for (i = rt->curvol; i < vol; i++)
+                       rt_incvol(rt);
        else
-               for(i = dev->curvol; i > vol; i--)
-                       rt_decvol();
+               for (i = rt->curvol; i > vol; i--)
+                       rt_decvol(rt);
 
-       dev->curvol = vol;
-       mutex_unlock(&lock);
+       rt->curvol = vol;
+       mutex_unlock(&rt->lock);
        return 0;
 }
 
@@ -135,155 +145,137 @@ static int rt_setvol(struct rt_device *dev, int vol)
  * and bit 4 (+16) is to keep the signal strength meter enabled
  */
 
-static void send_0_byte(int port, struct rt_device *dev)
+static void send_0_byte(struct rtrack *rt)
 {
-       if ((dev->curvol == 0) || (dev->muted)) {
-               outb_p(128+64+16+  1, port);   /* wr-enable + data low */
-               outb_p(128+64+16+2+1, port);   /* clock */
+       if (rt->curvol == 0 || rt->muted) {
+               outb_p(128+64+16+  1, rt->io);   /* wr-enable + data low */
+               outb_p(128+64+16+2+1, rt->io);   /* clock */
        }
        else {
-               outb_p(128+64+16+8+  1, port);  /* on + wr-enable + data low */
-               outb_p(128+64+16+8+2+1, port);  /* clock */
+               outb_p(128+64+16+8+  1, rt->io);  /* on + wr-enable + data low */
+               outb_p(128+64+16+8+2+1, rt->io);  /* clock */
        }
        sleep_delay(1000);
 }
 
-static void send_1_byte(int port, struct rt_device *dev)
+static void send_1_byte(struct rtrack *rt)
 {
-       if ((dev->curvol == 0) || (dev->muted)) {
-               outb_p(128+64+16+4  +1, port);   /* wr-enable+data high */
-               outb_p(128+64+16+4+2+1, port);   /* clock */
+       if (rt->curvol == 0 || rt->muted) {
+               outb_p(128+64+16+4  +1, rt->io);   /* wr-enable+data high */
+               outb_p(128+64+16+4+2+1, rt->io);   /* clock */
        }
        else {
-               outb_p(128+64+16+8+4  +1, port); /* on+wr-enable+data high */
-               outb_p(128+64+16+8+4+2+1, port); /* clock */
+               outb_p(128+64+16+8+4  +1, rt->io); /* on+wr-enable+data high */
+               outb_p(128+64+16+8+4+2+1, rt->io); /* clock */
        }
 
        sleep_delay(1000);
 }
 
-static int rt_setfreq(struct rt_device *dev, unsigned long freq)
+static int rt_setfreq(struct rtrack *rt, unsigned long freq)
 {
        int i;
 
-       /* adapted from radio-aztech.c */
+       mutex_lock(&rt->lock);                  /* Stop other ops interfering */
+
+       rt->curfreq = freq;
 
        /* now uses VIDEO_TUNER_LOW for fine tuning */
 
        freq += 171200;                 /* Add 10.7 MHz IF              */
        freq /= 800;                    /* Convert to 50 kHz units      */
 
-       mutex_lock(&lock);                      /* Stop other ops interfering */
-
-       send_0_byte (io, dev);          /*  0: LSB of frequency         */
+       send_0_byte(rt);                /*  0: LSB of frequency         */
 
        for (i = 0; i < 13; i++)        /*   : frequency bits (1-13)    */
                if (freq & (1 << i))
-                       send_1_byte (io, dev);
+                       send_1_byte(rt);
                else
-                       send_0_byte (io, dev);
+                       send_0_byte(rt);
 
-       send_0_byte (io, dev);          /* 14: test bit - always 0    */
-       send_0_byte (io, dev);          /* 15: test bit - always 0    */
+       send_0_byte(rt);                /* 14: test bit - always 0    */
+       send_0_byte(rt);                /* 15: test bit - always 0    */
 
-       send_0_byte (io, dev);          /* 16: band data 0 - always 0 */
-       send_0_byte (io, dev);          /* 17: band data 1 - always 0 */
-       send_0_byte (io, dev);          /* 18: band data 2 - always 0 */
-       send_0_byte (io, dev);          /* 19: time base - always 0   */
+       send_0_byte(rt);                /* 16: band data 0 - always 0 */
+       send_0_byte(rt);                /* 17: band data 1 - always 0 */
+       send_0_byte(rt);                /* 18: band data 2 - always 0 */
+       send_0_byte(rt);                /* 19: time base - always 0   */
 
-       send_0_byte (io, dev);          /* 20: spacing (0 = 25 kHz)   */
-       send_1_byte (io, dev);          /* 21: spacing (1 = 25 kHz)   */
-       send_0_byte (io, dev);          /* 22: spacing (0 = 25 kHz)   */
-       send_1_byte (io, dev);          /* 23: AM/FM (FM = 1, always) */
+       send_0_byte(rt);                /* 20: spacing (0 = 25 kHz)   */
+       send_1_byte(rt);                /* 21: spacing (1 = 25 kHz)   */
+       send_0_byte(rt);                /* 22: spacing (0 = 25 kHz)   */
+       send_1_byte(rt);                /* 23: AM/FM (FM = 1, always) */
 
-       if ((dev->curvol == 0) || (dev->muted))
-               outb (0xd0, io);        /* volume steady + sigstr */
+       if (rt->curvol == 0 || rt->muted)
+               outb(0xd0, rt->io);     /* volume steady + sigstr */
        else
-               outb (0xd8, io);        /* volume steady + sigstr + on */
+               outb(0xd8, rt->io);     /* volume steady + sigstr + on */
 
-       mutex_unlock(&lock);
+       mutex_unlock(&rt->lock);
 
        return 0;
 }
 
-static int rt_getsigstr(struct rt_device *dev)
+static int rt_getsigstr(struct rtrack *rt)
 {
-       if (inb(io) & 2)        /* bit set = no signal present  */
-               return 0;
-       return 1;               /* signal present               */
-}
+       int sig = 1;
 
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_AUDIO_VOLUME,
-               .name          = "Volume",
-               .minimum       = 0,
-               .maximum       = 0xff,
-               .step          = 1,
-               .default_value = 0xff,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       }
-};
+       mutex_lock(&rt->lock);
+       if (inb(rt->io) & 2)    /* bit set = no signal present  */
+               sig = 0;
+       mutex_unlock(&rt->lock);
+       return sig;
+}
 
 static int vidioc_querycap(struct file *file, void  *priv,
                                        struct v4l2_capability *v)
 {
        strlcpy(v->driver, "radio-aimslab", sizeof(v->driver));
        strlcpy(v->card, "RadioTrack", sizeof(v->card));
-       sprintf(v->bus_info, "ISA");
+       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
        v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER;
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
 
 static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       struct rt_device *rt = video_drvdata(file);
+       struct rtrack *rt = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
 
-       strcpy(v->name, "FM");
+       strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
-       v->rangelow = (87*16000);
-       v->rangehigh = (108*16000);
+       v->rangelow = 87 * 16000;
+       v->rangehigh = 108 * 16000;
        v->rxsubchans = V4L2_TUNER_SUB_MONO;
        v->capability = V4L2_TUNER_CAP_LOW;
        v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = 0xffff*rt_getsigstr(rt);
+       v->signal = 0xffff * rt_getsigstr(rt);
        return 0;
 }
 
 static int vidioc_s_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       if (v->index > 0)
-               return -EINVAL;
-       return 0;
+       return v->index ? -EINVAL : 0;
 }
 
 static int vidioc_s_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct rt_device *rt = video_drvdata(file);
+       struct rtrack *rt = video_drvdata(file);
 
-       rt->curfreq = f->frequency;
-       rt_setfreq(rt, rt->curfreq);
+       rt_setfreq(rt, f->frequency);
        return 0;
 }
 
 static int vidioc_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct rt_device *rt = video_drvdata(file);
+       struct rtrack *rt = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = rt->curfreq;
@@ -293,14 +285,11 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 static int vidioc_queryctrl(struct file *file, void *priv,
                                        struct v4l2_queryctrl *qc)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]),
-                                               sizeof(*qc));
-                       return 0;
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+       case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff);
        }
        return -EINVAL;
 }
@@ -308,14 +297,14 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct rt_device *rt = video_drvdata(file);
+       struct rtrack *rt = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
                ctrl->value = rt->muted;
                return 0;
        case V4L2_CID_AUDIO_VOLUME:
-               ctrl->value = rt->curvol * 6554;
+               ctrl->value = rt->curvol;
                return 0;
        }
        return -EINVAL;
@@ -324,33 +313,22 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct rt_device *rt = video_drvdata(file);
+       struct rtrack *rt = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
                if (ctrl->value)
                        rt_mute(rt);
                else
-                       rt_setvol(rt,rt->curvol);
+                       rt_setvol(rt, rt->curvol);
                return 0;
        case V4L2_CID_AUDIO_VOLUME:
-               rt_setvol(rt,ctrl->value);
+               rt_setvol(rt, ctrl->value);
                return 0;
        }
        return -EINVAL;
 }
 
-static int vidioc_g_audio (struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       if (a->index > 1)
-               return -EINVAL;
-
-       strcpy(a->name, "Radio");
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 {
        *i = 0;
@@ -359,36 +337,38 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 
 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-       if (i != 0)
-               return -EINVAL;
-       return 0;
+       return i ? -EINVAL : 0;
 }
 
-static int vidioc_s_audio(struct file *file, void *priv,
+static int vidioc_g_audio(struct file *file, void *priv,
                                        struct v4l2_audio *a)
 {
-       if (a->index != 0)
-               return -EINVAL;
+       a->index = 0;
+       strlcpy(a->name, "Radio", sizeof(a->name));
+       a->capability = V4L2_AUDCAP_STEREO;
        return 0;
 }
 
-static struct rt_device rtrack_unit;
+static int vidioc_s_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       return a->index ? -EINVAL : 0;
+}
 
-static int rtrack_exclusive_open(struct file *file)
+static int rtrack_open(struct file *file)
 {
-       return test_and_set_bit(0, &rtrack_unit.in_use) ? -EBUSY : 0;
+       return 0;
 }
 
-static int rtrack_exclusive_release(struct file *file)
+static int rtrack_release(struct file *file)
 {
-       clear_bit(0, &rtrack_unit.in_use);
        return 0;
 }
 
 static const struct v4l2_file_operations rtrack_fops = {
        .owner          = THIS_MODULE,
-       .open           = rtrack_exclusive_open,
-       .release        = rtrack_exclusive_release,
+       .open           = rtrack_open,
+       .release        = rtrack_release,
        .ioctl          = video_ioctl2,
 };
 
@@ -407,64 +387,69 @@ static const struct v4l2_ioctl_ops rtrack_ioctl_ops = {
        .vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
-static struct video_device rtrack_radio = {
-       .name           = "RadioTrack radio",
-       .fops           = &rtrack_fops,
-       .ioctl_ops      = &rtrack_ioctl_ops,
-       .release        = video_device_release_empty,
-};
-
 static int __init rtrack_init(void)
 {
-       if(io==-1)
-       {
-               printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+       struct rtrack *rt = &rtrack_card;
+       struct v4l2_device *v4l2_dev = &rt->v4l2_dev;
+       int res;
+
+       strlcpy(v4l2_dev->name, "rtrack", sizeof(v4l2_dev->name));
+       rt->io = io;
+
+       if (rt->io == -1) {
+               v4l2_err(v4l2_dev, "you must set an I/O address with io=0x20f or 0x30f\n");
                return -EINVAL;
        }
 
-       if (!request_region(io, 2, "rtrack"))
-       {
-               printk(KERN_ERR "rtrack: port 0x%x already in use\n", io);
+       if (!request_region(rt->io, 2, "rtrack")) {
+               v4l2_err(v4l2_dev, "port 0x%x already in use\n", rt->io);
                return -EBUSY;
        }
 
-       video_set_drvdata(&rtrack_radio, &rtrack_unit);
+       res = v4l2_device_register(NULL, v4l2_dev);
+       if (res < 0) {
+               release_region(rt->io, 2);
+               v4l2_err(v4l2_dev, "could not register v4l2_device\n");
+               return res;
+       }
 
-       if (video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
-               release_region(io, 2);
+       strlcpy(rt->vdev.name, v4l2_dev->name, sizeof(rt->vdev.name));
+       rt->vdev.v4l2_dev = v4l2_dev;
+       rt->vdev.fops = &rtrack_fops;
+       rt->vdev.ioctl_ops = &rtrack_ioctl_ops;
+       rt->vdev.release = video_device_release_empty;
+       video_set_drvdata(&rt->vdev, rt);
+
+       if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+               v4l2_device_unregister(&rt->v4l2_dev);
+               release_region(rt->io, 2);
                return -EINVAL;
        }
-       printk(KERN_INFO "AIMSlab RadioTrack/RadioReveal card driver.\n");
+       v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n");
 
        /* Set up the I/O locking */
 
-       mutex_init(&lock);
+       mutex_init(&rt->lock);
 
        /* mute card - prevents noisy bootups */
 
        /* this ensures that the volume is all the way down  */
-       outb(0x48, io);         /* volume down but still "on"   */
+       outb(0x48, rt->io);             /* volume down but still "on"   */
        sleep_delay(2000000);   /* make sure it's totally down  */
-       outb(0xc0, io);         /* steady volume, mute card     */
-       rtrack_unit.curvol = 0;
+       outb(0xc0, rt->io);             /* steady volume, mute card     */
 
        return 0;
 }
 
-MODULE_AUTHOR("M.Kirkwood");
-MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card.");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)");
-module_param(radio_nr, int, 0);
-
-static void __exit cleanup_rtrack_module(void)
+static void __exit rtrack_exit(void)
 {
-       video_unregister_device(&rtrack_radio);
-       release_region(io,2);
+       struct rtrack *rt = &rtrack_card;
+
+       video_unregister_device(&rt->vdev);
+       v4l2_device_unregister(&rt->v4l2_dev);
+       release_region(rt->io, 2);
 }
 
 module_init(rtrack_init);
-module_exit(cleanup_rtrack_module);
+module_exit(rtrack_exit);
 
index 5604e881e96c26292badc92c08e8afbb4017bb9a..49299f7fd8341df92c7632faec4f17e5bbcfc5e6 100644 (file)
 #include <linux/init.h>                /* Initdata                     */
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
-#include <asm/io.h>            /* outb, outb_p                 */
-#include <asm/uaccess.h>       /* copy to/from user            */
 #include <linux/videodev2.h>   /* kernel radio structs         */
-#include <media/v4l2-common.h>
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#include <linux/io.h>          /* outb, outb_p                 */
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
-
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_AUDIO_VOLUME,
-               .name          = "Volume",
-               .minimum       = 0,
-               .maximum       = 0xff,
-               .step          = 1,
-               .default_value = 0xff,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       }
-};
+MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
+MODULE_DESCRIPTION("A driver for the Aztech radio card.");
+MODULE_LICENSE("GPL");
 
 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
 
@@ -66,55 +48,64 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 static int io = CONFIG_RADIO_AZTECH_PORT;
 static int radio_nr = -1;
 static int radio_wait_time = 1000;
-static struct mutex lock;
 
-struct az_device
+module_param(io, int, 0);
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)");
+
+#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
+
+struct aztech
 {
-       unsigned long in_use;
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       int io;
        int curvol;
        unsigned long curfreq;
        int stereo;
+       struct mutex lock;
 };
 
+static struct aztech aztech_card;
+
 static int volconvert(int level)
 {
-       level>>=14;             /* Map 16bits down to 2 bit */
-       level&=3;
+       level >>= 14;           /* Map 16bits down to 2 bit */
+       level &= 3;
 
        /* convert to card-friendly values */
-       switch (level)
-       {
-               case 0:
-                       return 0;
-               case 1:
-                       return 1;
-               case 2:
-                       return 4;
-               case 3:
-                       return 5;
+       switch (level) {
+       case 0:
+               return 0;
+       case 1:
+               return 1;
+       case 2:
+               return 4;
+       case 3:
+               return 5;
        }
        return 0;       /* Quieten gcc */
 }
 
-static void send_0_byte (struct az_device *dev)
+static void send_0_byte(struct aztech *az)
 {
        udelay(radio_wait_time);
-       outb_p(2+volconvert(dev->curvol), io);
-       outb_p(64+2+volconvert(dev->curvol), io);
+       outb_p(2 + volconvert(az->curvol), az->io);
+       outb_p(64 + 2 + volconvert(az->curvol), az->io);
 }
 
-static void send_1_byte (struct az_device *dev)
+static void send_1_byte(struct aztech *az)
 {
        udelay (radio_wait_time);
-       outb_p(128+2+volconvert(dev->curvol), io);
-       outb_p(128+64+2+volconvert(dev->curvol), io);
+       outb_p(128 + 2 + volconvert(az->curvol), az->io);
+       outb_p(128 + 64 + 2 + volconvert(az->curvol), az->io);
 }
 
-static int az_setvol(struct az_device *dev, int vol)
+static int az_setvol(struct aztech *az, int vol)
 {
-       mutex_lock(&lock);
-       outb (volconvert(vol), io);
-       mutex_unlock(&lock);
+       mutex_lock(&az->lock);
+       outb(volconvert(vol), az->io);
+       mutex_unlock(&az->lock);
        return 0;
 }
 
@@ -126,116 +117,110 @@ static int az_setvol(struct az_device *dev, int vol)
  *
  */
 
-static int az_getsigstr(struct az_device *dev)
+static int az_getsigstr(struct aztech *az)
 {
-       if (inb(io) & 2)        /* bit set = no signal present */
-               return 0;
-       return 1;               /* signal present */
+       int sig = 1;
+
+       mutex_lock(&az->lock);
+       if (inb(az->io) & 2)    /* bit set = no signal present */
+               sig = 0;
+       mutex_unlock(&az->lock);
+       return sig;
 }
 
-static int az_getstereo(struct az_device *dev)
+static int az_getstereo(struct aztech *az)
 {
-       if (inb(io) & 1)        /* bit set = mono */
-               return 0;
-       return 1;               /* stereo */
+       int stereo = 1;
+
+       mutex_lock(&az->lock);
+       if (inb(az->io) & 1)    /* bit set = mono */
+               stereo = 0;
+       mutex_unlock(&az->lock);
+       return stereo;
 }
 
-static int az_setfreq(struct az_device *dev, unsigned long frequency)
+static int az_setfreq(struct aztech *az, unsigned long frequency)
 {
        int  i;
 
+       mutex_lock(&az->lock);
+
+       az->curfreq = frequency;
        frequency += 171200;            /* Add 10.7 MHz IF              */
        frequency /= 800;               /* Convert to 50 kHz units      */
 
-       mutex_lock(&lock);
-
-       send_0_byte (dev);              /*  0: LSB of frequency       */
+       send_0_byte(az);                /*  0: LSB of frequency       */
 
        for (i = 0; i < 13; i++)        /*   : frequency bits (1-13)  */
                if (frequency & (1 << i))
-                       send_1_byte (dev);
+                       send_1_byte(az);
                else
-                       send_0_byte (dev);
+                       send_0_byte(az);
 
-       send_0_byte (dev);              /* 14: test bit - always 0    */
-       send_0_byte (dev);              /* 15: test bit - always 0    */
-       send_0_byte (dev);              /* 16: band data 0 - always 0 */
-       if (dev->stereo)                /* 17: stereo (1 to enable)   */
-               send_1_byte (dev);
+       send_0_byte(az);                /* 14: test bit - always 0    */
+       send_0_byte(az);                /* 15: test bit - always 0    */
+       send_0_byte(az);                /* 16: band data 0 - always 0 */
+       if (az->stereo)         /* 17: stereo (1 to enable)   */
+               send_1_byte(az);
        else
-               send_0_byte (dev);
+               send_0_byte(az);
 
-       send_1_byte (dev);              /* 18: band data 1 - unknown  */
-       send_0_byte (dev);              /* 19: time base - always 0   */
-       send_0_byte (dev);              /* 20: spacing (0 = 25 kHz)   */
-       send_1_byte (dev);              /* 21: spacing (1 = 25 kHz)   */
-       send_0_byte (dev);              /* 22: spacing (0 = 25 kHz)   */
-       send_1_byte (dev);              /* 23: AM/FM (FM = 1, always) */
+       send_1_byte(az);                /* 18: band data 1 - unknown  */
+       send_0_byte(az);                /* 19: time base - always 0   */
+       send_0_byte(az);                /* 20: spacing (0 = 25 kHz)   */
+       send_1_byte(az);                /* 21: spacing (1 = 25 kHz)   */
+       send_0_byte(az);                /* 22: spacing (0 = 25 kHz)   */
+       send_1_byte(az);                /* 23: AM/FM (FM = 1, always) */
 
        /* latch frequency */
 
-       udelay (radio_wait_time);
-       outb_p(128+64+volconvert(dev->curvol), io);
+       udelay(radio_wait_time);
+       outb_p(128 + 64 + volconvert(az->curvol), az->io);
 
-       mutex_unlock(&lock);
+       mutex_unlock(&az->lock);
 
        return 0;
 }
 
-static int vidioc_querycap (struct file *file, void  *priv,
+static int vidioc_querycap(struct file *file, void  *priv,
                                        struct v4l2_capability *v)
 {
-       strlcpy(v->driver, "radio-aztech", sizeof (v->driver));
-       strlcpy(v->card, "Aztech Radio", sizeof (v->card));
-       sprintf(v->bus_info,"ISA");
+       strlcpy(v->driver, "radio-aztech", sizeof(v->driver));
+       strlcpy(v->card, "Aztech Radio", sizeof(v->card));
+       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
        v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER;
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
 
-static int vidioc_g_tuner (struct file *file, void *priv,
+static int vidioc_g_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
-       struct az_device *az = video_drvdata(file);
+       struct aztech *az = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
 
-       strcpy(v->name, "FM");
+       strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
 
-       v->rangelow=(87*16000);
-       v->rangehigh=(108*16000);
-       v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
-       v->capability=V4L2_TUNER_CAP_LOW;
-       if(az_getstereo(az))
+       v->rangelow = 87 * 16000;
+       v->rangehigh = 108 * 16000;
+       v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+       v->capability = V4L2_TUNER_CAP_LOW;
+       if (az_getstereo(az))
                v->audmode = V4L2_TUNER_MODE_STEREO;
        else
                v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal=0xFFFF*az_getsigstr(az);
+       v->signal = 0xFFFF * az_getsigstr(az);
 
        return 0;
 }
 
-
-static int vidioc_s_tuner (struct file *file, void *priv,
+static int vidioc_s_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
-       if (v->index > 0)
-               return -EINVAL;
-
-       return 0;
-}
-
-static int vidioc_g_audio (struct file *file, void *priv,
-                          struct v4l2_audio *a)
-{
-       if (a->index > 1)
-               return -EINVAL;
-
-       strcpy(a->name, "Radio");
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
+       return v->index ? -EINVAL : 0;
 }
 
 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
@@ -246,113 +231,107 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 
 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-       if (i != 0)
-               return -EINVAL;
-       return 0;
+       return i ? -EINVAL : 0;
 }
 
-
-static int vidioc_s_audio (struct file *file, void *priv,
+static int vidioc_g_audio(struct file *file, void *priv,
                           struct v4l2_audio *a)
 {
-       if (a->index != 0)
-               return -EINVAL;
-
+       a->index = 0;
+       strlcpy(a->name, "Radio", sizeof(a->name));
+       a->capability = V4L2_AUDCAP_STEREO;
        return 0;
 }
 
-static int vidioc_s_frequency (struct file *file, void *priv,
+static int vidioc_s_audio(struct file *file, void *priv,
+                          struct v4l2_audio *a)
+{
+       return a->index ? -EINVAL : 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       struct az_device *az = video_drvdata(file);
+       struct aztech *az = video_drvdata(file);
 
-       az->curfreq = f->frequency;
-       az_setfreq(az, az->curfreq);
+       az_setfreq(az, f->frequency);
        return 0;
 }
 
-static int vidioc_g_frequency (struct file *file, void *priv,
+static int vidioc_g_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       struct az_device *az = video_drvdata(file);
+       struct aztech *az = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = az->curfreq;
-
        return 0;
 }
 
-static int vidioc_queryctrl (struct file *file, void *priv,
+static int vidioc_queryctrl(struct file *file, void *priv,
                            struct v4l2_queryctrl *qc)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]),
-                                               sizeof(*qc));
-                       return (0);
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+       case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff);
        }
        return -EINVAL;
 }
 
-static int vidioc_g_ctrl (struct file *file, void *priv,
+static int vidioc_g_ctrl(struct file *file, void *priv,
                            struct v4l2_control *ctrl)
 {
-       struct az_device *az = video_drvdata(file);
+       struct aztech *az = video_drvdata(file);
 
        switch (ctrl->id) {
-               case V4L2_CID_AUDIO_MUTE:
-                       if (az->curvol==0)
-                               ctrl->value=1;
-                       else
-                               ctrl->value=0;
-                       return (0);
-               case V4L2_CID_AUDIO_VOLUME:
-                       ctrl->value=az->curvol * 6554;
-                       return (0);
+       case V4L2_CID_AUDIO_MUTE:
+               if (az->curvol == 0)
+                       ctrl->value = 1;
+               else
+                       ctrl->value = 0;
+               return 0;
+       case V4L2_CID_AUDIO_VOLUME:
+               ctrl->value = az->curvol * 6554;
+               return 0;
        }
        return -EINVAL;
 }
 
-static int vidioc_s_ctrl (struct file *file, void *priv,
+static int vidioc_s_ctrl(struct file *file, void *priv,
                            struct v4l2_control *ctrl)
 {
-       struct az_device *az = video_drvdata(file);
+       struct aztech *az = video_drvdata(file);
 
        switch (ctrl->id) {
-               case V4L2_CID_AUDIO_MUTE:
-                       if (ctrl->value) {
-                               az_setvol(az,0);
-                       } else {
-                               az_setvol(az,az->curvol);
-                       }
-                       return (0);
-               case V4L2_CID_AUDIO_VOLUME:
-                       az_setvol(az,ctrl->value);
-                       return (0);
+       case V4L2_CID_AUDIO_MUTE:
+               if (ctrl->value)
+                       az_setvol(az, 0);
+               else
+                       az_setvol(az, az->curvol);
+               return 0;
+       case V4L2_CID_AUDIO_VOLUME:
+               az_setvol(az, ctrl->value);
+               return 0;
        }
        return -EINVAL;
 }
 
-static struct az_device aztech_unit;
-
-static int aztech_exclusive_open(struct file *file)
+static int aztech_open(struct file *file)
 {
-       return test_and_set_bit(0, &aztech_unit.in_use) ? -EBUSY : 0;
+       return 0;
 }
 
-static int aztech_exclusive_release(struct file *file)
+static int aztech_release(struct file *file)
 {
-       clear_bit(0, &aztech_unit.in_use);
        return 0;
 }
 
 static const struct v4l2_file_operations aztech_fops = {
        .owner          = THIS_MODULE,
-       .open           = aztech_exclusive_open,
-       .release        = aztech_exclusive_release,
+       .open           = aztech_open,
+       .release        = aztech_release,
        .ioctl          = video_ioctl2,
 };
 
@@ -371,57 +350,60 @@ static const struct v4l2_ioctl_ops aztech_ioctl_ops = {
        .vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
-static struct video_device aztech_radio = {
-       .name           = "Aztech radio",
-       .fops           = &aztech_fops,
-       .ioctl_ops      = &aztech_ioctl_ops,
-       .release        = video_device_release_empty,
-};
-
-module_param_named(debug,aztech_radio.debug, int, 0644);
-MODULE_PARM_DESC(debug,"activates debug info");
-
 static int __init aztech_init(void)
 {
-       if(io==-1)
-       {
-               printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+       struct aztech *az = &aztech_card;
+       struct v4l2_device *v4l2_dev = &az->v4l2_dev;
+       int res;
+
+       strlcpy(v4l2_dev->name, "aztech", sizeof(v4l2_dev->name));
+       az->io = io;
+
+       if (az->io == -1) {
+               v4l2_err(v4l2_dev, "you must set an I/O address with io=0x350 or 0x358\n");
                return -EINVAL;
        }
 
-       if (!request_region(io, 2, "aztech"))
-       {
-               printk(KERN_ERR "aztech: port 0x%x already in use\n", io);
+       if (!request_region(az->io, 2, "aztech")) {
+               v4l2_err(v4l2_dev, "port 0x%x already in use\n", az->io);
                return -EBUSY;
        }
 
-       mutex_init(&lock);
-       video_set_drvdata(&aztech_radio, &aztech_unit);
+       res = v4l2_device_register(NULL, v4l2_dev);
+       if (res < 0) {
+               release_region(az->io, 2);
+               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+               return res;
+       }
 
-       if (video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
-               release_region(io,2);
+       mutex_init(&az->lock);
+       strlcpy(az->vdev.name, v4l2_dev->name, sizeof(az->vdev.name));
+       az->vdev.v4l2_dev = v4l2_dev;
+       az->vdev.fops = &aztech_fops;
+       az->vdev.ioctl_ops = &aztech_ioctl_ops;
+       az->vdev.release = video_device_release_empty;
+       video_set_drvdata(&az->vdev, az);
+
+       if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+               v4l2_device_unregister(v4l2_dev);
+               release_region(az->io, 2);
                return -EINVAL;
        }
 
-       printk(KERN_INFO "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
+       v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
        /* mute card - prevents noisy bootups */
-       outb (0, io);
+       outb(0, az->io);
        return 0;
 }
 
-MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
-MODULE_DESCRIPTION("A driver for the Aztech radio card.");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-module_param(radio_nr, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)");
-
-static void __exit aztech_cleanup(void)
+static void __exit aztech_exit(void)
 {
-       video_unregister_device(&aztech_radio);
-       release_region(io,2);
+       struct aztech *az = &aztech_card;
+
+       video_unregister_device(&az->vdev);
+       v4l2_device_unregister(&az->v4l2_dev);
+       release_region(az->io, 2);
 }
 
 module_init(aztech_init);
-module_exit(aztech_cleanup);
+module_exit(aztech_exit);
index cb3075ac104c211c281af8c77660749735a8f7ad..d30fc0ce82c08f093dc48d13052994eaedafbc87 100644 (file)
 #include <linux/init.h>                /* Initdata                     */
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
-#include <asm/io.h>            /* outb, outb_p                 */
-#include <asm/uaccess.h>       /* copy to/from user            */
 #include <linux/videodev2.h>   /* V4L2 API defs                */
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
 #include <linux/param.h>
 #include <linux/pnp.h>
+#include <linux/io.h>          /* outb, outb_p                 */
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+
+MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
+MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card.");
+MODULE_LICENSE("GPL");
+
+static int io = -1;            /* default to isapnp activation */
+static int radio_nr = -1;
+
+module_param(io, int, 0);
+MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)");
+module_param(radio_nr, int, 0);
+
+#define CADET_VERSION KERNEL_VERSION(0, 3, 3)
 
 #define RDS_BUFFER 256
 #define RDS_RX_FLAG 1
 #define MBS_RX_FLAG 2
 
-#define CADET_VERSION KERNEL_VERSION(0,3,3)
-
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_AUDIO_VOLUME,
-               .name          = "Volume",
-               .minimum       = 0,
-               .maximum       = 0xff,
-               .step          = 1,
-               .default_value = 0xff,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       }
+struct cadet {
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       int io;
+       int users;
+       int curtuner;
+       int tunestat;
+       int sigstrength;
+       wait_queue_head_t read_queue;
+       struct timer_list readtimer;
+       __u8 rdsin, rdsout, rdsstat;
+       unsigned char rdsbuf[RDS_BUFFER];
+       struct mutex lock;
+       int reading;
 };
 
-static int io=-1;              /* default to isapnp activation */
-static int radio_nr = -1;
-static int users;
-static int curtuner;
-static int tunestat;
-static int sigstrength;
-static wait_queue_head_t read_queue;
-static struct timer_list readtimer;
-static __u8 rdsin, rdsout, rdsstat;
-static unsigned char rdsbuf[RDS_BUFFER];
-static spinlock_t cadet_io_lock;
-
-static int cadet_probe(void);
+static struct cadet cadet_card;
 
 /*
  * Signal Strength Threshold Values
  * The V4L API spec does not define any particular unit for the signal
  * strength value.  These values are in microvolts of RF at the tuner's input.
  */
-static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
+static __u16 sigtable[2][4] = {
+       {  5, 10, 30,  150 },
+       { 28, 40, 63, 1000 }
+};
 
 
-static int
-cadet_getstereo(void)
+static int cadet_getstereo(struct cadet *dev)
 {
        int ret = V4L2_TUNER_SUB_MONO;
-       if(curtuner != 0)       /* Only FM has stereo capability! */
+
+       if (dev->curtuner != 0) /* Only FM has stereo capability! */
                return V4L2_TUNER_SUB_MONO;
 
-       spin_lock(&cadet_io_lock);
-       outb(7,io);          /* Select tuner control */
-       if( (inb(io+1) & 0x40) == 0)
+       mutex_lock(&dev->lock);
+       outb(7, dev->io);          /* Select tuner control */
+       if ((inb(dev->io + 1) & 0x40) == 0)
                ret = V4L2_TUNER_SUB_STEREO;
-       spin_unlock(&cadet_io_lock);
+       mutex_unlock(&dev->lock);
        return ret;
 }
 
-static unsigned
-cadet_gettune(void)
+static unsigned cadet_gettune(struct cadet *dev)
 {
-       int curvol,i;
-       unsigned fifo=0;
+       int curvol, i;
+       unsigned fifo = 0;
 
        /*
         * Prepare for read
         */
 
-       spin_lock(&cadet_io_lock);
+       mutex_lock(&dev->lock);
 
-       outb(7,io);       /* Select tuner control */
-       curvol=inb(io+1); /* Save current volume/mute setting */
-       outb(0x00,io+1);  /* Ensure WRITE-ENABLE is LOW */
-       tunestat=0xffff;
+       outb(7, dev->io);       /* Select tuner control */
+       curvol = inb(dev->io + 1); /* Save current volume/mute setting */
+       outb(0x00, dev->io + 1);  /* Ensure WRITE-ENABLE is LOW */
+       dev->tunestat = 0xffff;
 
        /*
         * Read the shift register
         */
-       for(i=0;i<25;i++) {
-               fifo=(fifo<<1)|((inb(io+1)>>7)&0x01);
-               if(i<24) {
-                       outb(0x01,io+1);
-                       tunestat&=inb(io+1);
-                       outb(0x00,io+1);
+       for (i = 0; i < 25; i++) {
+               fifo = (fifo << 1) | ((inb(dev->io + 1) >> 7) & 0x01);
+               if (i < 24) {
+                       outb(0x01, dev->io + 1);
+                       dev->tunestat &= inb(dev->io + 1);
+                       outb(0x00, dev->io + 1);
                }
        }
 
        /*
         * Restore volume/mute setting
         */
-       outb(curvol,io+1);
-       spin_unlock(&cadet_io_lock);
+       outb(curvol, dev->io + 1);
+       mutex_unlock(&dev->lock);
 
        return fifo;
 }
 
-static unsigned
-cadet_getfreq(void)
+static unsigned cadet_getfreq(struct cadet *dev)
 {
        int i;
-       unsigned freq=0,test,fifo=0;
+       unsigned freq = 0, test, fifo = 0;
 
        /*
         * Read current tuning
         */
-       fifo=cadet_gettune();
+       fifo = cadet_gettune(dev);
 
        /*
         * Convert to actual frequency
         */
-       if(curtuner==0) {    /* FM */
-               test=12500;
-               for(i=0;i<14;i++) {
-                       if((fifo&0x01)!=0) {
-                               freq+=test;
-                       }
-                       test=test<<1;
-                       fifo=fifo>>1;
+       if (dev->curtuner == 0) {    /* FM */
+               test = 12500;
+               for (i = 0; i < 14; i++) {
+                       if ((fifo & 0x01) != 0)
+                               freq += test;
+                       test = test << 1;
+                       fifo = fifo >> 1;
                }
-               freq-=10700000;           /* IF frequency is 10.7 MHz */
-               freq=(freq*16)/1000000;   /* Make it 1/16 MHz */
-       }
-       if(curtuner==1) {    /* AM */
-               freq=((fifo&0x7fff)-2010)*16;
+               freq -= 10700000;           /* IF frequency is 10.7 MHz */
+               freq = (freq * 16) / 1000000;   /* Make it 1/16 MHz */
        }
+       if (dev->curtuner == 1)    /* AM */
+               freq = ((fifo & 0x7fff) - 2010) * 16;
 
        return freq;
 }
 
-static void
-cadet_settune(unsigned fifo)
+static void cadet_settune(struct cadet *dev, unsigned fifo)
 {
        int i;
        unsigned test;
 
-       spin_lock(&cadet_io_lock);
+       mutex_lock(&dev->lock);
 
-       outb(7,io);                /* Select tuner control */
+       outb(7, dev->io);                /* Select tuner control */
        /*
         * Write the shift register
         */
-       test=0;
-       test=(fifo>>23)&0x02;      /* Align data for SDO */
-       test|=0x1c;                /* SDM=1, SWE=1, SEN=1, SCK=0 */
-       outb(7,io);                /* Select tuner control */
-       outb(test,io+1);           /* Initialize for write */
-       for(i=0;i<25;i++) {
-               test|=0x01;              /* Toggle SCK High */
-               outb(test,io+1);
-               test&=0xfe;              /* Toggle SCK Low */
-               outb(test,io+1);
-               fifo=fifo<<1;            /* Prepare the next bit */
-               test=0x1c|((fifo>>23)&0x02);
-               outb(test,io+1);
+       test = 0;
+       test = (fifo >> 23) & 0x02;      /* Align data for SDO */
+       test |= 0x1c;                /* SDM=1, SWE=1, SEN=1, SCK=0 */
+       outb(7, dev->io);                /* Select tuner control */
+       outb(test, dev->io + 1);           /* Initialize for write */
+       for (i = 0; i < 25; i++) {
+               test |= 0x01;              /* Toggle SCK High */
+               outb(test, dev->io + 1);
+               test &= 0xfe;              /* Toggle SCK Low */
+               outb(test, dev->io + 1);
+               fifo = fifo << 1;            /* Prepare the next bit */
+               test = 0x1c | ((fifo >> 23) & 0x02);
+               outb(test, dev->io + 1);
        }
-       spin_unlock(&cadet_io_lock);
+       mutex_unlock(&dev->lock);
 }
 
-static void
-cadet_setfreq(unsigned freq)
+static void cadet_setfreq(struct cadet *dev, unsigned freq)
 {
        unsigned fifo;
-       int i,j,test;
+       int i, j, test;
        int curvol;
 
        /*
         * Formulate a fifo command
         */
-       fifo=0;
-       if(curtuner==0) {    /* FM */
-               test=102400;
-               freq=(freq*1000)/16;       /* Make it kHz */
-               freq+=10700;               /* IF is 10700 kHz */
-               for(i=0;i<14;i++) {
-                       fifo=fifo<<1;
-                       if(freq>=test) {
-                               fifo|=0x01;
-                               freq-=test;
+       fifo = 0;
+       if (dev->curtuner == 0) {    /* FM */
+               test = 102400;
+               freq = (freq * 1000) / 16;       /* Make it kHz */
+               freq += 10700;               /* IF is 10700 kHz */
+               for (i = 0; i < 14; i++) {
+                       fifo = fifo << 1;
+                       if (freq >= test) {
+                               fifo |= 0x01;
+                               freq -= test;
                        }
-                       test=test>>1;
+                       test = test >> 1;
                }
        }
-       if(curtuner==1) {    /* AM */
-               fifo=(freq/16)+2010;            /* Make it kHz */
-               fifo|=0x100000;            /* Select AM Band */
+       if (dev->curtuner == 1) {    /* AM */
+               fifo = (freq / 16) + 2010;            /* Make it kHz */
+               fifo |= 0x100000;            /* Select AM Band */
        }
 
        /*
         * Save current volume/mute setting
         */
 
-       spin_lock(&cadet_io_lock);
-       outb(7,io);                /* Select tuner control */
-       curvol=inb(io+1);
-       spin_unlock(&cadet_io_lock);
+       mutex_lock(&dev->lock);
+       outb(7, dev->io);                /* Select tuner control */
+       curvol = inb(dev->io + 1);
+       mutex_unlock(&dev->lock);
 
        /*
         * Tune the card
         */
-       for(j=3;j>-1;j--) {
-               cadet_settune(fifo|(j<<16));
+       for (j = 3; j > -1; j--) {
+               cadet_settune(dev, fifo | (j << 16));
 
-               spin_lock(&cadet_io_lock);
-               outb(7,io);         /* Select tuner control */
-               outb(curvol,io+1);
-               spin_unlock(&cadet_io_lock);
+               mutex_lock(&dev->lock);
+               outb(7, dev->io);         /* Select tuner control */
+               outb(curvol, dev->io + 1);
+               mutex_unlock(&dev->lock);
 
                msleep(100);
 
-               cadet_gettune();
-               if((tunestat & 0x40) == 0) {   /* Tuned */
-                       sigstrength=sigtable[curtuner][j];
+               cadet_gettune(dev);
+               if ((dev->tunestat & 0x40) == 0) {   /* Tuned */
+                       dev->sigstrength = sigtable[dev->curtuner][j];
                        return;
                }
        }
-       sigstrength=0;
+       dev->sigstrength = 0;
 }
 
 
-static int
-cadet_getvol(void)
+static int cadet_getvol(struct cadet *dev)
 {
        int ret = 0;
 
-       spin_lock(&cadet_io_lock);
+       mutex_lock(&dev->lock);
 
-       outb(7,io);                /* Select tuner control */
-       if((inb(io + 1) & 0x20) != 0)
+       outb(7, dev->io);                /* Select tuner control */
+       if ((inb(dev->io + 1) & 0x20) != 0)
                ret = 0xffff;
 
-       spin_unlock(&cadet_io_lock);
+       mutex_unlock(&dev->lock);
        return ret;
 }
 
 
-static void
-cadet_setvol(int vol)
+static void cadet_setvol(struct cadet *dev, int vol)
 {
-       spin_lock(&cadet_io_lock);
-       outb(7,io);                /* Select tuner control */
-       if(vol>0)
-               outb(0x20,io+1);
+       mutex_lock(&dev->lock);
+       outb(7, dev->io);                /* Select tuner control */
+       if (vol > 0)
+               outb(0x20, dev->io + 1);
        else
-               outb(0x00,io+1);
-       spin_unlock(&cadet_io_lock);
+               outb(0x00, dev->io + 1);
+       mutex_unlock(&dev->lock);
 }
 
-static void
-cadet_handler(unsigned long data)
+static void cadet_handler(unsigned long data)
 {
-       /*
-        * Service the RDS fifo
-        */
+       struct cadet *dev = (void *)data;
 
-       if(spin_trylock(&cadet_io_lock))
-       {
-               outb(0x3,io);       /* Select RDS Decoder Control */
-               if((inb(io+1)&0x20)!=0) {
+       /* Service the RDS fifo */
+       if (mutex_trylock(&dev->lock)) {
+               outb(0x3, dev->io);       /* Select RDS Decoder Control */
+               if ((inb(dev->io + 1) & 0x20) != 0)
                        printk(KERN_CRIT "cadet: RDS fifo overflow\n");
-               }
-               outb(0x80,io);      /* Select RDS fifo */
-               while((inb(io)&0x80)!=0) {
-                       rdsbuf[rdsin]=inb(io+1);
-                       if(rdsin==rdsout)
+               outb(0x80, dev->io);      /* Select RDS fifo */
+               while ((inb(dev->io) & 0x80) != 0) {
+                       dev->rdsbuf[dev->rdsin] = inb(dev->io + 1);
+                       if (dev->rdsin == dev->rdsout)
                                printk(KERN_WARNING "cadet: RDS buffer overflow\n");
                        else
-                               rdsin++;
+                               dev->rdsin++;
                }
-               spin_unlock(&cadet_io_lock);
+               mutex_unlock(&dev->lock);
        }
 
        /*
         * Service pending read
         */
-       if( rdsin!=rdsout)
-               wake_up_interruptible(&read_queue);
+       if (dev->rdsin != dev->rdsout)
+               wake_up_interruptible(&dev->read_queue);
 
        /*
         * Clean up and exit
         */
-       init_timer(&readtimer);
-       readtimer.function=cadet_handler;
-       readtimer.data=(unsigned long)0;
-       readtimer.expires=jiffies+msecs_to_jiffies(50);
-       add_timer(&readtimer);
+       init_timer(&dev->readtimer);
+       dev->readtimer.function = cadet_handler;
+       dev->readtimer.data = (unsigned long)0;
+       dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
+       add_timer(&dev->readtimer);
 }
 
 
-
-static ssize_t
-cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+static ssize_t cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
-       int i=0;
+       struct cadet *dev = video_drvdata(file);
        unsigned char readbuf[RDS_BUFFER];
-
-       if(rdsstat==0) {
-               spin_lock(&cadet_io_lock);
-               rdsstat=1;
-               outb(0x80,io);        /* Select RDS fifo */
-               spin_unlock(&cadet_io_lock);
-               init_timer(&readtimer);
-               readtimer.function=cadet_handler;
-               readtimer.data=(unsigned long)0;
-               readtimer.expires=jiffies+msecs_to_jiffies(50);
-               add_timer(&readtimer);
+       int i = 0;
+
+       if (dev->rdsstat == 0) {
+               mutex_lock(&dev->lock);
+               dev->rdsstat = 1;
+               outb(0x80, dev->io);        /* Select RDS fifo */
+               mutex_unlock(&dev->lock);
+               init_timer(&dev->readtimer);
+               dev->readtimer.function = cadet_handler;
+               dev->readtimer.data = (unsigned long)dev;
+               dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
+               add_timer(&dev->readtimer);
        }
-       if(rdsin==rdsout) {
+       if (dev->rdsin == dev->rdsout) {
                if (file->f_flags & O_NONBLOCK)
                        return -EWOULDBLOCK;
-               interruptible_sleep_on(&read_queue);
+               interruptible_sleep_on(&dev->read_queue);
        }
-       while( i<count && rdsin!=rdsout)
-               readbuf[i++]=rdsbuf[rdsout++];
+       while (i < count && dev->rdsin != dev->rdsout)
+               readbuf[i++] = dev->rdsbuf[dev->rdsout++];
 
-       if (copy_to_user(data,readbuf,i))
+       if (copy_to_user(data, readbuf, i))
                return -EFAULT;
        return i;
 }
@@ -370,38 +355,40 @@ cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 static int vidioc_querycap(struct file *file, void *priv,
                                struct v4l2_capability *v)
 {
-       v->capabilities =
-               V4L2_CAP_TUNER |
-               V4L2_CAP_READWRITE;
+       strlcpy(v->driver, "ADS Cadet", sizeof(v->driver));
+       strlcpy(v->card, "ADS Cadet", sizeof(v->card));
+       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
        v->version = CADET_VERSION;
-       strcpy(v->driver, "ADS Cadet");
-       strcpy(v->card, "ADS Cadet");
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_READWRITE;
        return 0;
 }
 
 static int vidioc_g_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
+       struct cadet *dev = video_drvdata(file);
+
        v->type = V4L2_TUNER_RADIO;
        switch (v->index) {
        case 0:
-               strcpy(v->name, "FM");
+               strlcpy(v->name, "FM", sizeof(v->name));
                v->capability = V4L2_TUNER_CAP_STEREO;
                v->rangelow = 1400;     /* 87.5 MHz */
                v->rangehigh = 1728;    /* 108.0 MHz */
-               v->rxsubchans=cadet_getstereo();
-               switch (v->rxsubchans){
+               v->rxsubchans = cadet_getstereo(dev);
+               switch (v->rxsubchans) {
                case V4L2_TUNER_SUB_MONO:
                        v->audmode = V4L2_TUNER_MODE_MONO;
                        break;
                case V4L2_TUNER_SUB_STEREO:
                        v->audmode = V4L2_TUNER_MODE_STEREO;
                        break;
-               default: ;
+               default:
+                       break;
                }
                break;
        case 1:
-               strcpy(v->name, "AM");
+               strlcpy(v->name, "AM", sizeof(v->name));
                v->capability = V4L2_TUNER_CAP_LOW;
                v->rangelow = 8320;      /* 520 kHz */
                v->rangehigh = 26400;    /* 1650 kHz */
@@ -411,25 +398,29 @@ static int vidioc_g_tuner(struct file *file, void *priv,
        default:
                return -EINVAL;
        }
-       v->signal = sigstrength; /* We might need to modify scaling of this */
+       v->signal = dev->sigstrength; /* We might need to modify scaling of this */
        return 0;
 }
 
 static int vidioc_s_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
-       if((v->index != 0)&&(v->index != 1))
+       struct cadet *dev = video_drvdata(file);
+
+       if (v->index != 0 && v->index != 1)
                return -EINVAL;
-       curtuner = v->index;
+       dev->curtuner = v->index;
        return 0;
 }
 
 static int vidioc_g_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       f->tuner = curtuner;
+       struct cadet *dev = video_drvdata(file);
+
+       f->tuner = dev->curtuner;
        f->type = V4L2_TUNER_RADIO;
-       f->frequency = cadet_getfreq();
+       f->frequency = cadet_getfreq(dev);
        return 0;
 }
 
@@ -437,27 +428,26 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 static int vidioc_s_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
+       struct cadet *dev = video_drvdata(file);
+
        if (f->type != V4L2_TUNER_RADIO)
                return -EINVAL;
-       if((curtuner==0)&&((f->frequency<1400)||(f->frequency>1728)))
+       if (dev->curtuner == 0 && (f->frequency < 1400 || f->frequency > 1728))
                return -EINVAL;
-       if((curtuner==1)&&((f->frequency<8320)||(f->frequency>26400)))
+       if (dev->curtuner == 1 && (f->frequency < 8320 || f->frequency > 26400))
                return -EINVAL;
-       cadet_setfreq(f->frequency);
+       cadet_setfreq(dev, f->frequency);
        return 0;
 }
 
 static int vidioc_queryctrl(struct file *file, void *priv,
                                struct v4l2_queryctrl *qc)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]),
-                                               sizeof(*qc));
-                       return 0;
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+       case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff);
        }
        return -EINVAL;
 }
@@ -465,12 +455,14 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
-       switch (ctrl->id){
+       struct cadet *dev = video_drvdata(file);
+
+       switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */
-               ctrl->value = (cadet_getvol() == 0);
+               ctrl->value = (cadet_getvol(dev) == 0);
                break;
        case V4L2_CID_AUDIO_VOLUME:
-               ctrl->value = cadet_getvol();
+               ctrl->value = cadet_getvol(dev);
                break;
        default:
                return -EINVAL;
@@ -481,15 +473,17 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
+       struct cadet *dev = video_drvdata(file);
+
        switch (ctrl->id){
        case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */
                if (ctrl->value)
-                       cadet_setvol(0);
+                       cadet_setvol(dev, 0);
                else
-                       cadet_setvol(0xffff);
+                       cadet_setvol(dev, 0xffff);
                break;
        case V4L2_CID_AUDIO_VOLUME:
-               cadet_setvol(ctrl->value);
+               cadet_setvol(dev, ctrl->value);
                break;
        default:
                return -EINVAL;
@@ -497,16 +491,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_g_audio(struct file *file, void *priv,
-                               struct v4l2_audio *a)
-{
-       if (a->index > 1)
-               return -EINVAL;
-       strcpy(a->name, "Radio");
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 {
        *i = 0;
@@ -515,43 +499,52 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 
 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-       if (i != 0)
-               return -EINVAL;
+       return i ? -EINVAL : 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv,
+                               struct v4l2_audio *a)
+{
+       a->index = 0;
+       strlcpy(a->name, "Radio", sizeof(a->name));
+       a->capability = V4L2_AUDCAP_STEREO;
        return 0;
 }
 
 static int vidioc_s_audio(struct file *file, void *priv,
                                struct v4l2_audio *a)
 {
-       if (a->index != 0)
-               return -EINVAL;
-       return 0;
+       return a->index ? -EINVAL : 0;
 }
 
-static int
-cadet_open(struct file *file)
+static int cadet_open(struct file *file)
 {
-       users++;
-       if (1 == users) init_waitqueue_head(&read_queue);
+       struct cadet *dev = video_drvdata(file);
+
+       dev->users++;
+       if (1 == dev->users)
+               init_waitqueue_head(&dev->read_queue);
        return 0;
 }
 
-static int
-cadet_release(struct file *file)
+static int cadet_release(struct file *file)
 {
-       users--;
-       if (0 == users){
-               del_timer_sync(&readtimer);
-               rdsstat=0;
+       struct cadet *dev = video_drvdata(file);
+
+       dev->users--;
+       if (0 == dev->users) {
+               del_timer_sync(&dev->readtimer);
+               dev->rdsstat = 0;
        }
        return 0;
 }
 
-static unsigned int
-cadet_poll(struct file *file, struct poll_table_struct *wait)
+static unsigned int cadet_poll(struct file *file, struct poll_table_struct *wait)
 {
-       poll_wait(file,&read_queue,wait);
-       if(rdsin != rdsout)
+       struct cadet *dev = video_drvdata(file);
+
+       poll_wait(file, &dev->read_queue, wait);
+       if (dev->rdsin != dev->rdsout)
                return POLLIN | POLLRDNORM;
        return 0;
 }
@@ -581,13 +574,6 @@ static const struct v4l2_ioctl_ops cadet_ioctl_ops = {
        .vidioc_s_input     = vidioc_s_input,
 };
 
-static struct video_device cadet_radio = {
-       .name           = "Cadet radio",
-       .fops           = &cadet_fops,
-       .ioctl_ops      = &cadet_ioctl_ops,
-       .release        = video_device_release_empty,
-};
-
 #ifdef CONFIG_PNP
 
 static struct pnp_device_id cadet_pnp_devices[] = {
@@ -598,7 +584,7 @@ static struct pnp_device_id cadet_pnp_devices[] = {
 
 MODULE_DEVICE_TABLE(pnp, cadet_pnp_devices);
 
-static int cadet_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id)
+static int cadet_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
 {
        if (!dev)
                return -ENODEV;
@@ -606,13 +592,12 @@ static int cadet_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev
        if (io > 0)
                return -EBUSY;
 
-       if (!pnp_port_valid(dev, 0)) {
+       if (!pnp_port_valid(dev, 0))
                return -ENODEV;
-       }
 
        io = pnp_port_start(dev, 0);
 
-       printk ("radio-cadet: PnP reports device at %#x\n", io);
+       printk(KERN_INFO "radio-cadet: PnP reports device at %#x\n", io);
 
        return io;
 }
@@ -628,23 +613,23 @@ static struct pnp_driver cadet_pnp_driver = {
 static struct pnp_driver cadet_pnp_driver;
 #endif
 
-static int cadet_probe(void)
+static void cadet_probe(struct cadet *dev)
 {
-       static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
+       static int iovals[8] = { 0x330, 0x332, 0x334, 0x336, 0x338, 0x33a, 0x33c, 0x33e };
        int i;
 
-       for(i=0;i<8;i++) {
-               io=iovals[i];
-               if (request_region(io, 2, "cadet-probe")) {
-                       cadet_setfreq(1410);
-                       if(cadet_getfreq()==1410) {
-                               release_region(io, 2);
-                               return io;
+       for (i = 0; i < 8; i++) {
+               dev->io = iovals[i];
+               if (request_region(dev->io, 2, "cadet-probe")) {
+                       cadet_setfreq(dev, 1410);
+                       if (cadet_getfreq(dev) == 1410) {
+                               release_region(dev->io, 2);
+                               return;
                        }
-                       release_region(io, 2);
+                       release_region(dev->io, 2);
                }
        }
-       return -1;
+       dev->io = -1;
 }
 
 /*
@@ -654,59 +639,69 @@ static int cadet_probe(void)
 
 static int __init cadet_init(void)
 {
-       spin_lock_init(&cadet_io_lock);
+       struct cadet *dev = &cadet_card;
+       struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
+       int res;
 
-       /*
-        *      If a probe was requested then probe ISAPnP first (safest)
-        */
+       strlcpy(v4l2_dev->name, "cadet", sizeof(v4l2_dev->name));
+       mutex_init(&dev->lock);
+
+       /* If a probe was requested then probe ISAPnP first (safest) */
        if (io < 0)
                pnp_register_driver(&cadet_pnp_driver);
-       /*
-        *      If that fails then probe unsafely if probe is requested
-        */
-       if(io < 0)
-               io = cadet_probe ();
+       dev->io = io;
 
-       /*
-        *      Else we bail out
-        */
+       /* If that fails then probe unsafely if probe is requested */
+       if (dev->io < 0)
+               cadet_probe(dev);
 
-       if(io < 0) {
+       /* Else we bail out */
+       if (dev->io < 0) {
 #ifdef MODULE
-               printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+               v4l2_err(v4l2_dev, "you must set an I/O address with io=0x330, 0x332, 0x334,\n");
+               v4l2_err(v4l2_dev, "0x336, 0x338, 0x33a, 0x33c or 0x33e\n");
 #endif
                goto fail;
        }
-       if (!request_region(io,2,"cadet"))
+       if (!request_region(dev->io, 2, "cadet"))
+               goto fail;
+
+       res = v4l2_device_register(NULL, v4l2_dev);
+       if (res < 0) {
+               release_region(dev->io, 2);
+               v4l2_err(v4l2_dev, "could not register v4l2_device\n");
                goto fail;
-       if (video_register_device(&cadet_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
-               release_region(io,2);
+       }
+
+       strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
+       dev->vdev.v4l2_dev = v4l2_dev;
+       dev->vdev.fops = &cadet_fops;
+       dev->vdev.ioctl_ops = &cadet_ioctl_ops;
+       dev->vdev.release = video_device_release_empty;
+       video_set_drvdata(&dev->vdev, dev);
+
+       if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+               v4l2_device_unregister(v4l2_dev);
+               release_region(dev->io, 2);
                goto fail;
        }
-       printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io);
+       v4l2_info(v4l2_dev, "ADS Cadet Radio Card at 0x%x\n", dev->io);
        return 0;
 fail:
        pnp_unregister_driver(&cadet_pnp_driver);
-       return -1;
+       return -ENODEV;
 }
 
-
-
-MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
-MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card.");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)");
-module_param(radio_nr, int, 0);
-
-static void __exit cadet_cleanup_module(void)
+static void __exit cadet_exit(void)
 {
-       video_unregister_device(&cadet_radio);
-       release_region(io,2);
+       struct cadet *dev = &cadet_card;
+
+       video_unregister_device(&dev->vdev);
+       v4l2_device_unregister(&dev->v4l2_dev);
+       release_region(dev->io, 2);
        pnp_unregister_driver(&cadet_pnp_driver);
 }
 
 module_init(cadet_init);
-module_exit(cadet_cleanup_module);
+module_exit(cadet_exit);
 
index 0c96bf8525b056fbbb17d36c13ea2e1c267ff2c0..09265d25725e993c7fed2e64f0d4c2749b104c30 100644 (file)
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
 #include <linux/errno.h>
-
 #include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
-
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_AUDIO_VOLUME,
-               .name          = "Volume",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 65535,
-               .default_value = 0xff,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       }
-};
+#include <linux/io.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
 
-#include <asm/io.h>
-#include <asm/uaccess.h>
+MODULE_AUTHOR("Vladimir Shebordaev <vshebordaev@mail.ru>");
+MODULE_DESCRIPTION("The video4linux driver for the Gemtek PCI Radio Card");
+MODULE_LICENSE("GPL");
+
+static int nr_radio = -1;
+static int mx = 1;
+
+module_param(mx, bool, 0);
+MODULE_PARM_DESC(mx, "single digit: 1 - turn off the turner upon module exit (default), 0 - do not");
+module_param(nr_radio, int, 0);
+MODULE_PARM_DESC(nr_radio, "video4linux device number to use");
+
+#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
 
 #ifndef PCI_VENDOR_ID_GEMTEK
 #define PCI_VENDOR_ID_GEMTEK 0x5046
@@ -90,8 +81,11 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 #define GEMTEK_PCI_RANGE_HIGH (108*16000)
 #endif
 
-struct gemtek_pci_card {
-       struct video_device *videodev;
+struct gemtek_pci {
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       struct mutex lock;
+       struct pci_dev *pdev;
 
        u32 iobase;
        u32 length;
@@ -100,116 +94,133 @@ struct gemtek_pci_card {
        u8  mute;
 };
 
-static int nr_radio = -1;
-static unsigned long in_use;
+static inline struct gemtek_pci *to_gemtek_pci(struct v4l2_device *v4l2_dev)
+{
+       return container_of(v4l2_dev, struct gemtek_pci, v4l2_dev);
+}
 
-static inline u8 gemtek_pci_out( u16 value, u32 port )
+static inline u8 gemtek_pci_out(u16 value, u32 port)
 {
-       outw( value, port );
+       outw(value, port);
 
        return (u8)value;
 }
 
-#define _b0( v ) *((u8 *)&v)
-static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
+#define _b0(v) (*((u8 *)&v))
+
+static void __gemtek_pci_cmd(u16 value, u32 port, u8 *last_byte, int keep)
 {
-       register u8 byte = *last_byte;
+       u8 byte = *last_byte;
 
-       if ( !value ) {
-               if ( !keep )
+       if (!value) {
+               if (!keep)
                        value = (u16)port;
                byte &= 0xfd;
        } else
                byte |= 2;
 
-       _b0( value ) = byte;
-       outw( value, port );
+       _b0(value) = byte;
+       outw(value, port);
        byte |= 1;
-       _b0( value ) = byte;
-       outw( value, port );
+       _b0(value) = byte;
+       outw(value, port);
        byte &= 0xfe;
-       _b0( value ) = byte;
-       outw( value, port );
+       _b0(value) = byte;
+       outw(value, port);
 
        *last_byte = byte;
 }
 
-static inline void gemtek_pci_nil( u32 port, u8 *last_byte )
+static inline void gemtek_pci_nil(u32 port, u8 *last_byte)
 {
-       __gemtek_pci_cmd( 0x00, port, last_byte, false );
+       __gemtek_pci_cmd(0x00, port, last_byte, false);
 }
 
-static inline void gemtek_pci_cmd( u16 cmd, u32 port, u8 *last_byte )
+static inline void gemtek_pci_cmd(u16 cmd, u32 port, u8 *last_byte)
 {
-       __gemtek_pci_cmd( cmd, port, last_byte, true );
+       __gemtek_pci_cmd(cmd, port, last_byte, true);
 }
 
-static void gemtek_pci_setfrequency( struct gemtek_pci_card *card, unsigned long frequency )
+static void gemtek_pci_setfrequency(struct gemtek_pci *card, unsigned long frequency)
 {
-       register int i;
-       register u32 value = frequency / 200 + 856;
-       register u16 mask = 0x8000;
+       int i;
+       u32 value = frequency / 200 + 856;
+       u16 mask = 0x8000;
        u8 last_byte;
        u32 port = card->iobase;
 
-       last_byte = gemtek_pci_out( 0x06, port );
+       mutex_lock(&card->lock);
+       card->current_frequency = frequency;
+       last_byte = gemtek_pci_out(0x06, port);
 
        i = 0;
        do {
-               gemtek_pci_nil( port, &last_byte );
+               gemtek_pci_nil(port, &last_byte);
                i++;
-       } while ( i < 9 );
+       } while (i < 9);
 
        i = 0;
        do {
-               gemtek_pci_cmd( value & mask, port, &last_byte );
+               gemtek_pci_cmd(value & mask, port, &last_byte);
                mask >>= 1;
                i++;
-       } while ( i < 16 );
+       } while (i < 16);
 
-       outw( 0x10, port );
+       outw(0x10, port);
+       mutex_unlock(&card->lock);
 }
 
 
-static inline void gemtek_pci_mute( struct gemtek_pci_card *card )
+static void gemtek_pci_mute(struct gemtek_pci *card)
 {
-       outb( 0x1f, card->iobase );
+       mutex_lock(&card->lock);
+       outb(0x1f, card->iobase);
        card->mute = true;
+       mutex_unlock(&card->lock);
 }
 
-static inline void gemtek_pci_unmute( struct gemtek_pci_card *card )
+static void gemtek_pci_unmute(struct gemtek_pci *card)
 {
-       if ( card->mute ) {
-               gemtek_pci_setfrequency( card, card->current_frequency );
+       mutex_lock(&card->lock);
+       if (card->mute) {
+               gemtek_pci_setfrequency(card, card->current_frequency);
                card->mute = false;
        }
+       mutex_unlock(&card->lock);
 }
 
-static inline unsigned int gemtek_pci_getsignal( struct gemtek_pci_card *card )
+static int gemtek_pci_getsignal(struct gemtek_pci *card)
 {
-       return ( inb( card->iobase ) & 0x08 ) ? 0 : 1;
+       int sig;
+
+       mutex_lock(&card->lock);
+       sig = (inb(card->iobase) & 0x08) ? 0 : 1;
+       mutex_unlock(&card->lock);
+       return sig;
 }
 
 static int vidioc_querycap(struct file *file, void *priv,
                                        struct v4l2_capability *v)
 {
+       struct gemtek_pci *card = video_drvdata(file);
+
        strlcpy(v->driver, "radio-gemtek-pci", sizeof(v->driver));
        strlcpy(v->card, "GemTek PCI Radio", sizeof(v->card));
-       sprintf(v->bus_info, "ISA");
+       snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(card->pdev));
        v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER;
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
 
 static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       struct gemtek_pci_card *card = video_drvdata(file);
+       struct gemtek_pci *card = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
 
-       strcpy(v->name, "FM");
+       strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
        v->rangelow = GEMTEK_PCI_RANGE_LOW;
        v->rangehigh = GEMTEK_PCI_RANGE_HIGH;
@@ -223,21 +234,18 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 static int vidioc_s_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       if (v->index > 0)
-               return -EINVAL;
-       return 0;
+       return v->index ? -EINVAL : 0;
 }
 
 static int vidioc_s_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct gemtek_pci_card *card = video_drvdata(file);
+       struct gemtek_pci *card = video_drvdata(file);
 
-       if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) ||
-                       (f->frequency > GEMTEK_PCI_RANGE_HIGH) )
+       if (f->frequency < GEMTEK_PCI_RANGE_LOW ||
+           f->frequency > GEMTEK_PCI_RANGE_HIGH)
                return -EINVAL;
        gemtek_pci_setfrequency(card, f->frequency);
-       card->current_frequency = f->frequency;
        card->mute = false;
        return 0;
 }
@@ -245,7 +253,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 static int vidioc_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct gemtek_pci_card *card = video_drvdata(file);
+       struct gemtek_pci *card = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = card->current_frequency;
@@ -255,13 +263,11 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 static int vidioc_queryctrl(struct file *file, void *priv,
                                        struct v4l2_queryctrl *qc)
 {
-       int i;
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]),
-                                               sizeof(*qc));
-                       return 0;
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+       case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535);
        }
        return -EINVAL;
 }
@@ -269,7 +275,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct gemtek_pci_card *card = video_drvdata(file);
+       struct gemtek_pci *card = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -288,7 +294,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct gemtek_pci_card *card = video_drvdata(file);
+       struct gemtek_pci *card = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -307,17 +313,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        return -EINVAL;
 }
 
-static int vidioc_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       if (a->index > 1)
-               return -EINVAL;
-
-       strcpy(a->name, "Radio");
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 {
        *i = 0;
@@ -326,17 +321,22 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 
 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-       if (i != 0)
-               return -EINVAL;
+       return i ? -EINVAL : 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       a->index = 0;
+       strlcpy(a->name, "Radio", sizeof(a->name));
+       a->capability = V4L2_AUDCAP_STEREO;
        return 0;
 }
 
 static int vidioc_s_audio(struct file *file, void *priv,
                                        struct v4l2_audio *a)
 {
-       if (a->index != 0)
-               return -EINVAL;
-       return 0;
+       return a->index ? -EINVAL : 0;
 }
 
 enum {
@@ -354,25 +354,22 @@ static struct pci_device_id gemtek_pci_id[] =
        { 0 }
 };
 
-MODULE_DEVICE_TABLE( pci, gemtek_pci_id );
-
-static int mx = 1;
+MODULE_DEVICE_TABLE(pci, gemtek_pci_id);
 
-static int gemtek_pci_exclusive_open(struct file *file)
+static int gemtek_pci_open(struct file *file)
 {
-       return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
+       return 0;
 }
 
-static int gemtek_pci_exclusive_release(struct file *file)
+static int gemtek_pci_release(struct file *file)
 {
-       clear_bit(0, &in_use);
        return 0;
 }
 
 static const struct v4l2_file_operations gemtek_pci_fops = {
        .owner          = THIS_MODULE,
-       .open           = gemtek_pci_exclusive_open,
-       .release        = gemtek_pci_exclusive_release,
+       .open           = gemtek_pci_open,
+       .release        = gemtek_pci_release,
        .ioctl          = video_ioctl2,
 };
 
@@ -391,108 +388,100 @@ static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = {
        .vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
-static struct video_device vdev_template = {
-       .name           = "Gemtek PCI Radio",
-       .fops           = &gemtek_pci_fops,
-       .ioctl_ops      = &gemtek_pci_ioctl_ops,
-       .release        = video_device_release_empty,
-};
-
-static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id )
+static int __devinit gemtek_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
 {
-       struct gemtek_pci_card *card;
-       struct video_device *devradio;
+       struct gemtek_pci *card;
+       struct v4l2_device *v4l2_dev;
+       int res;
 
-       if ( (card = kzalloc( sizeof( struct gemtek_pci_card ), GFP_KERNEL )) == NULL ) {
-               printk( KERN_ERR "gemtek_pci: out of memory\n" );
+       card = kzalloc(sizeof(struct gemtek_pci), GFP_KERNEL);
+       if (card == NULL) {
+               dev_err(&pdev->dev, "out of memory\n");
                return -ENOMEM;
        }
 
-       if ( pci_enable_device( pci_dev ) )
-               goto err_pci;
+       v4l2_dev = &card->v4l2_dev;
+       mutex_init(&card->lock);
+       card->pdev = pdev;
 
-       card->iobase = pci_resource_start( pci_dev, 0 );
-       card->length = pci_resource_len( pci_dev, 0 );
+       strlcpy(v4l2_dev->name, "gemtek_pci", sizeof(v4l2_dev->name));
 
-       if ( request_region( card->iobase, card->length, card_names[pci_id->driver_data] ) == NULL ) {
-               printk( KERN_ERR "gemtek_pci: i/o port already in use\n" );
-               goto err_pci;
+       res = v4l2_device_register(&pdev->dev, v4l2_dev);
+       if (res < 0) {
+               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+               kfree(card);
+               return res;
        }
 
-       pci_set_drvdata( pci_dev, card );
+       if (pci_enable_device(pdev))
+               goto err_pci;
 
-       if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
-               printk( KERN_ERR "gemtek_pci: out of memory\n" );
-               goto err_video;
+       card->iobase = pci_resource_start(pdev, 0);
+       card->length = pci_resource_len(pdev, 0);
+
+       if (request_region(card->iobase, card->length, card_names[pci_id->driver_data]) == NULL) {
+               v4l2_err(v4l2_dev, "i/o port already in use\n");
+               goto err_pci;
        }
-       *devradio = vdev_template;
 
-       if (video_register_device(devradio, VFL_TYPE_RADIO, nr_radio) < 0) {
-               kfree( devradio );
+       strlcpy(card->vdev.name, v4l2_dev->name, sizeof(card->vdev.name));
+       card->vdev.v4l2_dev = v4l2_dev;
+       card->vdev.fops = &gemtek_pci_fops;
+       card->vdev.ioctl_ops = &gemtek_pci_ioctl_ops;
+       card->vdev.release = video_device_release_empty;
+       video_set_drvdata(&card->vdev, card);
+
+       if (video_register_device(&card->vdev, VFL_TYPE_RADIO, nr_radio) < 0)
                goto err_video;
-       }
 
-       card->videodev = devradio;
-       video_set_drvdata(devradio, card);
-       gemtek_pci_mute( card );
+       gemtek_pci_mute(card);
 
-       printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
-               pci_dev->revision, card->iobase, card->iobase + card->length - 1 );
+       v4l2_info(v4l2_dev, "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
+               pdev->revision, card->iobase, card->iobase + card->length - 1);
 
        return 0;
 
 err_video:
-       release_region( card->iobase, card->length );
+       release_region(card->iobase, card->length);
 
 err_pci:
-       kfree( card );
+       v4l2_device_unregister(v4l2_dev);
+       kfree(card);
        return -ENODEV;
 }
 
-static void __devexit gemtek_pci_remove( struct pci_dev *pci_dev )
+static void __devexit gemtek_pci_remove(struct pci_dev *pdev)
 {
-       struct gemtek_pci_card *card = pci_get_drvdata( pci_dev );
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+       struct gemtek_pci *card = to_gemtek_pci(v4l2_dev);
 
-       video_unregister_device( card->videodev );
-       kfree( card->videodev );
+       video_unregister_device(&card->vdev);
+       v4l2_device_unregister(v4l2_dev);
 
-       release_region( card->iobase, card->length );
+       release_region(card->iobase, card->length);
 
-       if ( mx )
-               gemtek_pci_mute( card );
+       if (mx)
+               gemtek_pci_mute(card);
 
-       kfree( card );
-
-       pci_set_drvdata( pci_dev, NULL );
+       kfree(card);
 }
 
-static struct pci_driver gemtek_pci_driver =
-{
+static struct pci_driver gemtek_pci_driver = {
        .name           = "gemtek_pci",
        .id_table       = gemtek_pci_id,
        .probe          = gemtek_pci_probe,
        .remove         = __devexit_p(gemtek_pci_remove),
 };
 
-static int __init gemtek_pci_init_module( void )
+static int __init gemtek_pci_init(void)
 {
-       return pci_register_driver( &gemtek_pci_driver );
+       return pci_register_driver(&gemtek_pci_driver);
 }
 
-static void __exit gemtek_pci_cleanup_module( void )
+static void __exit gemtek_pci_exit(void)
 {
        pci_unregister_driver(&gemtek_pci_driver);
 }
 
-MODULE_AUTHOR( "Vladimir Shebordaev <vshebordaev@mail.ru>" );
-MODULE_DESCRIPTION( "The video4linux driver for the Gemtek PCI Radio Card" );
-MODULE_LICENSE("GPL");
-
-module_param(mx, bool, 0);
-MODULE_PARM_DESC( mx, "single digit: 1 - turn off the turner upon module exit (default), 0 - do not" );
-module_param(nr_radio, int, 0);
-MODULE_PARM_DESC( nr_radio, "video4linux device number to use");
-
-module_init( gemtek_pci_init_module );
-module_exit( gemtek_pci_cleanup_module );
-
+module_init(gemtek_pci_init);
+module_exit(gemtek_pci_exit);
index 2b68be773f1381c443421fdf4ab8f40fe94009d3..150464426d1d227e75348a6e3debc551b3551b1e 100644 (file)
 #include <linux/init.h>                /* Initdata                     */
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
-#include <asm/io.h>            /* outb, outb_p                 */
-#include <asm/uaccess.h>       /* copy to/from user            */
 #include <linux/videodev2.h>   /* kernel radio structs         */
+#include <linux/version.h>     /* for KERNEL_VERSION MACRO     */
+#include <linux/mutex.h>
+#include <linux/io.h>          /* outb, outb_p                 */
 #include <media/v4l2-ioctl.h>
-#include <media/v4l2-common.h>
-#include <linux/spinlock.h>
+#include <media/v4l2-device.h>
 
-#include <linux/version.h>     /* for KERNEL_VERSION MACRO     */
-#define RADIO_VERSION KERNEL_VERSION(0,0,3)
-#define RADIO_BANNER "GemTek Radio card driver: v0.0.3"
+#define RADIO_VERSION KERNEL_VERSION(0, 0, 3)
 
 /*
  * Module info.
@@ -57,7 +55,6 @@ static int shutdown   = 1;
 static int keepmuted   = 1;
 static int initmute    = 1;
 static int radio_nr    = -1;
-static unsigned long in_use;
 
 module_param(io, int, 0444);
 MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic "
@@ -112,12 +109,19 @@ module_param(radio_nr, int, 0444);
 #define SHORT_DELAY 5          /* usec */
 #define LONG_DELAY 75          /* usec */
 
-struct gemtek_device {
+struct gemtek {
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       struct mutex lock;
        unsigned long lastfreq;
        int muted;
+       int verified;
+       int io;
        u32 bu2614data;
 };
 
+static struct gemtek gemtek_card;
+
 #define BU2614_FREQ_BITS       16 /* D0..D15, Frequency data           */
 #define BU2614_PORT_BITS       3 /* P0..P2, Output port control data   */
 #define BU2614_VOID_BITS       4 /* unused                             */
@@ -153,10 +157,6 @@ struct gemtek_device {
 #define BU2614_FMUN_MASK       MKMASK(FMUN)
 #define BU2614_TEST_MASK       MKMASK(TEST)
 
-static struct gemtek_device gemtek_unit;
-
-static spinlock_t lock;
-
 /*
  * Set data which will be sent to BU2614FS.
  */
@@ -166,33 +166,33 @@ static spinlock_t lock;
 /*
  * Transmit settings to BU2614FS over GemTek IC.
  */
-static void gemtek_bu2614_transmit(struct gemtek_device *dev)
+static void gemtek_bu2614_transmit(struct gemtek *gt)
 {
        int i, bit, q, mute;
 
-       spin_lock(&lock);
+       mutex_lock(&gt->lock);
 
-       mute = dev->muted ? GEMTEK_MT : 0x00;
+       mute = gt->muted ? GEMTEK_MT : 0x00;
 
-       outb_p(mute | GEMTEK_DA | GEMTEK_CK, io);
+       outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io);
        udelay(SHORT_DELAY);
-       outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io);
+       outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io);
        udelay(LONG_DELAY);
 
-       for (i = 0, q = dev->bu2614data; i < 32; i++, q >>= 1) {
-           bit = (q & 1) ? GEMTEK_DA : 0;
-           outb_p(mute | GEMTEK_CE | bit, io);
-           udelay(SHORT_DELAY);
-           outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, io);
-           udelay(SHORT_DELAY);
+       for (i = 0, q = gt->bu2614data; i < 32; i++, q >>= 1) {
+               bit = (q & 1) ? GEMTEK_DA : 0;
+               outb_p(mute | GEMTEK_CE | bit, gt->io);
+               udelay(SHORT_DELAY);
+               outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, gt->io);
+               udelay(SHORT_DELAY);
        }
 
-       outb_p(mute | GEMTEK_DA | GEMTEK_CK, io);
+       outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io);
        udelay(SHORT_DELAY);
-       outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io);
+       outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io);
        udelay(LONG_DELAY);
 
-       spin_unlock(&lock);
+       mutex_unlock(&gt->lock);
 }
 
 /*
@@ -206,107 +206,109 @@ static unsigned long gemtek_convfreq(unsigned long freq)
 /*
  * Set FM-frequency.
  */
-static void gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
+static void gemtek_setfreq(struct gemtek *gt, unsigned long freq)
 {
-
-       if (keepmuted && hardmute && dev->muted)
+       if (keepmuted && hardmute && gt->muted)
                return;
 
-       if (freq < GEMTEK_LOWFREQ)
-               freq = GEMTEK_LOWFREQ;
-       else if (freq > GEMTEK_HIGHFREQ)
-               freq = GEMTEK_HIGHFREQ;
+       freq = clamp_val(freq, GEMTEK_LOWFREQ, GEMTEK_HIGHFREQ);
 
-       dev->lastfreq = freq;
-       dev->muted = 0;
+       gt->lastfreq = freq;
+       gt->muted = 0;
 
-       gemtek_bu2614_set(dev, BU2614_PORT, 0);
-       gemtek_bu2614_set(dev, BU2614_FMES, 0);
-       gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode      */
-       gemtek_bu2614_set(dev, BU2614_SWAL, 0);
-       gemtek_bu2614_set(dev, BU2614_FMUN, 1); /* GT bit set   */
-       gemtek_bu2614_set(dev, BU2614_TEST, 0);
+       gemtek_bu2614_set(gt, BU2614_PORT, 0);
+       gemtek_bu2614_set(gt, BU2614_FMES, 0);
+       gemtek_bu2614_set(gt, BU2614_SWIN, 0);  /* FM-mode      */
+       gemtek_bu2614_set(gt, BU2614_SWAL, 0);
+       gemtek_bu2614_set(gt, BU2614_FMUN, 1);  /* GT bit set   */
+       gemtek_bu2614_set(gt, BU2614_TEST, 0);
 
-       gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_STDF_3_125_KHZ);
-       gemtek_bu2614_set(dev, BU2614_FREQ, gemtek_convfreq(freq));
+       gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_STDF_3_125_KHZ);
+       gemtek_bu2614_set(gt, BU2614_FREQ, gemtek_convfreq(freq));
 
-       gemtek_bu2614_transmit(dev);
+       gemtek_bu2614_transmit(gt);
 }
 
 /*
  * Set mute flag.
  */
-static void gemtek_mute(struct gemtek_device *dev)
+static void gemtek_mute(struct gemtek *gt)
 {
        int i;
-       dev->muted = 1;
+
+       gt->muted = 1;
 
        if (hardmute) {
                /* Turn off PLL, disable data output */
-               gemtek_bu2614_set(dev, BU2614_PORT, 0);
-               gemtek_bu2614_set(dev, BU2614_FMES, 0); /* CT bit off   */
-               gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode      */
-               gemtek_bu2614_set(dev, BU2614_SWAL, 0);
-               gemtek_bu2614_set(dev, BU2614_FMUN, 0); /* GT bit off   */
-               gemtek_bu2614_set(dev, BU2614_TEST, 0);
-               gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_PLL_OFF);
-               gemtek_bu2614_set(dev, BU2614_FREQ, 0);
-               gemtek_bu2614_transmit(dev);
-       } else {
-               spin_lock(&lock);
+               gemtek_bu2614_set(gt, BU2614_PORT, 0);
+               gemtek_bu2614_set(gt, BU2614_FMES, 0);  /* CT bit off   */
+               gemtek_bu2614_set(gt, BU2614_SWIN, 0);  /* FM-mode      */
+               gemtek_bu2614_set(gt, BU2614_SWAL, 0);
+               gemtek_bu2614_set(gt, BU2614_FMUN, 0);  /* GT bit off   */
+               gemtek_bu2614_set(gt, BU2614_TEST, 0);
+               gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_PLL_OFF);
+               gemtek_bu2614_set(gt, BU2614_FREQ, 0);
+               gemtek_bu2614_transmit(gt);
+               return;
+       }
 
-               /* Read bus contents (CE, CK and DA). */
-               i = inb_p(io);
-               /* Write it back with mute flag set. */
-               outb_p((i >> 5) | GEMTEK_MT, io);
-               udelay(SHORT_DELAY);
+       mutex_lock(&gt->lock);
 
-               spin_unlock(&lock);
-       }
+       /* Read bus contents (CE, CK and DA). */
+       i = inb_p(gt->io);
+       /* Write it back with mute flag set. */
+       outb_p((i >> 5) | GEMTEK_MT, gt->io);
+       udelay(SHORT_DELAY);
+
+       mutex_unlock(&gt->lock);
 }
 
 /*
  * Unset mute flag.
  */
-static void gemtek_unmute(struct gemtek_device *dev)
+static void gemtek_unmute(struct gemtek *gt)
 {
        int i;
-       dev->muted = 0;
 
+       gt->muted = 0;
        if (hardmute) {
                /* Turn PLL back on. */
-               gemtek_setfreq(dev, dev->lastfreq);
-       } else {
-               spin_lock(&lock);
+               gemtek_setfreq(gt, gt->lastfreq);
+               return;
+       }
+       mutex_lock(&gt->lock);
 
-               i = inb_p(io);
-               outb_p(i >> 5, io);
-               udelay(SHORT_DELAY);
+       i = inb_p(gt->io);
+       outb_p(i >> 5, gt->io);
+       udelay(SHORT_DELAY);
 
-               spin_unlock(&lock);
-       }
+       mutex_unlock(&gt->lock);
 }
 
 /*
  * Get signal strength (= stereo status).
  */
-static inline int gemtek_getsigstr(void)
+static inline int gemtek_getsigstr(struct gemtek *gt)
 {
-       return inb_p(io) & GEMTEK_NS ? 0 : 1;
+       int sig;
+
+       mutex_lock(&gt->lock);
+       sig = inb_p(gt->io) & GEMTEK_NS ? 0 : 1;
+       mutex_unlock(&gt->lock);
+       return sig;
 }
 
 /*
  * Check if requested card acts like GemTek Radio card.
  */
-static int gemtek_verify(int port)
+static int gemtek_verify(struct gemtek *gt, int port)
 {
-       static int verified = -1;
        int i, q;
 
-       if (verified == port)
+       if (gt->verified == port)
                return 1;
 
-       spin_lock(&lock);
+       mutex_lock(&gt->lock);
 
        q = inb_p(port);        /* Read bus contents before probing. */
        /* Try to turn on CE, CK and DA respectively and check if card responds
@@ -316,15 +318,15 @@ static int gemtek_verify(int port)
                udelay(SHORT_DELAY);
 
                if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) {
-                       spin_unlock(&lock);
+                       mutex_unlock(&gt->lock);
                        return 0;
                }
        }
        outb_p(q >> 5, port);   /* Write bus contents back. */
        udelay(SHORT_DELAY);
 
-       spin_unlock(&lock);
-       verified = port;
+       mutex_unlock(&gt->lock);
+       gt->verified = port;
 
        return 1;
 }
@@ -332,83 +334,61 @@ static int gemtek_verify(int port)
 /*
  * Automatic probing for card.
  */
-static int gemtek_probe(void)
+static int gemtek_probe(struct gemtek *gt)
 {
+       struct v4l2_device *v4l2_dev = &gt->v4l2_dev;
        int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c };
        int i;
 
        if (!probe) {
-               printk(KERN_INFO "Automatic device probing disabled.\n");
+               v4l2_info(v4l2_dev, "Automatic device probing disabled.\n");
                return -1;
        }
 
-       printk(KERN_INFO "Automatic device probing enabled.\n");
+       v4l2_info(v4l2_dev, "Automatic device probing enabled.\n");
 
        for (i = 0; i < ARRAY_SIZE(ioports); ++i) {
-               printk(KERN_INFO "Trying I/O port 0x%x...\n", ioports[i]);
+               v4l2_info(v4l2_dev, "Trying I/O port 0x%x...\n", ioports[i]);
 
                if (!request_region(ioports[i], 1, "gemtek-probe")) {
-                       printk(KERN_WARNING "I/O port 0x%x busy!\n",
+                       v4l2_warn(v4l2_dev, "I/O port 0x%x busy!\n",
                               ioports[i]);
                        continue;
                }
 
-               if (gemtek_verify(ioports[i])) {
-                       printk(KERN_INFO "Card found from I/O port "
+               if (gemtek_verify(gt, ioports[i])) {
+                       v4l2_info(v4l2_dev, "Card found from I/O port "
                               "0x%x!\n", ioports[i]);
 
                        release_region(ioports[i], 1);
-
-                       io = ioports[i];
-                       return io;
+                       gt->io = ioports[i];
+                       return gt->io;
                }
 
                release_region(ioports[i], 1);
        }
 
-       printk(KERN_ERR "Automatic probing failed!\n");
-
+       v4l2_err(v4l2_dev, "Automatic probing failed!\n");
        return -1;
 }
 
 /*
  * Video 4 Linux stuff.
  */
-
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id = V4L2_CID_AUDIO_MUTE,
-               .name = "Mute",
-               .minimum = 0,
-               .maximum = 1,
-               .default_value = 1,
-               .type = V4L2_CTRL_TYPE_BOOLEAN,
-       }, {
-               .id = V4L2_CID_AUDIO_VOLUME,
-               .name = "Volume",
-               .minimum = 0,
-               .maximum = 65535,
-               .step = 65535,
-               .default_value = 0xff,
-               .type = V4L2_CTRL_TYPE_INTEGER,
-       }
-};
-
-static int gemtek_exclusive_open(struct file *file)
+static int gemtek_open(struct file *file)
 {
-       return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
+       return 0;
 }
 
-static int gemtek_exclusive_release(struct file *file)
+static int gemtek_release(struct file *file)
 {
-       clear_bit(0, &in_use);
        return 0;
 }
 
 static const struct v4l2_file_operations gemtek_fops = {
        .owner          = THIS_MODULE,
-       .open           = gemtek_exclusive_open,
-       .release        = gemtek_exclusive_release,
+       .open           = gemtek_open,
+       .release        = gemtek_release,
        .ioctl          = video_ioctl2,
 };
 
@@ -417,23 +397,25 @@ static int vidioc_querycap(struct file *file, void *priv,
 {
        strlcpy(v->driver, "radio-gemtek", sizeof(v->driver));
        strlcpy(v->card, "GemTek", sizeof(v->card));
-       sprintf(v->bus_info, "ISA");
+       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
        v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER;
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
 
 static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
 {
+       struct gemtek *gt = video_drvdata(file);
+
        if (v->index > 0)
                return -EINVAL;
 
-       strcpy(v->name, "FM");
+       strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
        v->rangelow = GEMTEK_LOWFREQ;
        v->rangehigh = GEMTEK_HIGHFREQ;
        v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
-       v->signal = 0xffff * gemtek_getsigstr();
+       v->signal = 0xffff * gemtek_getsigstr(gt);
        if (v->signal) {
                v->audmode = V4L2_TUNER_MODE_STEREO;
                v->rxsubchans = V4L2_TUNER_SUB_STEREO;
@@ -441,65 +423,56 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
                v->audmode = V4L2_TUNER_MODE_MONO;
                v->rxsubchans = V4L2_TUNER_SUB_MONO;
        }
-
        return 0;
 }
 
 static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
 {
-       if (v->index > 0)
-               return -EINVAL;
-       return 0;
+       return (v->index != 0) ? -EINVAL : 0;
 }
 
-static int vidioc_s_frequency(struct file *file, void *priv,
+static int vidioc_g_frequency(struct file *file, void *priv,
                              struct v4l2_frequency *f)
 {
-       struct gemtek_device *rt = video_drvdata(file);
-
-       gemtek_setfreq(rt, f->frequency);
+       struct gemtek *gt = video_drvdata(file);
 
+       if (f->tuner != 0)
+               return -EINVAL;
+       f->type = V4L2_TUNER_RADIO;
+       f->frequency = gt->lastfreq;
        return 0;
 }
 
-static int vidioc_g_frequency(struct file *file, void *priv,
+static int vidioc_s_frequency(struct file *file, void *priv,
                              struct v4l2_frequency *f)
 {
-       struct gemtek_device *rt = video_drvdata(file);
+       struct gemtek *gt = video_drvdata(file);
 
-       f->type = V4L2_TUNER_RADIO;
-       f->frequency = rt->lastfreq;
+       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+               return -EINVAL;
+       gemtek_setfreq(gt, f->frequency);
        return 0;
 }
 
 static int vidioc_queryctrl(struct file *file, void *priv,
                            struct v4l2_queryctrl *qc)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); ++i) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
-                       return 0;
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+       default:
+               return -EINVAL;
        }
-       return -EINVAL;
 }
 
 static int vidioc_g_ctrl(struct file *file, void *priv,
                         struct v4l2_control *ctrl)
 {
-       struct gemtek_device *rt = video_drvdata(file);
+       struct gemtek *gt = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = rt->muted;
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               if (rt->muted)
-                       ctrl->value = 0;
-               else
-                       ctrl->value = 65535;
+               ctrl->value = gt->muted;
                return 0;
        }
        return -EINVAL;
@@ -508,35 +481,19 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                         struct v4l2_control *ctrl)
 {
-       struct gemtek_device *rt = video_drvdata(file);
+       struct gemtek *gt = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
                if (ctrl->value)
-                       gemtek_mute(rt);
-               else
-                       gemtek_unmute(rt);
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               if (ctrl->value)
-                       gemtek_unmute(rt);
+                       gemtek_mute(gt);
                else
-                       gemtek_mute(rt);
+                       gemtek_unmute(gt);
                return 0;
        }
        return -EINVAL;
 }
 
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
-       if (a->index > 1)
-               return -EINVAL;
-
-       strcpy(a->name, "Radio");
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 {
        *i = 0;
@@ -545,16 +502,20 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 
 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-       if (i != 0)
-               return -EINVAL;
+       return (i != 0) ? -EINVAL : 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+       a->index = 0;
+       strlcpy(a->name, "Radio", sizeof(a->name));
+       a->capability = V4L2_AUDCAP_STEREO;
        return 0;
 }
 
 static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
 {
-       if (a->index != 0)
-               return -EINVAL;
-       return 0;
+       return (a->index != 0) ? -EINVAL : 0;
 }
 
 static const struct v4l2_ioctl_ops gemtek_ioctl_ops = {
@@ -572,62 +533,73 @@ static const struct v4l2_ioctl_ops gemtek_ioctl_ops = {
        .vidioc_s_ctrl          = vidioc_s_ctrl
 };
 
-static struct video_device gemtek_radio = {
-       .name           = "GemTek Radio card",
-       .fops           = &gemtek_fops,
-       .ioctl_ops      = &gemtek_ioctl_ops,
-       .release        = video_device_release_empty,
-};
-
 /*
  * Initialization / cleanup related stuff.
  */
 
-/*
- * Initilize card.
- */
 static int __init gemtek_init(void)
 {
-       printk(KERN_INFO RADIO_BANNER "\n");
+       struct gemtek *gt = &gemtek_card;
+       struct v4l2_device *v4l2_dev = &gt->v4l2_dev;
+       int res;
 
-       spin_lock_init(&lock);
+       strlcpy(v4l2_dev->name, "gemtek", sizeof(v4l2_dev->name));
 
-       gemtek_probe();
-       if (io) {
-               if (!request_region(io, 1, "gemtek")) {
-                       printk(KERN_ERR "I/O port 0x%x already in use.\n", io);
+       v4l2_info(v4l2_dev, "GemTek Radio card driver: v0.0.3\n");
+
+       mutex_init(&gt->lock);
+
+       gt->verified = -1;
+       gt->io = io;
+       gemtek_probe(gt);
+       if (gt->io) {
+               if (!request_region(gt->io, 1, "gemtek")) {
+                       v4l2_err(v4l2_dev, "I/O port 0x%x already in use.\n", gt->io);
                        return -EBUSY;
                }
 
-               if (!gemtek_verify(io))
-                       printk(KERN_WARNING "Card at I/O port 0x%x does not "
+               if (!gemtek_verify(gt, gt->io))
+                       v4l2_warn(v4l2_dev, "Card at I/O port 0x%x does not "
                               "respond properly, check your "
-                              "configuration.\n", io);
+                              "configuration.\n", gt->io);
                else
-                       printk(KERN_INFO "Using I/O port 0x%x.\n", io);
+                       v4l2_info(v4l2_dev, "Using I/O port 0x%x.\n", gt->io);
        } else if (probe) {
-               printk(KERN_ERR "Automatic probing failed and no "
+               v4l2_err(v4l2_dev, "Automatic probing failed and no "
                       "fixed I/O port defined.\n");
                return -ENODEV;
        } else {
-               printk(KERN_ERR "Automatic probing disabled but no fixed "
+               v4l2_err(v4l2_dev, "Automatic probing disabled but no fixed "
                       "I/O port defined.");
                return -EINVAL;
        }
 
-       video_set_drvdata(&gemtek_radio, &gemtek_unit);
+       res = v4l2_device_register(NULL, v4l2_dev);
+       if (res < 0) {
+               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+               release_region(gt->io, 1);
+               return res;
+       }
 
-       if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
-               release_region(io, 1);
+       strlcpy(gt->vdev.name, v4l2_dev->name, sizeof(gt->vdev.name));
+       gt->vdev.v4l2_dev = v4l2_dev;
+       gt->vdev.fops = &gemtek_fops;
+       gt->vdev.ioctl_ops = &gemtek_ioctl_ops;
+       gt->vdev.release = video_device_release_empty;
+       video_set_drvdata(&gt->vdev, gt);
+
+       if (video_register_device(&gt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+               v4l2_device_unregister(v4l2_dev);
+               release_region(gt->io, 1);
                return -EBUSY;
        }
 
        /* Set defaults */
-       gemtek_unit.lastfreq = GEMTEK_LOWFREQ;
-       gemtek_unit.bu2614data = 0;
+       gt->lastfreq = GEMTEK_LOWFREQ;
+       gt->bu2614data = 0;
 
        if (initmute)
-               gemtek_mute(&gemtek_unit);
+               gemtek_mute(gt);
 
        return 0;
 }
@@ -637,15 +609,19 @@ static int __init gemtek_init(void)
  */
 static void __exit gemtek_exit(void)
 {
+       struct gemtek *gt = &gemtek_card;
+       struct v4l2_device *v4l2_dev = &gt->v4l2_dev;
+
        if (shutdown) {
                hardmute = 1;   /* Turn off PLL */
-               gemtek_mute(&gemtek_unit);
+               gemtek_mute(gt);
        } else {
-               printk(KERN_INFO "Module unloaded but card not muted!\n");
+               v4l2_info(v4l2_dev, "Module unloaded but card not muted!\n");
        }
 
-       video_unregister_device(&gemtek_radio);
-       release_region(io, 1);
+       video_unregister_device(&gt->vdev);
+       v4l2_device_unregister(&gt->v4l2_dev);
+       release_region(gt->io, 1);
 }
 
 module_init(gemtek_init);
index ba3a13a90013e4c58e232afe7b50baff892410a8..01a6d22950ade8ab7725fa9bc9e56e8e5a067f51 100644 (file)
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/pci.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <linux/io.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
-#define RADIO_VERSION KERNEL_VERSION(0,0,6)
-#define DRIVER_VERSION "0.06"
+MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl");
+MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio.");
+MODULE_LICENSE("GPL");
 
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       }
-};
+static int radio_nr = -1;
+module_param(radio_nr, int, 0);
+
+#define RADIO_VERSION KERNEL_VERSION(0, 0, 6)
+#define DRIVER_VERSION "0.06"
 
 #define GPIO_DATA      0x60   /* port offset from ESS_IO_BASE */
 
@@ -72,62 +67,27 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 
 #define BITS2FREQ(x)   ((x) * FREQ_STEP - FREQ_IF)
 
-static int radio_nr = -1;
-module_param(radio_nr, int, 0);
+struct maestro {
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       struct pci_dev *pdev;
+       struct mutex lock;
 
-static unsigned long in_use;
-
-static int maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+       u16     io;     /* base of Maestro card radio io (GPIO_DATA)*/
+       u16     muted;  /* VIDEO_AUDIO_MUTE */
+       u16     stereo; /* VIDEO_TUNER_STEREO_ON */
+       u16     tuned;  /* signal strength (0 or 0xffff) */
+};
 
-static int maestro_exclusive_open(struct file *file)
+static inline struct maestro *to_maestro(struct v4l2_device *v4l2_dev)
 {
-       return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
+       return container_of(v4l2_dev, struct maestro, v4l2_dev);
 }
 
-static int maestro_exclusive_release(struct file *file)
+static u32 radio_bits_get(struct maestro *dev)
 {
-       clear_bit(0, &in_use);
-       return 0;
-}
-
-static void maestro_remove(struct pci_dev *pdev);
-
-static struct pci_device_id maestro_r_pci_tbl[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1968),
-               .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
-               .class_mask = 0xffff00 },
-       { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1978),
-               .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
-               .class_mask = 0xffff00 },
-       { 0 }
-};
-MODULE_DEVICE_TABLE(pci, maestro_r_pci_tbl);
-
-static struct pci_driver maestro_r_driver = {
-       .name           = "maestro_radio",
-       .id_table       = maestro_r_pci_tbl,
-       .probe          = maestro_probe,
-       .remove         = __devexit_p(maestro_remove),
-};
-
-static const struct v4l2_file_operations maestro_fops = {
-       .owner          = THIS_MODULE,
-       .open           = maestro_exclusive_open,
-       .release        = maestro_exclusive_release,
-       .ioctl          = video_ioctl2,
-};
-
-struct radio_device {
-       u16     io,     /* base of Maestro card radio io (GPIO_DATA)*/
-               muted,  /* VIDEO_AUDIO_MUTE */
-               stereo, /* VIDEO_TUNER_STEREO_ON */
-               tuned;  /* signal strength (0 or 0xffff) */
-};
-
-static u32 radio_bits_get(struct radio_device *dev)
-{
-       register u16 io=dev->io, l, rdata;
-       register u32 data=0;
+       u16 io = dev->io, l, rdata;
+       u32 data = 0;
        u16 omask;
 
        omask = inw(io + IO_MASK);
@@ -135,25 +95,23 @@ static u32 radio_bits_get(struct radio_device *dev)
        outw(0, io);
        udelay(16);
 
-       for (l=24;l--;) {
+       for (l = 24; l--;) {
                outw(STR_CLK, io);              /* HI state */
                udelay(2);
-               if(!l)
+               if (!l)
                        dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff;
                outw(0, io);                    /* LO state */
                udelay(2);
                data <<= 1;                     /* shift data */
                rdata = inw(io);
-               if(!l)
-                       dev->stereo =  rdata & STR_MOST ?
-                       0 : 1;
-               else
-                       if(rdata & STR_DATA)
-                               data++;
+               if (!l)
+                       dev->stereo = (rdata & STR_MOST) ?  0 : 1;
+               else if (rdata & STR_DATA)
+                       data++;
                udelay(2);
        }
 
-       if(dev->muted)
+       if (dev->muted)
                outw(STR_WREN, io);
 
        udelay(4);
@@ -162,18 +120,18 @@ static u32 radio_bits_get(struct radio_device *dev)
        return data & 0x3ffe;
 }
 
-static void radio_bits_set(struct radio_device *dev, u32 data)
+static void radio_bits_set(struct maestro *dev, u32 data)
 {
-       register u16 io=dev->io, l, bits;
+       u16 io = dev->io, l, bits;
        u16 omask, odir;
 
        omask = inw(io + IO_MASK);
-       odir  = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
+       odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
        outw(odir | STR_DATA, io + IO_DIR);
        outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
        udelay(16);
-       for (l=25;l;l--) {
-               bits = ((data >> 18) & STR_DATA) | STR_WREN ;
+       for (l = 25; l; l--) {
+               bits = ((data >> 18) & STR_DATA) | STR_WREN;
                data <<= 1;                     /* shift data */
                outw(bits, io);                 /* start strobe */
                udelay(2);
@@ -183,7 +141,7 @@ static void radio_bits_set(struct radio_device *dev, u32 data)
                udelay(4);
        }
 
-       if(!dev->muted)
+       if (!dev->muted)
                outw(0, io);
 
        udelay(4);
@@ -195,78 +153,79 @@ static void radio_bits_set(struct radio_device *dev, u32 data)
 static int vidioc_querycap(struct file *file, void  *priv,
                                        struct v4l2_capability *v)
 {
+       struct maestro *dev = video_drvdata(file);
+
        strlcpy(v->driver, "radio-maestro", sizeof(v->driver));
        strlcpy(v->card, "Maestro Radio", sizeof(v->card));
-       sprintf(v->bus_info, "PCI");
+       snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev));
        v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER;
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
 
 static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       struct radio_device *card = video_drvdata(file);
+       struct maestro *dev = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
 
-       (void)radio_bits_get(card);
+       mutex_lock(&dev->lock);
+       radio_bits_get(dev);
 
-       strcpy(v->name, "FM");
+       strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
        v->rangelow = FREQ_LO;
        v->rangehigh = FREQ_HI;
-       v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+       v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
        v->capability = V4L2_TUNER_CAP_LOW;
-       if(card->stereo)
+       if (dev->stereo)
                v->audmode = V4L2_TUNER_MODE_STEREO;
        else
                v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = card->tuned;
+       v->signal = dev->tuned;
+       mutex_unlock(&dev->lock);
        return 0;
 }
 
 static int vidioc_s_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       if (v->index > 0)
-               return -EINVAL;
-       return 0;
+       return v->index ? -EINVAL : 0;
 }
 
 static int vidioc_s_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct radio_device *card = video_drvdata(file);
+       struct maestro *dev = video_drvdata(file);
 
        if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
                return -EINVAL;
-       radio_bits_set(card, FREQ2BITS(f->frequency));
+       mutex_lock(&dev->lock);
+       radio_bits_set(dev, FREQ2BITS(f->frequency));
+       mutex_unlock(&dev->lock);
        return 0;
 }
 
 static int vidioc_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct radio_device *card = video_drvdata(file);
+       struct maestro *dev = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
-       f->frequency = BITS2FREQ(radio_bits_get(card));
+       mutex_lock(&dev->lock);
+       f->frequency = BITS2FREQ(radio_bits_get(dev));
+       mutex_unlock(&dev->lock);
        return 0;
 }
 
 static int vidioc_queryctrl(struct file *file, void *priv,
                                        struct v4l2_queryctrl *qc)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]),
-                                               sizeof(*qc));
-                       return 0;
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
        }
        return -EINVAL;
 }
@@ -274,11 +233,11 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct radio_device *card = video_drvdata(file);
+       struct maestro *dev = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = card->muted;
+               ctrl->value = dev->muted;
                return 0;
        }
        return -EINVAL;
@@ -287,56 +246,85 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct radio_device *card = video_drvdata(file);
-       register u16 io = card->io;
-       register u16 omask = inw(io + IO_MASK);
+       struct maestro *dev = video_drvdata(file);
+       u16 io = dev->io;
+       u16 omask;
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
+               mutex_lock(&dev->lock);
+               omask = inw(io + IO_MASK);
                outw(~STR_WREN, io + IO_MASK);
-               outw((card->muted = ctrl->value ) ?
-                               STR_WREN : 0, io);
+               dev->muted = ctrl->value;
+               outw(dev->muted ? STR_WREN : 0, io);
                udelay(4);
                outw(omask, io + IO_MASK);
                msleep(125);
+               mutex_unlock(&dev->lock);
                return 0;
        }
        return -EINVAL;
 }
 
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
+}
+
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+       return i ? -EINVAL : 0;
+}
+
 static int vidioc_g_audio(struct file *file, void *priv,
                                        struct v4l2_audio *a)
 {
-       if (a->index > 1)
-               return -EINVAL;
-
-       strcpy(a->name, "Radio");
+       a->index = 0;
+       strlcpy(a->name, "Radio", sizeof(a->name));
        a->capability = V4L2_AUDCAP_STEREO;
        return 0;
 }
 
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+static int vidioc_s_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
 {
-       *i = 0;
-       return 0;
+       return a->index ? -EINVAL : 0;
 }
 
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+static int maestro_open(struct file *file)
 {
-       if (i != 0)
-               return -EINVAL;
        return 0;
 }
 
-static int vidioc_s_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
+static int maestro_release(struct file *file)
 {
-       if (a->index != 0)
-               return -EINVAL;
        return 0;
 }
 
-static u16 __devinit radio_power_on(struct radio_device *dev)
+static const struct v4l2_file_operations maestro_fops = {
+       .owner          = THIS_MODULE,
+       .open           = maestro_open,
+       .release        = maestro_release,
+       .ioctl          = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops maestro_ioctl_ops = {
+       .vidioc_querycap    = vidioc_querycap,
+       .vidioc_g_tuner     = vidioc_g_tuner,
+       .vidioc_s_tuner     = vidioc_s_tuner,
+       .vidioc_g_audio     = vidioc_g_audio,
+       .vidioc_s_audio     = vidioc_s_audio,
+       .vidioc_g_input     = vidioc_g_input,
+       .vidioc_s_input     = vidioc_s_input,
+       .vidioc_g_frequency = vidioc_g_frequency,
+       .vidioc_s_frequency = vidioc_s_frequency,
+       .vidioc_queryctrl   = vidioc_queryctrl,
+       .vidioc_g_ctrl      = vidioc_g_ctrl,
+       .vidioc_s_ctrl      = vidioc_s_ctrl,
+};
+
+static u16 __devinit radio_power_on(struct maestro *dev)
 {
        register u16 io = dev->io;
        register u32 ofreq;
@@ -360,33 +348,11 @@ static u16 __devinit radio_power_on(struct radio_device *dev)
        return (ofreq == radio_bits_get(dev));
 }
 
-static const struct v4l2_ioctl_ops maestro_ioctl_ops = {
-       .vidioc_querycap    = vidioc_querycap,
-       .vidioc_g_tuner     = vidioc_g_tuner,
-       .vidioc_s_tuner     = vidioc_s_tuner,
-       .vidioc_g_audio     = vidioc_g_audio,
-       .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
-       .vidioc_g_frequency = vidioc_g_frequency,
-       .vidioc_s_frequency = vidioc_s_frequency,
-       .vidioc_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
-};
-
-static struct video_device maestro_radio = {
-       .name           = "Maestro radio",
-       .fops           = &maestro_fops,
-       .ioctl_ops      = &maestro_ioctl_ops,
-       .release        = video_device_release,
-};
-
 static int __devinit maestro_probe(struct pci_dev *pdev,
        const struct pci_device_id *ent)
 {
-       struct radio_device *radio_unit;
-       struct video_device *maestro_radio_inst;
+       struct maestro *dev;
+       struct v4l2_device *v4l2_dev;
        int retval;
 
        retval = pci_enable_device(pdev);
@@ -397,46 +363,53 @@ static int __devinit maestro_probe(struct pci_dev *pdev,
 
        retval = -ENOMEM;
 
-       radio_unit = kzalloc(sizeof(*radio_unit), GFP_KERNEL);
-       if (radio_unit == NULL) {
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL) {
                dev_err(&pdev->dev, "not enough memory\n");
                goto err;
        }
 
-       radio_unit->io = pci_resource_start(pdev, 0) + GPIO_DATA;
+       v4l2_dev = &dev->v4l2_dev;
+       mutex_init(&dev->lock);
+       dev->pdev = pdev;
 
-       maestro_radio_inst = video_device_alloc();
-       if (maestro_radio_inst == NULL) {
-               dev_err(&pdev->dev, "not enough memory\n");
+       strlcpy(v4l2_dev->name, "maestro", sizeof(v4l2_dev->name));
+
+       retval = v4l2_device_register(&pdev->dev, v4l2_dev);
+       if (retval < 0) {
+               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
                goto errfr;
        }
 
-       memcpy(maestro_radio_inst, &maestro_radio, sizeof(maestro_radio));
-       video_set_drvdata(maestro_radio_inst, radio_unit);
-       pci_set_drvdata(pdev, maestro_radio_inst);
+       dev->io = pci_resource_start(pdev, 0) + GPIO_DATA;
 
-       retval = video_register_device(maestro_radio_inst, VFL_TYPE_RADIO, radio_nr);
+       strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
+       dev->vdev.v4l2_dev = v4l2_dev;
+       dev->vdev.fops = &maestro_fops;
+       dev->vdev.ioctl_ops = &maestro_ioctl_ops;
+       dev->vdev.release = video_device_release_empty;
+       video_set_drvdata(&dev->vdev, dev);
+
+       retval = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr);
        if (retval) {
-               printk(KERN_ERR "can't register video device!\n");
+               v4l2_err(v4l2_dev, "can't register video device!\n");
                goto errfr1;
        }
 
-       if (!radio_power_on(radio_unit)) {
+       if (!radio_power_on(dev)) {
                retval = -EIO;
                goto errunr;
        }
 
-       dev_info(&pdev->dev, "version " DRIVER_VERSION " time " __TIME__ "  "
-                __DATE__ "\n");
-       dev_info(&pdev->dev, "radio chip initialized\n");
+       v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n");
 
        return 0;
 errunr:
-       video_unregister_device(maestro_radio_inst);
+       video_unregister_device(&dev->vdev);
 errfr1:
-       video_device_release(maestro_radio_inst);
+       v4l2_device_unregister(v4l2_dev);
 errfr:
-       kfree(radio_unit);
+       kfree(dev);
 err:
        return retval;
 
@@ -444,11 +417,31 @@ err:
 
 static void __devexit maestro_remove(struct pci_dev *pdev)
 {
-       struct video_device *vdev = pci_get_drvdata(pdev);
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+       struct maestro *dev = to_maestro(v4l2_dev);
 
-       video_unregister_device(vdev);
+       video_unregister_device(&dev->vdev);
+       v4l2_device_unregister(&dev->v4l2_dev);
 }
 
+static struct pci_device_id maestro_r_pci_tbl[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1968),
+               .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+               .class_mask = 0xffff00 },
+       { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1978),
+               .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+               .class_mask = 0xffff00 },
+       { 0 }
+};
+MODULE_DEVICE_TABLE(pci, maestro_r_pci_tbl);
+
+static struct pci_driver maestro_r_driver = {
+       .name           = "maestro_radio",
+       .id_table       = maestro_r_pci_tbl,
+       .probe          = maestro_probe,
+       .remove         = __devexit_p(maestro_remove),
+};
+
 static int __init maestro_radio_init(void)
 {
        int retval = pci_register_driver(&maestro_r_driver);
@@ -466,7 +459,3 @@ static void __exit maestro_radio_exit(void)
 
 module_init(maestro_radio_init);
 module_exit(maestro_radio_exit);
-
-MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl");
-MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio.");
-MODULE_LICENSE("GPL");
index c5dc00aa9c9f467f2704ca3f13ef531b36248e93..2606f0b303554ed88dee27dd2353d7c3b81cfd7d 100644 (file)
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
 #include <linux/mutex.h>
-
 #include <linux/pci.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#include <linux/io.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 
+MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
+MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
+MODULE_LICENSE("GPL");
+
+static int radio_nr = -1;
+module_param(radio_nr, int, 0);
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
 #define DRIVER_VERSION "0.77"
 
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
-#define RADIO_VERSION KERNEL_VERSION(0,7,7)
-
-static struct video_device maxiradio_radio;
-
-#define dprintk(num, fmt, arg...)                                          \
-       do {                                                               \
-               if (maxiradio_radio.debug >= num)                          \
-                       printk(KERN_DEBUG "%s: " fmt,                      \
-                               maxiradio_radio.name, ## arg); } while (0)
-
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       }
-};
+#define RADIO_VERSION KERNEL_VERSION(0, 7, 7)
+
+#define dprintk(dev, num, fmt, arg...) \
+       v4l2_dbg(num, debug, &dev->v4l2_dev, fmt, ## arg)
 
 #ifndef PCI_VENDOR_ID_GUILLEMOT
 #define PCI_VENDOR_ID_GUILLEMOT 0x5046
@@ -80,90 +74,70 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 
 
 /* TEA5757 pin mappings */
-static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16 ;
-
-static int radio_nr = -1;
-module_param(radio_nr, int, 0);
+static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16;
 
-static unsigned long in_use;
-
-#define FREQ_LO                 50*16000
-#define FREQ_HI                150*16000
+#define FREQ_LO                (50 * 16000)
+#define FREQ_HI                (150 * 16000)
 
 #define FREQ_IF         171200 /* 10.7*16000   */
 #define FREQ_STEP       200    /* 12.5*16      */
 
 /* (x==fmhz*16*1000) -> bits */
-#define FREQ2BITS(x)   ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1)) \
-                       /(FREQ_STEP<<2))<<2)
+#define FREQ2BITS(x) \
+  ((((unsigned int)(x) + FREQ_IF + (FREQ_STEP << 1)) / (FREQ_STEP << 2)) << 2)
 
 #define BITS2FREQ(x)   ((x) * FREQ_STEP - FREQ_IF)
 
 
-static int maxiradio_exclusive_open(struct file *file)
+struct maxiradio
 {
-       return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
-}
-
-static int maxiradio_exclusive_release(struct file *file)
-{
-       clear_bit(0, &in_use);
-       return 0;
-}
-
-static const struct v4l2_file_operations maxiradio_fops = {
-       .owner          = THIS_MODULE,
-       .open           = maxiradio_exclusive_open,
-       .release        = maxiradio_exclusive_release,
-       .ioctl          = video_ioctl2,
-};
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       struct pci_dev *pdev;
 
-static struct radio_device
-{
-       __u16   io,     /* base of radio io */
-               muted,  /* VIDEO_AUDIO_MUTE */
-               stereo, /* VIDEO_TUNER_STEREO_ON */
-               tuned;  /* signal strength (0 or 0xffff) */
+       u16     io;     /* base of radio io */
+       u16     muted;  /* VIDEO_AUDIO_MUTE */
+       u16     stereo; /* VIDEO_TUNER_STEREO_ON */
+       u16     tuned;  /* signal strength (0 or 0xffff) */
 
        unsigned long freq;
 
        struct mutex lock;
-} radio_unit = {
-       .muted =1,
-       .freq = FREQ_LO,
 };
 
-static void outbit(unsigned long bit, __u16 io)
+static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev)
 {
-       if (bit != 0)
-               {
-                       outb(  power|wren|data     ,io); udelay(4);
-                       outb(  power|wren|data|clk ,io); udelay(4);
-                       outb(  power|wren|data     ,io); udelay(4);
-               }
-       else
-               {
-                       outb(  power|wren          ,io); udelay(4);
-                       outb(  power|wren|clk      ,io); udelay(4);
-                       outb(  power|wren          ,io); udelay(4);
-               }
+       return container_of(v4l2_dev, struct maxiradio, v4l2_dev);
 }
 
-static void turn_power(__u16 io, int p)
+static void outbit(unsigned long bit, u16 io)
+{
+       int val = power | wren | (bit ? data : 0);
+
+       outb(val, io);
+       udelay(4);
+       outb(val | clk, io);
+       udelay(4);
+       outb(val, io);
+       udelay(4);
+}
+
+static void turn_power(struct maxiradio *dev, int p)
 {
        if (p != 0) {
-               dprintk(1, "Radio powered on\n");
-               outb(power, io);
+               dprintk(dev, 1, "Radio powered on\n");
+               outb(power, dev->io);
        } else {
-               dprintk(1, "Radio powered off\n");
-               outb(0,io);
+               dprintk(dev, 1, "Radio powered off\n");
+               outb(0, dev->io);
        }
 }
 
-static void set_freq(__u16 io, __u32 freq)
+static void set_freq(struct maxiradio *dev, u32 freq)
 {
        unsigned long int si;
        int bl;
+       int io = dev->io;
        int val = FREQ2BITS(freq);
 
        /* TEA5757 shift register bits (see pdf) */
@@ -188,14 +162,14 @@ static void set_freq(__u16 io, __u32 freq)
                si >>= 1;
        }
 
-       dprintk(1, "Radio freq set to %d.%02d MHz\n",
+       dprintk(dev, 1, "Radio freq set to %d.%02d MHz\n",
                                freq / 16000,
                                freq % 16000 * 100 / 16000);
 
-       turn_power(io, 1);
+       turn_power(dev, 1);
 }
 
-static int get_stereo(__u16 io)
+static int get_stereo(u16 io)
 {
        outb(power,io);
        udelay(4);
@@ -203,7 +177,7 @@ static int get_stereo(__u16 io)
        return !(inb(io) & mo_st);
 }
 
-static int get_tune(__u16 io)
+static int get_tune(u16 io)
 {
        outb(power+clk,io);
        udelay(4);
@@ -212,95 +186,84 @@ static int get_tune(__u16 io)
 }
 
 
-static int vidioc_querycap (struct file *file, void  *priv,
+static int vidioc_querycap(struct file *file, void  *priv,
                            struct v4l2_capability *v)
 {
-       strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver));
-       strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card));
-       sprintf(v->bus_info,"ISA");
-       v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER;
+       struct maxiradio *dev = video_drvdata(file);
 
+       strlcpy(v->driver, "radio-maxiradio", sizeof(v->driver));
+       strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof(v->card));
+       snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev));
+       v->version = RADIO_VERSION;
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
 
-static int vidioc_g_tuner (struct file *file, void *priv,
+static int vidioc_g_tuner(struct file *file, void *priv,
                           struct v4l2_tuner *v)
 {
-       struct radio_device *card = video_drvdata(file);
+       struct maxiradio *dev = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
 
-       memset(v,0,sizeof(*v));
-       strcpy(v->name, "FM");
+       mutex_lock(&dev->lock);
+       strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
-
-       v->rangelow=FREQ_LO;
-       v->rangehigh=FREQ_HI;
-       v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
-       v->capability=V4L2_TUNER_CAP_LOW;
-       if(get_stereo(card->io))
+       v->rangelow = FREQ_LO;
+       v->rangehigh = FREQ_HI;
+       v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+       v->capability = V4L2_TUNER_CAP_LOW;
+       if (get_stereo(dev->io))
                v->audmode = V4L2_TUNER_MODE_STEREO;
        else
                v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal=0xffff*get_tune(card->io);
+       v->signal = 0xffff * get_tune(dev->io);
+       mutex_unlock(&dev->lock);
 
        return 0;
 }
 
-static int vidioc_s_tuner (struct file *file, void *priv,
+static int vidioc_s_tuner(struct file *file, void *priv,
                           struct v4l2_tuner *v)
 {
-       if (v->index > 0)
-               return -EINVAL;
-
-       return 0;
-}
-
-static int vidioc_g_audio (struct file *file, void *priv,
-                          struct v4l2_audio *a)
-{
-       if (a->index > 1)
-               return -EINVAL;
-
-       strcpy(a->name, "FM");
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
+       return v->index ? -EINVAL : 0;
 }
 
 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 {
        *i = 0;
-
        return 0;
 }
 
 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-       if (i != 0)
-               return -EINVAL;
+       return i ? -EINVAL : 0;
+}
 
+static int vidioc_g_audio(struct file *file, void *priv,
+                          struct v4l2_audio *a)
+{
+       a->index = 0;
+       strlcpy(a->name, "Radio", sizeof(a->name));
+       a->capability = V4L2_AUDCAP_STEREO;
        return 0;
 }
 
 
-static int vidioc_s_audio (struct file *file, void *priv,
+static int vidioc_s_audio(struct file *file, void *priv,
                           struct v4l2_audio *a)
 {
-       if (a->index != 0)
-               return -EINVAL;
-
-       return 0;
+       return a->index ? -EINVAL : 0;
 }
 
-static int vidioc_s_frequency (struct file *file, void *priv,
+static int vidioc_s_frequency(struct file *file, void *priv,
                               struct v4l2_frequency *f)
 {
-       struct radio_device *card = video_drvdata(file);
+       struct maxiradio *dev = video_drvdata(file);
 
        if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) {
-               dprintk(1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
+               dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
                                        f->frequency / 16000,
                                        f->frequency % 16000 * 100 / 16000,
                                        FREQ_LO / 16000, FREQ_HI / 16000);
@@ -308,75 +271,91 @@ static int vidioc_s_frequency (struct file *file, void *priv,
                return -EINVAL;
        }
 
-       card->freq = f->frequency;
-       set_freq(card->io, card->freq);
+       mutex_lock(&dev->lock);
+       dev->freq = f->frequency;
+       set_freq(dev, dev->freq);
        msleep(125);
+       mutex_unlock(&dev->lock);
 
        return 0;
 }
 
-static int vidioc_g_frequency (struct file *file, void *priv,
+static int vidioc_g_frequency(struct file *file, void *priv,
                               struct v4l2_frequency *f)
 {
-       struct radio_device *card = video_drvdata(file);
+       struct maxiradio *dev = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
-       f->frequency = card->freq;
+       f->frequency = dev->freq;
 
-       dprintk(4, "radio freq is %d.%02d MHz",
+       dprintk(dev, 4, "radio freq is %d.%02d MHz",
                                f->frequency / 16000,
                                f->frequency % 16000 * 100 / 16000);
 
        return 0;
 }
 
-static int vidioc_queryctrl (struct file *file, void *priv,
+static int vidioc_queryctrl(struct file *file, void *priv,
                             struct v4l2_queryctrl *qc)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
-                       return (0);
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
        }
-
        return -EINVAL;
 }
 
-static int vidioc_g_ctrl (struct file *file, void *priv,
-                           struct v4l2_control *ctrl)
+static int vidioc_g_ctrl(struct file *file, void *priv,
+               struct v4l2_control *ctrl)
 {
-       struct radio_device *card = video_drvdata(file);
+       struct maxiradio *dev = video_drvdata(file);
 
        switch (ctrl->id) {
-               case V4L2_CID_AUDIO_MUTE:
-                       ctrl->value=card->muted;
-                       return (0);
+       case V4L2_CID_AUDIO_MUTE:
+               ctrl->value = dev->muted;
+               return 0;
        }
 
        return -EINVAL;
 }
 
-static int vidioc_s_ctrl (struct file *file, void *priv,
-                         struct v4l2_control *ctrl)
+static int vidioc_s_ctrl(struct file *file, void *priv,
+               struct v4l2_control *ctrl)
 {
-       struct radio_device *card = video_drvdata(file);
+       struct maxiradio *dev = video_drvdata(file);
 
        switch (ctrl->id) {
-               case V4L2_CID_AUDIO_MUTE:
-                       card->muted = ctrl->value;
-                       if(card->muted)
-                               turn_power(card->io, 0);
-                       else
-                               set_freq(card->io, card->freq);
-                       return 0;
+       case V4L2_CID_AUDIO_MUTE:
+               mutex_lock(&dev->lock);
+               dev->muted = ctrl->value;
+               if (dev->muted)
+                       turn_power(dev, 0);
+               else
+                       set_freq(dev, dev->freq);
+               mutex_unlock(&dev->lock);
+               return 0;
        }
 
        return -EINVAL;
 }
 
+static int maxiradio_open(struct file *file)
+{
+       return 0;
+}
+
+static int maxiradio_release(struct file *file)
+{
+       return 0;
+}
+
+static const struct v4l2_file_operations maxiradio_fops = {
+       .owner          = THIS_MODULE,
+       .open           = maxiradio_open,
+       .release        = maxiradio_release,
+       .ioctl          = video_ioctl2,
+};
+
 static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = {
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
@@ -392,60 +371,84 @@ static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = {
        .vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
-static struct video_device maxiradio_radio = {
-       .name           = "Maxi Radio FM2000 radio",
-       .fops           = &maxiradio_fops,
-       .ioctl_ops      = &maxiradio_ioctl_ops,
-       .release        = video_device_release_empty,
-};
-
 static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-       if(!request_region(pci_resource_start(pdev, 0),
+       struct maxiradio *dev;
+       struct v4l2_device *v4l2_dev;
+       int retval = -ENOMEM;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL) {
+               dev_err(&pdev->dev, "not enough memory\n");
+               return -ENOMEM;
+       }
+
+       v4l2_dev = &dev->v4l2_dev;
+       mutex_init(&dev->lock);
+       dev->pdev = pdev;
+       dev->muted = 1;
+       dev->freq = FREQ_LO;
+
+       strlcpy(v4l2_dev->name, "maxiradio", sizeof(v4l2_dev->name));
+
+       retval = v4l2_device_register(&pdev->dev, v4l2_dev);
+       if (retval < 0) {
+               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+               goto errfr;
+       }
+
+       if (!request_region(pci_resource_start(pdev, 0),
                           pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
-               printk(KERN_ERR "radio-maxiradio: can't reserve I/O ports\n");
+               v4l2_err(v4l2_dev, "can't reserve I/O ports\n");
                goto err_out;
        }
 
        if (pci_enable_device(pdev))
                goto err_out_free_region;
 
-       radio_unit.io = pci_resource_start(pdev, 0);
-       mutex_init(&radio_unit.lock);
-       video_set_drvdata(&maxiradio_radio, &radio_unit);
+       dev->io = pci_resource_start(pdev, 0);
+       strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
+       dev->vdev.v4l2_dev = v4l2_dev;
+       dev->vdev.fops = &maxiradio_fops;
+       dev->vdev.ioctl_ops = &maxiradio_ioctl_ops;
+       dev->vdev.release = video_device_release_empty;
+       video_set_drvdata(&dev->vdev, dev);
 
-       if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
-               printk("radio-maxiradio: can't register device!");
+       if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+               v4l2_err(v4l2_dev, "can't register device!");
                goto err_out_free_region;
        }
 
-       printk(KERN_INFO "radio-maxiradio: version "
-              DRIVER_VERSION
-              " time "
-              __TIME__ "  "
-              __DATE__
-              "\n");
+       v4l2_info(v4l2_dev, "version " DRIVER_VERSION
+                       " time " __TIME__ "  " __DATE__ "\n");
 
-       printk(KERN_INFO "radio-maxiradio: found Guillemot MAXI Radio device (io = 0x%x)\n",
-              radio_unit.io);
+       v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n",
+              dev->io);
        return 0;
 
 err_out_free_region:
        release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
 err_out:
+       v4l2_device_unregister(v4l2_dev);
+errfr:
+       kfree(dev);
        return -ENODEV;
 }
 
 static void __devexit maxiradio_remove_one(struct pci_dev *pdev)
 {
-       video_unregister_device(&maxiradio_radio);
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+       struct maxiradio *dev = to_maxiradio(v4l2_dev);
+
+       video_unregister_device(&dev->vdev);
+       v4l2_device_unregister(&dev->v4l2_dev);
        release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
 }
 
 static struct pci_device_id maxiradio_pci_tbl[] = {
        { PCI_VENDOR_ID_GUILLEMOT, PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO,
                PCI_ANY_ID, PCI_ANY_ID, },
-       { 0,}
+       { 0 }
 };
 
 MODULE_DEVICE_TABLE(pci, maxiradio_pci_tbl);
@@ -469,10 +472,3 @@ static void __exit maxiradio_radio_exit(void)
 
 module_init(maxiradio_radio_init);
 module_exit(maxiradio_radio_exit);
-
-MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
-MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
-MODULE_LICENSE("GPL");
-
-module_param_named(debug,maxiradio_radio.debug, int, 0644);
-MODULE_PARM_DESC(debug,"activates debug info");
index fdfc7bf86b9e15c498ea4fc57eef55f304e6f67c..ded25bfb366e7ccc748c60bdf17ba6685f668197 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 /*
- * Big thanks to authors of dsbr100.c and radio-si470x.c
+ * Big thanks to authors and contributors of dsbr100.c and radio-si470x.c
  *
  * When work was looked pretty good, i discover this:
  * http://av-usbradio.sourceforge.net/index.php
  * Latest release of theirs project was in 2005.
  * Probably, this driver could be improved trough using their
  * achievements (specifications given).
- * So, we have smth to begin with.
+ * Also, Faidon Liambotis <paravoid@debian.org> wrote nice driver for this radio
+ * in 2007. He allowed to use his driver to improve current mr800 radio driver.
+ * http://kerneltrap.org/mailarchive/linux-usb-devel/2007/10/11/342492
  *
- * History:
  * Version 0.01:       First working version.
  *                     It's required to blacklist AverMedia USB Radio
  *                     in usbhid/hid-quirks.c
+ * Version 0.10:       A lot of cleanups and fixes: unpluging the device,
+ *                     few mutex locks were added, codinstyle issues, etc.
+ *                     Added stereo support. Thanks to
+ *                     Douglas Schilling Landgraf <dougsland@gmail.com> and
+ *                     David Ellingsworth <david@identd.dyndns.org>
+ *                     for discussion, help and support.
  *
  * Many things to do:
  *     - Correct power managment of device (suspend & resume)
- *     - Make x86 independance (little-endian and big-endian stuff)
  *     - Add code for scanning and smooth tuning
- *     - Checked and add stereo&mono stuff
  *     - Add code for sensitivity value
  *     - Correct mistakes
  *     - In Japan another FREQ_MIN and FREQ_MAX
@@ -62,8 +67,8 @@
 /* driver and module definitions */
 #define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
 #define DRIVER_DESC "AverMedia MR 800 USB FM radio driver"
-#define DRIVER_VERSION "0.01"
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 1)
+#define DRIVER_VERSION "0.10"
+#define RADIO_VERSION KERNEL_VERSION(0, 1, 0)
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -87,6 +92,22 @@ devices, that would be 76 and 91.  */
 #define FREQ_MAX 108.0
 #define FREQ_MUL 16000
 
+/*
+ * Commands that device should understand
+ * List isnt full and will be updated with implementation of new functions
+ */
+#define AMRADIO_SET_FREQ       0xa4
+#define AMRADIO_SET_MUTE       0xab
+#define AMRADIO_SET_MONO       0xae
+
+/* Comfortable defines for amradio_set_mute */
+#define AMRADIO_START          0x00
+#define AMRADIO_STOP           0x01
+
+/* Comfortable defines for amradio_set_stereo */
+#define WANT_STEREO            0x00
+#define WANT_MONO              0x01
+
 /* module parameter */
 static int radio_nr = -1;
 module_param(radio_nr, int, 0);
@@ -169,43 +190,48 @@ static struct usb_driver usb_amradio_driver = {
        .supports_autosuspend   = 0,
 };
 
-/* switch on radio. Send 8 bytes to device. */
-static int amradio_start(struct amradio_device *radio)
+/* switch on/off the radio. Send 8 bytes to device */
+static int amradio_set_mute(struct amradio_device *radio, char argument)
 {
        int retval;
        int size;
 
+       /* safety check */
+       if (radio->removed)
+               return -EIO;
+
        mutex_lock(&radio->lock);
 
        radio->buffer[0] = 0x00;
        radio->buffer[1] = 0x55;
        radio->buffer[2] = 0xaa;
        radio->buffer[3] = 0x00;
-       radio->buffer[4] = 0xab;
-       radio->buffer[5] = 0x00;
+       radio->buffer[4] = AMRADIO_SET_MUTE;
+       radio->buffer[5] = argument;
        radio->buffer[6] = 0x00;
        radio->buffer[7] = 0x00;
 
        retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
                (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
 
-       if (retval) {
+       if (retval < 0 || size != BUFFER_LENGTH) {
                mutex_unlock(&radio->lock);
                return retval;
        }
 
-       radio->muted = 0;
+       radio->muted = argument;
 
        mutex_unlock(&radio->lock);
 
        return retval;
 }
 
-/* switch off radio */
-static int amradio_stop(struct amradio_device *radio)
+/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
+static int amradio_setfreq(struct amradio_device *radio, int freq)
 {
        int retval;
        int size;
+       unsigned short freq_send = 0x10 + (freq >> 3) / 25;
 
        /* safety check */
        if (radio->removed)
@@ -216,33 +242,46 @@ static int amradio_stop(struct amradio_device *radio)
        radio->buffer[0] = 0x00;
        radio->buffer[1] = 0x55;
        radio->buffer[2] = 0xaa;
-       radio->buffer[3] = 0x00;
-       radio->buffer[4] = 0xab;
-       radio->buffer[5] = 0x01;
+       radio->buffer[3] = 0x03;
+       radio->buffer[4] = AMRADIO_SET_FREQ;
+       radio->buffer[5] = 0x00;
        radio->buffer[6] = 0x00;
-       radio->buffer[7] = 0x00;
+       radio->buffer[7] = 0x08;
 
        retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
                (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
 
-       if (retval) {
+       if (retval < 0 || size != BUFFER_LENGTH) {
                mutex_unlock(&radio->lock);
                return retval;
        }
 
-       radio->muted = 1;
+       /* frequency is calculated from freq_send and placed in first 2 bytes */
+       radio->buffer[0] = (freq_send >> 8) & 0xff;
+       radio->buffer[1] = freq_send & 0xff;
+       radio->buffer[2] = 0x01;
+       radio->buffer[3] = 0x00;
+       radio->buffer[4] = 0x00;
+       /* 5 and 6 bytes of buffer already = 0x00 */
+       radio->buffer[7] = 0x00;
+
+       retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
+               (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+
+       if (retval < 0 || size != BUFFER_LENGTH) {
+               mutex_unlock(&radio->lock);
+               return retval;
+       }
 
        mutex_unlock(&radio->lock);
 
        return retval;
 }
 
-/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
-static int amradio_setfreq(struct amradio_device *radio, int freq)
+static int amradio_set_stereo(struct amradio_device *radio, char argument)
 {
        int retval;
        int size;
-       unsigned short freq_send = 0x13 + (freq >> 3) / 25;
 
        /* safety check */
        if (radio->removed)
@@ -253,50 +292,33 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
        radio->buffer[0] = 0x00;
        radio->buffer[1] = 0x55;
        radio->buffer[2] = 0xaa;
-       radio->buffer[3] = 0x03;
-       radio->buffer[4] = 0xa4;
-       radio->buffer[5] = 0x00;
-       radio->buffer[6] = 0x00;
-       radio->buffer[7] = 0x08;
-
-       retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
-               (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
-
-       if (retval) {
-               mutex_unlock(&radio->lock);
-               return retval;
-       }
-
-       /* frequency is calculated from freq_send and placed in first 2 bytes */
-       radio->buffer[0] = (freq_send >> 8) & 0xff;
-       radio->buffer[1] = freq_send & 0xff;
-       radio->buffer[2] = 0x01;
        radio->buffer[3] = 0x00;
-       radio->buffer[4] = 0x00;
-       /* 5 and 6 bytes of buffer already = 0x00 */
+       radio->buffer[4] = AMRADIO_SET_MONO;
+       radio->buffer[5] = argument;
+       radio->buffer[6] = 0x00;
        radio->buffer[7] = 0x00;
 
        retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
                (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
 
-       if (retval) {
+       if (retval < 0 || size != BUFFER_LENGTH) {
+               radio->stereo = -1;
                mutex_unlock(&radio->lock);
                return retval;
        }
 
-       radio->stereo = 0;
+       radio->stereo = 1;
 
        mutex_unlock(&radio->lock);
 
        return retval;
 }
 
-/* USB subsystem interface begins here */
-
-/* handle unplugging of the device, release data structures
-if nothing keeps us from doing it.  If something is still
-keeping us busy, the release callback of v4l will take care
-of releasing it. */
+/* Handle unplugging the device.
+ * We call video_unregister_device in any case.
+ * The last function called in this procedure is
+ * usb_amradio_device_release.
+ */
 static void usb_amradio_disconnect(struct usb_interface *intf)
 {
        struct amradio_device *radio = usb_get_intfdata(intf);
@@ -313,9 +335,11 @@ static void usb_amradio_disconnect(struct usb_interface *intf)
 static int vidioc_querycap(struct file *file, void *priv,
                                        struct v4l2_capability *v)
 {
+       struct amradio_device *radio = video_drvdata(file);
+
        strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
        strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
-       sprintf(v->bus_info, "USB");
+       usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
        v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER;
        return 0;
@@ -326,6 +350,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
        struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+       int retval;
 
        /* safety check */
        if (radio->removed)
@@ -337,7 +362,16 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 /* TODO: Add function which look is signal stereo or not
  *     amradio_getstat(radio);
  */
-       radio->stereo = -1;
+
+/* we call amradio_set_stereo to set radio->stereo
+ * Honestly, amradio_getstat should cover this in future and
+ * amradio_set_stereo shouldn't be here
+ */
+       retval = amradio_set_stereo(radio, WANT_STEREO);
+       if (retval < 0)
+               amradio_dev_warn(&radio->videodev->dev,
+                       "set stereo failed\n");
+
        strcpy(v->name, "FM");
        v->type = V4L2_TUNER_RADIO;
        v->rangelow = FREQ_MIN * FREQ_MUL;
@@ -358,6 +392,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
        struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+       int retval;
 
        /* safety check */
        if (radio->removed)
@@ -365,6 +400,25 @@ static int vidioc_s_tuner(struct file *file, void *priv,
 
        if (v->index > 0)
                return -EINVAL;
+
+       /* mono/stereo selector */
+       switch (v->audmode) {
+       case V4L2_TUNER_MODE_MONO:
+               retval = amradio_set_stereo(radio, WANT_MONO);
+               if (retval < 0)
+                       amradio_dev_warn(&radio->videodev->dev,
+                               "set mono failed\n");
+               break;
+       case V4L2_TUNER_MODE_STEREO:
+               retval = amradio_set_stereo(radio, WANT_STEREO);
+               if (retval < 0)
+                       amradio_dev_warn(&radio->videodev->dev,
+                               "set stereo failed\n");
+               break;
+       default:
+               return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -373,13 +427,18 @@ static int vidioc_s_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
        struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+       int retval;
 
        /* safety check */
        if (radio->removed)
                return -EIO;
 
+       mutex_lock(&radio->lock);
        radio->curfreq = f->frequency;
-       if (amradio_setfreq(radio, radio->curfreq) < 0)
+       mutex_unlock(&radio->lock);
+
+       retval = amradio_setfreq(radio, radio->curfreq);
+       if (retval < 0)
                amradio_dev_warn(&radio->videodev->dev,
                        "set frequency failed\n");
        return 0;
@@ -438,6 +497,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
        struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+       int retval;
 
        /* safety check */
        if (radio->removed)
@@ -446,13 +506,15 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
                if (ctrl->value) {
-                       if (amradio_stop(radio) < 0) {
+                       retval = amradio_set_mute(radio, AMRADIO_STOP);
+                       if (retval < 0) {
                                amradio_dev_warn(&radio->videodev->dev,
                                        "amradio_stop failed\n");
                                return -1;
                        }
                } else {
-                       if (amradio_start(radio) < 0) {
+                       retval = amradio_set_mute(radio, AMRADIO_START);
+                       if (retval < 0) {
                                amradio_dev_warn(&radio->videodev->dev,
                                        "amradio_start failed\n");
                                return -1;
@@ -503,20 +565,29 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 static int usb_amradio_open(struct file *file)
 {
        struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+       int retval;
 
        lock_kernel();
 
        radio->users = 1;
        radio->muted = 1;
 
-       if (amradio_start(radio) < 0) {
+       retval = amradio_set_mute(radio, AMRADIO_START);
+       if (retval < 0) {
                amradio_dev_warn(&radio->videodev->dev,
                        "radio did not start up properly\n");
                radio->users = 0;
                unlock_kernel();
                return -EIO;
        }
-       if (amradio_setfreq(radio, radio->curfreq) < 0)
+
+       retval = amradio_set_stereo(radio, WANT_STEREO);
+       if (retval < 0)
+               amradio_dev_warn(&radio->videodev->dev,
+                       "set stereo failed\n");
+
+       retval = amradio_setfreq(radio, radio->curfreq);
+       if (retval < 0)
                amradio_dev_warn(&radio->videodev->dev,
                        "set frequency failed\n");
 
@@ -533,10 +604,12 @@ static int usb_amradio_close(struct file *file)
        if (!radio)
                return -ENODEV;
 
+       mutex_lock(&radio->lock);
        radio->users = 0;
+       mutex_unlock(&radio->lock);
 
        if (!radio->removed) {
-               retval = amradio_stop(radio);
+               retval = amradio_set_mute(radio, AMRADIO_STOP);
                if (retval < 0)
                        amradio_dev_warn(&radio->videodev->dev,
                                "amradio_stop failed\n");
@@ -549,8 +622,10 @@ static int usb_amradio_close(struct file *file)
 static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct amradio_device *radio = usb_get_intfdata(intf);
+       int retval;
 
-       if (amradio_stop(radio) < 0)
+       retval = amradio_set_mute(radio, AMRADIO_STOP);
+       if (retval < 0)
                dev_warn(&intf->dev, "amradio_stop failed\n");
 
        dev_info(&intf->dev, "going into suspend..\n");
@@ -562,8 +637,10 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
 static int usb_amradio_resume(struct usb_interface *intf)
 {
        struct amradio_device *radio = usb_get_intfdata(intf);
+       int retval;
 
-       if (amradio_start(radio) < 0)
+       retval = amradio_set_mute(radio, AMRADIO_START);
+       if (retval < 0)
                dev_warn(&intf->dev, "amradio_start failed\n");
 
        dev_info(&intf->dev, "coming out of suspend..\n");
@@ -614,28 +691,32 @@ static struct video_device amradio_videodev_template = {
        .release        = usb_amradio_device_release,
 };
 
-/* check if the device is present and register with v4l and
-usb if it is */
+/* check if the device is present and register with v4l and usb if it is */
 static int usb_amradio_probe(struct usb_interface *intf,
                                const struct usb_device_id *id)
 {
        struct amradio_device *radio;
+       int retval;
 
        radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL);
 
-       if (!(radio))
+       if (!radio) {
+               dev_err(&intf->dev, "kmalloc for amradio_device failed\n");
                return -ENOMEM;
+       }
 
        radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
 
-       if (!(radio->buffer)) {
+       if (!radio->buffer) {
+               dev_err(&intf->dev, "kmalloc for radio->buffer failed\n");
                kfree(radio);
                return -ENOMEM;
        }
 
        radio->videodev = video_device_alloc();
 
-       if (!(radio->videodev)) {
+       if (!radio->videodev) {
+               dev_err(&intf->dev, "video_device_alloc failed\n");
                kfree(radio->buffer);
                kfree(radio);
                return -ENOMEM;
@@ -648,12 +729,14 @@ static int usb_amradio_probe(struct usb_interface *intf,
        radio->users = 0;
        radio->usbdev = interface_to_usbdev(intf);
        radio->curfreq = 95.16 * FREQ_MUL;
+       radio->stereo = -1;
 
        mutex_init(&radio->lock);
 
        video_set_drvdata(radio->videodev, radio);
-       if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
-               dev_warn(&intf->dev, "could not register video device\n");
+       retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
+       if (retval < 0) {
+               dev_err(&intf->dev, "could not register video device\n");
                video_device_release(radio->videodev);
                kfree(radio->buffer);
                kfree(radio);
index 2587227214bf8cfe54f0120f87683006239f2d02..d1e6b01d4eca76caa70818c051dd843d9d251459 100644 (file)
 #include <linux/init.h>                /* Initdata                     */
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
-#include <asm/io.h>            /* outb, outb_p                 */
-#include <asm/uaccess.h>       /* copy to/from user            */
 #include <linux/videodev2.h>   /* kernel radio structs         */
-#include <media/v4l2-common.h>
+#include <linux/mutex.h>
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#include <linux/io.h>          /* outb, outb_p                 */
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
-#include <linux/spinlock.h>
 
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
-
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_AUDIO_VOLUME,
-               .name          = "Volume",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 65535,
-               .default_value = 0xff,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       }
-};
+MODULE_AUTHOR("Ben Pfaff");
+MODULE_DESCRIPTION("A driver for the RadioTrack II radio card.");
+MODULE_LICENSE("GPL");
 
 #ifndef CONFIG_RADIO_RTRACK2_PORT
 #define CONFIG_RADIO_RTRACK2_PORT -1
@@ -48,79 +30,88 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 
 static int io = CONFIG_RADIO_RTRACK2_PORT;
 static int radio_nr = -1;
-static spinlock_t lock;
 
-struct rt_device
+module_param(io, int, 0);
+MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)");
+module_param(radio_nr, int, 0);
+
+#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
+
+struct rtrack2
 {
-       unsigned long in_use;
-       int port;
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       int io;
        unsigned long curfreq;
        int muted;
+       struct mutex lock;
 };
 
+static struct rtrack2 rtrack2_card;
+
 
 /* local things */
 
-static void rt_mute(struct rt_device *dev)
+static void rt_mute(struct rtrack2 *dev)
 {
-       if(dev->muted)
+       if (dev->muted)
                return;
-       spin_lock(&lock);
-       outb(1, io);
-       spin_unlock(&lock);
+       mutex_lock(&dev->lock);
+       outb(1, dev->io);
+       mutex_unlock(&dev->lock);
        dev->muted = 1;
 }
 
-static void rt_unmute(struct rt_device *dev)
+static void rt_unmute(struct rtrack2 *dev)
 {
        if(dev->muted == 0)
                return;
-       spin_lock(&lock);
-       outb(0, io);
-       spin_unlock(&lock);
+       mutex_lock(&dev->lock);
+       outb(0, dev->io);
+       mutex_unlock(&dev->lock);
        dev->muted = 0;
 }
 
-static void zero(void)
+static void zero(struct rtrack2 *dev)
 {
-       outb_p(1, io);
-       outb_p(3, io);
-       outb_p(1, io);
+       outb_p(1, dev->io);
+       outb_p(3, dev->io);
+       outb_p(1, dev->io);
 }
 
-static void one(void)
+static void one(struct rtrack2 *dev)
 {
-       outb_p(5, io);
-       outb_p(7, io);
-       outb_p(5, io);
+       outb_p(5, dev->io);
+       outb_p(7, dev->io);
+       outb_p(5, dev->io);
 }
 
-static int rt_setfreq(struct rt_device *dev, unsigned long freq)
+static int rt_setfreq(struct rtrack2 *dev, unsigned long freq)
 {
        int i;
 
+       mutex_lock(&dev->lock);
+       dev->curfreq = freq;
        freq = freq / 200 + 856;
 
-       spin_lock(&lock);
-
-       outb_p(0xc8, io);
-       outb_p(0xc9, io);
-       outb_p(0xc9, io);
+       outb_p(0xc8, dev->io);
+       outb_p(0xc9, dev->io);
+       outb_p(0xc9, dev->io);
 
        for (i = 0; i < 10; i++)
-               zero ();
+               zero(dev);
 
        for (i = 14; i >= 0; i--)
                if (freq & (1 << i))
-                       one ();
+                       one(dev);
                else
-                       zero ();
+                       zero(dev);
 
-       outb_p(0xc8, io);
+       outb_p(0xc8, dev->io);
        if (!dev->muted)
-               outb_p(0, io);
+               outb_p(0, dev->io);
 
-       spin_unlock(&lock);
+       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -129,61 +120,61 @@ static int vidioc_querycap(struct file *file, void *priv,
 {
        strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver));
        strlcpy(v->card, "RadioTrack II", sizeof(v->card));
-       sprintf(v->bus_info, "ISA");
+       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
        v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER;
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
 
 static int vidioc_s_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
-       if (v->index > 0)
-               return -EINVAL;
-
-       return 0;
+       return v->index ? -EINVAL : 0;
 }
 
-static int rt_getsigstr(struct rt_device *dev)
+static int rt_getsigstr(struct rtrack2 *dev)
 {
-       if (inb(io) & 2)        /* bit set = no signal present  */
-               return 0;
-       return 1;               /* signal present               */
+       int sig = 1;
+
+       mutex_lock(&dev->lock);
+       if (inb(dev->io) & 2)   /* bit set = no signal present  */
+               sig = 0;
+       mutex_unlock(&dev->lock);
+       return sig;
 }
 
 static int vidioc_g_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
-       struct rt_device *rt = video_drvdata(file);
+       struct rtrack2 *rt = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
 
-       strcpy(v->name, "FM");
+       strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
-       v->rangelow = (88*16000);
-       v->rangehigh = (108*16000);
+       v->rangelow = 88 * 16000;
+       v->rangehigh = 108 * 16000;
        v->rxsubchans = V4L2_TUNER_SUB_MONO;
        v->capability = V4L2_TUNER_CAP_LOW;
        v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = 0xFFFF*rt_getsigstr(rt);
+       v->signal = 0xFFFF * rt_getsigstr(rt);
        return 0;
 }
 
 static int vidioc_s_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       struct rt_device *rt = video_drvdata(file);
+       struct rtrack2 *rt = video_drvdata(file);
 
-       rt->curfreq = f->frequency;
-       rt_setfreq(rt, rt->curfreq);
+       rt_setfreq(rt, f->frequency);
        return 0;
 }
 
 static int vidioc_g_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       struct rt_device *rt = video_drvdata(file);
+       struct rtrack2 *rt = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = rt->curfreq;
@@ -193,14 +184,11 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 static int vidioc_queryctrl(struct file *file, void *priv,
                                struct v4l2_queryctrl *qc)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]),
-                                               sizeof(*qc));
-                       return 0;
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+       case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535);
        }
        return -EINVAL;
 }
@@ -208,7 +196,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
-       struct rt_device *rt = video_drvdata(file);
+       struct rtrack2 *rt = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -227,7 +215,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
-       struct rt_device *rt = video_drvdata(file);
+       struct rtrack2 *rt = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -246,17 +234,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        return -EINVAL;
 }
 
-static int vidioc_g_audio(struct file *file, void *priv,
-                               struct v4l2_audio *a)
-{
-       if (a->index > 1)
-               return -EINVAL;
-
-       strcpy(a->name, "Radio");
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 {
        *i = 0;
@@ -265,36 +242,38 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 
 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-       if (i != 0)
-               return -EINVAL;
-       return 0;
+       return i ? -EINVAL : 0;
 }
 
-static int vidioc_s_audio(struct file *file, void *priv,
+static int vidioc_g_audio(struct file *file, void *priv,
                                struct v4l2_audio *a)
 {
-       if (a->index != 0)
-               return -EINVAL;
+       a->index = 0;
+       strlcpy(a->name, "Radio", sizeof(a->name));
+       a->capability = V4L2_AUDCAP_STEREO;
        return 0;
 }
 
-static struct rt_device rtrack2_unit;
+static int vidioc_s_audio(struct file *file, void *priv,
+                               struct v4l2_audio *a)
+{
+       return a->index ? -EINVAL : 0;
+}
 
-static int rtrack2_exclusive_open(struct file *file)
+static int rtrack2_open(struct file *file)
 {
-       return test_and_set_bit(0, &rtrack2_unit.in_use) ? -EBUSY : 0;
+       return 0;
 }
 
-static int rtrack2_exclusive_release(struct file *file)
+static int rtrack2_release(struct file *file)
 {
-       clear_bit(0, &rtrack2_unit.in_use);
        return 0;
 }
 
 static const struct v4l2_file_operations rtrack2_fops = {
        .owner          = THIS_MODULE,
-       .open           = rtrack2_exclusive_open,
-       .release        = rtrack2_exclusive_release,
+       .open           = rtrack2_open,
+       .release        = rtrack2_release,
        .ioctl          = video_ioctl2,
 };
 
@@ -313,62 +292,61 @@ static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = {
        .vidioc_s_input     = vidioc_s_input,
 };
 
-static struct video_device rtrack2_radio = {
-       .name           = "RadioTrack II radio",
-       .fops           = &rtrack2_fops,
-       .ioctl_ops      = &rtrack2_ioctl_ops,
-       .release        = video_device_release_empty,
-};
-
 static int __init rtrack2_init(void)
 {
-       if(io==-1)
-       {
-               printk(KERN_ERR "You must set an I/O address with io=0x20c or io=0x30c\n");
+       struct rtrack2 *dev = &rtrack2_card;
+       struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
+       int res;
+
+       strlcpy(v4l2_dev->name, "rtrack2", sizeof(v4l2_dev->name));
+       dev->io = io;
+       if (dev->io == -1) {
+               v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or io=0x30c\n");
                return -EINVAL;
        }
-       if (!request_region(io, 4, "rtrack2"))
-       {
-               printk(KERN_ERR "rtrack2: port 0x%x already in use\n", io);
+       if (!request_region(dev->io, 4, "rtrack2")) {
+               v4l2_err(v4l2_dev, "port 0x%x already in use\n", dev->io);
                return -EBUSY;
        }
 
-       video_set_drvdata(&rtrack2_radio, &rtrack2_unit);
+       res = v4l2_device_register(NULL, v4l2_dev);
+       if (res < 0) {
+               release_region(dev->io, 4);
+               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+               return res;
+       }
 
-       spin_lock_init(&lock);
-       if (video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
-               release_region(io, 4);
+       strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
+       dev->vdev.v4l2_dev = v4l2_dev;
+       dev->vdev.fops = &rtrack2_fops;
+       dev->vdev.ioctl_ops = &rtrack2_ioctl_ops;
+       dev->vdev.release = video_device_release_empty;
+       video_set_drvdata(&dev->vdev, dev);
+
+       mutex_init(&dev->lock);
+       if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+               v4l2_device_unregister(v4l2_dev);
+               release_region(dev->io, 4);
                return -EINVAL;
        }
 
-       printk(KERN_INFO "AIMSlab Radiotrack II card driver.\n");
+       v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n");
 
        /* mute card - prevents noisy bootups */
-       outb(1, io);
-       rtrack2_unit.muted = 1;
+       outb(1, dev->io);
+       dev->muted = 1;
 
        return 0;
 }
 
-MODULE_AUTHOR("Ben Pfaff");
-MODULE_DESCRIPTION("A driver for the RadioTrack II radio card.");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)");
-module_param(radio_nr, int, 0);
-
-static void __exit rtrack2_cleanup_module(void)
+static void __exit rtrack2_exit(void)
 {
-       video_unregister_device(&rtrack2_radio);
-       release_region(io,4);
+       struct rtrack2 *dev = &rtrack2_card;
+
+       video_unregister_device(&dev->vdev);
+       v4l2_device_unregister(&dev->v4l2_dev);
+       release_region(dev->io, 4);
 }
 
 module_init(rtrack2_init);
-module_exit(rtrack2_cleanup_module);
-
-/*
-  Local variables:
-  compile-command: "mmake"
-  End:
-*/
+module_exit(rtrack2_exit);
index d358e48c242286d0d9cf45768236e8473d64e8a0..f4784f0d1a887a1cb63cfa5d2411168a4a0a535c 100644 (file)
 #include <linux/init.h>                /* Initdata                     */
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
-#include <linux/videodev2.h>   /* kernel radio structs         */
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
 #include <linux/isapnp.h>
-#include <asm/io.h>            /* outb, outb_p                 */
-#include <asm/uaccess.h>       /* copy to/from user            */
 #include <linux/mutex.h>
+#include <linux/videodev2.h>   /* kernel radio structs         */
+#include <linux/io.h>          /* outb, outb_p                 */
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
 
-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
+MODULE_DESCRIPTION("A driver for the SF16MI radio.");
+MODULE_LICENSE("GPL");
 
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       }
-};
+static int io = -1;
+static int radio_nr = -1;
+
+module_param(io, int, 0);
+MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)");
+module_param(radio_nr, int, 0);
+
+#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
 
-struct fmi_device
+struct fmi
 {
-       unsigned long in_use;
-       int port;
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       int io;
        int curvol; /* 1 or 0 */
        unsigned long curfreq; /* freq in kHz */
        __u32 flags;
+       struct mutex lock;
 };
 
-static int io = -1;
-static int radio_nr = -1;
-static struct pnp_dev *dev = NULL;
-static struct mutex lock;
+static struct fmi fmi_card;
+static struct pnp_dev *dev;
 
 /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
 /* It is only useful to give freq in intervall of 800 (=0.05Mhz),
  * other bits will be truncated, e.g 92.7400016 -> 92.7, but
  * 92.7400017 -> 92.75
  */
-#define RSF16_ENCODE(x)        ((x)/800+214)
-#define RSF16_MINFREQ 87*16000
-#define RSF16_MAXFREQ 108*16000
+#define RSF16_ENCODE(x)        ((x) / 800 + 214)
+#define RSF16_MINFREQ (87 * 16000)
+#define RSF16_MAXFREQ (108 * 16000)
 
-static void outbits(int bits, unsigned int data, int port)
+static void outbits(int bits, unsigned int data, int io)
 {
-       while(bits--) {
-               if(data & 1) {
-                       outb(5, port);
+       while (bits--) {
+               if (data & 1) {
+                       outb(5, io);
                        udelay(6);
-                       outb(7, port);
+                       outb(7, io);
                        udelay(6);
                } else {
-                       outb(1, port);
+                       outb(1, io);
                        udelay(6);
-                       outb(3, port);
+                       outb(3, io);
                        udelay(6);
                }
-               data>>=1;
+               data >>= 1;
        }
 }
 
-static inline void fmi_mute(int port)
+static inline void fmi_mute(struct fmi *fmi)
 {
-       mutex_lock(&lock);
-       outb(0x00, port);
-       mutex_unlock(&lock);
+       mutex_lock(&fmi->lock);
+       outb(0x00, fmi->io);
+       mutex_unlock(&fmi->lock);
 }
 
-static inline void fmi_unmute(int port)
+static inline void fmi_unmute(struct fmi *fmi)
 {
-       mutex_lock(&lock);
-       outb(0x08, port);
-       mutex_unlock(&lock);
+       mutex_lock(&fmi->lock);
+       outb(0x08, fmi->io);
+       mutex_unlock(&fmi->lock);
 }
 
-static inline int fmi_setfreq(struct fmi_device *dev)
+static inline int fmi_setfreq(struct fmi *fmi, unsigned long freq)
 {
-       int myport = dev->port;
-       unsigned long freq = dev->curfreq;
+       mutex_lock(&fmi->lock);
+       fmi->curfreq = freq;
 
-       mutex_lock(&lock);
-
-       outbits(16, RSF16_ENCODE(freq), myport);
-       outbits(8, 0xC0, myport);
+       outbits(16, RSF16_ENCODE(freq), fmi->io);
+       outbits(8, 0xC0, fmi->io);
        msleep(143);            /* was schedule_timeout(HZ/7) */
-       mutex_unlock(&lock);
-       if (dev->curvol) fmi_unmute(myport);
+       mutex_unlock(&fmi->lock);
+       if (fmi->curvol)
+               fmi_unmute(fmi);
        return 0;
 }
 
-static inline int fmi_getsigstr(struct fmi_device *dev)
+static inline int fmi_getsigstr(struct fmi *fmi)
 {
        int val;
        int res;
-       int myport = dev->port;
-
 
-       mutex_lock(&lock);
-       val = dev->curvol ? 0x08 : 0x00;        /* unmute/mute */
-       outb(val, myport);
-       outb(val | 0x10, myport);
+       mutex_lock(&fmi->lock);
+       val = fmi->curvol ? 0x08 : 0x00;        /* unmute/mute */
+       outb(val, fmi->io);
+       outb(val | 0x10, fmi->io);
        msleep(143);            /* was schedule_timeout(HZ/7) */
-       res = (int)inb(myport+1);
-       outb(val, myport);
+       res = (int)inb(fmi->io + 1);
+       outb(val, fmi->io);
 
-       mutex_unlock(&lock);
+       mutex_unlock(&fmi->lock);
        return (res & 2) ? 0 : 0xFFFF;
 }
 
@@ -137,9 +133,9 @@ static int vidioc_querycap(struct file *file, void  *priv,
 {
        strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver));
        strlcpy(v->card, "SF16-FMx radio", sizeof(v->card));
-       sprintf(v->bus_info, "ISA");
+       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
        v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER;
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
 
@@ -147,18 +143,18 @@ static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
        int mult;
-       struct fmi_device *fmi = video_drvdata(file);
+       struct fmi *fmi = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
 
-       strcpy(v->name, "FM");
+       strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
        mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
-       v->rangelow = RSF16_MINFREQ/mult;
-       v->rangehigh = RSF16_MAXFREQ/mult;
+       v->rangelow = RSF16_MINFREQ / mult;
+       v->rangehigh = RSF16_MAXFREQ / mult;
        v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
-       v->capability = fmi->flags&V4L2_TUNER_CAP_LOW;
+       v->capability = fmi->flags & V4L2_TUNER_CAP_LOW;
        v->audmode = V4L2_TUNER_MODE_STEREO;
        v->signal = fmi_getsigstr(fmi);
        return 0;
@@ -167,32 +163,29 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 static int vidioc_s_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       if (v->index > 0)
-               return -EINVAL;
-       return 0;
+       return v->index ? -EINVAL : 0;
 }
 
 static int vidioc_s_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct fmi_device *fmi = video_drvdata(file);
+       struct fmi *fmi = video_drvdata(file);
 
        if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
                f->frequency *= 1000;
        if (f->frequency < RSF16_MINFREQ ||
-                       f->frequency > RSF16_MAXFREQ )
+                       f->frequency > RSF16_MAXFREQ)
                return -EINVAL;
-       /*rounding in steps of 800 to match th freq
-       that will be used */
-       fmi->curfreq = (f->frequency/800)*800;
-       fmi_setfreq(fmi);
+       /* rounding in steps of 800 to match the freq
+          that will be used */
+       fmi_setfreq(fmi, (f->frequency / 800) * 800);
        return 0;
 }
 
 static int vidioc_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct fmi_device *fmi = video_drvdata(file);
+       struct fmi *fmi = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = fmi->curfreq;
@@ -204,14 +197,9 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 static int vidioc_queryctrl(struct file *file, void *priv,
                                        struct v4l2_queryctrl *qc)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]),
-                                               sizeof(*qc));
-                       return 0;
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
        }
        return -EINVAL;
 }
@@ -219,7 +207,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct fmi_device *fmi = video_drvdata(file);
+       struct fmi *fmi = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -232,31 +220,20 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct fmi_device *fmi = video_drvdata(file);
+       struct fmi *fmi = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
                if (ctrl->value)
-                       fmi_mute(fmi->port);
+                       fmi_mute(fmi);
                else
-                       fmi_unmute(fmi->port);
+                       fmi_unmute(fmi);
                fmi->curvol = ctrl->value;
                return 0;
        }
        return -EINVAL;
 }
 
-static int vidioc_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       if (a->index > 1)
-               return -EINVAL;
-
-       strcpy(a->name, "Radio");
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 {
        *i = 0;
@@ -265,36 +242,38 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 
 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-       if (i != 0)
-               return -EINVAL;
-       return 0;
+       return i ? -EINVAL : 0;
 }
 
-static int vidioc_s_audio(struct file *file, void *priv,
+static int vidioc_g_audio(struct file *file, void *priv,
                                        struct v4l2_audio *a)
 {
-       if (a->index != 0)
-               return -EINVAL;
+       a->index = 0;
+       strlcpy(a->name, "Radio", sizeof(a->name));
+       a->capability = V4L2_AUDCAP_STEREO;
        return 0;
 }
 
-static struct fmi_device fmi_unit;
+static int vidioc_s_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       return a->index ? -EINVAL : 0;
+}
 
-static int fmi_exclusive_open(struct file *file)
+static int fmi_open(struct file *file)
 {
-       return test_and_set_bit(0, &fmi_unit.in_use) ? -EBUSY : 0;
+       return 0;
 }
 
-static int fmi_exclusive_release(struct file *file)
+static int fmi_release(struct file *file)
 {
-       clear_bit(0, &fmi_unit.in_use);
        return 0;
 }
 
 static const struct v4l2_file_operations fmi_fops = {
        .owner          = THIS_MODULE,
-       .open           = fmi_exclusive_open,
-       .release        = fmi_exclusive_release,
+       .open           = fmi_open,
+       .release        = fmi_release,
        .ioctl          = video_ioctl2,
 };
 
@@ -313,13 +292,6 @@ static const struct v4l2_ioctl_ops fmi_ioctl_ops = {
        .vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
-static struct video_device fmi_radio = {
-       .name           = "SF16FMx radio",
-       .fops           = &fmi_fops,
-       .ioctl_ops      = &fmi_ioctl_ops,
-       .release        = video_device_release_empty,
-};
-
 /* ladis: this is my card. does any other types exist? */
 static struct isapnp_device_id id_table[] __devinitdata = {
        {       ISAPNP_ANY_ID, ISAPNP_ANY_ID,
@@ -344,7 +316,7 @@ static int __init isapnp_fmi_probe(void)
        if (pnp_device_attach(dev) < 0)
                return -EAGAIN;
        if (pnp_activate_dev(dev) < 0) {
-               printk ("radio-sf16fmi: PnP configure failed (out of resources?)\n");
+               printk(KERN_ERR "radio-sf16fmi: PnP configure failed (out of resources?)\n");
                pnp_device_detach(dev);
                return -ENOMEM;
        }
@@ -354,59 +326,72 @@ static int __init isapnp_fmi_probe(void)
        }
 
        i = pnp_port_start(dev, 0);
-       printk ("radio-sf16fmi: PnP reports card at %#x\n", i);
+       printk(KERN_INFO "radio-sf16fmi: PnP reports card at %#x\n", i);
 
        return i;
 }
 
 static int __init fmi_init(void)
 {
+       struct fmi *fmi = &fmi_card;
+       struct v4l2_device *v4l2_dev = &fmi->v4l2_dev;
+       int res;
+
        if (io < 0)
                io = isapnp_fmi_probe();
-       if (io < 0) {
-               printk(KERN_ERR "radio-sf16fmi: No PnP card found.\n");
-               return io;
+       strlcpy(v4l2_dev->name, "sf16fmi", sizeof(v4l2_dev->name));
+       fmi->io = io;
+       if (fmi->io < 0) {
+               v4l2_err(v4l2_dev, "No PnP card found.\n");
+               return fmi->io;
        }
        if (!request_region(io, 2, "radio-sf16fmi")) {
-               printk(KERN_ERR "radio-sf16fmi: port 0x%x already in use\n", io);
+               v4l2_err(v4l2_dev, "port 0x%x already in use\n", fmi->io);
                pnp_device_detach(dev);
                return -EBUSY;
        }
 
-       fmi_unit.port = io;
-       fmi_unit.curvol = 0;
-       fmi_unit.curfreq = 0;
-       fmi_unit.flags = V4L2_TUNER_CAP_LOW;
-       video_set_drvdata(&fmi_radio, &fmi_unit);
+       res = v4l2_device_register(NULL, v4l2_dev);
+       if (res < 0) {
+               release_region(fmi->io, 2);
+               pnp_device_detach(dev);
+               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+               return res;
+       }
+
+       fmi->flags = V4L2_TUNER_CAP_LOW;
+       strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name));
+       fmi->vdev.v4l2_dev = v4l2_dev;
+       fmi->vdev.fops = &fmi_fops;
+       fmi->vdev.ioctl_ops = &fmi_ioctl_ops;
+       fmi->vdev.release = video_device_release_empty;
+       video_set_drvdata(&fmi->vdev, fmi);
 
-       mutex_init(&lock);
+       mutex_init(&fmi->lock);
 
-       if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
-               release_region(io, 2);
+       if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+               v4l2_device_unregister(v4l2_dev);
+               release_region(fmi->io, 2);
+               pnp_device_detach(dev);
                return -EINVAL;
        }
 
-       printk(KERN_INFO "SF16FMx radio card driver at 0x%x\n", io);
+       v4l2_info(v4l2_dev, "card driver at 0x%x\n", fmi->io);
        /* mute card - prevents noisy bootups */
-       fmi_mute(io);
+       fmi_mute(fmi);
        return 0;
 }
 
-MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
-MODULE_DESCRIPTION("A driver for the SF16MI radio.");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)");
-module_param(radio_nr, int, 0);
-
-static void __exit fmi_cleanup_module(void)
+static void __exit fmi_exit(void)
 {
-       video_unregister_device(&fmi_radio);
-       release_region(io, 2);
+       struct fmi *fmi = &fmi_card;
+
+       video_unregister_device(&fmi->vdev);
+       v4l2_device_unregister(&fmi->v4l2_dev);
+       release_region(fmi->io, 2);
        if (dev)
                pnp_device_detach(dev);
 }
 
 module_init(fmi_init);
-module_exit(fmi_cleanup_module);
+module_exit(fmi_exit);
index 92f17a347fa73baf2fa12fe7524d2cacd9dbd6a7..0ba9d88a80fc06d155100ae92bb41b6d102f3474 100644 (file)
 #include <linux/init.h>                /* Initdata                     */
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
-#include <asm/io.h>            /* outb, outb_p                 */
-#include <asm/uaccess.h>       /* copy to/from user            */
 #include <linux/videodev2.h>   /* kernel radio structs         */
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
 #include <linux/mutex.h>
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#include <linux/io.h>          /* outb, outb_p                 */
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
 
-static struct mutex lock;
+MODULE_AUTHOR("Ziglio Frediano, freddy77@angelfire.com");
+MODULE_DESCRIPTION("A driver for the SF16FMR2 radio.");
+MODULE_LICENSE("GPL");
+
+static int io = 0x384;
+static int radio_nr = -1;
+
+module_param(io, int, 0);
+MODULE_PARM_DESC(io, "I/O address of the SF16FMR2 card (should be 0x384, if do not work try 0x284)");
+module_param(radio_nr, int, 0);
 
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #define RADIO_VERSION KERNEL_VERSION(0,0,2)
 
 #define AUD_VOL_INDEX 1
 
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },
-       [AUD_VOL_INDEX] = {
-               .id            = V4L2_CID_AUDIO_VOLUME,
-               .name          = "Volume",
-               .minimum       = 0,
-               .maximum       = 15,
-               .step          = 1,
-               .default_value = 0,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       }
-};
-
 #undef DEBUG
 //#define DEBUG 1
 
@@ -62,156 +50,160 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 #endif
 
 /* this should be static vars for module size */
-struct fmr2_device
+struct fmr2
 {
-       unsigned long in_use;
-       int port;
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       struct mutex lock;
+       int io;
        int curvol; /* 0-15 */
        int mute;
        int stereo; /* card is producing stereo audio */
        unsigned long curfreq; /* freq in kHz */
        int card_type;
-       __u32 flags;
+       u32 flags;
 };
 
-static int io = 0x384;
-static int radio_nr = -1;
+static struct fmr2 fmr2_card;
 
 /* hw precision is 12.5 kHz
  * It is only useful to give freq in intervall of 200 (=0.0125Mhz),
  * other bits will be truncated
  */
-#define RSF16_ENCODE(x)        ((x)/200+856)
-#define RSF16_MINFREQ 87*16000
-#define RSF16_MAXFREQ 108*16000
+#define RSF16_ENCODE(x)        ((x) / 200 + 856)
+#define RSF16_MINFREQ (87 * 16000)
+#define RSF16_MAXFREQ (108 * 16000)
 
-static inline void wait(int n,int port)
+static inline void wait(int n, int io)
 {
-       for (;n;--n) inb(port);
+       for (; n; --n)
+               inb(io);
 }
 
-static void outbits(int bits, unsigned int data, int nWait, int port)
+static void outbits(int bits, unsigned int data, int nWait, int io)
 {
        int bit;
-       for(;--bits>=0;) {
-               bit = (data>>bits) & 1;
-               outb(bit,port);
-               wait(nWait,port);
-               outb(bit|2,port);
-               wait(nWait,port);
-               outb(bit,port);
-               wait(nWait,port);
+
+       for (; --bits >= 0;) {
+               bit = (data >> bits) & 1;
+               outb(bit, io);
+               wait(nWait, io);
+               outb(bit | 2, io);
+               wait(nWait, io);
+               outb(bit, io);
+               wait(nWait, io);
        }
 }
 
-static inline void fmr2_mute(int port)
+static inline void fmr2_mute(int io)
 {
-       outb(0x00, port);
-       wait(4,port);
+       outb(0x00, io);
+       wait(4, io);
 }
 
-static inline void fmr2_unmute(int port)
+static inline void fmr2_unmute(int io)
 {
-       outb(0x04, port);
-       wait(4,port);
+       outb(0x04, io);
+       wait(4, io);
 }
 
-static inline int fmr2_stereo_mode(int port)
+static inline int fmr2_stereo_mode(int io)
 {
-       int n = inb(port);
-       outb(6,port);
-       inb(port);
-       n = ((n>>3)&1)^1;
+       int n = inb(io);
+
+       outb(6, io);
+       inb(io);
+       n = ((n >> 3) & 1) ^ 1;
        debug_print((KERN_DEBUG "stereo: %d\n", n));
        return n;
 }
 
-static int fmr2_product_info(struct fmr2_device *dev)
+static int fmr2_product_info(struct fmr2 *dev)
 {
-       int n = inb(dev->port);
+       int n = inb(dev->io);
+
        n &= 0xC1;
-       if (n == 0)
-       {
+       if (n == 0) {
                /* this should support volume set */
                dev->card_type = 12;
                return 0;
        }
        /* not volume (mine is 11) */
-       dev->card_type = (n==128)?11:0;
+       dev->card_type = (n == 128) ? 11 : 0;
        return n;
 }
 
-static inline int fmr2_getsigstr(struct fmr2_device *dev)
+static inline int fmr2_getsigstr(struct fmr2 *dev)
 {
-       /* !!! work only if scanning freq */
-       int port = dev->port, res = 0xffff;
-       outb(5,port);
-       wait(4,port);
-       if (!(inb(port)&1)) res = 0;
+       /* !!! works only if scanning freq */
+       int res = 0xffff;
+
+       outb(5, dev->io);
+       wait(4, dev->io);
+       if (!(inb(dev->io) & 1))
+               res = 0;
        debug_print((KERN_DEBUG "signal: %d\n", res));
        return res;
 }
 
 /* set frequency and unmute card */
-static int fmr2_setfreq(struct fmr2_device *dev)
+static int fmr2_setfreq(struct fmr2 *dev)
 {
-       int port = dev->port;
        unsigned long freq = dev->curfreq;
 
-       fmr2_mute(port);
+       fmr2_mute(dev->io);
 
        /* 0x42 for mono output
         * 0x102 forward scanning
         * 0x182 scansione avanti
         */
-       outbits(9,0x2,3,port);
-       outbits(16,RSF16_ENCODE(freq),2,port);
+       outbits(9, 0x2, 3, dev->io);
+       outbits(16, RSF16_ENCODE(freq), 2, dev->io);
 
-       fmr2_unmute(port);
+       fmr2_unmute(dev->io);
 
        /* wait 0.11 sec */
        msleep(110);
 
        /* NOTE if mute this stop radio
           you must set freq on unmute */
-       dev->stereo = fmr2_stereo_mode(port);
+       dev->stereo = fmr2_stereo_mode(dev->io);
        return 0;
 }
 
 /* !!! not tested, in my card this does't work !!! */
-static int fmr2_setvolume(struct fmr2_device *dev)
+static int fmr2_setvolume(struct fmr2 *dev)
 {
        int vol[16] = { 0x021, 0x084, 0x090, 0x104,
                        0x110, 0x204, 0x210, 0x402,
                        0x404, 0x408, 0x410, 0x801,
                        0x802, 0x804, 0x808, 0x810 };
-       int i, a, port = dev->port;
+       int i, a;
        int n = vol[dev->curvol & 0x0f];
 
        if (dev->card_type != 11)
                return 1;
 
        for (i = 12; --i >= 0; ) {
-               a = ((n >> i) & 1) << 6; /* if (a=0) a= 0; else a= 0x40; */
-               outb(a | 4, port);
-               wait(4, port);
-               outb(a | 0x24, port);
-               wait(4, port);
-               outb(a | 4, port);
-               wait(4, port);
+               a = ((n >> i) & 1) << 6; /* if (a==0) a = 0; else a = 0x40; */
+               outb(a | 4, dev->io);
+               wait(4, dev->io);
+               outb(a | 0x24, dev->io);
+               wait(4, dev->io);
+               outb(a | 4, dev->io);
+               wait(4, dev->io);
        }
        for (i = 6; --i >= 0; ) {
                a = ((0x18 >> i) & 1) << 6;
-               outb(a | 4, port);
-               wait(4,port);
-               outb(a | 0x24, port);
-               wait(4,port);
-               outb(a|4, port);
-               wait(4,port);
+               outb(a | 4, dev->io);
+               wait(4, dev->io);
+               outb(a | 0x24, dev->io);
+               wait(4, dev->io);
+               outb(a | 4, dev->io);
+               wait(4, dev->io);
        }
-       wait(4, port);
-       outb(0x14, port);
-
+       wait(4, dev->io);
+       outb(0x14, dev->io);
        return 0;
 }
 
@@ -220,9 +212,9 @@ static int vidioc_querycap(struct file *file, void  *priv,
 {
        strlcpy(v->driver, "radio-sf16fmr2", sizeof(v->driver));
        strlcpy(v->card, "SF16-FMR2 radio", sizeof(v->card));
-       sprintf(v->bus_info, "ISA");
+       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
        v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER;
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
 
@@ -230,54 +222,52 @@ static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
        int mult;
-       struct fmr2_device *fmr2 = video_drvdata(file);
+       struct fmr2 *fmr2 = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
 
-       strcpy(v->name, "FM");
+       strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
 
        mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
-       v->rangelow = RSF16_MINFREQ/mult;
-       v->rangehigh = RSF16_MAXFREQ/mult;
+       v->rangelow = RSF16_MINFREQ / mult;
+       v->rangehigh = RSF16_MAXFREQ / mult;
        v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
        v->capability = fmr2->flags&V4L2_TUNER_CAP_LOW;
        v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO:
                                V4L2_TUNER_MODE_MONO;
-       mutex_lock(&lock);
+       mutex_lock(&fmr2->lock);
        v->signal = fmr2_getsigstr(fmr2);
-       mutex_unlock(&lock);
+       mutex_unlock(&fmr2->lock);
        return 0;
 }
 
 static int vidioc_s_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       if (v->index > 0)
-               return -EINVAL;
-       return 0;
+       return v->index ? -EINVAL : 0;
 }
 
 static int vidioc_s_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct fmr2_device *fmr2 = video_drvdata(file);
+       struct fmr2 *fmr2 = video_drvdata(file);
 
        if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
                f->frequency *= 1000;
        if (f->frequency < RSF16_MINFREQ ||
-                       f->frequency > RSF16_MAXFREQ )
+                       f->frequency > RSF16_MAXFREQ)
                return -EINVAL;
-       /*rounding in steps of 200 to match th freq
-       that will be used */
-       fmr2->curfreq = (f->frequency/200)*200;
+       /* rounding in steps of 200 to match the freq
+          that will be used */
+       fmr2->curfreq = (f->frequency / 200) * 200;
 
        /* set card freq (if not muted) */
        if (fmr2->curvol && !fmr2->mute) {
-               mutex_lock(&lock);
+               mutex_lock(&fmr2->lock);
                fmr2_setfreq(fmr2);
-               mutex_unlock(&lock);
+               mutex_unlock(&fmr2->lock);
        }
        return 0;
 }
@@ -285,7 +275,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 static int vidioc_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct fmr2_device *fmr2 = video_drvdata(file);
+       struct fmr2 *fmr2 = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = fmr2->curfreq;
@@ -297,13 +287,16 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 static int vidioc_queryctrl(struct file *file, void *priv,
                                        struct v4l2_queryctrl *qc)
 {
-       int i;
+       struct fmr2 *fmr2 = video_drvdata(file);
 
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &radio_qctrl[i], sizeof(*qc));
-                       return 0;
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+       case V4L2_CID_AUDIO_VOLUME:
+               /* Only card_type == 11 implements volume */
+               if (fmr2->card_type == 11)
+                       return v4l2_ctrl_query_fill(qc, 0, 15, 1, 0);
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
        }
        return -EINVAL;
 }
@@ -311,7 +304,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct fmr2_device *fmr2 = video_drvdata(file);
+       struct fmr2 *fmr2 = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -327,18 +320,14 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct fmr2_device *fmr2 = video_drvdata(file);
+       struct fmr2 *fmr2 = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
                fmr2->mute = ctrl->value;
                break;
        case V4L2_CID_AUDIO_VOLUME:
-               if (ctrl->value > radio_qctrl[AUD_VOL_INDEX].maximum)
-                       fmr2->curvol = radio_qctrl[AUD_VOL_INDEX].maximum;
-               else
-                       fmr2->curvol = ctrl->value;
-
+               fmr2->curvol = ctrl->value;
                break;
        default:
                return -EINVAL;
@@ -351,25 +340,14 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
                printk(KERN_DEBUG "mute\n");
 #endif
 
-       mutex_lock(&lock);
+       mutex_lock(&fmr2->lock);
        if (fmr2->curvol && !fmr2->mute) {
                fmr2_setvolume(fmr2);
                /* Set frequency and unmute card */
                fmr2_setfreq(fmr2);
        } else
-               fmr2_mute(fmr2->port);
-       mutex_unlock(&lock);
-       return 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       if (a->index > 1)
-               return -EINVAL;
-
-       strcpy(a->name, "Radio");
-       a->capability = V4L2_AUDCAP_STEREO;
+               fmr2_mute(fmr2->io);
+       mutex_unlock(&fmr2->lock);
        return 0;
 }
 
@@ -381,36 +359,38 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 
 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-       if (i != 0)
-               return -EINVAL;
-       return 0;
+       return i ? -EINVAL : 0;
 }
 
-static int vidioc_s_audio(struct file *file, void *priv,
+static int vidioc_g_audio(struct file *file, void *priv,
                                        struct v4l2_audio *a)
 {
-       if (a->index != 0)
-               return -EINVAL;
+       a->index = 0;
+       strlcpy(a->name, "Radio", sizeof(a->name));
+       a->capability = V4L2_AUDCAP_STEREO;
        return 0;
 }
 
-static struct fmr2_device fmr2_unit;
+static int vidioc_s_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       return a->index ? -EINVAL : 0;
+}
 
-static int fmr2_exclusive_open(struct file *file)
+static int fmr2_open(struct file *file)
 {
-       return test_and_set_bit(0, &fmr2_unit.in_use) ? -EBUSY : 0;
+       return 0;
 }
 
-static int fmr2_exclusive_release(struct file *file)
+static int fmr2_release(struct file *file)
 {
-       clear_bit(0, &fmr2_unit.in_use);
        return 0;
 }
 
 static const struct v4l2_file_operations fmr2_fops = {
        .owner          = THIS_MODULE,
-       .open           = fmr2_exclusive_open,
-       .release        = fmr2_exclusive_release,
+       .open           = fmr2_open,
+       .release        = fmr2_release,
        .ioctl          = video_ioctl2,
 };
 
@@ -429,67 +409,64 @@ static const struct v4l2_ioctl_ops fmr2_ioctl_ops = {
        .vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
-static struct video_device fmr2_radio = {
-       .name           = "SF16FMR2 radio",
-       .fops           = &fmr2_fops,
-       .ioctl_ops      = &fmr2_ioctl_ops,
-       .release        = video_device_release_empty,
-};
-
 static int __init fmr2_init(void)
 {
-       fmr2_unit.port = io;
-       fmr2_unit.curvol = 0;
-       fmr2_unit.mute = 0;
-       fmr2_unit.curfreq = 0;
-       fmr2_unit.stereo = 1;
-       fmr2_unit.flags = V4L2_TUNER_CAP_LOW;
-       fmr2_unit.card_type = 0;
-       video_set_drvdata(&fmr2_radio, &fmr2_unit);
-
-       mutex_init(&lock);
-
-       if (!request_region(io, 2, "sf16fmr2")) {
-               printk(KERN_ERR "radio-sf16fmr2: request_region failed!\n");
+       struct fmr2 *fmr2 = &fmr2_card;
+       struct v4l2_device *v4l2_dev = &fmr2->v4l2_dev;
+       int res;
+
+       strlcpy(v4l2_dev->name, "sf16fmr2", sizeof(v4l2_dev->name));
+       fmr2->io = io;
+       fmr2->stereo = 1;
+       fmr2->flags = V4L2_TUNER_CAP_LOW;
+       mutex_init(&fmr2->lock);
+
+       if (!request_region(fmr2->io, 2, "sf16fmr2")) {
+               v4l2_err(v4l2_dev, "request_region failed!\n");
                return -EBUSY;
        }
 
-       if (video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
-               release_region(io, 2);
-               return -EINVAL;
+       res = v4l2_device_register(NULL, v4l2_dev);
+       if (res < 0) {
+               release_region(fmr2->io, 2);
+               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+               return res;
        }
 
-       printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io);
-       /* mute card - prevents noisy bootups */
-       mutex_lock(&lock);
-       fmr2_mute(io);
-       fmr2_product_info(&fmr2_unit);
-       mutex_unlock(&lock);
-       debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type));
+       strlcpy(fmr2->vdev.name, v4l2_dev->name, sizeof(fmr2->vdev.name));
+       fmr2->vdev.v4l2_dev = v4l2_dev;
+       fmr2->vdev.fops = &fmr2_fops;
+       fmr2->vdev.ioctl_ops = &fmr2_ioctl_ops;
+       fmr2->vdev.release = video_device_release_empty;
+       video_set_drvdata(&fmr2->vdev, fmr2);
 
-       /* Only card_type == 11 implements volume */
-       if (fmr2_unit.card_type != 11)
-               radio_qctrl[AUD_VOL_INDEX].maximum = 1;
+       if (video_register_device(&fmr2->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+               v4l2_device_unregister(v4l2_dev);
+               release_region(fmr2->io, 2);
+               return -EINVAL;
+       }
 
+       v4l2_info(v4l2_dev, "SF16FMR2 radio card driver at 0x%x.\n", fmr2->io);
+       /* mute card - prevents noisy bootups */
+       mutex_lock(&fmr2->lock);
+       fmr2_mute(fmr2->io);
+       fmr2_product_info(fmr2);
+       mutex_unlock(&fmr2->lock);
+       debug_print((KERN_DEBUG "card_type %d\n", fmr2->card_type));
        return 0;
 }
 
-MODULE_AUTHOR("Ziglio Frediano, freddy77@angelfire.com");
-MODULE_DESCRIPTION("A driver for the SF16FMR2 radio.");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the SF16FMR2 card (should be 0x384, if do not work try 0x284)");
-module_param(radio_nr, int, 0);
-
-static void __exit fmr2_cleanup_module(void)
+static void __exit fmr2_exit(void)
 {
-       video_unregister_device(&fmr2_radio);
-       release_region(io,2);
+       struct fmr2 *fmr2 = &fmr2_card;
+
+       video_unregister_device(&fmr2->vdev);
+       v4l2_device_unregister(&fmr2->v4l2_dev);
+       release_region(fmr2->io, 2);
 }
 
 module_init(fmr2_init);
-module_exit(fmr2_cleanup_module);
+module_exit(fmr2_exit);
 
 #ifndef MODULE
 
index 4dfed6aa2dbc54921e175a591f8a40668553b294..713e242ba8b217e8e7a4acfe6cd1f6b57bbfa9fa 100644 (file)
@@ -5,8 +5,9 @@
  *   - 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) 2008 Tobias Lorenz <tobias.lorenz@gmx.net>
+ *  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
@@ -29,7 +30,7 @@
  * 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>
+ * 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)
  * 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
 /* driver definitions */
 #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
 #define DRIVER_NAME "radio-si470x"
-#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 8)
+#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.8"
+#define DRIVER_VERSION "1.0.9"
 
 
 /* kernel includes */
@@ -145,7 +147,7 @@ static struct usb_device_id si470x_usb_driver_id_table[] = {
        { 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) },
-       /* DealExtreme USB Radio */
+       /* 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 */
        { }
@@ -345,7 +347,7 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
 
 /* Report 19: stream */
 #define STREAM_REPORT_SIZE     3
-#define        STREAM_REPORT           19
+#define STREAM_REPORT          19
 
 /* Report 20: scratch */
 #define SCRATCH_PAGE_SIZE      63
@@ -353,9 +355,13 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
 #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 */
@@ -414,7 +420,7 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
 
 /* bootloader commands */
 #define GET_SW_VERSION_COMMAND 0x00
-#define        SET_PAGE_COMMAND        0x01
+#define SET_PAGE_COMMAND       0x01
 #define ERASE_PAGE_COMMAND     0x02
 #define WRITE_PAGE_COMMAND     0x03
 #define CRC_ON_PAGE_COMMAND    0x04
@@ -428,12 +434,6 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
 #define COMMAND_FAILED         0x02
 #define COMMAND_PENDING                0x03
 
-/* buffer sizes */
-#define COMMAND_BUFFER_SIZE    4
-#define RESPONSE_BUFFER_SIZE   2
-#define FLASH_BUFFER_SIZE      64
-#define CRC_BUFFER_SIZE                3
-
 
 
 /**************************************************************************
@@ -465,6 +465,10 @@ struct si470x_device {
        unsigned int buf_size;
        unsigned int rd_index;
        unsigned int wr_index;
+
+       /* scratch page */
+       unsigned char software_version;
+       unsigned char hardware_version;
 };
 
 
@@ -480,7 +484,7 @@ struct si470x_device {
 
 
 /**************************************************************************
- * General Driver Functions
+ * General Driver Functions - REGISTER_REPORTs
  **************************************************************************/
 
 /*
@@ -565,60 +569,6 @@ static int si470x_set_register(struct si470x_device *radio, int regnr)
 }
 
 
-/*
- * 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;
-}
-
-
-/*
- * 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;
-}
-
-
 /*
  * si470x_set_chan - set the channel
  */
@@ -886,6 +836,70 @@ static int si470x_rds_on(struct si470x_device *radio)
 
 
 
+/**************************************************************************
+ * 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
  **************************************************************************/
@@ -910,6 +924,35 @@ static int si470x_set_led_state(struct si470x_device *radio,
 
 
 
+/**************************************************************************
+ * 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
  **************************************************************************/
@@ -1124,6 +1167,7 @@ static int si470x_fops_open(struct file *file)
        }
 
        if (radio->users == 1) {
+               /* start radio */
                retval = si470x_start(radio);
                if (retval < 0)
                        usb_autopm_put_interface(radio->intf);
@@ -1165,6 +1209,7 @@ static int si470x_fops_release(struct file *file)
                /* cancel read processes */
                wake_up_interruptible(&radio->read_queue);
 
+               /* stop radio */
                retval = si470x_stop(radio);
                usb_autopm_put_interface(radio->intf);
        }
@@ -1226,9 +1271,11 @@ static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
 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));
-       sprintf(capability->bus_info, "USB");
+       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;
@@ -1636,7 +1683,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
                        sizeof(si470x_viddev_template));
        video_set_drvdata(radio->videodev, radio);
 
-       /* show some infos about the specific device */
+       /* show some infos about the specific si470x device */
        if (si470x_get_all_registers(radio) < 0) {
                retval = -EIO;
                goto err_all;
@@ -1644,7 +1691,16 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
        printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
                        radio->registers[DEVICEID], radio->registers[CHIPID]);
 
-       /* check if firmware is current */
+       /* get software and hardware versions */
+       if (si470x_get_scratch_page_versions(radio) < 0) {
+               retval = -EIO;
+               goto err_all;
+       }
+       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
@@ -1657,7 +1713,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
                        ": If you have some trouble using this driver,\n");
                printk(KERN_WARNING DRIVER_NAME
                        ": please report to V4L ML at "
-                       "video4linux-list@redhat.com\n");
+                       "linux-media@vger.kernel.org\n");
        }
 
        /* set initial frequency */
index 0798d71abd005d67f5a44c924da99a2da06c0330..5b007f5c74b2839e262d6fe801309c4248926595 100644 (file)
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
 #include <linux/ioport.h>      /* request_region               */
-#include <linux/delay.h>       /* udelay                       */
-#include <asm/io.h>            /* outb, outb_p                 */
-#include <asm/uaccess.h>       /* copy to/from user            */
 #include <linux/videodev2.h>   /* kernel radio structs         */
-#include <media/v4l2-common.h>
+#include <linux/mutex.h>
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#include <linux/io.h>          /* outb, outb_p                 */
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
-#include <linux/spinlock.h>
 
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+MODULE_AUTHOR("R.OFFERMANNS & others");
+MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
+MODULE_LICENSE("GPL");
+
+#ifndef CONFIG_RADIO_TERRATEC_PORT
+#define CONFIG_RADIO_TERRATEC_PORT 0x590
+#endif
+
+static int io = CONFIG_RADIO_TERRATEC_PORT;
+static int radio_nr = -1;
+
+module_param(io, int, 0);
+MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)");
+module_param(radio_nr, int, 0);
+
+#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
 
 static struct v4l2_queryctrl radio_qctrl[] = {
        {
@@ -57,13 +70,6 @@ static struct v4l2_queryctrl radio_qctrl[] = {
        }
 };
 
-#ifndef CONFIG_RADIO_TERRATEC_PORT
-#define CONFIG_RADIO_TERRATEC_PORT 0x590
-#endif
-
-/**************** this ones are for the terratec *******************/
-#define BASEPORT       0x590
-#define VOLPORT        0x591
 #define WRT_DIS        0x00
 #define CLK_OFF                0x00
 #define IIC_DATA       0x01
@@ -71,138 +77,124 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 #define DATA           0x04
 #define CLK_ON                 0x08
 #define WRT_EN         0x10
-/*******************************************************************/
 
-static int io = CONFIG_RADIO_TERRATEC_PORT;
-static int radio_nr = -1;
-static spinlock_t lock;
-
-struct tt_device
+struct terratec
 {
-       unsigned long in_use;
-       int port;
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       int io;
        int curvol;
        unsigned long curfreq;
        int muted;
+       struct mutex lock;
 };
 
+static struct terratec terratec_card;
 
 /* local things */
 
-static void cardWriteVol(int volume)
+static void tt_write_vol(struct terratec *tt, int volume)
 {
        int i;
-       volume = volume+(volume * 32); // change both channels
-       spin_lock(&lock);
-       for (i=0;i<8;i++)
-       {
-               if (volume & (0x80>>i))
-                       outb(0x80, VOLPORT);
-               else outb(0x00, VOLPORT);
+
+       volume = volume + (volume * 32); /* change both channels */
+       mutex_lock(&tt->lock);
+       for (i = 0; i < 8; i++) {
+               if (volume & (0x80 >> i))
+                       outb(0x80, tt->io + 1);
+               else
+                       outb(0x00, tt->io + 1);
        }
-       spin_unlock(&lock);
+       mutex_unlock(&tt->lock);
 }
 
 
 
-static void tt_mute(struct tt_device *dev)
+static void tt_mute(struct terratec *tt)
 {
-       dev->muted = 1;
-       cardWriteVol(0);
+       tt->muted = 1;
+       tt_write_vol(tt, 0);
 }
 
-static int tt_setvol(struct tt_device *dev, int vol)
+static int tt_setvol(struct terratec *tt, int vol)
 {
-
-//     printk(KERN_ERR "setvol called, vol = %d\n", vol);
-
-       if(vol == dev->curvol) {        /* requested volume = current */
-               if (dev->muted) {       /* user is unmuting the card  */
-                       dev->muted = 0;
-                       cardWriteVol(vol);      /* enable card */
+       if (vol == tt->curvol) {        /* requested volume = current */
+               if (tt->muted) {        /* user is unmuting the card  */
+                       tt->muted = 0;
+                       tt_write_vol(tt, vol);  /* enable card */
                }
-
                return 0;
        }
 
-       if(vol == 0) {                  /* volume = 0 means mute the card */
-               cardWriteVol(0);        /* "turn off card" by setting vol to 0 */
-               dev->curvol = vol;      /* track the volume state!      */
+       if (vol == 0) {                 /* volume = 0 means mute the card */
+               tt_write_vol(tt, 0);    /* "turn off card" by setting vol to 0 */
+               tt->curvol = vol;       /* track the volume state!      */
                return 0;
        }
 
-       dev->muted = 0;
-
-       cardWriteVol(vol);
-
-       dev->curvol = vol;
-
+       tt->muted = 0;
+       tt_write_vol(tt, vol);
+       tt->curvol = vol;
        return 0;
-
 }
 
 
 /* this is the worst part in this driver */
 /* many more or less strange things are going on here, but hey, it works :) */
 
-static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
+static int tt_setfreq(struct terratec *tt, unsigned long freq1)
 {
        int freq;
        int i;
        int p;
        int  temp;
        long rest;
-
        unsigned char buffer[25];               /* we have to bit shift 25 registers */
-       freq = freq1/160;                       /* convert the freq. to a nice to handle value */
-       for(i=24;i>-1;i--)
-               buffer[i]=0;
 
-       rest = freq*10+10700;           /* i once had understood what is going on here */
+       mutex_lock(&tt->lock);
+
+       tt->curfreq = freq1;
+
+       freq = freq1 / 160;                     /* convert the freq. to a nice to handle value */
+       memset(buffer, 0, sizeof(buffer));
+
+       rest = freq * 10 + 10700;       /* I once had understood what is going on here */
                                        /* maybe some wise guy (friedhelm?) can comment this stuff */
-       i=13;
-       p=10;
-       temp=102400;
-       while (rest!=0)
-       {
-               if (rest%temp  == rest)
+       i = 13;
+       p = 10;
+       temp = 102400;
+       while (rest != 0) {
+               if (rest % temp  == rest)
                        buffer[i] = 0;
-               else
-               {
+               else {
                        buffer[i] = 1;
-                       rest = rest-temp;
+                       rest = rest - temp;
                }
                i--;
                p--;
-               temp = temp/2;
+               temp = temp / 2;
        }
 
-       spin_lock(&lock);
-
-       for (i=24;i>-1;i--)                     /* bit shift the values to the radiocard */
-       {
-               if (buffer[i]==1)
-               {
-                       outb(WRT_EN|DATA, BASEPORT);
-                       outb(WRT_EN|DATA|CLK_ON  , BASEPORT);
-                       outb(WRT_EN|DATA, BASEPORT);
-               }
-               else
-               {
-                       outb(WRT_EN|0x00, BASEPORT);
-                       outb(WRT_EN|0x00|CLK_ON  , BASEPORT);
+       for (i = 24; i > -1; i--) {     /* bit shift the values to the radiocard */
+               if (buffer[i] == 1) {
+                       outb(WRT_EN | DATA, tt->io);
+                       outb(WRT_EN | DATA | CLK_ON, tt->io);
+                       outb(WRT_EN | DATA, tt->io);
+               } else {
+                       outb(WRT_EN | 0x00, tt->io);
+                       outb(WRT_EN | 0x00 | CLK_ON, tt->io);
                }
        }
-       outb(0x00, BASEPORT);
+       outb(0x00, tt->io);
 
-       spin_unlock(&lock);
+       mutex_unlock(&tt->lock);
 
        return 0;
 }
 
-static int tt_getsigstr(struct tt_device *dev)         /* TODO */
+static int tt_getsigstr(struct terratec *tt)
 {
-       if (inb(io) & 2)        /* bit set = no signal present  */
+       if (inb(tt->io) & 2)    /* bit set = no signal present  */
                return 0;
        return 1;               /* signal present               */
 }
@@ -212,53 +204,50 @@ static int vidioc_querycap(struct file *file, void *priv,
 {
        strlcpy(v->driver, "radio-terratec", sizeof(v->driver));
        strlcpy(v->card, "ActiveRadio", sizeof(v->card));
-       sprintf(v->bus_info, "ISA");
+       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
        v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER;
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
 
 static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       struct tt_device *tt = video_drvdata(file);
+       struct terratec *tt = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
 
-       strcpy(v->name, "FM");
+       strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
-       v->rangelow = (87*16000);
-       v->rangehigh = (108*16000);
+       v->rangelow = 87 * 16000;
+       v->rangehigh = 108 * 16000;
        v->rxsubchans = V4L2_TUNER_SUB_MONO;
        v->capability = V4L2_TUNER_CAP_LOW;
        v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = 0xFFFF*tt_getsigstr(tt);
+       v->signal = 0xFFFF * tt_getsigstr(tt);
        return 0;
 }
 
 static int vidioc_s_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       if (v->index > 0)
-               return -EINVAL;
-       return 0;
+       return v->index ? -EINVAL : 0;
 }
 
 static int vidioc_s_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct tt_device *tt = video_drvdata(file);
+       struct terratec *tt = video_drvdata(file);
 
-       tt->curfreq = f->frequency;
-       tt_setfreq(tt, tt->curfreq);
+       tt_setfreq(tt, f->frequency);
        return 0;
 }
 
 static int vidioc_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct tt_device *tt = video_drvdata(file);
+       struct terratec *tt = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = tt->curfreq;
@@ -272,8 +261,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 
        for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
                if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]),
-                                               sizeof(*qc));
+                       memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
                        return 0;
                }
        }
@@ -283,7 +271,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct tt_device *tt = video_drvdata(file);
+       struct terratec *tt = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -302,7 +290,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct tt_device *tt = video_drvdata(file);
+       struct terratec *tt = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -318,17 +306,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        return -EINVAL;
 }
 
-static int vidioc_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       if (a->index > 1)
-               return -EINVAL;
-
-       strcpy(a->name, "Radio");
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 {
        *i = 0;
@@ -337,36 +314,38 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 
 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-       if (i != 0)
-               return -EINVAL;
-       return 0;
+       return i ? -EINVAL : 0;
 }
 
-static int vidioc_s_audio(struct file *file, void *priv,
+static int vidioc_g_audio(struct file *file, void *priv,
                                        struct v4l2_audio *a)
 {
-       if (a->index != 0)
-               return -EINVAL;
+       a->index = 0;
+       strlcpy(a->name, "Radio", sizeof(a->name));
+       a->capability = V4L2_AUDCAP_STEREO;
        return 0;
 }
 
-static struct tt_device terratec_unit;
+static int vidioc_s_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       return a->index ? -EINVAL : 0;
+}
 
-static int terratec_exclusive_open(struct file *file)
+static int terratec_open(struct file *file)
 {
-       return test_and_set_bit(0, &terratec_unit.in_use) ? -EBUSY : 0;
+       return 0;
 }
 
-static int terratec_exclusive_release(struct file *file)
+static int terratec_release(struct file *file)
 {
-       clear_bit(0, &terratec_unit.in_use);
        return 0;
 }
 
 static const struct v4l2_file_operations terratec_fops = {
        .owner          = THIS_MODULE,
-       .open           = terratec_exclusive_open,
-       .release        = terratec_exclusive_release,
+       .open           = terratec_open,
+       .release        = terratec_release,
        .ioctl          = video_ioctl2,
 };
 
@@ -385,60 +364,63 @@ static const struct v4l2_ioctl_ops terratec_ioctl_ops = {
        .vidioc_s_input     = vidioc_s_input,
 };
 
-static struct video_device terratec_radio = {
-       .name           = "TerraTec ActiveRadio",
-       .fops           = &terratec_fops,
-       .ioctl_ops      = &terratec_ioctl_ops,
-       .release        = video_device_release_empty,
-};
-
 static int __init terratec_init(void)
 {
-       if(io==-1)
-       {
-               printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+       struct terratec *tt = &terratec_card;
+       struct v4l2_device *v4l2_dev = &tt->v4l2_dev;
+       int res;
+
+       strlcpy(v4l2_dev->name, "terratec", sizeof(v4l2_dev->name));
+       tt->io = io;
+       if (tt->io == -1) {
+               v4l2_err(v4l2_dev, "you must set an I/O address with io=0x590 or 0x591\n");
                return -EINVAL;
        }
-       if (!request_region(io, 2, "terratec"))
-       {
-               printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io);
+       if (!request_region(tt->io, 2, "terratec")) {
+               v4l2_err(v4l2_dev, "port 0x%x already in use\n", io);
                return -EBUSY;
        }
 
-       video_set_drvdata(&terratec_radio, &terratec_unit);
+       res = v4l2_device_register(NULL, v4l2_dev);
+       if (res < 0) {
+               release_region(tt->io, 2);
+               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+               return res;
+       }
+
+       strlcpy(tt->vdev.name, v4l2_dev->name, sizeof(tt->vdev.name));
+       tt->vdev.v4l2_dev = v4l2_dev;
+       tt->vdev.fops = &terratec_fops;
+       tt->vdev.ioctl_ops = &terratec_ioctl_ops;
+       tt->vdev.release = video_device_release_empty;
+       video_set_drvdata(&tt->vdev, tt);
 
-       spin_lock_init(&lock);
+       mutex_init(&tt->lock);
 
-       if (video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
-               release_region(io,2);
+       if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+               v4l2_device_unregister(&tt->v4l2_dev);
+               release_region(tt->io, 2);
                return -EINVAL;
        }
 
-       printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n");
+       v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n");
 
        /* mute card - prevents noisy bootups */
-
-       /* this ensures that the volume is all the way down  */
-       cardWriteVol(0);
-       terratec_unit.curvol = 0;
-
+       tt_write_vol(tt, 0);
        return 0;
 }
 
-MODULE_AUTHOR("R.OFFERMANNS & others");
-MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
-MODULE_LICENSE("GPL");
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)");
-module_param(radio_nr, int, 0);
-
-static void __exit terratec_cleanup_module(void)
+static void __exit terratec_exit(void)
 {
-       video_unregister_device(&terratec_radio);
-       release_region(io,2);
-       printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n");
+       struct terratec *tt = &terratec_card;
+       struct v4l2_device *v4l2_dev = &tt->v4l2_dev;
+
+       video_unregister_device(&tt->vdev);
+       v4l2_device_unregister(&tt->v4l2_dev);
+       release_region(tt->io, 2);
+       v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver unloaded.\n");
 }
 
 module_init(terratec_init);
-module_exit(terratec_cleanup_module);
+module_exit(terratec_exit);
 
index bdf9cb6a75f47c7634d99a615cabbf925cbdf740..d1be6492a07b1593e466a6012fc14b468577d596 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <linux/io.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
-
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_AUDIO_VOLUME,
-               .name          = "Volume",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 2048,
-               .default_value = 65535,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_AUDIO_BASS,
-               .name          = "Bass",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 4370,
-               .default_value = 32768,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_AUDIO_TREBLE,
-               .name          = "Treble",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 4370,
-               .default_value = 32768,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },
-};
+MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
+MODULE_DESCRIPTION("A driver for the Trust FM Radio card.");
+MODULE_LICENSE("GPL");
 
 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
 
@@ -71,26 +37,41 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 
 static int io = CONFIG_RADIO_TRUST_PORT;
 static int radio_nr = -1;
-static int ioval = 0xf;
-static __u16 curvol;
-static __u16 curbass;
-static __u16 curtreble;
-static unsigned long curfreq;
-static int curstereo;
-static int curmute;
-static unsigned long in_use;
+
+module_param(io, int, 0);
+MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)");
+module_param(radio_nr, int, 0);
+
+#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
+
+struct trust {
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       int io;
+       int ioval;
+       __u16 curvol;
+       __u16 curbass;
+       __u16 curtreble;
+       int muted;
+       unsigned long curfreq;
+       int curstereo;
+       int curmute;
+       struct mutex lock;
+};
+
+static struct trust trust_card;
 
 /* i2c addresses */
 #define TDA7318_ADDR 0x88
 #define TSA6060T_ADDR 0xc4
 
-#define TR_DELAY do { inb(io); inb(io); inb(io); } while(0)
-#define TR_SET_SCL outb(ioval |= 2, io)
-#define TR_CLR_SCL outb(ioval &= 0xfd, io)
-#define TR_SET_SDA outb(ioval |= 1, io)
-#define TR_CLR_SDA outb(ioval &= 0xfe, io)
+#define TR_DELAY do { inb(tr->io); inb(tr->io); inb(tr->io); } while (0)
+#define TR_SET_SCL outb(tr->ioval |= 2, tr->io)
+#define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->io)
+#define TR_SET_SDA outb(tr->ioval |= 1, tr->io)
+#define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->io)
 
-static void write_i2c(int n, ...)
+static void write_i2c(struct trust *tr, int n, ...)
 {
        unsigned char val, mask;
        va_list args;
@@ -136,62 +117,77 @@ static void write_i2c(int n, ...)
        va_end(args);
 }
 
-static void tr_setvol(__u16 vol)
+static void tr_setvol(struct trust *tr, __u16 vol)
 {
-       curvol = vol / 2048;
-       write_i2c(2, TDA7318_ADDR, curvol ^ 0x1f);
+       mutex_lock(&tr->lock);
+       tr->curvol = vol / 2048;
+       write_i2c(tr, 2, TDA7318_ADDR, tr->curvol ^ 0x1f);
+       mutex_unlock(&tr->lock);
 }
 
 static int basstreble2chip[15] = {
        0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8
 };
 
-static void tr_setbass(__u16 bass)
+static void tr_setbass(struct trust *tr, __u16 bass)
 {
-       curbass = bass / 4370;
-       write_i2c(2, TDA7318_ADDR, 0x60 | basstreble2chip[curbass]);
+       mutex_lock(&tr->lock);
+       tr->curbass = bass / 4370;
+       write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[tr->curbass]);
+       mutex_unlock(&tr->lock);
 }
 
-static void tr_settreble(__u16 treble)
+static void tr_settreble(struct trust *tr, __u16 treble)
 {
-       curtreble = treble / 4370;
-       write_i2c(2, TDA7318_ADDR, 0x70 | basstreble2chip[curtreble]);
+       mutex_lock(&tr->lock);
+       tr->curtreble = treble / 4370;
+       write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[tr->curtreble]);
+       mutex_unlock(&tr->lock);
 }
 
-static void tr_setstereo(int stereo)
+static void tr_setstereo(struct trust *tr, int stereo)
 {
-       curstereo = !!stereo;
-       ioval = (ioval & 0xfb) | (!curstereo << 2);
-       outb(ioval, io);
+       mutex_lock(&tr->lock);
+       tr->curstereo = !!stereo;
+       tr->ioval = (tr->ioval & 0xfb) | (!tr->curstereo << 2);
+       outb(tr->ioval, tr->io);
+       mutex_unlock(&tr->lock);
 }
 
-static void tr_setmute(int mute)
+static void tr_setmute(struct trust *tr, int mute)
 {
-       curmute = !!mute;
-       ioval = (ioval & 0xf7) | (curmute << 3);
-       outb(ioval, io);
+       mutex_lock(&tr->lock);
+       tr->curmute = !!mute;
+       tr->ioval = (tr->ioval & 0xf7) | (tr->curmute << 3);
+       outb(tr->ioval, tr->io);
+       mutex_unlock(&tr->lock);
 }
 
-static int tr_getsigstr(void)
+static int tr_getsigstr(struct trust *tr)
 {
        int i, v;
 
-       for(i = 0, v = 0; i < 100; i++) v |= inb(io);
-       return (v & 1)? 0 : 0xffff;
+       mutex_lock(&tr->lock);
+       for (i = 0, v = 0; i < 100; i++)
+               v |= inb(tr->io);
+       mutex_unlock(&tr->lock);
+       return (v & 1) ? 0 : 0xffff;
 }
 
-static int tr_getstereo(void)
+static int tr_getstereo(struct trust *tr)
 {
        /* don't know how to determine it, just return the setting */
-       return curstereo;
+       return tr->curstereo;
 }
 
-static void tr_setfreq(unsigned long f)
+static void tr_setfreq(struct trust *tr, unsigned long f)
 {
+       mutex_lock(&tr->lock);
+       tr->curfreq = f;
        f /= 160;       /* Convert to 10 kHz units      */
-       f += 1070;      /* Add 10.7 MHz IF                      */
-
-       write_i2c(5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0);
+       f += 1070;      /* Add 10.7 MHz IF              */
+       write_i2c(tr, 5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0);
+       mutex_unlock(&tr->lock);
 }
 
 static int vidioc_querycap(struct file *file, void *priv,
@@ -199,68 +195,75 @@ static int vidioc_querycap(struct file *file, void *priv,
 {
        strlcpy(v->driver, "radio-trust", sizeof(v->driver));
        strlcpy(v->card, "Trust FM Radio", sizeof(v->card));
-       sprintf(v->bus_info, "ISA");
+       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
        v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER;
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
 
 static int vidioc_g_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
+       struct trust *tr = video_drvdata(file);
+
        if (v->index > 0)
                return -EINVAL;
 
-       strcpy(v->name, "FM");
+       strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
-       v->rangelow = (87.5*16000);
-       v->rangehigh = (108*16000);
-       v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+       v->rangelow = 87.5 * 16000;
+       v->rangehigh = 108 * 16000;
+       v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
        v->capability = V4L2_TUNER_CAP_LOW;
-       if (tr_getstereo())
+       if (tr_getstereo(tr))
                v->audmode = V4L2_TUNER_MODE_STEREO;
        else
                v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = tr_getsigstr();
+       v->signal = tr_getsigstr(tr);
        return 0;
 }
 
 static int vidioc_s_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
-       if (v->index > 0)
-               return -EINVAL;
+       struct trust *tr = video_drvdata(file);
 
+       if (v->index)
+               return -EINVAL;
+       tr_setstereo(tr, v->audmode == V4L2_TUNER_MODE_STEREO);
        return 0;
 }
 
 static int vidioc_s_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       curfreq = f->frequency;
-       tr_setfreq(curfreq);
+       struct trust *tr = video_drvdata(file);
+
+       tr_setfreq(tr, f->frequency);
        return 0;
 }
 
 static int vidioc_g_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
+       struct trust *tr = video_drvdata(file);
+
        f->type = V4L2_TUNER_RADIO;
-       f->frequency = curfreq;
+       f->frequency = tr->curfreq;
        return 0;
 }
 
 static int vidioc_queryctrl(struct file *file, void *priv,
                                struct v4l2_queryctrl *qc)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]),
-                                               sizeof(*qc));
-                       return 0;
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+       case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(qc, 0, 65535, 2048, 65535);
+       case V4L2_CID_AUDIO_BASS:
+       case V4L2_CID_AUDIO_TREBLE:
+               return v4l2_ctrl_query_fill(qc, 0, 65535, 4370, 32768);
        }
        return -EINVAL;
 }
@@ -268,18 +271,20 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
+       struct trust *tr = video_drvdata(file);
+
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = curmute;
+               ctrl->value = tr->curmute;
                return 0;
        case V4L2_CID_AUDIO_VOLUME:
-               ctrl->value = curvol * 2048;
+               ctrl->value = tr->curvol * 2048;
                return 0;
        case V4L2_CID_AUDIO_BASS:
-               ctrl->value = curbass * 4370;
+               ctrl->value = tr->curbass * 4370;
                return 0;
        case V4L2_CID_AUDIO_TREBLE:
-               ctrl->value = curtreble * 4370;
+               ctrl->value = tr->curtreble * 4370;
                return 0;
        }
        return -EINVAL;
@@ -288,34 +293,25 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
+       struct trust *tr = video_drvdata(file);
+
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               tr_setmute(ctrl->value);
+               tr_setmute(tr, ctrl->value);
                return 0;
        case V4L2_CID_AUDIO_VOLUME:
-               tr_setvol(ctrl->value);
+               tr_setvol(tr, ctrl->value);
                return 0;
        case V4L2_CID_AUDIO_BASS:
-               tr_setbass(ctrl->value);
+               tr_setbass(tr, ctrl->value);
                return 0;
        case V4L2_CID_AUDIO_TREBLE:
-               tr_settreble(ctrl->value);
+               tr_settreble(tr, ctrl->value);
                return 0;
        }
        return -EINVAL;
 }
 
-static int vidioc_g_audio(struct file *file, void *priv,
-                               struct v4l2_audio *a)
-{
-       if (a->index > 1)
-               return -EINVAL;
-
-       strcpy(a->name, "Radio");
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 {
        *i = 0;
@@ -324,34 +320,38 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 
 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-       if (i != 0)
-               return -EINVAL;
+       return i ? -EINVAL : 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv,
+                               struct v4l2_audio *a)
+{
+       a->index = 0;
+       strlcpy(a->name, "Radio", sizeof(a->name));
+       a->capability = V4L2_AUDCAP_STEREO;
        return 0;
 }
 
 static int vidioc_s_audio(struct file *file, void *priv,
                                struct v4l2_audio *a)
 {
-       if (a->index != 0)
-               return -EINVAL;
-       return 0;
+       return a->index ? -EINVAL : 0;
 }
 
-static int trust_exclusive_open(struct file *file)
+static int trust_open(struct file *file)
 {
-       return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
+       return 0;
 }
 
-static int trust_exclusive_release(struct file *file)
+static int trust_release(struct file *file)
 {
-       clear_bit(0, &in_use);
        return 0;
 }
 
 static const struct v4l2_file_operations trust_fops = {
        .owner          = THIS_MODULE,
-       .open           = trust_exclusive_open,
-       .release        = trust_exclusive_release,
+       .open           = trust_open,
+       .release        = trust_release,
        .ioctl          = video_ioctl2,
 };
 
@@ -370,59 +370,72 @@ static const struct v4l2_ioctl_ops trust_ioctl_ops = {
        .vidioc_s_input     = vidioc_s_input,
 };
 
-static struct video_device trust_radio = {
-       .name           = "Trust FM Radio",
-       .fops           = &trust_fops,
-       .ioctl_ops      = &trust_ioctl_ops,
-       .release        = video_device_release_empty,
-};
-
 static int __init trust_init(void)
 {
-       if(io == -1) {
-               printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+       struct trust *tr = &trust_card;
+       struct v4l2_device *v4l2_dev = &tr->v4l2_dev;
+       int res;
+
+       strlcpy(v4l2_dev->name, "trust", sizeof(v4l2_dev->name));
+       tr->io = io;
+       tr->ioval = 0xf;
+       mutex_init(&tr->lock);
+
+       if (tr->io == -1) {
+               v4l2_err(v4l2_dev, "You must set an I/O address with io=0x0x350 or 0x358\n");
                return -EINVAL;
        }
-       if(!request_region(io, 2, "Trust FM Radio")) {
-               printk(KERN_ERR "trust: port 0x%x already in use\n", io);
+       if (!request_region(tr->io, 2, "Trust FM Radio")) {
+               v4l2_err(v4l2_dev, "port 0x%x already in use\n", tr->io);
                return -EBUSY;
        }
-       if (video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
-               release_region(io, 2);
+
+       res = v4l2_device_register(NULL, v4l2_dev);
+       if (res < 0) {
+               release_region(tr->io, 2);
+               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+               return res;
+       }
+
+       strlcpy(tr->vdev.name, v4l2_dev->name, sizeof(tr->vdev.name));
+       tr->vdev.v4l2_dev = v4l2_dev;
+       tr->vdev.fops = &trust_fops;
+       tr->vdev.ioctl_ops = &trust_ioctl_ops;
+       tr->vdev.release = video_device_release_empty;
+       video_set_drvdata(&tr->vdev, tr);
+
+       if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+               v4l2_device_unregister(v4l2_dev);
+               release_region(tr->io, 2);
                return -EINVAL;
        }
 
-       printk(KERN_INFO "Trust FM Radio card driver v1.0.\n");
+       v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n");
 
-       write_i2c(2, TDA7318_ADDR, 0x80);       /* speaker att. LF = 0 dB */
-       write_i2c(2, TDA7318_ADDR, 0xa0);       /* speaker att. RF = 0 dB */
-       write_i2c(2, TDA7318_ADDR, 0xc0);       /* speaker att. LR = 0 dB */
-       write_i2c(2, TDA7318_ADDR, 0xe0);       /* speaker att. RR = 0 dB */
-       write_i2c(2, TDA7318_ADDR, 0x40);       /* stereo 1 input, gain = 18.75 dB */
+       write_i2c(tr, 2, TDA7318_ADDR, 0x80);   /* speaker att. LF = 0 dB */
+       write_i2c(tr, 2, TDA7318_ADDR, 0xa0);   /* speaker att. RF = 0 dB */
+       write_i2c(tr, 2, TDA7318_ADDR, 0xc0);   /* speaker att. LR = 0 dB */
+       write_i2c(tr, 2, TDA7318_ADDR, 0xe0);   /* speaker att. RR = 0 dB */
+       write_i2c(tr, 2, TDA7318_ADDR, 0x40);   /* stereo 1 input, gain = 18.75 dB */
 
-       tr_setvol(0x8000);
-       tr_setbass(0x8000);
-       tr_settreble(0x8000);
-       tr_setstereo(1);
+       tr_setvol(tr, 0xffff);
+       tr_setbass(tr, 0x8000);
+       tr_settreble(tr, 0x8000);
+       tr_setstereo(tr, 1);
 
        /* mute card - prevents noisy bootups */
-       tr_setmute(1);
+       tr_setmute(tr, 1);
 
        return 0;
 }
 
-MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
-MODULE_DESCRIPTION("A driver for the Trust FM Radio card.");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)");
-module_param(radio_nr, int, 0);
-
 static void __exit cleanup_trust_module(void)
 {
-       video_unregister_device(&trust_radio);
-       release_region(io, 2);
+       struct trust *tr = &trust_card;
+
+       video_unregister_device(&tr->vdev);
+       v4l2_device_unregister(&tr->v4l2_dev);
+       release_region(tr->io, 2);
 }
 
 module_init(trust_init);
index 5c3b319dab37cadaadc64c576bc18482e943d444..92d923c7f3603e68fea5932b828697f1becb08bb 100644 (file)
 #include <linux/module.h>      /* Modules                        */
 #include <linux/init.h>                /* Initdata                       */
 #include <linux/ioport.h>      /* request_region                 */
-#include <linux/proc_fs.h>     /* radio card status report       */
-#include <linux/seq_file.h>
-#include <asm/io.h>            /* outb, outb_p                   */
-#include <asm/uaccess.h>       /* copy to/from user              */
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/videodev2.h>   /* kernel radio structs           */
-#include <media/v4l2-common.h>
+#include <linux/io.h>          /* outb, outb_p                   */
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
-#define RADIO_VERSION KERNEL_VERSION(0,1,1)
-#define BANNER "Typhoon Radio Card driver v0.1.1\n"
-
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_AUDIO_VOLUME,
-               .name          = "Volume",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 1<<14,
-               .default_value = 0xff,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       }
-};
-
+MODULE_AUTHOR("Dr. Henrik Seidel");
+MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio).");
+MODULE_LICENSE("GPL");
 
 #ifndef CONFIG_RADIO_TYPHOON_PORT
 #define CONFIG_RADIO_TYPHOON_PORT -1
@@ -74,13 +52,26 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 #define CONFIG_RADIO_TYPHOON_MUTEFREQ 0
 #endif
 
-#ifndef CONFIG_PROC_FS
-#undef CONFIG_RADIO_TYPHOON_PROC_FS
-#endif
+static int io = CONFIG_RADIO_TYPHOON_PORT;
+static int radio_nr = -1;
 
-struct typhoon_device {
-       unsigned long in_use;
-       int iobase;
+module_param(io, int, 0);
+MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)");
+
+module_param(radio_nr, int, 0);
+
+static unsigned long mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ;
+module_param(mutefreq, ulong, 0);
+MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)");
+
+#define RADIO_VERSION KERNEL_VERSION(0, 1, 1)
+
+#define BANNER "Typhoon Radio Card driver v0.1.1\n"
+
+struct typhoon {
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       int io;
        int curvol;
        int muted;
        unsigned long curfreq;
@@ -88,25 +79,19 @@ struct typhoon_device {
        struct mutex lock;
 };
 
-static void typhoon_setvol_generic(struct typhoon_device *dev, int vol);
-static int typhoon_setfreq_generic(struct typhoon_device *dev,
-                                  unsigned long frequency);
-static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency);
-static void typhoon_mute(struct typhoon_device *dev);
-static void typhoon_unmute(struct typhoon_device *dev);
-static int typhoon_setvol(struct typhoon_device *dev, int vol);
+static struct typhoon typhoon_card;
 
-static void typhoon_setvol_generic(struct typhoon_device *dev, int vol)
+static void typhoon_setvol_generic(struct typhoon *dev, int vol)
 {
        mutex_lock(&dev->lock);
        vol >>= 14;                             /* Map 16 bit to 2 bit */
        vol &= 3;
-       outb_p(vol / 2, dev->iobase);           /* Set the volume, high bit. */
-       outb_p(vol % 2, dev->iobase + 2);       /* Set the volume, low bit. */
+       outb_p(vol / 2, dev->io);               /* Set the volume, high bit. */
+       outb_p(vol % 2, dev->io + 2);   /* Set the volume, low bit. */
        mutex_unlock(&dev->lock);
 }
 
-static int typhoon_setfreq_generic(struct typhoon_device *dev,
+static int typhoon_setfreq_generic(struct typhoon *dev,
                                   unsigned long frequency)
 {
        unsigned long outval;
@@ -130,22 +115,22 @@ static int typhoon_setfreq_generic(struct typhoon_device *dev,
        outval -= (10 * x * x + 10433) / 20866;
        outval += 4 * x - 11505;
 
-       outb_p((outval >> 8) & 0x01, dev->iobase + 4);
-       outb_p(outval >> 9, dev->iobase + 6);
-       outb_p(outval & 0xff, dev->iobase + 8);
+       outb_p((outval >> 8) & 0x01, dev->io + 4);
+       outb_p(outval >> 9, dev->io + 6);
+       outb_p(outval & 0xff, dev->io + 8);
        mutex_unlock(&dev->lock);
 
        return 0;
 }
 
-static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency)
+static int typhoon_setfreq(struct typhoon *dev, unsigned long frequency)
 {
        typhoon_setfreq_generic(dev, frequency);
        dev->curfreq = frequency;
        return 0;
 }
 
-static void typhoon_mute(struct typhoon_device *dev)
+static void typhoon_mute(struct typhoon *dev)
 {
        if (dev->muted == 1)
                return;
@@ -154,7 +139,7 @@ static void typhoon_mute(struct typhoon_device *dev)
        dev->muted = 1;
 }
 
-static void typhoon_unmute(struct typhoon_device *dev)
+static void typhoon_unmute(struct typhoon *dev)
 {
        if (dev->muted == 0)
                return;
@@ -163,7 +148,7 @@ static void typhoon_unmute(struct typhoon_device *dev)
        dev->muted = 0;
 }
 
-static int typhoon_setvol(struct typhoon_device *dev, int vol)
+static int typhoon_setvol(struct typhoon *dev, int vol)
 {
        if (dev->muted && vol != 0) {   /* user is unmuting the card */
                dev->curvol = vol;
@@ -188,9 +173,9 @@ static int vidioc_querycap(struct file *file, void  *priv,
 {
        strlcpy(v->driver, "radio-typhoon", sizeof(v->driver));
        strlcpy(v->card, "Typhoon Radio", sizeof(v->card));
-       sprintf(v->bus_info, "ISA");
+       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
        v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER;
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
 
@@ -200,10 +185,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
        if (v->index > 0)
                return -EINVAL;
 
-       strcpy(v->name, "FM");
+       strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
-       v->rangelow = (87.5*16000);
-       v->rangehigh = (108*16000);
+       v->rangelow = 87.5 * 16000;
+       v->rangehigh = 108 * 16000;
        v->rxsubchans = V4L2_TUNER_SUB_MONO;
        v->capability = V4L2_TUNER_CAP_LOW;
        v->audmode = V4L2_TUNER_MODE_MONO;
@@ -214,44 +199,37 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 static int vidioc_s_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       if (v->index > 0)
-               return -EINVAL;
-
-       return 0;
+       return v->index ? -EINVAL : 0;
 }
 
-static int vidioc_s_frequency(struct file *file, void *priv,
+static int vidioc_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct typhoon_device *typhoon = video_drvdata(file);
+       struct typhoon *dev = video_drvdata(file);
 
-       typhoon->curfreq = f->frequency;
-       typhoon_setfreq(typhoon, typhoon->curfreq);
+       f->type = V4L2_TUNER_RADIO;
+       f->frequency = dev->curfreq;
        return 0;
 }
 
-static int vidioc_g_frequency(struct file *file, void *priv,
+static int vidioc_s_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct typhoon_device *typhoon = video_drvdata(file);
-
-       f->type = V4L2_TUNER_RADIO;
-       f->frequency = typhoon->curfreq;
+       struct typhoon *dev = video_drvdata(file);
 
+       dev->curfreq = f->frequency;
+       typhoon_setfreq(dev, dev->curfreq);
        return 0;
 }
 
 static int vidioc_queryctrl(struct file *file, void *priv,
                                        struct v4l2_queryctrl *qc)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]),
-                                               sizeof(*qc));
-                       return 0;
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+       case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(qc, 0, 65535, 16384, 65535);
        }
        return -EINVAL;
 }
@@ -259,14 +237,14 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct typhoon_device *typhoon = video_drvdata(file);
+       struct typhoon *dev = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = typhoon->muted;
+               ctrl->value = dev->muted;
                return 0;
        case V4L2_CID_AUDIO_VOLUME:
-               ctrl->value = typhoon->curvol;
+               ctrl->value = dev->curvol;
                return 0;
        }
        return -EINVAL;
@@ -275,33 +253,22 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl (struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct typhoon_device *typhoon = video_drvdata(file);
+       struct typhoon *dev = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
                if (ctrl->value)
-                       typhoon_mute(typhoon);
+                       typhoon_mute(dev);
                else
-                       typhoon_unmute(typhoon);
+                       typhoon_unmute(dev);
                return 0;
        case V4L2_CID_AUDIO_VOLUME:
-               typhoon_setvol(typhoon, ctrl->value);
+               typhoon_setvol(dev, ctrl->value);
                return 0;
        }
        return -EINVAL;
 }
 
-static int vidioc_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       if (a->index > 1)
-               return -EINVAL;
-
-       strcpy(a->name, "Radio");
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 {
        *i = 0;
@@ -310,45 +277,62 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 
 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-       if (i != 0)
-               return -EINVAL;
+       return i ? -EINVAL : 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       a->index = 0;
+       strlcpy(a->name, "Radio", sizeof(a->name));
+       a->capability = V4L2_AUDCAP_STEREO;
        return 0;
 }
 
 static int vidioc_s_audio(struct file *file, void *priv,
                                        struct v4l2_audio *a)
 {
-       if (a->index != 0)
-               return -EINVAL;
-       return 0;
+       return a->index ? -EINVAL : 0;
 }
 
-static struct typhoon_device typhoon_unit =
+static int vidioc_log_status(struct file *file, void *priv)
 {
-       .iobase         = CONFIG_RADIO_TYPHOON_PORT,
-       .curfreq        = CONFIG_RADIO_TYPHOON_MUTEFREQ,
-       .mutefreq       = CONFIG_RADIO_TYPHOON_MUTEFREQ,
-};
+       struct typhoon *dev = video_drvdata(file);
+       struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
+
+       v4l2_info(v4l2_dev, BANNER);
+#ifdef MODULE
+       v4l2_info(v4l2_dev, "Load type: Driver loaded as a module\n\n");
+#else
+       v4l2_info(v4l2_dev, "Load type: Driver compiled into kernel\n\n");
+#endif
+       v4l2_info(v4l2_dev, "frequency = %lu kHz\n", dev->curfreq >> 4);
+       v4l2_info(v4l2_dev, "volume = %d\n", dev->curvol);
+       v4l2_info(v4l2_dev, "mute = %s\n", dev->muted ?  "on" : "off");
+       v4l2_info(v4l2_dev, "io = 0x%x\n", dev->io);
+       v4l2_info(v4l2_dev, "mute frequency = %lu kHz\n", dev->mutefreq >> 4);
+       return 0;
+}
 
-static int typhoon_exclusive_open(struct file *file)
+static int typhoon_open(struct file *file)
 {
-       return test_and_set_bit(0, &typhoon_unit.in_use) ? -EBUSY : 0;
+       return 0;
 }
 
-static int typhoon_exclusive_release(struct file *file)
+static int typhoon_release(struct file *file)
 {
-       clear_bit(0, &typhoon_unit.in_use);
        return 0;
 }
 
 static const struct v4l2_file_operations typhoon_fops = {
        .owner          = THIS_MODULE,
-       .open           = typhoon_exclusive_open,
-       .release        = typhoon_exclusive_release,
+       .open           = typhoon_open,
+       .release        = typhoon_release,
        .ioctl          = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops typhoon_ioctl_ops = {
+       .vidioc_log_status  = vidioc_log_status,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
        .vidioc_s_tuner     = vidioc_s_tuner,
@@ -363,125 +347,72 @@ static const struct v4l2_ioctl_ops typhoon_ioctl_ops = {
        .vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
-static struct video_device typhoon_radio = {
-       .name           = "Typhoon Radio",
-       .fops           = &typhoon_fops,
-       .ioctl_ops      = &typhoon_ioctl_ops,
-       .release        = video_device_release_empty,
-};
-
-#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
-
-static int typhoon_proc_show(struct seq_file *m, void *v)
-{
-       #ifdef MODULE
-           #define MODULEPROCSTRING "Driver loaded as a module"
-       #else
-           #define MODULEPROCSTRING "Driver compiled into kernel"
-       #endif
-
-       seq_puts(m, BANNER);
-       seq_puts(m, "Load type: " MODULEPROCSTRING "\n\n");
-       seq_printf(m, "frequency = %lu kHz\n",
-               typhoon_unit.curfreq >> 4);
-       seq_printf(m, "volume = %d\n", typhoon_unit.curvol);
-       seq_printf(m, "mute = %s\n", typhoon_unit.muted ?
-               "on" : "off");
-       seq_printf(m, "iobase = 0x%x\n", typhoon_unit.iobase);
-       seq_printf(m, "mute frequency = %lu kHz\n",
-               typhoon_unit.mutefreq >> 4);
-       return 0;
-}
-
-static int typhoon_proc_open(struct inode *inode, struct file *file)
+static int __init typhoon_init(void)
 {
-       return single_open(file, typhoon_proc_show, NULL);
-}
-
-static const struct file_operations typhoon_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = typhoon_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-#endif /* CONFIG_RADIO_TYPHOON_PROC_FS */
-
-MODULE_AUTHOR("Dr. Henrik Seidel");
-MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio).");
-MODULE_LICENSE("GPL");
-
-static int io = -1;
-static int radio_nr = -1;
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)");
-module_param(radio_nr, int, 0);
+       struct typhoon *dev = &typhoon_card;
+       struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
+       int res;
 
-#ifdef MODULE
-static unsigned long mutefreq;
-module_param(mutefreq, ulong, 0);
-MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)");
-#endif
+       strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name));
+       dev->io = io;
+       dev->curfreq = dev->mutefreq = mutefreq;
 
-static int __init typhoon_init(void)
-{
-#ifdef MODULE
-       if (io == -1) {
-               printk(KERN_ERR "radio-typhoon: You must set an I/O address with io=0x316 or io=0x336\n");
+       if (dev->io == -1) {
+               v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n");
                return -EINVAL;
        }
-       typhoon_unit.iobase = io;
 
-       if (mutefreq < 87000 || mutefreq > 108500) {
-               printk(KERN_ERR "radio-typhoon: You must set a frequency (in kHz) used when muting the card,\n");
-               printk(KERN_ERR "radio-typhoon: e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n");
+       if (dev->mutefreq < 87000 || dev->mutefreq > 108500) {
+               v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n");
+               v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n");
                return -EINVAL;
        }
-       typhoon_unit.mutefreq = mutefreq;
-#endif /* MODULE */
-
-       printk(KERN_INFO BANNER);
-       mutex_init(&typhoon_unit.lock);
-       io = typhoon_unit.iobase;
-       if (!request_region(io, 8, "typhoon")) {
-               printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n",
-                      typhoon_unit.iobase);
+
+       mutex_init(&dev->lock);
+       if (!request_region(dev->io, 8, "typhoon")) {
+               v4l2_err(v4l2_dev, "port 0x%x already in use\n",
+                      dev->io);
                return -EBUSY;
        }
 
-       video_set_drvdata(&typhoon_radio, &typhoon_unit);
-       if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
-               release_region(io, 8);
+       res = v4l2_device_register(NULL, v4l2_dev);
+       if (res < 0) {
+               release_region(dev->io, 8);
+               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+               return res;
+       }
+       v4l2_info(v4l2_dev, BANNER);
+
+       strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
+       dev->vdev.v4l2_dev = v4l2_dev;
+       dev->vdev.fops = &typhoon_fops;
+       dev->vdev.ioctl_ops = &typhoon_ioctl_ops;
+       dev->vdev.release = video_device_release_empty;
+       video_set_drvdata(&dev->vdev, dev);
+       if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+               v4l2_device_unregister(&dev->v4l2_dev);
+               release_region(dev->io, 8);
                return -EINVAL;
        }
-       printk(KERN_INFO "radio-typhoon: port 0x%x.\n", typhoon_unit.iobase);
-       printk(KERN_INFO "radio-typhoon: mute frequency is %lu kHz.\n",
-              typhoon_unit.mutefreq);
-       typhoon_unit.mutefreq <<= 4;
+       v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io);
+       v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", dev->mutefreq);
+       dev->mutefreq <<= 4;
 
        /* mute card - prevents noisy bootups */
-       typhoon_mute(&typhoon_unit);
-
-#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
-       if (!proc_create("driver/radio-typhoon", 0, NULL, &typhoon_proc_fops))
-               printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n");
-#endif
+       typhoon_mute(dev);
 
        return 0;
 }
 
-static void __exit typhoon_cleanup_module(void)
+static void __exit typhoon_exit(void)
 {
+       struct typhoon *dev = &typhoon_card;
 
-#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
-       remove_proc_entry("driver/radio-typhoon", NULL);
-#endif
-
-       video_unregister_device(&typhoon_radio);
-       release_region(io, 8);
+       video_unregister_device(&dev->vdev);
+       v4l2_device_unregister(&dev->v4l2_dev);
+       release_region(dev->io, 8);
 }
 
 module_init(typhoon_init);
-module_exit(typhoon_cleanup_module);
+module_exit(typhoon_exit);
 
index d2ac17eeec5ffeb30c77a3c528cea291af6ec134..1f85f2024dc041625aca396912147aad44e8e5b0 100644 (file)
 #include <linux/init.h>                /* Initdata                       */
 #include <linux/ioport.h>      /* request_region                 */
 #include <linux/delay.h>       /* udelay, msleep                 */
-#include <asm/io.h>            /* outb, outb_p                   */
-#include <asm/uaccess.h>       /* copy to/from user              */
 #include <linux/videodev2.h>   /* kernel radio structs           */
-#include <media/v4l2-common.h>
+#include <linux/mutex.h>
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#include <linux/io.h>          /* outb, outb_p                   */
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
-
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_AUDIO_VOLUME,
-               .name          = "Volume",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 4096,
-               .default_value = 0xff,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       }
-};
+MODULE_AUTHOR("C.van Schaik");
+MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus.");
+MODULE_LICENSE("GPL");
 
 #ifndef CONFIG_RADIO_ZOLTRIX_PORT
 #define CONFIG_RADIO_ZOLTRIX_PORT -1
@@ -68,9 +51,16 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 static int io = CONFIG_RADIO_ZOLTRIX_PORT;
 static int radio_nr = -1;
 
-struct zol_device {
-       unsigned long in_use;
-       int port;
+module_param(io, int, 0);
+MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)");
+module_param(radio_nr, int, 0);
+
+#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
+
+struct zoltrix {
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       int io;
        int curvol;
        unsigned long curfreq;
        int muted;
@@ -78,161 +68,158 @@ struct zol_device {
        struct mutex lock;
 };
 
-static int zol_setvol(struct zol_device *dev, int vol)
+static struct zoltrix zoltrix_card;
+
+static int zol_setvol(struct zoltrix *zol, int vol)
 {
-       dev->curvol = vol;
-       if (dev->muted)
+       zol->curvol = vol;
+       if (zol->muted)
                return 0;
 
-       mutex_lock(&dev->lock);
+       mutex_lock(&zol->lock);
        if (vol == 0) {
-               outb(0, io);
-               outb(0, io);
-               inb(io + 3);    /* Zoltrix needs to be read to confirm */
-               mutex_unlock(&dev->lock);
+               outb(0, zol->io);
+               outb(0, zol->io);
+               inb(zol->io + 3);    /* Zoltrix needs to be read to confirm */
+               mutex_unlock(&zol->lock);
                return 0;
        }
 
-       outb(dev->curvol-1, io);
+       outb(zol->curvol-1, zol->io);
        msleep(10);
-       inb(io + 2);
-       mutex_unlock(&dev->lock);
+       inb(zol->io + 2);
+       mutex_unlock(&zol->lock);
        return 0;
 }
 
-static void zol_mute(struct zol_device *dev)
+static void zol_mute(struct zoltrix *zol)
 {
-       dev->muted = 1;
-       mutex_lock(&dev->lock);
-       outb(0, io);
-       outb(0, io);
-       inb(io + 3);            /* Zoltrix needs to be read to confirm */
-       mutex_unlock(&dev->lock);
+       zol->muted = 1;
+       mutex_lock(&zol->lock);
+       outb(0, zol->io);
+       outb(0, zol->io);
+       inb(zol->io + 3);            /* Zoltrix needs to be read to confirm */
+       mutex_unlock(&zol->lock);
 }
 
-static void zol_unmute(struct zol_device *dev)
+static void zol_unmute(struct zoltrix *zol)
 {
-       dev->muted = 0;
-       zol_setvol(dev, dev->curvol);
+       zol->muted = 0;
+       zol_setvol(zol, zol->curvol);
 }
 
-static int zol_setfreq(struct zol_device *dev, unsigned long freq)
+static int zol_setfreq(struct zoltrix *zol, unsigned long freq)
 {
        /* tunes the radio to the desired frequency */
+       struct v4l2_device *v4l2_dev = &zol->v4l2_dev;
        unsigned long long bitmask, f, m;
-       unsigned int stereo = dev->stereo;
+       unsigned int stereo = zol->stereo;
        int i;
 
        if (freq == 0) {
-               printk(KERN_WARNING "zoltrix: received zero freq. Failed to set.\n");
+               v4l2_warn(v4l2_dev, "cannot set a frequency of 0.\n");
                return -EINVAL;
        }
 
        m = (freq / 160 - 8800) * 2;
-       f = (unsigned long long) m + 0x4d1c;
+       f = (unsigned long long)m + 0x4d1c;
 
        bitmask = 0xc480402c10080000ull;
        i = 45;
 
-       mutex_lock(&dev->lock);
+       mutex_lock(&zol->lock);
 
-       outb(0, io);
-       outb(0, io);
-       inb(io + 3);            /* Zoltrix needs to be read to confirm */
+       zol->curfreq = freq;
 
-       outb(0x40, io);
-       outb(0xc0, io);
+       outb(0, zol->io);
+       outb(0, zol->io);
+       inb(zol->io + 3);            /* Zoltrix needs to be read to confirm */
 
-       bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ ( stereo << 31));
+       outb(0x40, zol->io);
+       outb(0xc0, zol->io);
+
+       bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ (stereo << 31));
        while (i--) {
                if ((bitmask & 0x8000000000000000ull) != 0) {
-                       outb(0x80, io);
+                       outb(0x80, zol->io);
                        udelay(50);
-                       outb(0x00, io);
+                       outb(0x00, zol->io);
                        udelay(50);
-                       outb(0x80, io);
+                       outb(0x80, zol->io);
                        udelay(50);
                } else {
-                       outb(0xc0, io);
+                       outb(0xc0, zol->io);
                        udelay(50);
-                       outb(0x40, io);
+                       outb(0x40, zol->io);
                        udelay(50);
-                       outb(0xc0, io);
+                       outb(0xc0, zol->io);
                        udelay(50);
                }
                bitmask *= 2;
        }
        /* termination sequence */
-       outb(0x80, io);
-       outb(0xc0, io);
-       outb(0x40, io);
+       outb(0x80, zol->io);
+       outb(0xc0, zol->io);
+       outb(0x40, zol->io);
        udelay(1000);
-       inb(io+2);
+       inb(zol->io + 2);
 
        udelay(1000);
 
-       if (dev->muted)
-       {
-               outb(0, io);
-               outb(0, io);
-               inb(io + 3);
+       if (zol->muted) {
+               outb(0, zol->io);
+               outb(0, zol->io);
+               inb(zol->io + 3);
                udelay(1000);
        }
 
-       mutex_unlock(&dev->lock);
+       mutex_unlock(&zol->lock);
 
-       if(!dev->muted)
-       {
-               zol_setvol(dev, dev->curvol);
-       }
+       if (!zol->muted)
+               zol_setvol(zol, zol->curvol);
        return 0;
 }
 
 /* Get signal strength */
-
-static int zol_getsigstr(struct zol_device *dev)
+static int zol_getsigstr(struct zoltrix *zol)
 {
        int a, b;
 
-       mutex_lock(&dev->lock);
-       outb(0x00, io);         /* This stuff I found to do nothing */
-       outb(dev->curvol, io);
+       mutex_lock(&zol->lock);
+       outb(0x00, zol->io);         /* This stuff I found to do nothing */
+       outb(zol->curvol, zol->io);
        msleep(20);
 
-       a = inb(io);
+       a = inb(zol->io);
        msleep(10);
-       b = inb(io);
+       b = inb(zol->io);
 
-       mutex_unlock(&dev->lock);
+       mutex_unlock(&zol->lock);
 
        if (a != b)
-               return (0);
+               return 0;
 
-       if ((a == 0xcf) || (a == 0xdf)  /* I found this out by playing */
-               || (a == 0xef))       /* with a binary scanner on the card io */
-               return (1);
-       return (0);
+       /* I found this out by playing with a binary scanner on the card io */
+       return a == 0xcf || a == 0xdf || a == 0xef;
 }
 
-static int zol_is_stereo (struct zol_device *dev)
+static int zol_is_stereo(struct zoltrix *zol)
 {
        int x1, x2;
 
-       mutex_lock(&dev->lock);
+       mutex_lock(&zol->lock);
 
-       outb(0x00, io);
-       outb(dev->curvol, io);
+       outb(0x00, zol->io);
+       outb(zol->curvol, zol->io);
        msleep(20);
 
-       x1 = inb(io);
+       x1 = inb(zol->io);
        msleep(10);
-       x2 = inb(io);
+       x2 = inb(zol->io);
 
-       mutex_unlock(&dev->lock);
+       mutex_unlock(&zol->lock);
 
-       if ((x1 == x2) && (x1 == 0xcf))
-               return 1;
-       return 0;
+       return x1 == x2 && x1 == 0xcf;
 }
 
 static int vidioc_querycap(struct file *file, void  *priv,
@@ -240,59 +227,54 @@ static int vidioc_querycap(struct file *file, void  *priv,
 {
        strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver));
        strlcpy(v->card, "Zoltrix Radio", sizeof(v->card));
-       sprintf(v->bus_info, "ISA");
+       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
        v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER;
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
 
 static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       struct zol_device *zol = video_drvdata(file);
+       struct zoltrix *zol = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
 
-       strcpy(v->name, "FM");
+       strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
-       v->rangelow = (88*16000);
-       v->rangehigh = (108*16000);
-       v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+       v->rangelow = 88 * 16000;
+       v->rangehigh = 108 * 16000;
+       v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
        v->capability = V4L2_TUNER_CAP_LOW;
        if (zol_is_stereo(zol))
                v->audmode = V4L2_TUNER_MODE_STEREO;
        else
                v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = 0xFFFF*zol_getsigstr(zol);
+       v->signal = 0xFFFF * zol_getsigstr(zol);
        return 0;
 }
 
 static int vidioc_s_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       if (v->index > 0)
-               return -EINVAL;
-       return 0;
+       return v->index ? -EINVAL : 0;
 }
 
 static int vidioc_s_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct zol_device *zol = video_drvdata(file);
+       struct zoltrix *zol = video_drvdata(file);
 
-       zol->curfreq = f->frequency;
-       if (zol_setfreq(zol, zol->curfreq) != 0) {
-               printk(KERN_WARNING "zoltrix: Set frequency failed.\n");
+       if (zol_setfreq(zol, f->frequency) != 0)
                return -EINVAL;
-       }
        return 0;
 }
 
 static int vidioc_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct zol_device *zol = video_drvdata(file);
+       struct zoltrix *zol = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = zol->curfreq;
@@ -302,14 +284,11 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 static int vidioc_queryctrl(struct file *file, void *priv,
                                        struct v4l2_queryctrl *qc)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]),
-                                               sizeof(*qc));
-                       return 0;
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+       case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(qc, 0, 65535, 4096, 65535);
        }
        return -EINVAL;
 }
@@ -317,7 +296,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
-       struct zol_device *zol = video_drvdata(file);
+       struct zoltrix *zol = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -333,7 +312,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
-       struct zol_device *zol = video_drvdata(file);
+       struct zoltrix *zol = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -341,43 +320,30 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
                        zol_mute(zol);
                else {
                        zol_unmute(zol);
-                       zol_setvol(zol,zol->curvol);
+                       zol_setvol(zol, zol->curvol);
                }
                return 0;
        case V4L2_CID_AUDIO_VOLUME:
-               zol_setvol(zol,ctrl->value/4096);
+               zol_setvol(zol, ctrl->value / 4096);
                return 0;
        }
        zol->stereo = 1;
-       if (zol_setfreq(zol, zol->curfreq) != 0) {
-               printk(KERN_WARNING "zoltrix: Set frequency failed.\n");
+       if (zol_setfreq(zol, zol->curfreq) != 0)
                return -EINVAL;
-       }
 #if 0
 /* FIXME: Implement stereo/mono switch on V4L2 */
-                       if (v->mode & VIDEO_SOUND_STEREO) {
-                               zol->stereo = 1;
-                               zol_setfreq(zol, zol->curfreq);
-                       }
-                       if (v->mode & VIDEO_SOUND_MONO) {
-                               zol->stereo = 0;
-                               zol_setfreq(zol, zol->curfreq);
-                       }
+       if (v->mode & VIDEO_SOUND_STEREO) {
+               zol->stereo = 1;
+               zol_setfreq(zol, zol->curfreq);
+       }
+       if (v->mode & VIDEO_SOUND_MONO) {
+               zol->stereo = 0;
+               zol_setfreq(zol, zol->curfreq);
+       }
 #endif
        return -EINVAL;
 }
 
-static int vidioc_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       if (a->index > 1)
-               return -EINVAL;
-
-       strcpy(a->name, "Radio");
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 {
        *i = 0;
@@ -386,37 +352,39 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 
 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-       if (i != 0)
-               return -EINVAL;
-       return 0;
+       return i ? -EINVAL : 0;
 }
 
-static int vidioc_s_audio(struct file *file, void *priv,
+static int vidioc_g_audio(struct file *file, void *priv,
                                        struct v4l2_audio *a)
 {
-       if (a->index != 0)
-               return -EINVAL;
+       a->index = 0;
+       strlcpy(a->name, "Radio", sizeof(a->name));
+       a->capability = V4L2_AUDCAP_STEREO;
        return 0;
 }
 
-static struct zol_device zoltrix_unit;
+static int vidioc_s_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       return a->index ? -EINVAL : 0;
+}
 
-static int zoltrix_exclusive_open(struct file *file)
+static int zoltrix_open(struct file *file)
 {
-       return test_and_set_bit(0, &zoltrix_unit.in_use) ? -EBUSY : 0;
+       return 0;
 }
 
-static int zoltrix_exclusive_release(struct file *file)
+static int zoltrix_release(struct file *file)
 {
-       clear_bit(0, &zoltrix_unit.in_use);
        return 0;
 }
 
 static const struct v4l2_file_operations zoltrix_fops =
 {
        .owner          = THIS_MODULE,
-       .open           = zoltrix_exclusive_open,
-       .release        = zoltrix_exclusive_release,
+       .open           = zoltrix_open,
+       .release        = zoltrix_release,
        .ioctl          = video_ioctl2,
 };
 
@@ -435,67 +403,75 @@ static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = {
        .vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
-static struct video_device zoltrix_radio = {
-       .name           = "Zoltrix Radio Plus",
-       .fops           = &zoltrix_fops,
-       .ioctl_ops      = &zoltrix_ioctl_ops,
-       .release        = video_device_release_empty,
-};
-
 static int __init zoltrix_init(void)
 {
-       if (io == -1) {
-               printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+       struct zoltrix *zol = &zoltrix_card;
+       struct v4l2_device *v4l2_dev = &zol->v4l2_dev;
+       int res;
+
+       strlcpy(v4l2_dev->name, "zoltrix", sizeof(v4l2_dev->name));
+       zol->io = io;
+       if (zol->io == -1) {
+               v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or 0x30c\n");
                return -EINVAL;
        }
-       if ((io != 0x20c) && (io != 0x30c)) {
-               printk(KERN_ERR "zoltrix: invalid port, try 0x20c or 0x30c\n");
+       if (zol->io != 0x20c && zol->io != 0x30c) {
+               v4l2_err(v4l2_dev, "invalid port, try 0x20c or 0x30c\n");
                return -ENXIO;
        }
 
-       video_set_drvdata(&zoltrix_radio, &zoltrix_unit);
-       if (!request_region(io, 2, "zoltrix")) {
-               printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io);
+       if (!request_region(zol->io, 2, "zoltrix")) {
+               v4l2_err(v4l2_dev, "port 0x%x already in use\n", zol->io);
                return -EBUSY;
        }
 
-       if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
-               release_region(io, 2);
+       res = v4l2_device_register(NULL, v4l2_dev);
+       if (res < 0) {
+               release_region(zol->io, 2);
+               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+               return res;
+       }
+
+       strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name));
+       zol->vdev.v4l2_dev = v4l2_dev;
+       zol->vdev.fops = &zoltrix_fops;
+       zol->vdev.ioctl_ops = &zoltrix_ioctl_ops;
+       zol->vdev.release = video_device_release_empty;
+       video_set_drvdata(&zol->vdev, zol);
+
+       if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+               v4l2_device_unregister(v4l2_dev);
+               release_region(zol->io, 2);
                return -EINVAL;
        }
-       printk(KERN_INFO "Zoltrix Radio Plus card driver.\n");
+       v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n");
 
-       mutex_init(&zoltrix_unit.lock);
+       mutex_init(&zol->lock);
 
        /* mute card - prevents noisy bootups */
 
        /* this ensures that the volume is all the way down  */
 
-       outb(0, io);
-       outb(0, io);
+       outb(0, zol->io);
+       outb(0, zol->io);
        msleep(20);
-       inb(io + 3);
+       inb(zol->io + 3);
 
-       zoltrix_unit.curvol = 0;
-       zoltrix_unit.stereo = 1;
+       zol->curvol = 0;
+       zol->stereo = 1;
 
        return 0;
 }
 
-MODULE_AUTHOR("C.van Schaik");
-MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus.");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)");
-module_param(radio_nr, int, 0);
-
-static void __exit zoltrix_cleanup_module(void)
+static void __exit zoltrix_exit(void)
 {
-       video_unregister_device(&zoltrix_radio);
-       release_region(io, 2);
+       struct zoltrix *zol = &zoltrix_card;
+
+       video_unregister_device(&zol->vdev);
+       v4l2_device_unregister(&zol->v4l2_dev);
+       release_region(zol->io, 2);
 }
 
 module_init(zoltrix_init);
-module_exit(zoltrix_cleanup_module);
+module_exit(zoltrix_exit);
 
index 19cf3b8f67c45213c9cb4dc2f7b887f27b102d1c..76bad58195928625583733b64009cc5e43dd4920 100644 (file)
@@ -249,11 +249,25 @@ config VIDEO_VP27SMPX
          To compile this driver as a module, choose M here: the
          module will be called vp27smpx.
 
+comment "RDS decoders"
+
+config VIDEO_SAA6588
+       tristate "SAA6588 Radio Chip RDS decoder support"
+       depends on VIDEO_V4L2 && I2C
+
+       help
+         Support for this Radio Data System (RDS) decoder. This allows
+         seeing radio station identification transmitted using this
+         standard.
+
+         To compile this driver as a module, choose M here: the
+         module will be called saa6588.
+
 comment "Video decoders"
 
 config VIDEO_BT819
        tristate "BT819A VideoStream decoder"
-       depends on VIDEO_V4L1 && I2C
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for BT819A video decoder.
 
@@ -262,7 +276,7 @@ config VIDEO_BT819
 
 config VIDEO_BT856
        tristate "BT856 VideoStream decoder"
-       depends on VIDEO_V4L1 && I2C
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for BT856 video decoder.
 
@@ -271,7 +285,7 @@ config VIDEO_BT856
 
 config VIDEO_BT866
        tristate "BT866 VideoStream decoder"
-       depends on VIDEO_V4L1 && I2C
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for BT866 video decoder.
 
@@ -280,7 +294,7 @@ config VIDEO_BT866
 
 config VIDEO_KS0127
        tristate "KS0127 video decoder"
-       depends on VIDEO_V4L1 && I2C
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for KS0127 video decoder.
 
@@ -307,38 +321,18 @@ config VIDEO_TCM825X
 
 config VIDEO_SAA7110
        tristate "Philips SAA7110 video decoder"
-       depends on VIDEO_V4L1 && I2C
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for the Philips SAA7110 video decoders.
 
          To compile this driver as a module, choose M here: the
          module will be called saa7110.
 
-config VIDEO_SAA7111
-       tristate "Philips SAA7111 video decoder"
-       depends on VIDEO_V4L1 && I2C
-       ---help---
-         Support for the Philips SAA711 video decoder.
-
-         To compile this driver as a module, choose M here: the
-         module will be called saa7111.
-
-config VIDEO_SAA7114
-       tristate "Philips SAA7114 video decoder"
-       depends on VIDEO_V4L1 && I2C
-       ---help---
-         Support for the Philips SAA7114 video decoder. This driver
-         is used only on Zoran driver and should be moved soon to
-         SAA711x module.
-
-         To compile this driver as a module, choose M here: the
-         module will be called saa7114.
-
 config VIDEO_SAA711X
-       tristate "Philips SAA7113/4/5 video decoders"
+       tristate "Philips SAA7111/3/4/5 video decoders"
        depends on VIDEO_V4L2 && I2C
        ---help---
-         Support for the Philips SAA7113/4/5 video decoders.
+         Support for the Philips SAA7111/3/4/5 video decoders.
 
          To compile this driver as a module, choose M here: the
          module will be called saa7115.
@@ -383,7 +377,7 @@ config VIDEO_TVP5150
 
 config VIDEO_VPX3220
        tristate "vpx3220a, vpx3216b & vpx3214c video decoders"
-       depends on VIDEO_V4L1 && I2C
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for VPX322x video decoders.
 
@@ -421,7 +415,7 @@ config VIDEO_SAA7127
 
 config VIDEO_SAA7185
        tristate "Philips SAA7185 video encoder"
-       depends on VIDEO_V4L1 && I2C
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for the Philips SAA7185 video encoder.
 
@@ -430,7 +424,7 @@ config VIDEO_SAA7185
 
 config VIDEO_ADV7170
        tristate "Analog Devices ADV7170 video encoder"
-       depends on VIDEO_V4L1 && I2C
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for the Analog Devices ADV7170 video encoder driver
 
@@ -439,7 +433,7 @@ config VIDEO_ADV7170
 
 config VIDEO_ADV7175
        tristate "Analog Devices ADV7175 video encoder"
-       depends on VIDEO_V4L1 && I2C
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for the Analog Devices ADV7175 video encoder driver
 
@@ -487,18 +481,6 @@ config VIDEO_VIVI
 
 source "drivers/media/video/bt8xx/Kconfig"
 
-config VIDEO_SAA6588
-       tristate "SAA6588 Radio Chip RDS decoder support on BT848 cards"
-       depends on I2C && VIDEO_BT848
-
-       help
-         Support for  Radio Data System (RDS) decoder. This allows seeing
-         radio station identification transmitted using this standard.
-         Currently, it works only with bt8x8 chips.
-
-         To compile this driver as a module, choose M here: the
-         module will be called saa6588.
-
 config VIDEO_PMS
        tristate "Mediavision Pro Movie Studio Video For Linux"
        depends on ISA && VIDEO_V4L1
@@ -602,7 +584,6 @@ config VIDEO_SAA5249
 config VIDEO_VINO
        tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
        depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
-       select I2C_ALGO_SGI
        select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO
        help
          Say Y here to build in support for the Vino video input system found
@@ -639,7 +620,7 @@ config VIDEO_MXB
        depends on PCI && VIDEO_V4L1 && I2C
        select VIDEO_SAA7146_VV
        select VIDEO_TUNER
-       select VIDEO_SAA7115 if VIDEO_HELPER_CHIPS_AUTO
+       select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_TEA6420 if VIDEO_HELPER_CHIPS_AUTO
@@ -728,13 +709,6 @@ config SOC_CAMERA_MT9M001
          This driver supports MT9M001 cameras from Micron, monochrome
          and colour models.
 
-config MT9M001_PCA9536_SWITCH
-       bool "pca9536 datawidth switch for mt9m001"
-       depends on SOC_CAMERA_MT9M001 && GENERIC_GPIO
-       help
-         Select this if your MT9M001 camera uses a PCA9536 I2C GPIO
-         extender to switch between 8 and 10 bit datawidth modes
-
 config SOC_CAMERA_MT9M111
        tristate "mt9m111 and mt9m112 support"
        depends on SOC_CAMERA && I2C
@@ -754,13 +728,6 @@ config SOC_CAMERA_MT9V022
        help
          This driver supports MT9V022 cameras from Micron
 
-config MT9V022_PCA9536_SWITCH
-       bool "pca9536 datawidth switch for mt9v022"
-       depends on SOC_CAMERA_MT9V022 && GENERIC_GPIO
-       help
-         Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
-         extender to switch between 8 and 10 bit datawidth modes
-
 config SOC_CAMERA_TW9910
        tristate "tw9910 support"
        depends on SOC_CAMERA && I2C
@@ -779,6 +746,13 @@ config SOC_CAMERA_OV772X
        help
          This is a ov772x camera driver
 
+config VIDEO_MX3
+       tristate "i.MX3x Camera Sensor Interface driver"
+       depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
+       select VIDEOBUF_DMA_CONTIG
+       ---help---
+         This is a v4l2 driver for the i.MX3x Camera Sensor Interface
+
 config VIDEO_PXA27x
        tristate "PXA27x Quick Capture Interface driver"
        depends on VIDEO_DEV && PXA27x && SOC_CAMERA
@@ -817,6 +791,8 @@ source "drivers/media/video/gspca/Kconfig"
 
 source "drivers/media/video/pvrusb2/Kconfig"
 
+source "drivers/media/video/hdpvr/Kconfig"
+
 source "drivers/media/video/em28xx/Kconfig"
 
 source "drivers/media/video/usbvision/Kconfig"
index 72f6d03d2d8f472600d60208b75d8e9d30d2f691..b9046744463b9f51cd0fe5d659afde2337d23ab9 100644 (file)
@@ -30,7 +30,6 @@ obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
 obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
 obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
 obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
-obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
 obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
 obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
@@ -43,8 +42,6 @@ obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
 obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
 obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
 obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o
-obj-$(CONFIG_VIDEO_SAA7111) += saa7111.o
-obj-$(CONFIG_VIDEO_SAA7114) += saa7114.o
 obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
 obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o
 obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
@@ -122,6 +119,8 @@ obj-$(CONFIG_USB_PWC)           += pwc/
 obj-$(CONFIG_USB_ZC0301)        += zc0301/
 obj-$(CONFIG_USB_GSPCA)         += gspca/
 
+obj-$(CONFIG_VIDEO_HDPVR)      += hdpvr/
+
 obj-$(CONFIG_USB_IBMCAM)        += usbvideo/
 obj-$(CONFIG_USB_KONICAWC)      += usbvideo/
 obj-$(CONFIG_USB_VICAM)         += usbvideo/
@@ -134,10 +133,11 @@ obj-$(CONFIG_VIDEO_CX18) += cx18/
 obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
-obj-$(CONFIG_VIDEO_PXA27x)     += pxa_camera.o
+obj-$(CONFIG_VIDEO_MX3)                        += mx3_camera.o
+obj-$(CONFIG_VIDEO_PXA27x)             += pxa_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)      += sh_mobile_ceu_camera.o
 obj-$(CONFIG_VIDEO_OMAP2)              += omap2cam.o
-obj-$(CONFIG_SOC_CAMERA)       += soc_camera.o
+obj-$(CONFIG_SOC_CAMERA)               += soc_camera.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)       += mt9m001.o
 obj-$(CONFIG_SOC_CAMERA_MT9M111)       += mt9m111.o
 obj-$(CONFIG_SOC_CAMERA_MT9T031)       += mt9t031.o
index e0eb4f321442c638253ff79f3e7f9f125e3403f7..873c30a41bd74420f408bc41216ea4a8f0d47ba9 100644 (file)
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
-#include <linux/videodev.h>
-#include <linux/video_encoder.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
 MODULE_AUTHOR("Maxim Yevtyushkin");
 MODULE_LICENSE("GPL");
 
+
 static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
@@ -50,38 +51,43 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 /* ----------------------------------------------------------------------- */
 
 struct adv7170 {
+       struct v4l2_subdev sd;
        unsigned char reg[128];
 
-       int norm;
+       v4l2_std_id norm;
        int input;
-       int enable;
-       int bright;
-       int contrast;
-       int hue;
-       int sat;
 };
 
+static inline struct adv7170 *to_adv7170(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct adv7170, sd);
+}
+
 static char *inputs[] = { "pass_through", "play_back" };
-static char *norms[] = { "PAL", "NTSC" };
 
 /* ----------------------------------------------------------------------- */
 
-static inline int adv7170_write(struct i2c_client *client, u8 reg, u8 value)
+static inline int adv7170_write(struct v4l2_subdev *sd, u8 reg, u8 value)
 {
-       struct adv7170 *encoder = i2c_get_clientdata(client);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct adv7170 *encoder = to_adv7170(sd);
 
        encoder->reg[reg] = value;
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static inline int adv7170_read(struct i2c_client *client, u8 reg)
+static inline int adv7170_read(struct v4l2_subdev *sd, u8 reg)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        return i2c_smbus_read_byte_data(client, reg);
 }
 
-static int adv7170_write_block(struct i2c_client *client,
+static int adv7170_write_block(struct v4l2_subdev *sd,
                     const u8 *data, unsigned int len)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct adv7170 *encoder = to_adv7170(sd);
        int ret = -1;
        u8 reg;
 
@@ -89,7 +95,6 @@ static int adv7170_write_block(struct i2c_client *client,
         * the adapter understands raw I2C */
        if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
                /* do raw I2C, not smbus compatible */
-               struct adv7170 *encoder = i2c_get_clientdata(client);
                u8 block_data[32];
                int block_len;
 
@@ -110,7 +115,7 @@ static int adv7170_write_block(struct i2c_client *client,
                /* do some slow I2C emulation kind of thing */
                while (len >= 2) {
                        reg = *data++;
-                       ret = adv7170_write(client, reg, *data++);
+                       ret = adv7170_write(sd, reg, *data++);
                        if (ret < 0)
                                break;
                        len -= 2;
@@ -128,203 +133,161 @@ static int adv7170_write_block(struct i2c_client *client,
 #define TR1PLAY            0x00
 
 static const unsigned char init_NTSC[] = {
-       0x00, 0x10,             // MR0
-       0x01, 0x20,             // MR1
-       0x02, 0x0e,             // MR2 RTC control: bits 2 and 1
-       0x03, 0x80,             // MR3
-       0x04, 0x30,             // MR4
-       0x05, 0x00,             // Reserved
-       0x06, 0x00,             // Reserved
-       0x07, TR0MODE,          // TM0
-       0x08, TR1CAPT,          // TM1
-       0x09, 0x16,             // Fsc0
-       0x0a, 0x7c,             // Fsc1
-       0x0b, 0xf0,             // Fsc2
-       0x0c, 0x21,             // Fsc3
-       0x0d, 0x00,             // Subcarrier Phase
-       0x0e, 0x00,             // Closed Capt. Ext 0
-       0x0f, 0x00,             // Closed Capt. Ext 1
-       0x10, 0x00,             // Closed Capt. 0
-       0x11, 0x00,             // Closed Capt. 1
-       0x12, 0x00,             // Pedestal Ctl 0
-       0x13, 0x00,             // Pedestal Ctl 1
-       0x14, 0x00,             // Pedestal Ctl 2
-       0x15, 0x00,             // Pedestal Ctl 3
-       0x16, 0x00,             // CGMS_WSS_0
-       0x17, 0x00,             // CGMS_WSS_1
-       0x18, 0x00,             // CGMS_WSS_2
-       0x19, 0x00,             // Teletext Ctl
+       0x00, 0x10,             /* MR0 */
+       0x01, 0x20,             /* MR1 */
+       0x02, 0x0e,             /* MR2 RTC control: bits 2 and 1 */
+       0x03, 0x80,             /* MR3 */
+       0x04, 0x30,             /* MR4 */
+       0x05, 0x00,             /* Reserved */
+       0x06, 0x00,             /* Reserved */
+       0x07, TR0MODE,          /* TM0 */
+       0x08, TR1CAPT,          /* TM1 */
+       0x09, 0x16,             /* Fsc0 */
+       0x0a, 0x7c,             /* Fsc1 */
+       0x0b, 0xf0,             /* Fsc2 */
+       0x0c, 0x21,             /* Fsc3 */
+       0x0d, 0x00,             /* Subcarrier Phase */
+       0x0e, 0x00,             /* Closed Capt. Ext 0 */
+       0x0f, 0x00,             /* Closed Capt. Ext 1 */
+       0x10, 0x00,             /* Closed Capt. 0 */
+       0x11, 0x00,             /* Closed Capt. 1 */
+       0x12, 0x00,             /* Pedestal Ctl 0 */
+       0x13, 0x00,             /* Pedestal Ctl 1 */
+       0x14, 0x00,             /* Pedestal Ctl 2 */
+       0x15, 0x00,             /* Pedestal Ctl 3 */
+       0x16, 0x00,             /* CGMS_WSS_0 */
+       0x17, 0x00,             /* CGMS_WSS_1 */
+       0x18, 0x00,             /* CGMS_WSS_2 */
+       0x19, 0x00,             /* Teletext Ctl */
 };
 
 static const unsigned char init_PAL[] = {
-       0x00, 0x71,             // MR0
-       0x01, 0x20,             // MR1
-       0x02, 0x0e,             // MR2 RTC control: bits 2 and 1
-       0x03, 0x80,             // MR3
-       0x04, 0x30,             // MR4
-       0x05, 0x00,             // Reserved
-       0x06, 0x00,             // Reserved
-       0x07, TR0MODE,          // TM0
-       0x08, TR1CAPT,          // TM1
-       0x09, 0xcb,             // Fsc0
-       0x0a, 0x8a,             // Fsc1
-       0x0b, 0x09,             // Fsc2
-       0x0c, 0x2a,             // Fsc3
-       0x0d, 0x00,             // Subcarrier Phase
-       0x0e, 0x00,             // Closed Capt. Ext 0
-       0x0f, 0x00,             // Closed Capt. Ext 1
-       0x10, 0x00,             // Closed Capt. 0
-       0x11, 0x00,             // Closed Capt. 1
-       0x12, 0x00,             // Pedestal Ctl 0
-       0x13, 0x00,             // Pedestal Ctl 1
-       0x14, 0x00,             // Pedestal Ctl 2
-       0x15, 0x00,             // Pedestal Ctl 3
-       0x16, 0x00,             // CGMS_WSS_0
-       0x17, 0x00,             // CGMS_WSS_1
-       0x18, 0x00,             // CGMS_WSS_2
-       0x19, 0x00,             // Teletext Ctl
+       0x00, 0x71,             /* MR0 */
+       0x01, 0x20,             /* MR1 */
+       0x02, 0x0e,             /* MR2 RTC control: bits 2 and 1 */
+       0x03, 0x80,             /* MR3 */
+       0x04, 0x30,             /* MR4 */
+       0x05, 0x00,             /* Reserved */
+       0x06, 0x00,             /* Reserved */
+       0x07, TR0MODE,          /* TM0 */
+       0x08, TR1CAPT,          /* TM1 */
+       0x09, 0xcb,             /* Fsc0 */
+       0x0a, 0x8a,             /* Fsc1 */
+       0x0b, 0x09,             /* Fsc2 */
+       0x0c, 0x2a,             /* Fsc3 */
+       0x0d, 0x00,             /* Subcarrier Phase */
+       0x0e, 0x00,             /* Closed Capt. Ext 0 */
+       0x0f, 0x00,             /* Closed Capt. Ext 1 */
+       0x10, 0x00,             /* Closed Capt. 0 */
+       0x11, 0x00,             /* Closed Capt. 1 */
+       0x12, 0x00,             /* Pedestal Ctl 0 */
+       0x13, 0x00,             /* Pedestal Ctl 1 */
+       0x14, 0x00,             /* Pedestal Ctl 2 */
+       0x15, 0x00,             /* Pedestal Ctl 3 */
+       0x16, 0x00,             /* CGMS_WSS_0 */
+       0x17, 0x00,             /* CGMS_WSS_1 */
+       0x18, 0x00,             /* CGMS_WSS_2 */
+       0x19, 0x00,             /* Teletext Ctl */
 };
 
 
-static int adv7170_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int adv7170_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
 {
-       struct adv7170 *encoder = i2c_get_clientdata(client);
-
-       switch (cmd) {
-       case 0:
-#if 0
-               /* This is just for testing!!! */
-               adv7170_write_block(client, init_common,
-                                   sizeof(init_common));
-               adv7170_write(client, 0x07, TR0MODE | TR0RST);
-               adv7170_write(client, 0x07, TR0MODE);
-#endif
-               break;
-
-       case ENCODER_GET_CAPABILITIES:
-       {
-               struct video_encoder_capability *cap = arg;
-
-               cap->flags = VIDEO_ENCODER_PAL |
-                            VIDEO_ENCODER_NTSC;
-               cap->inputs = 2;
-               cap->outputs = 1;
-               break;
+       struct adv7170 *encoder = to_adv7170(sd);
+
+       v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
+
+       if (std & V4L2_STD_NTSC) {
+               adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC));
+               if (encoder->input == 0)
+                       adv7170_write(sd, 0x02, 0x0e);  /* Enable genlock */
+               adv7170_write(sd, 0x07, TR0MODE | TR0RST);
+               adv7170_write(sd, 0x07, TR0MODE);
+       } else if (std & V4L2_STD_PAL) {
+               adv7170_write_block(sd, init_PAL, sizeof(init_PAL));
+               if (encoder->input == 0)
+                       adv7170_write(sd, 0x02, 0x0e);  /* Enable genlock */
+               adv7170_write(sd, 0x07, TR0MODE | TR0RST);
+               adv7170_write(sd, 0x07, TR0MODE);
+       } else {
+               v4l2_dbg(1, debug, sd, "illegal norm: %llx\n",
+                               (unsigned long long)std);
+               return -EINVAL;
        }
+       v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std);
+       encoder->norm = std;
+       return 0;
+}
 
-       case ENCODER_SET_NORM:
-       {
-               int iarg = *(int *) arg;
-
-               v4l_dbg(1, debug, client, "set norm %d\n", iarg);
-
-               switch (iarg) {
-               case VIDEO_MODE_NTSC:
-                       adv7170_write_block(client, init_NTSC,
-                                           sizeof(init_NTSC));
-                       if (encoder->input == 0)
-                               adv7170_write(client, 0x02, 0x0e);      // Enable genlock
-                       adv7170_write(client, 0x07, TR0MODE | TR0RST);
-                       adv7170_write(client, 0x07, TR0MODE);
-                       break;
-
-               case VIDEO_MODE_PAL:
-                       adv7170_write_block(client, init_PAL,
-                                           sizeof(init_PAL));
-                       if (encoder->input == 0)
-                               adv7170_write(client, 0x02, 0x0e);      // Enable genlock
-                       adv7170_write(client, 0x07, TR0MODE | TR0RST);
-                       adv7170_write(client, 0x07, TR0MODE);
-                       break;
-
-               default:
-                       v4l_dbg(1, debug, client, "illegal norm: %d\n", iarg);
-                       return -EINVAL;
-               }
-               v4l_dbg(1, debug, client, "switched to %s\n", norms[iarg]);
-               encoder->norm = iarg;
-               break;
-       }
+static int adv7170_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct adv7170 *encoder = to_adv7170(sd);
 
-       case ENCODER_SET_INPUT:
-       {
-               int iarg = *(int *) arg;
-
-               /* RJ: *iarg = 0: input is from decoder
-                *iarg = 1: input is from ZR36060
-                *iarg = 2: color bar */
-
-               v4l_dbg(1, debug, client, "set input from %s\n",
-                       iarg == 0 ? "decoder" : "ZR36060");
-
-               switch (iarg) {
-               case 0:
-                       adv7170_write(client, 0x01, 0x20);
-                       adv7170_write(client, 0x08, TR1CAPT);   /* TR1 */
-                       adv7170_write(client, 0x02, 0x0e);      // Enable genlock
-                       adv7170_write(client, 0x07, TR0MODE | TR0RST);
-                       adv7170_write(client, 0x07, TR0MODE);
-                       /* udelay(10); */
-                       break;
-
-               case 1:
-                       adv7170_write(client, 0x01, 0x00);
-                       adv7170_write(client, 0x08, TR1PLAY);   /* TR1 */
-                       adv7170_write(client, 0x02, 0x08);
-                       adv7170_write(client, 0x07, TR0MODE | TR0RST);
-                       adv7170_write(client, 0x07, TR0MODE);
-                       /* udelay(10); */
-                       break;
-
-               default:
-                       v4l_dbg(1, debug, client, "illegal input: %d\n", iarg);
-                       return -EINVAL;
-               }
-               v4l_dbg(1, debug, client, "switched to %s\n", inputs[iarg]);
-               encoder->input = iarg;
-               break;
-       }
+       /* RJ: route->input = 0: input is from decoder
+          route->input = 1: input is from ZR36060
+          route->input = 2: color bar */
 
-       case ENCODER_SET_OUTPUT:
-       {
-               int *iarg = arg;
+       v4l2_dbg(1, debug, sd, "set input from %s\n",
+                       route->input == 0 ? "decoder" : "ZR36060");
 
-               /* not much choice of outputs */
-               if (*iarg != 0) {
-                       return -EINVAL;
-               }
+       switch (route->input) {
+       case 0:
+               adv7170_write(sd, 0x01, 0x20);
+               adv7170_write(sd, 0x08, TR1CAPT);       /* TR1 */
+               adv7170_write(sd, 0x02, 0x0e);  /* Enable genlock */
+               adv7170_write(sd, 0x07, TR0MODE | TR0RST);
+               adv7170_write(sd, 0x07, TR0MODE);
+               /* udelay(10); */
                break;
-       }
-
-       case ENCODER_ENABLE_OUTPUT:
-       {
-               int *iarg = arg;
 
-               encoder->enable = !!*iarg;
+       case 1:
+               adv7170_write(sd, 0x01, 0x00);
+               adv7170_write(sd, 0x08, TR1PLAY);       /* TR1 */
+               adv7170_write(sd, 0x02, 0x08);
+               adv7170_write(sd, 0x07, TR0MODE | TR0RST);
+               adv7170_write(sd, 0x07, TR0MODE);
+               /* udelay(10); */
                break;
-       }
 
        default:
+               v4l2_dbg(1, debug, sd, "illegal input: %d\n", route->input);
                return -EINVAL;
        }
-
+       v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[route->input]);
+       encoder->input = route->input;
        return 0;
 }
 
+static int adv7170_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7170, 0);
+}
+
 /* ----------------------------------------------------------------------- */
 
-static unsigned short normal_i2c[] = {
-       0xd4 >> 1, 0xd6 >> 1,   /* adv7170 IDs */
-       0x54 >> 1, 0x56 >> 1,   /* adv7171 IDs */
-       I2C_CLIENT_END
+static const struct v4l2_subdev_core_ops adv7170_core_ops = {
+       .g_chip_ident = adv7170_g_chip_ident,
 };
 
-I2C_CLIENT_INSMOD;
+static const struct v4l2_subdev_video_ops adv7170_video_ops = {
+       .s_std_output = adv7170_s_std_output,
+       .s_routing = adv7170_s_routing,
+};
+
+static const struct v4l2_subdev_ops adv7170_ops = {
+       .core = &adv7170_core_ops,
+       .video = &adv7170_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
 
 static int adv7170_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        struct adv7170 *encoder;
+       struct v4l2_subdev *sd;
        int i;
 
        /* Check if the adapter supports the needed features */
@@ -337,26 +300,29 @@ static int adv7170_probe(struct i2c_client *client,
        encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL);
        if (encoder == NULL)
                return -ENOMEM;
-       encoder->norm = VIDEO_MODE_NTSC;
+       sd = &encoder->sd;
+       v4l2_i2c_subdev_init(sd, client, &adv7170_ops);
+       encoder->norm = V4L2_STD_NTSC;
        encoder->input = 0;
-       encoder->enable = 1;
-       i2c_set_clientdata(client, encoder);
 
-       i = adv7170_write_block(client, init_NTSC, sizeof(init_NTSC));
+       i = adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC));
        if (i >= 0) {
-               i = adv7170_write(client, 0x07, TR0MODE | TR0RST);
-               i = adv7170_write(client, 0x07, TR0MODE);
-               i = adv7170_read(client, 0x12);
-               v4l_dbg(1, debug, client, "revision %d\n", i & 1);
+               i = adv7170_write(sd, 0x07, TR0MODE | TR0RST);
+               i = adv7170_write(sd, 0x07, TR0MODE);
+               i = adv7170_read(sd, 0x12);
+               v4l2_dbg(1, debug, sd, "revision %d\n", i & 1);
        }
        if (i < 0)
-               v4l_dbg(1, debug, client, "init error 0x%x\n", i);
+               v4l2_dbg(1, debug, sd, "init error 0x%x\n", i);
        return 0;
 }
 
 static int adv7170_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_adv7170(sd));
        return 0;
 }
 
@@ -371,8 +337,6 @@ MODULE_DEVICE_TABLE(i2c, adv7170_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "adv7170",
-       .driverid = I2C_DRIVERID_ADV7170,
-       .command = adv7170_command,
        .probe = adv7170_probe,
        .remove = adv7170_remove,
        .id_table = adv7170_id,
index 6008e84653f1d67fd13eaaf7946c3913494e4f03..ff12103032952c058178166f1c631d9dc38572a0 100644 (file)
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
-#include <linux/videodev.h>
-#include <linux/video_encoder.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
 MODULE_AUTHOR("Dave Perks");
 MODULE_LICENSE("GPL");
 
+#define   I2C_ADV7175        0xd4
+#define   I2C_ADV7176        0x54
+
+
 static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
@@ -46,36 +50,38 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 /* ----------------------------------------------------------------------- */
 
 struct adv7175 {
-       int norm;
+       struct v4l2_subdev sd;
+       v4l2_std_id norm;
        int input;
-       int enable;
-       int bright;
-       int contrast;
-       int hue;
-       int sat;
 };
 
-#define   I2C_ADV7175        0xd4
-#define   I2C_ADV7176        0x54
+static inline struct adv7175 *to_adv7175(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct adv7175, sd);
+}
 
 static char *inputs[] = { "pass_through", "play_back", "color_bar" };
-static char *norms[] = { "PAL", "NTSC", "SECAM->PAL (may not work!)" };
 
 /* ----------------------------------------------------------------------- */
 
-static inline int adv7175_write(struct i2c_client *client, u8 reg, u8 value)
+static inline int adv7175_write(struct v4l2_subdev *sd, u8 reg, u8 value)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static inline int adv7175_read(struct i2c_client *client, u8 reg)
+static inline int adv7175_read(struct v4l2_subdev *sd, u8 reg)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        return i2c_smbus_read_byte_data(client, reg);
 }
 
-static int adv7175_write_block(struct i2c_client *client,
+static int adv7175_write_block(struct v4l2_subdev *sd,
                     const u8 *data, unsigned int len)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int ret = -1;
        u8 reg;
 
@@ -103,7 +109,7 @@ static int adv7175_write_block(struct i2c_client *client,
                /* do some slow I2C emulation kind of thing */
                while (len >= 2) {
                        reg = *data++;
-                       ret = adv7175_write(client, reg, *data++);
+                       ret = adv7175_write(sd, reg, *data++);
                        if (ret < 0)
                                break;
                        len -= 2;
@@ -113,18 +119,18 @@ static int adv7175_write_block(struct i2c_client *client,
        return ret;
 }
 
-static void set_subcarrier_freq(struct i2c_client *client, int pass_through)
+static void set_subcarrier_freq(struct v4l2_subdev *sd, int pass_through)
 {
        /* for some reason pass_through NTSC needs
         * a different sub-carrier freq to remain stable. */
        if (pass_through)
-               adv7175_write(client, 0x02, 0x00);
+               adv7175_write(sd, 0x02, 0x00);
        else
-               adv7175_write(client, 0x02, 0x55);
+               adv7175_write(sd, 0x02, 0x55);
 
-       adv7175_write(client, 0x03, 0x55);
-       adv7175_write(client, 0x04, 0x55);
-       adv7175_write(client, 0x05, 0x25);
+       adv7175_write(sd, 0x03, 0x55);
+       adv7175_write(sd, 0x04, 0x55);
+       adv7175_write(sd, 0x05, 0x25);
 }
 
 /* ----------------------------------------------------------------------- */
@@ -184,180 +190,144 @@ static const unsigned char init_ntsc[] = {
        0x06, 0x1a,             /* subc. phase */
 };
 
-static int adv7175_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int adv7175_init(struct v4l2_subdev *sd, u32 val)
 {
-       struct adv7175 *encoder = i2c_get_clientdata(client);
+       /* This is just for testing!!! */
+       adv7175_write_block(sd, init_common, sizeof(init_common));
+       adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+       adv7175_write(sd, 0x07, TR0MODE);
+       return 0;
+}
 
-       switch (cmd) {
-       case 0:
-               /* This is just for testing!!! */
-               adv7175_write_block(client, init_common,
-                                   sizeof(init_common));
-               adv7175_write(client, 0x07, TR0MODE | TR0RST);
-               adv7175_write(client, 0x07, TR0MODE);
-               break;
+static int adv7175_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct adv7175 *encoder = to_adv7175(sd);
+
+       if (std & V4L2_STD_NTSC) {
+               adv7175_write_block(sd, init_ntsc, sizeof(init_ntsc));
+               if (encoder->input == 0)
+                       adv7175_write(sd, 0x0d, 0x4f);  /* Enable genlock */
+               adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+               adv7175_write(sd, 0x07, TR0MODE);
+       } else if (std & V4L2_STD_PAL) {
+               adv7175_write_block(sd, init_pal, sizeof(init_pal));
+               if (encoder->input == 0)
+                       adv7175_write(sd, 0x0d, 0x4f);  /* Enable genlock */
+               adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+               adv7175_write(sd, 0x07, TR0MODE);
+       } else if (std & V4L2_STD_SECAM) {
+               /* This is an attempt to convert
+                * SECAM->PAL (typically it does not work
+                * due to genlock: when decoder is in SECAM
+                * and encoder in in PAL the subcarrier can
+                * not be syncronized with horizontal
+                * quency) */
+               adv7175_write_block(sd, init_pal, sizeof(init_pal));
+               if (encoder->input == 0)
+                       adv7175_write(sd, 0x0d, 0x49);  /* Disable genlock */
+               adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+               adv7175_write(sd, 0x07, TR0MODE);
+       } else {
+               v4l2_dbg(1, debug, sd, "illegal norm: %llx\n",
+                               (unsigned long long)std);
+               return -EINVAL;
+       }
+       v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std);
+       encoder->norm = std;
+       return 0;
+}
 
-       case ENCODER_GET_CAPABILITIES:
-       {
-               struct video_encoder_capability *cap = arg;
+static int adv7175_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct adv7175 *encoder = to_adv7175(sd);
 
-               cap->flags = VIDEO_ENCODER_PAL |
-                            VIDEO_ENCODER_NTSC |
-                            VIDEO_ENCODER_SECAM; /* well, hacky */
-               cap->inputs = 2;
-               cap->outputs = 1;
-               break;
-       }
+       /* RJ: route->input = 0: input is from decoder
+          route->input = 1: input is from ZR36060
+          route->input = 2: color bar */
 
-       case ENCODER_SET_NORM:
-       {
-               int iarg = *(int *) arg;
-
-               switch (iarg) {
-               case VIDEO_MODE_NTSC:
-                       adv7175_write_block(client, init_ntsc,
-                                           sizeof(init_ntsc));
-                       if (encoder->input == 0)
-                               adv7175_write(client, 0x0d, 0x4f);      // Enable genlock
-                       adv7175_write(client, 0x07, TR0MODE | TR0RST);
-                       adv7175_write(client, 0x07, TR0MODE);
-                       break;
-
-               case VIDEO_MODE_PAL:
-                       adv7175_write_block(client, init_pal,
-                                           sizeof(init_pal));
-                       if (encoder->input == 0)
-                               adv7175_write(client, 0x0d, 0x4f);      // Enable genlock
-                       adv7175_write(client, 0x07, TR0MODE | TR0RST);
-                       adv7175_write(client, 0x07, TR0MODE);
-                       break;
-
-               case VIDEO_MODE_SECAM:  // WARNING! ADV7176 does not support SECAM.
-                       /* This is an attempt to convert
-                        * SECAM->PAL (typically it does not work
-                        * due to genlock: when decoder is in SECAM
-                        * and encoder in in PAL the subcarrier can
-                        * not be syncronized with horizontal
-                        * quency) */
-                       adv7175_write_block(client, init_pal,
-                                           sizeof(init_pal));
-                       if (encoder->input == 0)
-                               adv7175_write(client, 0x0d, 0x49);      // Disable genlock
-                       adv7175_write(client, 0x07, TR0MODE | TR0RST);
-                       adv7175_write(client, 0x07, TR0MODE);
-                       break;
-               default:
-                       v4l_dbg(1, debug, client, "illegal norm: %d\n", iarg);
-                       return -EINVAL;
-               }
-               v4l_dbg(1, debug, client, "switched to %s\n", norms[iarg]);
-               encoder->norm = iarg;
+       switch (route->input) {
+       case 0:
+               adv7175_write(sd, 0x01, 0x00);
+
+               if (encoder->norm & V4L2_STD_NTSC)
+                       set_subcarrier_freq(sd, 1);
+
+               adv7175_write(sd, 0x0c, TR1CAPT);       /* TR1 */
+               if (encoder->norm & V4L2_STD_SECAM)
+                       adv7175_write(sd, 0x0d, 0x49);  /* Disable genlock */
+               else
+                       adv7175_write(sd, 0x0d, 0x4f);  /* Enable genlock */
+               adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+               adv7175_write(sd, 0x07, TR0MODE);
+               /*udelay(10);*/
                break;
-       }
 
-       case ENCODER_SET_INPUT:
-       {
-               int iarg = *(int *) arg;
-
-               /* RJ: *iarg = 0: input is from SAA7110
-                *iarg = 1: input is from ZR36060
-                *iarg = 2: color bar */
-
-               switch (iarg) {
-               case 0:
-                       adv7175_write(client, 0x01, 0x00);
-
-                       if (encoder->norm == VIDEO_MODE_NTSC)
-                               set_subcarrier_freq(client, 1);
-
-                       adv7175_write(client, 0x0c, TR1CAPT);   /* TR1 */
-                       if (encoder->norm == VIDEO_MODE_SECAM)
-                               adv7175_write(client, 0x0d, 0x49);      // Disable genlock
-                       else
-                               adv7175_write(client, 0x0d, 0x4f);      // Enable genlock
-                       adv7175_write(client, 0x07, TR0MODE | TR0RST);
-                       adv7175_write(client, 0x07, TR0MODE);
-                       //udelay(10);
-                       break;
-
-               case 1:
-                       adv7175_write(client, 0x01, 0x00);
-
-                       if (encoder->norm == VIDEO_MODE_NTSC)
-                               set_subcarrier_freq(client, 0);
-
-                       adv7175_write(client, 0x0c, TR1PLAY);   /* TR1 */
-                       adv7175_write(client, 0x0d, 0x49);
-                       adv7175_write(client, 0x07, TR0MODE | TR0RST);
-                       adv7175_write(client, 0x07, TR0MODE);
-                       /* udelay(10); */
-                       break;
-
-               case 2:
-                       adv7175_write(client, 0x01, 0x80);
-
-                       if (encoder->norm == VIDEO_MODE_NTSC)
-                               set_subcarrier_freq(client, 0);
-
-                       adv7175_write(client, 0x0d, 0x49);
-                       adv7175_write(client, 0x07, TR0MODE | TR0RST);
-                       adv7175_write(client, 0x07, TR0MODE);
-                       /* udelay(10); */
-                       break;
-
-               default:
-                       v4l_dbg(1, debug, client, "illegal input: %d\n", iarg);
-                       return -EINVAL;
-               }
-               v4l_dbg(1, debug, client, "switched to %s\n", inputs[iarg]);
-               encoder->input = iarg;
-               break;
-       }
+       case 1:
+               adv7175_write(sd, 0x01, 0x00);
 
-       case ENCODER_SET_OUTPUT:
-       {
-               int *iarg = arg;
+               if (encoder->norm & V4L2_STD_NTSC)
+                       set_subcarrier_freq(sd, 0);
 
-               /* not much choice of outputs */
-               if (*iarg != 0)
-                       return -EINVAL;
+               adv7175_write(sd, 0x0c, TR1PLAY);       /* TR1 */
+               adv7175_write(sd, 0x0d, 0x49);
+               adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+               adv7175_write(sd, 0x07, TR0MODE);
+               /* udelay(10); */
                break;
-       }
 
-       case ENCODER_ENABLE_OUTPUT:
-       {
-               int *iarg = arg;
+       case 2:
+               adv7175_write(sd, 0x01, 0x80);
+
+               if (encoder->norm & V4L2_STD_NTSC)
+                       set_subcarrier_freq(sd, 0);
 
-               encoder->enable = !!*iarg;
+               adv7175_write(sd, 0x0d, 0x49);
+               adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+               adv7175_write(sd, 0x07, TR0MODE);
+               /* udelay(10); */
                break;
-       }
 
        default:
+               v4l2_dbg(1, debug, sd, "illegal input: %d\n", route->input);
                return -EINVAL;
        }
-
+       v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[route->input]);
+       encoder->input = route->input;
        return 0;
 }
 
+static int adv7175_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7175, 0);
+}
+
 /* ----------------------------------------------------------------------- */
 
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-static unsigned short normal_i2c[] = {
-       I2C_ADV7175 >> 1, (I2C_ADV7175 >> 1) + 1,
-       I2C_ADV7176 >> 1, (I2C_ADV7176 >> 1) + 1,
-       I2C_CLIENT_END
+static const struct v4l2_subdev_core_ops adv7175_core_ops = {
+       .g_chip_ident = adv7175_g_chip_ident,
+       .init = adv7175_init,
 };
 
-I2C_CLIENT_INSMOD;
+static const struct v4l2_subdev_video_ops adv7175_video_ops = {
+       .s_std_output = adv7175_s_std_output,
+       .s_routing = adv7175_s_routing,
+};
+
+static const struct v4l2_subdev_ops adv7175_ops = {
+       .core = &adv7175_core_ops,
+       .video = &adv7175_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
 
 static int adv7175_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        int i;
        struct adv7175 *encoder;
+       struct v4l2_subdev *sd;
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -369,26 +339,29 @@ static int adv7175_probe(struct i2c_client *client,
        encoder = kzalloc(sizeof(struct adv7175), GFP_KERNEL);
        if (encoder == NULL)
                return -ENOMEM;
-       encoder->norm = VIDEO_MODE_PAL;
+       sd = &encoder->sd;
+       v4l2_i2c_subdev_init(sd, client, &adv7175_ops);
+       encoder->norm = V4L2_STD_NTSC;
        encoder->input = 0;
-       encoder->enable = 1;
-       i2c_set_clientdata(client, encoder);
 
-       i = adv7175_write_block(client, init_common, sizeof(init_common));
+       i = adv7175_write_block(sd, init_common, sizeof(init_common));
        if (i >= 0) {
-               i = adv7175_write(client, 0x07, TR0MODE | TR0RST);
-               i = adv7175_write(client, 0x07, TR0MODE);
-               i = adv7175_read(client, 0x12);
-               v4l_dbg(1, debug, client, "revision %d\n", i & 1);
+               i = adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+               i = adv7175_write(sd, 0x07, TR0MODE);
+               i = adv7175_read(sd, 0x12);
+               v4l2_dbg(1, debug, sd, "revision %d\n", i & 1);
        }
        if (i < 0)
-               v4l_dbg(1, debug, client, "init error 0x%x\n", i);
+               v4l2_dbg(1, debug, sd, "init error 0x%x\n", i);
        return 0;
 }
 
 static int adv7175_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_adv7175(sd));
        return 0;
 }
 
@@ -403,8 +376,6 @@ MODULE_DEVICE_TABLE(i2c, adv7175_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "adv7175",
-       .driverid = I2C_DRIVERID_ADV7175,
-       .command = adv7175_command,
        .probe = adv7175_probe,
        .remove = adv7175_remove,
        .id_table = adv7175_id,
index 018f72b8e3e201cf45c2abb07d41c8aa6ec7a0cb..05cdf494dfb0d7c320f4dcaf5a6dc63e9f5d83da 100644 (file)
@@ -1,13 +1,13 @@
 
 config VIDEO_AU0828
        tristate "Auvitek AU0828 support"
-       depends on I2C && INPUT && DVB_CORE && USB
+       depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2
        select I2C_ALGOBIT
        select VIDEO_TVEEPROM
-       select DVB_AU8522 if !DVB_FE_CUSTOMIZE
-       select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
-       select MEDIA_TUNER_MXL5007T if !DVB_FE_CUSTOMIZE
-       select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
+       select DVB_AU8522 if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
        ---help---
          This is a video4linux driver for Auvitek's USB device.
 
index cd2c58281b4eda4c26ac46483f10208389a881d5..4d2623158188943cb4ff8d02c227f6e143debea5 100644 (file)
@@ -1,4 +1,4 @@
-au0828-objs    := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o
+au0828-objs    := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o
 
 obj-$(CONFIG_VIDEO_AU0828) += au0828.o
 
index d60123b413f59a2e16a5225c38a336b3b47f85b0..1aabaa7e55bb0bb3f7930bc13ff6e831c4b73c41 100644 (file)
 
 #include "au0828.h"
 #include "au0828-cards.h"
+#include "au8522.h"
+#include "media/tuner.h"
+#include "media/v4l2-common.h"
+
+void hvr950q_cs5340_audio(void *priv, int enable)
+{
+       /* Because the HVR-950q shares an i2s bus between the cs5340 and the
+          au8522, we need to hold cs5340 in reset when using the au8522 */
+       struct au0828_dev *dev = priv;
+       if (enable == 1)
+               au0828_set(dev, REG_000, 0x10);
+       else
+               au0828_clear(dev, REG_000, 0x10);
+}
 
 struct au0828_board au0828_boards[] = {
        [AU0828_BOARD_UNKNOWN] = {
                .name   = "Unknown board",
+               .tuner_type = UNSET,
+               .tuner_addr = ADDR_UNSET,
        },
        [AU0828_BOARD_HAUPPAUGE_HVR850] = {
                .name   = "Hauppauge HVR850",
+               .tuner_type = TUNER_XC5000,
+               .tuner_addr = 0x61,
+               .input = {
+                       {
+                               .type = AU0828_VMUX_TELEVISION,
+                               .vmux = AU8522_COMPOSITE_CH4_SIF,
+                               .amux = AU8522_AUDIO_SIF,
+                       },
+                       {
+                               .type = AU0828_VMUX_COMPOSITE,
+                               .vmux = AU8522_COMPOSITE_CH1,
+                               .amux = AU8522_AUDIO_NONE,
+                               .audio_setup = hvr950q_cs5340_audio,
+                       },
+                       {
+                               .type = AU0828_VMUX_SVIDEO,
+                               .vmux = AU8522_SVIDEO_CH13,
+                               .amux = AU8522_AUDIO_NONE,
+                               .audio_setup = hvr950q_cs5340_audio,
+                       },
+               },
        },
        [AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
                .name   = "Hauppauge HVR950Q",
+               .tuner_type = TUNER_XC5000,
+               .tuner_addr = 0x61,
+               .input = {
+                       {
+                               .type = AU0828_VMUX_TELEVISION,
+                               .vmux = AU8522_COMPOSITE_CH4_SIF,
+                               .amux = AU8522_AUDIO_SIF,
+                       },
+                       {
+                               .type = AU0828_VMUX_COMPOSITE,
+                               .vmux = AU8522_COMPOSITE_CH1,
+                               .amux = AU8522_AUDIO_NONE,
+                               .audio_setup = hvr950q_cs5340_audio,
+                       },
+                       {
+                               .type = AU0828_VMUX_SVIDEO,
+                               .vmux = AU8522_SVIDEO_CH13,
+                               .amux = AU8522_AUDIO_NONE,
+                               .audio_setup = hvr950q_cs5340_audio,
+                       },
+               },
        },
        [AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = {
                .name   = "Hauppauge HVR950Q rev xxF8",
+               .tuner_type = UNSET,
+               .tuner_addr = ADDR_UNSET,
        },
        [AU0828_BOARD_DVICO_FUSIONHDTV7] = {
                .name   = "DViCO FusionHDTV USB",
+               .tuner_type = UNSET,
+               .tuner_addr = ADDR_UNSET,
        },
        [AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
                .name = "Hauppauge Woodbury",
+               .tuner_type = UNSET,
+               .tuner_addr = ADDR_UNSET,
        },
 };
 
@@ -52,7 +116,7 @@ int au0828_tuner_callback(void *priv, int component, int command, int arg)
 
        dprintk(1, "%s()\n", __func__);
 
-       switch (dev->board) {
+       switch (dev->boardnr) {
        case AU0828_BOARD_HAUPPAUGE_HVR850:
        case AU0828_BOARD_HAUPPAUGE_HVR950Q:
        case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
@@ -81,17 +145,18 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
        struct tveeprom tv;
 
        tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
+       dev->board.tuner_type = tv.tuner_type;
 
        /* Make sure we support the board model */
        switch (tv.model) {
        case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */
-       case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */
-       case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
-       case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
-       case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
-       case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and basic analog video */
-       case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */
-       case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and basic analog video */
+       case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
+       case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+       case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+       case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+       case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
+       case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
+       case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */
        case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
                break;
        default:
@@ -107,15 +172,21 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
 void au0828_card_setup(struct au0828_dev *dev)
 {
        static u8 eeprom[256];
+       struct tuner_setup tun_setup;
+       struct v4l2_subdev *sd;
+       unsigned int mode_mask = T_ANALOG_TV |
+                                T_DIGITAL_TV;
 
        dprintk(1, "%s()\n", __func__);
 
+       memcpy(&dev->board, &au0828_boards[dev->boardnr], sizeof(dev->board));
+
        if (dev->i2c_rc == 0) {
                dev->i2c_client.addr = 0xa0 >> 1;
                tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom));
        }
 
-       switch (dev->board) {
+       switch (dev->boardnr) {
        case AU0828_BOARD_HAUPPAUGE_HVR850:
        case AU0828_BOARD_HAUPPAUGE_HVR950Q:
        case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
@@ -124,6 +195,32 @@ void au0828_card_setup(struct au0828_dev *dev)
                        hauppauge_eeprom(dev, eeprom+0xa0);
                break;
        }
+
+       if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
+               /* Load the analog demodulator driver (note this would need to
+                  be abstracted out if we ever need to support a different
+                  demod) */
+               sd = v4l2_i2c_new_subdev(&dev->i2c_adap, "au8522", "au8522",
+                                        0x8e >> 1);
+               if (sd == NULL)
+                       printk(KERN_ERR "analog subdev registration failed\n");
+       }
+
+       /* Setup tuners */
+       if (dev->board.tuner_type != TUNER_ABSENT) {
+               /* Load the tuner module, which does the attach */
+               sd = v4l2_i2c_new_subdev(&dev->i2c_adap, "tuner", "tuner",
+                                        dev->board.tuner_addr);
+               if (sd == NULL)
+                       printk(KERN_ERR "tuner subdev registration fail\n");
+
+               tun_setup.mode_mask      = mode_mask;
+               tun_setup.type           = dev->board.tuner_type;
+               tun_setup.addr           = dev->board.tuner_addr;
+               tun_setup.tuner_callback = au0828_tuner_callback;
+               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr,
+                                    &tun_setup);
+       }
 }
 
 /*
@@ -135,7 +232,7 @@ void au0828_gpio_setup(struct au0828_dev *dev)
 {
        dprintk(1, "%s()\n", __func__);
 
-       switch (dev->board) {
+       switch (dev->boardnr) {
        case AU0828_BOARD_HAUPPAUGE_HVR850:
        case AU0828_BOARD_HAUPPAUGE_HVR950Q:
        case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
@@ -144,21 +241,23 @@ void au0828_gpio_setup(struct au0828_dev *dev)
                 * 4 - CS5340
                 * 5 - AU8522 Demodulator
                 * 6 - eeprom W/P
+                * 7 - power supply
                 * 9 - XC5000 Tuner
                 */
 
                /* Into reset */
                au0828_write(dev, REG_003, 0x02);
-               au0828_write(dev, REG_002, 0x88 | 0x20);
+               au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
                au0828_write(dev, REG_001, 0x0);
                au0828_write(dev, REG_000, 0x0);
                msleep(100);
 
-               /* Out of reset */
+               /* Out of reset (leave the cs5340 in reset until needed) */
                au0828_write(dev, REG_003, 0x02);
                au0828_write(dev, REG_001, 0x02);
-               au0828_write(dev, REG_002, 0x88 | 0x20);
-               au0828_write(dev, REG_000, 0x88 | 0x20 | 0x40);
+               au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
+               au0828_write(dev, REG_000, 0x80 | 0x40 | 0x20);
+
                msleep(250);
                break;
        case AU0828_BOARD_DVICO_FUSIONHDTV7:
index 5765e86563761a3f2647104c294ccce1bce1c0d2..8c761d1644420fa164108b1421ff314e636ca66e 100644 (file)
@@ -36,6 +36,8 @@ int au0828_debug;
 module_param_named(debug, au0828_debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable debug messages");
 
+static atomic_t au0828_instance = ATOMIC_INIT(0);
+
 #define _AU0828_BULKPIPE 0x03
 #define _BULKPIPESIZE 0xffff
 
@@ -51,13 +53,13 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
 u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
 {
        recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, dev->ctrlmsg, 1);
-       dprintk(8, "%s(0x%x) = 0x%x\n", __func__, reg, dev->ctrlmsg[0]);
+       dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, dev->ctrlmsg[0]);
        return dev->ctrlmsg[0];
 }
 
 u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
 {
-       dprintk(8, "%s(0x%x, 0x%x)\n", __func__, reg, val);
+       dprintk(8, "%s(0x%04x, 0x%02x)\n", __func__, reg, val);
        return send_control_msg(dev, CMD_REQUEST_OUT, val, reg,
                                dev->ctrlmsg, 0);
 }
@@ -146,9 +148,14 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
        /* Digital TV */
        au0828_dvb_unregister(dev);
 
+       if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
+               au0828_analog_unregister(dev);
+
        /* I2C */
        au0828_i2c_unregister(dev);
 
+       v4l2_device_unregister(&dev->v4l2_dev);
+
        usb_set_intfdata(interface, NULL);
 
        mutex_lock(&dev->mutex);
@@ -162,7 +169,7 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
 static int au0828_usb_probe(struct usb_interface *interface,
        const struct usb_device_id *id)
 {
-       int ifnum;
+       int ifnum, retval, i;
        struct au0828_dev *dev;
        struct usb_device *usbdev = interface_to_usbdev(interface);
 
@@ -185,10 +192,22 @@ static int au0828_usb_probe(struct usb_interface *interface,
        mutex_init(&dev->mutex);
        mutex_init(&dev->dvb.lock);
        dev->usbdev = usbdev;
-       dev->board = id->driver_info;
+       dev->boardnr = id->driver_info;
 
        usb_set_intfdata(interface, dev);
 
+       /* Create the v4l2_device */
+       i = atomic_inc_return(&au0828_instance) - 1;
+       snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s-%03d",
+                "au0828", i);
+       retval = v4l2_device_register(&dev->usbdev->dev, &dev->v4l2_dev);
+       if (retval) {
+               printk(KERN_ERR "%s() v4l2_device_register failed\n",
+                      __func__);
+               kfree(dev);
+               return -EIO;
+       }
+
        /* Power Up the bridge */
        au0828_write(dev, REG_600, 1 << 4);
 
@@ -201,12 +220,15 @@ static int au0828_usb_probe(struct usb_interface *interface,
        /* Setup */
        au0828_card_setup(dev);
 
+       /* Analog TV */
+       if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
+               au0828_analog_register(dev, interface);
+
        /* Digital TV */
        au0828_dvb_register(dev);
 
        printk(KERN_INFO "Registered device AU0828 [%s]\n",
-               au0828_boards[dev->board].name == NULL ? "Unset" :
-               au0828_boards[dev->board].name);
+               dev->board.name == NULL ? "Unset" : dev->board.name);
 
        return 0;
 }
index a882cf546d0aa5a0e0c1ff798a0b0b7f109d3c9e..14baffc221920d87febcffe22a65caebe062ffd6 100644 (file)
@@ -378,7 +378,7 @@ int au0828_dvb_register(struct au0828_dev *dev)
        dprintk(1, "%s()\n", __func__);
 
        /* init frontend */
-       switch (dev->board) {
+       switch (dev->boardnr) {
        case AU0828_BOARD_HAUPPAUGE_HVR850:
        case AU0828_BOARD_HAUPPAUGE_HVR950Q:
                dvb->frontend = dvb_attach(au8522_attach,
index d618fbaade1bcc3d31828e32d65e7cff310049be..f9a958d0aef1bb05bc57a1ad8090c286dec43e16 100644 (file)
@@ -140,13 +140,39 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
        dprintk(4, "%s()\n", __func__);
 
        au0828_write(dev, REG_2FF, 0x01);
-       au0828_write(dev, REG_202, 0x07);
+
+       /* FIXME: There is a problem with i2c communications with xc5000 that
+          requires us to slow down the i2c clock until we have a better
+          strategy (such as using the secondary i2c bus to do firmware
+          loading */
+       if ((msg->addr << 1) == 0xc2)
+               au0828_write(dev, REG_202, 0x40);
+       else
+               au0828_write(dev, REG_202, 0x07);
 
        /* Hardware needs 8 bit addresses */
        au0828_write(dev, REG_203, msg->addr << 1);
 
        dprintk(4, "SEND: %02x\n", msg->addr);
 
+       /* Deal with i2c_scan */
+       if (msg->len == 0) {
+               /* The analog tuner detection code makes use of the SMBUS_QUICK
+                  message (which involves a zero length i2c write).  To avoid
+                  checking the status register when we didn't strobe out any
+                  actual bytes to the bus, just do a read check.  This is
+                  consistent with how I saw i2c device checking done in the
+                  USB trace of the Windows driver */
+               au0828_write(dev, REG_200, 0x20);
+               if (!i2c_wait_done(i2c_adap))
+                       return -EIO;
+
+               if (i2c_wait_read_ack(i2c_adap))
+                       return -EIO;
+
+               return 0;
+       }
+
        for (i = 0; i < msg->len;) {
 
                dprintk(4, " %02x\n", msg->buf[i]);
@@ -191,7 +217,15 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
        dprintk(4, "%s()\n", __func__);
 
        au0828_write(dev, REG_2FF, 0x01);
-       au0828_write(dev, REG_202, 0x07);
+
+       /* FIXME: There is a problem with i2c communications with xc5000 that
+          requires us to slow down the i2c clock until we have a better
+          strategy (such as using the secondary i2c bus to do firmware
+          loading */
+       if ((msg->addr << 1) == 0xc2)
+               au0828_write(dev, REG_202, 0x40);
+       else
+               au0828_write(dev, REG_202, 0x07);
 
        /* Hardware needs 8 bit addresses */
        au0828_write(dev, REG_203, msg->addr << 1);
@@ -265,33 +299,6 @@ err:
        return retval;
 }
 
-static int attach_inform(struct i2c_client *client)
-{
-       dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
-               client->driver->driver.name, client->addr, client->name);
-
-       if (!client->driver->command)
-               return 0;
-
-       return 0;
-}
-
-static int detach_inform(struct i2c_client *client)
-{
-       dprintk(1, "i2c detach [client=%s]\n", client->name);
-
-       return 0;
-}
-
-void au0828_call_i2c_clients(struct au0828_dev *dev,
-                             unsigned int cmd, void *arg)
-{
-       if (dev->i2c_rc != 0)
-               return;
-
-       i2c_clients_command(&dev->i2c_adap, cmd, arg);
-}
-
 static u32 au0828_functionality(struct i2c_adapter *adap)
 {
        return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
@@ -309,9 +316,6 @@ static struct i2c_adapter au0828_i2c_adap_template = {
        .owner             = THIS_MODULE,
        .id                = I2C_HW_B_AU0828,
        .algo              = &au0828_i2c_algo_template,
-       .class             = I2C_CLASS_TV_ANALOG,
-       .client_register   = attach_inform,
-       .client_unregister = detach_inform,
 };
 
 static struct i2c_client au0828_i2c_client_template = {
@@ -356,9 +360,9 @@ int au0828_i2c_register(struct au0828_dev *dev)
        strlcpy(dev->i2c_adap.name, DRIVER_NAME,
                sizeof(dev->i2c_adap.name));
 
-       dev->i2c_algo.data = dev;
+       dev->i2c_adap.algo = &dev->i2c_algo;
        dev->i2c_adap.algo_data = dev;
-       i2c_set_adapdata(&dev->i2c_adap, dev);
+       i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
        i2c_add_adapter(&dev->i2c_adap);
 
        dev->i2c_client.adapter = &dev->i2c_adap;
index 1e87fa0c684261db53f58702a5a94a1a299a8532..b15e4a3b6fc054181d8a7ed869d2af71a702c3ed 100644 (file)
@@ -27,6 +27,9 @@
 #define REG_002 0x002
 #define REG_003 0x003
 
+#define AU0828_SENSORCTRL_100 0x100
+#define AU0828_SENSORCTRL_VBI_103 0x103
+
 #define REG_200 0x200
 #define REG_201 0x201
 #define REG_202 0x202
@@ -35,4 +38,7 @@
 #define REG_209 0x209
 #define REG_2FF 0x2ff
 
+/* Audio registers */
+#define AU0828_AUDIOCTRL_50C 0x50C
+
 #define REG_600 0x600
diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c
new file mode 100644 (file)
index 0000000..f7ad495
--- /dev/null
@@ -0,0 +1,1712 @@
+/*
+ * Auvitek AU0828 USB Bridge (Analog video support)
+ *
+ * Copyright (C) 2009 Devin Heitmueller <dheitmueller@linuxtv.org>
+ * Copyright (C) 2005-2008 Auvitek International, Ltd.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/* Developer Notes:
+ *
+ * VBI support is not yet working
+ * The hardware scaler supported is unimplemented
+ * AC97 audio support is unimplemented (only i2s audio mode)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/suspend.h>
+#include <linux/version.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/tuner.h>
+#include "au0828.h"
+#include "au0828-reg.h"
+
+static LIST_HEAD(au0828_devlist);
+static DEFINE_MUTEX(au0828_sysfs_lock);
+
+#define AU0828_VERSION_CODE KERNEL_VERSION(0, 0, 1)
+
+/* ------------------------------------------------------------------
+       Videobuf operations
+   ------------------------------------------------------------------*/
+
+static unsigned int isoc_debug;
+module_param(isoc_debug, int, 0644);
+MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
+
+#define au0828_isocdbg(fmt, arg...) \
+do {\
+       if (isoc_debug) { \
+               printk(KERN_INFO "au0828 %s :"fmt, \
+                      __func__ , ##arg);          \
+       } \
+  } while (0)
+
+static inline void print_err_status(struct au0828_dev *dev,
+                                   int packet, int status)
+{
+       char *errmsg = "Unknown";
+
+       switch (status) {
+       case -ENOENT:
+               errmsg = "unlinked synchronuously";
+               break;
+       case -ECONNRESET:
+               errmsg = "unlinked asynchronuously";
+               break;
+       case -ENOSR:
+               errmsg = "Buffer error (overrun)";
+               break;
+       case -EPIPE:
+               errmsg = "Stalled (device not responding)";
+               break;
+       case -EOVERFLOW:
+               errmsg = "Babble (bad cable?)";
+               break;
+       case -EPROTO:
+               errmsg = "Bit-stuff error (bad cable?)";
+               break;
+       case -EILSEQ:
+               errmsg = "CRC/Timeout (could be anything)";
+               break;
+       case -ETIME:
+               errmsg = "Device does not respond";
+               break;
+       }
+       if (packet < 0) {
+               au0828_isocdbg("URB status %d [%s].\n", status, errmsg);
+       } else {
+               au0828_isocdbg("URB packet %d, status %d [%s].\n",
+                              packet, status, errmsg);
+       }
+}
+
+static int check_dev(struct au0828_dev *dev)
+{
+       if (dev->dev_state & DEV_DISCONNECTED) {
+               printk(KERN_INFO "v4l2 ioctl: device not present\n");
+               return -ENODEV;
+       }
+
+       if (dev->dev_state & DEV_MISCONFIGURED) {
+               printk(KERN_INFO "v4l2 ioctl: device is misconfigured; "
+                      "close and open it again\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void au0828_irq_callback(struct urb *urb)
+{
+       struct au0828_dmaqueue  *dma_q = urb->context;
+       struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
+       int rc, i;
+
+       switch (urb->status) {
+       case 0:             /* success */
+       case -ETIMEDOUT:    /* NAK */
+               break;
+       case -ECONNRESET:   /* kill */
+       case -ENOENT:
+       case -ESHUTDOWN:
+               au0828_isocdbg("au0828_irq_callback called: status kill\n");
+               return;
+       default:            /* unknown error */
+               au0828_isocdbg("urb completition error %d.\n", urb->status);
+               break;
+       }
+
+       /* Copy data from URB */
+       spin_lock(&dev->slock);
+       rc = dev->isoc_ctl.isoc_copy(dev, urb);
+       spin_unlock(&dev->slock);
+
+       /* Reset urb buffers */
+       for (i = 0; i < urb->number_of_packets; i++) {
+               urb->iso_frame_desc[i].status = 0;
+               urb->iso_frame_desc[i].actual_length = 0;
+       }
+       urb->status = 0;
+
+       urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+       if (urb->status) {
+               au0828_isocdbg("urb resubmit failed (error=%i)\n",
+                              urb->status);
+       }
+}
+
+/*
+ * Stop and Deallocate URBs
+ */
+void au0828_uninit_isoc(struct au0828_dev *dev)
+{
+       struct urb *urb;
+       int i;
+
+       au0828_isocdbg("au0828: called au0828_uninit_isoc\n");
+
+       dev->isoc_ctl.nfields = -1;
+       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+               urb = dev->isoc_ctl.urb[i];
+               if (urb) {
+                       if (!irqs_disabled())
+                               usb_kill_urb(urb);
+                       else
+                               usb_unlink_urb(urb);
+
+                       if (dev->isoc_ctl.transfer_buffer[i]) {
+                               usb_buffer_free(dev->usbdev,
+                                       urb->transfer_buffer_length,
+                                       dev->isoc_ctl.transfer_buffer[i],
+                                       urb->transfer_dma);
+                       }
+                       usb_free_urb(urb);
+                       dev->isoc_ctl.urb[i] = NULL;
+               }
+               dev->isoc_ctl.transfer_buffer[i] = NULL;
+       }
+
+       kfree(dev->isoc_ctl.urb);
+       kfree(dev->isoc_ctl.transfer_buffer);
+
+       dev->isoc_ctl.urb = NULL;
+       dev->isoc_ctl.transfer_buffer = NULL;
+       dev->isoc_ctl.num_bufs = 0;
+}
+
+/*
+ * Allocate URBs and start IRQ
+ */
+int au0828_init_isoc(struct au0828_dev *dev, int max_packets,
+                    int num_bufs, int max_pkt_size,
+                    int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb))
+{
+       struct au0828_dmaqueue *dma_q = &dev->vidq;
+       int i;
+       int sb_size, pipe;
+       struct urb *urb;
+       int j, k;
+       int rc;
+
+       au0828_isocdbg("au0828: called au0828_prepare_isoc\n");
+
+       /* De-allocates all pending stuff */
+       au0828_uninit_isoc(dev);
+
+       dev->isoc_ctl.isoc_copy = isoc_copy;
+       dev->isoc_ctl.num_bufs = num_bufs;
+
+       dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs,  GFP_KERNEL);
+       if (!dev->isoc_ctl.urb) {
+               au0828_isocdbg("cannot alloc memory for usb buffers\n");
+               return -ENOMEM;
+       }
+
+       dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
+                                             GFP_KERNEL);
+       if (!dev->isoc_ctl.transfer_buffer) {
+               au0828_isocdbg("cannot allocate memory for usb transfer\n");
+               kfree(dev->isoc_ctl.urb);
+               return -ENOMEM;
+       }
+
+       dev->isoc_ctl.max_pkt_size = max_pkt_size;
+       dev->isoc_ctl.buf = NULL;
+
+       sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
+
+       /* allocate urbs and transfer buffers */
+       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+               urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+               if (!urb) {
+                       au0828_isocdbg("cannot alloc isoc_ctl.urb %i\n", i);
+                       au0828_uninit_isoc(dev);
+                       return -ENOMEM;
+               }
+               dev->isoc_ctl.urb[i] = urb;
+
+               dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->usbdev,
+                       sb_size, GFP_KERNEL, &urb->transfer_dma);
+               if (!dev->isoc_ctl.transfer_buffer[i]) {
+                       printk("unable to allocate %i bytes for transfer"
+                                       " buffer %i%s\n",
+                                       sb_size, i,
+                                       in_interrupt() ? " while in int" : "");
+                       au0828_uninit_isoc(dev);
+                       return -ENOMEM;
+               }
+               memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+
+               pipe = usb_rcvisocpipe(dev->usbdev,
+                                      dev->isoc_in_endpointaddr),
+
+               usb_fill_int_urb(urb, dev->usbdev, pipe,
+                                dev->isoc_ctl.transfer_buffer[i], sb_size,
+                                au0828_irq_callback, dma_q, 1);
+
+               urb->number_of_packets = max_packets;
+               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+
+               k = 0;
+               for (j = 0; j < max_packets; j++) {
+                       urb->iso_frame_desc[j].offset = k;
+                       urb->iso_frame_desc[j].length =
+                                               dev->isoc_ctl.max_pkt_size;
+                       k += dev->isoc_ctl.max_pkt_size;
+               }
+       }
+
+       init_waitqueue_head(&dma_q->wq);
+
+       /* submit urbs and enables IRQ */
+       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+               rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+               if (rc) {
+                       au0828_isocdbg("submit of urb %i failed (error=%i)\n",
+                                      i, rc);
+                       au0828_uninit_isoc(dev);
+                       return rc;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct au0828_dev *dev,
+                                 struct au0828_dmaqueue *dma_q,
+                                 struct au0828_buffer *buf)
+{
+       /* Advice that buffer was filled */
+       au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+
+       buf->vb.state = VIDEOBUF_DONE;
+       buf->vb.field_count++;
+       do_gettimeofday(&buf->vb.ts);
+
+       dev->isoc_ctl.buf = NULL;
+
+       list_del(&buf->vb.queue);
+       wake_up(&buf->vb.done);
+}
+
+/*
+ * Identify the buffer header type and properly handles
+ */
+static void au0828_copy_video(struct au0828_dev *dev,
+                             struct au0828_dmaqueue  *dma_q,
+                             struct au0828_buffer *buf,
+                             unsigned char *p,
+                             unsigned char *outp, unsigned long len)
+{
+       void *fieldstart, *startwrite, *startread;
+       int  linesdone, currlinedone, offset, lencopy, remain;
+       int bytesperline = dev->width << 1; /* Assumes 16-bit depth @@@@ */
+
+       if (dma_q->pos + len > buf->vb.size)
+               len = buf->vb.size - dma_q->pos;
+
+       startread = p;
+       remain = len;
+
+       /* Interlaces frame */
+       if (buf->top_field)
+               fieldstart = outp;
+       else
+               fieldstart = outp + bytesperline;
+
+       linesdone = dma_q->pos / bytesperline;
+       currlinedone = dma_q->pos % bytesperline;
+       offset = linesdone * bytesperline * 2 + currlinedone;
+       startwrite = fieldstart + offset;
+       lencopy = bytesperline - currlinedone;
+       lencopy = lencopy > remain ? remain : lencopy;
+
+       if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+               au0828_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
+                              ((char *)startwrite + lencopy) -
+                              ((char *)outp + buf->vb.size));
+               remain = (char *)outp + buf->vb.size - (char *)startwrite;
+               lencopy = remain;
+       }
+       if (lencopy <= 0)
+               return;
+       memcpy(startwrite, startread, lencopy);
+
+       remain -= lencopy;
+
+       while (remain > 0) {
+               startwrite += lencopy + bytesperline;
+               startread += lencopy;
+               if (bytesperline > remain)
+                       lencopy = remain;
+               else
+                       lencopy = bytesperline;
+
+               if ((char *)startwrite + lencopy > (char *)outp +
+                   buf->vb.size) {
+                       au0828_isocdbg("Overflow %zi bytes past buf end (2)\n",
+                                      ((char *)startwrite + lencopy) -
+                                      ((char *)outp + buf->vb.size));
+                       lencopy = remain = (char *)outp + buf->vb.size -
+                                          (char *)startwrite;
+               }
+               if (lencopy <= 0)
+                       break;
+
+               memcpy(startwrite, startread, lencopy);
+
+               remain -= lencopy;
+       }
+
+       if (offset > 1440) {
+               /* We have enough data to check for greenscreen */
+               if (outp[0] < 0x60 && outp[1440] < 0x60)
+                       dev->greenscreen_detected = 1;
+       }
+
+       dma_q->pos += len;
+}
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct au0828_dmaqueue *dma_q,
+                               struct au0828_buffer **buf)
+{
+       struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
+
+       if (list_empty(&dma_q->active)) {
+               au0828_isocdbg("No active queue to serve\n");
+               dev->isoc_ctl.buf = NULL;
+               *buf = NULL;
+               return;
+       }
+
+       /* Get the next buffer */
+       *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
+       dev->isoc_ctl.buf = *buf;
+
+       return;
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
+{
+       struct au0828_buffer    *buf;
+       struct au0828_dmaqueue  *dma_q = urb->context;
+       unsigned char *outp = NULL;
+       int i, len = 0, rc = 1;
+       unsigned char *p;
+       unsigned char fbyte;
+
+       if (!dev)
+               return 0;
+
+       if ((dev->dev_state & DEV_DISCONNECTED) ||
+           (dev->dev_state & DEV_MISCONFIGURED))
+               return 0;
+
+       if (urb->status < 0) {
+               print_err_status(dev, -1, urb->status);
+               if (urb->status == -ENOENT)
+                       return 0;
+       }
+
+       buf = dev->isoc_ctl.buf;
+       if (buf != NULL)
+               outp = videobuf_to_vmalloc(&buf->vb);
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               int status = urb->iso_frame_desc[i].status;
+
+               if (status < 0) {
+                       print_err_status(dev, i, status);
+                       if (urb->iso_frame_desc[i].status != -EPROTO)
+                               continue;
+               }
+
+               if (urb->iso_frame_desc[i].actual_length <= 0)
+                       continue;
+
+               if (urb->iso_frame_desc[i].actual_length >
+                                               dev->max_pkt_size) {
+                       au0828_isocdbg("packet bigger than packet size");
+                       continue;
+               }
+
+               p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+               fbyte = p[0];
+               len = urb->iso_frame_desc[i].actual_length - 4;
+               p += 4;
+
+               if (fbyte & 0x80) {
+                       len -= 4;
+                       p += 4;
+                       au0828_isocdbg("Video frame %s\n",
+                                      (fbyte & 0x40) ? "odd" : "even");
+                       if (!(fbyte & 0x40)) {
+                               if (buf != NULL)
+                                       buffer_filled(dev, dma_q, buf);
+                               get_next_buf(dma_q, &buf);
+                               if (buf == NULL)
+                                       outp = NULL;
+                               else
+                                       outp = videobuf_to_vmalloc(&buf->vb);
+                       }
+
+                       if (buf != NULL) {
+                               if (fbyte & 0x40)
+                                       buf->top_field = 1;
+                               else
+                                       buf->top_field = 0;
+                       }
+
+                       dma_q->pos = 0;
+               }
+               if (buf != NULL)
+                       au0828_copy_video(dev, dma_q, buf, p, outp, len);
+       }
+       return rc;
+}
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+            unsigned int *size)
+{
+       struct au0828_fh *fh = vq->priv_data;
+       *size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3;
+
+       if (0 == *count)
+               *count = AU0828_DEF_BUF;
+
+       if (*count < AU0828_MIN_BUF)
+               *count = AU0828_MIN_BUF;
+       return 0;
+}
+
+/* This is called *without* dev->slock held; please keep it that way */
+static void free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf)
+{
+       struct au0828_fh     *fh  = vq->priv_data;
+       struct au0828_dev    *dev = fh->dev;
+       unsigned long flags = 0;
+       if (in_interrupt())
+               BUG();
+
+       /* We used to wait for the buffer to finish here, but this didn't work
+          because, as we were keeping the state as VIDEOBUF_QUEUED,
+          videobuf_queue_cancel marked it as finished for us.
+          (Also, it could wedge forever if the hardware was misconfigured.)
+
+          This should be safe; by the time we get here, the buffer isn't
+          queued anymore. If we ever start marking the buffers as
+          VIDEOBUF_ACTIVE, it won't be, though.
+       */
+       spin_lock_irqsave(&dev->slock, flags);
+       if (dev->isoc_ctl.buf == buf)
+               dev->isoc_ctl.buf = NULL;
+       spin_unlock_irqrestore(&dev->slock, flags);
+
+       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 au0828_fh     *fh  = vq->priv_data;
+       struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
+       struct au0828_dev    *dev = fh->dev;
+       int                  rc = 0, urb_init = 0;
+
+       buf->vb.size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3;
+
+       if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+               return -EINVAL;
+
+       buf->vb.width  = dev->width;
+       buf->vb.height = dev->height;
+       buf->vb.field  = field;
+
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+               rc = videobuf_iolock(vq, &buf->vb, NULL);
+               if (rc < 0) {
+                       printk(KERN_INFO "videobuf_iolock failed\n");
+                       goto fail;
+               }
+       }
+
+       if (!dev->isoc_ctl.num_bufs)
+               urb_init = 1;
+
+       if (urb_init) {
+               rc = au0828_init_isoc(dev, AU0828_ISO_PACKETS_PER_URB,
+                                     AU0828_MAX_ISO_BUFS, dev->max_pkt_size,
+                                     au0828_isoc_copy);
+               if (rc < 0) {
+                       printk(KERN_INFO "au0828_init_isoc failed\n");
+                       goto fail;
+               }
+       }
+
+       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 au0828_buffer    *buf     = container_of(vb,
+                                                       struct au0828_buffer,
+                                                       vb);
+       struct au0828_fh        *fh      = vq->priv_data;
+       struct au0828_dev       *dev     = fh->dev;
+       struct au0828_dmaqueue  *vidq    = &dev->vidq;
+
+       buf->vb.state = VIDEOBUF_QUEUED;
+       list_add_tail(&buf->vb.queue, &vidq->active);
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+                               struct videobuf_buffer *vb)
+{
+       struct au0828_buffer   *buf  = container_of(vb,
+                                                   struct au0828_buffer,
+                                                   vb);
+
+       free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops au0828_video_qops = {
+       .buf_setup      = buffer_setup,
+       .buf_prepare    = buffer_prepare,
+       .buf_queue      = buffer_queue,
+       .buf_release    = buffer_release,
+};
+
+/* ------------------------------------------------------------------
+   V4L2 interface
+   ------------------------------------------------------------------*/
+
+static int au0828_i2s_init(struct au0828_dev *dev)
+{
+       /* Enable i2s mode */
+       au0828_writereg(dev, AU0828_AUDIOCTRL_50C, 0x01);
+       return 0;
+}
+
+/*
+ * Auvitek au0828 analog stream enable
+ * Please set interface0 to AS5 before enable the stream
+ */
+int au0828_analog_stream_enable(struct au0828_dev *d)
+{
+       dprintk(1, "au0828_analog_stream_enable called\n");
+       au0828_writereg(d, AU0828_SENSORCTRL_VBI_103, 0x00);
+       au0828_writereg(d, 0x106, 0x00);
+       /* set x position */
+       au0828_writereg(d, 0x110, 0x00);
+       au0828_writereg(d, 0x111, 0x00);
+       au0828_writereg(d, 0x114, 0xa0);
+       au0828_writereg(d, 0x115, 0x05);
+       /* set y position */
+       au0828_writereg(d, 0x112, 0x02);
+       au0828_writereg(d, 0x113, 0x00);
+       au0828_writereg(d, 0x116, 0xf2);
+       au0828_writereg(d, 0x117, 0x00);
+       au0828_writereg(d, AU0828_SENSORCTRL_100, 0xb3);
+
+       return 0;
+}
+
+int au0828_analog_stream_disable(struct au0828_dev *d)
+{
+       dprintk(1, "au0828_analog_stream_disable called\n");
+       au0828_writereg(d, AU0828_SENSORCTRL_100, 0x0);
+       return 0;
+}
+
+void au0828_analog_stream_reset(struct au0828_dev *dev)
+{
+       dprintk(1, "au0828_analog_stream_reset called\n");
+       au0828_writereg(dev, AU0828_SENSORCTRL_100, 0x0);
+       mdelay(30);
+       au0828_writereg(dev, AU0828_SENSORCTRL_100, 0xb3);
+}
+
+/*
+ * Some operations needs to stop current streaming
+ */
+static int au0828_stream_interrupt(struct au0828_dev *dev)
+{
+       int ret = 0;
+
+       dev->stream_state = STREAM_INTERRUPT;
+       if (dev->dev_state == DEV_DISCONNECTED)
+               return -ENODEV;
+       else if (ret) {
+               dev->dev_state = DEV_MISCONFIGURED;
+               dprintk(1, "%s device is misconfigured!\n", __func__);
+               return ret;
+       }
+       return 0;
+}
+
+/*
+ * au0828_release_resources
+ * unregister v4l2 devices
+ */
+void au0828_analog_unregister(struct au0828_dev *dev)
+{
+       dprintk(1, "au0828_release_resources called\n");
+       mutex_lock(&au0828_sysfs_lock);
+
+       if (dev->vdev) {
+               list_del(&dev->au0828list);
+               video_unregister_device(dev->vdev);
+       }
+       if (dev->vbi_dev)
+               video_unregister_device(dev->vbi_dev);
+
+       mutex_unlock(&au0828_sysfs_lock);
+}
+
+
+/* Usage lock check functions */
+static int res_get(struct au0828_fh *fh)
+{
+       struct au0828_dev *dev = fh->dev;
+       int              rc   = 0;
+
+       /* This instance already has stream_on */
+       if (fh->stream_on)
+               return rc;
+
+       if (dev->stream_on)
+               return -EBUSY;
+
+       dev->stream_on = 1;
+       fh->stream_on  = 1;
+       return rc;
+}
+
+static int res_check(struct au0828_fh *fh)
+{
+       return fh->stream_on;
+}
+
+static void res_free(struct au0828_fh *fh)
+{
+       struct au0828_dev *dev = fh->dev;
+
+       fh->stream_on = 0;
+       dev->stream_on = 0;
+}
+
+static int au0828_v4l2_open(struct file *filp)
+{
+       int minor = video_devdata(filp)->minor;
+       int ret = 0;
+       struct au0828_dev *h, *dev = NULL;
+       struct au0828_fh *fh;
+       int type = 0;
+       struct list_head *list;
+
+       list_for_each(list, &au0828_devlist) {
+               h = list_entry(list, struct au0828_dev, au0828list);
+               if (h->vdev->minor == minor) {
+                       dev = h;
+                       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               }
+#ifdef VBI_IS_WORKING
+               if (h->vbi_dev->minor == minor) {
+                       dev = h;
+                       type = V4L2_BUF_TYPE_VBI_CAPTURE;
+               }
+#endif
+       }
+
+       if (NULL == dev)
+               return -ENODEV;
+
+       fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL);
+       if (NULL == fh) {
+               dprintk(1, "Failed allocate au0828_fh struct!\n");
+               return -ENOMEM;
+       }
+
+       fh->type = type;
+       fh->dev = dev;
+       filp->private_data = fh;
+
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+               /* set au0828 interface0 to AS5 here again */
+               ret = usb_set_interface(dev->usbdev, 0, 5);
+               if (ret < 0) {
+                       printk(KERN_INFO "Au0828 can't set alternate to 5!\n");
+                       return -EBUSY;
+               }
+               dev->width = NTSC_STD_W;
+               dev->height = NTSC_STD_H;
+               dev->frame_size = dev->width * dev->height * 2;
+               dev->field_size = dev->width * dev->height;
+               dev->bytesperline = dev->width * 2;
+
+               au0828_analog_stream_enable(dev);
+               au0828_analog_stream_reset(dev);
+
+               /* If we were doing ac97 instead of i2s, it would go here...*/
+               au0828_i2s_init(dev);
+
+               dev->stream_state = STREAM_OFF;
+               dev->dev_state |= DEV_INITIALIZED;
+       }
+
+       dev->users++;
+
+       videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops,
+                                   NULL, &dev->slock, fh->type,
+                                   V4L2_FIELD_INTERLACED,
+                                   sizeof(struct au0828_buffer), fh);
+
+       return ret;
+}
+
+static int au0828_v4l2_close(struct file *filp)
+{
+       int ret;
+       struct au0828_fh *fh = filp->private_data;
+       struct au0828_dev *dev = fh->dev;
+
+       mutex_lock(&dev->lock);
+       if (res_check(fh))
+               res_free(fh);
+
+       if (dev->users == 1) {
+               videobuf_stop(&fh->vb_vidq);
+               videobuf_mmap_free(&fh->vb_vidq);
+
+               if (dev->dev_state & DEV_DISCONNECTED) {
+                       au0828_analog_unregister(dev);
+                       mutex_unlock(&dev->lock);
+                       kfree(dev);
+                       return 0;
+               }
+
+               au0828_analog_stream_disable(dev);
+
+               au0828_uninit_isoc(dev);
+
+               /* When close the device, set the usb intf0 into alt0 to free
+                  USB bandwidth */
+               ret = usb_set_interface(dev->usbdev, 0, 0);
+               if (ret < 0)
+                       printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
+       }
+
+       kfree(fh);
+       dev->users--;
+       wake_up_interruptible_nr(&dev->open, 1);
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
+                               size_t count, loff_t *pos)
+{
+       struct au0828_fh *fh = filp->private_data;
+       struct au0828_dev *dev = fh->dev;
+       int rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               mutex_lock(&dev->lock);
+               rc = res_get(fh);
+               mutex_unlock(&dev->lock);
+
+               if (unlikely(rc < 0))
+                       return rc;
+
+               return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
+                                       filp->f_flags & O_NONBLOCK);
+       }
+       return 0;
+}
+
+static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait)
+{
+       struct au0828_fh *fh = filp->private_data;
+       struct au0828_dev *dev = fh->dev;
+       int rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       mutex_lock(&dev->lock);
+       rc = res_get(fh);
+       mutex_unlock(&dev->lock);
+
+       if (unlikely(rc < 0))
+               return POLLERR;
+
+       if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+               return POLLERR;
+
+       return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+}
+
+static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct au0828_fh *fh    = filp->private_data;
+       struct au0828_dev *dev   = fh->dev;
+       int              rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       mutex_lock(&dev->lock);
+       rc = res_get(fh);
+       mutex_unlock(&dev->lock);
+
+       if (unlikely(rc < 0))
+               return rc;
+
+       rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+
+       dprintk(2, "vma start=0x%08lx, size=%ld, ret=%d\n",
+               (unsigned long)vma->vm_start,
+               (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+               rc);
+
+       return rc;
+}
+
+static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
+                            struct v4l2_format *format)
+{
+       int ret;
+       int width = format->fmt.pix.width;
+       int height = format->fmt.pix.height;
+       unsigned int maxwidth, maxheight;
+
+       maxwidth = 720;
+       maxheight = 480;
+
+#ifdef VBI_IS_WORKING
+       if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+               dprintk(1, "VBI format set: to be supported!\n");
+               return 0;
+       }
+       if (format->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               return 0;
+#endif
+       if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       /* If they are demanding a format other than the one we support,
+          bail out (tvtime asks for UYVY and then retries with YUYV) */
+       if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY)
+               return -EINVAL;
+
+       /* format->fmt.pix.width only support 720 and height 480 */
+       if (width != 720)
+               width = 720;
+       if (height != 480)
+               height = 480;
+
+       format->fmt.pix.width = width;
+       format->fmt.pix.height = height;
+       format->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+       format->fmt.pix.bytesperline = width * 2;
+       format->fmt.pix.sizeimage = width * height * 2;
+       format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+       format->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+       if (cmd == VIDIOC_TRY_FMT)
+               return 0;
+
+       /* maybe set new image format, driver current only support 720*480 */
+       dev->width = width;
+       dev->height = height;
+       dev->frame_size = width * height * 2;
+       dev->field_size = width * height;
+       dev->bytesperline = width * 2;
+
+       if (dev->stream_state == STREAM_ON) {
+               dprintk(1, "VIDIOC_SET_FMT: interrupting stream!\n");
+               ret = au0828_stream_interrupt(dev);
+               if (ret != 0) {
+                       dprintk(1, "error interrupting video stream!\n");
+                       return ret;
+               }
+       }
+
+       /* set au0828 interface0 to AS5 here again */
+       ret = usb_set_interface(dev->usbdev, 0, 5);
+       if (ret < 0) {
+               printk(KERN_INFO "Au0828 can't set alt setting to 5!\n");
+               return -EBUSY;
+       }
+
+       au0828_analog_stream_enable(dev);
+
+       return 0;
+}
+
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+                           struct v4l2_queryctrl *qc)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
+       if (qc->type)
+               return 0;
+       else
+               return -EINVAL;
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+                          struct v4l2_capability *cap)
+{
+       struct au0828_fh *fh  = priv;
+       struct au0828_dev *dev = fh->dev;
+
+       strlcpy(cap->driver, "au0828", sizeof(cap->driver));
+       strlcpy(cap->card, dev->board.name, sizeof(cap->card));
+       strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
+
+       cap->version = AU0828_VERSION_CODE;
+
+       /*set the device capabilities */
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+#ifdef VBI_IS_WORKING
+               V4L2_CAP_VBI_CAPTURE |
+#endif
+               V4L2_CAP_AUDIO |
+               V4L2_CAP_READWRITE |
+               V4L2_CAP_STREAMING |
+               V4L2_CAP_TUNER;
+       return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       if (f->index)
+               return -EINVAL;
+
+       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       strcpy(f->description, "Packed YUV2");
+
+       f->flags = 0;
+       f->pixelformat = V4L2_PIX_FMT_UYVY;
+
+       return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct au0828_fh *fh  = priv;
+       struct au0828_dev *dev = fh->dev;
+
+       f->fmt.pix.width = dev->width;
+       f->fmt.pix.height = dev->height;
+       f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+       f->fmt.pix.bytesperline = dev->bytesperline;
+       f->fmt.pix.sizeimage = dev->frame_size;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* NTSC/PAL */
+       f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+       return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       struct au0828_fh *fh  = priv;
+       struct au0828_dev *dev = fh->dev;
+
+       return au0828_set_format(dev, VIDIOC_TRY_FMT, f);
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct au0828_fh *fh  = priv;
+       struct au0828_dev *dev = fh->dev;
+       int rc;
+
+       if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+               printk(KERN_INFO "%s queue busy\n", __func__);
+               rc = -EBUSY;
+               goto out;
+       }
+
+       if (dev->stream_on && !fh->stream_on) {
+               printk(KERN_INFO "%s device in use by another fh\n", __func__);
+               rc = -EBUSY;
+               goto out;
+       }
+
+       return au0828_set_format(dev, VIDIOC_S_FMT, f);
+out:
+       return rc;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+
+       /* FIXME: when we support something other than NTSC, we are going to
+          have to make the au0828 bridge adjust the size of its capture
+          buffer, which is currently hardcoded at 720x480 */
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_std, *norm);
+       return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+                               struct v4l2_input *input)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+       unsigned int tmp;
+
+       static const char *inames[] = {
+               [AU0828_VMUX_UNDEFINED] = "Undefined",
+               [AU0828_VMUX_COMPOSITE] = "Composite",
+               [AU0828_VMUX_SVIDEO] = "S-Video",
+               [AU0828_VMUX_CABLE] = "Cable TV",
+               [AU0828_VMUX_TELEVISION] = "Television",
+               [AU0828_VMUX_DVB] = "DVB",
+               [AU0828_VMUX_DEBUG] = "tv debug"
+       };
+
+       tmp = input->index;
+
+       if (tmp > AU0828_MAX_INPUT)
+               return -EINVAL;
+       if (AUVI_INPUT(tmp).type == 0)
+               return -EINVAL;
+
+       input->index = tmp;
+       strcpy(input->name, inames[AUVI_INPUT(tmp).type]);
+       if ((AUVI_INPUT(tmp).type == AU0828_VMUX_TELEVISION) ||
+           (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE))
+               input->type |= V4L2_INPUT_TYPE_TUNER;
+       else
+               input->type |= V4L2_INPUT_TYPE_CAMERA;
+
+       input->std = dev->vdev->tvnorms;
+
+       return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+       *i = dev->ctrl_input;
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+       int i;
+       struct v4l2_routing route;
+
+       dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
+               index);
+       if (index >= AU0828_MAX_INPUT)
+               return -EINVAL;
+       if (AUVI_INPUT(index).type == 0)
+               return -EINVAL;
+       dev->ctrl_input = index;
+
+       switch (AUVI_INPUT(index).type) {
+       case AU0828_VMUX_SVIDEO:
+               dev->input_type = AU0828_VMUX_SVIDEO;
+               break;
+       case AU0828_VMUX_COMPOSITE:
+               dev->input_type = AU0828_VMUX_COMPOSITE;
+               break;
+       case AU0828_VMUX_TELEVISION:
+               dev->input_type = AU0828_VMUX_TELEVISION;
+               break;
+       default:
+               dprintk(1, "VIDIOC_S_INPUT unknown input type set [%d]\n",
+                       AUVI_INPUT(index).type);
+               break;
+       }
+
+       route.input = AUVI_INPUT(index).vmux;
+       route.output = 0;
+       v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, &route);
+
+       for (i = 0; i < AU0828_MAX_INPUT; i++) {
+               int enable = 0;
+               if (AUVI_INPUT(i).audio_setup == NULL)
+                       continue;
+
+               if (i == index)
+                       enable = 1;
+               else
+                       enable = 0;
+               if (enable) {
+                       (AUVI_INPUT(i).audio_setup)(dev, enable);
+               } else {
+                       /* Make sure we leave it turned on if some
+                          other input is routed to this callback */
+                       if ((AUVI_INPUT(i).audio_setup) !=
+                           ((AUVI_INPUT(index).audio_setup))) {
+                               (AUVI_INPUT(i).audio_setup)(dev, enable);
+                       }
+               }
+       }
+
+       route.input = AUVI_INPUT(index).amux;
+       v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing, &route);
+       return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+       unsigned int index = a->index;
+
+       if (a->index > 1)
+               return -EINVAL;
+
+       index = dev->ctrl_ainput;
+       if (index == 0)
+               strcpy(a->name, "Television");
+       else
+               strcpy(a->name, "Line in");
+
+       a->capability = V4L2_AUDCAP_STEREO;
+       a->index = index;
+       return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+       if (a->index != dev->ctrl_ainput)
+               return -EINVAL;
+       return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+                        struct v4l2_control *ctrl)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
+       return 0;
+
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
+       return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+
+       if (t->index != 0)
+               return -EINVAL;
+
+       strcpy(t->name, "Auvitek tuner");
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+       return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+
+       if (t->index != 0)
+               return -EINVAL;
+
+       t->type = V4L2_TUNER_ANALOG_TV;
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+       dprintk(1, "VIDIOC_S_TUNER: signal = %x, afc = %x\n", t->signal,
+               t->afc);
+       return 0;
+
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *freq)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+
+       freq->type = V4L2_TUNER_ANALOG_TV;
+       freq->frequency = dev->ctrl_freq;
+       return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *freq)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+
+       if (freq->tuner != 0)
+               return -EINVAL;
+       if (freq->type != V4L2_TUNER_ANALOG_TV)
+               return -EINVAL;
+
+       dev->ctrl_freq = freq->frequency;
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq);
+
+       au0828_analog_stream_reset(dev);
+
+       return 0;
+}
+
+static int vidioc_g_chip_ident(struct file *file, void *priv,
+              struct v4l2_dbg_chip_ident *chip)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+       chip->ident = V4L2_IDENT_NONE;
+       chip->revision = 0;
+
+       if (v4l2_chip_match_host(&chip->match)) {
+               chip->ident = V4L2_IDENT_AU0828;
+               return 0;
+       }
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
+       if (chip->ident == V4L2_IDENT_NONE)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int vidioc_cropcap(struct file *file, void *priv,
+                         struct v4l2_cropcap *cc)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+
+       if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       cc->bounds.left = 0;
+       cc->bounds.top = 0;
+       cc->bounds.width = dev->width;
+       cc->bounds.height = dev->height;
+
+       cc->defrect = cc->bounds;
+
+       cc->pixelaspect.numerator = 54;
+       cc->pixelaspect.denominator = 59;
+
+       return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+                          enum v4l2_buf_type type)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+       int rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               au0828_analog_stream_enable(dev);
+               v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
+       }
+
+       mutex_lock(&dev->lock);
+       rc = res_get(fh);
+
+       if (likely(rc >= 0))
+               rc = videobuf_streamon(&fh->vb_vidq);
+       mutex_unlock(&dev->lock);
+
+       return rc;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+                           enum v4l2_buf_type type)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+       int i;
+       int ret;
+       int rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (type != fh->type)
+               return -EINVAL;
+
+       if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+               ret = au0828_stream_interrupt(dev);
+               if (ret != 0)
+                       return ret;
+       }
+
+       for (i = 0; i < AU0828_MAX_INPUT; i++) {
+               if (AUVI_INPUT(i).audio_setup == NULL)
+                       continue;
+               (AUVI_INPUT(i).audio_setup)(dev, 0);
+       }
+
+       mutex_lock(&dev->lock);
+       videobuf_streamoff(&fh->vb_vidq);
+       res_free(fh);
+       mutex_unlock(&dev->lock);
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *priv,
+                            struct v4l2_dbg_register *reg)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+
+       switch (reg->match.type) {
+       case V4L2_CHIP_MATCH_I2C_DRIVER:
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+                            struct v4l2_dbg_register *reg)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+
+       switch (reg->match.type) {
+       case V4L2_CHIP_MATCH_I2C_DRIVER:
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+#endif
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *rb)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+       int rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       return videobuf_reqbufs(&fh->vb_vidq, rb);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+                          struct v4l2_buffer *b)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+       int rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       return videobuf_querybuf(&fh->vb_vidq, b);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+       int rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       return videobuf_qbuf(&fh->vb_vidq, b);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+       struct au0828_fh *fh = priv;
+       struct au0828_dev *dev = fh->dev;
+       int rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       /* Workaround for a bug in the au0828 hardware design that sometimes
+          results in the colorspace being inverted */
+       if (dev->greenscreen_detected == 1) {
+               dprintk(1, "Detected green frame.  Resetting stream...\n");
+               au0828_analog_stream_reset(dev);
+               dev->greenscreen_detected = 0;
+       }
+
+       return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+       struct au0828_fh *fh = priv;
+
+       return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+}
+#endif
+
+static struct v4l2_file_operations au0828_v4l_fops = {
+       .owner      = THIS_MODULE,
+       .open       = au0828_v4l2_open,
+       .release    = au0828_v4l2_close,
+       .read       = au0828_v4l2_read,
+       .poll       = au0828_v4l2_poll,
+       .mmap       = au0828_v4l2_mmap,
+       .ioctl      = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+       .vidioc_querycap            = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap    = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap       = vidioc_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap     = vidioc_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap       = vidioc_s_fmt_vid_cap,
+#ifdef VBI_IS_WORKING
+       .vidioc_g_fmt_vbi_cap       = vidioc_g_fmt_vbi_cap,
+       .vidioc_try_fmt_vbi_cap     = vidioc_s_fmt_vbi_cap,
+       .vidioc_s_fmt_vbi_cap       = vidioc_s_fmt_vbi_cap,
+#endif
+       .vidioc_g_audio             = vidioc_g_audio,
+       .vidioc_s_audio             = vidioc_s_audio,
+       .vidioc_cropcap             = vidioc_cropcap,
+#ifdef VBI_IS_WORKING
+       .vidioc_g_fmt_sliced_vbi_cap   = vidioc_g_fmt_sliced_vbi_cap,
+       .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
+       .vidioc_s_fmt_sliced_vbi_cap   = vidioc_try_set_sliced_vbi_cap,
+#endif
+       .vidioc_reqbufs             = vidioc_reqbufs,
+       .vidioc_querybuf            = vidioc_querybuf,
+       .vidioc_qbuf                = vidioc_qbuf,
+       .vidioc_dqbuf               = vidioc_dqbuf,
+       .vidioc_s_std               = vidioc_s_std,
+       .vidioc_enum_input          = vidioc_enum_input,
+       .vidioc_g_input             = vidioc_g_input,
+       .vidioc_s_input             = vidioc_s_input,
+       .vidioc_queryctrl           = vidioc_queryctrl,
+       .vidioc_g_ctrl              = vidioc_g_ctrl,
+       .vidioc_s_ctrl              = vidioc_s_ctrl,
+       .vidioc_streamon            = vidioc_streamon,
+       .vidioc_streamoff           = vidioc_streamoff,
+       .vidioc_g_tuner             = vidioc_g_tuner,
+       .vidioc_s_tuner             = vidioc_s_tuner,
+       .vidioc_g_frequency         = vidioc_g_frequency,
+       .vidioc_s_frequency         = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register          = vidioc_g_register,
+       .vidioc_s_register          = vidioc_s_register,
+#endif
+       .vidioc_g_chip_ident        = vidioc_g_chip_ident,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+       .vidiocgmbuf                = vidiocgmbuf,
+#endif
+};
+
+static const struct video_device au0828_video_template = {
+       .fops                       = &au0828_v4l_fops,
+       .release                    = video_device_release,
+       .ioctl_ops                  = &video_ioctl_ops,
+       .minor                      = -1,
+       .tvnorms                    = V4L2_STD_NTSC_M,
+       .current_norm               = V4L2_STD_NTSC_M,
+};
+
+/**************************************************************************/
+
+int au0828_analog_register(struct au0828_dev *dev,
+                          struct usb_interface *interface)
+{
+       int retval = -ENOMEM;
+       struct usb_host_interface *iface_desc;
+       struct usb_endpoint_descriptor *endpoint;
+       int i;
+
+       dprintk(1, "au0828_analog_register called!\n");
+
+       /* set au0828 usb interface0 to as5 */
+       retval = usb_set_interface(dev->usbdev,
+                       interface->cur_altsetting->desc.bInterfaceNumber, 5);
+       if (retval != 0) {
+               printk(KERN_INFO "Failure setting usb interface0 to as5\n");
+               return retval;
+       }
+
+       /* Figure out which endpoint has the isoc interface */
+       iface_desc = interface->cur_altsetting;
+       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_ISOC)) {
+
+                       /* we find our isoc in endpoint */
+                       u16 tmp = le16_to_cpu(endpoint->wMaxPacketSize);
+                       dev->max_pkt_size = (tmp & 0x07ff) *
+                               (((tmp & 0x1800) >> 11) + 1);
+                       dev->isoc_in_endpointaddr = endpoint->bEndpointAddress;
+               }
+       }
+       if (!(dev->isoc_in_endpointaddr)) {
+               printk(KERN_INFO "Could not locate isoc endpoint\n");
+               kfree(dev);
+               return -ENODEV;
+       }
+
+       init_waitqueue_head(&dev->open);
+       spin_lock_init(&dev->slock);
+       mutex_init(&dev->lock);
+
+       INIT_LIST_HEAD(&dev->vidq.active);
+       INIT_LIST_HEAD(&dev->vidq.queued);
+
+       dev->width = NTSC_STD_W;
+       dev->height = NTSC_STD_H;
+       dev->field_size = dev->width * dev->height;
+       dev->frame_size = dev->field_size << 1;
+       dev->bytesperline = dev->width << 1;
+       dev->ctrl_ainput = 0;
+
+       /* allocate and fill v4l2 video struct */
+       dev->vdev = video_device_alloc();
+       if (NULL == dev->vdev) {
+               dprintk(1, "Can't allocate video_device.\n");
+               return -ENOMEM;
+       }
+
+#ifdef VBI_IS_WORKING
+       dev->vbi_dev = video_device_alloc();
+       if (NULL == dev->vbi_dev) {
+               dprintk(1, "Can't allocate vbi_device.\n");
+               kfree(dev->vdev);
+               return -ENOMEM;
+       }
+#endif
+
+       /* Fill the video capture device struct */
+       *dev->vdev = au0828_video_template;
+       dev->vdev->parent = &dev->usbdev->dev;
+       strcpy(dev->vdev->name, "au0828a video");
+
+#ifdef VBI_IS_WORKING
+       /* Setup the VBI device */
+       *dev->vbi_dev = au0828_video_template;
+       dev->vbi_dev->parent = &dev->usbdev->dev;
+       strcpy(dev->vbi_dev->name, "au0828a vbi");
+#endif
+
+       list_add_tail(&dev->au0828list, &au0828_devlist);
+
+       /* Register the v4l2 device */
+       retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1);
+       if (retval != 0) {
+               dprintk(1, "unable to register video device (error = %d).\n",
+                       retval);
+               list_del(&dev->au0828list);
+               video_device_release(dev->vdev);
+               return -ENODEV;
+       }
+
+#ifdef VBI_IS_WORKING
+       /* Register the vbi device */
+       retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1);
+       if (retval != 0) {
+               dprintk(1, "unable to register vbi device (error = %d).\n",
+                       retval);
+               list_del(&dev->au0828list);
+               video_device_release(dev->vbi_dev);
+               video_device_release(dev->vdev);
+               return -ENODEV;
+       }
+#endif
+
+       dprintk(1, "%s completed!\n", __func__);
+
+       return 0;
+}
+
index 9d6a1161dc98f3801bdee3cf614c88696f7b7e5f..6ed1a6129731a540d5c73ad9df659c3f56e2b9b9 100644 (file)
 #include <linux/i2c-algo-bit.h>
 #include <media/tveeprom.h>
 
+/* Analog */
+#include <linux/videodev2.h>
+#include <media/videobuf-vmalloc.h>
+#include <media/v4l2-device.h>
+
 /* DVB */
 #include "demux.h"
 #include "dmxdev.h"
 #define URB_COUNT   16
 #define URB_BUFSIZE (0xe522)
 
+/* Analog constants */
+#define NTSC_STD_W      720
+#define NTSC_STD_H      480
+
+#define AU0828_INTERLACED_DEFAULT       1
+#define V4L2_CID_PRIVATE_SHARPNESS  (V4L2_CID_PRIVATE_BASE + 0)
+
+/* Defination for AU0828 USB transfer */
+#define AU0828_MAX_ISO_BUFS    12  /* maybe resize this value in the future */
+#define AU0828_ISO_PACKETS_PER_URB      10
+
+#define AU0828_MIN_BUF 4
+#define AU0828_DEF_BUF 8
+
+#define AU0828_MAX_INPUT        4
+
+enum au0828_itype {
+       AU0828_VMUX_UNDEFINED = 0,
+       AU0828_VMUX_COMPOSITE,
+       AU0828_VMUX_SVIDEO,
+       AU0828_VMUX_CABLE,
+       AU0828_VMUX_TELEVISION,
+       AU0828_VMUX_DVB,
+       AU0828_VMUX_DEBUG
+};
+
+struct au0828_input {
+       enum au0828_itype type;
+       unsigned int vmux;
+       unsigned int amux;
+       void (*audio_setup) (void *priv, int enable);
+};
+
 struct au0828_board {
        char *name;
+       unsigned int tuner_type;
+       unsigned char tuner_addr;
+       struct au0828_input input[AU0828_MAX_INPUT];
+
 };
 
 struct au0828_dvb {
@@ -55,31 +97,143 @@ struct au0828_dvb {
        int feeding;
 };
 
+enum au0828_stream_state {
+       STREAM_OFF,
+       STREAM_INTERRUPT,
+       STREAM_ON
+};
+
+#define AUVI_INPUT(nr) (dev->board.input[nr])
+
+/* device state */
+enum au0828_dev_state {
+       DEV_INITIALIZED = 0x01,
+       DEV_DISCONNECTED = 0x02,
+       DEV_MISCONFIGURED = 0x04
+};
+
+struct au0828_fh {
+       struct au0828_dev *dev;
+       unsigned int  stream_on:1;      /* Locks streams */
+       struct videobuf_queue        vb_vidq;
+       enum v4l2_buf_type           type;
+};
+
+struct au0828_usb_isoc_ctl {
+               /* max packet size of isoc transaction */
+       int                             max_pkt_size;
+
+               /* number of allocated urbs */
+       int                             num_bufs;
+
+               /* urb for isoc transfers */
+       struct urb                      **urb;
+
+               /* transfer buffers for isoc transfer */
+       char                            **transfer_buffer;
+
+               /* Last buffer command and region */
+       u8                              cmd;
+       int                             pos, size, pktsize;
+
+               /* Last field: ODD or EVEN? */
+       int                             field;
+
+               /* Stores incomplete commands */
+       u32                             tmp_buf;
+       int                             tmp_buf_len;
+
+               /* Stores already requested buffers */
+       struct au0828_buffer            *buf;
+
+               /* Stores the number of received fields */
+       int                             nfields;
+
+               /* isoc urb callback */
+       int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb);
+
+};
+
+/* buffer for one video frame */
+struct au0828_buffer {
+       /* common v4l buffer stuff -- must be first */
+       struct videobuf_buffer vb;
+
+       struct list_head frame;
+       int top_field;
+       int receiving;
+};
+
+struct au0828_dmaqueue {
+       struct list_head       active;
+       struct list_head       queued;
+
+       wait_queue_head_t          wq;
+
+       /* Counters to control buffer fill */
+       int                        pos;
+};
+
 struct au0828_dev {
        struct mutex mutex;
        struct usb_device       *usbdev;
-       int                     board;
+       int                     boardnr;
+       struct au0828_board     board;
        u8                      ctrlmsg[64];
 
        /* I2C */
        struct i2c_adapter              i2c_adap;
-       struct i2c_algo_bit_data        i2c_algo;
+       struct i2c_algorithm            i2c_algo;
        struct i2c_client               i2c_client;
        u32                             i2c_rc;
 
        /* Digital */
        struct au0828_dvb               dvb;
 
+       /* Analog */
+       struct list_head au0828list;
+       struct v4l2_device v4l2_dev;
+       int users;
+       unsigned int stream_on:1;       /* Locks streams */
+       struct video_device *vdev;
+       struct video_device *vbi_dev;
+       int width;
+       int height;
+       u32 field_size;
+       u32 frame_size;
+       u32 bytesperline;
+       int type;
+       u8 ctrl_ainput;
+       __u8 isoc_in_endpointaddr;
+       u8 isoc_init_ok;
+       int greenscreen_detected;
+       unsigned int frame_count;
+       int ctrl_freq;
+       int input_type;
+       unsigned int ctrl_input;
+       enum au0828_dev_state dev_state;
+       enum au0828_stream_state stream_state;
+       wait_queue_head_t open;
+
+       struct mutex lock;
+
+       /* Isoc control struct */
+       struct au0828_dmaqueue vidq;
+       struct au0828_usb_isoc_ctl isoc_ctl;
+       spinlock_t slock;
+
+       /* usb transfer */
+       int alt;                /* alternate */
+       int max_pkt_size;       /* max packet size of isoc transaction */
+       int num_alt;            /* Number of alternative settings */
+       unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
+       struct urb *urb[AU0828_MAX_ISO_BUFS];   /* urb for isoc transfers */
+       char *transfer_buffer[AU0828_MAX_ISO_BUFS];/* transfer buffers for isoc
+                                                  transfer */
+
        /* USB / URB Related */
        int             urb_streaming;
        struct urb      *urbs[URB_COUNT];
-
-};
-
-struct au0828_buff {
-       struct au0828_dev       *dev;
-       struct urb              *purb;
-       struct list_head        buff_list;
 };
 
 /* ----------------------------------------------------------- */
@@ -111,8 +265,13 @@ extern void au0828_card_setup(struct au0828_dev *dev);
 /* au0828-i2c.c */
 extern int au0828_i2c_register(struct au0828_dev *dev);
 extern int au0828_i2c_unregister(struct au0828_dev *dev);
-extern void au0828_call_i2c_clients(struct au0828_dev *dev,
-       unsigned int cmd, void *arg);
+
+/* ----------------------------------------------------------- */
+/* au0828-video.c */
+int au0828_analog_register(struct au0828_dev *dev,
+                          struct usb_interface *interface);
+int au0828_analog_stream_disable(struct au0828_dev *d);
+void au0828_analog_unregister(struct au0828_dev *dev);
 
 /* ----------------------------------------------------------- */
 /* au0828-dvb.c */
index a07b7b88e5b8198148d00f748edcef316e98974a..df4516d8dcab34e6d713d279c6edbe4c299b1a03 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/delay.h>
 #include <linux/types.h>
 #include <linux/ioctl.h>
-#include <asm/uaccess.h>
+#include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
-#include <linux/videodev.h>
-#include <linux/video_decoder.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
+#include <media/bt819.h>
 
 MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
 MODULE_AUTHOR("Mike Bernson & Dave Perks");
@@ -48,13 +48,15 @@ static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
+
 /* ----------------------------------------------------------------------- */
 
 struct bt819 {
+       struct v4l2_subdev sd;
        unsigned char reg[32];
 
-       int initialized;
-       int norm;
+       v4l2_std_id norm;
+       int ident;
        int input;
        int enable;
        int bright;
@@ -63,6 +65,11 @@ struct bt819 {
        int sat;
 };
 
+static inline struct bt819 *to_bt819(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct bt819, sd);
+}
+
 struct timing {
        int hactive;
        int hdelay;
@@ -80,24 +87,23 @@ static struct timing timing_data[] = {
 
 /* ----------------------------------------------------------------------- */
 
-static inline int bt819_write(struct i2c_client *client, u8 reg, u8 value)
+static inline int bt819_write(struct bt819 *decoder, u8 reg, u8 value)
 {
-       struct bt819 *decoder = i2c_get_clientdata(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd);
 
        decoder->reg[reg] = value;
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static inline int bt819_setbit(struct i2c_client *client, u8 reg, u8 bit, u8 value)
+static inline int bt819_setbit(struct bt819 *decoder, u8 reg, u8 bit, u8 value)
 {
-       struct bt819 *decoder = i2c_get_clientdata(client);
-
-       return bt819_write(client, reg,
+       return bt819_write(decoder, reg,
                (decoder->reg[reg] & ~(1 << bit)) | (value ? (1 << bit) : 0));
 }
 
-static int bt819_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
+static int bt819_write_block(struct bt819 *decoder, const u8 *data, unsigned int len)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd);
        int ret = -1;
        u8 reg;
 
@@ -105,7 +111,6 @@ static int bt819_write_block(struct i2c_client *client, const u8 *data, unsigned
         * the adapter understands raw I2C */
        if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
                /* do raw I2C, not smbus compatible */
-               struct bt819 *decoder = i2c_get_clientdata(client);
                u8 block_data[32];
                int block_len;
 
@@ -126,7 +131,8 @@ static int bt819_write_block(struct i2c_client *client, const u8 *data, unsigned
                /* do some slow I2C emulation kind of thing */
                while (len >= 2) {
                        reg = *data++;
-                       if ((ret = bt819_write(client, reg, *data++)) < 0)
+                       ret = bt819_write(decoder, reg, *data++);
+                       if (ret < 0)
                                break;
                        len -= 2;
                }
@@ -135,15 +141,15 @@ static int bt819_write_block(struct i2c_client *client, const u8 *data, unsigned
        return ret;
 }
 
-static inline int bt819_read(struct i2c_client *client, u8 reg)
+static inline int bt819_read(struct bt819 *decoder, u8 reg)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd);
+
        return i2c_smbus_read_byte_data(client, reg);
 }
 
-static int bt819_init(struct i2c_client *client)
+static int bt819_init(struct v4l2_subdev *sd)
 {
-       struct bt819 *decoder = i2c_get_clientdata(client);
-
        static unsigned char init[] = {
                /*0x1f, 0x00,*/     /* Reset */
                0x01, 0x59,     /* 0x01 input format */
@@ -178,7 +184,8 @@ static int bt819_init(struct i2c_client *client)
                0x1a, 0x80,     /* 0x1a ADC Interface */
        };
 
-       struct timing *timing = &timing_data[decoder->norm];
+       struct bt819 *decoder = to_bt819(sd);
+       struct timing *timing = &timing_data[(decoder->norm & V4L2_STD_525_60) ? 1 : 0];
 
        init[0x03 * 2 - 1] =
            (((timing->vdelay >> 8) & 0x03) << 6) |
@@ -192,266 +199,306 @@ static int bt819_init(struct i2c_client *client)
        init[0x08 * 2 - 1] = timing->hscale >> 8;
        init[0x09 * 2 - 1] = timing->hscale & 0xff;
        /* 0x15 in array is address 0x19 */
-       init[0x15 * 2 - 1] = (decoder->norm == 0) ? 115 : 93;   /* Chroma burst delay */
+       init[0x15 * 2 - 1] = (decoder->norm & V4L2_STD_625_50) ? 115 : 93;      /* Chroma burst delay */
        /* reset */
-       bt819_write(client, 0x1f, 0x00);
+       bt819_write(decoder, 0x1f, 0x00);
        mdelay(1);
 
        /* init */
-       return bt819_write_block(client, init, sizeof(init));
+       return bt819_write_block(decoder, init, sizeof(init));
 }
 
 /* ----------------------------------------------------------------------- */
 
-static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int bt819_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
 {
-       int temp;
+       struct bt819 *decoder = to_bt819(sd);
+       int status = bt819_read(decoder, 0x00);
+       int res = V4L2_IN_ST_NO_SIGNAL;
+       v4l2_std_id std;
 
-       struct bt819 *decoder = i2c_get_clientdata(client);
+       if ((status & 0x80))
+               res = 0;
 
-       if (!decoder->initialized) {    /* First call to bt819_init could be */
-               bt819_init(client);     /* without #FRST = 0 */
-               decoder->initialized = 1;
-       }
+       if ((status & 0x10))
+               std = V4L2_STD_PAL;
+       else
+               std = V4L2_STD_NTSC;
+       if (pstd)
+               *pstd = std;
+       if (pstatus)
+               *pstatus = status;
 
-       switch (cmd) {
-       case 0:
-               /* This is just for testing!!! */
-               bt819_init(client);
-               break;
+       v4l2_dbg(1, debug, sd, "get status %x\n", status);
+       return 0;
+}
 
-       case DECODER_GET_CAPABILITIES:
-       {
-               struct video_decoder_capability *cap = arg;
+static int bt819_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+       return bt819_status(sd, NULL, std);
+}
 
-               cap->flags = VIDEO_DECODER_PAL |
-                            VIDEO_DECODER_NTSC |
-                            VIDEO_DECODER_AUTO |
-                            VIDEO_DECODER_CCIR;
-               cap->inputs = 8;
-               cap->outputs = 1;
-               break;
+static int bt819_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+       return bt819_status(sd, status, NULL);
+}
+
+static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct bt819 *decoder = to_bt819(sd);
+       struct timing *timing = NULL;
+
+       v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
+
+       if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL)
+               v4l2_err(sd, "no notify found!\n");
+
+       if (std & V4L2_STD_NTSC) {
+               v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0);
+               bt819_setbit(decoder, 0x01, 0, 1);
+               bt819_setbit(decoder, 0x01, 1, 0);
+               bt819_setbit(decoder, 0x01, 5, 0);
+               bt819_write(decoder, 0x18, 0x68);
+               bt819_write(decoder, 0x19, 0x5d);
+               /* bt819_setbit(decoder, 0x1a,  5, 1); */
+               timing = &timing_data[1];
+       } else if (std & V4L2_STD_PAL) {
+               v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0);
+               bt819_setbit(decoder, 0x01, 0, 1);
+               bt819_setbit(decoder, 0x01, 1, 1);
+               bt819_setbit(decoder, 0x01, 5, 1);
+               bt819_write(decoder, 0x18, 0x7f);
+               bt819_write(decoder, 0x19, 0x72);
+               /* bt819_setbit(decoder, 0x1a,  5, 0); */
+               timing = &timing_data[0];
+       } else {
+               v4l2_dbg(1, debug, sd, "unsupported norm %llx\n",
+                               (unsigned long long)std);
+               return -EINVAL;
        }
+       bt819_write(decoder, 0x03,
+                       (((timing->vdelay >> 8) & 0x03) << 6) |
+                       (((timing->vactive >> 8) & 0x03) << 4) |
+                       (((timing->hdelay >> 8) & 0x03) << 2) |
+                       ((timing->hactive >> 8) & 0x03));
+       bt819_write(decoder, 0x04, timing->vdelay & 0xff);
+       bt819_write(decoder, 0x05, timing->vactive & 0xff);
+       bt819_write(decoder, 0x06, timing->hdelay & 0xff);
+       bt819_write(decoder, 0x07, timing->hactive & 0xff);
+       bt819_write(decoder, 0x08, (timing->hscale >> 8) & 0xff);
+       bt819_write(decoder, 0x09, timing->hscale & 0xff);
+       decoder->norm = std;
+       v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, 0);
+       return 0;
+}
 
-       case DECODER_GET_STATUS:
-       {
-               int *iarg = arg;
-               int status;
-               int res;
+static int bt819_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct bt819 *decoder = to_bt819(sd);
 
-               status = bt819_read(client, 0x00);
-               res = 0;
-               if ((status & 0x80))
-                       res |= DECODER_STATUS_GOOD;
+       v4l2_dbg(1, debug, sd, "set input %x\n", route->input);
 
-               switch (decoder->norm) {
-               case VIDEO_MODE_NTSC:
-                       res |= DECODER_STATUS_NTSC;
-                       break;
-               case VIDEO_MODE_PAL:
-                       res |= DECODER_STATUS_PAL;
-                       break;
-               default:
-               case VIDEO_MODE_AUTO:
-                       if ((status & 0x10))
-                               res |= DECODER_STATUS_PAL;
-                       else
-                               res |= DECODER_STATUS_NTSC;
-                       break;
-               }
-               res |= DECODER_STATUS_COLOR;
-               *iarg = res;
+       if (route->input < 0 || route->input > 7)
+               return -EINVAL;
 
-               v4l_dbg(1, debug, client, "get status %x\n", *iarg);
-               break;
+       if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL)
+               v4l2_err(sd, "no notify found!\n");
+
+       if (decoder->input != route->input) {
+               v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0);
+               decoder->input = route->input;
+               /* select mode */
+               if (decoder->input == 0) {
+                       bt819_setbit(decoder, 0x0b, 6, 0);
+                       bt819_setbit(decoder, 0x1a, 1, 1);
+               } else {
+                       bt819_setbit(decoder, 0x0b, 6, 1);
+                       bt819_setbit(decoder, 0x1a, 1, 0);
+               }
+               v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, 0);
        }
+       return 0;
+}
 
-       case DECODER_SET_NORM:
-       {
-               int *iarg = arg;
-               struct timing *timing = NULL;
-
-               v4l_dbg(1, debug, client, "set norm %x\n", *iarg);
-
-               switch (*iarg) {
-               case VIDEO_MODE_NTSC:
-                       bt819_setbit(client, 0x01, 0, 1);
-                       bt819_setbit(client, 0x01, 1, 0);
-                       bt819_setbit(client, 0x01, 5, 0);
-                       bt819_write(client, 0x18, 0x68);
-                       bt819_write(client, 0x19, 0x5d);
-                       /* bt819_setbit(client, 0x1a,  5, 1); */
-                       timing = &timing_data[VIDEO_MODE_NTSC];
-                       break;
-               case VIDEO_MODE_PAL:
-                       bt819_setbit(client, 0x01, 0, 1);
-                       bt819_setbit(client, 0x01, 1, 1);
-                       bt819_setbit(client, 0x01, 5, 1);
-                       bt819_write(client, 0x18, 0x7f);
-                       bt819_write(client, 0x19, 0x72);
-                       /* bt819_setbit(client, 0x1a,  5, 0); */
-                       timing = &timing_data[VIDEO_MODE_PAL];
-                       break;
-               case VIDEO_MODE_AUTO:
-                       bt819_setbit(client, 0x01, 0, 0);
-                       bt819_setbit(client, 0x01, 1, 0);
-                       break;
-               default:
-                       v4l_dbg(1, debug, client, "unsupported norm %x\n", *iarg);
-                       return -EINVAL;
-               }
+static int bt819_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct bt819 *decoder = to_bt819(sd);
 
-               if (timing) {
-                       bt819_write(client, 0x03,
-                                   (((timing->vdelay >> 8) & 0x03) << 6) |
-                                   (((timing->vactive >> 8) & 0x03) << 4) |
-                                   (((timing->hdelay >> 8) & 0x03) << 2) |
-                                    ((timing->hactive >> 8) & 0x03) );
-                       bt819_write(client, 0x04, timing->vdelay & 0xff);
-                       bt819_write(client, 0x05, timing->vactive & 0xff);
-                       bt819_write(client, 0x06, timing->hdelay & 0xff);
-                       bt819_write(client, 0x07, timing->hactive & 0xff);
-                       bt819_write(client, 0x08, (timing->hscale >> 8) & 0xff);
-                       bt819_write(client, 0x09, timing->hscale & 0xff);
-               }
+       v4l2_dbg(1, debug, sd, "enable output %x\n", enable);
 
-               decoder->norm = *iarg;
-               break;
+       if (decoder->enable != enable) {
+               decoder->enable = enable;
+               bt819_setbit(decoder, 0x16, 7, !enable);
        }
+       return 0;
+}
 
-       case DECODER_SET_INPUT:
-       {
-               int *iarg = arg;
-
-               v4l_dbg(1, debug, client, "set input %x\n", *iarg);
-
-               if (*iarg < 0 || *iarg > 7)
-                       return -EINVAL;
-
-               if (decoder->input != *iarg) {
-                       decoder->input = *iarg;
-                       /* select mode */
-                       if (decoder->input == 0) {
-                               bt819_setbit(client, 0x0b, 6, 0);
-                               bt819_setbit(client, 0x1a, 1, 1);
-                       } else {
-                               bt819_setbit(client, 0x0b, 6, 1);
-                               bt819_setbit(client, 0x1a, 1, 0);
-                       }
-               }
+static int bt819_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       switch (qc->id) {
+       case V4L2_CID_BRIGHTNESS:
+               v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
                break;
-       }
 
-       case DECODER_SET_OUTPUT:
-       {
-               int *iarg = arg;
+       case V4L2_CID_CONTRAST:
+               v4l2_ctrl_query_fill(qc, 0, 511, 1, 256);
+               break;
 
-               v4l_dbg(1, debug, client, "set output %x\n", *iarg);
+       case V4L2_CID_SATURATION:
+               v4l2_ctrl_query_fill(qc, 0, 511, 1, 256);
+               break;
 
-               /* not much choice of outputs */
-               if (*iarg != 0)
-                       return -EINVAL;
+       case V4L2_CID_HUE:
+               v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
                break;
-       }
 
-       case DECODER_ENABLE_OUTPUT:
-       {
-               int *iarg = arg;
-               int enable = (*iarg != 0);
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
 
-               v4l_dbg(1, debug, client, "enable output %x\n", *iarg);
+static int bt819_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct bt819 *decoder = to_bt819(sd);
+       int temp;
 
-               if (decoder->enable != enable) {
-                       decoder->enable = enable;
-                       bt819_setbit(client, 0x16, 7, !enable);
-               }
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               if (decoder->bright == ctrl->value)
+                       break;
+               decoder->bright = ctrl->value;
+               bt819_write(decoder, 0x0a, decoder->bright);
                break;
-       }
 
-       case DECODER_SET_PICTURE:
-       {
-               struct video_picture *pic = arg;
-
-               v4l_dbg(1, debug, client,
-                       "set picture brightness %d contrast %d colour %d\n",
-                       pic->brightness, pic->contrast, pic->colour);
+       case V4L2_CID_CONTRAST:
+               if (decoder->contrast == ctrl->value)
+                       break;
+               decoder->contrast = ctrl->value;
+               bt819_write(decoder, 0x0c, decoder->contrast & 0xff);
+               bt819_setbit(decoder, 0x0b, 2, ((decoder->contrast >> 8) & 0x01));
+               break;
 
+       case V4L2_CID_SATURATION:
+               if (decoder->sat == ctrl->value)
+                       break;
+               decoder->sat = ctrl->value;
+               bt819_write(decoder, 0x0d, (decoder->sat >> 7) & 0xff);
+               bt819_setbit(decoder, 0x0b, 1, ((decoder->sat >> 15) & 0x01));
+
+               /* Ratio between U gain and V gain must stay the same as
+                  the ratio between the default U and V gain values. */
+               temp = (decoder->sat * 180) / 254;
+               bt819_write(decoder, 0x0e, (temp >> 7) & 0xff);
+               bt819_setbit(decoder, 0x0b, 0, (temp >> 15) & 0x01);
+               break;
 
-               if (decoder->bright != pic->brightness) {
-                       /* We want -128 to 127 we get 0-65535 */
-                       decoder->bright = pic->brightness;
-                       bt819_write(client, 0x0a,
-                                   (decoder->bright >> 8) - 128);
-               }
+       case V4L2_CID_HUE:
+               if (decoder->hue == ctrl->value)
+                       break;
+               decoder->hue = ctrl->value;
+               bt819_write(decoder, 0x0f, decoder->hue);
+               break;
 
-               if (decoder->contrast != pic->contrast) {
-                       /* We want 0 to 511 we get 0-65535 */
-                       decoder->contrast = pic->contrast;
-                       bt819_write(client, 0x0c,
-                                   (decoder->contrast >> 7) & 0xff);
-                       bt819_setbit(client, 0x0b, 2,
-                                    ((decoder->contrast >> 15) & 0x01));
-               }
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
 
-               if (decoder->sat != pic->colour) {
-                       /* We want 0 to 511 we get 0-65535 */
-                       decoder->sat = pic->colour;
-                       bt819_write(client, 0x0d,
-                                   (decoder->sat >> 7) & 0xff);
-                       bt819_setbit(client, 0x0b, 1,
-                                    ((decoder->sat >> 15) & 0x01));
-
-                       temp = (decoder->sat * 201) / 237;
-                       bt819_write(client, 0x0e, (temp >> 7) & 0xff);
-                       bt819_setbit(client, 0x0b, 0, (temp >> 15) & 0x01);
-               }
+static int bt819_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct bt819 *decoder = to_bt819(sd);
 
-               if (decoder->hue != pic->hue) {
-                       /* We want -128 to 127 we get 0-65535 */
-                       decoder->hue = pic->hue;
-                       bt819_write(client, 0x0f,
-                                   128 - (decoder->hue >> 8));
-               }
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ctrl->value = decoder->bright;
+               break;
+       case V4L2_CID_CONTRAST:
+               ctrl->value = decoder->contrast;
+               break;
+       case V4L2_CID_SATURATION:
+               ctrl->value = decoder->sat;
+               break;
+       case V4L2_CID_HUE:
+               ctrl->value = decoder->hue;
                break;
-       }
-
        default:
                return -EINVAL;
        }
-
        return 0;
 }
 
+static int bt819_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+       struct bt819 *decoder = to_bt819(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0);
+}
+
 /* ----------------------------------------------------------------------- */
 
-static unsigned short normal_i2c[] = { 0x8a >> 1, I2C_CLIENT_END };
+static const struct v4l2_subdev_core_ops bt819_core_ops = {
+       .g_chip_ident = bt819_g_chip_ident,
+       .g_ctrl = bt819_g_ctrl,
+       .s_ctrl = bt819_s_ctrl,
+       .queryctrl = bt819_queryctrl,
+};
+
+static const struct v4l2_subdev_tuner_ops bt819_tuner_ops = {
+       .s_std = bt819_s_std,
+};
+
+static const struct v4l2_subdev_video_ops bt819_video_ops = {
+       .s_routing = bt819_s_routing,
+       .s_stream = bt819_s_stream,
+       .querystd = bt819_querystd,
+       .g_input_status = bt819_g_input_status,
+};
+
+static const struct v4l2_subdev_ops bt819_ops = {
+       .core = &bt819_core_ops,
+       .tuner = &bt819_tuner_ops,
+       .video = &bt819_video_ops,
+};
 
-I2C_CLIENT_INSMOD;
+/* ----------------------------------------------------------------------- */
 
 static int bt819_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        int i, ver;
        struct bt819 *decoder;
+       struct v4l2_subdev *sd;
        const char *name;
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
 
-       ver = bt819_read(client, 0x17);
+       decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL);
+       if (decoder == NULL)
+               return -ENOMEM;
+       sd = &decoder->sd;
+       v4l2_i2c_subdev_init(sd, client, &bt819_ops);
+
+       ver = bt819_read(decoder, 0x17);
        switch (ver & 0xf0) {
        case 0x70:
                name = "bt819a";
+               decoder->ident = V4L2_IDENT_BT819A;
                break;
        case 0x60:
                name = "bt817a";
+               decoder->ident = V4L2_IDENT_BT817A;
                break;
        case 0x20:
                name = "bt815a";
+               decoder->ident = V4L2_IDENT_BT815A;
                break;
        default:
-               v4l_dbg(1, debug, client,
+               v4l2_dbg(1, debug, sd,
                        "unknown chip version 0x%02x\n", ver);
                return -ENODEV;
        }
@@ -459,28 +506,26 @@ static int bt819_probe(struct i2c_client *client,
        v4l_info(client, "%s found @ 0x%x (%s)\n", name,
                        client->addr << 1, client->adapter->name);
 
-       decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL);
-       if (decoder == NULL)
-               return -ENOMEM;
-       decoder->norm = VIDEO_MODE_NTSC;
+       decoder->norm = V4L2_STD_NTSC;
        decoder->input = 0;
        decoder->enable = 1;
-       decoder->bright = 32768;
-       decoder->contrast = 32768;
-       decoder->hue = 32768;
-       decoder->sat = 32768;
-       decoder->initialized = 0;
-       i2c_set_clientdata(client, decoder);
-
-       i = bt819_init(client);
+       decoder->bright = 0;
+       decoder->contrast = 0xd8;       /* 100% of original signal */
+       decoder->hue = 0;
+       decoder->sat = 0xfe;            /* 100% of original signal */
+
+       i = bt819_init(sd);
        if (i < 0)
-               v4l_dbg(1, debug, client, "init status %d\n", i);
+               v4l2_dbg(1, debug, sd, "init status %d\n", i);
        return 0;
 }
 
 static int bt819_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_bt819(sd));
        return 0;
 }
 
@@ -496,8 +541,6 @@ MODULE_DEVICE_TABLE(i2c, bt819_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "bt819",
-       .driverid = I2C_DRIVERID_BT819,
-       .command = bt819_command,
        .probe = bt819_probe,
        .remove = bt819_remove,
        .id_table = bt819_id,
index 4213867507f8d0f8c45579466adf120091f8c17e..78db39503947b765df2ac93d68887494abaab552 100644 (file)
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
-#include <linux/videodev.h>
-#include <linux/video_encoder.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
 MODULE_AUTHOR("Mike Bernson & Dave Perks");
@@ -47,43 +47,46 @@ static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
+
 /* ----------------------------------------------------------------------- */
 
 #define BT856_REG_OFFSET       0xDA
 #define BT856_NR_REG           6
 
 struct bt856 {
+       struct v4l2_subdev sd;
        unsigned char reg[BT856_NR_REG];
 
-       int norm;
-       int enable;
+       v4l2_std_id norm;
 };
 
+static inline struct bt856 *to_bt856(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct bt856, sd);
+}
+
 /* ----------------------------------------------------------------------- */
 
-static inline int bt856_write(struct i2c_client *client, u8 reg, u8 value)
+static inline int bt856_write(struct bt856 *encoder, u8 reg, u8 value)
 {
-       struct bt856 *encoder = i2c_get_clientdata(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd);
 
        encoder->reg[reg - BT856_REG_OFFSET] = value;
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static inline int bt856_setbit(struct i2c_client *client, u8 reg, u8 bit, u8 value)
+static inline int bt856_setbit(struct bt856 *encoder, u8 reg, u8 bit, u8 value)
 {
-       struct bt856 *encoder = i2c_get_clientdata(client);
-
-       return bt856_write(client, reg,
+       return bt856_write(encoder, reg,
                (encoder->reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) |
                                (value ? (1 << bit) : 0));
 }
 
-static void bt856_dump(struct i2c_client *client)
+static void bt856_dump(struct bt856 *encoder)
 {
        int i;
-       struct bt856 *encoder = i2c_get_clientdata(client);
 
-       v4l_info(client, "register dump:\n");
+       v4l2_info(&encoder->sd, "register dump:\n");
        for (i = 0; i < BT856_NR_REG; i += 2)
                printk(KERN_CONT " %02x", encoder->reg[i]);
        printk(KERN_CONT "\n");
@@ -91,153 +94,120 @@ static void bt856_dump(struct i2c_client *client)
 
 /* ----------------------------------------------------------------------- */
 
-static int bt856_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int bt856_init(struct v4l2_subdev *sd, u32 arg)
 {
-       struct bt856 *encoder = i2c_get_clientdata(client);
-
-       switch (cmd) {
-       case 0:
-               /* This is just for testing!!! */
-               v4l_dbg(1, debug, client, "init\n");
-               bt856_write(client, 0xdc, 0x18);
-               bt856_write(client, 0xda, 0);
-               bt856_write(client, 0xde, 0);
-
-               bt856_setbit(client, 0xdc, 3, 1);
-               //bt856_setbit(client, 0xdc, 6, 0);
-               bt856_setbit(client, 0xdc, 4, 1);
-
-               switch (encoder->norm) {
-               case VIDEO_MODE_NTSC:
-                       bt856_setbit(client, 0xdc, 2, 0);
-                       break;
-
-               case VIDEO_MODE_PAL:
-                       bt856_setbit(client, 0xdc, 2, 1);
-                       break;
-               }
-
-               bt856_setbit(client, 0xdc, 1, 1);
-               bt856_setbit(client, 0xde, 4, 0);
-               bt856_setbit(client, 0xde, 3, 1);
-               if (debug != 0)
-                       bt856_dump(client);
-               break;
-
-       case ENCODER_GET_CAPABILITIES:
-       {
-               struct video_encoder_capability *cap = arg;
-
-               v4l_dbg(1, debug, client, "get capabilities\n");
+       struct bt856 *encoder = to_bt856(sd);
+
+       /* This is just for testing!!! */
+       v4l2_dbg(1, debug, sd, "init\n");
+       bt856_write(encoder, 0xdc, 0x18);
+       bt856_write(encoder, 0xda, 0);
+       bt856_write(encoder, 0xde, 0);
+
+       bt856_setbit(encoder, 0xdc, 3, 1);
+       /*bt856_setbit(encoder, 0xdc, 6, 0);*/
+       bt856_setbit(encoder, 0xdc, 4, 1);
+
+       if (encoder->norm & V4L2_STD_NTSC)
+               bt856_setbit(encoder, 0xdc, 2, 0);
+       else
+               bt856_setbit(encoder, 0xdc, 2, 1);
+
+       bt856_setbit(encoder, 0xdc, 1, 1);
+       bt856_setbit(encoder, 0xde, 4, 0);
+       bt856_setbit(encoder, 0xde, 3, 1);
+       if (debug != 0)
+               bt856_dump(encoder);
+       return 0;
+}
 
-               cap->flags = VIDEO_ENCODER_PAL |
-                            VIDEO_ENCODER_NTSC |
-                            VIDEO_ENCODER_CCIR;
-               cap->inputs = 2;
-               cap->outputs = 1;
-               break;
-       }
+static int bt856_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct bt856 *encoder = to_bt856(sd);
 
-       case ENCODER_SET_NORM:
-       {
-               int *iarg = arg;
-
-               v4l_dbg(1, debug, client, "set norm %d\n", *iarg);
-
-               switch (*iarg) {
-               case VIDEO_MODE_NTSC:
-                       bt856_setbit(client, 0xdc, 2, 0);
-                       break;
-
-               case VIDEO_MODE_PAL:
-                       bt856_setbit(client, 0xdc, 2, 1);
-                       bt856_setbit(client, 0xda, 0, 0);
-                       //bt856_setbit(client, 0xda, 0, 1);
-                       break;
-
-               default:
-                       return -EINVAL;
-               }
-               encoder->norm = *iarg;
-               if (debug != 0)
-                       bt856_dump(client);
-               break;
-       }
+       v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
 
-       case ENCODER_SET_INPUT:
-       {
-               int *iarg = arg;
-
-               v4l_dbg(1, debug, client, "set input %d\n", *iarg);
-
-               /* We only have video bus.
-                * iarg = 0: input is from bt819
-                * iarg = 1: input is from ZR36060 */
-               switch (*iarg) {
-               case 0:
-                       bt856_setbit(client, 0xde, 4, 0);
-                       bt856_setbit(client, 0xde, 3, 1);
-                       bt856_setbit(client, 0xdc, 3, 1);
-                       bt856_setbit(client, 0xdc, 6, 0);
-                       break;
-               case 1:
-                       bt856_setbit(client, 0xde, 4, 0);
-                       bt856_setbit(client, 0xde, 3, 1);
-                       bt856_setbit(client, 0xdc, 3, 1);
-                       bt856_setbit(client, 0xdc, 6, 1);
-                       break;
-               case 2: // Color bar
-                       bt856_setbit(client, 0xdc, 3, 0);
-                       bt856_setbit(client, 0xde, 4, 1);
-                       break;
-               default:
-                       return -EINVAL;
-               }
-
-               if (debug != 0)
-                       bt856_dump(client);
-               break;
+       if (std & V4L2_STD_NTSC) {
+               bt856_setbit(encoder, 0xdc, 2, 0);
+       } else if (std & V4L2_STD_PAL) {
+               bt856_setbit(encoder, 0xdc, 2, 1);
+               bt856_setbit(encoder, 0xda, 0, 0);
+               /*bt856_setbit(encoder, 0xda, 0, 1);*/
+       } else {
+               return -EINVAL;
        }
+       encoder->norm = std;
+       if (debug != 0)
+               bt856_dump(encoder);
+       return 0;
+}
 
-       case ENCODER_SET_OUTPUT:
-       {
-               int *iarg = arg;
+static int bt856_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct bt856 *encoder = to_bt856(sd);
 
-               v4l_dbg(1, debug, client, "set output %d\n", *iarg);
+       v4l2_dbg(1, debug, sd, "set input %d\n", route->input);
 
-               /* not much choice of outputs */
-               if (*iarg != 0)
-                       return -EINVAL;
+       /* We only have video bus.
+        * route->input= 0: input is from bt819
+        * route->input= 1: input is from ZR36060 */
+       switch (route->input) {
+       case 0:
+               bt856_setbit(encoder, 0xde, 4, 0);
+               bt856_setbit(encoder, 0xde, 3, 1);
+               bt856_setbit(encoder, 0xdc, 3, 1);
+               bt856_setbit(encoder, 0xdc, 6, 0);
                break;
-       }
-
-       case ENCODER_ENABLE_OUTPUT:
-       {
-               int *iarg = arg;
-
-               encoder->enable = !!*iarg;
-
-               v4l_dbg(1, debug, client, "enable output %d\n", encoder->enable);
+       case 1:
+               bt856_setbit(encoder, 0xde, 4, 0);
+               bt856_setbit(encoder, 0xde, 3, 1);
+               bt856_setbit(encoder, 0xdc, 3, 1);
+               bt856_setbit(encoder, 0xdc, 6, 1);
+               break;
+       case 2: /* Color bar */
+               bt856_setbit(encoder, 0xdc, 3, 0);
+               bt856_setbit(encoder, 0xde, 4, 1);
                break;
-       }
-
        default:
                return -EINVAL;
        }
 
+       if (debug != 0)
+               bt856_dump(encoder);
        return 0;
 }
 
+static int bt856_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT856, 0);
+}
+
 /* ----------------------------------------------------------------------- */
 
-static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
+static const struct v4l2_subdev_core_ops bt856_core_ops = {
+       .g_chip_ident = bt856_g_chip_ident,
+       .init = bt856_init,
+};
+
+static const struct v4l2_subdev_video_ops bt856_video_ops = {
+       .s_std_output = bt856_s_std_output,
+       .s_routing = bt856_s_routing,
+};
 
-I2C_CLIENT_INSMOD;
+static const struct v4l2_subdev_ops bt856_ops = {
+       .core = &bt856_core_ops,
+       .video = &bt856_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
 
 static int bt856_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        struct bt856 *encoder;
+       struct v4l2_subdev *sd;
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -249,41 +219,38 @@ static int bt856_probe(struct i2c_client *client,
        encoder = kzalloc(sizeof(struct bt856), GFP_KERNEL);
        if (encoder == NULL)
                return -ENOMEM;
-       encoder->norm = VIDEO_MODE_NTSC;
-       encoder->enable = 1;
-       i2c_set_clientdata(client, encoder);
+       sd = &encoder->sd;
+       v4l2_i2c_subdev_init(sd, client, &bt856_ops);
+       encoder->norm = V4L2_STD_NTSC;
 
-       bt856_write(client, 0xdc, 0x18);
-       bt856_write(client, 0xda, 0);
-       bt856_write(client, 0xde, 0);
+       bt856_write(encoder, 0xdc, 0x18);
+       bt856_write(encoder, 0xda, 0);
+       bt856_write(encoder, 0xde, 0);
 
-       bt856_setbit(client, 0xdc, 3, 1);
-       //bt856_setbit(client, 0xdc, 6, 0);
-       bt856_setbit(client, 0xdc, 4, 1);
+       bt856_setbit(encoder, 0xdc, 3, 1);
+       /*bt856_setbit(encoder, 0xdc, 6, 0);*/
+       bt856_setbit(encoder, 0xdc, 4, 1);
 
-       switch (encoder->norm) {
+       if (encoder->norm & V4L2_STD_NTSC)
+               bt856_setbit(encoder, 0xdc, 2, 0);
+       else
+               bt856_setbit(encoder, 0xdc, 2, 1);
 
-       case VIDEO_MODE_NTSC:
-               bt856_setbit(client, 0xdc, 2, 0);
-               break;
-
-       case VIDEO_MODE_PAL:
-               bt856_setbit(client, 0xdc, 2, 1);
-               break;
-       }
-
-       bt856_setbit(client, 0xdc, 1, 1);
-       bt856_setbit(client, 0xde, 4, 0);
-       bt856_setbit(client, 0xde, 3, 1);
+       bt856_setbit(encoder, 0xdc, 1, 1);
+       bt856_setbit(encoder, 0xde, 4, 0);
+       bt856_setbit(encoder, 0xde, 3, 1);
 
        if (debug != 0)
-               bt856_dump(client);
+               bt856_dump(encoder);
        return 0;
 }
 
 static int bt856_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_bt856(sd));
        return 0;
 }
 
@@ -295,8 +262,6 @@ MODULE_DEVICE_TABLE(i2c, bt856_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "bt856",
-       .driverid = I2C_DRIVERID_BT856,
-       .command = bt856_command,
        .probe = bt856_probe,
        .remove = bt856_remove,
        .id_table = bt856_id,
index 596f9e2376beccf140690bf92228ef973b32880f..350cae4b02c3f96866fd9a73583889a88ed9ef68 100644 (file)
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
-#include <linux/videodev.h>
-#include <linux/video_encoder.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
 MODULE_AUTHOR("Mike Bernson & Dave Perks");
@@ -47,22 +47,22 @@ static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
+
 /* ----------------------------------------------------------------------- */
 
 struct bt866 {
+       struct v4l2_subdev sd;
        u8 reg[256];
-
-       int norm;
-       int enable;
-       int bright;
-       int contrast;
-       int hue;
-       int sat;
 };
 
-static int bt866_write(struct i2c_client *client, u8 subaddr, u8 data)
+static inline struct bt866 *to_bt866(struct v4l2_subdev *sd)
 {
-       struct bt866 *encoder = i2c_get_clientdata(client);
+       return container_of(sd, struct bt866, sd);
+}
+
+static int bt866_write(struct bt866 *encoder, u8 subaddr, u8 data)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd);
        u8 buffer[2];
        int err;
 
@@ -89,163 +89,120 @@ static int bt866_write(struct i2c_client *client, u8 subaddr, u8 data)
        return 0;
 }
 
-static int bt866_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
 {
-       struct bt866 *encoder = i2c_get_clientdata(client);
-
-       switch (cmd) {
-       case ENCODER_GET_CAPABILITIES:
-       {
-               struct video_encoder_capability *cap = arg;
-
-               v4l_dbg(1, debug, client, "get capabilities\n");
-
-               cap->flags
-                       = VIDEO_ENCODER_PAL
-                       | VIDEO_ENCODER_NTSC
-                       | VIDEO_ENCODER_CCIR;
-               cap->inputs = 2;
-               cap->outputs = 1;
-               break;
-       }
-
-       case ENCODER_SET_NORM:
-       {
-               int *iarg = arg;
-
-               v4l_dbg(1, debug, client, "set norm %d\n", *iarg);
-
-               switch (*iarg) {
-               case VIDEO_MODE_NTSC:
-                       break;
-
-               case VIDEO_MODE_PAL:
-                       break;
-
-               default:
-                       return -EINVAL;
-               }
-               encoder->norm = *iarg;
-               break;
-       }
-
-       case ENCODER_SET_INPUT:
-       {
-               int *iarg = arg;
-               static const __u8 init[] = {
-                       0xc8, 0xcc, /* CRSCALE */
-                       0xca, 0x91, /* CBSCALE */
-                       0xcc, 0x24, /* YC16 | OSDNUM */
-                       0xda, 0x00, /*  */
-                       0xdc, 0x24, /* SETMODE | PAL */
-                       0xde, 0x02, /* EACTIVE */
-
-                       /* overlay colors */
-                       0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
-                       0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
-                       0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
-                       0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
-                       0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
-                       0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
-                       0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
-                       0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
-
-                       0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
-                       0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
-                       0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
-                       0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
-                       0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
-                       0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
-                       0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
-                       0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
-               };
-               int i;
-               u8 val;
-
-               for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
-                       bt866_write(client, init[i], init[i+1]);
-
-               val = encoder->reg[0xdc];
-
-               if (*iarg == 0)
-                       val |= 0x40; /* CBSWAP */
-               else
-                       val &= ~0x40; /* !CBSWAP */
-
-               bt866_write(client, 0xdc, val);
-
-               val = encoder->reg[0xcc];
-               if (*iarg == 2)
-                       val |= 0x01; /* OSDBAR */
-               else
-                       val &= ~0x01; /* !OSDBAR */
-               bt866_write(client, 0xcc, val);
-
-               v4l_dbg(1, debug, client, "set input %d\n", *iarg);
-
-               switch (*iarg) {
-               case 0:
-                       break;
-               case 1:
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
-       }
-
-       case ENCODER_SET_OUTPUT:
-       {
-               int *iarg = arg;
-
-               v4l_dbg(1, debug, client, "set output %d\n", *iarg);
-
-               /* not much choice of outputs */
-               if (*iarg != 0)
-                       return -EINVAL;
-               break;
-       }
-
-       case ENCODER_ENABLE_OUTPUT:
-       {
-               int *iarg = arg;
-               encoder->enable = !!*iarg;
+       v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
 
-               v4l_dbg(1, debug, client, "enable output %d\n", encoder->enable);
-               break;
-       }
-
-       case 4711:
-       {
-               int *iarg = arg;
-               __u8 val;
-
-               v4l_dbg(1, debug, client, "square %d\n", *iarg);
+       /* Only PAL supported by this driver at the moment! */
+       if (!(std & V4L2_STD_NTSC))
+               return -EINVAL;
+       return 0;
+}
 
-               val = encoder->reg[0xdc];
-               if (*iarg)
-                       val |= 1; /* SQUARE */
-               else
-                       val &= ~1; /* !SQUARE */
-               bt866_write(client, 0xdc, val);
+static int bt866_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       static const __u8 init[] = {
+               0xc8, 0xcc, /* CRSCALE */
+               0xca, 0x91, /* CBSCALE */
+               0xcc, 0x24, /* YC16 | OSDNUM */
+               0xda, 0x00, /*  */
+               0xdc, 0x24, /* SETMODE | PAL */
+               0xde, 0x02, /* EACTIVE */
+
+               /* overlay colors */
+               0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
+               0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
+               0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
+               0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
+               0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
+               0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
+               0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
+               0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
+
+               0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
+               0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
+               0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
+               0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
+               0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
+               0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
+               0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
+               0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
+       };
+       struct bt866 *encoder = to_bt866(sd);
+       u8 val;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
+               bt866_write(encoder, init[i], init[i+1]);
+
+       val = encoder->reg[0xdc];
+
+       if (route->input == 0)
+               val |= 0x40; /* CBSWAP */
+       else
+               val &= ~0x40; /* !CBSWAP */
+
+       bt866_write(encoder, 0xdc, val);
+
+       val = encoder->reg[0xcc];
+       if (route->input == 2)
+               val |= 0x01; /* OSDBAR */
+       else
+               val &= ~0x01; /* !OSDBAR */
+       bt866_write(encoder, 0xcc, val);
+
+       v4l2_dbg(1, debug, sd, "set input %d\n", route->input);
+
+       switch (route->input) {
+       case 0:
+       case 1:
+       case 2:
                break;
-       }
-
        default:
                return -EINVAL;
        }
-
        return 0;
 }
 
-static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
+#if 0
+/* Code to setup square pixels, might be of some use in the future,
+   but is currently unused. */
+       val = encoder->reg[0xdc];
+       if (*iarg)
+               val |= 1; /* SQUARE */
+       else
+               val &= ~1; /* !SQUARE */
+       bt866_write(client, 0xdc, val);
+#endif
+
+static int bt866_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT866, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops bt866_core_ops = {
+       .g_chip_ident = bt866_g_chip_ident,
+};
+
+static const struct v4l2_subdev_video_ops bt866_video_ops = {
+       .s_std_output = bt866_s_std_output,
+       .s_routing = bt866_s_routing,
+};
 
-I2C_CLIENT_INSMOD;
+static const struct v4l2_subdev_ops bt866_ops = {
+       .core = &bt866_core_ops,
+       .video = &bt866_video_ops,
+};
 
 static int bt866_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        struct bt866 *encoder;
+       struct v4l2_subdev *sd;
 
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
@@ -253,20 +210,18 @@ static int bt866_probe(struct i2c_client *client,
        encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
        if (encoder == NULL)
                return -ENOMEM;
-
-       i2c_set_clientdata(client, encoder);
+       sd = &encoder->sd;
+       v4l2_i2c_subdev_init(sd, client, &bt866_ops);
        return 0;
 }
 
 static int bt866_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
-       return 0;
-}
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
-static int bt866_legacy_probe(struct i2c_adapter *adapter)
-{
-       return adapter->id == I2C_HW_B_ZR36067;
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_bt866(sd));
+       return 0;
 }
 
 static const struct i2c_device_id bt866_id[] = {
@@ -277,10 +232,7 @@ MODULE_DEVICE_TABLE(i2c, bt866_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "bt866",
-       .driverid = I2C_DRIVERID_BT866,
-       .command = bt866_command,
        .probe = bt866_probe,
        .remove = bt866_remove,
-       .legacy_probe = bt866_legacy_probe,
        .id_table = bt866_id,
 };
index ce71e8e7b8355bd8fe59af2397b537bd7202a693..3077c45015f594e8c963c470fad2c07d81cf341a 100644 (file)
@@ -10,7 +10,7 @@ config VIDEO_BT848
        select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_TDA7432 if VIDEO_HELPER_CHIPS_AUTO
-       select VIDEO_TDA9875 if VIDEO_HELPER_CHIPS_AUTO
+       select VIDEO_SAA6588 if VIDEO_HELPER_CHIPS_AUTO
        ---help---
          Support for BT848 based frame grabber/overlay boards. This includes
          the Miro, Hauppauge and STB boards. Please read the material in
index d24dcc025e3714ff7c866fdff03cbd73fe9cbd6a..b9c3ba51fb86c3f66f0b3188215f70ec467f7c2b 100644 (file)
@@ -73,6 +73,11 @@ static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input);
 
 static void geovision_muxsel(struct bttv *btv, unsigned int input);
 
+static void phytec_muxsel(struct bttv *btv, unsigned int input);
+
+static void gv800s_muxsel(struct bttv *btv, unsigned int input);
+static void gv800s_init(struct bttv *btv);
+
 static int terratec_active_radio_upgrade(struct bttv *btv);
 static int tea5757_read(struct bttv *btv);
 static int tea5757_write(struct bttv *btv, int value);
@@ -91,12 +96,10 @@ static unsigned int pll[BTTV_MAX]    = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
 static unsigned int tuner[BTTV_MAX]  = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
 static unsigned int svhs[BTTV_MAX]   = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
 static unsigned int remote[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+static unsigned int audiodev[BTTV_MAX];
+static unsigned int saa6588[BTTV_MAX];
 static struct bttv  *master[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = NULL };
-#ifdef MODULE
-static unsigned int autoload = 1;
-#else
-static unsigned int autoload;
-#endif
+static unsigned int autoload = UNSET;
 static unsigned int gpiomask = UNSET;
 static unsigned int audioall = UNSET;
 static unsigned int audiomux[5] = { [ 0 ... 4 ] = UNSET };
@@ -115,6 +118,7 @@ module_param_array(pll,      int, NULL, 0444);
 module_param_array(tuner,    int, NULL, 0444);
 module_param_array(svhs,     int, NULL, 0444);
 module_param_array(remote,   int, NULL, 0444);
+module_param_array(audiodev, int, NULL, 0444);
 module_param_array(audiomux, int, NULL, 0444);
 
 MODULE_PARM_DESC(triton1,"set ETBF pci config bit "
@@ -125,7 +129,14 @@ MODULE_PARM_DESC(latency,"pci latency timer");
 MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
 MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
 MODULE_PARM_DESC(tuner,"specify installed tuner type");
-MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)");
+MODULE_PARM_DESC(autoload, "obsolete option, please do not use anymore");
+MODULE_PARM_DESC(audiodev, "specify audio device:\n"
+               "\t\t-1 = no audio\n"
+               "\t\t 0 = autodetect (default)\n"
+               "\t\t 1 = msp3400\n"
+               "\t\t 2 = tda7432\n"
+               "\t\t 3 = tvaudio");
+MODULE_PARM_DESC(saa6588, "if 1, then load the saa6588 RDS module, default (0) is to use the card definition.");
 MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)"
                " [some VIA/SIS chipsets are known to have problem with overlay]");
 
@@ -246,6 +257,10 @@ static struct CARD {
        { 0xa182ff0d, BTTV_BOARD_IVC120,        "IVC-120G" },
        { 0xa182ff0e, BTTV_BOARD_IVC120,        "IVC-120G" },
        { 0xa182ff0f, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xf0500000, BTTV_BOARD_IVCE8784,      "IVCE-8784" },
+       { 0xf0500001, BTTV_BOARD_IVCE8784,      "IVCE-8784" },
+       { 0xf0500002, BTTV_BOARD_IVCE8784,      "IVCE-8784" },
+       { 0xf0500003, BTTV_BOARD_IVCE8784,      "IVCE-8784" },
 
        { 0x41424344, BTTV_BOARD_GRANDTEC,      "GrandTec Multi Capture" },
        { 0x01020304, BTTV_BOARD_XGUARD,        "Grandtec Grand X-Guard" },
@@ -289,6 +304,8 @@ static struct CARD {
        /* Duplicate PCI ID, reconfigure for this board during the eeprom read.
        * { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB,  "Hauppauge ImpactVCB" }, */
 
+       { 0x109e036e, BTTV_BOARD_CONCEPTRONIC_CTVFMI2,  "Conceptronic CTVFMi v2"},
+
        /* DVB cards (using pci function .1 for mpeg data xfer) */
        { 0x001c11bd, BTTV_BOARD_PINNACLESAT,   "Pinnacle PCTV Sat" },
        { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
@@ -305,6 +322,20 @@ static struct CARD {
        { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2,    "DViCO FusionHDTV 2" },
        { 0x763c008a, BTTV_BOARD_GEOVISION_GV600,       "GeoVision GV-600" },
        { 0x18011000, BTTV_BOARD_ENLTV_FM_2,    "Encore ENL TV-FM-2" },
+       { 0x763d800a, BTTV_BOARD_GEOVISION_GV800S, "GeoVision GV-800(S) (master)" },
+       { 0x763d800b, BTTV_BOARD_GEOVISION_GV800S_SL,   "GeoVision GV-800(S) (slave)" },
+       { 0x763d800c, BTTV_BOARD_GEOVISION_GV800S_SL,   "GeoVision GV-800(S) (slave)" },
+       { 0x763d800d, BTTV_BOARD_GEOVISION_GV800S_SL,   "GeoVision GV-800(S) (slave)" },
+
+       { 0x15401830, BTTV_BOARD_PV183,         "Provideo PV183-1" },
+       { 0x15401831, BTTV_BOARD_PV183,         "Provideo PV183-2" },
+       { 0x15401832, BTTV_BOARD_PV183,         "Provideo PV183-3" },
+       { 0x15401833, BTTV_BOARD_PV183,         "Provideo PV183-4" },
+       { 0x15401834, BTTV_BOARD_PV183,         "Provideo PV183-5" },
+       { 0x15401835, BTTV_BOARD_PV183,         "Provideo PV183-6" },
+       { 0x15401836, BTTV_BOARD_PV183,         "Provideo PV183-7" },
+       { 0x15401837, BTTV_BOARD_PV183,         "Provideo PV183-8" },
+
        { 0, -1, NULL }
 };
 
@@ -316,59 +347,50 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_UNKNOWN] = {
                .name           = " *** UNKNOWN/GENERIC *** ",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
                .svhs           = 2,
-               .muxsel         = { 2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_MIRO] = {
                .name           = "MIRO PCTV",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 15,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 2, 0, 0, 0 },
                .gpiomute       = 10,
                .needs_tvaudio  = 1,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_HAUPPAUGE] = {
                .name           = "Hauppauge (bt848)",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 7,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 1, 2, 3 },
                .gpiomute       = 4,
                .needs_tvaudio  = 1,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_STB] = {
                .name           = "STB, Gateway P/N 6000699 (bt848)",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 7,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 4, 0, 2, 3 },
                .gpiomute       = 1,
                .no_msp34xx     = 1,
                .needs_tvaudio  = 1,
                .tuner_type     = TUNER_PHILIPS_NTSC,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
                .has_radio      = 1,
        },
@@ -377,202 +399,177 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_INTEL] = {
                .name           = "Intel Create and Share PCI/ Smart Video Recorder III",
                .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
+               /* .audio_inputs= 0, */
                .svhs           = 2,
                .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_DIAMOND] = {
                .name           = "Diamond DTV2000",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 3,
-               .muxsel         = { 2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .gpiomux        = { 0, 1, 0, 1 },
                .gpiomute       = 3,
                .needs_tvaudio  = 1,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_AVERMEDIA] = {
                .name           = "AVerMedia TVPhone",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 3,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomask       = 0x0f,
                .gpiomux        = { 0x0c, 0x04, 0x08, 0x04 },
                /*                0x04 for some cards ?? */
                .needs_tvaudio  = 1,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .audio_mode_gpio= avermedia_tvphone_audio,
                .has_remote     = 1,
        },
        [BTTV_BOARD_MATRIX_VISION] = {
                .name           = "MATRIX-Vision MV-Delta",
                .video_inputs   = 5,
-               .audio_inputs   = 1,
-               .tuner          = UNSET,
+               /* .audio_inputs= 1, */
                .svhs           = 3,
                .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 0, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0, 0),
                .gpiomux        = { 0 },
                .needs_tvaudio  = 1,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
        /* ---- card 0x08 ---------------------------------- */
        [BTTV_BOARD_FLYVIDEO] = {
                .name           = "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0xc00,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 0xc00, 0x800, 0x400 },
                .gpiomute       = 0xc00,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_TURBOTV] = {
                .name           = "IMS/IXmicro TurboTV",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 3,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 1, 1, 2, 3 },
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
                .tuner_type     = TUNER_TEMIC_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_HAUPPAUGE878] = {
                .name           = "Hauppauge (bt878)",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x0f, /* old: 7 */
-               .muxsel         = { 2, 0, 1, 1 },
+               .muxsel         = MUXSEL(2, 0, 1, 1),
                .gpiomux        = { 0, 1, 2, 3 },
                .gpiomute       = 4,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_MIROPRO] = {
                .name           = "MIRO PCTV pro",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x3014f,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0x20001,0x10001, 0, 0 },
                .gpiomute       = 10,
                .needs_tvaudio  = 1,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
        /* ---- card 0x0c ---------------------------------- */
        [BTTV_BOARD_ADSTECH_TV] = {
                .name           = "ADS Technologies Channel Surfer TV (bt848)",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 15,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 13, 14, 11, 7 },
                .needs_tvaudio  = 1,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_AVERMEDIA98] = {
                .name           = "AVerMedia TVCapture 98",
                .video_inputs   = 3,
-               .audio_inputs   = 4,
-               .tuner          = 0,
+               /* .audio_inputs= 4, */
                .svhs           = 2,
                .gpiomask       = 15,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 13, 14, 11, 7 },
                .needs_tvaudio  = 1,
                .msp34xx_alt    = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .audio_mode_gpio= avermedia_tv_stereo_audio,
                .no_gpioirq     = 1,
        },
        [BTTV_BOARD_VHX] = {
                .name           = "Aimslab Video Highway Xtreme (VHX)",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 7,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 2, 1, 3 }, /* old: {0, 1, 2, 3, 4} */
                .gpiomute       = 4,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_ZOLTRIX] = {
                .name           = "Zoltrix TV-Max",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 15,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 0, 1, 0 },
                .gpiomute       = 10,
                .needs_tvaudio  = 1,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
        /* ---- card 0x10 ---------------------------------- */
        [BTTV_BOARD_PIXVIEWPLAYTV] = {
                .name           = "Prolink Pixelview PlayTV (bt878)",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x01fe00,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                /* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
                .gpiomux        = { 0x001e00, 0, 0x018000, 0x014000 },
                .gpiomute       = 0x002000,
@@ -580,194 +577,170 @@ struct tvcard bttv_tvcards[] = {
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_WINVIEW_601] = {
                .name           = "Leadtek WinView 601",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x8300f8,
-               .muxsel         = { 2, 3, 1, 1,0 },
+               .muxsel         = MUXSEL(2, 3, 1, 1, 0),
                .gpiomux        = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007 },
                .gpiomute       = 0xcfa007,
                .needs_tvaudio  = 1,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .volume_gpio    = winview_volume,
                .has_radio      = 1,
        },
        [BTTV_BOARD_AVEC_INTERCAP] = {
                .name           = "AVEC Intercapture",
                .video_inputs   = 3,
-               .audio_inputs   = 2,
-               .tuner          = 0,
+               /* .audio_inputs= 2, */
                .svhs           = 2,
                .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 1, 0, 0, 0 },
                .needs_tvaudio  = 1,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_LIFE_FLYKIT] = {
                .name           = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = UNSET,
-               .svhs           = UNSET,
+               /* .audio_inputs= 1, */
+               .svhs           = NO_SVHS,
                .gpiomask       = 0x8dff00,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0 },
                .no_msp34xx     = 1,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
        /* ---- card 0x14 ---------------------------------- */
        [BTTV_BOARD_CEI_RAFFLES] = {
                .name           = "CEI Raffles Card",
                .video_inputs   = 3,
-               .audio_inputs   = 3,
-               .tuner          = 0,
+               /* .audio_inputs= 3, */
                .svhs           = 2,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_CONFERENCETV] = {
                .name           = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
                .video_inputs   = 4,
-               .audio_inputs   = 2,  /* tuner, line in */
-               .tuner          = 0,
+               /* .audio_inputs= 2,  tuner, line in */
                .svhs           = 2,
                .gpiomask       = 0x1800,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
                .gpiomute       = 0x1800,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL_I,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_PHOEBE_TVMAS] = {
                .name           = "Askey CPH050/ Phoebe Tv Master + FM",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0xc00,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 1, 0x800, 0x400 },
                .gpiomute       = 0xc00,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_MODTEC_205] = {
                .name           = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = UNSET,
+               /* .audio_inputs= 1, */
+               .svhs           = NO_SVHS,
+               .has_dig_in     = 1,
                .gpiomask       = 7,
-               .muxsel         = { 2, 3, -1 },
-               .digital_mode   = DIGITAL_MODE_CAMERA,
+               .muxsel         = MUXSEL(2, 3, 0), /* input 2 is digital */
+               /* .digital_mode= DIGITAL_MODE_CAMERA, */
                .gpiomux        = { 0, 0, 0, 0 },
                .no_msp34xx     = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_ALPS_TSBB5_PAL_I,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
        /* ---- card 0x18 ---------------------------------- */
        [BTTV_BOARD_MAGICTVIEW061] = {
                .name           = "Askey CPH05X/06X (bt878) [many vendors]",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0xe00,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = {0x400, 0x400, 0x400, 0x400 },
                .gpiomute       = 0xc00,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_remote     = 1,
        },
        [BTTV_BOARD_VOBIS_BOOSTAR] = {
                .name           = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x1f0fff,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0x20000, 0x30000, 0x10000, 0 },
                .gpiomute       = 0x40000,
                .needs_tvaudio  = 0,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .audio_mode_gpio= terratv_audio,
        },
        [BTTV_BOARD_HAUPPAUG_WCAM] = {
                .name           = "Hauppauge WinCam newer (bt878)",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 3,
                .gpiomask       = 7,
-               .muxsel         = { 2, 0, 1, 1 },
+               .muxsel         = MUXSEL(2, 0, 1, 1),
                .gpiomux        = { 0, 1, 2, 3 },
                .gpiomute       = 4,
                .needs_tvaudio  = 1,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_MAXI] = {
                .name           = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
                .video_inputs   = 4,
-               .audio_inputs   = 2,
-               .tuner          = 0,
+               /* .audio_inputs= 2, */
                .svhs           = 2,
                .gpiomask       = 0x1800,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
                .gpiomute       = 0x1800,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_SECAM,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
        /* ---- card 0x1c ---------------------------------- */
        [BTTV_BOARD_TERRATV] = {
                .name           = "Terratec TerraTV+ Version 1.1 (bt878)",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x1f0fff,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0x20000, 0x30000, 0x10000, 0x00000 },
                .gpiomute       = 0x40000,
                .needs_tvaudio  = 0,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .audio_mode_gpio= terratv_audio,
                /* GPIO wiring:
                External 20 pin connector (for Active Radio Upgrade board)
@@ -805,87 +778,77 @@ struct tvcard bttv_tvcards[] = {
                /* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
                .name           = "Imagenation PXC200",
                .video_inputs   = 5,
-               .audio_inputs   = 1,
-               .tuner          = UNSET,
+               /* .audio_inputs= 1, */
                .svhs           = 1, /* was: 4 */
                .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 0, 0},
+               .muxsel         = MUXSEL(2, 3, 1, 0, 0),
                .gpiomux        = { 0 },
                .needs_tvaudio  = 1,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .muxsel_hook    = PXC200_muxsel,
 
        },
        [BTTV_BOARD_FLYVIDEO_98] = {
                .name           = "Lifeview FlyVideo 98 LR50",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x1800,  /* 0x8dfe00 */
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 0x0800, 0x1000, 0x1000 },
                .gpiomute       = 0x1800,
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_IPROTV] = {
                .name           = "Formac iProTV, Formac ProTV I (bt848)",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 3,
                .gpiomask       = 1,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 1, 0, 0, 0 },
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
        /* ---- card 0x20 ---------------------------------- */
        [BTTV_BOARD_INTEL_C_S_PCI] = {
                .name           = "Intel Create and Share PCI/ Smart Video Recorder III",
                .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
+               /* .audio_inputs= 0, */
                .svhs           = 2,
                .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_TERRATVALUE] = {
                .name           = "Terratec TerraTValue Version Bt878",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0xffff00,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0x500, 0, 0x300, 0x900 },
                .gpiomute       = 0x900,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_WINFAST2000] = {
                .name           = "Leadtek WinFast 2000/ WinFast 2000 XP",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
-               .muxsel         = { 2, 3, 1, 1, 0 }, /* TV, CVid, SVid, CVid over SVid connector */
+               /* TV, CVid, SVid, CVid over SVid connector */
+               .muxsel         = MUXSEL(2, 3, 1, 1, 0),
                /* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
                .gpiomask       = 0xb33000,
                .gpiomux        = { 0x122000,0x1000,0x0000,0x620000 },
@@ -906,217 +869,191 @@ struct tvcard bttv_tvcards[] = {
                .has_radio      = 1,
                .tuner_type     = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .audio_mode_gpio= winfast2000_audio,
                .has_remote     = 1,
        },
        [BTTV_BOARD_CHRONOS_VS2] = {
                .name           = "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
                .video_inputs   = 4,
-               .audio_inputs   = 3,
-               .tuner          = 0,
+               /* .audio_inputs= 3, */
                .svhs           = 2,
                .gpiomask       = 0x1800,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
                .gpiomute       = 0x1800,
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
        /* ---- card 0x24 ---------------------------------- */
        [BTTV_BOARD_TYPHOON_TVIEW] = {
                .name           = "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
                .video_inputs   = 4,
-               .audio_inputs   = 3,
-               .tuner          = 0,
+               /* .audio_inputs= 3, */
                .svhs           = 2,
                .gpiomask       = 0x1800,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
                .gpiomute       = 0x1800,
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_radio      = 1,
        },
        [BTTV_BOARD_PXELVWPLTVPRO] = {
                .name           = "Prolink PixelView PlayTV pro",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0xff,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0x21, 0x20, 0x24, 0x2c },
                .gpiomute       = 0x29,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_MAGICTVIEW063] = {
                .name           = "Askey CPH06X TView99",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x551e00,
-               .muxsel         = { 2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .gpiomux        = { 0x551400, 0x551200, 0, 0 },
                .gpiomute       = 0x551c00,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL_I,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_remote     = 1,
        },
        [BTTV_BOARD_PINNACLE] = {
                .name           = "Pinnacle PCTV Studio/Rave",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x03000F,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 2, 0xd0001, 0, 0 },
                .gpiomute       = 1,
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
        /* ---- card 0x28 ---------------------------------- */
        [BTTV_BOARD_STB2] = {
                .name           = "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 7,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 4, 0, 2, 3 },
                .gpiomute       = 1,
                .no_msp34xx     = 1,
                .needs_tvaudio  = 1,
                .tuner_type     = TUNER_PHILIPS_NTSC,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
                .has_radio      = 1,
        },
        [BTTV_BOARD_AVPHONE98] = {
                .name           = "AVerMedia TVPhone 98",
                .video_inputs   = 3,
-               .audio_inputs   = 4,
-               .tuner          = 0,
+               /* .audio_inputs= 4, */
                .svhs           = 2,
                .gpiomask       = 15,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 13, 4, 11, 7 },
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_radio      = 1,
                .audio_mode_gpio= avermedia_tvphone_audio,
        },
        [BTTV_BOARD_PV951] = {
                .name           = "ProVideo PV951", /* pic16c54 */
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 1},
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 0, 0, 0},
                .needs_tvaudio  = 1,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL_I,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_ONAIR_TV] = {
                .name           = "Little OnAir TV",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0xe00b,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0xff9ff6, 0xff9ff6, 0xff1ff7, 0 },
                .gpiomute       = 0xff3ffc,
                .no_msp34xx     = 1,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
        /* ---- card 0x2c ---------------------------------- */
        [BTTV_BOARD_SIGMA_TVII_FM] = {
                .name           = "Sigma TVII-FM",
                .video_inputs   = 2,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = UNSET,
+               /* .audio_inputs= 1, */
+               .svhs           = NO_SVHS,
                .gpiomask       = 3,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 1, 1, 0, 2 },
                .gpiomute       = 3,
                .no_msp34xx     = 1,
                .pll            = PLL_NONE,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_MATRIX_VISION2] = {
                .name           = "MATRIX-Vision MV-Delta 2",
                .video_inputs   = 5,
-               .audio_inputs   = 1,
-               .tuner          = UNSET,
+               /* .audio_inputs= 1, */
                .svhs           = 3,
                .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 0, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0, 0),
                .gpiomux        = { 0 },
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_ZOLTRIX_GENIE] = {
                .name           = "Zoltrix Genie TV/FM",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0xbcf03f,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0xbc803f, 0xbc903f, 0xbcb03f, 0 },
                .gpiomute       = 0xbcb03f,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_TEMIC_4039FR5_NTSC,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_TERRATVRADIO] = {
                .name           = "Terratec TV/Radio+",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x70000,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0x20000, 0x30000, 0x10000, 0 },
                .gpiomute       = 0x40000,
                .needs_tvaudio  = 1,
@@ -1124,7 +1061,6 @@ struct tvcard bttv_tvcards[] = {
                .pll            = PLL_35,
                .tuner_type     = TUNER_PHILIPS_PAL_I,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_radio      = 1,
        },
 
@@ -1132,51 +1068,46 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_DYNALINK] = {
                .name           = "Askey CPH03x/ Dynalink Magic TView",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 15,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = {2,0,0,0 },
                .gpiomute       = 1,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_GVBCTV3PCI] = {
                .name           = "IODATA GV-BCTV3/PCI",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x010f00,
-               .muxsel         = {2, 3, 0, 0 },
+               .muxsel         = MUXSEL(2, 3, 0, 0),
                .gpiomux        = {0x10000, 0, 0x10000, 0 },
                .no_msp34xx     = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_ALPS_TSHC6_NTSC,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .audio_mode_gpio= gvbctv3pci_audio,
        },
        [BTTV_BOARD_PXELVWPLTVPAK] = {
                .name           = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
                .video_inputs   = 5,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 3,
+               .has_dig_in     = 1,
                .gpiomask       = 0xAA0000,
-               .muxsel         = { 2,3,1,1,-1 },
-               .digital_mode   = DIGITAL_MODE_CAMERA,
+               .muxsel         = MUXSEL(2, 3, 1, 1, 0), /* in 4 is digital */
+               /* .digital_mode= DIGITAL_MODE_CAMERA, */
                .gpiomux        = { 0x20000, 0, 0x80000, 0x80000 },
                .gpiomute       = 0xa8000,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL_I,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_remote     = 1,
                /* GPIO wiring: (different from Rev.4C !)
                        GPIO17: U4.A0 (first hef4052bt)
@@ -1191,17 +1122,15 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_EAGLE] = {
                .name           = "Eagle Wireless Capricorn2 (bt878A)",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 7,
-               .muxsel         = { 2, 0, 1, 1 },
+               .muxsel         = MUXSEL(2, 0, 1, 1),
                .gpiomux        = { 0, 1, 2, 3 },
                .gpiomute       = 4,
                .pll            = PLL_28,
                .tuner_type     = UNSET /* TUNER_ALPS_TMDH2_NTSC */,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
        /* ---- card 0x34 ---------------------------------- */
@@ -1209,11 +1138,10 @@ struct tvcard bttv_tvcards[] = {
                /* David Härdeman <david@2gen.com> */
                .name           = "Pinnacle PCTV Studio Pro",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 3,
                .gpiomask       = 0x03000F,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 1, 0xd0001, 0, 0 },
                .gpiomute       = 10,
                                /* sound path (5 sources):
@@ -1229,25 +1157,22 @@ struct tvcard bttv_tvcards[] = {
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_TVIEW_RDS_FM] = {
                /* Claas Langbehn <claas@bigfoot.com>,
                Sven Grothklags <sven@upb.de> */
                .name           = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
                .video_inputs   = 4,
-               .audio_inputs   = 3,
-               .tuner          = 0,
+               /* .audio_inputs= 3, */
                .svhs           = 2,
                .gpiomask       = 0x1c,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 0, 0x10, 8 },
                .gpiomute       = 4,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_radio      = 1,
        },
        [BTTV_BOARD_LIFETEC_9415] = {
@@ -1258,11 +1183,10 @@ struct tvcard bttv_tvcards[] = {
                        options tuner type=5 */
                .name           = "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x18e0,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0x0000,0x0800,0x1000,0x1000 },
                .gpiomute       = 0x18e0,
                        /* For cards with tda9820/tda9821:
@@ -1272,25 +1196,22 @@ struct tvcard bttv_tvcards[] = {
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_BESTBUY_EASYTV] = {
                /* Miguel Angel Alvarez <maacruz@navegalia.com>
                old Easy TV BT848 version (model CPH031) */
                .name           = "Askey CPH031/ BESTBUY Easy TV",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0xF,
-               .muxsel         = { 2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .gpiomux        = { 2, 0, 0, 0 },
                .gpiomute       = 10,
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
                .tuner_type     = TUNER_TEMIC_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
        /* ---- card 0x38 ---------------------------------- */
@@ -1298,17 +1219,15 @@ struct tvcard bttv_tvcards[] = {
                /* Gordon Heydon <gjheydon@bigfoot.com ('98) */
                .name           = "Lifeview FlyVideo 98FM LR50",
                .video_inputs   = 4,
-               .audio_inputs   = 3,
-               .tuner          = 0,
+               /* .audio_inputs= 3, */
                .svhs           = 2,
                .gpiomask       = 0x1800,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
                .gpiomute       = 0x1800,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
                /* This is the ultimate cheapo capture card
                * just a BT848A on a small PCB!
@@ -1316,51 +1235,45 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_GRANDTEC] = {
                .name           = "GrandTec 'Grand Video Capture' (Bt848)",
                .video_inputs   = 2,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
+               /* .audio_inputs= 0, */
                .svhs           = 1,
                .gpiomask       = 0,
-               .muxsel         = { 3, 1 },
+               .muxsel         = MUXSEL(3, 1),
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .pll            = PLL_35,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_ASKEY_CPH060] = {
                /* Daniel Herrington <daniel.herrington@home.com> */
                .name           = "Askey CPH060/ Phoebe TV Master Only (No FM)",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0xe00,
-               .muxsel         = { 2, 3, 1, 1},
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0x400, 0x400, 0x400, 0x400 },
                .gpiomute       = 0x800,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_TEMIC_4036FY5_NTSC,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_ASKEY_CPH03X] = {
                /* Matti Mottus <mottus@physic.ut.ee> */
                .name           = "Askey CPH03x TV Capturer",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x03000F,
-               .muxsel         = { 2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .gpiomux        = { 2, 0, 0, 0 },
                .gpiomute       = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_TEMIC_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
        /* ---- card 0x3c ---------------------------------- */
@@ -1368,34 +1281,30 @@ struct tvcard bttv_tvcards[] = {
                /* Philip Blundell <philb@gnu.org> */
                .name           = "Modular Technology MM100PCTV",
                .video_inputs   = 2,
-               .audio_inputs   = 2,
-               .tuner          = 0,
-               .svhs           = UNSET,
+               /* .audio_inputs= 2, */
+               .svhs           = NO_SVHS,
                .gpiomask       = 11,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 2, 0, 0, 1 },
                .gpiomute       = 8,
                .pll            = PLL_35,
                .tuner_type     = TUNER_TEMIC_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_GMV1] = {
                /* Adrian Cox <adrian@humboldt.co.uk */
                .name           = "AG Electronics GMV1",
                .video_inputs   = 2,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
+               /* .audio_inputs= 0, */
                .svhs           = 1,
                .gpiomask       = 0xF,
-               .muxsel         = { 2, 2 },
+               .muxsel         = MUXSEL(2, 2),
                .gpiomux        = { },
                .no_msp34xx     = 1,
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_BESTBUY_EASYTV2] = {
                /* Miguel Angel Alvarez <maacruz@navegalia.com>
@@ -1403,34 +1312,30 @@ struct tvcard bttv_tvcards[] = {
                special thanks to Informatica Mieres for providing the card */
                .name           = "Askey CPH061/ BESTBUY Easy TV (bt878)",
                .video_inputs   = 3,
-               .audio_inputs   = 2,
-               .tuner          = 0,
+               /* .audio_inputs= 2, */
                .svhs           = 2,
                .gpiomask       = 0xFF,
-               .muxsel         = { 2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .gpiomux        = { 1, 0, 4, 4 },
                .gpiomute       = 9,
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_ATI_TVWONDER] = {
                /* Lukas Gebauer <geby@volny.cz> */
                .name           = "ATI TV-Wonder",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0xf03f,
-               .muxsel         = { 2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .gpiomux        = { 0xbffe, 0, 0xbfff, 0 },
                .gpiomute       = 0xbffe,
                .pll            = PLL_28,
                .tuner_type     = TUNER_TEMIC_4006FN5_MULTI_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
        /* ---- card 0x40 ---------------------------------- */
@@ -1438,27 +1343,24 @@ struct tvcard bttv_tvcards[] = {
                /* Lukas Gebauer <geby@volny.cz> */
                .name           = "ATI TV-Wonder VE",
                .video_inputs   = 2,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = UNSET,
+               /* .audio_inputs= 1, */
+               .svhs           = NO_SVHS,
                .gpiomask       = 1,
-               .muxsel         = { 2, 3, 0, 1 },
+               .muxsel         = MUXSEL(2, 3, 0, 1),
                .gpiomux        = { 0, 0, 1, 0 },
                .no_msp34xx     = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_TEMIC_4006FN5_MULTI_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_FLYVIDEO2000] = {
                /* DeeJay <deejay@westel900.net (2000S) */
                .name           = "Lifeview FlyVideo 2000S LR90",
                .video_inputs   = 3,
-               .audio_inputs   = 3,
-               .tuner          = 0,
+               /* .audio_inputs= 3, */
                .svhs           = 2,
                .gpiomask       = 0x18e0,
-               .muxsel         = { 2, 3, 0, 1 },
+               .muxsel         = MUXSEL(2, 3, 0, 1),
                                /* Radio changed from 1e80 to 0x800 to make
                                FlyVideo2000S in .hu happy (gm)*/
                                /* -dk-???: set mute=0x1800 for tda9874h daughterboard */
@@ -1471,40 +1373,35 @@ struct tvcard bttv_tvcards[] = {
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_TERRATVALUER] = {
                .name           = "Terratec TValueRadio",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0xffff00,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0x500, 0x500, 0x300, 0x900 },
                .gpiomute       = 0x900,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_radio      = 1,
        },
        [BTTV_BOARD_GVBCTV4PCI] = {
                /* TANAKA Kei <peg00625@nifty.com> */
                .name           = "IODATA GV-BCTV4/PCI",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x010f00,
-               .muxsel         = {2, 3, 0, 0 },
+               .muxsel         = MUXSEL(2, 3, 0, 0),
                .gpiomux        = {0x10000, 0, 0x10000, 0 },
                .no_msp34xx     = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_SHARP_2U5JF5540_NTSC,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .audio_mode_gpio= gvbctv3pci_audio,
        },
 
@@ -1514,9 +1411,8 @@ struct tvcard bttv_tvcards[] = {
                /* try "insmod msp3400 simple=0" if you have
                * sound problems with this card. */
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = UNSET,
+               /* .audio_inputs= 1, */
+               .svhs           = NO_SVHS,
                .gpiomask       = 0x4f8a00,
                /* 0x100000: 1=MSP enabled (0=disable again)
                * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
@@ -1524,10 +1420,9 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0x947fff,
                /* tvtuner, radio,   external,internal, mute,  stereo
                * tuner, Composit, SVid, Composit-on-Svid-adapter */
-               .muxsel         = { 2, 3 ,0 ,1 },
+               .muxsel         = MUXSEL(2, 3, 0, 1),
                .tuner_type     = TUNER_MT2032,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
                .has_radio      = 1,
        },
@@ -1536,9 +1431,8 @@ struct tvcard bttv_tvcards[] = {
                /* try "insmod msp3400 simple=0" if you have
                * sound problems with this card. */
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = UNSET,
+               /* .audio_inputs= 1, */
+               .svhs           = NO_SVHS,
                .gpiomask       = 0x4f8a00,
                /* 0x100000: 1=MSP enabled (0=disable again)
                * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
@@ -1546,10 +1440,9 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0x947fff,
                /* tvtuner, radio,   external,internal, mute,  stereo
                * tuner, Composit, SVid, Composit-on-Svid-adapter */
-               .muxsel         = { 2, 3 ,0 ,1 },
+               .muxsel         = MUXSEL(2, 3, 0, 1),
                .tuner_type     = TUNER_MT2032,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
                .has_radio      = 1,
        },
@@ -1557,31 +1450,27 @@ struct tvcard bttv_tvcards[] = {
                /* Philip Blundell <pb@nexus.co.uk> */
                .name           = "Active Imaging AIMMS",
                .video_inputs   = 1,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .tuner_type     = UNSET,
+               /* .audio_inputs= 0, */
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
-               .muxsel         = { 2 },
+               .muxsel         = MUXSEL(2),
                .gpiomask       = 0
        },
        [BTTV_BOARD_PV_BT878P_PLUS] = {
                /* Tomasz Pyra <hellfire@sedez.iq.pl> */
                .name           = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)",
                .video_inputs   = 3,
-               .audio_inputs   = 4,
-               .tuner          = 0,
+               /* .audio_inputs= 4, */
                .svhs           = 2,
                .gpiomask       = 15,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 0, 11, 7 }, /* TV and Radio with same GPIO ! */
                .gpiomute       = 13,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_LG_PAL_I_FM,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_remote     = 1,
                /* GPIO wiring:
                        GPIO0: U4.A0 (hef4052bt)
@@ -1594,15 +1483,14 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_FLYVIDEO98EZ] = {
                .name           = "Lifeview FlyVideo 98EZ (capture only) LR51",
                .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
+               /* .audio_inputs= 0, */
                .svhs           = 2,
-               .muxsel         = { 2, 3, 1, 1 }, /* AV1, AV2, SVHS, CVid adapter on SVHS */
+               /* AV1, AV2, SVHS, CVid adapter on SVHS */
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .pll            = PLL_28,
                .no_msp34xx     = 1,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
        /* ---- card 0x48 ---------------------------------- */
@@ -1610,11 +1498,10 @@ struct tvcard bttv_tvcards[] = {
                /* Dariusz Kowalewski <darekk@automex.pl> */
                .name           = "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x3f,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0x01, 0x00, 0x03, 0x03 },
                .gpiomute       = 0x09,
                .needs_tvaudio  = 1,
@@ -1623,7 +1510,6 @@ struct tvcard bttv_tvcards[] = {
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .audio_mode_gpio= pvbt878p9b_audio, /* Note: not all cards have stereo */
                .has_radio      = 1,  /* Note: not all cards have radio */
                .has_remote     = 1,
@@ -1640,49 +1526,42 @@ struct tvcard bttv_tvcards[] = {
                /* you must jumper JP5 for the card to work */
                .name           = "Sensoray 311",
                .video_inputs   = 5,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
+               /* .audio_inputs= 0, */
                .svhs           = 4,
                .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 0, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0, 0),
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_RV605] = {
                /* Miguel Freitas <miguel@cetuc.puc-rio.br> */
                .name           = "RemoteVision MX (RV605)",
                .video_inputs   = 16,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .svhs           = UNSET,
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
                .gpiomask       = 0x00,
                .gpiomask2      = 0x07ff,
-               .muxsel         = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
-                               0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
+               .muxsel         = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .muxsel_hook    = rv605_muxsel,
        },
        [BTTV_BOARD_POWERCLR_MTV878] = {
                .name           = "Powercolor MTV878/ MTV878R/ MTV878F",
                .video_inputs   = 3,
-               .audio_inputs   = 2,
-               .tuner          = 0,
+               /* .audio_inputs= 2, */
                .svhs           = 2,
                .gpiomask       = 0x1C800F,  /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */
-               .muxsel         = { 2, 1, 1, },
+               .muxsel         = MUXSEL(2, 1, 1),
                .gpiomux        = { 0, 1, 2, 2 },
                .gpiomute       = 4,
                .needs_tvaudio  = 0,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
                .has_radio      = 1,
        },
@@ -1692,42 +1571,38 @@ struct tvcard bttv_tvcards[] = {
                /* Masaki Suzuki <masaki@btree.org> */
                .name           = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x140007,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 1, 2, 3 },
                .gpiomute       = 4,
                .tuner_type     = TUNER_PHILIPS_NTSC,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .audio_mode_gpio= windvr_audio,
        },
        [BTTV_BOARD_GRANDTEC_MULTI] = {
                .name           = "GrandTec Multi Capture Card (Bt878)",
                .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .svhs           = UNSET,
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
                .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_KWORLD] = {
                .name           = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
                .video_inputs   = 4,
-               .audio_inputs   = 3,
-               .tuner          = 0,
+               /* .audio_inputs= 3, */
                .svhs           = 2,
                .gpiomask       = 7,
-               .muxsel         = { 2, 3, 1, 1 },   /* Tuner, SVid, SVHS, SVid to SVHS connector */
+               /* Tuner, SVid, SVHS, SVid to SVHS connector */
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 0, 4, 4 },/* Yes, this tuner uses the same audio output for TV and FM radio!
                                                * This card lacks external Audio In, so we mute it on Ext. & Int.
                                                * The PCB can take a sbx1637/sbx1673, wiring unknown.
@@ -1741,7 +1616,6 @@ struct tvcard bttv_tvcards[] = {
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
                radio signal strength indicators work fine. */
                .has_radio      = 1,
@@ -1759,27 +1633,24 @@ struct tvcard bttv_tvcards[] = {
                /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
                .name           = "DSP Design TCVIDEO",
                .video_inputs   = 4,
-               .svhs           = UNSET,
-               .muxsel         = { 2, 3, 1, 0 },
+               .svhs           = NO_SVHS,
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
                /* ---- card 0x50 ---------------------------------- */
        [BTTV_BOARD_HAUPPAUGEPVR] = {
                .name           = "Hauppauge WinTV PVR",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
-               .muxsel         = { 2, 0, 1, 1 },
+               .muxsel         = MUXSEL(2, 0, 1, 1),
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
 
                .gpiomask       = 7,
                .gpiomux        = {7},
@@ -1787,32 +1658,28 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_GVBCTV5PCI] = {
                .name           = "IODATA GV-BCTV5/PCI",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x0f0f80,
-               .muxsel         = {2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .gpiomux        = {0x030000, 0x010000, 0, 0 },
                .gpiomute       = 0x020000,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_NTSC_M,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .audio_mode_gpio= gvbctv5pci_audio,
                .has_radio      = 1,
        },
        [BTTV_BOARD_OSPREY1x0] = {
                .name           = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
                .video_inputs   = 4,                  /* id-inputs-clock */
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
+               /* .audio_inputs= 0, */
                .svhs           = 3,
-               .muxsel         = { 3, 2, 0, 1 },
+               .muxsel         = MUXSEL(3, 2, 0, 1),
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
@@ -1820,14 +1687,12 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_OSPREY1x0_848] = {
                .name           = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
                .video_inputs   = 3,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
+               /* .audio_inputs= 0, */
                .svhs           = 2,
-               .muxsel         = { 2, 3, 1 },
+               .muxsel         = MUXSEL(2, 3, 1),
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
@@ -1837,14 +1702,12 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_OSPREY101_848] = {
                .name           = "Osprey 101 (848)", /* 0x05-40C0-C1 */
                .video_inputs   = 2,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
+               /* .audio_inputs= 0, */
                .svhs           = 1,
-               .muxsel         = { 3, 1 },
+               .muxsel         = MUXSEL(3, 1),
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
@@ -1852,14 +1715,12 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_OSPREY1x1] = {
                .name           = "Osprey 101/151",       /* 0x1(4|5)-0004-C4 */
                .video_inputs   = 1,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .svhs           = UNSET,
-               .muxsel         = { 0 },
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
+               .muxsel         = MUXSEL(0),
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
@@ -1867,14 +1728,12 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_OSPREY1x1_SVID] = {
                .name           = "Osprey 101/151 w/ svid",  /* 0x(16|17|20)-00C4-C1 */
                .video_inputs   = 2,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
+               /* .audio_inputs= 0, */
                .svhs           = 1,
-               .muxsel         = { 0, 1 },
+               .muxsel         = MUXSEL(0, 1),
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
@@ -1882,14 +1741,12 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_OSPREY2xx] = {
                .name           = "Osprey 200/201/250/251",  /* 0x1(8|9|E|F)-0004-C4 */
                .video_inputs   = 1,
-               .audio_inputs   = 1,
-               .tuner          = UNSET,
-               .svhs           = UNSET,
-               .muxsel         = { 0 },
+               /* .audio_inputs= 1, */
+               .svhs           = NO_SVHS,
+               .muxsel         = MUXSEL(0),
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
@@ -1899,14 +1756,12 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_OSPREY2x0_SVID] = {
                .name           = "Osprey 200/250",   /* 0x1(A|B)-00C4-C1 */
                .video_inputs   = 2,
-               .audio_inputs   = 1,
-               .tuner          = UNSET,
+               /* .audio_inputs= 1, */
                .svhs           = 1,
-               .muxsel         = { 0, 1 },
+               .muxsel         = MUXSEL(0, 1),
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
@@ -1914,14 +1769,12 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_OSPREY2x0] = {
                .name           = "Osprey 210/220/230",   /* 0x1(A|B)-04C0-C1 */
                .video_inputs   = 2,
-               .audio_inputs   = 1,
-               .tuner          = UNSET,
+               /* .audio_inputs= 1, */
                .svhs           = 1,
-               .muxsel         = { 2, 3 },
+               .muxsel         = MUXSEL(2, 3),
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
@@ -1929,14 +1782,12 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_OSPREY500] = {
                .name           = "Osprey 500",   /* 500 */
                .video_inputs   = 2,
-               .audio_inputs   = 1,
-               .tuner          = UNSET,
+               /* .audio_inputs= 1, */
                .svhs           = 1,
-               .muxsel         = { 2, 3 },
+               .muxsel         = MUXSEL(2, 3),
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
@@ -1944,12 +1795,10 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_OSPREY540] = {
                .name           = "Osprey 540",   /* 540 */
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = UNSET,
+               /* .audio_inputs= 1, */
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
@@ -1959,14 +1808,12 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_OSPREY2000] = {
                .name           = "Osprey 2000",  /* 2000 */
                .video_inputs   = 2,
-               .audio_inputs   = 1,
-               .tuner          = UNSET,
+               /* .audio_inputs= 1, */
                .svhs           = 1,
-               .muxsel         = { 2, 3 },
+               .muxsel         = MUXSEL(2, 3),
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,      /* must avoid, conflicts with the bt860 */
@@ -1975,14 +1822,12 @@ struct tvcard bttv_tvcards[] = {
                /* M G Berberich <berberic@forwiss.uni-passau.de> */
                .name           = "IDS Eagle",
                .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .tuner_type     = UNSET,
+               /* .audio_inputs= 0, */
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .svhs           = UNSET,
+               .svhs           = NO_SVHS,
                .gpiomask       = 0,
-               .muxsel         = { 0, 1, 2, 3 },
+               .muxsel         = MUXSEL(2, 2, 2, 2),
                .muxsel_hook    = eagle_muxsel,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
@@ -1991,16 +1836,14 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_PINNACLESAT] = {
                .name           = "Pinnacle PCTV Sat",
                .video_inputs   = 2,
-               .audio_inputs   = 0,
+               /* .audio_inputs= 0, */
                .svhs           = 1,
-               .tuner          = UNSET,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
-               .muxsel         = { 3, 1 },
+               .muxsel         = MUXSEL(3, 1),
                .pll            = PLL_28,
                .no_gpioirq     = 1,
                .has_dvb        = 1,
@@ -2008,18 +1851,16 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_FORMAC_PROTV] = {
                .name           = "Formac ProTV II (bt878)",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 3,
                .gpiomask       = 2,
                /* TV, Comp1, Composite over SVID con, SVID */
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 2, 2, 0, 0 },
                .pll            = PLL_28,
                .has_radio      = 1,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        /* sound routing:
                GPIO=0x00,0x01,0x03: mute (?)
                0x02: both TV and radio (tuner: FM1216/I)
@@ -2033,62 +1874,55 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_MACHTV] = {
                .name           = "MachTV",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = UNSET,
+               /* .audio_inputs= 1, */
+               .svhs           = NO_SVHS,
                .gpiomask       = 7,
-               .muxsel         = { 2, 3, 1, 1},
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 1, 2, 3},
                .gpiomute       = 4,
                .needs_tvaudio  = 1,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
        },
        [BTTV_BOARD_EURESYS_PICOLO] = {
                .name           = "Euresys Picolo",
                .video_inputs   = 3,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
+               /* .audio_inputs= 0, */
                .svhs           = 2,
                .gpiomask       = 0,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
-               .muxsel         = { 2, 0, 1},
+               .muxsel         = MUXSEL(2, 0, 1),
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_PV150] = {
                /* Luc Van Hoeylandt <luc@e-magic.be> */
                .name           = "ProVideo PV150", /* 0x4f */
                .video_inputs   = 2,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .svhs           = UNSET,
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
                .gpiomask       = 0,
-               .muxsel         = { 2, 3 },
+               .muxsel         = MUXSEL(2, 3),
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_AD_TVK503] = {
                /* Hiroshi Takekawa <sian@big.or.jp> */
                /* This card lacks subsystem ID */
                .name           = "AD-TVK503", /* 0x63 */
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x001e8007,
-               .muxsel         = { 2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                /*                  Tuner, Radio, external, internal, off,  on */
                .gpiomux        = { 0x08,  0x0f,  0x0a,     0x08 },
                .gpiomute       = 0x0f,
@@ -2097,7 +1931,6 @@ struct tvcard bttv_tvcards[] = {
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_NTSC,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .audio_mode_gpio= adtvk503_audio,
        },
 
@@ -2105,17 +1938,15 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_HERCULES_SM_TV] = {
                .name           = "Hercules Smart TV Stereo",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x00,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .needs_tvaudio  = 1,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                /* Notes:
                - card lacks subsystem ID
                - stereo variant w/ daughter board with tda9874a @0xb0
@@ -2129,16 +1960,15 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_PACETV] = {
                .name           = "Pace TV & Radio Card",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
-               .muxsel         = { 2, 3, 1, 1 }, /* Tuner, CVid, SVid, CVid over SVid connector */
+               /* Tuner, CVid, SVid, CVid over SVid connector */
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomask       = 0,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
                .tuner_type     = TUNER_PHILIPS_PAL_I,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_radio      = 1,
                .pll            = PLL_28,
                /* Bt878, Bt832, FI1246 tuner; no pci subsystem id
@@ -2152,27 +1982,34 @@ struct tvcard bttv_tvcards[] = {
                /* Chris Willing <chris@vislab.usyd.edu.au> */
                .name           = "IVC-200",
                .video_inputs   = 1,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .tuner_type     = UNSET,
+               /* .audio_inputs= 0, */
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .svhs           = UNSET,
+               .svhs           = NO_SVHS,
+               .gpiomask       = 0xdf,
+               .muxsel         = MUXSEL(2),
+               .pll            = PLL_28,
+       },
+       [BTTV_BOARD_IVCE8784] = {
+               .name           = "IVCE-8784",
+               .video_inputs   = 1,
+               /* .audio_inputs= 0, */
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = ADDR_UNSET,
+               .svhs           = NO_SVHS,
                .gpiomask       = 0xdf,
-               .muxsel         = { 2 },
+               .muxsel         = MUXSEL(2),
                .pll            = PLL_28,
        },
        [BTTV_BOARD_XGUARD] = {
                .name           = "Grand X-Guard / Trust 814PCI",
                .video_inputs   = 16,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .svhs           = UNSET,
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .gpiomask2      = 0xff,
-               .muxsel         = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 },
+               .muxsel         = MUXSEL(2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0),
                .muxsel_hook    = xguard_muxsel,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
@@ -2184,16 +2021,14 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_NEBULA_DIGITV] = {
                .name           = "Nebula Electronics DigiTV",
                .video_inputs   = 1,
-               .tuner          = UNSET,
-               .svhs           = UNSET,
-               .muxsel         = { 2, 3, 1, 0 },
+               .svhs           = NO_SVHS,
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_dvb        = 1,
                .has_remote     = 1,
                .gpiomask       = 0x1b,
@@ -2203,118 +2038,101 @@ struct tvcard bttv_tvcards[] = {
                /* Jorge Boncompte - DTI2 <jorge@dti2.net> */
                .name           = "ProVideo PV143",
                .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .svhs           = UNSET,
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
                .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_VD009X1_VD011_MINIDIN] = {
                /* M.Klahr@phytec.de */
                .name           = "PHYTEC VD-009-X1 VD-011 MiniDIN (bt878)",
                .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = UNSET, /* card has no tuner */
+               /* .audio_inputs= 0, */
                .svhs           = 3,
                .gpiomask       = 0x00,
-               .muxsel         = { 2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_VD009X1_VD011_COMBI] = {
                .name           = "PHYTEC VD-009-X1 VD-011 Combi (bt878)",
                .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = UNSET, /* card has no tuner */
+               /* .audio_inputs= 0, */
                .svhs           = 3,
                .gpiomask       = 0x00,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
 
                /* ---- card 0x6c ---------------------------------- */
        [BTTV_BOARD_VD009_MINIDIN] = {
                .name           = "PHYTEC VD-009 MiniDIN (bt878)",
                .video_inputs   = 10,
-               .audio_inputs   = 0,
-               .tuner          = UNSET, /* card has no tuner */
+               /* .audio_inputs= 0, */
                .svhs           = 9,
                .gpiomask       = 0x00,
-               .gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
-                                       via the upper nibble of muxsel. here: used for
-                                       xternal video-mux */
-               .muxsel         = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x00 },
+               .gpiomask2      = 0x03, /* used for external vodeo mux */
+               .muxsel         = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 0),
+               .muxsel_hook    = phytec_muxsel,
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_VD009_COMBI] = {
                .name           = "PHYTEC VD-009 Combi (bt878)",
                .video_inputs   = 10,
-               .audio_inputs   = 0,
-               .tuner          = UNSET, /* card has no tuner */
+               /* .audio_inputs= 0, */
                .svhs           = 9,
                .gpiomask       = 0x00,
-               .gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
-                                       via the upper nibble of muxsel. here: used for
-                                       xternal video-mux */
-               .muxsel         = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x01 },
+               .gpiomask2      = 0x03, /* used for external vodeo mux */
+               .muxsel         = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 1),
+               .muxsel_hook    = phytec_muxsel,
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_IVC100] = {
                .name           = "IVC-100",
                .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .tuner_type     = UNSET,
+               /* .audio_inputs= 0, */
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .svhs           = UNSET,
+               .svhs           = NO_SVHS,
                .gpiomask       = 0xdf,
-               .muxsel         = { 2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .pll            = PLL_28,
        },
        [BTTV_BOARD_IVC120] = {
                /* IVC-120G - Alan Garfield <alan@fromorbit.com> */
                .name           = "IVC-120G",
                .video_inputs   = 16,
-               .audio_inputs   = 0,    /* card has no audio */
-               .tuner          = UNSET,   /* card has no tuner */
-               .tuner_type     = UNSET,
+               /* .audio_inputs= 0, */
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .svhs           = UNSET,   /* card has no svhs */
+               .svhs           = NO_SVHS,   /* card has no svhs */
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
                .gpiomask       = 0x00,
-               .muxsel         = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-                               0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
+               .muxsel         = MUXSEL(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
                .muxsel_hook    = ivc120_muxsel,
                .pll            = PLL_28,
        },
@@ -2323,13 +2141,11 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_PC_HDTV] = {
                .name           = "pcHDTV HD-2000 TV",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
-               .muxsel         = { 2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .tuner_type     = TUNER_PHILIPS_FCV1236D,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_dvb        = 1,
        },
        [BTTV_BOARD_TWINHAN_DST] = {
@@ -2339,38 +2155,34 @@ struct tvcard bttv_tvcards[] = {
                .no_tda7432     = 1,
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .no_video       = 1,
                .has_dvb        = 1,
        },
        [BTTV_BOARD_WINFASTVC100] = {
                .name           = "Winfast VC100",
                .video_inputs   = 3,
-               .audio_inputs   = 0,
+               /* .audio_inputs= 0, */
                .svhs           = 1,
-               .tuner          = UNSET,
-               .muxsel         = { 3, 1, 1, 3 }, /* Vid In, SVid In, Vid over SVid in connector */
+               /* Vid In, SVid In, Vid over SVid in connector */
+               .muxsel         = MUXSEL(3, 1, 1, 3),
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
        },
        [BTTV_BOARD_TEV560] = {
                .name           = "Teppro TEV-560/InterVision IV-560",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 3,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 1, 1, 1, 1 },
                .needs_tvaudio  = 1,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .pll            = PLL_35,
        },
 
@@ -2378,14 +2190,12 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_SIMUS_GVC1100] = {
                .name           = "SIMUS GVC1100",
                .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .svhs           = UNSET,
-               .tuner_type     = UNSET,
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
-               .muxsel         = { 2, 2, 2, 2 },
+               .muxsel         = MUXSEL(2, 2, 2, 2),
                .gpiomask       = 0x3F,
                .muxsel_hook    = gvc1100_muxsel,
        },
@@ -2393,47 +2203,41 @@ struct tvcard bttv_tvcards[] = {
                /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */
                .name           = "NGS NGSTV+",
                .video_inputs   = 3,
-               .tuner          = 0,
                .svhs           = 2,
                .gpiomask       = 0x008007,
-               .muxsel         = { 2, 3, 0, 0 },
+               .muxsel         = MUXSEL(2, 3, 0, 0),
                .gpiomux        = { 0, 0, 0, 0 },
                .gpiomute       = 0x000003,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_remote     = 1,
        },
        [BTTV_BOARD_LMLBT4] = {
                /* http://linuxmedialabs.com */
                .name           = "LMLBT4",
                .video_inputs   = 4, /* IN1,IN2,IN3,IN4 */
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .svhs           = UNSET,
-               .muxsel         = { 2, 3, 1, 0 },
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
                .needs_tvaudio  = 0,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_TEKRAM_M205] = {
                /* Helmroos Harri <harri.helmroos@pp.inet.fi> */
                .name           = "Tekram M205 PRO",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .svhs           = 2,
                .needs_tvaudio  = 0,
                .gpiomask       = 0x68,
-               .muxsel         = { 2, 3, 1 },
+               .muxsel         = MUXSEL(2, 3, 1),
                .gpiomux        = { 0x68, 0x68, 0x61, 0x61 },
                .pll            = PLL_28,
        },
@@ -2444,18 +2248,16 @@ struct tvcard bttv_tvcards[] = {
                /* bt878 TV + FM without subsystem ID */
                .name           = "Conceptronic CONTVFMi",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x008007,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 1, 2, 2 },
                .gpiomute       = 3,
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_remote     = 1,
                .has_radio      = 1,
        },
@@ -2466,37 +2268,34 @@ struct tvcard bttv_tvcards[] = {
                /*0x79 in bttv.h*/
                .name           = "Euresys Picolo Tetra",
                .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .svhs           = UNSET,
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
                .gpiomask       = 0,
                .gpiomask2      = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
-               .muxsel         = {2,2,2,2},/*878A input is always MUX0, see above.*/
+               /*878A input is always MUX0, see above.*/
+               .muxsel         = MUXSEL(2, 2, 2, 2),
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
                .pll            = PLL_28,
                .needs_tvaudio  = 0,
                .muxsel_hook    = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_SPIRIT_TV] = {
                /* Spirit TV Tuner from http://spiritmodems.com.au */
                /* Stafford Goodsell <surge@goliath.homeunix.org> */
                .name           = "Spirit TV Tuner",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x0000000f,
-               .muxsel         = { 2, 1, 1 },
+               .muxsel         = MUXSEL(2, 1, 1),
                .gpiomux        = { 0x02, 0x00, 0x00, 0x00 },
                .tuner_type     = TUNER_TEMIC_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
        },
@@ -2505,11 +2304,9 @@ struct tvcard bttv_tvcards[] = {
                .name           = "AVerMedia AVerTV DVB-T 771",
                .video_inputs   = 2,
                .svhs           = 1,
-               .tuner          = UNSET,
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .muxsel         = { 3 , 3 },
+               .muxsel         = MUXSEL(3, 3),
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
@@ -2524,54 +2321,47 @@ struct tvcard bttv_tvcards[] = {
                /* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */
                .name           = "AverMedia AverTV DVB-T 761",
                .video_inputs   = 2,
-               .tuner          = UNSET,
                .svhs           = 1,
-               .muxsel         = { 3, 1, 2, 0 }, /* Comp0, S-Video, ?, ? */
+               .muxsel         = MUXSEL(3, 1, 2, 0), /* Comp0, S-Video, ?, ? */
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_dvb        = 1,
                .no_gpioirq     = 1,
                .has_remote     = 1,
        },
        [BTTV_BOARD_MATRIX_VISIONSQ] = {
                /* andre.schwarz@matrix-vision.de */
-               .name             = "MATRIX Vision Sigma-SQ",
-               .video_inputs     = 16,
-               .audio_inputs     = 0,
-               .tuner            = UNSET,
-               .svhs             = UNSET,
-               .gpiomask         = 0x0,
-               .muxsel           = { 2, 2, 2, 2, 2, 2, 2, 2,
-                               3, 3, 3, 3, 3, 3, 3, 3 },
-               .muxsel_hook      = sigmaSQ_muxsel,
-               .gpiomux          = { 0 },
-               .no_msp34xx       = 1,
-               .pll              = PLL_28,
-               .tuner_type       = UNSET,
-               .tuner_addr       = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
+               .name           = "MATRIX Vision Sigma-SQ",
+               .video_inputs   = 16,
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
+               .gpiomask       = 0x0,
+               .muxsel         = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3),
+               .muxsel_hook    = sigmaSQ_muxsel,
+               .gpiomux        = { 0 },
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_MATRIX_VISIONSLC] = {
                /* andre.schwarz@matrix-vision.de */
-               .name             = "MATRIX Vision Sigma-SLC",
-               .video_inputs     = 4,
-               .audio_inputs     = 0,
-               .tuner            = UNSET,
-               .svhs             = UNSET,
-               .gpiomask         = 0x0,
-               .muxsel           = { 2, 2, 2, 2 },
-               .muxsel_hook      = sigmaSLC_muxsel,
-               .gpiomux          = { 0 },
-               .no_msp34xx       = 1,
-               .pll              = PLL_28,
-               .tuner_type       = UNSET,
-               .tuner_addr       = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
+               .name           = "MATRIX Vision Sigma-SLC",
+               .video_inputs   = 4,
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
+               .gpiomask       = 0x0,
+               .muxsel         = MUXSEL(2, 2, 2, 2),
+               .muxsel_hook    = sigmaSLC_muxsel,
+               .gpiomux        = { 0 },
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = ADDR_UNSET,
        },
                /* BTTV_BOARD_APAC_VIEWCOMP */
        [BTTV_BOARD_APAC_VIEWCOMP] = {
@@ -2579,18 +2369,16 @@ struct tvcard bttv_tvcards[] = {
                /* bt878 TV + FM 0x00000000 subsystem ID */
                .name           = "APAC Viewcomp 878(AMAX)",
                .video_inputs   = 2,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = UNSET,
+               /* .audio_inputs= 1, */
+               .svhs           = NO_SVHS,
                .gpiomask       = 0xFF,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 2, 0, 0, 0 },
                .gpiomute       = 10,
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_remote     = 1,   /* miniremote works, see ir-kbd-gpio.c */
                .has_radio      = 1,   /* not every card has radio */
        },
@@ -2599,46 +2387,40 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_DVICO_DVBT_LITE] = {
                /* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
                .name           = "DViCO FusionHDTV DVB-T Lite",
-               .tuner          = UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
                .pll            = PLL_28,
                .no_video       = 1,
                .has_dvb        = 1,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_VGEAR_MYVCD] = {
                /* Steven <photon38@pchome.com.tw> */
                .name           = "V-Gear MyVCD",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x3f,
-               .muxsel         = {2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .gpiomux        = {0x31, 0x31, 0x31, 0x31 },
                .gpiomute       = 0x31,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_NTSC_M,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_radio      = 0,
        },
        [BTTV_BOARD_SUPER_TV] = {
                /* Rick C <cryptdragoon@gmail.com> */
                .name           = "Super TV Tuner",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
-               .muxsel         = { 2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .tuner_type     = TUNER_PHILIPS_NTSC,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .gpiomask       = 0x008007,
                .gpiomux        = { 0, 0x000001,0,0 },
                .needs_tvaudio  = 1,
@@ -2648,17 +2430,15 @@ struct tvcard bttv_tvcards[] = {
                /* Chris Fanning <video4linux@haydon.net> */
                .name           = "Tibet Systems 'Progress DVR' CS16",
                .video_inputs   = 16,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .svhs           = UNSET,
-               .muxsel         = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
+               .muxsel         = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),
                .pll            = PLL_28,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .muxsel_hook    = tibetCS16_muxsel,
        },
        [BTTV_BOARD_KODICOM_4400R] = {
@@ -2675,12 +2455,10 @@ struct tvcard bttv_tvcards[] = {
                */
                .name           = "Kodicom 4400R (master)",
                .video_inputs   = 16,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .tuner_type     = UNSET,
+               /* .audio_inputs= 0, */
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .svhs           = UNSET,
+               .svhs           = NO_SVHS,
                /* GPIO bits 0-9 used for analog switch:
                *   00 - 03:    camera selector
                *   04 - 06:    channel (controller) selector
@@ -2691,7 +2469,7 @@ struct tvcard bttv_tvcards[] = {
                */
                .gpiomask       = 0x0003ff,
                .no_gpioirq     = 1,
-               .muxsel         = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+               .muxsel         = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
                .pll            = PLL_28,
                .no_msp34xx     = 1,
                .no_tda7432     = 1,
@@ -2707,15 +2485,13 @@ struct tvcard bttv_tvcards[] = {
                */
                .name           = "Kodicom 4400R (slave)",
                .video_inputs   = 16,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .tuner_type     = UNSET,
+               /* .audio_inputs= 0, */
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .svhs           = UNSET,
+               .svhs           = NO_SVHS,
                .gpiomask       = 0x010000,
                .no_gpioirq     = 1,
-               .muxsel         = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+               .muxsel         = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
                .pll            = PLL_28,
                .no_msp34xx     = 1,
                .no_tda7432     = 1,
@@ -2728,27 +2504,23 @@ struct tvcard bttv_tvcards[] = {
                /* Adlink RTV24 with special unlock codes */
                .name           = "Adlink RTV24",
                .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
-               .muxsel         = { 2, 3, 1, 0 },
+               .muxsel         = MUXSEL(2, 3, 1, 0),
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
        },
                /* ---- card 0x87---------------------------------- */
        [BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE] = {
                /* Michael Krufky <mkrufky@m1k.net> */
                .name           = "DViCO FusionHDTV 5 Lite",
-               .tuner          = 0,
                .tuner_type     = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .video_inputs   = 3,
-               .audio_inputs   = 1,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
-               .muxsel         = { 2, 3, 1 },
+               .muxsel         = MUXSEL(2, 3, 1),
                .gpiomask       = 0x00e00007,
                .gpiomux        = { 0x00400005, 0, 0x00000001, 0 },
                .gpiomute       = 0x00c00007,
@@ -2762,75 +2534,68 @@ struct tvcard bttv_tvcards[] = {
                /* Mauro Carvalho Chehab <mchehab@infradead.org> */
                .name           = "Acorp Y878F",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x01fe00,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0x001e00, 0, 0x018000, 0x014000 },
                .gpiomute       = 0x002000,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_YMEC_TVF66T5_B_DFF,
                .tuner_addr     = 0xc1 >>1,
-               .radio_addr     = 0xc1 >>1,
                .has_radio      = 1,
        },
                /* ---- card 0x89 ---------------------------------- */
        [BTTV_BOARD_CONCEPTRONIC_CTVFMI2] = {
                .name           = "Conceptronic CTVFMi v2",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x001c0007,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 1, 2, 2 },
                .gpiomute       = 3,
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
                .tuner_type     = TUNER_TENA_9533_DI,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_remote     = 1,
                .has_radio      = 1,
        },
                /* ---- card 0x8a ---------------------------------- */
        [BTTV_BOARD_PV_BT878P_2E] = {
-               .name          = "Prolink Pixelview PV-BT878P+ (Rev.2E)",
-               .video_inputs  = 5,
-               .audio_inputs  = 1,
-               .tuner         = 0,
-               .svhs          = 3,
-               .gpiomask      = 0x01fe00,
-               .muxsel        = { 2,3,1,1,-1 },
-               .digital_mode  = DIGITAL_MODE_CAMERA,
-               .gpiomux       = { 0x00400, 0x10400, 0x04400, 0x80000 },
-               .gpiomute      = 0x12400,
-               .no_msp34xx    = 1,
-               .pll           = PLL_28,
-               .tuner_type    = TUNER_LG_PAL_FM,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_remote    = 1,
+               .name           = "Prolink Pixelview PV-BT878P+ (Rev.2E)",
+               .video_inputs   = 5,
+               /* .audio_inputs= 1, */
+               .svhs           = 3,
+               .has_dig_in     = 1,
+               .gpiomask       = 0x01fe00,
+               .muxsel         = MUXSEL(2, 3, 1, 1, 0), /* in 4 is digital */
+               /* .digital_mode= DIGITAL_MODE_CAMERA, */
+               .gpiomux        = { 0x00400, 0x10400, 0x04400, 0x80000 },
+               .gpiomute       = 0x12400,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_LG_PAL_FM,
+               .tuner_addr     = ADDR_UNSET,
+               .has_remote     = 1,
        },
                /* ---- card 0x8b ---------------------------------- */
        [BTTV_BOARD_PV_M4900] = {
                /* Sérgio Fortier <sergiofortier@yahoo.com.br> */
                .name           = "Prolink PixelView PlayTV MPEG2 PV-M4900",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x3f,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0x21, 0x20, 0x24, 0x2c },
                .gpiomute       = 0x29,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_YMEC_TVF_5533MF,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .has_radio      = 1,
                .has_remote     = 1,
        },
@@ -2850,17 +2615,15 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_OSPREY440]  = {
                .name           = "Osprey 440",
                .video_inputs   = 4,
-               .audio_inputs   = 2, /* this is meaningless */
-               .tuner          = UNSET,
-               .svhs           = UNSET,
-               .muxsel         = { 2, 3, 0, 1 }, /* 3,0,1 are guesses */
+               /* .audio_inputs= 2, */
+               .svhs           = NO_SVHS,
+               .muxsel         = MUXSEL(2, 3, 0, 1), /* 3,0,1 are guesses */
                .gpiomask       = 0x303,
                .gpiomute       = 0x000, /* int + 32kHz */
                .gpiomux        = { 0, 0, 0x000, 0x100},
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
@@ -2869,28 +2632,25 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_ASOUND_SKYEYE] = {
                .name           = "Asound Skyeye PCTV",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 15,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 2, 0, 0, 0 },
                .gpiomute       = 1,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_NTSC,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
                /* ---- card 0x8e ---------------------------------- */
        [BTTV_BOARD_SABRENT_TVFM] = {
                .name           = "Sabrent TV-FM (bttv version)",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x108007,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 100000, 100002, 100002, 100000 },
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
@@ -2904,17 +2664,15 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_HAUPPAUGE_IMPACTVCB] = {
                .name           = "Hauppauge ImpactVCB (bt878)",
                .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .svhs           = UNSET,
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
                .gpiomask       = 0x0f, /* old: 7 */
-               .muxsel         = { 0, 1, 3, 2 }, /* Composite 0-3 */
+               .muxsel         = MUXSEL(0, 1, 3, 2), /* Composite 0-3 */
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_MACHTV_MAGICTV] = {
                /* Julian Calaby <julian.calaby@gmail.com>
@@ -2926,16 +2684,14 @@ struct tvcard bttv_tvcards[] = {
 
                .name           = "MagicTV", /* rebranded MachTV */
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 7,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 1, 2, 3 },
                .gpiomute       = 4,
                .tuner_type     = TUNER_TEMIC_4009FR5_PAL,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
                .has_radio      = 1,
                .has_remote     = 1,
@@ -2943,36 +2699,30 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_SSAI_SECURITY] = {
                .name           = "SSAI Security Video Interface",
                .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
-               .svhs           = UNSET,
-               .muxsel         = { 0, 1, 2, 3 },
-               .tuner_type     = UNSET,
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
+               .muxsel         = MUXSEL(0, 1, 2, 3),
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_SSAI_ULTRASOUND] = {
                .name           = "SSAI Ultrasound Video Interface",
                .video_inputs   = 2,
-               .audio_inputs   = 0,
-               .tuner          = UNSET,
+               /* .audio_inputs= 0, */
                .svhs           = 1,
-               .muxsel         = { 2, 0, 1, 3 },
-               .tuner_type     = UNSET,
+               .muxsel         = MUXSEL(2, 0, 1, 3),
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        /* ---- card 0x94---------------------------------- */
        [BTTV_BOARD_DVICO_FUSIONHDTV_2] = {
                .name           = "DViCO FusionHDTV 2",
-               .tuner          = 0,
                .tuner_type     = TUNER_PHILIPS_FCV1236D,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .video_inputs   = 3,
-               .audio_inputs   = 1,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
-               .muxsel         = { 2, 3, 1 },
+               .muxsel         = MUXSEL(2, 3, 1),
                .gpiomask       = 0x00e00007,
                .gpiomux        = { 0x00400005, 0, 0x00000001, 0 },
                .gpiomute       = 0x00c00007,
@@ -2984,36 +2734,31 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_TYPHOON_TVTUNERPCI] = {
                .name           = "Typhoon TV-Tuner PCI (50684)",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x3014f,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0x20001,0x10001, 0, 0 },
                .gpiomute       = 10,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL_I,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_GEOVISION_GV600] = {
                /* emhn@usb.ve */
-               .name             = "Geovision GV-600",
-               .video_inputs     = 16,
-               .audio_inputs     = 0,
-               .tuner            = UNSET,
-               .svhs             = UNSET,
-               .gpiomask         = 0x0,
-               .muxsel           = { 2, 2, 2, 2, 2, 2, 2, 2,
-                                     2, 2, 2, 2, 2, 2, 2, 2 },
-               .muxsel_hook      = geovision_muxsel,
-               .gpiomux          = { 0 },
-               .no_msp34xx       = 1,
-               .pll              = PLL_28,
-               .tuner_type       = UNSET,
-               .tuner_addr       = ADDR_UNSET,
-               .radio_addr       = ADDR_UNSET,
+               .name           = "Geovision GV-600",
+               .video_inputs   = 16,
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
+               .gpiomask       = 0x0,
+               .muxsel         = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),
+               .muxsel_hook    = geovision_muxsel,
+               .gpiomux        = { 0 },
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = ADDR_UNSET,
        },
        [BTTV_BOARD_KOZUMI_KTV_01C] = {
                /* Mauro Lacy <mauro@lacy.com.ar>
@@ -3021,17 +2766,15 @@ struct tvcard bttv_tvcards[] = {
 
                .name           = "Kozumi KTV-01C",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                .gpiomask       = 0x008007,
-               .muxsel         = { 2, 3, 1, 1 },
+               .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 0, 1, 2, 2 }, /* CONTVFMi */
                .gpiomute       = 3, /* CONTVFMi */
                .needs_tvaudio  = 0,
                .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* TCL MK3 */
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
                .has_radio      = 1,
                .has_remote     = 1,
@@ -3041,8 +2784,7 @@ struct tvcard bttv_tvcards[] = {
                   Mauro Carvalho Chehab <mchehab@infradead.org */
                .name           = "Encore ENL TV-FM-2",
                .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
+               /* .audio_inputs= 1, */
                .svhs           = 2,
                /* bit 6          -> IR disabled
                   bit 18/17 = 00 -> mute
@@ -3051,12 +2793,11 @@ struct tvcard bttv_tvcards[] = {
                               11 -> internal audio input
                 */
                .gpiomask       = 0x060040,
-               .muxsel         = { 2, 3, 3 },
+               .muxsel         = MUXSEL(2, 3, 3),
                .gpiomux        = { 0x60000, 0x60000, 0x20000, 0x20000 },
                .gpiomute       = 0,
                .tuner_type     = TUNER_TCL_MF02GIP_5N,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
                .has_radio      = 1,
                .has_remote     = 1,
@@ -3065,50 +2806,111 @@ struct tvcard bttv_tvcards[] = {
                /* D.Heer@Phytec.de */
                .name           = "PHYTEC VD-012 (bt878)",
                .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = UNSET, /* card has no tuner */
-               .svhs           = UNSET, /* card has no s-video */
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
                .gpiomask       = 0x00,
-               .muxsel         = { 0, 2, 3, 1 },
+               .muxsel         = MUXSEL(0, 2, 3, 1),
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
                [BTTV_BOARD_VD012_X1] = {
                /* D.Heer@Phytec.de */
                .name           = "PHYTEC VD-012-X1 (bt878)",
                .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = UNSET, /* card has no tuner */
+               /* .audio_inputs= 0, */
                .svhs           = 3,
                .gpiomask       = 0x00,
-               .muxsel         = { 2, 3, 1 },
+               .muxsel         = MUXSEL(2, 3, 1),
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
        },
                [BTTV_BOARD_VD012_X2] = {
                /* D.Heer@Phytec.de */
                .name           = "PHYTEC VD-012-X2 (bt878)",
                .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = UNSET, /* card has no tuner */
+               /* .audio_inputs= 0, */
                .svhs           = 3,
                .gpiomask       = 0x00,
-               .muxsel         = { 3, 2, 1 },
+               .muxsel         = MUXSEL(3, 2, 1),
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       }
+       },
+               [BTTV_BOARD_GEOVISION_GV800S] = {
+               /* Bruno Christo <bchristo@inf.ufsm.br>
+                *
+                * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
+                *      1 audio input  per BT878A = 4 audio inputs
+                *      4 video inputs per BT878A = 16 video inputs
+                * This is the first BT878A chip of the GV-800(S). It's the
+                * "master" chip and it controls the video inputs through an
+                * analog multiplexer (a CD22M3494) via some GPIO pins. The
+                * slaves should use card type 0x9e (following this one).
+                * There is a EEPROM on the card which is currently not handled.
+                * The audio input is not working yet.
+                */
+               .name           = "Geovision GV-800(S) (master)",
+               .video_inputs   = 4,
+               /* .audio_inputs= 1, */
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = ADDR_UNSET,
+               .svhs           = NO_SVHS,
+               .gpiomask       = 0xf107f,
+               .no_gpioirq     = 1,
+               .muxsel         = MUXSEL(2, 2, 2, 2),
+               .pll            = PLL_28,
+               .no_msp34xx     = 1,
+               .no_tda7432     = 1,
+               .no_tda9875     = 1,
+               .muxsel_hook    = gv800s_muxsel,
+       },
+               [BTTV_BOARD_GEOVISION_GV800S_SL] = {
+               /* Bruno Christo <bchristo@inf.ufsm.br>
+                *
+                * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
+                *      1 audio input  per BT878A = 4 audio inputs
+                *      4 video inputs per BT878A = 16 video inputs
+                * The 3 other BT878A chips are "slave" chips of the GV-800(S)
+                * and should use this card type.
+                * The audio input is not working yet.
+                */
+               .name           = "Geovision GV-800(S) (slave)",
+               .video_inputs   = 4,
+               /* .audio_inputs= 1, */
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = ADDR_UNSET,
+               .svhs           = NO_SVHS,
+               .gpiomask       = 0x00,
+               .no_gpioirq     = 1,
+               .muxsel         = MUXSEL(2, 2, 2, 2),
+               .pll            = PLL_28,
+               .no_msp34xx     = 1,
+               .no_tda7432     = 1,
+               .no_tda9875     = 1,
+               .muxsel_hook    = gv800s_muxsel,
+       },
+       [BTTV_BOARD_PV183] = {
+               .name           = "ProVideo PV183", /* 0x9f */
+               .video_inputs   = 2,
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
+               .gpiomask       = 0,
+               .muxsel         = MUXSEL(2, 3),
+               .gpiomux        = { 0 },
+               .needs_tvaudio  = 0,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = ADDR_UNSET,
+       },
 };
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3152,7 +2954,7 @@ void __devinit bttv_idcard(struct bttv *btv)
                               btv->c.nr, btv->cardid & 0xffff,
                               (btv->cardid >> 16) & 0xffff);
                        printk(KERN_DEBUG "please mail id, board name and "
-                              "the correct card= insmod option to video4linux-list@redhat.com\n");
+                              "the correct card= insmod option to linux-media@vger.kernel.org\n");
                }
        }
 
@@ -3403,8 +3205,7 @@ static void init_ids_eagle(struct bttv *btv)
  * has its own multiplexer */
 static void eagle_muxsel(struct bttv *btv, unsigned int input)
 {
-       btaor((2)<<5, ~(3<<5), BT848_IFORM);
-       gpio_bits(3,bttv_tvcards[btv->c.type].muxsel[input&7]);
+       gpio_bits(3, input & 3);
 
        /* composite */
        /* set chroma ADC to sleep */
@@ -3523,6 +3324,17 @@ void __devinit bttv_init_card1(struct bttv *btv)
 /* initialization part two -- after registering i2c bus */
 void __devinit bttv_init_card2(struct bttv *btv)
 {
+       static const unsigned short tvaudio_addrs[] = {
+               I2C_ADDR_TDA8425   >> 1,
+               I2C_ADDR_TEA6300   >> 1,
+               I2C_ADDR_TEA6420   >> 1,
+               I2C_ADDR_TDA9840   >> 1,
+               I2C_ADDR_TDA985x_L >> 1,
+               I2C_ADDR_TDA985x_H >> 1,
+               I2C_ADDR_TDA9874   >> 1,
+               I2C_ADDR_PIC16C54  >> 1,
+               I2C_CLIENT_END
+       };
        int addr=ADDR_UNSET;
 
        btv->tuner_type = UNSET;
@@ -3629,6 +3441,9 @@ void __devinit bttv_init_card2(struct bttv *btv)
        case BTTV_BOARD_KODICOM_4400R:
                kodicom4400r_init(btv);
                break;
+       case BTTV_BOARD_GEOVISION_GV800S:
+               gv800s_init(btv);
+               break;
        }
 
        /* pll configuration */
@@ -3670,13 +3485,12 @@ void __devinit bttv_init_card2(struct bttv *btv)
                addr = bttv_tvcards[btv->c.type].tuner_addr;
 
        if (UNSET != bttv_tvcards[btv->c.type].tuner_type)
-               if(UNSET == btv->tuner_type)
+               if (UNSET == btv->tuner_type)
                        btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
        if (UNSET != tuner[btv->c.nr])
                btv->tuner_type = tuner[btv->c.nr];
 
-       if (btv->tuner_type == TUNER_ABSENT ||
-           bttv_tvcards[btv->c.type].tuner == UNSET)
+       if (btv->tuner_type == TUNER_ABSENT)
                printk(KERN_INFO "bttv%d: tuner absent\n", btv->c.nr);
        else if(btv->tuner_type == UNSET)
                printk(KERN_WARNING "bttv%d: tuner type unset\n", btv->c.nr);
@@ -3684,14 +3498,35 @@ void __devinit bttv_init_card2(struct bttv *btv)
                printk(KERN_INFO "bttv%d: tuner type=%d\n", btv->c.nr,
                       btv->tuner_type);
 
-       if (btv->tuner_type != UNSET) {
+       if (autoload != UNSET) {
+               printk(KERN_WARNING "bttv%d: the autoload option is obsolete.\n", btv->c.nr);
+               printk(KERN_WARNING "bttv%d: use option msp3400, tda7432 or tvaudio to\n", btv->c.nr);
+               printk(KERN_WARNING "bttv%d: override which audio module should be used.\n", btv->c.nr);
+       }
+
+       if (UNSET == btv->tuner_type)
+               btv->tuner_type = TUNER_ABSENT;
+
+       if (btv->tuner_type != TUNER_ABSENT) {
                struct tuner_setup tun_setup;
 
+               /* Load tuner module before issuing tuner config call! */
+               if (bttv_tvcards[btv->c.type].has_radio)
+                       v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+                               "tuner", "tuner", v4l2_i2c_tuner_addrs(ADDRS_RADIO));
+               v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap, "tuner",
+                               "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+               v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap, "tuner",
+                               "tuner", v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
+
                tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
                tun_setup.type = btv->tuner_type;
                tun_setup.addr = addr;
 
-               bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
+               if (bttv_tvcards[btv->c.type].has_radio)
+                       tun_setup.mode_mask |= T_RADIO;
+
+               bttv_call_all(btv, tuner, s_type_addr, &tun_setup);
        }
 
        if (btv->tda9887_conf) {
@@ -3700,10 +3535,13 @@ void __devinit bttv_init_card2(struct bttv *btv)
                tda9887_cfg.tuner = TUNER_TDA9887;
                tda9887_cfg.priv = &btv->tda9887_conf;
 
-               bttv_call_i2c_clients(btv, TUNER_SET_CONFIG, &tda9887_cfg);
+               bttv_call_all(btv, tuner, s_config, &tda9887_cfg);
        }
 
-       btv->svhs = bttv_tvcards[btv->c.type].svhs;
+       btv->dig = bttv_tvcards[btv->c.type].has_dig_in ?
+                  bttv_tvcards[btv->c.type].video_inputs - 1 : UNSET;
+       btv->svhs = bttv_tvcards[btv->c.type].svhs == NO_SVHS ?
+                   UNSET : bttv_tvcards[btv->c.type].svhs;
        if (svhs[btv->c.nr] != UNSET)
                btv->svhs = svhs[btv->c.nr];
        if (remote[btv->c.nr] != UNSET)
@@ -3720,34 +3558,127 @@ void __devinit bttv_init_card2(struct bttv *btv)
        if (bttv_tvcards[btv->c.type].audio_mode_gpio)
                btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio;
 
-       if (!autoload)
-               return;
-
-       if (bttv_tvcards[btv->c.type].tuner == UNSET)
+       if (btv->tuner_type == TUNER_ABSENT)
                return;  /* no tuner or related drivers to load */
 
+       if (btv->has_saa6588 || saa6588[btv->c.nr]) {
+               /* Probe for RDS receiver chip */
+               static const unsigned short addrs[] = {
+                       0x20 >> 1,
+                       0x22 >> 1,
+                       I2C_CLIENT_END
+               };
+               struct v4l2_subdev *sd;
+
+               sd = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+                               "saa6588", "saa6588", addrs);
+               btv->has_saa6588 = (sd != NULL);
+       }
+
        /* try to detect audio/fader chips */
-       if (!bttv_tvcards[btv->c.type].no_msp34xx &&
-           bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx") >=0)
-               request_module("msp3400");
 
-       if (bttv_tvcards[btv->c.type].msp34xx_alt &&
-           bttv_I2CRead(btv, I2C_ADDR_MSP3400_ALT, "MSP34xx (alternate address)") >=0)
-               request_module("msp3400");
+       /* First check if the user specified the audio chip via a module
+          option. */
+
+       switch (audiodev[btv->c.nr]) {
+       case -1:
+               return; /* do not load any audio module */
+
+       case 0: /* autodetect */
+               break;
+
+       case 1: {
+               /* The user specified that we should probe for msp3400 */
+               static const unsigned short addrs[] = {
+                       I2C_ADDR_MSP3400 >> 1,
+                       I2C_ADDR_MSP3400_ALT >> 1,
+                       I2C_CLIENT_END
+               };
+
+               btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+                               "msp3400", "msp3400", addrs);
+               if (btv->sd_msp34xx)
+                       return;
+               goto no_audio;
+       }
+
+       case 2: {
+               /* The user specified that we should probe for tda7432 */
+               static const unsigned short addrs[] = {
+                       I2C_ADDR_TDA7432 >> 1,
+                       I2C_CLIENT_END
+               };
+
+               if (v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+                               "tda7432", "tda7432", addrs))
+                       return;
+               goto no_audio;
+       }
+
+       case 3: {
+               /* The user specified that we should probe for tvaudio */
+               btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+                               "tvaudio", "tvaudio", tvaudio_addrs);
+               if (btv->sd_tvaudio)
+                       return;
+               goto no_audio;
+       }
+
+       default:
+               printk(KERN_WARNING "bttv%d: unknown audiodev value!\n",
+                       btv->c.nr);
+               return;
+       }
 
-       if (!bttv_tvcards[btv->c.type].no_tda9875 &&
-           bttv_I2CRead(btv, I2C_ADDR_TDA9875, "TDA9875") >=0)
-               request_module("tda9875");
+       /* There were no overrides, so now we try to discover this through the
+          card definition */
+
+       /* probe for msp3400 first: this driver can detect whether or not
+          it really is a msp3400, so it will return NULL when the device
+          found is really something else (e.g. a tea6300). */
+       if (!bttv_tvcards[btv->c.type].no_msp34xx) {
+               static const unsigned short addrs[] = {
+                       I2C_ADDR_MSP3400 >> 1,
+                       I2C_CLIENT_END
+               };
+
+               btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+                               "msp3400", "msp3400", addrs);
+       } else if (bttv_tvcards[btv->c.type].msp34xx_alt) {
+               static const unsigned short addrs[] = {
+                       I2C_ADDR_MSP3400_ALT >> 1,
+                       I2C_CLIENT_END
+               };
+
+               btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+                               "msp3400", "msp3400", addrs);
+       }
 
-       if (!bttv_tvcards[btv->c.type].no_tda7432 &&
-           bttv_I2CRead(btv, I2C_ADDR_TDA7432, "TDA7432") >=0)
-               request_module("tda7432");
+       /* If we found a msp34xx, then we're done. */
+       if (btv->sd_msp34xx)
+               return;
 
-       if (bttv_tvcards[btv->c.type].needs_tvaudio)
-               request_module("tvaudio");
+       /* it might also be a tda7432. */
+       if (!bttv_tvcards[btv->c.type].no_tda7432) {
+               static const unsigned short addrs[] = {
+                       I2C_ADDR_TDA7432 >> 1,
+                       I2C_CLIENT_END
+               };
 
-       if (btv->tuner_type != UNSET && btv->tuner_type != TUNER_ABSENT)
-               request_module("tuner");
+               if (v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+                               "tda7432", "tda7432", addrs))
+                       return;
+       }
+
+       /* Now see if we can find one of the tvaudio devices. */
+       btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+                       "tvaudio", "tvaudio", tvaudio_addrs);
+       if (btv->sd_tvaudio)
+               return;
+
+no_audio:
+       printk(KERN_WARNING "bttv%d: audio absent, no audio device found!\n",
+                       btv->c.nr);
 }
 
 
@@ -3819,6 +3750,7 @@ static int terratec_active_radio_upgrade(struct bttv *btv)
                printk("bttv%d: Terratec Active Radio Upgrade found.\n",
                       btv->c.nr);
                btv->has_radio    = 1;
+               btv->has_saa6588  = 1;
                btv->has_matchbox = 1;
        } else {
                btv->has_radio    = 0;
@@ -4067,27 +3999,26 @@ static void __devinit avermedia_eeprom(struct bttv *btv)
               btv->has_remote ? "yes" : "no");
 }
 
-/* used on Voodoo TV/FM (Voodoo 200), S0 wired to 0x10000 */
-void bttv_tda9880_setnorm(struct bttv *btv, int norm)
+/*
+ * For Voodoo TV/FM and Voodoo 200.  These cards' tuners use a TDA9880
+ * analog demod, which is not I2C controlled like the newer and more common
+ * TDA9887 series.  Instead is has two tri-state input pins, S0 and S1,
+ * that control the IF for the video and audio.  Apparently, bttv GPIO
+ * 0x10000 is connected to S0.  S0 low selects a 38.9 MHz VIF for B/G/D/K/I
+ * (i.e., PAL) while high selects 45.75 MHz for M/N (i.e., NTSC).
+ */
+u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits)
 {
-       /* fix up our card entry */
-       if(norm==V4L2_STD_NTSC) {
-               bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
-               bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff;
-               bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
-               bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x957fff;
-               dprintk("bttv_tda9880_setnorm to NTSC\n");
-       }
-       else {
-               bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
-               bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x947fff;
-               bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
-               bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x947fff;
-               dprintk("bttv_tda9880_setnorm to PAL\n");
+
+       if (btv->audio == TVAUDIO_INPUT_TUNER) {
+               if (bttv_tvnorms[btv->tvnorm].v4l2_id & V4L2_STD_MN)
+                       gpiobits |= 0x10000;
+               else
+                       gpiobits &= ~0x10000;
        }
-       /* set GPIO according */
-       gpio_bits(bttv_tvcards[btv->c.type].gpiomask,
-                 bttv_tvcards[btv->c.type].gpiomux[btv->audio]);
+
+       gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpiobits);
+       return gpiobits;
 }
 
 
@@ -4463,6 +4394,11 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq)
  */
 static void rv605_muxsel(struct bttv *btv, unsigned int input)
 {
+       static const u8 muxgpio[] = { 0x3, 0x1, 0x2, 0x4, 0xf, 0x7, 0xe, 0x0,
+                                     0xd, 0xb, 0xc, 0x6, 0x9, 0x5, 0x8, 0xa };
+
+       gpio_bits(0x07f, muxgpio[input]);
+
        /* reset all conections */
        gpio_bits(0x200,0x200);
        mdelay(1);
@@ -4470,7 +4406,6 @@ static void rv605_muxsel(struct bttv *btv, unsigned int input)
        mdelay(1);
 
        /* create a new connection */
-       gpio_bits(0x480,0x080);
        gpio_bits(0x480,0x480);
        mdelay(1);
        gpio_bits(0x480,0x080);
@@ -4729,8 +4664,7 @@ static void ivc120_muxsel(struct bttv *btv, unsigned int input)
        bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x02,
                      ((matrix == 2) ? 0x03 : 0x00), 1);  /* 9-12 */
 
-       /* Selects MUX0 for input on the 878 */
-       btaor((0)<<5, ~(3<<5), BT848_IFORM);
+       /* 878's MUX0 is already selected for input via muxsel values */
 }
 
 
@@ -4814,6 +4748,132 @@ static void PXC200_muxsel(struct bttv *btv, unsigned int input)
        printk(KERN_DEBUG "bttv%d: setting input channel to:%d\n", btv->c.nr,(int)mux);
 }
 
+static void phytec_muxsel(struct bttv *btv, unsigned int input)
+{
+       unsigned int mux = input % 4;
+
+       if (input == btv->svhs)
+               mux = 0;
+
+       gpio_bits(0x3, mux);
+}
+
+/*
+ * GeoVision GV-800(S) functions
+ * Bruno Christo <bchristo@inf.ufsm.br>
+*/
+
+/* This is a function to control the analog switch, which determines which
+ * camera is routed to which controller.  The switch comprises an X-address
+ * (gpio bits 0-3, representing the camera, ranging from 0-15), and a
+ * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3).
+ * A data value (gpio bit 18) of '1' enables the switch, and '0' disables
+ * the switch.  A STROBE bit (gpio bit 17) latches the data value into the
+ * specified address. There is also a chip select (gpio bit 16).
+ * The idea is to set the address and chip select together, bring
+ * STROBE high, write the data, and finally bring STROBE back to low.
+ */
+static void gv800s_write(struct bttv *btv,
+                        unsigned char xaddr,
+                        unsigned char yaddr,
+                        unsigned char data) {
+       /* On the "master" 878A:
+       * GPIO bits 0-9 are used for the analog switch:
+       *   00 - 03:    camera selector
+       *   04 - 06:    878A (controller) selector
+       *   16:         cselect
+       *   17:         strobe
+       *   18:         data (1->on, 0->off)
+       *   19:         reset
+       */
+       const u32 ADDRESS = ((xaddr&0xf) | (yaddr&3)<<4);
+       const u32 CSELECT = 1<<16;
+       const u32 STROBE = 1<<17;
+       const u32 DATA = data<<18;
+
+       gpio_bits(0x1007f, ADDRESS | CSELECT);  /* write ADDRESS and CSELECT */
+       gpio_bits(0x20000, STROBE);             /* STROBE high */
+       gpio_bits(0x40000, DATA);               /* write DATA */
+       gpio_bits(0x20000, ~STROBE);            /* STROBE low */
+}
+
+/*
+ * GeoVision GV-800(S) muxsel
+ *
+ * Each of the 4 cards (controllers) use this function.
+ * The controller using this function selects the input through the GPIO pins
+ * of the "master" card. A pointer to this card is stored in master[btv->c.nr].
+ *
+ * The parameter 'input' is the requested camera number (0-4) on the controller.
+ * The map array has the address of each input. Note that the addresses in the
+ * array are in the sequence the original GeoVision driver uses, that is, set
+ * every controller to input 0, then to input 1, 2, 3, repeat. This means that
+ * the physical "camera 1" connector corresponds to controller 0 input 0,
+ * "camera 2" corresponds to controller 1 input 0, and so on.
+ *
+ * After getting the input address, the function then writes the appropriate
+ * data to the analog switch, and housekeeps the local copy of the switch
+ * information.
+ */
+static void gv800s_muxsel(struct bttv *btv, unsigned int input)
+{
+       struct bttv *mctlr;
+       char *sw_status;
+       int xaddr, yaddr;
+       static unsigned int map[4][4] = { { 0x0, 0x4, 0xa, 0x6 },
+                                         { 0x1, 0x5, 0xb, 0x7 },
+                                         { 0x2, 0x8, 0xc, 0xe },
+                                         { 0x3, 0x9, 0xd, 0xf } };
+       input = input%4;
+       mctlr = master[btv->c.nr];
+       if (mctlr == NULL) {
+               /* do nothing until the "master" is detected */
+               return;
+       }
+       yaddr = (btv->c.nr - mctlr->c.nr) & 3;
+       sw_status = (char *)(&mctlr->mbox_we);
+       xaddr = map[yaddr][input] & 0xf;
+
+       /* Check if the controller/camera pair has changed, ignore otherwise */
+       if (sw_status[yaddr] != xaddr) {
+               /* disable the old switch, enable the new one and save status */
+               gv800s_write(mctlr, sw_status[yaddr], yaddr, 0);
+               sw_status[yaddr] = xaddr;
+               gv800s_write(mctlr, xaddr, yaddr, 1);
+       }
+}
+
+/* GeoVision GV-800(S) "master" chip init */
+static void gv800s_init(struct bttv *btv)
+{
+       char *sw_status = (char *)(&btv->mbox_we);
+       int ix;
+
+       gpio_inout(0xf107f, 0xf107f);
+       gpio_write(1<<19); /* reset the analog MUX */
+       gpio_write(0);
+
+       /* Preset camera 0 to the 4 controllers */
+       for (ix = 0; ix < 4; ix++) {
+               sw_status[ix] = ix;
+               gv800s_write(btv, ix, ix, 1);
+       }
+
+       /* Inputs on the "master" controller need this brightness fix */
+       bttv_I2CWrite(btv, 0x18, 0x5, 0x90, 1);
+
+       if (btv->c.nr > BTTV_MAX-4)
+               return;
+       /*
+        * Store the "master" controller pointer in the master
+        * array for later use in the muxsel function.
+        */
+       master[btv->c.nr]   = btv;
+       master[btv->c.nr+1] = btv;
+       master[btv->c.nr+2] = btv;
+       master[btv->c.nr+3] = btv;
+}
+
 /* ----------------------------------------------------------------------- */
 /* motherboard chipset specific stuff                                      */
 
index c71f394fc0ead807e04b166b2a300c4bf2978326..7a8ca0d8356f68ecb4fe228f93dd966bdc0e0905 100644 (file)
@@ -58,7 +58,7 @@
 
 
 unsigned int bttv_num;                 /* number of Bt848s in use */
-struct bttv bttvs[BTTV_MAX];
+struct bttv *bttvs[BTTV_MAX];
 
 unsigned int bttv_debug;
 unsigned int bttv_verbose = 1;
@@ -167,7 +167,7 @@ static ssize_t show_card(struct device *cd,
                         struct device_attribute *attr, char *buf)
 {
        struct video_device *vfd = container_of(cd, struct video_device, dev);
-       struct bttv *btv = dev_get_drvdata(vfd->parent);
+       struct bttv *btv = video_get_drvdata(vfd);
        return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
 }
 static DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
@@ -1040,7 +1040,7 @@ static void bt848A_set_timing(struct bttv *btv)
        int table_idx = bttv_tvnorms[btv->tvnorm].sram;
        int fsc       = bttv_tvnorms[btv->tvnorm].Fsc;
 
-       if (UNSET == bttv_tvcards[btv->c.type].muxsel[btv->input]) {
+       if (btv->input == btv->dig) {
                dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
                        btv->c.nr,table_idx);
 
@@ -1142,7 +1142,7 @@ video_mux(struct bttv *btv, unsigned int input)
                btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
                btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
        }
-       mux = bttv_tvcards[btv->c.type].muxsel[input] & 3;
+       mux = bttv_muxsel(btv, input);
        btaor(mux<<5, ~(3<<5), BT848_IFORM);
        dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
                btv->c.nr,input,mux);
@@ -1163,7 +1163,6 @@ audio_mux(struct bttv *btv, int input, int mute)
 {
        int gpio_val, signal;
        struct v4l2_control ctrl;
-       struct i2c_client *c;
 
        gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
                   bttv_tvcards[btv->c.type].gpiomask);
@@ -1180,7 +1179,16 @@ audio_mux(struct bttv *btv, int input, int mute)
        else
                gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];
 
-       gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
+       switch (btv->c.type) {
+       case BTTV_BOARD_VOODOOTV_FM:
+       case BTTV_BOARD_VOODOOTV_200:
+               gpio_val = bttv_tda9880_setnorm(btv, gpio_val);
+               break;
+
+       default:
+               gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
+       }
+
        if (bttv_gpio)
                bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]);
        if (in_interrupt())
@@ -1188,9 +1196,8 @@ audio_mux(struct bttv *btv, int input, int mute)
 
        ctrl.id = V4L2_CID_AUDIO_MUTE;
        ctrl.value = btv->mute;
-       bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, &ctrl);
-       c = btv->i2c_msp34xx_client;
-       if (c) {
+       bttv_call_all(btv, core, s_ctrl, &ctrl);
+       if (btv->sd_msp34xx) {
                struct v4l2_routing route;
 
                /* Note: the inputs tuner/radio/extern/intern are translated
@@ -1229,15 +1236,14 @@ audio_mux(struct bttv *btv, int input, int mute)
                        break;
                }
                route.output = MSP_OUTPUT_DEFAULT;
-               c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+               v4l2_subdev_call(btv->sd_msp34xx, audio, s_routing, &route);
        }
-       c = btv->i2c_tvaudio_client;
-       if (c) {
+       if (btv->sd_tvaudio) {
                struct v4l2_routing route;
 
                route.input = input;
                route.output = 0;
-               c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+               v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing, &route);
        }
        return 0;
 }
@@ -1277,7 +1283,7 @@ bttv_crop_calc_limits(struct bttv_crop *c)
 }
 
 static void
-bttv_crop_reset(struct bttv_crop *c, int norm)
+bttv_crop_reset(struct bttv_crop *c, unsigned int norm)
 {
        c->rect = bttv_tvnorms[norm].cropcap.defrect;
        bttv_crop_calc_limits(c);
@@ -1290,16 +1296,13 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
        const struct bttv_tvnorm *tvnorm;
        v4l2_std_id id;
 
-       if (norm < 0 || norm >= BTTV_TVNORMS)
-               return -EINVAL;
+       BUG_ON(norm >= BTTV_TVNORMS);
+       BUG_ON(btv->tvnorm >= BTTV_TVNORMS);
 
        tvnorm = &bttv_tvnorms[norm];
 
-       if (btv->tvnorm < 0 ||
-           btv->tvnorm >= BTTV_TVNORMS ||
-           0 != memcmp(&bttv_tvnorms[btv->tvnorm].cropcap,
-                       &tvnorm->cropcap,
-                       sizeof (tvnorm->cropcap))) {
+       if (!memcmp(&bttv_tvnorms[btv->tvnorm].cropcap, &tvnorm->cropcap,
+                   sizeof (tvnorm->cropcap))) {
                bttv_crop_reset(&btv->crop[0], norm);
                btv->crop[1] = btv->crop[0]; /* current = default */
 
@@ -1322,11 +1325,11 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
        switch (btv->c.type) {
        case BTTV_BOARD_VOODOOTV_FM:
        case BTTV_BOARD_VOODOOTV_200:
-               bttv_tda9880_setnorm(btv,norm);
+               bttv_tda9880_setnorm(btv, gpio_read());
                break;
        }
        id = tvnorm->v4l2_id;
-       bttv_call_i2c_clients(btv, VIDIOC_S_STD, &id);
+       bttv_call_all(btv, tuner, s_std, id);
 
        return 0;
 }
@@ -1350,8 +1353,8 @@ set_input(struct bttv *btv, unsigned int input, unsigned int norm)
        } else {
                video_mux(btv,input);
        }
-       audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
-                      TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
+       audio_input(btv, (btv->tuner_type != TUNER_ABSENT && input == 0) ?
+                        TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN);
        set_tvnorm(btv, norm);
 }
 
@@ -1470,7 +1473,7 @@ static int bttv_g_ctrl(struct file *file, void *priv,
        case V4L2_CID_AUDIO_BALANCE:
        case V4L2_CID_AUDIO_BASS:
        case V4L2_CID_AUDIO_TREBLE:
-               bttv_call_i2c_clients(btv, VIDIOC_G_CTRL, c);
+               bttv_call_all(btv, core, g_ctrl, c);
                break;
 
        case V4L2_CID_PRIVATE_CHROMA_AGC:
@@ -1544,12 +1547,12 @@ static int bttv_s_ctrl(struct file *file, void *f,
                if (btv->volume_gpio)
                        btv->volume_gpio(btv, c->value);
 
-               bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
+               bttv_call_all(btv, core, s_ctrl, c);
                break;
        case V4L2_CID_AUDIO_BALANCE:
        case V4L2_CID_AUDIO_BASS:
        case V4L2_CID_AUDIO_TREBLE:
-               bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
+               bttv_call_all(btv, core, s_ctrl, c);
                break;
 
        case V4L2_CID_PRIVATE_CHROMA_AGC:
@@ -1888,20 +1891,15 @@ static int bttv_enum_input(struct file *file, void *priv,
 {
        struct bttv_fh *fh = priv;
        struct bttv *btv = fh->btv;
-       unsigned int n;
-
-       n = i->index;
+       int n;
 
-       if (n >= bttv_tvcards[btv->c.type].video_inputs)
+       if (i->index >= bttv_tvcards[btv->c.type].video_inputs)
                return -EINVAL;
 
-       memset(i, 0, sizeof(*i));
-
-       i->index    = n;
        i->type     = V4L2_INPUT_TYPE_CAMERA;
        i->audioset = 1;
 
-       if (i->index == bttv_tvcards[btv->c.type].tuner) {
+       if (btv->tuner_type != TUNER_ABSENT && i->index == 0) {
                sprintf(i->name, "Television");
                i->type  = V4L2_INPUT_TYPE_TUNER;
                i->tuner = 0;
@@ -1965,14 +1963,14 @@ static int bttv_s_tuner(struct file *file, void *priv,
        if (0 != err)
                return err;
 
-       if (UNSET == bttv_tvcards[btv->c.type].tuner)
+       if (btv->tuner_type == TUNER_ABSENT)
                return -EINVAL;
 
        if (0 != t->index)
                return -EINVAL;
 
        mutex_lock(&btv->lock);
-       bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
+       bttv_call_all(btv, tuner, s_tuner, t);
 
        if (btv->audio_mode_gpio)
                btv->audio_mode_gpio(btv, t, 1);
@@ -2017,7 +2015,7 @@ static int bttv_s_frequency(struct file *file, void *priv,
                return -EINVAL;
        mutex_lock(&btv->lock);
        btv->freq = f->frequency;
-       bttv_call_i2c_clients(btv, VIDIOC_S_FREQUENCY, f);
+       bttv_call_all(btv, tuner, s_frequency, f);
        if (btv->has_matchbox && btv->radio_user)
                tea5757_set_freq(btv, btv->freq);
        mutex_unlock(&btv->lock);
@@ -2031,7 +2029,7 @@ static int bttv_log_status(struct file *file, void *f)
 
        printk(KERN_INFO "bttv%d: ========  START STATUS CARD #%d  ========\n",
                        btv->c.nr, btv->c.nr);
-       bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
+       bttv_call_all(btv, core, log_status);
        printk(KERN_INFO "bttv%d: ========  END STATUS CARD   #%d  ========\n",
                        btv->c.nr, btv->c.nr);
        return 0;
@@ -2659,8 +2657,7 @@ static int bttv_querycap(struct file *file, void  *priv,
        if (no_overlay <= 0)
                cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
 
-       if (bttv_tvcards[btv->c.type].tuner != UNSET &&
-           bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
+       if (btv->tuner_type != TUNER_ABSENT)
                cap->capabilities |= V4L2_CAP_TUNER;
        return 0;
 }
@@ -2927,13 +2924,9 @@ static int bttv_g_parm(struct file *file, void *f,
 {
        struct bttv_fh *fh = f;
        struct bttv *btv = fh->btv;
-       struct v4l2_standard s;
 
-       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
-                                bttv_tvnorms[btv->tvnorm].name);
-       parm->parm.capture.timeperframe = s.frameperiod;
+       v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id,
+                                   &parm->parm.capture.timeperframe);
        return 0;
 }
 
@@ -2943,15 +2936,14 @@ static int bttv_g_tuner(struct file *file, void *priv,
        struct bttv_fh *fh = priv;
        struct bttv *btv = fh->btv;
 
-       if (UNSET == bttv_tvcards[btv->c.type].tuner)
+       if (btv->tuner_type == TUNER_ABSENT)
                return -EINVAL;
        if (0 != t->index)
                return -EINVAL;
 
        mutex_lock(&btv->lock);
-       memset(t, 0, sizeof(*t));
        t->rxsubchans = V4L2_TUNER_SUB_MONO;
-       bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
+       bttv_call_all(btv, tuner, g_tuner, t);
        strcpy(t->name, "Television");
        t->capability = V4L2_TUNER_CAP_NORM;
        t->type       = V4L2_TUNER_ANALOG_TV;
@@ -3212,29 +3204,19 @@ err:
 static int bttv_open(struct file *file)
 {
        int minor = video_devdata(file)->minor;
-       struct bttv *btv = NULL;
+       struct bttv *btv = video_drvdata(file);
        struct bttv_fh *fh;
        enum v4l2_buf_type type = 0;
-       unsigned int i;
 
        dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
 
        lock_kernel();
-       for (i = 0; i < bttv_num; i++) {
-               if (bttvs[i].video_dev &&
-                   bttvs[i].video_dev->minor == minor) {
-                       btv = &bttvs[i];
-                       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                       break;
-               }
-               if (bttvs[i].vbi_dev &&
-                   bttvs[i].vbi_dev->minor == minor) {
-                       btv = &bttvs[i];
-                       type = V4L2_BUF_TYPE_VBI_CAPTURE;
-                       break;
-               }
-       }
-       if (NULL == btv) {
+       if (btv->video_dev->minor == minor) {
+               type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       } else if (btv->vbi_dev->minor == minor) {
+               type = V4L2_BUF_TYPE_VBI_CAPTURE;
+       } else {
+               WARN_ON(1);
                unlock_kernel();
                return -ENODEV;
        }
@@ -3424,20 +3406,14 @@ static struct video_device bttv_video_template = {
 static int radio_open(struct file *file)
 {
        int minor = video_devdata(file)->minor;
-       struct bttv *btv = NULL;
+       struct bttv *btv = video_drvdata(file);
        struct bttv_fh *fh;
-       unsigned int i;
 
        dprintk("bttv: open minor=%d\n",minor);
 
        lock_kernel();
-       for (i = 0; i < bttv_num; i++) {
-               if (bttvs[i].radio_dev && bttvs[i].radio_dev->minor == minor) {
-                       btv = &bttvs[i];
-                       break;
-               }
-       }
-       if (NULL == btv) {
+       WARN_ON(btv->radio_dev && btv->radio_dev->minor != minor);
+       if (!btv->radio_dev || btv->radio_dev->minor != minor) {
                unlock_kernel();
                return -ENODEV;
        }
@@ -3458,7 +3434,7 @@ static int radio_open(struct file *file)
 
        btv->radio_user++;
 
-       bttv_call_i2c_clients(btv,AUDC_SET_RADIO,NULL);
+       bttv_call_all(btv, tuner, s_radio);
        audio_input(btv,TVAUDIO_INPUT_RADIO);
 
        mutex_unlock(&btv->lock);
@@ -3478,7 +3454,7 @@ static int radio_release(struct file *file)
 
        btv->radio_user--;
 
-       bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
+       bttv_call_all(btv, core, ioctl, RDS_CMD_CLOSE, &cmd);
 
        return 0;
 }
@@ -3503,16 +3479,15 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
        struct bttv_fh *fh = priv;
        struct bttv *btv = fh->btv;
 
-       if (UNSET == bttv_tvcards[btv->c.type].tuner)
+       if (btv->tuner_type == TUNER_ABSENT)
                return -EINVAL;
        if (0 != t->index)
                return -EINVAL;
        mutex_lock(&btv->lock);
-       memset(t, 0, sizeof(*t));
        strcpy(t->name, "Radio");
        t->type = V4L2_TUNER_RADIO;
 
-       bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
+       bttv_call_all(btv, tuner, g_tuner, t);
 
        if (btv->audio_mode_gpio)
                btv->audio_mode_gpio(btv, t, 0);
@@ -3554,7 +3529,7 @@ static int radio_s_tuner(struct file *file, void *priv,
        if (0 != t->index)
                return -EINVAL;
 
-       bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
+       bttv_call_all(btv, tuner, g_tuner, t);
        return 0;
 }
 
@@ -3615,7 +3590,7 @@ static ssize_t radio_read(struct file *file, char __user *data,
        cmd.instance = file;
        cmd.result = -ENODEV;
 
-       bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd);
+       bttv_call_all(btv, core, ioctl, RDS_CMD_READ, &cmd);
 
        return cmd.result;
 }
@@ -3628,7 +3603,7 @@ static unsigned int radio_poll(struct file *file, poll_table *wait)
        cmd.instance = file;
        cmd.event_list = wait;
        cmd.result = -ENODEV;
-       bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd);
+       bttv_call_all(btv, core, ioctl, RDS_CMD_POLL, &cmd);
 
        return cmd.result;
 }
@@ -3712,14 +3687,14 @@ static void bttv_risc_disasm(struct bttv *btv,
        unsigned int i,j,n;
 
        printk("%s: risc disasm: %p [dma=0x%08lx]\n",
-              btv->c.name, risc->cpu, (unsigned long)risc->dma);
+              btv->c.v4l2_dev.name, risc->cpu, (unsigned long)risc->dma);
        for (i = 0; i < (risc->size >> 2); i += n) {
-               printk("%s:   0x%lx: ", btv->c.name,
+               printk("%s:   0x%lx: ", btv->c.v4l2_dev.name,
                       (unsigned long)(risc->dma + (i<<2)));
                n = bttv_risc_decode(le32_to_cpu(risc->cpu[i]));
                for (j = 1; j < n; j++)
                        printk("%s:   0x%lx: 0x%08x [ arg #%d ]\n",
-                              btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
+                              btv->c.v4l2_dev.name, (unsigned long)(risc->dma + ((i+j)<<2)),
                               risc->cpu[i+j], j);
                if (0 == risc->cpu[i])
                        break;
@@ -4195,9 +4170,10 @@ static struct video_device *vdev_init(struct bttv *btv,
                return NULL;
        *vfd = *template;
        vfd->minor   = -1;
-       vfd->parent  = &btv->c.pci->dev;
+       vfd->v4l2_dev = &btv->c.v4l2_dev;
        vfd->release = video_device_release;
        vfd->debug   = bttv_debug;
+       video_set_drvdata(vfd, btv);
        snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
                 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
                 type_name, bttv_tvcards[btv->c.type].name);
@@ -4307,10 +4283,14 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        if (bttv_num == BTTV_MAX)
                return -ENOMEM;
        printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
-       btv=&bttvs[bttv_num];
-       memset(btv,0,sizeof(*btv));
+       bttvs[bttv_num] = btv = kzalloc(sizeof(*btv), GFP_KERNEL);
+       if (btv == NULL) {
+               printk(KERN_ERR "bttv: out of memory.\n");
+               return -ENOMEM;
+       }
        btv->c.nr  = bttv_num;
-       sprintf(btv->c.name,"bttv%d",btv->c.nr);
+       snprintf(btv->c.v4l2_dev.name, sizeof(btv->c.v4l2_dev.name),
+                       "bttv%d", btv->c.nr);
 
        /* initialize structs / fill in defaults */
        mutex_init(&btv->lock);
@@ -4347,7 +4327,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        }
        if (!request_mem_region(pci_resource_start(dev,0),
                                pci_resource_len(dev,0),
-                               btv->c.name)) {
+                               btv->c.v4l2_dev.name)) {
                printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n",
                       btv->c.nr,
                       (unsigned long long)pci_resource_start(dev,0));
@@ -4355,7 +4335,12 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        }
        pci_set_master(dev);
        pci_set_command(dev);
-       pci_set_drvdata(dev,btv);
+
+       result = v4l2_device_register(&dev->dev, &btv->c.v4l2_dev);
+       if (result < 0) {
+               printk(KERN_WARNING "bttv%d: v4l2_device_register() failed\n", btv->c.nr);
+               goto fail0;
+       }
 
        pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
        pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
@@ -4379,7 +4364,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        /* disable irqs, register irq handler */
        btwrite(0, BT848_INT_MASK);
        result = request_irq(btv->c.pci->irq, bttv_irq,
-                            IRQF_SHARED | IRQF_DISABLED,btv->c.name,(void *)btv);
+           IRQF_SHARED | IRQF_DISABLED, btv->c.v4l2_dev.name, (void *)btv);
        if (result < 0) {
                printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
                       bttv_num,btv->c.pci->irq);
@@ -4463,21 +4448,24 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        bttv_num++;
        return 0;
 
- fail2:
+fail2:
        free_irq(btv->c.pci->irq,btv);
 
- fail1:
+fail1:
+       v4l2_device_unregister(&btv->c.v4l2_dev);
+
+fail0:
        if (btv->bt848_mmio)
                iounmap(btv->bt848_mmio);
        release_mem_region(pci_resource_start(btv->c.pci,0),
                           pci_resource_len(btv->c.pci,0));
-       pci_set_drvdata(dev,NULL);
        return result;
 }
 
 static void __devexit bttv_remove(struct pci_dev *pci_dev)
 {
-       struct bttv *btv = pci_get_drvdata(pci_dev);
+       struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+       struct bttv *btv = to_bttv(v4l2_dev);
 
        if (bttv_verbose)
                printk("bttv%d: unloading\n",btv->c.nr);
@@ -4511,14 +4499,18 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
        release_mem_region(pci_resource_start(btv->c.pci,0),
                           pci_resource_len(btv->c.pci,0));
 
-       pci_set_drvdata(pci_dev, NULL);
+       v4l2_device_unregister(&btv->c.v4l2_dev);
+       bttvs[btv->c.nr] = NULL;
+       kfree(btv);
+
        return;
 }
 
 #ifdef CONFIG_PM
 static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
 {
-       struct bttv *btv = pci_get_drvdata(pci_dev);
+       struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+       struct bttv *btv = to_bttv(v4l2_dev);
        struct bttv_buffer_set idle;
        unsigned long flags;
 
@@ -4553,7 +4545,8 @@ static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
 
 static int bttv_resume(struct pci_dev *pci_dev)
 {
-       struct bttv *btv = pci_get_drvdata(pci_dev);
+       struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+       struct bttv *btv = to_bttv(v4l2_dev);
        unsigned long flags;
        int err;
 
index bcd2cd240a165d96f189c5e66e93028cc00735e1..a99d92fac3dc4e7731cfa9b2349886ac926b6d6c 100644 (file)
@@ -36,8 +36,6 @@
 #include <linux/jiffies.h>
 #include <asm/io.h>
 
-static int attach_inform(struct i2c_client *client);
-
 static int i2c_debug;
 static int i2c_hw;
 static int i2c_scan;
@@ -231,7 +229,8 @@ bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
 
 static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
 {
-       struct bttv *btv = i2c_get_adapdata(i2c_adap);
+       struct v4l2_device *v4l2_dev = i2c_get_adapdata(i2c_adap);
+       struct bttv *btv = to_bttv(v4l2_dev);
        int retval = 0;
        int i;
 
@@ -265,52 +264,6 @@ static const struct i2c_algorithm bttv_algo = {
 /* ----------------------------------------------------------------------- */
 /* I2C functions - common stuff                                            */
 
-static int attach_inform(struct i2c_client *client)
-{
-       struct bttv *btv = i2c_get_adapdata(client->adapter);
-       int addr=ADDR_UNSET;
-
-
-       if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr)
-               addr = bttv_tvcards[btv->c.type].tuner_addr;
-
-
-       if (bttv_debug)
-               printk(KERN_DEBUG "bttv%d: %s i2c attach [addr=0x%x,client=%s]\n",
-                       btv->c.nr, client->driver->driver.name, client->addr,
-                       client->name);
-       if (!client->driver->command)
-               return 0;
-
-       if (client->driver->id == I2C_DRIVERID_MSP3400)
-               btv->i2c_msp34xx_client = client;
-       if (client->driver->id == I2C_DRIVERID_TVAUDIO)
-               btv->i2c_tvaudio_client = client;
-       if (btv->tuner_type != UNSET) {
-               struct tuner_setup tun_setup;
-
-               if ((addr==ADDR_UNSET) ||
-                               (addr==client->addr)) {
-
-                       tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV | T_RADIO;
-                       tun_setup.type = btv->tuner_type;
-                       tun_setup.addr = addr;
-                       bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
-               }
-
-       }
-
-       return 0;
-}
-
-void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
-{
-       if (0 != btv->i2c_rc)
-               return;
-       i2c_clients_command(&btv->c.i2c_adap, cmd, arg);
-}
-
-
 /* read I2C */
 int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
 {
@@ -417,21 +370,15 @@ int __devinit init_bttv_i2c(struct bttv *btv)
                btv->c.i2c_adap.algo_data = &btv->i2c_algo;
        }
        btv->c.i2c_adap.owner = THIS_MODULE;
-       btv->c.i2c_adap.class = I2C_CLASS_TV_ANALOG;
-       btv->c.i2c_adap.client_register = attach_inform;
 
        btv->c.i2c_adap.dev.parent = &btv->c.pci->dev;
        snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name),
                 "bt%d #%d [%s]", btv->id, btv->c.nr,
                 btv->use_i2c_hw ? "hw" : "sw");
 
-       i2c_set_adapdata(&btv->c.i2c_adap, btv);
+       i2c_set_adapdata(&btv->c.i2c_adap, &btv->c.v4l2_dev);
        btv->i2c_client.adapter = &btv->c.i2c_adap;
 
-       if (bttv_tvcards[btv->c.type].no_video)
-               btv->c.i2c_adap.class &= ~I2C_CLASS_TV_ANALOG;
-       if (bttv_tvcards[btv->c.type].has_dvb)
-               btv->c.i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
 
        if (btv->use_i2c_hw) {
                btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap);
@@ -441,7 +388,7 @@ int __devinit init_bttv_i2c(struct bttv *btv)
                btv->i2c_rc = i2c_bit_add_bus(&btv->c.i2c_adap);
        }
        if (0 == btv->i2c_rc && i2c_scan)
-               do_i2c_scan(btv->c.name,&btv->i2c_client);
+               do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client);
        return btv->i2c_rc;
 }
 
index ecf07988cd33ab83c18e7fa4a605b2db3d56d76b..a6a540dc9e4b526c81c68c782a36db7ecab253fe 100644 (file)
@@ -47,7 +47,10 @@ struct pci_dev* bttv_get_pcidev(unsigned int card)
 {
        if (card >= bttv_num)
                return NULL;
-       return bttvs[card].c.pci;
+       if (!bttvs[card])
+               return NULL;
+
+       return bttvs[card]->c.pci;
 }
 
 
@@ -59,7 +62,10 @@ int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
                return -EINVAL;
        }
 
-       btv = &bttvs[card];
+       btv = bttvs[card];
+       if (!btv)
+               return -ENODEV;
+
        gpio_inout(mask,data);
        if (bttv_gpio)
                bttv_gpio_tracking(btv,"extern enable");
@@ -74,7 +80,9 @@ int bttv_read_gpio(unsigned int card, unsigned long *data)
                return -EINVAL;
        }
 
-       btv = &bttvs[card];
+       btv = bttvs[card];
+       if (!btv)
+               return -ENODEV;
 
        if(btv->shutdown) {
                return -ENODEV;
@@ -94,7 +102,9 @@ int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data)
                return -EINVAL;
        }
 
-       btv = &bttvs[card];
+       btv = bttvs[card];
+       if (!btv)
+               return -ENODEV;
 
 /* prior setting BT848_GPIO_REG_INP is (probably) not needed
    because direct input is set on init */
index 5b1b8e4c78baf602b3c84511b506db451a0f5aad..d16af28363798d45a19336b3d621836b9b9dcb85 100644 (file)
@@ -341,7 +341,7 @@ bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
        int totalwidth   = tvnorm->totalwidth;
        int scaledtwidth = tvnorm->scaledtwidth;
 
-       if (bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
+       if (btv->input == btv->dig) {
                swidth       = 720;
                totalwidth   = 858;
                scaledtwidth = 858;
@@ -391,7 +391,7 @@ bttv_calc_geo               (struct bttv *                  btv,
             && crop->width == tvnorm->cropcap.defrect.width
             && crop->height == tvnorm->cropcap.defrect.height
             && width <= tvnorm->swidth /* see PAL-Nc et al */)
-           || bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
+           || btv->input == btv->dig) {
                bttv_calc_geo_old(btv, geo, width, height,
                                  both_fields, tvnorm);
                return;
index 6819e21a3773ea747a7ef8e5762076d097f9d008..e79a402fa6cd576897f042c44b75a5e0985fe386 100644 (file)
@@ -411,7 +411,7 @@ int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
        return 0;
 }
 
-void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm)
+void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm)
 {
        const struct bttv_tvnorm *tvnorm;
        unsigned int real_samples_per_line;
index 529bf6cf634d9c76c039ac51320f30ac55eae8a1..3d36daf206f37a3c05f3b8466d6a3e2c237de5be 100644 (file)
@@ -14,8 +14,9 @@
 #ifndef _BTTV_H_
 #define _BTTV_H_
 
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/i2c.h>
+#include <media/v4l2-device.h>
 #include <media/ir-common.h>
 #include <media/ir-kbd-i2c.h>
 #include <media/i2c-addr.h>
 #define BTTV_BOARD_VD012                  0x99
 #define BTTV_BOARD_VD012_X1               0x9a
 #define BTTV_BOARD_VD012_X2               0x9b
+#define BTTV_BOARD_IVCE8784               0x9c
+#define BTTV_BOARD_GEOVISION_GV800S       0x9d
+#define BTTV_BOARD_GEOVISION_GV800S_SL    0x9e
+#define BTTV_BOARD_PV183                   0x9f
 
 
 /* more card-specific defines */
 #define WINVIEW_PT2254_DATA 0x20
 #define WINVIEW_PT2254_STROBE 0x80
 
-/* digital_mode */
-#define DIGITAL_MODE_VIDEO 1
-#define DIGITAL_MODE_CAMERA 2
-
 struct bttv_core {
        /* device structs */
+       struct v4l2_device   v4l2_dev;
        struct pci_dev       *pci;
        struct i2c_adapter   i2c_adap;
        struct list_head     subs;     /* struct bttv_sub_device */
@@ -204,59 +206,79 @@ struct bttv_core {
        /* device config */
        unsigned int         nr;       /* dev nr (for printk("bttv%d: ...");  */
        unsigned int         type;     /* card type (pointer into tvcards[])  */
-       char                 name[8];  /* dev name */
 };
 
 struct bttv;
 
-
-struct tvcard
-{
+struct tvcard {
        char *name;
-       unsigned int video_inputs;
-       unsigned int audio_inputs;
-       unsigned int tuner;
-       unsigned int svhs;
-       unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO
+       void (*volume_gpio)(struct bttv *btv, __u16 volume);
+       void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+       void (*muxsel_hook)(struct bttv *btv, unsigned int input);
+
+       /* MUX bits for each input, two bits per input starting with the LSB */
+       u32 muxsel; /* Use MUXSEL() to set */
+
        u32 gpiomask;
-       u32 muxsel[16];
        u32 gpiomux[4];  /* Tuner, Radio, external, internal */
        u32 gpiomute;    /* GPIO mute setting */
        u32 gpiomask2;   /* GPIO MUX mask */
 
+       unsigned int tuner_type;
+       u8 tuner_addr;
+       u8 video_inputs;        /* Number of inputs */
+       unsigned int svhs:4;    /* Which input is s-video */
+#define NO_SVHS        15
+       unsigned int pll:2;
+#define PLL_NONE 0
+#define PLL_28   1
+#define PLL_35   2
+
        /* i2c audio flags */
        unsigned int no_msp34xx:1;
        unsigned int no_tda9875:1;
        unsigned int no_tda7432:1;
        unsigned int needs_tvaudio:1;
        unsigned int msp34xx_alt:1;
+       /* Note: currently no card definition needs to mark the presence
+          of a RDS saa6588 chip. If this is ever needed, then add a new
+          'has_saa6588' bit here. */
 
-       /* flag: video pci function is unused */
-       unsigned int no_video:1;
+       unsigned int no_video:1; /* video pci function is unused */
        unsigned int has_dvb:1;
        unsigned int has_remote:1;
+       unsigned int has_radio:1;
+       unsigned int has_dig_in:1; /* Has digital input (always last input) */
        unsigned int no_gpioirq:1;
-
-       /* other settings */
-       unsigned int pll;
-#define PLL_NONE 0
-#define PLL_28   1
-#define PLL_35   2
-
-       unsigned int tuner_type;
-       unsigned int tuner_addr;
-       unsigned int radio_addr;
-
-       unsigned int has_radio;
-
-       void (*volume_gpio)(struct bttv *btv, __u16 volume);
-       void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set);
-
-       void (*muxsel_hook)(struct bttv *btv, unsigned int input);
 };
 
 extern struct tvcard bttv_tvcards[];
 
+/*
+ * This bit of cpp voodoo is used to create a macro with a variable number of
+ * arguments (1 to 16).  It will pack each argument into a word two bits at a
+ * time.  It can't be a function because it needs to be compile time constant to
+ * initialize structures.  Since each argument must fit in two bits, it's ok
+ * that they are changed to octal.  One should not use hex number, macros, or
+ * anything else with this macro.  Just use plain integers from 0 to 3.
+ */
+#define _MUXSELf(a)            0##a << 30
+#define _MUXSELe(a, b...)      0##a << 28 | _MUXSELf(b)
+#define _MUXSELd(a, b...)      0##a << 26 | _MUXSELe(b)
+#define _MUXSELc(a, b...)      0##a << 24 | _MUXSELd(b)
+#define _MUXSELb(a, b...)      0##a << 22 | _MUXSELc(b)
+#define _MUXSELa(a, b...)      0##a << 20 | _MUXSELb(b)
+#define _MUXSEL9(a, b...)      0##a << 18 | _MUXSELa(b)
+#define _MUXSEL8(a, b...)      0##a << 16 | _MUXSEL9(b)
+#define _MUXSEL7(a, b...)      0##a << 14 | _MUXSEL8(b)
+#define _MUXSEL6(a, b...)      0##a << 12 | _MUXSEL7(b)
+#define _MUXSEL5(a, b...)      0##a << 10 | _MUXSEL6(b)
+#define _MUXSEL4(a, b...)      0##a << 8  | _MUXSEL5(b)
+#define _MUXSEL3(a, b...)      0##a << 6  | _MUXSEL4(b)
+#define _MUXSEL2(a, b...)      0##a << 4  | _MUXSEL3(b)
+#define _MUXSEL1(a, b...)      0##a << 2  | _MUXSEL2(b)
+#define MUXSEL(a, b...)                (a | _MUXSEL1(b))
+
 /* identification / initialization of the card */
 extern void bttv_idcard(struct bttv *btv);
 extern void bttv_init_card1(struct bttv *btv);
@@ -264,7 +286,7 @@ extern void bttv_init_card2(struct bttv *btv);
 
 /* card-specific funtions */
 extern void tea5757_set_freq(struct bttv *btv, unsigned short freq);
-extern void bttv_tda9880_setnorm(struct bttv *btv, int norm);
+extern u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits);
 
 /* extra tweaks for some chipsets */
 extern void bttv_check_chipset(void);
@@ -336,7 +358,9 @@ void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits);
 /* ---------------------------------------------------------- */
 /* i2c                                                        */
 
-extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg);
+#define bttv_call_all(btv, o, f, args...) \
+       v4l2_device_call_all(&btv->c.v4l2_dev, 0, o, f, ##args)
+
 extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for);
 extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
                         unsigned char b2, int both);
index 199a4d225caf6f4ec534b6477077b2280564d3fa..96498489199d25590cc7cd02700202df76eb0826 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/wait.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
-#include <linux/videodev.h>
 #include <linux/pci.h>
 #include <linux/input.h>
 #include <linux/mutex.h>
@@ -135,7 +134,7 @@ struct bttv_buffer {
 
        /* bttv specific */
        const struct bttv_format   *fmt;
-       int                        tvnorm;
+       unsigned int               tvnorm;
        int                        btformat;
        int                        btswap;
        struct bttv_geometry       geo;
@@ -154,7 +153,7 @@ struct bttv_buffer_set {
 };
 
 struct bttv_overlay {
-       int                    tvnorm;
+       unsigned int           tvnorm;
        struct v4l2_rect       w;
        enum v4l2_field        field;
        struct v4l2_clip       *clips;
@@ -174,7 +173,7 @@ struct bttv_vbi_fmt {
 };
 
 /* bttv-vbi.c */
-void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm);
+void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm);
 
 struct bttv_crop {
        /* A cropping rectangle in struct bttv_tvnorm.cropcap units. */
@@ -329,7 +328,8 @@ struct bttv {
        unsigned int cardid;   /* pci subsystem id (bt878 based ones) */
        unsigned int tuner_type;  /* tuner chip type */
        unsigned int tda9887_conf;
-       unsigned int svhs;
+       unsigned int svhs, dig;
+       unsigned int has_saa6588:1;
        struct bttv_pll_info pll;
        int triton1;
        int gpioirq;
@@ -353,8 +353,8 @@ struct bttv {
        int                        i2c_state, i2c_rc;
        int                        i2c_done;
        wait_queue_head_t          i2c_queue;
-       struct i2c_client         *i2c_msp34xx_client;
-       struct i2c_client         *i2c_tvaudio_client;
+       struct v4l2_subdev        *sd_msp34xx;
+       struct v4l2_subdev        *sd_tvaudio;
 
        /* video4linux (1) */
        struct video_device *video_dev;
@@ -378,7 +378,8 @@ struct bttv {
        unsigned int audio;
        unsigned int mute;
        unsigned long freq;
-       int tvnorm,hue,contrast,bright,saturation;
+       unsigned int tvnorm;
+       int hue, contrast, bright, saturation;
        struct v4l2_framebuffer fbuf;
        unsigned int field_count;
 
@@ -458,10 +459,21 @@ struct bttv {
        __s32                   crop_start;
 };
 
+static inline struct bttv *to_bttv(struct v4l2_device *v4l2_dev)
+{
+       return container_of(v4l2_dev, struct bttv, c.v4l2_dev);
+}
+
 /* our devices */
 #define BTTV_MAX 32
 extern unsigned int bttv_num;
-extern struct bttv bttvs[BTTV_MAX];
+extern struct bttv *bttvs[BTTV_MAX];
+
+static inline unsigned int bttv_muxsel(const struct bttv *btv,
+                                      unsigned int input)
+{
+       return (bttv_tvcards[btv->c.type].muxsel >> (input * 2)) & 3;
+}
 
 #endif
 
index 46fd573a4f1511594213c01525d10fb5a9f64b04..7abe94d9fb4cd2dcccf73e588f197c35fd516f3e 100644 (file)
  *
  * Written by Jonathan Corbet, corbet@lwn.net.
  *
+ * v4l2_device/v4l2_subdev conversion by:
+ * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Note: this conversion is untested! Please contact the linux-media
+ * mailinglist if you can test this, together with the test results.
+ *
  * This file may be distributed under the terms of the GNU General
  * Public License, version 2.
  */
@@ -25,7 +31,7 @@
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-chip-ident.h>
 #include <linux/device.h>
@@ -33,7 +39,6 @@
 #include <linux/list.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
-#include <linux/debugfs.h>
 #include <linux/jiffies.h>
 #include <linux/vmalloc.h>
 
@@ -136,6 +141,7 @@ struct cafe_sio_buffer {
  */
 struct cafe_camera
 {
+       struct v4l2_device v4l2_dev;
        enum cafe_state state;
        unsigned long flags;            /* Buffer status, mainly (dev_lock) */
        int users;                      /* How many open FDs */
@@ -145,9 +151,10 @@ struct cafe_camera
         * Subsystem structures.
         */
        struct pci_dev *pdev;
-       struct video_device v4ldev;
+       struct video_device vdev;
        struct i2c_adapter i2c_adapter;
-       struct i2c_client *sensor;
+       struct v4l2_subdev *sensor;
+       unsigned short sensor_addr;
 
        unsigned char __iomem *regs;
        struct list_head dev_list;      /* link to other devices */
@@ -180,10 +187,6 @@ struct cafe_camera
        /* Misc */
        wait_queue_head_t smbus_wait;   /* Waiting on i2c events */
        wait_queue_head_t iowait;       /* Waiting on frame data */
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       struct dentry *dfs_regs;
-       struct dentry *dfs_cam_regs;
-#endif
 };
 
 /*
@@ -195,6 +198,13 @@ struct cafe_camera
 #define CF_DMA_ACTIVE   3      /* A frame is incoming */
 #define CF_CONFIG_NEEDED 4     /* Must configure hardware */
 
+#define sensor_call(cam, o, f, args...) \
+       v4l2_subdev_call(cam->sensor, o, f, ##args)
+
+static inline struct cafe_camera *to_cam(struct v4l2_device *dev)
+{
+       return container_of(dev, struct cafe_camera, v4l2_dev);
+}
 
 
 /*
@@ -238,59 +248,7 @@ static void cafe_set_config_needed(struct cafe_camera *cam, int needed)
 
 
 /* ---------------------------------------------------------------------*/
-/*
- * We keep a simple list of known devices to search at open time.
- */
-static LIST_HEAD(cafe_dev_list);
-static DEFINE_MUTEX(cafe_dev_list_lock);
-
-static void cafe_add_dev(struct cafe_camera *cam)
-{
-       mutex_lock(&cafe_dev_list_lock);
-       list_add_tail(&cam->dev_list, &cafe_dev_list);
-       mutex_unlock(&cafe_dev_list_lock);
-}
-
-static void cafe_remove_dev(struct cafe_camera *cam)
-{
-       mutex_lock(&cafe_dev_list_lock);
-       list_del(&cam->dev_list);
-       mutex_unlock(&cafe_dev_list_lock);
-}
-
-static struct cafe_camera *cafe_find_dev(int minor)
-{
-       struct cafe_camera *cam;
-
-       mutex_lock(&cafe_dev_list_lock);
-       list_for_each_entry(cam, &cafe_dev_list, dev_list) {
-               if (cam->v4ldev.minor == minor)
-                       goto done;
-       }
-       cam = NULL;
-  done:
-       mutex_unlock(&cafe_dev_list_lock);
-       return cam;
-}
-
-
-static struct cafe_camera *cafe_find_by_pdev(struct pci_dev *pdev)
-{
-       struct cafe_camera *cam;
 
-       mutex_lock(&cafe_dev_list_lock);
-       list_for_each_entry(cam, &cafe_dev_list, dev_list) {
-               if (cam->pdev == pdev)
-                       goto done;
-       }
-       cam = NULL;
-  done:
-       mutex_unlock(&cafe_dev_list_lock);
-       return cam;
-}
-
-
-/* ------------------------------------------------------------------------ */
 /*
  * Device register I/O
  */
@@ -481,17 +439,10 @@ static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
                unsigned short flags, char rw, u8 command,
                int size, union i2c_smbus_data *data)
 {
-       struct cafe_camera *cam = i2c_get_adapdata(adapter);
+       struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
+       struct cafe_camera *cam = to_cam(v4l2_dev);
        int ret = -EINVAL;
 
-       /*
-        * Refuse to talk to anything but OV cam chips.  We should
-        * never even see an attempt to do so, but one never knows.
-        */
-       if (cam->sensor && addr != cam->sensor->addr) {
-               cam_err(cam, "funky smbus addr %d\n", addr);
-               return -EINVAL;
-       }
        /*
         * This interface would appear to only do byte data ops.  OK
         * it can do word too, but the cam chip has no use for that.
@@ -530,38 +481,9 @@ static struct i2c_algorithm cafe_smbus_algo = {
 };
 
 /* Somebody is on the bus */
-static int cafe_cam_init(struct cafe_camera *cam);
 static void cafe_ctlr_stop_dma(struct cafe_camera *cam);
 static void cafe_ctlr_power_down(struct cafe_camera *cam);
 
-static int cafe_smbus_attach(struct i2c_client *client)
-{
-       struct cafe_camera *cam = i2c_get_adapdata(client->adapter);
-
-       /*
-        * Don't talk to chips we don't recognize.
-        */
-       if (client->driver->id == I2C_DRIVERID_OV7670) {
-               cam->sensor = client;
-               return cafe_cam_init(cam);
-       }
-       return -EINVAL;
-}
-
-static int cafe_smbus_detach(struct i2c_client *client)
-{
-       struct cafe_camera *cam = i2c_get_adapdata(client->adapter);
-
-       if (cam->sensor == client) {
-               cafe_ctlr_stop_dma(cam);
-               cafe_ctlr_power_down(cam);
-               cam_err(cam, "lost the sensor!\n");
-               cam->sensor = NULL;  /* Bummer, no camera */
-               cam->state = S_NOTREADY;
-       }
-       return 0;
-}
-
 static int cafe_smbus_setup(struct cafe_camera *cam)
 {
        struct i2c_adapter *adap = &cam->i2c_adapter;
@@ -570,12 +492,10 @@ static int cafe_smbus_setup(struct cafe_camera *cam)
        cafe_smbus_enable_irq(cam);
        adap->id = I2C_HW_SMBUS_CAFE;
        adap->owner = THIS_MODULE;
-       adap->client_register = cafe_smbus_attach;
-       adap->client_unregister = cafe_smbus_detach;
        adap->algo = &cafe_smbus_algo;
        strcpy(adap->name, "cafe_ccic");
        adap->dev.parent = &cam->pdev->dev;
-       i2c_set_adapdata(adap, cam);
+       i2c_set_adapdata(adap, &cam->v4l2_dev);
        ret = i2c_add_adapter(adap);
        if (ret)
                printk(KERN_ERR "Unable to register cafe i2c adapter\n");
@@ -809,9 +729,9 @@ static void cafe_ctlr_power_up(struct cafe_camera *cam)
         * Control 1 is power down, set to 0 to operate.
         */
        cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */
-//     mdelay(1); /* Marvell says 1ms will do it */
+/*     mdelay(1); */ /* Marvell says 1ms will do it */
        cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
-//     mdelay(1); /* Enough? */
+/*     mdelay(1); */ /* Enough? */
        spin_unlock_irqrestore(&cam->dev_lock, flags);
        msleep(5); /* Just to be sure */
 }
@@ -833,23 +753,9 @@ static void cafe_ctlr_power_down(struct cafe_camera *cam)
  * Communications with the sensor.
  */
 
-static int __cafe_cam_cmd(struct cafe_camera *cam, int cmd, void *arg)
-{
-       struct i2c_client *sc = cam->sensor;
-       int ret;
-
-       if (sc == NULL || sc->driver == NULL || sc->driver->command == NULL)
-               return -EINVAL;
-       ret = sc->driver->command(sc, cmd, arg);
-       if (ret == -EPERM) /* Unsupported command */
-               return 0;
-       return ret;
-}
-
 static int __cafe_cam_reset(struct cafe_camera *cam)
 {
-       int zero = 0;
-       return __cafe_cam_cmd(cam, VIDIOC_INT_RESET, &zero);
+       return sensor_call(cam, core, reset, 0);
 }
 
 /*
@@ -869,14 +775,13 @@ static int cafe_cam_init(struct cafe_camera *cam)
        if (ret)
                goto out;
        chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR;
-       chip.match.addr = cam->sensor->addr;
-       ret = __cafe_cam_cmd(cam, VIDIOC_DBG_G_CHIP_IDENT, &chip);
+       chip.match.addr = cam->sensor_addr;
+       ret = sensor_call(cam, core, g_chip_ident, &chip);
        if (ret)
                goto out;
        cam->sensor_type = chip.ident;
-//     if (cam->sensor->addr != OV7xx0_SID) {
        if (cam->sensor_type != V4L2_IDENT_OV7670) {
-               cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr);
+               cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type);
                ret = -EINVAL;
                goto out;
        }
@@ -900,21 +805,21 @@ static int cafe_cam_set_flip(struct cafe_camera *cam)
        memset(&ctrl, 0, sizeof(ctrl));
        ctrl.id = V4L2_CID_VFLIP;
        ctrl.value = flip;
-       return __cafe_cam_cmd(cam, VIDIOC_S_CTRL, &ctrl);
+       return sensor_call(cam, core, s_ctrl, &ctrl);
 }
 
 
 static int cafe_cam_configure(struct cafe_camera *cam)
 {
        struct v4l2_format fmt;
-       int ret, zero = 0;
+       int ret;
 
        if (cam->state != S_IDLE)
                return -EINVAL;
        fmt.fmt.pix = cam->pix_format;
-       ret = __cafe_cam_cmd(cam, VIDIOC_INT_INIT, &zero);
+       ret = sensor_call(cam, core, init, 0);
        if (ret == 0)
-               ret = __cafe_cam_cmd(cam, VIDIOC_S_FMT, &fmt);
+               ret = sensor_call(cam, video, s_fmt, &fmt);
        /*
         * OV7670 does weird things if flip is set *before* format...
         */
@@ -1246,8 +1151,6 @@ static int cafe_vidioc_reqbufs(struct file *filp, void *priv,
         * Make sure it's something we can do.  User pointers could be
         * implemented without great pain, but that's not been done yet.
         */
-       if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
        if (req->memory != V4L2_MEMORY_MMAP)
                return -EINVAL;
        /*
@@ -1311,9 +1214,7 @@ static int cafe_vidioc_querybuf(struct file *filp, void *priv,
        int ret = -EINVAL;
 
        mutex_lock(&cam->s_mutex);
-       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               goto out;
-       if (buf->index < 0 || buf->index >= cam->n_sbufs)
+       if (buf->index >= cam->n_sbufs)
                goto out;
        *buf = cam->sb_bufs[buf->index].v4lbuf;
        ret = 0;
@@ -1331,9 +1232,7 @@ static int cafe_vidioc_qbuf(struct file *filp, void *priv,
        unsigned long flags;
 
        mutex_lock(&cam->s_mutex);
-       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               goto out;
-       if (buf->index < 0 || buf->index >= cam->n_sbufs)
+       if (buf->index >= cam->n_sbufs)
                goto out;
        sbuf = cam->sb_bufs + buf->index;
        if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) {
@@ -1364,8 +1263,6 @@ static int cafe_vidioc_dqbuf(struct file *filp, void *priv,
        unsigned long flags;
 
        mutex_lock(&cam->s_mutex);
-       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               goto out_unlock;
        if (cam->state != S_STREAMING)
                goto out_unlock;
        if (list_empty(&cam->sb_full) && filp->f_flags & O_NONBLOCK) {
@@ -1474,11 +1371,8 @@ static int cafe_v4l_mmap(struct file *filp, struct vm_area_struct *vma)
 
 static int cafe_v4l_open(struct file *filp)
 {
-       struct cafe_camera *cam;
+       struct cafe_camera *cam = video_drvdata(filp);
 
-       cam = cafe_find_dev(video_devdata(filp)->minor);
-       if (cam == NULL)
-               return -ENODEV;
        filp->private_data = cam;
 
        mutex_lock(&cam->s_mutex);
@@ -1532,11 +1426,11 @@ static unsigned int cafe_v4l_poll(struct file *filp,
 static int cafe_vidioc_queryctrl(struct file *filp, void *priv,
                struct v4l2_queryctrl *qc)
 {
-       struct cafe_camera *cam = filp->private_data;
+       struct cafe_camera *cam = priv;
        int ret;
 
        mutex_lock(&cam->s_mutex);
-       ret = __cafe_cam_cmd(cam, VIDIOC_QUERYCTRL, qc);
+       ret = sensor_call(cam, core, queryctrl, qc);
        mutex_unlock(&cam->s_mutex);
        return ret;
 }
@@ -1545,11 +1439,11 @@ static int cafe_vidioc_queryctrl(struct file *filp, void *priv,
 static int cafe_vidioc_g_ctrl(struct file *filp, void *priv,
                struct v4l2_control *ctrl)
 {
-       struct cafe_camera *cam = filp->private_data;
+       struct cafe_camera *cam = priv;
        int ret;
 
        mutex_lock(&cam->s_mutex);
-       ret = __cafe_cam_cmd(cam, VIDIOC_G_CTRL, ctrl);
+       ret = sensor_call(cam, core, g_ctrl, ctrl);
        mutex_unlock(&cam->s_mutex);
        return ret;
 }
@@ -1558,11 +1452,11 @@ static int cafe_vidioc_g_ctrl(struct file *filp, void *priv,
 static int cafe_vidioc_s_ctrl(struct file *filp, void *priv,
                struct v4l2_control *ctrl)
 {
-       struct cafe_camera *cam = filp->private_data;
+       struct cafe_camera *cam = priv;
        int ret;
 
        mutex_lock(&cam->s_mutex);
-       ret = __cafe_cam_cmd(cam, VIDIOC_S_CTRL, ctrl);
+       ret = sensor_call(cam, core, s_ctrl, ctrl);
        mutex_unlock(&cam->s_mutex);
        return ret;
 }
@@ -1601,10 +1495,8 @@ static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp,
        struct cafe_camera *cam = priv;
        int ret;
 
-       if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
        mutex_lock(&cam->s_mutex);
-       ret = __cafe_cam_cmd(cam, VIDIOC_ENUM_FMT, fmt);
+       ret = sensor_call(cam, video, enum_fmt, fmt);
        mutex_unlock(&cam->s_mutex);
        return ret;
 }
@@ -1617,7 +1509,7 @@ static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
        int ret;
 
        mutex_lock(&cam->s_mutex);
-       ret = __cafe_cam_cmd(cam, VIDIOC_TRY_FMT, fmt);
+       ret = sensor_call(cam, video, try_fmt, fmt);
        mutex_unlock(&cam->s_mutex);
        return ret;
 }
@@ -1726,7 +1618,7 @@ static int cafe_vidioc_g_parm(struct file *filp, void *priv,
        int ret;
 
        mutex_lock(&cam->s_mutex);
-       ret = __cafe_cam_cmd(cam, VIDIOC_G_PARM, parms);
+       ret = sensor_call(cam, video, g_parm, parms);
        mutex_unlock(&cam->s_mutex);
        parms->parm.capture.readbuffers = n_dma_bufs;
        return ret;
@@ -1739,20 +1631,52 @@ static int cafe_vidioc_s_parm(struct file *filp, void *priv,
        int ret;
 
        mutex_lock(&cam->s_mutex);
-       ret = __cafe_cam_cmd(cam, VIDIOC_S_PARM, parms);
+       ret = sensor_call(cam, video, s_parm, parms);
        mutex_unlock(&cam->s_mutex);
        parms->parm.capture.readbuffers = n_dma_bufs;
        return ret;
 }
 
+static int cafe_vidioc_g_chip_ident(struct file *file, void *priv,
+               struct v4l2_dbg_chip_ident *chip)
+{
+       struct cafe_camera *cam = priv;
 
-static void cafe_v4l_dev_release(struct video_device *vd)
+       chip->ident = V4L2_IDENT_NONE;
+       chip->revision = 0;
+       if (v4l2_chip_match_host(&chip->match)) {
+               chip->ident = V4L2_IDENT_CAFE;
+               return 0;
+       }
+       return sensor_call(cam, core, g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int cafe_vidioc_g_register(struct file *file, void *priv,
+               struct v4l2_dbg_register *reg)
 {
-       struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev);
+       struct cafe_camera *cam = priv;
 
-       kfree(cam);
+       if (v4l2_chip_match_host(&reg->match)) {
+               reg->val = cafe_reg_read(cam, reg->reg);
+               reg->size = 4;
+               return 0;
+       }
+       return sensor_call(cam, core, g_register, reg);
 }
 
+static int cafe_vidioc_s_register(struct file *file, void *priv,
+               struct v4l2_dbg_register *reg)
+{
+       struct cafe_camera *cam = priv;
+
+       if (v4l2_chip_match_host(&reg->match)) {
+               cafe_reg_write(cam, reg->reg, reg->val);
+               return 0;
+       }
+       return sensor_call(cam, core, s_register, reg);
+}
+#endif
 
 /*
  * This template device holds all of those v4l2 methods; we
@@ -1790,6 +1714,11 @@ static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = {
        .vidioc_s_ctrl          = cafe_vidioc_s_ctrl,
        .vidioc_g_parm          = cafe_vidioc_g_parm,
        .vidioc_s_parm          = cafe_vidioc_s_parm,
+       .vidioc_g_chip_ident    = cafe_vidioc_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register      = cafe_vidioc_g_register,
+       .vidioc_s_register      = cafe_vidioc_s_register,
+#endif
 };
 
 static struct video_device cafe_v4l_template = {
@@ -1800,15 +1729,10 @@ static struct video_device cafe_v4l_template = {
 
        .fops = &cafe_v4l_fops,
        .ioctl_ops = &cafe_v4l_ioctl_ops,
-       .release = cafe_v4l_dev_release,
+       .release = video_device_release_empty,
 };
 
 
-
-
-
-
-
 /* ---------------------------------------------------------------------- */
 /*
  * Interrupt handler stuff
@@ -1962,127 +1886,6 @@ static irqreturn_t cafe_irq(int irq, void *data)
 
 
 /* -------------------------------------------------------------------------- */
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-/*
- * Debugfs stuff.
- */
-
-static char cafe_debug_buf[1024];
-static struct dentry *cafe_dfs_root;
-
-static void cafe_dfs_setup(void)
-{
-       cafe_dfs_root = debugfs_create_dir("cafe_ccic", NULL);
-       if (IS_ERR(cafe_dfs_root)) {
-               cafe_dfs_root = NULL;  /* Never mind */
-               printk(KERN_NOTICE "cafe_ccic unable to set up debugfs\n");
-       }
-}
-
-static void cafe_dfs_shutdown(void)
-{
-       if (cafe_dfs_root)
-               debugfs_remove(cafe_dfs_root);
-}
-
-static int cafe_dfs_open(struct inode *inode, struct file *file)
-{
-       file->private_data = inode->i_private;
-       return 0;
-}
-
-static ssize_t cafe_dfs_read_regs(struct file *file,
-               char __user *buf, size_t count, loff_t *ppos)
-{
-       struct cafe_camera *cam = file->private_data;
-       char *s = cafe_debug_buf;
-       int offset;
-
-       for (offset = 0; offset < 0x44; offset += 4)
-               s += sprintf(s, "%02x: %08x\n", offset,
-                               cafe_reg_read(cam, offset));
-       for (offset = 0x88; offset <= 0x90; offset += 4)
-               s += sprintf(s, "%02x: %08x\n", offset,
-                               cafe_reg_read(cam, offset));
-       for (offset = 0xb4; offset <= 0xbc; offset += 4)
-               s += sprintf(s, "%02x: %08x\n", offset,
-                               cafe_reg_read(cam, offset));
-       for (offset = 0x3000; offset <= 0x300c; offset += 4)
-               s += sprintf(s, "%04x: %08x\n", offset,
-                               cafe_reg_read(cam, offset));
-       return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf,
-                       s - cafe_debug_buf);
-}
-
-static const struct file_operations cafe_dfs_reg_ops = {
-       .owner = THIS_MODULE,
-       .read = cafe_dfs_read_regs,
-       .open = cafe_dfs_open
-};
-
-static ssize_t cafe_dfs_read_cam(struct file *file,
-               char __user *buf, size_t count, loff_t *ppos)
-{
-       struct cafe_camera *cam = file->private_data;
-       char *s = cafe_debug_buf;
-       int offset;
-
-       if (! cam->sensor)
-               return -EINVAL;
-       for (offset = 0x0; offset < 0x8a; offset++)
-       {
-               u8 v;
-
-               cafe_smbus_read_data(cam, cam->sensor->addr, offset, &v);
-               s += sprintf(s, "%02x: %02x\n", offset, v);
-       }
-       return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf,
-                       s - cafe_debug_buf);
-}
-
-static const struct file_operations cafe_dfs_cam_ops = {
-       .owner = THIS_MODULE,
-       .read = cafe_dfs_read_cam,
-       .open = cafe_dfs_open
-};
-
-
-
-static void cafe_dfs_cam_setup(struct cafe_camera *cam)
-{
-       char fname[40];
-
-       if (!cafe_dfs_root)
-               return;
-       sprintf(fname, "regs-%d", cam->v4ldev.num);
-       cam->dfs_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,
-                       cam, &cafe_dfs_reg_ops);
-       sprintf(fname, "cam-%d", cam->v4ldev.num);
-       cam->dfs_cam_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,
-                       cam, &cafe_dfs_cam_ops);
-}
-
-
-static void cafe_dfs_cam_shutdown(struct cafe_camera *cam)
-{
-       if (! IS_ERR(cam->dfs_regs))
-               debugfs_remove(cam->dfs_regs);
-       if (! IS_ERR(cam->dfs_cam_regs))
-               debugfs_remove(cam->dfs_cam_regs);
-}
-
-#else
-
-#define cafe_dfs_setup()
-#define cafe_dfs_shutdown()
-#define cafe_dfs_cam_setup(cam)
-#define cafe_dfs_cam_shutdown(cam)
-#endif    /* CONFIG_VIDEO_ADV_DEBUG */
-
-
-
-
-/* ------------------------------------------------------------------------*/
 /*
  * PCI interface stuff.
  */
@@ -2100,6 +1903,10 @@ static int cafe_pci_probe(struct pci_dev *pdev,
        cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL);
        if (cam == NULL)
                goto out;
+       ret = v4l2_device_register(&pdev->dev, &cam->v4l2_dev);
+       if (ret)
+               goto out_free;
+
        mutex_init(&cam->s_mutex);
        mutex_lock(&cam->s_mutex);
        spin_lock_init(&cam->dev_lock);
@@ -2118,14 +1925,14 @@ static int cafe_pci_probe(struct pci_dev *pdev,
         */
        ret = pci_enable_device(pdev);
        if (ret)
-               goto out_free;
+               goto out_unreg;
        pci_set_master(pdev);
 
        ret = -EIO;
        cam->regs = pci_iomap(pdev, 0, 0);
        if (! cam->regs) {
                printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n");
-               goto out_free;
+               goto out_unreg;
        }
        ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);
        if (ret)
@@ -2145,17 +1952,31 @@ static int cafe_pci_probe(struct pci_dev *pdev,
        ret = cafe_smbus_setup(cam);
        if (ret)
                goto out_freeirq;
+
+       cam->sensor_addr = 0x42;
+       cam->sensor = v4l2_i2c_new_subdev(&cam->i2c_adapter,
+                       "ov7670", "ov7670", cam->sensor_addr);
+       if (cam->sensor == NULL) {
+               ret = -ENODEV;
+               goto out_smbus;
+       }
+       ret = cafe_cam_init(cam);
+       if (ret)
+               goto out_smbus;
+
        /*
         * Get the v4l2 setup done.
         */
        mutex_lock(&cam->s_mutex);
-       cam->v4ldev = cafe_v4l_template;
-       cam->v4ldev.debug = 0;
-//     cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG;
-       cam->v4ldev.parent = &pdev->dev;
-       ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1);
+       cam->vdev = cafe_v4l_template;
+       cam->vdev.debug = 0;
+/*     cam->vdev.debug = V4L2_DEBUG_IOCTL_ARG;*/
+       cam->vdev.v4l2_dev = &cam->v4l2_dev;
+       ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
        if (ret)
                goto out_smbus;
+       video_set_drvdata(&cam->vdev, cam);
+
        /*
         * If so requested, try to get our DMA buffers now.
         */
@@ -2165,21 +1986,21 @@ static int cafe_pci_probe(struct pci_dev *pdev,
                                        " will try again later.");
        }
 
-       cafe_dfs_cam_setup(cam);
        mutex_unlock(&cam->s_mutex);
-       cafe_add_dev(cam);
        return 0;
 
-  out_smbus:
+out_smbus:
        cafe_smbus_shutdown(cam);
-  out_freeirq:
+out_freeirq:
        cafe_ctlr_power_down(cam);
        free_irq(pdev->irq, cam);
-  out_iounmap:
+out_iounmap:
        pci_iounmap(pdev, cam->regs);
-  out_free:
+out_free:
+       v4l2_device_unregister(&cam->v4l2_dev);
+out_unreg:
        kfree(cam);
-  out:
+out:
        return ret;
 }
 
@@ -2190,25 +2011,23 @@ static int cafe_pci_probe(struct pci_dev *pdev,
 static void cafe_shutdown(struct cafe_camera *cam)
 {
 /* FIXME: Make sure we take care of everything here */
-       cafe_dfs_cam_shutdown(cam);
        if (cam->n_sbufs > 0)
                /* What if they are still mapped?  Shouldn't be, but... */
                cafe_free_sio_buffers(cam);
-       cafe_remove_dev(cam);
        cafe_ctlr_stop_dma(cam);
        cafe_ctlr_power_down(cam);
        cafe_smbus_shutdown(cam);
        cafe_free_dma_bufs(cam);
        free_irq(cam->pdev->irq, cam);
        pci_iounmap(cam->pdev, cam->regs);
-       video_unregister_device(&cam->v4ldev);
-       /* kfree(cam); done in v4l_release () */
+       video_unregister_device(&cam->vdev);
 }
 
 
 static void cafe_pci_remove(struct pci_dev *pdev)
 {
-       struct cafe_camera *cam = cafe_find_by_pdev(pdev);
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+       struct cafe_camera *cam = to_cam(v4l2_dev);
 
        if (cam == NULL) {
                printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev);
@@ -2218,6 +2037,8 @@ static void cafe_pci_remove(struct pci_dev *pdev)
        if (cam->users > 0)
                cam_warn(cam, "Removing a device with users!\n");
        cafe_shutdown(cam);
+       v4l2_device_unregister(&cam->v4l2_dev);
+       kfree(cam);
 /* No unlock - it no longer exists */
 }
 
@@ -2228,7 +2049,8 @@ static void cafe_pci_remove(struct pci_dev *pdev)
  */
 static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
-       struct cafe_camera *cam = cafe_find_by_pdev(pdev);
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+       struct cafe_camera *cam = to_cam(v4l2_dev);
        int ret;
        enum cafe_state cstate;
 
@@ -2246,7 +2068,8 @@ static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 
 static int cafe_pci_resume(struct pci_dev *pdev)
 {
-       struct cafe_camera *cam = cafe_find_by_pdev(pdev);
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+       struct cafe_camera *cam = to_cam(v4l2_dev);
        int ret = 0;
 
        ret = pci_restore_state(pdev);
@@ -2307,13 +2130,11 @@ static int __init cafe_init(void)
 
        printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n",
                        CAFE_VERSION);
-       cafe_dfs_setup();
        ret = pci_register_driver(&cafe_pci_driver);
        if (ret) {
                printk(KERN_ERR "Unable to register cafe_ccic driver\n");
                goto out;
        }
-       request_module("ov7670");  /* FIXME want something more general */
        ret = 0;
 
   out:
@@ -2324,7 +2145,6 @@ static int __init cafe_init(void)
 static void __exit cafe_exit(void)
 {
        pci_unregister_driver(&cafe_pci_driver);
-       cafe_dfs_shutdown();
 }
 
 module_init(cafe_init);
index c3b0c8c63c7642601a2b14feceb5a1f55ff86a78..43ab0adf3b610a8927299e833c6bb3ab5f3b73ad 100644 (file)
@@ -1381,9 +1381,7 @@ static void proc_cpia_create(void)
 {
        cpia_proc_root = proc_mkdir("cpia", NULL);
 
-       if (cpia_proc_root)
-               cpia_proc_root->owner = THIS_MODULE;
-       else
+       if (!cpia_proc_root)
                LOG("Unable to initialise /proc/cpia\n");
 }
 
index 9c25894fdd8e7b19050ae7c3e58d67d45c5b11d7..d4099f5312ac4ab8ac2ad00b1eb9ae405e847c2d 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/videodev.h>
 #include <media/v4l2-ioctl.h>
 
 #include "cpia2.h"
index 87e91072627ad934fec33920defb54fa05b1d64e..9714059ee9496746da94f813d45cd93b3d4d4947 100644 (file)
@@ -141,11 +141,6 @@ static int cs5345_log_status(struct v4l2_subdev *sd)
        return 0;
 }
 
-static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops cs5345_core_ops = {
@@ -214,8 +209,6 @@ MODULE_DEVICE_TABLE(i2c, cs5345_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "cs5345",
-       .driverid = I2C_DRIVERID_CS5345,
-       .command = cs5345_command,
        .probe = cs5345_probe,
        .remove = cs5345_remove,
        .id_table = cs5345_id,
index 7292a6316e63baa8cf278411b61591ff6f39a237..5aeb066857a723caf3ea330023de6dabf2d04dfd 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
 MODULE_AUTHOR("Martin Vaughan");
@@ -41,9 +41,6 @@ module_param(debug, bool, 0644);
 
 MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On");
 
-static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
 
 /* ----------------------------------------------------------------------- */
 
@@ -122,11 +119,6 @@ static int cs53l32a_log_status(struct v4l2_subdev *sd)
        return 0;
 }
 
-static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops cs53l32a_core_ops = {
@@ -218,8 +210,6 @@ MODULE_DEVICE_TABLE(i2c, cs53l32a_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "cs53l32a",
-       .driverid = I2C_DRIVERID_CS53L32A,
-       .command = cs53l32a_command,
        .remove = cs53l32a_remove,
        .probe = cs53l32a_probe,
        .id_table = cs53l32a_id,
index 8940b5387decc4fda02d8f41a3a86189d2380803..e8a50a611ebc38b7050b2f84c820c323c521a862 100644 (file)
@@ -9,7 +9,7 @@ config VIDEO_CX18
        select VIDEO_CX2341X
        select VIDEO_CS5345
        select DVB_S5H1409 if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
        ---help---
          This is a video4linux driver for Conexant cx23418 based
          PCI combo video recorder devices.
index 57beddf0af4df2d3936c69c3044d60c200ca67c2..bb5c5165dd5fd2274be9a5d2a6fed1e64cf562df 100644 (file)
@@ -23,7 +23,6 @@
 
 #include "cx18-driver.h"
 #include "cx18-io.h"
-#include "cx18-i2c.h"
 #include "cx18-cards.h"
 #include "cx18-audio.h"
 
    settings. */
 int cx18_audio_set_io(struct cx18 *cx)
 {
+       const struct cx18_card_audio_input *in;
        struct v4l2_routing route;
-       u32 audio_input;
        u32 val;
-       int mux_input;
        int err;
 
        /* Determine which input to use */
-       if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
-               audio_input = cx->card->radio_input.audio_input;
-               mux_input = cx->card->radio_input.muxer_input;
-       } else {
-               audio_input =
-                       cx->card->audio_inputs[cx->audio_input].audio_input;
-               mux_input =
-                       cx->card->audio_inputs[cx->audio_input].muxer_input;
-       }
+       if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags))
+               in = &cx->card->radio_input;
+       else
+               in = &cx->card->audio_inputs[cx->audio_input];
 
        /* handle muxer chips */
-       route.input = mux_input;
+       route.input = in->muxer_input;
        route.output = 0;
-       cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+       v4l2_subdev_call(cx->sd_extmux, audio, s_routing, &route);
 
-       route.input = audio_input;
-       err = cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
-                       VIDIOC_INT_S_AUDIO_ROUTING, &route);
+       route.input = in->audio_input;
+       err = cx18_call_hw_err(cx, cx->card->hw_audio_ctrl,
+                              audio, s_routing, &route);
        if (err)
                return err;
 
+       /* FIXME - this internal mux should be abstracted to a subdev */
        val = cx18_read_reg(cx, CX18_AUDIO_ENABLE) & ~0x30;
-       val |= (audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
-                                       (audio_input << 4);
-       cx18_write_reg(cx, val | 0xb00, CX18_AUDIO_ENABLE);
-       cx18_vapi(cx, CX18_APU_RESETAI, 1, 0);
+       val |= (in->audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
+                                       (in->audio_input << 4);
+       cx18_write_reg_expect(cx, val | 0xb00, CX18_AUDIO_ENABLE, val, 0x30);
        return 0;
 }
-
-void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route)
-{
-       cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
-                       VIDIOC_INT_S_AUDIO_ROUTING, route);
-}
-
-void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq)
-{
-       static u32 freqs[3] = { 44100, 48000, 32000 };
-
-       /* The audio clock of the digitizer must match the codec sample
-          rate otherwise you get some very strange effects. */
-       if (freq > 2)
-               return;
-       cx18_call_i2c_clients(cx, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]);
-}
index cb569a69379cc38298d5d2d791d9865f758ed301..2731d29b0ab95078cb856cac4c9fb4067fa9c6c6 100644 (file)
@@ -22,5 +22,3 @@
  */
 
 int cx18_audio_set_io(struct cx18 *cx);
-void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route);
-void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq);
index a2f0ad57043461cf72f3ac72ed1d4ae71dd94f1d..9e30983f2ff632496e2bcf731185956a79542ab6 100644 (file)
@@ -464,82 +464,76 @@ static void set_mute(struct cx18 *cx, int mute)
        }
 }
 
-int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
+int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
 {
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
        struct cx18_av_state *state = &cx->av_state;
-       struct v4l2_control *ctrl = arg;
        int retval;
+       u8 v;
 
-       switch (cmd) {
-       case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-       {
-               u8 v;
-               if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
-                       v = cx18_av_read(cx, 0x803) & ~0x10;
-                       cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
-                       cx18_av_write(cx, 0x8d3, 0x1f);
-               }
-               v = cx18_av_read(cx, 0x810) | 0x1;
-               cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
+       if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
+               v = cx18_av_read(cx, 0x803) & ~0x10;
+               cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
+               cx18_av_write(cx, 0x8d3, 0x1f);
+       }
+       v = cx18_av_read(cx, 0x810) | 0x1;
+       cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
 
-               retval = set_audclk_freq(cx, *(u32 *)arg);
+       retval = set_audclk_freq(cx, freq);
 
-               v = cx18_av_read(cx, 0x810) & ~0x1;
-               cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
-               if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
-                       v = cx18_av_read(cx, 0x803) | 0x10;
-                       cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
-               }
-               return retval;
+       v = cx18_av_read(cx, 0x810) & ~0x1;
+       cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
+       if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
+               v = cx18_av_read(cx, 0x803) | 0x10;
+               cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
        }
+       return retval;
+}
 
-       case VIDIOC_G_CTRL:
-               switch (ctrl->id) {
-               case V4L2_CID_AUDIO_VOLUME:
-                       ctrl->value = get_volume(cx);
-                       break;
-               case V4L2_CID_AUDIO_BASS:
-                       ctrl->value = get_bass(cx);
-                       break;
-               case V4L2_CID_AUDIO_TREBLE:
-                       ctrl->value = get_treble(cx);
-                       break;
-               case V4L2_CID_AUDIO_BALANCE:
-                       ctrl->value = get_balance(cx);
-                       break;
-               case V4L2_CID_AUDIO_MUTE:
-                       ctrl->value = get_mute(cx);
-                       break;
-               default:
-                       return -EINVAL;
-               }
+int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+               ctrl->value = get_volume(cx);
                break;
-
-       case VIDIOC_S_CTRL:
-               switch (ctrl->id) {
-               case V4L2_CID_AUDIO_VOLUME:
-                       set_volume(cx, ctrl->value);
-                       break;
-               case V4L2_CID_AUDIO_BASS:
-                       set_bass(cx, ctrl->value);
-                       break;
-               case V4L2_CID_AUDIO_TREBLE:
-                       set_treble(cx, ctrl->value);
-                       break;
-               case V4L2_CID_AUDIO_BALANCE:
-                       set_balance(cx, ctrl->value);
-                       break;
-               case V4L2_CID_AUDIO_MUTE:
-                       set_mute(cx, ctrl->value);
-                       break;
-               default:
-                       return -EINVAL;
-               }
+       case V4L2_CID_AUDIO_BASS:
+               ctrl->value = get_bass(cx);
+               break;
+       case V4L2_CID_AUDIO_TREBLE:
+               ctrl->value = get_treble(cx);
+               break;
+       case V4L2_CID_AUDIO_BALANCE:
+               ctrl->value = get_balance(cx);
+               break;
+       case V4L2_CID_AUDIO_MUTE:
+               ctrl->value = get_mute(cx);
                break;
-
        default:
                return -EINVAL;
        }
+       return 0;
+}
 
+int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+               set_volume(cx, ctrl->value);
+               break;
+       case V4L2_CID_AUDIO_BASS:
+               set_bass(cx, ctrl->value);
+               break;
+       case V4L2_CID_AUDIO_TREBLE:
+               set_treble(cx, ctrl->value);
+               break;
+       case V4L2_CID_AUDIO_BALANCE:
+               set_balance(cx, ctrl->value);
+               break;
+       case V4L2_CID_AUDIO_MUTE:
+               set_mute(cx, ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
        return 0;
 }
index 0b1c84b4ddd6eadd105373f152d82577dea5269e..f4dd9d78eb3d2fe346e8d98bc5e37bd919123b53 100644 (file)
  *  02110-1301, USA.
  */
 
+#include <media/v4l2-chip-ident.h>
 #include "cx18-driver.h"
 #include "cx18-io.h"
+#include "cx18-cards.h"
 
 int cx18_av_write(struct cx18 *cx, u16 addr, u8 value)
 {
@@ -97,15 +99,6 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
                             or_value);
 }
 
-/* ----------------------------------------------------------------------- */
-
-static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
-                                       enum cx18_av_audio_input aud_input);
-static void log_audio_status(struct cx18 *cx);
-static void log_video_status(struct cx18 *cx);
-
-/* ----------------------------------------------------------------------- */
-
 static void cx18_av_initialize(struct cx18 *cx)
 {
        struct cx18_av_state *state = &cx->av_state;
@@ -169,9 +162,14 @@ static void cx18_av_initialize(struct cx18 *cx)
        /* Set VGA_TRACK_RANGE to 0x20 */
        cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000);
 
-       /* Enable VBI capture */
-       cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253F);
-       /* cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253E); */
+       /*
+        * Initial VBI setup
+        * VIP-1.1, 10 bit mode, enable Raw, disable sliced,
+        * don't clamp raw samples when codes are in use, 1 byte user D-words,
+        * IDID0 has line #, RP code V bit transition on VBLANK, data during
+        * blanking intervals
+        */
+       cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4013252e);
 
        /* Set the video input.
           The setting in MODE_CTRL gets lost when we do the above setup */
@@ -195,11 +193,61 @@ static void cx18_av_initialize(struct cx18 *cx)
        state->default_volume = ((state->default_volume / 2) + 23) << 9;
 }
 
-/* ----------------------------------------------------------------------- */
+static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
+{
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+       cx18_av_initialize(cx);
+       return 0;
+}
+
+static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
+{
+       struct cx18_av_state *state = to_cx18_av_state(sd);
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+       switch (val) {
+       case CX18_AV_INIT_PLLS:
+               /*
+                * The crystal freq used in calculations in this driver will be
+                * 28.636360 MHz.
+                * Aim to run the PLLs' VCOs near 400 MHz to minimze errors.
+                */
+
+               /*
+                * VDCLK  Integer = 0x0f, Post Divider = 0x04
+                * AIMCLK Integer = 0x0e, Post Divider = 0x16
+                */
+               cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
+
+               /* VDCLK Fraction = 0x2be2fe */
+               /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
+               cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
+
+               /* AIMCLK Fraction = 0x05227ad */
+               /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/
+               cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
+
+               /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
+               cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
+               break;
+
+       case CX18_AV_INIT_NORMAL:
+       default:
+               if (!state->is_initialized) {
+                       /* initialize on first use */
+                       state->is_initialized = 1;
+                       cx18_av_initialize(cx);
+               }
+               break;
+       }
+       return 0;
+}
 
 void cx18_av_std_setup(struct cx18 *cx)
 {
        struct cx18_av_state *state = &cx->av_state;
+       struct v4l2_subdev *sd = &state->sd;
        v4l2_std_id std = state->std;
        int hblank, hactive, burst, vblank, vactive, sc;
        int vblank656, src_decimation;
@@ -213,6 +261,7 @@ void cx18_av_std_setup(struct cx18 *cx)
                cx18_av_write(cx, 0x49f, 0x14);
 
        if (std & V4L2_STD_625_50) {
+               /* FIXME - revisit these for Sliced VBI */
                hblank = 132;
                hactive = 720;
                burst = 93;
@@ -236,13 +285,40 @@ void cx18_av_std_setup(struct cx18 *cx)
                        sc = 672351;
                }
        } else {
+               /*
+                * The following relationships of half line counts should hold:
+                * 525 = vsync + vactive + vblank656
+                * 12 = vblank656 - vblank
+                *
+                * vsync:     always 6 half-lines of vsync pulses
+                * vactive:   half lines of active video
+                * vblank656: half lines, after line 3/mid-266, of blanked video
+                * vblank:    half lines, after line 9/272, of blanked video
+                *
+                * As far as I can tell:
+                * vblank656 starts counting from the falling edge of the first
+                *      vsync pulse (start of line 4 or mid-266)
+                * vblank starts counting from the after the 6 vsync pulses and
+                *      6 or 5 equalization pulses (start of line 10 or 272)
+                *
+                * For 525 line systems the driver will extract VBI information
+                * from lines 10-21 and lines 273-284.
+                */
+               vblank656 = 38; /* lines  4 -  22  &  266 - 284 */
+               vblank = 26;    /* lines 10 -  22  &  272 - 284 */
+               vactive = 481;  /* lines 23 - 263  &  285 - 525 */
+
+               /*
+                * For a 13.5 Mpps clock and 15,734.26 Hz line rate, a line is
+                * is 858 pixels = 720 active + 138 blanking.  The Hsync leading
+                * edge should happen 1.2 us * 13.5 Mpps ~= 16 pixels after the
+                * end of active video, leaving 122 pixels of hblank to ignore
+                * before active video starts.
+                */
                hactive = 720;
                hblank = 122;
-               vactive = 487;
                luma_lpf = 1;
                uv_lpf = 1;
-               vblank = 26;
-               vblank656 = 26;
 
                src_decimation = 0x21f;
                if (std == V4L2_STD_PAL_60) {
@@ -265,33 +341,35 @@ void cx18_av_std_setup(struct cx18 *cx)
        pll_int = cx18_av_read(cx, 0x108);
        pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff;
        pll_post = cx18_av_read(cx, 0x109);
-       CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n",
-                       pll_int, pll_frac, pll_post);
+       CX18_DEBUG_INFO_DEV(sd, "PLL regs = int: %u, frac: %u, post: %u\n",
+                           pll_int, pll_frac, pll_post);
 
        if (pll_post) {
                int fin, fsc, pll;
 
                pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25;
                pll /= pll_post;
-               CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
-                                       pll / 1000000, pll % 1000000);
-               CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n",
-                                       pll / 8000000, (pll / 8) % 1000000);
+               CX18_DEBUG_INFO_DEV(sd, "PLL = %d.%06d MHz\n",
+                                   pll / 1000000, pll % 1000000);
+               CX18_DEBUG_INFO_DEV(sd, "PLL/8 = %d.%06d MHz\n",
+                                   pll / 8000000, (pll / 8) % 1000000);
 
                fin = ((u64)src_decimation * pll) >> 12;
-               CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n",
-                                       fin / 1000000, fin % 1000000);
+               CX18_DEBUG_INFO_DEV(sd, "ADC Sampling freq = %d.%06d MHz\n",
+                                   fin / 1000000, fin % 1000000);
 
                fsc = (((u64)sc) * pll) >> 24L;
-               CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n",
-                                       fsc / 1000000, fsc % 1000000);
-
-               CX18_DEBUG_INFO("hblank %i, hactive %i, "
-                       "vblank %i , vactive %i, vblank656 %i, src_dec %i,"
-                       "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
-                       " sc 0x%06x\n",
-                       hblank, hactive, vblank, vactive, vblank656,
-                       src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+               CX18_DEBUG_INFO_DEV(sd,
+                                   "Chroma sub-carrier freq = %d.%06d MHz\n",
+                                   fsc / 1000000, fsc % 1000000);
+
+               CX18_DEBUG_INFO_DEV(sd, "hblank %i, hactive %i, vblank %i, "
+                                   "vactive %i, vblank656 %i, src_dec %i, "
+                                   "burst 0x%02x, luma_lpf %i, uv_lpf %i, "
+                                   "comb 0x%02x, sc 0x%06x\n",
+                                   hblank, hactive, vblank, vactive, vblank656,
+                                   src_decimation, burst, luma_lpf, uv_lpf,
+                                   comb, sc);
        }
 
        /* Sets horizontal blanking delay and active lines */
@@ -325,18 +403,16 @@ void cx18_av_std_setup(struct cx18 *cx)
        cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
        cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
 
-       /* Sets VBI parameters */
        if (std & V4L2_STD_625_50) {
-               cx18_av_write(cx, 0x47f, 0x01);
-               state->vbi_line_offset = 5;
+               state->slicer_line_delay = 1;
+               state->slicer_line_offset = (6 + state->slicer_line_delay - 2);
        } else {
-               cx18_av_write(cx, 0x47f, 0x00);
-               state->vbi_line_offset = 8;
+               state->slicer_line_delay = 0;
+               state->slicer_line_offset = (10 + state->slicer_line_delay - 2);
        }
+       cx18_av_write(cx, 0x47f, state->slicer_line_delay);
 }
 
-/* ----------------------------------------------------------------------- */
-
 static void input_change(struct cx18 *cx)
 {
        struct cx18_av_state *state = &cx->av_state;
@@ -382,17 +458,26 @@ static void input_change(struct cx18 *cx)
        }
 }
 
+static int cx18_av_s_frequency(struct v4l2_subdev *sd,
+                              struct v4l2_frequency *freq)
+{
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+       input_change(cx);
+       return 0;
+}
+
 static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
                                        enum cx18_av_audio_input aud_input)
 {
        struct cx18_av_state *state = &cx->av_state;
+       struct v4l2_subdev *sd = &state->sd;
        u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 &&
                           vid_input <= CX18_AV_COMPOSITE8);
        u8 reg;
        u8 v;
 
-       CX18_DEBUG_INFO("decoder set video input %d, audio input %d\n",
-                       vid_input, aud_input);
+       CX18_DEBUG_INFO_DEV(sd, "decoder set video input %d, audio input %d\n",
+                           vid_input, aud_input);
 
        if (is_composite) {
                reg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1);
@@ -405,8 +490,8 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
                    luma > CX18_AV_SVIDEO_LUMA8 ||
                    chroma < CX18_AV_SVIDEO_CHROMA4 ||
                    chroma > CX18_AV_SVIDEO_CHROMA8) {
-                       CX18_ERR("0x%04x is not a valid video input!\n",
-                                       vid_input);
+                       CX18_ERR_DEV(sd, "0x%04x is not a valid video input!\n",
+                                    vid_input);
                        return -EINVAL;
                }
                reg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4);
@@ -431,7 +516,8 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
        case CX18_AV_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
 
        default:
-               CX18_ERR("0x%04x is not a valid audio input!\n", aud_input);
+               CX18_ERR_DEV(sd, "0x%04x is not a valid audio input!\n",
+                            aud_input);
                return -EINVAL;
        }
 
@@ -461,14 +547,118 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
        return 0;
 }
 
-/* ----------------------------------------------------------------------- */
+static int cx18_av_s_video_routing(struct v4l2_subdev *sd,
+                                  const struct v4l2_routing *route)
+{
+       struct cx18_av_state *state = to_cx18_av_state(sd);
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+       return set_input(cx, route->input, state->aud_input);
+}
+
+static int cx18_av_s_audio_routing(struct v4l2_subdev *sd,
+                                  const struct v4l2_routing *route)
+{
+       struct cx18_av_state *state = to_cx18_av_state(sd);
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+       return set_input(cx, state->vid_input, route->input);
+}
 
-static int set_v4lstd(struct cx18 *cx)
+static int cx18_av_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 {
-       struct cx18_av_state *state = &cx->av_state;
+       struct cx18_av_state *state = to_cx18_av_state(sd);
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+       u8 vpres;
+       u8 mode;
+       int val = 0;
+
+       if (state->radio)
+               return 0;
+
+       vpres = cx18_av_read(cx, 0x40e) & 0x20;
+       vt->signal = vpres ? 0xffff : 0x0;
+
+       vt->capability |=
+                   V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+                   V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+
+       mode = cx18_av_read(cx, 0x804);
+
+       /* get rxsubchans and audmode */
+       if ((mode & 0xf) == 1)
+               val |= V4L2_TUNER_SUB_STEREO;
+       else
+               val |= V4L2_TUNER_SUB_MONO;
+
+       if (mode == 2 || mode == 4)
+               val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+
+       if (mode & 0x10)
+               val |= V4L2_TUNER_SUB_SAP;
+
+       vt->rxsubchans = val;
+       vt->audmode = state->audmode;
+       return 0;
+}
+
+static int cx18_av_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct cx18_av_state *state = to_cx18_av_state(sd);
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+       u8 v;
+
+       if (state->radio)
+               return 0;
+
+       v = cx18_av_read(cx, 0x809);
+       v &= ~0xf;
+
+       switch (vt->audmode) {
+       case V4L2_TUNER_MODE_MONO:
+               /* mono      -> mono
+                  stereo    -> mono
+                  bilingual -> lang1 */
+               break;
+       case V4L2_TUNER_MODE_STEREO:
+       case V4L2_TUNER_MODE_LANG1:
+               /* mono      -> mono
+                  stereo    -> stereo
+                  bilingual -> lang1 */
+               v |= 0x4;
+               break;
+       case V4L2_TUNER_MODE_LANG1_LANG2:
+               /* mono      -> mono
+                  stereo    -> stereo
+                  bilingual -> lang1/lang2 */
+               v |= 0x7;
+               break;
+       case V4L2_TUNER_MODE_LANG2:
+               /* mono      -> mono
+                  stereo    -> stereo
+                  bilingual -> lang2 */
+               v |= 0x1;
+               break;
+       default:
+               return -EINVAL;
+       }
+       cx18_av_write_expect(cx, 0x809, v, v, 0xff);
+       state->audmode = vt->audmode;
+       return 0;
+}
+
+static int cx18_av_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+       struct cx18_av_state *state = to_cx18_av_state(sd);
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+
        u8 fmt = 0;     /* zero is autodetect */
        u8 pal_m = 0;
 
+       if (state->radio == 0 && state->std == norm)
+               return 0;
+
+       state->radio = 0;
+       state->std = norm;
+
        /* First tests should be against specific std */
        if (state->std == V4L2_STD_NTSC_M_JP) {
                fmt = 0x2;
@@ -493,7 +683,7 @@ static int set_v4lstd(struct cx18 *cx)
                        fmt = 0xc;
        }
 
-       CX18_DEBUG_INFO("changing video std to fmt %i\n", fmt);
+       CX18_DEBUG_INFO_DEV(sd, "changing video std to fmt %i\n", fmt);
 
        /* Follow step 9 of section 3.16 in the cx18_av datasheet.
           Without this PAL may display a vertical ghosting effect.
@@ -511,15 +701,22 @@ static int set_v4lstd(struct cx18 *cx)
        return 0;
 }
 
-/* ----------------------------------------------------------------------- */
+static int cx18_av_s_radio(struct v4l2_subdev *sd)
+{
+       struct cx18_av_state *state = to_cx18_av_state(sd);
+       state->radio = 1;
+       return 0;
+}
 
-static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
+static int cx18_av_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
                if (ctrl->value < 0 || ctrl->value > 255) {
-                       CX18_ERR("invalid brightness setting %d\n",
-                                   ctrl->value);
+                       CX18_ERR_DEV(sd, "invalid brightness setting %d\n",
+                                    ctrl->value);
                        return -ERANGE;
                }
 
@@ -528,8 +725,8 @@ static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
 
        case V4L2_CID_CONTRAST:
                if (ctrl->value < 0 || ctrl->value > 127) {
-                       CX18_ERR("invalid contrast setting %d\n",
-                                   ctrl->value);
+                       CX18_ERR_DEV(sd, "invalid contrast setting %d\n",
+                                    ctrl->value);
                        return -ERANGE;
                }
 
@@ -538,8 +735,8 @@ static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
 
        case V4L2_CID_SATURATION:
                if (ctrl->value < 0 || ctrl->value > 127) {
-                       CX18_ERR("invalid saturation setting %d\n",
-                                   ctrl->value);
+                       CX18_ERR_DEV(sd, "invalid saturation setting %d\n",
+                                    ctrl->value);
                        return -ERANGE;
                }
 
@@ -548,8 +745,9 @@ static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
                break;
 
        case V4L2_CID_HUE:
-               if (ctrl->value < -127 || ctrl->value > 127) {
-                       CX18_ERR("invalid hue setting %d\n", ctrl->value);
+               if (ctrl->value < -128 || ctrl->value > 127) {
+                       CX18_ERR_DEV(sd, "invalid hue setting %d\n",
+                                    ctrl->value);
                        return -ERANGE;
                }
 
@@ -561,17 +759,18 @@ static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
        case V4L2_CID_AUDIO_TREBLE:
        case V4L2_CID_AUDIO_BALANCE:
        case V4L2_CID_AUDIO_MUTE:
-               return cx18_av_audio(cx, VIDIOC_S_CTRL, ctrl);
+               return cx18_av_audio_s_ctrl(cx, ctrl);
 
        default:
                return -EINVAL;
        }
-
        return 0;
 }
 
-static int get_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
+static int cx18_av_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
                ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128;
@@ -590,31 +789,57 @@ static int get_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
        case V4L2_CID_AUDIO_TREBLE:
        case V4L2_CID_AUDIO_BALANCE:
        case V4L2_CID_AUDIO_MUTE:
-               return cx18_av_audio(cx, VIDIOC_G_CTRL, ctrl);
+               return cx18_av_audio_g_ctrl(cx, ctrl);
        default:
                return -EINVAL;
        }
-
        return 0;
 }
 
-/* ----------------------------------------------------------------------- */
-
-static int get_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
+static int cx18_av_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
 {
-       switch (fmt->type) {
-       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-               return cx18_av_vbi(cx, VIDIOC_G_FMT, fmt);
+       struct cx18_av_state *state = to_cx18_av_state(sd);
+
+       switch (qc->id) {
+       case V4L2_CID_BRIGHTNESS:
+               return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
+       case V4L2_CID_CONTRAST:
+       case V4L2_CID_SATURATION:
+               return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
+       case V4L2_CID_HUE:
+               return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
+       default:
+               break;
+       }
+
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(qc, 0, 65535,
+                       65535 / 100, state->default_volume);
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+       case V4L2_CID_AUDIO_BALANCE:
+       case V4L2_CID_AUDIO_BASS:
+       case V4L2_CID_AUDIO_TREBLE:
+               return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
        default:
                return -EINVAL;
        }
+       return -EINVAL;
+}
 
-       return 0;
+static int cx18_av_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+       return cx18_av_vbi_g_fmt(cx, fmt);
 }
 
-static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
+static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
 {
-       struct cx18_av_state *state = &cx->av_state;
+       struct cx18_av_state *state = to_cx18_av_state(sd);
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+
        struct v4l2_pix_format *pix;
        int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
        int is_50Hz = !(state->std & V4L2_STD_525_60);
@@ -629,12 +854,26 @@ static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
                Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4;
                Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4;
 
-               Vlines = pix->height + (is_50Hz ? 4 : 7);
-
+               /*
+                * This adjustment reflects the excess of vactive, set in
+                * cx18_av_std_setup(), above standard values:
+                *
+                * 480 + 1 for 60 Hz systems
+                * 576 + 4 for 50 Hz systems
+                */
+               Vlines = pix->height + (is_50Hz ? 4 : 1);
+
+               /*
+                * Invalid height and width scaling requests are:
+                * 1. width less than 1/16 of the source width
+                * 2. width greater than the source width
+                * 3. height less than 1/8 of the source height
+                * 4. height greater than the source height
+                */
                if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
                    (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
-                       CX18_ERR("%dx%d is not a valid size!\n",
-                                   pix->width, pix->height);
+                       CX18_ERR_DEV(sd, "%dx%d is not a valid size!\n",
+                                    pix->width, pix->height);
                        return -ERANGE;
                }
 
@@ -651,8 +890,9 @@ static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
                else
                        filter = 3;
 
-               CX18_DEBUG_INFO("decoder set size %dx%d -> scale  %ux%u\n",
-                           pix->width, pix->height, HSC, VSC);
+               CX18_DEBUG_INFO_DEV(sd,
+                                   "decoder set size %dx%d -> scale  %ux%u\n",
+                                   pix->width, pix->height, HSC, VSC);
 
                /* HSCALE=HSC */
                cx18_av_write(cx, 0x418, HSC & 0xff);
@@ -666,231 +906,32 @@ static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
                break;
 
        case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-               return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt);
+               return cx18_av_vbi_s_fmt(cx, fmt);
 
        case V4L2_BUF_TYPE_VBI_CAPTURE:
-               return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt);
+               return cx18_av_vbi_s_fmt(cx, fmt);
 
        default:
                return -EINVAL;
        }
-
        return 0;
 }
 
-/* ----------------------------------------------------------------------- */
-
-int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg)
+static int cx18_av_s_stream(struct v4l2_subdev *sd, int enable)
 {
-       struct cx18_av_state *state = &cx->av_state;
-       struct v4l2_tuner *vt = arg;
-       struct v4l2_routing *route = arg;
-
-       /* ignore these commands */
-       switch (cmd) {
-       case TUNER_SET_TYPE_ADDR:
-               return 0;
-       }
-
-       if (!state->is_initialized) {
-               CX18_DEBUG_INFO("cmd %08x triggered fw load\n", cmd);
-               /* initialize on first use */
-               state->is_initialized = 1;
-               cx18_av_initialize(cx);
-       }
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
 
-       switch (cmd) {
-       case VIDIOC_INT_DECODE_VBI_LINE:
-               return cx18_av_vbi(cx, cmd, arg);
-
-       case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-               return cx18_av_audio(cx, cmd, arg);
-
-       case VIDIOC_STREAMON:
-               CX18_DEBUG_INFO("enable output\n");
+       CX18_DEBUG_INFO_DEV(sd, "%s output\n", enable ? "enable" : "disable");
+       if (enable) {
                cx18_av_write(cx, 0x115, 0x8c);
                cx18_av_write(cx, 0x116, 0x07);
-               break;
-
-       case VIDIOC_STREAMOFF:
-               CX18_DEBUG_INFO("disable output\n");
+       } else {
                cx18_av_write(cx, 0x115, 0x00);
                cx18_av_write(cx, 0x116, 0x00);
-               break;
-
-       case VIDIOC_LOG_STATUS:
-               log_video_status(cx);
-               log_audio_status(cx);
-               break;
-
-       case VIDIOC_G_CTRL:
-               return get_v4lctrl(cx, (struct v4l2_control *)arg);
-
-       case VIDIOC_S_CTRL:
-               return set_v4lctrl(cx, (struct v4l2_control *)arg);
-
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *qc = arg;
-
-               switch (qc->id) {
-               case V4L2_CID_BRIGHTNESS:
-               case V4L2_CID_CONTRAST:
-               case V4L2_CID_SATURATION:
-               case V4L2_CID_HUE:
-                       return v4l2_ctrl_query_fill_std(qc);
-               default:
-                       break;
-               }
-
-               switch (qc->id) {
-               case V4L2_CID_AUDIO_VOLUME:
-                       return v4l2_ctrl_query_fill(qc, 0, 65535,
-                               65535 / 100, state->default_volume);
-               case V4L2_CID_AUDIO_MUTE:
-               case V4L2_CID_AUDIO_BALANCE:
-               case V4L2_CID_AUDIO_BASS:
-               case V4L2_CID_AUDIO_TREBLE:
-                       return v4l2_ctrl_query_fill_std(qc);
-               default:
-                       return -EINVAL;
-               }
-               return -EINVAL;
-       }
-
-       case VIDIOC_G_STD:
-               *(v4l2_std_id *)arg = state->std;
-               break;
-
-       case VIDIOC_S_STD:
-               if (state->radio == 0 && state->std == *(v4l2_std_id *)arg)
-                       return 0;
-               state->radio = 0;
-               state->std = *(v4l2_std_id *)arg;
-               return set_v4lstd(cx);
-
-       case AUDC_SET_RADIO:
-               state->radio = 1;
-               break;
-
-       case VIDIOC_INT_G_VIDEO_ROUTING:
-               route->input = state->vid_input;
-               route->output = 0;
-               break;
-
-       case VIDIOC_INT_S_VIDEO_ROUTING:
-               return set_input(cx, route->input, state->aud_input);
-
-       case VIDIOC_INT_G_AUDIO_ROUTING:
-               route->input = state->aud_input;
-               route->output = 0;
-               break;
-
-       case VIDIOC_INT_S_AUDIO_ROUTING:
-               return set_input(cx, state->vid_input, route->input);
-
-       case VIDIOC_S_FREQUENCY:
-               input_change(cx);
-               break;
-
-       case VIDIOC_G_TUNER:
-       {
-               u8 vpres = cx18_av_read(cx, 0x40e) & 0x20;
-               u8 mode;
-               int val = 0;
-
-               if (state->radio)
-                       break;
-
-               vt->signal = vpres ? 0xffff : 0x0;
-
-               vt->capability |=
-                   V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
-                   V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
-
-               mode = cx18_av_read(cx, 0x804);
-
-               /* get rxsubchans and audmode */
-               if ((mode & 0xf) == 1)
-                       val |= V4L2_TUNER_SUB_STEREO;
-               else
-                       val |= V4L2_TUNER_SUB_MONO;
-
-               if (mode == 2 || mode == 4)
-                       val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
-
-               if (mode & 0x10)
-                       val |= V4L2_TUNER_SUB_SAP;
-
-               vt->rxsubchans = val;
-               vt->audmode = state->audmode;
-               break;
-       }
-
-       case VIDIOC_S_TUNER:
-       {
-               u8 v;
-
-               if (state->radio)
-                       break;
-
-               v = cx18_av_read(cx, 0x809);
-               v &= ~0xf;
-
-               switch (vt->audmode) {
-               case V4L2_TUNER_MODE_MONO:
-                       /* mono      -> mono
-                          stereo    -> mono
-                          bilingual -> lang1 */
-                       break;
-               case V4L2_TUNER_MODE_STEREO:
-               case V4L2_TUNER_MODE_LANG1:
-                       /* mono      -> mono
-                          stereo    -> stereo
-                          bilingual -> lang1 */
-                       v |= 0x4;
-                       break;
-               case V4L2_TUNER_MODE_LANG1_LANG2:
-                       /* mono      -> mono
-                          stereo    -> stereo
-                          bilingual -> lang1/lang2 */
-                       v |= 0x7;
-                       break;
-               case V4L2_TUNER_MODE_LANG2:
-                       /* mono      -> mono
-                          stereo    -> stereo
-                          bilingual -> lang2 */
-                       v |= 0x1;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               cx18_av_write_expect(cx, 0x809, v, v, 0xff);
-               state->audmode = vt->audmode;
-               break;
        }
-
-       case VIDIOC_G_FMT:
-               return get_v4lfmt(cx, (struct v4l2_format *)arg);
-
-       case VIDIOC_S_FMT:
-               return set_v4lfmt(cx, (struct v4l2_format *)arg);
-
-       case VIDIOC_INT_RESET:
-               cx18_av_initialize(cx);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
        return 0;
 }
 
-/* ----------------------------------------------------------------------- */
-
-/* ----------------------------------------------------------------------- */
-
 static void log_video_status(struct cx18 *cx)
 {
        static const char *const fmt_strs[] = {
@@ -903,36 +944,40 @@ static void log_video_status(struct cx18 *cx)
        };
 
        struct cx18_av_state *state = &cx->av_state;
+       struct v4l2_subdev *sd = &state->sd;
        u8 vidfmt_sel = cx18_av_read(cx, 0x400) & 0xf;
        u8 gen_stat1 = cx18_av_read(cx, 0x40d);
        u8 gen_stat2 = cx18_av_read(cx, 0x40e);
        int vid_input = state->vid_input;
 
-       CX18_INFO("Video signal:              %spresent\n",
-                   (gen_stat2 & 0x20) ? "" : "not ");
-       CX18_INFO("Detected format:           %s\n",
-                   fmt_strs[gen_stat1 & 0xf]);
+       CX18_INFO_DEV(sd, "Video signal:              %spresent\n",
+                     (gen_stat2 & 0x20) ? "" : "not ");
+       CX18_INFO_DEV(sd, "Detected format:           %s\n",
+                     fmt_strs[gen_stat1 & 0xf]);
 
-       CX18_INFO("Specified standard:        %s\n",
-                   vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+       CX18_INFO_DEV(sd, "Specified standard:        %s\n",
+                     vidfmt_sel ? fmt_strs[vidfmt_sel]
+                                : "automatic detection");
 
        if (vid_input >= CX18_AV_COMPOSITE1 &&
            vid_input <= CX18_AV_COMPOSITE8) {
-               CX18_INFO("Specified video input:     Composite %d\n",
-                       vid_input - CX18_AV_COMPOSITE1 + 1);
+               CX18_INFO_DEV(sd, "Specified video input:     Composite %d\n",
+                             vid_input - CX18_AV_COMPOSITE1 + 1);
        } else {
-               CX18_INFO("Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
-                       (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
+               CX18_INFO_DEV(sd, "Specified video input:     "
+                             "S-Video (Luma In%d, Chroma In%d)\n",
+                             (vid_input & 0xf0) >> 4,
+                             (vid_input & 0xf00) >> 8);
        }
 
-       CX18_INFO("Specified audioclock freq: %d Hz\n", state->audclk_freq);
+       CX18_INFO_DEV(sd, "Specified audioclock freq: %d Hz\n",
+                     state->audclk_freq);
 }
 
-/* ----------------------------------------------------------------------- */
-
 static void log_audio_status(struct cx18 *cx)
 {
        struct cx18_av_state *state = &cx->av_state;
+       struct v4l2_subdev *sd = &state->sd;
        u8 download_ctl = cx18_av_read(cx, 0x803);
        u8 mod_det_stat0 = cx18_av_read(cx, 0x804);
        u8 mod_det_stat1 = cx18_av_read(cx, 0x805);
@@ -955,7 +1000,7 @@ static void log_audio_status(struct cx18 *cx)
        case 0xfe: p = "forced mode"; break;
        default: p = "not defined"; break;
        }
-       CX18_INFO("Detected audio mode:       %s\n", p);
+       CX18_INFO_DEV(sd, "Detected audio mode:       %s\n", p);
 
        switch (mod_det_stat1) {
        case 0x00: p = "not defined"; break;
@@ -980,11 +1025,11 @@ static void log_audio_status(struct cx18 *cx)
        case 0xff: p = "no detected audio standard"; break;
        default: p = "not defined"; break;
        }
-       CX18_INFO("Detected audio standard:   %s\n", p);
-       CX18_INFO("Audio muted:               %s\n",
-                   (mute_ctl & 0x2) ? "yes" : "no");
-       CX18_INFO("Audio microcontroller:     %s\n",
-                   (download_ctl & 0x10) ? "running" : "stopped");
+       CX18_INFO_DEV(sd, "Detected audio standard:   %s\n", p);
+       CX18_INFO_DEV(sd, "Audio muted:               %s\n",
+                     (mute_ctl & 0x2) ? "yes" : "no");
+       CX18_INFO_DEV(sd, "Audio microcontroller:     %s\n",
+                     (download_ctl & 0x10) ? "running" : "stopped");
 
        switch (audio_config >> 4) {
        case 0x00: p = "undefined"; break;
@@ -1005,7 +1050,7 @@ static void log_audio_status(struct cx18 *cx)
        case 0x0f: p = "automatic detection"; break;
        default: p = "undefined"; break;
        }
-       CX18_INFO("Configured audio standard: %s\n", p);
+       CX18_INFO_DEV(sd, "Configured audio standard: %s\n", p);
 
        if ((audio_config >> 4) < 0xF) {
                switch (audio_config & 0xF) {
@@ -1019,7 +1064,7 @@ static void log_audio_status(struct cx18 *cx)
                case 0x07: p = "DUAL3 (AB)"; break;
                default: p = "undefined";
                }
-               CX18_INFO("Configured audio mode:     %s\n", p);
+               CX18_INFO_DEV(sd, "Configured audio mode:     %s\n", p);
        } else {
                switch (audio_config & 0xF) {
                case 0x00: p = "BG"; break;
@@ -1037,14 +1082,14 @@ static void log_audio_status(struct cx18 *cx)
                case 0x0f: p = "automatic standard and mode detection"; break;
                default: p = "undefined"; break;
                }
-               CX18_INFO("Configured audio system:   %s\n", p);
+               CX18_INFO_DEV(sd, "Configured audio system:   %s\n", p);
        }
 
        if (aud_input)
-               CX18_INFO("Specified audio input:     Tuner (In%d)\n",
-                               aud_input);
+               CX18_INFO_DEV(sd, "Specified audio input:     Tuner (In%d)\n",
+                             aud_input);
        else
-               CX18_INFO("Specified audio input:     External\n");
+               CX18_INFO_DEV(sd, "Specified audio input:     External\n");
 
        switch (pref_mode & 0xf) {
        case 0: p = "mono/language A"; break;
@@ -1057,14 +1102,14 @@ static void log_audio_status(struct cx18 *cx)
        case 7: p = "language AB"; break;
        default: p = "undefined"; break;
        }
-       CX18_INFO("Preferred audio mode:      %s\n", p);
+       CX18_INFO_DEV(sd, "Preferred audio mode:      %s\n", p);
 
        if ((audio_config & 0xf) == 0xf) {
                switch ((afc0 >> 3) & 0x1) {
                case 0: p = "system DK"; break;
                case 1: p = "system L"; break;
                }
-               CX18_INFO("Selected 65 MHz format:    %s\n", p);
+               CX18_INFO_DEV(sd, "Selected 65 MHz format:    %s\n", p);
 
                switch (afc0 & 0x7) {
                case 0: p = "Chroma"; break;
@@ -1074,6 +1119,131 @@ static void log_audio_status(struct cx18 *cx)
                case 4: p = "autodetect"; break;
                default: p = "undefined"; break;
                }
-               CX18_INFO("Selected 45 MHz format:    %s\n", p);
+               CX18_INFO_DEV(sd, "Selected 45 MHz format:    %s\n", p);
        }
 }
+
+static int cx18_av_log_status(struct v4l2_subdev *sd)
+{
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+       log_video_status(cx);
+       log_audio_status(cx);
+       return 0;
+}
+
+static inline int cx18_av_dbg_match(const struct v4l2_dbg_match *match)
+{
+       return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 1;
+}
+
+static int cx18_av_g_chip_ident(struct v4l2_subdev *sd,
+                               struct v4l2_dbg_chip_ident *chip)
+{
+       struct cx18_av_state *state = to_cx18_av_state(sd);
+
+       if (cx18_av_dbg_match(&chip->match)) {
+               chip->ident = state->id;
+               chip->revision = state->rev;
+       }
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int cx18_av_g_register(struct v4l2_subdev *sd,
+                             struct v4l2_dbg_register *reg)
+{
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+       if (!cx18_av_dbg_match(&reg->match))
+               return -EINVAL;
+       if ((reg->reg & 0x3) != 0)
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       reg->size = 4;
+       reg->val = cx18_av_read4(cx, reg->reg & 0x00000ffc);
+       return 0;
+}
+
+static int cx18_av_s_register(struct v4l2_subdev *sd,
+                             struct v4l2_dbg_register *reg)
+{
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+       if (!cx18_av_dbg_match(&reg->match))
+               return -EINVAL;
+       if ((reg->reg & 0x3) != 0)
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       cx18_av_write4(cx, reg->reg & 0x00000ffc, reg->val);
+       return 0;
+}
+#endif
+
+static const struct v4l2_subdev_core_ops cx18_av_general_ops = {
+       .g_chip_ident = cx18_av_g_chip_ident,
+       .log_status = cx18_av_log_status,
+       .init = cx18_av_init,
+       .reset = cx18_av_reset,
+       .queryctrl = cx18_av_queryctrl,
+       .g_ctrl = cx18_av_g_ctrl,
+       .s_ctrl = cx18_av_s_ctrl,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = cx18_av_g_register,
+       .s_register = cx18_av_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops cx18_av_tuner_ops = {
+       .s_radio = cx18_av_s_radio,
+       .s_frequency = cx18_av_s_frequency,
+       .g_tuner = cx18_av_g_tuner,
+       .s_tuner = cx18_av_s_tuner,
+       .s_std = cx18_av_s_std,
+};
+
+static const struct v4l2_subdev_audio_ops cx18_av_audio_ops = {
+       .s_clock_freq = cx18_av_s_clock_freq,
+       .s_routing = cx18_av_s_audio_routing,
+};
+
+static const struct v4l2_subdev_video_ops cx18_av_video_ops = {
+       .s_routing = cx18_av_s_video_routing,
+       .decode_vbi_line = cx18_av_decode_vbi_line,
+       .s_stream = cx18_av_s_stream,
+       .g_fmt = cx18_av_g_fmt,
+       .s_fmt = cx18_av_s_fmt,
+};
+
+static const struct v4l2_subdev_ops cx18_av_ops = {
+       .core = &cx18_av_general_ops,
+       .tuner = &cx18_av_tuner_ops,
+       .audio = &cx18_av_audio_ops,
+       .video = &cx18_av_video_ops,
+};
+
+int cx18_av_probe(struct cx18 *cx)
+{
+       struct cx18_av_state *state = &cx->av_state;
+       struct v4l2_subdev *sd;
+
+       state->rev = cx18_av_read4(cx, CXADEC_CHIP_CTRL) & 0xffff;
+       state->id = ((state->rev >> 4) == CXADEC_CHIP_TYPE_MAKO)
+                   ? V4L2_IDENT_CX23418_843 : V4L2_IDENT_UNKNOWN;
+
+       state->vid_input = CX18_AV_COMPOSITE7;
+       state->aud_input = CX18_AV_AUDIO8;
+       state->audclk_freq = 48000;
+       state->audmode = V4L2_TUNER_MODE_LANG1;
+       state->slicer_line_delay = 0;
+       state->slicer_line_offset = (10 + state->slicer_line_delay - 2);
+
+       sd = &state->sd;
+       v4l2_subdev_init(sd, &cx18_av_ops);
+       v4l2_set_subdevdata(sd, cx);
+       snprintf(sd->name, sizeof(sd->name),
+                "%s %03x", cx->v4l2_dev.name, (state->rev >> 4));
+       sd->grp_id = CX18_HW_418_AV;
+       return v4l2_device_register_subdev(&cx->v4l2_dev, sd);
+}
index cf68a6039091a7dc684249ef5953ba651aec985c..c458120e8c90e509f71d99b110ca47a72b009721 100644 (file)
@@ -25,6 +25,8 @@
 #ifndef _CX18_AV_CORE_H_
 #define _CX18_AV_CORE_H_
 
+#include <media/v4l2-device.h>
+
 struct cx18;
 
 enum cx18_av_video_input {
@@ -73,17 +75,40 @@ enum cx18_av_audio_input {
 };
 
 struct cx18_av_state {
+       struct v4l2_subdev sd;
        int radio;
        v4l2_std_id std;
        enum cx18_av_video_input vid_input;
        enum cx18_av_audio_input aud_input;
        u32 audclk_freq;
        int audmode;
-       int vbi_line_offset;
        int default_volume;
        u32 id;
        u32 rev;
        int is_initialized;
+
+       /*
+        * The VBI slicer starts operating and counting lines, begining at
+        * slicer line count of 1, at D lines after the deassertion of VRESET.
+        * This staring field line, S, is 6 (& 319) or 10 (& 273) for 625 or 525
+        * line systems respectively.  Sliced ancillary data captured on VBI
+        * slicer line M is inserted after the VBI slicer is done with line M,
+        * when VBI slicer line count is N = M+1.  Thus when the VBI slicer
+        * reports a VBI slicer line number with ancillary data, the IDID0 byte
+        * indicates VBI slicer line N.  The actual field line that the captured
+        * data comes from is
+        *
+        * L = M+(S+D-1) = N-1+(S+D-1) = N + (S+D-2).
+        *
+        * L is the line in the field, not frame, from which the VBI data came.
+        * N is the line reported by the slicer in the ancillary data.
+        * D is the slicer_line_delay value programmed into register 0x47f.
+        * S is 6 for 625 line systems or 10 for 525 line systems
+        * (S+D-2) is the slicer_line_offset used to convert slicer reported
+        * line counts to actual field lines.
+        */
+       int slicer_line_delay;
+       int slicer_line_offset;
 };
 
 
@@ -298,6 +323,16 @@ struct cx18_av_state {
 #define CXADEC_SELECT_AUDIO_STANDARD_FM    0xF9  /* FM radio */
 #define CXADEC_SELECT_AUDIO_STANDARD_AUTO  0xFF  /* Auto detect */
 
+static inline struct cx18_av_state *to_cx18_av_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct cx18_av_state, sd);
+}
+
+enum cx18_av_subdev_init_arg {
+       CX18_AV_INIT_NORMAL = 0,
+       CX18_AV_INIT_PLLS = 1,
+};
+
 /* ----------------------------------------------------------------------- */
 /* cx18_av-core.c                                                         */
 int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
@@ -310,20 +345,26 @@ u8 cx18_av_read(struct cx18 *cx, u16 addr);
 u32 cx18_av_read4(struct cx18 *cx, u16 addr);
 int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
 int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
-int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
 void cx18_av_std_setup(struct cx18 *cx);
 
+int cx18_av_probe(struct cx18 *cx);
+
 /* ----------------------------------------------------------------------- */
 /* cx18_av-firmware.c                                                      */
 int cx18_av_loadfw(struct cx18 *cx);
 
 /* ----------------------------------------------------------------------- */
 /* cx18_av-audio.c                                                         */
-int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg);
+int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl);
+int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl);
+int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
 void cx18_av_audio_set_path(struct cx18 *cx);
 
 /* ----------------------------------------------------------------------- */
 /* cx18_av-vbi.c                                                           */
-int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg);
+int cx18_av_decode_vbi_line(struct v4l2_subdev *sd,
+                          struct v4l2_decode_vbi_line *vbi);
+int cx18_av_vbi_g_fmt(struct cx18 *cx, struct v4l2_format *fmt);
+int cx18_av_vbi_s_fmt(struct cx18 *cx, struct v4l2_format *fmt);
 
 #endif
index c64fd0a05a9773c9e1eeb67cbba887fd7287601f..49a55cc8d839af13bbbe3dca43c06dd70a443220 100644 (file)
@@ -29,6 +29,7 @@
 
 int cx18_av_loadfw(struct cx18 *cx)
 {
+       struct v4l2_subdev *sd = &cx->av_state.sd;
        const struct firmware *fw = NULL;
        u32 size;
        u32 v;
@@ -36,8 +37,8 @@ int cx18_av_loadfw(struct cx18 *cx)
        int i;
        int retries1 = 0;
 
-       if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
-               CX18_ERR("unable to open firmware %s\n", FWFILE);
+       if (request_firmware(&fw, FWFILE, &cx->pci_dev->dev) != 0) {
+               CX18_ERR_DEV(sd, "unable to open firmware %s\n", FWFILE);
                return -EINVAL;
        }
 
@@ -88,7 +89,7 @@ int cx18_av_loadfw(struct cx18 *cx)
                retries1++;
        }
        if (retries1 >= 5) {
-               CX18_ERR("unable to load firmware %s\n", FWFILE);
+               CX18_ERR_DEV(sd, "unable to load firmware %s\n", FWFILE);
                release_firmware(fw);
                return -EIO;
        }
@@ -115,9 +116,9 @@ int cx18_av_loadfw(struct cx18 *cx)
           are generated) */
        cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0);
 
-       /* set alt I2s master clock to /16 and enable alt divider i2s
+       /* set alt I2s master clock to /0x16 and enable alt divider i2s
           passthrough */
-       cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687);
+       cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5600B687);
 
        cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, 0x000000F6, 0x000000F6,
                                                                  0x3F00FFFF);
@@ -131,7 +132,8 @@ int cx18_av_loadfw(struct cx18 *cx)
        v = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
        /* If bit 11 is 1, clear bit 10 */
        if (v & 0x800)
-               cx18_write_reg(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE);
+               cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE,
+                                     0, 0x400);
 
        /* Enable WW auto audio standard detection */
        v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
@@ -142,6 +144,6 @@ int cx18_av_loadfw(struct cx18 *cx)
 
        release_firmware(fw);
 
-       CX18_INFO("loaded %s firmware (%d bytes)\n", FWFILE, size);
+       CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size);
        return 0;
 }
index 1527ea4f6b06b83be93e4cdadc6eb9d73537c677..23b31670bf1dbc9143028ac2b68b78a1fb6844a1 100644 (file)
 
 #include "cx18-driver.h"
 
+/*
+ * For sliced VBI output, we set up to use VIP-1.1, 8-bit mode,
+ * NN counts 1 byte Dwords, an IDID with the VBI line # in it.
+ * Thus, according to the VIP-2 Spec, our VBI ancillary data lines
+ * (should!) look like:
+ *     4 byte EAV code:          0xff 0x00 0x00 0xRP
+ *     unknown number of possible idle bytes
+ *     3 byte Anc data preamble: 0x00 0xff 0xff
+ *     1 byte data identifier:   ne010iii (parity bits, 010, DID bits)
+ *     1 byte secondary data id: nessssss (parity bits, SDID bits)
+ *     1 byte data word count:   necccccc (parity bits, NN Dword count)
+ *     2 byte Internal DID:      VBI-line-# 0x80
+ *     NN data bytes
+ *     1 byte checksum
+ *     Fill bytes needed to fil out to 4*NN bytes of payload
+ *
+ * The RP codes for EAVs when in VIP-1.1 mode, not in raw mode, &
+ * in the vertical blanking interval are:
+ *     0xb0 (Task         0 VerticalBlank HorizontalBlank 0 0 0 0)
+ *     0xf0 (Task EvenField VerticalBlank HorizontalBlank 0 0 0 0)
+ *
+ * Since the V bit is only allowed to toggle in the EAV RP code, just
+ * before the first active region line and for active lines, they are:
+ *     0x90 (Task         0 0 HorizontalBlank 0 0 0 0)
+ *     0xd0 (Task EvenField 0 HorizontalBlank 0 0 0 0)
+ *
+ * The user application DID bytes we care about are:
+ *     0x91 (1 0 010        0 !ActiveLine AncDataPresent)
+ *     0x55 (0 1 010 2ndField !ActiveLine AncDataPresent)
+ *
+ */
+static const u8 sliced_vbi_did[2] = { 0x91, 0x55 };
+
+struct vbi_anc_data {
+       /* u8 eav[4]; */
+       /* u8 idle[]; Variable number of idle bytes */
+       u8 preamble[3];
+       u8 did;
+       u8 sdid;
+       u8 data_count;
+       u8 idid[2];
+       u8 payload[1]; /* data_count of payload */
+       /* u8 checksum; */
+       /* u8 fill[]; Variable number of fill bytes */
+};
+
 static int odd_parity(u8 c)
 {
        c ^= (c >> 4);
@@ -83,188 +129,189 @@ static int decode_vps(u8 *dst, u8 *p)
        return err & 0xf0;
 }
 
-int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
+int cx18_av_vbi_g_fmt(struct cx18 *cx, struct v4l2_format *fmt)
 {
        struct cx18_av_state *state = &cx->av_state;
-       struct v4l2_format *fmt;
        struct v4l2_sliced_vbi_format *svbi;
+       static const u16 lcr2vbi[] = {
+               0, V4L2_SLICED_TELETEXT_B, 0,   /* 1 */
+               0, V4L2_SLICED_WSS_625, 0,      /* 4 */
+               V4L2_SLICED_CAPTION_525,        /* 6 */
+               0, 0, V4L2_SLICED_VPS, 0, 0,    /* 9 */
+               0, 0, 0, 0
+       };
+       int is_pal = !(state->std & V4L2_STD_525_60);
+       int i;
 
-       switch (cmd) {
-       case VIDIOC_G_FMT:
-       {
-               static u16 lcr2vbi[] = {
-                       0, V4L2_SLICED_TELETEXT_B, 0,   /* 1 */
-                       0, V4L2_SLICED_WSS_625, 0,      /* 4 */
-                       V4L2_SLICED_CAPTION_525,        /* 6 */
-                       0, 0, V4L2_SLICED_VPS, 0, 0,    /* 9 */
-                       0, 0, 0, 0
-               };
-               int is_pal = !(state->std & V4L2_STD_525_60);
-               int i;
-
-               fmt = arg;
-               if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
-                       return -EINVAL;
-               svbi = &fmt->fmt.sliced;
-               memset(svbi, 0, sizeof(*svbi));
-               /* we're done if raw VBI is active */
-               if ((cx18_av_read(cx, 0x404) & 0x10) == 0)
-                       break;
-
-               if (is_pal) {
-                       for (i = 7; i <= 23; i++) {
-                               u8 v = cx18_av_read(cx, 0x424 + i - 7);
-
-                               svbi->service_lines[0][i] = lcr2vbi[v >> 4];
-                               svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
-                               svbi->service_set |= svbi->service_lines[0][i] |
-                                       svbi->service_lines[1][i];
-                       }
-               } else {
-                       for (i = 10; i <= 21; i++) {
-                               u8 v = cx18_av_read(cx, 0x424 + i - 10);
-
-                               svbi->service_lines[0][i] = lcr2vbi[v >> 4];
-                               svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
-                               svbi->service_set |= svbi->service_lines[0][i] |
-                                       svbi->service_lines[1][i];
-                       }
-               }
-               break;
-       }
+       if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+               return -EINVAL;
+       svbi = &fmt->fmt.sliced;
+       memset(svbi, 0, sizeof(*svbi));
+       /* we're done if raw VBI is active */
+       if ((cx18_av_read(cx, 0x404) & 0x10) == 0)
+               return 0;
 
-       case VIDIOC_S_FMT:
-       {
-               int is_pal = !(state->std & V4L2_STD_525_60);
-               int vbi_offset = is_pal ? 1 : 0;
-               int i, x;
-               u8 lcr[24];
-
-               fmt = arg;
-               if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
-                   fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
-                       return -EINVAL;
-               svbi = &fmt->fmt.sliced;
-               if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-                       /* raw VBI */
-                       memset(svbi, 0, sizeof(*svbi));
-
-                       /* Setup standard */
-                       cx18_av_std_setup(cx);
-
-                       /* VBI Offset */
-                       cx18_av_write(cx, 0x47f, vbi_offset);
-                       cx18_av_write(cx, 0x404, 0x2e);
-                       break;
+       if (is_pal) {
+               for (i = 7; i <= 23; i++) {
+                       u8 v = cx18_av_read(cx, 0x424 + i - 7);
+
+                       svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+                       svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+                       svbi->service_set |= svbi->service_lines[0][i] |
+                               svbi->service_lines[1][i];
+               }
+       } else {
+               for (i = 10; i <= 21; i++) {
+                       u8 v = cx18_av_read(cx, 0x424 + i - 10);
+
+                       svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+                       svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+                       svbi->service_set |= svbi->service_lines[0][i] |
+                               svbi->service_lines[1][i];
                }
+       }
+       return 0;
+}
 
-               for (x = 0; x <= 23; x++)
-                       lcr[x] = 0x00;
+int cx18_av_vbi_s_fmt(struct cx18 *cx, struct v4l2_format *fmt)
+{
+       struct cx18_av_state *state = &cx->av_state;
+       struct v4l2_sliced_vbi_format *svbi;
+       int is_pal = !(state->std & V4L2_STD_525_60);
+       int i, x;
+       u8 lcr[24];
+
+       if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
+                       fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
+               return -EINVAL;
+       svbi = &fmt->fmt.sliced;
+       if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               /* raw VBI */
+               memset(svbi, 0, sizeof(*svbi));
 
                /* Setup standard */
                cx18_av_std_setup(cx);
 
-               /* Sliced VBI */
-               cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */
-               cx18_av_write(cx, 0x406, 0x13);
-               cx18_av_write(cx, 0x47f, vbi_offset);
-
-               if (is_pal) {
-                       for (i = 0; i <= 6; i++)
-                               svbi->service_lines[0][i] =
-                                       svbi->service_lines[1][i] = 0;
-               } else {
-                       for (i = 0; i <= 9; i++)
-                               svbi->service_lines[0][i] =
-                                       svbi->service_lines[1][i] = 0;
-
-                       for (i = 22; i <= 23; i++)
-                               svbi->service_lines[0][i] =
-                                       svbi->service_lines[1][i] = 0;
-               }
+               /* VBI Offset */
+               cx18_av_write(cx, 0x47f, state->slicer_line_delay);
+               cx18_av_write(cx, 0x404, 0x2e);
+               return 0;
+       }
 
-               for (i = 7; i <= 23; i++) {
-                       for (x = 0; x <= 1; x++) {
-                               switch (svbi->service_lines[1-x][i]) {
-                               case V4L2_SLICED_TELETEXT_B:
-                                       lcr[i] |= 1 << (4 * x);
-                                       break;
-                               case V4L2_SLICED_WSS_625:
-                                       lcr[i] |= 4 << (4 * x);
-                                       break;
-                               case V4L2_SLICED_CAPTION_525:
-                                       lcr[i] |= 6 << (4 * x);
-                                       break;
-                               case V4L2_SLICED_VPS:
-                                       lcr[i] |= 9 << (4 * x);
-                                       break;
-                               }
-                       }
-               }
+       for (x = 0; x <= 23; x++)
+               lcr[x] = 0x00;
+
+       /* Setup standard */
+       cx18_av_std_setup(cx);
+
+       /* Sliced VBI */
+       cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */
+       cx18_av_write(cx, 0x406, 0x13);
+       cx18_av_write(cx, 0x47f, state->slicer_line_delay);
+
+       /* Force impossible lines to 0 */
+       if (is_pal) {
+               for (i = 0; i <= 6; i++)
+                       svbi->service_lines[0][i] =
+                               svbi->service_lines[1][i] = 0;
+       } else {
+               for (i = 0; i <= 9; i++)
+                       svbi->service_lines[0][i] =
+                               svbi->service_lines[1][i] = 0;
+
+               for (i = 22; i <= 23; i++)
+                       svbi->service_lines[0][i] =
+                               svbi->service_lines[1][i] = 0;
+       }
 
-               if (is_pal) {
-                       for (x = 1, i = 0x424; i <= 0x434; i++, x++)
-                               cx18_av_write(cx, i, lcr[6 + x]);
-               } else {
-                       for (x = 1, i = 0x424; i <= 0x430; i++, x++)
-                               cx18_av_write(cx, i, lcr[9 + x]);
-                       for (i = 0x431; i <= 0x434; i++)
-                               cx18_av_write(cx, i, 0);
+       /* Build register values for requested service lines */
+       for (i = 7; i <= 23; i++) {
+               for (x = 0; x <= 1; x++) {
+                       switch (svbi->service_lines[1-x][i]) {
+                       case V4L2_SLICED_TELETEXT_B:
+                               lcr[i] |= 1 << (4 * x);
+                               break;
+                       case V4L2_SLICED_WSS_625:
+                               lcr[i] |= 4 << (4 * x);
+                               break;
+                       case V4L2_SLICED_CAPTION_525:
+                               lcr[i] |= 6 << (4 * x);
+                               break;
+                       case V4L2_SLICED_VPS:
+                               lcr[i] |= 9 << (4 * x);
+                               break;
+                       }
                }
+       }
 
-               cx18_av_write(cx, 0x43c, 0x16);
-               cx18_av_write(cx, 0x474, is_pal ? 0x2a : 0x22);
-               break;
+       if (is_pal) {
+               for (x = 1, i = 0x424; i <= 0x434; i++, x++)
+                       cx18_av_write(cx, i, lcr[6 + x]);
+       } else {
+               for (x = 1, i = 0x424; i <= 0x430; i++, x++)
+                       cx18_av_write(cx, i, lcr[9 + x]);
+               for (i = 0x431; i <= 0x434; i++)
+                       cx18_av_write(cx, i, 0);
        }
 
-       case VIDIOC_INT_DECODE_VBI_LINE:
-       {
-               struct v4l2_decode_vbi_line *vbi = arg;
-               u8 *p = vbi->p;
-               int id1, id2, l, err = 0;
+       cx18_av_write(cx, 0x43c, 0x16);
+       /* FIXME - should match vblank set in cx18_av_std_setup() */
+       cx18_av_write(cx, 0x474, is_pal ? 0x2a : 26);
+       return 0;
+}
+
+int cx18_av_decode_vbi_line(struct v4l2_subdev *sd,
+                                  struct v4l2_decode_vbi_line *vbi)
+{
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+       struct cx18_av_state *state = &cx->av_state;
+       struct vbi_anc_data *anc = (struct vbi_anc_data *)vbi->p;
+       u8 *p;
+       int did, sdid, l, err = 0;
+
+       /*
+        * Check for the ancillary data header for sliced VBI
+        */
+       if (anc->preamble[0] ||
+                       anc->preamble[1] != 0xff || anc->preamble[2] != 0xff ||
+                       (anc->did != sliced_vbi_did[0] &&
+                        anc->did != sliced_vbi_did[1])) {
+               vbi->line = vbi->type = 0;
+               return 0;
+       }
 
-               if (p[0] || p[1] != 0xff || p[2] != 0xff ||
-                   (p[3] != 0x55 && p[3] != 0x91)) {
-                       vbi->line = vbi->type = 0;
-                       break;
-               }
+       did = anc->did;
+       sdid = anc->sdid & 0xf;
+       l = anc->idid[0] & 0x3f;
+       l += state->slicer_line_offset;
+       p = anc->payload;
 
-               p += 4;
-               id1 = p[-1];
-               id2 = p[0] & 0xf;
-               l = p[2] & 0x3f;
-               l += state->vbi_line_offset;
-               p += 4;
-
-               switch (id2) {
-               case 1:
-                       id2 = V4L2_SLICED_TELETEXT_B;
-                       break;
-               case 4:
-                       id2 = V4L2_SLICED_WSS_625;
-                       break;
-               case 6:
-                       id2 = V4L2_SLICED_CAPTION_525;
-                       err = !odd_parity(p[0]) || !odd_parity(p[1]);
-                       break;
-               case 9:
-                       id2 = V4L2_SLICED_VPS;
-                       if (decode_vps(p, p) != 0)
-                               err = 1;
-                       break;
-               default:
-                       id2 = 0;
+       /* Decode the SDID set by the slicer */
+       switch (sdid) {
+       case 1:
+               sdid = V4L2_SLICED_TELETEXT_B;
+               break;
+       case 4:
+               sdid = V4L2_SLICED_WSS_625;
+               break;
+       case 6:
+               sdid = V4L2_SLICED_CAPTION_525;
+               err = !odd_parity(p[0]) || !odd_parity(p[1]);
+               break;
+       case 9:
+               sdid = V4L2_SLICED_VPS;
+               if (decode_vps(p, p) != 0)
                        err = 1;
-                       break;
-               }
-
-               vbi->type = err ? 0 : id2;
-               vbi->line = err ? 0 : l;
-               vbi->is_second_field = err ? 0 : (id1 == 0x55);
-               vbi->p = p;
                break;
-       }
+       default:
+               sdid = 0;
+               err = 1;
+               break;
        }
 
+       vbi->type = err ? 0 : sdid;
+       vbi->line = err ? 0 : l;
+       vbi->is_second_field = err ? 0 : (did == sliced_vbi_did[1]);
+       vbi->p = p;
        return 0;
 }
index e274043657ddb01638b0c2155d1e4bb8ba84e7ee..9bc221837847675b1643c8b38459acedb1303483 100644 (file)
@@ -51,12 +51,12 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = {
 static const struct cx18_card cx18_card_hvr1600_esmt = {
        .type = CX18_CARD_HVR_1600_ESMT,
        .name = "Hauppauge HVR-1600",
-       .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
+       .comment = "Simultaneous Digital and Analog TV capture supported\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
-       .hw_audio_ctrl = CX18_HW_CX23418,
+       .hw_audio_ctrl = CX18_HW_418_AV,
        .hw_muxer = CX18_HW_CS5345,
-       .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER |
-                 CX18_HW_CS5345 | CX18_HW_DVB,
+       .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
+                 CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
        .video_inputs = {
                { CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE7 },
                { CX18_CARD_INPUT_SVIDEO1,    1, CX18_AV_SVIDEO1    },
@@ -97,12 +97,12 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
 static const struct cx18_card cx18_card_hvr1600_samsung = {
        .type = CX18_CARD_HVR_1600_SAMSUNG,
        .name = "Hauppauge HVR-1600 (Preproduction)",
-       .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
+       .comment = "Simultaneous Digital and Analog TV capture supported\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
-       .hw_audio_ctrl = CX18_HW_CX23418,
+       .hw_audio_ctrl = CX18_HW_418_AV,
        .hw_muxer = CX18_HW_CS5345,
-       .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER |
-                 CX18_HW_CS5345 | CX18_HW_DVB,
+       .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
+                 CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
        .video_inputs = {
                { CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE7 },
                { CX18_CARD_INPUT_SVIDEO1,    1, CX18_AV_SVIDEO1    },
@@ -152,10 +152,10 @@ static const struct cx18_card_pci_info cx18_pci_h900[] = {
 static const struct cx18_card cx18_card_h900 = {
        .type = CX18_CARD_COMPRO_H900,
        .name = "Compro VideoMate H900",
-       .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
+       .comment = "Analog TV capture supported\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
-       .hw_audio_ctrl = CX18_HW_CX23418,
-       .hw_all = CX18_HW_TUNER,
+       .hw_audio_ctrl = CX18_HW_418_AV,
+       .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL,
        .video_inputs = {
                { CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
                { CX18_CARD_INPUT_SVIDEO1,    1,
@@ -201,8 +201,8 @@ static const struct cx18_card cx18_card_mpc718 = {
        .name = "Yuan MPC718",
        .comment = "Analog video capture works; some audio line in may not.\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
-       .hw_audio_ctrl = CX18_HW_CX23418,
-       .hw_all = CX18_HW_TUNER,
+       .hw_audio_ctrl = CX18_HW_418_AV,
+       .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL,
        .video_inputs = {
                { CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
                { CX18_CARD_INPUT_SVIDEO1,    1,
@@ -249,11 +249,11 @@ static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = {
 static const struct cx18_card cx18_card_cnxt_raptor_pal = {
        .type = CX18_CARD_CNXT_RAPTOR_PAL,
        .name = "Conexant Raptor PAL/SECAM",
-       .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
+       .comment = "Analog TV capture supported\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
-       .hw_audio_ctrl = CX18_HW_CX23418,
-       .hw_muxer = CX18_HW_GPIO,
-       .hw_all = CX18_HW_TUNER | CX18_HW_GPIO,
+       .hw_audio_ctrl = CX18_HW_418_AV,
+       .hw_muxer = CX18_HW_GPIO_MUX,
+       .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX,
        .video_inputs = {
                { CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
                { CX18_CARD_INPUT_SVIDEO1,    1,
@@ -306,8 +306,8 @@ static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = {
        .comment = "Experimenters and photos needed for device to work well.\n"
                  "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
-       .hw_audio_ctrl = CX18_HW_CX23418,
-       .hw_all = CX18_HW_TUNER,
+       .hw_audio_ctrl = CX18_HW_418_AV,
+       .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL,
        .video_inputs = {
                { CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE6 },
                { CX18_CARD_INPUT_SVIDEO1,    1,
@@ -339,19 +339,21 @@ static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = {
 /* Leadtek WinFast PVR2100 */
 
 static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = {
-       { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 },
+       { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, /* PVR2100   */
+       { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */
        { 0, 0, 0 }
 };
 
 static const struct cx18_card cx18_card_leadtek_pvr2100 = {
        .type = CX18_CARD_LEADTEK_PVR2100,
-       .name = "Leadtek WinFast PVR2100",
+       .name = "Leadtek WinFast PVR2100/DVR3100 H",
        .comment = "Experimenters and photos needed for device to work well.\n"
                  "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
-       .hw_audio_ctrl = CX18_HW_CX23418,
-       .hw_muxer = CX18_HW_GPIO,
-       .hw_all = CX18_HW_TUNER | CX18_HW_GPIO,
+       .hw_audio_ctrl = CX18_HW_418_AV,
+       .hw_muxer = CX18_HW_GPIO_MUX,
+       .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX |
+                 CX18_HW_GPIO_RESET_CTRL,
        .video_inputs = {
                { CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
                { CX18_CARD_INPUT_SVIDEO1,    1,
index 6fa7bcb42dded2376e8b6ade7d29efba1d4c5de9..3c552b6b7c4d3baa43d7ae4850eea92fab72d396 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_GPIO      (1 << 3)
-#define CX18_HW_CX23418   (1 << 4)
-#define CX18_HW_DVB      (1 << 5)
+#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)
 
 /* video inputs */
 #define        CX18_CARD_INPUT_VID_TUNER       1
@@ -49,8 +50,7 @@
 /* V4L2 capability aliases */
 #define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
                          V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \
-                         V4L2_CAP_VBI_CAPTURE)
-/* | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
+                         V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)
 
 struct cx18_card_video_input {
        u8  video_type;         /* video input type */
@@ -122,7 +122,7 @@ struct cx18_card {
        char *comment;
        u32 v4l2_capabilities;
        u32 hw_audio_ctrl;      /* hardware used for the V4L2 controls (only
-                                  1 dev allowed) */
+                                  1 dev allowed currently) */
        u32 hw_muxer;           /* hardware used to multiplex audio input */
        u32 hw_all;             /* all hardware used by the board */
        struct cx18_card_video_input video_inputs[CX18_CARD_MAX_VIDEO_INPUTS];
index 17edf305d6499e7abcfc53b88c21627315f05443..82fc2f9d40219d3ff0075239597553a8909d930b 100644 (file)
  */
 
 #include "cx18-driver.h"
-#include "cx18-av-core.h"
 #include "cx18-cards.h"
 #include "cx18-ioctl.h"
 #include "cx18-audio.h"
-#include "cx18-i2c.h"
 #include "cx18-mailbox.h"
 #include "cx18-controls.h"
 
+/* Must be sorted from low to high control ID! */
 static const u32 user_ctrls[] = {
        V4L2_CID_USER_CLASS,
        V4L2_CID_BRIGHTNESS,
@@ -66,7 +65,7 @@ int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
        case V4L2_CID_HUE:
        case V4L2_CID_SATURATION:
        case V4L2_CID_CONTRAST:
-               if (cx18_av_cmd(cx, VIDIOC_QUERYCTRL, qctrl))
+               if (v4l2_subdev_call(cx->sd_av, core, queryctrl, qctrl))
                        qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
                return 0;
 
@@ -76,7 +75,7 @@ int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
        case V4L2_CID_AUDIO_BASS:
        case V4L2_CID_AUDIO_TREBLE:
        case V4L2_CID_AUDIO_LOUDNESS:
-               if (cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl))
+               if (v4l2_subdev_call(cx->sd_av, core, queryctrl, qctrl))
                        qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
                return 0;
 
@@ -125,7 +124,7 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
        case V4L2_CID_HUE:
        case V4L2_CID_SATURATION:
        case V4L2_CID_CONTRAST:
-               return cx18_av_cmd(cx, VIDIOC_S_CTRL, vctrl);
+               return v4l2_subdev_call(cx->sd_av, core, s_ctrl, vctrl);
 
        case V4L2_CID_AUDIO_VOLUME:
        case V4L2_CID_AUDIO_MUTE:
@@ -133,7 +132,7 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
        case V4L2_CID_AUDIO_BASS:
        case V4L2_CID_AUDIO_TREBLE:
        case V4L2_CID_AUDIO_LOUDNESS:
-               return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
+               return v4l2_subdev_call(cx->sd_av, core, s_ctrl, vctrl);
 
        default:
                CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
@@ -150,7 +149,7 @@ static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
        case V4L2_CID_HUE:
        case V4L2_CID_SATURATION:
        case V4L2_CID_CONTRAST:
-               return cx18_av_cmd(cx, VIDIOC_G_CTRL, vctrl);
+               return v4l2_subdev_call(cx->sd_av, core, g_ctrl, vctrl);
 
        case V4L2_CID_AUDIO_VOLUME:
        case V4L2_CID_AUDIO_MUTE:
@@ -158,7 +157,8 @@ static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
        case V4L2_CID_AUDIO_BASS:
        case V4L2_CID_AUDIO_TREBLE:
        case V4L2_CID_AUDIO_LOUDNESS:
-               return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
+               return v4l2_subdev_call(cx->sd_av, core, g_ctrl, vctrl);
+
        default:
                CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
                return -EINVAL;
@@ -166,38 +166,57 @@ static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
        return 0;
 }
 
-static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt)
+static int cx18_setup_vbi_fmt(struct cx18 *cx,
+                             enum v4l2_mpeg_stream_vbi_fmt fmt,
+                             enum v4l2_mpeg_stream_type type)
 {
        if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
                return -EINVAL;
        if (atomic_read(&cx->ana_capturing) > 0)
                return -EBUSY;
 
-       /* First try to allocate sliced VBI buffers if needed. */
-       if (fmt && cx->vbi.sliced_mpeg_data[0] == NULL) {
+       if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV ||
+           type != V4L2_MPEG_STREAM_TYPE_MPEG2_PS) {
+               /* We don't do VBI insertion aside from IVTV format in a PS */
+               cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE;
+               CX18_DEBUG_INFO("disabled insertion of sliced VBI data into "
+                               "the MPEG stream\n");
+               return 0;
+       }
+
+       /* Allocate sliced VBI buffers if needed. */
+       if (cx->vbi.sliced_mpeg_data[0] == NULL) {
                int i;
 
                for (i = 0; i < CX18_VBI_FRAMES; i++) {
-                       /* Yuck, hardcoded. Needs to be a define */
-                       cx->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL);
+                       cx->vbi.sliced_mpeg_data[i] =
+                              kmalloc(CX18_SLICED_MPEG_DATA_BUFSZ, GFP_KERNEL);
                        if (cx->vbi.sliced_mpeg_data[i] == NULL) {
                                while (--i >= 0) {
                                        kfree(cx->vbi.sliced_mpeg_data[i]);
                                        cx->vbi.sliced_mpeg_data[i] = NULL;
                                }
+                               cx->vbi.insert_mpeg =
+                                                 V4L2_MPEG_STREAM_VBI_FMT_NONE;
+                               CX18_WARN("Unable to allocate buffers for "
+                                         "sliced VBI data insertion\n");
                                return -ENOMEM;
                        }
                }
        }
 
        cx->vbi.insert_mpeg = fmt;
+       CX18_DEBUG_INFO("enabled insertion of sliced VBI data into the MPEG PS,"
+                       "when sliced VBI is enabled\n");
 
-       if (cx->vbi.insert_mpeg == 0)
-               return 0;
-       /* Need sliced data for mpeg insertion */
+       /*
+        * If our current settings have no lines set for capture, store a valid,
+        * default set of service lines to capture, in our current settings.
+        */
        if (cx18_get_service_set(cx->vbi.sliced_in) == 0) {
                if (cx->is_60hz)
-                       cx->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525;
+                       cx->vbi.sliced_in->service_set =
+                                                       V4L2_SLICED_CAPTION_525;
                else
                        cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
                cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz);
@@ -259,10 +278,12 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
                return err;
        }
        if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+               static u32 freqs[3] = { 44100, 48000, 32000 };
                struct cx18_api_func_private priv;
                struct cx2341x_mpeg_params p = cx->params;
                int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing),
                                                c, VIDIOC_S_EXT_CTRLS);
+               unsigned int idx;
 
                if (err)
                        return err;
@@ -277,16 +298,23 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
                        fmt.fmt.pix.width = cx->params.width
                                                / (is_mpeg1 ? 2 : 1);
                        fmt.fmt.pix.height = cx->params.height;
-                       cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
+                       v4l2_subdev_call(cx->sd_av, video, s_fmt, &fmt);
                }
                priv.cx = cx;
                priv.s = &cx->streams[id->type];
                err = cx2341x_update(&priv, cx18_api_func, &cx->params, &p);
-               if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
-                       err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
+               if (!err &&
+                   (cx->params.stream_vbi_fmt != p.stream_vbi_fmt ||
+                    cx->params.stream_type != p.stream_type))
+                       err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt,
+                                                p.stream_type);
                cx->params = p;
                cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
-               cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
+               idx = p.audio_properties & 0x03;
+               /* The audio clock of the digitizer must match the codec sample
+                  rate otherwise you get some very strange effects. */
+               if (idx < sizeof(freqs))
+                       cx18_call_all(cx, audio, s_clock_freq, freqs[idx]);
                return err;
        }
        return -EINVAL;
index f50cf2167adc1a6082789aef840915a53142f9f6..210c68aaae00ede73af85a4804b156e246a8fe6c 100644 (file)
 
 #include <media/tveeprom.h>
 
-
-/* var to keep track of the number of array elements in use */
-int cx18_cards_active;
-
 /* If you have already X v4l cards, then set this to X. This way
    the device numbers stay matched. Example: you have a WinTV card
    without radio and a Compro H900 with. Normally this would give a
@@ -50,12 +46,6 @@ int cx18_cards_active;
    setting this to 1 you ensure that radio0 is now also radio1. */
 int cx18_first_minor;
 
-/* Master variable for all cx18 info */
-struct cx18 *cx18_cards[CX18_MAX_CARDS];
-
-/* Protects cx18_cards_active */
-DEFINE_SPINLOCK(cx18_cards_lock);
-
 /* add your revision and whatnot here */
 static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
        {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
@@ -65,6 +55,8 @@ static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
 
 MODULE_DEVICE_TABLE(pci, cx18_pci_tbl);
 
+static atomic_t cx18_instance = ATOMIC_INIT(0);
+
 /* Parameter declarations */
 static int cardtype[CX18_MAX_CARDS];
 static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
@@ -159,7 +151,7 @@ MODULE_PARM_DESC(cardtype,
                 "\t\t\t 4 = Yuan MPC718\n"
                 "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
                 "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
-                "\t\t\t 7 = Leadtek WinFast PVR2100\n"
+                "\t\t\t 7 = Leadtek WinFast PVR2100/DVR3100 H\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: B, G, H, D, K, I, M, N, Nc, 60");
@@ -277,11 +269,16 @@ static void cx18_iounmap(struct cx18 *cx)
 /* Hauppauge card? get values from tveeprom */
 void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
 {
+       struct i2c_client c;
        u8 eedata[256];
 
-       cx->i2c_client[0].addr = 0xA0 >> 1;
-       tveeprom_read(&cx->i2c_client[0], eedata, sizeof(eedata));
-       tveeprom_hauppauge_analog(&cx->i2c_client[0], tv, eedata);
+       memset(&c, 0, sizeof(c));
+       strlcpy(c.name, "cx18 tveeprom tmp", sizeof(c.name));
+       c.adapter = &cx->i2c_adap[0];
+       c.addr = 0xA0 >> 1;
+
+       tveeprom_read(&c, eedata, sizeof(eedata));
+       tveeprom_hauppauge_analog(&c, tv, eedata);
 }
 
 static void cx18_process_eeprom(struct cx18 *cx)
@@ -448,34 +445,38 @@ static void cx18_process_options(struct cx18 *cx)
        cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize;
        cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize;
        cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize;
-       cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = 0; /* computed later */
+       cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_active_samples * 36;
        cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize;
        cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */
 
-       /* Except for VBI ensure stream_buffers & stream_buf_size are valid */
+       /* Ensure stream_buffers & stream_buf_size are valid */
        for (i = 0; i < CX18_MAX_STREAMS; i++) {
-               /* User said to use 0 buffers */
-               if (cx->stream_buffers[i] == 0) {
-                       cx->options.megabytes[i] = 0;
-                       cx->stream_buf_size[i] = 0;
-                       continue;
-               }
-               /* User said to use 0 MB total */
-               if (cx->options.megabytes[i] <= 0) {
+               if (cx->stream_buffers[i] == 0 ||     /* User said 0 buffers */
+                   cx->options.megabytes[i] <= 0 ||  /* User said 0 MB total */
+                   cx->stream_buf_size[i] <= 0) {    /* User said buf size 0 */
                        cx->options.megabytes[i] = 0;
                        cx->stream_buffers[i] = 0;
                        cx->stream_buf_size[i] = 0;
                        continue;
                }
-               /* VBI is computed later or user said buffer has size 0 */
-               if (cx->stream_buf_size[i] <= 0) {
-                       if (i != CX18_ENC_STREAM_TYPE_VBI) {
-                               cx->options.megabytes[i] = 0;
-                               cx->stream_buffers[i] = 0;
-                               cx->stream_buf_size[i] = 0;
+               /*
+                * VBI is a special case where the stream_buf_size is fixed
+                * and already in bytes
+                */
+               if (i == CX18_ENC_STREAM_TYPE_VBI) {
+                       if (cx->stream_buffers[i] < 0) {
+                               cx->stream_buffers[i] =
+                                       cx->options.megabytes[i] * 1024 * 1024
+                                       / cx->stream_buf_size[i];
+                       } else {
+                               /* N.B. This might round down to 0 */
+                               cx->options.megabytes[i] =
+                                       cx->stream_buffers[i]
+                                       * cx->stream_buf_size[i]/(1024 * 1024);
                        }
                        continue;
                }
+               /* All other streams have stream_buf_size in kB at this point */
                if (cx->stream_buffers[i] < 0) {
                        cx->stream_buffers[i] = cx->options.megabytes[i] * 1024
                                                / cx->stream_buf_size[i];
@@ -487,9 +488,9 @@ static void cx18_process_options(struct cx18 *cx)
                cx->stream_buf_size[i] *= 1024; /* convert from kB to bytes */
        }
 
-       cx->options.cardtype = cardtype[cx->num];
-       cx->options.tuner = tuner[cx->num];
-       cx->options.radio = radio[cx->num];
+       cx->options.cardtype = cardtype[cx->instance];
+       cx->options.tuner = tuner[cx->instance];
+       cx->options.radio = radio[cx->instance];
 
        cx->std = cx18_parse_std(cx);
        if (cx->options.cardtype == -1) {
@@ -502,7 +503,7 @@ static void cx18_process_options(struct cx18 *cx)
        else if (cx->options.cardtype != 0)
                CX18_ERR("Unknown user specified type, trying to autodetect card\n");
        if (cx->card == NULL) {
-               if (cx->dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) {
+               if (cx->pci_dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) {
                        cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
                        CX18_INFO("Autodetected Hauppauge card\n");
                }
@@ -512,13 +513,13 @@ static void cx18_process_options(struct cx18 *cx)
                        if (cx->card->pci_list == NULL)
                                continue;
                        for (j = 0; cx->card->pci_list[j].device; j++) {
-                               if (cx->dev->device !=
+                               if (cx->pci_dev->device !=
                                    cx->card->pci_list[j].device)
                                        continue;
-                               if (cx->dev->subsystem_vendor !=
+                               if (cx->pci_dev->subsystem_vendor !=
                                    cx->card->pci_list[j].subsystem_vendor)
                                        continue;
-                               if (cx->dev->subsystem_device !=
+                               if (cx->pci_dev->subsystem_device !=
                                    cx->card->pci_list[j].subsystem_device)
                                        continue;
                                CX18_INFO("Autodetected %s card\n", cx->card->name);
@@ -531,9 +532,10 @@ done:
        if (cx->card == NULL) {
                cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
                CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n",
-                    cx->dev->vendor, cx->dev->device);
+                        cx->pci_dev->vendor, cx->pci_dev->device);
                CX18_ERR("              subsystem vendor/device: [%04x:%04x]\n",
-                    cx->dev->subsystem_vendor, cx->dev->subsystem_device);
+                        cx->pci_dev->subsystem_vendor,
+                        cx->pci_dev->subsystem_device);
                CX18_ERR("Defaulting to %s card\n", cx->card->name);
                CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
                CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n");
@@ -545,7 +547,7 @@ done:
 }
 
 /* Precondition: the cx18 structure has been memset to 0. Only
-   the dev and num fields have been filled in.
+   the dev and instance fields have been filled in.
    No assumptions on the card type may be made here (see cx18_init_struct2
    for that).
  */
@@ -553,18 +555,14 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
 {
        int i;
 
-       cx->base_addr = pci_resource_start(cx->dev, 0);
+       cx->base_addr = pci_resource_start(cx->pci_dev, 0);
 
        mutex_init(&cx->serialize_lock);
-       mutex_init(&cx->i2c_bus_lock[0]);
-       mutex_init(&cx->i2c_bus_lock[1]);
        mutex_init(&cx->gpio_lock);
        mutex_init(&cx->epu2apu_mb_lock);
        mutex_init(&cx->epu2cpu_mb_lock);
 
-       spin_lock_init(&cx->lock);
-
-       cx->work_queue = create_singlethread_workqueue(cx->name);
+       cx->work_queue = create_singlethread_workqueue(cx->v4l2_dev.name);
        if (cx->work_queue == NULL) {
                CX18_ERR("Unable to create work hander thread\n");
                return -ENOMEM;
@@ -587,7 +585,8 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
                (cx->params.video_temporal_filter_mode << 1) |
                (cx->params.video_median_filter_type << 2);
        cx->params.port = CX2341X_PORT_MEMORY;
-       cx->params.capabilities = CX2341X_CAP_HAS_TS;
+       cx->params.capabilities =
+                               CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI;
        init_waitqueue_head(&cx->cap_w);
        init_waitqueue_head(&cx->mb_apu_waitq);
        init_waitqueue_head(&cx->mb_cpu_waitq);
@@ -597,49 +596,6 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
        cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
        cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
 
-       /*
-        * The VBI line sizes depend on the pixel clock and the horiz rate
-        *
-        * (1/Fh)*(2*Fp) = Samples/line
-        *     = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples
-        *
-        *  Sliced VBI is sent as ancillary data during horizontal blanking
-        *  Raw VBI is sent as active video samples during vertcal blanking
-        *
-        *  We use a  BT.656 pxiel clock of 13.5 MHz and a BT.656 active line
-        *  length of 720 pixels @ 4:2:2 sampling.  Thus...
-        *
-        *  For systems that use a 15.734 kHz horizontal rate, such as
-        *  NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have:
-        *
-        *  (1/15.734 kHz) * 2 * 13.5 MHz = 1716 samples/line =
-        *  4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples
-        *
-        *  For systems that use a 15.625 kHz horizontal rate, such as
-        *  PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have:
-        *
-        *  (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line =
-        *  4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples
-        *
-        */
-
-       /* FIXME: init these based on tuner std & modify when std changes */
-       /* CX18-AV-Core number of VBI samples output per horizontal line */
-       cx->vbi.raw_decoder_line_size = 1444;   /* 4 byte SAV + 2 * 720 */
-       cx->vbi.sliced_decoder_line_size = 272; /* 60 Hz: 268+4, 50 Hz: 280+4 */
-
-       /* CX18-AV-Core VBI samples/line possibly rounded up */
-       cx->vbi.raw_size = 1444;   /* Real max size is 1444 */
-       cx->vbi.sliced_size = 284; /* Real max size is  284 */
-
-       /*
-        * CX18-AV-Core SAV/EAV RP codes in VIP 1.x mode
-        * Task Field VerticalBlank HorizontalBlank 0 0 0 0
-        */
-       cx->vbi.raw_decoder_sav_odd_field = 0x20;     /*   V  */
-       cx->vbi.raw_decoder_sav_even_field = 0x60;    /*  FV  */
-       cx->vbi.sliced_decoder_sav_odd_field = 0xB0;  /* T VH - actually EAV */
-       cx->vbi.sliced_decoder_sav_even_field = 0xF0; /* TFVH - actually EAV */
        return 0;
 }
 
@@ -668,15 +624,9 @@ static void __devinit cx18_init_struct2(struct cx18 *cx)
                i = 0;
        cx->active_input = i;
        cx->audio_input = cx->card->video_inputs[i].audio_index;
-       cx->av_state.vid_input = CX18_AV_COMPOSITE7;
-       cx->av_state.aud_input = CX18_AV_AUDIO8;
-       cx->av_state.audclk_freq = 48000;
-       cx->av_state.audmode = V4L2_TUNER_MODE_LANG1;
-       /* FIXME - 8 is NTSC value, investigate */
-       cx->av_state.vbi_line_offset = 8;
 }
 
-static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev,
+static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
                          const struct pci_device_id *pci_id)
 {
        u16 cmd;
@@ -684,124 +634,125 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev,
 
        CX18_DEBUG_INFO("Enabling pci device\n");
 
-       if (pci_enable_device(dev)) {
-               CX18_ERR("Can't enable device %d!\n", cx->num);
+       if (pci_enable_device(pci_dev)) {
+               CX18_ERR("Can't enable device %d!\n", cx->instance);
                return -EIO;
        }
-       if (pci_set_dma_mask(dev, 0xffffffff)) {
-               CX18_ERR("No suitable DMA available on card %d.\n", cx->num);
+       if (pci_set_dma_mask(pci_dev, 0xffffffff)) {
+               CX18_ERR("No suitable DMA available, card %d\n", cx->instance);
                return -EIO;
        }
        if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) {
-               CX18_ERR("Cannot request encoder memory region on card %d.\n", cx->num);
+               CX18_ERR("Cannot request encoder memory region, card %d\n",
+                        cx->instance);
                return -EIO;
        }
 
        /* Enable bus mastering and memory mapped IO for the CX23418 */
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       pci_read_config_word(pci_dev, PCI_COMMAND, &cmd);
        cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
-       pci_write_config_word(dev, PCI_COMMAND, cmd);
+       pci_write_config_word(pci_dev, PCI_COMMAND, cmd);
 
-       pci_read_config_byte(dev, PCI_CLASS_REVISION, &cx->card_rev);
-       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
+       pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &cx->card_rev);
+       pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);
 
        if (pci_latency < 64 && cx18_pci_latency) {
                CX18_INFO("Unreasonably low latency timer, "
                               "setting to 64 (was %d)\n", pci_latency);
-               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
-               pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
+               pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, 64);
+               pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);
        }
 
        CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, "
                   "irq: %d, latency: %d, memory: 0x%lx\n",
-                  cx->dev->device, cx->card_rev, dev->bus->number,
-                  PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
-                  cx->dev->irq, pci_latency, (unsigned long)cx->base_addr);
+                  cx->pci_dev->device, cx->card_rev, pci_dev->bus->number,
+                  PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn),
+                  cx->pci_dev->irq, pci_latency, (unsigned long)cx->base_addr);
 
        return 0;
 }
 
-#ifdef MODULE
-static u32 cx18_request_module(struct cx18 *cx, u32 hw,
-               const char *name, u32 id)
-{
-       if ((hw & id) == 0)
-               return hw;
-       if (request_module(name) != 0) {
-               CX18_ERR("Failed to load module %s\n", name);
-               return hw & ~id;
-       }
-       CX18_DEBUG_INFO("Loaded module %s\n", name);
-       return hw;
-}
-#endif
-
-static void cx18_load_and_init_modules(struct cx18 *cx)
+static void cx18_init_subdevs(struct cx18 *cx)
 {
        u32 hw = cx->card->hw_all;
+       u32 device;
        int i;
 
-#ifdef MODULE
-       /* load modules */
-#ifdef CONFIG_MEDIA_TUNER_MODULE
-       hw = cx18_request_module(cx, hw, "tuner", CX18_HW_TUNER);
-#endif
-#ifdef CONFIG_VIDEO_CS5345_MODULE
-       hw = cx18_request_module(cx, hw, "cs5345", CX18_HW_CS5345);
-#endif
-#endif
-
-       /* check which i2c devices are actually found */
-       for (i = 0; i < 32; i++) {
-               u32 device = 1 << i;
+       for (i = 0, device = 1; i < 32; i++, device <<= 1) {
 
                if (!(device & hw))
                        continue;
-               if (device == CX18_HW_GPIO || device == CX18_HW_TVEEPROM ||
-                   device == CX18_HW_CX23418 || device == CX18_HW_DVB) {
-                       /* These 'devices' do not use i2c probing */
+
+               switch (device) {
+               case CX18_HW_DVB:
+               case CX18_HW_TVEEPROM:
+                       /* These subordinate devices do not use probing */
                        cx->hw_flags |= device;
-                       continue;
-               }
-               cx18_i2c_register(cx, i);
-               if (cx18_i2c_hw_addr(cx, device) > 0)
+                       break;
+               case CX18_HW_418_AV:
+                       /* The A/V decoder gets probed earlier to set PLLs */
+                       /* Just note that the card uses it (i.e. has analog) */
                        cx->hw_flags |= device;
+                       break;
+               case CX18_HW_GPIO_RESET_CTRL:
+                       /*
+                        * The Reset Controller gets probed and added to
+                        * hw_flags earlier for i2c adapter/bus initialization
+                        */
+                       break;
+               case CX18_HW_GPIO_MUX:
+                       if (cx18_gpio_register(cx, device) == 0)
+                               cx->hw_flags |= device;
+                       break;
+               default:
+                       if (cx18_i2c_register(cx, i) == 0)
+                               cx->hw_flags |= device;
+                       break;
+               }
        }
 
-       hw = cx->hw_flags;
+       if (cx->hw_flags & CX18_HW_418_AV)
+               cx->sd_av = cx18_find_hw(cx, CX18_HW_418_AV);
+
+       if (cx->card->hw_muxer != 0)
+               cx->sd_extmux = cx18_find_hw(cx, cx->card->hw_muxer);
 }
 
-static int __devinit cx18_probe(struct pci_dev *dev,
+static int __devinit cx18_probe(struct pci_dev *pci_dev,
                                const struct pci_device_id *pci_id)
 {
        int retval = 0;
        int i;
-       int vbi_buf_size;
        u32 devtype;
        struct cx18 *cx;
 
-       spin_lock(&cx18_cards_lock);
-
-       /* Make sure we've got a place for this card */
-       if (cx18_cards_active == CX18_MAX_CARDS) {
-               printk(KERN_ERR "cx18:  Maximum number of cards detected (%d).\n",
-                             cx18_cards_active);
-               spin_unlock(&cx18_cards_lock);
+       /* FIXME - module parameter arrays constrain max instances */
+       i = atomic_inc_return(&cx18_instance) - 1;
+       if (i >= CX18_MAX_CARDS) {
+               printk(KERN_ERR "cx18: cannot manage card %d, driver has a "
+                      "limit of 0 - %d\n", i, CX18_MAX_CARDS - 1);
                return -ENOMEM;
        }
 
        cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC);
-       if (!cx) {
-               spin_unlock(&cx18_cards_lock);
+       if (cx == NULL) {
+               printk(KERN_ERR "cx18: cannot manage card %d, out of memory\n",
+                      i);
                return -ENOMEM;
        }
-       cx18_cards[cx18_cards_active] = cx;
-       cx->dev = dev;
-       cx->num = cx18_cards_active++;
-       snprintf(cx->name, sizeof(cx->name), "cx18-%d", cx->num);
-       CX18_INFO("Initializing card #%d\n", cx->num);
+       cx->pci_dev = pci_dev;
+       cx->instance = i;
 
-       spin_unlock(&cx18_cards_lock);
+       retval = v4l2_device_register(&pci_dev->dev, &cx->v4l2_dev);
+       if (retval) {
+               printk(KERN_ERR "cx18: v4l2_device_register of card %d failed"
+                      "\n", cx->instance);
+               kfree(cx);
+               return retval;
+       }
+       snprintf(cx->v4l2_dev.name, sizeof(cx->v4l2_dev.name), "cx18-%d",
+                cx->instance);
+       CX18_INFO("Initializing card %d\n", cx->instance);
 
        cx18_process_options(cx);
        if (cx->options.cardtype == -1) {
@@ -816,13 +767,10 @@ static int __devinit cx18_probe(struct pci_dev *dev,
        CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr);
 
        /* PCI Device Setup */
-       retval = cx18_setup_pci(cx, dev, pci_id);
+       retval = cx18_setup_pci(cx, pci_dev, pci_id);
        if (retval != 0)
                goto free_workqueue;
 
-       /* save cx in the pci struct for later use */
-       pci_set_drvdata(dev, cx);
-
        /* map io memory */
        CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
                   cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE);
@@ -856,6 +804,23 @@ static int __devinit cx18_probe(struct pci_dev *dev,
 
        cx18_gpio_init(cx);
 
+       /* Initialize integrated A/V decoder early to set PLLs, just in case */
+       retval = cx18_av_probe(cx);
+       if (retval) {
+               CX18_ERR("Could not register A/V decoder subdevice\n");
+               goto free_map;
+       }
+       cx18_call_hw(cx, CX18_HW_418_AV, core, init, (u32) CX18_AV_INIT_PLLS);
+
+       /* Initialize GPIO Reset Controller to do chip resets during i2c init */
+       if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) {
+               if (cx18_gpio_register(cx, CX18_HW_GPIO_RESET_CTRL) != 0)
+                       CX18_WARN("Could not register GPIO reset controller"
+                                 "subdevice; proceeding anyway.\n");
+               else
+                       cx->hw_flags |= CX18_HW_GPIO_RESET_CTRL;
+       }
+
        /* active i2c  */
        CX18_DEBUG_INFO("activating i2c...\n");
        retval = init_cx18_i2c(cx);
@@ -864,8 +829,6 @@ static int __devinit cx18_probe(struct pci_dev *dev,
                goto free_map;
        }
 
-       CX18_DEBUG_INFO("Active card count: %d.\n", cx18_cards_active);
-
        if (cx->card->hw_all & CX18_HW_TVEEPROM) {
                /* Based on the model number the cardtype may be changed.
                   The PCI IDs are not always reliable. */
@@ -881,8 +844,9 @@ static int __devinit cx18_probe(struct pci_dev *dev,
        cx18_init_scb(cx);
 
        /* Register IRQ */
-       retval = request_irq(cx->dev->irq, cx18_irq_handler,
-                            IRQF_SHARED | IRQF_DISABLED, cx->name, (void *)cx);
+       retval = request_irq(cx->pci_dev->irq, cx18_irq_handler,
+                            IRQF_SHARED | IRQF_DISABLED,
+                            cx->v4l2_dev.name, (void *)cx);
        if (retval) {
                CX18_ERR("Failed to register irq %d\n", retval);
                goto free_i2c;
@@ -917,33 +881,14 @@ static int __devinit cx18_probe(struct pci_dev *dev,
           initialization. */
        cx18_init_struct2(cx);
 
-       cx18_load_and_init_modules(cx);
+       cx18_init_subdevs(cx);
 
-       if (cx->std & V4L2_STD_525_60) {
+       if (cx->std & V4L2_STD_525_60)
                cx->is_60hz = 1;
-               cx->is_out_60hz = 1;
-       } else {
+       else
                cx->is_50hz = 1;
-               cx->is_out_50hz = 1;
-       }
-       cx->params.video_gop_size = cx->is_60hz ? 15 : 12;
-
-       /*
-        * FIXME: setting the buffer size based on the tuner standard is
-        * suboptimal, as the CVBS and SVideo inputs could use a different std
-        * and the buffer could end up being too small in that case.
-        */
-       vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2;
-       cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size;
 
-       if (cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] < 0)
-               cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] =
-                  cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] * 1024 * 1024
-                  / vbi_buf_size;
-       else
-               cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] =
-                    cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] * vbi_buf_size
-                    / (1024 * 1024);
+       cx->params.video_gop_size = cx->is_60hz ? 15 : 12;
 
        if (cx->options.radio > 0)
                cx->v4l2_cap |= V4L2_CAP_RADIO;
@@ -956,7 +901,7 @@ static int __devinit cx18_probe(struct pci_dev *dev,
                setup.mode_mask = T_ANALOG_TV;  /* matches TV tuners */
                setup.tuner_callback = (setup.type == TUNER_XC2028) ?
                        cx18_reset_tuner_gpio : NULL;
-               cx18_call_i2c_clients(cx, TUNER_SET_TYPE_ADDR, &setup);
+               cx18_call_all(cx, tuner, s_type_addr, &setup);
                if (setup.type == TUNER_XC2028) {
                        static struct xc2028_ctrl ctrl = {
                                .fname = XC2028_DEFAULT_FIRMWARE,
@@ -966,7 +911,7 @@ static int __devinit cx18_probe(struct pci_dev *dev,
                                .tuner = cx->options.tuner,
                                .priv = &ctrl,
                        };
-                       cx18_call_i2c_clients(cx, TUNER_SET_CONFIG, &cfg);
+                       cx18_call_all(cx, tuner, s_config, &cfg);
                }
        }
 
@@ -985,14 +930,13 @@ static int __devinit cx18_probe(struct pci_dev *dev,
                goto free_streams;
        }
 
-       CX18_INFO("Initialized card #%d: %s\n", cx->num, cx->card_name);
-
+       CX18_INFO("Initialized card: %s\n", cx->card_name);
        return 0;
 
 free_streams:
        cx18_streams_cleanup(cx, 1);
 free_irq:
-       free_irq(cx->dev->irq, (void *)cx);
+       free_irq(cx->pci_dev->irq, (void *)cx);
 free_i2c:
        exit_cx18_i2c(cx);
 free_map:
@@ -1006,11 +950,8 @@ err:
                retval = -ENODEV;
        CX18_ERR("Error %d on initialization\n", retval);
 
-       i = cx->num;
-       spin_lock(&cx18_cards_lock);
-       kfree(cx18_cards[i]);
-       cx18_cards[i] = NULL;
-       spin_unlock(&cx18_cards_lock);
+       v4l2_device_unregister(&cx->v4l2_dev);
+       kfree(cx);
        return retval;
 }
 
@@ -1043,8 +984,21 @@ int cx18_init_on_first_open(struct cx18 *cx)
        }
        set_bit(CX18_F_I_LOADED_FW, &cx->i_flags);
 
-       /* Init the firmware twice to work around a silicon bug
-        * transport related. */
+       /*
+        * Init the firmware twice to work around a silicon bug
+        * with the digital TS.
+        *
+        * The second firmware load requires us to normalize the APU state,
+        * or the audio for the first analog capture will be badly incorrect.
+        *
+        * I can't seem to call APU_RESETAI and have it succeed without the
+        * APU capturing audio, so we start and stop it here to do the reset
+        */
+
+       /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */
+       cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0);
+       cx18_vapi(cx, CX18_APU_RESETAI, 0);
+       cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG);
 
        fw_retry_count = 3;
        while (--fw_retry_count > 0) {
@@ -1060,6 +1014,22 @@ int cx18_init_on_first_open(struct cx18 *cx)
                return -ENXIO;
        }
 
+       /*
+        * The second firmware load requires us to normalize the APU state,
+        * or the audio for the first analog capture will be badly incorrect.
+        *
+        * I can't seem to call APU_RESETAI and have it succeed without the
+        * APU capturing audio, so we start and stop it here to do the reset
+        */
+
+       /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */
+       cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0);
+       cx18_vapi(cx, CX18_APU_RESETAI, 0);
+       cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG);
+
+       /* Init the A/V decoder, if it hasn't been already */
+       v4l2_subdev_call(cx->sd_av, core, init, (u32) CX18_AV_INIT_NORMAL);
+
        vf.tuner = 0;
        vf.type = V4L2_TUNER_ANALOG_TV;
        vf.frequency = 6400; /* the tuner 'baseline' frequency */
@@ -1092,9 +1062,11 @@ static void cx18_cancel_epu_work_orders(struct cx18 *cx)
 
 static void cx18_remove(struct pci_dev *pci_dev)
 {
-       struct cx18 *cx = pci_get_drvdata(pci_dev);
+       struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+       struct cx18 *cx = to_cx18(v4l2_dev);
+       int i;
 
-       CX18_DEBUG_INFO("Removing Card #%d\n", cx->num);
+       CX18_DEBUG_INFO("Removing Card\n");
 
        /* Stop all captures */
        CX18_DEBUG_INFO("Stopping all streams\n");
@@ -1115,15 +1087,22 @@ static void cx18_remove(struct pci_dev *pci_dev)
 
        exit_cx18_i2c(cx);
 
-       free_irq(cx->dev->irq, (void *)cx);
+       free_irq(cx->pci_dev->irq, (void *)cx);
 
        cx18_iounmap(cx);
 
        release_mem_region(cx->base_addr, CX18_MEM_SIZE);
 
-       pci_disable_device(cx->dev);
+       pci_disable_device(cx->pci_dev);
+
+       if (cx->vbi.sliced_mpeg_data[0] != NULL)
+               for (i = 0; i < CX18_VBI_FRAMES; i++)
+                       kfree(cx->vbi.sliced_mpeg_data[i]);
+
+       CX18_INFO("Removed %s\n", cx->card_name);
 
-       CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num);
+       v4l2_device_unregister(v4l2_dev);
+       kfree(cx);
 }
 
 /* define a pci_driver for card detection */
@@ -1138,8 +1117,6 @@ static int module_start(void)
 {
        printk(KERN_INFO "cx18:  Start initialization, version %s\n", CX18_VERSION);
 
-       memset(cx18_cards, 0, sizeof(cx18_cards));
-
        /* Validate parameters */
        if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) {
                printk(KERN_ERR "cx18:  Exiting, cx18_first_minor must be between 0 and %d\n",
@@ -1162,16 +1139,7 @@ static int module_start(void)
 
 static void module_cleanup(void)
 {
-       int i;
-
        pci_unregister_driver(&cx18_pci_driver);
-
-       for (i = 0; i < cx18_cards_active; i++) {
-               if (cx18_cards[i] == NULL)
-                       continue;
-               kfree(cx18_cards[i]);
-       }
-
 }
 
 module_init(module_start);
index 0d2edebc39b4e199ca3cf5c1c1a20b0cc11580d0..ece4f281ef4254df1ec84b5bcc8676c316f84061 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/dvb/audio.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
 #include <media/tuner.h>
 #include "cx18-mailbox.h"
 #include "cx18-av-core.h"
@@ -79,7 +80,7 @@
 #define CX18_CARD_YUAN_MPC718        3 /* Yuan MPC718 */
 #define CX18_CARD_CNXT_RAPTOR_PAL     4        /* Conexant Raptor PAL */
 #define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/
-#define CX18_CARD_LEADTEK_PVR2100     6 /* Leadtek WinFast PVR2100 */
+#define CX18_CARD_LEADTEK_PVR2100     6 /* Leadtek WinFast PVR2100/DVR3100 H */
 #define CX18_CARD_LAST                       6
 
 #define CX18_ENC_STREAM_TYPE_MPG  0
 /* Flag to turn on high volume debugging */
 #define CX18_DBGFLG_HIGHVOL (1 << 8)
 
-/* NOTE: extra space before comma in 'cx->num , ## args' is required for
+/* NOTE: extra space before comma in 'fmt , ## args' is required for
    gcc-2.95, otherwise it won't compile. */
 #define CX18_DEBUG(x, type, fmt, args...) \
        do { \
                if ((x) & cx18_debug) \
-                       printk(KERN_INFO "cx18-%d " type ": " fmt, cx->num , ## args); \
+                       v4l2_info(&cx->v4l2_dev, " " type ": " fmt , ## args); \
        } while (0)
 #define CX18_DEBUG_WARN(fmt, args...)  CX18_DEBUG(CX18_DBGFLG_WARN, "warning", fmt , ## args)
 #define CX18_DEBUG_INFO(fmt, args...)  CX18_DEBUG(CX18_DBGFLG_INFO, "info", fmt , ## args)
 #define CX18_DEBUG_HIGH_VOL(x, type, fmt, args...) \
        do { \
                if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \
-                       printk(KERN_INFO "cx18%d " type ": " fmt, cx->num , ## args); \
+                       v4l2_info(&cx->v4l2_dev, " " type ": " fmt , ## args); \
        } while (0)
 #define CX18_DEBUG_HI_WARN(fmt, args...)  CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_WARN, "warning", fmt , ## args)
 #define CX18_DEBUG_HI_INFO(fmt, args...)  CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_INFO, "info", fmt , ## args)
 #define CX18_DEBUG_HI_IRQ(fmt, args...)   CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IRQ, "irq", fmt , ## args)
 
 /* Standard kernel messages */
-#define CX18_ERR(fmt, args...)      printk(KERN_ERR  "cx18-%d: " fmt, cx->num , ## args)
-#define CX18_WARN(fmt, args...)     printk(KERN_WARNING "cx18-%d: " fmt, cx->num , ## args)
-#define CX18_INFO(fmt, args...)     printk(KERN_INFO "cx18-%d: " fmt, cx->num , ## args)
+#define CX18_ERR(fmt, args...)      v4l2_err(&cx->v4l2_dev, fmt , ## args)
+#define CX18_WARN(fmt, args...)     v4l2_warn(&cx->v4l2_dev, fmt , ## args)
+#define CX18_INFO(fmt, args...)     v4l2_info(&cx->v4l2_dev, fmt , ## args)
+
+/* Messages for internal subdevs to use */
+#define CX18_DEBUG_DEV(x, dev, type, fmt, args...) \
+       do { \
+               if ((x) & cx18_debug) \
+                       v4l2_info(dev, " " type ": " fmt , ## args); \
+       } while (0)
+#define CX18_DEBUG_WARN_DEV(dev, fmt, args...) \
+               CX18_DEBUG_DEV(CX18_DBGFLG_WARN, dev, "warning", fmt , ## args)
+#define CX18_DEBUG_INFO_DEV(dev, fmt, args...) \
+               CX18_DEBUG_DEV(CX18_DBGFLG_INFO, dev, "info", fmt , ## args)
+#define CX18_DEBUG_API_DEV(dev, fmt, args...) \
+               CX18_DEBUG_DEV(CX18_DBGFLG_API, dev, "api", fmt , ## args)
+#define CX18_DEBUG_DMA_DEV(dev, fmt, args...) \
+               CX18_DEBUG_DEV(CX18_DBGFLG_DMA, dev, "dma", fmt , ## args)
+#define CX18_DEBUG_IOCTL_DEV(dev, fmt, args...) \
+               CX18_DEBUG_DEV(CX18_DBGFLG_IOCTL, dev, "ioctl", fmt , ## args)
+#define CX18_DEBUG_FILE_DEV(dev, fmt, args...) \
+               CX18_DEBUG_DEV(CX18_DBGFLG_FILE, dev, "file", fmt , ## args)
+#define CX18_DEBUG_I2C_DEV(dev, fmt, args...) \
+               CX18_DEBUG_DEV(CX18_DBGFLG_I2C, dev, "i2c", fmt , ## args)
+#define CX18_DEBUG_IRQ_DEV(dev, fmt, args...) \
+               CX18_DEBUG_DEV(CX18_DBGFLG_IRQ, dev, "irq", fmt , ## args)
+
+#define CX18_DEBUG_HIGH_VOL_DEV(x, dev, type, fmt, args...) \
+       do { \
+               if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \
+                       v4l2_info(dev, " " type ": " fmt , ## args); \
+       } while (0)
+#define CX18_DEBUG_HI_WARN_DEV(dev, fmt, args...) \
+       CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_WARN, dev, "warning", fmt , ## args)
+#define CX18_DEBUG_HI_INFO_DEV(dev, fmt, args...) \
+       CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_INFO, dev, "info", fmt , ## args)
+#define CX18_DEBUG_HI_API_DEV(dev, fmt, args...) \
+       CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_API, dev, "api", fmt , ## args)
+#define CX18_DEBUG_HI_DMA_DEV(dev, fmt, args...) \
+       CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_DMA, dev, "dma", fmt , ## args)
+#define CX18_DEBUG_HI_IOCTL_DEV(dev, fmt, args...) \
+       CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_IOCTL, dev, "ioctl", fmt , ## args)
+#define CX18_DEBUG_HI_FILE_DEV(dev, fmt, args...) \
+       CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_FILE, dev, "file", fmt , ## args)
+#define CX18_DEBUG_HI_I2C_DEV(dev, fmt, args...) \
+       CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_I2C, dev, "i2c", fmt , ## args)
+#define CX18_DEBUG_HI_IRQ_DEV(dev, fmt, args...) \
+       CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_IRQ, dev, "irq", fmt , ## args)
+
+#define CX18_ERR_DEV(dev, fmt, args...)      v4l2_err(dev, fmt , ## args)
+#define CX18_WARN_DEV(dev, fmt, args...)     v4l2_warn(dev, fmt , ## args)
+#define CX18_INFO_DEV(dev, fmt, args...)     v4l2_info(dev, fmt , ## args)
 
 /* Values for CX18_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */
 #define MPEG_FRAME_TYPE_IFRAME 1
@@ -279,7 +329,7 @@ struct cx18_epu_work_order {
 struct cx18_stream {
        /* These first four fields are always set, even if the stream
           is not actually created. */
-       struct video_device *v4l2dev;   /* NULL when stream not created */
+       struct video_device *video_dev; /* NULL when stream not created */
        struct cx18 *cx;                /* for ease of use */
        const char *name;               /* name of the stream */
        int type;                       /* stream type */
@@ -292,7 +342,6 @@ struct cx18_stream {
        int dma;                /* can be PCI_DMA_TODEVICE,
                                   PCI_DMA_FROMDEVICE or
                                   PCI_DMA_NONE */
-       u64 dma_pts;
        wait_queue_head_t waitq;
 
        /* Buffer Stats */
@@ -318,59 +367,121 @@ struct cx18_open_id {
 /* forward declaration of struct defined in cx18-cards.h */
 struct cx18_card;
 
+/*
+ * A note about "sliced" VBI data as implemented in this driver:
+ *
+ * Currently we collect the sliced VBI in the form of Ancillary Data
+ * packets, inserted by the AV core decoder/digitizer/slicer in the
+ * horizontal blanking region of the VBI lines, in "raw" mode as far as
+ * the Encoder is concerned.  We don't ever tell the Encoder itself
+ * to provide sliced VBI. (AV Core: sliced mode - Encoder: raw mode)
+ *
+ * We then process the ancillary data ourselves to send the sliced data
+ * to the user application directly or build up MPEG-2 private stream 1
+ * packets to splice into (only!) MPEG-2 PS streams for the user app.
+ *
+ * (That's how ivtv essentially does it.)
+ *
+ * The Encoder should be able to extract certain sliced VBI data for
+ * us and provide it in a separate stream or splice it into any type of
+ * MPEG PS or TS stream, but this isn't implemented yet.
+ */
+
+/*
+ * Number of "raw" VBI samples per horizontal line we tell the Encoder to
+ * grab from the decoder/digitizer/slicer output for raw or sliced VBI.
+ * It depends on the pixel clock and the horiz rate:
+ *
+ * (1/Fh)*(2*Fp) = Samples/line
+ *     = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples
+ *
+ *  Sliced VBI data is sent as ancillary data during horizontal blanking
+ *  Raw VBI is sent as active video samples during vertcal blanking
+ *
+ *  We use a  BT.656 pxiel clock of 13.5 MHz and a BT.656 active line
+ *  length of 720 pixels @ 4:2:2 sampling.  Thus...
+ *
+ *  For systems that use a 15.734 kHz horizontal rate, such as
+ *  NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have:
+ *
+ *  (1/15.734 kHz) * 2 * 13.5 MHz = 1716 samples/line =
+ *  4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples
+ *
+ *  For systems that use a 15.625 kHz horizontal rate, such as
+ *  PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have:
+ *
+ *  (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line =
+ *  4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples
+ */
+static const u32 vbi_active_samples = 1444; /* 4 byte SAV + 720 Y + 720 U/V */
+static const u32 vbi_hblank_samples_60Hz = 272; /* 4 byte EAV + 268 anc/fill */
+static const u32 vbi_hblank_samples_50Hz = 284; /* 4 byte EAV + 280 anc/fill */
 
 #define CX18_VBI_FRAMES 32
 
-/* VBI data */
 struct vbi_info {
-       u32 enc_size;
-       u32 frame;
-       u8 cc_data_odd[256];
-       u8 cc_data_even[256];
-       int cc_pos;
-       u8 cc_no_update;
-       u8 vps[5];
-       u8 vps_found;
-       int wss;
-       u8 wss_found;
-       u8 wss_no_update;
-       u32 raw_decoder_line_size;
-       u8 raw_decoder_sav_odd_field;
-       u8 raw_decoder_sav_even_field;
-       u32 sliced_decoder_line_size;
-       u8 sliced_decoder_sav_odd_field;
-       u8 sliced_decoder_sav_even_field;
+       /* Current state of v4l2 VBI settings for this device */
        struct v4l2_format in;
-       /* convenience pointer to sliced struct in vbi_in union */
-       struct v4l2_sliced_vbi_format *sliced_in;
-       u32 service_set_in;
-       int insert_mpeg;
+       struct v4l2_sliced_vbi_format *sliced_in; /* pointer to in.fmt.sliced */
+       u32 count;    /* Count of VBI data lines: 60 Hz: 12 or 50 Hz: 18 */
+       u32 start[2]; /* First VBI data line per field: 10 & 273 or 6 & 318 */
 
-       /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
-          One for /dev/vbi0 and one for /dev/vbi8 */
-       struct v4l2_sliced_vbi_data sliced_data[36];
+       u32 frame; /* Count of VBI buffers/frames received from Encoder */
 
-       /* Buffer for VBI data inserted into MPEG stream.
-          The first byte is a dummy byte that's never used.
-          The next 16 bytes contain the MPEG header for the VBI data,
-          the remainder is the actual VBI data.
-          The max size accepted by the MPEG VBI reinsertion turns out
-          to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes,
-          where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is
-          a single line header byte and 2 * 18 is the number of VBI lines per frame.
+       /*
+        * Vars for creation and insertion of MPEG Private Stream 1 packets
+        * of sliced VBI data into an MPEG PS
+        */
 
-          However, it seems that the data must be 1K aligned, so we have to
-          pad the data until the 1 or 2 K boundary.
+       /* Boolean: create and insert Private Stream 1 packets into the PS */
+       int insert_mpeg;
+
+       /*
+        * Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
+        * Used in cx18-vbi.c only for collecting sliced data, and as a source
+        * during conversion of sliced VBI data into MPEG Priv Stream 1 packets.
+        * We don't need to save state here, but the array may have been a bit
+        * too big (2304 bytes) to alloc from the stack.
+        */
+       struct v4l2_sliced_vbi_data sliced_data[36];
 
-          This pointer array will allocate 2049 bytes to store each VBI frame. */
+       /*
+        * A ring buffer of driver-generated MPEG-2 PS
+        * Program Pack/Private Stream 1 packets for sliced VBI data insertion
+        * into the MPEG PS stream.
+        *
+        * In each sliced_mpeg_data[] buffer is:
+        *      16 byte MPEG-2 PS Program Pack Header
+        *      16 byte MPEG-2 Private Stream 1 PES Header
+        *       4 byte magic number: "itv0" or "ITV0"
+        *       4 byte first  field line mask, if "itv0"
+        *       4 byte second field line mask, if "itv0"
+        *      36 lines, if "ITV0"; or <36 lines, if "itv0"; of sliced VBI data
+        *
+        *      Each line in the payload is
+        *       1 byte line header derived from the SDID (WSS, CC, VPS, etc.)
+        *      42 bytes of line data
+        *
+        * That's a maximum 1552 bytes of payload in the Private Stream 1 packet
+        * which is the payload size a PVR-350 (CX23415) MPEG decoder will
+        * accept for VBI data. So, including the headers, it's a maximum 1584
+        * bytes total.
+        */
+#define CX18_SLICED_MPEG_DATA_MAXSZ    1584
+       /* copy_vbi_buf() needs 8 temp bytes on the end for the worst case */
+#define CX18_SLICED_MPEG_DATA_BUFSZ    (CX18_SLICED_MPEG_DATA_MAXSZ+8)
        u8 *sliced_mpeg_data[CX18_VBI_FRAMES];
        u32 sliced_mpeg_size[CX18_VBI_FRAMES];
-       struct cx18_buffer sliced_mpeg_buf;
+
+       /* Count of Program Pack/Program Stream 1 packets inserted into PS */
        u32 inserted_frame;
 
-       u32 start[2], count;
-       u32 raw_size;
-       u32 sliced_size;
+       /*
+        * A dummy driver stream transfer buffer with a copy of the next
+        * sliced_mpeg_data[] buffer for output to userland apps.
+        * Only used in cx18-fileops.c, but its state needs to persist at times.
+        */
+       struct cx18_buffer sliced_mpeg_buf;
 };
 
 /* Per cx23418, per I2C bus private algo callback data */
@@ -383,16 +494,17 @@ struct cx18_i2c_algo_callback_data {
 
 /* Struct to hold info about cx18 cards */
 struct cx18 {
-       int num;                /* board number, -1 during init! */
-       char name[8];           /* board name for printk and interrupts (e.g. 'cx180') */
-       struct pci_dev *dev;    /* PCI device */
+       int instance;
+       struct pci_dev *pci_dev;
+       struct v4l2_device v4l2_dev;
+       struct v4l2_subdev *sd_av;     /* A/V decoder/digitizer sub-device */
+       struct v4l2_subdev *sd_extmux; /* External multiplexer sub-dev */
+
        const struct cx18_card *card;   /* card information */
        const char *card_name;  /* full name of the card */
        const struct cx18_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
        u8 is_50hz;
        u8 is_60hz;
-       u8 is_out_50hz;
-       u8 is_out_60hz;
        u8 nof_inputs;          /* number of video inputs */
        u8 nof_audio_inputs;    /* number of audio inputs */
        u16 buffer_id;          /* buffer ID counter */
@@ -413,10 +525,7 @@ struct cx18 {
 
        /* dualwatch */
        unsigned long dualwatch_jiffies;
-       u16 dualwatch_stereo_mode;
-
-       /* Digitizer type */
-       int digitizer;          /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */
+       u32 dualwatch_stereo_mode;
 
        struct mutex serialize_lock;    /* mutex used to serialize open/close/start/stop/ioctl operations */
        struct cx18_options options;    /* User options */
@@ -426,7 +535,6 @@ struct cx18 {
        unsigned long i_flags;  /* global cx18 flags */
        atomic_t ana_capturing; /* count number of active analog capture streams */
        atomic_t tot_capturing; /* total count number of active capture streams */
-       spinlock_t lock;        /* lock access to this struct */
        int search_pack_header;
 
        int open_id;            /* incremented each time an open occurs, used as
@@ -468,30 +576,30 @@ struct cx18 {
        struct i2c_adapter i2c_adap[2];
        struct i2c_algo_bit_data i2c_algo[2];
        struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2];
-       struct i2c_client i2c_client[2];
-       struct mutex i2c_bus_lock[2];
-       struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];
 
        /* gpio */
        u32 gpio_dir;
        u32 gpio_val;
        struct mutex gpio_lock;
+       struct v4l2_subdev sd_gpiomux;
+       struct v4l2_subdev sd_resetctrl;
 
        /* v4l2 and User settings */
 
        /* codec settings */
        u32 audio_input;
        u32 active_input;
-       u32 active_output;
        v4l2_std_id std;
        v4l2_std_id tuner_std;  /* The norm of the tuner (fixed) */
 };
 
+static inline struct cx18 *to_cx18(struct v4l2_device *v4l2_dev)
+{
+       return container_of(v4l2_dev, struct cx18, v4l2_dev);
+}
+
 /* Globals */
-extern struct cx18 *cx18_cards[];
-extern int cx18_cards_active;
 extern int cx18_first_minor;
-extern spinlock_t cx18_cards_lock;
 
 /*==============Prototypes==================*/
 
@@ -511,4 +619,22 @@ static inline int cx18_raw_vbi(const struct cx18 *cx)
        return cx->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE;
 }
 
+/* Call the specified callback for all subdevs with a grp_id bit matching the
+ * mask in hw (if 0, then match them all). Ignore any errors. */
+#define cx18_call_hw(cx, hw, o, f, args...) \
+       __v4l2_device_call_subdevs(&(cx)->v4l2_dev, \
+                                  !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+
+#define cx18_call_all(cx, o, f, args...) cx18_call_hw(cx, 0, o, f , ##args)
+
+/* Call the specified callback for all subdevs with a grp_id bit matching the
+ * mask in hw (if 0, then match them all). If the callback returns an error
+ * other than 0 or -ENOIOCTLCMD, then return with that error code. */
+#define cx18_call_hw_err(cx, hw, o, f, args...) \
+       __v4l2_device_call_subdevs_until_err( \
+                  &(cx)->v4l2_dev, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+
+#define cx18_call_all_err(cx, o, f, args...) \
+       cx18_call_hw_err(cx, 0, o, f , ##args)
+
 #endif /* CX18_DRIVER_H */
index bd5e6f3fd4d0a0c041bc8b9fae6300790f89c4d5..3b86f57cd15af5148aa4ec0d1284c21218fdf6b9 100644 (file)
@@ -167,7 +167,7 @@ int cx18_dvb_register(struct cx18_stream *stream)
 
        ret = dvb_register_adapter(&dvb->dvb_adapter,
                        CX18_DRIVER_NAME,
-                       THIS_MODULE, &cx->dev->dev, adapter_nr);
+                       THIS_MODULE, &cx->pci_dev->dev, adapter_nr);
        if (ret < 0)
                goto err_out;
 
index 055f6e004b2dccd8d6daf7e877b23b07733bed2d..4d7d6d5a7f86d2f9f7aca66643a7ecceada91be3 100644 (file)
@@ -128,15 +128,15 @@ static void cx18_release_stream(struct cx18_stream *s)
 static void cx18_dualwatch(struct cx18 *cx)
 {
        struct v4l2_tuner vt;
-       u16 new_bitmap;
-       u16 new_stereo_mode;
-       const u16 stereo_mask = 0x0300;
-       const u16 dual = 0x0200;
+       u32 new_bitmap;
+       u32 new_stereo_mode;
+       const u32 stereo_mask = 0x0300;
+       const u32 dual = 0x0200;
        u32 h;
 
        new_stereo_mode = cx->params.audio_properties & stereo_mask;
        memset(&vt, 0, sizeof(vt));
-       cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, &vt);
+       cx18_call_all(cx, tuner, g_tuner, &vt);
        if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 &&
                        (vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
                new_stereo_mode = dual;
@@ -176,6 +176,8 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
        *err = 0;
        while (1) {
                if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
+                       /* Process pending program info updates and pending
+                          VBI data */
 
                        if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) {
                                cx->dualwatch_jiffies = jiffies;
@@ -186,7 +188,6 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
                                while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) {
                                        /* byteswap and process VBI data */
                                        cx18_process_vbi_data(cx, buf,
-                                                             s_vbi->dma_pts,
                                                              s_vbi->type);
                                        cx18_stream_put_buf_fw(s_vbi, buf);
                                }
@@ -207,8 +208,7 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
                                cx18_buf_swap(buf);
                        else {
                                /* byteswap and process VBI data */
-                               cx18_process_vbi_data(cx, buf,
-                                               s->dma_pts, s->type);
+                               cx18_process_vbi_data(cx, buf, s->type);
                        }
                        return buf;
                }
@@ -260,6 +260,20 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
                len = ucount;
        if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&
            !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) {
+               /*
+                * Try to find a good splice point in the PS, just before
+                * an MPEG-2 Program Pack start code, and provide only
+                * up to that point to the user, so it's easy to insert VBI data
+                * the next time around.
+                */
+               /* FIXME - This only works for an MPEG-2 PS, not a TS */
+               /*
+                * An MPEG-2 Program Stream (PS) is a series of
+                * MPEG-2 Program Packs terminated by an
+                * MPEG Program End Code after the last Program Pack.
+                * A Program Pack may hold a PS System Header packet and any
+                * number of Program Elementary Stream (PES) Packets
+                */
                const char *start = buf->buf + buf->readpos;
                const char *p = start + 1;
                const u8 *q;
@@ -267,38 +281,54 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
                int stuffing, i;
 
                while (start + len > p) {
+                       /* Scan for a 0 to find a potential MPEG-2 start code */
                        q = memchr(p, 0, start + len - p);
                        if (q == NULL)
                                break;
                        p = q + 1;
+                       /*
+                        * Keep looking if not a
+                        * MPEG-2 Pack header start code:  0x00 0x00 0x01 0xba
+                        * or MPEG-2 video PES start code: 0x00 0x00 0x01 0xe0
+                        */
                        if ((char *)q + 15 >= buf->buf + buf->bytesused ||
                            q[1] != 0 || q[2] != 1 || q[3] != ch)
                                continue;
+
+                       /* If expecting the primary video PES */
                        if (!cx->search_pack_header) {
+                               /* Continue if it couldn't be a PES packet */
                                if ((q[6] & 0xc0) != 0x80)
                                        continue;
-                               if (((q[7] & 0xc0) == 0x80 &&
-                                    (q[9] & 0xf0) == 0x20) ||
-                                   ((q[7] & 0xc0) == 0xc0 &&
-                                    (q[9] & 0xf0) == 0x30)) {
-                                       ch = 0xba;
+                               /* Check if a PTS or PTS & DTS follow */
+                               if (((q[7] & 0xc0) == 0x80 &&  /* PTS only */
+                                    (q[9] & 0xf0) == 0x20) || /* PTS only */
+                                   ((q[7] & 0xc0) == 0xc0 &&  /* PTS & DTS */
+                                    (q[9] & 0xf0) == 0x30)) { /* DTS follows */
+                                       /* Assume we found the video PES hdr */
+                                       ch = 0xba; /* next want a Program Pack*/
                                        cx->search_pack_header = 1;
-                                       p = q + 9;
+                                       p = q + 9; /* Skip this video PES hdr */
                                }
                                continue;
                        }
+
+                       /* We may have found a Program Pack start code */
+
+                       /* Get the count of stuffing bytes & verify them */
                        stuffing = q[13] & 7;
                        /* all stuffing bytes must be 0xff */
                        for (i = 0; i < stuffing; i++)
                                if (q[14 + i] != 0xff)
                                        break;
-                       if (i == stuffing &&
-                           (q[4] & 0xc4) == 0x44 &&
-                           (q[12] & 3) == 3 &&
-                           q[14 + stuffing] == 0 &&
+                       if (i == stuffing && /* right number of stuffing bytes*/
+                           (q[4] & 0xc4) == 0x44 && /* marker check */
+                           (q[12] & 3) == 3 &&  /* marker check */
+                           q[14 + stuffing] == 0 && /* PES Pack or Sys Hdr */
                            q[15 + stuffing] == 0 &&
                            q[16 + stuffing] == 1) {
-                               cx->search_pack_header = 0;
+                               /* We declare we actually found a Program Pack*/
+                               cx->search_pack_header = 0; /* expect vid PES */
                                len = (char *)q - start;
                                cx18_setup_sliced_vbi_buf(cx);
                                break;
@@ -578,7 +608,7 @@ int cx18_v4l2_close(struct file *filp)
                /* Mark that the radio is no longer in use */
                clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags);
                /* Switch tuner to TV */
-               cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
+               cx18_call_all(cx, tuner, s_std, cx->std);
                /* Select correct audio input (i.e. TV tuner or Line in) */
                cx18_audio_set_io(cx);
                if (atomic_read(&cx->ana_capturing) > 0) {
@@ -641,7 +671,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
                /* We have the radio */
                cx18_mute(cx);
                /* Switch tuner to radio */
-               cx18_call_i2c_clients(cx, AUDC_SET_RADIO, NULL);
+               cx18_call_all(cx, tuner, s_radio);
                /* Select the correct audio input (i.e. radio tuner) */
                cx18_audio_set_io(cx);
                /* Done! Unmute and continue. */
@@ -652,38 +682,15 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
 
 int cx18_v4l2_open(struct file *filp)
 {
-       int res, x, y = 0;
-       struct cx18 *cx = NULL;
-       struct cx18_stream *s = NULL;
-       int minor = video_devdata(filp)->minor;
-
-       /* Find which card this open was on */
-       spin_lock(&cx18_cards_lock);
-       for (x = 0; cx == NULL && x < cx18_cards_active; x++) {
-               /* find out which stream this open was on */
-               for (y = 0; y < CX18_MAX_STREAMS; y++) {
-                       if (cx18_cards[x] == NULL)
-                               continue;
-                       s = &cx18_cards[x]->streams[y];
-                       if (s->v4l2dev && s->v4l2dev->minor == minor) {
-                               cx = cx18_cards[x];
-                               break;
-                       }
-               }
-       }
-       spin_unlock(&cx18_cards_lock);
-
-       if (cx == NULL) {
-               /* Couldn't find a device registered
-                  on that minor, shouldn't happen! */
-               printk(KERN_WARNING "No cx18 device found on minor %d\n",
-                               minor);
-               return -ENXIO;
-       }
+       int res;
+       struct video_device *video_dev = video_devdata(filp);
+       struct cx18_stream *s = video_get_drvdata(video_dev);
+       struct cx18 *cx = s->cx;;
 
        mutex_lock(&cx->serialize_lock);
        if (cx18_init_on_first_open(cx)) {
-               CX18_ERR("Failed to initialize on minor %d\n", minor);
+               CX18_ERR("Failed to initialize on minor %d\n",
+                        video_dev->minor);
                mutex_unlock(&cx->serialize_lock);
                return -ENXIO;
        }
index 1fa95da1575e63120c0f5e0b8e8d7318d7d6de54..83cd559cc6099ebb7e63886e86bb56e0d6b106ea 100644 (file)
@@ -26,7 +26,6 @@
 #include "cx18-irq.h"
 #include "cx18-firmware.h"
 #include "cx18-cards.h"
-#include "cx18-av-core.h"
 #include <linux/firmware.h>
 
 #define CX18_PROC_SOFT_RESET           0xc70010
@@ -107,7 +106,7 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx)
        u32 __iomem *dst = (u32 __iomem *)mem;
        const u32 *src;
 
-       if (request_firmware(&fw, fn, &cx->dev->dev)) {
+       if (request_firmware(&fw, fn, &cx->pci_dev->dev)) {
                CX18_ERR("Unable to open firmware %s\n", fn);
                CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n");
                return -ENOMEM;
@@ -151,7 +150,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx,
        u32 apu_version = 0;
        int sz;
 
-       if (request_firmware(&fw, fn, &cx->dev->dev)) {
+       if (request_firmware(&fw, fn, &cx->pci_dev->dev)) {
                CX18_ERR("unable to open firmware %s\n", fn);
                CX18_ERR("did you put the firmware in the hotplug firmware directory?\n");
                cx18_setup_page(cx, 0);
@@ -286,23 +285,6 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
        cx18_write_reg(cx, 0x2BE2FE, CX18_MPEG_CLOCK_PLL_FRAC);
        cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST);
 
-       /*
-        * VDCLK  Integer = 0x0f, Post Divider = 0x04
-        * AIMCLK Integer = 0x0e, Post Divider = 0x16
-        */
-       cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
-
-       /* VDCLK Fraction = 0x2be2fe */
-       /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
-       cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
-
-       /* AIMCLK Fraction = 0x05227ad */
-       /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz before post-divide */
-       cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
-
-       /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
-       cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
-
        /* Defaults */
        /* APU = SC or SC/2 = 125/62.5 */
        /* EPU = SC = 125 */
index 1a99329f33cb5b6375edd1736cfe7529976c5069..5518d1424f8fd250a25a28a5546ae9db368640a7 100644 (file)
@@ -46,6 +46,9 @@
  * gpio13: cs5345 reset pin
 */
 
+/*
+ * File scope utility functions
+ */
 static void gpio_write(struct cx18 *cx)
 {
        u32 dir_lo = cx->gpio_dir & 0xffff;
@@ -63,73 +66,201 @@ static void gpio_write(struct cx18 *cx)
                                        CX18_REG_GPIO_OUT2, val_hi, dir_hi);
 }
 
-void cx18_reset_i2c_slaves_gpio(struct cx18 *cx)
+static void gpio_update(struct cx18 *cx, u32 mask, u32 data)
 {
-       const struct cx18_gpio_i2c_slave_reset *p;
+       if (mask == 0)
+               return;
 
-       p = &cx->card->gpio_i2c_slave_reset;
+       mutex_lock(&cx->gpio_lock);
+       cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask);
+       gpio_write(cx);
+       mutex_unlock(&cx->gpio_lock);
+}
+
+static void gpio_reset_seq(struct cx18 *cx, u32 active_lo, u32 active_hi,
+                          unsigned int assert_msecs,
+                          unsigned int recovery_msecs)
+{
+       u32 mask;
 
-       if ((p->active_lo_mask | p->active_hi_mask) == 0)
+       mask = active_lo | active_hi;
+       if (mask == 0)
                return;
 
-       /* Assuming that the masks are a subset of the bits in gpio_dir */
+       /*
+        * Assuming that active_hi and active_lo are a subsets of the bits in
+        * gpio_dir.  Also assumes that active_lo and active_hi don't overlap
+        * in any bit position
+        */
 
        /* Assert */
-       mutex_lock(&cx->gpio_lock);
-       cx->gpio_val =
-               (cx->gpio_val | p->active_hi_mask) & ~(p->active_lo_mask);
-       gpio_write(cx);
-       schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted));
+       gpio_update(cx, mask, ~active_lo);
+       schedule_timeout_uninterruptible(msecs_to_jiffies(assert_msecs));
 
        /* Deassert */
-       cx->gpio_val =
-               (cx->gpio_val | p->active_lo_mask) & ~(p->active_hi_mask);
-       gpio_write(cx);
-       schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
+       gpio_update(cx, mask, ~active_hi);
+       schedule_timeout_uninterruptible(msecs_to_jiffies(recovery_msecs));
+}
+
+/*
+ * GPIO Multiplexer - logical device
+ */
+static int gpiomux_log_status(struct v4l2_subdev *sd)
+{
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+       mutex_lock(&cx->gpio_lock);
+       CX18_INFO_DEV(sd, "GPIO:  direction 0x%08x, value 0x%08x\n",
+                     cx->gpio_dir, cx->gpio_val);
        mutex_unlock(&cx->gpio_lock);
+       return 0;
 }
 
-void cx18_reset_ir_gpio(void *data)
+static int gpiomux_s_radio(struct v4l2_subdev *sd)
 {
-       struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
-       const struct cx18_gpio_i2c_slave_reset *p;
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
 
-       p = &cx->card->gpio_i2c_slave_reset;
+       /*
+        * FIXME - work out the cx->active/audio_input mess - this is
+        * intended to handle the switch to radio mode and set the
+        * audio routing, but we need to update the state in cx
+        */
+       gpio_update(cx, cx->card->gpio_audio_input.mask,
+                       cx->card->gpio_audio_input.radio);
+       return 0;
+}
 
-       if (p->ir_reset_mask == 0)
-               return;
+static int gpiomux_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+       u32 data;
 
-       CX18_DEBUG_INFO("Resetting IR microcontroller\n");
+       switch (cx->card->audio_inputs[cx->audio_input].muxer_input) {
+       case 1:
+               data = cx->card->gpio_audio_input.linein;
+               break;
+       case 0:
+               data = cx->card->gpio_audio_input.tuner;
+               break;
+       default:
+               /*
+                * FIXME - work out the cx->active/audio_input mess - this is
+                * intended to handle the switch from radio mode and set the
+                * audio routing, but we need to update the state in cx
+                */
+               data = cx->card->gpio_audio_input.tuner;
+               break;
+       }
+       gpio_update(cx, cx->card->gpio_audio_input.mask, data);
+       return 0;
+}
 
-       /*
-          Assert timing for the Z8F0811 on HVR-1600 boards:
-          1. Assert RESET for min of 4 clock cycles at 18.432 MHz to initiate
-          2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock cycles
-               (6,601,085 nanoseconds ~= 7 milliseconds)
-          3. DBG pin must be high before chip exits reset for normal operation.
-               DBG is open drain and hopefully pulled high since we don't
-               normally drive it (GPIO 1?) for the HVR-1600
-          4. Z8F0811 won't exit reset until RESET is deasserted
-       */
-       mutex_lock(&cx->gpio_lock);
-       cx->gpio_val = cx->gpio_val & ~p->ir_reset_mask;
-       gpio_write(cx);
-       mutex_unlock(&cx->gpio_lock);
-       schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted));
+static int gpiomux_s_audio_routing(struct v4l2_subdev *sd,
+                                  const struct v4l2_routing *route)
+{
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+       u32 data;
+
+       switch (route->input) {
+       case 0:
+               data = cx->card->gpio_audio_input.tuner;
+               break;
+       case 1:
+               data = cx->card->gpio_audio_input.linein;
+               break;
+       case 2:
+               data = cx->card->gpio_audio_input.radio;
+               break;
+       default:
+               return -EINVAL;
+       }
+       gpio_update(cx, cx->card->gpio_audio_input.mask, data);
+       return 0;
+}
+
+static const struct v4l2_subdev_core_ops gpiomux_core_ops = {
+       .log_status = gpiomux_log_status,
+};
+
+static const struct v4l2_subdev_tuner_ops gpiomux_tuner_ops = {
+       .s_std = gpiomux_s_std,
+       .s_radio = gpiomux_s_radio,
+};
+
+static const struct v4l2_subdev_audio_ops gpiomux_audio_ops = {
+       .s_routing = gpiomux_s_audio_routing,
+};
+
+static const struct v4l2_subdev_ops gpiomux_ops = {
+       .core = &gpiomux_core_ops,
+       .tuner = &gpiomux_tuner_ops,
+       .audio = &gpiomux_audio_ops,
+};
+
+/*
+ * GPIO Reset Controller - logical device
+ */
+static int resetctrl_log_status(struct v4l2_subdev *sd)
+{
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
 
-       /*
-          Zilog comes out of reset, loads reset vector address and executes
-          from there. Required recovery delay unknown.
-       */
        mutex_lock(&cx->gpio_lock);
-       cx->gpio_val = cx->gpio_val | p->ir_reset_mask;
-       gpio_write(cx);
+       CX18_INFO_DEV(sd, "GPIO:  direction 0x%08x, value 0x%08x\n",
+                     cx->gpio_dir, cx->gpio_val);
        mutex_unlock(&cx->gpio_lock);
-       schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
+       return 0;
 }
-EXPORT_SYMBOL(cx18_reset_ir_gpio);
-/* This symbol is exported for use by an infrared module for the IR-blaster */
 
+static int resetctrl_reset(struct v4l2_subdev *sd, u32 val)
+{
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+       const struct cx18_gpio_i2c_slave_reset *p;
+
+       p = &cx->card->gpio_i2c_slave_reset;
+       switch (val) {
+       case CX18_GPIO_RESET_I2C:
+               gpio_reset_seq(cx, p->active_lo_mask, p->active_hi_mask,
+                              p->msecs_asserted, p->msecs_recovery);
+               break;
+       case CX18_GPIO_RESET_Z8F0811:
+               /*
+                * Assert timing for the Z8F0811 on HVR-1600 boards:
+                * 1. Assert RESET for min of 4 clock cycles at 18.432 MHz to
+                *    initiate
+                * 2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock
+                *    cycles (6,601,085 nanoseconds ~= 7 milliseconds)
+                * 3. DBG pin must be high before chip exits reset for normal
+                *    operation.  DBG is open drain and hopefully pulled high
+                *    since we don't normally drive it (GPIO 1?) for the
+                *    HVR-1600
+                * 4. Z8F0811 won't exit reset until RESET is deasserted
+                * 5. Zilog comes out of reset, loads reset vector address and
+                *    executes from there. Required recovery delay unknown.
+                */
+               gpio_reset_seq(cx, p->ir_reset_mask, 0,
+                              p->msecs_asserted, p->msecs_recovery);
+               break;
+       case CX18_GPIO_RESET_XC2028:
+               if (cx->card->tuners[0].tuner == TUNER_XC2028)
+                       gpio_reset_seq(cx, (1 << cx->card->xceive_pin), 0,
+                                      1, 1);
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_subdev_core_ops resetctrl_core_ops = {
+       .log_status = resetctrl_log_status,
+       .reset = resetctrl_reset,
+};
+
+static const struct v4l2_subdev_ops resetctrl_ops = {
+       .core = &resetctrl_core_ops,
+};
+
+/*
+ * External entry points
+ */
 void cx18_gpio_init(struct cx18 *cx)
 {
        mutex_lock(&cx->gpio_lock);
@@ -156,6 +287,49 @@ void cx18_gpio_init(struct cx18 *cx)
        mutex_unlock(&cx->gpio_lock);
 }
 
+int cx18_gpio_register(struct cx18 *cx, u32 hw)
+{
+       struct v4l2_subdev *sd;
+       const struct v4l2_subdev_ops *ops;
+       char *str;
+
+       switch (hw) {
+       case CX18_HW_GPIO_MUX:
+               sd = &cx->sd_gpiomux;
+               ops = &gpiomux_ops;
+               str = "gpio-mux";
+               break;
+       case CX18_HW_GPIO_RESET_CTRL:
+               sd = &cx->sd_resetctrl;
+               ops = &resetctrl_ops;
+               str = "gpio-reset-ctrl";
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       v4l2_subdev_init(sd, ops);
+       v4l2_set_subdevdata(sd, cx);
+       snprintf(sd->name, sizeof(sd->name), "%s %s", cx->v4l2_dev.name, str);
+       sd->grp_id = hw;
+       return v4l2_device_register_subdev(&cx->v4l2_dev, sd);
+}
+
+void cx18_reset_ir_gpio(void *data)
+{
+       struct cx18 *cx = to_cx18((struct v4l2_device *)data);
+
+       if (cx->card->gpio_i2c_slave_reset.ir_reset_mask == 0)
+               return;
+
+       CX18_DEBUG_INFO("Resetting IR microcontroller\n");
+
+       v4l2_subdev_call(&cx->sd_resetctrl,
+                        core, reset, CX18_GPIO_RESET_Z8F0811);
+}
+EXPORT_SYMBOL(cx18_reset_ir_gpio);
+/* This symbol is exported for use by lirc_pvr150 for the IR-blaster */
+
 /* Xceive tuner reset function */
 int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value)
 {
@@ -163,56 +337,11 @@ int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value)
        struct cx18_i2c_algo_callback_data *cb_data = algo->data;
        struct cx18 *cx = cb_data->cx;
 
-       if (cmd != XC2028_TUNER_RESET)
+       if (cmd != XC2028_TUNER_RESET ||
+           cx->card->tuners[0].tuner != TUNER_XC2028)
                return 0;
-       CX18_DEBUG_INFO("Resetting tuner\n");
 
-       mutex_lock(&cx->gpio_lock);
-       cx->gpio_val &= ~(1 << cx->card->xceive_pin);
-       gpio_write(cx);
-       mutex_unlock(&cx->gpio_lock);
-       schedule_timeout_interruptible(msecs_to_jiffies(1));
-
-       mutex_lock(&cx->gpio_lock);
-       cx->gpio_val |= 1 << cx->card->xceive_pin;
-       gpio_write(cx);
-       mutex_unlock(&cx->gpio_lock);
-       schedule_timeout_interruptible(msecs_to_jiffies(1));
-       return 0;
-}
-
-int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg)
-{
-       struct v4l2_routing *route = arg;
-       u32 mask, data;
-
-       switch (command) {
-       case VIDIOC_INT_S_AUDIO_ROUTING:
-               if (route->input > 2)
-                       return -EINVAL;
-               mask = cx->card->gpio_audio_input.mask;
-               switch (route->input) {
-               case 0:
-                       data = cx->card->gpio_audio_input.tuner;
-                       break;
-               case 1:
-                       data = cx->card->gpio_audio_input.linein;
-                       break;
-               case 2:
-               default:
-                       data = cx->card->gpio_audio_input.radio;
-                       break;
-               }
-               break;
-
-       default:
-               return -EINVAL;
-       }
-       if (mask) {
-               mutex_lock(&cx->gpio_lock);
-               cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask);
-               gpio_write(cx);
-               mutex_unlock(&cx->gpio_lock);
-       }
-       return 0;
+       CX18_DEBUG_INFO("Resetting XCeive tuner\n");
+       return v4l2_subdev_call(&cx->sd_resetctrl,
+                               core, reset, CX18_GPIO_RESET_XC2028);
 }
index 39ffccc19d8a447dbbb646eb025ba18e92e5458b..f9a5ca3566af2fee27cf3b2186674164abc59f0d 100644 (file)
  */
 
 void cx18_gpio_init(struct cx18 *cx);
-void cx18_reset_i2c_slaves_gpio(struct cx18 *cx);
+int cx18_gpio_register(struct cx18 *cx, u32 hw);
+
+enum cx18_gpio_reset_type {
+       CX18_GPIO_RESET_I2C     = 0,
+       CX18_GPIO_RESET_Z8F0811 = 1,
+       CX18_GPIO_RESET_XC2028  = 2,
+};
+
 void cx18_reset_ir_gpio(void *data);
 int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value);
-int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg);
index 83e1c6333126eabf84da60d05d0a45fc6274a6cf..d092643faf463911d7d6d40467bf7672ee3daf89 100644 (file)
@@ -26,7 +26,6 @@
 #include "cx18-io.h"
 #include "cx18-cards.h"
 #include "cx18-gpio.h"
-#include "cx18-av-core.h"
 #include "cx18-i2c.h"
 #include "cx18-irq.h"
 
 
 #define CX18_CS5345_I2C_ADDR           0x4c
 
-/* This array should match the CX18_HW_ defines */
-static const u8 hw_driverids[] = {
-       I2C_DRIVERID_TUNER,
-       I2C_DRIVERID_TVEEPROM,
-       I2C_DRIVERID_CS5345,
-       0,              /* CX18_HW_GPIO dummy driver ID */
-       0               /* CX18_HW_CX23418 dummy driver ID */
-};
-
 /* This array should match the CX18_HW_ defines */
 static const u8 hw_addrs[] = {
-       0,
-       0,
-       CX18_CS5345_I2C_ADDR,
-       0,              /* CX18_HW_GPIO dummy driver ID */
-       0,              /* CX18_HW_CX23418 dummy driver ID */
+       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 */
 };
 
 /* This array should match the CX18_HW_ defines */
 /* This might well become a card-specific array */
 static const u8 hw_bus[] = {
-       0,
-       0,
-       0,
-       0,              /* CX18_HW_GPIO dummy driver ID */
-       0,              /* CX18_HW_CX23418 dummy driver ID */
+       1,      /* CX18_HW_TUNER */
+       0,      /* CX18_HW_TVEEPROM */
+       0,      /* CX18_HW_CS5345 */
+       0,      /* CX18_HW_DVB */
+       0,      /* CX18_HW_418_AV */
+       0,      /* CX18_HW_GPIO_MUX */
+       0,      /* CX18_HW_GPIO_RESET_CTRL */
+};
+
+/* This array should match the CX18_HW_ defines */
+static const char * const hw_modules[] = {
+       "tuner",        /* CX18_HW_TUNER */
+       NULL,           /* CX18_HW_TVEEPROM */
+       "cs5345",       /* CX18_HW_CS5345 */
+       NULL,           /* CX18_HW_DVB */
+       NULL,           /* CX18_HW_418_AV */
+       NULL,           /* CX18_HW_GPIO_MUX */
+       NULL,           /* CX18_HW_GPIO_RESET_CTRL */
 };
 
 /* This array should match the CX18_HW_ defines */
@@ -75,83 +80,67 @@ static const char * const hw_devicenames[] = {
        "tuner",
        "tveeprom",
        "cs5345",
-       "gpio",
-       "cx23418",
+       "cx23418_DTV",
+       "cx23418_AV",
+       "gpio_mux",
+       "gpio_reset_ctrl",
 };
 
 int cx18_i2c_register(struct cx18 *cx, unsigned idx)
 {
-       struct i2c_board_info info;
-       struct i2c_client *c;
-       u8 id, bus;
-       int i;
-
-       CX18_DEBUG_I2C("i2c client register\n");
-       if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0)
+       struct v4l2_subdev *sd;
+       int bus = hw_bus[idx];
+       struct i2c_adapter *adap = &cx->i2c_adap[bus];
+       const char *mod = hw_modules[idx];
+       const char *type = hw_devicenames[idx];
+       u32 hw = 1 << idx;
+
+       if (idx >= ARRAY_SIZE(hw_addrs))
                return -1;
-       id = hw_driverids[idx];
-       bus = hw_bus[idx];
-       memset(&info, 0, sizeof(info));
-       strlcpy(info.type, hw_devicenames[idx], sizeof(info.type));
-       info.addr = hw_addrs[idx];
-       for (i = 0; i < I2C_CLIENTS_MAX; i++)
-               if (cx->i2c_clients[i] == NULL)
-                       break;
-
-       if (i == I2C_CLIENTS_MAX) {
-               CX18_ERR("insufficient room for new I2C client!\n");
-               return -ENOMEM;
-       }
 
-       if (id != I2C_DRIVERID_TUNER) {
-               c = i2c_new_device(&cx->i2c_adap[bus], &info);
-               if (c->driver == NULL)
-                       i2c_unregister_device(c);
-               else
-                       cx->i2c_clients[i] = c;
-               return cx->i2c_clients[i] ? 0 : -ENODEV;
+       if (hw == CX18_HW_TUNER) {
+               /* special tuner group handling */
+               sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
+                                               cx->card_i2c->radio);
+               if (sd != NULL)
+                       sd->grp_id = hw;
+               sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
+                                               cx->card_i2c->demod);
+               if (sd != NULL)
+                       sd->grp_id = hw;
+               sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
+                                               cx->card_i2c->tv);
+               if (sd != NULL)
+                       sd->grp_id = hw;
+               return sd != NULL ? 0 : -1;
        }
 
-       /* special tuner handling */
-       c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->radio);
-       if (c && c->driver == NULL)
-               i2c_unregister_device(c);
-       else if (c)
-               cx->i2c_clients[i++] = c;
-       c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->demod);
-       if (c && c->driver == NULL)
-               i2c_unregister_device(c);
-       else if (c)
-               cx->i2c_clients[i++] = c;
-       c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->tv);
-       if (c && c->driver == NULL)
-               i2c_unregister_device(c);
-       else if (c)
-               cx->i2c_clients[i++] = c;
-       return 0;
-}
+       /* Is it not an I2C device or one we do not wish to register? */
+       if (!hw_addrs[idx])
+               return -1;
 
-static int attach_inform(struct i2c_client *client)
-{
-       return 0;
+       /* It's an I2C device other than an analog tuner */
+       sd = v4l2_i2c_new_subdev(adap, mod, type, hw_addrs[idx]);
+       if (sd != NULL)
+               sd->grp_id = hw;
+       return sd != NULL ? 0 : -1;
 }
 
-static int detach_inform(struct i2c_client *client)
+/* Find the first member of the subdev group id in hw */
+struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw)
 {
-       int i;
-       struct cx18 *cx = (struct cx18 *)i2c_get_adapdata(client->adapter);
+       struct v4l2_subdev *result = NULL;
+       struct v4l2_subdev *sd;
 
-       CX18_DEBUG_I2C("i2c client detach\n");
-       for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-               if (cx->i2c_clients[i] == client) {
-                       cx->i2c_clients[i] = NULL;
+       spin_lock(&cx->v4l2_dev.lock);
+       v4l2_device_for_each_subdev(sd, &cx->v4l2_dev) {
+               if (sd->grp_id == hw) {
+                       result = sd;
                        break;
                }
        }
-       CX18_DEBUG_I2C("i2c detach [client=%s,%s]\n",
-                  client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed");
-
-       return 0;
+       spin_unlock(&cx->v4l2_dev.lock);
+       return result;
 }
 
 static void cx18_setscl(void *data, int state)
@@ -204,8 +193,6 @@ static struct i2c_adapter cx18_i2c_adap_template = {
        .id = I2C_HW_B_CX2341X,
        .algo = NULL,                   /* set by i2c-algo-bit */
        .algo_data = NULL,              /* filled from template */
-       .client_register = attach_inform,
-       .client_unregister = detach_inform,
        .owner = THIS_MODULE,
 };
 
@@ -221,152 +208,28 @@ static struct i2c_algo_bit_data cx18_i2c_algo_template = {
        .timeout        = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */
 };
 
-static struct i2c_client cx18_i2c_client_template = {
-       .name = "cx18 internal",
-};
-
-int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg)
-{
-       struct i2c_client *client;
-       int retval;
-       int i;
-
-       CX18_DEBUG_I2C("call_i2c_client addr=%02x\n", addr);
-       for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-               client = cx->i2c_clients[i];
-               if (client == NULL || client->driver == NULL ||
-                               client->driver->command == NULL)
-                       continue;
-               if (addr == client->addr) {
-                       retval = client->driver->command(client, cmd, arg);
-                       return retval;
-               }
-       }
-       if (cmd != VIDIOC_DBG_G_CHIP_IDENT)
-               CX18_ERR("i2c addr 0x%02x not found for cmd 0x%x!\n",
-                              addr, cmd);
-       return -ENODEV;
-}
-
-/* Find the i2c device based on the driver ID and return
-   its i2c address or -ENODEV if no matching device was found. */
-static int cx18_i2c_id_addr(struct cx18 *cx, u32 id)
-{
-       struct i2c_client *client;
-       int retval = -ENODEV;
-       int i;
-
-       for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-               client = cx->i2c_clients[i];
-               if (client == NULL || client->driver == NULL)
-                       continue;
-               if (id == client->driver->id) {
-                       retval = client->addr;
-                       break;
-               }
-       }
-       return retval;
-}
-
-/* Find the i2c device name matching the CX18_HW_ flag */
-static const char *cx18_i2c_hw_name(u32 hw)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
-               if (1 << i == hw)
-                       return hw_devicenames[i];
-       return "unknown device";
-}
-
-/* Find the i2c device matching the CX18_HW_ flag and return
-   its i2c address or -ENODEV if no matching device was found. */
-int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
-               if (1 << i == hw)
-                       return cx18_i2c_id_addr(cx, hw_driverids[i]);
-       return -ENODEV;
-}
-
-/* Calls i2c device based on CX18_HW_ flag. If hw == 0, then do nothing.
-   If hw == CX18_HW_GPIO then call the gpio handler. */
-int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg)
-{
-       int addr;
-
-       if (hw == 0)
-               return 0;
-
-       if (hw == CX18_HW_GPIO)
-               return cx18_gpio(cx, cmd, arg);
-
-       if (hw == CX18_HW_CX23418)
-               return cx18_av_cmd(cx, cmd, arg);
-
-       addr = cx18_i2c_hw_addr(cx, hw);
-       if (addr < 0) {
-               CX18_ERR("i2c hardware 0x%08x (%s) not found for cmd 0x%x!\n",
-                              hw, cx18_i2c_hw_name(hw), cmd);
-               return addr;
-       }
-       return cx18_call_i2c_client(cx, addr, cmd, arg);
-}
-
-/* broadcast cmd for all I2C clients and for the gpio subsystem */
-void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg)
-{
-       if (cx->i2c_adap[0].algo == NULL || cx->i2c_adap[1].algo == NULL) {
-               CX18_ERR("adapter is not set\n");
-               return;
-       }
-       cx18_av_cmd(cx, cmd, arg);
-       i2c_clients_command(&cx->i2c_adap[0], cmd, arg);
-       i2c_clients_command(&cx->i2c_adap[1], cmd, arg);
-       if (cx->hw_flags & CX18_HW_GPIO)
-               cx18_gpio(cx, cmd, arg);
-}
-
 /* init + register i2c algo-bit adapter */
 int init_cx18_i2c(struct cx18 *cx)
 {
        int i;
        CX18_DEBUG_I2C("i2c init\n");
 
-       /* Sanity checks for the I2C hardware arrays. They must be the
-        * same size and GPIO/CX23418 must be the last entries.
-        */
-       if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
-           ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
-           CX18_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 2)) ||
-           CX18_HW_CX23418 != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
-           hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
-               CX18_ERR("Mismatched I2C hardware arrays\n");
-               return -ENODEV;
-       }
-
        for (i = 0; i < 2; i++) {
-               memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
-                       sizeof(struct i2c_adapter));
+               /* Setup algorithm for adapter */
                memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template,
                        sizeof(struct i2c_algo_bit_data));
                cx->i2c_algo_cb_data[i].cx = cx;
                cx->i2c_algo_cb_data[i].bus_index = i;
                cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i];
-               cx->i2c_adap[i].algo_data = &cx->i2c_algo[i];
 
+               /* Setup adapter */
+               memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
+                       sizeof(struct i2c_adapter));
+               cx->i2c_adap[i].algo_data = &cx->i2c_algo[i];
                sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name),
-                               " #%d-%d", cx->num, i);
-               i2c_set_adapdata(&cx->i2c_adap[i], cx);
-
-               memcpy(&cx->i2c_client[i], &cx18_i2c_client_template,
-                       sizeof(struct i2c_client));
-               sprintf(cx->i2c_client[i].name +
-                               strlen(cx->i2c_client[i].name), "%d", i);
-               cx->i2c_client[i].adapter = &cx->i2c_adap[i];
-               cx->i2c_adap[i].dev.parent = &cx->dev->dev;
+                               " #%d-%d", cx->instance, i);
+               i2c_set_adapdata(&cx->i2c_adap[i], &cx->v4l2_dev);
+               cx->i2c_adap[i].dev.parent = &cx->pci_dev->dev;
        }
 
        if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) {
@@ -402,7 +265,8 @@ int init_cx18_i2c(struct cx18 *cx)
        cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
        cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
 
-       cx18_reset_i2c_slaves_gpio(cx);
+       cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL,
+                    core, reset, (u32) CX18_GPIO_RESET_I2C);
 
        return i2c_bit_add_bus(&cx->i2c_adap[0]) ||
                i2c_bit_add_bus(&cx->i2c_adap[1]);
index 4869739013bdf3fbd68f37696f890256f89961d6..bdfd1921e30021062f8c1ddcd50f476f3bf8d513 100644 (file)
  *  02111-1307  USA
  */
 
-int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw);
-int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg);
-int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg);
-void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg);
 int cx18_i2c_register(struct cx18 *cx, unsigned idx);
+struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw);
 
 /* init + register i2c algo-bit adapter */
 int init_cx18_i2c(struct cx18 *cx);
index 7086aaba77d677ed5cc9f8d697b0206be56d4f17..e4c9e3d8bacd8538dff693ba6759b96a5136bed9 100644 (file)
@@ -58,12 +58,21 @@ u16 cx18_service2vbi(int type)
        }
 }
 
+/* Check if VBI services are allowed on the (field, line) for the video std */
 static int valid_service_line(int field, int line, int is_pal)
 {
-       return (is_pal && line >= 6 && (line != 23 || field == 0)) ||
+       return (is_pal && line >= 6 &&
+               ((field == 0 && line <= 23) || (field == 1 && line <= 22))) ||
               (!is_pal && line >= 10 && line < 22);
 }
 
+/*
+ * For a (field, line, std) and inbound potential set of services for that line,
+ * return the first valid service of those passed in the incoming set for that
+ * line in priority order:
+ * CC, VPS, or WSS over TELETEXT for well known lines
+ * TELETEXT, before VPS, before CC, before WSS, for other lines
+ */
 static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
 {
        u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
@@ -90,6 +99,10 @@ static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
        return 0;
 }
 
+/*
+ * Expand the service_set of *fmt into valid service_lines for the std,
+ * and clear the passed in fmt->service_set
+ */
 void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
 {
        u16 set = fmt->service_set;
@@ -102,7 +115,25 @@ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
        }
 }
 
+/*
+ * Sanitize the service_lines in *fmt per the video std, and return 1
+ * if any service_line is left as valid after santization
+ */
+static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+{
+       int f, l;
+       u16 set = 0;
+
+       for (f = 0; f < 2; f++) {
+               for (l = 0; l < 24; l++) {
+                       fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
+                       set |= fmt->service_lines[f][l];
+               }
+       }
+       return set != 0;
+}
 
+/* Compute the service_set from the assumed valid service_lines of *fmt */
 u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
 {
        int f, l;
@@ -129,10 +160,8 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
        pixfmt->priv = 0;
        if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
                pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
-               /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
-               pixfmt->sizeimage =
-                       pixfmt->height * pixfmt->width +
-                       pixfmt->height * (pixfmt->width / 2);
+               /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */
+               pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
                pixfmt->bytesperline = 720;
        } else {
                pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
@@ -149,8 +178,8 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
        struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
 
        vbifmt->sampling_rate = 27000000;
-       vbifmt->offset = 248;
-       vbifmt->samples_per_line = cx->vbi.raw_decoder_line_size - 4;
+       vbifmt->offset = 248; /* FIXME - slightly wrong for both 50 & 60 Hz */
+       vbifmt->samples_per_line = vbi_active_samples - 4;
        vbifmt->sample_format = V4L2_PIX_FMT_GREY;
        vbifmt->start[0] = cx->vbi.start[0];
        vbifmt->start[1] = cx->vbi.start[1];
@@ -164,7 +193,30 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
 static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
                                        struct v4l2_format *fmt)
 {
-       return -EINVAL;
+       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+       /* sane, V4L2 spec compliant, defaults */
+       vbifmt->reserved[0] = 0;
+       vbifmt->reserved[1] = 0;
+       vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+       memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
+       vbifmt->service_set = 0;
+
+       /*
+        * Fetch the configured service_lines and total service_set from the
+        * digitizer/slicer.  Note, cx18_av_vbi() wipes the passed in
+        * fmt->fmt.sliced under valid calling conditions
+        */
+       if (v4l2_subdev_call(cx->sd_av, video, g_fmt, fmt))
+               return -EINVAL;
+
+       /* Ensure V4L2 spec compliant output */
+       vbifmt->reserved[0] = 0;
+       vbifmt->reserved[1] = 0;
+       vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+       vbifmt->service_set = cx18_get_service_set(vbifmt);
+       return 0;
 }
 
 static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
@@ -174,11 +226,18 @@ static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
        struct cx18 *cx = id->cx;
        int w = fmt->fmt.pix.width;
        int h = fmt->fmt.pix.height;
+       int min_h = 2;
 
        w = min(w, 720);
-       w = max(w, 1);
+       w = max(w, 2);
+       if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
+               /* YUV height must be a multiple of 32 */
+               h &= ~0x1f;
+               min_h = 32;
+       }
        h = min(h, cx->is_50hz ? 576 : 480);
-       h = max(h, 2);
+       h = max(h, min_h);
+
        cx18_g_fmt_vid_cap(file, fh, fmt);
        fmt->fmt.pix.width = w;
        fmt->fmt.pix.height = h;
@@ -194,7 +253,20 @@ static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
 static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
                                        struct v4l2_format *fmt)
 {
-       return -EINVAL;
+       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+       vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+       vbifmt->reserved[0] = 0;
+       vbifmt->reserved[1] = 0;
+
+       /* If given a service set, expand it validly & clear passed in set */
+       if (vbifmt->service_set)
+               cx18_expand_service_set(vbifmt, cx->is_50hz);
+       /* Sanitize the service_lines, and compute the new set if any valid */
+       if (check_service_set(vbifmt, cx->is_50hz))
+               vbifmt->service_set = cx18_get_service_set(vbifmt);
+       return 0;
 }
 
 static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
@@ -223,7 +295,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
 
        cx->params.width = w;
        cx->params.height = h;
-       cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+       v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt);
        return cx18_g_fmt_vid_cap(file, fh, fmt);
 }
 
@@ -238,54 +310,131 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
        if (ret)
                return ret;
 
+       /*
+        * Changing the Encoder's Raw VBI parameters won't have any effect
+        * if any analog capture is ongoing
+        */
        if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
                return -EBUSY;
 
+       /*
+        * Set the digitizer registers for raw active VBI.
+        * Note cx18_av_vbi_wipes out alot of the passed in fmt under valid
+        * calling conditions
+        */
+       ret = v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt);
+       if (ret)
+               return ret;
+
+       /* Store our new v4l2 (non-)sliced VBI state */
        cx->vbi.sliced_in->service_set = 0;
        cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
-       cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+
        return cx18_g_fmt_vbi_cap(file, fh, fmt);
 }
 
 static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
                                        struct v4l2_format *fmt)
 {
-       return -EINVAL;
+       struct cx18_open_id *id = fh;
+       struct cx18 *cx = id->cx;
+       int ret;
+       struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+       ret = v4l2_prio_check(&cx->prio, &id->prio);
+       if (ret)
+               return ret;
+
+       cx18_try_fmt_sliced_vbi_cap(file, fh, fmt);
+
+       /*
+        * Changing the Encoder's Raw VBI parameters won't have any effect
+        * if any analog capture is ongoing
+        */
+       if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
+               return -EBUSY;
+
+       /*
+        * Set the service_lines requested in the digitizer/slicer registers.
+        * Note, cx18_av_vbi() wipes some "impossible" service lines in the
+        * passed in fmt->fmt.sliced under valid calling conditions
+        */
+       ret = v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt);
+       if (ret)
+               return ret;
+       /* Store our current v4l2 sliced VBI settings */
+       cx->vbi.in.type =  V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+       memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
+       return 0;
 }
 
 static int cx18_g_chip_ident(struct file *file, void *fh,
                                struct v4l2_dbg_chip_ident *chip)
 {
        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       int err = 0;
 
        chip->ident = V4L2_IDENT_NONE;
        chip->revision = 0;
-       if (v4l2_chip_match_host(&chip->match)) {
-               chip->ident = V4L2_IDENT_CX23418;
-               return 0;
+       switch (chip->match.type) {
+       case V4L2_CHIP_MATCH_HOST:
+               switch (chip->match.addr) {
+               case 0:
+                       chip->ident = V4L2_IDENT_CX23418;
+                       chip->revision = cx18_read_reg(cx, 0xC72028);
+                       break;
+               case 1:
+                       /*
+                        * The A/V decoder is always present, but in the rare
+                        * case that the card doesn't have analog, we don't
+                        * use it.  We find it w/o using the cx->sd_av pointer
+                        */
+                       cx18_call_hw(cx, CX18_HW_418_AV,
+                                    core, g_chip_ident, chip);
+                       break;
+               default:
+                       /*
+                        * Could return ident = V4L2_IDENT_UNKNOWN if we had
+                        * other host chips at higher addresses, but we don't
+                        */
+                       err = -EINVAL; /* per V4L2 spec */
+                       break;
+               }
+               break;
+       case V4L2_CHIP_MATCH_I2C_DRIVER:
+               /* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */
+               cx18_call_all(cx, core, g_chip_ident, chip);
+               break;
+       case V4L2_CHIP_MATCH_I2C_ADDR:
+               /*
+                * We could return V4L2_IDENT_UNKNOWN, but we don't do the work
+                * to look if a chip is at the address with no driver.  That's a
+                * dangerous thing to do with EEPROMs anyway.
+                */
+               cx18_call_all(cx, core, g_chip_ident, chip);
+               break;
+       default:
+               err = -EINVAL;
+               break;
        }
-       cx18_call_i2c_clients(cx, VIDIOC_DBG_G_CHIP_IDENT, chip);
-       return 0;
+       return err;
 }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
 {
        struct v4l2_dbg_register *regs = arg;
-       unsigned long flags;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
        if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
                return -EINVAL;
 
-       spin_lock_irqsave(&cx18_cards_lock, flags);
        regs->size = 4;
-       if (cmd == VIDIOC_DBG_G_REGISTER)
-               regs->val = cx18_read_enc(cx, regs->reg);
-       else
+       if (cmd == VIDIOC_DBG_S_REGISTER)
                cx18_write_enc(cx, regs->val, regs->reg);
-       spin_unlock_irqrestore(&cx18_cards_lock, flags);
+       else
+               regs->val = cx18_read_enc(cx, regs->reg);
        return 0;
 }
 
@@ -296,7 +445,8 @@ static int cx18_g_register(struct file *file, void *fh,
 
        if (v4l2_chip_match_host(&reg->match))
                return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg);
-       cx18_call_i2c_clients(cx, VIDIOC_DBG_G_REGISTER, reg);
+       /* FIXME - errors shouldn't be ignored */
+       cx18_call_all(cx, core, g_register, reg);
        return 0;
 }
 
@@ -307,7 +457,8 @@ static int cx18_s_register(struct file *file, void *fh,
 
        if (v4l2_chip_match_host(&reg->match))
                return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg);
-       cx18_call_i2c_clients(cx, VIDIOC_DBG_S_REGISTER, reg);
+       /* FIXME - errors shouldn't be ignored */
+       cx18_call_all(cx, core, s_register, reg);
        return 0;
 }
 #endif
@@ -335,7 +486,8 @@ static int cx18_querycap(struct file *file, void *fh,
 
        strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
        strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
-       snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(cx->dev));
+       snprintf(vcap->bus_info, sizeof(vcap->bus_info),
+                "PCI:%s", pci_name(cx->pci_dev));
        vcap->version = CX18_DRIVER_VERSION;        /* version */
        vcap->capabilities = cx->v4l2_cap;          /* capabilities */
        return 0;
@@ -403,7 +555,8 @@ static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 
        if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
-       return cx18_av_cmd(cx, VIDIOC_S_CROP, crop);
+       CX18_DEBUG_WARN("VIDIOC_S_CROP not implemented\n");
+       return -EINVAL;
 }
 
 static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
@@ -412,7 +565,8 @@ static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 
        if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
-       return cx18_av_cmd(cx, VIDIOC_G_CROP, crop);
+       CX18_DEBUG_WARN("VIDIOC_G_CROP not implemented\n");
+       return -EINVAL;
 }
 
 static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
@@ -483,7 +637,7 @@ static int cx18_g_frequency(struct file *file, void *fh,
        if (vf->tuner != 0)
                return -EINVAL;
 
-       cx18_call_i2c_clients(cx, VIDIOC_G_FREQUENCY, vf);
+       cx18_call_all(cx, tuner, g_frequency, vf);
        return 0;
 }
 
@@ -502,7 +656,7 @@ int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
 
        cx18_mute(cx);
        CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
-       cx18_call_i2c_clients(cx, VIDIOC_S_FREQUENCY, vf);
+       cx18_call_all(cx, tuner, s_frequency, vf);
        cx18_unmute(cx);
        return 0;
 }
@@ -547,12 +701,11 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
        cx->vbi.count = cx->is_50hz ? 18 : 12;
        cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
        cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
-       cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
        CX18_DEBUG_INFO("Switching standard to %llx.\n",
                        (unsigned long long) cx->std);
 
        /* Tuner */
-       cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
+       cx18_call_all(cx, tuner, s_std, cx->std);
        return 0;
 }
 
@@ -569,9 +722,7 @@ static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
        if (vt->index != 0)
                return -EINVAL;
 
-       /* Setting tuner can only set audio mode */
-       cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);
-
+       cx18_call_all(cx, tuner, s_tuner, vt);
        return 0;
 }
 
@@ -582,7 +733,7 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
        if (vt->index != 0)
                return -EINVAL;
 
-       cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);
+       cx18_call_all(cx, tuner, g_tuner, vt);
 
        if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
                strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
@@ -598,7 +749,30 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
 static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
                                        struct v4l2_sliced_vbi_cap *cap)
 {
-       return -EINVAL;
+       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
+       int f, l;
+
+       if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+               return -EINVAL;
+
+       cap->service_set = 0;
+       for (f = 0; f < 2; f++) {
+               for (l = 0; l < 24; l++) {
+                       if (valid_service_line(f, l, cx->is_50hz)) {
+                               /*
+                                * We can find all v4l2 supported vbi services
+                                * for the standard, on a valid line for the std
+                                */
+                               cap->service_lines[f][l] = set;
+                               cap->service_set |= set;
+                       } else
+                               cap->service_lines[f][l] = 0;
+               }
+       }
+       for (f = 0; f < 3; f++)
+               cap->reserved[f] = 0;
+       return 0;
 }
 
 static int cx18_g_enc_index(struct file *file, void *fh,
@@ -708,13 +882,15 @@ static int cx18_log_status(struct file *file, void *fh)
        struct v4l2_audio audin;
        int i;
 
-       CX18_INFO("=================  START STATUS CARD #%d  =================\n", cx->num);
+       CX18_INFO("=================  START STATUS CARD #%d  "
+                 "=================\n", cx->instance);
+       CX18_INFO("Version: %s  Card: %s\n", CX18_VERSION, cx->card_name);
        if (cx->hw_flags & CX18_HW_TVEEPROM) {
                struct tveeprom tv;
 
                cx18_read_eeprom(cx, &tv);
        }
-       cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
+       cx18_call_all(cx, core, log_status);
        cx18_get_input(cx, cx->active_input, &vidin);
        cx18_get_audio_input(cx, cx->audio_input, &audin);
        CX18_INFO("Video Input: %s\n", vidin.name);
@@ -725,12 +901,12 @@ static int cx18_log_status(struct file *file, void *fh)
        mutex_unlock(&cx->gpio_lock);
        CX18_INFO("Tuner: %s\n",
                test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?  "Radio" : "TV");
-       cx2341x_log_status(&cx->params, cx->name);
+       cx2341x_log_status(&cx->params, cx->v4l2_dev.name);
        CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
        for (i = 0; i < CX18_MAX_STREAMS; i++) {
                struct cx18_stream *s = &cx->streams[i];
 
-               if (s->v4l2dev == NULL || s->buffers == 0)
+               if (s->video_dev == NULL || s->buffers == 0)
                        continue;
                CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
                          s->name, s->s_flags,
@@ -740,7 +916,8 @@ static int cx18_log_status(struct file *file, void *fh)
        CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
                        (long long)cx->mpg_data_received,
                        (long long)cx->vbi_data_inserted);
-       CX18_INFO("==================  END STATUS CARD #%d  ==================\n", cx->num);
+       CX18_INFO("==================  END STATUS CARD #%d  "
+                 "==================\n", cx->instance);
        return 0;
 }
 
@@ -754,7 +931,8 @@ static long cx18_default(struct file *file, void *fh, int cmd, void *arg)
 
                CX18_DEBUG_IOCTL("VIDIOC_INT_S_AUDIO_ROUTING(%d, %d)\n",
                        route->input, route->output);
-               cx18_audio_set_route(cx, route);
+               cx18_call_hw(cx, cx->card->hw_audio_ctrl, audio, s_routing,
+                            route);
                break;
        }
 
@@ -762,7 +940,8 @@ static long cx18_default(struct file *file, void *fh, int cmd, void *arg)
                u32 val = *(u32 *)arg;
 
                if ((val == 0) || (val & 0x01))
-                       cx18_reset_ir_gpio(&cx->i2c_algo_cb_data[0]);
+                       cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, core, reset,
+                                    (u32) CX18_GPIO_RESET_Z8F0811);
                break;
        }
 
@@ -782,6 +961,8 @@ long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd,
 
        mutex_lock(&cx->serialize_lock);
 
+       /* FIXME - consolidate v4l2_prio_check()'s here */
+
        if (cx18_debug & CX18_DBGFLG_IOCTL)
                vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
        res = video_ioctl2(filp, cmd, arg);
index de5e723fdf445bbbbd66181c8ac26f5175f716e0..2226e5791e99412a4437ca73cd4bd7f59cd80796 100644 (file)
@@ -83,6 +83,8 @@ static const struct cx18_api_info api_info[] = {
        API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK,                 0),
        API_ENTRY(CPU, CX18_CPU_DE_SET_MDL,                     API_FAST),
        API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL,                 API_SLOW),
+       API_ENTRY(APU, CX18_APU_START,                          0),
+       API_ENTRY(APU, CX18_APU_STOP,                           0),
        API_ENTRY(APU, CX18_APU_RESETAI,                        0),
        API_ENTRY(CPU, CX18_CPU_DEBUG_PEEK32,                   0),
        API_ENTRY(0, 0,                                         0),
@@ -98,21 +100,30 @@ static const struct cx18_api_info *find_api_info(u32 cmd)
        return NULL;
 }
 
-static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name)
+/* Call with buf of n*11+1 bytes */
+static char *u32arr2hex(u32 data[], int n, char *buf)
 {
-       char argstr[MAX_MB_ARGUMENTS*11+1];
        char *p;
        int i;
 
+       for (i = 0, p = buf; i < n; i++, p += 11) {
+               /* kernel snprintf() appends '\0' always */
+               snprintf(p, 12, " %#010x", data[i]);
+       }
+       *p = '\0';
+       return buf;
+}
+
+static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name)
+{
+       char argstr[MAX_MB_ARGUMENTS*11+1];
+
        if (!(cx18_debug & CX18_DBGFLG_API))
                return;
 
-       for (i = 0, p = argstr; i < MAX_MB_ARGUMENTS; i++, p += 11) {
-               /* kernel snprintf() appends '\0' always */
-               snprintf(p, 12, " %#010x", mb->args[i]);
-       }
        CX18_DEBUG_API("%s: req %#010x ack %#010x cmd %#010x err %#010x args%s"
-               "\n", name, mb->request, mb->ack, mb->cmd, mb->error, argstr);
+                      "\n", name, mb->request, mb->ack, mb->cmd, mb->error,
+                      u32arr2hex(mb->args, MAX_MB_ARGUMENTS, argstr));
 }
 
 
@@ -439,7 +450,8 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
                                "incoming %s to EPU mailbox (sequence no. %u)"
                                "\n",
                                rpu_str[rpu], rpu_str[rpu], order_mb->request);
-               dump_mb(cx, order_mb, "incoming");
+               if (cx18_debug & CX18_DBGFLG_WARN)
+                       dump_mb(cx, order_mb, "incoming");
                order->flags = CX18_F_EWO_MB_STALE_UPON_RECEIPT;
        }
 
@@ -468,16 +480,24 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
        struct mutex *mb_lock;
        long int timeout, ret;
        int i;
+       char argstr[MAX_MB_ARGUMENTS*11+1];
 
        if (info == NULL) {
                CX18_WARN("unknown cmd %x\n", cmd);
                return -EINVAL;
        }
 
-       if (cmd == CX18_CPU_DE_SET_MDL)
-               CX18_DEBUG_HI_API("%s\n", info->name);
-       else
-               CX18_DEBUG_API("%s\n", info->name);
+       if (cx18_debug & CX18_DBGFLG_API) { /* only call u32arr2hex if needed */
+               if (cmd == CX18_CPU_DE_SET_MDL) {
+                       if (cx18_debug & CX18_DBGFLG_HIGHVOL)
+                               CX18_DEBUG_HI_API("%s\tcmd %#010x args%s\n",
+                                               info->name, cmd,
+                                               u32arr2hex(data, args, argstr));
+               } else
+                       CX18_DEBUG_API("%s\tcmd %#010x args%s\n",
+                                      info->name, cmd,
+                                      u32arr2hex(data, args, argstr));
+       }
 
        switch (info->rpu) {
        case APU:
index 8d9441e88c4ef4f2a62b0a564576c20f78f6560d..3046b8e74345081d30608af439ff09e17b3a331f 100644 (file)
@@ -204,7 +204,7 @@ int cx18_stream_alloc(struct cx18_stream *s)
                }
                buf->id = cx->buffer_id++;
                INIT_LIST_HEAD(&buf->list);
-               buf->dma_handle = pci_map_single(s->cx->dev,
+               buf->dma_handle = pci_map_single(s->cx->pci_dev,
                                buf->buf, s->buf_size, s->dma);
                cx18_buf_sync_for_cpu(s, buf);
                cx18_enqueue(s, buf, &s->q_free);
@@ -227,7 +227,7 @@ void cx18_stream_free(struct cx18_stream *s)
 
        /* empty q_free */
        while ((buf = cx18_dequeue(s, &s->q_free))) {
-               pci_unmap_single(s->cx->dev, buf->dma_handle,
+               pci_unmap_single(s->cx->pci_dev, buf->dma_handle,
                                s->buf_size, s->dma);
                kfree(buf->buf);
                kfree(buf);
index 456cec3bc28f2b9a193f75fd2179209c6f8d11b6..4de06269d88f74f0afac8c36cb870531097f3773 100644 (file)
 static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s,
        struct cx18_buffer *buf)
 {
-       pci_dma_sync_single_for_cpu(s->cx->dev, buf->dma_handle,
+       pci_dma_sync_single_for_cpu(s->cx->pci_dev, buf->dma_handle,
                                s->buf_size, s->dma);
 }
 
 static inline void cx18_buf_sync_for_device(struct cx18_stream *s,
        struct cx18_buffer *buf)
 {
-       pci_dma_sync_single_for_device(s->cx->dev, buf->dma_handle,
+       pci_dma_sync_single_for_device(s->cx->pci_dev, buf->dma_handle,
                                s->buf_size, s->dma);
 }
 
index 89c1ec94f33593b590ae0039b09597e72d29b5fa..0932b76b2373a76022274e5163c1976c5107191c 100644 (file)
@@ -32,7 +32,6 @@
 #include "cx18-streams.h"
 #include "cx18-cards.h"
 #include "cx18-scb.h"
-#include "cx18-av-core.h"
 #include "cx18-dvb.h"
 
 #define CX18_DSP0_INTERRUPT_MASK       0xd0004C
@@ -101,11 +100,11 @@ static struct {
 static void cx18_stream_init(struct cx18 *cx, int type)
 {
        struct cx18_stream *s = &cx->streams[type];
-       struct video_device *dev = s->v4l2dev;
+       struct video_device *video_dev = s->video_dev;
 
-       /* we need to keep v4l2dev, so restore it afterwards */
+       /* we need to keep video_dev, so restore it afterwards */
        memset(s, 0, sizeof(*s));
-       s->v4l2dev = dev;
+       s->video_dev = video_dev;
 
        /* initialize cx18_stream fields */
        s->cx = cx;
@@ -130,12 +129,12 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
        struct cx18_stream *s = &cx->streams[type];
        u32 cap = cx->v4l2_cap;
        int num_offset = cx18_stream_info[type].num_offset;
-       int num = cx->num + cx18_first_minor + num_offset;
+       int num = cx->instance + cx18_first_minor + num_offset;
 
-       /* These four fields are always initialized. If v4l2dev == NULL, then
+       /* These four fields are always initialized. If video_dev == NULL, then
           this stream is not in use. In that case no other fields but these
           four can be used. */
-       s->v4l2dev = NULL;
+       s->video_dev = NULL;
        s->cx = cx;
        s->type = type;
        s->name = cx18_stream_info[type].name;
@@ -163,22 +162,22 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
                return 0;
 
        /* allocate and initialize the v4l2 video device structure */
-       s->v4l2dev = video_device_alloc();
-       if (s->v4l2dev == NULL) {
+       s->video_dev = video_device_alloc();
+       if (s->video_dev == NULL) {
                CX18_ERR("Couldn't allocate v4l2 video_device for %s\n",
                                s->name);
                return -ENOMEM;
        }
 
-       snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18-%d",
-                       cx->num);
+       snprintf(s->video_dev->name, sizeof(s->video_dev->name), "%s %s",
+                cx->v4l2_dev.name, s->name);
 
-       s->v4l2dev->num = num;
-       s->v4l2dev->parent = &cx->dev->dev;
-       s->v4l2dev->fops = &cx18_v4l2_enc_fops;
-       s->v4l2dev->release = video_device_release;
-       s->v4l2dev->tvnorms = V4L2_STD_ALL;
-       cx18_set_funcs(s->v4l2dev);
+       s->video_dev->num = num;
+       s->video_dev->v4l2_dev = &cx->v4l2_dev;
+       s->video_dev->fops = &cx18_v4l2_enc_fops;
+       s->video_dev->release = video_device_release;
+       s->video_dev->tvnorms = V4L2_STD_ALL;
+       cx18_set_funcs(s->video_dev);
        return 0;
 }
 
@@ -227,28 +226,30 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
                }
        }
 
-       if (s->v4l2dev == NULL)
+       if (s->video_dev == NULL)
                return 0;
 
-       num = s->v4l2dev->num;
+       num = s->video_dev->num;
        /* card number + user defined offset + device offset */
        if (type != CX18_ENC_STREAM_TYPE_MPG) {
                struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
 
-               if (s_mpg->v4l2dev)
-                       num = s_mpg->v4l2dev->num + cx18_stream_info[type].num_offset;
+               if (s_mpg->video_dev)
+                       num = s_mpg->video_dev->num
+                           + cx18_stream_info[type].num_offset;
        }
+       video_set_drvdata(s->video_dev, s);
 
        /* Register device. First try the desired minor, then any free one. */
-       ret = video_register_device(s->v4l2dev, vfl_type, num);
+       ret = video_register_device(s->video_dev, vfl_type, num);
        if (ret < 0) {
                CX18_ERR("Couldn't register v4l2 device for %s kernel number %d\n",
                        s->name, num);
-               video_device_release(s->v4l2dev);
-               s->v4l2dev = NULL;
+               video_device_release(s->video_dev);
+               s->video_dev = NULL;
                return ret;
        }
-       num = s->v4l2dev->num;
+       num = s->video_dev->num;
 
        switch (vfl_type) {
        case VFL_TYPE_GRABBER:
@@ -312,9 +313,9 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
                        cx->streams[type].dvb.enabled = false;
                }
 
-               vdev = cx->streams[type].v4l2dev;
+               vdev = cx->streams[type].video_dev;
 
-               cx->streams[type].v4l2dev = NULL;
+               cx->streams[type].video_dev = NULL;
                if (vdev == NULL)
                        continue;
 
@@ -346,46 +347,88 @@ static void cx18_vbi_setup(struct cx18_stream *s)
        }
 
        /* setup VBI registers */
-       cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
-
-       /* determine number of lines and total number of VBI bytes.
-          A raw line takes 1444 bytes: 4 byte SAV code + 2 * 720
-          A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal
-          header, 42 data bytes + checksum (to be confirmed) */
+       v4l2_subdev_call(cx->sd_av, video, s_fmt, &cx->vbi.in);
+
+       /*
+        * Send the CX18_CPU_SET_RAW_VBI_PARAM API command to setup Encoder Raw
+        * VBI when the first analog capture channel starts, as once it starts
+        * (e.g. MPEG), we can't effect any change in the Encoder Raw VBI setup
+        * (i.e. for the VBI capture channels).  We also send it for each
+        * analog capture channel anyway just to make sure we get the proper
+        * behavior
+        */
        if (raw) {
                lines = cx->vbi.count * 2;
        } else {
-               lines = cx->is_60hz ? 24 : 38;
-               if (cx->is_60hz)
-                       lines += 2;
+               /*
+                * For 525/60 systems, according to the VIP 2 & BT.656 std:
+                * The EAV RP code's Field bit toggles on line 4, a few lines
+                * after the Vertcal Blank bit has already toggled.
+                * Tell the encoder to capture 21-4+1=18 lines per field,
+                * since we want lines 10 through 21.
+                *
+                * FIXME - revisit for 625/50 systems
+                */
+               lines = cx->is_60hz ? (21 - 4 + 1) * 2 : 38;
        }
 
-       cx->vbi.enc_size = lines *
-               (raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
-
        data[0] = s->handle;
        /* Lines per field */
        data[1] = (lines / 2) | ((lines / 2) << 16);
        /* bytes per line */
-       data[2] = (raw ? cx->vbi.raw_decoder_line_size
-                      : cx->vbi.sliced_decoder_line_size);
+       data[2] = (raw ? vbi_active_samples
+                      : (cx->is_60hz ? vbi_hblank_samples_60Hz
+                                     : vbi_hblank_samples_50Hz));
        /* Every X number of frames a VBI interrupt arrives
           (frames as in 25 or 30 fps) */
        data[3] = 1;
-       /* Setup VBI for the cx25840 digitizer */
+       /*
+        * Set the SAV/EAV RP codes to look for as start/stop points
+        * when in VIP-1.1 mode
+        */
        if (raw) {
+               /*
+                * Start codes for beginning of "active" line in vertical blank
+                * 0x20 (               VerticalBlank                )
+                * 0x60 (     EvenField VerticalBlank                )
+                */
                data[4] = 0x20602060;
+               /*
+                * End codes for end of "active" raw lines and regular lines
+                * 0x30 (               VerticalBlank HorizontalBlank)
+                * 0x70 (     EvenField VerticalBlank HorizontalBlank)
+                * 0x90 (Task                         HorizontalBlank)
+                * 0xd0 (Task EvenField               HorizontalBlank)
+                */
                data[5] = 0x307090d0;
        } else {
+               /*
+                * End codes for active video, we want data in the hblank region
+                * 0xb0 (Task         0 VerticalBlank HorizontalBlank)
+                * 0xf0 (Task EvenField VerticalBlank HorizontalBlank)
+                *
+                * Since the V bit is only allowed to toggle in the EAV RP code,
+                * just before the first active region line, these two
+                * are problematic:
+                * 0x90 (Task                         HorizontalBlank)
+                * 0xd0 (Task EvenField               HorizontalBlank)
+                *
+                * We have set the digitzer such that we don't have to worry
+                * about these problem codes.
+                */
                data[4] = 0xB0F0B0F0;
+               /*
+                * Start codes for beginning of active line in vertical blank
+                * 0xa0 (Task           VerticalBlank                )
+                * 0xe0 (Task EvenField VerticalBlank                )
+                */
                data[5] = 0xA0E0A0E0;
        }
 
        CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n",
                        data[0], data[1], data[2], data[3], data[4], data[5]);
 
-       if (s->type == CX18_ENC_STREAM_TYPE_VBI)
-               cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
+       cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
 }
 
 struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
@@ -434,10 +477,10 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
        u32 data[MAX_MB_ARGUMENTS];
        struct cx18 *cx = s->cx;
        struct cx18_buffer *buf;
-       int ts = 0;
        int captype = 0;
+       struct cx18_api_func_private priv;
 
-       if (s->v4l2dev == NULL && s->dvb.enabled == 0)
+       if (s->video_dev == NULL && s->dvb.enabled == 0)
                return -EINVAL;
 
        CX18_DEBUG_INFO("Start encoder stream %s\n", s->name);
@@ -453,7 +496,6 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
 
        case CX18_ENC_STREAM_TYPE_TS:
                captype = CAPTURE_CHANNEL_TYPE_TS;
-               ts = 1;
                break;
        case CX18_ENC_STREAM_TYPE_YUV:
                captype = CAPTURE_CHANNEL_TYPE_YUV;
@@ -462,8 +504,16 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
                captype = CAPTURE_CHANNEL_TYPE_PCM;
                break;
        case CX18_ENC_STREAM_TYPE_VBI:
+#ifdef CX18_ENCODER_PARSES_SLICED
                captype = cx18_raw_vbi(cx) ?
                     CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI;
+#else
+               /*
+                * Currently we set things up so that Sliced VBI from the
+                * digitizer is handled as Raw VBI by the encoder
+                */
+               captype = CAPTURE_CHANNEL_TYPE_VBI;
+#endif
                cx->vbi.frame = 0;
                cx->vbi.inserted_frame = 0;
                memset(cx->vbi.sliced_mpeg_size,
@@ -473,10 +523,6 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
                return -EINVAL;
        }
 
-       /* mute/unmute video */
-       cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
-                 s->handle, !!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags));
-
        /* Clear Streamoff flags in case left from last capture */
        clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
 
@@ -484,31 +530,63 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
        s->handle = data[0];
        cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype);
 
-       if (atomic_read(&cx->ana_capturing) == 0 && !ts) {
-               struct cx18_api_func_private priv;
-
-               /* Stuff from Windows, we don't know what it is */
+       /*
+        * For everything but CAPTURE_CHANNEL_TYPE_TS, play it safe and
+        * set up all the parameters, as it is not obvious which parameters the
+        * firmware shares across capture channel types and which it does not.
+        *
+        * Some of the cx18_vapi() calls below apply to only certain capture
+        * channel types.  We're hoping there's no harm in calling most of them
+        * anyway, as long as the values are all consistent.  Setting some
+        * shared parameters will have no effect once an analog capture channel
+        * has started streaming.
+        */
+       if (captype != CAPTURE_CHANNEL_TYPE_TS) {
                cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0);
                cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1);
                cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0);
                cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1);
-               cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, s->handle, 12);
 
+               /*
+                * Audio related reset according to
+                * Documentation/video4linux/cx2341x/fw-encoder-api.txt
+                */
+               if (atomic_read(&cx->ana_capturing) == 0)
+                       cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
+                                 s->handle, 12);
+
+               /*
+                * Number of lines for Field 1 & Field 2 according to
+                * Documentation/video4linux/cx2341x/fw-encoder-api.txt
+                * Field 1 is 312 for 625 line systems in BT.656
+                * Field 2 is 313 for 625 line systems in BT.656
+                */
                cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3,
-                              s->handle, cx->digitizer, cx->digitizer);
+                         s->handle, 312, 313);
 
-               /* Setup VBI */
                if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE)
                        cx18_vbi_setup(s);
 
-               /* assign program index info.
-                  Mask 7: select I/P/B, Num_req: 400 max */
+               /*
+                * assign program index info.
+                * Mask 7: select I/P/B, Num_req: 400 max
+                * FIXME - currently we have this hardcoded as disabled
+                */
                cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 1, 0);
 
-               /* Setup API for Stream */
+               /* Call out to the common CX2341x API setup for user controls */
                priv.cx = cx;
                priv.s = s;
                cx2341x_update(&priv, cx18_api_func, NULL, &cx->params);
+
+               /*
+                * When starting a capture and we're set for radio,
+                * ensure the video is muted, despite the user control.
+                */
+               if (!cx->params.video_mute &&
+                   test_bit(CX18_F_I_RADIO_USER, &cx->i_flags))
+                       cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
+                                 (cx->params.video_mute_yuv << 8) | 1);
        }
 
        if (atomic_read(&cx->tot_capturing) == 0) {
@@ -552,7 +630,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
        }
 
        /* you're live! sit back and await interrupts :) */
-       if (!ts)
+       if (captype != CAPTURE_CHANNEL_TYPE_TS)
                atomic_inc(&cx->ana_capturing);
        atomic_inc(&cx->tot_capturing);
        return 0;
@@ -565,7 +643,7 @@ void cx18_stop_all_captures(struct cx18 *cx)
        for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) {
                struct cx18_stream *s = &cx->streams[i];
 
-               if (s->v4l2dev == NULL && s->dvb.enabled == 0)
+               if (s->video_dev == NULL && s->dvb.enabled == 0)
                        continue;
                if (test_bit(CX18_F_S_STREAMING, &s->s_flags))
                        cx18_stop_v4l2_encode_stream(s, 0);
@@ -577,7 +655,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
        struct cx18 *cx = s->cx;
        unsigned long then;
 
-       if (s->v4l2dev == NULL && s->dvb.enabled == 0)
+       if (s->video_dev == NULL && s->dvb.enabled == 0)
                return -EINVAL;
 
        /* This function assumes that you are allowed to stop the capture
@@ -629,7 +707,7 @@ u32 cx18_find_handle(struct cx18 *cx)
        for (i = 0; i < CX18_MAX_STREAMS; i++) {
                struct cx18_stream *s = &cx->streams[i];
 
-               if (s->v4l2dev && (s->handle != CX18_INVALID_TASK_HANDLE))
+               if (s->video_dev && (s->handle != CX18_INVALID_TASK_HANDLE))
                        return s->handle;
        }
        return CX18_INVALID_TASK_HANDLE;
@@ -647,7 +725,7 @@ struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle)
                s = &cx->streams[i];
                if (s->handle != handle)
                        continue;
-               if (s->v4l2dev || s->dvb.enabled)
+               if (s->video_dev || s->dvb.enabled)
                        return s;
        }
        return NULL;
index fb595bd548e898f80d29f6d98982c3dfe8b91def..c2aef4add31da91aceb70ddaf03a9366561df36e 100644 (file)
 #include "cx18-vbi.h"
 #include "cx18-ioctl.h"
 #include "cx18-queue.h"
-#include "cx18-av-core.h"
+
+/*
+ * Raster Reference/Protection (RP) bytes, used in Start/End Active
+ * Video codes emitted from the digitzer in VIP 1.x mode, that flag the start
+ * of VBI sample or VBI ancilliary data regions in the digitial ratser line.
+ *
+ * Task FieldEven VerticalBlank HorizontalBlank 0 0 0 0
+ */
+static const u8 raw_vbi_sav_rp[2] = { 0x20, 0x60 };    /* __V_, _FV_ */
+static const u8 sliced_vbi_eav_rp[2] = { 0xb0, 0xf0 }; /* T_VH, TFVH */
 
 static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
 {
@@ -34,10 +43,17 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
        u32 linemask[2] = { 0, 0 };
        unsigned short size;
        static const u8 mpeg_hdr_data[] = {
-               0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66,
-               0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff,
-               0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80,
-               0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff
+               /* MPEG-2 Program Pack */
+               0x00, 0x00, 0x01, 0xba,             /* Prog Pack start code */
+               0x44, 0x00, 0x0c, 0x66, 0x24, 0x01, /* SCR, SCR Ext, markers */
+               0x01, 0xd1, 0xd3,                   /* Mux Rate, markers */
+               0xfa, 0xff, 0xff,                   /* Res, Suff cnt, Stuff */
+               /* MPEG-2 Private Stream 1 PES Packet */
+               0x00, 0x00, 0x01, 0xbd,             /* Priv Stream 1 start */
+               0x00, 0x1a,                         /* length */
+               0x84, 0x80, 0x07,                   /* flags, hdr data len */
+               0x21, 0x00, 0x5d, 0x63, 0xa7,       /* PTS, markers */
+               0xff, 0xff                          /* stuffing */
        };
        const int sd = sizeof(mpeg_hdr_data);   /* start of vbi data */
        int idx = cx->vbi.frame % CX18_VBI_FRAMES;
@@ -71,7 +87,9 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
                memcpy(dst + sd + 4, dst + sd + 12, line * 43);
                size = 4 + ((43 * line + 3) & ~3);
        } else {
-               memcpy(dst + sd, "cx0", 4);
+               memcpy(dst + sd, "itv0", 4);
+               cpu_to_le32s(&linemask[0]);
+               cpu_to_le32s(&linemask[1]);
                memcpy(dst + sd + 4, &linemask[0], 8);
                size = 12 + ((43 * line + 3) & ~3);
        }
@@ -86,58 +104,76 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
 }
 
 /* Compress raw VBI format, removes leading SAV codes and surplus space
-   after the field.
-   Returns new compressed size. */
-static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size)
+   after the frame.  Returns new compressed size. */
+static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size, u32 hdr_size)
 {
-       u32 line_size = cx->vbi.raw_decoder_line_size;
-       u32 lines = cx->vbi.count;
-       u8 sav1 = cx->vbi.raw_decoder_sav_odd_field;
-       u8 sav2 = cx->vbi.raw_decoder_sav_even_field;
+       u32 line_size = vbi_active_samples;
+       u32 lines = cx->vbi.count * 2;
        u8 *q = buf;
        u8 *p;
        int i;
 
+       /* Skip the header */
+       buf += hdr_size;
+
        for (i = 0; i < lines; i++) {
                p = buf + i * line_size;
 
                /* Look for SAV code */
                if (p[0] != 0xff || p[1] || p[2] ||
-                   (p[3] != sav1 && p[3] != sav2))
+                   (p[3] != raw_vbi_sav_rp[0] &&
+                    p[3] != raw_vbi_sav_rp[1]))
                        break;
-               memcpy(q, p + 4, line_size - 4);
-               q += line_size - 4;
+               if (i == lines - 1) {
+                       /* last line is hdr_size bytes short - extrapolate it */
+                       memcpy(q, p + 4, line_size - 4 - hdr_size);
+                       q += line_size - 4 - hdr_size;
+                       p += line_size - hdr_size - 1;
+                       memset(q, (int) *p, hdr_size);
+               } else {
+                       memcpy(q, p + 4, line_size - 4);
+                       q += line_size - 4;
+               }
        }
        return lines * (line_size - 4);
 }
 
-
-/* Compressed VBI format, all found sliced blocks put next to one another
-   Returns new compressed size */
-static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
-                              u32 size, u8 sav)
+static u32 compress_sliced_buf(struct cx18 *cx, u8 *buf, u32 size,
+                              const u32 hdr_size)
 {
-       u32 line_size = cx->vbi.sliced_decoder_line_size;
        struct v4l2_decode_vbi_line vbi;
        int i;
+       u32 line = 0;
+       u32 line_size = cx->is_60hz ? vbi_hblank_samples_60Hz
+                                   : vbi_hblank_samples_50Hz;
 
        /* find the first valid line */
-       for (i = 0; i < size; i++, buf++) {
-               if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav)
+       for (i = hdr_size, buf += hdr_size; i < size; i++, buf++) {
+               if (buf[0] == 0xff && !buf[1] && !buf[2] &&
+                   (buf[3] == sliced_vbi_eav_rp[0] ||
+                    buf[3] == sliced_vbi_eav_rp[1]))
                        break;
        }
 
-       size -= i;
+       /*
+        * The last line is short by hdr_size bytes, but for the remaining
+        * checks against size, we pretend that it is not, by counting the
+        * header bytes we knowingly skipped
+        */
+       size -= (i - hdr_size);
        if (size < line_size)
                return line;
+
        for (i = 0; i < size / line_size; i++) {
                u8 *p = buf + i * line_size;
 
-               /* Look for SAV code  */
-               if (p[0] != 0xff || p[1] || p[2] || p[3] != sav)
+               /* Look for EAV code  */
+               if (p[0] != 0xff || p[1] || p[2] ||
+                   (p[3] != sliced_vbi_eav_rp[0] &&
+                    p[3] != sliced_vbi_eav_rp[1]))
                        continue;
                vbi.p = p + 4;
-               cx18_av_cmd(cx, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
+               v4l2_subdev_call(cx->sd_av, video, decode_vbi_line, &vbi);
                if (vbi.type) {
                        cx->vbi.sliced_data[line].id = vbi.type;
                        cx->vbi.sliced_data[line].field = vbi.is_second_field;
@@ -150,51 +186,56 @@ static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
 }
 
 void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
-                          u64 pts_stamp, int streamtype)
+                          int streamtype)
 {
+       /*
+        * The CX23418 provides a 12 byte header in its raw VBI buffers to us:
+        * 0x3fffffff [4 bytes of something] [4 byte presentation time stamp]
+        */
+       struct vbi_data_hdr {
+               __be32 magic;
+               __be32 unknown;
+               __be32 pts;
+       } *hdr = (struct vbi_data_hdr *) buf->buf;
+
        u8 *p = (u8 *) buf->buf;
        u32 size = buf->bytesused;
+       u32 pts;
        int lines;
 
        if (streamtype != CX18_ENC_STREAM_TYPE_VBI)
                return;
 
+       /*
+        * The CX23418 sends us data that is 32 bit little-endian swapped,
+        * but we want the raw VBI bytes in the order they were in the raster
+        * line.  This has a side effect of making the header big endian
+        */
+       cx18_buf_swap(buf);
+
        /* Raw VBI data */
        if (cx18_raw_vbi(cx)) {
-               u8 type;
-
-               cx18_buf_swap(buf);
-
-               /* Skip 12 bytes of header that gets stuffed in */
-               size -= 12;
-               memcpy(p, &buf->buf[12], size);
-               type = p[3];
 
-               size = buf->bytesused = compress_raw_buf(cx, p, size);
+               size = buf->bytesused =
+                    compress_raw_buf(cx, p, size, sizeof(struct vbi_data_hdr));
 
-               /* second field of the frame? */
-               if (type == cx->vbi.raw_decoder_sav_even_field) {
-                       /* Dirty hack needed for backwards
-                          compatibility of old VBI software. */
-                       p += size - 4;
-                       memcpy(p, &cx->vbi.frame, 4);
-                       cx->vbi.frame++;
-               }
+               /*
+                * Hack needed for compatibility with old VBI software.
+                * Write the frame # at the last 4 bytes of the frame
+                */
+               p += size - 4;
+               memcpy(p, &cx->vbi.frame, 4);
+               cx->vbi.frame++;
                return;
        }
 
        /* Sliced VBI data with data insertion */
-       cx18_buf_swap(buf);
 
-       /* first field */
-       lines = compress_sliced_buf(cx, 0, p, size / 2,
-                       cx->vbi.sliced_decoder_sav_odd_field);
-       /* second field */
-       /* experimentation shows that the second half does not always
-          begin at the exact address. So start a bit earlier
-          (hence 32). */
-       lines = compress_sliced_buf(cx, lines, p + size / 2 - 32,
-                       size / 2 + 32, cx->vbi.sliced_decoder_sav_even_field);
+       pts = (be32_to_cpu(hdr->magic) == 0x3fffffff) ? be32_to_cpu(hdr->pts)
+                                                     : 0;
+
+       lines = compress_sliced_buf(cx, p, size, sizeof(struct vbi_data_hdr));
+
        /* always return at least one empty line */
        if (lines == 0) {
                cx->vbi.sliced_data[0].id = 0;
@@ -206,6 +247,6 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
        memcpy(p, &cx->vbi.sliced_data[0], size);
 
        if (cx->vbi.insert_mpeg)
-               copy_vbi_data(cx, lines, pts_stamp);
+               copy_vbi_data(cx, lines, pts);
        cx->vbi.frame++;
 }
index c56ff7d28f20f60706c51ebab4ad53a55f5ab833..e7e1ae427f34592bff07fd00cce15c244919cc82 100644 (file)
@@ -22,5 +22,5 @@
  */
 
 void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
-                          u64 pts_stamp, int streamtype);
+                          int streamtype);
 int cx18_used_line(struct cx18 *cx, int line, int field);
index 84c0ff13b607d6f8f27283917bbd3b9aca9d2f00..bd9bd44da791a3df585609523574199294520384 100644 (file)
@@ -24,8 +24,8 @@
 
 #define CX18_DRIVER_NAME "cx18"
 #define CX18_DRIVER_VERSION_MAJOR 1
-#define CX18_DRIVER_VERSION_MINOR 0
-#define CX18_DRIVER_VERSION_PATCHLEVEL 4
+#define CX18_DRIVER_VERSION_MINOR 1
+#define CX18_DRIVER_VERSION_PATCHLEVEL 0
 
 #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
 #define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \
index 2e5c41939330b7c19b3a49848693fd893d4d2e2e..6fdadedf17a89c8413c5797dac54153d95d0b351 100644 (file)
@@ -21,7 +21,6 @@
 
 #include "cx18-driver.h"
 #include "cx18-video.h"
-#include "cx18-av-core.h"
 #include "cx18-cards.h"
 
 void cx18_video_set_io(struct cx18 *cx)
@@ -32,7 +31,7 @@ void cx18_video_set_io(struct cx18 *cx)
 
        route.input = cx->card->video_inputs[inp].video_input;
        route.output = 0;
-       cx18_av_cmd(cx, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+       v4l2_subdev_call(cx->sd_av, video, s_routing, &route);
 
        type = cx->card->video_inputs[inp].video_type;
 
index 601f3a2ab7425d0873fec3d9ea0eb504d8d3496e..9956abf576c598a50e75e718216730c72e66e44a 100644 (file)
 #define APU_CMD_MASK                           0x10000000
 #define APU_CMD_MASK_ACK                       (APU_CMD_MASK | 0x80000000)
 
+#define CX18_APU_ENCODING_METHOD_MPEG          (0 << 28)
+#define CX18_APU_ENCODING_METHOD_AC3           (1 << 28)
+
+/* Description: Command APU to start audio
+   IN[0] - audio parameters (same as CX18_CPU_SET_AUDIO_PARAMETERS?)
+   IN[1] - caller buffer address, or 0
+   ReturnCode - ??? */
+#define CX18_APU_START                         (APU_CMD_MASK | 0x01)
+
+/* Description: Command APU to stop audio
+   IN[0] - encoding method to stop
+   ReturnCode - ??? */
+#define CX18_APU_STOP                          (APU_CMD_MASK | 0x02)
+
+/* Description: Command APU to reset the AI
+   ReturnCode - ??? */
 #define CX18_APU_RESETAI                       (APU_CMD_MASK | 0x05)
 
 /* Description: This command indicates that a Memory Descriptor List has been
index cbbe47fb87b7a7c6a836f0fee5e2422cb6e41a95..8ded52946334e2abcec10d04f776492c91952373 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * cx2341x - generic code for cx23415/6 based devices
+ * cx2341x - generic code for cx23415/6/8 based devices
  *
  * Copyright (C) 2006 Hans Verkuil <hverkuil@xs4all.nl>
  *
@@ -30,7 +30,7 @@
 #include <media/cx2341x.h>
 #include <media/v4l2-common.h>
 
-MODULE_DESCRIPTION("cx23415/6 driver");
+MODULE_DESCRIPTION("cx23415/6/8 driver");
 MODULE_AUTHOR("Hans Verkuil");
 MODULE_LICENSE("GPL");
 
@@ -38,6 +38,7 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
+/* Must be sorted from low to high control ID! */
 const u32 cx2341x_mpeg_ctrls[] = {
        V4L2_CID_MPEG_CLASS,
        V4L2_CID_MPEG_STREAM_TYPE,
@@ -50,6 +51,7 @@ const u32 cx2341x_mpeg_ctrls[] = {
        V4L2_CID_MPEG_AUDIO_EMPHASIS,
        V4L2_CID_MPEG_AUDIO_CRC,
        V4L2_CID_MPEG_AUDIO_MUTE,
+       V4L2_CID_MPEG_AUDIO_AC3_BITRATE,
        V4L2_CID_MPEG_VIDEO_ENCODING,
        V4L2_CID_MPEG_VIDEO_ASPECT,
        V4L2_CID_MPEG_VIDEO_B_FRAMES,
@@ -94,6 +96,7 @@ static const struct cx2341x_mpeg_params default_params = {
        .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
        .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
        .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
+       .audio_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_224K,
        .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
        .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
        .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
@@ -148,6 +151,9 @@ static int cx2341x_get_ctrl(const struct cx2341x_mpeg_params *params,
        case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
                ctrl->value = params->audio_l2_bitrate;
                break;
+       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+               ctrl->value = params->audio_ac3_bitrate;
+               break;
        case V4L2_CID_MPEG_AUDIO_MODE:
                ctrl->value = params->audio_mode;
                break;
@@ -256,6 +262,12 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
                params->audio_sampling_freq = ctrl->value;
                break;
        case V4L2_CID_MPEG_AUDIO_ENCODING:
+               if (busy)
+                       return -EBUSY;
+               if (params->capabilities & CX2341X_CAP_HAS_AC3)
+                       if (ctrl->value != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
+                           ctrl->value != V4L2_MPEG_AUDIO_ENCODING_AC3)
+                               return -ERANGE;
                params->audio_encoding = ctrl->value;
                break;
        case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
@@ -263,6 +275,13 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
                        return -EBUSY;
                params->audio_l2_bitrate = ctrl->value;
                break;
+       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+               if (busy)
+                       return -EBUSY;
+               if (!(params->capabilities & CX2341X_CAP_HAS_AC3))
+                       return -EINVAL;
+               params->audio_ac3_bitrate = ctrl->value;
+               break;
        case V4L2_CID_MPEG_AUDIO_MODE:
                params->audio_mode = ctrl->value;
                break;
@@ -481,29 +500,106 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
        int err;
 
        switch (qctrl->id) {
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+                               V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1,
+                               V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+
+       case V4L2_CID_MPEG_STREAM_VBI_FMT:
+               if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
+                       return v4l2_ctrl_query_fill(qctrl,
+                                       V4L2_MPEG_STREAM_VBI_FMT_NONE,
+                                       V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1,
+                                       V4L2_MPEG_STREAM_VBI_FMT_NONE);
+               return cx2341x_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_STREAM_VBI_FMT_NONE,
+                               V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
+                               default_params.stream_vbi_fmt);
+
+       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100,
+                               V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1,
+                               V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+
        case V4L2_CID_MPEG_AUDIO_ENCODING:
+               if (params->capabilities & CX2341X_CAP_HAS_AC3) {
+                       /*
+                        * The state of L2 & AC3 bitrate controls can change
+                        * when this control changes, but v4l2_ctrl_query_fill()
+                        * already sets V4L2_CTRL_FLAG_UPDATE for
+                        * V4L2_CID_MPEG_AUDIO_ENCODING, so we don't here.
+                        */
+                       return v4l2_ctrl_query_fill(qctrl,
+                                       V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+                                       V4L2_MPEG_AUDIO_ENCODING_AC3, 1,
+                                       default_params.audio_encoding);
+               }
+
                return v4l2_ctrl_query_fill(qctrl,
                                V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
                                V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
                                default_params.audio_encoding);
 
        case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
-               return v4l2_ctrl_query_fill(qctrl,
+               err = v4l2_ctrl_query_fill(qctrl,
                                V4L2_MPEG_AUDIO_L2_BITRATE_192K,
                                V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
                                default_params.audio_l2_bitrate);
+               if (err)
+                       return err;
+               if (params->capabilities & CX2341X_CAP_HAS_AC3 &&
+                   params->audio_encoding != V4L2_MPEG_AUDIO_ENCODING_LAYER_2)
+                       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               return 0;
 
-       case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
-       case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
-               return -EINVAL;
+       case V4L2_CID_MPEG_AUDIO_MODE:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_MODE_STEREO,
+                               V4L2_MPEG_AUDIO_MODE_MONO, 1,
+                               V4L2_MPEG_AUDIO_MODE_STEREO);
 
        case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
-               err = v4l2_ctrl_query_fill_std(qctrl);
+               err = v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+                               V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1,
+                               V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4);
                if (err == 0 &&
                    params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
                        qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
                return err;
 
+       case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+                               V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1,
+                               V4L2_MPEG_AUDIO_EMPHASIS_NONE);
+
+       case V4L2_CID_MPEG_AUDIO_CRC:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_CRC_NONE,
+                               V4L2_MPEG_AUDIO_CRC_CRC16, 1,
+                               V4L2_MPEG_AUDIO_CRC_NONE);
+
+       case V4L2_CID_MPEG_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+
+       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+               err = v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_AC3_BITRATE_48K,
+                               V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 1,
+                               default_params.audio_ac3_bitrate);
+               if (err)
+                       return err;
+               if (params->capabilities & CX2341X_CAP_HAS_AC3) {
+                       if (params->audio_encoding !=
+                                                  V4L2_MPEG_AUDIO_ENCODING_AC3)
+                               qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               } else
+                       qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+               return 0;
+
        case V4L2_CID_MPEG_VIDEO_ENCODING:
                /* this setting is read-only for the cx2341x since the
                   V4L2_CID_MPEG_STREAM_TYPE really determines the
@@ -516,32 +612,51 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
                        qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
                return err;
 
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_VIDEO_ASPECT_1x1,
+                               V4L2_MPEG_VIDEO_ASPECT_221x100, 1,
+                               V4L2_MPEG_VIDEO_ASPECT_4x3);
+
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+               return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2);
+
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               return v4l2_ctrl_query_fill(qctrl, 1, 34, 1,
+                               params->is_50hz ? 12 : 15);
+
+       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+               return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
+
        case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-               err = v4l2_ctrl_query_fill_std(qctrl);
+               err = v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+                               V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
+                               V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
                if (err == 0 &&
                    params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
                        qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
                return err;
 
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
+
        case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
-               err = v4l2_ctrl_query_fill_std(qctrl);
+               err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
                if (err == 0 &&
                    params->video_bitrate_mode ==
                                V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
                        qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
                return err;
 
-       case V4L2_CID_MPEG_STREAM_VBI_FMT:
-               if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
-                       return v4l2_ctrl_query_fill_std(qctrl);
-               return cx2341x_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_STREAM_VBI_FMT_NONE,
-                               V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
-                               default_params.stream_vbi_fmt);
+       case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+               return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
 
-       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
-               return v4l2_ctrl_query_fill(qctrl, 1, 34, 1,
-                               params->is_50hz ? 12 : 15);
+       case V4L2_CID_MPEG_VIDEO_MUTE:
+               return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+
+       case V4L2_CID_MPEG_VIDEO_MUTE_YUV:  /* Init YUV (really YCbCr) to black */
+               return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080);
 
        /* CX23415/6 specific */
        case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
@@ -643,7 +758,7 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
                                default_params.stream_insert_nav_packets);
 
        default:
-               return v4l2_ctrl_query_fill_std(qctrl);
+               return -EINVAL;
 
        }
 }
@@ -671,6 +786,15 @@ const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
                NULL
        };
 
+       static const char *mpeg_audio_encoding_l2_ac3[] = {
+               "",
+               "MPEG-1/2 Layer II",
+               "",
+               "",
+               "AC-3",
+               NULL
+       };
+
        static const char *cx2341x_video_spatial_filter_mode_menu[] = {
                "Manual",
                "Auto",
@@ -711,6 +835,9 @@ const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
        case V4L2_CID_MPEG_STREAM_TYPE:
                return (p->capabilities & CX2341X_CAP_HAS_TS) ?
                        mpeg_stream_type_with_ts : mpeg_stream_type_without_ts;
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               return (p->capabilities & CX2341X_CAP_HAS_AC3) ?
+                       mpeg_audio_encoding_l2_ac3 : v4l2_ctrl_get_menu(id);
        case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
        case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
                return NULL;
@@ -730,16 +857,34 @@ const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
 }
 EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
 
+/* definitions for audio properties bits 29-28 */
+#define CX2341X_AUDIO_ENCODING_METHOD_MPEG     0
+#define CX2341X_AUDIO_ENCODING_METHOD_AC3      1
+#define CX2341X_AUDIO_ENCODING_METHOD_LPCM     2
+
 static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
 {
-       params->audio_properties = (params->audio_sampling_freq << 0) |
-               ((3 - params->audio_encoding) << 2) |
-               ((1 + params->audio_l2_bitrate) << 4) |
+       params->audio_properties =
+               (params->audio_sampling_freq << 0) |
                (params->audio_mode << 8) |
                (params->audio_mode_extension << 10) |
                (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17)
                  ? 3 : params->audio_emphasis) << 12) |
                (params->audio_crc << 14);
+
+       if ((params->capabilities & CX2341X_CAP_HAS_AC3) &&
+           params->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) {
+               params->audio_properties |=
+                       /* Not sure if this MPEG Layer II setting is required */
+                       ((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) |
+                       (params->audio_ac3_bitrate << 4) |
+                       (CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28);
+       } else {
+               /* Assuming MPEG Layer II */
+               params->audio_properties |=
+                       ((3 - params->audio_encoding) << 2) |
+                       ((1 + params->audio_l2_bitrate) << 4);
+       }
 }
 
 int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
@@ -1022,7 +1167,10 @@ void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix)
                prefix,
                cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
                cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
-               cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
+               cx2341x_menu_item(p,
+                          p->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3
+                                             ? V4L2_CID_MPEG_AUDIO_AC3_BITRATE
+                                             : V4L2_CID_MPEG_AUDIO_L2_BITRATE),
                cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
                p->audio_mute ? " (muted)" : "");
        if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
index 00f1e2e8889e7fe23431827e17ce9f8b862d2714..fd3fc3e3198a7556069795a39fc0e15b23033bc1 100644 (file)
@@ -15,12 +15,15 @@ config VIDEO_CX23885
        select DVB_S5H1411 if !DVB_FE_CUSTOMISE
        select DVB_LGDT330X if !DVB_FE_CUSTOMISE
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-       select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
-       select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE
-       select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
-       select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
-       select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
+       select DVB_TDA10048 if !DVB_FE_CUSTOMISE
+       select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+       select DVB_STV6110 if !DVB_FE_CUSTOMISE
+       select DVB_STV0900 if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
        ---help---
          This is a video4linux driver for Conexant 23885 based
          TV cards.
index 29c23b44c13c95bd498c705c024024297f885914..ab8ea35c9bfbb8da57f6ffc283d64246f57e6060 100644 (file)
@@ -1,4 +1,6 @@
-cx23885-objs   := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o
+cx23885-objs   := cx23885-cards.o cx23885-video.o cx23885-vbi.o \
+                   cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \
+                   netup-init.o cimax2.o netup-eeprom.o
 
 obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
 
diff --git a/drivers/media/video/cx23885/cimax2.c b/drivers/media/video/cx23885/cimax2.c
new file mode 100644 (file)
index 0000000..9a65369
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * cimax2.c
+ *
+ * CIMax2(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * 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 "cx23885.h"
+#include "dvb_ca_en50221.h"
+/**** Bit definitions for MC417_RWD and MC417_OEN registers  ***
+  bits 31-16
++-----------+
+| Reserved  |
++-----------+
+  bit 15  bit 14  bit 13 bit 12  bit 11  bit 10  bit 9   bit 8
++-------+-------+-------+-------+-------+-------+-------+-------+
+|  WR#  |  RD#  |       |  ACK# |  ADHI |  ADLO |  CS1# |  CS0# |
++-------+-------+-------+-------+-------+-------+-------+-------+
+ bit 7   bit 6   bit 5   bit 4   bit 3   bit 2   bit 1   bit 0
++-------+-------+-------+-------+-------+-------+-------+-------+
+|  DATA7|  DATA6|  DATA5|  DATA4|  DATA3|  DATA2|  DATA1|  DATA0|
++-------+-------+-------+-------+-------+-------+-------+-------+
+***/
+/* MC417 */
+#define NETUP_DATA             0x000000ff
+#define NETUP_WR               0x00008000
+#define NETUP_RD               0x00004000
+#define NETUP_ACK              0x00001000
+#define NETUP_ADHI             0x00000800
+#define NETUP_ADLO             0x00000400
+#define NETUP_CS1              0x00000200
+#define NETUP_CS0              0x00000100
+#define NETUP_EN_ALL           0x00001000
+#define NETUP_CTRL_OFF         (NETUP_CS1 | NETUP_CS0 | NETUP_WR | NETUP_RD)
+#define NETUP_CI_CTL           0x04
+#define NETUP_CI_RD            1
+
+
+static unsigned int ci_dbg;
+module_param(ci_dbg, int, 0644);
+MODULE_PARM_DESC(ci_dbg, "Enable CI debugging");
+
+#define ci_dbg_print(args...) \
+       do { \
+               if (ci_dbg) \
+                       printk(KERN_DEBUG args); \
+       } while (0)
+
+/* stores all private variables for communication with CI */
+struct netup_ci_state {
+       struct dvb_ca_en50221 ca;
+       struct mutex ca_mutex;
+       struct i2c_adapter *i2c_adap;
+       u8 ci_i2c_addr;
+       int status;
+       struct work_struct work;
+       void *priv;
+};
+
+struct mutex gpio_mutex;/* Two CiMax's uses same GPIO lines */
+
+int netup_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg,
+                                               u8 *buf, int len)
+{
+       int ret;
+       struct i2c_msg msg[] = {
+               {
+                       .addr   = addr,
+                       .flags  = 0,
+                       .buf    = &reg,
+                       .len    = 1
+               }, {
+                       .addr   = addr,
+                       .flags  = I2C_M_RD,
+                       .buf    = buf,
+                       .len    = len
+               }
+       };
+
+       ret = i2c_transfer(i2c_adap, msg, 2);
+
+       if (ret != 2) {
+               ci_dbg_print("%s: i2c read error, Reg = 0x%02x, Status = %d\n",
+                                               __func__, reg, ret);
+
+               return -1;
+       }
+
+       ci_dbg_print("%s: i2c read Addr=0x%04x, Reg = 0x%02x, data = %02x\n",
+                                               __func__, addr, reg, buf[0]);
+
+       return 0;
+}
+
+int netup_write_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg,
+                                               u8 *buf, int len)
+{
+       int ret;
+       u8 buffer[len + 1];
+
+       struct i2c_msg msg = {
+               .addr   = addr,
+               .flags  = 0,
+               .buf    = &buffer[0],
+               .len    = len + 1
+       };
+
+       buffer[0] = reg;
+       memcpy(&buffer[1], buf, len);
+
+       ret = i2c_transfer(i2c_adap, &msg, 1);
+
+       if (ret != 1) {
+               ci_dbg_print("%s: i2c write error, Reg=[0x%02x], Status=%d\n",
+                                               __func__, reg, ret);
+               return -1;
+       }
+
+       return 0;
+}
+
+int netup_ci_get_mem(struct cx23885_dev *dev)
+{
+       int mem;
+       unsigned long timeout = jiffies + msecs_to_jiffies(1);
+
+       for (;;) {
+               mem = cx_read(MC417_RWD);
+               if ((mem & NETUP_ACK) == 0)
+                       break;
+               if (time_after(jiffies, timeout))
+                       break;
+               udelay(1);
+       }
+
+       cx_set(MC417_RWD, NETUP_CTRL_OFF);
+
+       return mem & 0xff;
+}
+
+int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot,
+                               u8 flag, u8 read, int addr, u8 data)
+{
+       struct netup_ci_state *state = en50221->data;
+       struct cx23885_tsport *port = state->priv;
+       struct cx23885_dev *dev = port->dev;
+
+       u8 store;
+       int mem;
+       int ret;
+
+       if (0 != slot)
+               return -EINVAL;
+
+       ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr,
+                                                       0, &store, 1);
+       if (ret != 0)
+               return ret;
+
+       store &= ~0x0c;
+       store |= flag;
+
+       ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+                                                       0, &store, 1);
+       if (ret != 0)
+               return ret;
+
+       mutex_lock(&gpio_mutex);
+
+       /* write addr */
+       cx_write(MC417_OEN, NETUP_EN_ALL);
+       cx_write(MC417_RWD, NETUP_CTRL_OFF |
+                               NETUP_ADLO | (0xff & addr));
+       cx_clear(MC417_RWD, NETUP_ADLO);
+       cx_write(MC417_RWD, NETUP_CTRL_OFF |
+                               NETUP_ADHI | (0xff & (addr >> 8)));
+       cx_clear(MC417_RWD, NETUP_ADHI);
+
+       if (read) /* data in */
+               cx_write(MC417_OEN, NETUP_EN_ALL | NETUP_DATA);
+       else /* data out */
+               cx_write(MC417_RWD, NETUP_CTRL_OFF | data);
+
+       /* choose chip */
+       cx_clear(MC417_RWD,
+                       (state->ci_i2c_addr == 0x40) ? NETUP_CS0 : NETUP_CS1);
+       /* read/write */
+       cx_clear(MC417_RWD, (read) ? NETUP_RD : NETUP_WR);
+       mem = netup_ci_get_mem(dev);
+
+       mutex_unlock(&gpio_mutex);
+
+       if (!read)
+               if (mem < 0)
+                       return -EREMOTEIO;
+
+       ci_dbg_print("%s: %s: addr=[0x%02x], %s=%x\n", __func__,
+                       (read) ? "read" : "write", addr,
+                       (flag == NETUP_CI_CTL) ? "ctl" : "mem",
+                       (read) ? mem : data);
+
+       if (read)
+               return mem;
+
+       return 0;
+}
+
+int netup_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
+                                               int slot, int addr)
+{
+       return netup_ci_op_cam(en50221, slot, 0, NETUP_CI_RD, addr, 0);
+}
+
+int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
+                                               int slot, int addr, u8 data)
+{
+       return netup_ci_op_cam(en50221, slot, 0, 0, addr, data);
+}
+
+int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)
+{
+       return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL,
+                                                       NETUP_CI_RD, addr, 0);
+}
+
+int netup_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot,
+                                                       u8 addr, u8 data)
+{
+       return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL, 0, addr, data);
+}
+
+int netup_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
+{
+       struct netup_ci_state *state = en50221->data;
+       u8 buf =  0x80;
+       int ret;
+
+       if (0 != slot)
+               return -EINVAL;
+
+       udelay(500);
+       ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+                                                       0, &buf, 1);
+
+       if (ret != 0)
+               return ret;
+
+       udelay(500);
+
+       buf = 0x00;
+       ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+                                                       0, &buf, 1);
+
+       msleep(1000);
+       dvb_ca_en50221_camready_irq(&state->ca, 0);
+
+       return 0;
+
+}
+
+int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
+{
+       /* not implemented */
+       return 0;
+}
+
+int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot)
+{
+       struct netup_ci_state *state = en50221->data;
+       u8 buf = 0x60;
+
+       if (0 != slot)
+               return -EINVAL;
+
+       return netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+                                                       0, &buf, 1);
+}
+
+/* work handler */
+static void netup_read_ci_status(struct work_struct *work)
+{
+       struct netup_ci_state *state =
+                       container_of(work, struct netup_ci_state, work);
+       u8 buf[33];
+       int ret;
+
+       ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr,
+                                                       0, &buf[0], 33);
+
+       if (ret != 0)
+               return;
+
+       ci_dbg_print("%s: Slot Status Addr=[0x%04x], Reg=[0x%02x], data=%02x, "
+               "TS config = %02x\n", __func__, state->ci_i2c_addr, 0, buf[0],
+               buf[32]);
+
+       if (buf[0] && 1)
+               state->status = DVB_CA_EN50221_POLL_CAM_PRESENT |
+                       DVB_CA_EN50221_POLL_CAM_READY;
+       else
+               state->status = 0;
+}
+
+/* CI irq handler */
+int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status)
+{
+       struct cx23885_tsport *port = NULL;
+       struct netup_ci_state *state = NULL;
+
+       if (pci_status & PCI_MSK_GPIO0)
+               port = &dev->ts1;
+       else if (pci_status & PCI_MSK_GPIO1)
+               port = &dev->ts2;
+       else /* who calls ? */
+               return 0;
+
+       state = port->port_priv;
+
+       schedule_work(&state->work);
+
+       return 1;
+}
+
+int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open)
+{
+       struct netup_ci_state *state = en50221->data;
+
+       if (0 != slot)
+               return -EINVAL;
+
+       return state->status;
+}
+
+int netup_ci_init(struct cx23885_tsport *port)
+{
+       struct netup_ci_state *state;
+       u8 cimax_init[34] = {
+               0x00, /* module A control*/
+               0x00, /* auto select mask high A */
+               0x00, /* auto select mask low A */
+               0x00, /* auto select pattern high A */
+               0x00, /* auto select pattern low A */
+               0x44, /* memory access time A */
+               0x00, /* invert input A */
+               0x00, /* RFU */
+               0x00, /* RFU */
+               0x00, /* module B control*/
+               0x00, /* auto select mask high B */
+               0x00, /* auto select mask low B */
+               0x00, /* auto select pattern high B */
+               0x00, /* auto select pattern low B */
+               0x44, /* memory access time B */
+               0x00, /* invert input B */
+               0x00, /* RFU */
+               0x00, /* RFU */
+               0x00, /* auto select mask high Ext */
+               0x00, /* auto select mask low Ext */
+               0x00, /* auto select pattern high Ext */
+               0x00, /* auto select pattern low Ext */
+               0x00, /* RFU */
+               0x02, /* destination - module A */
+               0x01, /* power on (use it like store place) */
+               0x00, /* RFU */
+               0x00, /* int status read only */
+               0x01, /* all int unmasked */
+               0x04, /* int config */
+               0x00, /* USCG1 */
+               0x04, /* ack active low */
+               0x00, /* LOCK = 0 */
+               0x33, /* serial mode, rising in, rising out, MSB first*/
+               0x31, /* syncronization */
+       };
+       int ret;
+
+       ci_dbg_print("%s\n", __func__);
+       state = kzalloc(sizeof(struct netup_ci_state), GFP_KERNEL);
+       if (!state) {
+               ci_dbg_print("%s: Unable create CI structure!\n", __func__);
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       port->port_priv = state;
+
+       switch (port->nr) {
+       case 1:
+               state->ci_i2c_addr = 0x40;
+               mutex_init(&gpio_mutex);
+               break;
+       case 2:
+               state->ci_i2c_addr = 0x41;
+               break;
+       }
+
+       state->i2c_adap = &port->dev->i2c_bus[0].i2c_adap;
+       state->ca.owner = THIS_MODULE;
+       state->ca.read_attribute_mem = netup_ci_read_attribute_mem;
+       state->ca.write_attribute_mem = netup_ci_write_attribute_mem;
+       state->ca.read_cam_control = netup_ci_read_cam_ctl;
+       state->ca.write_cam_control = netup_ci_write_cam_ctl;
+       state->ca.slot_reset = netup_ci_slot_reset;
+       state->ca.slot_shutdown = netup_ci_slot_shutdown;
+       state->ca.slot_ts_enable = netup_ci_slot_ts_ctl;
+       state->ca.poll_slot_status = netup_poll_ci_slot_status;
+       state->ca.data = state;
+       state->priv = port;
+
+       ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+                                               0, &cimax_init[0], 34);
+       /* lock registers */
+       ret |= netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+                                               0x1f, &cimax_init[0x18], 1);
+       /* power on slots */
+       ret |= netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+                                               0x18, &cimax_init[0x18], 1);
+
+       if (0 != ret)
+               goto err;
+
+       ret = dvb_ca_en50221_init(&port->frontends.adapter,
+                                  &state->ca,
+                                  /* flags */ 0,
+                                  /* n_slots */ 1);
+       if (0 != ret)
+               goto err;
+
+       INIT_WORK(&state->work, netup_read_ci_status);
+
+       ci_dbg_print("%s: CI initialized!\n", __func__);
+
+       return 0;
+err:
+       ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret);
+       kfree(state);
+       return ret;
+}
+
+void netup_ci_exit(struct cx23885_tsport *port)
+{
+       struct netup_ci_state *state;
+
+       if (NULL == port)
+               return;
+
+       state = (struct netup_ci_state *)port->port_priv;
+       if (NULL == state)
+               return;
+
+       if (NULL == state->ca.data)
+               return;
+
+       dvb_ca_en50221_release(&state->ca);
+       kfree(state);
+}
diff --git a/drivers/media/video/cx23885/cimax2.h b/drivers/media/video/cx23885/cimax2.h
new file mode 100644 (file)
index 0000000..518744a
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * cimax2.h
+ *
+ * CIMax(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * 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 CIMAX2_H
+#define CIMAX2_H
+#include "dvb_ca_en50221.h"
+
+extern int netup_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
+                                               int slot, int addr);
+extern int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
+                                               int slot, int addr, u8 data);
+extern int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221,
+                                               int slot, u8 addr);
+extern int netup_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221,
+                                               int slot, u8 addr, u8 data);
+extern int netup_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot);
+extern int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot);
+extern int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot);
+extern int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status);
+extern int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221,
+                                               int slot, int open);
+extern int netup_ci_init(struct cx23885_tsport *port);
+extern void netup_ci_exit(struct cx23885_tsport *port);
+
+#endif
index bfe25841dbf483239777cd72dddcbafb8e087a39..6f5df90af93ef2a89f2c4bc48bf0c64640b89dea 100644 (file)
@@ -896,7 +896,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev)
        if (retval != 0) {
                printk(KERN_ERR
                        "ERROR: Hotplug firmware request failed (%s).\n",
-                       CX2341X_FIRM_ENC_FILENAME);
+                       CX23885_FIRM_IMAGE_NAME);
                printk(KERN_ERR "Please fix your hotplug setup, the board will "
                        "not work without firmware loaded!\n");
                return -1;
@@ -1198,21 +1198,16 @@ static int vidioc_enum_input(struct file *file, void *priv,
        struct cx23885_fh  *fh  = file->private_data;
        struct cx23885_dev *dev = fh->dev;
        struct cx23885_input *input;
-       unsigned int n;
+       int n;
 
-       n = i->index;
-
-       if (n >= 4)
+       if (i->index >= 4)
                return -EINVAL;
 
-       input = &cx23885_boards[dev->board].input[n];
+       input = &cx23885_boards[dev->board].input[i->index];
 
        if (input->type == 0)
                return -EINVAL;
 
-       memset(i, 0, sizeof(*i));
-       i->index = n;
-
        /* FIXME
         * strcpy(i->name, input->name); */
        strcpy(i->name, "unset");
@@ -1255,10 +1250,8 @@ static int vidioc_g_tuner(struct file *file, void *priv,
                return -EINVAL;
        if (0 != t->index)
                return -EINVAL;
-       memset(t, 0, sizeof(*t));
        strcpy(t->name, "Television");
-       cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_TUNER, t);
-       cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_TUNER, t);
+       call_all(dev, tuner, g_tuner, t);
 
        dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
 
@@ -1275,7 +1268,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
                return -EINVAL;
 
        /* Update the A/V core */
-       cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_TUNER, t);
+       call_all(dev, tuner, s_tuner, t);
 
        return 0;
 }
@@ -1286,14 +1279,12 @@ static int vidioc_g_frequency(struct file *file, void *priv,
        struct cx23885_fh  *fh  = file->private_data;
        struct cx23885_dev *dev = fh->dev;
 
-       memset(f, 0, sizeof(*f));
        if (UNSET == dev->tuner_type)
                return -EINVAL;
        f->type = V4L2_TUNER_ANALOG_TV;
        f->frequency = dev->freq;
 
-       /* Assumption that tuner is always on bus 1 */
-       cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_FREQUENCY, f);
+       call_all(dev, tuner, g_frequency, f);
 
        return 0;
 }
@@ -1320,8 +1311,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
                return -EINVAL;
        dev->freq = f->frequency;
 
-       /* Assumption that tuner is always on bus 1 */
-       cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_FREQUENCY, f);
+       call_all(dev, tuner, s_frequency, f);
 
        cx23885_initialize_codec(dev);
 
@@ -1335,7 +1325,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        struct cx23885_dev *dev = fh->dev;
 
        /* Update the A/V core */
-       cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_CTRL, ctl);
+       call_all(dev, core, s_ctrl, ctl);
        return 0;
 }
 
@@ -1346,7 +1336,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        struct cx23885_dev *dev = fh->dev;
        struct cx23885_tsport  *tsport = &dev->ts1;
 
-       memset(cap, 0, sizeof(*cap));
        strcpy(cap->driver, dev->name);
        strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
                sizeof(cap->card));
@@ -1366,16 +1355,10 @@ static int vidioc_querycap(struct file *file, void  *priv,
 static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
                                        struct v4l2_fmtdesc *f)
 {
-       int index;
-
-       index = f->index;
-       if (index != 0)
+       if (f->index != 0)
                return -EINVAL;
 
-       memset(f, 0, sizeof(*f));
-       f->index = index;
        strlcpy(f->description, "MPEG", sizeof(f->description));
-       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        f->pixelformat = V4L2_PIX_FMT_MPEG;
 
        return 0;
@@ -1387,8 +1370,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
        struct cx23885_fh  *fh  = file->private_data;
        struct cx23885_dev *dev = fh->dev;
 
-       memset(f, 0, sizeof(*f));
-       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.bytesperline = 0;
        f->fmt.pix.sizeimage    =
@@ -1408,12 +1389,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        struct cx23885_fh  *fh  = file->private_data;
        struct cx23885_dev *dev = fh->dev;
 
-       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.bytesperline = 0;
        f->fmt.pix.sizeimage    =
                dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
-       f->fmt.pix.sizeimage    =
        f->fmt.pix.colorspace   = 0;
        dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
                dev->ts1.width, dev->ts1.height, fh->mpegq.field);
@@ -1426,7 +1405,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        struct cx23885_fh  *fh  = file->private_data;
        struct cx23885_dev *dev = fh->dev;
 
-       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.bytesperline = 0;
        f->fmt.pix.sizeimage    =
@@ -1543,12 +1521,7 @@ static int vidioc_log_status(struct file *file, void *priv)
        printk(KERN_INFO
                "%s/2: ============  START LOG STATUS  ============\n",
               dev->name);
-       cx23885_call_i2c_clients(&dev->i2c_bus[0], VIDIOC_LOG_STATUS,
-               NULL);
-       cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_LOG_STATUS,
-               NULL);
-       cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_LOG_STATUS,
-               NULL);
+       call_all(dev, core, log_status);
        cx2341x_log_status(&dev->mpeg_params, name);
        printk(KERN_INFO
                "%s/2: =============  END LOG STATUS  =============\n",
index caa098beeecf60f91f0a8482e5e2407d4d2f4fd7..5e4b7e790d9498f6235bd612696c38d4cb975669 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "cx23885.h"
 #include "tuner-xc2028.h"
+#include "netup-init.h"
 
 /* ------------------------------------------------------------------ */
 /* board config info                                                  */
@@ -162,6 +163,24 @@ struct cx23885_board cx23885_boards[] = {
                .name           = "Compro VideoMate E650F",
                .portc          = CX23885_MPEG_DVB,
        },
+       [CX23885_BOARD_TBS_6920] = {
+               .name           = "TurboSight TBS 6920",
+               .portb          = CX23885_MPEG_DVB,
+       },
+       [CX23885_BOARD_TEVII_S470] = {
+               .name           = "TeVii S470",
+               .portb          = CX23885_MPEG_DVB,
+       },
+       [CX23885_BOARD_DVBWORLD_2005] = {
+               .name           = "DVBWorld DVB-S2 2005",
+               .portb          = CX23885_MPEG_DVB,
+       },
+       [CX23885_BOARD_NETUP_DUAL_DVBS2_CI] = {
+               .cimax          = 1,
+               .name           = "NetUP Dual DVB-S2 CI",
+               .portb          = CX23885_MPEG_DVB,
+               .portc          = CX23885_MPEG_DVB,
+       },
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -245,6 +264,22 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x185b,
                .subdevice = 0xe800,
                .card      = CX23885_BOARD_COMPRO_VIDEOMATE_E650F,
+       }, {
+               .subvendor = 0x6920,
+               .subdevice = 0x8888,
+               .card      = CX23885_BOARD_TBS_6920,
+       }, {
+               .subvendor = 0xd470,
+               .subdevice = 0x9022,
+               .card      = CX23885_BOARD_TEVII_S470,
+       }, {
+               .subvendor = 0x0001,
+               .subdevice = 0x2005,
+               .card      = CX23885_BOARD_DVBWORLD_2005,
+       }, {
+               .subvendor = 0x1b55,
+               .subdevice = 0x2a2c,
+               .card      = CX23885_BOARD_NETUP_DUAL_DVBS2_CI,
        },
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -552,6 +587,38 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                mdelay(20);
                cx_set(GP0_IO, 0x00040004);
                break;
+       case CX23885_BOARD_TBS_6920:
+       case CX23885_BOARD_TEVII_S470:
+               cx_write(MC417_CTL, 0x00000036);
+               cx_write(MC417_OEN, 0x00001000);
+               cx_write(MC417_RWD, 0x00001800);
+               break;
+       case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+               /* GPIO-0 INTA from CiMax1
+                  GPIO-1 INTB from CiMax2
+                  GPIO-2 reset chips
+                  GPIO-3 to GPIO-10 data/addr for CA
+                  GPIO-11 ~CS0 to CiMax1
+                  GPIO-12 ~CS1 to CiMax2
+                  GPIO-13 ADL0 load LSB addr
+                  GPIO-14 ADL1 load MSB addr
+                  GPIO-15 ~RDY from CiMax
+                  GPIO-17 ~RD to CiMax
+                  GPIO-18 ~WR to CiMax
+                */
+               cx_set(GP0_IO, 0x00040000); /* GPIO as out */
+               /* GPIO1 and GPIO2 as INTA and INTB from CiMaxes, reset low */
+               cx_clear(GP0_IO, 0x00030004);
+               mdelay(100);/* reset delay */
+               cx_set(GP0_IO, 0x00040004); /* GPIO as out, reset high */
+               cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */
+               /* GPIO-15 IN as ~ACK, rest as OUT */
+               cx_write(MC417_OEN, 0x00001000);
+               /* ~RD, ~WR high; ADL0, ADL1 low; ~CS0, ~CS1 high */
+               cx_write(MC417_RWD, 0x0000c300);
+               /* enable irq */
+               cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
+               break;
        }
 }
 
@@ -632,6 +699,21 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
                ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
                break;
+       case CX23885_BOARD_TEVII_S470:
+       case CX23885_BOARD_TBS_6920:
+       case CX23885_BOARD_DVBWORLD_2005:
+               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;
+               break;
+       case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+               ts1->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+               ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+               ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+               ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+               ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+               ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+               break;
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
        case CX23885_BOARD_HAUPPAUGE_HVR1500:
        case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -656,7 +738,17 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1700:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
-               request_module("cx25840");
+       case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+               dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->i2c_bus[2].i2c_adap,
+                               "cx25840", "cx25840", 0x88 >> 1);
+               v4l2_subdev_call(dev->sd_cx25840, core, init, 0);
+               break;
+       }
+
+       /* AUX-PLL 27MHz CLK */
+       switch (dev->board) {
+       case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+               netup_initialize(dev);
                break;
        }
 }
index 8f6fb2add7dea0c895c030597c0a5b9757c2155f..dc7fff22cfdd5a0218547faf50036e0d1383915f 100644 (file)
@@ -31,6 +31,7 @@
 #include <asm/div64.h>
 
 #include "cx23885.h"
+#include "cimax2.h"
 
 MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
 MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
@@ -791,6 +792,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
        dev->pci_bus  = dev->pci->bus->number;
        dev->pci_slot = PCI_SLOT(dev->pci->devfn);
        dev->pci_irqmask = 0x001f00;
+       if (cx23885_boards[dev->board].cimax > 0)
+               dev->pci_irqmask |= 0x01800000; /* for CiMaxes */
 
        /* External Master 1 Bus */
        dev->i2c_bus[0].nr = 0;
@@ -872,7 +875,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
        cx23885_i2c_register(&dev->i2c_bus[1]);
        cx23885_i2c_register(&dev->i2c_bus[2]);
        cx23885_card_setup(dev);
-       cx23885_call_i2c_clients(&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL);
+       call_all(dev, core, s_standby, 0);
        cx23885_ir_init(dev);
 
        if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
@@ -1643,7 +1646,9 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
            (pci_status & PCI_MSK_VID_B) ||
            (pci_status & PCI_MSK_VID_A) ||
            (pci_status & PCI_MSK_AUD_INT) ||
-           (pci_status & PCI_MSK_AUD_EXT)) {
+           (pci_status & PCI_MSK_AUD_EXT) ||
+           (pci_status & PCI_MSK_GPIO0) ||
+           (pci_status & PCI_MSK_GPIO1)) {
 
                if (pci_status & PCI_MSK_RISC_RD)
                        dprintk(7, " (PCI_MSK_RISC_RD   0x%08x)\n",
@@ -1685,8 +1690,20 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
                        dprintk(7, " (PCI_MSK_AUD_EXT   0x%08x)\n",
                                PCI_MSK_AUD_EXT);
 
+               if (pci_status & PCI_MSK_GPIO0)
+                       dprintk(7, " (PCI_MSK_GPIO0     0x%08x)\n",
+                               PCI_MSK_GPIO0);
+
+               if (pci_status & PCI_MSK_GPIO1)
+                       dprintk(7, " (PCI_MSK_GPIO1     0x%08x)\n",
+                               PCI_MSK_GPIO1);
        }
 
+       if (cx23885_boards[dev->board].cimax > 0 &&
+               ((pci_status & PCI_MSK_GPIO0) || (pci_status & PCI_MSK_GPIO1)))
+               /* handled += cx23885_irq_gpio(dev, pci_status); */
+               handled += netup_ci_slot_status(dev, pci_status);
+
        if (ts1_status) {
                if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
                        handled += cx23885_irq_ts(ts1, ts1_status);
@@ -1722,16 +1739,20 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
        if (NULL == dev)
                return -ENOMEM;
 
+       err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
+       if (err < 0)
+               goto fail_free;
+
        /* pci init */
        dev->pci = pci_dev;
        if (pci_enable_device(pci_dev)) {
                err = -EIO;
-               goto fail_free;
+               goto fail_unreg;
        }
 
        if (cx23885_dev_setup(dev) < 0) {
                err = -EINVAL;
-               goto fail_free;
+               goto fail_unreg;
        }
 
        /* print pci info */
@@ -1758,11 +1779,18 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
                goto fail_irq;
        }
 
-       pci_set_drvdata(pci_dev, dev);
+       switch (dev->board) {
+       case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+               cx_set(PCI_INT_MSK, 0x01800000); /* for NetUP */
+               break;
+       }
+
        return 0;
 
 fail_irq:
        cx23885_dev_unregister(dev);
+fail_unreg:
+       v4l2_device_unregister(&dev->v4l2_dev);
 fail_free:
        kfree(dev);
        return err;
@@ -1770,7 +1798,8 @@ fail_free:
 
 static void __devexit cx23885_finidev(struct pci_dev *pci_dev)
 {
-       struct cx23885_dev *dev = pci_get_drvdata(pci_dev);
+       struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+       struct cx23885_dev *dev = to_cx23885(v4l2_dev);
 
        cx23885_shutdown(dev);
 
@@ -1778,13 +1807,13 @@ static void __devexit cx23885_finidev(struct pci_dev *pci_dev)
 
        /* unregister stuff */
        free_irq(pci_dev->irq, dev);
-       pci_set_drvdata(pci_dev, NULL);
 
        mutex_lock(&devlist);
        list_del(&dev->devlist);
        mutex_unlock(&devlist);
 
        cx23885_dev_unregister(dev);
+       v4l2_device_unregister(v4l2_dev);
        kfree(dev);
 }
 
index 1c454128a9df9c5fca5b2b6fd7253ed6111d5426..d43c7439676781fb35508d78ac05a3c76156dbf6 100644 (file)
@@ -30,6 +30,7 @@
 #include "cx23885.h"
 #include <media/v4l2-common.h>
 
+#include "dvb_ca_en50221.h"
 #include "s5h1409.h"
 #include "s5h1411.h"
 #include "mt2131.h"
 #include "dib7000p.h"
 #include "dibx000_common.h"
 #include "zl10353.h"
+#include "stv0900.h"
+#include "stv6110.h"
+#include "lnbh24.h"
+#include "cx24116.h"
+#include "cimax2.h"
+#include "netup-eeprom.h"
+#include "netup-init.h"
 
 static unsigned int debug;
 
@@ -308,11 +316,63 @@ static struct zl10353_config dvico_fusionhdtv_xc3028 = {
        .no_tuner      = 1,
 };
 
+static struct stv0900_config netup_stv0900_config = {
+       .demod_address = 0x68,
+       .xtal = 27000000,
+       .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
+       .diseqc_mode = 2,/* 2/3 PWM */
+       .path1_mode = 2,/*Serial continues clock */
+       .path2_mode = 2,/*Serial continues clock */
+       .tun1_maddress = 0,/* 0x60 */
+       .tun2_maddress = 3,/* 0x63 */
+       .tun1_adc = 1,/* 1 Vpp */
+       .tun2_adc = 1,/* 1 Vpp */
+};
+
+static struct stv6110_config netup_stv6110_tunerconfig_a = {
+       .i2c_address = 0x60,
+       .mclk = 27000000,
+       .iq_wiring = 0,
+};
+
+static struct stv6110_config netup_stv6110_tunerconfig_b = {
+       .i2c_address = 0x63,
+       .mclk = 27000000,
+       .iq_wiring = 1,
+};
+
+static int tbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+       struct cx23885_tsport *port = fe->dvb->priv;
+       struct cx23885_dev *dev = port->dev;
+
+       if (voltage == SEC_VOLTAGE_18)
+               cx_write(MC417_RWD, 0x00001e00);/* GPIO-13 high */
+       else if (voltage == SEC_VOLTAGE_13)
+               cx_write(MC417_RWD, 0x00001a00);/* GPIO-13 low */
+       else
+               cx_write(MC417_RWD, 0x00001800);/* GPIO-12 low */
+       return 0;
+}
+
+static struct cx24116_config tbs_cx24116_config = {
+       .demod_address = 0x05,
+};
+
+static struct cx24116_config tevii_cx24116_config = {
+       .demod_address = 0x55,
+};
+
+static struct cx24116_config dvbworld_cx24116_config = {
+       .demod_address = 0x05,
+};
+
 static int dvb_register(struct cx23885_tsport *port)
 {
        struct cx23885_dev *dev = port->dev;
        struct cx23885_i2c *i2c_bus = NULL;
        struct videobuf_dvb_frontend *fe0;
+       int ret;
 
        /* Get the first frontend */
        fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
@@ -526,6 +586,78 @@ static int dvb_register(struct cx23885_tsport *port)
                                fe->ops.tuner_ops.set_config(fe, &ctl);
                }
                break;
+       case CX23885_BOARD_TBS_6920:
+               i2c_bus = &dev->i2c_bus[0];
+
+               fe0->dvb.frontend = dvb_attach(cx24116_attach,
+                       &tbs_cx24116_config,
+                       &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL)
+                       fe0->dvb.frontend->ops.set_voltage = tbs_set_voltage;
+
+               break;
+       case CX23885_BOARD_TEVII_S470:
+               i2c_bus = &dev->i2c_bus[1];
+
+               fe0->dvb.frontend = dvb_attach(cx24116_attach,
+                       &tevii_cx24116_config,
+                       &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL)
+                       fe0->dvb.frontend->ops.set_voltage = tbs_set_voltage;
+
+               break;
+       case CX23885_BOARD_DVBWORLD_2005:
+               i2c_bus = &dev->i2c_bus[1];
+
+               fe0->dvb.frontend = dvb_attach(cx24116_attach,
+                       &dvbworld_cx24116_config,
+                       &i2c_bus->i2c_adap);
+               break;
+       case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+               i2c_bus = &dev->i2c_bus[0];
+               switch (port->nr) {
+               /* port B */
+               case 1:
+                       fe0->dvb.frontend = dvb_attach(stv0900_attach,
+                                                       &netup_stv0900_config,
+                                                       &i2c_bus->i2c_adap, 0);
+                       if (fe0->dvb.frontend != NULL) {
+                               if (dvb_attach(stv6110_attach,
+                                               fe0->dvb.frontend,
+                                               &netup_stv6110_tunerconfig_a,
+                                               &i2c_bus->i2c_adap)) {
+                                       if (!dvb_attach(lnbh24_attach,
+                                                       fe0->dvb.frontend,
+                                                       &i2c_bus->i2c_adap,
+                                                       LNBH24_PCL, 0, 0x09))
+                                               printk(KERN_ERR
+                                                       "No LNBH24 found!\n");
+
+                               }
+                       }
+                       break;
+               /* port C */
+               case 2:
+                       fe0->dvb.frontend = dvb_attach(stv0900_attach,
+                                                       &netup_stv0900_config,
+                                                       &i2c_bus->i2c_adap, 1);
+                       if (fe0->dvb.frontend != NULL) {
+                               if (dvb_attach(stv6110_attach,
+                                               fe0->dvb.frontend,
+                                               &netup_stv6110_tunerconfig_b,
+                                               &i2c_bus->i2c_adap)) {
+                                       if (!dvb_attach(lnbh24_attach,
+                                                       fe0->dvb.frontend,
+                                                       &i2c_bus->i2c_adap,
+                                                       LNBH24_PCL, 0, 0x0a))
+                                               printk(KERN_ERR
+                                                       "No LNBH24 found!\n");
+
+                               }
+                       }
+                       break;
+               }
+               break;
        default:
                printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
                        " isn't supported yet\n",
@@ -541,15 +673,39 @@ static int dvb_register(struct cx23885_tsport *port)
        fe0->dvb.frontend->callback = cx23885_tuner_callback;
 
        /* Put the analog decoder in standby to keep it quiet */
-       cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL);
+       call_all(dev, core, s_standby, 0);
 
        if (fe0->dvb.frontend->ops.analog_ops.standby)
                fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
 
        /* register everything */
-       return videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
+       ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
                &dev->pci->dev, adapter_nr, 0);
 
+       /* init CI & MAC */
+       switch (dev->board) {
+       case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: {
+               static struct netup_card_info cinfo;
+
+               netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
+               memcpy(port->frontends.adapter.proposed_mac,
+                               cinfo.port[port->nr - 1].mac, 6);
+               printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC="
+                       "%02X:%02X:%02X:%02X:%02X:%02X\n",
+                       port->nr,
+                       port->frontends.adapter.proposed_mac[0],
+                       port->frontends.adapter.proposed_mac[1],
+                       port->frontends.adapter.proposed_mac[2],
+                       port->frontends.adapter.proposed_mac[3],
+                       port->frontends.adapter.proposed_mac[4],
+                       port->frontends.adapter.proposed_mac[5]);
+
+               netup_ci_init(port);
+               break;
+               }
+       }
+
+       return ret;
 }
 
 int cx23885_dvb_register(struct cx23885_tsport *port)
@@ -622,6 +778,12 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port)
        if (fe0->dvb.frontend)
                videobuf_dvb_unregister_bus(&port->frontends);
 
+       switch (port->dev->board) {
+       case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+               netup_ci_exit(port);
+               break;
+       }
+
        return 0;
 }
 
index bb7f71a1fcbe7b30a997d50592fb98e138410915..3421bd12056a95ee58a4604ca380354f4ccb444c 100644 (file)
@@ -268,64 +268,6 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap,
        return retval;
 }
 
-static int attach_inform(struct i2c_client *client)
-{
-       struct cx23885_i2c *bus = i2c_get_adapdata(client->adapter);
-       struct cx23885_dev *dev = bus->dev;
-       struct tuner_setup tun_setup;
-
-       dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
-               client->driver->driver.name, client->addr, client->name);
-
-       if (!client->driver->command)
-               return 0;
-
-       if (dev->tuner_type != UNSET) {
-
-               dprintk(1, "%s  (tuner) i2c attach [addr=0x%x,client=%s]\n",
-                       client->driver->driver.name, client->addr,
-                       client->name);
-
-               if ((dev->tuner_addr == ADDR_UNSET) ||
-                       (dev->tuner_addr == client->addr)) {
-
-                       dprintk(1, "%s (tuner || addr UNSET)\n",
-                               client->driver->driver.name);
-
-                       dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
-                               client->driver->driver.name,
-                               client->addr, client->name);
-
-                       tun_setup.mode_mask = T_ANALOG_TV;
-                       tun_setup.type = dev->tuner_type;
-                       tun_setup.addr = dev->tuner_addr;
-
-                       client->driver->command(client, TUNER_SET_TYPE_ADDR,
-                               &tun_setup);
-               }
-       }
-
-       return 0;
-}
-
-static int detach_inform(struct i2c_client *client)
-{
-       struct cx23885_dev *dev = i2c_get_adapdata(client->adapter);
-
-       dprintk(1, "i2c detach [client=%s]\n", client->name);
-
-       return 0;
-}
-
-void cx23885_call_i2c_clients(struct cx23885_i2c *bus,
-                             unsigned int cmd, void *arg)
-{
-       if (bus->i2c_rc != 0)
-               return;
-
-       i2c_clients_command(&bus->i2c_adap, cmd, arg);
-}
-
 static u32 cx23885_functionality(struct i2c_adapter *adap)
 {
        return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
@@ -343,9 +285,6 @@ static struct i2c_adapter cx23885_i2c_adap_template = {
        .owner             = THIS_MODULE,
        .id                = I2C_HW_B_CX23885,
        .algo              = &cx23885_i2c_algo_template,
-       .class             = I2C_CLASS_TV_ANALOG,
-       .client_register   = attach_inform,
-       .client_unregister = detach_inform,
 };
 
 static struct i2c_client cx23885_i2c_client_template = {
@@ -402,15 +341,18 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
 
        bus->i2c_algo.data = bus;
        bus->i2c_adap.algo_data = bus;
-       i2c_set_adapdata(&bus->i2c_adap, bus);
+       i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev);
        i2c_add_adapter(&bus->i2c_adap);
 
        bus->i2c_client.adapter = &bus->i2c_adap;
 
        if (0 == bus->i2c_rc) {
                dprintk(1, "%s: i2c bus %d registered\n", dev->name, bus->nr);
-               if (i2c_scan)
+               if (i2c_scan) {
+                       printk(KERN_INFO "%s: scan bus %d:\n",
+                                       dev->name, bus->nr);
                        do_i2c_scan(dev->name, &bus->i2c_client);
+               }
        } else
                printk(KERN_WARNING "%s: i2c bus %d register FAILED\n",
                        dev->name, bus->nr);
index 20b68a23626064ccea4a5f94db8c68beff4fd6c0..eafbe5226bae4e2bce1694228bbacaa1a5419796 100644 (file)
@@ -212,6 +212,8 @@ Channel manager Data Structure entry = 20 DWORD
 
 #define DEV_CNTRL2     0x00040000
 
+#define PCI_MSK_GPIO1   (1 << 24)
+#define PCI_MSK_GPIO0   (1 << 23)
 #define PCI_MSK_APB_DMA   (1 << 12)
 #define PCI_MSK_AL_WR     (1 << 11)
 #define PCI_MSK_AL_RD     (1 << 10)
index eaa11893bfe918f23e1ca7403179c7d2ec975680..f0ac62c5dc83f398ee9b310fc8bff3069226ce1f 100644 (file)
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-/* Include V4L1 specific functions. Should be removed soon */
-#include <linux/videodev.h>
-#endif
-
 MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
 MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
 MODULE_LICENSE("GPL");
@@ -244,6 +239,7 @@ static struct cx23885_ctrl cx23885_ctls[] = {
 };
 static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls);
 
+/* Must be sorted from low to high control ID! */
 static const u32 cx23885_user_ctrls[] = {
        V4L2_CID_USER_CLASS,
        V4L2_CID_BRIGHTNESS,
@@ -303,11 +299,7 @@ static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
 
        dev->tvnorm = norm;
 
-       /* Tell the analog tuner/demods */
-       cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_STD, &norm);
-
-       /* Tell the internal A/V decoder */
-       cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_STD, &norm);
+       call_all(dev, tuner, s_std, norm);
 
        return 0;
 }
@@ -324,8 +316,8 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
        if (NULL == vfd)
                return NULL;
        *vfd = *template;
-       vfd->minor   = -1;
-       vfd->parent  = &pci->dev;
+       vfd->minor = -1;
+       vfd->v4l2_dev = &dev->v4l2_dev;
        vfd->release = video_device_release;
        snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
                 dev->name, type, cx23885_boards[dev->board].name);
@@ -414,8 +406,7 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
        route.input = INPUT(input)->vmux;
 
        /* Tell the internal A/V decoder */
-       cx23885_call_i2c_clients(&dev->i2c_bus[2],
-               VIDIOC_INT_S_VIDEO_ROUTING, &route);
+       v4l2_subdev_call(dev->sd_cx25840, video, s_routing, &route);
 
        return 0;
 }
@@ -891,7 +882,7 @@ static int cx23885_get_control(struct cx23885_dev *dev,
        struct v4l2_control *ctl)
 {
        dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__);
-       cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl);
+       call_all(dev, core, g_ctrl, ctl);
        return 0;
 }
 
@@ -1005,7 +996,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        fh->vidq.field = f->fmt.pix.field;
        dprintk(2, "%s() width=%d height=%d field=%d\n", __func__,
                fh->width, fh->height, fh->vidq.field);
-       cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_FMT, f);
+       call_all(dev, video, s_fmt, f);
        return 0;
 }
 
@@ -1285,7 +1276,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
        f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
        f->frequency = dev->freq;
 
-       cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_FREQUENCY, f);
+       call_all(dev, tuner, g_frequency, f);
 
        return 0;
 }
@@ -1300,7 +1291,7 @@ static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
        mutex_lock(&dev->lock);
        dev->freq = f->frequency;
 
-       cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_FREQUENCY, f);
+       call_all(dev, tuner, s_frequency, f);
 
        /* When changing channels it is required to reset TVAUDIO */
        msleep(10);
@@ -1334,7 +1325,7 @@ static int vidioc_g_register(struct file *file, void *fh,
        if (!v4l2_chip_match_host(&reg->match))
                return -EINVAL;
 
-       cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_G_REGISTER, reg);
+       call_all(dev, core, g_register, reg);
 
        return 0;
 }
@@ -1347,7 +1338,7 @@ static int vidioc_s_register(struct file *file, void *fh,
        if (!v4l2_chip_match_host(&reg->match))
                return -EINVAL;
 
-       cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_S_REGISTER, reg);
+       call_all(dev, core, s_register, reg);
 
        return 0;
 }
@@ -1528,6 +1519,26 @@ int cx23885_video_register(struct cx23885_dev *dev)
        /* Don't enable VBI yet */
        cx_set(PCI_INT_MSK, 1);
 
+       if (TUNER_ABSENT != dev->tuner_type) {
+               struct v4l2_subdev *sd = NULL;
+
+               if (dev->tuner_addr)
+                       sd = v4l2_i2c_new_subdev(&dev->i2c_bus[1].i2c_adap,
+                               "tuner", "tuner", dev->tuner_addr);
+               else
+                       sd = v4l2_i2c_new_probed_subdev(&dev->i2c_bus[1].i2c_adap,
+                               "tuner", "tuner", v4l2_i2c_tuner_addrs(ADDRS_TV));
+               if (sd) {
+                       struct tuner_setup tun_setup;
+
+                       tun_setup.mode_mask = T_ANALOG_TV;
+                       tun_setup.type = dev->tuner_type;
+                       tun_setup.addr = v4l2_i2c_subdev_addr(sd);
+
+                       v4l2_subdev_call(sd, tuner, s_type_addr, &tun_setup);
+               }
+       }
+
 
        /* register v4l devices */
        dev->video_dev = cx23885_vdev_init(dev, dev->pci,
index 67828029fc69ed9489ce91ba5f30bdb33a4eb9d9..02d980a29962381474a7aea6c34ba2b95792e304 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/i2c-algo-bit.h>
 #include <linux/kdev_t.h>
 
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/tuner.h>
 #include <media/tveeprom.h>
 #include <media/videobuf-dma-sg.h>
 #define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP 11
 #define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H 12
 #define CX23885_BOARD_COMPRO_VIDEOMATE_E650F   13
+#define CX23885_BOARD_TBS_6920                 14
+#define CX23885_BOARD_TEVII_S470               15
+#define CX23885_BOARD_DVBWORLD_2005            16
+#define CX23885_BOARD_NETUP_DUAL_DVBS2_CI      17
 
 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
 #define CX23885_NORMS (\
@@ -184,6 +188,7 @@ struct cx23885_board {
         */
        u32                     clk_freq;
        struct cx23885_input    input[MAX_CX23885_INPUT];
+       int                     cimax; /* for NetUP */
 };
 
 struct cx23885_subid {
@@ -266,11 +271,13 @@ struct cx23885_tsport {
 
        /* Allow a single tsport to have multiple frontends */
        u32                        num_frontends;
+       void                       *port_priv;
 };
 
 struct cx23885_dev {
        struct list_head           devlist;
        atomic_t                   refcount;
+       struct v4l2_device         v4l2_dev;
 
        /* pci stuff */
        struct pci_dev             *pci;
@@ -316,6 +323,7 @@ struct cx23885_dev {
        unsigned int               radio_type;
        unsigned char              radio_addr;
        unsigned int               has_radio;
+       struct v4l2_subdev         *sd_cx25840;
 
        /* V4l */
        u32                        freq;
@@ -336,6 +344,14 @@ struct cx23885_dev {
 
 };
 
+static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev)
+{
+       return container_of(v4l2_dev, struct cx23885_dev, v4l2_dev);
+}
+
+#define call_all(dev, o, f, args...) \
+       v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args)
+
 extern struct list_head cx23885_devlist;
 
 #define SRAM_CH01  0 /* Video A */
@@ -452,8 +468,6 @@ extern struct videobuf_queue_ops cx23885_vbi_qops;
 /* cx23885-i2c.c                                                */
 extern int cx23885_i2c_register(struct cx23885_i2c *bus);
 extern int cx23885_i2c_unregister(struct cx23885_i2c *bus);
-extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd,
-                                    void *arg);
 extern void cx23885_av_clk(struct cx23885_dev *dev, int enable);
 
 /* ----------------------------------------------------------- */
diff --git a/drivers/media/video/cx23885/netup-eeprom.c b/drivers/media/video/cx23885/netup-eeprom.c
new file mode 100644 (file)
index 0000000..042bbbb
--- /dev/null
@@ -0,0 +1,107 @@
+
+/*
+ * netup-eeprom.c
+ *
+ * 24LC02 EEPROM driver in conjunction with NetUP Dual DVB-S2 CI card
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * 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 "cx23885.h"
+#include "netup-eeprom.h"
+
+#define EEPROM_I2C_ADDR 0x50
+
+int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr)
+{
+       int ret;
+       unsigned char buf[2];
+
+       /* Read from EEPROM */
+       struct i2c_msg msg[] = {
+               {
+                       .addr   = EEPROM_I2C_ADDR,
+                       .flags  = 0,
+                       .buf    = &buf[0],
+                       .len    = 1
+               }, {
+                       .addr   = EEPROM_I2C_ADDR,
+                       .flags  = I2C_M_RD,
+                       .buf    = &buf[1],
+                       .len    = 1
+               }
+
+       };
+
+       buf[0] = addr;
+       buf[1] = 0x0;
+
+       ret = i2c_transfer(i2c_adap, msg, 2);
+
+       if (ret != 2) {
+               printk(KERN_ERR "eeprom i2c read error, status=%d\n", ret);
+               return -1;
+       }
+
+       return buf[1];
+};
+
+int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data)
+{
+       int ret;
+       unsigned char bufw[2];
+
+       /* Write into EEPROM */
+       struct i2c_msg msg[] = {
+               {
+                       .addr   = EEPROM_I2C_ADDR,
+                       .flags  = 0,
+                       .buf    = &bufw[0],
+                       .len    = 2
+               }
+       };
+
+       bufw[0] = addr;
+       bufw[1] = data;
+
+       ret = i2c_transfer(i2c_adap, msg, 1);
+
+       if (ret != 1) {
+               printk(KERN_ERR "eeprom i2c write error, status=%d\n", ret);
+               return -1;
+       }
+
+       mdelay(10); /* prophylactic delay, datasheet write cycle time = 5 ms */
+       return 0;
+};
+
+void netup_get_card_info(struct i2c_adapter *i2c_adap,
+                               struct netup_card_info *cinfo)
+{
+       int i, j;
+
+       cinfo->rev =  netup_eeprom_read(i2c_adap, 13);
+
+       for (i = 0, j = 0; i < 6; i++, j++)
+               cinfo->port[0].mac[j] =  netup_eeprom_read(i2c_adap, i);
+
+       for (i = 6, j = 0; i < 12; i++, j++)
+               cinfo->port[1].mac[j] =  netup_eeprom_read(i2c_adap, i);
+};
diff --git a/drivers/media/video/cx23885/netup-eeprom.h b/drivers/media/video/cx23885/netup-eeprom.h
new file mode 100644 (file)
index 0000000..13926e1
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * netup-eeprom.h
+ *
+ * 24LC02 EEPROM driver in conjunction with NetUP Dual DVB-S2 CI card
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * 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 NETUP_EEPROM_H
+#define NETUP_EEPROM_H
+
+struct netup_port_info {
+       u8 mac[6];/* card MAC address */
+};
+
+struct netup_card_info {
+       struct netup_port_info port[2];/* ports - 1,2 */
+       u8 rev;/* card revision */
+};
+
+extern int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr);
+extern int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data);
+extern void netup_get_card_info(struct i2c_adapter *i2c_adap,
+                               struct netup_card_info *cinfo);
+
+#endif
diff --git a/drivers/media/video/cx23885/netup-init.c b/drivers/media/video/cx23885/netup-init.c
new file mode 100644 (file)
index 0000000..f4893e6
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * netup-init.c
+ *
+ * NetUP Dual DVB-S2 CI driver
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * 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 "cx23885.h"
+
+static void i2c_av_write(struct i2c_adapter *i2c, u16 reg, u8 val)
+{
+       int ret;
+       u8 buf[3];
+       struct i2c_msg msg = {
+               .addr   = 0x88 >> 1,
+               .flags  = 0,
+               .buf    = buf,
+               .len    = 3
+       };
+
+       buf[0] = reg >> 8;
+       buf[1] = reg & 0xff;
+       buf[2] = val;
+
+       ret = i2c_transfer(i2c, &msg, 1);
+
+       if (ret != 1)
+               printk(KERN_ERR "%s: i2c write error!\n", __func__);
+}
+
+static void i2c_av_write4(struct i2c_adapter *i2c, u16 reg, u32 val)
+{
+       int ret;
+       u8 buf[6];
+       struct i2c_msg msg = {
+               .addr   = 0x88 >> 1,
+               .flags  = 0,
+               .buf    = buf,
+               .len    = 6
+       };
+
+       buf[0] = reg >> 8;
+       buf[1] = reg & 0xff;
+       buf[2] = val & 0xff;
+       buf[3] = (val >> 8) & 0xff;
+       buf[4] = (val >> 16) & 0xff;
+       buf[5] = val >> 24;
+
+       ret = i2c_transfer(i2c, &msg, 1);
+
+       if (ret != 1)
+               printk(KERN_ERR "%s: i2c write error!\n", __func__);
+}
+
+static u8 i2c_av_read(struct i2c_adapter *i2c, u16 reg)
+{
+       int ret;
+       u8 buf[2];
+       struct i2c_msg msg = {
+               .addr   = 0x88 >> 1,
+               .flags  = 0,
+               .buf    = buf,
+               .len    = 2
+       };
+
+       buf[0] = reg >> 8;
+       buf[1] = reg & 0xff;
+
+       ret = i2c_transfer(i2c, &msg, 1);
+
+       if (ret != 1)
+               printk(KERN_ERR "%s: i2c write error!\n", __func__);
+
+       msg.flags = I2C_M_RD;
+       msg.len = 1;
+
+       ret = i2c_transfer(i2c, &msg, 1);
+
+       if (ret != 1)
+               printk(KERN_ERR "%s: i2c read error!\n", __func__);
+
+       return buf[0];
+}
+
+static void i2c_av_and_or(struct i2c_adapter *i2c, u16 reg, unsigned and_mask,
+                                                               u8 or_value)
+{
+       i2c_av_write(i2c, reg, (i2c_av_read(i2c, reg) & and_mask) | or_value);
+}
+/* set 27MHz on AUX_CLK */
+void netup_initialize(struct cx23885_dev *dev)
+{
+       struct cx23885_i2c *i2c_bus = &dev->i2c_bus[2];
+       struct i2c_adapter *i2c = &i2c_bus->i2c_adap;
+
+       /* Stop microcontroller */
+       i2c_av_and_or(i2c, 0x803, ~0x10, 0x00);
+
+       /* Aux PLL frac for 27 MHz */
+       i2c_av_write4(i2c, 0x114, 0xea0eb3);
+
+       /* Aux PLL int for 27 MHz */
+       i2c_av_write4(i2c, 0x110, 0x090319);
+
+       /* start microcontroller */
+       i2c_av_and_or(i2c, 0x803, ~0x10, 0x10);
+}
diff --git a/drivers/media/video/cx23885/netup-init.h b/drivers/media/video/cx23885/netup-init.h
new file mode 100644 (file)
index 0000000..d26ae4b
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * netup-init.h
+ *
+ * NetUP Dual DVB-S2 CI driver
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * 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.
+ */
+extern void netup_initialize(struct cx23885_dev *dev);
index d199d80ea0a3642139918b96b64deeade3c54e7a..93d74bee292afc82a3b8b33ede264dd18b745dc1 100644 (file)
@@ -363,75 +363,74 @@ static void set_mute(struct i2c_client *client, int mute)
        }
 }
 
-int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
+int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
 {
-       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
-       struct v4l2_control *ctrl = arg;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct cx25840_state *state = to_state(sd);
        int retval;
 
-       switch (cmd) {
-       case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-               if (!state->is_cx25836)
-                       cx25840_and_or(client, 0x810, ~0x1, 1);
-               if (state->aud_input != CX25840_AUDIO_SERIAL) {
-                       cx25840_and_or(client, 0x803, ~0x10, 0);
-                       cx25840_write(client, 0x8d3, 0x1f);
-               }
-               retval = set_audclk_freq(client, *(u32 *)arg);
-               if (state->aud_input != CX25840_AUDIO_SERIAL) {
-                       cx25840_and_or(client, 0x803, ~0x10, 0x10);
-               }
-               if (!state->is_cx25836)
-                       cx25840_and_or(client, 0x810, ~0x1, 0);
-               return retval;
-
-       case VIDIOC_G_CTRL:
-               switch (ctrl->id) {
-               case V4L2_CID_AUDIO_VOLUME:
-                       ctrl->value = get_volume(client);
-                       break;
-               case V4L2_CID_AUDIO_BASS:
-                       ctrl->value = get_bass(client);
-                       break;
-               case V4L2_CID_AUDIO_TREBLE:
-                       ctrl->value = get_treble(client);
-                       break;
-               case V4L2_CID_AUDIO_BALANCE:
-                       ctrl->value = get_balance(client);
-                       break;
-               case V4L2_CID_AUDIO_MUTE:
-                       ctrl->value = get_mute(client);
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
+       if (!state->is_cx25836)
+               cx25840_and_or(client, 0x810, ~0x1, 1);
+       if (state->aud_input != CX25840_AUDIO_SERIAL) {
+               cx25840_and_or(client, 0x803, ~0x10, 0);
+               cx25840_write(client, 0x8d3, 0x1f);
+       }
+       retval = set_audclk_freq(client, freq);
+       if (state->aud_input != CX25840_AUDIO_SERIAL)
+               cx25840_and_or(client, 0x803, ~0x10, 0x10);
+       if (!state->is_cx25836)
+               cx25840_and_or(client, 0x810, ~0x1, 0);
+       return retval;
+}
 
-       case VIDIOC_S_CTRL:
-               switch (ctrl->id) {
-               case V4L2_CID_AUDIO_VOLUME:
-                       set_volume(client, ctrl->value);
-                       break;
-               case V4L2_CID_AUDIO_BASS:
-                       set_bass(client, ctrl->value);
-                       break;
-               case V4L2_CID_AUDIO_TREBLE:
-                       set_treble(client, ctrl->value);
-                       break;
-               case V4L2_CID_AUDIO_BALANCE:
-                       set_balance(client, ctrl->value);
-                       break;
-               case V4L2_CID_AUDIO_MUTE:
-                       set_mute(client, ctrl->value);
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
+int cx25840_audio_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+               ctrl->value = get_volume(client);
+               break;
+       case V4L2_CID_AUDIO_BASS:
+               ctrl->value = get_bass(client);
+               break;
+       case V4L2_CID_AUDIO_TREBLE:
+               ctrl->value = get_treble(client);
+               break;
+       case V4L2_CID_AUDIO_BALANCE:
+               ctrl->value = get_balance(client);
+               break;
+       case V4L2_CID_AUDIO_MUTE:
+               ctrl->value = get_mute(client);
+               break;
        default:
                return -EINVAL;
        }
+       return 0;
+}
 
+int cx25840_audio_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+               set_volume(client, ctrl->value);
+               break;
+       case V4L2_CID_AUDIO_BASS:
+               set_bass(client, ctrl->value);
+               break;
+       case V4L2_CID_AUDIO_TREBLE:
+               set_treble(client, ctrl->value);
+               break;
+       case V4L2_CID_AUDIO_BALANCE:
+               set_balance(client, ctrl->value);
+               break;
+       case V4L2_CID_AUDIO_MUTE:
+               set_mute(client, ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
        return 0;
 }
index 25eb3bec9e5d9dde1ef7051482dbc7d7e2e7c94a..737ee4ea883082294330abfff84ade1512efefaa 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/delay.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/v4l2-i2c-drv.h>
 #include <media/cx25840.h>
 
 #include "cx25840-core.h"
@@ -48,15 +48,12 @@ MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver");
 MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford");
 MODULE_LICENSE("GPL");
 
-static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
-
 static int cx25840_debug;
 
 module_param_named(debug,cx25840_debug, int, 0644);
 
 MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]");
 
-I2C_CLIENT_INSMOD;
 
 /* ----------------------------------------------------------------------- */
 
@@ -763,7 +760,7 @@ static int cx25840_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
                break;
 
        case V4L2_CID_HUE:
-               if (ctrl->value < -127 || ctrl->value > 127) {
+               if (ctrl->value < -128 || ctrl->value > 127) {
                        v4l_err(client, "invalid hue setting %d\n", ctrl->value);
                        return -ERANGE;
                }
@@ -778,7 +775,7 @@ static int cx25840_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
        case V4L2_CID_AUDIO_MUTE:
                if (state->is_cx25836)
                        return -EINVAL;
-               return cx25840_audio(client, VIDIOC_S_CTRL, ctrl);
+               return cx25840_audio_s_ctrl(sd, ctrl);
 
        default:
                return -EINVAL;
@@ -815,7 +812,7 @@ static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
        case V4L2_CID_AUDIO_MUTE:
                if (state->is_cx25836)
                        return -EINVAL;
-               return cx25840_audio(client, VIDIOC_G_CTRL, ctrl);
+               return cx25840_audio_g_ctrl(sd, ctrl);
        default:
                return -EINVAL;
        }
@@ -827,11 +824,9 @@ static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 
 static int cx25840_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
        switch (fmt->type) {
        case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-               return cx25840_vbi(client, VIDIOC_G_FMT, fmt);
+               return cx25840_vbi_g_fmt(sd, fmt);
        default:
                return -EINVAL;
        }
@@ -893,10 +888,10 @@ static int cx25840_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
                break;
 
        case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-               return cx25840_vbi(client, VIDIOC_S_FMT, fmt);
+               return cx25840_vbi_s_fmt(sd, fmt);
 
        case V4L2_BUF_TYPE_VBI_CAPTURE:
-               return cx25840_vbi(client, VIDIOC_S_FMT, fmt);
+               return cx25840_vbi_s_fmt(sd, fmt);
 
        default:
                return -EINVAL;
@@ -1101,6 +1096,16 @@ static void log_audio_status(struct i2c_client *client)
 
 /* ----------------------------------------------------------------------- */
 
+/* This init operation must be called to load the driver's firmware.
+   Without this the audio standard detection will fail and you will
+   only get mono.
+
+   Since loading the firmware is often problematic when the driver is
+   compiled into the kernel I recommend postponing calling this function
+   until the first open of the video device. Another reason for
+   postponing it is that loading this firmware takes a long time (seconds)
+   due to the slow i2c bus speed. So it will speed up the boot process if
+   you can avoid loading the fw as long as the video device isn't used.  */
 static int cx25840_init(struct v4l2_subdev *sd, u32 val)
 {
        struct cx25840_state *state = to_state(sd);
@@ -1146,20 +1151,6 @@ static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
 }
 #endif
 
-static int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return cx25840_vbi(client, VIDIOC_INT_DECODE_VBI_LINE, vbi);
-}
-
-static int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return cx25840_audio(client, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freq);
-}
-
 static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
 {
        struct cx25840_state *state = to_state(sd);
@@ -1195,10 +1186,12 @@ static int cx25840_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
 
        switch (qc->id) {
        case V4L2_CID_BRIGHTNESS:
+               return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
        case V4L2_CID_CONTRAST:
        case V4L2_CID_SATURATION:
+               return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
        case V4L2_CID_HUE:
-               return v4l2_ctrl_query_fill_std(qc);
+               return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
        default:
                break;
        }
@@ -1210,10 +1203,11 @@ static int cx25840_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
                return v4l2_ctrl_query_fill(qc, 0, 65535,
                                65535 / 100, state->default_volume);
        case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
        case V4L2_CID_AUDIO_BALANCE:
        case V4L2_CID_AUDIO_BASS:
        case V4L2_CID_AUDIO_TREBLE:
-               return v4l2_ctrl_query_fill_std(qc);
+               return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
        default:
                return -EINVAL;
        }
@@ -1380,19 +1374,6 @@ static int cx25840_log_status(struct v4l2_subdev *sd)
        return 0;
 }
 
-static int cx25840_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       /* ignore this command */
-       if (cmd == TUNER_SET_TYPE_ADDR || cmd == TUNER_SET_CONFIG)
-               return 0;
-
-       /* Old-style drivers rely on initialization on first use, so
-          call the init whenever a command is issued to this driver.
-          New-style drivers using v4l2_subdev should call init explicitly. */
-       cx25840_init(i2c_get_clientdata(client), 0);
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops cx25840_core_ops = {
@@ -1528,8 +1509,6 @@ MODULE_DEVICE_TABLE(i2c, cx25840_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "cx25840",
-       .driverid = I2C_DRIVERID_CX25840,
-       .command = cx25840_command,
        .probe = cx25840_probe,
        .remove = cx25840_remove,
        .id_table = cx25840_id,
index be0558277ca336567c8bf66771aa7fb5711d5d57..9ad0eb86ecfd4b94c7866bc696ea05f644234b2c 100644 (file)
@@ -75,11 +75,15 @@ int cx25840_loadfw(struct i2c_client *client);
 
 /* ----------------------------------------------------------------------- */
 /* cx25850-audio.c                                                         */
-int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg);
 void cx25840_audio_set_path(struct i2c_client *client);
+int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
+int cx25840_audio_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
+int cx25840_audio_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
 
 /* ----------------------------------------------------------------------- */
 /* cx25850-vbi.c                                                           */
-int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg);
+int cx25840_vbi_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt);
+int cx25840_vbi_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt);
+int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi);
 
 #endif
index 03f09b288eb8539ecd0438c68b989f59e9aef720..35f6592f6c47944d5e699cd783c3ded725d3c1ce 100644 (file)
@@ -82,199 +82,181 @@ static int decode_vps(u8 * dst, u8 * p)
        return err & 0xf0;
 }
 
-int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
+int cx25840_vbi_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
 {
-       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
-       struct v4l2_format *fmt;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct cx25840_state *state = to_state(sd);
        struct v4l2_sliced_vbi_format *svbi;
+       static const u16 lcr2vbi[] = {
+               0, V4L2_SLICED_TELETEXT_B, 0,   /* 1 */
+               0, V4L2_SLICED_WSS_625, 0,      /* 4 */
+               V4L2_SLICED_CAPTION_525,        /* 6 */
+               0, 0, V4L2_SLICED_VPS, 0, 0,    /* 9 */
+               0, 0, 0, 0
+       };
+       int is_pal = !(state->std & V4L2_STD_525_60);
+       int i;
 
-       switch (cmd) {
-       case VIDIOC_G_FMT:
-       {
-               static u16 lcr2vbi[] = {
-                       0, V4L2_SLICED_TELETEXT_B, 0,   /* 1 */
-                       0, V4L2_SLICED_WSS_625, 0,      /* 4 */
-                       V4L2_SLICED_CAPTION_525,        /* 6 */
-                       0, 0, V4L2_SLICED_VPS, 0, 0,    /* 9 */
-                       0, 0, 0, 0
-               };
-               int is_pal = !(state->std & V4L2_STD_525_60);
-               int i;
-
-               fmt = arg;
-               if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
-                       return -EINVAL;
-               svbi = &fmt->fmt.sliced;
-               memset(svbi, 0, sizeof(*svbi));
-               /* we're done if raw VBI is active */
-               if ((cx25840_read(client, 0x404) & 0x10) == 0)
-                       break;
+       if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+               return -EINVAL;
+       svbi = &fmt->fmt.sliced;
+       memset(svbi, 0, sizeof(*svbi));
+       /* we're done if raw VBI is active */
+       if ((cx25840_read(client, 0x404) & 0x10) == 0)
+               return 0;
 
-               if (is_pal) {
-                       for (i = 7; i <= 23; i++) {
-                               u8 v = cx25840_read(client, 0x424 + i - 7);
+       if (is_pal) {
+               for (i = 7; i <= 23; i++) {
+                       u8 v = cx25840_read(client, 0x424 + i - 7);
 
-                               svbi->service_lines[0][i] = lcr2vbi[v >> 4];
-                               svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
-                               svbi->service_set |=
-                                       svbi->service_lines[0][i] | svbi->service_lines[1][i];
-                       }
+                       svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+                       svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+                       svbi->service_set |= svbi->service_lines[0][i] |
+                                            svbi->service_lines[1][i];
                }
-               else {
-                       for (i = 10; i <= 21; i++) {
-                               u8 v = cx25840_read(client, 0x424 + i - 10);
-
-                               svbi->service_lines[0][i] = lcr2vbi[v >> 4];
-                               svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
-                               svbi->service_set |=
-                                       svbi->service_lines[0][i] | svbi->service_lines[1][i];
-                       }
+       } else {
+               for (i = 10; i <= 21; i++) {
+                       u8 v = cx25840_read(client, 0x424 + i - 10);
+
+                       svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+                       svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+                       svbi->service_set |= svbi->service_lines[0][i] |
+                                            svbi->service_lines[1][i];
                }
-               break;
        }
+       return 0;
+}
 
-       case VIDIOC_S_FMT:
-       {
-               int is_pal = !(state->std & V4L2_STD_525_60);
-               int vbi_offset = is_pal ? 1 : 0;
-               int i, x;
-               u8 lcr[24];
-
-               fmt = arg;
-               if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
-                   fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
-                       return -EINVAL;
-               svbi = &fmt->fmt.sliced;
-               if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-                       /* raw VBI */
-                       memset(svbi, 0, sizeof(*svbi));
-
-                       /* Setup standard */
-                       cx25840_std_setup(client);
-
-                       /* VBI Offset */
-                       cx25840_write(client, 0x47f, vbi_offset);
-                       cx25840_write(client, 0x404, 0x2e);
-                       break;
-               }
-
-               for (x = 0; x <= 23; x++)
-                       lcr[x] = 0x00;
+int cx25840_vbi_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct cx25840_state *state = to_state(sd);
+       struct v4l2_sliced_vbi_format *svbi;
+       int is_pal = !(state->std & V4L2_STD_525_60);
+       int vbi_offset = is_pal ? 1 : 0;
+       int i, x;
+       u8 lcr[24];
+
+       if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
+                       fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
+               return -EINVAL;
+       svbi = &fmt->fmt.sliced;
+       if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               /* raw VBI */
+               memset(svbi, 0, sizeof(*svbi));
 
                /* Setup standard */
                cx25840_std_setup(client);
 
-               /* Sliced VBI */
-               cx25840_write(client, 0x404, 0x32);     /* Ancillary data */
-               cx25840_write(client, 0x406, 0x13);
+               /* VBI Offset */
                cx25840_write(client, 0x47f, vbi_offset);
+               cx25840_write(client, 0x404, 0x2e);
+               return 0;
+       }
 
-               if (is_pal) {
-                       for (i = 0; i <= 6; i++)
-                               svbi->service_lines[0][i] =
-                                       svbi->service_lines[1][i] = 0;
-               } else {
-                       for (i = 0; i <= 9; i++)
-                               svbi->service_lines[0][i] =
-                                       svbi->service_lines[1][i] = 0;
-
-                       for (i = 22; i <= 23; i++)
-                               svbi->service_lines[0][i] =
-                                       svbi->service_lines[1][i] = 0;
-               }
-
-               for (i = 7; i <= 23; i++) {
-                       for (x = 0; x <= 1; x++) {
-                               switch (svbi->service_lines[1-x][i]) {
-                               case V4L2_SLICED_TELETEXT_B:
-                                       lcr[i] |= 1 << (4 * x);
-                                       break;
-                               case V4L2_SLICED_WSS_625:
-                                       lcr[i] |= 4 << (4 * x);
-                                       break;
-                               case V4L2_SLICED_CAPTION_525:
-                                       lcr[i] |= 6 << (4 * x);
-                                       break;
-                               case V4L2_SLICED_VPS:
-                                       lcr[i] |= 9 << (4 * x);
-                                       break;
-                               }
-                       }
-               }
+       for (x = 0; x <= 23; x++)
+               lcr[x] = 0x00;
+
+       /* Setup standard */
+       cx25840_std_setup(client);
+
+       /* Sliced VBI */
+       cx25840_write(client, 0x404, 0x32);     /* Ancillary data */
+       cx25840_write(client, 0x406, 0x13);
+       cx25840_write(client, 0x47f, vbi_offset);
+
+       if (is_pal) {
+               for (i = 0; i <= 6; i++)
+                       svbi->service_lines[0][i] =
+                               svbi->service_lines[1][i] = 0;
+       } else {
+               for (i = 0; i <= 9; i++)
+                       svbi->service_lines[0][i] =
+                               svbi->service_lines[1][i] = 0;
+
+               for (i = 22; i <= 23; i++)
+                       svbi->service_lines[0][i] =
+                               svbi->service_lines[1][i] = 0;
+       }
 
-               if (is_pal) {
-                       for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
-                               cx25840_write(client, i, lcr[6 + x]);
-                       }
-               }
-               else {
-                       for (x = 1, i = 0x424; i <= 0x430; i++, x++) {
-                               cx25840_write(client, i, lcr[9 + x]);
-                       }
-                       for (i = 0x431; i <= 0x434; i++) {
-                               cx25840_write(client, i, 0);
+       for (i = 7; i <= 23; i++) {
+               for (x = 0; x <= 1; x++) {
+                       switch (svbi->service_lines[1-x][i]) {
+                       case V4L2_SLICED_TELETEXT_B:
+                               lcr[i] |= 1 << (4 * x);
+                               break;
+                       case V4L2_SLICED_WSS_625:
+                               lcr[i] |= 4 << (4 * x);
+                               break;
+                       case V4L2_SLICED_CAPTION_525:
+                               lcr[i] |= 6 << (4 * x);
+                               break;
+                       case V4L2_SLICED_VPS:
+                               lcr[i] |= 9 << (4 * x);
+                               break;
                        }
                }
+       }
 
-               cx25840_write(client, 0x43c, 0x16);
-
-               if (is_pal) {
-                       cx25840_write(client, 0x474, 0x2a);
-               } else {
-                       cx25840_write(client, 0x474, 0x22);
-               }
-               break;
+       if (is_pal) {
+               for (x = 1, i = 0x424; i <= 0x434; i++, x++)
+                       cx25840_write(client, i, lcr[6 + x]);
+       } else {
+               for (x = 1, i = 0x424; i <= 0x430; i++, x++)
+                       cx25840_write(client, i, lcr[9 + x]);
+               for (i = 0x431; i <= 0x434; i++)
+                       cx25840_write(client, i, 0);
        }
 
-       case VIDIOC_INT_DECODE_VBI_LINE:
-       {
-               struct v4l2_decode_vbi_line *vbi = arg;
-               u8 *p = vbi->p;
-               int id1, id2, l, err = 0;
+       cx25840_write(client, 0x43c, 0x16);
+       cx25840_write(client, 0x474, is_pal ? 0x2a : 0x22);
+       return 0;
+}
 
-               if (p[0] || p[1] != 0xff || p[2] != 0xff ||
-                   (p[3] != 0x55 && p[3] != 0x91)) {
-                       vbi->line = vbi->type = 0;
-                       break;
-               }
+int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi)
+{
+       struct cx25840_state *state = to_state(sd);
+       u8 *p = vbi->p;
+       int id1, id2, l, err = 0;
+
+       if (p[0] || p[1] != 0xff || p[2] != 0xff ||
+                       (p[3] != 0x55 && p[3] != 0x91)) {
+               vbi->line = vbi->type = 0;
+               return 0;
+       }
 
-               p += 4;
-               id1 = p[-1];
-               id2 = p[0] & 0xf;
-               l = p[2] & 0x3f;
-               l += state->vbi_line_offset;
-               p += 4;
+       p += 4;
+       id1 = p[-1];
+       id2 = p[0] & 0xf;
+       l = p[2] & 0x3f;
+       l += state->vbi_line_offset;
+       p += 4;
 
-               switch (id2) {
-               case 1:
-                       id2 = V4L2_SLICED_TELETEXT_B;
-                       break;
-               case 4:
-                       id2 = V4L2_SLICED_WSS_625;
-                       break;
-               case 6:
-                       id2 = V4L2_SLICED_CAPTION_525;
-                       err = !odd_parity(p[0]) || !odd_parity(p[1]);
-                       break;
-               case 9:
-                       id2 = V4L2_SLICED_VPS;
-                       if (decode_vps(p, p) != 0) {
-                               err = 1;
-                       }
-                       break;
-               default:
-                       id2 = 0;
+       switch (id2) {
+       case 1:
+               id2 = V4L2_SLICED_TELETEXT_B;
+               break;
+       case 4:
+               id2 = V4L2_SLICED_WSS_625;
+               break;
+       case 6:
+               id2 = V4L2_SLICED_CAPTION_525;
+               err = !odd_parity(p[0]) || !odd_parity(p[1]);
+               break;
+       case 9:
+               id2 = V4L2_SLICED_VPS;
+               if (decode_vps(p, p) != 0)
                        err = 1;
-                       break;
-               }
-
-               vbi->type = err ? 0 : id2;
-               vbi->line = err ? 0 : l;
-               vbi->is_second_field = err ? 0 : (id1 == 0x55);
-               vbi->p = p;
                break;
-       }
+       default:
+               id2 = 0;
+               err = 1;
+               break;
        }
 
+       vbi->type = err ? 0 : id2;
+       vbi->line = err ? 0 : l;
+       vbi->is_second_field = err ? 0 : (id1 == 0x55);
+       vbi->p = p;
        return 0;
 }
index 2d250a2a7bc3ac53eaf6b3f6c546b33ad8510838..49952980dab3bccaf1ce2c913e487ef43498e38c 100644 (file)
@@ -61,7 +61,7 @@ config VIDEO_CX88_DVB
        select DVB_STV0299 if !DVB_FE_CUSTOMISE
        select DVB_STV0288 if !DVB_FE_CUSTOMISE
        select DVB_STB6000 if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
        ---help---
          This adds support for DVB/ATSC cards based on the
          Conexant 2388x chip.
index 7f5b8bfd08ac74aa01ec0657c0641ccc25348000..44eacfb0d0d6073db886168e8d4120f99cd76ae7 100644 (file)
@@ -746,7 +746,6 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void  *priv,
                return -EINVAL;
 
        strlcpy(f->description, "MPEG", sizeof(f->description));
-       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        f->pixelformat = V4L2_PIX_FMT_MPEG;
        return 0;
 }
@@ -757,7 +756,6 @@ static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
        struct cx8802_fh  *fh   = priv;
        struct cx8802_dev *dev  = fh->dev;
 
-       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.bytesperline = 0;
        f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
@@ -776,7 +774,6 @@ static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
        struct cx8802_fh  *fh   = priv;
        struct cx8802_dev *dev  = fh->dev;
 
-       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.bytesperline = 0;
        f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
@@ -793,7 +790,6 @@ static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,
        struct cx8802_dev *dev  = fh->dev;
        struct cx88_core  *core = dev->core;
 
-       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.bytesperline = 0;
        f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
@@ -919,7 +915,7 @@ static int vidioc_log_status (struct file *file, void *priv)
        snprintf(name, sizeof(name), "%s/2", core->name);
        printk("%s/2: ============  START LOG STATUS  ============\n",
                core->name);
-       cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL);
+       call_all(core, core, log_status);
        cx2341x_log_status(&dev->params, name);
        printk("%s/2: =============  END LOG STATUS  =============\n",
                core->name);
@@ -974,7 +970,7 @@ static int vidioc_g_frequency (struct file *file, void *priv,
 
        f->type = V4L2_TUNER_ANALOG_TV;
        f->frequency = core->freq;
-       cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
+       call_all(core, tuner, g_frequency, f);
 
        return 0;
 }
index 733ede34f93a43151db923d962e51cc225b0a0eb..0363971a23a83001140a012b66562f3b3ed01fb3 100644 (file)
@@ -732,6 +732,8 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               /* Some variants use a tda9874 and so need the tvaudio module. */
+               .audio_chip     = V4L2_IDENT_TVAUDIO,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
@@ -1934,6 +1936,39 @@ static const struct cx88_board cx88_boards[] = {
                } },
                .mpeg           = CX88_MPEG_DVB,
        },
+       [CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII] = {
+               .name           = "Terratec Cinergy HT PCI MKII",
+               .tuner_type     = TUNER_XC2028,
+               .tuner_addr     = 0x61,
+               .radio_type     = TUNER_XC2028,
+               .radio_addr     = 0x61,
+               .input          = { {
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x004ff,
+                       .gpio1  = 0x010ff,
+                       .gpio2  = 0x00001,
+               }, {
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x004fb,
+                       .gpio1  = 0x010ef,
+                       .audioroute = 1,
+               }, {
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x004fb,
+                       .gpio1  = 0x010ef,
+                       .audioroute = 1,
+               } },
+               .radio = {
+                       .type   = CX88_RADIO,
+                       .gpio0  = 0x004ff,
+                       .gpio1  = 0x010ff,
+                       .gpio2  = 0x0ff,
+               },
+               .mpeg           = CX88_MPEG_DVB,
+       },
 };
 
 /* ------------------------------------------------------------------ */
@@ -2343,6 +2378,10 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0xb200,
                .subdevice = 0x4200,
                .card      = CX88_BOARD_SATTRADE_ST4200,
+       }, {
+               .subvendor = 0x153b,
+               .subdevice = 0x1177,
+               .card      = CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII,
        },
 };
 
@@ -2819,6 +2858,7 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl)
                 */
                break;
        case CX88_BOARD_PINNACLE_HYBRID_PCTV:
+       case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII:
                ctl->demod = XC3028_FE_ZARLINK456;
                ctl->mts = 1;
                break;
@@ -2947,7 +2987,7 @@ static void cx88_card_setup(struct cx88_core *core)
                tea5767_cfg.tuner = TUNER_TEA5767;
                tea5767_cfg.priv  = &ctl;
 
-               cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg);
+               call_all(core, tuner, s_config, &tea5767_cfg);
                break;
        }
        case  CX88_BOARD_TEVII_S420:
@@ -2972,7 +3012,7 @@ static void cx88_card_setup(struct cx88_core *core)
                tun_setup.type           = core->board.radio_type;
                tun_setup.addr           = core->board.radio_addr;
                tun_setup.tuner_callback = cx88_tuner_callback;
-               cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup);
+               call_all(core, tuner, s_type_addr, &tun_setup);
                mode_mask &= ~T_RADIO;
        }
 
@@ -2982,7 +3022,7 @@ static void cx88_card_setup(struct cx88_core *core)
                tun_setup.addr           = core->board.tuner_addr;
                tun_setup.tuner_callback = cx88_tuner_callback;
 
-               cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup);
+               call_all(core, tuner, s_type_addr, &tun_setup);
        }
 
        if (core->board.tda9887_conf) {
@@ -2991,7 +3031,7 @@ static void cx88_card_setup(struct cx88_core *core)
                tda9887_cfg.tuner = TUNER_TDA9887;
                tda9887_cfg.priv  = &core->board.tda9887_conf;
 
-               cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tda9887_cfg);
+               call_all(core, tuner, s_config, &tda9887_cfg);
        }
 
        if (core->board.tuner_type == TUNER_XC2028) {
@@ -3007,9 +3047,9 @@ static void cx88_card_setup(struct cx88_core *core)
                xc2028_cfg.priv  = &ctl;
                info_printk(core, "Asking xc2028/3028 to load firmware %s\n",
                            ctl.fname);
-               cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &xc2028_cfg);
+               call_all(core, tuner, s_config, &xc2028_cfg);
        }
-       cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
+       call_all(core, core, s_standby, 0);
 }
 
 /* ------------------------------------------------------------------ */
@@ -3089,6 +3129,8 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
        int i;
 
        core = kzalloc(sizeof(*core), GFP_KERNEL);
+       if (core == NULL)
+               return NULL;
 
        atomic_inc(&core->refcount);
        core->pci_bus  = pci->bus->number;
@@ -3100,7 +3142,15 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
 
        core->nr = nr;
        sprintf(core->name, "cx88[%d]", core->nr);
+
+       strcpy(core->v4l2_dev.name, core->name);
+       if (v4l2_device_register(NULL, &core->v4l2_dev)) {
+               kfree(core);
+               return NULL;
+       }
+
        if (0 != cx88_get_resources(core, pci)) {
+               v4l2_device_unregister(&core->v4l2_dev);
                kfree(core);
                return NULL;
        }
@@ -3111,6 +3161,11 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
                              pci_resource_len(pci, 0));
        core->bmmio = (u8 __iomem *)core->lmmio;
 
+       if (core->lmmio == NULL) {
+               kfree(core);
+               return NULL;
+       }
+
        /* board config */
        core->boardnr = UNSET;
        if (card[core->nr] < ARRAY_SIZE(cx88_boards))
@@ -3149,8 +3204,36 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
        cx88_i2c_init(core, pci);
 
        /* load tuner module, if needed */
-       if (TUNER_ABSENT != core->board.tuner_type)
-               request_module("tuner");
+       if (TUNER_ABSENT != core->board.tuner_type) {
+               /* Ignore 0x6b and 0x6f on cx88 boards.
+                * FusionHDTV5 RT Gold has an ir receiver at 0x6b
+                * and an RTC at 0x6f which can get corrupted if probed. */
+               static const unsigned short tv_addrs[] = {
+                       0x42, 0x43, 0x4a, 0x4b,         /* tda8290 */
+                       0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+                       0x68, 0x69, 0x6a, 0x6c, 0x6d, 0x6e,
+                       I2C_CLIENT_END
+               };
+               int has_demod = (core->board.tda9887_conf & TDA9887_PRESENT);
+
+               /* I don't trust the radio_type as is stored in the card
+                  definitions, so we just probe for it.
+                  The radio_type is sometimes missing, or set to UNSET but
+                  later code configures a tea5767.
+                */
+               v4l2_i2c_new_probed_subdev(&core->i2c_adap, "tuner", "tuner",
+                               v4l2_i2c_tuner_addrs(ADDRS_RADIO));
+               if (has_demod)
+                       v4l2_i2c_new_probed_subdev(&core->i2c_adap, "tuner",
+                               "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+               if (core->board.tuner_addr == ADDR_UNSET) {
+                       v4l2_i2c_new_probed_subdev(&core->i2c_adap, "tuner",
+                               "tuner", has_demod ? tv_addrs + 4 : tv_addrs);
+               } else {
+                       v4l2_i2c_new_subdev(&core->i2c_adap,
+                               "tuner", "tuner", core->board.tuner_addr);
+               }
+       }
 
        cx88_card_setup(core);
        cx88_ir_init(core, pci);
index b045874ad04f98c5d89048204e57277ce345e4a7..f2fb9f30bfc185c025a06793294adb19bc06ad48 100644 (file)
@@ -991,7 +991,7 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
        set_tvaudio(core);
 
        // tell i2c chips
-       cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm);
+       call_all(core, tuner, s_std, norm);
 
        // done
        return 0;
@@ -1011,7 +1011,8 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
                return NULL;
        *vfd = *template;
        vfd->minor   = -1;
-       vfd->parent  = &pci->dev;
+       vfd->v4l2_dev = &core->v4l2_dev;
+       vfd->parent = &pci->dev;
        vfd->release = video_device_release;
        snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
                 core->name, type, core->board.name);
@@ -1058,12 +1059,16 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
 
        mutex_lock(&devlist);
        cx88_ir_fini(core);
-       if (0 == core->i2c_rc)
+       if (0 == core->i2c_rc) {
+               if (core->i2c_rtc)
+                       i2c_unregister_device(core->i2c_rtc);
                i2c_del_adapter(&core->i2c_adap);
+       }
        list_del(&core->devlist);
        iounmap(core->lmmio);
        cx88_devcount--;
        mutex_unlock(&devlist);
+       v4l2_device_unregister(&core->v4l2_dev);
        kfree(core);
 }
 
index aef5297534af95f7101ec065040f68cdf222bca7..4ff4d9fe0355849f3c9879421cdf98bd4beb7c45 100644 (file)
@@ -241,6 +241,12 @@ static struct mt352_config dvico_fusionhdtv_dual = {
        .demod_init    = dvico_dual_demod_init,
 };
 
+static struct zl10353_config cx88_terratec_cinergy_ht_pci_mkii_config = {
+       .demod_address = (0x1e >> 1),
+       .no_tuner      = 1,
+       .if2           = 45600,
+};
+
 #if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
 static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
 {
@@ -1131,6 +1137,16 @@ static int dvb_register(struct cx8802_dev *dev)
                if (fe0->dvb.frontend != NULL)
                        fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
                break;
+       case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII:
+               fe0->dvb.frontend = dvb_attach(zl10353_attach,
+                                              &cx88_terratec_cinergy_ht_pci_mkii_config,
+                                              &core->i2c_adap);
+               if (fe0->dvb.frontend) {
+                       fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+                       if (attach_xc3028(0x61, dev) < 0)
+                               goto frontend_detach;
+               }
+               break;
        default:
                printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
                       core->name);
@@ -1152,7 +1168,7 @@ static int dvb_register(struct cx8802_dev *dev)
                fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
 
        /* Put the analog decoder in standby to keep it quiet */
-       cx88_call_i2c_clients(core, TUNER_SET_STANDBY, NULL);
+       call_all(core, core, s_standby, 0);
 
        /* register everything */
        return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
index c0ff2305d804bfb7761577c8371d43e27036ba15..996b4ed5a4fc8ae414cd18abc1a6d1cdb44ef092 100644 (file)
@@ -97,37 +97,6 @@ static int cx8800_bit_getsda(void *data)
 
 /* ----------------------------------------------------------------------- */
 
-static int attach_inform(struct i2c_client *client)
-{
-       struct cx88_core *core = i2c_get_adapdata(client->adapter);
-
-       dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
-               client->driver->driver.name, client->addr, client->name);
-       return 0;
-}
-
-static int detach_inform(struct i2c_client *client)
-{
-       struct cx88_core *core = i2c_get_adapdata(client->adapter);
-
-       dprintk(1, "i2c detach [client=%s]\n", client->name);
-       return 0;
-}
-
-void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
-{
-       if (0 != core->i2c_rc)
-               return;
-
-       if (core->gate_ctrl)
-               core->gate_ctrl(core, 1);
-
-       i2c_clients_command(&core->i2c_adap, cmd, arg);
-
-       if (core->gate_ctrl)
-               core->gate_ctrl(core, 0);
-}
-
 static const struct i2c_algo_bit_data cx8800_i2c_algo_template = {
        .setsda  = cx8800_bit_setsda,
        .setscl  = cx8800_bit_setscl,
@@ -173,20 +142,14 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
        memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
               sizeof(core->i2c_algo));
 
-       if (core->board.tuner_type != TUNER_ABSENT)
-               core->i2c_adap.class |= I2C_CLASS_TV_ANALOG;
-       if (core->board.mpeg & CX88_MPEG_DVB)
-               core->i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
 
        core->i2c_adap.dev.parent = &pci->dev;
        strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
        core->i2c_adap.owner = THIS_MODULE;
        core->i2c_adap.id = I2C_HW_B_CX2388x;
-       core->i2c_adap.client_register = attach_inform;
-       core->i2c_adap.client_unregister = detach_inform;
        core->i2c_algo.udelay = i2c_udelay;
        core->i2c_algo.data = core;
-       i2c_set_adapdata(&core->i2c_adap,core);
+       i2c_set_adapdata(&core->i2c_adap, &core->v4l2_dev);
        core->i2c_adap.algo_data = &core->i2c_algo;
        core->i2c_client.adapter = &core->i2c_adap;
        strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE);
@@ -222,8 +185,6 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
 
 /* ----------------------------------------------------------------------- */
 
-EXPORT_SYMBOL(cx88_call_i2c_clients);
-
 /*
  * Local variables:
  * c-basic-offset: 8
index 8683d104de72a4113587bff03440d38749ce048b..ec05312a9b6222f2ba627fde070777d17ef82188 100644 (file)
@@ -48,8 +48,7 @@ struct cx88_IR {
 
        /* poll external decoder */
        int polling;
-       struct work_struct work;
-       struct timer_list timer;
+       struct delayed_work work;
        u32 gpio_addr;
        u32 last_gpio;
        u32 mask_keycode;
@@ -143,27 +142,19 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
        }
 }
 
-static void ir_timer(unsigned long data)
-{
-       struct cx88_IR *ir = (struct cx88_IR *)data;
-
-       schedule_work(&ir->work);
-}
-
 static void cx88_ir_work(struct work_struct *work)
 {
-       struct cx88_IR *ir = container_of(work, struct cx88_IR, work);
+       struct cx88_IR *ir = container_of(work, struct cx88_IR, work.work);
 
        cx88_ir_handle_key(ir);
-       mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
+       schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
 }
 
 void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
 {
        if (ir->polling) {
-               setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
-               INIT_WORK(&ir->work, cx88_ir_work);
-               schedule_work(&ir->work);
+               INIT_DELAYED_WORK(&ir->work, cx88_ir_work);
+               schedule_delayed_work(&ir->work, 0);
        }
        if (ir->sampling) {
                core->pci_irqmask |= PCI_INT_IR_SMPINT;
@@ -179,10 +170,8 @@ void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir)
                core->pci_irqmask &= ~PCI_INT_IR_SMPINT;
        }
 
-       if (ir->polling) {
-               del_timer_sync(&ir->timer);
-               flush_scheduled_work();
-       }
+       if (ir->polling)
+               cancel_delayed_work_sync(&ir->work);
 }
 
 /* ---------------------------------------------------------------------- */
@@ -226,6 +215,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        case CX88_BOARD_HAUPPAUGE_HVR3000:
        case CX88_BOARD_HAUPPAUGE_HVR4000:
        case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+       case CX88_BOARD_PCHDTV_HD3000:
+       case CX88_BOARD_PCHDTV_HD5500:
                ir_codes = ir_codes_hauppauge_new;
                ir_type = IR_TYPE_RC5;
                ir->sampling = 1;
@@ -466,6 +457,8 @@ void cx88_ir_irq(struct cx88_core *core)
        case CX88_BOARD_HAUPPAUGE_HVR3000:
        case CX88_BOARD_HAUPPAUGE_HVR4000:
        case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+       case CX88_BOARD_PCHDTV_HD3000:
+       case CX88_BOARD_PCHDTV_HD5500:
                ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
                ir_dprintk("biphase decoded: %x\n", ircode);
                /*
index 791e69d804f97d89ae37f42520fc34536675072c..434237af5184ec99632b454a195affc62a2ce78d 100644 (file)
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-/* Include V4L1 specific functions. Should be removed soon */
-#include <linux/videodev.h>
-#endif
-
 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
@@ -298,6 +293,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
 };
 static const int CX8800_CTLS = ARRAY_SIZE(cx8800_ctls);
 
+/* Must be sorted from low to high control ID! */
 const u32 cx88_user_ctrls[] = {
        V4L2_CID_USER_CLASS,
        V4L2_CID_BRIGHTNESS,
@@ -435,8 +431,7 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input)
                        struct v4l2_routing route;
 
                        route.input = INPUT(input).audioroute;
-                       cx88_call_i2c_clients(core,
-                               VIDIOC_INT_S_AUDIO_ROUTING, &route);
+                       call_all(core, audio, s_routing, &route);
                }
                /* cx2388's C-ADC is connected to the tuner only.
                   When used with S-Video, that ADC is busy dealing with
@@ -831,8 +826,7 @@ static int video_open(struct file *file)
                                struct v4l2_routing route;
 
                                route.input = core->board.radio.audioroute;
-                               cx88_call_i2c_clients(core,
-                                       VIDIOC_INT_S_AUDIO_ROUTING, &route);
+                               call_all(core, audio, s_routing, &route);
                        }
                        /* "I2S ADC mode" */
                        core->tvaudio = WW_I2SADC;
@@ -843,7 +837,7 @@ static int video_open(struct file *file)
                        cx88_set_tvaudio(core);
                        cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
                }
-               cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL);
+               call_all(core, tuner, s_radio);
        }
        unlock_kernel();
 
@@ -937,7 +931,7 @@ static int video_release(struct file *file)
        kfree(fh);
 
        if(atomic_dec_and_test(&dev->core->users))
-               cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+               call_all(dev->core, core, s_standby, 0);
 
        return 0;
 }
@@ -1276,15 +1270,12 @@ int cx88_enum_input (struct cx88_core  *core,struct v4l2_input *i)
                [ CX88_VMUX_DVB        ] = "DVB",
                [ CX88_VMUX_DEBUG      ] = "for debug only",
        };
-       unsigned int n;
+       unsigned int n = i->index;
 
-       n = i->index;
        if (n >= 4)
                return -EINVAL;
        if (0 == INPUT(n).type)
                return -EINVAL;
-       memset(i,0,sizeof(*i));
-       i->index = n;
        i->type  = V4L2_INPUT_TYPE_CAMERA;
        strcpy(i->name,iname[INPUT(n).type]);
        if ((CX88_VMUX_TELEVISION == INPUT(n).type) ||
@@ -1402,7 +1393,7 @@ static int vidioc_g_frequency (struct file *file, void *priv,
        f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
        f->frequency = core->freq;
 
-       cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
+       call_all(core, tuner, g_frequency, f);
 
        return 0;
 }
@@ -1418,7 +1409,7 @@ int cx88_set_freq (struct cx88_core  *core,
        mutex_lock(&core->lock);
        core->freq = f->frequency;
        cx88_newstation(core);
-       cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
+       call_all(core, tuner, s_frequency, f);
 
        /* When changing channels it is required to reset TVAUDIO */
        msleep (10);
@@ -1500,7 +1491,7 @@ static int radio_g_tuner (struct file *file, void *priv,
        strcpy(t->name, "Radio");
        t->type = V4L2_TUNER_RADIO;
 
-       cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);
+       call_all(core, tuner, g_tuner, t);
        return 0;
 }
 
@@ -1520,7 +1511,6 @@ static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
        if (unlikely(a->index))
                return -EINVAL;
 
-       memset(a,0,sizeof(*a));
        strcpy(a->name,"Radio");
        return 0;
 }
@@ -1535,7 +1525,7 @@ static int radio_s_tuner (struct file *file, void *priv,
        if (0 != t->index)
                return -EINVAL;
 
-       cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t);
+       call_all(core, tuner, s_tuner, t);
 
        return 0;
 }
@@ -1892,12 +1882,30 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
        /* load and configure helper modules */
 
        if (core->board.audio_chip == V4L2_IDENT_WM8775)
-               request_module("wm8775");
+               v4l2_i2c_new_subdev(&core->i2c_adap,
+                               "wm8775", "wm8775", 0x36 >> 1);
+
+       if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
+               /* This probes for a tda9874 as is used on some
+                  Pixelview Ultra boards. */
+               static const unsigned short i2c_addr[] = {
+                       0xb0 >> 1, I2C_CLIENT_END
+               };
+
+               v4l2_i2c_new_probed_subdev(&core->i2c_adap,
+                               "tvaudio", "tvaudio", i2c_addr);
+       }
 
        switch (core->boardnr) {
        case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
-       case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
+       case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: {
+               static struct i2c_board_info rtc_info = {
+                       I2C_BOARD_INFO("isl1208", 0x6f)
+               };
+
                request_module("rtc-isl1208");
+               core->i2c_rtc = i2c_new_device(&core->i2c_adap, &rtc_info);
+       }
                /* break intentionally omitted */
        case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
                request_module("ir-kbd-i2c");
index 6025fdd233445857d571632126399566acbc6a0b..9a43fdf20fae8977d3ac70fad7324a562aa6cc55 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/videodev2.h>
 #include <linux/kdev_t.h>
 
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/tuner.h>
 #include <media/tveeprom.h>
 #include <media/videobuf-dma-sg.h>
@@ -231,6 +231,7 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_SATTRADE_ST4200         76
 #define CX88_BOARD_TBS_8910                77
 #define CX88_BOARD_PROF_6200               78
+#define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
@@ -302,7 +303,6 @@ struct cx88_dmaqueue {
        struct btcx_riscmem    stopper;
        u32                    count;
 };
-struct cx88_core;
 
 struct cx88_core {
        struct list_head           devlist;
@@ -327,6 +327,8 @@ struct cx88_core {
        u32                        i2c_state, i2c_rc;
 
        /* config info -- analog */
+       struct v4l2_device         v4l2_dev;
+       struct i2c_client          *i2c_rtc;
        unsigned int               boardnr;
        struct cx88_board          board;
 
@@ -365,6 +367,22 @@ struct cx88_core {
        int                        active_fe_id;
 };
 
+static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
+{
+       return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
+}
+
+#define call_all(core, o, f, args...)                          \
+       do {                                                    \
+               if (!core->i2c_rc) {                            \
+                       if (core->gate_ctrl)                    \
+                               core->gate_ctrl(core, 1);       \
+                       v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \
+                       if (core->gate_ctrl)                    \
+                               core->gate_ctrl(core, 0);       \
+               }                                               \
+       } while (0)
+
 struct cx8800_dev;
 struct cx8802_dev;
 
@@ -610,8 +628,6 @@ extern struct videobuf_queue_ops cx8800_vbi_qops;
 /* cx88-i2c.c                                                  */
 
 extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci);
-extern void cx88_call_i2c_clients(struct cx88_core *core,
-                                 unsigned int cmd, void *arg);
 
 
 /* ----------------------------------------------------------- */
index 298810d5262bc7b31e5cd0acb06c194543f84541..ba3709bec3f0a42d84d34d2ba88e8bd62feb104a 100644 (file)
@@ -189,17 +189,20 @@ static void dabusb_iso_complete (struct urb *purb)
                                        dst += len;
                                }
                                else
-                                       err("dabusb_iso_complete: invalid len %d", len);
+                                       dev_err(&purb->dev->dev,
+                                               "dabusb_iso_complete: invalid len %d\n", len);
                        }
                        else
                                dev_warn(&purb->dev->dev, "dabusb_iso_complete: corrupted packet status: %d\n", purb->iso_frame_desc[i].status);
                if (dst != purb->actual_length)
-                       err("dst!=purb->actual_length:%d!=%d", dst, purb->actual_length);
+                       dev_err(&purb->dev->dev,
+                               "dst!=purb->actual_length:%d!=%d\n",
+                                       dst, purb->actual_length);
        }
 
        if (atomic_dec_and_test (&s->pending_io) && !s->remove_pending && s->state != _stopped) {
                s->overruns++;
-               err("overrun (%d)", s->overruns);
+               dev_err(&purb->dev->dev, "overrun (%d)\n", s->overruns);
        }
        wake_up (&s->wait);
 }
@@ -220,13 +223,14 @@ static int dabusb_alloc_buffers (pdabusb_t s)
        while (transfer_len < (s->total_buffer_size << 10)) {
                b = kzalloc(sizeof (buff_t), GFP_KERNEL);
                if (!b) {
-                       err("kzalloc(sizeof(buff_t))==NULL");
+                       dev_err(&s->usbdev->dev,
+                               "kzalloc(sizeof(buff_t))==NULL\n");
                        goto err;
                }
                b->s = s;
                b->purb = usb_alloc_urb(packets, GFP_KERNEL);
                if (!b->purb) {
-                       err("usb_alloc_urb == NULL");
+                       dev_err(&s->usbdev->dev, "usb_alloc_urb == NULL\n");
                        kfree (b);
                        goto err;
                }
@@ -235,7 +239,8 @@ static int dabusb_alloc_buffers (pdabusb_t s)
                if (!b->purb->transfer_buffer) {
                        kfree (b->purb);
                        kfree (b);
-                       err("kmalloc(%d)==NULL", transfer_buffer_length);
+                       dev_err(&s->usbdev->dev,
+                               "kmalloc(%d)==NULL\n", transfer_buffer_length);
                        goto err;
                }
 
@@ -279,10 +284,11 @@ static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb)
 
        ret=usb_bulk_msg(s->usbdev, pipe, pb->data, pb->size, &actual_length, 100);
        if(ret<0) {
-               err("dabusb: usb_bulk_msg failed(%d)",ret);
+               dev_err(&s->usbdev->dev,
+                       "usb_bulk_msg failed(%d)\n", ret);
 
                if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
-                       err("set_interface failed");
+                       dev_err(&s->usbdev->dev, "set_interface failed\n");
                        return -EINVAL;
                }
 
@@ -291,7 +297,7 @@ static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb)
        if( ret == -EPIPE ) {
                dev_warn(&s->usbdev->dev, "CLEAR_FEATURE request to remove STALL condition.\n");
                if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe)))
-                       err("request failed");
+                       dev_err(&s->usbdev->dev, "request failed\n");
        }
 
        pb->size = actual_length;
@@ -305,7 +311,8 @@ static int dabusb_writemem (pdabusb_t s, int pos, const unsigned char *data,
        unsigned char *transfer_buffer =  kmalloc (len, GFP_KERNEL);
 
        if (!transfer_buffer) {
-               err("dabusb_writemem: kmalloc(%d) failed.", len);
+               dev_err(&s->usbdev->dev,
+                       "dabusb_writemem: kmalloc(%d) failed.\n", len);
                return -ENOMEM;
        }
 
@@ -327,13 +334,14 @@ static int dabusb_loadmem (pdabusb_t s, const char *fname)
 {
        int ret;
        const struct ihex_binrec *rec;
-       const struct firmware *fw;
+       const struct firmware *uninitialized_var(fw);
 
        dbg("Enter dabusb_loadmem (internal)");
 
        ret = request_ihex_firmware(&fw, "dabusb/firmware.fw", &s->usbdev->dev);
        if (ret) {
-               err("Failed to load \"dabusb/firmware.fw\": %d\n", ret);
+               dev_err(&s->usbdev->dev,
+                       "Failed to load \"dabusb/firmware.fw\": %d\n", ret);
                goto out;
        }
        ret = dabusb_8051_reset (s, 1);
@@ -346,9 +354,10 @@ static int dabusb_loadmem (pdabusb_t s, const char *fname)
                ret = dabusb_writemem(s, be32_to_cpu(rec->addr), rec->data,
                                       be16_to_cpu(rec->len));
                if (ret < 0) {
-                       err("dabusb_writemem failed (%d %04X %p %d)", ret,
-                           be32_to_cpu(rec->addr), rec->data,
-                           be16_to_cpu(rec->len));
+                       dev_err(&s->usbdev->dev,
+                               "dabusb_writemem failed (%d %04X %p %d)\n",
+                               ret, be32_to_cpu(rec->addr),
+                               rec->data, be16_to_cpu(rec->len));
                        break;
                }
        }
@@ -396,13 +405,15 @@ static int dabusb_fpga_download (pdabusb_t s, const char *fname)
        dbg("Enter dabusb_fpga_download (internal)");
 
        if (!b) {
-               err("kmalloc(sizeof(bulk_transfer_t))==NULL");
+               dev_err(&s->usbdev->dev,
+                       "kmalloc(sizeof(bulk_transfer_t))==NULL\n");
                return -ENOMEM;
        }
 
        ret = request_firmware(&fw, "dabusb/bitstream.bin", &s->usbdev->dev);
        if (ret) {
-               err("Failed to load \"dabusb/bitstream.bin\": %d\n", ret);
+               dev_err(&s->usbdev->dev,
+                       "Failed to load \"dabusb/bitstream.bin\": %d\n", ret);
                kfree(b);
                return ret;
        }
@@ -425,7 +436,7 @@ static int dabusb_fpga_download (pdabusb_t s, const char *fname)
                memcpy (b->data + 4, fw->data + 74 + n, 60);
                ret = dabusb_bulk (s, b);
                if (ret < 0) {
-                       err("dabusb_bulk failed.");
+                       dev_err(&s->usbdev->dev, "dabusb_bulk failed.\n");
                        break;
                }
                mdelay (1);
@@ -478,9 +489,11 @@ static int dabusb_startrek (pdabusb_t s)
 
                        ret = usb_submit_urb (end->purb, GFP_KERNEL);
                        if (ret) {
-                               err("usb_submit_urb returned:%d", ret);
+                               dev_err(&s->usbdev->dev,
+                                       "usb_submit_urb returned:%d\n", ret);
                                if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
-                                       err("startrek: dabusb_add_buf_tail failed");
+                                       dev_err(&s->usbdev->dev,
+                                               "startrek: dabusb_add_buf_tail failed\n");
                                break;
                        }
                        else
@@ -523,7 +536,8 @@ static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, l
 
                        spin_unlock_irqrestore(&s->lock, flags);
 
-                       err("error: rec_buf_list is empty");
+                       dev_err(&s->usbdev->dev,
+                               "error: rec_buf_list is empty\n");
                        goto err;
                }
 
@@ -552,7 +566,8 @@ static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, l
 
                        if (list_empty (&s->rec_buff_list)) {
                                spin_unlock_irqrestore(&s->lock, flags);
-                               err("error: still no buffer available.");
+                               dev_err(&s->usbdev->dev,
+                                       "error: still no buffer available.\n");
                                goto err;
                        }
                        spin_unlock_irqrestore(&s->lock, flags);
@@ -573,7 +588,7 @@ static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, l
                dbg("copy_to_user:%p %p %d",buf, purb->transfer_buffer + s->readptr, cnt);
 
                if (copy_to_user (buf, purb->transfer_buffer + s->readptr, cnt)) {
-                       err("read: copy_to_user failed");
+                       dev_err(&s->usbdev->dev, "read: copy_to_user failed\n");
                        if (!ret)
                                ret = -EFAULT;
                        goto err;
@@ -587,7 +602,8 @@ static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, l
                if (s->readptr == purb->actual_length) {
                        // finished, take next buffer
                        if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
-                               err("read: dabusb_add_buf_tail failed");
+                               dev_err(&s->usbdev->dev,
+                                       "read: dabusb_add_buf_tail failed\n");
                        s->readptr = 0;
                }
        }
@@ -623,7 +639,7 @@ static int dabusb_open (struct inode *inode, struct file *file)
        }
        if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
                mutex_unlock(&s->mutex);
-               err("set_interface failed");
+               dev_err(&s->usbdev->dev, "set_interface failed\n");
                return -EINVAL;
        }
        s->opened = 1;
@@ -648,7 +664,7 @@ static int dabusb_release (struct inode *inode, struct file *file)
 
        if (!s->remove_pending) {
                if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0)
-                       err("set_interface failed");
+                       dev_err(&s->usbdev->dev, "set_interface failed\n");
        }
        else
                wake_up (&s->remove_ok);
@@ -657,7 +673,7 @@ static int dabusb_release (struct inode *inode, struct file *file)
        return 0;
 }
 
-static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long dabusb_ioctl (struct file *file, unsigned int cmd, unsigned long arg)
 {
        pdabusb_t s = (pdabusb_t) file->private_data;
        pbulk_transfer_t pbulk;
@@ -666,13 +682,17 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm
 
        dbg("dabusb_ioctl");
 
-       if (s->remove_pending)
+       lock_kernel();
+       if (s->remove_pending) {
+               unlock_kernel();
                return -EIO;
+       }
 
        mutex_lock(&s->mutex);
 
        if (!s->usbdev) {
                mutex_unlock(&s->mutex);
+               unlock_kernel();
                return -EIO;
        }
 
@@ -713,6 +733,7 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm
                break;
        }
        mutex_unlock(&s->mutex);
+       unlock_kernel();
        return ret;
 }
 
@@ -721,7 +742,7 @@ static const struct file_operations dabusb_fops =
        .owner =        THIS_MODULE,
        .llseek =       no_llseek,
        .read =         dabusb_read,
-       .ioctl =        dabusb_ioctl,
+       .unlocked_ioctl =       dabusb_ioctl,
        .open =         dabusb_open,
        .release =      dabusb_release,
 };
@@ -764,7 +785,7 @@ static int dabusb_probe (struct usb_interface *intf,
        s->devnum = intf->minor;
 
        if (usb_reset_configuration (usbdev) < 0) {
-               err("reset_configuration failed");
+               dev_err(&intf->dev, "reset_configuration failed\n");
                goto reject;
        }
        if (le16_to_cpu(usbdev->descriptor.idProduct) == 0x2131) {
@@ -775,7 +796,7 @@ static int dabusb_probe (struct usb_interface *intf,
                dabusb_fpga_download (s, NULL);
 
                if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) {
-                       err("set_interface failed");
+                       dev_err(&intf->dev, "set_interface failed\n");
                        goto reject;
                }
        }
index f132e31f6edd8c4bcd7e7262739255437195ec5e..0131322475bfa4792619ac0b0cdb881a36035843 100644 (file)
@@ -56,7 +56,7 @@ MODULE_PARM_DESC(debug, "activates debug info");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 
-static int em28xx_isoc_audio_deinit(struct em28xx *dev)
+static int em28xx_deinit_isoc_audio(struct em28xx *dev)
 {
        int i;
 
@@ -66,6 +66,7 @@ static int em28xx_isoc_audio_deinit(struct em28xx *dev)
                        usb_kill_urb(dev->adev.urb[i]);
                else
                        usb_unlink_urb(dev->adev.urb[i]);
+
                usb_free_urb(dev->adev.urb[i]);
                dev->adev.urb[i] = NULL;
 
@@ -87,6 +88,20 @@ static void em28xx_audio_isocirq(struct urb *urb)
        unsigned int             stride;
        struct snd_pcm_substream *substream;
        struct snd_pcm_runtime   *runtime;
+
+       switch (urb->status) {
+       case 0:             /* success */
+       case -ETIMEDOUT:    /* NAK */
+               break;
+       case -ECONNRESET:   /* kill */
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+       default:            /* error */
+               dprintk("urb completition error %d.\n", urb->status);
+               break;
+       }
+
        if (dev->adev.capture_pcm_substream) {
                substream = dev->adev.capture_pcm_substream;
                runtime = substream->runtime;
@@ -137,9 +152,6 @@ static void em28xx_audio_isocirq(struct urb *urb)
        }
        urb->status = 0;
 
-       if (dev->adev.shutdown)
-               return;
-
        status = usb_submit_urb(urb, GFP_ATOMIC);
        if (status < 0) {
                em28xx_errdev("resubmit of audio urb failed (error=%i)\n",
@@ -197,8 +209,7 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
        for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
                errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
                if (errCode) {
-                       em28xx_isoc_audio_deinit(dev);
-
+                       em28xx_deinit_isoc_audio(dev);
                        return errCode;
                }
        }
@@ -213,14 +224,16 @@ static int em28xx_cmd(struct em28xx *dev, int cmd, int arg)
 
        switch (cmd) {
        case EM28XX_CAPTURE_STREAM_EN:
-               if (dev->adev.capture_stream == STREAM_OFF && arg == 1) {
+               if (dev->adev.capture_stream == STREAM_OFF &&
+                   arg == EM28XX_START_AUDIO) {
                        dev->adev.capture_stream = STREAM_ON;
                        em28xx_init_audio_isoc(dev);
-               } else if (dev->adev.capture_stream == STREAM_ON && arg == 0) {
+               } else if (dev->adev.capture_stream == STREAM_ON &&
+                          arg == EM28XX_STOP_AUDIO) {
                        dev->adev.capture_stream = STREAM_OFF;
-                       em28xx_isoc_audio_deinit(dev);
+                       em28xx_deinit_isoc_audio(dev);
                } else {
-                       printk(KERN_ERR "An underrun very likely occurred. "
+                       em28xx_errdev("An underrun very likely occurred. "
                                        "Ignoring it.\n");
                }
                return 0;
@@ -234,7 +247,7 @@ static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
 {
        struct snd_pcm_runtime *runtime = subs->runtime;
 
-       dprintk("Alocating vbuffer\n");
+       dprintk("Allocating vbuffer\n");
        if (runtime->dma_area) {
                if (runtime->dma_bytes > size)
                        return 0;
@@ -302,7 +315,9 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
                dprintk("changing alternate number to 7\n");
        }
 
+       mutex_lock(&dev->lock);
        dev->adev.users++;
+       mutex_unlock(&dev->lock);
 
        snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
        dev->adev.capture_pcm_substream = substream;
@@ -317,22 +332,15 @@ err:
 static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
 {
        struct em28xx *dev = snd_pcm_substream_chip(substream);
-       dev->adev.users--;
 
        dprintk("closing device\n");
 
        dev->mute = 1;
        mutex_lock(&dev->lock);
+       dev->adev.users--;
        em28xx_audio_analog_set(dev);
        mutex_unlock(&dev->lock);
 
-       if (dev->adev.users == 0 && dev->adev.shutdown == 1) {
-               dprintk("audio users: %d\n", dev->adev.users);
-               dprintk("disabling audio stream!\n");
-               dev->adev.shutdown = 0;
-               dprintk("released lock\n");
-               em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0);
-       }
        return 0;
 }
 
@@ -363,7 +371,7 @@ static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream)
        dprintk("Stop capture, if needed\n");
 
        if (dev->adev.capture_stream == STREAM_ON)
-               em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0);
+               em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, EM28XX_STOP_AUDIO);
 
        return 0;
 }
@@ -377,33 +385,40 @@ static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
                                      int cmd)
 {
        struct em28xx *dev = snd_pcm_substream_chip(substream);
+       int retval;
 
-       dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START)?
-                                      "start": "stop");
+       dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START) ?
+                                      "start" : "stop");
+
+       spin_lock(&dev->adev.slock);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 1);
-               return 0;
+               em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, EM28XX_START_AUDIO);
+               retval = 0;
+               break;
        case SNDRV_PCM_TRIGGER_STOP:
-               dev->adev.shutdown = 1;
-               return 0;
+               em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, EM28XX_STOP_AUDIO);
+               retval = 0;
+               break;
        default:
-               return -EINVAL;
+               retval = -EINVAL;
        }
+
+       spin_unlock(&dev->adev.slock);
+       return retval;
 }
 
 static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
                                                    *substream)
 {
-       unsigned long flags;
-
+       unsigned long flags;
        struct em28xx *dev;
        snd_pcm_uframes_t hwptr_done;
 
        dev = snd_pcm_substream_chip(substream);
-       spin_lock_irqsave(&dev->adev.slock, flags);
+       spin_lock_irqsave(&dev->adev.slock, flags);
        hwptr_done = dev->adev.hwptr_done_capture;
-       spin_unlock_irqrestore(&dev->adev.slock, flags);
+       spin_unlock_irqrestore(&dev->adev.slock, flags);
 
        return hwptr_done;
 }
index 3b3ca3f46d52e1f78e67a94dc831d0565be92dd4..0f48c0ff5ac399e14a0e8d9c8ca137fec0d681ec 100644 (file)
@@ -122,6 +122,22 @@ static struct em28xx_reg_seq default_tuner_gpio[] = {
        {  -1,                  -1,             -1,             -1},
 };
 
+/* Mute/unmute */
+static struct em28xx_reg_seq compro_unmute_tv_gpio[] = {
+       {EM28XX_R08_GPIO,       5,              7,              10},
+       {  -1,                  -1,             -1,             -1},
+};
+
+static struct em28xx_reg_seq compro_unmute_svid_gpio[] = {
+       {EM28XX_R08_GPIO,       4,              7,              10},
+       {  -1,                  -1,             -1,             -1},
+};
+
+static struct em28xx_reg_seq compro_mute_gpio[] = {
+       {EM28XX_R08_GPIO,       6,              7,              10},
+       {  -1,                  -1,             -1,             -1},
+};
+
 /*
  *  Board definitions
  */
@@ -183,6 +199,25 @@ struct em28xx_board em28xx_boards[] = {
                        .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
+       [EM2820_BOARD_GADMEI_TVR200] = {
+               .name         = "Gadmei TVR200",
+               .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+               .tda9887_conf = TDA9887_PRESENT,
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = SAA7115_COMPOSITE2,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               }, {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = SAA7115_COMPOSITE0,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = SAA7115_SVIDEO3,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               } },
+       },
        [EM2820_BOARD_TERRATEC_CINERGY_250] = {
                .name         = "Terratec Cinergy 250 USB",
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
@@ -225,7 +260,7 @@ struct em28xx_board em28xx_boards[] = {
                .name         = "Hauppauge WinTV USB 2",
                .tuner_type   = TUNER_PHILIPS_FM1236_MK3,
                .tda9887_conf = TDA9887_PRESENT |
-                               TDA9887_PORT1_ACTIVE|
+                               TDA9887_PORT1_ACTIVE |
                                TDA9887_PORT2_ACTIVE,
                .decoder      = EM28XX_TVP5150,
                .has_msp34xx  = 1,
@@ -350,26 +385,6 @@ struct em28xx_board em28xx_boards[] = {
                        .amux     = EM28XX_AMUX_VIDEO,
                } },
        },
-       [EM2821_BOARD_PROLINK_PLAYTV_USB2] = {
-               .name         = "SIIG AVTuner-PVR/Prolink PlayTV USB 2.0",
-               .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .tuner_type   = TUNER_LG_PAL_NEW_TAPC,  /* unknown? */
-               .tda9887_conf = TDA9887_PRESENT,        /* unknown? */
-               .decoder      = EM28XX_SAA711X,
-               .input        = { {
-                       .type     = EM28XX_VMUX_TELEVISION,
-                       .vmux     = SAA7115_COMPOSITE2,
-                       .amux     = EM28XX_AMUX_LINE_IN,
-               }, {
-                       .type     = EM28XX_VMUX_COMPOSITE1,
-                       .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = EM28XX_AMUX_LINE_IN,
-               }, {
-                       .type     = EM28XX_VMUX_SVIDEO,
-                       .vmux     = SAA7115_SVIDEO3,
-                       .amux     = EM28XX_AMUX_LINE_IN,
-               } },
-       },
        [EM2821_BOARD_SUPERCOMP_USB_2] = {
                .name         = "Supercomp USB 2.0 TV",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
@@ -498,7 +513,7 @@ struct em28xx_board em28xx_boards[] = {
        },
        [EM2861_BOARD_YAKUMO_MOVIE_MIXER] = {
                .name          = "Yakumo MovieMixer",
-               .tuner_type   = TUNER_ABSENT,   /* Capture only device */
+               .tuner_type    = TUNER_ABSENT,  /* Capture only device */
                .decoder       = EM28XX_TVP5150,
                .input         = { {
                        .type     = EM28XX_VMUX_TELEVISION,
@@ -604,6 +619,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,
                .decoder      = EM28XX_TVP5150,
                .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
@@ -628,6 +644,7 @@ struct em28xx_board em28xx_boards[] = {
                .tuner_type   = TUNER_XC2028,
                .tuner_gpio   = default_tuner_gpio,
                .mts_firmware = 1,
+               .ir_codes     = ir_codes_hauppauge_new,
                .decoder      = EM28XX_TVP5150,
                .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
@@ -842,11 +859,11 @@ struct em28xx_board em28xx_boards[] = {
                } },
        },
        [EM2800_BOARD_GRABBEEX_USB2800] = {
-               .name         = "eMPIA Technology, Inc. GrabBeeX+ Video Encoder",
-               .is_em2800    = 1,
-               .decoder      = EM28XX_SAA711X,
-               .tuner_type   = TUNER_ABSENT, /* capture only board */
-               .input        = { {
+               .name       = "eMPIA Technology, Inc. GrabBeeX+ Video Encoder",
+               .is_em2800  = 1,
+               .decoder    = EM28XX_SAA711X,
+               .tuner_type = TUNER_ABSENT, /* capture only board */
+               .input      = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
                        .amux     = EM28XX_AMUX_LINE_IN,
@@ -897,7 +914,7 @@ struct em28xx_board em28xx_boards[] = {
                } },
        },
        [EM2820_BOARD_PINNACLE_DVC_90] = {
-               .name         = "Pinnacle Dazzle DVC 90/DVC 100",
+               .name         = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker",
                .tuner_type   = TUNER_ABSENT, /* capture only board */
                .decoder      = EM28XX_SAA711X,
                .input        = { {
@@ -952,7 +969,7 @@ struct em28xx_board em28xx_boards[] = {
                } },
        },
        [EM2820_BOARD_PROLINK_PLAYTV_USB2] = {
-               .name         = "Pixelview Prolink PlayTV USB 2.0",
+               .name         = "SIIG AVTuner-PVR / Pixelview Prolink PlayTV USB 2.0",
                .has_snapshot_button = 1,
                .tda9887_conf = TDA9887_PRESENT,
                .tuner_type   = TUNER_YMEC_TVF_5533MF,
@@ -1198,7 +1215,9 @@ struct em28xx_board em28xx_boards[] = {
                .has_dvb      = 1,
                .dvb_gpio     = kworld_330u_digital,
                .xclk             = EM28XX_XCLK_FREQUENCY_12MHZ,
-               .i2c_speed        = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_EEPROM_ON_BOARD | EM28XX_I2C_EEPROM_KEY_VALID,
+               .i2c_speed        = EM28XX_I2C_CLK_WAIT_ENABLE |
+                                   EM28XX_I2C_EEPROM_ON_BOARD |
+                                   EM28XX_I2C_EEPROM_KEY_VALID,
                .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
@@ -1223,21 +1242,88 @@ struct em28xx_board em28xx_boards[] = {
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
                .tda9887_conf = TDA9887_PRESENT,
                .decoder      = EM28XX_TVP5150,
+               .adecoder     = EM28XX_TVAUDIO,
+               .mute_gpio    = compro_mute_gpio,
                .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = compro_unmute_tv_gpio,
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = TVP5150_SVIDEO,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = compro_unmute_svid_gpio,
+               } },
+       },
+       [EM2860_BOARD_KAIOMY_TVNPC_U2] = {
+               .name         = "Kaiomy TVnPC U2",
+               .vchannels    = 3,
+               .tuner_type   = TUNER_XC2028,
+               .tuner_addr   = 0x61,
+               .mts_firmware = 1,
+               .decoder      = EM28XX_TVP5150,
+               .tuner_gpio   = default_tuner_gpio,
+               .ir_codes     = ir_codes_kaiomy,
+               .input          = { {
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = TVP5150_COMPOSITE0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+
+               }, {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = TVP5150_COMPOSITE1,
                        .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
                        .amux     = EM28XX_AMUX_LINE_IN,
                } },
+               .radio          = {
+                       .type     = EM28XX_RADIO,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               }
+       },
+       [EM2860_BOARD_EASYCAP] = {
+               .name         = "Easy Cap Capture DC-60",
+               .vchannels    = 2,
+               .tuner_type   = TUNER_ABSENT,
+               .decoder      = EM28XX_SAA711X,
+               .input           = { {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = SAA7115_COMPOSITE0,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = SAA7115_SVIDEO3,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               } },
+       },
+       [EM2820_BOARD_IODATA_GVMVP_SZ] = {
+               .name       = "IO-DATA GV-MVP/SZ",
+               .tuner_type   = TUNER_PHILIPS_FM1236_MK3,
+               .tuner_gpio   = default_tuner_gpio,
+               .tda9887_conf = TDA9887_PRESENT,
+               .decoder      = EM28XX_TVP5150,
+               .input        = { {
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = TVP5150_COMPOSITE0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+               }, { /* Composite has not been tested yet */
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = TVP5150_COMPOSITE1,
+                       .amux     = EM28XX_AMUX_VIDEO,
+               }, { /* S-video has not been tested yet */
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = TVP5150_SVIDEO,
+                       .amux     = EM28XX_AMUX_VIDEO,
+               } },
        },
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
 /* table of devices that work with this driver */
-struct usb_device_id em28xx_id_table [] = {
+struct usb_device_id em28xx_id_table[] = {
        { USB_DEVICE(0xeb1a, 0x2750),
                        .driver_info = EM2750_BOARD_UNKNOWN },
        { USB_DEVICE(0xeb1a, 0x2751),
@@ -1260,6 +1346,8 @@ struct usb_device_id em28xx_id_table [] = {
                        .driver_info = EM2820_BOARD_UNKNOWN },
        { USB_DEVICE(0xeb1a, 0xe300),
                        .driver_info = EM2861_BOARD_KWORLD_PVRTV_300U },
+       { USB_DEVICE(0xeb1a, 0xe303),
+                       .driver_info = EM2860_BOARD_KAIOMY_TVNPC_U2 },
        { USB_DEVICE(0xeb1a, 0xe305),
                        .driver_info = EM2880_BOARD_KWORLD_DVB_305U },
        { USB_DEVICE(0xeb1a, 0xe310),
@@ -1278,6 +1366,8 @@ struct usb_device_id em28xx_id_table [] = {
                        .driver_info = EM2800_BOARD_GRABBEEX_USB2800 },
        { USB_DEVICE(0xeb1a, 0xe357),
                        .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(0x0ccd, 0x0036),
                        .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
        { USB_DEVICE(0x0ccd, 0x004c),
@@ -1330,6 +1420,8 @@ struct usb_device_id em28xx_id_table [] = {
                        .driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII },
        { USB_DEVICE(0x093b, 0xa005),
                        .driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U },
+       { USB_DEVICE(0x04bb, 0x0515),
+                       .driver_info = EM2820_BOARD_IODATA_GVMVP_SZ },
        { },
 };
 MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -1337,7 +1429,7 @@ MODULE_DEVICE_TABLE(usb, em28xx_id_table);
 /*
  * EEPROM hash table for devices with generic USB IDs
  */
-static struct em28xx_hash_table em28xx_eeprom_hash [] = {
+static struct em28xx_hash_table em28xx_eeprom_hash[] = {
        /* P/N: SA 60002070465 Tuner: TVF7533-MF */
        {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
        {0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF},
@@ -1349,6 +1441,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
        {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC},
        {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
        {0x1ba50080, EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA, TUNER_ABSENT},
+       {0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC},
 };
 
 int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
@@ -1368,7 +1461,7 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
 }
 EXPORT_SYMBOL_GPL(em28xx_tuner_callback);
 
-static void inline em28xx_set_model(struct em28xx *dev)
+static inline void em28xx_set_model(struct em28xx *dev)
 {
        memcpy(&dev->board, &em28xx_boards[dev->model], sizeof(dev->board));
 
@@ -1504,6 +1597,34 @@ void em28xx_pre_card_setup(struct em28xx *dev)
                /* enables audio for that devices */
                em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
                break;
+
+       case EM2860_BOARD_KAIOMY_TVNPC_U2:
+               em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1);
+               em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
+               em28xx_write_regs(dev, 0x0d, "\x42", 1);
+               em28xx_write_regs(dev, 0x08, "\xfd", 1);
+               msleep(10);
+               em28xx_write_regs(dev, 0x08, "\xff", 1);
+               msleep(10);
+               em28xx_write_regs(dev, 0x08, "\x7f", 1);
+               msleep(10);
+               em28xx_write_regs(dev, 0x08, "\x6b", 1);
+
+               break;
+       case EM2860_BOARD_EASYCAP:
+               em28xx_write_regs(dev, 0x08, "\xf8", 1);
+               break;
+
+       case EM2820_BOARD_IODATA_GVMVP_SZ:
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+               msleep(70);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7);
+               msleep(10);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+               msleep(70);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+               msleep(70);
+               break;
        }
 
        em28xx_gpio_set(dev, dev->board.tuner_gpio);
@@ -1610,7 +1731,7 @@ static int em28xx_hint_board(struct em28xx *dev)
                        em28xx_errdev("If the board were missdetected, "
                                      "please email this log to:\n");
                        em28xx_errdev("\tV4L Mailing List "
-                                     " <video4linux-list@redhat.com>\n");
+                                     " <linux-media@vger.kernel.org>\n");
                        em28xx_errdev("Board detected as %s\n",
                                      em28xx_boards[dev->model].name);
 
@@ -1642,7 +1763,7 @@ static int em28xx_hint_board(struct em28xx *dev)
                        em28xx_errdev("If the board were missdetected, "
                                      "please email this log to:\n");
                        em28xx_errdev("\tV4L Mailing List "
-                                     " <video4linux-list@redhat.com>\n");
+                                     " <linux-media@vger.kernel.org>\n");
                        em28xx_errdev("Board detected as %s\n",
                                      em28xx_boards[dev->model].name);
 
@@ -1655,7 +1776,7 @@ static int em28xx_hint_board(struct em28xx *dev)
        em28xx_errdev("You may try to use card=<n> insmod option to "
                      "workaround that.\n");
        em28xx_errdev("Please send an email with this log to:\n");
-       em28xx_errdev("\tV4L Mailing List <video4linux-list@redhat.com>\n");
+       em28xx_errdev("\tV4L Mailing List <linux-media@vger.kernel.org>\n");
        em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash);
        em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash);
 
@@ -1800,6 +1921,8 @@ void em28xx_card_setup(struct em28xx *dev)
                request_module("tvp5150");
        if (dev->board.tuner_type != TUNER_ABSENT)
                request_module("tuner");
+       if (dev->board.adecoder == EM28XX_TVAUDIO)
+               request_module("tvaudio");
 #endif
 
        em28xx_config_tuner(dev);
index 94fb1b639a2e4c52762544a0cefb34b9486909b4..8f1999ca4803925f0cc78fdcae0877dfb2108305 100644 (file)
@@ -33,8 +33,8 @@
 /* #define ENABLE_DEBUG_ISOC_FRAMES */
 
 static unsigned int core_debug;
-module_param(core_debug,int,0644);
-MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+module_param(core_debug, int, 0644);
+MODULE_PARM_DESC(core_debug, "enable debug messages [core]");
 
 #define em28xx_coredbg(fmt, arg...) do {\
        if (core_debug) \
@@ -42,8 +42,8 @@ MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
                         dev->name, __func__ , ##arg); } while (0)
 
 static unsigned int reg_debug;
-module_param(reg_debug,int,0644);
-MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");
+module_param(reg_debug, int, 0644);
+MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
 
 #define em28xx_regdbg(fmt, arg...) do {\
        if (reg_debug) \
@@ -77,7 +77,7 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
                return -EINVAL;
 
        if (reg_debug) {
-               printk( KERN_DEBUG "(pipe 0x%08x): "
+               printk(KERN_DEBUG "(pipe 0x%08x): "
                        "IN:  %02x %02x %02x %02x %02x %02x %02x %02x ",
                        pipe,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
@@ -154,7 +154,7 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
        if (reg_debug) {
                int byte;
 
-               printk( KERN_DEBUG "(pipe 0x%08x): "
+               printk(KERN_DEBUG "(pipe 0x%08x): "
                        "OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>",
                        pipe,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
@@ -378,6 +378,11 @@ static int em28xx_set_audio_source(struct em28xx *dev)
                }
        }
 
+       if (dev->board.mute_gpio && dev->mute)
+               em28xx_gpio_set(dev, dev->board.mute_gpio);
+       else
+               em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio);
+
        ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0);
        if (ret < 0)
                return ret;
@@ -424,7 +429,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
 
        xclk = dev->board.xclk & 0x7f;
        if (!dev->mute)
-               xclk |= 0x80;
+               xclk |= EM28XX_XCLK_AUDIO_UNMUTE;
 
        ret = em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk);
        if (ret < 0)
@@ -462,7 +467,8 @@ int em28xx_audio_analog_set(struct em28xx *dev)
                if (dev->ctl_aoutput & EM28XX_AOUT_PCM_IN) {
                        int sel = ac97_return_record_select(dev->ctl_aoutput);
 
-                       /* Use the same input for both left and right channels */
+                       /* Use the same input for both left and right
+                          channels */
                        sel |= (sel << 8);
 
                        em28xx_write_ac97(dev, AC97_RECORD_SELECT, sel);
@@ -698,7 +704,7 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
                em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
                /* it seems that both H and V scalers must be active
                   to work correctly */
-               mode = (h || v)? 0x30: 0x00;
+               mode = (h || v) ? 0x30 : 0x00;
        }
        return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
 }
@@ -827,6 +833,19 @@ static void em28xx_irq_callback(struct urb *urb)
        struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
        int rc, i;
 
+       switch (urb->status) {
+       case 0:             /* success */
+       case -ETIMEDOUT:    /* NAK */
+               break;
+       case -ECONNRESET:   /* kill */
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+       default:            /* error */
+               em28xx_isocdbg("urb completition error %d.\n", urb->status);
+               break;
+       }
+
        /* Copy data from URB */
        spin_lock(&dev->slock);
        rc = dev->isoc_ctl.isoc_copy(dev, urb);
@@ -945,7 +964,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
                        em28xx_err("unable to allocate %i bytes for transfer"
                                        " buffer %i%s\n",
                                        sb_size, i,
-                                       in_interrupt()?" while in int":"");
+                                       in_interrupt() ? " while in int" : "");
                        em28xx_uninit_isoc(dev);
                        return -ENOMEM;
                }
@@ -963,7 +982,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
                                 em28xx_irq_callback, dma_q, 1);
 
                urb->number_of_packets = max_packets;
-               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
 
                k = 0;
                for (j = 0; j < max_packets; j++) {
index 9ad8527b3fda0b15c005edbe4ace40492687fde5..fcd25511209bc985f7273f057340a1bf07c6f5d2 100644 (file)
@@ -29,9 +29,6 @@
 #include "lgdt330x.h"
 #include "zl10353.h"
 #include "s5h1409.h"
-#ifdef EM28XX_DRX397XD_SUPPORT
-#include "drx397xD.h"
-#endif
 
 MODULE_DESCRIPTION("driver for em28xx based DVB cards");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
index d69f0efcc9aad821101d431b8c5a3afc1177da07..02c12fe6361be60834745e8e76c1b87e1f42873e 100644 (file)
@@ -402,10 +402,12 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
                                 dev->name);
                break;
        case 2:
-               printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n", dev->name);
+               printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n",
+                                dev->name);
                break;
        case 3:
-               printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n", dev->name);
+               printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n",
+                                dev->name);
                break;
        }
 
@@ -508,12 +510,17 @@ static int attach_inform(struct i2c_client *client)
                dprintk1(1, "attach_inform: tvp5150 detected.\n");
                break;
 
+       case 0xb0:
+               dprintk1(1, "attach_inform: tda9874 detected\n");
+               break;
+
        default:
                if (!dev->tuner_addr)
                        dev->tuner_addr = client->addr;
 
                dprintk1(1, "attach inform: detected I2C address %x\n",
                                client->addr << 1);
+               dprintk1(1, "driver id %d\n", client->driver->id);
 
        }
 
@@ -552,6 +559,7 @@ static char *i2c_devs[128] = {
        [0x80 >> 1] = "msp34xx",
        [0x88 >> 1] = "msp34xx",
        [0xa0 >> 1] = "eeprom",
+       [0xb0 >> 1] = "tda9874",
        [0xb8 >> 1] = "tvp5150a",
        [0xba >> 1] = "tvp5150a",
        [0xc0 >> 1] = "tuner (analog)",
index 0443afe09ff86deb4bc8315a90dc0f32fd231d6b..a5abfd7a19f577d4e00bd4bbaf42f647641b9385 100644 (file)
@@ -68,8 +68,7 @@ struct em28xx_IR {
 
        /* poll external decoder */
        int polling;
-       struct work_struct work;
-       struct timer_list timer;
+       struct delayed_work work;
        unsigned int last_toggle:1;
        unsigned int last_readcount;
        unsigned int repeat_interval;
@@ -292,32 +291,23 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
        return;
 }
 
-static void ir_timer(unsigned long data)
-{
-       struct em28xx_IR *ir = (struct em28xx_IR *)data;
-
-       schedule_work(&ir->work);
-}
-
 static void em28xx_ir_work(struct work_struct *work)
 {
-       struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work);
+       struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work);
 
        em28xx_ir_handle_key(ir);
-       mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
+       schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
 }
 
 static void em28xx_ir_start(struct em28xx_IR *ir)
 {
-       setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
-       INIT_WORK(&ir->work, em28xx_ir_work);
-       schedule_work(&ir->work);
+       INIT_DELAYED_WORK(&ir->work, em28xx_ir_work);
+       schedule_delayed_work(&ir->work, 0);
 }
 
 static void em28xx_ir_stop(struct em28xx_IR *ir)
 {
-       del_timer_sync(&ir->timer);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&ir->work);
 }
 
 int em28xx_ir_init(struct em28xx *dev)
index 8e61b2ca9167810b3b8db9f6f7b982be41bd369e..575472f1e7029ffcce9797354d8fb1c8ae797e63 100644 (file)
@@ -186,7 +186,8 @@ static void em28xx_copy_video(struct em28xx *dev,
                em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
                               ((char *)startwrite + lencopy) -
                               ((char *)outp + buf->vb.size));
-               lencopy = remain = (char *)outp + buf->vb.size - (char *)startwrite;
+               remain = (char *)outp + buf->vb.size - (char *)startwrite;
+               lencopy = remain;
        }
        if (lencopy <= 0)
                return;
@@ -202,7 +203,8 @@ static void em28xx_copy_video(struct em28xx *dev,
                else
                        lencopy = bytesperline;
 
-               if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+               if ((char *)startwrite + lencopy > (char *)outp +
+                   buf->vb.size) {
                        em28xx_isocdbg("Overflow of %zi bytes past buffer end (2)\n",
                                       ((char *)startwrite + lencopy) -
                                       ((char *)outp + buf->vb.size));
@@ -347,7 +349,7 @@ static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
                }
                if (p[0] == 0x22 && p[1] == 0x5a) {
                        em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
-                                      len, (p[2] & 1)? "odd" : "even");
+                                      len, (p[2] & 1) ? "odd" : "even");
 
                        if (!(p[2] & 1)) {
                                if (buf != NULL)
@@ -476,7 +478,9 @@ fail:
 static void
 buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 {
-       struct em28xx_buffer    *buf     = container_of(vb, struct em28xx_buffer, vb);
+       struct em28xx_buffer    *buf     = container_of(vb,
+                                                       struct em28xx_buffer,
+                                                       vb);
        struct em28xx_fh        *fh      = vq->priv_data;
        struct em28xx           *dev     = fh->dev;
        struct em28xx_dmaqueue  *vidq    = &dev->vidq;
@@ -489,7 +493,9 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 static void buffer_release(struct videobuf_queue *vq,
                                struct videobuf_buffer *vb)
 {
-       struct em28xx_buffer   *buf  = container_of(vb, struct em28xx_buffer, vb);
+       struct em28xx_buffer   *buf  = container_of(vb,
+                                                   struct em28xx_buffer,
+                                                   vb);
        struct em28xx_fh       *fh   = vq->priv_data;
        struct em28xx          *dev  = (struct em28xx *)fh->dev;
 
@@ -534,6 +540,13 @@ static void video_mux(struct em28xx *dev, int index)
                        &route);
        }
 
+       if (dev->board.adecoder != EM28XX_NOADECODER) {
+               route.input = dev->ctl_ainput;
+               route.output = dev->ctl_aoutput;
+               em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING,
+                       &route);
+       }
+
        em28xx_audio_analog_set(dev);
 }
 
@@ -557,7 +570,7 @@ static int res_get(struct em28xx_fh *fh)
 
 static int res_check(struct em28xx_fh *fh)
 {
-       return (fh->stream_on);
+       return fh->stream_on;
 }
 
 static void res_free(struct em28xx_fh *fh)
@@ -791,7 +804,7 @@ out:
        return rc;
 }
 
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
 {
        struct em28xx_fh   *fh  = priv;
        struct em28xx      *dev = fh->dev;
@@ -1008,8 +1021,13 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 
        if (dev->board.has_msp34xx)
                em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl);
-       else
+       else {
                rc = em28xx_get_ctrl(dev, ctrl);
+               if (rc < 0) {
+                       em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl);
+                       rc = 0;
+               }
+       }
 
        mutex_unlock(&dev->lock);
        return rc;
@@ -1345,7 +1363,7 @@ static int vidioc_querycap(struct file *file, void  *priv,
 
        strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
        strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
-       strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info));
+       usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
 
        cap->version = EM28XX_VERSION_CODE;
 
@@ -1431,7 +1449,7 @@ static int vidioc_reqbufs(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       return (videobuf_reqbufs(&fh->vb_vidq, rb));
+       return videobuf_reqbufs(&fh->vb_vidq, rb);
 }
 
 static int vidioc_querybuf(struct file *file, void *priv,
@@ -1445,7 +1463,7 @@ static int vidioc_querybuf(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       return (videobuf_querybuf(&fh->vb_vidq, b));
+       return videobuf_querybuf(&fh->vb_vidq, b);
 }
 
 static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1458,7 +1476,7 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
        if (rc < 0)
                return rc;
 
-       return (videobuf_qbuf(&fh->vb_vidq, b));
+       return videobuf_qbuf(&fh->vb_vidq, b);
 }
 
 static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1471,8 +1489,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
        if (rc < 0)
                return rc;
 
-       return (videobuf_dqbuf(&fh->vb_vidq, b,
-                               file->f_flags & O_NONBLOCK));
+       return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
 }
 
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -1496,7 +1513,7 @@ static int radio_querycap(struct file *file, void  *priv,
 
        strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
        strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
-       strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info));
+       usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
 
        cap->version = EM28XX_VERSION_CODE;
        cap->capabilities = V4L2_CAP_TUNER;
@@ -1781,7 +1798,7 @@ em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
  * em28xx_v4l2_poll()
  * will allocate buffers when called for the first time
  */
-static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
+static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait)
 {
        struct em28xx_fh *fh = filp->private_data;
        struct em28xx *dev = fh->dev;
@@ -1934,8 +1951,8 @@ static struct video_device em28xx_radio_template = {
 
 
 static struct video_device *em28xx_vdev_init(struct em28xx *dev,
-                                            const struct video_device *template,
-                                            const char *type_name)
+                                       const struct video_device *template,
+                                       const char *type_name)
 {
        struct video_device *vfd;
 
@@ -1984,8 +2001,9 @@ int em28xx_register_analog_devices(struct em28xx *dev)
        /* enable vbi capturing */
 
 /*     em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
-       val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK);
-       em28xx_write_reg(dev, EM28XX_R0F_XCLK, (EM28XX_XCLK_AUDIO_UNMUTE | val));
+       val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK);
+       em28xx_write_reg(dev, EM28XX_R0F_XCLK,
+                        (EM28XX_XCLK_AUDIO_UNMUTE | val));
        em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51);
 
        em28xx_set_outfmt(dev);
@@ -2020,7 +2038,8 @@ int em28xx_register_analog_devices(struct em28xx *dev)
        }
 
        if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
-               dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, "radio");
+               dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
+                                                 "radio");
                if (!dev->radio_dev) {
                        em28xx_errdev("cannot allocate video_device.\n");
                        return -ENODEV;
index dd2cd36fb1bbdcc1cab644e12b56b96e30d0041a..a33a58da016e708feb5adb9f9912a048452ed46d 100644 (file)
@@ -70,7 +70,6 @@
 #define EM2820_BOARD_VIDEOLOGY_20K14XUSB         30
 #define EM2821_BOARD_USBGEAR_VD204               31
 #define EM2821_BOARD_SUPERCOMP_USB_2             32
-#define EM2821_BOARD_PROLINK_PLAYTV_USB2         33
 #define EM2860_BOARD_TERRATEC_HYBRID_XS                  34
 #define EM2860_BOARD_TYPHOON_DVD_MAKER           35
 #define EM2860_BOARD_NETGMBH_CAM                 36
 #define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU     58
 #define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850     60
 #define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2    61
+#define EM2820_BOARD_GADMEI_TVR200               62
+#define EM2860_BOARD_KAIOMY_TVNPC_U2              63
+#define EM2860_BOARD_EASYCAP                      64
+#define EM2820_BOARD_IODATA_GVMVP_SZ             65
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
 #define EM28XX_BOARD_NOT_VALIDATED 1
 #define EM28XX_BOARD_VALIDATED    0
 
+/* Params for em28xx_cmd() audio */
+#define EM28XX_START_AUDIO      1
+#define EM28XX_STOP_AUDIO       0
+
 /* maximum number of em28xx boards */
 #define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */
 
 */
 
 /* time to wait when stopping the isoc transfer */
-#define EM28XX_URB_TIMEOUT       msecs_to_jiffies(EM28XX_NUM_BUFS * EM28XX_NUM_PACKETS)
+#define EM28XX_URB_TIMEOUT \
+                       msecs_to_jiffies(EM28XX_NUM_BUFS * EM28XX_NUM_PACKETS)
 
 /* time in msecs to wait for i2c writes to finish */
 #define EM2800_I2C_WRITE_TIMEOUT 20
@@ -348,6 +356,11 @@ enum em28xx_decoder {
        EM28XX_SAA711X,
 };
 
+enum em28xx_adecoder {
+       EM28XX_NOADECODER = 0,
+       EM28XX_TVAUDIO,
+};
+
 struct em28xx_board {
        char *name;
        int vchannels;
@@ -361,6 +374,7 @@ struct em28xx_board {
        struct em28xx_reg_seq *dvb_gpio;
        struct em28xx_reg_seq *suspend_gpio;
        struct em28xx_reg_seq *tuner_gpio;
+       struct em28xx_reg_seq *mute_gpio;
 
        unsigned int is_em2800:1;
        unsigned int has_msp34xx:1;
@@ -373,6 +387,7 @@ struct em28xx_board {
        unsigned char xclk, i2c_speed;
 
        enum em28xx_decoder decoder;
+       enum em28xx_adecoder adecoder;
 
        struct em28xx_input       input[MAX_EM28XX_INPUT];
        struct em28xx_input       radio;
@@ -420,7 +435,7 @@ struct em28xx_audio {
        unsigned int hwptr_done_capture;
        struct snd_card            *sndcard;
 
-       int users, shutdown;
+       int users;
        enum em28xx_stream_state capture_stream;
        spinlock_t slock;
 };
@@ -523,7 +538,8 @@ struct em28xx {
        int num_alt;            /* Number of alternative settings */
        unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
        struct urb *urb[EM28XX_NUM_BUFS];       /* urb for isoc transfers */
-       char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc transfer */
+       char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc
+                                                  transfer */
        char urb_buf[URB_MAX_CTRL_SIZE];        /* urb control msg buffer */
 
        /* helper funcs that call usb_control_msg */
index ee6a691dff229d9d597b5ac9cd1b101294872ab3..578dc4ffc9659454da44d548eb80dd5a0018e87b 100644 (file)
@@ -56,6 +56,15 @@ config USB_GSPCA_MARS
          To compile this driver as a module, choose M here: the
          module will be called gspca_mars.
 
+config USB_GSPCA_MR97310A
+       tristate "Mars-Semi MR97310A USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+         Say Y here if you want support for cameras based on the MR97310A chip.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_mr97310a.
+
 config USB_GSPCA_OV519
        tristate "OV519 USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
@@ -167,6 +176,24 @@ config USB_GSPCA_SPCA561
          To compile this driver as a module, choose M here: the
          module will be called gspca_spca561.
 
+config USB_GSPCA_SQ905
+       tristate "SQ Technologies SQ905 based USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+         Say Y here if you want support for cameras based on the SQ905 chip.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_sq905.
+
+config USB_GSPCA_SQ905C
+       tristate "SQ Technologies SQ905C based USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+         Say Y here if you want support for cameras based on the SQ905C chip.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_sq905c.
+
 config USB_GSPCA_STK014
        tristate "Syntek DV4000 (STK014) USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
index bd8d9ee405049624f4f417de1c99318ae95197c0..8a6643e8eb96d796ebaf6a02bf73d8e7306a0e7f 100644 (file)
@@ -1,50 +1,56 @@
-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_MARS)   += gspca_mars.o
-obj-$(CONFIG_USB_GSPCA_OV519)  += gspca_ov519.o
-obj-$(CONFIG_USB_GSPCA_OV534)  += gspca_ov534.o
-obj-$(CONFIG_USB_GSPCA_PAC207) += gspca_pac207.o
-obj-$(CONFIG_USB_GSPCA_PAC7311) += gspca_pac7311.o
-obj-$(CONFIG_USB_GSPCA_SONIXB) += gspca_sonixb.o
-obj-$(CONFIG_USB_GSPCA_SONIXJ) += gspca_sonixj.o
-obj-$(CONFIG_USB_GSPCA_SPCA500) += gspca_spca500.o
-obj-$(CONFIG_USB_GSPCA_SPCA501) += gspca_spca501.o
-obj-$(CONFIG_USB_GSPCA_SPCA505) += gspca_spca505.o
-obj-$(CONFIG_USB_GSPCA_SPCA506) += gspca_spca506.o
-obj-$(CONFIG_USB_GSPCA_SPCA508) += gspca_spca508.o
-obj-$(CONFIG_USB_GSPCA_SPCA561) += gspca_spca561.o
-obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o
-obj-$(CONFIG_USB_GSPCA_STK014) += gspca_stk014.o
-obj-$(CONFIG_USB_GSPCA_T613)   += gspca_t613.o
-obj-$(CONFIG_USB_GSPCA_TV8532) += gspca_tv8532.o
-obj-$(CONFIG_USB_GSPCA_VC032X) += gspca_vc032x.o
-obj-$(CONFIG_USB_GSPCA_ZC3XX)  += gspca_zc3xx.o
+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_MARS)     += gspca_mars.o
+obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o
+obj-$(CONFIG_USB_GSPCA_OV519)    += gspca_ov519.o
+obj-$(CONFIG_USB_GSPCA_OV534)    += gspca_ov534.o
+obj-$(CONFIG_USB_GSPCA_PAC207)   += gspca_pac207.o
+obj-$(CONFIG_USB_GSPCA_PAC7311)  += gspca_pac7311.o
+obj-$(CONFIG_USB_GSPCA_SONIXB)   += gspca_sonixb.o
+obj-$(CONFIG_USB_GSPCA_SONIXJ)   += gspca_sonixj.o
+obj-$(CONFIG_USB_GSPCA_SPCA500)  += gspca_spca500.o
+obj-$(CONFIG_USB_GSPCA_SPCA501)  += gspca_spca501.o
+obj-$(CONFIG_USB_GSPCA_SPCA505)  += gspca_spca505.o
+obj-$(CONFIG_USB_GSPCA_SPCA506)  += gspca_spca506.o
+obj-$(CONFIG_USB_GSPCA_SPCA508)  += gspca_spca508.o
+obj-$(CONFIG_USB_GSPCA_SPCA561)  += gspca_spca561.o
+obj-$(CONFIG_USB_GSPCA_SQ905)    += gspca_sq905.o
+obj-$(CONFIG_USB_GSPCA_SQ905C)   += gspca_sq905c.o
+obj-$(CONFIG_USB_GSPCA_SUNPLUS)  += gspca_sunplus.o
+obj-$(CONFIG_USB_GSPCA_STK014)   += gspca_stk014.o
+obj-$(CONFIG_USB_GSPCA_T613)     += gspca_t613.o
+obj-$(CONFIG_USB_GSPCA_TV8532)   += gspca_tv8532.o
+obj-$(CONFIG_USB_GSPCA_VC032X)   += gspca_vc032x.o
+obj-$(CONFIG_USB_GSPCA_ZC3XX)    += gspca_zc3xx.o
 
-gspca_main-objs                        := gspca.o
-gspca_conex-objs               := conex.o
-gspca_etoms-objs               := etoms.o
-gspca_finepix-objs             := finepix.o
-gspca_mars-objs                        := mars.o
-gspca_ov519-objs               := ov519.o
-gspca_ov534-objs               := ov534.o
-gspca_pac207-objs              := pac207.o
-gspca_pac7311-objs             := pac7311.o
-gspca_sonixb-objs              := sonixb.o
-gspca_sonixj-objs              := sonixj.o
-gspca_spca500-objs             := spca500.o
-gspca_spca501-objs             := spca501.o
-gspca_spca505-objs             := spca505.o
-gspca_spca506-objs             := spca506.o
-gspca_spca508-objs             := spca508.o
-gspca_spca561-objs             := spca561.o
-gspca_stk014-objs              := stk014.o
-gspca_sunplus-objs             := sunplus.o
-gspca_t613-objs                        := t613.o
-gspca_tv8532-objs              := tv8532.o
-gspca_vc032x-objs              := vc032x.o
-gspca_zc3xx-objs               := zc3xx.o
+gspca_main-objs     := gspca.o
+gspca_conex-objs    := conex.o
+gspca_etoms-objs    := etoms.o
+gspca_finepix-objs  := finepix.o
+gspca_mars-objs     := mars.o
+gspca_mr97310a-objs := mr97310a.o
+gspca_ov519-objs    := ov519.o
+gspca_ov534-objs    := ov534.o
+gspca_pac207-objs   := pac207.o
+gspca_pac7311-objs  := pac7311.o
+gspca_sonixb-objs   := sonixb.o
+gspca_sonixj-objs   := sonixj.o
+gspca_spca500-objs  := spca500.o
+gspca_spca501-objs  := spca501.o
+gspca_spca505-objs  := spca505.o
+gspca_spca506-objs  := spca506.o
+gspca_spca508-objs  := spca508.o
+gspca_spca561-objs  := spca561.o
+gspca_sq905-objs    := sq905.o
+gspca_sq905c-objs   := sq905c.o
+gspca_stk014-objs   := stk014.o
+gspca_sunplus-objs  := sunplus.o
+gspca_t613-objs     := t613.o
+gspca_tv8532-objs   := tv8532.o
+gspca_vc032x-objs   := vc032x.o
+gspca_zc3xx-objs    := zc3xx.o
 
-obj-$(CONFIG_USB_M5602)                += m5602/
-obj-$(CONFIG_USB_STV06XX)      += stv06xx/
+obj-$(CONFIG_USB_M5602)   += m5602/
+obj-$(CONFIG_USB_STV06XX) += stv06xx/
index 1753f5bb35444c7db2fba72d05016e2b06e36a2d..219cfa6fb877e2e20353bd0b160ac8933c8bc266 100644 (file)
@@ -36,8 +36,12 @@ struct sd {
        unsigned char brightness;
        unsigned char contrast;
        unsigned char colors;
+       u8 quality;
+#define QUALITY_MIN 30
+#define QUALITY_MAX 60
+#define QUALITY_DEF 40
 
-       unsigned char qindex;
+       u8 *jpeg_hdr;
 };
 
 /* V4L2 controls supported by the driver */
@@ -815,14 +819,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct cam *cam;
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 0x01;
        cam->cam_mode = vga_mode;
        cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
 
-       sd->qindex = 0;                 /* set the quantization */
        sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
        sd->colors = COLOR_DEF;
+       sd->quality = QUALITY_DEF;
        return 0;
 }
 
@@ -839,6 +842,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
 
 static int sd_start(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       /* create the JPEG header */
+       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+                       0x22);          /* JPEG 411 */
+       jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
        cx11646_initsize(gspca_dev);
        cx11646_fw(gspca_dev);
        cx_sensor(gspca_dev);
@@ -849,8 +860,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
 /* called on streamoff with alt 0 and on disconnect */
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
        int retry = 50;
 
+       kfree(sd->jpeg_hdr);
+
        if (!gspca_dev->present)
                return;
        reg_w_val(gspca_dev, 0x0000, 0x00);
@@ -876,6 +890,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        __u8 *data,                     /* isoc packet */
                        int len)                        /* iso packet length */
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+
        if (data[0] == 0xff && data[1] == 0xd8) {
 
                /* start of frame */
@@ -883,9 +899,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                                        data, 0);
 
                /* put the JPEG header in the new frame */
-               jpeg_put_header(gspca_dev, frame,
-                               ((struct sd *) gspca_dev)->qindex,
-                               0x22);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                       sd->jpeg_hdr, JPEG_HDR_SZ);
                data += 2;
                len -= 2;
        }
@@ -988,6 +1003,34 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (jcomp->quality < QUALITY_MIN)
+               sd->quality = QUALITY_MIN;
+       else if (jcomp->quality > QUALITY_MAX)
+               sd->quality = QUALITY_MAX;
+       else
+               sd->quality = jcomp->quality;
+       if (gspca_dev->streaming)
+               jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+       return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       memset(jcomp, 0, sizeof *jcomp);
+       jcomp->quality = sd->quality;
+       jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+                       | V4L2_JPEG_MARKER_DQT;
+       return 0;
+}
+
 /* sub-driver description */
 static struct sd_desc sd_desc = {
        .name = MODULE_NAME,
@@ -998,6 +1041,8 @@ static struct sd_desc sd_desc = {
        .start = sd_start,
        .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
+       .get_jcomp = sd_get_jcomp,
+       .set_jcomp = sd_set_jcomp,
 };
 
 /* -- module initialisation -- */
@@ -1029,8 +1074,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index f3cd8ff5cc923b07a4b97367bd5ee99b750127ba..2c20d06a03e8b7b009e0588cb20fe41d5e1e01c7 100644 (file)
@@ -472,19 +472,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
                reg_w_val(gspca_dev, ET_O_RED + i, brightness);
 }
 
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       int i;
-       int brightness = 0;
-
-       for (i = 0; i < 4; i++) {
-               reg_r(gspca_dev, ET_O_RED + i, 1);
-               brightness += gspca_dev->usb_buf[0];
-       }
-       sd->brightness = brightness >> 3;
-}
-
 static void setcontrast(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -495,19 +482,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
        reg_w(gspca_dev, ET_G_RED, RGBG, 6);
 }
 
-static void getcontrast(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       int i;
-       int contrast = 0;
-
-       for (i = 0; i < 4; i++) {
-               reg_r(gspca_dev, ET_G_RED + i, 1);
-               contrast += gspca_dev->usb_buf[0];
-       }
-       sd->contrast = contrast >> 2;
-}
-
 static void setcolors(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -658,7 +632,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct cam *cam;
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 1;
        sd->sensor = id->driver_info;
        if (sd->sensor == SENSOR_PAS106) {
                cam->cam_mode = sif_mode;
@@ -821,7 +794,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getbrightness(gspca_dev);
        *val = sd->brightness;
        return 0;
 }
@@ -840,7 +812,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getcontrast(gspca_dev);
        *val = sd->contrast;
        return 0;
 }
@@ -859,7 +830,6 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getcolors(gspca_dev);
        *val = sd->colors;
        return 0;
 }
@@ -928,8 +898,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index afc8b2dd307bb36df8b40886def1cdef96cb1dd8..00e6863ed66692d20581b88559041084fed917ad 100644 (file)
@@ -27,7 +27,7 @@ MODULE_DESCRIPTION("Fujifilm FinePix USB V4L2 driver");
 MODULE_LICENSE("GPL");
 
 /* Default timeout, in ms */
-#define FPIX_TIMEOUT (HZ / 10)
+#define FPIX_TIMEOUT 250
 
 /* Maximum transfer size to use. The windows driver reads by chunks of
  * 0x2000 bytes, so do the same. Note: reading more seems to work
@@ -38,38 +38,15 @@ MODULE_LICENSE("GPL");
 struct usb_fpix {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
-       /*
-        * USB stuff
-        */
-       struct usb_ctrlrequest ctrlreq;
-       struct urb *control_urb;
-       struct timer_list bulk_timer;
-
-       enum {
-               FPIX_NOP,       /* inactive, else streaming */
-               FPIX_RESET,     /* must reset */
-               FPIX_REQ_FRAME, /* requesting a frame */
-               FPIX_READ_FRAME,        /* reading frame */
-       } state;
-
-       /*
-        * Driver stuff
-        */
-       struct delayed_work wqe;
-       struct completion can_close;
-       int streaming;
+       struct work_struct work_struct;
+       struct workqueue_struct *work_thread;
 };
 
 /* Delay after which claim the next frame. If the delay is too small,
  * the camera will return old frames. On the 4800Z, 20ms is bad, 25ms
- * will fail every 4 or 5 frames, but 30ms is perfect. */
-#define NEXT_FRAME_DELAY  (((HZ * 30) + 999) / 1000)
-
-#define dev_new_state(new_state) {                             \
-               PDEBUG(D_STREAM, "new state from %d to %d at %s:%d",    \
-                       dev->state, new_state, __func__, __LINE__);     \
-               dev->state = new_state;                                 \
-}
+ * will fail every 4 or 5 frames, but 30ms is perfect. On the A210,
+ * 30ms is bad while 35ms is perfect. */
+#define NEXT_FRAME_DELAY 35
 
 /* These cameras only support 320x200. */
 static const struct v4l2_pix_format fpix_mode[1] = {
@@ -80,316 +57,183 @@ static const struct v4l2_pix_format fpix_mode[1] = {
                .priv = 0}
 };
 
-/* Reads part of a frame */
-static void read_frame_part(struct usb_fpix *dev)
+/* send a command to the webcam */
+static int command(struct gspca_dev *gspca_dev,
+               int order)      /* 0: reset, 1: frame request */
 {
-       int ret;
+       static u8 order_values[2][12] = {
+               {0xc6, 0, 0, 0, 0, 0, 0,    0, 0x20, 0, 0, 0},  /* reset */
+               {0xd3, 0, 0, 0, 0, 0, 0, 0x01,    0, 0, 0, 0},  /* fr req */
+       };
 
-       PDEBUG(D_STREAM, "read_frame_part");
-
-       /* Reads part of a frame */
-       ret = usb_submit_urb(dev->gspca_dev.urb[0], GFP_ATOMIC);
-       if (ret) {
-               dev_new_state(FPIX_RESET);
-               schedule_delayed_work(&dev->wqe, 1);
-               PDEBUG(D_STREAM, "usb_submit_urb failed with %d",
-                       ret);
-       } else {
-               /* Sometimes we never get a callback, so use a timer.
-                * Is this masking a bug somewhere else? */
-               dev->bulk_timer.expires = jiffies + msecs_to_jiffies(150);
-               add_timer(&dev->bulk_timer);
-       }
+       memcpy(gspca_dev->usb_buf, order_values[order], 12);
+       return usb_control_msg(gspca_dev->dev,
+                       usb_sndctrlpipe(gspca_dev->dev, 0),
+                       USB_REQ_GET_STATUS,
+                       USB_DIR_OUT | USB_TYPE_CLASS |
+                       USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
+                       12, FPIX_TIMEOUT);
 }
 
-/* Callback for URBs. */
-static void urb_callback(struct urb *urb)
+/* workqueue */
+static void dostream(struct work_struct *work)
 {
-       struct gspca_dev *gspca_dev = urb->context;
-       struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
-
-       PDEBUG(D_PACK,
-               "enter urb_callback - status=%d, length=%d",
-               urb->status, urb->actual_length);
-
-       if (dev->state == FPIX_READ_FRAME)
-               del_timer(&dev->bulk_timer);
-
-       if (urb->status != 0) {
-               /* We kill a stuck urb every 50 frames on average, so don't
-                * display a log message for that. */
-               if (urb->status != -ECONNRESET)
-                       PDEBUG(D_STREAM, "bad URB status %d", urb->status);
-               dev_new_state(FPIX_RESET);
-               schedule_delayed_work(&dev->wqe, 1);
-       }
-
-       switch (dev->state) {
-       case FPIX_REQ_FRAME:
-               dev_new_state(FPIX_READ_FRAME);
-               read_frame_part(dev);
-               break;
-
-       case FPIX_READ_FRAME: {
-               unsigned char *data = urb->transfer_buffer;
-               struct gspca_frame *frame;
-
-               frame = gspca_get_i_frame(&dev->gspca_dev);
-               if (frame == NULL)
-                       gspca_dev->last_packet_type = DISCARD_PACKET;
-               if (urb->actual_length < FPIX_MAX_TRANSFER ||
-                       (data[urb->actual_length-2] == 0xff &&
-                               data[urb->actual_length-1] == 0xd9)) {
-
-                       /* If the result is less than what was asked
-                        * for, then it's the end of the
-                        * frame. Sometime the jpeg is not complete,
-                        * but there's nothing we can do. We also end
-                        * here if the the jpeg ends right at the end
-                        * of the frame. */
-                       if (frame)
-                               gspca_frame_add(gspca_dev, LAST_PACKET,
-                                               frame,
-                                               data, urb->actual_length);
-                       dev_new_state(FPIX_REQ_FRAME);
-                       schedule_delayed_work(&dev->wqe, NEXT_FRAME_DELAY);
-               } else {
+       struct usb_fpix *dev = container_of(work, struct usb_fpix, work_struct);
+       struct gspca_dev *gspca_dev = &dev->gspca_dev;
+       struct urb *urb = gspca_dev->urb[0];
+       u8 *data = urb->transfer_buffer;
+       struct gspca_frame *frame;
+       int ret = 0;
+       int len;
+
+       /* synchronize with the main driver */
+       mutex_lock(&gspca_dev->usb_lock);
+       mutex_unlock(&gspca_dev->usb_lock);
+       PDEBUG(D_STREAM, "dostream started");
+
+       /* loop reading a frame */
+again:
+       while (gspca_dev->present && gspca_dev->streaming) {
+
+               /* request a frame */
+               mutex_lock(&gspca_dev->usb_lock);
+               ret = command(gspca_dev, 1);
+               mutex_unlock(&gspca_dev->usb_lock);
+               if (ret < 0)
+                       break;
+               if (!gspca_dev->present || !gspca_dev->streaming)
+                       break;
+
+               /* the frame comes in parts */
+               for (;;) {
+                       ret = usb_bulk_msg(gspca_dev->dev,
+                                       urb->pipe,
+                                       data,
+                                       FPIX_MAX_TRANSFER,
+                                       &len, FPIX_TIMEOUT);
+                       if (ret < 0) {
+                               /* Most of the time we get a timeout
+                                * error. Just restart. */
+                               goto again;
+                       }
+                       if (!gspca_dev->present || !gspca_dev->streaming)
+                               goto out;
+                       frame = gspca_get_i_frame(&dev->gspca_dev);
+                       if (frame == NULL)
+                               gspca_dev->last_packet_type = DISCARD_PACKET;
+
+                       if (len < FPIX_MAX_TRANSFER ||
+                               (data[len - 2] == 0xff &&
+                                       data[len - 1] == 0xd9)) {
+
+                               /* If the result is less than what was asked
+                                * for, then it's the end of the
+                                * frame. Sometimes the jpeg is not complete,
+                                * but there's nothing we can do. We also end
+                                * here if the the jpeg ends right at the end
+                                * of the frame. */
+                               if (frame)
+                                       frame = gspca_frame_add(gspca_dev,
+                                                       LAST_PACKET,
+                                                       frame,
+                                                       data, len);
+                               break;
+                       }
 
                        /* got a partial image */
                        if (frame)
                                gspca_frame_add(gspca_dev,
                                                gspca_dev->last_packet_type
-                                                               == LAST_PACKET
+                                                       == LAST_PACKET
                                                ? FIRST_PACKET : INTER_PACKET,
-                                               frame,
-                                       data, urb->actual_length);
-                       read_frame_part(dev);
+                                               frame, data, len);
                }
-               break;
-           }
-
-       case FPIX_NOP:
-       case FPIX_RESET:
-               PDEBUG(D_STREAM, "invalid state %d", dev->state);
-               break;
-       }
-}
 
-/* Request a new frame */
-static void request_frame(struct usb_fpix *dev)
-{
-       int ret;
-       struct gspca_dev *gspca_dev = &dev->gspca_dev;
-
-       /* Setup command packet */
-       memset(gspca_dev->usb_buf, 0, 12);
-       gspca_dev->usb_buf[0] = 0xd3;
-       gspca_dev->usb_buf[7] = 0x01;
-
-       /* Request a frame */
-       dev->ctrlreq.bRequestType =
-               USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-       dev->ctrlreq.bRequest = USB_REQ_GET_STATUS;
-       dev->ctrlreq.wValue = 0;
-       dev->ctrlreq.wIndex = 0;
-       dev->ctrlreq.wLength = cpu_to_le16(12);
-
-       usb_fill_control_urb(dev->control_urb,
-                            gspca_dev->dev,
-                            usb_sndctrlpipe(gspca_dev->dev, 0),
-                            (unsigned char *) &dev->ctrlreq,
-                            gspca_dev->usb_buf,
-                            12, urb_callback, gspca_dev);
-
-       ret = usb_submit_urb(dev->control_urb, GFP_ATOMIC);
-       if (ret) {
-               dev_new_state(FPIX_RESET);
-               schedule_delayed_work(&dev->wqe, 1);
-               PDEBUG(D_STREAM, "usb_submit_urb failed with %d", ret);
-       }
-}
-
-/*--------------------------------------------------------------------------*/
-
-/* State machine. */
-static void fpix_sm(struct work_struct *work)
-{
-       struct usb_fpix *dev = container_of(work, struct usb_fpix, wqe.work);
-
-       PDEBUG(D_STREAM, "fpix_sm state %d", dev->state);
-
-       /* verify that the device wasn't unplugged */
-       if (!dev->gspca_dev.present) {
-               PDEBUG(D_STREAM, "device is gone");
-               dev_new_state(FPIX_NOP);
-               complete(&dev->can_close);
-               return;
-       }
-
-       if (!dev->streaming) {
-               PDEBUG(D_STREAM, "stopping state machine");
-               dev_new_state(FPIX_NOP);
-               complete(&dev->can_close);
-               return;
+               /* We must wait before trying reading the next
+                * frame. If we don't, or if the delay is too short,
+                * the camera will disconnect. */
+               msleep(NEXT_FRAME_DELAY);
        }
 
-       switch (dev->state) {
-       case FPIX_RESET:
-               dev_new_state(FPIX_REQ_FRAME);
-               schedule_delayed_work(&dev->wqe, HZ / 10);
-               break;
-
-       case FPIX_REQ_FRAME:
-               /* get an image */
-               request_frame(dev);
-               break;
-
-       case FPIX_NOP:
-       case FPIX_READ_FRAME:
-               PDEBUG(D_STREAM, "invalid state %d", dev->state);
-               break;
-       }
+out:
+       PDEBUG(D_STREAM, "dostream stopped");
 }
 
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
                const struct usb_device_id *id)
 {
+       struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
        struct cam *cam = &gspca_dev->cam;
 
        cam->cam_mode = fpix_mode;
        cam->nmodes = 1;
-       cam->epaddr = 0x01;     /* todo: correct for all cams? */
        cam->bulk_size = FPIX_MAX_TRANSFER;
 
-/*     gspca_dev->nbalt = 1;    * use bulk transfer */
-       return 0;
-}
-
-/* Stop streaming and free the ressources allocated by sd_start. */
-static void sd_stopN(struct gspca_dev *gspca_dev)
-{
-       struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
-
-       dev->streaming = 0;
-
-       /* Stop the state machine */
-       if (dev->state != FPIX_NOP)
-               wait_for_completion(&dev->can_close);
-}
-
-/* called on streamoff with alt 0 and disconnect */
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-       struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
-
-       usb_free_urb(dev->control_urb);
-       dev->control_urb = NULL;
-}
-
-/* Kill an URB that hasn't completed. */
-static void timeout_kill(unsigned long data)
-{
-       struct urb *urb = (struct urb *) data;
+       INIT_WORK(&dev->work_struct, dostream);
 
-       usb_unlink_urb(urb);
+       return 0;
 }
 
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
-       struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
-
-       INIT_DELAYED_WORK(&dev->wqe, fpix_sm);
-
-       init_timer(&dev->bulk_timer);
-       dev->bulk_timer.function = timeout_kill;
-
        return 0;
 }
 
+/* start the camera */
 static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
-       int ret;
-       int size_ret;
+       int ret, len;
 
        /* Init the device */
-       memset(gspca_dev->usb_buf, 0, 12);
-       gspca_dev->usb_buf[0] = 0xc6;
-       gspca_dev->usb_buf[8] = 0x20;
-
-       ret = usb_control_msg(gspca_dev->dev,
-                       usb_sndctrlpipe(gspca_dev->dev, 0),
-                       USB_REQ_GET_STATUS,
-                       USB_DIR_OUT | USB_TYPE_CLASS |
-                       USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
-                       12, FPIX_TIMEOUT);
-
-       if (ret != 12) {
-               PDEBUG(D_STREAM, "usb_control_msg failed (%d)", ret);
-               ret = -EIO;
-               goto error;
+       ret = command(gspca_dev, 0);
+       if (ret < 0) {
+               PDEBUG(D_STREAM, "init failed %d", ret);
+               return ret;
        }
 
        /* Read the result of the command. Ignore the result, for it
         * varies with the device. */
        ret = usb_bulk_msg(gspca_dev->dev,
-                       usb_rcvbulkpipe(gspca_dev->dev,
-                                       gspca_dev->cam.epaddr),
-                       gspca_dev->usb_buf, FPIX_MAX_TRANSFER, &size_ret,
+                       gspca_dev->urb[0]->pipe,
+                       gspca_dev->urb[0]->transfer_buffer,
+                       FPIX_MAX_TRANSFER, &len,
                        FPIX_TIMEOUT);
-       if (ret != 0) {
-               PDEBUG(D_STREAM, "usb_bulk_msg failed (%d)", ret);
-               ret = -EIO;
-               goto error;
+       if (ret < 0) {
+               PDEBUG(D_STREAM, "usb_bulk_msg failed %d", ret);
+               return ret;
        }
 
        /* Request a frame, but don't read it */
-       memset(gspca_dev->usb_buf, 0, 12);
-       gspca_dev->usb_buf[0] = 0xd3;
-       gspca_dev->usb_buf[7] = 0x01;
-
-       ret = usb_control_msg(gspca_dev->dev,
-                       usb_sndctrlpipe(gspca_dev->dev, 0),
-                       USB_REQ_GET_STATUS,
-                       USB_DIR_OUT | USB_TYPE_CLASS |
-                       USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
-                       12, FPIX_TIMEOUT);
-       if (ret != 12) {
-               PDEBUG(D_STREAM, "usb_control_msg failed (%d)", ret);
-               ret = -EIO;
-               goto error;
+       ret = command(gspca_dev, 1);
+       if (ret < 0) {
+               PDEBUG(D_STREAM, "frame request failed %d", ret);
+               return ret;
        }
 
        /* Again, reset bulk in endpoint */
-       usb_clear_halt(gspca_dev->dev, gspca_dev->cam.epaddr);
-
-       /* Allocate a control URB */
-       dev->control_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!dev->control_urb) {
-               PDEBUG(D_STREAM, "No free urbs available");
-               ret = -EIO;
-               goto error;
-       }
-
-       /* Various initializations. */
-       init_completion(&dev->can_close);
-       dev->bulk_timer.data = (unsigned long)dev->gspca_dev.urb[0];
-       dev->gspca_dev.urb[0]->complete = urb_callback;
-       dev->streaming = 1;
+       usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe);
 
-       /* Schedule a frame request. */
-       dev_new_state(FPIX_REQ_FRAME);
-       schedule_delayed_work(&dev->wqe, 1);
+       /* 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;
+}
+
+/* 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 usb_fpix *dev = (struct usb_fpix *) gspca_dev;
 
-error:
-       /* Free the ressources */
-       sd_stopN(gspca_dev);
-       sd_stop0(gspca_dev);
-       return ret;
+       /* wait for the work queue to terminate */
+       mutex_unlock(&gspca_dev->usb_lock);
+       destroy_workqueue(dev->work_thread);
+       mutex_lock(&gspca_dev->usb_lock);
+       dev->work_thread = NULL;
 }
 
 /* Table of supported USB devices */
@@ -424,12 +268,11 @@ MODULE_DEVICE_TABLE(usb, device_table);
 
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
-       .name = MODULE_NAME,
+       .name   = MODULE_NAME,
        .config = sd_config,
-       .init = sd_init,
-       .start = sd_start,
-       .stopN = sd_stopN,
-       .stop0 = sd_stop0,
+       .init   = sd_init,
+       .start  = sd_start,
+       .stop0  = sd_stop0,
 };
 
 /* -- device connect -- */
@@ -443,24 +286,28 @@ static int sd_probe(struct usb_interface *intf,
 }
 
 static struct usb_driver sd_driver = {
-       .name = MODULE_NAME,
-       .id_table = device_table,
-       .probe = sd_probe,
+       .name       = MODULE_NAME,
+       .id_table   = device_table,
+       .probe      = sd_probe,
        .disconnect = gspca_disconnect,
 #ifdef CONFIG_PM
        .suspend = gspca_suspend,
-       .resume = gspca_resume,
+       .resume  = gspca_resume,
 #endif
 };
 
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       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);
index 65e4901f4db70a713a4b1d60c0400c4ec9f9250a..a75c1ca2db41d05953c8d9c6cba9c8ddc3701861 100644 (file)
 #include "gspca.h"
 
 /* global values */
-#define DEF_NURBS 2            /* default number of URBs */
+#define DEF_NURBS 3            /* default number of URBs */
+#if DEF_NURBS > MAX_NURBS
+#error "DEF_NURBS too big"
+#endif
 
 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, 4, 0)
-
-static int video_nr = -1;
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 5, 0)
 
 #ifdef GSPCA_DEBUG
 int gspca_debug = D_ERR | D_PROBE;
@@ -126,16 +127,18 @@ static void fill_frame(struct gspca_dev *gspca_dev,
                        struct urb *urb)
 {
        struct gspca_frame *frame;
-       __u8 *data;             /* address of data in the iso message */
+       u8 *data;               /* address of data in the iso message */
        int i, len, st;
        cam_pkt_op pkt_scan;
 
        if (urb->status != 0) {
+               if (urb->status == -ESHUTDOWN)
+                       return;         /* disconnection */
 #ifdef CONFIG_PM
                if (!gspca_dev->frozen)
 #endif
                        PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
-               return;         /* disconnection ? */
+               return;
        }
        pkt_scan = gspca_dev->sd_desc->pkt_scan;
        for (i = 0; i < urb->number_of_packets; i++) {
@@ -166,7 +169,7 @@ static void fill_frame(struct gspca_dev *gspca_dev,
                /* let the packet be analyzed by the subdriver */
                PDEBUG(D_PACK, "packet [%d] o:%d l:%d",
                        i, urb->iso_frame_desc[i].offset, len);
-               data = (__u8 *) urb->transfer_buffer
+               data = (u8 *) urb->transfer_buffer
                                        + urb->iso_frame_desc[i].offset;
                pkt_scan(gspca_dev, frame, data, len);
        }
@@ -182,8 +185,7 @@ static void fill_frame(struct gspca_dev *gspca_dev,
  *
  * Analyse each packet and call the subdriver for copy to the frame buffer.
  */
-static void isoc_irq(struct urb *urb
-)
+static void isoc_irq(struct urb *urb)
 {
        struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
 
@@ -196,8 +198,7 @@ static void isoc_irq(struct urb *urb
 /*
  * bulk message interrupt from the USB device
  */
-static void bulk_irq(struct urb *urb
-)
+static void bulk_irq(struct urb *urb)
 {
        struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
        struct gspca_frame *frame;
@@ -209,6 +210,8 @@ static void bulk_irq(struct urb *urb
        switch (urb->status) {
        case 0:
                break;
+       case -ESHUTDOWN:
+               return;         /* disconnection */
        case -ECONNRESET:
                urb->status = 0;
                break;
@@ -217,7 +220,7 @@ static void bulk_irq(struct urb *urb
                if (!gspca_dev->frozen)
 #endif
                        PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
-               return;         /* disconnection ? */
+               return;
        }
 
        /* check the availability of the frame buffer */
@@ -322,6 +325,7 @@ static int gspca_is_compressed(__u32 format)
        case V4L2_PIX_FMT_JPEG:
        case V4L2_PIX_FMT_SPCA561:
        case V4L2_PIX_FMT_PAC207:
+       case V4L2_PIX_FMT_MR97310A:
                return 1;
        }
        return 0;
@@ -422,10 +426,8 @@ static void destroy_urbs(struct gspca_dev *gspca_dev)
                if (urb == NULL)
                        break;
 
-               BUG_ON(!gspca_dev->dev);
                gspca_dev->urb[i] = NULL;
-               if (!gspca_dev->present)
-                       usb_kill_urb(urb);
+               usb_kill_urb(urb);
                if (urb->transfer_buffer != NULL)
                        usb_buffer_free(gspca_dev->dev,
                                        urb->transfer_buffer_length,
@@ -439,22 +441,16 @@ static void destroy_urbs(struct gspca_dev *gspca_dev)
  * look for an input transfer endpoint in an alternate setting
  */
 static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt,
-                                         __u8 epaddr,
                                          __u8 xfer)
 {
        struct usb_host_endpoint *ep;
        int i, attr;
 
-       epaddr |= USB_DIR_IN;
        for (i = 0; i < alt->desc.bNumEndpoints; i++) {
                ep = &alt->endpoint[i];
-               if (ep->desc.bEndpointAddress == epaddr) {
-                       attr = ep->desc.bmAttributes
-                                               & USB_ENDPOINT_XFERTYPE_MASK;
-                       if (attr == xfer)
-                               return ep;
-                       break;
-               }
+               attr = ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+               if (attr == xfer)
+                       return ep;
        }
        return NULL;
 }
@@ -478,23 +474,23 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
        i = gspca_dev->alt;                     /* previous alt setting */
 
        /* try isoc */
-       while (--i > 0) {                       /* alt 0 is unusable */
+       while (--i >= 0) {
                ep = alt_xfer(&intf->altsetting[i],
-                               gspca_dev->cam.epaddr,
                                USB_ENDPOINT_XFER_ISOC);
                if (ep)
                        break;
        }
 
-       /* if no isoc, try bulk */
+       /* if no isoc, try bulk (alt 0 only) */
        if (ep == NULL) {
                ep = alt_xfer(&intf->altsetting[0],
-                               gspca_dev->cam.epaddr,
                                USB_ENDPOINT_XFER_BULK);
                if (ep == NULL) {
                        err("no transfer endpoint found");
                        return NULL;
                }
+               i = 0;
+               gspca_dev->bulk = 1;
        }
        PDEBUG(D_STREAM, "use alt %d ep 0x%02x",
                        i, ep->desc.bEndpointAddress);
@@ -521,7 +517,7 @@ static int create_urbs(struct gspca_dev *gspca_dev,
        /* calculate the packet size and the number of packets */
        psize = le16_to_cpu(ep->desc.wMaxPacketSize);
 
-       if (gspca_dev->alt != 0) {              /* isoc */
+       if (!gspca_dev->bulk) {                 /* isoc */
 
                /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
                psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
@@ -601,6 +597,11 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
        if (mutex_lock_interruptible(&gspca_dev->usb_lock))
                return -ERESTARTSYS;
 
+       if (!gspca_dev->present) {
+               ret = -ENODEV;
+               goto out;
+       }
+
        /* set the higher alternate setting and
         * loop until urb submit succeeds */
        gspca_dev->alt = gspca_dev->nbalt;
@@ -616,10 +617,9 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
                        goto out;
 
                /* clear the bulk endpoint */
-               if (gspca_dev->alt == 0)        /* if bulk transfer */
+               if (gspca_dev->bulk)
                        usb_clear_halt(gspca_dev->dev,
-                                       usb_rcvintpipe(gspca_dev->dev,
-                                                gspca_dev->cam.epaddr));
+                                       gspca_dev->urb[0]->pipe);
 
                /* start the cam */
                ret = gspca_dev->sd_desc->start(gspca_dev);
@@ -630,7 +630,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
                gspca_dev->streaming = 1;
 
                /* some bulk transfers are started by the subdriver */
-               if (gspca_dev->alt == 0 && gspca_dev->cam.bulk_nurbs == 0)
+               if (gspca_dev->bulk && gspca_dev->cam.bulk_nurbs == 0)
                        break;
 
                /* submit the URBs */
@@ -671,11 +671,14 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev)
 static void gspca_stream_off(struct gspca_dev *gspca_dev)
 {
        gspca_dev->streaming = 0;
-       if (gspca_dev->present
-           && gspca_dev->sd_desc->stopN)
-               gspca_dev->sd_desc->stopN(gspca_dev);
-       destroy_urbs(gspca_dev);
-       gspca_set_alt0(gspca_dev);
+       if (gspca_dev->present) {
+               if (gspca_dev->sd_desc->stopN)
+                       gspca_dev->sd_desc->stopN(gspca_dev);
+               destroy_urbs(gspca_dev);
+               gspca_set_alt0(gspca_dev);
+       }
+
+       /* always call stop0 to free the subdriver's resources */
        if (gspca_dev->sd_desc->stop0)
                gspca_dev->sd_desc->stop0(gspca_dev);
        PDEBUG(D_STREAM, "stream off OK");
@@ -762,7 +765,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
        fmtdesc->pixelformat = fmt_tb[index];
        if (gspca_is_compressed(fmt_tb[index]))
                fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED;
-       fmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        fmtdesc->description[0] = fmtdesc->pixelformat & 0xff;
        fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff;
        fmtdesc->description[2] = (fmtdesc->pixelformat >> 16) & 0xff;
@@ -957,8 +959,15 @@ static int vidioc_querycap(struct file *file, void  *priv,
                           struct v4l2_capability *cap)
 {
        struct gspca_dev *gspca_dev = priv;
+       int ret;
 
-       memset(cap, 0, sizeof *cap);
+       /* protect the access to the usb device */
+       if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+               return -ERESTARTSYS;
+       if (!gspca_dev->present) {
+               ret = -ENODEV;
+               goto out;
+       }
        strncpy(cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver);
        if (gspca_dev->dev->product != NULL) {
                strncpy(cap->card, gspca_dev->dev->product,
@@ -969,13 +978,15 @@ static int vidioc_querycap(struct file *file, void  *priv,
                        le16_to_cpu(gspca_dev->dev->descriptor.idVendor),
                        le16_to_cpu(gspca_dev->dev->descriptor.idProduct));
        }
-       strncpy(cap->bus_info, gspca_dev->dev->bus->bus_name,
-               sizeof cap->bus_info);
+       usb_make_path(gspca_dev->dev, cap->bus_info, sizeof(cap->bus_info));
        cap->version = DRIVER_VERSION_NUMBER;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
                          | V4L2_CAP_STREAMING
                          | V4L2_CAP_READWRITE;
-       return 0;
+       ret = 0;
+out:
+       mutex_unlock(&gspca_dev->usb_lock);
+       return ret;
 }
 
 static int vidioc_queryctrl(struct file *file, void *priv,
@@ -1038,7 +1049,10 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
                PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
                if (mutex_lock_interruptible(&gspca_dev->usb_lock))
                        return -ERESTARTSYS;
-               ret = ctrls->set(gspca_dev, ctrl->value);
+               if (gspca_dev->present)
+                       ret = ctrls->set(gspca_dev, ctrl->value);
+               else
+                       ret = -ENODEV;
                mutex_unlock(&gspca_dev->usb_lock);
                return ret;
        }
@@ -1062,7 +1076,10 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
                        return -EINVAL;
                if (mutex_lock_interruptible(&gspca_dev->usb_lock))
                        return -ERESTARTSYS;
-               ret = ctrls->get(gspca_dev, &ctrl->value);
+               if (gspca_dev->present)
+                       ret = ctrls->get(gspca_dev, &ctrl->value);
+               else
+                       ret = -ENODEV;
                mutex_unlock(&gspca_dev->usb_lock);
                return ret;
        }
@@ -1081,7 +1098,6 @@ static int vidioc_s_audio(struct file *file, void *priv,
 static int vidioc_g_audio(struct file *file, void *priv,
                         struct v4l2_audio *audio)
 {
-       memset(audio, 0, sizeof *audio);
        strcpy(audio->name, "Microphone");
        return 0;
 }
@@ -1115,7 +1131,6 @@ static int vidioc_enum_input(struct file *file, void *priv,
 
        if (input->index != 0)
                return -EINVAL;
-       memset(input, 0, sizeof *input);
        input->type = V4L2_INPUT_TYPE_CAMERA;
        strncpy(input->name, gspca_dev->sd_desc->name,
                sizeof input->name);
@@ -1224,10 +1239,7 @@ static int vidioc_streamon(struct file *file, void *priv,
                return -EINVAL;
        if (mutex_lock_interruptible(&gspca_dev->queue_lock))
                return -ERESTARTSYS;
-       if (!gspca_dev->present) {
-               ret = -ENODEV;
-               goto out;
-       }
+
        if (gspca_dev->nframes == 0
            || !(gspca_dev->frame[0].v4l2_buf.flags & V4L2_BUF_FLAG_QUEUED)) {
                ret = -EINVAL;
@@ -1295,7 +1307,10 @@ static int vidioc_g_jpegcomp(struct file *file, void *priv,
                return -EINVAL;
        if (mutex_lock_interruptible(&gspca_dev->usb_lock))
                return -ERESTARTSYS;
-       ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp);
+       if (gspca_dev->present)
+               ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp);
+       else
+               ret = -ENODEV;
        mutex_unlock(&gspca_dev->usb_lock);
        return ret;
 }
@@ -1310,7 +1325,10 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv,
                return -EINVAL;
        if (mutex_lock_interruptible(&gspca_dev->usb_lock))
                return -ERESTARTSYS;
-       ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
+       if (gspca_dev->present)
+               ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
+       else
+               ret = -ENODEV;
        mutex_unlock(&gspca_dev->usb_lock);
        return ret;
 }
@@ -1320,8 +1338,6 @@ static int vidioc_g_parm(struct file *filp, void *priv,
 {
        struct gspca_dev *gspca_dev = priv;
 
-       memset(parm, 0, sizeof *parm);
-       parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        parm->parm.capture.readbuffers = gspca_dev->nbufread;
 
        if (gspca_dev->sd_desc->get_streamparm) {
@@ -1329,7 +1345,11 @@ static int vidioc_g_parm(struct file *filp, void *priv,
 
                if (mutex_lock_interruptible(&gspca_dev->usb_lock))
                        return -ERESTARTSYS;
-               ret = gspca_dev->sd_desc->get_streamparm(gspca_dev, parm);
+               if (gspca_dev->present)
+                       ret = gspca_dev->sd_desc->get_streamparm(gspca_dev,
+                                                                parm);
+               else
+                       ret = -ENODEV;
                mutex_unlock(&gspca_dev->usb_lock);
                return ret;
        }
@@ -1354,7 +1374,11 @@ static int vidioc_s_parm(struct file *filp, void *priv,
 
                if (mutex_lock_interruptible(&gspca_dev->usb_lock))
                        return -ERESTARTSYS;
-               ret = gspca_dev->sd_desc->set_streamparm(gspca_dev, parm);
+               if (gspca_dev->present)
+                       ret = gspca_dev->sd_desc->set_streamparm(gspca_dev,
+                                                                parm);
+               else
+                       ret = -ENODEV;
                mutex_unlock(&gspca_dev->usb_lock);
                return ret;
        }
@@ -1382,7 +1406,6 @@ static int vidiocgmbuf(struct file *file, void *priv,
                {
                        struct v4l2_format fmt;
 
-                       memset(&fmt, 0, sizeof fmt);
                        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                        i = gspca_dev->cam.nmodes - 1;  /* highest mode */
                        fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width;
@@ -1528,7 +1551,8 @@ static int frame_wait(struct gspca_dev *gspca_dev,
 
        if (gspca_dev->sd_desc->dq_callback) {
                mutex_lock(&gspca_dev->usb_lock);
-               gspca_dev->sd_desc->dq_callback(gspca_dev);
+               if (gspca_dev->present)
+                       gspca_dev->sd_desc->dq_callback(gspca_dev);
                mutex_unlock(&gspca_dev->usb_lock);
        }
        return j;
@@ -1550,6 +1574,9 @@ static int vidioc_dqbuf(struct file *file, void *priv,
        if (v4l2_buf->memory != gspca_dev->memory)
                return -EINVAL;
 
+       if (!gspca_dev->present)
+               return -ENODEV;
+
        /* if not streaming, be sure the application will not loop forever */
        if (!(file->f_flags & O_NONBLOCK)
            && !gspca_dev->streaming && gspca_dev->users == 1)
@@ -1700,8 +1727,6 @@ static unsigned int dev_poll(struct file *file, poll_table *wait)
        PDEBUG(D_FRAM, "poll");
 
        poll_wait(file, &gspca_dev->wq, wait);
-       if (!gspca_dev->present)
-               return POLLERR;
 
        /* if reqbufs is not done, the user would use read() */
        if (gspca_dev->nframes == 0) {
@@ -1714,10 +1739,6 @@ static unsigned int dev_poll(struct file *file, poll_table *wait)
 
        if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0)
                return POLLERR;
-       if (!gspca_dev->present) {
-               ret = POLLERR;
-               goto out;
-       }
 
        /* check the next incoming buffer */
        i = gspca_dev->fr_o;
@@ -1726,8 +1747,9 @@ static unsigned int dev_poll(struct file *file, poll_table *wait)
                ret = POLLIN | POLLRDNORM;      /* something to read */
        else
                ret = 0;
-out:
        mutex_unlock(&gspca_dev->queue_lock);
+       if (!gspca_dev->present)
+               return POLLHUP;
        return ret;
 }
 
@@ -1925,7 +1947,7 @@ int gspca_dev_probe(struct usb_interface *intf,
        gspca_dev->present = 1;
        ret = video_register_device(&gspca_dev->vdev,
                                  VFL_TYPE_GRABBER,
-                                 video_nr);
+                                 -1);
        if (ret < 0) {
                err("video_register_device err %d", ret);
                goto out;
@@ -1953,10 +1975,16 @@ void gspca_disconnect(struct usb_interface *intf)
 
        mutex_lock(&gspca_dev->usb_lock);
        gspca_dev->present = 0;
-       mutex_unlock(&gspca_dev->usb_lock);
 
-       destroy_urbs(gspca_dev);
+       if (gspca_dev->streaming) {
+               destroy_urbs(gspca_dev);
+               wake_up_interruptible(&gspca_dev->wq);
+       }
+
+       /* the device is freed at exit of this function */
        gspca_dev->dev = NULL;
+       mutex_unlock(&gspca_dev->usb_lock);
+
        usb_set_intfdata(intf, NULL);
 
        /* release the device */
index c90af9cb1e079b6c3aaa322c0ff739a2652207dc..e4d4cf6ce05a2825828e8d6599770e15fc0e949c 100644 (file)
@@ -33,19 +33,13 @@ extern int gspca_debug;
 #endif
 #undef err
 #define err(fmt, args...) \
-       do {\
-               printk(KERN_ERR MODULE_NAME ": " fmt "\n", ## args); \
-       } while (0)
+       printk(KERN_ERR MODULE_NAME ": " fmt "\n", ## args)
 #undef info
 #define info(fmt, args...) \
-       do {\
-               printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args); \
-       } while (0)
+       printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args)
 #undef warn
 #define warn(fmt, args...) \
-       do {\
-               printk(KERN_WARNING MODULE_NAME ": " fmt "\n", ## args); \
-       } while (0)
+       printk(KERN_WARNING MODULE_NAME ": " fmt "\n", ## args)
 
 #define GSPCA_MAX_FRAMES 16    /* maximum number of video frame buffers */
 /* image transfers */
@@ -62,7 +56,6 @@ struct cam {
                                 * - cannot be > MAX_NURBS
                                 * - when 0 and bulk_size != 0 means
                                 *   1 URB and submit done by subdriver */
-       __u8 epaddr;
 };
 
 struct gspca_dev;
@@ -174,6 +167,7 @@ struct gspca_dev {
        __u8 iface;                     /* USB interface number */
        __u8 alt;                       /* USB alternate setting */
        __u8 nbalt;                     /* number of USB alternate settings */
+       u8 bulk;                        /* image transfer by 0:isoc / 1:bulk */
 };
 
 int gspca_dev_probe(struct usb_interface *intf,
index d823b47bd4e6a6d39e40b3826614ec69f9b4eb91..de63c36806c09bbb2788faba8c1c6833c81863b8 100644 (file)
  *
  */
 
-/* start of jpeg frame + quantization table */
-static const unsigned char quant[][0x88] = {
-/* index 0 - Q40*/
-    {
+/*
+ * generation options
+ *     CONEX_CAM       Conexant if present
+ */
+
+/* JPEG header */
+static const u8 jpeg_head[] = {
        0xff, 0xd8,                     /* jpeg */
-       0xff, 0xdb, 0x00, 0x84,         /* DQT */
-0,                                     /* quantization table part 1 */
-     20, 14, 15, 18, 15, 13, 20, 18, 16, 18, 23, 21, 20, 24, 30, 50,
-     33, 30, 28, 28, 30, 61, 44, 46, 36, 50, 73, 64, 76, 75, 71, 64,
-     70, 69, 80, 90, 115, 98, 80, 85, 109, 86, 69, 70, 100, 136, 101,
-     109,
-     119, 123, 129, 130, 129, 78, 96, 141, 151, 140, 125, 150, 115,
-     126, 129, 124,
-1,                                     /* quantization table part 2 */
-     21, 23, 23, 30, 26, 30, 59, 33, 33, 59, 124, 83, 70, 83, 124, 124,
-     124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
-     124, 124, 124,
-     124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
-     124, 124, 124,
-     124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
-     124, 124, 124},
-/* index 1 - Q50 */
-    {
-       0xff, 0xd8,
-       0xff, 0xdb, 0x00, 0x84,         /* DQT */
-0,
-     16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16, 19, 24, 40,
-     26, 24, 22, 22, 24, 49, 35, 37, 29, 40, 58, 51, 61, 60, 57, 51,
-     56, 55, 64, 72, 92, 78, 64, 68, 87, 69, 55, 56, 80, 109, 81, 87,
-     95, 98, 103, 104, 103, 62, 77, 113, 121, 112, 100, 120, 92, 101,
-     103, 99,
-1,
-    17, 18, 18, 24, 21, 24, 47, 26, 26, 47, 99, 66, 56, 66, 99, 99,
-     99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-     99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-     99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99},
-/* index 2 Q60 */
-    {
-       0xff, 0xd8,
-       0xff, 0xdb, 0x00, 0x84,         /* DQT */
-0,
-     13, 9, 10, 11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15, 19, 32,
-     21, 19, 18, 18, 19, 39, 28, 30, 23, 32, 46, 41, 49, 48, 46, 41,
-     45, 44, 51, 58, 74, 62, 51, 54, 70, 55, 44, 45, 64, 87, 65, 70,
-     76, 78, 82, 83, 82, 50, 62, 90, 97, 90, 80, 96, 74, 81, 82, 79,
-1,
-     14, 14, 14, 19, 17, 19, 38, 21, 21, 38, 79, 53, 45, 53, 79, 79,
-     79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
-     79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
-     79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79},
-/* index 3 - Q70 */
-    {
-       0xff, 0xd8,
-       0xff, 0xdb, 0x00, 0x84,         /* DQT */
-0,
-     10, 7, 7, 8, 7, 6, 10, 8, 8, 8, 11, 10, 10, 11, 14, 24,
-     16, 14, 13, 13, 14, 29, 21, 22, 17, 24, 35, 31, 37, 36, 34, 31,
-     34, 33, 38, 43, 55, 47, 38, 41, 52, 41, 33, 34, 48, 65, 49, 52,
-     57, 59, 62, 62, 62, 37, 46, 68, 73, 67, 60, 72, 55, 61, 62, 59,
-1,
-     10, 11, 11, 14, 13, 14, 28, 16, 16, 28, 59, 40, 34, 40, 59, 59,
-     59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-     59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-     59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59},
-/* index 4 - Q80 */
-    {
-       0xff, 0xd8,
-       0xff, 0xdb, 0x00, 0x84,         /* DQT */
-0,
-      6, 4, 5, 6, 5, 4, 6, 6, 5, 6, 7, 7, 6, 8, 10, 16,
-     10, 10, 9, 9, 10, 20, 14, 15, 12, 16, 23, 20, 24, 24, 23, 20,
-     22, 22, 26, 29, 37, 31, 26, 27, 35, 28, 22, 22, 32, 44, 32, 35,
-     38, 39, 41, 42, 41, 25, 31, 45, 48, 45, 40, 48, 37, 40, 41, 40,
-1,
-      7, 7, 7, 10, 8, 10, 19, 10, 10, 19, 40, 26, 22, 26, 40, 40,
-     40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
-     40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
-     40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40},
-/* index 5 - Q85 */
-    {
-       0xff, 0xd8,
-       0xff, 0xdb, 0x00, 0x84,         /* DQT */
-0,
-     5, 3, 4, 4, 4, 3, 5, 4, 4, 4, 5, 5, 5, 6, 7, 12,
-     8, 7, 7, 7, 7, 15, 11, 11, 9, 12, 17, 15, 18, 18, 17, 15,
-     17, 17, 19, 22, 28, 23, 19, 20, 26, 21, 17, 17, 24, 33, 24, 26,
-     29, 29, 31, 31, 31, 19, 23, 34, 36, 34, 30, 36, 28, 30, 31, 30,
-1,
-     5, 5, 5, 7, 6, 7, 14, 8, 8, 14, 30, 20, 17, 20, 30, 30,
-     30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
-     30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
-     30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
-/* index 6 - 86 */
-{
-       0xff, 0xd8,
-       0xff, 0xdb, 0x00, 0x84,         /* DQT */
-0,
-       0x04, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x04,
-       0x04, 0x04, 0x05, 0x05, 0x04, 0x05, 0x07, 0x0B,
-       0x07, 0x07, 0x06, 0x06, 0x07, 0x0E, 0x0A, 0x0A,
-       0x08, 0x0B, 0x10, 0x0E, 0x11, 0x11, 0x10, 0x0E,
-       0x10, 0x0F, 0x12, 0x14, 0x1A, 0x16, 0x12, 0x13,
-       0x18, 0x13, 0x0F, 0x10, 0x16, 0x1F, 0x17, 0x18,
-       0x1B, 0x1B, 0x1D, 0x1D, 0x1D, 0x11, 0x16, 0x20,
-       0x22, 0x1F, 0x1C, 0x22, 0x1A, 0x1C, 0x1D, 0x1C,
-1,
-       0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x0D, 0x07,
-       0x07, 0x0D, 0x1C, 0x12, 0x10, 0x12, 0x1C, 0x1C,
-       0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
-       0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
-       0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
-       0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
-       0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
-       0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
- },
-/* index 7 - 88 */
-{
-       0xff, 0xd8,
-       0xff, 0xdb, 0x00, 0x84,         /* DQT */
-0,
-       0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x04, 0x03,
-       0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x06, 0x0A,
-       0x06, 0x06, 0x05, 0x05, 0x06, 0x0C, 0x08, 0x09,
-       0x07, 0x0A, 0x0E, 0x0C, 0x0F, 0x0E, 0x0E, 0x0C,
-       0x0D, 0x0D, 0x0F, 0x11, 0x16, 0x13, 0x0F, 0x10,
-       0x15, 0x11, 0x0D, 0x0D, 0x13, 0x1A, 0x13, 0x15,
-       0x17, 0x18, 0x19, 0x19, 0x19, 0x0F, 0x12, 0x1B,
-       0x1D, 0x1B, 0x18, 0x1D, 0x16, 0x18, 0x19, 0x18,
-1,
-       0x04, 0x04, 0x04, 0x06, 0x05, 0x06, 0x0B, 0x06,
-       0x06, 0x0B, 0x18, 0x10, 0x0D, 0x10, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-},
-/* index 8 - ?? */
-{
-       0xff, 0xd8,
+
+/* quantization table quality 50% */
        0xff, 0xdb, 0x00, 0x84,         /* DQT */
 0,
-       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
-       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x05,
-       0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x04, 0x05,
-       0x04, 0x05, 0x07, 0x06, 0x08, 0x08, 0x07, 0x06,
-       0x07, 0x07, 0x08, 0x09, 0x0C, 0x0A, 0x08, 0x09,
-       0x0B, 0x09, 0x07, 0x07, 0x0A, 0x0E, 0x0A, 0x0B,
-       0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x08, 0x0A, 0x0E,
-       0x0F, 0x0E, 0x0D, 0x0F, 0x0C, 0x0D, 0x0D, 0x0C,
+#define JPEG_QT0_OFFSET 7
+       0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e,
+       0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
+       0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
+       0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33,
+       0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44,
+       0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57,
+       0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
+       0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
 1,
-       0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x06, 0x03,
-       0x03, 0x06, 0x0C, 0x08, 0x07, 0x08, 0x0C, 0x0C,
-       0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
-       0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
-       0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
-       0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
-       0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
-       0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C
-}
-};
+#define JPEG_QT1_OFFSET 72
+       0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
+       0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
 
-/* huffman table + start of SOF0 */
-static unsigned char huffman[] = {
+/* huffman table */
        0xff, 0xc4, 0x01, 0xa2,
        0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01,
        0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -244,58 +112,57 @@ static unsigned char huffman[] = {
        0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
 #ifdef CONEX_CAM
 /* the Conexant frames start with SOF0 */
+#define JPEG_HDR_SZ 556
 #else
        0xff, 0xc0, 0x00, 0x11,         /* SOF0 (start of frame 0 */
        0x08,                           /* data precision */
-#endif
-};
-
-#ifndef CONEX_CAM
-/* variable part:
- *     0x01, 0xe0,                      height
- *     0x02, 0x80,                      width
- *     0x03,                            component number
- *             0x01,
- *                     0x21,                   samples Y
- */
-
-/* end of header */
-static unsigned char eoh[] = {
+#define JPEG_HEIGHT_OFFSET 561
+       0x01, 0xe0,                     /* height */
+       0x02, 0x80,                     /* width */
+       0x03,                           /* component number */
+               0x01,
+                       0x21,           /* samples Y */
                        0x00,           /* quant Y */
                0x02, 0x11, 0x01,       /* samples CbCr - quant CbCr */
                0x03, 0x11, 0x01,
 
        0xff, 0xda, 0x00, 0x0c,         /* SOS (start of scan) */
        0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
-};
+#define JPEG_HDR_SZ 589
 #endif
+};
 
-/* -- output the JPEG header -- */
-static void jpeg_put_header(struct gspca_dev *gspca_dev,
-                           struct gspca_frame *frame,
-                           int qindex,
-                           int samplesY)
+/* define the JPEG header */
+static void jpeg_define(u8 *jpeg_hdr,
+                       int height,
+                       int width,
+                       int samplesY)
 {
+       memcpy(jpeg_hdr, jpeg_head, sizeof jpeg_head);
 #ifndef CONEX_CAM
-       unsigned char tmpbuf[8];
+       jpeg_hdr[JPEG_HEIGHT_OFFSET + 0] = height >> 8;
+       jpeg_hdr[JPEG_HEIGHT_OFFSET + 1] = height & 0xff;
+       jpeg_hdr[JPEG_HEIGHT_OFFSET + 2] = width >> 8;
+       jpeg_hdr[JPEG_HEIGHT_OFFSET + 3] = width & 0xff;
+       jpeg_hdr[JPEG_HEIGHT_OFFSET + 6] = samplesY;
 #endif
+}
 
-       gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
-                       (unsigned char *) quant[qindex], sizeof quant[0]);
-       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-                       (unsigned char *) huffman, sizeof huffman);
-#ifndef CONEX_CAM
-       tmpbuf[0] = gspca_dev->height >> 8;
-       tmpbuf[1] = gspca_dev->height & 0xff;
-       tmpbuf[2] = gspca_dev->width >> 8;
-       tmpbuf[3] = gspca_dev->width & 0xff;
-       tmpbuf[4] = 0x03;               /* component number */
-       tmpbuf[5] = 0x01;               /* first component */
-       tmpbuf[6] = samplesY;
-       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-                       tmpbuf, 7);
-       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-                       eoh, sizeof eoh);
-#endif
+/* set the JPEG quality */
+static void jpeg_set_qual(u8 *jpeg_hdr,
+                         int quality)
+{
+       int i, sc;
+
+       if (quality < 50)
+               sc = 5000 / quality;
+       else
+               sc = 200 - quality * 2;
+       for (i = 0; i < 64; i++) {
+               jpeg_hdr[JPEG_QT0_OFFSET + i] =
+                       (jpeg_head[JPEG_QT0_OFFSET + i] * sc + 50) / 100;
+               jpeg_hdr[JPEG_QT1_OFFSET + i] =
+                       (jpeg_head[JPEG_QT1_OFFSET + i] * sc + 50) / 100;
+       }
 }
 #endif
index ed906fe31287d4350fe16f1b860b966187ed30f3..b35e4838a6e5740cca162efab67d7ddeaecbf253 100644 (file)
@@ -332,7 +332,6 @@ static int m5602_configure(struct gspca_dev *gspca_dev,
        int err;
 
        cam = &gspca_dev->cam;
-       cam->epaddr = M5602_ISOC_ENDPOINT_ADDR;
        sd->desc = &sd_desc;
 
        if (dump_bridge)
@@ -374,8 +373,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init mod_m5602_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index 3d2090e67a633046417738ce1e14b4d6ec451295..75e8d14e4ac74d0e620eff590d8e32d9fe7e0fab 100644 (file)
@@ -32,17 +32,91 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
-       char qindex;
+       u8 brightness;
+       u8 colors;
+       u8 gamma;
+       u8 sharpness;
+       u8 quality;
+#define QUALITY_MIN 40
+#define QUALITY_MAX 70
+#define QUALITY_DEF 50
+
+       u8 *jpeg_hdr;
 };
 
 /* V4L2 controls supported by the driver */
+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_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
+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[] = {
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 30,
+               .step    = 1,
+#define BRIGHTNESS_DEF 15
+               .default_value = BRIGHTNESS_DEF,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+       {
+           {
+               .id      = V4L2_CID_SATURATION,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Color",
+               .minimum = 1,
+               .maximum = 255,
+               .step    = 1,
+#define COLOR_DEF 200
+               .default_value = COLOR_DEF,
+           },
+           .set = sd_setcolors,
+           .get = sd_getcolors,
+       },
+       {
+           {
+               .id      = V4L2_CID_GAMMA,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Gamma",
+               .minimum = 0,
+               .maximum = 3,
+               .step    = 1,
+#define GAMMA_DEF 1
+               .default_value = GAMMA_DEF,
+           },
+           .set = sd_setgamma,
+           .get = sd_getgamma,
+       },
+       {
+           {
+               .id      = V4L2_CID_SHARPNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Sharpness",
+               .minimum = 0,
+               .maximum = 2,
+               .step    = 1,
+#define SHARPNESS_DEF 1
+               .default_value = SHARPNESS_DEF,
+           },
+           .set = sd_setsharpness,
+           .get = sd_getsharpness,
+       },
 };
 
 static const struct v4l2_pix_format vga_mode[] = {
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 320,
-               .sizeimage = 320 * 240 * 3 / 8 + 589,
+               .sizeimage = 320 * 240 * 3 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 2},
        {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
@@ -52,65 +126,45 @@ static const struct v4l2_pix_format vga_mode[] = {
                .priv = 1},
 };
 
-/* MI Register table //elvis */
-enum {
-       REG_HW_MI_0,
-       REG_HW_MI_1,
-       REG_HW_MI_2,
-       REG_HW_MI_3,
-       REG_HW_MI_4,
-       REG_HW_MI_5,
-       REG_HW_MI_6,
-       REG_HW_MI_7,
-       REG_HW_MI_9 = 0x09,
-       REG_HW_MI_B = 0x0B,
-       REG_HW_MI_C,
-       REG_HW_MI_D,
-       REG_HW_MI_1E = 0x1E,
-       REG_HW_MI_20 = 0x20,
-       REG_HW_MI_2B = 0x2B,
-       REG_HW_MI_2C,
-       REG_HW_MI_2D,
-       REG_HW_MI_2E,
-       REG_HW_MI_35 = 0x35,
-       REG_HW_MI_5F = 0x5f,
-       REG_HW_MI_60,
-       REG_HW_MI_61,
-       REG_HW_MI_62,
-       REG_HW_MI_63,
-       REG_HW_MI_64,
-       REG_HW_MI_F1 = 0xf1,
-       ATTR_TOTAL_MI_REG = 0xf2
+static const __u8 mi_data[0x20] = {
+/*      01    02   03     04    05    06    07    08 */
+       0x48, 0x22, 0x01, 0x47, 0x10, 0x00, 0x00, 0x00,
+/*      09    0a   0b     0c    0d    0e    0f    10 */
+       0x00, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01,
+/*      11    12   13     14    15    16    17    18 */
+       0x30, 0x00, 0x04, 0x00, 0x06, 0x01, 0xe2, 0x02,
+/*      19    1a   1b     1c    1d    1e    1f    20 */
+       0x82, 0x00, 0x20, 0x17, 0x80, 0x08, 0x0c, 0x00
 };
 
-/* the bytes to write are in gspca_dev->usb_buf */
+/* write <len> bytes from gspca_dev->usb_buf */
 static int reg_w(struct gspca_dev *gspca_dev,
-                __u16 index, int len)
+                int len)
 {
-       int rc;
-
-       rc = usb_control_msg(gspca_dev->dev,
-                        usb_sndbulkpipe(gspca_dev->dev, 4),
-                        0x12,
-                        0xc8,          /* ?? */
-                        0,             /* value */
-                        index, gspca_dev->usb_buf, len, 500);
-       if (rc < 0)
-               PDEBUG(D_ERR, "reg write [%02x] error %d", index, rc);
-       return rc;
+       int alen, ret;
+
+       ret = usb_bulk_msg(gspca_dev->dev,
+                       usb_sndbulkpipe(gspca_dev->dev, 4),
+                       gspca_dev->usb_buf,
+                       len,
+                       &alen,
+                       500);   /* timeout in milliseconds */
+       if (ret < 0)
+               PDEBUG(D_ERR, "reg write [%02x] error %d",
+                       gspca_dev->usb_buf[0], ret);
+       return ret;
 }
 
-static void bulk_w(struct gspca_dev *gspca_dev,
-                  __u16 *pch,
-                  __u16 Address)
+static void mi_w(struct gspca_dev *gspca_dev,
+                u8 addr,
+                u8 value)
 {
        gspca_dev->usb_buf[0] = 0x1f;
        gspca_dev->usb_buf[1] = 0;                      /* control byte */
-       gspca_dev->usb_buf[2] = Address;
-       gspca_dev->usb_buf[3] = *pch >> 8;              /* high byte */
-       gspca_dev->usb_buf[4] = *pch;                   /* low byte */
+       gspca_dev->usb_buf[2] = addr;
+       gspca_dev->usb_buf[3] = value;
 
-       reg_w(gspca_dev, Address, 5);
+       reg_w(gspca_dev, 4);
 }
 
 /* this function is called at probe time */
@@ -121,10 +175,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct cam *cam;
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 0x01;
        cam->cam_mode = vga_mode;
        cam->nmodes = ARRAY_SIZE(vga_mode);
-       sd->qindex = 1;                 /* set the quantization table */
+       sd->brightness = BRIGHTNESS_DEF;
+       sd->colors = COLOR_DEF;
+       sd->gamma = GAMMA_DEF;
+       sd->sharpness = SHARPNESS_DEF;
+       sd->quality = QUALITY_DEF;
+       gspca_dev->nbalt = 9;           /* use the altsetting 08 */
        return 0;
 }
 
@@ -136,24 +194,22 @@ static int sd_init(struct gspca_dev *gspca_dev)
 
 static int sd_start(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
        int err_code;
-       __u8 *data;
-       __u16 *MI_buf;
-       int h_size, v_size;
-       int intpipe;
-
-       PDEBUG(D_STREAM, "camera start, iface %d, alt 8", gspca_dev->iface);
-       err_code = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 8);
-       if (err_code < 0) {
-               PDEBUG(D_ERR|D_STREAM, "Set packet size: set interface error");
-               return err_code;
-       }
+       u8 *data;
+       int i;
+
+       /* create the JPEG header */
+       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+                       0x21);          /* JPEG 422 */
+       jpeg_set_qual(sd->jpeg_hdr, sd->quality);
 
        data = gspca_dev->usb_buf;
+
        data[0] = 0x01;         /* address */
        data[1] = 0x01;
-
-       err_code = reg_w(gspca_dev, data[0], 2);
+       err_code = reg_w(gspca_dev, 2);
        if (err_code < 0)
                return err_code;
 
@@ -163,30 +219,28 @@ static int sd_start(struct gspca_dev *gspca_dev)
        data[0] = 0x00;         /* address */
        data[1] = 0x0c | 0x01;  /* reg 0 */
        data[2] = 0x01;         /* reg 1 */
-       h_size = gspca_dev->width;
-       v_size = gspca_dev->height;
-       data[3] = h_size / 8;   /* h_size , reg 2 */
-       data[4] = v_size / 8;   /* v_size , reg 3 */
+       data[3] = gspca_dev->width / 8;         /* h_size , reg 2 */
+       data[4] = gspca_dev->height / 8;        /* v_size , reg 3 */
        data[5] = 0x30;         /* reg 4, MI, PAS5101 :
                                 *      0x30 for 24mhz , 0x28 for 12mhz */
-       data[6] = 4;            /* reg 5, H start */
-       data[7] = 0xc0;         /* reg 6, gamma 1.5 */
-       data[8] = 3;            /* reg 7, V start */
+       data[6] = 0x02;         /* reg 5, H start - was 0x04 */
+       data[7] = sd->gamma * 0x40;     /* reg 0x06: gamma */
+       data[8] = 0x01;         /* reg 7, V start - was 0x03 */
 /*     if (h_size == 320 ) */
 /*             data[9]= 0x56;   * reg 8, 24MHz, 2:1 scale down */
 /*     else */
        data[9] = 0x52;         /* reg 8, 24MHz, no scale down */
-       data[10] = 0x5d;        /* reg 9, I2C device address
-                                *      [for PAS5101 (0x40)] [for MI (0x5d)] */
+/*jfm: from win trace*/
+       data[10] = 0x18;
 
-       err_code = reg_w(gspca_dev, data[0], 11);
+       err_code = reg_w(gspca_dev, 11);
        if (err_code < 0)
                return err_code;
 
        data[0] = 0x23;         /* address */
        data[1] = 0x09;         /* reg 35, append frame header */
 
-       err_code = reg_w(gspca_dev, data[0], 2);
+       err_code = reg_w(gspca_dev, 2);
        if (err_code < 0)
                return err_code;
 
@@ -197,137 +251,57 @@ static int sd_start(struct gspca_dev *gspca_dev)
 /*     else */
        data[1] = 50;           /* 50 reg 60, pc-cam frame size
                                 *      (unit: 4KB) 200KB */
-       err_code = reg_w(gspca_dev, data[0], 2);
+       err_code = reg_w(gspca_dev, 2);
        if (err_code < 0)
                return err_code;
 
-       if (0) {                        /* fixed dark-gain */
-               data[1] = 0;            /* reg 94, Y Gain (1.75) */
-               data[2] = 0;            /* reg 95, UV Gain (1.75) */
-               data[3] = 0x3f;         /* reg 96, Y Gain/UV Gain/disable
-                                        *      auto dark-gain */
-               data[4] = 0;            /* reg 97, set fixed dark level */
-               data[5] = 0;            /* reg 98, don't care */
-       } else {                        /* auto dark-gain */
-               data[1] = 0;            /* reg 94, Y Gain (auto) */
-               data[2] = 0;            /* reg 95, UV Gain (1.75) */
-               data[3] = 0x78;         /* reg 96, Y Gain/UV Gain/disable
-                                        *      auto dark-gain */
-               switch (gspca_dev->width) {
-/*             case 1280: */
-/*                     data[4] = 154;
-                                * reg 97, %3 shadow point (unit: 256 pixel) */
-/*                     data[5] = 51;
-                                * reg 98, %1 highlight point
-                                *      (uint: 256 pixel) */
-/*                     break; */
-               default:
-/*             case 640: */
-                       data[4] = 36;   /* reg 97, %3 shadow point
-                                        *      (unit: 256 pixel) */
-                       data[5] = 12;   /* reg 98, %1 highlight point
-                                        *      (uint: 256 pixel) */
-                       break;
-               case 320:
-                       data[4] = 9;    /* reg 97, %3 shadow point
-                                        *      (unit: 256 pixel) */
-                       data[5] = 3;    /* reg 98, %1 highlight point
-                                        *      (uint: 256 pixel) */
-                       break;
-               }
-       }
        /* auto dark-gain */
        data[0] = 0x5e;         /* address */
-
-       err_code = reg_w(gspca_dev, data[0], 6);
+       data[1] = 0;            /* reg 94, Y Gain (auto) */
+/*jfm: from win trace*/
+                               /* reg 0x5f/0x60 (LE) = saturation */
+                               /* h (60): xxxx x100
+                                * l (5f): xxxx x000 */
+       data[2] = sd->colors << 3;
+       data[3] = ((sd->colors >> 2) & 0xf8) | 0x04;
+       data[4] = sd->brightness; /* reg 0x61 = brightness */
+       data[5] = 0x00;
+
+       err_code = reg_w(gspca_dev, 6);
        if (err_code < 0)
                return err_code;
 
        data[0] = 0x67;
-       data[1] = 0x13;         /* reg 103, first pixel B, disable sharpness */
-       err_code = reg_w(gspca_dev, data[0], 2);
+/*jfm: from win trace*/
+       data[1] = sd->sharpness * 4 + 3;
+       data[2] = 0x14;
+       err_code = reg_w(gspca_dev, 3);
        if (err_code < 0)
                return err_code;
 
-       /*
-        * initialize the value of MI sensor...
-        */
-       MI_buf = kzalloc(ATTR_TOTAL_MI_REG * sizeof *MI_buf, GFP_KERNEL);
-       MI_buf[REG_HW_MI_1] = 0x000a;
-       MI_buf[REG_HW_MI_2] = 0x000c;
-       MI_buf[REG_HW_MI_3] = 0x0405;
-       MI_buf[REG_HW_MI_4] = 0x0507;
-       /* mi_Attr_Reg_[REG_HW_MI_5]     = 0x01ff;//13 */
-       MI_buf[REG_HW_MI_5] = 0x0013;   /* 13 */
-       MI_buf[REG_HW_MI_6] = 0x001f;   /* vertical blanking */
-       /* mi_Attr_Reg_[REG_HW_MI_6]     = 0x0400;  // vertical blanking */
-       MI_buf[REG_HW_MI_7] = 0x0002;
-       /* mi_Attr_Reg_[REG_HW_MI_9]     = 0x015f; */
-       /* mi_Attr_Reg_[REG_HW_MI_9]     = 0x030f; */
-       MI_buf[REG_HW_MI_9] = 0x0374;
-       MI_buf[REG_HW_MI_B] = 0x0000;
-       MI_buf[REG_HW_MI_C] = 0x0000;
-       MI_buf[REG_HW_MI_D] = 0x0000;
-       MI_buf[REG_HW_MI_1E] = 0x8000;
-/* mi_Attr_Reg_[REG_HW_MI_20]    = 0x1104; */
-       MI_buf[REG_HW_MI_20] = 0x1104;  /* 0x111c; */
-       MI_buf[REG_HW_MI_2B] = 0x0008;
-/* mi_Attr_Reg_[REG_HW_MI_2C]    = 0x000f; */
-       MI_buf[REG_HW_MI_2C] = 0x001f;  /* lita suggest */
-       MI_buf[REG_HW_MI_2D] = 0x0008;
-       MI_buf[REG_HW_MI_2E] = 0x0008;
-       MI_buf[REG_HW_MI_35] = 0x0051;
-       MI_buf[REG_HW_MI_5F] = 0x0904;  /* fail to write */
-       MI_buf[REG_HW_MI_60] = 0x0000;
-       MI_buf[REG_HW_MI_61] = 0x0000;
-       MI_buf[REG_HW_MI_62] = 0x0498;
-       MI_buf[REG_HW_MI_63] = 0x0000;
-       MI_buf[REG_HW_MI_64] = 0x0000;
-       MI_buf[REG_HW_MI_F1] = 0x0001;
-       /* changing while setting up the different value of dx/dy */
-
-       if (gspca_dev->width != 1280) {
-               MI_buf[0x01] = 0x010a;
-               MI_buf[0x02] = 0x014c;
-               MI_buf[0x03] = 0x01e5;
-               MI_buf[0x04] = 0x0287;
-       }
-       MI_buf[0x20] = 0x1104;
-
-       bulk_w(gspca_dev, MI_buf + 1, 1);
-       bulk_w(gspca_dev, MI_buf + 2, 2);
-       bulk_w(gspca_dev, MI_buf + 3, 3);
-       bulk_w(gspca_dev, MI_buf + 4, 4);
-       bulk_w(gspca_dev, MI_buf + 5, 5);
-       bulk_w(gspca_dev, MI_buf + 6, 6);
-       bulk_w(gspca_dev, MI_buf + 7, 7);
-       bulk_w(gspca_dev, MI_buf + 9, 9);
-       bulk_w(gspca_dev, MI_buf + 0x0b, 0x0b);
-       bulk_w(gspca_dev, MI_buf + 0x0c, 0x0c);
-       bulk_w(gspca_dev, MI_buf + 0x0d, 0x0d);
-       bulk_w(gspca_dev, MI_buf + 0x1e, 0x1e);
-       bulk_w(gspca_dev, MI_buf + 0x20, 0x20);
-       bulk_w(gspca_dev, MI_buf + 0x2b, 0x2b);
-       bulk_w(gspca_dev, MI_buf + 0x2c, 0x2c);
-       bulk_w(gspca_dev, MI_buf + 0x2d, 0x2d);
-       bulk_w(gspca_dev, MI_buf + 0x2e, 0x2e);
-       bulk_w(gspca_dev, MI_buf + 0x35, 0x35);
-       bulk_w(gspca_dev, MI_buf + 0x5f, 0x5f);
-       bulk_w(gspca_dev, MI_buf + 0x60, 0x60);
-       bulk_w(gspca_dev, MI_buf + 0x61, 0x61);
-       bulk_w(gspca_dev, MI_buf + 0x62, 0x62);
-       bulk_w(gspca_dev, MI_buf + 0x63, 0x63);
-       bulk_w(gspca_dev, MI_buf + 0x64, 0x64);
-       bulk_w(gspca_dev, MI_buf + 0xf1, 0xf1);
-       kfree(MI_buf);
-
-       intpipe = usb_sndintpipe(gspca_dev->dev, 0);
-       err_code = usb_clear_halt(gspca_dev->dev, intpipe);
+       data[0] = 0x69;
+       data[1] = 0x2f;
+       data[2] = 0x28;
+       data[3] = 0x42;
+       err_code = reg_w(gspca_dev, 4);
+       if (err_code < 0)
+               return err_code;
+
+       data[0] = 0x63;
+       data[1] = 0x07;
+       err_code = reg_w(gspca_dev, 2);
+/*jfm: win trace - many writes here to reg 0x64*/
+       if (err_code < 0)
+               return err_code;
+
+       /* initialize the MI sensor */
+       for (i = 0; i < sizeof mi_data; i++)
+               mi_w(gspca_dev, i + 1, mi_data[i]);
 
        data[0] = 0x00;
        data[1] = 0x4d;         /* ISOC transfering enable... */
-       reg_w(gspca_dev, data[0], 2);
-       return err_code;
+       reg_w(gspca_dev, 2);
+       return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -336,11 +310,18 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 
        gspca_dev->usb_buf[0] = 1;
        gspca_dev->usb_buf[1] = 0;
-       result = reg_w(gspca_dev, gspca_dev->usb_buf[0], 2);
+       result = reg_w(gspca_dev, 2);
        if (result < 0)
                PDEBUG(D_ERR, "Camera Stop failed");
 }
 
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       kfree(sd->jpeg_hdr);
+}
+
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
@@ -363,16 +344,16 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                            || data[5 + p] == 0x65
                            || data[5 + p] == 0x66
                            || data[5 + p] == 0x67) {
-                               PDEBUG(D_PACK, "sof offset: %d leng: %d",
+                               PDEBUG(D_PACK, "sof offset: %d len: %d",
                                        p, len);
                                frame = gspca_frame_add(gspca_dev, LAST_PACKET,
-                                                       frame, data, 0);
+                                                       frame, data, p);
 
                                /* put the JPEG header */
-                               jpeg_put_header(gspca_dev, frame,
-                                               sd->qindex, 0x21);
-                               data += 16;
-                               len -= 16;
+                               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                                       sd->jpeg_hdr, JPEG_HDR_SZ);
+                               data += p + 16;
+                               len -= p + 16;
                                break;
                        }
                }
@@ -380,6 +361,121 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
+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) {
+               gspca_dev->usb_buf[0] = 0x61;
+               gspca_dev->usb_buf[1] = val;
+               reg_w(gspca_dev, 2);
+       }
+       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_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->colors = val;
+       if (gspca_dev->streaming) {
+
+               /* see sd_start */
+               gspca_dev->usb_buf[0] = 0x5f;
+               gspca_dev->usb_buf[1] = sd->colors << 3;
+               gspca_dev->usb_buf[2] = ((sd->colors >> 2) & 0xf8) | 0x04;
+               reg_w(gspca_dev, 3);
+       }
+       return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->colors;
+       return 0;
+}
+
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->gamma = val;
+       if (gspca_dev->streaming) {
+               gspca_dev->usb_buf[0] = 0x06;
+               gspca_dev->usb_buf[1] = val * 0x40;
+               reg_w(gspca_dev, 2);
+       }
+       return 0;
+}
+
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->gamma;
+       return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->sharpness = val;
+       if (gspca_dev->streaming) {
+               gspca_dev->usb_buf[0] = 0x67;
+               gspca_dev->usb_buf[1] = val * 4 + 3;
+               reg_w(gspca_dev, 2);
+       }
+       return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->sharpness;
+       return 0;
+}
+
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (jcomp->quality < QUALITY_MIN)
+               sd->quality = QUALITY_MIN;
+       else if (jcomp->quality > QUALITY_MAX)
+               sd->quality = QUALITY_MAX;
+       else
+               sd->quality = jcomp->quality;
+       if (gspca_dev->streaming)
+               jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+       return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       memset(jcomp, 0, sizeof *jcomp);
+       jcomp->quality = sd->quality;
+       jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+                       | V4L2_JPEG_MARKER_DQT;
+       return 0;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
@@ -389,7 +485,10 @@ static const struct sd_desc sd_desc = {
        .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
+       .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
+       .get_jcomp = sd_get_jcomp,
+       .set_jcomp = sd_set_jcomp,
 };
 
 /* -- module initialisation -- */
@@ -421,8 +520,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/video/gspca/mr97310a.c
new file mode 100644 (file)
index 0000000..2a901a4
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * Mars MR97310A library
+ *
+ * Copyright (C) 2009 Kyle Guinn <elyk03@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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 "mr97310a"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Kyle Guinn <elyk03@gmail.com>");
+MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;  /* !! must be the first item */
+       u8 sof_read;
+};
+
+/* V4L2 controls supported by the driver */
+static struct ctrl sd_ctrls[] = {
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+       {160, 120, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 4},
+       {176, 144, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
+               .bytesperline = 176,
+               .sizeimage = 176 * 144,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 3},
+       {320, 240, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 2},
+       {352, 288, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
+               .bytesperline = 352,
+               .sizeimage = 352 * 288,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1},
+       {640, 480, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0},
+};
+
+/* the bytes to write are in gspca_dev->usb_buf */
+static int reg_w(struct gspca_dev *gspca_dev, int len)
+{
+       int rc;
+
+       rc = usb_bulk_msg(gspca_dev->dev,
+                         usb_sndbulkpipe(gspca_dev->dev, 4),
+                         gspca_dev->usb_buf, len, NULL, 500);
+       if (rc < 0)
+               PDEBUG(D_ERR, "reg write [%02x] error %d",
+                      gspca_dev->usb_buf[0], rc);
+       return rc;
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                    const struct usb_device_id *id)
+{
+       struct cam *cam;
+
+       cam = &gspca_dev->cam;
+       cam->cam_mode = vga_mode;
+       cam->nmodes = ARRAY_SIZE(vga_mode);
+       return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       return 0;
+}
+
+static int sd_start(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 */
+
+       data[0] = 0x01;
+       data[1] = 0x01;
+       err_code = reg_w(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;
+
+       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 */
+               data[4] = 0x78;  /* reg 3, V size */
+               data[6] = 0x04;  /* reg 5, H start */
+               data[8] = 0x03;  /* reg 7, V start */
+               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 */
+               break;
+       }
+
+       err_code = reg_w(gspca_dev, 11);
+       if (err_code < 0)
+               return err_code;
+
+       data[0] = 0x0a;
+       data[1] = 0x80;
+       err_code = reg_w(gspca_dev, 2);
+       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;
+
+       data[0] = 0x1b;
+       data[1] = 0x00;
+       err_code = reg_w(gspca_dev, 2);
+       if (err_code < 0)
+               return err_code;
+
+       data[0] = 0x15;
+       data[1] = 0x16;
+       err_code = reg_w(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;
+
+       data[0] = 0x17;
+       data[1] = 0x3a;
+       err_code = reg_w(gspca_dev, 2);
+       if (err_code < 0)
+               return err_code;
+
+       data[0] = 0x18;
+       data[1] = 0x68;
+       err_code = reg_w(gspca_dev, 2);
+       if (err_code < 0)
+               return err_code;
+
+       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);
+       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 (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;
+
+       data[0] = 0x1f;
+       data[1] = 0x04;
+       data[2] = 0x11;
+       data[3] = 0x01;
+       err_code = reg_w(gspca_dev, 4);
+       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);
+       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 (err_code < 0)
+               return err_code;
+
+       data[0] = 0x00;
+       data[1] = 0x4d;  /* ISOC transfering enable... */
+       err_code = reg_w(gspca_dev, 2);
+       return err_code;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       int result;
+
+       gspca_dev->usb_buf[0] = 1;
+       gspca_dev->usb_buf[1] = 0;
+       result = reg_w(gspca_dev, 2);
+       if (result < 0)
+               PDEBUG(D_ERR, "Camera Stop failed");
+}
+
+/* Include pac common sof detection functions */
+#include "pac_common.h"
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,    /* target */
+                       __u8 *data,                   /* isoc packet */
+                       int len)                      /* iso packet length */
+{
+       unsigned char *sof;
+
+       sof = pac_find_sof(gspca_dev, data, len);
+       if (sof) {
+               int n;
+
+               /* finish decoding current frame */
+               n = sof - data;
+               if (n > sizeof pac_sof_marker)
+                       n -= sizeof pac_sof_marker;
+               else
+                       n = 0;
+               frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+                                       data, n);
+               /* Start next frame. */
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                       pac_sof_marker, sizeof pac_sof_marker);
+               len -= sof - data;
+               data = sof;
+       }
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .init = sd_init,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x08ca, 0x0111)},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- 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)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       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 ee232956c812523aa050fa77d7f129b257f3db79..1fff37b79891253bbe24a88d761dd30b1ab2eb8b 100644 (file)
@@ -1360,7 +1360,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        }
 
        cam = &gspca_dev->cam;
-       cam->epaddr = OV511_ENDPOINT_ADDRESS;
        if (!sd->sif) {
                cam->cam_mode = vga_mode;
                cam->nmodes = ARRAY_SIZE(vga_mode);
@@ -2177,8 +2176,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index 3bf15e4016933ca3b651621cbf29cbb4c36b7873..19e0bc60de14aecf95708b7d6c922b49e063ce3a 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * ov534/ov772x gspca driver
+ * ov534 gspca driver
  * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it>
  * Copyright (C) 2008 Jim Paris <jim@jtan.com>
+ * Copyright (C) 2009 Jean-Francois Moine http://moinejf.free.fr
  *
  * Based on a prototype written by Mark Ferrell <majortrips@gmail.com>
  * USB protocol reverse engineered by Jim Paris <jim@jtan.com>
@@ -26,7 +27,7 @@
 
 #include "gspca.h"
 
-#define OV534_REG_ADDRESS      0xf1    /* ? */
+#define OV534_REG_ADDRESS      0xf1    /* sensor address */
 #define OV534_REG_SUBADDR      0xf2
 #define OV534_REG_WRITE                0xf3
 #define OV534_REG_READ         0xf4
@@ -46,9 +47,13 @@ MODULE_LICENSE("GPL");
 /* specific webcam descriptor */
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
-       __u32 last_fid;
        __u32 last_pts;
-       int frame_rate;
+       u16 last_fid;
+       u8 frame_rate;
+
+       u8 sensor;
+#define SENSOR_OV772X 0
+#define SENSOR_OV965X 1
 };
 
 /* V4L2 controls supported by the driver */
@@ -63,114 +68,7 @@ static const struct v4l2_pix_format vga_mode[] = {
         .priv = 0},
 };
 
-static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
-{
-       struct usb_device *udev = gspca_dev->dev;
-       int ret;
-
-       PDEBUG(D_USBO, "reg=0x%04x, val=0%02x", reg, val);
-       gspca_dev->usb_buf[0] = val;
-       ret = usb_control_msg(udev,
-                             usb_sndctrlpipe(udev, 0),
-                             0x1,
-                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                             0x0, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
-       if (ret < 0)
-               PDEBUG(D_ERR, "write failed");
-}
-
-static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
-{
-       struct usb_device *udev = gspca_dev->dev;
-       int ret;
-
-       ret = usb_control_msg(udev,
-                             usb_rcvctrlpipe(udev, 0),
-                             0x1,
-                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                             0x0, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
-       PDEBUG(D_USBI, "reg=0x%04x, data=0x%02x", reg, gspca_dev->usb_buf[0]);
-       if (ret < 0)
-               PDEBUG(D_ERR, "read failed");
-       return gspca_dev->usb_buf[0];
-}
-
-/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7.
- * (direction and output)? */
-static void ov534_set_led(struct gspca_dev *gspca_dev, int status)
-{
-       u8 data;
-
-       PDEBUG(D_CONF, "led status: %d", status);
-
-       data = ov534_reg_read(gspca_dev, 0x21);
-       data |= 0x80;
-       ov534_reg_write(gspca_dev, 0x21, data);
-
-       data = ov534_reg_read(gspca_dev, 0x23);
-       if (status)
-               data |= 0x80;
-       else
-               data &= ~(0x80);
-
-       ov534_reg_write(gspca_dev, 0x23, data);
-}
-
-static int sccb_check_status(struct gspca_dev *gspca_dev)
-{
-       u8 data;
-       int i;
-
-       for (i = 0; i < 5; i++) {
-               data = ov534_reg_read(gspca_dev, OV534_REG_STATUS);
-
-               switch (data) {
-               case 0x00:
-                       return 1;
-               case 0x04:
-                       return 0;
-               case 0x03:
-                       break;
-               default:
-                       PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5",
-                              data, i + 1);
-               }
-       }
-       return 0;
-}
-
-static void sccb_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
-{
-       PDEBUG(D_USBO, "reg: 0x%04x, val: 0x%02x", reg, val);
-       ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
-       ov534_reg_write(gspca_dev, OV534_REG_WRITE, val);
-       ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
-
-       if (!sccb_check_status(gspca_dev))
-               PDEBUG(D_ERR, "sccb_reg_write failed");
-}
-
-#ifdef GSPCA_DEBUG
-static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg)
-{
-       ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
-       ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);
-       if (!sccb_check_status(gspca_dev))
-               PDEBUG(D_ERR, "sccb_reg_read failed 1");
-
-       ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2);
-       if (!sccb_check_status(gspca_dev))
-               PDEBUG(D_ERR, "sccb_reg_read failed 2");
-
-       return ov534_reg_read(gspca_dev, OV534_REG_READ);
-}
-#endif
-
-static const __u8 ov534_reg_initdata[][2] = {
-       { 0xe7, 0x3a },
-
-       { OV534_REG_ADDRESS, 0x42 }, /* select OV772x sensor */
-
+static const u8 bridge_init_ov722x[][2] = {
        { 0xc2, 0x0c },
        { 0x88, 0xf8 },
        { 0xc3, 0x69 },
@@ -228,7 +126,7 @@ static const __u8 ov534_reg_initdata[][2] = {
        { 0xc2, 0x0c },
 };
 
-static const __u8 ov772x_reg_initdata[][2] = {
+static const u8 sensor_init_ov722x[][2] = {
        { 0x12, 0x80 },
        { 0x11, 0x01 },
 
@@ -311,6 +209,456 @@ static const __u8 ov772x_reg_initdata[][2] = {
        { 0x0c, 0xd0 }
 };
 
+static const u8 bridge_init_ov965x[][2] = {
+       {0x88, 0xf8},
+       {0x89, 0xff},
+       {0x76, 0x03},
+       {0x92, 0x03},
+       {0x95, 0x10},
+       {0xe2, 0x00},
+       {0xe7, 0x3e},
+       {0x8d, 0x1c},
+       {0x8e, 0x00},
+       {0x8f, 0x00},
+       {0x1f, 0x00},
+       {0xc3, 0xf9},
+       {0x89, 0xff},
+       {0x88, 0xf8},
+       {0x76, 0x03},
+       {0x92, 0x01},
+       {0x93, 0x18},
+       {0x1c, 0x0a},
+       {0x1d, 0x48},
+       {0xc0, 0x50},
+       {0xc1, 0x3c},
+       {0x34, 0x05},
+       {0xc2, 0x0c},
+       {0xc3, 0xf9},
+       {0x34, 0x05},
+       {0xe7, 0x2e},
+       {0x31, 0xf9},
+       {0x35, 0x02},
+       {0xd9, 0x10},
+       {0x25, 0x42},
+       {0x94, 0x11},
+};
+
+static const u8 sensor_init_ov965x[][2] = {
+       {0x12, 0x80},   /* com7 - reset */
+       {0x00, 0x00},   /* gain */
+       {0x01, 0x80},   /* blue */
+       {0x02, 0x80},   /* red */
+       {0x03, 0x1b},   /* vref */
+       {0x04, 0x03},   /* com1 - exposure low bits */
+       {0x0b, 0x57},   /* ver */
+       {0x0e, 0x61},   /* com5 */
+       {0x0f, 0x42},   /* com6 */
+       {0x11, 0x00},   /* clkrc */
+       {0x12, 0x02},   /* com7 */
+       {0x13, 0xe7},   /* com8 - everything (AGC, AWB and AEC) */
+       {0x14, 0x28},   /* com9 */
+       {0x16, 0x24},   /* rsvd16 */
+       {0x17, 0x1d},   /* hstart*/
+       {0x18, 0xbd},   /* hstop */
+       {0x19, 0x01},   /* vstrt */
+       {0x1a, 0x81},   /* vstop*/
+       {0x1e, 0x04},   /* mvfp */
+       {0x24, 0x3c},   /* aew */
+       {0x25, 0x36},   /* aeb */
+       {0x26, 0x71},   /* vpt */
+       {0x27, 0x08},   /* bbias */
+       {0x28, 0x08},   /* gbbias */
+       {0x29, 0x15},   /* gr com */
+       {0x2a, 0x00},
+       {0x2b, 0x00},
+       {0x2c, 0x08},   /* rbias */
+       {0x32, 0xff},   /* href */
+       {0x33, 0x00},   /* chlf */
+       {0x34, 0x3f},   /* arblm */
+       {0x35, 0x00},   /* rsvd35 */
+       {0x36, 0xf8},   /* rsvd36 */
+       {0x38, 0x72},   /* acom38 */
+       {0x39, 0x57},   /* ofon */
+       {0x3a, 0x80},   /* tslb */
+       {0x3b, 0xc4},
+       {0x3d, 0x99},   /* com13 */
+       {0x3f, 0xc1},
+       {0x40, 0xc0},   /* com15 */
+       {0x41, 0x40},   /* com16 */
+       {0x42, 0xc0},
+       {0x43, 0x0a},
+       {0x44, 0xf0},
+       {0x45, 0x46},
+       {0x46, 0x62},
+       {0x47, 0x2a},
+       {0x48, 0x3c},
+       {0x4a, 0xfc},
+       {0x4b, 0xfc},
+       {0x4c, 0x7f},
+       {0x4d, 0x7f},
+       {0x4e, 0x7f},
+       {0x4f, 0x98},
+       {0x50, 0x98},
+       {0x51, 0x00},
+       {0x52, 0x28},
+       {0x53, 0x70},
+       {0x54, 0x98},
+       {0x58, 0x1a},
+       {0x59, 0x85},
+       {0x5a, 0xa9},
+       {0x5b, 0x64},
+       {0x5c, 0x84},
+       {0x5d, 0x53},
+       {0x5e, 0x0e},
+       {0x5f, 0xf0},
+       {0x60, 0xf0},
+       {0x61, 0xf0},
+       {0x62, 0x00},   /* lcc1 */
+       {0x63, 0x00},   /* lcc2 */
+       {0x64, 0x02},   /* lcc3 */
+       {0x65, 0x16},   /* lcc4 */
+       {0x66, 0x01},   /* lcc5 */
+       {0x69, 0x02},   /* hv */
+       {0x6b, 0x5a},   /* dbvl */
+       {0x6c, 0x04},
+       {0x6d, 0x55},
+       {0x6e, 0x00},
+       {0x6f, 0x9d},
+       {0x70, 0x21},
+       {0x71, 0x78},
+       {0x72, 0x00},
+       {0x73, 0x01},
+       {0x74, 0x3a},
+       {0x75, 0x35},
+       {0x76, 0x01},
+       {0x77, 0x02},
+       {0x7a, 0x12},
+       {0x7b, 0x08},
+       {0x7c, 0x16},
+       {0x7d, 0x30},
+       {0x7e, 0x5e},
+       {0x7f, 0x72},
+       {0x80, 0x82},
+       {0x81, 0x8e},
+       {0x82, 0x9a},
+       {0x83, 0xa4},
+       {0x84, 0xac},
+       {0x85, 0xb8},
+       {0x86, 0xc3},
+       {0x87, 0xd6},
+       {0x88, 0xe6},
+       {0x89, 0xf2},
+       {0x8a, 0x03},
+       {0x8c, 0x89},
+       {0x14, 0x28},   /* com9 */
+       {0x90, 0x7d},
+       {0x91, 0x7b},
+       {0x9d, 0x03},
+       {0x9e, 0x04},
+       {0x9f, 0x7a},
+       {0xa0, 0x79},
+       {0xa1, 0x40},   /* aechm */
+       {0xa4, 0x50},
+       {0xa5, 0x68},   /* com26 */
+       {0xa6, 0x4a},
+       {0xa8, 0xc1},   /* acoma8 */
+       {0xa9, 0xef},   /* acoma9 */
+       {0xaa, 0x92},
+       {0xab, 0x04},
+       {0xac, 0x80},
+       {0xad, 0x80},
+       {0xae, 0x80},
+       {0xaf, 0x80},
+       {0xb2, 0xf2},
+       {0xb3, 0x20},
+       {0xb4, 0x20},
+       {0xb5, 0x00},
+       {0xb6, 0xaf},
+       {0xbb, 0xae},
+       {0xbc, 0x7f},
+       {0xdb, 0x7f},
+       {0xbe, 0x7f},
+       {0xbf, 0x7f},
+       {0xc0, 0xe2},
+       {0xc1, 0xc0},
+       {0xc2, 0x01},
+       {0xc3, 0x4e},
+       {0xc6, 0x85},
+       {0xc7, 0x80},
+       {0xc9, 0xe0},
+       {0xca, 0xe8},
+       {0xcb, 0xf0},
+       {0xcc, 0xd8},
+       {0xcd, 0xf1},
+       {0x4f, 0x98},
+       {0x50, 0x98},
+       {0x51, 0x00},
+       {0x52, 0x28},
+       {0x53, 0x70},
+       {0x54, 0x98},
+       {0x58, 0x1a},
+       {0xff, 0x41},   /* read 41, write ff 00 */
+       {0x41, 0x40},   /* com16 */
+       {0xc5, 0x03},
+       {0x6a, 0x02},
+
+       {0x12, 0x62},   /* com7 - VGA + CIF */
+       {0x36, 0xfa},   /* rsvd36 */
+       {0x69, 0x0a},   /* hv */
+       {0x8c, 0x89},   /* com22 */
+       {0x14, 0x28},   /* com9 */
+       {0x3e, 0x0c},
+       {0x41, 0x40},   /* com16 */
+       {0x72, 0x00},
+       {0x73, 0x00},
+       {0x74, 0x3a},
+       {0x75, 0x35},
+       {0x76, 0x01},
+       {0xc7, 0x80},
+       {0x03, 0x12},   /* vref */
+       {0x17, 0x16},   /* hstart */
+       {0x18, 0x02},   /* hstop */
+       {0x19, 0x01},   /* vstrt */
+       {0x1a, 0x3d},   /* vstop */
+       {0x32, 0xff},   /* href */
+       {0xc0, 0xaa},
+};
+
+static const u8 bridge_init_ov965x_2[][2] = {
+       {0x94, 0xaa},
+       {0xf1, 0x60},
+       {0xe5, 0x04},
+       {0xc0, 0x50},
+       {0xc1, 0x3c},
+       {0x8c, 0x00},
+       {0x8d, 0x1c},
+       {0x34, 0x05},
+
+       {0xc2, 0x0c},
+       {0xc3, 0xf9},
+       {0xda, 0x01},
+       {0x50, 0x00},
+       {0x51, 0xa0},
+       {0x52, 0x3c},
+       {0x53, 0x00},
+       {0x54, 0x00},
+       {0x55, 0x00},
+       {0x57, 0x00},
+       {0x5c, 0x00},
+       {0x5a, 0xa0},
+       {0x5b, 0x78},
+       {0x35, 0x02},
+       {0xd9, 0x10},
+       {0x94, 0x11},
+};
+
+static const u8 sensor_init_ov965x_2[][2] = {
+       {0x3b, 0xc4},
+       {0x1e, 0x04},   /* mvfp */
+       {0x13, 0xe0},   /* com8 */
+       {0x00, 0x00},   /* gain */
+       {0x13, 0xe7},   /* com8 - everything (AGC, AWB and AEC) */
+       {0x11, 0x03},   /* clkrc */
+       {0x6b, 0x5a},   /* dblv */
+       {0x6a, 0x05},
+       {0xc5, 0x07},
+       {0xa2, 0x4b},
+       {0xa3, 0x3e},
+       {0x2d, 0x00},
+       {0xff, 0x42},   /* read 42, write ff 00 */
+       {0x42, 0xc0},
+       {0x2d, 0x00},
+       {0xff, 0x42},   /* read 42, write ff 00 */
+       {0x42, 0xc1},
+       {0x3f, 0x01},
+       {0xff, 0x42},   /* read 42, write ff 00 */
+       {0x42, 0xc1},
+       {0x4f, 0x98},
+       {0x50, 0x98},
+       {0x51, 0x00},
+       {0x52, 0x28},
+       {0x53, 0x70},
+       {0x54, 0x98},
+       {0x58, 0x1a},
+       {0xff, 0x41},   /* read 41, write ff 00 */
+       {0x41, 0x40},   /* com16 */
+       {0x56, 0x40},
+       {0x55, 0x8f},
+       {0x10, 0x25},   /* aech - exposure high bits */
+       {0xff, 0x13},   /* read 13, write ff 00 */
+       {0x13, 0xe7},   /* com8 - everything (AGC, AWB and AEC) */
+};
+
+static const u8 bridge_start_ov965x[][2] = {
+       {0xc2, 0x4c},
+       {0xc3, 0xf9},
+       {0x50, 0x00},
+       {0x51, 0xa0},
+       {0x52, 0x78},
+       {0x53, 0x00},
+       {0x54, 0x00},
+       {0x55, 0x00},
+       {0x57, 0x00},
+       {0x5c, 0x00},
+       {0x5a, 0x28},
+       {0x5b, 0x1e},
+       {0x35, 0x00},
+       {0xd9, 0x21},
+       {0x94, 0x11},
+};
+
+static const u8 sensor_start_ov965x[][2] = {
+       {0x3b, 0xe4},
+       {0x1e, 0x04},   /* mvfp */
+       {0x13, 0xe0},   /* com8 */
+       {0x00, 0x00},
+       {0x13, 0xe7},   /* com8 - everything (AGC, AWB and AEC) */
+       {0x11, 0x01},   /* clkrc */
+       {0x6b, 0x5a},   /* dblv */
+       {0x6a, 0x02},
+       {0xc5, 0x03},
+       {0xa2, 0x96},
+       {0xa3, 0x7d},
+       {0xff, 0x13},   /* read 13, write ff 00 */
+       {0x13, 0xe7},
+       {0x3a, 0x80},
+       {0xff, 0x42},   /* read 42, write ff 00 */
+       {0x42, 0xc1},
+};
+
+
+static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
+{
+       struct usb_device *udev = gspca_dev->dev;
+       int ret;
+
+       PDEBUG(D_USBO, "reg=0x%04x, val=0%02x", reg, val);
+       gspca_dev->usb_buf[0] = val;
+       ret = usb_control_msg(udev,
+                             usb_sndctrlpipe(udev, 0),
+                             0x01,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
+       if (ret < 0)
+               PDEBUG(D_ERR, "write failed");
+}
+
+static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
+{
+       struct usb_device *udev = gspca_dev->dev;
+       int ret;
+
+       ret = usb_control_msg(udev,
+                             usb_rcvctrlpipe(udev, 0),
+                             0x01,
+                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
+       PDEBUG(D_USBI, "reg=0x%04x, data=0x%02x", reg, gspca_dev->usb_buf[0]);
+       if (ret < 0)
+               PDEBUG(D_ERR, "read failed");
+       return gspca_dev->usb_buf[0];
+}
+
+/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7.
+ * (direction and output)? */
+static void ov534_set_led(struct gspca_dev *gspca_dev, int status)
+{
+       u8 data;
+
+       PDEBUG(D_CONF, "led status: %d", status);
+
+       data = ov534_reg_read(gspca_dev, 0x21);
+       data |= 0x80;
+       ov534_reg_write(gspca_dev, 0x21, data);
+
+       data = ov534_reg_read(gspca_dev, 0x23);
+       if (status)
+               data |= 0x80;
+       else
+               data &= ~0x80;
+
+       ov534_reg_write(gspca_dev, 0x23, data);
+
+       if (!status) {
+               data = ov534_reg_read(gspca_dev, 0x21);
+               data &= ~0x80;
+               ov534_reg_write(gspca_dev, 0x21, data);
+       }
+}
+
+static int sccb_check_status(struct gspca_dev *gspca_dev)
+{
+       u8 data;
+       int i;
+
+       for (i = 0; i < 5; i++) {
+               data = ov534_reg_read(gspca_dev, OV534_REG_STATUS);
+
+               switch (data) {
+               case 0x00:
+                       return 1;
+               case 0x04:
+                       return 0;
+               case 0x03:
+                       break;
+               default:
+                       PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5",
+                              data, i + 1);
+               }
+       }
+       return 0;
+}
+
+static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val)
+{
+       PDEBUG(D_USBO, "reg: 0x%02x, val: 0x%02x", reg, val);
+       ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
+       ov534_reg_write(gspca_dev, OV534_REG_WRITE, val);
+       ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
+
+       if (!sccb_check_status(gspca_dev))
+               PDEBUG(D_ERR, "sccb_reg_write failed");
+}
+
+static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg)
+{
+       ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
+       ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);
+       if (!sccb_check_status(gspca_dev))
+               PDEBUG(D_ERR, "sccb_reg_read failed 1");
+
+       ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2);
+       if (!sccb_check_status(gspca_dev))
+               PDEBUG(D_ERR, "sccb_reg_read failed 2");
+
+       return ov534_reg_read(gspca_dev, OV534_REG_READ);
+}
+
+/* output a bridge sequence (reg - val) */
+static void reg_w_array(struct gspca_dev *gspca_dev,
+                       const u8 (*data)[2], int len)
+{
+       while (--len >= 0) {
+               ov534_reg_write(gspca_dev, (*data)[0], (*data)[1]);
+               data++;
+       }
+}
+
+/* output a sensor sequence (reg - val) */
+static void sccb_w_array(struct gspca_dev *gspca_dev,
+                       const u8 (*data)[2], int len)
+{
+       while (--len >= 0) {
+               if ((*data)[0] != 0xff) {
+                       sccb_reg_write(gspca_dev, (*data)[0], (*data)[1]);
+               } else {
+                       sccb_reg_read(gspca_dev, (*data)[1]);
+                       sccb_reg_write(gspca_dev, 0xff, 0x00);
+               }
+               data++;
+       }
+}
+
 /* set framerate */
 static void ov534_set_frame_rate(struct gspca_dev *gspca_dev)
 {
@@ -346,40 +694,17 @@ static void ov534_set_frame_rate(struct gspca_dev *gspca_dev)
        PDEBUG(D_PROBE, "frame_rate: %d", fr);
 }
 
-/* setup method */
-static void ov534_setup(struct gspca_dev *gspca_dev)
-{
-       int i;
-
-       /* Initialize bridge chip */
-       for (i = 0; i < ARRAY_SIZE(ov534_reg_initdata); i++)
-               ov534_reg_write(gspca_dev, ov534_reg_initdata[i][0],
-                               ov534_reg_initdata[i][1]);
-
-       PDEBUG(D_PROBE, "sensor is ov%02x%02x",
-               sccb_reg_read(gspca_dev, 0x0a),
-               sccb_reg_read(gspca_dev, 0x0b));
-
-       ov534_set_led(gspca_dev, 1);
-
-       /* Initialize sensor */
-       for (i = 0; i < ARRAY_SIZE(ov772x_reg_initdata); i++)
-               sccb_reg_write(gspca_dev, ov772x_reg_initdata[i][0],
-                              ov772x_reg_initdata[i][1]);
-
-       ov534_reg_write(gspca_dev, 0xe0, 0x09);
-       ov534_set_led(gspca_dev, 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;
 
+       sd->sensor = id->driver_info;
+
        cam = &gspca_dev->cam;
 
-       cam->epaddr = 0x01;
        cam->cam_mode = vga_mode;
        cam->nmodes = ARRAY_SIZE(vga_mode);
 
@@ -392,26 +717,102 @@ static int sd_config(struct gspca_dev *gspca_dev,
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
-       ov534_setup(gspca_dev);
-       ov534_set_frame_rate(gspca_dev);
+       struct sd *sd = (struct sd *) gspca_dev;
+       u16 sensor_id;
+       static const u8 sensor_addr[2] = {
+               0x42,                   /* 0 SENSOR_OV772X */
+               0x60,                   /* 1 SENSOR_OV965X */
+       };
+
+       /* reset bridge */
+       ov534_reg_write(gspca_dev, 0xe7, 0x3a);
+       ov534_reg_write(gspca_dev, 0xe0, 0x08);
+       msleep(100);
+
+       /* initialize the sensor address */
+       ov534_reg_write(gspca_dev, OV534_REG_ADDRESS,
+                               sensor_addr[sd->sensor]);
+
+       /* reset sensor */
+       sccb_reg_write(gspca_dev, 0x12, 0x80);
+       msleep(10);
+
+       /* probe the sensor */
+       sccb_reg_read(gspca_dev, 0x0a);
+       sensor_id = sccb_reg_read(gspca_dev, 0x0a) << 8;
+       sccb_reg_read(gspca_dev, 0x0b);
+       sensor_id |= sccb_reg_read(gspca_dev, 0x0b);
+       PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id);
+
+       /* initialize */
+       switch (sd->sensor) {
+       case SENSOR_OV772X:
+               reg_w_array(gspca_dev, bridge_init_ov722x,
+                               ARRAY_SIZE(bridge_init_ov722x));
+               ov534_set_led(gspca_dev, 1);
+               sccb_w_array(gspca_dev, sensor_init_ov722x,
+                               ARRAY_SIZE(sensor_init_ov722x));
+               ov534_reg_write(gspca_dev, 0xe0, 0x09);
+               ov534_set_led(gspca_dev, 0);
+               ov534_set_frame_rate(gspca_dev);
+               break;
+       default:
+/*     case SENSOR_OV965X: */
+               reg_w_array(gspca_dev, bridge_init_ov965x,
+                               ARRAY_SIZE(bridge_init_ov965x));
+               sccb_w_array(gspca_dev, sensor_init_ov965x,
+                               ARRAY_SIZE(sensor_init_ov965x));
+               reg_w_array(gspca_dev, bridge_init_ov965x_2,
+                               ARRAY_SIZE(bridge_init_ov965x_2));
+               sccb_w_array(gspca_dev, sensor_init_ov965x_2,
+                               ARRAY_SIZE(sensor_init_ov965x_2));
+               ov534_reg_write(gspca_dev, 0xe0, 0x00);
+               ov534_reg_write(gspca_dev, 0xe0, 0x01);
+               ov534_set_led(gspca_dev, 0);
+               ov534_reg_write(gspca_dev, 0xe0, 0x00);
+       }
 
        return 0;
 }
 
 static int sd_start(struct gspca_dev *gspca_dev)
 {
-       /* start streaming data */
-       ov534_set_led(gspca_dev, 1);
-       ov534_reg_write(gspca_dev, 0xe0, 0x00);
+       struct sd *sd = (struct sd *) gspca_dev;
 
+       switch (sd->sensor) {
+       case SENSOR_OV772X:
+               ov534_set_led(gspca_dev, 1);
+               ov534_reg_write(gspca_dev, 0xe0, 0x00);
+               break;
+       default:
+/*     case SENSOR_OV965X: */
+               reg_w_array(gspca_dev, bridge_start_ov965x,
+                               ARRAY_SIZE(bridge_start_ov965x));
+               sccb_w_array(gspca_dev, sensor_start_ov965x,
+                               ARRAY_SIZE(sensor_start_ov965x));
+               ov534_reg_write(gspca_dev, 0xe0, 0x00);
+               ov534_set_led(gspca_dev, 1);
+/*fixme: other sensor start omitted*/
+       }
        return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-       /* stop streaming data */
-       ov534_reg_write(gspca_dev, 0xe0, 0x09);
-       ov534_set_led(gspca_dev, 0);
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->sensor) {
+       case SENSOR_OV772X:
+               ov534_reg_write(gspca_dev, 0xe0, 0x09);
+               ov534_set_led(gspca_dev, 0);
+               break;
+       default:
+/*     case SENSOR_OV965X: */
+               ov534_reg_write(gspca_dev, 0xe0, 0x01);
+               ov534_set_led(gspca_dev, 0);
+               ov534_reg_write(gspca_dev, 0xe0, 0x00);
+               break;
+       }
 }
 
 /* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
@@ -429,75 +830,75 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
 {
        struct sd *sd = (struct sd *) gspca_dev;
        __u32 this_pts;
-       int this_fid;
+       u16 this_fid;
        int remaining_len = len;
-       __u8 *next_data = data;
 
-scan_next:
-       if (remaining_len <= 0)
-               return;
-
-       data = next_data;
-       len = min(remaining_len, 2048);
-       remaining_len -= len;
-       next_data += len;
-
-       /* Payloads are prefixed with a UVC-style header.  We
-          consider a frame to start when the FID toggles, or the PTS
-          changes.  A frame ends when EOF is set, and we've received
-          the correct number of bytes. */
-
-       /* Verify UVC header.  Header length is always 12 */
-       if (data[0] != 12 || len < 12) {
-               PDEBUG(D_PACK, "bad header");
-               goto discard;
-       }
-
-       /* Check errors */
-       if (data[1] & UVC_STREAM_ERR) {
-               PDEBUG(D_PACK, "payload error");
-               goto discard;
-       }
+       do {
+               len = min(remaining_len, 2040);         /*fixme: was 2048*/
 
-       /* Extract PTS and FID */
-       if (!(data[1] & UVC_STREAM_PTS)) {
-               PDEBUG(D_PACK, "PTS not present");
-               goto discard;
-       }
-       this_pts = (data[5] << 24) | (data[4] << 16) | (data[3] << 8) | data[2];
-       this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0;
-
-       /* If PTS or FID has changed, start a new frame. */
-       if (this_pts != sd->last_pts || this_fid != sd->last_fid) {
-               gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
-               sd->last_pts = this_pts;
-               sd->last_fid = this_fid;
-       }
+               /* Payloads are prefixed with a UVC-style header.  We
+                  consider a frame to start when the FID toggles, or the PTS
+                  changes.  A frame ends when EOF is set, and we've received
+                  the correct number of bytes. */
 
-       /* Add the data from this payload */
-       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-                               data + 12, len - 12);
+               /* Verify UVC header.  Header length is always 12 */
+               if (data[0] != 12 || len < 12) {
+                       PDEBUG(D_PACK, "bad header");
+                       goto discard;
+               }
 
-       /* If this packet is marked as EOF, end the frame */
-       if (data[1] & UVC_STREAM_EOF) {
-               sd->last_pts = 0;
+               /* Check errors */
+               if (data[1] & UVC_STREAM_ERR) {
+                       PDEBUG(D_PACK, "payload error");
+                       goto discard;
+               }
 
-               if ((frame->data_end - frame->data) !=
-                   (gspca_dev->width * gspca_dev->height * 2)) {
-                       PDEBUG(D_PACK, "short frame");
+               /* Extract PTS and FID */
+               if (!(data[1] & UVC_STREAM_PTS)) {
+                       PDEBUG(D_PACK, "PTS not present");
                        goto discard;
                }
+               this_pts = (data[5] << 24) | (data[4] << 16)
+                                               | (data[3] << 8) | data[2];
+               this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0;
+
+               /* If PTS or FID has changed, start a new frame. */
+               if (this_pts != sd->last_pts || this_fid != sd->last_fid) {
+                       gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                                       NULL, 0);
+                       sd->last_pts = this_pts;
+                       sd->last_fid = this_fid;
+               }
 
-               gspca_frame_add(gspca_dev, LAST_PACKET, frame, NULL, 0);
-       }
+               /* Add the data from this payload */
+               gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                                       data + 12, len - 12);
 
-       /* Done this payload */
-       goto scan_next;
+               /* If this packet is marked as EOF, end the frame */
+               if (data[1] & UVC_STREAM_EOF) {
+                       sd->last_pts = 0;
+
+                       if (frame->data_end - frame->data !=
+                           gspca_dev->width * gspca_dev->height * 2) {
+                               PDEBUG(D_PACK, "short frame");
+                               goto discard;
+                       }
+
+                       frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+                                               NULL, 0);
+               }
+
+               /* Done this payload */
+               goto scan_next;
 
 discard:
-       /* Discard data until a new frame starts. */
-       gspca_frame_add(gspca_dev, DISCARD_PACKET, frame, NULL, 0);
-       goto scan_next;
+               /* Discard data until a new frame starts. */
+               gspca_frame_add(gspca_dev, DISCARD_PACKET, frame, NULL, 0);
+
+scan_next:
+               remaining_len -= len;
+               data += len;
+       } while (remaining_len > 0);
 }
 
 /* get stream parameters (framerate) */
@@ -556,9 +957,8 @@ static const struct sd_desc sd_desc = {
 
 /* -- module initialisation -- */
 static const __devinitdata struct usb_device_id device_table[] = {
-       {USB_DEVICE(0x06f8, 0x3002)},   /* Hercules Blog Webcam */
-       {USB_DEVICE(0x06f8, 0x3003)},   /* Hercules Dualpix HD Weblog */
-       {USB_DEVICE(0x1415, 0x2000)},   /* Sony HD Eye for PS3 (SLEH 00201) */
+       {USB_DEVICE(0x06f8, 0x3003), .driver_info = SENSOR_OV965X},
+       {USB_DEVICE(0x1415, 0x2000), .driver_info = SENSOR_OV772X},
        {}
 };
 
@@ -585,8 +985,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index c90ac852bac07eace63ab95756796d8a804f3693..95a97ab684cd3fdba219f7d54b6ef03fe55588ca 100644 (file)
@@ -256,7 +256,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
                " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 0x05;
        cam->cam_mode = sif_mode;
        cam->nmodes = ARRAY_SIZE(sif_mode);
        sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
@@ -536,6 +535,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x093a, 0x2470)},
        {USB_DEVICE(0x093a, 0x2471)},
        {USB_DEVICE(0x093a, 0x2472)},
+       {USB_DEVICE(0x093a, 0x2474)},
        {USB_DEVICE(0x093a, 0x2476)},
        {USB_DEVICE(0x145f, 0x013a)},
        {USB_DEVICE(0x2001, 0xf115)},
@@ -565,8 +565,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index a9c95cba710e350e14fb70df6121d2a721700fa1..e1e3a3a504845b1c3ea5b91ff8c31e2f427b7e41 100644 (file)
@@ -498,7 +498,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct cam *cam;
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 0x05;
 
        sd->sensor = id->driver_info;
        if (sd->sensor == SENSOR_PAC7302) {
@@ -1097,8 +1096,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index b3e4e0677b683546135400609c373a81d879974d..153d0a91d4b5c94acb6a06903f0862a3b9196398 100644 (file)
@@ -870,7 +870,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        gspca_dev->ctrl_dis = sensor_data[sd->sensor].ctrl_dis;
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 0x01;
        if (!(sensor_data[sd->sensor].flags & F_SIF)) {
                cam->cam_mode = vga_mode;
                cam->nmodes = ARRAY_SIZE(vga_mode);
@@ -1272,8 +1271,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index 3373b8d9d2a88fa92c8ec40feb5d4d207d9b17ab..c72e19d3ac370bbb00e883f233c1b49378ff96fa 100644 (file)
@@ -35,36 +35,47 @@ struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
        atomic_t avg_lum;
-       unsigned int exposure;
-
-       __u16 brightness;
-       __u8 contrast;
-       __u8 colors;
-       __u8 autogain;
-       __u8 blue;
-       __u8 red;
-       __u8 vflip;                     /* ov7630 only */
-       __u8 infrared;                  /* mi0360 only */
-
-       __s8 ag_cnt;
+       u32 exposure;
+
+       u16 brightness;
+       u8 contrast;
+       u8 colors;
+       u8 autogain;
+       u8 blue;
+       u8 red;
+       u8 gamma;
+       u8 vflip;                       /* ov7630/ov7648 only */
+       u8 infrared;                    /* mt9v111 only */
+       u8 quality;                     /* image quality */
+#define QUALITY_MIN 60
+#define QUALITY_MAX 95
+#define QUALITY_DEF 80
+       u8 jpegqual;                    /* webcam quality */
+
+       u8 reg18;
+
+       s8 ag_cnt;
 #define AG_CNT_START 13
 
-       __u8 qindex;
-       __u8 bridge;
+       u8 bridge;
 #define BRIDGE_SN9C102P 0
 #define BRIDGE_SN9C105 1
 #define BRIDGE_SN9C110 2
 #define BRIDGE_SN9C120 3
 #define BRIDGE_SN9C325 4
-       __u8 sensor;                    /* Type of image sensor chip */
+       u8 sensor;                      /* Type of image sensor chip */
 #define SENSOR_HV7131R 0
 #define SENSOR_MI0360 1
 #define SENSOR_MO4000 2
-#define SENSOR_OM6802 3
-#define SENSOR_OV7630 4
-#define SENSOR_OV7648 5
-#define SENSOR_OV7660 6
-       __u8 i2c_base;
+#define SENSOR_MT9V111 3
+#define SENSOR_OM6802 4
+#define SENSOR_OV7630 5
+#define SENSOR_OV7648 6
+#define SENSOR_OV7660 7
+#define SENSOR_SP80708 8
+       u8 i2c_base;
+
+       u8 *jpeg_hdr;
 };
 
 /* V4L2 controls supported by the driver */
@@ -78,6 +89,8 @@ static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
@@ -158,6 +171,20 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setred_balance,
            .get = sd_getred_balance,
        },
+       {
+           {
+               .id      = V4L2_CID_GAMMA,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Gamma",
+               .minimum = 0,
+               .maximum = 40,
+               .step    = 1,
+#define GAMMA_DEF 20
+               .default_value = GAMMA_DEF,
+           },
+           .set = sd_setgamma,
+           .get = sd_getgamma,
+       },
 #define AUTOGAIN_IDX 5
        {
            {
@@ -173,7 +200,7 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setautogain,
            .get = sd_getautogain,
        },
-/* ov7630 only */
+/* ov7630/ov7648 only */
 #define VFLIP_IDX 6
        {
            {
@@ -183,13 +210,13 @@ static struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
-#define VFLIP_DEF 1
+#define VFLIP_DEF 0                    /* vflip def = 1 for ov7630 */
                .default_value = VFLIP_DEF,
            },
            .set = sd_setvflip,
            .get = sd_getvflip,
        },
-/* mi0360 only */
+/* mt9v111 only */
 #define INFRARED_IDX 7
        {
            {
@@ -211,18 +238,22 @@ static struct ctrl sd_ctrls[] = {
 static __u32 ctrl_dis[] = {
        (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
                                                /* SENSOR_HV7131R 0 */
-       (1 << VFLIP_IDX),
+       (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
                                                /* SENSOR_MI0360 1 */
        (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
                                                /* SENSOR_MO4000 2 */
+       (1 << VFLIP_IDX),
+                                               /* SENSOR_MT9V111 3 */
        (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
-                                               /* SENSOR_OM6802 3 */
+                                               /* SENSOR_OM6802 4 */
        (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX),
-                                               /* SENSOR_OV7630 4 */
+                                               /* SENSOR_OV7630 5 */
+       (1 << INFRARED_IDX),
+                                               /* SENSOR_OV7648 6 */
        (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
-                                               /* SENSOR_OV7648 5 */
+                                               /* SENSOR_OV7660 7 */
        (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
-                                               /* SENSOR_OV7660 6 */
+                                               /* SENSOR_SP80708 8 */
 };
 
 static const struct v4l2_pix_format vga_mode[] = {
@@ -243,196 +274,228 @@ static const struct v4l2_pix_format vga_mode[] = {
                .priv = 0},
 };
 
-/*Data from sn9c102p+hv71331r */
-static const __u8 sn_hv7131[] = {
+/*Data from sn9c102p+hv7131r */
+static const u8 sn_hv7131[0x1c] = {
 /*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
        0x00,   0x03,   0x64,   0x00,   0x1a,   0x20,   0x20,   0x20,
 /*     reg8    reg9    rega    regb    regc    regd    rege    regf */
        0xa1,   0x11,   0x02,   0x09,   0x00,   0x00,   0x00,   0x10,
 /*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
        0x03,   0x00,   0x00,   0x01,   0x03,   0x28,   0x1e,   0x41,
-/*     reg18   reg19   reg1a   reg1b   reg1c   reg1d   reg1e   reg1f */
-       0x0a,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00
+/*     reg18   reg19   reg1a   reg1b */
+       0x0a,   0x00,   0x00,   0x00
 };
 
-static const __u8 sn_mi0360[] = {
+static const u8 sn_mi0360[0x1c] = {
 /*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
        0x00,   0x61,   0x44,   0x00,   0x1a,   0x20,   0x20,   0x20,
 /*     reg8    reg9    rega    regb    regc    regd    rege    regf */
        0xb1,   0x5d,   0x07,   0x00,   0x00,   0x00,   0x00,   0x10,
 /*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
        0x03,   0x00,   0x00,   0x02,   0x0a,   0x28,   0x1e,   0x61,
-/*     reg18   reg19   reg1a   reg1b   reg1c   reg1d   reg1e   reg1f */
-       0x06,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00
+/*     reg18   reg19   reg1a   reg1b */
+       0x06,   0x00,   0x00,   0x00
 };
 
-static const __u8 sn_mo4000[] = {
+static const u8 sn_mo4000[0x1c] = {
 /*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
-       0x12,   0x23,   0x60,   0x00,   0x1a,   0x00,   0x20,   0x18,
+       0x00,   0x23,   0x60,   0x00,   0x1a,   0x00,   0x20,   0x18,
 /*     reg8    reg9    rega    regb    regc    regd    rege    regf */
        0x81,   0x21,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,
 /*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
        0x03,    0x00,  0x0b,   0x0f,   0x14,   0x28,   0x1e,   0x40,
-/*     reg18   reg19   reg1a   reg1b   reg1c   reg1d   reg1e   reg1f */
-       0x08,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00
+/*     reg18   reg19   reg1a   reg1b */
+       0x08,   0x00,   0x00,   0x00
 };
 
-static const __u8 sn_om6802[] = {
+static const u8 sn_mt9v111[0x1c] = {
+/*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
+       0x00,   0x61,   0x40,   0x00,   0x1a,   0x20,   0x20,   0x20,
+/*     reg8    reg9    rega    regb    regc    regd    rege    regf */
+       0x81,   0x5c,   0x07,   0x00,   0x00,   0x00,   0x00,   0x00,
+/*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
+       0x03,   0x00,   0x00,   0x02,   0x1c,   0x28,   0x1e,   0x40,
+/*     reg18   reg19   reg1a   reg1b */
+       0x06,   0x00,   0x00,   0x00
+};
+
+static const u8 sn_om6802[0x1c] = {
 /*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
        0x00,   0x23,   0x72,   0x00,   0x1a,   0x34,   0x27,   0x20,
 /*     reg8    reg9    rega    regb    regc    regd    rege    regf */
        0x80,   0x34,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,
 /*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
        0x03,   0x00,   0x51,   0x01,   0x00,   0x28,   0x1e,   0x40,
-/*     reg18   reg19   reg1a   reg1b   reg1c   reg1d   reg1e   reg1f */
-       0x05,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,
-       0x08,   0x22,   0x44,   0x63,   0x7d,   0x92,   0xa3,   0xaf,
-       0xbc,   0xc4,   0xcd,   0xd5,   0xdc,   0xe1,   0xe8,   0xef,
-       0xf7
+/*     reg18   reg19   reg1a   reg1b */
+       0x05,   0x00,   0x00,   0x00
 };
 
-static const __u8 sn_ov7630[] = {
+static const u8 sn_ov7630[0x1c] = {
 /*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
        0x00,   0x21,   0x40,   0x00,   0x1a,   0x20,   0x1f,   0x20,
 /*     reg8    reg9    rega    regb    regc    regd    rege    regf */
        0xa1,   0x21,   0x76,   0x21,   0x00,   0x00,   0x00,   0x10,
 /*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
        0x03,   0x00,   0x04,   0x01,   0x0a,   0x28,   0x1e,   0xc2,
-/*     reg18   reg19   reg1a   reg1b   reg1c   reg1d   reg1e   reg1f */
-       0x0b,   0x00,   0x00,   0x00,   0x00,   0x00
+/*     reg18   reg19   reg1a   reg1b */
+       0x0b,   0x00,   0x00,   0x00
 };
 
-static const __u8 sn_ov7648[] = {
+static const u8 sn_ov7648[0x1c] = {
 /*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
        0x00,   0x63,   0x40,   0x00,   0x1a,   0x20,   0x20,   0x20,
 /*     reg8    reg9    rega    regb    regc    regd    rege    regf */
        0x81,   0x21,   0x00,   0x00,   0x00,   0x00,   0x00,   0x10,
 /*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
        0x03,   0x00,   0x00,   0x01,   0x00,   0x28,   0x1e,   0x00,
-/*     reg18   reg19   reg1a   reg1b   reg1c   reg1d   reg1e   reg1f */
-       0x0b,   0x00,   0x00,   0x00,   0x00,   0x00
+/*     reg18   reg19   reg1a   reg1b */
+       0x0b,   0x00,   0x00,   0x00
 };
 
-static const __u8 sn_ov7660[]  = {
+static const u8 sn_ov7660[0x1c] = {
 /*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
        0x00,   0x61,   0x40,   0x00,   0x1a,   0x20,   0x20,   0x20,
 /*     reg8    reg9    rega    regb    regc    regd    rege    regf */
        0x81,   0x21,   0x07,   0x00,   0x00,   0x00,   0x00,   0x10,
 /*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
        0x03,   0x00,   0x01,   0x01,   0x08,   0x28,   0x1e,   0x20,
-/*     reg18   reg19   reg1a   reg1b   reg1c   reg1d   reg1e   reg1f */
-       0x07,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,
+/*     reg18   reg19   reg1a   reg1b */
+       0x07,   0x00,   0x00,   0x00
+};
+
+static const u8 sn_sp80708[0x1c] = {
+/*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
+       0x00,   0x63,   0x60,   0x00,   0x1a,   0x20,   0x20,   0x20,
+/*     reg8    reg9    rega    regb    regc    regd    rege    regf */
+       0x81,   0x18,   0x07,   0x00,   0x00,   0x00,   0x00,   0x00,
+/*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
+       0x03,   0x00,   0x00,   0x03,   0x04,   0x28,   0x1e,   0x00,
+/*     reg18   reg19   reg1a   reg1b */
+       0x07,   0x00,   0x00,   0x00
 };
 
 /* sequence specific to the sensors - !! index = SENSOR_xxx */
-static const __u8 *sn_tb[] = {
+static const u8 *sn_tb[] = {
        sn_hv7131,
        sn_mi0360,
        sn_mo4000,
+       sn_mt9v111,
        sn_om6802,
        sn_ov7630,
        sn_ov7648,
-       sn_ov7660
+       sn_ov7660,
+       sn_sp80708
 };
 
-static const __u8 gamma_def[] = {
+/* default gamma table */
+static const u8 gamma_def[17] = {
        0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
        0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
 };
+/* gamma for sensors HV7131R and MT9V111 */
+static const u8 gamma_spec_1[17] = {
+       0x08, 0x3a, 0x52, 0x65, 0x75, 0x83, 0x91, 0x9d,
+       0xa9, 0xb4, 0xbe, 0xc8, 0xd2, 0xdb, 0xe4, 0xed, 0xf5
+};
+/* gamma for sensor SP80708 */
+static const u8 gamma_spec_2[17] = {
+       0x0a, 0x2d, 0x4e, 0x68, 0x7d, 0x8f, 0x9f, 0xab,
+       0xb7, 0xc2, 0xcc, 0xd3, 0xd8, 0xde, 0xe2, 0xe5, 0xe6
+};
 
 /* color matrix and offsets */
-static const __u8 reg84[] = {
+static const u8 reg84[] = {
        0x14, 0x00, 0x27, 0x00, 0x07, 0x00,     /* YR YG YB gains */
        0xe8, 0x0f, 0xda, 0x0f, 0x40, 0x00,     /* UR UG UB */
        0x3e, 0x00, 0xcd, 0x0f, 0xf7, 0x0f,     /* VR VG VB */
        0x00, 0x00, 0x00                        /* YUV offsets */
 };
-static const __u8 hv7131r_sensor_init[][8] = {
-       {0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
-       {0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10},
-       {0xD1, 0x11, 0x40, 0xFF, 0x7F, 0x7F, 0x7F, 0x10},
-       {0x91, 0x11, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x11, 0x14, 0x01, 0xE2, 0x02, 0x82, 0x10},
-       {0x91, 0x11, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
-
-       {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
-       {0xC1, 0x11, 0x25, 0x00, 0x61, 0xA8, 0x00, 0x10},
-       {0xA1, 0x11, 0x30, 0x22, 0x00, 0x00, 0x00, 0x10},
-       {0xC1, 0x11, 0x31, 0x20, 0x2E, 0x20, 0x00, 0x10},
-       {0xC1, 0x11, 0x25, 0x00, 0xC3, 0x50, 0x00, 0x10},
-       {0xA1, 0x11, 0x30, 0x07, 0x00, 0x00, 0x00, 0x10}, /* gain14 */
-       {0xC1, 0x11, 0x31, 0x10, 0x10, 0x10, 0x00, 0x10}, /* r g b 101a10 */
-
-       {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x11, 0x23, 0x09, 0x00, 0x00, 0x00, 0x10},
-
-       {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x11, 0x23, 0x10, 0x00, 0x00, 0x00, 0x10},
+static const u8 hv7131r_sensor_init[][8] = {
+       {0xc1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
+       {0xb1, 0x11, 0x34, 0x17, 0x7f, 0x00, 0x00, 0x10},
+       {0xd1, 0x11, 0x40, 0xff, 0x7f, 0x7f, 0x7f, 0x10},
+/*     {0x91, 0x11, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10}, */
+       {0xd1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x11, 0x14, 0x01, 0xe2, 0x02, 0x82, 0x10},
+/*     {0x91, 0x11, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10}, */
+
+       {0xa1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+       {0xc1, 0x11, 0x25, 0x00, 0x61, 0xa8, 0x00, 0x10},
+       {0xa1, 0x11, 0x30, 0x22, 0x00, 0x00, 0x00, 0x10},
+       {0xc1, 0x11, 0x31, 0x20, 0x2e, 0x20, 0x00, 0x10},
+       {0xc1, 0x11, 0x25, 0x00, 0xc3, 0x50, 0x00, 0x10},
+       {0xa1, 0x11, 0x30, 0x07, 0x00, 0x00, 0x00, 0x10}, /* gain14 */
+       {0xc1, 0x11, 0x31, 0x10, 0x10, 0x10, 0x00, 0x10}, /* r g b 101a10 */
+
+       {0xa1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x11, 0x23, 0x09, 0x00, 0x00, 0x00, 0x10},
+
+       {0xa1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x11, 0x21, 0xd0, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x11, 0x23, 0x10, 0x00, 0x00, 0x00, 0x10},
        {}
 };
-static const __u8 mi0360_sensor_init[][8] = {
-       {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
-       {0xB1, 0x5D, 0x0D, 0x00, 0x01, 0x00, 0x00, 0x10},
-       {0xB1, 0x5D, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10},
-       {0xD1, 0x5D, 0x03, 0x01, 0xE2, 0x02, 0x82, 0x10},
-       {0xD1, 0x5D, 0x05, 0x00, 0x09, 0x00, 0x53, 0x10},
-       {0xB1, 0x5D, 0x0D, 0x00, 0x02, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xB1, 0x5D, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10},
-       {0xD1, 0x5D, 0x2F, 0xF7, 0xB0, 0x00, 0x04, 0x10},
-       {0xD1, 0x5D, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10},
-       {0xB1, 0x5D, 0x3D, 0x06, 0x8F, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x40, 0x01, 0xE0, 0x00, 0xD1, 0x10},
-       {0xB1, 0x5D, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10},
-       {0xD1, 0x5D, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x5E, 0x00, 0x00, 0xA3, 0x1D, 0x10},
-       {0xB1, 0x5D, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10},
-
-       {0xB1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
-       {0xB1, 0x5D, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
-       {0xB1, 0x5D, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10},
-       {0xD1, 0x5D, 0x2B, 0x00, 0xA0, 0x00, 0xB0, 0x10},
-       {0xD1, 0x5D, 0x2D, 0x00, 0xA0, 0x00, 0xA0, 0x10},
-
-       {0xB1, 0x5D, 0x0A, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor clck ?2 */
-       {0xB1, 0x5D, 0x06, 0x00, 0x30, 0x00, 0x00, 0x10},
-       {0xB1, 0x5D, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x10},
-       {0xB1, 0x5D, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */
-
-       {0xD1, 0x5D, 0x2B, 0x00, 0xB9, 0x00, 0xE3, 0x10},
-       {0xD1, 0x5D, 0x2D, 0x00, 0x5f, 0x00, 0xB9, 0x10}, /* 42 */
-/*     {0xB1, 0x5D, 0x35, 0x00, 0x67, 0x00, 0x00, 0x10}, * gain orig */
-/*     {0xB1, 0x5D, 0x35, 0x00, 0x20, 0x00, 0x00, 0x10}, * gain */
-       {0xB1, 0x5D, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */
-       {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */
+static const u8 mi0360_sensor_init[][8] = {
+       {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
+       {0xb1, 0x5d, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x10},
+       {0xb1, 0x5d, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10},
+       {0xd1, 0x5d, 0x03, 0x01, 0xe2, 0x02, 0x82, 0x10},
+       {0xd1, 0x5d, 0x05, 0x00, 0x09, 0x00, 0x53, 0x10},
+       {0xb1, 0x5d, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xb1, 0x5d, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10},
+       {0xd1, 0x5d, 0x2f, 0xf7, 0xB0, 0x00, 0x04, 0x10},
+       {0xd1, 0x5d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10},
+       {0xb1, 0x5d, 0x3d, 0x06, 0x8f, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x40, 0x01, 0xe0, 0x00, 0xd1, 0x10},
+       {0xb1, 0x5d, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10},
+       {0xd1, 0x5d, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x5e, 0x00, 0x00, 0xa3, 0x1d, 0x10},
+       {0xb1, 0x5d, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10},
+
+       {0xb1, 0x5d, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
+       {0xb1, 0x5d, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
+       {0xb1, 0x5d, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10},
+       {0xd1, 0x5d, 0x2b, 0x00, 0xa0, 0x00, 0xb0, 0x10},
+       {0xd1, 0x5d, 0x2d, 0x00, 0xa0, 0x00, 0xa0, 0x10},
+
+       {0xb1, 0x5d, 0x0a, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor clck ?2 */
+       {0xb1, 0x5d, 0x06, 0x00, 0x30, 0x00, 0x00, 0x10},
+       {0xb1, 0x5d, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x10},
+       {0xb1, 0x5d, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */
+
+       {0xd1, 0x5d, 0x2b, 0x00, 0xb9, 0x00, 0xe3, 0x10},
+       {0xd1, 0x5d, 0x2d, 0x00, 0x5f, 0x00, 0xb9, 0x10}, /* 42 */
+/*     {0xb1, 0x5d, 0x35, 0x00, 0x67, 0x00, 0x00, 0x10}, * gain orig */
+/*     {0xb1, 0x5d, 0x35, 0x00, 0x20, 0x00, 0x00, 0x10}, * gain */
+       {0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */
+       {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */
        {}
 };
-static const __u8 mo4000_sensor_init[][8] = {
+static const u8 mo4000_sensor_init[][8] = {
        {0xa1, 0x21, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
@@ -455,7 +518,49 @@ static const __u8 mo4000_sensor_init[][8] = {
        {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
        {}
 };
-static __u8 om6802_sensor_init[][8] = {
+static const u8 mt9v111_sensor_init[][8] = {
+       {0xb1, 0x5c, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x10}, /* reset? */
+       /* delay 20 ms */
+       {0xb1, 0x5c, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xb1, 0x5c, 0x01, 0x00, 0x01, 0x00, 0x00, 0x10}, /* IFP select */
+       {0xb1, 0x5c, 0x08, 0x04, 0x80, 0x00, 0x00, 0x10}, /* output fmt ctrl */
+       {0xb1, 0x5c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}, /* op mode ctrl */
+       {0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10},
+       {0xb1, 0x5c, 0x03, 0x01, 0xe1, 0x00, 0x00, 0x10},
+       {0xb1, 0x5c, 0x04, 0x02, 0x81, 0x00, 0x00, 0x10},
+       {0xb1, 0x5c, 0x05, 0x00, 0x04, 0x00, 0x00, 0x10},
+       {0xb1, 0x5c, 0x01, 0x00, 0x04, 0x00, 0x00, 0x10}, /* sensor select */
+       {0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10},
+       {0xb1, 0x5c, 0x03, 0x01, 0xe6, 0x00, 0x00, 0x10},
+       {0xb1, 0x5c, 0x04, 0x02, 0x86, 0x00, 0x00, 0x10},
+       {0xb1, 0x5c, 0x05, 0x00, 0x04, 0x00, 0x00, 0x10},
+       {0xb1, 0x5c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xb1, 0x5c, 0x08, 0x00, 0x08, 0x00, 0x00, 0x10}, /* row start */
+       {0xb1, 0x5c, 0x0e, 0x00, 0x08, 0x00, 0x00, 0x10},
+       {0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10}, /* col start */
+       {0xb1, 0x5c, 0x03, 0x01, 0xe7, 0x00, 0x00, 0x10}, /* window height */
+       {0xb1, 0x5c, 0x04, 0x02, 0x87, 0x00, 0x00, 0x10}, /* window width */
+       {0xb1, 0x5c, 0x07, 0x30, 0x02, 0x00, 0x00, 0x10}, /* output ctrl */
+       {0xb1, 0x5c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x10}, /* shutter delay */
+       {0xb1, 0x5c, 0x12, 0x00, 0xb0, 0x00, 0x00, 0x10}, /* zoom col start */
+       {0xb1, 0x5c, 0x13, 0x00, 0x7c, 0x00, 0x00, 0x10}, /* zoom row start */
+       {0xb1, 0x5c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x10}, /* digital zoom */
+       {0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10}, /* read mode */
+       {0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+       /*******/
+       {0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xb1, 0x5c, 0x09, 0x01, 0x2c, 0x00, 0x00, 0x10},
+       {0xd1, 0x5c, 0x2b, 0x00, 0x33, 0x00, 0xa0, 0x10}, /* green1 gain */
+       {0xd1, 0x5c, 0x2d, 0x00, 0xa0, 0x00, 0x33, 0x10}, /* red gain */
+       /*******/
+       {0xb1, 0x5c, 0x06, 0x00, 0x1e, 0x00, 0x00, 0x10}, /* vert blanking */
+       {0xb1, 0x5c, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x10}, /* horiz blanking */
+       {0xd1, 0x5c, 0x2c, 0x00, 0xad, 0x00, 0xad, 0x10}, /* blue gain */
+       {0xb1, 0x5c, 0x35, 0x01, 0xc0, 0x00, 0x00, 0x10}, /* global gain */
+       {}
+};
+static const u8 om6802_sensor_init[][8] = {
        {0xa0, 0x34, 0x90, 0x05, 0x00, 0x00, 0x00, 0x10},
        {0xa0, 0x34, 0x49, 0x85, 0x00, 0x00, 0x00, 0x10},
        {0xa0, 0x34, 0x5a, 0xc0, 0x00, 0x00, 0x00, 0x10},
@@ -489,7 +594,7 @@ static __u8 om6802_sensor_init[][8] = {
 /*     {0xa0, 0x34, 0x69, 0x01, 0x00, 0x00, 0x00, 0x10}, */
        {}
 };
-static const __u8 ov7630_sensor_init[][8] = {
+static const u8 ov7630_sensor_init[][8] = {
        {0xa1, 0x21, 0x76, 0x01, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
 /* win: delay 20ms */
@@ -543,7 +648,7 @@ static const __u8 ov7630_sensor_init[][8] = {
        {}
 };
 
-static const __u8 ov7648_sensor_init[][8] = {
+static const u8 ov7648_sensor_init[][8] = {
        {0xa1, 0x21, 0x76, 0x00, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},       /* reset */
        {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
@@ -572,7 +677,8 @@ static const __u8 ov7648_sensor_init[][8] = {
        {0xb1, 0x21, 0x2d, 0x85, 0x00, 0x00, 0x00, 0x10},
 /*...*/
 /*     {0xa1, 0x21, 0x12, 0x08, 0x00, 0x00, 0x00, 0x10}, jfm done */
-/*     {0xa1, 0x21, 0x75, 0x06, 0x00, 0x00, 0x00, 0x10}, jfm done */
+/*     {0xa1, 0x21, 0x75, 0x06, 0x00, 0x00, 0x00, 0x10},   * COMN
+                                                        * set by setvflip */
        {0xa1, 0x21, 0x19, 0x02, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10},
 /*     {0xa1, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */
@@ -589,7 +695,7 @@ static const __u8 ov7648_sensor_init[][8] = {
        {}
 };
 
-static const __u8 ov7660_sensor_init[][8] = {
+static const u8 ov7660_sensor_init[][8] = {
        {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
 /*             (delay 20ms) */
        {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
@@ -678,28 +784,92 @@ static const __u8 ov7660_sensor_init[][8] = {
        {}
 };
 
-static const __u8 qtable4[] = {
-       0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x08, 0x06,
-       0x06, 0x08, 0x0A, 0x11,
-       0x0A, 0x0A, 0x08, 0x08, 0x0A, 0x15, 0x0F, 0x0F, 0x0C, 0x11, 0x19, 0x15,
-       0x19, 0x19, 0x17, 0x15,
-       0x17, 0x17, 0x1B, 0x1D, 0x25, 0x21, 0x1B, 0x1D, 0x23, 0x1D, 0x17, 0x17,
-       0x21, 0x2E, 0x21, 0x23,
-       0x27, 0x29, 0x2C, 0x2C, 0x2C, 0x19, 0x1F, 0x30, 0x32, 0x2E, 0x29, 0x32,
-       0x25, 0x29, 0x2C, 0x29,
-       0x06, 0x08, 0x08, 0x0A, 0x08, 0x0A, 0x13, 0x0A, 0x0A, 0x13, 0x29, 0x1B,
-       0x17, 0x1B, 0x29, 0x29,
-       0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
-       0x29, 0x29, 0x29, 0x29,
-       0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
-       0x29, 0x29, 0x29, 0x29,
-       0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
-       0x29, 0x29, 0x29, 0x29
+static const u8 sp80708_sensor_init[][8] = {
+       {0xa1, 0x18, 0x06, 0xf9, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x09, 0x1f, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x0d, 0xc0, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x10, 0x40, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x11, 0x4e, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x12, 0x53, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x15, 0x80, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x19, 0x18, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x1a, 0x10, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x1c, 0x28, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x1d, 0x02, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x1e, 0x10, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x26, 0x04, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x27, 0x1e, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x28, 0x5a, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x29, 0x28, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x2a, 0x78, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x2b, 0x01, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x2c, 0xf7, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x2d, 0x2d, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x2e, 0xd5, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x39, 0x42, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x3a, 0x67, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x3b, 0x87, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x3c, 0xa3, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x3d, 0xb0, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x3e, 0xbc, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x3f, 0xc8, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x40, 0xd4, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x41, 0xdf, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x42, 0xea, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x43, 0xf5, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x45, 0x80, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x46, 0x60, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x47, 0x50, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x48, 0x30, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x49, 0x01, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x4d, 0xae, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x4e, 0x03, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x4f, 0x66, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x50, 0x1c, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x44, 0x10, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x4a, 0x30, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x51, 0x80, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x52, 0x80, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x53, 0x80, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x54, 0x80, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x55, 0x80, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x56, 0x80, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x57, 0xe0, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x58, 0xc0, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x59, 0xab, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x5a, 0xa0, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x5b, 0x99, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x5c, 0x90, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x5e, 0x24, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x61, 0x73, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x63, 0x42, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x64, 0x42, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x65, 0x42, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x66, 0x24, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x67, 0x24, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x68, 0x08, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x2f, 0xc9, 0x00, 0x00, 0x00, 0x10},
+       /********/
+       {0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x03, 0x01, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x04, 0xa4, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x14, 0x3f, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x18, 0x5d, 0x80, 0x00, 0x00, 0x00, 0x10},
+       {0xb1, 0x18, 0x11, 0x40, 0x40, 0x00, 0x00, 0x10},
+       {}
 };
 
 /* read <len> bytes to gspca_dev->usb_buf */
 static void reg_r(struct gspca_dev *gspca_dev,
-                 __u16 value, int len)
+                 u16 value, int len)
 {
 #ifdef GSPCA_DEBUG
        if (len > USB_BUF_SZ) {
@@ -718,10 +888,10 @@ static void reg_r(struct gspca_dev *gspca_dev,
 }
 
 static void reg_w1(struct gspca_dev *gspca_dev,
-                  __u16 value,
-                  __u8 data)
+                  u16 value,
+                  u8 data)
 {
-       PDEBUG(D_USBO, "reg_w1 [%02x] = %02x", value, data);
+       PDEBUG(D_USBO, "reg_w1 [%04x] = %02x", value, data);
        gspca_dev->usb_buf[0] = data;
        usb_control_msg(gspca_dev->dev,
                        usb_sndctrlpipe(gspca_dev->dev, 0),
@@ -733,11 +903,11 @@ static void reg_w1(struct gspca_dev *gspca_dev,
                        500);
 }
 static void reg_w(struct gspca_dev *gspca_dev,
-                         __u16 value,
-                         const __u8 *buffer,
+                         u16 value,
+                         const u8 *buffer,
                          int len)
 {
-       PDEBUG(D_USBO, "reg_w [%02x] = %02x %02x ..",
+       PDEBUG(D_USBO, "reg_w [%04x] = %02x %02x ..",
                value, buffer[0], buffer[1]);
 #ifdef GSPCA_DEBUG
        if (len > USB_BUF_SZ) {
@@ -756,7 +926,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
 }
 
 /* I2C write 1 byte */
-static void i2c_w1(struct gspca_dev *gspca_dev, __u8 reg, __u8 val)
+static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
@@ -781,7 +951,7 @@ static void i2c_w1(struct gspca_dev *gspca_dev, __u8 reg, __u8 val)
 
 /* I2C write 8 bytes */
 static void i2c_w8(struct gspca_dev *gspca_dev,
-                  const __u8 *buffer)
+                  const u8 *buffer)
 {
        memcpy(gspca_dev->usb_buf, buffer, 8);
        usb_control_msg(gspca_dev->dev,
@@ -795,10 +965,10 @@ static void i2c_w8(struct gspca_dev *gspca_dev,
 }
 
 /* read 5 bytes in gspca_dev->usb_buf */
-static void i2c_r5(struct gspca_dev *gspca_dev, __u8 reg)
+static void i2c_r5(struct gspca_dev *gspca_dev, u8 reg)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       __u8 mode[8];
+       u8 mode[8];
 
        mode[0] = 0x81 | 0x10;
        mode[1] = sd->i2c_base;
@@ -817,7 +987,7 @@ static void i2c_r5(struct gspca_dev *gspca_dev, __u8 reg)
        reg_r(gspca_dev, 0x0a, 5);
 }
 
-static int probesensor(struct gspca_dev *gspca_dev)
+static int hv7131r_probe(struct gspca_dev *gspca_dev)
 {
        i2c_w1(gspca_dev, 0x02, 0);                     /* sensor wakeup */
        msleep(10);
@@ -839,16 +1009,66 @@ static int probesensor(struct gspca_dev *gspca_dev)
        return -ENODEV;
 }
 
+static void mi0360_probe(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i, j;
+       u16 val = 0;
+       static const u8 probe_tb[][4][8] = {
+           {                                   /* mi0360 */
+               {0xb0, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
+               {0x90, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
+               {0xa2, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
+               {0xb0, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10}
+           },
+           {                                   /* mt9v111 */
+               {0xb0, 0x5c, 0x01, 0x00, 0x04, 0x00, 0x00, 0x10},
+               {0x90, 0x5c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x10},
+               {0xa2, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
+               {}
+           },
+       };
+
+       for (i = 0; i < ARRAY_SIZE(probe_tb); i++) {
+               reg_w1(gspca_dev, 0x17, 0x62);
+               reg_w1(gspca_dev, 0x01, 0x08);
+               for (j = 0; j < 3; j++)
+                       i2c_w8(gspca_dev, probe_tb[i][j]);
+               msleep(2);
+               reg_r(gspca_dev, 0x0a, 5);
+               val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
+               if (probe_tb[i][3][0] != 0)
+                       i2c_w8(gspca_dev, probe_tb[i][3]);
+               reg_w1(gspca_dev, 0x01, 0x29);
+               reg_w1(gspca_dev, 0x17, 0x42);
+               if (val != 0xffff)
+                       break;
+       }
+       switch (val) {
+       case 0x823a:
+               PDEBUG(D_PROBE, "Sensor mt9v111");
+               sd->sensor = SENSOR_MT9V111;
+               sd->i2c_base = 0x5c;
+               break;
+       case 0x8243:
+               PDEBUG(D_PROBE, "Sensor mi0360");
+               break;
+       default:
+               PDEBUG(D_PROBE, "Unknown sensor %04x - forced to mi0360", val);
+               break;
+       }
+}
+
 static int configure_gpio(struct gspca_dev *gspca_dev,
-                         const __u8 *sn9c1xx)
+                         const u8 *sn9c1xx)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       const __u8 *reg9a;
-       static const __u8 reg9a_def[] =
+       const u8 *reg9a;
+       static const u8 reg9a_def[] =
                {0x08, 0x40, 0x20, 0x10, 0x00, 0x04};
-       static const __u8 reg9a_sn9c325[] =
+       static const u8 reg9a_sn9c325[] =
                {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20};
-       static const __u8 regd4[] = {0x60, 0x00, 0x00};
+       static const u8 regd4[] = {0x60, 0x00, 0x00};
 
        reg_w1(gspca_dev, 0xf1, 0x00);
        reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
@@ -872,6 +1092,12 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
        reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
 
        switch (sd->sensor) {
+       case SENSOR_MT9V111:
+               reg_w1(gspca_dev, 0x01, 0x61);
+               reg_w1(gspca_dev, 0x17, 0x61);
+               reg_w1(gspca_dev, 0x01, 0x60);
+               reg_w1(gspca_dev, 0x01, 0x40);
+               break;
        case SENSOR_OM6802:
                reg_w1(gspca_dev, 0x02, 0x71);
                reg_w1(gspca_dev, 0x01, 0x42);
@@ -900,12 +1126,20 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
                        break;
                }
                /* fall thru */
+       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);
+               reg_w1(gspca_dev, 0x02, 0x62);
+               break;
        default:
                reg_w1(gspca_dev, 0x01, 0x43);
                reg_w1(gspca_dev, 0x17, 0x61);
                reg_w1(gspca_dev, 0x01, 0x42);
                if (sd->sensor == SENSOR_HV7131R) {
-                       if (probesensor(gspca_dev) < 0)
+                       if (hv7131r_probe(gspca_dev) < 0)
                                return -ENODEV;
                }
                break;
@@ -916,7 +1150,7 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
 static void hv7131R_InitSensor(struct gspca_dev *gspca_dev)
 {
        int i = 0;
-       static const __u8 SetSensorClk[] =      /* 0x08 Mclk */
+       static const u8 SetSensorClk[] =        /* 0x08 Mclk */
                { 0xa1, 0x11, 0x01, 0x18, 0x00, 0x00, 0x00, 0x10 };
 
        while (hv7131r_sensor_init[i][0]) {
@@ -946,6 +1180,19 @@ static void mo4000_InitSensor(struct gspca_dev *gspca_dev)
        }
 }
 
+static void mt9v111_InitSensor(struct gspca_dev *gspca_dev)
+{
+       int i = 0;
+
+       i2c_w8(gspca_dev, mt9v111_sensor_init[i]);
+       i++;
+       msleep(20);
+       while (mt9v111_sensor_init[i][0]) {
+               i2c_w8(gspca_dev, mt9v111_sensor_init[i]);
+               i++;
+       }
+}
+
 static void om6802_InitSensor(struct gspca_dev *gspca_dev)
 {
        int i = 0;
@@ -1010,6 +1257,19 @@ static void ov7660_InitSensor(struct gspca_dev *gspca_dev)
        }
 }
 
+static void sp80708_InitSensor(struct gspca_dev *gspca_dev)
+{
+       int i = 0;
+
+       i2c_w8(gspca_dev, sp80708_sensor_init[i]);      /* reset SCCB */
+       i++;
+       msleep(20);
+       while (sp80708_sensor_init[i][0]) {
+               i2c_w8(gspca_dev, sp80708_sensor_init[i]);
+               i++;
+       }
+}
+
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
                        const struct usb_device_id *id)
@@ -1018,7 +1278,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct cam *cam;
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 0x01;
        cam->cam_mode = vga_mode;
        cam->nmodes = ARRAY_SIZE(vga_mode);
 
@@ -1026,16 +1285,21 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->sensor = id->driver_info >> 8;
        sd->i2c_base = id->driver_info;
 
-       sd->qindex = 4;                 /* set the quantization table */
        sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
        sd->colors = COLOR_DEF;
        sd->blue = BLUE_BALANCE_DEF;
        sd->red = RED_BALANCE_DEF;
+       sd->gamma = GAMMA_DEF;
        sd->autogain = AUTOGAIN_DEF;
        sd->ag_cnt = -1;
-       sd->vflip = VFLIP_DEF;
+       if (sd->sensor != SENSOR_OV7630)
+               sd->vflip = 0;
+       else
+               sd->vflip = 1;
        sd->infrared = INFRARED_DEF;
+       sd->quality = QUALITY_DEF;
+       sd->jpegqual = 80;
 
        gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
        return 0;
@@ -1045,8 +1309,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
 static int sd_init(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       __u8 regGpio[] = { 0x29, 0x74 };
-       __u8 regF1;
+       u8 regGpio[] = { 0x29, 0x74 };
+       u8 regF1;
 
        /* setup a selector by bridge */
        reg_w1(gspca_dev, 0xf1, 0x01);
@@ -1064,11 +1328,15 @@ static int sd_init(struct gspca_dev *gspca_dev)
        case BRIDGE_SN9C105:
                if (regF1 != 0x11)
                        return -ENODEV;
+               if (sd->sensor == SENSOR_MI0360)
+                       mi0360_probe(gspca_dev);
                reg_w(gspca_dev, 0x01, regGpio, 2);
                break;
        case BRIDGE_SN9C120:
                if (regF1 != 0x12)
                        return -ENODEV;
+               if (sd->sensor == SENSOR_MI0360)
+                       mi0360_probe(gspca_dev);
                regGpio[1] = 0x70;
                reg_w(gspca_dev, 0x01, regGpio, 2);
                break;
@@ -1086,20 +1354,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
-static unsigned int setexposure(struct gspca_dev *gspca_dev,
-                               unsigned int expo)
+static u32 setexposure(struct gspca_dev *gspca_dev,
+                       u32 expo)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       static const __u8 doit[] =              /* update sensor */
-               { 0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10 };
-       static const __u8 sensorgo[] =          /* sensor on */
-               { 0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10 };
-       static const __u8 gainMo[] =
-               { 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d };
 
        switch (sd->sensor) {
        case SENSOR_HV7131R: {
-               __u8 Expodoit[] =
+               u8 Expodoit[] =
                        { 0xc1, 0x11, 0x25, 0x07, 0x27, 0xc0, 0x00, 0x16 };
 
                Expodoit[3] = expo >> 16;
@@ -1109,8 +1371,12 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev,
                break;
            }
        case SENSOR_MI0360: {
-               __u8 expoMi[] =  /* exposure 0x0635 -> 4 fp/s 0x10 */
+               u8 expoMi[] =           /* exposure 0x0635 -> 4 fp/s 0x10 */
                        { 0xb1, 0x5d, 0x09, 0x06, 0x35, 0x00, 0x00, 0x16 };
+               static const u8 doit[] =                /* update sensor */
+                       { 0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10 };
+               static const u8 sensorgo[] =            /* sensor on */
+                       { 0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10 };
 
                if (expo > 0x0635)
                        expo = 0x0635;
@@ -1124,10 +1390,12 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev,
                break;
            }
        case SENSOR_MO4000: {
-               __u8 expoMof[] =
+               u8 expoMof[] =
                        { 0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10 };
-               __u8 expoMo10[] =
+               u8 expoMo10[] =
                        { 0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10 };
+               static const u8 gainMo[] =
+                       { 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d };
 
                if (expo > 0x1fff)
                        expo = 0x1fff;
@@ -1139,14 +1407,27 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev,
                                | ((expo & 0x0003) << 4);
                i2c_w8(gspca_dev, expoMo10);
                i2c_w8(gspca_dev, gainMo);
-               PDEBUG(D_CONF, "set exposure %d",
+               PDEBUG(D_FRAM, "set exposure %d",
                        ((expoMo10[3] & 0x07) << 10)
                        | (expoMof[3] << 2)
                        | ((expoMo10[3] & 0x30) >> 4));
                break;
            }
+       case SENSOR_MT9V111: {
+               u8 expo_c1[] =
+                       { 0xb1, 0x5c, 0x09, 0x00, 0x00, 0x00, 0x00, 0x10 };
+
+               if (expo > 0x0280)
+                       expo = 0x0280;
+               else if (expo < 0x0040)
+                       expo = 0x0040;
+               expo_c1[3] = expo >> 8;
+               expo_c1[4] = expo;
+               i2c_w8(gspca_dev, expo_c1);
+               break;
+           }
        case SENSOR_OM6802: {
-               __u8 gainOm[] =
+               u8 gainOm[] =
                        { 0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10 };
 
                if (expo > 0x03ff)
@@ -1156,7 +1437,7 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev,
                gainOm[3] = expo >> 2;
                i2c_w8(gspca_dev, gainOm);
                reg_w1(gspca_dev, 0x96, (expo >> 5) & 0x1f);
-               PDEBUG(D_CONF, "set exposure %d", gainOm[3]);
+               PDEBUG(D_FRAM, "set exposure %d", gainOm[3]);
                break;
            }
        }
@@ -1167,7 +1448,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        unsigned int expo;
-       __u8 k2;
+       u8 k2;
 
        k2 = ((int) sd->brightness - 0x8000) >> 10;
        switch (sd->sensor) {
@@ -1184,6 +1465,10 @@ static void setbrightness(struct gspca_dev *gspca_dev)
                expo = sd->brightness >> 4;
                sd->exposure = setexposure(gspca_dev, expo);
                break;
+       case SENSOR_MT9V111:
+               expo = sd->brightness >> 8;
+               sd->exposure = setexposure(gspca_dev, expo);
+               break;
        case SENSOR_OM6802:
                expo = sd->brightness >> 6;
                sd->exposure = setexposure(gspca_dev, expo);
@@ -1191,14 +1476,15 @@ static void setbrightness(struct gspca_dev *gspca_dev)
                break;
        }
 
-       reg_w1(gspca_dev, 0x96, k2);            /* color matrix Y offset */
+       if (sd->sensor != SENSOR_MT9V111)
+               reg_w1(gspca_dev, 0x96, k2);    /* color matrix Y offset */
 }
 
 static void setcontrast(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       __u8 k2;
-       __u8 contrast[6];
+       u8 k2;
+       u8 contrast[6];
 
        k2 = sd->contrast * 0x30 / (CONTRAST_MAX + 1) + 0x10;   /* 10..40 */
        contrast[0] = (k2 + 1) / 2;             /* red */
@@ -1214,8 +1500,8 @@ static void setcolors(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int i, v;
-       __u8 reg8a[12];                 /* U & V gains */
-       static __s16 uv[6] = {          /* same as reg84 in signed decimal */
+       u8 reg8a[12];                   /* U & V gains */
+       static s16 uv[6] = {            /* same as reg84 in signed decimal */
                -24, -38, 64,           /* UR UG UB */
                 62, -51, -9            /* VR VG VB */
        };
@@ -1236,22 +1522,75 @@ static void setredblue(struct gspca_dev *gspca_dev)
        reg_w1(gspca_dev, 0x06, sd->blue);
 }
 
+static void setgamma(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i;
+       u8 gamma[17];
+       const u8 *gamma_base;
+       static const u8 delta[17] = {
+               0x00, 0x14, 0x1c, 0x1c, 0x1c, 0x1c, 0x1b, 0x1a,
+               0x18, 0x13, 0x10, 0x0e, 0x08, 0x07, 0x04, 0x02, 0x00
+       };
+
+       switch (sd->sensor) {
+       case SENSOR_HV7131R:
+       case SENSOR_MT9V111:
+               gamma_base = gamma_spec_1;
+               break;
+       case SENSOR_SP80708:
+               gamma_base = gamma_spec_2;
+               break;
+       default:
+               gamma_base = gamma_def;
+               break;
+       }
+
+       for (i = 0; i < sizeof gamma; i++)
+               gamma[i] = gamma_base[i]
+                       + delta[i] * (sd->gamma - GAMMA_DEF) / 32;
+       reg_w(gspca_dev, 0x20, gamma, sizeof gamma);
+}
+
 static void setautogain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
        if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
                return;
+       switch (sd->sensor) {
+       case SENSOR_OV7630:
+       case SENSOR_OV7648: {
+               u8 comb;
+
+               if (sd->sensor == SENSOR_OV7630)
+                       comb = 0xc0;
+               else
+                       comb = 0xa0;
+               if (sd->autogain)
+                       comb |= 0x02;
+               i2c_w1(&sd->gspca_dev, 0x13, comb);
+               return;
+           }
+       }
        if (sd->autogain)
                sd->ag_cnt = AG_CNT_START;
        else
                sd->ag_cnt = -1;
 }
 
+/* ov7630/ov7648 only */
 static void setvflip(struct sd *sd)
 {
-       i2c_w1(&sd->gspca_dev, 0x75,                    /* COMN */
-               sd->vflip ? 0x82 : 0x02);
+       u8 comn;
+
+       if (sd->sensor == SENSOR_OV7630)
+               comn = 0x02;
+       else
+               comn = 0x06;
+       if (sd->vflip)
+               comn |= 0x80;
+       i2c_w1(&sd->gspca_dev, 0x75, comn);
 }
 
 static void setinfrared(struct sd *sd)
@@ -1262,20 +1601,63 @@ static void setinfrared(struct sd *sd)
                sd->infrared ? 0x66 : 0x64);
 }
 
+static void setjpegqual(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i, sc;
+
+       if (sd->jpegqual < 50)
+               sc = 5000 / sd->jpegqual;
+       else
+               sc = 200 - sd->jpegqual * 2;
+#if USB_BUF_SZ < 64
+#error "No room enough in usb_buf for quantization table"
+#endif
+       for (i = 0; i < 64; i++)
+               gspca_dev->usb_buf[i] =
+                       (jpeg_head[JPEG_QT0_OFFSET + i] * sc + 50) / 100;
+       usb_control_msg(gspca_dev->dev,
+                       usb_sndctrlpipe(gspca_dev->dev, 0),
+                       0x08,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                       0x0100, 0,
+                       gspca_dev->usb_buf, 64,
+                       500);
+       for (i = 0; i < 64; i++)
+               gspca_dev->usb_buf[i] =
+                       (jpeg_head[JPEG_QT1_OFFSET + i] * sc + 50) / 100;
+       usb_control_msg(gspca_dev->dev,
+                       usb_sndctrlpipe(gspca_dev->dev, 0),
+                       0x08,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                       0x0140, 0,
+                       gspca_dev->usb_buf, 64,
+                       500);
+
+       sd->reg18 ^= 0x40;
+       reg_w1(gspca_dev, 0x18, sd->reg18);
+}
+
 /* -- start the camera -- */
 static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int i;
-       __u8 reg1, reg17, reg18;
-       const __u8 *sn9c1xx;
+       u8 reg1, reg17;
+       const u8 *sn9c1xx;
        int mode;
-       static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
-       static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
-       static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd };    /* MI0360 */
-       static const __u8 CE_ov76xx[] =
+       static const u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
+       static const u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
+       static const u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd };      /* MI0360 */
+       static const u8 CE_ov76xx[] =
                                { 0x32, 0xdd, 0x32, 0xdd };
 
+       /* create the JPEG header */
+       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+                       0x21);          /* JPEG 422 */
+       jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
        sn9c1xx = sn_tb[(int) sd->sensor];
        configure_gpio(gspca_dev, sn9c1xx);
 
@@ -1292,6 +1674,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
        reg_w1(gspca_dev, 0xc9, 0x3c);
        reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
        switch (sd->sensor) {
+       case SENSOR_MT9V111:
+               reg17 = 0xe0;
+               break;
        case SENSOR_OV7630:
                reg17 = 0xe2;
                break;
@@ -1315,14 +1700,24 @@ static int sd_start(struct gspca_dev *gspca_dev)
        reg_w1(gspca_dev, 0x07, sn9c1xx[7]);    /* green */
        reg_w1(gspca_dev, 0x06, sn9c1xx[6]);    /* blue */
        reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]);
-       reg_w(gspca_dev, 0x20, gamma_def, sizeof gamma_def);
+
+       setgamma(gspca_dev);
+
        for (i = 0; i < 8; i++)
                reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
        switch (sd->sensor) {
+       case SENSOR_MT9V111:
+               reg_w1(gspca_dev, 0x9a, 0x07);
+               reg_w1(gspca_dev, 0x99, 0x59);
+               break;
        case SENSOR_OV7648:
                reg_w1(gspca_dev, 0x9a, 0x0a);
                reg_w1(gspca_dev, 0x99, 0x60);
                break;
+       case SENSOR_SP80708:
+               reg_w1(gspca_dev, 0x9a, 0x05);
+               reg_w1(gspca_dev, 0x99, 0x59);
+               break;
        case SENSOR_OV7660:
                if (sd->bridge == BRIDGE_SN9C120) {
                        reg_w1(gspca_dev, 0x9a, 0x05);
@@ -1358,6 +1753,15 @@ static int sd_start(struct gspca_dev *gspca_dev)
 /*                     reg1 = 0x06;     * 640 clk 24Mz (done) */
                }
                break;
+       case SENSOR_MT9V111:
+               mt9v111_InitSensor(gspca_dev);
+               if (mode) {
+                       reg1 = 0x04;    /* 320 clk 48Mhz */
+               } else {
+/*                     reg1 = 0x06;     * 640 clk 24Mz (done) */
+                       reg17 = 0xc2;
+               }
+               break;
        case SENSOR_OM6802:
                om6802_InitSensor(gspca_dev);
                reg17 = 0x64;           /* 640 MCKSIZE */
@@ -1373,8 +1777,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg17 = 0x21;
 /*             reg1 = 0x42;             * 42 - 46? */
                break;
-       default:
-/*     case SENSOR_OV7660: */
+       case SENSOR_OV7660:
                ov7660_InitSensor(gspca_dev);
                if (sd->bridge == BRIDGE_SN9C120) {
                        if (mode) {             /* 320x240 - 160x120 */
@@ -1387,6 +1790,16 @@ static int sd_start(struct gspca_dev *gspca_dev)
                                         * inverse power down */
                }
                break;
+       default:
+/*     case SENSOR_SP80708: */
+               sp80708_InitSensor(gspca_dev);
+               if (mode) {
+/*??                   reg1 = 0x04;     * 320 clk 48Mhz */
+               } else {
+                       reg1 = 0x46;     /* 640 clk 48Mz */
+                       reg17 = 0xa2;
+               }
+               break;
        }
        reg_w(gspca_dev, 0xc0, C0, 6);
        reg_w(gspca_dev, 0xca, CA, 4);
@@ -1403,20 +1816,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
        }
 
        /* here change size mode 0 -> VGA; 1 -> CIF */
-       reg18 = sn9c1xx[0x18] | (mode << 4);
-       reg_w1(gspca_dev, 0x18, reg18 | 0x40);
-
-       reg_w(gspca_dev, 0x100, qtable4, 0x40);
-       reg_w(gspca_dev, 0x140, qtable4 + 0x40, 0x40);
-
-       reg_w1(gspca_dev, 0x18, reg18);
+       sd->reg18 = sn9c1xx[0x18] | (mode << 4) | 0x40;
+       reg_w1(gspca_dev, 0x18, sd->reg18);
+       setjpegqual(gspca_dev);
 
        reg_w1(gspca_dev, 0x17, reg17);
        reg_w1(gspca_dev, 0x01, reg1);
        switch (sd->sensor) {
-       case SENSOR_MI0360:
-               setinfrared(sd);
-               break;
        case SENSOR_OV7630:
                setvflip(sd);
                break;
@@ -1430,14 +1836,14 @@ static int sd_start(struct gspca_dev *gspca_dev)
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       static const __u8 stophv7131[] =
+       static const u8 stophv7131[] =
                { 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 };
-       static const __u8 stopmi0360[] =
+       static const u8 stopmi0360[] =
                { 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 };
-       static const __u8 stopov7648[] =
+       static const u8 stopov7648[] =
                { 0xa1, 0x21, 0x76, 0x20, 0x00, 0x00, 0x00, 0x10 };
-       __u8 data;
-       const __u8 *sn9c1xx;
+       u8 data;
+       const u8 *sn9c1xx;
 
        data = 0x0b;
        switch (sd->sensor) {
@@ -1452,6 +1858,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        case SENSOR_OV7648:
                i2c_w8(gspca_dev, stopov7648);
                /* fall thru */
+       case SENSOR_MT9V111:
        case SENSOR_OV7630:
                data = 0x29;
                break;
@@ -1468,13 +1875,20 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        reg_w1(gspca_dev, 0xf1, 0x00);
 }
 
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       kfree(sd->jpeg_hdr);
+}
+
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int delta;
        int expotimes;
-       __u8 luma_mean = 130;
-       __u8 luma_delta = 20;
+       u8 luma_mean = 130;
+       u8 luma_delta = 20;
 
        /* Thanks S., without your advice, autobright should not work :) */
        if (sd->ag_cnt < 0)
@@ -1499,6 +1913,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
                default:
 /*             case SENSOR_MO4000: */
 /*             case SENSOR_MI0360: */
+/*             case SENSOR_MT9V111: */
 /*             case SENSOR_OM6802: */
                        expotimes = sd->exposure;
                        expotimes += (luma_mean - delta) >> 6;
@@ -1516,7 +1931,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
 /* This function is run at interrupt level. */
 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;
@@ -1550,7 +1965,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        if (gspca_dev->last_packet_type == LAST_PACKET) {
 
                /* put the JPEG 422 header */
-               jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                       sd->jpeg_hdr, JPEG_HDR_SZ);
        }
        gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
@@ -1645,6 +2061,24 @@ static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->gamma = val;
+       if (gspca_dev->streaming)
+               setgamma(gspca_dev);
+       return 0;
+}
+
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->gamma;
+       return 0;
+}
+
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1699,6 +2133,34 @@ static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (jcomp->quality < QUALITY_MIN)
+               sd->quality = QUALITY_MIN;
+       else if (jcomp->quality > QUALITY_MAX)
+               sd->quality = QUALITY_MAX;
+       else
+               sd->quality = jcomp->quality;
+       if (gspca_dev->streaming)
+               jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+       return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       memset(jcomp, 0, sizeof *jcomp);
+       jcomp->quality = sd->quality;
+       jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+                       | V4L2_JPEG_MARKER_DQT;
+       return 0;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
@@ -1708,8 +2170,11 @@ static const struct sd_desc sd_desc = {
        .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
+       .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
        .dq_callback = do_autogain,
+       .get_jcomp = sd_get_jcomp,
+       .set_jcomp = sd_set_jcomp,
 };
 
 /* -- module initialisation -- */
@@ -1724,9 +2189,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
 #endif
        {USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)},
        {USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
        {USB_DEVICE(0x0471, 0x0327), BSI(SN9C105, MI0360, 0x5d)},
-#endif
        {USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)},
        {USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)},
        {USB_DEVICE(0x06f8, 0x3004), BSI(SN9C105, OV7660, 0x21)},
@@ -1764,10 +2227,10 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x21)},
 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
        {USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)},
+#endif
        {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)},
 /*     {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x??)}, */
-#endif
-       {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, MI0360, 0x5d)},
+       {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)},
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
@@ -1794,8 +2257,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        info("registered");
        return 0;
 }
index 942f04cd44dd4c9e46a28e272fd558a189bf67a3..6f38fa6d86b6ac7a03d9035d247d49a3d4b6e7eb 100644 (file)
@@ -38,8 +38,11 @@ struct sd {
        unsigned char brightness;
        unsigned char contrast;
        unsigned char colors;
+       u8 quality;
+#define QUALITY_MIN 70
+#define QUALITY_MAX 95
+#define QUALITY_DEF 85
 
-       char qindex;
        char subtype;
 #define AgfaCl20 0
 #define AiptekPocketDV 1
@@ -56,6 +59,8 @@ struct sd {
 #define Optimedia 12
 #define PalmPixDC85 13
 #define ToptroIndus 14
+
+       u8 *jpeg_hdr;
 };
 
 /* V4L2 controls supported by the driver */
@@ -629,7 +634,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct cam *cam;
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 0x01;
        sd->subtype = id->driver_info;
        if (sd->subtype != LogitechClickSmart310) {
                cam->cam_mode = vga_mode;
@@ -638,10 +642,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
                cam->cam_mode = sif_mode;
                cam->nmodes = ARRAY_SIZE(sif_mode);
        }
-       sd->qindex = 5;
        sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
        sd->colors = COLOR_DEF;
+       sd->quality = QUALITY_DEF;
        return 0;
 }
 
@@ -667,6 +671,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
        __u8 Data;
        __u8 xmult, ymult;
 
+       /* create the JPEG header */
+       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+                       0x22);          /* JPEG 411 */
+       jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
        if (sd->subtype == LogitechClickSmart310) {
                xmult = 0x16;
                ymult = 0x12;
@@ -713,7 +723,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
                write_vector(gspca_dev, spca500_visual_defaults);
                spca500_setmode(gspca_dev, xmult, ymult);
                /* enable drop packet */
-               reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
+               err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
+               if (err < 0)
                        PDEBUG(D_ERR, "failed to enable drop packet");
                reg_w(gspca_dev, 0x00, 0x8880, 3);
                err = spca50x_setup_qtable(gspca_dev,
@@ -881,6 +892,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
                gspca_dev->usb_buf[0]);
 }
 
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       kfree(sd->jpeg_hdr);
+}
+
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
@@ -901,7 +919,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                                        ffd9, 2);
 
                /* put the JPEG header in the new frame */
-               jpeg_put_header(gspca_dev, frame, sd->qindex, 0x22);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                       sd->jpeg_hdr, JPEG_HDR_SZ);
 
                data += SPCA500_OFFSET_DATA;
                len -= SPCA500_OFFSET_DATA;
@@ -937,16 +956,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
                        (__u8) (sd->brightness - 128));
 }
 
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       int ret;
-
-       ret = reg_r_12(gspca_dev, 0x00, 0x8167, 1);
-       if (ret >= 0)
-               sd->brightness = ret + 128;
-}
-
 static void setcontrast(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -954,16 +963,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
        reg_w(gspca_dev, 0x00, 0x8168, sd->contrast);
 }
 
-static void getcontrast(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       int ret;
-
-       ret = reg_r_12(gspca_dev, 0x0, 0x8168, 1);
-       if (ret >= 0)
-               sd->contrast = ret;
-}
-
 static void setcolors(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -971,16 +970,6 @@ static void setcolors(struct gspca_dev *gspca_dev)
        reg_w(gspca_dev, 0x00, 0x8169, sd->colors);
 }
 
-static void getcolors(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       int ret;
-
-       ret = reg_r_12(gspca_dev, 0x0, 0x8169, 1);
-       if (ret >= 0)
-               sd->colors = ret;
-}
-
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -995,7 +984,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getbrightness(gspca_dev);
        *val = sd->brightness;
        return 0;
 }
@@ -1014,7 +1002,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getcontrast(gspca_dev);
        *val = sd->contrast;
        return 0;
 }
@@ -1033,11 +1020,38 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getcolors(gspca_dev);
        *val = sd->colors;
        return 0;
 }
 
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (jcomp->quality < QUALITY_MIN)
+               sd->quality = QUALITY_MIN;
+       else if (jcomp->quality > QUALITY_MAX)
+               sd->quality = QUALITY_MAX;
+       else
+               sd->quality = jcomp->quality;
+       if (gspca_dev->streaming)
+               jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+       return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       memset(jcomp, 0, sizeof *jcomp);
+       jcomp->quality = sd->quality;
+       jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+                       | V4L2_JPEG_MARKER_DQT;
+       return 0;
+}
+
 /* sub-driver description */
 static struct sd_desc sd_desc = {
        .name = MODULE_NAME,
@@ -1047,7 +1061,10 @@ static struct sd_desc sd_desc = {
        .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
+       .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
+       .get_jcomp = sd_get_jcomp,
+       .set_jcomp = sd_set_jcomp,
 };
 
 /* -- module initialisation -- */
@@ -1093,8 +1110,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index 82e3e3e2ada1434cf4d0fa36f7d2df81e8121f3f..d48b27c648ca553b1e355fb0b2abed64b498d9e0 100644 (file)
@@ -1883,10 +1883,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
        reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, sd->brightness);
 }
 
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
-}
-
 static void setcontrast(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1897,10 +1893,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
                                  sd->contrast & 0xff);
 }
 
-static void getcontrast(struct gspca_dev *gspca_dev)
-{
-}
-
 static void setcolors(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1908,10 +1900,6 @@ static void setcolors(struct gspca_dev *gspca_dev)
        reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, sd->colors);
 }
 
-static void getcolors(struct gspca_dev *gspca_dev)
-{
-}
-
 static void setblue_balance(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1934,7 +1922,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct cam *cam;
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 0x01;
        cam->cam_mode = vga_mode;
        cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
        sd->subtype = id->driver_info;
@@ -2084,7 +2071,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getbrightness(gspca_dev);
        *val = sd->brightness;
        return 0;
 }
@@ -2103,7 +2089,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getcontrast(gspca_dev);
        *val = sd->contrast;
        return 0;
 }
@@ -2122,7 +2107,6 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getcolors(gspca_dev);
        *val = sd->colors;
        return 0;
 }
@@ -2211,8 +2195,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index 2a33a29010ee59f62ca2efed92dc874a23b86e30..2acec58b1b9734cb67512100d2323416f15f3dae 100644 (file)
@@ -31,9 +31,9 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;             /* !! must be the first item */
 
-       unsigned char brightness;
+       u8 brightness;
 
-       char subtype;
+       u8 subtype;
 #define IntelPCCameraPro 0
 #define Nxultra 1
 };
@@ -43,7 +43,6 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
-#define SD_BRIGHTNESS 0
        {
            {
                .id      = V4L2_CID_BRIGHTNESS,
@@ -52,7 +51,8 @@ static struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 255,
                .step    = 1,
-               .default_value = 127,
+#define BRIGHTNESS_DEF 127
+               .default_value = BRIGHTNESS_DEF,
            },
            .set = sd_setbrightness,
            .get = sd_getbrightness,
@@ -64,12 +64,12 @@ static const struct v4l2_pix_format vga_mode[] = {
                .bytesperline = 160,
                .sizeimage = 160 * 120 * 3 / 2,
                .colorspace = V4L2_COLORSPACE_SRGB,
-               .priv = 5},
+               .priv = 4},
        {176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
                .bytesperline = 176,
                .sizeimage = 176 * 144 * 3 / 2,
                .colorspace = V4L2_COLORSPACE_SRGB,
-               .priv = 4},
+               .priv = 3},
        {320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 3 / 2,
@@ -93,6 +93,7 @@ static const struct v4l2_pix_format vga_mode[] = {
 
 #define SPCA50X_USB_CTRL 0x00  /* spca505 */
 #define SPCA50X_CUSB_ENABLE 0x01 /* spca505 */
+
 #define SPCA50X_REG_GLOBAL 0x03        /* spca505 */
 #define SPCA50X_GMISC0_IDSEL 0x01 /* Global control device ID select spca505 */
 #define SPCA50X_GLOBAL_MISC0 0x00 /* Global control miscellaneous 0 spca505 */
@@ -101,230 +102,230 @@ static const struct v4l2_pix_format vga_mode[] = {
 #define SPCA50X_GLOBAL_MISC3 0x03 /* 505 */
 #define SPCA50X_GMISC3_SAA7113RST 0x20 /* Not sure about this one spca505 */
 
+/* Image format and compression control */
+#define SPCA50X_REG_COMPRESS 0x04
+
 /*
  * Data to initialize a SPCA505. Common to the CCD and external modes
  */
-static const __u16 spca505_init_data[][3] = {
-       /* line    bmRequest,value,index */
-       /* 1819 */
+static const u8 spca505_init_data[][3] = {
+       /* bmRequest,value,index */
        {SPCA50X_REG_GLOBAL, SPCA50X_GMISC3_SAA7113RST, SPCA50X_GLOBAL_MISC3},
        /* Sensor reset */
-       /* 1822 */ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC3},
-       /* 1825 */ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC1},
+       {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC3},
+       {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC1},
        /* Block USB reset */
-       /* 1828 */ {SPCA50X_REG_GLOBAL, SPCA50X_GMISC0_IDSEL,
-               SPCA50X_GLOBAL_MISC0},
+       {SPCA50X_REG_GLOBAL, SPCA50X_GMISC0_IDSEL, SPCA50X_GLOBAL_MISC0},
 
-       /* 1831 */ {0x5, 0x01, 0x10},
+       {0x05, 0x01, 0x10},
                                        /* Maybe power down some stuff */
-       /* 1834 */ {0x5, 0x0f, 0x11},
+       {0x05, 0x0f, 0x11},
 
        /* Setup internal CCD  ? */
-       /* 1837 */ {0x6, 0x10, 0x08},
-       /* 1840 */ {0x6, 0x00, 0x09},
-       /* 1843 */ {0x6, 0x00, 0x0a},
-       /* 1846 */ {0x6, 0x00, 0x0b},
-       /* 1849 */ {0x6, 0x10, 0x0c},
-       /* 1852 */ {0x6, 0x00, 0x0d},
-       /* 1855 */ {0x6, 0x00, 0x0e},
-       /* 1858 */ {0x6, 0x00, 0x0f},
-       /* 1861 */ {0x6, 0x10, 0x10},
-       /* 1864 */ {0x6, 0x02, 0x11},
-       /* 1867 */ {0x6, 0x00, 0x12},
-       /* 1870 */ {0x6, 0x04, 0x13},
-       /* 1873 */ {0x6, 0x02, 0x14},
-       /* 1876 */ {0x6, 0x8a, 0x51},
-       /* 1879 */ {0x6, 0x40, 0x52},
-       /* 1882 */ {0x6, 0xb6, 0x53},
-       /* 1885 */ {0x6, 0x3d, 0x54},
+       {0x06, 0x10, 0x08},
+       {0x06, 0x00, 0x09},
+       {0x06, 0x00, 0x0a},
+       {0x06, 0x00, 0x0b},
+       {0x06, 0x10, 0x0c},
+       {0x06, 0x00, 0x0d},
+       {0x06, 0x00, 0x0e},
+       {0x06, 0x00, 0x0f},
+       {0x06, 0x10, 0x10},
+       {0x06, 0x02, 0x11},
+       {0x06, 0x00, 0x12},
+       {0x06, 0x04, 0x13},
+       {0x06, 0x02, 0x14},
+       {0x06, 0x8a, 0x51},
+       {0x06, 0x40, 0x52},
+       {0x06, 0xb6, 0x53},
+       {0x06, 0x3d, 0x54},
        {}
 };
 
 /*
  * Data to initialize the camera using the internal CCD
  */
-static const __u16 spca505_open_data_ccd[][3] = {
-       /* line    bmRequest,value,index */
+static const u8 spca505_open_data_ccd[][3] = {
+       /* bmRequest,value,index */
        /* Internal CCD data set */
-       /* 1891 */ {0x3, 0x04, 0x01},
+       {0x03, 0x04, 0x01},
        /* This could be a reset */
-       /* 1894 */ {0x3, 0x00, 0x01},
+       {0x03, 0x00, 0x01},
 
        /* Setup compression and image registers. 0x6 and 0x7 seem to be
           related to H&V hold, and are resolution mode specific */
-               /* 1897 */ {0x4, 0x10, 0x01},
+               {0x04, 0x10, 0x01},
                /* DIFF(0x50), was (0x10) */
-       /* 1900 */ {0x4, 0x00, 0x04},
-       /* 1903 */ {0x4, 0x00, 0x05},
-       /* 1906 */ {0x4, 0x20, 0x06},
-       /* 1909 */ {0x4, 0x20, 0x07},
+       {0x04, 0x00, 0x04},
+       {0x04, 0x00, 0x05},
+       {0x04, 0x20, 0x06},
+       {0x04, 0x20, 0x07},
 
-       /* 1912 */ {0x8, 0x0a, 0x00},
+       {0x08, 0x0a, 0x00},
        /* DIFF (0x4a), was (0xa) */
 
-       /* 1915 */ {0x5, 0x00, 0x10},
-       /* 1918 */ {0x5, 0x00, 0x11},
-       /* 1921 */ {0x5, 0x00, 0x00},
+       {0x05, 0x00, 0x10},
+       {0x05, 0x00, 0x11},
+       {0x05, 0x00, 0x00},
        /* DIFF not written */
-       /* 1924 */ {0x5, 0x00, 0x01},
+       {0x05, 0x00, 0x01},
        /* DIFF not written */
-       /* 1927 */ {0x5, 0x00, 0x02},
+       {0x05, 0x00, 0x02},
        /* DIFF not written */
-       /* 1930 */ {0x5, 0x00, 0x03},
+       {0x05, 0x00, 0x03},
        /* DIFF not written */
-       /* 1933 */ {0x5, 0x00, 0x04},
+       {0x05, 0x00, 0x04},
        /* DIFF not written */
-               /* 1936 */ {0x5, 0x80, 0x05},
+               {0x05, 0x80, 0x05},
                /* DIFF not written */
-               /* 1939 */ {0x5, 0xe0, 0x06},
+               {0x05, 0xe0, 0x06},
                /* DIFF not written */
-               /* 1942 */ {0x5, 0x20, 0x07},
+               {0x05, 0x20, 0x07},
                /* DIFF not written */
-               /* 1945 */ {0x5, 0xa0, 0x08},
+               {0x05, 0xa0, 0x08},
                /* DIFF not written */
-               /* 1948 */ {0x5, 0x0, 0x12},
+               {0x05, 0x0, 0x12},
                /* DIFF not written */
-       /* 1951 */ {0x5, 0x02, 0x0f},
+       {0x05, 0x02, 0x0f},
        /* DIFF not written */
-               /* 1954 */ {0x5, 0x10, 0x46},
+               {0x05, 0x10, 0x46},
                /* DIFF not written */
-               /* 1957 */ {0x5, 0x8, 0x4a},
+               {0x05, 0x8, 0x4a},
                /* DIFF not written */
 
-       /* 1960 */ {0x3, 0x08, 0x03},
+       {0x03, 0x08, 0x03},
        /* DIFF (0x3,0x28,0x3) */
-       /* 1963 */ {0x3, 0x08, 0x01},
-       /* 1966 */ {0x3, 0x0c, 0x03},
+       {0x03, 0x08, 0x01},
+       {0x03, 0x0c, 0x03},
        /* DIFF not written */
-               /* 1969 */ {0x3, 0x21, 0x00},
+               {0x03, 0x21, 0x00},
                /* DIFF (0x39) */
 
 /* Extra block copied from init to hopefully ensure CCD is in a sane state */
-       /* 1837 */ {0x6, 0x10, 0x08},
-       /* 1840 */ {0x6, 0x00, 0x09},
-       /* 1843 */ {0x6, 0x00, 0x0a},
-       /* 1846 */ {0x6, 0x00, 0x0b},
-       /* 1849 */ {0x6, 0x10, 0x0c},
-       /* 1852 */ {0x6, 0x00, 0x0d},
-       /* 1855 */ {0x6, 0x00, 0x0e},
-       /* 1858 */ {0x6, 0x00, 0x0f},
-       /* 1861 */ {0x6, 0x10, 0x10},
-       /* 1864 */ {0x6, 0x02, 0x11},
-       /* 1867 */ {0x6, 0x00, 0x12},
-       /* 1870 */ {0x6, 0x04, 0x13},
-       /* 1873 */ {0x6, 0x02, 0x14},
-       /* 1876 */ {0x6, 0x8a, 0x51},
-       /* 1879 */ {0x6, 0x40, 0x52},
-       /* 1882 */ {0x6, 0xb6, 0x53},
-       /* 1885 */ {0x6, 0x3d, 0x54},
+       {0x06, 0x10, 0x08},
+       {0x06, 0x00, 0x09},
+       {0x06, 0x00, 0x0a},
+       {0x06, 0x00, 0x0b},
+       {0x06, 0x10, 0x0c},
+       {0x06, 0x00, 0x0d},
+       {0x06, 0x00, 0x0e},
+       {0x06, 0x00, 0x0f},
+       {0x06, 0x10, 0x10},
+       {0x06, 0x02, 0x11},
+       {0x06, 0x00, 0x12},
+       {0x06, 0x04, 0x13},
+       {0x06, 0x02, 0x14},
+       {0x06, 0x8a, 0x51},
+       {0x06, 0x40, 0x52},
+       {0x06, 0xb6, 0x53},
+       {0x06, 0x3d, 0x54},
        /* End of extra block */
 
-               /* 1972 */ {0x6, 0x3f, 0x1},
+               {0x06, 0x3f, 0x1},
                /* Block skipped */
-       /* 1975 */ {0x6, 0x10, 0x02},
-       /* 1978 */ {0x6, 0x64, 0x07},
-       /* 1981 */ {0x6, 0x10, 0x08},
-       /* 1984 */ {0x6, 0x00, 0x09},
-       /* 1987 */ {0x6, 0x00, 0x0a},
-       /* 1990 */ {0x6, 0x00, 0x0b},
-       /* 1993 */ {0x6, 0x10, 0x0c},
-       /* 1996 */ {0x6, 0x00, 0x0d},
-       /* 1999 */ {0x6, 0x00, 0x0e},
-       /* 2002 */ {0x6, 0x00, 0x0f},
-       /* 2005 */ {0x6, 0x10, 0x10},
-       /* 2008 */ {0x6, 0x02, 0x11},
-       /* 2011 */ {0x6, 0x00, 0x12},
-       /* 2014 */ {0x6, 0x04, 0x13},
-       /* 2017 */ {0x6, 0x02, 0x14},
-       /* 2020 */ {0x6, 0x8a, 0x51},
-       /* 2023 */ {0x6, 0x40, 0x52},
-       /* 2026 */ {0x6, 0xb6, 0x53},
-       /* 2029 */ {0x6, 0x3d, 0x54},
-       /* 2032 */ {0x6, 0x60, 0x57},
-       /* 2035 */ {0x6, 0x20, 0x58},
-       /* 2038 */ {0x6, 0x15, 0x59},
-       /* 2041 */ {0x6, 0x05, 0x5a},
-
-       /* 2044 */ {0x5, 0x01, 0xc0},
-       /* 2047 */ {0x5, 0x10, 0xcb},
-               /* 2050 */ {0x5, 0x80, 0xc1},
+       {0x06, 0x10, 0x02},
+       {0x06, 0x64, 0x07},
+       {0x06, 0x10, 0x08},
+       {0x06, 0x00, 0x09},
+       {0x06, 0x00, 0x0a},
+       {0x06, 0x00, 0x0b},
+       {0x06, 0x10, 0x0c},
+       {0x06, 0x00, 0x0d},
+       {0x06, 0x00, 0x0e},
+       {0x06, 0x00, 0x0f},
+       {0x06, 0x10, 0x10},
+       {0x06, 0x02, 0x11},
+       {0x06, 0x00, 0x12},
+       {0x06, 0x04, 0x13},
+       {0x06, 0x02, 0x14},
+       {0x06, 0x8a, 0x51},
+       {0x06, 0x40, 0x52},
+       {0x06, 0xb6, 0x53},
+       {0x06, 0x3d, 0x54},
+       {0x06, 0x60, 0x57},
+       {0x06, 0x20, 0x58},
+       {0x06, 0x15, 0x59},
+       {0x06, 0x05, 0x5a},
+
+       {0x05, 0x01, 0xc0},
+       {0x05, 0x10, 0xcb},
+               {0x05, 0x80, 0xc1},
                /* */
-               /* 2053 */ {0x5, 0x0, 0xc2},
+               {0x05, 0x0, 0xc2},
                /* 4 was 0 */
-       /* 2056 */ {0x5, 0x00, 0xca},
-               /* 2059 */ {0x5, 0x80, 0xc1},
+       {0x05, 0x00, 0xca},
+               {0x05, 0x80, 0xc1},
                /*  */
-       /* 2062 */ {0x5, 0x04, 0xc2},
-       /* 2065 */ {0x5, 0x00, 0xca},
-               /* 2068 */ {0x5, 0x0, 0xc1},
+       {0x05, 0x04, 0xc2},
+       {0x05, 0x00, 0xca},
+               {0x05, 0x0, 0xc1},
                /*  */
-       /* 2071 */ {0x5, 0x00, 0xc2},
-       /* 2074 */ {0x5, 0x00, 0xca},
-               /* 2077 */ {0x5, 0x40, 0xc1},
+       {0x05, 0x00, 0xc2},
+       {0x05, 0x00, 0xca},
+               {0x05, 0x40, 0xc1},
                /* */
-       /* 2080 */ {0x5, 0x17, 0xc2},
-       /* 2083 */ {0x5, 0x00, 0xca},
-               /* 2086 */ {0x5, 0x80, 0xc1},
+       {0x05, 0x17, 0xc2},
+       {0x05, 0x00, 0xca},
+               {0x05, 0x80, 0xc1},
                /* */
-       /* 2089 */ {0x5, 0x06, 0xc2},
-       /* 2092 */ {0x5, 0x00, 0xca},
-               /* 2095 */ {0x5, 0x80, 0xc1},
+       {0x05, 0x06, 0xc2},
+       {0x05, 0x00, 0xca},
+               {0x05, 0x80, 0xc1},
                /* */
-       /* 2098 */ {0x5, 0x04, 0xc2},
-       /* 2101 */ {0x5, 0x00, 0xca},
+       {0x05, 0x04, 0xc2},
+       {0x05, 0x00, 0xca},
 
-       /* 2104 */ {0x3, 0x4c, 0x3},
-       /* 2107 */ {0x3, 0x18, 0x1},
+       {0x03, 0x4c, 0x3},
+       {0x03, 0x18, 0x1},
 
-       /* 2110 */ {0x6, 0x70, 0x51},
-       /* 2113 */ {0x6, 0xbe, 0x53},
-       /* 2116 */ {0x6, 0x71, 0x57},
-       /* 2119 */ {0x6, 0x20, 0x58},
-       /* 2122 */ {0x6, 0x05, 0x59},
-       /* 2125 */ {0x6, 0x15, 0x5a},
+       {0x06, 0x70, 0x51},
+       {0x06, 0xbe, 0x53},
+       {0x06, 0x71, 0x57},
+       {0x06, 0x20, 0x58},
+       {0x06, 0x05, 0x59},
+       {0x06, 0x15, 0x5a},
 
-       /* 2128 */ {0x4, 0x00, 0x08},
+       {0x04, 0x00, 0x08},
        /* Compress = OFF (0x1 to turn on) */
-       /* 2131 */ {0x4, 0x12, 0x09},
-       /* 2134 */ {0x4, 0x21, 0x0a},
-       /* 2137 */ {0x4, 0x10, 0x0b},
-       /* 2140 */ {0x4, 0x21, 0x0c},
-       /* 2143 */ {0x4, 0x05, 0x00},
+       {0x04, 0x12, 0x09},
+       {0x04, 0x21, 0x0a},
+       {0x04, 0x10, 0x0b},
+       {0x04, 0x21, 0x0c},
+       {0x04, 0x05, 0x00},
        /* was 5 (Image Type ? ) */
-       /* 2146 */ {0x4, 0x00, 0x01},
-
-       /* 2149 */ {0x6, 0x3f, 0x01},
-
-       /* 2152 */ {0x4, 0x00, 0x04},
-       /* 2155 */ {0x4, 0x00, 0x05},
-       /* 2158 */ {0x4, 0x40, 0x06},
-       /* 2161 */ {0x4, 0x40, 0x07},
-
-       /* 2164 */ {0x6, 0x1c, 0x17},
-       /* 2167 */ {0x6, 0xe2, 0x19},
-       /* 2170 */ {0x6, 0x1c, 0x1b},
-       /* 2173 */ {0x6, 0xe2, 0x1d},
-       /* 2176 */ {0x6, 0xaa, 0x1f},
-       /* 2179 */ {0x6, 0x70, 0x20},
-
-       /* 2182 */ {0x5, 0x01, 0x10},
-       /* 2185 */ {0x5, 0x00, 0x11},
-       /* 2188 */ {0x5, 0x01, 0x00},
-       /* 2191 */ {0x5, 0x05, 0x01},
-               /* 2194 */ {0x5, 0x00, 0xc1},
+       {0x04, 0x00, 0x01},
+
+       {0x06, 0x3f, 0x01},
+
+       {0x04, 0x00, 0x04},
+       {0x04, 0x00, 0x05},
+       {0x04, 0x40, 0x06},
+       {0x04, 0x40, 0x07},
+
+       {0x06, 0x1c, 0x17},
+       {0x06, 0xe2, 0x19},
+       {0x06, 0x1c, 0x1b},
+       {0x06, 0xe2, 0x1d},
+       {0x06, 0xaa, 0x1f},
+       {0x06, 0x70, 0x20},
+
+       {0x05, 0x01, 0x10},
+       {0x05, 0x00, 0x11},
+       {0x05, 0x01, 0x00},
+       {0x05, 0x05, 0x01},
+               {0x05, 0x00, 0xc1},
                /* */
-       /* 2197 */ {0x5, 0x00, 0xc2},
-       /* 2200 */ {0x5, 0x00, 0xca},
+       {0x05, 0x00, 0xc2},
+       {0x05, 0x00, 0xca},
 
-       /* 2203 */ {0x6, 0x70, 0x51},
-       /* 2206 */ {0x6, 0xbe, 0x53},
+       {0x06, 0x70, 0x51},
+       {0x06, 0xbe, 0x53},
        {}
 };
 
 /*
  Made by Tomasz Zablocki (skalamandra@poczta.onet.pl)
* Made by Tomasz Zablocki (skalamandra@poczta.onet.pl)
  * SPCA505b chip based cameras initialization data
- *
  */
 /* jfm */
 #define initial_brightness 0x7f        /* 0x0(white)-0xff(black) */
@@ -332,7 +333,7 @@ static const __u16 spca505_open_data_ccd[][3] = {
 /*
  * Data to initialize a SPCA505. Common to the CCD and external modes
  */
-static const __u16 spca505b_init_data[][3] = {
+static const u8 spca505b_init_data[][3] = {
 /* start */
        {0x02, 0x00, 0x00},             /* init */
        {0x02, 0x00, 0x01},
@@ -396,7 +397,7 @@ static const __u16 spca505b_init_data[][3] = {
 /*
  * Data to initialize the camera using the internal CCD
  */
-static const __u16 spca505b_open_data_ccd[][3] = {
+static const u8 spca505b_open_data_ccd[][3] = {
 
 /* {0x02,0x00,0x00}, */
        {0x03, 0x04, 0x01},             /* rst */
@@ -426,7 +427,7 @@ static const __u16 spca505b_open_data_ccd[][3] = {
        {0x05, 0x00, 0x12},
        {0x05, 0x6f, 0x00},
        {0x05, initial_brightness >> 6, 0x00},
-       {0x05, initial_brightness << 2, 0x01},
+       {0x05, (initial_brightness << 2) & 0xff, 0x01},
        {0x05, 0x00, 0x02},
        {0x05, 0x01, 0x03},
        {0x05, 0x00, 0x04},
@@ -436,7 +437,7 @@ static const __u16 spca505b_open_data_ccd[][3] = {
        {0x05, 0xa0, 0x08},
        {0x05, 0x00, 0x12},
        {0x05, 0x02, 0x0f},
-       {0x05, 128, 0x14},              /* max exposure off (0=on) */
+       {0x05, 0x80, 0x14},             /* max exposure off (0=on) */
        {0x05, 0x01, 0xb0},
        {0x05, 0x01, 0xbf},
        {0x03, 0x02, 0x06},
@@ -560,26 +561,26 @@ static const __u16 spca505b_open_data_ccd[][3] = {
        {0x06, 0x32, 0x20},
 
        {0x05, initial_brightness >> 6, 0x00},
-       {0x05, initial_brightness << 2, 0x01},
+       {0x05, (initial_brightness << 2) & 0xff, 0x01},
        {0x05, 0x06, 0xc1},
        {0x05, 0x58, 0xc2},
-       {0x05, 0x0, 0xca},
-       {0x05, 0x0, 0x11},
+       {0x05, 0x00, 0xca},
+       {0x05, 0x00, 0x11},
        {}
 };
 
 static int reg_write(struct usb_device *dev,
-                    __u16 reg, __u16 index, __u16 value)
+                    u16 req, u16 index, u16 value)
 {
        int ret;
 
        ret = usb_control_msg(dev,
                        usb_sndctrlpipe(dev, 0),
-                       reg,
+                       req,
                        USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        value, index, NULL, 0, 500);
-       PDEBUG(D_PACK, "reg write: 0x%02x,0x%02x:0x%02x, 0x%x",
-               reg, index, value, ret);
+       PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d",
+               req, index, value, ret);
        if (ret < 0)
                PDEBUG(D_ERR, "reg write: error %d", ret);
        return ret;
@@ -587,42 +588,34 @@ static int reg_write(struct usb_device *dev,
 
 /* returns: negative is error, pos or zero is data */
 static int reg_read(struct gspca_dev *gspca_dev,
-                       __u16 reg,      /* bRequest */
-                       __u16 index,    /* wIndex */
-                       __u16 length)   /* wLength (1 or 2 only) */
+                       u16 req,        /* bRequest */
+                       u16 index)      /* wIndex */
 {
        int ret;
 
-       gspca_dev->usb_buf[1] = 0;
        ret = usb_control_msg(gspca_dev->dev,
                        usb_rcvctrlpipe(gspca_dev->dev, 0),
-                       reg,
+                       req,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       (__u16) 0,              /* value */
-                       (__u16) index,
-                       gspca_dev->usb_buf, length,
+                       0,                      /* value */
+                       index,
+                       gspca_dev->usb_buf, 2,
                        500);                   /* timeout */
-       if (ret < 0) {
-               PDEBUG(D_ERR, "reg_read err %d", ret);
-               return -1;
-       }
+       if (ret < 0)
+               return ret;
        return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
 }
 
 static int write_vector(struct gspca_dev *gspca_dev,
-                       const __u16 data[][3])
+                       const u8 data[][3])
 {
        struct usb_device *dev = gspca_dev->dev;
        int ret, i = 0;
 
-       while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+       while (data[i][0] != 0) {
                ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
-               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]);
+               if (ret < 0)
                        return ret;
-               }
                i++;
        }
        return 0;
@@ -636,14 +629,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct cam *cam;
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 0x01;
        cam->cam_mode = vga_mode;
        sd->subtype = id->driver_info;
        if (sd->subtype != IntelPCCameraPro)
-               cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+               cam->nmodes = ARRAY_SIZE(vga_mode);
        else                    /* no 640x480 for IntelPCCameraPro */
-               cam->nmodes = sizeof vga_mode / sizeof vga_mode[0] - 1;
-       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+               cam->nmodes = ARRAY_SIZE(vga_mode) - 1;
+       sd->brightness = BRIGHTNESS_DEF;
 
        if (sd->subtype == Nxultra) {
                if (write_vector(gspca_dev, spca505b_init_data))
@@ -657,82 +649,72 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
+{
+       return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int ret;
+       u8 brightness = sd->brightness;
+
+       reg_write(gspca_dev->dev, 0x05, 0x00, (255 - brightness) >> 6);
+       reg_write(gspca_dev->dev, 0x05, 0x01, (255 - brightness) << 2);
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       int ret, mode;
+       static u8 mode_tb[][3] = {
+       /*        r00   r06   r07       */
+               {0x00, 0x10, 0x10},     /* 640x480 */
+               {0x01, 0x1a, 0x1a},     /* 352x288 */
+               {0x02, 0x1c, 0x1d},     /* 320x240 */
+               {0x04, 0x34, 0x34},     /* 176x144 */
+               {0x05, 0x40, 0x40}      /* 160x120 */
+       };
 
-       PDEBUG(D_STREAM, "Initializing SPCA505");
        if (sd->subtype == Nxultra)
                write_vector(gspca_dev, spca505b_open_data_ccd);
        else
                write_vector(gspca_dev, spca505_open_data_ccd);
-       ret = reg_read(gspca_dev, 6, 0x16, 2);
+       ret = reg_read(gspca_dev, 0x06, 0x16);
 
        if (ret < 0) {
-               PDEBUG(D_ERR|D_STREAM,
-                      "register read failed for after vector read err = %d",
+               PDEBUG(D_ERR|D_CONF,
+                      "register read failed err: %d",
                       ret);
-               return -EIO;
+               return ret;
        }
-       PDEBUG(D_STREAM,
-               "After vector read returns : 0x%x should be 0x0101",
-               ret & 0xffff);
-
-       ret = reg_write(gspca_dev->dev, 6, 0x16, 0x0a);
-       if (ret < 0) {
-               PDEBUG(D_ERR, "register write failed for (6,0xa,0x16) err=%d",
-                      ret);
-               return -EIO;
+       if (ret != 0x0101) {
+               PDEBUG(D_ERR|D_CONF,
+                       "After vector read returns 0x%04x should be 0x0101",
+                       ret);
        }
-       reg_write(gspca_dev->dev, 5, 0xc2, 18);
-       return 0;
-}
 
-static int sd_start(struct gspca_dev *gspca_dev)
-{
-       struct usb_device *dev = gspca_dev->dev;
-       int ret;
+       ret = reg_write(gspca_dev->dev, 0x06, 0x16, 0x0a);
+       if (ret < 0)
+               return ret;
+       reg_write(gspca_dev->dev, 0x05, 0xc2, 0x12);
 
        /* necessary because without it we can see stream
         * only once after loading module */
        /* stopping usb registers Tomasz change */
-       reg_write(dev, 0x02, 0x0, 0x0);
-       switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
-       case 0:
-               reg_write(dev, 0x04, 0x00, 0x00);
-               reg_write(dev, 0x04, 0x06, 0x10);
-               reg_write(dev, 0x04, 0x07, 0x10);
-               break;
-       case 1:
-               reg_write(dev, 0x04, 0x00, 0x01);
-               reg_write(dev, 0x04, 0x06, 0x1a);
-               reg_write(dev, 0x04, 0x07, 0x1a);
-               break;
-       case 2:
-               reg_write(dev, 0x04, 0x00, 0x02);
-               reg_write(dev, 0x04, 0x06, 0x1c);
-               reg_write(dev, 0x04, 0x07, 0x1d);
-               break;
-       case 4:
-               reg_write(dev, 0x04, 0x00, 0x04);
-               reg_write(dev, 0x04, 0x06, 0x34);
-               reg_write(dev, 0x04, 0x07, 0x34);
-               break;
-       default:
-/*     case 5: */
-               reg_write(dev, 0x04, 0x00, 0x05);
-               reg_write(dev, 0x04, 0x06, 0x40);
-               reg_write(dev, 0x04, 0x07, 0x40);
-               break;
-       }
-/* Enable ISO packet machine - should we do this here or in ISOC init ? */
+       reg_write(dev, 0x02, 0x00, 0x00);
+
+       mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+       reg_write(dev, SPCA50X_REG_COMPRESS, 0x00, mode_tb[mode][0]);
+       reg_write(dev, SPCA50X_REG_COMPRESS, 0x06, mode_tb[mode][1]);
+       reg_write(dev, SPCA50X_REG_COMPRESS, 0x07, mode_tb[mode][2]);
+
        ret = reg_write(dev, SPCA50X_REG_USB,
                         SPCA50X_USB_CTRL,
                         SPCA50X_CUSB_ENABLE);
 
-/*     reg_write(dev, 0x5, 0x0, 0x0); */
-/*     reg_write(dev, 0x5, 0x0, 0x1); */
-/*     reg_write(dev, 0x5, 0x11, 0x2); */
+       setbrightness(gspca_dev);
+
        return ret;
 }
 
@@ -750,15 +732,15 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
 
        /* This maybe reset or power control */
        reg_write(gspca_dev->dev, 0x03, 0x03, 0x20);
-       reg_write(gspca_dev->dev, 0x03, 0x01, 0x0);
-       reg_write(gspca_dev->dev, 0x03, 0x00, 0x1);
-       reg_write(gspca_dev->dev, 0x05, 0x10, 0x1);
-       reg_write(gspca_dev->dev, 0x05, 0x11, 0xf);
+       reg_write(gspca_dev->dev, 0x03, 0x01, 0x00);
+       reg_write(gspca_dev->dev, 0x03, 0x00, 0x01);
+       reg_write(gspca_dev->dev, 0x05, 0x10, 0x01);
+       reg_write(gspca_dev->dev, 0x05, 0x11, 0x0f);
 }
 
 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 */
 {
        switch (data[0]) {
@@ -771,7 +753,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                                data, len);
                break;
        case 0xff:                      /* drop */
-/*             gspca_dev->last_packet_type = DISCARD_PACKET; */
                break;
        default:
                data += 1;
@@ -782,24 +763,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        }
 }
 
-static void setbrightness(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       __u8 brightness = sd->brightness;
-       reg_write(gspca_dev->dev, 5, 0x00, (255 - brightness) >> 6);
-       reg_write(gspca_dev->dev, 5, 0x01, (255 - brightness) << 2);
-
-}
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->brightness = 255
-               - ((reg_read(gspca_dev, 5, 0x01, 1) >> 2)
-                       + (reg_read(gspca_dev, 5, 0x0, 1) << 6));
-}
-
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -814,7 +777,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getbrightness(gspca_dev);
        *val = sd->brightness;
        return 0;
 }
@@ -863,8 +825,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index 96e2512e0621df5e1cebfaafbb98e436676301d1..3a0c893f942da2cdbeb5b388f85f76e48ced6c4f 100644 (file)
@@ -193,24 +193,6 @@ static void spca506_WriteI2c(struct gspca_dev *gspca_dev, __u16 valeur,
        }
 }
 
-static int spca506_ReadI2c(struct gspca_dev *gspca_dev, __u16 reg)
-{
-       int retry = 60;
-
-       reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004);
-       reg_w(gspca_dev->dev, 0x07, reg, 0x0001);
-       reg_w(gspca_dev->dev, 0x07, 0x01, 0x0002);
-       while (--retry) {
-               reg_r(gspca_dev, 0x07, 0x0003, 2);
-               if ((gspca_dev->usb_buf[0] | gspca_dev->usb_buf[1]) == 0x00)
-                       break;
-       }
-       if (retry == 0)
-               return -1;
-       reg_r(gspca_dev, 0x07, 0x0000, 1);
-       return gspca_dev->usb_buf[0];
-}
-
 static void spca506_SetNormeInput(struct gspca_dev *gspca_dev,
                                 __u16 norme,
                                 __u16 channel)
@@ -303,7 +285,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct cam *cam;
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 0x01;
        cam->cam_mode = vga_mode;
        cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
        sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
@@ -596,13 +577,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
        spca506_WriteI2c(gspca_dev, 0x01, 0x09);
 }
 
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->brightness = spca506_ReadI2c(gspca_dev, SAA7113_bright);
-}
-
 static void setcontrast(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -612,13 +586,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
        spca506_WriteI2c(gspca_dev, 0x01, 0x09);
 }
 
-static void getcontrast(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->contrast = spca506_ReadI2c(gspca_dev, SAA7113_contrast);
-}
-
 static void setcolors(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -628,13 +595,6 @@ static void setcolors(struct gspca_dev *gspca_dev)
        spca506_WriteI2c(gspca_dev, 0x01, 0x09);
 }
 
-static void getcolors(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->colors = spca506_ReadI2c(gspca_dev, SAA7113_saturation);
-}
-
 static void sethue(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -644,13 +604,6 @@ static void sethue(struct gspca_dev *gspca_dev)
        spca506_WriteI2c(gspca_dev, 0x01, 0x09);
 }
 
-static void gethue(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->hue = spca506_ReadI2c(gspca_dev, SAA7113_hue);
-}
-
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -665,7 +618,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getbrightness(gspca_dev);
        *val = sd->brightness;
        return 0;
 }
@@ -684,7 +636,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getcontrast(gspca_dev);
        *val = sd->contrast;
        return 0;
 }
@@ -703,7 +654,6 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getcolors(gspca_dev);
        *val = sd->colors;
        return 0;
 }
@@ -722,7 +672,6 @@ static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       gethue(gspca_dev);
        *val = sd->hue;
        return 0;
 }
@@ -772,8 +721,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index be5d740a315d614b95f7077bcb11b4137e65e32e..adacf8437661366a2c8d228f47fc499dd3479f02 100644 (file)
@@ -101,8 +101,7 @@ static const struct v4l2_pix_format sif_mode[] = {
  * Initialization data: this is the first set-up data written to the
  * device (before the open data).
  */
-static const __u16 spca508_init_data[][3] =
-#define IGN(x)                 /* nothing */
+static const u16 spca508_init_data[][2] =
 {
        /*  line   URB      value, index */
        /* 44274  1804 */ {0x0000, 0x870b},
@@ -589,11 +588,10 @@ static const __u16 spca508_init_data[][3] =
        {}
 };
 
-
 /*
  * Initialization data for Intel EasyPC Camera CS110
  */
-static const __u16 spca508cs110_init_data[][3] = {
+static const u16 spca508cs110_init_data[][2] = {
        {0x0000, 0x870b}, /* Reset CTL3 */
        {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
        {0x0000, 0x8111}, /* Normal operation on reset */
@@ -677,7 +675,7 @@ static const __u16 spca508cs110_init_data[][3] = {
        {}
 };
 
-static const __u16 spca508_sightcam_init_data[][3] = {
+static const u16 spca508_sightcam_init_data[][2] = {
 /* This line seems to setup the frame/canvas */
        /*368  */ {0x000f, 0x8402},
 
@@ -760,7 +758,7 @@ static const __u16 spca508_sightcam_init_data[][3] = {
        {}
 };
 
-static const __u16 spca508_sightcam2_init_data[][3] = {
+static const u16 spca508_sightcam2_init_data[][2] = {
 /* 35 */ {0x0020, 0x8112},
 
 /* 36 */ {0x000f, 0x8402},
@@ -1107,7 +1105,7 @@ static const __u16 spca508_sightcam2_init_data[][3] = {
 /*
  * Initialization data for Creative Webcam Vista
  */
-static const __u16 spca508_vista_init_data[][3] = {
+static const u16 spca508_vista_init_data[][2] = {
        {0x0008, 0x8200},       /* Clear register */
        {0x0000, 0x870b},       /* Reset CTL3 */
        {0x0020, 0x8112},       /* Video Drop packet enable */
@@ -1309,18 +1307,18 @@ static const __u16 spca508_vista_init_data[][3] = {
 
        {0x0050, 0x8703},
        {0x0002, 0x8704},       /* External input CKIx1 */
-       {0x0001, 0x870C},       /* Select CKOx2 output */
-       {0x009A, 0x8600},       /* Line memory Read Counter (L) */
+       {0x0001, 0x870c},       /* Select CKOx2 output */
+       {0x009a, 0x8600},       /* Line memory Read Counter (L) */
        {0x0001, 0x8606},  /* 1 Line memory Read Counter (H) Result: (d)410 */
        {0x0023, 0x8601},
        {0x0010, 0x8602},
-       {0x000A, 0x8603},
+       {0x000a, 0x8603},
        {0x009A, 0x8600},
-       {0x0001, 0x865B},       /* 1 Horizontal Offset for Valid Pixel(L) */
-       {0x0003, 0x865C},       /* Vertical offset for valid lines (L) */
-       {0x0058, 0x865D},       /* Horizontal valid pixels window (L) */
-       {0x0048, 0x865E},       /* Vertical valid lines window (L) */
-       {0x0000, 0x865F},
+       {0x0001, 0x865b},       /* 1 Horizontal Offset for Valid Pixel(L) */
+       {0x0003, 0x865c},       /* Vertical offset for valid lines (L) */
+       {0x0058, 0x865d},       /* Horizontal valid pixels window (L) */
+       {0x0048, 0x865e},       /* Vertical valid lines window (L) */
+       {0x0000, 0x865f},
 
        {0x0006, 0x8660},
                    /* Enable nibble data input, select nibble input order */
@@ -1328,63 +1326,63 @@ static const __u16 spca508_vista_init_data[][3] = {
        {0x0013, 0x8608},       /* A11 Coeficients for color correction */
        {0x0028, 0x8609},
                    /* Note: these values are confirmed at the end of array */
-       {0x0005, 0x860A},       /* ... */
-       {0x0025, 0x860B},
-       {0x00E1, 0x860C},
-       {0x00FA, 0x860D},
-       {0x00F4, 0x860E},
-       {0x00E8, 0x860F},
+       {0x0005, 0x860a},       /* ... */
+       {0x0025, 0x860b},
+       {0x00e1, 0x860c},
+       {0x00fa, 0x860D},
+       {0x00f4, 0x860e},
+       {0x00e8, 0x860f},
        {0x0025, 0x8610},       /* A33 Coef. */
-       {0x00FC, 0x8611},       /* White balance offset: R */
+       {0x00fc, 0x8611},       /* White balance offset: R */
        {0x0001, 0x8612},       /* White balance offset: Gr */
-       {0x00FE, 0x8613},       /* White balance offset: B */
+       {0x00fe, 0x8613},       /* White balance offset: B */
        {0x0000, 0x8614},       /* White balance offset: Gb */
 
        {0x0064, 0x8651},       /* R gain for white balance (L) */
        {0x0040, 0x8652},       /* Gr gain for white balance (L) */
        {0x0066, 0x8653},       /* B gain for white balance (L) */
        {0x0040, 0x8654},       /* Gb gain for white balance (L) */
-       {0x0001, 0x863F},       /* Enable fixed gamma correction */
+       {0x0001, 0x863f},       /* Enable fixed gamma correction */
 
-       {0x00A1, 0x8656},       /* Size - Window1: 256x256, Window2: 128x128 */
+       {0x00a1, 0x8656},       /* Size - Window1: 256x256, Window2: 128x128 */
        /* UV division: UV no change, Enable New edge enhancement */
        {0x0018, 0x8657},       /* Edge gain high threshold */
        {0x0020, 0x8658},       /* Edge gain low threshold */
        {0x000A, 0x8659},       /* Edge bandwidth high threshold */
-       {0x0005, 0x865A},       /* Edge bandwidth low threshold */
+       {0x0005, 0x865a},       /* Edge bandwidth low threshold */
        {0x0064, 0x8607},       /* UV filter enable */
 
        {0x0016, 0x8660},
-       {0x0000, 0x86B0},       /* Bad pixels compensation address */
-       {0x00DC, 0x86B1},       /* X coord for bad pixels compensation (L) */
-       {0x0000, 0x86B2},
-       {0x0009, 0x86B3},       /* Y coord for bad pixels compensation (L) */
-       {0x0000, 0x86B4},
-
-       {0x0001, 0x86B0},
-       {0x00F5, 0x86B1},
-       {0x0000, 0x86B2},
-       {0x00C6, 0x86B3},
-       {0x0000, 0x86B4},
-
-       {0x0002, 0x86B0},
-       {0x001C, 0x86B1},
-       {0x0001, 0x86B2},
-       {0x00D7, 0x86B3},
-       {0x0000, 0x86B4},
-
-       {0x0003, 0x86B0},
-       {0x001C, 0x86B1},
-       {0x0001, 0x86B2},
-       {0x00D8, 0x86B3},
-       {0x0000, 0x86B4},
-
-       {0x0004, 0x86B0},
-       {0x001D, 0x86B1},
-       {0x0001, 0x86B2},
-       {0x00D8, 0x86B3},
-       {0x0000, 0x86B4},
-       {0x001E, 0x8660},
+       {0x0000, 0x86b0},       /* Bad pixels compensation address */
+       {0x00dc, 0x86b1},       /* X coord for bad pixels compensation (L) */
+       {0x0000, 0x86b2},
+       {0x0009, 0x86b3},       /* Y coord for bad pixels compensation (L) */
+       {0x0000, 0x86b4},
+
+       {0x0001, 0x86b0},
+       {0x00f5, 0x86b1},
+       {0x0000, 0x86b2},
+       {0x00c6, 0x86b3},
+       {0x0000, 0x86b4},
+
+       {0x0002, 0x86b0},
+       {0x001c, 0x86b1},
+       {0x0001, 0x86b2},
+       {0x00d7, 0x86b3},
+       {0x0000, 0x86b4},
+
+       {0x0003, 0x86b0},
+       {0x001c, 0x86b1},
+       {0x0001, 0x86b2},
+       {0x00d8, 0x86b3},
+       {0x0000, 0x86b4},
+
+       {0x0004, 0x86b0},
+       {0x001d, 0x86b1},
+       {0x0001, 0x86b2},
+       {0x00d8, 0x86b3},
+       {0x0000, 0x86b4},
+       {0x001e, 0x8660},
 
        /* READ { 0, 0x0000, 0x8608 } ->
                0000: 13  */
@@ -1449,7 +1447,7 @@ static int reg_read(struct gspca_dev *gspca_dev,
 }
 
 static int write_vector(struct gspca_dev *gspca_dev,
-                       const __u16 data[][3])
+                       const u16 data[][2])
 {
        struct usb_device *dev = gspca_dev->dev;
        int ret, i = 0;
@@ -1487,7 +1485,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1);
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 0x01;
        cam->cam_mode = sif_mode;
        cam->nmodes = ARRAY_SIZE(sif_mode);
 
@@ -1593,13 +1590,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
        reg_write(gspca_dev->dev, 0x8654, brightness);
 }
 
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->brightness = reg_read(gspca_dev, 0x8651);
-}
-
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1614,7 +1604,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getbrightness(gspca_dev);
        *val = sd->brightness;
        return 0;
 }
@@ -1666,8 +1655,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index 3c9288019e96faea92d22ab0b630404f6c5be0a0..c99c5e34e211d6ada81910d0d0b5bf981b11ac08 100644 (file)
@@ -141,38 +141,38 @@ static const struct v4l2_pix_format sif_072a_mode[] = {
 #define SPCA561_OFFSET_WIN1GBAVE 14
 #define SPCA561_OFFSET_FREQ 15
 #define SPCA561_OFFSET_VSYNC 16
-#define SPCA561_OFFSET_DATA 1
 #define SPCA561_INDEX_I2C_BASE 0x8800
 #define SPCA561_SNAPBIT 0x20
 #define SPCA561_SNAPCTRL 0x40
 
-static const __u16 rev72a_init_data1[][2] = {
+static const u16 rev72a_reset[][2] = {
        {0x0000, 0x8114},       /* Software GPIO output data */
        {0x0001, 0x8114},       /* Software GPIO output data */
        {0x0000, 0x8112},       /* Some kind of reset */
+       {}
+};
+static const __u16 rev72a_init_data1[][2] = {
        {0x0003, 0x8701},       /* PCLK clock delay adjustment */
        {0x0001, 0x8703},       /* HSYNC from cmos inverted */
        {0x0011, 0x8118},       /* Enable and conf sensor */
        {0x0001, 0x8118},       /* Conf sensor */
        {0x0092, 0x8804},       /* I know nothing about these */
        {0x0010, 0x8802},       /* 0x88xx registers, so I won't */
-       {0x000d, 0x8805},       /* sensor default setting */
        {}
 };
-static const __u16 rev72a_init_sensor1[][2] = {
-                               /* ms-win values */
-       {0x0001, 0x0018},       /* 0x01 <- 0x0d */
-       {0x0002, 0x0065},       /* 0x02 <- 0x18 */
-       {0x0004, 0x0121},       /* 0x04 <- 0x0165 */
-       {0x0005, 0x00aa},       /* 0x05 <- 0x21 */
-       {0x0007, 0x0004},       /* 0x07 <- 0xaa */
-       {0x0020, 0x1502},       /* 0x20 <- 0x1504 */
-       {0x0039, 0x0010},       /* 0x39 <- 0x02 */
-       {0x0035, 0x0049},       /* 0x35 <- 0x10 */
-       {0x0009, 0x100b},       /* 0x09 <- 0x1049 */
-       {0x0028, 0x000f},       /* 0x28 <- 0x0b */
-       {0x003b, 0x003c},       /* 0x3b <- 0x0f */
-       {0x003c, 0x0000},       /* 0x3c <- 0x00 */
+static const u16 rev72a_init_sensor1[][2] = {
+       {0x0001, 0x000d},
+       {0x0002, 0x0018},
+       {0x0004, 0x0165},
+       {0x0005, 0x0021},
+       {0x0007, 0x00aa},
+       {0x0020, 0x1504},
+       {0x0039, 0x0002},
+       {0x0035, 0x0010},
+       {0x0009, 0x1049},
+       {0x0028, 0x000b},
+       {0x003b, 0x000f},
+       {0x003c, 0x0000},
        {}
 };
 static const __u16 rev72a_init_data2[][2] = {
@@ -190,15 +190,10 @@ static const __u16 rev72a_init_data2[][2] = {
        {0x0002, 0x8201},       /* Output address for r/w serial EEPROM */
        {0x0008, 0x8200},       /* Clear valid bit for serial EEPROM */
        {0x0001, 0x8200},       /* OprMode to be executed by hardware */
-       {0x0007, 0x8201},       /* Output address for r/w serial EEPROM */
-       {0x0008, 0x8200},       /* Clear valid bit for serial EEPROM */
-       {0x0001, 0x8200},       /* OprMode to be executed by hardware */
-       {0x0010, 0x8660},       /* Compensation memory stuff */
-       {0x0018, 0x8660},       /* Compensation memory stuff */
-
-       {0x0004, 0x8611},       /* R offset for white balance */
-       {0x0004, 0x8612},       /* Gr offset for white balance */
-       {0x0007, 0x8613},       /* B offset for white balance */
+/* from ms-win */
+       {0x0000, 0x8611},       /* R offset for white balance */
+       {0x00fd, 0x8612},       /* Gr offset for white balance */
+       {0x0003, 0x8613},       /* B offset for white balance */
        {0x0000, 0x8614},       /* Gb offset for white balance */
 /* from ms-win */
        {0x0035, 0x8651},       /* R gain for white balance */
@@ -206,8 +201,8 @@ static const __u16 rev72a_init_data2[][2] = {
        {0x005f, 0x8653},       /* B gain for white balance */
        {0x0040, 0x8654},       /* Gb gain for white balance */
        {0x0002, 0x8502},       /* Maximum average bit rate stuff */
-
        {0x0011, 0x8802},
+
        {0x0087, 0x8700},       /* Set master clock (96Mhz????) */
        {0x0081, 0x8702},       /* Master clock output enable */
 
@@ -218,104 +213,15 @@ static const __u16 rev72a_init_data2[][2] = {
        {0x0003, 0x865c},       /* Vertical offset for valid lines */
        {}
 };
-static const __u16 rev72a_init_sensor2[][2] = {
-                               /* ms-win values */
-       {0x0003, 0x0121},       /* 0x03 <- 0x01 0x21 //289 */
-       {0x0004, 0x0165},       /* 0x04 <- 0x01 0x65 //357 */
-       {0x0005, 0x002f},       /* 0x05 <- 0x2f */
-       {0x0006, 0x0000},       /* 0x06 <- 0 */
-       {0x000a, 0x0002},       /* 0x0a <- 2 */
-       {0x0009, 0x1061},       /* 0x09 <- 0x1061 */
-       {0x0035, 0x0014},       /* 0x35 <- 0x14 */
-       {}
-};
-static const __u16 rev72a_init_data3[][2] = {
-       {0x0030, 0x8112},       /* ISO and drop packet enable */
-/*fixme: should stop here*/
-       {0x0000, 0x8112},       /* Some kind of reset ???? */
-       {0x0009, 0x8118},       /* Enable sensor and set standby */
-       {0x0000, 0x8114},       /* Software GPIO output data */
-       {0x0000, 0x8114},       /* Software GPIO output data */
-       {0x0001, 0x8114},       /* Software GPIO output data */
-       {0x0000, 0x8112},       /* Some kind of reset ??? */
-       {0x0003, 0x8701},
-       {0x0001, 0x8703},
-       {0x0011, 0x8118},
-       {0x0001, 0x8118},
-       /***************/
-       {0x0092, 0x8804},
-       {0x0010, 0x8802},
-       {0x000d, 0x8805},
-       {0x0001, 0x8801},
-       {0x0000, 0x8800},
-       {0x0018, 0x8805},
-       {0x0002, 0x8801},
-       {0x0000, 0x8800},
-       {0x0065, 0x8805},
-       {0x0004, 0x8801},
-       {0x0001, 0x8800},
-       {0x0021, 0x8805},
-       {0x0005, 0x8801},
-       {0x0000, 0x8800},
-       {0x00aa, 0x8805},
-       {0x0007, 0x8801},       /* mode 0xaa */
-       {0x0000, 0x8800},
-       {0x0004, 0x8805},
-       {0x0020, 0x8801},
-       {0x0015, 0x8800},       /* mode 0x0415 */
-       {0x0002, 0x8805},
-       {0x0039, 0x8801},
-       {0x0000, 0x8800},
-       {0x0010, 0x8805},
-       {0x0035, 0x8801},
-       {0x0000, 0x8800},
-       {0x0049, 0x8805},
-       {0x0009, 0x8801},
-       {0x0010, 0x8800},
-       {0x000b, 0x8805},
-       {0x0028, 0x8801},
-       {0x0000, 0x8800},
-       {0x000f, 0x8805},
-       {0x003b, 0x8801},
-       {0x0000, 0x8800},
-       {0x0000, 0x8805},
-       {0x003c, 0x8801},
-       {0x0000, 0x8800},
-       {0x0002, 0x8502},
-       {0x0039, 0x8801},
-       {0x0000, 0x8805},
-       {0x0000, 0x8800},
-
-       {0x0087, 0x8700},       /* overwrite by start */
-       {0x0081, 0x8702},
-       {0x0000, 0x8500},
-/*     {0x0010, 0x8500},  -- Previous line was this */
-       {0x0002, 0x865b},
-       {0x0003, 0x865c},
-       /***************/
-       {0x0003, 0x8801},       /* 0x121-> 289 */
-       {0x0021, 0x8805},
-       {0x0001, 0x8800},
-       {0x0004, 0x8801},       /* 0x165 -> 357 */
-       {0x0065, 0x8805},
-       {0x0001, 0x8800},
-       {0x0005, 0x8801},       /* 0x2f //blanking control colonne */
-       {0x002f, 0x8805},
-       {0x0000, 0x8800},
-       {0x0006, 0x8801},       /* 0x00 //blanking mode row */
-       {0x0000, 0x8805},
-       {0x0000, 0x8800},
-       {0x000a, 0x8801},       /* 0x01 //0x02 */
-       {0x0001, 0x8805},
-       {0x0000, 0x8800},
-       {0x0009, 0x8801},       /* 0x1061 - setexposure times && pixel clock
+static const u16 rev72a_init_sensor2[][2] = {
+       {0x0003, 0x0121},
+       {0x0004, 0x0165},
+       {0x0005, 0x002f},       /* blanking control column */
+       {0x0006, 0x0000},       /* blanking mode row*/
+       {0x000a, 0x0002},
+       {0x0009, 0x1061},       /* setexposure times && pixel clock
                                 * 0001 0 | 000 0110 0001 */
-       {0x0061, 0x8805},       /* 61 31 */
-       {0x0008, 0x8800},       /* 08 */
-       {0x0035, 0x8801},       /* 0x14 - set gain general */
-       {0x001f, 0x8805},       /* 0x14 */
-       {0x0000, 0x8800},
-       {0x000e, 0x8112},       /* white balance - was 30 */
+       {0x0035, 0x0014},
        {}
 };
 
@@ -460,6 +366,7 @@ static void i2c_write(struct gspca_dev *gspca_dev, __u16 value, __u16 reg)
                reg_r(gspca_dev, 0x8803, 1);
                if (!gspca_dev->usb_buf[0])
                        return;
+               msleep(10);
        } while (--retry);
 }
 
@@ -479,6 +386,7 @@ static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
                        reg_r(gspca_dev, 0x8805, 1);
                        return ((int) value << 8) | gspca_dev->usb_buf[0];
                }
+               msleep(10);
        } while (--retry);
        return -1;
 }
@@ -541,7 +449,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        }
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 0x01;
        gspca_dev->nbalt = 7 + 1;       /* choose alternate 7 first */
 
        sd->chip_revision = id->driver_info;
@@ -572,11 +479,13 @@ static int sd_init_12a(struct gspca_dev *gspca_dev)
 static int sd_init_72a(struct gspca_dev *gspca_dev)
 {
        PDEBUG(D_STREAM, "Chip revision: 072a");
+       write_vector(gspca_dev, rev72a_reset);
+       msleep(200);
        write_vector(gspca_dev, rev72a_init_data1);
        write_sensor_72a(gspca_dev, rev72a_init_sensor1);
        write_vector(gspca_dev, rev72a_init_data2);
        write_sensor_72a(gspca_dev, rev72a_init_sensor2);
-       write_vector(gspca_dev, rev72a_init_data3);
+       reg_w_val(gspca_dev->dev, 0x8112, 0x30);
        return 0;
 }
 
@@ -731,11 +640,18 @@ static int sd_start_72a(struct gspca_dev *gspca_dev)
        int Clck;
        int mode;
 
+       write_vector(gspca_dev, rev72a_reset);
+       msleep(200);
+       write_vector(gspca_dev, rev72a_init_data1);
+       write_sensor_72a(gspca_dev, rev72a_init_sensor1);
+
        mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
        switch (mode) {
        default:
-/*     case 0:
-       case 1: */
+       case 0:
+               Clck = 0x27;            /* ms-win 0x87 */
+               break;
+       case 1:
                Clck = 0x25;
                break;
        case 2:
@@ -745,13 +661,14 @@ static int sd_start_72a(struct gspca_dev *gspca_dev)
                Clck = 0x21;
                break;
        }
-       reg_w_val(dev, 0x8500, mode);   /* mode */
        reg_w_val(dev, 0x8700, Clck);   /* 0x27 clock */
-       reg_w_val(dev, 0x8112, 0x10 | 0x20);
+       reg_w_val(dev, 0x8702, 0x81);
+       reg_w_val(dev, 0x8500, mode);   /* mode */
+       write_sensor_72a(gspca_dev, rev72a_init_sensor2);
        setcontrast(gspca_dev);
 /*     setbrightness(gspca_dev);        * fixme: bad values */
-       setwhite(gspca_dev);
        setautogain(gspca_dev);
+       reg_w_val(dev, 0x8112, 0x10 | 0x20);
        return 0;
 }
 
@@ -867,12 +784,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       switch (data[0]) {                      /* sequence number */
+       len--;
+       switch (*data++) {                      /* sequence number */
        case 0:                                 /* start of frame */
                frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
                                        data, 0);
-               data += SPCA561_OFFSET_DATA;
-               len -= SPCA561_OFFSET_DATA;
                if (data[1] & 0x10) {
                        /* compressed bayer */
                        gspca_frame_add(gspca_dev, FIRST_PACKET,
@@ -893,8 +809,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        case 0xff:                      /* drop (empty mpackets) */
                return;
        }
-       data++;
-       len--;
        gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
@@ -1197,8 +1111,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/video/gspca/sq905.c
new file mode 100644 (file)
index 0000000..04e3ae5
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * SQ905 subdriver
+ *
+ * Copyright (C) 2008, 2009 Adam Baker and 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
+ */
+
+/*
+ * History and Acknowledgments
+ *
+ * The original Linux driver for SQ905 based cameras was written by
+ * Marcell Lengyel and furter developed by many other contributers
+ * and is available from http://sourceforge.net/projects/sqcam/
+ *
+ * This driver takes advantage of the reverse engineering work done for
+ * that driver and for libgphoto2 but shares no code with them.
+ *
+ * This driver has used as a base the finepix driver and other gspca
+ * based drivers and may still contain code fragments taken from those
+ * drivers.
+ */
+
+#define MODULE_NAME "sq905"
+
+#include <linux/workqueue.h>
+#include "gspca.h"
+
+MODULE_AUTHOR("Adam Baker <linux@baker-net.org.uk>, "
+               "Theodore Kilgore <kilgota@auburn.edu>");
+MODULE_DESCRIPTION("GSPCA/SQ905 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* Default timeouts, in ms */
+#define SQ905_CMD_TIMEOUT 500
+#define SQ905_DATA_TIMEOUT 1000
+
+/* Maximum transfer size to use. */
+#define SQ905_MAX_TRANSFER 0x8000
+#define FRAME_HEADER_LEN 64
+
+/* The known modes, or registers. These go in the "value" slot. */
+
+/* 00 is "none" obviously */
+
+#define SQ905_BULK_READ        0x03    /* precedes any bulk read */
+#define SQ905_COMMAND  0x06    /* precedes the command codes below */
+#define SQ905_PING     0x07    /* when reading an "idling" command */
+#define SQ905_READ_DONE 0xc0    /* ack bulk read completed */
+
+/* Any non-zero value in the bottom 2 bits of the 2nd byte of
+ * the ID appears to indicate the camera can do 640*480. If the
+ * LSB of that byte is set the image is just upside down, otherwise
+ * it is rotated 180 degrees. */
+#define SQ905_HIRES_MASK       0x00000300
+#define SQ905_ORIENTATION_MASK 0x00000100
+
+/* Some command codes. These go in the "index" slot. */
+
+#define SQ905_ID      0xf0     /* asks for model string */
+#define SQ905_CONFIG  0x20     /* gets photo alloc. table, not used here */
+#define SQ905_DATA    0x30     /* accesses photo data, not used here */
+#define SQ905_CLEAR   0xa0     /* clear everything */
+#define SQ905_CAPTURE_LOW  0x60        /* Starts capture at 160x120 */
+#define SQ905_CAPTURE_MED  0x61        /* Starts capture at 320x240 */
+#define SQ905_CAPTURE_HIGH 0x62        /* Starts capture at 640x480 (some cams only) */
+/* note that the capture command also controls the output dimensions */
+
+/* Structure to hold all of our device specific stuff */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       /*
+        * Driver stuff
+        */
+       struct work_struct work_struct;
+       struct workqueue_struct *work_thread;
+};
+
+static struct v4l2_pix_format sq905_mode[] = {
+       { 160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0},
+       { 320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0},
+       { 640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0}
+};
+
+/*
+ * Send a command to the camera.
+ */
+static int sq905_command(struct gspca_dev *gspca_dev, u16 index)
+{
+       int ret;
+
+       gspca_dev->usb_buf[0] = '\0';
+       ret = usb_control_msg(gspca_dev->dev,
+                             usb_sndctrlpipe(gspca_dev->dev, 0),
+                             USB_REQ_SYNCH_FRAME,                /* request */
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             SQ905_COMMAND, index, gspca_dev->usb_buf, 1,
+                             SQ905_CMD_TIMEOUT);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)",
+                       __func__, ret);
+               return ret;
+       }
+
+       ret = usb_control_msg(gspca_dev->dev,
+                             usb_sndctrlpipe(gspca_dev->dev, 0),
+                             USB_REQ_SYNCH_FRAME,                /* request */
+                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             SQ905_PING, 0, gspca_dev->usb_buf, 1,
+                             SQ905_CMD_TIMEOUT);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "%s: usb_control_msg failed 2 (%d)",
+                       __func__, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Acknowledge the end of a frame - see warning on sq905_command.
+ */
+static int sq905_ack_frame(struct gspca_dev *gspca_dev)
+{
+       int ret;
+
+       gspca_dev->usb_buf[0] = '\0';
+       ret = usb_control_msg(gspca_dev->dev,
+                             usb_sndctrlpipe(gspca_dev->dev, 0),
+                             USB_REQ_SYNCH_FRAME,                /* request */
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             SQ905_READ_DONE, 0, gspca_dev->usb_buf, 1,
+                             SQ905_CMD_TIMEOUT);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)", __func__, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ *  request and read a block of data - see warning on sq905_command.
+ */
+static int
+sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size)
+{
+       int ret;
+       int act_len;
+
+       gspca_dev->usb_buf[0] = '\0';
+       ret = usb_control_msg(gspca_dev->dev,
+                             usb_sndctrlpipe(gspca_dev->dev, 0),
+                             USB_REQ_SYNCH_FRAME,                /* request */
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             SQ905_BULK_READ, size, gspca_dev->usb_buf,
+                             1, SQ905_CMD_TIMEOUT);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)", __func__, ret);
+               return ret;
+       }
+       ret = usb_bulk_msg(gspca_dev->dev,
+                          usb_rcvbulkpipe(gspca_dev->dev, 0x81),
+                          data, size, &act_len, SQ905_DATA_TIMEOUT);
+
+       /* successful, it returns 0, otherwise  negative */
+       if (ret < 0 || act_len != size) {
+               PDEBUG(D_ERR, "bulk read fail (%d) len %d/%d",
+                       ret, act_len, size);
+               return -EIO;
+       }
+       return 0;
+}
+
+/* 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 we take the gspca
+ * usb_lock when performing USB operations. In practice the only thing we need
+ * to protect against is the usb_set_interface call that gspca makes during
+ * stream_off as the camera doesn't provide any controls that the user could try
+ * to change.
+ */
+static void sq905_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 bytes_left; /* bytes remaining in current frame. */
+       int data_len;   /* size to use for the next read. */
+       int header_read; /* true if we have already read the frame header. */
+       int discarding; /* true if we failed to get space for frame. */
+       int packet_type;
+       int frame_sz;
+       int ret;
+       u8 *data;
+       u8 *buffer;
+
+       buffer = kmalloc(SQ905_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
+       mutex_lock(&gspca_dev->usb_lock);
+       if (!buffer) {
+               PDEBUG(D_ERR, "Couldn't allocate USB buffer");
+               goto quit_stream;
+       }
+
+       frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage
+                       + FRAME_HEADER_LEN;
+
+       while (gspca_dev->present && gspca_dev->streaming) {
+               /* Need a short delay to ensure streaming flag was set by
+                * gspca and to make sure gspca can grab the mutex. */
+               mutex_unlock(&gspca_dev->usb_lock);
+               msleep(1);
+
+               /* request some data and then read it until we have
+                * a complete frame. */
+               bytes_left = frame_sz;
+               header_read = 0;
+               discarding = 0;
+
+               while (bytes_left > 0) {
+                       data_len = bytes_left > SQ905_MAX_TRANSFER ?
+                               SQ905_MAX_TRANSFER : bytes_left;
+                       mutex_lock(&gspca_dev->usb_lock);
+                       if (!gspca_dev->present)
+                               goto quit_stream;
+                       ret = sq905_read_data(gspca_dev, buffer, data_len);
+                       if (ret < 0)
+                               goto quit_stream;
+                       mutex_unlock(&gspca_dev->usb_lock);
+                       PDEBUG(D_STREAM,
+                               "Got %d bytes out of %d for frame",
+                               data_len, bytes_left);
+                       bytes_left -= data_len;
+                       data = buffer;
+                       if (!header_read) {
+                               packet_type = FIRST_PACKET;
+                               /* The first 64 bytes of each frame are
+                                * a header full of FF 00 bytes */
+                               data += FRAME_HEADER_LEN;
+                               data_len -= FRAME_HEADER_LEN;
+                               header_read = 1;
+                       } else if (bytes_left == 0) {
+                               packet_type = LAST_PACKET;
+                       } else {
+                               packet_type = INTER_PACKET;
+                       }
+                       frame = gspca_get_i_frame(gspca_dev);
+                       if (frame && !discarding) {
+                               frame = gspca_frame_add(gspca_dev, packet_type,
+                                               frame, data, data_len);
+                               /* If entire frame fits in one packet we still
+                                  need to add a LAST_PACKET */
+                               if (packet_type == FIRST_PACKET &&
+                                   bytes_left == 0)
+                                       frame = gspca_frame_add(gspca_dev,
+                                                       LAST_PACKET,
+                                                       frame, data, 0);
+                       } else {
+                               discarding = 1;
+                       }
+               }
+               /* acknowledge the frame */
+               mutex_lock(&gspca_dev->usb_lock);
+               if (!gspca_dev->present)
+                       goto quit_stream;
+               ret = sq905_ack_frame(gspca_dev);
+               if (ret < 0)
+                       goto quit_stream;
+       }
+quit_stream:
+       /* the usb_lock is already acquired */
+       if (gspca_dev->present)
+               sq905_command(gspca_dev, SQ905_CLEAR);
+       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;
+
+       /* We don't use the buffer gspca allocates so make it small. */
+       cam->bulk_size = 64;
+
+       INIT_WORK(&dev->work_struct, sq905_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 sq905_dostream to finish */
+       destroy_workqueue(dev->work_thread);
+       dev->work_thread = NULL;
+       mutex_lock(&gspca_dev->usb_lock);
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       u32 ident;
+       int ret;
+
+       /* connect to the camera and read
+        * the model ID and process that and put it away.
+        */
+       ret = sq905_command(gspca_dev, SQ905_CLEAR);
+       if (ret < 0)
+               return ret;
+       ret = sq905_command(gspca_dev, SQ905_ID);
+       if (ret < 0)
+               return ret;
+       ret = sq905_read_data(gspca_dev, gspca_dev->usb_buf, 4);
+       if (ret < 0)
+               return ret;
+       /* usb_buf is allocated with kmalloc so is aligned.
+        * Camera model number is the right way round if we assume this
+        * reverse engineered ID is supposed to be big endian. */
+       ident = be32_to_cpup((__be32 *)gspca_dev->usb_buf);
+       ret = sq905_command(gspca_dev, SQ905_CLEAR);
+       if (ret < 0)
+               return ret;
+       PDEBUG(D_CONF, "SQ905 camera ID %08x detected", ident);
+       gspca_dev->cam.cam_mode = sq905_mode;
+       gspca_dev->cam.nmodes = ARRAY_SIZE(sq905_mode);
+       if (!(ident & SQ905_HIRES_MASK))
+               gspca_dev->cam.nmodes--;
+       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;
+
+       /* "Open the shutter" and set size, to start capture */
+       switch (gspca_dev->curr_mode) {
+       default:
+/*     case 2: */
+               PDEBUG(D_STREAM, "Start streaming at high resolution");
+               ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_HIGH);
+               break;
+       case 1:
+               PDEBUG(D_STREAM, "Start streaming at medium resolution");
+               ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_MED);
+               break;
+       case 0:
+               PDEBUG(D_STREAM, "Start streaming at low resolution");
+               ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_LOW);
+       }
+
+       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(0x2770, 0x9120)},
+       {}
+};
+
+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);
diff --git a/drivers/media/video/gspca/sq905c.c b/drivers/media/video/gspca/sq905c.c
new file mode 100644 (file)
index 0000000..0bcb74a
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * SQ905C subdriver
+ *
+ * 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
+ */
+
+/*
+ *
+ * This driver uses work done in
+ * libgphoto2/camlibs/digigr8, Copyright (C) Theodore Kilgore.
+ *
+ * This driver has also used as a base the sq905c driver
+ * and may contain code fragments from it.
+ */
+
+#define MODULE_NAME "sq905c"
+
+#include <linux/workqueue.h>
+#include "gspca.h"
+
+MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>");
+MODULE_DESCRIPTION("GSPCA/SQ905C USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* Default timeouts, in ms */
+#define SQ905C_CMD_TIMEOUT 500
+#define SQ905C_DATA_TIMEOUT 1000
+
+/* Maximum transfer size to use. */
+#define SQ905C_MAX_TRANSFER 0x8000
+
+#define FRAME_HEADER_LEN 0x50
+
+/* Commands. These go in the "value" slot. */
+#define SQ905C_CLEAR   0xa0            /* clear everything */
+#define SQ905C_CAPTURE_LOW 0xa040      /* Starts capture at 160x120 */
+#define SQ905C_CAPTURE_MED 0x1440      /* Starts capture at 320x240 */
+#define SQ905C_CAPTURE_HI 0x2840       /* Starts capture at 320x240 */
+
+/* For capture, this must go in the "index" slot. */
+#define SQ905C_CAPTURE_INDEX 0x110f
+
+/* 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;
+};
+
+/*
+ * Most of these cameras will do 640x480 and 320x240. 160x120 works
+ * in theory but gives very poor output. Therefore, not supported.
+ * The 0x2770:0x9050 cameras have max resolution of 320x240.
+ */
+static struct v4l2_pix_format sq905c_mode[] = {
+       { 320, 240, V4L2_PIX_FMT_SQ905C, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0},
+       { 640, 480, V4L2_PIX_FMT_SQ905C, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0}
+};
+
+/* Send a command to the camera. */
+static int sq905c_command(struct gspca_dev *gspca_dev, u16 command, u16 index)
+{
+       int ret;
+
+       ret = usb_control_msg(gspca_dev->dev,
+                             usb_sndctrlpipe(gspca_dev->dev, 0),
+                             USB_REQ_SYNCH_FRAME,                /* request */
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             command, index, NULL, 0,
+                             SQ905C_CMD_TIMEOUT);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)",
+                       __func__, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+/* 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 sq905c_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 bytes_left; /* bytes remaining in current frame. */
+       int data_len;   /* size to use for the next read. */
+       int act_len;
+       int discarding = 0; /* true if we failed to get space for frame. */
+       int packet_type;
+       int ret;
+       u8 *buffer;
+
+       buffer = kmalloc(SQ905C_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;
+               /* Request the header, which tells the size to download */
+               ret = usb_bulk_msg(gspca_dev->dev,
+                               usb_rcvbulkpipe(gspca_dev->dev, 0x81),
+                               buffer, FRAME_HEADER_LEN, &act_len,
+                               SQ905C_DATA_TIMEOUT);
+               PDEBUG(D_STREAM,
+                       "Got %d bytes out of %d for header",
+                       act_len, FRAME_HEADER_LEN);
+               if (ret < 0 || act_len < FRAME_HEADER_LEN)
+                       goto quit_stream;
+               /* size is read from 4 bytes starting 0x40, little endian */
+               bytes_left = buffer[0x40]|(buffer[0x41]<<8)|(buffer[0x42]<<16)
+                                       |(buffer[0x43]<<24);
+               PDEBUG(D_STREAM, "bytes_left = 0x%x", bytes_left);
+               /* We keep the header. It has other information, too. */
+               packet_type = FIRST_PACKET;
+               frame = gspca_get_i_frame(gspca_dev);
+               if (frame && !discarding) {
+                       gspca_frame_add(gspca_dev, packet_type,
+                               frame, buffer, FRAME_HEADER_LEN);
+                       } else
+                               discarding = 1;
+               while (bytes_left > 0) {
+                       data_len = bytes_left > SQ905C_MAX_TRANSFER ?
+                               SQ905C_MAX_TRANSFER : bytes_left;
+                       if (!gspca_dev->present)
+                               goto quit_stream;
+                       ret = usb_bulk_msg(gspca_dev->dev,
+                               usb_rcvbulkpipe(gspca_dev->dev, 0x81),
+                               buffer, data_len, &act_len,
+                               SQ905C_DATA_TIMEOUT);
+                       if (ret < 0 || act_len < data_len)
+                               goto quit_stream;
+                       PDEBUG(D_STREAM,
+                               "Got %d bytes out of %d for frame",
+                               data_len, bytes_left);
+                       bytes_left -= data_len;
+                       if (bytes_left == 0)
+                               packet_type = LAST_PACKET;
+                       else
+                               packet_type = INTER_PACKET;
+                       frame = gspca_get_i_frame(gspca_dev);
+                       if (frame && !discarding)
+                               gspca_frame_add(gspca_dev, packet_type,
+                                               frame, buffer, data_len);
+                       else
+                               discarding = 1;
+               }
+       }
+quit_stream:
+       mutex_lock(&gspca_dev->usb_lock);
+       if (gspca_dev->present)
+               sq905c_command(gspca_dev, SQ905C_CLEAR, 0);
+       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;
+
+       PDEBUG(D_PROBE,
+               "SQ9050 camera detected"
+               " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+       cam->cam_mode = sq905c_mode;
+       cam->nmodes = 2;
+       if (id->idProduct == 0x9050)
+               cam->nmodes = 1;
+       /* We don't use the buffer gspca allocates so make it small. */
+       cam->bulk_size = 32;
+       INIT_WORK(&dev->work_struct, sq905c_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 sq905c_dostream to finish */
+       destroy_workqueue(dev->work_thread);
+       dev->work_thread = NULL;
+       mutex_lock(&gspca_dev->usb_lock);
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       int ret;
+
+       /* connect to the camera and reset it. */
+       ret = sq905c_command(gspca_dev, SQ905C_CLEAR, 0);
+       return ret;
+}
+
+/* Set up for getting frames. */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *dev = (struct sd *) gspca_dev;
+       int ret;
+
+       dev->cap_mode = gspca_dev->cam.cam_mode;
+       /* "Open the shutter" and set size, to start capture */
+       switch (gspca_dev->width) {
+       case 640:
+               PDEBUG(D_STREAM, "Start streaming at high resolution");
+               dev->cap_mode++;
+               ret = sq905c_command(gspca_dev, SQ905C_CAPTURE_HI,
+                                               SQ905C_CAPTURE_INDEX);
+               break;
+       default: /* 320 */
+       PDEBUG(D_STREAM, "Start streaming at medium resolution");
+               ret = sq905c_command(gspca_dev, SQ905C_CAPTURE_MED,
+                                               SQ905C_CAPTURE_INDEX);
+       }
+
+       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(0x2770, 0x905c)},
+       {USB_DEVICE(0x2770, 0x9050)},
+       {USB_DEVICE(0x2770, 0x913d)},
+       {}
+};
+
+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 60de9af87fbbe02504aec63ca6891881d7283f26..f25be20cf1a6f0865e6e8a1757076d2bc6ef4cf3 100644 (file)
@@ -35,10 +35,13 @@ struct sd {
        unsigned char contrast;
        unsigned char colors;
        unsigned char lightfreq;
-};
+       u8 quality;
+#define QUALITY_MIN 60
+#define QUALITY_MAX 95
+#define QUALITY_DEF 80
 
-/* global parameters */
-static int sd_quant = 7;               /* <= 4 KO - 7: good (enough!) */
+       u8 *jpeg_hdr;
+};
 
 /* V4L2 controls supported by the driver */
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
@@ -180,7 +183,7 @@ static int rcv_val(struct gspca_dev *gspca_dev,
        reg_w(gspca_dev, 0x63b, 0);
        reg_w(gspca_dev, 0x630, 5);
        ret = usb_bulk_msg(dev,
-                       usb_rcvbulkpipe(dev, 5),
+                       usb_rcvbulkpipe(dev, 0x05),
                        gspca_dev->usb_buf,
                        4,              /* length */
                        &alen,
@@ -294,15 +297,14 @@ 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 = &gspca_dev->cam;
 
-       cam->epaddr = 0x02;
        gspca_dev->cam.cam_mode = vga_mode;
        gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
        sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
        sd->colors = COLOR_DEF;
        sd->lightfreq = FREQ_DEF;
+       sd->quality = QUALITY_DEF;
        return 0;
 }
 
@@ -326,8 +328,15 @@ static int sd_init(struct gspca_dev *gspca_dev)
 /* -- start the camera -- */
 static int sd_start(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
        int ret, value;
 
+       /* create the JPEG header */
+       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+                       0x22);          /* JPEG 411 */
+       jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
        /* work on alternate 1 */
        usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
 
@@ -399,11 +408,19 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        PDEBUG(D_STREAM, "camera stopped");
 }
 
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       kfree(sd->jpeg_hdr);
+}
+
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
                        int len)                        /* iso packet length */
 {
+       struct sd *sd = (struct sd *) gspca_dev;
        static unsigned char ffd9[] = {0xff, 0xd9};
 
        /* a frame starts with:
@@ -420,7 +437,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                                        ffd9, 2);
 
                /* put the JPEG 411 header */
-               jpeg_put_header(gspca_dev, frame, sd_quant, 0x22);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                       sd->jpeg_hdr, JPEG_HDR_SZ);
 
                /* beginning of the frame */
 #define STKHDRSZ 12
@@ -520,6 +538,34 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
        return -EINVAL;
 }
 
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (jcomp->quality < QUALITY_MIN)
+               sd->quality = QUALITY_MIN;
+       else if (jcomp->quality > QUALITY_MAX)
+               sd->quality = QUALITY_MAX;
+       else
+               sd->quality = jcomp->quality;
+       if (gspca_dev->streaming)
+               jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+       return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       memset(jcomp, 0, sizeof *jcomp);
+       jcomp->quality = sd->quality;
+       jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+                       | V4L2_JPEG_MARKER_DQT;
+       return 0;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
@@ -529,8 +575,11 @@ static const struct sd_desc sd_desc = {
        .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
+       .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
        .querymenu = sd_querymenu,
+       .get_jcomp = sd_get_jcomp,
+       .set_jcomp = sd_set_jcomp,
 };
 
 /* -- module initialisation -- */
@@ -562,8 +611,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        info("registered");
        return 0;
 }
@@ -575,6 +626,3 @@ static void __exit sd_mod_exit(void)
 
 module_init(sd_mod_init);
 module_exit(sd_mod_exit);
-
-module_param_named(quant, sd_quant, int, 0644);
-MODULE_PARM_DESC(quant, "Quantization index (0..8)");
index 13a021e3cbb7b5d5f613688ca7880a8dac232bae..9dff2e65b116680b15b0d0e04383ce03918f9b12 100644 (file)
@@ -429,7 +429,6 @@ static int stv06xx_config(struct gspca_dev *gspca_dev,
        PDEBUG(D_PROBE, "Configuring camera");
 
        cam = &gspca_dev->cam;
-       cam->epaddr = STV_ISOC_ENDPOINT_ADDR;
        sd->desc = sd_desc;
        gspca_dev->sd_desc = &sd->desc;
 
@@ -501,8 +500,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index 14335a9e4bb575ecd805bfbe42aaefab256ef426..b1690381420300ddc93843eaeb064c02b0ebdb7f 100644 (file)
 
 #include "stv06xx_hdcs.h"
 
+static const struct ctrl hdcs1x00_ctrl[] = {
+       {
+               {
+                       .id             = V4L2_CID_EXPOSURE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "exposure",
+                       .minimum        = 0x00,
+                       .maximum        = 0xffff,
+                       .step           = 0x1,
+                       .default_value  = HDCS_DEFAULT_EXPOSURE,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = hdcs_set_exposure,
+               .get = hdcs_get_exposure
+       }, {
+               {
+                       .id             = V4L2_CID_GAIN,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "gain",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = HDCS_DEFAULT_GAIN,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = hdcs_set_gain,
+               .get = hdcs_get_gain
+       }
+};
+
+static struct v4l2_pix_format hdcs1x00_mode[] = {
+       {
+               HDCS_1X00_DEF_WIDTH,
+               HDCS_1X00_DEF_HEIGHT,
+               V4L2_PIX_FMT_SBGGR8,
+               V4L2_FIELD_NONE,
+               .sizeimage =
+                       HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT,
+               .bytesperline = HDCS_1X00_DEF_WIDTH,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1
+       }
+};
+
+static const struct ctrl hdcs1020_ctrl[] = {};
+
+static struct v4l2_pix_format hdcs1020_mode[] = {
+       {
+               HDCS_1020_DEF_WIDTH,
+               HDCS_1020_DEF_HEIGHT,
+               V4L2_PIX_FMT_SBGGR8,
+               V4L2_FIELD_NONE,
+               .sizeimage =
+                       HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT,
+               .bytesperline = HDCS_1020_DEF_WIDTH,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1
+       }
+};
+
 enum hdcs_power_state {
        HDCS_STATE_SLEEP,
        HDCS_STATE_IDLE,
@@ -353,10 +413,10 @@ static int hdcs_probe_1x00(struct sd *sd)
 
        info("HDCS-1000/1100 sensor detected");
 
-       sd->gspca_dev.cam.cam_mode = stv06xx_sensor_hdcs1x00.modes;
-       sd->gspca_dev.cam.nmodes = stv06xx_sensor_hdcs1x00.nmodes;
-       sd->desc.ctrls = stv06xx_sensor_hdcs1x00.ctrls;
-       sd->desc.nctrls = stv06xx_sensor_hdcs1x00.nctrls;
+       sd->gspca_dev.cam.cam_mode = hdcs1x00_mode;
+       sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1x00_mode);
+       sd->desc.ctrls = hdcs1x00_ctrl;
+       sd->desc.nctrls = ARRAY_SIZE(hdcs1x00_ctrl);
 
        hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
        if (!hdcs)
@@ -412,10 +472,10 @@ static int hdcs_probe_1020(struct sd *sd)
 
        info("HDCS-1020 sensor detected");
 
-       sd->gspca_dev.cam.cam_mode = stv06xx_sensor_hdcs1020.modes;
-       sd->gspca_dev.cam.nmodes = stv06xx_sensor_hdcs1020.nmodes;
-       sd->desc.ctrls = stv06xx_sensor_hdcs1020.ctrls;
-       sd->desc.nctrls = stv06xx_sensor_hdcs1020.nctrls;
+       sd->gspca_dev.cam.cam_mode = hdcs1020_mode;
+       sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1020_mode);
+       sd->desc.ctrls = hdcs1020_ctrl;
+       sd->desc.nctrls = ARRAY_SIZE(hdcs1020_ctrl);
 
        hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
        if (!hdcs)
index 9c7279a4cd88aab056cac6b0b8fd4ae29e71fae4..412f06cf3d5c4ef5506b97ba43227769d3dc67ee 100644 (file)
@@ -152,53 +152,6 @@ const struct stv06xx_sensor stv06xx_sensor_hdcs1x00 = {
        .stop = hdcs_stop,
        .disconnect = hdcs_disconnect,
        .dump = hdcs_dump,
-
-       .nctrls = 2,
-       .ctrls = {
-       {
-               {
-                       .id             = V4L2_CID_EXPOSURE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "exposure",
-                       .minimum        = 0x00,
-                       .maximum        = 0xffff,
-                       .step           = 0x1,
-                       .default_value  = HDCS_DEFAULT_EXPOSURE,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = hdcs_set_exposure,
-               .get = hdcs_get_exposure
-       },
-       {
-               {
-                       .id             = V4L2_CID_GAIN,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "gain",
-                       .minimum        = 0x00,
-                       .maximum        = 0xff,
-                       .step           = 0x1,
-                       .default_value  = HDCS_DEFAULT_GAIN,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = hdcs_set_gain,
-               .get = hdcs_get_gain
-       }
-       },
-
-       .nmodes = 1,
-       .modes = {
-       {
-               HDCS_1X00_DEF_WIDTH,
-               HDCS_1X00_DEF_HEIGHT,
-               V4L2_PIX_FMT_SBGGR8,
-               V4L2_FIELD_NONE,
-               .sizeimage =
-                       HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT,
-               .bytesperline = HDCS_1X00_DEF_WIDTH,
-               .colorspace = V4L2_COLORSPACE_SRGB,
-               .priv = 1
-       }
-       }
 };
 
 const struct stv06xx_sensor stv06xx_sensor_hdcs1020 = {
@@ -207,29 +160,11 @@ const struct stv06xx_sensor stv06xx_sensor_hdcs1020 = {
        .i2c_addr = (0x55 << 1),
        .i2c_len = 1,
 
-       .nctrls = 0,
-       .ctrls = {},
-
        .init = hdcs_init,
        .probe = hdcs_probe_1020,
        .start = hdcs_start,
        .stop = hdcs_stop,
        .dump = hdcs_dump,
-
-       .nmodes = 1,
-       .modes = {
-       {
-               HDCS_1020_DEF_WIDTH,
-               HDCS_1020_DEF_HEIGHT,
-               V4L2_PIX_FMT_SBGGR8,
-               V4L2_FIELD_NONE,
-               .sizeimage =
-                       HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT,
-               .bytesperline = HDCS_1020_DEF_WIDTH,
-               .colorspace = V4L2_COLORSPACE_SRGB,
-               .priv = 1
-       }
-       }
 };
 
 static const u16 stv_bridge_init[][2] = {
index d0a0f85964547d8e9c3a610e08a8d76daa322b29..285221e6b3908995e157fe3839b2d0f8f1621077 100644 (file)
 
 #include "stv06xx_pb0100.h"
 
+static const struct ctrl pb0100_ctrl[] = {
+#define GAIN_IDX 0
+       {
+               {
+                       .id             = V4L2_CID_GAIN,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Gain",
+                       .minimum        = 0,
+                       .maximum        = 255,
+                       .step           = 1,
+                       .default_value  = 128
+               },
+               .set = pb0100_set_gain,
+               .get = pb0100_get_gain
+       },
+#define RED_BALANCE_IDX 1
+       {
+               {
+                       .id             = V4L2_CID_RED_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Red Balance",
+                       .minimum        = -255,
+                       .maximum        = 255,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = pb0100_set_red_balance,
+               .get = pb0100_get_red_balance
+       },
+#define BLUE_BALANCE_IDX 2
+       {
+               {
+                       .id             = V4L2_CID_BLUE_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Blue Balance",
+                       .minimum        = -255,
+                       .maximum        = 255,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = pb0100_set_blue_balance,
+               .get = pb0100_get_blue_balance
+       },
+#define EXPOSURE_IDX 3
+       {
+               {
+                       .id             = V4L2_CID_EXPOSURE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Exposure",
+                       .minimum        = 0,
+                       .maximum        = 511,
+                       .step           = 1,
+                       .default_value  = 12
+               },
+               .set = pb0100_set_exposure,
+               .get = pb0100_get_exposure
+       },
+#define AUTOGAIN_IDX 4
+       {
+               {
+                       .id             = V4L2_CID_AUTOGAIN,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "Automatic Gain and Exposure",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 1
+               },
+               .set = pb0100_set_autogain,
+               .get = pb0100_get_autogain
+       },
+#define AUTOGAIN_TARGET_IDX 5
+       {
+               {
+                       .id             = V4L2_CTRL_CLASS_USER + 0x1000,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Automatic Gain Target",
+                       .minimum        = 0,
+                       .maximum        = 255,
+                       .step           = 1,
+                       .default_value  = 128
+               },
+               .set = pb0100_set_autogain_target,
+               .get = pb0100_get_autogain_target
+       },
+#define NATURAL_IDX 6
+       {
+               {
+                       .id             = V4L2_CTRL_CLASS_USER + 0x1001,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "Natural Light Source",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 1
+               },
+               .set = pb0100_set_natural,
+               .get = pb0100_get_natural
+       }
+};
+
+static struct v4l2_pix_format pb0100_mode[] = {
+/* low res / subsample modes disabled as they are only half res horizontal,
+   halving the vertical resolution does not seem to work */
+       {
+               320,
+               240,
+               V4L2_PIX_FMT_SGRBG8,
+               V4L2_FIELD_NONE,
+               .sizeimage = 320 * 240,
+               .bytesperline = 320,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = PB0100_CROP_TO_VGA
+       },
+       {
+               352,
+               288,
+               V4L2_PIX_FMT_SGRBG8,
+               V4L2_FIELD_NONE,
+               .sizeimage = 352 * 288,
+               .bytesperline = 352,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0
+       }
+};
+
 static int pb0100_probe(struct sd *sd)
 {
        u16 sensor;
@@ -59,20 +185,19 @@ static int pb0100_probe(struct sd *sd)
 
        if ((sensor >> 8) == 0x64) {
                sensor_settings = kmalloc(
-                               stv06xx_sensor_pb0100.nctrls * sizeof(s32),
+                               ARRAY_SIZE(pb0100_ctrl) * sizeof(s32),
                                GFP_KERNEL);
                if (!sensor_settings)
                        return -ENOMEM;
 
                info("Photobit pb0100 sensor detected");
 
-               sd->gspca_dev.cam.cam_mode = stv06xx_sensor_pb0100.modes;
-               sd->gspca_dev.cam.nmodes = stv06xx_sensor_pb0100.nmodes;
-               sd->desc.ctrls = stv06xx_sensor_pb0100.ctrls;
-               sd->desc.nctrls = stv06xx_sensor_pb0100.nctrls;
-               for (i = 0; i < stv06xx_sensor_pb0100.nctrls; i++)
-                       sensor_settings[i] = stv06xx_sensor_pb0100.
-                                            ctrls[i].qctrl.default_value;
+               sd->gspca_dev.cam.cam_mode = pb0100_mode;
+               sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode);
+               sd->desc.ctrls = pb0100_ctrl;
+               sd->desc.nctrls = ARRAY_SIZE(pb0100_ctrl);
+               for (i = 0; i < sd->desc.nctrls; i++)
+                       sensor_settings[i] = pb0100_ctrl[i].qctrl.default_value;
                sd->sensor_priv = sensor_settings;
 
                return 0;
@@ -143,6 +268,12 @@ out:
        return (err < 0) ? err : 0;
 }
 
+static void pb0100_disconnect(struct sd *sd)
+{
+       sd->sensor = NULL;
+       kfree(sd->sensor_priv);
+}
+
 /* FIXME: Sort the init commands out and put them into tables,
          this is only for getting the camera to work */
 /* FIXME: No error handling for now,
index 5ea21a1154c457079707ce369d8543e45e0dd8a9..4de4fa5ebc5766f46044a499b1b387c95941cffa 100644 (file)
@@ -114,6 +114,7 @@ static int pb0100_start(struct sd *sd);
 static int pb0100_init(struct sd *sd);
 static int pb0100_stop(struct sd *sd);
 static int pb0100_dump(struct sd *sd);
+static void pb0100_disconnect(struct sd *sd);
 
 /* V4L2 controls supported by the driver */
 static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
@@ -137,139 +138,12 @@ const struct stv06xx_sensor stv06xx_sensor_pb0100 = {
        .i2c_addr = 0xba,
        .i2c_len = 2,
 
-       .nctrls = 7,
-       .ctrls = {
-#define GAIN_IDX 0
-       {
-               {
-                       .id             = V4L2_CID_GAIN,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "Gain",
-                       .minimum        = 0,
-                       .maximum        = 255,
-                       .step           = 1,
-                       .default_value  = 128
-               },
-               .set = pb0100_set_gain,
-               .get = pb0100_get_gain
-       },
-#define RED_BALANCE_IDX 1
-       {
-               {
-                       .id             = V4L2_CID_RED_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "Red Balance",
-                       .minimum        = -255,
-                       .maximum        = 255,
-                       .step           = 1,
-                       .default_value  = 0
-               },
-               .set = pb0100_set_red_balance,
-               .get = pb0100_get_red_balance
-       },
-#define BLUE_BALANCE_IDX 2
-       {
-               {
-                       .id             = V4L2_CID_BLUE_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "Blue Balance",
-                       .minimum        = -255,
-                       .maximum        = 255,
-                       .step           = 1,
-                       .default_value  = 0
-               },
-               .set = pb0100_set_blue_balance,
-               .get = pb0100_get_blue_balance
-       },
-#define EXPOSURE_IDX 3
-       {
-               {
-                       .id             = V4L2_CID_EXPOSURE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "Exposure",
-                       .minimum        = 0,
-                       .maximum        = 511,
-                       .step           = 1,
-                       .default_value  = 12
-               },
-               .set = pb0100_set_exposure,
-               .get = pb0100_get_exposure
-       },
-#define AUTOGAIN_IDX 4
-       {
-               {
-                       .id             = V4L2_CID_AUTOGAIN,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "Automatic Gain and Exposure",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 1
-               },
-               .set = pb0100_set_autogain,
-               .get = pb0100_get_autogain
-       },
-#define AUTOGAIN_TARGET_IDX 5
-       {
-               {
-                       .id             = V4L2_CTRL_CLASS_USER + 0x1000,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "Automatic Gain Target",
-                       .minimum        = 0,
-                       .maximum        = 255,
-                       .step           = 1,
-                       .default_value  = 128
-               },
-               .set = pb0100_set_autogain_target,
-               .get = pb0100_get_autogain_target
-       },
-#define NATURAL_IDX 6
-       {
-               {
-                       .id             = V4L2_CTRL_CLASS_USER + 0x1001,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "Natural Light Source",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 1
-               },
-               .set = pb0100_set_natural,
-               .get = pb0100_get_natural
-       },
-       },
-
        .init = pb0100_init,
        .probe = pb0100_probe,
        .start = pb0100_start,
        .stop = pb0100_stop,
        .dump = pb0100_dump,
-
-       .nmodes = 2,
-       .modes = {
-/* low res / subsample modes disabled as they are only half res horizontal,
-   halving the vertical resolution does not seem to work */
-       {
-               320,
-               240,
-               V4L2_PIX_FMT_SGRBG8,
-               V4L2_FIELD_NONE,
-               .sizeimage = 320 * 240,
-               .bytesperline = 320,
-               .colorspace = V4L2_COLORSPACE_SRGB,
-               .priv = PB0100_CROP_TO_VGA
-       },
-       {
-               352,
-               288,
-               V4L2_PIX_FMT_SGRBG8,
-               V4L2_FIELD_NONE,
-               .sizeimage = 352 * 288,
-               .bytesperline = 352,
-               .colorspace = V4L2_COLORSPACE_SRGB,
-               .priv = 0
-       },
-       }
+       .disconnect = pb0100_disconnect,
 };
 
 #endif
index c726dacefa1fff8d8af18b7e6cc3a33970231111..e88c42f7d2f8eda0b2b84c9b11ad330f0ef2e4f7 100644 (file)
@@ -41,8 +41,6 @@ extern const struct stv06xx_sensor stv06xx_sensor_hdcs1x00;
 extern const struct stv06xx_sensor stv06xx_sensor_hdcs1020;
 extern const struct stv06xx_sensor stv06xx_sensor_pb0100;
 
-#define STV06XX_MAX_CTRLS              (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10)
-
 struct stv06xx_sensor {
        /* Defines the name of a sensor */
        char name[32];
@@ -81,12 +79,6 @@ struct stv06xx_sensor {
 
        /* Instructs the sensor to dump all its contents */
        int (*dump)(struct sd *sd);
-
-       int nctrls;
-       struct ctrl ctrls[STV06XX_MAX_CTRLS];
-
-       char nmodes;
-       struct v4l2_pix_format modes[];
 };
 
 #endif
index 1ca91f2a6deeb5337947527500b8097ed6c6dad6..69c77c932fc027b16e2d1d0d0d61962233f44b9c 100644 (file)
 
 #include "stv06xx_vv6410.h"
 
+static struct v4l2_pix_format vv6410_mode[] = {
+       {
+               356,
+               292,
+               V4L2_PIX_FMT_SGRBG8,
+               V4L2_FIELD_NONE,
+               .sizeimage = 356 * 292,
+               .bytesperline = 356,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0
+       }
+};
+
+static const struct ctrl vv6410_ctrl[] = {
+#define HFLIP_IDX 0
+       {
+               {
+                       .id             = V4L2_CID_HFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "horizontal flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = vv6410_set_hflip,
+               .get = vv6410_get_hflip
+       },
+#define VFLIP_IDX 1
+       {
+               {
+                       .id             = V4L2_CID_VFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "vertical flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = vv6410_set_vflip,
+               .get = vv6410_get_vflip
+       },
+#define GAIN_IDX 2
+       {
+               {
+                       .id             = V4L2_CID_GAIN,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "analog gain",
+                       .minimum        = 0,
+                       .maximum        = 15,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = vv6410_set_analog_gain,
+               .get = vv6410_get_analog_gain
+       }
+};
+
 static int vv6410_probe(struct sd *sd)
 {
        u16 data;
-       int err;
+       int err, i;
+       s32 *sensor_settings;
 
        err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data);
-
        if (err < 0)
                return -ENODEV;
 
        if (data == 0x19) {
                info("vv6410 sensor detected");
 
-               sd->gspca_dev.cam.cam_mode = stv06xx_sensor_vv6410.modes;
-               sd->gspca_dev.cam.nmodes = stv06xx_sensor_vv6410.nmodes;
-               sd->desc.ctrls = stv06xx_sensor_vv6410.ctrls;
-               sd->desc.nctrls = stv06xx_sensor_vv6410.nctrls;
+               sensor_settings = kmalloc(ARRAY_SIZE(vv6410_ctrl) * sizeof(s32),
+                                         GFP_KERNEL);
+               if (!sensor_settings)
+                       return -ENOMEM;
+
+               sd->gspca_dev.cam.cam_mode = vv6410_mode;
+               sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode);
+               sd->desc.ctrls = vv6410_ctrl;
+               sd->desc.nctrls = ARRAY_SIZE(vv6410_ctrl);
+
+               for (i = 0; i < sd->desc.nctrls; i++)
+                       sensor_settings[i] = vv6410_ctrl[i].qctrl.default_value;
+               sd->sensor_priv = sensor_settings;
                return 0;
        }
-
        return -ENODEV;
 }
 
@@ -80,6 +146,12 @@ static int vv6410_init(struct sd *sd)
        return (err < 0) ? err : 0;
 }
 
+static void vv6410_disconnect(struct sd *sd)
+{
+       sd->sensor = NULL;
+       kfree(sd->sensor_priv);
+}
+
 static int vv6410_start(struct sd *sd)
 {
        int err;
@@ -156,17 +228,13 @@ static int vv6410_dump(struct sd *sd)
 
 static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
-       int err;
-       u16 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
-
-       *val = (i2c_data & VV6410_HFLIP) ? 1 : 0;
-
+       *val = sensor_settings[HFLIP_IDX];
        PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
 
-       return (err < 0) ? err : 0;
+       return 0;
 }
 
 static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -174,6 +242,9 @@ static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
        int err;
        u16 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[HFLIP_IDX] = val;
        err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
        if (err < 0)
                return err;
@@ -191,17 +262,13 @@ static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
 
 static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
-       int err;
-       u16 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
-
-       *val = (i2c_data & VV6410_VFLIP) ? 1 : 0;
-
+       *val = sensor_settings[VFLIP_IDX];
        PDEBUG(D_V4L2, "Read vertical flip %d", *val);
 
-       return (err < 0) ? err : 0;
+       return 0;
 }
 
 static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -209,6 +276,9 @@ static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        int err;
        u16 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[VFLIP_IDX] = val;
        err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
        if (err < 0)
                return err;
@@ -226,24 +296,23 @@ static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
 
 static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val)
 {
-       int err;
-       u16 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = stv06xx_read_sensor(sd, VV6410_ANALOGGAIN, &i2c_data);
-
-       *val = i2c_data & 0xf;
+       *val = sensor_settings[GAIN_IDX];
 
        PDEBUG(D_V4L2, "Read analog gain %d", *val);
 
-       return (err < 0) ? err : 0;
+       return 0;
 }
 
 static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
 
+       sensor_settings[GAIN_IDX] = val;
        PDEBUG(D_V4L2, "Set analog gain to %d", val);
        err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf));
 
index 3ff8c4ea3362d03eacefe9dff8b3b632c2fafd14..95ac55891bd427c9a02b9252f07b5c906359dca6 100644 (file)
@@ -178,6 +178,7 @@ static int vv6410_start(struct sd *sd);
 static int vv6410_init(struct sd *sd);
 static int vv6410_stop(struct sd *sd);
 static int vv6410_dump(struct sd *sd);
+static void vv6410_disconnect(struct sd *sd);
 
 /* V4L2 controls supported by the driver */
 static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
@@ -197,62 +198,7 @@ const struct stv06xx_sensor stv06xx_sensor_vv6410 = {
        .start = vv6410_start,
        .stop = vv6410_stop,
        .dump = vv6410_dump,
-
-       .nctrls = 3,
-       .ctrls = {
-       {
-               {
-                       .id             = V4L2_CID_HFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "horizontal flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0
-               },
-               .set = vv6410_set_hflip,
-               .get = vv6410_get_hflip
-       }, {
-               {
-                       .id             = V4L2_CID_VFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "vertical flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0
-               },
-               .set = vv6410_set_vflip,
-               .get = vv6410_get_vflip
-       }, {
-               {
-                       .id             = V4L2_CID_GAIN,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "analog gain",
-                       .minimum        = 0,
-                       .maximum        = 15,
-                       .step           = 1,
-                       .default_value  = 0
-               },
-               .set = vv6410_set_analog_gain,
-               .get = vv6410_get_analog_gain
-       }
-       },
-
-       .nmodes = 1,
-       .modes = {
-       {
-               356,
-               292,
-               V4L2_PIX_FMT_SGRBG8,
-               V4L2_FIELD_NONE,
-               .sizeimage =
-                       356 * 292,
-               .bytesperline = 356,
-               .colorspace = V4L2_COLORSPACE_SRGB,
-               .priv = 0
-       }
-       }
+       .disconnect = vv6410_disconnect,
 };
 
 /* If NULL, only single value to write, stored in len */
index 6d904d5e4c74ef9cd02204e4eabd312652213396..c2b8c10c075add3bc79f5e83c4a36b2fd8cd5125 100644 (file)
@@ -39,8 +39,11 @@ struct sd {
        unsigned char contrast;
        unsigned char colors;
        unsigned char autogain;
+       u8 quality;
+#define QUALITY_MIN 70
+#define QUALITY_MAX 95
+#define QUALITY_DEF 85
 
-       char qindex;
        char bridge;
 #define BRIDGE_SPCA504 0
 #define BRIDGE_SPCA504B 1
@@ -52,6 +55,8 @@ struct sd {
 #define LogitechClickSmart420 2
 #define LogitechClickSmart820 3
 #define MegapixV4 4
+
+       u8 *jpeg_hdr;
 };
 
 /* V4L2 controls supported by the driver */
@@ -812,7 +817,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct cam *cam;
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 0x01;
 
        sd->bridge = id->driver_info >> 8;
        sd->subtype = id->driver_info;
@@ -850,10 +854,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
                cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0];
                break;
        }
-       sd->qindex = 5;                 /* set the quantization table */
        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->quality = QUALITY_DEF;
        return 0;
 }
 
@@ -970,6 +974,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
        __u8 i;
        __u8 info[6];
 
+       /* create the JPEG header */
+       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+                       0x22);          /* JPEG 411 */
+       jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
        if (sd->bridge == BRIDGE_SPCA504B)
                spca504B_setQtable(gspca_dev);
        spca504B_SetSizeType(gspca_dev);
@@ -1079,6 +1089,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        }
 }
 
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       kfree(sd->jpeg_hdr);
+}
+
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
@@ -1155,9 +1172,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                                        ffd9, 2);
 
                /* put the JPEG header in the new frame */
-               jpeg_put_header(gspca_dev, frame,
-                               ((struct sd *) gspca_dev)->qindex,
-                               0x22);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                       sd->jpeg_hdr, JPEG_HDR_SZ);
        }
 
        /* add 0x00 after 0xff */
@@ -1198,26 +1214,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
        }
 }
 
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       __u16 brightness = 0;
-
-       switch (sd->bridge) {
-       default:
-/*     case BRIDGE_SPCA533: */
-/*     case BRIDGE_SPCA504B: */
-/*     case BRIDGE_SPCA504: */
-/*     case BRIDGE_SPCA504C: */
-               brightness = reg_r_12(gspca_dev, 0x00, 0x21a7, 2);
-               break;
-       case BRIDGE_SPCA536:
-               brightness = reg_r_12(gspca_dev, 0x00, 0x20f0, 2);
-               break;
-       }
-       sd->brightness = ((brightness & 0xff) - 128) % 255;
-}
-
 static void setcontrast(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1237,24 +1233,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
        }
 }
 
-static void getcontrast(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       switch (sd->bridge) {
-       default:
-/*     case BRIDGE_SPCA533: */
-/*     case BRIDGE_SPCA504B: */
-/*     case BRIDGE_SPCA504: */
-/*     case BRIDGE_SPCA504C: */
-               sd->contrast = reg_r_12(gspca_dev, 0x00, 0x21a8, 2);
-               break;
-       case BRIDGE_SPCA536:
-               sd->contrast = reg_r_12(gspca_dev, 0x00, 0x20f1, 2);
-               break;
-       }
-}
-
 static void setcolors(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1274,24 +1252,6 @@ static void setcolors(struct gspca_dev *gspca_dev)
        }
 }
 
-static void getcolors(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       switch (sd->bridge) {
-       default:
-/*     case BRIDGE_SPCA533: */
-/*     case BRIDGE_SPCA504B: */
-/*     case BRIDGE_SPCA504: */
-/*     case BRIDGE_SPCA504C: */
-               sd->colors = reg_r_12(gspca_dev, 0x00, 0x21ae, 2) >> 1;
-               break;
-       case BRIDGE_SPCA536:
-               sd->colors = reg_r_12(gspca_dev, 0x00, 0x20f6, 2) >> 1;
-               break;
-       }
-}
-
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1306,7 +1266,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getbrightness(gspca_dev);
        *val = sd->brightness;
        return 0;
 }
@@ -1325,7 +1284,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getcontrast(gspca_dev);
        *val = sd->contrast;
        return 0;
 }
@@ -1344,7 +1302,6 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getcolors(gspca_dev);
        *val = sd->colors;
        return 0;
 }
@@ -1365,6 +1322,34 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (jcomp->quality < QUALITY_MIN)
+               sd->quality = QUALITY_MIN;
+       else if (jcomp->quality > QUALITY_MAX)
+               sd->quality = QUALITY_MAX;
+       else
+               sd->quality = jcomp->quality;
+       if (gspca_dev->streaming)
+               jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+       return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       memset(jcomp, 0, sizeof *jcomp);
+       jcomp->quality = sd->quality;
+       jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+                       | V4L2_JPEG_MARKER_DQT;
+       return 0;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
@@ -1374,7 +1359,10 @@ static const struct sd_desc sd_desc = {
        .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
+       .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
+       .get_jcomp = sd_get_jcomp,
+       .set_jcomp = sd_set_jcomp,
 };
 
 /* -- module initialisation -- */
@@ -1465,8 +1453,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index 6ee111a3cbd1e5889a3e7c44c6bdcd847be24b1b..f63e37e2e4fdd3c4031b69fd12c7bcd849b16978 100644 (file)
@@ -37,20 +37,21 @@ 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;
-       unsigned char gamma;
-       unsigned char sharpness;
-       unsigned char freq;
-       unsigned char whitebalance;
-       unsigned char mirror;
-       unsigned char effect;
-
-       __u8 sensor;
-#define SENSOR_TAS5130A 0
-#define SENSOR_OM6802 1
+       u8 brightness;
+       u8 contrast;
+       u8 colors;
+       u8 autogain;
+       u8 gamma;
+       u8 sharpness;
+       u8 freq;
+       u8 whitebalance;
+       u8 mirror;
+       u8 effect;
+
+       u8 sensor;
+#define SENSOR_OM6802 0
+#define SENSOR_OTHER 1
+#define SENSOR_TAS5130A 2
 };
 
 /* V4L2 controls supported by the driver */
@@ -78,7 +79,6 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
                        struct v4l2_querymenu *menu);
 
 static struct ctrl sd_ctrls[] = {
-#define SD_BRIGHTNESS 0
        {
         {
          .id = V4L2_CID_BRIGHTNESS,
@@ -87,12 +87,12 @@ static struct ctrl sd_ctrls[] = {
          .minimum = 0,
          .maximum = 14,
          .step = 1,
-         .default_value = 8,
+#define BRIGHTNESS_DEF 8
+         .default_value = BRIGHTNESS_DEF,
          },
         .set = sd_setbrightness,
         .get = sd_getbrightness,
         },
-#define SD_CONTRAST 1
        {
         {
          .id = V4L2_CID_CONTRAST,
@@ -101,12 +101,12 @@ static struct ctrl sd_ctrls[] = {
          .minimum = 0,
          .maximum = 0x0d,
          .step = 1,
-         .default_value = 0x07,
+#define CONTRAST_DEF 0x07
+         .default_value = CONTRAST_DEF,
          },
         .set = sd_setcontrast,
         .get = sd_getcontrast,
         },
-#define SD_COLOR 2
        {
         {
          .id = V4L2_CID_SATURATION,
@@ -115,7 +115,8 @@ static struct ctrl sd_ctrls[] = {
          .minimum = 0,
          .maximum = 0x0f,
          .step = 1,
-         .default_value = 0x05,
+#define COLORS_DEF 0x05
+         .default_value = COLORS_DEF,
          },
         .set = sd_setcolors,
         .get = sd_getcolors,
@@ -135,7 +136,6 @@ static struct ctrl sd_ctrls[] = {
         .set = sd_setgamma,
         .get = sd_getgamma,
         },
-#define SD_AUTOGAIN 4
        {
         {
          .id = V4L2_CID_GAIN,  /* here, i activate only the lowlight,
@@ -146,12 +146,12 @@ static struct ctrl sd_ctrls[] = {
          .minimum = 0,
          .maximum = 1,
          .step = 1,
-         .default_value = 0x01,
+#define AUTOGAIN_DEF 0x01
+         .default_value = AUTOGAIN_DEF,
          },
         .set = sd_setlowlight,
         .get = sd_getlowlight,
         },
-#define SD_MIRROR 5
        {
         {
          .id = V4L2_CID_HFLIP,
@@ -160,12 +160,12 @@ static struct ctrl sd_ctrls[] = {
          .minimum = 0,
          .maximum = 1,
          .step = 1,
-         .default_value = 0,
+#define MIRROR_DEF 0
+         .default_value = MIRROR_DEF,
          },
         .set = sd_setflip,
         .get = sd_getflip
        },
-#define SD_LIGHTFREQ 6
        {
         {
          .id = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -174,12 +174,12 @@ static struct ctrl sd_ctrls[] = {
          .minimum = 1,         /* 1 -> 0x50, 2->0x60 */
          .maximum = 2,
          .step = 1,
-         .default_value = 1,
+#define FREQ_DEF 1
+         .default_value = FREQ_DEF,
          },
         .set = sd_setfreq,
         .get = sd_getfreq},
 
-#define SD_WHITE_BALANCE 7
        {
         {
          .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
@@ -188,12 +188,12 @@ static struct ctrl sd_ctrls[] = {
          .minimum = 0,
          .maximum = 1,
          .step = 1,
-         .default_value = 0,
+#define WHITE_BALANCE_DEF 0
+         .default_value = WHITE_BALANCE_DEF,
          },
         .set = sd_setwhitebalance,
         .get = sd_getwhitebalance
        },
-#define SD_SHARPNESS 8         /* (aka definition on win) */
        {
         {
          .id = V4L2_CID_SHARPNESS,
@@ -202,12 +202,12 @@ static struct ctrl sd_ctrls[] = {
          .minimum = 0,
          .maximum = 15,
          .step = 1,
-         .default_value = 0x06,
+#define SHARPNESS_DEF 0x06
+         .default_value = SHARPNESS_DEF,
          },
         .set = sd_setsharpness,
         .get = sd_getsharpness,
         },
-#define SD_EFFECTS 9
        {
         {
          .id = V4L2_CID_EFFECTS,
@@ -216,7 +216,8 @@ static struct ctrl sd_ctrls[] = {
          .minimum = 0,
          .maximum = 4,
          .step = 1,
-         .default_value = 0,
+#define EFFECTS_DEF 0
+         .default_value = EFFECTS_DEF,
          },
         .set = sd_seteffect,
         .get = sd_geteffect
@@ -263,28 +264,50 @@ static const struct v4l2_pix_format vga_mode_t16[] = {
 
 /* sensor specific data */
 struct additional_sensor_data {
-       const __u8 data1[20];
-       const __u8 data2[18];
-       const __u8 data3[18];
-       const __u8 data4[4];
-       const __u8 data5[6];
-       const __u8 stream[4];
+       const u8 data1[10];
+       const u8 data2[9];
+       const u8 data3[9];
+       const u8 data4[4];
+       const u8 data5[6];
+       const u8 stream[4];
 };
 
-const static struct additional_sensor_data sensor_data[] = {
+static const struct additional_sensor_data sensor_data[] = {
+    {                          /* OM6802 */
+       .data1 =
+               {0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
+                0xb3, 0xfc},
+       .data2 =
+               {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 */
+               {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
+       .stream =
+               {0x0b, 0x04, 0x0a, 0x78},
+    },
+    {                          /* OTHER */
+       .data1 =
+               {0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
+                0xe8, 0xfc},
+       .data2 =
+               {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
+                0xd9},
+       .data4 =
+               {0x66, 0x00, 0xa8, 0xa8},
+       .data5 =
+               {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
+       .stream =
+               {0x0b, 0x04, 0x0a, 0x00},
+    },
     {                          /* TAS5130A */
        .data1 =
-               {0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10,
-                0xd4, 0xbb, 0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
-                0xd8, 0xc8, 0xd9, 0xfc},
+               {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
+                0xc8, 0xfc},
        .data2 =
-               {0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60,
-                0xe4, 0xa8, 0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
-                0xe8, 0xe0},
-       .data3 =
-               {0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60,
-                0xcb, 0xa8, 0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
-                0xcf, 0xe0},
+               {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
+                0xe0},
        .data4 =        /* Freq (50/60Hz). Splitted for test purpose */
                {0x66, 0x00, 0xa8, 0xe8},
        .data5 =
@@ -292,32 +315,12 @@ const static struct additional_sensor_data sensor_data[] = {
        .stream =
                {0x0b, 0x04, 0x0a, 0x40},
     },
-    {                          /* OM6802 */
-       .data1 =
-               {0xd0, 0xc2, 0xd1, 0x28, 0xd2, 0x0f, 0xd3, 0x22,
-                0xd4, 0xcd, 0xd5, 0x27, 0xd6, 0x2c, 0xd7, 0x06,
-                0xd8, 0xb3, 0xd9, 0xfc},
-       .data2 =
-               {0xe0, 0x80, 0xe1, 0xff, 0xe2, 0xff, 0xe3, 0x80,
-                0xe4, 0xff, 0xe5, 0xff, 0xe6, 0x80, 0xe7, 0xff,
-                0xe8, 0xff},
-       .data3 =
-               {0xc7, 0x80, 0xc8, 0xff, 0xc9, 0xff, 0xca, 0x80,
-                0xcb, 0xff, 0xcc, 0xff, 0xcd, 0x80, 0xce, 0xff,
-                0xcf, 0xff},
-       .data4 =        /*Freq (50/60Hz). Splitted for test purpose */
-               {0x66, 0xca, 0xa8, 0xf0 },
-       .data5 =        /* this could be removed later */
-               {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
-       .stream =
-               {0x0b, 0x04, 0x0a, 0x78},
-    }
 };
 
 #define MAX_EFFECTS 7
 /* easily done by soft, this table could be removed,
  * i keep it here just in case */
-static const __u8 effects_table[MAX_EFFECTS][6] = {
+static const u8 effects_table[MAX_EFFECTS][6] = {
        {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00},   /* Normal */
        {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04},   /* Repujar */
        {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20},   /* Monochrome */
@@ -327,90 +330,58 @@ static const __u8 effects_table[MAX_EFFECTS][6] = {
        {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40},   /* Negative */
 };
 
-static const __u8 gamma_table[GAMMA_MAX][34] = {
-       {0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85,        /* 0 */
-        0x94, 0x95, 0x95, 0xa1, 0x96, 0xae, 0x97, 0xb9,
-        0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdb,
-        0x9c, 0xe3, 0x9d, 0xea, 0x9e, 0xf1, 0x9f, 0xf8,
-        0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x33, 0x92, 0x5a, 0x93, 0x75,        /* 1 */
-        0x94, 0x85, 0x95, 0x93, 0x96, 0xa1, 0x97, 0xad,
-        0x98, 0xb7, 0x99, 0xc2, 0x9a, 0xcb, 0x9b, 0xd4,
-        0x9c, 0xde, 0x9D, 0xe7, 0x9e, 0xf0, 0x9f, 0xf7,
-        0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x2f, 0x92, 0x51, 0x93, 0x6b,        /* 2 */
-        0x94, 0x7c, 0x95, 0x8a, 0x96, 0x99, 0x97, 0xa6,
-        0x98, 0xb1, 0x99, 0xbc, 0x9a, 0xc6, 0x9b, 0xd0,
-        0x9c, 0xdb, 0x9d, 0xe4, 0x9e, 0xed, 0x9f, 0xf6,
-        0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60,        /* 3 */
-        0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9e,
-        0x98, 0xaa, 0x99, 0xb5, 0x9a, 0xbf, 0x9b, 0xcb,
-        0x9c, 0xd6, 0x9d, 0xe1, 0x9e, 0xeb, 0x9f, 0xf5,
-        0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x23, 0x92, 0x3f, 0x93, 0x55,        /* 4 */
-        0x94, 0x68, 0x95, 0x77, 0x96, 0x86, 0x97, 0x95,
-        0x98, 0xa2, 0x99, 0xad, 0x9a, 0xb9, 0x9b, 0xc6,
-        0x9c, 0xd2, 0x9d, 0xde, 0x9e, 0xe9, 0x9f, 0xf4,
-        0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x1b, 0x92, 0x33, 0x93, 0x48,        /* 5 */
-        0x94, 0x59, 0x95, 0x69, 0x96, 0x79, 0x97, 0x87,
-        0x98, 0x96, 0x99, 0xa3, 0x9a, 0xb1, 0x9b, 0xbe,
-        0x9c, 0xcc, 0x9d, 0xda, 0x9e, 0xe7, 0x9f, 0xf3,
-        0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20,        /* 6 */
-        0x94, 0x32, 0x95, 0x40, 0x96, 0x57, 0x97, 0x67,
-        0x98, 0x77, 0x99, 0x88, 0x9a, 0x99, 0x9b, 0xaa,
-        0x9c, 0xbb, 0x9d, 0xcc, 0x9e, 0xdd, 0x9f, 0xee,
-        0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26,        /* 7 */
-        0x94, 0x38, 0x95, 0x4a, 0x96, 0x60, 0x97, 0x70,
-        0x98, 0x80, 0x99, 0x90, 0x9a, 0xa0, 0x9b, 0xb0,
-        0x9c, 0xc0, 0x9D, 0xd0, 0x9e, 0xe0, 0x9f, 0xf0,
-        0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35,        /* 8 */
-        0x94, 0x47, 0x95, 0x5a, 0x96, 0x69, 0x97, 0x79,
-        0x98, 0x88, 0x99, 0x97, 0x9a, 0xa7, 0x9b, 0xb6,
-        0x9c, 0xc4, 0x9d, 0xd3, 0x9e, 0xe0, 0x9f, 0xf0,
-        0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40,        /* 9 */
-        0x94, 0x54, 0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
-        0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd,
-        0x9c, 0xca, 0x9d, 0xd6, 0x9e, 0xe0, 0x9f, 0xf0,
-        0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x18, 0x92, 0x2b, 0x93, 0x44,        /* 10 */
-        0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8e,
-        0x98, 0x9c, 0x99, 0xaa, 0x9a, 0xb7, 0x9b, 0xc4,
-        0x9c, 0xd0, 0x9d, 0xd8, 0x9e, 0xe2, 0x9f, 0xf0,
-        0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x1a, 0x92, 0x34, 0x93, 0x52,        /* 11 */
-        0x94, 0x66, 0x95, 0x7e, 0x96, 0x8D, 0x97, 0x9B,
-        0x98, 0xa8, 0x99, 0xb4, 0x9a, 0xc0, 0x9b, 0xcb,
-        0x9c, 0xd6, 0x9d, 0xe1, 0x9e, 0xeb, 0x9f, 0xf5,
-        0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x3f, 0x92, 0x5a, 0x93, 0x6e,        /* 12 */
-        0x94, 0x7f, 0x95, 0x8e, 0x96, 0x9c, 0x97, 0xa8,
-        0x98, 0xb4, 0x99, 0xbf, 0x9a, 0xc9, 0x9b, 0xd3,
-        0x9c, 0xdc, 0x9d, 0xe5, 0x9e, 0xee, 0x9f, 0xf6,
-        0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x54, 0x92, 0x6f, 0x93, 0x83,        /* 13 */
-        0x94, 0x93, 0x95, 0xa0, 0x96, 0xad, 0x97, 0xb7,
-        0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdc,
-        0x9c, 0xe4, 0x9d, 0xeb, 0x9e, 0xf2, 0x9f, 0xf9,
-        0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x6e, 0x92, 0x88, 0x93, 0x9a,        /* 14 */
-        0x94, 0xa8, 0x95, 0xb3, 0x96, 0xbd, 0x97, 0xc6,
-        0x98, 0xcf, 0x99, 0xd6, 0x9a, 0xdd, 0x9b, 0xe3,
-        0x9c, 0xe9, 0x9d, 0xef, 0x9e, 0xf4, 0x9f, 0xfa,
-        0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x93, 0x92, 0xa8, 0x93, 0xb7,        /* 15 */
-        0x94, 0xc1, 0x95, 0xca, 0x96, 0xd2, 0x97, 0xd8,
-        0x98, 0xde, 0x99, 0xe3, 0x9a, 0xe8, 0x9b, 0xed,
-        0x9c, 0xf1, 0x9d, 0xf5, 0x9e, 0xf8, 0x9f, 0xfc,
-        0xa0, 0xff}
+static const u8 gamma_table[GAMMA_MAX][17] = {
+       {0x00, 0x3e, 0x69, 0x85, 0x95, 0xa1, 0xae, 0xb9,        /* 0 */
+        0xc2, 0xcb, 0xd4, 0xdb, 0xe3, 0xea, 0xf1, 0xf8,
+        0xff},
+       {0x00, 0x33, 0x5a, 0x75, 0x85, 0x93, 0xa1, 0xad,        /* 1 */
+        0xb7, 0xc2, 0xcb, 0xd4, 0xde, 0xe7, 0xf0, 0xf7,
+        0xff},
+       {0x00, 0x2f, 0x51, 0x6b, 0x7c, 0x8a, 0x99, 0xa6,        /* 2 */
+        0xb1, 0xbc, 0xc6, 0xd0, 0xdb, 0xe4, 0xed, 0xf6,
+        0xff},
+       {0x00, 0x29, 0x48, 0x60, 0x72, 0x81, 0x90, 0x9e,        /* 3 */
+        0xaa, 0xb5, 0xbf, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
+        0xff},
+       {0x00, 0x23, 0x3f, 0x55, 0x68, 0x77, 0x86, 0x95,        /* 4 */
+        0xa2, 0xad, 0xb9, 0xc6, 0xd2, 0xde, 0xe9, 0xf4,
+        0xff},
+       {0x00, 0x1b, 0x33, 0x48, 0x59, 0x69, 0x79, 0x87,        /* 5 */
+        0x96, 0xa3, 0xb1, 0xbe, 0xcc, 0xda, 0xe7, 0xf3,
+        0xff},
+       {0x00, 0x02, 0x10, 0x20, 0x32, 0x40, 0x57, 0x67,        /* 6 */
+        0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
+        0xff},
+       {0x00, 0x02, 0x14, 0x26, 0x38, 0x4a, 0x60, 0x70,        /* 7 */
+        0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
+        0xff},
+       {0x00, 0x10, 0x22, 0x35, 0x47, 0x5a, 0x69, 0x79,        /* 8 */
+        0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe0, 0xf0,
+        0xff},
+       {0x00, 0x10, 0x26, 0x40, 0x54, 0x65, 0x75, 0x84,        /* 9 */
+        0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd6, 0xe0, 0xf0,
+        0xff},
+       {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 */
+        0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
+        0xff},
+       {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8,        /* 12 */
+        0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,
+        0xff},
+       {0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7,        /* 13 */
+        0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,
+        0xff},
+       {0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6,        /* 14 */
+        0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,
+        0xff},
+       {0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8,        /* 15 */
+        0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,
+        0xff}
 };
 
-static const __u8 tas5130a_sensor_init[][8] = {
+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},
@@ -418,11 +389,11 @@ static const __u8 tas5130a_sensor_init[][8] = {
        {},
 };
 
-static __u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
+static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
 
 /* read 1 byte */
-static int reg_r(struct gspca_dev *gspca_dev,
-                  __u16 index)
+static u8 reg_r(struct gspca_dev *gspca_dev,
+                  u16 index)
 {
        usb_control_msg(gspca_dev->dev,
                        usb_rcvctrlpipe(gspca_dev->dev, 0),
@@ -435,7 +406,7 @@ static int reg_r(struct gspca_dev *gspca_dev,
 }
 
 static void reg_w(struct gspca_dev *gspca_dev,
-                 __u16 index)
+                 u16 index)
 {
        usb_control_msg(gspca_dev->dev,
                        usb_sndctrlpipe(gspca_dev->dev, 0),
@@ -446,7 +417,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
 }
 
 static void reg_w_buf(struct gspca_dev *gspca_dev,
-                 const __u8 *buffer, __u16 len)
+                 const u8 *buffer, u16 len)
 {
        if (len <= USB_BUF_SZ) {
                memcpy(gspca_dev->usb_buf, buffer, len);
@@ -457,7 +428,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
                                0x01, 0,
                                gspca_dev->usb_buf, len, 500);
        } else {
-               __u8 *tmpbuf;
+               u8 *tmpbuf;
 
                tmpbuf = kmalloc(len, GFP_KERNEL);
                memcpy(tmpbuf, buffer, len);
@@ -471,14 +442,41 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
        }
 }
 
+/* write values to consecutive registers */
+static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
+                       u8 reg,
+                       const u8 *buffer, u16 len)
+{
+       int i;
+       u8 *p, *tmpbuf;
+
+       if (len * 2 <= USB_BUF_SZ)
+               p = tmpbuf = gspca_dev->usb_buf;
+       else
+               p = tmpbuf = kmalloc(len * 2, GFP_KERNEL);
+       i = len;
+       while (--i >= 0) {
+               *p++ = reg++;
+               *p++ = *buffer++;
+       }
+       usb_control_msg(gspca_dev->dev,
+                       usb_sndctrlpipe(gspca_dev->dev, 0),
+                       0,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0x01, 0,
+                       tmpbuf, len * 2, 500);
+       if (len * 2 > USB_BUF_SZ)
+               kfree(tmpbuf);
+}
+
 /* Reported as OM6802*/
 static void om6802_sensor_init(struct gspca_dev *gspca_dev)
 {
        int i;
-       const __u8 *p;
-       __u8 byte;
-       __u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
-       static const __u8 sensor_init[] = {
+       const u8 *p;
+       u8 byte;
+       u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
+       static const u8 sensor_init[] = {
                0xdf, 0x6d,
                0xdd, 0x18,
                0x5a, 0xe0,
@@ -497,7 +495,7 @@ static void om6802_sensor_init(struct gspca_dev *gspca_dev)
        };
 
        reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
-       msleep(5);
+       msleep(100);
        i = 4;
        while (--i > 0) {
                byte = reg_r(gspca_dev, 0x0060);
@@ -538,20 +536,20 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct cam *cam;
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 0x01;
 
        cam->cam_mode = vga_mode_t16;
        cam->nmodes = ARRAY_SIZE(vga_mode_t16);
 
-       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 = COLORS_DEF;
        sd->gamma = GAMMA_DEF;
-       sd->mirror = sd_ctrls[SD_MIRROR].qctrl.default_value;
-       sd->freq = sd_ctrls[SD_LIGHTFREQ].qctrl.default_value;
-       sd->whitebalance = sd_ctrls[SD_WHITE_BALANCE].qctrl.default_value;
-       sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
-       sd->effect = sd_ctrls[SD_EFFECTS].qctrl.default_value;
+       sd->autogain = AUTOGAIN_DEF;
+       sd->mirror = MIRROR_DEF;
+       sd->freq = FREQ_DEF;
+       sd->whitebalance = WHITE_BALANCE_DEF;
+       sd->sharpness = SHARPNESS_DEF;
+       sd->effect = EFFECTS_DEF;
        return 0;
 }
 
@@ -559,7 +557,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        unsigned int brightness;
-       __u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
+       u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
 
        brightness = sd->brightness;
        if (brightness < 7) {
@@ -576,7 +574,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        unsigned int contrast = sd->contrast;
-       __u16 reg_to_write;
+       u16 reg_to_write;
 
        if (contrast < 7)
                reg_to_write = 0x8ea9 - contrast * 0x200;
@@ -589,7 +587,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 static void setcolors(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       __u16 reg_to_write;
+       u16 reg_to_write;
 
        reg_to_write = 0x80bb + sd->colors * 0x100;     /* was 0xc0 */
        reg_w(gspca_dev, reg_to_write);
@@ -600,14 +598,15 @@ static void setgamma(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
-       reg_w_buf(gspca_dev, gamma_table[sd->gamma], sizeof gamma_table[0]);
+       reg_w_ixbuf(gspca_dev, 0x90,
+               gamma_table[sd->gamma], sizeof gamma_table[0]);
 }
 
 static void setwhitebalance(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       __u8 white_balance[8] =
+       u8 white_balance[8] =
                {0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38};
 
        if (sd->whitebalance)
@@ -619,7 +618,7 @@ static void setwhitebalance(struct gspca_dev *gspca_dev)
 static void setsharpness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       __u16 reg_to_write;
+       u16 reg_to_write;
 
        reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
 
@@ -635,18 +634,22 @@ static int sd_init(struct gspca_dev *gspca_dev)
         * to see the initial parameters.*/
        struct sd *sd = (struct sd *) gspca_dev;
        int i;
-       __u8 byte, test_byte;
-
-       static const __u8 read_indexs[] =
-               { 0x06, 0x07, 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
-                 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00, 0x00 };
-       static const __u8 n1[] =
+       u16 sensor_id;
+       u8 test_byte = 0;
+       u16 reg80, reg8e;
+
+       static const u8 read_indexs[] =
+               { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
+                 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
+       static const u8 n1[] =
                        {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
-       static const __u8 n2[] =
+       static const u8 n2[] =
                        {0x08, 0x00};
-       static const __u8 n3[] =
+       static const u8 n3[6] =
                        {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
-       static const __u8 n4[] =
+       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,
@@ -656,40 +659,61 @@ static int sd_init(struct gspca_dev *gspca_dev)
                 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 nset9[4] =
-                       { 0x0b, 0x04, 0x0a, 0x78 };
-       static const __u8 nset8[6] =
+       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 };
-
-       byte = reg_r(gspca_dev, 0x06);
-       test_byte = reg_r(gspca_dev, 0x07);
-       if (byte == 0x08 && test_byte == 0x07) {
-               PDEBUG(D_CONF, "sensor om6802");
-               sd->sensor = SENSOR_OM6802;
-       } else if (byte == 0x08 && test_byte == 0x01) {
-               PDEBUG(D_CONF, "sensor tas5130a");
-               sd->sensor = SENSOR_TAS5130A;
-       } else {
-               PDEBUG(D_CONF, "unknown sensor %02x %02x", byte, test_byte);
+       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);
+       switch (sensor_id & 0xff0f) {
+       case 0x0801:
+               PDEBUG(D_PROBE, "sensor tas5130a");
                sd->sensor = SENSOR_TAS5130A;
+               break;
+       case 0x0803:
+               PDEBUG(D_PROBE, "sensor 'other'");
+               sd->sensor = SENSOR_OTHER;
+               break;
+       case 0x0807:
+               PDEBUG(D_PROBE, "sensor om6802");
+               sd->sensor = SENSOR_OM6802;
+               break;
+       default:
+               PDEBUG(D_ERR|D_PROBE, "unknown sensor %04x", sensor_id);
+               return -EINVAL;
        }
 
-       reg_w_buf(gspca_dev, n1, sizeof n1);
-       test_byte = 0;
-       i = 5;
-       while (--i >= 0) {
-               reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
-               test_byte = reg_r(gspca_dev, 0x0063);
-               msleep(100);
-               if (test_byte == 0x17)
-                       break;          /* OK */
-       }
-       if (i < 0) {
-               err("Bad sensor reset %02x", test_byte);
-/*             return -EIO; */
+       if (sd->sensor != SENSOR_OTHER) {
+               reg_w_buf(gspca_dev, n1, sizeof n1);
+               i = 5;
+               while (--i >= 0) {
+                       reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
+                       test_byte = reg_r(gspca_dev, 0x0063);
+                       msleep(100);
+                       if (test_byte == 0x17)
+                               break;          /* OK */
+               }
+               if (i < 0) {
+                       err("Bad sensor reset %02x", test_byte);
+/*                     return -EIO; */
 /*fixme: test - continue */
+               }
+               reg_w_buf(gspca_dev, n2, sizeof n2);
        }
-       reg_w_buf(gspca_dev, n2, sizeof n2);
 
        i = 0;
        while (read_indexs[i] != 0x00) {
@@ -699,21 +723,31 @@ static int sd_init(struct gspca_dev *gspca_dev)
                i++;
        }
 
-       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);
+       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;
+       }
 
-       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data1,
+       reg_w_ixbuf(gspca_dev, 0xd0, sensor_data[sd->sensor].data1,
                        sizeof sensor_data[sd->sensor].data1);
-       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data3,
-                       sizeof sensor_data[sd->sensor].data3);
-       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data2,
+       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(gspca_dev, 0x3880);
-       reg_w(gspca_dev, 0x3880);
-       reg_w(gspca_dev, 0x338e);
+       reg_w(gspca_dev, reg80);
+       reg_w(gspca_dev, reg80);
+       reg_w(gspca_dev, reg8e);
 
        setbrightness(gspca_dev);
        setcontrast(gspca_dev);
@@ -730,16 +764,20 @@ static int sd_init(struct gspca_dev *gspca_dev)
                        sizeof sensor_data[sd->sensor].data4);
        reg_w_buf(gspca_dev, sensor_data[sd->sensor].data5,
                        sizeof sensor_data[sd->sensor].data5);
-       reg_w_buf(gspca_dev, nset8, sizeof nset8);
-       reg_w_buf(gspca_dev, nset9, sizeof nset9);
-
-       reg_w(gspca_dev, 0x2880);
+       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_data[sd->sensor].data1,
+       reg_w_ixbuf(gspca_dev, 0xd0, sensor_data[sd->sensor].data1,
                        sizeof sensor_data[sd->sensor].data1);
-       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data3,
-                       sizeof sensor_data[sd->sensor].data3);
-       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data2,
+       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);
 
        return 0;
@@ -748,7 +786,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
 static void setflip(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       __u8 flipcmd[8] =
+       u8 flipcmd[8] =
                {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
 
        if (sd->mirror)
@@ -778,7 +816,7 @@ static void seteffect(struct gspca_dev *gspca_dev)
 static void setlightfreq(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       __u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 };
+       u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 };
 
        if (sd->freq == 2)      /* 60hz */
                freq[1] = 0x00;
@@ -791,22 +829,22 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
 static void poll_sensor(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       static const __u8 poll1[] =
+       static const u8 poll1[] =
                {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
                 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
                 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
                 0x60, 0x14};
-       static const __u8 poll2[] =
+       static const u8 poll2[] =
                {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
                 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
-       static const __u8 poll3[] =
+       static const u8 poll3[] =
                {0x87, 0x3f, 0x88, 0x20, 0x89, 0x2d};
-       static const __u8 poll4[] =
+       static const u8 poll4[] =
                {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
                 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
                 0xc2, 0x80, 0xc3, 0x10};
 
-       if (sd->sensor != SENSOR_TAS5130A) {
+       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);
@@ -819,13 +857,14 @@ static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int i, mode;
-       __u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
-       static const __u8 t3[] =
-               { 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
-                 0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
+       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;
        switch (mode) {
+       case 0:         /* 640x480 (0x00) */
+               break;
        case 1:         /* 352x288 */
                t2[1] = 0x40;
                break;
@@ -835,14 +874,20 @@ static int sd_start(struct gspca_dev *gspca_dev)
        case 3:         /* 176x144 */
                t2[1] = 0x50;
                break;
-       case 4:         /* 160x120 */
+       default:
+/*     case 4:          * 160x120 */
                t2[1] = 0x20;
                break;
-       default:        /* 640x480 (0x00) */
-               break;
        }
 
-       if (sd->sensor == SENSOR_TAS5130A) {
+       switch (sd->sensor) {
+       case SENSOR_OM6802:
+               om6802_sensor_init(gspca_dev);
+               break;
+       case SENSOR_OTHER:
+               break;
+       default:
+/*     case SENSOR_TAS5130A: */
                i = 0;
                while (tas5130a_sensor_init[i][0] != 0) {
                        reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
@@ -854,14 +899,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg_w_buf(gspca_dev, tas5130a_sensor_init[3],
                                 sizeof tas5130a_sensor_init[0]);
                reg_w(gspca_dev, 0x3c80);
-       } else {
-               om6802_sensor_init(gspca_dev);
+               break;
        }
        reg_w_buf(gspca_dev, sensor_data[sd->sensor].data4,
                        sizeof sensor_data[sd->sensor].data4);
        reg_r(gspca_dev, 0x0012);
        reg_w_buf(gspca_dev, t2, sizeof t2);
-       reg_w_buf(gspca_dev, t3, sizeof t3);
+       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,
@@ -885,16 +929,18 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        msleep(20);
        reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
                        sizeof sensor_data[sd->sensor].stream);
-       msleep(20);
-       reg_w(gspca_dev, 0x0309);
+       if (sd->sensor != SENSOR_OTHER) {
+               msleep(20);
+               reg_w(gspca_dev, 0x0309);
+       }
 }
 
 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 */
 {
-       static __u8 ffd9[] = { 0xff, 0xd9 };
+       static u8 ffd9[] = { 0xff, 0xd9 };
 
        if (data[0] == 0x5a) {
                /* Control Packet, after this came the header again,
@@ -1172,8 +1218,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index 94163cceb28ae0bb6ec051294420288ddbc0816a..9f243d7e3110554d4107c90021d13d2c4325d4e5 100644 (file)
@@ -31,7 +31,6 @@ struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
        __u16 brightness;
-       __u16 contrast;
 
        __u8 packet;
 };
@@ -39,38 +38,22 @@ struct sd {
 /* V4L2 controls supported by the driver */
 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);
-static int sd_getcontrast(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 = 1,
-         .maximum = 0x2ff,
+         .maximum = 0x15f,     /* = 352 - 1 */
          .step = 1,
-         .default_value = 0x18f,
+#define BRIGHTNESS_DEF 0x14c
+         .default_value = BRIGHTNESS_DEF,
          },
         .set = sd_setbrightness,
         .get = sd_getbrightness,
         },
-#define SD_CONTRAST 1
-       {
-        {
-         .id = V4L2_CID_CONTRAST,
-         .type = V4L2_CTRL_TYPE_INTEGER,
-         .name = "Contrast",
-         .minimum = 0,
-         .maximum = 0xffff,
-         .step = 1,
-         .default_value = 0x7fff,
-         },
-        .set = sd_setcontrast,
-        .get = sd_getcontrast,
-        },
 };
 
 static const struct v4l2_pix_format sif_mode[] = {
@@ -86,78 +69,64 @@ static const struct v4l2_pix_format sif_mode[] = {
                .priv = 0},
 };
 
-/*
- * Initialization data: this is the first set-up data written to the
- * device (before the open data).
- */
-#define TESTCLK 0x10           /* reg 0x2c -> 0x12 //10 */
-#define TESTCOMP 0x90          /* reg 0x28 -> 0x80 */
-#define TESTLINE 0x81          /* reg 0x29 -> 0x81 */
-#define QCIFLINE 0x41          /* reg 0x29 -> 0x81 */
-#define TESTPTL 0x14           /* reg 0x2D -> 0x14 */
-#define TESTPTH 0x01           /* reg 0x2E -> 0x01 */
-#define TESTPTBL 0x12          /* reg 0x2F -> 0x0a */
-#define TESTPTBH 0x01          /* reg 0x30 -> 0x01 */
-#define ADWIDTHL 0xe8          /* reg 0x0c -> 0xe8 */
-#define ADWIDTHH 0x03          /* reg 0x0d -> 0x03 */
-#define ADHEIGHL 0x90          /* reg 0x0e -> 0x91 //93 */
-#define ADHEIGHH 0x01          /* reg 0x0f -> 0x01 */
-#define EXPOL 0x8f             /* reg 0x1c -> 0x8f */
-#define EXPOH 0x01             /* reg 0x1d -> 0x01 */
-#define ADCBEGINL 0x44         /* reg 0x10 -> 0x46 //47 */
-#define ADCBEGINH 0x00         /* reg 0x11 -> 0x00 */
-#define ADRBEGINL 0x0a         /* reg 0x14 -> 0x0b //0x0c */
-#define ADRBEGINH 0x00         /* reg 0x15 -> 0x00 */
-#define TV8532_CMD_UPDATE 0x84
-
-#define TV8532_EEprom_Add 0x03
-#define TV8532_EEprom_DataL 0x04
-#define TV8532_EEprom_DataM 0x05
-#define TV8532_EEprom_DataH 0x06
-#define TV8532_EEprom_TableLength 0x07
-#define TV8532_EEprom_Write 0x08
-#define TV8532_PART_CTRL 0x00
-#define TV8532_CTRL 0x01
-#define TV8532_CMD_EEprom_Open 0x30
-#define TV8532_CMD_EEprom_Close 0x29
-#define TV8532_UDP_UPDATE 0x31
-#define TV8532_GPIO 0x39
-#define TV8532_GPIO_OE 0x3B
-#define TV8532_REQ_RegWrite 0x02
-#define TV8532_REQ_RegRead 0x03
-
-#define TV8532_ADWIDTH_L 0x0C
-#define TV8532_ADWIDTH_H 0x0D
-#define TV8532_ADHEIGHT_L 0x0E
-#define TV8532_ADHEIGHT_H 0x0F
-#define TV8532_EXPOSURE 0x1C
-#define TV8532_QUANT_COMP 0x28
-#define TV8532_MODE_PACKET 0x29
-#define TV8532_SETCLK 0x2C
-#define TV8532_POINT_L 0x2D
-#define TV8532_POINT_H 0x2E
-#define TV8532_POINTB_L 0x2F
-#define TV8532_POINTB_H 0x30
-#define TV8532_BUDGET_L 0x2A
-#define TV8532_BUDGET_H 0x2B
-#define TV8532_VID_L 0x34
-#define TV8532_VID_H 0x35
-#define TV8532_PID_L 0x36
-#define TV8532_PID_H 0x37
-#define TV8532_DeviceID 0x83
-#define TV8532_AD_SLOPE 0x91
-#define TV8532_AD_BITCTRL 0x94
-#define TV8532_AD_COLBEGIN_L 0x10
-#define TV8532_AD_COLBEGIN_H 0x11
-#define TV8532_AD_ROWBEGIN_L 0x14
-#define TV8532_AD_ROWBEGIN_H 0x15
-
-static const __u32 tv_8532_eeprom_data[] = {
-/*     add             dataL      dataM        dataH */
-       0x00010001, 0x01018011, 0x02050014, 0x0305001c,
-       0x040d001e, 0x0505001f, 0x06050519, 0x0705011b,
-       0x0805091e, 0x090d892e, 0x0a05892f, 0x0b050dd9,
-       0x0c0509f1, 0
+/* TV-8532A (ICM532A) registers (LE) */
+#define R00_PART_CONTROL 0x00
+#define                LATENT_CHANGE   0x80
+#define                EXPO_CHANGE     0x04
+#define R01_TIMING_CONTROL_LOW 0x01
+#define                CMD_EEprom_Open 0x30
+#define                CMD_EEprom_Close 0x29
+#define R03_TABLE_ADDR 0x03
+#define R04_WTRAM_DATA_L 0x04
+#define R05_WTRAM_DATA_M 0x05
+#define R06_WTRAM_DATA_H 0x06
+#define R07_TABLE_LEN  0x07
+#define R08_RAM_WRITE_ACTION 0x08
+#define R0C_AD_WIDTHL  0x0c
+#define R0D_AD_WIDTHH  0x0d
+#define R0E_AD_HEIGHTL 0x0e
+#define R0F_AD_HEIGHTH 0x0f
+#define R10_AD_COL_BEGINL 0x10
+#define R11_AD_COL_BEGINH 0x11
+#define                MIRROR          0x04    /* [10] */
+#define R14_AD_ROW_BEGINL 0x14
+#define R15_AD_ROWBEGINH  0x15
+#define R1C_AD_EXPOSE_TIMEL 0x1c
+#define R28_QUANT      0x28
+#define R29_LINE       0x29
+#define R2C_POLARITY   0x2c
+#define R2D_POINT      0x2d
+#define R2E_POINTH     0x2e
+#define R2F_POINTB     0x2f
+#define R30_POINTBH    0x30
+#define R31_UPD                0x31
+#define R2A_HIGH_BUDGET 0x2a
+#define R2B_LOW_BUDGET 0x2b
+#define R34_VID                0x34
+#define R35_VIDH       0x35
+#define R36_PID                0x36
+#define R37_PIDH       0x37
+#define R39_Test1      0x39            /* GPIO */
+#define R3B_Test3      0x3B            /* GPIO */
+#define R83_AD_IDH     0x83
+#define R91_AD_SLOPEREG 0x91
+#define R94_AD_BITCONTROL 0x94
+
+static const u8 eeprom_data[][3] = {
+/*     dataH dataM dataL */
+       {0x01, 0x00, 0x01},
+       {0x01, 0x80, 0x11},
+       {0x05, 0x00, 0x14},
+       {0x05, 0x00, 0x1c},
+       {0x0d, 0x00, 0x1e},
+       {0x05, 0x00, 0x1f},
+       {0x05, 0x05, 0x19},
+       {0x05, 0x01, 0x1b},
+       {0x05, 0x09, 0x1e},
+       {0x0d, 0x89, 0x2e},
+       {0x05, 0x89, 0x2f},
+       {0x05, 0x0d, 0xd9},
+       {0x05, 0x09, 0xf1},
 };
 
 static int reg_r(struct gspca_dev *gspca_dev,
@@ -165,7 +134,7 @@ static int reg_r(struct gspca_dev *gspca_dev,
 {
        usb_control_msg(gspca_dev->dev,
                        usb_rcvctrlpipe(gspca_dev->dev, 0),
-                       TV8532_REQ_RegRead,
+                       0x03,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0,      /* value */
                        index, gspca_dev->usb_buf, 1,
@@ -174,27 +143,27 @@ static int reg_r(struct gspca_dev *gspca_dev,
 }
 
 /* write 1 byte */
-static void reg_w_1(struct gspca_dev *gspca_dev,
+static void reg_w1(struct gspca_dev *gspca_dev,
                  __u16 index, __u8 value)
 {
        gspca_dev->usb_buf[0] = value;
        usb_control_msg(gspca_dev->dev,
                        usb_sndctrlpipe(gspca_dev->dev, 0),
-                       TV8532_REQ_RegWrite,
+                       0x02,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0,      /* value */
                        index, gspca_dev->usb_buf, 1, 500);
 }
 
 /* write 2 bytes */
-static void reg_w_2(struct gspca_dev *gspca_dev,
-                 __u16 index, __u8 val1, __u8 val2)
+static void reg_w2(struct gspca_dev *gspca_dev,
+                 u16 index, u16 value)
 {
-       gspca_dev->usb_buf[0] = val1;
-       gspca_dev->usb_buf[1] = val2;
+       gspca_dev->usb_buf[0] = value;
+       gspca_dev->usb_buf[1] = value >> 8;
        usb_control_msg(gspca_dev->dev,
                        usb_sndctrlpipe(gspca_dev->dev, 0),
-                       TV8532_REQ_RegWrite,
+                       0x02,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0,      /* value */
                        index, gspca_dev->usb_buf, 2, 500);
@@ -202,32 +171,18 @@ static void reg_w_2(struct gspca_dev *gspca_dev,
 
 static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev)
 {
-       int i = 0;
-       __u8 reg, data0, data1, data2;
-
-       reg_w_1(gspca_dev, TV8532_GPIO, 0xb0);
-       reg_w_1(gspca_dev, TV8532_CTRL, TV8532_CMD_EEprom_Open);
-/*     msleep(1); */
-       while (tv_8532_eeprom_data[i]) {
-               reg = (tv_8532_eeprom_data[i] & 0xff000000) >> 24;
-               reg_w_1(gspca_dev, TV8532_EEprom_Add, reg);
-               /* msleep(1); */
-               data0 = (tv_8532_eeprom_data[i] & 0x000000ff);
-               reg_w_1(gspca_dev, TV8532_EEprom_DataL, data0);
-               /* msleep(1); */
-               data1 = (tv_8532_eeprom_data[i] & 0x0000ff00) >> 8;
-               reg_w_1(gspca_dev, TV8532_EEprom_DataM, data1);
-               /* msleep(1); */
-               data2 = (tv_8532_eeprom_data[i] & 0x00ff0000) >> 16;
-               reg_w_1(gspca_dev, TV8532_EEprom_DataH, data2);
-               /* msleep(1); */
-               reg_w_1(gspca_dev, TV8532_EEprom_Write, 0);
-               /* msleep(10); */
-               i++;
+       int i;
+
+       reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Open);
+       for (i = 0; i < ARRAY_SIZE(eeprom_data); i++) {
+               reg_w1(gspca_dev, R03_TABLE_ADDR, i);
+               reg_w1(gspca_dev, R04_WTRAM_DATA_L, eeprom_data[i][2]);
+               reg_w1(gspca_dev, R05_WTRAM_DATA_M, eeprom_data[i][1]);
+               reg_w1(gspca_dev, R06_WTRAM_DATA_H, eeprom_data[i][0]);
+               reg_w1(gspca_dev, R08_RAM_WRITE_ACTION, 0);
        }
-       reg_w_1(gspca_dev, TV8532_EEprom_TableLength, i);
-/*     msleep(1); */
-       reg_w_1(gspca_dev, TV8532_CTRL, TV8532_CMD_EEprom_Close);
+       reg_w1(gspca_dev, R07_TABLE_LEN, i);
+       reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close);
        msleep(10);
 }
 
@@ -238,79 +193,76 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct sd *sd = (struct sd *) gspca_dev;
        struct cam *cam;
 
-       tv_8532WriteEEprom(gspca_dev);
-
        cam = &gspca_dev->cam;
-       cam->epaddr = 1;
        cam->cam_mode = sif_mode;
-       cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+       cam->nmodes = ARRAY_SIZE(sif_mode);
 
-       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
-       sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+       sd->brightness = BRIGHTNESS_DEF;
        return 0;
 }
 
 static void tv_8532ReadRegisters(struct gspca_dev *gspca_dev)
 {
-       __u8 data;
-
-       data = reg_r(gspca_dev, 0x0001);
-       PDEBUG(D_USBI, "register 0x01-> %x", data);
-       data = reg_r(gspca_dev, 0x0002);
-       PDEBUG(D_USBI, "register 0x02-> %x", data);
-       reg_r(gspca_dev, TV8532_ADWIDTH_L);
-       reg_r(gspca_dev, TV8532_ADWIDTH_H);
-       reg_r(gspca_dev, TV8532_QUANT_COMP);
-       reg_r(gspca_dev, TV8532_MODE_PACKET);
-       reg_r(gspca_dev, TV8532_SETCLK);
-       reg_r(gspca_dev, TV8532_POINT_L);
-       reg_r(gspca_dev, TV8532_POINT_H);
-       reg_r(gspca_dev, TV8532_POINTB_L);
-       reg_r(gspca_dev, TV8532_POINTB_H);
-       reg_r(gspca_dev, TV8532_BUDGET_L);
-       reg_r(gspca_dev, TV8532_BUDGET_H);
-       reg_r(gspca_dev, TV8532_VID_L);
-       reg_r(gspca_dev, TV8532_VID_H);
-       reg_r(gspca_dev, TV8532_PID_L);
-       reg_r(gspca_dev, TV8532_PID_H);
-       reg_r(gspca_dev, TV8532_DeviceID);
-       reg_r(gspca_dev, TV8532_AD_COLBEGIN_L);
-       reg_r(gspca_dev, TV8532_AD_COLBEGIN_H);
-       reg_r(gspca_dev, TV8532_AD_ROWBEGIN_L);
-       reg_r(gspca_dev, TV8532_AD_ROWBEGIN_H);
+       int i;
+       static u8 reg_tb[] = {
+               R0C_AD_WIDTHL,
+               R0D_AD_WIDTHH,
+               R28_QUANT,
+               R29_LINE,
+               R2C_POLARITY,
+               R2D_POINT,
+               R2E_POINTH,
+               R2F_POINTB,
+               R30_POINTBH,
+               R2A_HIGH_BUDGET,
+               R2B_LOW_BUDGET,
+               R34_VID,
+               R35_VIDH,
+               R36_PID,
+               R37_PIDH,
+               R83_AD_IDH,
+               R10_AD_COL_BEGINL,
+               R11_AD_COL_BEGINH,
+               R14_AD_ROW_BEGINL,
+               R15_AD_ROWBEGINH,
+               0
+       };
+
+       i = 0;
+       do {
+               reg_r(gspca_dev, reg_tb[i]);
+               i++;
+       } while (reg_tb[i] != 0);
 }
 
 static void tv_8532_setReg(struct gspca_dev *gspca_dev)
 {
-       reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_L,
-                       ADCBEGINL);                     /* 0x10 */
-       reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_H,
-                       ADCBEGINH);                     /* also digital gain */
-       reg_w_1(gspca_dev, TV8532_PART_CTRL,
-                       TV8532_CMD_UPDATE);             /* 0x00<-0x84 */
-
-       reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0a);
+       reg_w1(gspca_dev, R10_AD_COL_BEGINL, 0x44);
+                                               /* begin active line */
+       reg_w1(gspca_dev, R11_AD_COL_BEGINH, 0x00);
+                                               /* mirror and digital gain */
+       reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
+                                               /* = 0x84 */
+
+       reg_w1(gspca_dev, R3B_Test3, 0x0a);     /* Test0Sel = 10 */
        /******************************************************/
-       reg_w_1(gspca_dev, TV8532_ADHEIGHT_L, ADHEIGHL); /* 0e */
-       reg_w_1(gspca_dev, TV8532_ADHEIGHT_H, ADHEIGHH); /* 0f */
-       reg_w_2(gspca_dev, TV8532_EXPOSURE,
-                       EXPOL, EXPOH);                  /* 350d 0x014c; 1c */
-       reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_L,
-                       ADCBEGINL);                     /* 0x10 */
-       reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_H,
-                       ADCBEGINH);                     /* also digital gain */
-       reg_w_1(gspca_dev, TV8532_AD_ROWBEGIN_L,
-                       ADRBEGINL);                     /* 0x14 */
-
-       reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x00);      /* 0x91 */
-       reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x02);    /* 0x94 */
-
-       reg_w_1(gspca_dev, TV8532_CTRL,
-                       TV8532_CMD_EEprom_Close);       /* 0x01 */
-
-       reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x00);      /* 0x91 */
-       reg_w_1(gspca_dev, TV8532_PART_CTRL,
-                       TV8532_CMD_UPDATE);             /* 0x00<-0x84 */
+       reg_w1(gspca_dev, R0E_AD_HEIGHTL, 0x90);
+       reg_w1(gspca_dev, R0F_AD_HEIGHTH, 0x01);
+       reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, 0x018f);
+       reg_w1(gspca_dev, R10_AD_COL_BEGINL, 0x44);
+                                               /* begin active line */
+       reg_w1(gspca_dev, R11_AD_COL_BEGINH, 0x00);
+                                               /* mirror and digital gain */
+       reg_w1(gspca_dev, R14_AD_ROW_BEGINL, 0x0a);
+
+       reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00);
+       reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x02);
+
+       reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close);
+
+       reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00);
+       reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
+                                               /* = 0x84 */
 }
 
 static void tv_8532_PollReg(struct gspca_dev *gspca_dev)
@@ -319,54 +271,55 @@ static void tv_8532_PollReg(struct gspca_dev *gspca_dev)
 
        /* strange polling from tgc */
        for (i = 0; i < 10; i++) {
-               reg_w_1(gspca_dev, TV8532_SETCLK,
-                       TESTCLK);               /* 0x48; //0x08; 0x2c */
-               reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE);
-               reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01);    /* 0x31 */
+               reg_w1(gspca_dev, R2C_POLARITY, 0x10);
+               reg_w1(gspca_dev, R00_PART_CONTROL,
+                               LATENT_CHANGE | EXPO_CHANGE);
+               reg_w1(gspca_dev, R31_UPD, 0x01);
        }
 }
 
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
-       reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
-       reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
+       tv_8532WriteEEprom(gspca_dev);
+
+       reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x32);       /* slope begin 1,7V,
+                                                        * slope rate 2 */
+       reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x00);
        tv_8532ReadRegisters(gspca_dev);
-       reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
-       reg_w_2(gspca_dev, TV8532_ADHEIGHT_L, ADHEIGHL,
-                               ADHEIGHH);      /* 401d 0x0169; 0e */
-       reg_w_2(gspca_dev, TV8532_EXPOSURE, EXPOL,
-                               EXPOH);         /* 350d 0x014c; 1c */
-       reg_w_1(gspca_dev, TV8532_ADWIDTH_L, ADWIDTHL); /* 0x20; 0x0c */
-       reg_w_1(gspca_dev, TV8532_ADWIDTH_H, ADWIDTHH); /* 0x0d */
+       reg_w1(gspca_dev, R3B_Test3, 0x0b);
+       reg_w2(gspca_dev, R0E_AD_HEIGHTL, 0x0190);
+       reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, 0x018f);
+       reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8);
+       reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03);
 
        /*******************************************************************/
-       reg_w_1(gspca_dev, TV8532_QUANT_COMP,
-                       TESTCOMP);      /* 0x72 compressed mode 0x28 */
-       reg_w_1(gspca_dev, TV8532_MODE_PACKET,
-                       TESTLINE);      /* 0x84; // CIF | 4 packet 0x29 */
+       reg_w1(gspca_dev, R28_QUANT, 0x90);
+                                       /* no compress - fixed Q - quant 0 */
+       reg_w1(gspca_dev, R29_LINE, 0x81);
+                                       /* 0x84; // CIF | 4 packet 0x29 */
 
        /************************************************/
-       reg_w_1(gspca_dev, TV8532_SETCLK,
-                       TESTCLK);               /* 0x48; //0x08; 0x2c */
-       reg_w_1(gspca_dev, TV8532_POINT_L,
-                       TESTPTL);               /* 0x38; 0x2d */
-       reg_w_1(gspca_dev, TV8532_POINT_H,
-                       TESTPTH);               /* 0x04; 0x2e */
-       reg_w_1(gspca_dev, TV8532_POINTB_L,
-                       TESTPTBL);              /* 0x04; 0x2f */
-       reg_w_1(gspca_dev, TV8532_POINTB_H,
-                       TESTPTBH);              /* 0x04; 0x30 */
-       reg_w_1(gspca_dev, TV8532_PART_CTRL,
-                       TV8532_CMD_UPDATE);     /* 0x00<-0x84 */
+       reg_w1(gspca_dev, R2C_POLARITY, 0x10);
+                                               /* 0x48; //0x08; 0x2c */
+       reg_w1(gspca_dev, R2D_POINT, 0x14);
+                                               /* 0x38; 0x2d */
+       reg_w1(gspca_dev, R2E_POINTH, 0x01);
+                                               /* 0x04; 0x2e */
+       reg_w1(gspca_dev, R2F_POINTB, 0x12);
+                                               /* 0x04; 0x2f */
+       reg_w1(gspca_dev, R30_POINTBH, 0x01);
+                                               /* 0x04; 0x30 */
+       reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
+                                               /* 0x00<-0x84 */
        /*************************************************/
-       reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01);    /* 0x31 */
+       reg_w1(gspca_dev, R31_UPD, 0x01);       /* update registers */
        msleep(200);
-       reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00);    /* 0x31 */
+       reg_w1(gspca_dev, R31_UPD, 0x00);               /* end update */
        /*************************************************/
        tv_8532_setReg(gspca_dev);
        /*************************************************/
-       reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
+       reg_w1(gspca_dev, R3B_Test3, 0x0b);     /* Test0Sel = 11 = GPIO */
        /*************************************************/
        tv_8532_setReg(gspca_dev);
        /*************************************************/
@@ -377,11 +330,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int brightness = sd->brightness;
 
-       reg_w_2(gspca_dev, TV8532_EXPOSURE,
-               brightness >> 8, brightness);           /* 1c */
-       reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE);
+       reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, sd->brightness);
+       reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
+                                               /* 0x84 */
 }
 
 /* -- start the camera -- */
@@ -389,57 +341,50 @@ static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
-       reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
+       reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x32);       /* slope begin 1,7V,
+                                                        * slope rate 2 */
+       reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x00);
        tv_8532ReadRegisters(gspca_dev);
-       reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
-       reg_w_2(gspca_dev, TV8532_ADHEIGHT_L,
-               ADHEIGHL, ADHEIGHH);    /* 401d 0x0169; 0e */
-/*     reg_w_2(gspca_dev, TV8532_EXPOSURE,
-               EXPOL, EXPOH);           * 350d 0x014c; 1c */
+       reg_w1(gspca_dev, R3B_Test3, 0x0b);
+
+       reg_w2(gspca_dev, R0E_AD_HEIGHTL, 0x0190);
        setbrightness(gspca_dev);
 
-       reg_w_1(gspca_dev, TV8532_ADWIDTH_L, ADWIDTHL); /* 0x20; 0x0c */
-       reg_w_1(gspca_dev, TV8532_ADWIDTH_H, ADWIDTHH); /* 0x0d */
+       reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8);         /* 0x20; 0x0c */
+       reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03);
 
        /************************************************/
-       reg_w_1(gspca_dev, TV8532_QUANT_COMP,
-                       TESTCOMP);      /* 0x72 compressed mode 0x28 */
+       reg_w1(gspca_dev, R28_QUANT, 0x90);
+                                       /* 0x72 compressed mode 0x28 */
        if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
                /* 176x144 */
-               reg_w_1(gspca_dev, TV8532_MODE_PACKET,
-                       QCIFLINE);      /* 0x84; // CIF | 4 packet 0x29 */
+               reg_w1(gspca_dev, R29_LINE, 0x41);
+                                       /* CIF - 2 lines/packet */
        } else {
                /* 352x288 */
-               reg_w_1(gspca_dev, TV8532_MODE_PACKET,
-                       TESTLINE);      /* 0x84; // CIF | 4 packet 0x29 */
+               reg_w1(gspca_dev, R29_LINE, 0x81);
+                                       /* CIF - 2 lines/packet */
        }
        /************************************************/
-       reg_w_1(gspca_dev, TV8532_SETCLK,
-                       TESTCLK);               /* 0x48; //0x08; 0x2c */
-       reg_w_1(gspca_dev, TV8532_POINT_L,
-                       TESTPTL);               /* 0x38; 0x2d */
-       reg_w_1(gspca_dev, TV8532_POINT_H,
-                       TESTPTH);               /* 0x04; 0x2e */
-       reg_w_1(gspca_dev, TV8532_POINTB_L,
-                       TESTPTBL);              /* 0x04; 0x2f */
-       reg_w_1(gspca_dev, TV8532_POINTB_H,
-                       TESTPTBH);              /* 0x04; 0x30 */
-       reg_w_1(gspca_dev, TV8532_PART_CTRL,
-                       TV8532_CMD_UPDATE);     /* 0x00<-0x84 */
+       reg_w1(gspca_dev, R2C_POLARITY, 0x10);          /* slow clock */
+       reg_w1(gspca_dev, R2D_POINT, 0x14);
+       reg_w1(gspca_dev, R2E_POINTH, 0x01);
+       reg_w1(gspca_dev, R2F_POINTB, 0x12);
+       reg_w1(gspca_dev, R30_POINTBH, 0x01);
+       reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
        /************************************************/
-       reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01);    /* 0x31 */
+       reg_w1(gspca_dev, R31_UPD, 0x01);       /* update registers */
        msleep(200);
-       reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00);    /* 0x31 */
+       reg_w1(gspca_dev, R31_UPD, 0x00);               /* end update */
        /************************************************/
        tv_8532_setReg(gspca_dev);
        /************************************************/
-       reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
+       reg_w1(gspca_dev, R3B_Test3, 0x0b);     /* Test0Sel = 11 = GPIO */
        /************************************************/
        tv_8532_setReg(gspca_dev);
        /************************************************/
        tv_8532_PollReg(gspca_dev);
-       reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00);    /* 0x31 */
+       reg_w1(gspca_dev, R31_UPD, 0x00);       /* end update */
 
        gspca_dev->empty_packet = 0;            /* check the empty packets */
        sd->packet = 0;                         /* ignore the first packets */
@@ -449,7 +394,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-       reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
+       reg_w1(gspca_dev, R3B_Test3, 0x0b);     /* Test0Sel = 11 = GPIO */
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -473,9 +418,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 
        /* each packet contains:
         * - header 2 bytes
-        * - RG line
+        * - RGRG line
         * - 4 bytes
-        * - GB line
+        * - GBGB line
         * - 4 bytes
         */
        gspca_frame_add(gspca_dev, packet_type0,
@@ -484,10 +429,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        frame, data + gspca_dev->width + 6, gspca_dev->width);
 }
 
-static void setcontrast(struct gspca_dev *gspca_dev)
-{
-}
-
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -506,24 +447,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->contrast = val;
-       if (gspca_dev->streaming)
-               setcontrast(gspca_dev);
-       return 0;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->contrast;
-       return 0;
-}
-
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
@@ -570,8 +493,10 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index 0525ea51a6dea95f54311933616e7f15bd825f8a..4c802fb12cd67d738770278f505386f1920f5b36 100644 (file)
@@ -37,18 +37,21 @@ struct sd {
        __u8 lightfreq;
        __u8 sharpness;
 
+       u8 image_offset;
+
        char bridge;
 #define BRIDGE_VC0321 0
 #define BRIDGE_VC0323 1
        char sensor;
 #define SENSOR_HV7131R 0
 #define SENSOR_MI0360 1
-#define SENSOR_MI1320 2
-#define SENSOR_MI1310_SOC 3
-#define SENSOR_OV7660 4
-#define SENSOR_OV7670 5
-#define SENSOR_PO1200 6
-#define SENSOR_PO3130NC 7
+#define SENSOR_MI1310_SOC 2
+#define SENSOR_MI1320 3
+#define SENSOR_MI1320_SOC 4
+#define SENSOR_OV7660 5
+#define SENSOR_OV7670 6
+#define SENSOR_PO1200 7
+#define SENSOR_PO3130NC 8
 };
 
 /* V4L2 controls supported by the driver */
@@ -149,8 +152,50 @@ 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 */
+               .bytesperline = 1280,
+               .sizeimage = 1280 * 1024 * 1 / 4 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 2},
+};
+static const struct v4l2_pix_format bi_mode[] = {
+/*fixme: jeg does not work
+       {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 5},
+*/
+       {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 2,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 4},
+/*
+       {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 3},
+*/
+       {640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480 * 2,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 2},
+/*
+       {1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 1280,
+               .sizeimage = 1280 * 1024 * 1 / 4 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 1},
+*/
+       {1280, 1024, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
+               .bytesperline = 1280,
+               .sizeimage = 1280 * 1024 * 2,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0},
 };
-
 static const struct v4l2_pix_format svga_mode[] = {
        {800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 800,
@@ -400,92 +445,208 @@ static const __u8 mi0360_initQVGA_JPG[][4] = {
 static const __u8 mi1310_socinitVGA_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, 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, 0x02, 0x00, 0xcc},
        {0xb3, 0x03, 0x0a, 0xcc},
-       {0xb3, 0x04, 0x05, 0xcc},
+       {0xb3, 0x04, 0x0d, 0xcc},
        {0xb3, 0x20, 0x00, 0xcc},
        {0xb3, 0x21, 0x00, 0xcc},
-       {0xb3, 0x22, 0x03, 0xcc},
-       {0xb3, 0x23, 0xc0, 0xcc},
+       {0xb3, 0x22, 0x01, 0xcc},
+       {0xb3, 0x23, 0xe0, 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, 0xd0, 0xcc},
-       {0xbc, 0x01, 0x01, 0xcc},
-       {0xf0, 0x00, 0x02, 0xbb},
-       {0xc8, 0x9f, 0x0b, 0xbb},
-       {0x5b, 0x00, 0x01, 0xbb},
-       {0x2f, 0xde, 0x20, 0xbb},
+       {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},
        {0xf0, 0x00, 0x00, 0xbb},
-       {0x20, 0x03, 0x02, 0xbb},
+       {0x00, 0x01, 0x00, 0xdd},
+       {0x0d, 0x00, 0x09, 0xbb},
+       {0x0d, 0x00, 0x08, 0xbb},
        {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},
+       {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},
-       {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},
+       {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, 0x02, 0xcc},
        {0xb6, 0x02, 0x80, 0xcc},
        {0xb6, 0x05, 0x01, 0xcc},
        {0xb6, 0x04, 0xe0, 0xcc},
-       {0xb6, 0x12, 0xf8, 0xcc},
-       {0xb6, 0x13, 0x25, 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, 0x00, 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},
        {0xbc, 0x02, 0x18, 0xcc},
        {0xbc, 0x03, 0x50, 0xcc},
        {0xbc, 0x04, 0x18, 0xcc},
@@ -496,131 +657,123 @@ static const __u8 mi1310_socinitVGA_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},
+       {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, 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},       {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},
-       {},
+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, 0x05, 0x00, 0xcc},
+       {0xb3, 0x06, 0x01, 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, 0x04, 0xcc},
+       {0xb3, 0x23, 0x00, 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},
+       {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, 0x03, 0xbb},
+       {0xb6, 0x00, 0x00, 0xcc},
+       {0xb6, 0x03, 0x05, 0xcc},
+       {0xb6, 0x02, 0x00, 0xcc},
+       {0xb6, 0x05, 0x04, 0xcc},
+       {0xb6, 0x04, 0x00, 0xcc},
+       {0xb6, 0x12, 0xf8, 0xcc},
+       {0xb6, 0x18, 0x0a, 0xcc},
+       {0xb6, 0x17, 0x00, 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},
+       {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},
+       {}
 };
 
 static const __u8 mi1320_gamma[17] = {
@@ -709,75 +862,791 @@ static const __u8 mi1320_initVGA_data[][4] = {
        {0xb3, 0x5c, 0x01, 0xcc},       {0xb3, 0x01, 0x41, 0xcc},
        {}
 };
-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},
-       {0xb3, 0x00, 0x64, 0xcc},       {0xb3, 0x00, 0x65, 0xcc},
-       {0xb0, 0x16, 0x03, 0xcc},       {0xb3, 0x05, 0x01, 0xcc},
-       {0xb3, 0x06, 0x01, 0xcc},       {0xb3, 0x08, 0x01, 0xcc},
-       {0xb3, 0x09, 0x0c, 0xcc},       {0xb3, 0x34, 0x02, 0xcc},
-       {0xb3, 0x35, 0xc8, 0xcc},       {0xb3, 0x02, 0x00, 0xcc},
-       {0xb3, 0x03, 0x0a, 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, 0x17, 0x7f, 0xcc},
-       {0xb3, 0x00, 0x65, 0xcc},       {0xb8, 0x00, 0x00, 0xcc},
-       {0xbc, 0x00, 0xd0, 0xcc},       {0xbc, 0x01, 0x01, 0xcc},
-       {0xf0, 0x00, 0x00, 0xbb},       {0x0d, 0x00, 0x09, 0xbb},
-       {0x00, 0x01, 0x00, 0xdd},       {0x0d, 0x00, 0x08, 0xbb},
-       {0xf0, 0x00, 0x00, 0xbb},       {0x02, 0x00, 0x64, 0xbb},
-       {0x05, 0x01, 0x78, 0xbb},       {0x06, 0x00, 0x11, 0xbb},
-       {0x07, 0x01, 0x42, 0xbb},       {0x08, 0x00, 0x11, 0xbb},
-       {0x20, 0x01, 0x00, 0xbb},       {0x21, 0x80, 0x00, 0xbb},
-       {0x22, 0x0d, 0x0f, 0xbb},       {0x24, 0x80, 0x00, 0xbb},
-       {0x59, 0x00, 0xff, 0xbb},       {0xf0, 0x00, 0x01, 0xbb},
-       {0x9d, 0x3c, 0xa0, 0xbb},       {0x47, 0x30, 0x30, 0xbb},
-       {0xf0, 0x00, 0x00, 0xbb},       {0x0a, 0x80, 0x11, 0xbb},
-       {0x35, 0x00, 0x22, 0xbb},       {0xf0, 0x00, 0x02, 0xbb},
-       {0x9d, 0xc5, 0x05, 0xbb},       {0xdc, 0x0f, 0xfc, 0xbb},
-       {0xf0, 0x00, 0x01, 0xbb},       {0x06, 0x74, 0x0e, 0xbb},
-       {0x80, 0x00, 0x06, 0xbb},       {0x81, 0x04, 0x00, 0xbb},
-       {0x82, 0x01, 0x02, 0xbb},       {0x83, 0x03, 0x02, 0xbb},
-       {0x84, 0x05, 0x00, 0xbb},       {0x85, 0x01, 0x00, 0xbb},
-       {0x86, 0x03, 0x02, 0xbb},       {0x87, 0x05, 0x00, 0xbb},
-       {0x88, 0x01, 0x00, 0xbb},       {0x89, 0x02, 0x02, 0xbb},
-       {0x8a, 0xfd, 0x04, 0xbb},       {0x8b, 0xfc, 0xfd, 0xbb},
-       {0x8c, 0xff, 0xfd, 0xbb},       {0x8d, 0x00, 0x00, 0xbb},
-       {0x8e, 0xfe, 0x05, 0xbb},       {0x8f, 0xfc, 0xfd, 0xbb},
-       {0x90, 0xfe, 0xfd, 0xbb},       {0x91, 0x00, 0x00, 0xbb},
-       {0x92, 0xfe, 0x03, 0xbb},       {0x93, 0xfd, 0xfe, 0xbb},
-       {0x94, 0xff, 0xfd, 0xbb},       {0x95, 0x00, 0x00, 0xbb},
-       {0xb6, 0x07, 0x05, 0xbb},       {0xb7, 0x13, 0x06, 0xbb},
-       {0xb8, 0x08, 0x06, 0xbb},       {0xb9, 0x14, 0x08, 0xbb},
-       {0xba, 0x06, 0x05, 0xbb},       {0xbb, 0x13, 0x06, 0xbb},
-       {0xbc, 0x03, 0x01, 0xbb},       {0xbd, 0x03, 0x04, 0xbb},
-       {0xbe, 0x00, 0x02, 0xbb},       {0xbf, 0x03, 0x01, 0xbb},
-       {0xc0, 0x02, 0x04, 0xbb},       {0xc1, 0x00, 0x04, 0xbb},
-       {0xc2, 0x02, 0x01, 0xbb},       {0xc3, 0x01, 0x03, 0xbb},
-       {0xc4, 0x00, 0x04, 0xbb},       {0xf0, 0x00, 0x02, 0xbb},
-       {0xc8, 0x00, 0x00, 0xbb},       {0x2e, 0x00, 0x00, 0xbb},
-       {0x2e, 0x0c, 0x5b, 0xbb},       {0x2f, 0xd1, 0x00, 0xbb},
-       {0x39, 0x03, 0xca, 0xbb},       {0x3a, 0x06, 0x80, 0xbb},
-       {0x3b, 0x01, 0x52, 0xbb},       {0x3c, 0x05, 0x40, 0xbb},
-       {0x57, 0x01, 0x9c, 0xbb},       {0x58, 0x01, 0xee, 0xbb},
-       {0x59, 0x00, 0xf0, 0xbb},       {0x5a, 0x01, 0x20, 0xbb},
-       {0x5c, 0x1d, 0x17, 0xbb},       {0x5d, 0x22, 0x1c, 0xbb},
-       {0x64, 0x1e, 0x1c, 0xbb},       {0x5b, 0x00, 0x01, 0xbb},
-       {0xf0, 0x00, 0x02, 0xbb},       {0x36, 0x68, 0x10, 0xbb},
-       {0x00, 0x00, 0x30, 0xdd},       {0x37, 0x81, 0x00, 0xbb},
-       {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},
-       {0xbf, 0xc0, 0x26, 0xcc},       {0xbf, 0xc1, 0x02, 0xcc},
-       {0xbf, 0xcc, 0x04, 0xcc},       {0xb3, 0x5c, 0x01, 0xcc},
+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},
+       {0xb3, 0x00, 0x64, 0xcc},       {0xb3, 0x00, 0x65, 0xcc},
+       {0xb0, 0x16, 0x03, 0xcc},       {0xb3, 0x05, 0x01, 0xcc},
+       {0xb3, 0x06, 0x01, 0xcc},       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},       {0xb3, 0x34, 0x02, 0xcc},
+       {0xb3, 0x35, 0xc8, 0xcc},       {0xb3, 0x02, 0x00, 0xcc},
+       {0xb3, 0x03, 0x0a, 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, 0x17, 0x7f, 0xcc},
+       {0xb3, 0x00, 0x65, 0xcc},       {0xb8, 0x00, 0x00, 0xcc},
+       {0xbc, 0x00, 0xd0, 0xcc},       {0xbc, 0x01, 0x01, 0xcc},
+       {0xf0, 0x00, 0x00, 0xbb},       {0x0d, 0x00, 0x09, 0xbb},
+       {0x00, 0x01, 0x00, 0xdd},       {0x0d, 0x00, 0x08, 0xbb},
+       {0xf0, 0x00, 0x00, 0xbb},       {0x02, 0x00, 0x64, 0xbb},
+       {0x05, 0x01, 0x78, 0xbb},       {0x06, 0x00, 0x11, 0xbb},
+       {0x07, 0x01, 0x42, 0xbb},       {0x08, 0x00, 0x11, 0xbb},
+       {0x20, 0x01, 0x00, 0xbb},       {0x21, 0x80, 0x00, 0xbb},
+       {0x22, 0x0d, 0x0f, 0xbb},       {0x24, 0x80, 0x00, 0xbb},
+       {0x59, 0x00, 0xff, 0xbb},       {0xf0, 0x00, 0x01, 0xbb},
+       {0x9d, 0x3c, 0xa0, 0xbb},       {0x47, 0x30, 0x30, 0xbb},
+       {0xf0, 0x00, 0x00, 0xbb},       {0x0a, 0x80, 0x11, 0xbb},
+       {0x35, 0x00, 0x22, 0xbb},       {0xf0, 0x00, 0x02, 0xbb},
+       {0x9d, 0xc5, 0x05, 0xbb},       {0xdc, 0x0f, 0xfc, 0xbb},
+       {0xf0, 0x00, 0x01, 0xbb},       {0x06, 0x74, 0x0e, 0xbb},
+       {0x80, 0x00, 0x06, 0xbb},       {0x81, 0x04, 0x00, 0xbb},
+       {0x82, 0x01, 0x02, 0xbb},       {0x83, 0x03, 0x02, 0xbb},
+       {0x84, 0x05, 0x00, 0xbb},       {0x85, 0x01, 0x00, 0xbb},
+       {0x86, 0x03, 0x02, 0xbb},       {0x87, 0x05, 0x00, 0xbb},
+       {0x88, 0x01, 0x00, 0xbb},       {0x89, 0x02, 0x02, 0xbb},
+       {0x8a, 0xfd, 0x04, 0xbb},       {0x8b, 0xfc, 0xfd, 0xbb},
+       {0x8c, 0xff, 0xfd, 0xbb},       {0x8d, 0x00, 0x00, 0xbb},
+       {0x8e, 0xfe, 0x05, 0xbb},       {0x8f, 0xfc, 0xfd, 0xbb},
+       {0x90, 0xfe, 0xfd, 0xbb},       {0x91, 0x00, 0x00, 0xbb},
+       {0x92, 0xfe, 0x03, 0xbb},       {0x93, 0xfd, 0xfe, 0xbb},
+       {0x94, 0xff, 0xfd, 0xbb},       {0x95, 0x00, 0x00, 0xbb},
+       {0xb6, 0x07, 0x05, 0xbb},       {0xb7, 0x13, 0x06, 0xbb},
+       {0xb8, 0x08, 0x06, 0xbb},       {0xb9, 0x14, 0x08, 0xbb},
+       {0xba, 0x06, 0x05, 0xbb},       {0xbb, 0x13, 0x06, 0xbb},
+       {0xbc, 0x03, 0x01, 0xbb},       {0xbd, 0x03, 0x04, 0xbb},
+       {0xbe, 0x00, 0x02, 0xbb},       {0xbf, 0x03, 0x01, 0xbb},
+       {0xc0, 0x02, 0x04, 0xbb},       {0xc1, 0x00, 0x04, 0xbb},
+       {0xc2, 0x02, 0x01, 0xbb},       {0xc3, 0x01, 0x03, 0xbb},
+       {0xc4, 0x00, 0x04, 0xbb},       {0xf0, 0x00, 0x02, 0xbb},
+       {0xc8, 0x00, 0x00, 0xbb},       {0x2e, 0x00, 0x00, 0xbb},
+       {0x2e, 0x0c, 0x5b, 0xbb},       {0x2f, 0xd1, 0x00, 0xbb},
+       {0x39, 0x03, 0xca, 0xbb},       {0x3a, 0x06, 0x80, 0xbb},
+       {0x3b, 0x01, 0x52, 0xbb},       {0x3c, 0x05, 0x40, 0xbb},
+       {0x57, 0x01, 0x9c, 0xbb},       {0x58, 0x01, 0xee, 0xbb},
+       {0x59, 0x00, 0xf0, 0xbb},       {0x5a, 0x01, 0x20, 0xbb},
+       {0x5c, 0x1d, 0x17, 0xbb},       {0x5d, 0x22, 0x1c, 0xbb},
+       {0x64, 0x1e, 0x1c, 0xbb},       {0x5b, 0x00, 0x01, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},       {0x36, 0x68, 0x10, 0xbb},
+       {0x00, 0x00, 0x30, 0xdd},       {0x37, 0x81, 0x00, 0xbb},
+       {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},
+       {0xbf, 0xc0, 0x26, 0xcc},       {0xbf, 0xc1, 0x02, 0xcc},
+       {0xbf, 0xcc, 0x04, 0xcc},       {0xb3, 0x5c, 0x01, 0xcc},
+       {0xb3, 0x01, 0x41, 0xcc},
+       {}
+};
+
+static const u8 mi1320_soc_InitVGA[][4] = {
+       {0xb3, 0x01, 0x01, 0xcc},
+       {0xb0, 0x03, 0x19, 0xcc},
+       {0xb0, 0x04, 0x02, 0xcc},
+       {0x00, 0x00, 0x30, 0xdd},
+       {0xb3, 0x00, 0x64, 0xcc},
+       {0xb3, 0x00, 0x67, 0xcc},
+       {0xb3, 0x05, 0x01, 0xcc},
+       {0xb3, 0x06, 0x01, 0xcc},
+       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},
+       {0xb3, 0x34, 0x02, 0xcc},
+       {0xb3, 0x35, 0xc8, 0xcc},
+       {0xb3, 0x02, 0x00, 0xcc},
+       {0xb3, 0x03, 0x0a, 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, 0x17, 0x7f, 0xcc},
+       {0xb3, 0x00, 0x67, 0xcc},
+       {0xb8, 0x00, 0x00, 0xcc},
+       {0xbc, 0x00, 0x71, 0xcc},
+       {0xbc, 0x01, 0x01, 0xcc},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x00, 0x00, 0x10, 0xdd},
+       {0xc8, 0x00, 0x00, 0xbb},
+       {0x00, 0x00, 0x30, 0xdd},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x00, 0x00, 0x10, 0xdd},
+       {0x07, 0x00, 0xe0, 0xbb},
+       {0x08, 0x00, 0x0b, 0xbb},
+       {0x21, 0x00, 0x0c, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},
+       {0xbf, 0xc0, 0x26, 0xcc},
+       {0xbf, 0xc1, 0x02, 0xcc},
+       {0xbf, 0xcc, 0x04, 0xcc},
+       {0xb3, 0x01, 0x41, 0xcc},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x05, 0x01, 0x78, 0xbb},
+       {0x06, 0x00, 0x11, 0xbb},
+       {0x07, 0x01, 0x42, 0xbb},
+       {0x08, 0x00, 0x11, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},
+       {0x21, 0x80, 0x00, 0xbb},
+       {0x22, 0x0d, 0x0f, 0xbb},
+       {0x24, 0x80, 0x00, 0xbb},
+       {0x59, 0x00, 0xff, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x39, 0x03, 0xca, 0xbb},
+       {0x3a, 0x06, 0x80, 0xbb},
+       {0x3b, 0x01, 0x52, 0xbb},
+       {0x3c, 0x05, 0x40, 0xbb},
+       {0x57, 0x01, 0x9c, 0xbb},
+       {0x58, 0x01, 0xee, 0xbb},
+       {0x59, 0x00, 0xf0, 0xbb},
+       {0x5a, 0x01, 0x20, 0xbb},
+       {0x5c, 0x1d, 0x17, 0xbb},
+       {0x5d, 0x22, 0x1c, 0xbb},
+       {0x64, 0x1e, 0x1c, 0xbb},
+       {0x5b, 0x00, 0x00, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {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},
+       {0x06, 0xe0, 0x0e, 0xbb},
+       {0x06, 0x60, 0x0e, 0xbb},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {}
+};
+static const u8 mi1320_soc_InitVGA_JPG[][4] = {
+       {0xb3, 0x01, 0x01, 0xcc},
+       {0xb0, 0x03, 0x19, 0xcc},
+       {0xb0, 0x04, 0x02, 0xcc},
+       {0x00, 0x00, 0x30, 0xdd},
+       {0xb3, 0x00, 0x64, 0xcc},
+       {0xb3, 0x00, 0x67, 0xcc},
+       {0xb3, 0x05, 0x01, 0xcc},
+       {0xb3, 0x06, 0x01, 0xcc},
+       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},
+       {0xb3, 0x34, 0x02, 0xcc},
+       {0xb3, 0x35, 0xc8, 0xcc},
+       {0xb3, 0x02, 0x00, 0xcc},
+       {0xb3, 0x03, 0x0a, 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, 0x17, 0x7f, 0xcc},
+       {0xb3, 0x00, 0x67, 0xcc},
+       {0xb8, 0x00, 0x00, 0xcc},
+       {0xbc, 0x00, 0x71, 0xcc},
+       {0xbc, 0x01, 0x01, 0xcc},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x00, 0x00, 0x10, 0xdd},
+       {0xc8, 0x00, 0x00, 0xbb},
+       {0x00, 0x00, 0x30, 0xdd},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x00, 0x00, 0x10, 0xdd},
+       {0x07, 0x00, 0xe0, 0xbb},
+       {0x08, 0x00, 0x0b, 0xbb},
+       {0x21, 0x00, 0x0c, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},
+       {0xb6, 0x00, 0x00, 0xcc},
+       {0xb6, 0x03, 0x02, 0xcc},
+       {0xb6, 0x02, 0x80, 0xcc},
+       {0xb6, 0x05, 0x01, 0xcc},
+       {0xb6, 0x04, 0xe0, 0xcc},
+       {0xb6, 0x12, 0xf8, 0xcc},
+       {0xb6, 0x13, 0x05, 0xcc},
+       {0xb6, 0x18, 0x02, 0xcc},
+       {0xb6, 0x17, 0x58, 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, 0x01, 0x41, 0xcc},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x05, 0x01, 0x78, 0xbb},
+       {0x06, 0x00, 0x11, 0xbb},
+       {0x07, 0x01, 0x42, 0xbb},
+       {0x08, 0x00, 0x11, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},
+       {0x21, 0x80, 0x00, 0xbb},
+       {0x22, 0x0d, 0x0f, 0xbb},
+       {0x24, 0x80, 0x00, 0xbb},
+       {0x59, 0x00, 0xff, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x39, 0x03, 0xca, 0xbb},
+       {0x3a, 0x06, 0x80, 0xbb},
+       {0x3b, 0x01, 0x52, 0xbb},
+       {0x3c, 0x05, 0x40, 0xbb},
+       {0x57, 0x01, 0x9c, 0xbb},
+       {0x58, 0x01, 0xee, 0xbb},
+       {0x59, 0x00, 0xf0, 0xbb},
+       {0x5a, 0x01, 0x20, 0xbb},
+       {0x5c, 0x1d, 0x17, 0xbb},
+       {0x5d, 0x22, 0x1c, 0xbb},
+       {0x64, 0x1e, 0x1c, 0xbb},
+       {0x5b, 0x00, 0x00, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {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},
+       {0x06, 0xe0, 0x0e, 0xbb},
+       {0x06, 0x60, 0x0e, 0xbb},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {}
+};
+static const u8 mi1320_soc_InitQVGA[][4] = {
+       {0xb3, 0x01, 0x01, 0xcc},
+       {0xb0, 0x03, 0x19, 0xcc},
+       {0xb0, 0x04, 0x02, 0xcc},
+       {0x00, 0x00, 0x30, 0xdd},
+       {0xb3, 0x00, 0x64, 0xcc},
+       {0xb3, 0x00, 0x67, 0xcc},
+       {0xb3, 0x05, 0x01, 0xcc},
+       {0xb3, 0x06, 0x01, 0xcc},
+       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},
+       {0xb3, 0x34, 0x02, 0xcc},
+       {0xb3, 0x35, 0xc8, 0xcc},
+       {0xb3, 0x02, 0x00, 0xcc},
+       {0xb3, 0x03, 0x0a, 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, 0x17, 0x7f, 0xcc},
+       {0xb3, 0x00, 0x67, 0xcc},
+       {0xb8, 0x00, 0x00, 0xcc},
+       {0xbc, 0x00, 0xd1, 0xcc},
+       {0xbc, 0x01, 0x01, 0xcc},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x00, 0x00, 0x10, 0xdd},
+       {0xc8, 0x00, 0x00, 0xbb},
+       {0x00, 0x00, 0x30, 0xdd},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x00, 0x00, 0x10, 0xdd},
+       {0x07, 0x00, 0xe0, 0xbb},
+       {0x08, 0x00, 0x0b, 0xbb},
+       {0x21, 0x00, 0x0c, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},
+       {0xbf, 0xc0, 0x26, 0xcc},
+       {0xbf, 0xc1, 0x02, 0xcc},
+       {0xbf, 0xcc, 0x04, 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},
+       {0xb3, 0x01, 0x41, 0xcc},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x05, 0x01, 0x78, 0xbb},
+       {0x06, 0x00, 0x11, 0xbb},
+       {0x07, 0x01, 0x42, 0xbb},
+       {0x08, 0x00, 0x11, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},
+       {0x21, 0x80, 0x00, 0xbb},
+       {0x22, 0x0d, 0x0f, 0xbb},
+       {0x24, 0x80, 0x00, 0xbb},
+       {0x59, 0x00, 0xff, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x39, 0x03, 0xca, 0xbb},
+       {0x3a, 0x06, 0x80, 0xbb},
+       {0x3b, 0x01, 0x52, 0xbb},
+       {0x3c, 0x05, 0x40, 0xbb},
+       {0x57, 0x01, 0x9c, 0xbb},
+       {0x58, 0x01, 0xee, 0xbb},
+       {0x59, 0x00, 0xf0, 0xbb},
+       {0x5a, 0x01, 0x20, 0xbb},
+       {0x5c, 0x1d, 0x17, 0xbb},
+       {0x5d, 0x22, 0x1c, 0xbb},
+       {0x64, 0x1e, 0x1c, 0xbb},
+       {0x5b, 0x00, 0x00, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {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},
+       {0x06, 0xe0, 0x0e, 0xbb},
+       {0x06, 0x60, 0x0e, 0xbb},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {}
+};
+static const u8 mi1320_soc_InitQVGA_JPG[][4] = {
+       {0xb3, 0x01, 0x01, 0xcc},
+       {0xb0, 0x03, 0x19, 0xcc},
+       {0xb0, 0x04, 0x02, 0xcc},
+       {0x00, 0x00, 0x30, 0xdd},
+       {0xb3, 0x00, 0x64, 0xcc},
+       {0xb3, 0x00, 0x67, 0xcc},
+       {0xb3, 0x05, 0x01, 0xcc},
+       {0xb3, 0x06, 0x01, 0xcc},
+       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},
+       {0xb3, 0x34, 0x02, 0xcc},
+       {0xb3, 0x35, 0xc8, 0xcc},
+       {0xb3, 0x02, 0x00, 0xcc},
+       {0xb3, 0x03, 0x0a, 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, 0x17, 0x7f, 0xcc},
+       {0xb3, 0x00, 0x67, 0xcc},
+       {0xb8, 0x00, 0x00, 0xcc},
+       {0xbc, 0x00, 0xd1, 0xcc},
+       {0xbc, 0x01, 0x01, 0xcc},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x00, 0x00, 0x10, 0xdd},
+       {0xc8, 0x00, 0x00, 0xbb},
+       {0x00, 0x00, 0x30, 0xdd},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x00, 0x00, 0x10, 0xdd},
+       {0x07, 0x00, 0xe0, 0xbb},
+       {0x08, 0x00, 0x0b, 0xbb},
+       {0x21, 0x00, 0x0c, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},
+       {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, 0x05, 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},
+       {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},
+       {0xb3, 0x01, 0x41, 0xcc},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x05, 0x01, 0x78, 0xbb},
+       {0x06, 0x00, 0x11, 0xbb},
+       {0x07, 0x01, 0x42, 0xbb},
+       {0x08, 0x00, 0x11, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},
+       {0x21, 0x80, 0x00, 0xbb},
+       {0x22, 0x0d, 0x0f, 0xbb},
+       {0x24, 0x80, 0x00, 0xbb},
+       {0x59, 0x00, 0xff, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x39, 0x03, 0xca, 0xbb},
+       {0x3a, 0x06, 0x80, 0xbb},
+       {0x3b, 0x01, 0x52, 0xbb},
+       {0x3c, 0x05, 0x40, 0xbb},
+       {0x57, 0x01, 0x9c, 0xbb},
+       {0x58, 0x01, 0xee, 0xbb},
+       {0x59, 0x00, 0xf0, 0xbb},
+       {0x5a, 0x01, 0x20, 0xbb},
+       {0x5c, 0x1d, 0x17, 0xbb},
+       {0x5d, 0x22, 0x1c, 0xbb},
+       {0x64, 0x1e, 0x1c, 0xbb},
+       {0x5b, 0x00, 0x00, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {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},
+       {0x06, 0xe0, 0x0e, 0xbb},
+       {0x06, 0x60, 0x0e, 0xbb},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {}
+};
+static const u8 mi1320_soc_InitSXGA_JPG[][4] = {
+       {0xb3, 0x01, 0x01, 0xcc},
+       {0xb0, 0x03, 0x19, 0xcc},
+       {0xb0, 0x04, 0x02, 0xcc},
+       {0x00, 0x00, 0x33, 0xdd},
+       {0xb3, 0x00, 0x64, 0xcc},
+       {0xb3, 0x00, 0x67, 0xcc},
+       {0xb3, 0x05, 0x00, 0xcc},
+       {0xb3, 0x06, 0x00, 0xcc},
+       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},
+       {0xb3, 0x34, 0x02, 0xcc},
+       {0xb3, 0x35, 0xc8, 0xcc},
+       {0xb3, 0x02, 0x00, 0xcc},
+       {0xb3, 0x03, 0x0a, 0xcc},
+       {0xb3, 0x04, 0x05, 0xcc},
+       {0xb3, 0x20, 0x00, 0xcc},
+       {0xb3, 0x21, 0x00, 0xcc},
+       {0xb3, 0x22, 0x04, 0xcc},
+       {0xb3, 0x23, 0x00, 0xcc},
+       {0xb3, 0x14, 0x00, 0xcc},
+       {0xb3, 0x15, 0x00, 0xcc},
+       {0xb3, 0x16, 0x04, 0xcc},
+       {0xb3, 0x17, 0xff, 0xcc},
+       {0xb3, 0x00, 0x67, 0xcc},
+       {0xbc, 0x00, 0x71, 0xcc},
+       {0xbc, 0x01, 0x01, 0xcc},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x00, 0x00, 0x30, 0xdd},
+       {0xc8, 0x9f, 0x0b, 0xbb},
+       {0x00, 0x00, 0x20, 0xdd},
+       {0x5b, 0x00, 0x01, 0xbb},
+       {0x00, 0x00, 0x20, 0xdd},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x00, 0x00, 0x30, 0xdd},
+       {0x20, 0x01, 0x03, 0xbb},
+       {0x00, 0x00, 0x20, 0xdd},
+       {0xb6, 0x00, 0x00, 0xcc},
+       {0xb6, 0x03, 0x05, 0xcc},
+       {0xb6, 0x02, 0x00, 0xcc},
+       {0xb6, 0x05, 0x04, 0xcc},
+       {0xb6, 0x04, 0x00, 0xcc},
+       {0xb6, 0x12, 0xf8, 0xcc},
+       {0xb6, 0x13, 0x29, 0xcc},
+       {0xb6, 0x18, 0x0a, 0xcc},
+       {0xb6, 0x17, 0x00, 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},
        {0xb3, 0x01, 0x41, 0xcc},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x05, 0x01, 0x78, 0xbb},
+       {0x06, 0x00, 0x11, 0xbb},
+       {0x07, 0x01, 0x42, 0xbb},
+       {0x08, 0x00, 0x11, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},
+       {0x21, 0x80, 0x00, 0xbb},
+       {0x22, 0x0d, 0x0f, 0xbb},
+       {0x24, 0x80, 0x00, 0xbb},
+       {0x59, 0x00, 0xff, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x39, 0x03, 0xca, 0xbb},
+       {0x3a, 0x06, 0x80, 0xbb},
+       {0x3b, 0x01, 0x52, 0xbb},
+       {0x3c, 0x05, 0x40, 0xbb},
+       {0x57, 0x01, 0x9c, 0xbb},
+       {0x58, 0x01, 0xee, 0xbb},
+       {0x59, 0x00, 0xf0, 0xbb},
+       {0x5a, 0x01, 0x20, 0xbb},
+       {0x5c, 0x1d, 0x17, 0xbb},
+       {0x5d, 0x22, 0x1c, 0xbb},
+       {0x64, 0x1e, 0x1c, 0xbb},
+       {0x5b, 0x00, 0x00, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {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},
+       {0x06, 0xe0, 0x0e, 0xbb},
+       {0x06, 0x60, 0x0e, 0xbb},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x05, 0x01, 0x13, 0xbb},
+       {0x06, 0x00, 0x11, 0xbb},
+       {0x07, 0x00, 0x85, 0xbb},
+       {0x08, 0x00, 0x27, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},
+       {0x21, 0x80, 0x00, 0xbb},
+       {0x22, 0x0d, 0x0f, 0xbb},
+       {0x24, 0x80, 0x00, 0xbb},
+       {0x59, 0x00, 0xff, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x39, 0x03, 0x0d, 0xbb},
+       {0x3a, 0x06, 0x1b, 0xbb},
+       {0x3b, 0x00, 0x95, 0xbb},
+       {0x3c, 0x04, 0xdb, 0xbb},
+       {0x57, 0x02, 0x00, 0xbb},
+       {0x58, 0x02, 0x66, 0xbb},
+       {0x59, 0x00, 0xff, 0xbb},
+       {0x5a, 0x01, 0x33, 0xbb},
+       {0x5c, 0x12, 0x0d, 0xbb},
+       {0x5d, 0x16, 0x11, 0xbb},
+       {0x64, 0x5e, 0x1c, 0xbb},
+       {0x2f, 0x90, 0x00, 0xbb},
+       {}
+};
+static const u8 mi1320_soc_InitSXGA[][4] = {
+       {0xb3, 0x01, 0x01, 0xcc},
+       {0xb0, 0x03, 0x19, 0xcc},
+       {0x00, 0x00, 0x30, 0xdd},
+       {0xb3, 0x00, 0x64, 0xcc},
+       {0xb3, 0x00, 0x67, 0xcc},
+       {0xb3, 0x05, 0x01, 0xcc},
+       {0xb3, 0x06, 0x01, 0xcc},
+       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},
+       {0xb3, 0x34, 0x02, 0xcc},
+       {0xb3, 0x35, 0xc8, 0xcc},
+       {0xb3, 0x02, 0x00, 0xcc},
+       {0xb3, 0x03, 0x0a, 0xcc},
+       {0xb3, 0x04, 0x05, 0xcc},
+       {0xb3, 0x20, 0x00, 0xcc},
+       {0xb3, 0x21, 0x00, 0xcc},
+       {0xb3, 0x22, 0x04, 0xcc},
+       {0xb3, 0x23, 0x00, 0xcc},
+       {0xb3, 0x14, 0x00, 0xcc},
+       {0xb3, 0x15, 0x00, 0xcc},
+       {0xb3, 0x16, 0x04, 0xcc},
+       {0xb3, 0x17, 0xff, 0xcc},
+       {0xb3, 0x00, 0x67, 0xcc},
+       {0xbc, 0x00, 0x71, 0xcc},
+       {0xbc, 0x01, 0x01, 0xcc},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x00, 0x00, 0x30, 0xdd},
+       {0xc8, 0x9f, 0x0b, 0xbb},
+       {0x00, 0x00, 0x20, 0xdd},
+       {0x5b, 0x00, 0x01, 0xbb},
+       {0x00, 0x00, 0x20, 0xdd},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x00, 0x00, 0x30, 0xdd},
+       {0x20, 0x01, 0x03, 0xbb},
+       {0x00, 0x00, 0x20, 0xdd},
+       {0xbf, 0xc0, 0x26, 0xcc},
+       {0xbf, 0xc1, 0x02, 0xcc},
+       {0xbf, 0xcc, 0x04, 0xcc},
+       {0xb3, 0x01, 0x41, 0xcc},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x05, 0x01, 0x78, 0xbb},
+       {0x06, 0x00, 0x11, 0xbb},
+       {0x07, 0x01, 0x42, 0xbb},
+       {0x08, 0x00, 0x11, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},
+       {0x21, 0x80, 0x00, 0xbb},
+       {0x22, 0x0d, 0x0f, 0xbb},
+       {0x24, 0x80, 0x00, 0xbb},
+       {0x59, 0x00, 0xff, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x39, 0x03, 0xca, 0xbb},
+       {0x3a, 0x06, 0x80, 0xbb},
+       {0x3b, 0x01, 0x52, 0xbb},
+       {0x3c, 0x05, 0x40, 0xbb},
+       {0x57, 0x01, 0x9c, 0xbb},
+       {0x58, 0x01, 0xee, 0xbb},
+       {0x59, 0x00, 0xf0, 0xbb},
+       {0x5a, 0x01, 0x20, 0xbb},
+       {0x5c, 0x1d, 0x17, 0xbb},
+       {0x5d, 0x22, 0x1c, 0xbb},
+       {0x64, 0x1e, 0x1c, 0xbb},
+       {0x5b, 0x00, 0x00, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {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},
+       {0x06, 0xe0, 0x0e, 0xbb},
+       {0x06, 0x60, 0x0e, 0xbb},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x05, 0x01, 0x13, 0xbb},
+       {0x06, 0x00, 0x11, 0xbb},
+       {0x07, 0x00, 0x85, 0xbb},
+       {0x08, 0x00, 0x27, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},
+       {0x21, 0x80, 0x00, 0xbb},
+       {0x22, 0x0d, 0x0f, 0xbb},
+       {0x24, 0x80, 0x00, 0xbb},
+       {0x59, 0x00, 0xff, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x39, 0x03, 0x0d, 0xbb},
+       {0x3a, 0x06, 0x1b, 0xbb},
+       {0x3b, 0x00, 0x95, 0xbb},
+       {0x3c, 0x04, 0xdb, 0xbb},
+       {0x57, 0x02, 0x00, 0xbb},
+       {0x58, 0x02, 0x66, 0xbb},
+       {0x59, 0x00, 0xff, 0xbb},
+       {0x5a, 0x01, 0x33, 0xbb},
+       {0x5c, 0x12, 0x0d, 0xbb},
+       {0x5d, 0x16, 0x11, 0xbb},
+       {0x64, 0x5e, 0x1c, 0xbb},
        {}
 };
-
 static const __u8 po3130_gamma[17] = {
        0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
        0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
@@ -1764,26 +2633,43 @@ static const __u8 po1200_initVGA_data[][4] = {
 };
 
 struct sensor_info {
-       int sensorId;
-       __u8 I2cAdd;
-       __u8 IdAdd;
-       __u16 VpId;
-       __u8 m1;
-       __u8 m2;
-       __u8 op;
-       };
+       s8 sensorId;
+       u8 I2cAdd;
+       u8 IdAdd;
+       u16 VpId;
+       u8 m1;
+       u8 m2;
+       u8 op;
+};
 
 static const struct sensor_info sensor_info_data[] = {
 /*      sensorId,         I2cAdd,      IdAdd,  VpId,  m1,    m2,  op */
-       {SENSOR_HV7131R,    0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
-       {SENSOR_OV7660,     0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
+       {-1,                0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05},
+       {-1,                0x80 | 0x20, 0x82, 0x0000, 0x24, 0x25, 0x01},
+/* (tested in vc032x_probe_sensor) */
+/*     {-1,                0x80 | 0x20, 0x83, 0x0000, 0x24, 0x25, 0x01}, */
        {SENSOR_PO3130NC,   0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01},
-       {SENSOR_MI1320,     0x80 | 0xc8, 0x00, 0x148c, 0x64, 0x65, 0x01},
-       {SENSOR_OV7670,     0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
        {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
 /* (tested in vc032x_probe_sensor) */
 /*     {SENSOR_MI0360,     0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */
+       {SENSOR_HV7131R,    0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
+       {-1,                0x80 | 0x21, 0x0a, 0x0000, 0x21, 0x20, 0x05},
+       {-1,                0x80 | 0x40, 0x00, 0x0000, 0x20, 0x22, 0x05},
+       {SENSOR_OV7660,     0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
+/*     {SENSOR_PO3130NC,   0x80 | 0x76, 0x00, 0x0000, 0x24, 0x25, 0x01}, */
+       {-1,                0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/*     {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x0000, 0x24, 0x25, 0x01}, */
+/*     {-1,                0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05}, */
+       {-1,                0x80 | 0x11, 0x39, 0x0000, 0x24, 0x25, 0x01},
        {SENSOR_PO1200,     0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01},
+       {-1,                0x80 | 0x2d, 0x00, 0x0000, 0x65, 0x67, 0x01},
+       {-1,                0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
+       {-1,                0x80 | 0x56, 0x01, 0x0000, 0x64, 0x67, 0x01},
+       {SENSOR_MI1320_SOC, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x67, 0x01},
+/*fixme: previously detected?*/
+       {SENSOR_MI1320,     0x80 | 0x48, 0x00, 0x148c, 0x64, 0x65, 0x01},
+/*fixme: not in the ms-win probe - may be found before?*/
+       {SENSOR_OV7670,     0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
 };
 
 /* read 'len' bytes in gspca_dev->usb_buf */
@@ -1814,51 +2700,49 @@ static void reg_w(struct usb_device *dev,
                        500);
 }
 
-static void read_sensor_register(struct gspca_dev *gspca_dev,
-                               __u16 address, __u16 *value)
+static u16 read_sensor_register(struct gspca_dev *gspca_dev,
+                               u16 address)
 {
        struct usb_device *dev = gspca_dev->dev;
-       __u8 ldata, mdata, hdata;
+       u8 ldata, mdata, hdata;
        int retry = 50;
 
-       *value = 0;
-
        reg_r(gspca_dev, 0xa1, 0xb33f, 1);
-       /*PDEBUG(D_PROBE, " I2c Bus Busy Wait  0x%02X ", tmpvalue); */
        if (!(gspca_dev->usb_buf[0] & 0x02)) {
-               PDEBUG(D_ERR, "I2c Bus Busy Wait %d",
-                       gspca_dev->usb_buf[0] & 0x02);
-               return;
+               PDEBUG(D_ERR, "I2c Bus Busy Wait %02x",
+                       gspca_dev->usb_buf[0]);
+               return 0;
        }
        reg_w(dev, 0xa0, address, 0xb33a);
        reg_w(dev, 0xa0, 0x02, 0xb339);
 
-       reg_r(gspca_dev, 0xa1, 0xb33b, 1);
-       while (retry-- && gspca_dev->usb_buf[0]) {
+       do {
                reg_r(gspca_dev, 0xa1, 0xb33b, 1);
-/*             PDEBUG(D_PROBE, "Read again 0xb33b %d", tmpvalue); */
-               msleep(1);
-       }
+               if (gspca_dev->usb_buf[0] == 0x00)
+                       break;
+               msleep(40);
+       } while (--retry >= 0);
+
        reg_r(gspca_dev, 0xa1, 0xb33e, 1);
        ldata = gspca_dev->usb_buf[0];
        reg_r(gspca_dev, 0xa1, 0xb33d, 1);
        mdata = gspca_dev->usb_buf[0];
        reg_r(gspca_dev, 0xa1, 0xb33c, 1);
        hdata = gspca_dev->usb_buf[0];
-       PDEBUG(D_PROBE, "Read Sensor %02x%02x %02x",
-               hdata, mdata, ldata);
+       if (hdata != 0 && mdata != 0 && ldata != 0)
+               PDEBUG(D_PROBE, "Read Sensor %02x%02x %02x",
+                       hdata, mdata, ldata);
        reg_r(gspca_dev, 0xa1, 0xb334, 1);
        if (gspca_dev->usb_buf[0] == 0x02)
-               *value = (hdata << 8) + mdata;
-       else
-               *value = hdata;
+               return (hdata << 8) + mdata;
+       return hdata;
 }
 
 static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
 {
        struct usb_device *dev = gspca_dev->dev;
        int i;
-       __u16 value;
+       u16 value;
        const struct sensor_info *ptsensor_info;
 
        reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
@@ -1872,48 +2756,51 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
                reg_w(dev, 0xa0, 0x0c, 0xb309);
                reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
                reg_w(dev, 0xa0, ptsensor_info->op, 0xb301);
-               read_sensor_register(gspca_dev, ptsensor_info->IdAdd, &value);
-               if (value == ptsensor_info->VpId)
-                       return ptsensor_info->sensorId;
-
-               /* special case for MI0360 */
-               if (ptsensor_info->sensorId == SENSOR_MI1310_SOC
-                   && value == 0x8243)
-                       return SENSOR_MI0360;
+               value = read_sensor_register(gspca_dev, ptsensor_info->IdAdd);
+               if (value == 0 && ptsensor_info->IdAdd == 0x82)
+                       value = read_sensor_register(gspca_dev, 0x83);
+               if (value != 0) {
+                       PDEBUG(D_ERR|D_PROBE, "Sensor ID %04x (%d)",
+                               value, i);
+                       if (value == ptsensor_info->VpId)
+                               return ptsensor_info->sensorId;
+
+                       switch (value) {
+                       case 0x7673:
+                               return SENSOR_OV7670;
+                       case 0x8243:
+                               return SENSOR_MI0360;
+                       }
+/*fixme: should return here*/
+               }
        }
        return -1;
 }
 
-static __u8 i2c_write(struct gspca_dev *gspca_dev,
-                       __u8 reg, const __u8 *val, __u8 size)
+static void i2c_write(struct gspca_dev *gspca_dev,
+                       u8 reg, const u8 *val,
+                       u8 size)                /* 1 or 2 */
 {
        struct usb_device *dev = gspca_dev->dev;
+       int retry;
 
-       if (size > 3 || size < 1)
-               return -EINVAL;
        reg_r(gspca_dev, 0xa1, 0xb33f, 1);
+/*fixme:should check if (!(gspca_dev->usb_buf[0] & 0x02)) error*/
        reg_w(dev, 0xa0, size, 0xb334);
        reg_w(dev, 0xa0, reg, 0xb33a);
-       switch (size) {
-       case 1:
-               reg_w(dev, 0xa0, val[0], 0xb336);
-               break;
-       case 2:
-               reg_w(dev, 0xa0, val[0], 0xb336);
+       reg_w(dev, 0xa0, val[0], 0xb336);
+       if (size > 1)
                reg_w(dev, 0xa0, val[1], 0xb337);
-               break;
-       case 3:
-               reg_w(dev, 0xa0, val[0], 0xb336);
-               reg_w(dev, 0xa0, val[1], 0xb337);
-               reg_w(dev, 0xa0, val[2], 0xb338);
-               break;
-       default:
-               reg_w(dev, 0xa0, 0x01, 0xb334);
-               return -EINVAL;
-       }
        reg_w(dev, 0xa0, 0x01, 0xb339);
-       reg_r(gspca_dev, 0xa1, 0xb33b, 1);
-       return gspca_dev->usb_buf[0] == 0;
+       retry = 4;
+       do {
+               reg_r(gspca_dev, 0xa1, 0xb33b, 1);
+               if (gspca_dev->usb_buf[0] == 0)
+                       break;
+               msleep(20);
+       } while (--retry > 0);
+       if (retry <= 0)
+               PDEBUG(D_ERR, "i2c_write failed");
 }
 
 static void put_tab_to_reg(struct gspca_dev *gspca_dev,
@@ -1938,7 +2825,7 @@ static void usb_exchange(struct gspca_dev *gspca_dev,
                        return;
                case 0xcc:                      /* normal write */
                        reg_w(dev, 0xa0, data[i][2],
-                                       ((data[i][0])<<8) | data[i][1]);
+                                       (data[i][0]) << 8 | data[i][1]);
                        break;
                case 0xaa:                      /* i2c op */
                        i2c_write(gspca_dev, data[i][1], &data[i][2], 1);
@@ -1955,19 +2842,6 @@ static void usb_exchange(struct gspca_dev *gspca_dev,
        /*not reached*/
 }
 
-/*
- "GammaT"=hex:04,17,31,4f,6a,83,99,ad,bf,ce,da,e5,ee,f5,fb,ff,ff
- "MatrixT"=hex:60,f9,e5,e7,50,05,f3,e6,66
- */
-
-static void vc0321_reset(struct gspca_dev *gspca_dev)
-{
-       reg_w(gspca_dev->dev, 0xa0, 0x00, 0xb04d);
-       reg_w(gspca_dev->dev, 0xa0, 0x01, 0xb301);
-       msleep(100);
-       reg_w(gspca_dev->dev, 0xa0, 0x01, 0xb003);
-       msleep(100);
-}
 
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
@@ -1979,10 +2853,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        int sensor;
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 0x02;
        sd->bridge = id->driver_info;
-
-       vc0321_reset(gspca_dev);
        sensor = vc032x_probe_sensor(gspca_dev);
        switch (sensor) {
        case -1:
@@ -2001,6 +2872,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
        case SENSOR_MI1320:
                PDEBUG(D_PROBE, "Find Sensor MI1320");
                break;
+       case SENSOR_MI1320_SOC:
+               PDEBUG(D_PROBE, "Find Sensor MI1320_SOC");
+               break;
        case SENSOR_OV7660:
                PDEBUG(D_PROBE, "Find Sensor OV7660");
                break;
@@ -2020,12 +2894,23 @@ static int sd_config(struct gspca_dev *gspca_dev,
                cam->cam_mode = vc0321_mode;
                cam->nmodes = ARRAY_SIZE(vc0321_mode);
        } else {
-               if (sensor != SENSOR_PO1200) {
-                       cam->cam_mode = vc0323_mode;
-                       cam->nmodes = ARRAY_SIZE(vc0323_mode);
-               } else {
+               switch (sensor) {
+               case SENSOR_PO1200:
                        cam->cam_mode = svga_mode;
                        cam->nmodes = ARRAY_SIZE(svga_mode);
+                       break;
+               case SENSOR_MI1310_SOC:
+                       cam->cam_mode = vc0323_mode;
+                       cam->nmodes = ARRAY_SIZE(vc0323_mode);
+                       break;
+               case SENSOR_MI1320_SOC:
+                       cam->cam_mode = bi_mode;
+                       cam->nmodes = ARRAY_SIZE(bi_mode);
+                       break;
+               default:
+                       cam->cam_mode = vc0323_mode;
+                       cam->nmodes = ARRAY_SIZE(vc0323_mode) - 1;
+                       break;
                }
        }
 
@@ -2061,7 +2946,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        return 0;
 }
 
-/* this function is called at probe and time */
+/* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
        return 0;
@@ -2124,9 +3009,18 @@ 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;
        int mode;
+       static const u8 (*mi1320_soc_init[])[4] = {
+               mi1320_soc_InitSXGA,
+               mi1320_soc_InitSXGA_JPG,
+               mi1320_soc_InitVGA,
+               mi1320_soc_InitVGA_JPG,
+               mi1320_soc_InitQVGA,
+               mi1320_soc_InitQVGA_JPG
+       };
 
        /* Assume start use the good resolution from gspca_dev->mode */
        if (sd->bridge == BRIDGE_VC0321) {
@@ -2134,6 +3028,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfed);
                reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfee);
                reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfef);
+               sd->image_offset = 46;
+       } else {
+               if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].pixelformat
+                               == V4L2_PIX_FMT_JPEG)
+                       sd->image_offset = 0;
+               else
+                       sd->image_offset = 32;
        }
 
        mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
@@ -2141,115 +3042,87 @@ static int sd_start(struct gspca_dev *gspca_dev)
        case SENSOR_HV7131R:
                GammaT = hv7131r_gamma;
                MatrixT = hv7131r_matrix;
-               if (mode) {
-                       /* 320x240 */
-                       usb_exchange(gspca_dev, hv7131r_initQVGA_data);
-               } else {
-                       /* 640x480 */
-                       usb_exchange(gspca_dev, hv7131r_initVGA_data);
-               }
+               if (mode)
+                       init = hv7131r_initQVGA_data;   /* 320x240 */
+               else
+                       init = hv7131r_initVGA_data;    /* 640x480 */
                break;
        case SENSOR_OV7660:
                GammaT = ov7660_gamma;
                MatrixT = ov7660_matrix;
-               if (mode) {
-                       /* 320x240 */
-                       usb_exchange(gspca_dev, ov7660_initQVGA_data);
-               } else {
-                       /* 640x480 */
-                       usb_exchange(gspca_dev, ov7660_initVGA_data);
-               }
+               if (mode)
+                       init = ov7660_initQVGA_data;    /* 320x240 */
+               else
+                       init = ov7660_initVGA_data;     /* 640x480 */
                break;
        case SENSOR_OV7670:
                /*GammaT = ov7660_gamma; */
                /*MatrixT = ov7660_matrix; */
-               if (mode) {
-                       /* 320x240 */
-                       usb_exchange(gspca_dev, ov7670_initQVGA_JPG);
-               } else {
-                       /* 640x480 */
-                       usb_exchange(gspca_dev, ov7670_initVGA_JPG);
-               }
+               if (mode)
+                       init = ov7670_initQVGA_JPG;     /* 320x240 */
+               else
+                       init = ov7670_initVGA_JPG;      /* 640x480 */
                break;
        case SENSOR_MI0360:
                GammaT = mi1320_gamma;
                MatrixT = mi0360_matrix;
-               if (mode) {
-                       /* 320x240 */
-                       usb_exchange(gspca_dev, mi0360_initQVGA_JPG);
-               } else {
-                       /* 640x480 */
-                       usb_exchange(gspca_dev, mi0360_initVGA_JPG);
-               }
+               if (mode)
+                       init = mi0360_initQVGA_JPG;     /* 320x240 */
+               else
+                       init = mi0360_initVGA_JPG;      /* 640x480 */
                break;
        case SENSOR_MI1310_SOC:
-               if (mode) {
-                       /* 320x240 */
-                       usb_exchange(gspca_dev, mi1310_socinitQVGA_JPG);
-               } else {
-                       /* 640x480 */
-                       usb_exchange(gspca_dev, mi1310_socinitVGA_JPG);
+               GammaT = mi1320_gamma;
+               MatrixT = mi1320_matrix;
+               switch (mode) {
+               case 1:
+                       init = mi1310_socinitQVGA_JPG;  /* 320x240 */
+                       break;
+               case 0:
+                       init = mi1310_socinitVGA_JPG;   /* 640x480 */
+                       break;
+               default:
+                       init = mi1310_soc_InitSXGA_JPG; /* 1280x1024 */
+                       break;
                }
                break;
        case SENSOR_MI1320:
                GammaT = mi1320_gamma;
                MatrixT = mi1320_matrix;
-               if (mode) {
-                       /* 320x240 */
-                       usb_exchange(gspca_dev, mi1320_initQVGA_data);
-               } else {
-                       /* 640x480 */
-                       usb_exchange(gspca_dev, mi1320_initVGA_data);
-               }
+               if (mode)
+                       init = mi1320_initQVGA_data;    /* 320x240 */
+               else
+                       init = mi1320_initVGA_data;     /* 640x480 */
+               break;
+       case SENSOR_MI1320_SOC:
+               GammaT = mi1320_gamma;
+               MatrixT = mi1320_matrix;
+               init = mi1320_soc_init[mode];
                break;
        case SENSOR_PO3130NC:
                GammaT = po3130_gamma;
                MatrixT = po3130_matrix;
-               if (mode) {
-                       /* 320x240 */
-                       usb_exchange(gspca_dev, po3130_initQVGA_data);
-               } else {
-                       /* 640x480 */
-                       usb_exchange(gspca_dev, po3130_initVGA_data);
-               }
-               usb_exchange(gspca_dev, po3130_rundata);
+               if (mode)
+                       init = po3130_initQVGA_data;    /* 320x240 */
+               else
+                       init = po3130_initVGA_data;     /* 640x480 */
+               usb_exchange(gspca_dev, init);
+               init = po3130_rundata;
                break;
-       case SENSOR_PO1200:
+       default:
+/*     case SENSOR_PO1200: */
                GammaT = po1200_gamma;
                MatrixT = po1200_matrix;
-               usb_exchange(gspca_dev, po1200_initVGA_data);
+               init = po1200_initVGA_data;
                break;
-       default:
-               PDEBUG(D_PROBE, "Damned !! no sensor found Bye");
-               return -EMEDIUMTYPE;
        }
+       usb_exchange(gspca_dev, init);
        if (GammaT && MatrixT) {
                put_tab_to_reg(gspca_dev, GammaT, 17, 0xb84a);
                put_tab_to_reg(gspca_dev, GammaT, 17, 0xb85b);
                put_tab_to_reg(gspca_dev, GammaT, 17, 0xb86c);
                put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c);
 
-               /* Seem SHARPNESS */
-               /*
-               reg_w(gspca_dev->dev, 0xa0, 0x80, 0xb80a);
-               reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb80b);
-               reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb80e);
-               */
-               /* all 0x40 ??? do nothing
-               reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb822);
-               reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb823);
-               reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb824);
-               */
-               /* Only works for HV7131R ??
-               reg_r (gspca_dev, 0xa1, 0xb881, 1);
-               reg_w(gspca_dev->dev, 0xa0, 0xfe01, 0xb881);
-               reg_w(gspca_dev->dev, 0xa0, 0x79, 0xb801);
-               */
-               /* only hv7131r et ov7660
-               reg_w(gspca_dev->dev, 0xa0, 0x20, 0xb827);
-               reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb826); * ISP_GAIN 80
-               reg_w(gspca_dev->dev, 0xa0, 0x23, 0xb800); * ISP CTRL_BAS
-               */
                /* set the led on 0x0892 0x0896 */
                if (sd->sensor != SENSOR_PO1200) {
                        reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
@@ -2296,12 +3169,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        "vc032x header packet found len %d", len);
                frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
                                                data, 0);
-               if (sd->bridge == BRIDGE_VC0321) {
-#define VCHDRSZ 46
-                       data += VCHDRSZ;
-                       len -= VCHDRSZ;
-#undef VCHDRSZ
-               }
+               data += sd->image_offset;
+               len -= sd->image_offset;
                gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
                                data, len);
                return;
@@ -2399,7 +3268,8 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
                case 1:         /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
                        strcpy((char *) menu->name, "50 Hz");
                        return 0;
-               case 2:         /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+               default:
+/*             case 2:          * V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
                        strcpy((char *) menu->name, "60 Hz");
                        return 0;
                }
@@ -2424,6 +3294,7 @@ static const struct sd_desc sd_desc = {
 
 /* -- module initialisation -- */
 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},
@@ -2432,6 +3303,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {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},
        {}
@@ -2460,8 +3332,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index ec2a53d53fe269c3886a0ad3bad92a693777f36a..4fe01d8b6c87e542d6e4655d55c4ab4567fc369f 100644 (file)
@@ -23,6 +23,7 @@
 #define MODULE_NAME "zc3xx"
 
 #include "gspca.h"
+#include "jpeg.h"
 
 MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>, "
                "Serge A. Suchkov <Serge.A.S@tochka.ru>");
@@ -31,7 +32,7 @@ MODULE_LICENSE("GPL");
 
 static int force_sensor = -1;
 
-#include "jpeg.h"
+#define QUANT_VAL 1            /* quantization table */
 #include "zc3xx-reg.h"
 
 /* specific webcam descriptor */
@@ -44,30 +45,36 @@ struct sd {
        __u8 autogain;
        __u8 lightfreq;
        __u8 sharpness;
+       u8 quality;                     /* image quality */
+#define QUALITY_MIN 40
+#define QUALITY_MAX 60
+#define QUALITY_DEF 50
 
-       char qindex;
        signed char sensor;             /* Type of image sensor chip */
 /* !! values used in different tables */
-#define SENSOR_CS2102 0
-#define SENSOR_CS2102K 1
-#define SENSOR_GC0305 2
-#define SENSOR_HDCS2020b 3
-#define SENSOR_HV7131B 4
-#define SENSOR_HV7131C 5
-#define SENSOR_ICM105A 6
-#define SENSOR_MC501CB 7
-#define SENSOR_OV7620 8
-/*#define SENSOR_OV7648 8 - same values */
-#define SENSOR_OV7630C 9
-#define SENSOR_PAS106 10
-#define SENSOR_PAS202B 11
-#define SENSOR_PB0330 12
-#define SENSOR_PO2030 13
-#define SENSOR_TAS5130CK 14
-#define SENSOR_TAS5130CXX 15
-#define SENSOR_TAS5130C_VF0250 16
-#define SENSOR_MAX 17
+#define SENSOR_ADCM2700 0
+#define SENSOR_CS2102 1
+#define SENSOR_CS2102K 2
+#define SENSOR_GC0305 3
+#define SENSOR_HDCS2020b 4
+#define SENSOR_HV7131B 5
+#define SENSOR_HV7131C 6
+#define SENSOR_ICM105A 7
+#define SENSOR_MC501CB 8
+#define SENSOR_OV7620 9
+/*#define SENSOR_OV7648 9 - same values */
+#define SENSOR_OV7630C 10
+#define SENSOR_PAS106 11
+#define SENSOR_PAS202B 12
+#define SENSOR_PB0330 13
+#define SENSOR_PO2030 14
+#define SENSOR_TAS5130CK 15
+#define SENSOR_TAS5130CXX 16
+#define SENSOR_TAS5130C_VF0250 17
+#define SENSOR_MAX 18
        unsigned short chip_revision;
+
+       u8 *jpeg_hdr;
 };
 
 /* V4L2 controls supported by the driver */
@@ -206,6 +213,213 @@ struct usb_action {
        __u16   idx;
 };
 
+static const struct usb_action adcm2700_Initial[] = {
+       {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},         /* 00,00,01,cc */
+       {0xa0, 0x04, ZC3XX_R002_CLOCKSELECT},           /* 00,02,04,cc */
+       {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING},          /* 00,08,03,cc */
+       {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0a,cc */
+       {0xa0, 0xd3, ZC3XX_R08B_I2CDEVICEADDR},         /* 00,8b,d3,cc */
+       {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},        /* 00,03,02,cc */
+       {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},         /* 00,04,80,cc */
+       {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},       /* 00,05,01,cc */
+       {0xa0, 0xd8, ZC3XX_R006_FRAMEHEIGHTLOW},        /* 00,06,d8,cc */
+       {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},       /* 00,01,01,cc */
+       {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},      /* 00,12,03,cc */
+       {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},      /* 00,12,01,cc */
+       {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},      /* 00,12,05,cc */
+       {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},          /* 00,98,00,cc */
+       {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},          /* 00,9a,00,cc */
+       {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},             /* 01,1a,00,cc */
+       {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},             /* 01,1c,00,cc */
+       {0xa0, 0xde, ZC3XX_R09C_WINHEIGHTLOW},          /* 00,9c,de,cc */
+       {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW},           /* 00,9e,86,cc */
+       {0xbb, 0x00, 0x0400},                           /* 04,00,00,bb */
+       {0xdd, 0x00, 0x0010},                           /* 00,00,10,dd */
+       {0xbb, 0x0f, 0x140f},                           /* 14,0f,0f,bb */
+       {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},      /* 01,01,37,cc */
+       {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},         /* 01,00,0d,cc */
+       {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},             /* 01,89,06,cc */
+       {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},         /* 01,c5,03,cc */
+       {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},           /* 01,cb,13,cc */
+       {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},        /* 02,50,08,cc */
+       {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},          /* 03,01,08,cc */
+       {0xa0, 0x58, ZC3XX_R116_RGAIN},                 /* 01,16,58,cc */
+       {0xa0, 0x5a, ZC3XX_R118_BGAIN},                 /* 01,18,5a,cc */
+       {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},     /* 01,80,02,cc */
+       {0xa0, 0xd3, ZC3XX_R08B_I2CDEVICEADDR},         /* 00,8b,d3,cc */
+       {0xbb, 0x00, 0x0408},                           /* 04,00,08,bb */
+       {0xdd, 0x00, 0x0200},                           /* 00,02,00,dd */
+       {0xbb, 0x00, 0x0400},                           /* 04,00,00,bb */
+       {0xdd, 0x00, 0x0010},                           /* 00,00,10,dd */
+       {0xbb, 0x0f, 0x140f},                           /* 14,0f,0f,bb */
+       {0xbb, 0xe0, 0x0c2e},                           /* 0c,e0,2e,bb */
+       {0xbb, 0x01, 0x2000},                           /* 20,01,00,bb */
+       {0xbb, 0x96, 0x2400},                           /* 24,96,00,bb */
+       {0xbb, 0x06, 0x1006},                           /* 10,06,06,bb */
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xdd, 0x00, 0x0010},                           /* 00,00,10,dd */
+       {0xaa, 0xfe, 0x0002},                           /* 00,fe,02,aa */
+       {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0a,cc */
+       {0xdd, 0x00, 0x0010},                           /* 00,00,10,dd */
+       {0xbb, 0x5f, 0x2090},                           /* 20,5f,90,bb */
+       {0xbb, 0x01, 0x8000},                           /* 80,01,00,bb */
+       {0xbb, 0x09, 0x8400},                           /* 84,09,00,bb */
+       {0xbb, 0x86, 0x0002},                           /* 00,86,02,bb */
+       {0xbb, 0xe6, 0x0401},                           /* 04,e6,01,bb */
+       {0xbb, 0x86, 0x0802},                           /* 08,86,02,bb */
+       {0xbb, 0xe6, 0x0c01},                           /* 0c,e6,01,bb */
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xdd, 0x00, 0x0010},                           /* 00,00,10,dd */
+       {0xaa, 0xfe, 0x0000},                           /* 00,fe,00,aa */
+       {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0a,cc */
+       {0xdd, 0x00, 0x0010},                           /* 00,00,10,dd */
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xaa, 0xfe, 0x0020},                           /* 00,fe,20,aa */
+/*mswin+*/
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},
+       {0xaa, 0xfe, 0x0002},
+       {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
+       {0xaa, 0xb4, 0xcd37},
+       {0xaa, 0xa4, 0x0004},
+       {0xaa, 0xa8, 0x0007},
+       {0xaa, 0xac, 0x0004},
+/*mswin-*/
+       {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0a,cc */
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xdd, 0x00, 0x0010},                           /* 00,00,10,dd */
+       {0xaa, 0xfe, 0x0000},                           /* 00,fe,00,aa */
+       {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0a,cc */
+       {0xdd, 0x00, 0x0010},                           /* 00,00,10,dd */
+       {0xbb, 0x04, 0x0400},                           /* 04,04,00,bb */
+       {0xdd, 0x00, 0x0100},                           /* 00,01,00,dd */
+       {0xbb, 0x01, 0x0400},                           /* 04,01,00,bb */
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xaa, 0xfe, 0x0002},                           /* 00,fe,02,aa */
+       {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0a,cc */
+       {0xbb, 0x41, 0x2803},                           /* 28,41,03,bb */
+       {0xbb, 0x40, 0x2c03},                           /* 2c,40,03,bb */
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xaa, 0xfe, 0x0010},                           /* 00,fe,10,aa */
+       {}
+};
+static const struct usb_action adcm2700_InitialScale[] = {
+       {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},         /* 00,00,01,cc */
+       {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},           /* 00,02,10,cc */
+       {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING},          /* 00,08,03,cc */
+       {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0a,cc */
+       {0xa0, 0xd3, ZC3XX_R08B_I2CDEVICEADDR},         /* 00,8b,d3,cc */
+       {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},        /* 00,03,02,cc */
+       {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},         /* 00,04,80,cc */
+       {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},       /* 00,05,01,cc */
+       {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW},        /* 00,06,d0,cc */
+       {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},       /* 00,01,01,cc */
+       {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},      /* 00,12,03,cc */
+       {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},      /* 00,12,01,cc */
+       {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},      /* 00,12,05,cc */
+       {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},          /* 00,98,00,cc */
+       {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},          /* 00,9a,00,cc */
+       {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},             /* 01,1a,00,cc */
+       {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},             /* 01,1c,00,cc */
+       {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW},          /* 00,9c,d8,cc */
+       {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},           /* 00,9e,88,cc */
+       {0xbb, 0x00, 0x0400},                           /* 04,00,00,bb */
+       {0xdd, 0x00, 0x0010},                           /* 00,00,10,dd */
+       {0xbb, 0x0f, 0x140f},                           /* 14,0f,0f,bb */
+       {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},      /* 01,01,37,cc */
+       {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},         /* 01,00,0d,cc */
+       {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},             /* 01,89,06,cc */
+       {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},         /* 01,c5,03,cc */
+       {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},           /* 01,cb,13,cc */
+       {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},        /* 02,50,08,cc */
+       {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},          /* 03,01,08,cc */
+       {0xa0, 0x58, ZC3XX_R116_RGAIN},                 /* 01,16,58,cc */
+       {0xa0, 0x5a, ZC3XX_R118_BGAIN},                 /* 01,18,5a,cc */
+       {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},     /* 01,80,02,cc */
+       {0xa0, 0xd3, ZC3XX_R08B_I2CDEVICEADDR},         /* 00,8b,d3,cc */
+       {0xbb, 0x00, 0x0408},                           /* 04,00,08,bb */
+       {0xdd, 0x00, 0x0200},                           /* 00,02,00,dd */
+       {0xbb, 0x00, 0x0400},                           /* 04,00,00,bb */
+       {0xdd, 0x00, 0x0050},                           /* 00,00,50,dd */
+       {0xbb, 0x0f, 0x140f},                           /* 14,0f,0f,bb */
+       {0xbb, 0xe0, 0x0c2e},                           /* 0c,e0,2e,bb */
+       {0xbb, 0x01, 0x2000},                           /* 20,01,00,bb */
+       {0xbb, 0x96, 0x2400},                           /* 24,96,00,bb */
+       {0xbb, 0x06, 0x1006},                           /* 10,06,06,bb */
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xdd, 0x00, 0x0010},                           /* 00,00,10,dd */
+       {0xaa, 0xfe, 0x0002},                           /* 00,fe,02,aa */
+       {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0a,cc */
+       {0xdd, 0x00, 0x0010},                           /* 00,00,10,dd */
+       {0xbb, 0x5f, 0x2090},                           /* 20,5f,90,bb */
+       {0xbb, 0x01, 0x8000},                           /* 80,01,00,bb */
+       {0xbb, 0x09, 0x8400},                           /* 84,09,00,bb */
+       {0xbb, 0x86, 0x0002},                           /* 00,88,02,bb */
+       {0xbb, 0xe6, 0x0401},                           /* 04,e6,01,bb */
+       {0xbb, 0x86, 0x0802},                           /* 08,88,02,bb */
+       {0xbb, 0xe6, 0x0c01},                           /* 0c,e6,01,bb */
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xdd, 0x00, 0x0010},                           /* 00,00,10,dd */
+       {0xaa, 0xfe, 0x0000},                           /* 00,fe,00,aa */
+       {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0a,cc */
+       {0xdd, 0x00, 0x0010},                           /* 00,00,10,dd */
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xaa, 0xfe, 0x0020},                           /* 00,fe,20,aa */
+       /*******/
+       {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0a,cc */
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xdd, 0x00, 0x0010},                           /* 00,00,10,dd */
+       {0xaa, 0xfe, 0x0000},                           /* 00,fe,00,aa */
+       {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0a,cc */
+       {0xdd, 0x00, 0x0010},                           /* 00,00,10,dd */
+       {0xbb, 0x04, 0x0400},                           /* 04,04,00,bb */
+       {0xdd, 0x00, 0x0100},                           /* 00,01,00,dd */
+       {0xbb, 0x01, 0x0400},                           /* 04,01,00,bb */
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xaa, 0xfe, 0x0002},                           /* 00,fe,02,aa */
+       {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0a,cc */
+       {0xbb, 0x41, 0x2803},                           /* 28,41,03,bb */
+       {0xbb, 0x40, 0x2c03},                           /* 2c,40,03,bb */
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xaa, 0xfe, 0x0010},                           /* 00,fe,10,aa */
+       {}
+};
+static const struct usb_action adcm2700_50HZ[] = {
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xaa, 0xfe, 0x0002},                           /* 00,fe,02,aa */
+       {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0a,cc */
+       {0xbb, 0x05, 0x8400},                           /* 84,05,00,bb */
+       {0xbb, 0xd0, 0xb007},                           /* b0,d0,07,bb */
+       {0xbb, 0xa0, 0xb80f},                           /* b8,a0,0f,bb */
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xaa, 0xfe, 0x0010},                           /* 00,fe,10,aa */
+       {0xaa, 0x26, 0x00d0},                           /* 00,26,d0,aa */
+       {0xaa, 0x28, 0x0002},                           /* 00,28,02,aa */
+       {}
+};
+static const struct usb_action adcm2700_60HZ[] = {
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xaa, 0xfe, 0x0002},                           /* 00,fe,02,aa */
+       {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0a,cc */
+       {0xbb, 0x07, 0x8400},                           /* 84,07,00,bb */
+       {0xbb, 0x82, 0xb006},                           /* b0,82,06,bb */
+       {0xbb, 0x04, 0xb80d},                           /* b8,04,0d,bb */
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xaa, 0xfe, 0x0010},                           /* 00,fe,10,aa */
+       {0xaa, 0x26, 0x0057},                           /* 00,26,57,aa */
+       {0xaa, 0x28, 0x0002},                           /* 00,28,02,aa */
+       {}
+};
+static const struct usb_action adcm2700_NoFliker[] = {
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xaa, 0xfe, 0x0002},                           /* 00,fe,02,aa */
+       {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0a,cc */
+       {0xbb, 0x07, 0x8400},                           /* 84,07,00,bb */
+       {0xbb, 0x05, 0xb000},                           /* b0,05,00,bb */
+       {0xbb, 0xa0, 0xb801},                           /* b8,a0,01,bb */
+       {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc */
+       {0xaa, 0xfe, 0x0010},                           /* 00,fe,10,aa */
+       {}
+};
 static const struct usb_action cs2102_Initial[] = {
        {0xa1, 0x01, 0x0008},
        {0xa1, 0x01, 0x0008},
@@ -877,7 +1091,7 @@ static const struct usb_action cs2102K_Initial[] = {
 };
 
 static const struct usb_action cs2102K_InitialScale[] = {
-       {0xa0, 0x11, ZC3XX_R002_CLOCKSELECT},
+       {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
        {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
        {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
        {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT},
@@ -894,6 +1108,7 @@ static const struct usb_action cs2102K_InitialScale[] = {
        {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
        {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
        {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+/*fixme: next sequence = i2c exchanges*/
        {0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR},
        {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
        {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
@@ -1077,207 +1292,6 @@ static const struct usb_action cs2102K_InitialScale[] = {
        {0xa0, 0x60, ZC3XX_R116_RGAIN},
        {0xa0, 0x40, ZC3XX_R117_GGAIN},
        {0xa0, 0x4c, ZC3XX_R118_BGAIN},
-       {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
-       {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
-       {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
-       {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
-       {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT},
-       {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
-       {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
-       {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
-       {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
-       {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
-       {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
-       {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
-       {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
-       {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
-       {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
-       {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
-       {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
-       {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
-       {0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR},
-       {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x0A, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x0B, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x0C, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x7b, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x0D, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0xA3, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0xfb, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x03, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x08, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x0E, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x0f, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x10, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x11, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x12, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x15, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x16, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x17, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x0C, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION},
-       {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
-       {0xa0, 0x78, ZC3XX_R18D_YTARGET},
-       {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
-       {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
-       {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
-       {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
-       {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},
-       {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},
-       {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
-       {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
-       {0xa0, 0x00, 0x01ad},
-       {0xa0, 0x01, 0x01b1},
-       {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
-       {0xa0, 0x60, ZC3XX_R116_RGAIN},
-       {0xa0, 0x40, ZC3XX_R117_GGAIN},
-       {0xa0, 0x4c, ZC3XX_R118_BGAIN},
-       {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},  /* clock ? */
-       {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},   /* sharpness+ */
-       {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},   /* sharpness- */
-       {0xa0, 0x13, ZC3XX_R120_GAMMA00},       /* gamma 4 */
-       {0xa0, 0x38, ZC3XX_R121_GAMMA01},
-       {0xa0, 0x59, ZC3XX_R122_GAMMA02},
-       {0xa0, 0x79, ZC3XX_R123_GAMMA03},
-       {0xa0, 0x92, ZC3XX_R124_GAMMA04},
-       {0xa0, 0xa7, ZC3XX_R125_GAMMA05},
-       {0xa0, 0xb9, ZC3XX_R126_GAMMA06},
-       {0xa0, 0xc8, ZC3XX_R127_GAMMA07},
-       {0xa0, 0xd4, ZC3XX_R128_GAMMA08},
-       {0xa0, 0xdf, ZC3XX_R129_GAMMA09},
-       {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A},
-       {0xa0, 0xee, ZC3XX_R12B_GAMMA0B},
-       {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C},
-       {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D},
-       {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E},
-       {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
-       {0xa0, 0x26, ZC3XX_R130_GAMMA10},
-       {0xa0, 0x22, ZC3XX_R131_GAMMA11},
-       {0xa0, 0x20, ZC3XX_R132_GAMMA12},
-       {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
-       {0xa0, 0x16, ZC3XX_R134_GAMMA14},
-       {0xa0, 0x13, ZC3XX_R135_GAMMA15},
-       {0xa0, 0x10, ZC3XX_R136_GAMMA16},
-       {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
-       {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
-       {0xa0, 0x09, ZC3XX_R139_GAMMA19},
-       {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
-       {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
-       {0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
-       {0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
-       {0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
-       {0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
-       {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */
-       {0xa0, 0xf4, ZC3XX_R10B_RGB01},
-       {0xa0, 0xf4, ZC3XX_R10C_RGB02},
-       {0xa0, 0xf4, ZC3XX_R10D_RGB10},
-       {0xa0, 0x58, ZC3XX_R10E_RGB11},
-       {0xa0, 0xf4, ZC3XX_R10F_RGB12},
-       {0xa0, 0xf4, ZC3XX_R110_RGB20},
-       {0xa0, 0xf4, ZC3XX_R111_RGB21},
-       {0xa0, 0x58, ZC3XX_R112_RGB22},
-       {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
-       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
-       {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
-       {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
-       {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
-       {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH},
-       {0xa0, 0x22, ZC3XX_R0A4_EXPOSURETIMELOW},
-       {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
-       {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
-       {0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW},
-       {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
-       {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
-       {0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW},
-       {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
-       {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
-       {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF},
-       {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP},
-       {0xa0, 0x04, ZC3XX_R01D_HSYNC_0},
-       {0xa0, 0x0f, ZC3XX_R01E_HSYNC_1},
-       {0xa0, 0x19, ZC3XX_R01F_HSYNC_2},
-       {0xa0, 0x1f, ZC3XX_R020_HSYNC_3},
-       {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
-       {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
-       {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
-       {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
-       {0xa0, 0x60, ZC3XX_R116_RGAIN},
-       {0xa0, 0x40, ZC3XX_R117_GGAIN},
-       {0xa0, 0x4c, ZC3XX_R118_BGAIN},
        {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
        {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
        {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
@@ -1334,6 +1348,7 @@ static const struct usb_action cs2102K_InitialScale[] = {
        {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
        {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
        {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+/*fixme:what does the next sequence?*/
        {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
        {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
        {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
@@ -6237,7 +6252,7 @@ static const struct usb_action tas5130c_vf0250_NoFlikerScale[] = {
        {}
 };
 
-static int reg_r_i(struct gspca_dev *gspca_dev,
+static u8 reg_r_i(struct gspca_dev *gspca_dev,
                __u16 index)
 {
        usb_control_msg(gspca_dev->dev,
@@ -6250,10 +6265,10 @@ static int reg_r_i(struct gspca_dev *gspca_dev,
        return gspca_dev->usb_buf[0];
 }
 
-static int reg_r(struct gspca_dev *gspca_dev,
+static u8 reg_r(struct gspca_dev *gspca_dev,
                __u16 index)
 {
-       int ret;
+       u8 ret;
 
        ret = reg_r_i(gspca_dev, index);
        PDEBUG(D_USBI, "reg r [%04x] -> %02x", index, ret);
@@ -6286,8 +6301,8 @@ static __u16 i2c_read(struct gspca_dev *gspca_dev,
        __u8 retbyte;
        __u16 retval;
 
-       reg_w_i(gspca_dev->dev, reg, 0x92);
-       reg_w_i(gspca_dev->dev, 0x02, 0x90);            /* <- read command */
+       reg_w_i(gspca_dev->dev, reg, 0x0092);
+       reg_w_i(gspca_dev->dev, 0x02, 0x0090);          /* <- read command */
        msleep(25);
        retbyte = reg_r_i(gspca_dev, 0x0091);           /* read status */
        retval = reg_r_i(gspca_dev, 0x0095);            /* read Lowbyte */
@@ -6332,6 +6347,12 @@ static void usb_exchange(struct gspca_dev *gspca_dev,
                                  action->idx & 0xff,           /* valL */
                                  action->idx >> 8);            /* valH */
                        break;
+               case 0xbb:
+                       i2c_write(gspca_dev,
+                                 action->idx >> 8,             /* reg */
+                                 action->idx & 0xff,           /* valL */
+                                 action->val);                 /* valH */
+                       break;
                default:
 /*             case 0xdd:       * delay */
                        msleep(action->val / 64 + 10);
@@ -6347,6 +6368,10 @@ static void setmatrix(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int i;
        const __u8 *matrix;
+       static const u8 adcm2700_matrix[9] =
+/*             {0x66, 0xed, 0xed, 0xed, 0x66, 0xed, 0xed, 0xed, 0x66}; */
+/*ms-win*/
+               {0x74, 0xed, 0xed, 0xed, 0x74, 0xed, 0xed, 0xed, 0x74};
        static const __u8 gc0305_matrix[9] =
                {0x50, 0xf8, 0xf8, 0xf8, 0x50, 0xf8, 0xf8, 0xf8, 0x50};
        static const __u8 ov7620_matrix[9] =
@@ -6358,23 +6383,24 @@ static void setmatrix(struct gspca_dev *gspca_dev)
        static const __u8 vf0250_matrix[9] =
                {0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b};
        static const __u8 *matrix_tb[SENSOR_MAX] = {
-               NULL,           /* SENSOR_CS2102 0 */
-               NULL,           /* SENSOR_CS2102K 1 */
-               gc0305_matrix,  /* SENSOR_GC0305 2 */
-               NULL,           /* SENSOR_HDCS2020b 3 */
-               NULL,           /* SENSOR_HV7131B 4 */
-               NULL,           /* SENSOR_HV7131C 5 */
-               NULL,           /* SENSOR_ICM105A 6 */
-               NULL,           /* SENSOR_MC501CB 7 */
-               ov7620_matrix,  /* SENSOR_OV7620 8 */
-               NULL,           /* SENSOR_OV7630C 9 */
-               NULL,           /* SENSOR_PAS106 10 */
-               pas202b_matrix, /* SENSOR_PAS202B 11 */
-               NULL,           /* SENSOR_PB0330 12 */
-               po2030_matrix,  /* SENSOR_PO2030 13 */
-               NULL,           /* SENSOR_TAS5130CK 14 */
-               NULL,           /* SENSOR_TAS5130CXX 15 */
-               vf0250_matrix,  /* SENSOR_TAS5130C_VF0250 16 */
+               adcm2700_matrix, /* SENSOR_ADCM2700 0 */
+               NULL,           /* SENSOR_CS2102 1 */
+               NULL,           /* SENSOR_CS2102K 2 */
+               gc0305_matrix,  /* SENSOR_GC0305 3 */
+               NULL,           /* SENSOR_HDCS2020b 4 */
+               NULL,           /* SENSOR_HV7131B 5 */
+               NULL,           /* SENSOR_HV7131C 6 */
+               NULL,           /* SENSOR_ICM105A 7 */
+               NULL,           /* SENSOR_MC501CB 8 */
+               ov7620_matrix,  /* SENSOR_OV7620 9 */
+               NULL,           /* SENSOR_OV7630C 10 */
+               NULL,           /* SENSOR_PAS106 11 */
+               pas202b_matrix, /* SENSOR_PAS202B 12 */
+               NULL,           /* SENSOR_PB0330 13 */
+               po2030_matrix,  /* SENSOR_PO2030 14 */
+               NULL,           /* SENSOR_TAS5130CK 15 */
+               NULL,           /* SENSOR_TAS5130CXX 16 */
+               vf0250_matrix,  /* SENSOR_TAS5130C_VF0250 17 */
        };
 
        matrix = matrix_tb[sd->sensor];
@@ -6398,8 +6424,11 @@ static void setbrightness(struct gspca_dev *gspca_dev)
 /*fixme: is it really write to 011d and 018d for all other sensors? */
        brightness = sd->brightness;
        reg_w(gspca_dev->dev, brightness, 0x011d);
-       if (sd->sensor == SENSOR_HV7131B)
+       switch (sd->sensor) {
+       case SENSOR_ADCM2700:
+       case SENSOR_HV7131B:
                return;
+       }
        if (brightness < 0x70)
                brightness += 0x10;
        else
@@ -6536,10 +6565,10 @@ static void setquality(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        struct usb_device *dev = gspca_dev->dev;
-       __u8 quality;
        __u8 frxt;
 
        switch (sd->sensor) {
+       case SENSOR_ADCM2700:
        case SENSOR_GC0305:
        case SENSOR_HV7131B:
        case SENSOR_OV7620:
@@ -6547,26 +6576,18 @@ static void setquality(struct gspca_dev *gspca_dev)
                return;
        }
 /*fixme: is it really 0008 0007 0018 for all other sensors? */
-       quality = sd->qindex;
-       reg_w(dev, quality, 0x0008);
+       reg_w(dev, QUANT_VAL, 0x0008);
        frxt = 0x30;
        reg_w(dev, frxt, 0x0007);
-       switch (quality) {
-       case 0:
-       case 1:
-       case 2:
-               frxt = 0xff;
-               break;
-       case 3:
-               frxt = 0xf0;
-               break;
-       case 4:
-               frxt = 0xe0;
-               break;
-       case 5:
-               frxt = 0x20;
-               break;
-       }
+#if QUANT_VAL == 0 || QUANT_VAL == 1 || QUANT_VAL == 2
+       frxt = 0xff;
+#elif QUANT_VAL == 3
+       frxt = 0xf0;
+#elif QUANT_VAL == 4
+       frxt = 0xe0;
+#else
+       frxt = 0x20;
+#endif
        reg_w(dev, frxt, 0x0018);
 }
 
@@ -6583,71 +6604,75 @@ static int setlightfreq(struct gspca_dev *gspca_dev)
        int i, mode;
        const struct usb_action *zc3_freq;
        static const struct usb_action *freq_tb[SENSOR_MAX][6] = {
-/* SENSOR_CS2102 0 */
+/* SENSOR_ADCM2700 0 */
+               {adcm2700_NoFliker, adcm2700_NoFliker,
+                adcm2700_50HZ, adcm2700_50HZ,
+                adcm2700_60HZ, adcm2700_60HZ},
+/* SENSOR_CS2102 1 */
                {cs2102_NoFliker, cs2102_NoFlikerScale,
                 cs2102_50HZ, cs2102_50HZScale,
                 cs2102_60HZ, cs2102_60HZScale},
-/* SENSOR_CS2102K 1 */
+/* SENSOR_CS2102K 2 */
                {cs2102_NoFliker, cs2102_NoFlikerScale,
                 NULL, NULL, /* currently disabled */
                 NULL, NULL},
-/* SENSOR_GC0305 2 */
+/* SENSOR_GC0305 3 */
                {gc0305_NoFliker, gc0305_NoFliker,
                 gc0305_50HZ, gc0305_50HZ,
                 gc0305_60HZ, gc0305_60HZ},
-/* SENSOR_HDCS2020b 3 */
+/* SENSOR_HDCS2020b 4 */
                {hdcs2020b_NoFliker, hdcs2020b_NoFliker,
                 hdcs2020b_50HZ, hdcs2020b_50HZ,
                 hdcs2020b_60HZ, hdcs2020b_60HZ},
-/* SENSOR_HV7131B 4 */
+/* SENSOR_HV7131B 5 */
                {hv7131b_NoFlikerScale, hv7131b_NoFliker,
                 hv7131b_50HZScale, hv7131b_50HZ,
                 hv7131b_60HZScale, hv7131b_60HZ},
-/* SENSOR_HV7131C 5 */
+/* SENSOR_HV7131C 6 */
                {NULL, NULL,
                 NULL, NULL,
                 NULL, NULL},
-/* SENSOR_ICM105A 6 */
+/* SENSOR_ICM105A 7 */
                {icm105a_NoFliker, icm105a_NoFlikerScale,
                 icm105a_50HZ, icm105a_50HZScale,
                 icm105a_60HZ, icm105a_60HZScale},
-/* SENSOR_MC501CB 7 */
+/* SENSOR_MC501CB 8 */
                {MC501CB_NoFliker, MC501CB_NoFlikerScale,
                 MC501CB_50HZ, MC501CB_50HZScale,
                 MC501CB_60HZ, MC501CB_60HZScale},
-/* SENSOR_OV7620 8 */
+/* SENSOR_OV7620 9 */
                {OV7620_NoFliker, OV7620_NoFliker,
                 OV7620_50HZ, OV7620_50HZ,
                 OV7620_60HZ, OV7620_60HZ},
-/* SENSOR_OV7630C 9 */
+/* SENSOR_OV7630C 10 */
                {NULL, NULL,
                 NULL, NULL,
                 NULL, NULL},
-/* SENSOR_PAS106 10 */
+/* SENSOR_PAS106 11 */
                {pas106b_NoFliker, pas106b_NoFliker,
                 pas106b_50HZ, pas106b_50HZ,
                 pas106b_60HZ, pas106b_60HZ},
-/* SENSOR_PAS202B 11 */
+/* SENSOR_PAS202B 12 */
                {pas202b_NoFlikerScale, pas202b_NoFliker,
                 pas202b_50HZScale, pas202b_50HZ,
                 pas202b_60HZScale, pas202b_60HZ},
-/* SENSOR_PB0330 12 */
+/* SENSOR_PB0330 13 */
                {pb0330_NoFliker, pb0330_NoFlikerScale,
                 pb0330_50HZ, pb0330_50HZScale,
                 pb0330_60HZ, pb0330_60HZScale},
-/* SENSOR_PO2030 13 */
+/* SENSOR_PO2030 14 */
                {PO2030_NoFliker, PO2030_NoFliker,
                 PO2030_50HZ, PO2030_50HZ,
                 PO2030_60HZ, PO2030_60HZ},
-/* SENSOR_TAS5130CK 14 */
+/* SENSOR_TAS5130CK 15 */
                {tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
                 tas5130cxx_50HZ, tas5130cxx_50HZScale,
                 tas5130cxx_60HZ, tas5130cxx_60HZScale},
-/* SENSOR_TAS5130CXX 15 */
+/* SENSOR_TAS5130CXX 16 */
                {tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
                 tas5130cxx_50HZ, tas5130cxx_50HZScale,
                 tas5130cxx_60HZ, tas5130cxx_60HZScale},
-/* SENSOR_TAS5130C_VF0250 16 */
+/* SENSOR_TAS5130C_VF0250 17 */
                {tas5130c_vf0250_NoFliker, tas5130c_vf0250_NoFlikerScale,
                 tas5130c_vf0250_50HZ, tas5130c_vf0250_50HZScale,
                 tas5130c_vf0250_60HZ, tas5130c_vf0250_60HZScale},
@@ -6701,6 +6726,7 @@ static void send_unknown(struct usb_device *dev, int sensor)
                reg_w(dev, 0x0c, 0x003b);
                reg_w(dev, 0x08, 0x0038);
                break;
+       case SENSOR_ADCM2700:
        case SENSOR_GC0305:
        case SENSOR_OV7620:
        case SENSOR_PB0330:
@@ -6743,26 +6769,25 @@ static int sif_probe(struct gspca_dev *gspca_dev)
 static int vga_2wr_probe(struct gspca_dev *gspca_dev)
 {
        struct usb_device *dev = gspca_dev->dev;
-       __u8 retbyte;
-       __u16 checkword;
+       u16 retword;
 
        start_2wr_probe(dev, 0x00);             /* HV7131B */
        i2c_write(gspca_dev, 0x01, 0xaa, 0x00);
-       retbyte = i2c_read(gspca_dev, 0x01);
-       if (retbyte != 0)
+       retword = i2c_read(gspca_dev, 0x01);
+       if (retword != 0)
                return 0x00;                    /* HV7131B */
 
        start_2wr_probe(dev, 0x04);             /* CS2102 */
        i2c_write(gspca_dev, 0x01, 0xaa, 0x00);
-       retbyte = i2c_read(gspca_dev, 0x01);
-       if (retbyte != 0)
+       retword = i2c_read(gspca_dev, 0x01);
+       if (retword != 0)
                return 0x04;                    /* CS2102 */
 
        start_2wr_probe(dev, 0x06);             /* OmniVision */
        reg_w(dev, 0x08, 0x008d);
        i2c_write(gspca_dev, 0x11, 0xaa, 0x00);
-       retbyte = i2c_read(gspca_dev, 0x11);
-       if (retbyte != 0) {
+       retword = i2c_read(gspca_dev, 0x11);
+       if (retword != 0) {
                /* (should have returned 0xaa) --> Omnivision? */
                /* reg_r 0x10 -> 0x06 -->  */
                goto ov_check;
@@ -6770,40 +6795,40 @@ static int vga_2wr_probe(struct gspca_dev *gspca_dev)
 
        start_2wr_probe(dev, 0x08);             /* HDCS2020 */
        i2c_write(gspca_dev, 0x15, 0xaa, 0x00);
-       retbyte = i2c_read(gspca_dev, 0x15);
-       if (retbyte != 0)
+       retword = i2c_read(gspca_dev, 0x15);
+       if (retword != 0)
                return 0x08;                    /* HDCS2020 */
 
        start_2wr_probe(dev, 0x0a);             /* PB0330 */
        i2c_write(gspca_dev, 0x07, 0xaa, 0xaa);
-       retbyte = i2c_read(gspca_dev, 0x07);
-       if (retbyte != 0)
+       retword = i2c_read(gspca_dev, 0x07);
+       if (retword != 0)
                return 0x0a;                    /* PB0330 */
-       retbyte = i2c_read(gspca_dev, 0x03);
-       if (retbyte != 0)
+       retword = i2c_read(gspca_dev, 0x03);
+       if (retword != 0)
                return 0x0a;                    /* PB0330 ?? */
-       retbyte = i2c_read(gspca_dev, 0x04);
-       if (retbyte != 0)
+       retword = i2c_read(gspca_dev, 0x04);
+       if (retword != 0)
                return 0x0a;                    /* PB0330 ?? */
 
        start_2wr_probe(dev, 0x0c);             /* ICM105A */
        i2c_write(gspca_dev, 0x01, 0x11, 0x00);
-       retbyte = i2c_read(gspca_dev, 0x01);
-       if (retbyte != 0)
+       retword = i2c_read(gspca_dev, 0x01);
+       if (retword != 0)
                return 0x0c;                    /* ICM105A */
 
        start_2wr_probe(dev, 0x0e);             /* PAS202BCB */
        reg_w(dev, 0x08, 0x008d);
        i2c_write(gspca_dev, 0x03, 0xaa, 0x00);
        msleep(500);
-       retbyte = i2c_read(gspca_dev, 0x03);
-       if (retbyte != 0)
+       retword = i2c_read(gspca_dev, 0x03);
+       if (retword != 0)
                return 0x0e;                    /* PAS202BCB */
 
        start_2wr_probe(dev, 0x02);             /* ?? */
        i2c_write(gspca_dev, 0x01, 0xaa, 0x00);
-       retbyte = i2c_read(gspca_dev, 0x01);
-       if (retbyte != 0)
+       retword = i2c_read(gspca_dev, 0x01);
+       if (retword != 0)
                return 0x02;                    /* ?? */
 ov_check:
        reg_r(gspca_dev, 0x0010);               /* ?? */
@@ -6817,12 +6842,10 @@ ov_check:
        msleep(500);
        reg_w(dev, 0x01, 0x0012);
        i2c_write(gspca_dev, 0x12, 0x80, 0x00); /* sensor reset */
-       retbyte = i2c_read(gspca_dev, 0x0a);
-       checkword = retbyte << 8;
-       retbyte = i2c_read(gspca_dev, 0x0b);
-       checkword |= retbyte;
-       PDEBUG(D_PROBE, "probe 2wr ov vga 0x%04x", checkword);
-       switch (checkword) {
+       retword = i2c_read(gspca_dev, 0x0a) << 8;
+       retword |= i2c_read(gspca_dev, 0x0b);
+       PDEBUG(D_PROBE, "probe 2wr ov vga 0x%04x", retword);
+       switch (retword) {
        case 0x7631:                            /* OV7630C */
                reg_w(dev, 0x06, 0x0010);
                break;
@@ -6832,7 +6855,7 @@ ov_check:
        default:
                return -1;                      /* not OmniVision */
        }
-       return checkword;
+       return retword;
 }
 
 struct sensor_by_chipset_revision {
@@ -6845,6 +6868,7 @@ static const struct sensor_by_chipset_revision chipset_revision_sensor[] = {
        {0x8001, 0x13},
        {0x8000, 0x14},         /* CS2102K */
        {0x8400, 0x15},         /* TAS5130K */
+       {0x4001, 0x16},         /* ADCM2700 */
 };
 
 static int vga_3wr_probe(struct gspca_dev *gspca_dev)
@@ -6853,7 +6877,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
        struct usb_device *dev = gspca_dev->dev;
        int i;
        __u8 retbyte;
-       __u16 checkword;
+       u16 retword;
 
 /*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/
        reg_w(dev, 0x02, 0x0010);
@@ -6865,27 +6889,25 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
        reg_w(dev, 0x03, 0x0012);
        reg_w(dev, 0x01, 0x0012);
        reg_w(dev, 0x05, 0x0012);
-       retbyte = i2c_read(gspca_dev, 0x14);
-       if (retbyte != 0)
+       retword = i2c_read(gspca_dev, 0x14);
+       if (retword != 0)
                return 0x11;                    /* HV7131R */
-       retbyte = i2c_read(gspca_dev, 0x15);
-       if (retbyte != 0)
+       retword = i2c_read(gspca_dev, 0x15);
+       if (retword != 0)
                return 0x11;                    /* HV7131R */
-       retbyte = i2c_read(gspca_dev, 0x16);
-       if (retbyte != 0)
+       retword = i2c_read(gspca_dev, 0x16);
+       if (retword != 0)
                return 0x11;                    /* HV7131R */
 
        reg_w(dev, 0x02, 0x0010);
-       retbyte = reg_r(gspca_dev, 0x000b);
-       checkword = retbyte << 8;
-       retbyte = reg_r(gspca_dev, 0x000a);
-       checkword |= retbyte;
-       PDEBUG(D_PROBE, "probe 3wr vga 1 0x%04x", checkword);
+       retword = reg_r(gspca_dev, 0x000b) << 8;
+       retword |= reg_r(gspca_dev, 0x000a);
+       PDEBUG(D_PROBE, "probe 3wr vga 1 0x%04x", retword);
        reg_r(gspca_dev, 0x0010);
        /* this is tested only once anyway */
        for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) {
-               if (chipset_revision_sensor[i].revision == checkword) {
-                       sd->chip_revision = checkword;
+               if (chipset_revision_sensor[i].revision == retword) {
+                       sd->chip_revision = retword;
                        send_unknown(dev, SENSOR_PB0330);
                        return chipset_revision_sensor[i].internal_sensor_id;
                }
@@ -6897,8 +6919,8 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
        reg_w(dev, 0x0a, 0x0010);
        reg_w(dev, 0x03, 0x0012);
        reg_w(dev, 0x01, 0x0012);
-       retbyte = i2c_read(gspca_dev, 0x00);
-       if (retbyte != 0) {
+       retword = i2c_read(gspca_dev, 0x00);
+       if (retword != 0) {
                PDEBUG(D_PROBE, "probe 3wr vga type 0a ?");
                return 0x0a;                    /* ?? */
        }
@@ -6910,14 +6932,14 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
        reg_w(dev, 0x03, 0x0012);
        msleep(2);
        reg_w(dev, 0x01, 0x0012);
-       retbyte = i2c_read(gspca_dev, 0x00);
-       if (retbyte != 0) {
-               PDEBUG(D_PROBE, "probe 3wr vga type %02x", retbyte);
-               if (retbyte == 0x11)                    /* VF0250 */
+       retword = i2c_read(gspca_dev, 0x00);
+       if (retword != 0) {
+               PDEBUG(D_PROBE, "probe 3wr vga type %02x", retword);
+               if (retword == 0x0011)                  /* VF0250 */
                        return 0x0250;
-               if (retbyte == 0x29)                    /* gc0305 */
+               if (retword == 0x0029)                  /* gc0305 */
                        send_unknown(dev, SENSOR_GC0305);
-               return retbyte;
+               return retword;
        }
 
        reg_w(dev, 0x01, 0x0000);       /* check OmniVision */
@@ -6927,8 +6949,8 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
        reg_w(dev, 0x06, 0x0010);
        reg_w(dev, 0x01, 0x0012);
        reg_w(dev, 0x05, 0x0012);
-       if (i2c_read(gspca_dev, 0x1c) == 0x7f   /* OV7610 - manufacturer ID */
-           && i2c_read(gspca_dev, 0x1d) == 0xa2) {
+       if (i2c_read(gspca_dev, 0x1c) == 0x007f /* OV7610 - manufacturer ID */
+           && i2c_read(gspca_dev, 0x1d) == 0x00a2) {
                send_unknown(dev, SENSOR_OV7620);
                return 0x06;            /* OmniVision confirm ? */
        }
@@ -6942,16 +6964,14 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
 /*     msleep(150); */
        reg_w(dev, 0x01, 0x0012);
        reg_w(dev, 0x05, 0x0012);
-       retbyte = i2c_read(gspca_dev, 0x0000);          /* ID 0 */
-       checkword = retbyte << 8;
-       retbyte = i2c_read(gspca_dev, 0x0001);          /* ID 1 */
-       checkword |= retbyte;
-       PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", checkword);
-       if (checkword == 0x2030) {
+       retword = i2c_read(gspca_dev, 0x00) << 8;       /* ID 0 */
+       retword |= i2c_read(gspca_dev, 0x01);           /* ID 1 */
+       PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", retword);
+       if (retword == 0x2030) {
                retbyte = i2c_read(gspca_dev, 0x02);    /* revision number */
                PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte);
                send_unknown(dev, SENSOR_PO2030);
-               return checkword;
+               return retword;
        }
 
        reg_w(dev, 0x01, 0x0000);
@@ -6962,10 +6982,10 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
        reg_w(dev, 0x01, 0x0012);
        reg_w(dev, 0x05, 0x0001);
        reg_w(dev, 0xd3, 0x008b);
-       retbyte = i2c_read(gspca_dev, 0x01);
-       if (retbyte != 0) {
-               PDEBUG(D_PROBE, "probe 3wr vga type 0a ?");
-               return 0x0a;                    /* ?? */
+       retword = i2c_read(gspca_dev, 0x01);
+       if (retword != 0) {
+               PDEBUG(D_PROBE, "probe 3wr vga type 0a ? ret: %04x", retword);
+               return retword;
        }
        return -1;
 }
@@ -6973,7 +6993,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
 static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int sensor, sensor2;
+       int sensor;
 
        switch (sd->sensor) {
        case SENSOR_MC501CB:
@@ -6988,16 +7008,9 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
                break;
        }
        sensor = vga_2wr_probe(gspca_dev);
-       if (sensor >= 0) {
-               if (sensor < 0x7600)
-                       return sensor;
-               /* next probe is needed for OmniVision ? */
-       }
-       sensor2 = vga_3wr_probe(gspca_dev);
-       if (sensor2 >= 0
-           && sensor >= 0)
+       if (sensor >= 0)
                return sensor;
-       return sensor2;
+       return vga_3wr_probe(gspca_dev);
 }
 
 /* this function is called at probe time */
@@ -7009,23 +7022,24 @@ static int sd_config(struct gspca_dev *gspca_dev,
        int sensor;
        int vga = 1;            /* 1: vga, 0: sif */
        static const __u8 gamma[SENSOR_MAX] = {
-               5,      /* SENSOR_CS2102 0 */
-               5,      /* SENSOR_CS2102K 1 */
-               4,      /* SENSOR_GC0305 2 */
-               4,      /* SENSOR_HDCS2020b 3 */
-               4,      /* SENSOR_HV7131B 4 */
-               4,      /* SENSOR_HV7131C 5 */
-               4,      /* SENSOR_ICM105A 6 */
-               4,      /* SENSOR_MC501CB 7 */
-               3,      /* SENSOR_OV7620 8 */
-               4,      /* SENSOR_OV7630C 9 */
-               4,      /* SENSOR_PAS106 10 */
-               4,      /* SENSOR_PAS202B 11 */
-               4,      /* SENSOR_PB0330 12 */
-               4,      /* SENSOR_PO2030 13 */
-               4,      /* SENSOR_TAS5130CK 14 */
-               4,      /* SENSOR_TAS5130CXX 15 */
-               3,      /* SENSOR_TAS5130C_VF0250 16 */
+               4,      /* SENSOR_ADCM2700 0 */
+               5,      /* SENSOR_CS2102 1 */
+               5,      /* SENSOR_CS2102K 2 */
+               4,      /* SENSOR_GC0305 3 */
+               4,      /* SENSOR_HDCS2020b 4 */
+               4,      /* SENSOR_HV7131B 5 */
+               4,      /* SENSOR_HV7131C 6 */
+               4,      /* SENSOR_ICM105A 7 */
+               4,      /* SENSOR_MC501CB 8 */
+               3,      /* SENSOR_OV7620 9 */
+               4,      /* SENSOR_OV7630C 10 */
+               4,      /* SENSOR_PAS106 11 */
+               4,      /* SENSOR_PAS202B 12 */
+               4,      /* SENSOR_PB0330 13 */
+               4,      /* SENSOR_PO2030 14 */
+               4,      /* SENSOR_TAS5130CK 15 */
+               4,      /* SENSOR_TAS5130CXX 16 */
+               3,      /* SENSOR_TAS5130C_VF0250 17 */
        };
 
        /* define some sensors from the vendor/product */
@@ -7033,7 +7047,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->sensor = id->driver_info;
        sensor = zcxx_probeSensor(gspca_dev);
        if (sensor >= 0)
-               PDEBUG(D_PROBE, "probe sensor -> %02x", sensor);
+               PDEBUG(D_PROBE, "probe sensor -> %04x", sensor);
        if ((unsigned) force_sensor < SENSOR_MAX) {
                sd->sensor = force_sensor;
                PDEBUG(D_PROBE, "sensor forced to %d", force_sensor);
@@ -7112,6 +7126,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
                                sd->chip_revision);
                        sd->sensor = SENSOR_TAS5130CK;
                        break;
+               case 0x16:
+                       PDEBUG(D_PROBE, "Find Sensor ADCM2700");
+                       sd->sensor = SENSOR_ADCM2700;
+                       break;
                case 0x29:
                        PDEBUG(D_PROBE, "Find Sensor GC0305");
                        sd->sensor = SENSOR_GC0305;
@@ -7129,12 +7147,16 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        PDEBUG(D_PROBE, "Find Sensor OV7620");
                        sd->sensor = SENSOR_OV7620;
                        break;
+               case 0x7631:
+                       PDEBUG(D_PROBE, "Find Sensor OV7630C");
+                       sd->sensor = SENSOR_OV7630C;
+                       break;
                case 0x7648:
                        PDEBUG(D_PROBE, "Find Sensor OV7648");
                        sd->sensor = SENSOR_OV7620;     /* same sensor (?) */
                        break;
                default:
-                       PDEBUG(D_ERR|D_PROBE, "Unknown sensor %02x", sensor);
+                       PDEBUG(D_ERR|D_PROBE, "Unknown sensor %04x", sensor);
                        return -EINVAL;
                }
        }
@@ -7147,7 +7169,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        }
 
        cam = &gspca_dev->cam;
-       cam->epaddr = 0x01;
 /*fixme:test*/
        gspca_dev->nbalt--;
        if (vga) {
@@ -7157,12 +7178,12 @@ static int sd_config(struct gspca_dev *gspca_dev,
                cam->cam_mode = sif_mode;
                cam->nmodes = ARRAY_SIZE(sif_mode);
        }
-       sd->qindex = 1;
        sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
        sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
        sd->gamma = gamma[(int) sd->sensor];
        sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
        sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
+       sd->quality = QUALITY_DEF;
 
        switch (sd->sensor) {
        case SENSOR_GC0305:
@@ -7196,27 +7217,34 @@ static int sd_start(struct gspca_dev *gspca_dev)
        const struct usb_action *zc3_init;
        int mode;
        static const struct usb_action *init_tb[SENSOR_MAX][2] = {
-               {cs2102_InitialScale, cs2102_Initial},          /* 0 */
-               {cs2102K_InitialScale, cs2102K_Initial},        /* 1 */
-               {gc0305_Initial, gc0305_InitialScale},          /* 2 */
-               {hdcs2020xb_InitialScale, hdcs2020xb_Initial},  /* 3 */
-               {hv7131bxx_InitialScale, hv7131bxx_Initial},    /* 4 */
-               {hv7131cxx_InitialScale, hv7131cxx_Initial},    /* 5 */
-               {icm105axx_InitialScale, icm105axx_Initial},    /* 6 */
-               {MC501CB_InitialScale, MC501CB_Initial},        /* 7 */
-               {OV7620_mode0, OV7620_mode1},                   /* 8 */
-               {ov7630c_InitialScale, ov7630c_Initial},        /* 9 */
-               {pas106b_InitialScale, pas106b_Initial},        /* 10 */
-               {pas202b_Initial, pas202b_InitialScale},        /* 11 */
-               {pb0330xx_InitialScale, pb0330xx_Initial},      /* 12 */
+               {adcm2700_Initial, adcm2700_InitialScale},      /* 0 */
+               {cs2102_InitialScale, cs2102_Initial},          /* 1 */
+               {cs2102K_InitialScale, cs2102K_Initial},        /* 2 */
+               {gc0305_Initial, gc0305_InitialScale},          /* 3 */
+               {hdcs2020xb_InitialScale, hdcs2020xb_Initial},  /* 4 */
+               {hv7131bxx_InitialScale, hv7131bxx_Initial},    /* 5 */
+               {hv7131cxx_InitialScale, hv7131cxx_Initial},    /* 6 */
+               {icm105axx_InitialScale, icm105axx_Initial},    /* 7 */
+               {MC501CB_InitialScale, MC501CB_Initial},        /* 8 */
+               {OV7620_mode0, OV7620_mode1},                   /* 9 */
+               {ov7630c_InitialScale, ov7630c_Initial},        /* 10 */
+               {pas106b_InitialScale, pas106b_Initial},        /* 11 */
+               {pas202b_Initial, pas202b_InitialScale},        /* 12 */
+               {pb0330xx_InitialScale, pb0330xx_Initial},      /* 13 */
 /* or          {pb03303x_InitialScale, pb03303x_Initial}, */
-               {PO2030_mode0, PO2030_mode1},                   /* 13 */
-               {tas5130CK_InitialScale, tas5130CK_Initial},    /* 14 */
-               {tas5130cxx_InitialScale, tas5130cxx_Initial},  /* 15 */
+               {PO2030_mode0, PO2030_mode1},                   /* 14 */
+               {tas5130CK_InitialScale, tas5130CK_Initial},    /* 15 */
+               {tas5130cxx_InitialScale, tas5130cxx_Initial},  /* 16 */
                {tas5130c_vf0250_InitialScale, tas5130c_vf0250_Initial},
-                                                               /* 16 */
+                                                               /* 17 */
        };
 
+       /* create the JPEG header */
+       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+                       0x21);          /* JPEG 422 */
+       jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
        mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
        zc3_init = init_tb[(int) sd->sensor][mode];
        switch (sd->sensor) {
@@ -7243,11 +7271,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
        usb_exchange(gspca_dev, zc3_init);
 
        switch (sd->sensor) {
+       case SENSOR_ADCM2700:
        case SENSOR_GC0305:
        case SENSOR_OV7620:
        case SENSOR_PO2030:
        case SENSOR_TAS5130C_VF0250:
-               msleep(100);                    /* ?? */
+/*             msleep(100);                     * ?? */
                reg_r(gspca_dev, 0x0002);       /* --> 0x40 */
                reg_w(dev, 0x09, 0x01ad);       /* (from win traces) */
                reg_w(dev, 0x15, 0x01ae);
@@ -7260,6 +7289,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        setmatrix(gspca_dev);
        setbrightness(gspca_dev);
        switch (sd->sensor) {
+       case SENSOR_ADCM2700:
        case SENSOR_OV7620:
                reg_r(gspca_dev, 0x0008);
                reg_w(dev, 0x00, 0x0008);
@@ -7301,6 +7331,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
        setlightfreq(gspca_dev);
 
        switch (sd->sensor) {
+       case SENSOR_ADCM2700:
+               reg_w(dev, 0x09, 0x01ad);       /* (from win traces) */
+               reg_w(dev, 0x15, 0x01ae);
+               reg_w(dev, 0x02, 0x0180);
+                                               /* ms-win + */
+               reg_w(dev, 0x40, 0x0117);
+               break;
        case SENSOR_GC0305:
                reg_w(dev, 0x09, 0x01ad);       /* (from win traces) */
                reg_w(dev, 0x15, 0x01ae);
@@ -7323,19 +7360,16 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        setautogain(gspca_dev);
        switch (sd->sensor) {
-       case SENSOR_PAS202B:
-               reg_w(dev, 0x00, 0x0007);       /* (from win traces) */
-               break;
        case SENSOR_PO2030:
                msleep(500);
                reg_r(gspca_dev, 0x0008);
                reg_r(gspca_dev, 0x0007);
+               /*fall thru*/
+       case SENSOR_PAS202B:
                reg_w(dev, 0x00, 0x0007);       /* (from win traces) */
-               reg_w(dev, 0x02, 0x0008);
+               reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING);
                break;
        }
-       if (sd->sensor == SENSOR_PAS202B)
-               reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING);
        return 0;
 }
 
@@ -7344,6 +7378,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
+       kfree(sd->jpeg_hdr);
        if (!gspca_dev->present)
                return;
        send_unknown(gspca_dev->dev, sd->sensor);
@@ -7354,14 +7389,15 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        __u8 *data,
                        int len)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
 
        if (data[0] == 0xff && data[1] == 0xd8) {       /* start of frame */
                frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
                                        data, 0);
                /* put the JPEG header in the new frame */
-               jpeg_put_header(gspca_dev, frame,
-                               ((struct sd *) gspca_dev)->qindex,
-                               0x21);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                       sd->jpeg_hdr, JPEG_HDR_SZ);
+
                /* remove the webcam's header:
                 * ff d8 ff fe 00 0e 00 00 ss ss 00 01 ww ww hh hh pp pp
                 *      - 'ss ss' is the frame sequence number (BE)
@@ -7503,6 +7539,34 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
        return -EINVAL;
 }
 
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (jcomp->quality < QUALITY_MIN)
+               sd->quality = QUALITY_MIN;
+       else if (jcomp->quality > QUALITY_MAX)
+               sd->quality = QUALITY_MAX;
+       else
+               sd->quality = jcomp->quality;
+       if (gspca_dev->streaming)
+               jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+       return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       memset(jcomp, 0, sizeof *jcomp);
+       jcomp->quality = sd->quality;
+       jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+                       | V4L2_JPEG_MARKER_DQT;
+       return 0;
+}
+
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
        .ctrls = sd_ctrls,
@@ -7513,6 +7577,8 @@ static const struct sd_desc sd_desc = {
        .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
        .querymenu = sd_querymenu,
+       .get_jcomp = sd_get_jcomp,
+       .set_jcomp = sd_set_jcomp,
 };
 
 static const __devinitdata struct usb_device_id device_table[] = {
@@ -7563,11 +7629,9 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x055f, 0xd004)},
        {USB_DEVICE(0x0698, 0x2003)},
        {USB_DEVICE(0x0ac8, 0x0301), .driver_info = SENSOR_PAS106},
-       {USB_DEVICE(0x0ac8, 0x0302)},
+       {USB_DEVICE(0x0ac8, 0x0302), .driver_info = SENSOR_PAS106},
        {USB_DEVICE(0x0ac8, 0x301b)},
-#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE
        {USB_DEVICE(0x0ac8, 0x303b)},
-#endif
        {USB_DEVICE(0x0ac8, 0x305b), .driver_info = SENSOR_TAS5130C_VF0250},
        {USB_DEVICE(0x0ac8, 0x307b)},
        {USB_DEVICE(0x10fd, 0x0128)},
@@ -7600,8 +7664,10 @@ static struct usb_driver sd_driver = {
 
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
diff --git a/drivers/media/video/hdpvr/Kconfig b/drivers/media/video/hdpvr/Kconfig
new file mode 100644 (file)
index 0000000..de247f3
--- /dev/null
@@ -0,0 +1,10 @@
+
+config VIDEO_HDPVR
+       tristate "Hauppauge HD PVR support"
+       depends on VIDEO_DEV
+       ---help---
+         This is a video4linux driver for Hauppauge's HD PVR USB device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called hdpvr
+
diff --git a/drivers/media/video/hdpvr/Makefile b/drivers/media/video/hdpvr/Makefile
new file mode 100644 (file)
index 0000000..e0230fc
--- /dev/null
@@ -0,0 +1,9 @@
+hdpvr-objs     := hdpvr-control.o hdpvr-core.o hdpvr-video.o
+
+hdpvr-$(CONFIG_I2C) += hdpvr-i2c.o
+
+obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
+
+EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/hdpvr/hdpvr-control.c b/drivers/media/video/hdpvr/hdpvr-control.c
new file mode 100644 (file)
index 0000000..0679174
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Hauppauge HD PVR USB driver - video 4 linux 2 interface
+ *
+ * Copyright (C) 2008      Janne Grunau (j@jannau.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, version 2.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+
+#include <linux/videodev2.h>
+
+#include <media/v4l2-common.h>
+
+#include "hdpvr.h"
+
+
+int hdpvr_config_call(struct hdpvr_device *dev, uint value, u8 valbuf)
+{
+       int ret;
+       char request_type = 0x38, snd_request = 0x01;
+
+       msleep(10);
+
+       mutex_lock(&dev->usbc_mutex);
+       dev->usbc_buf[0] = valbuf;
+       ret = usb_control_msg(dev->udev,
+                             usb_sndctrlpipe(dev->udev, 0),
+                             snd_request, 0x00 | request_type,
+                             value, CTRL_DEFAULT_INDEX,
+                             dev->usbc_buf, 1, 10000);
+
+       mutex_unlock(&dev->usbc_mutex);
+       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+                "config call request for value 0x%x returned %d\n", value,
+                ret);
+
+       return ret < 0 ? ret : 0;
+}
+
+struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev)
+{
+       struct hdpvr_video_info *vidinf = NULL;
+#ifdef HDPVR_DEBUG
+       char print_buf[15];
+#endif
+       int ret;
+
+       vidinf = kzalloc(sizeof(struct hdpvr_video_info), GFP_KERNEL);
+       if (!vidinf) {
+               v4l2_err(&dev->v4l2_dev, "out of memory\n");
+               goto err;
+       }
+
+       mutex_lock(&dev->usbc_mutex);
+       ret = usb_control_msg(dev->udev,
+                             usb_rcvctrlpipe(dev->udev, 0),
+                             0x81, 0x80 | 0x38,
+                             0x1400, 0x0003,
+                             dev->usbc_buf, 5,
+                             1000);
+       if (ret == 5) {
+               vidinf->width   = dev->usbc_buf[1] << 8 | dev->usbc_buf[0];
+               vidinf->height  = dev->usbc_buf[3] << 8 | dev->usbc_buf[2];
+               vidinf->fps     = dev->usbc_buf[4];
+       }
+
+#ifdef HDPVR_DEBUG
+       if (hdpvr_debug & MSG_INFO) {
+               hex_dump_to_buffer(dev->usbc_buf, 5, 16, 1, print_buf,
+                                  sizeof(print_buf), 0);
+               v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+                        "get video info returned: %d, %s\n", ret, print_buf);
+       }
+#endif
+       mutex_unlock(&dev->usbc_mutex);
+
+       if (!vidinf->width || !vidinf->height || !vidinf->fps) {
+               kfree(vidinf);
+               vidinf = NULL;
+       }
+err:
+       return vidinf;
+}
+
+int get_input_lines_info(struct hdpvr_device *dev)
+{
+#ifdef HDPVR_DEBUG
+       char print_buf[9];
+#endif
+       int ret, lines;
+
+       mutex_lock(&dev->usbc_mutex);
+       ret = usb_control_msg(dev->udev,
+                             usb_rcvctrlpipe(dev->udev, 0),
+                             0x81, 0x80 | 0x38,
+                             0x1800, 0x0003,
+                             dev->usbc_buf, 3,
+                             1000);
+
+#ifdef HDPVR_DEBUG
+       if (hdpvr_debug & MSG_INFO) {
+               hex_dump_to_buffer(dev->usbc_buf, 3, 16, 1, print_buf,
+                                  sizeof(print_buf), 0);
+               v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+                        "get input lines info returned: %d, %s\n", ret,
+                        print_buf);
+       }
+#endif
+       lines = dev->usbc_buf[1] << 8 | dev->usbc_buf[0];
+       mutex_unlock(&dev->usbc_mutex);
+       return lines;
+}
+
+
+int hdpvr_set_bitrate(struct hdpvr_device *dev)
+{
+       int ret;
+
+       mutex_lock(&dev->usbc_mutex);
+       memset(dev->usbc_buf, 0, 4);
+       dev->usbc_buf[0] = dev->options.bitrate;
+       dev->usbc_buf[2] = dev->options.peak_bitrate;
+
+       ret = usb_control_msg(dev->udev,
+                             usb_sndctrlpipe(dev->udev, 0),
+                             0x01, 0x38, CTRL_BITRATE_VALUE,
+                             CTRL_DEFAULT_INDEX, dev->usbc_buf, 4, 1000);
+       mutex_unlock(&dev->usbc_mutex);
+
+       return ret;
+}
+
+int hdpvr_set_audio(struct hdpvr_device *dev, u8 input,
+                   enum v4l2_mpeg_audio_encoding codec)
+{
+       int ret = 0;
+
+       if (dev->flags & HDPVR_FLAG_AC3_CAP) {
+               mutex_lock(&dev->usbc_mutex);
+               memset(dev->usbc_buf, 0, 2);
+               dev->usbc_buf[0] = input;
+               if (codec == V4L2_MPEG_AUDIO_ENCODING_AAC)
+                       dev->usbc_buf[1] = 0;
+               else if (codec == V4L2_MPEG_AUDIO_ENCODING_AC3)
+                       dev->usbc_buf[1] = 1;
+               else {
+                       mutex_unlock(&dev->usbc_mutex);
+                       v4l2_err(&dev->v4l2_dev, "invalid audio codec %d\n",
+                                codec);
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               ret = usb_control_msg(dev->udev,
+                                     usb_sndctrlpipe(dev->udev, 0),
+                                     0x01, 0x38, CTRL_AUDIO_INPUT_VALUE,
+                                     CTRL_DEFAULT_INDEX, dev->usbc_buf, 2,
+                                     1000);
+               mutex_unlock(&dev->usbc_mutex);
+               if (ret == 2)
+                       ret = 0;
+       } else
+               ret = hdpvr_config_call(dev, CTRL_AUDIO_INPUT_VALUE,
+                                       dev->options.audio_input+1);
+error:
+       return ret;
+}
+
+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_INPUT_VALUE,
+                        dev->options.video_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,
+                        dev->options.bitrate_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);
+
+       return 0;
+}
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
new file mode 100644 (file)
index 0000000..188bd5a
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * Hauppauge HD PVR USB driver
+ *
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2008      Janne Grunau (j@jannau.net)
+ * Copyright (C) 2008      John Poet
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-common.h>
+
+#include "hdpvr.h"
+
+static int video_nr[HDPVR_MAX] = {[0 ... (HDPVR_MAX - 1)] = UNSET};
+module_param_array(video_nr, int, NULL, 0);
+MODULE_PARM_DESC(video_nr, "video device number (-1=Auto)");
+
+/* holds the number of currently registered devices */
+static atomic_t dev_nr = ATOMIC_INIT(-1);
+
+int hdpvr_debug;
+module_param(hdpvr_debug, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(hdpvr_debug, "enable debugging output");
+
+uint default_video_input = HDPVR_VIDEO_INPUTS;
+module_param(default_video_input, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(default_video_input, "default video input: 0=Component / "
+                "1=S-Video / 2=Composite");
+
+uint default_audio_input = HDPVR_AUDIO_INPUTS;
+module_param(default_audio_input, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(default_audio_input, "default audio input: 0=RCA back / "
+                "1=RCA front / 2=S/PDIF");
+
+static int boost_audio;
+module_param(boost_audio, bool, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(boost_audio, "boost the audio signal");
+
+
+/* table of devices that work with this driver */
+static struct usb_device_id hdpvr_table[] = {
+       { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID) },
+       { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID1) },
+       { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID2) },
+       { }                                     /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, hdpvr_table);
+
+
+void hdpvr_delete(struct hdpvr_device *dev)
+{
+       hdpvr_free_buffers(dev);
+
+       if (dev->video_dev)
+               video_device_release(dev->video_dev);
+
+       usb_put_dev(dev->udev);
+}
+
+static void challenge(u8 *bytes)
+{
+       u64 *i64P, tmp64;
+       uint i, idx;
+
+       for (idx = 0; idx < 32; ++idx) {
+
+               if (idx & 0x3)
+                       bytes[(idx >> 3) + 3] = bytes[(idx >> 2) & 0x3];
+
+               switch (idx & 0x3) {
+               case 0x3:
+                       bytes[2] += bytes[3] * 4 + bytes[4] + bytes[5];
+                       bytes[4] += bytes[(idx & 0x1) * 2] * 9 + 9;
+                       break;
+               case 0x1:
+                       bytes[0] *= 8;
+                       bytes[0] += 7*idx + 4;
+                       bytes[6] += bytes[3] * 3;
+                       break;
+               case 0x0:
+                       bytes[3 - (idx >> 3)] = bytes[idx >> 2];
+                       bytes[5] += bytes[6] * 3;
+                       for (i = 0; i < 3; i++)
+                               bytes[3] *= bytes[3] + 1;
+                       break;
+               case 0x2:
+                       for (i = 0; i < 3; i++)
+                               bytes[1] *= bytes[6] + 1;
+                       for (i = 0; i < 3; i++) {
+                               i64P = (u64 *)bytes;
+                               tmp64 = le64_to_cpup(i64P);
+                               tmp64 <<= bytes[7] & 0x0f;
+                               *i64P += cpu_to_le64(tmp64);
+                       }
+                       break;
+               }
+       }
+}
+
+/* try to init the device like the windows driver */
+static int device_authorization(struct hdpvr_device *dev)
+{
+
+       int ret, retval = -ENOMEM;
+       char request_type = 0x38, rcv_request = 0x81;
+       char *response;
+#ifdef HDPVR_DEBUG
+       size_t buf_size = 46;
+       char *print_buf = kzalloc(5*buf_size+1, GFP_KERNEL);
+       if (!print_buf) {
+               v4l2_err(&dev->v4l2_dev, "Out of memory\n");
+               goto error;
+       }
+#endif
+
+       mutex_lock(&dev->usbc_mutex);
+       ret = usb_control_msg(dev->udev,
+                             usb_rcvctrlpipe(dev->udev, 0),
+                             rcv_request, 0x80 | request_type,
+                             0x0400, 0x0003,
+                             dev->usbc_buf, 46,
+                             10000);
+       if (ret != 46) {
+               v4l2_err(&dev->v4l2_dev,
+                        "unexpected answer of status request, len %d\n", ret);
+               goto error;
+       }
+#ifdef HDPVR_DEBUG
+       else {
+               hex_dump_to_buffer(dev->usbc_buf, 46, 16, 1, print_buf,
+                                  sizeof(print_buf), 0);
+               v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+                        "Status request returned, len %d: %s\n",
+                        ret, print_buf);
+       }
+#endif
+       if (dev->usbc_buf[1] == HDPVR_FIRMWARE_VERSION) {
+               dev->flags &= ~HDPVR_FLAG_AC3_CAP;
+       } else if (dev->usbc_buf[1] == HDPVR_FIRMWARE_VERSION_AC3) {
+               dev->flags |= HDPVR_FLAG_AC3_CAP;
+       } else if (dev->usbc_buf[1] > HDPVR_FIRMWARE_VERSION_AC3) {
+               v4l2_info(&dev->v4l2_dev, "untested firmware version 0x%x, "
+                         "the driver might not work\n", dev->usbc_buf[1]);
+               dev->flags |= HDPVR_FLAG_AC3_CAP;
+       } else {
+               v4l2_err(&dev->v4l2_dev, "unknown firmware version 0x%x\n",
+                       dev->usbc_buf[1]);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       response = dev->usbc_buf+38;
+#ifdef HDPVR_DEBUG
+       hex_dump_to_buffer(response, 8, 16, 1, print_buf, sizeof(print_buf), 0);
+       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %s\n",
+                print_buf);
+#endif
+       challenge(response);
+#ifdef HDPVR_DEBUG
+       hex_dump_to_buffer(response, 8, 16, 1, print_buf, sizeof(print_buf), 0);
+       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %s\n",
+                print_buf);
+#endif
+
+       msleep(100);
+       ret = usb_control_msg(dev->udev,
+                             usb_sndctrlpipe(dev->udev, 0),
+                             0xd1, 0x00 | request_type,
+                             0x0000, 0x0000,
+                             response, 8,
+                             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:
+       return retval;
+}
+
+static int hdpvr_device_init(struct hdpvr_device *dev)
+{
+       int ret;
+       u8 *buf;
+       struct hdpvr_video_info *vidinf;
+
+       if (device_authorization(dev))
+               return -EACCES;
+
+       /* default options for init */
+       hdpvr_set_options(dev);
+
+       /* set filter options */
+       mutex_lock(&dev->usbc_mutex);
+       buf = dev->usbc_buf;
+       buf[0] = 0x03; buf[1] = 0x03; buf[2] = 0x00; buf[3] = 0x00;
+       ret = usb_control_msg(dev->udev,
+                             usb_sndctrlpipe(dev->udev, 0),
+                             0x01, 0x38,
+                             CTRL_LOW_PASS_FILTER_VALUE, CTRL_DEFAULT_INDEX,
+                             buf, 4,
+                             1000);
+       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+                "control request returned %d\n", ret);
+       mutex_unlock(&dev->usbc_mutex);
+
+       vidinf = get_video_info(dev);
+       if (!vidinf)
+               v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+                       "no valid video signal or device init failed\n");
+       else
+               kfree(vidinf);
+
+       /* enable fan and bling leds */
+       mutex_lock(&dev->usbc_mutex);
+       buf[0] = 0x1;
+       ret = usb_control_msg(dev->udev,
+                             usb_sndctrlpipe(dev->udev, 0),
+                             0xd4, 0x38, 0, 0, buf, 1,
+                             1000);
+       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+                "control request returned %d\n", ret);
+
+       /* boost analog audio */
+       buf[0] = boost_audio;
+       ret = usb_control_msg(dev->udev,
+                             usb_sndctrlpipe(dev->udev, 0),
+                             0xd5, 0x38, 0, 0, buf, 1,
+                             1000);
+       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+                "control request returned %d\n", ret);
+       mutex_unlock(&dev->usbc_mutex);
+
+       dev->status = STATUS_IDLE;
+       return 0;
+}
+
+static const struct hdpvr_options hdpvr_default_options = {
+       .video_std      = HDPVR_60HZ,
+       .video_input    = HDPVR_COMPONENT,
+       .audio_input    = HDPVR_RCA_BACK,
+       .bitrate        = 65, /* 6 mbps */
+       .peak_bitrate   = 90, /* 9 mbps */
+       .bitrate_mode   = HDPVR_CONSTANT,
+       .gop_mode       = HDPVR_SIMPLE_IDR_GOP,
+       .audio_codec    = V4L2_MPEG_AUDIO_ENCODING_AAC,
+       .brightness     = 0x86,
+       .contrast       = 0x80,
+       .hue            = 0x80,
+       .saturation     = 0x80,
+       .sharpness      = 0x80,
+};
+
+static int hdpvr_probe(struct usb_interface *interface,
+                      const struct usb_device_id *id)
+{
+       struct hdpvr_device *dev;
+       struct usb_host_interface *iface_desc;
+       struct usb_endpoint_descriptor *endpoint;
+       size_t buffer_size;
+       int i;
+       int retval = -ENOMEM;
+
+       /* allocate memory for our device state and initialize it */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               err("Out of memory");
+               goto error;
+       }
+
+       /* register v4l2_device early so it can be used for printks */
+       if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
+               err("v4l2_device_register failed");
+               goto error;
+       }
+
+       mutex_init(&dev->io_mutex);
+       mutex_init(&dev->i2c_mutex);
+       mutex_init(&dev->usbc_mutex);
+       dev->usbc_buf = kmalloc(64, GFP_KERNEL);
+       if (!dev->usbc_buf) {
+               v4l2_err(&dev->v4l2_dev, "Out of memory\n");
+               goto error;
+       }
+
+       init_waitqueue_head(&dev->wait_buffer);
+       init_waitqueue_head(&dev->wait_data);
+
+       dev->workqueue = create_singlethread_workqueue("hdpvr_buffer");
+       if (!dev->workqueue)
+               goto error;
+
+       /* init video transfer queues */
+       INIT_LIST_HEAD(&dev->free_buff_list);
+       INIT_LIST_HEAD(&dev->rec_buff_list);
+
+       dev->options = hdpvr_default_options;
+
+       if (default_video_input < HDPVR_VIDEO_INPUTS)
+               dev->options.video_input = default_video_input;
+
+       if (default_audio_input < HDPVR_AUDIO_INPUTS)
+               dev->options.audio_input = default_audio_input;
+
+       dev->udev = usb_get_dev(interface_to_usbdev(interface));
+
+       /* set up the endpoint information */
+       /* use only the first bulk-in and bulk-out endpoints */
+       iface_desc = interface->cur_altsetting;
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+               endpoint = &iface_desc->endpoint[i].desc;
+
+               if (!dev->bulk_in_endpointAddr &&
+                   usb_endpoint_is_bulk_in(endpoint)) {
+                       /* USB interface description is buggy, reported max
+                        * packet size is 512 bytes, windows driver uses 8192 */
+                       buffer_size = 8192;
+                       dev->bulk_in_size = buffer_size;
+                       dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
+               }
+
+       }
+       if (!dev->bulk_in_endpointAddr) {
+               v4l2_err(&dev->v4l2_dev, "Could not find bulk-in endpoint\n");
+               goto error;
+       }
+
+       /* init the device */
+       if (hdpvr_device_init(dev)) {
+               v4l2_err(&dev->v4l2_dev, "device init failed\n");
+               goto error;
+       }
+
+       mutex_lock(&dev->io_mutex);
+       if (hdpvr_alloc_buffers(dev, NUM_BUFFERS)) {
+               v4l2_err(&dev->v4l2_dev,
+                        "allocating transfer buffers failed\n");
+               goto error;
+       }
+       mutex_unlock(&dev->io_mutex);
+
+       if (hdpvr_register_videodev(dev, &interface->dev,
+                                   video_nr[atomic_inc_return(&dev_nr)])) {
+               v4l2_err(&dev->v4l2_dev, "registering videodev failed\n");
+               goto error;
+       }
+
+#ifdef CONFIG_I2C
+       /* until i2c is working properly */
+       retval = 0; /* hdpvr_register_i2c_adapter(dev); */
+       if (retval < 0) {
+               v4l2_err(&dev->v4l2_dev, "registering i2c adapter failed\n");
+               goto error;
+       }
+#endif /* CONFIG_I2C */
+
+       /* save our data pointer in this interface device */
+       usb_set_intfdata(interface, dev);
+
+       /* let the user know what node this device is now attached to */
+       v4l2_info(&dev->v4l2_dev, "device now attached to /dev/video%d\n",
+                 dev->video_dev->minor);
+       return 0;
+
+error:
+       if (dev) {
+               mutex_unlock(&dev->io_mutex);
+               /* this frees allocated memory */
+               hdpvr_delete(dev);
+       }
+       return retval;
+}
+
+static void hdpvr_disconnect(struct usb_interface *interface)
+{
+       struct hdpvr_device *dev;
+       int minor;
+
+       dev = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+
+       minor = dev->video_dev->minor;
+
+       /* prevent more I/O from starting and stop any ongoing */
+       mutex_lock(&dev->io_mutex);
+       dev->status = STATUS_DISCONNECTED;
+       v4l2_device_disconnect(&dev->v4l2_dev);
+       video_unregister_device(dev->video_dev);
+       wake_up_interruptible(&dev->wait_data);
+       wake_up_interruptible(&dev->wait_buffer);
+       mutex_unlock(&dev->io_mutex);
+       msleep(100);
+       flush_workqueue(dev->workqueue);
+       mutex_lock(&dev->io_mutex);
+       hdpvr_cancel_queue(dev);
+       destroy_workqueue(dev->workqueue);
+       mutex_unlock(&dev->io_mutex);
+
+       /* deregister I2C adapter */
+#ifdef CONFIG_I2C
+       mutex_lock(&dev->i2c_mutex);
+       if (dev->i2c_adapter)
+               i2c_del_adapter(dev->i2c_adapter);
+       kfree(dev->i2c_adapter);
+       dev->i2c_adapter = NULL;
+       mutex_unlock(&dev->i2c_mutex);
+#endif /* CONFIG_I2C */
+
+       atomic_dec(&dev_nr);
+
+       v4l2_info(&dev->v4l2_dev, "device /dev/video%d disconnected\n", minor);
+
+       v4l2_device_unregister(&dev->v4l2_dev);
+       kfree(dev->usbc_buf);
+       kfree(dev);
+}
+
+
+static struct usb_driver hdpvr_usb_driver = {
+       .name =         "hdpvr",
+       .probe =        hdpvr_probe,
+       .disconnect =   hdpvr_disconnect,
+       .id_table =     hdpvr_table,
+};
+
+static int __init hdpvr_init(void)
+{
+       int result;
+
+       /* register this driver with the USB subsystem */
+       result = usb_register(&hdpvr_usb_driver);
+       if (result)
+               err("usb_register failed. Error number %d", result);
+
+       return result;
+}
+
+static void __exit hdpvr_exit(void)
+{
+       /* deregister this driver with the USB subsystem */
+       usb_deregister(&hdpvr_usb_driver);
+}
+
+module_init(hdpvr_init);
+module_exit(hdpvr_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Janne Grunau");
+MODULE_DESCRIPTION("Hauppauge HD PVR driver");
diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c
new file mode 100644 (file)
index 0000000..c4b5d15
--- /dev/null
@@ -0,0 +1,145 @@
+
+/*
+ * Hauppauge HD PVR USB driver
+ *
+ * Copyright (C) 2008      Janne Grunau (j@jannau.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, version 2.
+ *
+ */
+
+#include <linux/i2c.h>
+
+#include "hdpvr.h"
+
+#define CTRL_READ_REQUEST      0xb8
+#define CTRL_WRITE_REQUEST     0x38
+
+#define REQTYPE_I2C_READ       0xb1
+#define REQTYPE_I2C_WRITE      0xb0
+#define REQTYPE_I2C_WRITE_STATT        0xd0
+
+static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr,
+                         char *data, int len)
+{
+       int ret;
+       char *buf = kmalloc(len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = usb_control_msg(dev->udev,
+                             usb_rcvctrlpipe(dev->udev, 0),
+                             REQTYPE_I2C_READ, CTRL_READ_REQUEST,
+                             0x100|addr, 0, buf, len, 1000);
+
+       if (ret == len) {
+               memcpy(data, buf, len);
+               ret = 0;
+       } else if (ret >= 0)
+               ret = -EIO;
+
+       kfree(buf);
+
+       return ret;
+}
+
+static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr,
+                          char *data, int len)
+{
+       int ret;
+       char *buf = kmalloc(len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       memcpy(buf, data, len);
+       ret = usb_control_msg(dev->udev,
+                             usb_sndctrlpipe(dev->udev, 0),
+                             REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
+                             0x100|addr, 0, buf, len, 1000);
+
+       if (ret < 0)
+               goto error;
+
+       ret = usb_control_msg(dev->udev,
+                             usb_rcvctrlpipe(dev->udev, 0),
+                             REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST,
+                             0, 0, buf, 2, 1000);
+
+       if (ret == 2)
+               ret = 0;
+       else if (ret >= 0)
+               ret = -EIO;
+
+error:
+       kfree(buf);
+       return ret;
+}
+
+static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs,
+                         int num)
+{
+       struct hdpvr_device *dev = i2c_get_adapdata(i2c_adapter);
+       int retval = 0, i, addr;
+
+       if (num <= 0)
+               return 0;
+
+       mutex_lock(&dev->i2c_mutex);
+
+       for (i = 0; i < num && !retval; i++) {
+               addr = msgs[i].addr << 1;
+
+               if (msgs[i].flags & I2C_M_RD)
+                       retval = hdpvr_i2c_read(dev, addr, msgs[i].buf,
+                                               msgs[i].len);
+               else
+                       retval = hdpvr_i2c_write(dev, addr, msgs[i].buf,
+                                                msgs[i].len);
+       }
+
+       mutex_unlock(&dev->i2c_mutex);
+
+       return retval ? retval : num;
+}
+
+static u32 hdpvr_functionality(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm hdpvr_algo = {
+       .master_xfer   = hdpvr_transfer,
+       .functionality = hdpvr_functionality,
+};
+
+int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
+{
+       struct i2c_adapter *i2c_adap;
+       int retval = -ENOMEM;
+
+       i2c_adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+       if (i2c_adap == NULL)
+               goto error;
+
+       strlcpy(i2c_adap->name, "Hauppauge HD PVR I2C",
+               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;
+
+       i2c_set_adapdata(i2c_adap, dev);
+
+       retval = i2c_add_adapter(i2c_adap);
+
+       if (!retval)
+               dev->i2c_adapter = i2c_adap;
+       else
+               kfree(i2c_adap);
+
+error:
+       return retval;
+}
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
new file mode 100644 (file)
index 0000000..3e6ffee
--- /dev/null
@@ -0,0 +1,1248 @@
+/*
+ * Hauppauge HD PVR USB driver - video 4 linux 2 interface
+ *
+ * Copyright (C) 2008      Janne Grunau (j@jannau.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, version 2.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include "hdpvr.h"
+
+#define BULK_URB_TIMEOUT 1250 /* 1.25 seconds */
+
+#define print_buffer_status() { \
+               v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,       \
+                        "%s:%d buffer stat: %d free, %d proc\n",       \
+                        __func__, __LINE__,                            \
+                        list_size(&dev->free_buff_list),               \
+                        list_size(&dev->rec_buff_list)); }
+
+struct hdpvr_fh {
+       struct hdpvr_device     *dev;
+};
+
+static uint list_size(struct list_head *list)
+{
+       struct list_head *tmp;
+       uint count = 0;
+
+       list_for_each(tmp, list) {
+               count++;
+       }
+
+       return count;
+}
+
+/*=========================================================================*/
+/* urb callback */
+static void hdpvr_read_bulk_callback(struct urb *urb)
+{
+       struct hdpvr_buffer *buf = (struct hdpvr_buffer *)urb->context;
+       struct hdpvr_device *dev = buf->dev;
+
+       /* marking buffer as received and wake waiting */
+       buf->status = BUFSTAT_READY;
+       wake_up_interruptible(&dev->wait_data);
+}
+
+/*=========================================================================*/
+/* bufffer bits */
+
+/* function expects dev->io_mutex to be hold by caller */
+int hdpvr_cancel_queue(struct hdpvr_device *dev)
+{
+       struct hdpvr_buffer *buf;
+
+       list_for_each_entry(buf, &dev->rec_buff_list, buff_list) {
+               usb_kill_urb(buf->urb);
+               buf->status = BUFSTAT_AVAILABLE;
+       }
+
+       list_splice_init(&dev->rec_buff_list, dev->free_buff_list.prev);
+
+       return 0;
+}
+
+static int hdpvr_free_queue(struct list_head *q)
+{
+       struct list_head *tmp;
+       struct list_head *p;
+       struct hdpvr_buffer *buf;
+       struct urb *urb;
+
+       for (p = q->next; p != q;) {
+               buf = list_entry(p, struct hdpvr_buffer, buff_list);
+
+               urb = buf->urb;
+               usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+                               urb->transfer_buffer, urb->transfer_dma);
+               usb_free_urb(urb);
+               tmp = p->next;
+               list_del(p);
+               kfree(buf);
+               p = tmp;
+       }
+
+       return 0;
+}
+
+/* function expects dev->io_mutex to be hold by caller */
+int hdpvr_free_buffers(struct hdpvr_device *dev)
+{
+       hdpvr_cancel_queue(dev);
+
+       hdpvr_free_queue(&dev->free_buff_list);
+       hdpvr_free_queue(&dev->rec_buff_list);
+
+       return 0;
+}
+
+/* function expects dev->io_mutex to be hold by caller */
+int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count)
+{
+       uint i;
+       int retval = -ENOMEM;
+       u8 *mem;
+       struct hdpvr_buffer *buf;
+       struct urb *urb;
+
+       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+                "allocating %u buffers\n", count);
+
+       for (i = 0; i < count; i++) {
+
+               buf = kzalloc(sizeof(struct hdpvr_buffer), GFP_KERNEL);
+               if (!buf) {
+                       v4l2_err(&dev->v4l2_dev, "cannot allocate buffer\n");
+                       goto exit;
+               }
+               buf->dev = dev;
+
+               urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!urb) {
+                       v4l2_err(&dev->v4l2_dev, "cannot allocate urb\n");
+                       goto exit;
+               }
+               buf->urb = urb;
+
+               mem = usb_buffer_alloc(dev->udev, dev->bulk_in_size, GFP_KERNEL,
+                                      &urb->transfer_dma);
+               if (!mem) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "cannot allocate usb transfer buffer\n");
+                       goto exit;
+               }
+
+               usb_fill_bulk_urb(buf->urb, dev->udev,
+                                 usb_rcvbulkpipe(dev->udev,
+                                                 dev->bulk_in_endpointAddr),
+                                 mem, dev->bulk_in_size,
+                                 hdpvr_read_bulk_callback, buf);
+
+               buf->status = BUFSTAT_AVAILABLE;
+               list_add_tail(&buf->buff_list, &dev->free_buff_list);
+       }
+       return 0;
+exit:
+       hdpvr_free_buffers(dev);
+       return retval;
+}
+
+static int hdpvr_submit_buffers(struct hdpvr_device *dev)
+{
+       struct hdpvr_buffer *buf;
+       struct urb *urb;
+       int ret = 0, err_count = 0;
+
+       mutex_lock(&dev->io_mutex);
+
+       while (dev->status == STATUS_STREAMING &&
+              !list_empty(&dev->free_buff_list)) {
+
+               buf = list_entry(dev->free_buff_list.next, struct hdpvr_buffer,
+                                buff_list);
+               if (buf->status != BUFSTAT_AVAILABLE) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "buffer not marked as availbale\n");
+                       ret = -EFAULT;
+                       goto err;
+               }
+
+               urb = buf->urb;
+               urb->status = 0;
+               urb->actual_length = 0;
+               ret = usb_submit_urb(urb, GFP_KERNEL);
+               if (ret) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "usb_submit_urb in %s returned %d\n",
+                                __func__, ret);
+                       if (++err_count > 2)
+                               break;
+                       continue;
+               }
+               buf->status = BUFSTAT_INPROGRESS;
+               list_move_tail(&buf->buff_list, &dev->rec_buff_list);
+       }
+err:
+       print_buffer_status();
+       mutex_unlock(&dev->io_mutex);
+       return ret;
+}
+
+static struct hdpvr_buffer *hdpvr_get_next_buffer(struct hdpvr_device *dev)
+{
+       struct hdpvr_buffer *buf;
+
+       mutex_lock(&dev->io_mutex);
+
+       if (list_empty(&dev->rec_buff_list)) {
+               mutex_unlock(&dev->io_mutex);
+               return NULL;
+       }
+
+       buf = list_entry(dev->rec_buff_list.next, struct hdpvr_buffer,
+                        buff_list);
+       mutex_unlock(&dev->io_mutex);
+
+       return buf;
+}
+
+static void hdpvr_transmit_buffers(struct work_struct *work)
+{
+       struct hdpvr_device *dev = container_of(work, struct hdpvr_device,
+                                               worker);
+
+       while (dev->status == STATUS_STREAMING) {
+
+               if (hdpvr_submit_buffers(dev)) {
+                       v4l2_err(&dev->v4l2_dev, "couldn't submit buffers\n");
+                       goto error;
+               }
+               if (wait_event_interruptible(dev->wait_buffer,
+                               !list_empty(&dev->free_buff_list) ||
+                                            dev->status != STATUS_STREAMING))
+                       goto error;
+       }
+
+       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+                "transmit worker exited\n");
+       return;
+error:
+       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+                "transmit buffers errored\n");
+       dev->status = STATUS_ERROR;
+}
+
+/* function expects dev->io_mutex to be hold by caller */
+static int hdpvr_start_streaming(struct hdpvr_device *dev)
+{
+       int ret;
+       struct hdpvr_video_info *vidinf;
+
+       if (dev->status == STATUS_STREAMING)
+               return 0;
+       else if (dev->status != STATUS_IDLE)
+               return -EAGAIN;
+
+       vidinf = get_video_info(dev);
+
+       if (vidinf) {
+               v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+                        "video signal: %dx%d@%dhz\n", vidinf->width,
+                        vidinf->height, vidinf->fps);
+               kfree(vidinf);
+
+               /* start streaming 2 request */
+               ret = usb_control_msg(dev->udev,
+                                     usb_sndctrlpipe(dev->udev, 0),
+                                     0xb8, 0x38, 0x1, 0, NULL, 0, 8000);
+               v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+                        "encoder start control request returned %d\n", ret);
+
+               hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00);
+
+               INIT_WORK(&dev->worker, hdpvr_transmit_buffers);
+               queue_work(dev->workqueue, &dev->worker);
+
+               v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+                        "streaming started\n");
+               dev->status = STATUS_STREAMING;
+
+               return 0;
+       }
+       msleep(250);
+       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+                "no video signal at input %d\n", dev->options.video_input);
+       return -EAGAIN;
+}
+
+
+/* function expects dev->io_mutex to be hold by caller */
+static int hdpvr_stop_streaming(struct hdpvr_device *dev)
+{
+       uint actual_length, c = 0;
+       u8 *buf;
+
+       if (dev->status == STATUS_IDLE)
+               return 0;
+       else if (dev->status != STATUS_STREAMING)
+               return -EAGAIN;
+
+       buf = kmalloc(dev->bulk_in_size, GFP_KERNEL);
+       if (!buf)
+               v4l2_err(&dev->v4l2_dev, "failed to allocate temporary buffer "
+                        "for emptying the internal device buffer. "
+                        "Next capture start will be slow\n");
+
+       dev->status = STATUS_SHUTTING_DOWN;
+       hdpvr_config_call(dev, CTRL_STOP_STREAMING_VALUE, 0x00);
+       mutex_unlock(&dev->io_mutex);
+
+       wake_up_interruptible(&dev->wait_buffer);
+       msleep(50);
+
+       flush_workqueue(dev->workqueue);
+
+       mutex_lock(&dev->io_mutex);
+       /* kill the still outstanding urbs */
+       hdpvr_cancel_queue(dev);
+
+       /* emptying the device buffer beforeshutting it down */
+       while (buf && ++c < 500 &&
+              !usb_bulk_msg(dev->udev,
+                            usb_rcvbulkpipe(dev->udev,
+                                            dev->bulk_in_endpointAddr),
+                            buf, dev->bulk_in_size, &actual_length,
+                            BULK_URB_TIMEOUT)) {
+               /* wait */
+               msleep(5);
+               v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+                        "%2d: got %d bytes\n", c, actual_length);
+       }
+       kfree(buf);
+       v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+                "used %d urbs to empty device buffers\n", c-1);
+       msleep(10);
+
+       dev->status = STATUS_IDLE;
+
+       return 0;
+}
+
+
+/*=======================================================================*/
+/*
+ * video 4 linux 2 file operations
+ */
+
+static int hdpvr_open(struct file *file)
+{
+       struct hdpvr_device *dev;
+       struct hdpvr_fh *fh;
+       int retval = -ENOMEM;
+
+       dev = (struct hdpvr_device *)video_get_drvdata(video_devdata(file));
+       if (!dev) {
+               v4l2_err(&dev->v4l2_dev, "open failing with with ENODEV\n");
+               retval = -ENODEV;
+               goto err;
+       }
+
+       fh = kzalloc(sizeof(struct hdpvr_fh), GFP_KERNEL);
+       if (!fh) {
+               v4l2_err(&dev->v4l2_dev, "Out of memory\n");
+               goto err;
+       }
+       /* lock the device to allow correctly handling errors
+        * in resumption */
+       mutex_lock(&dev->io_mutex);
+       dev->open_count++;
+
+       fh->dev = dev;
+
+       /* save our object in the file's private structure */
+       file->private_data = fh;
+
+       retval = 0;
+err:
+       mutex_unlock(&dev->io_mutex);
+       return retval;
+}
+
+static int hdpvr_release(struct file *file)
+{
+       struct hdpvr_fh         *fh  = (struct hdpvr_fh *)file->private_data;
+       struct hdpvr_device     *dev = fh->dev;
+
+       if (!dev)
+               return -ENODEV;
+
+       mutex_lock(&dev->io_mutex);
+       if (!(--dev->open_count) && dev->status == STATUS_STREAMING)
+               hdpvr_stop_streaming(dev);
+
+       mutex_unlock(&dev->io_mutex);
+
+       return 0;
+}
+
+/*
+ * hdpvr_v4l2_read()
+ * will allocate buffers when called for the first time
+ */
+static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
+                         loff_t *pos)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       struct hdpvr_buffer *buf = NULL;
+       struct urb *urb;
+       unsigned int ret = 0;
+       int rem, cnt;
+
+       if (*pos)
+               return -ESPIPE;
+
+       if (!dev)
+               return -ENODEV;
+
+       mutex_lock(&dev->io_mutex);
+       if (dev->status == STATUS_IDLE) {
+               if (hdpvr_start_streaming(dev)) {
+                       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+                                "start_streaming failed\n");
+                       ret = -EIO;
+                       msleep(200);
+                       dev->status = STATUS_IDLE;
+                       mutex_unlock(&dev->io_mutex);
+                       goto err;
+               }
+               print_buffer_status();
+       }
+       mutex_unlock(&dev->io_mutex);
+
+       /* wait for the first buffer */
+       if (!(file->f_flags & O_NONBLOCK)) {
+               if (wait_event_interruptible(dev->wait_data,
+                                            hdpvr_get_next_buffer(dev)))
+                       return -ERESTARTSYS;
+       }
+
+       buf = hdpvr_get_next_buffer(dev);
+
+       while (count > 0 && buf) {
+
+               if (buf->status != BUFSTAT_READY &&
+                   dev->status != STATUS_DISCONNECTED) {
+                       /* return nonblocking */
+                       if (file->f_flags & O_NONBLOCK) {
+                               if (!ret)
+                                       ret = -EAGAIN;
+                               goto err;
+                       }
+
+                       if (wait_event_interruptible(dev->wait_data,
+                                             buf->status == BUFSTAT_READY)) {
+                               ret = -ERESTARTSYS;
+                               goto err;
+                       }
+               }
+
+               if (buf->status != BUFSTAT_READY)
+                       break;
+
+               /* set remaining bytes to copy */
+               urb = buf->urb;
+               rem = urb->actual_length - buf->pos;
+               cnt = rem > count ? count : rem;
+
+               if (copy_to_user(buffer, urb->transfer_buffer + buf->pos,
+                                cnt)) {
+                       v4l2_err(&dev->v4l2_dev, "read: copy_to_user failed\n");
+                       if (!ret)
+                               ret = -EFAULT;
+                       goto err;
+               }
+
+               buf->pos += cnt;
+               count -= cnt;
+               buffer += cnt;
+               ret += cnt;
+
+               /* finished, take next buffer */
+               if (buf->pos == urb->actual_length) {
+                       mutex_lock(&dev->io_mutex);
+                       buf->pos = 0;
+                       buf->status = BUFSTAT_AVAILABLE;
+
+                       list_move_tail(&buf->buff_list, &dev->free_buff_list);
+
+                       print_buffer_status();
+
+                       mutex_unlock(&dev->io_mutex);
+
+                       wake_up_interruptible(&dev->wait_buffer);
+
+                       buf = hdpvr_get_next_buffer(dev);
+               }
+       }
+err:
+       if (!ret && !buf)
+               ret = -EAGAIN;
+       return ret;
+}
+
+static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
+{
+       struct hdpvr_buffer *buf = NULL;
+       struct hdpvr_fh *fh = (struct hdpvr_fh *)filp->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       unsigned int mask = 0;
+
+       mutex_lock(&dev->io_mutex);
+
+       if (video_is_unregistered(dev->video_dev))
+               return -EIO;
+
+       if (dev->status == STATUS_IDLE) {
+               if (hdpvr_start_streaming(dev)) {
+                       v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+                                "start_streaming failed\n");
+                       dev->status = STATUS_IDLE;
+               }
+
+               print_buffer_status();
+       }
+       mutex_unlock(&dev->io_mutex);
+
+       buf = hdpvr_get_next_buffer(dev);
+       /* only wait if no data is available */
+       if (!buf || buf->status != BUFSTAT_READY) {
+               poll_wait(filp, &dev->wait_data, wait);
+               buf = hdpvr_get_next_buffer(dev);
+       }
+       if (buf && buf->status == BUFSTAT_READY)
+               mask |= POLLIN | POLLRDNORM;
+
+       return mask;
+}
+
+
+static const struct v4l2_file_operations hdpvr_fops = {
+       .owner          = THIS_MODULE,
+       .open           = hdpvr_open,
+       .release        = hdpvr_release,
+       .read           = hdpvr_read,
+       .poll           = hdpvr_poll,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+/*=======================================================================*/
+/*
+ * V4L2 ioctl handling
+ */
+
+static int vidioc_querycap(struct file *file, void  *priv,
+                          struct v4l2_capability *cap)
+{
+       struct hdpvr_device *dev = video_drvdata(file);
+
+       strcpy(cap->driver, "hdpvr");
+       strcpy(cap->card, "Haupauge HD PVR");
+       usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+       cap->version = HDPVR_VERSION;
+       cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
+                               V4L2_CAP_AUDIO         |
+                               V4L2_CAP_READWRITE;
+       return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *private_data,
+                       v4l2_std_id *std)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       u8 std_type = 1;
+
+       if (*std & (V4L2_STD_NTSC | V4L2_STD_PAL_60))
+               std_type = 0;
+
+       return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type);
+}
+
+static const char *iname[] = {
+       [HDPVR_COMPONENT] = "Component",
+       [HDPVR_SVIDEO]    = "S-Video",
+       [HDPVR_COMPOSITE] = "Composite",
+};
+
+static int vidioc_enum_input(struct file *file, void *priv,
+                               struct v4l2_input *i)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       unsigned int n;
+
+       n = i->index;
+       if (n >= HDPVR_VIDEO_INPUTS)
+               return -EINVAL;
+
+       i->type = V4L2_INPUT_TYPE_CAMERA;
+
+       strncpy(i->name, iname[n], sizeof(i->name) - 1);
+       i->name[sizeof(i->name) - 1] = '\0';
+
+       i->audioset = 1<<HDPVR_RCA_FRONT | 1<<HDPVR_RCA_BACK | 1<<HDPVR_SPDIF;
+
+       i->std = dev->video_dev->tvnorms;
+
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *private_data,
+                         unsigned int index)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       int retval;
+
+       if (index >= HDPVR_VIDEO_INPUTS)
+               return -EINVAL;
+
+       if (dev->status != STATUS_IDLE)
+               return -EAGAIN;
+
+       retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1);
+       if (!retval)
+               dev->options.video_input = index;
+
+       return retval;
+}
+
+static int vidioc_g_input(struct file *file, void *private_data,
+                         unsigned int *index)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+
+       *index = dev->options.video_input;
+       return 0;
+}
+
+
+static const char *audio_iname[] = {
+       [HDPVR_RCA_FRONT] = "RCA front",
+       [HDPVR_RCA_BACK]  = "RCA back",
+       [HDPVR_SPDIF]     = "SPDIF",
+};
+
+static int vidioc_enumaudio(struct file *file, void *priv,
+                               struct v4l2_audio *audio)
+{
+       unsigned int n;
+
+       n = audio->index;
+       if (n >= HDPVR_AUDIO_INPUTS)
+               return -EINVAL;
+
+       audio->capability = V4L2_AUDCAP_STEREO;
+
+       strncpy(audio->name, audio_iname[n], sizeof(audio->name) - 1);
+       audio->name[sizeof(audio->name) - 1] = '\0';
+
+       return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *private_data,
+                         struct v4l2_audio *audio)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       int retval;
+
+       if (audio->index >= HDPVR_AUDIO_INPUTS)
+               return -EINVAL;
+
+       if (dev->status != STATUS_IDLE)
+               return -EAGAIN;
+
+       retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec);
+       if (!retval)
+               dev->options.audio_input = audio->index;
+
+       return retval;
+}
+
+static int vidioc_g_audio(struct file *file, void *private_data,
+                         struct v4l2_audio *audio)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+
+       audio->index = dev->options.audio_input;
+       audio->capability = V4L2_AUDCAP_STEREO;
+       strncpy(audio->name, audio_iname[audio->index], sizeof(audio->name));
+       audio->name[sizeof(audio->name) - 1] = '\0';
+       return 0;
+}
+
+static const s32 supported_v4l2_ctrls[] = {
+       V4L2_CID_BRIGHTNESS,
+       V4L2_CID_CONTRAST,
+       V4L2_CID_SATURATION,
+       V4L2_CID_HUE,
+       V4L2_CID_SHARPNESS,
+       V4L2_CID_MPEG_AUDIO_ENCODING,
+       V4L2_CID_MPEG_VIDEO_ENCODING,
+       V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+       V4L2_CID_MPEG_VIDEO_BITRATE,
+       V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+};
+
+static int fill_queryctrl(struct hdpvr_options *opt, struct v4l2_queryctrl *qc,
+                         int ac3)
+{
+       int err;
+
+       switch (qc->id) {
+       case V4L2_CID_BRIGHTNESS:
+               return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x86);
+       case V4L2_CID_CONTRAST:
+               return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+       case V4L2_CID_SATURATION:
+               return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+       case V4L2_CID_HUE:
+               return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+       case V4L2_CID_SHARPNESS:
+               return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               return v4l2_ctrl_query_fill(
+                       qc, V4L2_MPEG_AUDIO_ENCODING_AAC,
+                       ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3
+                       : V4L2_MPEG_AUDIO_ENCODING_AAC,
+                       1, V4L2_MPEG_AUDIO_ENCODING_AAC);
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               return v4l2_ctrl_query_fill(
+                       qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC,
+                       V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
+                       V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
+
+/*     case V4L2_CID_MPEG_VIDEO_? maybe keyframe interval: */
+/*             return v4l2_ctrl_query_fill(qc, 0, 128, 128, 0); */
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               return v4l2_ctrl_query_fill(
+                       qc, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+                       V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
+                       V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
+
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               return v4l2_ctrl_query_fill(qc, 1000000, 13500000, 100000,
+                                           6500000);
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+               err = v4l2_ctrl_query_fill(qc, 1100000, 20200000, 100000,
+                                          9000000);
+               if (!err && opt->bitrate_mode == HDPVR_CONSTANT)
+                       qc->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               return err;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int vidioc_queryctrl(struct file *file, void *private_data,
+                           struct v4l2_queryctrl *qc)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       int i, next;
+       u32 id = qc->id;
+
+       memset(qc, 0, sizeof(*qc));
+
+       next = !!(id &  V4L2_CTRL_FLAG_NEXT_CTRL);
+       qc->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
+
+       for (i = 0; i < ARRAY_SIZE(supported_v4l2_ctrls); i++) {
+               if (next) {
+                       if (qc->id < supported_v4l2_ctrls[i])
+                               qc->id = supported_v4l2_ctrls[i];
+                       else
+                               continue;
+               }
+
+               if (qc->id == supported_v4l2_ctrls[i])
+                       return fill_queryctrl(&dev->options, qc,
+                                             dev->flags & HDPVR_FLAG_AC3_CAP);
+
+               if (qc->id < supported_v4l2_ctrls[i])
+                       break;
+       }
+
+       return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *private_data,
+                        struct v4l2_control *ctrl)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ctrl->value = dev->options.brightness;
+               break;
+       case V4L2_CID_CONTRAST:
+               ctrl->value = dev->options.contrast;
+               break;
+       case V4L2_CID_SATURATION:
+               ctrl->value = dev->options.saturation;
+               break;
+       case V4L2_CID_HUE:
+               ctrl->value = dev->options.hue;
+               break;
+       case V4L2_CID_SHARPNESS:
+               ctrl->value = dev->options.sharpness;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *private_data,
+                        struct v4l2_control *ctrl)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       int retval;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               retval = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->value);
+               if (!retval)
+                       dev->options.brightness = ctrl->value;
+               break;
+       case V4L2_CID_CONTRAST:
+               retval = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->value);
+               if (!retval)
+                       dev->options.contrast = ctrl->value;
+               break;
+       case V4L2_CID_SATURATION:
+               retval = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->value);
+               if (!retval)
+                       dev->options.saturation = ctrl->value;
+               break;
+       case V4L2_CID_HUE:
+               retval = hdpvr_config_call(dev, CTRL_HUE, ctrl->value);
+               if (!retval)
+                       dev->options.hue = ctrl->value;
+               break;
+       case V4L2_CID_SHARPNESS:
+               retval = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->value);
+               if (!retval)
+                       dev->options.sharpness = ctrl->value;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return retval;
+}
+
+
+static int hdpvr_get_ctrl(struct hdpvr_options *opt,
+                         struct v4l2_ext_control *ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               ctrl->value = opt->audio_codec;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC;
+               break;
+/*     case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
+/*             ctrl->value = (opt->gop_mode & 0x2) ? 0 : 128; */
+/*             break; */
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               ctrl->value = opt->bitrate_mode == HDPVR_CONSTANT
+                       ? V4L2_MPEG_VIDEO_BITRATE_MODE_CBR
+                       : V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               ctrl->value = opt->bitrate * 100000;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+               ctrl->value = opt->peak_bitrate * 100000;
+               break;
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+                             struct v4l2_ext_controls *ctrls)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       int i, err = 0;
+
+       if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+               for (i = 0; i < ctrls->count; i++) {
+                       struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+                       err = hdpvr_get_ctrl(&dev->options, ctrl);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+               }
+               return err;
+
+       }
+
+       return -EINVAL;
+}
+
+
+static int hdpvr_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
+{
+       int ret = -EINVAL;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               if (ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AAC ||
+                   (ac3 && ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AC3))
+                       ret = 0;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               if (ctrl->value == V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC)
+                       ret = 0;
+               break;
+/*     case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
+/*             if (ctrl->value == 0 || ctrl->value == 128) */
+/*                     ret = 0; */
+/*             break; */
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR ||
+                   ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
+                       ret = 0;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+       {
+               uint bitrate = ctrl->value / 100000;
+               if (bitrate >= 10 && bitrate <= 135)
+                       ret = 0;
+               break;
+       }
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+       {
+               uint peak_bitrate = ctrl->value / 100000;
+               if (peak_bitrate >= 10 && peak_bitrate <= 202)
+                       ret = 0;
+               break;
+       }
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               if (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)
+                       ret = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+                               struct v4l2_ext_controls *ctrls)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       int i, err = 0;
+
+       if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+               for (i = 0; i < ctrls->count; i++) {
+                       struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+                       err = hdpvr_try_ctrl(ctrl,
+                                            dev->flags & HDPVR_FLAG_AC3_CAP);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+               }
+               return err;
+       }
+
+       return -EINVAL;
+}
+
+
+static int hdpvr_set_ctrl(struct hdpvr_device *dev,
+                         struct v4l2_ext_control *ctrl)
+{
+       struct hdpvr_options *opt = &dev->options;
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               if (dev->flags & HDPVR_FLAG_AC3_CAP) {
+                       opt->audio_codec = ctrl->value;
+                       ret = hdpvr_set_audio(dev, opt->audio_input,
+                                             opt->audio_codec);
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               break;
+/*     case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
+/*             if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */
+/*                     opt->gop_mode |= 0x2; */
+/*                     hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
+/*                                       opt->gop_mode); */
+/*             } */
+/*             if (ctrl->value == 128 && opt->gop_mode & 0x2) { */
+/*                     opt->gop_mode &= ~0x2; */
+/*                     hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
+/*                                       opt->gop_mode); */
+/*             } */
+/*             break; */
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR &&
+                   opt->bitrate_mode != HDPVR_CONSTANT) {
+                       opt->bitrate_mode = HDPVR_CONSTANT;
+                       hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
+                                         opt->bitrate_mode);
+               }
+               if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+                   opt->bitrate_mode == HDPVR_CONSTANT) {
+                       opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE;
+                       hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
+                                         opt->bitrate_mode);
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE: {
+               uint bitrate = ctrl->value / 100000;
+
+               opt->bitrate = bitrate;
+               if (bitrate >= opt->peak_bitrate)
+                       opt->peak_bitrate = bitrate+1;
+
+               hdpvr_set_bitrate(dev);
+               break;
+       }
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: {
+               uint peak_bitrate = ctrl->value / 100000;
+
+               if (opt->bitrate_mode == HDPVR_CONSTANT)
+                       break;
+
+               if (opt->bitrate < peak_bitrate) {
+                       opt->peak_bitrate = peak_bitrate;
+                       hdpvr_set_bitrate(dev);
+               } else
+                       ret = -EINVAL;
+               break;
+       }
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               break;
+       default:
+               return -EINVAL;
+       }
+       return ret;
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+                             struct v4l2_ext_controls *ctrls)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       int i, err = 0;
+
+       if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+               for (i = 0; i < ctrls->count; i++) {
+                       struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+                       err = hdpvr_try_ctrl(ctrl,
+                                            dev->flags & HDPVR_FLAG_AC3_CAP);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+                       err = hdpvr_set_ctrl(dev, ctrl);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+               }
+               return err;
+
+       }
+
+       return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
+                                   struct v4l2_fmtdesc *f)
+{
+
+       if (f->index != 0 || f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       f->flags = V4L2_FMT_FLAG_COMPRESSED;
+       strncpy(f->description, "MPEG2-TS with AVC/AAC streams", 32);
+       f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+       return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data,
+                               struct v4l2_format *f)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       struct hdpvr_video_info *vid_info;
+
+       if (!dev)
+               return -ENODEV;
+
+       vid_info = get_video_info(dev);
+       if (!vid_info)
+               return -EFAULT;
+
+       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.width        = vid_info->width;
+       f->fmt.pix.height       = vid_info->height;
+       f->fmt.pix.sizeimage    = dev->bulk_in_size;
+       f->fmt.pix.colorspace   = 0;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.field        = V4L2_FIELD_ANY;
+
+       kfree(vid_info);
+       return 0;
+}
+
+static int vidioc_encoder_cmd(struct file *filp, void *priv,
+                              struct v4l2_encoder_cmd *a)
+{
+       struct hdpvr_fh *fh = filp->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       int res;
+
+       mutex_lock(&dev->io_mutex);
+
+       memset(&a->raw, 0, sizeof(a->raw));
+       switch (a->cmd) {
+       case V4L2_ENC_CMD_START:
+               a->flags = 0;
+               res = hdpvr_start_streaming(dev);
+               break;
+       case V4L2_ENC_CMD_STOP:
+               res = hdpvr_stop_streaming(dev);
+               break;
+       default:
+               v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+                        "Unsupported encoder cmd %d\n", a->cmd);
+               res = -EINVAL;
+       }
+       mutex_unlock(&dev->io_mutex);
+       return res;
+}
+
+static int vidioc_try_encoder_cmd(struct file *filp, void *priv,
+                                       struct v4l2_encoder_cmd *a)
+{
+       switch (a->cmd) {
+       case V4L2_ENC_CMD_START:
+       case V4L2_ENC_CMD_STOP:
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
+       .vidioc_querycap        = vidioc_querycap,
+       .vidioc_s_std           = vidioc_s_std,
+       .vidioc_enum_input      = vidioc_enum_input,
+       .vidioc_g_input         = vidioc_g_input,
+       .vidioc_s_input         = vidioc_s_input,
+       .vidioc_enumaudio       = vidioc_enumaudio,
+       .vidioc_g_audio         = vidioc_g_audio,
+       .vidioc_s_audio         = vidioc_s_audio,
+       .vidioc_queryctrl       = vidioc_queryctrl,
+       .vidioc_g_ctrl          = vidioc_g_ctrl,
+       .vidioc_s_ctrl          = vidioc_s_ctrl,
+       .vidioc_g_ext_ctrls     = vidioc_g_ext_ctrls,
+       .vidioc_s_ext_ctrls     = vidioc_s_ext_ctrls,
+       .vidioc_try_ext_ctrls   = vidioc_try_ext_ctrls,
+       .vidioc_enum_fmt_vid_cap        = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap           = vidioc_g_fmt_vid_cap,
+       .vidioc_encoder_cmd     = vidioc_encoder_cmd,
+       .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd,
+};
+
+static void hdpvr_device_release(struct video_device *vdev)
+{
+       struct hdpvr_device *dev = video_get_drvdata(vdev);
+
+       hdpvr_delete(dev);
+}
+
+static const struct video_device hdpvr_video_template = {
+/*     .type                   = VFL_TYPE_GRABBER, */
+/*     .type2                  = VID_TYPE_CAPTURE | VID_TYPE_MPEG_ENCODER, */
+       .fops                   = &hdpvr_fops,
+       .release                = hdpvr_device_release,
+       .ioctl_ops              = &hdpvr_ioctl_ops,
+       .tvnorms                =
+               V4L2_STD_NTSC  | V4L2_STD_SECAM | V4L2_STD_PAL_B |
+               V4L2_STD_PAL_G | V4L2_STD_PAL_H | V4L2_STD_PAL_I |
+               V4L2_STD_PAL_D | V4L2_STD_PAL_M | V4L2_STD_PAL_N |
+               V4L2_STD_PAL_60,
+};
+
+int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
+                           int devnum)
+{
+       /* setup and register video device */
+       dev->video_dev = video_device_alloc();
+       if (!dev->video_dev) {
+               v4l2_err(&dev->v4l2_dev, "video_device_alloc() failed\n");
+               goto error;
+       }
+
+       *(dev->video_dev) = hdpvr_video_template;
+       strcpy(dev->video_dev->name, "Hauppauge HD PVR");
+       dev->video_dev->parent = parent;
+       video_set_drvdata(dev->video_dev, dev);
+
+       if (video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum)) {
+               v4l2_err(&dev->v4l2_dev, "video_device registration failed\n");
+               goto error;
+       }
+
+       return 0;
+error:
+       return -ENOMEM;
+}
diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/video/hdpvr/hdpvr.h
new file mode 100644 (file)
index 0000000..1edd875
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * Hauppauge HD PVR USB driver
+ *
+ * Copyright (C) 2008      Janne Grunau (j@jannau.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, version 2.
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+
+#define HDPVR_MAJOR_VERSION 0
+#define HDPVR_MINOR_VERSION 2
+#define HDPVR_RELEASE 0
+#define HDPVR_VERSION \
+       KERNEL_VERSION(HDPVR_MAJOR_VERSION, HDPVR_MINOR_VERSION, HDPVR_RELEASE)
+
+#define HDPVR_MAX 8
+
+/* Define these values to match your devices */
+#define HD_PVR_VENDOR_ID       0x2040
+#define HD_PVR_PRODUCT_ID      0x4900
+#define HD_PVR_PRODUCT_ID1     0x4901
+#define HD_PVR_PRODUCT_ID2     0x4902
+
+#define UNSET    (-1U)
+
+#define NUM_BUFFERS 64
+
+#define HDPVR_FIRMWARE_VERSION         0x8
+#define HDPVR_FIRMWARE_VERSION_AC3     0xd
+
+/* #define HDPVR_DEBUG */
+
+extern int hdpvr_debug;
+
+#define MSG_INFO       1
+#define MSG_BUFFER     2
+
+struct hdpvr_options {
+       u8      video_std;
+       u8      video_input;
+       u8      audio_input;
+       u8      bitrate;        /* in 100kbps */
+       u8      peak_bitrate;   /* in 100kbps */
+       u8      bitrate_mode;
+       u8      gop_mode;
+       enum v4l2_mpeg_audio_encoding   audio_codec;
+       u8      brightness;
+       u8      contrast;
+       u8      hue;
+       u8      saturation;
+       u8      sharpness;
+};
+
+/* Structure to hold all of our device specific stuff */
+struct hdpvr_device {
+       /* the v4l device for this device */
+       struct video_device     *video_dev;
+       /* the usb device for this device */
+       struct usb_device       *udev;
+       /* v4l2-device unused */
+       struct v4l2_device      v4l2_dev;
+
+       /* the max packet size of the bulk endpoint */
+       size_t                  bulk_in_size;
+       /* the address of the bulk in endpoint */
+       __u8                    bulk_in_endpointAddr;
+
+       /* holds the current device status */
+       __u8                    status;
+       /* count the number of openers */
+       uint                    open_count;
+
+       /* holds the cureent set options */
+       struct hdpvr_options    options;
+
+       uint                    flags;
+
+       /* synchronize I/O */
+       struct mutex            io_mutex;
+       /* available buffers */
+       struct list_head        free_buff_list;
+       /* in progress buffers */
+       struct list_head        rec_buff_list;
+       /* waitqueue for buffers */
+       wait_queue_head_t       wait_buffer;
+       /* waitqueue for data */
+       wait_queue_head_t       wait_data;
+       /**/
+       struct workqueue_struct *workqueue;
+       /**/
+       struct work_struct      worker;
+
+       /* I2C adapter */
+       struct i2c_adapter      *i2c_adapter;
+       /* I2C lock */
+       struct mutex            i2c_mutex;
+
+       /* usb control transfer buffer and lock */
+       struct mutex            usbc_mutex;
+       u8                      *usbc_buf;
+};
+
+
+/* buffer one bulk urb of data */
+struct hdpvr_buffer {
+       struct list_head        buff_list;
+
+       struct urb              *urb;
+
+       struct hdpvr_device     *dev;
+
+       uint                    pos;
+
+       __u8                    status;
+};
+
+/* */
+
+struct hdpvr_video_info {
+       u16     width;
+       u16     height;
+       u8      fps;
+};
+
+enum {
+       STATUS_UNINITIALIZED    = 0,
+       STATUS_IDLE,
+       STATUS_STARTING,
+       STATUS_SHUTTING_DOWN,
+       STATUS_STREAMING,
+       STATUS_ERROR,
+       STATUS_DISCONNECTED,
+};
+
+enum {
+       HDPVR_FLAG_AC3_CAP = 1,
+};
+
+enum {
+       BUFSTAT_UNINITIALIZED = 0,
+       BUFSTAT_AVAILABLE,
+       BUFSTAT_INPROGRESS,
+       BUFSTAT_READY,
+};
+
+#define CTRL_START_STREAMING_VALUE     0x0700
+#define CTRL_STOP_STREAMING_VALUE      0x0800
+#define CTRL_BITRATE_VALUE             0x1000
+#define CTRL_BITRATE_MODE_VALUE                0x1200
+#define CTRL_GOP_MODE_VALUE            0x1300
+#define CTRL_VIDEO_INPUT_VALUE         0x1500
+#define CTRL_VIDEO_STD_TYPE            0x1700
+#define CTRL_AUDIO_INPUT_VALUE         0x2500
+#define CTRL_BRIGHTNESS                        0x2900
+#define CTRL_CONTRAST                  0x2a00
+#define CTRL_HUE                       0x2b00
+#define CTRL_SATURATION                        0x2c00
+#define CTRL_SHARPNESS                 0x2d00
+#define CTRL_LOW_PASS_FILTER_VALUE     0x3100
+
+#define CTRL_DEFAULT_INDEX             0x0003
+
+
+       /* :0 s 38 01 1000 0003 0004 4 = 0a00ca00
+        * BITRATE SETTING
+        *   1st and 2nd byte (little endian): average bitrate in 100 000 bit/s
+        *                                     min: 1 mbit/s, max: 13.5 mbit/s
+        *   3rd and 4th byte (little endian): peak bitrate in 100 000 bit/s
+        *                                     min: average + 100kbit/s,
+        *                                      max: 20.2 mbit/s
+        */
+
+       /* :0 s 38 01 1200 0003 0001 1 = 02
+        * BIT RATE MODE
+        *  constant = 1, variable (peak) = 2, variable (average) = 3
+        */
+
+       /* :0 s 38 01 1300 0003 0001 1 = 03
+        * GOP MODE (2 bit)
+        *    low bit 0/1: advanced/simple GOP
+        *   high bit 0/1: IDR(4/32/128) / no IDR (4/32/0)
+        */
+
+       /* :0 s 38 01 1700 0003 0001 1 = 00
+        * VIDEO STANDARD or FREQUNCY 0 = 60hz, 1 = 50hz
+        */
+
+       /* :0 s 38 01 3100 0003 0004 4 = 03030000
+        * FILTER CONTROL
+        *   1st byte luma low pass filter strength,
+        *   2nd byte chroma low pass filter strength,
+        *   3rd byte MF enable chroma, min=0, max=1
+        *   4th byte n
+        */
+
+
+       /* :0 s 38 b9 0001 0000 0000 0 */
+
+
+
+/* :0 s 38 d3 0000 0000 0001 1 = 00 */
+/*             ret = usb_control_msg(dev->udev, */
+/*                                   usb_sndctrlpipe(dev->udev, 0), */
+/*                                   0xd3, 0x38, */
+/*                                   0, 0, */
+/*                                   "\0", 1, */
+/*                                   1000); */
+
+/*             info("control request returned %d", ret); */
+/*             msleep(5000); */
+
+
+       /* :0 s b8 81 1400 0003 0005 5 <
+        * :0 0 5 = d0024002 19
+        * QUERY FRAME SIZE AND RATE
+        *   1st and 2nd byte (little endian): horizontal resolution
+        *   3rd and 4th byte (little endian): vertical resolution
+        *   5th byte: frame rate
+        */
+
+       /* :0 s b8 81 1800 0003 0003 3 <
+        * :0 0 3 = 030104
+        * QUERY SIGNAL AND DETECTED LINES, maybe INPUT
+        */
+
+enum hdpvr_video_std {
+       HDPVR_60HZ = 0,
+       HDPVR_50HZ,
+};
+
+enum hdpvr_video_input {
+       HDPVR_COMPONENT = 0,
+       HDPVR_SVIDEO,
+       HDPVR_COMPOSITE,
+       HDPVR_VIDEO_INPUTS
+};
+
+enum hdpvr_audio_inputs {
+       HDPVR_RCA_BACK = 0,
+       HDPVR_RCA_FRONT,
+       HDPVR_SPDIF,
+       HDPVR_AUDIO_INPUTS
+};
+
+enum hdpvr_bitrate_mode {
+       HDPVR_CONSTANT = 1,
+       HDPVR_VARIABLE_PEAK,
+       HDPVR_VARIABLE_AVERAGE,
+};
+
+enum hdpvr_gop_mode {
+       HDPVR_ADVANCED_IDR_GOP = 0,
+       HDPVR_SIMPLE_IDR_GOP,
+       HDPVR_ADVANCED_NOIDR_GOP,
+       HDPVR_SIMPLE_NOIDR_GOP,
+};
+
+void hdpvr_delete(struct hdpvr_device *dev);
+
+/*========================================================================*/
+/* hardware control functions */
+int hdpvr_set_options(struct hdpvr_device *dev);
+
+int hdpvr_set_bitrate(struct hdpvr_device *dev);
+
+int hdpvr_set_audio(struct hdpvr_device *dev, u8 input,
+                   enum v4l2_mpeg_audio_encoding codec);
+
+int hdpvr_config_call(struct hdpvr_device *dev, uint value,
+                     unsigned char valbuf);
+
+struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev);
+
+/* :0 s b8 81 1800 0003 0003 3 < */
+/* :0 0 3 = 0301ff */
+int get_input_lines_info(struct hdpvr_device *dev);
+
+
+/*========================================================================*/
+/* v4l2 registration */
+int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
+                           int devnumber);
+
+int hdpvr_cancel_queue(struct hdpvr_device *dev);
+
+/*========================================================================*/
+/* i2c adapter registration */
+int hdpvr_register_i2c_adapter(struct hdpvr_device *dev);
+
+/*========================================================================*/
+/* buffer management */
+int hdpvr_free_buffers(struct hdpvr_device *dev);
+int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count);
index 79393d1772e40163a7e4bcfa1f971ef88faaacd8..8e1463ee1b6420c0e9e652850a05293900bdf150 100644 (file)
@@ -56,17 +56,6 @@ struct hexium_data
        u8 byte;
 };
 
-static struct saa7146_extension_ioctls ioctls[] = {
-       { VIDIOC_G_INPUT,       SAA7146_EXCLUSIVE },
-       { VIDIOC_S_INPUT,       SAA7146_EXCLUSIVE },
-       { VIDIOC_QUERYCTRL,     SAA7146_BEFORE },
-       { VIDIOC_ENUMINPUT,     SAA7146_EXCLUSIVE },
-       { VIDIOC_S_STD,         SAA7146_AFTER },
-       { VIDIOC_G_CTRL,        SAA7146_BEFORE },
-       { VIDIOC_S_CTRL,        SAA7146_BEFORE },
-       { 0,                    0 }
-};
-
 #define HEXIUM_CONTROLS        1
 static struct v4l2_queryctrl hexium_controls[] = {
        { V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 },
@@ -231,6 +220,132 @@ static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
        return 0;
 }
 
+static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+       DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
+
+       if (i->index < 0 || i->index >= HEXIUM_INPUTS)
+               return -EINVAL;
+
+       memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
+
+       DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
+       return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+       *input = hexium->cur_input;
+
+       DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+       DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
+
+       if (input < 0 || input >= HEXIUM_INPUTS)
+               return -EINVAL;
+
+       hexium->cur_input = input;
+       hexium_set_input(hexium, input);
+       return 0;
+}
+
+/* the saa7146 provides some controls (brightness, contrast, saturation)
+   which gets registered *after* this function. because of this we have
+   to return with a value != 0 even if the function succeded.. */
+static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       int i;
+
+       for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
+               if (hexium_controls[i].id == qc->id) {
+                       *qc = hexium_controls[i];
+                       DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
+                       return 0;
+               }
+       }
+       return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc);
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct hexium *hexium = (struct hexium *) dev->ext_priv;
+       int i;
+
+       for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
+               if (hexium_controls[i].id == vc->id)
+                       break;
+       }
+
+       if (i < 0)
+               return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc);
+
+       if (vc->id == V4L2_CID_PRIVATE_BASE) {
+               vc->value = hexium->cur_bw;
+               DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value));
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct hexium *hexium = (struct hexium *) dev->ext_priv;
+       int i = 0;
+
+       for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
+               if (hexium_controls[i].id == vc->id)
+                       break;
+       }
+
+       if (i < 0)
+               return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc);
+
+       if (vc->id == V4L2_CID_PRIVATE_BASE)
+               hexium->cur_bw = vc->value;
+
+       DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw));
+
+       if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
+               hexium_set_standard(hexium, hexium_pal);
+               return 0;
+       }
+       if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
+               hexium_set_standard(hexium, hexium_ntsc);
+               return 0;
+       }
+       if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
+               hexium_set_standard(hexium, hexium_secam);
+               return 0;
+       }
+       if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
+               hexium_set_standard(hexium, hexium_pal_bw);
+               return 0;
+       }
+       if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
+               hexium_set_standard(hexium, hexium_ntsc_bw);
+               return 0;
+       }
+       if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std)
+               /* fixme: is there no bw secam mode? */
+               return -EINVAL;
+
+       return -EINVAL;
+}
+
+
 static struct saa7146_ext_vv vv_data;
 
 /* this function only gets called when the probing was successful */
@@ -279,6 +394,12 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
        hexium->cur_input = 0;
 
        saa7146_vv_init(dev, &vv_data);
+       vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
+       vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
+       vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
+       vv_data.ops.vidioc_enum_input = vidioc_enum_input;
+       vv_data.ops.vidioc_g_input = vidioc_g_input;
+       vv_data.ops.vidioc_s_input = vidioc_s_input;
        if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) {
                printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n");
                return -1;
@@ -306,153 +427,6 @@ static int hexium_detach(struct saa7146_dev *dev)
        return 0;
 }
 
-static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
-{
-       struct saa7146_dev *dev = fh->dev;
-       struct hexium *hexium = (struct hexium *) dev->ext_priv;
-/*
-       struct saa7146_vv *vv = dev->vv_data;
-*/
-       switch (cmd) {
-       case VIDIOC_ENUMINPUT:
-               {
-                       struct v4l2_input *i = arg;
-                       DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
-
-                       if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
-                               return -EINVAL;
-                       }
-
-                       memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
-
-                       DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
-                       return 0;
-               }
-       case VIDIOC_G_INPUT:
-               {
-                       int *input = (int *) arg;
-                       *input = hexium->cur_input;
-
-                       DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
-                       return 0;
-               }
-       case VIDIOC_S_INPUT:
-               {
-                       int input = *(int *) arg;
-
-                       DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
-
-                       if (input < 0 || input >= HEXIUM_INPUTS) {
-                               return -EINVAL;
-                       }
-
-                       hexium->cur_input = input;
-                       hexium_set_input(hexium, input);
-
-                       return 0;
-               }
-               /* the saa7146 provides some controls (brightness, contrast, saturation)
-                  which gets registered *after* this function. because of this we have
-                  to return with a value != 0 even if the function succeded.. */
-       case VIDIOC_QUERYCTRL:
-               {
-                       struct v4l2_queryctrl *qc = arg;
-                       int i;
-
-                       for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
-                               if (hexium_controls[i].id == qc->id) {
-                                       *qc = hexium_controls[i];
-                                       DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
-                                       return 0;
-                               }
-                       }
-                       return -EAGAIN;
-               }
-       case VIDIOC_G_CTRL:
-               {
-                       struct v4l2_control *vc = arg;
-                       int i;
-
-                       for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
-                               if (hexium_controls[i].id == vc->id) {
-                                       break;
-                               }
-                       }
-
-                       if (i < 0) {
-                               return -EAGAIN;
-                       }
-
-                       switch (vc->id) {
-                       case V4L2_CID_PRIVATE_BASE:{
-                                       vc->value = hexium->cur_bw;
-                                       DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value));
-                                       return 0;
-                               }
-                       }
-                       return -EINVAL;
-               }
-
-       case VIDIOC_S_CTRL:
-               {
-                       struct v4l2_control *vc = arg;
-                       int i = 0;
-
-                       for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
-                               if (hexium_controls[i].id == vc->id) {
-                                       break;
-                               }
-                       }
-
-                       if (i < 0) {
-                               return -EAGAIN;
-                       }
-
-                       switch (vc->id) {
-                       case V4L2_CID_PRIVATE_BASE:{
-                                       hexium->cur_bw = vc->value;
-                                       break;
-                               }
-                       }
-
-                       DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw));
-
-                       if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
-                               hexium_set_standard(hexium, hexium_pal);
-                               return 0;
-                       }
-                       if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
-                               hexium_set_standard(hexium, hexium_ntsc);
-                               return 0;
-                       }
-                       if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
-                               hexium_set_standard(hexium, hexium_secam);
-                               return 0;
-                       }
-                       if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
-                               hexium_set_standard(hexium, hexium_pal_bw);
-                               return 0;
-                       }
-                       if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
-                               hexium_set_standard(hexium, hexium_ntsc_bw);
-                               return 0;
-                       }
-                       if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
-                               /* fixme: is there no bw secam mode? */
-                               return -EINVAL;
-                       }
-
-                       return -EINVAL;
-               }
-       default:
-/*
-               DEB_D(("hexium_ioctl() does not handle this ioctl.\n"));
-*/
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
 static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
 {
        struct hexium *hexium = (struct hexium *) dev->ext_priv;
@@ -514,8 +488,6 @@ static struct saa7146_ext_vv vv_data = {
        .stds = &hexium_standards[0],
        .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
        .std_callback = &std_callback,
-       .ioctls = &ioctls[0],
-       .ioctl = hexium_ioctl,
 };
 
 static struct saa7146_extension hexium_extension = {
index 074bec711fe0a621b1894f50c35246195b7bc3bf..2bc39f62845527dda7391c253d2aa6c0d29b148a 100644 (file)
@@ -57,14 +57,6 @@ struct hexium_data
        u8 byte;
 };
 
-static struct saa7146_extension_ioctls ioctls[] = {
-       { VIDIOC_G_INPUT,       SAA7146_EXCLUSIVE },
-       { VIDIOC_S_INPUT,       SAA7146_EXCLUSIVE },
-       { VIDIOC_ENUMINPUT,     SAA7146_EXCLUSIVE },
-       { VIDIOC_S_STD,         SAA7146_AFTER },
-       { 0,                    0 }
-};
-
 struct hexium
 {
        int type;
@@ -329,6 +321,44 @@ static int hexium_set_input(struct hexium *hexium, int input)
        return 0;
 }
 
+static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+       DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
+
+       if (i->index < 0 || i->index >= HEXIUM_INPUTS)
+               return -EINVAL;
+
+       memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
+
+       DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
+       return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+       *input = hexium->cur_input;
+
+       DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+       if (input < 0 || input >= HEXIUM_INPUTS)
+               return -EINVAL;
+
+       hexium->cur_input = input;
+       hexium_set_input(hexium, input);
+
+       return 0;
+}
+
 static struct saa7146_ext_vv vv_data;
 
 /* this function only gets called when the probing was successful */
@@ -339,6 +369,9 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
        DEB_EE((".\n"));
 
        saa7146_vv_init(dev, &vv_data);
+       vv_data.ops.vidioc_enum_input = vidioc_enum_input;
+       vv_data.ops.vidioc_g_input = vidioc_g_input;
+       vv_data.ops.vidioc_s_input = vidioc_s_input;
        if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
                printk("hexium_orion: cannot register capture v4l2 device. skipping.\n");
                return -1;
@@ -370,58 +403,6 @@ static int hexium_detach(struct saa7146_dev *dev)
        return 0;
 }
 
-static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
-{
-       struct saa7146_dev *dev = fh->dev;
-       struct hexium *hexium = (struct hexium *) dev->ext_priv;
-/*
-       struct saa7146_vv *vv = dev->vv_data;
-*/
-       switch (cmd) {
-       case VIDIOC_ENUMINPUT:
-               {
-                       struct v4l2_input *i = arg;
-                       DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
-
-                       if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
-                               return -EINVAL;
-                       }
-
-                       memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
-
-                       DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
-                       return 0;
-               }
-       case VIDIOC_G_INPUT:
-               {
-                       int *input = (int *) arg;
-                       *input = hexium->cur_input;
-
-                       DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
-                       return 0;
-               }
-       case VIDIOC_S_INPUT:
-               {
-                       int input = *(int *) arg;
-
-                       if (input < 0 || input >= HEXIUM_INPUTS) {
-                               return -EINVAL;
-                       }
-
-                       hexium->cur_input = input;
-                       hexium_set_input(hexium, input);
-
-                       return 0;
-               }
-       default:
-/*
-               DEB_D(("hexium_ioctl() does not handle this ioctl.\n"));
-*/
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
 static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
 {
        return 0;
@@ -479,8 +460,6 @@ static struct saa7146_ext_vv vv_data = {
        .stds = &hexium_standards[0],
        .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
        .std_callback = &std_callback,
-       .ioctls = &ioctls[0],
-       .ioctl = hexium_ioctl,
 };
 
 static struct saa7146_extension extension = {
index 84b9e4f2b3b3fcef7c25b2b60d88df30925d44f6..3d6940163b125977bee7d7cd13acf42f00bbdef8 100644 (file)
 #include <linux/mm.h>
 #include <linux/slab.h>
 
-#include <linux/videodev.h>
 /* IndyCam decodes stream of photons into digital image representation ;-) */
-#include <linux/video_decoder.h>
+#include <linux/videodev2.h>
 #include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 
 #include "indycam.h"
 
@@ -33,6 +35,7 @@ MODULE_VERSION(INDYCAM_MODULE_VERSION);
 MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
 MODULE_LICENSE("GPL");
 
+
 // #define INDYCAM_DEBUG
 
 #ifdef INDYCAM_DEBUG
@@ -44,11 +47,14 @@ MODULE_LICENSE("GPL");
 #endif
 
 struct indycam {
-       struct i2c_client *client;
+       struct v4l2_subdev sd;
        u8 version;
 };
 
-static struct i2c_driver i2c_driver_indycam;
+static inline struct indycam *to_indycam(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct indycam, sd);
+}
 
 static const u8 initseq[] = {
        INDYCAM_CONTROL_AGCENA,         /* INDYCAM_CONTROL */
@@ -63,8 +69,9 @@ static const u8 initseq[] = {
 
 /* IndyCam register handling */
 
-static int indycam_read_reg(struct i2c_client *client, u8 reg, u8 *value)
+static int indycam_read_reg(struct v4l2_subdev *sd, u8 reg, u8 *value)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int ret;
 
        if (reg == INDYCAM_REG_RESET) {
@@ -87,12 +94,12 @@ static int indycam_read_reg(struct i2c_client *client, u8 reg, u8 *value)
        return 0;
 }
 
-static int indycam_write_reg(struct i2c_client *client, u8 reg, u8 value)
+static int indycam_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int err;
 
-       if ((reg == INDYCAM_REG_BRIGHTNESS)
-           || (reg == INDYCAM_REG_VERSION)) {
+       if (reg == INDYCAM_REG_BRIGHTNESS || reg == INDYCAM_REG_VERSION) {
                dprintk("indycam_write_reg(): "
                        "skipping read-only register %d\n", reg);
                return 0;
@@ -108,13 +115,13 @@ static int indycam_write_reg(struct i2c_client *client, u8 reg, u8 value)
        return err;
 }
 
-static int indycam_write_block(struct i2c_client *client, u8 reg,
+static int indycam_write_block(struct v4l2_subdev *sd, u8 reg,
                               u8 length, u8 *data)
 {
        int i, err;
 
        for (i = 0; i < length; i++) {
-               err = indycam_write_reg(client, reg + i, data[i]);
+               err = indycam_write_reg(sd, reg + i, data[i]);
                if (err)
                        return err;
        }
@@ -125,79 +132,78 @@ static int indycam_write_block(struct i2c_client *client, u8 reg,
 /* Helper functions */
 
 #ifdef INDYCAM_DEBUG
-static void indycam_regdump_debug(struct i2c_client *client)
+static void indycam_regdump_debug(struct v4l2_subdev *sd)
 {
        int i;
        u8 val;
 
        for (i = 0; i < 9; i++) {
-               indycam_read_reg(client, i, &val);
+               indycam_read_reg(sd, i, &val);
                dprintk("Reg %d = 0x%02x\n", i, val);
        }
 }
 #endif
 
-static int indycam_get_control(struct i2c_client *client,
-                              struct indycam_control *ctrl)
+static int indycam_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct indycam *camera = i2c_get_clientdata(client);
+       struct indycam *camera = to_indycam(sd);
        u8 reg;
        int ret = 0;
 
-       switch (ctrl->type) {
-       case INDYCAM_CONTROL_AGC:
-       case INDYCAM_CONTROL_AWB:
-               ret = indycam_read_reg(client, INDYCAM_REG_CONTROL, &reg);
+       switch (ctrl->id) {
+       case V4L2_CID_AUTOGAIN:
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, &reg);
                if (ret)
                        return -EIO;
-               if (ctrl->type == INDYCAM_CONTROL_AGC)
+               if (ctrl->id == V4L2_CID_AUTOGAIN)
                        ctrl->value = (reg & INDYCAM_CONTROL_AGCENA)
                                ? 1 : 0;
                else
                        ctrl->value = (reg & INDYCAM_CONTROL_AWBCTL)
                                ? 1 : 0;
                break;
-       case INDYCAM_CONTROL_SHUTTER:
-               ret = indycam_read_reg(client, INDYCAM_REG_SHUTTER, &reg);
+       case V4L2_CID_EXPOSURE:
+               ret = indycam_read_reg(sd, INDYCAM_REG_SHUTTER, &reg);
                if (ret)
                        return -EIO;
                ctrl->value = ((s32)reg == 0x00) ? 0xff : ((s32)reg - 1);
                break;
-       case INDYCAM_CONTROL_GAIN:
-               ret = indycam_read_reg(client, INDYCAM_REG_GAIN, &reg);
+       case V4L2_CID_GAIN:
+               ret = indycam_read_reg(sd, INDYCAM_REG_GAIN, &reg);
                if (ret)
                        return -EIO;
                ctrl->value = (s32)reg;
                break;
-       case INDYCAM_CONTROL_RED_BALANCE:
-               ret = indycam_read_reg(client, INDYCAM_REG_RED_BALANCE, &reg);
+       case V4L2_CID_RED_BALANCE:
+               ret = indycam_read_reg(sd, INDYCAM_REG_RED_BALANCE, &reg);
                if (ret)
                        return -EIO;
                ctrl->value = (s32)reg;
                break;
-       case INDYCAM_CONTROL_BLUE_BALANCE:
-               ret = indycam_read_reg(client, INDYCAM_REG_BLUE_BALANCE, &reg);
+       case V4L2_CID_BLUE_BALANCE:
+               ret = indycam_read_reg(sd, INDYCAM_REG_BLUE_BALANCE, &reg);
                if (ret)
                        return -EIO;
                ctrl->value = (s32)reg;
                break;
        case INDYCAM_CONTROL_RED_SATURATION:
-               ret = indycam_read_reg(client,
+               ret = indycam_read_reg(sd,
                                       INDYCAM_REG_RED_SATURATION, &reg);
                if (ret)
                        return -EIO;
                ctrl->value = (s32)reg;
                break;
        case INDYCAM_CONTROL_BLUE_SATURATION:
-               ret = indycam_read_reg(client,
+               ret = indycam_read_reg(sd,
                                       INDYCAM_REG_BLUE_SATURATION, &reg);
                if (ret)
                        return -EIO;
                ctrl->value = (s32)reg;
                break;
-       case INDYCAM_CONTROL_GAMMA:
+       case V4L2_CID_GAMMA:
                if (camera->version == CAMERA_VERSION_MOOSE) {
-                       ret = indycam_read_reg(client,
+                       ret = indycam_read_reg(sd,
                                               INDYCAM_REG_GAMMA, &reg);
                        if (ret)
                                return -EIO;
@@ -213,21 +219,20 @@ static int indycam_get_control(struct i2c_client *client,
        return ret;
 }
 
-static int indycam_set_control(struct i2c_client *client,
-                              struct indycam_control *ctrl)
+static int indycam_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct indycam *camera = i2c_get_clientdata(client);
+       struct indycam *camera = to_indycam(sd);
        u8 reg;
        int ret = 0;
 
-       switch (ctrl->type) {
-       case INDYCAM_CONTROL_AGC:
-       case INDYCAM_CONTROL_AWB:
-               ret = indycam_read_reg(client, INDYCAM_REG_CONTROL, &reg);
+       switch (ctrl->id) {
+       case V4L2_CID_AUTOGAIN:
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, &reg);
                if (ret)
                        break;
 
-               if (ctrl->type == INDYCAM_CONTROL_AGC) {
+               if (ctrl->id == V4L2_CID_AUTOGAIN) {
                        if (ctrl->value)
                                reg |= INDYCAM_CONTROL_AGCENA;
                        else
@@ -239,34 +244,34 @@ static int indycam_set_control(struct i2c_client *client,
                                reg &= ~INDYCAM_CONTROL_AWBCTL;
                }
 
-               ret = indycam_write_reg(client, INDYCAM_REG_CONTROL, reg);
+               ret = indycam_write_reg(sd, INDYCAM_REG_CONTROL, reg);
                break;
-       case INDYCAM_CONTROL_SHUTTER:
+       case V4L2_CID_EXPOSURE:
                reg = (ctrl->value == 0xff) ? 0x00 : (ctrl->value + 1);
-               ret = indycam_write_reg(client, INDYCAM_REG_SHUTTER, reg);
+               ret = indycam_write_reg(sd, INDYCAM_REG_SHUTTER, reg);
                break;
-       case INDYCAM_CONTROL_GAIN:
-               ret = indycam_write_reg(client, INDYCAM_REG_GAIN, ctrl->value);
+       case V4L2_CID_GAIN:
+               ret = indycam_write_reg(sd, INDYCAM_REG_GAIN, ctrl->value);
                break;
-       case INDYCAM_CONTROL_RED_BALANCE:
-               ret = indycam_write_reg(client, INDYCAM_REG_RED_BALANCE,
+       case V4L2_CID_RED_BALANCE:
+               ret = indycam_write_reg(sd, INDYCAM_REG_RED_BALANCE,
                                        ctrl->value);
                break;
-       case INDYCAM_CONTROL_BLUE_BALANCE:
-               ret = indycam_write_reg(client, INDYCAM_REG_BLUE_BALANCE,
+       case V4L2_CID_BLUE_BALANCE:
+               ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_BALANCE,
                                        ctrl->value);
                break;
        case INDYCAM_CONTROL_RED_SATURATION:
-               ret = indycam_write_reg(client, INDYCAM_REG_RED_SATURATION,
+               ret = indycam_write_reg(sd, INDYCAM_REG_RED_SATURATION,
                                        ctrl->value);
                break;
        case INDYCAM_CONTROL_BLUE_SATURATION:
-               ret = indycam_write_reg(client, INDYCAM_REG_BLUE_SATURATION,
+               ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_SATURATION,
                                        ctrl->value);
                break;
-       case INDYCAM_CONTROL_GAMMA:
+       case V4L2_CID_GAMMA:
                if (camera->version == CAMERA_VERSION_MOOSE) {
-                       ret = indycam_write_reg(client, INDYCAM_REG_GAMMA,
+                       ret = indycam_write_reg(sd, INDYCAM_REG_GAMMA,
                                                ctrl->value);
                }
                break;
@@ -279,192 +284,103 @@ static int indycam_set_control(struct i2c_client *client,
 
 /* I2C-interface */
 
-static int indycam_attach(struct i2c_adapter *adap, int addr, int kind)
+static int indycam_g_chip_ident(struct v4l2_subdev *sd,
+               struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct indycam *camera = to_indycam(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_INDYCAM,
+                      camera->version);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops indycam_core_ops = {
+       .g_chip_ident = indycam_g_chip_ident,
+       .g_ctrl = indycam_g_ctrl,
+       .s_ctrl = indycam_s_ctrl,
+};
+
+static const struct v4l2_subdev_ops indycam_ops = {
+       .core = &indycam_core_ops,
+};
+
+static int indycam_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
 {
        int err = 0;
        struct indycam *camera;
-       struct i2c_client *client;
+       struct v4l2_subdev *sd;
 
-       printk(KERN_INFO "SGI IndyCam driver version %s\n",
-              INDYCAM_MODULE_VERSION);
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;
        camera = kzalloc(sizeof(struct indycam), GFP_KERNEL);
-       if (!camera) {
-               err = -ENOMEM;
-               goto out_free_client;
-       }
-
-       client->addr = addr;
-       client->adapter = adap;
-       client->driver = &i2c_driver_indycam;
-       client->flags = 0;
-       strcpy(client->name, "IndyCam client");
-       i2c_set_clientdata(client, camera);
-
-       camera->client = client;
+       if (!camera)
+               return -ENOMEM;
 
-       err = i2c_attach_client(client);
-       if (err)
-               goto out_free_camera;
+       sd = &camera->sd;
+       v4l2_i2c_subdev_init(sd, client, &indycam_ops);
 
        camera->version = i2c_smbus_read_byte_data(client,
                                                   INDYCAM_REG_VERSION);
        if (camera->version != CAMERA_VERSION_INDY &&
            camera->version != CAMERA_VERSION_MOOSE) {
-               err = -ENODEV;
-               goto out_detach_client;
+               kfree(camera);
+               return -ENODEV;
        }
+
        printk(KERN_INFO "IndyCam v%d.%d detected\n",
               INDYCAM_VERSION_MAJOR(camera->version),
               INDYCAM_VERSION_MINOR(camera->version));
 
-       indycam_regdump(client);
+       indycam_regdump(sd);
 
        // initialize
-       err = indycam_write_block(client, 0, sizeof(initseq), (u8 *)&initseq);
+       err = indycam_write_block(sd, 0, sizeof(initseq), (u8 *)&initseq);
        if (err) {
                printk(KERN_ERR "IndyCam initialization failed\n");
-               err = -EIO;
-               goto out_detach_client;
+               kfree(camera);
+               return -EIO;
        }
 
-       indycam_regdump(client);
+       indycam_regdump(sd);
 
        // white balance
-       err = indycam_write_reg(client, INDYCAM_REG_CONTROL,
+       err = indycam_write_reg(sd, INDYCAM_REG_CONTROL,
                          INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL);
        if (err) {
                printk(KERN_ERR "IndyCam: White balancing camera failed\n");
-               err = -EIO;
-               goto out_detach_client;
+               kfree(camera);
+               return -EIO;
        }
 
-       indycam_regdump(client);
+       indycam_regdump(sd);
 
        printk(KERN_INFO "IndyCam initialized\n");
 
        return 0;
-
-out_detach_client:
-       i2c_detach_client(client);
-out_free_camera:
-       kfree(camera);
-out_free_client:
-       kfree(client);
-       return err;
 }
 
-static int indycam_probe(struct i2c_adapter *adap)
+static int indycam_remove(struct i2c_client *client)
 {
-       /* Indy specific crap */
-       if (adap->id == I2C_HW_SGI_VINO)
-               return indycam_attach(adap, INDYCAM_ADDR, 0);
-       /* Feel free to add probe here :-) */
-       return -ENODEV;
-}
-
-static int indycam_detach(struct i2c_client *client)
-{
-       struct indycam *camera = i2c_get_clientdata(client);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
-       i2c_detach_client(client);
-       kfree(camera);
-       kfree(client);
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_indycam(sd));
        return 0;
 }
 
-static int indycam_command(struct i2c_client *client, unsigned int cmd,
-                          void *arg)
-{
-       // struct indycam *camera = i2c_get_clientdata(client);
-
-       /* The old video_decoder interface just isn't enough,
-        * so we'll use some custom commands. */
-       switch (cmd) {
-       case DECODER_GET_CAPABILITIES: {
-               struct video_decoder_capability *cap = arg;
-
-               cap->flags  = VIDEO_DECODER_NTSC;
-               cap->inputs = 1;
-               cap->outputs = 1;
-               break;
-       }
-       case DECODER_GET_STATUS: {
-               int *iarg = arg;
-
-               *iarg = DECODER_STATUS_GOOD | DECODER_STATUS_NTSC |
-                       DECODER_STATUS_COLOR;
-               break;
-       }
-       case DECODER_SET_NORM: {
-               int *iarg = arg;
-
-               switch (*iarg) {
-               case VIDEO_MODE_NTSC:
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
-       }
-       case DECODER_SET_INPUT: {
-               int *iarg = arg;
-
-               if (*iarg != 0)
-                       return -EINVAL;
-               break;
-       }
-       case DECODER_SET_OUTPUT: {
-               int *iarg = arg;
-
-               if (*iarg != 0)
-                       return -EINVAL;
-               break;
-       }
-       case DECODER_ENABLE_OUTPUT: {
-               /* Always enabled */
-               break;
-       }
-       case DECODER_SET_PICTURE: {
-               // struct video_picture *pic = arg;
-               /* TODO: convert values for indycam_set_controls() */
-               break;
-       }
-       case DECODER_INDYCAM_GET_CONTROL: {
-               return indycam_get_control(client, arg);
-       }
-       case DECODER_INDYCAM_SET_CONTROL: {
-               return indycam_set_control(client, arg);
-       }
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static struct i2c_driver i2c_driver_indycam = {
-       .driver = {
-               .name   = "indycam",
-       },
-       .id             = I2C_DRIVERID_INDYCAM,
-       .attach_adapter = indycam_probe,
-       .detach_client  = indycam_detach,
-       .command        = indycam_command,
+static const struct i2c_device_id indycam_id[] = {
+       { "indycam", 0 },
+       { }
 };
+MODULE_DEVICE_TABLE(i2c, indycam_id);
 
-static int __init indycam_init(void)
-{
-       return i2c_add_driver(&i2c_driver_indycam);
-}
-
-static void __exit indycam_exit(void)
-{
-       i2c_del_driver(&i2c_driver_indycam);
-}
-
-module_init(indycam_init);
-module_exit(indycam_exit);
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "indycam",
+       .probe = indycam_probe,
+       .remove = indycam_remove,
+       .id_table = indycam_id,
+};
index e6ee82063ed89214c58bc0e801cc318ad743fa6e..881f21c474c48b3472fd038f61bf64ee2265792c 100644 (file)
 
 /* Driver interface definitions */
 
-#define INDYCAM_CONTROL_AGC                    0       /* boolean */
-#define INDYCAM_CONTROL_AWB                    1       /* boolean */
-#define INDYCAM_CONTROL_SHUTTER                        2
-#define INDYCAM_CONTROL_GAIN                   3
-#define INDYCAM_CONTROL_RED_BALANCE            4
-#define INDYCAM_CONTROL_BLUE_BALANCE           5
-#define INDYCAM_CONTROL_RED_SATURATION         6
-#define INDYCAM_CONTROL_BLUE_SATURATION                7
-#define INDYCAM_CONTROL_GAMMA                  8
-
-struct indycam_control {
-       u8 type;
-       s32 value;
-};
-
-#define        DECODER_INDYCAM_GET_CONTROL     _IOR('d', 193, struct indycam_control)
-#define        DECODER_INDYCAM_SET_CONTROL     _IOW('d', 194, struct indycam_control)
+#define INDYCAM_CONTROL_RED_SATURATION         (V4L2_CID_PRIVATE_BASE + 0)
+#define INDYCAM_CONTROL_BLUE_SATURATION                (V4L2_CID_PRIVATE_BASE + 1)
 
 #endif
index d4658c56eddc53974a7e96e59833f25a6af00e45..092c7da0f37a7a534351536cd2f57ee15b01a4ab 100644 (file)
@@ -16,6 +16,8 @@
  *      Henry Wong <henry@stuffedcow.net>
  *      Mark Schultz <n9xmj@yahoo.com>
  *      Brian Rogers <brian_rogers@comcast.net>
+ * modified for AVerMedia Cardbus by
+ *      Oldrich Jedlicka <oldium.pro@seznam.cz>
  *
  *  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
@@ -216,6 +218,46 @@ static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        return 1;
 }
 
+static int get_key_avermedia_cardbus(struct IR_i2c *ir,
+                                    u32 *ir_key, u32 *ir_raw)
+{
+       unsigned char subaddr, key, keygroup;
+       struct i2c_msg msg[] = { { .addr = ir->c.addr, .flags = 0,
+                                  .buf = &subaddr, .len = 1},
+                                { .addr = ir->c.addr, .flags = I2C_M_RD,
+                                 .buf = &key, .len = 1} };
+       subaddr = 0x0d;
+       if (2 != i2c_transfer(ir->c.adapter, msg, 2)) {
+               dprintk(1, "read error\n");
+               return -EIO;
+       }
+
+       if (key == 0xff)
+               return 0;
+
+       subaddr = 0x0b;
+       msg[1].buf = &keygroup;
+       if (2 != i2c_transfer(ir->c.adapter, msg, 2)) {
+               dprintk(1, "read error\n");
+               return -EIO;
+       }
+
+       if (keygroup == 0xff)
+               return 0;
+
+       dprintk(1, "read key 0x%02x/0x%02x\n", key, keygroup);
+       if (keygroup < 2 || keygroup > 3) {
+               /* Only a warning */
+               dprintk(1, "warning: invalid key group 0x%02x for key 0x%02x\n",
+                                                               keygroup, key);
+       }
+       key |= (keygroup & 1) << 6;
+
+       *ir_key = key;
+       *ir_raw = key;
+       return 1;
+}
+
 /* ----------------------------------------------------------------------- */
 
 static void ir_key_poll(struct IR_i2c *ir)
@@ -237,15 +279,9 @@ static void ir_key_poll(struct IR_i2c *ir)
        }
 }
 
-static void ir_timer(unsigned long data)
-{
-       struct IR_i2c *ir = (struct IR_i2c*)data;
-       schedule_work(&ir->work);
-}
-
 static void ir_work(struct work_struct *work)
 {
-       struct IR_i2c *ir = container_of(work, struct IR_i2c, work);
+       struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work);
        int polling_interval = 100;
 
        /* MSI TV@nywhere Plus requires more frequent polling
@@ -254,7 +290,7 @@ static void ir_work(struct work_struct *work)
                polling_interval = 50;
 
        ir_key_poll(ir);
-       mod_timer(&ir->timer, jiffies + msecs_to_jiffies(polling_interval));
+       schedule_delayed_work(&ir->work, msecs_to_jiffies(polling_interval));
 }
 
 /* ----------------------------------------------------------------------- */
@@ -360,6 +396,12 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
                        ir_type     = IR_TYPE_OTHER;
                }
                break;
+       case 0x40:
+               name        = "AVerMedia Cardbus remote";
+               ir->get_key = get_key_avermedia_cardbus;
+               ir_type     = IR_TYPE_OTHER;
+               ir_codes    = ir_codes_avermedia_cardbus;
+               break;
        default:
                /* shouldn't happen */
                printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n", addr);
@@ -404,11 +446,8 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
               ir->input->name, ir->input->phys, adap->name);
 
        /* start polling via eventd */
-       INIT_WORK(&ir->work, ir_work);
-       init_timer(&ir->timer);
-       ir->timer.function = ir_timer;
-       ir->timer.data     = (unsigned long)ir;
-       schedule_work(&ir->work);
+       INIT_DELAYED_WORK(&ir->work, ir_work);
+       schedule_delayed_work(&ir->work, 0);
 
        return 0;
 
@@ -425,8 +464,7 @@ static int ir_detach(struct i2c_client *client)
        struct IR_i2c *ir = i2c_get_clientdata(client);
 
        /* kill outstanding polls */
-       del_timer_sync(&ir->timer);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&ir->work);
 
        /* unregister devices */
        input_unregister_device(ir->input);
@@ -524,6 +562,22 @@ static int ir_probe(struct i2c_adapter *adap)
                        ir_attach(adap, msg.addr, 0, 0);
        }
 
+       /* Special case for AVerMedia Cardbus remote */
+       if (adap->id == I2C_HW_SAA7134) {
+               unsigned char subaddr, data;
+               struct i2c_msg msg[] = { { .addr = 0x40, .flags = 0,
+                                          .buf = &subaddr, .len = 1},
+                                        { .addr = 0x40, .flags = I2C_M_RD,
+                                          .buf = &data, .len = 1} };
+               subaddr = 0x0d;
+               rc = i2c_transfer(adap, msg, 2);
+               dprintk(1, "probe 0x%02x/0x%02x @ %s: %s\n",
+                       msg[0].addr, subaddr, adap->name,
+                       (2 == rc) ? "yes" : "no");
+               if (2 == rc)
+                       ir_attach(adap, msg[0].addr, 0, 0);
+       }
+
        return 0;
 }
 
index 62aa06f5d168529d4b946418005222edfbfa74da..84995bcf4a75a6207ad6beb24191ed23b18809ec 100644 (file)
@@ -26,6 +26,7 @@
 #include "ivtv-mailbox.h"
 #include "ivtv-controls.h"
 
+/* Must be sorted from low to high control ID! */
 static const u32 user_ctrls[] = {
        V4L2_CID_USER_CLASS,
        V4L2_CID_BRIGHTNESS,
index c46c990987f9b417a263e51782eb0ec3915b05a0..eca8bf92a225c3e7236717302ff3228ff81a77bc 100644 (file)
@@ -357,7 +357,7 @@ void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv)
 static void ivtv_process_eeprom(struct ivtv *itv)
 {
        struct tveeprom tv;
-       int pci_slot = PCI_SLOT(itv->dev->devfn);
+       int pci_slot = PCI_SLOT(itv->pdev->devfn);
 
        ivtv_read_eeprom(itv, &tv);
 
@@ -604,7 +604,7 @@ static void ivtv_process_options(struct ivtv *itv)
        itv->std = ivtv_parse_std(itv);
        if (itv->std == 0 && tunertype >= 0)
                itv->std = tunertype ? V4L2_STD_MN : (V4L2_STD_ALL & ~V4L2_STD_MN);
-       itv->has_cx23415 = (itv->dev->device == PCI_DEVICE_ID_IVTV15);
+       itv->has_cx23415 = (itv->pdev->device == PCI_DEVICE_ID_IVTV15);
        chipname = itv->has_cx23415 ? "cx23415" : "cx23416";
        if (itv->options.cardtype == -1) {
                IVTV_INFO("Ignore card (detected %s based chip)\n", chipname);
@@ -617,9 +617,9 @@ static void ivtv_process_options(struct ivtv *itv)
                IVTV_ERR("Unknown user specified type, trying to autodetect card\n");
        }
        if (itv->card == NULL) {
-               if (itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE ||
-                   itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT1 ||
-                   itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT2) {
+               if (itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE ||
+                   itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT1 ||
+                   itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT2) {
                        itv->card = ivtv_get_card(itv->has_cx23415 ? IVTV_CARD_PVR_350 : IVTV_CARD_PVR_150);
                        IVTV_INFO("Autodetected Hauppauge card (%s based)\n",
                                        chipname);
@@ -630,13 +630,13 @@ static void ivtv_process_options(struct ivtv *itv)
                        if (itv->card->pci_list == NULL)
                                continue;
                        for (j = 0; itv->card->pci_list[j].device; j++) {
-                               if (itv->dev->device !=
+                               if (itv->pdev->device !=
                                    itv->card->pci_list[j].device)
                                        continue;
-                               if (itv->dev->subsystem_vendor !=
+                               if (itv->pdev->subsystem_vendor !=
                                    itv->card->pci_list[j].subsystem_vendor)
                                        continue;
-                               if (itv->dev->subsystem_device !=
+                               if (itv->pdev->subsystem_device !=
                                    itv->card->pci_list[j].subsystem_device)
                                        continue;
                                IVTV_INFO("Autodetected %s card (%s based)\n",
@@ -650,9 +650,9 @@ done:
        if (itv->card == NULL) {
                itv->card = ivtv_get_card(IVTV_CARD_PVR_150);
                IVTV_ERR("Unknown card: vendor/device: [%04x:%04x]\n",
-                    itv->dev->vendor, itv->dev->device);
+                    itv->pdev->vendor, itv->pdev->device);
                IVTV_ERR("              subsystem vendor/device: [%04x:%04x]\n",
-                    itv->dev->subsystem_vendor, itv->dev->subsystem_device);
+                    itv->pdev->subsystem_vendor, itv->pdev->subsystem_device);
                IVTV_ERR("              %s based\n", chipname);
                IVTV_ERR("Defaulting to %s card\n", itv->card->name);
                IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
@@ -671,7 +671,7 @@ done:
  */
 static int __devinit ivtv_init_struct1(struct ivtv *itv)
 {
-       itv->base_addr = pci_resource_start(itv->dev, 0);
+       itv->base_addr = pci_resource_start(itv->pdev, 0);
        itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */
        itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */
 
@@ -682,7 +682,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
        spin_lock_init(&itv->lock);
        spin_lock_init(&itv->dma_reg_lock);
 
-       itv->irq_work_queues = create_singlethread_workqueue(itv->device.name);
+       itv->irq_work_queues = create_singlethread_workqueue(itv->v4l2_dev.name);
        if (itv->irq_work_queues == NULL) {
                IVTV_ERR("Could not create ivtv workqueue\n");
                return -1;
@@ -766,7 +766,7 @@ static void __devinit ivtv_init_struct2(struct ivtv *itv)
        itv->audio_input = itv->card->video_inputs[i].audio_index;
 }
 
-static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
+static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
                          const struct pci_device_id *pci_id)
 {
        u16 cmd;
@@ -775,11 +775,11 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
 
        IVTV_DEBUG_INFO("Enabling pci device\n");
 
-       if (pci_enable_device(dev)) {
+       if (pci_enable_device(pdev)) {
                IVTV_ERR("Can't enable device!\n");
                return -EIO;
        }
-       if (pci_set_dma_mask(dev, 0xffffffff)) {
+       if (pci_set_dma_mask(pdev, 0xffffffff)) {
                IVTV_ERR("No suitable DMA available.\n");
                return -EIO;
        }
@@ -805,11 +805,11 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
        }
 
        /* Check for bus mastering */
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       pci_read_config_word(pdev, PCI_COMMAND, &cmd);
        if (!(cmd & PCI_COMMAND_MASTER)) {
                IVTV_DEBUG_INFO("Attempting to enable Bus Mastering\n");
-               pci_set_master(dev);
-               pci_read_config_word(dev, PCI_COMMAND, &cmd);
+               pci_set_master(pdev);
+               pci_read_config_word(pdev, PCI_COMMAND, &cmd);
                if (!(cmd & PCI_COMMAND_MASTER)) {
                        IVTV_ERR("Bus Mastering is not enabled\n");
                        return -ENXIO;
@@ -817,26 +817,26 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
        }
        IVTV_DEBUG_INFO("Bus Mastering Enabled.\n");
 
-       pci_read_config_byte(dev, PCI_CLASS_REVISION, &card_rev);
-       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
+       pci_read_config_byte(pdev, PCI_CLASS_REVISION, &card_rev);
+       pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
 
        if (pci_latency < 64 && ivtv_pci_latency) {
                IVTV_INFO("Unreasonably low latency timer, "
                               "setting to 64 (was %d)\n", pci_latency);
-               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
-               pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
+               pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
+               pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
        }
        /* This config space value relates to DMA latencies. The
           default value 0x8080 is too low however and will lead
           to DMA errors. 0xffff is the max value which solves
           these problems. */
-       pci_write_config_dword(dev, 0x40, 0xffff);
+       pci_write_config_dword(pdev, 0x40, 0xffff);
 
        IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, "
                   "irq: %d, latency: %d, memory: 0x%lx\n",
-                  itv->dev->device, card_rev, dev->bus->number,
-                  PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
-                  itv->dev->irq, pci_latency, (unsigned long)itv->base_addr);
+                  pdev->device, card_rev, pdev->bus->number,
+                  PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+                  pdev->irq, pci_latency, (unsigned long)itv->base_addr);
 
        return 0;
 }
@@ -935,7 +935,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
        }
 }
 
-static int __devinit ivtv_probe(struct pci_dev *dev,
+static int __devinit ivtv_probe(struct pci_dev *pdev,
                                const struct pci_device_id *pci_id)
 {
        int retval = 0;
@@ -945,17 +945,17 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
        itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC);
        if (itv == NULL)
                return -ENOMEM;
-       itv->dev = dev;
+       itv->pdev = pdev;
        itv->instance = atomic_inc_return(&ivtv_instance) - 1;
 
-       retval = v4l2_device_register(&dev->dev, &itv->device);
+       retval = v4l2_device_register(&pdev->dev, &itv->v4l2_dev);
        if (retval) {
                kfree(itv);
                return retval;
        }
        /* "ivtv + PCI ID" is a bit of a mouthful, so use
           "ivtv + instance" instead. */
-       snprintf(itv->device.name, sizeof(itv->device.name),
+       snprintf(itv->v4l2_dev.name, sizeof(itv->v4l2_dev.name),
                        "ivtv%d", itv->instance);
        IVTV_INFO("Initializing card %d\n", itv->instance);
 
@@ -972,12 +972,11 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
        IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr);
 
        /* PCI Device Setup */
-       if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) {
-               if (retval == -EIO)
-                       goto free_workqueue;
-               else if (retval == -ENXIO)
-                       goto free_mem;
-       }
+       retval = ivtv_setup_pci(itv, pdev, pci_id);
+       if (retval == -EIO)
+               goto free_workqueue;
+       if (retval == -ENXIO)
+               goto free_mem;
 
        /* map io memory */
        IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
@@ -1154,8 +1153,8 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
        ivtv_set_irq_mask(itv, 0xffffffff);
 
        /* Register IRQ */
-       retval = request_irq(itv->dev->irq, ivtv_irq_handler,
-            IRQF_SHARED | IRQF_DISABLED, itv->device.name, (void *)itv);
+       retval = request_irq(itv->pdev->irq, ivtv_irq_handler,
+            IRQF_SHARED | IRQF_DISABLED, itv->v4l2_dev.name, (void *)itv);
        if (retval) {
                IVTV_ERR("Failed to register irq %d\n", retval);
                goto free_i2c;
@@ -1177,7 +1176,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 free_streams:
        ivtv_streams_cleanup(itv, 1);
 free_irq:
-       free_irq(itv->dev->irq, (void *)itv);
+       free_irq(itv->pdev->irq, (void *)itv);
 free_i2c:
        exit_ivtv_i2c(itv);
 free_io:
@@ -1194,7 +1193,7 @@ err:
                retval = -ENODEV;
        IVTV_ERR("Error %d on initialization\n", retval);
 
-       v4l2_device_unregister(&itv->device);
+       v4l2_device_unregister(&itv->v4l2_dev);
        kfree(itv);
        return retval;
 }
@@ -1292,10 +1291,10 @@ int ivtv_init_on_first_open(struct ivtv *itv)
        return 0;
 }
 
-static void ivtv_remove(struct pci_dev *pci_dev)
+static void ivtv_remove(struct pci_dev *pdev)
 {
-       struct v4l2_device *dev = dev_get_drvdata(&pci_dev->dev);
-       struct ivtv *itv = to_ivtv(dev);
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+       struct ivtv *itv = to_ivtv(v4l2_dev);
        int i;
 
        IVTV_DEBUG_INFO("Removing card\n");
@@ -1336,11 +1335,9 @@ static void ivtv_remove(struct pci_dev *pci_dev)
        ivtv_streams_cleanup(itv, 1);
        ivtv_udma_free(itv);
 
-       v4l2_device_unregister(&itv->device);
-
        exit_ivtv_i2c(itv);
 
-       free_irq(itv->dev->irq, (void *)itv);
+       free_irq(itv->pdev->irq, (void *)itv);
        ivtv_iounmap(itv);
 
        release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
@@ -1348,11 +1345,13 @@ static void ivtv_remove(struct pci_dev *pci_dev)
        if (itv->has_cx23415)
                release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
 
-       pci_disable_device(itv->dev);
+       pci_disable_device(itv->pdev);
        for (i = 0; i < IVTV_VBI_FRAMES; i++)
                kfree(itv->vbi.sliced_mpeg_data[i]);
 
        printk(KERN_INFO "ivtv: Removed %s\n", itv->card_name);
+
+       v4l2_device_unregister(&itv->v4l2_dev);
        kfree(itv);
 }
 
index ce8d9b74357ef2e6ad42cd5c6261103ed8c82d1b..440f7328a7eda1aacb6bb1416f7c58718572d87d 100644 (file)
@@ -133,7 +133,7 @@ extern int ivtv_debug;
 #define IVTV_DEBUG(x, type, fmt, args...) \
        do { \
                if ((x) & ivtv_debug) \
-                       v4l2_info(&itv->device, " " type ": " fmt , ##args);    \
+                       v4l2_info(&itv->v4l2_dev, " " type ": " fmt , ##args);  \
        } while (0)
 #define IVTV_DEBUG_WARN(fmt, args...)  IVTV_DEBUG(IVTV_DBGFLG_WARN,  "warn",  fmt , ## args)
 #define IVTV_DEBUG_INFO(fmt, args...)  IVTV_DEBUG(IVTV_DBGFLG_INFO,  "info",  fmt , ## args)
@@ -149,7 +149,7 @@ extern int ivtv_debug;
 #define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \
        do { \
                if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL))   \
-                       v4l2_info(&itv->device, " " type ": " fmt , ##args);    \
+                       v4l2_info(&itv->v4l2_dev, " " type ": " fmt , ##args);  \
        } while (0)
 #define IVTV_DEBUG_HI_WARN(fmt, args...)  IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN,  "warn",  fmt , ## args)
 #define IVTV_DEBUG_HI_INFO(fmt, args...)  IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO,  "info",  fmt , ## args)
@@ -163,9 +163,9 @@ extern int ivtv_debug;
 #define IVTV_DEBUG_HI_YUV(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV,   "yuv",   fmt , ## args)
 
 /* Standard kernel messages */
-#define IVTV_ERR(fmt, args...)      v4l2_err(&itv->device, fmt , ## args)
-#define IVTV_WARN(fmt, args...)     v4l2_warn(&itv->device, fmt , ## args)
-#define IVTV_INFO(fmt, args...)     v4l2_info(&itv->device, fmt , ## args)
+#define IVTV_ERR(fmt, args...)      v4l2_err(&itv->v4l2_dev, fmt , ## args)
+#define IVTV_WARN(fmt, args...)     v4l2_warn(&itv->v4l2_dev, fmt , ## args)
+#define IVTV_INFO(fmt, args...)     v4l2_info(&itv->v4l2_dev, fmt , ## args)
 
 /* output modes (cx23415 only) */
 #define OUT_NONE        0
@@ -315,7 +315,7 @@ struct ivtv;                                /* forward reference */
 struct ivtv_stream {
        /* These first four fields are always set, even if the stream
           is not actually created. */
-       struct video_device *v4l2dev;   /* NULL when stream not created */
+       struct video_device *vdev;      /* NULL when stream not created */
        struct ivtv *itv;               /* for ease of use */
        const char *name;               /* name of the stream */
        int type;                       /* stream type */
@@ -592,7 +592,7 @@ struct ivtv_card;
 /* Struct to hold info about ivtv cards */
 struct ivtv {
        /* General fixed card data */
-       struct pci_dev *dev;            /* PCI device */
+       struct pci_dev *pdev;           /* PCI device */
        const struct ivtv_card *card;   /* card information */
        const char *card_name;          /* full name of the card */
        const struct ivtv_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
@@ -612,7 +612,7 @@ struct ivtv {
        volatile void __iomem *reg_mem; /* pointer to mapped registers */
        struct ivtv_options options;    /* user options */
 
-       struct v4l2_device device;
+       struct v4l2_device v4l2_dev;
        struct v4l2_subdev sd_gpio;     /* GPIO sub-device */
        u16 instance;
 
@@ -696,7 +696,7 @@ struct ivtv {
        u64 vbi_data_inserted;          /* number of VBI bytes inserted into the MPEG stream */
        u32 last_dec_timing[3];         /* cache last retrieved pts/scr/frame values */
        unsigned long dualwatch_jiffies;/* jiffies value of the previous dualwatch check */
-       u16 dualwatch_stereo_mode;      /* current detected dualwatch stereo mode */
+       u32 dualwatch_stereo_mode;      /* current detected dualwatch stereo mode */
 
 
        /* VBI state info */
@@ -719,9 +719,9 @@ struct ivtv {
        struct osd_info *osd_info;      /* ivtvfb private OSD info */
 };
 
-static inline struct ivtv *to_ivtv(struct v4l2_device *dev)
+static inline struct ivtv *to_ivtv(struct v4l2_device *v4l2_dev)
 {
-       return container_of(dev, struct ivtv, device);
+       return container_of(v4l2_dev, struct ivtv, v4l2_dev);
 }
 
 /* Globals */
@@ -788,7 +788,7 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv)
 /* Call the specified callback for all subdevs matching hw (if 0, then
    match them all). Ignore any errors. */
 #define ivtv_call_hw(itv, hw, o, f, args...)                           \
-       __v4l2_device_call_subdevs(&(itv)->device, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+       __v4l2_device_call_subdevs(&(itv)->v4l2_dev, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
 
 #define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args)
 
@@ -796,7 +796,7 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv)
    match them all). If the callback returns an error other than 0 or
    -ENOIOCTLCMD, then return with that error code. */
 #define ivtv_call_hw_err(itv, hw, o, f, args...)               \
-       __v4l2_device_call_subdevs_until_err(&(itv)->device, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+       __v4l2_device_call_subdevs_until_err(&(itv)->v4l2_dev, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
 
 #define ivtv_call_all_err(itv, o, f, args...) ivtv_call_hw_err(itv, 0, o, f , ##args)
 
index d594bc29f07f48a4293f0e1b7e753719e30e9f2a..cfaacf6096d00735f7703f66fd5c282b592d54d8 100644 (file)
@@ -148,10 +148,10 @@ void ivtv_release_stream(struct ivtv_stream *s)
 static void ivtv_dualwatch(struct ivtv *itv)
 {
        struct v4l2_tuner vt;
-       u16 new_bitmap;
-       u16 new_stereo_mode;
-       const u16 stereo_mask = 0x0300;
-       const u16 dual = 0x0200;
+       u32 new_bitmap;
+       u32 new_stereo_mode;
+       const u32 stereo_mask = 0x0300;
+       const u32 dual = 0x0200;
 
        new_stereo_mode = itv->params.audio_properties & stereo_mask;
        memset(&vt, 0, sizeof(vt));
@@ -991,7 +991,7 @@ int ivtv_v4l2_open(struct file *filp)
        mutex_lock(&itv->serialize_lock);
        if (ivtv_init_on_first_open(itv)) {
                IVTV_ERR("Failed to initialize on minor %d\n",
-                               s->v4l2dev->minor);
+                               vdev->minor);
                mutex_unlock(&itv->serialize_lock);
                return -ENXIO;
        }
index 6dba55b7e25aea7cd5892869edf36f72598238f7..c1b7ec475c27cc1813c2a89dd42a8a807e6c04c4 100644 (file)
@@ -52,7 +52,7 @@ static int load_fw_direct(const char *fn, volatile u8 __iomem *mem, struct ivtv
        int retries = 3;
 
 retry:
-       if (retries && request_firmware(&fw, fn, &itv->dev->dev) == 0) {
+       if (retries && request_firmware(&fw, fn, &itv->pdev->dev) == 0) {
                int i;
                volatile u32 __iomem *dst = (volatile u32 __iomem *)mem;
                const u32 *src = (const u32 *)fw->data;
index dc2850e87a7e1b1106b8da0a8eac50b9363c0ce6..3321983d89e55124516801296fd9caeaa81b88dc 100644 (file)
@@ -384,7 +384,7 @@ int ivtv_gpio_init(struct ivtv *itv)
        write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT);
        write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR);
        v4l2_subdev_init(&itv->sd_gpio, &subdev_ops);
-       snprintf(itv->sd_gpio.name, sizeof(itv->sd_gpio.name), "%s-gpio", itv->device.name);
+       snprintf(itv->sd_gpio.name, sizeof(itv->sd_gpio.name), "%s-gpio", itv->v4l2_dev.name);
        itv->sd_gpio.grp_id = IVTV_HW_GPIO;
-       return v4l2_device_register_subdev(&itv->device, &itv->sd_gpio);
+       return v4l2_device_register_subdev(&itv->v4l2_dev, &itv->sd_gpio);
 }
index ca1d9557945eef807310b8dbaad09bab69d9a674..e73a196ecc7ac88f9518a9c0539cf0defcbe198f 100644 (file)
@@ -194,14 +194,14 @@ struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw)
        struct v4l2_subdev *result = NULL;
        struct v4l2_subdev *sd;
 
-       spin_lock(&itv->device.lock);
-       v4l2_device_for_each_subdev(sd, &itv->device) {
+       spin_lock(&itv->v4l2_dev.lock);
+       v4l2_device_for_each_subdev(sd, &itv->v4l2_dev) {
                if (sd->grp_id == hw) {
                        result = sd;
                        break;
                }
        }
-       spin_unlock(&itv->device.lock);
+       spin_unlock(&itv->v4l2_dev.lock);
        return result;
 }
 
@@ -472,8 +472,8 @@ static int ivtv_read(struct ivtv *itv, unsigned char addr, unsigned char *data,
    intervening stop condition */
 static int ivtv_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
 {
-       struct v4l2_device *drv = i2c_get_adapdata(i2c_adap);
-       struct ivtv *itv = to_ivtv(drv);
+       struct v4l2_device *v4l2_dev = i2c_get_adapdata(i2c_adap);
+       struct ivtv *itv = to_ivtv(v4l2_dev);
        int retval;
        int i;
 
@@ -604,12 +604,12 @@ int init_ivtv_i2c(struct ivtv *itv)
 
        sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d",
                itv->instance);
-       i2c_set_adapdata(&itv->i2c_adap, &itv->device);
+       i2c_set_adapdata(&itv->i2c_adap, &itv->v4l2_dev);
 
        memcpy(&itv->i2c_client, &ivtv_i2c_client_template,
               sizeof(struct i2c_client));
        itv->i2c_client.adapter = &itv->i2c_adap;
-       itv->i2c_adap.dev.parent = &itv->dev->dev;
+       itv->i2c_adap.dev.parent = &itv->pdev->dev;
 
        IVTV_DEBUG_I2C("setting scl and sda to 1\n");
        ivtv_setscl(itv, 1);
index c13bd2aa0bea6180a98fe078be7449e6ea2e25ca..9a0424298af1452c30562c730ef10f4f85d96279 100644 (file)
@@ -345,10 +345,8 @@ static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
        pixfmt->priv = 0;
        if (id->type == IVTV_ENC_STREAM_TYPE_YUV) {
                pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
-               /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
-               pixfmt->sizeimage =
-                       pixfmt->height * pixfmt->width +
-                       pixfmt->height * (pixfmt->width / 2);
+               /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */
+               pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
                pixfmt->bytesperline = 720;
        } else {
                pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
@@ -469,11 +467,17 @@ static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format
        struct ivtv *itv = id->itv;
        int w = fmt->fmt.pix.width;
        int h = fmt->fmt.pix.height;
+       int min_h = 2;
 
        w = min(w, 720);
        w = max(w, 2);
+       if (id->type == IVTV_ENC_STREAM_TYPE_YUV) {
+               /* YUV height must be a multiple of 32 */
+               h &= ~0x1f;
+               min_h = 32;
+       }
        h = min(h, itv->is_50hz ? 576 : 480);
-       h = max(h, 2);
+       h = max(h, min_h);
        ivtv_g_fmt_vid_cap(file, fh, fmt);
        fmt->fmt.pix.width = w;
        fmt->fmt.pix.height = h;
@@ -766,7 +770,7 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc
 
        strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
        strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
-       snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->dev));
+       snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev));
        vcap->version = IVTV_DRIVER_VERSION;        /* version */
        vcap->capabilities = itv->v4l2_cap;         /* capabilities */
        return 0;
@@ -1513,12 +1517,12 @@ static int ivtv_log_status(struct file *file, void *fh)
        }
        IVTV_INFO("Tuner:  %s\n",
                test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
-       cx2341x_log_status(&itv->params, itv->device.name);
+       cx2341x_log_status(&itv->params, itv->v4l2_dev.name);
        IVTV_INFO("Status flags:    0x%08lx\n", itv->i_flags);
        for (i = 0; i < IVTV_MAX_STREAMS; i++) {
                struct ivtv_stream *s = &itv->streams[i];
 
-               if (s->v4l2dev == NULL || s->buffers == 0)
+               if (s->vdev == NULL || s->buffers == 0)
                        continue;
                IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags,
                                (s->buffers - s->q_free.buffers) * 100 / s->buffers,
index f5d00ec5da73501cb2b99ad93404b9b5dc63a881..01c14d2b381a3111ab9db4389aa8ce09a8dd4757 100644 (file)
@@ -46,7 +46,7 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
 
        IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n");
        if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS ||
-                       s->v4l2dev == NULL || !ivtv_use_pio(s)) {
+                       s->vdev == NULL || !ivtv_use_pio(s)) {
                itv->cur_pio_stream = -1;
                /* trigger PIO complete user interrupt */
                write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
@@ -109,7 +109,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
        int rc;
 
        /* sanity checks */
-       if (s->v4l2dev == NULL) {
+       if (s->vdev == NULL) {
                IVTV_DEBUG_WARN("Stream %s not started\n", s->name);
                return -1;
        }
index 71bd13e22e2ee20a5f6d27c2a4bceda494fd6d61..ff7b7deded4f5108def042ffc8e6cdf665982201 100644 (file)
@@ -230,7 +230,7 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
                return -ENOMEM;
        }
        if (ivtv_might_use_dma(s)) {
-               s->sg_handle = pci_map_single(itv->dev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma);
+               s->sg_handle = pci_map_single(itv->pdev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma);
                ivtv_stream_sync_for_cpu(s);
        }
 
@@ -248,7 +248,7 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
                }
                INIT_LIST_HEAD(&buf->list);
                if (ivtv_might_use_dma(s)) {
-                       buf->dma_handle = pci_map_single(s->itv->dev,
+                       buf->dma_handle = pci_map_single(s->itv->pdev,
                                buf->buf, s->buf_size + 256, s->dma);
                        ivtv_buf_sync_for_cpu(s, buf);
                }
@@ -271,7 +271,7 @@ void ivtv_stream_free(struct ivtv_stream *s)
        /* empty q_free */
        while ((buf = ivtv_dequeue(s, &s->q_free))) {
                if (ivtv_might_use_dma(s))
-                       pci_unmap_single(s->itv->dev, buf->dma_handle,
+                       pci_unmap_single(s->itv->pdev, buf->dma_handle,
                                s->buf_size + 256, s->dma);
                kfree(buf->buf);
                kfree(buf);
@@ -280,7 +280,7 @@ void ivtv_stream_free(struct ivtv_stream *s)
        /* Free SG Array/Lists */
        if (s->sg_dma != NULL) {
                if (s->sg_handle != IVTV_DMA_UNMAPPED) {
-                       pci_unmap_single(s->itv->dev, s->sg_handle,
+                       pci_unmap_single(s->itv->pdev, s->sg_handle,
                                 sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
                        s->sg_handle = IVTV_DMA_UNMAPPED;
                }
index 476556afd39aa2bc99c8f3b4cee03d91d07a0fd8..91233839a26c7747b298a5b2523e43e87455da26 100644 (file)
@@ -53,14 +53,14 @@ static inline int ivtv_use_dma(struct ivtv_stream *s)
 static inline void ivtv_buf_sync_for_cpu(struct ivtv_stream *s, struct ivtv_buffer *buf)
 {
        if (ivtv_use_dma(s))
-               pci_dma_sync_single_for_cpu(s->itv->dev, buf->dma_handle,
+               pci_dma_sync_single_for_cpu(s->itv->pdev, buf->dma_handle,
                                s->buf_size + 256, s->dma);
 }
 
 static inline void ivtv_buf_sync_for_device(struct ivtv_stream *s, struct ivtv_buffer *buf)
 {
        if (ivtv_use_dma(s))
-               pci_dma_sync_single_for_device(s->itv->dev, buf->dma_handle,
+               pci_dma_sync_single_for_device(s->itv->pdev, buf->dma_handle,
                                s->buf_size + 256, s->dma);
 }
 
@@ -82,14 +82,14 @@ void ivtv_stream_free(struct ivtv_stream *s);
 static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s)
 {
        if (ivtv_use_dma(s))
-               pci_dma_sync_single_for_cpu(s->itv->dev, s->sg_handle,
+               pci_dma_sync_single_for_cpu(s->itv->pdev, s->sg_handle,
                        sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
 }
 
 static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s)
 {
        if (ivtv_use_dma(s))
-               pci_dma_sync_single_for_device(s->itv->dev, s->sg_handle,
+               pci_dma_sync_single_for_device(s->itv->pdev, s->sg_handle,
                        sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
 }
 
index 854a950af78c757ae95ff9f8a39a6a7a6f1d3ede..15da01710efc61f044d5ba6854b406135fd174ee 100644 (file)
@@ -137,11 +137,11 @@ static struct {
 static void ivtv_stream_init(struct ivtv *itv, int type)
 {
        struct ivtv_stream *s = &itv->streams[type];
-       struct video_device *dev = s->v4l2dev;
+       struct video_device *vdev = s->vdev;
 
-       /* we need to keep v4l2dev, so restore it afterwards */
+       /* we need to keep vdev, so restore it afterwards */
        memset(s, 0, sizeof(*s));
-       s->v4l2dev = dev;
+       s->vdev = vdev;
 
        /* initialize ivtv_stream fields */
        s->itv = itv;
@@ -172,10 +172,10 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
        int num_offset = ivtv_stream_info[type].num_offset;
        int num = itv->instance + ivtv_first_minor + num_offset;
 
-       /* These four fields are always initialized. If v4l2dev == NULL, then
+       /* These four fields are always initialized. If vdev == NULL, then
           this stream is not in use. In that case no other fields but these
           four can be used. */
-       s->v4l2dev = NULL;
+       s->vdev = NULL;
        s->itv = itv;
        s->type = type;
        s->name = ivtv_stream_info[type].name;
@@ -197,21 +197,21 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
        ivtv_stream_init(itv, type);
 
        /* allocate and initialize the v4l2 video device structure */
-       s->v4l2dev = video_device_alloc();
-       if (s->v4l2dev == NULL) {
+       s->vdev = video_device_alloc();
+       if (s->vdev == NULL) {
                IVTV_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name);
                return -ENOMEM;
        }
 
-       snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "%s %s",
-                       itv->device.name, s->name);
+       snprintf(s->vdev->name, sizeof(s->vdev->name), "%s %s",
+                       itv->v4l2_dev.name, s->name);
 
-       s->v4l2dev->num = num;
-       s->v4l2dev->v4l2_dev = &itv->device;
-       s->v4l2dev->fops = ivtv_stream_info[type].fops;
-       s->v4l2dev->release = video_device_release;
-       s->v4l2dev->tvnorms = V4L2_STD_ALL;
-       ivtv_set_funcs(s->v4l2dev);
+       s->vdev->num = num;
+       s->vdev->v4l2_dev = &itv->v4l2_dev;
+       s->vdev->fops = ivtv_stream_info[type].fops;
+       s->vdev->release = video_device_release;
+       s->vdev->tvnorms = V4L2_STD_ALL;
+       ivtv_set_funcs(s->vdev);
        return 0;
 }
 
@@ -226,7 +226,7 @@ int ivtv_streams_setup(struct ivtv *itv)
                if (ivtv_prep_dev(itv, type))
                        break;
 
-               if (itv->streams[type].v4l2dev == NULL)
+               if (itv->streams[type].vdev == NULL)
                        continue;
 
                /* Allocate Stream */
@@ -247,28 +247,28 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
        int vfl_type = ivtv_stream_info[type].vfl_type;
        int num;
 
-       if (s->v4l2dev == NULL)
+       if (s->vdev == NULL)
                return 0;
 
-       num = s->v4l2dev->num;
+       num = s->vdev->num;
        /* card number + user defined offset + device offset */
        if (type != IVTV_ENC_STREAM_TYPE_MPG) {
                struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
 
-               if (s_mpg->v4l2dev)
-                       num = s_mpg->v4l2dev->num + ivtv_stream_info[type].num_offset;
+               if (s_mpg->vdev)
+                       num = s_mpg->vdev->num + ivtv_stream_info[type].num_offset;
        }
-       video_set_drvdata(s->v4l2dev, s);
+       video_set_drvdata(s->vdev, s);
 
        /* Register device. First try the desired minor, then any free one. */
-       if (video_register_device(s->v4l2dev, vfl_type, num)) {
+       if (video_register_device(s->vdev, vfl_type, num)) {
                IVTV_ERR("Couldn't register v4l2 device for %s kernel number %d\n",
                                s->name, num);
-               video_device_release(s->v4l2dev);
-               s->v4l2dev = NULL;
+               video_device_release(s->vdev);
+               s->vdev = NULL;
                return -ENOMEM;
        }
-       num = s->v4l2dev->num;
+       num = s->vdev->num;
 
        switch (vfl_type) {
        case VFL_TYPE_GRABBER:
@@ -316,9 +316,9 @@ void ivtv_streams_cleanup(struct ivtv *itv, int unregister)
 
        /* Teardown all streams */
        for (type = 0; type < IVTV_MAX_STREAMS; type++) {
-               struct video_device *vdev = itv->streams[type].v4l2dev;
+               struct video_device *vdev = itv->streams[type].vdev;
 
-               itv->streams[type].v4l2dev = NULL;
+               itv->streams[type].vdev = NULL;
                if (vdev == NULL)
                        continue;
 
@@ -449,7 +449,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
        int captype = 0, subtype = 0;
        int enable_passthrough = 0;
 
-       if (s->v4l2dev == NULL)
+       if (s->vdev == NULL)
                return -EINVAL;
 
        IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
@@ -611,7 +611,7 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
        struct cx2341x_mpeg_params *p = &itv->params;
        int datatype;
 
-       if (s->v4l2dev == NULL)
+       if (s->vdev == NULL)
                return -EINVAL;
 
        IVTV_DEBUG_INFO("Setting some initial decoder settings\n");
@@ -657,7 +657,7 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
 {
        struct ivtv *itv = s->itv;
 
-       if (s->v4l2dev == NULL)
+       if (s->vdev == NULL)
                return -EINVAL;
 
        if (test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags))
@@ -705,7 +705,7 @@ void ivtv_stop_all_captures(struct ivtv *itv)
        for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) {
                struct ivtv_stream *s = &itv->streams[i];
 
-               if (s->v4l2dev == NULL)
+               if (s->vdev == NULL)
                        continue;
                if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
                        ivtv_stop_v4l2_encode_stream(s, 0);
@@ -720,7 +720,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
        int cap_type;
        int stopmode;
 
-       if (s->v4l2dev == NULL)
+       if (s->vdev == NULL)
                return -EINVAL;
 
        /* This function assumes that you are allowed to stop the capture
@@ -834,7 +834,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
 {
        struct ivtv *itv = s->itv;
 
-       if (s->v4l2dev == NULL)
+       if (s->vdev == NULL)
                return -EINVAL;
 
        if (s->type != IVTV_DEC_STREAM_TYPE_YUV && s->type != IVTV_DEC_STREAM_TYPE_MPG)
@@ -895,7 +895,7 @@ int ivtv_passthrough_mode(struct ivtv *itv, int enable)
        struct ivtv_stream *yuv_stream = &itv->streams[IVTV_ENC_STREAM_TYPE_YUV];
        struct ivtv_stream *dec_stream = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
 
-       if (yuv_stream->v4l2dev == NULL || dec_stream->v4l2dev == NULL)
+       if (yuv_stream->vdev == NULL || dec_stream->vdev == NULL)
                return -EINVAL;
 
        IVTV_DEBUG_INFO("ivtv ioctl: Select passthrough mode\n");
index 460db03b0ba061477ae321038378f99b08c6b61e..d07ad6c39024774c11cb41c14f451d57b52c6f6d 100644 (file)
@@ -93,7 +93,7 @@ void ivtv_udma_alloc(struct ivtv *itv)
 {
        if (itv->udma.SG_handle == 0) {
                /* Map DMA Page Array Buffer */
-               itv->udma.SG_handle = pci_map_single(itv->dev, itv->udma.SGarray,
+               itv->udma.SG_handle = pci_map_single(itv->pdev, itv->udma.SGarray,
                           sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
                ivtv_udma_sync_for_cpu(itv);
        }
@@ -147,7 +147,7 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
        }
 
        /* Map SG List */
-       dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
+       dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
 
        /* Fill SG Array with new values */
        ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1);
@@ -172,7 +172,7 @@ void ivtv_udma_unmap(struct ivtv *itv)
 
        /* Unmap Scatterlist */
        if (dma->SG_length) {
-               pci_unmap_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
+               pci_unmap_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
                dma->SG_length = 0;
        }
        /* sync DMA */
@@ -191,13 +191,13 @@ void ivtv_udma_free(struct ivtv *itv)
 
        /* Unmap SG Array */
        if (itv->udma.SG_handle) {
-               pci_unmap_single(itv->dev, itv->udma.SG_handle,
+               pci_unmap_single(itv->pdev, itv->udma.SG_handle,
                         sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
        }
 
        /* Unmap Scatterlist */
        if (itv->udma.SG_length) {
-               pci_unmap_sg(itv->dev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE);
+               pci_unmap_sg(itv->pdev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE);
        }
 
        for (i = 0; i < IVTV_DMA_SG_OSD_ENT; i++) {
index df727e23be0a4719a57c2e6698821c46a8c1cf3e..ee3c9efb5b727d0ae86b24c9bdb251f3692a6a77 100644 (file)
@@ -35,13 +35,13 @@ void ivtv_udma_start(struct ivtv *itv);
 
 static inline void ivtv_udma_sync_for_device(struct ivtv *itv)
 {
-       pci_dma_sync_single_for_device((struct pci_dev *)itv->dev, itv->udma.SG_handle,
+       pci_dma_sync_single_for_device(itv->pdev, itv->udma.SG_handle,
                sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
 }
 
 static inline void ivtv_udma_sync_for_cpu(struct ivtv *itv)
 {
-       pci_dma_sync_single_for_cpu((struct pci_dev *)itv->dev, itv->udma.SG_handle,
+       pci_dma_sync_single_for_cpu(itv->pdev, itv->udma.SG_handle,
                sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
 }
 
index 5c5d1c462fefe7cd752e2ffa77b7ddc36ae4a024..f420d31b937dcfccfb8ee64c76eade9197d62979 100644 (file)
@@ -185,6 +185,8 @@ static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp)
                size = 4 + ((43 * line + 3) & ~3);
        } else {
                memcpy(dst + sd, "itv0", 4);
+               cpu_to_le32s(&linemask[0]);
+               cpu_to_le32s(&linemask[1]);
                memcpy(dst + sd + 4, &linemask[0], 8);
                size = 12 + ((43 * line + 3) & ~3);
        }
index 8cd753d30bf76160bf4f3f2a951b34c5a31b760e..b530dec399d31dda6aa24ee1d7864ed855832bf9 100644 (file)
@@ -23,7 +23,7 @@
 #define IVTV_DRIVER_NAME "ivtv"
 #define IVTV_DRIVER_VERSION_MAJOR 1
 #define IVTV_DRIVER_VERSION_MINOR 4
-#define IVTV_DRIVER_VERSION_PATCHLEVEL 0
+#define IVTV_DRIVER_VERSION_PATCHLEVEL 1
 
 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
 #define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL)
index ee91107376c75440ca56f6620924724a2267c5ab..7912ed6b72eec0e70a4028cfefc66efe04dbb1d8 100644 (file)
@@ -103,7 +103,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
                dma->page_count = 0;
                return -ENOMEM;
        }
-       dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
+       dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
 
        /* Fill SG Array with new values */
        ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
@@ -910,7 +910,7 @@ static void ivtv_yuv_init(struct ivtv *itv)
        /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
        yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);
        if (yi->blanking_ptr) {
-               yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
+               yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
        } else {
                yi->blanking_dmaptr = 0;
                IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
@@ -1237,7 +1237,7 @@ void ivtv_yuv_close(struct ivtv *itv)
        if (yi->blanking_ptr) {
                kfree(yi->blanking_ptr);
                yi->blanking_ptr = NULL;
-               pci_unmap_single(itv->dev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
+               pci_unmap_single(itv->pdev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
        }
 
        /* Invalidate the old dimension information */
index 36abd2aef6f1473b6ff90948bb3235de5941ddbd..66e6eb513076a8073831bacdc462e34955c9d885 100644 (file)
@@ -1192,12 +1192,12 @@ static int ivtvfb_init_card(struct ivtv *itv)
 static int __init ivtvfb_callback_init(struct device *dev, void *p)
 {
        struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
-       struct ivtv *itv = container_of(v4l2_dev, struct ivtv, device);
+       struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
 
        if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
                if (ivtvfb_init_card(itv) == 0) {
                        IVTVFB_INFO("Framebuffer registered on %s\n",
-                                       itv->device.name);
+                                       itv->v4l2_dev.name);
                        (*(int *)p)++;
                }
        }
@@ -1207,7 +1207,7 @@ static int __init ivtvfb_callback_init(struct device *dev, void *p)
 static int ivtvfb_callback_cleanup(struct device *dev, void *p)
 {
        struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
-       struct ivtv *itv = container_of(v4l2_dev, struct ivtv, device);
+       struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
 
        if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
                if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
index bae2d2beb7093344f84b89ee7e0629701c14ca6c..841024b6bcdf7c9274fcddc34260211c1349db95 100644 (file)
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/i2c.h>
-#include <linux/video_decoder.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 #include "ks0127.h"
 
 MODULE_DESCRIPTION("KS0127 video decoder driver");
 MODULE_AUTHOR("Ryan Drake");
 MODULE_LICENSE("GPL");
 
-#define KS_TYPE_UNKNOWN        0
-#define KS_TYPE_0122S  1
-#define KS_TYPE_0127   2
-#define KS_TYPE_0127B  3
+/* Addresses */
+#define I2C_KS0127_ADDON   0xD8
+#define I2C_KS0127_ONBOARD 0xDA
+
 
 /* ks0127 control registers */
 #define KS_STAT     0x00
@@ -197,15 +198,17 @@ struct adjust {
 };
 
 struct ks0127 {
-       int             format_width;
-       int             format_height;
-       int             cap_width;
-       int             cap_height;
-       int             norm;
-       int             ks_type;
+       struct v4l2_subdev sd;
+       v4l2_std_id     norm;
+       int             ident;
        u8              regs[256];
 };
 
+static inline struct ks0127 *to_ks0127(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct ks0127, sd);
+}
+
 
 static int debug; /* insmod parameter */
 
@@ -311,43 +314,45 @@ static void init_reg_defaults(void)
  */
 
 
-static u8 ks0127_read(struct i2c_client *c, u8 reg)
+static u8 ks0127_read(struct v4l2_subdev *sd, u8 reg)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        char val = 0;
        struct i2c_msg msgs[] = {
-               { c->addr, 0, sizeof(reg), &reg },
-               { c->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val }
+               { client->addr, 0, sizeof(reg), &reg },
+               { client->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val }
        };
        int ret;
 
-       ret = i2c_transfer(c->adapter, msgs, ARRAY_SIZE(msgs));
+       ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
        if (ret != ARRAY_SIZE(msgs))
-               v4l_dbg(1, debug, c, "read error\n");
+               v4l2_dbg(1, debug, sd, "read error\n");
 
        return val;
 }
 
 
-static void ks0127_write(struct i2c_client *c, u8 reg, u8 val)
+static void ks0127_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
-       struct ks0127 *ks = i2c_get_clientdata(c);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ks0127 *ks = to_ks0127(sd);
        char msg[] = { reg, val };
 
-       if (i2c_master_send(c, msg, sizeof(msg)) != sizeof(msg))
-               v4l_dbg(1, debug, c, "write error\n");
+       if (i2c_master_send(client, msg, sizeof(msg)) != sizeof(msg))
+               v4l2_dbg(1, debug, sd, "write error\n");
 
        ks->regs[reg] = val;
 }
 
 
 /* generic bit-twiddling */
-static void ks0127_and_or(struct i2c_client *client, u8 reg, u8 and_v, u8 or_v)
+static void ks0127_and_or(struct v4l2_subdev *sd, u8 reg, u8 and_v, u8 or_v)
 {
-       struct ks0127 *ks = i2c_get_clientdata(client);
+       struct ks0127 *ks = to_ks0127(sd);
 
        u8 val = ks->regs[reg];
        val = (val & and_v) | or_v;
-       ks0127_write(client, reg, val);
+       ks0127_write(sd, reg, val);
 }
 
 
@@ -355,439 +360,363 @@ static void ks0127_and_or(struct i2c_client *client, u8 reg, u8 and_v, u8 or_v)
 /****************************************************************************
 * ks0127 private api
 ****************************************************************************/
-static void ks0127_reset(struct i2c_client *c)
+static void ks0127_init(struct v4l2_subdev *sd)
 {
-       struct ks0127 *ks = i2c_get_clientdata(c);
+       struct ks0127 *ks = to_ks0127(sd);
        u8 *table = reg_defaults;
        int i;
 
-       ks->ks_type = KS_TYPE_UNKNOWN;
+       ks->ident = V4L2_IDENT_KS0127;
 
-       v4l_dbg(1, debug, c, "reset\n");
+       v4l2_dbg(1, debug, sd, "reset\n");
        msleep(1);
 
        /* initialize all registers to known values */
        /* (except STAT, 0x21, 0x22, TEST and 0x38,0x39) */
 
        for (i = 1; i < 33; i++)
-               ks0127_write(c, i, table[i]);
+               ks0127_write(sd, i, table[i]);
 
        for (i = 35; i < 40; i++)
-               ks0127_write(c, i, table[i]);
+               ks0127_write(sd, i, table[i]);
 
        for (i = 41; i < 56; i++)
-               ks0127_write(c, i, table[i]);
+               ks0127_write(sd, i, table[i]);
 
        for (i = 58; i < 64; i++)
-               ks0127_write(c, i, table[i]);
+               ks0127_write(sd, i, table[i]);
 
 
-       if ((ks0127_read(c, KS_STAT) & 0x80) == 0) {
-               ks->ks_type = KS_TYPE_0122S;
-               v4l_dbg(1, debug, c, "ks0122s found\n");
+       if ((ks0127_read(sd, KS_STAT) & 0x80) == 0) {
+               ks->ident = V4L2_IDENT_KS0122S;
+               v4l2_dbg(1, debug, sd, "ks0122s found\n");
                return;
        }
 
-       switch (ks0127_read(c, KS_CMDE) & 0x0f) {
+       switch (ks0127_read(sd, KS_CMDE) & 0x0f) {
        case 0:
-               ks->ks_type = KS_TYPE_0127;
-               v4l_dbg(1, debug, c, "ks0127 found\n");
+               v4l2_dbg(1, debug, sd, "ks0127 found\n");
                break;
 
        case 9:
-               ks->ks_type = KS_TYPE_0127B;
-               v4l_dbg(1, debug, c, "ks0127B Revision A found\n");
+               ks->ident = V4L2_IDENT_KS0127B;
+               v4l2_dbg(1, debug, sd, "ks0127B Revision A found\n");
                break;
 
        default:
-               v4l_dbg(1, debug, c, "unknown revision\n");
+               v4l2_dbg(1, debug, sd, "unknown revision\n");
                break;
        }
 }
 
-static int ks0127_command(struct i2c_client *c, unsigned cmd, void *arg)
+static int ks0127_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
 {
-       struct ks0127 *ks = i2c_get_clientdata(c);
-       int             *iarg = (int *)arg;
-       int             status;
-
-       if (!ks)
-               return -ENODEV;
+       struct ks0127 *ks = to_ks0127(sd);
+
+       switch (route->input) {
+       case KS_INPUT_COMPOSITE_1:
+       case KS_INPUT_COMPOSITE_2:
+       case KS_INPUT_COMPOSITE_3:
+       case KS_INPUT_COMPOSITE_4:
+       case KS_INPUT_COMPOSITE_5:
+       case KS_INPUT_COMPOSITE_6:
+               v4l2_dbg(1, debug, sd,
+                       "s_routing %d: Composite\n", route->input);
+               /* autodetect 50/60 Hz */
+               ks0127_and_or(sd, KS_CMDA,   0xfc, 0x00);
+               /* VSE=0 */
+               ks0127_and_or(sd, KS_CMDA,   ~0x40, 0x00);
+               /* set input line */
+               ks0127_and_or(sd, KS_CMDB,   0xb0, route->input);
+               /* non-freerunning mode */
+               ks0127_and_or(sd, KS_CMDC,   0x70, 0x0a);
+               /* analog input */
+               ks0127_and_or(sd, KS_CMDD,   0x03, 0x00);
+               /* enable chroma demodulation */
+               ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x00);
+               /* chroma trap, HYBWR=1 */
+               ks0127_and_or(sd, KS_LUMA,   0x00,
+                              (reg_defaults[KS_LUMA])|0x0c);
+               /* scaler fullbw, luma comb off */
+               ks0127_and_or(sd, KS_VERTIA, 0x08, 0x81);
+               /* manual chroma comb .25 .5 .25 */
+               ks0127_and_or(sd, KS_VERTIC, 0x0f, 0x90);
+
+               /* chroma path delay */
+               ks0127_and_or(sd, KS_CHROMB, 0x0f, 0x90);
+
+               ks0127_write(sd, KS_UGAIN, reg_defaults[KS_UGAIN]);
+               ks0127_write(sd, KS_VGAIN, reg_defaults[KS_VGAIN]);
+               ks0127_write(sd, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+               ks0127_write(sd, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+               break;
 
-       switch (cmd) {
-       case DECODER_INIT:
-               v4l_dbg(1, debug, c, "DECODER_INIT\n");
-               ks0127_reset(c);
+       case KS_INPUT_SVIDEO_1:
+       case KS_INPUT_SVIDEO_2:
+       case KS_INPUT_SVIDEO_3:
+               v4l2_dbg(1, debug, sd,
+                       "s_routing %d: S-Video\n", route->input);
+               /* autodetect 50/60 Hz */
+               ks0127_and_or(sd, KS_CMDA,   0xfc, 0x00);
+               /* VSE=0 */
+               ks0127_and_or(sd, KS_CMDA,   ~0x40, 0x00);
+               /* set input line */
+               ks0127_and_or(sd, KS_CMDB,   0xb0, route->input);
+               /* non-freerunning mode */
+               ks0127_and_or(sd, KS_CMDC,   0x70, 0x0a);
+               /* analog input */
+               ks0127_and_or(sd, KS_CMDD,   0x03, 0x00);
+               /* enable chroma demodulation */
+               ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x00);
+               ks0127_and_or(sd, KS_LUMA, 0x00,
+                              reg_defaults[KS_LUMA]);
+               /* disable luma comb */
+               ks0127_and_or(sd, KS_VERTIA, 0x08,
+                              (reg_defaults[KS_VERTIA]&0xf0)|0x01);
+               ks0127_and_or(sd, KS_VERTIC, 0x0f,
+                              reg_defaults[KS_VERTIC]&0xf0);
+
+               ks0127_and_or(sd, KS_CHROMB, 0x0f,
+                              reg_defaults[KS_CHROMB]&0xf0);
+
+               ks0127_write(sd, KS_UGAIN, reg_defaults[KS_UGAIN]);
+               ks0127_write(sd, KS_VGAIN, reg_defaults[KS_VGAIN]);
+               ks0127_write(sd, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+               ks0127_write(sd, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
                break;
 
-       case DECODER_SET_INPUT:
-               switch(*iarg) {
-               case KS_INPUT_COMPOSITE_1:
-               case KS_INPUT_COMPOSITE_2:
-               case KS_INPUT_COMPOSITE_3:
-               case KS_INPUT_COMPOSITE_4:
-               case KS_INPUT_COMPOSITE_5:
-               case KS_INPUT_COMPOSITE_6:
-                       v4l_dbg(1, debug, c,
-                               "DECODER_SET_INPUT %d: Composite\n", *iarg);
-                       /* autodetect 50/60 Hz */
-                       ks0127_and_or(c, KS_CMDA,   0xfc, 0x00);
-                       /* VSE=0 */
-                       ks0127_and_or(c, KS_CMDA,   ~0x40, 0x00);
-                       /* set input line */
-                       ks0127_and_or(c, KS_CMDB,   0xb0, *iarg);
-                       /* non-freerunning mode */
-                       ks0127_and_or(c, KS_CMDC,   0x70, 0x0a);
-                       /* analog input */
-                       ks0127_and_or(c, KS_CMDD,   0x03, 0x00);
-                       /* enable chroma demodulation */
-                       ks0127_and_or(c, KS_CTRACK, 0xcf, 0x00);
-                       /* chroma trap, HYBWR=1 */
-                       ks0127_and_or(c, KS_LUMA,   0x00,
-                                      (reg_defaults[KS_LUMA])|0x0c);
-                       /* scaler fullbw, luma comb off */
-                       ks0127_and_or(c, KS_VERTIA, 0x08, 0x81);
-                       /* manual chroma comb .25 .5 .25 */
-                       ks0127_and_or(c, KS_VERTIC, 0x0f, 0x90);
-
-                       /* chroma path delay */
-                       ks0127_and_or(c, KS_CHROMB, 0x0f, 0x90);
-
-                       ks0127_write(c, KS_UGAIN, reg_defaults[KS_UGAIN]);
-                       ks0127_write(c, KS_VGAIN, reg_defaults[KS_VGAIN]);
-                       ks0127_write(c, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
-                       ks0127_write(c, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
-                       break;
-
-               case KS_INPUT_SVIDEO_1:
-               case KS_INPUT_SVIDEO_2:
-               case KS_INPUT_SVIDEO_3:
-                       v4l_dbg(1, debug, c,
-                               "DECODER_SET_INPUT %d: S-Video\n", *iarg);
-                       /* autodetect 50/60 Hz */
-                       ks0127_and_or(c, KS_CMDA,   0xfc, 0x00);
-                       /* VSE=0 */
-                       ks0127_and_or(c, KS_CMDA,   ~0x40, 0x00);
-                       /* set input line */
-                       ks0127_and_or(c, KS_CMDB,   0xb0, *iarg);
-                       /* non-freerunning mode */
-                       ks0127_and_or(c, KS_CMDC,   0x70, 0x0a);
-                       /* analog input */
-                       ks0127_and_or(c, KS_CMDD,   0x03, 0x00);
-                       /* enable chroma demodulation */
-                       ks0127_and_or(c, KS_CTRACK, 0xcf, 0x00);
-                       ks0127_and_or(c, KS_LUMA, 0x00,
-                                      reg_defaults[KS_LUMA]);
-                       /* disable luma comb */
-                       ks0127_and_or(c, KS_VERTIA, 0x08,
-                                      (reg_defaults[KS_VERTIA]&0xf0)|0x01);
-                       ks0127_and_or(c, KS_VERTIC, 0x0f,
-                                      reg_defaults[KS_VERTIC]&0xf0);
-
-                       ks0127_and_or(c, KS_CHROMB, 0x0f,
-                                      reg_defaults[KS_CHROMB]&0xf0);
-
-                       ks0127_write(c, KS_UGAIN, reg_defaults[KS_UGAIN]);
-                       ks0127_write(c, KS_VGAIN, reg_defaults[KS_VGAIN]);
-                       ks0127_write(c, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
-                       ks0127_write(c, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
-                       break;
-
-               case KS_INPUT_YUV656:
-                       v4l_dbg(1, debug, c,
-                               "DECODER_SET_INPUT 15: YUV656\n");
-                       if (ks->norm == VIDEO_MODE_NTSC ||
-                           ks->norm == KS_STD_PAL_M)
-                               /* force 60 Hz */
-                               ks0127_and_or(c, KS_CMDA,   0xfc, 0x03);
-                       else
-                               /* force 50 Hz */
-                               ks0127_and_or(c, KS_CMDA,   0xfc, 0x02);
-
-                       ks0127_and_or(c, KS_CMDA,   0xff, 0x40); /* VSE=1 */
-                       /* set input line and VALIGN */
-                       ks0127_and_or(c, KS_CMDB,   0xb0, (*iarg | 0x40));
-                       /* freerunning mode, */
-                       /* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0  VMEM=1*/
-                       ks0127_and_or(c, KS_CMDC,   0x70, 0x87);
-                       /* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */
-                       ks0127_and_or(c, KS_CMDD,   0x03, 0x08);
-                       /* disable chroma demodulation */
-                       ks0127_and_or(c, KS_CTRACK, 0xcf, 0x30);
-                       /* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */
-                       ks0127_and_or(c, KS_LUMA,   0x00, 0x71);
-                       ks0127_and_or(c, KS_VERTIC, 0x0f,
-                                      reg_defaults[KS_VERTIC]&0xf0);
-
-                       /* scaler fullbw, luma comb off */
-                       ks0127_and_or(c, KS_VERTIA, 0x08, 0x81);
-
-                       ks0127_and_or(c, KS_CHROMB, 0x0f,
-                                      reg_defaults[KS_CHROMB]&0xf0);
-
-                       ks0127_and_or(c, KS_CON, 0x00, 0x00);
-                       ks0127_and_or(c, KS_BRT, 0x00, 32);     /* spec: 34 */
-                               /* spec: 229 (e5) */
-                       ks0127_and_or(c, KS_SAT, 0x00, 0xe8);
-                       ks0127_and_or(c, KS_HUE, 0x00, 0);
-
-                       ks0127_and_or(c, KS_UGAIN, 0x00, 238);
-                       ks0127_and_or(c, KS_VGAIN, 0x00, 0x00);
-
-                       /*UOFF:0x30, VOFF:0x30, TSTCGN=1 */
-                       ks0127_and_or(c, KS_UVOFFH, 0x00, 0x4f);
-                       ks0127_and_or(c, KS_UVOFFL, 0x00, 0x00);
-                       break;
-
-               default:
-                       v4l_dbg(1, debug, c,
-                               "DECODER_SET_INPUT: Unknown input %d\n", *iarg);
-                       break;
-               }
-
-               /* hack: CDMLPF sometimes spontaneously switches on; */
-               /* force back off */
-               ks0127_write(c, KS_DEMOD, reg_defaults[KS_DEMOD]);
+       case KS_INPUT_YUV656:
+               v4l2_dbg(1, debug, sd, "s_routing 15: YUV656\n");
+               if (ks->norm & V4L2_STD_525_60)
+                       /* force 60 Hz */
+                       ks0127_and_or(sd, KS_CMDA,   0xfc, 0x03);
+               else
+                       /* force 50 Hz */
+                       ks0127_and_or(sd, KS_CMDA,   0xfc, 0x02);
+
+               ks0127_and_or(sd, KS_CMDA,   0xff, 0x40); /* VSE=1 */
+               /* set input line and VALIGN */
+               ks0127_and_or(sd, KS_CMDB,   0xb0, (route->input | 0x40));
+               /* freerunning mode, */
+               /* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0  VMEM=1*/
+               ks0127_and_or(sd, KS_CMDC,   0x70, 0x87);
+               /* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */
+               ks0127_and_or(sd, KS_CMDD,   0x03, 0x08);
+               /* disable chroma demodulation */
+               ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x30);
+               /* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */
+               ks0127_and_or(sd, KS_LUMA,   0x00, 0x71);
+               ks0127_and_or(sd, KS_VERTIC, 0x0f,
+                              reg_defaults[KS_VERTIC]&0xf0);
+
+               /* scaler fullbw, luma comb off */
+               ks0127_and_or(sd, KS_VERTIA, 0x08, 0x81);
+
+               ks0127_and_or(sd, KS_CHROMB, 0x0f,
+                              reg_defaults[KS_CHROMB]&0xf0);
+
+               ks0127_and_or(sd, KS_CON, 0x00, 0x00);
+               ks0127_and_or(sd, KS_BRT, 0x00, 32);    /* spec: 34 */
+                       /* spec: 229 (e5) */
+               ks0127_and_or(sd, KS_SAT, 0x00, 0xe8);
+               ks0127_and_or(sd, KS_HUE, 0x00, 0);
+
+               ks0127_and_or(sd, KS_UGAIN, 0x00, 238);
+               ks0127_and_or(sd, KS_VGAIN, 0x00, 0x00);
+
+               /*UOFF:0x30, VOFF:0x30, TSTCGN=1 */
+               ks0127_and_or(sd, KS_UVOFFH, 0x00, 0x4f);
+               ks0127_and_or(sd, KS_UVOFFL, 0x00, 0x00);
                break;
 
-       case DECODER_SET_OUTPUT:
-               switch(*iarg) {
-               case KS_OUTPUT_YUV656E:
-                       v4l_dbg(1, debug, c,
-                               "DECODER_SET_OUTPUT: OUTPUT_YUV656E (Missing)\n");
-                       return -EINVAL;
-
-               case KS_OUTPUT_EXV:
-                       v4l_dbg(1, debug, c,
-                               "DECODER_SET_OUTPUT: OUTPUT_EXV\n");
-                       ks0127_and_or(c, KS_OFMTA, 0xf0, 0x09);
-                       break;
-               }
+       default:
+               v4l2_dbg(1, debug, sd,
+                       "s_routing: Unknown input %d\n", route->input);
                break;
+       }
 
-       case DECODER_SET_NORM: /* sam This block mixes old and new norm names... */
-               /* Set to automatic SECAM/Fsc mode */
-               ks0127_and_or(c, KS_DEMOD, 0xf0, 0x00);
-
-               ks->norm = *iarg;
-               switch (*iarg) {
-               /* this is untested !! */
-               /* It just detects PAL_N/NTSC_M (no special frequencies) */
-               /* And you have to set the standard a second time afterwards */
-               case VIDEO_MODE_AUTO:
-                       v4l_dbg(1, debug, c,
-                               "DECODER_SET_NORM: AUTO\n");
-
-                       /* The chip determines the format */
-                       /* based on the current field rate */
-                       ks0127_and_or(c, KS_CMDA,   0xfc, 0x00);
-                       ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20);
-                       /* This is wrong for PAL ! As I said, */
-                       /* you need to set the standard once again !! */
-                       ks->format_height = 240;
-                       ks->format_width = 704;
-                       break;
-
-               case VIDEO_MODE_NTSC:
-                       v4l_dbg(1, debug, c,
-                               "DECODER_SET_NORM: NTSC_M\n");
-                       ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20);
-                       ks->format_height = 240;
-                       ks->format_width = 704;
-                       break;
-
-               case KS_STD_NTSC_N:
-                       v4l_dbg(1, debug, c,
-                               "KS0127_SET_NORM: NTSC_N (fixme)\n");
-                       ks0127_and_or(c, KS_CHROMA, 0x9f, 0x40);
-                       ks->format_height = 240;
-                       ks->format_width = 704;
-                       break;
-
-               case VIDEO_MODE_PAL:
-                       v4l_dbg(1, debug, c,
-                               "DECODER_SET_NORM: PAL_N\n");
-                       ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20);
-                       ks->format_height = 290;
-                       ks->format_width = 704;
-                       break;
-
-               case KS_STD_PAL_M:
-                       v4l_dbg(1, debug, c,
-                               "KS0127_SET_NORM: PAL_M (fixme)\n");
-                       ks0127_and_or(c, KS_CHROMA, 0x9f, 0x40);
-                       ks->format_height = 290;
-                       ks->format_width = 704;
-                       break;
-
-               case VIDEO_MODE_SECAM:
-                       v4l_dbg(1, debug, c,
-                               "KS0127_SET_NORM: SECAM\n");
-                       ks->format_height = 290;
-                       ks->format_width = 704;
-
-                       /* set to secam autodetection */
-                       ks0127_and_or(c, KS_CHROMA, 0xdf, 0x20);
-                       ks0127_and_or(c, KS_DEMOD, 0xf0, 0x00);
-                       schedule_timeout_interruptible(HZ/10+1);
-
-                       /* did it autodetect? */
-                       if (ks0127_read(c, KS_DEMOD) & 0x40)
-                               break;
+       /* hack: CDMLPF sometimes spontaneously switches on; */
+       /* force back off */
+       ks0127_write(sd, KS_DEMOD, reg_defaults[KS_DEMOD]);
+       return 0;
+}
 
+static int ks0127_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct ks0127 *ks = to_ks0127(sd);
+
+       /* Set to automatic SECAM/Fsc mode */
+       ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x00);
+
+       ks->norm = std;
+       if (std & V4L2_STD_NTSC) {
+               v4l2_dbg(1, debug, sd,
+                       "s_std: NTSC_M\n");
+               ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x20);
+       } else if (std & V4L2_STD_PAL_N) {
+               v4l2_dbg(1, debug, sd,
+                       "s_std: NTSC_N (fixme)\n");
+               ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x40);
+       } else if (std & V4L2_STD_PAL) {
+               v4l2_dbg(1, debug, sd,
+                       "s_std: PAL_N\n");
+               ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x20);
+       } else if (std & V4L2_STD_PAL_M) {
+               v4l2_dbg(1, debug, sd,
+                       "s_std: PAL_M (fixme)\n");
+               ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x40);
+       } else if (std & V4L2_STD_SECAM) {
+               v4l2_dbg(1, debug, sd,
+                       "s_std: SECAM\n");
+
+               /* set to secam autodetection */
+               ks0127_and_or(sd, KS_CHROMA, 0xdf, 0x20);
+               ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x00);
+               schedule_timeout_interruptible(HZ/10+1);
+
+               /* did it autodetect? */
+               if (!(ks0127_read(sd, KS_DEMOD) & 0x40))
                        /* force to secam mode */
-                       ks0127_and_or(c, KS_DEMOD, 0xf0, 0x0f);
-                       break;
-
-               default:
-                       v4l_dbg(1, debug, c,
-                               "DECODER_SET_NORM: Unknown norm %d\n", *iarg);
-                       break;
-               }
-               break;
-
-       case DECODER_SET_PICTURE:
-               v4l_dbg(1, debug, c,
-                       "DECODER_SET_PICTURE: not yet supported\n");
-               return -EINVAL;
-
-       /* sam todo: KS0127_SET_BRIGHTNESS: Merge into DECODER_SET_PICTURE */
-       /* sam todo: KS0127_SET_CONTRAST: Merge into DECODER_SET_PICTURE */
-       /* sam todo: KS0127_SET_HUE: Merge into DECODER_SET_PICTURE? */
-       /* sam todo: KS0127_SET_SATURATION: Merge into DECODER_SET_PICTURE */
-       /* sam todo: KS0127_SET_AGC_MODE: */
-       /* sam todo: KS0127_SET_AGC: */
-       /* sam todo: KS0127_SET_CHROMA_MODE: */
-       /* sam todo: KS0127_SET_PIXCLK_MODE: */
-       /* sam todo: KS0127_SET_GAMMA_MODE: */
-       /* sam todo: KS0127_SET_UGAIN: */
-       /* sam todo: KS0127_SET_VGAIN: */
-       /* sam todo: KS0127_SET_INVALY: */
-       /* sam todo: KS0127_SET_INVALU: */
-       /* sam todo: KS0127_SET_INVALV: */
-       /* sam todo: KS0127_SET_UNUSEY: */
-       /* sam todo: KS0127_SET_UNUSEU: */
-       /* sam todo: KS0127_SET_UNUSEV: */
-       /* sam todo: KS0127_SET_VSALIGN_MODE: */
-
-       case DECODER_ENABLE_OUTPUT:
-       {
-               int enable;
-
-               iarg = arg;
-               enable = (*iarg != 0);
-               if (enable) {
-                       v4l_dbg(1, debug, c,
-                               "DECODER_ENABLE_OUTPUT on\n");
-                       /* All output pins on */
-                       ks0127_and_or(c, KS_OFMTA, 0xcf, 0x30);
-                       /* Obey the OEN pin */
-                       ks0127_and_or(c, KS_CDEM, 0x7f, 0x00);
-               } else {
-                       v4l_dbg(1, debug, c,
-                               "DECODER_ENABLE_OUTPUT off\n");
-                       /* Video output pins off */
-                       ks0127_and_or(c, KS_OFMTA, 0xcf, 0x00);
-                       /* Ignore the OEN pin */
-                       ks0127_and_or(c, KS_CDEM, 0x7f, 0x80);
-               }
-               break;
+                       ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x0f);
+       } else {
+               v4l2_dbg(1, debug, sd, "s_std: Unknown norm %llx\n",
+                              (unsigned long long)std);
        }
+       return 0;
+}
 
-       /* sam todo: KS0127_SET_OUTPUT_MODE: */
-       /* sam todo: KS0127_SET_WIDTH: */
-       /* sam todo: KS0127_SET_HEIGHT: */
-       /* sam todo: KS0127_SET_HSCALE: */
-
-       case DECODER_GET_STATUS:
-               v4l_dbg(1, debug, c, "DECODER_GET_STATUS\n");
-               *iarg = 0;
-               status = ks0127_read(c, KS_STAT);
-               if (!(status & 0x20))            /* NOVID not set */
-                       *iarg = (*iarg | DECODER_STATUS_GOOD);
-               if ((status & 0x01))                  /* CLOCK set */
-                       *iarg = (*iarg | DECODER_STATUS_COLOR);
-               if ((status & 0x08))               /* PALDET set */
-                       *iarg = (*iarg | DECODER_STATUS_PAL);
-               else
-                       *iarg = (*iarg | DECODER_STATUS_NTSC);
-               break;
-
-       /* Catch any unknown command */
-       default:
-               v4l_dbg(1, debug, c, "unknown: 0x%08x\n", cmd);
-               return -EINVAL;
+static int ks0127_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       v4l2_dbg(1, debug, sd, "s_stream(%d)\n", enable);
+       if (enable) {
+               /* All output pins on */
+               ks0127_and_or(sd, KS_OFMTA, 0xcf, 0x30);
+               /* Obey the OEN pin */
+               ks0127_and_or(sd, KS_CDEM, 0x7f, 0x00);
+       } else {
+               /* Video output pins off */
+               ks0127_and_or(sd, KS_OFMTA, 0xcf, 0x00);
+               /* Ignore the OEN pin */
+               ks0127_and_or(sd, KS_CDEM, 0x7f, 0x80);
        }
        return 0;
 }
 
+static int ks0127_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
+{
+       int stat = V4L2_IN_ST_NO_SIGNAL;
+       u8 status;
+       v4l2_std_id std = V4L2_STD_ALL;
+
+       status = ks0127_read(sd, KS_STAT);
+       if (!(status & 0x20))            /* NOVID not set */
+               stat = 0;
+       if (!(status & 0x01))                 /* CLOCK set */
+               stat |= V4L2_IN_ST_NO_COLOR;
+       if ((status & 0x08))               /* PALDET set */
+               std = V4L2_STD_PAL;
+       else
+               std = V4L2_STD_NTSC;
+       if (pstd)
+               *pstd = std;
+       if (pstatus)
+               *pstatus = stat;
+       return 0;
+}
+
+static int ks0127_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+       v4l2_dbg(1, debug, sd, "querystd\n");
+       return ks0127_status(sd, NULL, std);
+}
 
-/* Addresses to scan */
-#define I2C_KS0127_ADDON   0xD8
-#define I2C_KS0127_ONBOARD 0xDA
+static int ks0127_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+       v4l2_dbg(1, debug, sd, "g_input_status\n");
+       return ks0127_status(sd, status, NULL);
+}
+
+static int ks0127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ks0127 *ks = to_ks0127(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, ks->ident, 0);
+}
+
+/* ----------------------------------------------------------------------- */
 
-static unsigned short normal_i2c[] = {
-       I2C_KS0127_ADDON >> 1,
-       I2C_KS0127_ONBOARD >> 1,
-       I2C_CLIENT_END
+static const struct v4l2_subdev_core_ops ks0127_core_ops = {
+       .g_chip_ident = ks0127_g_chip_ident,
 };
 
-I2C_CLIENT_INSMOD;
+static const struct v4l2_subdev_tuner_ops ks0127_tuner_ops = {
+       .s_std = ks0127_s_std,
+};
+
+static const struct v4l2_subdev_video_ops ks0127_video_ops = {
+       .s_routing = ks0127_s_routing,
+       .s_stream = ks0127_s_stream,
+       .querystd = ks0127_querystd,
+       .g_input_status = ks0127_g_input_status,
+};
+
+static const struct v4l2_subdev_ops ks0127_ops = {
+       .core = &ks0127_core_ops,
+       .tuner = &ks0127_tuner_ops,
+       .video = &ks0127_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
 
-static int ks0127_probe(struct i2c_client *c, const struct i2c_device_id *id)
+static int ks0127_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
        struct ks0127 *ks;
+       struct v4l2_subdev *sd;
 
-       v4l_info(c, "%s chip found @ 0x%x (%s)\n",
-               c->addr == (I2C_KS0127_ADDON >> 1) ? "addon" : "on-board",
-               c->addr << 1, c->adapter->name);
+       v4l_info(client, "%s chip found @ 0x%x (%s)\n",
+               client->addr == (I2C_KS0127_ADDON >> 1) ? "addon" : "on-board",
+               client->addr << 1, client->adapter->name);
 
        ks = kzalloc(sizeof(*ks), GFP_KERNEL);
        if (ks == NULL)
                return -ENOMEM;
-
-       i2c_set_clientdata(c, ks);
-
-       ks->ks_type = KS_TYPE_UNKNOWN;
+       sd = &ks->sd;
+       v4l2_i2c_subdev_init(sd, client, &ks0127_ops);
 
        /* power up */
        init_reg_defaults();
-       ks0127_write(c, KS_CMDA, 0x2c);
+       ks0127_write(sd, KS_CMDA, 0x2c);
        mdelay(10);
 
        /* reset the device */
-       ks0127_reset(c);
+       ks0127_init(sd);
        return 0;
 }
 
-static int ks0127_remove(struct i2c_client *c)
+static int ks0127_remove(struct i2c_client *client)
 {
-       struct ks0127 *ks = i2c_get_clientdata(c);
-
-       ks0127_write(c, KS_OFMTA, 0x20); /* tristate */
-       ks0127_write(c, KS_CMDA, 0x2c | 0x80); /* power down */
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
-       kfree(ks);
+       v4l2_device_unregister_subdev(sd);
+       ks0127_write(sd, KS_OFMTA, 0x20); /* tristate */
+       ks0127_write(sd, KS_CMDA, 0x2c | 0x80); /* power down */
+       kfree(to_ks0127(sd));
        return 0;
 }
 
-static int ks0127_legacy_probe(struct i2c_adapter *adapter)
-{
-       return adapter->id == I2C_HW_B_ZR36067;
-}
-
 static const struct i2c_device_id ks0127_id[] = {
        { "ks0127", 0 },
+       { "ks0127b", 0 },
+       { "ks0122s", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ks0127_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "ks0127",
-       .driverid = I2C_DRIVERID_KS0127,
-       .command = ks0127_command,
        .probe = ks0127_probe,
        .remove = ks0127_remove,
-       .legacy_probe = ks0127_legacy_probe,
        .id_table = ks0127_id,
 };
index 1ec578833aeacc4044e9e90ab873eb8ecf12cbcc..cb8abd5403b341f12a1243a6e39286a75a2a5d55 100644 (file)
@@ -24,8 +24,6 @@
 #ifndef KS0127_H
 #define KS0127_H
 
-#include <linux/videodev.h>
-
 /* input channels */
 #define KS_INPUT_COMPOSITE_1    0
 #define KS_INPUT_COMPOSITE_2    1
index de397ef57b44d7aefa843a2e5f6fbd761e24a6ac..1f340fefc49db00dba48961ffb8edaad711bef1c 100644 (file)
@@ -132,11 +132,6 @@ static int m52790_log_status(struct v4l2_subdev *sd)
        return 0;
 }
 
-static int m52790_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops m52790_core_ops = {
@@ -210,8 +205,6 @@ MODULE_DEVICE_TABLE(i2c, m52790_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "m52790",
-       .driverid = I2C_DRIVERID_M52790,
-       .command = m52790_command,
        .probe = m52790_probe,
        .remove = m52790_remove,
        .id_table = m52790_id,
index b76e33d5c867bad4430035ac952765497fc128ee..2ad11f0999c69a843d289d8af4ced5a88f2a2e04 100644 (file)
@@ -1017,7 +1017,6 @@ static int meyeioc_stilljcapt(int *len)
 static int vidioc_querycap(struct file *file, void *fh,
                                struct v4l2_capability *cap)
 {
-       memset(cap, 0, sizeof(*cap));
        strcpy(cap->driver, "meye");
        strcpy(cap->card, "meye");
        sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
@@ -1036,8 +1035,6 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
        if (i->index != 0)
                return -EINVAL;
 
-       memset(i, 0, sizeof(*i));
-       i->index = 0;
        strcpy(i->name, "Camera");
        i->type = V4L2_INPUT_TYPE_CAMERA;
 
@@ -1259,22 +1256,13 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
        if (f->index > 1)
                return -EINVAL;
 
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
        if (f->index == 0) {
                /* standard YUV 422 capture */
-               memset(f, 0, sizeof(*f));
-               f->index = 0;
-               f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                f->flags = 0;
                strcpy(f->description, "YUV422");
                f->pixelformat = V4L2_PIX_FMT_YUYV;
        } else {
                /* compressed MJPEG capture */
-               memset(f, 0, sizeof(*f));
-               f->index = 1;
-               f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                f->flags = V4L2_FMT_FLAG_COMPRESSED;
                strcpy(f->description, "MJPEG");
                f->pixelformat = V4L2_PIX_FMT_MJPEG;
@@ -1286,9 +1274,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
 static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
                                struct v4l2_format *f)
 {
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
        if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
            f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
                return -EINVAL;
@@ -1319,12 +1304,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
 static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
                                    struct v4l2_format *f)
 {
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
-       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
        switch (meye.mchip_mode) {
        case MCHIP_HIC_MODE_CONT_OUT:
        default:
@@ -1341,8 +1320,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
        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;
 
        return 0;
 }
@@ -1350,9 +1327,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
 static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
                                    struct v4l2_format *f)
 {
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
        if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
            f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
                return -EINVAL;
@@ -1398,9 +1372,6 @@ static int vidioc_reqbufs(struct file *file, void *fh,
 {
        int i;
 
-       if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
        if (req->memory != V4L2_MEMORY_MMAP)
                return -EINVAL;
 
@@ -1441,15 +1412,11 @@ static int vidioc_reqbufs(struct file *file, void *fh,
 
 static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
-       int index = buf->index;
+       unsigned int index = buf->index;
 
-       if (index < 0 || index >= gbuffers)
+       if (index >= gbuffers)
                return -EINVAL;
 
-       memset(buf, 0, sizeof(*buf));
-
-       buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       buf->index = index;
        buf->bytesused = meye.grab_buffer[index].size;
        buf->flags = V4L2_BUF_FLAG_MAPPED;
 
@@ -1471,13 +1438,10 @@ static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 
 static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
-       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
        if (buf->memory != V4L2_MEMORY_MMAP)
                return -EINVAL;
 
-       if (buf->index < 0 || buf->index >= gbuffers)
+       if (buf->index >= gbuffers)
                return -EINVAL;
 
        if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED)
@@ -1497,9 +1461,6 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
        int reqnr;
 
-       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
        if (buf->memory != V4L2_MEMORY_MMAP)
                return -EINVAL;
 
index 4d7a91852117920b6dfe38b5d9ed7f1f9278f5c6..9e8e06cfe5c6d4d0f43acb23f0caa748fba551a5 100644 (file)
@@ -366,29 +366,6 @@ int msp_sleep(struct msp_state *state, int timeout)
 }
 
 /* ------------------------------------------------------------------------ */
-#ifdef CONFIG_VIDEO_ALLOW_V4L1
-static int msp_mode_v4l2_to_v4l1(int rxsubchans, int audmode)
-{
-       if (rxsubchans == V4L2_TUNER_SUB_MONO)
-               return VIDEO_SOUND_MONO;
-       if (rxsubchans == V4L2_TUNER_SUB_STEREO)
-               return VIDEO_SOUND_STEREO;
-       if (audmode == V4L2_TUNER_MODE_LANG2)
-               return VIDEO_SOUND_LANG2;
-       return VIDEO_SOUND_LANG1;
-}
-
-static int msp_mode_v4l1_to_v4l2(int mode)
-{
-       if (mode & VIDEO_SOUND_STEREO)
-               return V4L2_TUNER_MODE_STEREO;
-       if (mode & VIDEO_SOUND_LANG2)
-               return V4L2_TUNER_MODE_LANG2;
-       if (mode & VIDEO_SOUND_LANG1)
-               return V4L2_TUNER_MODE_LANG1;
-       return V4L2_TUNER_MODE_MONO;
-}
-#endif
 
 static int msp_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
@@ -482,96 +459,6 @@ static int msp_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
        return 0;
 }
 
-#ifdef CONFIG_VIDEO_ALLOW_V4L1
-static long msp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
-       struct msp_state *state = to_state(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       switch (cmd) {
-       /* --- v4l ioctls --- */
-       /* take care: bttv does userspace copying, we'll get a
-          kernel pointer here... */
-       case VIDIOCGAUDIO:
-       {
-               struct video_audio *va = arg;
-
-               va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_MUTABLE;
-               if (state->has_sound_processing)
-                       va->flags |= VIDEO_AUDIO_BALANCE |
-                               VIDEO_AUDIO_BASS |
-                               VIDEO_AUDIO_TREBLE;
-               if (state->muted)
-                       va->flags |= VIDEO_AUDIO_MUTE;
-               va->volume = state->volume;
-               va->balance = state->volume ? state->balance : 32768;
-               va->bass = state->bass;
-               va->treble = state->treble;
-
-               if (state->radio)
-                       break;
-               if (state->opmode == OPMODE_AUTOSELECT)
-                       msp_detect_stereo(client);
-               va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans, state->audmode);
-               break;
-       }
-
-       case VIDIOCSAUDIO:
-       {
-               struct video_audio *va = arg;
-
-               state->muted = (va->flags & VIDEO_AUDIO_MUTE);
-               state->volume = va->volume;
-               state->balance = va->balance;
-               state->bass = va->bass;
-               state->treble = va->treble;
-               msp_set_audio(client);
-
-               if (va->mode != 0 && state->radio == 0 &&
-                   state->audmode != msp_mode_v4l1_to_v4l2(va->mode)) {
-                       state->audmode = msp_mode_v4l1_to_v4l2(va->mode);
-                       msp_set_audmode(client);
-               }
-               break;
-       }
-
-       case VIDIOCSCHAN:
-       {
-               struct video_channel *vc = arg;
-               int update = 0;
-               v4l2_std_id std;
-
-               if (state->radio)
-                       update = 1;
-               state->radio = 0;
-               if (vc->norm == VIDEO_MODE_PAL)
-                       std = V4L2_STD_PAL;
-               else if (vc->norm == VIDEO_MODE_SECAM)
-                       std = V4L2_STD_SECAM;
-               else
-                       std = V4L2_STD_NTSC;
-               if (std != state->v4l2_std) {
-                       state->v4l2_std = std;
-                       update = 1;
-               }
-               if (update)
-                       msp_wake_thread(client);
-               break;
-       }
-
-       case VIDIOCSFREQ:
-       {
-               /* new channel -- kick audio carrier scan */
-               msp_wake_thread(client);
-               break;
-       }
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-#endif
-
 /* --- v4l2 ioctls --- */
 static int msp_s_radio(struct v4l2_subdev *sd)
 {
@@ -713,22 +600,24 @@ static int msp_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
        struct msp_state *state = to_state(sd);
 
        switch (qc->id) {
-               case V4L2_CID_AUDIO_VOLUME:
-               case V4L2_CID_AUDIO_MUTE:
-                       return v4l2_ctrl_query_fill_std(qc);
-               default:
-                       break;
+       case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+       default:
+               break;
        }
        if (!state->has_sound_processing)
                return -EINVAL;
        switch (qc->id) {
-               case V4L2_CID_AUDIO_LOUDNESS:
-               case V4L2_CID_AUDIO_BALANCE:
-               case V4L2_CID_AUDIO_BASS:
-               case V4L2_CID_AUDIO_TREBLE:
-                       return v4l2_ctrl_query_fill_std(qc);
-               default:
-                       return -EINVAL;
+       case V4L2_CID_AUDIO_LOUDNESS:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+       case V4L2_CID_AUDIO_BALANCE:
+       case V4L2_CID_AUDIO_BASS:
+       case V4L2_CID_AUDIO_TREBLE:
+               return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
+       default:
+               return -EINVAL;
        }
        return 0;
 }
@@ -820,9 +709,6 @@ static const struct v4l2_subdev_core_ops msp_core_ops = {
        .g_ctrl = msp_g_ctrl,
        .s_ctrl = msp_s_ctrl,
        .queryctrl = msp_queryctrl,
-#ifdef CONFIG_VIDEO_ALLOW_V4L1
-       .ioctl = msp_ioctl,
-#endif
 };
 
 static const struct v4l2_subdev_tuner_ops msp_tuner_ops = {
index c1bf75ef2741389576f167c65ccbda8254fa4c40..fa7e5093edeb653e5b3ea6b0151d43019ae47f6a 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/log2.h>
-#include <linux/gpio.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
@@ -73,9 +72,7 @@ struct mt9m001 {
        struct i2c_client *client;
        struct soc_camera_device icd;
        int model;      /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
-       int switch_gpio;
        unsigned char autoexposure;
-       unsigned char datawidth;
 };
 
 static int reg_read(struct soc_camera_device *icd, const u8 reg)
@@ -181,92 +178,28 @@ static int mt9m001_stop_capture(struct soc_camera_device *icd)
        return 0;
 }
 
-static int bus_switch_request(struct mt9m001 *mt9m001,
-                             struct soc_camera_link *icl)
-{
-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
-       int ret;
-       unsigned int gpio = icl->gpio;
-
-       if (gpio_is_valid(gpio)) {
-               /* We have a data bus switch. */
-               ret = gpio_request(gpio, "mt9m001");
-               if (ret < 0) {
-                       dev_err(&mt9m001->client->dev, "Cannot get GPIO %u\n",
-                               gpio);
-                       return ret;
-               }
-
-               ret = gpio_direction_output(gpio, 0);
-               if (ret < 0) {
-                       dev_err(&mt9m001->client->dev,
-                               "Cannot set GPIO %u to output\n", gpio);
-                       gpio_free(gpio);
-                       return ret;
-               }
-       }
-
-       mt9m001->switch_gpio = gpio;
-#else
-       mt9m001->switch_gpio = -EINVAL;
-#endif
-       return 0;
-}
-
-static void bus_switch_release(struct mt9m001 *mt9m001)
-{
-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
-       if (gpio_is_valid(mt9m001->switch_gpio))
-               gpio_free(mt9m001->switch_gpio);
-#endif
-}
-
-static int bus_switch_act(struct mt9m001 *mt9m001, int go8bit)
-{
-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
-       if (!gpio_is_valid(mt9m001->switch_gpio))
-               return -ENODEV;
-
-       gpio_set_value_cansleep(mt9m001->switch_gpio, go8bit);
-       return 0;
-#else
-       return -ENODEV;
-#endif
-}
-
-static int bus_switch_possible(struct mt9m001 *mt9m001)
-{
-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
-       return gpio_is_valid(mt9m001->switch_gpio);
-#else
-       return 0;
-#endif
-}
-
 static int mt9m001_set_bus_param(struct soc_camera_device *icd,
                                 unsigned long flags)
 {
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-       unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
-       int ret;
+       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+       unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK;
 
-       /* Flags validity verified in test_bus_param */
+       /* Only one width bit may be set */
+       if (!is_power_of_2(width_flag))
+               return -EINVAL;
 
-       if ((mt9m001->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
-           (mt9m001->datawidth != 9  && (width_flag == SOCAM_DATAWIDTH_9)) ||
-           (mt9m001->datawidth != 8  && (width_flag == SOCAM_DATAWIDTH_8))) {
-               /* Well, we actually only can do 10 or 8 bits... */
-               if (width_flag == SOCAM_DATAWIDTH_9)
-                       return -EINVAL;
-               ret = bus_switch_act(mt9m001,
-                                    width_flag == SOCAM_DATAWIDTH_8);
-               if (ret < 0)
-                       return ret;
+       if (icl->set_bus_param)
+               return icl->set_bus_param(icl, width_flag);
 
-               mt9m001->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
-       }
+       /*
+        * Without board specific bus width settings we only support the
+        * sensors native bus width
+        */
+       if (width_flag == SOCAM_DATAWIDTH_10)
+               return 0;
 
-       return 0;
+       return -EINVAL;
 }
 
 static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
@@ -274,18 +207,20 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
        struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
        /* MT9M001 has all capture_format parameters fixed */
-       unsigned long flags = SOCAM_DATAWIDTH_10 | SOCAM_PCLK_SAMPLE_RISING |
+       unsigned long flags = SOCAM_PCLK_SAMPLE_RISING |
                SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
-               SOCAM_MASTER;
+               SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER;
 
-       if (bus_switch_possible(mt9m001))
-               flags |= SOCAM_DATAWIDTH_8;
+       if (icl->query_bus_param)
+               flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK;
+       else
+               flags |= SOCAM_DATAWIDTH_10;
 
        return soc_camera_apply_sensor_flags(icl, flags);
 }
 
-static int mt9m001_set_fmt(struct soc_camera_device *icd,
-                          __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9m001_set_crop(struct soc_camera_device *icd,
+                           struct v4l2_rect *rect)
 {
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
        int ret;
@@ -324,6 +259,20 @@ static int mt9m001_set_fmt(struct soc_camera_device *icd,
        return ret;
 }
 
+static int mt9m001_set_fmt(struct soc_camera_device *icd,
+                          struct v4l2_format *f)
+{
+       struct v4l2_rect rect = {
+               .left   = icd->x_current,
+               .top    = icd->y_current,
+               .width  = f->fmt.pix.width,
+               .height = f->fmt.pix.height,
+       };
+
+       /* No support for scaling so far, just crop. TODO: use skipping */
+       return mt9m001_set_crop(icd, &rect);
+}
+
 static int mt9m001_try_fmt(struct soc_camera_device *icd,
                           struct v4l2_format *f)
 {
@@ -449,6 +398,7 @@ static struct soc_camera_ops mt9m001_ops = {
        .release                = mt9m001_release,
        .start_capture          = mt9m001_start_capture,
        .stop_capture           = mt9m001_stop_capture,
+       .set_crop               = mt9m001_set_crop,
        .set_fmt                = mt9m001_set_fmt,
        .try_fmt                = mt9m001_try_fmt,
        .set_bus_param          = mt9m001_set_bus_param,
@@ -583,6 +533,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
        struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
        s32 data;
        int ret;
+       unsigned long flags;
 
        /* We must have a parent by now. And it cannot be a wrong one.
         * So this entire test is completely redundant. */
@@ -603,18 +554,10 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
        case 0x8421:
                mt9m001->model = V4L2_IDENT_MT9M001C12ST;
                icd->formats = mt9m001_colour_formats;
-               if (gpio_is_valid(icl->gpio))
-                       icd->num_formats = ARRAY_SIZE(mt9m001_colour_formats);
-               else
-                       icd->num_formats = 1;
                break;
        case 0x8431:
                mt9m001->model = V4L2_IDENT_MT9M001C12STM;
                icd->formats = mt9m001_monochrome_formats;
-               if (gpio_is_valid(icl->gpio))
-                       icd->num_formats = ARRAY_SIZE(mt9m001_monochrome_formats);
-               else
-                       icd->num_formats = 1;
                break;
        default:
                ret = -ENODEV;
@@ -623,6 +566,26 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
                goto ei2c;
        }
 
+       icd->num_formats = 0;
+
+       /*
+        * This is a 10bit sensor, so by default we only allow 10bit.
+        * The platform may support different bus widths due to
+        * different routing of the data lines.
+        */
+       if (icl->query_bus_param)
+               flags = icl->query_bus_param(icl);
+       else
+               flags = SOCAM_DATAWIDTH_10;
+
+       if (flags & SOCAM_DATAWIDTH_10)
+               icd->num_formats++;
+       else
+               icd->formats++;
+
+       if (flags & SOCAM_DATAWIDTH_8)
+               icd->num_formats++;
+
        dev_info(&icd->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
                 data == 0x8431 ? "C12STM" : "C12ST");
 
@@ -688,18 +651,10 @@ static int mt9m001_probe(struct i2c_client *client,
        icd->height_max = 1024;
        icd->y_skip_top = 1;
        icd->iface      = icl->bus_id;
-       /* Default datawidth - this is the only width this camera (normally)
-        * supports. It is only with extra logic that it can support
-        * other widths. Therefore it seems to be a sensible default. */
-       mt9m001->datawidth = 10;
        /* Simulated autoexposure. If enabled, we calculate shutter width
         * ourselves in the driver based on vertical blanking and frame width */
        mt9m001->autoexposure = 1;
 
-       ret = bus_switch_request(mt9m001, icl);
-       if (ret)
-               goto eswinit;
-
        ret = soc_camera_device_register(icd);
        if (ret)
                goto eisdr;
@@ -707,8 +662,6 @@ static int mt9m001_probe(struct i2c_client *client,
        return 0;
 
 eisdr:
-       bus_switch_release(mt9m001);
-eswinit:
        kfree(mt9m001);
        return ret;
 }
@@ -718,7 +671,6 @@ static int mt9m001_remove(struct i2c_client *client)
        struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
 
        soc_camera_device_unregister(&mt9m001->icd);
-       bus_switch_release(mt9m001);
        kfree(mt9m001);
 
        return 0;
index 5b8e20979cceeb94288a328b8cde1c3ee6a27a4c..cdd1ddb513881a3ec982454bc052c8a267346dc3 100644 (file)
@@ -152,7 +152,7 @@ struct mt9m111 {
        struct soc_camera_device icd;
        int model;      /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */
        enum mt9m111_context context;
-       unsigned int left, top, width, height;
+       struct v4l2_rect rect;
        u32 pixfmt;
        unsigned char autoexposure;
        unsigned char datawidth;
@@ -249,12 +249,13 @@ static int mt9m111_set_context(struct soc_camera_device *icd,
                return reg_write(CONTEXT_CONTROL, valA);
 }
 
-static int mt9m111_setup_rect(struct soc_camera_device *icd)
+static int mt9m111_setup_rect(struct soc_camera_device *icd,
+                             struct v4l2_rect *rect)
 {
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
        int ret, is_raw_format;
-       int width = mt9m111->width;
-       int height = mt9m111->height;
+       int width = rect->width;
+       int height = rect->height;
 
        if ((mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8)
            || (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16))
@@ -262,9 +263,9 @@ static int mt9m111_setup_rect(struct soc_camera_device *icd)
        else
                is_raw_format = 0;
 
-       ret = reg_write(COLUMN_START, mt9m111->left);
+       ret = reg_write(COLUMN_START, rect->left);
        if (!ret)
-               ret = reg_write(ROW_START, mt9m111->top);
+               ret = reg_write(ROW_START, rect->top);
 
        if (is_raw_format) {
                if (!ret)
@@ -393,6 +394,8 @@ static int mt9m111_disable(struct soc_camera_device *icd)
 
 static int mt9m111_reset(struct soc_camera_device *icd)
 {
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
        int ret;
 
        ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
@@ -401,6 +404,10 @@ static int mt9m111_reset(struct soc_camera_device *icd)
        if (!ret)
                ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE
                                | MT9M111_RESET_RESET_SOC);
+
+       if (icl->reset)
+               icl->reset(&mt9m111->client->dev);
+
        return ret;
 }
 
@@ -420,7 +427,7 @@ static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd)
        struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
        unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
                SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
-               SOCAM_DATAWIDTH_8;
+               SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
 
        return soc_camera_apply_sensor_flags(icl, flags);
 }
@@ -430,6 +437,22 @@ static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
        return 0;
 }
 
+static int mt9m111_set_crop(struct soc_camera_device *icd,
+                           struct v4l2_rect *rect)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       int ret;
+
+       dev_dbg(&icd->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
+               __func__, rect->left, rect->top, rect->width,
+               rect->height);
+
+       ret = mt9m111_setup_rect(icd, rect);
+       if (!ret)
+               mt9m111->rect = *rect;
+       return ret;
+}
+
 static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
 {
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
@@ -480,23 +503,27 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
 }
 
 static int mt9m111_set_fmt(struct soc_camera_device *icd,
-                          __u32 pixfmt, struct v4l2_rect *rect)
+                          struct v4l2_format *f)
 {
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct v4l2_rect rect = {
+               .left   = mt9m111->rect.left,
+               .top    = mt9m111->rect.top,
+               .width  = pix->width,
+               .height = pix->height,
+       };
        int ret;
 
-       mt9m111->left = rect->left;
-       mt9m111->top = rect->top;
-       mt9m111->width = rect->width;
-       mt9m111->height = rect->height;
-
        dev_dbg(&icd->dev, "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n",
-               __func__, pixfmt, mt9m111->left, mt9m111->top, mt9m111->width,
-               mt9m111->height);
+               __func__, pix->pixelformat, rect.left, rect.top, rect.width,
+               rect.height);
 
-       ret = mt9m111_setup_rect(icd);
+       ret = mt9m111_setup_rect(icd, &rect);
+       if (!ret)
+               ret = mt9m111_set_pixfmt(icd, pix->pixelformat);
        if (!ret)
-               ret = mt9m111_set_pixfmt(icd, pixfmt);
+               mt9m111->rect = rect;
        return ret;
 }
 
@@ -627,6 +654,7 @@ static struct soc_camera_ops mt9m111_ops = {
        .release                = mt9m111_release,
        .start_capture          = mt9m111_start_capture,
        .stop_capture           = mt9m111_stop_capture,
+       .set_crop               = mt9m111_set_crop,
        .set_fmt                = mt9m111_set_fmt,
        .try_fmt                = mt9m111_try_fmt,
        .query_bus_param        = mt9m111_query_bus_param,
@@ -811,7 +839,7 @@ static int mt9m111_restore_state(struct soc_camera_device *icd)
 
        mt9m111_set_context(icd, mt9m111->context);
        mt9m111_set_pixfmt(icd, mt9m111->pixfmt);
-       mt9m111_setup_rect(icd);
+       mt9m111_setup_rect(icd, &mt9m111->rect);
        mt9m111_set_flip(icd, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
        mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
        mt9m111_set_global_gain(icd, icd->gain);
index 349d8e36553087886354ff8771cf4b1cab12c4c5..23f9ce9d67ef688ee10158fb4543417992d1fa06 100644 (file)
@@ -144,13 +144,11 @@ static int mt9t031_init(struct soc_camera_device *icd)
        int ret;
 
        /* Disable chip output, synchronous option update */
-       dev_dbg(icd->vdev->parent, "%s\n", __func__);
-
        ret = reg_write(icd, MT9T031_RESET, 1);
        if (ret >= 0)
                ret = reg_write(icd, MT9T031_RESET, 0);
        if (ret >= 0)
-               ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3);
+               ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2);
 
        return ret >= 0 ? 0 : -EIO;
 }
@@ -158,14 +156,14 @@ static int mt9t031_init(struct soc_camera_device *icd)
 static int mt9t031_release(struct soc_camera_device *icd)
 {
        /* Disable the chip */
-       reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3);
+       reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2);
        return 0;
 }
 
 static int mt9t031_start_capture(struct soc_camera_device *icd)
 {
        /* Switch to master "normal" mode */
-       if (reg_set(icd, MT9T031_OUTPUT_CONTROL, 3) < 0)
+       if (reg_set(icd, MT9T031_OUTPUT_CONTROL, 2) < 0)
                return -EIO;
        return 0;
 }
@@ -173,7 +171,7 @@ static int mt9t031_start_capture(struct soc_camera_device *icd)
 static int mt9t031_stop_capture(struct soc_camera_device *icd)
 {
        /* Stop sensor readout */
-       if (reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3) < 0)
+       if (reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2) < 0)
                return -EIO;
        return 0;
 }
@@ -186,9 +184,9 @@ static int mt9t031_set_bus_param(struct soc_camera_device *icd,
                return -EINVAL;
 
        if (flags & SOCAM_PCLK_SAMPLE_FALLING)
-               reg_set(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
-       else
                reg_clear(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+       else
+               reg_set(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
 
        return 0;
 }
@@ -201,67 +199,73 @@ static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd)
        return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM);
 }
 
-static int mt9t031_set_fmt(struct soc_camera_device *icd,
-                          __u32 pixfmt, struct v4l2_rect *rect)
+/* Round up minima and round down maxima */
+static void recalculate_limits(struct soc_camera_device *icd,
+                              u16 xskip, u16 yskip)
+{
+       icd->x_min = (MT9T031_COLUMN_SKIP + xskip - 1) / xskip;
+       icd->y_min = (MT9T031_ROW_SKIP + yskip - 1) / yskip;
+       icd->width_min = (MT9T031_MIN_WIDTH + xskip - 1) / xskip;
+       icd->height_min = (MT9T031_MIN_HEIGHT + yskip - 1) / yskip;
+       icd->width_max = MT9T031_MAX_WIDTH / xskip;
+       icd->height_max = MT9T031_MAX_HEIGHT / yskip;
+}
+
+static int mt9t031_set_params(struct soc_camera_device *icd,
+                             struct v4l2_rect *rect, u16 xskip, u16 yskip)
 {
        struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
        int ret;
+       u16 xbin, ybin, width, height, left, top;
        const u16 hblank = MT9T031_HORIZONTAL_BLANK,
                vblank = MT9T031_VERTICAL_BLANK;
-       u16 xbin, xskip = mt9t031->xskip, ybin, yskip = mt9t031->yskip,
-               width = rect->width * xskip, height = rect->height * yskip;
 
-       if (pixfmt) {
-               /* S_FMT - use binning and skipping for scaling, recalculate */
-               /* Is this more optimal than just a division? */
-               for (xskip = 8; xskip > 1; xskip--)
-                       if (rect->width * xskip <= icd->width_max)
-                               break;
+       /* Make sure we don't exceed sensor limits */
+       if (rect->left + rect->width > icd->width_max)
+               rect->left = (icd->width_max - rect->width) / 2 + icd->x_min;
 
-               for (yskip = 8; yskip > 1; yskip--)
-                       if (rect->height * yskip <= icd->height_max)
-                               break;
+       if (rect->top + rect->height > icd->height_max)
+               rect->top = (icd->height_max - rect->height) / 2 + icd->y_min;
 
-               width = rect->width * xskip;
-               height = rect->height * yskip;
-
-               dev_dbg(&icd->dev, "xskip %u, width %u, yskip %u, height %u\n",
-                       xskip, width, yskip, height);
-       }
+       width = rect->width * xskip;
+       height = rect->height * yskip;
+       left = rect->left * xskip;
+       top = rect->top * yskip;
 
        xbin = min(xskip, (u16)3);
        ybin = min(yskip, (u16)3);
 
-       /* Make sure we don't exceed frame limits */
-       if (rect->left + width > icd->width_max)
-               rect->left = (icd->width_max - width) / 2;
-
-       if (rect->top + height > icd->height_max)
-               rect->top = (icd->height_max - height) / 2;
+       dev_dbg(&icd->dev, "xskip %u, width %u/%u, yskip %u, height %u/%u\n",
+               xskip, width, rect->width, yskip, height, rect->height);
 
-       /* Could just do roundup(rect->left, [xy]bin); but this is cheaper */
+       /* Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper */
        switch (xbin) {
        case 2:
-               rect->left = (rect->left + 1) & ~1;
+               left = (left + 3) & ~3;
                break;
        case 3:
-               rect->left = roundup(rect->left, 3);
+               left = roundup(left, 6);
        }
 
        switch (ybin) {
        case 2:
-               rect->top = (rect->top + 1) & ~1;
+               top = (top + 3) & ~3;
                break;
        case 3:
-               rect->top = roundup(rect->top, 3);
+               top = roundup(top, 6);
        }
 
+       /* Disable register update, reconfigure atomically */
+       ret = reg_set(icd, MT9T031_OUTPUT_CONTROL, 1);
+       if (ret < 0)
+               return ret;
+
        /* Blanking and start values - default... */
        ret = reg_write(icd, MT9T031_HORIZONTAL_BLANKING, hblank);
        if (ret >= 0)
                ret = reg_write(icd, MT9T031_VERTICAL_BLANKING, vblank);
 
-       if (pixfmt) {
+       if (yskip != mt9t031->yskip || xskip != mt9t031->xskip) {
                /* Binning, skipping */
                if (ret >= 0)
                        ret = reg_write(icd, MT9T031_COLUMN_ADDRESS_MODE,
@@ -270,14 +274,14 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd,
                        ret = reg_write(icd, MT9T031_ROW_ADDRESS_MODE,
                                        ((ybin - 1) << 4) | (yskip - 1));
        }
-       dev_dbg(&icd->dev, "new left %u, top %u\n", rect->left, rect->top);
+       dev_dbg(&icd->dev, "new physical left %u, top %u\n", left, top);
 
        /* The caller provides a supported format, as guaranteed by
         * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */
        if (ret >= 0)
-               ret = reg_write(icd, MT9T031_COLUMN_START, rect->left);
+               ret = reg_write(icd, MT9T031_COLUMN_START, left);
        if (ret >= 0)
-               ret = reg_write(icd, MT9T031_ROW_START, rect->top);
+               ret = reg_write(icd, MT9T031_ROW_START, top);
        if (ret >= 0)
                ret = reg_write(icd, MT9T031_WINDOW_WIDTH, width - 1);
        if (ret >= 0)
@@ -297,12 +301,58 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd,
                }
        }
 
-       if (!ret && pixfmt) {
+       /* Re-enable register update, commit all changes */
+       if (ret >= 0)
+               ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 1);
+
+       return ret < 0 ? ret : 0;
+}
+
+static int mt9t031_set_crop(struct soc_camera_device *icd,
+                           struct v4l2_rect *rect)
+{
+       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+
+       /* CROP - no change in scaling, or in limits */
+       return mt9t031_set_params(icd, rect, mt9t031->xskip, mt9t031->yskip);
+}
+
+static int mt9t031_set_fmt(struct soc_camera_device *icd,
+                          struct v4l2_format *f)
+{
+       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+       int ret;
+       u16 xskip, yskip;
+       struct v4l2_rect rect = {
+               .left   = icd->x_current,
+               .top    = icd->y_current,
+               .width  = f->fmt.pix.width,
+               .height = f->fmt.pix.height,
+       };
+
+       /*
+        * try_fmt has put rectangle within limits.
+        * S_FMT - use binning and skipping for scaling, recalculate
+        * limits, used for cropping
+        */
+       /* Is this more optimal than just a division? */
+       for (xskip = 8; xskip > 1; xskip--)
+               if (rect.width * xskip <= MT9T031_MAX_WIDTH)
+                       break;
+
+       for (yskip = 8; yskip > 1; yskip--)
+               if (rect.height * yskip <= MT9T031_MAX_HEIGHT)
+                       break;
+
+       recalculate_limits(icd, xskip, yskip);
+
+       ret = mt9t031_set_params(icd, &rect, xskip, yskip);
+       if (!ret) {
                mt9t031->xskip = xskip;
                mt9t031->yskip = yskip;
        }
 
-       return ret < 0 ? ret : 0;
+       return ret;
 }
 
 static int mt9t031_try_fmt(struct soc_camera_device *icd,
@@ -310,14 +360,14 @@ static int mt9t031_try_fmt(struct soc_camera_device *icd,
 {
        struct v4l2_pix_format *pix = &f->fmt.pix;
 
-       if (pix->height < icd->height_min)
-               pix->height = icd->height_min;
-       if (pix->height > icd->height_max)
-               pix->height = icd->height_max;
-       if (pix->width < icd->width_min)
-               pix->width = icd->width_min;
-       if (pix->width > icd->width_max)
-               pix->width = icd->width_max;
+       if (pix->height < MT9T031_MIN_HEIGHT)
+               pix->height = MT9T031_MIN_HEIGHT;
+       if (pix->height > MT9T031_MAX_HEIGHT)
+               pix->height = MT9T031_MAX_HEIGHT;
+       if (pix->width < MT9T031_MIN_WIDTH)
+               pix->width = MT9T031_MIN_WIDTH;
+       if (pix->width > MT9T031_MAX_WIDTH)
+               pix->width = MT9T031_MAX_WIDTH;
 
        pix->width &= ~0x01; /* has to be even */
        pix->height &= ~0x01; /* has to be even */
@@ -389,6 +439,14 @@ static const struct v4l2_queryctrl mt9t031_controls[] = {
                .maximum        = 1,
                .step           = 1,
                .default_value  = 0,
+       }, {
+               .id             = V4L2_CID_HFLIP,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Flip Horizontally",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
        }, {
                .id             = V4L2_CID_GAIN,
                .type           = V4L2_CTRL_TYPE_INTEGER,
@@ -431,6 +489,7 @@ static struct soc_camera_ops mt9t031_ops = {
        .release                = mt9t031_release,
        .start_capture          = mt9t031_start_capture,
        .stop_capture           = mt9t031_stop_capture,
+       .set_crop               = mt9t031_set_crop,
        .set_fmt                = mt9t031_set_fmt,
        .try_fmt                = mt9t031_try_fmt,
        .set_bus_param          = mt9t031_set_bus_param,
@@ -513,21 +572,23 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
                        if (data < 0)
                                return -EIO;
                } else {
-                       /* Pack it into 1.125..15 variable step, register values 9..67 */
+                       /* Pack it into 1.125..128 variable step, register values 9..0x7860 */
                        /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
                        unsigned long range = qctrl->maximum - qctrl->default_value - 1;
+                       /* calculated gain: map 65..127 to 9..1024 step 0.125 */
                        unsigned long gain = ((ctrl->value - qctrl->default_value - 1) *
-                                              111 + range / 2) / range + 9;
+                                              1015 + range / 2) / range + 9;
 
-                       if (gain <= 32)
+                       if (gain <= 32)         /* calculated gain 9..32 -> 9..32 */
                                data = gain;
-                       else if (gain <= 64)
+                       else if (gain <= 64)    /* calculated gain 33..64 -> 0x51..0x60 */
                                data = ((gain - 32) * 16 + 16) / 32 + 80;
                        else
-                               data = ((gain - 64) * 7 + 28) / 56 + 96;
+                               /* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */
+                               data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60;
 
-                       dev_dbg(&icd->dev, "Setting gain from %d to %d\n",
-                                reg_read(icd, MT9T031_GLOBAL_GAIN), data);
+                       dev_dbg(&icd->dev, "Setting gain from 0x%x to 0x%x\n",
+                               reg_read(icd, MT9T031_GLOBAL_GAIN), data);
                        data = reg_write(icd, MT9T031_GLOBAL_GAIN, data);
                        if (data < 0)
                                return -EIO;
index b04c8cb1644d1193cf3d59ef7b6df597fb7b6933..4d3b4813c322e67dc46c2c8c272a8db1ba1c728f 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/log2.h>
-#include <linux/gpio.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
@@ -89,9 +88,7 @@ struct mt9v022 {
        struct i2c_client *client;
        struct soc_camera_device icd;
        int model;      /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
-       int switch_gpio;
        u16 chip_control;
-       unsigned char datawidth;
 };
 
 static int reg_read(struct soc_camera_device *icd, const u8 reg)
@@ -209,66 +206,6 @@ static int mt9v022_stop_capture(struct soc_camera_device *icd)
        return 0;
 }
 
-static int bus_switch_request(struct mt9v022 *mt9v022, struct soc_camera_link *icl)
-{
-#ifdef CONFIG_MT9V022_PCA9536_SWITCH
-       int ret;
-       unsigned int gpio = icl->gpio;
-
-       if (gpio_is_valid(gpio)) {
-               /* We have a data bus switch. */
-               ret = gpio_request(gpio, "mt9v022");
-               if (ret < 0) {
-                       dev_err(&mt9v022->client->dev, "Cannot get GPIO %u\n", gpio);
-                       return ret;
-               }
-
-               ret = gpio_direction_output(gpio, 0);
-               if (ret < 0) {
-                       dev_err(&mt9v022->client->dev,
-                               "Cannot set GPIO %u to output\n", gpio);
-                       gpio_free(gpio);
-                       return ret;
-               }
-       }
-
-       mt9v022->switch_gpio = gpio;
-#else
-       mt9v022->switch_gpio = -EINVAL;
-#endif
-       return 0;
-}
-
-static void bus_switch_release(struct mt9v022 *mt9v022)
-{
-#ifdef CONFIG_MT9V022_PCA9536_SWITCH
-       if (gpio_is_valid(mt9v022->switch_gpio))
-               gpio_free(mt9v022->switch_gpio);
-#endif
-}
-
-static int bus_switch_act(struct mt9v022 *mt9v022, int go8bit)
-{
-#ifdef CONFIG_MT9V022_PCA9536_SWITCH
-       if (!gpio_is_valid(mt9v022->switch_gpio))
-               return -ENODEV;
-
-       gpio_set_value_cansleep(mt9v022->switch_gpio, go8bit);
-       return 0;
-#else
-       return -ENODEV;
-#endif
-}
-
-static int bus_switch_possible(struct mt9v022 *mt9v022)
-{
-#ifdef CONFIG_MT9V022_PCA9536_SWITCH
-       return gpio_is_valid(mt9v022->switch_gpio);
-#else
-       return 0;
-#endif
-}
-
 static int mt9v022_set_bus_param(struct soc_camera_device *icd,
                                 unsigned long flags)
 {
@@ -282,19 +219,17 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
        if (!is_power_of_2(width_flag))
                return -EINVAL;
 
-       if ((mt9v022->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
-           (mt9v022->datawidth != 9  && (width_flag == SOCAM_DATAWIDTH_9)) ||
-           (mt9v022->datawidth != 8  && (width_flag == SOCAM_DATAWIDTH_8))) {
-               /* Well, we actually only can do 10 or 8 bits... */
-               if (width_flag == SOCAM_DATAWIDTH_9)
-                       return -EINVAL;
-
-               ret = bus_switch_act(mt9v022,
-                                    width_flag == SOCAM_DATAWIDTH_8);
-               if (ret < 0)
+       if (icl->set_bus_param) {
+               ret = icl->set_bus_param(icl, width_flag);
+               if (ret)
                        return ret;
-
-               mt9v022->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
+       } else {
+               /*
+                * Without board specific bus width settings we only support the
+                * sensors native bus width
+                */
+               if (width_flag != SOCAM_DATAWIDTH_10)
+                       return -EINVAL;
        }
 
        flags = soc_camera_apply_sensor_flags(icl, flags);
@@ -328,44 +263,27 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
 static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
 {
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-       unsigned int width_flag = SOCAM_DATAWIDTH_10;
+       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+       unsigned int width_flag;
 
-       if (bus_switch_possible(mt9v022))
-               width_flag |= SOCAM_DATAWIDTH_8;
+       if (icl->query_bus_param)
+               width_flag = icl->query_bus_param(icl) &
+                       SOCAM_DATAWIDTH_MASK;
+       else
+               width_flag = SOCAM_DATAWIDTH_10;
 
        return SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING |
                SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW |
                SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |
-               SOCAM_MASTER | SOCAM_SLAVE |
+               SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_SLAVE |
                width_flag;
 }
 
-static int mt9v022_set_fmt(struct soc_camera_device *icd,
-                          __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9v022_set_crop(struct soc_camera_device *icd,
+                           struct v4l2_rect *rect)
 {
-       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
        int ret;
 
-       /* The caller provides a supported format, as verified per call to
-        * icd->try_fmt(), datawidth is from our supported format list */
-       switch (pixfmt) {
-       case V4L2_PIX_FMT_GREY:
-       case V4L2_PIX_FMT_Y16:
-               if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
-                       return -EINVAL;
-               break;
-       case V4L2_PIX_FMT_SBGGR8:
-       case V4L2_PIX_FMT_SBGGR16:
-               if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
-                       return -EINVAL;
-               break;
-       case 0:
-               /* No format change, only geometry */
-               break;
-       default:
-               return -EINVAL;
-       }
-
        /* Like in example app. Contradicts the datasheet though */
        ret = reg_read(icd, MT9V022_AEC_AGC_ENABLE);
        if (ret >= 0) {
@@ -403,6 +321,42 @@ static int mt9v022_set_fmt(struct soc_camera_device *icd,
        return 0;
 }
 
+static int mt9v022_set_fmt(struct soc_camera_device *icd,
+                          struct v4l2_format *f)
+{
+       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct v4l2_rect rect = {
+               .left   = icd->x_current,
+               .top    = icd->y_current,
+               .width  = pix->width,
+               .height = pix->height,
+       };
+
+       /* The caller provides a supported format, as verified per call to
+        * icd->try_fmt(), datawidth is from our supported format list */
+       switch (pix->pixelformat) {
+       case V4L2_PIX_FMT_GREY:
+       case V4L2_PIX_FMT_Y16:
+               if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
+                       return -EINVAL;
+               break;
+       case V4L2_PIX_FMT_SBGGR8:
+       case V4L2_PIX_FMT_SBGGR16:
+               if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
+                       return -EINVAL;
+               break;
+       case 0:
+               /* No format change, only geometry */
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* No support for scaling on this camera, just crop. */
+       return mt9v022_set_crop(icd, &rect);
+}
+
 static int mt9v022_try_fmt(struct soc_camera_device *icd,
                           struct v4l2_format *f)
 {
@@ -544,6 +498,7 @@ static struct soc_camera_ops mt9v022_ops = {
        .release                = mt9v022_release,
        .start_capture          = mt9v022_start_capture,
        .stop_capture           = mt9v022_stop_capture,
+       .set_crop               = mt9v022_set_crop,
        .set_fmt                = mt9v022_set_fmt,
        .try_fmt                = mt9v022_try_fmt,
        .set_bus_param          = mt9v022_set_bus_param,
@@ -699,6 +654,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
        struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
        s32 data;
        int ret;
+       unsigned long flags;
 
        if (!icd->dev.parent ||
            to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
@@ -732,22 +688,36 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
                ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
                mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
                icd->formats = mt9v022_colour_formats;
-               if (gpio_is_valid(icl->gpio))
-                       icd->num_formats = ARRAY_SIZE(mt9v022_colour_formats);
-               else
-                       icd->num_formats = 1;
        } else {
                ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 0x11);
                mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
                icd->formats = mt9v022_monochrome_formats;
-               if (gpio_is_valid(icl->gpio))
-                       icd->num_formats = ARRAY_SIZE(mt9v022_monochrome_formats);
-               else
-                       icd->num_formats = 1;
        }
 
-       if (!ret)
-               ret = soc_camera_video_start(icd);
+       if (ret < 0)
+               goto eisis;
+
+       icd->num_formats = 0;
+
+       /*
+        * This is a 10bit sensor, so by default we only allow 10bit.
+        * The platform may support different bus widths due to
+        * different routing of the data lines.
+        */
+       if (icl->query_bus_param)
+               flags = icl->query_bus_param(icl);
+       else
+               flags = SOCAM_DATAWIDTH_10;
+
+       if (flags & SOCAM_DATAWIDTH_10)
+               icd->num_formats++;
+       else
+               icd->formats++;
+
+       if (flags & SOCAM_DATAWIDTH_8)
+               icd->num_formats++;
+
+       ret = soc_camera_video_start(icd);
        if (ret < 0)
                goto eisis;
 
@@ -812,14 +782,6 @@ static int mt9v022_probe(struct i2c_client *client,
        icd->height_max = 480;
        icd->y_skip_top = 1;
        icd->iface      = icl->bus_id;
-       /* Default datawidth - this is the only width this camera (normally)
-        * supports. It is only with extra logic that it can support
-        * other widths. Therefore it seems to be a sensible default. */
-       mt9v022->datawidth = 10;
-
-       ret = bus_switch_request(mt9v022, icl);
-       if (ret)
-               goto eswinit;
 
        ret = soc_camera_device_register(icd);
        if (ret)
@@ -828,8 +790,6 @@ static int mt9v022_probe(struct i2c_client *client,
        return 0;
 
 eisdr:
-       bus_switch_release(mt9v022);
-eswinit:
        kfree(mt9v022);
        return ret;
 }
@@ -839,7 +799,6 @@ static int mt9v022_remove(struct i2c_client *client)
        struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
 
        soc_camera_device_unregister(&mt9v022->icd);
-       bus_switch_release(mt9v022);
        kfree(mt9v022);
 
        return 0;
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
new file mode 100644 (file)
index 0000000..70629e1
--- /dev/null
@@ -0,0 +1,1220 @@
+/*
+ * V4L2 Driver for i.MX3x camera host
+ *
+ * Copyright (C) 2008
+ * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/soc_camera.h>
+
+#include <mach/ipu.h>
+#include <mach/mx3_camera.h>
+
+#define MX3_CAM_DRV_NAME "mx3-camera"
+
+/* CMOS Sensor Interface Registers */
+#define CSI_REG_START          0x60
+
+#define CSI_SENS_CONF          (0x60 - CSI_REG_START)
+#define CSI_SENS_FRM_SIZE      (0x64 - CSI_REG_START)
+#define CSI_ACT_FRM_SIZE       (0x68 - CSI_REG_START)
+#define CSI_OUT_FRM_CTRL       (0x6C - CSI_REG_START)
+#define CSI_TST_CTRL           (0x70 - CSI_REG_START)
+#define CSI_CCIR_CODE_1                (0x74 - CSI_REG_START)
+#define CSI_CCIR_CODE_2                (0x78 - CSI_REG_START)
+#define CSI_CCIR_CODE_3                (0x7C - CSI_REG_START)
+#define CSI_FLASH_STROBE_1     (0x80 - CSI_REG_START)
+#define CSI_FLASH_STROBE_2     (0x84 - CSI_REG_START)
+
+#define CSI_SENS_CONF_VSYNC_POL_SHIFT          0
+#define CSI_SENS_CONF_HSYNC_POL_SHIFT          1
+#define CSI_SENS_CONF_DATA_POL_SHIFT           2
+#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT                3
+#define CSI_SENS_CONF_SENS_PRTCL_SHIFT         4
+#define CSI_SENS_CONF_SENS_CLKSRC_SHIFT                7
+#define CSI_SENS_CONF_DATA_FMT_SHIFT           8
+#define CSI_SENS_CONF_DATA_WIDTH_SHIFT         10
+#define CSI_SENS_CONF_EXT_VSYNC_SHIFT          15
+#define CSI_SENS_CONF_DIVRATIO_SHIFT           16
+
+#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444      (0UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
+#define CSI_SENS_CONF_DATA_FMT_YUV422          (2UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
+#define CSI_SENS_CONF_DATA_FMT_BAYER           (3UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
+
+#define MAX_VIDEO_MEM 16
+
+struct mx3_camera_buffer {
+       /* common v4l buffer stuff -- must be first */
+       struct videobuf_buffer                  vb;
+       const struct soc_camera_data_format     *fmt;
+
+       /* One descriptot per scatterlist (per frame) */
+       struct dma_async_tx_descriptor          *txd;
+
+       /* We have to "build" a scatterlist ourselves - one element per frame */
+       struct scatterlist                      sg;
+};
+
+/**
+ * struct mx3_camera_dev - i.MX3x camera (CSI) object
+ * @dev:               camera device, to which the coherent buffer is attached
+ * @icd:               currently attached camera sensor
+ * @clk:               pointer to clock
+ * @base:              remapped register base address
+ * @pdata:             platform data
+ * @platform_flags:    platform flags
+ * @mclk:              master clock frequency in Hz
+ * @capture:           list of capture videobuffers
+ * @lock:              protects video buffer lists
+ * @active:            active video buffer
+ * @idmac_channel:     array of pointers to IPU DMAC DMA channels
+ * @soc_host:          embedded soc_host object
+ */
+struct mx3_camera_dev {
+       struct device           *dev;
+       /*
+        * i.MX3x is only supposed to handle one camera on its Camera Sensor
+        * Interface. If anyone ever builds hardware to enable more than one
+        * camera _simultaneously_, they will have to modify this driver too
+        */
+       struct soc_camera_device *icd;
+       struct clk              *clk;
+
+       void __iomem            *base;
+
+       struct mx3_camera_pdata *pdata;
+
+       unsigned long           platform_flags;
+       unsigned long           mclk;
+
+       struct list_head        capture;
+       spinlock_t              lock;           /* Protects video buffer lists */
+       struct mx3_camera_buffer *active;
+
+       /* IDMAC / dmaengine interface */
+       struct idmac_channel    *idmac_channel[1];      /* We need one channel */
+
+       struct soc_camera_host  soc_host;
+};
+
+struct dma_chan_request {
+       struct mx3_camera_dev   *mx3_cam;
+       enum ipu_channel        id;
+};
+
+static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt);
+
+static u32 csi_reg_read(struct mx3_camera_dev *mx3, off_t reg)
+{
+       return __raw_readl(mx3->base + reg);
+}
+
+static void csi_reg_write(struct mx3_camera_dev *mx3, u32 value, off_t reg)
+{
+       __raw_writel(value, mx3->base + reg);
+}
+
+/* Called from the IPU IDMAC ISR */
+static void mx3_cam_dma_done(void *arg)
+{
+       struct idmac_tx_desc *desc = to_tx_desc(arg);
+       struct dma_chan *chan = desc->txd.chan;
+       struct idmac_channel *ichannel = to_idmac_chan(chan);
+       struct mx3_camera_dev *mx3_cam = ichannel->client;
+       struct videobuf_buffer *vb;
+
+       dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n",
+               desc->txd.cookie, mx3_cam->active ? sg_dma_address(&mx3_cam->active->sg) : 0);
+
+       spin_lock(&mx3_cam->lock);
+       if (mx3_cam->active) {
+               vb = &mx3_cam->active->vb;
+
+               list_del_init(&vb->queue);
+               vb->state = VIDEOBUF_DONE;
+               do_gettimeofday(&vb->ts);
+               vb->field_count++;
+               wake_up(&vb->done);
+       }
+
+       if (list_empty(&mx3_cam->capture)) {
+               mx3_cam->active = NULL;
+               spin_unlock(&mx3_cam->lock);
+
+               /*
+                * stop capture - without further buffers IPU_CHA_BUF0_RDY will
+                * not get updated
+                */
+               return;
+       }
+
+       mx3_cam->active = list_entry(mx3_cam->capture.next,
+                                    struct mx3_camera_buffer, vb.queue);
+       mx3_cam->active->vb.state = VIDEOBUF_ACTIVE;
+       spin_unlock(&mx3_cam->lock);
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct mx3_camera_buffer *buf)
+{
+       struct soc_camera_device *icd = vq->priv_data;
+       struct videobuf_buffer *vb = &buf->vb;
+       struct dma_async_tx_descriptor *txd = buf->txd;
+       struct idmac_channel *ichan;
+
+       BUG_ON(in_interrupt());
+
+       dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+               vb, vb->baddr, vb->bsize);
+
+       /*
+        * This waits until this buffer is out of danger, i.e., until it is no
+        * longer in STATE_QUEUED or STATE_ACTIVE
+        */
+       videobuf_waiton(vb, 0, 0);
+       if (txd) {
+               ichan = to_idmac_chan(txd->chan);
+               async_tx_ack(txd);
+       }
+       videobuf_dma_contig_free(vq, vb);
+       buf->txd = NULL;
+
+       vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+/*
+ * Videobuf operations
+ */
+
+/*
+ * Calculate the __buffer__ (not data) size and number of buffers.
+ * Called with .vb_lock held
+ */
+static int mx3_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
+                             unsigned int *size)
+{
+       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx3_camera_dev *mx3_cam = ici->priv;
+       /*
+        * bits-per-pixel (depth) as specified in camera's pixel format does
+        * not necessarily match what the camera interface writes to RAM, but
+        * it should be good enough for now.
+        */
+       unsigned int bpp = DIV_ROUND_UP(icd->current_fmt->depth, 8);
+
+       if (!mx3_cam->idmac_channel[0])
+               return -EINVAL;
+
+       *size = icd->width * icd->height * bpp;
+
+       if (!*count)
+               *count = 32;
+
+       if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
+               *count = MAX_VIDEO_MEM * 1024 * 1024 / *size;
+
+       return 0;
+}
+
+/* Called with .vb_lock held */
+static int mx3_videobuf_prepare(struct videobuf_queue *vq,
+               struct videobuf_buffer *vb, enum v4l2_field field)
+{
+       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx3_camera_dev *mx3_cam = ici->priv;
+       struct mx3_camera_buffer *buf =
+               container_of(vb, struct mx3_camera_buffer, vb);
+       /* current_fmt _must_ always be set */
+       size_t new_size = icd->width * icd->height *
+               ((icd->current_fmt->depth + 7) >> 3);
+       int ret;
+
+       /*
+        * I think, in buf_prepare you only have to protect global data,
+        * the actual buffer is yours
+        */
+
+       if (buf->fmt    != icd->current_fmt ||
+           vb->width   != icd->width ||
+           vb->height  != icd->height ||
+           vb->field   != field) {
+               buf->fmt        = icd->current_fmt;
+               vb->width       = icd->width;
+               vb->height      = icd->height;
+               vb->field       = field;
+               if (vb->state != VIDEOBUF_NEEDS_INIT)
+                       free_buffer(vq, buf);
+       }
+
+       if (vb->baddr && vb->bsize < new_size) {
+               /* User provided buffer, but it is too small */
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if (vb->state == VIDEOBUF_NEEDS_INIT) {
+               struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
+               struct scatterlist *sg = &buf->sg;
+
+               /*
+                * The total size of video-buffers that will be allocated / mapped.
+                * *size that we calculated in videobuf_setup gets assigned to
+                * vb->bsize, and now we use the same calculation to get vb->size.
+                */
+               vb->size = new_size;
+
+               /* This actually (allocates and) maps buffers */
+               ret = videobuf_iolock(vq, vb, NULL);
+               if (ret)
+                       goto fail;
+
+               /*
+                * We will have to configure the IDMAC channel. It has two slots
+                * for DMA buffers, we shall enter the first two buffers there,
+                * and then submit new buffers in DMA-ready interrupts
+                */
+               sg_init_table(sg, 1);
+               sg_dma_address(sg)      = videobuf_to_dma_contig(vb);
+               sg_dma_len(sg)          = vb->size;
+
+               buf->txd = ichan->dma_chan.device->device_prep_slave_sg(
+                       &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE,
+                       DMA_PREP_INTERRUPT);
+               if (!buf->txd) {
+                       ret = -EIO;
+                       goto fail;
+               }
+
+               buf->txd->callback_param        = buf->txd;
+               buf->txd->callback              = mx3_cam_dma_done;
+
+               vb->state = VIDEOBUF_PREPARED;
+       }
+
+       return 0;
+
+fail:
+       free_buffer(vq, buf);
+out:
+       return ret;
+}
+
+static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc)
+{
+       /* Add more formats as need arises and test possibilities appear... */
+       switch (fourcc) {
+       case V4L2_PIX_FMT_RGB565:
+               return IPU_PIX_FMT_RGB565;
+       case V4L2_PIX_FMT_RGB24:
+               return IPU_PIX_FMT_RGB24;
+       case V4L2_PIX_FMT_RGB332:
+               return IPU_PIX_FMT_RGB332;
+       case V4L2_PIX_FMT_YUV422P:
+               return IPU_PIX_FMT_YVU422P;
+       default:
+               return IPU_PIX_FMT_GENERIC;
+       }
+}
+
+/* Called with .vb_lock held */
+static void mx3_videobuf_queue(struct videobuf_queue *vq,
+                              struct videobuf_buffer *vb)
+{
+       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx3_camera_dev *mx3_cam = ici->priv;
+       struct mx3_camera_buffer *buf =
+               container_of(vb, struct mx3_camera_buffer, vb);
+       struct dma_async_tx_descriptor *txd = buf->txd;
+       struct idmac_channel *ichan = to_idmac_chan(txd->chan);
+       struct idmac_video_param *video = &ichan->params.video;
+       const struct soc_camera_data_format *data_fmt = icd->current_fmt;
+       dma_cookie_t cookie;
+       unsigned long flags;
+
+       /* This is the configuration of one sg-element */
+       video->out_pixel_fmt    = fourcc_to_ipu_pix(data_fmt->fourcc);
+       video->out_width        = icd->width;
+       video->out_height       = icd->height;
+       video->out_stride       = icd->width;
+
+#ifdef DEBUG
+       /* helps to see what DMA actually has written */
+       memset((void *)vb->baddr, 0xaa, vb->bsize);
+#endif
+
+       spin_lock_irqsave(&mx3_cam->lock, flags);
+
+       list_add_tail(&vb->queue, &mx3_cam->capture);
+
+       if (!mx3_cam->active) {
+               mx3_cam->active = buf;
+               vb->state = VIDEOBUF_ACTIVE;
+       } else {
+               vb->state = VIDEOBUF_QUEUED;
+       }
+
+       spin_unlock_irqrestore(&mx3_cam->lock, flags);
+
+       cookie = txd->tx_submit(txd);
+       dev_dbg(&icd->dev, "Submitted cookie %d DMA 0x%08x\n", cookie, sg_dma_address(&buf->sg));
+       if (cookie >= 0)
+               return;
+
+       /* Submit error */
+       vb->state = VIDEOBUF_PREPARED;
+
+       spin_lock_irqsave(&mx3_cam->lock, flags);
+
+       list_del_init(&vb->queue);
+
+       if (mx3_cam->active == buf)
+               mx3_cam->active = NULL;
+
+       spin_unlock_irqrestore(&mx3_cam->lock, flags);
+}
+
+/* Called with .vb_lock held */
+static void mx3_videobuf_release(struct videobuf_queue *vq,
+                                struct videobuf_buffer *vb)
+{
+       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx3_camera_dev *mx3_cam = ici->priv;
+       struct mx3_camera_buffer *buf =
+               container_of(vb, struct mx3_camera_buffer, vb);
+       unsigned long flags;
+
+       dev_dbg(&icd->dev, "Release%s DMA 0x%08x (state %d), queue %sempty\n",
+               mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg),
+                vb->state, list_empty(&vb->queue) ? "" : "not ");
+       spin_lock_irqsave(&mx3_cam->lock, flags);
+       if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
+           !list_empty(&vb->queue)) {
+               vb->state = VIDEOBUF_ERROR;
+
+               list_del_init(&vb->queue);
+               if (mx3_cam->active == buf)
+                       mx3_cam->active = NULL;
+       }
+       spin_unlock_irqrestore(&mx3_cam->lock, flags);
+       free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops mx3_videobuf_ops = {
+       .buf_setup      = mx3_videobuf_setup,
+       .buf_prepare    = mx3_videobuf_prepare,
+       .buf_queue      = mx3_videobuf_queue,
+       .buf_release    = mx3_videobuf_release,
+};
+
+static void mx3_camera_init_videobuf(struct videobuf_queue *q,
+                                    struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx3_camera_dev *mx3_cam = ici->priv;
+
+       videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, mx3_cam->dev,
+                                      &mx3_cam->lock,
+                                      V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                                      V4L2_FIELD_NONE,
+                                      sizeof(struct mx3_camera_buffer), icd);
+}
+
+/* First part of ipu_csi_init_interface() */
+static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
+                               struct soc_camera_device *icd)
+{
+       u32 conf;
+       long rate;
+
+       /* Set default size: ipu_csi_set_window_size() */
+       csi_reg_write(mx3_cam, (640 - 1) | ((480 - 1) << 16), CSI_ACT_FRM_SIZE);
+       /* ...and position to 0:0: ipu_csi_set_window_pos() */
+       conf = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000;
+       csi_reg_write(mx3_cam, conf, CSI_OUT_FRM_CTRL);
+
+       /* We use only gated clock synchronisation mode so far */
+       conf = 0 << CSI_SENS_CONF_SENS_PRTCL_SHIFT;
+
+       /* Set generic data, platform-biggest bus-width */
+       conf |= CSI_SENS_CONF_DATA_FMT_BAYER;
+
+       if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15)
+               conf |= 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+       else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10)
+               conf |= 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+       else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8)
+               conf |= 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+       else/* if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)*/
+               conf |= 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+
+       if (mx3_cam->platform_flags & MX3_CAMERA_CLK_SRC)
+               conf |= 1 << CSI_SENS_CONF_SENS_CLKSRC_SHIFT;
+       if (mx3_cam->platform_flags & MX3_CAMERA_EXT_VSYNC)
+               conf |= 1 << CSI_SENS_CONF_EXT_VSYNC_SHIFT;
+       if (mx3_cam->platform_flags & MX3_CAMERA_DP)
+               conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT;
+       if (mx3_cam->platform_flags & MX3_CAMERA_PCP)
+               conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT;
+       if (mx3_cam->platform_flags & MX3_CAMERA_HSP)
+               conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT;
+       if (mx3_cam->platform_flags & MX3_CAMERA_VSP)
+               conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT;
+
+       /* ipu_csi_init_interface() */
+       csi_reg_write(mx3_cam, conf, CSI_SENS_CONF);
+
+       clk_enable(mx3_cam->clk);
+       rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk);
+       dev_dbg(&icd->dev, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
+       if (rate)
+               clk_set_rate(mx3_cam->clk, rate);
+}
+
+/* Called with .video_lock held */
+static int mx3_camera_add_device(struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx3_camera_dev *mx3_cam = ici->priv;
+       int ret;
+
+       if (mx3_cam->icd) {
+               ret = -EBUSY;
+               goto ebusy;
+       }
+
+       mx3_camera_activate(mx3_cam, icd);
+       ret = icd->ops->init(icd);
+       if (ret < 0) {
+               clk_disable(mx3_cam->clk);
+               goto einit;
+       }
+
+       mx3_cam->icd = icd;
+
+einit:
+ebusy:
+       if (!ret)
+               dev_info(&icd->dev, "MX3 Camera driver attached to camera %d\n",
+                        icd->devnum);
+
+       return ret;
+}
+
+/* Called with .video_lock held */
+static void mx3_camera_remove_device(struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx3_camera_dev *mx3_cam = ici->priv;
+       struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
+
+       BUG_ON(icd != mx3_cam->icd);
+
+       if (*ichan) {
+               dma_release_channel(&(*ichan)->dma_chan);
+               *ichan = NULL;
+       }
+
+       icd->ops->release(icd);
+
+       clk_disable(mx3_cam->clk);
+
+       mx3_cam->icd = NULL;
+
+       dev_info(&icd->dev, "MX3 Camera driver detached from camera %d\n",
+                icd->devnum);
+}
+
+static bool channel_change_requested(struct soc_camera_device *icd,
+                                    struct v4l2_rect *rect)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx3_camera_dev *mx3_cam = ici->priv;
+       struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
+
+       /* Do buffers have to be re-allocated or channel re-configured? */
+       return ichan && rect->width * rect->height > icd->width * icd->height;
+}
+
+static int test_platform_param(struct mx3_camera_dev *mx3_cam,
+                              unsigned char buswidth, unsigned long *flags)
+{
+       /*
+        * Platform specified synchronization and pixel clock polarities are
+        * only a recommendation and are only used during probing. MX3x
+        * camera interface only works in master mode, i.e., uses HSYNC and
+        * VSYNC signals from the sensor
+        */
+       *flags = SOCAM_MASTER |
+               SOCAM_HSYNC_ACTIVE_HIGH |
+               SOCAM_HSYNC_ACTIVE_LOW |
+               SOCAM_VSYNC_ACTIVE_HIGH |
+               SOCAM_VSYNC_ACTIVE_LOW |
+               SOCAM_PCLK_SAMPLE_RISING |
+               SOCAM_PCLK_SAMPLE_FALLING |
+               SOCAM_DATA_ACTIVE_HIGH |
+               SOCAM_DATA_ACTIVE_LOW;
+
+       /* If requested data width is supported by the platform, use it or any
+        * possible lower value - i.MX31 is smart enough to schift bits */
+       switch (buswidth) {
+       case 15:
+               if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15))
+                       return -EINVAL;
+               *flags |= SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_10 |
+                       SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4;
+               break;
+       case 10:
+               if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10))
+                       return -EINVAL;
+               *flags |= SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8 |
+                       SOCAM_DATAWIDTH_4;
+               break;
+       case 8:
+               if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8))
+                       return -EINVAL;
+               *flags |= SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4;
+               break;
+       case 4:
+               if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4))
+                       return -EINVAL;
+               *flags |= SOCAM_DATAWIDTH_4;
+               break;
+       default:
+               dev_info(mx3_cam->dev, "Unsupported bus width %d\n", buswidth);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
+                                   const unsigned int depth)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx3_camera_dev *mx3_cam = ici->priv;
+       unsigned long bus_flags, camera_flags;
+       int ret = test_platform_param(mx3_cam, depth, &bus_flags);
+
+       dev_dbg(&ici->dev, "requested bus width %d bit: %d\n", depth, ret);
+
+       if (ret < 0)
+               return ret;
+
+       camera_flags = icd->ops->query_bus_param(icd);
+
+       ret = soc_camera_bus_param_compatible(camera_flags, bus_flags);
+       if (ret < 0)
+               dev_warn(&icd->dev, "Flags incompatible: camera %lx, host %lx\n",
+                        camera_flags, bus_flags);
+
+       return ret;
+}
+
+static bool chan_filter(struct dma_chan *chan, void *arg)
+{
+       struct dma_chan_request *rq = arg;
+       struct mx3_camera_pdata *pdata;
+
+       if (!rq)
+               return false;
+
+       pdata = rq->mx3_cam->dev->platform_data;
+
+       return rq->id == chan->chan_id &&
+               pdata->dma_dev == chan->device->dev;
+}
+
+static const struct soc_camera_data_format mx3_camera_formats[] = {
+       {
+               .name           = "Bayer (sRGB) 8 bit",
+               .depth          = 8,
+               .fourcc         = V4L2_PIX_FMT_SBGGR8,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+       }, {
+               .name           = "Monochrome 8 bit",
+               .depth          = 8,
+               .fourcc         = V4L2_PIX_FMT_GREY,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+       },
+};
+
+static bool buswidth_supported(struct soc_camera_host *ici, int depth)
+{
+       struct mx3_camera_dev *mx3_cam = ici->priv;
+
+       switch (depth) {
+       case 4:
+               return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4);
+       case 8:
+               return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8);
+       case 10:
+               return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10);
+       case 15:
+               return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15);
+       }
+       return false;
+}
+
+static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx,
+                                 struct soc_camera_format_xlate *xlate)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       int formats = 0, buswidth, ret;
+
+       buswidth = icd->formats[idx].depth;
+
+       if (!buswidth_supported(ici, buswidth))
+               return 0;
+
+       ret = mx3_camera_try_bus_param(icd, buswidth);
+       if (ret < 0)
+               return 0;
+
+       switch (icd->formats[idx].fourcc) {
+       case V4L2_PIX_FMT_SGRBG10:
+               formats++;
+               if (xlate) {
+                       xlate->host_fmt = &mx3_camera_formats[0];
+                       xlate->cam_fmt = icd->formats + idx;
+                       xlate->buswidth = buswidth;
+                       xlate++;
+                       dev_dbg(&ici->dev, "Providing format %s using %s\n",
+                               mx3_camera_formats[0].name,
+                               icd->formats[idx].name);
+               }
+               goto passthrough;
+       case V4L2_PIX_FMT_Y16:
+               formats++;
+               if (xlate) {
+                       xlate->host_fmt = &mx3_camera_formats[1];
+                       xlate->cam_fmt = icd->formats + idx;
+                       xlate->buswidth = buswidth;
+                       xlate++;
+                       dev_dbg(&ici->dev, "Providing format %s using %s\n",
+                               mx3_camera_formats[0].name,
+                               icd->formats[idx].name);
+               }
+       default:
+passthrough:
+               /* Generic pass-through */
+               formats++;
+               if (xlate) {
+                       xlate->host_fmt = icd->formats + idx;
+                       xlate->cam_fmt = icd->formats + idx;
+                       xlate->buswidth = buswidth;
+                       xlate++;
+                       dev_dbg(&ici->dev,
+                               "Providing format %s in pass-through mode\n",
+                               icd->formats[idx].name);
+               }
+       }
+
+       return formats;
+}
+
+static void configure_geometry(struct mx3_camera_dev *mx3_cam,
+                              struct v4l2_rect *rect)
+{
+       u32 ctrl, width_field, height_field;
+
+       /* Setup frame size - this cannot be changed on-the-fly... */
+       width_field = rect->width - 1;
+       height_field = rect->height - 1;
+       csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE);
+
+       csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1);
+       csi_reg_write(mx3_cam, (height_field << 16) | 0x22, CSI_FLASH_STROBE_2);
+
+       csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_ACT_FRM_SIZE);
+
+       /* ...and position */
+       ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000;
+       /* Sensor does the cropping */
+       csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL);
+
+       /*
+        * No need to free resources here if we fail, we'll see if we need to
+        * do this next time we are called
+        */
+}
+
+static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
+{
+       dma_cap_mask_t mask;
+       struct dma_chan *chan;
+       struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
+       /* We have to use IDMAC_IC_7 for Bayer / generic data */
+       struct dma_chan_request rq = {.mx3_cam = mx3_cam,
+                                     .id = IDMAC_IC_7};
+
+       if (*ichan) {
+               struct videobuf_buffer *vb, *_vb;
+               dma_release_channel(&(*ichan)->dma_chan);
+               *ichan = NULL;
+               mx3_cam->active = NULL;
+               list_for_each_entry_safe(vb, _vb, &mx3_cam->capture, queue) {
+                       list_del_init(&vb->queue);
+                       vb->state = VIDEOBUF_ERROR;
+                       wake_up(&vb->done);
+               }
+       }
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+       dma_cap_set(DMA_PRIVATE, mask);
+       chan = dma_request_channel(mask, chan_filter, &rq);
+       if (!chan)
+               return -EBUSY;
+
+       *ichan = to_idmac_chan(chan);
+       (*ichan)->client = mx3_cam;
+
+       return 0;
+}
+
+static int mx3_camera_set_crop(struct soc_camera_device *icd,
+                              struct v4l2_rect *rect)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx3_camera_dev *mx3_cam = ici->priv;
+
+       /*
+        * We now know pixel formats and can decide upon DMA-channel(s)
+        * So far only direct camera-to-memory is supported
+        */
+       if (channel_change_requested(icd, rect)) {
+               int ret = acquire_dma_channel(mx3_cam);
+               if (ret < 0)
+                       return ret;
+       }
+
+       configure_geometry(mx3_cam, rect);
+
+       return icd->ops->set_crop(icd, rect);
+}
+
+static int mx3_camera_set_fmt(struct soc_camera_device *icd,
+                             struct v4l2_format *f)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx3_camera_dev *mx3_cam = ici->priv;
+       const struct soc_camera_format_xlate *xlate;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct v4l2_rect rect = {
+               .left   = icd->x_current,
+               .top    = icd->y_current,
+               .width  = pix->width,
+               .height = pix->height,
+       };
+       int ret;
+
+       xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+       if (!xlate) {
+               dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat);
+               return -EINVAL;
+       }
+
+       ret = acquire_dma_channel(mx3_cam);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Might have to perform a complete interface initialisation like in
+        * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider
+        * mxc_v4l2_s_fmt()
+        */
+
+       configure_geometry(mx3_cam, &rect);
+
+       ret = icd->ops->set_fmt(icd, f);
+       if (!ret) {
+               icd->buswidth = xlate->buswidth;
+               icd->current_fmt = xlate->host_fmt;
+       }
+
+       return ret;
+}
+
+static int mx3_camera_try_fmt(struct soc_camera_device *icd,
+                             struct v4l2_format *f)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       const struct soc_camera_format_xlate *xlate;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       __u32 pixfmt = pix->pixelformat;
+       enum v4l2_field field;
+       int ret;
+
+       xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+       if (pixfmt && !xlate) {
+               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               return -EINVAL;
+       }
+
+       /* limit to MX3 hardware capabilities */
+       if (pix->height > 4096)
+               pix->height = 4096;
+       if (pix->width > 4096)
+               pix->width = 4096;
+
+       pix->bytesperline = pix->width *
+               DIV_ROUND_UP(xlate->host_fmt->depth, 8);
+       pix->sizeimage = pix->height * pix->bytesperline;
+
+       /* camera has to see its format, but the user the original one */
+       pix->pixelformat = xlate->cam_fmt->fourcc;
+       /* limit to sensor capabilities */
+       ret = icd->ops->try_fmt(icd, f);
+       pix->pixelformat = xlate->host_fmt->fourcc;
+
+       field = pix->field;
+
+       if (field == V4L2_FIELD_ANY) {
+               pix->field = V4L2_FIELD_NONE;
+       } else if (field != V4L2_FIELD_NONE) {
+               dev_err(&icd->dev, "Field type %d unsupported.\n", field);
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+static int mx3_camera_reqbufs(struct soc_camera_file *icf,
+                             struct v4l2_requestbuffers *p)
+{
+       return 0;
+}
+
+static unsigned int mx3_camera_poll(struct file *file, poll_table *pt)
+{
+       struct soc_camera_file *icf = file->private_data;
+
+       return videobuf_poll_stream(file, &icf->vb_vidq, pt);
+}
+
+static int mx3_camera_querycap(struct soc_camera_host *ici,
+                              struct v4l2_capability *cap)
+{
+       /* cap->name is set by the firendly caller:-> */
+       strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card));
+       cap->version = KERNEL_VERSION(0, 2, 2);
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+       return 0;
+}
+
+static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx3_camera_dev *mx3_cam = ici->priv;
+       unsigned long bus_flags, camera_flags, common_flags;
+       u32 dw, sens_conf;
+       int ret = test_platform_param(mx3_cam, icd->buswidth, &bus_flags);
+       const struct soc_camera_format_xlate *xlate;
+
+       xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+       if (!xlate) {
+               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               return -EINVAL;
+       }
+
+       dev_dbg(&ici->dev, "requested bus width %d bit: %d\n",
+               icd->buswidth, ret);
+
+       if (ret < 0)
+               return ret;
+
+       camera_flags = icd->ops->query_bus_param(icd);
+
+       common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
+       if (!common_flags) {
+               dev_dbg(&ici->dev, "no common flags: camera %lx, host %lx\n",
+                       camera_flags, bus_flags);
+               return -EINVAL;
+       }
+
+       /* Make choices, based on platform preferences */
+       if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
+           (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
+               if (mx3_cam->platform_flags & MX3_CAMERA_HSP)
+                       common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
+               else
+                       common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
+       }
+
+       if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
+           (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
+               if (mx3_cam->platform_flags & MX3_CAMERA_VSP)
+                       common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
+               else
+                       common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
+       }
+
+       if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) &&
+           (common_flags & SOCAM_DATA_ACTIVE_LOW)) {
+               if (mx3_cam->platform_flags & MX3_CAMERA_DP)
+                       common_flags &= ~SOCAM_DATA_ACTIVE_HIGH;
+               else
+                       common_flags &= ~SOCAM_DATA_ACTIVE_LOW;
+       }
+
+       if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
+           (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
+               if (mx3_cam->platform_flags & MX3_CAMERA_PCP)
+                       common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
+               else
+                       common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
+       }
+
+       /* Make the camera work in widest common mode, we'll take care of
+        * the rest */
+       if (common_flags & SOCAM_DATAWIDTH_15)
+               common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) |
+                       SOCAM_DATAWIDTH_15;
+       else if (common_flags & SOCAM_DATAWIDTH_10)
+               common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) |
+                       SOCAM_DATAWIDTH_10;
+       else if (common_flags & SOCAM_DATAWIDTH_8)
+               common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) |
+                       SOCAM_DATAWIDTH_8;
+       else
+               common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) |
+                       SOCAM_DATAWIDTH_4;
+
+       ret = icd->ops->set_bus_param(icd, common_flags);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * So far only gated clock mode is supported. Add a line
+        *      (3 << CSI_SENS_CONF_SENS_PRTCL_SHIFT) |
+        * below and select the required mode when supporting other
+        * synchronisation protocols.
+        */
+       sens_conf = csi_reg_read(mx3_cam, CSI_SENS_CONF) &
+               ~((1 << CSI_SENS_CONF_VSYNC_POL_SHIFT) |
+                 (1 << CSI_SENS_CONF_HSYNC_POL_SHIFT) |
+                 (1 << CSI_SENS_CONF_DATA_POL_SHIFT) |
+                 (1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT) |
+                 (3 << CSI_SENS_CONF_DATA_FMT_SHIFT) |
+                 (3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT));
+
+       /* TODO: Support RGB and YUV formats */
+
+       /* This has been set in mx3_camera_activate(), but we clear it above */
+       sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER;
+
+       if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
+               sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT;
+       if (common_flags & SOCAM_HSYNC_ACTIVE_LOW)
+               sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT;
+       if (common_flags & SOCAM_VSYNC_ACTIVE_LOW)
+               sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT;
+       if (common_flags & SOCAM_DATA_ACTIVE_LOW)
+               sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT;
+
+       /* Just do what we're asked to do */
+       switch (xlate->host_fmt->depth) {
+       case 4:
+               dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+               break;
+       case 8:
+               dw = 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+               break;
+       case 10:
+               dw = 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+               break;
+       default:
+               /*
+                * Actually it can only be 15 now, default is just to silence
+                * compiler warnings
+                */
+       case 15:
+               dw = 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+       }
+
+       csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF);
+
+       dev_dbg(&ici->dev, "Set SENS_CONF to %x\n", sens_conf | dw);
+
+       return 0;
+}
+
+static struct soc_camera_host_ops mx3_soc_camera_host_ops = {
+       .owner          = THIS_MODULE,
+       .add            = mx3_camera_add_device,
+       .remove         = mx3_camera_remove_device,
+#ifdef CONFIG_PM
+       .suspend        = mx3_camera_suspend,
+       .resume         = mx3_camera_resume,
+#endif
+       .set_crop       = mx3_camera_set_crop,
+       .set_fmt        = mx3_camera_set_fmt,
+       .try_fmt        = mx3_camera_try_fmt,
+       .get_formats    = mx3_camera_get_formats,
+       .init_videobuf  = mx3_camera_init_videobuf,
+       .reqbufs        = mx3_camera_reqbufs,
+       .poll           = mx3_camera_poll,
+       .querycap       = mx3_camera_querycap,
+       .set_bus_param  = mx3_camera_set_bus_param,
+};
+
+static int mx3_camera_probe(struct platform_device *pdev)
+{
+       struct mx3_camera_dev *mx3_cam;
+       struct resource *res;
+       void __iomem *base;
+       int err = 0;
+       struct soc_camera_host *soc_host;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               err = -ENODEV;
+               goto egetres;
+       }
+
+       mx3_cam = vmalloc(sizeof(*mx3_cam));
+       if (!mx3_cam) {
+               dev_err(&pdev->dev, "Could not allocate mx3 camera object\n");
+               err = -ENOMEM;
+               goto ealloc;
+       }
+       memset(mx3_cam, 0, sizeof(*mx3_cam));
+
+       mx3_cam->clk = clk_get(&pdev->dev, "csi_clk");
+       if (IS_ERR(mx3_cam->clk)) {
+               err = PTR_ERR(mx3_cam->clk);
+               goto eclkget;
+       }
+
+       dev_set_drvdata(&pdev->dev, mx3_cam);
+
+       mx3_cam->pdata = pdev->dev.platform_data;
+       mx3_cam->platform_flags = mx3_cam->pdata->flags;
+       if (!(mx3_cam->platform_flags & (MX3_CAMERA_DATAWIDTH_4 |
+                       MX3_CAMERA_DATAWIDTH_8 | MX3_CAMERA_DATAWIDTH_10 |
+                       MX3_CAMERA_DATAWIDTH_15))) {
+               /* Platform hasn't set available data widths. This is bad.
+                * Warn and use a default. */
+               dev_warn(&pdev->dev, "WARNING! Platform hasn't set available "
+                        "data widths, using default 8 bit\n");
+               mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8;
+       }
+
+       mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000;
+       if (!mx3_cam->mclk) {
+               dev_warn(&pdev->dev,
+                        "mclk_10khz == 0! Please, fix your platform data. "
+                        "Using default 20MHz\n");
+               mx3_cam->mclk = 20000000;
+       }
+
+       /* list of video-buffers */
+       INIT_LIST_HEAD(&mx3_cam->capture);
+       spin_lock_init(&mx3_cam->lock);
+
+       base = ioremap(res->start, res->end - res->start + 1);
+       if (!base) {
+               err = -ENOMEM;
+               goto eioremap;
+       }
+
+       mx3_cam->base   = base;
+       mx3_cam->dev    = &pdev->dev;
+
+       soc_host                = &mx3_cam->soc_host;
+       soc_host->drv_name      = MX3_CAM_DRV_NAME;
+       soc_host->ops           = &mx3_soc_camera_host_ops;
+       soc_host->priv          = mx3_cam;
+       soc_host->dev.parent    = &pdev->dev;
+       soc_host->nr            = pdev->id;
+       err = soc_camera_host_register(soc_host);
+       if (err)
+               goto ecamhostreg;
+
+       /* IDMAC interface */
+       dmaengine_get();
+
+       return 0;
+
+ecamhostreg:
+       iounmap(base);
+eioremap:
+       clk_put(mx3_cam->clk);
+eclkget:
+       vfree(mx3_cam);
+ealloc:
+egetres:
+       return err;
+}
+
+static int __devexit mx3_camera_remove(struct platform_device *pdev)
+{
+       struct mx3_camera_dev *mx3_cam = platform_get_drvdata(pdev);
+
+       clk_put(mx3_cam->clk);
+
+       soc_camera_host_unregister(&mx3_cam->soc_host);
+
+       iounmap(mx3_cam->base);
+
+       /*
+        * The channel has either not been allocated,
+        * or should have been released
+        */
+       if (WARN_ON(mx3_cam->idmac_channel[0]))
+               dma_release_channel(&mx3_cam->idmac_channel[0]->dma_chan);
+
+       vfree(mx3_cam);
+
+       dmaengine_put();
+
+       dev_info(&pdev->dev, "i.MX3x Camera driver unloaded\n");
+
+       return 0;
+}
+
+static struct platform_driver mx3_camera_driver = {
+       .driver         = {
+               .name   = MX3_CAM_DRV_NAME,
+       },
+       .probe          = mx3_camera_probe,
+       .remove         = __exit_p(mx3_camera_remove),
+};
+
+
+static int __devinit mx3_camera_init(void)
+{
+       return platform_driver_register(&mx3_camera_driver);
+}
+
+static void __exit mx3_camera_exit(void)
+{
+       platform_driver_unregister(&mx3_camera_driver);
+}
+
+module_init(mx3_camera_init);
+module_exit(mx3_camera_exit);
+
+MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
+MODULE_LICENSE("GPL v2");
index e3cbe14c349a788288987200be077322e7ecf3d1..84aec62e84527675d8706596967fb2d14a8e7224 100644 (file)
 
 #include <media/saa7146_vv.h>
 #include <media/tuner.h>
-#include <linux/video_decoder.h>
 #include <media/v4l2-common.h>
 #include <media/saa7115.h>
 
 #include "mxb.h"
 #include "tea6415c.h"
 #include "tea6420.h"
-#include "tda9840.h"
 
-#define I2C_SAA7111 0x24
+#define        I2C_SAA5246A  0x11
+#define I2C_SAA7111A  0x24
+#define        I2C_TDA9840   0x42
+#define        I2C_TEA6415C  0x43
+#define        I2C_TEA6420_1 0x4c
+#define        I2C_TEA6420_2 0x4d
+#define        I2C_TUNER     0x60
 
 #define MXB_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0)
 
@@ -79,57 +83,35 @@ static struct {
 static int video_audio_connect[MXB_INPUTS] =
        { 0, 1, 3, 3 };
 
-/* these are the necessary input-output-pins for bringing one audio source
-(see above) to the CD-output */
-static struct tea6420_multiplex TEA6420_cd[MXB_AUDIOS+1][2] =
-               {
-               {{1,1,0},{1,1,0}},      /* Tuner */
-               {{5,1,0},{6,1,0}},      /* AUX 1 */
-               {{4,1,0},{6,1,0}},      /* AUX 2 */
-               {{3,1,0},{6,1,0}},      /* AUX 3 */
-               {{1,1,0},{3,1,0}},      /* Radio */
-               {{1,1,0},{2,1,0}},      /* CD-Rom */
-               {{6,1,0},{6,1,0}}       /* Mute */
-               };
-
-/* these are the necessary input-output-pins for bringing one audio source
-(see above) to the line-output */
-static struct tea6420_multiplex TEA6420_line[MXB_AUDIOS+1][2] =
-               {
-               {{2,3,0},{1,2,0}},
-               {{5,3,0},{6,2,0}},
-               {{4,3,0},{6,2,0}},
-               {{3,3,0},{6,2,0}},
-               {{2,3,0},{3,2,0}},
-               {{2,3,0},{2,2,0}},
-               {{6,3,0},{6,2,0}}       /* Mute */
-               };
+/* These are the necessary input-output-pins for bringing one audio source
+   (see above) to the CD-output. Note that gain is set to 0 in this table. */
+static struct v4l2_routing TEA6420_cd[MXB_AUDIOS + 1][2] = {
+       { { 1, 1 }, { 1, 1 } }, /* Tuner */
+       { { 5, 1 }, { 6, 1 } }, /* AUX 1 */
+       { { 4, 1 }, { 6, 1 } }, /* AUX 2 */
+       { { 3, 1 }, { 6, 1 } }, /* AUX 3 */
+       { { 1, 1 }, { 3, 1 } }, /* Radio */
+       { { 1, 1 }, { 2, 1 } }, /* CD-Rom */
+       { { 6, 1 }, { 6, 1 } }  /* Mute */
+};
+
+/* These are the necessary input-output-pins for bringing one audio source
+   (see above) to the line-output. Note that gain is set to 0 in this table. */
+static struct v4l2_routing TEA6420_line[MXB_AUDIOS + 1][2] = {
+       { { 2, 3 }, { 1, 2 } },
+       { { 5, 3 }, { 6, 2 } },
+       { { 4, 3 }, { 6, 2 } },
+       { { 3, 3 }, { 6, 2 } },
+       { { 2, 3 }, { 3, 2 } },
+       { { 2, 3 }, { 2, 2 } },
+       { { 6, 3 }, { 6, 2 } }  /* Mute */
+};
 
 #define MAXCONTROLS    1
 static struct v4l2_queryctrl mxb_controls[] = {
        { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 },
 };
 
-static struct saa7146_extension_ioctls ioctls[] = {
-       { VIDIOC_ENUMINPUT,     SAA7146_EXCLUSIVE },
-       { VIDIOC_G_INPUT,       SAA7146_EXCLUSIVE },
-       { VIDIOC_S_INPUT,       SAA7146_EXCLUSIVE },
-       { VIDIOC_QUERYCTRL,     SAA7146_BEFORE },
-       { VIDIOC_G_CTRL,        SAA7146_BEFORE },
-       { VIDIOC_S_CTRL,        SAA7146_BEFORE },
-       { VIDIOC_G_TUNER,       SAA7146_EXCLUSIVE },
-       { VIDIOC_S_TUNER,       SAA7146_EXCLUSIVE },
-       { VIDIOC_G_FREQUENCY,   SAA7146_EXCLUSIVE },
-       { VIDIOC_S_FREQUENCY,   SAA7146_EXCLUSIVE },
-       { VIDIOC_G_AUDIO,       SAA7146_EXCLUSIVE },
-       { VIDIOC_S_AUDIO,       SAA7146_EXCLUSIVE },
-       { VIDIOC_DBG_G_REGISTER,        SAA7146_EXCLUSIVE },
-       { VIDIOC_DBG_S_REGISTER,        SAA7146_EXCLUSIVE },
-       { MXB_S_AUDIO_CD,       SAA7146_EXCLUSIVE },    /* custom control */
-       { MXB_S_AUDIO_LINE,     SAA7146_EXCLUSIVE },    /* custom control */
-       { 0,                    0 }
-};
-
 struct mxb
 {
        struct video_device     *video_dev;
@@ -137,12 +119,12 @@ struct mxb
 
        struct i2c_adapter      i2c_adapter;
 
-       struct i2c_client       *saa7111a;
-       struct i2c_client       *tda9840;
-       struct i2c_client       *tea6415c;
-       struct i2c_client       *tuner;
-       struct i2c_client       *tea6420_1;
-       struct i2c_client       *tea6420_2;
+       struct v4l2_subdev      *saa7111a;
+       struct v4l2_subdev      *tda9840;
+       struct v4l2_subdev      *tea6415c;
+       struct v4l2_subdev      *tuner;
+       struct v4l2_subdev      *tea6420_1;
+       struct v4l2_subdev      *tea6420_2;
 
        int     cur_mode;       /* current audio mode (mono, stereo, ...) */
        int     cur_input;      /* current input */
@@ -150,84 +132,51 @@ struct mxb
        struct v4l2_frequency   cur_freq;       /* current frequency the tuner is tuned to */
 };
 
-static struct saa7146_extension extension;
-
-static int mxb_check_clients(struct device *dev, void *data)
-{
-       struct mxb *mxb = data;
-       struct i2c_client *client = i2c_verify_client(dev);
-
-       if (!client)
-               return 0;
-
-       if (I2C_ADDR_TEA6420_1 == client->addr)
-               mxb->tea6420_1 = client;
-       if (I2C_ADDR_TEA6420_2 == client->addr)
-               mxb->tea6420_2 = client;
-       if (I2C_TEA6415C_2 == client->addr)
-               mxb->tea6415c = client;
-       if (I2C_ADDR_TDA9840 == client->addr)
-               mxb->tda9840 = client;
-       if (I2C_SAA7111 == client->addr)
-               mxb->saa7111a = client;
-       if (0x60 == client->addr)
-               mxb->tuner = client;
+#define saa7111a_call(mxb, o, f, args...) \
+       v4l2_subdev_call(mxb->saa7111a, o, f, ##args)
+#define tea6420_1_call(mxb, o, f, args...) \
+       v4l2_subdev_call(mxb->tea6420_1, o, f, ##args)
+#define tea6420_2_call(mxb, o, f, args...) \
+       v4l2_subdev_call(mxb->tea6420_2, o, f, ##args)
+#define tda9840_call(mxb, o, f, args...) \
+       v4l2_subdev_call(mxb->tda9840, o, f, ##args)
+#define tea6415c_call(mxb, o, f, args...) \
+       v4l2_subdev_call(mxb->tea6415c, o, f, ##args)
+#define tuner_call(mxb, o, f, args...) \
+       v4l2_subdev_call(mxb->tuner, o, f, ##args)
+#define call_all(dev, o, f, args...) \
+       v4l2_device_call_until_err(&dev->v4l2_dev, 0, o, f, ##args)
 
-       return 0;
-}
+static struct saa7146_extension extension;
 
-static int mxb_probe(struct saa7146_devdev)
+static int mxb_probe(struct saa7146_dev *dev)
 {
-       struct mxb* mxb = NULL;
-       int result;
-
-       result = request_module("saa7115");
-       if (result < 0) {
-               printk("mxb: saa7111 i2c module not available.\n");
-               return -ENODEV;
-       }
-       result = request_module("tea6420");
-       if (result < 0) {
-               printk("mxb: tea6420 i2c module not available.\n");
-               return -ENODEV;
-       }
-       result = request_module("tea6415c");
-       if (result < 0) {
-               printk("mxb: tea6415c i2c module not available.\n");
-               return -ENODEV;
-       }
-       result = request_module("tda9840");
-       if (result < 0) {
-               printk("mxb: tda9840 i2c module not available.\n");
-               return -ENODEV;
-       }
-       result = request_module("tuner");
-       if (result < 0) {
-               printk("mxb: tuner i2c module not available.\n");
-               return -ENODEV;
-       }
+       struct mxb *mxb = NULL;
 
        mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
-       if( NULL == mxb ) {
+       if (mxb == NULL) {
                DEB_D(("not enough kernel memory.\n"));
                return -ENOMEM;
        }
 
-       mxb->i2c_adapter = (struct i2c_adapter) {
-               .class = I2C_CLASS_TV_ANALOG,
-       };
-
        snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num);
 
        saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
-       if(i2c_add_adapter(&mxb->i2c_adapter) < 0) {
+       if (i2c_add_adapter(&mxb->i2c_adapter) < 0) {
                DEB_S(("cannot register i2c-device. skipping.\n"));
                kfree(mxb);
                return -EFAULT;
        }
 
-       /* loop through all i2c-devices on the bus and look who is there */
-       device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients);
+       mxb->saa7111a = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "saa7115", "saa7111", I2C_SAA7111A);
+       mxb->tea6420_1 = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "tea6420", "tea6420", I2C_TEA6420_1);
+       mxb->tea6420_2 = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "tea6420", "tea6420", I2C_TEA6420_2);
+       mxb->tea6415c = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "tea6415c", "tea6415c", I2C_TEA6415C);
+       mxb->tda9840 = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "tda9840", "tda9840", I2C_TDA9840);
+       mxb->tuner = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "tuner", "tuner", I2C_TUNER);
+       if (v4l2_i2c_new_subdev(&mxb->i2c_adapter, "saa5246a", "saa5246a", I2C_SAA5246A)) {
+               printk(KERN_INFO "mxb: found teletext decoder\n");
+       }
 
        /* check if all devices are present */
        if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
@@ -315,47 +264,45 @@ static int mxb_init_done(struct saa7146_dev* dev)
        struct v4l2_routing route;
 
        int i = 0, err = 0;
-       struct tea6415c_multiplex vm;
 
        /* select video mode in saa7111a */
-       mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_S_STD, &std);
+       saa7111a_call(mxb, tuner, s_std, std);
 
        /* select tuner-output on saa7111a */
        i = 0;
        route.input = SAA7115_COMPOSITE0;
        route.output = SAA7111_FMT_CCIR | SAA7111_VBI_BYPASS;
-       mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+       saa7111a_call(mxb, video, s_routing, &route);
 
        /* select a tuner type */
        tun_setup.mode_mask = T_ANALOG_TV;
        tun_setup.addr = ADDR_UNSET;
        tun_setup.type = TUNER_PHILIPS_PAL;
-       mxb->tuner->driver->command(mxb->tuner, TUNER_SET_TYPE_ADDR, &tun_setup);
+       tuner_call(mxb, tuner, s_type_addr, &tun_setup);
        /* tune in some frequency on tuner */
        mxb->cur_freq.tuner = 0;
        mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
        mxb->cur_freq.frequency = freq;
-       mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY,
-                                       &mxb->cur_freq);
+       tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq);
 
        /* set a default video standard */
-       mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
+       tuner_call(mxb, tuner, s_std, std);
 
        /* mute audio on tea6420s */
-       mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_line[6][0]);
-       mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_line[6][1]);
-       mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_cd[6][0]);
-       mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_cd[6][1]);
+       tea6420_1_call(mxb, audio, s_routing, &TEA6420_line[6][0]);
+       tea6420_2_call(mxb, audio, s_routing, &TEA6420_line[6][1]);
+       tea6420_1_call(mxb, audio, s_routing, &TEA6420_line[6][0]);
+       tea6420_2_call(mxb, audio, s_routing, &TEA6420_line[6][1]);
 
-       /* switch to tuner-channel on tea6415c*/
-       vm.out = 17;
-       vm.in  = 3;
-       mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm);
+       /* switch to tuner-channel on tea6415c */
+       route.input = 3;
+       route.output = 17;
+       tea6415c_call(mxb, video, s_routing, &route);
 
-       /* select tuner-output on multicable on tea6415c*/
-       vm.in  = 3;
-       vm.out = 13;
-       mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm);
+       /* select tuner-output on multicable on tea6415c */
+       route.input = 3;
+       route.output = 13;
+       tea6415c_call(mxb, video, s_routing, &route);
 
        /* the rest for mxb */
        mxb->cur_input = 0;
@@ -424,395 +371,414 @@ void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
 }
 */
 
-static struct saa7146_ext_vv vv_data;
-
-/* this function only gets called when the probing was successful */
-static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
+static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
 {
-       struct mxb *mxb = (struct mxb *)dev->ext_priv;
-
-       DEB_EE(("dev:%p\n", dev));
-
-       /* checking for i2c-devices can be omitted here, because we
-          already did this in "mxb_vl42_probe" */
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       int i;
 
-       saa7146_vv_init(dev, &vv_data);
-       if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
-               ERR(("cannot register capture v4l2 device. skipping.\n"));
-               return -1;
+       for (i = MAXCONTROLS - 1; i >= 0; i--) {
+               if (mxb_controls[i].id == qc->id) {
+                       *qc = mxb_controls[i];
+                       DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
+                       return 0;
+               }
        }
+       return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc);
+}
 
-       /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
-       if (MXB_BOARD_CAN_DO_VBI(dev)) {
-               if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
-                       ERR(("cannot register vbi v4l2 device. skipping.\n"));
-               }
+static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct mxb *mxb = (struct mxb *)dev->ext_priv;
+       int i;
+
+       for (i = MAXCONTROLS - 1; i >= 0; i--) {
+               if (mxb_controls[i].id == vc->id)
+                       break;
        }
 
-       i2c_use_client(mxb->tea6420_1);
-       i2c_use_client(mxb->tea6420_2);
-       i2c_use_client(mxb->tea6415c);
-       i2c_use_client(mxb->tda9840);
-       i2c_use_client(mxb->saa7111a);
-       i2c_use_client(mxb->tuner);
+       if (i < 0)
+               return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc);
 
-       printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);
+       if (vc->id == V4L2_CID_AUDIO_MUTE) {
+               vc->value = mxb->cur_mute;
+               DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
+               return 0;
+       }
 
-       mxb_num++;
-       mxb_init_done(dev);
+       DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
        return 0;
 }
 
-static int mxb_detach(struct saa7146_dev *dev)
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
 {
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
        struct mxb *mxb = (struct mxb *)dev->ext_priv;
+       int i = 0;
 
-       DEB_EE(("dev:%p\n", dev));
-
-       i2c_release_client(mxb->tea6420_1);
-       i2c_release_client(mxb->tea6420_2);
-       i2c_release_client(mxb->tea6415c);
-       i2c_release_client(mxb->tda9840);
-       i2c_release_client(mxb->saa7111a);
-       i2c_release_client(mxb->tuner);
-
-       saa7146_unregister_device(&mxb->video_dev,dev);
-       if (MXB_BOARD_CAN_DO_VBI(dev))
-               saa7146_unregister_device(&mxb->vbi_dev, dev);
-       saa7146_vv_release(dev);
-
-       mxb_num--;
+       for (i = MAXCONTROLS - 1; i >= 0; i--) {
+               if (mxb_controls[i].id == vc->id)
+                       break;
+       }
 
-       i2c_del_adapter(&mxb->i2c_adapter);
-       kfree(mxb);
+       if (i < 0)
+               return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc);
+
+       if (vc->id == V4L2_CID_AUDIO_MUTE) {
+               mxb->cur_mute = vc->value;
+               if (!vc->value) {
+                       /* switch the audio-source */
+                       tea6420_1_call(mxb, audio, s_routing,
+                                       &TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
+                       tea6420_2_call(mxb, audio, s_routing,
+                                       &TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
+               } else {
+                       tea6420_1_call(mxb, audio, s_routing,
+                                       &TEA6420_line[6][0]);
+                       tea6420_2_call(mxb, audio, s_routing,
+                                       &TEA6420_line[6][1]);
+               }
+               DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));
+       }
+       return 0;
+}
 
+static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+       DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
+       if (i->index < 0 || i->index >= MXB_INPUTS)
+               return -EINVAL;
+       memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
        return 0;
 }
 
-static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
 {
-       struct saa7146_dev *dev = fh->dev;
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
        struct mxb *mxb = (struct mxb *)dev->ext_priv;
-       struct saa7146_vv *vv = dev->vv_data;
+       *i = mxb->cur_input;
 
-       switch(cmd) {
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *i = arg;
+       DEB_EE(("VIDIOC_G_INPUT %d.\n", *i));
+       return 0;
+}
 
-               DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
-               if (i->index < 0 || i->index >= MXB_INPUTS)
-                       return -EINVAL;
-               memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
-               return 0;
-       }
-       /* the saa7146 provides some controls (brightness, contrast, saturation)
-          which gets registered *after* this function. because of this we have
-          to return with a value != 0 even if the function succeded.. */
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *qc = arg;
-               int i;
-
-               for (i = MAXCONTROLS - 1; i >= 0; i--) {
-                       if (mxb_controls[i].id == qc->id) {
-                               *qc = mxb_controls[i];
-                               DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
-                               return 0;
-                       }
-               }
-               return -EAGAIN;
-       }
-       case VIDIOC_G_CTRL:
-       {
-               struct v4l2_control *vc = arg;
-               int i;
+static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct mxb *mxb = (struct mxb *)dev->ext_priv;
+       struct v4l2_routing route;
+       int i = 0;
 
-               for (i = MAXCONTROLS - 1; i >= 0; i--) {
-                       if (mxb_controls[i].id == vc->id)
-                               break;
-               }
+       DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
 
-               if (i < 0)
-                       return -EAGAIN;
+       if (input < 0 || input >= MXB_INPUTS)
+               return -EINVAL;
 
-               if (vc->id == V4L2_CID_AUDIO_MUTE) {
-                       vc->value = mxb->cur_mute;
-                       DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
-                       return 0;
-               }
+       mxb->cur_input = input;
 
-               DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
-               return 0;
-       }
+       saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source,
+                       input_port_selection[input].hps_sync);
 
-       case VIDIOC_S_CTRL:
-       {
-               struct v4l2_control *vc = arg;
-               int i = 0;
+       /* prepare switching of tea6415c and saa7111a;
+          have a look at the 'background'-file for further informations  */
+       switch (input) {
+       case TUNER:
+               i = SAA7115_COMPOSITE0;
+               route.input = 3;
+               route.output = 17;
 
-               for (i = MAXCONTROLS - 1; i >= 0; i--) {
-                       if (mxb_controls[i].id == vc->id)
-                               break;
+               if (tea6415c_call(mxb, video, s_routing, &route)) {
+                       printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n");
+                       return -EFAULT;
                }
+               /* connect tuner-output always to multicable */
+               route.input = 3;
+               route.output = 13;
+               break;
+       case AUX3_YC:
+               /* nothing to be done here. aux3_yc is
+                  directly connected to the saa711a */
+               i = SAA7115_SVIDEO1;
+               break;
+       case AUX3:
+               /* nothing to be done here. aux3 is
+                  directly connected to the saa711a */
+               i = SAA7115_COMPOSITE1;
+               break;
+       case AUX1:
+               i = SAA7115_COMPOSITE0;
+               route.input = 1;
+               route.output = 17;
+               break;
+       }
 
-               if (i < 0)
-                       return -EAGAIN;
-
-               if (vc->id == V4L2_CID_AUDIO_MUTE) {
-                       mxb->cur_mute = vc->value;
-                       if (!vc->value) {
-                               /* switch the audio-source */
-                               mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
-                                               &TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
-                               mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
-                                               &TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
-                       } else {
-                               mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
-                                               &TEA6420_line[6][0]);
-                               mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
-                                               &TEA6420_line[6][1]);
-                       }
-                       DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));
+       /* switch video in tea6415c only if necessary */
+       switch (input) {
+       case TUNER:
+       case AUX1:
+               if (tea6415c_call(mxb, video, s_routing, &route)) {
+                       printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n");
+                       return -EFAULT;
                }
-               return 0;
+               break;
+       default:
+               break;
        }
-       case VIDIOC_G_INPUT:
-       {
-               int *input = (int *)arg;
-               *input = mxb->cur_input;
 
-               DEB_EE(("VIDIOC_G_INPUT %d.\n", *input));
-               return 0;
+       /* switch video in saa7111a */
+       route.input = i;
+       route.output = 0;
+       if (saa7111a_call(mxb, video, s_routing, &route))
+               printk(KERN_ERR "VIDIOC_S_INPUT: could not address saa7111a #1.\n");
+
+       /* switch the audio-source only if necessary */
+       if (0 == mxb->cur_mute) {
+               tea6420_1_call(mxb, audio, s_routing,
+                               &TEA6420_line[video_audio_connect[input]][0]);
+               tea6420_2_call(mxb, audio, s_routing,
+                               &TEA6420_line[video_audio_connect[input]][1]);
        }
-       case VIDIOC_S_INPUT:
-       {
-               int input = *(int *)arg;
-               struct tea6415c_multiplex vm;
-               struct v4l2_routing route;
-               int i = 0;
 
-               DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
+       return 0;
+}
 
-               if (input < 0 || input >= MXB_INPUTS)
-                       return -EINVAL;
+static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
-               mxb->cur_input = input;
+       if (t->index) {
+               DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
+               return -EINVAL;
+       }
 
-               saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source,
-                               input_port_selection[input].hps_sync);
+       DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
 
-               /* prepare switching of tea6415c and saa7111a;
-                  have a look at the 'background'-file for further informations  */
-               switch (input) {
-               case TUNER:
-                       i = SAA7115_COMPOSITE0;
-                       vm.in  = 3;
-                       vm.out = 17;
+       memset(t, 0, sizeof(*t));
+       strlcpy(t->name, "TV Tuner", sizeof(t->name));
+       t->type = V4L2_TUNER_ANALOG_TV;
+       t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
+                       V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+       t->audmode = mxb->cur_mode;
+       return call_all(dev, tuner, g_tuner, t);
+}
 
-                       if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
-                               printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n");
-                               return -EFAULT;
-                       }
-                       /* connect tuner-output always to multicable */
-                       vm.in  = 3;
-                       vm.out = 13;
-                       break;
-               case AUX3_YC:
-                       /* nothing to be done here. aux3_yc is
-                          directly connected to the saa711a */
-                       i = SAA7115_SVIDEO1;
-                       break;
-               case AUX3:
-                       /* nothing to be done here. aux3 is
-                          directly connected to the saa711a */
-                       i = SAA7115_COMPOSITE1;
-                       break;
-               case AUX1:
-                       i = SAA7115_COMPOSITE0;
-                       vm.in  = 1;
-                       vm.out = 17;
-                       break;
-               }
+static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
-               /* switch video in tea6415c only if necessary */
-               switch (input) {
-               case TUNER:
-               case AUX1:
-                       if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
-                               printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n");
-                               return -EFAULT;
-                       }
-                       break;
-               default:
-                       break;
-               }
+       if (t->index) {
+               DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n", t->index));
+               return -EINVAL;
+       }
 
-               /* switch video in saa7111a */
-               route.input = i;
-               route.output = 0;
-               if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route))
-                       printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
-
-               /* switch the audio-source only if necessary */
-               if( 0 == mxb->cur_mute ) {
-                       mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
-                                       &TEA6420_line[video_audio_connect[input]][0]);
-                       mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
-                                      &TEA6420_line[video_audio_connect[input]][1]);
-               }
+       mxb->cur_mode = t->audmode;
+       return call_all(dev, tuner, s_tuner, t);
+}
 
-               return 0;
+static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct mxb *mxb = (struct mxb *)dev->ext_priv;
+
+       if (mxb->cur_input) {
+               DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
+                                       mxb->cur_input));
+               return -EINVAL;
        }
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
 
-               if (t->index) {
-                       DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
-                       return -EINVAL;
-               }
+       *f = mxb->cur_freq;
 
-               DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
+       DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
+       return 0;
+}
 
-               memset(t, 0, sizeof(*t));
-               i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
+static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct mxb *mxb = (struct mxb *)dev->ext_priv;
+       struct saa7146_vv *vv = dev->vv_data;
 
-               strlcpy(t->name, "TV Tuner", sizeof(t->name));
-               t->type = V4L2_TUNER_ANALOG_TV;
-               t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | \
-                       V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
-               t->audmode = mxb->cur_mode;
-               return 0;
-       }
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
+       if (f->tuner)
+               return -EINVAL;
 
-               if (t->index) {
-                       DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
-                       return -EINVAL;
-               }
+       if (V4L2_TUNER_ANALOG_TV != f->type)
+               return -EINVAL;
 
-               mxb->cur_mode = t->audmode;
-               i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
-               return 0;
+       if (mxb->cur_input) {
+               DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input));
+               return -EINVAL;
        }
-       case VIDIOC_G_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
 
-               if (mxb->cur_input) {
-                       DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
-                                               mxb->cur_input));
-                       return -EINVAL;
-               }
+       mxb->cur_freq = *f;
+       DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
 
-               *f = mxb->cur_freq;
+       /* tune in desired frequency */
+       tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq);
 
-               DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
-               return 0;
+       /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
+       spin_lock(&dev->slock);
+       vv->vbi_fieldcount = 0;
+       spin_unlock(&dev->slock);
+
+       return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct mxb *mxb = (struct mxb *)dev->ext_priv;
+
+       if (a->index < 0 || a->index > MXB_INPUTS) {
+               DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
+               return -EINVAL;
        }
-       case VIDIOC_S_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
 
-               if (f->tuner)
-                       return -EINVAL;
+       DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index));
+       memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
+       return 0;
+}
 
-               if (V4L2_TUNER_ANALOG_TV != f->type)
-                       return -EINVAL;
+static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+       DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index));
+       return 0;
+}
 
-               if (mxb->cur_input) {
-                       DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input));
-                       return -EINVAL;
-               }
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
 
-               mxb->cur_freq = *f;
-               DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
+       return call_all(dev, core, g_register, reg);
+}
 
-               /* tune in desired frequency */
-               mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
+static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
 
-               /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
-               spin_lock(&dev->slock);
-               vv->vbi_fieldcount = 0;
-               spin_unlock(&dev->slock);
+       return call_all(dev, core, s_register, reg);
+}
+#endif
 
-               return 0;
-       }
+static long vidioc_default(struct file *file, void *fh, int cmd, void *arg)
+{
+       struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+       struct mxb *mxb = (struct mxb *)dev->ext_priv;
+
+       switch (cmd) {
        case MXB_S_AUDIO_CD:
        {
-               int i = *(int*)arg;
+               int i = *(int *)arg;
 
                if (i < 0 || i >= MXB_AUDIOS) {
-                       DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
+                       DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n", i));
                        return -EINVAL;
                }
 
-               DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));
+               DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n", i));
 
-               mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
-               mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]);
+               tea6420_1_call(mxb, audio, s_routing, &TEA6420_cd[i][0]);
+               tea6420_2_call(mxb, audio, s_routing, &TEA6420_cd[i][1]);
 
                return 0;
        }
        case MXB_S_AUDIO_LINE:
        {
-               int i = *(int*)arg;
+               int i = *(int *)arg;
 
                if (i < 0 || i >= MXB_AUDIOS) {
-                       DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
+                       DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n", i));
                        return -EINVAL;
                }
 
-               DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));
-               mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
-               mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);
+               DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n", i));
+               tea6420_1_call(mxb, audio, s_routing, &TEA6420_line[i][0]);
+               tea6420_2_call(mxb, audio, s_routing, &TEA6420_line[i][1]);
 
                return 0;
        }
-       case VIDIOC_G_AUDIO:
-       {
-               struct v4l2_audio *a = arg;
+       default:
+/*
+               DEB2(printk("does not handle this ioctl.\n"));
+*/
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
 
-               if (a->index < 0 || a->index > MXB_INPUTS) {
-                       DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
-                       return -EINVAL;
-               }
+static struct saa7146_ext_vv vv_data;
 
-               DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index));
-               memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
+/* this function only gets called when the probing was successful */
+static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
+{
+       struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
-               return 0;
-       }
-       case VIDIOC_S_AUDIO:
-       {
-               struct v4l2_audio *a = arg;
+       DEB_EE(("dev:%p\n", dev));
 
-               DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index));
-               return 0;
-       }
+       /* checking for i2c-devices can be omitted here, because we
+          already did this in "mxb_vl42_probe" */
+
+       saa7146_vv_init(dev, &vv_data);
+       vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
+       vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
+       vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
+       vv_data.ops.vidioc_enum_input = vidioc_enum_input;
+       vv_data.ops.vidioc_g_input = vidioc_g_input;
+       vv_data.ops.vidioc_s_input = vidioc_s_input;
+       vv_data.ops.vidioc_g_tuner = vidioc_g_tuner;
+       vv_data.ops.vidioc_s_tuner = vidioc_s_tuner;
+       vv_data.ops.vidioc_g_frequency = vidioc_g_frequency;
+       vv_data.ops.vidioc_s_frequency = vidioc_s_frequency;
+       vv_data.ops.vidioc_g_audio = vidioc_g_audio;
+       vv_data.ops.vidioc_s_audio = vidioc_s_audio;
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_DBG_S_REGISTER:
-       case VIDIOC_DBG_G_REGISTER:
-               i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
-               return 0;
+       vv_data.ops.vidioc_g_register = vidioc_g_register;
+       vv_data.ops.vidioc_s_register = vidioc_s_register;
 #endif
-       default:
-/*
-               DEB2(printk("does not handle this ioctl.\n"));
-*/
-               return -ENOIOCTLCMD;
+       vv_data.ops.vidioc_default = vidioc_default;
+       if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
+               ERR(("cannot register capture v4l2 device. skipping.\n"));
+               return -1;
        }
+
+       /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
+       if (MXB_BOARD_CAN_DO_VBI(dev)) {
+               if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
+                       ERR(("cannot register vbi v4l2 device. skipping.\n"));
+               }
+       }
+
+       printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);
+
+       mxb_num++;
+       mxb_init_done(dev);
+       return 0;
+}
+
+static int mxb_detach(struct saa7146_dev *dev)
+{
+       struct mxb *mxb = (struct mxb *)dev->ext_priv;
+
+       DEB_EE(("dev:%p\n", dev));
+
+       saa7146_unregister_device(&mxb->video_dev,dev);
+       if (MXB_BOARD_CAN_DO_VBI(dev))
+               saa7146_unregister_device(&mxb->vbi_dev, dev);
+       saa7146_vv_release(dev);
+
+       mxb_num--;
+
+       i2c_del_adapter(&mxb->i2c_adapter);
+       kfree(mxb);
+
        return 0;
 }
 
 static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
 {
        struct mxb *mxb = (struct mxb *)dev->ext_priv;
-       int zero = 0;
-       int one = 1;
 
        if (V4L2_STD_PAL_I == standard->id) {
                v4l2_std_id std = V4L2_STD_PAL_I;
@@ -821,8 +787,8 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa
                /* set the 7146 gpio register -- I don't know what this does exactly */
                saa7146_write(dev, GPIO_CTRL, 0x00404050);
                /* unset the 7111 gpio register -- I don't know what this does exactly */
-               mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &zero);
-               mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
+               saa7111a_call(mxb, core, s_gpio, 0);
+               tuner_call(mxb, tuner, s_std, std);
        } else {
                v4l2_std_id std = V4L2_STD_PAL_BG;
 
@@ -830,8 +796,8 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa
                /* set the 7146 gpio register -- I don't know what this does exactly */
                saa7146_write(dev, GPIO_CTRL, 0x00404050);
                /* set the 7111 gpio register -- I don't know what this does exactly */
-               mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &one);
-               mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
+               saa7111a_call(mxb, core, s_gpio, 1);
+               tuner_call(mxb, tuner, s_std, std);
        }
        return 0;
 }
@@ -885,8 +851,6 @@ static struct saa7146_ext_vv vv_data = {
        .stds           = &standard[0],
        .num_stds       = sizeof(standard)/sizeof(struct saa7146_standard),
        .std_callback   = &std_callback,
-       .ioctls         = &ioctls[0],
-       .ioctl          = mxb_ioctl,
 };
 
 static struct saa7146_extension extension = {
index 805faaea64498a97061f3db0f85ac454e4525201..5fc4ac0d88f042beb8e4cddf8a8180f90a777266 100644 (file)
@@ -1285,9 +1285,6 @@ static int vidioc_g_parm(struct file *file, void *fh,
        struct omap24xxcam_device *cam = ofh->cam;
        int rval;
 
-       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
        mutex_lock(&cam->mutex);
        rval = vidioc_int_g_parm(cam->sdev, a);
        mutex_unlock(&cam->mutex);
@@ -1303,9 +1300,6 @@ static int vidioc_s_parm(struct file *file, void *fh,
        struct v4l2_streamparm old_streamparm;
        int rval;
 
-       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
        mutex_lock(&cam->mutex);
        if (cam->streaming) {
                rval = -EBUSY;
@@ -1665,7 +1659,6 @@ static int omap24xxcam_device_register(struct v4l2_int_device *s)
        vfd->parent = cam->dev;
 
        strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
-       vfd->vfl_type            = VID_TYPE_CAPTURE | VID_TYPE_CHROMAKEY;
        vfd->fops                = &omap24xxcam_fops;
        vfd->minor               = -1;
        vfd->ioctl_ops           = &omap24xxcam_ioctl_fops;
index 05c14a29375ae6f921899b0ce28db21f218c39c0..0e2184ec994efa0ee4b39ed55031e139ecb6de97 100644 (file)
  */
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/slab.h>
+#include <linux/i2c.h>
 #include <linux/delay.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <linux/i2c.h>
+#include <media/v4l2-i2c-drv.h>
 
 
 MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
 MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
 MODULE_LICENSE("GPL");
 
+static int debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
 /*
  * Basic window sizes.  These probably belong somewhere more globally
  * useful.
@@ -189,11 +193,16 @@ MODULE_LICENSE("GPL");
  */
 struct ov7670_format_struct;  /* coming later */
 struct ov7670_info {
+       struct v4l2_subdev sd;
        struct ov7670_format_struct *fmt;  /* Current format */
        unsigned char sat;              /* Saturation value */
        int hue;                        /* Hue value */
 };
 
+static inline struct ov7670_info *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct ov7670_info, sd);
+}
 
 
 
@@ -400,24 +409,27 @@ static struct regval_list ov7670_fmt_raw[] = {
  * Low-level register I/O.
  */
 
-static int ov7670_read(struct i2c_client *c, unsigned char reg,
+static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
                unsigned char *value)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int ret;
 
-       ret = i2c_smbus_read_byte_data(c, reg);
+       ret = i2c_smbus_read_byte_data(client, reg);
        if (ret >= 0) {
-               *value = (unsigned char) ret;
+               *value = (unsigned char)ret;
                ret = 0;
        }
        return ret;
 }
 
 
-static int ov7670_write(struct i2c_client *c, unsigned char reg,
+static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg,
                unsigned char value)
 {
-       int ret = i2c_smbus_write_byte_data(c, reg, value);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = i2c_smbus_write_byte_data(client, reg, value);
+
        if (reg == REG_COM7 && (value & COM7_RESET))
                msleep(2);  /* Wait for reset to run */
        return ret;
@@ -427,10 +439,10 @@ static int ov7670_write(struct i2c_client *c, unsigned char reg,
 /*
  * Write a list of register settings; ff/ff stops the process.
  */
-static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals)
+static int ov7670_write_array(struct v4l2_subdev *sd, struct regval_list *vals)
 {
        while (vals->reg_num != 0xff || vals->value != 0xff) {
-               int ret = ov7670_write(c, vals->reg_num, vals->value);
+               int ret = ov7670_write(sd, vals->reg_num, vals->value);
                if (ret < 0)
                        return ret;
                vals++;
@@ -442,34 +454,35 @@ static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals)
 /*
  * Stuff that knows about the sensor.
  */
-static void ov7670_reset(struct i2c_client *client)
+static int ov7670_reset(struct v4l2_subdev *sd, u32 val)
 {
-       ov7670_write(client, REG_COM7, COM7_RESET);
+       ov7670_write(sd, REG_COM7, COM7_RESET);
        msleep(1);
+       return 0;
 }
 
 
-static int ov7670_init(struct i2c_client *client)
+static int ov7670_init(struct v4l2_subdev *sd, u32 val)
 {
-       return ov7670_write_array(client, ov7670_default_regs);
+       return ov7670_write_array(sd, ov7670_default_regs);
 }
 
 
 
-static int ov7670_detect(struct i2c_client *client)
+static int ov7670_detect(struct v4l2_subdev *sd)
 {
        unsigned char v;
        int ret;
 
-       ret = ov7670_init(client);
+       ret = ov7670_init(sd, 0);
        if (ret < 0)
                return ret;
-       ret = ov7670_read(client, REG_MIDH, &v);
+       ret = ov7670_read(sd, REG_MIDH, &v);
        if (ret < 0)
                return ret;
        if (v != 0x7f) /* OV manuf. id. */
                return -ENODEV;
-       ret = ov7670_read(client, REG_MIDL, &v);
+       ret = ov7670_read(sd, REG_MIDL, &v);
        if (ret < 0)
                return ret;
        if (v != 0xa2)
@@ -477,12 +490,12 @@ static int ov7670_detect(struct i2c_client *client)
        /*
         * OK, we know we have an OmniVision chip...but which one?
         */
-       ret = ov7670_read(client, REG_PID, &v);
+       ret = ov7670_read(sd, REG_PID, &v);
        if (ret < 0)
                return ret;
        if (v != 0x76)  /* PID + VER = 0x76 / 0x73 */
                return -ENODEV;
-       ret = ov7670_read(client, REG_VER, &v);
+       ret = ov7670_read(sd, REG_VER, &v);
        if (ret < 0)
                return ret;
        if (v != 0x73)  /* PID + VER = 0x76 / 0x73 */
@@ -627,7 +640,7 @@ static struct ov7670_win_size {
 /*
  * Store a set of start/stop values into the camera.
  */
-static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop,
+static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop,
                int vstart, int vstop)
 {
        int ret;
@@ -637,26 +650,26 @@ static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop,
  * hstart are in href[2:0], bottom 3 of hstop in href[5:3].  There is
  * a mystery "edge offset" value in the top two bits of href.
  */
-       ret =  ov7670_write(client, REG_HSTART, (hstart >> 3) & 0xff);
-       ret += ov7670_write(client, REG_HSTOP, (hstop >> 3) & 0xff);
-       ret += ov7670_read(client, REG_HREF, &v);
+       ret =  ov7670_write(sd, REG_HSTART, (hstart >> 3) & 0xff);
+       ret += ov7670_write(sd, REG_HSTOP, (hstop >> 3) & 0xff);
+       ret += ov7670_read(sd, REG_HREF, &v);
        v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7);
        msleep(10);
-       ret += ov7670_write(client, REG_HREF, v);
+       ret += ov7670_write(sd, REG_HREF, v);
 /*
  * Vertical: similar arrangement, but only 10 bits.
  */
-       ret += ov7670_write(client, REG_VSTART, (vstart >> 2) & 0xff);
-       ret += ov7670_write(client, REG_VSTOP, (vstop >> 2) & 0xff);
-       ret += ov7670_read(client, REG_VREF, &v);
+       ret += ov7670_write(sd, REG_VSTART, (vstart >> 2) & 0xff);
+       ret += ov7670_write(sd, REG_VSTOP, (vstop >> 2) & 0xff);
+       ret += ov7670_read(sd, REG_VREF, &v);
        v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3);
        msleep(10);
-       ret += ov7670_write(client, REG_VREF, v);
+       ret += ov7670_write(sd, REG_VREF, v);
        return ret;
 }
 
 
-static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt)
+static int ov7670_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
 {
        struct ov7670_format_struct *ofmt;
 
@@ -671,7 +684,8 @@ static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt)
 }
 
 
-static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt,
+static int ov7670_try_fmt_internal(struct v4l2_subdev *sd,
+               struct v4l2_format *fmt,
                struct ov7670_format_struct **ret_fmt,
                struct ov7670_win_size **ret_wsize)
 {
@@ -715,18 +729,23 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt,
        return 0;
 }
 
+static int ov7670_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+       return ov7670_try_fmt_internal(sd, fmt, NULL, NULL);
+}
+
 /*
  * Set a format.
  */
-static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
+static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
 {
        int ret;
        struct ov7670_format_struct *ovfmt;
        struct ov7670_win_size *wsize;
-       struct ov7670_info *info = i2c_get_clientdata(c);
-       unsigned char com7, clkrc;
+       struct ov7670_info *info = to_state(sd);
+       unsigned char com7, clkrc = 0;
 
-       ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize);
+       ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize);
        if (ret)
                return ret;
        /*
@@ -735,7 +754,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
         * the colors.
         */
        if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) {
-               ret = ov7670_read(c, REG_CLKRC, &clkrc);
+               ret = ov7670_read(sd, REG_CLKRC, &clkrc);
                if (ret)
                        return ret;
        }
@@ -747,20 +766,20 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
         */
        com7 = ovfmt->regs[0].value;
        com7 |= wsize->com7_bit;
-       ov7670_write(c, REG_COM7, com7);
+       ov7670_write(sd, REG_COM7, com7);
        /*
         * Now write the rest of the array.  Also store start/stops
         */
-       ov7670_write_array(c, ovfmt->regs + 1);
-       ov7670_set_hw(c, wsize->hstart, wsize->hstop, wsize->vstart,
+       ov7670_write_array(sd, ovfmt->regs + 1);
+       ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart,
                        wsize->vstop);
        ret = 0;
        if (wsize->regs)
-               ret = ov7670_write_array(c, wsize->regs);
+               ret = ov7670_write_array(sd, wsize->regs);
        info->fmt = ovfmt;
 
        if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 && ret == 0)
-               ret = ov7670_write(c, REG_CLKRC, clkrc);
+               ret = ov7670_write(sd, REG_CLKRC, clkrc);
        return ret;
 }
 
@@ -768,7 +787,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
  * Implement G/S_PARM.  There is a "high quality" mode we could try
  * to do someday; for now, we just do the frame rate tweak.
  */
-static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
+static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
 {
        struct v4l2_captureparm *cp = &parms->parm.capture;
        unsigned char clkrc;
@@ -776,7 +795,7 @@ static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
 
        if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
-       ret = ov7670_read(c, REG_CLKRC, &clkrc);
+       ret = ov7670_read(sd, REG_CLKRC, &clkrc);
        if (ret < 0)
                return ret;
        memset(cp, 0, sizeof(struct v4l2_captureparm));
@@ -788,7 +807,7 @@ static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
        return 0;
 }
 
-static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
+static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
 {
        struct v4l2_captureparm *cp = &parms->parm.capture;
        struct v4l2_fract *tpf = &cp->timeperframe;
@@ -802,7 +821,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
        /*
         * CLKRC has a reserved bit, so let's preserve it.
         */
-       ret = ov7670_read(c, REG_CLKRC, &clkrc);
+       ret = ov7670_read(sd, REG_CLKRC, &clkrc);
        if (ret < 0)
                return ret;
        if (tpf->numerator == 0 || tpf->denominator == 0)
@@ -816,7 +835,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
        clkrc = (clkrc & 0x80) | div;
        tpf->numerator = 1;
        tpf->denominator = OV7670_FRAME_RATE/div;
-       return ov7670_write(c, REG_CLKRC, clkrc);
+       return ov7670_write(sd, REG_CLKRC, clkrc);
 }
 
 
@@ -829,7 +848,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
 
 
 
-static int ov7670_store_cmatrix(struct i2c_client *client,
+static int ov7670_store_cmatrix(struct v4l2_subdev *sd,
                int matrix[CMATRIX_LEN])
 {
        int i, ret;
@@ -839,7 +858,7 @@ static int ov7670_store_cmatrix(struct i2c_client *client,
         * Weird crap seems to exist in the upper part of
         * the sign bits register, so let's preserve it.
         */
-       ret = ov7670_read(client, REG_CMATRIX_SIGN, &signbits);
+       ret = ov7670_read(sd, REG_CMATRIX_SIGN, &signbits);
        signbits &= 0xc0;
 
        for (i = 0; i < CMATRIX_LEN; i++) {
@@ -858,9 +877,9 @@ static int ov7670_store_cmatrix(struct i2c_client *client,
                        else
                                raw = matrix[i] & 0xff;
                }
-               ret += ov7670_write(client, REG_CMATRIX_BASE + i, raw);
+               ret += ov7670_write(sd, REG_CMATRIX_BASE + i, raw);
        }
-       ret += ov7670_write(client, REG_CMATRIX_SIGN, signbits);
+       ret += ov7670_write(sd, REG_CMATRIX_SIGN, signbits);
        return ret;
 }
 
@@ -943,29 +962,29 @@ static void ov7670_calc_cmatrix(struct ov7670_info *info,
 
 
 
-static int ov7670_t_sat(struct i2c_client *client, int value)
+static int ov7670_s_sat(struct v4l2_subdev *sd, int value)
 {
-       struct ov7670_info *info = i2c_get_clientdata(client);
+       struct ov7670_info *info = to_state(sd);
        int matrix[CMATRIX_LEN];
        int ret;
 
        info->sat = value;
        ov7670_calc_cmatrix(info, matrix);
-       ret = ov7670_store_cmatrix(client, matrix);
+       ret = ov7670_store_cmatrix(sd, matrix);
        return ret;
 }
 
-static int ov7670_q_sat(struct i2c_client *client, __s32 *value)
+static int ov7670_g_sat(struct v4l2_subdev *sd, __s32 *value)
 {
-       struct ov7670_info *info = i2c_get_clientdata(client);
+       struct ov7670_info *info = to_state(sd);
 
        *value = info->sat;
        return 0;
 }
 
-static int ov7670_t_hue(struct i2c_client *client, int value)
+static int ov7670_s_hue(struct v4l2_subdev *sd, int value)
 {
-       struct ov7670_info *info = i2c_get_clientdata(client);
+       struct ov7670_info *info = to_state(sd);
        int matrix[CMATRIX_LEN];
        int ret;
 
@@ -973,14 +992,14 @@ static int ov7670_t_hue(struct i2c_client *client, int value)
                return -EINVAL;
        info->hue = value;
        ov7670_calc_cmatrix(info, matrix);
-       ret = ov7670_store_cmatrix(client, matrix);
+       ret = ov7670_store_cmatrix(sd, matrix);
        return ret;
 }
 
 
-static int ov7670_q_hue(struct i2c_client *client, __s32 *value)
+static int ov7670_g_hue(struct v4l2_subdev *sd, __s32 *value)
 {
-       struct ov7670_info *info = i2c_get_clientdata(client);
+       struct ov7670_info *info = to_state(sd);
 
        *value = info->hue;
        return 0;
@@ -994,8 +1013,7 @@ static unsigned char ov7670_sm_to_abs(unsigned char v)
 {
        if ((v & 0x80) == 0)
                return v + 128;
-       else
-               return 128 - (v & 0x7f);
+       return 128 - (v & 0x7f);
 }
 
 
@@ -1003,369 +1021,275 @@ static unsigned char ov7670_abs_to_sm(unsigned char v)
 {
        if (v > 127)
                return v & 0x7f;
-       else
-               return (128 - v) | 0x80;
+       return (128 - v) | 0x80;
 }
 
-static int ov7670_t_brightness(struct i2c_client *client, int value)
+static int ov7670_s_brightness(struct v4l2_subdev *sd, int value)
 {
        unsigned char com8 = 0, v;
        int ret;
 
-       ov7670_read(client, REG_COM8, &com8);
+       ov7670_read(sd, REG_COM8, &com8);
        com8 &= ~COM8_AEC;
-       ov7670_write(client, REG_COM8, com8);
+       ov7670_write(sd, REG_COM8, com8);
        v = ov7670_abs_to_sm(value);
-       ret = ov7670_write(client, REG_BRIGHT, v);
+       ret = ov7670_write(sd, REG_BRIGHT, v);
        return ret;
 }
 
-static int ov7670_q_brightness(struct i2c_client *client, __s32 *value)
+static int ov7670_g_brightness(struct v4l2_subdev *sd, __s32 *value)
 {
        unsigned char v = 0;
-       int ret = ov7670_read(client, REG_BRIGHT, &v);
+       int ret = ov7670_read(sd, REG_BRIGHT, &v);
 
        *value = ov7670_sm_to_abs(v);
        return ret;
 }
 
-static int ov7670_t_contrast(struct i2c_client *client, int value)
+static int ov7670_s_contrast(struct v4l2_subdev *sd, int value)
 {
-       return ov7670_write(client, REG_CONTRAS, (unsigned char) value);
+       return ov7670_write(sd, REG_CONTRAS, (unsigned char) value);
 }
 
-static int ov7670_q_contrast(struct i2c_client *client, __s32 *value)
+static int ov7670_g_contrast(struct v4l2_subdev *sd, __s32 *value)
 {
        unsigned char v = 0;
-       int ret = ov7670_read(client, REG_CONTRAS, &v);
+       int ret = ov7670_read(sd, REG_CONTRAS, &v);
 
        *value = v;
        return ret;
 }
 
-static int ov7670_q_hflip(struct i2c_client *client, __s32 *value)
+static int ov7670_g_hflip(struct v4l2_subdev *sd, __s32 *value)
 {
        int ret;
        unsigned char v = 0;
 
-       ret = ov7670_read(client, REG_MVFP, &v);
+       ret = ov7670_read(sd, REG_MVFP, &v);
        *value = (v & MVFP_MIRROR) == MVFP_MIRROR;
        return ret;
 }
 
 
-static int ov7670_t_hflip(struct i2c_client *client, int value)
+static int ov7670_s_hflip(struct v4l2_subdev *sd, int value)
 {
        unsigned char v = 0;
        int ret;
 
-       ret = ov7670_read(client, REG_MVFP, &v);
+       ret = ov7670_read(sd, REG_MVFP, &v);
        if (value)
                v |= MVFP_MIRROR;
        else
                v &= ~MVFP_MIRROR;
        msleep(10);  /* FIXME */
-       ret += ov7670_write(client, REG_MVFP, v);
+       ret += ov7670_write(sd, REG_MVFP, v);
        return ret;
 }
 
 
 
-static int ov7670_q_vflip(struct i2c_client *client, __s32 *value)
+static int ov7670_g_vflip(struct v4l2_subdev *sd, __s32 *value)
 {
        int ret;
        unsigned char v = 0;
 
-       ret = ov7670_read(client, REG_MVFP, &v);
+       ret = ov7670_read(sd, REG_MVFP, &v);
        *value = (v & MVFP_FLIP) == MVFP_FLIP;
        return ret;
 }
 
 
-static int ov7670_t_vflip(struct i2c_client *client, int value)
+static int ov7670_s_vflip(struct v4l2_subdev *sd, int value)
 {
        unsigned char v = 0;
        int ret;
 
-       ret = ov7670_read(client, REG_MVFP, &v);
+       ret = ov7670_read(sd, REG_MVFP, &v);
        if (value)
                v |= MVFP_FLIP;
        else
                v &= ~MVFP_FLIP;
        msleep(10);  /* FIXME */
-       ret += ov7670_write(client, REG_MVFP, v);
+       ret += ov7670_write(sd, REG_MVFP, v);
        return ret;
 }
 
-
-static struct ov7670_control {
-       struct v4l2_queryctrl qc;
-       int (*query)(struct i2c_client *c, __s32 *value);
-       int (*tweak)(struct i2c_client *c, int value);
-} ov7670_controls[] =
+static int ov7670_queryctrl(struct v4l2_subdev *sd,
+               struct v4l2_queryctrl *qc)
 {
-       {
-               .qc = {
-                       .id = V4L2_CID_BRIGHTNESS,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "Brightness",
-                       .minimum = 0,
-                       .maximum = 255,
-                       .step = 1,
-                       .default_value = 0x80,
-                       .flags = V4L2_CTRL_FLAG_SLIDER
-               },
-               .tweak = ov7670_t_brightness,
-               .query = ov7670_q_brightness,
-       },
-       {
-               .qc = {
-                       .id = V4L2_CID_CONTRAST,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "Contrast",
-                       .minimum = 0,
-                       .maximum = 127,
-                       .step = 1,
-                       .default_value = 0x40,   /* XXX ov7670 spec */
-                       .flags = V4L2_CTRL_FLAG_SLIDER
-               },
-               .tweak = ov7670_t_contrast,
-               .query = ov7670_q_contrast,
-       },
-       {
-               .qc = {
-                       .id = V4L2_CID_SATURATION,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "Saturation",
-                       .minimum = 0,
-                       .maximum = 256,
-                       .step = 1,
-                       .default_value = 0x80,
-                       .flags = V4L2_CTRL_FLAG_SLIDER
-               },
-               .tweak = ov7670_t_sat,
-               .query = ov7670_q_sat,
-       },
-       {
-               .qc = {
-                       .id = V4L2_CID_HUE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "HUE",
-                       .minimum = -180,
-                       .maximum = 180,
-                       .step = 5,
-                       .default_value = 0,
-                       .flags = V4L2_CTRL_FLAG_SLIDER
-               },
-               .tweak = ov7670_t_hue,
-               .query = ov7670_q_hue,
-       },
-       {
-               .qc = {
-                       .id = V4L2_CID_VFLIP,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "Vertical flip",
-                       .minimum = 0,
-                       .maximum = 1,
-                       .step = 1,
-                       .default_value = 0,
-               },
-               .tweak = ov7670_t_vflip,
-               .query = ov7670_q_vflip,
-       },
-       {
-               .qc = {
-                       .id = V4L2_CID_HFLIP,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "Horizontal mirror",
-                       .minimum = 0,
-                       .maximum = 1,
-                       .step = 1,
-                       .default_value = 0,
-               },
-               .tweak = ov7670_t_hflip,
-               .query = ov7670_q_hflip,
-       },
-};
-#define N_CONTROLS (ARRAY_SIZE(ov7670_controls))
+       /* Fill in min, max, step and default value for these controls. */
+       switch (qc->id) {
+       case V4L2_CID_BRIGHTNESS:
+               return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
+       case V4L2_CID_CONTRAST:
+               return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
+       case V4L2_CID_VFLIP:
+       case V4L2_CID_HFLIP:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+       case V4L2_CID_SATURATION:
+               return v4l2_ctrl_query_fill(qc, 0, 256, 1, 128);
+       case V4L2_CID_HUE:
+               return v4l2_ctrl_query_fill(qc, -180, 180, 5, 0);
+       }
+       return -EINVAL;
+}
 
-static struct ov7670_control *ov7670_find_control(__u32 id)
+static int ov7670_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       int i;
-
-       for (i = 0; i < N_CONTROLS; i++)
-               if (ov7670_controls[i].qc.id == id)
-                       return ov7670_controls + i;
-       return NULL;
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               return ov7670_g_brightness(sd, &ctrl->value);
+       case V4L2_CID_CONTRAST:
+               return ov7670_g_contrast(sd, &ctrl->value);
+       case V4L2_CID_SATURATION:
+               return ov7670_g_sat(sd, &ctrl->value);
+       case V4L2_CID_HUE:
+               return ov7670_g_hue(sd, &ctrl->value);
+       case V4L2_CID_VFLIP:
+               return ov7670_g_vflip(sd, &ctrl->value);
+       case V4L2_CID_HFLIP:
+               return ov7670_g_hflip(sd, &ctrl->value);
+       }
+       return -EINVAL;
 }
 
+static int ov7670_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               return ov7670_s_brightness(sd, ctrl->value);
+       case V4L2_CID_CONTRAST:
+               return ov7670_s_contrast(sd, ctrl->value);
+       case V4L2_CID_SATURATION:
+               return ov7670_s_sat(sd, ctrl->value);
+       case V4L2_CID_HUE:
+               return ov7670_s_hue(sd, ctrl->value);
+       case V4L2_CID_VFLIP:
+               return ov7670_s_vflip(sd, ctrl->value);
+       case V4L2_CID_HFLIP:
+               return ov7670_s_hflip(sd, ctrl->value);
+       }
+       return -EINVAL;
+}
 
-static int ov7670_queryctrl(struct i2c_client *client,
-               struct v4l2_queryctrl *qc)
+static int ov7670_g_chip_ident(struct v4l2_subdev *sd,
+               struct v4l2_dbg_chip_ident *chip)
 {
-       struct ov7670_control *ctrl = ov7670_find_control(qc->id);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (ctrl == NULL)
-               return -EINVAL;
-       *qc = ctrl->qc;
-       return 0;
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV7670, 0);
 }
 
-static int ov7670_g_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
-       struct ov7670_control *octrl = ov7670_find_control(ctrl->id);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       unsigned char val = 0;
        int ret;
 
-       if (octrl == NULL)
+       if (!v4l2_chip_match_i2c_client(client, &reg->match))
                return -EINVAL;
-       ret = octrl->query(client, &ctrl->value);
-       if (ret >= 0)
-               return 0;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       ret = ov7670_read(sd, reg->reg & 0xff, &val);
+       reg->val = val;
+       reg->size = 1;
        return ret;
 }
 
-static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int ov7670_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
-       struct ov7670_control *octrl = ov7670_find_control(ctrl->id);
-       int ret;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (octrl == NULL)
+       if (!v4l2_chip_match_i2c_client(client, &reg->match))
                return -EINVAL;
-       ret =  octrl->tweak(client, ctrl->value);
-       if (ret >= 0)
-               return 0;
-       return ret;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       ov7670_write(sd, reg->reg & 0xff, reg->val & 0xff);
+       return 0;
 }
+#endif
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops ov7670_core_ops = {
+       .g_chip_ident = ov7670_g_chip_ident,
+       .g_ctrl = ov7670_g_ctrl,
+       .s_ctrl = ov7670_s_ctrl,
+       .queryctrl = ov7670_queryctrl,
+       .reset = ov7670_reset,
+       .init = ov7670_init,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = ov7670_g_register,
+       .s_register = ov7670_s_register,
+#endif
+};
 
+static const struct v4l2_subdev_video_ops ov7670_video_ops = {
+       .enum_fmt = ov7670_enum_fmt,
+       .try_fmt = ov7670_try_fmt,
+       .s_fmt = ov7670_s_fmt,
+       .s_parm = ov7670_s_parm,
+       .g_parm = ov7670_g_parm,
+};
 
+static const struct v4l2_subdev_ops ov7670_ops = {
+       .core = &ov7670_core_ops,
+       .video = &ov7670_video_ops,
+};
 
+/* ----------------------------------------------------------------------- */
 
-
-
-/*
- * Basic i2c stuff.
- */
-static struct i2c_driver ov7670_driver;
-
-static int ov7670_attach(struct i2c_adapter *adapter)
+static int ov7670_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
-       int ret;
-       struct i2c_client *client;
+       struct v4l2_subdev *sd;
        struct ov7670_info *info;
+       int ret;
 
-       /*
-        * For now: only deal with adapters we recognize.
-        */
-       if (adapter->id != I2C_HW_SMBUS_CAFE)
-               return -ENODEV;
-
-       client = kzalloc(sizeof (struct i2c_client), GFP_KERNEL);
-       if (! client)
+       info = kzalloc(sizeof(struct ov7670_info), GFP_KERNEL);
+       if (info == NULL)
                return -ENOMEM;
-       client->adapter = adapter;
-       client->addr = OV7670_I2C_ADDR;
-       client->driver = &ov7670_driver,
-       strcpy(client->name, "OV7670");
-       /*
-        * Set up our info structure.
-        */
-       info = kzalloc(sizeof (struct ov7670_info), GFP_KERNEL);
-       if (! info) {
-               ret = -ENOMEM;
-               goto out_free;
+       sd = &info->sd;
+       v4l2_i2c_subdev_init(sd, client, &ov7670_ops);
+
+       /* Make sure it's an ov7670 */
+       ret = ov7670_detect(sd);
+       if (ret) {
+               v4l_dbg(1, debug, client,
+                       "chip found @ 0x%x (%s) is not an ov7670 chip.\n",
+                       client->addr << 1, client->adapter->name);
+               kfree(info);
+               return ret;
        }
+       v4l_info(client, "chip found @ 0x%02x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+
        info->fmt = &ov7670_formats[0];
        info->sat = 128;        /* Review this */
-       i2c_set_clientdata(client, info);
 
-       /*
-        * Make sure it's an ov7670
-        */
-       ret = ov7670_detect(client);
-       if (ret)
-               goto out_free_info;
-       ret = i2c_attach_client(client);
-       if (ret)
-               goto out_free_info;
        return 0;
-
-  out_free_info:
-       kfree(info);
-  out_free:
-       kfree(client);
-       return ret;
 }
 
 
-static int ov7670_detach(struct i2c_client *client)
+static int ov7670_remove(struct i2c_client *client)
 {
-       i2c_detach_client(client);
-       kfree(i2c_get_clientdata(client));
-       kfree(client);
-       return 0;
-}
-
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
-static int ov7670_command(struct i2c_client *client, unsigned int cmd,
-               void *arg)
-{
-       switch (cmd) {
-       case VIDIOC_DBG_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_OV7670, 0);
-
-       case VIDIOC_INT_RESET:
-               ov7670_reset(client);
-               return 0;
-
-       case VIDIOC_INT_INIT:
-               return ov7670_init(client);
-
-       case VIDIOC_ENUM_FMT:
-               return ov7670_enum_fmt(client, (struct v4l2_fmtdesc *) arg);
-       case VIDIOC_TRY_FMT:
-               return ov7670_try_fmt(client, (struct v4l2_format *) arg, NULL, NULL);
-       case VIDIOC_S_FMT:
-               return ov7670_s_fmt(client, (struct v4l2_format *) arg);
-       case VIDIOC_QUERYCTRL:
-               return ov7670_queryctrl(client, (struct v4l2_queryctrl *) arg);
-       case VIDIOC_S_CTRL:
-               return ov7670_s_ctrl(client, (struct v4l2_control *) arg);
-       case VIDIOC_G_CTRL:
-               return ov7670_g_ctrl(client, (struct v4l2_control *) arg);
-       case VIDIOC_S_PARM:
-               return ov7670_s_parm(client, (struct v4l2_streamparm *) arg);
-       case VIDIOC_G_PARM:
-               return ov7670_g_parm(client, (struct v4l2_streamparm *) arg);
-       }
-       return -EINVAL;
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
+       return 0;
 }
 
-
-
-static struct i2c_driver ov7670_driver = {
-       .driver = {
-               .name = "ov7670",
-       },
-       .id             = I2C_DRIVERID_OV7670,
-       .attach_adapter = ov7670_attach,
-       .detach_client  = ov7670_detach,
-       .command        = ov7670_command,
+static const struct i2c_device_id ov7670_id[] = {
+       { "ov7670", 0 },
+       { }
 };
+MODULE_DEVICE_TABLE(i2c, ov7670_id);
 
-
-/*
- * Module initialization
- */
-static int __init ov7670_mod_init(void)
-{
-       printk(KERN_NOTICE "OmniVision ov7670 sensor driver, at your service\n");
-       return i2c_add_driver(&ov7670_driver);
-}
-
-static void __exit ov7670_mod_exit(void)
-{
-       i2c_del_driver(&ov7670_driver);
-}
-
-module_init(ov7670_mod_init);
-module_exit(ov7670_mod_exit);
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "ov7670",
+       .probe = ov7670_probe,
+       .remove = ov7670_remove,
+       .id_table = ov7670_id,
+};
index 3c9e0ba974e9ec57bb819b234f18cb05c53ecc4d..84b0fc1bb23712874205063d4eff38eb63629de5 100644 (file)
 #define OCAP_4x         0x03   /* 4x */
 
 /* COM3 */
-#define SWAP_MASK       0x38
+#define SWAP_MASK       (SWAP_RGB | SWAP_YUV | SWAP_ML)
+#define IMG_MASK        (VFLIP_IMG | HFLIP_IMG)
 
-#define VFIMG_ON_OFF    0x80   /* Vertical flip image ON/OFF selection */
-#define HMIMG_ON_OFF    0x40   /* Horizontal mirror image ON/OFF selection */
+#define VFLIP_IMG       0x80   /* Vertical flip image ON/OFF selection */
+#define HFLIP_IMG       0x40   /* Horizontal mirror image ON/OFF selection */
 #define SWAP_RGB        0x20   /* Swap B/R  output sequence in RGB mode */
 #define SWAP_YUV        0x10   /* Swap Y/UV output sequence in YUV mode */
 #define SWAP_ML         0x08   /* Swap output MSB/LSB */
 #define SLCT_QVGA       0x40   /*   1 : QVGA */
 #define ITU656_ON_OFF   0x20   /* ITU656 protocol ON/OFF selection */
                                /* RGB output format control */
+#define FMT_MASK        0x0c   /*      Mask of color format */
 #define FMT_GBR422      0x00   /*      00 : GBR 4:2:2 */
 #define FMT_RGB565      0x04   /*      01 : RGB 565 */
 #define FMT_RGB555      0x08   /*      10 : RGB 555 */
 #define FMT_RGB444      0x0c   /* 11 : RGB 444 */
                                /* Output format control */
+#define OFMT_MASK       0x03    /*      Mask of output format */
 #define OFMT_YUV        0x00   /*      00 : YUV */
 #define OFMT_P_BRAW     0x01   /*      01 : Processed Bayer RAW */
 #define OFMT_RGB        0x02   /*      10 : RGB */
 #define GAIN_2x         0x00   /*    000 :   2x */
 #define GAIN_4x         0x10   /*    001 :   4x */
 #define GAIN_8x         0x20   /*    010 :   8x */
-#define GAIN_16x        0x30   /* 011 :  16x */
+#define GAIN_16x        0x30   /*    011 :  16x */
 #define GAIN_32x        0x40   /*    100 :  32x */
 #define GAIN_64x        0x50   /* 101 :  64x */
 #define GAIN_128x       0x60   /* 110 : 128x */
 #define VOSZ_VGA        0xF0
 #define VOSZ_QVGA       0x78
 
-/*
- * bit configure (32 bit)
- * this is used in struct ov772x_color_format :: option
- */
-#define OP_UV       0x00000001
-#define OP_SWAP_RGB 0x00000002
-
 /*
  * ID
  */
@@ -380,8 +376,9 @@ struct regval_list {
 struct ov772x_color_format {
        char                     *name;
        __u32                     fourcc;
-       const struct regval_list *regs;
-       unsigned int              option;
+       u8                        dsp3;
+       u8                        com3;
+       u8                        com7;
 };
 
 struct ov772x_win_size {
@@ -399,38 +396,12 @@ struct ov772x_priv {
        const struct ov772x_color_format *fmt;
        const struct ov772x_win_size     *win;
        int                               model;
+       unsigned int                      flag_vflip:1;
+       unsigned int                      flag_hflip:1;
 };
 
 #define ENDMARKER { 0xff, 0xff }
 
-/*
- * register setting for color format
- */
-static const struct regval_list ov772x_RGB555_regs[] = {
-       { COM3, 0x00 },
-       { COM7, FMT_RGB555 | OFMT_RGB },
-       ENDMARKER,
-};
-
-static const struct regval_list ov772x_RGB565_regs[] = {
-       { COM3, 0x00 },
-       { COM7, FMT_RGB565 | OFMT_RGB },
-       ENDMARKER,
-};
-
-static const struct regval_list ov772x_YYUV_regs[] = {
-       { COM3, SWAP_YUV },
-       { COM7, OFMT_YUV },
-       ENDMARKER,
-};
-
-static const struct regval_list ov772x_UVYY_regs[] = {
-       { COM3, 0x00 },
-       { COM7, OFMT_YUV },
-       ENDMARKER,
-};
-
-
 /*
  * register setting for window size
  */
@@ -500,38 +471,48 @@ static const struct soc_camera_data_format ov772x_fmt_lists[] = {
 /*
  * color format list
  */
-#define T_YUYV 0
 static const struct ov772x_color_format ov772x_cfmts[] = {
-       [T_YUYV] = {
+       {
                SETFOURCC(YUYV),
-               .regs   = ov772x_YYUV_regs,
+               .dsp3   = 0x0,
+               .com3   = SWAP_YUV,
+               .com7   = OFMT_YUV,
        },
        {
                SETFOURCC(YVYU),
-               .regs   = ov772x_YYUV_regs,
-               .option = OP_UV,
+               .dsp3   = UV_ON,
+               .com3   = SWAP_YUV,
+               .com7   = OFMT_YUV,
        },
        {
                SETFOURCC(UYVY),
-               .regs   = ov772x_UVYY_regs,
+               .dsp3   = 0x0,
+               .com3   = 0x0,
+               .com7   = OFMT_YUV,
        },
        {
                SETFOURCC(RGB555),
-               .regs   = ov772x_RGB555_regs,
-               .option = OP_SWAP_RGB,
+               .dsp3   = 0x0,
+               .com3   = SWAP_RGB,
+               .com7   = FMT_RGB555 | OFMT_RGB,
        },
        {
                SETFOURCC(RGB555X),
-               .regs   = ov772x_RGB555_regs,
+               .dsp3   = 0x0,
+               .com3   = 0x0,
+               .com7   = FMT_RGB555 | OFMT_RGB,
        },
        {
                SETFOURCC(RGB565),
-               .regs   = ov772x_RGB565_regs,
-               .option = OP_SWAP_RGB,
+               .dsp3   = 0x0,
+               .com3   = SWAP_RGB,
+               .com7   = FMT_RGB565 | OFMT_RGB,
        },
        {
                SETFOURCC(RGB565X),
-               .regs   = ov772x_RGB565_regs,
+               .dsp3   = 0x0,
+               .com3   = 0x0,
+               .com7   = FMT_RGB565 | OFMT_RGB,
        },
 };
 
@@ -562,6 +543,27 @@ static const struct ov772x_win_size ov772x_win_qvga = {
        .regs     = ov772x_qvga_regs,
 };
 
+static const struct v4l2_queryctrl ov772x_controls[] = {
+       {
+               .id             = V4L2_CID_VFLIP,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Flip Vertically",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
+       },
+       {
+               .id             = V4L2_CID_HFLIP,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Flip Horizontally",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
+       },
+};
+
 
 /*
  * general function
@@ -587,8 +589,11 @@ static int ov772x_mask_set(struct i2c_client *client,
                                          u8  set)
 {
        s32 val = i2c_smbus_read_byte_data(client, command);
+       if (val < 0)
+               return val;
+
        val &= ~mask;
-       val |=  set;
+       val |= set & mask;
 
        return i2c_smbus_write_byte_data(client, command, val);
 }
@@ -635,74 +640,24 @@ static int ov772x_release(struct soc_camera_device *icd)
 static int ov772x_start_capture(struct soc_camera_device *icd)
 {
        struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
-       int                 ret;
-
-       if (!priv->win)
-               priv->win = &ov772x_win_vga;
-       if (!priv->fmt)
-               priv->fmt = &ov772x_cfmts[T_YUYV];
-
-       /*
-        * reset hardware
-        */
-       ov772x_reset(priv->client);
 
-       /*
-        * set color format
-        */
-       ret = ov772x_write_array(priv->client, priv->fmt->regs);
-       if (ret < 0)
-               goto start_end;
-
-       /*
-        * set size format
-        */
-       ret = ov772x_write_array(priv->client, priv->win->regs);
-       if (ret < 0)
-               goto start_end;
-
-       /*
-        * set COM7 bit ( QVGA or VGA )
-        */
-       ret = ov772x_mask_set(priv->client,
-                             COM7, SLCT_MASK, priv->win->com7_bit);
-       if (ret < 0)
-               goto start_end;
-
-       /*
-        * set UV setting
-        */
-       if (priv->fmt->option & OP_UV) {
-               ret = ov772x_mask_set(priv->client,
-                                     DSP_CTRL3, UV_MASK, UV_ON);
-               if (ret < 0)
-                       goto start_end;
+       if (!priv->win || !priv->fmt) {
+               dev_err(&icd->dev, "norm or win select error\n");
+               return -EPERM;
        }
 
-       /*
-        * set SWAP setting
-        */
-       if (priv->fmt->option & OP_SWAP_RGB) {
-               ret = ov772x_mask_set(priv->client,
-                                     COM3, SWAP_MASK, SWAP_RGB);
-               if (ret < 0)
-                       goto start_end;
-       }
+       ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, 0);
 
        dev_dbg(&icd->dev,
                 "format %s, win %s\n", priv->fmt->name, priv->win->name);
 
-start_end:
-       priv->fmt = NULL;
-       priv->win = NULL;
-
-       return ret;
+       return 0;
 }
 
 static int ov772x_stop_capture(struct soc_camera_device *icd)
 {
        struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
-       ov772x_reset(priv->client);
+       ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
        return 0;
 }
 
@@ -718,11 +673,54 @@ static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
        struct soc_camera_link *icl = priv->client->dev.platform_data;
        unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
                SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
-               priv->info->buswidth;
+               SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth;
 
        return soc_camera_apply_sensor_flags(icl, flags);
 }
 
+static int ov772x_get_control(struct soc_camera_device *icd,
+                             struct v4l2_control *ctrl)
+{
+       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               ctrl->value = priv->flag_vflip;
+               break;
+       case V4L2_CID_HFLIP:
+               ctrl->value = priv->flag_hflip;
+               break;
+       }
+       return 0;
+}
+
+static int ov772x_set_control(struct soc_camera_device *icd,
+                             struct v4l2_control *ctrl)
+{
+       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+       int ret = 0;
+       u8 val;
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               val = ctrl->value ? VFLIP_IMG : 0x00;
+               priv->flag_vflip = ctrl->value;
+               if (priv->info->flags & OV772X_FLAG_VFLIP)
+                       val ^= VFLIP_IMG;
+               ret = ov772x_mask_set(priv->client, COM3, VFLIP_IMG, val);
+               break;
+       case V4L2_CID_HFLIP:
+               val = ctrl->value ? HFLIP_IMG : 0x00;
+               priv->flag_hflip = ctrl->value;
+               if (priv->info->flags & OV772X_FLAG_HFLIP)
+                       val ^= HFLIP_IMG;
+               ret = ov772x_mask_set(priv->client, COM3, HFLIP_IMG, val);
+               break;
+       }
+
+       return ret;
+}
+
 static int ov772x_get_chip_id(struct soc_camera_device *icd,
                              struct v4l2_dbg_chip_ident   *id)
 {
@@ -787,13 +785,11 @@ ov772x_select_win(u32 width, u32 height)
        return win;
 }
 
-
-static int ov772x_set_fmt(struct soc_camera_device *icd,
-                         __u32                     pixfmt,
-                         struct v4l2_rect         *rect)
+static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
+                            u32 pixfmt)
 {
-       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
        int ret = -EINVAL;
+       u8  val;
        int i;
 
        /*
@@ -803,19 +799,101 @@ static int ov772x_set_fmt(struct soc_camera_device *icd,
        for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) {
                if (pixfmt == ov772x_cfmts[i].fourcc) {
                        priv->fmt = ov772x_cfmts + i;
-                       ret = 0;
                        break;
                }
        }
+       if (!priv->fmt)
+               goto ov772x_set_fmt_error;
 
        /*
         * select win
         */
-       priv->win = ov772x_select_win(rect->width, rect->height);
+       priv->win = ov772x_select_win(width, height);
+
+       /*
+        * reset hardware
+        */
+       ov772x_reset(priv->client);
+
+       /*
+        * set size format
+        */
+       ret = ov772x_write_array(priv->client, priv->win->regs);
+       if (ret < 0)
+               goto ov772x_set_fmt_error;
+
+       /*
+        * set DSP_CTRL3
+        */
+       val = priv->fmt->dsp3;
+       if (val) {
+               ret = ov772x_mask_set(priv->client,
+                                     DSP_CTRL3, UV_MASK, val);
+               if (ret < 0)
+                       goto ov772x_set_fmt_error;
+       }
+
+       /*
+        * set COM3
+        */
+       val = priv->fmt->com3;
+       if (priv->info->flags & OV772X_FLAG_VFLIP)
+               val |= VFLIP_IMG;
+       if (priv->info->flags & OV772X_FLAG_HFLIP)
+               val |= HFLIP_IMG;
+       if (priv->flag_vflip)
+               val ^= VFLIP_IMG;
+       if (priv->flag_hflip)
+               val ^= HFLIP_IMG;
+
+       ret = ov772x_mask_set(priv->client,
+                             COM3, SWAP_MASK | IMG_MASK, val);
+       if (ret < 0)
+               goto ov772x_set_fmt_error;
+
+       /*
+        * set COM7
+        */
+       val = priv->win->com7_bit | priv->fmt->com7;
+       ret = ov772x_mask_set(priv->client,
+                             COM7, (SLCT_MASK | FMT_MASK | OFMT_MASK),
+                             val);
+       if (ret < 0)
+               goto ov772x_set_fmt_error;
+
+       return ret;
+
+ov772x_set_fmt_error:
+
+       ov772x_reset(priv->client);
+       priv->win = NULL;
+       priv->fmt = NULL;
 
        return ret;
 }
 
+static int ov772x_set_crop(struct soc_camera_device *icd,
+                          struct v4l2_rect *rect)
+{
+       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+
+       if (!priv->fmt)
+               return -EINVAL;
+
+       return ov772x_set_params(priv, rect->width, rect->height,
+                                priv->fmt->fourcc);
+}
+
+static int ov772x_set_fmt(struct soc_camera_device *icd,
+                         struct v4l2_format *f)
+{
+       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+
+       return ov772x_set_params(priv, pix->width, pix->height,
+                                pix->pixelformat);
+}
+
 static int ov772x_try_fmt(struct soc_camera_device *icd,
                          struct v4l2_format       *f)
 {
@@ -889,7 +967,6 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
                 i2c_smbus_read_byte_data(priv->client, MIDH),
                 i2c_smbus_read_byte_data(priv->client, MIDL));
 
-
        return soc_camera_video_start(icd);
 }
 
@@ -906,10 +983,15 @@ static struct soc_camera_ops ov772x_ops = {
        .release                = ov772x_release,
        .start_capture          = ov772x_start_capture,
        .stop_capture           = ov772x_stop_capture,
+       .set_crop               = ov772x_set_crop,
        .set_fmt                = ov772x_set_fmt,
        .try_fmt                = ov772x_try_fmt,
        .set_bus_param          = ov772x_set_bus_param,
        .query_bus_param        = ov772x_query_bus_param,
+       .controls               = ov772x_controls,
+       .num_controls           = ARRAY_SIZE(ov772x_controls),
+       .get_control            = ov772x_get_control,
+       .set_control            = ov772x_set_control,
        .get_chip_id            = ov772x_get_chip_id,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .get_register           = ov772x_get_register,
index c841f4e4fbe4903d45f1877e982c9aaebda7e73e..d573d84289988e0140cb08b7f40f0f7ef7b70b4b 100644 (file)
@@ -15,6 +15,9 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-i2c-drv.h>
 #include "ovcamchip_priv.h"
 
 #define DRIVER_VERSION "v2.27 for Linux 2.6"
@@ -44,6 +47,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
+
 /* Registers common to all chips, that are needed for detection */
 #define GENERIC_REG_ID_HIGH       0x1C /* manufacturer ID MSB */
 #define GENERIC_REG_ID_LOW        0x1D /* manufacturer ID LSB */
@@ -61,10 +65,6 @@ static char *chip_names[NUM_CC_TYPES] = {
        [CC_OV6630AF]   = "OV6630AF",
 };
 
-/* Forward declarations */
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
 /* ----------------------------------------------------------------------- */
 
 int ov_write_regvals(struct i2c_client *c, struct ovcamchip_regvals *rvals)
@@ -253,112 +253,36 @@ static int ovcamchip_detect(struct i2c_client *c)
 
        /* Test for 7xx0 */
        PDEBUG(3, "Testing for 0V7xx0");
-       c->addr = OV7xx0_SID;
-       if (init_camchip(c) < 0) {
-               /* Test for 6xx0 */
-               PDEBUG(3, "Testing for 0V6xx0");
-               c->addr = OV6xx0_SID;
-               if (init_camchip(c) < 0) {
-                       return -ENODEV;
-               } else {
-                       if (ov6xx0_detect(c) < 0) {
-                               PERROR("Failed to init OV6xx0");
-                               return -EIO;
-                       }
-               }
-       } else {
+       if (init_camchip(c) < 0)
+               return -ENODEV;
+       /* 7-bit addresses with bit 0 set are for the OV7xx0 */
+       if (c->addr & 1) {
                if (ov7xx0_detect(c) < 0) {
                        PERROR("Failed to init OV7xx0");
                        return -EIO;
                }
+               return 0;
+       }
+       /* Test for 6xx0 */
+       PDEBUG(3, "Testing for 0V6xx0");
+       if (ov6xx0_detect(c) < 0) {
+               PERROR("Failed to init OV6xx0");
+               return -EIO;
        }
-
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static int ovcamchip_attach(struct i2c_adapter *adap)
+static long ovcamchip_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
-       int rc = 0;
-       struct ovcamchip *ov;
-       struct i2c_client *c;
-
-       /* I2C is not a PnP bus, so we can never be certain that we're talking
-        * to the right chip. To prevent damage to EEPROMS and such, only
-        * attach to adapters that are known to contain OV camera chips. */
-
-       switch (adap->id) {
-       case I2C_HW_SMBUS_OV511:
-       case I2C_HW_SMBUS_OV518:
-       case I2C_HW_SMBUS_W9968CF:
-               PDEBUG(1, "Adapter ID 0x%06x accepted", adap->id);
-               break;
-       default:
-               PDEBUG(1, "Adapter ID 0x%06x rejected", adap->id);
-               return -ENODEV;
-       }
-
-       c = kmalloc(sizeof *c, GFP_KERNEL);
-       if (!c) {
-               rc = -ENOMEM;
-               goto no_client;
-       }
-       memcpy(c, &client_template, sizeof *c);
-       c->adapter = adap;
-       strcpy(c->name, "OV????");
-
-       ov = kzalloc(sizeof *ov, GFP_KERNEL);
-       if (!ov) {
-               rc = -ENOMEM;
-               goto no_ov;
-       }
-       i2c_set_clientdata(c, ov);
-
-       rc = ovcamchip_detect(c);
-       if (rc < 0)
-               goto error;
-
-       strcpy(c->name, chip_names[ov->subtype]);
-
-       PDEBUG(1, "Camera chip detection complete");
-
-       i2c_attach_client(c);
-
-       return rc;
-error:
-       kfree(ov);
-no_ov:
-       kfree(c);
-no_client:
-       PDEBUG(1, "returning %d", rc);
-       return rc;
-}
-
-static int ovcamchip_detach(struct i2c_client *c)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       int rc;
-
-       rc = ov->sops->free(c);
-       if (rc < 0)
-               return rc;
-
-       i2c_detach_client(c);
-
-       kfree(ov);
-       kfree(c);
-       return 0;
-}
-
-static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
+       struct ovcamchip *ov = to_ovcamchip(sd);
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
 
        if (!ov->initialized &&
            cmd != OVCAMCHIP_CMD_Q_SUBTYPE &&
            cmd != OVCAMCHIP_CMD_INITIALIZE) {
-               dev_err(&c->dev, "ERROR: Camera chip not initialized yet!\n");
+               v4l2_err(sd, "Camera chip not initialized yet!\n");
                return -EPERM;
        }
 
@@ -379,10 +303,10 @@ static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg)
 
                if (ov->mono) {
                        if (ov->subtype != CC_OV7620)
-                               dev_warn(&c->dev, "Warning: Monochrome not "
+                               v4l2_warn(sd, "Monochrome not "
                                        "implemented for this chip\n");
                        else
-                               dev_info(&c->dev, "Initializing chip as "
+                               v4l2_info(sd, "Initializing chip as "
                                        "monochrome\n");
                }
 
@@ -400,35 +324,72 @@ static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg)
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver driver = {
-       .driver = {
-               .name =         "ovcamchip",
-       },
-       .id =                   I2C_DRIVERID_OVCAMCHIP,
-       .attach_adapter =       ovcamchip_attach,
-       .detach_client =        ovcamchip_detach,
-       .command =              ovcamchip_command,
+static const struct v4l2_subdev_core_ops ovcamchip_core_ops = {
+       .ioctl = ovcamchip_ioctl,
 };
 
-static struct i2c_client client_template = {
-       .name =         "(unset)",
-       .driver =       &driver,
+static const struct v4l2_subdev_ops ovcamchip_ops = {
+       .core = &ovcamchip_core_ops,
 };
 
-static int __init ovcamchip_init(void)
+static int ovcamchip_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
-#ifdef DEBUG
-       ovcamchip_debug = debug;
-#endif
+       struct ovcamchip *ov;
+       struct v4l2_subdev *sd;
+       int rc = 0;
+
+       ov = kzalloc(sizeof *ov, GFP_KERNEL);
+       if (!ov) {
+               rc = -ENOMEM;
+               goto no_ov;
+       }
+       sd = &ov->sd;
+       v4l2_i2c_subdev_init(sd, client, &ovcamchip_ops);
+
+       rc = ovcamchip_detect(client);
+       if (rc < 0)
+               goto error;
+
+       v4l_info(client, "%s found @ 0x%02x (%s)\n",
+                       chip_names[ov->subtype], client->addr << 1, client->adapter->name);
+
+       PDEBUG(1, "Camera chip detection complete");
 
-       PINFO(DRIVER_VERSION " : " DRIVER_DESC);
-       return i2c_add_driver(&driver);
+       return rc;
+error:
+       kfree(ov);
+no_ov:
+       PDEBUG(1, "returning %d", rc);
+       return rc;
 }
 
-static void __exit ovcamchip_exit(void)
+static int ovcamchip_remove(struct i2c_client *client)
 {
-       i2c_del_driver(&driver);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ovcamchip *ov = to_ovcamchip(sd);
+       int rc;
+
+       v4l2_device_unregister_subdev(sd);
+       rc = ov->sops->free(client);
+       if (rc < 0)
+               return rc;
+
+       kfree(ov);
+       return 0;
 }
 
-module_init(ovcamchip_init);
-module_exit(ovcamchip_exit);
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id ovcamchip_id[] = {
+       { "ovcamchip", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ovcamchip_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "ovcamchip",
+       .probe = ovcamchip_probe,
+       .remove = ovcamchip_remove,
+       .id_table = ovcamchip_id,
+};
index a05650faedda435363e6bfeb5339b51fe896541e..4f07b78c88bc347f8fd5c7ef7214dc748074f9d3 100644 (file)
@@ -16,6 +16,7 @@
 #define __LINUX_OVCAMCHIP_PRIV_H
 
 #include <linux/i2c.h>
+#include <media/v4l2-subdev.h>
 #include <media/ovcamchip.h>
 
 #ifdef DEBUG
@@ -46,6 +47,7 @@ struct ovcamchip_ops {
 };
 
 struct ovcamchip {
+       struct v4l2_subdev sd;
        struct ovcamchip_ops *sops;
        void *spriv;               /* Private data for OV7x10.c etc... */
        int subtype;               /* = SEN_OV7610 etc... */
@@ -53,6 +55,11 @@ struct ovcamchip {
        int initialized;           /* OVCAMCHIP_CMD_INITIALIZE was successful */
 };
 
+static inline struct ovcamchip *to_ovcamchip(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct ovcamchip, sd);
+}
+
 extern struct ovcamchip_ops ov6x20_ops;
 extern struct ovcamchip_ops ov6x30_ops;
 extern struct ovcamchip_ops ov7x10_ops;
index 854c2a88535880a3e2a6c2d560303c46faaa8f2f..f9b6001e1dd71dba3f901badcdc120643301d3f5 100644 (file)
@@ -40,10 +40,10 @@ config VIDEO_PVRUSB2_DVB
        select DVB_LGDT330X if !DVB_FE_CUSTOMISE
        select DVB_S5H1409 if !DVB_FE_CUSTOMISE
        select DVB_S5H1411 if !DVB_FE_CUSTOMISE
-       select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
-       select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
-       select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
+       select DVB_TDA10048 if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
        ---help---
 
          This option enables a DVB interface for the pvrusb2 driver.
index 4fda2de69ab7240022856bd4a2c3064b41c136d4..de2fc14f043b8b4a9ab79bf35b0a5eee189177e2 100644 (file)
@@ -2,14 +2,15 @@ obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o
 obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
 obj-pvrusb2-dvb-$(CONFIG_VIDEO_PVRUSB2_DVB) := pvrusb2-dvb.o
 
-pvrusb2-objs   := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
-                  pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \
+pvrusb2-objs   := pvrusb2-i2c-core.o \
+                  pvrusb2-audio.o \
                   pvrusb2-encoder.o pvrusb2-video-v4l.o \
-                  pvrusb2-eeprom.o pvrusb2-tuner.o \
+                  pvrusb2-eeprom.o \
                   pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \
                   pvrusb2-ctrl.o pvrusb2-std.o pvrusb2-devattr.o \
                   pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
                   pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \
+                  pvrusb2-cs53l32a.o \
                   $(obj-pvrusb2-dvb-y) \
                   $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
 
index cdedaa55f152de97549d455ff2edf01bb3d3219c..ccf2a3c7ad068ac218e75f1c6235c187028555fe 100644 (file)
 #include <media/msp3400.h>
 #include <media/v4l2-common.h>
 
-struct pvr2_msp3400_handler {
-       struct pvr2_hdw *hdw;
-       struct pvr2_i2c_client *client;
-       struct pvr2_i2c_handler i2c_handler;
-       unsigned long stale_mask;
-};
-
-
 
 struct routing_scheme {
        const int *def;
@@ -63,123 +55,33 @@ static const struct routing_scheme routing_schemes[] = {
        },
 };
 
-/* This function selects the correct audio input source */
-static void set_stereo(struct pvr2_msp3400_handler *ctxt)
-{
-       struct pvr2_hdw *hdw = ctxt->hdw;
-       struct v4l2_routing route;
-       const struct routing_scheme *sp;
-       unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
-
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
-
-       if ((sid < ARRAY_SIZE(routing_schemes)) &&
-           ((sp = routing_schemes + sid) != NULL) &&
-           (hdw->input_val >= 0) &&
-           (hdw->input_val < sp->cnt)) {
-               route.input = sp->def[hdw->input_val];
-       } else {
-               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                          "*** WARNING *** i2c msp3400 v4l2 set_stereo:"
-                          " Invalid routing scheme (%u) and/or input (%d)",
-                          sid,hdw->input_val);
-               return;
-       }
-       route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
-       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
-}
-
-
-static int check_stereo(struct pvr2_msp3400_handler *ctxt)
+void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
 {
-       struct pvr2_hdw *hdw = ctxt->hdw;
-       return hdw->input_dirty;
-}
-
-
-struct pvr2_msp3400_ops {
-       void (*update)(struct pvr2_msp3400_handler *);
-       int (*check)(struct pvr2_msp3400_handler *);
-};
-
-
-static const struct pvr2_msp3400_ops msp3400_ops[] = {
-       { .update = set_stereo, .check = check_stereo},
-};
-
-
-static int msp3400_check(struct pvr2_msp3400_handler *ctxt)
-{
-       unsigned long msk;
-       unsigned int idx;
-
-       for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
-               msk = 1 << idx;
-               if (ctxt->stale_mask & msk) continue;
-               if (msp3400_ops[idx].check(ctxt)) {
-                       ctxt->stale_mask |= msk;
+       if (hdw->input_dirty || hdw->force_dirty) {
+               struct v4l2_routing route;
+               const struct routing_scheme *sp;
+               unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
+
+               pvr2_trace(PVR2_TRACE_CHIPS, "subdev msp3400 v4l2 set_stereo");
+
+               if ((sid < ARRAY_SIZE(routing_schemes)) &&
+                   ((sp = routing_schemes + sid) != NULL) &&
+                   (hdw->input_val >= 0) &&
+                   (hdw->input_val < sp->cnt)) {
+                       route.input = sp->def[hdw->input_val];
+               } else {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "*** WARNING *** subdev msp3400 set_input:"
+                                  " Invalid routing scheme (%u)"
+                                  " and/or input (%d)",
+                                  sid, hdw->input_val);
+                       return;
                }
+               route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
+               sd->ops->audio->s_routing(sd, &route);
        }
-       return ctxt->stale_mask != 0;
 }
 
-
-static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
-{
-       unsigned long msk;
-       unsigned int idx;
-
-       for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
-               msk = 1 << idx;
-               if (!(ctxt->stale_mask & msk)) continue;
-               ctxt->stale_mask &= ~msk;
-               msp3400_ops[idx].update(ctxt);
-       }
-}
-
-
-static void pvr2_msp3400_detach(struct pvr2_msp3400_handler *ctxt)
-{
-       ctxt->client->handler = NULL;
-       kfree(ctxt);
-}
-
-
-static unsigned int pvr2_msp3400_describe(struct pvr2_msp3400_handler *ctxt,
-                                         char *buf,unsigned int cnt)
-{
-       return scnprintf(buf,cnt,"handler: pvrusb2-audio v4l2");
-}
-
-
-static const struct pvr2_i2c_handler_functions msp3400_funcs = {
-       .detach = (void (*)(void *))pvr2_msp3400_detach,
-       .check = (int (*)(void *))msp3400_check,
-       .update = (void (*)(void *))msp3400_update,
-       .describe = (unsigned int (*)(void *,char *,unsigned int))pvr2_msp3400_describe,
-};
-
-
-int pvr2_i2c_msp3400_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
-{
-       struct pvr2_msp3400_handler *ctxt;
-       if (cp->handler) return 0;
-
-       ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
-       if (!ctxt) return 0;
-
-       ctxt->i2c_handler.func_data = ctxt;
-       ctxt->i2c_handler.func_table = &msp3400_funcs;
-       ctxt->client = cp;
-       ctxt->hdw = hdw;
-       ctxt->stale_mask = (1 << ARRAY_SIZE(msp3400_ops)) - 1;
-       cp->handler = &ctxt->i2c_handler;
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x msp3400 V4L2 handler set up",
-                  cp->client->addr);
-       return !0;
-}
-
-
 /*
   Stuff for Emacs to see, in order to encourage consistent editing style:
   *** Local Variables: ***
index ac54eed3721b7a5804aaaa1002d8459b5f88fa20..e3e63d750891033339698a9916414497620aee3f 100644 (file)
 #ifndef __PVRUSB2_AUDIO_H
 #define __PVRUSB2_AUDIO_H
 
-#include "pvrusb2-i2c-core.h"
-
-int pvr2_i2c_msp3400_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
-
+#include "pvrusb2-hdw-internal.h"
+void pvr2_msp3400_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *);
 #endif /* __PVRUSB2_AUDIO_H */
 
 /*
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c b/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c
new file mode 100644 (file)
index 0000000..b5c3428
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ *
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  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
+ *
+ *  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
+ *
+ */
+
+/*
+
+   This source file is specifically designed to interface with the
+   v4l-dvb cs53l32a module.
+
+*/
+
+#include "pvrusb2-cs53l32a.h"
+
+
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+struct routing_scheme {
+       const int *def;
+       unsigned int cnt;
+};
+
+
+static const int routing_scheme1[] = {
+       [PVR2_CVAL_INPUT_TV] = 2,  /* 1 or 2 seems to work here */
+       [PVR2_CVAL_INPUT_RADIO] = 2,
+       [PVR2_CVAL_INPUT_COMPOSITE] = 0,
+       [PVR2_CVAL_INPUT_SVIDEO] =  0,
+};
+
+static const struct routing_scheme routing_schemes[] = {
+       [PVR2_ROUTING_SCHEME_ONAIR] = {
+               .def = routing_scheme1,
+               .cnt = ARRAY_SIZE(routing_scheme1),
+       },
+};
+
+
+void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
+{
+       if (hdw->input_dirty || hdw->force_dirty) {
+               struct v4l2_routing route;
+               const struct routing_scheme *sp;
+               unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
+               pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_input(%d)",
+                          hdw->input_val);
+               if ((sid < ARRAY_SIZE(routing_schemes)) &&
+                   ((sp = routing_schemes + sid) != NULL) &&
+                   (hdw->input_val >= 0) &&
+                   (hdw->input_val < sp->cnt)) {
+                       route.input = sp->def[hdw->input_val];
+               } else {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "*** WARNING *** subdev v4l2 set_input:"
+                                  " Invalid routing scheme (%u)"
+                                  " and/or input (%d)",
+                                  sid, hdw->input_val);
+                       return;
+               }
+               route.output = 0;
+               sd->ops->audio->s_routing(sd, &route);
+       }
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
similarity index 64%
rename from drivers/media/video/pvrusb2/pvrusb2-tuner.h
rename to drivers/media/video/pvrusb2/pvrusb2-cs53l32a.h
index ef4afaf37b0afde085574e01b1fd9d7c8cd7dfc1..53ba548b72a766e061d889860b4cddea358d7eaa 100644 (file)
@@ -2,6 +2,7 @@
  *
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
  *
  *  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
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
-#ifndef __PVRUSB2_TUNER_H
-#define __PVRUSB2_TUNER_H
 
-#include "pvrusb2-i2c-core.h"
+#ifndef __PVRUSB2_CS53L32A_H
+#define __PVRUSB2_CS53L32A_H
 
-int pvr2_i2c_tuner_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+/*
+
+   This module connects the pvrusb2 driver to the I2C chip level
+   driver which handles device video processing.  This interface is
+   used internally by the driver; higher level code should only
+   interact through the interface provided by pvrusb2-hdw.h.
+
+*/
+
+
+#include "pvrusb2-hdw-internal.h"
+void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *);
 
-#endif /* __PVRUSB2_TUNER_H */
+#endif /* __PVRUSB2_AUDIO_CS53L32A_H */
 
 /*
   Stuff for Emacs to see, in order to encourage consistent editing style:
index 895859ec495a7737b85ebd2ca47fd4924ed7e5da..4e017ff26c368e7a011c487debdb1cdbd96e367b 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "pvrusb2-cx2584x-v4l.h"
 #include "pvrusb2-video-v4l.h"
-#include "pvrusb2-i2c-cmd-v4l2.h"
 
 
 #include "pvrusb2-hdw-internal.h"
 #include <linux/errno.h>
 #include <linux/slab.h>
 
-struct pvr2_v4l_cx2584x {
-       struct pvr2_i2c_handler handler;
-       struct pvr2_decoder_ctrl ctrl;
-       struct pvr2_i2c_client *client;
-       struct pvr2_hdw *hdw;
-       unsigned long stale_mask;
-};
-
 
 struct routing_scheme_item {
        int vid;
@@ -110,218 +101,44 @@ static const struct routing_scheme routing_schemes[] = {
        },
 };
 
-static void set_input(struct pvr2_v4l_cx2584x *ctxt)
-{
-       struct pvr2_hdw *hdw = ctxt->hdw;
-       struct v4l2_routing route;
-       enum cx25840_video_input vid_input;
-       enum cx25840_audio_input aud_input;
-       const struct routing_scheme *sp;
-       unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
-
-       memset(&route,0,sizeof(route));
-
-       if ((sid < ARRAY_SIZE(routing_schemes)) &&
-           ((sp = routing_schemes + sid) != NULL) &&
-           (hdw->input_val >= 0) &&
-           (hdw->input_val < sp->cnt)) {
-               vid_input = sp->def[hdw->input_val].vid;
-               aud_input = sp->def[hdw->input_val].aud;
-       } else {
-               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                          "*** WARNING *** i2c cx2584x set_input:"
-                          " Invalid routing scheme (%u) and/or input (%d)",
-                          sid,hdw->input_val);
-               return;
-       }
-
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_input vid=0x%x aud=0x%x",
-                  vid_input,aud_input);
-       route.input = (u32)vid_input;
-       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
-       route.input = (u32)aud_input;
-       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
-}
-
-
-static int check_input(struct pvr2_v4l_cx2584x *ctxt)
-{
-       struct pvr2_hdw *hdw = ctxt->hdw;
-       return hdw->input_dirty != 0;
-}
-
-
-static void set_audio(struct pvr2_v4l_cx2584x *ctxt)
-{
-       u32 val;
-       struct pvr2_hdw *hdw = ctxt->hdw;
-
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_audio %d",
-                  hdw->srate_val);
-       switch (hdw->srate_val) {
-       default:
-       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
-               val = 48000;
-               break;
-       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
-               val = 44100;
-               break;
-       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
-               val = 32000;
-               break;
-       }
-       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val);
-}
-
-
-static int check_audio(struct pvr2_v4l_cx2584x *ctxt)
-{
-       struct pvr2_hdw *hdw = ctxt->hdw;
-       return hdw->srate_dirty != 0;
-}
-
-
-struct pvr2_v4l_cx2584x_ops {
-       void (*update)(struct pvr2_v4l_cx2584x *);
-       int (*check)(struct pvr2_v4l_cx2584x *);
-};
-
-
-static const struct pvr2_v4l_cx2584x_ops decoder_ops[] = {
-       { .update = set_input, .check = check_input},
-       { .update = set_audio, .check = check_audio},
-};
-
-
-static void decoder_detach(struct pvr2_v4l_cx2584x *ctxt)
+void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
 {
-       ctxt->client->handler = NULL;
-       pvr2_hdw_set_decoder(ctxt->hdw,NULL);
-       kfree(ctxt);
-}
-
-
-static int decoder_check(struct pvr2_v4l_cx2584x *ctxt)
-{
-       unsigned long msk;
-       unsigned int idx;
-
-       for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
-               msk = 1 << idx;
-               if (ctxt->stale_mask & msk) continue;
-               if (decoder_ops[idx].check(ctxt)) {
-                       ctxt->stale_mask |= msk;
+       pvr2_trace(PVR2_TRACE_CHIPS, "subdev cx2584x update...");
+       if (hdw->input_dirty || hdw->force_dirty) {
+               struct v4l2_routing route;
+               enum cx25840_video_input vid_input;
+               enum cx25840_audio_input aud_input;
+               const struct routing_scheme *sp;
+               unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
+
+               memset(&route, 0, sizeof(route));
+
+               if ((sid < ARRAY_SIZE(routing_schemes)) &&
+                   ((sp = routing_schemes + sid) != NULL) &&
+                   (hdw->input_val >= 0) &&
+                   (hdw->input_val < sp->cnt)) {
+                       vid_input = sp->def[hdw->input_val].vid;
+                       aud_input = sp->def[hdw->input_val].aud;
+               } else {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "*** WARNING *** subdev cx2584x set_input:"
+                                  " Invalid routing scheme (%u)"
+                                  " and/or input (%d)",
+                                  sid, hdw->input_val);
+                       return;
                }
-       }
-       return ctxt->stale_mask != 0;
-}
-
 
-static void decoder_update(struct pvr2_v4l_cx2584x *ctxt)
-{
-       unsigned long msk;
-       unsigned int idx;
-
-       for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
-               msk = 1 << idx;
-               if (!(ctxt->stale_mask & msk)) continue;
-               ctxt->stale_mask &= ~msk;
-               decoder_ops[idx].update(ctxt);
+               pvr2_trace(PVR2_TRACE_CHIPS,
+                          "subdev cx2584x set_input vid=0x%x aud=0x%x",
+                          vid_input, aud_input);
+               route.input = (u32)vid_input;
+               sd->ops->video->s_routing(sd, &route);
+               route.input = (u32)aud_input;
+               sd->ops->audio->s_routing(sd, &route);
        }
 }
 
 
-static void decoder_enable(struct pvr2_v4l_cx2584x *ctxt,int fl)
-{
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_enable(%d)",fl);
-       pvr2_v4l2_cmd_stream(ctxt->client,fl);
-}
-
-
-static int decoder_detect(struct pvr2_i2c_client *cp)
-{
-       int ret;
-       /* Attempt to query the decoder - let's see if it will answer */
-       struct v4l2_queryctrl qc;
-
-       memset(&qc,0,sizeof(qc));
-
-       qc.id = V4L2_CID_BRIGHTNESS;
-
-       ret = pvr2_i2c_client_cmd(cp,VIDIOC_QUERYCTRL,&qc);
-       return ret == 0; /* Return true if it answered */
-}
-
-
-static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt,
-                                    char *buf,unsigned int cnt)
-{
-       return scnprintf(buf,cnt,"handler: pvrusb2-cx2584x-v4l");
-}
-
-
-static void decoder_reset(struct pvr2_v4l_cx2584x *ctxt)
-{
-       int ret;
-       ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,NULL);
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_reset (ret=%d)",ret);
-}
-
-
-static const struct pvr2_i2c_handler_functions hfuncs = {
-       .detach = (void (*)(void *))decoder_detach,
-       .check = (int (*)(void *))decoder_check,
-       .update = (void (*)(void *))decoder_update,
-       .describe = (unsigned int (*)(void *,char *,unsigned int))decoder_describe,
-};
-
-
-int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
-                              struct pvr2_i2c_client *cp)
-{
-       struct pvr2_v4l_cx2584x *ctxt;
-
-       if (hdw->decoder_ctrl) return 0;
-       if (cp->handler) return 0;
-       if (!decoder_detect(cp)) return 0;
-
-       ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
-       if (!ctxt) return 0;
-
-       ctxt->handler.func_data = ctxt;
-       ctxt->handler.func_table = &hfuncs;
-       ctxt->ctrl.ctxt = ctxt;
-       ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
-       ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
-       ctxt->ctrl.force_reset = (void (*)(void*))decoder_reset;
-       ctxt->client = cp;
-       ctxt->hdw = hdw;
-       ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
-       pvr2_hdw_set_decoder(hdw,&ctxt->ctrl);
-       cp->handler = &ctxt->handler;
-       {
-               /*
-                 Mike Isely <isely@pobox.com> 19-Nov-2006 - This bit
-                 of nuttiness for cx25840 causes that module to
-                 correctly set up its video scaling.  This is really
-                 a problem in the cx25840 module itself, but we work
-                 around it here.  The problem has not been seen in
-                 ivtv because there VBI is supported and set up.  We
-                 don't do VBI here (at least not yet) and thus we
-                 never attempted to even set it up.
-                */
-               struct v4l2_format fmt;
-               memset(&fmt,0,sizeof(fmt));
-               fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
-               pvr2_i2c_client_cmd(ctxt->client,VIDIOC_S_FMT,&fmt);
-       }
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x cx2584x V4L2 handler set up",
-                  cp->client->addr);
-       return !0;
-}
-
-
-
 
 /*
   Stuff for Emacs to see, in order to encourage consistent editing style:
index 66abf77f51fdb91f90c26ae556f81dbfeec77adf..e35c2322a08c3f3d6ddf5bd1a81a848f95aa6748 100644 (file)
@@ -34,9 +34,9 @@
 
 
 
-#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-hdw-internal.h"
 
-int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+void pvr2_cx25840_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *sd);
 
 
 #endif /* __PVRUSB2_CX2584X_V4L_H */
index ca892fb78a5b8055a6da521e767f5a637130f70c..fbe3856bdca650571dd65fffb8fd950e99387121 100644 (file)
@@ -23,7 +23,6 @@
 #include "pvrusb2-debugifc.h"
 #include "pvrusb2-hdw.h"
 #include "pvrusb2-debug.h"
-#include "pvrusb2-i2c-core.h"
 
 struct debugifc_mask_item {
        const char *name;
@@ -147,10 +146,6 @@ int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt)
        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
        ccnt = pvr2_hdw_state_report(hdw,buf,acnt);
        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n");
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       ccnt = pvr2_i2c_report(hdw,buf,acnt);
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 
        return bcnt;
 }
index e24ff59f8605d50501ca8e5e5a5976e9840ab675..2f8d46761cd0d0ec0d482843a6f739b5e1a6c720 100644 (file)
 
 struct pvr2_hdw;
 
-/* Non-intrusively print some useful debugging info from inside the
-   driver.  This should work even if the driver appears to be
-   wedged. */
-int pvr2_debugifc_print_info(struct pvr2_hdw *,
-                            char *buf_ptr,unsigned int buf_size);
-
 /* Print general status of driver.  This will also trigger a probe of
    the USB link.  Unlike print_info(), this one synchronizes with the
    driver so the information should be self-consistent (but it will
    hang if the driver is wedged). */
+int pvr2_debugifc_print_info(struct pvr2_hdw *,
+                            char *buf_ptr, unsigned int buf_size);
+
+/* Non-intrusively print some useful debugging info from inside the
+   driver.  This should work even if the driver appears to be
+   wedged. */
 int pvr2_debugifc_print_status(struct pvr2_hdw *,
                               char *buf_ptr,unsigned int buf_size);
 
index cbe2a3417851a80bc6fa02459afdf521f256117d..1cb6a260e8b00056940c4200348ce9461cd1e16c 100644 (file)
@@ -46,10 +46,11 @@ pvr2_device_desc structures.
 /*------------------------------------------------------------------------*/
 /* Hauppauge PVR-USB2 Model 29xxx */
 
-static const char *pvr2_client_29xxx[] = {
-       "msp3400",
-       "saa7115",
-       "tuner",
+static const struct pvr2_device_client_desc pvr2_cli_29xxx[] = {
+       { .module_id = PVR2_CLIENT_ID_SAA7115 },
+       { .module_id = PVR2_CLIENT_ID_MSP3400 },
+       { .module_id = PVR2_CLIENT_ID_TUNER },
+       { .module_id = PVR2_CLIENT_ID_DEMOD },
 };
 
 static const char *pvr2_fw1_names_29xxx[] = {
@@ -59,8 +60,8 @@ static const char *pvr2_fw1_names_29xxx[] = {
 static const struct pvr2_device_desc pvr2_device_29xxx = {
                .description = "WinTV PVR USB2 Model Category 29xxx",
                .shortname = "29xxx",
-               .client_modules.lst = pvr2_client_29xxx,
-               .client_modules.cnt = ARRAY_SIZE(pvr2_client_29xxx),
+               .client_table.lst = pvr2_cli_29xxx,
+               .client_table.cnt = ARRAY_SIZE(pvr2_cli_29xxx),
                .fx2_firmware.lst = pvr2_fw1_names_29xxx,
                .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx),
                .flag_has_hauppauge_rom = !0,
@@ -77,10 +78,11 @@ static const struct pvr2_device_desc pvr2_device_29xxx = {
 /*------------------------------------------------------------------------*/
 /* Hauppauge PVR-USB2 Model 24xxx */
 
-static const char *pvr2_client_24xxx[] = {
-       "cx25840",
-       "tuner",
-       "wm8775",
+static const struct pvr2_device_client_desc pvr2_cli_24xxx[] = {
+       { .module_id = PVR2_CLIENT_ID_CX25840 },
+       { .module_id = PVR2_CLIENT_ID_TUNER },
+       { .module_id = PVR2_CLIENT_ID_WM8775 },
+       { .module_id = PVR2_CLIENT_ID_DEMOD },
 };
 
 static const char *pvr2_fw1_names_24xxx[] = {
@@ -90,8 +92,8 @@ static const char *pvr2_fw1_names_24xxx[] = {
 static const struct pvr2_device_desc pvr2_device_24xxx = {
                .description = "WinTV PVR USB2 Model Category 24xxx",
                .shortname = "24xxx",
-               .client_modules.lst = pvr2_client_24xxx,
-               .client_modules.cnt = ARRAY_SIZE(pvr2_client_24xxx),
+               .client_table.lst = pvr2_cli_24xxx,
+               .client_table.cnt = ARRAY_SIZE(pvr2_cli_24xxx),
                .fx2_firmware.lst = pvr2_fw1_names_24xxx,
                .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_24xxx),
                .flag_has_cx25840 = !0,
@@ -111,16 +113,16 @@ static const struct pvr2_device_desc pvr2_device_24xxx = {
 /*------------------------------------------------------------------------*/
 /* GOTVIEW USB2.0 DVD2 */
 
-static const char *pvr2_client_gotview_2[] = {
-       "cx25840",
-       "tuner",
+static const struct pvr2_device_client_desc pvr2_cli_gotview_2[] = {
+       { .module_id = PVR2_CLIENT_ID_CX25840 },
+       { .module_id = PVR2_CLIENT_ID_TUNER },
 };
 
 static const struct pvr2_device_desc pvr2_device_gotview_2 = {
                .description = "Gotview USB 2.0 DVD 2",
                .shortname = "gv2",
-               .client_modules.lst = pvr2_client_gotview_2,
-               .client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2),
+               .client_table.lst = pvr2_cli_gotview_2,
+               .client_table.cnt = ARRAY_SIZE(pvr2_cli_gotview_2),
                .flag_has_cx25840 = !0,
                .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
                .flag_has_analogtuner = !0,
@@ -140,8 +142,8 @@ static const struct pvr2_device_desc pvr2_device_gotview_2 = {
 static const struct pvr2_device_desc pvr2_device_gotview_2d = {
                .description = "Gotview USB 2.0 DVD Deluxe",
                .shortname = "gv2d",
-               .client_modules.lst = pvr2_client_gotview_2,
-               .client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2),
+               .client_table.lst = pvr2_cli_gotview_2,
+               .client_table.cnt = ARRAY_SIZE(pvr2_cli_gotview_2),
                .flag_has_cx25840 = !0,
                .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
                .flag_has_analogtuner = !0,
@@ -181,29 +183,29 @@ static int pvr2_lgh06xf_attach(struct pvr2_dvb_adapter *adap)
        return 0;
 }
 
-static struct pvr2_dvb_props pvr2_onair_creator_fe_props = {
+static const struct pvr2_dvb_props pvr2_onair_creator_fe_props = {
        .frontend_attach = pvr2_lgdt3303_attach,
        .tuner_attach    = pvr2_lgh06xf_attach,
 };
 #endif
 
-static const char *pvr2_client_onair_creator[] = {
-       "saa7115",
-       "tuner",
-       "cs53l32a",
+static const struct pvr2_device_client_desc pvr2_cli_onair_creator[] = {
+       { .module_id = PVR2_CLIENT_ID_SAA7115 },
+       { .module_id = PVR2_CLIENT_ID_CS53L32A },
+       { .module_id = PVR2_CLIENT_ID_TUNER },
 };
 
 static const struct pvr2_device_desc pvr2_device_onair_creator = {
                .description = "OnAir Creator Hybrid USB tuner",
                .shortname = "oac",
-               .client_modules.lst = pvr2_client_onair_creator,
-               .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_creator),
+               .client_table.lst = pvr2_cli_onair_creator,
+               .client_table.cnt = ARRAY_SIZE(pvr2_cli_onair_creator),
                .default_tuner_type = TUNER_LG_TDVS_H06XF,
                .flag_has_analogtuner = !0,
                .flag_has_composite = !0,
                .flag_has_svideo = !0,
                .flag_digital_requires_cx23416 = !0,
-               .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+               .signal_routing_scheme = PVR2_ROUTING_SCHEME_ONAIR,
                .digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
                .default_std_mask = V4L2_STD_NTSC_M,
 #ifdef CONFIG_VIDEO_PVRUSB2_DVB
@@ -241,29 +243,29 @@ static int pvr2_fcv1236d_attach(struct pvr2_dvb_adapter *adap)
        return 0;
 }
 
-static struct pvr2_dvb_props pvr2_onair_usb2_fe_props = {
+static const struct pvr2_dvb_props pvr2_onair_usb2_fe_props = {
        .frontend_attach = pvr2_lgdt3302_attach,
        .tuner_attach    = pvr2_fcv1236d_attach,
 };
 #endif
 
-static const char *pvr2_client_onair_usb2[] = {
-       "saa7115",
-       "tuner",
-       "cs53l32a",
+static const struct pvr2_device_client_desc pvr2_cli_onair_usb2[] = {
+       { .module_id = PVR2_CLIENT_ID_SAA7115 },
+       { .module_id = PVR2_CLIENT_ID_CS53L32A },
+       { .module_id = PVR2_CLIENT_ID_TUNER },
 };
 
 static const struct pvr2_device_desc pvr2_device_onair_usb2 = {
                .description = "OnAir USB2 Hybrid USB tuner",
                .shortname = "oa2",
-               .client_modules.lst = pvr2_client_onair_usb2,
-               .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_usb2),
+               .client_table.lst = pvr2_cli_onair_usb2,
+               .client_table.cnt = ARRAY_SIZE(pvr2_cli_onair_usb2),
                .default_tuner_type = TUNER_PHILIPS_FCV1236D,
                .flag_has_analogtuner = !0,
                .flag_has_composite = !0,
                .flag_has_svideo = !0,
                .flag_digital_requires_cx23416 = !0,
-               .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+               .signal_routing_scheme = PVR2_ROUTING_SCHEME_ONAIR,
                .digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
                .default_std_mask = V4L2_STD_NTSC_M,
 #ifdef CONFIG_VIDEO_PVRUSB2_DVB
@@ -314,15 +316,16 @@ static int pvr2_73xxx_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
        return 0;
 }
 
-static struct pvr2_dvb_props pvr2_73xxx_dvb_props = {
+static const struct pvr2_dvb_props pvr2_73xxx_dvb_props = {
        .frontend_attach = pvr2_tda10048_attach,
        .tuner_attach    = pvr2_73xxx_tda18271_8295_attach,
 };
 #endif
 
-static const char *pvr2_client_73xxx[] = {
-       "cx25840",
-       "tuner",
+static const struct pvr2_device_client_desc pvr2_cli_73xxx[] = {
+       { .module_id = PVR2_CLIENT_ID_CX25840 },
+       { .module_id = PVR2_CLIENT_ID_TUNER,
+         .i2c_address_list = "\x42"},
 };
 
 static const char *pvr2_fw1_names_73xxx[] = {
@@ -332,8 +335,8 @@ static const char *pvr2_fw1_names_73xxx[] = {
 static const struct pvr2_device_desc pvr2_device_73xxx = {
                .description = "WinTV HVR-1900 Model Category 73xxx",
                .shortname = "73xxx",
-               .client_modules.lst = pvr2_client_73xxx,
-               .client_modules.cnt = ARRAY_SIZE(pvr2_client_73xxx),
+               .client_table.lst = pvr2_cli_73xxx,
+               .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
                .fx2_firmware.lst = pvr2_fw1_names_73xxx,
                .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_73xxx),
                .flag_has_cx25840 = !0,
@@ -418,22 +421,17 @@ static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
        return 0;
 }
 
-static struct pvr2_dvb_props pvr2_750xx_dvb_props = {
+static const struct pvr2_dvb_props pvr2_750xx_dvb_props = {
        .frontend_attach = pvr2_s5h1409_attach,
        .tuner_attach    = pvr2_tda18271_8295_attach,
 };
 
-static struct pvr2_dvb_props pvr2_751xx_dvb_props = {
+static const struct pvr2_dvb_props pvr2_751xx_dvb_props = {
        .frontend_attach = pvr2_s5h1411_attach,
        .tuner_attach    = pvr2_tda18271_8295_attach,
 };
 #endif
 
-static const char *pvr2_client_75xxx[] = {
-       "cx25840",
-       "tuner",
-};
-
 static const char *pvr2_fw1_names_75xxx[] = {
                "v4l-pvrusb2-73xxx-01.fw",
 };
@@ -441,8 +439,8 @@ static const char *pvr2_fw1_names_75xxx[] = {
 static const struct pvr2_device_desc pvr2_device_750xx = {
                .description = "WinTV HVR-1950 Model Category 750xx",
                .shortname = "750xx",
-               .client_modules.lst = pvr2_client_75xxx,
-               .client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx),
+               .client_table.lst = pvr2_cli_73xxx,
+               .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
                .fx2_firmware.lst = pvr2_fw1_names_75xxx,
                .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
                .flag_has_cx25840 = !0,
@@ -463,8 +461,8 @@ static const struct pvr2_device_desc pvr2_device_750xx = {
 static const struct pvr2_device_desc pvr2_device_751xx = {
                .description = "WinTV HVR-1950 Model Category 751xx",
                .shortname = "751xx",
-               .client_modules.lst = pvr2_client_75xxx,
-               .client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx),
+               .client_table.lst = pvr2_cli_73xxx,
+               .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
                .fx2_firmware.lst = pvr2_fw1_names_75xxx,
                .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
                .flag_has_cx25840 = !0,
index cb3a33eb027660a12c3dc355271dbad6c35c69ac..3e553389cbc34c4c8f94c3d2db7be1d8afd84c32 100644 (file)
 */
 
 
+#define PVR2_CLIENT_ID_NULL 0
+#define PVR2_CLIENT_ID_MSP3400 1
+#define PVR2_CLIENT_ID_CX25840 2
+#define PVR2_CLIENT_ID_SAA7115 3
+#define PVR2_CLIENT_ID_TUNER 4
+#define PVR2_CLIENT_ID_CS53L32A 5
+#define PVR2_CLIENT_ID_WM8775 6
+#define PVR2_CLIENT_ID_DEMOD 7
+
+struct pvr2_device_client_desc {
+       /* One ovr PVR2_CLIENT_ID_xxxx */
+       unsigned char module_id;
+
+       /* Null-terminated array of I2C addresses to try in order
+          initialize the module.  It's safe to make this null terminated
+          since we're never going to encounter an i2c device with an
+          address of zero.  If this is a null pointer or zero-length,
+          then no I2C addresses have been specified, in which case we'll
+          try some compiled in defaults for now. */
+       unsigned char *i2c_address_list;
+};
+
+struct pvr2_device_client_table {
+       const struct pvr2_device_client_desc *lst;
+       unsigned char cnt;
+};
+
+
 struct pvr2_string_table {
        const char **lst;
        unsigned int cnt;
@@ -40,6 +68,7 @@ struct pvr2_string_table {
 
 #define PVR2_ROUTING_SCHEME_HAUPPAUGE 0
 #define PVR2_ROUTING_SCHEME_GOTVIEW 1
+#define PVR2_ROUTING_SCHEME_ONAIR 2
 
 #define PVR2_DIGITAL_SCHEME_NONE 0
 #define PVR2_DIGITAL_SCHEME_HAUPPAUGE 1
@@ -66,6 +95,9 @@ struct pvr2_device_desc {
        /* List of additional client modules we need to load */
        struct pvr2_string_table client_modules;
 
+       /* List of defined client modules we need to load */
+       struct pvr2_device_client_table client_table;
+
        /* List of FX2 firmware file names we should search; if empty then
           FX2 firmware check / load is skipped and we assume the device
           was initialized from internal ROM. */
@@ -73,7 +105,7 @@ struct pvr2_device_desc {
 
 #ifdef CONFIG_VIDEO_PVRUSB2_DVB
        /* callback functions to handle attachment of digital tuner & demod */
-       struct pvr2_dvb_props *dvb_props;
+       const struct pvr2_dvb_props *dvb_props;
 
 #endif
        /* Initial standard bits to use for this device, if not zero.
index 77b3c338506624992f9023eff7adc2a123dd3550..b7f5c49b1dbc19f35bc7ce59461d9996cef111a6 100644 (file)
@@ -321,7 +321,7 @@ static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap)
 static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
 {
        struct pvr2_hdw *hdw = adap->channel.hdw;
-       struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props;
+       const struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props;
        int ret = 0;
 
        if (dvb_props == NULL) {
index 273d2a1aa220f0b8a42ad41ae9722dd3c299de5c..54ac5349dee2f29d47303269cf07ee99cc26706c 100644 (file)
@@ -347,7 +347,7 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
        int encMisc3Arg = 0;
 
 #if 0
-       /* This inexplicable bit happens in the Hauppage windows
+       /* This inexplicable bit happens in the Hauppauge windows
           driver (for both 24xxx and 29xxx devices).  However I
           currently see no difference in behavior with or without
           this stuff.  Leave this here as a note of its existence,
index de7ee7264be63bc8855380942b1e14ae222ca7d6..5d75eb5211b1a774067b34338c41a153a29aef45 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/mutex.h>
 #include "pvrusb2-hdw.h"
 #include "pvrusb2-io.h"
+#include <media/v4l2-device.h>
 #include <media/cx2341x.h>
 #include "pvrusb2-devattr.h"
 
@@ -57,8 +58,6 @@
 #define LOCK_TAKE(x) do { mutex_lock(&x##_mutex); x##_held = !0; } while (0)
 #define LOCK_GIVE(x) do { x##_held = 0; mutex_unlock(&x##_mutex); } while (0)
 
-struct pvr2_decoder;
-
 typedef int (*pvr2_ctlf_is_dirty)(struct pvr2_ctrl *);
 typedef void (*pvr2_ctlf_clear_dirty)(struct pvr2_ctrl *);
 typedef int (*pvr2_ctlf_check_value)(struct pvr2_ctrl *,int);
@@ -139,22 +138,6 @@ struct pvr2_ctrl {
 };
 
 
-struct pvr2_decoder_ctrl {
-       void *ctxt;
-       void (*detach)(void *);
-       void (*enable)(void *,int);
-       void (*force_reset)(void *);
-};
-
-#define PVR2_I2C_PEND_DETECT  0x01  /* Need to detect a client type */
-#define PVR2_I2C_PEND_CLIENT  0x02  /* Client needs a specific update */
-#define PVR2_I2C_PEND_REFRESH 0x04  /* Client has specific pending bits */
-#define PVR2_I2C_PEND_STALE   0x08  /* Broadcast pending bits */
-
-#define PVR2_I2C_PEND_ALL (PVR2_I2C_PEND_DETECT |\
-                          PVR2_I2C_PEND_CLIENT |\
-                          PVR2_I2C_PEND_REFRESH |\
-                          PVR2_I2C_PEND_STALE)
 
 /* Disposition of firmware1 loading situation */
 #define FW1_STATE_UNKNOWN 0
@@ -179,6 +162,8 @@ struct pvr2_hdw {
        struct usb_device *usb_dev;
        struct usb_interface *usb_intf;
 
+       /* Our handle into the v4l2 sub-device architecture */
+       struct v4l2_device v4l2_dev;
        /* Device description, anything that must adjust behavior based on
           device specific info will use information held here. */
        const struct pvr2_device_desc *hdw_desc;
@@ -186,7 +171,6 @@ struct pvr2_hdw {
        /* Kernel worker thread handling */
        struct workqueue_struct *workqueue;
        struct work_struct workpoll;     /* Update driver state */
-       struct work_struct worki2csync;  /* Update i2c clients */
 
        /* Video spigot */
        struct pvr2_stream *vid_stream;
@@ -195,20 +179,26 @@ struct pvr2_hdw {
        struct mutex big_lock_mutex;
        int big_lock_held;  /* For debugging */
 
+       /* This is a simple string which identifies the instance of this
+          driver.  It is unique within the set of existing devices, but
+          there is no attempt to keep the name consistent with the same
+          physical device each time. */
        char name[32];
 
+       /* This is a simple string which identifies the physical device
+          instance itself - if possible.  (If not possible, then it is
+          based on the specific driver instance, similar to name above.)
+          The idea here is that userspace might hopefully be able to use
+          this recognize specific tuners.  It will encode a serial number,
+          if available. */
+       char identifier[32];
+
        /* I2C stuff */
        struct i2c_adapter i2c_adap;
        struct i2c_algorithm i2c_algo;
        pvr2_i2c_func i2c_func[PVR2_I2C_FUNC_CNT];
        int i2c_cx25840_hack_state;
        int i2c_linked;
-       unsigned int i2c_pend_types;    /* Which types of update are needed */
-       unsigned long i2c_pend_mask;    /* Change bits we need to scan */
-       unsigned long i2c_stale_mask;   /* Pending broadcast change bits */
-       unsigned long i2c_active_mask;  /* All change bits currently in use */
-       struct list_head i2c_clients;
-       struct mutex i2c_list_lock;
 
        /* Frequency table */
        unsigned int freqTable[FREQTABLE_SIZE];
@@ -275,6 +265,7 @@ struct pvr2_hdw {
        wait_queue_head_t state_wait_data;
 
 
+       int force_dirty;        /* consider all controls dirty if true */
        int flag_ok;            /* device in known good state */
        int flag_disconnected;  /* flag_ok == 0 due to disconnect */
        int flag_init_ok;       /* true if structure is fully initialized */
@@ -283,17 +274,13 @@ struct pvr2_hdw {
        int flag_decoder_missed;/* We've noticed missing decoder */
        int flag_tripped;       /* Indicates overall failure to start */
 
-       struct pvr2_decoder_ctrl *decoder_ctrl;
+       unsigned int decoder_client_id;
 
        // CPU firmware info (used to help find / save firmware data)
        char *fw_buffer;
        unsigned int fw_size;
        int fw_cpu_flag; /* True if we are dealing with the CPU */
 
-       // True if there is a request to trigger logging of state in each
-       // module.
-       int log_requested;
-
        /* Tuner / frequency control stuff */
        unsigned int tuner_type;
        int tuner_updated;
@@ -391,7 +378,8 @@ struct pvr2_hdw {
 
 /* This function gets the current frequency */
 unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *);
-void pvr2_hdw_set_decoder(struct pvr2_hdw *,struct pvr2_decoder_ctrl *);
+
+void pvr2_hdw_status_poll(struct pvr2_hdw *);
 
 #endif /* __PVRUSB2_HDW_INTERNAL_H */
 
index fa304e5f252a65df9f289af4ece6da1b1b071d28..7a65b42a4f53571abdba88c11d36bd83c7fad011 100644 (file)
 #include <linux/firmware.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/tuner.h>
 #include "pvrusb2.h"
 #include "pvrusb2-std.h"
 #include "pvrusb2-util.h"
 #include "pvrusb2-hdw.h"
 #include "pvrusb2-i2c-core.h"
-#include "pvrusb2-tuner.h"
 #include "pvrusb2-eeprom.h"
 #include "pvrusb2-hdw-internal.h"
 #include "pvrusb2-encoder.h"
 #include "pvrusb2-debug.h"
 #include "pvrusb2-fx2-cmd.h"
+#include "pvrusb2-wm8775.h"
+#include "pvrusb2-video-v4l.h"
+#include "pvrusb2-cx2584x-v4l.h"
+#include "pvrusb2-cs53l32a.h"
+#include "pvrusb2-audio.h"
 
 #define TV_MIN_FREQ     55250000L
 #define TV_MAX_FREQ    850000000L
@@ -104,6 +109,39 @@ MODULE_PARM_DESC(radio_freq, "specify initial radio frequency");
 /* size of a firmware chunk */
 #define FIRMWARE_CHUNK_SIZE 0x2000
 
+typedef void (*pvr2_subdev_update_func)(struct pvr2_hdw *,
+                                       struct v4l2_subdev *);
+
+static const pvr2_subdev_update_func pvr2_module_update_functions[] = {
+       [PVR2_CLIENT_ID_WM8775] = pvr2_wm8775_subdev_update,
+       [PVR2_CLIENT_ID_SAA7115] = pvr2_saa7115_subdev_update,
+       [PVR2_CLIENT_ID_MSP3400] = pvr2_msp3400_subdev_update,
+       [PVR2_CLIENT_ID_CX25840] = pvr2_cx25840_subdev_update,
+       [PVR2_CLIENT_ID_CS53L32A] = pvr2_cs53l32a_subdev_update,
+};
+
+static const char *module_names[] = {
+       [PVR2_CLIENT_ID_MSP3400] = "msp3400",
+       [PVR2_CLIENT_ID_CX25840] = "cx25840",
+       [PVR2_CLIENT_ID_SAA7115] = "saa7115",
+       [PVR2_CLIENT_ID_TUNER] = "tuner",
+       [PVR2_CLIENT_ID_DEMOD] = "tuner",
+       [PVR2_CLIENT_ID_CS53L32A] = "cs53l32a",
+       [PVR2_CLIENT_ID_WM8775] = "wm8775",
+};
+
+
+static const unsigned char *module_i2c_addresses[] = {
+       [PVR2_CLIENT_ID_TUNER] = "\x60\x61\x62\x63",
+       [PVR2_CLIENT_ID_DEMOD] = "\x43",
+       [PVR2_CLIENT_ID_MSP3400] = "\x40",
+       [PVR2_CLIENT_ID_SAA7115] = "\x21",
+       [PVR2_CLIENT_ID_WM8775] = "\x1b",
+       [PVR2_CLIENT_ID_CX25840] = "\x44",
+       [PVR2_CLIENT_ID_CS53L32A] = "\x11",
+};
+
+
 /* Define the list of additional controls we'll dynamically construct based
    on query of the cx2341x module. */
 struct pvr2_mpeg_ids {
@@ -277,7 +315,6 @@ static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v);
 static void pvr2_hdw_state_sched(struct pvr2_hdw *);
 static int pvr2_hdw_state_eval(struct pvr2_hdw *);
 static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
-static void pvr2_hdw_worker_i2c(struct work_struct *work);
 static void pvr2_hdw_worker_poll(struct work_struct *work);
 static int pvr2_hdw_wait(struct pvr2_hdw *,int state);
 static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *);
@@ -642,7 +679,7 @@ static int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp)
        unsigned long fv;
        struct pvr2_hdw *hdw = cptr->hdw;
        if (hdw->tuner_signal_stale) {
-               pvr2_i2c_core_status_poll(hdw);
+               pvr2_hdw_status_poll(hdw);
        }
        fv = hdw->tuner_signal_info.rangehigh;
        if (!fv) {
@@ -664,7 +701,7 @@ static int ctrl_freq_min_get(struct pvr2_ctrl *cptr, int *vp)
        unsigned long fv;
        struct pvr2_hdw *hdw = cptr->hdw;
        if (hdw->tuner_signal_stale) {
-               pvr2_i2c_core_status_poll(hdw);
+               pvr2_hdw_status_poll(hdw);
        }
        fv = hdw->tuner_signal_info.rangelow;
        if (!fv) {
@@ -858,7 +895,7 @@ static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
 static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp)
 {
        struct pvr2_hdw *hdw = cptr->hdw;
-       pvr2_i2c_core_status_poll(hdw);
+       pvr2_hdw_status_poll(hdw);
        *vp = hdw->tuner_signal_info.signal;
        return 0;
 }
@@ -868,7 +905,7 @@ static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
        int val = 0;
        unsigned int subchan;
        struct pvr2_hdw *hdw = cptr->hdw;
-       pvr2_i2c_core_status_poll(hdw);
+       pvr2_hdw_status_poll(hdw);
        subchan = hdw->tuner_signal_info.rxsubchans;
        if (subchan & V4L2_TUNER_SUB_MONO) {
                val |= (1 << V4L2_TUNER_MODE_MONO);
@@ -1283,6 +1320,12 @@ const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *hdw)
 }
 
 
+const char *pvr2_hdw_get_device_identifier(struct pvr2_hdw *hdw)
+{
+       return hdw->identifier;
+}
+
+
 unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw)
 {
        return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio;
@@ -1634,33 +1677,27 @@ static const char *pvr2_get_state_name(unsigned int st)
 
 static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl)
 {
-       if (!hdw->decoder_ctrl) {
-               if (!hdw->flag_decoder_missed) {
-                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                                  "WARNING: No decoder present");
-                       hdw->flag_decoder_missed = !0;
-                       trace_stbit("flag_decoder_missed",
-                                   hdw->flag_decoder_missed);
-               }
-               return -EIO;
+       /* Even though we really only care about the video decoder chip at
+          this point, we'll broadcast stream on/off to all sub-devices
+          anyway, just in case somebody else wants to hear the
+          command... */
+       pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 stream=%s",
+                  (enablefl ? "on" : "off"));
+       v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_stream, enablefl);
+       if (hdw->decoder_client_id) {
+               /* We get here if the encoder has been noticed.  Otherwise
+                  we'll issue a warning to the user (which should
+                  normally never happen). */
+               return 0;
        }
-       hdw->decoder_ctrl->enable(hdw->decoder_ctrl->ctxt,enablefl);
-       return 0;
-}
-
-
-void pvr2_hdw_set_decoder(struct pvr2_hdw *hdw,struct pvr2_decoder_ctrl *ptr)
-{
-       if (hdw->decoder_ctrl == ptr) return;
-       hdw->decoder_ctrl = ptr;
-       if (hdw->decoder_ctrl && hdw->flag_decoder_missed) {
-               hdw->flag_decoder_missed = 0;
+       if (!hdw->flag_decoder_missed) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "WARNING: No decoder present");
+               hdw->flag_decoder_missed = !0;
                trace_stbit("flag_decoder_missed",
                            hdw->flag_decoder_missed);
-               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                          "Decoder has appeared");
-               pvr2_hdw_state_sched(hdw);
        }
+       return -EIO;
 }
 
 
@@ -1927,6 +1964,166 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
 }
 
 
+static unsigned int pvr2_copy_i2c_addr_list(
+       unsigned short *dst, const unsigned char *src,
+       unsigned int dst_max)
+{
+       unsigned int cnt = 0;
+       if (!src) return 0;
+       while (src[cnt] && (cnt + 1) < dst_max) {
+               dst[cnt] = src[cnt];
+               cnt++;
+       }
+       dst[cnt] = I2C_CLIENT_END;
+       return cnt;
+}
+
+
+static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
+                               const struct pvr2_device_client_desc *cd)
+{
+       const char *fname;
+       unsigned char mid;
+       struct v4l2_subdev *sd;
+       unsigned int i2ccnt;
+       const unsigned char *p;
+       /* Arbitrary count - max # i2c addresses we will probe */
+       unsigned short i2caddr[25];
+
+       mid = cd->module_id;
+       fname = (mid < ARRAY_SIZE(module_names)) ? module_names[mid] : NULL;
+       if (!fname) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Module ID %u for device %s has no name",
+                          mid,
+                          hdw->hdw_desc->description);
+               return -EINVAL;
+       }
+       pvr2_trace(PVR2_TRACE_INIT,
+                  "Module ID %u (%s) for device %s being loaded...",
+                  mid, fname,
+                  hdw->hdw_desc->description);
+
+       i2ccnt = pvr2_copy_i2c_addr_list(i2caddr, cd->i2c_address_list,
+                                        ARRAY_SIZE(i2caddr));
+       if (!i2ccnt && ((p = (mid < ARRAY_SIZE(module_i2c_addresses)) ?
+                        module_i2c_addresses[mid] : NULL) != NULL)) {
+               /* Second chance: Try default i2c address list */
+               i2ccnt = pvr2_copy_i2c_addr_list(i2caddr, p,
+                                                ARRAY_SIZE(i2caddr));
+               if (i2ccnt) {
+                       pvr2_trace(PVR2_TRACE_INIT,
+                                  "Module ID %u:"
+                                  " Using default i2c address list",
+                                  mid);
+               }
+       }
+
+       if (!i2ccnt) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Module ID %u (%s) for device %s:"
+                          " No i2c addresses",
+                          mid, fname, hdw->hdw_desc->description);
+               return -EINVAL;
+       }
+
+       /* Note how the 2nd and 3rd arguments are the same for both
+        * v4l2_i2c_new_subdev() and v4l2_i2c_new_probed_subdev().  Why?
+        * Well the 2nd argument is the module name to load, while the 3rd
+        * argument is documented in the framework as being the "chipid" -
+        * and every other place where I can find examples of this, the
+        * "chipid" appears to just be the module name again.  So here we
+        * just do the same thing. */
+       if (i2ccnt == 1) {
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Module ID %u:"
+                          " Setting up with specified i2c address 0x%x",
+                          mid, i2caddr[0]);
+               sd = v4l2_i2c_new_subdev(&hdw->i2c_adap,
+                                        fname, fname,
+                                        i2caddr[0]);
+       } else {
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Module ID %u:"
+                          " Setting up with address probe list",
+                          mid);
+               sd = v4l2_i2c_new_probed_subdev(&hdw->i2c_adap,
+                                               fname, fname,
+                                               i2caddr);
+       }
+
+       if (!sd) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Module ID %u (%s) for device %s failed to load",
+                          mid, fname, hdw->hdw_desc->description);
+               return -EIO;
+       }
+
+       /* Tag this sub-device instance with the module ID we know about.
+          In other places we'll use that tag to determine if the instance
+          requires special handling. */
+       sd->grp_id = mid;
+
+       pvr2_trace(PVR2_TRACE_INFO, "Attached sub-driver %s", fname);
+
+
+       /* client-specific setup... */
+       switch (mid) {
+       case PVR2_CLIENT_ID_CX25840:
+               hdw->decoder_client_id = mid;
+               {
+                       /*
+                         Mike Isely <isely@pobox.com> 19-Nov-2006 - This
+                         bit of nuttiness for cx25840 causes that module
+                         to correctly set up its video scaling.  This is
+                         really a problem in the cx25840 module itself,
+                         but we work around it here.  The problem has not
+                         been seen in ivtv because there VBI is supported
+                         and set up.  We don't do VBI here (at least not
+                         yet) and thus we never attempted to even set it
+                         up.
+                       */
+                       struct v4l2_format fmt;
+                       pvr2_trace(PVR2_TRACE_INIT,
+                                  "Module ID %u:"
+                                  " Executing cx25840 VBI hack",
+                                  mid);
+                       memset(&fmt, 0, sizeof(fmt));
+                       fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+                       v4l2_device_call_all(&hdw->v4l2_dev, mid,
+                                            video, s_fmt, &fmt);
+               }
+               break;
+       case PVR2_CLIENT_ID_SAA7115:
+               hdw->decoder_client_id = mid;
+               break;
+       default: break;
+       }
+
+       return 0;
+}
+
+
+static void pvr2_hdw_load_modules(struct pvr2_hdw *hdw)
+{
+       unsigned int idx;
+       const struct pvr2_string_table *cm;
+       const struct pvr2_device_client_table *ct;
+       int okFl = !0;
+
+       cm = &hdw->hdw_desc->client_modules;
+       for (idx = 0; idx < cm->cnt; idx++) {
+               request_module(cm->lst[idx]);
+       }
+
+       ct = &hdw->hdw_desc->client_table;
+       for (idx = 0; idx < ct->cnt; idx++) {
+               if (pvr2_hdw_load_subdev(hdw, &ct->lst[idx]) < 0) okFl = 0;
+       }
+       if (!okFl) pvr2_hdw_render_useless(hdw);
+}
+
+
 static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
 {
        int ret;
@@ -1966,9 +2163,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
 
        if (!pvr2_hdw_dev_ok(hdw)) return;
 
-       for (idx = 0; idx < hdw->hdw_desc->client_modules.cnt; idx++) {
-               request_module(hdw->hdw_desc->client_modules.lst[idx]);
-       }
+       hdw->force_dirty = !0;
 
        if (!hdw->hdw_desc->flag_no_powerup) {
                pvr2_hdw_cmd_powerup(hdw);
@@ -1987,6 +2182,11 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
        pvr2_i2c_core_init(hdw);
        if (!pvr2_hdw_dev_ok(hdw)) return;
 
+       pvr2_hdw_load_modules(hdw);
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+
+       v4l2_device_call_all(&hdw->v4l2_dev, 0, core, init, 0);
+
        for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
                cptr = hdw->controls + idx;
                if (cptr->info->skip_init) continue;
@@ -2024,6 +2224,19 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
                hdw->std_mask_eeprom = V4L2_STD_ALL;
        }
 
+       if (hdw->serial_number) {
+               idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1,
+                               "sn-%lu", hdw->serial_number);
+       } else if (hdw->unit_number >= 0) {
+               idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1,
+                               "unit-%c",
+                               hdw->unit_number + 'a');
+       } else {
+               idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1,
+                               "unit-??");
+       }
+       hdw->identifier[idx] = 0;
+
        pvr2_hdw_setup_std(hdw);
 
        if (!get_default_tuner_type(hdw)) {
@@ -2032,8 +2245,6 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
                           hdw->tuner_type);
        }
 
-       pvr2_i2c_core_check_stale(hdw);
-       hdw->tuner_updated = 0;
 
        if (!pvr2_hdw_dev_ok(hdw)) return;
 
@@ -2171,11 +2382,14 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        struct pvr2_hdw *hdw = NULL;
        int valid_std_mask;
        struct pvr2_ctrl *cptr;
+       struct usb_device *usb_dev;
        const struct pvr2_device_desc *hdw_desc;
        __u8 ifnum;
        struct v4l2_queryctrl qctrl;
        struct pvr2_ctl_info *ciptr;
 
+       usb_dev = interface_to_usbdev(intf);
+
        hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info);
 
        if (hdw_desc == NULL) {
@@ -2360,6 +2574,11 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        hdw->ctl_read_urb = usb_alloc_urb(0,GFP_KERNEL);
        if (!hdw->ctl_read_urb) goto fail;
 
+       if (v4l2_device_register(&usb_dev->dev, &hdw->v4l2_dev) != 0) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Error registering with v4l core, giving up");
+               goto fail;
+       }
        mutex_lock(&pvr2_unit_mtx); do {
                for (idx = 0; idx < PVR_NUM; idx++) {
                        if (unit_pointers[idx]) continue;
@@ -2382,7 +2601,6 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 
        hdw->workqueue = create_singlethread_workqueue(hdw->name);
        INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll);
-       INIT_WORK(&hdw->worki2csync,pvr2_hdw_worker_i2c);
 
        pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
                   hdw->unit_number,hdw->name);
@@ -2391,12 +2609,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        hdw->flag_ok = !0;
 
        hdw->usb_intf = intf;
-       hdw->usb_dev = interface_to_usbdev(intf);
+       hdw->usb_dev = usb_dev;
 
-       scnprintf(hdw->bus_info,sizeof(hdw->bus_info),
-                 "usb %s address %d",
-                 dev_name(&hdw->usb_dev->dev),
-                 hdw->usb_dev->devnum);
+       usb_make_path(hdw->usb_dev, hdw->bus_info, sizeof(hdw->bus_info));
 
        ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber;
        usb_set_interface(hdw->usb_dev,ifnum,0);
@@ -2454,6 +2669,10 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw)
                hdw->ctl_write_buffer = NULL;
        }
        hdw->flag_disconnected = !0;
+       /* If we don't do this, then there will be a dangling struct device
+          reference to our disappearing device persisting inside the V4L
+          core... */
+       v4l2_device_disconnect(&hdw->v4l2_dev);
        hdw->usb_dev = NULL;
        hdw->usb_intf = NULL;
        pvr2_hdw_render_useless(hdw);
@@ -2481,10 +2700,8 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
                pvr2_stream_destroy(hdw->vid_stream);
                hdw->vid_stream = NULL;
        }
-       if (hdw->decoder_ctrl) {
-               hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
-       }
        pvr2_i2c_core_done(hdw);
+       v4l2_device_unregister(&hdw->v4l2_dev);
        pvr2_hdw_remove_usb_stuff(hdw);
        mutex_lock(&pvr2_unit_mtx); do {
                if ((hdw->unit_number >= 0) &&
@@ -2678,6 +2895,150 @@ static const char *get_ctrl_typename(enum pvr2_ctl_type tp)
 }
 
 
+static void pvr2_subdev_set_control(struct pvr2_hdw *hdw, int id,
+                                   const char *name, int val)
+{
+       struct v4l2_control ctrl;
+       pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 %s=%d", name, val);
+       memset(&ctrl, 0, sizeof(ctrl));
+       ctrl.id = id;
+       ctrl.value = val;
+       v4l2_device_call_all(&hdw->v4l2_dev, 0, core, s_ctrl, &ctrl);
+}
+
+#define PVR2_SUBDEV_SET_CONTROL(hdw, id, lab) \
+       if ((hdw)->lab##_dirty || (hdw)->force_dirty) {         \
+               pvr2_subdev_set_control(hdw, id, #lab, (hdw)->lab##_val); \
+       }
+
+/* Execute whatever commands are required to update the state of all the
+   sub-devices so that they match our current control values. */
+static void pvr2_subdev_update(struct pvr2_hdw *hdw)
+{
+       struct v4l2_subdev *sd;
+       unsigned int id;
+       pvr2_subdev_update_func fp;
+
+       pvr2_trace(PVR2_TRACE_CHIPS, "subdev update...");
+
+       if (hdw->tuner_updated || hdw->force_dirty) {
+               struct tuner_setup setup;
+               pvr2_trace(PVR2_TRACE_CHIPS, "subdev tuner set_type(%d)",
+                          hdw->tuner_type);
+               if (((int)(hdw->tuner_type)) >= 0) {
+                       setup.addr = ADDR_UNSET;
+                       setup.type = hdw->tuner_type;
+                       setup.mode_mask = T_RADIO | T_ANALOG_TV;
+                       v4l2_device_call_all(&hdw->v4l2_dev, 0,
+                                            tuner, s_type_addr, &setup);
+               }
+       }
+
+       if (hdw->input_dirty || hdw->std_dirty || hdw->force_dirty) {
+               pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_standard");
+               if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+                       v4l2_device_call_all(&hdw->v4l2_dev, 0,
+                                            tuner, s_radio);
+               } else {
+                       v4l2_std_id vs;
+                       vs = hdw->std_mask_cur;
+                       v4l2_device_call_all(&hdw->v4l2_dev, 0,
+                                            tuner, s_std, vs);
+               }
+               hdw->tuner_signal_stale = !0;
+               hdw->cropcap_stale = !0;
+       }
+
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_BRIGHTNESS, brightness);
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_CONTRAST, contrast);
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_SATURATION, saturation);
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_HUE, hue);
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_MUTE, mute);
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_VOLUME, volume);
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_BALANCE, balance);
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_BASS, bass);
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_TREBLE, treble);
+
+       if (hdw->input_dirty || hdw->audiomode_dirty || hdw->force_dirty) {
+               struct v4l2_tuner vt;
+               memset(&vt, 0, sizeof(vt));
+               vt.audmode = hdw->audiomode_val;
+               v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, s_tuner, &vt);
+       }
+
+       if (hdw->freqDirty || hdw->force_dirty) {
+               unsigned long fv;
+               struct v4l2_frequency freq;
+               fv = pvr2_hdw_get_cur_freq(hdw);
+               pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_freq(%lu)", fv);
+               if (hdw->tuner_signal_stale) pvr2_hdw_status_poll(hdw);
+               memset(&freq, 0, sizeof(freq));
+               if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+                       /* ((fv * 1000) / 62500) */
+                       freq.frequency = (fv * 2) / 125;
+               } else {
+                       freq.frequency = fv / 62500;
+               }
+               /* tuner-core currently doesn't seem to care about this, but
+                  let's set it anyway for completeness. */
+               if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+                       freq.type = V4L2_TUNER_RADIO;
+               } else {
+                       freq.type = V4L2_TUNER_ANALOG_TV;
+               }
+               freq.tuner = 0;
+               v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner,
+                                    s_frequency, &freq);
+       }
+
+       if (hdw->res_hor_dirty || hdw->res_ver_dirty || hdw->force_dirty) {
+               struct v4l2_format fmt;
+               memset(&fmt, 0, sizeof(fmt));
+               fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               fmt.fmt.pix.width = hdw->res_hor_val;
+               fmt.fmt.pix.height = hdw->res_ver_val;
+               pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_size(%dx%d)",
+                          fmt.fmt.pix.width, fmt.fmt.pix.height);
+               v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_fmt, &fmt);
+       }
+
+       if (hdw->srate_dirty || hdw->force_dirty) {
+               u32 val;
+               pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_audio %d",
+                          hdw->srate_val);
+               switch (hdw->srate_val) {
+               default:
+               case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
+                       val = 48000;
+                       break;
+               case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
+                       val = 44100;
+                       break;
+               case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
+                       val = 32000;
+                       break;
+               }
+               v4l2_device_call_all(&hdw->v4l2_dev, 0,
+                                    audio, s_clock_freq, val);
+       }
+
+       /* Unable to set crop parameters; there is apparently no equivalent
+          for VIDIOC_S_CROP */
+
+       v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
+               id = sd->grp_id;
+               if (id >= ARRAY_SIZE(pvr2_module_update_functions)) continue;
+               fp = pvr2_module_update_functions[id];
+               if (!fp) continue;
+               (*fp)(hdw, sd);
+       }
+
+       if (hdw->tuner_signal_stale || hdw->cropcap_stale) {
+               pvr2_hdw_status_poll(hdw);
+       }
+}
+
+
 /* Figure out if we need to commit control changes.  If so, mark internal
    state flags to indicate this fact and return true.  Otherwise do nothing
    else and return false. */
@@ -2686,7 +3047,7 @@ static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw)
        unsigned int idx;
        struct pvr2_ctrl *cptr;
        int value;
-       int commit_flag = 0;
+       int commit_flag = hdw->force_dirty;
        char buf[100];
        unsigned int bcnt,ccnt;
 
@@ -2842,18 +3203,6 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
                cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,VIDIOC_S_EXT_CTRLS);
        }
 
-       /* Scan i2c core at this point - before we clear all the dirty
-          bits.  Various parts of the i2c core will notice dirty bits as
-          appropriate and arrange to broadcast or directly send updates to
-          the client drivers in order to keep everything in sync */
-       pvr2_i2c_core_check_stale(hdw);
-
-       for (idx = 0; idx < hdw->control_cnt; idx++) {
-               cptr = hdw->controls + idx;
-               if (!cptr->info->clear_dirty) continue;
-               cptr->info->clear_dirty(cptr);
-       }
-
        if (hdw->active_stream_type != hdw->desired_stream_type) {
                /* Handle any side effects of stream config here */
                hdw->active_stream_type = hdw->desired_stream_type;
@@ -2873,8 +3222,16 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
                }
        }
 
-       /* Now execute i2c core update */
-       pvr2_i2c_core_sync(hdw);
+       /* Check and update state for all sub-devices. */
+       pvr2_subdev_update(hdw);
+
+       hdw->tuner_updated = 0;
+       hdw->force_dirty = 0;
+       for (idx = 0; idx < hdw->control_cnt; idx++) {
+               cptr = hdw->controls + idx;
+               if (!cptr->info->clear_dirty) continue;
+               cptr->info->clear_dirty(cptr);
+       }
 
        if ((hdw->pathway_state == PVR2_PATHWAY_ANALOG) &&
            hdw->state_encoder_run) {
@@ -2904,15 +3261,6 @@ int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw)
 }
 
 
-static void pvr2_hdw_worker_i2c(struct work_struct *work)
-{
-       struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,worki2csync);
-       LOCK_TAKE(hdw->big_lock); do {
-               pvr2_i2c_core_sync(hdw);
-       } while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
 static void pvr2_hdw_worker_poll(struct work_struct *work)
 {
        int fl = 0;
@@ -2973,7 +3321,7 @@ int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
 void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw)
 {
        LOCK_TAKE(hdw->big_lock); do {
-               pvr2_i2c_core_status_poll(hdw);
+               pvr2_hdw_status_poll(hdw);
        } while (0); LOCK_GIVE(hdw->big_lock);
 }
 
@@ -2983,7 +3331,7 @@ static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw)
        if (!hdw->cropcap_stale) {
                return 0;
        }
-       pvr2_i2c_core_status_poll(hdw);
+       pvr2_hdw_status_poll(hdw);
        if (hdw->cropcap_stale) {
                return -EIO;
        }
@@ -3010,7 +3358,7 @@ int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp)
 {
        LOCK_TAKE(hdw->big_lock); do {
                if (hdw->tuner_signal_stale) {
-                       pvr2_i2c_core_status_poll(hdw);
+                       pvr2_hdw_status_poll(hdw);
                }
                memcpy(vtp,&hdw->tuner_signal_info,sizeof(struct v4l2_tuner));
        } while (0); LOCK_GIVE(hdw->big_lock);
@@ -3029,11 +3377,8 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw)
 {
        int nr = pvr2_hdw_get_unit_number(hdw);
        LOCK_TAKE(hdw->big_lock); do {
-               hdw->log_requested = !0;
                printk(KERN_INFO "pvrusb2: =================  START STATUS CARD #%d  =================\n", nr);
-               pvr2_i2c_core_check_stale(hdw);
-               hdw->log_requested = 0;
-               pvr2_i2c_core_sync(hdw);
+               v4l2_device_call_all(&hdw->v4l2_dev, 0, core, log_status);
                pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:");
                cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2");
                pvr2_hdw_state_log_state(hdw);
@@ -3716,22 +4061,16 @@ int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *hdw)
 
 int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
 {
-       if (!hdw->decoder_ctrl) {
-               pvr2_trace(PVR2_TRACE_INIT,
-                          "Unable to reset decoder: nothing attached");
-               return -ENOTTY;
-       }
-
-       if (!hdw->decoder_ctrl->force_reset) {
-               pvr2_trace(PVR2_TRACE_INIT,
-                          "Unable to reset decoder: not implemented");
-               return -ENOTTY;
-       }
-
        pvr2_trace(PVR2_TRACE_INIT,
                   "Requesting decoder reset");
-       hdw->decoder_ctrl->force_reset(hdw->decoder_ctrl->ctxt);
-       return 0;
+       if (hdw->decoder_client_id) {
+               v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id,
+                                    core, reset, 0);
+               return 0;
+       }
+       pvr2_trace(PVR2_TRACE_INIT,
+                  "Unable to reset decoder: nothing attached");
+       return -ENOTTY;
 }
 
 
@@ -4476,6 +4815,79 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
 }
 
 
+/* Generate report containing info about attached sub-devices and attached
+   i2c clients, including an indication of which attached i2c clients are
+   actually sub-devices. */
+static unsigned int pvr2_hdw_report_clients(struct pvr2_hdw *hdw,
+                                           char *buf, unsigned int acnt)
+{
+       struct v4l2_subdev *sd;
+       unsigned int tcnt = 0;
+       unsigned int ccnt;
+       struct i2c_client *client;
+       struct list_head *item;
+       void *cd;
+       const char *p;
+       unsigned int id;
+
+       ccnt = scnprintf(buf, acnt, "Associated v4l2-subdev drivers:");
+       tcnt += ccnt;
+       v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
+               id = sd->grp_id;
+               p = NULL;
+               if (id < ARRAY_SIZE(module_names)) p = module_names[id];
+               if (p) {
+                       ccnt = scnprintf(buf + tcnt, acnt - tcnt, " %s", p);
+                       tcnt += ccnt;
+               } else {
+                       ccnt = scnprintf(buf + tcnt, acnt - tcnt,
+                                        " (unknown id=%u)", id);
+                       tcnt += ccnt;
+               }
+       }
+       ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n");
+       tcnt += ccnt;
+
+       ccnt = scnprintf(buf + tcnt, acnt - tcnt, "I2C clients:\n");
+       tcnt += ccnt;
+
+       mutex_lock(&hdw->i2c_adap.clist_lock);
+       list_for_each(item, &hdw->i2c_adap.clients) {
+               client = list_entry(item, struct i2c_client, list);
+               ccnt = scnprintf(buf + tcnt, acnt - tcnt,
+                                "  %s: i2c=%02x", client->name, client->addr);
+               tcnt += ccnt;
+               cd = i2c_get_clientdata(client);
+               v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
+                       if (cd == sd) {
+                               id = sd->grp_id;
+                               p = NULL;
+                               if (id < ARRAY_SIZE(module_names)) {
+                                       p = module_names[id];
+                               }
+                               if (p) {
+                                       ccnt = scnprintf(buf + tcnt,
+                                                        acnt - tcnt,
+                                                        " subdev=%s", p);
+                                       tcnt += ccnt;
+                               } else {
+                                       ccnt = scnprintf(buf + tcnt,
+                                                        acnt - tcnt,
+                                                        " subdev= id %u)",
+                                                        id);
+                                       tcnt += ccnt;
+                               }
+                               break;
+                       }
+               }
+               ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n");
+               tcnt += ccnt;
+       }
+       mutex_unlock(&hdw->i2c_adap.clist_lock);
+       return tcnt;
+}
+
+
 unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
                                   char *buf,unsigned int acnt)
 {
@@ -4490,6 +4902,8 @@ unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
                buf[0] = '\n'; ccnt = 1;
                bcnt += ccnt; acnt -= ccnt; buf += ccnt;
        }
+       ccnt = pvr2_hdw_report_clients(hdw, buf, acnt);
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
        LOCK_GIVE(hdw->big_lock);
        return bcnt;
 }
@@ -4497,14 +4911,25 @@ unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
 
 static void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw)
 {
-       char buf[128];
-       unsigned int idx,ccnt;
+       char buf[256];
+       unsigned int idx, ccnt;
+       unsigned int lcnt, ucnt;
 
        for (idx = 0; ; idx++) {
                ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,sizeof(buf));
                if (!ccnt) break;
                printk(KERN_INFO "%s %.*s\n",hdw->name,ccnt,buf);
        }
+       ccnt = pvr2_hdw_report_clients(hdw, buf, sizeof(buf));
+       ucnt = 0;
+       while (ucnt < ccnt) {
+               lcnt = 0;
+               while ((lcnt + ucnt < ccnt) && (buf[lcnt + ucnt] != '\n')) {
+                       lcnt++;
+               }
+               printk(KERN_INFO "%s %.*s\n", hdw->name, lcnt, buf + ucnt);
+               ucnt += lcnt + 1;
+       }
 }
 
 
@@ -4641,6 +5066,30 @@ int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val)
 }
 
 
+void pvr2_hdw_status_poll(struct pvr2_hdw *hdw)
+{
+       struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
+       memset(vtp, 0, sizeof(*vtp));
+       hdw->tuner_signal_stale = 0;
+       /* Note: There apparently is no replacement for VIDIOC_CROPCAP
+          using v4l2-subdev - therefore we can't support that AT ALL right
+          now.  (Of course, no sub-drivers seem to implement it either.
+          But now it's a a chicken and egg problem...) */
+       v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, g_tuner,
+                            &hdw->tuner_signal_info);
+       pvr2_trace(PVR2_TRACE_CHIPS, "subdev status poll"
+                  " type=%u strength=%u audio=0x%x cap=0x%x"
+                  " low=%u hi=%u",
+                  vtp->type,
+                  vtp->signal, vtp->rxsubchans, vtp->capability,
+                  vtp->rangelow, vtp->rangehigh);
+
+       /* We have to do this to avoid getting into constant polling if
+          there's nobody to answer a poll of cropcap info. */
+       hdw->cropcap_stale = 0;
+}
+
+
 unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *hdw)
 {
        return hdw->input_avail_mask;
@@ -4736,7 +5185,6 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
                             int setFl, u64 *val_ptr)
 {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       struct pvr2_i2c_client *cp;
        struct v4l2_dbg_register req;
        int stat = 0;
        int okFl = 0;
@@ -4746,21 +5194,9 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
        req.match = *match;
        req.reg = reg_id;
        if (setFl) req.val = *val_ptr;
-       mutex_lock(&hdw->i2c_list_lock); do {
-               list_for_each_entry(cp, &hdw->i2c_clients, list) {
-                       if (!v4l2_chip_match_i2c_client(
-                                   cp->client,
-                                   &req.match)) {
-                               continue;
-                       }
-                       stat = pvr2_i2c_client_cmd(
-                               cp,(setFl ? VIDIOC_DBG_S_REGISTER :
-                                   VIDIOC_DBG_G_REGISTER),&req);
-                       if (!setFl) *val_ptr = req.val;
-                       okFl = !0;
-                       break;
-               }
-       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+       /* It would be nice to know if a sub-device answered the request */
+       v4l2_device_call_all(&hdw->v4l2_dev, 0, core, g_register, &req);
+       if (!setFl) *val_ptr = req.val;
        if (okFl) {
                return stat;
        }
index 1b4fec337c6b2f694b2aa6a53d8a7f7afb60fe3d..7b6940554e9a93848fd99b04469b53281156a431 100644 (file)
@@ -132,6 +132,9 @@ unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *);
 /* Retrieve bus location info of device */
 const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *);
 
+/* Retrieve per-instance string identifier for this specific device */
+const char *pvr2_hdw_get_device_identifier(struct pvr2_hdw *);
+
 /* Called when hardware has been unplugged */
 void pvr2_hdw_disconnect(struct pvr2_hdw *);
 
@@ -236,8 +239,7 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,
                                     enum pvr2_v4l_type index,int);
 
 /* Direct read/write access to chip's registers:
-   match_type - how to interpret match_chip (e.g. driver ID, i2c address)
-   match_chip - chip match value (e.g. I2C_DRIVERD_xxxx)
+   match - specify criteria to identify target chip (this is a v4l dbg struct)
    reg_id  - register number to access
    setFl   - true to set the register, false to read it
    val_ptr - storage location for source / result. */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
deleted file mode 100644 (file)
index 94a4771..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- *
- *
- *  Copyright (C) 2005 Mike Isely <isely@pobox.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
- *
- *  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 "pvrusb2-i2c-core.h"
-#include "pvrusb2-hdw-internal.h"
-#include "pvrusb2-debug.h"
-#include "pvrusb2-i2c-cmd-v4l2.h"
-#include "pvrusb2-audio.h"
-#include "pvrusb2-tuner.h"
-#include "pvrusb2-video-v4l.h"
-#include "pvrusb2-cx2584x-v4l.h"
-#include "pvrusb2-wm8775.h"
-
-#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
-
-#define OP_STANDARD 0
-#define OP_AUDIOMODE 1
-#define OP_BCSH 2
-#define OP_VOLUME 3
-#define OP_FREQ 4
-#define OP_AUDIORATE 5
-#define OP_CROP 6
-#define OP_SIZE 7
-#define OP_LOG 8
-
-static const struct pvr2_i2c_op * const ops[] = {
-       [OP_STANDARD] = &pvr2_i2c_op_v4l2_standard,
-       [OP_AUDIOMODE] = &pvr2_i2c_op_v4l2_audiomode,
-       [OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh,
-       [OP_VOLUME] = &pvr2_i2c_op_v4l2_volume,
-       [OP_FREQ] = &pvr2_i2c_op_v4l2_frequency,
-       [OP_CROP] = &pvr2_i2c_op_v4l2_crop,
-       [OP_SIZE] = &pvr2_i2c_op_v4l2_size,
-       [OP_LOG] = &pvr2_i2c_op_v4l2_log,
-};
-
-void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
-{
-       int id;
-       id = cp->client->driver->id;
-       cp->ctl_mask = ((1 << OP_STANDARD) |
-                       (1 << OP_AUDIOMODE) |
-                       (1 << OP_BCSH) |
-                       (1 << OP_VOLUME) |
-                       (1 << OP_FREQ) |
-                       (1 << OP_CROP) |
-                       (1 << OP_SIZE) |
-                       (1 << OP_LOG));
-       cp->status_poll = pvr2_v4l2_cmd_status_poll;
-
-       if (id == I2C_DRIVERID_MSP3400) {
-               if (pvr2_i2c_msp3400_setup(hdw,cp)) {
-                       return;
-               }
-       }
-       if (id == I2C_DRIVERID_TUNER) {
-               if (pvr2_i2c_tuner_setup(hdw,cp)) {
-                       return;
-               }
-       }
-       if (id == I2C_DRIVERID_CX25840) {
-               if (pvr2_i2c_cx2584x_v4l_setup(hdw,cp)) {
-                       return;
-               }
-       }
-       if (id == I2C_DRIVERID_WM8775) {
-               if (pvr2_i2c_wm8775_setup(hdw,cp)) {
-                       return;
-               }
-       }
-       if (id == I2C_DRIVERID_SAA711X) {
-               if (pvr2_i2c_decoder_v4l_setup(hdw,cp)) {
-                       return;
-               }
-       }
-}
-
-
-const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx)
-{
-       if (idx >= ARRAY_SIZE(ops))
-               return NULL;
-       return ops[idx];
-}
-
-
-/*
-  Stuff for Emacs to see, in order to encourage consistent editing style:
-  *** Local Variables: ***
-  *** mode: c ***
-  *** fill-column: 75 ***
-  *** tab-width: 8 ***
-  *** c-basic-offset: 8 ***
-  *** End: ***
-  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
deleted file mode 100644 (file)
index 16bb119..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- *
- *
- *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- *  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
- *
- *  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 "pvrusb2-i2c-cmd-v4l2.h"
-#include "pvrusb2-hdw-internal.h"
-#include "pvrusb2-debug.h"
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-
-static void set_standard(struct pvr2_hdw *hdw)
-{
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_standard");
-
-       if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
-               pvr2_i2c_core_cmd(hdw,AUDC_SET_RADIO,NULL);
-       } else {
-               v4l2_std_id vs;
-               vs = hdw->std_mask_cur;
-               pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
-       }
-       hdw->tuner_signal_stale = !0;
-       hdw->cropcap_stale = !0;
-}
-
-
-static int check_standard(struct pvr2_hdw *hdw)
-{
-       return (hdw->input_dirty != 0) || (hdw->std_dirty != 0);
-}
-
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard = {
-       .check = check_standard,
-       .update = set_standard,
-       .name = "v4l2_standard",
-};
-
-
-static void set_bcsh(struct pvr2_hdw *hdw)
-{
-       struct v4l2_control ctrl;
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_bcsh"
-                  " b=%d c=%d s=%d h=%d",
-                  hdw->brightness_val,hdw->contrast_val,
-                  hdw->saturation_val,hdw->hue_val);
-       memset(&ctrl,0,sizeof(ctrl));
-       ctrl.id = V4L2_CID_BRIGHTNESS;
-       ctrl.value = hdw->brightness_val;
-       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
-       ctrl.id = V4L2_CID_CONTRAST;
-       ctrl.value = hdw->contrast_val;
-       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
-       ctrl.id = V4L2_CID_SATURATION;
-       ctrl.value = hdw->saturation_val;
-       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
-       ctrl.id = V4L2_CID_HUE;
-       ctrl.value = hdw->hue_val;
-       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
-}
-
-
-static int check_bcsh(struct pvr2_hdw *hdw)
-{
-       return (hdw->brightness_dirty ||
-               hdw->contrast_dirty ||
-               hdw->saturation_dirty ||
-               hdw->hue_dirty);
-}
-
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh = {
-       .check = check_bcsh,
-       .update = set_bcsh,
-       .name = "v4l2_bcsh",
-};
-
-
-static void set_volume(struct pvr2_hdw *hdw)
-{
-       struct v4l2_control ctrl;
-       pvr2_trace(PVR2_TRACE_CHIPS,
-                  "i2c v4l2 set_volume"
-                  "(vol=%d bal=%d bas=%d treb=%d mute=%d)",
-                  hdw->volume_val,
-                  hdw->balance_val,
-                  hdw->bass_val,
-                  hdw->treble_val,
-                  hdw->mute_val);
-       memset(&ctrl,0,sizeof(ctrl));
-       ctrl.id = V4L2_CID_AUDIO_MUTE;
-       ctrl.value = hdw->mute_val ? 1 : 0;
-       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
-       ctrl.id = V4L2_CID_AUDIO_VOLUME;
-       ctrl.value = hdw->volume_val;
-       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
-       ctrl.id = V4L2_CID_AUDIO_BALANCE;
-       ctrl.value = hdw->balance_val;
-       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
-       ctrl.id = V4L2_CID_AUDIO_BASS;
-       ctrl.value = hdw->bass_val;
-       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
-       ctrl.id = V4L2_CID_AUDIO_TREBLE;
-       ctrl.value = hdw->treble_val;
-       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
-}
-
-
-static int check_volume(struct pvr2_hdw *hdw)
-{
-       return (hdw->volume_dirty ||
-               hdw->balance_dirty ||
-               hdw->bass_dirty ||
-               hdw->treble_dirty ||
-               hdw->mute_dirty);
-}
-
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume = {
-       .check = check_volume,
-       .update = set_volume,
-       .name = "v4l2_volume",
-};
-
-
-static void set_audiomode(struct pvr2_hdw *hdw)
-{
-       struct v4l2_tuner vt;
-       memset(&vt,0,sizeof(vt));
-       vt.audmode = hdw->audiomode_val;
-       pvr2_i2c_core_cmd(hdw,VIDIOC_S_TUNER,&vt);
-}
-
-
-static int check_audiomode(struct pvr2_hdw *hdw)
-{
-       return (hdw->input_dirty ||
-               hdw->audiomode_dirty);
-}
-
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode = {
-       .check = check_audiomode,
-       .update = set_audiomode,
-       .name = "v4l2_audiomode",
-};
-
-
-static void set_frequency(struct pvr2_hdw *hdw)
-{
-       unsigned long fv;
-       struct v4l2_frequency freq;
-       fv = pvr2_hdw_get_cur_freq(hdw);
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_freq(%lu)",fv);
-       if (hdw->tuner_signal_stale) {
-               pvr2_i2c_core_status_poll(hdw);
-       }
-       memset(&freq,0,sizeof(freq));
-       if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
-               // ((fv * 1000) / 62500)
-               freq.frequency = (fv * 2) / 125;
-       } else {
-               freq.frequency = fv / 62500;
-       }
-       /* tuner-core currently doesn't seem to care about this, but
-          let's set it anyway for completeness. */
-       if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
-               freq.type = V4L2_TUNER_RADIO;
-       } else {
-               freq.type = V4L2_TUNER_ANALOG_TV;
-       }
-       freq.tuner = 0;
-       pvr2_i2c_core_cmd(hdw,VIDIOC_S_FREQUENCY,&freq);
-}
-
-
-static int check_frequency(struct pvr2_hdw *hdw)
-{
-       return hdw->freqDirty != 0;
-}
-
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency = {
-       .check = check_frequency,
-       .update = set_frequency,
-       .name = "v4l2_freq",
-};
-
-
-static void set_size(struct pvr2_hdw *hdw)
-{
-       struct v4l2_format fmt;
-
-       memset(&fmt,0,sizeof(fmt));
-
-       fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       fmt.fmt.pix.width = hdw->res_hor_val;
-       fmt.fmt.pix.height = hdw->res_ver_val;
-
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_size(%dx%d)",
-                          fmt.fmt.pix.width,fmt.fmt.pix.height);
-
-       pvr2_i2c_core_cmd(hdw,VIDIOC_S_FMT,&fmt);
-}
-
-
-static int check_size(struct pvr2_hdw *hdw)
-{
-       return (hdw->res_hor_dirty || hdw->res_ver_dirty);
-}
-
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size = {
-       .check = check_size,
-       .update = set_size,
-       .name = "v4l2_size",
-};
-
-
-static void set_crop(struct pvr2_hdw *hdw)
-{
-       struct v4l2_crop crop;
-
-       memset(&crop, 0, sizeof crop);
-       crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       crop.c.left = hdw->cropl_val;
-       crop.c.top = hdw->cropt_val;
-       crop.c.height = hdw->croph_val;
-       crop.c.width = hdw->cropw_val;
-
-       pvr2_trace(PVR2_TRACE_CHIPS,
-                  "i2c v4l2 set_crop crop=%d:%d:%d:%d",
-                  crop.c.width, crop.c.height, crop.c.left, crop.c.top);
-
-       pvr2_i2c_core_cmd(hdw, VIDIOC_S_CROP, &crop);
-}
-
-static int check_crop(struct pvr2_hdw *hdw)
-{
-       return (hdw->cropl_dirty || hdw->cropt_dirty ||
-               hdw->cropw_dirty || hdw->croph_dirty);
-}
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_crop = {
-       .check = check_crop,
-       .update = set_crop,
-       .name = "v4l2_crop",
-};
-
-
-static void do_log(struct pvr2_hdw *hdw)
-{
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 do_log()");
-       pvr2_i2c_core_cmd(hdw,VIDIOC_LOG_STATUS,NULL);
-
-}
-
-
-static int check_log(struct pvr2_hdw *hdw)
-{
-       return hdw->log_requested != 0;
-}
-
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log = {
-       .check = check_log,
-       .update = do_log,
-       .name = "v4l2_log",
-};
-
-
-void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl)
-{
-       pvr2_i2c_client_cmd(cp,
-                           (fl ? VIDIOC_STREAMON : VIDIOC_STREAMOFF),NULL);
-}
-
-
-void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *cp)
-{
-       int stat;
-       struct pvr2_hdw *hdw = cp->hdw;
-       if (hdw->cropcap_stale) {
-               hdw->cropcap_info.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               stat = pvr2_i2c_client_cmd(cp, VIDIOC_CROPCAP,
-                                          &hdw->cropcap_info);
-               if (stat == 0) {
-                       /* Check was successful, so the data is no
-                          longer considered stale. */
-                       hdw->cropcap_stale = 0;
-               }
-       }
-       pvr2_i2c_client_cmd(cp, VIDIOC_G_TUNER, &hdw->tuner_signal_info);
-}
-
-
-/*
-  Stuff for Emacs to see, in order to encourage consistent editing style:
-  *** Local Variables: ***
-  *** mode: c ***
-  *** fill-column: 70 ***
-  *** tab-width: 8 ***
-  *** c-basic-offset: 8 ***
-  *** End: ***
-  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
deleted file mode 100644 (file)
index eb744a2..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *
- *
- *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- *  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
- *
- *  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 __PVRUSB2_CMD_V4L2_H
-#define __PVRUSB2_CMD_V4L2_H
-
-#include "pvrusb2-i2c-core.h"
-
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_radio;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_crop;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log;
-
-void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *,int);
-void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *);
-
-#endif /* __PVRUSB2_CMD_V4L2_H */
-
-/*
-  Stuff for Emacs to see, in order to encourage consistent editing style:
-  *** Local Variables: ***
-  *** mode: c ***
-  *** fill-column: 70 ***
-  *** tab-width: 8 ***
-  *** c-basic-offset: 8 ***
-  *** End: ***
-  */
index d6a35401fefb78186ad40e758003a4c34b77ce84..9464862745fa35873a996568fc0c7c136cc06f0c 100644 (file)
@@ -18,6 +18,7 @@
  *
  */
 
+#include <linux/i2c.h>
 #include "pvrusb2-i2c-core.h"
 #include "pvrusb2-hdw-internal.h"
 #include "pvrusb2-debug.h"
@@ -29,8 +30,7 @@
 /*
 
   This module attempts to implement a compliant I2C adapter for the pvrusb2
-  device.  By doing this we can then make use of existing functionality in
-  V4L (e.g. tuner.c) rather than rolling our own.
+  device.
 
 */
 
@@ -42,10 +42,6 @@ static int ir_mode[PVR_NUM] = { [0 ... PVR_NUM-1] = 1 };
 module_param_array(ir_mode, int, NULL, 0444);
 MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR");
 
-static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
-                                            unsigned int detail,
-                                            char *buf,unsigned int maxlen);
-
 static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
                          u8 i2c_addr,      /* I2C address we're talking to */
                          u8 *data,         /* Data to write */
@@ -524,414 +520,13 @@ static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
        return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
 }
 
-static int pvr2_i2c_core_singleton(struct i2c_client *cp,
-                                  unsigned int cmd,void *arg)
-{
-       int stat;
-       if (!cp) return -EINVAL;
-       if (!(cp->driver)) return -EINVAL;
-       if (!(cp->driver->command)) return -EINVAL;
-       if (!try_module_get(cp->driver->driver.owner)) return -EAGAIN;
-       stat = cp->driver->command(cp,cmd,arg);
-       module_put(cp->driver->driver.owner);
-       return stat;
-}
-
-int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg)
-{
-       int stat;
-       if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
-               char buf[100];
-               unsigned int cnt;
-               cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
-                                              buf,sizeof(buf));
-               pvr2_trace(PVR2_TRACE_I2C_CMD,
-                          "i2c COMMAND (code=%u 0x%x) to %.*s",
-                          cmd,cmd,cnt,buf);
-       }
-       stat = pvr2_i2c_core_singleton(cp->client,cmd,arg);
-       if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
-               char buf[100];
-               unsigned int cnt;
-               cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
-                                              buf,sizeof(buf));
-               pvr2_trace(PVR2_TRACE_I2C_CMD,
-                          "i2c COMMAND to %.*s (ret=%d)",cnt,buf,stat);
-       }
-       return stat;
-}
-
-int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
-{
-       struct pvr2_i2c_client *cp, *ncp;
-       int stat = -EINVAL;
-
-       if (!hdw) return stat;
-
-       mutex_lock(&hdw->i2c_list_lock);
-       list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
-               if (!cp->recv_enable) continue;
-               mutex_unlock(&hdw->i2c_list_lock);
-               stat = pvr2_i2c_client_cmd(cp,cmd,arg);
-               mutex_lock(&hdw->i2c_list_lock);
-       }
-       mutex_unlock(&hdw->i2c_list_lock);
-       return stat;
-}
-
-
-static int handler_check(struct pvr2_i2c_client *cp)
-{
-       struct pvr2_i2c_handler *hp = cp->handler;
-       if (!hp) return 0;
-       if (!hp->func_table->check) return 0;
-       return hp->func_table->check(hp->func_data) != 0;
-}
-
-#define BUFSIZE 500
-
-
-void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
-{
-       struct pvr2_i2c_client *cp;
-       mutex_lock(&hdw->i2c_list_lock); do {
-               struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
-               memset(vtp,0,sizeof(*vtp));
-               list_for_each_entry(cp, &hdw->i2c_clients, list) {
-                       if (!cp->detected_flag) continue;
-                       if (!cp->status_poll) continue;
-                       cp->status_poll(cp);
-               }
-               hdw->tuner_signal_stale = 0;
-               pvr2_trace(PVR2_TRACE_CHIPS,"i2c status poll"
-                          " type=%u strength=%u audio=0x%x cap=0x%x"
-                          " low=%u hi=%u",
-                          vtp->type,
-                          vtp->signal,vtp->rxsubchans,vtp->capability,
-                          vtp->rangelow,vtp->rangehigh);
-       } while (0); mutex_unlock(&hdw->i2c_list_lock);
-}
-
-
-/* Issue various I2C operations to bring chip-level drivers into sync with
-   state stored in this driver. */
-void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
-{
-       unsigned long msk;
-       unsigned int idx;
-       struct pvr2_i2c_client *cp, *ncp;
-
-       if (!hdw->i2c_linked) return;
-       if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) {
-               return;
-       }
-       mutex_lock(&hdw->i2c_list_lock); do {
-               pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync BEGIN");
-               if (hdw->i2c_pend_types & PVR2_I2C_PEND_DETECT) {
-                       /* One or more I2C clients have attached since we
-                          last synced.  So scan the list and identify the
-                          new clients. */
-                       char *buf;
-                       unsigned int cnt;
-                       unsigned long amask = 0;
-                       buf = kmalloc(BUFSIZE,GFP_KERNEL);
-                       pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT");
-                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT;
-                       list_for_each_entry(cp, &hdw->i2c_clients, list) {
-                               if (!cp->detected_flag) {
-                                       cp->ctl_mask = 0;
-                                       pvr2_i2c_probe(hdw,cp);
-                                       cp->detected_flag = !0;
-                                       msk = cp->ctl_mask;
-                                       cnt = 0;
-                                       if (buf) {
-                                               cnt = pvr2_i2c_client_describe(
-                                                       cp,
-                                                       PVR2_I2C_DETAIL_ALL,
-                                                       buf,BUFSIZE);
-                                       }
-                                       trace_i2c("Probed: %.*s",cnt,buf);
-                                       if (handler_check(cp)) {
-                                               hdw->i2c_pend_types |=
-                                                       PVR2_I2C_PEND_CLIENT;
-                                       }
-                                       cp->pend_mask = msk;
-                                       hdw->i2c_pend_mask |= msk;
-                                       hdw->i2c_pend_types |=
-                                               PVR2_I2C_PEND_REFRESH;
-                               }
-                               amask |= cp->ctl_mask;
-                       }
-                       hdw->i2c_active_mask = amask;
-                       if (buf) kfree(buf);
-               }
-               if (hdw->i2c_pend_types & PVR2_I2C_PEND_STALE) {
-                       /* Need to do one or more global updates.  Arrange
-                          for this to happen. */
-                       unsigned long m2;
-                       pvr2_trace(PVR2_TRACE_I2C_CORE,
-                                  "i2c: PEND_STALE (0x%lx)",
-                                  hdw->i2c_stale_mask);
-                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE;
-                       list_for_each_entry(cp, &hdw->i2c_clients, list) {
-                               m2 = hdw->i2c_stale_mask;
-                               m2 &= cp->ctl_mask;
-                               m2 &= ~cp->pend_mask;
-                               if (m2) {
-                                       pvr2_trace(PVR2_TRACE_I2C_CORE,
-                                                  "i2c: cp=%p setting 0x%lx",
-                                                  cp,m2);
-                                       cp->pend_mask |= m2;
-                               }
-                       }
-                       hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
-                       hdw->i2c_stale_mask = 0;
-                       hdw->i2c_pend_types |= PVR2_I2C_PEND_REFRESH;
-               }
-               if (hdw->i2c_pend_types & PVR2_I2C_PEND_CLIENT) {
-                       /* One or more client handlers are asking for an
-                          update.  Run through the list of known clients
-                          and update each one. */
-                       pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT");
-                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT;
-                       list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients,
-                                                list) {
-                               if (!cp->handler) continue;
-                               if (!cp->handler->func_table->update) continue;
-                               pvr2_trace(PVR2_TRACE_I2C_CORE,
-                                          "i2c: cp=%p update",cp);
-                               mutex_unlock(&hdw->i2c_list_lock);
-                               cp->handler->func_table->update(
-                                       cp->handler->func_data);
-                               mutex_lock(&hdw->i2c_list_lock);
-                               /* If client's update function set some
-                                  additional pending bits, account for that
-                                  here. */
-                               if (cp->pend_mask & ~hdw->i2c_pend_mask) {
-                                       hdw->i2c_pend_mask |= cp->pend_mask;
-                                       hdw->i2c_pend_types |=
-                                               PVR2_I2C_PEND_REFRESH;
-                               }
-                       }
-               }
-               if (hdw->i2c_pend_types & PVR2_I2C_PEND_REFRESH) {
-                       const struct pvr2_i2c_op *opf;
-                       unsigned long pm;
-                       /* Some actual updates are pending.  Walk through
-                          each update type and perform it. */
-                       pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_REFRESH"
-                                  " (0x%lx)",hdw->i2c_pend_mask);
-                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_REFRESH;
-                       pm = hdw->i2c_pend_mask;
-                       hdw->i2c_pend_mask = 0;
-                       for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
-                               if (!(pm & msk)) continue;
-                               pm &= ~msk;
-                               list_for_each_entry(cp, &hdw->i2c_clients,
-                                                   list) {
-                                       if (cp->pend_mask & msk) {
-                                               cp->pend_mask &= ~msk;
-                                               cp->recv_enable = !0;
-                                       } else {
-                                               cp->recv_enable = 0;
-                                       }
-                               }
-                               opf = pvr2_i2c_get_op(idx);
-                               if (!opf) continue;
-                               mutex_unlock(&hdw->i2c_list_lock);
-                               opf->update(hdw);
-                               mutex_lock(&hdw->i2c_list_lock);
-                       }
-               }
-               pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync END");
-       } while (0); mutex_unlock(&hdw->i2c_list_lock);
-}
-
-int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw)
-{
-       unsigned long msk,sm,pm;
-       unsigned int idx;
-       const struct pvr2_i2c_op *opf;
-       struct pvr2_i2c_client *cp;
-       unsigned int pt = 0;
-
-       pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale BEGIN");
-
-       pm = hdw->i2c_active_mask;
-       sm = 0;
-       for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
-               if (!(msk & pm)) continue;
-               pm &= ~msk;
-               opf = pvr2_i2c_get_op(idx);
-               if (!opf) continue;
-               if (opf->check(hdw)) {
-                       sm |= msk;
-               }
-       }
-       if (sm) pt |= PVR2_I2C_PEND_STALE;
-
-       list_for_each_entry(cp, &hdw->i2c_clients, list)
-               if (handler_check(cp))
-                       pt |= PVR2_I2C_PEND_CLIENT;
-
-       if (pt) {
-               mutex_lock(&hdw->i2c_list_lock); do {
-                       hdw->i2c_pend_types |= pt;
-                       hdw->i2c_stale_mask |= sm;
-                       hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
-               } while (0); mutex_unlock(&hdw->i2c_list_lock);
-       }
-
-       pvr2_trace(PVR2_TRACE_I2C_CORE,
-                  "i2c: types=0x%x stale=0x%lx pend=0x%lx",
-                  hdw->i2c_pend_types,
-                  hdw->i2c_stale_mask,
-                  hdw->i2c_pend_mask);
-       pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale END");
-
-       return (hdw->i2c_pend_types & PVR2_I2C_PEND_ALL) != 0;
-}
-
-static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
-                                            unsigned int detail,
-                                            char *buf,unsigned int maxlen)
-{
-       unsigned int ccnt,bcnt;
-       int spcfl = 0;
-       const struct pvr2_i2c_op *opf;
-
-       ccnt = 0;
-       if (detail & PVR2_I2C_DETAIL_DEBUG) {
-               bcnt = scnprintf(buf,maxlen,
-                                "ctxt=%p ctl_mask=0x%lx",
-                                cp,cp->ctl_mask);
-               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-               spcfl = !0;
-       }
-       bcnt = scnprintf(buf,maxlen,
-                        "%s%s @ 0x%x",
-                        (spcfl ? " " : ""),
-                        cp->client->name,
-                        cp->client->addr);
-       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-       if ((detail & PVR2_I2C_DETAIL_HANDLER) &&
-           cp->handler && cp->handler->func_table->describe) {
-               bcnt = scnprintf(buf,maxlen," (");
-               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-               bcnt = cp->handler->func_table->describe(
-                       cp->handler->func_data,buf,maxlen);
-               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-               bcnt = scnprintf(buf,maxlen,")");
-               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-       }
-       if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) {
-               unsigned int idx;
-               unsigned long msk,sm;
-
-               bcnt = scnprintf(buf,maxlen," [");
-               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-               sm = 0;
-               spcfl = 0;
-               for (idx = 0, msk = 1; msk; idx++, msk <<= 1) {
-                       if (!(cp->ctl_mask & msk)) continue;
-                       opf = pvr2_i2c_get_op(idx);
-                       if (opf) {
-                               bcnt = scnprintf(buf,maxlen,"%s%s",
-                                                spcfl ? " " : "",
-                                                opf->name);
-                               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-                               spcfl = !0;
-                       } else {
-                               sm |= msk;
-                       }
-               }
-               if (sm) {
-                       bcnt = scnprintf(buf,maxlen,"%s%lx",
-                                        idx != 0 ? " " : "",sm);
-                       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-               }
-               bcnt = scnprintf(buf,maxlen,"]");
-               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-       }
-       return ccnt;
-}
-
-unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw,
-                            char *buf,unsigned int maxlen)
-{
-       unsigned int ccnt,bcnt;
-       struct pvr2_i2c_client *cp;
-       ccnt = 0;
-       mutex_lock(&hdw->i2c_list_lock); do {
-               list_for_each_entry(cp, &hdw->i2c_clients, list) {
-                       bcnt = pvr2_i2c_client_describe(
-                               cp,
-                               (PVR2_I2C_DETAIL_HANDLER|
-                                PVR2_I2C_DETAIL_CTLMASK),
-                               buf,maxlen);
-                       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-                       bcnt = scnprintf(buf,maxlen,"\n");
-                       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-               }
-       } while (0); mutex_unlock(&hdw->i2c_list_lock);
-       return ccnt;
-}
-
 static int pvr2_i2c_attach_inform(struct i2c_client *client)
 {
-       struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
-       struct pvr2_i2c_client *cp;
-       int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
-       cp = kzalloc(sizeof(*cp),GFP_KERNEL);
-       trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
-                 client->name,
-                 client->addr,cp);
-       if (!cp) return -ENOMEM;
-       cp->hdw = hdw;
-       INIT_LIST_HEAD(&cp->list);
-       cp->client = client;
-       mutex_lock(&hdw->i2c_list_lock); do {
-               hdw->cropcap_stale = !0;
-               list_add_tail(&cp->list,&hdw->i2c_clients);
-               hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
-       } while (0); mutex_unlock(&hdw->i2c_list_lock);
-       if (fl) queue_work(hdw->workqueue,&hdw->worki2csync);
        return 0;
 }
 
 static int pvr2_i2c_detach_inform(struct i2c_client *client)
 {
-       struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
-       struct pvr2_i2c_client *cp, *ncp;
-       unsigned long amask = 0;
-       int foundfl = 0;
-       mutex_lock(&hdw->i2c_list_lock); do {
-               hdw->cropcap_stale = !0;
-               list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
-                       if (cp->client == client) {
-                               trace_i2c("pvr2_i2c_detach"
-                                         " [client=%s @ 0x%x ctxt=%p]",
-                                         client->name,
-                                         client->addr,cp);
-                               if (cp->handler &&
-                                   cp->handler->func_table->detach) {
-                                       cp->handler->func_table->detach(
-                                               cp->handler->func_data);
-                               }
-                               list_del(&cp->list);
-                               kfree(cp);
-                               foundfl = !0;
-                               continue;
-                       }
-                       amask |= cp->ctl_mask;
-               }
-               hdw->i2c_active_mask = amask;
-       } while (0); mutex_unlock(&hdw->i2c_list_lock);
-       if (!foundfl) {
-               trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]",
-                         client->name,
-                         client->addr);
-       }
        return 0;
 }
 
@@ -942,7 +537,7 @@ static struct i2c_algorithm pvr2_i2c_algo_template = {
 
 static struct i2c_adapter pvr2_i2c_adap_template = {
        .owner         = THIS_MODULE,
-       .class     = I2C_CLASS_TV_ANALOG,
+       .class         = 0,
        .id            = I2C_HW_B_BT848,
        .client_register = pvr2_i2c_attach_inform,
        .client_unregister = pvr2_i2c_detach_inform,
@@ -1009,12 +604,8 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
        hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;
        hdw->i2c_adap.algo = &hdw->i2c_algo;
        hdw->i2c_adap.algo_data = hdw;
-       hdw->i2c_pend_mask = 0;
-       hdw->i2c_stale_mask = 0;
-       hdw->i2c_active_mask = 0;
-       INIT_LIST_HEAD(&hdw->i2c_clients);
-       mutex_init(&hdw->i2c_list_lock);
        hdw->i2c_linked = !0;
+       i2c_set_adapdata(&hdw->i2c_adap, &hdw->v4l2_dev);
        i2c_add_adapter(&hdw->i2c_adap);
        if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
                /* Probe for a different type of IR receiver on this
index 6ef7a1c0e93595630a23ff3b9eabd6c61a99d29e..6a75769200bde38ea4ba52409d66c6117043cc03 100644 (file)
 #ifndef __PVRUSB2_I2C_CORE_H
 #define __PVRUSB2_I2C_CORE_H
 
-#include <linux/list.h>
-#include <linux/i2c.h>
-
 struct pvr2_hdw;
-struct pvr2_i2c_client;
-struct pvr2_i2c_handler;
-struct pvr2_i2c_handler_functions;
-struct pvr2_i2c_op;
-struct pvr2_i2c_op_functions;
-
-struct pvr2_i2c_client {
-       struct i2c_client *client;
-       struct pvr2_i2c_handler *handler;
-       struct list_head list;
-       struct pvr2_hdw *hdw;
-       int detected_flag;
-       int recv_enable;
-       unsigned long pend_mask;
-       unsigned long ctl_mask;
-       void (*status_poll)(struct pvr2_i2c_client *);
-};
-
-struct pvr2_i2c_handler {
-       void *func_data;
-       const struct pvr2_i2c_handler_functions *func_table;
-};
-
-struct pvr2_i2c_handler_functions {
-       void (*detach)(void *);
-       int (*check)(void *);
-       void (*update)(void *);
-       unsigned int (*describe)(void *,char *,unsigned int);
-};
-
-struct pvr2_i2c_op {
-       int (*check)(struct pvr2_hdw *);
-       void (*update)(struct pvr2_hdw *);
-       const char *name;
-};
 
 void pvr2_i2c_core_init(struct pvr2_hdw *);
 void pvr2_i2c_core_done(struct pvr2_hdw *);
 
-int pvr2_i2c_client_cmd(struct pvr2_i2c_client *,unsigned int cmd,void *arg);
-int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg);
-
-int pvr2_i2c_core_check_stale(struct pvr2_hdw *);
-void pvr2_i2c_core_sync(struct pvr2_hdw *);
-void pvr2_i2c_core_status_poll(struct pvr2_hdw *);
-unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
-#define PVR2_I2C_DETAIL_DEBUG   0x0001
-#define PVR2_I2C_DETAIL_HANDLER 0x0002
-#define PVR2_I2C_DETAIL_CTLMASK 0x0004
-#define PVR2_I2C_DETAIL_ALL (\
-       PVR2_I2C_DETAIL_DEBUG |\
-       PVR2_I2C_DETAIL_HANDLER |\
-       PVR2_I2C_DETAIL_CTLMASK)
-
-void pvr2_i2c_probe(struct pvr2_hdw *,struct pvr2_i2c_client *);
-const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx);
 
-#endif /* __PVRUSB2_I2C_CORE_H */
+#endif /* __PVRUSB2_I2C_ADAPTER_H */
 
 
 /*
index 9b3c874d96d612c18bc07a9e72fb88f2fb78caad..8689ddb54420d05c0fb3b4e428aff6647a5ab719 100644 (file)
@@ -137,10 +137,10 @@ static int __init pvr_init(void)
        ret = usb_register(&pvr_driver);
 
        if (ret == 0)
-               printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+               printk(KERN_INFO "pvrusb2: " DRIVER_VERSION ":"
                       DRIVER_DESC "\n");
        if (pvrusb2_debug)
-               printk(KERN_INFO KBUILD_MODNAME ": Debug mask is %d (0x%x)\n",
+               printk(KERN_INFO "pvrusb2: Debug mask is %d (0x%x)\n",
                       pvrusb2_debug,pvrusb2_debug);
 
        pvr2_trace(PVR2_TRACE_INIT,"pvr_init complete");
index e641cd971453c2b6cb622ae1ff2c36d38cd7f831..e20ba1e6e0ea20e63d4a0a82ad23225d028dd58c 100644 (file)
@@ -627,16 +627,8 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
        pvr2_sysfs_trace("Creating class_dev id=%p",class_dev);
 
        class_dev->class = &class_ptr->class;
-       if (pvr2_hdw_get_sn(sfp->channel.hdw)) {
-               dev_set_name(class_dev, "sn-%lu",
-                        pvr2_hdw_get_sn(sfp->channel.hdw));
-       } else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) {
-               dev_set_name(class_dev, "unit-%c",
-                        pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a');
-       } else {
-               kfree(class_dev);
-               return;
-       }
+       dev_set_name(class_dev, "%s",
+                    pvr2_hdw_get_device_identifier(sfp->channel.hdw));
 
        class_dev->parent = &usb_dev->dev;
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.c b/drivers/media/video/pvrusb2/pvrusb2-tuner.c
deleted file mode 100644 (file)
index 07775d1..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- *
- *
- *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- *  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
- *
- *  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 "pvrusb2.h"
-#include "pvrusb2-util.h"
-#include "pvrusb2-tuner.h"
-#include "pvrusb2-hdw-internal.h"
-#include "pvrusb2-debug.h"
-#include <linux/videodev2.h>
-#include <media/tuner.h>
-#include <media/v4l2-common.h>
-
-struct pvr2_tuner_handler {
-       struct pvr2_hdw *hdw;
-       struct pvr2_i2c_client *client;
-       struct pvr2_i2c_handler i2c_handler;
-       int type_update_fl;
-};
-
-
-static void set_type(struct pvr2_tuner_handler *ctxt)
-{
-       struct pvr2_hdw *hdw = ctxt->hdw;
-       struct tuner_setup setup;
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c tuner set_type(%d)",hdw->tuner_type);
-       if (((int)(hdw->tuner_type)) < 0) return;
-
-       setup.addr = ADDR_UNSET;
-       setup.type = hdw->tuner_type;
-       setup.mode_mask = T_RADIO | T_ANALOG_TV;
-       /* We may really want mode_mask to be T_ANALOG_TV for now */
-       pvr2_i2c_client_cmd(ctxt->client,TUNER_SET_TYPE_ADDR,&setup);
-       ctxt->type_update_fl = 0;
-}
-
-
-static int tuner_check(struct pvr2_tuner_handler *ctxt)
-{
-       struct pvr2_hdw *hdw = ctxt->hdw;
-       if (hdw->tuner_updated) ctxt->type_update_fl = !0;
-       return ctxt->type_update_fl != 0;
-}
-
-
-static void tuner_update(struct pvr2_tuner_handler *ctxt)
-{
-       if (ctxt->type_update_fl) set_type(ctxt);
-}
-
-
-static void pvr2_tuner_detach(struct pvr2_tuner_handler *ctxt)
-{
-       ctxt->client->handler = NULL;
-       kfree(ctxt);
-}
-
-
-static unsigned int pvr2_tuner_describe(struct pvr2_tuner_handler *ctxt,char *buf,unsigned int cnt)
-{
-       return scnprintf(buf,cnt,"handler: pvrusb2-tuner");
-}
-
-
-static const struct pvr2_i2c_handler_functions tuner_funcs = {
-       .detach = (void (*)(void *))pvr2_tuner_detach,
-       .check = (int (*)(void *))tuner_check,
-       .update = (void (*)(void *))tuner_update,
-       .describe = (unsigned int (*)(void *,char *,unsigned int))pvr2_tuner_describe,
-};
-
-
-int pvr2_i2c_tuner_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
-{
-       struct pvr2_tuner_handler *ctxt;
-       if (cp->handler) return 0;
-
-       ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
-       if (!ctxt) return 0;
-
-       ctxt->i2c_handler.func_data = ctxt;
-       ctxt->i2c_handler.func_table = &tuner_funcs;
-       ctxt->type_update_fl = !0;
-       ctxt->client = cp;
-       ctxt->hdw = hdw;
-       cp->handler = &ctxt->i2c_handler;
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x tuner handler set up",
-                  cp->client->addr);
-       return !0;
-}
-
-
-
-
-/*
-  Stuff for Emacs to see, in order to encourage consistent editing style:
-  *** Local Variables: ***
-  *** mode: c ***
-  *** fill-column: 70 ***
-  *** tab-width: 8 ***
-  *** c-basic-offset: 8 ***
-  *** End: ***
-  */
index 878fd52a73b3a330df8cae9af1a0b5b9deae7bbc..9e0f2b07b93b277bed1123220b77eeb222956a02 100644 (file)
@@ -91,7 +91,7 @@ static struct v4l2_capability pvr_capability ={
        .card           = "Hauppauge WinTV pvr-usb2",
        .bus_info       = "usb",
        .version        = KERNEL_VERSION(0,8,0),
-       .capabilities   = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
+       .capabilities   = (V4L2_CAP_VIDEO_CAPTURE |
                           V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
                           V4L2_CAP_READWRITE),
        .reserved       = {0,0,0,0}
@@ -952,10 +952,6 @@ static long pvr2_v4l2_ioctl(struct file *file,
                           unsigned int cmd, unsigned long arg)
 {
 
-/* Temporary hack : use ivtv api until a v4l2 one is available. */
-#define IVTV_IOC_G_CODEC        0xFFEE7703
-#define IVTV_IOC_S_CODEC        0xFFEE7704
-       if (cmd == IVTV_IOC_G_CODEC || cmd == IVTV_IOC_S_CODEC) return 0;
        return video_usercopy(file, cmd, arg, pvr2_v4l2_do_ioctl);
 }
 
@@ -1268,8 +1264,9 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
                dip->minor_type = pvr2_v4l_type_video;
                nr_ptr = video_nr;
                if (!dip->stream) {
-                       err("Failed to set up pvrusb2 v4l video dev"
-                           " due to missing stream instance");
+                       pr_err(KBUILD_MODNAME
+                               ": Failed to set up pvrusb2 v4l video dev"
+                               " due to missing stream instance\n");
                        return;
                }
                break;
@@ -1286,8 +1283,8 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
                break;
        default:
                /* Bail out (this should be impossible) */
-               err("Failed to set up pvrusb2 v4l dev"
-                   " due to unrecognized config");
+               pr_err(KBUILD_MODNAME ": Failed to set up pvrusb2 v4l dev"
+                   " due to unrecognized config\n");
                return;
        }
 
@@ -1303,7 +1300,8 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
                                   dip->v4l_type, mindevnum) < 0) &&
            (video_register_device(&dip->devbase,
                                   dip->v4l_type, -1) < 0)) {
-               err("Failed to register pvrusb2 v4l device");
+               pr_err(KBUILD_MODNAME
+                       ": Failed to register pvrusb2 v4l device\n");
        }
 
        printk(KERN_INFO "pvrusb2: registered device %s%u [%s]\n",
index 4059648c70563341844c90697a79f03782b37ec2..b3862f5554bd92a9b4c0d3b7baaeaf651b0c573d 100644 (file)
@@ -28,7 +28,7 @@
 */
 
 #include "pvrusb2-video-v4l.h"
-#include "pvrusb2-i2c-cmd-v4l2.h"
+
 
 
 #include "pvrusb2-hdw-internal.h"
 #include <linux/errno.h>
 #include <linux/slab.h>
 
-struct pvr2_v4l_decoder {
-       struct pvr2_i2c_handler handler;
-       struct pvr2_decoder_ctrl ctrl;
-       struct pvr2_i2c_client *client;
-       struct pvr2_hdw *hdw;
-       unsigned long stale_mask;
-};
-
-
 struct routing_scheme {
        const int *def;
        unsigned int cnt;
@@ -63,190 +54,51 @@ static const int routing_scheme0[] = {
        [PVR2_CVAL_INPUT_SVIDEO] =  SAA7115_SVIDEO2,
 };
 
+static const int routing_scheme1[] = {
+       [PVR2_CVAL_INPUT_TV] = SAA7115_COMPOSITE4,
+       [PVR2_CVAL_INPUT_RADIO] = SAA7115_COMPOSITE5,
+       [PVR2_CVAL_INPUT_COMPOSITE] = SAA7115_COMPOSITE3,
+       [PVR2_CVAL_INPUT_SVIDEO] =  SAA7115_SVIDEO2, /* or SVIDEO0, it seems */
+};
+
 static const struct routing_scheme routing_schemes[] = {
        [PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
                .def = routing_scheme0,
                .cnt = ARRAY_SIZE(routing_scheme0),
        },
+       [PVR2_ROUTING_SCHEME_ONAIR] = {
+               .def = routing_scheme1,
+               .cnt = ARRAY_SIZE(routing_scheme1),
+       },
 };
 
-static void set_input(struct pvr2_v4l_decoder *ctxt)
-{
-       struct pvr2_hdw *hdw = ctxt->hdw;
-       struct v4l2_routing route;
-       const struct routing_scheme *sp;
-       unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
-
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val);
-
-       if ((sid < ARRAY_SIZE(routing_schemes)) &&
-           ((sp = routing_schemes + sid) != NULL) &&
-           (hdw->input_val >= 0) &&
-           (hdw->input_val < sp->cnt)) {
-               route.input = sp->def[hdw->input_val];
-       } else {
-               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                          "*** WARNING *** i2c v4l2 set_input:"
-                          " Invalid routing scheme (%u) and/or input (%d)",
-                          sid,hdw->input_val);
-               return;
-       }
-
-       route.output = 0;
-       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
-}
-
-
-static int check_input(struct pvr2_v4l_decoder *ctxt)
-{
-       struct pvr2_hdw *hdw = ctxt->hdw;
-       return hdw->input_dirty != 0;
-}
-
-
-static void set_audio(struct pvr2_v4l_decoder *ctxt)
-{
-       u32 val;
-       struct pvr2_hdw *hdw = ctxt->hdw;
-
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_audio %d",
-                  hdw->srate_val);
-       switch (hdw->srate_val) {
-       default:
-       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
-               val = 48000;
-               break;
-       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
-               val = 44100;
-               break;
-       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
-               val = 32000;
-               break;
-       }
-       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val);
-}
-
-
-static int check_audio(struct pvr2_v4l_decoder *ctxt)
-{
-       struct pvr2_hdw *hdw = ctxt->hdw;
-       return hdw->srate_dirty != 0;
-}
-
-
-struct pvr2_v4l_decoder_ops {
-       void (*update)(struct pvr2_v4l_decoder *);
-       int (*check)(struct pvr2_v4l_decoder *);
-};
-
-
-static const struct pvr2_v4l_decoder_ops decoder_ops[] = {
-       { .update = set_input, .check = check_input},
-       { .update = set_audio, .check = check_audio},
-};
-
-
-static void decoder_detach(struct pvr2_v4l_decoder *ctxt)
+void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
 {
-       ctxt->client->handler = NULL;
-       pvr2_hdw_set_decoder(ctxt->hdw,NULL);
-       kfree(ctxt);
-}
-
-
-static int decoder_check(struct pvr2_v4l_decoder *ctxt)
-{
-       unsigned long msk;
-       unsigned int idx;
-
-       for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
-               msk = 1 << idx;
-               if (ctxt->stale_mask & msk) continue;
-               if (decoder_ops[idx].check(ctxt)) {
-                       ctxt->stale_mask |= msk;
+       if (hdw->input_dirty || hdw->force_dirty) {
+               struct v4l2_routing route;
+               const struct routing_scheme *sp;
+               unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
+               pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_input(%d)",
+                          hdw->input_val);
+               if ((sid < ARRAY_SIZE(routing_schemes)) &&
+                   ((sp = routing_schemes + sid) != NULL) &&
+                   (hdw->input_val >= 0) &&
+                   (hdw->input_val < sp->cnt)) {
+                       route.input = sp->def[hdw->input_val];
+               } else {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "*** WARNING *** subdev v4l2 set_input:"
+                                  " Invalid routing scheme (%u)"
+                                  " and/or input (%d)",
+                                  sid, hdw->input_val);
+                       return;
                }
+               route.output = 0;
+               sd->ops->video->s_routing(sd, &route);
        }
-       return ctxt->stale_mask != 0;
-}
-
-
-static void decoder_update(struct pvr2_v4l_decoder *ctxt)
-{
-       unsigned long msk;
-       unsigned int idx;
-
-       for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
-               msk = 1 << idx;
-               if (!(ctxt->stale_mask & msk)) continue;
-               ctxt->stale_mask &= ~msk;
-               decoder_ops[idx].update(ctxt);
-       }
-}
-
-
-static int decoder_detect(struct pvr2_i2c_client *cp)
-{
-       /* Attempt to query the decoder - let's see if it will answer */
-       struct v4l2_tuner vt;
-       int ret;
-
-       memset(&vt,0,sizeof(vt));
-       ret = pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&vt);
-       return ret == 0; /* Return true if it answered */
-}
-
-
-static void decoder_enable(struct pvr2_v4l_decoder *ctxt,int fl)
-{
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 decoder_enable(%d)",fl);
-       pvr2_v4l2_cmd_stream(ctxt->client,fl);
-}
-
-
-static unsigned int decoder_describe(struct pvr2_v4l_decoder *ctxt,char *buf,unsigned int cnt)
-{
-       return scnprintf(buf,cnt,"handler: pvrusb2-video-v4l");
-}
-
-
-static const struct pvr2_i2c_handler_functions hfuncs = {
-       .detach = (void (*)(void *))decoder_detach,
-       .check = (int (*)(void *))decoder_check,
-       .update = (void (*)(void *))decoder_update,
-       .describe = (unsigned int (*)(void *,char *,unsigned int))decoder_describe,
-};
-
-
-int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
-                              struct pvr2_i2c_client *cp)
-{
-       struct pvr2_v4l_decoder *ctxt;
-
-       if (hdw->decoder_ctrl) return 0;
-       if (cp->handler) return 0;
-       if (!decoder_detect(cp)) return 0;
-
-       ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
-       if (!ctxt) return 0;
-
-       ctxt->handler.func_data = ctxt;
-       ctxt->handler.func_table = &hfuncs;
-       ctxt->ctrl.ctxt = ctxt;
-       ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
-       ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
-       ctxt->client = cp;
-       ctxt->hdw = hdw;
-       ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
-       pvr2_hdw_set_decoder(hdw,&ctxt->ctrl);
-       cp->handler = &ctxt->handler;
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up",
-                  cp->client->addr);
-       return !0;
 }
 
 
-
-
 /*
   Stuff for Emacs to see, in order to encourage consistent editing style:
   *** Local Variables: ***
index 4ff5b892b30338f66ddbedc940b570ed95d00e66..3b0bd5db602b81c6875b1e2112b3c27ef609d45b 100644 (file)
 */
 
 
-
-#include "pvrusb2-i2c-core.h"
-
-int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
-
+#include "pvrusb2-hdw-internal.h"
+void pvr2_saa7115_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *);
 
 #endif /* __PVRUSB2_VIDEO_V4L_H */
 
index f6fcf0ac61189ef33e0d9c3da977e12e8ce9c2a4..1670aa4051ce7ecf8df6cade0fcd9a80c2bfb70a 100644 (file)
@@ -27,7 +27,6 @@
 */
 
 #include "pvrusb2-wm8775.h"
-#include "pvrusb2-i2c-cmd-v4l2.h"
 
 
 #include "pvrusb2-hdw-internal.h"
 #include <linux/errno.h>
 #include <linux/slab.h>
 
-struct pvr2_v4l_wm8775 {
-       struct pvr2_i2c_handler handler;
-       struct pvr2_i2c_client *client;
-       struct pvr2_hdw *hdw;
-       unsigned long stale_mask;
-};
-
-
-static void set_input(struct pvr2_v4l_wm8775 *ctxt)
-{
-       struct v4l2_routing route;
-       struct pvr2_hdw *hdw = ctxt->hdw;
-
-       memset(&route,0,sizeof(route));
-
-       switch(hdw->input_val) {
-       case PVR2_CVAL_INPUT_RADIO:
-               route.input = 1;
-               break;
-       default:
-               /* All other cases just use the second input */
-               route.input = 2;
-               break;
-       }
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c wm8775 set_input(val=%d route=0x%x)",
-                  hdw->input_val,route.input);
-
-       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
-}
-
-static int check_input(struct pvr2_v4l_wm8775 *ctxt)
-{
-       struct pvr2_hdw *hdw = ctxt->hdw;
-       return hdw->input_dirty != 0;
-}
-
-
-struct pvr2_v4l_wm8775_ops {
-       void (*update)(struct pvr2_v4l_wm8775 *);
-       int (*check)(struct pvr2_v4l_wm8775 *);
-};
-
-
-static const struct pvr2_v4l_wm8775_ops wm8775_ops[] = {
-       { .update = set_input, .check = check_input},
-};
-
-
-static unsigned int wm8775_describe(struct pvr2_v4l_wm8775 *ctxt,
-                                    char *buf,unsigned int cnt)
-{
-       return scnprintf(buf,cnt,"handler: pvrusb2-wm8775");
-}
-
-
-static void wm8775_detach(struct pvr2_v4l_wm8775 *ctxt)
+void pvr2_wm8775_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
 {
-       ctxt->client->handler = NULL;
-       kfree(ctxt);
-}
-
-
-static int wm8775_check(struct pvr2_v4l_wm8775 *ctxt)
-{
-       unsigned long msk;
-       unsigned int idx;
-
-       for (idx = 0; idx < ARRAY_SIZE(wm8775_ops); idx++) {
-               msk = 1 << idx;
-               if (ctxt->stale_mask & msk) continue;
-               if (wm8775_ops[idx].check(ctxt)) {
-                       ctxt->stale_mask |= msk;
+       if (hdw->input_dirty || hdw->force_dirty) {
+               struct v4l2_routing route;
+
+               memset(&route, 0, sizeof(route));
+
+               switch (hdw->input_val) {
+               case PVR2_CVAL_INPUT_RADIO:
+                       route.input = 1;
+                       break;
+               default:
+                       /* All other cases just use the second input */
+                       route.input = 2;
+                       break;
                }
-       }
-       return ctxt->stale_mask != 0;
-}
-
-
-static void wm8775_update(struct pvr2_v4l_wm8775 *ctxt)
-{
-       unsigned long msk;
-       unsigned int idx;
+               pvr2_trace(PVR2_TRACE_CHIPS, "subdev wm8775"
+                          " set_input(val=%d route=0x%x)",
+                          hdw->input_val, route.input);
 
-       for (idx = 0; idx < ARRAY_SIZE(wm8775_ops); idx++) {
-               msk = 1 << idx;
-               if (!(ctxt->stale_mask & msk)) continue;
-               ctxt->stale_mask &= ~msk;
-               wm8775_ops[idx].update(ctxt);
+               sd->ops->audio->s_routing(sd, &route);
        }
 }
 
 
-static const struct pvr2_i2c_handler_functions hfuncs = {
-       .detach = (void (*)(void *))wm8775_detach,
-       .check = (int (*)(void *))wm8775_check,
-       .update = (void (*)(void *))wm8775_update,
-       .describe = (unsigned int (*)(void *,char *,unsigned int))wm8775_describe,
-};
-
-
-int pvr2_i2c_wm8775_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
-{
-       struct pvr2_v4l_wm8775 *ctxt;
-
-       if (cp->handler) return 0;
-
-       ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
-       if (!ctxt) return 0;
-
-       ctxt->handler.func_data = ctxt;
-       ctxt->handler.func_table = &hfuncs;
-       ctxt->client = cp;
-       ctxt->hdw = hdw;
-       ctxt->stale_mask = (1 << ARRAY_SIZE(wm8775_ops)) - 1;
-       cp->handler = &ctxt->handler;
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x wm8775 V4L2 handler set up",
-                  cp->client->addr);
-       return !0;
-}
-
-
-
 
 /*
   Stuff for Emacs to see, in order to encourage consistent editing style:
index 807090961255dd101698f4989e305d4605a0037f..0577bc7246fb40728ffcb98cbb7c1920e6db6f16 100644 (file)
@@ -34,9 +34,9 @@
 
 
 
-#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-hdw-internal.h"
 
-int pvr2_i2c_wm8775_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+void pvr2_wm8775_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *sd);
 
 
 #endif /* __PVRUSB2_WM8775_H */
index 7298cf2e1650f53f2c5e90f0873045d295e43c17..8b9f0aa844a19b8f63b5dd66134a43f9d7993aa0 100644 (file)
@@ -35,3 +35,13 @@ config USB_PWC_DEBUG
          Say Y here in order to have the pwc driver generate verbose debugging
          messages.
          A special module options 'trace' is used to control the verbosity.
+
+config USB_PWC_INPUT_EVDEV
+       bool "USB Philips Cameras input events device support"
+       default y
+       depends on USB_PWC && INPUT
+       ---help---
+         This option makes USB Philips cameras register the snapshot button as
+         an input device to report button events.
+
+         If you are in doubt, say Y.
index 0d810189dd87836861e1974267137e6325e5b7e4..7c542caf248e40ff1647bf0b4c6d6345448affd5 100644 (file)
@@ -53,6 +53,7 @@
    - Xavier Roche: QuickCam Pro 4000 ID
    - Jens Knudsen: QuickCam Zoom ID
    - J. Debert: QuickCam for Notebooks ID
+   - Pham Thanh Nam: webcam snapshot button as an event input device
 */
 
 #include <linux/errno.h>
@@ -61,6 +62,9 @@
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/slab.h>
+#ifdef CONFIG_USB_PWC_INPUT_EVDEV
+#include <linux/usb/input.h>
+#endif
 #include <linux/vmalloc.h>
 #include <asm/io.h>
 
@@ -586,6 +590,23 @@ static void pwc_frame_dumped(struct pwc_device *pdev)
                                pdev->vframe_count);
 }
 
+static void pwc_snapshot_button(struct pwc_device *pdev, int down)
+{
+       if (down) {
+               PWC_TRACE("Snapshot button pressed.\n");
+               pdev->snapshot_button_status = 1;
+       } else {
+               PWC_TRACE("Snapshot button released.\n");
+       }
+
+#ifdef CONFIG_USB_PWC_INPUT_EVDEV
+       if (pdev->button_dev) {
+               input_report_key(pdev->button_dev, BTN_0, down);
+               input_sync(pdev->button_dev);
+       }
+#endif
+}
+
 static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf)
 {
        int awake = 0;
@@ -603,13 +624,7 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_
                        pdev->vframes_error++;
                }
                if ((ptr[0] ^ pdev->vmirror) & 0x01) {
-                       if (ptr[0] & 0x01) {
-                               pdev->snapshot_button_status = 1;
-                               PWC_TRACE("Snapshot button pressed.\n");
-                       }
-                       else {
-                               PWC_TRACE("Snapshot button released.\n");
-                       }
+                       pwc_snapshot_button(pdev, ptr[0] & 0x01);
                }
                if ((ptr[0] ^ pdev->vmirror) & 0x02) {
                        if (ptr[0] & 0x02)
@@ -633,12 +648,7 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_
        else if (pdev->type == 740 || pdev->type == 720) {
                unsigned char *ptr = (unsigned char *)fbuf->data;
                if ((ptr[0] ^ pdev->vmirror) & 0x01) {
-                       if (ptr[0] & 0x01) {
-                               pdev->snapshot_button_status = 1;
-                               PWC_TRACE("Snapshot button pressed.\n");
-                       }
-                       else
-                               PWC_TRACE("Snapshot button released.\n");
+                       pwc_snapshot_button(pdev, ptr[0] & 0x01);
                }
                pdev->vmirror = ptr[0] & 0x03;
        }
@@ -1115,6 +1125,7 @@ static int pwc_video_open(struct file *file)
        }
 
        mutex_lock(&pdev->modlock);
+       pwc_construct(pdev); /* set min/max sizes correct */
        if (!pdev->usb_init) {
                PWC_DEBUG_OPEN("Doing first time initialization.\n");
                pdev->usb_init = 1;
@@ -1139,7 +1150,6 @@ static int pwc_video_open(struct file *file)
        if (pwc_set_leds(pdev, led_on, led_off) < 0)
                PWC_DEBUG_OPEN("Failed to set LED on/off time.\n");
 
-       pwc_construct(pdev); /* set min/max sizes correct */
 
        /* So far, so good. Allocate memory. */
        i = pwc_allocate_buffers(pdev);
@@ -1216,6 +1226,15 @@ static void pwc_cleanup(struct pwc_device *pdev)
 {
        pwc_remove_sysfs_files(pdev->vdev);
        video_unregister_device(pdev->vdev);
+
+#ifdef CONFIG_USB_PWC_INPUT_EVDEV
+       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
 }
 
 /* Note that all cleanup is done in the reverse order as in _open */
@@ -1483,6 +1502,9 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        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);
@@ -1807,6 +1829,35 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        pwc_set_leds(pdev, 0, 0);
        pwc_camera_power(pdev, 0);
 
+#ifdef CONFIG_USB_PWC_INPUT_EVDEV
+       /* register webcam snapshot button input device */
+       pdev->button_dev = input_allocate_device();
+       if (!pdev->button_dev) {
+               PWC_ERROR("Err, insufficient memory for webcam snapshot button device.");
+               return -ENOMEM;
+       }
+
+       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;
+       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);
+       pdev->button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+
+       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;
+       }
+#endif
+
        return 0;
 
 err_unreg:
index 01411fb2337ae9d0e392d2d0cd611889b1e8b2b7..0be6f814f5396cb7615484201db3a45a46f98ac5 100644 (file)
@@ -37,6 +37,9 @@
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#ifdef CONFIG_USB_PWC_INPUT_EVDEV
+#include <linux/input.h>
+#endif
 
 #include "pwc-uncompress.h"
 #include <media/pwc-ioctl.h>
@@ -255,6 +258,9 @@ struct pwc_device
    int pan_angle;                      /* in degrees * 100 */
    int tilt_angle;                     /* absolute angle; 0,0 is home position */
    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 */
+#endif
 
    /*** Misc. data ***/
    wait_queue_head_t frameq;           /* When waiting for a frame to finish... */
index 0c4ce58c53d53363afa9e7371a2e868b90dc34b5..c522616ef38f500006dd83075451a575de72e91e 100644 (file)
@@ -878,6 +878,7 @@ static int test_platform_param(struct pxa_camera_dev *pcdev,
                SOCAM_HSYNC_ACTIVE_LOW |
                SOCAM_VSYNC_ACTIVE_HIGH |
                SOCAM_VSYNC_ACTIVE_LOW |
+               SOCAM_DATA_ACTIVE_HIGH |
                SOCAM_PCLK_SAMPLE_RISING |
                SOCAM_PCLK_SAMPLE_FALLING;
 
@@ -1149,8 +1150,43 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
        return formats;
 }
 
+static int pxa_camera_set_crop(struct soc_camera_device *icd,
+                              struct v4l2_rect *rect)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct pxa_camera_dev *pcdev = ici->priv;
+       struct soc_camera_sense sense = {
+               .master_clock = pcdev->mclk,
+               .pixel_clock_max = pcdev->ciclk / 4,
+       };
+       int ret;
+
+       /* If PCLK is used to latch data from the sensor, check sense */
+       if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
+               icd->sense = &sense;
+
+       ret = icd->ops->set_crop(icd, rect);
+
+       icd->sense = NULL;
+
+       if (ret < 0) {
+               dev_warn(&ici->dev, "Failed to crop to %ux%u@%u:%u\n",
+                        rect->width, rect->height, rect->left, rect->top);
+       } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
+               if (sense.pixel_clock > sense.pixel_clock_max) {
+                       dev_err(&ici->dev,
+                               "pixel clock %lu set by the camera too high!",
+                               sense.pixel_clock);
+                       return -EIO;
+               }
+               recalculate_fifo_timeout(pcdev, sense.pixel_clock);
+       }
+
+       return ret;
+}
+
 static int pxa_camera_set_fmt(struct soc_camera_device *icd,
-                             __u32 pixfmt, struct v4l2_rect *rect)
+                             struct v4l2_format *f)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
@@ -1160,35 +1196,30 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
                .master_clock = pcdev->mclk,
                .pixel_clock_max = pcdev->ciclk / 4,
        };
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct v4l2_format cam_f = *f;
        int ret;
 
-       if (pixfmt) {
-               xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
-               if (!xlate) {
-                       dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
-                       return -EINVAL;
-               }
-
-               cam_fmt = xlate->cam_fmt;
+       xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+       if (!xlate) {
+               dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat);
+               return -EINVAL;
        }
 
+       cam_fmt = xlate->cam_fmt;
+
        /* If PCLK is used to latch data from the sensor, check sense */
        if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
                icd->sense = &sense;
 
-       switch (pixfmt) {
-       case 0:                         /* Only geometry change */
-               ret = icd->ops->set_fmt(icd, pixfmt, rect);
-               break;
-       default:
-               ret = icd->ops->set_fmt(icd, cam_fmt->fourcc, rect);
-       }
+       cam_f.fmt.pix.pixelformat = cam_fmt->fourcc;
+       ret = icd->ops->set_fmt(icd, &cam_f);
 
        icd->sense = NULL;
 
        if (ret < 0) {
                dev_warn(&ici->dev, "Failed to configure for format %x\n",
-                        pixfmt);
+                        pix->pixelformat);
        } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
                if (sense.pixel_clock > sense.pixel_clock_max) {
                        dev_err(&ici->dev,
@@ -1199,7 +1230,7 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
                recalculate_fifo_timeout(pcdev, sense.pixel_clock);
        }
 
-       if (pixfmt && !ret) {
+       if (!ret) {
                icd->buswidth = xlate->buswidth;
                icd->current_fmt = xlate->host_fmt;
        }
@@ -1363,6 +1394,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
        .remove         = pxa_camera_remove_device,
        .suspend        = pxa_camera_suspend,
        .resume         = pxa_camera_resume,
+       .set_crop       = pxa_camera_set_crop,
        .get_formats    = pxa_camera_get_formats,
        .set_fmt        = pxa_camera_set_fmt,
        .try_fmt        = pxa_camera_try_fmt,
index 13f85ad363cd3b7b81e5eae85675846b0452a966..b5be633e3bb0cb0683d7a085f553eb1a228c710c 100644 (file)
@@ -336,14 +336,19 @@ static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req,
                             u16 index, u16 value, void *buf,
                             s32 buf_len, int bOut);
 
+/* dev_err macro with driver name */
+#define S2255_DRIVER_NAME "s2255"
+#define s2255_dev_err(dev, fmt, arg...)                                        \
+               dev_err(dev, S2255_DRIVER_NAME " - " fmt, ##arg)
+
 #define dprintk(level, fmt, arg...)                                    \
        do {                                                            \
                if (*s2255_debug >= (level)) {                          \
-                       printk(KERN_DEBUG "s2255: " fmt, ##arg);        \
+                       printk(KERN_DEBUG S2255_DRIVER_NAME             \
+                               ": " fmt, ##arg);                       \
                }                                                       \
        } while (0)
 
-
 static struct usb_driver s2255_driver;
 
 
@@ -528,14 +533,14 @@ static void s2255_fwchunk_complete(struct urb *urb)
        int len;
        dprintk(100, "udev %p urb %p", udev, urb);
        if (urb->status) {
-               dev_err(&udev->dev, "URB failed with status %d", urb->status);
+               dev_err(&udev->dev, "URB failed with status %d\n", urb->status);
                atomic_set(&data->fw_state, S2255_FW_FAILED);
                /* wake up anything waiting for the firmware */
                wake_up(&data->wait_fw);
                return;
        }
        if (data->fw_urb == NULL) {
-               dev_err(&udev->dev, "s2255 disconnected\n");
+               s2255_dev_err(&udev->dev, "disconnected\n");
                atomic_set(&data->fw_state, S2255_FW_FAILED);
                /* wake up anything waiting for the firmware */
                wake_up(&data->wait_fw);
@@ -841,8 +846,7 @@ static int vidioc_querycap(struct file *file, void *priv,
        struct s2255_dev *dev = fh->dev;
        strlcpy(cap->driver, "s2255", sizeof(cap->driver));
        strlcpy(cap->card, "s2255", sizeof(cap->card));
-       strlcpy(cap->bus_info, dev_name(&dev->udev->dev),
-               sizeof(cap->bus_info));
+       usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
        cap->version = S2255_VERSION;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
        return 0;
@@ -1278,7 +1282,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
        }
 
        if (!res_get(dev, fh)) {
-               dev_err(&dev->udev->dev, "s2255: stream busy\n");
+               s2255_dev_err(&dev->udev->dev, "stream busy\n");
                return -EBUSY;
        }
 
@@ -1545,7 +1549,8 @@ static int s2255_open(struct file *file)
 
        switch (atomic_read(&dev->fw_data->fw_state)) {
        case S2255_FW_FAILED:
-               err("2255 firmware load failed. retrying.\n");
+               s2255_dev_err(&dev->udev->dev,
+                       "firmware load failed. retrying.\n");
                s2255_fwload_start(dev, 1);
                wait_event_timeout(dev->fw_data->wait_fw,
                                   ((atomic_read(&dev->fw_data->fw_state)
@@ -2173,7 +2178,8 @@ static int s2255_board_init(struct s2255_dev *dev)
 
        printk(KERN_INFO "2255 usb firmware version %d \n", fw_ver);
        if (fw_ver < CUR_USB_FWVER)
-               err("usb firmware not up to date %d\n", fw_ver);
+               dev_err(&dev->udev->dev,
+                       "usb firmware not up to date %d\n", fw_ver);
 
        for (j = 0; j < MAX_CHANNELS; j++) {
                dev->b_acquire[j] = 0;
@@ -2228,13 +2234,13 @@ static void read_pipe_completion(struct urb *purb)
        dprintk(100, "read pipe completion %p, status %d\n", purb,
                purb->status);
        if (pipe_info == NULL) {
-               err("no context !");
+               dev_err(&purb->dev->dev, "no context!\n");
                return;
        }
 
        dev = pipe_info->dev;
        if (dev == NULL) {
-               err("no context !");
+               dev_err(&purb->dev->dev, "no context!\n");
                return;
        }
        status = purb->status;
@@ -2286,7 +2292,7 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
                pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
                if (!pipe_info->stream_urb) {
                        dev_err(&dev->udev->dev,
-                               "ReadStream: Unable to alloc URB");
+                               "ReadStream: Unable to alloc URB\n");
                        return -ENOMEM;
                }
                /* transfer buffer allocated in board_init */
@@ -2391,7 +2397,7 @@ static void s2255_stop_readpipe(struct s2255_dev *dev)
        int j;
 
        if (dev == NULL) {
-               err("s2255: invalid device");
+               s2255_dev_err(&dev->udev->dev, "invalid device\n");
                return;
        }
        dprintk(4, "stop read pipe\n");
@@ -2453,7 +2459,7 @@ static int s2255_probe(struct usb_interface *interface,
        /* allocate memory for our device state and initialize it to zero */
        dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL);
        if (dev == NULL) {
-               err("s2255: out of memory");
+               s2255_dev_err(&interface->dev, "out of memory\n");
                goto error;
        }
 
@@ -2487,7 +2493,7 @@ static int s2255_probe(struct usb_interface *interface,
        }
 
        if (!dev->read_endpoint) {
-               dev_err(&interface->dev, "Could not find bulk-in endpoint");
+               dev_err(&interface->dev, "Could not find bulk-in endpoint\n");
                goto error;
        }
 
@@ -2583,7 +2589,7 @@ static void s2255_disconnect(struct usb_interface *interface)
 }
 
 static struct usb_driver s2255_driver = {
-       .name = "s2255",
+       .name = S2255_DRIVER_NAME,
        .probe = s2255_probe,
        .disconnect = s2255_disconnect,
        .id_table = s2255_table,
@@ -2597,7 +2603,8 @@ static int __init usb_s2255_init(void)
        result = usb_register(&s2255_driver);
 
        if (result)
-               err("usb_register failed. Error number %d", result);
+               pr_err(KBUILD_MODNAME
+                       ": usb_register failed. Error number %d\n", result);
 
        dprintk(2, "s2255_init: done\n");
        return result;
index e637e440b6d589eaba402bebff53e4e05f756467..da47b2f05288eed28aa467dfef63369be505c733 100644 (file)
 #include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/videotext.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ioctl.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
 MODULE_DESCRIPTION("Philips SAA5246A, SAA5281 Teletext decoder driver");
@@ -388,13 +389,19 @@ MODULE_LICENSE("GPL");
 
 struct saa5246a_device
 {
+       struct v4l2_subdev sd;
+       struct video_device *vdev;
        u8     pgbuf[NUM_DAUS][VTX_VIRTUALSIZE];
        int    is_searching[NUM_DAUS];
-       struct i2c_client *client;
        unsigned long in_use;
        struct mutex lock;
 };
 
+static inline struct saa5246a_device *to_dev(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct saa5246a_device, sd);
+}
+
 static struct video_device saa_template;       /* Declared near bottom */
 
 /*
@@ -403,12 +410,13 @@ static struct video_device saa_template;  /* Declared near bottom */
 
 static int i2c_sendbuf(struct saa5246a_device *t, int reg, int count, u8 *data)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
        char buf[64];
 
        buf[0] = reg;
        memcpy(buf+1, data, count);
 
-       if(i2c_master_send(t->client, buf, count+1)==count+1)
+       if (i2c_master_send(client, buf, count + 1) == count + 1)
                return 0;
        return -1;
 }
@@ -436,7 +444,9 @@ static int i2c_senddata(struct saa5246a_device *t, ...)
  */
 static int i2c_getdata(struct saa5246a_device *t, int count, u8 *buf)
 {
-       if(i2c_master_recv(t->client, buf, count)!=count)
+       struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
+
+       if (i2c_master_recv(client, buf, count) != count)
                return -1;
        return 0;
 }
@@ -961,9 +971,6 @@ static int saa5246a_open(struct file *file)
 {
        struct saa5246a_device *t = video_drvdata(file);
 
-       if (t->client == NULL)
-               return -ENODEV;
-
        if (test_and_set_bit(0, &t->in_use))
                return -EBUSY;
 
@@ -1033,18 +1040,29 @@ static struct video_device saa_template =
        .minor    = -1,
 };
 
-/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
+static int saa5246a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA5246A, 0);
+}
+
+static const struct v4l2_subdev_core_ops saa5246a_core_ops = {
+       .g_chip_ident = saa5246a_g_chip_ident,
+};
+
+static const struct v4l2_subdev_ops saa5246a_ops = {
+       .core = &saa5246a_core_ops,
+};
 
-I2C_CLIENT_INSMOD;
 
 static int saa5246a_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        int pgbuf;
        int err;
-       struct video_device *vd;
        struct saa5246a_device *t;
+       struct v4l2_subdev *sd;
 
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
@@ -1053,40 +1071,43 @@ static int saa5246a_probe(struct i2c_client *client,
        t = kzalloc(sizeof(*t), GFP_KERNEL);
        if (t == NULL)
                return -ENOMEM;
+       sd = &t->sd;
+       v4l2_i2c_subdev_init(sd, client, &saa5246a_ops);
        mutex_init(&t->lock);
 
        /* Now create a video4linux device */
-       vd = video_device_alloc();
-       if (vd == NULL) {
+       t->vdev = video_device_alloc();
+       if (t->vdev == NULL) {
                kfree(t);
                return -ENOMEM;
        }
-       i2c_set_clientdata(client, vd);
-       memcpy(vd, &saa_template, sizeof(*vd));
+       memcpy(t->vdev, &saa_template, sizeof(*t->vdev));
 
        for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
                memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0]));
                t->is_searching[pgbuf] = false;
        }
-       video_set_drvdata(vd, t);
+       video_set_drvdata(t->vdev, t);
 
        /* Register it */
-       err = video_register_device(vd, VFL_TYPE_VTX, -1);
+       err = video_register_device(t->vdev, VFL_TYPE_VTX, -1);
        if (err < 0) {
                kfree(t);
-               video_device_release(vd);
+               video_device_release(t->vdev);
+               t->vdev = NULL;
                return err;
        }
-       t->client = client;
        return 0;
 }
 
 static int saa5246a_remove(struct i2c_client *client)
 {
-       struct video_device *vd = i2c_get_clientdata(client);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct saa5246a_device *t = to_dev(sd);
 
-       video_unregister_device(vd);
-       kfree(video_get_drvdata(vd));
+       video_unregister_device(t->vdev);
+       v4l2_device_unregister_subdev(sd);
+       kfree(t);
        return 0;
 }
 
@@ -1098,7 +1119,6 @@ MODULE_DEVICE_TABLE(i2c, saa5246a_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "saa5246a",
-       .driverid = I2C_DRIVERID_SAA5249,
        .probe = saa5246a_probe,
        .remove = saa5246a_remove,
        .id_table = saa5246a_id,
index e297651924697ad8114977253ee509a5c3bfbefe..48b27fe48087c2446b2d4d452071c3aa4b696a44 100644 (file)
 #include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/videotext.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ioctl.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
 MODULE_DESCRIPTION("Philips SAA5249 Teletext decoder driver");
 MODULE_LICENSE("GPL");
 
+
 #define VTX_VER_MAJ 1
 #define VTX_VER_MIN 8
 
@@ -95,17 +97,23 @@ typedef struct {
 
 struct saa5249_device
 {
+       struct v4l2_subdev sd;
+       struct video_device *vdev;
        vdau_t vdau[NUM_DAUS];                  /* Data for virtual DAUs (the 5249 only has one */
                                                /* real DAU, so we have to simulate some more) */
        int vtx_use_count;
        int is_searching[NUM_DAUS];
        int disp_mode;
        int virtual_mode;
-       struct i2c_client *client;
        unsigned long in_use;
        struct mutex lock;
 };
 
+static inline struct saa5249_device *to_dev(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct saa5249_device, sd);
+}
+
 
 #define CCTWR 34               /* I²C write/read-address of vtx-chip */
 #define CCTRD 35
@@ -147,12 +155,13 @@ static void jdelay(unsigned long delay)
 
 static int i2c_sendbuf(struct saa5249_device *t, int reg, int count, u8 *data)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
        char buf[64];
 
        buf[0] = reg;
        memcpy(buf+1, data, count);
 
-       if (i2c_master_send(t->client, buf, count + 1) == count + 1)
+       if (i2c_master_send(client, buf, count + 1) == count + 1)
                return 0;
        return -1;
 }
@@ -180,7 +189,9 @@ static int i2c_senddata(struct saa5249_device *t, ...)
 
 static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
 {
-       if(i2c_master_recv(t->client, buf, count)!=count)
+       struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
+
+       if (i2c_master_recv(client, buf, count) != count)
                return -1;
        return 0;
 }
@@ -497,9 +508,6 @@ static int saa5249_open(struct file *file)
        struct saa5249_device *t = video_drvdata(file);
        int pgbuf;
 
-       if (t->client == NULL)
-               return -ENODEV;
-
        if (test_and_set_bit(0, &t->in_use))
                return -EBUSY;
 
@@ -553,18 +561,28 @@ static struct video_device saa_template =
        .release        = video_device_release,
 };
 
-/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
+static int saa5249_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA5249, 0);
+}
 
-I2C_CLIENT_INSMOD;
+static const struct v4l2_subdev_core_ops saa5249_core_ops = {
+       .g_chip_ident = saa5249_g_chip_ident,
+};
+
+static const struct v4l2_subdev_ops saa5249_ops = {
+       .core = &saa5249_core_ops,
+};
 
 static int saa5249_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        int pgbuf;
        int err;
-       struct video_device *vd;
        struct saa5249_device *t;
+       struct v4l2_subdev *sd;
 
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
@@ -573,16 +591,17 @@ static int saa5249_probe(struct i2c_client *client,
        t = kzalloc(sizeof(*t), GFP_KERNEL);
        if (t == NULL)
                return -ENOMEM;
+       sd = &t->sd;
+       v4l2_i2c_subdev_init(sd, client, &saa5249_ops);
        mutex_init(&t->lock);
 
        /* Now create a video4linux device */
-       vd = kmalloc(sizeof(struct video_device), GFP_KERNEL);
-       if (vd == NULL) {
+       t->vdev = video_device_alloc();
+       if (t->vdev == NULL) {
                kfree(client);
                return -ENOMEM;
        }
-       i2c_set_clientdata(client, vd);
-       memcpy(vd, &saa_template, sizeof(*vd));
+       memcpy(t->vdev, &saa_template, sizeof(*t->vdev));
 
        for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
                memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
@@ -593,26 +612,27 @@ static int saa5249_probe(struct i2c_client *client,
                t->vdau[pgbuf].stopped = true;
                t->is_searching[pgbuf] = false;
        }
-       video_set_drvdata(vd, t);
+       video_set_drvdata(t->vdev, t);
 
        /* Register it */
-       err = video_register_device(vd, VFL_TYPE_VTX, -1);
+       err = video_register_device(t->vdev, VFL_TYPE_VTX, -1);
        if (err < 0) {
                kfree(t);
-               kfree(vd);
+               video_device_release(t->vdev);
+               t->vdev = NULL;
                return err;
        }
-       t->client = client;
        return 0;
 }
 
 static int saa5249_remove(struct i2c_client *client)
 {
-       struct video_device *vd = i2c_get_clientdata(client);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct saa5249_device *t = to_dev(sd);
 
-       video_unregister_device(vd);
-       kfree(video_get_drvdata(vd));
-       kfree(vd);
+       video_unregister_device(t->vdev);
+       v4l2_device_unregister_subdev(sd);
+       kfree(t);
        return 0;
 }
 
@@ -624,7 +644,6 @@ MODULE_DEVICE_TABLE(i2c, saa5249_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "saa5249",
-       .driverid = I2C_DRIVERID_SAA5249,
        .probe = saa5249_probe,
        .remove = saa5249_remove,
        .id_table = saa5249_id,
index f05024259f0150707957dfc37b6e973ae0bcb011..c25e81af5ce09be383110d3d0452c53b3cd64074 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/kernel.h>
 #include <linux/i2c.h>
 #include <linux/types.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <asm/uaccess.h>
 
 #include <media/rds.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {
-       0x20 >> 1,
-       0x22 >> 1,
-       I2C_CLIENT_END,
-};
-
-I2C_CLIENT_INSMOD;
 
 /* insmod options */
 static unsigned int debug;
@@ -72,9 +67,8 @@ MODULE_LICENSE("GPL");
 #define dprintk     if (debug) printk
 
 struct saa6588 {
-       struct i2c_client client;
-       struct work_struct work;
-       struct timer_list timer;
+       struct v4l2_subdev sd;
+       struct delayed_work work;
        spinlock_t lock;
        unsigned char *buffer;
        unsigned int buf_size;
@@ -86,8 +80,10 @@ struct saa6588 {
        int data_available_for_read;
 };
 
-static struct i2c_driver driver;
-static struct i2c_client client_template;
+static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct saa6588, sd);
+}
 
 /* ---------------------------------------------------------------------- */
 
@@ -258,6 +254,7 @@ static void block_to_buf(struct saa6588 *s, unsigned char *blockbuf)
 
 static void saa6588_i2c_poll(struct saa6588 *s)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(&s->sd);
        unsigned long flags;
        unsigned char tmpbuf[6];
        unsigned char blocknum;
@@ -265,7 +262,7 @@ static void saa6588_i2c_poll(struct saa6588 *s)
 
        /* Although we only need 3 bytes, we have to read at least 6.
           SAA6588 returns garbage otherwise */
-       if (6 != i2c_master_recv(&s->client, &tmpbuf[0], 6)) {
+       if (6 != i2c_master_recv(client, &tmpbuf[0], 6)) {
                if (debug > 1)
                        dprintk(PREFIX "read error!\n");
                return;
@@ -316,23 +313,17 @@ static void saa6588_i2c_poll(struct saa6588 *s)
        wake_up_interruptible(&s->read_queue);
 }
 
-static void saa6588_timer(unsigned long data)
-{
-       struct saa6588 *s = (struct saa6588 *)data;
-
-       schedule_work(&s->work);
-}
-
 static void saa6588_work(struct work_struct *work)
 {
-       struct saa6588 *s = container_of(work, struct saa6588, work);
+       struct saa6588 *s = container_of(work, struct saa6588, work.work);
 
        saa6588_i2c_poll(s);
-       mod_timer(&s->timer, jiffies + msecs_to_jiffies(20));
+       schedule_delayed_work(&s->work, msecs_to_jiffies(20));
 }
 
 static int saa6588_configure(struct saa6588 *s)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(&s->sd);
        unsigned char buf[3];
        int rc;
 
@@ -380,7 +371,8 @@ static int saa6588_configure(struct saa6588 *s)
        dprintk(PREFIX "writing: 0w=0x%02x 1w=0x%02x 2w=0x%02x\n",
                buf[0], buf[1], buf[2]);
 
-       if (3 != (rc = i2c_master_send(&s->client, buf, 3)))
+       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;
@@ -388,70 +380,10 @@ static int saa6588_configure(struct saa6588 *s)
 
 /* ---------------------------------------------------------------------- */
 
-static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-       struct saa6588 *s;
-       client_template.adapter = adap;
-       client_template.addr = addr;
-
-       printk(PREFIX "chip found @ 0x%x\n", addr << 1);
-
-       if (NULL == (s = kmalloc(sizeof(*s), GFP_KERNEL)))
-               return -ENOMEM;
-
-       s->buf_size = bufblocks * 3;
-
-       if (NULL == (s->buffer = kmalloc(s->buf_size, GFP_KERNEL))) {
-               kfree(s);
-               return -ENOMEM;
-       }
-       spin_lock_init(&s->lock);
-       s->client = client_template;
-       s->block_count = 0;
-       s->wr_index = 0;
-       s->rd_index = 0;
-       s->last_blocknum = 0xff;
-       init_waitqueue_head(&s->read_queue);
-       s->data_available_for_read = 0;
-       i2c_set_clientdata(&s->client, s);
-       i2c_attach_client(&s->client);
-
-       saa6588_configure(s);
-
-       /* start polling via eventd */
-       INIT_WORK(&s->work, saa6588_work);
-       init_timer(&s->timer);
-       s->timer.function = saa6588_timer;
-       s->timer.data = (unsigned long)s;
-       schedule_work(&s->work);
-       return 0;
-}
-
-static int saa6588_probe(struct i2c_adapter *adap)
-{
-       if (adap->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adap, &addr_data, saa6588_attach);
-       return 0;
-}
-
-static int saa6588_detach(struct i2c_client *client)
-{
-       struct saa6588 *s = i2c_get_clientdata(client);
-
-       del_timer_sync(&s->timer);
-       flush_scheduled_work();
-
-       i2c_detach_client(client);
-       kfree(s->buffer);
-       kfree(s);
-       return 0;
-}
-
-static int saa6588_command(struct i2c_client *client, unsigned int cmd,
-                                                       void *arg)
+static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
-       struct saa6588 *s = i2c_get_clientdata(client);
-       struct rds_command *a = (struct rds_command *)arg;
+       struct saa6588 *s = to_saa6588(sd);
+       struct rds_command *a = arg;
 
        switch (cmd) {
                /* --- open() for /dev/radio --- */
@@ -479,45 +411,94 @@ static int saa6588_command(struct i2c_client *client, unsigned int cmd,
 
        default:
                /* nothing */
-               break;
+               return -ENOIOCTLCMD;
        }
        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);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA6588, 0);
+}
+
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver driver = {
-       .driver = {
-               .name = "saa6588",
-       },
-       .id = -1,               /* FIXME */
-       .attach_adapter = saa6588_probe,
-       .detach_client = saa6588_detach,
-       .command = saa6588_command,
+static const struct v4l2_subdev_core_ops saa6588_core_ops = {
+       .g_chip_ident = saa6588_g_chip_ident,
+       .ioctl = saa6588_ioctl,
 };
 
-static struct i2c_client client_template = {
-       .name = "saa6588",
-       .driver = &driver,
+static const struct v4l2_subdev_ops saa6588_ops = {
+       .core = &saa6588_core_ops,
 };
 
-static int __init saa6588_init_module(void)
+/* ---------------------------------------------------------------------- */
+
+static int saa6588_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
-       return i2c_add_driver(&driver);
+       struct saa6588 *s;
+       struct v4l2_subdev *sd;
+
+       v4l_info(client, "saa6588 found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+
+       s = kzalloc(sizeof(*s), GFP_KERNEL);
+       if (s == NULL)
+               return -ENOMEM;
+
+       s->buf_size = bufblocks * 3;
+
+       s->buffer = kmalloc(s->buf_size, GFP_KERNEL);
+       if (s->buffer == NULL) {
+               kfree(s);
+               return -ENOMEM;
+       }
+       sd = &s->sd;
+       v4l2_i2c_subdev_init(sd, client, &saa6588_ops);
+       spin_lock_init(&s->lock);
+       s->block_count = 0;
+       s->wr_index = 0;
+       s->rd_index = 0;
+       s->last_blocknum = 0xff;
+       init_waitqueue_head(&s->read_queue);
+       s->data_available_for_read = 0;
+
+       saa6588_configure(s);
+
+       /* start polling via eventd */
+       INIT_DELAYED_WORK(&s->work, saa6588_work);
+       schedule_delayed_work(&s->work, 0);
+       return 0;
 }
 
-static void __exit saa6588_cleanup_module(void)
+static int saa6588_remove(struct i2c_client *client)
 {
-       i2c_del_driver(&driver);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct saa6588 *s = to_saa6588(sd);
+
+       v4l2_device_unregister_subdev(sd);
+
+       cancel_delayed_work_sync(&s->work);
+
+       kfree(s->buffer);
+       kfree(s);
+       return 0;
 }
 
-module_init(saa6588_init_module);
-module_exit(saa6588_cleanup_module);
+/* ----------------------------------------------------------------------- */
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+static const struct i2c_device_id saa6588_id[] = {
+       { "saa6588", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, saa6588_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "saa6588",
+       .probe = saa6588_probe,
+       .remove = saa6588_remove,
+       .id_table = saa6588_id,
+};
index 37860698f7826aaf2f77e86aefc57e411ccac667..df4e08d2dceb7d83f04fc6b1bd3749486c991b7a 100644 (file)
 #include <linux/wait.h>
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
-#include <linux/videodev.h>
-#include <linux/video_decoder.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
 MODULE_AUTHOR("Pauline Middelink");
 MODULE_LICENSE("GPL");
 
+
 static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
@@ -52,9 +53,10 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 #define SAA7110_NR_REG         0x35
 
 struct saa7110 {
+       struct v4l2_subdev sd;
        u8 reg[SAA7110_NR_REG];
 
-       int norm;
+       v4l2_std_id norm;
        int input;
        int enable;
        int bright;
@@ -65,20 +67,28 @@ struct saa7110 {
        wait_queue_head_t wq;
 };
 
+static inline struct saa7110 *to_saa7110(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct saa7110, sd);
+}
+
 /* ----------------------------------------------------------------------- */
 /* I2C support functions                                                  */
 /* ----------------------------------------------------------------------- */
 
-static int saa7110_write(struct i2c_client *client, u8 reg, u8 value)
+static int saa7110_write(struct v4l2_subdev *sd, u8 reg, u8 value)
 {
-       struct saa7110 *decoder = i2c_get_clientdata(client);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct saa7110 *decoder = to_saa7110(sd);
 
        decoder->reg[reg] = value;
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static int saa7110_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
+static int saa7110_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct saa7110 *decoder = to_saa7110(sd);
        int ret = -1;
        u8 reg = *data;         /* first register to write to */
 
@@ -89,15 +99,13 @@ static int saa7110_write_block(struct i2c_client *client, const u8 *data, unsign
        /* the saa7110 has an autoincrement function, use it if
         * the adapter understands raw I2C */
        if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
-               struct saa7110 *decoder = i2c_get_clientdata(client);
-
                ret = i2c_master_send(client, data, len);
 
                /* Cache the written data */
                memcpy(decoder->reg + reg, data + 1, len - 1);
        } else {
                for (++data, --len; len; len--) {
-                       ret = saa7110_write(client, reg++, *data++);
+                       ret = saa7110_write(sd, reg++, *data++);
                        if (ret < 0)
                                break;
                }
@@ -106,8 +114,10 @@ static int saa7110_write_block(struct i2c_client *client, const u8 *data, unsign
        return ret;
 }
 
-static inline int saa7110_read(struct i2c_client *client)
+static inline int saa7110_read(struct v4l2_subdev *sd)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        return i2c_smbus_read_byte(client);
 }
 
@@ -115,11 +125,11 @@ static inline int saa7110_read(struct i2c_client *client)
 /* SAA7110 functions                                                      */
 /* ----------------------------------------------------------------------- */
 
-#define FRESP_06H_COMPST 0x03  //0x13
-#define FRESP_06H_SVIDEO 0x83  //0xC0
+#define FRESP_06H_COMPST 0x03  /*0x13*/
+#define FRESP_06H_SVIDEO 0x83  /*0xC0*/
 
 
-static int saa7110_selmux(struct i2c_client *client, int chan)
+static int saa7110_selmux(struct v4l2_subdev *sd, int chan)
 {
        static const unsigned char modes[9][8] = {
                /* mode 0 */
@@ -150,17 +160,17 @@ static int saa7110_selmux(struct i2c_client *client, int chan)
                {FRESP_06H_SVIDEO, 0x3C, 0x27, 0xC1, 0x23,
                              0x44, 0x75, 0x21}
        };
-       struct saa7110 *decoder = i2c_get_clientdata(client);
+       struct saa7110 *decoder = to_saa7110(sd);
        const unsigned char *ptr = modes[chan];
 
-       saa7110_write(client, 0x06, ptr[0]);    /* Luminance control    */
-       saa7110_write(client, 0x20, ptr[1]);    /* Analog Control #1    */
-       saa7110_write(client, 0x21, ptr[2]);    /* Analog Control #2    */
-       saa7110_write(client, 0x22, ptr[3]);    /* Mixer Control #1     */
-       saa7110_write(client, 0x2C, ptr[4]);    /* Mixer Control #2     */
-       saa7110_write(client, 0x30, ptr[5]);    /* ADCs gain control    */
-       saa7110_write(client, 0x31, ptr[6]);    /* Mixer Control #3     */
-       saa7110_write(client, 0x21, ptr[7]);    /* Analog Control #2    */
+       saa7110_write(sd, 0x06, ptr[0]);        /* Luminance control    */
+       saa7110_write(sd, 0x20, ptr[1]);        /* Analog Control #1    */
+       saa7110_write(sd, 0x21, ptr[2]);        /* Analog Control #2    */
+       saa7110_write(sd, 0x22, ptr[3]);        /* Mixer Control #1     */
+       saa7110_write(sd, 0x2C, ptr[4]);        /* Mixer Control #2     */
+       saa7110_write(sd, 0x30, ptr[5]);        /* ADCs gain control    */
+       saa7110_write(sd, 0x31, ptr[6]);        /* Mixer Control #3     */
+       saa7110_write(sd, 0x21, ptr[7]);        /* Analog Control #2    */
        decoder->input = chan;
 
        return 0;
@@ -176,246 +186,260 @@ static const unsigned char initseq[1 + SAA7110_NR_REG] = {
        /* 0x30 */ 0x44, 0x71, 0x02, 0x8C, 0x02
 };
 
-static int determine_norm(struct i2c_client *client)
+static v4l2_std_id determine_norm(struct v4l2_subdev *sd)
 {
        DEFINE_WAIT(wait);
-       struct saa7110 *decoder = i2c_get_clientdata(client);
+       struct saa7110 *decoder = to_saa7110(sd);
        int status;
 
        /* mode changed, start automatic detection */
-       saa7110_write_block(client, initseq, sizeof(initseq));
-       saa7110_selmux(client, decoder->input);
+       saa7110_write_block(sd, initseq, sizeof(initseq));
+       saa7110_selmux(sd, decoder->input);
        prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
        schedule_timeout(msecs_to_jiffies(250));
        finish_wait(&decoder->wq, &wait);
-       status = saa7110_read(client);
+       status = saa7110_read(sd);
        if (status & 0x40) {
-               v4l_dbg(1, debug, client, "status=0x%02x (no signal)\n", status);
-               return decoder->norm;   // no change
+               v4l2_dbg(1, debug, sd, "status=0x%02x (no signal)\n", status);
+               return decoder->norm;   /* no change*/
        }
        if ((status & 3) == 0) {
-               saa7110_write(client, 0x06, 0x83);
+               saa7110_write(sd, 0x06, 0x83);
                if (status & 0x20) {
-                       v4l_dbg(1, debug, client, "status=0x%02x (NTSC/no color)\n", status);
-                       //saa7110_write(client,0x2E,0x81);
-                       return VIDEO_MODE_NTSC;
+                       v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC/no color)\n", status);
+                       /*saa7110_write(sd,0x2E,0x81);*/
+                       return V4L2_STD_NTSC;
                }
-               v4l_dbg(1, debug, client, "status=0x%02x (PAL/no color)\n", status);
-               //saa7110_write(client,0x2E,0x9A);
-               return VIDEO_MODE_PAL;
+               v4l2_dbg(1, debug, sd, "status=0x%02x (PAL/no color)\n", status);
+               /*saa7110_write(sd,0x2E,0x9A);*/
+               return V4L2_STD_PAL;
        }
-       //saa7110_write(client,0x06,0x03);
+       /*saa7110_write(sd,0x06,0x03);*/
        if (status & 0x20) {    /* 60Hz */
-               v4l_dbg(1, debug, client, "status=0x%02x (NTSC)\n", status);
-               saa7110_write(client, 0x0D, 0x86);
-               saa7110_write(client, 0x0F, 0x50);
-               saa7110_write(client, 0x11, 0x2C);
-               //saa7110_write(client,0x2E,0x81);
-               return VIDEO_MODE_NTSC;
+               v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC)\n", status);
+               saa7110_write(sd, 0x0D, 0x86);
+               saa7110_write(sd, 0x0F, 0x50);
+               saa7110_write(sd, 0x11, 0x2C);
+               /*saa7110_write(sd,0x2E,0x81);*/
+               return V4L2_STD_NTSC;
        }
 
        /* 50Hz -> PAL/SECAM */
-       saa7110_write(client, 0x0D, 0x86);
-       saa7110_write(client, 0x0F, 0x10);
-       saa7110_write(client, 0x11, 0x59);
-       //saa7110_write(client,0x2E,0x9A);
+       saa7110_write(sd, 0x0D, 0x86);
+       saa7110_write(sd, 0x0F, 0x10);
+       saa7110_write(sd, 0x11, 0x59);
+       /*saa7110_write(sd,0x2E,0x9A);*/
 
        prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
        schedule_timeout(msecs_to_jiffies(250));
        finish_wait(&decoder->wq, &wait);
 
-       status = saa7110_read(client);
+       status = saa7110_read(sd);
        if ((status & 0x03) == 0x01) {
-               v4l_dbg(1, debug, client, "status=0x%02x (SECAM)\n", status);
-               saa7110_write(client, 0x0D, 0x87);
-               return VIDEO_MODE_SECAM;
+               v4l2_dbg(1, debug, sd, "status=0x%02x (SECAM)\n", status);
+               saa7110_write(sd, 0x0D, 0x87);
+               return V4L2_STD_SECAM;
        }
-       v4l_dbg(1, debug, client, "status=0x%02x (PAL)\n", status);
-       return VIDEO_MODE_PAL;
+       v4l2_dbg(1, debug, sd, "status=0x%02x (PAL)\n", status);
+       return V4L2_STD_PAL;
 }
 
-static int
-saa7110_command (struct i2c_client *client,
-                unsigned int       cmd,
-                void              *arg)
+static int saa7110_g_input_status(struct v4l2_subdev *sd, u32 *pstatus)
 {
-       struct saa7110 *decoder = i2c_get_clientdata(client);
-       int v;
+       struct saa7110 *decoder = to_saa7110(sd);
+       int res = V4L2_IN_ST_NO_SIGNAL;
+       int status = saa7110_read(sd);
+
+       v4l2_dbg(1, debug, sd, "status=0x%02x norm=%llx\n",
+                      status, (unsigned long long)decoder->norm);
+       if (!(status & 0x40))
+               res = 0;
+       if (!(status & 0x03))
+               res |= V4L2_IN_ST_NO_COLOR;
+
+       *pstatus = res;
+       return 0;
+}
 
-       switch (cmd) {
-       case 0:
-               //saa7110_write_block(client, initseq, sizeof(initseq));
-               break;
+static int saa7110_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+       *(v4l2_std_id *)std = determine_norm(sd);
+       return 0;
+}
 
-       case DECODER_GET_CAPABILITIES:
-       {
-               struct video_decoder_capability *dc = arg;
+static int saa7110_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct saa7110 *decoder = to_saa7110(sd);
+
+       if (decoder->norm != std) {
+               decoder->norm = std;
+               /*saa7110_write(sd, 0x06, 0x03);*/
+               if (std & V4L2_STD_NTSC) {
+                       saa7110_write(sd, 0x0D, 0x86);
+                       saa7110_write(sd, 0x0F, 0x50);
+                       saa7110_write(sd, 0x11, 0x2C);
+                       /*saa7110_write(sd, 0x2E, 0x81);*/
+                       v4l2_dbg(1, debug, sd, "switched to NTSC\n");
+               } else if (std & V4L2_STD_PAL) {
+                       saa7110_write(sd, 0x0D, 0x86);
+                       saa7110_write(sd, 0x0F, 0x10);
+                       saa7110_write(sd, 0x11, 0x59);
+                       /*saa7110_write(sd, 0x2E, 0x9A);*/
+                       v4l2_dbg(1, debug, sd, "switched to PAL\n");
+               } else if (std & V4L2_STD_SECAM) {
+                       saa7110_write(sd, 0x0D, 0x87);
+                       saa7110_write(sd, 0x0F, 0x10);
+                       saa7110_write(sd, 0x11, 0x59);
+                       /*saa7110_write(sd, 0x2E, 0x9A);*/
+                       v4l2_dbg(1, debug, sd, "switched to SECAM\n");
+               } else {
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
 
-               dc->flags =
-                   VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC |
-                   VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO;
-               dc->inputs = SAA7110_MAX_INPUT;
-               dc->outputs = SAA7110_MAX_OUTPUT;
-               break;
+static int saa7110_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct saa7110 *decoder = to_saa7110(sd);
+
+       if (route->input < 0 || route->input >= SAA7110_MAX_INPUT) {
+               v4l2_dbg(1, debug, sd, "input=%d not available\n", route->input);
+               return -EINVAL;
+       }
+       if (decoder->input != route->input) {
+               saa7110_selmux(sd, route->input);
+               v4l2_dbg(1, debug, sd, "switched to input=%d\n", route->input);
        }
+       return 0;
+}
 
-       case DECODER_GET_STATUS:
-       {
-               int status;
-               int res = 0;
-
-               status = saa7110_read(client);
-               v4l_dbg(1, debug, client, "status=0x%02x norm=%d\n",
-                              status, decoder->norm);
-               if (!(status & 0x40))
-                       res |= DECODER_STATUS_GOOD;
-               if (status & 0x03)
-                       res |= DECODER_STATUS_COLOR;
-
-               switch (decoder->norm) {
-               case VIDEO_MODE_NTSC:
-                       res |= DECODER_STATUS_NTSC;
-                       break;
-               case VIDEO_MODE_PAL:
-                       res |= DECODER_STATUS_PAL;
-                       break;
-               case VIDEO_MODE_SECAM:
-                       res |= DECODER_STATUS_SECAM;
-                       break;
-               }
-               *(int *) arg = res;
-               break;
+static int saa7110_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct saa7110 *decoder = to_saa7110(sd);
+
+       if (decoder->enable != enable) {
+               decoder->enable = enable;
+               saa7110_write(sd, 0x0E, enable ? 0x18 : 0x80);
+               v4l2_dbg(1, debug, sd, "YUV %s\n", enable ? "on" : "off");
        }
+       return 0;
+}
 
-       case DECODER_SET_NORM:
-               v = *(int *) arg;
-               if (decoder->norm != v) {
-                       decoder->norm = v;
-                       //saa7110_write(client, 0x06, 0x03);
-                       switch (v) {
-                       case VIDEO_MODE_NTSC:
-                               saa7110_write(client, 0x0D, 0x86);
-                               saa7110_write(client, 0x0F, 0x50);
-                               saa7110_write(client, 0x11, 0x2C);
-                               //saa7110_write(client, 0x2E, 0x81);
-                               v4l_dbg(1, debug, client, "switched to NTSC\n");
-                               break;
-                       case VIDEO_MODE_PAL:
-                               saa7110_write(client, 0x0D, 0x86);
-                               saa7110_write(client, 0x0F, 0x10);
-                               saa7110_write(client, 0x11, 0x59);
-                               //saa7110_write(client, 0x2E, 0x9A);
-                               v4l_dbg(1, debug, client, "switched to PAL\n");
-                               break;
-                       case VIDEO_MODE_SECAM:
-                               saa7110_write(client, 0x0D, 0x87);
-                               saa7110_write(client, 0x0F, 0x10);
-                               saa7110_write(client, 0x11, 0x59);
-                               //saa7110_write(client, 0x2E, 0x9A);
-                               v4l_dbg(1, debug, client, "switched to SECAM\n");
-                               break;
-                       case VIDEO_MODE_AUTO:
-                               v4l_dbg(1, debug, client, "switched to AUTO\n");
-                               decoder->norm = determine_norm(client);
-                               *(int *) arg = decoder->norm;
-                               break;
-                       default:
-                               return -EPERM;
-                       }
-               }
-               break;
+static int saa7110_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       switch (qc->id) {
+       case V4L2_CID_BRIGHTNESS:
+               return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
+       case V4L2_CID_CONTRAST:
+       case V4L2_CID_SATURATION:
+               return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
+       case V4L2_CID_HUE:
+               return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
 
-       case DECODER_SET_INPUT:
-               v = *(int *) arg;
-               if (v < 0 || v >= SAA7110_MAX_INPUT) {
-                       v4l_dbg(1, debug, client, "input=%d not available\n", v);
-                       return -EINVAL;
-               }
-               if (decoder->input != v) {
-                       saa7110_selmux(client, v);
-                       v4l_dbg(1, debug, client, "switched to input=%d\n", v);
-               }
-               break;
+static int saa7110_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct saa7110 *decoder = to_saa7110(sd);
 
-       case DECODER_SET_OUTPUT:
-               v = *(int *) arg;
-               /* not much choice of outputs */
-               if (v != 0)
-                       return -EINVAL;
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ctrl->value = decoder->bright;
                break;
-
-       case DECODER_ENABLE_OUTPUT:
-               v = *(int *) arg;
-               if (decoder->enable != v) {
-                       decoder->enable = v;
-                       saa7110_write(client, 0x0E, v ? 0x18 : 0x80);
-                       v4l_dbg(1, debug, client, "YUV %s\n", v ? "on" : "off");
-               }
+       case V4L2_CID_CONTRAST:
+               ctrl->value = decoder->contrast;
+               break;
+       case V4L2_CID_SATURATION:
+               ctrl->value = decoder->sat;
+               break;
+       case V4L2_CID_HUE:
+               ctrl->value = decoder->hue;
                break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
 
-       case DECODER_SET_PICTURE:
-       {
-               struct video_picture *pic = arg;
+static int saa7110_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct saa7110 *decoder = to_saa7110(sd);
 
-               if (decoder->bright != pic->brightness) {
-                       /* We want 0 to 255 we get 0-65535 */
-                       decoder->bright = pic->brightness;
-                       saa7110_write(client, 0x19, decoder->bright >> 8);
-               }
-               if (decoder->contrast != pic->contrast) {
-                       /* We want 0 to 127 we get 0-65535 */
-                       decoder->contrast = pic->contrast;
-                       saa7110_write(client, 0x13,
-                                     decoder->contrast >> 9);
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               if (decoder->bright != ctrl->value) {
+                       decoder->bright = ctrl->value;
+                       saa7110_write(sd, 0x19, decoder->bright);
                }
-               if (decoder->sat != pic->colour) {
-                       /* We want 0 to 127 we get 0-65535 */
-                       decoder->sat = pic->colour;
-                       saa7110_write(client, 0x12, decoder->sat >> 9);
+               break;
+       case V4L2_CID_CONTRAST:
+               if (decoder->contrast != ctrl->value) {
+                       decoder->contrast = ctrl->value;
+                       saa7110_write(sd, 0x13, decoder->contrast);
                }
-               if (decoder->hue != pic->hue) {
-                       /* We want -128 to 127 we get 0-65535 */
-                       decoder->hue = pic->hue;
-                       saa7110_write(client, 0x07,
-                                     (decoder->hue >> 8) - 128);
+               break;
+       case V4L2_CID_SATURATION:
+               if (decoder->sat != ctrl->value) {
+                       decoder->sat = ctrl->value;
+                       saa7110_write(sd, 0x12, decoder->sat);
                }
                break;
-       }
-
-       case DECODER_DUMP:
-               if (!debug)
-                       break;
-               for (v = 0; v < SAA7110_NR_REG; v += 16) {
-                       int j;
-                       v4l_dbg(1, debug, client, "%02x:", v);
-                       for (j = 0; j < 16 && v + j < SAA7110_NR_REG; j++)
-                               printk(KERN_CONT " %02x", decoder->reg[v + j]);
-                       printk(KERN_CONT "\n");
+       case V4L2_CID_HUE:
+               if (decoder->hue != ctrl->value) {
+                       decoder->hue = ctrl->value;
+                       saa7110_write(sd, 0x07, decoder->hue);
                }
                break;
-
        default:
-               v4l_dbg(1, debug, client, "unknown command %08x\n", cmd);
                return -EINVAL;
        }
        return 0;
 }
 
+static int saa7110_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7110, 0);
+}
+
 /* ----------------------------------------------------------------------- */
 
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
+static const struct v4l2_subdev_core_ops saa7110_core_ops = {
+       .g_chip_ident = saa7110_g_chip_ident,
+       .g_ctrl = saa7110_g_ctrl,
+       .s_ctrl = saa7110_s_ctrl,
+       .queryctrl = saa7110_queryctrl,
+};
 
-static unsigned short normal_i2c[] = { 0x9c >> 1, 0x9e >> 1, I2C_CLIENT_END };
+static const struct v4l2_subdev_tuner_ops saa7110_tuner_ops = {
+       .s_std = saa7110_s_std,
+};
 
-I2C_CLIENT_INSMOD;
+static const struct v4l2_subdev_video_ops saa7110_video_ops = {
+       .s_routing = saa7110_s_routing,
+       .s_stream = saa7110_s_stream,
+       .querystd = saa7110_querystd,
+       .g_input_status = saa7110_g_input_status,
+};
+
+static const struct v4l2_subdev_ops saa7110_ops = {
+       .core = &saa7110_core_ops,
+       .tuner = &saa7110_tuner_ops,
+       .video = &saa7110_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
 
 static int saa7110_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        struct saa7110 *decoder;
+       struct v4l2_subdev *sd;
        int rv;
 
        /* Check if the adapter supports the needed features */
@@ -429,7 +453,9 @@ static int saa7110_probe(struct i2c_client *client,
        decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL);
        if (!decoder)
                return -ENOMEM;
-       decoder->norm = VIDEO_MODE_PAL;
+       sd = &decoder->sd;
+       v4l2_i2c_subdev_init(sd, client, &saa7110_ops);
+       decoder->norm = V4L2_STD_PAL;
        decoder->input = 0;
        decoder->enable = 1;
        decoder->bright = 32768;
@@ -437,30 +463,29 @@ static int saa7110_probe(struct i2c_client *client,
        decoder->hue = 32768;
        decoder->sat = 32768;
        init_waitqueue_head(&decoder->wq);
-       i2c_set_clientdata(client, decoder);
 
-       rv = saa7110_write_block(client, initseq, sizeof(initseq));
+       rv = saa7110_write_block(sd, initseq, sizeof(initseq));
        if (rv < 0) {
-               v4l_dbg(1, debug, client, "init status %d\n", rv);
+               v4l2_dbg(1, debug, sd, "init status %d\n", rv);
        } else {
                int ver, status;
-               saa7110_write(client, 0x21, 0x10);
-               saa7110_write(client, 0x0e, 0x18);
-               saa7110_write(client, 0x0D, 0x04);
-               ver = saa7110_read(client);
-               saa7110_write(client, 0x0D, 0x06);
-               //mdelay(150);
-               status = saa7110_read(client);
-               v4l_dbg(1, debug, client, "version %x, status=0x%02x\n",
+               saa7110_write(sd, 0x21, 0x10);
+               saa7110_write(sd, 0x0e, 0x18);
+               saa7110_write(sd, 0x0D, 0x04);
+               ver = saa7110_read(sd);
+               saa7110_write(sd, 0x0D, 0x06);
+               /*mdelay(150);*/
+               status = saa7110_read(sd);
+               v4l2_dbg(1, debug, sd, "version %x, status=0x%02x\n",
                               ver, status);
-               saa7110_write(client, 0x0D, 0x86);
-               saa7110_write(client, 0x0F, 0x10);
-               saa7110_write(client, 0x11, 0x59);
-               //saa7110_write(client, 0x2E, 0x9A);
+               saa7110_write(sd, 0x0D, 0x86);
+               saa7110_write(sd, 0x0F, 0x10);
+               saa7110_write(sd, 0x11, 0x59);
+               /*saa7110_write(sd, 0x2E, 0x9A);*/
        }
 
-       //saa7110_selmux(client,0);
-       //determine_norm(client);
+       /*saa7110_selmux(sd,0);*/
+       /*determine_norm(sd);*/
        /* setup and implicit mode 0 select has been performed */
 
        return 0;
@@ -468,7 +493,10 @@ static int saa7110_probe(struct i2c_client *client,
 
 static int saa7110_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_saa7110(sd));
        return 0;
 }
 
@@ -482,8 +510,6 @@ MODULE_DEVICE_TABLE(i2c, saa7110_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "saa7110",
-       .driverid = I2C_DRIVERID_SAA7110,
-       .command = saa7110_command,
        .probe = saa7110_probe,
        .remove = saa7110_remove,
        .id_table = saa7110_id,
diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c
deleted file mode 100644 (file)
index a4738a2..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * saa7111 - Philips SAA7111A video decoder driver version 0.0.3
- *
- * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
- *
- * Slight changes for video timing and attachment output by
- * Wolfgang Scherr <scherr@net4you.net>
- *
- * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
- *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
- *
- * Changes by Michael Hunold <michael@mihu.de>
- *    - implemented DECODER_SET_GPIO, DECODER_INIT, DECODER_SET_VBI_BYPASS
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/ioctl.h>
-#include <asm/uaccess.h>
-#include <linux/i2c.h>
-#include <linux/i2c-id.h>
-#include <linux/videodev.h>
-#include <linux/video_decoder.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-i2c-drv-legacy.h>
-
-MODULE_DESCRIPTION("Philips SAA7111 video decoder driver");
-MODULE_AUTHOR("Dave Perks");
-MODULE_LICENSE("GPL");
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Debug level (0-1)");
-
-/* ----------------------------------------------------------------------- */
-
-#define SAA7111_NR_REG         0x18
-
-struct saa7111 {
-       unsigned char reg[SAA7111_NR_REG];
-
-       int norm;
-       int input;
-       int enable;
-};
-
-/* ----------------------------------------------------------------------- */
-
-static inline int saa7111_write(struct i2c_client *client, u8 reg, u8 value)
-{
-       struct saa7111 *decoder = i2c_get_clientdata(client);
-
-       decoder->reg[reg] = value;
-       return i2c_smbus_write_byte_data(client, reg, value);
-}
-
-static inline void saa7111_write_if_changed(struct i2c_client *client, u8 reg, u8 value)
-{
-       struct saa7111 *decoder = i2c_get_clientdata(client);
-
-       if (decoder->reg[reg] != value) {
-               decoder->reg[reg] = value;
-               i2c_smbus_write_byte_data(client, reg, value);
-       }
-}
-
-static int saa7111_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
-{
-       int ret = -1;
-       u8 reg;
-
-       /* the saa7111 has an autoincrement function, use it if
-        * the adapter understands raw I2C */
-       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
-               /* do raw I2C, not smbus compatible */
-               struct saa7111 *decoder = i2c_get_clientdata(client);
-               u8 block_data[32];
-               int block_len;
-
-               while (len >= 2) {
-                       block_len = 0;
-                       block_data[block_len++] = reg = data[0];
-                       do {
-                               block_data[block_len++] =
-                                   decoder->reg[reg++] = data[1];
-                               len -= 2;
-                               data += 2;
-                       } while (len >= 2 && data[0] == reg && block_len < 32);
-                       ret = i2c_master_send(client, block_data, block_len);
-                       if (ret < 0)
-                               break;
-               }
-       } else {
-               /* do some slow I2C emulation kind of thing */
-               while (len >= 2) {
-                       reg = *data++;
-                       ret = saa7111_write(client, reg, *data++);
-                       if (ret < 0)
-                               break;
-                       len -= 2;
-               }
-       }
-
-       return ret;
-}
-
-static int saa7111_init_decoder(struct i2c_client *client,
-               struct video_decoder_init *init)
-{
-       return saa7111_write_block(client, init->data, init->len);
-}
-
-static inline int saa7111_read(struct i2c_client *client, u8 reg)
-{
-       return i2c_smbus_read_byte_data(client, reg);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const unsigned char saa7111_i2c_init[] = {
-       0x00, 0x00,             /* 00 - ID byte */
-       0x01, 0x00,             /* 01 - reserved */
-
-       /*front end */
-       0x02, 0xd0,             /* 02 - FUSE=3, GUDL=2, MODE=0 */
-       0x03, 0x23,             /* 03 - HLNRS=0, VBSL=1, WPOFF=0,
-                                * HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
-       0x04, 0x00,             /* 04 - GAI1=256 */
-       0x05, 0x00,             /* 05 - GAI2=256 */
-
-       /* decoder */
-       0x06, 0xf3,             /* 06 - HSB at  13(50Hz) /  17(60Hz)
-                                * pixels after end of last line */
-       /*0x07, 0x13,     * 07 - HSS at 113(50Hz) / 117(60Hz) pixels
-                                * after end of last line */
-       0x07, 0xe8,             /* 07 - HSS seems to be needed to
-                                * work with NTSC, too */
-       0x08, 0xc8,             /* 08 - AUFD=1, FSEL=1, EXFIL=0,
-                                * VTRC=1, HPLL=0, VNOI=0 */
-       0x09, 0x01,             /* 09 - BYPS=0, PREF=0, BPSS=0,
-                                * VBLB=0, UPTCV=0, APER=1 */
-       0x0a, 0x80,             /* 0a - BRIG=128 */
-       0x0b, 0x47,             /* 0b - CONT=1.109 */
-       0x0c, 0x40,             /* 0c - SATN=1.0 */
-       0x0d, 0x00,             /* 0d - HUE=0 */
-       0x0e, 0x01,             /* 0e - CDTO=0, CSTD=0, DCCF=0,
-                                * FCTC=0, CHBW=1 */
-       0x0f, 0x00,             /* 0f - reserved */
-       0x10, 0x48,             /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
-       0x11, 0x1c,             /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1,
-                                * OEYC=1, OEHV=1, VIPB=0, COLO=0 */
-       0x12, 0x00,             /* 12 - output control 2 */
-       0x13, 0x00,             /* 13 - output control 3 */
-       0x14, 0x00,             /* 14 - reserved */
-       0x15, 0x00,             /* 15 - VBI */
-       0x16, 0x00,             /* 16 - VBI */
-       0x17, 0x00,             /* 17 - VBI */
-};
-
-static int saa7111_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       struct saa7111 *decoder = i2c_get_clientdata(client);
-
-       switch (cmd) {
-       case 0:
-               break;
-       case DECODER_INIT:
-       {
-               struct video_decoder_init *init = arg;
-               struct video_decoder_init vdi;
-
-               if (NULL != init)
-                       return saa7111_init_decoder(client, init);
-               vdi.data = saa7111_i2c_init;
-               vdi.len = sizeof(saa7111_i2c_init);
-               return saa7111_init_decoder(client, &vdi);
-       }
-
-       case DECODER_DUMP:
-       {
-               int i;
-
-               for (i = 0; i < SAA7111_NR_REG; i += 16) {
-                       int j;
-
-                       v4l_info(client, "%03x", i);
-                       for (j = 0; j < 16 && i + j < SAA7111_NR_REG; ++j) {
-                               printk(KERN_CONT " %02x",
-                                      saa7111_read(client, i + j));
-                       }
-                       printk(KERN_CONT "\n");
-               }
-               break;
-       }
-
-       case DECODER_GET_CAPABILITIES:
-       {
-               struct video_decoder_capability *cap = arg;
-
-               cap->flags = VIDEO_DECODER_PAL |
-                            VIDEO_DECODER_NTSC |
-                            VIDEO_DECODER_SECAM |
-                            VIDEO_DECODER_AUTO |
-                            VIDEO_DECODER_CCIR;
-               cap->inputs = 8;
-               cap->outputs = 1;
-               break;
-       }
-
-       case DECODER_GET_STATUS:
-       {
-               int *iarg = arg;
-               int status;
-               int res;
-
-               status = saa7111_read(client, 0x1f);
-               v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
-               res = 0;
-               if ((status & (1 << 6)) == 0) {
-                       res |= DECODER_STATUS_GOOD;
-               }
-               switch (decoder->norm) {
-               case VIDEO_MODE_NTSC:
-                       res |= DECODER_STATUS_NTSC;
-                       break;
-               case VIDEO_MODE_PAL:
-                       res |= DECODER_STATUS_PAL;
-                       break;
-               case VIDEO_MODE_SECAM:
-                       res |= DECODER_STATUS_SECAM;
-                       break;
-               default:
-               case VIDEO_MODE_AUTO:
-                       if ((status & (1 << 5)) != 0) {
-                               res |= DECODER_STATUS_NTSC;
-                       } else {
-                               res |= DECODER_STATUS_PAL;
-                       }
-                       break;
-               }
-               if ((status & (1 << 0)) != 0) {
-                       res |= DECODER_STATUS_COLOR;
-               }
-               *iarg = res;
-               break;
-       }
-
-       case DECODER_SET_GPIO:
-       {
-               int *iarg = arg;
-               if (0 != *iarg) {
-                       saa7111_write(client, 0x11,
-                               (decoder->reg[0x11] | 0x80));
-               } else {
-                       saa7111_write(client, 0x11,
-                               (decoder->reg[0x11] & 0x7f));
-               }
-               break;
-       }
-
-       case DECODER_SET_VBI_BYPASS:
-       {
-               int *iarg = arg;
-               if (0 != *iarg) {
-                       saa7111_write(client, 0x13,
-                               (decoder->reg[0x13] & 0xf0) | 0x0a);
-               } else {
-                       saa7111_write(client, 0x13,
-                               (decoder->reg[0x13] & 0xf0));
-               }
-               break;
-       }
-
-       case DECODER_SET_NORM:
-       {
-               int *iarg = arg;
-
-               switch (*iarg) {
-
-               case VIDEO_MODE_NTSC:
-                       saa7111_write(client, 0x08,
-                                     (decoder->reg[0x08] & 0x3f) | 0x40);
-                       saa7111_write(client, 0x0e,
-                                     (decoder->reg[0x0e] & 0x8f));
-                       break;
-
-               case VIDEO_MODE_PAL:
-                       saa7111_write(client, 0x08,
-                                     (decoder->reg[0x08] & 0x3f) | 0x00);
-                       saa7111_write(client, 0x0e,
-                                     (decoder->reg[0x0e] & 0x8f));
-                       break;
-
-               case VIDEO_MODE_SECAM:
-                       saa7111_write(client, 0x08,
-                                     (decoder->reg[0x08] & 0x3f) | 0x00);
-                       saa7111_write(client, 0x0e,
-                                     (decoder->reg[0x0e] & 0x8f) | 0x50);
-                       break;
-
-               case VIDEO_MODE_AUTO:
-                       saa7111_write(client, 0x08,
-                                     (decoder->reg[0x08] & 0x3f) | 0x80);
-                       saa7111_write(client, 0x0e,
-                                     (decoder->reg[0x0e] & 0x8f));
-                       break;
-
-               default:
-                       return -EINVAL;
-
-               }
-               decoder->norm = *iarg;
-               break;
-       }
-
-       case DECODER_SET_INPUT:
-       {
-               int *iarg = arg;
-
-               if (*iarg < 0 || *iarg > 7) {
-                       return -EINVAL;
-               }
-
-               if (decoder->input != *iarg) {
-                       decoder->input = *iarg;
-                       /* select mode */
-                       saa7111_write(client, 0x02,
-                                     (decoder->
-                                      reg[0x02] & 0xf8) | decoder->input);
-                       /* bypass chrominance trap for modes 4..7 */
-                       saa7111_write(client, 0x09,
-                                     (decoder->
-                                      reg[0x09] & 0x7f) | ((decoder->
-                                                            input >
-                                                            3) ? 0x80 :
-                                                           0));
-               }
-               break;
-       }
-
-       case DECODER_SET_OUTPUT:
-       {
-               int *iarg = arg;
-
-               /* not much choice of outputs */
-               if (*iarg != 0) {
-                       return -EINVAL;
-               }
-               break;
-       }
-
-       case DECODER_ENABLE_OUTPUT:
-       {
-               int *iarg = arg;
-               int enable = (*iarg != 0);
-
-               if (decoder->enable != enable) {
-                       decoder->enable = enable;
-
-                       /* RJ: If output should be disabled (for
-                        * playing videos), we also need a open PLL.
-                        * The input is set to 0 (where no input
-                        * source is connected), although this
-                        * is not necessary.
-                        *
-                        * If output should be enabled, we have to
-                        * reverse the above.
-                        */
-
-                       if (decoder->enable) {
-                               saa7111_write(client, 0x02,
-                                             (decoder->
-                                              reg[0x02] & 0xf8) |
-                                             decoder->input);
-                               saa7111_write(client, 0x08,
-                                             (decoder->reg[0x08] & 0xfb));
-                               saa7111_write(client, 0x11,
-                                             (decoder->
-                                              reg[0x11] & 0xf3) | 0x0c);
-                       } else {
-                               saa7111_write(client, 0x02,
-                                             (decoder->reg[0x02] & 0xf8));
-                               saa7111_write(client, 0x08,
-                                             (decoder->
-                                              reg[0x08] & 0xfb) | 0x04);
-                               saa7111_write(client, 0x11,
-                                             (decoder->reg[0x11] & 0xf3));
-                       }
-               }
-               break;
-       }
-
-       case DECODER_SET_PICTURE:
-       {
-               struct video_picture *pic = arg;
-
-               /* We want 0 to 255 we get 0-65535 */
-               saa7111_write_if_changed(client, 0x0a, pic->brightness >> 8);
-               /* We want 0 to 127 we get 0-65535 */
-               saa7111_write(client, 0x0b, pic->contrast >> 9);
-               /* We want 0 to 127 we get 0-65535 */
-               saa7111_write(client, 0x0c, pic->colour >> 9);
-               /* We want -128 to 127 we get 0-65535 */
-               saa7111_write(client, 0x0d, (pic->hue - 32768) >> 8);
-               break;
-       }
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static unsigned short normal_i2c[] = { 0x48 >> 1, I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
-static int saa7111_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
-{
-       int i;
-       struct saa7111 *decoder;
-       struct video_decoder_init vdi;
-
-       /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return -ENODEV;
-
-       v4l_info(client, "chip found @ 0x%x (%s)\n",
-                       client->addr << 1, client->adapter->name);
-
-       decoder = kzalloc(sizeof(struct saa7111), GFP_KERNEL);
-       if (decoder == NULL) {
-               kfree(client);
-               return -ENOMEM;
-       }
-       decoder->norm = VIDEO_MODE_NTSC;
-       decoder->input = 0;
-       decoder->enable = 1;
-       i2c_set_clientdata(client, decoder);
-
-       vdi.data = saa7111_i2c_init;
-       vdi.len = sizeof(saa7111_i2c_init);
-       i = saa7111_init_decoder(client, &vdi);
-       if (i < 0) {
-               v4l_dbg(1, debug, client, "init status %d\n", i);
-       } else {
-               v4l_dbg(1, debug, client, "revision %x\n",
-                       saa7111_read(client, 0x00) >> 4);
-       }
-       return 0;
-}
-
-static int saa7111_remove(struct i2c_client *client)
-{
-       kfree(i2c_get_clientdata(client));
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct i2c_device_id saa7111_id[] = {
-       { "saa7111_old", 0 },   /* "saa7111" maps to the saa7115 driver */
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, saa7111_id);
-
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "saa7111",
-       .driverid = I2C_DRIVERID_SAA7111A,
-       .command = saa7111_command,
-       .probe = saa7111_probe,
-       .remove = saa7111_remove,
-       .id_table = saa7111_id,
-};
diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c
deleted file mode 100644 (file)
index 7ca709f..0000000
+++ /dev/null
@@ -1,1068 +0,0 @@
-/*
- * saa7114 - Philips SAA7114H video decoder driver version 0.0.1
- *
- * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
- *
- * Based on saa7111 driver by Dave Perks
- *
- * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
- *
- * Slight changes for video timing and attachment output by
- * Wolfgang Scherr <scherr@net4you.net>
- *
- * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
- *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/ioctl.h>
-#include <asm/uaccess.h>
-#include <linux/i2c.h>
-#include <linux/i2c-id.h>
-#include <linux/videodev.h>
-#include <linux/video_decoder.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-i2c-drv-legacy.h>
-
-MODULE_DESCRIPTION("Philips SAA7114H video decoder driver");
-MODULE_AUTHOR("Maxim Yevtyushkin");
-MODULE_LICENSE("GPL");
-
-static int debug;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "Debug level (0-1)");
-
-/* ----------------------------------------------------------------------- */
-
-struct saa7114 {
-       unsigned char reg[0xf0 * 2];
-
-       int norm;
-       int input;
-       int enable;
-       int bright;
-       int contrast;
-       int hue;
-       int sat;
-       int playback;
-};
-
-#define   I2C_DELAY   10
-
-
-//#define SAA_7114_NTSC_HSYNC_START       (-3)
-//#define SAA_7114_NTSC_HSYNC_STOP        (-18)
-
-#define SAA_7114_NTSC_HSYNC_START  (-17)
-#define SAA_7114_NTSC_HSYNC_STOP   (-32)
-
-//#define SAA_7114_NTSC_HOFFSET           (5)
-#define SAA_7114_NTSC_HOFFSET          (6)
-#define SAA_7114_NTSC_VOFFSET           (10)
-#define SAA_7114_NTSC_WIDTH             (720)
-#define SAA_7114_NTSC_HEIGHT            (250)
-
-#define SAA_7114_SECAM_HSYNC_START      (-17)
-#define SAA_7114_SECAM_HSYNC_STOP       (-32)
-
-#define SAA_7114_SECAM_HOFFSET          (2)
-#define SAA_7114_SECAM_VOFFSET          (10)
-#define SAA_7114_SECAM_WIDTH            (720)
-#define SAA_7114_SECAM_HEIGHT           (300)
-
-#define SAA_7114_PAL_HSYNC_START        (-17)
-#define SAA_7114_PAL_HSYNC_STOP         (-32)
-
-#define SAA_7114_PAL_HOFFSET            (2)
-#define SAA_7114_PAL_VOFFSET            (10)
-#define SAA_7114_PAL_WIDTH              (720)
-#define SAA_7114_PAL_HEIGHT             (300)
-
-
-
-#define SAA_7114_VERTICAL_CHROMA_OFFSET         0      //0x50504040
-#define SAA_7114_VERTICAL_LUMA_OFFSET           0
-
-#define REG_ADDR(x) (((x) << 1) + 1)
-#define LOBYTE(x) ((unsigned char)((x) & 0xff))
-#define HIBYTE(x) ((unsigned char)(((x) >> 8) & 0xff))
-#define LOWORD(x) ((unsigned short int)((x) & 0xffff))
-#define HIWORD(x) ((unsigned short int)(((x) >> 16) & 0xffff))
-
-
-/* ----------------------------------------------------------------------- */
-
-static inline int saa7114_write(struct i2c_client *client, u8 reg, u8 value)
-{
-       return i2c_smbus_write_byte_data(client, reg, value);
-}
-
-static int saa7114_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
-{
-       int ret = -1;
-       u8 reg;
-
-       /* the saa7114 has an autoincrement function, use it if
-        * the adapter understands raw I2C */
-       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
-               /* do raw I2C, not smbus compatible */
-               u8 block_data[32];
-               int block_len;
-
-               while (len >= 2) {
-                       block_len = 0;
-                       block_data[block_len++] = reg = data[0];
-                       do {
-                               block_data[block_len++] = data[1];
-                               reg++;
-                               len -= 2;
-                               data += 2;
-                       } while (len >= 2 && data[0] == reg && block_len < 32);
-                       ret = i2c_master_send(client, block_data, block_len);
-                       if (ret < 0)
-                               break;
-               }
-       } else {
-               /* do some slow I2C emulation kind of thing */
-               while (len >= 2) {
-                       reg = *data++;
-                       ret = saa7114_write(client, reg, *data++);
-                       if (ret < 0)
-                               break;
-                       len -= 2;
-               }
-       }
-
-       return ret;
-}
-
-static inline int saa7114_read(struct i2c_client *client, u8 reg)
-{
-       return i2c_smbus_read_byte_data(client, reg);
-}
-
-/* ----------------------------------------------------------------------- */
-
-// initially set NTSC, composite
-
-
-static const unsigned char init[] = {
-       0x00, 0x00,             /* 00 - ID byte , chip version,
-                                * read only */
-       0x01, 0x08,             /* 01 - X,X,X,X, IDEL3 to IDEL0 -
-                                * horizontal increment delay,
-                                * recommended position */
-       0x02, 0x00,             /* 02 - FUSE=3, GUDL=2, MODE=0 ;
-                                * input control */
-       0x03, 0x10,             /* 03 - HLNRS=0, VBSL=1, WPOFF=0,
-                                * HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
-       0x04, 0x90,             /* 04 - GAI1=256 */
-       0x05, 0x90,             /* 05 - GAI2=256 */
-       0x06, SAA_7114_NTSC_HSYNC_START,        /* 06 - HSB: hsync start,
-                                * depends on the video standard */
-       0x07, SAA_7114_NTSC_HSYNC_STOP, /* 07 - HSS: hsync stop, depends
-                                *on the video standard */
-       0x08, 0xb8,             /* 08 - AUFD=1, FSEL=1, EXFIL=0, VTRC=1,
-                                * HPLL: free running in playback, locked
-                                * in capture, VNOI=0 */
-       0x09, 0x80,             /* 09 - BYPS=0, PREF=0, BPSS=0, VBLB=0,
-                                * UPTCV=0, APER=1; depends from input */
-       0x0a, 0x80,             /* 0a - BRIG=128 */
-       0x0b, 0x44,             /* 0b - CONT=1.109 */
-       0x0c, 0x40,             /* 0c - SATN=1.0 */
-       0x0d, 0x00,             /* 0d - HUE=0 */
-       0x0e, 0x84,             /* 0e - CDTO, CSTD2 to 0, DCVF, FCTC,
-                                * CCOMB; depends from video standard */
-       0x0f, 0x24,             /* 0f - ACGC,CGAIN6 to CGAIN0; depends
-                                * from video standard */
-       0x10, 0x03,             /* 10 - OFFU1 to 0, OFFV1 to 0, CHBW,
-                                * LCBW2 to 0 */
-       0x11, 0x59,             /* 11 - COLO, RTP1, HEDL1 to 0, RTP0,
-                                * YDEL2 to 0 */
-       0x12, 0xc9,             /* 12 - RT signal control RTSE13 to 10
-                                * and 03 to 00 */
-       0x13, 0x80,             /* 13 - RT/X port output control  */
-       0x14, 0x00,             /* 14 - analog, ADC, compatibility control */
-       0x15, 0x00,             /* 15 - VGATE start FID change  */
-       0x16, 0xfe,             /* 16 - VGATE stop */
-       0x17, 0x00,             /* 17 - Misc., VGATE MSBs */
-       0x18, 0x40,             /* RAWG */
-       0x19, 0x80,             /* RAWO */
-       0x1a, 0x00,
-       0x1b, 0x00,
-       0x1c, 0x00,
-       0x1d, 0x00,
-       0x1e, 0x00,
-       0x1f, 0x00,             /* status byte, read only */
-       0x20, 0x00,             /* video decoder reserved part */
-       0x21, 0x00,
-       0x22, 0x00,
-       0x23, 0x00,
-       0x24, 0x00,
-       0x25, 0x00,
-       0x26, 0x00,
-       0x27, 0x00,
-       0x28, 0x00,
-       0x29, 0x00,
-       0x2a, 0x00,
-       0x2b, 0x00,
-       0x2c, 0x00,
-       0x2d, 0x00,
-       0x2e, 0x00,
-       0x2f, 0x00,
-       0x30, 0xbc,             /* audio clock generator */
-       0x31, 0xdf,
-       0x32, 0x02,
-       0x33, 0x00,
-       0x34, 0xcd,
-       0x35, 0xcc,
-       0x36, 0x3a,
-       0x37, 0x00,
-       0x38, 0x03,
-       0x39, 0x10,
-       0x3a, 0x00,
-       0x3b, 0x00,
-       0x3c, 0x00,
-       0x3d, 0x00,
-       0x3e, 0x00,
-       0x3f, 0x00,
-       0x40, 0x00,             /* VBI data slicer */
-       0x41, 0xff,
-       0x42, 0xff,
-       0x43, 0xff,
-       0x44, 0xff,
-       0x45, 0xff,
-       0x46, 0xff,
-       0x47, 0xff,
-       0x48, 0xff,
-       0x49, 0xff,
-       0x4a, 0xff,
-       0x4b, 0xff,
-       0x4c, 0xff,
-       0x4d, 0xff,
-       0x4e, 0xff,
-       0x4f, 0xff,
-       0x50, 0xff,
-       0x51, 0xff,
-       0x52, 0xff,
-       0x53, 0xff,
-       0x54, 0xff,
-       0x55, 0xff,
-       0x56, 0xff,
-       0x57, 0xff,
-       0x58, 0x40,             // framing code
-       0x59, 0x47,             // horizontal offset
-       0x5a, 0x06,             // vertical offset
-       0x5b, 0x83,             // field offset
-       0x5c, 0x00,             // reserved
-       0x5d, 0x3e,             // header and data
-       0x5e, 0x00,             // sliced data
-       0x5f, 0x00,             // reserved
-       0x60, 0x00,             /* video decoder reserved part */
-       0x61, 0x00,
-       0x62, 0x00,
-       0x63, 0x00,
-       0x64, 0x00,
-       0x65, 0x00,
-       0x66, 0x00,
-       0x67, 0x00,
-       0x68, 0x00,
-       0x69, 0x00,
-       0x6a, 0x00,
-       0x6b, 0x00,
-       0x6c, 0x00,
-       0x6d, 0x00,
-       0x6e, 0x00,
-       0x6f, 0x00,
-       0x70, 0x00,             /* video decoder reserved part */
-       0x71, 0x00,
-       0x72, 0x00,
-       0x73, 0x00,
-       0x74, 0x00,
-       0x75, 0x00,
-       0x76, 0x00,
-       0x77, 0x00,
-       0x78, 0x00,
-       0x79, 0x00,
-       0x7a, 0x00,
-       0x7b, 0x00,
-       0x7c, 0x00,
-       0x7d, 0x00,
-       0x7e, 0x00,
-       0x7f, 0x00,
-       0x80, 0x00,             /* X-port, I-port and scaler */
-       0x81, 0x00,
-       0x82, 0x00,
-       0x83, 0x00,
-       0x84, 0xc5,
-       0x85, 0x0d,             // hsync and vsync ?
-       0x86, 0x40,
-       0x87, 0x01,
-       0x88, 0x00,
-       0x89, 0x00,
-       0x8a, 0x00,
-       0x8b, 0x00,
-       0x8c, 0x00,
-       0x8d, 0x00,
-       0x8e, 0x00,
-       0x8f, 0x00,
-       0x90, 0x03,             /* Task A definition           */
-       0x91, 0x08,
-       0x92, 0x00,
-       0x93, 0x40,
-       0x94, 0x00,             // window settings
-       0x95, 0x00,
-       0x96, 0x00,
-       0x97, 0x00,
-       0x98, 0x00,
-       0x99, 0x00,
-       0x9a, 0x00,
-       0x9b, 0x00,
-       0x9c, 0x00,
-       0x9d, 0x00,
-       0x9e, 0x00,
-       0x9f, 0x00,
-       0xa0, 0x01,             /* horizontal integer prescaling ratio */
-       0xa1, 0x00,             /* horizontal prescaler accumulation
-                                * sequence length */
-       0xa2, 0x00,             /* UV FIR filter, Y FIR filter, prescaler
-                                * DC gain */
-       0xa3, 0x00,
-       0xa4, 0x80,             // luminance brightness
-       0xa5, 0x40,             // luminance gain
-       0xa6, 0x40,             // chrominance saturation
-       0xa7, 0x00,
-       0xa8, 0x00,             // horizontal luminance scaling increment
-       0xa9, 0x04,
-       0xaa, 0x00,             // horizontal luminance phase offset
-       0xab, 0x00,
-       0xac, 0x00,             // horizontal chrominance scaling increment
-       0xad, 0x02,
-       0xae, 0x00,             // horizontal chrominance phase offset
-       0xaf, 0x00,
-       0xb0, 0x00,             // vertical luminance scaling increment
-       0xb1, 0x04,
-       0xb2, 0x00,             // vertical chrominance scaling increment
-       0xb3, 0x04,
-       0xb4, 0x00,
-       0xb5, 0x00,
-       0xb6, 0x00,
-       0xb7, 0x00,
-       0xb8, 0x00,
-       0xb9, 0x00,
-       0xba, 0x00,
-       0xbb, 0x00,
-       0xbc, 0x00,
-       0xbd, 0x00,
-       0xbe, 0x00,
-       0xbf, 0x00,
-       0xc0, 0x02,             // Task B definition
-       0xc1, 0x08,
-       0xc2, 0x00,
-       0xc3, 0x40,
-       0xc4, 0x00,             // window settings
-       0xc5, 0x00,
-       0xc6, 0x00,
-       0xc7, 0x00,
-       0xc8, 0x00,
-       0xc9, 0x00,
-       0xca, 0x00,
-       0xcb, 0x00,
-       0xcc, 0x00,
-       0xcd, 0x00,
-       0xce, 0x00,
-       0xcf, 0x00,
-       0xd0, 0x01,             // horizontal integer prescaling ratio
-       0xd1, 0x00,             // horizontal prescaler accumulation sequence length
-       0xd2, 0x00,             // UV FIR filter, Y FIR filter, prescaler DC gain
-       0xd3, 0x00,
-       0xd4, 0x80,             // luminance brightness
-       0xd5, 0x40,             // luminance gain
-       0xd6, 0x40,             // chrominance saturation
-       0xd7, 0x00,
-       0xd8, 0x00,             // horizontal luminance scaling increment
-       0xd9, 0x04,
-       0xda, 0x00,             // horizontal luminance phase offset
-       0xdb, 0x00,
-       0xdc, 0x00,             // horizontal chrominance scaling increment
-       0xdd, 0x02,
-       0xde, 0x00,             // horizontal chrominance phase offset
-       0xdf, 0x00,
-       0xe0, 0x00,             // vertical luminance scaling increment
-       0xe1, 0x04,
-       0xe2, 0x00,             // vertical chrominance scaling increment
-       0xe3, 0x04,
-       0xe4, 0x00,
-       0xe5, 0x00,
-       0xe6, 0x00,
-       0xe7, 0x00,
-       0xe8, 0x00,
-       0xe9, 0x00,
-       0xea, 0x00,
-       0xeb, 0x00,
-       0xec, 0x00,
-       0xed, 0x00,
-       0xee, 0x00,
-       0xef, 0x00
-};
-
-static int saa7114_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       struct saa7114 *decoder = i2c_get_clientdata(client);
-
-       switch (cmd) {
-       case 0:
-               //dprintk(1, KERN_INFO "%s: writing init\n", I2C_NAME(client));
-               //saa7114_write_block(client, init, sizeof(init));
-               break;
-
-       case DECODER_DUMP:
-       {
-               int i;
-
-               if (!debug)
-                       break;
-               v4l_info(client, "decoder dump\n");
-
-               for (i = 0; i < 32; i += 16) {
-                       int j;
-
-                       v4l_info(client, "%03x", i);
-                       for (j = 0; j < 16; ++j) {
-                               printk(KERN_CONT " %02x",
-                                      saa7114_read(client, i + j));
-                       }
-                       printk(KERN_CONT "\n");
-               }
-               break;
-       }
-
-       case DECODER_GET_CAPABILITIES:
-       {
-               struct video_decoder_capability *cap = arg;
-
-               v4l_dbg(1, debug, client, "get capabilities\n");
-
-               cap->flags = VIDEO_DECODER_PAL |
-                            VIDEO_DECODER_NTSC |
-                            VIDEO_DECODER_AUTO |
-                            VIDEO_DECODER_CCIR;
-               cap->inputs = 8;
-               cap->outputs = 1;
-               break;
-       }
-
-       case DECODER_GET_STATUS:
-       {
-               int *iarg = arg;
-               int status;
-               int res;
-
-               status = saa7114_read(client, 0x1f);
-
-               v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
-               res = 0;
-               if ((status & (1 << 6)) == 0) {
-                       res |= DECODER_STATUS_GOOD;
-               }
-               switch (decoder->norm) {
-               case VIDEO_MODE_NTSC:
-                       res |= DECODER_STATUS_NTSC;
-                       break;
-               case VIDEO_MODE_PAL:
-                       res |= DECODER_STATUS_PAL;
-                       break;
-               case VIDEO_MODE_SECAM:
-                       res |= DECODER_STATUS_SECAM;
-                       break;
-               default:
-               case VIDEO_MODE_AUTO:
-                       if ((status & (1 << 5)) != 0) {
-                               res |= DECODER_STATUS_NTSC;
-                       } else {
-                               res |= DECODER_STATUS_PAL;
-                       }
-                       break;
-               }
-               if ((status & (1 << 0)) != 0) {
-                       res |= DECODER_STATUS_COLOR;
-               }
-               *iarg = res;
-               break;
-       }
-
-       case DECODER_SET_NORM:
-       {
-               int *iarg = arg;
-
-               short int hoff = 0, voff = 0, w = 0, h = 0;
-
-               v4l_dbg(1, debug, client, "set norm\n");
-
-               switch (*iarg) {
-               case VIDEO_MODE_NTSC:
-                       v4l_dbg(1, debug, client, "NTSC\n");
-                       decoder->reg[REG_ADDR(0x06)] =
-                           SAA_7114_NTSC_HSYNC_START;
-                       decoder->reg[REG_ADDR(0x07)] =
-                           SAA_7114_NTSC_HSYNC_STOP;
-
-                       decoder->reg[REG_ADDR(0x08)] = decoder->playback ? 0x7c : 0xb8; // PLL free when playback, PLL close when capture
-
-                       decoder->reg[REG_ADDR(0x0e)] = 0x85;
-                       decoder->reg[REG_ADDR(0x0f)] = 0x24;
-
-                       hoff = SAA_7114_NTSC_HOFFSET;
-                       voff = SAA_7114_NTSC_VOFFSET;
-                       w = SAA_7114_NTSC_WIDTH;
-                       h = SAA_7114_NTSC_HEIGHT;
-
-                       break;
-
-               case VIDEO_MODE_PAL:
-                       v4l_dbg(1, debug, client, "PAL\n");
-                       decoder->reg[REG_ADDR(0x06)] =
-                           SAA_7114_PAL_HSYNC_START;
-                       decoder->reg[REG_ADDR(0x07)] =
-                           SAA_7114_PAL_HSYNC_STOP;
-
-                       decoder->reg[REG_ADDR(0x08)] = decoder->playback ? 0x7c : 0xb8; // PLL free when playback, PLL close when capture
-
-                       decoder->reg[REG_ADDR(0x0e)] = 0x81;
-                       decoder->reg[REG_ADDR(0x0f)] = 0x24;
-
-                       hoff = SAA_7114_PAL_HOFFSET;
-                       voff = SAA_7114_PAL_VOFFSET;
-                       w = SAA_7114_PAL_WIDTH;
-                       h = SAA_7114_PAL_HEIGHT;
-
-                       break;
-
-               default:
-                       v4l_dbg(1, debug, client, "Unknown video mode\n");
-                       return -EINVAL;
-               }
-
-
-               decoder->reg[REG_ADDR(0x94)] = LOBYTE(hoff);    // hoffset low
-               decoder->reg[REG_ADDR(0x95)] = HIBYTE(hoff) & 0x0f;     // hoffset high
-               decoder->reg[REG_ADDR(0x96)] = LOBYTE(w);       // width low
-               decoder->reg[REG_ADDR(0x97)] = HIBYTE(w) & 0x0f;        // width high
-               decoder->reg[REG_ADDR(0x98)] = LOBYTE(voff);    // voffset low
-               decoder->reg[REG_ADDR(0x99)] = HIBYTE(voff) & 0x0f;     // voffset high
-               decoder->reg[REG_ADDR(0x9a)] = LOBYTE(h + 2);   // height low
-               decoder->reg[REG_ADDR(0x9b)] = HIBYTE(h + 2) & 0x0f;    // height high
-               decoder->reg[REG_ADDR(0x9c)] = LOBYTE(w);       // out width low
-               decoder->reg[REG_ADDR(0x9d)] = HIBYTE(w) & 0x0f;        // out width high
-               decoder->reg[REG_ADDR(0x9e)] = LOBYTE(h);       // out height low
-               decoder->reg[REG_ADDR(0x9f)] = HIBYTE(h) & 0x0f;        // out height high
-
-               decoder->reg[REG_ADDR(0xc4)] = LOBYTE(hoff);    // hoffset low
-               decoder->reg[REG_ADDR(0xc5)] = HIBYTE(hoff) & 0x0f;     // hoffset high
-               decoder->reg[REG_ADDR(0xc6)] = LOBYTE(w);       // width low
-               decoder->reg[REG_ADDR(0xc7)] = HIBYTE(w) & 0x0f;        // width high
-               decoder->reg[REG_ADDR(0xc8)] = LOBYTE(voff);    // voffset low
-               decoder->reg[REG_ADDR(0xc9)] = HIBYTE(voff) & 0x0f;     // voffset high
-               decoder->reg[REG_ADDR(0xca)] = LOBYTE(h + 2);   // height low
-               decoder->reg[REG_ADDR(0xcb)] = HIBYTE(h + 2) & 0x0f;    // height high
-               decoder->reg[REG_ADDR(0xcc)] = LOBYTE(w);       // out width low
-               decoder->reg[REG_ADDR(0xcd)] = HIBYTE(w) & 0x0f;        // out width high
-               decoder->reg[REG_ADDR(0xce)] = LOBYTE(h);       // out height low
-               decoder->reg[REG_ADDR(0xcf)] = HIBYTE(h) & 0x0f;        // out height high
-
-
-               saa7114_write(client, 0x80, 0x06);      // i-port and scaler back end clock selection, task A&B off
-               saa7114_write(client, 0x88, 0xd8);      // sw reset scaler
-               saa7114_write(client, 0x88, 0xf8);      // sw reset scaler release
-
-               saa7114_write_block(client, decoder->reg + (0x06 << 1),
-                                   3 << 1);
-               saa7114_write_block(client, decoder->reg + (0x0e << 1),
-                                   2 << 1);
-               saa7114_write_block(client, decoder->reg + (0x5a << 1),
-                                   2 << 1);
-
-               saa7114_write_block(client, decoder->reg + (0x94 << 1),
-                                   (0x9f + 1 - 0x94) << 1);
-               saa7114_write_block(client, decoder->reg + (0xc4 << 1),
-                                   (0xcf + 1 - 0xc4) << 1);
-
-               saa7114_write(client, 0x88, 0xd8);      // sw reset scaler
-               saa7114_write(client, 0x88, 0xf8);      // sw reset scaler release
-               saa7114_write(client, 0x80, 0x36);      // i-port and scaler back end clock selection
-
-               decoder->norm = *iarg;
-               break;
-       }
-
-       case DECODER_SET_INPUT:
-       {
-               int *iarg = arg;
-
-               v4l_dbg(1, debug, client, "set input (%d)\n", *iarg);
-               if (*iarg < 0 || *iarg > 7) {
-                       return -EINVAL;
-               }
-
-               if (decoder->input != *iarg) {
-                       v4l_dbg(1, debug, client, "now setting %s input\n",
-                               *iarg >= 6 ? "S-Video" : "Composite");
-                       decoder->input = *iarg;
-
-                       /* select mode */
-                       decoder->reg[REG_ADDR(0x02)] =
-                           (decoder->
-                            reg[REG_ADDR(0x02)] & 0xf0) | (decoder->
-                                                           input <
-                                                           6 ? 0x0 : 0x9);
-                       saa7114_write(client, 0x02,
-                                     decoder->reg[REG_ADDR(0x02)]);
-
-                       /* bypass chrominance trap for modes 6..9 */
-                       decoder->reg[REG_ADDR(0x09)] =
-                           (decoder->
-                            reg[REG_ADDR(0x09)] & 0x7f) | (decoder->
-                                                           input <
-                                                           6 ? 0x0 :
-                                                           0x80);
-                       saa7114_write(client, 0x09,
-                                     decoder->reg[REG_ADDR(0x09)]);
-
-                       decoder->reg[REG_ADDR(0x0e)] =
-                           decoder->input <
-                           6 ? decoder->
-                           reg[REG_ADDR(0x0e)] | 1 : decoder->
-                           reg[REG_ADDR(0x0e)] & ~1;
-                       saa7114_write(client, 0x0e,
-                                     decoder->reg[REG_ADDR(0x0e)]);
-               }
-               break;
-       }
-
-       case DECODER_SET_OUTPUT:
-       {
-               int *iarg = arg;
-
-               v4l_dbg(1, debug, client, "set output\n");
-
-               /* not much choice of outputs */
-               if (*iarg != 0) {
-                       return -EINVAL;
-               }
-               break;
-       }
-
-       case DECODER_ENABLE_OUTPUT:
-       {
-               int *iarg = arg;
-               int enable = (*iarg != 0);
-
-               v4l_dbg(1, debug, client, "%s output\n",
-                       enable ? "enable" : "disable");
-
-               decoder->playback = !enable;
-
-               if (decoder->enable != enable) {
-                       decoder->enable = enable;
-
-                       /* RJ: If output should be disabled (for
-                        * playing videos), we also need a open PLL.
-                        * The input is set to 0 (where no input
-                        * source is connected), although this
-                        * is not necessary.
-                        *
-                        * If output should be enabled, we have to
-                        * reverse the above.
-                        */
-
-                       if (decoder->enable) {
-                               decoder->reg[REG_ADDR(0x08)] = 0xb8;
-                               decoder->reg[REG_ADDR(0x12)] = 0xc9;
-                               decoder->reg[REG_ADDR(0x13)] = 0x80;
-                               decoder->reg[REG_ADDR(0x87)] = 0x01;
-                       } else {
-                               decoder->reg[REG_ADDR(0x08)] = 0x7c;
-                               decoder->reg[REG_ADDR(0x12)] = 0x00;
-                               decoder->reg[REG_ADDR(0x13)] = 0x00;
-                               decoder->reg[REG_ADDR(0x87)] = 0x00;
-                       }
-
-                       saa7114_write_block(client,
-                                           decoder->reg + (0x12 << 1),
-                                           2 << 1);
-                       saa7114_write(client, 0x08,
-                                     decoder->reg[REG_ADDR(0x08)]);
-                       saa7114_write(client, 0x87,
-                                     decoder->reg[REG_ADDR(0x87)]);
-                       saa7114_write(client, 0x88, 0xd8);      // sw reset scaler
-                       saa7114_write(client, 0x88, 0xf8);      // sw reset scaler release
-                       saa7114_write(client, 0x80, 0x36);
-
-               }
-               break;
-       }
-
-       case DECODER_SET_PICTURE:
-       {
-               struct video_picture *pic = arg;
-
-               v4l_dbg(1, debug, client,
-                       "decoder set picture bright=%d contrast=%d saturation=%d hue=%d\n",
-                       pic->brightness, pic->contrast, pic->colour, pic->hue);
-
-               if (decoder->bright != pic->brightness) {
-                       /* We want 0 to 255 we get 0-65535 */
-                       decoder->bright = pic->brightness;
-                       saa7114_write(client, 0x0a, decoder->bright >> 8);
-               }
-               if (decoder->contrast != pic->contrast) {
-                       /* We want 0 to 127 we get 0-65535 */
-                       decoder->contrast = pic->contrast;
-                       saa7114_write(client, 0x0b,
-                                     decoder->contrast >> 9);
-               }
-               if (decoder->sat != pic->colour) {
-                       /* We want 0 to 127 we get 0-65535 */
-                       decoder->sat = pic->colour;
-                       saa7114_write(client, 0x0c, decoder->sat >> 9);
-               }
-               if (decoder->hue != pic->hue) {
-                       /* We want -128 to 127 we get 0-65535 */
-                       decoder->hue = pic->hue;
-                       saa7114_write(client, 0x0d,
-                                     (decoder->hue - 32768) >> 8);
-               }
-               break;
-       }
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
-static int saa7114_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
-{
-       int i, err[30];
-       short int hoff = SAA_7114_NTSC_HOFFSET;
-       short int voff = SAA_7114_NTSC_VOFFSET;
-       short int w = SAA_7114_NTSC_WIDTH;
-       short int h = SAA_7114_NTSC_HEIGHT;
-       struct saa7114 *decoder;
-
-       /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return -ENODEV;
-
-       v4l_info(client, "chip found @ 0x%x (%s)\n",
-                       client->addr << 1, client->adapter->name);
-
-       decoder = kzalloc(sizeof(struct saa7114), GFP_KERNEL);
-       if (decoder == NULL)
-               return -ENOMEM;
-       decoder->norm = VIDEO_MODE_NTSC;
-       decoder->input = -1;
-       decoder->enable = 1;
-       decoder->bright = 32768;
-       decoder->contrast = 32768;
-       decoder->hue = 32768;
-       decoder->sat = 32768;
-       decoder->playback = 0;  // initially capture mode useda
-       i2c_set_clientdata(client, decoder);
-
-       memcpy(decoder->reg, init, sizeof(init));
-
-       decoder->reg[REG_ADDR(0x94)] = LOBYTE(hoff);    // hoffset low
-       decoder->reg[REG_ADDR(0x95)] = HIBYTE(hoff) & 0x0f;     // hoffset high
-       decoder->reg[REG_ADDR(0x96)] = LOBYTE(w);       // width low
-       decoder->reg[REG_ADDR(0x97)] = HIBYTE(w) & 0x0f;        // width high
-       decoder->reg[REG_ADDR(0x98)] = LOBYTE(voff);    // voffset low
-       decoder->reg[REG_ADDR(0x99)] = HIBYTE(voff) & 0x0f;     // voffset high
-       decoder->reg[REG_ADDR(0x9a)] = LOBYTE(h + 2);   // height low
-       decoder->reg[REG_ADDR(0x9b)] = HIBYTE(h + 2) & 0x0f;    // height high
-       decoder->reg[REG_ADDR(0x9c)] = LOBYTE(w);       // out width low
-       decoder->reg[REG_ADDR(0x9d)] = HIBYTE(w) & 0x0f;        // out width high
-       decoder->reg[REG_ADDR(0x9e)] = LOBYTE(h);       // out height low
-       decoder->reg[REG_ADDR(0x9f)] = HIBYTE(h) & 0x0f;        // out height high
-
-       decoder->reg[REG_ADDR(0xc4)] = LOBYTE(hoff);    // hoffset low
-       decoder->reg[REG_ADDR(0xc5)] = HIBYTE(hoff) & 0x0f;     // hoffset high
-       decoder->reg[REG_ADDR(0xc6)] = LOBYTE(w);       // width low
-       decoder->reg[REG_ADDR(0xc7)] = HIBYTE(w) & 0x0f;        // width high
-       decoder->reg[REG_ADDR(0xc8)] = LOBYTE(voff);    // voffset low
-       decoder->reg[REG_ADDR(0xc9)] = HIBYTE(voff) & 0x0f;     // voffset high
-       decoder->reg[REG_ADDR(0xca)] = LOBYTE(h + 2);   // height low
-       decoder->reg[REG_ADDR(0xcb)] = HIBYTE(h + 2) & 0x0f;    // height high
-       decoder->reg[REG_ADDR(0xcc)] = LOBYTE(w);       // out width low
-       decoder->reg[REG_ADDR(0xcd)] = HIBYTE(w) & 0x0f;        // out width high
-       decoder->reg[REG_ADDR(0xce)] = LOBYTE(h);       // out height low
-       decoder->reg[REG_ADDR(0xcf)] = HIBYTE(h) & 0x0f;        // out height high
-
-       decoder->reg[REG_ADDR(0xb8)] =
-           LOBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));
-       decoder->reg[REG_ADDR(0xb9)] =
-           HIBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));
-       decoder->reg[REG_ADDR(0xba)] =
-           LOBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));
-       decoder->reg[REG_ADDR(0xbb)] =
-           HIBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));
-
-       decoder->reg[REG_ADDR(0xbc)] =
-           LOBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET));
-       decoder->reg[REG_ADDR(0xbd)] =
-           HIBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET));
-       decoder->reg[REG_ADDR(0xbe)] =
-           LOBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET));
-       decoder->reg[REG_ADDR(0xbf)] =
-           HIBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET));
-
-       decoder->reg[REG_ADDR(0xe8)] =
-           LOBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));
-       decoder->reg[REG_ADDR(0xe9)] =
-           HIBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));
-       decoder->reg[REG_ADDR(0xea)] =
-           LOBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));
-       decoder->reg[REG_ADDR(0xeb)] =
-           HIBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));
-
-       decoder->reg[REG_ADDR(0xec)] =
-           LOBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET));
-       decoder->reg[REG_ADDR(0xed)] =
-           HIBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET));
-       decoder->reg[REG_ADDR(0xee)] =
-           LOBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET));
-       decoder->reg[REG_ADDR(0xef)] =
-           HIBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET));
-
-
-       decoder->reg[REG_ADDR(0x13)] = 0x80;    // RTC0 on
-       decoder->reg[REG_ADDR(0x87)] = 0x01;    // I-Port
-       decoder->reg[REG_ADDR(0x12)] = 0xc9;    // RTS0
-
-       decoder->reg[REG_ADDR(0x02)] = 0xc0;    // set composite1 input, aveasy
-       decoder->reg[REG_ADDR(0x09)] = 0x00;    // chrominance trap
-       decoder->reg[REG_ADDR(0x0e)] |= 1;      // combfilter on
-
-
-       v4l_dbg(1, debug, client, "starting init\n");
-
-       err[0] =
-           saa7114_write_block(client, decoder->reg + (0x20 << 1),
-                               0x10 << 1);
-       err[1] =
-           saa7114_write_block(client, decoder->reg + (0x30 << 1),
-                               0x10 << 1);
-       err[2] =
-           saa7114_write_block(client, decoder->reg + (0x63 << 1),
-                               (0x7f + 1 - 0x63) << 1);
-       err[3] =
-           saa7114_write_block(client, decoder->reg + (0x89 << 1),
-                               6 << 1);
-       err[4] =
-           saa7114_write_block(client, decoder->reg + (0xb8 << 1),
-                               8 << 1);
-       err[5] =
-           saa7114_write_block(client, decoder->reg + (0xe8 << 1),
-                               8 << 1);
-
-
-       for (i = 0; i <= 5; i++) {
-               if (err[i] < 0) {
-                       v4l_dbg(1, debug, client,
-                               "init error %d at stage %d, leaving attach.\n",
-                               i, err[i]);
-                       kfree(decoder);
-                       return -EIO;
-               }
-       }
-
-       for (i = 6; i < 8; i++) {
-               v4l_dbg(1, debug, client,
-                       "reg[0x%02x] = 0x%02x (0x%02x)\n",
-                       i, saa7114_read(client, i),
-                       decoder->reg[REG_ADDR(i)]);
-       }
-
-       v4l_dbg(1, debug, client,
-               "performing decoder reset sequence\n");
-
-       err[6] = saa7114_write(client, 0x80, 0x06);     // i-port and scaler backend clock selection, task A&B off
-       err[7] = saa7114_write(client, 0x88, 0xd8);     // sw reset scaler
-       err[8] = saa7114_write(client, 0x88, 0xf8);     // sw reset scaler release
-
-       for (i = 6; i <= 8; i++) {
-               if (err[i] < 0) {
-                       v4l_dbg(1, debug, client,
-                               "init error %d at stage %d, leaving attach.\n",
-                               i, err[i]);
-                       kfree(decoder);
-                       return -EIO;
-               }
-       }
-
-       v4l_dbg(1, debug, client, "performing the rest of init\n");
-
-       err[9] = saa7114_write(client, 0x01, decoder->reg[REG_ADDR(0x01)]);
-       err[10] = saa7114_write_block(client, decoder->reg + (0x03 << 1), (0x1e + 1 - 0x03) << 1);      // big seq
-       err[11] = saa7114_write_block(client, decoder->reg + (0x40 << 1), (0x5f + 1 - 0x40) << 1);      // slicer
-       err[12] = saa7114_write_block(client, decoder->reg + (0x81 << 1), 2 << 1);      // ?
-       err[13] = saa7114_write_block(client, decoder->reg + (0x83 << 1), 5 << 1);      // ?
-       err[14] = saa7114_write_block(client, decoder->reg + (0x90 << 1), 4 << 1);      // Task A
-       err[15] =
-           saa7114_write_block(client, decoder->reg + (0x94 << 1),
-                               12 << 1);
-       err[16] =
-           saa7114_write_block(client, decoder->reg + (0xa0 << 1),
-                               8 << 1);
-       err[17] =
-           saa7114_write_block(client, decoder->reg + (0xa8 << 1),
-                               8 << 1);
-       err[18] =
-           saa7114_write_block(client, decoder->reg + (0xb0 << 1),
-                               8 << 1);
-       err[19] = saa7114_write_block(client, decoder->reg + (0xc0 << 1), 4 << 1);      // Task B
-       err[15] =
-           saa7114_write_block(client, decoder->reg + (0xc4 << 1),
-                               12 << 1);
-       err[16] =
-           saa7114_write_block(client, decoder->reg + (0xd0 << 1),
-                               8 << 1);
-       err[17] =
-           saa7114_write_block(client, decoder->reg + (0xd8 << 1),
-                               8 << 1);
-       err[18] =
-           saa7114_write_block(client, decoder->reg + (0xe0 << 1),
-                               8 << 1);
-
-       for (i = 9; i <= 18; i++) {
-               if (err[i] < 0) {
-                       v4l_dbg(1, debug, client,
-                               "init error %d at stage %d, leaving attach.\n",
-                               i, err[i]);
-                       kfree(decoder);
-                       return -EIO;
-               }
-       }
-
-
-       for (i = 6; i < 8; i++) {
-               v4l_dbg(1, debug, client,
-                       "reg[0x%02x] = 0x%02x (0x%02x)\n",
-                       i, saa7114_read(client, i),
-                       decoder->reg[REG_ADDR(i)]);
-       }
-
-
-       for (i = 0x11; i <= 0x13; i++) {
-               v4l_dbg(1, debug, client,
-                       "reg[0x%02x] = 0x%02x (0x%02x)\n",
-                       i, saa7114_read(client, i),
-                       decoder->reg[REG_ADDR(i)]);
-       }
-
-
-       v4l_dbg(1, debug, client, "setting video input\n");
-
-       err[19] =
-           saa7114_write(client, 0x02, decoder->reg[REG_ADDR(0x02)]);
-       err[20] =
-           saa7114_write(client, 0x09, decoder->reg[REG_ADDR(0x09)]);
-       err[21] =
-           saa7114_write(client, 0x0e, decoder->reg[REG_ADDR(0x0e)]);
-
-       for (i = 19; i <= 21; i++) {
-               if (err[i] < 0) {
-                       v4l_dbg(1, debug, client,
-                               "init error %d at stage %d, leaving attach.\n",
-                               i, err[i]);
-                       kfree(decoder);
-                       return -EIO;
-               }
-       }
-
-       v4l_dbg(1, debug, client, "performing decoder reset sequence\n");
-
-       err[22] = saa7114_write(client, 0x88, 0xd8);    // sw reset scaler
-       err[23] = saa7114_write(client, 0x88, 0xf8);    // sw reset scaler release
-       err[24] = saa7114_write(client, 0x80, 0x36);    // i-port and scaler backend clock selection, task A&B off
-
-
-       for (i = 22; i <= 24; i++) {
-               if (err[i] < 0) {
-                       v4l_dbg(1, debug, client,
-                               "init error %d at stage %d, leaving attach.\n",
-                               i, err[i]);
-                       kfree(decoder);
-                       return -EIO;
-               }
-       }
-
-       err[25] = saa7114_write(client, 0x06, init[REG_ADDR(0x06)]);
-       err[26] = saa7114_write(client, 0x07, init[REG_ADDR(0x07)]);
-       err[27] = saa7114_write(client, 0x10, init[REG_ADDR(0x10)]);
-
-       v4l_dbg(1, debug, client, "chip version %x, decoder status 0x%02x\n",
-               saa7114_read(client, 0x00) >> 4,
-               saa7114_read(client, 0x1f));
-       v4l_dbg(1, debug, client,
-               "power save control: 0x%02x, scaler status: 0x%02x\n",
-               saa7114_read(client, 0x88),
-               saa7114_read(client, 0x8f));
-
-
-       for (i = 0x94; i < 0x96; i++) {
-               v4l_dbg(1, debug, client,
-                       "reg[0x%02x] = 0x%02x (0x%02x)\n",
-                       i, saa7114_read(client, i),
-                       decoder->reg[REG_ADDR(i)]);
-       }
-
-       //i = saa7114_write_block(client, init, sizeof(init));
-       return 0;
-}
-
-static int saa7114_remove(struct i2c_client *client)
-{
-       kfree(i2c_get_clientdata(client));
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct i2c_device_id saa7114_id[] = {
-       { "saa7114_old", 0 },   /* "saa7114" maps to the saa7115 driver */
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, saa7114_id);
-
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "saa7114",
-       .driverid = I2C_DRIVERID_SAA7114,
-       .command = saa7114_command,
-       .probe = saa7114_probe,
-       .remove = saa7114_remove,
-       .id_table = saa7114_id,
-};
index 46c796c3fec887010d1da38810fdeac0d1ef2158..cebf159f52cfd4e09bea71d808ba60c21cf35a52 100644 (file)
@@ -778,7 +778,7 @@ static int saa711x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
                break;
 
        case V4L2_CID_HUE:
-               if (ctrl->value < -127 || ctrl->value > 127) {
+               if (ctrl->value < -128 || ctrl->value > 127) {
                        v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
                        return -ERANGE;
                }
@@ -931,8 +931,8 @@ static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std)
        /* Prevent unnecessary standard changes. During a standard
           change the I-Port is temporarily disabled. Any devices
           reading from that port can get confused.
-          Note that VIDIOC_S_STD is also used to switch from
-          radio to TV mode, so if a VIDIOC_S_STD is broadcast to
+          Note that s_std is also used to switch from
+          radio to TV mode, so if a s_std is broadcast to
           all I2C devices then you do not want to have an unwanted
           side-effect here. */
        if (std == state->std)
@@ -1206,10 +1206,12 @@ static int saa711x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
 {
        switch (qc->id) {
        case V4L2_CID_BRIGHTNESS:
+               return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
        case V4L2_CID_CONTRAST:
        case V4L2_CID_SATURATION:
+               return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
        case V4L2_CID_HUE:
-               return v4l2_ctrl_query_fill_std(qc);
+               return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
        default:
                return -EINVAL;
        }
@@ -1308,11 +1310,12 @@ static int saa711x_s_stream(struct v4l2_subdev *sd, int enable)
        v4l2_dbg(1, debug, sd, "%s output\n",
                        enable ? "enable" : "disable");
 
-       if (state->enable != enable) {
-               state->enable = enable;
-               saa711x_write(sd, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
-                               state->enable);
-       }
+       if (state->enable == enable)
+               return 0;
+       state->enable = enable;
+       if (!saa711x_has_reg(state->ident, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED))
+               return 0;
+       saa711x_write(sd, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, state->enable);
        return 0;
 }
 
@@ -1370,6 +1373,47 @@ static int saa711x_g_vbi_data(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_dat
        }
 }
 
+static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+       struct saa711x_state *state = to_state(sd);
+       int reg1e;
+
+       *std = V4L2_STD_ALL;
+       if (state->ident != V4L2_IDENT_SAA7115)
+               return 0;
+       reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
+
+       switch (reg1e & 0x03) {
+       case 1:
+               *std = V4L2_STD_NTSC;
+               break;
+       case 2:
+               *std = V4L2_STD_PAL;
+               break;
+       case 3:
+               *std = V4L2_STD_SECAM;
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int saa711x_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+       struct saa711x_state *state = to_state(sd);
+       int reg1e = 0x80;
+       int reg1f;
+
+       *status = V4L2_IN_ST_NO_SIGNAL;
+       if (state->ident == V4L2_IDENT_SAA7115)
+               reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
+       reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
+       if ((reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80)
+               *status = 0;
+       return 0;
+}
+
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int saa711x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
@@ -1493,6 +1537,8 @@ static const struct v4l2_subdev_video_ops saa711x_video_ops = {
        .g_vbi_data = saa711x_g_vbi_data,
        .decode_vbi_line = saa711x_decode_vbi_line,
        .s_stream = saa711x_s_stream,
+       .querystd = saa711x_querystd,
+       .g_input_status = saa711x_g_input_status,
 };
 
 static const struct v4l2_subdev_ops saa711x_ops = {
index 05221d47dd4c9e464db5483c94d52435acd764b6..128bb8b8dbbf1ba16ee97224862b89e2fb243888 100644 (file)
@@ -810,7 +810,6 @@ MODULE_DEVICE_TABLE(i2c, saa7127_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "saa7127",
-       .driverid = I2C_DRIVERID_SAA7127,
        .probe = saa7127_probe,
        .remove = saa7127_remove,
        .id_table = saa7127_id,
index fc2164e28e76d11bbcb12fa60de4cb69d8acb7f3..0ba68987bfce96c541788eddd94d3a1d2bd334b7 100644 (file)
@@ -6,6 +6,7 @@ config VIDEO_SAA7134
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
        select CRC32
+       select VIDEO_SAA6588 if VIDEO_HELPER_CHIPS_AUTO
        ---help---
          This is a video4linux driver for Philips SAA713x based
          TV cards.
@@ -35,8 +36,16 @@ config VIDEO_SAA7134_DVB
        select DVB_TDA10086 if !DVB_FE_CUSTOMISE
        select DVB_TDA826X if !DVB_FE_CUSTOMISE
        select DVB_ISL6421 if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
-       select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+       select DVB_ISL6405 if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
+       select DVB_ZL10036 if !DVB_FE_CUSTOMISE
+       select DVB_MT312 if !DVB_FE_CUSTOMISE
+       select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+       select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+       select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
        ---help---
          This adds support for DVB cards based on the
          Philips saa7134 chip.
index 1fee6e84a512c77ac4e8dffaadca0d994a6fb9bf..dc2213e2f86e67095f11a17206ddce66413181c5 100644 (file)
 #include <linux/i2c.h>
 #include <linux/types.h>
 #include <linux/videodev2.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/v4l2-i2c-drv.h>
 #include <linux/init.h>
 #include <linux/crc32.h>
 
 #define MPEG_TOTAL_TARGET_BITRATE_MAX  27000
 #define MPEG_PID_MAX ((1 << 14) - 1)
 
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END};
-
-I2C_CLIENT_INSMOD;
 
 MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder");
 MODULE_AUTHOR("Andrew de Quincey");
@@ -95,6 +92,7 @@ static const struct v4l2_format v4l2_format_table[] =
 };
 
 struct saa6752hs_state {
+       struct v4l2_subdev            sd;
        int                           chip;
        u32                           revision;
        int                           has_ac3;
@@ -115,6 +113,11 @@ enum saa6752hs_command {
        SAA6752HS_COMMAND_MAX
 };
 
+static inline struct saa6752hs_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct saa6752hs_state, sd);
+}
+
 /* ---------------------------------------------------------------------- */
 
 static u8 PAT[] = {
@@ -360,185 +363,191 @@ static int saa6752hs_set_bitrate(struct i2c_client *client,
        return 0;
 }
 
-static void saa6752hs_set_subsampling(struct i2c_client *client,
-                                     struct v4l2_format *f)
-{
-       struct saa6752hs_state *h = i2c_get_clientdata(client);
-       int dist_352, dist_480, dist_720;
-
-       /*
-         FIXME: translate and round width/height into EMPRESS
-         subsample type:
 
-         type   |   PAL   |  NTSC
-         ---------------------------
-         SIF    | 352x288 | 352x240
-         1/2 D1 | 352x576 | 352x480
-         2/3 D1 | 480x576 | 480x480
-         D1     | 720x576 | 720x480
-       */
-
-       dist_352 = abs(f->fmt.pix.width - 352);
-       dist_480 = abs(f->fmt.pix.width - 480);
-       dist_720 = abs(f->fmt.pix.width - 720);
-       if (dist_720 < dist_480) {
-               f->fmt.pix.width = 720;
-               f->fmt.pix.height = 576;
-               h->video_format = SAA6752HS_VF_D1;
-       }
-       else if (dist_480 < dist_352) {
-               f->fmt.pix.width = 480;
-               f->fmt.pix.height = 576;
-               h->video_format = SAA6752HS_VF_2_3_D1;
-       }
-       else {
-               f->fmt.pix.width = 352;
-               if (abs(f->fmt.pix.height - 576) <
-                   abs(f->fmt.pix.height - 288)) {
-                       f->fmt.pix.height = 576;
-                       h->video_format = SAA6752HS_VF_1_2_D1;
-               }
-               else {
-                       f->fmt.pix.height = 288;
-                       h->video_format = SAA6752HS_VF_SIF;
-               }
+static int get_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
+               struct v4l2_ext_control *ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
+               break;
+       case V4L2_CID_MPEG_STREAM_PID_PMT:
+               ctrl->value = params->ts_pid_pmt;
+               break;
+       case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+               ctrl->value = params->ts_pid_audio;
+               break;
+       case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+               ctrl->value = params->ts_pid_video;
+               break;
+       case V4L2_CID_MPEG_STREAM_PID_PCR:
+               ctrl->value = params->ts_pid_pcr;
+               break;
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               ctrl->value = params->au_encoding;
+               break;
+       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+               ctrl->value = params->au_l2_bitrate;
+               break;
+       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+               if (!has_ac3)
+                       return -EINVAL;
+               ctrl->value = params->au_ac3_bitrate;
+               break;
+       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+               ctrl->value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               ctrl->value = params->vi_aspect;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               ctrl->value = params->vi_bitrate * 1000;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+               ctrl->value = params->vi_bitrate_peak * 1000;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               ctrl->value = params->vi_bitrate_mode;
+               break;
+       default:
+               return -EINVAL;
        }
+       return 0;
 }
 
-
 static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
-               struct v4l2_ext_control *ctrl, unsigned int cmd)
+               struct v4l2_ext_control *ctrl, int set)
 {
        int old = 0, new;
-       int set = (cmd == VIDIOC_S_EXT_CTRLS);
 
        new = ctrl->value;
        switch (ctrl->id) {
-               case V4L2_CID_MPEG_STREAM_TYPE:
-                       old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
-                       if (set && new != old)
-                               return -ERANGE;
-                       new = old;
-                       break;
-               case V4L2_CID_MPEG_STREAM_PID_PMT:
-                       old = params->ts_pid_pmt;
-                       if (set && new > MPEG_PID_MAX)
-                               return -ERANGE;
-                       if (new > MPEG_PID_MAX)
-                               new = MPEG_PID_MAX;
-                       params->ts_pid_pmt = new;
-                       break;
-               case V4L2_CID_MPEG_STREAM_PID_AUDIO:
-                       old = params->ts_pid_audio;
-                       if (set && new > MPEG_PID_MAX)
-                               return -ERANGE;
-                       if (new > MPEG_PID_MAX)
-                               new = MPEG_PID_MAX;
-                       params->ts_pid_audio = new;
-                       break;
-               case V4L2_CID_MPEG_STREAM_PID_VIDEO:
-                       old = params->ts_pid_video;
-                       if (set && new > MPEG_PID_MAX)
-                               return -ERANGE;
-                       if (new > MPEG_PID_MAX)
-                               new = MPEG_PID_MAX;
-                       params->ts_pid_video = new;
-                       break;
-               case V4L2_CID_MPEG_STREAM_PID_PCR:
-                       old = params->ts_pid_pcr;
-                       if (set && new > MPEG_PID_MAX)
-                               return -ERANGE;
-                       if (new > MPEG_PID_MAX)
-                               new = MPEG_PID_MAX;
-                       params->ts_pid_pcr = new;
-                       break;
-               case V4L2_CID_MPEG_AUDIO_ENCODING:
-                       old = params->au_encoding;
-                       if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
-                           (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3))
-                               return -ERANGE;
-                       new = old;
-                       break;
-               case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
-                       old = params->au_l2_bitrate;
-                       if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K &&
-                                  new != V4L2_MPEG_AUDIO_L2_BITRATE_384K)
-                               return -ERANGE;
-                       if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K)
-                               new = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
-                       else
-                               new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
-                       params->au_l2_bitrate = new;
-                       break;
-               case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
-                       if (!has_ac3)
-                               return -EINVAL;
-                       old = params->au_ac3_bitrate;
-                       if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K &&
-                                  new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K)
-                               return -ERANGE;
-                       if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K)
-                               new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K;
-                       else
-                               new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K;
-                       params->au_ac3_bitrate = new;
-                       break;
-               case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
-                       old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
-                       if (set && new != old)
-                               return -ERANGE;
-                       new = old;
-                       break;
-               case V4L2_CID_MPEG_VIDEO_ENCODING:
-                       old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
-                       if (set && new != old)
-                               return -ERANGE;
-                       new = old;
-                       break;
-               case V4L2_CID_MPEG_VIDEO_ASPECT:
-                       old = params->vi_aspect;
-                       if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 &&
-                                  new != V4L2_MPEG_VIDEO_ASPECT_4x3)
-                               return -ERANGE;
-                       if (new != V4L2_MPEG_VIDEO_ASPECT_16x9)
-                               new = V4L2_MPEG_VIDEO_ASPECT_4x3;
-                       params->vi_aspect = new;
-                       break;
-               case V4L2_CID_MPEG_VIDEO_BITRATE:
-                       old = params->vi_bitrate * 1000;
-                       new = 1000 * (new / 1000);
-                       if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
-                               return -ERANGE;
-                       if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
-                               new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
-                       params->vi_bitrate = new / 1000;
-                       break;
-               case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
-                       old = params->vi_bitrate_peak * 1000;
-                       new = 1000 * (new / 1000);
-                       if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
-                               return -ERANGE;
-                       if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
-                               new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
-                       params->vi_bitrate_peak = new / 1000;
-                       break;
-               case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-                       old = params->vi_bitrate_mode;
-                       params->vi_bitrate_mode = new;
-                       break;
-               default:
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
+               if (set && new != old)
+                       return -ERANGE;
+               new = old;
+               break;
+       case V4L2_CID_MPEG_STREAM_PID_PMT:
+               old = params->ts_pid_pmt;
+               if (set && new > MPEG_PID_MAX)
+                       return -ERANGE;
+               if (new > MPEG_PID_MAX)
+                       new = MPEG_PID_MAX;
+               params->ts_pid_pmt = new;
+               break;
+       case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+               old = params->ts_pid_audio;
+               if (set && new > MPEG_PID_MAX)
+                       return -ERANGE;
+               if (new > MPEG_PID_MAX)
+                       new = MPEG_PID_MAX;
+               params->ts_pid_audio = new;
+               break;
+       case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+               old = params->ts_pid_video;
+               if (set && new > MPEG_PID_MAX)
+                       return -ERANGE;
+               if (new > MPEG_PID_MAX)
+                       new = MPEG_PID_MAX;
+               params->ts_pid_video = new;
+               break;
+       case V4L2_CID_MPEG_STREAM_PID_PCR:
+               old = params->ts_pid_pcr;
+               if (set && new > MPEG_PID_MAX)
+                       return -ERANGE;
+               if (new > MPEG_PID_MAX)
+                       new = MPEG_PID_MAX;
+               params->ts_pid_pcr = new;
+               break;
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               old = params->au_encoding;
+               if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
+                   (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3))
+                       return -ERANGE;
+               new = old;
+               break;
+       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+               old = params->au_l2_bitrate;
+               if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K &&
+                          new != V4L2_MPEG_AUDIO_L2_BITRATE_384K)
+                       return -ERANGE;
+               if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K)
+                       new = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
+               else
+                       new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
+               params->au_l2_bitrate = new;
+               break;
+       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+               if (!has_ac3)
                        return -EINVAL;
+               old = params->au_ac3_bitrate;
+               if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K &&
+                          new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K)
+                       return -ERANGE;
+               if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K)
+                       new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K;
+               else
+                       new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K;
+               params->au_ac3_bitrate = new;
+               break;
+       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+               old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
+               if (set && new != old)
+                       return -ERANGE;
+               new = old;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+               if (set && new != old)
+                       return -ERANGE;
+               new = old;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               old = params->vi_aspect;
+               if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 &&
+                          new != V4L2_MPEG_VIDEO_ASPECT_4x3)
+                       return -ERANGE;
+               if (new != V4L2_MPEG_VIDEO_ASPECT_16x9)
+                       new = V4L2_MPEG_VIDEO_ASPECT_4x3;
+               params->vi_aspect = new;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               old = params->vi_bitrate * 1000;
+               new = 1000 * (new / 1000);
+               if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+                       return -ERANGE;
+               if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+                       new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
+               params->vi_bitrate = new / 1000;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+               old = params->vi_bitrate_peak * 1000;
+               new = 1000 * (new / 1000);
+               if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+                       return -ERANGE;
+               if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+                       new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
+               params->vi_bitrate_peak = new / 1000;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               old = params->vi_bitrate_mode;
+               params->vi_bitrate_mode = new;
+               break;
+       default:
+               return -EINVAL;
        }
-       if (cmd == VIDIOC_G_EXT_CTRLS)
-               ctrl->value = old;
-       else
-               ctrl->value = new;
+       ctrl->value = new;
        return 0;
 }
 
-static int saa6752hs_qctrl(struct saa6752hs_state *h,
-               struct v4l2_queryctrl *qctrl)
+
+static int saa6752hs_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
 {
+       struct saa6752hs_state *h = to_state(sd);
        struct saa6752hs_mpeg_params *params = &h->params;
        int err;
 
@@ -583,7 +592,7 @@ static int saa6752hs_qctrl(struct saa6752hs_state *h,
                                V4L2_MPEG_VIDEO_ASPECT_4x3);
 
        case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
-               err = v4l2_ctrl_query_fill_std(qctrl);
+               err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
                if (err == 0 &&
                    params->vi_bitrate_mode ==
                                V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
@@ -597,12 +606,20 @@ static int saa6752hs_qctrl(struct saa6752hs_state *h,
                                V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
 
        case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+                               V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
+                               V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
        case V4L2_CID_MPEG_VIDEO_BITRATE:
+               return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
        case V4L2_CID_MPEG_STREAM_PID_PMT:
+               return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16);
        case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+               return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260);
        case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+               return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256);
        case V4L2_CID_MPEG_STREAM_PID_PCR:
-               return v4l2_ctrl_query_fill_std(qctrl);
+               return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259);
 
        default:
                break;
@@ -610,8 +627,7 @@ static int saa6752hs_qctrl(struct saa6752hs_state *h,
        return -EINVAL;
 }
 
-static int saa6752hs_qmenu(struct saa6752hs_state *h,
-               struct v4l2_querymenu *qmenu)
+static int saa6752hs_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qmenu)
 {
        static const u32 mpeg_audio_encoding[] = {
                V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
@@ -632,11 +648,12 @@ static int saa6752hs_qmenu(struct saa6752hs_state *h,
                V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
                V4L2_CTRL_MENU_IDS_END
        };
+       struct saa6752hs_state *h = to_state(sd);
        struct v4l2_queryctrl qctrl;
        int err;
 
        qctrl.id = qmenu->id;
-       err = saa6752hs_qctrl(h, &qctrl);
+       err = saa6752hs_queryctrl(sd, &qctrl);
        if (err)
                return err;
        switch (qmenu->id) {
@@ -656,17 +673,16 @@ static int saa6752hs_qmenu(struct saa6752hs_state *h,
        return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
 }
 
-static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes)
+static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes)
 {
        unsigned char buf[9], buf2[4];
-       struct saa6752hs_state *h;
+       struct saa6752hs_state *h = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        unsigned size;
        u32 crc;
        unsigned char localPAT[256];
        unsigned char localPMT[256];
 
-       h = i2c_get_clientdata(client);
-
        /* Set video format - must be done first as it resets other settings */
        set_reg8(client, 0x41, h->video_format);
 
@@ -762,7 +778,7 @@ static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes)
        buf[3] = 0x82;
        buf[4] = 0xB0;
        buf[5] = buf2[0];
-       switch(h->params.vi_aspect) {
+       switch (h->params.vi_aspect) {
        case V4L2_MPEG_VIDEO_ASPECT_16x9:
                buf[6] = buf2[1] | 0x40;
                break;
@@ -770,7 +786,6 @@ static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes)
        default:
                buf[6] = buf2[1] & 0xBF;
                break;
-               break;
        }
        buf[7] = buf2[2];
        buf[8] = buf2[3];
@@ -779,81 +794,162 @@ static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes)
        return 0;
 }
 
-static int
-saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int saa6752hs_do_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls, int set)
 {
-       struct saa6752hs_state *h = i2c_get_clientdata(client);
-       struct v4l2_ext_controls *ctrls = arg;
+       struct saa6752hs_state *h = to_state(sd);
        struct saa6752hs_mpeg_params params;
-       int err = 0;
        int i;
 
-       switch (cmd) {
-       case VIDIOC_INT_INIT:
-               /* apply settings and start encoder */
-               saa6752hs_init(client, *(u32 *)arg);
-               break;
-       case VIDIOC_S_EXT_CTRLS:
-               if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-                       return -EINVAL;
-               /* fall through */
-       case VIDIOC_TRY_EXT_CTRLS:
-       case VIDIOC_G_EXT_CTRLS:
-               if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-                       return -EINVAL;
-               params = h->params;
-               for (i = 0; i < ctrls->count; i++) {
-                       err = handle_ctrl(h->has_ac3, &params, ctrls->controls + i, cmd);
-                       if (err) {
-                               ctrls->error_idx = i;
-                               return err;
-                       }
+       if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+               return -EINVAL;
+
+       params = h->params;
+       for (i = 0; i < ctrls->count; i++) {
+               int err = handle_ctrl(h->has_ac3, &params, ctrls->controls + i, set);
+
+               if (err) {
+                       ctrls->error_idx = i;
+                       return err;
                }
-               h->params = params;
-               break;
-       case VIDIOC_QUERYCTRL:
-               return saa6752hs_qctrl(h, arg);
-       case VIDIOC_QUERYMENU:
-               return saa6752hs_qmenu(h, arg);
-       case VIDIOC_G_FMT:
-       {
-          struct v4l2_format *f = arg;
-
-          if (h->video_format == SAA6752HS_VF_UNKNOWN)
-                  h->video_format = SAA6752HS_VF_D1;
-          f->fmt.pix.width =
-                  v4l2_format_table[h->video_format].fmt.pix.width;
-          f->fmt.pix.height =
-                  v4l2_format_table[h->video_format].fmt.pix.height;
-          break ;
        }
-       case VIDIOC_S_FMT:
-       {
-               struct v4l2_format *f = arg;
+       if (set)
+               h->params = params;
+       return 0;
+}
 
-               saa6752hs_set_subsampling(client, f);
-               break;
+static int saa6752hs_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
+{
+       return saa6752hs_do_ext_ctrls(sd, ctrls, 1);
+}
+
+static int saa6752hs_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
+{
+       return saa6752hs_do_ext_ctrls(sd, ctrls, 0);
+}
+
+static int saa6752hs_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
+{
+       struct saa6752hs_state *h = to_state(sd);
+       int i;
+
+       if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+               return -EINVAL;
+
+       for (i = 0; i < ctrls->count; i++) {
+               int err = get_ctrl(h->has_ac3, &h->params, ctrls->controls + i);
+
+               if (err) {
+                       ctrls->error_idx = i;
+                       return err;
+               }
        }
-       case VIDIOC_S_STD:
-               h->standard = *((v4l2_std_id *) arg);
-               break;
+       return 0;
+}
 
-       case VIDIOC_DBG_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client,
-                               arg, h->chip, h->revision);
+static int saa6752hs_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+       struct saa6752hs_state *h = to_state(sd);
 
-       default:
-               /* nothing */
-               break;
+       if (h->video_format == SAA6752HS_VF_UNKNOWN)
+               h->video_format = SAA6752HS_VF_D1;
+       f->fmt.pix.width =
+               v4l2_format_table[h->video_format].fmt.pix.width;
+       f->fmt.pix.height =
+               v4l2_format_table[h->video_format].fmt.pix.height;
+       return 0;
+}
+
+static int saa6752hs_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+       struct saa6752hs_state *h = to_state(sd);
+       int dist_352, dist_480, dist_720;
+
+       /*
+         FIXME: translate and round width/height into EMPRESS
+         subsample type:
+
+         type   |   PAL   |  NTSC
+         ---------------------------
+         SIF    | 352x288 | 352x240
+         1/2 D1 | 352x576 | 352x480
+         2/3 D1 | 480x576 | 480x480
+         D1     | 720x576 | 720x480
+       */
+
+       dist_352 = abs(f->fmt.pix.width - 352);
+       dist_480 = abs(f->fmt.pix.width - 480);
+       dist_720 = abs(f->fmt.pix.width - 720);
+       if (dist_720 < dist_480) {
+               f->fmt.pix.width = 720;
+               f->fmt.pix.height = 576;
+               h->video_format = SAA6752HS_VF_D1;
+       } else if (dist_480 < dist_352) {
+               f->fmt.pix.width = 480;
+               f->fmt.pix.height = 576;
+               h->video_format = SAA6752HS_VF_2_3_D1;
+       } else {
+               f->fmt.pix.width = 352;
+               if (abs(f->fmt.pix.height - 576) <
+                   abs(f->fmt.pix.height - 288)) {
+                       f->fmt.pix.height = 576;
+                       h->video_format = SAA6752HS_VF_1_2_D1;
+               } else {
+                       f->fmt.pix.height = 288;
+                       h->video_format = SAA6752HS_VF_SIF;
+               }
        }
+       return 0;
+}
+
+static int saa6752hs_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct saa6752hs_state *h = to_state(sd);
+
+       h->standard = std;
+       return 0;
+}
 
-       return err;
+static int saa6752hs_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct saa6752hs_state *h = to_state(sd);
+
+       return v4l2_chip_ident_i2c_client(client,
+                       chip, h->chip, h->revision);
 }
 
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops saa6752hs_core_ops = {
+       .g_chip_ident = saa6752hs_g_chip_ident,
+       .init = saa6752hs_init,
+       .queryctrl = saa6752hs_queryctrl,
+       .querymenu = saa6752hs_querymenu,
+       .g_ext_ctrls = saa6752hs_g_ext_ctrls,
+       .s_ext_ctrls = saa6752hs_s_ext_ctrls,
+       .try_ext_ctrls = saa6752hs_try_ext_ctrls,
+};
+
+static const struct v4l2_subdev_tuner_ops saa6752hs_tuner_ops = {
+       .s_std = saa6752hs_s_std,
+};
+
+static const struct v4l2_subdev_video_ops saa6752hs_video_ops = {
+       .s_fmt = saa6752hs_s_fmt,
+       .g_fmt = saa6752hs_g_fmt,
+};
+
+static const struct v4l2_subdev_ops saa6752hs_ops = {
+       .core = &saa6752hs_core_ops,
+       .tuner = &saa6752hs_tuner_ops,
+       .video = &saa6752hs_video_ops,
+};
+
 static int saa6752hs_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+               const struct i2c_device_id *id)
 {
        struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL);
+       struct v4l2_subdev *sd;
        u8 addr = 0x13;
        u8 data[12];
 
@@ -861,6 +957,8 @@ static int saa6752hs_probe(struct i2c_client *client,
                        client->addr << 1, client->adapter->name);
        if (h == NULL)
                return -ENOMEM;
+       sd = &h->sd;
+       v4l2_i2c_subdev_init(sd, client, &saa6752hs_ops);
 
        i2c_master_send(client, &addr, 1);
        i2c_master_recv(client, data, sizeof(data));
@@ -874,14 +972,15 @@ static int saa6752hs_probe(struct i2c_client *client,
        }
        h->params = param_defaults;
        h->standard = 0; /* Assume 625 input lines */
-
-       i2c_set_clientdata(client, h);
        return 0;
 }
 
 static int saa6752hs_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
        return 0;
 }
 
@@ -893,8 +992,6 @@ MODULE_DEVICE_TABLE(i2c, saa6752hs_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "saa6752hs",
-       .driverid = I2C_DRIVERID_SAA6752HS,
-       .command = saa6752hs_command,
        .probe = saa6752hs_probe,
        .remove = saa6752hs_remove,
        .id_table = saa6752hs_id,
index e2febcd6e529f45245bbd02c6c7e684ca9e14fe5..a790a7246a631c64439ba06ee1ee93c40ee8ee30 100644 (file)
@@ -31,6 +31,7 @@
 #include <media/v4l2-common.h>
 #include <media/tveeprom.h>
 #include "tea5767.h"
+#include "tda18271.h"
 
 /* commly used strings */
 static char name_mute[]    = "mute";
@@ -272,6 +273,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .empress_addr   = 0x20,
 
                .inputs         = {{
                        .name = name_comp1,
@@ -408,6 +410,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .empress_addr   = 0x20,
                .tda9887_conf   = TDA9887_PRESENT,
                .gpiomask       = 0x820000,
                .inputs         = {{
@@ -818,6 +821,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .empress_addr   = 0x20,
                .inputs         = {{
                        .name = name_comp1,
                        .vmux = 4,
@@ -977,6 +981,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .empress_addr   = 0x20,
                .inputs         = {{
                        .name = name_comp1,
                        .vmux = 1,
@@ -1699,6 +1704,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,
@@ -2364,6 +2370,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .empress_addr   = 0x21,
                .inputs         = {{
                        .name   = "Composite 0",
                        .vmux   = 0,
@@ -3291,6 +3298,68 @@ struct saa7134_board saa7134_boards[] = {
                        .gpio = 0x0200100,
                },
        },
+       [SAA7134_BOARD_HAUPPAUGE_HVR1120] = {
+               .name           = "Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tuner_config   = 3,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .ts_type        = SAA7134_MPEG_TS_SERIAL,
+               .gpiomask       = 0x0800100, /* GPIO 21 is an INPUT */
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+                       .gpio = 0x0000100,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = TV,
+                       .gpio = 0x0800100, /* GPIO 23 HI for FM */
+               },
+       },
+       [SAA7134_BOARD_HAUPPAUGE_HVR1110R3] = {
+               .name           = "Hauppauge WinTV-HVR1110r3",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tuner_config   = 3,
+               .gpiomask       = 0x0800100, /* GPIO 21 is an INPUT */
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+                       .gpio = 0x0000100,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = TV,
+                       .gpio = 0x0800100, /* GPIO 23 HI for FM */
+               },
+       },
        [SAA7134_BOARD_CINERGY_HT_PCMCIA] = {
                .name           = "Terratec Cinergy HT PCMCIA",
                .audio_clock    = 0x00187de7,
@@ -4070,6 +4139,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .empress_addr   = 0x20,
                .tda9887_conf   = TDA9887_PRESENT,
                .inputs         = { {
                        .name = name_tv,
@@ -4106,6 +4176,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .empress_addr   = 0x20,
                .tda9887_conf   = TDA9887_PRESENT,
                .inputs         = { {
                        .name = name_tv,
@@ -4143,6 +4214,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .empress_addr   = 0x20,
                .tda9887_conf   = TDA9887_PRESENT,
                .inputs         = { {
                        .name = name_tv,
@@ -4323,13 +4395,13 @@ struct saa7134_board saa7134_boards[] = {
                         .amux = TV,
                         .tv   = 1,
                 }, {
-                        .name = name_comp,
-                        .vmux = 0,
+                        .name = name_comp1,
+                        .vmux = 3,
                         .amux = LINE1,
                 }, {
                         .name = name_svideo,
                         .vmux = 8,
-                        .amux = LINE1,
+                        .amux = LINE2,
                 } },
                 .radio = {
                         .name = name_radio,
@@ -4421,8 +4493,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               /* no DVB support for now */
-               /* .mpeg           = SAA7134_MPEG_DVB, */
+               .mpeg           = SAA7134_MPEG_DVB,
                .inputs         = { {
                        .name = name_comp,
                        .vmux = 1,
@@ -4441,8 +4512,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               /* no DVB support for now */
-               /* .mpeg           = SAA7134_MPEG_DVB, */
+               .mpeg           = SAA7134_MPEG_DVB,
                .inputs         = { {
                        .name = name_comp,
                        .vmux = 1,
@@ -4611,7 +4681,7 @@ struct saa7134_board saa7134_boards[] = {
                .tuner_type     = TUNER_YMEC_TVF_5533MF,
                .radio_type     = TUNER_TEA5767,
                .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
+               .radio_addr     = 0x60,
                .gpiomask       = 0x80000700,
                .inputs = { {
                        .name   = name_tv,
@@ -5402,6 +5472,36 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x0070,
                .subdevice    = 0x6705,
                .driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0070,
+               .subdevice    = 0x6706,
+               .driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1120,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0070,
+               .subdevice    = 0x6707,
+               .driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110R3,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0070,
+               .subdevice    = 0x6708,
+               .driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1120,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0070,
+               .subdevice    = 0x6709,
+               .driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110R3,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0070,
+               .subdevice    = 0x670a,
+               .driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110R3,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -5821,8 +5921,8 @@ static int saa7134_xc2028_callback(struct saa7134_dev *dev,
 }
 
 
-static int saa7134_tda8290_callback(struct saa7134_dev *dev,
-                                   int command, int arg)
+static int saa7134_tda8290_827x_callback(struct saa7134_dev *dev,
+                                        int command, int arg)
 {
        u8 sync_control;
 
@@ -5848,6 +5948,65 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev,
        return 0;
 }
 
+static inline int saa7134_tda18271_hvr11x0_toggle_agc(struct saa7134_dev *dev,
+                                                     enum tda18271_mode mode)
+{
+       /* toggle AGC switch through GPIO 26 */
+       switch (mode) {
+       case TDA18271_ANALOG:
+               saa7134_set_gpio(dev, 26, 0);
+               break;
+       case TDA18271_DIGITAL:
+               saa7134_set_gpio(dev, 26, 1);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
+                                         int command, int arg)
+{
+       int ret = 0;
+
+       switch (command) {
+       case TDA18271_CALLBACK_CMD_AGC_ENABLE: /* 0 */
+               switch (dev->board) {
+               case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+               case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
+                       ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static int saa7134_tda8290_callback(struct saa7134_dev *dev,
+                                   int command, int arg)
+{
+       int ret;
+
+       switch (dev->board) {
+       case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+       case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
+               /* tda8290 + tda18271 */
+               ret = saa7134_tda8290_18271_callback(dev, command, arg);
+               break;
+       default:
+               /* tda8290 + tda827x */
+               ret = saa7134_tda8290_827x_callback(dev, command, arg);
+               break;
+       }
+       return ret;
+}
+
 int saa7134_tuner_callback(void *priv, int component, int command, int arg)
 {
        struct saa7134_dev *dev = priv;
@@ -5878,11 +6037,16 @@ static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data)
        switch (tv.model) {
        case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */
        case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */
+       case 67201: /* WinTV-HVR1120 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */
+       case 67301: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */
+       case 67209: /* WinTV-HVR1110 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */
        case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
        case 67569: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM) */
        case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */
        case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
        case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
+       case 67651: /* WinTV-HVR1120 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
+       case 67659: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
                break;
        default:
                printk(KERN_WARNING "%s: warning: "
@@ -6019,6 +6183,11 @@ int saa7134_board_init1(struct saa7134_dev *dev)
                msleep(10);
                break;
        case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+               saa7134_set_gpio(dev, 23, 0);
+               msleep(10);
+               saa7134_set_gpio(dev, 23, 1);
+               dev->has_remote = SAA7134_REMOTE_I2C;
+               break;
        case SAA7134_BOARD_AVERMEDIA_M103:
                saa7134_set_gpio(dev, 23, 0);
                msleep(10);
@@ -6054,6 +6223,16 @@ int saa7134_board_init1(struct saa7134_dev *dev)
 
                saa_writeb (SAA7134_PRODUCTION_TEST_MODE, 0x00);
                break;
+       case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+       case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
+               /* GPIO 26 high for digital, low for analog */
+               saa7134_set_gpio(dev, 26, 0);
+               msleep(1);
+
+               saa7134_set_gpio(dev, 22, 0);
+               msleep(10);
+               saa7134_set_gpio(dev, 22, 1);
+               break;
        /* i2c remotes */
        case SAA7134_BOARD_PINNACLE_PCTV_110i:
        case SAA7134_BOARD_PINNACLE_PCTV_310i:
@@ -6079,15 +6258,15 @@ int saa7134_board_init1(struct saa7134_dev *dev)
                saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x8c040007, 0x8c040007);
                saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd);
                break;
-       case SAA7134_BOARD_AVERMEDIA_A700_PRO:
        case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
-               /* write windows gpio values */
-               saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x80040100, 0x80040100);
-               saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
                printk("%s: %s: hybrid analog/dvb card\n"
-                      "%s: Sorry, only analog s-video and composite input "
+                      "%s: Sorry, of the analog inputs, only analog s-video and composite "
                       "are supported for now.\n",
                        dev->name, card(dev).name, dev->name);
+       case SAA7134_BOARD_AVERMEDIA_A700_PRO:
+               /* write windows gpio values */
+               saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x80040100, 0x80040100);
+               saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
                break;
        }
        return 0;
@@ -6109,7 +6288,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev)
 
                tun_setup.mode_mask = T_RADIO;
 
-               saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+               saa_call_all(dev, tuner, s_type_addr, &tun_setup);
                mode_mask &= ~T_RADIO;
        }
 
@@ -6121,7 +6300,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev)
 
                tun_setup.mode_mask = mode_mask;
 
-               saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+               saa_call_all(dev, tuner, s_type_addr, &tun_setup);
        }
 
        if (dev->tda9887_conf) {
@@ -6130,8 +6309,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev)
                tda9887_cfg.tuner = TUNER_TDA9887;
                tda9887_cfg.priv = &dev->tda9887_conf;
 
-               saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
-                                        &tda9887_cfg);
+               saa_call_all(dev, tuner, s_config, &tda9887_cfg);
        }
 
        if (dev->tuner_type == TUNER_XC2028) {
@@ -6158,7 +6336,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev)
                xc2028_cfg.tuner = TUNER_XC2028;
                xc2028_cfg.priv  = &ctl;
 
-               saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg);
+               saa_call_all(dev, tuner, s_config, &xc2028_cfg);
        }
 }
 
@@ -6168,9 +6346,20 @@ int saa7134_board_init2(struct saa7134_dev *dev)
        unsigned char buf;
        int board;
 
+       /* Put here the code that enables the chips that are needed
+          for analog mode and doesn't depend on the tuner attachment.
+          It is also a good idea to get tuner type from eeprom, etc before
+          initializing tuner, since we can avoid loading tuner driver
+          on devices that has TUNER_ABSENT
+        */
        switch (dev->board) {
        case SAA7134_BOARD_BMK_MPEX_NOTUNER:
        case SAA7134_BOARD_BMK_MPEX_TUNER:
+               /* Checks if the device has a tuner at 0x60 addr
+                  If the device doesn't have a tuner, TUNER_ABSENT
+                  will be used at tuner_type, avoiding loading tuner
+                  without needing it
+                */
                dev->i2c_client.addr = 0x60;
                board = (i2c_master_recv(&dev->i2c_client, &buf, 0) < 0)
                        ? SAA7134_BOARD_BMK_MPEX_NOTUNER
@@ -6188,11 +6377,15 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                u8 subaddr;
                u8 data[3];
                int ret, tuner_t;
-
                struct i2c_msg msg[] = {{.addr=0x50, .flags=0, .buf=&subaddr, .len = 1},
                                        {.addr=0x50, .flags=I2C_M_RD, .buf=data, .len = 3}};
+
                subaddr= 0x14;
                tuner_t = 0;
+
+               /* Retrieve device data from eeprom, checking for the
+                  proper tuner_type.
+                */
                ret = i2c_transfer(&dev->i2c_adap, msg, 2);
                if (ret != 2) {
                        printk(KERN_ERR "EEPROM read failure\n");
@@ -6248,12 +6441,14 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                                dev->name, saa7134_boards[dev->board].name);
                        break;
                }
+               /* break intentionally omitted */
        case SAA7134_BOARD_VIDEOMATE_DVBT_300:
        case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
        {
 
-               /* The Philips EUROPA based hybrid boards have the tuner connected through
-                * the channel decoder. We have to make it transparent to find it
+               /* The Philips EUROPA based hybrid boards have the tuner
+                  connected through the channel decoder. We have to make it
+                  transparent to find it
                 */
                u8 data[] = { 0x07, 0x02};
                struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
@@ -6274,21 +6469,15 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                if (dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) {
                        dev->tuner_type = TUNER_PHILIPS_TDA8290;
 
-                       saa7134_tuner_setup(dev);
-
                        data[2] = 0x68;
                        i2c_transfer(&dev->i2c_adap, &msg, 1);
-
-                       /* Tuner setup is handled before I2C transfer.
-                          Due to that, there's no need to do it later
-                        */
-                       return 0;
+                       break;
                }
                i2c_transfer(&dev->i2c_adap, &msg, 1);
                break;
        }
-       case SAA7134_BOARD_ASUSTeK_TVFM7135:
-       /* The card below is detected as card=53, but is different */
+       case SAA7134_BOARD_ASUSTeK_TVFM7135:
+       /* The card below is detected as card=53, but is different */
               if (dev->autodetected && (dev->eedata[0x27] == 0x03)) {
                       dev->board = SAA7134_BOARD_ASUSTeK_P7131_ANALOG;
                       printk(KERN_INFO "%s: P7131 analog only, using "
@@ -6296,6 +6485,10 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                       dev->name, saa7134_boards[dev->board].name);
               }
               break;
+       case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+       case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
+               hauppauge_eeprom(dev, dev->eedata+0x80);
+               break;
        case SAA7134_BOARD_HAUPPAUGE_HVR1110:
                hauppauge_eeprom(dev, dev->eedata+0x80);
                /* break intentionally omitted */
@@ -6351,22 +6544,6 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                i2c_transfer(&dev->i2c_adap, &msg, 1);
                break;
        }
-       case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
-       case SAA7134_BOARD_KWORLD_ATSC110:
-       {
-               /* enable tuner */
-               int i;
-               static const u8 buffer [] = { 0x10, 0x12, 0x13, 0x04, 0x16,
-                                             0x00, 0x14, 0x04, 0x17, 0x00 };
-               dev->i2c_client.addr = 0x0a;
-               for (i = 0; i < 5; i++)
-                       if (2 != i2c_master_send(&dev->i2c_client,
-                                                &buffer[i*2], 2))
-                               printk(KERN_WARNING
-                                      "%s: Unable to enable tuner(%i).\n",
-                                      dev->name, i);
-               break;
-       }
        case SAA7134_BOARD_VIDEOMATE_DVBT_200:
        case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
                /* The T200 and the T200A share the same pci id.  Consequently,
@@ -6375,9 +6552,9 @@ int saa7134_board_init2(struct saa7134_dev *dev)
 
                /* Don't do this if the board was specifically selected with an
                 * insmod option or if we have the default configuration T200*/
-               if(!dev->autodetected || (dev->eedata[0x41] == 0xd0))
+               if (!dev->autodetected || (dev->eedata[0x41] == 0xd0))
                        break;
-               if(dev->eedata[0x41] == 0x02) {
+               if (dev->eedata[0x41] == 0x02) {
                        /* Reconfigure board  as T200A */
                        dev->board = SAA7134_BOARD_VIDEOMATE_DVBT_200A;
                        dev->tuner_type   = saa7134_boards[dev->board].tuner_type;
@@ -6390,6 +6567,58 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                        break;
                }
                break;
+       case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
+       case SAA7134_BOARD_KWORLD_ATSC110:
+       {
+               struct i2c_msg msg = { .addr = 0x0a, .flags = 0 };
+               int i;
+               static u8 buffer[][2] = {
+                       { 0x10, 0x12 },
+                       { 0x13, 0x04 },
+                       { 0x16, 0x00 },
+                       { 0x14, 0x04 },
+                       { 0x17, 0x00 },
+               };
+
+               for (i = 0; i < ARRAY_SIZE(buffer); i++) {
+                       msg.buf = &buffer[i][0];
+                       msg.len = ARRAY_SIZE(buffer[0]);
+                       if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+                               printk(KERN_WARNING
+                                      "%s: Unable to enable tuner(%i).\n",
+                                      dev->name, i);
+               }
+               break;
+       }
+       } /* switch() */
+
+       /* initialize tuner */
+       if (TUNER_ABSENT != dev->tuner_type) {
+               int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
+
+               /* Note: radio tuner address is always filled in,
+                  so we do not need to probe for a radio tuner device. */
+               if (dev->radio_type != UNSET)
+                       v4l2_i2c_new_subdev(&dev->i2c_adap,
+                               "tuner", "tuner", dev->radio_addr);
+               if (has_demod)
+                       v4l2_i2c_new_probed_subdev(&dev->i2c_adap, "tuner",
+                               "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+               if (dev->tuner_addr == ADDR_UNSET) {
+                       enum v4l2_i2c_tuner_type type =
+                               has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
+
+                       v4l2_i2c_new_probed_subdev(&dev->i2c_adap, "tuner",
+                               "tuner", v4l2_i2c_tuner_addrs(type));
+               } else {
+                       v4l2_i2c_new_subdev(&dev->i2c_adap,
+                               "tuner", "tuner", dev->tuner_addr);
+               }
+       }
+
+       saa7134_tuner_setup(dev);
+
+       switch (dev->board) {
        case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
        {
                struct v4l2_priv_tun_config tea5767_cfg;
@@ -6401,12 +6630,10 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                ctl.xtal_freq = TEA5767_HIGH_LO_13MHz;
                tea5767_cfg.tuner = TUNER_TEA5767;
                tea5767_cfg.priv  = &ctl;
-               saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tea5767_cfg);
+               saa_call_all(dev, tuner, s_config, &tea5767_cfg);
                break;
        }
        } /* switch() */
 
-       saa7134_tuner_setup(dev);
-
        return 0;
 }
index 99221d726edb373603c6d75789459b3209b03b9b..dafa0d88bed09662cace3ba2e153b12f0163b695 100644 (file)
@@ -54,13 +54,9 @@ static unsigned int gpio_tracking;
 module_param(gpio_tracking, int, 0644);
 MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]");
 
-static unsigned int alsa;
+static unsigned int alsa = 1;
 module_param(alsa, int, 0644);
-MODULE_PARM_DESC(alsa,"enable ALSA DMA sound [dmasound]");
-
-static unsigned int oss;
-module_param(oss, int, 0644);
-MODULE_PARM_DESC(oss,"enable OSS DMA sound [dmasound]");
+MODULE_PARM_DESC(alsa,"enable/disable ALSA DMA sound [dmasound]");
 
 static unsigned int latency = UNSET;
 module_param(latency, int, 0444);
@@ -90,8 +86,10 @@ MODULE_PARM_DESC(radio_nr, "radio device number");
 MODULE_PARM_DESC(tuner,    "tuner type");
 MODULE_PARM_DESC(card,     "card type");
 
-static DEFINE_MUTEX(devlist_lock);
+DEFINE_MUTEX(saa7134_devlist_lock);
+EXPORT_SYMBOL(saa7134_devlist_lock);
 LIST_HEAD(saa7134_devlist);
+EXPORT_SYMBOL(saa7134_devlist);
 static LIST_HEAD(mops_list);
 static unsigned int saa7134_devcount;
 
@@ -156,10 +154,10 @@ static void request_module_async(struct work_struct *work){
                request_module("saa7134-empress");
        if (card_is_dvb(dev))
                request_module("saa7134-dvb");
-       if (alsa)
-               request_module("saa7134-alsa");
-       if (oss)
-               request_module("saa7134-oss");
+       if (alsa) {
+               if (dev->pci->device != PCI_DEVICE_ID_PHILIPS_SAA7130)
+                       request_module("saa7134-alsa");
+       }
 }
 
 static void request_submodules(struct saa7134_dev *dev)
@@ -778,7 +776,7 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,
                return NULL;
        *vfd = *template;
        vfd->minor   = -1;
-       vfd->parent  = &dev->pci->dev;
+       vfd->v4l2_dev  = &dev->v4l2_dev;
        vfd->release = video_device_release;
        vfd->debug   = video_debug;
        snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
@@ -851,6 +849,10 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        if (NULL == dev)
                return -ENOMEM;
 
+       err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
+       if (err)
+               goto fail0;
+
        /* pci init */
        dev->pci = pci_dev;
        if (pci_enable_device(pci_dev)) {
@@ -927,6 +929,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        dev->autodetected = card[dev->nr] != dev->board;
        dev->tuner_type = saa7134_boards[dev->board].tuner_type;
        dev->tuner_addr = saa7134_boards[dev->board].tuner_addr;
+       dev->radio_type = saa7134_boards[dev->board].radio_type;
+       dev->radio_addr = saa7134_boards[dev->board].radio_addr;
        dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf;
        if (UNSET != tuner[dev->nr])
                dev->tuner_type = tuner[dev->nr];
@@ -971,23 +975,48 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        /* wait a bit, register i2c bus */
        msleep(100);
        saa7134_i2c_register(dev);
-
-       /* initialize hardware #2 */
-       if (TUNER_ABSENT != dev->tuner_type)
-               request_module("tuner");
        saa7134_board_init2(dev);
 
        saa7134_hwinit2(dev);
 
        /* load i2c helpers */
        if (card_is_empress(dev)) {
-               request_module("saa6752hs");
+               struct v4l2_subdev *sd =
+                       v4l2_i2c_new_subdev(&dev->i2c_adap,
+                               "saa6752hs", "saa6752hs",
+                               saa7134_boards[dev->board].empress_addr);
+
+               if (sd)
+                       sd->grp_id = GRP_EMPRESS;
+       }
+
+       if (saa7134_boards[dev->board].rds_addr) {
+               unsigned short addrs[2] = { 0, I2C_CLIENT_END };
+               struct v4l2_subdev *sd;
+
+               addrs[0] = saa7134_boards[dev->board].rds_addr;
+               sd = v4l2_i2c_new_probed_subdev(&dev->i2c_adap, "saa6588",
+                           "saa6588", addrs);
+               if (sd)
+                       printk(KERN_INFO "%s: found RDS decoder\n", dev->name);
        }
 
        request_submodules(dev);
 
        v4l2_prio_init(&dev->prio);
 
+       mutex_lock(&saa7134_devlist_lock);
+       list_for_each_entry(mops, &mops_list, next)
+               mpeg_ops_attach(mops, dev);
+       list_add_tail(&dev->devlist, &saa7134_devlist);
+       mutex_unlock(&saa7134_devlist_lock);
+
+       /* check for signal */
+       saa7134_irq_video_signalchange(dev);
+
+       if (TUNER_ABSENT != dev->tuner_type)
+               saa_call_all(dev, core, s_standby, 0);
+
        /* register v4l devices */
        if (saa7134_no_overlay > 0)
                printk(KERN_INFO "%s: Overlay support disabled.\n", dev->name);
@@ -1023,24 +1052,10 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        }
 
        /* everything worked */
-       pci_set_drvdata(pci_dev,dev);
        saa7134_devcount++;
 
-       mutex_lock(&devlist_lock);
-       list_for_each_entry(mops, &mops_list, next)
-               mpeg_ops_attach(mops, dev);
-       list_add_tail(&dev->devlist,&saa7134_devlist);
-       mutex_unlock(&devlist_lock);
-
-       /* check for signal */
-       saa7134_irq_video_signalchange(dev);
-
-       if (saa7134_dmasound_init && !dev->dmasound.priv_data) {
+       if (saa7134_dmasound_init && !dev->dmasound.priv_data)
                saa7134_dmasound_init(dev);
-       }
-
-       if (TUNER_ABSENT != dev->tuner_type)
-               saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
 
        return 0;
 
@@ -1055,13 +1070,16 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        release_mem_region(pci_resource_start(pci_dev,0),
                           pci_resource_len(pci_dev,0));
  fail1:
+       v4l2_device_unregister(&dev->v4l2_dev);
+ fail0:
        kfree(dev);
        return err;
 }
 
 static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
 {
-       struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
+       struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+       struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
        struct saa7134_mpeg_ops *mops;
 
        /* Release DMA sound modules if present */
@@ -1088,11 +1106,11 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
        saa7134_hwfini(dev);
 
        /* unregister */
-       mutex_lock(&devlist_lock);
+       mutex_lock(&saa7134_devlist_lock);
        list_del(&dev->devlist);
        list_for_each_entry(mops, &mops_list, next)
                mpeg_ops_detach(mops, dev);
-       mutex_unlock(&devlist_lock);
+       mutex_unlock(&saa7134_devlist_lock);
        saa7134_devcount--;
 
        saa7134_i2c_unregister(dev);
@@ -1113,7 +1131,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
        release_mem_region(pci_resource_start(pci_dev,0),
                           pci_resource_len(pci_dev,0));
 
-       pci_set_drvdata(pci_dev, NULL);
+
+       v4l2_device_unregister(&dev->v4l2_dev);
 
        /* free memory */
        kfree(dev);
@@ -1148,8 +1167,8 @@ static int saa7134_buffer_requeue(struct saa7134_dev *dev,
 
 static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
 {
-
-       struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
+       struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+       struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
 
        /* disable overlay - apps should enable it explicitly on resume*/
        dev->ovenable = 0;
@@ -1185,7 +1204,8 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
 
 static int saa7134_resume(struct pci_dev *pci_dev)
 {
-       struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
+       struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+       struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
        unsigned long flags;
 
        pci_set_power_state(pci_dev, PCI_D0);
@@ -1247,11 +1267,11 @@ int saa7134_ts_register(struct saa7134_mpeg_ops *ops)
 {
        struct saa7134_dev *dev;
 
-       mutex_lock(&devlist_lock);
+       mutex_lock(&saa7134_devlist_lock);
        list_for_each_entry(dev, &saa7134_devlist, devlist)
                mpeg_ops_attach(ops, dev);
        list_add_tail(&ops->next,&mops_list);
-       mutex_unlock(&devlist_lock);
+       mutex_unlock(&saa7134_devlist_lock);
        return 0;
 }
 
@@ -1259,11 +1279,11 @@ void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops)
 {
        struct saa7134_dev *dev;
 
-       mutex_lock(&devlist_lock);
+       mutex_lock(&saa7134_devlist_lock);
        list_del(&ops->next);
        list_for_each_entry(dev, &saa7134_devlist, devlist)
                mpeg_ops_detach(ops, dev);
-       mutex_unlock(&devlist_lock);
+       mutex_unlock(&saa7134_devlist_lock);
 }
 
 EXPORT_SYMBOL(saa7134_ts_register);
@@ -1307,8 +1327,6 @@ module_exit(saa7134_fini);
 /* ----------------------------------------------------------- */
 
 EXPORT_SYMBOL(saa7134_set_gpio);
-EXPORT_SYMBOL(saa7134_i2c_call_clients);
-EXPORT_SYMBOL(saa7134_devlist);
 EXPORT_SYMBOL(saa7134_boards);
 
 /* ----------------- for the DMA sound modules --------------- */
index b5370b3e1a3dab2e3b969d99664c2f830ecfb94e..4eff1ca8593cd9398fd15ce06d2e0c02ddf71d09 100644 (file)
 #include "isl6405.h"
 #include "lnbp21.h"
 #include "tuner-simple.h"
+#include "tda18271.h"
+#include "lgdt3305.h"
+#include "tda8290.h"
 
 #include "zl10353.h"
 
+#include "zl10036.h"
+#include "mt312.h"
+
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
 
@@ -189,7 +195,7 @@ static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(&dev->i2c_adap, &msg, 1);
-       saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f);
+       saa_call_all(dev, tuner, s_frequency, &f);
        msg.buf = on;
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
@@ -950,6 +956,45 @@ static struct nxt200x_config kworldatsc110 = {
        .demod_address    = 0x0a,
 };
 
+/* ------------------------------------------------------------------ */
+
+static struct mt312_config avertv_a700_mt312 = {
+       .demod_address = 0x0e,
+       .voltage_inverted = 1,
+};
+
+static struct zl10036_config avertv_a700_tuner = {
+       .tuner_address = 0x60,
+};
+
+static struct lgdt3305_config hcw_lgdt3305_config = {
+       .i2c_addr           = 0x0e,
+       .mpeg_mode          = LGDT3305_MPEG_SERIAL,
+       .tpclk_edge         = LGDT3305_TPCLK_RISING_EDGE,
+       .tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
+       .deny_i2c_rptr      = 1,
+       .spectral_inversion = 1,
+       .qam_if_khz         = 4000,
+       .vsb_if_khz         = 3250,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+       .atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 4,
+                     .if_lvl = 1, .rfagc_top = 0x58, },
+       .qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 5,
+                     .if_lvl = 1, .rfagc_top = 0x58, },
+};
+
+static struct tda18271_config hcw_tda18271_config = {
+       .std_map = &hauppauge_tda18271_std_map,
+       .gate    = TDA18271_GATE_ANALOG,
+       .config  = 3,
+};
+
+static struct tda829x_config tda829x_no_probe = {
+       .probe_tuner = TDA829X_DONT_PROBE,
+};
+
 /* ==================================================================
  * Core code
  */
@@ -1076,6 +1121,19 @@ static int dvb_init(struct saa7134_dev *dev)
                                         &tda827x_cfg_1) < 0)
                        goto dettach_frontend;
                break;
+       case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+               fe0->dvb.frontend = dvb_attach(lgdt3305_attach,
+                                              &hcw_lgdt3305_config,
+                                              &dev->i2c_adap);
+               if (fe0->dvb.frontend) {
+                       dvb_attach(tda829x_attach, fe0->dvb.frontend,
+                                  &dev->i2c_adap, 0x4b,
+                                  &tda829x_no_probe);
+                       dvb_attach(tda18271_attach, fe0->dvb.frontend,
+                                  0x60, &dev->i2c_adap,
+                                  &hcw_tda18271_config);
+               }
+               break;
        case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
                if (configure_tda827x_fe(dev, &asus_p7131_dual_config,
                                         &tda827x_cfg_0) < 0)
@@ -1376,6 +1434,19 @@ static int dvb_init(struct saa7134_dev *dev)
                                   TUNER_PHILIPS_FMD1216ME_MK3);
                }
                break;
+       case SAA7134_BOARD_AVERMEDIA_A700_PRO:
+       case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
+               /* Zarlink ZL10313 */
+               fe0->dvb.frontend = dvb_attach(mt312_attach,
+                       &avertv_a700_mt312, &dev->i2c_adap);
+               if (fe0->dvb.frontend) {
+                       if (dvb_attach(zl10036_attach, fe0->dvb.frontend,
+                                       &avertv_a700_tuner, &dev->i2c_adap) == NULL) {
+                               wprintk("%s: No zl10036 found!\n",
+                                       __func__);
+                       }
+               }
+               break;
        default:
                wprintk("Huh? unknown DVB card?\n");
                break;
@@ -1449,7 +1520,7 @@ static int dvb_fini(struct saa7134_dev *dev)
                tda9887_cfg.priv  = &on;
 
                /* otherwise we don't detect the tuner on next insmod */
-               saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tda9887_cfg);
+               saa_call_all(dev, tuner, s_config, &tda9887_cfg);
        } else if (dev->board == SAA7134_BOARD_MEDION_MD8800_QUADRO) {
                if ((dev->eedata[2] == 0x07) && use_frontend) {
                        /* turn off the 2nd lnb supply */
index c9d8beb87a608114c30ce64577a440afb788847c..9db3472667e52d311f1aab49bd003efb21cac30a 100644 (file)
@@ -76,7 +76,7 @@ static int ts_init_encoder(struct saa7134_dev* dev)
                break;
        }
        ts_reset_encoder(dev);
-       saa7134_i2c_call_clients(dev, VIDIOC_INT_INIT, &leading_null_bytes);
+       saa_call_all(dev, core, init, leading_null_bytes);
        dev->empress_started = 1;
        return 0;
 }
@@ -234,7 +234,7 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv,
 {
        struct saa7134_dev *dev = file->private_data;
 
-       saa7134_i2c_call_clients(dev, VIDIOC_G_FMT, f);
+       saa_call_all(dev, video, g_fmt, f);
 
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
@@ -247,7 +247,7 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv,
 {
        struct saa7134_dev *dev = file->private_data;
 
-       saa7134_i2c_call_clients(dev, VIDIOC_S_FMT, f);
+       saa_call_all(dev, video, s_fmt, f);
 
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
@@ -317,7 +317,7 @@ static int empress_s_ext_ctrls(struct file *file, void *priv,
        if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
                return -EINVAL;
 
-       err = saa7134_i2c_call_saa6752(dev, VIDIOC_S_EXT_CTRLS, ctrls);
+       err = saa_call_empress(dev, core, s_ext_ctrls, ctrls);
        ts_init_encoder(dev);
 
        return err;
@@ -330,7 +330,7 @@ static int empress_g_ext_ctrls(struct file *file, void *priv,
 
        if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
                return -EINVAL;
-       return saa7134_i2c_call_saa6752(dev, VIDIOC_G_EXT_CTRLS, ctrls);
+       return saa_call_empress(dev, core, g_ext_ctrls, ctrls);
 }
 
 static int empress_g_ctrl(struct file *file, void *priv,
@@ -352,6 +352,7 @@ static int empress_s_ctrl(struct file *file, void *priv,
 static int empress_queryctrl(struct file *file, void *priv,
                                        struct v4l2_queryctrl *c)
 {
+       /* Must be sorted from low to high control ID! */
        static const u32 user_ctrls[] = {
                V4L2_CID_USER_CLASS,
                V4L2_CID_BRIGHTNESS,
@@ -364,6 +365,7 @@ static int empress_queryctrl(struct file *file, void *priv,
                0
        };
 
+       /* Must be sorted from low to high control ID! */
        static const u32 mpeg_ctrls[] = {
                V4L2_CID_MPEG_CLASS,
                V4L2_CID_MPEG_STREAM_TYPE,
@@ -388,10 +390,10 @@ static int empress_queryctrl(struct file *file, void *priv,
        if (c->id == 0)
                return -EINVAL;
        if (c->id == V4L2_CID_USER_CLASS || c->id == V4L2_CID_MPEG_CLASS)
-               return v4l2_ctrl_query_fill_std(c);
+               return v4l2_ctrl_query_fill(c, 0, 0, 0, 0);
        if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
                return saa7134_queryctrl(file, priv, c);
-       return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYCTRL, c);
+       return saa_call_empress(dev, core, queryctrl, c);
 }
 
 static int empress_querymenu(struct file *file, void *priv,
@@ -401,7 +403,7 @@ static int empress_querymenu(struct file *file, void *priv,
 
        if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
                return -EINVAL;
-       return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYMENU, c);
+       return saa_call_empress(dev, core, querymenu, c);
 }
 
 static int empress_g_chip_ident(struct file *file, void *fh,
@@ -411,14 +413,11 @@ static int empress_g_chip_ident(struct file *file, void *fh,
 
        chip->ident = V4L2_IDENT_NONE;
        chip->revision = 0;
-       if (dev->mpeg_i2c_client == NULL)
-               return -EINVAL;
        if (chip->match.type == V4L2_CHIP_MATCH_I2C_DRIVER &&
            !strcmp(chip->match.name, "saa6752hs"))
-               return saa7134_i2c_call_saa6752(dev, VIDIOC_DBG_G_CHIP_IDENT, chip);
-       if (chip->match.type == V4L2_CHIP_MATCH_I2C_ADDR &&
-           chip->match.addr == dev->mpeg_i2c_client->addr)
-               return saa7134_i2c_call_saa6752(dev, VIDIOC_DBG_G_CHIP_IDENT, chip);
+               return saa_call_empress(dev, core, g_chip_ident, chip);
+       if (chip->match.type == V4L2_CHIP_MATCH_I2C_ADDR)
+               return saa_call_empress(dev, core, g_chip_ident, chip);
        return -EINVAL;
 }
 
index 20c1b33caf7b64bbd551a929db1f2a52bbf3da32..f3e285aa2fb4ee66ea8a8e8365f0995816b9fd53 100644 (file)
@@ -255,7 +255,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
                        addr  = msgs[i].addr << 1;
                        if (msgs[i].flags & I2C_M_RD)
                                addr |= 1;
-                       if (i > 0 && msgs[i].flags & I2C_M_RD) {
+                       if (i > 0 && msgs[i].flags & I2C_M_RD && msgs[i].addr != 0x40) {
                                /* workaround for a saa7134 i2c bug
                                 * needed to talk to the mt352 demux
                                 * thanks to pinnacle for the hint */
@@ -327,8 +327,6 @@ static int attach_inform(struct i2c_client *client)
 
        d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
                client->driver->driver.name, client->addr, client->name);
-       if (client->addr == 0x20 && client->driver && client->driver->command)
-               dev->mpeg_i2c_client = client;
 
        /* Am I an i2c remote control? */
 
@@ -357,7 +355,6 @@ static struct i2c_algorithm saa7134_algo = {
 
 static struct i2c_adapter saa7134_adap_template = {
        .owner         = THIS_MODULE,
-       .class         = I2C_CLASS_TV_ANALOG,
        .name          = "saa7134",
        .id            = I2C_HW_SAA7134,
        .algo          = &saa7134_algo,
@@ -421,29 +418,13 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
        }
 }
 
-void saa7134_i2c_call_clients(struct saa7134_dev *dev,
-                             unsigned int cmd, void *arg)
-{
-       BUG_ON(NULL == dev->i2c_adap.algo_data);
-       i2c_clients_command(&dev->i2c_adap, cmd, arg);
-}
-
-int saa7134_i2c_call_saa6752(struct saa7134_dev *dev,
-                                             unsigned int cmd, void *arg)
-{
-       if (dev->mpeg_i2c_client == NULL)
-               return -EINVAL;
-       return dev->mpeg_i2c_client->driver->command(dev->mpeg_i2c_client,
-                                                               cmd, arg);
-}
-EXPORT_SYMBOL_GPL(saa7134_i2c_call_saa6752);
-
 int saa7134_i2c_register(struct saa7134_dev *dev)
 {
        dev->i2c_adap = saa7134_adap_template;
        dev->i2c_adap.dev.parent = &dev->pci->dev;
        strcpy(dev->i2c_adap.name,dev->name);
        dev->i2c_adap.algo_data = dev;
+       i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
        i2c_add_adapter(&dev->i2c_adap);
 
        dev->i2c_client = saa7134_client_template;
index ef55a59f0cda59623cec062bea0a313051d8857a..cc8b923afbc077c37cee7708a4518c2b91968f09 100644 (file)
@@ -79,8 +79,19 @@ static int buffer_activate(struct saa7134_dev *dev,
                saa_writeb(SAA7134_TS_SERIAL1, 0x00);
 
                /* Start TS stream */
-               saa_writeb(SAA7134_TS_SERIAL0, 0x40);
-               saa_writeb(SAA7134_TS_PARALLEL, 0xEC);
+               switch (saa7134_boards[dev->board].ts_type) {
+               case SAA7134_MPEG_TS_PARALLEL:
+                       saa_writeb(SAA7134_TS_SERIAL0, 0x40);
+                       saa_writeb(SAA7134_TS_PARALLEL, 0xec);
+                       break;
+               case SAA7134_MPEG_TS_SERIAL:
+                       saa_writeb(SAA7134_TS_SERIAL0, 0xd8);
+                       saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
+                       saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 0xbc);
+                       saa_writeb(SAA7134_TS_SERIAL1, 0x02);
+                       break;
+               }
+
                dev->ts_state = SAA7134_TS_STARTED;
        }
 
index a1f7e351f57234480719c0b297c38ccbf7583cb1..404f70eeb355e9f7f6cd31ae55d494925fffd3f3 100644 (file)
 #include "saa7134-reg.h"
 #include "saa7134.h"
 #include <media/v4l2-common.h>
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-/* Include V4L1 specific functions. Should be removed soon */
-#include <linux/videodev.h>
-#endif
+#include <media/rds.h>
 
 /* ------------------------------------------------------------------ */
 
@@ -452,6 +448,7 @@ static const struct v4l2_queryctrl video_ctrls[] = {
                .name          = "y offset odd field",
                .minimum       = 0,
                .maximum       = 128,
+               .step          = 1,
                .default_value = 0,
                .type          = V4L2_CTRL_TYPE_INTEGER,
        },{
@@ -459,6 +456,7 @@ static const struct v4l2_queryctrl video_ctrls[] = {
                .name          = "y offset even field",
                .minimum       = 0,
                .maximum       = 128,
+               .step          = 1,
                .default_value = 0,
                .type          = V4L2_CTRL_TYPE_INTEGER,
        },{
@@ -627,10 +625,10 @@ void saa7134_set_tvnorm_hw(struct saa7134_dev *dev)
        saa7134_set_decoder(dev);
 
        if (card_in(dev, dev->ctl_input).tv)
-               saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id);
+               saa_call_all(dev, tuner, s_std, dev->tvnorm->id);
        /* Set the correct norm for the saa6752hs. This function
           does nothing if there is no saa6752hs. */
-       saa7134_i2c_call_saa6752(dev, VIDIOC_S_STD, &dev->tvnorm->id);
+       saa_call_empress(dev, tuner, s_std, dev->tvnorm->id);
 }
 
 static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
@@ -1266,8 +1264,7 @@ int saa7134_s_ctrl_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, str
                        else
                                dev->tda9887_conf &= ~TDA9887_AUTOMUTE;
 
-                       saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
-                                                &tda9887_cfg);
+                       saa_call_all(dev, tuner, s_config, &tda9887_cfg);
                }
                break;
        }
@@ -1334,7 +1331,7 @@ static int video_open(struct file *file)
        enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        int radio = 0;
 
-       lock_kernel();
+       mutex_lock(&saa7134_devlist_lock);
        list_for_each_entry(dev, &saa7134_devlist, devlist) {
                if (dev->video_dev && (dev->video_dev->minor == minor))
                        goto found;
@@ -1347,19 +1344,20 @@ static int video_open(struct file *file)
                        goto found;
                }
        }
-       unlock_kernel();
+       mutex_unlock(&saa7134_devlist_lock);
        return -ENODEV;
- found:
+
+found:
+       mutex_unlock(&saa7134_devlist_lock);
 
        dprintk("open minor=%d radio=%d type=%s\n",minor,radio,
                v4l2_type_names[type]);
 
        /* allocate + initialize per filehandle data */
        fh = kzalloc(sizeof(*fh),GFP_KERNEL);
-       if (NULL == fh) {
-               unlock_kernel();
+       if (NULL == fh)
                return -ENOMEM;
-       }
+
        file->private_data = fh;
        fh->dev      = dev;
        fh->radio    = radio;
@@ -1387,12 +1385,11 @@ static int video_open(struct file *file)
        if (fh->radio) {
                /* switch to radio mode */
                saa7134_tvaudio_setinput(dev,&card(dev).radio);
-               saa7134_i2c_call_clients(dev,AUDC_SET_RADIO, NULL);
+               saa_call_all(dev, tuner, s_radio);
        } else {
                /* switch to video/vbi mode */
                video_mux(dev,dev->ctl_input);
        }
-       unlock_kernel();
        return 0;
 }
 
@@ -1466,6 +1463,7 @@ static int video_release(struct file *file)
 {
        struct saa7134_fh  *fh  = file->private_data;
        struct saa7134_dev *dev = fh->dev;
+       struct rds_command cmd;
        unsigned long flags;
 
        /* turn off overlay */
@@ -1498,7 +1496,9 @@ static int video_release(struct file *file)
        saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0);
        saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0);
 
-       saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
+       saa_call_all(dev, core, s_standby, 0);
+       if (fh->radio)
+               saa_call_all(dev, core, ioctl, RDS_CMD_CLOSE, &cmd);
 
        /* free stuff */
        videobuf_mmap_free(&fh->cap);
@@ -1519,6 +1519,37 @@ static int video_mmap(struct file *file, struct vm_area_struct * vma)
        return videobuf_mmap_mapper(saa7134_queue(fh), vma);
 }
 
+static ssize_t radio_read(struct file *file, char __user *data,
+                        size_t count, loff_t *ppos)
+{
+       struct saa7134_fh *fh = file->private_data;
+       struct saa7134_dev *dev = fh->dev;
+       struct rds_command cmd;
+
+       cmd.block_count = count/3;
+       cmd.buffer = data;
+       cmd.instance = file;
+       cmd.result = -ENODEV;
+
+       saa_call_all(dev, core, ioctl, RDS_CMD_READ, &cmd);
+
+       return cmd.result;
+}
+
+static unsigned int radio_poll(struct file *file, poll_table *wait)
+{
+       struct saa7134_fh *fh = file->private_data;
+       struct saa7134_dev *dev = fh->dev;
+       struct rds_command cmd;
+
+       cmd.instance = file;
+       cmd.event_list = wait;
+       cmd.result = -ENODEV;
+       saa_call_all(dev, core, ioctl, RDS_CMD_POLL, &cmd);
+
+       return cmd.result;
+}
+
 /* ------------------------------------------------------------------ */
 
 static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv,
@@ -2041,7 +2072,7 @@ static int saa7134_s_frequency(struct file *file, void *priv,
        mutex_lock(&dev->lock);
        dev->ctl_freq = f->frequency;
 
-       saa7134_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
+       saa_call_all(dev, tuner, s_frequency, f);
 
        saa7134_tvaudio_do_scan(dev);
        mutex_unlock(&dev->lock);
@@ -2299,7 +2330,7 @@ static int radio_g_tuner(struct file *file, void *priv,
        strcpy(t->name, "Radio");
        t->type = V4L2_TUNER_RADIO;
 
-       saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
+       saa_call_all(dev, tuner, g_tuner, t);
        if (dev->input->amux == TV) {
                t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
                t->rxsubchans = (saa_readb(0x529) & 0x08) ?
@@ -2316,7 +2347,7 @@ static int radio_s_tuner(struct file *file, void *priv,
        if (0 != t->index)
                return -EINVAL;
 
-       saa7134_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
+       saa_call_all(dev, tuner, s_tuner, t);
        return 0;
 }
 
@@ -2443,8 +2474,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
 static const struct v4l2_file_operations radio_fops = {
        .owner    = THIS_MODULE,
        .open     = video_open,
+       .read     = radio_read,
        .release  = video_release,
        .ioctl    = video_ioctl2,
+       .poll     = radio_poll,
 };
 
 static const struct v4l2_ioctl_ops radio_ioctl_ops = {
index 14ee265f33747b3f9583f8e51d78b917189dfd97..a2dd326de5b91d40b899e94a6988f98de7d4d71a 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
 #include <media/tuner.h>
 #include <media/ir-common.h>
 #include <media/ir-kbd-i2c.h>
@@ -277,6 +278,8 @@ struct saa7134_format {
 #define SAA7134_BOARD_ASUSTeK_TIGER         152
 #define SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG 153
 #define SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS 154
+#define SAA7134_BOARD_HAUPPAUGE_HVR1120     155
+#define SAA7134_BOARD_HAUPPAUGE_HVR1110R3   156
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
@@ -309,6 +312,11 @@ enum saa7134_mpeg_type {
        SAA7134_MPEG_DVB,
 };
 
+enum saa7134_mpeg_ts_type {
+       SAA7134_MPEG_TS_PARALLEL = 0,
+       SAA7134_MPEG_TS_SERIAL,
+};
+
 struct saa7134_board {
        char                    *name;
        unsigned int            audio_clock;
@@ -324,6 +332,8 @@ struct saa7134_board {
        unsigned int            radio_type;
        unsigned char           tuner_addr;
        unsigned char           radio_addr;
+       unsigned char           empress_addr;
+       unsigned char           rds_addr;
 
        unsigned int            tda9887_conf;
        unsigned int            tuner_config;
@@ -331,6 +341,7 @@ struct saa7134_board {
        /* peripheral I/O */
        enum saa7134_video_out  video_out;
        enum saa7134_mpeg_type  mpeg;
+       enum saa7134_mpeg_ts_type ts_type;
        unsigned int            vid_port_opts;
 };
 
@@ -445,7 +456,6 @@ struct saa7134_dmasound {
        unsigned int               bufsize;
        struct saa7134_pgtable     pt;
        struct videobuf_dmabuf     dma;
-       wait_queue_head_t          wq;
        unsigned int               dma_blk;
        unsigned int               read_offset;
        unsigned int               read_count;
@@ -482,6 +492,7 @@ struct saa7134_dev {
        struct mutex               lock;
        spinlock_t                 slock;
        struct v4l2_prio_state     prio;
+       struct v4l2_device         v4l2_dev;
        /* workstruct for loading modules */
        struct work_struct request_module_wk;
 
@@ -572,7 +583,6 @@ struct saa7134_dev {
        enum saa7134_ts_status     ts_state;
        unsigned int               buff_cnt;
        struct saa7134_mpeg_ops    *mops;
-       struct i2c_client          *mpeg_i2c_client;
 
        /* SAA7134_MPEG_EMPRESS only */
        struct video_device        *empress_dev;
@@ -588,6 +598,7 @@ struct saa7134_dev {
        int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
        int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg);
 #endif
+       void (*gate_ctrl)(struct saa7134_dev *dev, int open);
 };
 
 /* ----------------------------------------------------------- */
@@ -616,10 +627,31 @@ struct saa7134_dev {
                V4L2_STD_NTSC   | V4L2_STD_PAL_M | \
                V4L2_STD_PAL_60)
 
+#define GRP_EMPRESS (1)
+#define saa_call_all(dev, o, f, args...) do {                          \
+       if (dev->gate_ctrl)                                             \
+               dev->gate_ctrl(dev, 1);                                 \
+       v4l2_device_call_all(&(dev)->v4l2_dev, 0, o, f , ##args);       \
+       if (dev->gate_ctrl)                                             \
+               dev->gate_ctrl(dev, 0);                                 \
+} while (0)
+
+#define saa_call_empress(dev, o, f, args...) ({                                \
+       long _rc;                                                       \
+       if (dev->gate_ctrl)                                             \
+               dev->gate_ctrl(dev, 1);                                 \
+       _rc = v4l2_device_call_until_err(&(dev)->v4l2_dev,              \
+                                        GRP_EMPRESS, o, f , ##args);   \
+       if (dev->gate_ctrl)                                             \
+               dev->gate_ctrl(dev, 0);                                 \
+       _rc;                                                            \
+})
+
 /* ----------------------------------------------------------- */
 /* saa7134-core.c                                              */
 
 extern struct list_head  saa7134_devlist;
+extern struct mutex saa7134_devlist_lock;
 extern int saa7134_no_overlay;
 
 void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
@@ -668,10 +700,6 @@ int saa7134_tuner_callback(void *priv, int component, int command, int arg);
 
 int saa7134_i2c_register(struct saa7134_dev *dev);
 int saa7134_i2c_unregister(struct saa7134_dev *dev);
-void saa7134_i2c_call_clients(struct saa7134_dev *dev,
-                             unsigned int cmd, void *arg);
-int saa7134_i2c_call_saa6752(struct saa7134_dev *dev,
-                             unsigned int cmd, void *arg);
 
 
 /* ----------------------------------------------------------- */
index 2830b5e33aec97c90b94acfd9756def5aa50d13c..9fadb331a40b6716b628c1345214b1365d2cadbe 100644 (file)
@@ -25,8 +25,6 @@
 #include <linux/types.h>
 #include <linux/wait.h>
 
-#include <linux/videodev.h>
-
 #ifndef O_NONCAP
 #define O_NONCAP       O_TRUNC
 #endif
index 88c5e942f751806d414b753234dee9d984fb197a..25bf2303a6b5b2c0fc57ab10cef415087b7ba4c9 100644 (file)
@@ -931,7 +931,7 @@ static int saa717x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
                break;
 
        case V4L2_CID_HUE:
-               if (ctrl->value < -127 || ctrl->value > 127) {
+               if (ctrl->value < -128 || ctrl->value > 127) {
                        v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
                        return -ERANGE;
                }
@@ -1380,11 +1380,6 @@ static int saa717x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
        return 0;
 }
 
-static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops saa717x_core_ops = {
@@ -1528,10 +1523,7 @@ MODULE_DEVICE_TABLE(i2c, saa717x_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "saa717x",
-       .driverid = I2C_DRIVERID_SAA717X,
-       .command = saa717x_command,
        .probe = saa717x_probe,
        .remove = saa717x_remove,
-       .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
        .id_table = saa717x_id,
 };
index 6debb65152ee1f88a3f455c731903d3dc0fe217b..75747b104d0738eed0d002953dd92124a205eac4 100644 (file)
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
-#include <linux/videodev.h>
-#include <linux/video_encoder.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
 MODULE_AUTHOR("Dave Perks");
 MODULE_LICENSE("GPL");
 
-
 static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
+
 /* ----------------------------------------------------------------------- */
 
 struct saa7185 {
+       struct v4l2_subdev sd;
        unsigned char reg[128];
 
-       int norm;
-       int enable;
-       int bright;
-       int contrast;
-       int hue;
-       int sat;
+       v4l2_std_id norm;
 };
 
+static inline struct saa7185 *to_saa7185(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct saa7185, sd);
+}
+
 /* ----------------------------------------------------------------------- */
 
-static inline int saa7185_read(struct i2c_client *client)
+static inline int saa7185_read(struct v4l2_subdev *sd)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        return i2c_smbus_read_byte(client);
 }
 
-static int saa7185_write(struct i2c_client *client, u8 reg, u8 value)
+static int saa7185_write(struct v4l2_subdev *sd, u8 reg, u8 value)
 {
-       struct saa7185 *encoder = i2c_get_clientdata(client);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct saa7185 *encoder = to_saa7185(sd);
 
-       v4l_dbg(1, debug, client, "%02x set to %02x\n", reg, value);
+       v4l2_dbg(1, debug, sd, "%02x set to %02x\n", reg, value);
        encoder->reg[reg] = value;
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static int saa7185_write_block(struct i2c_client *client,
+static int saa7185_write_block(struct v4l2_subdev *sd,
                const u8 *data, unsigned int len)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct saa7185 *encoder = to_saa7185(sd);
        int ret = -1;
        u8 reg;
 
@@ -83,7 +89,6 @@ static int saa7185_write_block(struct i2c_client *client,
         * the adapter understands raw I2C */
        if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
                /* do raw I2C, not smbus compatible */
-               struct saa7185 *encoder = i2c_get_clientdata(client);
                u8 block_data[32];
                int block_len;
 
@@ -104,7 +109,7 @@ static int saa7185_write_block(struct i2c_client *client,
                /* do some slow I2C emulation kind of thing */
                while (len >= 2) {
                        reg = *data++;
-                       ret = saa7185_write(client, reg, *data++);
+                       ret = saa7185_write(sd, reg, *data++);
                        if (ret < 0)
                                break;
                        len -= 2;
@@ -213,133 +218,106 @@ static const unsigned char init_ntsc[] = {
        0x66, 0x21,             /* FSC3 */
 };
 
-static int saa7185_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       struct saa7185 *encoder = i2c_get_clientdata(client);
-
-       switch (cmd) {
-       case 0:
-               saa7185_write_block(client, init_common,
-                                   sizeof(init_common));
-               switch (encoder->norm) {
-
-               case VIDEO_MODE_NTSC:
-                       saa7185_write_block(client, init_ntsc,
-                                           sizeof(init_ntsc));
-                       break;
-
-               case VIDEO_MODE_PAL:
-                       saa7185_write_block(client, init_pal,
-                                           sizeof(init_pal));
-                       break;
-               }
-               break;
 
-       case ENCODER_GET_CAPABILITIES:
-       {
-               struct video_encoder_capability *cap = arg;
+static int saa7185_init(struct v4l2_subdev *sd, u32 val)
+{
+       struct saa7185 *encoder = to_saa7185(sd);
 
-               cap->flags =
-                   VIDEO_ENCODER_PAL | VIDEO_ENCODER_NTSC |
-                   VIDEO_ENCODER_SECAM | VIDEO_ENCODER_CCIR;
-               cap->inputs = 1;
-               cap->outputs = 1;
-               break;
-       }
+       saa7185_write_block(sd, init_common, sizeof(init_common));
+       if (encoder->norm & V4L2_STD_NTSC)
+               saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc));
+       else
+               saa7185_write_block(sd, init_pal, sizeof(init_pal));
+       return 0;
+}
 
-       case ENCODER_SET_NORM:
-       {
-               int *iarg = arg;
+static int saa7185_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct saa7185 *encoder = to_saa7185(sd);
 
-               //saa7185_write_block(client, init_common, sizeof(init_common));
+       if (std & V4L2_STD_NTSC)
+               saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc));
+       else if (std & V4L2_STD_PAL)
+               saa7185_write_block(sd, init_pal, sizeof(init_pal));
+       else
+               return -EINVAL;
+       encoder->norm = std;
+       return 0;
+}
 
-               switch (*iarg) {
-               case VIDEO_MODE_NTSC:
-                       saa7185_write_block(client, init_ntsc,
-                                           sizeof(init_ntsc));
-                       break;
+static int saa7185_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct saa7185 *encoder = to_saa7185(sd);
 
-               case VIDEO_MODE_PAL:
-                       saa7185_write_block(client, init_pal,
-                                           sizeof(init_pal));
-                       break;
+       /* RJ: route->input = 0: input is from SA7111
+        route->input = 1: input is from ZR36060 */
 
-               case VIDEO_MODE_SECAM:
-               default:
-                       return -EINVAL;
-               }
-               encoder->norm = *iarg;
-               break;
-       }
-
-       case ENCODER_SET_INPUT:
-       {
-               int *iarg = arg;
-
-               /* RJ: *iarg = 0: input is from SA7111
-                *iarg = 1: input is from ZR36060 */
-
-               switch (*iarg) {
-               case 0:
-                       /* Switch RTCE to 1 */
-                       saa7185_write(client, 0x61,
-                                     (encoder->reg[0x61] & 0xf7) | 0x08);
-                       saa7185_write(client, 0x6e, 0x01);
-                       break;
-
-               case 1:
-                       /* Switch RTCE to 0 */
-                       saa7185_write(client, 0x61,
-                                     (encoder->reg[0x61] & 0xf7) | 0x00);
-                       /* SW: a slight sync problem... */
-                       saa7185_write(client, 0x6e, 0x00);
-                       break;
-
-               default:
-                       return -EINVAL;
-               }
+       switch (route->input) {
+       case 0:
+               /* turn off colorbar */
+               saa7185_write(sd, 0x3a, 0x0f);
+               /* Switch RTCE to 1 */
+               saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08);
+               saa7185_write(sd, 0x6e, 0x01);
                break;
-       }
 
-       case ENCODER_SET_OUTPUT:
-       {
-               int *iarg = arg;
-
-               /* not much choice of outputs */
-               if (*iarg != 0)
-                       return -EINVAL;
+       case 1:
+               /* turn off colorbar */
+               saa7185_write(sd, 0x3a, 0x0f);
+               /* Switch RTCE to 0 */
+               saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x00);
+               /* SW: a slight sync problem... */
+               saa7185_write(sd, 0x6e, 0x00);
                break;
-       }
-
-       case ENCODER_ENABLE_OUTPUT:
-       {
-               int *iarg = arg;
 
-               encoder->enable = !!*iarg;
-               saa7185_write(client, 0x61,
-                             (encoder->reg[0x61] & 0xbf) |
-                             (encoder->enable ? 0x00 : 0x40));
+       case 2:
+               /* turn on colorbar */
+               saa7185_write(sd, 0x3a, 0x8f);
+               /* Switch RTCE to 0 */
+               saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08);
+               /* SW: a slight sync problem... */
+               saa7185_write(sd, 0x6e, 0x01);
                break;
-       }
 
        default:
                return -EINVAL;
        }
-
        return 0;
 }
 
+static int saa7185_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7185, 0);
+}
+
 /* ----------------------------------------------------------------------- */
 
-static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
+static const struct v4l2_subdev_core_ops saa7185_core_ops = {
+       .g_chip_ident = saa7185_g_chip_ident,
+       .init = saa7185_init,
+};
 
-I2C_CLIENT_INSMOD;
+static const struct v4l2_subdev_video_ops saa7185_video_ops = {
+       .s_std_output = saa7185_s_std_output,
+       .s_routing = saa7185_s_routing,
+};
+
+static const struct v4l2_subdev_ops saa7185_ops = {
+       .core = &saa7185_core_ops,
+       .video = &saa7185_video_ops,
+};
+
+
+/* ----------------------------------------------------------------------- */
 
 static int saa7185_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        int i;
        struct saa7185 *encoder;
+       struct v4l2_subdev *sd;
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -351,28 +329,29 @@ static int saa7185_probe(struct i2c_client *client,
        encoder = kzalloc(sizeof(struct saa7185), GFP_KERNEL);
        if (encoder == NULL)
                return -ENOMEM;
-       encoder->norm = VIDEO_MODE_NTSC;
-       encoder->enable = 1;
-       i2c_set_clientdata(client, encoder);
+       encoder->norm = V4L2_STD_NTSC;
+       sd = &encoder->sd;
+       v4l2_i2c_subdev_init(sd, client, &saa7185_ops);
 
-       i = saa7185_write_block(client, init_common, sizeof(init_common));
+       i = saa7185_write_block(sd, init_common, sizeof(init_common));
        if (i >= 0)
-               i = saa7185_write_block(client, init_ntsc, sizeof(init_ntsc));
+               i = saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc));
        if (i < 0)
-               v4l_dbg(1, debug, client, "init error %d\n", i);
+               v4l2_dbg(1, debug, sd, "init error %d\n", i);
        else
-               v4l_dbg(1, debug, client, "revision 0x%x\n",
-                               saa7185_read(client) >> 5);
+               v4l2_dbg(1, debug, sd, "revision 0x%x\n",
+                               saa7185_read(sd) >> 5);
        return 0;
 }
 
 static int saa7185_remove(struct i2c_client *client)
 {
-       struct saa7185 *encoder = i2c_get_clientdata(client);
-
-       saa7185_write(client, 0x61, (encoder->reg[0x61]) | 0x40);       /* SW: output off is active */
-       //saa7185_write(client, 0x3a, (encoder->reg[0x3a]) | 0x80); /* SW: color bar */
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct saa7185 *encoder = to_saa7185(sd);
 
+       v4l2_device_unregister_subdev(sd);
+       /* SW: output off is active */
+       saa7185_write(sd, 0x61, (encoder->reg[0x61]) | 0x40);
        kfree(encoder);
        return 0;
 }
@@ -387,8 +366,6 @@ MODULE_DEVICE_TABLE(i2c, saa7185_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "saa7185",
-       .driverid = I2C_DRIVERID_SAA7185B,
-       .command = saa7185_command,
        .probe = saa7185_probe,
        .remove = saa7185_remove,
        .id_table = saa7185_id,
index b4018cce328536c4a2a1f06b7bb11bcc48f6e94e..3f523aeec56e6c12673af5f06336b235c2c34a56 100644 (file)
 #include <linux/mm.h>
 #include <linux/slab.h>
 
-#include <linux/videodev.h>
-#include <linux/video_decoder.h>
+#include <linux/videodev2.h>
 #include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 
 #include "saa7191.h"
 
@@ -32,6 +34,7 @@ MODULE_VERSION(SAA7191_MODULE_VERSION);
 MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
 MODULE_LICENSE("GPL");
 
+
 // #define SAA7191_DEBUG
 
 #ifdef SAA7191_DEBUG
@@ -44,17 +47,20 @@ MODULE_LICENSE("GPL");
 #define SAA7191_SYNC_DELAY     100     /* milliseconds */
 
 struct saa7191 {
-       struct i2c_client *client;
+       struct v4l2_subdev sd;
 
        /* the register values are stored here as the actual
         * I2C-registers are write-only */
        u8 reg[25];
 
        int input;
-       int norm;
+       v4l2_std_id norm;
 };
 
-static struct i2c_driver i2c_driver_saa7191;
+static inline struct saa7191 *to_saa7191(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct saa7191, sd);
+}
 
 static const u8 initseq[] = {
        0,      /* Subaddress */
@@ -100,15 +106,14 @@ static const u8 initseq[] = {
 
 /* SAA7191 register handling */
 
-static u8 saa7191_read_reg(struct i2c_client *client,
-                          u8 reg)
+static u8 saa7191_read_reg(struct v4l2_subdev *sd, u8 reg)
 {
-       return ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg];
+       return to_saa7191(sd)->reg[reg];
 }
 
-static int saa7191_read_status(struct i2c_client *client,
-                              u8 *value)
+static int saa7191_read_status(struct v4l2_subdev *sd, u8 *value)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int ret;
 
        ret = i2c_master_recv(client, value, 1);
@@ -121,21 +126,23 @@ static int saa7191_read_status(struct i2c_client *client,
 }
 
 
-static int saa7191_write_reg(struct i2c_client *client, u8 reg,
-                            u8 value)
+static int saa7191_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value)
 {
-       ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg] = value;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       to_saa7191(sd)->reg[reg] = value;
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
 /* the first byte of data must be the first subaddress number (register) */
-static int saa7191_write_block(struct i2c_client *client,
+static int saa7191_write_block(struct v4l2_subdev *sd,
                               u8 length, const u8 *data)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct saa7191 *decoder = to_saa7191(sd);
        int i;
        int ret;
 
-       struct saa7191 *decoder = (struct saa7191 *)i2c_get_clientdata(client);
        for (i = 0; i < (length - 1); i++) {
                decoder->reg[data[0] + i] = data[i + 1];
        }
@@ -152,14 +159,15 @@ static int saa7191_write_block(struct i2c_client *client,
 
 /* Helper functions */
 
-static int saa7191_set_input(struct i2c_client *client, int input)
+static int saa7191_s_routing(struct v4l2_subdev *sd,
+                               const struct v4l2_routing *route)
 {
-       struct saa7191 *decoder = i2c_get_clientdata(client);
-       u8 luma = saa7191_read_reg(client, SAA7191_REG_LUMA);
-       u8 iock = saa7191_read_reg(client, SAA7191_REG_IOCK);
+       struct saa7191 *decoder = to_saa7191(sd);
+       u8 luma = saa7191_read_reg(sd, SAA7191_REG_LUMA);
+       u8 iock = saa7191_read_reg(sd, SAA7191_REG_IOCK);
        int err;
 
-       switch (input) {
+       switch (route->input) {
        case SAA7191_INPUT_COMPOSITE: /* Set Composite input */
                iock &= ~(SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW1
                          | SAA7191_IOCK_GPSW2);
@@ -175,54 +183,50 @@ static int saa7191_set_input(struct i2c_client *client, int input)
                return -EINVAL;
        }
 
-       err = saa7191_write_reg(client, SAA7191_REG_LUMA, luma);
+       err = saa7191_write_reg(sd, SAA7191_REG_LUMA, luma);
        if (err)
                return -EIO;
-       err = saa7191_write_reg(client, SAA7191_REG_IOCK, iock);
+       err = saa7191_write_reg(sd, SAA7191_REG_IOCK, iock);
        if (err)
                return -EIO;
 
-       decoder->input = input;
+       decoder->input = route->input;
 
        return 0;
 }
 
-static int saa7191_set_norm(struct i2c_client *client, int norm)
+static int saa7191_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
 {
-       struct saa7191 *decoder = i2c_get_clientdata(client);
-       u8 stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
-       u8 ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
-       u8 chcv = saa7191_read_reg(client, SAA7191_REG_CHCV);
+       struct saa7191 *decoder = to_saa7191(sd);
+       u8 stdc = saa7191_read_reg(sd, SAA7191_REG_STDC);
+       u8 ctl3 = saa7191_read_reg(sd, SAA7191_REG_CTL3);
+       u8 chcv = saa7191_read_reg(sd, SAA7191_REG_CHCV);
        int err;
 
-       switch(norm) {
-       case SAA7191_NORM_PAL:
+       if (norm & V4L2_STD_PAL) {
                stdc &= ~SAA7191_STDC_SECS;
                ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
                chcv = SAA7191_CHCV_PAL;
-               break;
-       case SAA7191_NORM_NTSC:
+       } else if (norm & V4L2_STD_NTSC) {
                stdc &= ~SAA7191_STDC_SECS;
                ctl3 &= ~SAA7191_CTL3_AUFD;
                ctl3 |= SAA7191_CTL3_FSEL;
                chcv = SAA7191_CHCV_NTSC;
-               break;
-       case SAA7191_NORM_SECAM:
+       } else if (norm & V4L2_STD_SECAM) {
                stdc |= SAA7191_STDC_SECS;
                ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
                chcv = SAA7191_CHCV_PAL;
-               break;
-       default:
+       } else {
                return -EINVAL;
        }
 
-       err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
+       err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
        if (err)
                return -EIO;
-       err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
+       err = saa7191_write_reg(sd, SAA7191_REG_STDC, stdc);
        if (err)
                return -EIO;
-       err = saa7191_write_reg(client, SAA7191_REG_CHCV, chcv);
+       err = saa7191_write_reg(sd, SAA7191_REG_CHCV, chcv);
        if (err)
                return -EIO;
 
@@ -230,19 +234,19 @@ static int saa7191_set_norm(struct i2c_client *client, int norm)
 
        dprintk("ctl3: %02x stdc: %02x chcv: %02x\n", ctl3,
                stdc, chcv);
-       dprintk("norm: %d\n", norm);
+       dprintk("norm: %llx\n", norm);
 
        return 0;
 }
 
-static int saa7191_wait_for_signal(struct i2c_client *client, u8 *status)
+static int saa7191_wait_for_signal(struct v4l2_subdev *sd, u8 *status)
 {
        int i = 0;
 
        dprintk("Checking for signal...\n");
 
        for (i = 0; i < SAA7191_SYNC_COUNT; i++) {
-               if (saa7191_read_status(client, status))
+               if (saa7191_read_status(sd, status))
                        return -EIO;
 
                if (((*status) & SAA7191_STATUS_HLCK) == 0) {
@@ -258,31 +262,34 @@ static int saa7191_wait_for_signal(struct i2c_client *client, u8 *status)
        return -EBUSY;
 }
 
-static int saa7191_autodetect_norm_extended(struct i2c_client *client)
+static int saa7191_querystd(struct v4l2_subdev *sd, v4l2_std_id *norm)
 {
-       u8 stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
-       u8 ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
+       struct saa7191 *decoder = to_saa7191(sd);
+       u8 stdc = saa7191_read_reg(sd, SAA7191_REG_STDC);
+       u8 ctl3 = saa7191_read_reg(sd, SAA7191_REG_CTL3);
        u8 status;
+       v4l2_std_id old_norm = decoder->norm;
        int err = 0;
 
        dprintk("SAA7191 extended signal auto-detection...\n");
 
+       *norm = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
        stdc &= ~SAA7191_STDC_SECS;
        ctl3 &= ~(SAA7191_CTL3_FSEL);
 
-       err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
+       err = saa7191_write_reg(sd, SAA7191_REG_STDC, stdc);
        if (err) {
                err = -EIO;
                goto out;
        }
-       err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
+       err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
        if (err) {
                err = -EIO;
                goto out;
        }
 
        ctl3 |= SAA7191_CTL3_AUFD;
-       err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
+       err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
        if (err) {
                err = -EIO;
                goto out;
@@ -290,53 +297,54 @@ static int saa7191_autodetect_norm_extended(struct i2c_client *client)
 
        msleep(SAA7191_SYNC_DELAY);
 
-       err = saa7191_wait_for_signal(client, &status);
+       err = saa7191_wait_for_signal(sd, &status);
        if (err)
                goto out;
 
        if (status & SAA7191_STATUS_FIDT) {
                /* 60Hz signal -> NTSC */
                dprintk("60Hz signal: NTSC\n");
-               return saa7191_set_norm(client, SAA7191_NORM_NTSC);
+               *norm = V4L2_STD_NTSC;
+               return 0;
        }
 
        /* 50Hz signal */
        dprintk("50Hz signal: Trying PAL...\n");
 
        /* try PAL first */
-       err = saa7191_set_norm(client, SAA7191_NORM_PAL);
+       err = saa7191_s_std(sd, V4L2_STD_PAL);
        if (err)
                goto out;
 
        msleep(SAA7191_SYNC_DELAY);
 
-       err = saa7191_wait_for_signal(client, &status);
+       err = saa7191_wait_for_signal(sd, &status);
        if (err)
                goto out;
 
        /* not 50Hz ? */
        if (status & SAA7191_STATUS_FIDT) {
                dprintk("No 50Hz signal\n");
-               err = -EAGAIN;
-               goto out;
+               saa7191_s_std(sd, old_norm);
+               return -EAGAIN;
        }
 
        if (status & SAA7191_STATUS_CODE) {
                dprintk("PAL\n");
-               return 0;
+               *norm = V4L2_STD_PAL;
+               return saa7191_s_std(sd, old_norm);
        }
 
        dprintk("No color detected with PAL - Trying SECAM...\n");
 
        /* no color detected ? -> try SECAM */
-       err = saa7191_set_norm(client,
-                              SAA7191_NORM_SECAM);
+       err = saa7191_s_std(sd, V4L2_STD_SECAM);
        if (err)
                goto out;
 
        msleep(SAA7191_SYNC_DELAY);
 
-       err = saa7191_wait_for_signal(client, &status);
+       err = saa7191_wait_for_signal(sd, &status);
        if (err)
                goto out;
 
@@ -350,32 +358,17 @@ static int saa7191_autodetect_norm_extended(struct i2c_client *client)
        if (status & SAA7191_STATUS_CODE) {
                /* Color detected -> SECAM */
                dprintk("SECAM\n");
-               return 0;
+               *norm = V4L2_STD_SECAM;
+               return saa7191_s_std(sd, old_norm);
        }
 
        dprintk("No color detected with SECAM - Going back to PAL.\n");
 
-       /* still no color detected ?
-        * -> set norm back to PAL */
-       err = saa7191_set_norm(client,
-                              SAA7191_NORM_PAL);
-       if (err)
-               goto out;
-
 out:
-       ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
-       if (ctl3 & SAA7191_CTL3_AUFD) {
-               ctl3 &= ~(SAA7191_CTL3_AUFD);
-               err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
-               if (err) {
-                       err = -EIO;
-               }
-       }
-
-       return err;
+       return saa7191_s_std(sd, old_norm);
 }
 
-static int saa7191_autodetect_norm(struct i2c_client *client)
+static int saa7191_autodetect_norm(struct v4l2_subdev *sd)
 {
        u8 status;
 
@@ -383,7 +376,7 @@ static int saa7191_autodetect_norm(struct i2c_client *client)
 
        dprintk("Reading status...\n");
 
-       if (saa7191_read_status(client, &status))
+       if (saa7191_read_status(sd, &status))
                return -EIO;
 
        dprintk("Checking for signal...\n");
@@ -399,26 +392,25 @@ static int saa7191_autodetect_norm(struct i2c_client *client)
        if (status & SAA7191_STATUS_FIDT) {
                /* 60hz signal -> NTSC */
                dprintk("NTSC\n");
-               return saa7191_set_norm(client, SAA7191_NORM_NTSC);
+               return saa7191_s_std(sd, V4L2_STD_NTSC);
        } else {
                /* 50hz signal -> PAL */
                dprintk("PAL\n");
-               return saa7191_set_norm(client, SAA7191_NORM_PAL);
+               return saa7191_s_std(sd, V4L2_STD_PAL);
        }
 }
 
-static int saa7191_get_control(struct i2c_client *client,
-                              struct saa7191_control *ctrl)
+static int saa7191_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
        u8 reg;
        int ret = 0;
 
-       switch (ctrl->type) {
+       switch (ctrl->id) {
        case SAA7191_CONTROL_BANDPASS:
        case SAA7191_CONTROL_BANDPASS_WEIGHT:
        case SAA7191_CONTROL_CORING:
-               reg = saa7191_read_reg(client, SAA7191_REG_LUMA);
-               switch (ctrl->type) {
+               reg = saa7191_read_reg(sd, SAA7191_REG_LUMA);
+               switch (ctrl->id) {
                case SAA7191_CONTROL_BANDPASS:
                        ctrl->value = ((s32)reg & SAA7191_LUMA_BPSS_MASK)
                                >> SAA7191_LUMA_BPSS_SHIFT;
@@ -435,15 +427,15 @@ static int saa7191_get_control(struct i2c_client *client,
                break;
        case SAA7191_CONTROL_FORCE_COLOUR:
        case SAA7191_CONTROL_CHROMA_GAIN:
-               reg = saa7191_read_reg(client, SAA7191_REG_GAIN);
-               if (ctrl->type == SAA7191_CONTROL_FORCE_COLOUR)
+               reg = saa7191_read_reg(sd, SAA7191_REG_GAIN);
+               if (ctrl->id == SAA7191_CONTROL_FORCE_COLOUR)
                        ctrl->value = ((s32)reg & SAA7191_GAIN_COLO) ? 1 : 0;
                else
                        ctrl->value = ((s32)reg & SAA7191_GAIN_LFIS_MASK)
                                >> SAA7191_GAIN_LFIS_SHIFT;
                break;
-       case SAA7191_CONTROL_HUE:
-               reg = saa7191_read_reg(client, SAA7191_REG_HUEC);
+       case V4L2_CID_HUE:
+               reg = saa7191_read_reg(sd, SAA7191_REG_HUEC);
                if (reg < 0x80)
                        reg += 0x80;
                else
@@ -451,18 +443,18 @@ static int saa7191_get_control(struct i2c_client *client,
                ctrl->value = (s32)reg;
                break;
        case SAA7191_CONTROL_VTRC:
-               reg = saa7191_read_reg(client, SAA7191_REG_STDC);
+               reg = saa7191_read_reg(sd, SAA7191_REG_STDC);
                ctrl->value = ((s32)reg & SAA7191_STDC_VTRC) ? 1 : 0;
                break;
        case SAA7191_CONTROL_LUMA_DELAY:
-               reg = saa7191_read_reg(client, SAA7191_REG_CTL3);
+               reg = saa7191_read_reg(sd, SAA7191_REG_CTL3);
                ctrl->value = ((s32)reg & SAA7191_CTL3_YDEL_MASK)
                        >> SAA7191_CTL3_YDEL_SHIFT;
                if (ctrl->value >= 4)
                        ctrl->value -= 8;
                break;
        case SAA7191_CONTROL_VNR:
-               reg = saa7191_read_reg(client, SAA7191_REG_CTL4);
+               reg = saa7191_read_reg(sd, SAA7191_REG_CTL4);
                ctrl->value = ((s32)reg & SAA7191_CTL4_VNOI_MASK)
                        >> SAA7191_CTL4_VNOI_SHIFT;
                break;
@@ -473,18 +465,17 @@ static int saa7191_get_control(struct i2c_client *client,
        return ret;
 }
 
-static int saa7191_set_control(struct i2c_client *client,
-                              struct saa7191_control *ctrl)
+static int saa7191_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
        u8 reg;
        int ret = 0;
 
-       switch (ctrl->type) {
+       switch (ctrl->id) {
        case SAA7191_CONTROL_BANDPASS:
        case SAA7191_CONTROL_BANDPASS_WEIGHT:
        case SAA7191_CONTROL_CORING:
-               reg = saa7191_read_reg(client, SAA7191_REG_LUMA);
-               switch (ctrl->type) {
+               reg = saa7191_read_reg(sd, SAA7191_REG_LUMA);
+               switch (ctrl->id) {
                case SAA7191_CONTROL_BANDPASS:
                        reg &= ~SAA7191_LUMA_BPSS_MASK;
                        reg |= (ctrl->value << SAA7191_LUMA_BPSS_SHIFT)
@@ -501,12 +492,12 @@ static int saa7191_set_control(struct i2c_client *client,
                                & SAA7191_LUMA_CORI_MASK;
                        break;
                }
-               ret = saa7191_write_reg(client, SAA7191_REG_LUMA, reg);
+               ret = saa7191_write_reg(sd, SAA7191_REG_LUMA, reg);
                break;
        case SAA7191_CONTROL_FORCE_COLOUR:
        case SAA7191_CONTROL_CHROMA_GAIN:
-               reg = saa7191_read_reg(client, SAA7191_REG_GAIN);
-               if (ctrl->type == SAA7191_CONTROL_FORCE_COLOUR) {
+               reg = saa7191_read_reg(sd, SAA7191_REG_GAIN);
+               if (ctrl->id == SAA7191_CONTROL_FORCE_COLOUR) {
                        if (ctrl->value)
                                reg |= SAA7191_GAIN_COLO;
                        else
@@ -516,41 +507,41 @@ static int saa7191_set_control(struct i2c_client *client,
                        reg |= (ctrl->value << SAA7191_GAIN_LFIS_SHIFT)
                                & SAA7191_GAIN_LFIS_MASK;
                }
-               ret = saa7191_write_reg(client, SAA7191_REG_GAIN, reg);
+               ret = saa7191_write_reg(sd, SAA7191_REG_GAIN, reg);
                break;
-       case SAA7191_CONTROL_HUE:
+       case V4L2_CID_HUE:
                reg = ctrl->value & 0xff;
                if (reg < 0x80)
                        reg += 0x80;
                else
                        reg -= 0x80;
-               ret = saa7191_write_reg(client, SAA7191_REG_HUEC, reg);
+               ret = saa7191_write_reg(sd, SAA7191_REG_HUEC, reg);
                break;
        case SAA7191_CONTROL_VTRC:
-               reg = saa7191_read_reg(client, SAA7191_REG_STDC);
+               reg = saa7191_read_reg(sd, SAA7191_REG_STDC);
                if (ctrl->value)
                        reg |= SAA7191_STDC_VTRC;
                else
                        reg &= ~SAA7191_STDC_VTRC;
-               ret = saa7191_write_reg(client, SAA7191_REG_STDC, reg);
+               ret = saa7191_write_reg(sd, SAA7191_REG_STDC, reg);
                break;
        case SAA7191_CONTROL_LUMA_DELAY: {
                s32 value = ctrl->value;
                if (value < 0)
                        value += 8;
-               reg = saa7191_read_reg(client, SAA7191_REG_CTL3);
+               reg = saa7191_read_reg(sd, SAA7191_REG_CTL3);
                reg &= ~SAA7191_CTL3_YDEL_MASK;
                reg |= (value << SAA7191_CTL3_YDEL_SHIFT)
                        & SAA7191_CTL3_YDEL_MASK;
-               ret = saa7191_write_reg(client, SAA7191_REG_CTL3, reg);
+               ret = saa7191_write_reg(sd, SAA7191_REG_CTL3, reg);
                break;
        }
        case SAA7191_CONTROL_VNR:
-               reg = saa7191_read_reg(client, SAA7191_REG_CTL4);
+               reg = saa7191_read_reg(sd, SAA7191_REG_CTL4);
                reg &= ~SAA7191_CTL4_VNOI_MASK;
                reg |= (ctrl->value << SAA7191_CTL4_VNOI_SHIFT)
                        & SAA7191_CTL4_VNOI_MASK;
-               ret = saa7191_write_reg(client, SAA7191_REG_CTL4, reg);
+               ret = saa7191_write_reg(sd, SAA7191_REG_CTL4, reg);
                break;
        default:
                ret = -EINVAL;
@@ -561,247 +552,108 @@ static int saa7191_set_control(struct i2c_client *client,
 
 /* I2C-interface */
 
-static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind)
+static int saa7191_g_input_status(struct v4l2_subdev *sd, u32 *status)
 {
-       int err = 0;
-       struct saa7191 *decoder;
-       struct i2c_client *client;
-
-       printk(KERN_INFO "Philips SAA7191 driver version %s\n",
-              SAA7191_MODULE_VERSION);
-
-       client = kzalloc(sizeof(*client), GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;
-       decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
-       if (!decoder) {
-               err = -ENOMEM;
-               goto out_free_client;
-       }
-
-       client->addr = addr;
-       client->adapter = adap;
-       client->driver = &i2c_driver_saa7191;
-       client->flags = 0;
-       strcpy(client->name, "saa7191 client");
-       i2c_set_clientdata(client, decoder);
-
-       decoder->client = client;
-
-       err = i2c_attach_client(client);
-       if (err)
-               goto out_free_decoder;
-
-       err = saa7191_write_block(client, sizeof(initseq), initseq);
-       if (err) {
-               printk(KERN_ERR "SAA7191 initialization failed\n");
-               goto out_detach_client;
-       }
-
-       printk(KERN_INFO "SAA7191 initialized\n");
-
-       decoder->input = SAA7191_INPUT_COMPOSITE;
-       decoder->norm = SAA7191_NORM_PAL;
-
-       err = saa7191_autodetect_norm(client);
-       if (err && (err != -EBUSY)) {
-               printk(KERN_ERR "SAA7191: Signal auto-detection failed\n");
-       }
+       u8 status_reg;
+       int res = V4L2_IN_ST_NO_SIGNAL;
 
+       if (saa7191_read_status(sd, &status_reg))
+               return -EIO;
+       if ((status_reg & SAA7191_STATUS_HLCK) == 0)
+               res = 0;
+       if (!(status_reg & SAA7191_STATUS_CODE))
+               res |= V4L2_IN_ST_NO_COLOR;
+       *status = res;
        return 0;
-
-out_detach_client:
-       i2c_detach_client(client);
-out_free_decoder:
-       kfree(decoder);
-out_free_client:
-       kfree(client);
-       return err;
 }
 
-static int saa7191_probe(struct i2c_adapter *adap)
-{
-       /* Always connected to VINO */
-       if (adap->id == I2C_HW_SGI_VINO)
-               return saa7191_attach(adap, SAA7191_ADDR, 0);
-       /* Feel free to add probe here :-) */
-       return -ENODEV;
-}
 
-static int saa7191_detach(struct i2c_client *client)
+static int saa7191_g_chip_ident(struct v4l2_subdev *sd,
+               struct v4l2_dbg_chip_ident *chip)
 {
-       struct saa7191 *decoder = i2c_get_clientdata(client);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       i2c_detach_client(client);
-       kfree(decoder);
-       kfree(client);
-       return 0;
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7191, 0);
 }
 
-static int saa7191_command(struct i2c_client *client, unsigned int cmd,
-                          void *arg)
-{
-       struct saa7191 *decoder = i2c_get_clientdata(client);
+/* ----------------------------------------------------------------------- */
 
-       switch (cmd) {
-       case DECODER_GET_CAPABILITIES: {
-               struct video_decoder_capability *cap = arg;
+static const struct v4l2_subdev_core_ops saa7191_core_ops = {
+       .g_chip_ident = saa7191_g_chip_ident,
+       .g_ctrl = saa7191_g_ctrl,
+       .s_ctrl = saa7191_s_ctrl,
+};
 
-               cap->flags  = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC |
-                             VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO;
-               cap->inputs = (client->adapter->id == I2C_HW_SGI_VINO) ? 2 : 1;
-               cap->outputs = 1;
-               break;
-       }
-       case DECODER_GET_STATUS: {
-               int *iarg = arg;
-               u8 status;
-               int res = 0;
+static const struct v4l2_subdev_tuner_ops saa7191_tuner_ops = {
+       .s_std = saa7191_s_std,
+};
 
-               if (saa7191_read_status(client, &status)) {
-                       return -EIO;
-               }
-               if ((status & SAA7191_STATUS_HLCK) == 0)
-                       res |= DECODER_STATUS_GOOD;
-               if (status & SAA7191_STATUS_CODE)
-                       res |= DECODER_STATUS_COLOR;
-               switch (decoder->norm) {
-               case SAA7191_NORM_NTSC:
-                       res |= DECODER_STATUS_NTSC;
-                       break;
-               case SAA7191_NORM_PAL:
-                       res |= DECODER_STATUS_PAL;
-                       break;
-               case SAA7191_NORM_SECAM:
-                       res |= DECODER_STATUS_SECAM;
-                       break;
-               case SAA7191_NORM_AUTO:
-               default:
-                       if (status & SAA7191_STATUS_FIDT)
-                               res |= DECODER_STATUS_NTSC;
-                       else
-                               res |= DECODER_STATUS_PAL;
-                       break;
-               }
-               *iarg = res;
-               break;
-       }
-       case DECODER_SET_NORM: {
-               int *iarg = arg;
-
-               switch (*iarg) {
-               case VIDEO_MODE_AUTO:
-                       return saa7191_autodetect_norm(client);
-               case VIDEO_MODE_PAL:
-                       return saa7191_set_norm(client, SAA7191_NORM_PAL);
-               case VIDEO_MODE_NTSC:
-                       return saa7191_set_norm(client, SAA7191_NORM_NTSC);
-               case VIDEO_MODE_SECAM:
-                       return saa7191_set_norm(client, SAA7191_NORM_SECAM);
-               default:
-                       return -EINVAL;
-               }
-               break;
-       }
-       case DECODER_SET_INPUT: {
-               int *iarg = arg;
-
-               switch (client->adapter->id) {
-               case I2C_HW_SGI_VINO:
-                       return saa7191_set_input(client, *iarg);
-               default:
-                       if (*iarg != 0)
-                               return -EINVAL;
-               }
-               break;
-       }
-       case DECODER_SET_OUTPUT: {
-               int *iarg = arg;
+static const struct v4l2_subdev_video_ops saa7191_video_ops = {
+       .s_routing = saa7191_s_routing,
+       .querystd = saa7191_querystd,
+       .g_input_status = saa7191_g_input_status,
+};
 
-               /* not much choice of outputs */
-               if (*iarg != 0)
-                       return -EINVAL;
-               break;
-       }
-       case DECODER_ENABLE_OUTPUT: {
-               /* Always enabled */
-               break;
-       }
-       case DECODER_SET_PICTURE: {
-               struct video_picture *pic = arg;
-               unsigned val;
-               int err;
+static const struct v4l2_subdev_ops saa7191_ops = {
+       .core = &saa7191_core_ops,
+       .video = &saa7191_video_ops,
+       .tuner = &saa7191_tuner_ops,
+};
 
-               val = (pic->hue >> 8) - 0x80;
+static int saa7191_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       int err = 0;
+       struct saa7191 *decoder;
+       struct v4l2_subdev *sd;
 
-               err = saa7191_write_reg(client, SAA7191_REG_HUEC, val);
-               if (err)
-                       return -EIO;
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
-               break;
-       }
-       case DECODER_SAA7191_GET_STATUS: {
-               struct saa7191_status *status = arg;
-               u8 status_reg;
+       decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
+       if (!decoder)
+               return -ENOMEM;
 
-               if (saa7191_read_status(client, &status_reg))
-                       return -EIO;
+       sd = &decoder->sd;
+       v4l2_i2c_subdev_init(sd, client, &saa7191_ops);
 
-               status->signal = ((status_reg & SAA7191_STATUS_HLCK) == 0)
-                       ? 1 : 0;
-               status->signal_60hz = (status_reg & SAA7191_STATUS_FIDT)
-                       ? 1 : 0;
-               status->color = (status_reg & SAA7191_STATUS_CODE) ? 1 : 0;
+       err = saa7191_write_block(sd, sizeof(initseq), initseq);
+       if (err) {
+               printk(KERN_ERR "SAA7191 initialization failed\n");
+               kfree(decoder);
+               return err;
+       }
 
-               status->input = decoder->input;
-               status->norm = decoder->norm;
+       printk(KERN_INFO "SAA7191 initialized\n");
 
-               break;
-       }
-       case DECODER_SAA7191_SET_NORM: {
-               int *norm = arg;
-
-               switch (*norm) {
-               case SAA7191_NORM_AUTO:
-                       return saa7191_autodetect_norm(client);
-               case SAA7191_NORM_AUTO_EXT:
-                       return saa7191_autodetect_norm_extended(client);
-               default:
-                       return saa7191_set_norm(client, *norm);
-               }
-       }
-       case DECODER_SAA7191_GET_CONTROL: {
-               return saa7191_get_control(client, arg);
-       }
-       case DECODER_SAA7191_SET_CONTROL: {
-               return saa7191_set_control(client, arg);
-       }
-       default:
-               return -EINVAL;
-       }
+       decoder->input = SAA7191_INPUT_COMPOSITE;
+       decoder->norm = V4L2_STD_PAL;
+
+       err = saa7191_autodetect_norm(sd);
+       if (err && (err != -EBUSY))
+               printk(KERN_ERR "SAA7191: Signal auto-detection failed\n");
 
        return 0;
 }
 
-static struct i2c_driver i2c_driver_saa7191 = {
-       .driver = {
-               .name   = "saa7191",
-       },
-       .id             = I2C_DRIVERID_SAA7191,
-       .attach_adapter = saa7191_probe,
-       .detach_client  = saa7191_detach,
-       .command        = saa7191_command
-};
-
-static int saa7191_init(void)
+static int saa7191_remove(struct i2c_client *client)
 {
-       return i2c_add_driver(&i2c_driver_saa7191);
-}
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
-static void saa7191_exit(void)
-{
-       i2c_del_driver(&i2c_driver_saa7191);
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_saa7191(sd));
+       return 0;
 }
 
-module_init(saa7191_init);
-module_exit(saa7191_exit);
+static const struct i2c_device_id saa7191_id[] = {
+       { "saa7191", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7191_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "saa7191",
+       .probe = saa7191_probe,
+       .remove = saa7191_remove,
+       .id_table = saa7191_id,
+};
index a2310da1940df4e7993c71102a92629aab5875b1..803c74d6066f3bf24e2cbf6cf615dd580f82b298 100644 (file)
 #define SAA7191_INPUT_COMPOSITE        0
 #define SAA7191_INPUT_SVIDEO   1
 
-#define SAA7191_NORM_AUTO      0
 #define SAA7191_NORM_PAL       1
 #define SAA7191_NORM_NTSC      2
 #define SAA7191_NORM_SECAM     3
-#define SAA7191_NORM_AUTO_EXT  4       /* extended auto-detection */
 
 struct saa7191_status {
        /* 0=no signal, 1=signal detected */
@@ -232,24 +230,16 @@ struct saa7191_status {
 #define SAA7191_VNR_MAX                        0x03
 #define SAA7191_VNR_DEFAULT            0x00
 
-#define SAA7191_CONTROL_BANDPASS       0
-#define SAA7191_CONTROL_BANDPASS_WEIGHT        1
-#define SAA7191_CONTROL_CORING         2
-#define SAA7191_CONTROL_FORCE_COLOUR   3       /* boolean */
-#define SAA7191_CONTROL_CHROMA_GAIN    4
-#define SAA7191_CONTROL_HUE            5
-#define SAA7191_CONTROL_VTRC           6       /* boolean */
-#define SAA7191_CONTROL_LUMA_DELAY     7
-#define SAA7191_CONTROL_VNR            8
-
-struct saa7191_control {
-       u8 type;
-       s32 value;
-};
+#define SAA7191_CONTROL_BANDPASS       (V4L2_CID_PRIVATE_BASE + 0)
+#define SAA7191_CONTROL_BANDPASS_WEIGHT        (V4L2_CID_PRIVATE_BASE + 1)
+#define SAA7191_CONTROL_CORING         (V4L2_CID_PRIVATE_BASE + 2)
+#define SAA7191_CONTROL_FORCE_COLOUR   (V4L2_CID_PRIVATE_BASE + 3)
+#define SAA7191_CONTROL_CHROMA_GAIN    (V4L2_CID_PRIVATE_BASE + 4)
+#define SAA7191_CONTROL_VTRC           (V4L2_CID_PRIVATE_BASE + 5)
+#define SAA7191_CONTROL_LUMA_DELAY     (V4L2_CID_PRIVATE_BASE + 6)
+#define SAA7191_CONTROL_VNR            (V4L2_CID_PRIVATE_BASE + 7)
 
 #define        DECODER_SAA7191_GET_STATUS      _IOR('d', 195, struct saa7191_status)
 #define        DECODER_SAA7191_SET_NORM        _IOW('d', 196, int)
-#define        DECODER_SAA7191_GET_CONTROL     _IOR('d', 197, struct saa7191_control)
-#define        DECODER_SAA7191_SET_CONTROL     _IOW('d', 198, struct saa7191_control)
 
 #endif
index ddcb81d0b81a36df1ebebe0b6663c0eed1887040..b5e37a530c62a9cad5ac1401d78639c31577d62f 100644 (file)
@@ -94,13 +94,37 @@ struct sh_mobile_ceu_dev {
        spinlock_t lock;
        struct list_head capture;
        struct videobuf_buffer *active;
-       int is_interlace;
+       int is_interlaced;
 
        struct sh_mobile_ceu_info *pdata;
 
        const struct soc_camera_data_format *camera_fmt;
 };
 
+static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev)
+{
+       unsigned long flags;
+
+       flags = SOCAM_MASTER |
+               SOCAM_PCLK_SAMPLE_RISING |
+               SOCAM_HSYNC_ACTIVE_HIGH |
+               SOCAM_HSYNC_ACTIVE_LOW |
+               SOCAM_VSYNC_ACTIVE_HIGH |
+               SOCAM_VSYNC_ACTIVE_LOW |
+               SOCAM_DATA_ACTIVE_HIGH;
+
+       if (pcdev->pdata->flags & SH_CEU_FLAG_USE_8BIT_BUS)
+               flags |= SOCAM_DATAWIDTH_8;
+
+       if (pcdev->pdata->flags & SH_CEU_FLAG_USE_16BIT_BUS)
+               flags |= SOCAM_DATAWIDTH_16;
+
+       if (flags & SOCAM_DATAWIDTH_MASK)
+               return flags;
+
+       return 0;
+}
+
 static void ceu_write(struct sh_mobile_ceu_dev *priv,
                      unsigned long reg_offs, u32 data)
 {
@@ -150,6 +174,7 @@ static void free_buffer(struct videobuf_queue *vq,
        if (in_interrupt())
                BUG();
 
+       videobuf_waiton(&buf->vb, 0, 0);
        videobuf_dma_contig_free(vq, &buf->vb);
        dev_dbg(&icd->dev, "%s freed\n", __func__);
        buf->vb.state = VIDEOBUF_NEEDS_INIT;
@@ -181,7 +206,7 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
 
        phys_addr_top = videobuf_to_dma_contig(pcdev->active);
        ceu_write(pcdev, CDAYR, phys_addr_top);
-       if (pcdev->is_interlace) {
+       if (pcdev->is_interlaced) {
                phys_addr_bottom = phys_addr_top + icd->width;
                ceu_write(pcdev, CDBYR, phys_addr_bottom);
        }
@@ -193,7 +218,7 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
        case V4L2_PIX_FMT_NV61:
                phys_addr_top += icd->width * icd->height;
                ceu_write(pcdev, CDACR, phys_addr_top);
-               if (pcdev->is_interlace) {
+               if (pcdev->is_interlaced) {
                        phys_addr_bottom = phys_addr_top + icd->width;
                        ceu_write(pcdev, CDBCR, phys_addr_bottom);
                }
@@ -396,7 +421,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
 
        camera_flags = icd->ops->query_bus_param(icd);
        common_flags = soc_camera_bus_param_compatible(camera_flags,
-                                                      pcdev->pdata->flags);
+                                                      make_bus_param(pcdev));
        if (!common_flags)
                return -EINVAL;
 
@@ -457,7 +482,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
        ceu_write(pcdev, CAMCR, value);
 
        ceu_write(pcdev, CAPCR, 0x00300000);
-       ceu_write(pcdev, CAIFR, (pcdev->is_interlace) ? 0x101 : 0);
+       ceu_write(pcdev, CAIFR, pcdev->is_interlaced ? 0x101 : 0);
 
        mdelay(1);
 
@@ -473,7 +498,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
        }
 
        height = icd->height;
-       if (pcdev->is_interlace) {
+       if (pcdev->is_interlaced) {
                height /= 2;
                cdwdr_width *= 2;
        }
@@ -517,7 +542,7 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd)
 
        camera_flags = icd->ops->query_bus_param(icd);
        common_flags = soc_camera_bus_param_compatible(camera_flags,
-                                                      pcdev->pdata->flags);
+                                                      make_bus_param(pcdev));
        if (!common_flags)
                return -EINVAL;
 
@@ -562,11 +587,29 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
        if (ret < 0)
                return 0;
 
+       /* Beginning of a pass */
+       if (!idx)
+               icd->host_priv = NULL;
+
        switch (icd->formats[idx].fourcc) {
        case V4L2_PIX_FMT_UYVY:
        case V4L2_PIX_FMT_VYUY:
        case V4L2_PIX_FMT_YUYV:
        case V4L2_PIX_FMT_YVYU:
+               if (icd->host_priv)
+                       goto add_single_format;
+
+               /*
+                * Our case is simple so far: for any of the above four camera
+                * formats we add all our four synthesized NV* formats, so,
+                * just marking the device with a single flag suffices. If
+                * the format generation rules are more complex, you would have
+                * to actually hang your already added / counted formats onto
+                * the host_priv pointer and check whether the format you're
+                * going to add now is already there.
+                */
+               icd->host_priv = (void *)sh_mobile_ceu_formats;
+
                n = ARRAY_SIZE(sh_mobile_ceu_formats);
                formats += n;
                for (k = 0; xlate && k < n; k++) {
@@ -579,6 +622,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
                                icd->formats[idx].name);
                }
        default:
+add_single_format:
                /* Generic pass-through */
                formats++;
                if (xlate) {
@@ -595,24 +639,30 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
        return formats;
 }
 
+static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
+                                 struct v4l2_rect *rect)
+{
+       return icd->ops->set_crop(icd, rect);
+}
+
 static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
-                                __u32 pixfmt, struct v4l2_rect *rect)
+                                struct v4l2_format *f)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
+       __u32 pixfmt = f->fmt.pix.pixelformat;
        const struct soc_camera_format_xlate *xlate;
+       struct v4l2_format cam_f = *f;
        int ret;
 
-       if (!pixfmt)
-               return icd->ops->set_fmt(icd, pixfmt, rect);
-
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
                dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
-       ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect);
+       cam_f.fmt.pix.pixelformat = xlate->cam_fmt->fourcc;
+       ret = icd->ops->set_fmt(icd, &cam_f);
 
        if (!ret) {
                icd->buswidth = xlate->buswidth;
@@ -662,13 +712,13 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
 
        switch (f->fmt.pix.field) {
        case V4L2_FIELD_INTERLACED:
-               pcdev->is_interlace = 1;
+               pcdev->is_interlaced = 1;
                break;
        case V4L2_FIELD_ANY:
                f->fmt.pix.field = V4L2_FIELD_NONE;
                /* fall-through */
        case V4L2_FIELD_NONE:
-               pcdev->is_interlace = 0;
+               pcdev->is_interlaced = 0;
                break;
        default:
                ret = -EINVAL;
@@ -734,7 +784,8 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
                                       &sh_mobile_ceu_videobuf_ops,
                                       &ici->dev, &pcdev->lock,
                                       V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                                      V4L2_FIELD_ANY,
+                                      pcdev->is_interlaced ?
+                                      V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE,
                                       sizeof(struct sh_mobile_ceu_buffer),
                                       icd);
 }
@@ -744,6 +795,7 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
        .add            = sh_mobile_ceu_add_device,
        .remove         = sh_mobile_ceu_remove_device,
        .get_formats    = sh_mobile_ceu_get_formats,
+       .set_crop       = sh_mobile_ceu_set_crop,
        .set_fmt        = sh_mobile_ceu_set_fmt,
        .try_fmt        = sh_mobile_ceu_try_fmt,
        .reqbufs        = sh_mobile_ceu_reqbufs,
index 8cb3457e778d0d30d408f454071e2bbc2ea4dea0..38a716020d7f46daa6dace7cebce7a60811580d3 100644 (file)
@@ -96,9 +96,7 @@ static const struct usb_device_id sn9c102_id_table[] = {
 #if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
        { SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), },
        { SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), },
-#endif
        { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
-#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
        { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), },
 #endif
        { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), },
@@ -123,7 +121,9 @@ static const struct usb_device_id sn9c102_id_table[] = {
        { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
 #endif
        { 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), },
        { }
 };
index fcb05f06de8ffb7d73e564820110ca78100a7a07..6d8bfd4d97e20ba49303b26b133665045f5a61a9 100644 (file)
 #include <media/videobuf-core.h>
 #include <media/soc_camera.h>
 
+/* Default to VGA resolution */
+#define DEFAULT_WIDTH  640
+#define DEFAULT_HEIGHT 480
+
 static LIST_HEAD(hosts);
 static LIST_HEAD(devices);
 static DEFINE_MUTEX(list_lock);
@@ -256,6 +260,46 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd)
        vfree(icd->user_formats);
 }
 
+/* Called with .vb_lock held */
+static int soc_camera_set_fmt(struct soc_camera_file *icf,
+                             struct v4l2_format *f)
+{
+       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       int ret;
+
+       /* We always call try_fmt() before set_fmt() or set_crop() */
+       ret = ici->ops->try_fmt(icd, f);
+       if (ret < 0)
+               return ret;
+
+       ret = ici->ops->set_fmt(icd, f);
+       if (ret < 0) {
+               return ret;
+       } else if (!icd->current_fmt ||
+                  icd->current_fmt->fourcc != pix->pixelformat) {
+               dev_err(&ici->dev,
+                       "Host driver hasn't set up current format correctly!\n");
+               return -EINVAL;
+       }
+
+       icd->width              = pix->width;
+       icd->height             = pix->height;
+       icf->vb_vidq.field      =
+               icd->field      = pix->field;
+
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
+                        f->type);
+
+       dev_dbg(&icd->dev, "set width: %d height: %d\n",
+               icd->width, icd->height);
+
+       /* set physical bus parameters */
+       return ici->ops->set_bus_param(icd, pix->pixelformat);
+}
+
 static int soc_camera_open(struct file *file)
 {
        struct video_device *vdev;
@@ -297,14 +341,28 @@ static int soc_camera_open(struct file *file)
 
        /* Now we really have to activate the camera */
        if (icd->use_count == 1) {
-               ret = soc_camera_init_user_formats(icd);
-               if (ret < 0)
-                       goto eiufmt;
+               /* Restore parameters before the last close() per V4L2 API */
+               struct v4l2_format f = {
+                       .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                       .fmt.pix = {
+                               .width          = icd->width,
+                               .height         = icd->height,
+                               .field          = icd->field,
+                               .pixelformat    = icd->current_fmt->fourcc,
+                               .colorspace     = icd->current_fmt->colorspace,
+                       },
+               };
+
                ret = ici->ops->add(icd);
                if (ret < 0) {
                        dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
                        goto eiciadd;
                }
+
+               /* Try to configure with default parameters */
+               ret = soc_camera_set_fmt(icf, &f);
+               if (ret < 0)
+                       goto esfmt;
        }
 
        mutex_unlock(&icd->video_lock);
@@ -316,10 +374,13 @@ static int soc_camera_open(struct file *file)
 
        return 0;
 
-       /* First two errors are entered with the .video_lock held */
+       /*
+        * First three errors are entered with the .video_lock held
+        * and use_count == 1
+        */
+esfmt:
+       ici->ops->remove(icd);
 eiciadd:
-       soc_camera_free_user_formats(icd);
-eiufmt:
        icd->use_count--;
        mutex_unlock(&icd->video_lock);
        module_put(ici->ops->owner);
@@ -339,10 +400,9 @@ static int soc_camera_close(struct file *file)
 
        mutex_lock(&icd->video_lock);
        icd->use_count--;
-       if (!icd->use_count) {
+       if (!icd->use_count)
                ici->ops->remove(icd);
-               soc_camera_free_user_formats(icd);
-       }
+
        mutex_unlock(&icd->video_lock);
 
        module_put(icd->ops->owner);
@@ -415,18 +475,10 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
 {
        struct soc_camera_file *icf = file->private_data;
        struct soc_camera_device *icd = icf->icd;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
-       struct v4l2_pix_format *pix = &f->fmt.pix;
-       __u32 pixfmt = pix->pixelformat;
        int ret;
-       struct v4l2_rect rect;
 
        WARN_ON(priv != file->private_data);
 
-       ret = soc_camera_try_fmt_vid_cap(file, priv, f);
-       if (ret < 0)
-               return ret;
-
        mutex_lock(&icf->vb_vidq.vb_lock);
 
        if (videobuf_queue_is_busy(&icf->vb_vidq)) {
@@ -435,33 +487,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
                goto unlock;
        }
 
-       rect.left       = icd->x_current;
-       rect.top        = icd->y_current;
-       rect.width      = pix->width;
-       rect.height     = pix->height;
-       ret = ici->ops->set_fmt(icd, pix->pixelformat, &rect);
-       if (ret < 0) {
-               goto unlock;
-       } else if (!icd->current_fmt ||
-                  icd->current_fmt->fourcc != pixfmt) {
-               dev_err(&ici->dev,
-                       "Host driver hasn't set up current format correctly!\n");
-               ret = -EINVAL;
-               goto unlock;
-       }
-
-       icd->width              = rect.width;
-       icd->height             = rect.height;
-       icf->vb_vidq.field      = pix->field;
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
-                        f->type);
-
-       dev_dbg(&icd->dev, "set width: %d height: %d\n",
-               icd->width, icd->height);
-
-       /* set physical bus parameters */
-       ret = ici->ops->set_bus_param(icd, pixfmt);
+       ret = soc_camera_set_fmt(icf, f);
 
 unlock:
        mutex_unlock(&icf->vb_vidq.vb_lock);
@@ -648,8 +674,8 @@ static int soc_camera_cropcap(struct file *file, void *fh,
        a->bounds.height                = icd->height_max;
        a->defrect.left                 = icd->x_min;
        a->defrect.top                  = icd->y_min;
-       a->defrect.width                = 640;
-       a->defrect.height               = 480;
+       a->defrect.width                = DEFAULT_WIDTH;
+       a->defrect.height               = DEFAULT_HEIGHT;
        a->pixelaspect.numerator        = 1;
        a->pixelaspect.denominator      = 1;
 
@@ -685,7 +711,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
        /* Cropping is allowed during a running capture, guard consistency */
        mutex_lock(&icf->vb_vidq.vb_lock);
 
-       ret = ici->ops->set_fmt(icd, 0, &a->c);
+       ret = ici->ops->set_crop(icd, &a->c);
        if (!ret) {
                icd->width      = a->c.width;
                icd->height     = a->c.height;
@@ -844,9 +870,18 @@ static int soc_camera_probe(struct device *dev)
                qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
                icd->exposure = qctrl ? qctrl->default_value :
                        (unsigned short)~0;
+
+               ret = soc_camera_init_user_formats(icd);
+               if (ret < 0)
+                       goto eiufmt;
+
+               icd->height     = DEFAULT_HEIGHT;
+               icd->width      = DEFAULT_WIDTH;
+               icd->field      = V4L2_FIELD_ANY;
        }
-       ici->ops->remove(icd);
 
+eiufmt:
+       ici->ops->remove(icd);
 eiadd:
        mutex_unlock(&icd->video_lock);
        module_put(ici->ops->owner);
@@ -865,6 +900,8 @@ static int soc_camera_remove(struct device *dev)
        if (icd->ops->remove)
                icd->ops->remove(icd);
 
+       soc_camera_free_user_formats(icd);
+
        return 0;
 }
 
@@ -918,6 +955,7 @@ int soc_camera_host_register(struct soc_camera_host *ici)
        if (!ici || !ici->ops ||
            !ici->ops->try_fmt ||
            !ici->ops->set_fmt ||
+           !ici->ops->set_crop ||
            !ici->ops->set_bus_param ||
            !ici->ops->querycap ||
            !ici->ops->init_videobuf ||
@@ -998,6 +1036,7 @@ int soc_camera_device_register(struct soc_camera_device *icd)
            !icd->ops->release ||
            !icd->ops->start_capture ||
            !icd->ops->stop_capture ||
+           !icd->ops->set_crop ||
            !icd->ops->set_fmt ||
            !icd->ops->try_fmt ||
            !icd->ops->query_bus_param ||
index 013ab06e318042c39369bcf380fa709234b6b227..c48676356ab7d503a4fc32257fccfe67d8a73ffa 100644 (file)
@@ -79,8 +79,14 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *icd)
        return p->bus_param;
 }
 
+static int soc_camera_platform_set_crop(struct soc_camera_device *icd,
+                                       struct v4l2_rect *rect)
+{
+       return 0;
+}
+
 static int soc_camera_platform_set_fmt(struct soc_camera_device *icd,
-                                      __u32 pixfmt, struct v4l2_rect *rect)
+                                      struct v4l2_format *f)
 {
        return 0;
 }
@@ -125,6 +131,7 @@ static struct soc_camera_ops soc_camera_platform_ops = {
        .release                = soc_camera_platform_release,
        .start_capture          = soc_camera_platform_start_capture,
        .stop_capture           = soc_camera_platform_stop_capture,
+       .set_crop               = soc_camera_platform_set_crop,
        .set_fmt                = soc_camera_platform_set_fmt,
        .try_fmt                = soc_camera_platform_try_fmt,
        .set_bus_param          = soc_camera_platform_set_bus_param,
index 26378cf390fc483542dce73a1e0ad5ccb6f3a698..1a6d39cbd6f31b79ad91071f1d9a2802a91042a3 100644 (file)
@@ -933,8 +933,6 @@ static int stk_vidioc_s_ctrl(struct file *filp,
 static int stk_vidioc_enum_fmt_vid_cap(struct file *filp,
                void *priv, struct v4l2_fmtdesc *fmtd)
 {
-       fmtd->flags = 0;
-
        switch (fmtd->index) {
        case 0:
                fmtd->pixelformat = V4L2_PIX_FMT_RGB565;
@@ -992,7 +990,6 @@ static int stk_vidioc_g_fmt_vid_cap(struct file *filp,
        pix_format->height = stk_sizes[i].h;
        pix_format->field = V4L2_FIELD_NONE;
        pix_format->colorspace = V4L2_COLORSPACE_SRGB;
-       pix_format->priv = 0;
        pix_format->pixelformat = dev->vsettings.palette;
        if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8)
                pix_format->bytesperline = pix_format->width;
@@ -1115,8 +1112,6 @@ static int stk_vidioc_reqbufs(struct file *filp,
 
        if (dev == NULL)
                return -ENODEV;
-       if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
        if (rb->memory != V4L2_MEMORY_MMAP)
                return -EINVAL;
        if (is_streaming(dev)
@@ -1139,16 +1134,10 @@ static int stk_vidioc_reqbufs(struct file *filp,
 static int stk_vidioc_querybuf(struct file *filp,
                void *priv, struct v4l2_buffer *buf)
 {
-       int index;
        struct stk_camera *dev = priv;
        struct stk_sio_buffer *sbuf;
 
-       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       index = buf->index;
-
-       if (index < 0 || index >= dev->n_sbufs)
+       if (buf->index < 0 || buf->index >= dev->n_sbufs)
                return -EINVAL;
        sbuf = dev->sio_bufs + buf->index;
        *buf = sbuf->v4lbuf;
@@ -1161,8 +1150,6 @@ static int stk_vidioc_qbuf(struct file *filp,
        struct stk_camera *dev = priv;
        struct stk_sio_buffer *sbuf;
        unsigned long flags;
-       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
 
        if (buf->memory != V4L2_MEMORY_MMAP)
                return -EINVAL;
@@ -1189,8 +1176,7 @@ static int stk_vidioc_dqbuf(struct file *filp,
        unsigned long flags;
        int ret;
 
-       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
-               || !is_streaming(dev))
+       if (!is_streaming(dev))
                return -EINVAL;
 
        if (filp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full))
@@ -1249,16 +1235,10 @@ static int stk_vidioc_streamoff(struct file *filp,
 static int stk_vidioc_g_parm(struct file *filp,
                void *priv, struct v4l2_streamparm *sp)
 {
-       if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       sp->parm.capture.capability = 0;
-       sp->parm.capture.capturemode = 0;
        /*FIXME This is not correct */
        sp->parm.capture.timeperframe.numerator = 1;
        sp->parm.capture.timeperframe.denominator = 30;
        sp->parm.capture.readbuffers = 2;
-       sp->parm.capture.extendedmode = 0;
        return 0;
 }
 
index 29991d1cf13e185fae6090f7a0467b490e2689a9..b30c492482175ada8427e87ce36bc8a80405d17d 100644 (file)
@@ -50,7 +50,7 @@ struct tcm825x_sensor {
 };
 
 /* list of image formats supported by TCM825X sensor */
-const static struct v4l2_fmtdesc tcm825x_formats[] = {
+static const struct v4l2_fmtdesc tcm825x_formats[] = {
        {
                .description = "YUYV (YUV 4:2:2), packed",
                .pixelformat = V4L2_PIX_FMT_UYVY,
@@ -76,15 +76,15 @@ const static struct v4l2_fmtdesc tcm825x_formats[] = {
  * TCM825X register configuration for all combinations of pixel format and
  * image size
  */
-const static struct tcm825x_reg subqcif        =       { 0x20, TCM825X_PICSIZ };
-const static struct tcm825x_reg qcif   =       { 0x18, TCM825X_PICSIZ };
-const static struct tcm825x_reg cif    =       { 0x14, TCM825X_PICSIZ };
-const static struct tcm825x_reg qqvga  =       { 0x0c, TCM825X_PICSIZ };
-const static struct tcm825x_reg qvga   =       { 0x04, TCM825X_PICSIZ };
-const static struct tcm825x_reg vga    =       { 0x00, TCM825X_PICSIZ };
+static const struct tcm825x_reg subqcif        =       { 0x20, TCM825X_PICSIZ };
+static const struct tcm825x_reg qcif   =       { 0x18, TCM825X_PICSIZ };
+static const struct tcm825x_reg cif    =       { 0x14, TCM825X_PICSIZ };
+static const struct tcm825x_reg qqvga  =       { 0x0c, TCM825X_PICSIZ };
+static const struct tcm825x_reg qvga   =       { 0x04, TCM825X_PICSIZ };
+static const struct tcm825x_reg vga    =       { 0x00, TCM825X_PICSIZ };
 
-const static struct tcm825x_reg yuv422 =       { 0x00, TCM825X_PICFMT };
-const static struct tcm825x_reg rgb565 =       { 0x02, TCM825X_PICFMT };
+static const struct tcm825x_reg yuv422 =       { 0x00, TCM825X_PICFMT };
+static const struct tcm825x_reg rgb565 =       { 0x02, TCM825X_PICFMT };
 
 /* Our own specific controls */
 #define V4L2_CID_ALC                           V4L2_CID_PRIVATE_BASE
@@ -248,10 +248,10 @@ static struct vcontrol {
 };
 
 
-const static struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] =
+static const struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] =
 { &subqcif, &qqvga, &qcif, &qvga, &cif, &vga };
 
-const static struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] =
+static const struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] =
 { &yuv422, &rgb565 };
 
 /*
index 770ebacfa344a109663d533f9dc049a226409bd1..5b7e69682368c6189a2965386ced056e7ba5ac48 100644 (file)
@@ -188,7 +188,7 @@ struct tcm825x_platform_data {
 /* Array of image sizes supported by TCM825X.  These must be ordered from
  * smallest image size to largest.
  */
-const static struct capture_size tcm825x_sizes[] = {
+static const struct capture_size tcm825x_sizes[] = {
        { 128,  96 }, /* subQCIF */
        { 160, 120 }, /* QQVGA */
        { 176, 144 }, /* QCIF */
index 0c020585fffbc02f4cb49865868cb690f4122555..005f8a46803148873f6e1dfba22a6bc36c8fcc6b 100644 (file)
@@ -50,7 +50,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/i2c-addr.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/v4l2-i2c-drv.h>
 
 #ifndef VIDEO_AUDIO_BALANCE
 # define VIDEO_AUDIO_BALANCE 32
@@ -69,13 +69,6 @@ MODULE_PARM_DESC(maxvol,"Set maximium volume to +20db (0), default is 0db(1)");
 module_param(maxvol, int, S_IRUGO | S_IWUSR);
 
 
-/* Address to scan (I2C address of this chip) */
-static unsigned short normal_i2c[] = {
-       I2C_ADDR_TDA7432 >> 1,
-       I2C_CLIENT_END,
-};
-
-I2C_CLIENT_INSMOD;
 
 /* Structure of address and subaddresses for the tda7432 */
 
@@ -421,21 +414,18 @@ static int tda7432_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 static int tda7432_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
 {
        switch (qc->id) {
-       case V4L2_CID_AUDIO_MUTE:
        case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
        case V4L2_CID_AUDIO_BALANCE:
        case V4L2_CID_AUDIO_BASS:
        case V4L2_CID_AUDIO_TREBLE:
-               return v4l2_ctrl_query_fill_std(qc);
+               return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
        }
        return -EINVAL;
 }
 
-static int tda7432_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops tda7432_core_ops = {
@@ -498,8 +488,6 @@ MODULE_DEVICE_TABLE(i2c, tda7432_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "tda7432",
-       .driverid = I2C_DRIVERID_TDA7432,
-       .command = tda7432_command,
        .probe = tda7432_probe,
        .remove = tda7432_remove,
        .id_table = tda7432_id,
index 6afb7059502d00df6aa75dbdd24568bb11a2d5f1..fe1158094c2491c277ec433db8f99de44651ee98 100644 (file)
@@ -30,8 +30,8 @@
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-i2c-drv-legacy.h>
-#include "tda9840.h"
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
 MODULE_DESCRIPTION("tda9840 driver");
@@ -56,11 +56,6 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 #define TDA9840_SET_BOTH_R              0x16
 #define TDA9840_SET_EXTERNAL            0x7a
 
-/* addresses to scan, found only at 0x42 (7-Bit) */
-static unsigned short normal_i2c[] = { I2C_ADDR_TDA9840, I2C_CLIENT_END };
-
-/* magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
 
 static void tda9840_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
@@ -137,60 +132,17 @@ static int tda9840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
        return 0;
 }
 
-static long tda9840_ioctl(struct v4l2_subdev *sd, unsigned cmd, void *arg)
+static int tda9840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
 {
-       int byte;
-
-       switch (cmd) {
-       case TDA9840_LEVEL_ADJUST:
-               byte = *(int *)arg;
-               v4l2_dbg(1, debug, sd, "TDA9840_LEVEL_ADJUST: %d\n", byte);
-
-               /* check for correct range */
-               if (byte > 25 || byte < -20)
-                       return -EINVAL;
-
-               /* calculate actual value to set, see specs, page 18 */
-               byte /= 5;
-               if (0 < byte)
-                       byte += 0x8;
-               else
-                       byte = -byte;
-               tda9840_write(sd, LEVEL_ADJUST, byte);
-               break;
-
-       case TDA9840_STEREO_ADJUST:
-               byte = *(int *)arg;
-               v4l2_dbg(1, debug, sd, "TDA9840_STEREO_ADJUST: %d\n", byte);
-
-               /* check for correct range */
-               if (byte > 25 || byte < -24)
-                       return -EINVAL;
-
-               /* calculate actual value to set */
-               byte /= 5;
-               if (0 < byte)
-                       byte += 0x20;
-               else
-                       byte = -byte;
-
-               tda9840_write(sd, STEREO_ADJUST, byte);
-               break;
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TDA9840, 0);
 }
 
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops tda9840_core_ops = {
-       .ioctl = tda9840_ioctl,
+       .g_chip_ident = tda9840_g_chip_ident,
 };
 
 static const struct v4l2_subdev_tuner_ops tda9840_tuner_ops = {
@@ -209,8 +161,6 @@ static int tda9840_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
        struct v4l2_subdev *sd;
-       int result;
-       int byte;
 
        /* let's see whether this adapter can support what we need */
        if (!i2c_check_functionality(client->adapter,
@@ -227,15 +177,9 @@ static int tda9840_probe(struct i2c_client *client,
        v4l2_i2c_subdev_init(sd, client, &tda9840_ops);
 
        /* set initial values for level & stereo - adjustment, mode */
-       byte = 0;
-       result = tda9840_ioctl(sd, TDA9840_LEVEL_ADJUST, &byte);
-       result |= tda9840_ioctl(sd, TDA9840_STEREO_ADJUST, &byte);
+       tda9840_write(sd, LEVEL_ADJUST, 0);
+       tda9840_write(sd, STEREO_ADJUST, 0);
        tda9840_write(sd, SWITCH, TDA9840_SET_STEREO);
-       if (result) {
-               v4l2_dbg(1, debug, sd, "could not initialize tda9840\n");
-               kfree(sd);
-               return -ENODEV;
-       }
        return 0;
 }
 
@@ -248,12 +192,7 @@ static int tda9840_remove(struct i2c_client *client)
        return 0;
 }
 
-static int tda9840_legacy_probe(struct i2c_adapter *adapter)
-{
-       /* Let's see whether this is a known adapter we can attach to.
-          Prevents conflicts with tvaudio.c. */
-       return adapter->id == I2C_HW_SAA7146;
-}
+
 static const struct i2c_device_id tda9840_id[] = {
        { "tda9840", 0 },
        { }
@@ -262,10 +201,7 @@ MODULE_DEVICE_TABLE(i2c, tda9840_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "tda9840",
-       .driverid = I2C_DRIVERID_TDA9840,
-       .command = tda9840_command,
        .probe = tda9840_probe,
        .remove = tda9840_remove,
-       .legacy_probe = tda9840_legacy_probe,
        .id_table = tda9840_id,
 };
diff --git a/drivers/media/video/tda9840.h b/drivers/media/video/tda9840.h
deleted file mode 100644 (file)
index dc12ae7..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __INCLUDED_TDA9840__
-#define __INCLUDED_TDA9840__
-
-#define        I2C_ADDR_TDA9840                0x42
-
-/* values may range between +2.5 and -2.0;
-   the value has to be multiplied with 10 */
-#define TDA9840_LEVEL_ADJUST   _IOW('v',3,int)
-
-/* values may range between +2.5 and -2.4;
-   the value has to be multiplied with 10 */
-#define TDA9840_STEREO_ADJUST  _IOW('v',4,int)
-
-#endif
index 00c6cbe06ab0e047d7132b8cb3f699a3ee4049fe..24e2b7d2ae588410657c7ae2a4e19f18cb9f481f 100644 (file)
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/v4l2-i2c-drv.h>
 #include <media/i2c-addr.h>
 
 static int debug; /* insmod parameter */
 module_param(debug, int, S_IRUGO | S_IWUSR);
 MODULE_LICENSE("GPL");
 
-/* Addresses to scan */
-static unsigned short normal_i2c[] =  {
-    I2C_ADDR_TDA9875 >> 1,
-    I2C_CLIENT_END
-};
-
-I2C_CLIENT_INSMOD;
 
 /* This is a superset of the TDA9875 */
 struct tda9875 {
@@ -313,18 +306,14 @@ static int tda9875_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
 {
        switch (qc->id) {
        case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
        case V4L2_CID_AUDIO_BASS:
        case V4L2_CID_AUDIO_TREBLE:
-               return v4l2_ctrl_query_fill_std(qc);
+               return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
        }
        return -EINVAL;
 }
 
-static int tda9875_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops tda9875_core_ops = {
@@ -401,8 +390,6 @@ MODULE_DEVICE_TABLE(i2c, tda9875_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "tda9875",
-       .driverid = I2C_DRIVERID_TDA9875,
-       .command = tda9875_command,
        .probe = tda9875_probe,
        .remove = tda9875_remove,
        .id_table = tda9875_id,
index 7519fd1f57efbd14418b7c9993d34a0528e6ab34..d61c56f42bcd93010e96731147c6dd80ca0026c3 100644 (file)
@@ -32,7 +32,8 @@
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 #include "tea6415c.h"
 
 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
@@ -44,25 +45,22 @@ module_param(debug, int, 0644);
 
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-/* addresses to scan, found only at 0x03 and/or 0x43 (7-bit) */
-static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIENT_END };
 
-/* magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-/* makes a connection between the input-pin 'i' and the output-pin 'o'
-   for the tea6415c-client 'client' */
-static int switch_matrix(struct i2c_client *client, int i, int o)
+/* makes a connection between the input-pin 'i' and the output-pin 'o' */
+static int tea6415c_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        u8 byte = 0;
+       u32 i = route->input;
+       u32 o = route->output;
        int ret;
 
-       v4l_dbg(1, debug, client, "i=%d, o=%d\n", i, o);
+       v4l2_dbg(1, debug, sd, "i=%d, o=%d\n", i, o);
 
        /* check if the pins are valid */
        if (0 == ((1 == i ||  3 == i ||  5 == i ||  6 == i ||  8 == i || 10 == i || 20 == i || 11 == i)
              && (18 == o || 17 == o || 16 == o || 15 == o || 14 == o || 13 == o)))
-               return -1;
+               return -EINVAL;
 
        /* to understand this, have a look at the tea6415c-specs (p.5) */
        switch (o) {
@@ -115,37 +113,33 @@ static int switch_matrix(struct i2c_client *client, int i, int o)
 
        ret = i2c_smbus_write_byte(client, byte);
        if (ret) {
-               v4l_dbg(1, debug, client,
+               v4l2_dbg(1, debug, sd,
                        "i2c_smbus_write_byte() failed, ret:%d\n", ret);
                return -EIO;
        }
        return ret;
 }
 
-static long tea6415c_ioctl(struct v4l2_subdev *sd, unsigned cmd, void *arg)
+static int tea6415c_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
 {
-       if (cmd == TEA6415C_SWITCH) {
-               struct i2c_client *client = v4l2_get_subdevdata(sd);
-               struct tea6415c_multiplex *v = (struct tea6415c_multiplex *)arg;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-               return switch_matrix(client, v->in, v->out);
-       }
-       return -ENOIOCTLCMD;
-}
-
-static int tea6415c_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEA6415C, 0);
 }
 
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops tea6415c_core_ops = {
-       .ioctl = tea6415c_ioctl,
+       .g_chip_ident = tea6415c_g_chip_ident,
+};
+
+static const struct v4l2_subdev_video_ops tea6415c_video_ops = {
+       .s_routing = tea6415c_s_routing,
 };
 
 static const struct v4l2_subdev_ops tea6415c_ops = {
        .core = &tea6415c_core_ops,
+       .video = &tea6415c_video_ops,
 };
 
 /* this function is called by i2c_probe */
@@ -176,12 +170,6 @@ static int tea6415c_remove(struct i2c_client *client)
        return 0;
 }
 
-static int tea6415c_legacy_probe(struct i2c_adapter *adapter)
-{
-       /* Let's see whether this is a known adapter we can attach to.
-          Prevents conflicts with tvaudio.c. */
-       return adapter->id == I2C_HW_SAA7146;
-}
 
 static const struct i2c_device_id tea6415c_id[] = {
        { "tea6415c", 0 },
@@ -191,10 +179,7 @@ MODULE_DEVICE_TABLE(i2c, tea6415c_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "tea6415c",
-       .driverid = I2C_DRIVERID_TEA6415C,
-       .command = tea6415c_command,
        .probe = tea6415c_probe,
        .remove = tea6415c_remove,
-       .legacy_probe = tea6415c_legacy_probe,
        .id_table = tea6415c_id,
 };
index f84ed80050b34c6ac6e27bcc1cbc982432912ea3..3a47d697536ea24d3167b81e01333555bb089e91 100644 (file)
@@ -1,10 +1,6 @@
 #ifndef __INCLUDED_TEA6415C__
 #define __INCLUDED_TEA6415C__
 
-/* possible i2c-addresses */
-#define        I2C_TEA6415C_1          0x03
-#define        I2C_TEA6415C_2          0x43
-
 /* the tea6415c's design is quite brain-dead. although there are
    8 inputs and 6 outputs, these aren't enumerated in any way. because
    I don't want to say "connect input pin 20 to output pin 17", I define
 #define TEA6415C_INPUT7 1
 #define TEA6415C_INPUT8 11
 
-struct tea6415c_multiplex
-{
-       int     in;     /* input-pin */
-       int     out;    /* output-pin */
-};
-
-#define TEA6415C_SWITCH                _IOW('v',1,struct tea6415c_multiplex)
-
 #endif
index 081e74fa3b2eb2360dc68c1a0cdac0564548a0d2..34922232402af32e72dc4cc672bd15bd80816605 100644 (file)
@@ -32,7 +32,8 @@
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 #include "tea6420.h"
 
 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
@@ -44,24 +45,23 @@ module_param(debug, int, 0644);
 
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-/* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */
-static unsigned short normal_i2c[] = { I2C_ADDR_TEA6420_1, I2C_ADDR_TEA6420_2, I2C_CLIENT_END };
-
-/* magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
 
 /* make a connection between the input 'i' and the output 'o'
-   with gain 'g' for the tea6420-client 'client' (note: i = 6 means 'mute') */
-static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
+   with gain 'g' (note: i = 6 means 'mute') */
+static int tea6420_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int i = route->input;
+       int o = route->output & 0xf;
+       int g = (route->output >> 4) & 0xf;
        u8 byte;
        int ret;
 
-       v4l_dbg(1, debug, client, "i=%d, o=%d, g=%d\n", i, o, g);
+       v4l2_dbg(1, debug, sd, "i=%d, o=%d, g=%d\n", i, o, g);
 
        /* check if the parameters are valid */
        if (i < 1 || i > 6 || o < 1 || o > 4 || g < 0 || g > 6 || g % 2 != 0)
-               return -1;
+               return -EINVAL;
 
        byte = ((o - 1) << 5);
        byte |= (i - 1);
@@ -83,37 +83,33 @@ static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
 
        ret = i2c_smbus_write_byte(client, byte);
        if (ret) {
-               v4l_dbg(1, debug, client,
+               v4l2_dbg(1, debug, sd,
                        "i2c_smbus_write_byte() failed, ret:%d\n", ret);
                return -EIO;
        }
        return 0;
 }
 
-static long tea6420_ioctl(struct v4l2_subdev *sd, unsigned cmd, void *arg)
+static int tea6420_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
 {
-       if (cmd == TEA6420_SWITCH) {
-               struct i2c_client *client = v4l2_get_subdevdata(sd);
-               struct tea6420_multiplex *a = (struct tea6420_multiplex *)arg;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-               return tea6420_switch(client, a->in, a->out, a->gain);
-       }
-       return -ENOIOCTLCMD;
-}
-
-static int tea6420_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEA6420, 0);
 }
 
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops tea6420_core_ops = {
-       .ioctl = tea6420_ioctl,
+       .g_chip_ident = tea6420_g_chip_ident,
+};
+
+static const struct v4l2_subdev_audio_ops tea6420_audio_ops = {
+       .s_routing = tea6420_s_routing,
 };
 
 static const struct v4l2_subdev_ops tea6420_ops = {
        .core = &tea6420_core_ops,
+       .audio = &tea6420_audio_ops,
 };
 
 /* this function is called by i2c_probe */
@@ -130,20 +126,24 @@ static int tea6420_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
+       sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       if (sd == NULL)
+               return -ENOMEM;
+       v4l2_i2c_subdev_init(sd, client, &tea6420_ops);
+
        /* set initial values: set "mute"-input to all outputs at gain 0 */
        err = 0;
        for (i = 1; i < 5; i++) {
-               err += tea6420_switch(client, 6, i, 0);
+               struct v4l2_routing route;
+
+               route.input = 6;
+               route.output = i;
+               err += tea6420_s_routing(sd, &route);
        }
        if (err) {
                v4l_dbg(1, debug, client, "could not initialize tea6420\n");
                return -ENODEV;
        }
-
-       sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
-       if (sd == NULL)
-               return -ENOMEM;
-       v4l2_i2c_subdev_init(sd, client, &tea6420_ops);
        return 0;
 }
 
@@ -156,12 +156,6 @@ static int tea6420_remove(struct i2c_client *client)
        return 0;
 }
 
-static int tea6420_legacy_probe(struct i2c_adapter *adapter)
-{
-       /* Let's see whether this is a known adapter we can attach to.
-          Prevents conflicts with tvaudio.c. */
-       return adapter->id == I2C_HW_SAA7146;
-}
 
 static const struct i2c_device_id tea6420_id[] = {
        { "tea6420", 0 },
@@ -171,10 +165,7 @@ MODULE_DEVICE_TABLE(i2c, tea6420_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "tea6420",
-       .driverid = I2C_DRIVERID_TEA6420,
-       .command = tea6420_command,
        .probe = tea6420_probe,
        .remove = tea6420_remove,
-       .legacy_probe = tea6420_legacy_probe,
        .id_table = tea6420_id,
 };
index 5ef7c18e0c5404e08d0a4a840f050b15db33c6e6..4aa3edb3e1930c8c6ef3f5ea789eabfbeca93eaf 100644 (file)
@@ -1,17 +1,24 @@
 #ifndef __INCLUDED_TEA6420__
 #define __INCLUDED_TEA6420__
 
-/* possible addresses */
-#define        I2C_ADDR_TEA6420_1              0x4c
-#define        I2C_ADDR_TEA6420_2              0x4d
+/* input pins */
+#define TEA6420_OUTPUT1 1
+#define TEA6420_OUTPUT2 2
+#define TEA6420_OUTPUT3 3
+#define TEA6420_OUTPUT4 4
 
-struct tea6420_multiplex
-{
-       int     in;     /* input of audio switch */
-       int     out;    /* output of audio switch  */
-       int     gain;   /* gain of connection */
-};
+/* output pins */
+#define TEA6420_INPUT1 1
+#define TEA6420_INPUT2 2
+#define TEA6420_INPUT3 3
+#define TEA6420_INPUT4 4
+#define TEA6420_INPUT5 5
+#define TEA6420_INPUT6 6
 
-#define TEA6420_SWITCH         _IOW('v',1,struct tea6420_multiplex)
+/* gain on the output pins, ORed with the output pin */
+#define TEA6420_GAIN0 0x00
+#define TEA6420_GAIN2 0x20
+#define TEA6420_GAIN4 0x40
+#define TEA6420_GAIN6 0x60
 
 #endif
index 5c95ecd09dc2bbaff772073c8d2f650739868faf..07789c64814cf4d133da0b83b84090a730c54721 100644 (file)
 #include <linux/i2c-id.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("tlv320aic23b driver");
 MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
 MODULE_LICENSE("GPL");
 
-static unsigned short normal_i2c[] = { 0x34 >> 1, I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
 
 /* ----------------------------------------------------------------------- */
 
@@ -121,11 +118,6 @@ static int tlv320aic23b_log_status(struct v4l2_subdev *sd)
        return 0;
 }
 
-static int tlv320aic23b_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops tlv320aic23b_core_ops = {
@@ -208,8 +200,6 @@ MODULE_DEVICE_TABLE(i2c, tlv320aic23b_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "tlv320aic23b",
-       .driverid = I2C_DRIVERID_TLV320AIC23B,
-       .command = tlv320aic23b_command,
        .probe = tlv320aic23b_probe,
        .remove = tlv320aic23b_remove,
        .id_table = tlv320aic23b_id,
index 30640fbfd0f921ad0734eb939a533bfea1e7fc0e..72d41032742dd003e51abf923798d83fe838f65a 100644 (file)
@@ -364,7 +364,8 @@ static void set_type(struct i2c_client *c, unsigned int type,
        }
 
        t->type = type;
-       t->config = new_config;
+       /* prevent invalid config values */
+       t->config = ((new_config >= 0) && (new_config < 256)) ? new_config : 0;
        if (tuner_callback != NULL) {
                tuner_dbg("defining GPIO callback\n");
                t->fe.callback = tuner_callback;
@@ -452,7 +453,8 @@ static void set_type(struct i2c_client *c, unsigned int type,
                struct dvb_tuner_ops *xc_tuner_ops;
 
                xc5000_cfg.i2c_address    = t->i2c->addr;
-               xc5000_cfg.if_khz         = 5380;
+               /* if_khz will be set when the digital dvb_attach() occurs */
+               xc5000_cfg.if_khz         = 0;
                if (!dvb_attach(xc5000_attach,
                                &t->fe, t->i2c->adapter, &xc5000_cfg))
                        goto attach_failed;
@@ -776,8 +778,7 @@ static int tuner_s_radio(struct v4l2_subdev *sd)
        struct tuner *t = to_tuner(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
-                       == -EINVAL)
+       if (set_mode(client, t, V4L2_TUNER_RADIO, "s_radio") == -EINVAL)
                return 0;
        if (t->radio_freq)
                set_freq(client, t->radio_freq);
@@ -791,7 +792,7 @@ static int tuner_s_standby(struct v4l2_subdev *sd, u32 standby)
 
        tuner_dbg("Putting tuner to sleep\n");
 
-       if (check_mode(t, "TUNER_SET_STANDBY") == -EINVAL)
+       if (check_mode(t, "s_standby") == -EINVAL)
                return 0;
        t->mode = T_STANDBY;
        if (analog_ops->standby)
@@ -799,132 +800,6 @@ static int tuner_s_standby(struct v4l2_subdev *sd, u32 standby)
        return 0;
 }
 
-#ifdef CONFIG_VIDEO_ALLOW_V4L1
-static long tuner_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
-       struct tuner *t = to_tuner(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
-       struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
-
-       switch (cmd) {
-       case VIDIOCSAUDIO:
-               if (check_mode(t, "VIDIOCSAUDIO") == -EINVAL)
-                       return 0;
-               if (check_v4l2(t) == -EINVAL)
-                       return 0;
-
-               /* Should be implemented, since bttv calls it */
-               tuner_dbg("VIDIOCSAUDIO not implemented.\n");
-               break;
-       case VIDIOCSCHAN:
-               {
-                       static const v4l2_std_id map[] = {
-                               [VIDEO_MODE_PAL] = V4L2_STD_PAL,
-                               [VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M,
-                               [VIDEO_MODE_SECAM] = V4L2_STD_SECAM,
-                               [4 /* bttv */ ] = V4L2_STD_PAL_M,
-                               [5 /* bttv */ ] = V4L2_STD_PAL_N,
-                               [6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
-                       };
-                       struct video_channel *vc = arg;
-
-                       if (check_v4l2(t) == -EINVAL)
-                               return 0;
-
-                       if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==-EINVAL)
-                               return 0;
-
-                       if (vc->norm < ARRAY_SIZE(map))
-                               t->std = map[vc->norm];
-                       tuner_fixup_std(t);
-                       if (t->tv_freq)
-                               set_tv_freq(client, t->tv_freq);
-                       return 0;
-               }
-       case VIDIOCSFREQ:
-               {
-                       unsigned long *v = arg;
-
-                       if (check_mode(t, "VIDIOCSFREQ") == -EINVAL)
-                               return 0;
-                       if (check_v4l2(t) == -EINVAL)
-                               return 0;
-
-                       set_freq(client, *v);
-                       return 0;
-               }
-       case VIDIOCGTUNER:
-               {
-                       struct video_tuner *vt = arg;
-
-                       if (check_mode(t, "VIDIOCGTUNER") == -EINVAL)
-                               return 0;
-                       if (check_v4l2(t) == -EINVAL)
-                               return 0;
-
-                       if (V4L2_TUNER_RADIO == t->mode) {
-                               if (fe_tuner_ops->get_status) {
-                                       u32 tuner_status;
-
-                                       fe_tuner_ops->get_status(&t->fe, &tuner_status);
-                                       if (tuner_status & TUNER_STATUS_STEREO)
-                                               vt->flags |= VIDEO_TUNER_STEREO_ON;
-                                       else
-                                               vt->flags &= ~VIDEO_TUNER_STEREO_ON;
-                               } else {
-                                       if (analog_ops->is_stereo) {
-                                               if (analog_ops->is_stereo(&t->fe))
-                                                       vt->flags |=
-                                                               VIDEO_TUNER_STEREO_ON;
-                                               else
-                                                       vt->flags &=
-                                                               ~VIDEO_TUNER_STEREO_ON;
-                                       }
-                               }
-                               if (analog_ops->has_signal)
-                                       vt->signal =
-                                               analog_ops->has_signal(&t->fe);
-
-                               vt->flags |= VIDEO_TUNER_LOW;   /* Allow freqs at 62.5 Hz */
-
-                               vt->rangelow = radio_range[0] * 16000;
-                               vt->rangehigh = radio_range[1] * 16000;
-
-                       } else {
-                               vt->rangelow = tv_range[0] * 16;
-                               vt->rangehigh = tv_range[1] * 16;
-                       }
-
-                       return 0;
-               }
-       case VIDIOCGAUDIO:
-               {
-                       struct video_audio *va = arg;
-
-                       if (check_mode(t, "VIDIOCGAUDIO") == -EINVAL)
-                               return 0;
-                       if (check_v4l2(t) == -EINVAL)
-                               return 0;
-
-                       if (V4L2_TUNER_RADIO == t->mode) {
-                               if (fe_tuner_ops->get_status) {
-                                       u32 tuner_status;
-
-                                       fe_tuner_ops->get_status(&t->fe, &tuner_status);
-                                       va->mode = (tuner_status & TUNER_STATUS_STEREO)
-                                           ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
-                               } else if (analog_ops->is_stereo)
-                                       va->mode = analog_ops->is_stereo(&t->fe)
-                                           ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
-                       }
-                       return 0;
-               }
-       }
-       return -ENOIOCTLCMD;
-}
-#endif
-
 static int tuner_s_config(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *cfg)
 {
        struct tuner *t = to_tuner(sd);
@@ -950,8 +825,7 @@ static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
        struct tuner *t = to_tuner(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (set_mode(client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
-                       == -EINVAL)
+       if (set_mode(client, t, V4L2_TUNER_ANALOG_TV, "s_std") == -EINVAL)
                return 0;
 
        switch_v4l2();
@@ -968,8 +842,7 @@ static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
        struct tuner *t = to_tuner(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (set_mode(client, t, f->type, "VIDIOC_S_FREQUENCY")
-                       == -EINVAL)
+       if (set_mode(client, t, f->type, "s_frequency") == -EINVAL)
                return 0;
        switch_v4l2();
        set_freq(client, f->frequency);
@@ -982,7 +855,7 @@ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
        struct tuner *t = to_tuner(sd);
        struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
 
-       if (check_mode(t, "VIDIOC_G_FREQUENCY") == -EINVAL)
+       if (check_mode(t, "g_frequency") == -EINVAL)
                return 0;
        switch_v4l2();
        f->type = t->mode;
@@ -1006,7 +879,7 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
        struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
        struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
 
-       if (check_mode(t, "VIDIOC_G_TUNER") == -EINVAL)
+       if (check_mode(t, "g_tuner") == -EINVAL)
                return 0;
        switch_v4l2();
 
@@ -1055,7 +928,7 @@ static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
        struct tuner *t = to_tuner(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (check_mode(t, "VIDIOC_S_TUNER") == -EINVAL)
+       if (check_mode(t, "s_tuner") == -EINVAL)
                return 0;
 
        switch_v4l2();
@@ -1112,9 +985,6 @@ static int tuner_resume(struct i2c_client *c)
 static const struct v4l2_subdev_core_ops tuner_core_ops = {
        .log_status = tuner_log_status,
        .s_standby = tuner_s_standby,
-#ifdef CONFIG_VIDEO_ALLOW_V4L1
-       .ioctl = tuner_ioctl,
-#endif
 };
 
 static const struct v4l2_subdev_tuner_ops tuner_tuner_ops = {
index 076ed5bf48b1d88e24a6f4f7d321f4aef164070e..226bf3565ac96eddf81c33182d715e878ca1fe8d 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/kthread.h>
@@ -1047,6 +1047,116 @@ static int tda9874a_initialize(struct CHIPSTATE *chip)
        return 0;
 }
 
+/* ---------------------------------------------------------------------- */
+/* audio chip description - defines+functions for tda9875                 */
+/* The TDA9875 is made by Philips Semiconductor
+ * http://www.semiconductors.philips.com
+ * TDA9875: I2C-bus controlled DSP audio processor, FM demodulator
+ *
+ */
+
+/* subaddresses for TDA9875 */
+#define TDA9875_MUT         0x12  /*General mute  (value --> 0b11001100*/
+#define TDA9875_CFG         0x01  /* Config register (value --> 0b00000000 */
+#define TDA9875_DACOS       0x13  /*DAC i/o select (ADC) 0b0000100*/
+#define TDA9875_LOSR        0x16  /*Line output select regirter 0b0100 0001*/
+
+#define TDA9875_CH1V        0x0c  /*Channel 1 volume (mute)*/
+#define TDA9875_CH2V        0x0d  /*Channel 2 volume (mute)*/
+#define TDA9875_SC1         0x14  /*SCART 1 in (mono)*/
+#define TDA9875_SC2         0x15  /*SCART 2 in (mono)*/
+
+#define TDA9875_ADCIS       0x17  /*ADC input select (mono) 0b0110 000*/
+#define TDA9875_AER         0x19  /*Audio effect (AVL+Pseudo) 0b0000 0110*/
+#define TDA9875_MCS         0x18  /*Main channel select (DAC) 0b0000100*/
+#define TDA9875_MVL         0x1a  /* Main volume gauche */
+#define TDA9875_MVR         0x1b  /* Main volume droite */
+#define TDA9875_MBA         0x1d  /* Main Basse */
+#define TDA9875_MTR         0x1e  /* Main treble */
+#define TDA9875_ACS         0x1f  /* Auxilary channel select (FM) 0b0000000*/
+#define TDA9875_AVL         0x20  /* Auxilary volume gauche */
+#define TDA9875_AVR         0x21  /* Auxilary volume droite */
+#define TDA9875_ABA         0x22  /* Auxilary Basse */
+#define TDA9875_ATR         0x23  /* Auxilary treble */
+
+#define TDA9875_MSR         0x02  /* Monitor select register */
+#define TDA9875_C1MSB       0x03  /* Carrier 1 (FM) frequency register MSB */
+#define TDA9875_C1MIB       0x04  /* Carrier 1 (FM) frequency register (16-8]b */
+#define TDA9875_C1LSB       0x05  /* Carrier 1 (FM) frequency register LSB */
+#define TDA9875_C2MSB       0x06  /* Carrier 2 (nicam) frequency register MSB */
+#define TDA9875_C2MIB       0x07  /* Carrier 2 (nicam) frequency register (16-8]b */
+#define TDA9875_C2LSB       0x08  /* Carrier 2 (nicam) frequency register LSB */
+#define TDA9875_DCR         0x09  /* Demodulateur configuration regirter*/
+#define TDA9875_DEEM        0x0a  /* FM de-emphasis regirter*/
+#define TDA9875_FMAT        0x0b  /* FM Matrix regirter*/
+
+/* values */
+#define TDA9875_MUTE_ON            0xff /* general mute */
+#define TDA9875_MUTE_OFF    0xcc /* general no mute */
+
+static int tda9875_initialize(struct CHIPSTATE *chip)
+{
+       chip_write(chip, TDA9875_CFG, 0xd0); /*reg de config 0 (reset)*/
+       chip_write(chip, TDA9875_MSR, 0x03);    /* Monitor 0b00000XXX*/
+       chip_write(chip, TDA9875_C1MSB, 0x00);  /*Car1(FM) MSB XMHz*/
+       chip_write(chip, TDA9875_C1MIB, 0x00);  /*Car1(FM) MIB XMHz*/
+       chip_write(chip, TDA9875_C1LSB, 0x00);  /*Car1(FM) LSB XMHz*/
+       chip_write(chip, TDA9875_C2MSB, 0x00);  /*Car2(NICAM) MSB XMHz*/
+       chip_write(chip, TDA9875_C2MIB, 0x00);  /*Car2(NICAM) MIB XMHz*/
+       chip_write(chip, TDA9875_C2LSB, 0x00);  /*Car2(NICAM) LSB XMHz*/
+       chip_write(chip, TDA9875_DCR, 0x00);    /*Demod config 0x00*/
+       chip_write(chip, TDA9875_DEEM, 0x44);   /*DE-Emph 0b0100 0100*/
+       chip_write(chip, TDA9875_FMAT, 0x00);   /*FM Matrix reg 0x00*/
+       chip_write(chip, TDA9875_SC1, 0x00);    /* SCART 1 (SC1)*/
+       chip_write(chip, TDA9875_SC2, 0x01);    /* SCART 2 (sc2)*/
+
+       chip_write(chip, TDA9875_CH1V, 0x10);  /* Channel volume 1 mute*/
+       chip_write(chip, TDA9875_CH2V, 0x10);  /* Channel volume 2 mute */
+       chip_write(chip, TDA9875_DACOS, 0x02); /* sig DAC i/o(in:nicam)*/
+       chip_write(chip, TDA9875_ADCIS, 0x6f); /* sig ADC input(in:mono)*/
+       chip_write(chip, TDA9875_LOSR, 0x00);  /* line out (in:mono)*/
+       chip_write(chip, TDA9875_AER, 0x00);   /*06 Effect (AVL+PSEUDO) */
+       chip_write(chip, TDA9875_MCS, 0x44);   /* Main ch select (DAC) */
+       chip_write(chip, TDA9875_MVL, 0x03);   /* Vol Main left 10dB */
+       chip_write(chip, TDA9875_MVR, 0x03);   /* Vol Main right 10dB*/
+       chip_write(chip, TDA9875_MBA, 0x00);   /* Main Bass Main 0dB*/
+       chip_write(chip, TDA9875_MTR, 0x00);   /* Main Treble Main 0dB*/
+       chip_write(chip, TDA9875_ACS, 0x44);   /* Aux chan select (dac)*/
+       chip_write(chip, TDA9875_AVL, 0x00);   /* Vol Aux left 0dB*/
+       chip_write(chip, TDA9875_AVR, 0x00);   /* Vol Aux right 0dB*/
+       chip_write(chip, TDA9875_ABA, 0x00);   /* Aux Bass Main 0dB*/
+       chip_write(chip, TDA9875_ATR, 0x00);   /* Aux Aigus Main 0dB*/
+
+       chip_write(chip, TDA9875_MUT, 0xcc);   /* General mute  */
+       return 0;
+}
+
+static int tda9875_volume(int val) { return (unsigned char)(val / 602 - 84); }
+static int tda9875_bass(int val) { return (unsigned char)(max(-12, val / 2115 - 15)); }
+static int tda9875_treble(int val) { return (unsigned char)(val / 2622 - 12); }
+
+/* ----------------------------------------------------------------------- */
+
+
+/* *********************** *
+ * i2c interface functions *
+ * *********************** */
+
+static int tda9875_checkit(struct CHIPSTATE *chip)
+{
+       struct v4l2_subdev *sd = &chip->sd;
+       int dic, rev;
+
+       dic = chip_read2(chip, 254);
+       rev = chip_read2(chip, 255);
+
+       if (dic == 0 || dic == 2) { /* tda9875 and tda9875A */
+               v4l2_info(sd, "found tda9875%s rev. %d.\n",
+                       dic == 0 ? "" : "A", rev);
+               return 1;
+       }
+       return 0;
+}
 
 /* ---------------------------------------------------------------------- */
 /* audio chip descriptions - defines+functions for tea6420                */
@@ -1280,6 +1390,7 @@ static int tda9850  = 1;
 static int tda9855  = 1;
 static int tda9873  = 1;
 static int tda9874a = 1;
+static int tda9875  = 1;
 static int tea6300;    /* default 0 - address clash with msp34xx */
 static int tea6320;    /* default 0 - address clash with msp34xx */
 static int tea6420  = 1;
@@ -1292,6 +1403,7 @@ module_param(tda9850, int, 0444);
 module_param(tda9855, int, 0444);
 module_param(tda9873, int, 0444);
 module_param(tda9874a, int, 0444);
+module_param(tda9875, int, 0444);
 module_param(tea6300, int, 0444);
 module_param(tea6320, int, 0444);
 module_param(tea6420, int, 0444);
@@ -1348,6 +1460,26 @@ static struct CHIPDESC chiplist[] = {
                .getmode    = tda9874a_getmode,
                .setmode    = tda9874a_setmode,
        },
+       {
+               .name       = "tda9875",
+               .insmodopt  = &tda9875,
+               .addr_lo    = I2C_ADDR_TDA9875 >> 1,
+               .addr_hi    = I2C_ADDR_TDA9875 >> 1,
+               .flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
+
+               /* callbacks */
+               .initialize = tda9875_initialize,
+               .checkit    = tda9875_checkit,
+               .volfunc    = tda9875_volume,
+               .bassfunc   = tda9875_bass,
+               .treblefunc = tda9875_treble,
+               .leftreg    = TDA9875_MVL,
+               .rightreg   = TDA9875_MVR,
+               .bassreg    = TDA9875_MBA,
+               .treblereg  = TDA9875_MTR,
+               .leftinit   = 58880,
+               .rightinit  = 58880,
+       },
        {
                .name       = "tda9850",
                .insmodopt  = &tda9850,
@@ -1511,6 +1643,8 @@ static int tvaudio_g_ctrl(struct v4l2_subdev *sd,
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
+               if (!(desc->flags & CHIP_HAS_INPUTSEL))
+                       break;
                ctrl->value=chip->muted;
                return 0;
        case V4L2_CID_AUDIO_VOLUME:
@@ -1552,6 +1686,9 @@ static int tvaudio_s_ctrl(struct v4l2_subdev *sd,
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
+               if (!(desc->flags & CHIP_HAS_INPUTSEL))
+                       break;
+
                if (ctrl->value < 0 || ctrl->value >= 2)
                        return -ERANGE;
                chip->muted = ctrl->value;
@@ -1636,21 +1773,26 @@ static int tvaudio_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
 
        switch (qc->id) {
        case V4L2_CID_AUDIO_MUTE:
+               if (desc->flags & CHIP_HAS_INPUTSEL)
+                       return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
                break;
        case V4L2_CID_AUDIO_VOLUME:
+               if (desc->flags & CHIP_HAS_VOLUME)
+                       return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
+               break;
        case V4L2_CID_AUDIO_BALANCE:
-               if (!(desc->flags & CHIP_HAS_VOLUME))
-                       return -EINVAL;
+               if (desc->flags & CHIP_HAS_VOLUME)
+                       return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
                break;
        case V4L2_CID_AUDIO_BASS:
        case V4L2_CID_AUDIO_TREBLE:
-               if (!(desc->flags & CHIP_HAS_BASSTREBLE))
-                       return -EINVAL;
+               if (desc->flags & CHIP_HAS_BASSTREBLE)
+                       return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
                break;
        default:
-               return -EINVAL;
+               break;
        }
-       return v4l2_ctrl_query_fill_std(qc);
+       return -EINVAL;
 }
 
 static int tvaudio_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *rt)
@@ -1658,7 +1800,9 @@ static int tvaudio_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *
        struct CHIPSTATE *chip = to_state(sd);
        struct CHIPDESC *desc = chip->desc;
 
-       if (!(desc->flags & CHIP_HAS_INPUTSEL) || rt->input >= 4)
+       if (!(desc->flags & CHIP_HAS_INPUTSEL))
+               return 0;
+       if (rt->input >= 4)
                return -EINVAL;
        /* There are four inputs: tuner, radio, extern and intern. */
        chip->input = rt->input;
@@ -1675,8 +1819,11 @@ static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
        struct CHIPDESC *desc = chip->desc;
        int mode = 0;
 
+       if (!desc->setmode)
+               return 0;
        if (chip->radio)
                return 0;
+
        switch (vt->audmode) {
        case V4L2_TUNER_MODE_MONO:
        case V4L2_TUNER_MODE_STEREO:
@@ -1692,7 +1839,7 @@ static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
        }
        chip->audmode = vt->audmode;
 
-       if (desc->setmode && mode) {
+       if (mode) {
                chip->watch_stereo = 0;
                /* del_timer(&chip->wt); */
                chip->mode = mode;
@@ -1707,15 +1854,17 @@ static int tvaudio_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
        struct CHIPDESC *desc = chip->desc;
        int mode = V4L2_TUNER_MODE_MONO;
 
+       if (!desc->getmode)
+               return 0;
        if (chip->radio)
                return 0;
+
        vt->audmode = chip->audmode;
        vt->rxsubchans = 0;
        vt->capability = V4L2_TUNER_CAP_STEREO |
                V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
 
-       if (desc->getmode)
-               mode = desc->getmode(chip);
+       mode = desc->getmode(chip);
 
        if (mode & V4L2_TUNER_MODE_MONO)
                vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
@@ -1901,6 +2050,7 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
        }
 
        chip->thread = NULL;
+       init_timer(&chip->wt);
        if (desc->flags & CHIP_NEED_CHECKMODE) {
                if (!desc->getmode || !desc->setmode) {
                        /* This shouldn't be happen. Warn user, but keep working
@@ -1910,7 +2060,6 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
                        return 0;
                }
                /* start async thread */
-               init_timer(&chip->wt);
                chip->wt.function = chip_thread_wake;
                chip->wt.data     = (unsigned long)chip;
                chip->thread = kthread_run(chip_thread, chip, client->name);
index 78277abb733be27074074e671e9abfaad7ffb169..e24a38c7fa46320dac823bcb2778846db2f3e210 100644 (file)
@@ -261,7 +261,12 @@ hauppauge_tuner[] =
        { TUNER_ABSENT,                 "MaxLinear MXL5005_v2"},
        { TUNER_PHILIPS_TDA8290,        "Philips 18271_8295"},
        /* 150-159 */
-       { TUNER_ABSENT,                 "Xceive XC5000"},
+       { TUNER_XC5000,                 "Xceive XC5000"},
+       { TUNER_ABSENT,                 "Xceive XC3028L"},
+       { TUNER_ABSENT,                 "NXP 18271C2_716x"},
+       { TUNER_ABSENT,                 "Xceive XC4000"},
+       { TUNER_ABSENT,                 "Dibcom 7070"},
+       { TUNER_PHILIPS_TDA8290,        "NXP 18271C2"},
 };
 
 /* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are
index 8e23aa53c29ac7e06ac54c646fb5a97397a663d0..4262e60b8116a3df1fb161ae49fa44bc0c3ae037 100644 (file)
@@ -86,9 +86,12 @@ struct tvp514x_std_info {
        struct v4l2_standard standard;
 };
 
+static struct tvp514x_reg tvp514x_reg_list_default[0x40];
 /**
- * struct tvp514x_decoded - TVP5146/47 decoder object
+ * struct tvp514x_decoder - TVP5146/47 decoder object
  * @v4l2_int_device: Slave handle
+ * @tvp514x_slave: Slave pointer which is used by @v4l2_int_device
+ * @tvp514x_regs: copy of hw's regs with preset values.
  * @pdata: Board specific
  * @client: I2C client data
  * @id: Entry from I2C table
@@ -103,7 +106,9 @@ struct tvp514x_std_info {
  * @route: input and output routing at chip level
  */
 struct tvp514x_decoder {
-       struct v4l2_int_device *v4l2_int_device;
+       struct v4l2_int_device v4l2_int_device;
+       struct v4l2_int_slave tvp514x_slave;
+       struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)];
        const struct tvp514x_platform_data *pdata;
        struct i2c_client *client;
 
@@ -124,7 +129,7 @@ struct tvp514x_decoder {
 };
 
 /* TVP514x default register values */
-static struct tvp514x_reg tvp514x_reg_list[] = {
+static struct tvp514x_reg tvp514x_reg_list_default[] = {
        {TOK_WRITE, REG_INPUT_SEL, 0x05},       /* Composite selected */
        {TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F},
        {TOK_WRITE, REG_VIDEO_STD, 0x00},       /* Auto mode */
@@ -422,7 +427,7 @@ static int tvp514x_configure(struct tvp514x_decoder *decoder)
 
        /* common register initialization */
        err =
-           tvp514x_write_regs(decoder->client, tvp514x_reg_list);
+           tvp514x_write_regs(decoder->client, decoder->tvp514x_regs);
        if (err)
                return err;
 
@@ -580,7 +585,8 @@ static int ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id *std_id)
                return err;
 
        decoder->current_std = i;
-       tvp514x_reg_list[REG_VIDEO_STD].val = decoder->std_list[i].video_std;
+       decoder->tvp514x_regs[REG_VIDEO_STD].val =
+               decoder->std_list[i].video_std;
 
        v4l_dbg(1, debug, decoder->client, "Standard set to: %s",
                        decoder->std_list[i].standard.name);
@@ -625,8 +631,8 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
        if (err)
                return err;
 
-       tvp514x_reg_list[REG_INPUT_SEL].val = input_sel;
-       tvp514x_reg_list[REG_OUTPUT_FORMATTER1].val = output_sel;
+       decoder->tvp514x_regs[REG_INPUT_SEL].val = input_sel;
+       decoder->tvp514x_regs[REG_OUTPUT_FORMATTER1].val = output_sel;
 
        /* Clear status */
        msleep(LOCK_RETRY_DELAY);
@@ -686,7 +692,7 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
                        break;  /* Input detected */
        }
 
-       if ((current_std == STD_INVALID) || (try_count < 0))
+       if ((current_std == STD_INVALID) || (try_count <= 0))
                return -EINVAL;
 
        decoder->current_std = current_std;
@@ -719,10 +725,9 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
 
        switch (qctrl->id) {
        case V4L2_CID_BRIGHTNESS:
-               /* Brightness supported is same as standard one (0-255),
-                * so make use of standard API provided.
+               /* Brightness supported is (0-255),
                 */
-               err = v4l2_ctrl_query_fill_std(qctrl);
+               err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
                break;
        case V4L2_CID_CONTRAST:
        case V4L2_CID_SATURATION:
@@ -779,16 +784,16 @@ ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
-               ctrl->value = tvp514x_reg_list[REG_BRIGHTNESS].val;
+               ctrl->value = decoder->tvp514x_regs[REG_BRIGHTNESS].val;
                break;
        case V4L2_CID_CONTRAST:
-               ctrl->value = tvp514x_reg_list[REG_CONTRAST].val;
+               ctrl->value = decoder->tvp514x_regs[REG_CONTRAST].val;
                break;
        case V4L2_CID_SATURATION:
-               ctrl->value = tvp514x_reg_list[REG_SATURATION].val;
+               ctrl->value = decoder->tvp514x_regs[REG_SATURATION].val;
                break;
        case V4L2_CID_HUE:
-               ctrl->value = tvp514x_reg_list[REG_HUE].val;
+               ctrl->value = decoder->tvp514x_regs[REG_HUE].val;
                if (ctrl->value == 0x7F)
                        ctrl->value = 180;
                else if (ctrl->value == 0x80)
@@ -798,7 +803,7 @@ ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
 
                break;
        case V4L2_CID_AUTOGAIN:
-               ctrl->value = tvp514x_reg_list[REG_AFE_GAIN_CTRL].val;
+               ctrl->value = decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val;
                if ((ctrl->value & 0x3) == 3)
                        ctrl->value = 1;
                else
@@ -848,7 +853,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
                                value);
                if (err)
                        return err;
-               tvp514x_reg_list[REG_BRIGHTNESS].val = value;
+               decoder->tvp514x_regs[REG_BRIGHTNESS].val = value;
                break;
        case V4L2_CID_CONTRAST:
                if (ctrl->value < 0 || ctrl->value > 255) {
@@ -861,7 +866,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
                                value);
                if (err)
                        return err;
-               tvp514x_reg_list[REG_CONTRAST].val = value;
+               decoder->tvp514x_regs[REG_CONTRAST].val = value;
                break;
        case V4L2_CID_SATURATION:
                if (ctrl->value < 0 || ctrl->value > 255) {
@@ -874,7 +879,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
                                value);
                if (err)
                        return err;
-               tvp514x_reg_list[REG_SATURATION].val = value;
+               decoder->tvp514x_regs[REG_SATURATION].val = value;
                break;
        case V4L2_CID_HUE:
                if (value == 180)
@@ -893,7 +898,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
                                value);
                if (err)
                        return err;
-               tvp514x_reg_list[REG_HUE].val = value;
+               decoder->tvp514x_regs[REG_HUE].val = value;
                break;
        case V4L2_CID_AUTOGAIN:
                if (value == 1)
@@ -910,7 +915,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
                                value);
                if (err)
                        return err;
-               tvp514x_reg_list[REG_AFE_GAIN_CTRL].val = value;
+               decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value;
                break;
        default:
                v4l_err(decoder->client,
@@ -1275,7 +1280,7 @@ static int ioctl_init(struct v4l2_int_device *s)
        struct tvp514x_decoder *decoder = s->priv;
 
        /* Set default standard to auto */
-       tvp514x_reg_list[REG_VIDEO_STD].val =
+       decoder->tvp514x_regs[REG_VIDEO_STD].val =
            VIDEO_STD_AUTO_SWITCH_BIT;
 
        return tvp514x_configure(decoder);
@@ -1344,11 +1349,6 @@ static struct v4l2_int_ioctl_desc tvp514x_ioctl_desc[] = {
                (v4l2_int_ioctl_func *) ioctl_s_routing},
 };
 
-static struct v4l2_int_slave tvp514x_slave = {
-       .ioctls = tvp514x_ioctl_desc,
-       .num_ioctls = ARRAY_SIZE(tvp514x_ioctl_desc),
-};
-
 static struct tvp514x_decoder tvp514x_dev = {
        .state = STATE_NOT_DETECTED,
 
@@ -1369,17 +1369,15 @@ static struct tvp514x_decoder tvp514x_dev = {
        .current_std = STD_NTSC_MJ,
        .std_list = tvp514x_std_list,
        .num_stds = ARRAY_SIZE(tvp514x_std_list),
-
-};
-
-static struct v4l2_int_device tvp514x_int_device = {
-       .module = THIS_MODULE,
-       .name = TVP514X_MODULE_NAME,
-       .priv = &tvp514x_dev,
-       .type = v4l2_int_type_slave,
-       .u = {
-             .slave = &tvp514x_slave,
-             },
+       .v4l2_int_device = {
+               .module = THIS_MODULE,
+               .name = TVP514X_MODULE_NAME,
+               .type = v4l2_int_type_slave,
+       },
+       .tvp514x_slave = {
+               .ioctls = tvp514x_ioctl_desc,
+               .num_ioctls = ARRAY_SIZE(tvp514x_ioctl_desc),
+       },
 };
 
 /**
@@ -1392,26 +1390,37 @@ static struct v4l2_int_device tvp514x_int_device = {
 static int
 tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
-       struct tvp514x_decoder *decoder = &tvp514x_dev;
+       struct tvp514x_decoder *decoder;
        int err;
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -EIO;
 
-       decoder->pdata = client->dev.platform_data;
-       if (!decoder->pdata) {
+       decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
+       if (!decoder)
+               return -ENOMEM;
+
+       if (!client->dev.platform_data) {
                v4l_err(client, "No platform data!!\n");
-               return -ENODEV;
+               err = -ENODEV;
+               goto out_free;
        }
+
+       *decoder = tvp514x_dev;
+       decoder->v4l2_int_device.priv = decoder;
+       decoder->pdata = client->dev.platform_data;
+       decoder->v4l2_int_device.u.slave = &decoder->tvp514x_slave;
+       memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default,
+                       sizeof(tvp514x_reg_list_default));
        /*
         * Fetch platform specific data, and configure the
         * tvp514x_reg_list[] accordingly. Since this is one
         * time configuration, no need to preserve.
         */
-       tvp514x_reg_list[REG_OUTPUT_FORMATTER2].val |=
+       decoder->tvp514x_regs[REG_OUTPUT_FORMATTER2].val |=
                        (decoder->pdata->clk_polarity << 1);
-       tvp514x_reg_list[REG_SYNC_CONTROL].val |=
+       decoder->tvp514x_regs[REG_SYNC_CONTROL].val |=
                        ((decoder->pdata->hs_polarity << 2) |
                        (decoder->pdata->vs_polarity << 3));
        /*
@@ -1419,23 +1428,27 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
         */
        decoder->id = (struct i2c_device_id *)id;
        /* Attach to Master */
-       strcpy(tvp514x_int_device.u.slave->attach_to, decoder->pdata->master);
-       decoder->v4l2_int_device = &tvp514x_int_device;
+       strcpy(decoder->v4l2_int_device.u.slave->attach_to,
+                       decoder->pdata->master);
        decoder->client = client;
        i2c_set_clientdata(client, decoder);
 
        /* Register with V4L2 layer as slave device */
-       err = v4l2_int_device_register(decoder->v4l2_int_device);
+       err = v4l2_int_device_register(&decoder->v4l2_int_device);
        if (err) {
                i2c_set_clientdata(client, NULL);
                v4l_err(client,
                        "Unable to register to v4l2. Err[%d]\n", err);
+               goto out_free;
 
        } else
                v4l_info(client, "Registered to v4l2 master %s!!\n",
                                decoder->pdata->master);
-
        return 0;
+
+out_free:
+       kfree(decoder);
+       return err;
 }
 
 /**
@@ -1452,9 +1465,9 @@ static int __exit tvp514x_remove(struct i2c_client *client)
        if (!client->adapter)
                return -ENODEV; /* our client isn't attached */
 
-       v4l2_int_device_unregister(decoder->v4l2_int_device);
+       v4l2_int_device_unregister(&decoder->v4l2_int_device);
        i2c_set_clientdata(client, NULL);
-
+       kfree(decoder);
        return 0;
 }
 /*
index 2cd64ef27b95ee6b8f37a982cc233bb690d02017..3a5a95f134b4cae0cfe19b39c77894c5018a55d9 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <linux/delay.h>
-#include <linux/video_decoder.h>
 #include <media/v4l2-device.h>
 #include <media/tvp5150.h>
 #include <media/v4l2-i2c-drv-legacy.h>
@@ -632,7 +631,7 @@ static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd,
        const struct i2c_vbi_ram_value *regs = vbi_ram_default;
        int line;
 
-       v4l2_dbg(1, debug, sd, "VIDIOC_G_SLICED_VBI_CAP\n");
+       v4l2_dbg(1, debug, sd, "g_sliced_vbi_cap\n");
        memset(cap, 0, sizeof *cap);
 
        while (regs->reg != (u16)-1 ) {
@@ -831,7 +830,7 @@ static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
 
 static int tvp5150_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       v4l2_dbg(1, debug, sd, "VIDIOC_G_CTRL called\n");
+       v4l2_dbg(1, debug, sd, "g_ctrl called\n");
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
@@ -861,7 +860,7 @@ static int tvp5150_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
                if (ctrl->value < tvp5150_qctrl[i].minimum ||
                    ctrl->value > tvp5150_qctrl[i].maximum)
                        return -ERANGE;
-               v4l2_dbg(1, debug, sd, "VIDIOC_S_CTRL: id=%d, value=%d\n",
+               v4l2_dbg(1, debug, sd, "s_ctrl: id=%d, value=%d\n",
                                        ctrl->id, ctrl->value);
                break;
        }
@@ -1015,7 +1014,7 @@ static int tvp5150_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
 {
        int i;
 
-       v4l2_dbg(1, debug, sd, "VIDIOC_QUERYCTRL called\n");
+       v4l2_dbg(1, debug, sd, "queryctrl called\n");
 
        for (i = 0; i < ARRAY_SIZE(tvp5150_qctrl); i++)
                if (qc->id && qc->id == tvp5150_qctrl[i].id) {
@@ -1126,7 +1125,6 @@ MODULE_DEVICE_TABLE(i2c, tvp5150_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "tvp5150",
-       .driverid = I2C_DRIVERID_TVP5150,
        .command = tvp5150_command,
        .probe = tvp5150_probe,
        .remove = tvp5150_remove,
index 52c0357faa5d0fb2e270e41dc05fd44ec56bdd7a..a399476439920f78d320c376c72153995381ae0f 100644 (file)
@@ -460,9 +460,11 @@ static int tw9910_mask_set(struct i2c_client *client, u8 command,
                           u8 mask, u8 set)
 {
        s32 val = i2c_smbus_read_byte_data(client, command);
+       if (val < 0)
+               return val;
 
        val &= ~mask;
-       val |=  set;
+       val |= set & mask;
 
        return i2c_smbus_write_byte_data(client, command, val);
 }
@@ -639,8 +641,8 @@ static int tw9910_set_register(struct soc_camera_device *icd,
 }
 #endif
 
-static int tw9910_set_fmt(struct soc_camera_device *icd, __u32 pixfmt,
-                             struct v4l2_rect *rect)
+static int tw9910_set_crop(struct soc_camera_device *icd,
+                          struct v4l2_rect *rect)
 {
        struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
        int                 ret  = -EINVAL;
@@ -731,8 +733,33 @@ tw9910_set_fmt_error:
        return ret;
 }
 
+static int tw9910_set_fmt(struct soc_camera_device *icd,
+                         struct v4l2_format *f)
+{
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct v4l2_rect rect = {
+               .left   = icd->x_current,
+               .top    = icd->y_current,
+               .width  = pix->width,
+               .height = pix->height,
+       };
+       int i;
+
+       /*
+        * check color format
+        */
+       for (i = 0; i < ARRAY_SIZE(tw9910_color_fmt); i++)
+               if (pix->pixelformat == tw9910_color_fmt[i].fourcc)
+                       break;
+
+       if (i == ARRAY_SIZE(tw9910_color_fmt))
+               return -EINVAL;
+
+       return tw9910_set_crop(icd, &rect);
+}
+
 static int tw9910_try_fmt(struct soc_camera_device *icd,
-                             struct v4l2_format *f)
+                         struct v4l2_format *f)
 {
        struct v4l2_pix_format *pix = &f->fmt.pix;
        const struct tw9910_scale_ctrl *scale;
@@ -820,6 +847,7 @@ static struct soc_camera_ops tw9910_ops = {
        .release                = tw9910_release,
        .start_capture          = tw9910_start_capture,
        .stop_capture           = tw9910_stop_capture,
+       .set_crop               = tw9910_set_crop,
        .set_fmt                = tw9910_set_fmt,
        .try_fmt                = tw9910_try_fmt,
        .set_bus_param          = tw9910_set_bus_param,
index f4522bb0891666742231012f5cc23d9cd519b35e..c0ac651bb35844bd8d63d44b2c5b7526fba78ac3 100644 (file)
@@ -187,11 +187,6 @@ static int upd64031a_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register
 }
 #endif
 
-static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops upd64031a_core_ops = {
@@ -267,8 +262,6 @@ MODULE_DEVICE_TABLE(i2c, upd64031a_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "upd64031a",
-       .driverid = I2C_DRIVERID_UPD64031A,
-       .command = upd64031a_command,
        .probe = upd64031a_probe,
        .remove = upd64031a_remove,
        .id_table = upd64031a_id,
index a5fb74bf2407901052a468b9f24dee8be598f2d6..410c915d51fa3e56e70122ae9d800b6d4430d910 100644 (file)
@@ -164,11 +164,6 @@ static int upd64083_log_status(struct v4l2_subdev *sd)
        return 0;
 }
 
-static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops upd64083_core_ops = {
@@ -239,8 +234,6 @@ MODULE_DEVICE_TABLE(i2c, upd64083_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "upd64083",
-       .driverid = I2C_DRIVERID_UPD64083,
-       .command = upd64083_command,
        .probe = upd64083_probe,
        .remove = upd64083_remove,
        .id_table = upd64083_id,
index 2f1106338c085d7881940e54951d10b8ac93c44b..8d73979596f9d9542c35e10aa158d6792878099a 100644 (file)
@@ -191,7 +191,7 @@ initialize_camera(struct vicam_camera *cam)
 {
        int err;
        const struct ihex_binrec *rec;
-       const struct firmware *fw;
+       const struct firmware *uninitialized_var(fw);
 
        err = request_ihex_firmware(&fw, "vicam/firmware.fw", &cam->udev->dev);
        if (err) {
index 9e4f50639975308c0ca23ed446f1aa26d8e4f4df..a0feb1c97736b4c6ac2e68be71ac4857709526a7 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/spinlock.h>
 #include <asm/io.h>
 #include <linux/videodev2.h>
-#include <linux/video_decoder.h>
 #include <linux/i2c.h>
 
 #include <media/saa7115.h>
@@ -381,8 +380,9 @@ int usbvision_scratch_alloc(struct usb_usbvision *usbvision)
        usbvision->scratch = vmalloc_32(scratch_buf_size);
        scratch_reset(usbvision);
        if(usbvision->scratch == NULL) {
-               err("%s: unable to allocate %d bytes for scratch",
-                   __func__, scratch_buf_size);
+               dev_err(&usbvision->dev->dev,
+                       "%s: unable to allocate %d bytes for scratch\n",
+                               __func__, scratch_buf_size);
                return -ENOMEM;
        }
        return 0;
@@ -491,8 +491,9 @@ int usbvision_decompress_alloc(struct usb_usbvision *usbvision)
        int IFB_size = MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * 3 / 2;
        usbvision->IntraFrameBuffer = vmalloc_32(IFB_size);
        if (usbvision->IntraFrameBuffer == NULL) {
-               err("%s: unable to allocate %d for compr. frame buffer",
-                   __func__, IFB_size);
+               dev_err(&usbvision->dev->dev,
+                       "%s: unable to allocate %d for compr. frame buffer\n",
+                               __func__, IFB_size);
                return -ENOMEM;
        }
        return 0;
@@ -1514,8 +1515,9 @@ static void usbvision_isocIrq(struct urb *urb)
        errCode = usb_submit_urb (urb, GFP_ATOMIC);
 
        if(errCode) {
-               err("%s: usb_submit_urb failed: error %d",
-                   __func__, errCode);
+               dev_err(&usbvision->dev->dev,
+                       "%s: usb_submit_urb failed: error %d\n",
+                               __func__, errCode);
        }
 
        return;
@@ -1546,7 +1548,8 @@ int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg)
                                0, (__u16) reg, buffer, 1, HZ);
 
        if (errCode < 0) {
-               err("%s: failed: error %d", __func__, errCode);
+               dev_err(&usbvision->dev->dev,
+                       "%s: failed: error %d\n", __func__, errCode);
                return errCode;
        }
        return buffer[0];
@@ -1574,7 +1577,8 @@ int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg,
                                USB_RECIP_ENDPOINT, 0, (__u16) reg, &value, 1, HZ);
 
        if (errCode < 0) {
-               err("%s: failed: error %d", __func__, errCode);
+               dev_err(&usbvision->dev->dev,
+                       "%s: failed: error %d\n", __func__, errCode);
        }
        return errCode;
 }
@@ -1850,7 +1854,8 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width,
                                 0, (__u16) USBVISION_LXSIZE_O, value, 4, HZ);
 
                if (errCode < 0) {
-                       err("%s failed: error %d", __func__, errCode);
+                       dev_err(&usbvision->dev->dev,
+                               "%s failed: error %d\n", __func__, errCode);
                        return errCode;
                }
                usbvision->curwidth = usbvision->stretch_width * UsbWidth;
@@ -2236,7 +2241,7 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
                             (__u16) USBVISION_DRM_PRM1, value, 8, HZ);
 
        if (rc < 0) {
-               err("%sERROR=%d", __func__, rc);
+               dev_err(&usbvision->dev->dev, "%sERROR=%d\n", __func__, rc);
                return rc;
        }
 
@@ -2432,8 +2437,9 @@ int usbvision_set_alternate(struct usb_usbvision *dev)
                PDEBUG(DBG_FUNC,"setting alternate %d with wMaxPacketSize=%u", dev->ifaceAlt,dev->isocPacketSize);
                errCode = usb_set_interface(dev->dev, dev->iface, dev->ifaceAlt);
                if (errCode < 0) {
-                       err ("cannot change alternate number to %d (error=%i)",
-                                                       dev->ifaceAlt, errCode);
+                       dev_err(&dev->dev->dev,
+                               "cannot change alternate number to %d (error=%i)\n",
+                                       dev->ifaceAlt, errCode);
                        return errCode;
                }
        }
@@ -2484,7 +2490,8 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
 
                urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
                if (urb == NULL) {
-                       err("%s: usb_alloc_urb() failed", __func__);
+                       dev_err(&usbvision->dev->dev,
+                               "%s: usb_alloc_urb() failed\n", __func__);
                        return -ENOMEM;
                }
                usbvision->sbuf[bufIdx].urb = urb;
@@ -2496,7 +2503,7 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
                urb->dev = dev;
                urb->context = usbvision;
                urb->pipe = usb_rcvisocpipe(dev, usbvision->video_endp);
-               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
                urb->interval = 1;
                urb->transfer_buffer = usbvision->sbuf[bufIdx].data;
                urb->complete = usbvision_isocIrq;
@@ -2516,8 +2523,9 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
                        errCode = usb_submit_urb(usbvision->sbuf[bufIdx].urb,
                                                 GFP_KERNEL);
                if (errCode) {
-                       err("%s: usb_submit_urb(%d) failed: error %d",
-                           __func__, bufIdx, errCode);
+                       dev_err(&usbvision->dev->dev,
+                               "%s: usb_submit_urb(%d) failed: error %d\n",
+                                       __func__, bufIdx, errCode);
                }
        }
 
@@ -2566,8 +2574,9 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision)
                errCode = usb_set_interface(usbvision->dev, usbvision->iface,
                                            usbvision->ifaceAlt);
                if (errCode < 0) {
-                       err("%s: usb_set_interface() failed: error %d",
-                           __func__, errCode);
+                       dev_err(&usbvision->dev->dev,
+                               "%s: usb_set_interface() failed: error %d\n",
+                                       __func__, errCode);
                        usbvision->last_error = errCode;
                }
                regValue = (16-usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F;
@@ -2623,7 +2632,7 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
        }
        route.input = mode[channel];
        route.output = 0;
-       call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
+       call_all(usbvision, video, s_routing, &route);
        usbvision_set_audio(usbvision, audio[channel]);
        return 0;
 }
index 6b66ae4f430f04889768575758f06596262d0ded..dd2f8f27c73bbbc38244ada5040d043dd6a013c9 100644 (file)
@@ -119,7 +119,8 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap,
                /* try extended address code... */
                ret = try_write_address(i2c_adap, addr, retries);
                if (ret != 1) {
-                       err("died at extended address code, while writing");
+                       dev_err(&i2c_adap->dev,
+                               "died at extended address code, while writing\n");
                        return -EREMOTEIO;
                }
                add[0] = addr;
@@ -128,7 +129,8 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap,
                        addr |= 0x01;
                        ret = try_read_address(i2c_adap, addr, retries);
                        if (ret != 1) {
-                               err("died at extended address code, while reading");
+                               dev_err(&i2c_adap->dev,
+                                       "died at extended address code, while reading\n");
                                return -EREMOTEIO;
                        }
                }
@@ -200,72 +202,78 @@ static struct i2c_algorithm usbvision_algo = {
 };
 
 
-/*
- * registering functions to load algorithms at runtime
- */
-static int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap)
-{
-       PDEBUG(DBG_I2C, "I2C   debugging is enabled [i2c]");
-       PDEBUG(DBG_I2C, "ALGO   debugging is enabled [i2c]");
-
-       /* register new adapter to i2c module... */
-
-       adap->algo = &usbvision_algo;
-
-       adap->timeout = 100;    /* default values, should       */
-       adap->retries = 3;      /* be replaced by defines       */
-
-       i2c_add_adapter(adap);
-
-       PDEBUG(DBG_I2C,"i2c bus for %s registered", adap->name);
-
-       return 0;
-}
-
 /* ----------------------------------------------------------------------- */
 /* usbvision specific I2C functions                                        */
 /* ----------------------------------------------------------------------- */
 static struct i2c_adapter i2c_adap_template;
-static struct i2c_client i2c_client_template;
 
 int usbvision_i2c_register(struct usb_usbvision *usbvision)
 {
+       static unsigned short saa711x_addrs[] = {
+               0x4a >> 1, 0x48 >> 1,   /* SAA7111, SAA7111A and SAA7113 */
+               0x42 >> 1, 0x40 >> 1,   /* SAA7114, SAA7115 and SAA7118 */
+               I2C_CLIENT_END };
+
        memcpy(&usbvision->i2c_adap, &i2c_adap_template,
               sizeof(struct i2c_adapter));
-       memcpy(&usbvision->i2c_client, &i2c_client_template,
-              sizeof(struct i2c_client));
 
        sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name),
                " #%d", usbvision->vdev->num);
        PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name);
        usbvision->i2c_adap.dev.parent = &usbvision->dev->dev;
 
-       i2c_set_adapdata(&usbvision->i2c_adap, usbvision);
-       i2c_set_clientdata(&usbvision->i2c_client, usbvision);
-
-       usbvision->i2c_client.adapter = &usbvision->i2c_adap;
+       i2c_set_adapdata(&usbvision->i2c_adap, &usbvision->v4l2_dev);
 
        if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) {
                printk(KERN_ERR "usbvision_register: can't write reg\n");
                return -EBUSY;
        }
 
-#ifdef CONFIG_MODULES
+       PDEBUG(DBG_I2C, "I2C   debugging is enabled [i2c]");
+       PDEBUG(DBG_I2C, "ALGO   debugging is enabled [i2c]");
+
+       /* register new adapter to i2c module... */
+
+       usbvision->i2c_adap.algo = &usbvision_algo;
+
+       usbvision->i2c_adap.timeout = 100;      /* default values, should       */
+       usbvision->i2c_adap.retries = 3;        /* be replaced by defines       */
+
+       i2c_add_adapter(&usbvision->i2c_adap);
+
+       PDEBUG(DBG_I2C, "i2c bus for %s registered", usbvision->i2c_adap.name);
+
        /* Request the load of the i2c modules we need */
        switch (usbvision_device_data[usbvision->DevModel].Codec) {
        case CODEC_SAA7113:
-               request_module("saa7115");
-               break;
        case CODEC_SAA7111:
-               request_module("saa7115");
+               v4l2_i2c_new_probed_subdev(&usbvision->i2c_adap, "saa7115",
+                               "saa7115_auto", saa711x_addrs);
                break;
        }
        if (usbvision_device_data[usbvision->DevModel].Tuner == 1) {
-               request_module("tuner");
+               struct v4l2_subdev *sd;
+               enum v4l2_i2c_tuner_type type;
+               struct tuner_setup tun_setup;
+
+               sd = v4l2_i2c_new_probed_subdev(&usbvision->i2c_adap, "tuner",
+                               "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+               /* depending on whether we found a demod or not, select
+                  the tuner type. */
+               type = sd ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
+
+               sd = v4l2_i2c_new_probed_subdev(&usbvision->i2c_adap, "tuner",
+                               "tuner", v4l2_i2c_tuner_addrs(type));
+
+               if (usbvision->tuner_type != -1) {
+                       tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+                       tun_setup.type = usbvision->tuner_type;
+                       tun_setup.addr = v4l2_i2c_subdev_addr(sd);
+                       call_all(usbvision, tuner, s_type_addr, &tun_setup);
+               }
        }
-#endif
 
-       return usbvision_i2c_usb_add_bus(&usbvision->i2c_adap);
+       return 0;
 }
 
 int usbvision_i2c_unregister(struct usb_usbvision *usbvision)
@@ -278,67 +286,6 @@ int usbvision_i2c_unregister(struct usb_usbvision *usbvision)
        return 0;
 }
 
-void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,
-                     void *arg)
-{
-       i2c_clients_command(&usbvision->i2c_adap, cmd, arg);
-}
-
-static int attach_inform(struct i2c_client *client)
-{
-       struct usb_usbvision *usbvision;
-
-       usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter);
-
-       switch (client->addr << 1) {
-               case 0x42 << 1:
-               case 0x43 << 1:
-               case 0x4a << 1:
-               case 0x4b << 1:
-                       PDEBUG(DBG_I2C,"attach_inform: tda9887 detected.");
-                       break;
-               case 0x42:
-                       PDEBUG(DBG_I2C,"attach_inform: saa7114 detected.");
-                       break;
-               case 0x4a:
-                       PDEBUG(DBG_I2C,"attach_inform: saa7113 detected.");
-                       break;
-               case 0x48:
-                       PDEBUG(DBG_I2C,"attach_inform: saa7111 detected.");
-                       break;
-               case 0xa0:
-                       PDEBUG(DBG_I2C,"attach_inform: eeprom detected.");
-                       break;
-
-               default:
-                       {
-                               struct tuner_setup tun_setup;
-
-                               PDEBUG(DBG_I2C,"attach inform: detected I2C address %x", client->addr << 1);
-                               usbvision->tuner_addr = client->addr;
-
-                               if ((usbvision->have_tuner) && (usbvision->tuner_type != -1)) {
-                                       tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
-                                       tun_setup.type = usbvision->tuner_type;
-                                       tun_setup.addr = usbvision->tuner_addr;
-                                       call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup);
-                               }
-                       }
-                       break;
-       }
-       return 0;
-}
-
-static int detach_inform(struct i2c_client *client)
-{
-       struct usb_usbvision *usbvision;
-
-       usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter);
-
-       PDEBUG(DBG_I2C,"usbvision[%d] detaches %s", usbvision->nr, client->name);
-       return 0;
-}
-
 static int
 usbvision_i2c_read_max4(struct usb_usbvision *usbvision, unsigned char addr,
                     char *buf, short len)
@@ -511,14 +458,6 @@ static int usbvision_i2c_read(struct usb_usbvision *usbvision, unsigned char add
 static struct i2c_adapter i2c_adap_template = {
        .owner = THIS_MODULE,
        .name              = "usbvision",
-       .id                = I2C_HW_B_BT848, /* FIXME */
-       .client_register   = attach_inform,
-       .client_unregister = detach_inform,
-       .class             = I2C_CLASS_TV_ANALOG,
-};
-
-static struct i2c_client i2c_client_template = {
-       .name           = "usbvision internal",
 };
 
 /*
index 2622de003a452a49936f628fa6a0c063857be7c6..fa62a2fd7b22ee342102711712cf9c39306d3ae1 100644 (file)
@@ -59,7 +59,6 @@
 #include <linux/spinlock.h>
 #include <asm/io.h>
 #include <linux/videodev2.h>
-#include <linux/video_decoder.h>
 #include <linux/i2c.h>
 
 #include <media/saa7115.h>
@@ -212,7 +211,7 @@ static ssize_t show_hue(struct device *cd,
        ctrl.id = V4L2_CID_HUE;
        ctrl.value = 0;
        if(usbvision->user)
-               call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+               call_all(usbvision, core, g_ctrl, &ctrl);
        return sprintf(buf, "%d\n", ctrl.value);
 }
 static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
@@ -227,7 +226,7 @@ static ssize_t show_contrast(struct device *cd,
        ctrl.id = V4L2_CID_CONTRAST;
        ctrl.value = 0;
        if(usbvision->user)
-               call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+               call_all(usbvision, core, g_ctrl, &ctrl);
        return sprintf(buf, "%d\n", ctrl.value);
 }
 static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
@@ -242,7 +241,7 @@ static ssize_t show_brightness(struct device *cd,
        ctrl.id = V4L2_CID_BRIGHTNESS;
        ctrl.value = 0;
        if(usbvision->user)
-               call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+               call_all(usbvision, core, g_ctrl, &ctrl);
        return sprintf(buf, "%d\n", ctrl.value);
 }
 static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
@@ -257,7 +256,7 @@ static ssize_t show_saturation(struct device *cd,
        ctrl.id = V4L2_CID_SATURATION;
        ctrl.value = 0;
        if(usbvision->user)
-               call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+               call_all(usbvision, core, g_ctrl, &ctrl);
        return sprintf(buf, "%d\n", ctrl.value);
 }
 static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
@@ -329,7 +328,7 @@ static void usbvision_create_sysfs(struct video_device *vdev)
                        return;
        } while (0);
 
-       err("%s error: %d\n", __func__, res);
+       dev_err(&vdev->dev, "%s error: %d\n", __func__, res);
 }
 
 static void usbvision_remove_sysfs(struct video_device *vdev)
@@ -487,8 +486,9 @@ static int vidioc_g_register (struct file *file, void *priv,
        /* NT100x has a 8-bit register space */
        errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
        if (errCode < 0) {
-               err("%s: VIDIOC_DBG_G_REGISTER failed: error %d",
-                   __func__, errCode);
+               dev_err(&usbvision->vdev->dev,
+                       "%s: VIDIOC_DBG_G_REGISTER failed: error %d\n",
+                               __func__, errCode);
                return errCode;
        }
        reg->val = errCode;
@@ -507,8 +507,9 @@ static int vidioc_s_register (struct file *file, void *priv,
        /* NT100x has a 8-bit register space */
        errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
        if (errCode < 0) {
-               err("%s: VIDIOC_DBG_S_REGISTER failed: error %d",
-                   __func__, errCode);
+               dev_err(&usbvision->vdev->dev,
+                       "%s: VIDIOC_DBG_S_REGISTER failed: error %d\n",
+                               __func__, errCode);
                return errCode;
        }
        return 0;
@@ -524,8 +525,7 @@ static int vidioc_querycap (struct file *file, void  *priv,
        strlcpy(vc->card,
                usbvision_device_data[usbvision->DevModel].ModelString,
                sizeof(vc->card));
-       strlcpy(vc->bus_info, dev_name(&usbvision->dev->dev),
-               sizeof(vc->bus_info));
+       usb_make_path(usbvision->dev, vc->bus_info, sizeof(vc->bus_info));
        vc->version = USBVISION_DRIVER_VERSION;
        vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_AUDIO |
@@ -621,8 +621,7 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
        usbvision->tvnormId=*id;
 
        mutex_lock(&usbvision->lock);
-       call_i2c_clients(usbvision, VIDIOC_S_STD,
-                        &usbvision->tvnormId);
+       call_all(usbvision, tuner, s_std, usbvision->tvnormId);
        mutex_unlock(&usbvision->lock);
        /* propagate the change to the decoder */
        usbvision_muxsel(usbvision, usbvision->ctl_input);
@@ -644,7 +643,7 @@ static int vidioc_g_tuner (struct file *file, void *priv,
                strcpy(vt->name, "Television");
        }
        /* Let clients fill in the remainder of this struct */
-       call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
+       call_all(usbvision, tuner, g_tuner, vt);
 
        return 0;
 }
@@ -658,7 +657,7 @@ static int vidioc_s_tuner (struct file *file, void *priv,
        if (!usbvision->have_tuner || vt->index)
                return -EINVAL;
        /* let clients handle this */
-       call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
+       call_all(usbvision, tuner, s_tuner, vt);
 
        return 0;
 }
@@ -689,7 +688,7 @@ static int vidioc_s_frequency (struct file *file, void *priv,
                return -EINVAL;
 
        usbvision->freq = freq->frequency;
-       call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, freq);
+       call_all(usbvision, tuner, s_frequency, freq);
 
        return 0;
 }
@@ -698,7 +697,6 @@ static int vidioc_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
 {
        struct usb_usbvision *usbvision = video_drvdata(file);
 
-       memset(a,0,sizeof(*a));
        if(usbvision->radio) {
                strcpy(a->name,"Radio");
        } else {
@@ -722,12 +720,8 @@ static int vidioc_queryctrl (struct file *file, void *priv,
                            struct v4l2_queryctrl *ctrl)
 {
        struct usb_usbvision *usbvision = video_drvdata(file);
-       int id=ctrl->id;
 
-       memset(ctrl,0,sizeof(*ctrl));
-       ctrl->id=id;
-
-       call_i2c_clients(usbvision, VIDIOC_QUERYCTRL, ctrl);
+       call_all(usbvision, core, queryctrl, ctrl);
 
        if (!ctrl->type)
                return -EINVAL;
@@ -739,7 +733,7 @@ static int vidioc_g_ctrl (struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
        struct usb_usbvision *usbvision = video_drvdata(file);
-       call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
+       call_all(usbvision, core, g_ctrl, ctrl);
 
        return 0;
 }
@@ -748,7 +742,7 @@ static int vidioc_s_ctrl (struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
        struct usb_usbvision *usbvision = video_drvdata(file);
-       call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
+       call_all(usbvision, core, s_ctrl, ctrl);
 
        return 0;
 }
@@ -763,8 +757,7 @@ static int vidioc_reqbufs (struct file *file,
 
        /* Check input validity:
           the user must do a VIDEO CAPTURE and MMAP method. */
-       if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
-          (vr->memory != V4L2_MEMORY_MMAP))
+       if (vr->memory != V4L2_MEMORY_MMAP)
                return -EINVAL;
 
        if(usbvision->streaming == Stream_On) {
@@ -789,9 +782,6 @@ static int vidioc_querybuf (struct file *file,
 
        /* FIXME : must control
           that buffers are mapped (VIDIOC_REQBUFS has been called) */
-       if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
-               return -EINVAL;
-       }
        if(vb->index>=usbvision->num_frames)  {
                return -EINVAL;
        }
@@ -825,9 +815,6 @@ static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
        unsigned long lock_flags;
 
        /* FIXME : works only on VIDEO_CAPTURE MODE, MMAP. */
-       if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
-               return -EINVAL;
-       }
        if(vb->index>=usbvision->num_frames)  {
                return -EINVAL;
        }
@@ -862,9 +849,6 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
        struct usbvision_frame *f;
        unsigned long lock_flags;
 
-       if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
        if (list_empty(&(usbvision->outqueue))) {
                if (usbvision->streaming == Stream_Idle)
                        return -EINVAL;
@@ -899,10 +883,9 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
        struct usb_usbvision *usbvision = video_drvdata(file);
-       int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
        usbvision->streaming = Stream_On;
-       call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
+       call_all(usbvision, video, s_stream, 1);
 
        return 0;
 }
@@ -911,7 +894,6 @@ static int vidioc_streamoff(struct file *file,
                            void *priv, enum v4l2_buf_type type)
 {
        struct usb_usbvision *usbvision = video_drvdata(file);
-       int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
        if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
@@ -919,7 +901,7 @@ static int vidioc_streamoff(struct file *file,
        if(usbvision->streaming == Stream_On) {
                usbvision_stream_interrupt(usbvision);
                /* Stop all video streamings */
-               call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
+               call_all(usbvision, video, s_stream, 0);
        }
        usbvision_empty_framequeues(usbvision);
 
@@ -932,11 +914,8 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void  *priv,
        if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
                return -EINVAL;
        }
-       vfd->flags = 0;
-       vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
        vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
-       memset(vfd->reserved, 0, sizeof(vfd->reserved));
        return 0;
 }
 
@@ -1042,7 +1021,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
        if(usbvision->streaming != Stream_On) {
                /* no stream is running, make it running ! */
                usbvision->streaming = Stream_On;
-               call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
+               call_all(usbvision, video, s_stream, 1);
        }
 
        /* Then, enqueue as many frames as possible
@@ -1189,7 +1168,9 @@ static int usbvision_radio_open(struct file *file)
        mutex_lock(&usbvision->lock);
 
        if (usbvision->user) {
-               err("%s: Someone tried to open an already opened USBVision Radio!", __func__);
+               dev_err(&usbvision->rdev->dev,
+                       "%s: Someone tried to open an already opened USBVision Radio!\n",
+                               __func__);
                errCode = -EBUSY;
        }
        else {
@@ -1211,7 +1192,7 @@ static int usbvision_radio_open(struct file *file)
 
                // If so far no errors then we shall start the radio
                usbvision->radio = 1;
-               call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type);
+               call_all(usbvision, tuner, s_radio);
                usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO);
                usbvision->user++;
        }
@@ -1413,7 +1394,8 @@ static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
        struct video_device *vdev;
 
        if (usb_dev == NULL) {
-               err("%s: usbvision->dev is not set", __func__);
+               dev_err(&usbvision->dev->dev,
+                       "%s: usbvision->dev is not set\n", __func__);
                return NULL;
        }
 
@@ -1423,7 +1405,7 @@ static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
        }
        *vdev = *vdev_template;
 //     vdev->minor   = -1;
-       vdev->parent  = &usb_dev->dev;
+       vdev->v4l2_dev = &usbvision->v4l2_dev;
        snprintf(vdev->name, sizeof(vdev->name), "%s", name);
        video_set_drvdata(vdev, usbvision);
        return vdev;
@@ -1524,7 +1506,9 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
        return 0;
 
  err_exit:
-       err("USBVision[%d]: video_register_device() failed", usbvision->nr);
+       dev_err(&usbvision->dev->dev,
+               "USBVision[%d]: video_register_device() failed\n",
+                       usbvision->nr);
        usbvision_unregister_video(usbvision);
        return -1;
 }
@@ -1542,33 +1526,30 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
 {
        struct usb_usbvision *usbvision;
 
-       if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) ==
-           NULL) {
-               goto err_exit;
-       }
+       usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL);
+       if (usbvision == NULL)
+               return NULL;
 
        usbvision->dev = dev;
+       if (v4l2_device_register(&dev->dev, &usbvision->v4l2_dev))
+               goto err_free;
 
        mutex_init(&usbvision->lock);   /* available */
 
        // prepare control urb for control messages during interrupts
        usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
-       if (usbvision->ctrlUrb == NULL) {
-               goto err_exit;
-       }
+       if (usbvision->ctrlUrb == NULL)
+               goto err_unreg;
        init_waitqueue_head(&usbvision->ctrlUrb_wq);
 
        usbvision_init_powerOffTimer(usbvision);
 
        return usbvision;
 
-err_exit:
-       if (usbvision && usbvision->ctrlUrb) {
-               usb_free_urb(usbvision->ctrlUrb);
-       }
-       if (usbvision) {
-               kfree(usbvision);
-       }
+err_unreg:
+       v4l2_device_unregister(&usbvision->v4l2_dev);
+err_free:
+       kfree(usbvision);
        return NULL;
 }
 
@@ -1598,6 +1579,7 @@ static void usbvision_release(struct usb_usbvision *usbvision)
                usb_free_urb(usbvision->ctrlUrb);
        }
 
+       v4l2_device_unregister(&usbvision->v4l2_dev);
        kfree(usbvision);
 
        PDEBUG(DBG_PROBE, "success");
@@ -1675,20 +1657,20 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
        }
        endpoint = &interface->endpoint[1].desc;
        if (!usb_endpoint_xfer_isoc(endpoint)) {
-               err("%s: interface %d. has non-ISO endpoint!",
+               dev_err(&intf->dev, "%s: interface %d. has non-ISO endpoint!\n",
                    __func__, ifnum);
-               err("%s: Endpoint attributes %d",
+               dev_err(&intf->dev, "%s: Endpoint attributes %d",
                    __func__, endpoint->bmAttributes);
                return -ENODEV;
        }
        if (usb_endpoint_dir_out(endpoint)) {
-               err("%s: interface %d. has ISO OUT endpoint!",
+               dev_err(&intf->dev, "%s: interface %d. has ISO OUT endpoint!\n",
                    __func__, ifnum);
                return -ENODEV;
        }
 
        if ((usbvision = usbvision_alloc(dev)) == NULL) {
-               err("%s: couldn't allocate USBVision struct", __func__);
+               dev_err(&intf->dev, "%s: couldn't allocate USBVision struct\n", __func__);
                return -ENOMEM;
        }
 
@@ -1711,7 +1693,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
        usbvision->alt_max_pkt_size = kmalloc(32*
                                              usbvision->num_alt,GFP_KERNEL);
        if (usbvision->alt_max_pkt_size == NULL) {
-               err("usbvision: out of memory!\n");
+               dev_err(&intf->dev, "usbvision: out of memory!\n");
                mutex_unlock(&usbvision->lock);
                return -ENOMEM;
        }
@@ -1733,8 +1715,6 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
                usbvision->tuner_type = usbvision_device_data[model].TunerType;
        }
 
-       usbvision->tuner_addr = ADDR_UNSET;
-
        usbvision->DevModel = model;
        usbvision->remove_pending = 0;
        usbvision->iface = ifnum;
@@ -1772,7 +1752,8 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
        PDEBUG(DBG_PROBE, "");
 
        if (usbvision == NULL) {
-               err("%s: usb_get_intfdata() failed", __func__);
+               dev_err(&usbvision->dev->dev,
+                       "%s: usb_get_intfdata() failed\n", __func__);
                return;
        }
        usb_set_intfdata (intf, NULL);
@@ -1782,6 +1763,8 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
        // At this time we ask to cancel outstanding URBs
        usbvision_stop_isoc(usbvision);
 
+       v4l2_device_disconnect(&usbvision->v4l2_dev);
+
        if (usbvision->power) {
                usbvision_i2c_unregister(usbvision);
                usbvision_power_off(usbvision);
index 20d7ec624999d677037dea1cb5ff26d8345ef71f..f8d7458daf3e14eac135bb5cfed8170afa1cca6a 100644 (file)
@@ -6,7 +6,7 @@
  *                         Dwaine Garden <dwainegarden@rogers.com>
  *
  *
- * Report problems to v4l MailingList : http://www.redhat.com/mailman/listinfo/video4linux-list
+ * Report problems to v4l MailingList: linux-media@vger.kernel.org
  *
  * This module is part of usbvision driver project.
  * Updates to driver completed by Dwaine P. Garden
@@ -35,7 +35,7 @@
 #include <linux/usb.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/tuner.h>
 #include <linux/videodev2.h>
 
@@ -357,13 +357,13 @@ extern struct usbvision_device_data_st usbvision_device_data[];
 extern struct usb_device_id usbvision_table[];
 
 struct usb_usbvision {
+       struct v4l2_device v4l2_dev;
        struct video_device *vdev;                                      /* Video Device */
        struct video_device *rdev;                                      /* Radio Device */
        struct video_device *vbi;                                       /* VBI Device   */
 
        /* i2c Declaration Section*/
        struct i2c_adapter i2c_adap;
-       struct i2c_client i2c_client;
 
        struct urb *ctrlUrb;
        unsigned char ctrlUrbBuffer[8];
@@ -374,7 +374,6 @@ struct usb_usbvision {
        /* configuration part */
        int have_tuner;
        int tuner_type;
-       int tuner_addr;
        int bridgeType;                                                 // NT1003, NT1004, NT1005
        int radio;
        int video_inputs;                                               // # of inputs
@@ -464,6 +463,8 @@ struct usb_usbvision {
        int ComprBlockTypes[4];
 };
 
+#define call_all(usbvision, o, f, args...) \
+       v4l2_device_call_all(&usbvision->v4l2_dev, 0, o, f, ##args)
 
 /* --------------------------------------------------------------- */
 /* defined in usbvision-i2c.c                                      */
@@ -475,7 +476,6 @@ struct usb_usbvision {
 /* ----------------------------------------------------------------------- */
 int usbvision_i2c_register(struct usb_usbvision *usbvision);
 int usbvision_i2c_unregister(struct usb_usbvision *usbvision);
-void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg);
 
 /* defined in usbvision-core.c                                      */
 int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg);
index d2576f6391c06f4c643c96f9b0ffc0051e5fa124..0d7e38d6ff6a416ed6905b9bb66d6b3f6f2dd2f6 100644 (file)
@@ -786,7 +786,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
        memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);
        v4l2_ctrl->id = mapping->id;
        v4l2_ctrl->type = mapping->v4l2_type;
-       strncpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
+       strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
        v4l2_ctrl->flags = 0;
 
        if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR))
index b12873265cc56c5c811a6cba514305f8e6534a3d..399412d7f020db9b19278994ff9e826111bd0e23 100644 (file)
@@ -314,7 +314,7 @@ static int uvc_parse_format(struct uvc_device *dev,
                fmtdesc = uvc_format_by_guid(&buffer[5]);
 
                if (fmtdesc != NULL) {
-                       strncpy(format->name, fmtdesc->name,
+                       strlcpy(format->name, fmtdesc->name,
                                sizeof format->name);
                        format->fcc = fmtdesc->fcc;
                } else {
@@ -345,7 +345,7 @@ static int uvc_parse_format(struct uvc_device *dev,
                        return -EINVAL;
                }
 
-               strncpy(format->name, "MJPEG", sizeof format->name);
+               strlcpy(format->name, "MJPEG", sizeof format->name);
                format->fcc = V4L2_PIX_FMT_MJPEG;
                format->flags = UVC_FMT_FLAG_COMPRESSED;
                format->bpp = 0;
@@ -363,13 +363,13 @@ static int uvc_parse_format(struct uvc_device *dev,
 
                switch (buffer[8] & 0x7f) {
                case 0:
-                       strncpy(format->name, "SD-DV", sizeof format->name);
+                       strlcpy(format->name, "SD-DV", sizeof format->name);
                        break;
                case 1:
-                       strncpy(format->name, "SDL-DV", sizeof format->name);
+                       strlcpy(format->name, "SDL-DV", sizeof format->name);
                        break;
                case 2:
-                       strncpy(format->name, "HD-DV", sizeof format->name);
+                       strlcpy(format->name, "HD-DV", sizeof format->name);
                        break;
                default:
                        uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
@@ -379,7 +379,7 @@ static int uvc_parse_format(struct uvc_device *dev,
                        return -EINVAL;
                }
 
-               strncat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz",
+               strlcat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz",
                        sizeof format->name);
 
                format->fcc = V4L2_PIX_FMT_DV;
@@ -1526,7 +1526,7 @@ static int uvc_register_video(struct uvc_device *dev)
        vdev->minor = -1;
        vdev->fops = &uvc_fops;
        vdev->release = video_device_release;
-       strncpy(vdev->name, dev->name, sizeof vdev->name);
+       strlcpy(vdev->name, dev->name, sizeof vdev->name);
 
        /* Set the driver data before calling video_register_device, otherwise
         * uvc_v4l2_open might race us.
@@ -1621,7 +1621,7 @@ static int uvc_probe(struct usb_interface *intf,
        dev->quirks = id->driver_info | uvc_quirks_param;
 
        if (udev->product != NULL)
-               strncpy(dev->name, udev->product, sizeof dev->name);
+               strlcpy(dev->name, udev->product, sizeof dev->name);
        else
                snprintf(dev->name, sizeof dev->name,
                        "UVC Camera (%04x:%04x)",
@@ -1833,6 +1833,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceClass      = USB_CLASS_VENDOR_SPEC,
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0 },
+       /* Alcor Micro AU3820 (Future Boy PC USB Webcam) */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x058f,
+         .idProduct            = 0x3820,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
        /* Apple Built-In iSight */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1852,6 +1861,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
+       /* ViMicro */
+       { .match_flags          = USB_DEVICE_ID_MATCH_VENDOR
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x0ac8,
+         .idProduct            = 0x0000,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_FIX_BANDWIDTH },
        /* MT6227 */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1879,7 +1897,7 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
-       /* Asus F9SG */
+       /* Syntek (Asus F9SG) */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
          .idVendor             = 0x174f,
@@ -1897,6 +1915,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
+       /* Syntek (JAOtech Smart Terminal) */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x174f,
+         .idProduct            = 0x8a34,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_STREAM_NO_FID },
        /* Lenovo Thinkpad SL500 */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
index c705f248da8856d72c384d5b69b67df0c86a7567..21d87124986b57336afc53debe4315ce17d618a2 100644 (file)
 #ifdef CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV
 static int uvc_input_init(struct uvc_device *dev)
 {
-       struct usb_device *udev = dev->udev;
        struct input_dev *input;
-       char *phys = NULL;
        int ret;
 
        input = input_allocate_device();
        if (input == NULL)
                return -ENOMEM;
 
-       phys = kmalloc(6 + strlen(udev->bus->bus_name) + strlen(udev->devpath),
-                       GFP_KERNEL);
-       if (phys == NULL) {
-               ret = -ENOMEM;
-               goto error;
-       }
-       sprintf(phys, "usb-%s-%s", udev->bus->bus_name, udev->devpath);
+       usb_make_path(dev->udev, dev->input_phys, sizeof(dev->input_phys));
+       strlcat(dev->input_phys, "/button", sizeof(dev->input_phys));
 
        input->name = dev->name;
-       input->phys = phys;
-       usb_to_input_id(udev, &input->id);
+       input->phys = dev->input_phys;
+       usb_to_input_id(dev->udev, &input->id);
        input->dev.parent = &dev->intf->dev;
 
        __set_bit(EV_KEY, input->evbit);
@@ -57,7 +50,6 @@ static int uvc_input_init(struct uvc_device *dev)
 
 error:
        input_free_device(input);
-       kfree(phys);
        return ret;
 }
 
index d681519d0c8ae1ffa380352f85819c59ee44450f..2a80caa54fb42638d6808e8819a0fbb7c351e0aa 100644 (file)
@@ -55,7 +55,7 @@ static int uvc_v4l2_query_menu(struct uvc_video_device *video,
                return -EINVAL;
 
        menu_info = &mapping->menu_info[query_menu->index];
-       strncpy(query_menu->name, menu_info->name, 32);
+       strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
        return 0;
 }
 
@@ -486,10 +486,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                struct v4l2_capability *cap = arg;
 
                memset(cap, 0, sizeof *cap);
-               strncpy(cap->driver, "uvcvideo", sizeof cap->driver);
-               strncpy(cap->card, vdev->name, 32);
-               strncpy(cap->bus_info, video->dev->udev->bus->bus_name,
-                       sizeof cap->bus_info);
+               strlcpy(cap->driver, "uvcvideo", sizeof cap->driver);
+               strlcpy(cap->card, vdev->name, sizeof cap->card);
+               usb_make_path(video->dev->udev,
+                             cap->bus_info, sizeof(cap->bus_info));
                cap->version = DRIVER_VERSION_NUMBER;
                if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
                        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
@@ -620,7 +620,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
                memset(input, 0, sizeof *input);
                input->index = index;
-               strncpy(input->name, iterm->name, sizeof input->name);
+               strlcpy(input->name, iterm->name, sizeof input->name);
                if (UVC_ENTITY_TYPE(iterm) == ITT_CAMERA)
                        input->type = V4L2_INPUT_TYPE_CAMERA;
                break;
@@ -673,16 +673,22 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        {
                struct v4l2_fmtdesc *fmt = arg;
                struct uvc_format *format;
+               enum v4l2_buf_type type = fmt->type;
+               __u32 index = fmt->index;
 
                if (fmt->type != video->streaming->type ||
                    fmt->index >= video->streaming->nformats)
                        return -EINVAL;
 
+               memset(fmt, 0, sizeof(*fmt));
+               fmt->index = index;
+               fmt->type = type;
+
                format = &video->streaming->format[fmt->index];
                fmt->flags = 0;
                if (format->flags & UVC_FMT_FLAG_COMPRESSED)
                        fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
-               strncpy(fmt->description, format->name,
+               strlcpy(fmt->description, format->name,
                        sizeof fmt->description);
                fmt->description[sizeof fmt->description - 1] = 0;
                fmt->pixelformat = format->fcc;
index 9bc4705be78d8ebb893a9dd24d2e6215c344507f..a95e17329c5bb366d6eb7d70039a3328e8dbbc77 100644 (file)
@@ -61,7 +61,7 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
        return 0;
 }
 
-static void uvc_fixup_buffer_size(struct uvc_video_device *video,
+static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
        struct uvc_streaming_control *ctrl)
 {
        struct uvc_format *format;
@@ -84,6 +84,31 @@ static void uvc_fixup_buffer_size(struct uvc_video_device *video,
              video->dev->uvc_version < 0x0110))
                ctrl->dwMaxVideoFrameSize =
                        frame->dwMaxVideoFrameBufferSize;
+
+       if (video->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH &&
+           video->streaming->intf->num_altsetting > 1) {
+               u32 interval;
+               u32 bandwidth;
+
+               interval = (ctrl->dwFrameInterval > 100000)
+                        ? ctrl->dwFrameInterval
+                        : frame->dwFrameInterval[0];
+
+               /* Compute a bandwidth estimation by multiplying the frame
+                * size by the number of video frames per second, divide the
+                * result by the number of USB frames (or micro-frames for
+                * high-speed devices) per second and add the UVC header size
+                * (assumed to be 12 bytes long).
+                */
+               bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp;
+               bandwidth *= 10000000 / interval + 1;
+               bandwidth /= 1000;
+               if (video->dev->udev->speed == USB_SPEED_HIGH)
+                       bandwidth /= 8;
+               bandwidth += 12;
+
+               ctrl->dwMaxPayloadTransferSize = bandwidth;
+       }
 }
 
 static int uvc_get_video_ctrl(struct uvc_video_device *video,
@@ -158,10 +183,11 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
                ctrl->bMaxVersion = 0;
        }
 
-       /* Some broken devices return a null or wrong dwMaxVideoFrameSize.
-        * Try to get the value from the format and frame descriptors.
+       /* Some broken devices return null or wrong dwMaxVideoFrameSize and
+        * dwMaxPayloadTransferSize fields. Try to get the value from the
+        * format and frame descriptors.
         */
-       uvc_fixup_buffer_size(video, ctrl);
+       uvc_fixup_video_ctrl(video, ctrl);
        ret = 0;
 
 out:
@@ -540,6 +566,9 @@ static void uvc_video_decode_bulk(struct urb *urb,
        u8 *mem;
        int len, ret;
 
+       if (urb->actual_length == 0)
+               return;
+
        mem = urb->transfer_buffer;
        len = urb->actual_length;
        video->bulk.payload_size += len;
@@ -699,27 +728,47 @@ static void uvc_free_urb_buffers(struct uvc_video_device *video)
  * already allocated when resuming from suspend, in which case it will
  * return without touching the buffers.
  *
- * Return 0 on success or -ENOMEM when out of memory.
+ * Limit the buffer size to UVC_MAX_PACKETS bulk/isochronous packets. If the
+ * system is too low on memory try successively smaller numbers of packets
+ * until allocation succeeds.
+ *
+ * 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,
-       unsigned int size)
+       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 0;
 
-       for (i = 0; i < UVC_URBS; ++i) {
-               video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
-                       size, GFP_KERNEL, &video->urb_dma[i]);
-               if (video->urb_buffer[i] == NULL) {
-                       uvc_free_urb_buffers(video);
-                       return -ENOMEM;
+       /* Compute the number of packets. Bulk endpoints might transfer UVC
+        * payloads accross multiple URBs.
+        */
+       npackets = DIV_ROUND_UP(size, psize);
+       if (npackets > UVC_MAX_PACKETS)
+               npackets = UVC_MAX_PACKETS;
+
+       /* 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);
+                               break;
+                       }
+               }
+
+               if (i == UVC_URBS) {
+                       video->urb_size = psize * npackets;
+                       return npackets;
                }
        }
 
-       video->urb_size = size;
        return 0;
 }
 
@@ -753,29 +802,19 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
 {
        struct urb *urb;
        unsigned int npackets, i, j;
-       __u16 psize;
-       __u32 size;
+       u16 psize;
+       u32 size;
 
-       /* Compute the number of isochronous packets to allocate by dividing
-        * the maximum video frame size by the packet size. Limit the result
-        * to UVC_MAX_ISO_PACKETS.
-        */
        psize = le16_to_cpu(ep->desc.wMaxPacketSize);
        psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
-
        size = video->streaming->ctrl.dwMaxVideoFrameSize;
-       if (size > UVC_MAX_FRAME_SIZE)
-               return -EINVAL;
 
-       npackets = DIV_ROUND_UP(size, psize);
-       if (npackets > UVC_MAX_ISO_PACKETS)
-               npackets = UVC_MAX_ISO_PACKETS;
+       npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags);
+       if (npackets == 0)
+               return -ENOMEM;
 
        size = npackets * psize;
 
-       if (uvc_alloc_urb_buffers(video, size) < 0)
-               return -ENOMEM;
-
        for (i = 0; i < UVC_URBS; ++i) {
                urb = usb_alloc_urb(npackets, gfp_flags);
                if (urb == NULL) {
@@ -814,25 +853,20 @@ static int uvc_init_video_bulk(struct uvc_video_device *video,
        struct usb_host_endpoint *ep, gfp_t gfp_flags)
 {
        struct urb *urb;
-       unsigned int pipe, i;
-       __u16 psize;
-       __u32 size;
-
-       /* Compute the bulk URB size. Some devices set the maximum payload
-        * size to a value too high for memory-constrained devices. We must
-        * then transfer the payload accross multiple URBs. To be consistant
-        * with isochronous mode, allocate maximum UVC_MAX_ISO_PACKETS per bulk
-        * URB.
-        */
+       unsigned int npackets, pipe, i;
+       u16 psize;
+       u32 size;
+
        psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;
        size = video->streaming->ctrl.dwMaxPayloadTransferSize;
        video->bulk.max_payload_size = size;
-       if (size > psize * UVC_MAX_ISO_PACKETS)
-               size = psize * UVC_MAX_ISO_PACKETS;
 
-       if (uvc_alloc_urb_buffers(video, size) < 0)
+       npackets = uvc_alloc_urb_buffers(video, 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,
                                       ep->desc.bEndpointAddress);
@@ -1021,11 +1055,20 @@ int uvc_video_init(struct uvc_video_device *video)
         */
        usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
 
-       /* Some webcams don't suport GET_DEF requests on the probe control. We
-        * fall back to GET_CUR if GET_DEF fails.
+       /* 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);
+
+       /* 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_DEF)) < 0 &&
-           (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+       if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
                return ret;
 
        /* Check if the default format descriptor exists. Use the first
index 027947ea9b6eb497bc1263f07680902d08bec5ba..e5014e668f9979307996d507d034cdc3fb793e94 100644 (file)
@@ -296,10 +296,8 @@ struct uvc_xu_control {
 
 /* Number of isochronous URBs. */
 #define UVC_URBS               5
-/* Maximum number of packets per isochronous URB. */
-#define UVC_MAX_ISO_PACKETS    40
-/* Maximum frame size in bytes, for sanity checking. */
-#define UVC_MAX_FRAME_SIZE     (16*1024*1024)
+/* Maximum number of packets per URB. */
+#define UVC_MAX_PACKETS                32
 /* Maximum number of video buffers. */
 #define UVC_MAX_VIDEO_BUFFERS  32
 /* Maximum status buffer size in bytes of interrupt URB. */
@@ -316,6 +314,7 @@ struct uvc_xu_control {
 #define UVC_QUIRK_STREAM_NO_FID                0x00000010
 #define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
 #define UVC_QUIRK_PRUNE_CONTROLS       0x00000040
+#define UVC_QUIRK_FIX_BANDWIDTH                0x00000080
 
 /* Format flags */
 #define UVC_FMT_FLAG_COMPRESSED                0x00000001
@@ -649,6 +648,7 @@ struct uvc_device {
        struct urb *int_urb;
        __u8 *status;
        struct input_dev *input;
+       char input_phys[64];
 
        /* Video Streaming interfaces */
        struct list_head streaming;
index b8f2be8d5c0ee3702bad5f880180797e711082f9..1da8cb836cb6a247622a332a8674364b45baf92a 100644 (file)
@@ -334,6 +334,12 @@ const char **v4l2_ctrl_get_menu(u32 id)
                "Aperture Priority Mode",
                NULL
        };
+       static const char *colorfx[] = {
+               "None",
+               "Black & White",
+               "Sepia",
+               NULL
+       };
 
        switch (id) {
                case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
@@ -370,6 +376,8 @@ const char **v4l2_ctrl_get_menu(u32 id)
                        return camera_power_line_frequency;
                case V4L2_CID_EXPOSURE_AUTO:
                        return camera_exposure_auto;
+               case V4L2_CID_COLORFX:
+                       return colorfx;
                default:
                        return NULL;
        }
@@ -382,16 +390,16 @@ const char *v4l2_ctrl_get_name(u32 id)
        switch (id) {
        /* USER controls */
        case V4L2_CID_USER_CLASS:               return "User Controls";
+       case V4L2_CID_BRIGHTNESS:               return "Brightness";
+       case V4L2_CID_CONTRAST:                 return "Contrast";
+       case V4L2_CID_SATURATION:               return "Saturation";
+       case V4L2_CID_HUE:                      return "Hue";
        case V4L2_CID_AUDIO_VOLUME:             return "Volume";
-       case V4L2_CID_AUDIO_MUTE:               return "Mute";
        case V4L2_CID_AUDIO_BALANCE:            return "Balance";
        case V4L2_CID_AUDIO_BASS:               return "Bass";
        case V4L2_CID_AUDIO_TREBLE:             return "Treble";
+       case V4L2_CID_AUDIO_MUTE:               return "Mute";
        case V4L2_CID_AUDIO_LOUDNESS:           return "Loudness";
-       case V4L2_CID_BRIGHTNESS:               return "Brightness";
-       case V4L2_CID_CONTRAST:                 return "Contrast";
-       case V4L2_CID_SATURATION:               return "Saturation";
-       case V4L2_CID_HUE:                      return "Hue";
        case V4L2_CID_BLACK_LEVEL:              return "Black Level";
        case V4L2_CID_AUTO_WHITE_BALANCE:       return "White Balance, Automatic";
        case V4L2_CID_DO_WHITE_BALANCE:         return "Do White Balance";
@@ -412,6 +420,7 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_BACKLIGHT_COMPENSATION:   return "Backlight Compensation";
        case V4L2_CID_CHROMA_AGC:               return "Chroma AGC";
        case V4L2_CID_COLOR_KILLER:             return "Color Killer";
+       case V4L2_CID_COLORFX:                  return "Color Effects";
 
        /* MPEG controls */
        case V4L2_CID_MPEG_CLASS:               return "MPEG Encoder Controls";
@@ -490,16 +499,25 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
        case V4L2_CID_HFLIP:
        case V4L2_CID_VFLIP:
        case V4L2_CID_HUE_AUTO:
+       case V4L2_CID_CHROMA_AGC:
+       case V4L2_CID_COLOR_KILLER:
        case V4L2_CID_MPEG_AUDIO_MUTE:
        case V4L2_CID_MPEG_VIDEO_MUTE:
        case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
        case V4L2_CID_MPEG_VIDEO_PULLDOWN:
        case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
+       case V4L2_CID_FOCUS_AUTO:
        case V4L2_CID_PRIVACY:
                qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
                min = 0;
                max = step = 1;
                break;
+       case V4L2_CID_PAN_RESET:
+       case V4L2_CID_TILT_RESET:
+               qctrl->type = V4L2_CTRL_TYPE_BUTTON;
+               qctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
+               min = max = step = def = 0;
+               break;
        case V4L2_CID_POWER_LINE_FREQUENCY:
        case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
        case V4L2_CID_MPEG_AUDIO_ENCODING:
@@ -517,6 +535,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
        case V4L2_CID_MPEG_STREAM_TYPE:
        case V4L2_CID_MPEG_STREAM_VBI_FMT:
        case V4L2_CID_EXPOSURE_AUTO:
+       case V4L2_CID_COLORFX:
                qctrl->type = V4L2_CTRL_TYPE_MENU;
                step = 1;
                break;
@@ -547,161 +566,29 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
        case V4L2_CID_CONTRAST:
        case V4L2_CID_SATURATION:
        case V4L2_CID_HUE:
+       case V4L2_CID_RED_BALANCE:
+       case V4L2_CID_BLUE_BALANCE:
+       case V4L2_CID_GAMMA:
+       case V4L2_CID_SHARPNESS:
                qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
                break;
+       case V4L2_CID_PAN_RELATIVE:
+       case V4L2_CID_TILT_RELATIVE:
+       case V4L2_CID_FOCUS_RELATIVE:
+       case V4L2_CID_ZOOM_RELATIVE:
+               qctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
+               break;
        }
        qctrl->minimum = min;
        qctrl->maximum = max;
        qctrl->step = step;
        qctrl->default_value = def;
        qctrl->reserved[0] = qctrl->reserved[1] = 0;
-       snprintf(qctrl->name, sizeof(qctrl->name), name);
+       strlcpy(qctrl->name, name, sizeof(qctrl->name));
        return 0;
 }
 EXPORT_SYMBOL(v4l2_ctrl_query_fill);
 
-/* Fill in a struct v4l2_queryctrl with standard values based on
-   the control ID. */
-int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
-{
-       switch (qctrl->id) {
-       /* USER controls */
-       case V4L2_CID_USER_CLASS:
-       case V4L2_CID_MPEG_CLASS:
-               return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
-       case V4L2_CID_AUDIO_VOLUME:
-               return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 58880);
-       case V4L2_CID_AUDIO_MUTE:
-       case V4L2_CID_AUDIO_LOUDNESS:
-               return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
-       case V4L2_CID_AUDIO_BALANCE:
-       case V4L2_CID_AUDIO_BASS:
-       case V4L2_CID_AUDIO_TREBLE:
-               return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 32768);
-       case V4L2_CID_BRIGHTNESS:
-               return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
-       case V4L2_CID_CONTRAST:
-       case V4L2_CID_SATURATION:
-               return v4l2_ctrl_query_fill(qctrl, 0, 127, 1, 64);
-       case V4L2_CID_HUE:
-               return v4l2_ctrl_query_fill(qctrl, -128, 127, 1, 0);
-
-       /* MPEG controls */
-       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100,
-                               V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1,
-                               V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
-       case V4L2_CID_MPEG_AUDIO_ENCODING:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_AUDIO_ENCODING_LAYER_1,
-                               V4L2_MPEG_AUDIO_ENCODING_AC3, 1,
-                               V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
-       case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_AUDIO_L1_BITRATE_32K,
-                               V4L2_MPEG_AUDIO_L1_BITRATE_448K, 1,
-                               V4L2_MPEG_AUDIO_L1_BITRATE_256K);
-       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_AUDIO_L2_BITRATE_32K,
-                               V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
-                               V4L2_MPEG_AUDIO_L2_BITRATE_224K);
-       case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_AUDIO_L3_BITRATE_32K,
-                               V4L2_MPEG_AUDIO_L3_BITRATE_320K, 1,
-                               V4L2_MPEG_AUDIO_L3_BITRATE_192K);
-       case V4L2_CID_MPEG_AUDIO_AAC_BITRATE:
-               return v4l2_ctrl_query_fill(qctrl, 0, 6400, 1, 3200000);
-       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_AUDIO_AC3_BITRATE_32K,
-                               V4L2_MPEG_AUDIO_AC3_BITRATE_640K, 1,
-                               V4L2_MPEG_AUDIO_AC3_BITRATE_384K);
-       case V4L2_CID_MPEG_AUDIO_MODE:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_AUDIO_MODE_STEREO,
-                               V4L2_MPEG_AUDIO_MODE_MONO, 1,
-                               V4L2_MPEG_AUDIO_MODE_STEREO);
-       case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
-                               V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1,
-                               V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4);
-       case V4L2_CID_MPEG_AUDIO_EMPHASIS:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_AUDIO_EMPHASIS_NONE,
-                               V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1,
-                               V4L2_MPEG_AUDIO_EMPHASIS_NONE);
-       case V4L2_CID_MPEG_AUDIO_CRC:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_AUDIO_CRC_NONE,
-                               V4L2_MPEG_AUDIO_CRC_CRC16, 1,
-                               V4L2_MPEG_AUDIO_CRC_NONE);
-       case V4L2_CID_MPEG_AUDIO_MUTE:
-               return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
-       case V4L2_CID_MPEG_VIDEO_ENCODING:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
-                               V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
-                               V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
-       case V4L2_CID_MPEG_VIDEO_ASPECT:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_VIDEO_ASPECT_1x1,
-                               V4L2_MPEG_VIDEO_ASPECT_221x100, 1,
-                               V4L2_MPEG_VIDEO_ASPECT_4x3);
-       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
-               return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2);
-       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
-               return v4l2_ctrl_query_fill(qctrl, 1, 34, 1, 12);
-       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
-               return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
-       case V4L2_CID_MPEG_VIDEO_PULLDOWN:
-               return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
-       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
-                               V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
-                               V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
-       case V4L2_CID_MPEG_VIDEO_BITRATE:
-               return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
-       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
-               return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
-       case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
-               return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
-       case V4L2_CID_MPEG_VIDEO_MUTE:
-               return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
-       case V4L2_CID_MPEG_VIDEO_MUTE_YUV:  /* Init YUV (really YCbCr) to black */
-               return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080);
-       case V4L2_CID_MPEG_STREAM_TYPE:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
-                               V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1,
-                               V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
-       case V4L2_CID_MPEG_STREAM_PID_PMT:
-               return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16);
-       case V4L2_CID_MPEG_STREAM_PID_AUDIO:
-               return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260);
-       case V4L2_CID_MPEG_STREAM_PID_VIDEO:
-               return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256);
-       case V4L2_CID_MPEG_STREAM_PID_PCR:
-               return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259);
-       case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO:
-               return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
-       case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO:
-               return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
-       case V4L2_CID_MPEG_STREAM_VBI_FMT:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_STREAM_VBI_FMT_NONE,
-                               V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1,
-                               V4L2_MPEG_STREAM_VBI_FMT_NONE);
-       default:
-               return -EINVAL;
-       }
-}
-EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
-
 /* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and
    the menu. The qctrl pointer may be NULL, in which case it is ignored.
    If menu_items is NULL, then the menu items are retrieved using
@@ -720,7 +607,7 @@ int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qc
        for (i = 0; i < qmenu->index && menu_items[i]; i++) ;
        if (menu_items[i] == NULL || menu_items[i][0] == '\0')
                return -EINVAL;
-       snprintf(qmenu->name, sizeof(qmenu->name), menu_items[qmenu->index]);
+       strlcpy(qmenu->name, menu_items[qmenu->index], sizeof(qmenu->name));
        return 0;
 }
 EXPORT_SYMBOL(v4l2_ctrl_query_menu);
@@ -737,8 +624,8 @@ int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *id
                return -EINVAL;
        while (*ids != V4L2_CTRL_MENU_IDS_END) {
                if (*ids++ == qmenu->index) {
-                       snprintf(qmenu->name, sizeof(qmenu->name),
-                                      menu_items[qmenu->index]);
+                       strlcpy(qmenu->name, menu_items[qmenu->index],
+                                       sizeof(qmenu->name));
                        return 0;
                }
        }
@@ -749,7 +636,7 @@ EXPORT_SYMBOL(v4l2_ctrl_query_menu_valid_items);
 /* ctrl_classes points to an array of u32 pointers, the last element is
    a NULL pointer. Each u32 array is a 0-terminated array of control IDs.
    Each array must be sorted low to high and belong to the same control
-   class. The array of u32 pointer must also be sorted, from low class IDs
+   class. The array of u32 pointers must also be sorted, from low class IDs
    to high class IDs.
 
    This function returns the first ID that follows after the given ID.
@@ -910,10 +797,10 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter,
        struct i2c_board_info info;
 
        BUG_ON(!dev);
-#ifdef MODULE
+
        if (module_name)
                request_module(module_name);
-#endif
+
        /* Setup the i2c board info with the device type and
           the device address. */
        memset(&info, 0, sizeof(info));
@@ -927,11 +814,11 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter,
           We need better support from the kernel so that we
           can easily wait for the load to finish. */
        if (client == NULL || client->driver == NULL)
-               return NULL;
+               goto error;
 
        /* Lock the module so we can safely get the v4l2_subdev pointer */
        if (!try_module_get(client->driver->driver.owner))
-               return NULL;
+               goto error;
        sd = i2c_get_clientdata(client);
 
        /* Register with the v4l2_device which increases the module's
@@ -940,8 +827,13 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter,
                sd = NULL;
        /* Decrease the module use count to match the first try_module_get. */
        module_put(client->driver->driver.owner);
-       return sd;
 
+error:
+       /* If we have a client but no subdev, then something went wrong and
+          we must unregister the client. */
+       if (client && sd == NULL)
+               i2c_unregister_device(client);
+       return sd;
 }
 EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
 
@@ -958,10 +850,10 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter,
        struct i2c_board_info info;
 
        BUG_ON(!dev);
-#ifdef MODULE
+
        if (module_name)
                request_module(module_name);
-#endif
+
        /* Setup the i2c board info with the device type and
           the device address. */
        memset(&info, 0, sizeof(info));
@@ -974,11 +866,11 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter,
           We need better support from the kernel so that we
           can easily wait for the load to finish. */
        if (client == NULL || client->driver == NULL)
-               return NULL;
+               goto error;
 
        /* Lock the module so we can safely get the v4l2_subdev pointer */
        if (!try_module_get(client->driver->driver.owner))
-               return NULL;
+               goto error;
        sd = i2c_get_clientdata(client);
 
        /* Register with the v4l2_device which increases the module's
@@ -987,8 +879,59 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter,
                sd = NULL;
        /* Decrease the module use count to match the first try_module_get. */
        module_put(client->driver->driver.owner);
+
+error:
+       /* If we have a client but no subdev, then something went wrong and
+          we must unregister the client. */
+       if (client && sd == NULL)
+               i2c_unregister_device(client);
        return sd;
 }
 EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev);
 
+/* Return i2c client address of v4l2_subdev. */
+unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return client ? client->addr : I2C_CLIENT_END;
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_addr);
+
+/* Return a list of I2C tuner addresses to probe. Use only if the tuner
+   addresses are unknown. */
+const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type)
+{
+       static const unsigned short radio_addrs[] = {
+#if defined(CONFIG_MEDIA_TUNER_TEA5761) || defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE)
+               0x10,
+#endif
+               0x60,
+               I2C_CLIENT_END
+       };
+       static const unsigned short demod_addrs[] = {
+               0x42, 0x43, 0x4a, 0x4b,
+               I2C_CLIENT_END
+       };
+       static const unsigned short tv_addrs[] = {
+               0x42, 0x43, 0x4a, 0x4b,         /* tda8290 */
+               0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+               0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+               I2C_CLIENT_END
+       };
+
+       switch (type) {
+       case ADDRS_RADIO:
+               return radio_addrs;
+       case ADDRS_DEMOD:
+               return demod_addrs;
+       case ADDRS_TV:
+               return tv_addrs;
+       case ADDRS_TV_WITH_DEMOD:
+               return tv_addrs + 4;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs);
+
 #endif
index 110376be5d2b247921d390f5ea1e503d3c82331d..0056b115b42e488239b56bc7793e1a105a67c0b2 100644 (file)
@@ -1047,7 +1047,6 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
        case VIDIOC_DBG_S_REGISTER:
        case VIDIOC_DBG_G_REGISTER:
        case VIDIOC_DBG_G_CHIP_IDENT:
-       case VIDIOC_G_CHIP_IDENT_OLD:
        case VIDIOC_S_HW_FREQ_SEEK:
                ret = do_video_ioctl(file, cmd, arg);
                break;
index 13f87c22e78dce1721bb10c464409786df685c2c..91228b3df07d92f639804c89d1a98953829f6bd9 100644 (file)
@@ -198,6 +198,23 @@ static long v4l2_unlocked_ioctl(struct file *filp,
        return vdev->fops->unlocked_ioctl(filp, cmd, arg);
 }
 
+#ifdef CONFIG_MMU
+#define v4l2_get_unmapped_area NULL
+#else
+static unsigned long v4l2_get_unmapped_area(struct file *filp,
+               unsigned long addr, unsigned long len, unsigned long pgoff,
+               unsigned long flags)
+{
+       struct video_device *vdev = video_devdata(filp);
+
+       if (!vdev->fops->get_unmapped_area)
+               return -ENOSYS;
+       if (video_is_unregistered(vdev))
+               return -ENODEV;
+       return vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags);
+}
+#endif
+
 static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
 {
        struct video_device *vdev = video_devdata(filp);
@@ -250,6 +267,7 @@ static const struct file_operations v4l2_unlocked_fops = {
        .read = v4l2_read,
        .write = v4l2_write,
        .open = v4l2_open,
+       .get_unmapped_area = v4l2_get_unmapped_area,
        .mmap = v4l2_mmap,
        .unlocked_ioctl = v4l2_unlocked_ioctl,
 #ifdef CONFIG_COMPAT
@@ -265,6 +283,7 @@ static const struct file_operations v4l2_fops = {
        .read = v4l2_read,
        .write = v4l2_write,
        .open = v4l2_open,
+       .get_unmapped_area = v4l2_get_unmapped_area,
        .mmap = v4l2_mmap,
        .ioctl = v4l2_ioctl,
 #ifdef CONFIG_COMPAT
@@ -288,37 +307,38 @@ static const struct file_operations v4l2_fops = {
  */
 static int get_index(struct video_device *vdev, int num)
 {
-       u32 used = 0;
-       const int max_index = sizeof(used) * 8 - 1;
+       /* This can be static since this function is called with the global
+          videodev_lock held. */
+       static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES);
        int i;
 
-       /* Currently a single v4l driver instance cannot create more than
-          32 devices.
-          Increase to u64 or an array of u32 if more are needed. */
-       if (num > max_index) {
+       if (num >= VIDEO_NUM_DEVICES) {
                printk(KERN_ERR "videodev: %s num is too large\n", __func__);
                return -EINVAL;
        }
 
-       /* Some drivers do not set the parent. In that case always return 0. */
+       /* Some drivers do not set the parent. In that case always return
+          num or 0. */
        if (vdev->parent == NULL)
-               return 0;
+               return num >= 0 ? num : 0;
+
+       bitmap_zero(used, VIDEO_NUM_DEVICES);
 
        for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
                if (video_device[i] != NULL &&
                    video_device[i]->parent == vdev->parent) {
-                       used |= 1 << video_device[i]->index;
+                       set_bit(video_device[i]->index, used);
                }
        }
 
        if (num >= 0) {
-               if (used & (1 << num))
+               if (test_bit(num, used))
                        return -ENFILE;
                return num;
        }
 
-       i = ffz(used);
-       return i > max_index ? -ENFILE : i;
+       i = find_first_zero_bit(used, VIDEO_NUM_DEVICES);
+       return i == VIDEO_NUM_DEVICES ? -ENFILE : i;
 }
 
 int video_register_device(struct video_device *vdev, int type, int nr)
@@ -365,12 +385,11 @@ int video_register_device_index(struct video_device *vdev, int type, int nr,
 
        /* A minor value of -1 marks this video device as never
           having been registered */
-       if (vdev)
-               vdev->minor = -1;
+       vdev->minor = -1;
 
        /* the release callback MUST be present */
-       WARN_ON(!vdev || !vdev->release);
-       if (!vdev || !vdev->release)
+       WARN_ON(!vdev->release);
+       if (!vdev->release)
                return -EINVAL;
 
        /* Part 1: check device type */
@@ -395,7 +414,7 @@ int video_register_device_index(struct video_device *vdev, int type, int nr,
 
        vdev->vfl_type = type;
        vdev->cdev = NULL;
-       if (vdev->v4l2_dev)
+       if (vdev->v4l2_dev && vdev->v4l2_dev->dev)
                vdev->parent = vdev->v4l2_dev->dev;
 
        /* Part 2: find a free minor, kernel number and device index. */
@@ -582,6 +601,7 @@ module_exit(videodev_exit)
 MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(VIDEO_MAJOR);
 
 
 /*
index 8a4b74f3129f7978ba6c6a7e0d1940199d3a8dae..94aa485ade52efb9b87a01871366b8363a39143b 100644 (file)
 
 int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
 {
-       if (dev == NULL || v4l2_dev == NULL)
+       if (v4l2_dev == NULL)
                return -EINVAL;
-       /* Warn if we apparently re-register a device */
-       WARN_ON(dev_get_drvdata(dev) != NULL);
+
        INIT_LIST_HEAD(&v4l2_dev->subdevs);
        spin_lock_init(&v4l2_dev->lock);
        v4l2_dev->dev = dev;
-       snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
+       if (dev == NULL) {
+               /* If dev == NULL, then name must be filled in by the caller */
+               WARN_ON(!v4l2_dev->name[0]);
+               return 0;
+       }
+
+       /* Set name to driver name + device name if it is empty. */
+       if (!v4l2_dev->name[0])
+               snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
                        dev->driver->name, dev_name(dev));
+       if (dev_get_drvdata(dev))
+               v4l2_warn(v4l2_dev, "Non-NULL drvdata on register\n");
        dev_set_drvdata(dev, v4l2_dev);
        return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_device_register);
 
+void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
+{
+       if (v4l2_dev->dev) {
+               dev_set_drvdata(v4l2_dev->dev, NULL);
+               v4l2_dev->dev = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(v4l2_device_disconnect);
+
 void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
 {
        struct v4l2_subdev *sd, *next;
 
-       if (v4l2_dev == NULL || v4l2_dev->dev == NULL)
+       if (v4l2_dev == NULL)
                return;
-       dev_set_drvdata(v4l2_dev->dev, NULL);
-       /* unregister subdevs */
+       v4l2_device_disconnect(v4l2_dev);
+
+       /* Unregister subdevs */
        list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list)
                v4l2_device_unregister_subdev(sd);
-
-       v4l2_dev->dev = NULL;
 }
 EXPORT_SYMBOL_GPL(v4l2_device_unregister);
 
-int v4l2_device_register_subdev(struct v4l2_device *dev, struct v4l2_subdev *sd)
+int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
+                                               struct v4l2_subdev *sd)
 {
        /* Check for valid input */
-       if (dev == NULL || sd == NULL || !sd->name[0])
+       if (v4l2_dev == NULL || sd == NULL || !sd->name[0])
                return -EINVAL;
        /* Warn if we apparently re-register a subdev */
-       WARN_ON(sd->dev != NULL);
+       WARN_ON(sd->v4l2_dev != NULL);
        if (!try_module_get(sd->owner))
                return -ENODEV;
-       sd->dev = dev;
-       spin_lock(&dev->lock);
-       list_add_tail(&sd->list, &dev->subdevs);
-       spin_unlock(&dev->lock);
+       sd->v4l2_dev = v4l2_dev;
+       spin_lock(&v4l2_dev->lock);
+       list_add_tail(&sd->list, &v4l2_dev->subdevs);
+       spin_unlock(&v4l2_dev->lock);
        return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
@@ -75,12 +93,12 @@ EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
 void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
 {
        /* return if it isn't registered */
-       if (sd == NULL || sd->dev == NULL)
+       if (sd == NULL || sd->v4l2_dev == NULL)
                return;
-       spin_lock(&sd->dev->lock);
+       spin_lock(&sd->v4l2_dev->lock);
        list_del(&sd->list);
-       spin_unlock(&sd->dev->lock);
-       sd->dev = NULL;
+       spin_unlock(&sd->v4l2_dev->lock);
+       sd->v4l2_dev = NULL;
        module_put(sd->owner);
 }
 EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
index 52d687b165e0c6589cc3bab0e29f953b6625b295..f41c6f506f4209e11ba7885f1833a43ad7656f62 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/kernel.h>
 
 #define __OLD_VIDIOC_ /* To allow fixing old calls */
+#include <linux/videodev.h>
 #include <linux/videodev2.h>
 
 #ifdef CONFIG_VIDEO_V4L1
@@ -24,7 +25,7 @@
 #endif
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
-#include <linux/video_decoder.h>
+#include <media/v4l2-chip-ident.h>
 
 #define dbgarg(cmd, fmt, arg...) \
                do {                                                    \
@@ -100,25 +101,27 @@ const char *v4l2_norm_to_name(v4l2_std_id id)
 }
 EXPORT_SYMBOL(v4l2_norm_to_name);
 
+/* Returns frame period for the given standard */
+void v4l2_video_std_frame_period(int id, struct v4l2_fract *frameperiod)
+{
+       if (id & V4L2_STD_525_60) {
+               frameperiod->numerator = 1001;
+               frameperiod->denominator = 30000;
+       } else {
+               frameperiod->numerator = 1;
+               frameperiod->denominator = 25;
+       }
+}
+EXPORT_SYMBOL(v4l2_video_std_frame_period);
+
 /* Fill in the fields of a v4l2_standard structure according to the
    'id' and 'transmission' parameters.  Returns negative on error.  */
 int v4l2_video_std_construct(struct v4l2_standard *vs,
                             int id, const char *name)
 {
-       u32 index = vs->index;
-
-       memset(vs, 0, sizeof(struct v4l2_standard));
-       vs->index = index;
-       vs->id    = id;
-       if (id & V4L2_STD_525_60) {
-               vs->frameperiod.numerator = 1001;
-               vs->frameperiod.denominator = 30000;
-               vs->framelines = 525;
-       } else {
-               vs->frameperiod.numerator = 1;
-               vs->frameperiod.denominator = 25;
-               vs->framelines = 625;
-       }
+       vs->id = id;
+       v4l2_video_std_frame_period(id, &vs->frameperiod);
+       vs->framelines = (id & V4L2_STD_525_60) ? 525 : 625;
        strlcpy(vs->name, name, sizeof(vs->name));
        return 0;
 }
@@ -273,19 +276,6 @@ static const char *v4l2_ioctls[] = {
 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
 
 static const char *v4l2_int_ioctls[] = {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       [_IOC_NR(DECODER_GET_CAPABILITIES)]    = "DECODER_GET_CAPABILITIES",
-       [_IOC_NR(DECODER_GET_STATUS)]          = "DECODER_GET_STATUS",
-       [_IOC_NR(DECODER_SET_NORM)]            = "DECODER_SET_NORM",
-       [_IOC_NR(DECODER_SET_INPUT)]           = "DECODER_SET_INPUT",
-       [_IOC_NR(DECODER_SET_OUTPUT)]          = "DECODER_SET_OUTPUT",
-       [_IOC_NR(DECODER_ENABLE_OUTPUT)]       = "DECODER_ENABLE_OUTPUT",
-       [_IOC_NR(DECODER_SET_PICTURE)]         = "DECODER_SET_PICTURE",
-       [_IOC_NR(DECODER_SET_GPIO)]            = "DECODER_SET_GPIO",
-       [_IOC_NR(DECODER_INIT)]                = "DECODER_INIT",
-       [_IOC_NR(DECODER_SET_VBI_BYPASS)]      = "DECODER_SET_VBI_BYPASS",
-       [_IOC_NR(DECODER_DUMP)]                = "DECODER_DUMP",
-#endif
        [_IOC_NR(AUDC_SET_RADIO)]              = "AUDC_SET_RADIO",
 
        [_IOC_NR(TUNER_SET_TYPE_ADDR)]         = "TUNER_SET_TYPE_ADDR",
@@ -654,8 +644,6 @@ static long __video_do_ioctl(struct file *file,
        if (cmd == VIDIOCGMBUF) {
                struct video_mbuf *p = arg;
 
-               memset(p, 0, sizeof(*p));
-
                if (!ops->vidiocgmbuf)
                        return ret;
                ret = ops->vidiocgmbuf(file, fh, p);
@@ -682,7 +670,6 @@ static long __video_do_ioctl(struct file *file,
        case VIDIOC_QUERYCAP:
        {
                struct v4l2_capability *cap = (struct v4l2_capability *)arg;
-               memset(cap, 0, sizeof(*cap));
 
                if (!ops->vidioc_querycap)
                        break;
@@ -725,16 +712,8 @@ static long __video_do_ioctl(struct file *file,
        case VIDIOC_ENUM_FMT:
        {
                struct v4l2_fmtdesc *f = arg;
-               enum v4l2_buf_type type;
-               unsigned int index;
-
-               index = f->index;
-               type  = f->type;
-               memset(f, 0, sizeof(*f));
-               f->index = index;
-               f->type  = type;
 
-               switch (type) {
+               switch (f->type) {
                case V4L2_BUF_TYPE_VIDEO_CAPTURE:
                        if (ops->vidioc_enum_fmt_vid_cap)
                                ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f);
@@ -771,8 +750,6 @@ static long __video_do_ioctl(struct file *file,
        {
                struct v4l2_format *f = (struct v4l2_format *)arg;
 
-               memset(f->fmt.raw_data, 0, sizeof(f->fmt.raw_data));
-
                /* FIXME: Should be one dump per type */
                dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
 
@@ -1088,7 +1065,6 @@ static long __video_do_ioctl(struct file *file,
                        return -EINVAL;
 
                v4l2_video_std_construct(p, curr_id, descr);
-               p->index = index;
 
                dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, "
                                "framelines=%d\n", p->index,
@@ -1153,12 +1129,9 @@ static long __video_do_ioctl(struct file *file,
        case VIDIOC_ENUMINPUT:
        {
                struct v4l2_input *p = arg;
-               int i = p->index;
 
                if (!ops->vidioc_enum_input)
                        break;
-               memset(p, 0, sizeof(*p));
-               p->index = i;
 
                ret = ops->vidioc_enum_input(file, fh, p);
                if (!ret)
@@ -1197,12 +1170,9 @@ static long __video_do_ioctl(struct file *file,
        case VIDIOC_ENUMOUTPUT:
        {
                struct v4l2_output *p = arg;
-               int i = p->index;
 
                if (!ops->vidioc_enum_output)
                        break;
-               memset(p, 0, sizeof(*p));
-               p->index = i;
 
                ret = ops->vidioc_enum_output(file, fh, p);
                if (!ret)
@@ -1378,13 +1348,10 @@ static long __video_do_ioctl(struct file *file,
        case VIDIOC_G_AUDIO:
        {
                struct v4l2_audio *p = arg;
-               __u32 index = p->index;
 
                if (!ops->vidioc_g_audio)
                        break;
 
-               memset(p, 0, sizeof(*p));
-               p->index = index;
                ret = ops->vidioc_g_audio(file, fh, p);
                if (!ret)
                        dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
@@ -1426,7 +1393,7 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_g_audout)
                        break;
-               dbgarg(cmd, "Enum for index=%d\n", p->index);
+
                ret = ops->vidioc_g_audout(file, fh, p);
                if (!ret)
                        dbgarg2("index=%d, name=%s, capability=%d, "
@@ -1479,15 +1446,10 @@ static long __video_do_ioctl(struct file *file,
        case VIDIOC_G_CROP:
        {
                struct v4l2_crop *p = arg;
-               __u32 type;
 
                if (!ops->vidioc_g_crop)
                        break;
 
-               type = p->type;
-               memset(p, 0, sizeof(*p));
-               p->type = type;
-
                dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
                ret = ops->vidioc_g_crop(file, fh, p);
                if (!ret)
@@ -1508,16 +1470,11 @@ static long __video_do_ioctl(struct file *file,
        case VIDIOC_CROPCAP:
        {
                struct v4l2_cropcap *p = arg;
-               __u32 type;
 
                /*FIXME: Should also show v4l2_fract pixelaspect */
                if (!ops->vidioc_cropcap)
                        break;
 
-               type = p->type;
-               memset(p, 0, sizeof(*p));
-               p->type = type;
-
                dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
                ret = ops->vidioc_cropcap(file, fh, p);
                if (!ret) {
@@ -1533,8 +1490,6 @@ static long __video_do_ioctl(struct file *file,
                if (!ops->vidioc_g_jpegcomp)
                        break;
 
-               memset(p, 0, sizeof(*p));
-
                ret = ops->vidioc_g_jpegcomp(file, fh, p);
                if (!ret)
                        dbgarg(cmd, "quality=%d, APPn=%d, "
@@ -1575,7 +1530,6 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_encoder_cmd)
                        break;
-               memset(&p->raw, 0, sizeof(p->raw));
                ret = ops->vidioc_encoder_cmd(file, fh, p);
                if (!ret)
                        dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1587,7 +1541,6 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_try_encoder_cmd)
                        break;
-               memset(&p->raw, 0, sizeof(p->raw));
                ret = ops->vidioc_try_encoder_cmd(file, fh, p);
                if (!ret)
                        dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1596,23 +1549,18 @@ static long __video_do_ioctl(struct file *file,
        case VIDIOC_G_PARM:
        {
                struct v4l2_streamparm *p = arg;
-               __u32 type = p->type;
-
-               memset(p, 0, sizeof(*p));
-               p->type = type;
 
                if (ops->vidioc_g_parm) {
+                       ret = check_fmt(ops, p->type);
+                       if (ret)
+                               break;
                        ret = ops->vidioc_g_parm(file, fh, p);
                } else {
-                       struct v4l2_standard s;
-
                        if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                                return -EINVAL;
 
-                       v4l2_video_std_construct(&s, vfd->current_norm,
-                                                v4l2_norm_to_name(vfd->current_norm));
-
-                       p->parm.capture.timeperframe = s.frameperiod;
+                       v4l2_video_std_frame_period(vfd->current_norm,
+                                                   &p->parm.capture.timeperframe);
                        ret = 0;
                }
 
@@ -1625,6 +1573,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_s_parm)
                        break;
+               ret = check_fmt(ops, p->type);
+               if (ret)
+                       break;
+
                dbgarg(cmd, "type=%d\n", p->type);
                ret = ops->vidioc_s_parm(file, fh, p);
                break;
@@ -1632,14 +1584,10 @@ static long __video_do_ioctl(struct file *file,
        case VIDIOC_G_TUNER:
        {
                struct v4l2_tuner *p = arg;
-               __u32 index = p->index;
 
                if (!ops->vidioc_g_tuner)
                        break;
 
-               memset(p, 0, sizeof(*p));
-               p->index = index;
-
                ret = ops->vidioc_g_tuner(file, fh, p);
                if (!ret)
                        dbgarg(cmd, "index=%d, name=%s, type=%d, "
@@ -1676,8 +1624,6 @@ static long __video_do_ioctl(struct file *file,
                if (!ops->vidioc_g_frequency)
                        break;
 
-               memset(p->reserved, 0, sizeof(p->reserved));
-
                ret = ops->vidioc_g_frequency(file, fh, p);
                if (!ret)
                        dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
@@ -1698,12 +1644,13 @@ static long __video_do_ioctl(struct file *file,
        case VIDIOC_G_SLICED_VBI_CAP:
        {
                struct v4l2_sliced_vbi_cap *p = arg;
-               __u32 type = p->type;
 
                if (!ops->vidioc_g_sliced_vbi_cap)
                        break;
-               memset(p, 0, sizeof(*p));
-               p->type = type;
+
+               /* Clear up to type, everything after type is zerod already */
+               memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type));
+
                dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
                ret = ops->vidioc_g_sliced_vbi_cap(file, fh, p);
                if (!ret)
@@ -1745,16 +1692,13 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_g_chip_ident)
                        break;
+               p->ident = V4L2_IDENT_NONE;
+               p->revision = 0;
                ret = ops->vidioc_g_chip_ident(file, fh, p);
                if (!ret)
                        dbgarg(cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision);
                break;
        }
-       case VIDIOC_G_CHIP_IDENT_OLD:
-               printk(KERN_ERR "VIDIOC_G_CHIP_IDENT has been deprecated and will disappear in 2.6.30.\n");
-               printk(KERN_ERR "It is a debugging ioctl and must not be used in applications!\n");
-               return -EINVAL;
-
        case VIDIOC_S_HW_FREQ_SEEK:
        {
                struct v4l2_hw_freq_seek *p = arg;
@@ -1774,8 +1718,6 @@ static long __video_do_ioctl(struct file *file,
                if (!ops->vidioc_enum_framesizes)
                        break;
 
-               memset(p, 0, sizeof(*p));
-
                ret = ops->vidioc_enum_framesizes(file, fh, p);
                dbgarg(cmd,
                        "index=%d, pixelformat=%d, type=%d ",
@@ -1807,8 +1749,6 @@ static long __video_do_ioctl(struct file *file,
                if (!ops->vidioc_enum_frameintervals)
                        break;
 
-               memset(p, 0, sizeof(*p));
-
                ret = ops->vidioc_enum_frameintervals(file, fh, p);
                dbgarg(cmd,
                        "index=%d, pixelformat=%d, width=%d, height=%d, type=%d ",
@@ -1857,6 +1797,45 @@ static long __video_do_ioctl(struct file *file,
        return ret;
 }
 
+/* In some cases, only a few fields are used as input, i.e. when the app sets
+ * "index" and then the driver fills in the rest of the structure for the thing
+ * with that index.  We only need to copy up the first non-input field.  */
+static unsigned long cmd_input_size(unsigned int cmd)
+{
+       /* Size of structure up to and including 'field' */
+#define CMDINSIZE(cmd, type, field)                            \
+       case VIDIOC_##cmd:                                      \
+               return offsetof(struct v4l2_##type, field) +    \
+                       sizeof(((struct v4l2_##type *)0)->field);
+
+       switch (cmd) {
+               CMDINSIZE(ENUM_FMT,             fmtdesc,        type);
+               CMDINSIZE(G_FMT,                format,         type);
+               CMDINSIZE(QUERYBUF,             buffer,         type);
+               CMDINSIZE(G_PARM,               streamparm,     type);
+               CMDINSIZE(ENUMSTD,              standard,       index);
+               CMDINSIZE(ENUMINPUT,            input,          index);
+               CMDINSIZE(G_CTRL,               control,        id);
+               CMDINSIZE(G_TUNER,              tuner,          index);
+               CMDINSIZE(QUERYCTRL,            queryctrl,      id);
+               CMDINSIZE(QUERYMENU,            querymenu,      index);
+               CMDINSIZE(ENUMOUTPUT,           output,         index);
+               CMDINSIZE(G_MODULATOR,          modulator,      index);
+               CMDINSIZE(G_FREQUENCY,          frequency,      tuner);
+               CMDINSIZE(CROPCAP,              cropcap,        type);
+               CMDINSIZE(G_CROP,               crop,           type);
+               CMDINSIZE(ENUMAUDIO,            audio,          index);
+               CMDINSIZE(ENUMAUDOUT,           audioout,       index);
+               CMDINSIZE(ENCODER_CMD,          encoder_cmd,    flags);
+               CMDINSIZE(TRY_ENCODER_CMD,      encoder_cmd,    flags);
+               CMDINSIZE(G_SLICED_VBI_CAP,     sliced_vbi_cap, type);
+               CMDINSIZE(ENUM_FRAMESIZES,      frmsizeenum,    pixel_format);
+               CMDINSIZE(ENUM_FRAMEINTERVALS,  frmivalenum,    height);
+       default:
+               return _IOC_SIZE(cmd);
+       }
+}
+
 long video_ioctl2(struct file *file,
               unsigned int cmd, unsigned long arg)
 {
@@ -1875,13 +1854,7 @@ long video_ioctl2(struct file *file,
                       cmd == VIDIOC_TRY_EXT_CTRLS);
 
        /*  Copy arguments into temp kernel buffer  */
-       switch (_IOC_DIR(cmd)) {
-       case _IOC_NONE:
-               parg = NULL;
-               break;
-       case _IOC_READ:
-       case _IOC_WRITE:
-       case (_IOC_WRITE | _IOC_READ):
+       if (_IOC_DIR(cmd) != _IOC_NONE) {
                if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
                        parg = sbuf;
                } else {
@@ -1893,10 +1866,19 @@ long video_ioctl2(struct file *file,
                }
 
                err = -EFAULT;
-               if (_IOC_DIR(cmd) & _IOC_WRITE)
-                       if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+               if (_IOC_DIR(cmd) & _IOC_WRITE) {
+                       unsigned long n = cmd_input_size(cmd);
+
+                       if (copy_from_user(parg, (void __user *)arg, n))
                                goto out;
-               break;
+
+                       /* zero out anything we don't copy from userspace */
+                       if (n < _IOC_SIZE(cmd))
+                               memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
+               } else {
+                       /* read-only ioctl */
+                       memset(parg, 0, _IOC_SIZE(cmd));
+               }
        }
 
        if (is_ext_ctrl) {
index 21208805ea9bb67991de26a14738cf2b486247d2..dc881671d536993e98616711304ba04164c27bca 100644 (file)
@@ -33,6 +33,12 @@ int v4l2_subdev_command(struct v4l2_subdev *sd, unsigned cmd, void *arg)
                return v4l2_subdev_call(sd, core, g_ctrl, arg);
        case VIDIOC_S_CTRL:
                return v4l2_subdev_call(sd, core, s_ctrl, arg);
+       case VIDIOC_G_EXT_CTRLS:
+               return v4l2_subdev_call(sd, core, g_ext_ctrls, arg);
+       case VIDIOC_S_EXT_CTRLS:
+               return v4l2_subdev_call(sd, core, s_ext_ctrls, arg);
+       case VIDIOC_TRY_EXT_CTRLS:
+               return v4l2_subdev_call(sd, core, try_ext_ctrls, arg);
        case VIDIOC_QUERYMENU:
                return v4l2_subdev_call(sd, core, querymenu, arg);
        case VIDIOC_LOG_STATUS:
@@ -92,16 +98,28 @@ int v4l2_subdev_command(struct v4l2_subdev *sd, unsigned cmd, void *arg)
                return v4l2_subdev_call(sd, video, g_vbi_data, arg);
        case VIDIOC_G_SLICED_VBI_CAP:
                return v4l2_subdev_call(sd, video, g_sliced_vbi_cap, arg);
+       case VIDIOC_ENUM_FMT:
+               return v4l2_subdev_call(sd, video, enum_fmt, arg);
+       case VIDIOC_TRY_FMT:
+               return v4l2_subdev_call(sd, video, try_fmt, arg);
        case VIDIOC_S_FMT:
                return v4l2_subdev_call(sd, video, s_fmt, arg);
        case VIDIOC_G_FMT:
                return v4l2_subdev_call(sd, video, g_fmt, arg);
        case VIDIOC_INT_S_STD_OUTPUT:
                return v4l2_subdev_call(sd, video, s_std_output, *(v4l2_std_id *)arg);
+       case VIDIOC_QUERYSTD:
+               return v4l2_subdev_call(sd, video, querystd, arg);
+       case VIDIOC_INT_G_INPUT_STATUS:
+               return v4l2_subdev_call(sd, video, g_input_status, arg);
        case VIDIOC_STREAMON:
                return v4l2_subdev_call(sd, video, s_stream, 1);
        case VIDIOC_STREAMOFF:
                return v4l2_subdev_call(sd, video, s_stream, 0);
+       case VIDIOC_S_PARM:
+               return v4l2_subdev_call(sd, video, s_parm, arg);
+       case VIDIOC_G_PARM:
+               return v4l2_subdev_call(sd, video, g_parm, arg);
 
        default:
                return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
index 31944b11e6ea409fa454eb1f02a99f7e761f2e4e..6109fb5f34e2bb9b54ae7a1a289c8144c9ea86f3 100644 (file)
@@ -400,7 +400,7 @@ void videobuf_dma_contig_free(struct videobuf_queue *q,
           So, it should free memory only if the memory were allocated for
           read() operation.
         */
-       if ((buf->memory != V4L2_MEMORY_USERPTR) || !buf->baddr)
+       if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
                return;
 
        if (!mem)
index be65a2fb39762551d8d30c56634cf273aa909636..30ae30f99ccc38dd6f10bd0b0685e7e881111099 100644 (file)
@@ -425,7 +425,7 @@ void videobuf_vmalloc_free (struct videobuf_buffer *buf)
           So, it should free memory only if the memory were allocated for
           read() operation.
         */
-       if ((buf->memory != V4L2_MEMORY_USERPTR) || (buf->baddr == 0))
+       if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
                return;
 
        if (!mem)
index 88bf845a3d567cbe754dbd89dfe2fc3952ba0ecd..8da4dd1e0e94ac1300fb2dcd0530d6f724045fdd 100644 (file)
@@ -8,6 +8,12 @@
  *
  * Based on the previous version of the driver for 2.4 kernels by:
  * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ *
+ * v4l2_device/v4l2_subdev conversion by:
+ * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Note: this conversion is untested! Please contact the linux-media
+ * mailinglist if you can test this, together with the test results.
  */
 
 /*
 #include <linux/kmod.h>
 
 #include <linux/i2c.h>
-#include <linux/i2c-algo-sgi.h>
 
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
-#include <linux/video_decoder.h>
 #include <linux/mutex.h>
 
 #include <asm/paccess.h>
@@ -139,13 +143,23 @@ MODULE_LICENSE("GPL");
 #define VINO_DATA_NORM_PAL             1
 #define VINO_DATA_NORM_SECAM           2
 #define VINO_DATA_NORM_D1              3
-/* The following are special entries that can be used to
- * autodetect the norm. */
-#define VINO_DATA_NORM_AUTO            0xfe
-#define VINO_DATA_NORM_AUTO_EXT                0xff
 
 #define VINO_DATA_NORM_COUNT           4
 
+/* I2C controller flags */
+#define SGI_I2C_FORCE_IDLE             (0 << 0)
+#define SGI_I2C_NOT_IDLE               (1 << 0)
+#define SGI_I2C_WRITE                  (0 << 1)
+#define SGI_I2C_READ                   (1 << 1)
+#define SGI_I2C_RELEASE_BUS            (0 << 2)
+#define SGI_I2C_HOLD_BUS               (1 << 2)
+#define SGI_I2C_XFER_DONE              (0 << 4)
+#define SGI_I2C_XFER_BUSY              (1 << 4)
+#define SGI_I2C_ACK                    (0 << 5)
+#define SGI_I2C_NACK                   (1 << 5)
+#define SGI_I2C_BUS_OK                 (0 << 7)
+#define SGI_I2C_BUS_ERR                        (1 << 7)
+
 /* Internal data structure definitions */
 
 struct vino_input {
@@ -289,22 +303,20 @@ struct vino_channel_settings {
        struct vino_interrupt_data int_data;
 
        /* V4L support */
-       struct video_device *v4l_device;
-};
-
-struct vino_client {
-       /* the channel which owns this client:
-        * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */
-       unsigned int owner;
-       struct i2c_client *driver;
+       struct video_device *vdev;
 };
 
 struct vino_settings {
+       struct v4l2_device v4l2_dev;
        struct vino_channel_settings a;
        struct vino_channel_settings b;
 
-       struct vino_client decoder;
-       struct vino_client camera;
+       /* the channel which owns this client:
+        * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */
+       unsigned int decoder_owner;
+       struct v4l2_subdev *decoder;
+       unsigned int camera_owner;
+       struct v4l2_subdev *camera;
 
        /* a lock for vino register access */
        spinlock_t vino_lock;
@@ -344,11 +356,16 @@ static struct sgi_vino *vino;
 
 static struct vino_settings *vino_drvdata;
 
+#define camera_call(o, f, args...) \
+       v4l2_subdev_call(vino_drvdata->camera, o, f, ##args)
+#define decoder_call(o, f, args...) \
+       v4l2_subdev_call(vino_drvdata->decoder, o, f, ##args)
+
 static const char *vino_driver_name = "vino";
 static const char *vino_driver_description = "SGI VINO";
 static const char *vino_bus_name = "GIO64 bus";
-static const char *vino_v4l_device_name_a = "SGI VINO Channel A";
-static const char *vino_v4l_device_name_b = "SGI VINO Channel B";
+static const char *vino_vdev_name_a = "SGI VINO Channel A";
+static const char *vino_vdev_name_b = "SGI VINO Channel B";
 
 static void vino_capture_tasklet(unsigned long channel);
 
@@ -360,11 +377,11 @@ static const struct vino_input vino_inputs[] = {
                .name           = "Composite",
                .std            = V4L2_STD_NTSC | V4L2_STD_PAL
                | V4L2_STD_SECAM,
-       },{
+       }, {
                .name           = "S-Video",
                .std            = V4L2_STD_NTSC | V4L2_STD_PAL
                | V4L2_STD_SECAM,
-       },{
+       }, {
                .name           = "D1/IndyCam",
                .std            = V4L2_STD_NTSC,
        }
@@ -376,17 +393,17 @@ static const struct vino_data_format vino_data_formats[] = {
                .bpp            = 1,
                .pixelformat    = V4L2_PIX_FMT_GREY,
                .colorspace     = V4L2_COLORSPACE_SMPTE170M,
-       },{
+       }, {
                .description    = "8-bit dithered RGB 3-3-2",
                .bpp            = 1,
                .pixelformat    = V4L2_PIX_FMT_RGB332,
                .colorspace     = V4L2_COLORSPACE_SRGB,
-       },{
+       }, {
                .description    = "32-bit RGB",
                .bpp            = 4,
                .pixelformat    = V4L2_PIX_FMT_RGB32,
                .colorspace     = V4L2_COLORSPACE_SRGB,
-       },{
+       }, {
                .description    = "YUV 4:2:2",
                .bpp            = 2,
                .pixelformat    = V4L2_PIX_FMT_YUYV, // XXX: swapped?
@@ -417,7 +434,7 @@ static const struct vino_data_norm vino_data_norms[] = {
                        + VINO_NTSC_HEIGHT / 2 - 1,
                        .right  = VINO_NTSC_WIDTH,
                },
-       },{
+       }, {
                .description    = "PAL",
                .std            = V4L2_STD_PAL,
                .fps_min        = 5,
@@ -439,7 +456,7 @@ static const struct vino_data_norm vino_data_norms[] = {
                        + VINO_PAL_HEIGHT / 2 - 1,
                        .right  = VINO_PAL_WIDTH,
                },
-       },{
+       }, {
                .description    = "SECAM",
                .std            = V4L2_STD_SECAM,
                .fps_min        = 5,
@@ -461,7 +478,7 @@ static const struct vino_data_norm vino_data_norms[] = {
                        + VINO_PAL_HEIGHT / 2 - 1,
                        .right  = VINO_PAL_WIDTH,
                },
-       },{
+       }, {
                .description    = "NTSC/D1",
                .std            = V4L2_STD_NTSC,
                .fps_min        = 6,
@@ -497,9 +514,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
                .maximum = 1,
                .step = 1,
                .default_value = INDYCAM_AGC_DEFAULT,
-               .flags = 0,
-               .reserved = { INDYCAM_CONTROL_AGC, 0 },
-       },{
+       }, {
                .id = V4L2_CID_AUTO_WHITE_BALANCE,
                .type = V4L2_CTRL_TYPE_BOOLEAN,
                .name = "Automatic White Balance",
@@ -507,9 +522,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
                .maximum = 1,
                .step = 1,
                .default_value = INDYCAM_AWB_DEFAULT,
-               .flags = 0,
-               .reserved = { INDYCAM_CONTROL_AWB, 0 },
-       },{
+       }, {
                .id = V4L2_CID_GAIN,
                .type = V4L2_CTRL_TYPE_INTEGER,
                .name = "Gain",
@@ -517,29 +530,23 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
                .maximum = INDYCAM_GAIN_MAX,
                .step = 1,
                .default_value = INDYCAM_GAIN_DEFAULT,
-               .flags = 0,
-               .reserved = { INDYCAM_CONTROL_GAIN, 0 },
-       },{
-               .id = V4L2_CID_PRIVATE_BASE,
+       }, {
+               .id = INDYCAM_CONTROL_RED_SATURATION,
                .type = V4L2_CTRL_TYPE_INTEGER,
                .name = "Red Saturation",
                .minimum = INDYCAM_RED_SATURATION_MIN,
                .maximum = INDYCAM_RED_SATURATION_MAX,
                .step = 1,
                .default_value = INDYCAM_RED_SATURATION_DEFAULT,
-               .flags = 0,
-               .reserved = { INDYCAM_CONTROL_RED_SATURATION, 0 },
-       },{
-               .id = V4L2_CID_PRIVATE_BASE + 1,
+       }, {
+               .id = INDYCAM_CONTROL_BLUE_SATURATION,
                .type = V4L2_CTRL_TYPE_INTEGER,
                .name = "Blue Saturation",
                .minimum = INDYCAM_BLUE_SATURATION_MIN,
                .maximum = INDYCAM_BLUE_SATURATION_MAX,
                .step = 1,
                .default_value = INDYCAM_BLUE_SATURATION_DEFAULT,
-               .flags = 0,
-               .reserved = { INDYCAM_CONTROL_BLUE_SATURATION, 0 },
-       },{
+       }, {
                .id = V4L2_CID_RED_BALANCE,
                .type = V4L2_CTRL_TYPE_INTEGER,
                .name = "Red Balance",
@@ -547,9 +554,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
                .maximum = INDYCAM_RED_BALANCE_MAX,
                .step = 1,
                .default_value = INDYCAM_RED_BALANCE_DEFAULT,
-               .flags = 0,
-               .reserved = { INDYCAM_CONTROL_RED_BALANCE, 0 },
-       },{
+       }, {
                .id = V4L2_CID_BLUE_BALANCE,
                .type = V4L2_CTRL_TYPE_INTEGER,
                .name = "Blue Balance",
@@ -557,9 +562,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
                .maximum = INDYCAM_BLUE_BALANCE_MAX,
                .step = 1,
                .default_value = INDYCAM_BLUE_BALANCE_DEFAULT,
-               .flags = 0,
-               .reserved = { INDYCAM_CONTROL_BLUE_BALANCE, 0 },
-       },{
+       }, {
                .id = V4L2_CID_EXPOSURE,
                .type = V4L2_CTRL_TYPE_INTEGER,
                .name = "Shutter Control",
@@ -567,9 +570,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
                .maximum = INDYCAM_SHUTTER_MAX,
                .step = 1,
                .default_value = INDYCAM_SHUTTER_DEFAULT,
-               .flags = 0,
-               .reserved = { INDYCAM_CONTROL_SHUTTER, 0 },
-       },{
+       }, {
                .id = V4L2_CID_GAMMA,
                .type = V4L2_CTRL_TYPE_INTEGER,
                .name = "Gamma",
@@ -577,8 +578,6 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
                .maximum = INDYCAM_GAMMA_MAX,
                .step = 1,
                .default_value = INDYCAM_GAMMA_DEFAULT,
-               .flags = 0,
-               .reserved = { INDYCAM_CONTROL_GAMMA, 0 },
        }
 };
 
@@ -593,209 +592,73 @@ struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = {
                .maximum = SAA7191_HUE_MAX,
                .step = 1,
                .default_value = SAA7191_HUE_DEFAULT,
-               .flags = 0,
-               .reserved = { SAA7191_CONTROL_HUE, 0 },
-       },{
-               .id = V4L2_CID_PRIVATE_BASE,
+       }, {
+               .id = SAA7191_CONTROL_BANDPASS,
                .type = V4L2_CTRL_TYPE_INTEGER,
                .name = "Luminance Bandpass",
                .minimum = SAA7191_BANDPASS_MIN,
                .maximum = SAA7191_BANDPASS_MAX,
                .step = 1,
                .default_value = SAA7191_BANDPASS_DEFAULT,
-               .flags = 0,
-               .reserved = { SAA7191_CONTROL_BANDPASS, 0 },
-       },{
-               .id = V4L2_CID_PRIVATE_BASE + 1,
+       }, {
+               .id = SAA7191_CONTROL_BANDPASS_WEIGHT,
                .type = V4L2_CTRL_TYPE_INTEGER,
                .name = "Luminance Bandpass Weight",
                .minimum = SAA7191_BANDPASS_WEIGHT_MIN,
                .maximum = SAA7191_BANDPASS_WEIGHT_MAX,
                .step = 1,
                .default_value = SAA7191_BANDPASS_WEIGHT_DEFAULT,
-               .flags = 0,
-               .reserved = { SAA7191_CONTROL_BANDPASS_WEIGHT, 0 },
-       },{
-               .id = V4L2_CID_PRIVATE_BASE + 2,
+       }, {
+               .id = SAA7191_CONTROL_CORING,
                .type = V4L2_CTRL_TYPE_INTEGER,
                .name = "HF Luminance Coring",
                .minimum = SAA7191_CORING_MIN,
                .maximum = SAA7191_CORING_MAX,
                .step = 1,
                .default_value = SAA7191_CORING_DEFAULT,
-               .flags = 0,
-               .reserved = { SAA7191_CONTROL_CORING, 0 },
-       },{
-               .id = V4L2_CID_PRIVATE_BASE + 3,
+       }, {
+               .id = SAA7191_CONTROL_FORCE_COLOUR,
                .type = V4L2_CTRL_TYPE_BOOLEAN,
                .name = "Force Colour",
                .minimum = SAA7191_FORCE_COLOUR_MIN,
                .maximum = SAA7191_FORCE_COLOUR_MAX,
                .step = 1,
                .default_value = SAA7191_FORCE_COLOUR_DEFAULT,
-               .flags = 0,
-               .reserved = { SAA7191_CONTROL_FORCE_COLOUR, 0 },
-       },{
-               .id = V4L2_CID_PRIVATE_BASE + 4,
+       }, {
+               .id = SAA7191_CONTROL_CHROMA_GAIN,
                .type = V4L2_CTRL_TYPE_INTEGER,
                .name = "Chrominance Gain Control",
                .minimum = SAA7191_CHROMA_GAIN_MIN,
                .maximum = SAA7191_CHROMA_GAIN_MAX,
                .step = 1,
                .default_value = SAA7191_CHROMA_GAIN_DEFAULT,
-               .flags = 0,
-               .reserved = { SAA7191_CONTROL_CHROMA_GAIN, 0 },
-       },{
-               .id = V4L2_CID_PRIVATE_BASE + 5,
+       }, {
+               .id = SAA7191_CONTROL_VTRC,
                .type = V4L2_CTRL_TYPE_BOOLEAN,
                .name = "VTR Time Constant",
                .minimum = SAA7191_VTRC_MIN,
                .maximum = SAA7191_VTRC_MAX,
                .step = 1,
                .default_value = SAA7191_VTRC_DEFAULT,
-               .flags = 0,
-               .reserved = { SAA7191_CONTROL_VTRC, 0 },
-       },{
-               .id = V4L2_CID_PRIVATE_BASE + 6,
+       }, {
+               .id = SAA7191_CONTROL_LUMA_DELAY,
                .type = V4L2_CTRL_TYPE_INTEGER,
                .name = "Luminance Delay Compensation",
                .minimum = SAA7191_LUMA_DELAY_MIN,
                .maximum = SAA7191_LUMA_DELAY_MAX,
                .step = 1,
                .default_value = SAA7191_LUMA_DELAY_DEFAULT,
-               .flags = 0,
-               .reserved = { SAA7191_CONTROL_LUMA_DELAY, 0 },
-       },{
-               .id = V4L2_CID_PRIVATE_BASE + 7,
+       }, {
+               .id = SAA7191_CONTROL_VNR,
                .type = V4L2_CTRL_TYPE_INTEGER,
                .name = "Vertical Noise Reduction",
                .minimum = SAA7191_VNR_MIN,
                .maximum = SAA7191_VNR_MAX,
                .step = 1,
                .default_value = SAA7191_VNR_DEFAULT,
-               .flags = 0,
-               .reserved = { SAA7191_CONTROL_VNR, 0 },
-       }
-};
-
-/* VINO I2C bus functions */
-
-unsigned i2c_vino_getctrl(void *data)
-{
-       return vino->i2c_control;
-}
-
-void i2c_vino_setctrl(void *data, unsigned val)
-{
-       vino->i2c_control = val;
-}
-
-unsigned i2c_vino_rdata(void *data)
-{
-       return vino->i2c_data;
-}
-
-void i2c_vino_wdata(void *data, unsigned val)
-{
-       vino->i2c_data = val;
-}
-
-static struct i2c_algo_sgi_data i2c_sgi_vino_data =
-{
-       .getctrl = &i2c_vino_getctrl,
-       .setctrl = &i2c_vino_setctrl,
-       .rdata   = &i2c_vino_rdata,
-       .wdata   = &i2c_vino_wdata,
-       .xfer_timeout = 200,
-       .ack_timeout  = 1000,
-};
-
-/*
- * There are two possible clients on VINO I2C bus, so we limit usage only
- * to them.
- */
-static int i2c_vino_client_reg(struct i2c_client *client)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-       switch (client->driver->id) {
-       case I2C_DRIVERID_SAA7191:
-               if (vino_drvdata->decoder.driver)
-                       ret = -EBUSY;
-               else
-                       vino_drvdata->decoder.driver = client;
-               break;
-       case I2C_DRIVERID_INDYCAM:
-               if (vino_drvdata->camera.driver)
-                       ret = -EBUSY;
-               else
-                       vino_drvdata->camera.driver = client;
-               break;
-       default:
-               ret = -ENODEV;
-       }
-       spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
-       return ret;
-}
-
-static int i2c_vino_client_unreg(struct i2c_client *client)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-       if (client == vino_drvdata->decoder.driver) {
-               if (vino_drvdata->decoder.owner != VINO_NO_CHANNEL)
-                       ret = -EBUSY;
-               else
-                       vino_drvdata->decoder.driver = NULL;
-       } else if (client == vino_drvdata->camera.driver) {
-               if (vino_drvdata->camera.owner != VINO_NO_CHANNEL)
-                       ret = -EBUSY;
-               else
-                       vino_drvdata->camera.driver = NULL;
        }
-       spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
-       return ret;
-}
-
-static struct i2c_adapter vino_i2c_adapter =
-{
-       .name                   = "VINO I2C bus",
-       .id                     = I2C_HW_SGI_VINO,
-       .algo_data              = &i2c_sgi_vino_data,
-       .client_register        = &i2c_vino_client_reg,
-       .client_unregister      = &i2c_vino_client_unreg,
 };
 
-static int vino_i2c_add_bus(void)
-{
-       return i2c_sgi_add_bus(&vino_i2c_adapter);
-}
-
-static int vino_i2c_del_bus(void)
-{
-       return i2c_del_adapter(&vino_i2c_adapter);
-}
-
-static int i2c_camera_command(unsigned int cmd, void *arg)
-{
-       return vino_drvdata->camera.driver->
-               driver->command(vino_drvdata->camera.driver,
-                               cmd, arg);
-}
-
-static int i2c_decoder_command(unsigned int cmd, void *arg)
-{
-       return vino_drvdata->decoder.driver->
-               driver->command(vino_drvdata->decoder.driver,
-                               cmd, arg);
-}
-
 /* VINO framebuffer/DMA descriptor management */
 
 static void vino_free_buffer_with_count(struct vino_framebuffer *fb,
@@ -1741,6 +1604,184 @@ static inline void vino_set_default_framerate(struct
        vino_set_framerate(vcs, vino_data_norms[vcs->data_norm].fps_max);
 }
 
+/* VINO I2C bus functions */
+
+struct i2c_algo_sgi_data {
+       void *data;     /* private data for lowlevel routines */
+       unsigned (*getctrl)(void *data);
+       void (*setctrl)(void *data, unsigned val);
+       unsigned (*rdata)(void *data);
+       void (*wdata)(void *data, unsigned val);
+
+       int xfer_timeout;
+       int ack_timeout;
+};
+
+static int wait_xfer_done(struct i2c_algo_sgi_data *adap)
+{
+       int i;
+
+       for (i = 0; i < adap->xfer_timeout; i++) {
+               if ((adap->getctrl(adap->data) & SGI_I2C_XFER_BUSY) == 0)
+                       return 0;
+               udelay(1);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static int wait_ack(struct i2c_algo_sgi_data *adap)
+{
+       int i;
+
+       if (wait_xfer_done(adap))
+               return -ETIMEDOUT;
+       for (i = 0; i < adap->ack_timeout; i++) {
+               if ((adap->getctrl(adap->data) & SGI_I2C_NACK) == 0)
+                       return 0;
+               udelay(1);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static int force_idle(struct i2c_algo_sgi_data *adap)
+{
+       int i;
+
+       adap->setctrl(adap->data, SGI_I2C_FORCE_IDLE);
+       for (i = 0; i < adap->xfer_timeout; i++) {
+               if ((adap->getctrl(adap->data) & SGI_I2C_NOT_IDLE) == 0)
+                       goto out;
+               udelay(1);
+       }
+       return -ETIMEDOUT;
+out:
+       if (adap->getctrl(adap->data) & SGI_I2C_BUS_ERR)
+               return -EIO;
+       return 0;
+}
+
+static int do_address(struct i2c_algo_sgi_data *adap, unsigned int addr,
+                     int rd)
+{
+       if (rd)
+               adap->setctrl(adap->data, SGI_I2C_NOT_IDLE);
+       /* Check if bus is idle, eventually force it to do so */
+       if (adap->getctrl(adap->data) & SGI_I2C_NOT_IDLE)
+               if (force_idle(adap))
+                       return -EIO;
+       /* Write out the i2c chip address and specify operation */
+       adap->setctrl(adap->data,
+                     SGI_I2C_HOLD_BUS | SGI_I2C_WRITE | SGI_I2C_NOT_IDLE);
+       if (rd)
+               addr |= 1;
+       adap->wdata(adap->data, addr);
+       if (wait_ack(adap))
+               return -EIO;
+       return 0;
+}
+
+static int i2c_read(struct i2c_algo_sgi_data *adap, unsigned char *buf,
+                   unsigned int len)
+{
+       int i;
+
+       adap->setctrl(adap->data,
+                     SGI_I2C_HOLD_BUS | SGI_I2C_READ | SGI_I2C_NOT_IDLE);
+       for (i = 0; i < len; i++) {
+               if (wait_xfer_done(adap))
+                       return -EIO;
+               buf[i] = adap->rdata(adap->data);
+       }
+       adap->setctrl(adap->data, SGI_I2C_RELEASE_BUS | SGI_I2C_FORCE_IDLE);
+
+       return 0;
+
+}
+
+static int i2c_write(struct i2c_algo_sgi_data *adap, unsigned char *buf,
+                    unsigned int len)
+{
+       int i;
+
+       /* We are already in write state */
+       for (i = 0; i < len; i++) {
+               adap->wdata(adap->data, buf[i]);
+               if (wait_ack(adap))
+                       return -EIO;
+       }
+       return 0;
+}
+
+static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
+                   int num)
+{
+       struct i2c_algo_sgi_data *adap = i2c_adap->algo_data;
+       struct i2c_msg *p;
+       int i, err = 0;
+
+       for (i = 0; !err && i < num; i++) {
+               p = &msgs[i];
+               err = do_address(adap, p->addr, p->flags & I2C_M_RD);
+               if (err || !p->len)
+                       continue;
+               if (p->flags & I2C_M_RD)
+                       err = i2c_read(adap, p->buf, p->len);
+               else
+                       err = i2c_write(adap, p->buf, p->len);
+       }
+
+       return (err < 0) ? err : i;
+}
+
+static u32 sgi_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm sgi_algo = {
+       .master_xfer    = sgi_xfer,
+       .functionality  = sgi_func,
+};
+
+static unsigned i2c_vino_getctrl(void *data)
+{
+       return vino->i2c_control;
+}
+
+static void i2c_vino_setctrl(void *data, unsigned val)
+{
+       vino->i2c_control = val;
+}
+
+static unsigned i2c_vino_rdata(void *data)
+{
+       return vino->i2c_data;
+}
+
+static void i2c_vino_wdata(void *data, unsigned val)
+{
+       vino->i2c_data = val;
+}
+
+static struct i2c_algo_sgi_data i2c_sgi_vino_data = {
+       .getctrl = &i2c_vino_getctrl,
+       .setctrl = &i2c_vino_setctrl,
+       .rdata   = &i2c_vino_rdata,
+       .wdata   = &i2c_vino_wdata,
+       .xfer_timeout = 200,
+       .ack_timeout  = 1000,
+};
+
+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,
+};
+
 /*
  * Prepare VINO for DMA transfer...
  * (execute only with vino_lock and input_lock locked)
@@ -2490,86 +2531,15 @@ static int vino_get_saa7191_input(int input)
        }
 }
 
-static int vino_get_saa7191_norm(unsigned int data_norm)
-{
-       switch (data_norm) {
-       case VINO_DATA_NORM_AUTO:
-               return SAA7191_NORM_AUTO;
-       case VINO_DATA_NORM_AUTO_EXT:
-               return SAA7191_NORM_AUTO_EXT;
-       case VINO_DATA_NORM_PAL:
-               return SAA7191_NORM_PAL;
-       case VINO_DATA_NORM_NTSC:
-               return SAA7191_NORM_NTSC;
-       case VINO_DATA_NORM_SECAM:
-               return SAA7191_NORM_SECAM;
-       default:
-               printk(KERN_ERR "VINO: vino_get_saa7191_norm(): "
-                      "invalid norm!\n");
-               return -1;
-       }
-}
-
-static int vino_get_from_saa7191_norm(int saa7191_norm)
-{
-       switch (saa7191_norm) {
-       case SAA7191_NORM_PAL:
-               return VINO_DATA_NORM_PAL;
-       case SAA7191_NORM_NTSC:
-               return VINO_DATA_NORM_NTSC;
-       case SAA7191_NORM_SECAM:
-               return VINO_DATA_NORM_SECAM;
-       default:
-               printk(KERN_ERR "VINO: vino_get_from_saa7191_norm(): "
-                      "invalid norm!\n");
-               return VINO_DATA_NORM_NONE;
-       }
-}
-
-static int vino_saa7191_set_norm(unsigned int *data_norm)
-{
-       int saa7191_norm, new_data_norm;
-       int err = 0;
-
-       saa7191_norm = vino_get_saa7191_norm(*data_norm);
-
-       err = i2c_decoder_command(DECODER_SAA7191_SET_NORM,
-                                 &saa7191_norm);
-       if (err)
-               goto out;
-
-       if ((*data_norm == VINO_DATA_NORM_AUTO)
-           || (*data_norm == VINO_DATA_NORM_AUTO_EXT)) {
-               struct saa7191_status status;
-
-               err = i2c_decoder_command(DECODER_SAA7191_GET_STATUS,
-                                         &status);
-               if (err)
-                       goto out;
-
-               new_data_norm =
-                       vino_get_from_saa7191_norm(status.norm);
-               if (new_data_norm == VINO_DATA_NORM_NONE) {
-                       err = -EINVAL;
-                       goto out;
-               }
-
-               *data_norm = (unsigned int)new_data_norm;
-       }
-
-out:
-       return err;
-}
-
 /* execute with input_lock locked */
 static int vino_is_input_owner(struct vino_channel_settings *vcs)
 {
        switch(vcs->input) {
        case VINO_INPUT_COMPOSITE:
        case VINO_INPUT_SVIDEO:
-               return (vino_drvdata->decoder.owner == vcs->channel);
+               return vino_drvdata->decoder_owner == vcs->channel;
        case VINO_INPUT_D1:
-               return (vino_drvdata->camera.owner == vcs->channel);
+               return vino_drvdata->camera_owner == vcs->channel;
        default:
                return 0;
        }
@@ -2585,23 +2555,22 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
        spin_lock_irqsave(&vino_drvdata->input_lock, flags);
 
        /* First try D1 and then SAA7191 */
-       if (vino_drvdata->camera.driver
-           && (vino_drvdata->camera.owner == VINO_NO_CHANNEL)) {
-               i2c_use_client(vino_drvdata->camera.driver);
-               vino_drvdata->camera.owner = vcs->channel;
+       if (vino_drvdata->camera
+           && (vino_drvdata->camera_owner == VINO_NO_CHANNEL)) {
+               vino_drvdata->camera_owner = vcs->channel;
                vcs->input = VINO_INPUT_D1;
                vcs->data_norm = VINO_DATA_NORM_D1;
-       } else if (vino_drvdata->decoder.driver
-                  && (vino_drvdata->decoder.owner == VINO_NO_CHANNEL)) {
-               int input, data_norm;
-               int saa7191_input;
+       } else if (vino_drvdata->decoder
+                  && (vino_drvdata->decoder_owner == VINO_NO_CHANNEL)) {
+               int input;
+               int data_norm;
+               v4l2_std_id norm;
+               struct v4l2_routing route = { 0, 0 };
 
-               i2c_use_client(vino_drvdata->decoder.driver);
                input = VINO_INPUT_COMPOSITE;
 
-               saa7191_input = vino_get_saa7191_input(input);
-               ret = i2c_decoder_command(DECODER_SET_INPUT,
-                                         &saa7191_input);
+               route.input = vino_get_saa7191_input(input);
+               ret = decoder_call(video, s_routing, &route);
                if (ret) {
                        ret = -EINVAL;
                        goto out;
@@ -2612,12 +2581,15 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
                /* Don't hold spinlocks while auto-detecting norm
                 * as it may take a while... */
 
-               data_norm = VINO_DATA_NORM_AUTO_EXT;
-
-               ret = vino_saa7191_set_norm(&data_norm);
-               if ((ret == -EBUSY) || (ret == -EAGAIN)) {
-                       data_norm = VINO_DATA_NORM_PAL;
-                       ret = vino_saa7191_set_norm(&data_norm);
+               ret = decoder_call(video, querystd, &norm);
+               if (!ret) {
+                       for (data_norm = 0; data_norm < 3; data_norm++) {
+                               if (vino_data_norms[data_norm].std & norm)
+                                       break;
+                       }
+                       if (data_norm == 3)
+                               data_norm = VINO_DATA_NORM_PAL;
+                       ret = decoder_call(tuner, s_std, norm);
                }
 
                spin_lock_irqsave(&vino_drvdata->input_lock, flags);
@@ -2627,7 +2599,7 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
                        goto out;
                }
 
-               vino_drvdata->decoder.owner = vcs->channel;
+               vino_drvdata->decoder_owner = vcs->channel;
 
                vcs->input = input;
                vcs->data_norm = data_norm;
@@ -2672,25 +2644,24 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
        switch (input) {
        case VINO_INPUT_COMPOSITE:
        case VINO_INPUT_SVIDEO:
-               if (!vino_drvdata->decoder.driver) {
+               if (!vino_drvdata->decoder) {
                        ret = -EINVAL;
                        goto out;
                }
 
-               if (vino_drvdata->decoder.owner == VINO_NO_CHANNEL) {
-                       i2c_use_client(vino_drvdata->decoder.driver);
-                       vino_drvdata->decoder.owner = vcs->channel;
+               if (vino_drvdata->decoder_owner == VINO_NO_CHANNEL) {
+                       vino_drvdata->decoder_owner = vcs->channel;
                }
 
-               if (vino_drvdata->decoder.owner == vcs->channel) {
+               if (vino_drvdata->decoder_owner == vcs->channel) {
                        int data_norm;
-                       int saa7191_input;
+                       v4l2_std_id norm;
+                       struct v4l2_routing route = { 0, 0 };
 
-                       saa7191_input = vino_get_saa7191_input(input);
-                       ret = i2c_decoder_command(DECODER_SET_INPUT,
-                                                 &saa7191_input);
+                       route.input = vino_get_saa7191_input(input);
+                       ret = decoder_call(video, s_routing, &route);
                        if (ret) {
-                               vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+                               vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
                                ret = -EINVAL;
                                goto out;
                        }
@@ -2700,18 +2671,21 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
                        /* Don't hold spinlocks while auto-detecting norm
                         * as it may take a while... */
 
-                       data_norm = VINO_DATA_NORM_AUTO_EXT;
-
-                       ret = vino_saa7191_set_norm(&data_norm);
-                       if ((ret  == -EBUSY) || (ret == -EAGAIN)) {
-                               data_norm = VINO_DATA_NORM_PAL;
-                               ret = vino_saa7191_set_norm(&data_norm);
+                       ret = decoder_call(video, querystd, &norm);
+                       if (!ret) {
+                               for (data_norm = 0; data_norm < 3; data_norm++) {
+                                       if (vino_data_norms[data_norm].std & norm)
+                                               break;
+                               }
+                               if (data_norm == 3)
+                                       data_norm = VINO_DATA_NORM_PAL;
+                               ret = decoder_call(tuner, s_std, norm);
                        }
 
                        spin_lock_irqsave(&vino_drvdata->input_lock, flags);
 
                        if (ret) {
-                               vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+                               vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
                                ret = -EINVAL;
                                goto out;
                        }
@@ -2728,37 +2702,31 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
                        vcs->data_norm = vcs2->data_norm;
                }
 
-               if (vino_drvdata->camera.owner == vcs->channel) {
+               if (vino_drvdata->camera_owner == vcs->channel) {
                        /* Transfer the ownership or release the input */
                        if (vcs2->input == VINO_INPUT_D1) {
-                               vino_drvdata->camera.owner = vcs2->channel;
+                               vino_drvdata->camera_owner = vcs2->channel;
                        } else {
-                               i2c_release_client(vino_drvdata->
-                                                  camera.driver);
-                               vino_drvdata->camera.owner = VINO_NO_CHANNEL;
+                               vino_drvdata->camera_owner = VINO_NO_CHANNEL;
                        }
                }
                break;
        case VINO_INPUT_D1:
-               if (!vino_drvdata->camera.driver) {
+               if (!vino_drvdata->camera) {
                        ret = -EINVAL;
                        goto out;
                }
 
-               if (vino_drvdata->camera.owner == VINO_NO_CHANNEL) {
-                       i2c_use_client(vino_drvdata->camera.driver);
-                       vino_drvdata->camera.owner = vcs->channel;
-               }
+               if (vino_drvdata->camera_owner == VINO_NO_CHANNEL)
+                       vino_drvdata->camera_owner = vcs->channel;
 
-               if (vino_drvdata->decoder.owner == vcs->channel) {
+               if (vino_drvdata->decoder_owner == vcs->channel) {
                        /* Transfer the ownership or release the input */
                        if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
                                 (vcs2->input == VINO_INPUT_SVIDEO)) {
-                               vino_drvdata->decoder.owner = vcs2->channel;
+                               vino_drvdata->decoder_owner = vcs2->channel;
                        } else {
-                               i2c_release_client(vino_drvdata->
-                                                  decoder.driver);
-                               vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+                               vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
                        }
                }
 
@@ -2795,20 +2763,18 @@ static void vino_release_input(struct vino_channel_settings *vcs)
        /* Release ownership of the channel
         * and if the other channel takes input from
         * the same source, transfer the ownership */
-       if (vino_drvdata->camera.owner == vcs->channel) {
+       if (vino_drvdata->camera_owner == vcs->channel) {
                if (vcs2->input == VINO_INPUT_D1) {
-                       vino_drvdata->camera.owner = vcs2->channel;
+                       vino_drvdata->camera_owner = vcs2->channel;
                } else {
-                       i2c_release_client(vino_drvdata->camera.driver);
-                       vino_drvdata->camera.owner = VINO_NO_CHANNEL;
+                       vino_drvdata->camera_owner = VINO_NO_CHANNEL;
                }
-       } else if (vino_drvdata->decoder.owner == vcs->channel) {
+       } else if (vino_drvdata->decoder_owner == vcs->channel) {
                if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
                         (vcs2->input == VINO_INPUT_SVIDEO)) {
-                       vino_drvdata->decoder.owner = vcs2->channel;
+                       vino_drvdata->decoder_owner = vcs2->channel;
                } else {
-                       i2c_release_client(vino_drvdata->decoder.driver);
-                       vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+                       vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
                }
        }
        vcs->input = VINO_INPUT_NONE;
@@ -2829,18 +2795,16 @@ static int vino_set_data_norm(struct vino_channel_settings *vcs,
        switch (vcs->input) {
        case VINO_INPUT_D1:
                /* only one "norm" supported */
-               if ((data_norm != VINO_DATA_NORM_D1)
-                   && (data_norm != VINO_DATA_NORM_AUTO)
-                   && (data_norm != VINO_DATA_NORM_AUTO_EXT))
+               if (data_norm != VINO_DATA_NORM_D1)
                        return -EINVAL;
                break;
        case VINO_INPUT_COMPOSITE:
        case VINO_INPUT_SVIDEO: {
+               v4l2_std_id norm;
+
                if ((data_norm != VINO_DATA_NORM_PAL)
                    && (data_norm != VINO_DATA_NORM_NTSC)
-                   && (data_norm != VINO_DATA_NORM_SECAM)
-                   && (data_norm != VINO_DATA_NORM_AUTO)
-                   && (data_norm != VINO_DATA_NORM_AUTO_EXT))
+                   && (data_norm != VINO_DATA_NORM_SECAM))
                        return -EINVAL;
 
                spin_unlock_irqrestore(&vino_drvdata->input_lock, *flags);
@@ -2848,7 +2812,8 @@ static int vino_set_data_norm(struct vino_channel_settings *vcs,
                /* Don't hold spinlocks while setting norm
                 * as it may take a while... */
 
-               err = vino_saa7191_set_norm(&data_norm);
+               norm = vino_data_norms[data_norm].std;
+               err = decoder_call(tuner, s_std, norm);
 
                spin_lock_irqsave(&vino_drvdata->input_lock, *flags);
 
@@ -2884,41 +2849,13 @@ static int vino_find_data_format(__u32 pixelformat)
        return VINO_DATA_FMT_NONE;
 }
 
-static int vino_enum_data_norm(struct vino_channel_settings *vcs, __u32 index)
-{
-       int data_norm = VINO_DATA_NORM_NONE;
-       unsigned long flags;
-
-       spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-       switch(vcs->input) {
-       case VINO_INPUT_COMPOSITE:
-       case VINO_INPUT_SVIDEO:
-               if (index == 0) {
-                       data_norm = VINO_DATA_NORM_PAL;
-               } else if (index == 1) {
-                       data_norm = VINO_DATA_NORM_NTSC;
-               } else if (index == 2) {
-                       data_norm = VINO_DATA_NORM_SECAM;
-               }
-               break;
-       case VINO_INPUT_D1:
-               if (index == 0) {
-                       data_norm = VINO_DATA_NORM_D1;
-               }
-               break;
-       }
-       spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
-       return data_norm;
-}
-
-static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
+static int vino_int_enum_input(struct vino_channel_settings *vcs, __u32 index)
 {
        int input = VINO_INPUT_NONE;
        unsigned long flags;
 
        spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-       if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) {
+       if (vino_drvdata->decoder && vino_drvdata->camera) {
                switch (index) {
                case 0:
                        input = VINO_INPUT_COMPOSITE;
@@ -2930,7 +2867,7 @@ static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
                        input = VINO_INPUT_D1;
                        break;
                }
-       } else if (vino_drvdata->decoder.driver) {
+       } else if (vino_drvdata->decoder) {
                switch (index) {
                case 0:
                        input = VINO_INPUT_COMPOSITE;
@@ -2939,7 +2876,7 @@ static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
                        input = VINO_INPUT_SVIDEO;
                        break;
                }
-       } else if (vino_drvdata->camera.driver) {
+       } else if (vino_drvdata->camera) {
                switch (index) {
                case 0:
                        input = VINO_INPUT_D1;
@@ -2957,7 +2894,7 @@ static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
        __u32 index = 0;
        // FIXME: detect when no inputs available
 
-       if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) {
+       if (vino_drvdata->decoder && vino_drvdata->camera) {
                switch (vcs->input) {
                case VINO_INPUT_COMPOSITE:
                        index = 0;
@@ -2969,7 +2906,7 @@ static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
                        index = 2;
                        break;
                }
-       } else if (vino_drvdata->decoder.driver) {
+       } else if (vino_drvdata->decoder) {
                switch (vcs->input) {
                case VINO_INPUT_COMPOSITE:
                        index = 0;
@@ -2978,7 +2915,7 @@ static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
                        index = 1;
                        break;
                }
-       } else if (vino_drvdata->camera.driver) {
+       } else if (vino_drvdata->camera) {
                switch (vcs->input) {
                case VINO_INPUT_D1:
                        index = 0;
@@ -2991,7 +2928,8 @@ static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
 
 /* V4L2 ioctls */
 
-static void vino_v4l2_querycap(struct v4l2_capability *cap)
+static int vino_querycap(struct file *file, void *__fh,
+               struct v4l2_capability *cap)
 {
        memset(cap, 0, sizeof(struct v4l2_capability));
 
@@ -3003,16 +2941,18 @@ static void vino_v4l2_querycap(struct v4l2_capability *cap)
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_STREAMING;
        // V4L2_CAP_OVERLAY, V4L2_CAP_READWRITE
+       return 0;
 }
 
-static int vino_v4l2_enuminput(struct vino_channel_settings *vcs,
+static int vino_enum_input(struct file *file, void *__fh,
                               struct v4l2_input *i)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        __u32 index = i->index;
        int input;
        dprintk("requested index = %d\n", index);
 
-       input = vino_enum_input(vcs, index);
+       input = vino_int_enum_input(vcs, index);
        if (input == VINO_INPUT_NONE)
                return -EINVAL;
 
@@ -3023,20 +2963,15 @@ static int vino_v4l2_enuminput(struct vino_channel_settings *vcs,
        i->std = vino_inputs[input].std;
        strcpy(i->name, vino_inputs[input].name);
 
-       if ((input == VINO_INPUT_COMPOSITE)
-           || (input == VINO_INPUT_SVIDEO)) {
-               struct saa7191_status status;
-               i2c_decoder_command(DECODER_SAA7191_GET_STATUS, &status);
-               i->status |= status.signal ? 0 : V4L2_IN_ST_NO_SIGNAL;
-               i->status |= status.color ? 0 : V4L2_IN_ST_NO_COLOR;
-       }
-
+       if (input == VINO_INPUT_COMPOSITE || input == VINO_INPUT_SVIDEO)
+               decoder_call(video, g_input_status, &i->status);
        return 0;
 }
 
-static int vino_v4l2_g_input(struct vino_channel_settings *vcs,
+static int vino_g_input(struct file *file, void *__fh,
                             unsigned int *i)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        __u32 index;
        int input;
        unsigned long flags;
@@ -3057,56 +2992,28 @@ static int vino_v4l2_g_input(struct vino_channel_settings *vcs,
        return 0;
 }
 
-static int vino_v4l2_s_input(struct vino_channel_settings *vcs,
-                            unsigned int *i)
+static int vino_s_input(struct file *file, void *__fh,
+                            unsigned int i)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        int input;
-       dprintk("requested input = %d\n", *i);
+       dprintk("requested input = %d\n", i);
 
-       input = vino_enum_input(vcs, *i);
+       input = vino_int_enum_input(vcs, i);
        if (input == VINO_INPUT_NONE)
                return -EINVAL;
 
        return vino_set_input(vcs, input);
 }
 
-static int vino_v4l2_enumstd(struct vino_channel_settings *vcs,
-                            struct v4l2_standard *s)
+static int vino_querystd(struct file *file, void *__fh,
+                             v4l2_std_id *std)
 {
-       int index = s->index;
-       int data_norm;
-
-       data_norm = vino_enum_data_norm(vcs, index);
-       dprintk("standard index = %d\n", index);
+       struct vino_channel_settings *vcs = video_drvdata(file);
+       unsigned long flags;
+       int err = 0;
 
-       if (data_norm == VINO_DATA_NORM_NONE)
-               return -EINVAL;
-
-       dprintk("standard name = %s\n",
-              vino_data_norms[data_norm].description);
-
-       memset(s, 0, sizeof(struct v4l2_standard));
-       s->index = index;
-
-       s->id = vino_data_norms[data_norm].std;
-       s->frameperiod.numerator = 1;
-       s->frameperiod.denominator =
-               vino_data_norms[data_norm].fps_max;
-       s->framelines =
-               vino_data_norms[data_norm].framelines;
-       strcpy(s->name,
-              vino_data_norms[data_norm].description);
-
-       return 0;
-}
-
-static int vino_v4l2_querystd(struct vino_channel_settings *vcs,
-                             v4l2_std_id *std)
-{
-       unsigned long flags;
-       int err = 0;
-
-       spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+       spin_lock_irqsave(&vino_drvdata->input_lock, flags);
 
        switch (vcs->input) {
        case VINO_INPUT_D1:
@@ -3114,19 +3021,7 @@ static int vino_v4l2_querystd(struct vino_channel_settings *vcs,
                break;
        case VINO_INPUT_COMPOSITE:
        case VINO_INPUT_SVIDEO: {
-               struct saa7191_status status;
-
-               i2c_decoder_command(DECODER_SAA7191_GET_STATUS, &status);
-
-               if (status.signal) {
-                       if (status.signal_60hz) {
-                               *std = V4L2_STD_NTSC;
-                       } else {
-                               *std = V4L2_STD_PAL | V4L2_STD_SECAM;
-                       }
-               } else {
-                       *std = vino_inputs[vcs->input].std;
-               }
+               decoder_call(video, querystd, std);
                break;
        }
        default:
@@ -3138,9 +3033,10 @@ static int vino_v4l2_querystd(struct vino_channel_settings *vcs,
        return err;
 }
 
-static int vino_v4l2_g_std(struct vino_channel_settings *vcs,
+static int vino_g_std(struct file *file, void *__fh,
                           v4l2_std_id *std)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        unsigned long flags;
 
        spin_lock_irqsave(&vino_drvdata->input_lock, flags);
@@ -3153,9 +3049,10 @@ static int vino_v4l2_g_std(struct vino_channel_settings *vcs,
        return 0;
 }
 
-static int vino_v4l2_s_std(struct vino_channel_settings *vcs,
+static int vino_s_std(struct file *file, void *__fh,
                           v4l2_std_id *std)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        unsigned long flags;
        int ret = 0;
 
@@ -3176,12 +3073,7 @@ static int vino_v4l2_s_std(struct vino_channel_settings *vcs,
                if (vcs->input == VINO_INPUT_D1)
                        goto out;
 
-               if (((*std) & V4L2_STD_PAL)
-                   && ((*std) & V4L2_STD_NTSC)
-                   && ((*std) & V4L2_STD_SECAM)) {
-                       ret = vino_set_data_norm(vcs, VINO_DATA_NORM_AUTO_EXT,
-                                                &flags);
-               } else if ((*std) & V4L2_STD_PAL) {
+               if ((*std) & V4L2_STD_PAL) {
                        ret = vino_set_data_norm(vcs, VINO_DATA_NORM_PAL,
                                                 &flags);
                } else if ((*std) & V4L2_STD_NTSC) {
@@ -3207,185 +3099,144 @@ out:
        return ret;
 }
 
-static int vino_v4l2_enum_fmt(struct vino_channel_settings *vcs,
+static int vino_enum_fmt_vid_cap(struct file *file, void *__fh,
                              struct v4l2_fmtdesc *fd)
 {
-       enum v4l2_buf_type type = fd->type;
-       int index = fd->index;
-       dprintk("format index = %d\n", index);
+       dprintk("format index = %d\n", fd->index);
 
-       switch (fd->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if ((fd->index < 0) ||
-                   (fd->index >= VINO_DATA_FMT_COUNT))
-                       return -EINVAL;
-               dprintk("format name = %s\n",
-                      vino_data_formats[index].description);
-
-               memset(fd, 0, sizeof(struct v4l2_fmtdesc));
-               fd->index = index;
-               fd->type = type;
-               fd->pixelformat = vino_data_formats[index].pixelformat;
-               strcpy(fd->description, vino_data_formats[index].description);
-               break;
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-       default:
+       if (fd->index >= VINO_DATA_FMT_COUNT)
                return -EINVAL;
-       }
+       dprintk("format name = %s\n", vino_data_formats[fd->index].description);
 
+       fd->pixelformat = vino_data_formats[fd->index].pixelformat;
+       strcpy(fd->description, vino_data_formats[fd->index].description);
        return 0;
 }
 
-static int vino_v4l2_try_fmt(struct vino_channel_settings *vcs,
+static int vino_try_fmt_vid_cap(struct file *file, void *__fh,
                             struct v4l2_format *f)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        struct vino_channel_settings tempvcs;
        unsigned long flags;
+       struct v4l2_pix_format *pf = &f->fmt.pix;
 
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-               struct v4l2_pix_format *pf = &f->fmt.pix;
-
-               dprintk("requested: w = %d, h = %d\n",
-                      pf->width, pf->height);
+       dprintk("requested: w = %d, h = %d\n",
+                       pf->width, pf->height);
 
-               spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-               memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings));
-               spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
-               tempvcs.data_format = vino_find_data_format(pf->pixelformat);
-               if (tempvcs.data_format == VINO_DATA_FMT_NONE) {
-                       tempvcs.data_format = VINO_DATA_FMT_GREY;
-                       pf->pixelformat =
-                               vino_data_formats[tempvcs.data_format].
-                               pixelformat;
-               }
+       spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+       memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings));
+       spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
 
-               /* data format must be set before clipping/scaling */
-               vino_set_scaling(&tempvcs, pf->width, pf->height);
+       tempvcs.data_format = vino_find_data_format(pf->pixelformat);
+       if (tempvcs.data_format == VINO_DATA_FMT_NONE) {
+               tempvcs.data_format = VINO_DATA_FMT_GREY;
+               pf->pixelformat =
+                       vino_data_formats[tempvcs.data_format].
+                       pixelformat;
+       }
 
-               dprintk("data format = %s\n",
-                      vino_data_formats[tempvcs.data_format].description);
+       /* data format must be set before clipping/scaling */
+       vino_set_scaling(&tempvcs, pf->width, pf->height);
 
-               pf->width = (tempvcs.clipping.right - tempvcs.clipping.left) /
-                       tempvcs.decimation;
-               pf->height = (tempvcs.clipping.bottom - tempvcs.clipping.top) /
-                       tempvcs.decimation;
+       dprintk("data format = %s\n",
+                       vino_data_formats[tempvcs.data_format].description);
 
-               pf->field = V4L2_FIELD_INTERLACED;
-               pf->bytesperline = tempvcs.line_size;
-               pf->sizeimage = tempvcs.line_size *
-                       (tempvcs.clipping.bottom - tempvcs.clipping.top) /
-                       tempvcs.decimation;
-               pf->colorspace =
-                       vino_data_formats[tempvcs.data_format].colorspace;
+       pf->width = (tempvcs.clipping.right - tempvcs.clipping.left) /
+               tempvcs.decimation;
+       pf->height = (tempvcs.clipping.bottom - tempvcs.clipping.top) /
+               tempvcs.decimation;
 
-               pf->priv = 0;
-               break;
-       }
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-       default:
-               return -EINVAL;
-       }
+       pf->field = V4L2_FIELD_INTERLACED;
+       pf->bytesperline = tempvcs.line_size;
+       pf->sizeimage = tempvcs.line_size *
+               (tempvcs.clipping.bottom - tempvcs.clipping.top) /
+               tempvcs.decimation;
+       pf->colorspace =
+               vino_data_formats[tempvcs.data_format].colorspace;
 
+       pf->priv = 0;
        return 0;
 }
 
-static int vino_v4l2_g_fmt(struct vino_channel_settings *vcs,
+static int vino_g_fmt_vid_cap(struct file *file, void *__fh,
                           struct v4l2_format *f)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        unsigned long flags;
+       struct v4l2_pix_format *pf = &f->fmt.pix;
 
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-               struct v4l2_pix_format *pf = &f->fmt.pix;
-
-               spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
-               pf->width = (vcs->clipping.right - vcs->clipping.left) /
-                       vcs->decimation;
-               pf->height = (vcs->clipping.bottom - vcs->clipping.top) /
-                       vcs->decimation;
-               pf->pixelformat =
-                       vino_data_formats[vcs->data_format].pixelformat;
+       spin_lock_irqsave(&vino_drvdata->input_lock, flags);
 
-               pf->field = V4L2_FIELD_INTERLACED;
-               pf->bytesperline = vcs->line_size;
-               pf->sizeimage = vcs->line_size *
-                       (vcs->clipping.bottom - vcs->clipping.top) /
-                       vcs->decimation;
-               pf->colorspace =
-                       vino_data_formats[vcs->data_format].colorspace;
+       pf->width = (vcs->clipping.right - vcs->clipping.left) /
+               vcs->decimation;
+       pf->height = (vcs->clipping.bottom - vcs->clipping.top) /
+               vcs->decimation;
+       pf->pixelformat =
+               vino_data_formats[vcs->data_format].pixelformat;
 
-               pf->priv = 0;
+       pf->field = V4L2_FIELD_INTERLACED;
+       pf->bytesperline = vcs->line_size;
+       pf->sizeimage = vcs->line_size *
+               (vcs->clipping.bottom - vcs->clipping.top) /
+               vcs->decimation;
+       pf->colorspace =
+               vino_data_formats[vcs->data_format].colorspace;
 
-               spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-               break;
-       }
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-       default:
-               return -EINVAL;
-       }
+       pf->priv = 0;
 
+       spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
        return 0;
 }
 
-static int vino_v4l2_s_fmt(struct vino_channel_settings *vcs,
+static int vino_s_fmt_vid_cap(struct file *file, void *__fh,
                           struct v4l2_format *f)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        int data_format;
        unsigned long flags;
+       struct v4l2_pix_format *pf = &f->fmt.pix;
 
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-               struct v4l2_pix_format *pf = &f->fmt.pix;
-
-               spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
-               data_format = vino_find_data_format(pf->pixelformat);
+       spin_lock_irqsave(&vino_drvdata->input_lock, flags);
 
-               if (data_format == VINO_DATA_FMT_NONE) {
-                       vcs->data_format = VINO_DATA_FMT_GREY;
-                       pf->pixelformat =
-                               vino_data_formats[vcs->data_format].
-                               pixelformat;
-               } else {
-                       vcs->data_format = data_format;
-               }
+       data_format = vino_find_data_format(pf->pixelformat);
 
-               /* data format must be set before clipping/scaling */
-               vino_set_scaling(vcs, pf->width, pf->height);
+       if (data_format == VINO_DATA_FMT_NONE) {
+               vcs->data_format = VINO_DATA_FMT_GREY;
+               pf->pixelformat =
+                       vino_data_formats[vcs->data_format].
+                       pixelformat;
+       } else {
+               vcs->data_format = data_format;
+       }
 
-               dprintk("data format = %s\n",
-                      vino_data_formats[vcs->data_format].description);
+       /* data format must be set before clipping/scaling */
+       vino_set_scaling(vcs, pf->width, pf->height);
 
-               pf->width = vcs->clipping.right - vcs->clipping.left;
-               pf->height = vcs->clipping.bottom - vcs->clipping.top;
+       dprintk("data format = %s\n",
+              vino_data_formats[vcs->data_format].description);
 
-               pf->field = V4L2_FIELD_INTERLACED;
-               pf->bytesperline = vcs->line_size;
-               pf->sizeimage = vcs->line_size *
-                       (vcs->clipping.bottom - vcs->clipping.top) /
-                       vcs->decimation;
-               pf->colorspace =
-                       vino_data_formats[vcs->data_format].colorspace;
+       pf->width = vcs->clipping.right - vcs->clipping.left;
+       pf->height = vcs->clipping.bottom - vcs->clipping.top;
 
-               pf->priv = 0;
+       pf->field = V4L2_FIELD_INTERLACED;
+       pf->bytesperline = vcs->line_size;
+       pf->sizeimage = vcs->line_size *
+               (vcs->clipping.bottom - vcs->clipping.top) /
+               vcs->decimation;
+       pf->colorspace =
+               vino_data_formats[vcs->data_format].colorspace;
 
-               spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-               break;
-       }
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-       default:
-               return -EINVAL;
-       }
+       pf->priv = 0;
 
+       spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
        return 0;
 }
 
-static int vino_v4l2_cropcap(struct vino_channel_settings *vcs,
+static int vino_cropcap(struct file *file, void *__fh,
                             struct v4l2_cropcap *ccap)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        const struct vino_data_norm *norm;
        unsigned long flags;
 
@@ -3415,9 +3266,10 @@ static int vino_v4l2_cropcap(struct vino_channel_settings *vcs,
        return 0;
 }
 
-static int vino_v4l2_g_crop(struct vino_channel_settings *vcs,
+static int vino_g_crop(struct file *file, void *__fh,
                            struct v4l2_crop *c)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        unsigned long flags;
 
        switch (c->type) {
@@ -3439,9 +3291,10 @@ static int vino_v4l2_g_crop(struct vino_channel_settings *vcs,
        return 0;
 }
 
-static int vino_v4l2_s_crop(struct vino_channel_settings *vcs,
+static int vino_s_crop(struct file *file, void *__fh,
                            struct v4l2_crop *c)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        unsigned long flags;
 
        switch (c->type) {
@@ -3461,108 +3314,83 @@ static int vino_v4l2_s_crop(struct vino_channel_settings *vcs,
        return 0;
 }
 
-static int vino_v4l2_g_parm(struct vino_channel_settings *vcs,
+static int vino_g_parm(struct file *file, void *__fh,
                            struct v4l2_streamparm *sp)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        unsigned long flags;
+       struct v4l2_captureparm *cp = &sp->parm.capture;
 
-       switch (sp->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-               struct v4l2_captureparm *cp = &sp->parm.capture;
-               memset(cp, 0, sizeof(struct v4l2_captureparm));
+       cp->capability = V4L2_CAP_TIMEPERFRAME;
+       cp->timeperframe.numerator = 1;
 
-               cp->capability = V4L2_CAP_TIMEPERFRAME;
-               cp->timeperframe.numerator = 1;
-
-               spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+       spin_lock_irqsave(&vino_drvdata->input_lock, flags);
 
-               cp->timeperframe.denominator = vcs->fps;
+       cp->timeperframe.denominator = vcs->fps;
 
-               spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+       spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
 
-               // TODO: cp->readbuffers = xxx;
-               break;
-       }
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-       default:
-               return -EINVAL;
-       }
+       /* TODO: cp->readbuffers = xxx; */
 
        return 0;
 }
 
-static int vino_v4l2_s_parm(struct vino_channel_settings *vcs,
+static int vino_s_parm(struct file *file, void *__fh,
                            struct v4l2_streamparm *sp)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        unsigned long flags;
+       struct v4l2_captureparm *cp = &sp->parm.capture;
 
-       switch (sp->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-               struct v4l2_captureparm *cp = &sp->parm.capture;
-
-               spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
-               if ((cp->timeperframe.numerator == 0) ||
-                   (cp->timeperframe.denominator == 0)) {
-                       /* reset framerate */
-                       vino_set_default_framerate(vcs);
-               } else {
-                       vino_set_framerate(vcs, cp->timeperframe.denominator /
-                                          cp->timeperframe.numerator);
-               }
-
-               spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+       spin_lock_irqsave(&vino_drvdata->input_lock, flags);
 
-               // TODO: set buffers according to cp->readbuffers
-               break;
-       }
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-       default:
-               return -EINVAL;
+       if ((cp->timeperframe.numerator == 0) ||
+           (cp->timeperframe.denominator == 0)) {
+               /* reset framerate */
+               vino_set_default_framerate(vcs);
+       } else {
+               vino_set_framerate(vcs, cp->timeperframe.denominator /
+                                  cp->timeperframe.numerator);
        }
 
+       spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
        return 0;
 }
 
-static int vino_v4l2_reqbufs(struct vino_channel_settings *vcs,
+static int vino_reqbufs(struct file *file, void *__fh,
                             struct v4l2_requestbuffers *rb)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
+
        if (vcs->reading)
                return -EBUSY;
 
-       switch (rb->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-               // TODO: check queue type
-               if (rb->memory != V4L2_MEMORY_MMAP) {
-                       dprintk("type not mmap\n");
-                       return -EINVAL;
-               }
+       /* TODO: check queue type */
+       if (rb->memory != V4L2_MEMORY_MMAP) {
+               dprintk("type not mmap\n");
+               return -EINVAL;
+       }
 
-               dprintk("count = %d\n", rb->count);
-               if (rb->count > 0) {
-                       if (vino_is_capturing(vcs)) {
-                               dprintk("busy, capturing\n");
-                               return -EBUSY;
-                       }
+       dprintk("count = %d\n", rb->count);
+       if (rb->count > 0) {
+               if (vino_is_capturing(vcs)) {
+                       dprintk("busy, capturing\n");
+                       return -EBUSY;
+               }
 
-                       if (vino_queue_has_mapped_buffers(&vcs->fb_queue)) {
-                               dprintk("busy, buffers still mapped\n");
-                               return -EBUSY;
-                       } else {
-                               vcs->streaming = 0;
-                               vino_queue_free(&vcs->fb_queue);
-                               vino_queue_init(&vcs->fb_queue, &rb->count);
-                       }
+               if (vino_queue_has_mapped_buffers(&vcs->fb_queue)) {
+                       dprintk("busy, buffers still mapped\n");
+                       return -EBUSY;
                } else {
                        vcs->streaming = 0;
-                       vino_capture_stop(vcs);
                        vino_queue_free(&vcs->fb_queue);
+                       vino_queue_init(&vcs->fb_queue, &rb->count);
                }
-               break;
-       }
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-       default:
-               return -EINVAL;
+       } else {
+               vcs->streaming = 0;
+               vino_capture_stop(vcs);
+               vino_queue_free(&vcs->fb_queue);
        }
 
        return 0;
@@ -3606,156 +3434,135 @@ static void vino_v4l2_get_buffer_status(struct vino_channel_settings *vcs,
                fb->id, fb->size, fb->data_size, fb->offset);
 }
 
-static int vino_v4l2_querybuf(struct vino_channel_settings *vcs,
+static int vino_querybuf(struct file *file, void *__fh,
                              struct v4l2_buffer *b)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
+       struct vino_framebuffer *fb;
+
        if (vcs->reading)
                return -EBUSY;
 
-       switch (b->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-               struct vino_framebuffer *fb;
-
-               // TODO: check queue type
-               if (b->index >= vino_queue_get_length(&vcs->fb_queue)) {
-                       dprintk("invalid index = %d\n",
-                              b->index);
-                       return -EINVAL;
-               }
-
-               fb = vino_queue_get_buffer(&vcs->fb_queue,
-                                          b->index);
-               if (fb == NULL) {
-                       dprintk("vino_queue_get_buffer() failed");
-                       return -EINVAL;
-               }
-
-               vino_v4l2_get_buffer_status(vcs, fb, b);
-               break;
+       /* TODO: check queue type */
+       if (b->index >= vino_queue_get_length(&vcs->fb_queue)) {
+               dprintk("invalid index = %d\n",
+                      b->index);
+               return -EINVAL;
        }
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-       default:
+
+       fb = vino_queue_get_buffer(&vcs->fb_queue,
+                                  b->index);
+       if (fb == NULL) {
+               dprintk("vino_queue_get_buffer() failed");
                return -EINVAL;
        }
 
+       vino_v4l2_get_buffer_status(vcs, fb, b);
+
        return 0;
 }
 
-static int vino_v4l2_qbuf(struct vino_channel_settings *vcs,
+static int vino_qbuf(struct file *file, void *__fh,
                          struct v4l2_buffer *b)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
+       struct vino_framebuffer *fb;
+       int ret;
+
        if (vcs->reading)
                return -EBUSY;
 
-       switch (b->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-               struct vino_framebuffer *fb;
-               int ret;
-
-               // TODO: check queue type
-               if (b->memory != V4L2_MEMORY_MMAP) {
-                       dprintk("type not mmap\n");
-                       return -EINVAL;
-               }
+       /* TODO: check queue type */
+       if (b->memory != V4L2_MEMORY_MMAP) {
+               dprintk("type not mmap\n");
+               return -EINVAL;
+       }
 
-               fb = vino_capture_enqueue(vcs, b->index);
-               if (fb == NULL)
-                       return -EINVAL;
+       fb = vino_capture_enqueue(vcs, b->index);
+       if (fb == NULL)
+               return -EINVAL;
 
-               vino_v4l2_get_buffer_status(vcs, fb, b);
+       vino_v4l2_get_buffer_status(vcs, fb, b);
 
-               if (vcs->streaming) {
-                       ret = vino_capture_next(vcs, 1);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       }
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-       default:
-               return -EINVAL;
+       if (vcs->streaming) {
+               ret = vino_capture_next(vcs, 1);
+               if (ret)
+                       return ret;
        }
 
        return 0;
 }
 
-static int vino_v4l2_dqbuf(struct vino_channel_settings *vcs,
-                          struct v4l2_buffer *b,
-                          unsigned int nonblocking)
+static int vino_dqbuf(struct file *file, void *__fh,
+                          struct v4l2_buffer *b)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
+       unsigned int nonblocking = file->f_flags & O_NONBLOCK;
+       struct vino_framebuffer *fb;
+       unsigned int incoming, outgoing;
+       int err;
+
        if (vcs->reading)
                return -EBUSY;
 
-       switch (b->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-               struct vino_framebuffer *fb;
-               unsigned int incoming, outgoing;
-               int err;
+       /* TODO: check queue type */
+
+       err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
+       if (err) {
+               dprintk("vino_queue_get_incoming() failed\n");
+               return -EINVAL;
+       }
+       err = vino_queue_get_outgoing(&vcs->fb_queue, &outgoing);
+       if (err) {
+               dprintk("vino_queue_get_outgoing() failed\n");
+               return -EINVAL;
+       }
 
-               // TODO: check queue type
+       dprintk("incoming = %d, outgoing = %d\n", incoming, outgoing);
 
-               err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
-               if (err) {
-                       dprintk("vino_queue_get_incoming() failed\n");
+       if (outgoing == 0) {
+               if (incoming == 0) {
+                       dprintk("no incoming or outgoing buffers\n");
                        return -EINVAL;
                }
-               err = vino_queue_get_outgoing(&vcs->fb_queue, &outgoing);
-               if (err) {
-                       dprintk("vino_queue_get_outgoing() failed\n");
-                       return -EINVAL;
+               if (nonblocking) {
+                       dprintk("non-blocking I/O was selected and "
+                               "there are no buffers to dequeue\n");
+                       return -EAGAIN;
                }
 
-               dprintk("incoming = %d, outgoing = %d\n", incoming, outgoing);
-
-               if (outgoing == 0) {
-                       if (incoming == 0) {
-                               dprintk("no incoming or outgoing buffers\n");
-                               return -EINVAL;
-                       }
-                       if (nonblocking) {
-                               dprintk("non-blocking I/O was selected and "
-                                       "there are no buffers to dequeue\n");
-                               return -EAGAIN;
-                       }
-
+               err = vino_wait_for_frame(vcs);
+               if (err) {
                        err = vino_wait_for_frame(vcs);
                        if (err) {
-                               err = vino_wait_for_frame(vcs);
-                               if (err) {
-                                       /* interrupted or
-                                        * no frames captured because
-                                        * of frame skipping */
-                                       // vino_capture_failed(vcs);
-                                       return -EIO;
-                               }
+                               /* interrupted or no frames captured because of
+                                * frame skipping */
+                               /* vino_capture_failed(vcs); */
+                               return -EIO;
                        }
                }
+       }
 
-               fb = vino_queue_remove(&vcs->fb_queue, &b->index);
-               if (fb == NULL) {
-                       dprintk("vino_queue_remove() failed\n");
-                       return -EINVAL;
-               }
-
-               err = vino_check_buffer(vcs, fb);
+       fb = vino_queue_remove(&vcs->fb_queue, &b->index);
+       if (fb == NULL) {
+               dprintk("vino_queue_remove() failed\n");
+               return -EINVAL;
+       }
 
-               vino_v4l2_get_buffer_status(vcs, fb, b);
+       err = vino_check_buffer(vcs, fb);
 
-               if (err)
-                       return -EIO;
+       vino_v4l2_get_buffer_status(vcs, fb, b);
 
-               break;
-       }
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-       default:
-               return -EINVAL;
-       }
+       if (err)
+               return -EIO;
 
        return 0;
 }
 
-static int vino_v4l2_streamon(struct vino_channel_settings *vcs)
+static int vino_streamon(struct file *file, void *__fh,
+               enum v4l2_buf_type i)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        unsigned int incoming;
        int ret;
        if (vcs->reading)
@@ -3792,8 +3599,10 @@ static int vino_v4l2_streamon(struct vino_channel_settings *vcs)
        return 0;
 }
 
-static int vino_v4l2_streamoff(struct vino_channel_settings *vcs)
+static int vino_streamoff(struct file *file, void *__fh,
+               enum v4l2_buf_type i)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        if (vcs->reading)
                return -EBUSY;
 
@@ -3806,9 +3615,10 @@ static int vino_v4l2_streamoff(struct vino_channel_settings *vcs)
        return 0;
 }
 
-static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs,
+static int vino_queryctrl(struct file *file, void *__fh,
                               struct v4l2_queryctrl *queryctrl)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        unsigned long flags;
        int i;
        int err = 0;
@@ -3855,9 +3665,10 @@ static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs,
        return err;
 }
 
-static int vino_v4l2_g_ctrl(struct vino_channel_settings *vcs,
+static int vino_g_ctrl(struct file *file, void *__fh,
                            struct v4l2_control *control)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        unsigned long flags;
        int i;
        int err = 0;
@@ -3866,56 +3677,38 @@ static int vino_v4l2_g_ctrl(struct vino_channel_settings *vcs,
 
        switch (vcs->input) {
        case VINO_INPUT_D1: {
-               struct indycam_control indycam_ctrl;
-
+               err = -EINVAL;
                for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
-                       if (vino_indycam_v4l2_controls[i].id ==
-                           control->id) {
-                               goto found1;
+                       if (vino_indycam_v4l2_controls[i].id == control->id) {
+                               err = 0;
+                               break;
                        }
                }
 
-               err = -EINVAL;
-               goto out;
-
-found1:
-               indycam_ctrl.type = vino_indycam_v4l2_controls[i].reserved[0];
-
-               err = i2c_camera_command(DECODER_INDYCAM_GET_CONTROL,
-                                        &indycam_ctrl);
-               if (err) {
-                       err = -EINVAL;
+               if (err)
                        goto out;
-               }
 
-               control->value = indycam_ctrl.value;
+               err = camera_call(core, g_ctrl, control);
+               if (err)
+                       err = -EINVAL;
                break;
        }
        case VINO_INPUT_COMPOSITE:
        case VINO_INPUT_SVIDEO: {
-               struct saa7191_control saa7191_ctrl;
-
+               err = -EINVAL;
                for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
-                       if (vino_saa7191_v4l2_controls[i].id ==
-                           control->id) {
-                               goto found2;
+                       if (vino_saa7191_v4l2_controls[i].id == control->id) {
+                               err = 0;
+                               break;
                        }
                }
 
-               err = -EINVAL;
-               goto out;
-
-found2:
-               saa7191_ctrl.type = vino_saa7191_v4l2_controls[i].reserved[0];
-
-               err = i2c_decoder_command(DECODER_SAA7191_GET_CONTROL,
-                                         &saa7191_ctrl);
-               if (err) {
-                       err = -EINVAL;
+               if (err)
                        goto out;
-               }
 
-               control->value = saa7191_ctrl.value;
+               err = decoder_call(core, g_ctrl, control);
+               if (err)
+                       err = -EINVAL;
                break;
        }
        default:
@@ -3928,9 +3721,10 @@ out:
        return err;
 }
 
-static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs,
+static int vino_s_ctrl(struct file *file, void *__fh,
                            struct v4l2_control *control)
 {
+       struct vino_channel_settings *vcs = video_drvdata(file);
        unsigned long flags;
        int i;
        int err = 0;
@@ -3944,65 +3738,43 @@ static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs,
 
        switch (vcs->input) {
        case VINO_INPUT_D1: {
-               struct indycam_control indycam_ctrl;
-
+               err = -EINVAL;
                for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
-                       if (vino_indycam_v4l2_controls[i].id ==
-                           control->id) {
-                               if ((control->value >=
-                                    vino_indycam_v4l2_controls[i].minimum)
-                                   && (control->value <=
-                                       vino_indycam_v4l2_controls[i].
-                                       maximum)) {
-                                       goto found1;
-                               } else {
-                                       err = -ERANGE;
-                                       goto out;
-                               }
+                       if (vino_indycam_v4l2_controls[i].id == control->id) {
+                               err = 0;
+                               break;
                        }
                }
-
-               err = -EINVAL;
-               goto out;
-
-found1:
-               indycam_ctrl.type = vino_indycam_v4l2_controls[i].reserved[0];
-               indycam_ctrl.value = control->value;
-
-               err = i2c_camera_command(DECODER_INDYCAM_SET_CONTROL,
-                                        &indycam_ctrl);
+               if (err)
+                       goto out;
+               if (control->value < vino_indycam_v4l2_controls[i].minimum ||
+                   control->value > vino_indycam_v4l2_controls[i].maximum) {
+                       err = -ERANGE;
+                       goto out;
+               }
+               err = camera_call(core, s_ctrl, control);
                if (err)
                        err = -EINVAL;
                break;
        }
        case VINO_INPUT_COMPOSITE:
        case VINO_INPUT_SVIDEO: {
-               struct saa7191_control saa7191_ctrl;
-
+               err = -EINVAL;
                for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
-                       if (vino_saa7191_v4l2_controls[i].id ==
-                           control->id) {
-                               if ((control->value >=
-                                    vino_saa7191_v4l2_controls[i].minimum)
-                                   && (control->value <=
-                                       vino_saa7191_v4l2_controls[i].
-                                       maximum)) {
-                                       goto found2;
-                               } else {
-                                       err = -ERANGE;
-                                       goto out;
-                               }
+                       if (vino_saa7191_v4l2_controls[i].id == control->id) {
+                               err = 0;
+                               break;
                        }
                }
-               err = -EINVAL;
-               goto out;
-
-found2:
-               saa7191_ctrl.type = vino_saa7191_v4l2_controls[i].reserved[0];
-               saa7191_ctrl.value = control->value;
+               if (err)
+                       goto out;
+               if (control->value < vino_saa7191_v4l2_controls[i].minimum ||
+                   control->value > vino_saa7191_v4l2_controls[i].maximum) {
+                       err = -ERANGE;
+                       goto out;
+               }
 
-               err = i2c_decoder_command(DECODER_SAA7191_SET_CONTROL,
-                                         &saa7191_ctrl);
+               err = decoder_call(core, s_ctrl, control);
                if (err)
                        err = -EINVAL;
                break;
@@ -4233,116 +4005,9 @@ over:
                ret = POLLIN | POLLRDNORM;
 
 error:
-
        return ret;
 }
 
-static long vino_do_ioctl(struct file *file, unsigned int cmd, void *arg)
-{
-       struct vino_channel_settings *vcs = video_drvdata(file);
-
-#ifdef VINO_DEBUG
-       switch (_IOC_TYPE(cmd)) {
-       case 'v':
-               dprintk("ioctl(): V4L1 unsupported (0x%08x)\n", cmd);
-               break;
-       case 'V':
-               dprintk("ioctl(): V4L2 %s (0x%08x)\n",
-                       v4l2_ioctl_names[_IOC_NR(cmd)], cmd);
-               break;
-       default:
-               dprintk("ioctl(): unsupported command 0x%08x\n", cmd);
-       }
-#endif
-
-       switch (cmd) {
-       /* V4L2 interface */
-       case VIDIOC_QUERYCAP: {
-               vino_v4l2_querycap(arg);
-               break;
-       }
-       case VIDIOC_ENUMINPUT: {
-               return vino_v4l2_enuminput(vcs, arg);
-       }
-       case VIDIOC_G_INPUT: {
-               return vino_v4l2_g_input(vcs, arg);
-       }
-       case VIDIOC_S_INPUT: {
-               return vino_v4l2_s_input(vcs, arg);
-       }
-       case VIDIOC_ENUMSTD: {
-               return vino_v4l2_enumstd(vcs, arg);
-       }
-       case VIDIOC_QUERYSTD: {
-               return vino_v4l2_querystd(vcs, arg);
-       }
-       case VIDIOC_G_STD: {
-               return vino_v4l2_g_std(vcs, arg);
-       }
-       case VIDIOC_S_STD: {
-               return vino_v4l2_s_std(vcs, arg);
-       }
-       case VIDIOC_ENUM_FMT: {
-               return vino_v4l2_enum_fmt(vcs, arg);
-       }
-       case VIDIOC_TRY_FMT: {
-               return vino_v4l2_try_fmt(vcs, arg);
-       }
-       case VIDIOC_G_FMT: {
-               return vino_v4l2_g_fmt(vcs, arg);
-       }
-       case VIDIOC_S_FMT: {
-               return vino_v4l2_s_fmt(vcs, arg);
-       }
-       case VIDIOC_CROPCAP: {
-               return vino_v4l2_cropcap(vcs, arg);
-       }
-       case VIDIOC_G_CROP: {
-               return vino_v4l2_g_crop(vcs, arg);
-       }
-       case VIDIOC_S_CROP: {
-               return vino_v4l2_s_crop(vcs, arg);
-       }
-       case VIDIOC_G_PARM: {
-               return vino_v4l2_g_parm(vcs, arg);
-       }
-       case VIDIOC_S_PARM: {
-               return vino_v4l2_s_parm(vcs, arg);
-       }
-       case VIDIOC_REQBUFS: {
-               return vino_v4l2_reqbufs(vcs, arg);
-       }
-       case VIDIOC_QUERYBUF: {
-               return vino_v4l2_querybuf(vcs, arg);
-       }
-       case VIDIOC_QBUF: {
-               return vino_v4l2_qbuf(vcs, arg);
-       }
-       case VIDIOC_DQBUF: {
-               return vino_v4l2_dqbuf(vcs, arg, file->f_flags & O_NONBLOCK);
-       }
-       case VIDIOC_STREAMON: {
-               return vino_v4l2_streamon(vcs);
-       }
-       case VIDIOC_STREAMOFF: {
-               return vino_v4l2_streamoff(vcs);
-       }
-       case VIDIOC_QUERYCTRL: {
-               return vino_v4l2_queryctrl(vcs, arg);
-       }
-       case VIDIOC_G_CTRL: {
-               return vino_v4l2_g_ctrl(vcs, arg);
-       }
-       case VIDIOC_S_CTRL: {
-               return vino_v4l2_s_ctrl(vcs, arg);
-       }
-       default:
-               return -ENOIOCTLCMD;
-       }
-
-       return 0;
-}
-
 static long vino_ioctl(struct file *file,
                      unsigned int cmd, unsigned long arg)
 {
@@ -4352,7 +4017,7 @@ static long vino_ioctl(struct file *file,
        if (mutex_lock_interruptible(&vcs->mutex))
                return -EINTR;
 
-       ret = video_usercopy(file, cmd, arg, vino_do_ioctl);
+       ret = video_ioctl2(file, cmd, arg);
 
        mutex_unlock(&vcs->mutex);
 
@@ -4364,45 +4029,75 @@ static long vino_ioctl(struct file *file,
 /* __initdata */
 static int vino_init_stage;
 
+const struct v4l2_ioctl_ops vino_ioctl_ops = {
+       .vidioc_enum_fmt_vid_cap     = vino_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap        = vino_g_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap        = vino_s_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap      = vino_try_fmt_vid_cap,
+       .vidioc_querycap             = vino_querycap,
+       .vidioc_enum_input           = vino_enum_input,
+       .vidioc_g_input              = vino_g_input,
+       .vidioc_s_input              = vino_s_input,
+       .vidioc_g_std                = vino_g_std,
+       .vidioc_s_std                = vino_s_std,
+       .vidioc_querystd             = vino_querystd,
+       .vidioc_cropcap              = vino_cropcap,
+       .vidioc_s_crop               = vino_s_crop,
+       .vidioc_g_crop               = vino_g_crop,
+       .vidioc_s_parm               = vino_s_parm,
+       .vidioc_g_parm               = vino_g_parm,
+       .vidioc_reqbufs              = vino_reqbufs,
+       .vidioc_querybuf             = vino_querybuf,
+       .vidioc_qbuf                 = vino_qbuf,
+       .vidioc_dqbuf                = vino_dqbuf,
+       .vidioc_streamon             = vino_streamon,
+       .vidioc_streamoff            = vino_streamoff,
+       .vidioc_queryctrl            = vino_queryctrl,
+       .vidioc_g_ctrl               = vino_g_ctrl,
+       .vidioc_s_ctrl               = vino_s_ctrl,
+};
+
 static const struct v4l2_file_operations vino_fops = {
        .owner          = THIS_MODULE,
        .open           = vino_open,
        .release        = vino_close,
-       .ioctl          = vino_ioctl,
+       .unlocked_ioctl = vino_ioctl,
        .mmap           = vino_mmap,
        .poll           = vino_poll,
 };
 
-static struct video_device v4l_device_template = {
+static struct video_device vdev_template = {
        .name           = "NOT SET",
        .fops           = &vino_fops,
+       .ioctl_ops      = &vino_ioctl_ops,
+       .tvnorms        = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
        .minor          = -1,
 };
 
 static void vino_module_cleanup(int stage)
 {
        switch(stage) {
+       case 11:
+               video_unregister_device(vino_drvdata->b.vdev);
+               vino_drvdata->b.vdev = NULL;
        case 10:
-               video_unregister_device(vino_drvdata->b.v4l_device);
-               vino_drvdata->b.v4l_device = NULL;
+               video_unregister_device(vino_drvdata->a.vdev);
+               vino_drvdata->a.vdev = NULL;
        case 9:
-               video_unregister_device(vino_drvdata->a.v4l_device);
-               vino_drvdata->a.v4l_device = NULL;
+               i2c_del_adapter(&vino_i2c_adapter);
        case 8:
-               vino_i2c_del_bus();
-       case 7:
                free_irq(SGI_VINO_IRQ, NULL);
+       case 7:
+               if (vino_drvdata->b.vdev) {
+                       video_device_release(vino_drvdata->b.vdev);
+                       vino_drvdata->b.vdev = NULL;
+               }
        case 6:
-               if (vino_drvdata->b.v4l_device) {
-                       video_device_release(vino_drvdata->b.v4l_device);
-                       vino_drvdata->b.v4l_device = NULL;
+               if (vino_drvdata->a.vdev) {
+                       video_device_release(vino_drvdata->a.vdev);
+                       vino_drvdata->a.vdev = NULL;
                }
        case 5:
-               if (vino_drvdata->a.v4l_device) {
-                       video_device_release(vino_drvdata->a.v4l_device);
-                       vino_drvdata->a.v4l_device = NULL;
-               }
-       case 4:
                /* all entries in dma_cpu dummy table have the same address */
                dma_unmap_single(NULL,
                                 vino_drvdata->dummy_desc_table.dma_cpu[0],
@@ -4412,8 +4107,10 @@ static void vino_module_cleanup(int stage)
                                  (void *)vino_drvdata->
                                  dummy_desc_table.dma_cpu,
                                  vino_drvdata->dummy_desc_table.dma);
-       case 3:
+       case 4:
                free_page(vino_drvdata->dummy_page);
+       case 3:
+               v4l2_device_unregister(&vino_drvdata->v4l2_dev);
        case 2:
                kfree(vino_drvdata);
        case 1:
@@ -4468,6 +4165,7 @@ static int vino_probe(void)
 static int vino_init(void)
 {
        dma_addr_t dma_dummy_address;
+       int err;
        int i;
 
        vino_drvdata = kzalloc(sizeof(struct vino_settings), GFP_KERNEL);
@@ -4476,6 +4174,12 @@ static int vino_init(void)
                return -ENOMEM;
        }
        vino_init_stage++;
+       strlcpy(vino_drvdata->v4l2_dev.name, "vino",
+                       sizeof(vino_drvdata->v4l2_dev.name));
+       err = v4l2_device_register(NULL, &vino_drvdata->v4l2_dev);
+       if (err)
+               return err;
+       vino_init_stage++;
 
        /* create a dummy dma descriptor */
        vino_drvdata->dummy_page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
@@ -4542,25 +4246,27 @@ static int vino_init_channel_settings(struct vino_channel_settings *vcs,
        spin_lock_init(&vcs->fb_queue.queue_lock);
        init_waitqueue_head(&vcs->fb_queue.frame_wait_queue);
 
-       vcs->v4l_device = video_device_alloc();
-       if (!vcs->v4l_device) {
+       vcs->vdev = video_device_alloc();
+       if (!vcs->vdev) {
                vino_module_cleanup(vino_init_stage);
                return -ENOMEM;
        }
        vino_init_stage++;
 
-       memcpy(vcs->v4l_device, &v4l_device_template,
+       memcpy(vcs->vdev, &vdev_template,
               sizeof(struct video_device));
-       strcpy(vcs->v4l_device->name, name);
-       vcs->v4l_device->release = video_device_release;
+       strcpy(vcs->vdev->name, name);
+       vcs->vdev->release = video_device_release;
+       vcs->vdev->v4l2_dev = &vino_drvdata->v4l2_dev;
 
-       video_set_drvdata(vcs->v4l_device, vcs);
+       video_set_drvdata(vcs->vdev, vcs);
 
        return 0;
 }
 
 static int __init vino_module_init(void)
 {
+       unsigned short addr[] = { 0, I2C_CLIENT_END };
        int ret;
 
        printk(KERN_INFO "SGI VINO driver version %s\n",
@@ -4580,12 +4286,12 @@ static int __init vino_module_init(void)
        spin_lock_init(&vino_drvdata->input_lock);
 
        ret = vino_init_channel_settings(&vino_drvdata->a, VINO_CHANNEL_A,
-                                   vino_v4l_device_name_a);
+                                   vino_vdev_name_a);
        if (ret)
                return ret;
 
        ret = vino_init_channel_settings(&vino_drvdata->b, VINO_CHANNEL_B,
-                                   vino_v4l_device_name_b);
+                                   vino_vdev_name_b);
        if (ret)
                return ret;
 
@@ -4601,15 +4307,16 @@ static int __init vino_module_init(void)
        }
        vino_init_stage++;
 
-       ret = vino_i2c_add_bus();
+       ret = i2c_add_adapter(&vino_i2c_adapter);
        if (ret) {
                printk(KERN_ERR "VINO I2C bus registration failed\n");
                vino_module_cleanup(vino_init_stage);
                return ret;
        }
+       i2c_set_adapdata(&vino_i2c_adapter, &vino_drvdata->v4l2_dev);
        vino_init_stage++;
 
-       ret = video_register_device(vino_drvdata->a.v4l_device,
+       ret = video_register_device(vino_drvdata->a.vdev,
                                    VFL_TYPE_GRABBER, -1);
        if (ret < 0) {
                printk(KERN_ERR "VINO channel A Video4Linux-device "
@@ -4619,7 +4326,7 @@ static int __init vino_module_init(void)
        }
        vino_init_stage++;
 
-       ret = video_register_device(vino_drvdata->b.v4l_device,
+       ret = video_register_device(vino_drvdata->b.vdev,
                                    VFL_TYPE_GRABBER, -1);
        if (ret < 0) {
                printk(KERN_ERR "VINO channel B Video4Linux-device "
@@ -4629,10 +4336,12 @@ static int __init vino_module_init(void)
        }
        vino_init_stage++;
 
-#ifdef MODULE
-       request_module("saa7191");
-       request_module("indycam");
-#endif
+       addr[0] = 0x45;
+       vino_drvdata->decoder = v4l2_i2c_new_probed_subdev(&vino_i2c_adapter,
+                       "saa7191", "saa7191", addr);
+       addr[0] = 0x2b;
+       vino_drvdata->camera = v4l2_i2c_new_probed_subdev(&vino_i2c_adapter,
+                       "indycam", "indycam", addr);
 
        dprintk("init complete!\n");
 
index 81d5aa5cf3317c336ecbaf7c666e75d793514dab..fbfefae7886fac4cfc337a9d66b591ed9880fa11 100644 (file)
 #include <linux/mutex.h>
 #include <linux/videodev2.h>
 #include <linux/dma-mapping.h>
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-/* Include V4L1 specific functions. Should be removed soon */
-#include <linux/videodev.h>
-#endif
 #include <linux/interrupt.h>
-#include <media/videobuf-vmalloc.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
 #include <linux/kthread.h>
 #include <linux/highmem.h>
 #include <linux/freezer.h>
+#include <media/videobuf-vmalloc.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include "font.h"
 
 #define VIVI_MODULE_NAME "vivi"
 
 #define WAKE_DENOMINATOR 1001
 #define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
 
-#include "font.h"
-
 #define VIVI_MAJOR_VERSION 0
-#define VIVI_MINOR_VERSION 5
+#define VIVI_MINOR_VERSION 6
 #define VIVI_RELEASE 0
 #define VIVI_VERSION \
        KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
 
-/* Declare static vars that will be used as parameters */
-static unsigned int vid_limit = 16;    /* Video memory limit, in Mb */
-static int video_nr = -1;              /* /dev/videoN, -1 for autodetect */
-static int n_devs = 1;                 /* Number of virtual devices */
+MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
+MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
+MODULE_LICENSE("Dual BSD/GPL");
+
+static unsigned video_nr = -1;
+module_param(video_nr, uint, 0644);
+MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect");
+
+static unsigned n_devs = 1;
+module_param(n_devs, uint, 0644);
+MODULE_PARM_DESC(n_devs, "number of video devices to create");
+
+static unsigned debug;
+module_param(debug, uint, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
+static unsigned int vid_limit = 16;
+module_param(vid_limit, uint, 0644);
+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
+
 
 /* supported controls */
 static struct v4l2_queryctrl vivi_qctrl[] = {
@@ -69,7 +80,7 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
                .maximum       = 65535,
                .step          = 65535/100,
                .default_value = 65535,
-               .flags         = 0,
+               .flags         = V4L2_CTRL_FLAG_SLIDER,
                .type          = V4L2_CTRL_TYPE_INTEGER,
        }, {
                .id            = V4L2_CID_BRIGHTNESS,
@@ -79,7 +90,7 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
                .maximum       = 255,
                .step          = 1,
                .default_value = 127,
-               .flags         = 0,
+               .flags         = V4L2_CTRL_FLAG_SLIDER,
        }, {
                .id            = V4L2_CID_CONTRAST,
                .type          = V4L2_CTRL_TYPE_INTEGER,
@@ -88,7 +99,7 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
                .maximum       = 255,
                .step          = 0x1,
                .default_value = 0x10,
-               .flags         = 0,
+               .flags         = V4L2_CTRL_FLAG_SLIDER,
        }, {
                .id            = V4L2_CID_SATURATION,
                .type          = V4L2_CTRL_TYPE_INTEGER,
@@ -97,7 +108,7 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
                .maximum       = 255,
                .step          = 0x1,
                .default_value = 127,
-               .flags         = 0,
+               .flags         = V4L2_CTRL_FLAG_SLIDER,
        }, {
                .id            = V4L2_CID_HUE,
                .type          = V4L2_CTRL_TYPE_INTEGER,
@@ -106,17 +117,12 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
                .maximum       = 127,
                .step          = 0x1,
                .default_value = 0,
-               .flags         = 0,
+               .flags         = V4L2_CTRL_FLAG_SLIDER,
        }
 };
 
-static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
-
-#define dprintk(dev, level, fmt, arg...)                               \
-       do {                                                            \
-               if (dev->vfd->debug >= (level))                         \
-                       printk(KERN_DEBUG "vivi: " fmt , ## arg);       \
-       } while (0)
+#define dprintk(dev, level, fmt, arg...) \
+       v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
 
 /* ------------------------------------------------------------------
        Basic structures
@@ -206,6 +212,7 @@ static LIST_HEAD(vivi_devlist);
 
 struct vivi_dev {
        struct list_head           vivi_devlist;
+       struct v4l2_device         v4l2_dev;
 
        spinlock_t                 slock;
        struct mutex               mutex;
@@ -223,6 +230,12 @@ struct vivi_dev {
        char                       timestr[13];
 
        int                        mv_count;    /* Controls bars movement */
+
+       /* Input Number */
+       int                        input;
+
+       /* Control 'registers' */
+       int                        qctl_regs[ARRAY_SIZE(vivi_qctrl)];
 };
 
 struct vivi_fh {
@@ -235,6 +248,7 @@ struct vivi_fh {
 
        enum v4l2_buf_type         type;
        unsigned char              bars[8][3];
+       int                        input;       /* Input Number on bars */
 };
 
 /* ------------------------------------------------------------------
@@ -254,18 +268,72 @@ enum colors {
        BLACK,
 };
 
-static u8 bars[8][3] = {
        /* R   G   B */
-       {204, 204, 204},  /* white */
-       {208, 208,   0},  /* ambar */
-       {  0, 206, 206},  /* cyan */
-       {  0, 239,   0},  /* green */
-       {239,   0, 239},  /* magenta */
-       {205,   0,   0},  /* red */
-       {  0,   0, 255},  /* blue */
-       {  0,   0,   0},  /* black */
+#define COLOR_WHITE    {204, 204, 204}
+#define COLOR_AMBAR    {208, 208,   0}
+#define COLOR_CIAN     {  0, 206, 206}
+#define        COLOR_GREEN     {  0, 239,   0}
+#define COLOR_MAGENTA  {239,   0, 239}
+#define COLOR_RED      {205,   0,   0}
+#define COLOR_BLUE     {  0,   0, 255}
+#define COLOR_BLACK    {  0,   0,   0}
+
+struct bar_std {
+       u8 bar[8][3];
 };
 
+/* Maximum number of bars are 10 - otherwise, the input print code
+   should be modified */
+static struct bar_std bars[] = {
+       {       /* Standard ITU-R color bar sequence */
+               {
+                       COLOR_WHITE,
+                       COLOR_AMBAR,
+                       COLOR_CIAN,
+                       COLOR_GREEN,
+                       COLOR_MAGENTA,
+                       COLOR_RED,
+                       COLOR_BLUE,
+                       COLOR_BLACK,
+               }
+       }, {
+               {
+                       COLOR_WHITE,
+                       COLOR_AMBAR,
+                       COLOR_BLACK,
+                       COLOR_WHITE,
+                       COLOR_AMBAR,
+                       COLOR_BLACK,
+                       COLOR_WHITE,
+                       COLOR_AMBAR,
+               }
+       }, {
+               {
+                       COLOR_WHITE,
+                       COLOR_CIAN,
+                       COLOR_BLACK,
+                       COLOR_WHITE,
+                       COLOR_CIAN,
+                       COLOR_BLACK,
+                       COLOR_WHITE,
+                       COLOR_CIAN,
+               }
+       }, {
+               {
+                       COLOR_WHITE,
+                       COLOR_GREEN,
+                       COLOR_BLACK,
+                       COLOR_WHITE,
+                       COLOR_GREEN,
+                       COLOR_BLACK,
+                       COLOR_WHITE,
+                       COLOR_GREEN,
+               }
+       },
+};
+
+#define NUM_INPUTS ARRAY_SIZE(bars)
+
 #define TO_Y(r, g, b) \
        (((16829 * r + 33039 * g + 6416 * b  + 32768) >> 16) + 16)
 /* RGB to  V(Cr) Color transform */
@@ -275,9 +343,10 @@ static u8 bars[8][3] = {
 #define TO_U(r, g, b) \
        (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
 
-#define TSTAMP_MIN_Y 24
-#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
-#define TSTAMP_MIN_X 64
+#define TSTAMP_MIN_Y   24
+#define TSTAMP_MAX_Y   (TSTAMP_MIN_Y + 15)
+#define TSTAMP_INPUT_X 10
+#define TSTAMP_MIN_X   (54 + TSTAMP_INPUT_X)
 
 static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos)
 {
@@ -392,9 +461,29 @@ static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax,
                pos += 4; /* only 16 bpp supported for now */
        }
 
-       /* Checks if it is possible to show timestamp */
+       /* Prints input entry number */
+
+       /* Checks if it is possible to input number */
        if (TSTAMP_MAX_Y >= hmax)
                goto end;
+
+       if (TSTAMP_INPUT_X + strlen(timestr) >= wmax)
+               goto end;
+
+       if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) {
+               chr = rom8x16_bits[fh->input * 16 + line - TSTAMP_MIN_Y];
+               pos = TSTAMP_INPUT_X;
+               for (i = 0; i < 7; i++) {
+                       /* Draw white font on black background */
+                       if (chr & 1 << (7 - i))
+                               gen_twopix(fh, basep + pos, WHITE);
+                       else
+                               gen_twopix(fh, basep + pos, BLACK);
+                       pos += 2;
+               }
+       }
+
+       /* Checks if it is possible to show timestamp */
        if (TSTAMP_MIN_X + strlen(timestr) >= wmax)
                goto end;
 
@@ -577,7 +666,7 @@ static int vivi_start_thread(struct vivi_fh *fh)
        dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
 
        if (IS_ERR(dma_q->kthread)) {
-               printk(KERN_ERR "vivi: kernel_thread() failed\n");
+               v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
                return PTR_ERR(dma_q->kthread);
        }
        /* Wakes thread */
@@ -720,8 +809,12 @@ static struct videobuf_queue_ops vivi_video_qops = {
 static int vidioc_querycap(struct file *file, void  *priv,
                                        struct v4l2_capability *cap)
 {
+       struct vivi_fh  *fh  = priv;
+       struct vivi_dev *dev = fh->dev;
+
        strcpy(cap->driver, "vivi");
        strcpy(cap->card, "vivi");
+       strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
        cap->version = VIVI_VERSION;
        cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
                                V4L2_CAP_STREAMING     |
@@ -807,38 +900,19 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        return 0;
 }
 
-/*FIXME: This seems to be generic enough to be at videodev2 */
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                                       struct v4l2_format *f)
+/* precalculate color bar values to speed up rendering */
+static void precalculate_bars(struct vivi_fh *fh)
 {
-       struct vivi_fh  *fh = priv;
-       struct videobuf_queue *q = &fh->vb_vidq;
+       struct vivi_dev *dev = fh->dev;
        unsigned char r, g, b;
        int k, is_yuv;
 
-       int ret = vidioc_try_fmt_vid_cap(file, fh, f);
-       if (ret < 0)
-               return (ret);
-
-       mutex_lock(&q->vb_lock);
-
-       if (videobuf_queue_is_busy(&fh->vb_vidq)) {
-               dprintk(fh->dev, 1, "%s queue busy\n", __func__);
-               ret = -EBUSY;
-               goto out;
-       }
-
-       fh->fmt           = get_format(f);
-       fh->width         = f->fmt.pix.width;
-       fh->height        = f->fmt.pix.height;
-       fh->vb_vidq.field = f->fmt.pix.field;
-       fh->type          = f->type;
+       fh->input = dev->input;
 
-       /* precalculate color bar values to speed up rendering */
        for (k = 0; k < 8; k++) {
-               r = bars[k][0];
-               g = bars[k][1];
-               b = bars[k][2];
+               r = bars[fh->input].bar[k][0];
+               g = bars[fh->input].bar[k][1];
+               b = bars[fh->input].bar[k][2];
                is_yuv = 0;
 
                switch (fh->fmt->fourcc) {
@@ -871,11 +945,40 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                }
        }
 
+}
+
+/*FIXME: This seems to be generic enough to be at videodev2 */
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivi_fh *fh = priv;
+       struct videobuf_queue *q = &fh->vb_vidq;
+
+       int ret = vidioc_try_fmt_vid_cap(file, fh, f);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&q->vb_lock);
+
+       if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+               dprintk(fh->dev, 1, "%s queue busy\n", __func__);
+               ret = -EBUSY;
+               goto out;
+       }
+
+       fh->fmt           = get_format(f);
+       fh->width         = f->fmt.pix.width;
+       fh->height        = f->fmt.pix.height;
+       fh->vb_vidq.field = f->fmt.pix.field;
+       fh->type          = f->type;
+
+       precalculate_bars(fh);
+
        ret = 0;
 out:
        mutex_unlock(&q->vb_lock);
 
-       return (ret);
+       return ret;
 }
 
 static int vidioc_reqbufs(struct file *file, void *priv,
@@ -950,27 +1053,36 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
 static int vidioc_enum_input(struct file *file, void *priv,
                                struct v4l2_input *inp)
 {
-       if (inp->index != 0)
+       if (inp->index >= NUM_INPUTS)
                return -EINVAL;
 
        inp->type = V4L2_INPUT_TYPE_CAMERA;
        inp->std = V4L2_STD_525_60;
-       strcpy(inp->name, "Camera");
+       sprintf(inp->name, "Camera %u", inp->index);
 
        return (0);
 }
 
 static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 {
-       *i = 0;
+       struct vivi_fh *fh = priv;
+       struct vivi_dev *dev = fh->dev;
+
+       *i = dev->input;
 
        return (0);
 }
 static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 {
-       if (i > 0)
+       struct vivi_fh *fh = priv;
+       struct vivi_dev *dev = fh->dev;
+
+       if (i >= NUM_INPUTS)
                return -EINVAL;
 
+       dev->input = i;
+       precalculate_bars(fh);
+
        return (0);
 }
 
@@ -993,12 +1105,14 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                         struct v4l2_control *ctrl)
 {
+       struct vivi_fh *fh = priv;
+       struct vivi_dev *dev = fh->dev;
        int i;
 
        for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
                if (ctrl->id == vivi_qctrl[i].id) {
-                       ctrl->value = qctl_regs[i];
-                       return (0);
+                       ctrl->value = dev->qctl_regs[i];
+                       return 0;
                }
 
        return -EINVAL;
@@ -1006,16 +1120,18 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
+       struct vivi_fh *fh = priv;
+       struct vivi_dev *dev = fh->dev;
        int i;
 
        for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
                if (ctrl->id == vivi_qctrl[i].id) {
-                       if (ctrl->value < vivi_qctrl[i].minimum
-                           || ctrl->value > vivi_qctrl[i].maximum) {
-                                       return (-ERANGE);
-                               }
-                       qctl_regs[i] = ctrl->value;
-                       return (0);
+                       if (ctrl->value < vivi_qctrl[i].minimum ||
+                           ctrl->value > vivi_qctrl[i].maximum) {
+                               return -ERANGE;
+                       }
+                       dev->qctl_regs[i] = ctrl->value;
+                       return 0;
                }
        return -EINVAL;
 }
@@ -1026,32 +1142,20 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 
 static int vivi_open(struct file *file)
 {
-       int minor = video_devdata(file)->minor;
-       struct vivi_dev *dev;
+       struct vivi_dev *dev = video_drvdata(file);
        struct vivi_fh *fh = NULL;
-       int i;
        int retval = 0;
 
-       printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
-
-       lock_kernel();
-       list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
-               if (dev->vfd->minor == minor)
-                       goto found;
-       unlock_kernel();
-       return -ENODEV;
-
-found:
        mutex_lock(&dev->mutex);
        dev->users++;
 
        if (dev->users > 1) {
                dev->users--;
-               retval = -EBUSY;
-               goto unlock;
+               mutex_unlock(&dev->mutex);
+               return -EBUSY;
        }
 
-       dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor,
+       dprintk(dev, 1, "open /dev/video%d type=%s users=%d\n", dev->vfd->num,
                v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
 
        /* allocate + initialize per filehandle data */
@@ -1059,14 +1163,11 @@ found:
        if (NULL == fh) {
                dev->users--;
                retval = -ENOMEM;
-               goto unlock;
        }
-unlock:
        mutex_unlock(&dev->mutex);
-       if (retval) {
-               unlock_kernel();
+
+       if (retval)
                return retval;
-       }
 
        file->private_data = fh;
        fh->dev      = dev;
@@ -1076,10 +1177,6 @@ unlock:
        fh->width    = 640;
        fh->height   = 480;
 
-       /* Put all controls at a sane state */
-       for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-               qctl_regs[i] = vivi_qctrl[i].default_value;
-
        /* Resets frame counters */
        dev->h = 0;
        dev->m = 0;
@@ -1095,7 +1192,6 @@ unlock:
                        sizeof(struct vivi_buffer), fh);
 
        vivi_start_thread(fh);
-       unlock_kernel();
 
        return 0;
 }
@@ -1151,32 +1247,6 @@ static int vivi_close(struct file *file)
        return 0;
 }
 
-static int vivi_release(void)
-{
-       struct vivi_dev *dev;
-       struct list_head *list;
-
-       while (!list_empty(&vivi_devlist)) {
-               list = vivi_devlist.next;
-               list_del(list);
-               dev = list_entry(list, struct vivi_dev, vivi_devlist);
-
-               if (-1 != dev->vfd->minor) {
-                       printk(KERN_INFO "%s: unregistering /dev/video%d\n",
-                               VIVI_MODULE_NAME, dev->vfd->num);
-                       video_unregister_device(dev->vfd);
-               } else {
-                       printk(KERN_INFO "%s: releasing /dev/video%d\n",
-                               VIVI_MODULE_NAME, dev->vfd->num);
-                       video_device_release(dev->vfd);
-               }
-
-               kfree(dev);
-       }
-
-       return 0;
-}
-
 static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct vivi_fh  *fh = file->private_data;
@@ -1239,87 +1309,130 @@ static struct video_device vivi_template = {
        .tvnorms              = V4L2_STD_525_60,
        .current_norm         = V4L2_STD_NTSC_M,
 };
+
 /* -----------------------------------------------------------------
        Initialization and module stuff
    ------------------------------------------------------------------*/
 
-/* This routine allocates from 1 to n_devs virtual drivers.
+static int vivi_release(void)
+{
+       struct vivi_dev *dev;
+       struct list_head *list;
 
-   The real maximum number of virtual drivers will depend on how many drivers
-   will succeed. This is limited to the maximum number of devices that
-   videodev supports. Since there are 64 minors for video grabbers, this is
-   currently the theoretical maximum limit. However, a further limit does
-   exist at videodev that forbids any driver to register more than 32 video
-   grabbers.
- */
-static int __init vivi_init(void)
+       while (!list_empty(&vivi_devlist)) {
+               list = vivi_devlist.next;
+               list_del(list);
+               dev = list_entry(list, struct vivi_dev, vivi_devlist);
+
+               v4l2_info(&dev->v4l2_dev, "unregistering /dev/video%d\n",
+                       dev->vfd->num);
+               video_unregister_device(dev->vfd);
+               v4l2_device_unregister(&dev->v4l2_dev);
+               kfree(dev);
+       }
+
+       return 0;
+}
+
+static int __init vivi_create_instance(int inst)
 {
-       int ret = -ENOMEM, i;
        struct vivi_dev *dev;
        struct video_device *vfd;
+       int ret, i;
 
-       if (n_devs <= 0)
-               n_devs = 1;
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
 
-       for (i = 0; i < n_devs; i++) {
-               dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-               if (!dev)
-                       break;
+       snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+                       "%s-%03d", VIVI_MODULE_NAME, inst);
+       ret = v4l2_device_register(NULL, &dev->v4l2_dev);
+       if (ret)
+               goto free_dev;
 
-               /* init video dma queues */
-               INIT_LIST_HEAD(&dev->vidq.active);
-               init_waitqueue_head(&dev->vidq.wq);
+       /* init video dma queues */
+       INIT_LIST_HEAD(&dev->vidq.active);
+       init_waitqueue_head(&dev->vidq.wq);
 
-               /* initialize locks */
-               spin_lock_init(&dev->slock);
-               mutex_init(&dev->mutex);
+       /* initialize locks */
+       spin_lock_init(&dev->slock);
+       mutex_init(&dev->mutex);
 
-               vfd = video_device_alloc();
-               if (!vfd) {
-                       kfree(dev);
-                       break;
-               }
+       ret = -ENOMEM;
+       vfd = video_device_alloc();
+       if (!vfd)
+               goto unreg_dev;
 
-               *vfd = vivi_template;
+       *vfd = vivi_template;
 
-               ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
-               if (ret < 0) {
-                       video_device_release(vfd);
-                       kfree(dev);
+       ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
+       if (ret < 0)
+               goto rel_vdev;
 
-                       /* If some registers succeeded, keep driver */
-                       if (i)
-                               ret = 0;
+       video_set_drvdata(vfd, dev);
 
-                       break;
-               }
+       /* Set all controls to their default value. */
+       for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+               dev->qctl_regs[i] = vivi_qctrl[i].default_value;
+
+       /* Now that everything is fine, let's add it to device list */
+       list_add_tail(&dev->vivi_devlist, &vivi_devlist);
+
+       snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
+                       vivi_template.name, vfd->num);
+
+       if (video_nr >= 0)
+               video_nr++;
 
-               /* Now that everything is fine, let's add it to device list */
-               list_add_tail(&dev->vivi_devlist, &vivi_devlist);
+       dev->vfd = vfd;
+       v4l2_info(&dev->v4l2_dev, "V4L2 device registered as /dev/video%d\n",
+                       vfd->num);
+       return 0;
+
+rel_vdev:
+       video_device_release(vfd);
+unreg_dev:
+       v4l2_device_unregister(&dev->v4l2_dev);
+free_dev:
+       kfree(dev);
+       return ret;
+}
+
+/* This routine allocates from 1 to n_devs virtual drivers.
 
-               snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
-                        vivi_template.name, vfd->minor);
+   The real maximum number of virtual drivers will depend on how many drivers
+   will succeed. This is limited to the maximum number of devices that
+   videodev supports, which is equal to VIDEO_NUM_DEVICES.
+ */
+static int __init vivi_init(void)
+{
+       int ret = 0, i;
 
-               if (video_nr >= 0)
-                       video_nr++;
+       if (n_devs <= 0)
+               n_devs = 1;
 
-               dev->vfd = vfd;
-               printk(KERN_INFO "%s: V4L2 device registered as /dev/video%d\n",
-                       VIVI_MODULE_NAME, vfd->num);
+       for (i = 0; i < n_devs; i++) {
+               ret = vivi_create_instance(i);
+               if (ret) {
+                       /* If some instantiations succeeded, keep driver */
+                       if (i)
+                               ret = 0;
+                       break;
+               }
        }
 
        if (ret < 0) {
-               vivi_release();
                printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
-       } else {
-               printk(KERN_INFO "Video Technology Magazine Virtual Video "
+               return ret;
+       }
+
+       printk(KERN_INFO "Video Technology Magazine Virtual Video "
                        "Capture Board ver %u.%u.%u successfully loaded.\n",
                        (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
                        VIVI_VERSION & 0xFF);
 
-               /* n_devs will reflect the actual number of allocated devices */
-               n_devs = i;
-       }
+       /* n_devs will reflect the actual number of allocated devices */
+       n_devs = i;
 
        return ret;
 }
@@ -1331,19 +1444,3 @@ static void __exit vivi_exit(void)
 
 module_init(vivi_init);
 module_exit(vivi_exit);
-
-MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
-MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
-MODULE_LICENSE("Dual BSD/GPL");
-
-module_param(video_nr, uint, 0444);
-MODULE_PARM_DESC(video_nr, "video iminor start number");
-
-module_param(n_devs, uint, 0444);
-MODULE_PARM_DESC(n_devs, "number of video devices to create");
-
-module_param_named(debug, vivi_template.debug, int, 0444);
-MODULE_PARM_DESC(debug, "activates debug info");
-
-module_param(vid_limit, int, 0644);
-MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
index 5d73f66d9f551efb65f541a2fab1c27970a7f667..42e23a4fa60715cc129ec3b361f6c61966b17a97 100644 (file)
@@ -129,11 +129,6 @@ static int vp27smpx_log_status(struct v4l2_subdev *sd)
        return 0;
 }
 
-static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops vp27smpx_core_ops = {
@@ -206,8 +201,6 @@ MODULE_DEVICE_TABLE(i2c, vp27smpx_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "vp27smpx",
-       .driverid = I2C_DRIVERID_VP27SMPX,
-       .command = vp27smpx_command,
        .probe = vp27smpx_probe,
        .remove = vp27smpx_remove,
        .id_table = vp27smpx_id,
index 67aa0db4b81a1049d21b7a096650d86362325a41..2fa7e8bb5746fa7893dc7f07fefb43b79b95e872 100644 (file)
 #include <linux/types.h>
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-i2c-drv-legacy.h>
-#include <linux/videodev.h>
-#include <linux/video_decoder.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
 MODULE_AUTHOR("Laurent Pinchart");
@@ -37,14 +37,17 @@ static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
+
 #define VPX_TIMEOUT_COUNT  10
 
 /* ----------------------------------------------------------------------- */
 
 struct vpx3220 {
+       struct v4l2_subdev sd;
        unsigned char reg[255];
 
-       int norm;
+       v4l2_std_id norm;
+       int ident;
        int input;
        int enable;
        int bright;
@@ -53,30 +56,38 @@ struct vpx3220 {
        int sat;
 };
 
+static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct vpx3220, sd);
+}
+
 static char *inputs[] = { "internal", "composite", "svideo" };
 
 /* ----------------------------------------------------------------------- */
 
-static inline int vpx3220_write(struct i2c_client *client, u8 reg, u8 value)
+static inline int vpx3220_write(struct v4l2_subdev *sd, u8 reg, u8 value)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct vpx3220 *decoder = i2c_get_clientdata(client);
 
        decoder->reg[reg] = value;
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static inline int vpx3220_read(struct i2c_client *client, u8 reg)
+static inline int vpx3220_read(struct v4l2_subdev *sd, u8 reg)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        return i2c_smbus_read_byte_data(client, reg);
 }
 
-static int vpx3220_fp_status(struct i2c_client *client)
+static int vpx3220_fp_status(struct v4l2_subdev *sd)
 {
        unsigned char status;
        unsigned int i;
 
        for (i = 0; i < VPX_TIMEOUT_COUNT; i++) {
-               status = vpx3220_read(client, 0x29);
+               status = vpx3220_read(sd, 0x29);
 
                if (!(status & 4))
                        return 0;
@@ -90,57 +101,60 @@ static int vpx3220_fp_status(struct i2c_client *client)
        return -1;
 }
 
-static int vpx3220_fp_write(struct i2c_client *client, u8 fpaddr, u16 data)
+static int vpx3220_fp_write(struct v4l2_subdev *sd, u8 fpaddr, u16 data)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        /* Write the 16-bit address to the FPWR register */
        if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) {
-               v4l_dbg(1, debug, client, "%s: failed\n", __func__);
+               v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
                return -1;
        }
 
-       if (vpx3220_fp_status(client) < 0)
+       if (vpx3220_fp_status(sd) < 0)
                return -1;
 
        /* Write the 16-bit data to the FPDAT register */
        if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) {
-               v4l_dbg(1, debug, client, "%s: failed\n", __func__);
+               v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
                return -1;
        }
 
        return 0;
 }
 
-static u16 vpx3220_fp_read(struct i2c_client *client, u16 fpaddr)
+static u16 vpx3220_fp_read(struct v4l2_subdev *sd, u16 fpaddr)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        s16 data;
 
        /* Write the 16-bit address to the FPRD register */
        if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) {
-               v4l_dbg(1, debug, client, "%s: failed\n", __func__);
+               v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
                return -1;
        }
 
-       if (vpx3220_fp_status(client) < 0)
+       if (vpx3220_fp_status(sd) < 0)
                return -1;
 
        /* Read the 16-bit data from the FPDAT register */
        data = i2c_smbus_read_word_data(client, 0x28);
        if (data == -1) {
-               v4l_dbg(1, debug, client, "%s: failed\n", __func__);
+               v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
                return -1;
        }
 
        return swab16(data);
 }
 
-static int vpx3220_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
+static int vpx3220_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len)
 {
        u8 reg;
        int ret = -1;
 
        while (len >= 2) {
                reg = *data++;
-               ret = vpx3220_write(client, reg, *data++);
+               ret = vpx3220_write(sd, reg, *data++);
                if (ret < 0)
                        break;
                len -= 2;
@@ -149,7 +163,7 @@ static int vpx3220_write_block(struct i2c_client *client, const u8 *data, unsign
        return ret;
 }
 
-static int vpx3220_write_fp_block(struct i2c_client *client,
+static int vpx3220_write_fp_block(struct v4l2_subdev *sd,
                const u16 *data, unsigned int len)
 {
        u8 reg;
@@ -157,7 +171,7 @@ static int vpx3220_write_fp_block(struct i2c_client *client,
 
        while (len > 1) {
                reg = *data++;
-               ret |= vpx3220_fp_write(client, reg, *data++);
+               ret |= vpx3220_fp_write(sd, reg, *data++);
                len -= 2;
        }
 
@@ -259,276 +273,277 @@ static const unsigned short init_fp[] = {
        0x4b, 0x298,            /* PLL gain */
 };
 
-static void vpx3220_dump_i2c(struct i2c_client *client)
-{
-       int len = sizeof(init_common);
-       const unsigned char *data = init_common;
 
-       while (len > 1) {
-               v4l_dbg(1, debug, client, "i2c reg 0x%02x data 0x%02x\n",
-                       *data, vpx3220_read(client, *data));
-               data += 2;
-               len -= 2;
-       }
+static int vpx3220_init(struct v4l2_subdev *sd, u32 val)
+{
+       struct vpx3220 *decoder = to_vpx3220(sd);
+
+       vpx3220_write_block(sd, init_common, sizeof(init_common));
+       vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
+       if (decoder->norm & V4L2_STD_NTSC)
+               vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
+       else if (decoder->norm & V4L2_STD_PAL)
+               vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
+       else if (decoder->norm & V4L2_STD_SECAM)
+               vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
+       else
+               vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
+       return 0;
 }
 
-static int vpx3220_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
 {
-       struct vpx3220 *decoder = i2c_get_clientdata(client);
+       int res = V4L2_IN_ST_NO_SIGNAL, status;
+       v4l2_std_id std = 0;
 
-       switch (cmd) {
-       case 0:
-       {
-               vpx3220_write_block(client, init_common,
-                                   sizeof(init_common));
-               vpx3220_write_fp_block(client, init_fp,
-                                      sizeof(init_fp) >> 1);
-               switch (decoder->norm) {
-               case VIDEO_MODE_NTSC:
-                       vpx3220_write_fp_block(client, init_ntsc,
-                                              sizeof(init_ntsc) >> 1);
-                       break;
+       status = vpx3220_fp_read(sd, 0x0f3);
+
+       v4l2_dbg(1, debug, sd, "status: 0x%04x\n", status);
+
+       if (status < 0)
+               return status;
 
-               case VIDEO_MODE_PAL:
-                       vpx3220_write_fp_block(client, init_pal,
-                                              sizeof(init_pal) >> 1);
+       if ((status & 0x20) == 0) {
+               res = 0;
+
+               switch (status & 0x18) {
+               case 0x00:
+               case 0x10:
+               case 0x14:
+               case 0x18:
+                       std = V4L2_STD_PAL;
                        break;
-               case VIDEO_MODE_SECAM:
-                       vpx3220_write_fp_block(client, init_secam,
-                                              sizeof(init_secam) >> 1);
+
+               case 0x08:
+                       std = V4L2_STD_SECAM;
                        break;
-               default:
-                       vpx3220_write_fp_block(client, init_pal,
-                                              sizeof(init_pal) >> 1);
+
+               case 0x04:
+               case 0x0c:
+               case 0x1c:
+                       std = V4L2_STD_NTSC;
                        break;
                }
-               break;
-       }
-
-       case DECODER_DUMP:
-       {
-               vpx3220_dump_i2c(client);
-               break;
        }
+       if (pstd)
+               *pstd = std;
+       if (pstatus)
+               *pstatus = status;
+       return 0;
+}
 
-       case DECODER_GET_CAPABILITIES:
-       {
-               struct video_decoder_capability *cap = arg;
+static int vpx3220_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+       v4l2_dbg(1, debug, sd, "querystd\n");
+       return vpx3220_status(sd, NULL, std);
+}
 
-               v4l_dbg(1, debug, client, "DECODER_GET_CAPABILITIES\n");
+static int vpx3220_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+       v4l2_dbg(1, debug, sd, "g_input_status\n");
+       return vpx3220_status(sd, status, NULL);
+}
 
-               cap->flags = VIDEO_DECODER_PAL |
-                            VIDEO_DECODER_NTSC |
-                            VIDEO_DECODER_SECAM |
-                            VIDEO_DECODER_AUTO |
-                            VIDEO_DECODER_CCIR;
-               cap->inputs = 3;
-               cap->outputs = 1;
-               break;
+static int vpx3220_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct vpx3220 *decoder = to_vpx3220(sd);
+       int temp_input;
+
+       /* Here we back up the input selection because it gets
+          overwritten when we fill the registers with the
+          choosen video norm */
+       temp_input = vpx3220_fp_read(sd, 0xf2);
+
+       v4l2_dbg(1, debug, sd, "s_std %llx\n", (unsigned long long)std);
+       if (std & V4L2_STD_NTSC) {
+               vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
+               v4l2_dbg(1, debug, sd, "norm switched to NTSC\n");
+       } else if (std & V4L2_STD_PAL) {
+               vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
+               v4l2_dbg(1, debug, sd, "norm switched to PAL\n");
+       } else if (std & V4L2_STD_SECAM) {
+               vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
+               v4l2_dbg(1, debug, sd, "norm switched to SECAM\n");
+       } else {
+               return -EINVAL;
        }
 
-       case DECODER_GET_STATUS:
-       {
-               int res = 0, status;
+       decoder->norm = std;
 
-               v4l_dbg(1, debug, client, "DECODER_GET_STATUS\n");
-
-               status = vpx3220_fp_read(client, 0x0f3);
-
-               v4l_dbg(1, debug, client, "status: 0x%04x\n", status);
-
-               if (status < 0)
-                       return status;
+       /* And here we set the backed up video input again */
+       vpx3220_fp_write(sd, 0xf2, temp_input | 0x0010);
+       udelay(10);
+       return 0;
+}
 
-               if ((status & 0x20) == 0) {
-                       res |= DECODER_STATUS_GOOD | DECODER_STATUS_COLOR;
+static int vpx3220_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       int data;
 
-                       switch (status & 0x18) {
-                       case 0x00:
-                       case 0x10:
-                       case 0x14:
-                       case 0x18:
-                               res |= DECODER_STATUS_PAL;
-                               break;
+       /* RJ:   route->input = 0: ST8 (PCTV) input
+                route->input = 1: COMPOSITE  input
+                route->input = 2: SVHS       input  */
 
-                       case 0x08:
-                               res |= DECODER_STATUS_SECAM;
-                               break;
+       const int input[3][2] = {
+               {0x0c, 0},
+               {0x0d, 0},
+               {0x0e, 1}
+       };
 
-                       case 0x04:
-                       case 0x0c:
-                       case 0x1c:
-                               res |= DECODER_STATUS_NTSC;
-                               break;
-                       }
-               }
+       if (route->input < 0 || route->input > 2)
+               return -EINVAL;
 
-               *(int *) arg = res;
-               break;
-       }
+       v4l2_dbg(1, debug, sd, "input switched to %s\n", inputs[route->input]);
 
-       case DECODER_SET_NORM:
-       {
-               int *iarg = arg, data;
-               int temp_input;
-
-               /* Here we back up the input selection because it gets
-                  overwritten when we fill the registers with the
-                  choosen video norm */
-               temp_input = vpx3220_fp_read(client, 0xf2);
-
-               v4l_dbg(1, debug, client, "DECODER_SET_NORM %d\n", *iarg);
-               switch (*iarg) {
-               case VIDEO_MODE_NTSC:
-                       vpx3220_write_fp_block(client, init_ntsc,
-                                              sizeof(init_ntsc) >> 1);
-                       v4l_dbg(1, debug, client, "norm switched to NTSC\n");
-                       break;
+       vpx3220_write(sd, 0x33, input[route->input][0]);
 
-               case VIDEO_MODE_PAL:
-                       vpx3220_write_fp_block(client, init_pal,
-                                              sizeof(init_pal) >> 1);
-                       v4l_dbg(1, debug, client, "norm switched to PAL\n");
-                       break;
+       data = vpx3220_fp_read(sd, 0xf2) & ~(0x0020);
+       if (data < 0)
+               return data;
+       /* 0x0010 is required to latch the setting */
+       vpx3220_fp_write(sd, 0xf2,
+                       data | (input[route->input][1] << 5) | 0x0010);
 
-               case VIDEO_MODE_SECAM:
-                       vpx3220_write_fp_block(client, init_secam,
-                                              sizeof(init_secam) >> 1);
-                       v4l_dbg(1, debug, client, "norm switched to SECAM\n");
-                       break;
+       udelay(10);
+       return 0;
+}
 
-               case VIDEO_MODE_AUTO:
-                       /* FIXME This is only preliminary support */
-                       data = vpx3220_fp_read(client, 0xf2) & 0x20;
-                       vpx3220_fp_write(client, 0xf2, 0x00c0 | data);
-                       v4l_dbg(1, debug, client, "norm switched to AUTO\n");
-                       break;
+static int vpx3220_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       v4l2_dbg(1, debug, sd, "s_stream %s\n", enable ? "on" : "off");
 
-               default:
-                       return -EINVAL;
-               }
-               decoder->norm = *iarg;
+       vpx3220_write(sd, 0xf2, (enable ? 0x1b : 0x00));
+       return 0;
+}
 
-               /* And here we set the backed up video input again */
-               vpx3220_fp_write(client, 0xf2, temp_input | 0x0010);
-               udelay(10);
+static int vpx3220_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       switch (qc->id) {
+       case V4L2_CID_BRIGHTNESS:
+               v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
                break;
-       }
-
-       case DECODER_SET_INPUT:
-       {
-               int *iarg = arg, data;
-
-               /* RJ:  *iarg = 0: ST8 (PCTV) input
-                *iarg = 1: COMPOSITE  input
-                *iarg = 2: SVHS       input  */
-
-               const int input[3][2] = {
-                       {0x0c, 0},
-                       {0x0d, 0},
-                       {0x0e, 1}
-               };
 
-               if (*iarg < 0 || *iarg > 2)
-                       return -EINVAL;
-
-               v4l_dbg(1, debug, client, "input switched to %s\n", inputs[*iarg]);
-
-               vpx3220_write(client, 0x33, input[*iarg][0]);
-
-               data = vpx3220_fp_read(client, 0xf2) & ~(0x0020);
-               if (data < 0)
-                       return data;
-               /* 0x0010 is required to latch the setting */
-               vpx3220_fp_write(client, 0xf2,
-                                data | (input[*iarg][1] << 5) | 0x0010);
-
-               udelay(10);
+       case V4L2_CID_CONTRAST:
+               v4l2_ctrl_query_fill(qc, 0, 63, 1, 32);
                break;
-       }
 
-       case DECODER_SET_OUTPUT:
-       {
-               int *iarg = arg;
+       case V4L2_CID_SATURATION:
+               v4l2_ctrl_query_fill(qc, 0, 4095, 1, 2048);
+               break;
 
-               /* not much choice of outputs */
-               if (*iarg != 0) {
-                       return -EINVAL;
-               }
+       case V4L2_CID_HUE:
+               v4l2_ctrl_query_fill(qc, -512, 511, 1, 0);
                break;
-       }
 
-       case DECODER_ENABLE_OUTPUT:
-       {
-               int *iarg = arg;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
 
-               v4l_dbg(1, debug, client, "DECODER_ENABLE_OUTPUT %d\n", *iarg);
+static int vpx3220_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct vpx3220 *decoder = to_vpx3220(sd);
 
-               vpx3220_write(client, 0xf2, (*iarg ? 0x1b : 0x00));
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ctrl->value = decoder->bright;
+               break;
+       case V4L2_CID_CONTRAST:
+               ctrl->value = decoder->contrast;
                break;
+       case V4L2_CID_SATURATION:
+               ctrl->value = decoder->sat;
+               break;
+       case V4L2_CID_HUE:
+               ctrl->value = decoder->hue;
+               break;
+       default:
+               return -EINVAL;
        }
+       return 0;
+}
 
-       case DECODER_SET_PICTURE:
-       {
-               struct video_picture *pic = arg;
+static int vpx3220_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct vpx3220 *decoder = to_vpx3220(sd);
 
-               if (decoder->bright != pic->brightness) {
-                       /* We want -128 to 128 we get 0-65535 */
-                       decoder->bright = pic->brightness;
-                       vpx3220_write(client, 0xe6,
-                                     (decoder->bright - 32768) >> 8);
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               if (decoder->bright != ctrl->value) {
+                       decoder->bright = ctrl->value;
+                       vpx3220_write(sd, 0xe6, decoder->bright);
                }
-               if (decoder->contrast != pic->contrast) {
-                       /* We want 0 to 64 we get 0-65535 */
+               break;
+       case V4L2_CID_CONTRAST:
+               if (decoder->contrast != ctrl->value) {
                        /* Bit 7 and 8 is for noise shaping */
-                       decoder->contrast = pic->contrast;
-                       vpx3220_write(client, 0xe7,
-                                     (decoder->contrast >> 10) + 192);
+                       decoder->contrast = ctrl->value;
+                       vpx3220_write(sd, 0xe7, decoder->contrast + 192);
                }
-               if (decoder->sat != pic->colour) {
-                       /* We want 0 to 4096 we get 0-65535 */
-                       decoder->sat = pic->colour;
-                       vpx3220_fp_write(client, 0xa0,
-                                        decoder->sat >> 4);
+               break;
+       case V4L2_CID_SATURATION:
+               if (decoder->sat != ctrl->value) {
+                       decoder->sat = ctrl->value;
+                       vpx3220_fp_write(sd, 0xa0, decoder->sat);
                }
-               if (decoder->hue != pic->hue) {
-                       /* We want -512 to 512 we get 0-65535 */
-                       decoder->hue = pic->hue;
-                       vpx3220_fp_write(client, 0x1c,
-                                        ((decoder->hue - 32768) >> 6) & 0xFFF);
+               break;
+       case V4L2_CID_HUE:
+               if (decoder->hue != ctrl->value) {
+                       decoder->hue = ctrl->value;
+                       vpx3220_fp_write(sd, 0x1c, decoder->hue);
                }
                break;
-       }
-
        default:
                return -EINVAL;
        }
-
        return 0;
 }
 
-static int vpx3220_init_client(struct i2c_client *client)
+static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
 {
-       vpx3220_write_block(client, init_common, sizeof(init_common));
-       vpx3220_write_fp_block(client, init_fp, sizeof(init_fp) >> 1);
-       /* Default to PAL */
-       vpx3220_write_fp_block(client, init_pal, sizeof(init_pal) >> 1);
+       struct vpx3220 *decoder = to_vpx3220(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       return 0;
+       return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0);
 }
 
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops vpx3220_core_ops = {
+       .g_chip_ident = vpx3220_g_chip_ident,
+       .init = vpx3220_init,
+       .g_ctrl = vpx3220_g_ctrl,
+       .s_ctrl = vpx3220_s_ctrl,
+       .queryctrl = vpx3220_queryctrl,
+};
+
+static const struct v4l2_subdev_tuner_ops vpx3220_tuner_ops = {
+       .s_std = vpx3220_s_std,
+};
+
+static const struct v4l2_subdev_video_ops vpx3220_video_ops = {
+       .s_routing = vpx3220_s_routing,
+       .s_stream = vpx3220_s_stream,
+       .querystd = vpx3220_querystd,
+       .g_input_status = vpx3220_g_input_status,
+};
+
+static const struct v4l2_subdev_ops vpx3220_ops = {
+       .core = &vpx3220_core_ops,
+       .tuner = &vpx3220_tuner_ops,
+       .video = &vpx3220_video_ops,
+};
+
 /* -----------------------------------------------------------------------
  * Client management code
  */
 
-static unsigned short normal_i2c[] = { 0x86 >> 1, 0x8e >> 1, I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
 static int vpx3220_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        struct vpx3220 *decoder;
+       struct v4l2_subdev *sd;
        const char *name = NULL;
        u8 ver;
        u16 pn;
@@ -541,18 +556,20 @@ static int vpx3220_probe(struct i2c_client *client,
        decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL);
        if (decoder == NULL)
                return -ENOMEM;
-       decoder->norm = VIDEO_MODE_PAL;
+       sd = &decoder->sd;
+       v4l2_i2c_subdev_init(sd, client, &vpx3220_ops);
+       decoder->norm = V4L2_STD_PAL;
        decoder->input = 0;
        decoder->enable = 1;
        decoder->bright = 32768;
        decoder->contrast = 32768;
        decoder->hue = 32768;
        decoder->sat = 32768;
-       i2c_set_clientdata(client, decoder);
 
        ver = i2c_smbus_read_byte_data(client, 0x00);
        pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) +
                i2c_smbus_read_byte_data(client, 0x01);
+       decoder->ident = V4L2_IDENT_VPX3220A;
        if (ver == 0xec) {
                switch (pn) {
                case 0x4680:
@@ -560,26 +577,34 @@ static int vpx3220_probe(struct i2c_client *client,
                        break;
                case 0x4260:
                        name = "vpx3216b";
+                       decoder->ident = V4L2_IDENT_VPX3216B;
                        break;
                case 0x4280:
                        name = "vpx3214c";
+                       decoder->ident = V4L2_IDENT_VPX3214C;
                        break;
                }
        }
        if (name)
-               v4l_info(client, "%s found @ 0x%x (%s)\n", name,
+               v4l2_info(sd, "%s found @ 0x%x (%s)\n", name,
                        client->addr << 1, client->adapter->name);
        else
-               v4l_info(client, "chip (%02x:%04x) found @ 0x%x (%s)\n",
+               v4l2_info(sd, "chip (%02x:%04x) found @ 0x%x (%s)\n",
                        ver, pn, client->addr << 1, client->adapter->name);
 
-       vpx3220_init_client(client);
+       vpx3220_write_block(sd, init_common, sizeof(init_common));
+       vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
+       /* Default to PAL */
+       vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
        return 0;
 }
 
 static int vpx3220_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_vpx3220(sd));
        return 0;
 }
 
@@ -593,8 +618,6 @@ MODULE_DEVICE_TABLE(i2c, vpx3220_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "vpx3220",
-       .driverid = I2C_DRIVERID_VPX3220,
-       .command = vpx3220_command,
        .probe = vpx3220_probe,
        .remove = vpx3220_remove,
        .id_table = vpx3220_id,
index 038ff32b01b85943fdc572fb6266becb9c4f4ada..dcade619cbd8454db5ba93166064eba0ccf39c35 100644 (file)
@@ -57,7 +57,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/videodev2.h>
+#include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <linux/parport.h>
index 105a832531f2529a61a6c45cbb0855f79b514bfa..3b08bc4af909c57131ed90d67d76e496809103cb 100644 (file)
@@ -42,6 +42,7 @@
 #include <asm/page.h>
 #include <asm/uaccess.h>
 #include <linux/page-flags.h>
+#include <linux/videodev.h>
 #include <media/v4l2-ioctl.h>
 
 #include "w9968cf.h"
@@ -68,7 +69,6 @@ MODULE_VERSION(W9968CF_MODULE_VERSION);
 MODULE_LICENSE(W9968CF_MODULE_LICENSE);
 MODULE_SUPPORTED_DEVICE("Video");
 
-static int ovmod_load = W9968CF_OVMOD_LOAD;
 static unsigned short simcams = W9968CF_SIMCAMS;
 static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/
 static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] =
@@ -111,9 +111,6 @@ static int specific_debug = W9968CF_SPECIFIC_DEBUG;
 
 static unsigned int param_nv[24]; /* number of values per parameter */
 
-#ifdef CONFIG_MODULES
-module_param(ovmod_load, bool, 0644);
-#endif
 module_param(simcams, ushort, 0644);
 module_param_array(video_nr, short, &param_nv[0], 0444);
 module_param_array(packet_size, uint, &param_nv[1], 0444);
@@ -144,18 +141,6 @@ module_param(debug, ushort, 0644);
 module_param(specific_debug, bool, 0644);
 #endif
 
-#ifdef CONFIG_MODULES
-MODULE_PARM_DESC(ovmod_load,
-                "\n<0|1> Automatic 'ovcamchip' module loading."
-                "\n0 disabled, 1 enabled."
-                "\nIf enabled,'insmod' searches for the required 'ovcamchip'"
-                "\nmodule in the system, according to its configuration, and"
-                "\nattempts to load that module automatically. This action is"
-                "\nperformed once as soon as the 'w9968cf' module is loaded"
-                "\ninto memory."
-                "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"."
-                "\n");
-#endif
 MODULE_PARM_DESC(simcams,
                 "\n<n> Number of cameras allowed to stream simultaneously."
                 "\nn may vary from 0 to "
@@ -443,8 +428,6 @@ static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr,
                                  unsigned short flags, char read_write,
                                  u8 command, int size, union i2c_smbus_data*);
 static u32 w9968cf_i2c_func(struct i2c_adapter*);
-static int w9968cf_i2c_attach_inform(struct i2c_client*);
-static int w9968cf_i2c_detach_inform(struct i2c_client*);
 
 /* Memory management */
 static void* rvmalloc(unsigned long size);
@@ -1443,19 +1426,11 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
                       unsigned short flags, char read_write, u8 command,
                       int size, union i2c_smbus_data *data)
 {
-       struct w9968cf_device* cam = i2c_get_adapdata(adapter);
+       struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
+       struct w9968cf_device *cam = to_cam(v4l2_dev);
        u8 i;
        int err = 0;
 
-       switch (addr) {
-               case OV6xx0_SID:
-               case OV7xx0_SID:
-                       break;
-               default:
-                       DBG(4, "Rejected slave ID 0x%04X", addr)
-                       return -EINVAL;
-       }
-
        if (size == I2C_SMBUS_BYTE) {
                /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */
                addr <<= 1;
@@ -1463,8 +1438,17 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
                if (read_write == I2C_SMBUS_WRITE)
                        err = w9968cf_i2c_adap_write_byte(cam, addr, command);
                else if (read_write == I2C_SMBUS_READ)
-                       err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte);
-
+                       for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
+                               err = w9968cf_i2c_adap_read_byte(cam, addr,
+                                                        &data->byte);
+                               if (err) {
+                                       if (w9968cf_smbus_refresh_bus(cam)) {
+                                               err = -EIO;
+                                               break;
+                                       }
+                               } else
+                                       break;
+                       }
        } else if (size == I2C_SMBUS_BYTE_DATA) {
                addr <<= 1;
 
@@ -1491,7 +1475,6 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
                DBG(4, "Unsupported I2C transfer mode (%d)", size)
                return -EINVAL;
        }
-
        return err;
 }
 
@@ -1504,44 +1487,6 @@ static u32 w9968cf_i2c_func(struct i2c_adapter* adap)
 }
 
 
-static int w9968cf_i2c_attach_inform(struct i2c_client* client)
-{
-       struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
-       int id = client->driver->id, err = 0;
-
-       if (id == I2C_DRIVERID_OVCAMCHIP) {
-               cam->sensor_client = client;
-               err = w9968cf_sensor_init(cam);
-               if (err) {
-                       cam->sensor_client = NULL;
-                       return err;
-               }
-       } else {
-               DBG(4, "Rejected client [%s] with driver [%s]",
-                   client->name, client->driver->driver.name)
-               return -EINVAL;
-       }
-
-       DBG(5, "I2C attach client [%s] with driver [%s]",
-           client->name, client->driver->driver.name)
-
-       return 0;
-}
-
-
-static int w9968cf_i2c_detach_inform(struct i2c_client* client)
-{
-       struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
-
-       if (cam->sensor_client == client)
-               cam->sensor_client = NULL;
-
-       DBG(5, "I2C detach client [%s]", client->name)
-
-       return 0;
-}
-
-
 static int w9968cf_i2c_init(struct w9968cf_device* cam)
 {
        int err = 0;
@@ -1554,15 +1499,13 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam)
        static struct i2c_adapter adap = {
                .id =                I2C_HW_SMBUS_W9968CF,
                .owner =             THIS_MODULE,
-               .client_register =   w9968cf_i2c_attach_inform,
-               .client_unregister = w9968cf_i2c_detach_inform,
                .algo =              &algo,
        };
 
        memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter));
        strcpy(cam->i2c_adapter.name, "w9968cf");
        cam->i2c_adapter.dev.parent = &cam->usbdev->dev;
-       i2c_set_adapdata(&cam->i2c_adapter, cam);
+       i2c_set_adapdata(&cam->i2c_adapter, &cam->v4l2_dev);
 
        DBG(6, "Registering I2C adapter with kernel...")
 
@@ -2165,13 +2108,9 @@ w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val)
 static int
 w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg)
 {
-       struct i2c_client* c = cam->sensor_client;
-       int rc = 0;
-
-       if (!c || !c->driver || !c->driver->command)
-               return -EINVAL;
+       int rc;
 
-       rc = c->driver->command(c, cmd, arg);
+       rc = v4l2_subdev_call(cam->sensor_sd, core, ioctl, cmd, arg);
        /* The I2C driver returns -EPERM on non-supported controls */
        return (rc < 0 && rc != -EPERM) ? rc : 0;
 }
@@ -2346,7 +2285,7 @@ static int w9968cf_sensor_init(struct w9968cf_device* cam)
                goto error;
 
        /* NOTE: Make sure width and height are a multiple of 16 */
-       switch (cam->sensor_client->addr) {
+       switch (v4l2_i2c_subdev_addr(cam->sensor_sd)) {
                case OV6xx0_SID:
                        cam->maxwidth = 352;
                        cam->maxheight = 288;
@@ -2651,6 +2590,7 @@ static void w9968cf_release_resources(struct w9968cf_device* cam)
        w9968cf_deallocate_memory(cam);
        kfree(cam->control_buffer);
        kfree(cam->data_buffer);
+       v4l2_device_unregister(&cam->v4l2_dev);
 
        mutex_unlock(&w9968cf_devlist_mutex);
 }
@@ -3480,6 +3420,11 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        struct list_head* ptr;
        u8 sc = 0; /* number of simultaneous cameras */
        static unsigned short dev_nr; /* 0 - we are handling device number n */
+       static unsigned short addrs[] = {
+               OV7xx0_SID,
+               OV6xx0_SID,
+               I2C_CLIENT_END
+       };
 
        if (le16_to_cpu(udev->descriptor.idVendor)  == winbond_id_table[0].idVendor &&
            le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct)
@@ -3495,12 +3440,14 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        if (!cam)
                return -ENOMEM;
 
+       err = v4l2_device_register(&udev->dev, &cam->v4l2_dev);
+       if (err)
+               goto fail0;
+
        mutex_init(&cam->dev_mutex);
        mutex_lock(&cam->dev_mutex);
 
        cam->usbdev = udev;
-       /* NOTE: a local copy is used to avoid possible race conditions */
-       memcpy(&cam->dev, &udev->dev, sizeof(struct device));
 
        DBG(2, "%s detected", symbolic(camlist, mod_id))
 
@@ -3549,7 +3496,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        cam->v4ldev->minor = video_nr[dev_nr];
        cam->v4ldev->release = video_device_release;
        video_set_drvdata(cam->v4ldev, cam);
-       cam->v4ldev->parent = &cam->dev;
+       cam->v4ldev->v4l2_dev = &cam->v4l2_dev;
 
        err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
                                    video_nr[dev_nr]);
@@ -3576,9 +3523,13 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        w9968cf_turn_on_led(cam);
 
        w9968cf_i2c_init(cam);
+       cam->sensor_sd = v4l2_i2c_new_probed_subdev(&cam->i2c_adapter,
+                       "ovcamchip", "ovcamchip", addrs);
 
        usb_set_intfdata(intf, cam);
        mutex_unlock(&cam->dev_mutex);
+
+       err = w9968cf_sensor_init(cam);
        return 0;
 
 fail: /* Free unused memory */
@@ -3587,6 +3538,8 @@ fail: /* Free unused memory */
        if (cam->v4ldev)
                video_device_release(cam->v4ldev);
        mutex_unlock(&cam->dev_mutex);
+       v4l2_device_unregister(&cam->v4l2_dev);
+fail0:
        kfree(cam);
        return err;
 }
@@ -3597,15 +3550,16 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
        struct w9968cf_device* cam =
           (struct w9968cf_device*)usb_get_intfdata(intf);
 
-       down_write(&w9968cf_disconnect);
-
        if (cam) {
+               down_write(&w9968cf_disconnect);
                /* Prevent concurrent accesses to data */
                mutex_lock(&cam->dev_mutex);
 
                cam->disconnected = 1;
 
-               DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id))
+               DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id));
+
+               v4l2_device_disconnect(&cam->v4l2_dev);
 
                wake_up_interruptible_all(&cam->open);
 
@@ -3621,12 +3575,12 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
                        w9968cf_release_resources(cam);
 
                mutex_unlock(&cam->dev_mutex);
+               up_write(&w9968cf_disconnect);
 
-               if (!cam->users)
+               if (!cam->users) {
                        kfree(cam);
+               }
        }
-
-       up_write(&w9968cf_disconnect);
 }
 
 
@@ -3650,9 +3604,6 @@ static int __init w9968cf_module_init(void)
        KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION)
        KDBG(3, W9968CF_MODULE_AUTHOR)
 
-       if (ovmod_load)
-               request_module("ovcamchip");
-
        if ((err = usb_register(&w9968cf_usb_driver)))
                return err;
 
index 30032e15e23c2761fc9461462466c0cf82eb381c..fdfc6a4e1c8f92b703f137102404cd81177c5076 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/rwsem.h>
 #include <linux/mutex.h>
 
+#include <media/v4l2-device.h>
 #include <media/ovcamchip.h>
 
 #include "w9968cf_vpp.h"
@@ -42,7 +43,6 @@
  * Default values                                                           *
  ****************************************************************************/
 
-#define W9968CF_OVMOD_LOAD      1  /* automatic 'ovcamchip' module loading */
 #define W9968CF_VPPMOD_LOAD     1  /* automatic 'w9968cf-vpp' module loading */
 
 /* Comment/uncomment the following line to enable/disable debugging messages */
@@ -195,10 +195,9 @@ enum w9968cf_vpp_flag {
 
 /* Main device driver structure */
 struct w9968cf_device {
-       struct device dev; /* device structure */
-
        enum w9968cf_model_id id;   /* private device identifier */
 
+       struct v4l2_device v4l2_dev;
        struct video_device* v4ldev; /* -> V4L structure */
        struct list_head v4llist;    /* entry of the list of V4L cameras */
 
@@ -265,7 +264,7 @@ struct w9968cf_device {
 
        /* I2C interface to kernel */
        struct i2c_adapter i2c_adapter;
-       struct i2c_client* sensor_client;
+       struct v4l2_subdev *sensor_sd;
 
        /* Locks */
        struct mutex dev_mutex,    /* for probe, disconnect,open and close */
@@ -277,6 +276,11 @@ struct w9968cf_device {
        char command[16]; /* name of the program holding the device */
 };
 
+static inline struct w9968cf_device *to_cam(struct v4l2_device *v4l2_dev)
+{
+       return container_of(v4l2_dev, struct w9968cf_device, v4l2_dev);
+}
+
 
 /****************************************************************************
  * Macros for debugging                                                     *
@@ -291,14 +295,14 @@ struct w9968cf_device {
        if ( ((specific_debug) && (debug == (level))) ||                      \
             ((!specific_debug) && (debug >= (level))) ) {                    \
                if ((level) == 1)                                             \
-                       dev_err(&cam->dev, fmt "\n", ## args);                \
+                       v4l2_err(&cam->v4l2_dev, fmt "\n", ## args);          \
                else if ((level) == 2 || (level) == 3)                        \
-                       dev_info(&cam->dev, fmt "\n", ## args);               \
+                       v4l2_info(&cam->v4l2_dev, fmt "\n", ## args);         \
                else if ((level) == 4)                                        \
-                       dev_warn(&cam->dev, fmt "\n", ## args);               \
+                       v4l2_warn(&cam->v4l2_dev, fmt "\n", ## args);         \
                else if ((level) >= 5)                                        \
-                       dev_info(&cam->dev, "[%s:%d] " fmt "\n",              \
-                                __func__, __LINE__ , ## args);           \
+                       v4l2_info(&cam->v4l2_dev, "[%s:%d] " fmt "\n",        \
+                                __func__, __LINE__ , ## args);               \
        }                                                                     \
 }
 /* For generic kernel (not device specific) messages */
@@ -321,7 +325,7 @@ struct w9968cf_device {
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __func__, __LINE__ , ## args);
+v4l2_info(&cam->v4l2_dev, "[%s:%d] " fmt "\n", __func__, __LINE__ , ## args);
 
 #undef PDBGG
 #define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
index f2864d5cd1800c5662e6985bf5be2fdeafcb8c71..b572ce288e14857d2e6f3f9fffe2675a5f111d89 100644 (file)
@@ -252,11 +252,6 @@ static int wm8739_log_status(struct v4l2_subdev *sd)
        return 0;
 }
 
-static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops wm8739_core_ops = {
@@ -343,8 +338,6 @@ MODULE_DEVICE_TABLE(i2c, wm8739_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "wm8739",
-       .driverid = I2C_DRIVERID_WM8739,
-       .command = wm8739_command,
        .probe = wm8739_probe,
        .remove = wm8739_remove,
        .id_table = wm8739_id,
index 53fcd42843e0eae0ef6c998002db002f8d37e355..eddf11abe1d9e93e279754da4e418f533b047be6 100644 (file)
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("wm8775 driver");
 MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
 MODULE_LICENSE("GPL");
 
-static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
 
 
 /* ----------------------------------------------------------------------- */
@@ -161,11 +158,6 @@ static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *fre
        return 0;
 }
 
-static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops wm8775_core_ops = {
@@ -268,8 +260,6 @@ MODULE_DEVICE_TABLE(i2c, wm8775_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "wm8775",
-       .driverid = I2C_DRIVERID_WM8775,
-       .command = wm8775_command,
        .probe = wm8775_probe,
        .remove = wm8775_remove,
        .id_table = wm8775_id,
index b0cd49c438a3259b18490b50023864abd44b5756..3a408de91b9cc46f7195b812f3b563ad85c03523 100644 (file)
@@ -58,12 +58,20 @@ zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
        .idProduct = (prod),                                                  \
        .bInterfaceClass = (intclass)
 
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
 #define ZC0301_ID_TABLE                                                       \
 static const struct usb_device_id zc0301_id_table[] =  {                      \
        { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
        { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */           \
        { }                                                                   \
 };
+#else
+#define ZC0301_ID_TABLE                                                       \
+static const struct usb_device_id zc0301_id_table[] =  {                      \
+       { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
+       { }                                                                   \
+};
+#endif
 
 /*****************************************************************************/
 
index 8666e19f31a7288d413ab586f6cdb6571936c46a..fd4120e4c104490d9cbb0f6bda4971b049e673a5 100644 (file)
@@ -1,6 +1,6 @@
 config VIDEO_ZORAN
        tristate "Zoran ZR36057/36067 Video For Linux"
-       depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && VIRT_TO_BUS
+       depends on PCI && I2C_ALGOBIT && VIDEO_V4L2 && VIRT_TO_BUS
        help
          Say Y for support for MJPEG capture cards based on the Zoran
          36057/36067 PCI controller chipset. This includes the Iomega
@@ -32,7 +32,7 @@ config VIDEO_ZORAN_ZR36060
 config VIDEO_ZORAN_BUZ
        tristate "Iomega Buz support"
        depends on VIDEO_ZORAN_ZR36060
-       select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
+       select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
        help
          Support for the Iomega Buz MJPEG capture/playback card.
@@ -58,7 +58,7 @@ config VIDEO_ZORAN_LML33
 config VIDEO_ZORAN_LML33R10
        tristate "Linux Media Labs LML33R10 support"
        depends on VIDEO_ZORAN_ZR36060
-       select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO
+       select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO
        help
          support for the Linux Media Labs LML33R10 MJPEG capture/playback
@@ -66,7 +66,7 @@ config VIDEO_ZORAN_LML33R10
 
 config VIDEO_ZORAN_AVS6EYES
        tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
-       depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL && VIDEO_V4L1
+       depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL
        select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_BT866 if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
index 97a3bbeda5056acfa1a9fed0f05b836d6ce08269..5c27b251354e5019bc1dff232d2e9f087ba2932c 100644 (file)
@@ -97,7 +97,7 @@
               available) - it returns 0 if the mode is possible
    set_size -> this fn-ref. sets the norm and image size for
               compression/decompression (returns 0 on success)
-              the norm param is defined in videodev.h (VIDEO_MODE_*)
+              the norm param is defined in videodev2.h (V4L2_STD_*)
 
    additional setup may be available, too - but the codec should work with
    some default values even without this
@@ -144,9 +144,8 @@ M                       zr36055[1] 0001 0000c001 00000000 (zr36050[1])
 #ifndef __LINUX_VIDEOCODEC_H
 #define __LINUX_VIDEOCODEC_H
 
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 
-//should be in videodev.h ??? (VID_DO_....)
 #define CODEC_DO_COMPRESSION 0
 #define CODEC_DO_EXPANSION   1
 
@@ -237,10 +236,6 @@ struct vfe_settings {
        __u32 width, height;    /* Area to capture */
        __u16 decimation;       /* Decimation divider */
        __u16 flags;            /* Flags for capture */
-/* flags are the same as in struct video_capture - see videodev.h:
-#define VIDEO_CAPTURE_ODD              0
-#define VIDEO_CAPTURE_EVEN             1
-*/
        __u16 quality;          /* quality of the video */
 };
 
index e873a916250f4dbfbca98370413eb064a9c3f81b..afecf32f1a87c5a709eccd0a8db5fa798f658350 100644 (file)
@@ -31,6 +31,8 @@
 #ifndef _BUZ_H_
 #define _BUZ_H_
 
+#include <media/v4l2-device.h>
+
 struct zoran_requestbuffers {
        unsigned long count;    /* Number of buffers for MJPEG grabbing */
        unsigned long size;     /* Size PER BUFFER in bytes */
@@ -170,7 +172,7 @@ Private IOCTL to set up for displaying MJPEG
 #endif
 #define   V4L_MASK_FRAME   (V4L_MAX_FRAME - 1)
 
-#define MAX_KMALLOC_MEM (128*1024)
+#define MAX_FRAME (BUZ_MAX_FRAME > VIDEO_MAX_FRAME ? BUZ_MAX_FRAME : VIDEO_MAX_FRAME)
 
 #include "zr36057.h"
 
@@ -240,9 +242,6 @@ enum gpcs_type {
 
 struct zoran_format {
        char *name;
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       int palette;
-#endif
        __u32 fourcc;
        int colorspace;
        int depth;
@@ -283,21 +282,21 @@ struct zoran_mapping {
        int count;
 };
 
-struct zoran_jpg_buffer {
-       struct zoran_mapping *map;
-       __le32 *frag_tab;               /* addresses of frag table */
-       u32 frag_tab_bus;       /* same value cached to save time in ISR */
-       enum zoran_buffer_state state;  /* non-zero if corresponding buffer is in use in grab queue */
-       struct zoran_sync bs;   /* DONE: info to return to application */
-};
-
-struct zoran_v4l_buffer {
+struct zoran_buffer {
        struct zoran_mapping *map;
-       char *fbuffer;          /* virtual  address of frame buffer */
-       unsigned long fbuffer_phys;     /* physical address of frame buffer */
-       unsigned long fbuffer_bus;      /* bus      address of frame buffer */
-       enum zoran_buffer_state state;  /* state: unused/pending/done */
-       struct zoran_sync bs;   /* DONE: info to return to application */
+       enum zoran_buffer_state state;  /* state: unused/pending/dma/done */
+       struct zoran_sync bs;           /* DONE: info to return to application */
+       union {
+               struct {
+                       __le32 *frag_tab;       /* addresses of frag table */
+                       u32 frag_tab_bus;       /* same value cached to save time in ISR */
+               } jpg;
+               struct {
+                       char *fbuffer;          /* virtual address of frame buffer */
+                       unsigned long fbuffer_phys;/* physical address of frame buffer */
+                       unsigned long fbuffer_bus;/* bus address of frame buffer */
+               } v4l;
+       };
 };
 
 enum zoran_lock_activity {
@@ -307,21 +306,13 @@ enum zoran_lock_activity {
 };
 
 /* buffer collections */
-struct zoran_jpg_struct {
+struct zoran_buffer_col {
        enum zoran_lock_activity active;        /* feature currently in use? */
-       struct zoran_jpg_buffer buffer[BUZ_MAX_FRAME];  /* buffers */
-       int num_buffers, buffer_size;
+       unsigned int num_buffers, buffer_size;
+       struct zoran_buffer buffer[MAX_FRAME];  /* buffers */
        u8 allocated;           /* Flag if buffers are allocated  */
-       u8 ready_to_be_freed;   /* hack - see zoran_driver.c */
        u8 need_contiguous;     /* Flag if contiguous buffers are needed */
-};
-
-struct zoran_v4l_struct {
-       enum zoran_lock_activity active;        /* feature currently in use? */
-       struct zoran_v4l_buffer buffer[VIDEO_MAX_FRAME];        /* buffers */
-       int num_buffers, buffer_size;
-       u8 allocated;           /* Flag if buffers are allocated  */
-       u8 ready_to_be_freed;   /* hack - see zoran_driver.c */
+       /* only applies to jpg buffers, raw buffers are always contiguous */
 };
 
 struct zoran;
@@ -330,23 +321,27 @@ struct zoran;
 struct zoran_fh {
        struct zoran *zr;
 
-       enum zoran_map_mode map_mode;   /* Flag which bufferset will map by next mmap() */
+       enum zoran_map_mode map_mode;           /* Flag which bufferset will map by next mmap() */
 
        struct zoran_overlay_settings overlay_settings;
-       u32 *overlay_mask;      /* overlay mask */
-       enum zoran_lock_activity overlay_active;        /* feature currently in use? */
+       u32 *overlay_mask;                      /* overlay mask */
+       enum zoran_lock_activity overlay_active;/* feature currently in use? */
 
-       struct zoran_v4l_settings v4l_settings; /* structure with a lot of things to play with */
-       struct zoran_v4l_struct v4l_buffers;    /* V4L buffers' info */
+       struct zoran_buffer_col buffers;        /* buffers' info */
 
+       struct zoran_v4l_settings v4l_settings; /* structure with a lot of things to play with */
        struct zoran_jpg_settings jpg_settings; /* structure with a lot of things to play with */
-       struct zoran_jpg_struct jpg_buffers;    /* MJPEG buffers' info */
 };
 
 struct card_info {
        enum card_type type;
        char name[32];
-       u16 i2c_decoder, i2c_encoder;                   /* I2C types */
+       const char *i2c_decoder;        /* i2c decoder device */
+       const char *mod_decoder;        /* i2c decoder module */
+       const unsigned short *addrs_decoder;
+       const char *i2c_encoder;        /* i2c encoder device */
+       const char *mod_encoder;        /* i2c encoder module */
+       const unsigned short *addrs_encoder;
        u16 video_vfe, video_codec;                     /* videocodec types */
        u16 audio_chip;                                 /* audio type */
 
@@ -356,7 +351,7 @@ struct card_info {
                char name[32];
        } input[BUZ_MAX_INPUT];
 
-       int norms;
+       v4l2_std_id norms;
        struct tvnorm *tvn[3];  /* supported TV norms */
 
        u32 jpeg_int;           /* JPEG interrupt */
@@ -377,14 +372,15 @@ struct card_info {
 };
 
 struct zoran {
+       struct v4l2_device v4l2_dev;
        struct video_device *video_dev;
 
        struct i2c_adapter i2c_adapter; /* */
        struct i2c_algo_bit_data i2c_algo;      /* */
        u32 i2cbr;
 
-       struct i2c_client *decoder;     /* video decoder i2c client */
-       struct i2c_client *encoder;     /* video encoder i2c client */
+       struct v4l2_subdev *decoder;    /* video decoder sub-device */
+       struct v4l2_subdev *encoder;    /* video encoder sub-device */
 
        struct videocodec *codec;       /* video codec */
        struct videocodec *vfe; /* video front end */
@@ -405,9 +401,15 @@ struct zoran {
        spinlock_t spinlock;    /* Spinlock */
 
        /* Video for Linux parameters */
-       int input, norm;        /* card's norm and input - norm=VIDEO_MODE_* */
-       int hue, saturation, contrast, brightness;      /* Current picture params */
-       struct video_buffer buffer;     /* Current buffer params */
+       int input;      /* card's norm and input - norm=VIDEO_MODE_* */
+       v4l2_std_id norm;
+
+       /* Current buffer params */
+       void    *vbuf_base;
+       int     vbuf_height, vbuf_width;
+       int     vbuf_depth;
+       int     vbuf_bytesperline;
+
        struct zoran_overlay_settings overlay_settings;
        u32 *overlay_mask;      /* overlay mask */
        enum zoran_lock_activity overlay_active;        /* feature currently in use? */
@@ -427,7 +429,7 @@ struct zoran {
        unsigned long v4l_pend_tail;
        unsigned long v4l_sync_tail;
        int v4l_pend[V4L_MAX_FRAME];
-       struct zoran_v4l_struct v4l_buffers;    /* V4L buffers' info */
+       struct zoran_buffer_col v4l_buffers;    /* V4L buffers' info */
 
        /* Buz MJPEG parameters */
        enum zoran_codec_mode codec_mode;       /* status of codec */
@@ -454,7 +456,7 @@ struct zoran {
        int jpg_pend[BUZ_MAX_FRAME];
 
        /* array indexed by frame number */
-       struct zoran_jpg_struct jpg_buffers;    /* MJPEG buffers' info */
+       struct zoran_buffer_col jpg_buffers;    /* MJPEG buffers' info */
 
        /* Additional stuff for testing */
 #ifdef CONFIG_PROC_FS
@@ -488,6 +490,11 @@ struct zoran {
        wait_queue_head_t test_q;
 };
 
+static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev)
+{
+       return container_of(v4l2_dev, struct zoran, v4l2_dev);
+}
+
 /* There was something called _ALPHA_BUZ that used the PCI address instead of
  * the kernel iomapped address for btread/btwrite.  */
 #define btwrite(dat,adr)    writel((dat), zr->zr36057_mem+(adr))
index 5d2f090aa0f82c12aa3adec4daed69bffea4d63a..f91bba435ed56f394a96ef73e80446b6a6d4efe0 100644 (file)
@@ -38,8 +38,7 @@
 #include <linux/proc_fs.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
+#include <linux/videodev2.h>
 #include <linux/spinlock.h>
 #include <linux/sem.h>
 #include <linux/kmod.h>
 
 #include <linux/pci.h>
 #include <linux/interrupt.h>
-#include <linux/video_decoder.h>
-#include <linux/video_encoder.h>
 #include <linux/mutex.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
+#include <media/v4l2-common.h>
+#include <media/bt819.h>
 
 #include "videocodec.h"
 #include "zoran.h"
@@ -108,25 +106,8 @@ static int video_nr[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 };
 module_param_array(video_nr, int, NULL, 0444);
 MODULE_PARM_DESC(video_nr, "Video device number (-1=Auto)");
 
-/*
-   Number and size of grab buffers for Video 4 Linux
-   The vast majority of applications should not need more than 2,
-   the very popular BTTV driver actually does ONLY have 2.
-   Time sensitive applications might need more, the maximum
-   is VIDEO_MAX_FRAME (defined in <linux/videodev.h>).
-
-   The size is set so that the maximum possible request
-   can be satisfied. Decrease  it, if bigphys_area alloc'd
-   memory is low. If you don't have the bigphys_area patch,
-   set it to 128 KB. Will you allow only to grab small
-   images with V4L, but that's better than nothing.
-
-   v4l_bufsize has to be given in KB !
-
-*/
-
-int v4l_nbufs = 2;
-int v4l_bufsize = 128;         /* Everybody should be able to work with this setting */
+int v4l_nbufs = 4;
+int v4l_bufsize = 864;         /* Everybody should be able to work with this setting */
 module_param(v4l_nbufs, int, 0644);
 MODULE_PARM_DESC(v4l_nbufs, "Maximum number of V4L buffers to use");
 module_param(v4l_bufsize, int, 0644);
@@ -273,7 +254,7 @@ zr36016_write (struct videocodec *codec,
 static void
 dc10_init (struct zoran *zr)
 {
-       dprintk(3, KERN_DEBUG "%s: dc10_init()\n", ZR_DEVNAME(zr));
+       dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
 
        /* Pixel clock selection */
        GPIO(zr, 4, 0);
@@ -285,13 +266,13 @@ dc10_init (struct zoran *zr)
 static void
 dc10plus_init (struct zoran *zr)
 {
-       dprintk(3, KERN_DEBUG "%s: dc10plus_init()\n", ZR_DEVNAME(zr));
+       dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
 }
 
 static void
 buz_init (struct zoran *zr)
 {
-       dprintk(3, KERN_DEBUG "%s: buz_init()\n", ZR_DEVNAME(zr));
+       dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
 
        /* some stuff from Iomega */
        pci_write_config_dword(zr->pci_dev, 0xfc, 0x90680f15);
@@ -302,7 +283,7 @@ buz_init (struct zoran *zr)
 static void
 lml33_init (struct zoran *zr)
 {
-       dprintk(3, KERN_DEBUG "%s: lml33_init()\n", ZR_DEVNAME(zr));
+       dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
 
        GPIO(zr, 2, 1);         // Set Composite input/output
 }
@@ -331,50 +312,6 @@ avs6eyes_init (struct zoran *zr)
 
 }
 
-static char *
-i2cid_to_modulename (u16 i2c_id)
-{
-       char *name = NULL;
-
-       switch (i2c_id) {
-       case I2C_DRIVERID_SAA7110:
-               name = "saa7110";
-               break;
-       case I2C_DRIVERID_SAA7111A:
-               name = "saa7111";
-               break;
-       case I2C_DRIVERID_SAA7114:
-               name = "saa7114";
-               break;
-       case I2C_DRIVERID_SAA7185B:
-               name = "saa7185";
-               break;
-       case I2C_DRIVERID_ADV7170:
-               name = "adv7170";
-               break;
-       case I2C_DRIVERID_ADV7175:
-               name = "adv7175";
-               break;
-       case I2C_DRIVERID_BT819:
-               name = "bt819";
-               break;
-       case I2C_DRIVERID_BT856:
-               name = "bt856";
-               break;
-       case I2C_DRIVERID_BT866:
-               name = "bt866";
-               break;
-       case I2C_DRIVERID_VPX3220:
-               name = "vpx3220";
-               break;
-       case I2C_DRIVERID_KS0127:
-               name = "ks0127";
-               break;
-       }
-
-       return name;
-}
-
 static char *
 codecid_to_modulename (u16 codecid)
 {
@@ -425,11 +362,24 @@ static struct tvnorm f60ccir601_lm33r10 = { 858, 720, 56+54, 788, 525, 480, 16 }
 static struct tvnorm f50ccir601_avs6eyes = { 864, 720, 74, 804, 625, 576, 18 };
 static struct tvnorm f60ccir601_avs6eyes = { 858, 720, 56, 788, 525, 480, 16 };
 
+static const unsigned short vpx3220_addrs[] = { 0x43, 0x47, I2C_CLIENT_END };
+static const unsigned short saa7110_addrs[] = { 0x4e, 0x4f, I2C_CLIENT_END };
+static const unsigned short saa7111_addrs[] = { 0x25, 0x24, I2C_CLIENT_END };
+static const unsigned short saa7114_addrs[] = { 0x21, 0x20, I2C_CLIENT_END };
+static const unsigned short adv717x_addrs[] = { 0x6a, 0x6b, 0x2a, 0x2b, I2C_CLIENT_END };
+static const unsigned short ks0127_addrs[] = { 0x6c, 0x6d, I2C_CLIENT_END };
+static const unsigned short saa7185_addrs[] = { 0x44, I2C_CLIENT_END };
+static const unsigned short bt819_addrs[] = { 0x45, I2C_CLIENT_END };
+static const unsigned short bt856_addrs[] = { 0x44, I2C_CLIENT_END };
+static const unsigned short bt866_addrs[] = { 0x44, I2C_CLIENT_END };
+
 static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
        {
                .type = DC10_old,
                .name = "DC10(old)",
-               .i2c_decoder = I2C_DRIVERID_VPX3220,
+               .i2c_decoder = "vpx3220a",
+               .mod_decoder = "vpx3220",
+               .addrs_decoder = vpx3220_addrs,
                .video_codec = CODEC_TYPE_ZR36050,
                .video_vfe = CODEC_TYPE_ZR36016,
 
@@ -439,7 +389,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                        { 2, "S-Video" },
                        { 0, "Internal/comp" }
                },
-               .norms = 3,
+               .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
                .tvn = {
                        &f50sqpixel_dc10,
                        &f60sqpixel_dc10,
@@ -457,8 +407,12 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
        }, {
                .type = DC10_new,
                .name = "DC10(new)",
-               .i2c_decoder = I2C_DRIVERID_SAA7110,
-               .i2c_encoder = I2C_DRIVERID_ADV7175,
+               .i2c_decoder = "saa7110",
+               .mod_decoder = "saa7110",
+               .addrs_decoder = saa7110_addrs,
+               .i2c_encoder = "adv7175",
+               .mod_encoder = "adv7175",
+               .addrs_encoder = adv717x_addrs,
                .video_codec = CODEC_TYPE_ZR36060,
 
                .inputs = 3,
@@ -467,7 +421,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                                { 7, "S-Video" },
                                { 5, "Internal/comp" }
                        },
-               .norms = 3,
+               .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
                .tvn = {
                                &f50sqpixel,
                                &f60sqpixel,
@@ -484,8 +438,12 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
        }, {
                .type = DC10plus,
                .name = "DC10plus",
-               .i2c_decoder = I2C_DRIVERID_SAA7110,
-               .i2c_encoder = I2C_DRIVERID_ADV7175,
+               .i2c_decoder = "saa7110",
+               .mod_decoder = "saa7110",
+               .addrs_decoder = saa7110_addrs,
+               .i2c_encoder = "adv7175",
+               .mod_encoder = "adv7175",
+               .addrs_encoder = adv717x_addrs,
                .video_codec = CODEC_TYPE_ZR36060,
 
                .inputs = 3,
@@ -494,7 +452,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                        { 7, "S-Video" },
                        { 5, "Internal/comp" }
                },
-               .norms = 3,
+               .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
                .tvn = {
                        &f50sqpixel,
                        &f60sqpixel,
@@ -512,8 +470,12 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
        }, {
                .type = DC30,
                .name = "DC30",
-               .i2c_decoder = I2C_DRIVERID_VPX3220,
-               .i2c_encoder = I2C_DRIVERID_ADV7175,
+               .i2c_decoder = "vpx3220a",
+               .mod_decoder = "vpx3220",
+               .addrs_decoder = vpx3220_addrs,
+               .i2c_encoder = "adv7175",
+               .mod_encoder = "adv7175",
+               .addrs_encoder = adv717x_addrs,
                .video_codec = CODEC_TYPE_ZR36050,
                .video_vfe = CODEC_TYPE_ZR36016,
 
@@ -523,7 +485,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                        { 2, "S-Video" },
                        { 0, "Internal/comp" }
                },
-               .norms = 3,
+               .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
                .tvn = {
                        &f50sqpixel_dc10,
                        &f60sqpixel_dc10,
@@ -541,8 +503,12 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
        }, {
                .type = DC30plus,
                .name = "DC30plus",
-               .i2c_decoder = I2C_DRIVERID_VPX3220,
-               .i2c_encoder = I2C_DRIVERID_ADV7175,
+               .i2c_decoder = "vpx3220a",
+               .mod_decoder = "vpx3220",
+               .addrs_decoder = vpx3220_addrs,
+               .i2c_encoder = "adv7175",
+               .mod_encoder = "adv7175",
+               .addrs_encoder = adv717x_addrs,
                .video_codec = CODEC_TYPE_ZR36050,
                .video_vfe = CODEC_TYPE_ZR36016,
 
@@ -552,7 +518,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                        { 2, "S-Video" },
                        { 0, "Internal/comp" }
                },
-               .norms = 3,
+               .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
                .tvn = {
                        &f50sqpixel_dc10,
                        &f60sqpixel_dc10,
@@ -570,8 +536,12 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
        }, {
                .type = LML33,
                .name = "LML33",
-               .i2c_decoder = I2C_DRIVERID_BT819,
-               .i2c_encoder = I2C_DRIVERID_BT856,
+               .i2c_decoder = "bt819a",
+               .mod_decoder = "bt819",
+               .addrs_decoder = bt819_addrs,
+               .i2c_encoder = "bt856",
+               .mod_encoder = "bt856",
+               .addrs_encoder = bt856_addrs,
                .video_codec = CODEC_TYPE_ZR36060,
 
                .inputs = 2,
@@ -579,7 +549,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                        { 0, "Composite" },
                        { 7, "S-Video" }
                },
-               .norms = 2,
+               .norms = V4L2_STD_NTSC|V4L2_STD_PAL,
                .tvn = {
                        &f50ccir601_lml33,
                        &f60ccir601_lml33,
@@ -597,8 +567,12 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
        }, {
                .type = LML33R10,
                .name = "LML33R10",
-               .i2c_decoder = I2C_DRIVERID_SAA7114,
-               .i2c_encoder = I2C_DRIVERID_ADV7170,
+               .i2c_decoder = "saa7114",
+               .mod_decoder = "saa7115",
+               .addrs_decoder = saa7114_addrs,
+               .i2c_encoder = "adv7170",
+               .mod_encoder = "adv7170",
+               .addrs_encoder = adv717x_addrs,
                .video_codec = CODEC_TYPE_ZR36060,
 
                .inputs = 2,
@@ -606,7 +580,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                        { 0, "Composite" },
                        { 7, "S-Video" }
                },
-               .norms = 2,
+               .norms = V4L2_STD_NTSC|V4L2_STD_PAL,
                .tvn = {
                        &f50ccir601_lm33r10,
                        &f60ccir601_lm33r10,
@@ -624,8 +598,12 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
        }, {
                .type = BUZ,
                .name = "Buz",
-               .i2c_decoder = I2C_DRIVERID_SAA7111A,
-               .i2c_encoder = I2C_DRIVERID_SAA7185B,
+               .i2c_decoder = "saa7111",
+               .mod_decoder = "saa7115",
+               .addrs_decoder = saa7111_addrs,
+               .i2c_encoder = "saa7185",
+               .mod_encoder = "saa7185",
+               .addrs_encoder = saa7185_addrs,
                .video_codec = CODEC_TYPE_ZR36060,
 
                .inputs = 2,
@@ -633,7 +611,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                        { 3, "Composite" },
                        { 7, "S-Video" }
                },
-               .norms = 3,
+               .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
                .tvn = {
                        &f50ccir601,
                        &f60ccir601,
@@ -653,8 +631,12 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .name = "6-Eyes",
                /* AverMedia chose not to brand the 6-Eyes. Thus it
                   can't be autodetected, and requires card=x. */
-               .i2c_decoder = I2C_DRIVERID_KS0127,
-               .i2c_encoder = I2C_DRIVERID_BT866,
+               .i2c_decoder = "ks0127",
+               .mod_decoder = "ks0127",
+               .addrs_decoder = ks0127_addrs,
+               .i2c_encoder = "bt866",
+               .mod_encoder = "bt866",
+               .addrs_encoder = bt866_addrs,
                .video_codec = CODEC_TYPE_ZR36060,
 
                .inputs = 10,
@@ -670,7 +652,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                        {10, "S-Video 3" },
                        {15, "YCbCr" }
                },
-               .norms = 2,
+               .norms = V4L2_STD_NTSC|V4L2_STD_PAL,
                .tvn = {
                        &f50ccir601_avs6eyes,
                        &f60ccir601_avs6eyes,
@@ -735,69 +717,6 @@ zoran_i2c_setscl (void *data,
        btwrite(zr->i2cbr, ZR36057_I2CBR);
 }
 
-static int
-zoran_i2c_client_register (struct i2c_client *client)
-{
-       struct zoran *zr = (struct zoran *) i2c_get_adapdata(client->adapter);
-       int res = 0;
-
-       dprintk(2,
-               KERN_DEBUG "%s: i2c_client_register() - driver id = %d\n",
-               ZR_DEVNAME(zr), client->driver->id);
-
-       mutex_lock(&zr->resource_lock);
-
-       if (zr->user > 0) {
-               /* we're already busy, so we keep a reference to
-                * them... Could do a lot of stuff here, but this
-                * is easiest. (Did I ever mention I'm a lazy ass?)
-                */
-               res = -EBUSY;
-               goto clientreg_unlock_and_return;
-       }
-
-       if (client->driver->id == zr->card.i2c_decoder)
-               zr->decoder = client;
-       else if (client->driver->id == zr->card.i2c_encoder)
-               zr->encoder = client;
-       else {
-               res = -ENODEV;
-               goto clientreg_unlock_and_return;
-       }
-
-clientreg_unlock_and_return:
-       mutex_unlock(&zr->resource_lock);
-
-       return res;
-}
-
-static int
-zoran_i2c_client_unregister (struct i2c_client *client)
-{
-       struct zoran *zr = (struct zoran *) i2c_get_adapdata(client->adapter);
-       int res = 0;
-
-       dprintk(2, KERN_DEBUG "%s: i2c_client_unregister()\n", ZR_DEVNAME(zr));
-
-       mutex_lock(&zr->resource_lock);
-
-       if (zr->user > 0) {
-               res = -EBUSY;
-               goto clientunreg_unlock_and_return;
-       }
-
-       /* try to locate it */
-       if (client == zr->encoder) {
-               zr->encoder = NULL;
-       } else if (client == zr->decoder) {
-               zr->decoder = NULL;
-               snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%d]", zr->id);
-       }
-clientunreg_unlock_and_return:
-       mutex_unlock(&zr->resource_lock);
-       return res;
-}
-
 static const struct i2c_algo_bit_data zoran_i2c_bit_data_template = {
        .setsda = zoran_i2c_setsda,
        .setscl = zoran_i2c_setscl,
@@ -813,13 +732,10 @@ 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.class = I2C_CLASS_TV_ANALOG;
        zr->i2c_adapter.id = I2C_HW_B_ZR36067;
-       zr->i2c_adapter.client_register = zoran_i2c_client_register;
-       zr->i2c_adapter.client_unregister = zoran_i2c_client_unregister;
        strlcpy(zr->i2c_adapter.name, ZR_DEVNAME(zr),
                sizeof(zr->i2c_adapter.name));
-       i2c_set_adapdata(&zr->i2c_adapter, zr);
+       i2c_set_adapdata(&zr->i2c_adapter, &zr->v4l2_dev);
        zr->i2c_adapter.algo_data = &zr->i2c_algo;
        zr->i2c_adapter.dev.parent = &zr->pci_dev->dev;
        return i2c_bit_add_bus(&zr->i2c_adapter);
@@ -835,19 +751,20 @@ zoran_unregister_i2c (struct zoran *zr)
 
 int
 zoran_check_jpg_settings (struct zoran              *zr,
-                         struct zoran_jpg_settings *settings)
+                         struct zoran_jpg_settings *settings,
+                         int try)
 {
        int err = 0, err0 = 0;
 
        dprintk(4,
                KERN_DEBUG
-               "%s: check_jpg_settings() - dec: %d, Hdcm: %d, Vdcm: %d, Tdcm: %d\n",
-               ZR_DEVNAME(zr), settings->decimation, settings->HorDcm,
+               "%s: %s - dec: %d, Hdcm: %d, Vdcm: %d, Tdcm: %d\n",
+               ZR_DEVNAME(zr), __func__, settings->decimation, settings->HorDcm,
                settings->VerDcm, settings->TmpDcm);
        dprintk(4,
                KERN_DEBUG
-               "%s: check_jpg_settings() - x: %d, y: %d, w: %d, y: %d\n",
-               ZR_DEVNAME(zr), settings->img_x, settings->img_y,
+               "%s: %s - x: %d, y: %d, w: %d, y: %d\n",
+               ZR_DEVNAME(zr), __func__, settings->img_x, settings->img_y,
                settings->img_width, settings->img_height);
        /* Check decimation, set default values for decimation = 1, 2, 4 */
        switch (settings->decimation) {
@@ -879,8 +796,8 @@ zoran_check_jpg_settings (struct zoran              *zr,
                if (zr->card.type == DC10_new) {
                        dprintk(1,
                                KERN_DEBUG
-                               "%s: check_jpg_settings() - HDec by 4 is not supported on the DC10\n",
-                               ZR_DEVNAME(zr));
+                               "%s: %s - HDec by 4 is not supported on the DC10\n",
+                               ZR_DEVNAME(zr), __func__);
                        err0++;
                        break;
                }
@@ -900,50 +817,73 @@ zoran_check_jpg_settings (struct zoran              *zr,
                /* We have to check the data the user has set */
 
                if (settings->HorDcm != 1 && settings->HorDcm != 2 &&
-                   (zr->card.type == DC10_new || settings->HorDcm != 4))
+                   (zr->card.type == DC10_new || settings->HorDcm != 4)) {
+                       settings->HorDcm = clamp(settings->HorDcm, 1, 2);
                        err0++;
-               if (settings->VerDcm != 1 && settings->VerDcm != 2)
+               }
+               if (settings->VerDcm != 1 && settings->VerDcm != 2) {
+                       settings->VerDcm = clamp(settings->VerDcm, 1, 2);
                        err0++;
-               if (settings->TmpDcm != 1 && settings->TmpDcm != 2)
+               }
+               if (settings->TmpDcm != 1 && settings->TmpDcm != 2) {
+                       settings->TmpDcm = clamp(settings->TmpDcm, 1, 2);
                        err0++;
+               }
                if (settings->field_per_buff != 1 &&
-                   settings->field_per_buff != 2)
+                   settings->field_per_buff != 2) {
+                       settings->field_per_buff = clamp(settings->field_per_buff, 1, 2);
                        err0++;
-               if (settings->img_x < 0)
+               }
+               if (settings->img_x < 0) {
+                       settings->img_x = 0;
                        err0++;
-               if (settings->img_y < 0)
+               }
+               if (settings->img_y < 0) {
+                       settings->img_y = 0;
                        err0++;
-               if (settings->img_width < 0)
+               }
+               if (settings->img_width < 0 || settings->img_width > BUZ_MAX_WIDTH) {
+                       settings->img_width = clamp(settings->img_width, 0, (int)BUZ_MAX_WIDTH);
                        err0++;
-               if (settings->img_height < 0)
+               }
+               if (settings->img_height < 0 || settings->img_height > BUZ_MAX_HEIGHT / 2) {
+                       settings->img_height = clamp(settings->img_height, 0, BUZ_MAX_HEIGHT / 2);
                        err0++;
-               if (settings->img_x + settings->img_width > BUZ_MAX_WIDTH)
+               }
+               if (settings->img_x + settings->img_width > BUZ_MAX_WIDTH) {
+                       settings->img_x = BUZ_MAX_WIDTH - settings->img_width;
                        err0++;
-               if (settings->img_y + settings->img_height >
-                   BUZ_MAX_HEIGHT / 2)
+               }
+               if (settings->img_y + settings->img_height > BUZ_MAX_HEIGHT / 2) {
+                       settings->img_y = BUZ_MAX_HEIGHT / 2 - settings->img_height;
+                       err0++;
+               }
+               if (settings->img_width % (16 * settings->HorDcm) != 0) {
+                       settings->img_width -= settings->img_width % (16 * settings->HorDcm);
+                       if (settings->img_width == 0)
+                               settings->img_width = 16 * settings->HorDcm;
+                       err0++;
+               }
+               if (settings->img_height % (8 * settings->VerDcm) != 0) {
+                       settings->img_height -= settings->img_height % (8 * settings->VerDcm);
+                       if (settings->img_height == 0)
+                               settings->img_height = 8 * settings->VerDcm;
                        err0++;
-               if (settings->HorDcm && settings->VerDcm) {
-                       if (settings->img_width %
-                           (16 * settings->HorDcm) != 0)
-                               err0++;
-                       if (settings->img_height %
-                           (8 * settings->VerDcm) != 0)
-                               err0++;
                }
 
-               if (err0) {
+               if (!try && err0) {
                        dprintk(1,
                                KERN_ERR
-                               "%s: check_jpg_settings() - error in params for decimation = 0\n",
-                               ZR_DEVNAME(zr));
+                               "%s: %s - error in params for decimation = 0\n",
+                               ZR_DEVNAME(zr), __func__);
                        err++;
                }
                break;
        default:
                dprintk(1,
                        KERN_ERR
-                       "%s: check_jpg_settings() - decimation = %d, must be 0, 1, 2 or 4\n",
-                       ZR_DEVNAME(zr), settings->decimation);
+                       "%s: %s - decimation = %d, must be 0, 1, 2 or 4\n",
+                       ZR_DEVNAME(zr), __func__, settings->decimation);
                err++;
                break;
        }
@@ -1021,12 +961,10 @@ zoran_open_init_params (struct zoran *zr)
               sizeof(zr->jpg_settings.jpg_comp.COM_data));
        zr->jpg_settings.jpg_comp.jpeg_markers =
            JPEG_MARKER_DHT | JPEG_MARKER_DQT;
-       i = zoran_check_jpg_settings(zr, &zr->jpg_settings);
+       i = zoran_check_jpg_settings(zr, &zr->jpg_settings, 0);
        if (i)
-               dprintk(1,
-                       KERN_ERR
-                       "%s: zoran_open_init_params() internal error\n",
-                       ZR_DEVNAME(zr));
+               dprintk(1, KERN_ERR "%s: %s internal error\n",
+                       ZR_DEVNAME(zr), __func__);
 
        clear_interrupt_counters(zr);
        zr->testing = 0;
@@ -1062,13 +1000,11 @@ static int __devinit
 zr36057_init (struct zoran *zr)
 {
        int j, err;
-       int two = 2;
-       int zero = 0;
 
        dprintk(1,
                KERN_INFO
-               "%s: zr36057_init() - initializing card[%d], zr=%p\n",
-               ZR_DEVNAME(zr), zr->id, zr);
+               "%s: %s - initializing card[%d], zr=%p\n",
+               ZR_DEVNAME(zr), __func__, zr->id, zr);
 
        /* default setup of all parameters which will persist between opens */
        zr->user = 0;
@@ -1079,24 +1015,32 @@ zr36057_init (struct zoran *zr)
        zr->jpg_buffers.allocated = 0;
        zr->v4l_buffers.allocated = 0;
 
-       zr->buffer.base = (void *) vidmem;
-       zr->buffer.width = 0;
-       zr->buffer.height = 0;
-       zr->buffer.depth = 0;
-       zr->buffer.bytesperline = 0;
+       zr->vbuf_base = (void *) vidmem;
+       zr->vbuf_width = 0;
+       zr->vbuf_height = 0;
+       zr->vbuf_depth = 0;
+       zr->vbuf_bytesperline = 0;
 
        /* Avoid nonsense settings from user for default input/norm */
-       if (default_norm < VIDEO_MODE_PAL &&
-           default_norm > VIDEO_MODE_SECAM)
-               default_norm = VIDEO_MODE_PAL;
-       zr->norm = default_norm;
-       if (!(zr->timing = zr->card.tvn[zr->norm])) {
+       if (default_norm < 0 && default_norm > 2)
+               default_norm = 0;
+       if (default_norm == 0) {
+               zr->norm = V4L2_STD_PAL;
+               zr->timing = zr->card.tvn[0];
+       } else if (default_norm == 1) {
+               zr->norm = V4L2_STD_NTSC;
+               zr->timing = zr->card.tvn[1];
+       } else {
+               zr->norm = V4L2_STD_SECAM;
+               zr->timing = zr->card.tvn[2];
+       }
+       if (zr->timing == NULL) {
                dprintk(1,
                        KERN_WARNING
-                       "%s: zr36057_init() - default TV standard not supported by hardware. PAL will be used.\n",
-                       ZR_DEVNAME(zr));
-               zr->norm = VIDEO_MODE_PAL;
-               zr->timing = zr->card.tvn[zr->norm];
+                       "%s: %s - default TV standard not supported by hardware. PAL will be used.\n",
+                       ZR_DEVNAME(zr), __func__);
+               zr->norm = V4L2_STD_PAL;
+               zr->timing = zr->card.tvn[0];
        }
 
        if (default_input > zr->card.inputs-1) {
@@ -1108,12 +1052,6 @@ zr36057_init (struct zoran *zr)
        }
        zr->input = default_input;
 
-       /* Should the following be reset at every open ? */
-       zr->hue = 32768;
-       zr->contrast = 32768;
-       zr->saturation = 32768;
-       zr->brightness = 32768;
-
        /* default setup (will be repeated at every open) */
        zoran_open_init_params(zr);
 
@@ -1124,8 +1062,8 @@ zr36057_init (struct zoran *zr)
        if (!zr->stat_com || !zr->video_dev) {
                dprintk(1,
                        KERN_ERR
-                       "%s: zr36057_init() - kmalloc (STAT_COM) failed\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - kmalloc (STAT_COM) failed\n",
+                       ZR_DEVNAME(zr), __func__);
                err = -ENOMEM;
                goto exit_free;
        }
@@ -1137,6 +1075,7 @@ zr36057_init (struct zoran *zr)
         *   Now add the template and register the device unit.
         */
        memcpy(zr->video_dev, &zoran_template, sizeof(zoran_template));
+       zr->video_dev->parent = &zr->pci_dev->dev;
        strcpy(zr->video_dev->name, ZR_DEVNAME(zr));
        err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr[zr->id]);
        if (err < 0)
@@ -1148,8 +1087,10 @@ zr36057_init (struct zoran *zr)
                detect_guest_activity(zr);
        test_interrupts(zr);
        if (!pass_through) {
-               decoder_command(zr, DECODER_ENABLE_OUTPUT, &zero);
-               encoder_command(zr, ENCODER_SET_INPUT, &two);
+               struct v4l2_routing route = { 2, 0 };
+
+               decoder_call(zr, video, s_stream, 0);
+               encoder_call(zr, video, s_routing, &route);
        }
 
        zr->zoran_proc = NULL;
@@ -1164,7 +1105,8 @@ exit_free:
 
 static void __devexit zoran_remove(struct pci_dev *pdev)
 {
-       struct zoran *zr = pci_get_drvdata(pdev);
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+       struct zoran *zr = to_zoran(v4l2_dev);
 
        if (!zr->initialized)
                goto exit_free;
@@ -1197,7 +1139,7 @@ static void __devexit zoran_remove(struct pci_dev *pdev)
        pci_disable_device(zr->pci_dev);
        video_unregister_device(zr->video_dev);
 exit_free:
-       pci_set_drvdata(pdev, NULL);
+       v4l2_device_unregister(&zr->v4l2_dev);
        kfree(zr);
 }
 
@@ -1215,10 +1157,8 @@ zoran_setup_videocodec (struct zoran *zr,
 
        m = kmalloc(sizeof(struct videocodec_master), GFP_KERNEL);
        if (!m) {
-               dprintk(1,
-                       KERN_ERR
-                       "%s: zoran_setup_videocodec() - no memory\n",
-                       ZR_DEVNAME(zr));
+               dprintk(1, KERN_ERR "%s: %s - no memory\n",
+                       ZR_DEVNAME(zr), __func__);
                return m;
        }
 
@@ -1256,6 +1196,18 @@ zoran_setup_videocodec (struct zoran *zr,
        return m;
 }
 
+static void zoran_subdev_notify(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+       struct zoran *zr = to_zoran(sd->v4l2_dev);
+
+       /* Bt819 needs to reset its FIFO buffer using #FRST pin and
+          LML33 card uses GPIO(7) for that. */
+       if (cmd == BT819_FIFO_RESET_LOW)
+               GPIO(zr, 7, 0);
+       else if (cmd == BT819_FIFO_RESET_HIGH)
+               GPIO(zr, 7, 1);
+}
+
 /*
  *   Scan for a Buz card (actually for the PCI controller ZR36057),
  *   request the irq and map the io memory
@@ -1269,34 +1221,33 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
        struct videocodec_master *master_vfe = NULL;
        struct videocodec_master *master_codec = NULL;
        int card_num;
-       char *i2c_enc_name, *i2c_dec_name, *codec_name, *vfe_name;
+       char *codec_name, *vfe_name;
        unsigned int nr;
 
 
        nr = zoran_num++;
        if (nr >= BUZ_MAX) {
-               dprintk(1,
-                       KERN_ERR
-                       "%s: driver limited to %d card(s) maximum\n",
+               dprintk(1, KERN_ERR "%s: driver limited to %d card(s) maximum\n",
                        ZORAN_NAME, BUZ_MAX);
                return -ENOENT;
        }
 
        zr = kzalloc(sizeof(struct zoran), GFP_KERNEL);
        if (!zr) {
-               dprintk(1,
-                       KERN_ERR
-                       "%s: find_zr36057() - kzalloc failed\n",
-                       ZORAN_NAME);
+               dprintk(1, KERN_ERR "%s: %s - kzalloc failed\n",
+                       ZORAN_NAME, __func__);
                return -ENOMEM;
        }
+       zr->v4l2_dev.notify = zoran_subdev_notify;
+       if (v4l2_device_register(&pdev->dev, &zr->v4l2_dev))
+               goto zr_free_mem;
        zr->pci_dev = pdev;
        zr->id = nr;
        snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id);
        spin_lock_init(&zr->spinlock);
        mutex_init(&zr->resource_lock);
        if (pci_enable_device(pdev))
-               goto zr_free_mem;
+               goto zr_unreg;
        pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision);
 
        dprintk(1,
@@ -1323,7 +1274,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
                                KERN_ERR
                                "%s: It is not possible to auto-detect ZR36057 based cards\n",
                                ZR_DEVNAME(zr));
-                       goto zr_free_mem;
+                       goto zr_unreg;
                }
 
                card_num = ent->driver_data;
@@ -1332,7 +1283,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
                                KERN_ERR
                                "%s: Unknown card, try specifying card=X module parameter\n",
                                ZR_DEVNAME(zr));
-                       goto zr_free_mem;
+                       goto zr_unreg;
                }
                dprintk(3,
                        KERN_DEBUG
@@ -1345,7 +1296,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
                                KERN_ERR
                                "%s: User specified card type %d out of range (0 .. %d)\n",
                                ZR_DEVNAME(zr), card_num, NUM_CARDS - 1);
-                       goto zr_free_mem;
+                       goto zr_unreg;
                }
        }
 
@@ -1360,11 +1311,9 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
 
        zr->zr36057_mem = pci_ioremap_bar(zr->pci_dev, 0);
        if (!zr->zr36057_mem) {
-               dprintk(1,
-                       KERN_ERR
-                       "%s: %s() - ioremap failed\n",
+               dprintk(1, KERN_ERR "%s: %s() - ioremap failed\n",
                        ZR_DEVNAME(zr), __func__);
-               goto zr_free_mem;
+               goto zr_unreg;
        }
 
        result = request_irq(zr->pci_dev->irq, zoran_irq,
@@ -1373,18 +1322,18 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
                if (result == -EINVAL) {
                        dprintk(1,
                                KERN_ERR
-                               "%s: find_zr36057() - bad irq number or handler\n",
-                               ZR_DEVNAME(zr));
+                               "%s: %s - bad irq number or handler\n",
+                               ZR_DEVNAME(zr), __func__);
                } else if (result == -EBUSY) {
                        dprintk(1,
                                KERN_ERR
-                               "%s: find_zr36057() - IRQ %d busy, change your PnP config in BIOS\n",
-                               ZR_DEVNAME(zr), zr->pci_dev->irq);
+                               "%s: %s - IRQ %d busy, change your PnP config in BIOS\n",
+                               ZR_DEVNAME(zr), __func__, zr->pci_dev->irq);
                } else {
                        dprintk(1,
                                KERN_ERR
-                               "%s: find_zr36057() - can't assign irq, error code %d\n",
-                               ZR_DEVNAME(zr), result);
+                               "%s: %s - can't assign irq, error code %d\n",
+                               ZR_DEVNAME(zr), __func__, result);
                }
                goto zr_unmap;
        }
@@ -1394,9 +1343,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
                             &latency);
        need_latency = zr->revision > 1 ? 32 : 48;
        if (latency != need_latency) {
-               dprintk(2,
-                       KERN_INFO
-                       "%s: Changing PCI latency from %d to %d\n",
+               dprintk(2, KERN_INFO "%s: Changing PCI latency from %d to %d\n",
                        ZR_DEVNAME(zr), latency, need_latency);
                pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER,
                                      need_latency);
@@ -1407,54 +1354,20 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
        dprintk(2, KERN_INFO "%s: Initializing i2c bus...\n",
                ZR_DEVNAME(zr));
 
-       /* i2c decoder */
-       if (decoder[zr->id] != -1) {
-               i2c_dec_name = i2cid_to_modulename(decoder[zr->id]);
-               zr->card.i2c_decoder = decoder[zr->id];
-       } else if (zr->card.i2c_decoder != 0) {
-               i2c_dec_name = i2cid_to_modulename(zr->card.i2c_decoder);
-       } else {
-               i2c_dec_name = NULL;
-       }
-
-       if (i2c_dec_name) {
-               result = request_module(i2c_dec_name);
-               if (result < 0) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: failed to load module %s: %d\n",
-                               ZR_DEVNAME(zr), i2c_dec_name, result);
-               }
-       }
-
-       /* i2c encoder */
-       if (encoder[zr->id] != -1) {
-               i2c_enc_name = i2cid_to_modulename(encoder[zr->id]);
-               zr->card.i2c_encoder = encoder[zr->id];
-       } else if (zr->card.i2c_encoder != 0) {
-               i2c_enc_name = i2cid_to_modulename(zr->card.i2c_encoder);
-       } else {
-               i2c_enc_name = NULL;
-       }
-
-       if (i2c_enc_name) {
-               result = request_module(i2c_enc_name);
-               if (result < 0) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: failed to load module %s: %d\n",
-                               ZR_DEVNAME(zr), i2c_enc_name, result);
-               }
-       }
-
        if (zoran_register_i2c(zr) < 0) {
-               dprintk(1,
-                       KERN_ERR
-                       "%s: find_zr36057() - can't initialize i2c bus\n",
-                       ZR_DEVNAME(zr));
+               dprintk(1, KERN_ERR "%s: %s - can't initialize i2c bus\n",
+                       ZR_DEVNAME(zr), __func__);
                goto zr_free_irq;
        }
 
+       zr->decoder = v4l2_i2c_new_probed_subdev(&zr->i2c_adapter,
+               zr->card.mod_decoder, zr->card.i2c_decoder, zr->card.addrs_decoder);
+
+       if (zr->card.mod_encoder)
+               zr->encoder = v4l2_i2c_new_probed_subdev(&zr->i2c_adapter,
+                       zr->card.mod_encoder, zr->card.i2c_encoder,
+                       zr->card.addrs_encoder);
+
        dprintk(2,
                KERN_INFO "%s: Initializing videocodec bus...\n",
                ZR_DEVNAME(zr));
@@ -1495,17 +1408,13 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
                        goto zr_unreg_i2c;
                zr->codec = videocodec_attach(master_codec);
                if (!zr->codec) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: find_zr36057() - no codec found\n",
-                               ZR_DEVNAME(zr));
+                       dprintk(1, KERN_ERR "%s: %s - no codec found\n",
+                               ZR_DEVNAME(zr), __func__);
                        goto zr_free_codec;
                }
                if (zr->codec->type != zr->card.video_codec) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: find_zr36057() - wrong codec\n",
-                               ZR_DEVNAME(zr));
+                       dprintk(1, KERN_ERR "%s: %s - wrong codec\n",
+                               ZR_DEVNAME(zr), __func__);
                        goto zr_detach_codec;
                }
        }
@@ -1515,17 +1424,13 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
                        goto zr_detach_codec;
                zr->vfe = videocodec_attach(master_vfe);
                if (!zr->vfe) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: find_zr36057() - no VFE found\n",
-                               ZR_DEVNAME(zr));
+                       dprintk(1, KERN_ERR "%s: %s - no VFE found\n",
+                               ZR_DEVNAME(zr), __func__);
                        goto zr_free_vfe;
                }
                if (zr->vfe->type != zr->card.video_vfe) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: find_zr36057() = wrong VFE\n",
-                               ZR_DEVNAME(zr));
+                       dprintk(1, KERN_ERR "%s: %s = wrong VFE\n",
+                               ZR_DEVNAME(zr), __func__);
                        goto zr_detach_vfe;
                }
        }
@@ -1533,8 +1438,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
        /* take care of Natoma chipset and a revision 1 zr36057 */
        if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) {
                zr->jpg_buffers.need_contiguous = 1;
-               dprintk(1,
-                       KERN_INFO
+               dprintk(1, KERN_INFO
                        "%s: ZR36057/Natoma bug, max. buffer size is 128K\n",
                        ZR_DEVNAME(zr));
        }
@@ -1544,8 +1448,6 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
 
        zoran_proc_init(zr);
 
-       pci_set_drvdata(pdev, zr);
-
        return 0;
 
 zr_detach_vfe:
@@ -1563,6 +1465,8 @@ zr_free_irq:
        free_irq(zr->pci_dev->irq, zr);
 zr_unmap:
        iounmap(zr->zr36057_mem);
+zr_unreg:
+       v4l2_device_unregister(&zr->v4l2_dev);
 zr_free_mem:
        kfree(zr);
 
@@ -1613,9 +1517,6 @@ static int __init zoran_init(void)
                        ZORAN_NAME, vidmem);
        }
 
-       /* random nonsense */
-       dprintk(6, KERN_DEBUG "Jotti is een held!\n");
-
        /* some mainboards might not do PCI-PCI data transfer well */
        if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL|PCIPCI_ALIMAGIK)) {
                dprintk(1,
index 4507bdc5e3385d27be3ef23652390c66c28b8056..4936fead73e8693cfab4a2ad7ebb9111be92a1e7 100644 (file)
@@ -44,7 +44,8 @@ extern int zr36067_debug;
 extern struct video_device zoran_template;
 
 extern int zoran_check_jpg_settings(struct zoran *zr,
-                                   struct zoran_jpg_settings *settings);
+                                   struct zoran_jpg_settings *settings,
+                                   int try);
 extern void zoran_open_init_params(struct zoran *zr);
 extern void zoran_vdev_release(struct video_device *vdev);
 
index 5d948ff7faf0199909973ccfc4005259c0290105..e0223deed35edfc268917b5c22976ad25be1d1cb 100644 (file)
 #include <linux/proc_fs.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
 #include <linux/spinlock.h>
 #include <linux/sem.h>
 
 #include <linux/pci.h>
-#include <linux/video_decoder.h>
-#include <linux/video_encoder.h>
 #include <linux/delay.h>
 #include <linux/wait.h>
 
@@ -312,9 +311,9 @@ zr36057_adjust_vfe (struct zoran          *zr,
        case BUZ_MODE_MOTION_COMPRESS:
        case BUZ_MODE_IDLE:
        default:
-               if (zr->norm == VIDEO_MODE_NTSC ||
+               if ((zr->norm & V4L2_STD_NTSC) ||
                    (zr->card.type == LML33R10 &&
-                    zr->norm == VIDEO_MODE_PAL))
+                    (zr->norm & V4L2_STD_PAL)))
                        btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
                else
                        btor(ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
@@ -355,14 +354,6 @@ zr36057_set_vfe (struct zoran              *zr,
        dprintk(2, KERN_INFO "%s: set_vfe() - width = %d, height = %d\n",
                ZR_DEVNAME(zr), video_width, video_height);
 
-       if (zr->norm != VIDEO_MODE_PAL &&
-           zr->norm != VIDEO_MODE_NTSC &&
-           zr->norm != VIDEO_MODE_SECAM) {
-               dprintk(1,
-                       KERN_ERR "%s: set_vfe() - norm = %d not valid\n",
-                       ZR_DEVNAME(zr), zr->norm);
-               return;
-       }
        if (video_width < BUZ_MIN_WIDTH ||
            video_height < BUZ_MIN_HEIGHT ||
            video_width > Wa || video_height > Ha) {
@@ -426,7 +417,7 @@ zr36057_set_vfe (struct zoran              *zr,
         * we get the correct colors when uncompressing to the screen  */
        //reg |= ZR36057_VFESPFR_VCLKPol; /**/
        /* RJ: Don't know if that is needed for NTSC also */
-       if (zr->norm != VIDEO_MODE_NTSC)
+       if (!(zr->norm & V4L2_STD_NTSC))
                reg |= ZR36057_VFESPFR_ExtFl;   // NEEDED!!!!!!! Wolfgang
        reg |= ZR36057_VFESPFR_TopField;
        if (HorDcm >= 48) {
@@ -497,11 +488,11 @@ zr36057_overlay (struct zoran *zr,
                 * All error messages are internal driver checking only! */
 
                /* video display top and bottom registers */
-               reg = (long) zr->buffer.base +
+               reg = (long) zr->vbuf_base +
                    zr->overlay_settings.x *
                    ((zr->overlay_settings.format->depth + 7) / 8) +
                    zr->overlay_settings.y *
-                   zr->buffer.bytesperline;
+                   zr->vbuf_bytesperline;
                btwrite(reg, ZR36057_VDTR);
                if (reg & 3)
                        dprintk(1,
@@ -509,15 +500,15 @@ zr36057_overlay (struct zoran *zr,
                                "%s: zr36057_overlay() - video_address not aligned\n",
                                ZR_DEVNAME(zr));
                if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2)
-                       reg += zr->buffer.bytesperline;
+                       reg += zr->vbuf_bytesperline;
                btwrite(reg, ZR36057_VDBR);
 
                /* video stride, status, and frame grab register */
-               reg = zr->buffer.bytesperline -
+               reg = zr->vbuf_bytesperline -
                    zr->overlay_settings.width *
                    ((zr->overlay_settings.format->depth + 7) / 8);
                if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2)
-                       reg += zr->buffer.bytesperline;
+                       reg += zr->vbuf_bytesperline;
                if (reg & 3)
                        dprintk(1,
                                KERN_ERR
@@ -544,12 +535,8 @@ zr36057_overlay (struct zoran *zr,
  *  and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels.
  */
 
-void
-write_overlay_mask (struct file       *file,
-                   struct video_clip *vp,
-                   int                count)
+void write_overlay_mask(struct zoran_fh *fh, struct v4l2_clip *vp, int count)
 {
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
        unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
        u32 *mask;
@@ -563,10 +550,10 @@ write_overlay_mask (struct file       *file,
 
        for (i = 0; i < count; ++i) {
                /* pick up local copy of clip */
-               x = vp[i].x;
-               y = vp[i].y;
-               width = vp[i].width;
-               height = vp[i].height;
+               x = vp[i].c.left;
+               y = vp[i].c.top;
+               width = vp[i].c.width;
+               height = vp[i].c.height;
 
                /* trim clips that extend beyond the window */
                if (x < 0) {
@@ -981,11 +968,10 @@ void
 zr36057_enable_jpg (struct zoran          *zr,
                    enum zoran_codec_mode  mode)
 {
-       static int zero;
-       static int one = 1;
        struct vfe_settings cap;
        int field_size =
            zr->jpg_buffers.buffer_size / zr->jpg_settings.field_per_buff;
+       struct v4l2_routing route = { 0, 0 };
 
        zr->codec_mode = mode;
 
@@ -1007,8 +993,9 @@ zr36057_enable_jpg (struct zoran          *zr,
                 * the video bus direction set to input.
                 */
                set_videobus_dir(zr, 0);
-               decoder_command(zr, DECODER_ENABLE_OUTPUT, &one);
-               encoder_command(zr, ENCODER_SET_INPUT, &zero);
+               decoder_call(zr, video, s_stream, 1);
+               route.input = 0;
+               encoder_call(zr, video, s_routing, &route);
 
                /* Take the JPEG codec and the VFE out of sleep */
                jpeg_codec_sleep(zr, 0);
@@ -1054,9 +1041,10 @@ zr36057_enable_jpg (struct zoran          *zr,
                /* In motion decompression mode, the decoder output must be disabled, and
                 * the video bus direction set to output.
                 */
-               decoder_command(zr, DECODER_ENABLE_OUTPUT, &zero);
+               decoder_call(zr, video, s_stream, 0);
                set_videobus_dir(zr, 1);
-               encoder_command(zr, ENCODER_SET_INPUT, &one);
+               route.input = 1;
+               encoder_call(zr, video, s_routing, &route);
 
                /* Take the JPEG codec and the VFE out of sleep */
                jpeg_codec_sleep(zr, 0);
@@ -1100,8 +1088,9 @@ zr36057_enable_jpg (struct zoran          *zr,
                jpeg_codec_sleep(zr, 1);
                zr36057_adjust_vfe(zr, mode);
 
-               decoder_command(zr, DECODER_ENABLE_OUTPUT, &one);
-               encoder_command(zr, ENCODER_SET_INPUT, &zero);
+               decoder_call(zr, video, s_stream, 1);
+               route.input = 0;
+               encoder_call(zr, video, s_routing, &route);
 
                dprintk(2, KERN_INFO "%s: enable_jpg(IDLE)\n", ZR_DEVNAME(zr));
                break;
@@ -1132,7 +1121,7 @@ zoran_feed_stat_com (struct zoran *zr)
                        if (!(zr->stat_com[i] & cpu_to_le32(1)))
                                break;
                        zr->stat_com[i] =
-                           cpu_to_le32(zr->jpg_buffers.buffer[frame].frag_tab_bus);
+                           cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus);
                } else {
                        /* fill 2 stat_com entries */
                        i = ((zr->jpg_dma_head -
@@ -1140,9 +1129,9 @@ zoran_feed_stat_com (struct zoran *zr)
                        if (!(zr->stat_com[i] & cpu_to_le32(1)))
                                break;
                        zr->stat_com[i] =
-                           cpu_to_le32(zr->jpg_buffers.buffer[frame].frag_tab_bus);
+                           cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus);
                        zr->stat_com[i + 1] =
-                           cpu_to_le32(zr->jpg_buffers.buffer[frame].frag_tab_bus);
+                           cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus);
                }
                zr->jpg_buffers.buffer[frame].state = BUZ_STATE_DMA;
                zr->jpg_dma_head++;
@@ -1162,7 +1151,7 @@ zoran_reap_stat_com (struct zoran *zr)
        u32 stat_com;
        unsigned int seq;
        unsigned int dif;
-       struct zoran_jpg_buffer *buffer;
+       struct zoran_buffer *buffer;
        int frame;
 
        /* In motion decompress we don't have a hardware frame counter,
@@ -1208,22 +1197,52 @@ zoran_reap_stat_com (struct zoran *zr)
        }
 }
 
+static void zoran_restart(struct zoran *zr)
+{
+       /* Now the stat_comm buffer is ready for restart */
+       int status = 0, mode;
+
+       if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
+               decoder_call(zr, video, g_input_status, &status);
+               mode = CODEC_DO_COMPRESSION;
+       } else {
+               status = V4L2_IN_ST_NO_SIGNAL;
+               mode = CODEC_DO_EXPANSION;
+       }
+       if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
+           !(status & V4L2_IN_ST_NO_SIGNAL)) {
+               /********** RESTART code *************/
+               jpeg_codec_reset(zr);
+               zr->codec->set_mode(zr->codec, mode);
+               zr36057_set_jpg(zr, zr->codec_mode);
+               jpeg_start(zr);
+
+               if (zr->num_errors <= 8)
+                       dprintk(2, KERN_INFO "%s: Restart\n",
+                               ZR_DEVNAME(zr));
+
+               zr->JPEG_missed = 0;
+               zr->JPEG_error = 2;
+               /********** End RESTART code ***********/
+       }
+}
+
 static void
 error_handler (struct zoran *zr,
               u32           astat,
               u32           stat)
 {
+       int i, j;
+
        /* This is JPEG error handling part */
-       if ((zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) &&
-           (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS)) {
-               //dprintk(1, KERN_ERR "%s: Internal error: error handling request in mode %d\n", ZR_DEVNAME(zr), zr->codec_mode);
+       if (zr->codec_mode != BUZ_MODE_MOTION_COMPRESS &&
+           zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS) {
                return;
        }
 
        if ((stat & 1) == 0 &&
            zr->codec_mode == BUZ_MODE_MOTION_COMPRESS &&
-           zr->jpg_dma_tail - zr->jpg_que_tail >=
-            zr->jpg_buffers.num_buffers) {
+           zr->jpg_dma_tail - zr->jpg_que_tail >= zr->jpg_buffers.num_buffers) {
                /* No free buffers... */
                zoran_reap_stat_com(zr);
                zoran_feed_stat_com(zr);
@@ -1232,142 +1251,95 @@ error_handler (struct zoran *zr,
                return;
        }
 
-       if (zr->JPEG_error != 1) {
-               /*
-                * First entry: error just happened during normal operation
-                *
-                * In BUZ_MODE_MOTION_COMPRESS:
-                *
-                * Possible glitch in TV signal. In this case we should
-                * stop the codec and wait for good quality signal before
-                * restarting it to avoid further problems
-                *
-                * In BUZ_MODE_MOTION_DECOMPRESS:
-                *
-                * Bad JPEG frame: we have to mark it as processed (codec crashed
-                * and was not able to do it itself), and to remove it from queue.
-                */
-               btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
-               udelay(1);
-               stat = stat | (post_office_read(zr, 7, 0) & 3) << 8;
-               btwrite(0, ZR36057_JPC);
-               btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
-               jpeg_codec_reset(zr);
-               jpeg_codec_sleep(zr, 1);
-               zr->JPEG_error = 1;
-               zr->num_errors++;
-
-               /* Report error */
-               if (zr36067_debug > 1 && zr->num_errors <= 8) {
-                       long frame;
-                       frame =
-                           zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
-                       printk(KERN_ERR
-                              "%s: JPEG error stat=0x%08x(0x%08x) queue_state=%ld/%ld/%ld/%ld seq=%ld frame=%ld. Codec stopped. ",
-                              ZR_DEVNAME(zr), stat, zr->last_isr,
-                              zr->jpg_que_tail, zr->jpg_dma_tail,
-                              zr->jpg_dma_head, zr->jpg_que_head,
-                              zr->jpg_seq_num, frame);
-                       printk("stat_com frames:");
-                       {
-                               int i, j;
-                               for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
-                                       for (i = 0;
-                                            i < zr->jpg_buffers.num_buffers;
-                                            i++) {
-                                               if (le32_to_cpu(zr->stat_com[j]) ==
-                                                   zr->jpg_buffers.
-                                                   buffer[i].
-                                                   frag_tab_bus) {
-                                                       printk("% d->%d",
-                                                              j, i);
-                                               }
-                                       }
-                               }
-                               printk("\n");
-                       }
-               }
-               /* Find an entry in stat_com and rotate contents */
-               {
-                       int i;
-
-                       if (zr->jpg_settings.TmpDcm == 1)
-                               i = (zr->jpg_dma_tail -
-                                    zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
-                       else
-                               i = ((zr->jpg_dma_tail -
-                                     zr->jpg_err_shift) & 1) * 2;
-                       if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) {
-                               /* Mimic zr36067 operation */
-                               zr->stat_com[i] |= cpu_to_le32(1);
-                               if (zr->jpg_settings.TmpDcm != 1)
-                                       zr->stat_com[i + 1] |= cpu_to_le32(1);
-                               /* Refill */
-                               zoran_reap_stat_com(zr);
-                               zoran_feed_stat_com(zr);
-                               wake_up_interruptible(&zr->jpg_capq);
-                               /* Find an entry in stat_com again after refill */
-                               if (zr->jpg_settings.TmpDcm == 1)
-                                       i = (zr->jpg_dma_tail -
-                                            zr->jpg_err_shift) &
-                                           BUZ_MASK_STAT_COM;
-                               else
-                                       i = ((zr->jpg_dma_tail -
-                                             zr->jpg_err_shift) & 1) * 2;
-                       }
-                       if (i) {
-                               /* Rotate stat_comm entries to make current entry first */
-                               int j;
-                               __le32 bus_addr[BUZ_NUM_STAT_COM];
-
-                               /* Here we are copying the stat_com array, which
-                                * is already in little endian format, so
-                                * no endian conversions here
-                                */
-                               memcpy(bus_addr, zr->stat_com,
-                                      sizeof(bus_addr));
-                               for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
-                                       zr->stat_com[j] =
-                                           bus_addr[(i + j) &
-                                                    BUZ_MASK_STAT_COM];
+       if (zr->JPEG_error == 1) {
+               zoran_restart(zr);
+               return;
+       }
 
-                               }
-                               zr->jpg_err_shift += i;
-                               zr->jpg_err_shift &= BUZ_MASK_STAT_COM;
+       /*
+        * First entry: error just happened during normal operation
+        *
+        * In BUZ_MODE_MOTION_COMPRESS:
+        *
+        * Possible glitch in TV signal. In this case we should
+        * stop the codec and wait for good quality signal before
+        * restarting it to avoid further problems
+        *
+        * In BUZ_MODE_MOTION_DECOMPRESS:
+        *
+        * Bad JPEG frame: we have to mark it as processed (codec crashed
+        * and was not able to do it itself), and to remove it from queue.
+        */
+       btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
+       udelay(1);
+       stat = stat | (post_office_read(zr, 7, 0) & 3) << 8;
+       btwrite(0, ZR36057_JPC);
+       btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
+       jpeg_codec_reset(zr);
+       jpeg_codec_sleep(zr, 1);
+       zr->JPEG_error = 1;
+       zr->num_errors++;
+
+       /* Report error */
+       if (zr36067_debug > 1 && zr->num_errors <= 8) {
+               long frame;
+
+               frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
+               printk(KERN_ERR
+                      "%s: JPEG error stat=0x%08x(0x%08x) queue_state=%ld/%ld/%ld/%ld seq=%ld frame=%ld. Codec stopped. ",
+                      ZR_DEVNAME(zr), stat, zr->last_isr,
+                      zr->jpg_que_tail, zr->jpg_dma_tail,
+                      zr->jpg_dma_head, zr->jpg_que_head,
+                      zr->jpg_seq_num, frame);
+               printk(KERN_INFO "stat_com frames:");
+               for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
+                       for (i = 0; i < zr->jpg_buffers.num_buffers; i++) {
+                               if (le32_to_cpu(zr->stat_com[j]) == zr->jpg_buffers.buffer[i].jpg.frag_tab_bus)
+                                       printk(KERN_CONT "% d->%d", j, i);
                        }
-                       if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)
-                               zr->jpg_err_seq = zr->jpg_seq_num;      /* + 1; */
                }
+               printk(KERN_CONT "\n");
        }
+       /* Find an entry in stat_com and rotate contents */
+       if (zr->jpg_settings.TmpDcm == 1)
+               i = (zr->jpg_dma_tail - zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
+       else
+               i = ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2;
+       if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) {
+               /* Mimic zr36067 operation */
+               zr->stat_com[i] |= cpu_to_le32(1);
+               if (zr->jpg_settings.TmpDcm != 1)
+                       zr->stat_com[i + 1] |= cpu_to_le32(1);
+               /* Refill */
+               zoran_reap_stat_com(zr);
+               zoran_feed_stat_com(zr);
+               wake_up_interruptible(&zr->jpg_capq);
+               /* Find an entry in stat_com again after refill */
+               if (zr->jpg_settings.TmpDcm == 1)
+                       i = (zr->jpg_dma_tail - zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
+               else
+                       i = ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2;
+       }
+       if (i) {
+               /* Rotate stat_comm entries to make current entry first */
+               int j;
+               __le32 bus_addr[BUZ_NUM_STAT_COM];
+
+               /* Here we are copying the stat_com array, which
+                * is already in little endian format, so
+                * no endian conversions here
+                */
+               memcpy(bus_addr, zr->stat_com, sizeof(bus_addr));
 
-       /* Now the stat_comm buffer is ready for restart */
-       do {
-               int status, mode;
-
-               if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
-                       decoder_command(zr, DECODER_GET_STATUS, &status);
-                       mode = CODEC_DO_COMPRESSION;
-               } else {
-                       status = 0;
-                       mode = CODEC_DO_EXPANSION;
-               }
-               if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
-                   (status & DECODER_STATUS_GOOD)) {
-                       /********** RESTART code *************/
-                       jpeg_codec_reset(zr);
-                       zr->codec->set_mode(zr->codec, mode);
-                       zr36057_set_jpg(zr, zr->codec_mode);
-                       jpeg_start(zr);
-
-                       if (zr->num_errors <= 8)
-                               dprintk(2, KERN_INFO "%s: Restart\n",
-                                       ZR_DEVNAME(zr));
+               for (j = 0; j < BUZ_NUM_STAT_COM; j++)
+                       zr->stat_com[j] = bus_addr[(i + j) & BUZ_MASK_STAT_COM];
 
-                       zr->JPEG_missed = 0;
-                       zr->JPEG_error = 2;
-                       /********** End RESTART code ***********/
-               }
-       } while (0);
+               zr->jpg_err_shift += i;
+               zr->jpg_err_shift &= BUZ_MASK_STAT_COM;
+       }
+       if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)
+               zr->jpg_err_seq = zr->jpg_seq_num;      /* + 1; */
+       zoran_restart(zr);
 }
 
 irqreturn_t
@@ -1425,10 +1397,8 @@ zoran_irq (int             irq,
                         * We simply ignore them */
 
                        if (zr->v4l_memgrab_active) {
-
                                /* A lot more checks should be here ... */
-                               if ((btread(ZR36057_VSSFGR) &
-                                    ZR36057_VSSFGR_SnapShot) == 0)
+                               if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot) == 0)
                                        dprintk(1,
                                                KERN_WARNING
                                                "%s: BuzIRQ with SnapShot off ???\n",
@@ -1436,10 +1406,7 @@ zoran_irq (int             irq,
 
                                if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) {
                                        /* There is a grab on a frame going on, check if it has finished */
-
-                                       if ((btread(ZR36057_VSSFGR) &
-                                            ZR36057_VSSFGR_FrameGrab) ==
-                                           0) {
+                                       if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_FrameGrab) == 0) {
                                                /* it is finished, notify the user */
 
                                                zr->v4l_buffers.buffer[zr->v4l_grab_frame].state = BUZ_STATE_DONE;
@@ -1457,9 +1424,7 @@ zoran_irq (int             irq,
 
                                if (zr->v4l_grab_frame == NO_GRAB_ACTIVE &&
                                    zr->v4l_pend_tail != zr->v4l_pend_head) {
-
-                                       int frame = zr->v4l_pend[zr->v4l_pend_tail &
-                                                        V4L_MASK_FRAME];
+                                       int frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME];
                                        u32 reg;
 
                                        zr->v4l_grab_frame = frame;
@@ -1468,27 +1433,17 @@ zoran_irq (int             irq,
 
                                        /* Buffer address */
 
-                                       reg =
-                                           zr->v4l_buffers.buffer[frame].
-                                           fbuffer_bus;
+                                       reg = zr->v4l_buffers.buffer[frame].v4l.fbuffer_bus;
                                        btwrite(reg, ZR36057_VDTR);
-                                       if (zr->v4l_settings.height >
-                                           BUZ_MAX_HEIGHT / 2)
-                                               reg +=
-                                                   zr->v4l_settings.
-                                                   bytesperline;
+                                       if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2)
+                                               reg += zr->v4l_settings.bytesperline;
                                        btwrite(reg, ZR36057_VDBR);
 
                                        /* video stride, status, and frame grab register */
                                        reg = 0;
-                                       if (zr->v4l_settings.height >
-                                           BUZ_MAX_HEIGHT / 2)
-                                               reg +=
-                                                   zr->v4l_settings.
-                                                   bytesperline;
-                                       reg =
-                                           (reg <<
-                                            ZR36057_VSSFGR_DispStride);
+                                       if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2)
+                                               reg += zr->v4l_settings.bytesperline;
+                                       reg = (reg << ZR36057_VSSFGR_DispStride);
                                        reg |= ZR36057_VSSFGR_VidOvf;
                                        reg |= ZR36057_VSSFGR_SnapShot;
                                        reg |= ZR36057_VSSFGR_FrameGrab;
@@ -1506,77 +1461,66 @@ zoran_irq (int             irq,
 #if (IRQ_MASK & ZR36057_ISR_CodRepIRQ)
                if (astat & ZR36057_ISR_CodRepIRQ) {
                        zr->intr_counter_CodRepIRQ++;
-                       IDEBUG(printk
-                              (KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n",
+                       IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n",
                                ZR_DEVNAME(zr)));
                        btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR);
                }
 #endif                         /* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */
 
 #if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ)
-               if (astat & ZR36057_ISR_JPEGRepIRQ) {
-
-                       if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
-                           zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
-                               if (zr36067_debug > 1 &&
-                                   (!zr->frame_num || zr->JPEG_error)) {
-                                       printk(KERN_INFO
-                                              "%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n",
-                                              ZR_DEVNAME(zr), stat,
-                                              zr->jpg_settings.odd_even,
-                                              zr->jpg_settings.
-                                              field_per_buff,
-                                              zr->JPEG_missed);
-                                       {
-                                               char sc[] = "0000";
-                                               char sv[5];
-                                               int i;
-                                               strcpy(sv, sc);
-                                               for (i = 0; i < 4; i++) {
-                                                       if (le32_to_cpu(zr->stat_com[i]) & 1)
-                                                               sv[i] = '1';
-                                               }
-                                               sv[4] = 0;
-                                               printk(KERN_INFO
-                                                      "%s: stat_com=%s queue_state=%ld/%ld/%ld/%ld\n",
-                                                      ZR_DEVNAME(zr), sv,
-                                                      zr->jpg_que_tail,
-                                                      zr->jpg_dma_tail,
-                                                      zr->jpg_dma_head,
-                                                      zr->jpg_que_head);
-                                       }
-                               } else {
-                                       if (zr->JPEG_missed > zr->JPEG_max_missed)      // Get statistics
-                                               zr->JPEG_max_missed =
-                                                   zr->JPEG_missed;
-                                       if (zr->JPEG_missed <
-                                           zr->JPEG_min_missed)
-                                               zr->JPEG_min_missed =
-                                                   zr->JPEG_missed;
+               if ((astat & ZR36057_ISR_JPEGRepIRQ) &&
+                   (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
+                    zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)) {
+                       if (zr36067_debug > 1 && (!zr->frame_num || zr->JPEG_error)) {
+                               char sc[] = "0000";
+                               char sv[5];
+                               int i;
+
+                               printk(KERN_INFO
+                                      "%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n",
+                                      ZR_DEVNAME(zr), stat,
+                                      zr->jpg_settings.odd_even,
+                                      zr->jpg_settings.field_per_buff,
+                                      zr->JPEG_missed);
+
+                               strcpy(sv, sc);
+                               for (i = 0; i < 4; i++) {
+                                       if (le32_to_cpu(zr->stat_com[i]) & 1)
+                                               sv[i] = '1';
                                }
+                               sv[4] = 0;
+                               printk(KERN_INFO
+                                      "%s: stat_com=%s queue_state=%ld/%ld/%ld/%ld\n",
+                                      ZR_DEVNAME(zr), sv,
+                                      zr->jpg_que_tail,
+                                      zr->jpg_dma_tail,
+                                      zr->jpg_dma_head,
+                                      zr->jpg_que_head);
+                       } else {
+                               /* Get statistics */
+                               if (zr->JPEG_missed > zr->JPEG_max_missed)
+                                       zr->JPEG_max_missed = zr->JPEG_missed;
+                               if (zr->JPEG_missed < zr->JPEG_min_missed)
+                                       zr->JPEG_min_missed = zr->JPEG_missed;
+                       }
 
-                               if (zr36067_debug > 2 && zr->frame_num < 6) {
-                                       int i;
-                                       printk("%s: seq=%ld stat_com:",
-                                              ZR_DEVNAME(zr), zr->jpg_seq_num);
-                                       for (i = 0; i < 4; i++) {
-                                               printk(" %08x",
-                                                      le32_to_cpu(zr->stat_com[i]));
-                                       }
-                                       printk("\n");
+                       if (zr36067_debug > 2 && zr->frame_num < 6) {
+                               int i;
+
+                               printk(KERN_INFO "%s: seq=%ld stat_com:",
+                                      ZR_DEVNAME(zr), zr->jpg_seq_num);
+                               for (i = 0; i < 4; i++) {
+                                       printk(KERN_CONT " %08x",
+                                              le32_to_cpu(zr->stat_com[i]));
                                }
-                               zr->frame_num++;
-                               zr->JPEG_missed = 0;
-                               zr->JPEG_error = 0;
-                               zoran_reap_stat_com(zr);
-                               zoran_feed_stat_com(zr);
-                               wake_up_interruptible(&zr->jpg_capq);
-                       } /*else {
-                             dprintk(1,
-                                       KERN_ERR
-                                       "%s: JPEG interrupt while not in motion (de)compress mode!\n",
-                                       ZR_DEVNAME(zr));
-                       }*/
+                               printk(KERN_CONT "\n");
+                       }
+                       zr->frame_num++;
+                       zr->JPEG_missed = 0;
+                       zr->JPEG_error = 0;
+                       zoran_reap_stat_com(zr);
+                       zoran_feed_stat_com(zr);
+                       wake_up_interruptible(&zr->jpg_capq);
                }
 #endif                         /* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */
 
@@ -1585,8 +1529,7 @@ zoran_irq (int             irq,
                    zr->JPEG_missed > 25 ||
                    zr->JPEG_error == 1 ||
                    ((zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) &&
-                    (zr->frame_num & (zr->JPEG_missed >
-                                      zr->jpg_settings.field_per_buff)))) {
+                    (zr->frame_num & (zr->JPEG_missed > zr->jpg_settings.field_per_buff)))) {
                        error_handler(zr, astat, stat);
                }
 
@@ -1628,7 +1571,7 @@ zoran_set_pci_master (struct zoran *zr,
 void
 zoran_init_hardware (struct zoran *zr)
 {
-       int j, zero = 0;
+       struct v4l2_routing route = { 0, 0 };
 
        /* Enable bus-mastering */
        zoran_set_pci_master(zr, 1);
@@ -1638,15 +1581,16 @@ zoran_init_hardware (struct zoran *zr)
                zr->card.init(zr);
        }
 
-       j = zr->card.input[zr->input].muxsel;
+       route.input = zr->card.input[zr->input].muxsel;
 
-       decoder_command(zr, 0, NULL);
-       decoder_command(zr, DECODER_SET_NORM, &zr->norm);
-       decoder_command(zr, DECODER_SET_INPUT, &j);
+       decoder_call(zr, core, init, 0);
+       decoder_call(zr, tuner, s_std, zr->norm);
+       decoder_call(zr, video, s_routing, &route);
 
-       encoder_command(zr, 0, NULL);
-       encoder_command(zr, ENCODER_SET_NORM, &zr->norm);
-       encoder_command(zr, ENCODER_SET_INPUT, &zero);
+       encoder_call(zr, core, init, 0);
+       encoder_call(zr, video, s_std_output, zr->norm);
+       route.input = 0;
+       encoder_call(zr, video, s_routing, &route);
 
        /* toggle JPEG codec sleep to sync PLL */
        jpeg_codec_sleep(zr, 1);
@@ -1706,42 +1650,3 @@ zr36057_init_vfe (struct zoran *zr)
                reg |= ZR36057_VDCR_Triton;
        btwrite(reg, ZR36057_VDCR);
 }
-
-/*
- * Interface to decoder and encoder chips using i2c bus
- */
-
-int
-decoder_command (struct zoran *zr,
-                int           cmd,
-                void         *data)
-{
-       if (zr->decoder == NULL)
-               return -EIO;
-
-       if (zr->card.type == LML33 &&
-           (cmd == DECODER_SET_NORM || cmd == DECODER_SET_INPUT)) {
-               int res;
-
-               // Bt819 needs to reset its FIFO buffer using #FRST pin and
-               // LML33 card uses GPIO(7) for that.
-               GPIO(zr, 7, 0);
-               res = zr->decoder->driver->command(zr->decoder, cmd, data);
-               // Pull #FRST high.
-               GPIO(zr, 7, 1);
-               return res;
-       } else
-               return zr->decoder->driver->command(zr->decoder, cmd,
-                                                   data);
-}
-
-int
-encoder_command (struct zoran *zr,
-                int           cmd,
-                void         *data)
-{
-       if (zr->encoder == NULL)
-               return -1;
-
-       return zr->encoder->driver->command(zr->encoder, cmd, data);
-}
index 74c6c8edb7d0243661661bce2110ba036be86a55..07f2c23ff7401a3b5e6653f0133477939c4ca2a3 100644 (file)
@@ -54,8 +54,8 @@ extern int jpeg_codec_reset(struct zoran *zr);
 /* zr360x7 access to raw capture */
 extern void zr36057_overlay(struct zoran *zr,
                            int on);
-extern void write_overlay_mask(struct file *file,
-                              struct video_clip *vp,
+extern void write_overlay_mask(struct zoran_fh *fh,
+                              struct v4l2_clip *vp,
                               int count);
 extern void zr36057_set_memgrab(struct zoran *zr,
                                int mode);
@@ -87,11 +87,9 @@ extern int jpg_bufsize;
 extern int pass_through;
 
 /* i2c */
-extern int decoder_command(struct zoran *zr,
-                          int cmd,
-                          void *data);
-extern int encoder_command(struct zoran *zr,
-                          int cmd,
-                          void *data);
+#define decoder_call(zr, o, f, args...) \
+       v4l2_subdev_call(zr->decoder, o, f, ##args)
+#define encoder_call(zr, o, f, args...) \
+       v4l2_subdev_call(zr->encoder, o, f, ##args)
 
 #endif                         /* __ZORAN_DEVICE_H__ */
index 120ef235e63d07a3d8a3a9c16ae03006bcbdc4cf..f16e57cf11e40d7f368dac81e781b27677ac0ee0 100644 (file)
 #include <linux/i2c-algo-bit.h>
 
 #include <linux/spinlock.h>
-#define     MAP_NR(x)       virt_to_page(x)
-#define     ZORAN_VID_TYPE  ( \
-                               VID_TYPE_CAPTURE | \
-                               VID_TYPE_OVERLAY | \
-                               VID_TYPE_CLIPPING | \
-                               VID_TYPE_FRAMERAM | \
-                               VID_TYPE_SCALES | \
-                               VID_TYPE_MJPEG_DECODER | \
-                               VID_TYPE_MJPEG_ENCODER \
-                            )
 
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <asm/uaccess.h>
 #include <linux/proc_fs.h>
 
-#include <linux/video_decoder.h>
-#include <linux/video_encoder.h>
 #include <linux/mutex.h>
 #include "zoran.h"
 #include "zoran_device.h"
 #include "zoran_card.h"
 
-       /* we declare some card type definitions here, they mean
-        * the same as the v4l1 ZORAN_VID_TYPE above, except it's v4l2 */
-#define ZORAN_V4L2_VID_FLAGS ( \
-                               V4L2_CAP_STREAMING |\
-                               V4L2_CAP_VIDEO_CAPTURE |\
-                               V4L2_CAP_VIDEO_OUTPUT |\
-                               V4L2_CAP_VIDEO_OVERLAY \
-                             )
-
-
-#if defined(CONFIG_VIDEO_V4L1_COMPAT)
-#define ZFMT(pal, fcc, cs) \
-       .palette = (pal), .fourcc = (fcc), .colorspace = (cs)
-#else
-#define ZFMT(pal, fcc, cs) \
-       .fourcc = (fcc), .colorspace = (cs)
-#endif
 
 const struct zoran_format zoran_formats[] = {
        {
                .name = "15-bit RGB LE",
-               ZFMT(VIDEO_PALETTE_RGB555,
-                    V4L2_PIX_FMT_RGB555, V4L2_COLORSPACE_SRGB),
+               .fourcc = V4L2_PIX_FMT_RGB555,
+               .colorspace = V4L2_COLORSPACE_SRGB,
                .depth = 15,
                .flags = ZORAN_FORMAT_CAPTURE |
                         ZORAN_FORMAT_OVERLAY,
@@ -116,16 +87,16 @@ const struct zoran_format zoran_formats[] = {
                           ZR36057_VFESPFR_LittleEndian,
        }, {
                .name = "15-bit RGB BE",
-               ZFMT(-1,
-                    V4L2_PIX_FMT_RGB555X, V4L2_COLORSPACE_SRGB),
+               .fourcc = V4L2_PIX_FMT_RGB555X,
+               .colorspace = V4L2_COLORSPACE_SRGB,
                .depth = 15,
                .flags = ZORAN_FORMAT_CAPTURE |
                         ZORAN_FORMAT_OVERLAY,
                .vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif,
        }, {
                .name = "16-bit RGB LE",
-               ZFMT(VIDEO_PALETTE_RGB565,
-                    V4L2_PIX_FMT_RGB565, V4L2_COLORSPACE_SRGB),
+               .fourcc = V4L2_PIX_FMT_RGB565,
+               .colorspace = V4L2_COLORSPACE_SRGB,
                .depth = 16,
                .flags = ZORAN_FORMAT_CAPTURE |
                         ZORAN_FORMAT_OVERLAY,
@@ -133,56 +104,56 @@ const struct zoran_format zoran_formats[] = {
                           ZR36057_VFESPFR_LittleEndian,
        }, {
                .name = "16-bit RGB BE",
-               ZFMT(-1,
-                    V4L2_PIX_FMT_RGB565X, V4L2_COLORSPACE_SRGB),
+               .fourcc = V4L2_PIX_FMT_RGB565X,
+               .colorspace = V4L2_COLORSPACE_SRGB,
                .depth = 16,
                .flags = ZORAN_FORMAT_CAPTURE |
                         ZORAN_FORMAT_OVERLAY,
                .vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif,
        }, {
                .name = "24-bit RGB",
-               ZFMT(VIDEO_PALETTE_RGB24,
-                    V4L2_PIX_FMT_BGR24, V4L2_COLORSPACE_SRGB),
+               .fourcc = V4L2_PIX_FMT_BGR24,
+               .colorspace = V4L2_COLORSPACE_SRGB,
                .depth = 24,
                .flags = ZORAN_FORMAT_CAPTURE |
                         ZORAN_FORMAT_OVERLAY,
                .vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_Pack24,
        }, {
                .name = "32-bit RGB LE",
-               ZFMT(VIDEO_PALETTE_RGB32,
-                    V4L2_PIX_FMT_BGR32, V4L2_COLORSPACE_SRGB),
+               .fourcc = V4L2_PIX_FMT_BGR32,
+               .colorspace = V4L2_COLORSPACE_SRGB,
                .depth = 32,
                .flags = ZORAN_FORMAT_CAPTURE |
                         ZORAN_FORMAT_OVERLAY,
                .vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_LittleEndian,
        }, {
                .name = "32-bit RGB BE",
-               ZFMT(-1,
-                    V4L2_PIX_FMT_RGB32, V4L2_COLORSPACE_SRGB),
+               .fourcc = V4L2_PIX_FMT_RGB32,
+               .colorspace = V4L2_COLORSPACE_SRGB,
                .depth = 32,
                .flags = ZORAN_FORMAT_CAPTURE |
                         ZORAN_FORMAT_OVERLAY,
                .vfespfr = ZR36057_VFESPFR_RGB888,
        }, {
                .name = "4:2:2, packed, YUYV",
-               ZFMT(VIDEO_PALETTE_YUV422,
-                    V4L2_PIX_FMT_YUYV, V4L2_COLORSPACE_SMPTE170M),
+               .fourcc = V4L2_PIX_FMT_YUYV,
+               .colorspace = V4L2_COLORSPACE_SMPTE170M,
                .depth = 16,
                .flags = ZORAN_FORMAT_CAPTURE |
                         ZORAN_FORMAT_OVERLAY,
                .vfespfr = ZR36057_VFESPFR_YUV422,
        }, {
                .name = "4:2:2, packed, UYVY",
-               ZFMT(VIDEO_PALETTE_UYVY,
-                    V4L2_PIX_FMT_UYVY, V4L2_COLORSPACE_SMPTE170M),
+               .fourcc = V4L2_PIX_FMT_UYVY,
+               .colorspace = V4L2_COLORSPACE_SMPTE170M,
                .depth = 16,
                .flags = ZORAN_FORMAT_CAPTURE |
                         ZORAN_FORMAT_OVERLAY,
                .vfespfr = ZR36057_VFESPFR_YUV422|ZR36057_VFESPFR_LittleEndian,
        }, {
                .name = "Hardware-encoded Motion-JPEG",
-               ZFMT(-1,
-                    V4L2_PIX_FMT_MJPEG, V4L2_COLORSPACE_SMPTE170M),
+               .fourcc = V4L2_PIX_FMT_MJPEG,
+               .colorspace = V4L2_COLORSPACE_SMPTE170M,
                .depth = 0,
                .flags = ZORAN_FORMAT_CAPTURE |
                         ZORAN_FORMAT_PLAYBACK |
@@ -191,13 +162,6 @@ const struct zoran_format zoran_formats[] = {
 };
 #define NUM_FORMATS ARRAY_SIZE(zoran_formats)
 
-// RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined
-
-
-static int lock_norm;  /* 0 = default 1 = Don't change TV standard (norm) */
-module_param(lock_norm, int, 0644);
-MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)");
-
        /* small helper function for calculating buffersizes for v4l2
         * we calculate the nearest higher power-of-two, which
         * will be the recommended buffersize */
@@ -222,221 +186,106 @@ zoran_v4l2_calc_bufsize (struct zoran_jpg_settings *settings)
 }
 
 /* forward references */
-static void v4l_fbuffer_free(struct file *file);
-static void jpg_fbuffer_free(struct file *file);
+static void v4l_fbuffer_free(struct zoran_fh *fh);
+static void jpg_fbuffer_free(struct zoran_fh *fh);
+
+/* Set mapping mode */
+static void map_mode_raw(struct zoran_fh *fh)
+{
+       fh->map_mode = ZORAN_MAP_MODE_RAW;
+       fh->buffers.buffer_size = v4l_bufsize;
+       fh->buffers.num_buffers = v4l_nbufs;
+}
+static void map_mode_jpg(struct zoran_fh *fh, int play)
+{
+       fh->map_mode = play ? ZORAN_MAP_MODE_JPG_PLAY : ZORAN_MAP_MODE_JPG_REC;
+       fh->buffers.buffer_size = jpg_bufsize;
+       fh->buffers.num_buffers = jpg_nbufs;
+}
+static inline const char *mode_name(enum zoran_map_mode mode)
+{
+       return mode == ZORAN_MAP_MODE_RAW ? "V4L" : "JPG";
+}
 
 /*
  *   Allocate the V4L grab buffers
  *
  *   These have to be pysically contiguous.
- *   If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc
- *   else we try to allocate them with bigphysarea_alloc_pages
- *   if the bigphysarea patch is present in the kernel,
- *   else we try to use high memory (if the user has bootet
- *   Linux with the necessary memory left over).
- */
-
-static unsigned long
-get_high_mem (unsigned long size)
-{
-/*
- * Check if there is usable memory at the end of Linux memory
- * of at least size. Return the physical address of this memory,
- * return 0 on failure.
- *
- * The idea is from Alexandro Rubini's book "Linux device drivers".
- * The driver from him which is downloadable from O'Reilly's
- * web site misses the "virt_to_phys(high_memory)" part
- * (and therefore doesn't work at all - at least with 2.2.x kernels).
- *
- * It should be unnecessary to mention that THIS IS DANGEROUS,
- * if more than one driver at a time has the idea to use this memory!!!!
  */
 
-       volatile unsigned char __iomem *mem;
-       unsigned char c;
-       unsigned long hi_mem_ph;
-       unsigned long i;
-
-       /* Map the high memory to user space */
-
-       hi_mem_ph = virt_to_phys(high_memory);
-
-       mem = ioremap(hi_mem_ph, size);
-       if (!mem) {
-               dprintk(1,
-                       KERN_ERR "%s: get_high_mem() - ioremap failed\n",
-                       ZORAN_NAME);
-               return 0;
-       }
-
-       for (i = 0; i < size; i++) {
-               /* Check if it is memory */
-               c = i & 0xff;
-               writeb(c, mem + i);
-               if (readb(mem + i) != c)
-                       break;
-               c = 255 - c;
-               writeb(c, mem + i);
-               if (readb(mem + i) != c)
-                       break;
-               writeb(0, mem + i);     /* zero out memory */
-
-               /* give the kernel air to breath */
-               if ((i & 0x3ffff) == 0x3ffff)
-                       schedule();
-       }
-
-       iounmap(mem);
-
-       if (i != size) {
-               dprintk(1,
-                       KERN_ERR
-                       "%s: get_high_mem() - requested %lu, avail %lu\n",
-                       ZORAN_NAME, size, i);
-               return 0;
-       }
-
-       return hi_mem_ph;
-}
-
-static int
-v4l_fbuffer_alloc (struct file *file)
+static int v4l_fbuffer_alloc(struct zoran_fh *fh)
 {
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
        int i, off;
        unsigned char *mem;
-       unsigned long pmem = 0;
 
-       /* we might have old buffers lying around... */
-       if (fh->v4l_buffers.ready_to_be_freed) {
-               v4l_fbuffer_free(file);
-       }
-
-       for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
-               if (fh->v4l_buffers.buffer[i].fbuffer)
+       for (i = 0; i < fh->buffers.num_buffers; i++) {
+               if (fh->buffers.buffer[i].v4l.fbuffer)
                        dprintk(2,
                                KERN_WARNING
-                               "%s: v4l_fbuffer_alloc() - buffer %d allready allocated!?\n",
-                               ZR_DEVNAME(zr), i);
+                               "%s: %s - buffer %d already allocated!?\n",
+                               ZR_DEVNAME(zr), __func__, i);
 
                //udelay(20);
-               if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) {
-                       /* Use kmalloc */
-
-                       mem = kmalloc(fh->v4l_buffers.buffer_size, GFP_KERNEL);
-                       if (!mem) {
-                               dprintk(1,
-                                       KERN_ERR
-                                       "%s: v4l_fbuffer_alloc() - kmalloc for V4L buf %d failed\n",
-                                       ZR_DEVNAME(zr), i);
-                               v4l_fbuffer_free(file);
-                               return -ENOBUFS;
-                       }
-                       fh->v4l_buffers.buffer[i].fbuffer = mem;
-                       fh->v4l_buffers.buffer[i].fbuffer_phys =
-                           virt_to_phys(mem);
-                       fh->v4l_buffers.buffer[i].fbuffer_bus =
-                           virt_to_bus(mem);
-                       for (off = 0; off < fh->v4l_buffers.buffer_size;
-                            off += PAGE_SIZE)
-                               SetPageReserved(MAP_NR(mem + off));
-                       dprintk(4,
-                               KERN_INFO
-                               "%s: v4l_fbuffer_alloc() - V4L frame %d mem 0x%lx (bus: 0x%lx)\n",
-                               ZR_DEVNAME(zr), i, (unsigned long) mem,
-                               virt_to_bus(mem));
-               } else {
-
-                       /* Use high memory which has been left at boot time */
-
-                       /* Ok., Ok. this is an evil hack - we make
-                        * the assumption that physical addresses are
-                        * the same as bus addresses (true at least
-                        * for Intel processors). The whole method of
-                        * obtaining and using this memory is not very
-                        * nice - but I hope it saves some poor users
-                        * from kernel hacking, which might have even
-                        * more evil results */
-
-                       if (i == 0) {
-                               int size =
-                                   fh->v4l_buffers.num_buffers *
-                                   fh->v4l_buffers.buffer_size;
-
-                               pmem = get_high_mem(size);
-                               if (pmem == 0) {
-                                       dprintk(1,
-                                               KERN_ERR
-                                               "%s: v4l_fbuffer_alloc() - get_high_mem (size = %d KB) for V4L bufs failed\n",
-                                               ZR_DEVNAME(zr), size >> 10);
-                                       return -ENOBUFS;
-                               }
-                               fh->v4l_buffers.buffer[0].fbuffer = NULL;
-                               fh->v4l_buffers.buffer[0].fbuffer_phys = pmem;
-                               fh->v4l_buffers.buffer[0].fbuffer_bus = pmem;
-                               dprintk(4,
-                                       KERN_INFO
-                                       "%s: v4l_fbuffer_alloc() - using %d KB high memory\n",
-                                       ZR_DEVNAME(zr), size >> 10);
-                       } else {
-                               fh->v4l_buffers.buffer[i].fbuffer = NULL;
-                               fh->v4l_buffers.buffer[i].fbuffer_phys =
-                                   pmem + i * fh->v4l_buffers.buffer_size;
-                               fh->v4l_buffers.buffer[i].fbuffer_bus =
-                                   pmem + i * fh->v4l_buffers.buffer_size;
-                       }
+               mem = kmalloc(fh->buffers.buffer_size,
+                             GFP_KERNEL | __GFP_NOWARN);
+               if (!mem) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: %s - kmalloc for V4L buf %d failed\n",
+                               ZR_DEVNAME(zr), __func__, i);
+                       v4l_fbuffer_free(fh);
+                       return -ENOBUFS;
                }
+               fh->buffers.buffer[i].v4l.fbuffer = mem;
+               fh->buffers.buffer[i].v4l.fbuffer_phys = virt_to_phys(mem);
+               fh->buffers.buffer[i].v4l.fbuffer_bus = virt_to_bus(mem);
+               for (off = 0; off < fh->buffers.buffer_size;
+                    off += PAGE_SIZE)
+                       SetPageReserved(virt_to_page(mem + off));
+               dprintk(4,
+                       KERN_INFO
+                       "%s: %s - V4L frame %d mem 0x%lx (bus: 0x%llx)\n",
+                       ZR_DEVNAME(zr), __func__, i, (unsigned long) mem,
+                       (unsigned long long)virt_to_bus(mem));
        }
 
-       fh->v4l_buffers.allocated = 1;
+       fh->buffers.allocated = 1;
 
        return 0;
 }
 
 /* free the V4L grab buffers */
-static void
-v4l_fbuffer_free (struct file *file)
+static void v4l_fbuffer_free(struct zoran_fh *fh)
 {
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
        int i, off;
        unsigned char *mem;
 
-       dprintk(4, KERN_INFO "%s: v4l_fbuffer_free()\n", ZR_DEVNAME(zr));
+       dprintk(4, KERN_INFO "%s: %s\n", ZR_DEVNAME(zr), __func__);
 
-       for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
-               if (!fh->v4l_buffers.buffer[i].fbuffer)
+       for (i = 0; i < fh->buffers.num_buffers; i++) {
+               if (!fh->buffers.buffer[i].v4l.fbuffer)
                        continue;
 
-               if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) {
-                       mem = fh->v4l_buffers.buffer[i].fbuffer;
-                       for (off = 0; off < fh->v4l_buffers.buffer_size;
-                            off += PAGE_SIZE)
-                               ClearPageReserved(MAP_NR(mem + off));
-                       kfree((void *) fh->v4l_buffers.buffer[i].fbuffer);
-               }
-               fh->v4l_buffers.buffer[i].fbuffer = NULL;
+               mem = fh->buffers.buffer[i].v4l.fbuffer;
+               for (off = 0; off < fh->buffers.buffer_size;
+                    off += PAGE_SIZE)
+                       ClearPageReserved(virt_to_page(mem + off));
+               kfree(fh->buffers.buffer[i].v4l.fbuffer);
+               fh->buffers.buffer[i].v4l.fbuffer = NULL;
        }
 
-       fh->v4l_buffers.allocated = 0;
-       fh->v4l_buffers.ready_to_be_freed = 0;
+       fh->buffers.allocated = 0;
 }
 
 /*
  *   Allocate the MJPEG grab buffers.
  *
- *   If the requested buffer size is smaller than MAX_KMALLOC_MEM,
- *   kmalloc is used to request a physically contiguous area,
- *   else we allocate the memory in framgents with get_zeroed_page.
- *
  *   If a Natoma chipset is present and this is a revision 1 zr36057,
  *   each MJPEG buffer needs to be physically contiguous.
  *   (RJ: This statement is from Dave Perks' original driver,
  *   I could never check it because I have a zr36067)
- *   The driver cares about this because it reduces the buffer
- *   size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation).
  *
  *   RJ: The contents grab buffers needs never be accessed in the driver.
  *       Therefore there is no need to allocate them with vmalloc in order
@@ -458,162 +307,128 @@ v4l_fbuffer_free (struct file *file)
  *       and fragment buffers are not little-endian.
  */
 
-static int
-jpg_fbuffer_alloc (struct file *file)
+static int jpg_fbuffer_alloc(struct zoran_fh *fh)
 {
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
        int i, j, off;
-       unsigned long mem;
-
-       /* we might have old buffers lying around */
-       if (fh->jpg_buffers.ready_to_be_freed) {
-               jpg_fbuffer_free(file);
-       }
+       u8 *mem;
 
-       for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
-               if (fh->jpg_buffers.buffer[i].frag_tab)
+       for (i = 0; i < fh->buffers.num_buffers; i++) {
+               if (fh->buffers.buffer[i].jpg.frag_tab)
                        dprintk(2,
                                KERN_WARNING
-                               "%s: jpg_fbuffer_alloc() - buffer %d allready allocated!?\n",
-                               ZR_DEVNAME(zr), i);
+                               "%s: %s - buffer %d already allocated!?\n",
+                               ZR_DEVNAME(zr), __func__, i);
 
                /* Allocate fragment table for this buffer */
 
-               mem = get_zeroed_page(GFP_KERNEL);
+               mem = (void *)get_zeroed_page(GFP_KERNEL);
                if (mem == 0) {
                        dprintk(1,
                                KERN_ERR
-                               "%s: jpg_fbuffer_alloc() - get_zeroed_page (frag_tab) failed for buffer %d\n",
-                               ZR_DEVNAME(zr), i);
-                       jpg_fbuffer_free(file);
+                               "%s: %s - get_zeroed_page (frag_tab) failed for buffer %d\n",
+                               ZR_DEVNAME(zr), __func__, i);
+                       jpg_fbuffer_free(fh);
                        return -ENOBUFS;
                }
-               fh->jpg_buffers.buffer[i].frag_tab = (__le32 *) mem;
-               fh->jpg_buffers.buffer[i].frag_tab_bus =
-                   virt_to_bus((void *) mem);
-
-               //if (alloc_contig) {
-               if (fh->jpg_buffers.need_contiguous) {
-                       mem =
-                           (unsigned long) kmalloc(fh->jpg_buffers.
-                                                   buffer_size,
-                                                   GFP_KERNEL);
-                       if (mem == 0) {
+               fh->buffers.buffer[i].jpg.frag_tab = (__le32 *)mem;
+               fh->buffers.buffer[i].jpg.frag_tab_bus = virt_to_bus(mem);
+
+               if (fh->buffers.need_contiguous) {
+                       mem = kmalloc(fh->buffers.buffer_size, GFP_KERNEL);
+                       if (mem == NULL) {
                                dprintk(1,
                                        KERN_ERR
-                                       "%s: jpg_fbuffer_alloc() - kmalloc failed for buffer %d\n",
-                                       ZR_DEVNAME(zr), i);
-                               jpg_fbuffer_free(file);
+                                       "%s: %s - kmalloc failed for buffer %d\n",
+                                       ZR_DEVNAME(zr), __func__, i);
+                               jpg_fbuffer_free(fh);
                                return -ENOBUFS;
                        }
-                       fh->jpg_buffers.buffer[i].frag_tab[0] =
-                           cpu_to_le32(virt_to_bus((void *) mem));
-                       fh->jpg_buffers.buffer[i].frag_tab[1] =
-                           cpu_to_le32(((fh->jpg_buffers.buffer_size / 4) << 1) | 1);
-                       for (off = 0; off < fh->jpg_buffers.buffer_size;
-                            off += PAGE_SIZE)
-                               SetPageReserved(MAP_NR(mem + off));
+                       fh->buffers.buffer[i].jpg.frag_tab[0] =
+                               cpu_to_le32(virt_to_bus(mem));
+                       fh->buffers.buffer[i].jpg.frag_tab[1] =
+                               cpu_to_le32((fh->buffers.buffer_size >> 1) | 1);
+                       for (off = 0; off < fh->buffers.buffer_size; off += PAGE_SIZE)
+                               SetPageReserved(virt_to_page(mem + off));
                } else {
-                       /* jpg_bufsize is allreay page aligned */
-                       for (j = 0;
-                            j < fh->jpg_buffers.buffer_size / PAGE_SIZE;
-                            j++) {
-                               mem = get_zeroed_page(GFP_KERNEL);
-                               if (mem == 0) {
+                       /* jpg_bufsize is already page aligned */
+                       for (j = 0; j < fh->buffers.buffer_size / PAGE_SIZE; j++) {
+                               mem = (void *)get_zeroed_page(GFP_KERNEL);
+                               if (mem == NULL) {
                                        dprintk(1,
                                                KERN_ERR
-                                               "%s: jpg_fbuffer_alloc() - get_zeroed_page failed for buffer %d\n",
-                                               ZR_DEVNAME(zr), i);
-                                       jpg_fbuffer_free(file);
+                                               "%s: %s - get_zeroed_page failed for buffer %d\n",
+                                               ZR_DEVNAME(zr), __func__, i);
+                                       jpg_fbuffer_free(fh);
                                        return -ENOBUFS;
                                }
 
-                               fh->jpg_buffers.buffer[i].frag_tab[2 * j] =
-                                   cpu_to_le32(virt_to_bus((void *) mem));
-                               fh->jpg_buffers.buffer[i].frag_tab[2 * j +
-                                                                  1] =
-                                   cpu_to_le32((PAGE_SIZE / 4) << 1);
-                               SetPageReserved(MAP_NR(mem));
+                               fh->buffers.buffer[i].jpg.frag_tab[2 * j] =
+                                       cpu_to_le32(virt_to_bus(mem));
+                               fh->buffers.buffer[i].jpg.frag_tab[2 * j + 1] =
+                                       cpu_to_le32((PAGE_SIZE >> 2) << 1);
+                               SetPageReserved(virt_to_page(mem));
                        }
 
-                       fh->jpg_buffers.buffer[i].frag_tab[2 * j - 1] |= cpu_to_le32(1);
+                       fh->buffers.buffer[i].jpg.frag_tab[2 * j - 1] |= cpu_to_le32(1);
                }
        }
 
        dprintk(4,
-               KERN_DEBUG "%s: jpg_fbuffer_alloc() - %d KB allocated\n",
-               ZR_DEVNAME(zr),
-               (fh->jpg_buffers.num_buffers *
-                fh->jpg_buffers.buffer_size) >> 10);
+               KERN_DEBUG "%s: %s - %d KB allocated\n",
+               ZR_DEVNAME(zr), __func__,
+               (fh->buffers.num_buffers * fh->buffers.buffer_size) >> 10);
 
-       fh->jpg_buffers.allocated = 1;
+       fh->buffers.allocated = 1;
 
        return 0;
 }
 
 /* free the MJPEG grab buffers */
-static void
-jpg_fbuffer_free (struct file *file)
+static void jpg_fbuffer_free(struct zoran_fh *fh)
 {
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
        int i, j, off;
        unsigned char *mem;
+       __le32 frag_tab;
+       struct zoran_buffer *buffer;
 
-       dprintk(4, KERN_DEBUG "%s: jpg_fbuffer_free()\n", ZR_DEVNAME(zr));
+       dprintk(4, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
 
-       for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
-               if (!fh->jpg_buffers.buffer[i].frag_tab)
+       for (i = 0, buffer = &fh->buffers.buffer[0];
+            i < fh->buffers.num_buffers; i++, buffer++) {
+               if (!buffer->jpg.frag_tab)
                        continue;
 
-               //if (alloc_contig) {
-               if (fh->jpg_buffers.need_contiguous) {
-                       if (fh->jpg_buffers.buffer[i].frag_tab[0]) {
-                               mem = (unsigned char *) bus_to_virt(le32_to_cpu(
-                                       fh->jpg_buffers.buffer[i].frag_tab[0]));
-                               for (off = 0;
-                                    off < fh->jpg_buffers.buffer_size;
-                                    off += PAGE_SIZE)
-                                       ClearPageReserved(MAP_NR
-                                                         (mem + off));
+               if (fh->buffers.need_contiguous) {
+                       frag_tab = buffer->jpg.frag_tab[0];
+
+                       if (frag_tab) {
+                               mem = bus_to_virt(le32_to_cpu(frag_tab));
+                               for (off = 0; off < fh->buffers.buffer_size; off += PAGE_SIZE)
+                                       ClearPageReserved(virt_to_page(mem + off));
                                kfree(mem);
-                               fh->jpg_buffers.buffer[i].frag_tab[0] = 0;
-                               fh->jpg_buffers.buffer[i].frag_tab[1] = 0;
+                               buffer->jpg.frag_tab[0] = 0;
+                               buffer->jpg.frag_tab[1] = 0;
                        }
                } else {
-                       for (j = 0;
-                            j < fh->jpg_buffers.buffer_size / PAGE_SIZE;
-                            j++) {
-                               if (!fh->jpg_buffers.buffer[i].
-                                   frag_tab[2 * j])
+                       for (j = 0; j < fh->buffers.buffer_size / PAGE_SIZE; j++) {
+                               frag_tab = buffer->jpg.frag_tab[2 * j];
+
+                               if (!frag_tab)
                                        break;
-                               ClearPageReserved(MAP_NR
-                                                 (bus_to_virt
-                                                  (le32_to_cpu
-                                                   (fh->jpg_buffers.
-                                                    buffer[i].frag_tab[2 *
-                                                                      j]))));
-                               free_page((unsigned long)
-                                         bus_to_virt
-                                                 (le32_to_cpu
-                                                  (fh->jpg_buffers.
-                                                     buffer[i].
-                                                     frag_tab[2 * j])));
-                               fh->jpg_buffers.buffer[i].frag_tab[2 * j] =
-                                   0;
-                               fh->jpg_buffers.buffer[i].frag_tab[2 * j +
-                                                                  1] = 0;
+                               ClearPageReserved(virt_to_page(bus_to_virt(le32_to_cpu(frag_tab))));
+                               free_page((unsigned long)bus_to_virt(le32_to_cpu(frag_tab)));
+                               buffer->jpg.frag_tab[2 * j] = 0;
+                               buffer->jpg.frag_tab[2 * j + 1] = 0;
                        }
                }
 
-               free_page((unsigned long) fh->jpg_buffers.buffer[i].
-                         frag_tab);
-               fh->jpg_buffers.buffer[i].frag_tab = NULL;
+               free_page((unsigned long)buffer->jpg.frag_tab);
+               buffer->jpg.frag_tab = NULL;
        }
 
-       fh->jpg_buffers.allocated = 0;
-       fh->jpg_buffers.ready_to_be_freed = 0;
+       fh->buffers.allocated = 0;
 }
 
 /*
@@ -621,12 +436,11 @@ jpg_fbuffer_free (struct file *file)
  */
 
 static int
-zoran_v4l_set_format (struct file               *file,
+zoran_v4l_set_format (struct zoran_fh           *fh,
                      int                        width,
                      int                        height,
                      const struct zoran_format *format)
 {
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
        int bpp;
 
@@ -636,19 +450,19 @@ zoran_v4l_set_format (struct file               *file,
            height > BUZ_MAX_HEIGHT || width > BUZ_MAX_WIDTH) {
                dprintk(1,
                        KERN_ERR
-                       "%s: v4l_set_format() - wrong frame size (%dx%d)\n",
-                       ZR_DEVNAME(zr), width, height);
+                       "%s: %s - wrong frame size (%dx%d)\n",
+                       ZR_DEVNAME(zr), __func__, width, height);
                return -EINVAL;
        }
 
        bpp = (format->depth + 7) / 8;
 
        /* Check against available buffer size */
-       if (height * width * bpp > fh->v4l_buffers.buffer_size) {
+       if (height * width * bpp > fh->buffers.buffer_size) {
                dprintk(1,
                        KERN_ERR
-                       "%s: v4l_set_format() - video buffer size (%d kB) is too small\n",
-                       ZR_DEVNAME(zr), fh->v4l_buffers.buffer_size >> 10);
+                       "%s: %s - video buffer size (%d kB) is too small\n",
+                       ZR_DEVNAME(zr), __func__, fh->buffers.buffer_size >> 10);
                return -EINVAL;
        }
 
@@ -657,8 +471,8 @@ zoran_v4l_set_format (struct file               *file,
        if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) {
                dprintk(1,
                        KERN_ERR
-                       "%s: v4l_set_format() - wrong frame alingment\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - wrong frame alignment\n",
+                       ZR_DEVNAME(zr), __func__);
                return -EINVAL;
        }
 
@@ -670,43 +484,40 @@ zoran_v4l_set_format (struct file               *file,
        return 0;
 }
 
-static int
-zoran_v4l_queue_frame (struct file *file,
-                      int          num)
+static int zoran_v4l_queue_frame(struct zoran_fh *fh, int num)
 {
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
        unsigned long flags;
        int res = 0;
 
-       if (!fh->v4l_buffers.allocated) {
+       if (!fh->buffers.allocated) {
                dprintk(1,
                        KERN_ERR
-                       "%s: v4l_queue_frame() - buffers not yet allocated\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - buffers not yet allocated\n",
+                       ZR_DEVNAME(zr), __func__);
                res = -ENOMEM;
        }
 
        /* No grabbing outside the buffer range! */
-       if (num >= fh->v4l_buffers.num_buffers || num < 0) {
+       if (num >= fh->buffers.num_buffers || num < 0) {
                dprintk(1,
                        KERN_ERR
-                       "%s: v4l_queue_frame() - buffer %d is out of range\n",
-                       ZR_DEVNAME(zr), num);
+                       "%s: %s - buffer %d is out of range\n",
+                       ZR_DEVNAME(zr), __func__, num);
                res = -EINVAL;
        }
 
        spin_lock_irqsave(&zr->spinlock, flags);
 
-       if (fh->v4l_buffers.active == ZORAN_FREE) {
+       if (fh->buffers.active == ZORAN_FREE) {
                if (zr->v4l_buffers.active == ZORAN_FREE) {
-                       zr->v4l_buffers = fh->v4l_buffers;
-                       fh->v4l_buffers.active = ZORAN_ACTIVE;
+                       zr->v4l_buffers = fh->buffers;
+                       fh->buffers.active = ZORAN_ACTIVE;
                } else {
                        dprintk(1,
                                KERN_ERR
-                               "%s: v4l_queue_frame() - another session is already capturing\n",
-                               ZR_DEVNAME(zr));
+                               "%s: %s - another session is already capturing\n",
+                               ZR_DEVNAME(zr), __func__);
                        res = -EBUSY;
                }
        }
@@ -717,7 +528,7 @@ zoran_v4l_queue_frame (struct file *file,
                default:
                case BUZ_STATE_PEND:
                        if (zr->v4l_buffers.active == ZORAN_FREE) {
-                               fh->v4l_buffers.active = ZORAN_FREE;
+                               fh->buffers.active = ZORAN_FREE;
                                zr->v4l_buffers.allocated = 0;
                        }
                        res = -EBUSY;   /* what are you doing? */
@@ -725,19 +536,17 @@ zoran_v4l_queue_frame (struct file *file,
                case BUZ_STATE_DONE:
                        dprintk(2,
                                KERN_WARNING
-                               "%s: v4l_queue_frame() - queueing buffer %d in state DONE!?\n",
-                               ZR_DEVNAME(zr), num);
+                               "%s: %s - queueing buffer %d in state DONE!?\n",
+                               ZR_DEVNAME(zr), __func__, num);
                case BUZ_STATE_USER:
                        /* since there is at least one unused buffer there's room for at least
                         * one more pend[] entry */
-                       zr->v4l_pend[zr->v4l_pend_head++ &
-                                       V4L_MASK_FRAME] = num;
+                       zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = num;
                        zr->v4l_buffers.buffer[num].state = BUZ_STATE_PEND;
                        zr->v4l_buffers.buffer[num].bs.length =
                            fh->v4l_settings.bytesperline *
                            zr->v4l_settings.height;
-                       fh->v4l_buffers.buffer[num] =
-                           zr->v4l_buffers.buffer[num];
+                       fh->buffers.buffer[num] = zr->v4l_buffers.buffer[num];
                        break;
                }
        }
@@ -745,65 +554,7 @@ zoran_v4l_queue_frame (struct file *file,
        spin_unlock_irqrestore(&zr->spinlock, flags);
 
        if (!res && zr->v4l_buffers.active == ZORAN_FREE)
-               zr->v4l_buffers.active = fh->v4l_buffers.active;
-
-       return res;
-}
-
-static int
-v4l_grab (struct file       *file,
-         struct video_mmap *mp)
-{
-       struct zoran_fh *fh = file->private_data;
-       struct zoran *zr = fh->zr;
-       int res = 0, i;
-
-       for (i = 0; i < NUM_FORMATS; i++) {
-               if (zoran_formats[i].palette == mp->format &&
-                   zoran_formats[i].flags & ZORAN_FORMAT_CAPTURE &&
-                   !(zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED))
-                       break;
-       }
-       if (i == NUM_FORMATS || zoran_formats[i].depth == 0) {
-               dprintk(1,
-                       KERN_ERR
-                       "%s: v4l_grab() - wrong bytes-per-pixel format\n",
-                       ZR_DEVNAME(zr));
-               return -EINVAL;
-       }
-
-       /*
-        * To minimize the time spent in the IRQ routine, we avoid setting up
-        * the video front end there.
-        * If this grab has different parameters from a running streaming capture
-        * we stop the streaming capture and start it over again.
-        */
-       if (zr->v4l_memgrab_active &&
-           (zr->v4l_settings.width != mp->width ||
-            zr->v4l_settings.height != mp->height ||
-            zr->v4l_settings.format->palette != mp->format)) {
-               res = wait_grab_pending(zr);
-               if (res)
-                       return res;
-       }
-       if ((res = zoran_v4l_set_format(file,
-                                       mp->width,
-                                       mp->height,
-                                       &zoran_formats[i])))
-               return res;
-       zr->v4l_settings = fh->v4l_settings;
-
-       /* queue the frame in the pending queue */
-       if ((res = zoran_v4l_queue_frame(file, mp->frame))) {
-               fh->v4l_buffers.active = ZORAN_FREE;
-               return res;
-       }
-
-       /* put the 36057 into frame grabbing mode */
-       if (!res && !zr->v4l_memgrab_active)
-               zr36057_set_memgrab(zr, 1);
-
-       //dprintk(4, KERN_INFO "%s: Frame grab 3...\n", ZR_DEVNAME(zr));
+               zr->v4l_buffers.active = fh->buffers.active;
 
        return res;
 }
@@ -812,27 +563,24 @@ v4l_grab (struct file       *file,
  * Sync on a V4L buffer
  */
 
-static int
-v4l_sync (struct file *file,
-         int          frame)
+static int v4l_sync(struct zoran_fh *fh, int frame)
 {
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
        unsigned long flags;
 
-       if (fh->v4l_buffers.active == ZORAN_FREE) {
+       if (fh->buffers.active == ZORAN_FREE) {
                dprintk(1,
                        KERN_ERR
-                       "%s: v4l_sync() - no grab active for this session\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - no grab active for this session\n",
+                       ZR_DEVNAME(zr), __func__);
                return -EINVAL;
        }
 
        /* check passed-in frame number */
-       if (frame >= fh->v4l_buffers.num_buffers || frame < 0) {
+       if (frame >= fh->buffers.num_buffers || frame < 0) {
                dprintk(1,
-                       KERN_ERR "%s: v4l_sync() - frame %d is invalid\n",
-                       ZR_DEVNAME(zr), frame);
+                       KERN_ERR "%s: %s - frame %d is invalid\n",
+                       ZR_DEVNAME(zr), __func__, frame);
                return -EINVAL;
        }
 
@@ -840,15 +588,14 @@ v4l_sync (struct file *file,
        if (zr->v4l_buffers.buffer[frame].state == BUZ_STATE_USER) {
                dprintk(1,
                        KERN_ERR
-                       "%s: v4l_sync() - attempt to sync on a buffer which was not queued?\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - attempt to sync on a buffer which was not queued?\n",
+                       ZR_DEVNAME(zr), __func__);
                return -EPROTO;
        }
 
        /* wait on this buffer to get ready */
        if (!wait_event_interruptible_timeout(zr->v4l_capq,
-                               (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_PEND),
-                               10*HZ))
+               (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_PEND), 10*HZ))
                return -ETIME;
        if (signal_pending(current))
                return -ERESTARTSYS;
@@ -856,11 +603,11 @@ v4l_sync (struct file *file,
        /* buffer should now be in BUZ_STATE_DONE */
        if (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_DONE)
                dprintk(2,
-                       KERN_ERR "%s: v4l_sync() - internal state error\n",
-                       ZR_DEVNAME(zr));
+                       KERN_ERR "%s: %s - internal state error\n",
+                       ZR_DEVNAME(zr), __func__);
 
        zr->v4l_buffers.buffer[frame].state = BUZ_STATE_USER;
-       fh->v4l_buffers.buffer[frame] = zr->v4l_buffers.buffer[frame];
+       fh->buffers.buffer[frame] = zr->v4l_buffers.buffer[frame];
 
        spin_lock_irqsave(&zr->spinlock, flags);
 
@@ -868,8 +615,7 @@ v4l_sync (struct file *file,
        if (zr->v4l_pend_tail == zr->v4l_pend_head) {
                zr36057_set_memgrab(zr, 0);
                if (zr->v4l_buffers.active == ZORAN_ACTIVE) {
-                       fh->v4l_buffers.active = zr->v4l_buffers.active =
-                           ZORAN_FREE;
+                       fh->buffers.active = zr->v4l_buffers.active = ZORAN_FREE;
                        zr->v4l_buffers.allocated = 0;
                }
        }
@@ -883,31 +629,28 @@ v4l_sync (struct file *file,
  *   Queue a MJPEG buffer for capture/playback
  */
 
-static int
-zoran_jpg_queue_frame (struct file          *file,
-                      int                   num,
-                      enum zoran_codec_mode mode)
+static int zoran_jpg_queue_frame(struct zoran_fh *fh, int num,
+                                enum zoran_codec_mode mode)
 {
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
        unsigned long flags;
        int res = 0;
 
        /* Check if buffers are allocated */
-       if (!fh->jpg_buffers.allocated) {
+       if (!fh->buffers.allocated) {
                dprintk(1,
                        KERN_ERR
-                       "%s: jpg_queue_frame() - buffers not yet allocated\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - buffers not yet allocated\n",
+                       ZR_DEVNAME(zr), __func__);
                return -ENOMEM;
        }
 
        /* No grabbing outside the buffer range! */
-       if (num >= fh->jpg_buffers.num_buffers || num < 0) {
+       if (num >= fh->buffers.num_buffers || num < 0) {
                dprintk(1,
                        KERN_ERR
-                       "%s: jpg_queue_frame() - buffer %d out of range\n",
-                       ZR_DEVNAME(zr), num);
+                       "%s: %s - buffer %d out of range\n",
+                       ZR_DEVNAME(zr), __func__, num);
                return -EINVAL;
        }
 
@@ -918,20 +661,20 @@ zoran_jpg_queue_frame (struct file          *file,
                /* wrong codec mode active - invalid */
                dprintk(1,
                        KERN_ERR
-                       "%s: jpg_queue_frame() - codec in wrong mode\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - codec in wrong mode\n",
+                       ZR_DEVNAME(zr), __func__);
                return -EINVAL;
        }
 
-       if (fh->jpg_buffers.active == ZORAN_FREE) {
+       if (fh->buffers.active == ZORAN_FREE) {
                if (zr->jpg_buffers.active == ZORAN_FREE) {
-                       zr->jpg_buffers = fh->jpg_buffers;
-                       fh->jpg_buffers.active = ZORAN_ACTIVE;
+                       zr->jpg_buffers = fh->buffers;
+                       fh->buffers.active = ZORAN_ACTIVE;
                } else {
                        dprintk(1,
                                KERN_ERR
-                               "%s: jpg_queue_frame() - another session is already capturing\n",
-                               ZR_DEVNAME(zr));
+                               "%s: %s - another session is already capturing\n",
+                               ZR_DEVNAME(zr), __func__);
                        res = -EBUSY;
                }
        }
@@ -948,23 +691,21 @@ zoran_jpg_queue_frame (struct file          *file,
                case BUZ_STATE_DONE:
                        dprintk(2,
                                KERN_WARNING
-                               "%s: jpg_queue_frame() - queing frame in BUZ_STATE_DONE state!?\n",
-                               ZR_DEVNAME(zr));
+                               "%s: %s - queing frame in BUZ_STATE_DONE state!?\n",
+                               ZR_DEVNAME(zr), __func__);
                case BUZ_STATE_USER:
                        /* since there is at least one unused buffer there's room for at
                         *least one more pend[] entry */
-                       zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] =
-                           num;
+                       zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = num;
                        zr->jpg_buffers.buffer[num].state = BUZ_STATE_PEND;
-                       fh->jpg_buffers.buffer[num] =
-                           zr->jpg_buffers.buffer[num];
+                       fh->buffers.buffer[num] = zr->jpg_buffers.buffer[num];
                        zoran_feed_stat_com(zr);
                        break;
                default:
                case BUZ_STATE_DMA:
                case BUZ_STATE_PEND:
                        if (zr->jpg_buffers.active == ZORAN_FREE) {
-                               fh->jpg_buffers.active = ZORAN_FREE;
+                               fh->buffers.active = ZORAN_FREE;
                                zr->jpg_buffers.allocated = 0;
                        }
                        res = -EBUSY;   /* what are you doing? */
@@ -974,47 +715,41 @@ zoran_jpg_queue_frame (struct file          *file,
 
        spin_unlock_irqrestore(&zr->spinlock, flags);
 
-       if (!res && zr->jpg_buffers.active == ZORAN_FREE) {
-               zr->jpg_buffers.active = fh->jpg_buffers.active;
-       }
+       if (!res && zr->jpg_buffers.active == ZORAN_FREE)
+               zr->jpg_buffers.active = fh->buffers.active;
 
        return res;
 }
 
-static int
-jpg_qbuf (struct file          *file,
-         int                   frame,
-         enum zoran_codec_mode mode)
+static int jpg_qbuf(struct zoran_fh *fh, int frame, enum zoran_codec_mode mode)
 {
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
        int res = 0;
 
        /* Does the user want to stop streaming? */
        if (frame < 0) {
                if (zr->codec_mode == mode) {
-                       if (fh->jpg_buffers.active == ZORAN_FREE) {
+                       if (fh->buffers.active == ZORAN_FREE) {
                                dprintk(1,
                                        KERN_ERR
-                                       "%s: jpg_qbuf(-1) - session not active\n",
-                                       ZR_DEVNAME(zr));
+                                       "%s: %s(-1) - session not active\n",
+                                       ZR_DEVNAME(zr), __func__);
                                return -EINVAL;
                        }
-                       fh->jpg_buffers.active = zr->jpg_buffers.active =
-                           ZORAN_FREE;
+                       fh->buffers.active = zr->jpg_buffers.active = ZORAN_FREE;
                        zr->jpg_buffers.allocated = 0;
                        zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
                        return 0;
                } else {
                        dprintk(1,
                                KERN_ERR
-                               "%s: jpg_qbuf() - stop streaming but not in streaming mode\n",
-                               ZR_DEVNAME(zr));
+                               "%s: %s - stop streaming but not in streaming mode\n",
+                               ZR_DEVNAME(zr), __func__);
                        return -EINVAL;
                }
        }
 
-       if ((res = zoran_jpg_queue_frame(file, frame, mode)))
+       if ((res = zoran_jpg_queue_frame(fh, frame, mode)))
                return res;
 
        /* Start the jpeg codec when the first frame is queued  */
@@ -1028,28 +763,25 @@ jpg_qbuf (struct file          *file,
  *   Sync on a MJPEG buffer
  */
 
-static int
-jpg_sync (struct file       *file,
-         struct zoran_sync *bs)
+static int jpg_sync(struct zoran_fh *fh, struct zoran_sync *bs)
 {
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
        unsigned long flags;
        int frame;
 
-       if (fh->jpg_buffers.active == ZORAN_FREE) {
+       if (fh->buffers.active == ZORAN_FREE) {
                dprintk(1,
                        KERN_ERR
-                       "%s: jpg_sync() - capture is not currently active\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - capture is not currently active\n",
+                       ZR_DEVNAME(zr), __func__);
                return -EINVAL;
        }
        if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS &&
            zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) {
                dprintk(1,
                        KERN_ERR
-                       "%s: jpg_sync() - codec not in streaming mode\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - codec not in streaming mode\n",
+                       ZR_DEVNAME(zr), __func__);
                return -EINVAL;
        }
        if (!wait_event_interruptible_timeout(zr->jpg_capq,
@@ -1064,8 +796,8 @@ jpg_sync (struct file       *file,
                                           sizeof(isr), &isr);
                dprintk(1,
                        KERN_ERR
-                       "%s: jpg_sync() - timeout: codec isr=0x%02x\n",
-                       ZR_DEVNAME(zr), isr);
+                       "%s: %s - timeout: codec isr=0x%02x\n",
+                       ZR_DEVNAME(zr), __func__, isr);
 
                return -ETIME;
 
@@ -1083,28 +815,26 @@ jpg_sync (struct file       *file,
        /* buffer should now be in BUZ_STATE_DONE */
        if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE)
                dprintk(2,
-                       KERN_ERR "%s: jpg_sync() - internal state error\n",
-                       ZR_DEVNAME(zr));
+                       KERN_ERR "%s: %s - internal state error\n",
+                       ZR_DEVNAME(zr), __func__);
 
        *bs = zr->jpg_buffers.buffer[frame].bs;
        bs->frame = frame;
        zr->jpg_buffers.buffer[frame].state = BUZ_STATE_USER;
-       fh->jpg_buffers.buffer[frame] = zr->jpg_buffers.buffer[frame];
+       fh->buffers.buffer[frame] = zr->jpg_buffers.buffer[frame];
 
        spin_unlock_irqrestore(&zr->spinlock, flags);
 
        return 0;
 }
 
-static void
-zoran_open_init_session (struct file *file)
+static void zoran_open_init_session(struct zoran_fh *fh)
 {
        int i;
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
 
        /* Per default, map the V4L Buffers */
-       fh->map_mode = ZORAN_MAP_MODE_RAW;
+       map_mode_raw(fh);
 
        /* take over the card's current settings */
        fh->overlay_settings = zr->overlay_settings;
@@ -1114,40 +844,21 @@ zoran_open_init_session (struct file *file)
 
        /* v4l settings */
        fh->v4l_settings = zr->v4l_settings;
-
-       /* v4l_buffers */
-       memset(&fh->v4l_buffers, 0, sizeof(struct zoran_v4l_struct));
-       for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-               fh->v4l_buffers.buffer[i].state = BUZ_STATE_USER;       /* nothing going on */
-               fh->v4l_buffers.buffer[i].bs.frame = i;
-       }
-       fh->v4l_buffers.allocated = 0;
-       fh->v4l_buffers.ready_to_be_freed = 0;
-       fh->v4l_buffers.active = ZORAN_FREE;
-       fh->v4l_buffers.buffer_size = v4l_bufsize;
-       fh->v4l_buffers.num_buffers = v4l_nbufs;
-
        /* jpg settings */
        fh->jpg_settings = zr->jpg_settings;
 
-       /* jpg_buffers */
-       memset(&fh->jpg_buffers, 0, sizeof(struct zoran_jpg_struct));
-       for (i = 0; i < BUZ_MAX_FRAME; i++) {
-               fh->jpg_buffers.buffer[i].state = BUZ_STATE_USER;       /* nothing going on */
-               fh->jpg_buffers.buffer[i].bs.frame = i;
+       /* buffers */
+       memset(&fh->buffers, 0, sizeof(fh->buffers));
+       for (i = 0; i < MAX_FRAME; i++) {
+               fh->buffers.buffer[i].state = BUZ_STATE_USER;   /* nothing going on */
+               fh->buffers.buffer[i].bs.frame = i;
        }
-       fh->jpg_buffers.need_contiguous = zr->jpg_buffers.need_contiguous;
-       fh->jpg_buffers.allocated = 0;
-       fh->jpg_buffers.ready_to_be_freed = 0;
-       fh->jpg_buffers.active = ZORAN_FREE;
-       fh->jpg_buffers.buffer_size = jpg_bufsize;
-       fh->jpg_buffers.num_buffers = jpg_nbufs;
+       fh->buffers.allocated = 0;
+       fh->buffers.active = ZORAN_FREE;
 }
 
-static void
-zoran_close_end_session (struct file *file)
+static void zoran_close_end_session(struct zoran_fh *fh)
 {
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
 
        /* overlay */
@@ -1159,36 +870,32 @@ zoran_close_end_session (struct file *file)
                zr->overlay_mask = NULL;
        }
 
-       /* v4l capture */
-       if (fh->v4l_buffers.active != ZORAN_FREE) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&zr->spinlock, flags);
-               zr36057_set_memgrab(zr, 0);
-               zr->v4l_buffers.allocated = 0;
-               zr->v4l_buffers.active = fh->v4l_buffers.active =
-                   ZORAN_FREE;
-               spin_unlock_irqrestore(&zr->spinlock, flags);
-       }
+       if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
+               /* v4l capture */
+               if (fh->buffers.active != ZORAN_FREE) {
+                       unsigned long flags;
 
-       /* v4l buffers */
-       if (fh->v4l_buffers.allocated ||
-           fh->v4l_buffers.ready_to_be_freed) {
-               v4l_fbuffer_free(file);
-       }
+                       spin_lock_irqsave(&zr->spinlock, flags);
+                       zr36057_set_memgrab(zr, 0);
+                       zr->v4l_buffers.allocated = 0;
+                       zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE;
+                       spin_unlock_irqrestore(&zr->spinlock, flags);
+               }
 
-       /* jpg capture */
-       if (fh->jpg_buffers.active != ZORAN_FREE) {
-               zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
-               zr->jpg_buffers.allocated = 0;
-               zr->jpg_buffers.active = fh->jpg_buffers.active =
-                   ZORAN_FREE;
-       }
+               /* v4l buffers */
+               if (fh->buffers.allocated)
+                       v4l_fbuffer_free(fh);
+       } else {
+               /* jpg capture */
+               if (fh->buffers.active != ZORAN_FREE) {
+                       zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+                       zr->jpg_buffers.allocated = 0;
+                       zr->jpg_buffers.active = fh->buffers.active = ZORAN_FREE;
+               }
 
-       /* jpg buffers */
-       if (fh->jpg_buffers.allocated ||
-           fh->jpg_buffers.ready_to_be_freed) {
-               jpg_fbuffer_free(file);
+               /* jpg buffers */
+               if (fh->buffers.allocated)
+                       jpg_fbuffer_free(fh);
        }
 }
 
@@ -1202,15 +909,11 @@ static int zoran_open(struct file *file)
        struct zoran_fh *fh;
        int res, first_open = 0;
 
-       dprintk(2, KERN_INFO "%s: zoran_open(%s, pid=[%d]), users(-)=%d\n",
-               ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user + 1);
+       dprintk(2, KERN_INFO "%s: %s(%s, pid=[%d]), users(-)=%d\n",
+               ZR_DEVNAME(zr), __func__, current->comm, task_pid_nr(current), zr->user + 1);
 
        lock_kernel();
 
-       /* see fs/device.c - the kernel already locks during open(),
-        * so locking ourselves only causes deadlocks */
-       /*mutex_lock(&zr->resource_lock);*/
-
        if (zr->user >= 2048) {
                dprintk(1, KERN_ERR "%s: too many users (%d) on device\n",
                        ZR_DEVNAME(zr), zr->user);
@@ -1218,41 +921,15 @@ static int zoran_open(struct file *file)
                goto fail_unlock;
        }
 
-       if (!zr->decoder) {
-               dprintk(1,
-                       KERN_ERR "%s: no TV decoder loaded for device!\n",
-                       ZR_DEVNAME(zr));
-               res = -EIO;
-               goto fail_unlock;
-       }
-
-       if (!try_module_get(zr->decoder->driver->driver.owner)) {
-               dprintk(1,
-                       KERN_ERR
-                       "%s: failed to grab ownership of video decoder\n",
-                       ZR_DEVNAME(zr));
-               res = -EIO;
-               goto fail_unlock;
-       }
-       if (zr->encoder &&
-           !try_module_get(zr->encoder->driver->driver.owner)) {
-               dprintk(1,
-                       KERN_ERR
-                       "%s: failed to grab ownership of video encoder\n",
-                       ZR_DEVNAME(zr));
-               res = -EIO;
-               goto fail_decoder;
-       }
-
        /* now, create the open()-specific file_ops struct */
        fh = kzalloc(sizeof(struct zoran_fh), GFP_KERNEL);
        if (!fh) {
                dprintk(1,
                        KERN_ERR
-                       "%s: zoran_open() - allocation of zoran_fh failed\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - allocation of zoran_fh failed\n",
+                       ZR_DEVNAME(zr), __func__);
                res = -ENOMEM;
-               goto fail_encoder;
+               goto fail_unlock;
        }
        /* used to be BUZ_MAX_WIDTH/HEIGHT, but that gives overflows
         * on norm-change! */
@@ -1261,8 +938,8 @@ static int zoran_open(struct file *file)
        if (!fh->overlay_mask) {
                dprintk(1,
                        KERN_ERR
-                       "%s: zoran_open() - allocation of overlay_mask failed\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - allocation of overlay_mask failed\n",
+                       ZR_DEVNAME(zr), __func__);
                res = -ENOMEM;
                goto fail_fh;
        }
@@ -1284,18 +961,13 @@ static int zoran_open(struct file *file)
        /* set file_ops stuff */
        file->private_data = fh;
        fh->zr = zr;
-       zoran_open_init_session(file);
+       zoran_open_init_session(fh);
        unlock_kernel();
 
        return 0;
 
 fail_fh:
        kfree(fh);
-fail_encoder:
-       if (zr->encoder)
-               module_put(zr->encoder->driver->driver.owner);
-fail_decoder:
-       module_put(zr->decoder->driver->driver.owner);
 fail_unlock:
        unlock_kernel();
 
@@ -1311,14 +983,14 @@ zoran_close(struct file  *file)
        struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
 
-       dprintk(2, KERN_INFO "%s: zoran_close(%s, pid=[%d]), users(+)=%d\n",
-               ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user - 1);
+       dprintk(2, KERN_INFO "%s: %s(%s, pid=[%d]), users(+)=%d\n",
+               ZR_DEVNAME(zr), __func__, current->comm, task_pid_nr(current), zr->user - 1);
 
        /* kernel locks (fs/device.c), so don't do that ourselves
         * (prevents deadlocks) */
        /*mutex_lock(&zr->resource_lock);*/
 
-       zoran_close_end_session(file);
+       zoran_close_end_session(fh);
 
        if (zr->user-- == 1) {  /* Last process */
                /* Clean up JPEG process */
@@ -1346,9 +1018,10 @@ zoran_close(struct file  *file)
                zoran_set_pci_master(zr, 0);
 
                if (!pass_through) {    /* Switch to color bar */
-                       int zero = 0, two = 2;
-                       decoder_command(zr, DECODER_ENABLE_OUTPUT, &zero);
-                       encoder_command(zr, ENCODER_SET_INPUT, &two);
+                       struct v4l2_routing route = { 2, 0 };
+
+                       decoder_call(zr, video, s_stream, 0);
+                       encoder_call(zr, video, s_routing, &route);
                }
        }
 
@@ -1356,14 +1029,7 @@ zoran_close(struct file  *file)
        kfree(fh->overlay_mask);
        kfree(fh);
 
-       /* release locks on the i2c modules */
-       module_put(zr->decoder->driver->driver.owner);
-       if (zr->encoder)
-               module_put(zr->encoder->driver->driver.owner);
-
-       /*mutex_unlock(&zr->resource_lock);*/
-
-       dprintk(4, KERN_INFO "%s: zoran_close() done\n", ZR_DEVNAME(zr));
+       dprintk(4, KERN_INFO "%s: %s done\n", ZR_DEVNAME(zr), __func__);
 
        return 0;
 }
@@ -1391,15 +1057,13 @@ zoran_write (struct file *file,
        return -EINVAL;
 }
 
-static int
-setup_fbuffer (struct file               *file,
+static int setup_fbuffer(struct zoran_fh *fh,
               void                      *base,
               const struct zoran_format *fmt,
               int                        width,
               int                        height,
               int                        bytesperline)
 {
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
 
        /* (Ronald) v4l/v4l2 guidelines */
@@ -1427,8 +1091,8 @@ setup_fbuffer (struct file               *file,
                 * friendly and silently do as if nothing went wrong */
                dprintk(3,
                        KERN_ERR
-                       "%s: setup_fbuffer() - forced overlay turnoff because framebuffer changed\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - forced overlay turnoff because framebuffer changed\n",
+                       ZR_DEVNAME(zr), __func__);
                zr36057_overlay(zr, 0);
        }
 #endif
@@ -1436,31 +1100,31 @@ setup_fbuffer (struct file               *file,
        if (!(fmt->flags & ZORAN_FORMAT_OVERLAY)) {
                dprintk(1,
                        KERN_ERR
-                       "%s: setup_fbuffer() - no valid overlay format given\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - no valid overlay format given\n",
+                       ZR_DEVNAME(zr), __func__);
                return -EINVAL;
        }
        if (height <= 0 || width <= 0 || bytesperline <= 0) {
                dprintk(1,
                        KERN_ERR
-                       "%s: setup_fbuffer() - invalid height/width/bpl value (%d|%d|%d)\n",
-                       ZR_DEVNAME(zr), width, height, bytesperline);
+                       "%s: %s - invalid height/width/bpl value (%d|%d|%d)\n",
+                       ZR_DEVNAME(zr), __func__, width, height, bytesperline);
                return -EINVAL;
        }
        if (bytesperline & 3) {
                dprintk(1,
                        KERN_ERR
-                       "%s: setup_fbuffer() - bytesperline (%d) must be 4-byte aligned\n",
-                       ZR_DEVNAME(zr), bytesperline);
+                       "%s: %s - bytesperline (%d) must be 4-byte aligned\n",
+                       ZR_DEVNAME(zr), __func__, bytesperline);
                return -EINVAL;
        }
 
-       zr->buffer.base = (void *) ((unsigned long) base & ~3);
-       zr->buffer.height = height;
-       zr->buffer.width = width;
-       zr->buffer.depth = fmt->depth;
+       zr->vbuf_base = (void *) ((unsigned long) base & ~3);
+       zr->vbuf_height = height;
+       zr->vbuf_width = width;
+       zr->vbuf_depth = fmt->depth;
        zr->overlay_settings.format = fmt;
-       zr->buffer.bytesperline = bytesperline;
+       zr->vbuf_bytesperline = bytesperline;
 
        /* The user should set new window parameters */
        zr->overlay_settings.is_set = 0;
@@ -1469,35 +1133,27 @@ setup_fbuffer (struct file               *file,
 }
 
 
-static int
-setup_window (struct file       *file,
-             int                x,
-             int                y,
-             int                width,
-             int                height,
-             struct video_clip __user *clips,
-             int                clipcount,
-             void              __user *bitmap)
+static int setup_window(struct zoran_fh *fh, int x, int y, int width, int height,
+       struct v4l2_clip __user *clips, int clipcount, void __user *bitmap)
 {
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
-       struct video_clip *vcp = NULL;
+       struct v4l2_clip *vcp = NULL;
        int on, end;
 
 
-       if (!zr->buffer.base) {
+       if (!zr->vbuf_base) {
                dprintk(1,
                        KERN_ERR
-                       "%s: setup_window() - frame buffer has to be set first\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - frame buffer has to be set first\n",
+                       ZR_DEVNAME(zr), __func__);
                return -EINVAL;
        }
 
        if (!fh->overlay_settings.format) {
                dprintk(1,
                        KERN_ERR
-                       "%s: setup_window() - no overlay format set\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - no overlay format set\n",
+                       ZR_DEVNAME(zr), __func__);
                return -EINVAL;
        }
 
@@ -1505,13 +1161,13 @@ setup_window (struct file       *file,
         * The video front end needs 4-byte alinged line sizes, we correct that
         * silently here if necessary
         */
-       if (zr->buffer.depth == 15 || zr->buffer.depth == 16) {
+       if (zr->vbuf_depth == 15 || zr->vbuf_depth == 16) {
                end = (x + width) & ~1; /* round down */
                x = (x + 1) & ~1;       /* round up */
                width = end - x;
        }
 
-       if (zr->buffer.depth == 24) {
+       if (zr->vbuf_depth == 24) {
                end = (x + width) & ~3; /* round down */
                x = (x + 3) & ~3;       /* round up */
                width = end - x;
@@ -1527,8 +1183,8 @@ setup_window (struct file       *file,
            width > BUZ_MAX_WIDTH || height > BUZ_MAX_HEIGHT) {
                dprintk(1,
                        KERN_ERR
-                       "%s: setup_window() - width = %d or height = %d invalid\n",
-                       ZR_DEVNAME(zr), width, height);
+                       "%s: %s - width = %d or height = %d invalid\n",
+                       ZR_DEVNAME(zr), __func__, width, height);
                return -EINVAL;
        }
 
@@ -1566,20 +1222,20 @@ setup_window (struct file       *file,
                }
        } else if (clipcount > 0) {
                /* write our own bitmap from the clips */
-               vcp = vmalloc(sizeof(struct video_clip) * (clipcount + 4));
+               vcp = vmalloc(sizeof(struct v4l2_clip) * (clipcount + 4));
                if (vcp == NULL) {
                        dprintk(1,
                                KERN_ERR
-                               "%s: setup_window() - Alloc of clip mask failed\n",
-                               ZR_DEVNAME(zr));
+                               "%s: %s - Alloc of clip mask failed\n",
+                               ZR_DEVNAME(zr), __func__);
                        return -ENOMEM;
                }
                if (copy_from_user
-                   (vcp, clips, sizeof(struct video_clip) * clipcount)) {
+                   (vcp, clips, sizeof(struct v4l2_clip) * clipcount)) {
                        vfree(vcp);
                        return -EFAULT;
                }
-               write_overlay_mask(file, vcp, clipcount);
+               write_overlay_mask(fh, vcp, clipcount);
                vfree(vcp);
        }
 
@@ -1595,11 +1251,8 @@ setup_window (struct file       *file,
        return wait_grab_pending(zr);
 }
 
-static int
-setup_overlay (struct file *file,
-              int          on)
+static int setup_overlay(struct zoran_fh *fh, int on)
 {
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
 
        /* If there is nothing to do, return immediatly */
@@ -1612,16 +1265,16 @@ setup_overlay (struct file *file,
            fh->overlay_active == ZORAN_FREE) {
                dprintk(1,
                        KERN_ERR
-                       "%s: setup_overlay() - overlay is already active for another session\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - overlay is already active for another session\n",
+                       ZR_DEVNAME(zr), __func__);
                return -EBUSY;
        }
        if (!on && zr->overlay_active != ZORAN_FREE &&
            fh->overlay_active == ZORAN_FREE) {
                dprintk(1,
                        KERN_ERR
-                       "%s: setup_overlay() - you cannot cancel someone else's session\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - you cannot cancel someone else's session\n",
+                       ZR_DEVNAME(zr), __func__);
                return -EPERM;
        }
 
@@ -1634,18 +1287,18 @@ setup_overlay (struct file *file,
                        zr36057_overlay(zr, 0);
                zr->overlay_mask = NULL;
        } else {
-               if (!zr->buffer.base || !fh->overlay_settings.is_set) {
+               if (!zr->vbuf_base || !fh->overlay_settings.is_set) {
                        dprintk(1,
                                KERN_ERR
-                               "%s: setup_overlay() - buffer or window not set\n",
-                               ZR_DEVNAME(zr));
+                               "%s: %s - buffer or window not set\n",
+                               ZR_DEVNAME(zr), __func__);
                        return -EINVAL;
                }
                if (!fh->overlay_settings.format) {
                        dprintk(1,
                                KERN_ERR
-                               "%s: setup_overlay() - no overlay format set\n",
-                               ZR_DEVNAME(zr));
+                               "%s: %s - no overlay format set\n",
+                               ZR_DEVNAME(zr), __func__);
                        return -EINVAL;
                }
                zr->overlay_active = fh->overlay_active = ZORAN_LOCKED;
@@ -1662,41 +1315,47 @@ setup_overlay (struct file *file,
        return wait_grab_pending(zr);
 }
 
-       /* get the status of a buffer in the clients buffer queue */
-static int
-zoran_v4l2_buffer_status (struct file        *file,
-                         struct v4l2_buffer *buf,
-                         int                 num)
+/* get the status of a buffer in the clients buffer queue */
+static int zoran_v4l2_buffer_status(struct zoran_fh *fh,
+                                   struct v4l2_buffer *buf, int num)
 {
-       struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
+       unsigned long flags;
 
        buf->flags = V4L2_BUF_FLAG_MAPPED;
 
        switch (fh->map_mode) {
        case ZORAN_MAP_MODE_RAW:
-
                /* check range */
-               if (num < 0 || num >= fh->v4l_buffers.num_buffers ||
-                   !fh->v4l_buffers.allocated) {
+               if (num < 0 || num >= fh->buffers.num_buffers ||
+                   !fh->buffers.allocated) {
                        dprintk(1,
                                KERN_ERR
-                               "%s: v4l2_buffer_status() - wrong number or buffers not allocated\n",
-                               ZR_DEVNAME(zr));
+                               "%s: %s - wrong number or buffers not allocated\n",
+                               ZR_DEVNAME(zr), __func__);
                        return -EINVAL;
                }
 
+               spin_lock_irqsave(&zr->spinlock, flags);
+               dprintk(3,
+                       KERN_DEBUG
+                       "%s: %s() - raw active=%c, buffer %d: state=%c, map=%c\n",
+                       ZR_DEVNAME(zr), __func__,
+                       "FAL"[fh->buffers.active], num,
+                       "UPMD"[zr->v4l_buffers.buffer[num].state],
+                       fh->buffers.buffer[num].map ? 'Y' : 'N');
+               spin_unlock_irqrestore(&zr->spinlock, flags);
+
                buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               buf->length = fh->v4l_buffers.buffer_size;
+               buf->length = fh->buffers.buffer_size;
 
                /* get buffer */
-               buf->bytesused = fh->v4l_buffers.buffer[num].bs.length;
-               if (fh->v4l_buffers.buffer[num].state == BUZ_STATE_DONE ||
-                   fh->v4l_buffers.buffer[num].state == BUZ_STATE_USER) {
-                       buf->sequence = fh->v4l_buffers.buffer[num].bs.seq;
+               buf->bytesused = fh->buffers.buffer[num].bs.length;
+               if (fh->buffers.buffer[num].state == BUZ_STATE_DONE ||
+                   fh->buffers.buffer[num].state == BUZ_STATE_USER) {
+                       buf->sequence = fh->buffers.buffer[num].bs.seq;
                        buf->flags |= V4L2_BUF_FLAG_DONE;
-                       buf->timestamp =
-                           fh->v4l_buffers.buffer[num].bs.timestamp;
+                       buf->timestamp = fh->buffers.buffer[num].bs.timestamp;
                } else {
                        buf->flags |= V4L2_BUF_FLAG_QUEUED;
                }
@@ -1712,28 +1371,26 @@ zoran_v4l2_buffer_status (struct file        *file,
        case ZORAN_MAP_MODE_JPG_PLAY:
 
                /* check range */
-               if (num < 0 || num >= fh->jpg_buffers.num_buffers ||
-                   !fh->jpg_buffers.allocated) {
+               if (num < 0 || num >= fh->buffers.num_buffers ||
+                   !fh->buffers.allocated) {
                        dprintk(1,
                                KERN_ERR
-                               "%s: v4l2_buffer_status() - wrong number or buffers not allocated\n",
-                               ZR_DEVNAME(zr));
+                               "%s: %s - wrong number or buffers not allocated\n",
+                               ZR_DEVNAME(zr), __func__);
                        return -EINVAL;
                }
 
                buf->type = (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ?
                              V4L2_BUF_TYPE_VIDEO_CAPTURE :
                              V4L2_BUF_TYPE_VIDEO_OUTPUT;
-               buf->length = fh->jpg_buffers.buffer_size;
+               buf->length = fh->buffers.buffer_size;
 
                /* these variables are only written after frame has been captured */
-               if (fh->jpg_buffers.buffer[num].state == BUZ_STATE_DONE ||
-                   fh->jpg_buffers.buffer[num].state == BUZ_STATE_USER) {
-                       buf->sequence = fh->jpg_buffers.buffer[num].bs.seq;
-                       buf->timestamp =
-                           fh->jpg_buffers.buffer[num].bs.timestamp;
-                       buf->bytesused =
-                           fh->jpg_buffers.buffer[num].bs.length;
+               if (fh->buffers.buffer[num].state == BUZ_STATE_DONE ||
+                   fh->buffers.buffer[num].state == BUZ_STATE_USER) {
+                       buf->sequence = fh->buffers.buffer[num].bs.seq;
+                       buf->timestamp = fh->buffers.buffer[num].bs.timestamp;
+                       buf->bytesused = fh->buffers.buffer[num].bs.length;
                        buf->flags |= V4L2_BUF_FLAG_DONE;
                } else {
                        buf->flags |= V4L2_BUF_FLAG_QUEUED;
@@ -1741,14 +1398,11 @@ zoran_v4l2_buffer_status (struct file        *file,
 
                /* which fields are these? */
                if (fh->jpg_settings.TmpDcm != 1)
-                       buf->field =
-                           fh->jpg_settings.
-                           odd_even ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM;
+                       buf->field = fh->jpg_settings.odd_even ?
+                               V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM;
                else
-                       buf->field =
-                           fh->jpg_settings.
-                           odd_even ? V4L2_FIELD_SEQ_TB :
-                           V4L2_FIELD_SEQ_BT;
+                       buf->field = fh->jpg_settings.odd_even ?
+                               V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT;
 
                break;
 
@@ -1756,8 +1410,8 @@ zoran_v4l2_buffer_status (struct file        *file,
 
                dprintk(5,
                        KERN_ERR
-                       "%s: v4l2_buffer_status() - invalid buffer type|map_mode (%d|%d)\n",
-                       ZR_DEVNAME(zr), buf->type, fh->map_mode);
+                       "%s: %s - invalid buffer type|map_mode (%d|%d)\n",
+                       ZR_DEVNAME(zr), __func__, buf->type, fh->map_mode);
                return -EINVAL;
        }
 
@@ -1770,81 +1424,55 @@ zoran_v4l2_buffer_status (struct file        *file,
 
 static int
 zoran_set_norm (struct zoran *zr,
-               int           norm) /* VIDEO_MODE_* */
+               v4l2_std_id norm)
 {
-       int norm_encoder, on;
+       int on;
 
        if (zr->v4l_buffers.active != ZORAN_FREE ||
            zr->jpg_buffers.active != ZORAN_FREE) {
                dprintk(1,
                        KERN_WARNING
-                       "%s: set_norm() called while in playback/capture mode\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s called while in playback/capture mode\n",
+                       ZR_DEVNAME(zr), __func__);
                return -EBUSY;
        }
 
-       if (lock_norm && norm != zr->norm) {
-               if (lock_norm > 1) {
-                       dprintk(1,
-                               KERN_WARNING
-                               "%s: set_norm() - TV standard is locked, can not switch norm\n",
-                               ZR_DEVNAME(zr));
-                       return -EPERM;
-               } else {
-                       dprintk(1,
-                               KERN_WARNING
-                               "%s: set_norm() - TV standard is locked, norm was not changed\n",
-                               ZR_DEVNAME(zr));
-                       norm = zr->norm;
-               }
-       }
-
-       if (norm != VIDEO_MODE_AUTO &&
-           (norm < 0 || norm >= zr->card.norms ||
-            !zr->card.tvn[norm])) {
+       if (!(norm & zr->card.norms)) {
                dprintk(1,
-                       KERN_ERR "%s: set_norm() - unsupported norm %d\n",
-                       ZR_DEVNAME(zr), norm);
+                       KERN_ERR "%s: %s - unsupported norm %llx\n",
+                       ZR_DEVNAME(zr), __func__, norm);
                return -EINVAL;
        }
 
-       if (norm == VIDEO_MODE_AUTO) {
-               int status;
-
-               /* if we have autodetect, ... */
-               struct video_decoder_capability caps;
-               decoder_command(zr, DECODER_GET_CAPABILITIES, &caps);
-               if (!(caps.flags & VIDEO_DECODER_AUTO)) {
-                       dprintk(1, KERN_ERR "%s: norm=auto unsupported\n",
-                               ZR_DEVNAME(zr));
-                       return -EINVAL;
-               }
+       if (norm == V4L2_STD_ALL) {
+               int status = 0;
+               v4l2_std_id std = 0;
 
-               decoder_command(zr, DECODER_SET_NORM, &norm);
+               decoder_call(zr, video, querystd, &std);
+               decoder_call(zr, tuner, s_std, std);
 
                /* let changes come into effect */
                ssleep(2);
 
-               decoder_command(zr, DECODER_GET_STATUS, &status);
-               if (!(status & DECODER_STATUS_GOOD)) {
+               decoder_call(zr, video, g_input_status, &status);
+               if (status & V4L2_IN_ST_NO_SIGNAL) {
                        dprintk(1,
                                KERN_ERR
-                               "%s: set_norm() - no norm detected\n",
-                               ZR_DEVNAME(zr));
+                               "%s: %s - no norm detected\n",
+                               ZR_DEVNAME(zr), __func__);
                        /* reset norm */
-                       decoder_command(zr, DECODER_SET_NORM, &zr->norm);
+                       decoder_call(zr, tuner, s_std, zr->norm);
                        return -EIO;
                }
 
-               if (status & DECODER_STATUS_NTSC)
-                       norm = VIDEO_MODE_NTSC;
-               else if (status & DECODER_STATUS_SECAM)
-                       norm = VIDEO_MODE_SECAM;
-               else
-                       norm = VIDEO_MODE_PAL;
+               norm = std;
        }
-       zr->timing = zr->card.tvn[norm];
-       norm_encoder = norm;
+       if (norm & V4L2_STD_SECAM)
+               zr->timing = zr->card.tvn[2];
+       else if (norm & V4L2_STD_NTSC)
+               zr->timing = zr->card.tvn[1];
+       else
+               zr->timing = zr->card.tvn[0];
 
        /* We switch overlay off and on since a change in the
         * norm needs different VFE settings */
@@ -1852,8 +1480,8 @@ zoran_set_norm (struct zoran *zr,
        if (on)
                zr36057_overlay(zr, 0);
 
-       decoder_command(zr, DECODER_SET_NORM, &norm);
-       encoder_command(zr, ENCODER_SET_NORM, &norm_encoder);
+       decoder_call(zr, tuner, s_std, norm);
+       encoder_call(zr, video, s_std_output, norm);
 
        if (on)
                zr36057_overlay(zr, 1);
@@ -1868,7 +1496,7 @@ static int
 zoran_set_input (struct zoran *zr,
                 int           input)
 {
-       int realinput;
+       struct v4l2_routing route = { 0, 0 };
 
        if (input == zr->input) {
                return 0;
@@ -1878,23 +1506,23 @@ zoran_set_input (struct zoran *zr,
            zr->jpg_buffers.active != ZORAN_FREE) {
                dprintk(1,
                        KERN_WARNING
-                       "%s: set_input() called while in playback/capture mode\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s called while in playback/capture mode\n",
+                       ZR_DEVNAME(zr), __func__);
                return -EBUSY;
        }
 
        if (input < 0 || input >= zr->card.inputs) {
                dprintk(1,
                        KERN_ERR
-                       "%s: set_input() - unnsupported input %d\n",
-                       ZR_DEVNAME(zr), input);
+                       "%s: %s - unnsupported input %d\n",
+                       ZR_DEVNAME(zr), __func__, input);
                return -EINVAL;
        }
 
-       realinput = zr->card.input[input].muxsel;
+       route.input = zr->card.input[input].muxsel;
        zr->input = input;
 
-       decoder_command(zr, DECODER_SET_INPUT, &realinput);
+       decoder_call(zr, video, s_routing, &route);
 
        return 0;
 }
@@ -1903,435 +1531,45 @@ zoran_set_input (struct zoran *zr,
  *   ioctl routine
  */
 
-static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static long zoran_default(struct file *file, void *__fh, int cmd, void *arg)
 {
-       struct zoran_fh *fh = file->private_data;
+       struct zoran_fh *fh = __fh;
        struct zoran *zr = fh->zr;
-       /* CAREFUL: used in multiple places here */
        struct zoran_jpg_settings settings;
 
-       /* we might have older buffers lying around... We don't want
-        * to wait, but we do want to try cleaning them up ASAP. So
-        * we try to obtain the lock and free them. If that fails, we
-        * don't do anything and wait for the next turn. In the end,
-        * zoran_close() or a new allocation will still free them...
-        * This is just a 'the sooner the better' extra 'feature'
-        *
-        * We don't free the buffers right on munmap() because that
-        * causes oopses (kfree() inside munmap() oopses for no
-        * apparent reason - it's also not reproduceable in any way,
-        * but moving the free code outside the munmap() handler fixes
-        * all this... If someone knows why, please explain me (Ronald)
-        */
-       if (mutex_trylock(&zr->resource_lock)) {
-               /* we obtained it! Let's try to free some things */
-               if (fh->jpg_buffers.ready_to_be_freed)
-                       jpg_fbuffer_free(file);
-               if (fh->v4l_buffers.ready_to_be_freed)
-                       v4l_fbuffer_free(file);
-
-               mutex_unlock(&zr->resource_lock);
-       }
-
        switch (cmd) {
-
-       case VIDIOCGCAP:
+       case BUZIOC_G_PARAMS:
        {
-               struct video_capability *vcap = arg;
+               struct zoran_params *bparams = arg;
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOCGCAP\n", ZR_DEVNAME(zr));
+               dprintk(3, KERN_DEBUG "%s: BUZIOC_G_PARAMS\n", ZR_DEVNAME(zr));
 
-               memset(vcap, 0, sizeof(struct video_capability));
-               strncpy(vcap->name, ZR_DEVNAME(zr), sizeof(vcap->name)-1);
-               vcap->type = ZORAN_VID_TYPE;
+               memset(bparams, 0, sizeof(struct zoran_params));
+               bparams->major_version = MAJOR_VERSION;
+               bparams->minor_version = MINOR_VERSION;
 
-               vcap->channels = zr->card.inputs;
-               vcap->audios = 0;
                mutex_lock(&zr->resource_lock);
-               vcap->maxwidth = BUZ_MAX_WIDTH;
-               vcap->maxheight = BUZ_MAX_HEIGHT;
-               vcap->minwidth = BUZ_MIN_WIDTH;
-               vcap->minheight = BUZ_MIN_HEIGHT;
-               mutex_unlock(&zr->resource_lock);
 
-               return 0;
-       }
-               break;
+               if (zr->norm & V4L2_STD_NTSC)
+                       bparams->norm = VIDEO_MODE_NTSC;
+               else if (zr->norm & V4L2_STD_PAL)
+                       bparams->norm = VIDEO_MODE_PAL;
+               else
+                       bparams->norm = VIDEO_MODE_SECAM;
 
-       case VIDIOCGCHAN:
-       {
-               struct video_channel *vchan = arg;
-               int channel = vchan->channel;
+               bparams->input = zr->input;
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOCGCHAN - channel=%d\n",
-                       ZR_DEVNAME(zr), vchan->channel);
-
-               memset(vchan, 0, sizeof(struct video_channel));
-               if (channel > zr->card.inputs || channel < 0) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOCGCHAN on not existing channel %d\n",
-                               ZR_DEVNAME(zr), channel);
-                       return -EINVAL;
-               }
-
-               strcpy(vchan->name, zr->card.input[channel].name);
-
-               vchan->tuners = 0;
-               vchan->flags = 0;
-               vchan->type = VIDEO_TYPE_CAMERA;
-               mutex_lock(&zr->resource_lock);
-               vchan->norm = zr->norm;
-               mutex_unlock(&zr->resource_lock);
-               vchan->channel = channel;
-
-               return 0;
-       }
-               break;
-
-               /* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says:
-                *
-                * * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input."
-                * *                                 ^^^^^^^
-                * * The famos BTTV driver has it implemented with a struct video_channel argument
-                * * and we follow it for compatibility reasons
-                * *
-                * * BTW: this is the only way the user can set the norm!
-                */
-
-       case VIDIOCSCHAN:
-       {
-               struct video_channel *vchan = arg;
-               int res;
-
-               dprintk(3,
-                       KERN_DEBUG
-                       "%s: VIDIOCSCHAN - channel=%d, norm=%d\n",
-                       ZR_DEVNAME(zr), vchan->channel, vchan->norm);
-
-               mutex_lock(&zr->resource_lock);
-               if ((res = zoran_set_input(zr, vchan->channel)))
-                       goto schan_unlock_and_return;
-               if ((res = zoran_set_norm(zr, vchan->norm)))
-                       goto schan_unlock_and_return;
-
-               /* Make sure the changes come into effect */
-               res = wait_grab_pending(zr);
-       schan_unlock_and_return:
-               mutex_unlock(&zr->resource_lock);
-               return res;
-       }
-               break;
-
-       case VIDIOCGPICT:
-       {
-               struct video_picture *vpict = arg;
-
-               dprintk(3, KERN_DEBUG "%s: VIDIOCGPICT\n", ZR_DEVNAME(zr));
-
-               memset(vpict, 0, sizeof(struct video_picture));
-               mutex_lock(&zr->resource_lock);
-               vpict->hue = zr->hue;
-               vpict->brightness = zr->brightness;
-               vpict->contrast = zr->contrast;
-               vpict->colour = zr->saturation;
-               if (fh->overlay_settings.format) {
-                       vpict->depth = fh->overlay_settings.format->depth;
-                       vpict->palette = fh->overlay_settings.format->palette;
-               } else {
-                       vpict->depth = 0;
-               }
-               mutex_unlock(&zr->resource_lock);
-
-               return 0;
-       }
-               break;
-
-       case VIDIOCSPICT:
-       {
-               struct video_picture *vpict = arg;
-               int i;
-
-               dprintk(3,
-                       KERN_DEBUG
-                       "%s: VIDIOCSPICT - bri=%d, hue=%d, col=%d, con=%d, dep=%d, pal=%d\n",
-                       ZR_DEVNAME(zr), vpict->brightness, vpict->hue,
-                       vpict->colour, vpict->contrast, vpict->depth,
-                       vpict->palette);
-
-               for (i = 0; i < NUM_FORMATS; i++) {
-                       const struct zoran_format *fmt = &zoran_formats[i];
-
-                       if (fmt->palette != -1 &&
-                           fmt->flags & ZORAN_FORMAT_OVERLAY &&
-                           fmt->palette == vpict->palette &&
-                           fmt->depth == vpict->depth)
-                               break;
-               }
-               if (i == NUM_FORMATS) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOCSPICT - Invalid palette %d\n",
-                               ZR_DEVNAME(zr), vpict->palette);
-                       return -EINVAL;
-               }
-
-               mutex_lock(&zr->resource_lock);
-
-               decoder_command(zr, DECODER_SET_PICTURE, vpict);
-
-               zr->hue = vpict->hue;
-               zr->contrast = vpict->contrast;
-               zr->saturation = vpict->colour;
-               zr->brightness = vpict->brightness;
-
-               fh->overlay_settings.format = &zoran_formats[i];
-
-               mutex_unlock(&zr->resource_lock);
-
-               return 0;
-       }
-               break;
-
-       case VIDIOCCAPTURE:
-       {
-               int *on = arg, res;
-
-               dprintk(3, KERN_DEBUG "%s: VIDIOCCAPTURE - on=%d\n",
-                       ZR_DEVNAME(zr), *on);
-
-               mutex_lock(&zr->resource_lock);
-               res = setup_overlay(file, *on);
-               mutex_unlock(&zr->resource_lock);
-
-               return res;
-       }
-               break;
-
-       case VIDIOCGWIN:
-       {
-               struct video_window *vwin = arg;
-
-               dprintk(3, KERN_DEBUG "%s: VIDIOCGWIN\n", ZR_DEVNAME(zr));
-
-               memset(vwin, 0, sizeof(struct video_window));
-               mutex_lock(&zr->resource_lock);
-               vwin->x = fh->overlay_settings.x;
-               vwin->y = fh->overlay_settings.y;
-               vwin->width = fh->overlay_settings.width;
-               vwin->height = fh->overlay_settings.height;
-               mutex_unlock(&zr->resource_lock);
-               vwin->clipcount = 0;
-               return 0;
-       }
-               break;
-
-       case VIDIOCSWIN:
-       {
-               struct video_window *vwin = arg;
-               int res;
-
-               dprintk(3,
-                       KERN_DEBUG
-                       "%s: VIDIOCSWIN - x=%d, y=%d, w=%d, h=%d, clipcount=%d\n",
-                       ZR_DEVNAME(zr), vwin->x, vwin->y, vwin->width,
-                       vwin->height, vwin->clipcount);
-
-               mutex_lock(&zr->resource_lock);
-               res =
-                   setup_window(file, vwin->x, vwin->y, vwin->width,
-                                vwin->height, vwin->clips,
-                                vwin->clipcount, NULL);
-               mutex_unlock(&zr->resource_lock);
-
-               return res;
-       }
-               break;
-
-       case VIDIOCGFBUF:
-       {
-               struct video_buffer *vbuf = arg;
-
-               dprintk(3, KERN_DEBUG "%s: VIDIOCGFBUF\n", ZR_DEVNAME(zr));
-
-               mutex_lock(&zr->resource_lock);
-               *vbuf = zr->buffer;
-               mutex_unlock(&zr->resource_lock);
-               return 0;
-       }
-               break;
-
-       case VIDIOCSFBUF:
-       {
-               struct video_buffer *vbuf = arg;
-               int i, res = 0;
-
-               dprintk(3,
-                       KERN_DEBUG
-                       "%s: VIDIOCSFBUF - base=%p, w=%d, h=%d, depth=%d, bpl=%d\n",
-                       ZR_DEVNAME(zr), vbuf->base, vbuf->width,
-                       vbuf->height, vbuf->depth, vbuf->bytesperline);
-
-               for (i = 0; i < NUM_FORMATS; i++)
-                       if (zoran_formats[i].depth == vbuf->depth)
-                               break;
-               if (i == NUM_FORMATS) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOCSFBUF - invalid fbuf depth %d\n",
-                               ZR_DEVNAME(zr), vbuf->depth);
-                       return -EINVAL;
-               }
-
-               mutex_lock(&zr->resource_lock);
-               res =
-                   setup_fbuffer(file, vbuf->base, &zoran_formats[i],
-                                 vbuf->width, vbuf->height,
-                                 vbuf->bytesperline);
-               mutex_unlock(&zr->resource_lock);
-
-               return res;
-       }
-               break;
-
-       case VIDIOCSYNC:
-       {
-               int *frame = arg, res;
-
-               dprintk(3, KERN_DEBUG "%s: VIDIOCSYNC - frame=%d\n",
-                       ZR_DEVNAME(zr), *frame);
-
-               mutex_lock(&zr->resource_lock);
-               res = v4l_sync(file, *frame);
-               mutex_unlock(&zr->resource_lock);
-               if (!res)
-                       zr->v4l_sync_tail++;
-               return res;
-       }
-               break;
-
-       case VIDIOCMCAPTURE:
-       {
-               struct video_mmap *vmap = arg;
-               int res;
-
-               dprintk(3,
-                       KERN_DEBUG
-                       "%s: VIDIOCMCAPTURE - frame=%d, geom=%dx%d, fmt=%d\n",
-                       ZR_DEVNAME(zr), vmap->frame, vmap->width, vmap->height,
-                       vmap->format);
-
-               mutex_lock(&zr->resource_lock);
-               res = v4l_grab(file, vmap);
-               mutex_unlock(&zr->resource_lock);
-               return res;
-       }
-               break;
-
-       case VIDIOCGMBUF:
-       {
-               struct video_mbuf *vmbuf = arg;
-               int i, res = 0;
-
-               dprintk(3, KERN_DEBUG "%s: VIDIOCGMBUF\n", ZR_DEVNAME(zr));
-
-               vmbuf->size =
-                   fh->v4l_buffers.num_buffers *
-                   fh->v4l_buffers.buffer_size;
-               vmbuf->frames = fh->v4l_buffers.num_buffers;
-               for (i = 0; i < vmbuf->frames; i++) {
-                       vmbuf->offsets[i] =
-                           i * fh->v4l_buffers.buffer_size;
-               }
-
-               mutex_lock(&zr->resource_lock);
-
-               if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOCGMBUF - buffers already allocated\n",
-                               ZR_DEVNAME(zr));
-                       res = -EINVAL;
-                       goto v4l1reqbuf_unlock_and_return;
-               }
-
-               if (v4l_fbuffer_alloc(file)) {
-                       res = -ENOMEM;
-                       goto v4l1reqbuf_unlock_and_return;
-               }
-
-               /* The next mmap will map the V4L buffers */
-               fh->map_mode = ZORAN_MAP_MODE_RAW;
-       v4l1reqbuf_unlock_and_return:
-               mutex_unlock(&zr->resource_lock);
-
-               return res;
-       }
-               break;
-
-       case VIDIOCGUNIT:
-       {
-               struct video_unit *vunit = arg;
-
-               dprintk(3, KERN_DEBUG "%s: VIDIOCGUNIT\n", ZR_DEVNAME(zr));
-
-               vunit->video = zr->video_dev->minor;
-               vunit->vbi = VIDEO_NO_UNIT;
-               vunit->radio = VIDEO_NO_UNIT;
-               vunit->audio = VIDEO_NO_UNIT;
-               vunit->teletext = VIDEO_NO_UNIT;
-
-               return 0;
-       }
-               break;
-
-               /*
-                * RJ: In principal we could support subcaptures for V4L grabbing.
-                *     Not even the famous BTTV driver has them, however.
-                *     If there should be a strong demand, one could consider
-                *     to implement them.
-                */
-       case VIDIOCGCAPTURE:
-       {
-               dprintk(3, KERN_ERR "%s: VIDIOCGCAPTURE not supported\n",
-                       ZR_DEVNAME(zr));
-               return -EINVAL;
-       }
-               break;
-
-       case VIDIOCSCAPTURE:
-       {
-               dprintk(3, KERN_ERR "%s: VIDIOCSCAPTURE not supported\n",
-                       ZR_DEVNAME(zr));
-               return -EINVAL;
-       }
-               break;
-
-       case BUZIOC_G_PARAMS:
-       {
-               struct zoran_params *bparams = arg;
-
-               dprintk(3, KERN_DEBUG "%s: BUZIOC_G_PARAMS\n", ZR_DEVNAME(zr));
-
-               memset(bparams, 0, sizeof(struct zoran_params));
-               bparams->major_version = MAJOR_VERSION;
-               bparams->minor_version = MINOR_VERSION;
-
-               mutex_lock(&zr->resource_lock);
-
-               bparams->norm = zr->norm;
-               bparams->input = zr->input;
-
-               bparams->decimation = fh->jpg_settings.decimation;
-               bparams->HorDcm = fh->jpg_settings.HorDcm;
-               bparams->VerDcm = fh->jpg_settings.VerDcm;
-               bparams->TmpDcm = fh->jpg_settings.TmpDcm;
-               bparams->field_per_buff = fh->jpg_settings.field_per_buff;
-               bparams->img_x = fh->jpg_settings.img_x;
-               bparams->img_y = fh->jpg_settings.img_y;
-               bparams->img_width = fh->jpg_settings.img_width;
-               bparams->img_height = fh->jpg_settings.img_height;
-               bparams->odd_even = fh->jpg_settings.odd_even;
+               bparams->decimation = fh->jpg_settings.decimation;
+               bparams->HorDcm = fh->jpg_settings.HorDcm;
+               bparams->VerDcm = fh->jpg_settings.VerDcm;
+               bparams->TmpDcm = fh->jpg_settings.TmpDcm;
+               bparams->field_per_buff = fh->jpg_settings.field_per_buff;
+               bparams->img_x = fh->jpg_settings.img_x;
+               bparams->img_y = fh->jpg_settings.img_y;
+               bparams->img_width = fh->jpg_settings.img_width;
+               bparams->img_height = fh->jpg_settings.img_height;
+               bparams->odd_even = fh->jpg_settings.odd_even;
 
                bparams->quality = fh->jpg_settings.jpg_comp.quality;
                bparams->APPn = fh->jpg_settings.jpg_comp.APPn;
@@ -2352,7 +1590,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
                return 0;
        }
-               break;
 
        case BUZIOC_S_PARAMS:
        {
@@ -2395,18 +1632,17 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
                /* Check the params first before overwriting our
                 * nternal values */
-               if (zoran_check_jpg_settings(zr, &settings)) {
+               if (zoran_check_jpg_settings(zr, &settings, 0)) {
                        res = -EINVAL;
                        goto sparams_unlock_and_return;
                }
 
                fh->jpg_settings = settings;
-       sparams_unlock_and_return:
+sparams_unlock_and_return:
                mutex_unlock(&zr->resource_lock);
 
                return res;
        }
-               break;
 
        case BUZIOC_REQBUFS:
        {
@@ -2430,38 +1666,34 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                 * tables to a Maximum of 2 MB */
                if (breq->size > jpg_bufsize)
                        breq->size = jpg_bufsize;
-               if (fh->jpg_buffers.need_contiguous &&
-                   breq->size > MAX_KMALLOC_MEM)
-                       breq->size = MAX_KMALLOC_MEM;
 
                mutex_lock(&zr->resource_lock);
 
-               if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
+               if (fh->buffers.allocated) {
                        dprintk(1,
                                KERN_ERR
-                               "%s: BUZIOC_REQBUFS - buffers allready allocated\n",
+                               "%s: BUZIOC_REQBUFS - buffers already allocated\n",
                                ZR_DEVNAME(zr));
                        res = -EBUSY;
                        goto jpgreqbuf_unlock_and_return;
                }
 
-               fh->jpg_buffers.num_buffers = breq->count;
-               fh->jpg_buffers.buffer_size = breq->size;
+               /* The next mmap will map the MJPEG buffers - could
+                * also be *_PLAY, but it doesn't matter here */
+               map_mode_jpg(fh, 0);
+               fh->buffers.num_buffers = breq->count;
+               fh->buffers.buffer_size = breq->size;
 
-               if (jpg_fbuffer_alloc(file)) {
+               if (jpg_fbuffer_alloc(fh)) {
                        res = -ENOMEM;
                        goto jpgreqbuf_unlock_and_return;
                }
 
-               /* The next mmap will map the MJPEG buffers - could
-                * also be *_PLAY, but it doesn't matter here */
-               fh->map_mode = ZORAN_MAP_MODE_JPG_REC;
-       jpgreqbuf_unlock_and_return:
+jpgreqbuf_unlock_and_return:
                mutex_unlock(&zr->resource_lock);
 
                return res;
        }
-               break;
 
        case BUZIOC_QBUF_CAPT:
        {
@@ -2471,12 +1703,11 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                        ZR_DEVNAME(zr), *frame);
 
                mutex_lock(&zr->resource_lock);
-               res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_COMPRESS);
+               res = jpg_qbuf(fh, *frame, BUZ_MODE_MOTION_COMPRESS);
                mutex_unlock(&zr->resource_lock);
 
                return res;
        }
-               break;
 
        case BUZIOC_QBUF_PLAY:
        {
@@ -2486,12 +1717,11 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                        ZR_DEVNAME(zr), *frame);
 
                mutex_lock(&zr->resource_lock);
-               res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_DECOMPRESS);
+               res = jpg_qbuf(fh, *frame, BUZ_MODE_MOTION_DECOMPRESS);
                mutex_unlock(&zr->resource_lock);
 
                return res;
        }
-               break;
 
        case BUZIOC_SYNC:
        {
@@ -2501,17 +1731,26 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                dprintk(3, KERN_DEBUG "%s: BUZIOC_SYNC\n", ZR_DEVNAME(zr));
 
                mutex_lock(&zr->resource_lock);
-               res = jpg_sync(file, bsync);
+
+               if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
+                       dprintk(2, KERN_WARNING
+                               "%s: %s - not in jpg capture mode\n",
+                               ZR_DEVNAME(zr), __func__);
+                       res = -EINVAL;
+               } else {
+                       res = jpg_sync(fh, bsync);
+               }
                mutex_unlock(&zr->resource_lock);
 
                return res;
        }
-               break;
 
        case BUZIOC_G_STATUS:
        {
                struct zoran_status *bstat = arg;
-               int norm, input, status, res = 0;
+               struct v4l2_routing route = { 0, 0 };
+               int status = 0, res = 0;
+               v4l2_std_id norm;
 
                dprintk(3, KERN_DEBUG "%s: BUZIOC_G_STATUS\n", ZR_DEVNAME(zr));
 
@@ -2523,8 +1762,7 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                        return -EINVAL;
                }
 
-               input = zr->card.input[bstat->input].muxsel;
-               norm = VIDEO_MODE_AUTO;
+               route.input = zr->card.input[bstat->input].muxsel;
 
                mutex_lock(&zr->resource_lock);
 
@@ -2537,1629 +1775,1262 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                        goto gstat_unlock_and_return;
                }
 
-               decoder_command(zr, DECODER_SET_INPUT, &input);
-               decoder_command(zr, DECODER_SET_NORM, &norm);
+               decoder_call(zr, video, s_routing, &route);
 
                /* sleep 1 second */
                ssleep(1);
 
                /* Get status of video decoder */
-               decoder_command(zr, DECODER_GET_STATUS, &status);
+               decoder_call(zr, video, querystd, &norm);
+               decoder_call(zr, video, g_input_status, &status);
 
                /* restore previous input and norm */
-               input = zr->card.input[zr->input].muxsel;
-               decoder_command(zr, DECODER_SET_INPUT, &input);
-               decoder_command(zr, DECODER_SET_NORM, &zr->norm);
-       gstat_unlock_and_return:
+               route.input = zr->card.input[zr->input].muxsel;
+               decoder_call(zr, video, s_routing, &route);
+gstat_unlock_and_return:
                mutex_unlock(&zr->resource_lock);
 
                if (!res) {
                        bstat->signal =
-                           (status & DECODER_STATUS_GOOD) ? 1 : 0;
-                       if (status & DECODER_STATUS_NTSC)
+                           (status & V4L2_IN_ST_NO_SIGNAL) ? 0 : 1;
+                       if (norm & V4L2_STD_NTSC)
                                bstat->norm = VIDEO_MODE_NTSC;
-                       else if (status & DECODER_STATUS_SECAM)
+                       else if (norm & V4L2_STD_SECAM)
                                bstat->norm = VIDEO_MODE_SECAM;
                        else
                                bstat->norm = VIDEO_MODE_PAL;
 
                        bstat->color =
-                           (status & DECODER_STATUS_COLOR) ? 1 : 0;
+                           (status & V4L2_IN_ST_NO_COLOR) ? 0 : 1;
                }
 
                return res;
        }
-               break;
 
-               /* The new video4linux2 capture interface - much nicer than video4linux1, since
-                * it allows for integrating the JPEG capturing calls inside standard v4l2
-                */
+       default:
+               return -EINVAL;
+       }
+}
 
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *cap = arg;
+static int zoran_vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *vmbuf)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int i, res = 0;
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCAP\n", ZR_DEVNAME(zr));
 
-               memset(cap, 0, sizeof(*cap));
-               strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1);
-               strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
-               snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
-                        pci_name(zr->pci_dev));
-               cap->version =
-                   KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION,
-                                  RELEASE_VERSION);
-               cap->capabilities = ZORAN_V4L2_VID_FLAGS;
+       mutex_lock(&zr->resource_lock);
 
-               return 0;
+       if (fh->buffers.allocated) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: VIDIOCGMBUF - buffers already allocated\n",
+                       ZR_DEVNAME(zr));
+               res = -EINVAL;
+               goto v4l1reqbuf_unlock_and_return;
        }
-               break;
 
-       case VIDIOC_ENUM_FMT:
-       {
-               struct v4l2_fmtdesc *fmt = arg;
-               int index = fmt->index, num = -1, i, flag = 0, type =
-                   fmt->type;
+       /* The next mmap will map the V4L buffers */
+       map_mode_raw(fh);
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUM_FMT - index=%d\n",
-                       ZR_DEVNAME(zr), fmt->index);
+       if (v4l_fbuffer_alloc(fh)) {
+               res = -ENOMEM;
+               goto v4l1reqbuf_unlock_and_return;
+       }
 
-               switch (fmt->type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                       flag = ZORAN_FORMAT_CAPTURE;
-                       break;
-               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-                       flag = ZORAN_FORMAT_PLAYBACK;
-                       break;
-               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-                       flag = ZORAN_FORMAT_OVERLAY;
-                       break;
-               default:
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOC_ENUM_FMT - unknown type %d\n",
-                               ZR_DEVNAME(zr), fmt->type);
-                       return -EINVAL;
-               }
+       vmbuf->size = fh->buffers.num_buffers * fh->buffers.buffer_size;
+       vmbuf->frames = fh->buffers.num_buffers;
+       for (i = 0; i < vmbuf->frames; i++)
+               vmbuf->offsets[i] = i * fh->buffers.buffer_size;
 
-               for (i = 0; i < NUM_FORMATS; i++) {
-                       if (zoran_formats[i].flags & flag)
-                               num++;
-                       if (num == fmt->index)
-                               break;
-               }
-               if (fmt->index < 0 /* late, but not too late */  ||
-                   i == NUM_FORMATS)
-                       return -EINVAL;
+v4l1reqbuf_unlock_and_return:
+       mutex_unlock(&zr->resource_lock);
 
-               memset(fmt, 0, sizeof(*fmt));
-               fmt->index = index;
-               fmt->type = type;
-               strncpy(fmt->description, zoran_formats[i].name, sizeof(fmt->description)-1);
-               fmt->pixelformat = zoran_formats[i].fourcc;
-               if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
-                       fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
+       return res;
+}
+#endif
 
-               return 0;
-       }
-               break;
-
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format *fmt = arg;
-               int type = fmt->type;
-
-               dprintk(5, KERN_DEBUG "%s: VIDIOC_G_FMT\n", ZR_DEVNAME(zr));
-
-               memset(fmt, 0, sizeof(*fmt));
-               fmt->type = type;
-
-               switch (fmt->type) {
-               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-
-                       mutex_lock(&zr->resource_lock);
+static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability *cap)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
 
-                       fmt->fmt.win.w.left = fh->overlay_settings.x;
-                       fmt->fmt.win.w.top = fh->overlay_settings.y;
-                       fmt->fmt.win.w.width = fh->overlay_settings.width;
-                       fmt->fmt.win.w.height =
-                           fh->overlay_settings.height;
-                       if (fh->overlay_settings.width * 2 >
-                           BUZ_MAX_HEIGHT)
-                               fmt->fmt.win.field = V4L2_FIELD_INTERLACED;
-                       else
-                               fmt->fmt.win.field = V4L2_FIELD_TOP;
+       memset(cap, 0, sizeof(*cap));
+       strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1);
+       strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
+       snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
+                pci_name(zr->pci_dev));
+       cap->version = KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION,
+                          RELEASE_VERSION);
+       cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |
+                           V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OVERLAY;
+       return 0;
+}
 
-                       mutex_unlock(&zr->resource_lock);
+static int zoran_enum_fmt(struct zoran *zr, struct v4l2_fmtdesc *fmt, int flag)
+{
+       int num = -1, i;
 
+       for (i = 0; i < NUM_FORMATS; i++) {
+               if (zoran_formats[i].flags & flag)
+                       num++;
+               if (num == fmt->index)
                        break;
+       }
+       if (fmt->index < 0 /* late, but not too late */  || i == NUM_FORMATS)
+               return -EINVAL;
 
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-
-                       mutex_lock(&zr->resource_lock);
-
-                       if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-                           fh->map_mode == ZORAN_MAP_MODE_RAW) {
-
-                               fmt->fmt.pix.width =
-                                   fh->v4l_settings.width;
-                               fmt->fmt.pix.height =
-                                   fh->v4l_settings.height;
-                               fmt->fmt.pix.sizeimage =
-                                   fh->v4l_settings.bytesperline *
-                                   fh->v4l_settings.height;
-                               fmt->fmt.pix.pixelformat =
-                                   fh->v4l_settings.format->fourcc;
-                               fmt->fmt.pix.colorspace =
-                                   fh->v4l_settings.format->colorspace;
-                               fmt->fmt.pix.bytesperline =
-                                   fh->v4l_settings.bytesperline;
-                               if (BUZ_MAX_HEIGHT <
-                                   (fh->v4l_settings.height * 2))
-                                       fmt->fmt.pix.field =
-                                           V4L2_FIELD_INTERLACED;
-                               else
-                                       fmt->fmt.pix.field =
-                                           V4L2_FIELD_TOP;
-
-                       } else {
-
-                               fmt->fmt.pix.width =
-                                   fh->jpg_settings.img_width /
-                                   fh->jpg_settings.HorDcm;
-                               fmt->fmt.pix.height =
-                                   fh->jpg_settings.img_height /
-                                   (fh->jpg_settings.VerDcm *
-                                    fh->jpg_settings.TmpDcm);
-                               fmt->fmt.pix.sizeimage =
-                                   zoran_v4l2_calc_bufsize(&fh->
-                                                           jpg_settings);
-                               fmt->fmt.pix.pixelformat =
-                                   V4L2_PIX_FMT_MJPEG;
-                               if (fh->jpg_settings.TmpDcm == 1)
-                                       fmt->fmt.pix.field =
-                                           (fh->jpg_settings.
-                                            odd_even ? V4L2_FIELD_SEQ_BT :
-                                            V4L2_FIELD_SEQ_BT);
-                               else
-                                       fmt->fmt.pix.field =
-                                           (fh->jpg_settings.
-                                            odd_even ? V4L2_FIELD_TOP :
-                                            V4L2_FIELD_BOTTOM);
-
-                               fmt->fmt.pix.bytesperline = 0;
-                               fmt->fmt.pix.colorspace =
-                                   V4L2_COLORSPACE_SMPTE170M;
-                       }
-
-                       mutex_unlock(&zr->resource_lock);
+       strncpy(fmt->description, zoran_formats[i].name, sizeof(fmt->description)-1);
+       fmt->pixelformat = zoran_formats[i].fourcc;
+       if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
+               fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
+       return 0;
+}
 
-                       break;
+static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh,
+                                           struct v4l2_fmtdesc *f)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
 
-               default:
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOC_G_FMT - unsupported type %d\n",
-                               ZR_DEVNAME(zr), fmt->type);
-                       return -EINVAL;
-               }
-               return 0;
-       }
-               break;
+       return zoran_enum_fmt(zr, f, ZORAN_FORMAT_CAPTURE);
+}
 
-       case VIDIOC_S_FMT:
-       {
-               struct v4l2_format *fmt = arg;
-               int i, res = 0;
-               __le32 printformat;
-
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_S_FMT - type=%d, ",
-                       ZR_DEVNAME(zr), fmt->type);
-
-               switch (fmt->type) {
-               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-
-                       dprintk(3, "x=%d, y=%d, w=%d, h=%d, cnt=%d, map=0x%p\n",
-                               fmt->fmt.win.w.left, fmt->fmt.win.w.top,
-                               fmt->fmt.win.w.width,
-                               fmt->fmt.win.w.height,
-                               fmt->fmt.win.clipcount,
-                               fmt->fmt.win.bitmap);
-                       mutex_lock(&zr->resource_lock);
-                       res =
-                           setup_window(file, fmt->fmt.win.w.left,
-                                        fmt->fmt.win.w.top,
-                                        fmt->fmt.win.w.width,
-                                        fmt->fmt.win.w.height,
-                                        (struct video_clip __user *)
-                                          fmt->fmt.win.clips,
-                                        fmt->fmt.win.clipcount,
-                                        fmt->fmt.win.bitmap);
-                       mutex_unlock(&zr->resource_lock);
-                       return res;
-                       break;
+static int zoran_enum_fmt_vid_out(struct file *file, void *__fh,
+                                           struct v4l2_fmtdesc *f)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
 
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-
-                       printformat =
-                           __cpu_to_le32(fmt->fmt.pix.pixelformat);
-                       dprintk(3, "size=%dx%d, fmt=0x%x (%4.4s)\n",
-                               fmt->fmt.pix.width, fmt->fmt.pix.height,
-                               fmt->fmt.pix.pixelformat,
-                               (char *) &printformat);
-
-                       /* we can be requested to do JPEG/raw playback/capture */
-                       if (!
-                           (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                            (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-                             fmt->fmt.pix.pixelformat ==
-                             V4L2_PIX_FMT_MJPEG))) {
-                               dprintk(1,
-                                       KERN_ERR
-                                       "%s: VIDIOC_S_FMT - unknown type %d/0x%x(%4.4s) combination\n",
-                                       ZR_DEVNAME(zr), fmt->type,
-                                       fmt->fmt.pix.pixelformat,
-                                       (char *) &printformat);
-                               return -EINVAL;
-                       }
+       return zoran_enum_fmt(zr, f, ZORAN_FORMAT_PLAYBACK);
+}
 
-                       if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
-                               mutex_lock(&zr->resource_lock);
+static int zoran_enum_fmt_vid_overlay(struct file *file, void *__fh,
+                                           struct v4l2_fmtdesc *f)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
 
-                               settings = fh->jpg_settings;
+       return zoran_enum_fmt(zr, f, ZORAN_FORMAT_OVERLAY);
+}
 
-                               if (fh->v4l_buffers.allocated ||
-                                   fh->jpg_buffers.allocated) {
-                                       dprintk(1,
-                                               KERN_ERR
-                                               "%s: VIDIOC_S_FMT - cannot change capture mode\n",
-                                               ZR_DEVNAME(zr));
-                                       res = -EBUSY;
-                                       goto sfmtjpg_unlock_and_return;
-                               }
+static int zoran_g_fmt_vid_out(struct file *file, void *__fh,
+                                       struct v4l2_format *fmt)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
 
-                               /* we actually need to set 'real' parameters now */
-                               if ((fmt->fmt.pix.height * 2) >
-                                   BUZ_MAX_HEIGHT)
-                                       settings.TmpDcm = 1;
-                               else
-                                       settings.TmpDcm = 2;
-                               settings.decimation = 0;
-                               if (fmt->fmt.pix.height <=
-                                   fh->jpg_settings.img_height / 2)
-                                       settings.VerDcm = 2;
-                               else
-                                       settings.VerDcm = 1;
-                               if (fmt->fmt.pix.width <=
-                                   fh->jpg_settings.img_width / 4)
-                                       settings.HorDcm = 4;
-                               else if (fmt->fmt.pix.width <=
-                                        fh->jpg_settings.img_width / 2)
-                                       settings.HorDcm = 2;
-                               else
-                                       settings.HorDcm = 1;
-                               if (settings.TmpDcm == 1)
-                                       settings.field_per_buff = 2;
-                               else
-                                       settings.field_per_buff = 1;
-
-                               /* check */
-                               if ((res =
-                                    zoran_check_jpg_settings(zr,
-                                                             &settings)))
-                                       goto sfmtjpg_unlock_and_return;
-
-                               /* it's ok, so set them */
-                               fh->jpg_settings = settings;
-
-                               /* tell the user what we actually did */
-                               fmt->fmt.pix.width =
-                                   settings.img_width / settings.HorDcm;
-                               fmt->fmt.pix.height =
-                                   settings.img_height * 2 /
-                                   (settings.TmpDcm * settings.VerDcm);
-                               if (settings.TmpDcm == 1)
-                                       fmt->fmt.pix.field =
-                                           (fh->jpg_settings.
-                                            odd_even ? V4L2_FIELD_SEQ_TB :
-                                            V4L2_FIELD_SEQ_BT);
-                               else
-                                       fmt->fmt.pix.field =
-                                           (fh->jpg_settings.
-                                            odd_even ? V4L2_FIELD_TOP :
-                                            V4L2_FIELD_BOTTOM);
-                               fh->jpg_buffers.buffer_size =
-                                   zoran_v4l2_calc_bufsize(&fh->
-                                                           jpg_settings);
-                               fmt->fmt.pix.bytesperline = 0;
-                               fmt->fmt.pix.sizeimage =
-                                   fh->jpg_buffers.buffer_size;
-                               fmt->fmt.pix.colorspace =
-                                   V4L2_COLORSPACE_SMPTE170M;
-
-                               /* we hereby abuse this variable to show that
-                                * we're gonna do mjpeg capture */
-                               fh->map_mode =
-                                   (fmt->type ==
-                                    V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
-                                   ZORAN_MAP_MODE_JPG_REC :
-                                   ZORAN_MAP_MODE_JPG_PLAY;
-                       sfmtjpg_unlock_and_return:
-                               mutex_unlock(&zr->resource_lock);
-                       } else {
-                               for (i = 0; i < NUM_FORMATS; i++)
-                                       if (fmt->fmt.pix.pixelformat ==
-                                           zoran_formats[i].fourcc)
-                                               break;
-                               if (i == NUM_FORMATS) {
-                                       dprintk(1,
-                                               KERN_ERR
-                                               "%s: VIDIOC_S_FMT - unknown/unsupported format 0x%x (%4.4s)\n",
-                                               ZR_DEVNAME(zr),
-                                               fmt->fmt.pix.pixelformat,
-                                               (char *) &printformat);
-                                       return -EINVAL;
-                               }
-                               mutex_lock(&zr->resource_lock);
-                               if (fh->jpg_buffers.allocated ||
-                                   (fh->v4l_buffers.allocated &&
-                                    fh->v4l_buffers.active !=
-                                    ZORAN_FREE)) {
-                                       dprintk(1,
-                                               KERN_ERR
-                                               "%s: VIDIOC_S_FMT - cannot change capture mode\n",
-                                               ZR_DEVNAME(zr));
-                                       res = -EBUSY;
-                                       goto sfmtv4l_unlock_and_return;
-                               }
-                               if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
-                                       fmt->fmt.pix.height =
-                                           BUZ_MAX_HEIGHT;
-                               if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
-                                       fmt->fmt.pix.width = BUZ_MAX_WIDTH;
-
-                               if ((res =
-                                    zoran_v4l_set_format(file,
-                                                         fmt->fmt.pix.
-                                                         width,
-                                                         fmt->fmt.pix.
-                                                         height,
-                                                         &zoran_formats
-                                                         [i])))
-                                       goto sfmtv4l_unlock_and_return;
-
-                               /* tell the user the
-                                * results/missing stuff */
-                               fmt->fmt.pix.bytesperline =
-                                       fh->v4l_settings.bytesperline;
-                               fmt->fmt.pix.sizeimage =
-                                       fh->v4l_settings.height *
-                                       fh->v4l_settings.bytesperline;
-                               fmt->fmt.pix.colorspace =
-                                       fh->v4l_settings.format->colorspace;
-                               if (BUZ_MAX_HEIGHT <
-                                   (fh->v4l_settings.height * 2))
-                                       fmt->fmt.pix.field =
-                                           V4L2_FIELD_INTERLACED;
-                               else
-                                       fmt->fmt.pix.field =
-                                           V4L2_FIELD_TOP;
-
-                               fh->map_mode = ZORAN_MAP_MODE_RAW;
-                       sfmtv4l_unlock_and_return:
-                               mutex_unlock(&zr->resource_lock);
-                       }
+       mutex_lock(&zr->resource_lock);
 
-                       break;
+       fmt->fmt.pix.width = fh->jpg_settings.img_width / fh->jpg_settings.HorDcm;
+       fmt->fmt.pix.height = fh->jpg_settings.img_height * 2 /
+               (fh->jpg_settings.VerDcm * fh->jpg_settings.TmpDcm);
+       fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&fh->jpg_settings);
+       fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
+       if (fh->jpg_settings.TmpDcm == 1)
+               fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
+                               V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT);
+       else
+               fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
+                               V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
+       fmt->fmt.pix.bytesperline = 0;
+       fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 
-               default:
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOC_S_FMT - unsupported type %d\n",
-                               ZR_DEVNAME(zr), fmt->type);
-                       return -EINVAL;
-               }
+       mutex_unlock(&zr->resource_lock);
+       return 0;
+}
 
-               return res;
-       }
-               break;
+static int zoran_g_fmt_vid_cap(struct file *file, void *__fh,
+                                       struct v4l2_format *fmt)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
 
-       case VIDIOC_G_FBUF:
-       {
-               struct v4l2_framebuffer *fb = arg;
+       if (fh->map_mode != ZORAN_MAP_MODE_RAW)
+               return zoran_g_fmt_vid_out(file, fh, fmt);
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_G_FBUF\n", ZR_DEVNAME(zr));
+       mutex_lock(&zr->resource_lock);
+       fmt->fmt.pix.width = fh->v4l_settings.width;
+       fmt->fmt.pix.height = fh->v4l_settings.height;
+       fmt->fmt.pix.sizeimage = fh->v4l_settings.bytesperline *
+                                       fh->v4l_settings.height;
+       fmt->fmt.pix.pixelformat = fh->v4l_settings.format->fourcc;
+       fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace;
+       fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline;
+       if (BUZ_MAX_HEIGHT < (fh->v4l_settings.height * 2))
+               fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
+       else
+               fmt->fmt.pix.field = V4L2_FIELD_TOP;
+       mutex_unlock(&zr->resource_lock);
+       return 0;
+}
 
-               memset(fb, 0, sizeof(*fb));
-               mutex_lock(&zr->resource_lock);
-               fb->base = zr->buffer.base;
-               fb->fmt.width = zr->buffer.width;
-               fb->fmt.height = zr->buffer.height;
-               if (zr->overlay_settings.format) {
-                       fb->fmt.pixelformat =
-                               fh->overlay_settings.format->fourcc;
-               }
-               fb->fmt.bytesperline = zr->buffer.bytesperline;
-               mutex_unlock(&zr->resource_lock);
-               fb->fmt.colorspace = V4L2_COLORSPACE_SRGB;
-               fb->fmt.field = V4L2_FIELD_INTERLACED;
-               fb->flags = V4L2_FBUF_FLAG_OVERLAY;
-               fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+static int zoran_g_fmt_vid_overlay(struct file *file, void *__fh,
+                                       struct v4l2_format *fmt)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
 
-               return 0;
-       }
-               break;
+       mutex_lock(&zr->resource_lock);
 
-       case VIDIOC_S_FBUF:
-       {
-               int i, res = 0;
-               struct v4l2_framebuffer *fb = arg;
-               __le32 printformat = __cpu_to_le32(fb->fmt.pixelformat);
+       fmt->fmt.win.w.left = fh->overlay_settings.x;
+       fmt->fmt.win.w.top = fh->overlay_settings.y;
+       fmt->fmt.win.w.width = fh->overlay_settings.width;
+       fmt->fmt.win.w.height = fh->overlay_settings.height;
+       if (fh->overlay_settings.width * 2 > BUZ_MAX_HEIGHT)
+               fmt->fmt.win.field = V4L2_FIELD_INTERLACED;
+       else
+               fmt->fmt.win.field = V4L2_FIELD_TOP;
 
-               dprintk(3,
-                       KERN_DEBUG
-                       "%s: VIDIOC_S_FBUF - base=0x%p, size=%dx%d, bpl=%d, fmt=0x%x (%4.4s)\n",
-                       ZR_DEVNAME(zr), fb->base, fb->fmt.width, fb->fmt.height,
-                       fb->fmt.bytesperline, fb->fmt.pixelformat,
-                       (char *) &printformat);
+       mutex_unlock(&zr->resource_lock);
+       return 0;
+}
 
-               for (i = 0; i < NUM_FORMATS; i++)
-                       if (zoran_formats[i].fourcc == fb->fmt.pixelformat)
-                               break;
-               if (i == NUM_FORMATS) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOC_S_FBUF - format=0x%x (%4.4s) not allowed\n",
-                               ZR_DEVNAME(zr), fb->fmt.pixelformat,
-                               (char *) &printformat);
-                       return -EINVAL;
-               }
+static int zoran_try_fmt_vid_overlay(struct file *file, void *__fh,
+                                       struct v4l2_format *fmt)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
 
-               mutex_lock(&zr->resource_lock);
-               res =
-                   setup_fbuffer(file, fb->base, &zoran_formats[i],
-                                 fb->fmt.width, fb->fmt.height,
-                                 fb->fmt.bytesperline);
-               mutex_unlock(&zr->resource_lock);
+       mutex_lock(&zr->resource_lock);
 
-               return res;
-       }
-               break;
+       if (fmt->fmt.win.w.width > BUZ_MAX_WIDTH)
+               fmt->fmt.win.w.width = BUZ_MAX_WIDTH;
+       if (fmt->fmt.win.w.width < BUZ_MIN_WIDTH)
+               fmt->fmt.win.w.width = BUZ_MIN_WIDTH;
+       if (fmt->fmt.win.w.height > BUZ_MAX_HEIGHT)
+               fmt->fmt.win.w.height = BUZ_MAX_HEIGHT;
+       if (fmt->fmt.win.w.height < BUZ_MIN_HEIGHT)
+               fmt->fmt.win.w.height = BUZ_MIN_HEIGHT;
 
-       case VIDIOC_OVERLAY:
-       {
-               int *on = arg, res;
+       mutex_unlock(&zr->resource_lock);
+       return 0;
+}
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_PREVIEW - on=%d\n",
-                       ZR_DEVNAME(zr), *on);
+static int zoran_try_fmt_vid_out(struct file *file, void *__fh,
+                                       struct v4l2_format *fmt)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       struct zoran_jpg_settings settings;
+       int res = 0;
 
-               mutex_lock(&zr->resource_lock);
-               res = setup_overlay(file, *on);
-               mutex_unlock(&zr->resource_lock);
+       if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
+               return -EINVAL;
 
-               return res;
-       }
-               break;
+       mutex_lock(&zr->resource_lock);
+       settings = fh->jpg_settings;
 
-       case VIDIOC_REQBUFS:
-       {
-               struct v4l2_requestbuffers *req = arg;
-               int res = 0;
+       /* we actually need to set 'real' parameters now */
+       if ((fmt->fmt.pix.height * 2) > BUZ_MAX_HEIGHT)
+               settings.TmpDcm = 1;
+       else
+               settings.TmpDcm = 2;
+       settings.decimation = 0;
+       if (fmt->fmt.pix.height <= fh->jpg_settings.img_height / 2)
+               settings.VerDcm = 2;
+       else
+               settings.VerDcm = 1;
+       if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 4)
+               settings.HorDcm = 4;
+       else if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 2)
+               settings.HorDcm = 2;
+       else
+               settings.HorDcm = 1;
+       if (settings.TmpDcm == 1)
+               settings.field_per_buff = 2;
+       else
+               settings.field_per_buff = 1;
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_REQBUFS - type=%d\n",
-                       ZR_DEVNAME(zr), req->type);
+       if (settings.HorDcm > 1) {
+               settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
+               settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
+       } else {
+               settings.img_x = 0;
+               settings.img_width = BUZ_MAX_WIDTH;
+       }
+
+       /* check */
+       res = zoran_check_jpg_settings(zr, &settings, 1);
+       if (res)
+               goto tryfmt_unlock_and_return;
+
+       /* tell the user what we actually did */
+       fmt->fmt.pix.width = settings.img_width / settings.HorDcm;
+       fmt->fmt.pix.height = settings.img_height * 2 /
+               (settings.TmpDcm * settings.VerDcm);
+       if (settings.TmpDcm == 1)
+               fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
+                               V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT);
+       else
+               fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
+                               V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
 
-               if (req->memory != V4L2_MEMORY_MMAP) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: only MEMORY_MMAP capture is supported, not %d\n",
-                               ZR_DEVNAME(zr), req->memory);
-                       return -EINVAL;
-               }
+       fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&settings);
+       fmt->fmt.pix.bytesperline = 0;
+       fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+tryfmt_unlock_and_return:
+       mutex_unlock(&zr->resource_lock);
+       return res;
+}
 
-               mutex_lock(&zr->resource_lock);
+static int zoran_try_fmt_vid_cap(struct file *file, void *__fh,
+                                       struct v4l2_format *fmt)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int bpp;
+       int i;
 
-               if (fh->v4l_buffers.allocated || fh->jpg_buffers.allocated) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOC_REQBUFS - buffers allready allocated\n",
-                               ZR_DEVNAME(zr));
-                       res = -EBUSY;
-                       goto v4l2reqbuf_unlock_and_return;
-               }
+       if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
+               return zoran_try_fmt_vid_out(file, fh, fmt);
 
-               if (fh->map_mode == ZORAN_MAP_MODE_RAW &&
-                   req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+       mutex_lock(&zr->resource_lock);
 
-                       /* control user input */
-                       if (req->count < 2)
-                               req->count = 2;
-                       if (req->count > v4l_nbufs)
-                               req->count = v4l_nbufs;
-                       fh->v4l_buffers.num_buffers = req->count;
+       for (i = 0; i < NUM_FORMATS; i++)
+               if (zoran_formats[i].fourcc == fmt->fmt.pix.pixelformat)
+                       break;
 
-                       if (v4l_fbuffer_alloc(file)) {
-                               res = -ENOMEM;
-                               goto v4l2reqbuf_unlock_and_return;
-                       }
+       if (i == NUM_FORMATS) {
+               mutex_unlock(&zr->resource_lock);
+               return -EINVAL;
+       }
 
-                       /* The next mmap will map the V4L buffers */
-                       fh->map_mode = ZORAN_MAP_MODE_RAW;
+       bpp = (zoran_formats[i].depth + 7) / 8;
+       fmt->fmt.pix.width &= ~((bpp == 2) ? 1 : 3);
+       if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
+               fmt->fmt.pix.width = BUZ_MAX_WIDTH;
+       if (fmt->fmt.pix.width < BUZ_MIN_WIDTH)
+               fmt->fmt.pix.width = BUZ_MIN_WIDTH;
+       if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
+               fmt->fmt.pix.height = BUZ_MAX_HEIGHT;
+       if (fmt->fmt.pix.height < BUZ_MIN_HEIGHT)
+               fmt->fmt.pix.height = BUZ_MIN_HEIGHT;
+       mutex_unlock(&zr->resource_lock);
 
-               } else if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC ||
-                          fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
+       return 0;
+}
 
-                       /* we need to calculate size ourselves now */
-                       if (req->count < 4)
-                               req->count = 4;
-                       if (req->count > jpg_nbufs)
-                               req->count = jpg_nbufs;
-                       fh->jpg_buffers.num_buffers = req->count;
-                       fh->jpg_buffers.buffer_size =
-                           zoran_v4l2_calc_bufsize(&fh->jpg_settings);
+static int zoran_s_fmt_vid_overlay(struct file *file, void *__fh,
+                                       struct v4l2_format *fmt)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int res;
+
+       dprintk(3, "x=%d, y=%d, w=%d, h=%d, cnt=%d, map=0x%p\n",
+                       fmt->fmt.win.w.left, fmt->fmt.win.w.top,
+                       fmt->fmt.win.w.width,
+                       fmt->fmt.win.w.height,
+                       fmt->fmt.win.clipcount,
+                       fmt->fmt.win.bitmap);
+       mutex_lock(&zr->resource_lock);
+       res = setup_window(fh, fmt->fmt.win.w.left, fmt->fmt.win.w.top,
+                          fmt->fmt.win.w.width, fmt->fmt.win.w.height,
+                          (struct v4l2_clip __user *)fmt->fmt.win.clips,
+                          fmt->fmt.win.clipcount, fmt->fmt.win.bitmap);
+       mutex_unlock(&zr->resource_lock);
+       return res;
+}
 
-                       if (jpg_fbuffer_alloc(file)) {
-                               res = -ENOMEM;
-                               goto v4l2reqbuf_unlock_and_return;
-                       }
+static int zoran_s_fmt_vid_out(struct file *file, void *__fh,
+                                       struct v4l2_format *fmt)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       __le32 printformat = __cpu_to_le32(fmt->fmt.pix.pixelformat);
+       struct zoran_jpg_settings settings;
+       int res = 0;
 
-                       /* The next mmap will map the MJPEG buffers */
-                       if (req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                               fh->map_mode = ZORAN_MAP_MODE_JPG_REC;
-                       else
-                               fh->map_mode = ZORAN_MAP_MODE_JPG_PLAY;
+       dprintk(3, "size=%dx%d, fmt=0x%x (%4.4s)\n",
+                       fmt->fmt.pix.width, fmt->fmt.pix.height,
+                       fmt->fmt.pix.pixelformat,
+                       (char *) &printformat);
+       if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
+               return -EINVAL;
 
-               } else {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOC_REQBUFS - unknown type %d\n",
-                               ZR_DEVNAME(zr), req->type);
-                       res = -EINVAL;
-                       goto v4l2reqbuf_unlock_and_return;
-               }
-       v4l2reqbuf_unlock_and_return:
-               mutex_unlock(&zr->resource_lock);
+       mutex_lock(&zr->resource_lock);
 
-               return 0;
+       if (fh->buffers.allocated) {
+               dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - cannot change capture mode\n",
+                       ZR_DEVNAME(zr));
+               res = -EBUSY;
+               goto sfmtjpg_unlock_and_return;
        }
-               break;
-
-       case VIDIOC_QUERYBUF:
-       {
-               struct v4l2_buffer *buf = arg;
-               __u32 type = buf->type;
-               int index = buf->index, res;
-
-               dprintk(3,
-                       KERN_DEBUG
-                       "%s: VIDIOC_QUERYBUF - index=%d, type=%d\n",
-                       ZR_DEVNAME(zr), buf->index, buf->type);
 
-               memset(buf, 0, sizeof(*buf));
-               buf->type = type;
-               buf->index = index;
+       settings = fh->jpg_settings;
 
-               mutex_lock(&zr->resource_lock);
-               res = zoran_v4l2_buffer_status(file, buf, buf->index);
-               mutex_unlock(&zr->resource_lock);
+       /* we actually need to set 'real' parameters now */
+       if (fmt->fmt.pix.height * 2 > BUZ_MAX_HEIGHT)
+               settings.TmpDcm = 1;
+       else
+               settings.TmpDcm = 2;
+       settings.decimation = 0;
+       if (fmt->fmt.pix.height <= fh->jpg_settings.img_height / 2)
+               settings.VerDcm = 2;
+       else
+               settings.VerDcm = 1;
+       if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 4)
+               settings.HorDcm = 4;
+       else if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 2)
+               settings.HorDcm = 2;
+       else
+               settings.HorDcm = 1;
+       if (settings.TmpDcm == 1)
+               settings.field_per_buff = 2;
+       else
+               settings.field_per_buff = 1;
 
-               return res;
+       if (settings.HorDcm > 1) {
+               settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
+               settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
+       } else {
+               settings.img_x = 0;
+               settings.img_width = BUZ_MAX_WIDTH;
        }
-               break;
 
-       case VIDIOC_QBUF:
-       {
-               struct v4l2_buffer *buf = arg;
-               int res = 0, codec_mode, buf_type;
+       /* check */
+       res = zoran_check_jpg_settings(zr, &settings, 0);
+       if (res)
+               goto sfmtjpg_unlock_and_return;
 
-               dprintk(3,
-                       KERN_DEBUG "%s: VIDIOC_QBUF - type=%d, index=%d\n",
-                       ZR_DEVNAME(zr), buf->type, buf->index);
+       /* it's ok, so set them */
+       fh->jpg_settings = settings;
 
-               mutex_lock(&zr->resource_lock);
+       map_mode_jpg(fh, fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       fh->buffers.buffer_size = zoran_v4l2_calc_bufsize(&fh->jpg_settings);
 
-               switch (fh->map_mode) {
-               case ZORAN_MAP_MODE_RAW:
-                       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                               dprintk(1,
-                                       KERN_ERR
-                                       "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
-                                       ZR_DEVNAME(zr), buf->type, fh->map_mode);
-                               res = -EINVAL;
-                               goto qbuf_unlock_and_return;
-                       }
+       /* tell the user what we actually did */
+       fmt->fmt.pix.width = settings.img_width / settings.HorDcm;
+       fmt->fmt.pix.height = settings.img_height * 2 /
+               (settings.TmpDcm * settings.VerDcm);
+       if (settings.TmpDcm == 1)
+               fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
+                               V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT);
+       else
+               fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
+                               V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
+       fmt->fmt.pix.bytesperline = 0;
+       fmt->fmt.pix.sizeimage = fh->buffers.buffer_size;
+       fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 
-                       res = zoran_v4l_queue_frame(file, buf->index);
-                       if (res)
-                               goto qbuf_unlock_and_return;
-                       if (!zr->v4l_memgrab_active &&
-                           fh->v4l_buffers.active == ZORAN_LOCKED)
-                               zr36057_set_memgrab(zr, 1);
-                       break;
+sfmtjpg_unlock_and_return:
+       mutex_unlock(&zr->resource_lock);
+       return res;
+}
 
-               case ZORAN_MAP_MODE_JPG_REC:
-               case ZORAN_MAP_MODE_JPG_PLAY:
-                       if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
-                               buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-                               codec_mode = BUZ_MODE_MOTION_DECOMPRESS;
-                       } else {
-                               buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                               codec_mode = BUZ_MODE_MOTION_COMPRESS;
-                       }
+static int zoran_s_fmt_vid_cap(struct file *file, void *__fh,
+                                       struct v4l2_format *fmt)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int i;
+       int res = 0;
 
-                       if (buf->type != buf_type) {
-                               dprintk(1,
-                                       KERN_ERR
-                                       "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
-                                       ZR_DEVNAME(zr), buf->type, fh->map_mode);
-                               res = -EINVAL;
-                               goto qbuf_unlock_and_return;
-                       }
+       if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
+               return zoran_s_fmt_vid_out(file, fh, fmt);
 
-                       res =
-                           zoran_jpg_queue_frame(file, buf->index,
-                                                 codec_mode);
-                       if (res != 0)
-                               goto qbuf_unlock_and_return;
-                       if (zr->codec_mode == BUZ_MODE_IDLE &&
-                           fh->jpg_buffers.active == ZORAN_LOCKED) {
-                               zr36057_enable_jpg(zr, codec_mode);
-                       }
+       for (i = 0; i < NUM_FORMATS; i++)
+               if (fmt->fmt.pix.pixelformat == zoran_formats[i].fourcc)
                        break;
-
-               default:
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOC_QBUF - unsupported type %d\n",
-                               ZR_DEVNAME(zr), buf->type);
-                       res = -EINVAL;
-                       goto qbuf_unlock_and_return;
-               }
-       qbuf_unlock_and_return:
-               mutex_unlock(&zr->resource_lock);
-
-               return res;
+       if (i == NUM_FORMATS) {
+               dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - unknown/unsupported format 0x%x\n",
+                       ZR_DEVNAME(zr), fmt->fmt.pix.pixelformat);
+               return -EINVAL;
        }
-               break;
-
-       case VIDIOC_DQBUF:
-       {
-               struct v4l2_buffer *buf = arg;
-               int res = 0, buf_type, num = -1;        /* compiler borks here (?) */
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_DQBUF - type=%d\n",
-                       ZR_DEVNAME(zr), buf->type);
-
-               mutex_lock(&zr->resource_lock);
+       mutex_lock(&zr->resource_lock);
 
-               switch (fh->map_mode) {
-               case ZORAN_MAP_MODE_RAW:
-                       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                               dprintk(1,
-                                       KERN_ERR
-                                       "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
-                                       ZR_DEVNAME(zr), buf->type, fh->map_mode);
-                               res = -EINVAL;
-                               goto dqbuf_unlock_and_return;
-                       }
+       if ((fh->map_mode != ZORAN_MAP_MODE_RAW && fh->buffers.allocated) ||
+           fh->buffers.active != ZORAN_FREE) {
+               dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - cannot change capture mode\n",
+                               ZR_DEVNAME(zr));
+               res = -EBUSY;
+               goto sfmtv4l_unlock_and_return;
+       }
+       if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
+               fmt->fmt.pix.height = BUZ_MAX_HEIGHT;
+       if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
+               fmt->fmt.pix.width = BUZ_MAX_WIDTH;
+
+       map_mode_raw(fh);
+
+       res = zoran_v4l_set_format(fh, fmt->fmt.pix.width, fmt->fmt.pix.height,
+                                  &zoran_formats[i]);
+       if (res)
+               goto sfmtv4l_unlock_and_return;
+
+       /* tell the user the results/missing stuff */
+       fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline;
+       fmt->fmt.pix.sizeimage = fh->v4l_settings.height * fh->v4l_settings.bytesperline;
+       fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace;
+       if (BUZ_MAX_HEIGHT < (fh->v4l_settings.height * 2))
+               fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
+       else
+               fmt->fmt.pix.field = V4L2_FIELD_TOP;
 
-                       num = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME];
-                       if (file->f_flags & O_NONBLOCK &&
-                           zr->v4l_buffers.buffer[num].state !=
-                           BUZ_STATE_DONE) {
-                               res = -EAGAIN;
-                               goto dqbuf_unlock_and_return;
-                       }
-                       res = v4l_sync(file, num);
-                       if (res)
-                               goto dqbuf_unlock_and_return;
-                       else
-                               zr->v4l_sync_tail++;
-                       res = zoran_v4l2_buffer_status(file, buf, num);
-                       break;
+sfmtv4l_unlock_and_return:
+       mutex_unlock(&zr->resource_lock);
+       return res;
+}
 
-               case ZORAN_MAP_MODE_JPG_REC:
-               case ZORAN_MAP_MODE_JPG_PLAY:
-               {
-                       struct zoran_sync bs;
+static int zoran_g_fbuf(struct file *file, void *__fh,
+               struct v4l2_framebuffer *fb)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
 
-                       if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY)
-                               buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-                       else
-                               buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       memset(fb, 0, sizeof(*fb));
+       mutex_lock(&zr->resource_lock);
+       fb->base = zr->vbuf_base;
+       fb->fmt.width = zr->vbuf_width;
+       fb->fmt.height = zr->vbuf_height;
+       if (zr->overlay_settings.format)
+               fb->fmt.pixelformat = fh->overlay_settings.format->fourcc;
+       fb->fmt.bytesperline = zr->vbuf_bytesperline;
+       mutex_unlock(&zr->resource_lock);
+       fb->fmt.colorspace = V4L2_COLORSPACE_SRGB;
+       fb->fmt.field = V4L2_FIELD_INTERLACED;
+       fb->flags = V4L2_FBUF_FLAG_OVERLAY;
+       fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
 
-                       if (buf->type != buf_type) {
-                               dprintk(1,
-                                       KERN_ERR
-                                       "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
-                                       ZR_DEVNAME(zr), buf->type, fh->map_mode);
-                               res = -EINVAL;
-                               goto dqbuf_unlock_and_return;
-                       }
+       return 0;
+}
 
-                       num =
-                           zr->jpg_pend[zr->
-                                        jpg_que_tail & BUZ_MASK_FRAME];
+static int zoran_s_fbuf(struct file *file, void *__fh,
+               struct v4l2_framebuffer *fb)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int i, res = 0;
+       __le32 printformat = __cpu_to_le32(fb->fmt.pixelformat);
 
-                       if (file->f_flags & O_NONBLOCK &&
-                           zr->jpg_buffers.buffer[num].state !=
-                           BUZ_STATE_DONE) {
-                               res = -EAGAIN;
-                               goto dqbuf_unlock_and_return;
-                       }
-                       res = jpg_sync(file, &bs);
-                       if (res)
-                               goto dqbuf_unlock_and_return;
-                       res =
-                           zoran_v4l2_buffer_status(file, buf, bs.frame);
+       for (i = 0; i < NUM_FORMATS; i++)
+               if (zoran_formats[i].fourcc == fb->fmt.pixelformat)
                        break;
-               }
-
-               default:
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOC_DQBUF - unsupported type %d\n",
-                               ZR_DEVNAME(zr), buf->type);
-                       res = -EINVAL;
-                       goto dqbuf_unlock_and_return;
-               }
-       dqbuf_unlock_and_return:
-               mutex_unlock(&zr->resource_lock);
-
-               return res;
+       if (i == NUM_FORMATS) {
+               dprintk(1, KERN_ERR "%s: VIDIOC_S_FBUF - format=0x%x (%4.4s) not allowed\n",
+                       ZR_DEVNAME(zr), fb->fmt.pixelformat,
+                       (char *)&printformat);
+               return -EINVAL;
        }
-               break;
-
-       case VIDIOC_STREAMON:
-       {
-               int res = 0;
-
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_STREAMON\n", ZR_DEVNAME(zr));
 
-               mutex_lock(&zr->resource_lock);
+       mutex_lock(&zr->resource_lock);
+       res = setup_fbuffer(fh, fb->base, &zoran_formats[i], fb->fmt.width,
+                           fb->fmt.height, fb->fmt.bytesperline);
+       mutex_unlock(&zr->resource_lock);
 
-               switch (fh->map_mode) {
-               case ZORAN_MAP_MODE_RAW:        /* raw capture */
-                       if (zr->v4l_buffers.active != ZORAN_ACTIVE ||
-                           fh->v4l_buffers.active != ZORAN_ACTIVE) {
-                               res = -EBUSY;
-                               goto strmon_unlock_and_return;
-                       }
+       return res;
+}
 
-                       zr->v4l_buffers.active = fh->v4l_buffers.active =
-                           ZORAN_LOCKED;
-                       zr->v4l_settings = fh->v4l_settings;
+static int zoran_overlay(struct file *file, void *__fh, unsigned int on)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int res;
 
-                       zr->v4l_sync_tail = zr->v4l_pend_tail;
-                       if (!zr->v4l_memgrab_active &&
-                           zr->v4l_pend_head != zr->v4l_pend_tail) {
-                               zr36057_set_memgrab(zr, 1);
-                       }
-                       break;
+       mutex_lock(&zr->resource_lock);
+       res = setup_overlay(fh, on);
+       mutex_unlock(&zr->resource_lock);
 
-               case ZORAN_MAP_MODE_JPG_REC:
-               case ZORAN_MAP_MODE_JPG_PLAY:
-                       /* what is the codec mode right now? */
-                       if (zr->jpg_buffers.active != ZORAN_ACTIVE ||
-                           fh->jpg_buffers.active != ZORAN_ACTIVE) {
-                               res = -EBUSY;
-                               goto strmon_unlock_and_return;
-                       }
+       return res;
+}
 
-                       zr->jpg_buffers.active = fh->jpg_buffers.active =
-                           ZORAN_LOCKED;
+static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type);
 
-                       if (zr->jpg_que_head != zr->jpg_que_tail) {
-                               /* Start the jpeg codec when the first frame is queued  */
-                               jpeg_start(zr);
-                       }
+static int zoran_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *req)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int res = 0;
 
-                       break;
-               default:
-                       dprintk(1,
+       if (req->memory != V4L2_MEMORY_MMAP) {
+               dprintk(2,
                                KERN_ERR
-                               "%s: VIDIOC_STREAMON - invalid map mode %d\n",
-                               ZR_DEVNAME(zr), fh->map_mode);
-                       res = -EINVAL;
-                       goto strmon_unlock_and_return;
-               }
-       strmon_unlock_and_return:
-               mutex_unlock(&zr->resource_lock);
-
-               return res;
+                               "%s: only MEMORY_MMAP capture is supported, not %d\n",
+                               ZR_DEVNAME(zr), req->memory);
+               return -EINVAL;
        }
-               break;
 
-       case VIDIOC_STREAMOFF:
-       {
-               int i, res = 0;
-
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_STREAMOFF\n", ZR_DEVNAME(zr));
-
-               mutex_lock(&zr->resource_lock);
+       if (req->count == 0)
+               return zoran_streamoff(file, fh, req->type);
 
-               switch (fh->map_mode) {
-               case ZORAN_MAP_MODE_RAW:        /* raw capture */
-                       if (fh->v4l_buffers.active == ZORAN_FREE &&
-                           zr->v4l_buffers.active != ZORAN_FREE) {
-                               res = -EPERM;   /* stay off other's settings! */
-                               goto strmoff_unlock_and_return;
-                       }
-                       if (zr->v4l_buffers.active == ZORAN_FREE)
-                               goto strmoff_unlock_and_return;
+       mutex_lock(&zr->resource_lock);
+       if (fh->buffers.allocated) {
+               dprintk(2,
+                               KERN_ERR
+                               "%s: VIDIOC_REQBUFS - buffers already allocated\n",
+                               ZR_DEVNAME(zr));
+               res = -EBUSY;
+               goto v4l2reqbuf_unlock_and_return;
+       }
 
-                       /* unload capture */
-                       if (zr->v4l_memgrab_active) {
-                               unsigned long flags;
+       if (fh->map_mode == ZORAN_MAP_MODE_RAW &&
+           req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               /* control user input */
+               if (req->count < 2)
+                       req->count = 2;
+               if (req->count > v4l_nbufs)
+                       req->count = v4l_nbufs;
 
-                               spin_lock_irqsave(&zr->spinlock, flags);
-                               zr36057_set_memgrab(zr, 0);
-                               spin_unlock_irqrestore(&zr->spinlock, flags);
-                       }
+               /* The next mmap will map the V4L buffers */
+               map_mode_raw(fh);
+               fh->buffers.num_buffers = req->count;
 
-                       for (i = 0; i < fh->v4l_buffers.num_buffers; i++)
-                               zr->v4l_buffers.buffer[i].state =
-                                   BUZ_STATE_USER;
-                       fh->v4l_buffers = zr->v4l_buffers;
+               if (v4l_fbuffer_alloc(fh)) {
+                       res = -ENOMEM;
+                       goto v4l2reqbuf_unlock_and_return;
+               }
+       } else if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC ||
+                  fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
+               /* we need to calculate size ourselves now */
+               if (req->count < 4)
+                       req->count = 4;
+               if (req->count > jpg_nbufs)
+                       req->count = jpg_nbufs;
 
-                       zr->v4l_buffers.active = fh->v4l_buffers.active =
-                           ZORAN_FREE;
+               /* The next mmap will map the MJPEG buffers */
+               map_mode_jpg(fh, req->type == V4L2_BUF_TYPE_VIDEO_OUTPUT);
+               fh->buffers.num_buffers = req->count;
+               fh->buffers.buffer_size = zoran_v4l2_calc_bufsize(&fh->jpg_settings);
 
-                       zr->v4l_grab_seq = 0;
-                       zr->v4l_pend_head = zr->v4l_pend_tail = 0;
-                       zr->v4l_sync_tail = 0;
+               if (jpg_fbuffer_alloc(fh)) {
+                       res = -ENOMEM;
+                       goto v4l2reqbuf_unlock_and_return;
+               }
+       } else {
+               dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_REQBUFS - unknown type %d\n",
+                               ZR_DEVNAME(zr), req->type);
+               res = -EINVAL;
+               goto v4l2reqbuf_unlock_and_return;
+       }
+v4l2reqbuf_unlock_and_return:
+       mutex_unlock(&zr->resource_lock);
 
-                       break;
+       return res;
+}
 
-               case ZORAN_MAP_MODE_JPG_REC:
-               case ZORAN_MAP_MODE_JPG_PLAY:
-                       if (fh->jpg_buffers.active == ZORAN_FREE &&
-                           zr->jpg_buffers.active != ZORAN_FREE) {
-                               res = -EPERM;   /* stay off other's settings! */
-                               goto strmoff_unlock_and_return;
-                       }
-                       if (zr->jpg_buffers.active == ZORAN_FREE)
-                               goto strmoff_unlock_and_return;
-
-                       res =
-                           jpg_qbuf(file, -1,
-                                    (fh->map_mode ==
-                                     ZORAN_MAP_MODE_JPG_REC) ?
-                                    BUZ_MODE_MOTION_COMPRESS :
-                                    BUZ_MODE_MOTION_DECOMPRESS);
-                       if (res)
-                               goto strmoff_unlock_and_return;
-                       break;
-               default:
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOC_STREAMOFF - invalid map mode %d\n",
-                               ZR_DEVNAME(zr), fh->map_mode);
-                       res = -EINVAL;
-                       goto strmoff_unlock_and_return;
-               }
-       strmoff_unlock_and_return:
-               mutex_unlock(&zr->resource_lock);
+static int zoran_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int res;
 
-               return res;
-       }
-               break;
+       mutex_lock(&zr->resource_lock);
+       res = zoran_v4l2_buffer_status(fh, buf, buf->index);
+       mutex_unlock(&zr->resource_lock);
 
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *ctrl = arg;
+       return res;
+}
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCTRL - id=%d\n",
-                       ZR_DEVNAME(zr), ctrl->id);
+static int zoran_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int res = 0, codec_mode, buf_type;
 
-               /* we only support hue/saturation/contrast/brightness */
-               if (ctrl->id < V4L2_CID_BRIGHTNESS ||
-                   ctrl->id > V4L2_CID_HUE)
-                       return -EINVAL;
-               else {
-                       int id = ctrl->id;
-                       memset(ctrl, 0, sizeof(*ctrl));
-                       ctrl->id = id;
-               }
+       mutex_lock(&zr->resource_lock);
 
-               switch (ctrl->id) {
-               case V4L2_CID_BRIGHTNESS:
-                       strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)-1);
-                       break;
-               case V4L2_CID_CONTRAST:
-                       strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)-1);
-                       break;
-               case V4L2_CID_SATURATION:
-                       strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)-1);
-                       break;
-               case V4L2_CID_HUE:
-                       strncpy(ctrl->name, "Hue", sizeof(ctrl->name)-1);
-                       break;
+       switch (fh->map_mode) {
+       case ZORAN_MAP_MODE_RAW:
+               if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       dprintk(1, KERN_ERR
+                               "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
+                               ZR_DEVNAME(zr), buf->type, fh->map_mode);
+                       res = -EINVAL;
+                       goto qbuf_unlock_and_return;
                }
 
-               ctrl->minimum = 0;
-               ctrl->maximum = 65535;
-               ctrl->step = 1;
-               ctrl->default_value = 32768;
-               ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-
-               return 0;
-       }
+               res = zoran_v4l_queue_frame(fh, buf->index);
+               if (res)
+                       goto qbuf_unlock_and_return;
+               if (!zr->v4l_memgrab_active && fh->buffers.active == ZORAN_LOCKED)
+                       zr36057_set_memgrab(zr, 1);
                break;
 
-       case VIDIOC_G_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
+       case ZORAN_MAP_MODE_JPG_REC:
+       case ZORAN_MAP_MODE_JPG_PLAY:
+               if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
+                       buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+                       codec_mode = BUZ_MODE_MOTION_DECOMPRESS;
+               } else {
+                       buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                       codec_mode = BUZ_MODE_MOTION_COMPRESS;
+               }
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_G_CTRL - id=%d\n",
-                       ZR_DEVNAME(zr), ctrl->id);
+               if (buf->type != buf_type) {
+                       dprintk(1, KERN_ERR
+                               "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
+                               ZR_DEVNAME(zr), buf->type, fh->map_mode);
+                       res = -EINVAL;
+                       goto qbuf_unlock_and_return;
+               }
 
-               /* we only support hue/saturation/contrast/brightness */
-               if (ctrl->id < V4L2_CID_BRIGHTNESS ||
-                   ctrl->id > V4L2_CID_HUE)
-                       return -EINVAL;
+               res = zoran_jpg_queue_frame(fh, buf->index, codec_mode);
+               if (res != 0)
+                       goto qbuf_unlock_and_return;
+               if (zr->codec_mode == BUZ_MODE_IDLE &&
+                   fh->buffers.active == ZORAN_LOCKED)
+                       zr36057_enable_jpg(zr, codec_mode);
 
-               mutex_lock(&zr->resource_lock);
-               switch (ctrl->id) {
-               case V4L2_CID_BRIGHTNESS:
-                       ctrl->value = zr->brightness;
-                       break;
-               case V4L2_CID_CONTRAST:
-                       ctrl->value = zr->contrast;
-                       break;
-               case V4L2_CID_SATURATION:
-                       ctrl->value = zr->saturation;
-                       break;
-               case V4L2_CID_HUE:
-                       ctrl->value = zr->hue;
-                       break;
-               }
-               mutex_unlock(&zr->resource_lock);
+               break;
 
-               return 0;
-       }
+       default:
+               dprintk(1, KERN_ERR
+                       "%s: VIDIOC_QBUF - unsupported type %d\n",
+                       ZR_DEVNAME(zr), buf->type);
+               res = -EINVAL;
                break;
+       }
+qbuf_unlock_and_return:
+       mutex_unlock(&zr->resource_lock);
 
-       case VIDIOC_S_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-               struct video_picture pict;
+       return res;
+}
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_S_CTRL - id=%d\n",
-                       ZR_DEVNAME(zr), ctrl->id);
+static int zoran_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int res = 0, buf_type, num = -1;        /* compiler borks here (?) */
 
-               /* we only support hue/saturation/contrast/brightness */
-               if (ctrl->id < V4L2_CID_BRIGHTNESS ||
-                   ctrl->id > V4L2_CID_HUE)
-                       return -EINVAL;
+       mutex_lock(&zr->resource_lock);
 
-               if (ctrl->value < 0 || ctrl->value > 65535) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOC_S_CTRL - invalid value %d for id=%d\n",
-                               ZR_DEVNAME(zr), ctrl->value, ctrl->id);
-                       return -EINVAL;
+       switch (fh->map_mode) {
+       case ZORAN_MAP_MODE_RAW:
+               if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       dprintk(1, KERN_ERR
+                               "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
+                               ZR_DEVNAME(zr), buf->type, fh->map_mode);
+                       res = -EINVAL;
+                       goto dqbuf_unlock_and_return;
                }
 
-               mutex_lock(&zr->resource_lock);
-               switch (ctrl->id) {
-               case V4L2_CID_BRIGHTNESS:
-                       zr->brightness = ctrl->value;
-                       break;
-               case V4L2_CID_CONTRAST:
-                       zr->contrast = ctrl->value;
-                       break;
-               case V4L2_CID_SATURATION:
-                       zr->saturation = ctrl->value;
-                       break;
-               case V4L2_CID_HUE:
-                       zr->hue = ctrl->value;
-                       break;
+               num = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME];
+               if (file->f_flags & O_NONBLOCK &&
+                   zr->v4l_buffers.buffer[num].state != BUZ_STATE_DONE) {
+                       res = -EAGAIN;
+                       goto dqbuf_unlock_and_return;
                }
-               pict.brightness = zr->brightness;
-               pict.contrast = zr->contrast;
-               pict.colour = zr->saturation;
-               pict.hue = zr->hue;
-
-               decoder_command(zr, DECODER_SET_PICTURE, &pict);
-
-               mutex_unlock(&zr->resource_lock);
-
-               return 0;
-       }
+               res = v4l_sync(fh, num);
+               if (res)
+                       goto dqbuf_unlock_and_return;
+               zr->v4l_sync_tail++;
+               res = zoran_v4l2_buffer_status(fh, buf, num);
                break;
 
-       case VIDIOC_ENUMSTD:
+       case ZORAN_MAP_MODE_JPG_REC:
+       case ZORAN_MAP_MODE_JPG_PLAY:
        {
-               struct v4l2_standard *std = arg;
+               struct zoran_sync bs;
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMSTD - index=%d\n",
-                       ZR_DEVNAME(zr), std->index);
+               if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY)
+                       buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+               else
+                       buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
-               if (std->index < 0 || std->index >= (zr->card.norms + 1))
-                       return -EINVAL;
-               else {
-                       int id = std->index;
-                       memset(std, 0, sizeof(*std));
-                       std->index = id;
+               if (buf->type != buf_type) {
+                       dprintk(1, KERN_ERR
+                               "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
+                               ZR_DEVNAME(zr), buf->type, fh->map_mode);
+                       res = -EINVAL;
+                       goto dqbuf_unlock_and_return;
                }
 
-               if (std->index == zr->card.norms) {
-                       /* if we have autodetect, ... */
-                       struct video_decoder_capability caps;
-                       decoder_command(zr, DECODER_GET_CAPABILITIES,
-                                       &caps);
-                       if (caps.flags & VIDEO_DECODER_AUTO) {
-                               std->id = V4L2_STD_ALL;
-                               strncpy(std->name, "Autodetect", sizeof(std->name)-1);
-                               return 0;
-                       } else
-                               return -EINVAL;
-               }
-               switch (std->index) {
-               case 0:
-                       std->id = V4L2_STD_PAL;
-                       strncpy(std->name, "PAL", sizeof(std->name)-1);
-                       std->frameperiod.numerator = 1;
-                       std->frameperiod.denominator = 25;
-                       std->framelines = zr->card.tvn[0]->Ht;
-                       break;
-               case 1:
-                       std->id = V4L2_STD_NTSC;
-                       strncpy(std->name, "NTSC", sizeof(std->name)-1);
-                       std->frameperiod.numerator = 1001;
-                       std->frameperiod.denominator = 30000;
-                       std->framelines = zr->card.tvn[1]->Ht;
-                       break;
-               case 2:
-                       std->id = V4L2_STD_SECAM;
-                       strncpy(std->name, "SECAM", sizeof(std->name)-1);
-                       std->frameperiod.numerator = 1;
-                       std->frameperiod.denominator = 25;
-                       std->framelines = zr->card.tvn[2]->Ht;
-                       break;
-               }
+               num = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
 
-               return 0;
+               if (file->f_flags & O_NONBLOCK &&
+                   zr->jpg_buffers.buffer[num].state != BUZ_STATE_DONE) {
+                       res = -EAGAIN;
+                       goto dqbuf_unlock_and_return;
+               }
+               res = jpg_sync(fh, &bs);
+               if (res)
+                       goto dqbuf_unlock_and_return;
+               res = zoran_v4l2_buffer_status(fh, buf, bs.frame);
+               break;
        }
+
+       default:
+               dprintk(1, KERN_ERR
+                       "%s: VIDIOC_DQBUF - unsupported type %d\n",
+                       ZR_DEVNAME(zr), buf->type);
+               res = -EINVAL;
                break;
+       }
+dqbuf_unlock_and_return:
+       mutex_unlock(&zr->resource_lock);
 
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *std = arg;
-               int norm;
+       return res;
+}
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_G_STD\n", ZR_DEVNAME(zr));
+static int zoran_streamon(struct file *file, void *__fh, enum v4l2_buf_type type)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int res = 0;
 
-               mutex_lock(&zr->resource_lock);
-               norm = zr->norm;
-               mutex_unlock(&zr->resource_lock);
+       mutex_lock(&zr->resource_lock);
 
-               switch (norm) {
-               case VIDEO_MODE_PAL:
-                       *std = V4L2_STD_PAL;
-                       break;
-               case VIDEO_MODE_NTSC:
-                       *std = V4L2_STD_NTSC;
-                       break;
-               case VIDEO_MODE_SECAM:
-                       *std = V4L2_STD_SECAM;
-                       break;
+       switch (fh->map_mode) {
+       case ZORAN_MAP_MODE_RAW:        /* raw capture */
+               if (zr->v4l_buffers.active != ZORAN_ACTIVE ||
+                   fh->buffers.active != ZORAN_ACTIVE) {
+                       res = -EBUSY;
+                       goto strmon_unlock_and_return;
                }
 
-               return 0;
-       }
+               zr->v4l_buffers.active = fh->buffers.active = ZORAN_LOCKED;
+               zr->v4l_settings = fh->v4l_settings;
+
+               zr->v4l_sync_tail = zr->v4l_pend_tail;
+               if (!zr->v4l_memgrab_active &&
+                   zr->v4l_pend_head != zr->v4l_pend_tail) {
+                       zr36057_set_memgrab(zr, 1);
+               }
                break;
 
-       case VIDIOC_S_STD:
-       {
-               int norm = -1, res = 0;
-               v4l2_std_id *std = arg;
-
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_S_STD - norm=0x%llx\n",
-                       ZR_DEVNAME(zr), (unsigned long long)*std);
-
-               if ((*std & V4L2_STD_PAL) && !(*std & ~V4L2_STD_PAL))
-                       norm = VIDEO_MODE_PAL;
-               else if ((*std & V4L2_STD_NTSC) && !(*std & ~V4L2_STD_NTSC))
-                       norm = VIDEO_MODE_NTSC;
-               else if ((*std & V4L2_STD_SECAM) && !(*std & ~V4L2_STD_SECAM))
-                       norm = VIDEO_MODE_SECAM;
-               else if (*std == V4L2_STD_ALL)
-                       norm = VIDEO_MODE_AUTO;
-               else {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOC_S_STD - invalid norm 0x%llx\n",
-                               ZR_DEVNAME(zr), (unsigned long long)*std);
-                       return -EINVAL;
+       case ZORAN_MAP_MODE_JPG_REC:
+       case ZORAN_MAP_MODE_JPG_PLAY:
+               /* what is the codec mode right now? */
+               if (zr->jpg_buffers.active != ZORAN_ACTIVE ||
+                   fh->buffers.active != ZORAN_ACTIVE) {
+                       res = -EBUSY;
+                       goto strmon_unlock_and_return;
                }
 
-               mutex_lock(&zr->resource_lock);
-               if ((res = zoran_set_norm(zr, norm)))
-                       goto sstd_unlock_and_return;
+               zr->jpg_buffers.active = fh->buffers.active = ZORAN_LOCKED;
 
-               res = wait_grab_pending(zr);
-       sstd_unlock_and_return:
-               mutex_unlock(&zr->resource_lock);
-               return res;
-       }
+               if (zr->jpg_que_head != zr->jpg_que_tail) {
+                       /* Start the jpeg codec when the first frame is queued  */
+                       jpeg_start(zr);
+               }
                break;
 
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *inp = arg;
-               int status;
-
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMINPUT - index=%d\n",
-                       ZR_DEVNAME(zr), inp->index);
+       default:
+               dprintk(1,
+                       KERN_ERR
+                       "%s: VIDIOC_STREAMON - invalid map mode %d\n",
+                       ZR_DEVNAME(zr), fh->map_mode);
+               res = -EINVAL;
+               break;
+       }
+strmon_unlock_and_return:
+       mutex_unlock(&zr->resource_lock);
 
-               if (inp->index < 0 || inp->index >= zr->card.inputs)
-                       return -EINVAL;
-               else {
-                       int id = inp->index;
-                       memset(inp, 0, sizeof(*inp));
-                       inp->index = id;
-               }
+       return res;
+}
 
-               strncpy(inp->name, zr->card.input[inp->index].name,
-                       sizeof(inp->name) - 1);
-               inp->type = V4L2_INPUT_TYPE_CAMERA;
-               inp->std = V4L2_STD_ALL;
+static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int i, res = 0;
+       unsigned long flags;
 
-               /* Get status of video decoder */
-               mutex_lock(&zr->resource_lock);
-               decoder_command(zr, DECODER_GET_STATUS, &status);
-               mutex_unlock(&zr->resource_lock);
+       mutex_lock(&zr->resource_lock);
 
-               if (!(status & DECODER_STATUS_GOOD)) {
-                       inp->status |= V4L2_IN_ST_NO_POWER;
-                       inp->status |= V4L2_IN_ST_NO_SIGNAL;
+       switch (fh->map_mode) {
+       case ZORAN_MAP_MODE_RAW:        /* raw capture */
+               if (fh->buffers.active == ZORAN_FREE &&
+                   zr->v4l_buffers.active != ZORAN_FREE) {
+                       res = -EPERM;   /* stay off other's settings! */
+                       goto strmoff_unlock_and_return;
                }
-               if (!(status & DECODER_STATUS_COLOR))
-                       inp->status |= V4L2_IN_ST_NO_COLOR;
+               if (zr->v4l_buffers.active == ZORAN_FREE)
+                       goto strmoff_unlock_and_return;
 
-               return 0;
-       }
-               break;
+               spin_lock_irqsave(&zr->spinlock, flags);
+               /* unload capture */
+               if (zr->v4l_memgrab_active) {
 
-       case VIDIOC_G_INPUT:
-       {
-               int *input = arg;
+                       zr36057_set_memgrab(zr, 0);
+               }
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_G_INPUT\n", ZR_DEVNAME(zr));
+               for (i = 0; i < fh->buffers.num_buffers; i++)
+                       zr->v4l_buffers.buffer[i].state = BUZ_STATE_USER;
+               fh->buffers = zr->v4l_buffers;
 
-               mutex_lock(&zr->resource_lock);
-               *input = zr->input;
-               mutex_unlock(&zr->resource_lock);
+               zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE;
 
-               return 0;
-       }
-               break;
+               zr->v4l_grab_seq = 0;
+               zr->v4l_pend_head = zr->v4l_pend_tail = 0;
+               zr->v4l_sync_tail = 0;
 
-       case VIDIOC_S_INPUT:
-       {
-               int *input = arg, res = 0;
+               spin_unlock_irqrestore(&zr->spinlock, flags);
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_S_INPUT - input=%d\n",
-                       ZR_DEVNAME(zr), *input);
+               break;
 
-               mutex_lock(&zr->resource_lock);
-               if ((res = zoran_set_input(zr, *input)))
-                       goto sinput_unlock_and_return;
+       case ZORAN_MAP_MODE_JPG_REC:
+       case ZORAN_MAP_MODE_JPG_PLAY:
+               if (fh->buffers.active == ZORAN_FREE &&
+                   zr->jpg_buffers.active != ZORAN_FREE) {
+                       res = -EPERM;   /* stay off other's settings! */
+                       goto strmoff_unlock_and_return;
+               }
+               if (zr->jpg_buffers.active == ZORAN_FREE)
+                       goto strmoff_unlock_and_return;
 
-               /* Make sure the changes come into effect */
-               res = wait_grab_pending(zr);
-       sinput_unlock_and_return:
-               mutex_unlock(&zr->resource_lock);
-               return res;
-       }
+               res = jpg_qbuf(fh, -1,
+                            (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ?
+                            BUZ_MODE_MOTION_COMPRESS :
+                            BUZ_MODE_MOTION_DECOMPRESS);
+               if (res)
+                       goto strmoff_unlock_and_return;
                break;
+       default:
+               dprintk(1, KERN_ERR
+                       "%s: VIDIOC_STREAMOFF - invalid map mode %d\n",
+                       ZR_DEVNAME(zr), fh->map_mode);
+               res = -EINVAL;
+               break;
+       }
+strmoff_unlock_and_return:
+       mutex_unlock(&zr->resource_lock);
 
-       case VIDIOC_ENUMOUTPUT:
-       {
-               struct v4l2_output *outp = arg;
-
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMOUTPUT - index=%d\n",
-                       ZR_DEVNAME(zr), outp->index);
+       return res;
+}
 
-               if (outp->index != 0)
-                       return -EINVAL;
+static int zoran_queryctrl(struct file *file, void *__fh,
+                                       struct v4l2_queryctrl *ctrl)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
 
-               memset(outp, 0, sizeof(*outp));
-               outp->index = 0;
-               outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
-               strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);
+       /* we only support hue/saturation/contrast/brightness */
+       if (ctrl->id < V4L2_CID_BRIGHTNESS ||
+           ctrl->id > V4L2_CID_HUE)
+               return -EINVAL;
 
-               return 0;
-       }
-               break;
+       decoder_call(zr, core, queryctrl, ctrl);
 
-       case VIDIOC_G_OUTPUT:
-       {
-               int *output = arg;
+       return 0;
+}
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_G_OUTPUT\n", ZR_DEVNAME(zr));
+static int zoran_g_ctrl(struct file *file, void *__fh, struct v4l2_control *ctrl)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
 
-               *output = 0;
+       /* we only support hue/saturation/contrast/brightness */
+       if (ctrl->id < V4L2_CID_BRIGHTNESS ||
+           ctrl->id > V4L2_CID_HUE)
+               return -EINVAL;
 
-               return 0;
-       }
-               break;
+       mutex_lock(&zr->resource_lock);
+       decoder_call(zr, core, g_ctrl, ctrl);
+       mutex_unlock(&zr->resource_lock);
 
-       case VIDIOC_S_OUTPUT:
-       {
-               int *output = arg;
+       return 0;
+}
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_S_OUTPUT - output=%d\n",
-                       ZR_DEVNAME(zr), *output);
+static int zoran_s_ctrl(struct file *file, void *__fh, struct v4l2_control *ctrl)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
 
-               if (*output != 0)
-                       return -EINVAL;
+       /* we only support hue/saturation/contrast/brightness */
+       if (ctrl->id < V4L2_CID_BRIGHTNESS ||
+           ctrl->id > V4L2_CID_HUE)
+               return -EINVAL;
 
-               return 0;
-       }
-               break;
+       mutex_lock(&zr->resource_lock);
+       decoder_call(zr, core, s_ctrl, ctrl);
+       mutex_unlock(&zr->resource_lock);
 
-               /* cropping (sub-frame capture) */
-       case VIDIOC_CROPCAP:
-       {
-               struct v4l2_cropcap *cropcap = arg;
-               int type = cropcap->type, res = 0;
+       return 0;
+}
 
-               dprintk(3, KERN_ERR "%s: VIDIOC_CROPCAP - type=%d\n",
-                       ZR_DEVNAME(zr), cropcap->type);
+static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
 
-               memset(cropcap, 0, sizeof(*cropcap));
-               cropcap->type = type;
+       mutex_lock(&zr->resource_lock);
+       *std = zr->norm;
+       mutex_unlock(&zr->resource_lock);
+       return 0;
+}
 
-               mutex_lock(&zr->resource_lock);
+static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id *std)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int res = 0;
 
-               if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-                   (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                    fh->map_mode == ZORAN_MAP_MODE_RAW)) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOC_CROPCAP - subcapture only supported for compressed capture\n",
-                               ZR_DEVNAME(zr));
-                       res = -EINVAL;
-                       goto cropcap_unlock_and_return;
-               }
+       mutex_lock(&zr->resource_lock);
+       res = zoran_set_norm(zr, *std);
+       if (res)
+               goto sstd_unlock_and_return;
 
-               cropcap->bounds.top = cropcap->bounds.left = 0;
-               cropcap->bounds.width = BUZ_MAX_WIDTH;
-               cropcap->bounds.height = BUZ_MAX_HEIGHT;
-               cropcap->defrect.top = cropcap->defrect.left = 0;
-               cropcap->defrect.width = BUZ_MIN_WIDTH;
-               cropcap->defrect.height = BUZ_MIN_HEIGHT;
-       cropcap_unlock_and_return:
-               mutex_unlock(&zr->resource_lock);
-               return res;
-       }
-               break;
+       res = wait_grab_pending(zr);
+sstd_unlock_and_return:
+       mutex_unlock(&zr->resource_lock);
+       return res;
+}
 
-       case VIDIOC_G_CROP:
-       {
-               struct v4l2_crop *crop = arg;
-               int type = crop->type, res = 0;
+static int zoran_enum_input(struct file *file, void *__fh,
+                                struct v4l2_input *inp)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
 
-               dprintk(3, KERN_ERR "%s: VIDIOC_G_CROP - type=%d\n",
-                       ZR_DEVNAME(zr), crop->type);
+       if (inp->index < 0 || inp->index >= zr->card.inputs)
+               return -EINVAL;
+       else {
+               int id = inp->index;
+               memset(inp, 0, sizeof(*inp));
+               inp->index = id;
+       }
 
-               memset(crop, 0, sizeof(*crop));
-               crop->type = type;
+       strncpy(inp->name, zr->card.input[inp->index].name,
+               sizeof(inp->name) - 1);
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+       inp->std = V4L2_STD_ALL;
 
-               mutex_lock(&zr->resource_lock);
+       /* Get status of video decoder */
+       mutex_lock(&zr->resource_lock);
+       decoder_call(zr, video, g_input_status, &inp->status);
+       mutex_unlock(&zr->resource_lock);
+       return 0;
+}
 
-               if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-                   (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                    fh->map_mode == ZORAN_MAP_MODE_RAW)) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
-                               ZR_DEVNAME(zr));
-                       res = -EINVAL;
-                       goto gcrop_unlock_and_return;
-               }
+static int zoran_g_input(struct file *file, void *__fh, unsigned int *input)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
 
-               crop->c.top = fh->jpg_settings.img_y;
-               crop->c.left = fh->jpg_settings.img_x;
-               crop->c.width = fh->jpg_settings.img_width;
-               crop->c.height = fh->jpg_settings.img_height;
+       mutex_lock(&zr->resource_lock);
+       *input = zr->input;
+       mutex_unlock(&zr->resource_lock);
 
-       gcrop_unlock_and_return:
-               mutex_unlock(&zr->resource_lock);
+       return 0;
+}
 
-               return res;
-       }
-               break;
+static int zoran_s_input(struct file *file, void *__fh, unsigned int input)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int res;
 
-       case VIDIOC_S_CROP:
-       {
-               struct v4l2_crop *crop = arg;
-               int res = 0;
+       mutex_lock(&zr->resource_lock);
+       res = zoran_set_input(zr, input);
+       if (res)
+               goto sinput_unlock_and_return;
 
-               settings = fh->jpg_settings;
+       /* Make sure the changes come into effect */
+       res = wait_grab_pending(zr);
+sinput_unlock_and_return:
+       mutex_unlock(&zr->resource_lock);
+       return res;
+}
 
-               dprintk(3,
-                       KERN_ERR
-                       "%s: VIDIOC_S_CROP - type=%d, x=%d,y=%d,w=%d,h=%d\n",
-                       ZR_DEVNAME(zr), crop->type, crop->c.left, crop->c.top,
-                       crop->c.width, crop->c.height);
+static int zoran_enum_output(struct file *file, void *__fh,
+                                 struct v4l2_output *outp)
+{
+       if (outp->index != 0)
+               return -EINVAL;
 
-               mutex_lock(&zr->resource_lock);
+       memset(outp, 0, sizeof(*outp));
+       outp->index = 0;
+       outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
+       strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);
 
-               if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOC_S_CROP - cannot change settings while active\n",
-                               ZR_DEVNAME(zr));
-                       res = -EBUSY;
-                       goto scrop_unlock_and_return;
-               }
+       return 0;
+}
 
-               if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-                   (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                    fh->map_mode == ZORAN_MAP_MODE_RAW)) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
-                               ZR_DEVNAME(zr));
-                       res = -EINVAL;
-                       goto scrop_unlock_and_return;
-               }
+static int zoran_g_output(struct file *file, void *__fh, unsigned int *output)
+{
+       *output = 0;
 
-               /* move into a form that we understand */
-               settings.img_x = crop->c.left;
-               settings.img_y = crop->c.top;
-               settings.img_width = crop->c.width;
-               settings.img_height = crop->c.height;
+       return 0;
+}
 
-               /* check validity */
-               if ((res = zoran_check_jpg_settings(zr, &settings)))
-                       goto scrop_unlock_and_return;
+static int zoran_s_output(struct file *file, void *__fh, unsigned int output)
+{
+       if (output != 0)
+               return -EINVAL;
 
-               /* accept */
-               fh->jpg_settings = settings;
+       return 0;
+}
 
-       scrop_unlock_and_return:
-               mutex_unlock(&zr->resource_lock);
-               return res;
-       }
-               break;
+/* cropping (sub-frame capture) */
+static int zoran_cropcap(struct file *file, void *__fh,
+                                       struct v4l2_cropcap *cropcap)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int type = cropcap->type, res = 0;
 
-       case VIDIOC_G_JPEGCOMP:
-       {
-               struct v4l2_jpegcompression *params = arg;
+       memset(cropcap, 0, sizeof(*cropcap));
+       cropcap->type = type;
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_G_JPEGCOMP\n",
+       mutex_lock(&zr->resource_lock);
+
+       if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+           (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+            fh->map_mode == ZORAN_MAP_MODE_RAW)) {
+               dprintk(1, KERN_ERR
+                       "%s: VIDIOC_CROPCAP - subcapture only supported for compressed capture\n",
                        ZR_DEVNAME(zr));
+               res = -EINVAL;
+               goto cropcap_unlock_and_return;
+       }
 
-               memset(params, 0, sizeof(*params));
+       cropcap->bounds.top = cropcap->bounds.left = 0;
+       cropcap->bounds.width = BUZ_MAX_WIDTH;
+       cropcap->bounds.height = BUZ_MAX_HEIGHT;
+       cropcap->defrect.top = cropcap->defrect.left = 0;
+       cropcap->defrect.width = BUZ_MIN_WIDTH;
+       cropcap->defrect.height = BUZ_MIN_HEIGHT;
+cropcap_unlock_and_return:
+       mutex_unlock(&zr->resource_lock);
+       return res;
+}
 
-               mutex_lock(&zr->resource_lock);
+static int zoran_g_crop(struct file *file, void *__fh, struct v4l2_crop *crop)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int type = crop->type, res = 0;
 
-               params->quality = fh->jpg_settings.jpg_comp.quality;
-               params->APPn = fh->jpg_settings.jpg_comp.APPn;
-               memcpy(params->APP_data,
-                      fh->jpg_settings.jpg_comp.APP_data,
-                      fh->jpg_settings.jpg_comp.APP_len);
-               params->APP_len = fh->jpg_settings.jpg_comp.APP_len;
-               memcpy(params->COM_data,
-                      fh->jpg_settings.jpg_comp.COM_data,
-                      fh->jpg_settings.jpg_comp.COM_len);
-               params->COM_len = fh->jpg_settings.jpg_comp.COM_len;
-               params->jpeg_markers =
-                   fh->jpg_settings.jpg_comp.jpeg_markers;
+       memset(crop, 0, sizeof(*crop));
+       crop->type = type;
 
-               mutex_unlock(&zr->resource_lock);
+       mutex_lock(&zr->resource_lock);
 
-               return 0;
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+           (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+            fh->map_mode == ZORAN_MAP_MODE_RAW)) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
+                       ZR_DEVNAME(zr));
+               res = -EINVAL;
+               goto gcrop_unlock_and_return;
        }
-               break;
-
-       case VIDIOC_S_JPEGCOMP:
-       {
-               struct v4l2_jpegcompression *params = arg;
-               int res = 0;
 
-               settings = fh->jpg_settings;
+       crop->c.top = fh->jpg_settings.img_y;
+       crop->c.left = fh->jpg_settings.img_x;
+       crop->c.width = fh->jpg_settings.img_width;
+       crop->c.height = fh->jpg_settings.img_height;
 
-               dprintk(3,
-                       KERN_DEBUG
-                       "%s: VIDIOC_S_JPEGCOMP - quality=%d, APPN=%d, APP_len=%d, COM_len=%d\n",
-                       ZR_DEVNAME(zr), params->quality, params->APPn,
-                       params->APP_len, params->COM_len);
+gcrop_unlock_and_return:
+       mutex_unlock(&zr->resource_lock);
 
-               settings.jpg_comp = *params;
+       return res;
+}
 
-               mutex_lock(&zr->resource_lock);
+static int zoran_s_crop(struct file *file, void *__fh, struct v4l2_crop *crop)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int res = 0;
+       struct zoran_jpg_settings settings;
 
-               if (fh->v4l_buffers.active != ZORAN_FREE ||
-                   fh->jpg_buffers.active != ZORAN_FREE) {
-                       dprintk(1,
-                               KERN_WARNING
-                               "%s: VIDIOC_S_JPEGCOMP called while in playback/capture mode\n",
-                               ZR_DEVNAME(zr));
-                       res = -EBUSY;
-                       goto sjpegc_unlock_and_return;
-               }
+       settings = fh->jpg_settings;
 
-               if ((res = zoran_check_jpg_settings(zr, &settings)))
-                       goto sjpegc_unlock_and_return;
-               if (!fh->jpg_buffers.allocated)
-                       fh->jpg_buffers.buffer_size =
-                           zoran_v4l2_calc_bufsize(&fh->jpg_settings);
-               fh->jpg_settings.jpg_comp = *params = settings.jpg_comp;
-       sjpegc_unlock_and_return:
-               mutex_unlock(&zr->resource_lock);
+       mutex_lock(&zr->resource_lock);
 
-               return 0;
+       if (fh->buffers.allocated) {
+               dprintk(1, KERN_ERR
+                       "%s: VIDIOC_S_CROP - cannot change settings while active\n",
+                       ZR_DEVNAME(zr));
+               res = -EBUSY;
+               goto scrop_unlock_and_return;
        }
-               break;
-
-       case VIDIOC_QUERYSTD:   /* why is this useful? */
-       {
-               v4l2_std_id *std = arg;
-
-               dprintk(3,
-                       KERN_DEBUG "%s: VIDIOC_QUERY_STD - std=0x%llx\n",
-                       ZR_DEVNAME(zr), (unsigned long long)*std);
-
-               if (*std == V4L2_STD_ALL || *std == V4L2_STD_NTSC ||
-                   *std == V4L2_STD_PAL || (*std == V4L2_STD_SECAM &&
-                                            zr->card.norms == 3)) {
-                       return 0;
-               }
 
-               return -EINVAL;
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+           (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+            fh->map_mode == ZORAN_MAP_MODE_RAW)) {
+               dprintk(1, KERN_ERR
+                       "%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
+                       ZR_DEVNAME(zr));
+               res = -EINVAL;
+               goto scrop_unlock_and_return;
        }
-               break;
 
-       case VIDIOC_TRY_FMT:
-       {
-               struct v4l2_format *fmt = arg;
-               int res = 0;
+       /* move into a form that we understand */
+       settings.img_x = crop->c.left;
+       settings.img_y = crop->c.top;
+       settings.img_width = crop->c.width;
+       settings.img_height = crop->c.height;
 
-               dprintk(3, KERN_DEBUG "%s: VIDIOC_TRY_FMT - type=%d\n",
-                       ZR_DEVNAME(zr), fmt->type);
+       /* check validity */
+       res = zoran_check_jpg_settings(zr, &settings, 0);
+       if (res)
+               goto scrop_unlock_and_return;
 
-               switch (fmt->type) {
-               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-                       mutex_lock(&zr->resource_lock);
+       /* accept */
+       fh->jpg_settings = settings;
+
+scrop_unlock_and_return:
+       mutex_unlock(&zr->resource_lock);
+       return res;
+}
 
-                       if (fmt->fmt.win.w.width > BUZ_MAX_WIDTH)
-                               fmt->fmt.win.w.width = BUZ_MAX_WIDTH;
-                       if (fmt->fmt.win.w.width < BUZ_MIN_WIDTH)
-                               fmt->fmt.win.w.width = BUZ_MIN_WIDTH;
-                       if (fmt->fmt.win.w.height > BUZ_MAX_HEIGHT)
-                               fmt->fmt.win.w.height = BUZ_MAX_HEIGHT;
-                       if (fmt->fmt.win.w.height < BUZ_MIN_HEIGHT)
-                               fmt->fmt.win.w.height = BUZ_MIN_HEIGHT;
+static int zoran_g_jpegcomp(struct file *file, void *__fh,
+                                       struct v4l2_jpegcompression *params)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       memset(params, 0, sizeof(*params));
 
-                       mutex_unlock(&zr->resource_lock);
-                       break;
+       mutex_lock(&zr->resource_lock);
 
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-                       if (fmt->fmt.pix.bytesperline > 0)
-                               return -EINVAL;
+       params->quality = fh->jpg_settings.jpg_comp.quality;
+       params->APPn = fh->jpg_settings.jpg_comp.APPn;
+       memcpy(params->APP_data,
+              fh->jpg_settings.jpg_comp.APP_data,
+              fh->jpg_settings.jpg_comp.APP_len);
+       params->APP_len = fh->jpg_settings.jpg_comp.APP_len;
+       memcpy(params->COM_data,
+              fh->jpg_settings.jpg_comp.COM_data,
+              fh->jpg_settings.jpg_comp.COM_len);
+       params->COM_len = fh->jpg_settings.jpg_comp.COM_len;
+       params->jpeg_markers =
+           fh->jpg_settings.jpg_comp.jpeg_markers;
 
-                       mutex_lock(&zr->resource_lock);
-
-                       if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
-                               settings = fh->jpg_settings;
-
-                               /* we actually need to set 'real' parameters now */
-                               if ((fmt->fmt.pix.height * 2) >
-                                   BUZ_MAX_HEIGHT)
-                                       settings.TmpDcm = 1;
-                               else
-                                       settings.TmpDcm = 2;
-                               settings.decimation = 0;
-                               if (fmt->fmt.pix.height <=
-                                   fh->jpg_settings.img_height / 2)
-                                       settings.VerDcm = 2;
-                               else
-                                       settings.VerDcm = 1;
-                               if (fmt->fmt.pix.width <=
-                                   fh->jpg_settings.img_width / 4)
-                                       settings.HorDcm = 4;
-                               else if (fmt->fmt.pix.width <=
-                                        fh->jpg_settings.img_width / 2)
-                                       settings.HorDcm = 2;
-                               else
-                                       settings.HorDcm = 1;
-                               if (settings.TmpDcm == 1)
-                                       settings.field_per_buff = 2;
-                               else
-                                       settings.field_per_buff = 1;
-
-                               /* check */
-                               if ((res =
-                                    zoran_check_jpg_settings(zr,
-                                                             &settings)))
-                                       goto tryfmt_unlock_and_return;
-
-                               /* tell the user what we actually did */
-                               fmt->fmt.pix.width =
-                                   settings.img_width / settings.HorDcm;
-                               fmt->fmt.pix.height =
-                                   settings.img_height * 2 /
-                                   (settings.TmpDcm * settings.VerDcm);
-                               if (settings.TmpDcm == 1)
-                                       fmt->fmt.pix.field =
-                                           (fh->jpg_settings.
-                                            odd_even ? V4L2_FIELD_SEQ_TB :
-                                            V4L2_FIELD_SEQ_BT);
-                               else
-                                       fmt->fmt.pix.field =
-                                           (fh->jpg_settings.
-                                            odd_even ? V4L2_FIELD_TOP :
-                                            V4L2_FIELD_BOTTOM);
-
-                               fmt->fmt.pix.sizeimage =
-                                   zoran_v4l2_calc_bufsize(&settings);
-                       } else if (fmt->type ==
-                                  V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                               int i;
-
-                               for (i = 0; i < NUM_FORMATS; i++)
-                                       if (zoran_formats[i].fourcc ==
-                                           fmt->fmt.pix.pixelformat)
-                                               break;
-                               if (i == NUM_FORMATS) {
-                                       res = -EINVAL;
-                                       goto tryfmt_unlock_and_return;
-                               }
+       mutex_unlock(&zr->resource_lock);
 
-                               if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
-                                       fmt->fmt.pix.width = BUZ_MAX_WIDTH;
-                               if (fmt->fmt.pix.width < BUZ_MIN_WIDTH)
-                                       fmt->fmt.pix.width = BUZ_MIN_WIDTH;
-                               if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
-                                       fmt->fmt.pix.height =
-                                           BUZ_MAX_HEIGHT;
-                               if (fmt->fmt.pix.height < BUZ_MIN_HEIGHT)
-                                       fmt->fmt.pix.height =
-                                           BUZ_MIN_HEIGHT;
-                       } else {
-                               res = -EINVAL;
-                               goto tryfmt_unlock_and_return;
-                       }
-               tryfmt_unlock_and_return:
-                       mutex_unlock(&zr->resource_lock);
+       return 0;
+}
 
-                       return res;
-                       break;
+static int zoran_s_jpegcomp(struct file *file, void *__fh,
+                                       struct v4l2_jpegcompression *params)
+{
+       struct zoran_fh *fh = __fh;
+       struct zoran *zr = fh->zr;
+       int res = 0;
+       struct zoran_jpg_settings settings;
 
-               default:
-                       return -EINVAL;
-               }
+       settings = fh->jpg_settings;
 
-               return 0;
-       }
-               break;
+       settings.jpg_comp = *params;
 
-       default:
-               dprintk(1, KERN_DEBUG "%s: UNKNOWN ioctl cmd: 0x%x\n",
-                       ZR_DEVNAME(zr), cmd);
-               return -ENOIOCTLCMD;
-               break;
+       mutex_lock(&zr->resource_lock);
 
+       if (fh->buffers.active != ZORAN_FREE) {
+               dprintk(1, KERN_WARNING
+                       "%s: VIDIOC_S_JPEGCOMP called while in playback/capture mode\n",
+                       ZR_DEVNAME(zr));
+               res = -EBUSY;
+               goto sjpegc_unlock_and_return;
        }
-       return 0;
-}
 
+       res = zoran_check_jpg_settings(zr, &settings, 0);
+       if (res)
+               goto sjpegc_unlock_and_return;
+       if (!fh->buffers.allocated)
+               fh->buffers.buffer_size =
+                       zoran_v4l2_calc_bufsize(&fh->jpg_settings);
+       fh->jpg_settings.jpg_comp = *params = settings.jpg_comp;
+sjpegc_unlock_and_return:
+       mutex_unlock(&zr->resource_lock);
 
-static long
-zoran_ioctl(struct file  *file,
-           unsigned int  cmd,
-           unsigned long arg)
-{
-       return video_usercopy(file, cmd, arg, zoran_do_ioctl);
+       return res;
 }
 
 static unsigned int
@@ -4191,11 +3062,11 @@ zoran_poll (struct file *file,
                        KERN_DEBUG
                        "%s: %s() raw - active=%c, sync_tail=%lu/%c, pend_tail=%lu, pend_head=%lu\n",
                        ZR_DEVNAME(zr), __func__,
-                       "FAL"[fh->v4l_buffers.active], zr->v4l_sync_tail,
+                       "FAL"[fh->buffers.active], zr->v4l_sync_tail,
                        "UPMD"[zr->v4l_buffers.buffer[frame].state],
                        zr->v4l_pend_tail, zr->v4l_pend_head);
                /* Process is the one capturing? */
-               if (fh->v4l_buffers.active != ZORAN_FREE &&
+               if (fh->buffers.active != ZORAN_FREE &&
                    /* Buffer ready to DQBUF? */
                    zr->v4l_buffers.buffer[frame].state == BUZ_STATE_DONE)
                        res = POLLIN | POLLRDNORM;
@@ -4213,10 +3084,10 @@ zoran_poll (struct file *file,
                        KERN_DEBUG
                        "%s: %s() jpg - active=%c, que_tail=%lu/%c, que_head=%lu, dma=%lu/%lu\n",
                        ZR_DEVNAME(zr), __func__,
-                       "FAL"[fh->jpg_buffers.active], zr->jpg_que_tail,
+                       "FAL"[fh->buffers.active], zr->jpg_que_tail,
                        "UPMD"[zr->jpg_buffers.buffer[frame].state],
                        zr->jpg_que_head, zr->jpg_dma_tail, zr->jpg_dma_head);
-               if (fh->jpg_buffers.active != ZORAN_FREE &&
+               if (fh->buffers.active != ZORAN_FREE &&
                    zr->jpg_buffers.buffer[frame].state == BUZ_STATE_DONE) {
                        if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC)
                                res = POLLIN | POLLRDNORM;
@@ -4230,8 +3101,8 @@ zoran_poll (struct file *file,
        default:
                dprintk(1,
                        KERN_ERR
-                       "%s: zoran_poll() - internal error, unknown map_mode=%d\n",
-                       ZR_DEVNAME(zr), fh->map_mode);
+                       "%s: %s - internal error, unknown map_mode=%d\n",
+                       ZR_DEVNAME(zr), __func__, fh->map_mode);
                res = POLLNVAL;
        }
 
@@ -4265,98 +3136,53 @@ static void
 zoran_vm_close (struct vm_area_struct *vma)
 {
        struct zoran_mapping *map = vma->vm_private_data;
-       struct file *file = map->file;
-       struct zoran_fh *fh = file->private_data;
+       struct zoran_fh *fh = map->file->private_data;
        struct zoran *zr = fh->zr;
        int i;
 
-       map->count--;
-       if (map->count == 0) {
-               switch (fh->map_mode) {
-               case ZORAN_MAP_MODE_JPG_REC:
-               case ZORAN_MAP_MODE_JPG_PLAY:
-
-                       dprintk(3, KERN_INFO "%s: munmap(MJPEG)\n",
-                               ZR_DEVNAME(zr));
-
-                       for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
-                               if (fh->jpg_buffers.buffer[i].map == map) {
-                                       fh->jpg_buffers.buffer[i].map =
-                                           NULL;
-                               }
-                       }
-                       kfree(map);
-
-                       for (i = 0; i < fh->jpg_buffers.num_buffers; i++)
-                               if (fh->jpg_buffers.buffer[i].map)
-                                       break;
-                       if (i == fh->jpg_buffers.num_buffers) {
-                               mutex_lock(&zr->resource_lock);
-
-                               if (fh->jpg_buffers.active != ZORAN_FREE) {
-                                       jpg_qbuf(file, -1, zr->codec_mode);
-                                       zr->jpg_buffers.allocated = 0;
-                                       zr->jpg_buffers.active =
-                                           fh->jpg_buffers.active =
-                                           ZORAN_FREE;
-                               }
-                               //jpg_fbuffer_free(file);
-                               fh->jpg_buffers.allocated = 0;
-                               fh->jpg_buffers.ready_to_be_freed = 1;
-
-                               mutex_unlock(&zr->resource_lock);
-                       }
-
-                       break;
-
-               case ZORAN_MAP_MODE_RAW:
+       if (--map->count > 0)
+               return;
 
-                       dprintk(3, KERN_INFO "%s: munmap(V4L)\n",
-                               ZR_DEVNAME(zr));
+       dprintk(3, KERN_INFO "%s: %s - munmap(%s)\n", ZR_DEVNAME(zr),
+               __func__, mode_name(fh->map_mode));
 
-                       for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
-                               if (fh->v4l_buffers.buffer[i].map == map) {
-                                       /* unqueue/unmap */
-                                       fh->v4l_buffers.buffer[i].map =
-                                           NULL;
-                               }
-                       }
-                       kfree(map);
+       for (i = 0; i < fh->buffers.num_buffers; i++) {
+               if (fh->buffers.buffer[i].map == map)
+                       fh->buffers.buffer[i].map = NULL;
+       }
+       kfree(map);
 
-                       for (i = 0; i < fh->v4l_buffers.num_buffers; i++)
-                               if (fh->v4l_buffers.buffer[i].map)
-                                       break;
-                       if (i == fh->v4l_buffers.num_buffers) {
-                               mutex_lock(&zr->resource_lock);
-
-                               if (fh->v4l_buffers.active != ZORAN_FREE) {
-                                       unsigned long flags;
-
-                                       spin_lock_irqsave(&zr->spinlock, flags);
-                                       zr36057_set_memgrab(zr, 0);
-                                       zr->v4l_buffers.allocated = 0;
-                                       zr->v4l_buffers.active =
-                                           fh->v4l_buffers.active =
-                                           ZORAN_FREE;
-                                       spin_unlock_irqrestore(&zr->spinlock, flags);
-                               }
-                               //v4l_fbuffer_free(file);
-                               fh->v4l_buffers.allocated = 0;
-                               fh->v4l_buffers.ready_to_be_freed = 1;
+       /* Any buffers still mapped? */
+       for (i = 0; i < fh->buffers.num_buffers; i++)
+               if (fh->buffers.buffer[i].map)
+                       return;
 
-                               mutex_unlock(&zr->resource_lock);
-                       }
+       dprintk(3, KERN_INFO "%s: %s - free %s buffers\n", ZR_DEVNAME(zr),
+               __func__, mode_name(fh->map_mode));
 
-                       break;
+       mutex_lock(&zr->resource_lock);
 
-               default:
-                       printk(KERN_ERR
-                              "%s: munmap() - internal error - unknown map mode %d\n",
-                              ZR_DEVNAME(zr), fh->map_mode);
-                       break;
+       if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
+               if (fh->buffers.active != ZORAN_FREE) {
+                       unsigned long flags;
 
+                       spin_lock_irqsave(&zr->spinlock, flags);
+                       zr36057_set_memgrab(zr, 0);
+                       zr->v4l_buffers.allocated = 0;
+                       zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE;
+                       spin_unlock_irqrestore(&zr->spinlock, flags);
                }
+               v4l_fbuffer_free(fh);
+       } else {
+               if (fh->buffers.active != ZORAN_FREE) {
+                       jpg_qbuf(fh, -1, zr->codec_mode);
+                       zr->jpg_buffers.allocated = 0;
+                       zr->jpg_buffers.active = fh->buffers.active = ZORAN_FREE;
+               }
+               jpg_fbuffer_free(fh);
        }
+
+       mutex_unlock(&zr->resource_lock);
 }
 
 static struct vm_operations_struct zoran_vm_ops = {
@@ -4379,90 +3205,106 @@ zoran_mmap (struct file           *file,
        int res = 0;
 
        dprintk(3,
-               KERN_INFO "%s: mmap(%s) of 0x%08lx-0x%08lx (size=%lu)\n",
-               ZR_DEVNAME(zr),
-               fh->map_mode == ZORAN_MAP_MODE_RAW ? "V4L" : "MJPEG",
-               vma->vm_start, vma->vm_end, size);
+               KERN_INFO "%s: %s(%s) of 0x%08lx-0x%08lx (size=%lu)\n",
+               ZR_DEVNAME(zr), __func__,
+               mode_name(fh->map_mode), vma->vm_start, vma->vm_end, size);
 
        if (!(vma->vm_flags & VM_SHARED) || !(vma->vm_flags & VM_READ) ||
            !(vma->vm_flags & VM_WRITE)) {
                dprintk(1,
                        KERN_ERR
-                       "%s: mmap() - no MAP_SHARED/PROT_{READ,WRITE} given\n",
-                       ZR_DEVNAME(zr));
+                       "%s: %s - no MAP_SHARED/PROT_{READ,WRITE} given\n",
+                       ZR_DEVNAME(zr), __func__);
                return -EINVAL;
        }
 
-       switch (fh->map_mode) {
+       mutex_lock(&zr->resource_lock);
 
-       case ZORAN_MAP_MODE_JPG_REC:
-       case ZORAN_MAP_MODE_JPG_PLAY:
+       if (!fh->buffers.allocated) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: %s(%s) - buffers not yet allocated\n",
+                       ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode));
+               res = -ENOMEM;
+               goto mmap_unlock_and_return;
+       }
 
-               /* lock */
-               mutex_lock(&zr->resource_lock);
+       first = offset / fh->buffers.buffer_size;
+       last = first - 1 + size / fh->buffers.buffer_size;
+       if (offset % fh->buffers.buffer_size != 0 ||
+           size % fh->buffers.buffer_size != 0 || first < 0 ||
+           last < 0 || first >= fh->buffers.num_buffers ||
+           last >= fh->buffers.buffer_size) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: %s(%s) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n",
+                       ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode), offset, size,
+                       fh->buffers.buffer_size,
+                       fh->buffers.num_buffers);
+               res = -EINVAL;
+               goto mmap_unlock_and_return;
+       }
 
-               /* Map the MJPEG buffers */
-               if (!fh->jpg_buffers.allocated) {
+       /* Check if any buffers are already mapped */
+       for (i = first; i <= last; i++) {
+               if (fh->buffers.buffer[i].map) {
                        dprintk(1,
                                KERN_ERR
-                               "%s: zoran_mmap(MJPEG) - buffers not yet allocated\n",
-                               ZR_DEVNAME(zr));
-                       res = -ENOMEM;
-                       goto jpg_mmap_unlock_and_return;
+                               "%s: %s(%s) - buffer %d already mapped\n",
+                               ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode), i);
+                       res = -EBUSY;
+                       goto mmap_unlock_and_return;
                }
+       }
 
-               first = offset / fh->jpg_buffers.buffer_size;
-               last = first - 1 + size / fh->jpg_buffers.buffer_size;
-               if (offset % fh->jpg_buffers.buffer_size != 0 ||
-                   size % fh->jpg_buffers.buffer_size != 0 || first < 0 ||
-                   last < 0 || first >= fh->jpg_buffers.num_buffers ||
-                   last >= fh->jpg_buffers.num_buffers) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: mmap(MJPEG) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n",
-                               ZR_DEVNAME(zr), offset, size,
-                               fh->jpg_buffers.buffer_size,
-                               fh->jpg_buffers.num_buffers);
-                       res = -EINVAL;
-                       goto jpg_mmap_unlock_and_return;
-               }
+       /* map these buffers */
+       map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL);
+       if (!map) {
+               res = -ENOMEM;
+               goto mmap_unlock_and_return;
+       }
+       map->file = file;
+       map->count = 1;
+
+       vma->vm_ops = &zoran_vm_ops;
+       vma->vm_flags |= VM_DONTEXPAND;
+       vma->vm_private_data = map;
+
+       if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
                for (i = first; i <= last; i++) {
-                       if (fh->jpg_buffers.buffer[i].map) {
+                       todo = size;
+                       if (todo > fh->buffers.buffer_size)
+                               todo = fh->buffers.buffer_size;
+                       page = fh->buffers.buffer[i].v4l.fbuffer_phys;
+                       if (remap_pfn_range(vma, start, page >> PAGE_SHIFT,
+                                                       todo, PAGE_SHARED)) {
                                dprintk(1,
                                        KERN_ERR
-                                       "%s: mmap(MJPEG) - buffer %d already mapped\n",
-                                       ZR_DEVNAME(zr), i);
-                               res = -EBUSY;
-                               goto jpg_mmap_unlock_and_return;
+                                       "%s: %s(V4L) - remap_pfn_range failed\n",
+                                       ZR_DEVNAME(zr), __func__);
+                               res = -EAGAIN;
+                               goto mmap_unlock_and_return;
                        }
+                       size -= todo;
+                       start += todo;
+                       fh->buffers.buffer[i].map = map;
+                       if (size == 0)
+                               break;
                }
-
-               /* map these buffers (v4l_buffers[i]) */
-               map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL);
-               if (!map) {
-                       res = -ENOMEM;
-                       goto jpg_mmap_unlock_and_return;
-               }
-               map->file = file;
-               map->count = 1;
-
-               vma->vm_ops = &zoran_vm_ops;
-               vma->vm_flags |= VM_DONTEXPAND;
-               vma->vm_private_data = map;
-
+       } else {
                for (i = first; i <= last; i++) {
                        for (j = 0;
-                            j < fh->jpg_buffers.buffer_size / PAGE_SIZE;
+                            j < fh->buffers.buffer_size / PAGE_SIZE;
                             j++) {
                                fraglen =
-                                   (le32_to_cpu(fh->jpg_buffers.buffer[i].
+                                   (le32_to_cpu(fh->buffers.buffer[i].jpg.
                                     frag_tab[2 * j + 1]) & ~1) << 1;
                                todo = size;
                                if (todo > fraglen)
                                        todo = fraglen;
                                pos =
-                                   le32_to_cpu(fh->jpg_buffers.
-                                   buffer[i].frag_tab[2 * j]);
+                                   le32_to_cpu(fh->buffers.
+                                   buffer[i].jpg.frag_tab[2 * j]);
                                /* should just be pos on i386 */
                                page = virt_to_phys(bus_to_virt(pos))
                                                                >> PAGE_SHIFT;
@@ -4470,123 +3312,82 @@ zoran_mmap (struct file           *file,
                                                        todo, PAGE_SHARED)) {
                                        dprintk(1,
                                                KERN_ERR
-                                               "%s: zoran_mmap(V4L) - remap_pfn_range failed\n",
-                                               ZR_DEVNAME(zr));
+                                               "%s: %s(V4L) - remap_pfn_range failed\n",
+                                               ZR_DEVNAME(zr), __func__);
                                        res = -EAGAIN;
-                                       goto jpg_mmap_unlock_and_return;
+                                       goto mmap_unlock_and_return;
                                }
                                size -= todo;
                                start += todo;
                                if (size == 0)
                                        break;
-                               if (le32_to_cpu(fh->jpg_buffers.buffer[i].
+                               if (le32_to_cpu(fh->buffers.buffer[i].jpg.
                                    frag_tab[2 * j + 1]) & 1)
                                        break;  /* was last fragment */
                        }
-                       fh->jpg_buffers.buffer[i].map = map;
+                       fh->buffers.buffer[i].map = map;
                        if (size == 0)
                                break;
 
                }
-       jpg_mmap_unlock_and_return:
-               mutex_unlock(&zr->resource_lock);
-
-               break;
-
-       case ZORAN_MAP_MODE_RAW:
-
-               mutex_lock(&zr->resource_lock);
-
-               /* Map the V4L buffers */
-               if (!fh->v4l_buffers.allocated) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: zoran_mmap(V4L) - buffers not yet allocated\n",
-                               ZR_DEVNAME(zr));
-                       res = -ENOMEM;
-                       goto v4l_mmap_unlock_and_return;
-               }
-
-               first = offset / fh->v4l_buffers.buffer_size;
-               last = first - 1 + size / fh->v4l_buffers.buffer_size;
-               if (offset % fh->v4l_buffers.buffer_size != 0 ||
-                   size % fh->v4l_buffers.buffer_size != 0 || first < 0 ||
-                   last < 0 || first >= fh->v4l_buffers.num_buffers ||
-                   last >= fh->v4l_buffers.buffer_size) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: mmap(V4L) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n",
-                               ZR_DEVNAME(zr), offset, size,
-                               fh->v4l_buffers.buffer_size,
-                               fh->v4l_buffers.num_buffers);
-                       res = -EINVAL;
-                       goto v4l_mmap_unlock_and_return;
-               }
-               for (i = first; i <= last; i++) {
-                       if (fh->v4l_buffers.buffer[i].map) {
-                               dprintk(1,
-                                       KERN_ERR
-                                       "%s: mmap(V4L) - buffer %d already mapped\n",
-                                       ZR_DEVNAME(zr), i);
-                               res = -EBUSY;
-                               goto v4l_mmap_unlock_and_return;
-                       }
-               }
-
-               /* map these buffers (v4l_buffers[i]) */
-               map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL);
-               if (!map) {
-                       res = -ENOMEM;
-                       goto v4l_mmap_unlock_and_return;
-               }
-               map->file = file;
-               map->count = 1;
-
-               vma->vm_ops = &zoran_vm_ops;
-               vma->vm_flags |= VM_DONTEXPAND;
-               vma->vm_private_data = map;
-
-               for (i = first; i <= last; i++) {
-                       todo = size;
-                       if (todo > fh->v4l_buffers.buffer_size)
-                               todo = fh->v4l_buffers.buffer_size;
-                       page = fh->v4l_buffers.buffer[i].fbuffer_phys;
-                       if (remap_pfn_range(vma, start, page >> PAGE_SHIFT,
-                                                       todo, PAGE_SHARED)) {
-                               dprintk(1,
-                                       KERN_ERR
-                                       "%s: zoran_mmap(V4L)i - remap_pfn_range failed\n",
-                                       ZR_DEVNAME(zr));
-                               res = -EAGAIN;
-                               goto v4l_mmap_unlock_and_return;
-                       }
-                       size -= todo;
-                       start += todo;
-                       fh->v4l_buffers.buffer[i].map = map;
-                       if (size == 0)
-                               break;
-               }
-       v4l_mmap_unlock_and_return:
-               mutex_unlock(&zr->resource_lock);
-
-               break;
-
-       default:
-               dprintk(1,
-                       KERN_ERR
-                       "%s: zoran_mmap() - internal error - unknown map mode %d\n",
-                       ZR_DEVNAME(zr), fh->map_mode);
-               break;
        }
 
+mmap_unlock_and_return:
+       mutex_unlock(&zr->resource_lock);
+
        return 0;
 }
 
+static const struct v4l2_ioctl_ops zoran_ioctl_ops = {
+       .vidioc_querycap                    = zoran_querycap,
+       .vidioc_cropcap                     = zoran_cropcap,
+       .vidioc_s_crop                      = zoran_s_crop,
+       .vidioc_g_crop                      = zoran_g_crop,
+       .vidioc_enum_input                  = zoran_enum_input,
+       .vidioc_g_input                     = zoran_g_input,
+       .vidioc_s_input                     = zoran_s_input,
+       .vidioc_enum_output                 = zoran_enum_output,
+       .vidioc_g_output                    = zoran_g_output,
+       .vidioc_s_output                    = zoran_s_output,
+       .vidioc_g_fbuf                      = zoran_g_fbuf,
+       .vidioc_s_fbuf                      = zoran_s_fbuf,
+       .vidioc_g_std                       = zoran_g_std,
+       .vidioc_s_std                       = zoran_s_std,
+       .vidioc_g_jpegcomp                  = zoran_g_jpegcomp,
+       .vidioc_s_jpegcomp                  = zoran_s_jpegcomp,
+       .vidioc_overlay                     = zoran_overlay,
+       .vidioc_reqbufs                     = zoran_reqbufs,
+       .vidioc_querybuf                    = zoran_querybuf,
+       .vidioc_qbuf                        = zoran_qbuf,
+       .vidioc_dqbuf                       = zoran_dqbuf,
+       .vidioc_streamon                    = zoran_streamon,
+       .vidioc_streamoff                   = zoran_streamoff,
+       .vidioc_enum_fmt_vid_cap            = zoran_enum_fmt_vid_cap,
+       .vidioc_enum_fmt_vid_out            = zoran_enum_fmt_vid_out,
+       .vidioc_enum_fmt_vid_overlay        = zoran_enum_fmt_vid_overlay,
+       .vidioc_g_fmt_vid_cap               = zoran_g_fmt_vid_cap,
+       .vidioc_g_fmt_vid_out               = zoran_g_fmt_vid_out,
+       .vidioc_g_fmt_vid_overlay           = zoran_g_fmt_vid_overlay,
+       .vidioc_s_fmt_vid_cap               = zoran_s_fmt_vid_cap,
+       .vidioc_s_fmt_vid_out               = zoran_s_fmt_vid_out,
+       .vidioc_s_fmt_vid_overlay           = zoran_s_fmt_vid_overlay,
+       .vidioc_try_fmt_vid_cap             = zoran_try_fmt_vid_cap,
+       .vidioc_try_fmt_vid_out             = zoran_try_fmt_vid_out,
+       .vidioc_try_fmt_vid_overlay         = zoran_try_fmt_vid_overlay,
+       .vidioc_queryctrl                   = zoran_queryctrl,
+       .vidioc_s_ctrl                      = zoran_s_ctrl,
+       .vidioc_g_ctrl                      = zoran_g_ctrl,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+       .vidioc_default                     = zoran_default,
+       .vidiocgmbuf                        = zoran_vidiocgmbuf,
+#endif
+};
+
 static const struct v4l2_file_operations zoran_fops = {
        .owner = THIS_MODULE,
        .open = zoran_open,
        .release = zoran_close,
-       .ioctl = zoran_ioctl,
+       .ioctl = video_ioctl2,
        .read = zoran_read,
        .write = zoran_write,
        .mmap = zoran_mmap,
@@ -4596,7 +3397,9 @@ static const struct v4l2_file_operations zoran_fops = {
 struct video_device zoran_template __devinitdata = {
        .name = ZORAN_NAME,
        .fops = &zoran_fops,
+       .ioctl_ops = &zoran_ioctl_ops,
        .release = &zoran_vdev_release,
+       .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
        .minor = -1
 };
 
index 870bc5a70e3fdf7fb41f12b5142bba4c050722c4..f1423b777db16e6447863cf1851ef892b9f09b95 100644 (file)
@@ -36,7 +36,7 @@
 #include <linux/pci.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/spinlock.h>
 #include <linux/sem.h>
 #include <linux/seq_file.h>
index 00d132bcd1e4fecb64860d9d165a61eedc547b29..21c088ea9046349d2cabb5d58355b01c9f85927f 100644 (file)
 #include <linux/types.h>
 #include <linux/wait.h>
 
-/* includes for structures and defines regarding video
-   #include<linux/videodev.h> */
-
 /* I/O commands, error codes */
 #include <asm/io.h>
-//#include<errno.h>
 
 /* v4l  API */
-#include <linux/videodev.h>
 
 /* headerfile of this module */
 #include"zr36016.h"
index cf8b271a1c8f1907e3885773ba5dad02d67f07cf..639dd87c663f01a6af22d62bb9a3d8ef960fc68e 100644 (file)
 #include <linux/types.h>
 #include <linux/wait.h>
 
-/* includes for structures and defines regarding video
-   #include<linux/videodev.h> */
-
 /* I/O commands, error codes */
 #include <asm/io.h>
-//#include<errno.h>
 
 /* headerfile of this module */
 #include "zr36050.h"
index 8e74054d5ef10ea0615fbf927f3e17b06c04a81e..008746ff7746a45f55856321bb2a24e2cdc375cc 100644 (file)
 #include <linux/types.h>
 #include <linux/wait.h>
 
-/* includes for structures and defines regarding video
-   #include<linux/videodev.h> */
-
 /* I/O commands, error codes */
 #include <asm/io.h>
-//#include<errno.h>
 
 /* headerfile of this module */
 #include "zr36060.h"
index 93023560f3242550f0ed2e026954cfcac9c0794c..221409fe168265f921bd0ff57b3f5271a58412d8 100644 (file)
@@ -96,6 +96,7 @@ static struct usb_device_id device_table[] = {
        {USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 },
        {USB_DEVICE(0x0a17, 0x004e), .driver_info = METHOD2 },
        {USB_DEVICE(0x041e, 0x405d), .driver_info = METHOD2 },
+       {USB_DEVICE(0x08ca, 0x2102), .driver_info = METHOD2 },
        {}                      /* Terminating entry */
 };
 
@@ -425,7 +426,6 @@ static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
 static int zr364xx_vidioc_querycap(struct file *file, void *priv,
                                   struct v4l2_capability *cap)
 {
-       memset(cap, 0, sizeof(*cap));
        strcpy(cap->driver, DRIVER_DESC);
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
        return 0;
@@ -436,8 +436,6 @@ static int zr364xx_vidioc_enum_input(struct file *file, void *priv,
 {
        if (i->index != 0)
                return -EINVAL;
-       memset(i, 0, sizeof(*i));
-       i->index = 0;
        strcpy(i->name, DRIVER_DESC " Camera");
        i->type = V4L2_INPUT_TYPE_CAMERA;
        return 0;
@@ -529,11 +527,6 @@ static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file,
 {
        if (f->index > 0)
                return -EINVAL;
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       memset(f, 0, sizeof(*f));
-       f->index = 0;
-       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        f->flags = V4L2_FMT_FLAG_COMPRESSED;
        strcpy(f->description, "JPEG");
        f->pixelformat = V4L2_PIX_FMT_JPEG;
@@ -550,8 +543,6 @@ static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                return -ENODEV;
        cam = video_get_drvdata(vdev);
 
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
        if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
                return -EINVAL;
        if (f->fmt.pix.field != V4L2_FIELD_ANY &&
@@ -577,10 +568,6 @@ static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
                return -ENODEV;
        cam = video_get_drvdata(vdev);
 
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
-       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        f->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
        f->fmt.pix.field = V4L2_FIELD_NONE;
        f->fmt.pix.width = cam->width;
@@ -602,8 +589,6 @@ static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                return -ENODEV;
        cam = video_get_drvdata(vdev);
 
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
        if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
                return -EINVAL;
        if (f->fmt.pix.field != V4L2_FIELD_ANY &&
index 9a36b5a7de5736365f356190877a6947f2048246..7045c45da9b160030fdd07859b373708656d2ea0 100644 (file)
@@ -2037,8 +2037,6 @@ static int __init i2o_proc_fs_create(void)
        if (!i2o_proc_dir_root)
                return -1;
 
-       i2o_proc_dir_root->owner = THIS_MODULE;
-
        list_for_each_entry(c, &i2o_controllers, list)
            i2o_proc_iop_add(i2o_proc_dir_root, c);
 
index 1c484084ed4f874c78cf7ccbf555350148a2a00c..0b92b2f6ea68d1b46aac012d0ec7efd1b599e36a 100644 (file)
@@ -165,7 +165,7 @@ config SGI_XP
        depends on (IA64_GENERIC || IA64_SGI_SN2 || IA64_SGI_UV || X86_UV) && SMP
        select IA64_UNCACHED_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2
        select GENERIC_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2
-       select SGI_GRU if (IA64_GENERIC || IA64_SGI_UV || X86_64) && SMP
+       select SGI_GRU if X86_64 && SMP
        ---help---
          An SGI machine can be divided into multiple Single System
          Images which act independently of each other and have
@@ -189,7 +189,7 @@ config HP_ILO
 
 config SGI_GRU
        tristate "SGI GRU driver"
-       depends on (X86_UV || IA64_SGI_UV || IA64_GENERIC) && SMP
+       depends on X86_UV && SMP
        default n
        select MMU_NOTIFIER
        ---help---
@@ -223,6 +223,16 @@ config DELL_LAPTOP
        This driver adds support for rfkill and backlight control to Dell
        laptops.
 
+config ISL29003
+       tristate "Intersil ISL29003 ambient light sensor"
+       depends on I2C && SYSFS
+       help
+         If you say yes here you get support for the Intersil ISL29003
+         ambient light sensor.
+
+         This driver can also be built as a module.  If so, the module
+         will be called isl29003.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 
index bc11998305544752f67b16ab587d14e725a870e2..7871f05dcb9b8d29804dbe7e68743c01369937da 100644 (file)
@@ -18,5 +18,6 @@ obj-$(CONFIG_KGDB_TESTS)      += kgdbts.o
 obj-$(CONFIG_SGI_XP)           += sgi-xp/
 obj-$(CONFIG_SGI_GRU)          += sgi-gru/
 obj-$(CONFIG_HP_ILO)           += hpilo.o
+obj-$(CONFIG_ISL29003)         += isl29003.o
 obj-$(CONFIG_C2PORT)           += c2port/
 obj-y                          += eeprom/
index d4775528abc69b2d4c4d580d712e48862ef7d1d7..d184dfab9631c0315ef40ed58d502136dc0055e2 100644 (file)
@@ -53,6 +53,7 @@
 
 struct at24_data {
        struct at24_platform_data chip;
+       struct memory_accessor macc;
        bool use_smbus;
 
        /*
@@ -225,14 +226,11 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
                return status;
 }
 
-static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr,
+static ssize_t at24_read(struct at24_data *at24,
                char *buf, loff_t off, size_t count)
 {
-       struct at24_data *at24;
        ssize_t retval = 0;
 
-       at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
-
        if (unlikely(!count))
                return count;
 
@@ -262,12 +260,14 @@ static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr,
        return retval;
 }
 
+static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count)
+{
+       struct at24_data *at24;
 
-/*
- * REVISIT: export at24_bin{read,write}() to let other kernel code use
- * eeprom data. For example, it might hold a board's Ethernet address, or
- * board-specific calibration data generated on the manufacturing floor.
- */
+       at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
+       return at24_read(at24, buf, off, count);
+}
 
 
 /*
@@ -347,14 +347,11 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, char *buf,
        return -ETIMEDOUT;
 }
 
-static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr,
+static ssize_t at24_write(struct at24_data *at24,
                char *buf, loff_t off, size_t count)
 {
-       struct at24_data *at24;
        ssize_t retval = 0;
 
-       at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
-
        if (unlikely(!count))
                return count;
 
@@ -384,6 +381,39 @@ static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr,
        return retval;
 }
 
+static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count)
+{
+       struct at24_data *at24;
+
+       at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
+       return at24_write(at24, buf, off, count);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * This lets other kernel code access the eeprom data. For example, it
+ * might hold a board's Ethernet address, or board-specific calibration
+ * data generated on the manufacturing floor.
+ */
+
+static ssize_t at24_macc_read(struct memory_accessor *macc, char *buf,
+                        off_t offset, size_t count)
+{
+       struct at24_data *at24 = container_of(macc, struct at24_data, macc);
+
+       return at24_read(at24, buf, offset, count);
+}
+
+static ssize_t at24_macc_write(struct memory_accessor *macc, char *buf,
+                         off_t offset, size_t count)
+{
+       struct at24_data *at24 = container_of(macc, struct at24_data, macc);
+
+       return at24_write(at24, buf, offset, count);
+}
+
 /*-------------------------------------------------------------------------*/
 
 static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
@@ -413,6 +443,9 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
                 * is recommended anyhow.
                 */
                chip.page_size = 1;
+
+               chip.setup = NULL;
+               chip.context = NULL;
        }
 
        if (!is_power_of_2(chip.byte_len))
@@ -463,6 +496,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
        at24->bin.read = at24_bin_read;
        at24->bin.size = chip.byte_len;
 
+       at24->macc.read = at24_macc_read;
+
        writable = !(chip.flags & AT24_FLAG_READONLY);
        if (writable) {
                if (!use_smbus || i2c_check_functionality(client->adapter,
@@ -470,6 +505,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
                        unsigned write_max = chip.page_size;
 
+                       at24->macc.write = at24_macc_write;
+
                        at24->bin.write = at24_bin_write;
                        at24->bin.attr.mode |= S_IWUSR;
 
@@ -520,6 +557,10 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
                at24->write_max,
                use_smbus ? ", use_smbus" : "");
 
+       /* export data to kernel code */
+       if (chip.setup)
+               chip.setup(&at24->macc, chip.context);
+
        return 0;
 
 err_clients:
index 290dbe99647a141125a4465170343c51c770ec02..6bc0dac5c1e8f425f6390495220cc4572cea8037 100644 (file)
@@ -30,6 +30,7 @@
 
 struct at25_data {
        struct spi_device       *spi;
+       struct memory_accessor  mem;
        struct mutex            lock;
        struct spi_eeprom       chip;
        struct bin_attribute    bin;
@@ -75,6 +76,13 @@ at25_ee_read(
        struct spi_transfer     t[2];
        struct spi_message      m;
 
+       if (unlikely(offset >= at25->bin.size))
+               return 0;
+       if ((offset + count) > at25->bin.size)
+               count = at25->bin.size - offset;
+       if (unlikely(!count))
+               return count;
+
        cp = command;
        *cp++ = AT25_READ;
 
@@ -127,13 +135,6 @@ at25_bin_read(struct kobject *kobj, struct bin_attribute *bin_attr,
        dev = container_of(kobj, struct device, kobj);
        at25 = dev_get_drvdata(dev);
 
-       if (unlikely(off >= at25->bin.size))
-               return 0;
-       if ((off + count) > at25->bin.size)
-               count = at25->bin.size - off;
-       if (unlikely(!count))
-               return count;
-
        return at25_ee_read(at25, buf, off, count);
 }
 
@@ -146,6 +147,13 @@ at25_ee_write(struct at25_data *at25, char *buf, loff_t off, size_t count)
        unsigned                buf_size;
        u8                      *bounce;
 
+       if (unlikely(off >= at25->bin.size))
+               return -EFBIG;
+       if ((off + count) > at25->bin.size)
+               count = at25->bin.size - off;
+       if (unlikely(!count))
+               return count;
+
        /* Temp buffer starts with command and address */
        buf_size = at25->chip.page_size;
        if (buf_size > io_limit)
@@ -253,18 +261,31 @@ at25_bin_write(struct kobject *kobj, struct bin_attribute *bin_attr,
        dev = container_of(kobj, struct device, kobj);
        at25 = dev_get_drvdata(dev);
 
-       if (unlikely(off >= at25->bin.size))
-               return -EFBIG;
-       if ((off + count) > at25->bin.size)
-               count = at25->bin.size - off;
-       if (unlikely(!count))
-               return count;
-
        return at25_ee_write(at25, buf, off, count);
 }
 
 /*-------------------------------------------------------------------------*/
 
+/* Let in-kernel code access the eeprom data. */
+
+static ssize_t at25_mem_read(struct memory_accessor *mem, char *buf,
+                        off_t offset, size_t count)
+{
+       struct at25_data *at25 = container_of(mem, struct at25_data, mem);
+
+       return at25_ee_read(at25, buf, offset, count);
+}
+
+static ssize_t at25_mem_write(struct memory_accessor *mem, char *buf,
+                         off_t offset, size_t count)
+{
+       struct at25_data *at25 = container_of(mem, struct at25_data, mem);
+
+       return at25_ee_write(at25, buf, offset, count);
+}
+
+/*-------------------------------------------------------------------------*/
+
 static int at25_probe(struct spi_device *spi)
 {
        struct at25_data        *at25 = NULL;
@@ -317,6 +338,10 @@ static int at25_probe(struct spi_device *spi)
        at25->addrlen = addrlen;
 
        /* Export the EEPROM bytes through sysfs, since that's convenient.
+        * And maybe to other kernel code; it might hold a board's Ethernet
+        * address, or board-specific calibration data generated on the
+        * manufacturing floor.
+        *
         * Default to root-only access to the data; EEPROMs often hold data
         * that's sensitive for read and/or write, like ethernet addresses,
         * security codes, board-specific manufacturing calibrations, etc.
@@ -324,17 +349,22 @@ static int at25_probe(struct spi_device *spi)
        at25->bin.attr.name = "eeprom";
        at25->bin.attr.mode = S_IRUSR;
        at25->bin.read = at25_bin_read;
+       at25->mem.read = at25_mem_read;
 
        at25->bin.size = at25->chip.byte_len;
        if (!(chip->flags & EE_READONLY)) {
                at25->bin.write = at25_bin_write;
                at25->bin.attr.mode |= S_IWUSR;
+               at25->mem.write = at25_mem_write;
        }
 
        err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);
        if (err)
                goto fail;
 
+       if (chip->setup)
+               chip->setup(&at25->mem, chip->context);
+
        dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",
                (at25->bin.size < 1024)
                        ? at25->bin.size
index cf991850f01ba04b23ad40b1ded35747735b0bf4..880ccf39e23b1f70c83d26883c9a169ce76281f0 100644 (file)
@@ -209,7 +209,7 @@ static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data)
        /* give iLO some time to process stop request */
        for (retries = MAX_WAIT; retries > 0; retries--) {
                doorbell_set(driver_ccb);
-               udelay(1);
+               udelay(WAIT_TIME);
                if (!(ioread32(&device_ccb->send_ctrl) & (1 << CTRL_BITPOS_A))
                    &&
                    !(ioread32(&device_ccb->recv_ctrl) & (1 << CTRL_BITPOS_A)))
@@ -312,7 +312,7 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
        for (i = MAX_WAIT; i > 0; i--) {
                if (ilo_pkt_dequeue(hw, driver_ccb, SENDQ, &pkt_id, NULL, NULL))
                        break;
-               udelay(1);
+               udelay(WAIT_TIME);
        }
 
        if (i) {
@@ -759,7 +759,7 @@ static void __exit ilo_exit(void)
        class_destroy(ilo_class);
 }
 
-MODULE_VERSION("1.0");
+MODULE_VERSION("1.1");
 MODULE_ALIAS(ILO_NAME);
 MODULE_DESCRIPTION(ILO_NAME);
 MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>");
index b64a20ef07e3cc6e7280386b5dc462233e1fd99a..03a14c82aad9bc9f0588cb3ee974ea5e2d8cd493 100644 (file)
 #define MAX_ILO_DEV    1
 /* max number of files */
 #define MAX_OPEN       (MAX_CCB * MAX_ILO_DEV)
+/* total wait time in usec */
+#define MAX_WAIT_TIME  10000
+/* per spin wait time in usec */
+#define WAIT_TIME      10
 /* spin counter for open/close delay */
-#define MAX_WAIT       10000
+#define MAX_WAIT       (MAX_WAIT_TIME / WAIT_TIME)
 
 /*
  * Per device, used to track global memory allocations.
diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c
new file mode 100644 (file)
index 0000000..2e2a592
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ *  isl29003.c - Linux kernel module for
+ *     Intersil ISL29003 ambient light sensor
+ *
+ *  See file:Documentation/misc-devices/isl29003
+ *
+ *  Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ *  Based on code written by
+ *     Rodolfo Giometti <giometti@linux.it>
+ *     Eurotech S.p.A. <info@eurotech.it>
+ *
+ *  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/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#define ISL29003_DRV_NAME      "isl29003"
+#define DRIVER_VERSION         "1.0"
+
+#define ISL29003_REG_COMMAND           0x00
+#define ISL29003_ADC_ENABLED           (1 << 7)
+#define ISL29003_ADC_PD                        (1 << 6)
+#define ISL29003_TIMING_INT            (1 << 5)
+#define ISL29003_MODE_SHIFT            (2)
+#define ISL29003_MODE_MASK             (0x3 << ISL29003_MODE_SHIFT)
+#define ISL29003_RES_SHIFT             (0)
+#define ISL29003_RES_MASK              (0x3 << ISL29003_RES_SHIFT)
+
+#define ISL29003_REG_CONTROL           0x01
+#define ISL29003_INT_FLG               (1 << 5)
+#define ISL29003_RANGE_SHIFT           (2)
+#define ISL29003_RANGE_MASK            (0x3 << ISL29003_RANGE_SHIFT)
+#define ISL29003_INT_PERSISTS_SHIFT    (0)
+#define ISL29003_INT_PERSISTS_MASK     (0xf << ISL29003_INT_PERSISTS_SHIFT)
+
+#define ISL29003_REG_IRQ_THRESH_HI     0x02
+#define ISL29003_REG_IRQ_THRESH_LO     0x03
+#define ISL29003_REG_LSB_SENSOR                0x04
+#define ISL29003_REG_MSB_SENSOR                0x05
+#define ISL29003_REG_LSB_TIMER         0x06
+#define ISL29003_REG_MSB_TIMER         0x07
+
+#define ISL29003_NUM_CACHABLE_REGS     4
+
+struct isl29003_data {
+       struct i2c_client *client;
+       struct mutex lock;
+       u8 reg_cache[ISL29003_NUM_CACHABLE_REGS];
+};
+
+static int gain_range[] = {
+       1000, 4000, 16000, 64000
+};
+
+/*
+ * register access helpers
+ */
+
+static int __isl29003_read_reg(struct i2c_client *client,
+                              u32 reg, u8 mask, u8 shift)
+{
+       struct isl29003_data *data = i2c_get_clientdata(client);
+       return (data->reg_cache[reg] & mask) >> shift;
+}
+
+static int __isl29003_write_reg(struct i2c_client *client,
+                               u32 reg, u8 mask, u8 shift, u8 val)
+{
+       struct isl29003_data *data = i2c_get_clientdata(client);
+       int ret = 0;
+       u8 tmp;
+
+       if (reg >= ISL29003_NUM_CACHABLE_REGS)
+               return -EINVAL;
+
+       mutex_lock(&data->lock);
+
+       tmp = data->reg_cache[reg];
+       tmp &= ~mask;
+       tmp |= val << shift;
+
+       ret = i2c_smbus_write_byte_data(client, reg, tmp);
+       if (!ret)
+               data->reg_cache[reg] = tmp;
+
+       mutex_unlock(&data->lock);
+       return ret;
+}
+
+/*
+ * internally used functions
+ */
+
+/* range */
+static int isl29003_get_range(struct i2c_client *client)
+{
+       return __isl29003_read_reg(client, ISL29003_REG_CONTROL,
+               ISL29003_RANGE_MASK, ISL29003_RANGE_SHIFT);
+}
+
+static int isl29003_set_range(struct i2c_client *client, int range)
+{
+       return __isl29003_write_reg(client, ISL29003_REG_CONTROL,
+               ISL29003_RANGE_MASK, ISL29003_RANGE_SHIFT, range);
+}
+
+/* resolution */
+static int isl29003_get_resolution(struct i2c_client *client)
+{
+       return __isl29003_read_reg(client, ISL29003_REG_COMMAND,
+               ISL29003_RES_MASK, ISL29003_RES_SHIFT);
+}
+
+static int isl29003_set_resolution(struct i2c_client *client, int res)
+{
+       return __isl29003_write_reg(client, ISL29003_REG_COMMAND,
+               ISL29003_RES_MASK, ISL29003_RES_SHIFT, res);
+}
+
+/* mode */
+static int isl29003_get_mode(struct i2c_client *client)
+{
+       return __isl29003_read_reg(client, ISL29003_REG_COMMAND,
+               ISL29003_RES_MASK, ISL29003_RES_SHIFT);
+}
+
+static int isl29003_set_mode(struct i2c_client *client, int mode)
+{
+       return __isl29003_write_reg(client, ISL29003_REG_COMMAND,
+               ISL29003_RES_MASK, ISL29003_RES_SHIFT, mode);
+}
+
+/* power_state */
+static int isl29003_set_power_state(struct i2c_client *client, int state)
+{
+       return __isl29003_write_reg(client, ISL29003_REG_COMMAND,
+                               ISL29003_ADC_ENABLED | ISL29003_ADC_PD, 0,
+                               state ? ISL29003_ADC_ENABLED : ISL29003_ADC_PD);
+}
+
+static int isl29003_get_power_state(struct i2c_client *client)
+{
+       struct isl29003_data *data = i2c_get_clientdata(client);
+       u8 cmdreg = data->reg_cache[ISL29003_REG_COMMAND];
+       return ~cmdreg & ISL29003_ADC_PD;
+}
+
+static int isl29003_get_adc_value(struct i2c_client *client)
+{
+       struct isl29003_data *data = i2c_get_clientdata(client);
+       int lsb, msb, range, bitdepth;
+
+       mutex_lock(&data->lock);
+       lsb = i2c_smbus_read_byte_data(client, ISL29003_REG_LSB_SENSOR);
+
+       if (lsb < 0) {
+               mutex_unlock(&data->lock);
+               return lsb;
+       }
+
+       msb = i2c_smbus_read_byte_data(client, ISL29003_REG_MSB_SENSOR);
+       mutex_unlock(&data->lock);
+
+       if (msb < 0)
+               return msb;
+
+       range = isl29003_get_range(client);
+       bitdepth = (4 - isl29003_get_resolution(client)) * 4;
+       return (((msb << 8) | lsb) * gain_range[range]) >> bitdepth;
+}
+
+/*
+ * sysfs layer
+ */
+
+/* range */
+static ssize_t isl29003_show_range(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       return sprintf(buf, "%i\n", isl29003_get_range(client));
+}
+
+static ssize_t isl29003_store_range(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned long val;
+       int ret;
+
+       if ((strict_strtoul(buf, 10, &val) < 0) || (val > 3))
+               return -EINVAL;
+
+       ret = isl29003_set_range(client, val);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static DEVICE_ATTR(range, S_IWUSR | S_IRUGO,
+                  isl29003_show_range, isl29003_store_range);
+
+
+/* resolution */
+static ssize_t isl29003_show_resolution(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       return sprintf(buf, "%d\n", isl29003_get_resolution(client));
+}
+
+static ssize_t isl29003_store_resolution(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned long val;
+       int ret;
+
+       if ((strict_strtoul(buf, 10, &val) < 0) || (val > 3))
+               return -EINVAL;
+
+       ret = isl29003_set_resolution(client, val);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static DEVICE_ATTR(resolution, S_IWUSR | S_IRUGO,
+                  isl29003_show_resolution, isl29003_store_resolution);
+
+/* mode */
+static ssize_t isl29003_show_mode(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       return sprintf(buf, "%d\n", isl29003_get_mode(client));
+}
+
+static ssize_t isl29003_store_mode(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned long val;
+       int ret;
+
+       if ((strict_strtoul(buf, 10, &val) < 0) || (val > 2))
+               return -EINVAL;
+
+       ret = isl29003_set_mode(client, val);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO,
+                  isl29003_show_mode, isl29003_store_mode);
+
+
+/* power state */
+static ssize_t isl29003_show_power_state(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       return sprintf(buf, "%d\n", isl29003_get_power_state(client));
+}
+
+static ssize_t isl29003_store_power_state(struct device *dev,
+                                         struct device_attribute *attr,
+                                         const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned long val;
+       int ret;
+
+       if ((strict_strtoul(buf, 10, &val) < 0) || (val > 1))
+               return -EINVAL;
+
+       ret = isl29003_set_power_state(client, val);
+       return ret ? ret : count;
+}
+
+static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
+                  isl29003_show_power_state, isl29003_store_power_state);
+
+
+/* lux */
+static ssize_t isl29003_show_lux(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       /* No LUX data if not operational */
+       if (!isl29003_get_power_state(client))
+               return -EBUSY;
+
+       return sprintf(buf, "%d\n", isl29003_get_adc_value(client));
+}
+
+static DEVICE_ATTR(lux, S_IRUGO, isl29003_show_lux, NULL);
+
+static struct attribute *isl29003_attributes[] = {
+       &dev_attr_range.attr,
+       &dev_attr_resolution.attr,
+       &dev_attr_mode.attr,
+       &dev_attr_power_state.attr,
+       &dev_attr_lux.attr,
+       NULL
+};
+
+static const struct attribute_group isl29003_attr_group = {
+       .attrs = isl29003_attributes,
+};
+
+static int isl29003_init_client(struct i2c_client *client)
+{
+       struct isl29003_data *data = i2c_get_clientdata(client);
+       int i;
+
+       /* read all the registers once to fill the cache.
+        * if one of the reads fails, we consider the init failed */
+       for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) {
+               int v = i2c_smbus_read_byte_data(client, i);
+               if (v < 0)
+                       return -ENODEV;
+
+               data->reg_cache[i] = v;
+       }
+
+       /* set defaults */
+       isl29003_set_range(client, 0);
+       isl29003_set_resolution(client, 0);
+       isl29003_set_mode(client, 0);
+       isl29003_set_power_state(client, 0);
+
+       return 0;
+}
+
+/*
+ * I2C layer
+ */
+
+static int __devinit isl29003_probe(struct i2c_client *client,
+                                   const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct isl29003_data *data;
+       int err = 0;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
+               return -EIO;
+
+       data = kzalloc(sizeof(struct isl29003_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->client = client;
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->lock);
+
+       /* initialize the ISL29003 chip */
+       err = isl29003_init_client(client);
+       if (err)
+               goto exit_kfree;
+
+       /* register sysfs hooks */
+       err = sysfs_create_group(&client->dev.kobj, &isl29003_attr_group);
+       if (err)
+               goto exit_kfree;
+
+       dev_info(&client->dev, "driver version %s enabled\n", DRIVER_VERSION);
+       return 0;
+
+exit_kfree:
+       kfree(data);
+       return err;
+}
+
+static int __devexit isl29003_remove(struct i2c_client *client)
+{
+       sysfs_remove_group(&client->dev.kobj, &isl29003_attr_group);
+       isl29003_set_power_state(client, 0);
+       kfree(i2c_get_clientdata(client));
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int isl29003_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+       return isl29003_set_power_state(client, 0);
+}
+
+static int isl29003_resume(struct i2c_client *client)
+{
+       int i;
+       struct isl29003_data *data = i2c_get_clientdata(client);
+
+       /* restore registers from cache */
+       for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++)
+               if (!i2c_smbus_write_byte_data(client, i, data->reg_cache[i]))
+                       return -EIO;
+
+       return 0;
+}
+
+#else
+#define isl29003_suspend       NULL
+#define isl29003_resume                NULL
+#endif /* CONFIG_PM */
+
+static const struct i2c_device_id isl29003_id[] = {
+       { "isl29003", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, isl29003_id);
+
+static struct i2c_driver isl29003_driver = {
+       .driver = {
+               .name   = ISL29003_DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .suspend = isl29003_suspend,
+       .resume = isl29003_resume,
+       .probe  = isl29003_probe,
+       .remove = __devexit_p(isl29003_remove),
+       .id_table = isl29003_id,
+};
+
+static int __init isl29003_init(void)
+{
+       return i2c_add_driver(&isl29003_driver);
+}
+
+static void __exit isl29003_exit(void)
+{
+       i2c_del_driver(&isl29003_driver);
+}
+
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
+MODULE_DESCRIPTION("ISL29003 ambient light sensor driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRIVER_VERSION);
+
+module_init(isl29003_init);
+module_exit(isl29003_exit);
+
index 9e9170b3599a249e4576fbb8b8d4214dead20a2a..bcd8136d2f985bab6341c0ba912fc09f2fe83d65 100644 (file)
@@ -3,5 +3,5 @@ ifdef CONFIG_SGI_GRU_DEBUG
 endif
 
 obj-$(CONFIG_SGI_GRU) := gru.o
-gru-y := grufile.o grumain.o grufault.o grutlbpurge.o gruprocfs.o grukservices.o
+gru-y := grufile.o grumain.o grufault.o grutlbpurge.o gruprocfs.o grukservices.o gruhandles.o
 
index 48762e7b98be65a5b3758489657a5d1675cf5de0..3fde33c1e8f3b64e10192194974ec0016ea95f00 100644 (file)
 #ifndef __GRU_INSTRUCTIONS_H__
 #define __GRU_INSTRUCTIONS_H__
 
-#define gru_flush_cache_hook(p)
-#define gru_emulator_wait_hook(p, w)
+extern int gru_check_status_proc(void *cb);
+extern int gru_wait_proc(void *cb);
+extern void gru_wait_abort_proc(void *cb);
+
+
 
 /*
  * Architecture dependent functions
 #if defined(CONFIG_IA64)
 #include <linux/compiler.h>
 #include <asm/intrinsics.h>
-#define __flush_cache(p)               ia64_fc(p)
+#define __flush_cache(p)               ia64_fc((unsigned long)p)
 /* Use volatile on IA64 to ensure ordering via st4.rel */
-#define gru_ordered_store_int(p,v)                                     \
+#define gru_ordered_store_int(p, v)                                    \
                do {                                                    \
                        barrier();                                      \
                        *((volatile int *)(p)) = v; /* force st.rel */  \
                } while (0)
 #elif defined(CONFIG_X86_64)
 #define __flush_cache(p)               clflush(p)
-#define gru_ordered_store_int(p,v)                                     \
+#define gru_ordered_store_int(p, v)                                    \
                do {                                                    \
                        barrier();                                      \
                        *(int *)p = v;                                  \
@@ -558,20 +561,19 @@ extern int gru_get_cb_exception_detail(void *cb,
 
 #define GRU_EXC_STR_SIZE               256
 
-extern int gru_check_status_proc(void *cb);
-extern int gru_wait_proc(void *cb);
-extern void gru_wait_abort_proc(void *cb);
 
 /*
  * Control block definition for checking status
  */
 struct gru_control_block_status {
        unsigned int    icmd            :1;
-       unsigned int    unused1         :31;
+       unsigned int    ima             :3;
+       unsigned int    reserved0       :4;
+       unsigned int    unused1         :24;
        unsigned int    unused2         :24;
        unsigned int    istatus         :2;
        unsigned int    isubstatus      :4;
-       unsigned int    inused3         :2;
+       unsigned int    unused3         :2;
 };
 
 /* Get CB status */
index 3ee698ad85997cf2f5c32b986689d7c07a0ed607..ab118558552e96a3fea1071f406b47d88514e905 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/device.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
+#include <linux/security.h>
 #include <asm/pgtable.h>
 #include "gru.h"
 #include "grutables.h"
@@ -266,6 +267,44 @@ err:
        return 1;
 }
 
+static int gru_vtop(struct gru_thread_state *gts, unsigned long vaddr,
+                   int write, int atomic, unsigned long *gpa, int *pageshift)
+{
+       struct mm_struct *mm = gts->ts_mm;
+       struct vm_area_struct *vma;
+       unsigned long paddr;
+       int ret, ps;
+
+       vma = find_vma(mm, vaddr);
+       if (!vma)
+               goto inval;
+
+       /*
+        * Atomic lookup is faster & usually works even if called in non-atomic
+        * context.
+        */
+       rmb();  /* Must/check ms_range_active before loading PTEs */
+       ret = atomic_pte_lookup(vma, vaddr, write, &paddr, &ps);
+       if (ret) {
+               if (atomic)
+                       goto upm;
+               if (non_atomic_pte_lookup(vma, vaddr, write, &paddr, &ps))
+                       goto inval;
+       }
+       if (is_gru_paddr(paddr))
+               goto inval;
+       paddr = paddr & ~((1UL << ps) - 1);
+       *gpa = uv_soc_phys_ram_to_gpa(paddr);
+       *pageshift = ps;
+       return 0;
+
+inval:
+       return -1;
+upm:
+       return -2;
+}
+
+
 /*
  * Drop a TLB entry into the GRU. The fault is described by info in an TFH.
  *     Input:
@@ -280,10 +319,8 @@ static int gru_try_dropin(struct gru_thread_state *gts,
                          struct gru_tlb_fault_handle *tfh,
                          unsigned long __user *cb)
 {
-       struct mm_struct *mm = gts->ts_mm;
-       struct vm_area_struct *vma;
-       int pageshift, asid, write, ret;
-       unsigned long paddr, gpa, vaddr;
+       int pageshift = 0, asid, write, ret, atomic = !cb;
+       unsigned long gpa = 0, vaddr = 0;
 
        /*
         * NOTE: The GRU contains magic hardware that eliminates races between
@@ -317,28 +354,19 @@ static int gru_try_dropin(struct gru_thread_state *gts,
        if (atomic_read(&gts->ts_gms->ms_range_active))
                goto failactive;
 
-       vma = find_vma(mm, vaddr);
-       if (!vma)
+       ret = gru_vtop(gts, vaddr, write, atomic, &gpa, &pageshift);
+       if (ret == -1)
                goto failinval;
+       if (ret == -2)
+               goto failupm;
 
-       /*
-        * Atomic lookup is faster & usually works even if called in non-atomic
-        * context.
-        */
-       rmb();  /* Must/check ms_range_active before loading PTEs */
-       ret = atomic_pte_lookup(vma, vaddr, write, &paddr, &pageshift);
-       if (ret) {
-               if (!cb)
+       if (!(gts->ts_sizeavail & GRU_SIZEAVAIL(pageshift))) {
+               gts->ts_sizeavail |= GRU_SIZEAVAIL(pageshift);
+               if (atomic || !gru_update_cch(gts, 0)) {
+                       gts->ts_force_cch_reload = 1;
                        goto failupm;
-               if (non_atomic_pte_lookup(vma, vaddr, write, &paddr,
-                                         &pageshift))
-                       goto failinval;
+               }
        }
-       if (is_gru_paddr(paddr))
-               goto failinval;
-
-       paddr = paddr & ~((1UL << pageshift) - 1);
-       gpa = uv_soc_phys_ram_to_gpa(paddr);
        gru_cb_set_istatus_active(cb);
        tfh_write_restart(tfh, gpa, GAA_RAM, vaddr, asid, write,
                          GRU_PAGESIZE(pageshift));
@@ -368,6 +396,7 @@ failupm:
 
 failfmm:
        /* FMM state on UPM call */
+       gru_flush_cache(tfh);
        STAT(tlb_dropin_fail_fmm);
        gru_dbg(grudev, "FAILED fmm tfh: 0x%p, state %d\n", tfh, tfh->state);
        return 0;
@@ -448,6 +477,7 @@ irqreturn_t gru_intr(int irq, void *dev_id)
                        up_read(&gts->ts_mm->mmap_sem);
                } else {
                        tfh_user_polling_mode(tfh);
+                       STAT(intr_mm_lock_failed);
                }
        }
        return IRQ_HANDLED;
@@ -497,10 +527,8 @@ int gru_handle_user_call_os(unsigned long cb)
        if (!gts)
                return -EINVAL;
 
-       if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE) {
-               ret = -EINVAL;
+       if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE)
                goto exit;
-       }
 
        /*
         * If force_unload is set, the UPM TLB fault is phony. The task
@@ -508,6 +536,20 @@ int gru_handle_user_call_os(unsigned long cb)
         * unload the context. The task will page fault and assign a new
         * context.
         */
+       if (gts->ts_tgid_owner == current->tgid && gts->ts_blade >= 0 &&
+                               gts->ts_blade != uv_numa_blade_id()) {
+               STAT(call_os_offnode_reference);
+               gts->ts_force_unload = 1;
+       }
+
+       /*
+        * CCH may contain stale data if ts_force_cch_reload is set.
+        */
+       if (gts->ts_gru && gts->ts_force_cch_reload) {
+               gru_update_cch(gts, 0);
+               gts->ts_force_cch_reload = 0;
+       }
+
        ret = -EAGAIN;
        cbrnum = thread_cbr_number(gts, ucbnum);
        if (gts->ts_force_unload) {
@@ -541,11 +583,13 @@ int gru_get_exception_detail(unsigned long arg)
        if (!gts)
                return -EINVAL;
 
-       if (gts->ts_gru) {
-               ucbnum = get_cb_number((void *)excdet.cb);
+       ucbnum = get_cb_number((void *)excdet.cb);
+       if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE) {
+               ret = -EINVAL;
+       } else if (gts->ts_gru) {
                cbrnum = thread_cbr_number(gts, ucbnum);
                cbe = get_cbe_by_index(gts->ts_gru, cbrnum);
-               prefetchw(cbe);         /* Harmless on hardware, required for emulator */
+               prefetchw(cbe);/* Harmless on hardware, required for emulator */
                excdet.opc = cbe->opccpy;
                excdet.exopc = cbe->exopccpy;
                excdet.ecause = cbe->ecause;
@@ -567,6 +611,31 @@ int gru_get_exception_detail(unsigned long arg)
 /*
  * User request to unload a context. Content is saved for possible reload.
  */
+static int gru_unload_all_contexts(void)
+{
+       struct gru_thread_state *gts;
+       struct gru_state *gru;
+       int gid, ctxnum;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       foreach_gid(gid) {
+               gru = GID_TO_GRU(gid);
+               spin_lock(&gru->gs_lock);
+               for (ctxnum = 0; ctxnum < GRU_NUM_CCH; ctxnum++) {
+                       gts = gru->gs_gts[ctxnum];
+                       if (gts && mutex_trylock(&gts->ts_ctxlock)) {
+                               spin_unlock(&gru->gs_lock);
+                               gru_unload_context(gts, 1);
+                               gru_unlock_gts(gts);
+                               spin_lock(&gru->gs_lock);
+                       }
+               }
+               spin_unlock(&gru->gs_lock);
+       }
+       return 0;
+}
+
 int gru_user_unload_context(unsigned long arg)
 {
        struct gru_thread_state *gts;
@@ -578,6 +647,9 @@ int gru_user_unload_context(unsigned long arg)
 
        gru_dbg(grudev, "gseg 0x%lx\n", req.gseg);
 
+       if (!req.gseg)
+               return gru_unload_all_contexts();
+
        gts = gru_find_lock_gts(req.gseg);
        if (!gts)
                return -EINVAL;
@@ -609,7 +681,7 @@ int gru_user_flush_tlb(unsigned long arg)
        if (!gts)
                return -EINVAL;
 
-       gru_flush_tlb_range(gts->ts_gms, req.vaddr, req.vaddr + req.len);
+       gru_flush_tlb_range(gts->ts_gms, req.vaddr, req.len);
        gru_unlock_gts(gts);
 
        return 0;
index c67e4e8bd62c5fd83236ff97fb0961a82db189d2..3e6e42d2f01b559c93d5396852e2830a3cc9316a 100644 (file)
@@ -45,7 +45,9 @@
 #include <asm/uv/uv_mmrs.h>
 
 struct gru_blade_state *gru_base[GRU_MAX_BLADES] __read_mostly;
-unsigned long gru_start_paddr, gru_end_paddr __read_mostly;
+unsigned long gru_start_paddr __read_mostly;
+unsigned long gru_end_paddr __read_mostly;
+unsigned int gru_max_gids __read_mostly;
 struct gru_stats_s gru_stats;
 
 /* Guaranteed user available resources on each node */
@@ -101,7 +103,7 @@ static int gru_file_mmap(struct file *file, struct vm_area_struct *vma)
                return -EPERM;
 
        if (vma->vm_start & (GRU_GSEG_PAGESIZE - 1) ||
-                               vma->vm_end & (GRU_GSEG_PAGESIZE - 1))
+                               vma->vm_end & (GRU_GSEG_PAGESIZE - 1))
                return -EINVAL;
 
        vma->vm_flags |=
@@ -273,8 +275,11 @@ static void gru_init_chiplet(struct gru_state *gru, unsigned long paddr,
        gru->gs_blade_id = bid;
        gru->gs_cbr_map = (GRU_CBR_AU == 64) ? ~0 : (1UL << GRU_CBR_AU) - 1;
        gru->gs_dsr_map = (1UL << GRU_DSR_AU) - 1;
+       gru->gs_asid_limit = MAX_ASID;
        gru_tgh_flush_init(gru);
-       gru_dbg(grudev, "bid %d, nid %d, gru %x, vaddr %p (0x%lx)\n",
+       if (gru->gs_gid >= gru_max_gids)
+               gru_max_gids = gru->gs_gid + 1;
+       gru_dbg(grudev, "bid %d, nid %d, gid %d, vaddr %p (0x%lx)\n",
                bid, nid, gru->gs_gid, gru->gs_gru_base_vaddr,
                gru->gs_gru_base_paddr);
        gru_kservices_init(gru);
@@ -295,7 +300,7 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr)
        for_each_online_node(nid) {
                bid = uv_node_to_blade_id(nid);
                pnode = uv_node_to_pnode(nid);
-               if (gru_base[bid])
+               if (bid < 0 || gru_base[bid])
                        continue;
                page = alloc_pages_node(nid, GFP_KERNEL, order);
                if (!page)
@@ -308,11 +313,11 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr)
                dsrbytes = 0;
                cbrs = 0;
                for (gru = gru_base[bid]->bs_grus, chip = 0;
-                               chip < GRU_CHIPLETS_PER_BLADE;
+                               chip < GRU_CHIPLETS_PER_BLADE;
                                chip++, gru++) {
                        paddr = gru_chiplet_paddr(gru_base_paddr, pnode, chip);
                        vaddr = gru_chiplet_vaddr(gru_base_vaddr, pnode, chip);
-                       gru_init_chiplet(gru, paddr, vaddr, bid, nid, chip);
+                       gru_init_chiplet(gru, paddr, vaddr, nid, bid, chip);
                        n = hweight64(gru->gs_cbr_map) * GRU_CBR_AU_SIZE;
                        cbrs = max(cbrs, n);
                        n = hweight64(gru->gs_dsr_map) * GRU_DSR_AU_BYTES;
@@ -370,26 +375,26 @@ static int __init gru_init(void)
        void *gru_start_vaddr;
 
        if (!is_uv_system())
-               return 0;
+               return -ENODEV;
 
 #if defined CONFIG_IA64
        gru_start_paddr = 0xd000000000UL; /* ZZZZZZZZZZZZZZZZZZZ fixme */
 #else
        gru_start_paddr = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR) &
                                0x7fffffffffffUL;
-
 #endif
        gru_start_vaddr = __va(gru_start_paddr);
-       gru_end_paddr = gru_start_paddr + MAX_NUMNODES * GRU_SIZE;
+       gru_end_paddr = gru_start_paddr + GRU_MAX_BLADES * GRU_SIZE;
        printk(KERN_INFO "GRU space: 0x%lx - 0x%lx\n",
               gru_start_paddr, gru_end_paddr);
        irq = get_base_irq();
        for (chip = 0; chip < GRU_CHIPLETS_PER_BLADE; chip++) {
                ret = request_irq(irq + chip, gru_intr, 0, id, NULL);
-               /* TODO: fix irq handling on x86. For now ignore failures because
+               /* TODO: fix irq handling on x86. For now ignore failure because
                 * interrupts are not required & not yet fully supported */
                if (ret) {
-                       printk("!!!WARNING: GRU ignoring request failure!!!\n");
+                       printk(KERN_WARNING
+                              "!!!WARNING: GRU ignoring request failure!!!\n");
                        ret = 0;
                }
                if (ret) {
@@ -435,7 +440,7 @@ exit1:
 
 static void __exit gru_exit(void)
 {
-       int i, bid;
+       int i, bid, gid;
        int order = get_order(sizeof(struct gru_state) *
                              GRU_CHIPLETS_PER_BLADE);
 
@@ -445,6 +450,9 @@ static void __exit gru_exit(void)
        for (i = 0; i < GRU_CHIPLETS_PER_BLADE; i++)
                free_irq(IRQ_GRU + i, NULL);
 
+       foreach_gid(gid)
+               gru_kservices_exit(GID_TO_GRU(gid));
+
        for (bid = 0; bid < GRU_MAX_BLADES; bid++)
                free_pages((unsigned long)gru_base[bid], order);
 
@@ -469,7 +477,11 @@ struct vm_operations_struct gru_vm_ops = {
        .fault          = gru_fault,
 };
 
+#ifndef MODULE
 fs_initcall(gru_init);
+#else
+module_init(gru_init);
+#endif
 module_exit(gru_exit);
 
 module_param(gru_options, ulong, 0644);
diff --git a/drivers/misc/sgi-gru/gruhandles.c b/drivers/misc/sgi-gru/gruhandles.c
new file mode 100644 (file)
index 0000000..9b7ccb3
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ *              GRU KERNEL MCS INSTRUCTIONS
+ *
+ *  Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ *  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 "gru.h"
+#include "grulib.h"
+#include "grutables.h"
+
+/* 10 sec */
+#ifdef CONFIG_IA64
+#include <asm/processor.h>
+#define GRU_OPERATION_TIMEOUT  (((cycles_t) local_cpu_data->itc_freq)*10)
+#else
+#include <asm/tsc.h>
+#define GRU_OPERATION_TIMEOUT  ((cycles_t) tsc_khz*10*1000)
+#endif
+
+/* Extract the status field from a kernel handle */
+#define GET_MSEG_HANDLE_STATUS(h)      (((*(unsigned long *)(h)) >> 16) & 3)
+
+struct mcs_op_statistic mcs_op_statistics[mcsop_last];
+
+static void update_mcs_stats(enum mcs_op op, unsigned long clks)
+{
+       atomic_long_inc(&mcs_op_statistics[op].count);
+       atomic_long_add(clks, &mcs_op_statistics[op].total);
+       if (mcs_op_statistics[op].max < clks)
+               mcs_op_statistics[op].max = clks;
+}
+
+static void start_instruction(void *h)
+{
+       unsigned long *w0 = h;
+
+       wmb();          /* setting CMD bit must be last */
+       *w0 = *w0 | 1;
+       gru_flush_cache(h);
+}
+
+static int wait_instruction_complete(void *h, enum mcs_op opc)
+{
+       int status;
+       cycles_t start_time = get_cycles();
+
+       while (1) {
+               cpu_relax();
+               status = GET_MSEG_HANDLE_STATUS(h);
+               if (status != CCHSTATUS_ACTIVE)
+                       break;
+               if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time))
+                       panic("GRU %p is malfunctioning\n", h);
+       }
+       if (gru_options & OPT_STATS)
+               update_mcs_stats(opc, get_cycles() - start_time);
+       return status;
+}
+
+int cch_allocate(struct gru_context_configuration_handle *cch,
+               int asidval, int sizeavail, unsigned long cbrmap,
+               unsigned long dsrmap)
+{
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               cch->asid[i] = (asidval++);
+               cch->sizeavail[i] = sizeavail;
+       }
+       cch->dsr_allocation_map = dsrmap;
+       cch->cbr_allocation_map = cbrmap;
+       cch->opc = CCHOP_ALLOCATE;
+       start_instruction(cch);
+       return wait_instruction_complete(cch, cchop_allocate);
+}
+
+int cch_start(struct gru_context_configuration_handle *cch)
+{
+       cch->opc = CCHOP_START;
+       start_instruction(cch);
+       return wait_instruction_complete(cch, cchop_start);
+}
+
+int cch_interrupt(struct gru_context_configuration_handle *cch)
+{
+       cch->opc = CCHOP_INTERRUPT;
+       start_instruction(cch);
+       return wait_instruction_complete(cch, cchop_interrupt);
+}
+
+int cch_deallocate(struct gru_context_configuration_handle *cch)
+{
+       cch->opc = CCHOP_DEALLOCATE;
+       start_instruction(cch);
+       return wait_instruction_complete(cch, cchop_deallocate);
+}
+
+int cch_interrupt_sync(struct gru_context_configuration_handle
+                                    *cch)
+{
+       cch->opc = CCHOP_INTERRUPT_SYNC;
+       start_instruction(cch);
+       return wait_instruction_complete(cch, cchop_interrupt_sync);
+}
+
+int tgh_invalidate(struct gru_tlb_global_handle *tgh,
+                                unsigned long vaddr, unsigned long vaddrmask,
+                                int asid, int pagesize, int global, int n,
+                                unsigned short ctxbitmap)
+{
+       tgh->vaddr = vaddr;
+       tgh->asid = asid;
+       tgh->pagesize = pagesize;
+       tgh->n = n;
+       tgh->global = global;
+       tgh->vaddrmask = vaddrmask;
+       tgh->ctxbitmap = ctxbitmap;
+       tgh->opc = TGHOP_TLBINV;
+       start_instruction(tgh);
+       return wait_instruction_complete(tgh, tghop_invalidate);
+}
+
+void tfh_write_only(struct gru_tlb_fault_handle *tfh,
+                                 unsigned long pfn, unsigned long vaddr,
+                                 int asid, int dirty, int pagesize)
+{
+       tfh->fillasid = asid;
+       tfh->fillvaddr = vaddr;
+       tfh->pfn = pfn;
+       tfh->dirty = dirty;
+       tfh->pagesize = pagesize;
+       tfh->opc = TFHOP_WRITE_ONLY;
+       start_instruction(tfh);
+}
+
+void tfh_write_restart(struct gru_tlb_fault_handle *tfh,
+                                    unsigned long paddr, int gaa,
+                                    unsigned long vaddr, int asid, int dirty,
+                                    int pagesize)
+{
+       tfh->fillasid = asid;
+       tfh->fillvaddr = vaddr;
+       tfh->pfn = paddr >> GRU_PADDR_SHIFT;
+       tfh->gaa = gaa;
+       tfh->dirty = dirty;
+       tfh->pagesize = pagesize;
+       tfh->opc = TFHOP_WRITE_RESTART;
+       start_instruction(tfh);
+}
+
+void tfh_restart(struct gru_tlb_fault_handle *tfh)
+{
+       tfh->opc = TFHOP_RESTART;
+       start_instruction(tfh);
+}
+
+void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh)
+{
+       tfh->opc = TFHOP_USER_POLLING_MODE;
+       start_instruction(tfh);
+}
+
+void tfh_exception(struct gru_tlb_fault_handle *tfh)
+{
+       tfh->opc = TFHOP_EXCEPTION;
+       start_instruction(tfh);
+}
+
index b63018d60fe1a56b22e0cc2c02cc43b650dba7f6..1ed74d7508c8bb14181c181a07925d04041c6283 100644 (file)
@@ -489,170 +489,28 @@ enum gru_cbr_state {
  *      64m                    26      8
  *     ...
  */
-#define GRU_PAGESIZE(sh)       ((((sh) > 20 ? (sh) + 2: (sh)) >> 1) - 6)
+#define GRU_PAGESIZE(sh)       ((((sh) > 20 ? (sh) + 2 : (sh)) >> 1) - 6)
 #define GRU_SIZEAVAIL(sh)      (1UL << GRU_PAGESIZE(sh))
 
 /* minimum TLB purge count to ensure a full purge */
 #define GRUMAXINVAL            1024UL
 
-
-/* Extract the status field from a kernel handle */
-#define GET_MSEG_HANDLE_STATUS(h)      (((*(unsigned long *)(h)) >> 16) & 3)
-
-static inline void start_instruction(void *h)
-{
-       unsigned long *w0 = h;
-
-       wmb();          /* setting CMD bit must be last */
-       *w0 = *w0 | 1;
-       gru_flush_cache(h);
-}
-
-static inline int wait_instruction_complete(void *h)
-{
-       int status;
-
-       do {
-               cpu_relax();
-               barrier();
-               status = GET_MSEG_HANDLE_STATUS(h);
-       } while (status == CCHSTATUS_ACTIVE);
-       return status;
-}
-
-#if defined CONFIG_IA64
-static inline void cch_allocate_set_asids(
-                 struct gru_context_configuration_handle *cch, int asidval)
-{
-       int i;
-
-       for (i = 0; i <= RGN_HPAGE; i++) {  /*  assume HPAGE is last region */
-               cch->asid[i] = (asidval++);
-#if 0
-               /* ZZZ hugepages not supported yet */
-               if (i == RGN_HPAGE)
-                       cch->sizeavail[i] = GRU_SIZEAVAIL(hpage_shift);
-               else
-#endif
-                       cch->sizeavail[i] = GRU_SIZEAVAIL(PAGE_SHIFT);
-       }
-}
-#elif defined CONFIG_X86_64
-static inline void cch_allocate_set_asids(
-                 struct gru_context_configuration_handle *cch, int asidval)
-{
-       int i;
-
-       for (i = 0; i < 8; i++) {
-               cch->asid[i] = asidval++;
-               cch->sizeavail[i] = GRU_SIZEAVAIL(PAGE_SHIFT) |
-                       GRU_SIZEAVAIL(21);
-       }
-}
-#endif
-
-static inline int cch_allocate(struct gru_context_configuration_handle *cch,
-                              int asidval, unsigned long cbrmap,
-                              unsigned long dsrmap)
-{
-       cch_allocate_set_asids(cch, asidval);
-       cch->dsr_allocation_map = dsrmap;
-       cch->cbr_allocation_map = cbrmap;
-       cch->opc = CCHOP_ALLOCATE;
-       start_instruction(cch);
-       return wait_instruction_complete(cch);
-}
-
-static inline int cch_start(struct gru_context_configuration_handle *cch)
-{
-       cch->opc = CCHOP_START;
-       start_instruction(cch);
-       return wait_instruction_complete(cch);
-}
-
-static inline int cch_interrupt(struct gru_context_configuration_handle *cch)
-{
-       cch->opc = CCHOP_INTERRUPT;
-       start_instruction(cch);
-       return wait_instruction_complete(cch);
-}
-
-static inline int cch_deallocate(struct gru_context_configuration_handle *cch)
-{
-       cch->opc = CCHOP_DEALLOCATE;
-       start_instruction(cch);
-       return wait_instruction_complete(cch);
-}
-
-static inline int cch_interrupt_sync(struct gru_context_configuration_handle
-                                    *cch)
-{
-       cch->opc = CCHOP_INTERRUPT_SYNC;
-       start_instruction(cch);
-       return wait_instruction_complete(cch);
-}
-
-static inline int tgh_invalidate(struct gru_tlb_global_handle *tgh,
-                                unsigned long vaddr, unsigned long vaddrmask,
-                                int asid, int pagesize, int global, int n,
-                                unsigned short ctxbitmap)
-{
-       tgh->vaddr = vaddr;
-       tgh->asid = asid;
-       tgh->pagesize = pagesize;
-       tgh->n = n;
-       tgh->global = global;
-       tgh->vaddrmask = vaddrmask;
-       tgh->ctxbitmap = ctxbitmap;
-       tgh->opc = TGHOP_TLBINV;
-       start_instruction(tgh);
-       return wait_instruction_complete(tgh);
-}
-
-static inline void tfh_write_only(struct gru_tlb_fault_handle *tfh,
-                                 unsigned long pfn, unsigned long vaddr,
-                                 int asid, int dirty, int pagesize)
-{
-       tfh->fillasid = asid;
-       tfh->fillvaddr = vaddr;
-       tfh->pfn = pfn;
-       tfh->dirty = dirty;
-       tfh->pagesize = pagesize;
-       tfh->opc = TFHOP_WRITE_ONLY;
-       start_instruction(tfh);
-}
-
-static inline void tfh_write_restart(struct gru_tlb_fault_handle *tfh,
-                                    unsigned long paddr, int gaa,
-                                    unsigned long vaddr, int asid, int dirty,
-                                    int pagesize)
-{
-       tfh->fillasid = asid;
-       tfh->fillvaddr = vaddr;
-       tfh->pfn = paddr >> GRU_PADDR_SHIFT;
-       tfh->gaa = gaa;
-       tfh->dirty = dirty;
-       tfh->pagesize = pagesize;
-       tfh->opc = TFHOP_WRITE_RESTART;
-       start_instruction(tfh);
-}
-
-static inline void tfh_restart(struct gru_tlb_fault_handle *tfh)
-{
-       tfh->opc = TFHOP_RESTART;
-       start_instruction(tfh);
-}
-
-static inline void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh)
-{
-       tfh->opc = TFHOP_USER_POLLING_MODE;
-       start_instruction(tfh);
-}
-
-static inline void tfh_exception(struct gru_tlb_fault_handle *tfh)
-{
-       tfh->opc = TFHOP_EXCEPTION;
-       start_instruction(tfh);
-}
+int cch_allocate(struct gru_context_configuration_handle *cch,
+       int asidval, int sizeavail, unsigned long cbrmap, unsigned long dsrmap);
+
+int cch_start(struct gru_context_configuration_handle *cch);
+int cch_interrupt(struct gru_context_configuration_handle *cch);
+int cch_deallocate(struct gru_context_configuration_handle *cch);
+int cch_interrupt_sync(struct gru_context_configuration_handle *cch);
+int tgh_invalidate(struct gru_tlb_global_handle *tgh, unsigned long vaddr,
+       unsigned long vaddrmask, int asid, int pagesize, int global, int n,
+       unsigned short ctxbitmap);
+void tfh_write_only(struct gru_tlb_fault_handle *tfh, unsigned long pfn,
+       unsigned long vaddr, int asid, int dirty, int pagesize);
+void tfh_write_restart(struct gru_tlb_fault_handle *tfh, unsigned long paddr,
+       int gaa, unsigned long vaddr, int asid, int dirty, int pagesize);
+void tfh_restart(struct gru_tlb_fault_handle *tfh);
+void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh);
+void tfh_exception(struct gru_tlb_fault_handle *tfh);
 
 #endif /* __GRUHANDLES_H__ */
index 880c55dfb66266dfd53cae3dea2492b986ff5744..d8bd7d84a7cf7117ca1e3f409b718e16a8ba1151 100644 (file)
  */
 
 /* Blade percpu resources PERMANENTLY reserved for kernel use */
-#define GRU_NUM_KERNEL_CBR      1
+#define GRU_NUM_KERNEL_CBR     1
 #define GRU_NUM_KERNEL_DSR_BYTES 256
+#define GRU_NUM_KERNEL_DSR_CL  (GRU_NUM_KERNEL_DSR_BYTES /             \
+                                       GRU_CACHE_LINE_BYTES)
 #define KERNEL_CTXNUM           15
 
 /* GRU instruction attributes for all instructions */
@@ -94,7 +96,6 @@ struct message_header {
        char    fill;
 };
 
-#define QLINES(mq)     ((mq) + offsetof(struct message_queue, qlines))
 #define HSTATUS(mq, h) ((mq) + offsetof(struct message_queue, hstatus[h]))
 
 static int gru_get_cpu_resources(int dsr_bytes, void **cb, void **dsr)
@@ -122,7 +123,7 @@ int gru_get_cb_exception_detail(void *cb,
        struct gru_control_block_extended *cbe;
 
        cbe = get_cbe(GRUBASE(cb), get_cb_number(cb));
-       prefetchw(cbe);         /* Harmless on hardware, required for emulator */
+       prefetchw(cbe); /* Harmless on hardware, required for emulator */
        excdet->opc = cbe->opccpy;
        excdet->exopc = cbe->exopccpy;
        excdet->ecause = cbe->ecause;
@@ -250,7 +251,8 @@ static inline void restore_present2(void *p, int val)
  * Create a message queue.
  *     qlines - message queue size in cache lines. Includes 2-line header.
  */
-int gru_create_message_queue(void *p, unsigned int bytes)
+int gru_create_message_queue(struct gru_message_queue_desc *mqd,
+               void *p, unsigned int bytes, int nasid, int vector, int apicid)
 {
        struct message_queue *mq = p;
        unsigned int qlines;
@@ -265,6 +267,12 @@ int gru_create_message_queue(void *p, unsigned int bytes)
        mq->hstatus[0] = 0;
        mq->hstatus[1] = 1;
        mq->head = gru_mesq_head(2, qlines / 2 + 1);
+       mqd->mq = mq;
+       mqd->mq_gpa = uv_gpa(mq);
+       mqd->qlines = qlines;
+       mqd->interrupt_pnode = UV_NASID_TO_PNODE(nasid);
+       mqd->interrupt_vector = vector;
+       mqd->interrupt_apicid = apicid;
        return 0;
 }
 EXPORT_SYMBOL_GPL(gru_create_message_queue);
@@ -277,8 +285,8 @@ EXPORT_SYMBOL_GPL(gru_create_message_queue);
  *             -1 - if mesq sent successfully but queue not full
  *             >0 - unexpected error. MQE_xxx returned
  */
-static int send_noop_message(void *cb,
-                               unsigned long mq, void *mesg)
+static int send_noop_message(void *cb, struct gru_message_queue_desc *mqd,
+                               void *mesg)
 {
        const struct message_header noop_header = {
                                        .present = MQS_NOOP, .lines = 1};
@@ -289,7 +297,7 @@ static int send_noop_message(void *cb,
        STAT(mesq_noop);
        save_mhdr = *mhdr;
        *mhdr = noop_header;
-       gru_mesq(cb, mq, gru_get_tri(mhdr), 1, IMA);
+       gru_mesq(cb, mqd->mq_gpa, gru_get_tri(mhdr), 1, IMA);
        ret = gru_wait(cb);
 
        if (ret) {
@@ -313,7 +321,7 @@ static int send_noop_message(void *cb,
                        break;
                case CBSS_PUT_NACKED:
                        STAT(mesq_noop_put_nacked);
-                       m = mq + (gru_get_amo_value_head(cb) << 6);
+                       m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6);
                        gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, 1, 1,
                                                IMA);
                        if (gru_wait(cb) == CBS_IDLE)
@@ -333,30 +341,20 @@ static int send_noop_message(void *cb,
 /*
  * Handle a gru_mesq full.
  */
-static int send_message_queue_full(void *cb,
-                          unsigned long mq, void *mesg, int lines)
+static int send_message_queue_full(void *cb, struct gru_message_queue_desc *mqd,
+                               void *mesg, int lines)
 {
        union gru_mesqhead mqh;
        unsigned int limit, head;
        unsigned long avalue;
-       int half, qlines, save;
+       int half, qlines;
 
        /* Determine if switching to first/second half of q */
        avalue = gru_get_amo_value(cb);
        head = gru_get_amo_value_head(cb);
        limit = gru_get_amo_value_limit(cb);
 
-       /*
-        * Fetch "qlines" from the queue header. Since the queue may be
-        * in memory that can't be accessed using socket addresses, use
-        * the GRU to access the data. Use DSR space from the message.
-        */
-       save = *(int *)mesg;
-       gru_vload(cb, QLINES(mq), gru_get_tri(mesg), XTYPE_W, 1, 1, IMA);
-       if (gru_wait(cb) != CBS_IDLE)
-               goto cberr;
-       qlines = *(int *)mesg;
-       *(int *)mesg = save;
+       qlines = mqd->qlines;
        half = (limit != qlines);
 
        if (half)
@@ -365,7 +363,7 @@ static int send_message_queue_full(void *cb,
                mqh = gru_mesq_head(2, qlines / 2 + 1);
 
        /* Try to get lock for switching head pointer */
-       gru_gamir(cb, EOP_IR_CLR, HSTATUS(mq, half), XTYPE_DW, IMA);
+       gru_gamir(cb, EOP_IR_CLR, HSTATUS(mqd->mq_gpa, half), XTYPE_DW, IMA);
        if (gru_wait(cb) != CBS_IDLE)
                goto cberr;
        if (!gru_get_amo_value(cb)) {
@@ -375,8 +373,8 @@ static int send_message_queue_full(void *cb,
 
        /* Got the lock. Send optional NOP if queue not full, */
        if (head != limit) {
-               if (send_noop_message(cb, mq, mesg)) {
-                       gru_gamir(cb, EOP_IR_INC, HSTATUS(mq, half),
+               if (send_noop_message(cb, mqd, mesg)) {
+                       gru_gamir(cb, EOP_IR_INC, HSTATUS(mqd->mq_gpa, half),
                                        XTYPE_DW, IMA);
                        if (gru_wait(cb) != CBS_IDLE)
                                goto cberr;
@@ -387,14 +385,16 @@ static int send_message_queue_full(void *cb,
        }
 
        /* Then flip queuehead to other half of queue. */
-       gru_gamer(cb, EOP_ERR_CSWAP, mq, XTYPE_DW, mqh.val, avalue, IMA);
+       gru_gamer(cb, EOP_ERR_CSWAP, mqd->mq_gpa, XTYPE_DW, mqh.val, avalue,
+                                                       IMA);
        if (gru_wait(cb) != CBS_IDLE)
                goto cberr;
 
        /* If not successfully in swapping queue head, clear the hstatus lock */
        if (gru_get_amo_value(cb) != avalue) {
                STAT(mesq_qf_switch_head_failed);
-               gru_gamir(cb, EOP_IR_INC, HSTATUS(mq, half), XTYPE_DW, IMA);
+               gru_gamir(cb, EOP_IR_INC, HSTATUS(mqd->mq_gpa, half), XTYPE_DW,
+                                                       IMA);
                if (gru_wait(cb) != CBS_IDLE)
                        goto cberr;
        }
@@ -404,15 +404,25 @@ cberr:
        return MQE_UNEXPECTED_CB_ERR;
 }
 
+/*
+ * Send a cross-partition interrupt to the SSI that contains the target
+ * message queue. Normally, the interrupt is automatically delivered by hardware
+ * but some error conditions require explicit delivery.
+ */
+static void send_message_queue_interrupt(struct gru_message_queue_desc *mqd)
+{
+       if (mqd->interrupt_vector)
+               uv_hub_send_ipi(mqd->interrupt_pnode, mqd->interrupt_apicid,
+                               mqd->interrupt_vector);
+}
+
 
 /*
  * Handle a gru_mesq failure. Some of these failures are software recoverable
  * or retryable.
  */
-static int send_message_failure(void *cb,
-                               unsigned long mq,
-                               void *mesg,
-                               int lines)
+static int send_message_failure(void *cb, struct gru_message_queue_desc *mqd,
+                               void *mesg, int lines)
 {
        int substatus, ret = 0;
        unsigned long m;
@@ -429,7 +439,7 @@ static int send_message_failure(void *cb,
                break;
        case CBSS_QLIMIT_REACHED:
                STAT(mesq_send_qlimit_reached);
-               ret = send_message_queue_full(cb, mq, mesg, lines);
+               ret = send_message_queue_full(cb, mqd, mesg, lines);
                break;
        case CBSS_AMO_NACKED:
                STAT(mesq_send_amo_nacked);
@@ -437,12 +447,14 @@ static int send_message_failure(void *cb,
                break;
        case CBSS_PUT_NACKED:
                STAT(mesq_send_put_nacked);
-               m =mq + (gru_get_amo_value_head(cb) << 6);
+               m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6);
                gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA);
-               if (gru_wait(cb) == CBS_IDLE)
+               if (gru_wait(cb) == CBS_IDLE) {
                        ret = MQE_OK;
-               else
+                       send_message_queue_interrupt(mqd);
+               } else {
                        ret = MQE_UNEXPECTED_CB_ERR;
+               }
                break;
        default:
                BUG();
@@ -452,12 +464,12 @@ static int send_message_failure(void *cb,
 
 /*
  * Send a message to a message queue
- *     cb      GRU control block to use to send message
- *     mq      message queue
+ *     mqd     message queue descriptor
  *     mesg    message. ust be vaddr within a GSEG
  *     bytes   message size (<= 2 CL)
  */
-int gru_send_message_gpa(unsigned long mq, void *mesg, unsigned int bytes)
+int gru_send_message_gpa(struct gru_message_queue_desc *mqd, void *mesg,
+                               unsigned int bytes)
 {
        struct message_header *mhdr;
        void *cb;
@@ -481,10 +493,10 @@ int gru_send_message_gpa(unsigned long mq, void *mesg, unsigned int bytes)
 
        do {
                ret = MQE_OK;
-               gru_mesq(cb, mq, gru_get_tri(mhdr), clines, IMA);
+               gru_mesq(cb, mqd->mq_gpa, gru_get_tri(mhdr), clines, IMA);
                istatus = gru_wait(cb);
                if (istatus != CBS_IDLE)
-                       ret = send_message_failure(cb, mq, dsr, clines);
+                       ret = send_message_failure(cb, mqd, dsr, clines);
        } while (ret == MQIE_AGAIN);
        gru_free_cpu_resources(cb, dsr);
 
@@ -497,9 +509,9 @@ EXPORT_SYMBOL_GPL(gru_send_message_gpa);
 /*
  * Advance the receive pointer for the queue to the next message.
  */
-void gru_free_message(void *rmq, void *mesg)
+void gru_free_message(struct gru_message_queue_desc *mqd, void *mesg)
 {
-       struct message_queue *mq = rmq;
+       struct message_queue *mq = mqd->mq;
        struct message_header *mhdr = mq->next;
        void *next, *pnext;
        int half = -1;
@@ -529,16 +541,16 @@ EXPORT_SYMBOL_GPL(gru_free_message);
  * present. User must call next_message() to move to next message.
  *     rmq     message queue
  */
-void *gru_get_next_message(void *rmq)
+void *gru_get_next_message(struct gru_message_queue_desc *mqd)
 {
-       struct message_queue *mq = rmq;
+       struct message_queue *mq = mqd->mq;
        struct message_header *mhdr = mq->next;
        int present = mhdr->present;
 
        /* skip NOOP messages */
        STAT(mesq_receive);
        while (present == MQS_NOOP) {
-               gru_free_message(rmq, mhdr);
+               gru_free_message(mqd, mhdr);
                mhdr = mq->next;
                present = mhdr->present;
        }
@@ -576,7 +588,7 @@ int gru_copy_gpa(unsigned long dest_gpa, unsigned long src_gpa,
        if (gru_get_cpu_resources(GRU_NUM_KERNEL_DSR_BYTES, &cb, &dsr))
                return MQE_BUG_NO_RESOURCES;
        gru_bcopy(cb, src_gpa, dest_gpa, gru_get_tri(dsr),
-                 XTYPE_B, bytes, GRU_NUM_KERNEL_DSR_BYTES, IMA);
+                 XTYPE_B, bytes, GRU_NUM_KERNEL_DSR_CL, IMA);
        ret = gru_wait(cb);
        gru_free_cpu_resources(cb, dsr);
        return ret;
@@ -611,7 +623,7 @@ static int quicktest(struct gru_state *gru)
 
        if (word0 != word1 || word0 != MAGIC) {
                printk
-                   ("GRU quicktest err: gru %d, found 0x%lx, expected 0x%lx\n",
+                   ("GRU quicktest err: gid %d, found 0x%lx, expected 0x%lx\n",
                     gru->gs_gid, word1, MAGIC);
                BUG();          /* ZZZ should not be fatal */
        }
@@ -660,15 +672,15 @@ int gru_kservices_init(struct gru_state *gru)
        cch->tlb_int_enable = 0;
        cch->tfm_done_bit_enable = 0;
        cch->unmap_enable = 1;
-       err = cch_allocate(cch, 0, cbr_map, dsr_map);
+       err = cch_allocate(cch, 0, 0, cbr_map, dsr_map);
        if (err) {
                gru_dbg(grudev,
-                       "Unable to allocate kernel CCH: gru %d, err %d\n",
+                       "Unable to allocate kernel CCH: gid %d, err %d\n",
                        gru->gs_gid, err);
                BUG();
        }
        if (cch_start(cch)) {
-               gru_dbg(grudev, "Unable to start kernel CCH: gru %d, err %d\n",
+               gru_dbg(grudev, "Unable to start kernel CCH: gid %d, err %d\n",
                        gru->gs_gid, err);
                BUG();
        }
@@ -678,3 +690,22 @@ int gru_kservices_init(struct gru_state *gru)
                quicktest(gru);
        return 0;
 }
+
+void gru_kservices_exit(struct gru_state *gru)
+{
+       struct gru_context_configuration_handle *cch;
+       struct gru_blade_state *bs;
+
+       bs = gru->gs_blade;
+       if (gru != &bs->bs_grus[1])
+               return;
+
+       cch = get_cch(gru->gs_gru_base_vaddr, KERNEL_CTXNUM);
+       lock_cch_handle(cch);
+       if (cch_interrupt_sync(cch))
+               BUG();
+       if (cch_deallocate(cch))
+               BUG();
+       unlock_cch_handle(cch);
+}
+
index eb17e0a3ac61e4a0ff702b2edf8ebf894cb35c0f..747ed315d56f41998cec48f1a66057b144afe35c 100644 (file)
  *     - gru_create_message_queue() needs interrupt vector info
  */
 
+struct gru_message_queue_desc {
+       void            *mq;                    /* message queue vaddress */
+       unsigned long   mq_gpa;                 /* global address of mq */
+       int             qlines;                 /* queue size in CL */
+       int             interrupt_vector;       /* interrupt vector */
+       int             interrupt_pnode;        /* pnode for interrupt */
+       int             interrupt_apicid;       /* lapicid for interrupt */
+};
+
 /*
  * Initialize a user allocated chunk of memory to be used as
  * a message queue. The caller must ensure that the queue is
  * to manage the queue.
  *
  *  Input:
- *     p       pointer to user allocated memory.
+ *     mqd     pointer to message queue descriptor
+ *     p       pointer to user allocated mesq memory.
  *     bytes   size of message queue in bytes
+ *      vector interrupt vector (zero if no interrupts)
+ *      nasid  nasid of blade where interrupt is delivered
+ *      apicid apicid of cpu for interrupt
  *
  *  Errors:
  *     0       OK
  *     >0      error
  */
-extern int gru_create_message_queue(void *p, unsigned int bytes);
+extern int gru_create_message_queue(struct gru_message_queue_desc *mqd,
+               void *p, unsigned int bytes, int nasid, int vector, int apicid);
 
 /*
  * Send a message to a message queue.
@@ -68,7 +82,7 @@ extern int gru_create_message_queue(void *p, unsigned int bytes);
  *
  *
  *   Input:
- *     xmq     message queue - must be a UV global physical address
+ *     mqd     pointer to message queue descriptor
  *     mesg    pointer to message. Must be 64-bit aligned
  *     bytes   size of message in bytes
  *
@@ -77,8 +91,8 @@ extern int gru_create_message_queue(void *p, unsigned int bytes);
  *     >0      Send failure - see error codes below
  *
  */
-extern int gru_send_message_gpa(unsigned long mq_gpa, void *mesg,
-                                               unsigned int bytes);
+extern int gru_send_message_gpa(struct gru_message_queue_desc *mqd,
+                       void *mesg, unsigned int bytes);
 
 /* Status values for gru_send_message() */
 #define MQE_OK                 0       /* message sent successfully */
@@ -94,10 +108,11 @@ extern int gru_send_message_gpa(unsigned long mq_gpa, void *mesg,
  * API extensions may allow for out-of-order freeing.
  *
  *   Input
- *     mq      message queue
+ *     mqd     pointer to message queue descriptor
  *     mesq    message being freed
  */
-extern void gru_free_message(void *mq, void *mesq);
+extern void gru_free_message(struct gru_message_queue_desc *mqd,
+                            void *mesq);
 
 /*
  * Get next message from message queue. Returns pointer to
@@ -106,13 +121,13 @@ extern void gru_free_message(void *mq, void *mesq);
  * in order to move the queue pointers to next message.
  *
  *   Input
- *     mq      message queue
+ *     mqd     pointer to message queue descriptor
  *
  *   Output:
  *     p       pointer to message
  *     NULL    no message available
  */
-extern void *gru_get_next_message(void *mq);
+extern void *gru_get_next_message(struct gru_message_queue_desc *mqd);
 
 
 /*
index 3d2fc216bae5b561dea357cd86d1661803a0377d..ec3f7a17d221e01bd82bc23b6a64025263627c65 100644 (file)
@@ -76,10 +76,9 @@ int gru_cpu_fault_map_id(void)
 /* Hit the asid limit. Start over */
 static int gru_wrap_asid(struct gru_state *gru)
 {
-       gru_dbg(grudev, "gru %p\n", gru);
+       gru_dbg(grudev, "gid %d\n", gru->gs_gid);
        STAT(asid_wrap);
        gru->gs_asid_gen++;
-       gru_flush_all_tlb(gru);
        return MIN_ASID;
 }
 
@@ -88,19 +87,21 @@ static int gru_reset_asid_limit(struct gru_state *gru, int asid)
 {
        int i, gid, inuse_asid, limit;
 
-       gru_dbg(grudev, "gru %p, asid 0x%x\n", gru, asid);
+       gru_dbg(grudev, "gid %d, asid 0x%x\n", gru->gs_gid, asid);
        STAT(asid_next);
        limit = MAX_ASID;
        if (asid >= limit)
                asid = gru_wrap_asid(gru);
+       gru_flush_all_tlb(gru);
        gid = gru->gs_gid;
 again:
        for (i = 0; i < GRU_NUM_CCH; i++) {
                if (!gru->gs_gts[i])
                        continue;
                inuse_asid = gru->gs_gts[i]->ts_gms->ms_asids[gid].mt_asid;
-               gru_dbg(grudev, "gru %p, inuse_asid 0x%x, cxtnum %d, gts %p\n",
-                       gru, inuse_asid, i, gru->gs_gts[i]);
+               gru_dbg(grudev, "gid %d, gts %p, gms %p, inuse 0x%x, cxt %d\n",
+                       gru->gs_gid, gru->gs_gts[i], gru->gs_gts[i]->ts_gms,
+                       inuse_asid, i);
                if (inuse_asid == asid) {
                        asid += ASID_INC;
                        if (asid >= limit) {
@@ -120,8 +121,8 @@ again:
        }
        gru->gs_asid_limit = limit;
        gru->gs_asid = asid;
-       gru_dbg(grudev, "gru %p, new asid 0x%x, new_limit 0x%x\n", gru, asid,
-               limit);
+       gru_dbg(grudev, "gid %d, new asid 0x%x, new_limit 0x%x\n", gru->gs_gid,
+                                       asid, limit);
        return asid;
 }
 
@@ -130,14 +131,12 @@ static int gru_assign_asid(struct gru_state *gru)
 {
        int asid;
 
-       spin_lock(&gru->gs_asid_lock);
        gru->gs_asid += ASID_INC;
        asid = gru->gs_asid;
        if (asid >= gru->gs_asid_limit)
                asid = gru_reset_asid_limit(gru, asid);
-       spin_unlock(&gru->gs_asid_lock);
 
-       gru_dbg(grudev, "gru %p, asid 0x%x\n", gru, asid);
+       gru_dbg(grudev, "gid %d, asid 0x%x\n", gru->gs_gid, asid);
        return asid;
 }
 
@@ -215,17 +214,20 @@ static int check_gru_resources(struct gru_state *gru, int cbr_au_count,
  * TLB manangment requires tracking all GRU chiplets that have loaded a GSEG
  * context.
  */
-static int gru_load_mm_tracker(struct gru_state *gru, struct gru_mm_struct *gms,
-                              int ctxnum)
+static int gru_load_mm_tracker(struct gru_state *gru,
+                                       struct gru_thread_state *gts)
 {
+       struct gru_mm_struct *gms = gts->ts_gms;
        struct gru_mm_tracker *asids = &gms->ms_asids[gru->gs_gid];
-       unsigned short ctxbitmap = (1 << ctxnum);
+       unsigned short ctxbitmap = (1 << gts->ts_ctxnum);
        int asid;
 
        spin_lock(&gms->ms_asid_lock);
        asid = asids->mt_asid;
 
-       if (asid == 0 || asids->mt_asid_gen != gru->gs_asid_gen) {
+       spin_lock(&gru->gs_asid_lock);
+       if (asid == 0 || (asids->mt_ctxbitmap == 0 && asids->mt_asid_gen !=
+                         gru->gs_asid_gen)) {
                asid = gru_assign_asid(gru);
                asids->mt_asid = asid;
                asids->mt_asid_gen = gru->gs_asid_gen;
@@ -233,6 +235,7 @@ static int gru_load_mm_tracker(struct gru_state *gru, struct gru_mm_struct *gms,
        } else {
                STAT(asid_reuse);
        }
+       spin_unlock(&gru->gs_asid_lock);
 
        BUG_ON(asids->mt_ctxbitmap & ctxbitmap);
        asids->mt_ctxbitmap |= ctxbitmap;
@@ -241,24 +244,28 @@ static int gru_load_mm_tracker(struct gru_state *gru, struct gru_mm_struct *gms,
        spin_unlock(&gms->ms_asid_lock);
 
        gru_dbg(grudev,
-               "gru %x, gms %p, ctxnum 0x%d, asid 0x%x, asidmap 0x%lx\n",
-               gru->gs_gid, gms, ctxnum, asid, gms->ms_asidmap[0]);
+               "gid %d, gts %p, gms %p, ctxnum %d, asid 0x%x, asidmap 0x%lx\n",
+               gru->gs_gid, gts, gms, gts->ts_ctxnum, asid,
+               gms->ms_asidmap[0]);
        return asid;
 }
 
 static void gru_unload_mm_tracker(struct gru_state *gru,
-                                 struct gru_mm_struct *gms, int ctxnum)
+                                       struct gru_thread_state *gts)
 {
+       struct gru_mm_struct *gms = gts->ts_gms;
        struct gru_mm_tracker *asids;
        unsigned short ctxbitmap;
 
        asids = &gms->ms_asids[gru->gs_gid];
-       ctxbitmap = (1 << ctxnum);
+       ctxbitmap = (1 << gts->ts_ctxnum);
        spin_lock(&gms->ms_asid_lock);
+       spin_lock(&gru->gs_asid_lock);
        BUG_ON((asids->mt_ctxbitmap & ctxbitmap) != ctxbitmap);
        asids->mt_ctxbitmap ^= ctxbitmap;
-       gru_dbg(grudev, "gru %x, gms %p, ctxnum 0x%d, asidmap 0x%lx\n",
-               gru->gs_gid, gms, ctxnum, gms->ms_asidmap[0]);
+       gru_dbg(grudev, "gid %d, gts %p, gms %p, ctxnum 0x%d, asidmap 0x%lx\n",
+               gru->gs_gid, gts, gms, gts->ts_ctxnum, gms->ms_asidmap[0]);
+       spin_unlock(&gru->gs_asid_lock);
        spin_unlock(&gms->ms_asid_lock);
 }
 
@@ -319,6 +326,7 @@ static struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma,
        gts->ts_vma = vma;
        gts->ts_tlb_int_select = -1;
        gts->ts_gms = gru_register_mmu_notifier();
+       gts->ts_sizeavail = GRU_SIZEAVAIL(PAGE_SHIFT);
        if (!gts->ts_gms)
                goto err;
 
@@ -399,7 +407,7 @@ static void gru_free_gru_context(struct gru_thread_state *gts)
        struct gru_state *gru;
 
        gru = gts->ts_gru;
-       gru_dbg(grudev, "gts %p, gru %p\n", gts, gru);
+       gru_dbg(grudev, "gts %p, gid %d\n", gts, gru->gs_gid);
 
        spin_lock(&gru->gs_lock);
        gru->gs_gts[gts->ts_ctxnum] = NULL;
@@ -408,6 +416,7 @@ static void gru_free_gru_context(struct gru_thread_state *gts)
        __clear_bit(gts->ts_ctxnum, &gru->gs_context_map);
        gts->ts_ctxnum = NULLCTX;
        gts->ts_gru = NULL;
+       gts->ts_blade = -1;
        spin_unlock(&gru->gs_lock);
 
        gts_drop(gts);
@@ -432,8 +441,8 @@ static inline long gru_copy_handle(void *d, void *s)
        return GRU_HANDLE_BYTES;
 }
 
-static void gru_prefetch_context(void *gseg, void *cb, void *cbe, unsigned long cbrmap,
-                               unsigned long length)
+static void gru_prefetch_context(void *gseg, void *cb, void *cbe,
+                               unsigned long cbrmap, unsigned long length)
 {
        int i, scr;
 
@@ -500,12 +509,12 @@ void gru_unload_context(struct gru_thread_state *gts, int savestate)
        zap_vma_ptes(gts->ts_vma, UGRUADDR(gts), GRU_GSEG_PAGESIZE);
        cch = get_cch(gru->gs_gru_base_vaddr, ctxnum);
 
+       gru_dbg(grudev, "gts %p\n", gts);
        lock_cch_handle(cch);
        if (cch_interrupt_sync(cch))
                BUG();
-       gru_dbg(grudev, "gts %p\n", gts);
 
-       gru_unload_mm_tracker(gru, gts->ts_gms, gts->ts_ctxnum);
+       gru_unload_mm_tracker(gru, gts);
        if (savestate)
                gru_unload_context_data(gts->ts_gdata, gru->gs_gru_base_vaddr,
                                        ctxnum, gts->ts_cbr_map,
@@ -534,7 +543,7 @@ static void gru_load_context(struct gru_thread_state *gts)
        cch = get_cch(gru->gs_gru_base_vaddr, ctxnum);
 
        lock_cch_handle(cch);
-       asid = gru_load_mm_tracker(gru, gts->ts_gms, gts->ts_ctxnum);
+       asid = gru_load_mm_tracker(gru, gts);
        cch->tfm_fault_bit_enable =
            (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL
             || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR);
@@ -544,7 +553,8 @@ static void gru_load_context(struct gru_thread_state *gts)
                cch->tlb_int_select = gts->ts_tlb_int_select;
        }
        cch->tfm_done_bit_enable = 0;
-       err = cch_allocate(cch, asid, gts->ts_cbr_map, gts->ts_dsr_map);
+       err = cch_allocate(cch, asid, gts->ts_sizeavail, gts->ts_cbr_map,
+                               gts->ts_dsr_map);
        if (err) {
                gru_dbg(grudev,
                        "err %d: cch %p, gts %p, cbr 0x%lx, dsr 0x%lx\n",
@@ -565,11 +575,12 @@ static void gru_load_context(struct gru_thread_state *gts)
 /*
  * Update fields in an active CCH:
  *     - retarget interrupts on local blade
+ *     - update sizeavail mask
  *     - force a delayed context unload by clearing the CCH asids. This
  *       forces TLB misses for new GRU instructions. The context is unloaded
  *       when the next TLB miss occurs.
  */
-static int gru_update_cch(struct gru_thread_state *gts, int int_select)
+int gru_update_cch(struct gru_thread_state *gts, int force_unload)
 {
        struct gru_context_configuration_handle *cch;
        struct gru_state *gru = gts->ts_gru;
@@ -583,9 +594,11 @@ static int gru_update_cch(struct gru_thread_state *gts, int int_select)
                        goto exit;
                if (cch_interrupt(cch))
                        BUG();
-               if (int_select >= 0) {
-                       gts->ts_tlb_int_select = int_select;
-                       cch->tlb_int_select = int_select;
+               if (!force_unload) {
+                       for (i = 0; i < 8; i++)
+                               cch->sizeavail[i] = gts->ts_sizeavail;
+                       gts->ts_tlb_int_select = gru_cpu_fault_map_id();
+                       cch->tlb_int_select = gru_cpu_fault_map_id();
                } else {
                        for (i = 0; i < 8; i++)
                                cch->asid[i] = 0;
@@ -617,7 +630,7 @@ static int gru_retarget_intr(struct gru_thread_state *gts)
 
        gru_dbg(grudev, "retarget from %d to %d\n", gts->ts_tlb_int_select,
                gru_cpu_fault_map_id());
-       return gru_update_cch(gts, gru_cpu_fault_map_id());
+       return gru_update_cch(gts, 0);
 }
 
 
@@ -688,7 +701,7 @@ static void gru_steal_context(struct gru_thread_state *gts)
                STAT(steal_context_failed);
        }
        gru_dbg(grudev,
-               "stole gru %x, ctxnum %d from gts %p. Need cb %d, ds %d;"
+               "stole gid %d, ctxnum %d from gts %p. Need cb %d, ds %d;"
                " avail cb %ld, ds %ld\n",
                gru->gs_gid, ctxnum, ngts, cbr, dsr, hweight64(gru->gs_cbr_map),
                hweight64(gru->gs_dsr_map));
@@ -727,6 +740,7 @@ again:
                }
                reserve_gru_resources(gru, gts);
                gts->ts_gru = gru;
+               gts->ts_blade = gru->gs_blade_id;
                gts->ts_ctxnum =
                    find_first_zero_bit(&gru->gs_context_map, GRU_NUM_CCH);
                BUG_ON(gts->ts_ctxnum == GRU_NUM_CCH);
@@ -737,7 +751,7 @@ again:
 
                STAT(assign_context);
                gru_dbg(grudev,
-                       "gseg %p, gts %p, gru %x, ctx %d, cbr %d, dsr %d\n",
+                       "gseg %p, gts %p, gid %d, ctx %d, cbr %d, dsr %d\n",
                        gseg_virtual_address(gts->ts_gru, gts->ts_ctxnum), gts,
                        gts->ts_gru->gs_gid, gts->ts_ctxnum,
                        gts->ts_cbr_au_count, gts->ts_dsr_au_count);
@@ -773,8 +787,8 @@ int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                return VM_FAULT_SIGBUS;
 
 again:
-       preempt_disable();
        mutex_lock(&gts->ts_ctxlock);
+       preempt_disable();
        if (gts->ts_gru) {
                if (gts->ts_gru->gs_blade_id != uv_numa_blade_id()) {
                        STAT(migrated_nopfn_unload);
index 73b0ca061bb567401cc4d30a145c9daf05e72160..ee74821b171c9eff780b0079760c29b016e05371 100644 (file)
@@ -62,7 +62,9 @@ static int statistics_show(struct seq_file *s, void *p)
        printstat(s, asid_wrap);
        printstat(s, asid_reuse);
        printstat(s, intr);
+       printstat(s, intr_mm_lock_failed);
        printstat(s, call_os);
+       printstat(s, call_os_offnode_reference);
        printstat(s, call_os_check_for_bug);
        printstat(s, call_os_wait_queue);
        printstat(s, user_flush_tlb);
@@ -120,6 +122,30 @@ static ssize_t statistics_write(struct file *file, const char __user *userbuf,
        return count;
 }
 
+static int mcs_statistics_show(struct seq_file *s, void *p)
+{
+       int op;
+       unsigned long total, count, max;
+       static char *id[] = {"cch_allocate", "cch_start", "cch_interrupt",
+               "cch_interrupt_sync", "cch_deallocate", "tgh_invalidate"};
+
+       for (op = 0; op < mcsop_last; op++) {
+               count = atomic_long_read(&mcs_op_statistics[op].count);
+               total = atomic_long_read(&mcs_op_statistics[op].total);
+               max = mcs_op_statistics[op].max;
+               seq_printf(s, "%-20s%12ld%12ld%12ld\n", id[op], count,
+                          count ? total / count : 0, max);
+       }
+       return 0;
+}
+
+static ssize_t mcs_statistics_write(struct file *file,
+                       const char __user *userbuf, size_t count, loff_t *data)
+{
+       memset(mcs_op_statistics, 0, sizeof(mcs_op_statistics));
+       return count;
+}
+
 static int options_show(struct seq_file *s, void *p)
 {
        seq_printf(s, "0x%lx\n", gru_options);
@@ -135,6 +161,7 @@ static ssize_t options_write(struct file *file, const char __user *userbuf,
        if (copy_from_user
            (buf, userbuf, count < sizeof(buf) ? count : sizeof(buf)))
                return -EFAULT;
+       buf[count - 1] = '\0';
        if (!strict_strtoul(buf, 10, &val))
                gru_options = val;
 
@@ -199,7 +226,7 @@ static void seq_stop(struct seq_file *file, void *data)
 
 static void *seq_start(struct seq_file *file, loff_t *gid)
 {
-       if (*gid < GRU_MAX_GRUS)
+       if (*gid < gru_max_gids)
                return gid;
        return NULL;
 }
@@ -207,7 +234,7 @@ static void *seq_start(struct seq_file *file, loff_t *gid)
 static void *seq_next(struct seq_file *file, void *data, loff_t *gid)
 {
        (*gid)++;
-       if (*gid < GRU_MAX_GRUS)
+       if (*gid < gru_max_gids)
                return gid;
        return NULL;
 }
@@ -231,6 +258,11 @@ static int statistics_open(struct inode *inode, struct file *file)
        return single_open(file, statistics_show, NULL);
 }
 
+static int mcs_statistics_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, mcs_statistics_show, NULL);
+}
+
 static int options_open(struct inode *inode, struct file *file)
 {
        return single_open(file, options_show, NULL);
@@ -255,6 +287,14 @@ static const struct file_operations statistics_fops = {
        .release        = single_release,
 };
 
+static const struct file_operations mcs_statistics_fops = {
+       .open           = mcs_statistics_open,
+       .read           = seq_read,
+       .write          = mcs_statistics_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static const struct file_operations options_fops = {
        .open           = options_open,
        .read           = seq_read,
@@ -283,6 +323,7 @@ static struct proc_entry {
        struct proc_dir_entry *entry;
 } proc_files[] = {
        {"statistics", 0644, &statistics_fops},
+       {"mcs_statistics", 0644, &mcs_statistics_fops},
        {"debug_options", 0644, &options_fops},
        {"cch_status", 0444, &cch_fops},
        {"gru_status", 0444, &gru_fops},
index a78f70deeb59d47a9554b99ed0ec5803c6ea26ee..bf1eeb7553edda963bfea5b1b7f8de28cccf0b28 100644 (file)
 extern struct gru_stats_s gru_stats;
 extern struct gru_blade_state *gru_base[];
 extern unsigned long gru_start_paddr, gru_end_paddr;
+extern unsigned int gru_max_gids;
 
 #define GRU_MAX_BLADES         MAX_NUMNODES
 #define GRU_MAX_GRUS           (GRU_MAX_BLADES * GRU_CHIPLETS_PER_BLADE)
@@ -184,7 +185,9 @@ struct gru_stats_s {
        atomic_long_t asid_wrap;
        atomic_long_t asid_reuse;
        atomic_long_t intr;
+       atomic_long_t intr_mm_lock_failed;
        atomic_long_t call_os;
+       atomic_long_t call_os_offnode_reference;
        atomic_long_t call_os_check_for_bug;
        atomic_long_t call_os_wait_queue;
        atomic_long_t user_flush_tlb;
@@ -237,6 +240,17 @@ struct gru_stats_s {
 
 };
 
+enum mcs_op {cchop_allocate, cchop_start, cchop_interrupt, cchop_interrupt_sync,
+       cchop_deallocate, tghop_invalidate, mcsop_last};
+
+struct mcs_op_statistic {
+       atomic_long_t   count;
+       atomic_long_t   total;
+       unsigned long   max;
+};
+
+extern struct mcs_op_statistic mcs_op_statistics[mcsop_last];
+
 #define OPT_DPRINT     1
 #define OPT_STATS      2
 #define GRU_QUICKLOOK  4
@@ -278,13 +292,12 @@ struct gru_stats_s {
 /* Generate a GRU asid value from a GRU base asid & a virtual address. */
 #if defined CONFIG_IA64
 #define VADDR_HI_BIT           64
-#define GRUREGION(addr)                ((addr) >> (VADDR_HI_BIT - 3) & 3)
 #elif defined CONFIG_X86_64
 #define VADDR_HI_BIT           48
-#define GRUREGION(addr)                (0)             /* ZZZ could do better */
 #else
 #error "Unsupported architecture"
 #endif
+#define GRUREGION(addr)                ((addr) >> (VADDR_HI_BIT - 3) & 3)
 #define GRUASID(asid, addr)    ((asid) + GRUREGION(addr))
 
 /*------------------------------------------------------------------------------
@@ -297,12 +310,12 @@ struct gru_state;
  * This structure is pointed to from the mmstruct via the notifier pointer.
  * There is one of these per address space.
  */
-struct gru_mm_tracker {
-       unsigned int            mt_asid_gen;    /* ASID wrap count */
-       int                     mt_asid;        /* current base ASID for gru */
-       unsigned short          mt_ctxbitmap;   /* bitmap of contexts using
+struct gru_mm_tracker {                                /* pack to reduce size */
+       unsigned int            mt_asid_gen:24; /* ASID wrap count */
+       unsigned int            mt_asid:24;     /* current base ASID for gru */
+       unsigned short          mt_ctxbitmap:16;/* bitmap of contexts using
                                                   asid */
-};
+} __attribute__ ((packed));
 
 struct gru_mm_struct {
        struct mmu_notifier     ms_notifier;
@@ -348,6 +361,7 @@ struct gru_thread_state {
        long                    ts_user_options;/* misc user option flags */
        pid_t                   ts_tgid_owner;  /* task that is using the
                                                   context - for migration */
+       unsigned short          ts_sizeavail;   /* Pagesizes in use */
        int                     ts_tsid;        /* thread that owns the
                                                   structure */
        int                     ts_tlb_int_select;/* target cpu if interrupts
@@ -359,6 +373,9 @@ struct gru_thread_state {
                                                   required for contest */
        unsigned char           ts_cbr_au_count;/* Number of CBR resources
                                                   required for contest */
+       char                    ts_blade;       /* If >= 0, migrate context if
+                                                  ref from diferent blade */
+       char                    ts_force_cch_reload;
        char                    ts_force_unload;/* force context to be unloaded
                                                   after migration */
        char                    ts_cbr_idx[GRU_CBR_AU];/* CBR numbers of each
@@ -392,12 +409,12 @@ struct gru_state {
                                                           gru segments (64) */
        void                    *gs_gru_base_vaddr;     /* Virtual address of
                                                           gru segments (64) */
-       unsigned char           gs_gid;                 /* unique GRU number */
+       unsigned short          gs_gid;                 /* unique GRU number */
+       unsigned short          gs_blade_id;            /* blade of GRU */
        unsigned char           gs_tgh_local_shift;     /* used to pick TGH for
                                                           local flush */
        unsigned char           gs_tgh_first_remote;    /* starting TGH# for
                                                           remote flush */
-       unsigned short          gs_blade_id;            /* blade of GRU */
        spinlock_t              gs_asid_lock;           /* lock used for
                                                           assigning asids */
        spinlock_t              gs_lock;                /* lock used for
@@ -492,6 +509,10 @@ struct gru_blade_state {
                        (i) < GRU_CHIPLETS_PER_BLADE;                   \
                        (i)++, (gru)++)
 
+/* Scan all GRUs */
+#define foreach_gid(gid)                                               \
+       for ((gid) = 0; (gid) < gru_max_gids; (gid)++)
+
 /* Scan all active GTSs on a gru. Note: must hold ss_lock to use this macro. */
 #define for_each_gts_on_gru(gts, gru, ctxnum)                          \
        for ((ctxnum) = 0; (ctxnum) < GRU_NUM_CCH; (ctxnum)++)          \
@@ -578,9 +599,11 @@ extern struct gru_thread_state *gru_find_thread_state(struct vm_area_struct
 extern struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct
                                *vma, int tsid);
 extern void gru_unload_context(struct gru_thread_state *gts, int savestate);
+extern int gru_update_cch(struct gru_thread_state *gts, int force_unload);
 extern void gts_drop(struct gru_thread_state *gts);
 extern void gru_tgh_flush_init(struct gru_state *gru);
 extern int gru_kservices_init(struct gru_state *gru);
+extern void gru_kservices_exit(struct gru_state *gru);
 extern irqreturn_t gru_intr(int irq, void *dev_id);
 extern int gru_handle_user_call_os(unsigned long address);
 extern int gru_user_flush_tlb(unsigned long arg);
index c84496a7769176843d03b2ea680a620cf888c5be..1d125091f5e721f773e0c10597b2d5a232f18a49 100644 (file)
@@ -187,7 +187,7 @@ void gru_flush_tlb_range(struct gru_mm_struct *gms, unsigned long start,
        "  FLUSH gruid %d, asid 0x%x, num %ld, cbmap 0x%x\n",
                                gid, asid, num, asids->mt_ctxbitmap);
                        tgh = get_lock_tgh_handle(gru);
-                       tgh_invalidate(tgh, start, 0, asid, grupagesize, 0,
+                       tgh_invalidate(tgh, start, ~0, asid, grupagesize, 0,
                                       num - 1, asids->mt_ctxbitmap);
                        get_unlock_tgh_handle(tgh);
                } else {
@@ -210,11 +210,10 @@ void gru_flush_all_tlb(struct gru_state *gru)
 {
        struct gru_tlb_global_handle *tgh;
 
-       gru_dbg(grudev, "gru %p, gid %d\n", gru, gru->gs_gid);
+       gru_dbg(grudev, "gid %d\n", gru->gs_gid);
        tgh = get_lock_tgh_handle(gru);
-       tgh_invalidate(tgh, 0, ~0, 0, 1, 1, GRUMAXINVAL - 1, 0);
+       tgh_invalidate(tgh, 0, ~0, 0, 1, 1, GRUMAXINVAL - 1, 0xffff);
        get_unlock_tgh_handle(tgh);
-       preempt_enable();
 }
 
 /*
index 275b78896a73622362b6b53b5776db6fe20245d5..114444cfd496ee2e5526587fc7ccc2e17248a087 100644 (file)
@@ -92,7 +92,9 @@ struct xpc_rsvd_page {
        u8 pad1[3];             /* align to next u64 in 1st 64-byte cacheline */
        union {
                unsigned long vars_pa;  /* phys address of struct xpc_vars */
-               unsigned long activate_mq_gpa; /* gru phy addr of activate_mq */
+               unsigned long activate_gru_mq_desc_gpa; /* phys addr of */
+                                                       /* activate mq's */
+                                                       /* gru mq descriptor */
        } sn;
        unsigned long ts_jiffies; /* timestamp when rsvd pg was setup by XPC */
        u64 pad2[10];           /* align to last u64 in 2nd 64-byte cacheline */
@@ -189,7 +191,9 @@ struct xpc_gru_mq_uv {
        int irq;                /* irq raised when message is received in mq */
        int mmr_blade;          /* blade where watchlist was allocated from */
        unsigned long mmr_offset; /* offset of irq mmr located on mmr_blade */
+       unsigned long mmr_value; /* value of irq mmr located on mmr_blade */
        int watchlist_num;      /* number of watchlist allocatd by BIOS */
+       void *gru_mq_desc;      /* opaque structure used by the GRU driver */
 };
 
 /*
@@ -197,6 +201,7 @@ struct xpc_gru_mq_uv {
  * heartbeat, partition active state, and channel state. This is UV only.
  */
 struct xpc_activate_mq_msghdr_uv {
+       unsigned int gru_msg_hdr; /* FOR GRU INTERNAL USE ONLY */
        short partid;           /* sender's partid */
        u8 act_state;           /* sender's act_state at time msg sent */
        u8 type;                /* message's type */
@@ -232,7 +237,7 @@ struct xpc_activate_mq_msg_heartbeat_req_uv {
 struct xpc_activate_mq_msg_activate_req_uv {
        struct xpc_activate_mq_msghdr_uv hdr;
        unsigned long rp_gpa;
-       unsigned long activate_mq_gpa;
+       unsigned long activate_gru_mq_desc_gpa;
 };
 
 struct xpc_activate_mq_msg_deactivate_req_uv {
@@ -263,7 +268,7 @@ struct xpc_activate_mq_msg_chctl_openreply_uv {
        short ch_number;
        short remote_nentries;  /* ??? Is this needed? What is? */
        short local_nentries;   /* ??? Is this needed? What is? */
-       unsigned long local_notify_mq_gpa;
+       unsigned long notify_gru_mq_desc_gpa;
 };
 
 /*
@@ -510,8 +515,8 @@ struct xpc_channel_sn2 {
 };
 
 struct xpc_channel_uv {
-       unsigned long remote_notify_mq_gpa;     /* gru phys address of remote */
-                                               /* partition's notify mq */
+       void *cached_notify_gru_mq_desc; /* remote partition's notify mq's */
+                                        /* gru mq descriptor */
 
        struct xpc_send_msg_slot_uv *send_msg_slots;
        void *recv_msg_slots;   /* each slot will hold a xpc_notify_mq_msg_uv */
@@ -682,8 +687,12 @@ struct xpc_partition_sn2 {
 };
 
 struct xpc_partition_uv {
-       unsigned long remote_activate_mq_gpa;   /* gru phys address of remote */
-                                               /* partition's activate mq */
+       unsigned long activate_gru_mq_desc_gpa; /* phys addr of parititon's */
+                                               /* activate mq's gru mq */
+                                               /* descriptor */
+       void *cached_activate_gru_mq_desc; /* cached copy of partition's */
+                                          /* activate mq's gru mq descriptor */
+       struct mutex cached_activate_gru_mq_desc_mutex;
        spinlock_t flags_lock;  /* protect updating of flags */
        unsigned int flags;     /* general flags */
        u8 remote_act_state;    /* remote partition's act_state */
@@ -694,8 +703,9 @@ struct xpc_partition_uv {
 
 /* struct xpc_partition_uv flags */
 
-#define XPC_P_HEARTBEAT_OFFLINE_UV     0x00000001
-#define XPC_P_ENGAGED_UV               0x00000002
+#define XPC_P_HEARTBEAT_OFFLINE_UV             0x00000001
+#define XPC_P_ENGAGED_UV                       0x00000002
+#define XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV   0x00000004
 
 /* struct xpc_partition_uv act_state change requests */
 
@@ -804,6 +814,7 @@ extern void xpc_activate_kthreads(struct xpc_channel *, int);
 extern void xpc_create_kthreads(struct xpc_channel *, int, int);
 extern void xpc_disconnect_wait(int);
 extern int (*xpc_setup_partitions_sn) (void);
+extern void (*xpc_teardown_partitions_sn) (void);
 extern enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *, u64 *,
                                                         unsigned long *,
                                                         size_t *);
@@ -846,8 +857,8 @@ extern void (*xpc_send_chctl_openrequest) (struct xpc_channel *,
                                           unsigned long *);
 extern void (*xpc_send_chctl_openreply) (struct xpc_channel *, unsigned long *);
 
-extern void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *,
-                                           unsigned long);
+extern enum xp_retval (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *,
+                                                     unsigned long);
 
 extern enum xp_retval (*xpc_send_payload) (struct xpc_channel *, u32, void *,
                                           u16, u8, xpc_notify_func, void *);
index 45fd653dbe311b5d5c775e8ae8ee753a04b769c7..99a2534c38a1ffa092ecc9f1334a8d12aff1a16f 100644 (file)
@@ -183,6 +183,7 @@ xpc_process_openclose_chctl_flags(struct xpc_partition *part, int ch_number,
            &part->remote_openclose_args[ch_number];
        struct xpc_channel *ch = &part->channels[ch_number];
        enum xp_retval reason;
+       enum xp_retval ret;
 
        spin_lock_irqsave(&ch->lock, irq_flags);
 
@@ -399,8 +400,13 @@ again:
                DBUG_ON(args->local_nentries == 0);
                DBUG_ON(args->remote_nentries == 0);
 
+               ret = xpc_save_remote_msgqueue_pa(ch, args->local_msgqueue_pa);
+               if (ret != xpSuccess) {
+                       XPC_DISCONNECT_CHANNEL(ch, ret, &irq_flags);
+                       spin_unlock_irqrestore(&ch->lock, irq_flags);
+                       return;
+               }
                ch->flags |= XPC_C_ROPENREPLY;
-               xpc_save_remote_msgqueue_pa(ch, args->local_msgqueue_pa);
 
                if (args->local_nentries < ch->remote_nentries) {
                        dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY: new "
index 6576170de9628ae9ab72fde2aace263248ad52de..1ab9fda87fabaf581fcb5bf6e6151da7b2ca1e27 100644 (file)
@@ -171,6 +171,7 @@ static struct notifier_block xpc_die_notifier = {
 };
 
 int (*xpc_setup_partitions_sn) (void);
+void (*xpc_teardown_partitions_sn) (void);
 enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *buf, u64 *cookie,
                                                  unsigned long *rp_pa,
                                                  size_t *len);
@@ -217,8 +218,8 @@ void (*xpc_send_chctl_openrequest) (struct xpc_channel *ch,
 void (*xpc_send_chctl_openreply) (struct xpc_channel *ch,
                                  unsigned long *irq_flags);
 
-void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *ch,
-                                    unsigned long msgqueue_pa);
+enum xp_retval (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *ch,
+                                              unsigned long msgqueue_pa);
 
 enum xp_retval (*xpc_send_payload) (struct xpc_channel *ch, u32 flags,
                                    void *payload, u16 payload_size,
@@ -998,6 +999,7 @@ xpc_setup_partitions(void)
 static void
 xpc_teardown_partitions(void)
 {
+       xpc_teardown_partitions_sn();
        kfree(xpc_partitions);
 }
 
index 2e975762c32b42224f80234ccf4f8caddb34cfb4..eaaa964942de97e91b0c5edfd7d3a6ff12bc4ed4 100644 (file)
@@ -66,6 +66,12 @@ xpc_setup_partitions_sn_sn2(void)
        return 0;
 }
 
+static void
+xpc_teardown_partitions_sn_sn2(void)
+{
+       /* nothing needs to be done */
+}
+
 /* SH_IPI_ACCESS shub register value on startup */
 static u64 xpc_sh1_IPI_access_sn2;
 static u64 xpc_sh2_IPI_access0_sn2;
@@ -436,11 +442,12 @@ xpc_send_chctl_local_msgrequest_sn2(struct xpc_channel *ch)
        XPC_SEND_LOCAL_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_MSGREQUEST);
 }
 
-static void
+static enum xp_retval
 xpc_save_remote_msgqueue_pa_sn2(struct xpc_channel *ch,
                                unsigned long msgqueue_pa)
 {
        ch->sn.sn2.remote_msgqueue_pa = msgqueue_pa;
+       return xpSuccess;
 }
 
 /*
@@ -1737,20 +1744,20 @@ xpc_clear_remote_msgqueue_flags_sn2(struct xpc_channel *ch)
 {
        struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
        struct xpc_msg_sn2 *msg;
-       s64 put;
+       s64 put, remote_nentries = ch->remote_nentries;
 
        /* flags are zeroed when the buffer is allocated */
-       if (ch_sn2->remote_GP.put < ch->remote_nentries)
+       if (ch_sn2->remote_GP.put < remote_nentries)
                return;
 
-       put = max(ch_sn2->w_remote_GP.put, ch->remote_nentries);
+       put = max(ch_sn2->w_remote_GP.put, remote_nentries);
        do {
                msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue +
-                                            (put % ch->remote_nentries) *
+                                            (put % remote_nentries) *
                                             ch->entry_size);
                DBUG_ON(!(msg->flags & XPC_M_SN2_READY));
                DBUG_ON(!(msg->flags & XPC_M_SN2_DONE));
-               DBUG_ON(msg->number != put - ch->remote_nentries);
+               DBUG_ON(msg->number != put - remote_nentries);
                msg->flags = 0;
        } while (++put < ch_sn2->remote_GP.put);
 }
@@ -2315,6 +2322,7 @@ xpc_init_sn2(void)
        size_t buf_size;
 
        xpc_setup_partitions_sn = xpc_setup_partitions_sn_sn2;
+       xpc_teardown_partitions_sn = xpc_teardown_partitions_sn_sn2;
        xpc_get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_sn2;
        xpc_setup_rsvd_page_sn = xpc_setup_rsvd_page_sn_sn2;
        xpc_increment_heartbeat = xpc_increment_heartbeat_sn2;
index 29c0502a96b26fd9e9436d65f133136ccfce5410..f7fff4727edb0681840076b7c65b2a0d4b60a368 100644 (file)
 #include "../sgi-gru/grukservices.h"
 #include "xpc.h"
 
+#if defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+struct uv_IO_APIC_route_entry {
+       __u64   vector          :  8,
+               delivery_mode   :  3,
+               dest_mode       :  1,
+               delivery_status :  1,
+               polarity        :  1,
+               __reserved_1    :  1,
+               trigger         :  1,
+               mask            :  1,
+               __reserved_2    : 15,
+               dest            : 32;
+};
+#endif
+
 static atomic64_t xpc_heartbeat_uv;
 static DECLARE_BITMAP(xpc_heartbeating_to_mask_uv, XP_MAX_NPARTITIONS_UV);
 
@@ -56,26 +71,52 @@ xpc_setup_partitions_sn_uv(void)
        for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) {
                part_uv = &xpc_partitions[partid].sn.uv;
 
+               mutex_init(&part_uv->cached_activate_gru_mq_desc_mutex);
                spin_lock_init(&part_uv->flags_lock);
                part_uv->remote_act_state = XPC_P_AS_INACTIVE;
        }
        return 0;
 }
 
+static void
+xpc_teardown_partitions_sn_uv(void)
+{
+       short partid;
+       struct xpc_partition_uv *part_uv;
+       unsigned long irq_flags;
+
+       for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) {
+               part_uv = &xpc_partitions[partid].sn.uv;
+
+               if (part_uv->cached_activate_gru_mq_desc != NULL) {
+                       mutex_lock(&part_uv->cached_activate_gru_mq_desc_mutex);
+                       spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+                       part_uv->flags &= ~XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV;
+                       spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+                       kfree(part_uv->cached_activate_gru_mq_desc);
+                       part_uv->cached_activate_gru_mq_desc = NULL;
+                       mutex_unlock(&part_uv->
+                                    cached_activate_gru_mq_desc_mutex);
+               }
+       }
+}
+
 static int
 xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name)
 {
+       int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade);
+
 #if defined CONFIG_X86_64
        mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset);
        if (mq->irq < 0) {
                dev_err(xpc_part, "uv_setup_irq() returned error=%d\n",
-                       mq->irq);
+                       -mq->irq);
+               return mq->irq;
        }
 
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
-       int mmr_pnode;
-       unsigned long mmr_value;
+       mq->mmr_value = uv_read_global_mmr64(mmr_pnode, mq->mmr_offset);
 
+#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
        if (strcmp(irq_name, XPC_ACTIVATE_IRQ_NAME) == 0)
                mq->irq = SGI_XPC_ACTIVATE;
        else if (strcmp(irq_name, XPC_NOTIFY_IRQ_NAME) == 0)
@@ -83,10 +124,8 @@ xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name)
        else
                return -EINVAL;
 
-       mmr_pnode = uv_blade_to_pnode(mq->mmr_blade);
-       mmr_value = (unsigned long)cpu_physical_id(cpu) << 32 | mq->irq;
-
-       uv_write_global_mmr64(mmr_pnode, mq->mmr_offset, mmr_value);
+       mq->mmr_value = (unsigned long)cpu_physical_id(cpu) << 32 | mq->irq;
+       uv_write_global_mmr64(mmr_pnode, mq->mmr_offset, mq->mmr_value);
 #else
        #error not a supported configuration
 #endif
@@ -127,7 +166,7 @@ xpc_gru_mq_watchlist_alloc_uv(struct xpc_gru_mq_uv *mq)
                return ret;
        }
 #elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
-       ret = sn_mq_watchlist_alloc(mq->mmr_blade, uv_gpa(mq->address),
+       ret = sn_mq_watchlist_alloc(mq->mmr_blade, (void *)uv_gpa(mq->address),
                                    mq->order, &mq->mmr_offset);
        if (ret < 0) {
                dev_err(xpc_part, "sn_mq_watchlist_alloc() failed, ret=%d\n",
@@ -168,12 +207,22 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
        int pg_order;
        struct page *page;
        struct xpc_gru_mq_uv *mq;
+       struct uv_IO_APIC_route_entry *mmr_value;
 
        mq = kmalloc(sizeof(struct xpc_gru_mq_uv), GFP_KERNEL);
        if (mq == NULL) {
                dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to kmalloc() "
                        "a xpc_gru_mq_uv structure\n");
                ret = -ENOMEM;
+               goto out_0;
+       }
+
+       mq->gru_mq_desc = kzalloc(sizeof(struct gru_message_queue_desc),
+                                 GFP_KERNEL);
+       if (mq->gru_mq_desc == NULL) {
+               dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to kmalloc() "
+                       "a gru_message_queue_desc structure\n");
+               ret = -ENOMEM;
                goto out_1;
        }
 
@@ -194,14 +243,6 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
        }
        mq->address = page_address(page);
 
-       ret = gru_create_message_queue(mq->address, mq_size);
-       if (ret != 0) {
-               dev_err(xpc_part, "gru_create_message_queue() returned "
-                       "error=%d\n", ret);
-               ret = -EINVAL;
-               goto out_3;
-       }
-
        /* enable generation of irq when GRU mq operation occurs to this mq */
        ret = xpc_gru_mq_watchlist_alloc_uv(mq);
        if (ret != 0)
@@ -214,10 +255,20 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
        ret = request_irq(mq->irq, irq_handler, 0, irq_name, NULL);
        if (ret != 0) {
                dev_err(xpc_part, "request_irq(irq=%d) returned error=%d\n",
-                       mq->irq, ret);
+                       mq->irq, -ret);
                goto out_5;
        }
 
+       mmr_value = (struct uv_IO_APIC_route_entry *)&mq->mmr_value;
+       ret = gru_create_message_queue(mq->gru_mq_desc, mq->address, mq_size,
+                                      nid, mmr_value->vector, mmr_value->dest);
+       if (ret != 0) {
+               dev_err(xpc_part, "gru_create_message_queue() returned "
+                       "error=%d\n", ret);
+               ret = -EINVAL;
+               goto out_6;
+       }
+
        /* allow other partitions to access this GRU mq */
        xp_ret = xp_expand_memprotect(xp_pa(mq->address), mq_size);
        if (xp_ret != xpSuccess) {
@@ -237,8 +288,10 @@ out_4:
 out_3:
        free_pages((unsigned long)mq->address, pg_order);
 out_2:
-       kfree(mq);
+       kfree(mq->gru_mq_desc);
 out_1:
+       kfree(mq);
+out_0:
        return ERR_PTR(ret);
 }
 
@@ -268,13 +321,14 @@ xpc_destroy_gru_mq_uv(struct xpc_gru_mq_uv *mq)
 }
 
 static enum xp_retval
-xpc_send_gru_msg(unsigned long mq_gpa, void *msg, size_t msg_size)
+xpc_send_gru_msg(struct gru_message_queue_desc *gru_mq_desc, void *msg,
+                size_t msg_size)
 {
        enum xp_retval xp_ret;
        int ret;
 
        while (1) {
-               ret = gru_send_message_gpa(mq_gpa, msg, msg_size);
+               ret = gru_send_message_gpa(gru_mq_desc, msg, msg_size);
                if (ret == MQE_OK) {
                        xp_ret = xpSuccess;
                        break;
@@ -421,7 +475,15 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
                part_uv->act_state_req = XPC_P_ASR_ACTIVATE_UV;
                part->remote_rp_pa = msg->rp_gpa; /* !!! _pa is _gpa */
                part->remote_rp_ts_jiffies = msg_hdr->rp_ts_jiffies;
-               part_uv->remote_activate_mq_gpa = msg->activate_mq_gpa;
+
+               if (msg->activate_gru_mq_desc_gpa !=
+                   part_uv->activate_gru_mq_desc_gpa) {
+                       spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+                       part_uv->flags &= ~XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV;
+                       spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+                       part_uv->activate_gru_mq_desc_gpa =
+                           msg->activate_gru_mq_desc_gpa;
+               }
                spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
 
                (*wakeup_hb_checker)++;
@@ -498,7 +560,7 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
                args = &part->remote_openclose_args[msg->ch_number];
                args->remote_nentries = msg->remote_nentries;
                args->local_nentries = msg->local_nentries;
-               args->local_msgqueue_pa = msg->local_notify_mq_gpa;
+               args->local_msgqueue_pa = msg->notify_gru_mq_desc_gpa;
 
                spin_lock_irqsave(&part->chctl_lock, irq_flags);
                part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENREPLY;
@@ -558,9 +620,10 @@ xpc_handle_activate_IRQ_uv(int irq, void *dev_id)
        short partid;
        struct xpc_partition *part;
        int wakeup_hb_checker = 0;
+       int part_referenced;
 
        while (1) {
-               msg_hdr = gru_get_next_message(xpc_activate_mq_uv->address);
+               msg_hdr = gru_get_next_message(xpc_activate_mq_uv->gru_mq_desc);
                if (msg_hdr == NULL)
                        break;
 
@@ -571,14 +634,15 @@ xpc_handle_activate_IRQ_uv(int irq, void *dev_id)
                                partid);
                } else {
                        part = &xpc_partitions[partid];
-                       if (xpc_part_ref(part)) {
-                               xpc_handle_activate_mq_msg_uv(part, msg_hdr,
-                                                           &wakeup_hb_checker);
+
+                       part_referenced = xpc_part_ref(part);
+                       xpc_handle_activate_mq_msg_uv(part, msg_hdr,
+                                                     &wakeup_hb_checker);
+                       if (part_referenced)
                                xpc_part_deref(part);
-                       }
                }
 
-               gru_free_message(xpc_activate_mq_uv->address, msg_hdr);
+               gru_free_message(xpc_activate_mq_uv->gru_mq_desc, msg_hdr);
        }
 
        if (wakeup_hb_checker)
@@ -587,22 +651,74 @@ xpc_handle_activate_IRQ_uv(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static enum xp_retval
+xpc_cache_remote_gru_mq_desc_uv(struct gru_message_queue_desc *gru_mq_desc,
+                               unsigned long gru_mq_desc_gpa)
+{
+       enum xp_retval ret;
+
+       ret = xp_remote_memcpy(uv_gpa(gru_mq_desc), gru_mq_desc_gpa,
+                              sizeof(struct gru_message_queue_desc));
+       if (ret == xpSuccess)
+               gru_mq_desc->mq = NULL;
+
+       return ret;
+}
+
 static enum xp_retval
 xpc_send_activate_IRQ_uv(struct xpc_partition *part, void *msg, size_t msg_size,
                         int msg_type)
 {
        struct xpc_activate_mq_msghdr_uv *msg_hdr = msg;
+       struct xpc_partition_uv *part_uv = &part->sn.uv;
+       struct gru_message_queue_desc *gru_mq_desc;
+       unsigned long irq_flags;
+       enum xp_retval ret;
 
        DBUG_ON(msg_size > XPC_ACTIVATE_MSG_SIZE_UV);
 
        msg_hdr->type = msg_type;
-       msg_hdr->partid = XPC_PARTID(part);
+       msg_hdr->partid = xp_partition_id;
        msg_hdr->act_state = part->act_state;
        msg_hdr->rp_ts_jiffies = xpc_rsvd_page->ts_jiffies;
 
+       mutex_lock(&part_uv->cached_activate_gru_mq_desc_mutex);
+again:
+       if (!(part_uv->flags & XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV)) {
+               gru_mq_desc = part_uv->cached_activate_gru_mq_desc;
+               if (gru_mq_desc == NULL) {
+                       gru_mq_desc = kmalloc(sizeof(struct
+                                             gru_message_queue_desc),
+                                             GFP_KERNEL);
+                       if (gru_mq_desc == NULL) {
+                               ret = xpNoMemory;
+                               goto done;
+                       }
+                       part_uv->cached_activate_gru_mq_desc = gru_mq_desc;
+               }
+
+               ret = xpc_cache_remote_gru_mq_desc_uv(gru_mq_desc,
+                                                     part_uv->
+                                                     activate_gru_mq_desc_gpa);
+               if (ret != xpSuccess)
+                       goto done;
+
+               spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+               part_uv->flags |= XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV;
+               spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+       }
+
        /* ??? Is holding a spin_lock (ch->lock) during this call a bad idea? */
-       return xpc_send_gru_msg(part->sn.uv.remote_activate_mq_gpa, msg,
-                               msg_size);
+       ret = xpc_send_gru_msg(part_uv->cached_activate_gru_mq_desc, msg,
+                              msg_size);
+       if (ret != xpSuccess) {
+               smp_rmb();      /* ensure a fresh copy of part_uv->flags */
+               if (!(part_uv->flags & XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV))
+                       goto again;
+       }
+done:
+       mutex_unlock(&part_uv->cached_activate_gru_mq_desc_mutex);
+       return ret;
 }
 
 static void
@@ -620,7 +736,7 @@ static void
 xpc_send_activate_IRQ_ch_uv(struct xpc_channel *ch, unsigned long *irq_flags,
                         void *msg, size_t msg_size, int msg_type)
 {
-       struct xpc_partition *part = &xpc_partitions[ch->number];
+       struct xpc_partition *part = &xpc_partitions[ch->partid];
        enum xp_retval ret;
 
        ret = xpc_send_activate_IRQ_uv(part, msg, msg_size, msg_type);
@@ -692,7 +808,8 @@ xpc_get_partition_rsvd_page_pa_uv(void *buf, u64 *cookie, unsigned long *rp_pa,
 static int
 xpc_setup_rsvd_page_sn_uv(struct xpc_rsvd_page *rp)
 {
-       rp->sn.activate_mq_gpa = uv_gpa(xpc_activate_mq_uv->address);
+       rp->sn.activate_gru_mq_desc_gpa =
+           uv_gpa(xpc_activate_mq_uv->gru_mq_desc);
        return 0;
 }
 
@@ -787,7 +904,8 @@ xpc_request_partition_activation_uv(struct xpc_rsvd_page *remote_rp,
 
        part->remote_rp_pa = remote_rp_gpa; /* !!! _pa here is really _gpa */
        part->remote_rp_ts_jiffies = remote_rp->ts_jiffies;
-       part->sn.uv.remote_activate_mq_gpa = remote_rp->sn.activate_mq_gpa;
+       part->sn.uv.activate_gru_mq_desc_gpa =
+           remote_rp->sn.activate_gru_mq_desc_gpa;
 
        /*
         * ??? Is it a good idea to make this conditional on what is
@@ -795,7 +913,8 @@ xpc_request_partition_activation_uv(struct xpc_rsvd_page *remote_rp,
         */
        if (part->sn.uv.remote_act_state == XPC_P_AS_INACTIVE) {
                msg.rp_gpa = uv_gpa(xpc_rsvd_page);
-               msg.activate_mq_gpa = xpc_rsvd_page->sn.activate_mq_gpa;
+               msg.activate_gru_mq_desc_gpa =
+                   xpc_rsvd_page->sn.activate_gru_mq_desc_gpa;
                xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg),
                                           XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV);
        }
@@ -857,7 +976,8 @@ xpc_get_fifo_entry_uv(struct xpc_fifo_head_uv *head)
                if (head->first == NULL)
                        head->last = NULL;
        }
-       head->n_entries++;
+       head->n_entries--;
+       BUG_ON(head->n_entries < 0);
        spin_unlock_irqrestore(&head->lock, irq_flags);
        first->next = NULL;
        return first;
@@ -876,8 +996,7 @@ xpc_put_fifo_entry_uv(struct xpc_fifo_head_uv *head,
        else
                head->first = last;
        head->last = last;
-       head->n_entries--;
-       BUG_ON(head->n_entries < 0);
+       head->n_entries++;
        spin_unlock_irqrestore(&head->lock, irq_flags);
 }
 
@@ -1037,6 +1156,12 @@ xpc_setup_msg_structures_uv(struct xpc_channel *ch)
 
        DBUG_ON(ch->flags & XPC_C_SETUP);
 
+       ch_uv->cached_notify_gru_mq_desc = kmalloc(sizeof(struct
+                                                  gru_message_queue_desc),
+                                                  GFP_KERNEL);
+       if (ch_uv->cached_notify_gru_mq_desc == NULL)
+               return xpNoMemory;
+
        ret = xpc_allocate_send_msg_slot_uv(ch);
        if (ret == xpSuccess) {
 
@@ -1060,7 +1185,8 @@ xpc_teardown_msg_structures_uv(struct xpc_channel *ch)
 
        DBUG_ON(!spin_is_locked(&ch->lock));
 
-       ch_uv->remote_notify_mq_gpa = 0;
+       kfree(ch_uv->cached_notify_gru_mq_desc);
+       ch_uv->cached_notify_gru_mq_desc = NULL;
 
        if (ch->flags & XPC_C_SETUP) {
                xpc_init_fifo_uv(&ch_uv->msg_slot_free_list);
@@ -1111,7 +1237,7 @@ xpc_send_chctl_openreply_uv(struct xpc_channel *ch, unsigned long *irq_flags)
        msg.ch_number = ch->number;
        msg.local_nentries = ch->local_nentries;
        msg.remote_nentries = ch->remote_nentries;
-       msg.local_notify_mq_gpa = uv_gpa(xpc_notify_mq_uv);
+       msg.notify_gru_mq_desc_gpa = uv_gpa(xpc_notify_mq_uv->gru_mq_desc);
        xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg),
                                    XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV);
 }
@@ -1128,11 +1254,15 @@ xpc_send_chctl_local_msgrequest_uv(struct xpc_partition *part, int ch_number)
        xpc_wakeup_channel_mgr(part);
 }
 
-static void
+static enum xp_retval
 xpc_save_remote_msgqueue_pa_uv(struct xpc_channel *ch,
-                              unsigned long msgqueue_pa)
+                              unsigned long gru_mq_desc_gpa)
 {
-       ch->sn.uv.remote_notify_mq_gpa = msgqueue_pa;
+       struct xpc_channel_uv *ch_uv = &ch->sn.uv;
+
+       DBUG_ON(ch_uv->cached_notify_gru_mq_desc == NULL);
+       return xpc_cache_remote_gru_mq_desc_uv(ch_uv->cached_notify_gru_mq_desc,
+                                              gru_mq_desc_gpa);
 }
 
 static void
@@ -1339,7 +1469,8 @@ xpc_handle_notify_IRQ_uv(int irq, void *dev_id)
        short partid;
        struct xpc_partition *part;
 
-       while ((msg = gru_get_next_message(xpc_notify_mq_uv)) != NULL) {
+       while ((msg = gru_get_next_message(xpc_notify_mq_uv->gru_mq_desc)) !=
+              NULL) {
 
                partid = msg->hdr.partid;
                if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) {
@@ -1354,7 +1485,7 @@ xpc_handle_notify_IRQ_uv(int irq, void *dev_id)
                        }
                }
 
-               gru_free_message(xpc_notify_mq_uv, msg);
+               gru_free_message(xpc_notify_mq_uv->gru_mq_desc, msg);
        }
 
        return IRQ_HANDLED;
@@ -1438,7 +1569,8 @@ xpc_send_payload_uv(struct xpc_channel *ch, u32 flags, void *payload,
        msg->hdr.msg_slot_number = msg_slot->msg_slot_number;
        memcpy(&msg->payload, payload, payload_size);
 
-       ret = xpc_send_gru_msg(ch->sn.uv.remote_notify_mq_gpa, msg, msg_size);
+       ret = xpc_send_gru_msg(ch->sn.uv.cached_notify_gru_mq_desc, msg,
+                              msg_size);
        if (ret == xpSuccess)
                goto out_1;
 
@@ -1529,7 +1661,7 @@ xpc_received_payload_uv(struct xpc_channel *ch, void *payload)
        msg->hdr.partid = xp_partition_id;
        msg->hdr.size = 0;      /* size of zero indicates this is an ACK */
 
-       ret = xpc_send_gru_msg(ch->sn.uv.remote_notify_mq_gpa, msg,
+       ret = xpc_send_gru_msg(ch->sn.uv.cached_notify_gru_mq_desc, msg,
                               sizeof(struct xpc_notify_mq_msghdr_uv));
        if (ret != xpSuccess)
                XPC_DEACTIVATE_PARTITION(&xpc_partitions[ch->partid], ret);
@@ -1541,6 +1673,7 @@ int
 xpc_init_uv(void)
 {
        xpc_setup_partitions_sn = xpc_setup_partitions_sn_uv;
+       xpc_teardown_partitions_sn = xpc_teardown_partitions_sn_uv;
        xpc_process_activate_IRQ_rcvd = xpc_process_activate_IRQ_rcvd_uv;
        xpc_get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_uv;
        xpc_setup_rsvd_page_sn = xpc_setup_rsvd_page_sn_uv;
index 78ad48718ab028e61b1d77d83e29de8efbe9930c..36a8d53ad2a2ba90cf7b5d7dd3fffb647545a1d1 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/mutex.h>
+#include <linux/seq_file.h>
 #include <linux/serial_reg.h>
 #include <linux/circ_buf.h>
 #include <linux/gfp.h>
@@ -933,67 +934,64 @@ static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file,
        return result;
 }
 
-static int sdio_uart_read_proc(char *page, char **start, off_t off,
-                              int count, int *eof, void *data)
+static int sdio_uart_proc_show(struct seq_file *m, void *v)
 {
-       int i, len = 0;
-       off_t begin = 0;
+       int i;
 
-       len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n",
+       seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n",
                       "", "", "");
-       for (i = 0; i < UART_NR && len < PAGE_SIZE - 96; i++) {
+       for (i = 0; i < UART_NR; i++) {
                struct sdio_uart_port *port = sdio_uart_port_get(i);
                if (port) {
-                       len += sprintf(page+len, "%d: uart:SDIO", i);
+                       seq_printf(m, "%d: uart:SDIO", i);
                        if(capable(CAP_SYS_ADMIN)) {
-                               len += sprintf(page + len, " tx:%d rx:%d",
+                               seq_printf(m, " tx:%d rx:%d",
                                               port->icount.tx, port->icount.rx);
                                if (port->icount.frame)
-                                       len += sprintf(page + len, " fe:%d",
+                                       seq_printf(m, " fe:%d",
                                                       port->icount.frame);
                                if (port->icount.parity)
-                                       len += sprintf(page + len, " pe:%d",
+                                       seq_printf(m, " pe:%d",
                                                       port->icount.parity);
                                if (port->icount.brk)
-                                       len += sprintf(page + len, " brk:%d",
+                                       seq_printf(m, " brk:%d",
                                                       port->icount.brk);
                                if (port->icount.overrun)
-                                       len += sprintf(page + len, " oe:%d",
+                                       seq_printf(m, " oe:%d",
                                                       port->icount.overrun);
                                if (port->icount.cts)
-                                       len += sprintf(page + len, " cts:%d",
+                                       seq_printf(m, " cts:%d",
                                                       port->icount.cts);
                                if (port->icount.dsr)
-                                       len += sprintf(page + len, " dsr:%d",
+                                       seq_printf(m, " dsr:%d",
                                                       port->icount.dsr);
                                if (port->icount.rng)
-                                       len += sprintf(page + len, " rng:%d",
+                                       seq_printf(m, " rng:%d",
                                                       port->icount.rng);
                                if (port->icount.dcd)
-                                       len += sprintf(page + len, " dcd:%d",
+                                       seq_printf(m, " dcd:%d",
                                                       port->icount.dcd);
                        }
-                       strcat(page, "\n");
-                       len++;
                        sdio_uart_port_put(port);
-               }
-
-               if (len + begin > off + count)
-                       goto done;
-               if (len + begin < off) {
-                       begin += len;
-                       len = 0;
+                       seq_putc(m, '\n');
                }
        }
-       *eof = 1;
+       return 0;
+}
 
-done:
-       if (off >= len + begin)
-               return 0;
-       *start = page + (off - begin);
-       return (count < begin + len - off) ? count : (begin + len - off);
+static int sdio_uart_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, sdio_uart_proc_show, NULL);
 }
 
+static const struct file_operations sdio_uart_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = sdio_uart_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static const struct tty_operations sdio_uart_ops = {
        .open                   = sdio_uart_open,
        .close                  = sdio_uart_close,
@@ -1007,7 +1005,7 @@ static const struct tty_operations sdio_uart_ops = {
        .break_ctl              = sdio_uart_break_ctl,
        .tiocmget               = sdio_uart_tiocmget,
        .tiocmset               = sdio_uart_tiocmset,
-       .read_proc              = sdio_uart_read_proc,
+       .proc_fops              = &sdio_uart_proc_fops,
 };
 
 static struct tty_driver *sdio_uart_tty_driver;
index 9c326a50a3eecb22851cc21ecb5f3d3a3e861e5b..99610f358c40629cecf9a12dfbc2566587a5026d 100644 (file)
@@ -3444,25 +3444,12 @@ static void bond_remove_proc_entry(struct bonding *bond)
  */
 static void bond_create_proc_dir(void)
 {
-       int len = strlen(DRV_NAME);
-
-       for (bond_proc_dir = init_net.proc_net->subdir; bond_proc_dir;
-            bond_proc_dir = bond_proc_dir->next) {
-               if ((bond_proc_dir->namelen == len) &&
-                   !memcmp(bond_proc_dir->name, DRV_NAME, len)) {
-                       break;
-               }
-       }
-
        if (!bond_proc_dir) {
                bond_proc_dir = proc_mkdir(DRV_NAME, init_net.proc_net);
-               if (bond_proc_dir) {
-                       bond_proc_dir->owner = THIS_MODULE;
-               } else {
+               if (!bond_proc_dir)
                        printk(KERN_WARNING DRV_NAME
                                ": Warning: cannot create /proc/net/%s\n",
                                DRV_NAME);
-               }
        }
 }
 
@@ -3471,25 +3458,7 @@ static void bond_create_proc_dir(void)
  */
 static void bond_destroy_proc_dir(void)
 {
-       struct proc_dir_entry *de;
-
-       if (!bond_proc_dir) {
-               return;
-       }
-
-       /* verify that the /proc dir is empty */
-       for (de = bond_proc_dir->subdir; de; de = de->next) {
-               /* ignore . and .. */
-               if (*(de->name) != '.') {
-                       break;
-               }
-       }
-
-       if (de) {
-               if (bond_proc_dir->owner == THIS_MODULE) {
-                       bond_proc_dir->owner = NULL;
-               }
-       } else {
+       if (bond_proc_dir) {
                remove_proc_entry(DRV_NAME, init_net.proc_net);
                bond_proc_dir = NULL;
        }
index 254ec62b5f58d4e13f3848040362e7660108b6d3..d8350860c0f8db5e6c622f4962586d8024c2636f 100644 (file)
@@ -559,7 +559,7 @@ static void dm9000_show_carrier(board_info_t *db,
 static void
 dm9000_poll_work(struct work_struct *w)
 {
-       struct delayed_work *dw = container_of(w, struct delayed_work, work);
+       struct delayed_work *dw = to_delayed_work(w);
        board_info_t *db = container_of(dw, board_info_t, phy_poll);
        struct net_device *ndev = db->ndev;
 
index 2d0a198882ab9df0ef85f5324b8eb42568aac0c0..8bbe7f6179949c30b167d82cb2236394af9332c4 100644 (file)
@@ -1134,9 +1134,9 @@ static int mpc52xx_fec_of_resume(struct of_device *op)
 #endif
 
 static struct of_device_id mpc52xx_fec_match[] = {
-       { .type = "network", .compatible = "fsl,mpc5200b-fec", },
-       { .type = "network", .compatible = "fsl,mpc5200-fec", },
-       { .type = "network", .compatible = "mpc5200-fec", },
+       { .compatible = "fsl,mpc5200b-fec", },
+       { .compatible = "fsl,mpc5200-fec", },
+       { .compatible = "mpc5200-fec", },
        { }
 };
 
index 1243bc8e0035877dd2edf703b96edfbacdaaa54b..ac0e4b6b6b66793ca8fd16b2ffff4818975c2a28 100644 (file)
@@ -1871,13 +1871,6 @@ static int __init vlsi_mod_init(void)
         * without procfs - it's not required for the driver to work.
         */
        vlsi_proc_root = proc_mkdir(PROC_DIR, NULL);
-       if (vlsi_proc_root) {
-               /* protect registered procdir against module removal.
-                * Because we are in the module init path there's no race
-                * window after create_proc_entry (and no barrier needed).
-                */
-               vlsi_proc_root->owner = THIS_MODULE;
-       }
 
        ret = pci_register_driver(&vlsi_irda_driver);
 
index c336a1f42510c09d5c9e690cc46c207f9f6880e3..aa08987f6e8156e6f9dd18bcc30a279bb23a73ab 100644 (file)
@@ -398,7 +398,7 @@ static void meth_rx(struct net_device* dev, unsigned long int_status)
                        int len = (status & 0xffff) - 4; /* omit CRC */
                        /* length sanity check */
                        if (len < 60 || len > 1518) {
-                               printk(KERN_DEBUG "%s: bogus packet size: %ld, status=%#2lx.\n",
+                               printk(KERN_DEBUG "%s: bogus packet size: %ld, status=%#2Lx.\n",
                                       dev->name, priv->rx_write,
                                       priv->rx_ring[priv->rx_write]->status.raw);
                                dev->stats.rx_errors++;
index 9f6644a440304e756822119142dd0602e0c7ccc1..303c23de6cacff0c917b1e6c48f62e5f1003b5b2 100644 (file)
@@ -505,7 +505,7 @@ out:
 
 static void mlx4_en_do_get_stats(struct work_struct *work)
 {
-       struct delayed_work *delay = container_of(work, struct delayed_work, work);
+       struct delayed_work *delay = to_delayed_work(work);
        struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv,
                                                 stats_task);
        struct mlx4_en_dev *mdev = priv->mdev;
index a4130e764991a79e77a30395c685a2ac5088188e..7e40741fb7d87ef9d1136797cb54145db8cbe6dc 100644 (file)
@@ -298,7 +298,7 @@ static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv,
 
 void mlx4_en_rx_refill(struct work_struct *work)
 {
-       struct delayed_work *delay = container_of(work, struct delayed_work, work);
+       struct delayed_work *delay = to_delayed_work(work);
        struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv,
                                                 refill_task);
        struct mlx4_en_dev *mdev = priv->mdev;
index 6d5089ecb5af2c2d3d51202e90a1a2ed3cd645f4..f36ae691cab3c343091fb7130591c8737ab4afee 100644 (file)
@@ -103,7 +103,7 @@ void mlx4_do_sense_ports(struct mlx4_dev *dev,
 
 static void mlx4_sense_port(struct work_struct *work)
 {
-       struct delayed_work *delay = container_of(work, struct delayed_work, work);
+       struct delayed_work *delay = to_delayed_work(work);
        struct mlx4_sense *sense = container_of(delay, struct mlx4_sense,
                                                sense_poll);
        struct mlx4_dev *dev = sense->dev;
index 58b73b08dde08503b35d6e8d3c7ef4f6620ad8c2..3ff1f425f1bb2e48c3321034bb7d9c646331229f 100644 (file)
@@ -757,8 +757,7 @@ EXPORT_SYMBOL(phy_start);
  */
 static void phy_state_machine(struct work_struct *work)
 {
-       struct delayed_work *dwork =
-                       container_of(work, struct delayed_work, work);
+       struct delayed_work *dwork = to_delayed_work(work);
        struct phy_device *phydev =
                        container_of(dwork, struct phy_device, state_queue);
        int needs_aneg = 0;
index 6c44f86ae3fdb9a42b816c05d31b9e627be214a4..912308eec8657ed9db7528dff8cb69f37c2f3772 100644 (file)
@@ -346,38 +346,6 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r,
 #define RPC_LSA_DEFAULT                RPC_LED_TX_RX
 #define RPC_LSB_DEFAULT                RPC_LED_100_10
 
-#elif defined(CONFIG_SOC_AU1X00)
-
-#include <au1xxx.h>
-
-/* We can only do 16-bit reads and writes in the static memory space. */
-#define SMC_CAN_USE_8BIT       0
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      0
-#define SMC_IO_SHIFT           0
-#define SMC_NOWAIT             1
-
-#define SMC_inw(a, r)          au_readw((unsigned long)((a) + (r)))
-#define SMC_insw(a, r, p, l)   \
-       do {    \
-               unsigned long _a = (unsigned long)((a) + (r)); \
-               int _l = (l); \
-               u16 *_p = (u16 *)(p); \
-               while (_l-- > 0) \
-                       *_p++ = au_readw(_a); \
-       } while(0)
-#define SMC_outw(v, a, r)      au_writew(v, (unsigned long)((a) + (r)))
-#define SMC_outsw(a, r, p, l)  \
-       do {    \
-               unsigned long _a = (unsigned long)((a) + (r)); \
-               int _l = (l); \
-               const u16 *_p = (const u16 *)(p); \
-               while (_l-- > 0) \
-                       au_writew(*_p++ , _a); \
-       } while(0)
-
-#define SMC_IRQ_FLAGS          (0)
-
 #elif  defined(CONFIG_ARCH_VERSATILE)
 
 #define SMC_CAN_USE_8BIT       1
index 93302c0a36b045f5eabd70cc5b5f0834e8d93769..f21a6171c691940b8f9d7788da1153766ba3ec74 100644 (file)
@@ -4492,7 +4492,6 @@ static int setup_proc_entry( struct net_device *dev,
                goto fail;
        apriv->proc_entry->uid = proc_uid;
        apriv->proc_entry->gid = proc_gid;
-       apriv->proc_entry->owner = THIS_MODULE;
 
        /* Setup the StatsDelta */
        entry = proc_create_data("StatsDelta",
index cd17092b82bd4bbfa93e760e994046861d8f9902..41c5dfd853586704d0ac75fee8b23068466fa9d8 100644 (file)
@@ -446,6 +446,7 @@ struct of_modalias_table {
 };
 static struct of_modalias_table of_modalias_table[] = {
        { "fsl,mcu-mpc8349emitx", "mcu-mpc8349emitx" },
+       { "mmc-spi-slot", "mmc_spi" },
 };
 
 /**
index c3ea5fa7d05a6db4079bebb99ecc865b89eefca5..2c9aa49e43cdf1a879214ac281bf705b84015f25 100644 (file)
@@ -574,7 +574,7 @@ int __init buffer_sync_init(void)
                return 0;
 }
 
-void __exit buffer_sync_cleanup(void)
+void buffer_sync_cleanup(void)
 {
        free_cpumask_var(marked_cpus);
 }
index 032db815b0f9784f6835548d68333edc4c376022..f3492110b1ad31bb8f895f2c2e6bde361221148c 100644 (file)
@@ -30,6 +30,7 @@ enum parport_pc_pci_cards {
        titan_210l,
        netmos_9xx5_combo,
        netmos_9855,
+       netmos_9855_2p,
        avlab_1s1p,
        avlab_1s2p,
        avlab_2s1p,
@@ -62,7 +63,7 @@ struct parport_pc_pci {
                                struct parport_pc_pci *card, int failed);
 };
 
-static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *card, int autoirq, int autodma)
+static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *par, int autoirq, int autodma)
 {
        /* the rule described below doesn't hold for this device */
        if (dev->device == PCI_DEVICE_ID_NETMOS_9835 &&
@@ -74,9 +75,17 @@ static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc
         * and serial ports.  The form is 0x00PS, where <P> is the number of
         * parallel ports and <S> is the number of serial ports.
         */
-       card->numports = (dev->subsystem_device & 0xf0) >> 4;
-       if (card->numports > ARRAY_SIZE(card->addr))
-               card->numports = ARRAY_SIZE(card->addr);
+       par->numports = (dev->subsystem_device & 0xf0) >> 4;
+       if (par->numports > ARRAY_SIZE(par->addr))
+               par->numports = ARRAY_SIZE(par->addr);
+       /*
+        * This function is currently only called for cards with up to
+        * one parallel port.
+        * Parallel port BAR is either before or after serial ports BARS;
+        * hence, lo should be either 0 or equal to the number of serial ports.
+        */
+       if (par->addr[0].lo != 0)
+               par->addr[0].lo = dev->subsystem_device & 0xf;
        return 0;
 }
 
@@ -84,7 +93,8 @@ static struct parport_pc_pci cards[] __devinitdata = {
        /* titan_110l */                { 1, { { 3, -1 }, } },
        /* titan_210l */                { 1, { { 3, -1 }, } },
        /* netmos_9xx5_combo */         { 1, { { 2, -1 }, }, netmos_parallel_init },
-       /* netmos_9855 */               { 1, { { 2, -1 }, }, netmos_parallel_init },
+       /* netmos_9855 */               { 1, { { 0, -1 }, }, netmos_parallel_init },
+       /* netmos_9855_2p */            { 2, { { 0, -1 }, { 2, -1 }, } },
        /* avlab_1s1p     */            { 1, { { 1, 2}, } },
        /* avlab_1s2p     */            { 2, { { 1, 2}, { 3, 4 },} },
        /* avlab_2s1p     */            { 1, { { 2, 3}, } },
@@ -109,6 +119,10 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
        { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9845,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
+       { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
+         0x1000, 0x0020, 0, 0, netmos_9855_2p },
+       { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
+         0x1000, 0x0022, 0, 0, netmos_9855_2p },
        { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9855 },
        /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
@@ -192,6 +206,12 @@ static struct pciserial_board pci_parport_serial_boards[] __devinitdata = {
                .uart_offset    = 8,
        },
        [netmos_9855] = {
+               .flags          = FL_BASE2 | FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [netmos_9855_2p] = {
                .flags          = FL_BASE4 | FL_BASE_BARS,
                .num_ports      = 1,
                .base_baud      = 115200,
index 2a4501dd251503ddb6d5fefd78737b4c97425452..fdc864f9cf233d5134803593640f49c3ed0b1ccf 100644 (file)
@@ -59,3 +59,13 @@ config HT_IRQ
           This allows native hypertransport devices to use interrupts.
 
           If unsure say Y.
+
+config PCI_IOV
+       bool "PCI IOV support"
+       depends on PCI
+       help
+         I/O Virtualization is a PCI feature supported by some devices
+         which allows them to create virtual devices which share their
+         physical resources.
+
+         If unsure, say N.
index 3d07ce24f6a8a2eae8b44bdbaf11dcaf536a2fed..ba6af162fd39a259663c53c0269cf98f380499cc 100644 (file)
@@ -29,6 +29,8 @@ obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o
 
 obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o
 
+obj-$(CONFIG_PCI_IOV) += iov.o
+
 #
 # Some architectures use the generic PCI setup functions
 #
index 52b54f053be092e4c589b03d1dd03c6be9deacb6..68f91a25259563c6bb7250d8ea3acfd636ad0b29 100644 (file)
@@ -133,7 +133,7 @@ int pci_bus_add_child(struct pci_bus *bus)
  *
  * Call hotplug for each new devices.
  */
-void pci_bus_add_devices(struct pci_bus *bus)
+void pci_bus_add_devices(const struct pci_bus *bus)
 {
        struct pci_dev *dev;
        struct pci_bus *child;
@@ -184,8 +184,10 @@ void pci_enable_bridges(struct pci_bus *bus)
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
                if (dev->subordinate) {
-                       retval = pci_enable_device(dev);
-                       pci_set_master(dev);
+                       if (atomic_read(&dev->enable_cnt) == 0) {
+                               retval = pci_enable_device(dev);
+                               pci_set_master(dev);
+                       }
                        pci_enable_bridges(dev->subordinate);
                }
        }
index 5f333403c2ea0fdb4434942e555f3373871869ec..d313039e2fdf8179dbc3324e7778b7e2e6bed964 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/iova.h>
 #include <linux/intel-iommu.h>
 #include <linux/timer.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
 
 #undef PREFIX
 #define PREFIX "DMAR:"
@@ -509,6 +511,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
                return -ENOMEM;
 
        iommu->seq_id = iommu_allocated++;
+       sprintf (iommu->name, "dmar%d", iommu->seq_id);
 
        iommu->reg = ioremap(drhd->reg_base_addr, VTD_PAGE_SIZE);
        if (!iommu->reg) {
@@ -750,6 +753,42 @@ int qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr,
        return qi_submit_sync(&desc, iommu);
 }
 
+/*
+ * Disable Queued Invalidation interface.
+ */
+void dmar_disable_qi(struct intel_iommu *iommu)
+{
+       unsigned long flags;
+       u32 sts;
+       cycles_t start_time = get_cycles();
+
+       if (!ecap_qis(iommu->ecap))
+               return;
+
+       spin_lock_irqsave(&iommu->register_lock, flags);
+
+       sts =  dmar_readq(iommu->reg + DMAR_GSTS_REG);
+       if (!(sts & DMA_GSTS_QIES))
+               goto end;
+
+       /*
+        * Give a chance to HW to complete the pending invalidation requests.
+        */
+       while ((readl(iommu->reg + DMAR_IQT_REG) !=
+               readl(iommu->reg + DMAR_IQH_REG)) &&
+               (DMAR_OPERATION_TIMEOUT > (get_cycles() - start_time)))
+               cpu_relax();
+
+       iommu->gcmd &= ~DMA_GCMD_QIE;
+
+       writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
+
+       IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, readl,
+                     !(sts & DMA_GSTS_QIES), sts);
+end:
+       spin_unlock_irqrestore(&iommu->register_lock, flags);
+}
+
 /*
  * Enable Queued Invalidation interface. This is a must to support
  * interrupt-remapping. Also used by DMA-remapping, which replaces
@@ -770,20 +809,20 @@ int dmar_enable_qi(struct intel_iommu *iommu)
        if (iommu->qi)
                return 0;
 
-       iommu->qi = kmalloc(sizeof(*qi), GFP_KERNEL);
+       iommu->qi = kmalloc(sizeof(*qi), GFP_ATOMIC);
        if (!iommu->qi)
                return -ENOMEM;
 
        qi = iommu->qi;
 
-       qi->desc = (void *)(get_zeroed_page(GFP_KERNEL));
+       qi->desc = (void *)(get_zeroed_page(GFP_ATOMIC));
        if (!qi->desc) {
                kfree(qi);
                iommu->qi = 0;
                return -ENOMEM;
        }
 
-       qi->desc_status = kmalloc(QI_LENGTH * sizeof(int), GFP_KERNEL);
+       qi->desc_status = kmalloc(QI_LENGTH * sizeof(int), GFP_ATOMIC);
        if (!qi->desc_status) {
                free_page((unsigned long) qi->desc);
                kfree(qi);
@@ -812,3 +851,254 @@ int dmar_enable_qi(struct intel_iommu *iommu)
 
        return 0;
 }
+
+/* iommu interrupt handling. Most stuff are MSI-like. */
+
+enum faulttype {
+       DMA_REMAP,
+       INTR_REMAP,
+       UNKNOWN,
+};
+
+static const char *dma_remap_fault_reasons[] =
+{
+       "Software",
+       "Present bit in root entry is clear",
+       "Present bit in context entry is clear",
+       "Invalid context entry",
+       "Access beyond MGAW",
+       "PTE Write access is not set",
+       "PTE Read access is not set",
+       "Next page table ptr is invalid",
+       "Root table address invalid",
+       "Context table ptr is invalid",
+       "non-zero reserved fields in RTP",
+       "non-zero reserved fields in CTP",
+       "non-zero reserved fields in PTE",
+};
+
+static const char *intr_remap_fault_reasons[] =
+{
+       "Detected reserved fields in the decoded interrupt-remapped request",
+       "Interrupt index exceeded the interrupt-remapping table size",
+       "Present field in the IRTE entry is clear",
+       "Error accessing interrupt-remapping table pointed by IRTA_REG",
+       "Detected reserved fields in the IRTE entry",
+       "Blocked a compatibility format interrupt request",
+       "Blocked an interrupt request due to source-id verification failure",
+};
+
+#define MAX_FAULT_REASON_IDX   (ARRAY_SIZE(fault_reason_strings) - 1)
+
+const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type)
+{
+       if (fault_reason >= 0x20 && (fault_reason <= 0x20 +
+                                    ARRAY_SIZE(intr_remap_fault_reasons))) {
+               *fault_type = INTR_REMAP;
+               return intr_remap_fault_reasons[fault_reason - 0x20];
+       } else if (fault_reason < ARRAY_SIZE(dma_remap_fault_reasons)) {
+               *fault_type = DMA_REMAP;
+               return dma_remap_fault_reasons[fault_reason];
+       } else {
+               *fault_type = UNKNOWN;
+               return "Unknown";
+       }
+}
+
+void dmar_msi_unmask(unsigned int irq)
+{
+       struct intel_iommu *iommu = get_irq_data(irq);
+       unsigned long flag;
+
+       /* unmask it */
+       spin_lock_irqsave(&iommu->register_lock, flag);
+       writel(0, iommu->reg + DMAR_FECTL_REG);
+       /* Read a reg to force flush the post write */
+       readl(iommu->reg + DMAR_FECTL_REG);
+       spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+void dmar_msi_mask(unsigned int irq)
+{
+       unsigned long flag;
+       struct intel_iommu *iommu = get_irq_data(irq);
+
+       /* mask it */
+       spin_lock_irqsave(&iommu->register_lock, flag);
+       writel(DMA_FECTL_IM, iommu->reg + DMAR_FECTL_REG);
+       /* Read a reg to force flush the post write */
+       readl(iommu->reg + DMAR_FECTL_REG);
+       spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+void dmar_msi_write(int irq, struct msi_msg *msg)
+{
+       struct intel_iommu *iommu = get_irq_data(irq);
+       unsigned long flag;
+
+       spin_lock_irqsave(&iommu->register_lock, flag);
+       writel(msg->data, iommu->reg + DMAR_FEDATA_REG);
+       writel(msg->address_lo, iommu->reg + DMAR_FEADDR_REG);
+       writel(msg->address_hi, iommu->reg + DMAR_FEUADDR_REG);
+       spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+void dmar_msi_read(int irq, struct msi_msg *msg)
+{
+       struct intel_iommu *iommu = get_irq_data(irq);
+       unsigned long flag;
+
+       spin_lock_irqsave(&iommu->register_lock, flag);
+       msg->data = readl(iommu->reg + DMAR_FEDATA_REG);
+       msg->address_lo = readl(iommu->reg + DMAR_FEADDR_REG);
+       msg->address_hi = readl(iommu->reg + DMAR_FEUADDR_REG);
+       spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+static int dmar_fault_do_one(struct intel_iommu *iommu, int type,
+               u8 fault_reason, u16 source_id, unsigned long long addr)
+{
+       const char *reason;
+       int fault_type;
+
+       reason = dmar_get_fault_reason(fault_reason, &fault_type);
+
+       if (fault_type == INTR_REMAP)
+               printk(KERN_ERR "INTR-REMAP: Request device [[%02x:%02x.%d] "
+                      "fault index %llx\n"
+                       "INTR-REMAP:[fault reason %02d] %s\n",
+                       (source_id >> 8), PCI_SLOT(source_id & 0xFF),
+                       PCI_FUNC(source_id & 0xFF), addr >> 48,
+                       fault_reason, reason);
+       else
+               printk(KERN_ERR
+                      "DMAR:[%s] Request device [%02x:%02x.%d] "
+                      "fault addr %llx \n"
+                      "DMAR:[fault reason %02d] %s\n",
+                      (type ? "DMA Read" : "DMA Write"),
+                      (source_id >> 8), PCI_SLOT(source_id & 0xFF),
+                      PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason);
+       return 0;
+}
+
+#define PRIMARY_FAULT_REG_LEN (16)
+irqreturn_t dmar_fault(int irq, void *dev_id)
+{
+       struct intel_iommu *iommu = dev_id;
+       int reg, fault_index;
+       u32 fault_status;
+       unsigned long flag;
+
+       spin_lock_irqsave(&iommu->register_lock, flag);
+       fault_status = readl(iommu->reg + DMAR_FSTS_REG);
+       if (fault_status)
+               printk(KERN_ERR "DRHD: handling fault status reg %x\n",
+                      fault_status);
+
+       /* TBD: ignore advanced fault log currently */
+       if (!(fault_status & DMA_FSTS_PPF))
+               goto clear_rest;
+
+       fault_index = dma_fsts_fault_record_index(fault_status);
+       reg = cap_fault_reg_offset(iommu->cap);
+       while (1) {
+               u8 fault_reason;
+               u16 source_id;
+               u64 guest_addr;
+               int type;
+               u32 data;
+
+               /* highest 32 bits */
+               data = readl(iommu->reg + reg +
+                               fault_index * PRIMARY_FAULT_REG_LEN + 12);
+               if (!(data & DMA_FRCD_F))
+                       break;
+
+               fault_reason = dma_frcd_fault_reason(data);
+               type = dma_frcd_type(data);
+
+               data = readl(iommu->reg + reg +
+                               fault_index * PRIMARY_FAULT_REG_LEN + 8);
+               source_id = dma_frcd_source_id(data);
+
+               guest_addr = dmar_readq(iommu->reg + reg +
+                               fault_index * PRIMARY_FAULT_REG_LEN);
+               guest_addr = dma_frcd_page_addr(guest_addr);
+               /* clear the fault */
+               writel(DMA_FRCD_F, iommu->reg + reg +
+                       fault_index * PRIMARY_FAULT_REG_LEN + 12);
+
+               spin_unlock_irqrestore(&iommu->register_lock, flag);
+
+               dmar_fault_do_one(iommu, type, fault_reason,
+                               source_id, guest_addr);
+
+               fault_index++;
+               if (fault_index > cap_num_fault_regs(iommu->cap))
+                       fault_index = 0;
+               spin_lock_irqsave(&iommu->register_lock, flag);
+       }
+clear_rest:
+       /* clear all the other faults */
+       fault_status = readl(iommu->reg + DMAR_FSTS_REG);
+       writel(fault_status, iommu->reg + DMAR_FSTS_REG);
+
+       spin_unlock_irqrestore(&iommu->register_lock, flag);
+       return IRQ_HANDLED;
+}
+
+int dmar_set_interrupt(struct intel_iommu *iommu)
+{
+       int irq, ret;
+
+       /*
+        * Check if the fault interrupt is already initialized.
+        */
+       if (iommu->irq)
+               return 0;
+
+       irq = create_irq();
+       if (!irq) {
+               printk(KERN_ERR "IOMMU: no free vectors\n");
+               return -EINVAL;
+       }
+
+       set_irq_data(irq, iommu);
+       iommu->irq = irq;
+
+       ret = arch_setup_dmar_msi(irq);
+       if (ret) {
+               set_irq_data(irq, NULL);
+               iommu->irq = 0;
+               destroy_irq(irq);
+               return 0;
+       }
+
+       ret = request_irq(irq, dmar_fault, 0, iommu->name, iommu);
+       if (ret)
+               printk(KERN_ERR "IOMMU: can't request irq\n");
+       return ret;
+}
+
+int __init enable_drhd_fault_handling(void)
+{
+       struct dmar_drhd_unit *drhd;
+
+       /*
+        * Enable fault control interrupt.
+        */
+       for_each_drhd_unit(drhd) {
+               int ret;
+               struct intel_iommu *iommu = drhd->iommu;
+               ret = dmar_set_interrupt(iommu);
+
+               if (ret) {
+                       printk(KERN_ERR "DRHD %Lx: failed to enable fault, "
+                              " interrupt, ret %d\n",
+                              (unsigned long long)drhd->reg_base_addr, ret);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
index 1c1141801060ea1c791e6c788a225e29921c752d..fbc63d5e459fd4182f35f5beffc9bee1a875c8d8 100644 (file)
@@ -30,9 +30,8 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
+#include <linux/acpi.h>
 #include <linux/pci-acpi.h>
-#include <acpi/acpi.h>
-#include <acpi/acpi_bus.h>
 
 #define MY_NAME        "acpi_pcihp"
 
@@ -333,19 +332,14 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
 {
        acpi_status status = AE_NOT_FOUND;
        acpi_handle handle, phandle;
-       struct pci_bus *pbus = bus;
-       struct pci_dev *pdev;
-
-       do {
-               pdev = pbus->self;
-               if (!pdev) {
-                       handle = acpi_get_pci_rootbridge_handle(
-                               pci_domain_nr(pbus), pbus->number);
+       struct pci_bus *pbus;
+
+       handle = NULL;
+       for (pbus = bus; pbus; pbus = pbus->parent) {
+               handle = acpi_pci_get_bridge_handle(pbus);
+               if (handle)
                        break;
-               }
-               handle = DEVICE_ACPI_HANDLE(&(pdev->dev));
-               pbus = pbus->parent;
-       } while (!handle);
+       }
 
        /*
         * _HPP settings apply to all child buses, until another _HPP is
@@ -378,12 +372,10 @@ EXPORT_SYMBOL_GPL(acpi_get_hp_params_from_firmware);
  *
  * Attempt to take hotplug control from firmware.
  */
-int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags)
+int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
 {
        acpi_status status;
        acpi_handle chandle, handle;
-       struct pci_dev *pdev = dev;
-       struct pci_bus *parent;
        struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
 
        flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
@@ -408,33 +400,25 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags)
                acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
                dbg("Trying to get hotplug control for %s\n",
                                (char *)string.pointer);
-               status = pci_osc_control_set(handle, flags);
+               status = acpi_pci_osc_control_set(handle, flags);
                if (ACPI_SUCCESS(status))
                        goto got_one;
                kfree(string.pointer);
                string = (struct acpi_buffer){ ACPI_ALLOCATE_BUFFER, NULL };
        }
 
-       pdev = dev;
-       handle = DEVICE_ACPI_HANDLE(&dev->dev);
-       while (!handle) {
+       handle = DEVICE_ACPI_HANDLE(&pdev->dev);
+       if (!handle) {
                /*
                 * This hotplug controller was not listed in the ACPI name
                 * space at all. Try to get acpi handle of parent pci bus.
                 */
-               if (!pdev || !pdev->bus->parent)
-                       break;
-               parent = pdev->bus->parent;
-               dbg("Could not find %s in acpi namespace, trying parent\n",
-                   pci_name(pdev));
-               if (!parent->self)
-                       /* Parent must be a host bridge */
-                       handle = acpi_get_pci_rootbridge_handle(
-                                       pci_domain_nr(parent),
-                                       parent->number);
-               else
-                       handle = DEVICE_ACPI_HANDLE(&(parent->self->dev));
-               pdev = parent->self;
+               struct pci_bus *pbus;
+               for (pbus = pdev->bus; pbus; pbus = pbus->parent) {
+                       handle = acpi_pci_get_bridge_handle(pbus);
+                       if (handle)
+                               break;
+               }
        }
 
        while (handle) {
@@ -453,13 +437,13 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags)
        }
 
        dbg("Cannot get control of hotplug hardware for pci %s\n",
-           pci_name(dev));
+           pci_name(pdev));
 
        kfree(string.pointer);
        return -ENODEV;
 got_one:
-       dbg("Gained control for hotplug HW for pci %s (%s)\n", pci_name(dev),
-                       (char *)string.pointer);
+       dbg("Gained control for hotplug HW for pci %s (%s)\n",
+           pci_name(pdev), (char *)string.pointer);
        kfree(string.pointer);
        return 0;
 }
index d8649e12729863f67f406b86af873b89bc58062f..6151389fd90304d1b02b364150432d8d3e17bb34 100644 (file)
-/*
- * Fake PCI Hot Plug Controller Driver
+/* Works like the fakephp driver used to, except a little better.
  *
- * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (C) 2003 IBM Corp.
- * Copyright (C) 2003 Rolf Eike Beer <eike-kernel@sf-tec.de>
+ * - It's possible to remove devices with subordinate busses.
+ * - New PCI devices that appear via any method, not just a fakephp triggered
+ *   rescan, will be noticed.
+ * - Devices that are removed via any method, not just a fakephp triggered
+ *   removal, will also be noticed.
  *
- * Based on ideas and code from:
- *     Vladimir Kondratiev <vladimir.kondratiev@intel.com>
- *     Rolf Eike Beer <eike-kernel@sf-tec.de>
+ * Uses nothing from the pci-hotplug subsystem.
  *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 2 of the License.
- *
- * Send feedback to <greg@kroah.com>
  */
 
-/*
- *
- * This driver will "emulate" removing PCI devices from the system.  If
- * the "power" file is written to with "0" then the specified PCI device
- * will be completely removed from the kernel.
- *
- * WARNING, this does NOT turn off the power to the PCI device.  This is
- * a "logical" removal, not a physical or electrical removal.
- *
- * Use this module at your own risk, you have been warned!
- *
- * Enabling PCI devices is left as an exercise for the reader...
- *
- */
-#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/pci_hotplug.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
 #include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
+#include <linux/pci.h>
+#include <linux/device.h>
 #include "../pci.h"
 
-#if !defined(MODULE)
-       #define MY_NAME "fakephp"
-#else
-       #define MY_NAME THIS_MODULE->name
-#endif
-
-#define dbg(format, arg...)                                    \
-       do {                                                    \
-               if (debug)                                      \
-                       printk(KERN_DEBUG "%s: " format,        \
-                               MY_NAME , ## arg);              \
-       } while (0)
-#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
-
-#define DRIVER_AUTHOR  "Greg Kroah-Hartman <greg@kroah.com>"
-#define DRIVER_DESC    "Fake PCI Hot Plug Controller Driver"
-
-struct dummy_slot {
-       struct list_head node;
-       struct hotplug_slot *slot;
-       struct pci_dev *dev;
-       struct work_struct remove_work;
-       unsigned long removed;
+struct legacy_slot {
+       struct kobject          kobj;
+       struct pci_dev          *dev;
+       struct list_head        list;
 };
 
-static int debug;
-static int dup_slots;
-static LIST_HEAD(slot_list);
-static struct workqueue_struct *dummyphp_wq;
-
-static void pci_rescan_worker(struct work_struct *work);
-static DECLARE_WORK(pci_rescan_work, pci_rescan_worker);
-
-static int enable_slot (struct hotplug_slot *slot);
-static int disable_slot (struct hotplug_slot *slot);
+static LIST_HEAD(legacy_list);
 
-static struct hotplug_slot_ops dummy_hotplug_slot_ops = {
-       .owner                  = THIS_MODULE,
-       .enable_slot            = enable_slot,
-       .disable_slot           = disable_slot,
-};
-
-static void dummy_release(struct hotplug_slot *slot)
+static ssize_t legacy_show(struct kobject *kobj, struct attribute *attr,
+                          char *buf)
 {
-       struct dummy_slot *dslot = slot->private;
-
-       list_del(&dslot->node);
-       kfree(dslot->slot->info);
-       kfree(dslot->slot);
-       pci_dev_put(dslot->dev);
-       kfree(dslot);
+       struct legacy_slot *slot = container_of(kobj, typeof(*slot), kobj);
+       strcpy(buf, "1\n");
+       return 2;
 }
 
-#define SLOT_NAME_SIZE 8
-
-static int add_slot(struct pci_dev *dev)
+static void remove_callback(void *data)
 {
-       struct dummy_slot *dslot;
-       struct hotplug_slot *slot;
-       char name[SLOT_NAME_SIZE];
-       int retval = -ENOMEM;
-       static int count = 1;
-
-       slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
-       if (!slot)
-               goto error;
-
-       slot->info = kzalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
-       if (!slot->info)
-               goto error_slot;
-
-       slot->info->power_status = 1;
-       slot->info->max_bus_speed = PCI_SPEED_UNKNOWN;
-       slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
-
-       dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL);
-       if (!dslot)
-               goto error_info;
-
-       if (dup_slots)
-               snprintf(name, SLOT_NAME_SIZE, "fake");
-       else
-               snprintf(name, SLOT_NAME_SIZE, "fake%d", count++);
-       dbg("slot->name = %s\n", name);
-       slot->ops = &dummy_hotplug_slot_ops;
-       slot->release = &dummy_release;
-       slot->private = dslot;
-
-       retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn), name);
-       if (retval) {
-               err("pci_hp_register failed with error %d\n", retval);
-               goto error_dslot;
-       }
-
-       dbg("slot->name = %s\n", hotplug_slot_name(slot));
-       dslot->slot = slot;
-       dslot->dev = pci_dev_get(dev);
-       list_add (&dslot->node, &slot_list);
-       return retval;
-
-error_dslot:
-       kfree(dslot);
-error_info:
-       kfree(slot->info);
-error_slot:
-       kfree(slot);
-error:
-       return retval;
+       pci_remove_bus_device((struct pci_dev *)data);
 }
 
-static int __init pci_scan_buses(void)
+static ssize_t legacy_store(struct kobject *kobj, struct attribute *attr,
+                           const char *buf, size_t len)
 {
-       struct pci_dev *dev = NULL;
-       int lastslot = 0;
+       struct legacy_slot *slot = container_of(kobj, typeof(*slot), kobj);
+       unsigned long val;
 
-       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-               if (PCI_FUNC(dev->devfn) > 0 &&
-                               lastslot == PCI_SLOT(dev->devfn))
-                       continue;
-               lastslot = PCI_SLOT(dev->devfn);
-               add_slot(dev);
-       }
+       if (strict_strtoul(buf, 0, &val) < 0)
+               return -EINVAL;
 
-       return 0;
+       if (val)
+               pci_rescan_bus(slot->dev->bus);
+       else
+               sysfs_schedule_callback(&slot->dev->dev.kobj, remove_callback,
+                                       slot->dev, THIS_MODULE);
+       return len;
 }
 
-static void remove_slot(struct dummy_slot *dslot)
-{
-       int retval;
-
-       dbg("removing slot %s\n", hotplug_slot_name(dslot->slot));
-       retval = pci_hp_deregister(dslot->slot);
-       if (retval)
-               err("Problem unregistering a slot %s\n",
-                       hotplug_slot_name(dslot->slot));
-}
+static struct attribute *legacy_attrs[] = {
+       &(struct attribute){ .name = "power", .mode = 0644 },
+       NULL,
+};
 
-/* called from the single-threaded workqueue handler to remove a slot */
-static void remove_slot_worker(struct work_struct *work)
+static void legacy_release(struct kobject *kobj)
 {
-       struct dummy_slot *dslot =
-               container_of(work, struct dummy_slot, remove_work);
-       remove_slot(dslot);
-}
+       struct legacy_slot *slot = container_of(kobj, typeof(*slot), kobj);
 
-/**
- * pci_rescan_slot - Rescan slot
- * @temp: Device template. Should be set: bus and devfn.
- *
- * Tries hard not to re-enable already existing devices;
- * also handles scanning of subfunctions.
- */
-static int pci_rescan_slot(struct pci_dev *temp)
-{
-       struct pci_bus *bus = temp->bus;
-       struct pci_dev *dev;
-       int func;
-       u8 hdr_type;
-       int count = 0;
-
-       if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) {
-               temp->hdr_type = hdr_type & 0x7f;
-               if ((dev = pci_get_slot(bus, temp->devfn)) != NULL)
-                       pci_dev_put(dev);
-               else {
-                       dev = pci_scan_single_device(bus, temp->devfn);
-                       if (dev) {
-                               dbg("New device on %s function %x:%x\n",
-                                       bus->name, temp->devfn >> 3,
-                                       temp->devfn & 7);
-                               count++;
-                       }
-               }
-               /* multifunction device? */
-               if (!(hdr_type & 0x80))
-                       return count;
-
-               /* continue scanning for other functions */
-               for (func = 1, temp->devfn++; func < 8; func++, temp->devfn++) {
-                       if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type))
-                               continue;
-                       temp->hdr_type = hdr_type & 0x7f;
-
-                       if ((dev = pci_get_slot(bus, temp->devfn)) != NULL)
-                               pci_dev_put(dev);
-                       else {
-                               dev = pci_scan_single_device(bus, temp->devfn);
-                               if (dev) {
-                                       dbg("New device on %s function %x:%x\n",
-                                               bus->name, temp->devfn >> 3,
-                                               temp->devfn & 7);
-                                       count++;
-                               }
-                       }
-               }
-       }
-
-       return count;
+       pci_dev_put(slot->dev);
+       kfree(slot);
 }
 
+static struct kobj_type legacy_ktype = {
+       .sysfs_ops = &(struct sysfs_ops){
+               .store = legacy_store, .show = legacy_show
+       },
+       .release = &legacy_release,
+       .default_attrs = legacy_attrs,
+};
 
-/**
- * pci_rescan_bus - Rescan PCI bus
- * @bus: the PCI bus to rescan
- *
- * Call pci_rescan_slot for each possible function of the bus.
- */
-static void pci_rescan_bus(const struct pci_bus *bus)
+static int legacy_add_slot(struct pci_dev *pdev)
 {
-       unsigned int devfn;
-       struct pci_dev *dev;
-       int retval;
-       int found = 0;
-       dev = alloc_pci_dev();
-       if (!dev)
-               return;
+       struct legacy_slot *slot = kzalloc(sizeof(*slot), GFP_KERNEL);
 
-       dev->bus = (struct pci_bus*)bus;
-       dev->sysdata = bus->sysdata;
-       for (devfn = 0; devfn < 0x100; devfn += 8) {
-               dev->devfn = devfn;
-               found += pci_rescan_slot(dev);
-       }
-
-       if (found) {
-               pci_bus_assign_resources(bus);
-               list_for_each_entry(dev, &bus->devices, bus_list) {
-                       /* Skip already-added devices */
-                       if (dev->is_added)
-                                       continue;
-                       retval = pci_bus_add_device(dev);
-                       if (retval)
-                               dev_err(&dev->dev,
-                                       "Error adding device, continuing\n");
-                       else
-                               add_slot(dev);
-               }
-               pci_bus_add_devices(bus);
-       }
-       kfree(dev);
-}
+       if (!slot)
+               return -ENOMEM;
 
-/* recursively scan all buses */
-static void pci_rescan_buses(const struct list_head *list)
-{
-       const struct list_head *l;
-       list_for_each(l,list) {
-               const struct pci_bus *b = pci_bus_b(l);
-               pci_rescan_bus(b);
-               pci_rescan_buses(&b->children);
+       if (kobject_init_and_add(&slot->kobj, &legacy_ktype,
+                                &pci_slots_kset->kobj, "%s",
+                                dev_name(&pdev->dev))) {
+               dev_warn(&pdev->dev, "Failed to created legacy fake slot\n");
+               return -EINVAL;
        }
-}
+       slot->dev = pci_dev_get(pdev);
 
-/* initiate rescan of all pci buses */
-static inline void pci_rescan(void) {
-       pci_rescan_buses(&pci_root_buses);
-}
-
-/* called from the single-threaded workqueue handler to rescan all pci buses */
-static void pci_rescan_worker(struct work_struct *work)
-{
-       pci_rescan();
-}
+       list_add(&slot->list, &legacy_list);
 
-static int enable_slot(struct hotplug_slot *hotplug_slot)
-{
-       /* mis-use enable_slot for rescanning of the pci bus */
-       cancel_work_sync(&pci_rescan_work);
-       queue_work(dummyphp_wq, &pci_rescan_work);
        return 0;
 }
 
-static int disable_slot(struct hotplug_slot *slot)
+static int legacy_notify(struct notifier_block *nb,
+                        unsigned long action, void *data)
 {
-       struct dummy_slot *dslot;
-       struct pci_dev *dev;
-       int func;
-
-       if (!slot)
-               return -ENODEV;
-       dslot = slot->private;
-
-       dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(slot));
+       struct pci_dev *pdev = to_pci_dev(data);
 
-       for (func = 7; func >= 0; func--) {
-               dev = pci_get_slot(dslot->dev->bus, dslot->dev->devfn + func);
-               if (!dev)
-                       continue;
+       if (action == BUS_NOTIFY_ADD_DEVICE) {
+               legacy_add_slot(pdev);
+       } else if (action == BUS_NOTIFY_DEL_DEVICE) {
+               struct legacy_slot *slot;
 
-               if (test_and_set_bit(0, &dslot->removed)) {
-                       dbg("Slot already scheduled for removal\n");
-                       pci_dev_put(dev);
-                       return -ENODEV;
-               }
+               list_for_each_entry(slot, &legacy_list, list)
+                       if (slot->dev == pdev)
+                               goto found;
 
-               /* remove the device from the pci core */
-               pci_remove_bus_device(dev);
-
-               /* queue work item to blow away this sysfs entry and other
-                * parts.
-                */
-               INIT_WORK(&dslot->remove_work, remove_slot_worker);
-               queue_work(dummyphp_wq, &dslot->remove_work);
-
-               pci_dev_put(dev);
+               dev_warn(&pdev->dev, "Missing legacy fake slot?");
+               return -ENODEV;
+found:
+               kobject_del(&slot->kobj);
+               list_del(&slot->list);
+               kobject_put(&slot->kobj);
        }
+
        return 0;
 }
 
-static void cleanup_slots (void)
-{
-       struct list_head *tmp;
-       struct list_head *next;
-       struct dummy_slot *dslot;
-
-       destroy_workqueue(dummyphp_wq);
-       list_for_each_safe (tmp, next, &slot_list) {
-               dslot = list_entry (tmp, struct dummy_slot, node);
-               remove_slot(dslot);
-       }
-       
-}
+static struct notifier_block legacy_notifier = {
+       .notifier_call = legacy_notify
+};
 
-static int __init dummyphp_init(void)
+static int __init init_legacy(void)
 {
-       info(DRIVER_DESC "\n");
+       struct pci_dev *pdev = NULL;
 
-       dummyphp_wq = create_singlethread_workqueue(MY_NAME);
-       if (!dummyphp_wq)
-               return -ENOMEM;
+       /* Add existing devices */
+       while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)))
+               legacy_add_slot(pdev);
 
-       return pci_scan_buses();
+       /* Be alerted of any new ones */
+       bus_register_notifier(&pci_bus_type, &legacy_notifier);
+       return 0;
 }
+module_init(init_legacy);
 
-
-static void __exit dummyphp_exit(void)
+static void __exit remove_legacy(void)
 {
-       cleanup_slots();
+       struct legacy_slot *slot, *tmp;
+
+       bus_unregister_notifier(&pci_bus_type, &legacy_notifier);
+
+       list_for_each_entry_safe(slot, tmp, &legacy_list, list) {
+               list_del(&slot->list);
+               kobject_del(&slot->kobj);
+               kobject_put(&slot->kobj);
+       }
 }
+module_exit(remove_legacy);
 
-module_init(dummyphp_init);
-module_exit(dummyphp_exit);
 
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Trent Piepho <xyzzy@speakeasy.org>");
+MODULE_DESCRIPTION("Legacy version of the fakephp interface");
 MODULE_LICENSE("GPL");
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
-module_param(dup_slots, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(dup_slots, "Force duplicate slot names for debugging");
index 39ae37589fda7f6106d845148d1175b4a927b1df..0a368547e6339d41ed7a80c08c9c6509d4d57007 100644 (file)
@@ -46,10 +46,10 @@ extern int pciehp_force;
 extern struct workqueue_struct *pciehp_wq;
 
 #define dbg(format, arg...)                                            \
-       do {                                                            \
-               if (pciehp_debug)                                       \
-                       printk("%s: " format, MY_NAME , ## arg);        \
-       } while (0)
+do {                                                                   \
+       if (pciehp_debug)                                               \
+               printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg);     \
+} while (0)
 #define err(format, arg...)                                            \
        printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
 #define info(format, arg...)                                           \
@@ -60,7 +60,7 @@ extern struct workqueue_struct *pciehp_wq;
 #define ctrl_dbg(ctrl, format, arg...)                                 \
        do {                                                            \
                if (pciehp_debug)                                       \
-                       dev_printk(, &ctrl->pcie->device,               \
+                       dev_printk(KERN_DEBUG, &ctrl->pcie->device,     \
                                        format, ## arg);                \
        } while (0)
 #define ctrl_err(ctrl, format, arg...)                                 \
@@ -108,10 +108,11 @@ struct controller {
        u32 slot_cap;
        u8 cap_base;
        struct timer_list poll_timer;
-       int cmd_busy;
+       unsigned int cmd_busy:1;
        unsigned int no_cmd_complete:1;
        unsigned int link_active_reporting:1;
        unsigned int notification_enabled:1;
+       unsigned int power_fault_detected;
 };
 
 #define INT_BUTTON_IGNORE              0
index 438d795f9fe31f1299e4612695db65ff36a4476d..96048010e7d9064f2f6b0a2d007ab056bfb8e94a 100644 (file)
@@ -67,37 +67,27 @@ static int __init parse_detect_mode(void)
        return PCIEHP_DETECT_DEFAULT;
 }
 
-static struct pcie_port_service_id __initdata port_pci_ids[] = {
-       {
-               .vendor = PCI_ANY_ID,
-               .device = PCI_ANY_ID,
-               .port_type = PCIE_ANY_PORT,
-               .service_type = PCIE_PORT_SERVICE_HP,
-               .driver_data =  0,
-        }, { /* end: all zeroes */ }
-};
-
 static int __initdata dup_slot_id;
 static int __initdata acpi_slot_detected;
 static struct list_head __initdata dummy_slots = LIST_HEAD_INIT(dummy_slots);
 
 /* Dummy driver for dumplicate name detection */
-static int __init dummy_probe(struct pcie_device *dev,
-                             const struct pcie_port_service_id *id)
+static int __init dummy_probe(struct pcie_device *dev)
 {
        int pos;
        u32 slot_cap;
        struct slot *slot, *tmp;
        struct pci_dev *pdev = dev->port;
        struct pci_bus *pbus = pdev->subordinate;
-       if (!(slot = kzalloc(sizeof(*slot), GFP_KERNEL)))
-               return -ENOMEM;
        /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */
        if (pciehp_get_hp_hw_control_from_firmware(pdev))
                return -ENODEV;
        if (!(pos = pci_find_capability(pdev, PCI_CAP_ID_EXP)))
                return -ENODEV;
        pci_read_config_dword(pdev, pos + PCI_EXP_SLTCAP, &slot_cap);
+       slot = kzalloc(sizeof(*slot), GFP_KERNEL);
+       if (!slot)
+               return -ENOMEM;
        slot->number = slot_cap >> 19;
        list_for_each_entry(tmp, &dummy_slots, slot_list) {
                if (tmp->number == slot->number)
@@ -111,7 +101,8 @@ static int __init dummy_probe(struct pcie_device *dev,
 
 static struct pcie_port_service_driver __initdata dummy_driver = {
         .name           = "pciehp_dummy",
-        .id_table       = port_pci_ids,
+       .port_type      = PCIE_ANY_PORT,
+       .service        = PCIE_PORT_SERVICE_HP,
         .probe          = dummy_probe,
 };
 
index 681e3912b821a4dce3f5ee11844b73cf6e8b316d..fb254b2454de7345ff4c0e3a73f43e2531e67b8a 100644 (file)
@@ -401,7 +401,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
        return 0;
 }
 
-static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_id *id)
+static int pciehp_probe(struct pcie_device *dev)
 {
        int rc;
        struct controller *ctrl;
@@ -475,7 +475,7 @@ static void pciehp_remove (struct pcie_device *dev)
 }
 
 #ifdef CONFIG_PM
-static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)
+static int pciehp_suspend (struct pcie_device *dev)
 {
        dev_info(&dev->device, "%s ENTRY\n", __func__);
        return 0;
@@ -503,20 +503,12 @@ static int pciehp_resume (struct pcie_device *dev)
        }
        return 0;
 }
-#endif
-
-static struct pcie_port_service_id port_pci_ids[] = { {
-       .vendor = PCI_ANY_ID,
-       .device = PCI_ANY_ID,
-       .port_type = PCIE_ANY_PORT,
-       .service_type = PCIE_PORT_SERVICE_HP,
-       .driver_data =  0,
-       }, { /* end: all zeroes */ }
-};
+#endif /* PM */
 
 static struct pcie_port_service_driver hpdriver_portdrv = {
        .name           = PCIE_MODULE_NAME,
-       .id_table       = &port_pci_ids[0],
+       .port_type      = PCIE_ANY_PORT,
+       .service        = PCIE_PORT_SERVICE_HP,
 
        .probe          = pciehp_probe,
        .remove         = pciehp_remove,
index 7a16c6897bb92698abc8edfb9af1d909f235453d..07bd321511463653ebe0005ebdf000efd083fe4c 100644 (file)
@@ -548,23 +548,21 @@ static int hpc_power_on_slot(struct slot * slot)
 
        slot_cmd = POWER_ON;
        cmd_mask = PCI_EXP_SLTCTL_PCC;
-       /* Enable detection that we turned off at slot power-off time */
        if (!pciehp_poll_mode) {
-               slot_cmd |= (PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE |
-                            PCI_EXP_SLTCTL_PDCE);
-               cmd_mask |= (PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE |
-                            PCI_EXP_SLTCTL_PDCE);
+               /* Enable power fault detection turned off at power off time */
+               slot_cmd |= PCI_EXP_SLTCTL_PFDE;
+               cmd_mask |= PCI_EXP_SLTCTL_PFDE;
        }
 
        retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
-
        if (retval) {
                ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd);
-               return -1;
+               return retval;
        }
        ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n",
                 __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd);
 
+       ctrl->power_fault_detected = 0;
        return retval;
 }
 
@@ -621,18 +619,10 @@ static int hpc_power_off_slot(struct slot * slot)
 
        slot_cmd = POWER_OFF;
        cmd_mask = PCI_EXP_SLTCTL_PCC;
-       /*
-        * If we get MRL or presence detect interrupts now, the isr
-        * will notice the sticky power-fault bit too and issue power
-        * indicator change commands. This will lead to an endless loop
-        * of command completions, since the power-fault bit remains on
-        * till the slot is powered on again.
-        */
        if (!pciehp_poll_mode) {
-               slot_cmd &= ~(PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE |
-                             PCI_EXP_SLTCTL_PDCE);
-               cmd_mask |= (PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE |
-                            PCI_EXP_SLTCTL_PDCE);
+               /* Disable power fault detection */
+               slot_cmd &= ~PCI_EXP_SLTCTL_PFDE;
+               cmd_mask |= PCI_EXP_SLTCTL_PFDE;
        }
 
        retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
@@ -672,10 +662,11 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
                detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
                             PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
                             PCI_EXP_SLTSTA_CC);
+               detected &= ~intr_loc;
                intr_loc |= detected;
                if (!intr_loc)
                        return IRQ_NONE;
-               if (detected && pciehp_writew(ctrl, PCI_EXP_SLTSTA, detected)) {
+               if (detected && pciehp_writew(ctrl, PCI_EXP_SLTSTA, intr_loc)) {
                        ctrl_err(ctrl, "%s: Cannot write to SLOTSTATUS\n",
                                 __func__);
                        return IRQ_NONE;
@@ -709,9 +700,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
                pciehp_handle_presence_change(p_slot);
 
        /* Check Power Fault Detected */
-       if (intr_loc & PCI_EXP_SLTSTA_PFD)
+       if ((intr_loc & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) {
+               ctrl->power_fault_detected = 1;
                pciehp_handle_power_fault(p_slot);
-
+       }
        return IRQ_HANDLED;
 }
 
index 6aba0b6cf2e0769fa25787e55e84beccbf9a0a21..974e924ca96d57d06fd5e689b97e1faaf6d9ae44 100644 (file)
@@ -48,10 +48,10 @@ extern int shpchp_debug;
 extern struct workqueue_struct *shpchp_wq;
 
 #define dbg(format, arg...)                                            \
-       do {                                                            \
-               if (shpchp_debug)                                       \
-                       printk("%s: " format, MY_NAME , ## arg);        \
-       } while (0)
+do {                                                                   \
+       if (shpchp_debug)                                               \
+               printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg);     \
+} while (0)
 #define err(format, arg...)                                            \
        printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
 #define info(format, arg...)                                           \
@@ -62,7 +62,7 @@ extern struct workqueue_struct *shpchp_wq;
 #define ctrl_dbg(ctrl, format, arg...)                                 \
        do {                                                            \
                if (shpchp_debug)                                       \
-                       dev_printk(, &ctrl->pci_dev->dev,               \
+                       dev_printk(KERN_DEBUG, &ctrl->pci_dev->dev,     \
                                        format, ## arg);                \
        } while (0)
 #define ctrl_err(ctrl, format, arg...)                                 \
index 138f161becc0758ef36121896b71f17ecc769c8c..aa315e52529bf60e0c72bd85142cf695c5c5c232 100644 (file)
@@ -137,7 +137,7 @@ int __ref shpchp_configure_device(struct slot *p_slot)
                                                        busnr))
                                        break;
                        }
-                       if (busnr >= end) {
+                       if (busnr > end) {
                                ctrl_err(ctrl,
                                         "No free bus for hot-added bridge\n");
                                pci_dev_put(dev);
index f3f686581a9026685dc3e6c994b00e88ed88486c..9dbd5066acafee0594b7d20938822d6f7a3f3dbd 100644 (file)
@@ -1004,194 +1004,6 @@ static int iommu_disable_translation(struct intel_iommu *iommu)
        return 0;
 }
 
-/* iommu interrupt handling. Most stuff are MSI-like. */
-
-static const char *fault_reason_strings[] =
-{
-       "Software",
-       "Present bit in root entry is clear",
-       "Present bit in context entry is clear",
-       "Invalid context entry",
-       "Access beyond MGAW",
-       "PTE Write access is not set",
-       "PTE Read access is not set",
-       "Next page table ptr is invalid",
-       "Root table address invalid",
-       "Context table ptr is invalid",
-       "non-zero reserved fields in RTP",
-       "non-zero reserved fields in CTP",
-       "non-zero reserved fields in PTE",
-};
-#define MAX_FAULT_REASON_IDX   (ARRAY_SIZE(fault_reason_strings) - 1)
-
-const char *dmar_get_fault_reason(u8 fault_reason)
-{
-       if (fault_reason > MAX_FAULT_REASON_IDX)
-               return "Unknown";
-       else
-               return fault_reason_strings[fault_reason];
-}
-
-void dmar_msi_unmask(unsigned int irq)
-{
-       struct intel_iommu *iommu = get_irq_data(irq);
-       unsigned long flag;
-
-       /* unmask it */
-       spin_lock_irqsave(&iommu->register_lock, flag);
-       writel(0, iommu->reg + DMAR_FECTL_REG);
-       /* Read a reg to force flush the post write */
-       readl(iommu->reg + DMAR_FECTL_REG);
-       spin_unlock_irqrestore(&iommu->register_lock, flag);
-}
-
-void dmar_msi_mask(unsigned int irq)
-{
-       unsigned long flag;
-       struct intel_iommu *iommu = get_irq_data(irq);
-
-       /* mask it */
-       spin_lock_irqsave(&iommu->register_lock, flag);
-       writel(DMA_FECTL_IM, iommu->reg + DMAR_FECTL_REG);
-       /* Read a reg to force flush the post write */
-       readl(iommu->reg + DMAR_FECTL_REG);
-       spin_unlock_irqrestore(&iommu->register_lock, flag);
-}
-
-void dmar_msi_write(int irq, struct msi_msg *msg)
-{
-       struct intel_iommu *iommu = get_irq_data(irq);
-       unsigned long flag;
-
-       spin_lock_irqsave(&iommu->register_lock, flag);
-       writel(msg->data, iommu->reg + DMAR_FEDATA_REG);
-       writel(msg->address_lo, iommu->reg + DMAR_FEADDR_REG);
-       writel(msg->address_hi, iommu->reg + DMAR_FEUADDR_REG);
-       spin_unlock_irqrestore(&iommu->register_lock, flag);
-}
-
-void dmar_msi_read(int irq, struct msi_msg *msg)
-{
-       struct intel_iommu *iommu = get_irq_data(irq);
-       unsigned long flag;
-
-       spin_lock_irqsave(&iommu->register_lock, flag);
-       msg->data = readl(iommu->reg + DMAR_FEDATA_REG);
-       msg->address_lo = readl(iommu->reg + DMAR_FEADDR_REG);
-       msg->address_hi = readl(iommu->reg + DMAR_FEUADDR_REG);
-       spin_unlock_irqrestore(&iommu->register_lock, flag);
-}
-
-static int iommu_page_fault_do_one(struct intel_iommu *iommu, int type,
-               u8 fault_reason, u16 source_id, unsigned long long addr)
-{
-       const char *reason;
-
-       reason = dmar_get_fault_reason(fault_reason);
-
-       printk(KERN_ERR
-               "DMAR:[%s] Request device [%02x:%02x.%d] "
-               "fault addr %llx \n"
-               "DMAR:[fault reason %02d] %s\n",
-               (type ? "DMA Read" : "DMA Write"),
-               (source_id >> 8), PCI_SLOT(source_id & 0xFF),
-               PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason);
-       return 0;
-}
-
-#define PRIMARY_FAULT_REG_LEN (16)
-static irqreturn_t iommu_page_fault(int irq, void *dev_id)
-{
-       struct intel_iommu *iommu = dev_id;
-       int reg, fault_index;
-       u32 fault_status;
-       unsigned long flag;
-
-       spin_lock_irqsave(&iommu->register_lock, flag);
-       fault_status = readl(iommu->reg + DMAR_FSTS_REG);
-
-       /* TBD: ignore advanced fault log currently */
-       if (!(fault_status & DMA_FSTS_PPF))
-               goto clear_overflow;
-
-       fault_index = dma_fsts_fault_record_index(fault_status);
-       reg = cap_fault_reg_offset(iommu->cap);
-       while (1) {
-               u8 fault_reason;
-               u16 source_id;
-               u64 guest_addr;
-               int type;
-               u32 data;
-
-               /* highest 32 bits */
-               data = readl(iommu->reg + reg +
-                               fault_index * PRIMARY_FAULT_REG_LEN + 12);
-               if (!(data & DMA_FRCD_F))
-                       break;
-
-               fault_reason = dma_frcd_fault_reason(data);
-               type = dma_frcd_type(data);
-
-               data = readl(iommu->reg + reg +
-                               fault_index * PRIMARY_FAULT_REG_LEN + 8);
-               source_id = dma_frcd_source_id(data);
-
-               guest_addr = dmar_readq(iommu->reg + reg +
-                               fault_index * PRIMARY_FAULT_REG_LEN);
-               guest_addr = dma_frcd_page_addr(guest_addr);
-               /* clear the fault */
-               writel(DMA_FRCD_F, iommu->reg + reg +
-                       fault_index * PRIMARY_FAULT_REG_LEN + 12);
-
-               spin_unlock_irqrestore(&iommu->register_lock, flag);
-
-               iommu_page_fault_do_one(iommu, type, fault_reason,
-                               source_id, guest_addr);
-
-               fault_index++;
-               if (fault_index > cap_num_fault_regs(iommu->cap))
-                       fault_index = 0;
-               spin_lock_irqsave(&iommu->register_lock, flag);
-       }
-clear_overflow:
-       /* clear primary fault overflow */
-       fault_status = readl(iommu->reg + DMAR_FSTS_REG);
-       if (fault_status & DMA_FSTS_PFO)
-               writel(DMA_FSTS_PFO, iommu->reg + DMAR_FSTS_REG);
-
-       spin_unlock_irqrestore(&iommu->register_lock, flag);
-       return IRQ_HANDLED;
-}
-
-int dmar_set_interrupt(struct intel_iommu *iommu)
-{
-       int irq, ret;
-
-       irq = create_irq();
-       if (!irq) {
-               printk(KERN_ERR "IOMMU: no free vectors\n");
-               return -EINVAL;
-       }
-
-       set_irq_data(irq, iommu);
-       iommu->irq = irq;
-
-       ret = arch_setup_dmar_msi(irq);
-       if (ret) {
-               set_irq_data(irq, NULL);
-               iommu->irq = 0;
-               destroy_irq(irq);
-               return 0;
-       }
-
-       /* Force fault register is cleared */
-       iommu_page_fault(irq, iommu);
-
-       ret = request_irq(irq, iommu_page_fault, 0, iommu->name, iommu);
-       if (ret)
-               printk(KERN_ERR "IOMMU: can't request irq\n");
-       return ret;
-}
 
 static int iommu_init_domains(struct intel_iommu *iommu)
 {
@@ -1970,7 +1782,7 @@ static inline void iommu_prepare_isa(void)
        ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024);
 
        if (ret)
-               printk("IOMMU: Failed to create 0-64M identity map, "
+               printk(KERN_ERR "IOMMU: Failed to create 0-64M identity map, "
                        "floppy might not work\n");
 
 }
@@ -1987,7 +1799,7 @@ static int __init init_dmars(void)
        struct dmar_rmrr_unit *rmrr;
        struct pci_dev *pdev;
        struct intel_iommu *iommu;
-       int i, ret, unit = 0;
+       int i, ret;
 
        /*
         * for each drhd
@@ -2043,11 +1855,40 @@ static int __init init_dmars(void)
                }
        }
 
+       /*
+        * Start from the sane iommu hardware state.
+        */
        for_each_drhd_unit(drhd) {
                if (drhd->ignored)
                        continue;
 
                iommu = drhd->iommu;
+
+               /*
+                * If the queued invalidation is already initialized by us
+                * (for example, while enabling interrupt-remapping) then
+                * we got the things already rolling from a sane state.
+                */
+               if (iommu->qi)
+                       continue;
+
+               /*
+                * Clear any previous faults.
+                */
+               dmar_fault(-1, iommu);
+               /*
+                * Disable queued invalidation if supported and already enabled
+                * before OS handover.
+                */
+               dmar_disable_qi(iommu);
+       }
+
+       for_each_drhd_unit(drhd) {
+               if (drhd->ignored)
+                       continue;
+
+               iommu = drhd->iommu;
+
                if (dmar_enable_qi(iommu)) {
                        /*
                         * Queued Invalidate not enabled, use Register Based
@@ -2109,7 +1950,6 @@ static int __init init_dmars(void)
                if (drhd->ignored)
                        continue;
                iommu = drhd->iommu;
-               sprintf (iommu->name, "dmar%d", unit++);
 
                iommu_flush_write_buffer(iommu);
 
@@ -2284,11 +2124,13 @@ error:
        return 0;
 }
 
-dma_addr_t intel_map_single(struct device *hwdev, phys_addr_t paddr,
-                           size_t size, int dir)
+static dma_addr_t intel_map_page(struct device *dev, struct page *page,
+                                unsigned long offset, size_t size,
+                                enum dma_data_direction dir,
+                                struct dma_attrs *attrs)
 {
-       return __intel_map_single(hwdev, paddr, size, dir,
-                                 to_pci_dev(hwdev)->dma_mask);
+       return __intel_map_single(dev, page_to_phys(page) + offset, size,
+                                 dir, to_pci_dev(dev)->dma_mask);
 }
 
 static void flush_unmaps(void)
@@ -2352,8 +2194,9 @@ static void add_unmap(struct dmar_domain *dom, struct iova *iova)
        spin_unlock_irqrestore(&async_umap_flush_lock, flags);
 }
 
-void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size,
-                       int dir)
+static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
+                            size_t size, enum dma_data_direction dir,
+                            struct dma_attrs *attrs)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct dmar_domain *domain;
@@ -2397,8 +2240,14 @@ void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size,
        }
 }
 
-void *intel_alloc_coherent(struct device *hwdev, size_t size,
-                          dma_addr_t *dma_handle, gfp_t flags)
+static void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size,
+                              int dir)
+{
+       intel_unmap_page(dev, dev_addr, size, dir, NULL);
+}
+
+static void *intel_alloc_coherent(struct device *hwdev, size_t size,
+                                 dma_addr_t *dma_handle, gfp_t flags)
 {
        void *vaddr;
        int order;
@@ -2421,8 +2270,8 @@ void *intel_alloc_coherent(struct device *hwdev, size_t size,
        return NULL;
 }
 
-void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
-                        dma_addr_t dma_handle)
+static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
+                               dma_addr_t dma_handle)
 {
        int order;
 
@@ -2435,8 +2284,9 @@ void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
 
 #define SG_ENT_VIRT_ADDRESS(sg)        (sg_virt((sg)))
 
-void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
-                   int nelems, int dir)
+static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
+                          int nelems, enum dma_data_direction dir,
+                          struct dma_attrs *attrs)
 {
        int i;
        struct pci_dev *pdev = to_pci_dev(hwdev);
@@ -2493,8 +2343,8 @@ static int intel_nontranslate_map_sg(struct device *hddev,
        return nelems;
 }
 
-int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
-                int dir)
+static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
+                       enum dma_data_direction dir, struct dma_attrs *attrs)
 {
        void *addr;
        int i;
@@ -2574,13 +2424,19 @@ int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
        return nelems;
 }
 
-static struct dma_mapping_ops intel_dma_ops = {
+static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       return !dma_addr;
+}
+
+struct dma_map_ops intel_dma_ops = {
        .alloc_coherent = intel_alloc_coherent,
        .free_coherent = intel_free_coherent,
-       .map_single = intel_map_single,
-       .unmap_single = intel_unmap_single,
        .map_sg = intel_map_sg,
        .unmap_sg = intel_unmap_sg,
+       .map_page = intel_map_page,
+       .unmap_page = intel_unmap_page,
+       .mapping_error = intel_mapping_error,
 };
 
 static inline int iommu_domain_cache_init(void)
index 9d07a05d26f1125227fa8f37a73ac0c948ed32d2..b041a409f4a70f84e4a76ed4e0011c758aa31d71 100644 (file)
@@ -117,21 +117,22 @@ int get_irte(int irq, struct irte *entry)
 {
        int index;
        struct irq_2_iommu *irq_iommu;
+       unsigned long flags;
 
        if (!entry)
                return -1;
 
-       spin_lock(&irq_2_ir_lock);
+       spin_lock_irqsave(&irq_2_ir_lock, flags);
        irq_iommu = valid_irq_2_iommu(irq);
        if (!irq_iommu) {
-               spin_unlock(&irq_2_ir_lock);
+               spin_unlock_irqrestore(&irq_2_ir_lock, flags);
                return -1;
        }
 
        index = irq_iommu->irte_index + irq_iommu->sub_handle;
        *entry = *(irq_iommu->iommu->ir_table->base + index);
 
-       spin_unlock(&irq_2_ir_lock);
+       spin_unlock_irqrestore(&irq_2_ir_lock, flags);
        return 0;
 }
 
@@ -141,6 +142,7 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
        struct irq_2_iommu *irq_iommu;
        u16 index, start_index;
        unsigned int mask = 0;
+       unsigned long flags;
        int i;
 
        if (!count)
@@ -170,7 +172,7 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
                return -1;
        }
 
-       spin_lock(&irq_2_ir_lock);
+       spin_lock_irqsave(&irq_2_ir_lock, flags);
        do {
                for (i = index; i < index + count; i++)
                        if  (table->base[i].present)
@@ -182,7 +184,7 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
                index = (index + count) % INTR_REMAP_TABLE_ENTRIES;
 
                if (index == start_index) {
-                       spin_unlock(&irq_2_ir_lock);
+                       spin_unlock_irqrestore(&irq_2_ir_lock, flags);
                        printk(KERN_ERR "can't allocate an IRTE\n");
                        return -1;
                }
@@ -193,7 +195,7 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
 
        irq_iommu = irq_2_iommu_alloc(irq);
        if (!irq_iommu) {
-               spin_unlock(&irq_2_ir_lock);
+               spin_unlock_irqrestore(&irq_2_ir_lock, flags);
                printk(KERN_ERR "can't allocate irq_2_iommu\n");
                return -1;
        }
@@ -203,7 +205,7 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
        irq_iommu->sub_handle = 0;
        irq_iommu->irte_mask = mask;
 
-       spin_unlock(&irq_2_ir_lock);
+       spin_unlock_irqrestore(&irq_2_ir_lock, flags);
 
        return index;
 }
@@ -223,30 +225,32 @@ int map_irq_to_irte_handle(int irq, u16 *sub_handle)
 {
        int index;
        struct irq_2_iommu *irq_iommu;
+       unsigned long flags;
 
-       spin_lock(&irq_2_ir_lock);
+       spin_lock_irqsave(&irq_2_ir_lock, flags);
        irq_iommu = valid_irq_2_iommu(irq);
        if (!irq_iommu) {
-               spin_unlock(&irq_2_ir_lock);
+               spin_unlock_irqrestore(&irq_2_ir_lock, flags);
                return -1;
        }
 
        *sub_handle = irq_iommu->sub_handle;
        index = irq_iommu->irte_index;
-       spin_unlock(&irq_2_ir_lock);
+       spin_unlock_irqrestore(&irq_2_ir_lock, flags);
        return index;
 }
 
 int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
 {
        struct irq_2_iommu *irq_iommu;
+       unsigned long flags;
 
-       spin_lock(&irq_2_ir_lock);
+       spin_lock_irqsave(&irq_2_ir_lock, flags);
 
        irq_iommu = irq_2_iommu_alloc(irq);
 
        if (!irq_iommu) {
-               spin_unlock(&irq_2_ir_lock);
+               spin_unlock_irqrestore(&irq_2_ir_lock, flags);
                printk(KERN_ERR "can't allocate irq_2_iommu\n");
                return -1;
        }
@@ -256,7 +260,7 @@ int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
        irq_iommu->sub_handle = subhandle;
        irq_iommu->irte_mask = 0;
 
-       spin_unlock(&irq_2_ir_lock);
+       spin_unlock_irqrestore(&irq_2_ir_lock, flags);
 
        return 0;
 }
@@ -264,11 +268,12 @@ int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
 int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index)
 {
        struct irq_2_iommu *irq_iommu;
+       unsigned long flags;
 
-       spin_lock(&irq_2_ir_lock);
+       spin_lock_irqsave(&irq_2_ir_lock, flags);
        irq_iommu = valid_irq_2_iommu(irq);
        if (!irq_iommu) {
-               spin_unlock(&irq_2_ir_lock);
+               spin_unlock_irqrestore(&irq_2_ir_lock, flags);
                return -1;
        }
 
@@ -277,7 +282,7 @@ int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index)
        irq_iommu->sub_handle = 0;
        irq_2_iommu(irq)->irte_mask = 0;
 
-       spin_unlock(&irq_2_ir_lock);
+       spin_unlock_irqrestore(&irq_2_ir_lock, flags);
 
        return 0;
 }
@@ -289,11 +294,12 @@ int modify_irte(int irq, struct irte *irte_modified)
        struct irte *irte;
        struct intel_iommu *iommu;
        struct irq_2_iommu *irq_iommu;
+       unsigned long flags;
 
-       spin_lock(&irq_2_ir_lock);
+       spin_lock_irqsave(&irq_2_ir_lock, flags);
        irq_iommu = valid_irq_2_iommu(irq);
        if (!irq_iommu) {
-               spin_unlock(&irq_2_ir_lock);
+               spin_unlock_irqrestore(&irq_2_ir_lock, flags);
                return -1;
        }
 
@@ -302,11 +308,11 @@ int modify_irte(int irq, struct irte *irte_modified)
        index = irq_iommu->irte_index + irq_iommu->sub_handle;
        irte = &iommu->ir_table->base[index];
 
-       set_64bit((unsigned long *)irte, irte_modified->low | (1 << 1));
+       set_64bit((unsigned long *)irte, irte_modified->low);
        __iommu_flush_cache(iommu, irte, sizeof(*irte));
 
        rc = qi_flush_iec(iommu, index, 0);
-       spin_unlock(&irq_2_ir_lock);
+       spin_unlock_irqrestore(&irq_2_ir_lock, flags);
 
        return rc;
 }
@@ -317,11 +323,12 @@ int flush_irte(int irq)
        int index;
        struct intel_iommu *iommu;
        struct irq_2_iommu *irq_iommu;
+       unsigned long flags;
 
-       spin_lock(&irq_2_ir_lock);
+       spin_lock_irqsave(&irq_2_ir_lock, flags);
        irq_iommu = valid_irq_2_iommu(irq);
        if (!irq_iommu) {
-               spin_unlock(&irq_2_ir_lock);
+               spin_unlock_irqrestore(&irq_2_ir_lock, flags);
                return -1;
        }
 
@@ -330,7 +337,7 @@ int flush_irte(int irq)
        index = irq_iommu->irte_index + irq_iommu->sub_handle;
 
        rc = qi_flush_iec(iommu, index, irq_iommu->irte_mask);
-       spin_unlock(&irq_2_ir_lock);
+       spin_unlock_irqrestore(&irq_2_ir_lock, flags);
 
        return rc;
 }
@@ -363,11 +370,12 @@ int free_irte(int irq)
        struct irte *irte;
        struct intel_iommu *iommu;
        struct irq_2_iommu *irq_iommu;
+       unsigned long flags;
 
-       spin_lock(&irq_2_ir_lock);
+       spin_lock_irqsave(&irq_2_ir_lock, flags);
        irq_iommu = valid_irq_2_iommu(irq);
        if (!irq_iommu) {
-               spin_unlock(&irq_2_ir_lock);
+               spin_unlock_irqrestore(&irq_2_ir_lock, flags);
                return -1;
        }
 
@@ -378,7 +386,7 @@ int free_irte(int irq)
 
        if (!irq_iommu->sub_handle) {
                for (i = 0; i < (1 << irq_iommu->irte_mask); i++)
-                       set_64bit((unsigned long *)irte, 0);
+                       set_64bit((unsigned long *)(irte + i), 0);
                rc = qi_flush_iec(iommu, index, irq_iommu->irte_mask);
        }
 
@@ -387,7 +395,7 @@ int free_irte(int irq)
        irq_iommu->sub_handle = 0;
        irq_iommu->irte_mask = 0;
 
-       spin_unlock(&irq_2_ir_lock);
+       spin_unlock_irqrestore(&irq_2_ir_lock, flags);
 
        return rc;
 }
@@ -439,12 +447,12 @@ static int setup_intr_remapping(struct intel_iommu *iommu, int mode)
        struct page *pages;
 
        ir_table = iommu->ir_table = kzalloc(sizeof(struct ir_table),
-                                            GFP_KERNEL);
+                                            GFP_ATOMIC);
 
        if (!iommu->ir_table)
                return -ENOMEM;
 
-       pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, INTR_REMAP_PAGE_ORDER);
+       pages = alloc_pages(GFP_ATOMIC | __GFP_ZERO, INTR_REMAP_PAGE_ORDER);
 
        if (!pages) {
                printk(KERN_ERR "failed to allocate pages of order %d\n",
@@ -459,11 +467,55 @@ static int setup_intr_remapping(struct intel_iommu *iommu, int mode)
        return 0;
 }
 
+/*
+ * Disable Interrupt Remapping.
+ */
+static void disable_intr_remapping(struct intel_iommu *iommu)
+{
+       unsigned long flags;
+       u32 sts;
+
+       if (!ecap_ir_support(iommu->ecap))
+               return;
+
+       spin_lock_irqsave(&iommu->register_lock, flags);
+
+       sts = dmar_readq(iommu->reg + DMAR_GSTS_REG);
+       if (!(sts & DMA_GSTS_IRES))
+               goto end;
+
+       iommu->gcmd &= ~DMA_GCMD_IRE;
+       writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
+
+       IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+                     readl, !(sts & DMA_GSTS_IRES), sts);
+
+end:
+       spin_unlock_irqrestore(&iommu->register_lock, flags);
+}
+
 int __init enable_intr_remapping(int eim)
 {
        struct dmar_drhd_unit *drhd;
        int setup = 0;
 
+       for_each_drhd_unit(drhd) {
+               struct intel_iommu *iommu = drhd->iommu;
+
+               /*
+                * Clear previous faults.
+                */
+               dmar_fault(-1, iommu);
+
+               /*
+                * Disable intr remapping and queued invalidation, if already
+                * enabled prior to OS handover.
+                */
+               disable_intr_remapping(iommu);
+
+               dmar_disable_qi(iommu);
+       }
+
        /*
         * check for the Interrupt-remapping support
         */
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
new file mode 100644 (file)
index 0000000..7227efc
--- /dev/null
@@ -0,0 +1,680 @@
+/*
+ * drivers/pci/iov.c
+ *
+ * Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
+ *
+ * PCI Express I/O Virtualization (IOV) support.
+ *   Single Root IOV 1.0
+ */
+
+#include <linux/pci.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include "pci.h"
+
+#define VIRTFN_ID_LEN  16
+
+static inline u8 virtfn_bus(struct pci_dev *dev, int id)
+{
+       return dev->bus->number + ((dev->devfn + dev->sriov->offset +
+                                   dev->sriov->stride * id) >> 8);
+}
+
+static inline u8 virtfn_devfn(struct pci_dev *dev, int id)
+{
+       return (dev->devfn + dev->sriov->offset +
+               dev->sriov->stride * id) & 0xff;
+}
+
+static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)
+{
+       int rc;
+       struct pci_bus *child;
+
+       if (bus->number == busnr)
+               return bus;
+
+       child = pci_find_bus(pci_domain_nr(bus), busnr);
+       if (child)
+               return child;
+
+       child = pci_add_new_bus(bus, NULL, busnr);
+       if (!child)
+               return NULL;
+
+       child->subordinate = busnr;
+       child->dev.parent = bus->bridge;
+       rc = pci_bus_add_child(child);
+       if (rc) {
+               pci_remove_bus(child);
+               return NULL;
+       }
+
+       return child;
+}
+
+static void virtfn_remove_bus(struct pci_bus *bus, int busnr)
+{
+       struct pci_bus *child;
+
+       if (bus->number == busnr)
+               return;
+
+       child = pci_find_bus(pci_domain_nr(bus), busnr);
+       BUG_ON(!child);
+
+       if (list_empty(&child->devices))
+               pci_remove_bus(child);
+}
+
+static int virtfn_add(struct pci_dev *dev, int id, int reset)
+{
+       int i;
+       int rc;
+       u64 size;
+       char buf[VIRTFN_ID_LEN];
+       struct pci_dev *virtfn;
+       struct resource *res;
+       struct pci_sriov *iov = dev->sriov;
+
+       virtfn = alloc_pci_dev();
+       if (!virtfn)
+               return -ENOMEM;
+
+       mutex_lock(&iov->dev->sriov->lock);
+       virtfn->bus = virtfn_add_bus(dev->bus, virtfn_bus(dev, id));
+       if (!virtfn->bus) {
+               kfree(virtfn);
+               mutex_unlock(&iov->dev->sriov->lock);
+               return -ENOMEM;
+       }
+       virtfn->devfn = virtfn_devfn(dev, id);
+       virtfn->vendor = dev->vendor;
+       pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_DID, &virtfn->device);
+       pci_setup_device(virtfn);
+       virtfn->dev.parent = dev->dev.parent;
+
+       for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
+               res = dev->resource + PCI_IOV_RESOURCES + i;
+               if (!res->parent)
+                       continue;
+               virtfn->resource[i].name = pci_name(virtfn);
+               virtfn->resource[i].flags = res->flags;
+               size = resource_size(res);
+               do_div(size, iov->total);
+               virtfn->resource[i].start = res->start + size * id;
+               virtfn->resource[i].end = virtfn->resource[i].start + size - 1;
+               rc = request_resource(res, &virtfn->resource[i]);
+               BUG_ON(rc);
+       }
+
+       if (reset)
+               pci_execute_reset_function(virtfn);
+
+       pci_device_add(virtfn, virtfn->bus);
+       mutex_unlock(&iov->dev->sriov->lock);
+
+       virtfn->physfn = pci_dev_get(dev);
+       virtfn->is_virtfn = 1;
+
+       rc = pci_bus_add_device(virtfn);
+       if (rc)
+               goto failed1;
+       sprintf(buf, "virtfn%u", id);
+       rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf);
+       if (rc)
+               goto failed1;
+       rc = sysfs_create_link(&virtfn->dev.kobj, &dev->dev.kobj, "physfn");
+       if (rc)
+               goto failed2;
+
+       kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE);
+
+       return 0;
+
+failed2:
+       sysfs_remove_link(&dev->dev.kobj, buf);
+failed1:
+       pci_dev_put(dev);
+       mutex_lock(&iov->dev->sriov->lock);
+       pci_remove_bus_device(virtfn);
+       virtfn_remove_bus(dev->bus, virtfn_bus(dev, id));
+       mutex_unlock(&iov->dev->sriov->lock);
+
+       return rc;
+}
+
+static void virtfn_remove(struct pci_dev *dev, int id, int reset)
+{
+       char buf[VIRTFN_ID_LEN];
+       struct pci_bus *bus;
+       struct pci_dev *virtfn;
+       struct pci_sriov *iov = dev->sriov;
+
+       bus = pci_find_bus(pci_domain_nr(dev->bus), virtfn_bus(dev, id));
+       if (!bus)
+               return;
+
+       virtfn = pci_get_slot(bus, virtfn_devfn(dev, id));
+       if (!virtfn)
+               return;
+
+       pci_dev_put(virtfn);
+
+       if (reset) {
+               device_release_driver(&virtfn->dev);
+               pci_execute_reset_function(virtfn);
+       }
+
+       sprintf(buf, "virtfn%u", id);
+       sysfs_remove_link(&dev->dev.kobj, buf);
+       sysfs_remove_link(&virtfn->dev.kobj, "physfn");
+
+       mutex_lock(&iov->dev->sriov->lock);
+       pci_remove_bus_device(virtfn);
+       virtfn_remove_bus(dev->bus, virtfn_bus(dev, id));
+       mutex_unlock(&iov->dev->sriov->lock);
+
+       pci_dev_put(dev);
+}
+
+static int sriov_migration(struct pci_dev *dev)
+{
+       u16 status;
+       struct pci_sriov *iov = dev->sriov;
+
+       if (!iov->nr_virtfn)
+               return 0;
+
+       if (!(iov->cap & PCI_SRIOV_CAP_VFM))
+               return 0;
+
+       pci_read_config_word(dev, iov->pos + PCI_SRIOV_STATUS, &status);
+       if (!(status & PCI_SRIOV_STATUS_VFM))
+               return 0;
+
+       schedule_work(&iov->mtask);
+
+       return 1;
+}
+
+static void sriov_migration_task(struct work_struct *work)
+{
+       int i;
+       u8 state;
+       u16 status;
+       struct pci_sriov *iov = container_of(work, struct pci_sriov, mtask);
+
+       for (i = iov->initial; i < iov->nr_virtfn; i++) {
+               state = readb(iov->mstate + i);
+               if (state == PCI_SRIOV_VFM_MI) {
+                       writeb(PCI_SRIOV_VFM_AV, iov->mstate + i);
+                       state = readb(iov->mstate + i);
+                       if (state == PCI_SRIOV_VFM_AV)
+                               virtfn_add(iov->self, i, 1);
+               } else if (state == PCI_SRIOV_VFM_MO) {
+                       virtfn_remove(iov->self, i, 1);
+                       writeb(PCI_SRIOV_VFM_UA, iov->mstate + i);
+                       state = readb(iov->mstate + i);
+                       if (state == PCI_SRIOV_VFM_AV)
+                               virtfn_add(iov->self, i, 0);
+               }
+       }
+
+       pci_read_config_word(iov->self, iov->pos + PCI_SRIOV_STATUS, &status);
+       status &= ~PCI_SRIOV_STATUS_VFM;
+       pci_write_config_word(iov->self, iov->pos + PCI_SRIOV_STATUS, status);
+}
+
+static int sriov_enable_migration(struct pci_dev *dev, int nr_virtfn)
+{
+       int bir;
+       u32 table;
+       resource_size_t pa;
+       struct pci_sriov *iov = dev->sriov;
+
+       if (nr_virtfn <= iov->initial)
+               return 0;
+
+       pci_read_config_dword(dev, iov->pos + PCI_SRIOV_VFM, &table);
+       bir = PCI_SRIOV_VFM_BIR(table);
+       if (bir > PCI_STD_RESOURCE_END)
+               return -EIO;
+
+       table = PCI_SRIOV_VFM_OFFSET(table);
+       if (table + nr_virtfn > pci_resource_len(dev, bir))
+               return -EIO;
+
+       pa = pci_resource_start(dev, bir) + table;
+       iov->mstate = ioremap(pa, nr_virtfn);
+       if (!iov->mstate)
+               return -ENOMEM;
+
+       INIT_WORK(&iov->mtask, sriov_migration_task);
+
+       iov->ctrl |= PCI_SRIOV_CTRL_VFM | PCI_SRIOV_CTRL_INTR;
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+
+       return 0;
+}
+
+static void sriov_disable_migration(struct pci_dev *dev)
+{
+       struct pci_sriov *iov = dev->sriov;
+
+       iov->ctrl &= ~(PCI_SRIOV_CTRL_VFM | PCI_SRIOV_CTRL_INTR);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+
+       cancel_work_sync(&iov->mtask);
+       iounmap(iov->mstate);
+}
+
+static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
+{
+       int rc;
+       int i, j;
+       int nres;
+       u16 offset, stride, initial;
+       struct resource *res;
+       struct pci_dev *pdev;
+       struct pci_sriov *iov = dev->sriov;
+
+       if (!nr_virtfn)
+               return 0;
+
+       if (iov->nr_virtfn)
+               return -EINVAL;
+
+       pci_read_config_word(dev, iov->pos + PCI_SRIOV_INITIAL_VF, &initial);
+       if (initial > iov->total ||
+           (!(iov->cap & PCI_SRIOV_CAP_VFM) && (initial != iov->total)))
+               return -EIO;
+
+       if (nr_virtfn < 0 || nr_virtfn > iov->total ||
+           (!(iov->cap & PCI_SRIOV_CAP_VFM) && (nr_virtfn > initial)))
+               return -EINVAL;
+
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, nr_virtfn);
+       pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_OFFSET, &offset);
+       pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_STRIDE, &stride);
+       if (!offset || (nr_virtfn > 1 && !stride))
+               return -EIO;
+
+       nres = 0;
+       for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
+               res = dev->resource + PCI_IOV_RESOURCES + i;
+               if (res->parent)
+                       nres++;
+       }
+       if (nres != iov->nres) {
+               dev_err(&dev->dev, "not enough MMIO resources for SR-IOV\n");
+               return -ENOMEM;
+       }
+
+       iov->offset = offset;
+       iov->stride = stride;
+
+       if (virtfn_bus(dev, nr_virtfn - 1) > dev->bus->subordinate) {
+               dev_err(&dev->dev, "SR-IOV: bus number out of range\n");
+               return -ENOMEM;
+       }
+
+       if (iov->link != dev->devfn) {
+               pdev = pci_get_slot(dev->bus, iov->link);
+               if (!pdev)
+                       return -ENODEV;
+
+               pci_dev_put(pdev);
+
+               if (!pdev->is_physfn)
+                       return -ENODEV;
+
+               rc = sysfs_create_link(&dev->dev.kobj,
+                                       &pdev->dev.kobj, "dep_link");
+               if (rc)
+                       return rc;
+       }
+
+       iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE;
+       pci_block_user_cfg_access(dev);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+       msleep(100);
+       pci_unblock_user_cfg_access(dev);
+
+       iov->initial = initial;
+       if (nr_virtfn < initial)
+               initial = nr_virtfn;
+
+       for (i = 0; i < initial; i++) {
+               rc = virtfn_add(dev, i, 0);
+               if (rc)
+                       goto failed;
+       }
+
+       if (iov->cap & PCI_SRIOV_CAP_VFM) {
+               rc = sriov_enable_migration(dev, nr_virtfn);
+               if (rc)
+                       goto failed;
+       }
+
+       kobject_uevent(&dev->dev.kobj, KOBJ_CHANGE);
+       iov->nr_virtfn = nr_virtfn;
+
+       return 0;
+
+failed:
+       for (j = 0; j < i; j++)
+               virtfn_remove(dev, j, 0);
+
+       iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
+       pci_block_user_cfg_access(dev);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+       ssleep(1);
+       pci_unblock_user_cfg_access(dev);
+
+       if (iov->link != dev->devfn)
+               sysfs_remove_link(&dev->dev.kobj, "dep_link");
+
+       return rc;
+}
+
+static void sriov_disable(struct pci_dev *dev)
+{
+       int i;
+       struct pci_sriov *iov = dev->sriov;
+
+       if (!iov->nr_virtfn)
+               return;
+
+       if (iov->cap & PCI_SRIOV_CAP_VFM)
+               sriov_disable_migration(dev);
+
+       for (i = 0; i < iov->nr_virtfn; i++)
+               virtfn_remove(dev, i, 0);
+
+       iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
+       pci_block_user_cfg_access(dev);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+       ssleep(1);
+       pci_unblock_user_cfg_access(dev);
+
+       if (iov->link != dev->devfn)
+               sysfs_remove_link(&dev->dev.kobj, "dep_link");
+
+       iov->nr_virtfn = 0;
+}
+
+static int sriov_init(struct pci_dev *dev, int pos)
+{
+       int i;
+       int rc;
+       int nres;
+       u32 pgsz;
+       u16 ctrl, total, offset, stride;
+       struct pci_sriov *iov;
+       struct resource *res;
+       struct pci_dev *pdev;
+
+       if (dev->pcie_type != PCI_EXP_TYPE_RC_END &&
+           dev->pcie_type != PCI_EXP_TYPE_ENDPOINT)
+               return -ENODEV;
+
+       pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &ctrl);
+       if (ctrl & PCI_SRIOV_CTRL_VFE) {
+               pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, 0);
+               ssleep(1);
+       }
+
+       pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &total);
+       if (!total)
+               return 0;
+
+       ctrl = 0;
+       list_for_each_entry(pdev, &dev->bus->devices, bus_list)
+               if (pdev->is_physfn)
+                       goto found;
+
+       pdev = NULL;
+       if (pci_ari_enabled(dev->bus))
+               ctrl |= PCI_SRIOV_CTRL_ARI;
+
+found:
+       pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl);
+       pci_write_config_word(dev, pos + PCI_SRIOV_NUM_VF, total);
+       pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset);
+       pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride);
+       if (!offset || (total > 1 && !stride))
+               return -EIO;
+
+       pci_read_config_dword(dev, pos + PCI_SRIOV_SUP_PGSIZE, &pgsz);
+       i = PAGE_SHIFT > 12 ? PAGE_SHIFT - 12 : 0;
+       pgsz &= ~((1 << i) - 1);
+       if (!pgsz)
+               return -EIO;
+
+       pgsz &= ~(pgsz - 1);
+       pci_write_config_dword(dev, pos + PCI_SRIOV_SYS_PGSIZE, pgsz);
+
+       nres = 0;
+       for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
+               res = dev->resource + PCI_IOV_RESOURCES + i;
+               i += __pci_read_base(dev, pci_bar_unknown, res,
+                                    pos + PCI_SRIOV_BAR + i * 4);
+               if (!res->flags)
+                       continue;
+               if (resource_size(res) & (PAGE_SIZE - 1)) {
+                       rc = -EIO;
+                       goto failed;
+               }
+               res->end = res->start + resource_size(res) * total - 1;
+               nres++;
+       }
+
+       iov = kzalloc(sizeof(*iov), GFP_KERNEL);
+       if (!iov) {
+               rc = -ENOMEM;
+               goto failed;
+       }
+
+       iov->pos = pos;
+       iov->nres = nres;
+       iov->ctrl = ctrl;
+       iov->total = total;
+       iov->offset = offset;
+       iov->stride = stride;
+       iov->pgsz = pgsz;
+       iov->self = dev;
+       pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap);
+       pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
+
+       if (pdev)
+               iov->dev = pci_dev_get(pdev);
+       else {
+               iov->dev = dev;
+               mutex_init(&iov->lock);
+       }
+
+       dev->sriov = iov;
+       dev->is_physfn = 1;
+
+       return 0;
+
+failed:
+       for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
+               res = dev->resource + PCI_IOV_RESOURCES + i;
+               res->flags = 0;
+       }
+
+       return rc;
+}
+
+static void sriov_release(struct pci_dev *dev)
+{
+       BUG_ON(dev->sriov->nr_virtfn);
+
+       if (dev == dev->sriov->dev)
+               mutex_destroy(&dev->sriov->lock);
+       else
+               pci_dev_put(dev->sriov->dev);
+
+       kfree(dev->sriov);
+       dev->sriov = NULL;
+}
+
+static void sriov_restore_state(struct pci_dev *dev)
+{
+       int i;
+       u16 ctrl;
+       struct pci_sriov *iov = dev->sriov;
+
+       pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &ctrl);
+       if (ctrl & PCI_SRIOV_CTRL_VFE)
+               return;
+
+       for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++)
+               pci_update_resource(dev, i);
+
+       pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, iov->nr_virtfn);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+       if (iov->ctrl & PCI_SRIOV_CTRL_VFE)
+               msleep(100);
+}
+
+/**
+ * pci_iov_init - initialize the IOV capability
+ * @dev: the PCI device
+ *
+ * Returns 0 on success, or negative on failure.
+ */
+int pci_iov_init(struct pci_dev *dev)
+{
+       int pos;
+
+       if (!dev->is_pcie)
+               return -ENODEV;
+
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
+       if (pos)
+               return sriov_init(dev, pos);
+
+       return -ENODEV;
+}
+
+/**
+ * pci_iov_release - release resources used by the IOV capability
+ * @dev: the PCI device
+ */
+void pci_iov_release(struct pci_dev *dev)
+{
+       if (dev->is_physfn)
+               sriov_release(dev);
+}
+
+/**
+ * pci_iov_resource_bar - get position of the SR-IOV BAR
+ * @dev: the PCI device
+ * @resno: the resource number
+ * @type: the BAR type to be filled in
+ *
+ * Returns position of the BAR encapsulated in the SR-IOV capability.
+ */
+int pci_iov_resource_bar(struct pci_dev *dev, int resno,
+                        enum pci_bar_type *type)
+{
+       if (resno < PCI_IOV_RESOURCES || resno > PCI_IOV_RESOURCE_END)
+               return 0;
+
+       BUG_ON(!dev->is_physfn);
+
+       *type = pci_bar_unknown;
+
+       return dev->sriov->pos + PCI_SRIOV_BAR +
+               4 * (resno - PCI_IOV_RESOURCES);
+}
+
+/**
+ * pci_restore_iov_state - restore the state of the IOV capability
+ * @dev: the PCI device
+ */
+void pci_restore_iov_state(struct pci_dev *dev)
+{
+       if (dev->is_physfn)
+               sriov_restore_state(dev);
+}
+
+/**
+ * pci_iov_bus_range - find bus range used by Virtual Function
+ * @bus: the PCI bus
+ *
+ * Returns max number of buses (exclude current one) used by Virtual
+ * Functions.
+ */
+int pci_iov_bus_range(struct pci_bus *bus)
+{
+       int max = 0;
+       u8 busnr;
+       struct pci_dev *dev;
+
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               if (!dev->is_physfn)
+                       continue;
+               busnr = virtfn_bus(dev, dev->sriov->total - 1);
+               if (busnr > max)
+                       max = busnr;
+       }
+
+       return max ? max - bus->number : 0;
+}
+
+/**
+ * pci_enable_sriov - enable the SR-IOV capability
+ * @dev: the PCI device
+ *
+ * Returns 0 on success, or negative on failure.
+ */
+int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
+{
+       might_sleep();
+
+       if (!dev->is_physfn)
+               return -ENODEV;
+
+       return sriov_enable(dev, nr_virtfn);
+}
+EXPORT_SYMBOL_GPL(pci_enable_sriov);
+
+/**
+ * pci_disable_sriov - disable the SR-IOV capability
+ * @dev: the PCI device
+ */
+void pci_disable_sriov(struct pci_dev *dev)
+{
+       might_sleep();
+
+       if (!dev->is_physfn)
+               return;
+
+       sriov_disable(dev);
+}
+EXPORT_SYMBOL_GPL(pci_disable_sriov);
+
+/**
+ * pci_sriov_migration - notify SR-IOV core of Virtual Function Migration
+ * @dev: the PCI device
+ *
+ * Returns IRQ_HANDLED if the IRQ is handled, or IRQ_NONE if not.
+ *
+ * Physical Function driver is responsible to register IRQ handler using
+ * VF Migration Interrupt Message Number, and call this function when the
+ * interrupt is generated by the hardware.
+ */
+irqreturn_t pci_sriov_migration(struct pci_dev *dev)
+{
+       if (!dev->is_physfn)
+               return IRQ_NONE;
+
+       return sriov_migration(dev) ? IRQ_HANDLED : IRQ_NONE;
+}
+EXPORT_SYMBOL_GPL(pci_sriov_migration);
index baba2eb5367df54bcc947333beda7e56332f3785..6f2e6295e773d657eb76af3bbb39d53e917ce415 100644 (file)
@@ -27,48 +27,53 @@ static int pci_msi_enable = 1;
 
 /* Arch hooks */
 
-int __attribute__ ((weak))
-arch_msi_check_device(struct pci_dev *dev, int nvec, int type)
+#ifndef arch_msi_check_device
+int arch_msi_check_device(struct pci_dev *dev, int nvec, int type)
 {
        return 0;
 }
+#endif
 
-int __attribute__ ((weak))
-arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry)
-{
-       return 0;
-}
-
-int __attribute__ ((weak))
-arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+#ifndef arch_setup_msi_irqs
+int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 {
        struct msi_desc *entry;
        int ret;
 
+       /*
+        * If an architecture wants to support multiple MSI, it needs to
+        * override arch_setup_msi_irqs()
+        */
+       if (type == PCI_CAP_ID_MSI && nvec > 1)
+               return 1;
+
        list_for_each_entry(entry, &dev->msi_list, list) {
                ret = arch_setup_msi_irq(dev, entry);
-               if (ret)
+               if (ret < 0)
                        return ret;
+               if (ret > 0)
+                       return -ENOSPC;
        }
 
        return 0;
 }
+#endif
 
-void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq)
-{
-       return;
-}
-
-void __attribute__ ((weak))
-arch_teardown_msi_irqs(struct pci_dev *dev)
+#ifndef arch_teardown_msi_irqs
+void arch_teardown_msi_irqs(struct pci_dev *dev)
 {
        struct msi_desc *entry;
 
        list_for_each_entry(entry, &dev->msi_list, list) {
-               if (entry->irq != 0)
-                       arch_teardown_msi_irq(entry->irq);
+               int i, nvec;
+               if (entry->irq == 0)
+                       continue;
+               nvec = 1 << entry->msi_attrib.multiple;
+               for (i = 0; i < nvec; i++)
+                       arch_teardown_msi_irq(entry->irq + i);
        }
 }
+#endif
 
 static void __msi_set_enable(struct pci_dev *dev, int pos, int enable)
 {
@@ -111,27 +116,14 @@ static inline __attribute_const__ u32 msi_mask(unsigned x)
        return (1 << (1 << x)) - 1;
 }
 
-static void msix_flush_writes(struct irq_desc *desc)
+static inline __attribute_const__ u32 msi_capable_mask(u16 control)
 {
-       struct msi_desc *entry;
+       return msi_mask((control >> 1) & 7);
+}
 
-       entry = get_irq_desc_msi(desc);
-       BUG_ON(!entry || !entry->dev);
-       switch (entry->msi_attrib.type) {
-       case PCI_CAP_ID_MSI:
-               /* nothing to do */
-               break;
-       case PCI_CAP_ID_MSIX:
-       {
-               int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-                       PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
-               readl(entry->mask_base + offset);
-               break;
-       }
-       default:
-               BUG();
-               break;
-       }
+static inline __attribute_const__ u32 msi_enabled_mask(u16 control)
+{
+       return msi_mask((control >> 4) & 7);
 }
 
 /*
@@ -143,49 +135,71 @@ static void msix_flush_writes(struct irq_desc *desc)
  * Returns 1 if it succeeded in masking the interrupt and 0 if the device
  * doesn't support MSI masking.
  */
-static int msi_set_mask_bits(struct irq_desc *desc, u32 mask, u32 flag)
+static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
 {
-       struct msi_desc *entry;
+       u32 mask_bits = desc->masked;
 
-       entry = get_irq_desc_msi(desc);
-       BUG_ON(!entry || !entry->dev);
-       switch (entry->msi_attrib.type) {
-       case PCI_CAP_ID_MSI:
-               if (entry->msi_attrib.maskbit) {
-                       int pos;
-                       u32 mask_bits;
-
-                       pos = (long)entry->mask_base;
-                       pci_read_config_dword(entry->dev, pos, &mask_bits);
-                       mask_bits &= ~(mask);
-                       mask_bits |= flag & mask;
-                       pci_write_config_dword(entry->dev, pos, mask_bits);
-               } else {
-                       return 0;
-               }
-               break;
-       case PCI_CAP_ID_MSIX:
-       {
-               int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-                       PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
-               writel(flag, entry->mask_base + offset);
-               readl(entry->mask_base + offset);
-               break;
-       }
-       default:
-               BUG();
-               break;
+       if (!desc->msi_attrib.maskbit)
+               return;
+
+       mask_bits &= ~mask;
+       mask_bits |= flag;
+       pci_write_config_dword(desc->dev, desc->mask_pos, mask_bits);
+       desc->masked = mask_bits;
+}
+
+/*
+ * This internal function does not flush PCI writes to the device.
+ * All users must ensure that they read from the device before either
+ * assuming that the device state is up to date, or returning out of this
+ * file.  This saves a few milliseconds when initialising devices with lots
+ * of MSI-X interrupts.
+ */
+static void msix_mask_irq(struct msi_desc *desc, u32 flag)
+{
+       u32 mask_bits = desc->masked;
+       unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+                                       PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
+       mask_bits &= ~1;
+       mask_bits |= flag;
+       writel(mask_bits, desc->mask_base + offset);
+       desc->masked = mask_bits;
+}
+
+static void msi_set_mask_bit(unsigned irq, u32 flag)
+{
+       struct msi_desc *desc = get_irq_msi(irq);
+
+       if (desc->msi_attrib.is_msix) {
+               msix_mask_irq(desc, flag);
+               readl(desc->mask_base);         /* Flush write to device */
+       } else {
+               unsigned offset = irq - desc->dev->irq;
+               msi_mask_irq(desc, 1 << offset, flag << offset);
        }
-       entry->msi_attrib.masked = !!flag;
-       return 1;
+}
+
+void mask_msi_irq(unsigned int irq)
+{
+       msi_set_mask_bit(irq, 1);
+}
+
+void unmask_msi_irq(unsigned int irq)
+{
+       msi_set_mask_bit(irq, 0);
 }
 
 void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
 {
        struct msi_desc *entry = get_irq_desc_msi(desc);
-       switch(entry->msi_attrib.type) {
-       case PCI_CAP_ID_MSI:
-       {
+       if (entry->msi_attrib.is_msix) {
+               void __iomem *base = entry->mask_base +
+                       entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
+
+               msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+               msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+               msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET);
+       } else {
                struct pci_dev *dev = entry->dev;
                int pos = entry->msi_attrib.pos;
                u16 data;
@@ -201,21 +215,6 @@ void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
                        pci_read_config_word(dev, msi_data_reg(pos, 0), &data);
                }
                msg->data = data;
-               break;
-       }
-       case PCI_CAP_ID_MSIX:
-       {
-               void __iomem *base;
-               base = entry->mask_base +
-                       entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
-
-               msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-               msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-               msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET);
-               break;
-       }
-       default:
-               BUG();
        }
 }
 
@@ -229,11 +228,25 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
 void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
 {
        struct msi_desc *entry = get_irq_desc_msi(desc);
-       switch (entry->msi_attrib.type) {
-       case PCI_CAP_ID_MSI:
-       {
+       if (entry->msi_attrib.is_msix) {
+               void __iomem *base;
+               base = entry->mask_base +
+                       entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
+
+               writel(msg->address_lo,
+                       base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+               writel(msg->address_hi,
+                       base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+               writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET);
+       } else {
                struct pci_dev *dev = entry->dev;
                int pos = entry->msi_attrib.pos;
+               u16 msgctl;
+
+               pci_read_config_word(dev, msi_control_reg(pos), &msgctl);
+               msgctl &= ~PCI_MSI_FLAGS_QSIZE;
+               msgctl |= entry->msi_attrib.multiple << 4;
+               pci_write_config_word(dev, msi_control_reg(pos), msgctl);
 
                pci_write_config_dword(dev, msi_lower_address_reg(pos),
                                        msg->address_lo);
@@ -246,23 +259,6 @@ void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
                        pci_write_config_word(dev, msi_data_reg(pos, 0),
                                                msg->data);
                }
-               break;
-       }
-       case PCI_CAP_ID_MSIX:
-       {
-               void __iomem *base;
-               base = entry->mask_base +
-                       entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
-
-               writel(msg->address_lo,
-                       base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-               writel(msg->address_hi,
-                       base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-               writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET);
-               break;
-       }
-       default:
-               BUG();
        }
        entry->msg = *msg;
 }
@@ -274,37 +270,18 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg)
        write_msi_msg_desc(desc, msg);
 }
 
-void mask_msi_irq(unsigned int irq)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       msi_set_mask_bits(desc, 1, 1);
-       msix_flush_writes(desc);
-}
-
-void unmask_msi_irq(unsigned int irq)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       msi_set_mask_bits(desc, 1, 0);
-       msix_flush_writes(desc);
-}
-
 static int msi_free_irqs(struct pci_dev* dev);
 
-static struct msi_desc* alloc_msi_entry(void)
+static struct msi_desc *alloc_msi_entry(struct pci_dev *dev)
 {
-       struct msi_desc *entry;
-
-       entry = kzalloc(sizeof(struct msi_desc), GFP_KERNEL);
-       if (!entry)
+       struct msi_desc *desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+       if (!desc)
                return NULL;
 
-       INIT_LIST_HEAD(&entry->list);
-       entry->irq = 0;
-       entry->dev = NULL;
+       INIT_LIST_HEAD(&desc->list);
+       desc->dev = dev;
 
-       return entry;
+       return desc;
 }
 
 static void pci_intx_for_msi(struct pci_dev *dev, int enable)
@@ -328,15 +305,11 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
        pci_intx_for_msi(dev, 0);
        msi_set_enable(dev, 0);
        write_msi_msg(dev->irq, &entry->msg);
-       if (entry->msi_attrib.maskbit) {
-               struct irq_desc *desc = irq_to_desc(dev->irq);
-               msi_set_mask_bits(desc, entry->msi_attrib.maskbits_mask,
-                                 entry->msi_attrib.masked);
-       }
 
        pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
+       msi_mask_irq(entry, msi_capable_mask(control), entry->masked);
        control &= ~PCI_MSI_FLAGS_QSIZE;
-       control |= PCI_MSI_FLAGS_ENABLE;
+       control |= (entry->msi_attrib.multiple << 4) | PCI_MSI_FLAGS_ENABLE;
        pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
 }
 
@@ -354,9 +327,8 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
        msix_set_enable(dev, 0);
 
        list_for_each_entry(entry, &dev->msi_list, list) {
-               struct irq_desc *desc = irq_to_desc(entry->irq);
                write_msi_msg(entry->irq, &entry->msg);
-               msi_set_mask_bits(desc, 1, entry->msi_attrib.masked);
+               msix_mask_irq(entry, entry->masked);
        }
 
        BUG_ON(list_empty(&dev->msi_list));
@@ -378,52 +350,48 @@ EXPORT_SYMBOL_GPL(pci_restore_msi_state);
 /**
  * msi_capability_init - configure device's MSI capability structure
  * @dev: pointer to the pci_dev data structure of MSI device function
+ * @nvec: number of interrupts to allocate
  *
- * Setup the MSI capability structure of device function with a single
- * MSI irq, regardless of device function is capable of handling
- * multiple messages. A return of zero indicates the successful setup
- * of an entry zero with the new MSI irq or non-zero for otherwise.
- **/
-static int msi_capability_init(struct pci_dev *dev)
+ * Setup the MSI capability structure of the device with the requested
+ * number of interrupts.  A return value of zero indicates the successful
+ * setup of an entry with the new MSI irq.  A negative return value indicates
+ * an error, and a positive return value indicates the number of interrupts
+ * which could have been allocated.
+ */
+static int msi_capability_init(struct pci_dev *dev, int nvec)
 {
        struct msi_desc *entry;
        int pos, ret;
        u16 control;
+       unsigned mask;
 
        msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */
 
        pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
        pci_read_config_word(dev, msi_control_reg(pos), &control);
        /* MSI Entry Initialization */
-       entry = alloc_msi_entry();
+       entry = alloc_msi_entry(dev);
        if (!entry)
                return -ENOMEM;
 
-       entry->msi_attrib.type = PCI_CAP_ID_MSI;
+       entry->msi_attrib.is_msix = 0;
        entry->msi_attrib.is_64 = is_64bit_address(control);
        entry->msi_attrib.entry_nr = 0;
        entry->msi_attrib.maskbit = is_mask_bit_support(control);
-       entry->msi_attrib.masked = 1;
        entry->msi_attrib.default_irq = dev->irq;       /* Save IOAPIC IRQ */
        entry->msi_attrib.pos = pos;
-       entry->dev = dev;
-       if (entry->msi_attrib.maskbit) {
-               unsigned int base, maskbits, temp;
-
-               base = msi_mask_bits_reg(pos, entry->msi_attrib.is_64);
-               entry->mask_base = (void __iomem *)(long)base;
-
-               /* All MSIs are unmasked by default, Mask them all */
-               pci_read_config_dword(dev, base, &maskbits);
-               temp = msi_mask((control & PCI_MSI_FLAGS_QMASK) >> 1);
-               maskbits |= temp;
-               pci_write_config_dword(dev, base, maskbits);
-               entry->msi_attrib.maskbits_mask = temp;
-       }
+
+       entry->mask_pos = msi_mask_bits_reg(pos, entry->msi_attrib.is_64);
+       /* All MSIs are unmasked by default, Mask them all */
+       if (entry->msi_attrib.maskbit)
+               pci_read_config_dword(dev, entry->mask_pos, &entry->masked);
+       mask = msi_capable_mask(control);
+       msi_mask_irq(entry, mask, mask);
+
        list_add_tail(&entry->list, &dev->msi_list);
 
        /* Configure MSI capability structure */
-       ret = arch_setup_msi_irqs(dev, 1, PCI_CAP_ID_MSI);
+       ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI);
        if (ret) {
                msi_free_irqs(dev);
                return ret;
@@ -476,26 +444,28 @@ static int msix_capability_init(struct pci_dev *dev,
 
        /* MSI-X Table Initialization */
        for (i = 0; i < nvec; i++) {
-               entry = alloc_msi_entry();
+               entry = alloc_msi_entry(dev);
                if (!entry)
                        break;
 
                j = entries[i].entry;
-               entry->msi_attrib.type = PCI_CAP_ID_MSIX;
+               entry->msi_attrib.is_msix = 1;
                entry->msi_attrib.is_64 = 1;
                entry->msi_attrib.entry_nr = j;
-               entry->msi_attrib.maskbit = 1;
-               entry->msi_attrib.masked = 1;
                entry->msi_attrib.default_irq = dev->irq;
                entry->msi_attrib.pos = pos;
-               entry->dev = dev;
                entry->mask_base = base;
+               entry->masked = readl(base + j * PCI_MSIX_ENTRY_SIZE +
+                                       PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
+               msix_mask_irq(entry, 1);
 
                list_add_tail(&entry->list, &dev->msi_list);
        }
 
        ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
-       if (ret) {
+       if (ret < 0) {
+               /* If we had some success report the number of irqs
+                * we succeeded in setting up. */
                int avail = 0;
                list_for_each_entry(entry, &dev->msi_list, list) {
                        if (entry->irq != 0) {
@@ -503,14 +473,13 @@ static int msix_capability_init(struct pci_dev *dev,
                        }
                }
 
-               msi_free_irqs(dev);
+               if (avail != 0)
+                       ret = avail;
+       }
 
-               /* If we had some success report the number of irqs
-                * we succeeded in setting up.
-                */
-               if (avail == 0)
-                       avail = ret;
-               return avail;
+       if (ret) {
+               msi_free_irqs(dev);
+               return ret;
        }
 
        i = 0;
@@ -575,39 +544,54 @@ static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type)
 }
 
 /**
- * pci_enable_msi - configure device's MSI capability structure
- * @dev: pointer to the pci_dev data structure of MSI device function
+ * pci_enable_msi_block - configure device's MSI capability structure
+ * @dev: device to configure
+ * @nvec: number of interrupts to configure
  *
- * Setup the MSI capability structure of device function with
- * a single MSI irq upon its software driver call to request for
- * MSI mode enabled on its hardware device function. A return of zero
- * indicates the successful setup of an entry zero with the new MSI
- * irq or non-zero for otherwise.
- **/
-int pci_enable_msi(struct pci_dev* dev)
+ * Allocate IRQs for a device with the MSI capability.
+ * This function returns a negative errno if an error occurs.  If it
+ * is unable to allocate the number of interrupts requested, it returns
+ * the number of interrupts it might be able to allocate.  If it successfully
+ * allocates at least the number of interrupts requested, it returns 0 and
+ * updates the @dev's irq member to the lowest new interrupt number; the
+ * other interrupt numbers allocated to this device are consecutive.
+ */
+int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec)
 {
-       int status;
+       int status, pos, maxvec;
+       u16 msgctl;
 
-       status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI);
+       pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+       if (!pos)
+               return -EINVAL;
+       pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
+       maxvec = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
+       if (nvec > maxvec)
+               return maxvec;
+
+       status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSI);
        if (status)
                return status;
 
        WARN_ON(!!dev->msi_enabled);
 
-       /* Check whether driver already requested for MSI-X irqs */
+       /* Check whether driver already requested MSI-X irqs */
        if (dev->msix_enabled) {
                dev_info(&dev->dev, "can't enable MSI "
                         "(MSI-X already enabled)\n");
                return -EINVAL;
        }
-       status = msi_capability_init(dev);
+
+       status = msi_capability_init(dev, nvec);
        return status;
 }
-EXPORT_SYMBOL(pci_enable_msi);
+EXPORT_SYMBOL(pci_enable_msi_block);
 
-void pci_msi_shutdown(struct pci_devdev)
+void pci_msi_shutdown(struct pci_dev *dev)
 {
-       struct msi_desc *entry;
+       struct msi_desc *desc;
+       u32 mask;
+       u16 ctrl;
 
        if (!pci_msi_enable || !dev || !dev->msi_enabled)
                return;
@@ -617,19 +601,15 @@ void pci_msi_shutdown(struct pci_dev* dev)
        dev->msi_enabled = 0;
 
        BUG_ON(list_empty(&dev->msi_list));
-       entry = list_entry(dev->msi_list.next, struct msi_desc, list);
-       /* Return the the pci reset with msi irqs unmasked */
-       if (entry->msi_attrib.maskbit) {
-               u32 mask = entry->msi_attrib.maskbits_mask;
-               struct irq_desc *desc = irq_to_desc(dev->irq);
-               msi_set_mask_bits(desc, mask, ~mask);
-       }
-       if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI)
-               return;
+       desc = list_first_entry(&dev->msi_list, struct msi_desc, list);
+       pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &ctrl);
+       mask = msi_capable_mask(ctrl);
+       msi_mask_irq(desc, mask, ~mask);
 
        /* Restore dev->irq to its default pin-assertion irq */
-       dev->irq = entry->msi_attrib.default_irq;
+       dev->irq = desc->msi_attrib.default_irq;
 }
+
 void pci_disable_msi(struct pci_dev* dev)
 {
        struct msi_desc *entry;
@@ -640,7 +620,7 @@ void pci_disable_msi(struct pci_dev* dev)
        pci_msi_shutdown(dev);
 
        entry = list_entry(dev->msi_list.next, struct msi_desc, list);
-       if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI)
+       if (entry->msi_attrib.is_msix)
                return;
 
        msi_free_irqs(dev);
@@ -652,14 +632,18 @@ static int msi_free_irqs(struct pci_dev* dev)
        struct msi_desc *entry, *tmp;
 
        list_for_each_entry(entry, &dev->msi_list, list) {
-               if (entry->irq)
-                       BUG_ON(irq_has_action(entry->irq));
+               int i, nvec;
+               if (!entry->irq)
+                       continue;
+               nvec = 1 << entry->msi_attrib.multiple;
+               for (i = 0; i < nvec; i++)
+                       BUG_ON(irq_has_action(entry->irq + i));
        }
 
        arch_teardown_msi_irqs(dev);
 
        list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) {
-               if (entry->msi_attrib.type == PCI_CAP_ID_MSIX) {
+               if (entry->msi_attrib.is_msix) {
                        writel(1, entry->mask_base + entry->msi_attrib.entry_nr
                                  * PCI_MSIX_ENTRY_SIZE
                                  + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
@@ -674,6 +658,23 @@ static int msi_free_irqs(struct pci_dev* dev)
        return 0;
 }
 
+/**
+ * pci_msix_table_size - return the number of device's MSI-X table entries
+ * @dev: pointer to the pci_dev data structure of MSI-X device function
+ */
+int pci_msix_table_size(struct pci_dev *dev)
+{
+       int pos;
+       u16 control;
+
+       pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+       if (!pos)
+               return 0;
+
+       pci_read_config_word(dev, msi_control_reg(pos), &control);
+       return multi_msix_capable(control);
+}
+
 /**
  * pci_enable_msix - configure device's MSI-X capability structure
  * @dev: pointer to the pci_dev data structure of MSI-X device function
@@ -691,9 +692,8 @@ static int msi_free_irqs(struct pci_dev* dev)
  **/
 int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
 {
-       int status, pos, nr_entries;
+       int status, nr_entries;
        int i, j;
-       u16 control;
 
        if (!entries)
                return -EINVAL;
@@ -702,9 +702,7 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
        if (status)
                return status;
 
-       pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-       pci_read_config_word(dev, msi_control_reg(pos), &control);
-       nr_entries = multi_msix_capable(control);
+       nr_entries = pci_msix_table_size(dev);
        if (nvec > nr_entries)
                return -EINVAL;
 
index 3898f523714453a9a3f6481df2e74b56c863d157..71f4df2ef65499d84481441be24015f3b0c17398 100644 (file)
 #define msi_mask_bits_reg(base, is64bit) \
        ( (is64bit == 1) ? base+PCI_MSI_MASK_BIT : base+PCI_MSI_MASK_BIT-4)
 #define msi_disable(control)           control &= ~PCI_MSI_FLAGS_ENABLE
-#define multi_msi_capable(control) \
-       (1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1))
-#define multi_msi_enable(control, num) \
-       control |= (((num >> 1) << 4) & PCI_MSI_FLAGS_QSIZE);
 #define is_64bit_address(control)      (!!(control & PCI_MSI_FLAGS_64BIT))
 #define is_mask_bit_support(control)   (!!(control & PCI_MSI_FLAGS_MASKBIT))
-#define msi_enable(control, num) multi_msi_enable(control, num); \
-       control |= PCI_MSI_FLAGS_ENABLE
 
 #define msix_table_offset_reg(base)    (base + 0x04)
 #define msix_pba_offset_reg(base)      (base + 0x08)
index deea8a187eb86f6b81d423c2fae4e4859937764a..fac5eddcefd2a2ee1100471de5c627654cd76814 100644 (file)
 #include <linux/pci-acpi.h>
 #include "pci.h"
 
-struct acpi_osc_data {
-       acpi_handle handle;
-       u32 support_set;
-       u32 control_set;
-       u32 control_query;
-       int is_queried;
-       struct list_head sibiling;
-};
-static LIST_HEAD(acpi_osc_data_list);
-
-struct acpi_osc_args {
-       u32 capbuf[3];
-};
-
-static DEFINE_MUTEX(pci_acpi_lock);
-
-static struct acpi_osc_data *acpi_get_osc_data(acpi_handle handle)
-{
-       struct acpi_osc_data *data;
-
-       list_for_each_entry(data, &acpi_osc_data_list, sibiling) {
-               if (data->handle == handle)
-                       return data;
-       }
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data)
-               return NULL;
-       INIT_LIST_HEAD(&data->sibiling);
-       data->handle = handle;
-       list_add_tail(&data->sibiling, &acpi_osc_data_list);
-       return data;
-}
-
-static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40,
-                         0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66};
-
-static acpi_status acpi_run_osc(acpi_handle handle,
-                               struct acpi_osc_args *osc_args, u32 *retval)
-{
-       acpi_status status;
-       struct acpi_object_list input;
-       union acpi_object in_params[4];
-       struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
-       union acpi_object *out_obj;
-       u32 errors, flags = osc_args->capbuf[OSC_QUERY_TYPE];
-
-       /* Setting up input parameters */
-       input.count = 4;
-       input.pointer = in_params;
-       in_params[0].type               = ACPI_TYPE_BUFFER;
-       in_params[0].buffer.length      = 16;
-       in_params[0].buffer.pointer     = OSC_UUID;
-       in_params[1].type               = ACPI_TYPE_INTEGER;
-       in_params[1].integer.value      = 1;
-       in_params[2].type               = ACPI_TYPE_INTEGER;
-       in_params[2].integer.value      = 3;
-       in_params[3].type               = ACPI_TYPE_BUFFER;
-       in_params[3].buffer.length      = 12;
-       in_params[3].buffer.pointer     = (u8 *)osc_args->capbuf;
-
-       status = acpi_evaluate_object(handle, "_OSC", &input, &output);
-       if (ACPI_FAILURE(status))
-               return status;
-
-       if (!output.length)
-               return AE_NULL_OBJECT;
-
-       out_obj = output.pointer;
-       if (out_obj->type != ACPI_TYPE_BUFFER) {
-               printk(KERN_DEBUG "Evaluate _OSC returns wrong type\n");
-               status = AE_TYPE;
-               goto out_kfree;
-       }
-       /* Need to ignore the bit0 in result code */
-       errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
-       if (errors) {
-               if (errors & OSC_REQUEST_ERROR)
-                       printk(KERN_DEBUG "_OSC request fails\n"); 
-               if (errors & OSC_INVALID_UUID_ERROR)
-                       printk(KERN_DEBUG "_OSC invalid UUID\n"); 
-               if (errors & OSC_INVALID_REVISION_ERROR)
-                       printk(KERN_DEBUG "_OSC invalid revision\n"); 
-               if (errors & OSC_CAPABILITIES_MASK_ERROR) {
-                       if (flags & OSC_QUERY_ENABLE)
-                               goto out_success;
-                       printk(KERN_DEBUG "_OSC FW not grant req. control\n");
-                       status = AE_SUPPORT;
-                       goto out_kfree;
-               }
-               status = AE_ERROR;
-               goto out_kfree;
-       }
-out_success:
-       *retval = *((u32 *)(out_obj->buffer.pointer + 8));
-       status = AE_OK;
-
-out_kfree:
-       kfree(output.pointer);
-       return status;
-}
-
-static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data)
-{
-       acpi_status status;
-       u32 support_set, result;
-       struct acpi_osc_args osc_args;
-
-       /* do _OSC query for all possible controls */
-       support_set = osc_data->support_set | (flags & OSC_SUPPORT_MASKS);
-       osc_args.capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
-       osc_args.capbuf[OSC_SUPPORT_TYPE] = support_set;
-       osc_args.capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
-
-       status = acpi_run_osc(osc_data->handle, &osc_args, &result);
-       if (ACPI_SUCCESS(status)) {
-               osc_data->support_set = support_set;
-               osc_data->control_query = result;
-               osc_data->is_queried = 1;
-       }
-
-       return status;
-}
-
-/*
- * pci_acpi_osc_support: Invoke _OSC indicating support for the given feature
- * @flags: Bitmask of flags to support
- *
- * See the ACPI spec for the definition of the flags
- */
-int pci_acpi_osc_support(acpi_handle handle, u32 flags)
-{
-       acpi_status status;
-       acpi_handle tmp;
-       struct acpi_osc_data *osc_data;
-       int rc = 0;
-
-       status = acpi_get_handle(handle, "_OSC", &tmp);
-       if (ACPI_FAILURE(status))
-               return -ENOTTY;
-
-       mutex_lock(&pci_acpi_lock);
-       osc_data = acpi_get_osc_data(handle);
-       if (!osc_data) {
-               printk(KERN_ERR "acpi osc data array is full\n");
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       __acpi_query_osc(flags, osc_data);
-out:
-       mutex_unlock(&pci_acpi_lock);
-       return rc;
-}
-
-/**
- * pci_osc_control_set - commit requested control to Firmware
- * @handle: acpi_handle for the target ACPI object
- * @flags: driver's requested control bits
- *
- * Attempt to take control from Firmware on requested control bits.
- **/
-acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
-{
-       acpi_status status;
-       u32 control_req, control_set, result;
-       acpi_handle tmp;
-       struct acpi_osc_data *osc_data;
-       struct acpi_osc_args osc_args;
-
-       status = acpi_get_handle(handle, "_OSC", &tmp);
-       if (ACPI_FAILURE(status))
-               return status;
-
-       mutex_lock(&pci_acpi_lock);
-       osc_data = acpi_get_osc_data(handle);
-       if (!osc_data) {
-               printk(KERN_ERR "acpi osc data array is full\n");
-               status = AE_ERROR;
-               goto out;
-       }
-
-       control_req = (flags & OSC_CONTROL_MASKS);
-       if (!control_req) {
-               status = AE_TYPE;
-               goto out;
-       }
-
-       /* No need to evaluate _OSC if the control was already granted. */
-       if ((osc_data->control_set & control_req) == control_req)
-               goto out;
-
-       if (!osc_data->is_queried) {
-               status = __acpi_query_osc(osc_data->support_set, osc_data);
-               if (ACPI_FAILURE(status))
-                       goto out;
-       }
-
-       if ((osc_data->control_query & control_req) != control_req) {
-               status = AE_SUPPORT;
-               goto out;
-       }
-
-       control_set = osc_data->control_set | control_req;
-       osc_args.capbuf[OSC_QUERY_TYPE] = 0;
-       osc_args.capbuf[OSC_SUPPORT_TYPE] = osc_data->support_set;
-       osc_args.capbuf[OSC_CONTROL_TYPE] = control_set;
-       status = acpi_run_osc(handle, &osc_args, &result);
-       if (ACPI_SUCCESS(status))
-               osc_data->control_set = result;
-out:
-       mutex_unlock(&pci_acpi_lock);
-       return status;
-}
-EXPORT_SYMBOL(pci_osc_control_set);
-
 /*
  * _SxD returns the D-state with the highest power
  * (lowest D-state number) supported in the S-state "x".
index 93eac14235854c648e6e895c51f063b8af68e152..c0cbbb5a245e6167e3292e4765ff59aa06bc533b 100644 (file)
@@ -99,6 +99,52 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
 }
 static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
 
+/**
+ * store_remove_id - remove a PCI device ID from this driver
+ * @driver: target device driver
+ * @buf: buffer for scanning device ID data
+ * @count: input size
+ *
+ * Removes a dynamic pci device ID to this driver.
+ */
+static ssize_t
+store_remove_id(struct device_driver *driver, const char *buf, size_t count)
+{
+       struct pci_dynid *dynid, *n;
+       struct pci_driver *pdrv = to_pci_driver(driver);
+       __u32 vendor, device, subvendor = PCI_ANY_ID,
+               subdevice = PCI_ANY_ID, class = 0, class_mask = 0;
+       int fields = 0;
+       int retval = -ENODEV;
+
+       fields = sscanf(buf, "%x %x %x %x %x %x",
+                       &vendor, &device, &subvendor, &subdevice,
+                       &class, &class_mask);
+       if (fields < 2)
+               return -EINVAL;
+
+       spin_lock(&pdrv->dynids.lock);
+       list_for_each_entry_safe(dynid, n, &pdrv->dynids.list, node) {
+               struct pci_device_id *id = &dynid->id;
+               if ((id->vendor == vendor) &&
+                   (id->device == device) &&
+                   (subvendor == PCI_ANY_ID || id->subvendor == subvendor) &&
+                   (subdevice == PCI_ANY_ID || id->subdevice == subdevice) &&
+                   !((id->class ^ class) & class_mask)) {
+                       list_del(&dynid->node);
+                       kfree(dynid);
+                       retval = 0;
+                       break;
+               }
+       }
+       spin_unlock(&pdrv->dynids.lock);
+
+       if (retval)
+               return retval;
+       return count;
+}
+static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);
+
 static void
 pci_free_dynids(struct pci_driver *drv)
 {
@@ -125,6 +171,20 @@ static void pci_remove_newid_file(struct pci_driver *drv)
 {
        driver_remove_file(&drv->driver, &driver_attr_new_id);
 }
+
+static int
+pci_create_removeid_file(struct pci_driver *drv)
+{
+       int error = 0;
+       if (drv->probe != NULL)
+               error = driver_create_file(&drv->driver,&driver_attr_remove_id);
+       return error;
+}
+
+static void pci_remove_removeid_file(struct pci_driver *drv)
+{
+       driver_remove_file(&drv->driver, &driver_attr_remove_id);
+}
 #else /* !CONFIG_HOTPLUG */
 static inline void pci_free_dynids(struct pci_driver *drv) {}
 static inline int pci_create_newid_file(struct pci_driver *drv)
@@ -132,6 +192,11 @@ static inline int pci_create_newid_file(struct pci_driver *drv)
        return 0;
 }
 static inline void pci_remove_newid_file(struct pci_driver *drv) {}
+static inline int pci_create_removeid_file(struct pci_driver *drv)
+{
+       return 0;
+}
+static inline void pci_remove_removeid_file(struct pci_driver *drv) {}
 #endif
 
 /**
@@ -352,53 +417,60 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state)
 {
        struct pci_dev * pci_dev = to_pci_dev(dev);
        struct pci_driver * drv = pci_dev->driver;
-       int i = 0;
+
+       pci_dev->state_saved = false;
 
        if (drv && drv->suspend) {
                pci_power_t prev = pci_dev->current_state;
+               int error;
 
-               pci_dev->state_saved = false;
-
-               i = drv->suspend(pci_dev, state);
-               suspend_report_result(drv->suspend, i);
-               if (i)
-                       return i;
-
-               if (pci_dev->state_saved)
-                       goto Fixup;
+               error = drv->suspend(pci_dev, state);
+               suspend_report_result(drv->suspend, error);
+               if (error)
+                       return error;
 
-               if (pci_dev->current_state != PCI_D0
+               if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
                    && pci_dev->current_state != PCI_UNKNOWN) {
                        WARN_ONCE(pci_dev->current_state != prev,
                                "PCI PM: Device state not saved by %pF\n",
                                drv->suspend);
-                       goto Fixup;
                }
        }
 
-       pci_save_state(pci_dev);
-       /*
-        * This is for compatibility with existing code with legacy PM support.
-        */
-       pci_pm_set_unknown_state(pci_dev);
-
- Fixup:
        pci_fixup_device(pci_fixup_suspend, pci_dev);
 
-       return i;
+       return 0;
 }
 
 static int pci_legacy_suspend_late(struct device *dev, pm_message_t state)
 {
        struct pci_dev * pci_dev = to_pci_dev(dev);
        struct pci_driver * drv = pci_dev->driver;
-       int i = 0;
 
        if (drv && drv->suspend_late) {
-               i = drv->suspend_late(pci_dev, state);
-               suspend_report_result(drv->suspend_late, i);
+               pci_power_t prev = pci_dev->current_state;
+               int error;
+
+               error = drv->suspend_late(pci_dev, state);
+               suspend_report_result(drv->suspend_late, error);
+               if (error)
+                       return error;
+
+               if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
+                   && pci_dev->current_state != PCI_UNKNOWN) {
+                       WARN_ONCE(pci_dev->current_state != prev,
+                               "PCI PM: Device state not saved by %pF\n",
+                               drv->suspend_late);
+                       return 0;
+               }
        }
-       return i;
+
+       if (!pci_dev->state_saved)
+               pci_save_state(pci_dev);
+
+       pci_pm_set_unknown_state(pci_dev);
+
+       return 0;
 }
 
 static int pci_legacy_resume_early(struct device *dev)
@@ -423,6 +495,23 @@ static int pci_legacy_resume(struct device *dev)
 
 /* Auxiliary functions used by the new power management framework */
 
+/**
+ * pci_restore_standard_config - restore standard config registers of PCI device
+ * @pci_dev: PCI device to handle
+ */
+static int pci_restore_standard_config(struct pci_dev *pci_dev)
+{
+       pci_update_current_state(pci_dev, PCI_UNKNOWN);
+
+       if (pci_dev->current_state != PCI_D0) {
+               int error = pci_set_power_state(pci_dev, PCI_D0);
+               if (error)
+                       return error;
+       }
+
+       return pci_dev->state_saved ? pci_restore_state(pci_dev) : 0;
+}
+
 static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev)
 {
        pci_restore_standard_config(pci_dev);
@@ -443,7 +532,6 @@ static void pci_pm_default_suspend(struct pci_dev *pci_dev)
        /* Disable non-bridge devices without PM support */
        if (!pci_is_bridge(pci_dev))
                pci_disable_enabled_device(pci_dev);
-       pci_save_state(pci_dev);
 }
 
 static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev)
@@ -493,13 +581,13 @@ static int pci_pm_suspend(struct device *dev)
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend(dev, PMSG_SUSPEND);
 
+       pci_dev->state_saved = false;
+
        if (!pm) {
                pci_pm_default_suspend(pci_dev);
                goto Fixup;
        }
 
-       pci_dev->state_saved = false;
-
        if (pm->suspend) {
                pci_power_t prev = pci_dev->current_state;
                int error;
@@ -509,24 +597,14 @@ static int pci_pm_suspend(struct device *dev)
                if (error)
                        return error;
 
-               if (pci_dev->state_saved)
-                       goto Fixup;
-
-               if (pci_dev->current_state != PCI_D0
+               if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
                    && pci_dev->current_state != PCI_UNKNOWN) {
                        WARN_ONCE(pci_dev->current_state != prev,
                                "PCI PM: State of device not saved by %pF\n",
                                pm->suspend);
-                       goto Fixup;
                }
        }
 
-       if (!pci_dev->state_saved) {
-               pci_save_state(pci_dev);
-               if (!pci_is_bridge(pci_dev))
-                       pci_prepare_to_sleep(pci_dev);
-       }
-
  Fixup:
        pci_fixup_device(pci_fixup_suspend, pci_dev);
 
@@ -536,21 +614,43 @@ static int pci_pm_suspend(struct device *dev)
 static int pci_pm_suspend_noirq(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct device_driver *drv = dev->driver;
-       int error = 0;
+       struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend_late(dev, PMSG_SUSPEND);
 
-       if (drv && drv->pm && drv->pm->suspend_noirq) {
-               error = drv->pm->suspend_noirq(dev);
-               suspend_report_result(drv->pm->suspend_noirq, error);
+       if (!pm) {
+               pci_save_state(pci_dev);
+               return 0;
        }
 
-       if (!error)
-               pci_pm_set_unknown_state(pci_dev);
+       if (pm->suspend_noirq) {
+               pci_power_t prev = pci_dev->current_state;
+               int error;
 
-       return error;
+               error = pm->suspend_noirq(dev);
+               suspend_report_result(pm->suspend_noirq, error);
+               if (error)
+                       return error;
+
+               if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
+                   && pci_dev->current_state != PCI_UNKNOWN) {
+                       WARN_ONCE(pci_dev->current_state != prev,
+                               "PCI PM: State of device not saved by %pF\n",
+                               pm->suspend_noirq);
+                       return 0;
+               }
+       }
+
+       if (!pci_dev->state_saved) {
+               pci_save_state(pci_dev);
+               if (!pci_is_bridge(pci_dev))
+                       pci_prepare_to_sleep(pci_dev);
+       }
+
+       pci_pm_set_unknown_state(pci_dev);
+
+       return 0;
 }
 
 static int pci_pm_resume_noirq(struct device *dev)
@@ -617,13 +717,13 @@ static int pci_pm_freeze(struct device *dev)
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend(dev, PMSG_FREEZE);
 
+       pci_dev->state_saved = false;
+
        if (!pm) {
                pci_pm_default_suspend(pci_dev);
                return 0;
        }
 
-       pci_dev->state_saved = false;
-
        if (pm->freeze) {
                int error;
 
@@ -633,9 +733,6 @@ static int pci_pm_freeze(struct device *dev)
                        return error;
        }
 
-       if (!pci_dev->state_saved)
-               pci_save_state(pci_dev);
-
        return 0;
 }
 
@@ -643,20 +740,25 @@ static int pci_pm_freeze_noirq(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
        struct device_driver *drv = dev->driver;
-       int error = 0;
 
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend_late(dev, PMSG_FREEZE);
 
        if (drv && drv->pm && drv->pm->freeze_noirq) {
+               int error;
+
                error = drv->pm->freeze_noirq(dev);
                suspend_report_result(drv->pm->freeze_noirq, error);
+               if (error)
+                       return error;
        }
 
-       if (!error)
-               pci_pm_set_unknown_state(pci_dev);
+       if (!pci_dev->state_saved)
+               pci_save_state(pci_dev);
 
-       return error;
+       pci_pm_set_unknown_state(pci_dev);
+
+       return 0;
 }
 
 static int pci_pm_thaw_noirq(struct device *dev)
@@ -699,46 +801,56 @@ static int pci_pm_poweroff(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
        struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-       int error = 0;
 
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend(dev, PMSG_HIBERNATE);
 
+       pci_dev->state_saved = false;
+
        if (!pm) {
                pci_pm_default_suspend(pci_dev);
                goto Fixup;
        }
 
-       pci_dev->state_saved = false;
-
        if (pm->poweroff) {
+               int error;
+
                error = pm->poweroff(dev);
                suspend_report_result(pm->poweroff, error);
+               if (error)
+                       return error;
        }
 
-       if (!pci_dev->state_saved && !pci_is_bridge(pci_dev))
-               pci_prepare_to_sleep(pci_dev);
-
  Fixup:
        pci_fixup_device(pci_fixup_suspend, pci_dev);
 
-       return error;
+       return 0;
 }
 
 static int pci_pm_poweroff_noirq(struct device *dev)
 {
+       struct pci_dev *pci_dev = to_pci_dev(dev);
        struct device_driver *drv = dev->driver;
-       int error = 0;
 
        if (pci_has_legacy_pm_support(to_pci_dev(dev)))
                return pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
 
-       if (drv && drv->pm && drv->pm->poweroff_noirq) {
+       if (!drv || !drv->pm)
+               return 0;
+
+       if (drv->pm->poweroff_noirq) {
+               int error;
+
                error = drv->pm->poweroff_noirq(dev);
                suspend_report_result(drv->pm->poweroff_noirq, error);
+               if (error)
+                       return error;
        }
 
-       return error;
+       if (!pci_dev->state_saved && !pci_is_bridge(pci_dev))
+               pci_prepare_to_sleep(pci_dev);
+
+       return 0;
 }
 
 static int pci_pm_restore_noirq(struct device *dev)
@@ -852,13 +964,23 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
        /* register with core */
        error = driver_register(&drv->driver);
        if (error)
-               return error;
+               goto out;
 
        error = pci_create_newid_file(drv);
        if (error)
-               driver_unregister(&drv->driver);
+               goto out_newid;
 
+       error = pci_create_removeid_file(drv);
+       if (error)
+               goto out_removeid;
+out:
        return error;
+
+out_removeid:
+       pci_remove_newid_file(drv);
+out_newid:
+       driver_unregister(&drv->driver);
+       goto out;
 }
 
 /**
@@ -874,6 +996,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
 void
 pci_unregister_driver(struct pci_driver *drv)
 {
+       pci_remove_removeid_file(drv);
        pci_remove_newid_file(drv);
        driver_unregister(&drv->driver);
        pci_free_dynids(drv);
@@ -973,6 +1096,7 @@ struct bus_type pci_bus_type = {
        .remove         = pci_device_remove,
        .shutdown       = pci_device_shutdown,
        .dev_attrs      = pci_dev_attrs,
+       .bus_attrs      = pci_bus_attrs,
        .pm             = PCI_PM_OPS_PTR,
 };
 
index dfc4e0ddf241b57a93c8e94d3f81a583a772074c..e9a8706a640182de0da0257cf2d82b590245eaf5 100644 (file)
@@ -219,6 +219,83 @@ msi_bus_store(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
+#ifdef CONFIG_HOTPLUG
+static DEFINE_MUTEX(pci_remove_rescan_mutex);
+static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf,
+                               size_t count)
+{
+       unsigned long val;
+       struct pci_bus *b = NULL;
+
+       if (strict_strtoul(buf, 0, &val) < 0)
+               return -EINVAL;
+
+       if (val) {
+               mutex_lock(&pci_remove_rescan_mutex);
+               while ((b = pci_find_next_bus(b)) != NULL)
+                       pci_rescan_bus(b);
+               mutex_unlock(&pci_remove_rescan_mutex);
+       }
+       return count;
+}
+
+struct bus_attribute pci_bus_attrs[] = {
+       __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store),
+       __ATTR_NULL
+};
+
+static ssize_t
+dev_rescan_store(struct device *dev, struct device_attribute *attr,
+                const char *buf, size_t count)
+{
+       unsigned long val;
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       if (strict_strtoul(buf, 0, &val) < 0)
+               return -EINVAL;
+
+       if (val) {
+               mutex_lock(&pci_remove_rescan_mutex);
+               pci_rescan_bus(pdev->bus);
+               mutex_unlock(&pci_remove_rescan_mutex);
+       }
+       return count;
+}
+
+static void remove_callback(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       mutex_lock(&pci_remove_rescan_mutex);
+       pci_remove_bus_device(pdev);
+       mutex_unlock(&pci_remove_rescan_mutex);
+}
+
+static ssize_t
+remove_store(struct device *dev, struct device_attribute *dummy,
+            const char *buf, size_t count)
+{
+       int ret = 0;
+       unsigned long val;
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       if (strict_strtoul(buf, 0, &val) < 0)
+               return -EINVAL;
+
+       if (pci_is_root_bus(pdev->bus))
+               return -EBUSY;
+
+       /* An attribute cannot be unregistered by one of its own methods,
+        * so we have to use this roundabout approach.
+        */
+       if (val)
+               ret = device_schedule_callback(dev, remove_callback);
+       if (ret)
+               count = ret;
+       return count;
+}
+#endif
+
 struct device_attribute pci_dev_attrs[] = {
        __ATTR_RO(resource),
        __ATTR_RO(vendor),
@@ -237,9 +314,24 @@ struct device_attribute pci_dev_attrs[] = {
        __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
                broken_parity_status_show,broken_parity_status_store),
        __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store),
+#ifdef CONFIG_HOTPLUG
+       __ATTR(remove, (S_IWUSR|S_IWGRP), NULL, remove_store),
+       __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_rescan_store),
+#endif
        __ATTR_NULL,
 };
 
+static ssize_t
+boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       return sprintf(buf, "%u\n",
+               !!(pdev->resource[PCI_ROM_RESOURCE].flags &
+                  IORESOURCE_ROM_SHADOW));
+}
+struct device_attribute vga_attr = __ATTR_RO(boot_vga);
+
 static ssize_t
 pci_read_config(struct kobject *kobj, struct bin_attribute *bin_attr,
                char *buf, loff_t off, size_t count)
@@ -492,6 +584,19 @@ pci_mmap_legacy_io(struct kobject *kobj, struct bin_attribute *attr,
         return pci_mmap_legacy_page_range(bus, vma, pci_mmap_io);
 }
 
+/**
+ * pci_adjust_legacy_attr - adjustment of legacy file attributes
+ * @b: bus to create files under
+ * @mmap_type: I/O port or memory
+ *
+ * Stub implementation. Can be overridden by arch if necessary.
+ */
+void __weak
+pci_adjust_legacy_attr(struct pci_bus *b, enum pci_mmap_state mmap_type)
+{
+       return;
+}
+
 /**
  * pci_create_legacy_files - create legacy I/O port and memory files
  * @b: bus to create files under
@@ -518,6 +623,7 @@ void pci_create_legacy_files(struct pci_bus *b)
        b->legacy_io->read = pci_read_legacy_io;
        b->legacy_io->write = pci_write_legacy_io;
        b->legacy_io->mmap = pci_mmap_legacy_io;
+       pci_adjust_legacy_attr(b, pci_mmap_io);
        error = device_create_bin_file(&b->dev, b->legacy_io);
        if (error)
                goto legacy_io_err;
@@ -528,6 +634,7 @@ void pci_create_legacy_files(struct pci_bus *b)
        b->legacy_mem->size = 1024*1024;
        b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
        b->legacy_mem->mmap = pci_mmap_legacy_mem;
+       pci_adjust_legacy_attr(b, pci_mmap_mem);
        error = device_create_bin_file(&b->dev, b->legacy_mem);
        if (error)
                goto legacy_mem_err;
@@ -719,8 +826,8 @@ static int pci_create_resource_files(struct pci_dev *pdev)
        return 0;
 }
 #else /* !HAVE_PCI_MMAP */
-static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; }
-static inline void pci_remove_resource_files(struct pci_dev *dev) { return; }
+int __weak pci_create_resource_files(struct pci_dev *dev) { return 0; }
+void __weak pci_remove_resource_files(struct pci_dev *dev) { return; }
 #endif /* HAVE_PCI_MMAP */
 
 /**
@@ -884,18 +991,27 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
                pdev->rom_attr = attr;
        }
 
+       if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
+               retval = device_create_file(&pdev->dev, &vga_attr);
+               if (retval)
+                       goto err_rom_file;
+       }
+
        /* add platform-specific attributes */
        retval = pcibios_add_platform_entries(pdev);
        if (retval)
-               goto err_rom_file;
+               goto err_vga_file;
 
        /* add sysfs entries for various capabilities */
        retval = pci_create_capabilities_sysfs(pdev);
        if (retval)
-               goto err_rom_file;
+               goto err_vga_file;
 
        return 0;
 
+err_vga_file:
+       if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+               device_remove_file(&pdev->dev, &vga_attr);
 err_rom_file:
        if (rom_size) {
                sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
index 6d6120007af4ed01d5fdc39331bff59349b1ed00..fe7ac2cea7c971a9737b5babdbc58b97338f60b7 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/pm_wakeup.h>
 #include <linux/interrupt.h>
 #include <asm/dma.h>   /* isa_dma_bridge_buggy */
+#include <linux/device.h>
+#include <asm/setup.h>
 #include "pci.h"
 
 unsigned int pci_pm_d3_delay = PCI_PM_D3_WAIT;
@@ -426,7 +428,6 @@ static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable)
  *                           given PCI device
  * @dev: PCI device to handle.
  * @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
- * @wait: If 'true', wait for the device to change its power state
  *
  * RETURN VALUE:
  * -EINVAL if the requested state is invalid.
@@ -435,12 +436,15 @@ static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable)
  * 0 if device already is in the requested state.
  * 0 if device's power state has been successfully changed.
  */
-static int
-pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait)
+static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
 {
        u16 pmcsr;
        bool need_restore = false;
 
+       /* Check if we're already there */
+       if (dev->current_state == state)
+               return 0;
+
        if (!dev->pm_cap)
                return -EIO;
 
@@ -451,10 +455,7 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait)
         * Can enter D0 from any state, but if we can only go deeper 
         * to sleep if we're already in a low power state
         */
-       if (dev->current_state == state) {
-               /* we're already there */
-               return 0;
-       } else if (state != PCI_D0 && dev->current_state <= PCI_D3cold
+       if (state != PCI_D0 && dev->current_state <= PCI_D3cold
            && dev->current_state > state) {
                dev_err(&dev->dev, "invalid power transition "
                        "(from state %d to %d)\n", dev->current_state, state);
@@ -481,10 +482,8 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait)
                break;
        case PCI_UNKNOWN: /* Boot-up */
                if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot
-                && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) {
+                && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET))
                        need_restore = true;
-                       wait = true;
-               }
                /* Fall-through: force to D0 */
        default:
                pmcsr = 0;
@@ -494,9 +493,6 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait)
        /* enter specified state */
        pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
 
-       if (!wait)
-               return 0;
-
        /* Mandatory power management transition delays */
        /* see PCI PM 1.1 5.6.1 table 18 */
        if (state == PCI_D3hot || dev->current_state == PCI_D3hot)
@@ -521,7 +517,7 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait)
        if (need_restore)
                pci_restore_bars(dev);
 
-       if (wait && dev->bus->self)
+       if (dev->bus->self)
                pcie_aspm_pm_state_change(dev->bus->self);
 
        return 0;
@@ -545,6 +541,53 @@ void pci_update_current_state(struct pci_dev *dev, pci_power_t state)
        }
 }
 
+/**
+ * pci_platform_power_transition - Use platform to change device power state
+ * @dev: PCI device to handle.
+ * @state: State to put the device into.
+ */
+static int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state)
+{
+       int error;
+
+       if (platform_pci_power_manageable(dev)) {
+               error = platform_pci_set_power_state(dev, state);
+               if (!error)
+                       pci_update_current_state(dev, state);
+       } else {
+               error = -ENODEV;
+               /* Fall back to PCI_D0 if native PM is not supported */
+               pci_update_current_state(dev, PCI_D0);
+       }
+
+       return error;
+}
+
+/**
+ * __pci_start_power_transition - Start power transition of a PCI device
+ * @dev: PCI device to handle.
+ * @state: State to put the device into.
+ */
+static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state)
+{
+       if (state == PCI_D0)
+               pci_platform_power_transition(dev, PCI_D0);
+}
+
+/**
+ * __pci_complete_power_transition - Complete power transition of a PCI device
+ * @dev: PCI device to handle.
+ * @state: State to put the device into.
+ *
+ * This function should not be called directly by device drivers.
+ */
+int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state)
+{
+       return state > PCI_D0 ?
+                       pci_platform_power_transition(dev, state) : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(__pci_complete_power_transition);
+
 /**
  * pci_set_power_state - Set the power state of a PCI device
  * @dev: PCI device to handle.
@@ -577,30 +620,21 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
                 */
                return 0;
 
-       if (state == PCI_D0 && platform_pci_power_manageable(dev)) {
-               /*
-                * Allow the platform to change the state, for example via ACPI
-                * _PR0, _PS0 and some such, but do not trust it.
-                */
-               int ret = platform_pci_set_power_state(dev, PCI_D0);
-               if (!ret)
-                       pci_update_current_state(dev, PCI_D0);
-       }
+       /* Check if we're already there */
+       if (dev->current_state == state)
+               return 0;
+
+       __pci_start_power_transition(dev, state);
+
        /* This device is quirked not to be put into D3, so
           don't put it in D3 */
        if (state == PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3))
                return 0;
 
-       error = pci_raw_set_power_state(dev, state, true);
+       error = pci_raw_set_power_state(dev, state);
 
-       if (state > PCI_D0 && platform_pci_power_manageable(dev)) {
-               /* Allow the platform to finalize the transition */
-               int ret = platform_pci_set_power_state(dev, state);
-               if (!ret) {
-                       pci_update_current_state(dev, state);
-                       error = 0;
-               }
-       }
+       if (!__pci_complete_power_transition(dev, state))
+               error = 0;
 
        return error;
 }
@@ -645,6 +679,8 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
 
 EXPORT_SYMBOL(pci_choose_state);
 
+#define PCI_EXP_SAVE_REGS      7
+
 static int pci_save_pcie_state(struct pci_dev *dev)
 {
        int pos, i = 0;
@@ -657,7 +693,7 @@ static int pci_save_pcie_state(struct pci_dev *dev)
 
        save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
        if (!save_state) {
-               dev_err(&dev->dev, "buffer not found in %s\n", __FUNCTION__);
+               dev_err(&dev->dev, "buffer not found in %s\n", __func__);
                return -ENOMEM;
        }
        cap = (u16 *)&save_state->data[0];
@@ -666,6 +702,9 @@ static int pci_save_pcie_state(struct pci_dev *dev)
        pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]);
        pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]);
        pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]);
+       pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &cap[i++]);
+       pci_read_config_word(dev, pos + PCI_EXP_LNKCTL2, &cap[i++]);
+       pci_read_config_word(dev, pos + PCI_EXP_SLTCTL2, &cap[i++]);
 
        return 0;
 }
@@ -686,6 +725,9 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
        pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, cap[i++]);
        pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]);
        pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]);
+       pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, cap[i++]);
+       pci_write_config_word(dev, pos + PCI_EXP_LNKCTL2, cap[i++]);
+       pci_write_config_word(dev, pos + PCI_EXP_SLTCTL2, cap[i++]);
 }
 
 
@@ -700,7 +742,7 @@ static int pci_save_pcix_state(struct pci_dev *dev)
 
        save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
        if (!save_state) {
-               dev_err(&dev->dev, "buffer not found in %s\n", __FUNCTION__);
+               dev_err(&dev->dev, "buffer not found in %s\n", __func__);
                return -ENOMEM;
        }
 
@@ -773,6 +815,7 @@ pci_restore_state(struct pci_dev *dev)
        }
        pci_restore_pcix_state(dev);
        pci_restore_msi_state(dev);
+       pci_restore_iov_state(dev);
 
        return 0;
 }
@@ -1231,7 +1274,7 @@ int pci_prepare_to_sleep(struct pci_dev *dev)
        if (target_state == PCI_POWER_ERROR)
                return -EIO;
 
-       pci_enable_wake(dev, target_state, true);
+       pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev));
 
        error = pci_set_power_state(dev, target_state);
 
@@ -1369,7 +1412,8 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
 {
        int error;
 
-       error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_EXP, 4 * sizeof(u16));
+       error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_EXP,
+                                       PCI_EXP_SAVE_REGS * sizeof(u16));
        if (error)
                dev_err(&dev->dev,
                        "unable to preallocate PCI Express save buffer\n");
@@ -1380,50 +1424,6 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
                        "unable to preallocate PCI-X save buffer\n");
 }
 
-/**
- * pci_restore_standard_config - restore standard config registers of PCI device
- * @dev: PCI device to handle
- *
- * This function assumes that the device's configuration space is accessible.
- * If the device needs to be powered up, the function will wait for it to
- * change the state.
- */
-int pci_restore_standard_config(struct pci_dev *dev)
-{
-       pci_power_t prev_state;
-       int error;
-
-       pci_update_current_state(dev, PCI_D0);
-
-       prev_state = dev->current_state;
-       if (prev_state == PCI_D0)
-               goto Restore;
-
-       error = pci_raw_set_power_state(dev, PCI_D0, false);
-       if (error)
-               return error;
-
-       /*
-        * This assumes that we won't get a bus in B2 or B3 from the BIOS, but
-        * we've made this assumption forever and it appears to be universally
-        * satisfied.
-        */
-       switch(prev_state) {
-       case PCI_D3cold:
-       case PCI_D3hot:
-               mdelay(pci_pm_d3_delay);
-               break;
-       case PCI_D2:
-               udelay(PCI_PM_D2_DELAY);
-               break;
-       }
-
-       pci_update_current_state(dev, PCI_D0);
-
- Restore:
-       return dev->state_saved ? pci_restore_state(dev) : 0;
-}
-
 /**
  * pci_enable_ari - enable ARI forwarding if hardware support it
  * @dev: the PCI device
@@ -1484,7 +1484,7 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
        if (!pin)
                return -1;
 
-       while (dev->bus->self) {
+       while (dev->bus->parent) {
                pin = pci_swizzle_interrupt_pin(dev, pin);
                dev = dev->bus->self;
        }
@@ -1504,7 +1504,7 @@ u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp)
 {
        u8 pin = *pinp;
 
-       while (dev->bus->self) {
+       while (dev->bus->parent) {
                pin = pci_swizzle_interrupt_pin(dev, pin);
                dev = dev->bus->self;
        }
@@ -2028,18 +2028,24 @@ static int __pcie_flr(struct pci_dev *dev, int probe)
        pci_block_user_cfg_access(dev);
 
        /* Wait for Transaction Pending bit clean */
+       pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status);
+       if (!(status & PCI_EXP_DEVSTA_TRPND))
+               goto transaction_done;
+
        msleep(100);
        pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status);
-       if (status & PCI_EXP_DEVSTA_TRPND) {
-               dev_info(&dev->dev, "Busy after 100ms while trying to reset; "
+       if (!(status & PCI_EXP_DEVSTA_TRPND))
+               goto transaction_done;
+
+       dev_info(&dev->dev, "Busy after 100ms while trying to reset; "
                        "sleeping for 1 second\n");
-               ssleep(1);
-               pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status);
-               if (status & PCI_EXP_DEVSTA_TRPND)
-                       dev_info(&dev->dev, "Still busy after 1s; "
+       ssleep(1);
+       pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status);
+       if (status & PCI_EXP_DEVSTA_TRPND)
+               dev_info(&dev->dev, "Still busy after 1s; "
                                "proceeding with reset anyway\n");
-       }
 
+transaction_done:
        pci_write_config_word(dev, exppos + PCI_EXP_DEVCTL,
                                PCI_EXP_DEVCTL_BCR_FLR);
        mdelay(100);
@@ -2066,18 +2072,24 @@ static int __pci_af_flr(struct pci_dev *dev, int probe)
        pci_block_user_cfg_access(dev);
 
        /* Wait for Transaction Pending bit clean */
+       pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status);
+       if (!(status & PCI_AF_STATUS_TP))
+               goto transaction_done;
+
        msleep(100);
        pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status);
-       if (status & PCI_AF_STATUS_TP) {
-               dev_info(&dev->dev, "Busy after 100ms while trying to"
-                               " reset; sleeping for 1 second\n");
-               ssleep(1);
-               pci_read_config_byte(dev,
-                               cappos + PCI_AF_STATUS, &status);
-               if (status & PCI_AF_STATUS_TP)
-                       dev_info(&dev->dev, "Still busy after 1s; "
-                                       "proceeding with reset anyway\n");
-       }
+       if (!(status & PCI_AF_STATUS_TP))
+               goto transaction_done;
+
+       dev_info(&dev->dev, "Busy after 100ms while trying to"
+                       " reset; sleeping for 1 second\n");
+       ssleep(1);
+       pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status);
+       if (status & PCI_AF_STATUS_TP)
+               dev_info(&dev->dev, "Still busy after 1s; "
+                               "proceeding with reset anyway\n");
+
+transaction_done:
        pci_write_config_byte(dev, cappos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
        mdelay(100);
 
@@ -2346,18 +2358,140 @@ int pci_select_bars(struct pci_dev *dev, unsigned long flags)
  */
 int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type)
 {
+       int reg;
+
        if (resno < PCI_ROM_RESOURCE) {
                *type = pci_bar_unknown;
                return PCI_BASE_ADDRESS_0 + 4 * resno;
        } else if (resno == PCI_ROM_RESOURCE) {
                *type = pci_bar_mem32;
                return dev->rom_base_reg;
+       } else if (resno < PCI_BRIDGE_RESOURCES) {
+               /* device specific resource */
+               reg = pci_iov_resource_bar(dev, resno, type);
+               if (reg)
+                       return reg;
        }
 
        dev_err(&dev->dev, "BAR: invalid resource #%d\n", resno);
        return 0;
 }
 
+#define RESOURCE_ALIGNMENT_PARAM_SIZE COMMAND_LINE_SIZE
+static char resource_alignment_param[RESOURCE_ALIGNMENT_PARAM_SIZE] = {0};
+spinlock_t resource_alignment_lock = SPIN_LOCK_UNLOCKED;
+
+/**
+ * pci_specified_resource_alignment - get resource alignment specified by user.
+ * @dev: the PCI device to get
+ *
+ * RETURNS: Resource alignment if it is specified.
+ *          Zero if it is not specified.
+ */
+resource_size_t pci_specified_resource_alignment(struct pci_dev *dev)
+{
+       int seg, bus, slot, func, align_order, count;
+       resource_size_t align = 0;
+       char *p;
+
+       spin_lock(&resource_alignment_lock);
+       p = resource_alignment_param;
+       while (*p) {
+               count = 0;
+               if (sscanf(p, "%d%n", &align_order, &count) == 1 &&
+                                                       p[count] == '@') {
+                       p += count + 1;
+               } else {
+                       align_order = -1;
+               }
+               if (sscanf(p, "%x:%x:%x.%x%n",
+                       &seg, &bus, &slot, &func, &count) != 4) {
+                       seg = 0;
+                       if (sscanf(p, "%x:%x.%x%n",
+                                       &bus, &slot, &func, &count) != 3) {
+                               /* Invalid format */
+                               printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: %s\n",
+                                       p);
+                               break;
+                       }
+               }
+               p += count;
+               if (seg == pci_domain_nr(dev->bus) &&
+                       bus == dev->bus->number &&
+                       slot == PCI_SLOT(dev->devfn) &&
+                       func == PCI_FUNC(dev->devfn)) {
+                       if (align_order == -1) {
+                               align = PAGE_SIZE;
+                       } else {
+                               align = 1 << align_order;
+                       }
+                       /* Found */
+                       break;
+               }
+               if (*p != ';' && *p != ',') {
+                       /* End of param or invalid format */
+                       break;
+               }
+               p++;
+       }
+       spin_unlock(&resource_alignment_lock);
+       return align;
+}
+
+/**
+ * pci_is_reassigndev - check if specified PCI is target device to reassign
+ * @dev: the PCI device to check
+ *
+ * RETURNS: non-zero for PCI device is a target device to reassign,
+ *          or zero is not.
+ */
+int pci_is_reassigndev(struct pci_dev *dev)
+{
+       return (pci_specified_resource_alignment(dev) != 0);
+}
+
+ssize_t pci_set_resource_alignment_param(const char *buf, size_t count)
+{
+       if (count > RESOURCE_ALIGNMENT_PARAM_SIZE - 1)
+               count = RESOURCE_ALIGNMENT_PARAM_SIZE - 1;
+       spin_lock(&resource_alignment_lock);
+       strncpy(resource_alignment_param, buf, count);
+       resource_alignment_param[count] = '\0';
+       spin_unlock(&resource_alignment_lock);
+       return count;
+}
+
+ssize_t pci_get_resource_alignment_param(char *buf, size_t size)
+{
+       size_t count;
+       spin_lock(&resource_alignment_lock);
+       count = snprintf(buf, size, "%s", resource_alignment_param);
+       spin_unlock(&resource_alignment_lock);
+       return count;
+}
+
+static ssize_t pci_resource_alignment_show(struct bus_type *bus, char *buf)
+{
+       return pci_get_resource_alignment_param(buf, PAGE_SIZE);
+}
+
+static ssize_t pci_resource_alignment_store(struct bus_type *bus,
+                                       const char *buf, size_t count)
+{
+       return pci_set_resource_alignment_param(buf, count);
+}
+
+BUS_ATTR(resource_alignment, 0644, pci_resource_alignment_show,
+                                       pci_resource_alignment_store);
+
+static int __init pci_resource_alignment_sysfs_init(void)
+{
+       return bus_create_file(&pci_bus_type,
+                                       &bus_attr_resource_alignment);
+}
+
+late_initcall(pci_resource_alignment_sysfs_init);
+
 static void __devinit pci_no_domains(void)
 {
 #ifdef CONFIG_PCI_DOMAINS
@@ -2406,6 +2540,9 @@ static int __init pci_setup(char *str)
                                pci_cardbus_io_size = memparse(str + 9, &str);
                        } else if (!strncmp(str, "cbmemsize=", 10)) {
                                pci_cardbus_mem_size = memparse(str + 10, &str);
+                       } else if (!strncmp(str, "resource_alignment=", 19)) {
+                               pci_set_resource_alignment_param(str + 19,
+                                                       strlen(str + 19));
                        } else {
                                printk(KERN_ERR "PCI: Unknown option `%s'\n",
                                                str);
index 07c0aa5275e6edf33ab1914761d6acb3113f1741..d03f6b99f292cbe36e619ad1c599aadd75bb39dd 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef DRIVERS_PCI_H
 #define DRIVERS_PCI_H
 
+#include <linux/workqueue.h>
+
 #define PCI_CFG_SPACE_SIZE     256
 #define PCI_CFG_SPACE_EXP_SIZE 4096
 
@@ -49,7 +51,6 @@ extern void pci_disable_enabled_device(struct pci_dev *dev);
 extern void pci_pm_init(struct pci_dev *dev);
 extern void platform_pci_wakeup_init(struct pci_dev *dev);
 extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
-extern int pci_restore_standard_config(struct pci_dev *dev);
 
 static inline bool pci_is_bridge(struct pci_dev *pci_dev)
 {
@@ -136,6 +137,12 @@ extern int pcie_mch_quirk;
 extern struct device_attribute pci_dev_attrs[];
 extern struct device_attribute dev_attr_cpuaffinity;
 extern struct device_attribute dev_attr_cpulistaffinity;
+#ifdef CONFIG_HOTPLUG
+extern struct bus_attribute pci_bus_attrs[];
+#else
+#define pci_bus_attrs  NULL
+#endif
+
 
 /**
  * pci_match_one_device - Tell if a PCI device structure has a matching
@@ -178,6 +185,7 @@ enum pci_bar_type {
        pci_bar_mem64,          /* A 64-bit memory BAR */
 };
 
+extern int pci_setup_device(struct pci_dev *dev);
 extern int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                                struct resource *res, unsigned int reg);
 extern int pci_resource_bar(struct pci_dev *dev, int resno,
@@ -195,4 +203,60 @@ static inline int pci_ari_enabled(struct pci_bus *bus)
        return bus->self && bus->self->ari_enabled;
 }
 
+#ifdef CONFIG_PCI_QUIRKS
+extern int pci_is_reassigndev(struct pci_dev *dev);
+resource_size_t pci_specified_resource_alignment(struct pci_dev *dev);
+extern void pci_disable_bridge_window(struct pci_dev *dev);
+#endif
+
+/* Single Root I/O Virtualization */
+struct pci_sriov {
+       int pos;                /* capability position */
+       int nres;               /* number of resources */
+       u32 cap;                /* SR-IOV Capabilities */
+       u16 ctrl;               /* SR-IOV Control */
+       u16 total;              /* total VFs associated with the PF */
+       u16 initial;            /* initial VFs associated with the PF */
+       u16 nr_virtfn;          /* number of VFs available */
+       u16 offset;             /* first VF Routing ID offset */
+       u16 stride;             /* following VF stride */
+       u32 pgsz;               /* page size for BAR alignment */
+       u8 link;                /* Function Dependency Link */
+       struct pci_dev *dev;    /* lowest numbered PF */
+       struct pci_dev *self;   /* this PF */
+       struct mutex lock;      /* lock for VF bus */
+       struct work_struct mtask; /* VF Migration task */
+       u8 __iomem *mstate;     /* VF Migration State Array */
+};
+
+#ifdef CONFIG_PCI_IOV
+extern int pci_iov_init(struct pci_dev *dev);
+extern void pci_iov_release(struct pci_dev *dev);
+extern int pci_iov_resource_bar(struct pci_dev *dev, int resno,
+                               enum pci_bar_type *type);
+extern void pci_restore_iov_state(struct pci_dev *dev);
+extern int pci_iov_bus_range(struct pci_bus *bus);
+#else
+static inline int pci_iov_init(struct pci_dev *dev)
+{
+       return -ENODEV;
+}
+static inline void pci_iov_release(struct pci_dev *dev)
+
+{
+}
+static inline int pci_iov_resource_bar(struct pci_dev *dev, int resno,
+                                      enum pci_bar_type *type)
+{
+       return 0;
+}
+static inline void pci_restore_iov_state(struct pci_dev *dev)
+{
+}
+static inline int pci_iov_bus_range(struct pci_bus *bus)
+{
+       return 0;
+}
+#endif /* CONFIG_PCI_IOV */
+
 #endif /* DRIVERS_PCI_H */
index e390707661dde323e8beafc4bf96e651a843dd06..32ade5af927e21c11e008be87ae7380c64a1932a 100644 (file)
@@ -38,30 +38,13 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-static int __devinit aer_probe (struct pcie_device *dev,
-       const struct pcie_port_service_id *id );
+static int __devinit aer_probe (struct pcie_device *dev);
 static void aer_remove(struct pcie_device *dev);
-static int aer_suspend(struct pcie_device *dev, pm_message_t state)
-{return 0;}
-static int aer_resume(struct pcie_device *dev) {return 0;}
 static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
        enum pci_channel_state error);
 static void aer_error_resume(struct pci_dev *dev);
 static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
 
-/*
- * PCI Express bus's AER Root service driver data structure
- */
-static struct pcie_port_service_id aer_id[] = {
-       {
-       .vendor         = PCI_ANY_ID,
-       .device         = PCI_ANY_ID,
-       .port_type      = PCIE_RC_PORT,
-       .service_type   = PCIE_PORT_SERVICE_AER,
-       },
-       { /* end: all zeroes */ }
-};
-
 static struct pci_error_handlers aer_error_handlers = {
        .error_detected = aer_error_detected,
        .resume = aer_error_resume,
@@ -69,14 +52,12 @@ static struct pci_error_handlers aer_error_handlers = {
 
 static struct pcie_port_service_driver aerdriver = {
        .name           = "aer",
-       .id_table       = &aer_id[0],
+       .port_type      = PCIE_ANY_PORT,
+       .service        = PCIE_PORT_SERVICE_AER,
 
        .probe          = aer_probe,
        .remove         = aer_remove,
 
-       .suspend        = aer_suspend,
-       .resume         = aer_resume,
-
        .err_handler    = &aer_error_handlers,
 
        .reset_link     = aer_root_reset,
@@ -207,8 +188,7 @@ static void aer_remove(struct pcie_device *dev)
  *
  * Invoked when PCI Express bus loads AER service driver.
  **/
-static int __devinit aer_probe (struct pcie_device *dev,
-                               const struct pcie_port_service_id *id )
+static int __devinit aer_probe (struct pcie_device *dev)
 {
        int status;
        struct aer_rpc *rpc;
index ebce26c37049ad5ccc0483da56d3df682f865414..8edb2f300e8f85cc91c31ad8f6c208b6363cb118 100644 (file)
@@ -38,7 +38,7 @@ int aer_osc_setup(struct pcie_device *pciedev)
 
        handle = acpi_find_root_bridge_handle(pdev);
        if (handle) {
-               status = pci_osc_control_set(handle,
+               status = acpi_pci_osc_control_set(handle,
                                        OSC_PCI_EXPRESS_AER_CONTROL |
                                        OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
        }
index 38257500738223486758e337cb49d7184ddcef5a..307452f30035562cea6f290fb0fa1bac34679893 100644 (file)
@@ -351,21 +351,21 @@ static int find_aer_service_iter(struct device *device, void *data)
 {
        struct device_driver *driver;
        struct pcie_port_service_driver *service_driver;
-       struct pcie_device *pcie_dev;
        struct find_aer_service_data *result;
 
        result = (struct find_aer_service_data *) data;
 
        if (device->bus == &pcie_port_bus_type) {
-               pcie_dev = to_pcie_device(device);
-               if (pcie_dev->id.port_type == PCIE_SW_DOWNSTREAM_PORT)
+               struct pcie_port_data *port_data;
+
+               port_data = pci_get_drvdata(to_pcie_device(device)->port);
+               if (port_data->port_type == PCIE_SW_DOWNSTREAM_PORT)
                        result->is_downstream = 1;
 
                driver = device->driver;
                if (driver) {
                        service_driver = to_service_driver(driver);
-                       if (service_driver->id_table->service_type ==
-                                       PCIE_PORT_SERVICE_AER) {
+                       if (service_driver->service == PCIE_PORT_SERVICE_AER) {
                                result->aer_driver = service_driver;
                                return 1;
                        }
index 2529f3f2ea5a246ad3134307eb0e50d4c73d00a6..17ad53868f9f1566b0628061a4359cb15d1ae472 100644 (file)
 #define PCIE_CAPABILITIES_REG          0x2
 #define PCIE_SLOT_CAPABILITIES_REG     0x14
 #define PCIE_PORT_DEVICE_MAXSERVICES   4
+#define PCIE_PORT_MSI_VECTOR_MASK      0x1f
+/*
+ * According to the PCI Express Base Specification 2.0, the indices of the MSI-X
+ * table entires used by port services must not exceed 31
+ */
+#define PCIE_PORT_MAX_MSIX_ENTRIES     32
 
 #define get_descriptor_id(type, service) (((type - 4) << 4) | service)
 
-struct pcie_port_device_ext {
-       int interrupt_mode;     /* [0:INTx | 1:MSI | 2:MSI-X] */
-};
-
 extern struct bus_type pcie_port_bus_type;
 extern int pcie_port_device_probe(struct pci_dev *dev);
 extern int pcie_port_device_register(struct pci_dev *dev);
 #ifdef CONFIG_PM
-extern int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state);
-extern int pcie_port_device_resume(struct pci_dev *dev);
+extern int pcie_port_device_suspend(struct device *dev);
+extern int pcie_port_device_resume(struct device *dev);
 #endif
 extern void pcie_port_device_remove(struct pci_dev *dev);
 extern int __must_check pcie_port_bus_register(void);
index eec89b767f9f828d3389ef2584ad5fd103388869..ef3a4eeaebb45077005f4948b458e3b241ba1f38 100644 (file)
@@ -26,20 +26,22 @@ EXPORT_SYMBOL_GPL(pcie_port_bus_type);
 static int pcie_port_bus_match(struct device *dev, struct device_driver *drv)
 {
        struct pcie_device *pciedev;
+       struct pcie_port_data *port_data;
        struct pcie_port_service_driver *driver;
 
        if (drv->bus != &pcie_port_bus_type || dev->bus != &pcie_port_bus_type)
                return 0;
-       
+
        pciedev = to_pcie_device(dev);
        driver = to_service_driver(drv);
-       if (   (driver->id_table->vendor != PCI_ANY_ID && 
-               driver->id_table->vendor != pciedev->id.vendor) ||
-              (driver->id_table->device != PCI_ANY_ID &&
-               driver->id_table->device != pciedev->id.device) ||      
-              (driver->id_table->port_type != PCIE_ANY_PORT &&
-               driver->id_table->port_type != pciedev->id.port_type) ||
-               driver->id_table->service_type != pciedev->id.service_type )
+
+       if (driver->service != pciedev->service)
+               return 0;
+
+       port_data = pci_get_drvdata(pciedev->port);
+
+       if (driver->port_type != PCIE_ANY_PORT
+            && driver->port_type != port_data->port_type)
                return 0;
 
        return 1;
index 8b3f8c18032f3a295c5af3ab7ab09ca0e11b2fc4..e39982503863e4a1539d4f1f968a9dbf47bc3242 100644 (file)
 #include <linux/slab.h>
 #include <linux/pcieport_if.h>
 
+#include "../pci.h"
 #include "portdrv.h"
 
-extern int pcie_mch_quirk;     /* MSI-quirk Indicator */
-
 /**
  * release_pcie_device - free PCI Express port service device structure
  * @dev: Port service device to release
@@ -31,26 +30,150 @@ static void release_pcie_device(struct device *dev)
        kfree(to_pcie_device(dev));                     
 }
 
-static int is_msi_quirked(struct pci_dev *dev)
+/**
+ * pcie_port_msix_add_entry - add entry to given array of MSI-X entries
+ * @entries: Array of MSI-X entries
+ * @new_entry: Index of the entry to add to the array
+ * @nr_entries: Number of entries aleady in the array
+ *
+ * Return value: Position of the added entry in the array
+ */
+static int pcie_port_msix_add_entry(
+       struct msix_entry *entries, int new_entry, int nr_entries)
 {
-       int port_type, quirk = 0;
+       int j;
+
+       for (j = 0; j < nr_entries; j++)
+               if (entries[j].entry == new_entry)
+                       return j;
+
+       entries[j].entry = new_entry;
+       return j;
+}
+
+/**
+ * pcie_port_enable_msix - try to set up MSI-X as interrupt mode for given port
+ * @dev: PCI Express port to handle
+ * @vectors: Array of interrupt vectors to populate
+ * @mask: Bitmask of port capabilities returned by get_port_device_capability()
+ *
+ * Return value: 0 on success, error code on failure
+ */
+static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask)
+{
+       struct msix_entry *msix_entries;
+       int idx[PCIE_PORT_DEVICE_MAXSERVICES];
+       int nr_entries, status, pos, i, nvec;
        u16 reg16;
+       u32 reg32;
 
-       pci_read_config_word(dev, 
-               pci_find_capability(dev, PCI_CAP_ID_EXP) + 
-               PCIE_CAPABILITIES_REG, &reg16);
-       port_type = (reg16 >> 4) & PORT_TYPE_MASK;
-       switch(port_type) {
-       case PCIE_RC_PORT:
-               if (pcie_mch_quirk == 1)
-                       quirk = 1;
-               break;
-       case PCIE_SW_UPSTREAM_PORT:
-       case PCIE_SW_DOWNSTREAM_PORT:
-       default:
-               break;  
+       nr_entries = pci_msix_table_size(dev);
+       if (!nr_entries)
+               return -EINVAL;
+       if (nr_entries > PCIE_PORT_MAX_MSIX_ENTRIES)
+               nr_entries = PCIE_PORT_MAX_MSIX_ENTRIES;
+
+       msix_entries = kzalloc(sizeof(*msix_entries) * nr_entries, GFP_KERNEL);
+       if (!msix_entries)
+               return -ENOMEM;
+
+       /*
+        * Allocate as many entries as the port wants, so that we can check
+        * which of them will be useful.  Moreover, if nr_entries is correctly
+        * equal to the number of entries this port actually uses, we'll happily
+        * go through without any tricks.
+        */
+       for (i = 0; i < nr_entries; i++)
+               msix_entries[i].entry = i;
+
+       status = pci_enable_msix(dev, msix_entries, nr_entries);
+       if (status)
+               goto Exit;
+
+       for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
+               idx[i] = -1;
+       status = -EIO;
+       nvec = 0;
+
+       if (mask & (PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP)) {
+               int entry;
+
+               /*
+                * The code below follows the PCI Express Base Specification 2.0
+                * stating in Section 6.1.6 that "PME and Hot-Plug Event
+                * interrupts (when both are implemented) always share the same
+                * MSI or MSI-X vector, as indicated by the Interrupt Message
+                * Number field in the PCI Express Capabilities register", where
+                * according to Section 7.8.2 of the specification "For MSI-X,
+                * the value in this field indicates which MSI-X Table entry is
+                * used to generate the interrupt message."
+                */
+               pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+               pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, &reg16);
+               entry = (reg16 >> 9) & PCIE_PORT_MSI_VECTOR_MASK;
+               if (entry >= nr_entries)
+                       goto Error;
+
+               i = pcie_port_msix_add_entry(msix_entries, entry, nvec);
+               if (i == nvec)
+                       nvec++;
+
+               idx[PCIE_PORT_SERVICE_PME_SHIFT] = i;
+               idx[PCIE_PORT_SERVICE_HP_SHIFT] = i;
+       }
+
+       if (mask & PCIE_PORT_SERVICE_AER) {
+               int entry;
+
+               /*
+                * The code below follows Section 7.10.10 of the PCI Express
+                * Base Specification 2.0 stating that bits 31-27 of the Root
+                * Error Status Register contain a value indicating which of the
+                * MSI/MSI-X vectors assigned to the port is going to be used
+                * for AER, where "For MSI-X, the value in this register
+                * indicates which MSI-X Table entry is used to generate the
+                * interrupt message."
+                */
+               pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+               pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &reg32);
+               entry = reg32 >> 27;
+               if (entry >= nr_entries)
+                       goto Error;
+
+               i = pcie_port_msix_add_entry(msix_entries, entry, nvec);
+               if (i == nvec)
+                       nvec++;
+
+               idx[PCIE_PORT_SERVICE_AER_SHIFT] = i;
        }
-       return quirk;
+
+       /*
+        * If nvec is equal to the allocated number of entries, we can just use
+        * what we have.  Otherwise, the port has some extra entries not for the
+        * services we know and we need to work around that.
+        */
+       if (nvec == nr_entries) {
+               status = 0;
+       } else {
+               /* Drop the temporary MSI-X setup */
+               pci_disable_msix(dev);
+
+               /* Now allocate the MSI-X vectors for real */
+               status = pci_enable_msix(dev, msix_entries, nvec);
+               if (status)
+                       goto Exit;
+       }
+
+       for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
+               vectors[i] = idx[i] >= 0 ? msix_entries[idx[i]].vector : -1;
+
+ Exit:
+       kfree(msix_entries);
+       return status;
+
+ Error:
+       pci_disable_msix(dev);
+       goto Exit;
 }
 
 /**
@@ -64,47 +187,32 @@ static int is_msi_quirked(struct pci_dev *dev)
  */
 static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask)
 {
-       int i, pos, nvec, status = -EINVAL;
-       int interrupt_mode = PCIE_PORT_INTx_MODE;
+       struct pcie_port_data *port_data = pci_get_drvdata(dev);
+       int irq, interrupt_mode = PCIE_PORT_NO_IRQ;
+       int i;
 
-       /* Set INTx as default */
-       for (i = 0, nvec = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
-               if (mask & (1 << i)) 
-                       nvec++;
-               vectors[i] = dev->irq;
-       }
-       
        /* Check MSI quirk */
-       if (is_msi_quirked(dev))
-               return interrupt_mode;
-
-       /* Select MSI-X over MSI if supported */                
-       pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-       if (pos) {
-               struct msix_entry msix_entries[PCIE_PORT_DEVICE_MAXSERVICES] = 
-                       {{0, 0}, {0, 1}, {0, 2}, {0, 3}};
-               status = pci_enable_msix(dev, msix_entries, nvec);
-               if (!status) {
-                       int j = 0;
-
-                       interrupt_mode = PCIE_PORT_MSIX_MODE;
-                       for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
-                               if (mask & (1 << i)) 
-                                       vectors[i] = msix_entries[j++].vector;
-                       }
-               }
-       } 
-       if (status) {
-               pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
-               if (pos) {
-                       status = pci_enable_msi(dev);
-                       if (!status) {
-                               interrupt_mode = PCIE_PORT_MSI_MODE;
-                               for (i = 0;i < PCIE_PORT_DEVICE_MAXSERVICES;i++)
-                                       vectors[i] = dev->irq;
-                       }
-               }
-       } 
+       if (port_data->port_type == PCIE_RC_PORT && pcie_mch_quirk)
+               goto Fallback;
+
+       /* Try to use MSI-X if supported */
+       if (!pcie_port_enable_msix(dev, vectors, mask))
+               return PCIE_PORT_MSIX_MODE;
+
+       /* We're not going to use MSI-X, so try MSI and fall back to INTx */
+       if (!pci_enable_msi(dev))
+               interrupt_mode = PCIE_PORT_MSI_MODE;
+
+ Fallback:
+       if (interrupt_mode == PCIE_PORT_NO_IRQ && dev->pin)
+               interrupt_mode = PCIE_PORT_INTx_MODE;
+
+       irq = interrupt_mode != PCIE_PORT_NO_IRQ ? dev->irq : -1;
+       for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
+               vectors[i] = irq;
+
+       vectors[PCIE_PORT_SERVICE_VC_SHIFT] = -1;
+
        return interrupt_mode;
 }
 
@@ -132,13 +240,11 @@ static int get_port_device_capability(struct pci_dev *dev)
                        pos + PCIE_SLOT_CAPABILITIES_REG, &reg32);
                if (reg32 & SLOT_HP_CAPABLE_MASK)
                        services |= PCIE_PORT_SERVICE_HP;
-       } 
-       /* PME Capable - root port capability */
-       if (((reg16 >> 4) & PORT_TYPE_MASK) == PCIE_RC_PORT)
-               services |= PCIE_PORT_SERVICE_PME;
-
+       }
+       /* AER capable */
        if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
                services |= PCIE_PORT_SERVICE_AER;
+       /* VC support */
        if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC))
                services |= PCIE_PORT_SERVICE_VC;
 
@@ -152,20 +258,17 @@ static int get_port_device_capability(struct pci_dev *dev)
  * @port_type: Type of the port
  * @service_type: Type of service to associate with the service device
  * @irq: Interrupt vector to associate with the service device
- * @irq_mode: Interrupt mode of the service (INTx, MSI-X, MSI)
  */
 static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, 
-       int port_type, int service_type, int irq, int irq_mode)
+       int service_type, int irq)
 {
+       struct pcie_port_data *port_data = pci_get_drvdata(parent);
        struct device *device;
+       int port_type = port_data->port_type;
 
        dev->port = parent;
-       dev->interrupt_mode = irq_mode;
        dev->irq = irq;
-       dev->id.vendor = parent->vendor;
-       dev->id.device = parent->device;
-       dev->id.port_type = port_type;
-       dev->id.service_type = (1 << service_type);
+       dev->service = service_type;
 
        /* Initialize generic device interface */
        device = &dev->device;
@@ -185,10 +288,9 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev,
  * @port_type: Type of the port
  * @service_type: Type of service to associate with the service device
  * @irq: Interrupt vector to associate with the service device
- * @irq_mode: Interrupt mode of the service (INTx, MSI-X, MSI)
  */
 static struct pcie_device* alloc_pcie_device(struct pci_dev *parent,
-       int port_type, int service_type, int irq, int irq_mode)
+       int service_type, int irq)
 {
        struct pcie_device *device;
 
@@ -196,7 +298,7 @@ static struct pcie_device* alloc_pcie_device(struct pci_dev *parent,
        if (!device)
                return NULL;
 
-       pcie_device_init(parent, device, port_type, service_type, irq,irq_mode);
+       pcie_device_init(parent, device, service_type, irq);
        return device;
 }
 
@@ -230,63 +332,90 @@ int pcie_port_device_probe(struct pci_dev *dev)
  */
 int pcie_port_device_register(struct pci_dev *dev)
 {
-       struct pcie_port_device_ext *p_ext;
-       int status, type, capabilities, irq_mode, i;
+       struct pcie_port_data *port_data;
+       int status, capabilities, irq_mode, i, nr_serv;
        int vectors[PCIE_PORT_DEVICE_MAXSERVICES];
        u16 reg16;
 
-       /* Allocate port device extension */
-       if (!(p_ext = kmalloc(sizeof(struct pcie_port_device_ext), GFP_KERNEL)))
+       port_data = kzalloc(sizeof(*port_data), GFP_KERNEL);
+       if (!port_data)
                return -ENOMEM;
-
-       pci_set_drvdata(dev, p_ext);
+       pci_set_drvdata(dev, port_data);
 
        /* Get port type */
        pci_read_config_word(dev,
                pci_find_capability(dev, PCI_CAP_ID_EXP) +
                PCIE_CAPABILITIES_REG, &reg16);
-       type = (reg16 >> 4) & PORT_TYPE_MASK;
+       port_data->port_type = (reg16 >> 4) & PORT_TYPE_MASK;
 
-       /* Now get port services */
        capabilities = get_port_device_capability(dev);
+       /* Root ports are capable of generating PME too */
+       if (port_data->port_type == PCIE_RC_PORT)
+               capabilities |= PCIE_PORT_SERVICE_PME;
+
        irq_mode = assign_interrupt_mode(dev, vectors, capabilities);
-       p_ext->interrupt_mode = irq_mode;
+       if (irq_mode == PCIE_PORT_NO_IRQ) {
+               /*
+                * Don't use service devices that require interrupts if there is
+                * no way to generate them.
+                */
+               if (!(capabilities & PCIE_PORT_SERVICE_VC)) {
+                       status = -ENODEV;
+                       goto Error;
+               }
+               capabilities = PCIE_PORT_SERVICE_VC;
+       }
+       port_data->port_irq_mode = irq_mode;
+
+       status = pci_enable_device(dev);
+       if (status)
+               goto Error;
+       pci_set_master(dev);
 
        /* Allocate child services if any */
-       for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
+       for (i = 0, nr_serv = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
                struct pcie_device *child;
+               int service = 1 << i;
+
+               if (!(capabilities & service))
+                       continue;
 
-               if (capabilities & (1 << i)) {
-                       child = alloc_pcie_device(
-                               dev,            /* parent */
-                               type,           /* port type */
-                               i,              /* service type */
-                               vectors[i],     /* irq */
-                               irq_mode        /* interrupt mode */);
-                       if (child) {
-                               status = device_register(&child->device);
-                               if (status) {
-                                       kfree(child);
-                                       continue;
-                               }
-                               get_device(&child->device);
-                       }
+               child = alloc_pcie_device(dev, service, vectors[i]);
+               if (!child)
+                       continue;
+
+               status = device_register(&child->device);
+               if (status) {
+                       kfree(child);
+                       continue;
                }
+
+               get_device(&child->device);
+               nr_serv++;
+       }
+       if (!nr_serv) {
+               pci_disable_device(dev);
+               status = -ENODEV;
+               goto Error;
        }
+
        return 0;
+
+ Error:
+       kfree(port_data);
+       return status;
 }
 
 #ifdef CONFIG_PM
 static int suspend_iter(struct device *dev, void *data)
 {
        struct pcie_port_service_driver *service_driver;
-       pm_message_t state = * (pm_message_t *) data;
 
        if ((dev->bus == &pcie_port_bus_type) &&
            (dev->driver)) {
                service_driver = to_service_driver(dev->driver);
                if (service_driver->suspend)
-                       service_driver->suspend(to_pcie_device(dev), state);
+                       service_driver->suspend(to_pcie_device(dev));
        }
        return 0;
 }
@@ -294,11 +423,10 @@ static int suspend_iter(struct device *dev, void *data)
 /**
  * pcie_port_device_suspend - suspend port services associated with a PCIe port
  * @dev: PCI Express port to handle
- * @state: Representation of system power management transition in progress
  */
-int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state)
+int pcie_port_device_suspend(struct device *dev)
 {
-       return device_for_each_child(&dev->dev, &state, suspend_iter);
+       return device_for_each_child(dev, NULL, suspend_iter);
 }
 
 static int resume_iter(struct device *dev, void *data)
@@ -318,24 +446,17 @@ static int resume_iter(struct device *dev, void *data)
  * pcie_port_device_suspend - resume port services associated with a PCIe port
  * @dev: PCI Express port to handle
  */
-int pcie_port_device_resume(struct pci_dev *dev)
+int pcie_port_device_resume(struct device *dev)
 {
-       return device_for_each_child(&dev->dev, NULL, resume_iter);
+       return device_for_each_child(dev, NULL, resume_iter);
 }
-#endif
+#endif /* PM */
 
 static int remove_iter(struct device *dev, void *data)
 {
-       struct pcie_port_service_driver *service_driver;
-
        if (dev->bus == &pcie_port_bus_type) {
-               if (dev->driver) {
-                       service_driver = to_service_driver(dev->driver);
-                       if (service_driver->remove)
-                               service_driver->remove(to_pcie_device(dev));
-               }
-               *(unsigned long*)data = (unsigned long)dev;
-               return 1;
+               put_device(dev);
+               device_unregister(dev);
        }
        return 0;
 }
@@ -349,25 +470,21 @@ static int remove_iter(struct device *dev, void *data)
  */
 void pcie_port_device_remove(struct pci_dev *dev)
 {
-       struct device *device;
-       unsigned long device_addr;
-       int interrupt_mode = PCIE_PORT_INTx_MODE;
-       int status;
+       struct pcie_port_data *port_data = pci_get_drvdata(dev);
 
-       do {
-               status = device_for_each_child(&dev->dev, &device_addr, remove_iter);
-               if (status) {
-                       device = (struct device*)device_addr;
-                       interrupt_mode = (to_pcie_device(device))->interrupt_mode;
-                       put_device(device);
-                       device_unregister(device);
-               }
-       } while (status);
-       /* Switch to INTx by default if MSI enabled */
-       if (interrupt_mode == PCIE_PORT_MSIX_MODE)
+       device_for_each_child(&dev->dev, NULL, remove_iter);
+       pci_disable_device(dev);
+
+       switch (port_data->port_irq_mode) {
+       case PCIE_PORT_MSIX_MODE:
                pci_disable_msix(dev);
-       else if (interrupt_mode == PCIE_PORT_MSI_MODE)
+               break;
+       case PCIE_PORT_MSI_MODE:
                pci_disable_msi(dev);
+               break;
+       }
+
+       kfree(port_data);
 }
 
 /**
@@ -392,7 +509,7 @@ static int pcie_port_probe_service(struct device *dev)
                return -ENODEV;
 
        pciedev = to_pcie_device(dev);
-       status = driver->probe(pciedev, driver->id_table);
+       status = driver->probe(pciedev);
        if (!status) {
                dev_printk(KERN_DEBUG, dev, "service driver %s loaded\n",
                        driver->name);
index 5ea566e20b375410ed2cc5b19d30d8eec8992fd8..b924e2463f85e0dd7f8f8e313071e9340b579048 100644 (file)
@@ -32,11 +32,6 @@ MODULE_LICENSE("GPL");
 /* global data */
 static const char device_name[] = "pcieport-driver";
 
-static int pcie_portdrv_save_config(struct pci_dev *dev)
-{
-       return pci_save_state(dev);
-}
-
 static int pcie_portdrv_restore_config(struct pci_dev *dev)
 {
        int retval;
@@ -49,21 +44,21 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev)
 }
 
 #ifdef CONFIG_PM
-static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state)
-{
-       return pcie_port_device_suspend(dev, state);
+static struct dev_pm_ops pcie_portdrv_pm_ops = {
+       .suspend        = pcie_port_device_suspend,
+       .resume         = pcie_port_device_resume,
+       .freeze         = pcie_port_device_suspend,
+       .thaw           = pcie_port_device_resume,
+       .poweroff       = pcie_port_device_suspend,
+       .restore        = pcie_port_device_resume,
+};
 
-}
+#define PCIE_PORTDRV_PM_OPS    (&pcie_portdrv_pm_ops)
 
-static int pcie_portdrv_resume(struct pci_dev *dev)
-{
-       pci_set_master(dev);
-       return pcie_port_device_resume(dev);
-}
-#else
-#define pcie_portdrv_suspend NULL
-#define pcie_portdrv_resume NULL
-#endif
+#else /* !PM */
+
+#define PCIE_PORTDRV_PM_OPS    NULL
+#endif /* !PM */
 
 /*
  * pcie_portdrv_probe - Probe PCI-Express port devices
@@ -82,20 +77,15 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev,
        if (status)
                return status;
 
-       if (pci_enable_device(dev) < 0) 
-               return -ENODEV;
-       
-       pci_set_master(dev);
         if (!dev->irq && dev->pin) {
                dev_warn(&dev->dev, "device [%04x:%04x] has invalid IRQ; "
                         "check vendor BIOS\n", dev->vendor, dev->device);
        }
-       if (pcie_port_device_register(dev)) {
-               pci_disable_device(dev);
-               return -ENOMEM;
-       }
+       status = pcie_port_device_register(dev);
+       if (status)
+               return status;
 
-       pcie_portdrv_save_config(dev);
+       pci_save_state(dev);
 
        return 0;
 }
@@ -104,7 +94,6 @@ static void pcie_portdrv_remove (struct pci_dev *dev)
 {
        pcie_port_device_remove(dev);
        pci_disable_device(dev);
-       kfree(pci_get_drvdata(dev));
 }
 
 static int error_detected_iter(struct device *device, void *data)
@@ -278,10 +267,9 @@ static struct pci_driver pcie_portdriver = {
        .probe          = pcie_portdrv_probe,
        .remove         = pcie_portdrv_remove,
 
-       .suspend        = pcie_portdrv_suspend,
-       .resume         = pcie_portdrv_resume,
-
        .err_handler    = &pcie_portdrv_err_handler,
+
+       .driver.pm      = PCIE_PORTDRV_PM_OPS,
 };
 
 static int __init pcie_portdrv_init(void)
index 55ec44a27e89e65e8d01c750ebca0f76bcf4e152..e2f3dd098cfa16c710814dcffbb1f294f7197b0c 100644 (file)
@@ -287,7 +287,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
        struct resource *res;
        int i;
 
-       if (!dev)               /* It's a host bus, nothing to read */
+       if (!child->parent)     /* It's a host bus, nothing to read */
                return;
 
        if (dev->transparent) {
@@ -511,21 +511,21 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
 
                /*
                 * If we already got to this bus through a different bridge,
-                * ignore it.  This can happen with the i450NX chipset.
+                * don't re-add it. This can happen with the i450NX chipset.
+                *
+                * However, we continue to descend down the hierarchy and
+                * scan remaining child buses.
                 */
-               if (pci_find_bus(pci_domain_nr(bus), busnr)) {
-                       dev_info(&dev->dev, "bus %04x:%02x already known\n",
-                                pci_domain_nr(bus), busnr);
-                       goto out;
+               child = pci_find_bus(pci_domain_nr(bus), busnr);
+               if (!child) {
+                       child = pci_add_new_bus(bus, dev, busnr);
+                       if (!child)
+                               goto out;
+                       child->primary = buses & 0xFF;
+                       child->subordinate = (buses >> 16) & 0xFF;
+                       child->bridge_ctl = bctl;
                }
 
-               child = pci_add_new_bus(bus, dev, busnr);
-               if (!child)
-                       goto out;
-               child->primary = buses & 0xFF;
-               child->subordinate = (buses >> 16) & 0xFF;
-               child->bridge_ctl = bctl;
-
                cmax = pci_scan_child_bus(child);
                if (cmax > max)
                        max = cmax;
@@ -674,6 +674,19 @@ static void pci_read_irq(struct pci_dev *dev)
        dev->irq = irq;
 }
 
+static void set_pcie_port_type(struct pci_dev *pdev)
+{
+       int pos;
+       u16 reg16;
+
+       pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+       if (!pos)
+               return;
+       pdev->is_pcie = 1;
+       pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
+       pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4;
+}
+
 #define LEGACY_IO_RESOURCE     (IORESOURCE_IO | IORESOURCE_PCI_FIXED)
 
 /**
@@ -683,12 +696,33 @@ static void pci_read_irq(struct pci_dev *dev)
  * Initialize the device structure with information about the device's 
  * vendor,class,memory and IO-space addresses,IRQ lines etc.
  * Called at initialisation of the PCI subsystem and by CardBus services.
- * Returns 0 on success and -1 if unknown type of device (not normal, bridge
- * or CardBus).
+ * Returns 0 on success and negative if unknown type of device (not normal,
+ * bridge or CardBus).
  */
-static int pci_setup_device(struct pci_dev * dev)
+int pci_setup_device(struct pci_dev *dev)
 {
        u32 class;
+       u8 hdr_type;
+       struct pci_slot *slot;
+
+       if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type))
+               return -EIO;
+
+       dev->sysdata = dev->bus->sysdata;
+       dev->dev.parent = dev->bus->bridge;
+       dev->dev.bus = &pci_bus_type;
+       dev->hdr_type = hdr_type & 0x7f;
+       dev->multifunction = !!(hdr_type & 0x80);
+       dev->error_state = pci_channel_io_normal;
+       set_pcie_port_type(dev);
+
+       list_for_each_entry(slot, &dev->bus->slots, list)
+               if (PCI_SLOT(dev->devfn) == slot->number)
+                       dev->slot = slot;
+
+       /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
+          set this higher, assuming the system even supports it.  */
+       dev->dma_mask = 0xffffffff;
 
        dev_set_name(&dev->dev, "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus),
                     dev->bus->number, PCI_SLOT(dev->devfn),
@@ -703,12 +737,14 @@ static int pci_setup_device(struct pci_dev * dev)
        dev_dbg(&dev->dev, "found [%04x:%04x] class %06x header type %02x\n",
                 dev->vendor, dev->device, class, dev->hdr_type);
 
+       /* need to have dev->class ready */
+       dev->cfg_size = pci_cfg_space_size(dev);
+
        /* "Unknown power state" */
        dev->current_state = PCI_UNKNOWN;
 
        /* Early fixups, before probing the BARs */
        pci_fixup_device(pci_fixup_early, dev);
-       class = dev->class >> 8;
 
        switch (dev->hdr_type) {                    /* header type */
        case PCI_HEADER_TYPE_NORMAL:                /* standard header */
@@ -770,7 +806,7 @@ static int pci_setup_device(struct pci_dev * dev)
        default:                                    /* unknown header */
                dev_err(&dev->dev, "unknown header type %02x, "
                        "ignoring device\n", dev->hdr_type);
-               return -1;
+               return -EIO;
 
        bad:
                dev_err(&dev->dev, "ignoring class %02x (doesn't match header "
@@ -785,6 +821,7 @@ static int pci_setup_device(struct pci_dev * dev)
 static void pci_release_capabilities(struct pci_dev *dev)
 {
        pci_vpd_release(dev);
+       pci_iov_release(dev);
 }
 
 /**
@@ -803,19 +840,6 @@ static void pci_release_dev(struct device *dev)
        kfree(pci_dev);
 }
 
-static void set_pcie_port_type(struct pci_dev *pdev)
-{
-       int pos;
-       u16 reg16;
-
-       pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
-       if (!pos)
-               return;
-       pdev->is_pcie = 1;
-       pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
-       pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4;
-}
-
 /**
  * pci_cfg_space_size - get the configuration space size of the PCI device.
  * @dev: PCI device
@@ -847,6 +871,11 @@ int pci_cfg_space_size(struct pci_dev *dev)
 {
        int pos;
        u32 status;
+       u16 class;
+
+       class = dev->class >> 8;
+       if (class == PCI_CLASS_BRIDGE_HOST)
+               return pci_cfg_space_size_ext(dev);
 
        pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
        if (!pos) {
@@ -891,9 +920,7 @@ EXPORT_SYMBOL(alloc_pci_dev);
 static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
 {
        struct pci_dev *dev;
-       struct pci_slot *slot;
        u32 l;
-       u8 hdr_type;
        int delay = 1;
 
        if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
@@ -920,34 +947,16 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
                }
        }
 
-       if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type))
-               return NULL;
-
        dev = alloc_pci_dev();
        if (!dev)
                return NULL;
 
        dev->bus = bus;
-       dev->sysdata = bus->sysdata;
-       dev->dev.parent = bus->bridge;
-       dev->dev.bus = &pci_bus_type;
        dev->devfn = devfn;
-       dev->hdr_type = hdr_type & 0x7f;
-       dev->multifunction = !!(hdr_type & 0x80);
        dev->vendor = l & 0xffff;
        dev->device = (l >> 16) & 0xffff;
-       dev->cfg_size = pci_cfg_space_size(dev);
-       dev->error_state = pci_channel_io_normal;
-       set_pcie_port_type(dev);
-
-       list_for_each_entry(slot, &bus->slots, list)
-               if (PCI_SLOT(devfn) == slot->number)
-                       dev->slot = slot;
 
-       /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
-          set this higher, assuming the system even supports it.  */
-       dev->dma_mask = 0xffffffff;
-       if (pci_setup_device(dev) < 0) {
+       if (pci_setup_device(dev)) {
                kfree(dev);
                return NULL;
        }
@@ -972,6 +981,9 @@ static void pci_init_capabilities(struct pci_dev *dev)
 
        /* Alternative Routing-ID Forwarding */
        pci_enable_ari(dev);
+
+       /* Single Root I/O Virtualization */
+       pci_iov_init(dev);
 }
 
 void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
@@ -1006,6 +1018,12 @@ struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
 {
        struct pci_dev *dev;
 
+       dev = pci_get_slot(bus, devfn);
+       if (dev) {
+               pci_dev_put(dev);
+               return dev;
+       }
+
        dev = pci_scan_device(bus, devfn);
        if (!dev)
                return NULL;
@@ -1024,35 +1042,27 @@ EXPORT_SYMBOL(pci_scan_single_device);
  * Scan a PCI slot on the specified PCI bus for devices, adding
  * discovered devices to the @bus->devices list.  New devices
  * will not have is_added set.
+ *
+ * Returns the number of new devices found.
  */
 int pci_scan_slot(struct pci_bus *bus, int devfn)
 {
-       int func, nr = 0;
-       int scan_all_fns;
-
-       scan_all_fns = pcibios_scan_all_fns(bus, devfn);
-
-       for (func = 0; func < 8; func++, devfn++) {
-               struct pci_dev *dev;
-
-               dev = pci_scan_single_device(bus, devfn);
-               if (dev) {
-                       nr++;
+       int fn, nr = 0;
+       struct pci_dev *dev;
 
-                       /*
-                        * If this is a single function device,
-                        * don't scan past the first function.
-                        */
-                       if (!dev->multifunction) {
-                               if (func > 0) {
-                                       dev->multifunction = 1;
-                               } else {
-                                       break;
-                               }
+       dev = pci_scan_single_device(bus, devfn);
+       if (dev && !dev->is_added)      /* new device? */
+               nr++;
+
+       if ((dev && dev->multifunction) ||
+           (!dev && pcibios_scan_all_fns(bus, devfn))) {
+               for (fn = 1; fn < 8; fn++) {
+                       dev = pci_scan_single_device(bus, devfn + fn);
+                       if (dev) {
+                               if (!dev->is_added)
+                                       nr++;
+                               dev->multifunction = 1;
                        }
-               } else {
-                       if (func == 0 && !scan_all_fns)
-                               break;
                }
        }
 
@@ -1074,12 +1084,21 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
        for (devfn = 0; devfn < 0x100; devfn += 8)
                pci_scan_slot(bus, devfn);
 
+       /* Reserve buses for SR-IOV capability. */
+       max += pci_iov_bus_range(bus);
+
        /*
         * After performing arch-dependent fixup of the bus, look behind
         * all PCI-to-PCI bridges on this bus.
         */
-       pr_debug("PCI: Fixups for bus %04x:%02x\n", pci_domain_nr(bus), bus->number);
-       pcibios_fixup_bus(bus);
+       if (!bus->is_added) {
+               pr_debug("PCI: Fixups for bus %04x:%02x\n",
+                        pci_domain_nr(bus), bus->number);
+               pcibios_fixup_bus(bus);
+               if (pci_is_root_bus(bus))
+                       bus->is_added = 1;
+       }
+
        for (pass=0; pass < 2; pass++)
                list_for_each_entry(dev, &bus->devices, bus_list) {
                        if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
@@ -1114,7 +1133,7 @@ struct pci_bus * pci_create_bus(struct device *parent,
        if (!b)
                return NULL;
 
-       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev){
                kfree(b);
                return NULL;
@@ -1133,7 +1152,6 @@ struct pci_bus * pci_create_bus(struct device *parent,
        list_add_tail(&b->node, &pci_root_buses);
        up_write(&pci_bus_sem);
 
-       memset(dev, 0, sizeof(*dev));
        dev->parent = parent;
        dev->release = pci_release_bus_bridge_dev;
        dev_set_name(dev, "pci%04x:%02x", pci_domain_nr(b), bus);
@@ -1193,6 +1211,38 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent,
 EXPORT_SYMBOL(pci_scan_bus_parented);
 
 #ifdef CONFIG_HOTPLUG
+/**
+ * pci_rescan_bus - scan a PCI bus for devices.
+ * @bus: PCI bus to scan
+ *
+ * Scan a PCI bus and child buses for new devices, adds them,
+ * and enables them.
+ *
+ * Returns the max number of subordinate bus discovered.
+ */
+unsigned int __devinit pci_rescan_bus(struct pci_bus *bus)
+{
+       unsigned int max;
+       struct pci_dev *dev;
+
+       max = pci_scan_child_bus(bus);
+
+       down_read(&pci_bus_sem);
+       list_for_each_entry(dev, &bus->devices, bus_list)
+               if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+                   dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+                       if (dev->subordinate)
+                               pci_bus_size_bridges(dev->subordinate);
+       up_read(&pci_bus_sem);
+
+       pci_bus_assign_resources(bus);
+       pci_enable_bridges(bus);
+       pci_bus_add_devices(bus);
+
+       return max;
+}
+EXPORT_SYMBOL_GPL(pci_rescan_bus);
+
 EXPORT_SYMBOL(pci_add_new_bus);
 EXPORT_SYMBOL(pci_scan_slot);
 EXPORT_SYMBOL(pci_scan_bridge);
index 92b9efe9bcaf628faa260c0e919eece0d2610e9f..9b2f0d96900def68ff56606f27e056e6d77dff7d 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/kallsyms.h>
 #include <linux/dmi.h>
 #include <linux/pci-aspm.h>
+#include <linux/ioport.h>
 #include "pci.h"
 
 int isa_dma_bridge_buggy;
@@ -34,6 +35,65 @@ int pcie_mch_quirk;
 EXPORT_SYMBOL(pcie_mch_quirk);
 
 #ifdef CONFIG_PCI_QUIRKS
+/*
+ * This quirk function disables the device and releases resources
+ * which is specified by kernel's boot parameter 'pci=resource_alignment='.
+ * It also rounds up size to specified alignment.
+ * Later on, the kernel will assign page-aligned memory resource back
+ * to that device.
+ */
+static void __devinit quirk_resource_alignment(struct pci_dev *dev)
+{
+       int i;
+       struct resource *r;
+       resource_size_t align, size;
+
+       if (!pci_is_reassigndev(dev))
+               return;
+
+       if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL &&
+           (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) {
+               dev_warn(&dev->dev,
+                       "Can't reassign resources to host bridge.\n");
+               return;
+       }
+
+       dev_info(&dev->dev, "Disabling device and release resources.\n");
+       pci_disable_device(dev);
+
+       align = pci_specified_resource_alignment(dev);
+       for (i=0; i < PCI_BRIDGE_RESOURCES; i++) {
+               r = &dev->resource[i];
+               if (!(r->flags & IORESOURCE_MEM))
+                       continue;
+               size = resource_size(r);
+               if (size < align) {
+                       size = align;
+                       dev_info(&dev->dev,
+                               "Rounding up size of resource #%d to %#llx.\n",
+                               i, (unsigned long long)size);
+               }
+               r->end = size - 1;
+               r->start = 0;
+       }
+       /* Need to disable bridge's resource window,
+        * to enable the kernel to reassign new resource
+        * window later on.
+        */
+       if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
+           (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+               for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
+                       r = &dev->resource[i];
+                       if (!(r->flags & IORESOURCE_MEM))
+                               continue;
+                       r->end = resource_size(r) - 1;
+                       r->start = 0;
+               }
+               pci_disable_bridge_window(dev);
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_resource_alignment);
+
 /* The Mellanox Tavor device gives false positive parity errors
  * Mark this device with a broken_parity_status, to allow
  * PCI scanning code to "skip" this now blacklisted device.
@@ -1126,10 +1186,15 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
                                 * its on-board VGA controller */
                                asus_hides_smbus = 1;
                        }
-               else if (dev->device == PCI_DEVICE_ID_INTEL_82845G_IG)
+               else if (dev->device == PCI_DEVICE_ID_INTEL_82801DB_2)
                        switch(dev->subsystem_device) {
                        case 0x00b8: /* Compaq Evo D510 CMT */
                        case 0x00b9: /* Compaq Evo D510 SFF */
+                               /* Motherboard doesn't have Host bridge
+                                * subvendor/subdevice IDs and on-board VGA
+                                * controller is disabled if an AGP card is
+                                * inserted, therefore checking USB UHCI
+                                * Controller #1 */
                                asus_hides_smbus = 1;
                        }
                else if (dev->device == PCI_DEVICE_ID_INTEL_82815_CGC)
@@ -1154,7 +1219,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,     PCI_DEVICE_ID_INTEL_82855GM_HB, as
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge);
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82810_IG3,  asus_hides_smbus_hostbridge);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82845G_IG,  asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801DB_2,  asus_hides_smbus_hostbridge);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82815_CGC,  asus_hides_smbus_hostbridge);
 
 static void asus_hides_smbus_lpc(struct pci_dev *dev)
@@ -1664,9 +1729,13 @@ static void __devinit quirk_netmos(struct pci_dev *dev)
         * of parallel ports and <S> is the number of serial ports.
         */
        switch (dev->device) {
+       case PCI_DEVICE_ID_NETMOS_9835:
+               /* Well, this rule doesn't hold for the following 9835 device */
+               if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
+                               dev->subsystem_device == 0x0299)
+                       return;
        case PCI_DEVICE_ID_NETMOS_9735:
        case PCI_DEVICE_ID_NETMOS_9745:
-       case PCI_DEVICE_ID_NETMOS_9835:
        case PCI_DEVICE_ID_NETMOS_9845:
        case PCI_DEVICE_ID_NETMOS_9855:
                if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL &&
@@ -2078,6 +2147,92 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA,
                        PCI_DEVICE_ID_NVIDIA_NVENET_15,
                        nvenet_msi_disable);
 
+static int __devinit ht_check_msi_mapping(struct pci_dev *dev)
+{
+       int pos, ttl = 48;
+       int found = 0;
+
+       /* check if there is HT MSI cap or enabled on this device */
+       pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
+       while (pos && ttl--) {
+               u8 flags;
+
+               if (found < 1)
+                       found = 1;
+               if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
+                                        &flags) == 0) {
+                       if (flags & HT_MSI_FLAGS_ENABLE) {
+                               if (found < 2) {
+                                       found = 2;
+                                       break;
+                               }
+                       }
+               }
+               pos = pci_find_next_ht_capability(dev, pos,
+                                                 HT_CAPTYPE_MSI_MAPPING);
+       }
+
+       return found;
+}
+
+static int __devinit host_bridge_with_leaf(struct pci_dev *host_bridge)
+{
+       struct pci_dev *dev;
+       int pos;
+       int i, dev_no;
+       int found = 0;
+
+       dev_no = host_bridge->devfn >> 3;
+       for (i = dev_no + 1; i < 0x20; i++) {
+               dev = pci_get_slot(host_bridge->bus, PCI_DEVFN(i, 0));
+               if (!dev)
+                       continue;
+
+               /* found next host bridge ?*/
+               pos = pci_find_ht_capability(dev, HT_CAPTYPE_SLAVE);
+               if (pos != 0) {
+                       pci_dev_put(dev);
+                       break;
+               }
+
+               if (ht_check_msi_mapping(dev)) {
+                       found = 1;
+                       pci_dev_put(dev);
+                       break;
+               }
+               pci_dev_put(dev);
+       }
+
+       return found;
+}
+
+#define PCI_HT_CAP_SLAVE_CTRL0     4    /* link control */
+#define PCI_HT_CAP_SLAVE_CTRL1     8    /* link control to */
+
+static int __devinit is_end_of_ht_chain(struct pci_dev *dev)
+{
+       int pos, ctrl_off;
+       int end = 0;
+       u16 flags, ctrl;
+
+       pos = pci_find_ht_capability(dev, HT_CAPTYPE_SLAVE);
+
+       if (!pos)
+               goto out;
+
+       pci_read_config_word(dev, pos + PCI_CAP_FLAGS, &flags);
+
+       ctrl_off = ((flags >> 10) & 1) ?
+                       PCI_HT_CAP_SLAVE_CTRL0 : PCI_HT_CAP_SLAVE_CTRL1;
+       pci_read_config_word(dev, pos + ctrl_off, &ctrl);
+
+       if (ctrl & (1 << 6))
+               end = 1;
+
+out:
+       return end;
+}
+
 static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev)
 {
        struct pci_dev *host_bridge;
@@ -2102,6 +2257,11 @@ static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev)
        if (!found)
                return;
 
+       /* don't enable end_device/host_bridge with leaf directly here */
+       if (host_bridge == dev && is_end_of_ht_chain(host_bridge) &&
+           host_bridge_with_leaf(host_bridge))
+               goto out;
+
        /* root did that ! */
        if (msi_ht_cap_enabled(host_bridge))
                goto out;
@@ -2132,44 +2292,12 @@ static void __devinit ht_disable_msi_mapping(struct pci_dev *dev)
        }
 }
 
-static int __devinit ht_check_msi_mapping(struct pci_dev *dev)
-{
-       int pos, ttl = 48;
-       int found = 0;
-
-       /* check if there is HT MSI cap or enabled on this device */
-       pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
-       while (pos && ttl--) {
-               u8 flags;
-
-               if (found < 1)
-                       found = 1;
-               if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
-                                        &flags) == 0) {
-                       if (flags & HT_MSI_FLAGS_ENABLE) {
-                               if (found < 2) {
-                                       found = 2;
-                                       break;
-                               }
-                       }
-               }
-               pos = pci_find_next_ht_capability(dev, pos,
-                                                 HT_CAPTYPE_MSI_MAPPING);
-       }
-
-       return found;
-}
-
-static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
+static void __devinit __nv_msi_ht_cap_quirk(struct pci_dev *dev, int all)
 {
        struct pci_dev *host_bridge;
        int pos;
        int found;
 
-       /* Enabling HT MSI mapping on this device breaks MCP51 */
-       if (dev->device == 0x270)
-               return;
-
        /* check if there is HT MSI cap or enabled on this device */
        found = ht_check_msi_mapping(dev);
 
@@ -2193,7 +2321,10 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
                /* Host bridge is to HT */
                if (found == 1) {
                        /* it is not enabled, try to enable it */
-                       nv_ht_enable_msi_mapping(dev);
+                       if (all)
+                               ht_enable_msi_mapping(dev);
+                       else
+                               nv_ht_enable_msi_mapping(dev);
                }
                return;
        }
@@ -2205,8 +2336,20 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
        /* Host bridge is not to HT, disable HT MSI mapping on this device */
        ht_disable_msi_mapping(dev);
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk);
+
+static void __devinit nv_msi_ht_cap_quirk_all(struct pci_dev *dev)
+{
+       return __nv_msi_ht_cap_quirk(dev, 1);
+}
+
+static void __devinit nv_msi_ht_cap_quirk_leaf(struct pci_dev *dev)
+{
+       return __nv_msi_ht_cap_quirk(dev, 0);
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk_leaf);
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk_all);
 
 static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev)
 {
index 042e08924421bbd8d3c773a1ee40dfb50d9a2a1e..86503c14ce7e610119ae8b8f0a1e3f5148a1d0b5 100644 (file)
@@ -71,6 +71,9 @@ void pci_remove_bus(struct pci_bus *pci_bus)
        down_write(&pci_bus_sem);
        list_del(&pci_bus->node);
        up_write(&pci_bus_sem);
+       if (!pci_bus->is_added)
+               return;
+
        pci_remove_legacy_files(pci_bus);
        device_remove_file(&pci_bus->dev, &dev_attr_cpuaffinity);
        device_remove_file(&pci_bus->dev, &dev_attr_cpulistaffinity);
@@ -92,6 +95,7 @@ EXPORT_SYMBOL(pci_remove_bus);
  */
 void pci_remove_bus_device(struct pci_dev *dev)
 {
+       pci_stop_bus_device(dev);
        if (dev->subordinate) {
                struct pci_bus *b = dev->subordinate;
 
index 5af8bd5381497656291ec61de58e678e8b874dd6..710d4ea6956860bdadad1951408ae5999ae68654 100644 (file)
@@ -29,7 +29,7 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
        if (pdev->is_pcie)
                return NULL;
        while (1) {
-               if (!pdev->bus->self)
+               if (!pdev->bus->parent)
                        break;
                pdev = pdev->bus->self;
                /* a p2p bridge */
index 7046089457805bea53eb9efdce66a4c13f41f018..334285a8e23760f7b36eda595e9ef7aa0da0ecf4 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/slab.h>
 
 
-static void pbus_assign_resources_sorted(struct pci_bus *bus)
+static void pbus_assign_resources_sorted(const struct pci_bus *bus)
 {
        struct pci_dev *dev;
        struct resource *res;
@@ -144,6 +144,9 @@ static void pci_setup_bridge(struct pci_bus *bus)
        struct pci_bus_region region;
        u32 l, bu, lu, io_upper16;
 
+       if (!pci_is_root_bus(bus) && bus->is_added)
+               return;
+
        dev_info(&bridge->dev, "PCI bridge, secondary bus %04x:%02x\n",
                 pci_domain_nr(bus), bus->number);
 
@@ -495,7 +498,7 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pci_bus_size_bridges);
 
-void __ref pci_bus_assign_resources(struct pci_bus *bus)
+void __ref pci_bus_assign_resources(const struct pci_bus *bus)
 {
        struct pci_bus *b;
        struct pci_dev *dev;
index 32e8d88a46192fcdd2ab2248f4feb71fe987ec1d..3039fcb86afc8481333fbf378904fd2853da2dbb 100644 (file)
@@ -120,6 +120,21 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
        return err;
 }
 
+#ifdef CONFIG_PCI_QUIRKS
+void pci_disable_bridge_window(struct pci_dev *dev)
+{
+       dev_dbg(&dev->dev, "Disabling bridge window.\n");
+
+       /* MMIO Base/Limit */
+       pci_write_config_dword(dev, PCI_MEMORY_BASE, 0x0000fff0);
+
+       /* Prefetchable MMIO Base/Limit */
+       pci_write_config_dword(dev, PCI_PREF_LIMIT_UPPER32, 0);
+       pci_write_config_dword(dev, PCI_PREF_MEMORY_BASE, 0x0000fff0);
+       pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, 0xffffffff);
+}
+#endif /* CONFIG_PCI_QUIRKS */
+
 int pci_assign_resource(struct pci_dev *dev, int resno)
 {
        struct pci_bus *bus = dev->bus;
index 5a8ccb4f604deed50495b61ced5ba403e59e9484..21189447e54511679ab103dcd5a9ddc7b150bd96 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * drivers/pci/slot.c
  * Copyright (C) 2006 Matthew Wilcox <matthew@wil.cx>
- * Copyright (C) 2006-2008 Hewlett-Packard Development Company, L.P.
- *     Alex Chiang <achiang@hp.com>
+ * Copyright (C) 2006-2009 Hewlett-Packard Development Company, L.P.
+ *     Alex Chiang <achiang@hp.com>
  */
 
 #include <linux/kobject.h>
@@ -52,8 +52,8 @@ static void pci_slot_release(struct kobject *kobj)
        struct pci_dev *dev;
        struct pci_slot *slot = to_pci_slot(kobj);
 
-       pr_debug("%s: releasing pci_slot on %x:%d\n", __func__,
-                slot->bus->number, slot->number);
+       dev_dbg(&slot->bus->dev, "dev %02x, released physical slot %s\n",
+               slot->number, pci_slot_name(slot));
 
        list_for_each_entry(dev, &slot->bus->devices, bus_list)
                if (PCI_SLOT(dev->devfn) == slot->number)
@@ -248,9 +248,8 @@ placeholder:
                if (PCI_SLOT(dev->devfn) == slot_nr)
                        dev->slot = slot;
 
-       /* Don't care if debug printk has a -1 for slot_nr */
-       pr_debug("%s: created pci_slot on %04x:%02x:%02x\n",
-                __func__, pci_domain_nr(parent), parent->number, slot_nr);
+       dev_dbg(&parent->dev, "dev %02x, created physical slot %s\n",
+               slot_nr, pci_slot_name(slot));
 
 out:
        kfree(slot_name);
@@ -299,9 +298,8 @@ EXPORT_SYMBOL_GPL(pci_renumber_slot);
  */
 void pci_destroy_slot(struct pci_slot *slot)
 {
-       pr_debug("%s: dec refcount to %d on %04x:%02x:%02x\n", __func__,
-                atomic_read(&slot->kobj.kref.refcount) - 1,
-                pci_domain_nr(slot->bus), slot->bus->number, slot->number);
+       dev_dbg(&slot->bus->dev, "dev %02x, dec refcount to %d\n",
+               slot->number, atomic_read(&slot->kobj.kref.refcount) - 1);
 
        down_write(&pci_bus_sem);
        kobject_put(&slot->kobj);
index d63f26e666a4c0c369d340f7f90646d48a814c59..ba1f7497e4b9a99f5be8d9d9d406ff1f6b170dbd 100644 (file)
@@ -987,7 +987,6 @@ asus_proc_add(char *name, proc_writefunc *writefunc,
        proc->write_proc = writefunc;
        proc->read_proc = readfunc;
        proc->data = acpi_driver_data(device);
-       proc->owner = THIS_MODULE;
        proc->uid = asus_uid;
        proc->gid = asus_gid;
        return 0;
@@ -1020,7 +1019,6 @@ static int asus_hotk_add_fs(struct acpi_device *device)
        if (proc) {
                proc->read_proc = proc_read_info;
                proc->data = acpi_driver_data(device);
-               proc->owner = THIS_MODULE;
                proc->uid = asus_uid;
                proc->gid = asus_gid;
        } else {
@@ -1436,7 +1434,6 @@ static int __init asus_acpi_init(void)
                printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n");
                return -ENODEV;
        }
-       asus_proc_dir->owner = THIS_MODULE;
 
        result = acpi_bus_register_driver(&asus_hotk_driver);
        if (result < 0) {
index 16e11c2ee19a2a4dfb54f8c95e6639aa26bbfe70..af9f430211722d71f85a79c762adb35ccda50b35 100644 (file)
@@ -103,7 +103,7 @@ static void parse_da_table(const struct dmi_header *dm)
        da_num_tokens += tokens;
 }
 
-static void find_tokens(const struct dmi_header *dm)
+static void find_tokens(const struct dmi_header *dm, void *dummy)
 {
        switch (dm->type) {
        case 0xd4: /* Indexed IO */
@@ -356,7 +356,7 @@ static int __init dell_init(void)
        if (!dmi_check_system(dell_device_table))
                return -ENODEV;
 
-       dmi_walk(find_tokens);
+       dmi_walk(find_tokens, NULL);
 
        if (!da_tokens)  {
                printk(KERN_INFO "dell-laptop: Unable to find dmi tokens\n");
index d2433204a40c056721d76c9f8bc2798e43feeb04..3dad27a385d3b27e90c80a229927db11b47cc9e5 100644 (file)
@@ -6992,7 +6992,6 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
                        ret = -ENODEV;
                        goto err_out;
                }
-               entry->owner = THIS_MODULE;
                entry->data = ibm;
                entry->read_proc = &dispatch_procfs_read;
                if (ibm->write)
@@ -7405,7 +7404,6 @@ static int __init thinkpad_acpi_module_init(void)
                thinkpad_acpi_module_exit();
                return -ENODEV;
        }
-       proc_dir->owner = THIS_MODULE;
 
        ret = platform_driver_register(&tpacpi_pdriver);
        if (ret) {
index 40e60fc2e596daead5c656396aa84fca0587868b..9f187265db8e260d201b167bc0095e8bd4757765 100644 (file)
@@ -679,8 +679,6 @@ static acpi_status __init add_device(void)
                                              toshiba_proc_dir,
                                              (read_proc_t *) dispatch_read,
                                              item);
-               if (proc)
-                       proc->owner = THIS_MODULE;
                if (proc && item->write_func)
                        proc->write_proc = (write_proc_t *) dispatch_write;
        }
@@ -772,7 +770,6 @@ static int __init toshiba_acpi_init(void)
                toshiba_acpi_exit();
                return -ENODEV;
        } else {
-               toshiba_proc_dir->owner = THIS_MODULE;
                status = add_device();
                if (ACPI_FAILURE(status)) {
                        toshiba_acpi_exit();
index 996f6483807909b3c773e6bbbace9997135cbcd9..cfe86853feb28a3c26750777e6f0f3397561945d 100644 (file)
@@ -94,7 +94,6 @@ struct pnp_dev_node_info node_info;
 
 #ifdef CONFIG_HOTPLUG
 
-static int unloading = 0;
 static struct completion unload_sem;
 
 /*
@@ -158,7 +157,7 @@ static int pnp_dock_thread(void *unused)
        int docked = -1, d = 0;
 
        set_freezable();
-       while (!unloading) {
+       while (1) {
                int status;
 
                /*
@@ -575,8 +574,6 @@ fs_initcall(pnpbios_init);
 
 static int __init pnpbios_thread_init(void)
 {
-       struct task_struct *task;
-
 #if defined(CONFIG_PPC)
        if (check_legacy_ioport(PNPBIOS_BASE))
                return 0;
@@ -584,10 +581,13 @@ static int __init pnpbios_thread_init(void)
        if (pnpbios_disabled)
                return 0;
 #ifdef CONFIG_HOTPLUG
-       init_completion(&unload_sem);
-       task = kthread_run(pnp_dock_thread, NULL, "kpnpbiosd");
-       if (!IS_ERR(task))
-               unloading = 0;
+       {
+               struct task_struct *task;
+               init_completion(&unload_sem);
+               task = kthread_run(pnp_dock_thread, NULL, "kpnpbiosd");
+               if (IS_ERR(task))
+                       return PTR_ERR(task);
+       }
 #endif
        return 0;
 }
index 5324978b73fba2d8aeee419d0debd31c0428ee38..235e87fcb49f5c5ab5979c2dc2fd6eeaa4b5feef 100644 (file)
@@ -838,7 +838,7 @@ static int ps3av_get_hw_conf(struct ps3av *ps3av)
 }
 
 /* set mode using id */
-int ps3av_set_video_mode(u32 id)
+int ps3av_set_video_mode(int id)
 {
        int size;
        u32 option;
@@ -940,7 +940,7 @@ EXPORT_SYMBOL_GPL(ps3av_audio_mute);
 static int ps3av_probe(struct ps3_system_bus_device *dev)
 {
        int res;
-       u32 id;
+       int id;
 
        dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
        dev_dbg(&dev->core, "  timeout=%d\n", timeout);
@@ -962,8 +962,10 @@ static int ps3av_probe(struct ps3_system_bus_device *dev)
        init_completion(&ps3av->done);
        complete(&ps3av->done);
        ps3av->wq = create_singlethread_workqueue("ps3avd");
-       if (!ps3av->wq)
+       if (!ps3av->wq) {
+               res = -ENOMEM;
                goto fail;
+       }
 
        switch (ps3_os_area_get_av_multi_out()) {
        case PS3_PARAM_AV_MULTI_OUT_NTSC:
@@ -994,6 +996,12 @@ static int ps3av_probe(struct ps3_system_bus_device *dev)
                safe_mode = 1;
 #endif /* CONFIG_FB */
        id = ps3av_auto_videomode(&ps3av->av_hw_conf);
+       if (id < 0) {
+               printk(KERN_ERR "%s: invalid id :%d\n", __func__, id);
+               res = -EINVAL;
+               goto fail;
+       }
+
        safe_mode = 0;
 
        mutex_lock(&ps3av->mutex);
@@ -1007,7 +1015,7 @@ static int ps3av_probe(struct ps3_system_bus_device *dev)
 fail:
        kfree(ps3av);
        ps3av = NULL;
-       return -ENOMEM;
+       return res;
 }
 
 static int ps3av_remove(struct ps3_system_bus_device *dev)
index 81450fbd8b1246c3bca1841f8cd314af79264081..56002f7d26bdf349612b0500e31d12e5cac24b49 100644 (file)
@@ -129,13 +129,14 @@ comment "I2C RTC drivers"
 if I2C
 
 config RTC_DRV_DS1307
-       tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00"
+       tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025"
        help
          If you say yes here you get support for various compatible RTC
          chips (often with battery backup) connected with I2C. This driver
          should handle DS1307, DS1337, DS1338, DS1339, DS1340, ST M41T00,
-         and probably other chips. In some cases the RTC must already
-         have been initialized (by manufacturing or a bootloader).
+         EPSON RX-8025 and probably other chips. In some cases the RTC
+         must already have been initialized (by manufacturing or a
+         bootloader).
 
          The first seven registers on these chips hold an RTC, and other
          registers may add features such as NVRAM, a trickle charger for
@@ -224,11 +225,11 @@ config RTC_DRV_PCF8583
          will be called rtc-pcf8583.
 
 config RTC_DRV_M41T80
-       tristate "ST M41T65/M41T80/81/82/83/84/85/87"
+       tristate "ST M41T62/65/M41T80/81/82/83/84/85/87"
        help
          If you say Y here you will get support for the ST M41T60
          and M41T80 RTC chips series. Currently, the following chips are
-         supported: M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84,
+         supported: M41T62, M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84,
          M41ST85, and M41ST87.
 
          This driver can also be built as a module. If so, the module
@@ -440,6 +441,16 @@ config RTC_DRV_DS1742
          This driver can also be built as a module. If so, the module
          will be called rtc-ds1742.
 
+config RTC_DRV_EFI
+       tristate "EFI RTC"
+       depends on IA64
+       help
+         If you say yes here you will get support for the EFI
+         Real Time Clock.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-efi.
+
 config RTC_DRV_STK17TA8
        tristate "Simtek STK17TA8"
        depends on RTC_CLASS
index 0e697aa51caa5a2d8f891772ed793dd1d69d2f45..e7b09986d26ee84b961068a0051d6ab8c7094916 100644 (file)
@@ -36,6 +36,7 @@ obj-$(CONFIG_RTC_DRV_DS1553)  += rtc-ds1553.o
 obj-$(CONFIG_RTC_DRV_DS1672)   += rtc-ds1672.o
 obj-$(CONFIG_RTC_DRV_DS1742)   += rtc-ds1742.o
 obj-$(CONFIG_RTC_DRV_DS3234)   += rtc-ds3234.o
+obj-$(CONFIG_RTC_DRV_EFI)      += rtc-efi.o
 obj-$(CONFIG_RTC_DRV_EP93XX)   += rtc-ep93xx.o
 obj-$(CONFIG_RTC_DRV_FM3130)   += rtc-fm3130.o
 obj-$(CONFIG_RTC_DRV_ISL1208)  += rtc-isl1208.o
index 7e5155e88ac75a19c9a4f6809298da344f020516..2c4a65302a9dbf55c5a73af88146aeb3e80dd872 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2005 James Chapman (ds1337 core)
  *  Copyright (C) 2006 David Brownell
+ *  Copyright (C) 2009 Matthias Fuchs (rx8025 support)
  *
  * 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
@@ -31,6 +32,7 @@ enum ds_type {
        ds_1339,
        ds_1340,
        m41t00,
+       rx_8025,
        // rs5c372 too?  different address...
 };
 
@@ -83,6 +85,12 @@ enum ds_type {
 #define DS1339_REG_ALARM1_SECS 0x07
 #define DS1339_REG_TRICKLE     0x10
 
+#define RX8025_REG_CTRL1       0x0e
+#      define RX8025_BIT_2412          0x20
+#define RX8025_REG_CTRL2       0x0f
+#      define RX8025_BIT_PON           0x10
+#      define RX8025_BIT_VDET          0x40
+#      define RX8025_BIT_XST           0x20
 
 
 struct ds1307 {
@@ -94,6 +102,10 @@ struct ds1307 {
        struct i2c_client       *client;
        struct rtc_device       *rtc;
        struct work_struct      work;
+       s32 (*read_block_data)(struct i2c_client *client, u8 command,
+                              u8 length, u8 *values);
+       s32 (*write_block_data)(struct i2c_client *client, u8 command,
+                               u8 length, const u8 *values);
 };
 
 struct chip_desc {
@@ -117,6 +129,8 @@ static const struct chip_desc chips[] = {
 [ds_1340] = {
 },
 [m41t00] = {
+},
+[rx_8025] = {
 }, };
 
 static const struct i2c_device_id ds1307_id[] = {
@@ -126,12 +140,86 @@ static const struct i2c_device_id ds1307_id[] = {
        { "ds1339", ds_1339 },
        { "ds1340", ds_1340 },
        { "m41t00", m41t00 },
+       { "rx8025", rx_8025 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ds1307_id);
 
 /*----------------------------------------------------------------------*/
 
+#define BLOCK_DATA_MAX_TRIES 10
+
+static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command,
+                                 u8 length, u8 *values)
+{
+       s32 i, data;
+
+       for (i = 0; i < length; i++) {
+               data = i2c_smbus_read_byte_data(client, command + i);
+               if (data < 0)
+                       return data;
+               values[i] = data;
+       }
+       return i;
+}
+
+static s32 ds1307_read_block_data(struct i2c_client *client, u8 command,
+                                 u8 length, u8 *values)
+{
+       u8 oldvalues[I2C_SMBUS_BLOCK_MAX];
+       s32 ret;
+       int tries = 0;
+
+       dev_dbg(&client->dev, "ds1307_read_block_data (length=%d)\n", length);
+       ret = ds1307_read_block_data_once(client, command, length, values);
+       if (ret < 0)
+               return ret;
+       do {
+               if (++tries > BLOCK_DATA_MAX_TRIES) {
+                       dev_err(&client->dev,
+                               "ds1307_read_block_data failed\n");
+                       return -EIO;
+               }
+               memcpy(oldvalues, values, length);
+               ret = ds1307_read_block_data_once(client, command, length,
+                                                 values);
+               if (ret < 0)
+                       return ret;
+       } while (memcmp(oldvalues, values, length));
+       return length;
+}
+
+static s32 ds1307_write_block_data(struct i2c_client *client, u8 command,
+                                  u8 length, const u8 *values)
+{
+       u8 currvalues[I2C_SMBUS_BLOCK_MAX];
+       int tries = 0;
+
+       dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length);
+       do {
+               s32 i, ret;
+
+               if (++tries > BLOCK_DATA_MAX_TRIES) {
+                       dev_err(&client->dev,
+                               "ds1307_write_block_data failed\n");
+                       return -EIO;
+               }
+               for (i = 0; i < length; i++) {
+                       ret = i2c_smbus_write_byte_data(client, command + i,
+                                                       values[i]);
+                       if (ret < 0)
+                               return ret;
+               }
+               ret = ds1307_read_block_data_once(client, command, length,
+                                                 currvalues);
+               if (ret < 0)
+                       return ret;
+       } while (memcmp(currvalues, values, length));
+       return length;
+}
+
+/*----------------------------------------------------------------------*/
+
 /*
  * The IRQ logic includes a "real" handler running in IRQ context just
  * long enough to schedule this workqueue entry.   We need a task context
@@ -202,7 +290,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
        int             tmp;
 
        /* read the RTC date and time registers all at once */
-       tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
+       tmp = ds1307->read_block_data(ds1307->client,
                DS1307_REG_SECS, 7, ds1307->regs);
        if (tmp != 7) {
                dev_err(dev, "%s error %d\n", "read", tmp);
@@ -279,7 +367,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
                "write", buf[0], buf[1], buf[2], buf[3],
                buf[4], buf[5], buf[6]);
 
-       result = i2c_smbus_write_i2c_block_data(ds1307->client, 0, 7, buf);
+       result = ds1307->write_block_data(ds1307->client, 0, 7, buf);
        if (result < 0) {
                dev_err(dev, "%s error %d\n", "write", result);
                return result;
@@ -297,7 +385,7 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
                return -EINVAL;
 
        /* read all ALARM1, ALARM2, and status registers at once */
-       ret = i2c_smbus_read_i2c_block_data(client,
+       ret = ds1307->read_block_data(client,
                        DS1339_REG_ALARM1_SECS, 9, ds1307->regs);
        if (ret != 9) {
                dev_err(dev, "%s error %d\n", "alarm read", ret);
@@ -356,7 +444,7 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
                t->enabled, t->pending);
 
        /* read current status of both alarms and the chip */
-       ret = i2c_smbus_read_i2c_block_data(client,
+       ret = ds1307->read_block_data(client,
                        DS1339_REG_ALARM1_SECS, 9, buf);
        if (ret != 9) {
                dev_err(dev, "%s error %d\n", "alarm write", ret);
@@ -391,7 +479,7 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        }
        buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I);
 
-       ret = i2c_smbus_write_i2c_block_data(client,
+       ret = ds1307->write_block_data(client,
                        DS1339_REG_ALARM1_SECS, 9, buf);
        if (ret < 0) {
                dev_err(dev, "can't set alarm time\n");
@@ -479,7 +567,7 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
        if (unlikely(!count))
                return count;
 
-       result = i2c_smbus_read_i2c_block_data(client, 8 + off, count, buf);
+       result = ds1307->read_block_data(client, 8 + off, count, buf);
        if (result < 0)
                dev_err(&client->dev, "%s error %d\n", "nvram read", result);
        return result;
@@ -490,9 +578,11 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
                char *buf, loff_t off, size_t count)
 {
        struct i2c_client       *client;
+       struct ds1307           *ds1307;
        int                     result;
 
        client = kobj_to_i2c_client(kobj);
+       ds1307 = i2c_get_clientdata(client);
 
        if (unlikely(off >= NVRAM_SIZE))
                return -EFBIG;
@@ -501,7 +591,7 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
        if (unlikely(!count))
                return count;
 
-       result = i2c_smbus_write_i2c_block_data(client, 8 + off, count, buf);
+       result = ds1307->write_block_data(client, 8 + off, count, buf);
        if (result < 0) {
                dev_err(&client->dev, "%s error %d\n", "nvram write", result);
                return result;
@@ -535,9 +625,8 @@ static int __devinit ds1307_probe(struct i2c_client *client,
        int                     want_irq = false;
        unsigned char           *buf;
 
-       if (!i2c_check_functionality(adapter,
-                       I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
-                       I2C_FUNC_SMBUS_I2C_BLOCK))
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)
+           && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
                return -EIO;
 
        if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL)))
@@ -547,6 +636,13 @@ static int __devinit ds1307_probe(struct i2c_client *client,
        i2c_set_clientdata(client, ds1307);
        ds1307->type = id->driver_data;
        buf = ds1307->regs;
+       if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
+               ds1307->read_block_data = i2c_smbus_read_i2c_block_data;
+               ds1307->write_block_data = i2c_smbus_write_i2c_block_data;
+       } else {
+               ds1307->read_block_data = ds1307_read_block_data;
+               ds1307->write_block_data = ds1307_write_block_data;
+       }
 
        switch (ds1307->type) {
        case ds_1337:
@@ -557,7 +653,7 @@ static int __devinit ds1307_probe(struct i2c_client *client,
                        want_irq = true;
                }
                /* get registers that the "rtc" read below won't read... */
-               tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
+               tmp = ds1307->read_block_data(ds1307->client,
                                DS1337_REG_CONTROL, 2, buf);
                if (tmp != 2) {
                        pr_debug("read error %d\n", tmp);
@@ -589,13 +685,79 @@ static int __devinit ds1307_probe(struct i2c_client *client,
                        dev_warn(&client->dev, "SET TIME!\n");
                }
                break;
+
+       case rx_8025:
+               tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
+                               RX8025_REG_CTRL1 << 4 | 0x08, 2, buf);
+               if (tmp != 2) {
+                       pr_debug("read error %d\n", tmp);
+                       err = -EIO;
+                       goto exit_free;
+               }
+
+               /* oscillator off?  turn it on, so clock can tick. */
+               if (!(ds1307->regs[1] & RX8025_BIT_XST)) {
+                       ds1307->regs[1] |= RX8025_BIT_XST;
+                       i2c_smbus_write_byte_data(client,
+                                                 RX8025_REG_CTRL2 << 4 | 0x08,
+                                                 ds1307->regs[1]);
+                       dev_warn(&client->dev,
+                                "oscillator stop detected - SET TIME!\n");
+               }
+
+               if (ds1307->regs[1] & RX8025_BIT_PON) {
+                       ds1307->regs[1] &= ~RX8025_BIT_PON;
+                       i2c_smbus_write_byte_data(client,
+                                                 RX8025_REG_CTRL2 << 4 | 0x08,
+                                                 ds1307->regs[1]);
+                       dev_warn(&client->dev, "power-on detected\n");
+               }
+
+               if (ds1307->regs[1] & RX8025_BIT_VDET) {
+                       ds1307->regs[1] &= ~RX8025_BIT_VDET;
+                       i2c_smbus_write_byte_data(client,
+                                                 RX8025_REG_CTRL2 << 4 | 0x08,
+                                                 ds1307->regs[1]);
+                       dev_warn(&client->dev, "voltage drop detected\n");
+               }
+
+               /* make sure we are running in 24hour mode */
+               if (!(ds1307->regs[0] & RX8025_BIT_2412)) {
+                       u8 hour;
+
+                       /* switch to 24 hour mode */
+                       i2c_smbus_write_byte_data(client,
+                                                 RX8025_REG_CTRL1 << 4 | 0x08,
+                                                 ds1307->regs[0] |
+                                                 RX8025_BIT_2412);
+
+                       tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
+                                       RX8025_REG_CTRL1 << 4 | 0x08, 2, buf);
+                       if (tmp != 2) {
+                               pr_debug("read error %d\n", tmp);
+                               err = -EIO;
+                               goto exit_free;
+                       }
+
+                       /* correct hour */
+                       hour = bcd2bin(ds1307->regs[DS1307_REG_HOUR]);
+                       if (hour == 12)
+                               hour = 0;
+                       if (ds1307->regs[DS1307_REG_HOUR] & DS1307_BIT_PM)
+                               hour += 12;
+
+                       i2c_smbus_write_byte_data(client,
+                                                 DS1307_REG_HOUR << 4 | 0x08,
+                                                 hour);
+               }
+               break;
        default:
                break;
        }
 
 read_rtc:
        /* read RTC registers */
-       tmp = i2c_smbus_read_i2c_block_data(ds1307->client, 0, 8, buf);
+       tmp = ds1307->read_block_data(ds1307->client, 0, 8, buf);
        if (tmp != 8) {
                pr_debug("read error %d\n", tmp);
                err = -EIO;
@@ -649,6 +811,7 @@ read_rtc:
                        dev_warn(&client->dev, "SET TIME!\n");
                }
                break;
+       case rx_8025:
        case ds_1337:
        case ds_1339:
                break;
@@ -662,6 +825,8 @@ read_rtc:
                 * systems that will run through year 2100.
                 */
                break;
+       case rx_8025:
+               break;
        default:
                if (!(tmp & DS1307_BIT_12HR))
                        break;
index a5b0fc09f0c673976720b10eca2cc3ecf8ff03bb..4d32e328f6cd6b7bb2e9cf9e72748b6031f30ef6 100644 (file)
@@ -222,16 +222,16 @@ static int ds1374_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        rtc_tm_to_time(&alarm->time, &new_alarm);
        rtc_tm_to_time(&now, &itime);
 
-       new_alarm -= itime;
-
        /* This can happen due to races, in addition to dates that are
         * truly in the past.  To avoid requiring the caller to check for
         * races, dates in the past are assumed to be in the recent past
         * (i.e. not something that we'd rather the caller know about via
         * an error), and the alarm is set to go off as soon as possible.
         */
-       if (new_alarm <= 0)
+       if (time_before_eq(new_alarm, itime))
                new_alarm = 1;
+       else
+               new_alarm -= itime;
 
        mutex_lock(&ds1374->mutex);
 
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
new file mode 100644 (file)
index 0000000..5502923
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * rtc-efi: RTC Class Driver for EFI-based systems
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * Author: dann frazier <dannf@hp.com>
+ * Based on efirtc.c by Stephane Eranian
+ *
+ *  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/kernel.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/efi.h>
+
+#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
+/*
+ * EFI Epoch is 1/1/1998
+ */
+#define EFI_RTC_EPOCH          1998
+
+/*
+ * returns day of the year [0-365]
+ */
+static inline int
+compute_yday(efi_time_t *eft)
+{
+       /* efi_time_t.month is in the [1-12] so, we need -1 */
+       return rtc_year_days(eft->day - 1, eft->month - 1, eft->year);
+}
+/*
+ * returns day of the week [0-6] 0=Sunday
+ *
+ * Don't try to provide a year that's before 1998, please !
+ */
+static int
+compute_wday(efi_time_t *eft)
+{
+       int y;
+       int ndays = 0;
+
+       if (eft->year < 1998) {
+               printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
+               return -1;
+       }
+
+       for (y = EFI_RTC_EPOCH; y < eft->year; y++)
+               ndays += 365 + (is_leap_year(y) ? 1 : 0);
+
+       ndays += compute_yday(eft);
+
+       /*
+        * 4=1/1/1998 was a Thursday
+        */
+       return (ndays + 4) % 7;
+}
+
+static void
+convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
+{
+       eft->year       = wtime->tm_year + 1900;
+       eft->month      = wtime->tm_mon + 1;
+       eft->day        = wtime->tm_mday;
+       eft->hour       = wtime->tm_hour;
+       eft->minute     = wtime->tm_min;
+       eft->second     = wtime->tm_sec;
+       eft->nanosecond = 0;
+       eft->daylight   = wtime->tm_isdst ? EFI_ISDST : 0;
+       eft->timezone   = EFI_UNSPECIFIED_TIMEZONE;
+}
+
+static void
+convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
+{
+       memset(wtime, 0, sizeof(*wtime));
+       wtime->tm_sec  = eft->second;
+       wtime->tm_min  = eft->minute;
+       wtime->tm_hour = eft->hour;
+       wtime->tm_mday = eft->day;
+       wtime->tm_mon  = eft->month - 1;
+       wtime->tm_year = eft->year - 1900;
+
+       /* day of the week [0-6], Sunday=0 */
+       wtime->tm_wday = compute_wday(eft);
+
+       /* day in the year [1-365]*/
+       wtime->tm_yday = compute_yday(eft);
+
+
+       switch (eft->daylight & EFI_ISDST) {
+       case EFI_ISDST:
+               wtime->tm_isdst = 1;
+               break;
+       case EFI_TIME_ADJUST_DAYLIGHT:
+               wtime->tm_isdst = 0;
+               break;
+       default:
+               wtime->tm_isdst = -1;
+       }
+}
+
+static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+       efi_time_t eft;
+       efi_status_t status;
+
+       /*
+        * As of EFI v1.10, this call always returns an unsupported status
+        */
+       status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
+                                    (efi_bool_t *)&wkalrm->pending, &eft);
+
+       if (status != EFI_SUCCESS)
+               return -EINVAL;
+
+       convert_from_efi_time(&eft, &wkalrm->time);
+
+       return rtc_valid_tm(&wkalrm->time);
+}
+
+static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+       efi_time_t eft;
+       efi_status_t status;
+
+       convert_to_efi_time(&wkalrm->time, &eft);
+
+       /*
+        * XXX Fixme:
+        * As of EFI 0.92 with the firmware I have on my
+        * machine this call does not seem to work quite
+        * right
+        *
+        * As of v1.10, this call always returns an unsupported status
+        */
+       status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
+
+       printk(KERN_WARNING "write status is %d\n", (int)status);
+
+       return status == EFI_SUCCESS ? 0 : -EINVAL;
+}
+
+static int efi_read_time(struct device *dev, struct rtc_time *tm)
+{
+       efi_status_t status;
+       efi_time_t eft;
+       efi_time_cap_t cap;
+
+       status = efi.get_time(&eft, &cap);
+
+       if (status != EFI_SUCCESS) {
+               /* should never happen */
+               printk(KERN_ERR "efitime: can't read time\n");
+               return -EINVAL;
+       }
+
+       convert_from_efi_time(&eft, tm);
+
+       return rtc_valid_tm(tm);
+}
+
+static int efi_set_time(struct device *dev, struct rtc_time *tm)
+{
+       efi_status_t status;
+       efi_time_t eft;
+
+       convert_to_efi_time(tm, &eft);
+
+       status = efi.set_time(&eft);
+
+       return status == EFI_SUCCESS ? 0 : -EINVAL;
+}
+
+static const struct rtc_class_ops efi_rtc_ops = {
+       .read_time = efi_read_time,
+       .set_time = efi_set_time,
+       .read_alarm = efi_read_alarm,
+       .set_alarm = efi_set_alarm,
+};
+
+static int __init efi_rtc_probe(struct platform_device *dev)
+{
+       struct rtc_device *rtc;
+
+       rtc = rtc_device_register("rtc-efi", &dev->dev, &efi_rtc_ops,
+                                       THIS_MODULE);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       platform_set_drvdata(dev, rtc);
+
+       return 0;
+}
+
+static int __exit efi_rtc_remove(struct platform_device *dev)
+{
+       struct rtc_device *rtc = platform_get_drvdata(dev);
+
+       rtc_device_unregister(rtc);
+
+       return 0;
+}
+
+static struct platform_driver efi_rtc_driver = {
+       .driver = {
+               .name = "rtc-efi",
+               .owner = THIS_MODULE,
+       },
+       .probe = efi_rtc_probe,
+       .remove = __exit_p(efi_rtc_remove),
+};
+
+static int __init efi_rtc_init(void)
+{
+       return platform_driver_probe(&efi_rtc_driver, efi_rtc_probe);
+}
+
+static void __exit efi_rtc_exit(void)
+{
+       platform_driver_unregister(&efi_rtc_driver);
+}
+
+module_init(efi_rtc_init);
+module_exit(efi_rtc_exit);
+
+MODULE_AUTHOR("dann frazier <dannf@hp.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EFI RTC driver");
index dd70bf73ce9d5e3dd5fa1686c12f1c46421b5624..773851f338b81df956913d57a80e198a40ffdb82 100644 (file)
@@ -26,14 +26,13 @@ static const unsigned short rtc_ydays[2][13] = {
 };
 
 #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
-#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
 
 /*
  * The number of days in the month.
  */
 int rtc_month_days(unsigned int month, unsigned int year)
 {
-       return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1);
+       return rtc_days_in_month[month] + (is_leap_year(year) && month == 1);
 }
 EXPORT_SYMBOL(rtc_month_days);
 
@@ -42,7 +41,7 @@ EXPORT_SYMBOL(rtc_month_days);
  */
 int rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
 {
-       return rtc_ydays[LEAP_YEAR(year)][month] + day-1;
+       return rtc_ydays[is_leap_year(year)][month] + day-1;
 }
 EXPORT_SYMBOL(rtc_year_days);
 
@@ -66,7 +65,7 @@ void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
                - LEAPS_THRU_END_OF(1970 - 1);
        if (days < 0) {
                year -= 1;
-               days += 365 + LEAP_YEAR(year);
+               days += 365 + is_leap_year(year);
        }
        tm->tm_year = year - 1900;
        tm->tm_yday = days + 1;
index 893f7dece239522afcca4579d2524dba58f645a0..60fe266f0f494c7bd5db9b93763f4f4b7e7b2745 100644 (file)
 #define M41T80_FEATURE_BL      (1 << 1)        /* Battery low indicator */
 #define M41T80_FEATURE_SQ      (1 << 2)        /* Squarewave feature */
 #define M41T80_FEATURE_WD      (1 << 3)        /* Extra watchdog resolution */
+#define M41T80_FEATURE_SQ_ALT  (1 << 4)        /* RSx bits are in reg 4 */
 
 #define DRV_VERSION "0.05"
 
 static const struct i2c_device_id m41t80_id[] = {
+       { "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT },
        { "m41t65", M41T80_FEATURE_HT | M41T80_FEATURE_WD },
        { "m41t80", M41T80_FEATURE_SQ },
        { "m41t81", M41T80_FEATURE_HT | M41T80_FEATURE_SQ},
@@ -393,12 +395,15 @@ static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev,
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct m41t80_data *clientdata = i2c_get_clientdata(client);
-       int val;
+       int val, reg_sqw;
 
        if (!(clientdata->features & M41T80_FEATURE_SQ))
                return -EINVAL;
 
-       val = i2c_smbus_read_byte_data(client, M41T80_REG_SQW);
+       reg_sqw = M41T80_REG_SQW;
+       if (clientdata->features & M41T80_FEATURE_SQ_ALT)
+               reg_sqw = M41T80_REG_WDAY;
+       val = i2c_smbus_read_byte_data(client, reg_sqw);
        if (val < 0)
                return -EIO;
        val = (val >> 4) & 0xf;
@@ -419,7 +424,7 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct m41t80_data *clientdata = i2c_get_clientdata(client);
-       int almon, sqw;
+       int almon, sqw, reg_sqw;
        int val = simple_strtoul(buf, NULL, 0);
 
        if (!(clientdata->features & M41T80_FEATURE_SQ))
@@ -440,13 +445,16 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,
        almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
        if (almon < 0)
                return -EIO;
-       sqw = i2c_smbus_read_byte_data(client, M41T80_REG_SQW);
+       reg_sqw = M41T80_REG_SQW;
+       if (clientdata->features & M41T80_FEATURE_SQ_ALT)
+               reg_sqw = M41T80_REG_WDAY;
+       sqw = i2c_smbus_read_byte_data(client, reg_sqw);
        if (sqw < 0)
                return -EIO;
        sqw = (sqw & 0x0f) | (val << 4);
        if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
                                      almon & ~M41T80_ALMON_SQWE) < 0 ||
-           i2c_smbus_write_byte_data(client, M41T80_REG_SQW, sqw) < 0)
+           i2c_smbus_write_byte_data(client, reg_sqw, sqw) < 0)
                return -EIO;
        if (val && i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
                                             almon | M41T80_ALMON_SQWE) < 0)
index c6bfa6fe1a2a289dddc0748ebd660df195087724..b966f56da976e4dec379c56eb6fcc88545883295 100644 (file)
@@ -7,41 +7,25 @@
 #include <linux/module.h>
 #include <linux/time.h>
 #include <linux/platform_device.h>
+#include <linux/rtc.h>
 
 #include <asm/rtc.h>
 
-/* as simple as can be, and no simpler. */
-struct parisc_rtc {
-       struct rtc_device *rtc;
-       spinlock_t lock;
-};
-
 static int parisc_get_time(struct device *dev, struct rtc_time *tm)
 {
-       struct parisc_rtc *p = dev_get_drvdata(dev);
-       unsigned long flags, ret;
+       unsigned long ret;
 
-       spin_lock_irqsave(&p->lock, flags);
        ret = get_rtc_time(tm);
-       spin_unlock_irqrestore(&p->lock, flags);
 
        if (ret & RTC_BATT_BAD)
                return -EOPNOTSUPP;
 
-       return 0;
+       return rtc_valid_tm(tm);
 }
 
 static int parisc_set_time(struct device *dev, struct rtc_time *tm)
 {
-       struct parisc_rtc *p = dev_get_drvdata(dev);
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&p->lock, flags);
-       ret = set_rtc_time(tm);
-       spin_unlock_irqrestore(&p->lock, flags);
-
-       if (ret < 0)
+       if (set_rtc_time(tm) < 0)
                return -EOPNOTSUPP;
 
        return 0;
@@ -52,35 +36,25 @@ static const struct rtc_class_ops parisc_rtc_ops = {
        .set_time = parisc_set_time,
 };
 
-static int __devinit parisc_rtc_probe(struct platform_device *dev)
+static int __init parisc_rtc_probe(struct platform_device *dev)
 {
-       struct parisc_rtc *p;
-
-       p = kzalloc(sizeof (*p), GFP_KERNEL);
-       if (!p)
-               return -ENOMEM;
-
-       spin_lock_init(&p->lock);
+       struct rtc_device *rtc;
 
-       p->rtc = rtc_device_register("rtc-parisc", &dev->dev, &parisc_rtc_ops,
-                                       THIS_MODULE);
-       if (IS_ERR(p->rtc)) {
-               int err = PTR_ERR(p->rtc);
-               kfree(p);
-               return err;
-       }
+       rtc = rtc_device_register("rtc-parisc", &dev->dev, &parisc_rtc_ops,
+                                 THIS_MODULE);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
 
-       platform_set_drvdata(dev, p);
+       platform_set_drvdata(dev, rtc);
 
        return 0;
 }
 
-static int __devexit parisc_rtc_remove(struct platform_device *dev)
+static int __exit parisc_rtc_remove(struct platform_device *dev)
 {
-       struct parisc_rtc *p = platform_get_drvdata(dev);
+       struct rtc_device *rtc = platform_get_drvdata(dev);
 
-       rtc_device_unregister(p->rtc);
-       kfree(p);
+       rtc_device_unregister(rtc);
 
        return 0;
 }
@@ -96,7 +70,7 @@ static struct platform_driver parisc_rtc_driver = {
 
 static int __init parisc_rtc_init(void)
 {
-       return platform_driver_register(&parisc_rtc_driver);
+       return platform_driver_probe(&parisc_rtc_driver, parisc_rtc_probe);
 }
 
 static void __exit parisc_rtc_fini(void)
index 0c6257a034ff07b3dc85e9ce1db3847571c97fc4..c086fc30a84c9ad3b4e834559a4d433688758a1a 100644 (file)
@@ -105,14 +105,8 @@ static const struct file_operations rtc_proc_fops = {
 
 void rtc_proc_add_device(struct rtc_device *rtc)
 {
-       if (rtc->id == 0) {
-               struct proc_dir_entry *ent;
-
-               ent = proc_create_data("driver/rtc", 0, NULL,
-                                      &rtc_proc_fops, rtc);
-               if (ent)
-                       ent->owner = rtc->owner;
-       }
+       if (rtc->id == 0)
+               proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc);
 }
 
 void rtc_proc_del_device(struct rtc_device *rtc)
index 14d4f036a7686e7c637752c95ae620df99458f77..ad164056feb6692cf7e66896a1c9f0d6b050b073 100644 (file)
 #include <linux/bcd.h>
 #include <linux/rtc-v3020.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
 
-#include <asm/io.h>
+#include <linux/io.h>
 
 #undef DEBUG
 
+struct v3020;
+
+struct v3020_chip_ops {
+       int (*map_io)(struct v3020 *chip, struct platform_device *pdev,
+                     struct v3020_platform_data *pdata);
+       void (*unmap_io)(struct v3020 *chip);
+       unsigned char (*read_bit)(struct v3020 *chip);
+       void (*write_bit)(struct v3020 *chip, unsigned char bit);
+};
+
+#define V3020_CS       0
+#define V3020_WR       1
+#define V3020_RD       2
+#define V3020_IO       3
+
+struct v3020_gpio {
+       const char *name;
+       unsigned int gpio;
+};
+
 struct v3020 {
+       /* MMIO access */
        void __iomem *ioaddress;
        int leftshift;
+
+       /* GPIO access */
+       struct v3020_gpio *gpio;
+
+       struct v3020_chip_ops *ops;
+
        struct rtc_device *rtc;
 };
 
+
+static int v3020_mmio_map(struct v3020 *chip, struct platform_device *pdev,
+                         struct v3020_platform_data *pdata)
+{
+       if (pdev->num_resources != 1)
+               return -EBUSY;
+
+       if (pdev->resource[0].flags != IORESOURCE_MEM)
+               return -EBUSY;
+
+       chip->leftshift = pdata->leftshift;
+       chip->ioaddress = ioremap(pdev->resource[0].start, 1);
+       if (chip->ioaddress == NULL)
+               return -EBUSY;
+
+       return 0;
+}
+
+static void v3020_mmio_unmap(struct v3020 *chip)
+{
+       iounmap(chip->ioaddress);
+}
+
+static void v3020_mmio_write_bit(struct v3020 *chip, unsigned char bit)
+{
+       writel(bit << chip->leftshift, chip->ioaddress);
+}
+
+static unsigned char v3020_mmio_read_bit(struct v3020 *chip)
+{
+       return readl(chip->ioaddress) & (1 << chip->leftshift);
+}
+
+static struct v3020_chip_ops v3020_mmio_ops = {
+       .map_io         = v3020_mmio_map,
+       .unmap_io       = v3020_mmio_unmap,
+       .read_bit       = v3020_mmio_read_bit,
+       .write_bit      = v3020_mmio_write_bit,
+};
+
+static struct v3020_gpio v3020_gpio[] = {
+       { "RTC CS", 0 },
+       { "RTC WR", 0 },
+       { "RTC RD", 0 },
+       { "RTC IO", 0 },
+};
+
+static int v3020_gpio_map(struct v3020 *chip, struct platform_device *pdev,
+                         struct v3020_platform_data *pdata)
+{
+       int i, err;
+
+       v3020_gpio[V3020_CS].gpio = pdata->gpio_cs;
+       v3020_gpio[V3020_WR].gpio = pdata->gpio_wr;
+       v3020_gpio[V3020_RD].gpio = pdata->gpio_rd;
+       v3020_gpio[V3020_IO].gpio = pdata->gpio_io;
+
+       for (i = 0; i < ARRAY_SIZE(v3020_gpio); i++) {
+               err = gpio_request(v3020_gpio[i].gpio, v3020_gpio[i].name);
+               if (err)
+                       goto err_request;
+
+               gpio_direction_output(v3020_gpio[i].gpio, 1);
+       }
+
+       chip->gpio = v3020_gpio;
+
+       return 0;
+
+err_request:
+       while (--i >= 0)
+               gpio_free(v3020_gpio[i].gpio);
+
+       return err;
+}
+
+static void v3020_gpio_unmap(struct v3020 *chip)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(v3020_gpio); i++)
+               gpio_free(v3020_gpio[i].gpio);
+}
+
+static void v3020_gpio_write_bit(struct v3020 *chip, unsigned char bit)
+{
+       gpio_direction_output(chip->gpio[V3020_IO].gpio, bit);
+       gpio_set_value(chip->gpio[V3020_CS].gpio, 0);
+       gpio_set_value(chip->gpio[V3020_WR].gpio, 0);
+       udelay(1);
+       gpio_set_value(chip->gpio[V3020_WR].gpio, 1);
+       gpio_set_value(chip->gpio[V3020_CS].gpio, 1);
+}
+
+static unsigned char v3020_gpio_read_bit(struct v3020 *chip)
+{
+       int bit;
+
+       gpio_direction_input(chip->gpio[V3020_IO].gpio);
+       gpio_set_value(chip->gpio[V3020_CS].gpio, 0);
+       gpio_set_value(chip->gpio[V3020_RD].gpio, 0);
+       udelay(1);
+       bit = !!gpio_get_value(chip->gpio[V3020_IO].gpio);
+       udelay(1);
+       gpio_set_value(chip->gpio[V3020_RD].gpio, 1);
+       gpio_set_value(chip->gpio[V3020_CS].gpio, 1);
+
+       return bit;
+}
+
+static struct v3020_chip_ops v3020_gpio_ops = {
+       .map_io         = v3020_gpio_map,
+       .unmap_io       = v3020_gpio_unmap,
+       .read_bit       = v3020_gpio_read_bit,
+       .write_bit      = v3020_gpio_write_bit,
+};
+
 static void v3020_set_reg(struct v3020 *chip, unsigned char address,
                        unsigned char data)
 {
@@ -46,7 +191,7 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address,
 
        tmp = address;
        for (i = 0; i < 4; i++) {
-               writel((tmp & 1) << chip->leftshift, chip->ioaddress);
+               chip->ops->write_bit(chip, (tmp & 1));
                tmp >>= 1;
                udelay(1);
        }
@@ -54,7 +199,7 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address,
        /* Commands dont have data */
        if (!V3020_IS_COMMAND(address)) {
                for (i = 0; i < 8; i++) {
-                       writel((data & 1) << chip->leftshift, chip->ioaddress);
+                       chip->ops->write_bit(chip, (data & 1));
                        data >>= 1;
                        udelay(1);
                }
@@ -63,18 +208,18 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address,
 
 static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address)
 {
-       unsigned int data=0;
+       unsigned int data = 0;
        int i;
 
        for (i = 0; i < 4; i++) {
-               writel((address & 1) << chip->leftshift, chip->ioaddress);
+               chip->ops->write_bit(chip, (address & 1));
                address >>= 1;
                udelay(1);
        }
 
        for (i = 0; i < 8; i++) {
                data >>= 1;
-               if (readl(chip->ioaddress) & (1 << chip->leftshift))
+               if (chip->ops->read_bit(chip))
                        data |= 0x80;
                udelay(1);
        }
@@ -106,16 +251,14 @@ static int v3020_read_time(struct device *dev, struct rtc_time *dt)
        tmp = v3020_get_reg(chip, V3020_YEAR);
        dt->tm_year = bcd2bin(tmp)+100;
 
-#ifdef DEBUG
-       printk("\n%s : Read RTC values\n",__func__);
-       printk("tm_hour: %i\n",dt->tm_hour);
-       printk("tm_min : %i\n",dt->tm_min);
-       printk("tm_sec : %i\n",dt->tm_sec);
-       printk("tm_year: %i\n",dt->tm_year);
-       printk("tm_mon : %i\n",dt->tm_mon);
-       printk("tm_mday: %i\n",dt->tm_mday);
-       printk("tm_wday: %i\n",dt->tm_wday);
-#endif
+       dev_dbg(dev, "\n%s : Read RTC values\n", __func__);
+       dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour);
+       dev_dbg(dev, "tm_min : %i\n", dt->tm_min);
+       dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec);
+       dev_dbg(dev, "tm_year: %i\n", dt->tm_year);
+       dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon);
+       dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday);
+       dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday);
 
        return 0;
 }
@@ -125,15 +268,13 @@ static int v3020_set_time(struct device *dev, struct rtc_time *dt)
 {
        struct v3020 *chip = dev_get_drvdata(dev);
 
-#ifdef DEBUG
-       printk("\n%s : Setting RTC values\n",__func__);
-       printk("tm_sec : %i\n",dt->tm_sec);
-       printk("tm_min : %i\n",dt->tm_min);
-       printk("tm_hour: %i\n",dt->tm_hour);
-       printk("tm_mday: %i\n",dt->tm_mday);
-       printk("tm_wday: %i\n",dt->tm_wday);
-       printk("tm_year: %i\n",dt->tm_year);
-#endif
+       dev_dbg(dev, "\n%s : Setting RTC values\n", __func__);
+       dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec);
+       dev_dbg(dev, "tm_min : %i\n", dt->tm_min);
+       dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour);
+       dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday);
+       dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday);
+       dev_dbg(dev, "tm_year: %i\n", dt->tm_year);
 
        /* Write all the values to ram... */
        v3020_set_reg(chip, V3020_SECONDS,      bin2bcd(dt->tm_sec));
@@ -168,30 +309,28 @@ static int rtc_probe(struct platform_device *pdev)
        int i;
        int temp;
 
-       if (pdev->num_resources != 1)
-               return -EBUSY;
-
-       if (pdev->resource[0].flags != IORESOURCE_MEM)
-               return -EBUSY;
-
        chip = kzalloc(sizeof *chip, GFP_KERNEL);
        if (!chip)
                return -ENOMEM;
 
-       chip->leftshift = pdata->leftshift;
-       chip->ioaddress = ioremap(pdev->resource[0].start, 1);
-       if (chip->ioaddress == NULL)
+       if (pdata->use_gpio)
+               chip->ops = &v3020_gpio_ops;
+       else
+               chip->ops = &v3020_mmio_ops;
+
+       retval = chip->ops->map_io(chip, pdev, pdata);
+       if (retval)
                goto err_chip;
 
        /* Make sure the v3020 expects a communication cycle
         * by reading 8 times */
        for (i = 0; i < 8; i++)
-               temp = readl(chip->ioaddress);
+               temp = chip->ops->read_bit(chip);
 
        /* Test chip by doing a write/read sequence
         * to the chip ram */
        v3020_set_reg(chip, V3020_SECONDS, 0x33);
-       if(v3020_get_reg(chip, V3020_SECONDS) != 0x33) {
+       if (v3020_get_reg(chip, V3020_SECONDS) != 0x33) {
                retval = -ENODEV;
                goto err_io;
        }
@@ -200,10 +339,17 @@ static int rtc_probe(struct platform_device *pdev)
         * are all disabled */
        v3020_set_reg(chip, V3020_STATUS_0, 0x0);
 
-       dev_info(&pdev->dev, "Chip available at physical address 0x%llx,"
-               "data connected to D%d\n",
-               (unsigned long long)pdev->resource[0].start,
-               chip->leftshift);
+       if (pdata->use_gpio)
+               dev_info(&pdev->dev, "Chip available at GPIOs "
+                        "%d, %d, %d, %d\n",
+                        chip->gpio[V3020_CS].gpio, chip->gpio[V3020_WR].gpio,
+                        chip->gpio[V3020_RD].gpio, chip->gpio[V3020_IO].gpio);
+       else
+               dev_info(&pdev->dev, "Chip available at "
+                        "physical address 0x%llx,"
+                        "data connected to D%d\n",
+                        (unsigned long long)pdev->resource[0].start,
+                        chip->leftshift);
 
        platform_set_drvdata(pdev, chip);
 
@@ -218,7 +364,7 @@ static int rtc_probe(struct platform_device *pdev)
        return 0;
 
 err_io:
-       iounmap(chip->ioaddress);
+       chip->ops->unmap_io(chip);
 err_chip:
        kfree(chip);
 
@@ -233,7 +379,7 @@ static int rtc_remove(struct platform_device *dev)
        if (rtc)
                rtc_device_unregister(rtc);
 
-       iounmap(chip->ioaddress);
+       chip->ops->unmap_io(chip);
        kfree(chip);
 
        return 0;
index 5c5e3aa91385bd7efa94f6ae831c03858e02a4f5..c91edc572eb609f3c78449099fabf04d0e76af8d 100644 (file)
@@ -122,7 +122,7 @@ static int wm8350_rtc_settime(struct device *dev, struct rtc_time *tm)
        do {
                rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
                schedule_timeout_uninterruptible(msecs_to_jiffies(1));
-       } while (retries-- && !(rtc_ctrl & WM8350_RTC_STS));
+       } while (--retries && !(rtc_ctrl & WM8350_RTC_STS));
 
        if (!retries) {
                dev_err(dev, "timed out on set confirmation\n");
@@ -236,6 +236,17 @@ static int wm8350_rtc_start_alarm(struct wm8350 *wm8350)
        return 0;
 }
 
+static int wm8350_rtc_alarm_irq_enable(struct device *dev,
+                                      unsigned int enabled)
+{
+       struct wm8350 *wm8350 = dev_get_drvdata(dev);
+
+       if (enabled)
+               return wm8350_rtc_start_alarm(wm8350);
+       else
+               return wm8350_rtc_stop_alarm(wm8350);
+}
+
 static int wm8350_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
        struct wm8350 *wm8350 = dev_get_drvdata(dev);
@@ -291,30 +302,15 @@ static int wm8350_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
        return ret;
 }
 
-/*
- * Handle commands from user-space
- */
-static int wm8350_rtc_ioctl(struct device *dev, unsigned int cmd,
-                           unsigned long arg)
+static int wm8350_rtc_update_irq_enable(struct device *dev,
+                                       unsigned int enabled)
 {
        struct wm8350 *wm8350 = dev_get_drvdata(dev);
 
-       switch (cmd) {
-       case RTC_AIE_OFF:
-               return wm8350_rtc_stop_alarm(wm8350);
-       case RTC_AIE_ON:
-               return wm8350_rtc_start_alarm(wm8350);
-
-       case RTC_UIE_OFF:
-               wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);
-               break;
-       case RTC_UIE_ON:
+       if (enabled)
                wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_SEC);
-               break;
-
-       default:
-               return -ENOIOCTLCMD;
-       }
+       else
+               wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);
 
        return 0;
 }
@@ -345,11 +341,12 @@ static void wm8350_rtc_update_handler(struct wm8350 *wm8350, int irq,
 }
 
 static const struct rtc_class_ops wm8350_rtc_ops = {
-       .ioctl = wm8350_rtc_ioctl,
        .read_time = wm8350_rtc_readtime,
        .set_time = wm8350_rtc_settime,
        .read_alarm = wm8350_rtc_readalarm,
        .set_alarm = wm8350_rtc_setalarm,
+       .alarm_irq_enable = wm8350_rtc_alarm_irq_enable,
+       .update_irq_enable = wm8350_rtc_update_irq_enable,
 };
 
 #ifdef CONFIG_PM
@@ -440,7 +437,7 @@ static int wm8350_rtc_probe(struct platform_device *pdev)
                do {
                        timectl = wm8350_reg_read(wm8350,
                                                  WM8350_RTC_TIME_CONTROL);
-               } while (timectl & WM8350_RTC_STS && retries--);
+               } while (timectl & WM8350_RTC_STS && --retries);
 
                if (retries == 0) {
                        dev_err(&pdev->dev, "failed to start: timeout\n");
index 2fd64e5a9ab267ae38d6b79454125a41d929ec74..0570794ccf1c8f8d26c89f4d6825abd9d047738e 100644 (file)
@@ -2363,6 +2363,7 @@ int dasd_generic_notify(struct ccw_device *cdev, int event)
        ret = 0;
        switch (event) {
        case CIO_GONE:
+       case CIO_BOXED:
        case CIO_NO_PATH:
                /* First of all call extended error reporting. */
                dasd_eer_write(device, NULL, DASD_EER_NOPATH);
index 2080ba6a69b0ea5b906c0a3bfc1c6ed639651b8b..654daa3cdfda7bcb60ad0f51e4748c8ffdfd0da1 100644 (file)
@@ -320,7 +320,6 @@ dasd_proc_init(void)
        dasd_proc_root_entry = proc_mkdir("dasd", NULL);
        if (!dasd_proc_root_entry)
                goto out_nodasd;
-       dasd_proc_root_entry->owner = THIS_MODULE;
        dasd_devices_entry = proc_create("devices",
                                         S_IFREG | S_IRUGO | S_IWUSR,
                                         dasd_proc_root_entry,
@@ -334,7 +333,6 @@ dasd_proc_init(void)
                goto out_nostatistics;
        dasd_statistics_entry->read_proc = dasd_statistics_read;
        dasd_statistics_entry->write_proc = dasd_statistics_write;
-       dasd_statistics_entry->owner = THIS_MODULE;
        return 0;
 
  out_nostatistics:
index c4d2f667a2f685a8c887ca82d2e3346efb783125..35441fa16be1de86dcb72dd02d8e319da458edde 100644 (file)
@@ -310,8 +310,6 @@ static void ccw_device_remove_orphan_cb(struct work_struct *work)
        put_device(&cdev->dev);
 }
 
-static void ccw_device_call_sch_unregister(struct work_struct *work);
-
 static void
 ccw_device_remove_disconnected(struct ccw_device *cdev)
 {
@@ -335,11 +333,10 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
                spin_unlock_irqrestore(cdev->ccwlock, flags);
                PREPARE_WORK(&cdev->private->kick_work,
                                ccw_device_remove_orphan_cb);
+               queue_work(slow_path_wq, &cdev->private->kick_work);
        } else
                /* Deregister subchannel, which will kill the ccw device. */
-               PREPARE_WORK(&cdev->private->kick_work,
-                               ccw_device_call_sch_unregister);
-       queue_work(slow_path_wq, &cdev->private->kick_work);
+               ccw_device_schedule_sch_unregister(cdev);
 }
 
 /**
@@ -471,7 +468,7 @@ static int online_store_recog_and_online(struct ccw_device *cdev)
        int ret;
 
        /* Do device recognition, if needed. */
-       if (cdev->id.cu_type == 0) {
+       if (cdev->private->state == DEV_STATE_BOXED) {
                ret = ccw_device_recognition(cdev);
                if (ret) {
                        CIO_MSG_EVENT(0, "Couldn't start recognition "
@@ -482,17 +479,21 @@ static int online_store_recog_and_online(struct ccw_device *cdev)
                }
                wait_event(cdev->private->wait_q,
                           cdev->private->flags.recog_done);
+               if (cdev->private->state != DEV_STATE_OFFLINE)
+                       /* recognition failed */
+                       return -EAGAIN;
        }
        if (cdev->drv && cdev->drv->set_online)
                ccw_device_set_online(cdev);
        return 0;
 }
+
 static int online_store_handle_online(struct ccw_device *cdev, int force)
 {
        int ret;
 
        ret = online_store_recog_and_online(cdev);
-       if (ret)
+       if (ret && !force)
                return ret;
        if (force && cdev->private->state == DEV_STATE_BOXED) {
                ret = ccw_device_stlck(cdev);
@@ -500,7 +501,9 @@ static int online_store_handle_online(struct ccw_device *cdev, int force)
                        return ret;
                if (cdev->id.cu_type == 0)
                        cdev->private->state = DEV_STATE_NOT_OPER;
-               online_store_recog_and_online(cdev);
+               ret = online_store_recog_and_online(cdev);
+               if (ret)
+                       return ret;
        }
        return 0;
 }
@@ -512,7 +515,11 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
        int force, ret;
        unsigned long i;
 
-       if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
+       if ((cdev->private->state != DEV_STATE_OFFLINE &&
+            cdev->private->state != DEV_STATE_ONLINE &&
+            cdev->private->state != DEV_STATE_BOXED &&
+            cdev->private->state != DEV_STATE_DISCONNECTED) ||
+           atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
                return -EAGAIN;
 
        if (cdev->drv && !try_module_get(cdev->drv->owner)) {
@@ -1014,6 +1021,13 @@ static void ccw_device_call_sch_unregister(struct work_struct *work)
        put_device(&sch->dev);
 }
 
+void ccw_device_schedule_sch_unregister(struct ccw_device *cdev)
+{
+       PREPARE_WORK(&cdev->private->kick_work,
+                    ccw_device_call_sch_unregister);
+       queue_work(slow_path_wq, &cdev->private->kick_work);
+}
+
 /*
  * subchannel recognition done. Called from the state machine.
  */
@@ -1025,19 +1039,17 @@ io_subchannel_recog_done(struct ccw_device *cdev)
                return;
        }
        switch (cdev->private->state) {
+       case DEV_STATE_BOXED:
+               /* Device did not respond in time. */
        case DEV_STATE_NOT_OPER:
                cdev->private->flags.recog_done = 1;
                /* Remove device found not operational. */
                if (!get_device(&cdev->dev))
                        break;
-               PREPARE_WORK(&cdev->private->kick_work,
-                            ccw_device_call_sch_unregister);
-               queue_work(slow_path_wq, &cdev->private->kick_work);
+               ccw_device_schedule_sch_unregister(cdev);
                if (atomic_dec_and_test(&ccw_device_init_count))
                        wake_up(&ccw_device_init_wq);
                break;
-       case DEV_STATE_BOXED:
-               /* Device did not respond in time. */
        case DEV_STATE_OFFLINE:
                /* 
                 * We can't register the device in interrupt context so
@@ -1551,8 +1563,7 @@ static int purge_fn(struct device *dev, void *data)
                goto out;
        CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", priv->dev_id.ssid,
                      priv->dev_id.devno);
-       PREPARE_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister);
-       queue_work(slow_path_wq, &cdev->private->kick_work);
+       ccw_device_schedule_sch_unregister(cdev);
 
 out:
        /* Abort loop in case of pending signal. */
index 85e01846ca658ca1ea6154985d9b142687937d6d..f1cbbd94ad4e76fbaaba927b1988ede2107d515c 100644 (file)
@@ -87,6 +87,7 @@ int ccw_device_is_orphan(struct ccw_device *);
 int ccw_device_recognition(struct ccw_device *);
 int ccw_device_online(struct ccw_device *);
 int ccw_device_offline(struct ccw_device *);
+void ccw_device_schedule_sch_unregister(struct ccw_device *);
 int ccw_purge_blacklisted(void);
 
 /* Function prototypes for device status and basic sense stuff. */
index 87b4bfca080f86436691f5b08fcb539e37482c74..e46049261561986174c8448714e811ef6344a092 100644 (file)
@@ -256,13 +256,12 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                old_lpm = 0;
        if (sch->lpm != old_lpm)
                __recover_lost_chpids(sch, old_lpm);
-       if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) {
-               if (state == DEV_STATE_NOT_OPER) {
-                       cdev->private->flags.recog_done = 1;
-                       cdev->private->state = DEV_STATE_DISCONNECTED;
-                       return;
-               }
-               /* Boxed devices don't need extra treatment. */
+       if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID &&
+           (state == DEV_STATE_NOT_OPER || state == DEV_STATE_BOXED)) {
+               cdev->private->flags.recog_done = 1;
+               cdev->private->state = DEV_STATE_DISCONNECTED;
+               wake_up(&cdev->private->wait_q);
+               return;
        }
        notify = 0;
        same_dev = 0; /* Keep the compiler quiet... */
@@ -274,7 +273,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                              sch->schid.ssid, sch->schid.sch_no);
                break;
        case DEV_STATE_OFFLINE:
-               if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) {
+               if (cdev->online) {
                        same_dev = ccw_device_handle_oper(cdev);
                        notify = 1;
                }
@@ -307,12 +306,17 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                              " subchannel 0.%x.%04x\n",
                              cdev->private->dev_id.devno,
                              sch->schid.ssid, sch->schid.sch_no);
+               if (cdev->id.cu_type != 0) { /* device was recognized before */
+                       cdev->private->flags.recog_done = 1;
+                       cdev->private->state = DEV_STATE_BOXED;
+                       wake_up(&cdev->private->wait_q);
+                       return;
+               }
                break;
        }
        cdev->private->state = state;
        io_subchannel_recog_done(cdev);
-       if (state != DEV_STATE_NOT_OPER)
-               wake_up(&cdev->private->wait_q);
+       wake_up(&cdev->private->wait_q);
 }
 
 /*
@@ -390,10 +394,13 @@ ccw_device_done(struct ccw_device *cdev, int state)
 
        cdev->private->state = state;
 
-
-       if (state == DEV_STATE_BOXED)
+       if (state == DEV_STATE_BOXED) {
                CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n",
                              cdev->private->dev_id.devno, sch->schid.sch_no);
+               if (cdev->online && !ccw_device_notify(cdev, CIO_BOXED))
+                       ccw_device_schedule_sch_unregister(cdev);
+               cdev->private->flags.donotify = 0;
+       }
 
        if (cdev->private->flags.donotify) {
                cdev->private->flags.donotify = 0;
diff --git a/drivers/s390/net/qeth_core_offl.c b/drivers/s390/net/qeth_core_offl.c
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/drivers/s390/net/qeth_core_offl.h b/drivers/s390/net/qeth_core_offl.h
deleted file mode 100644 (file)
index e69de29..0000000
index 1fe1e2eda5121187ecc9d060647c6159afb3cbf1..cfb0dcb6e3ff365354c85238c861140f60987577 100644 (file)
@@ -176,6 +176,11 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
                zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
                                        "ccnoti4", NULL);
                break;
+       case CIO_BOXED:
+               dev_warn(&adapter->ccw_device->dev,
+                        "The ccw device did not respond in time.\n");
+               zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL);
+               break;
        }
        return 1;
 }
index aab8123c59664f6b51098080868342b46001c73c..e8d032b9dfbd2a54668658a88db23b7ef76e4364 100644 (file)
@@ -94,7 +94,7 @@ static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port)
 
 static void zfcp_wka_port_offline(struct work_struct *work)
 {
-       struct delayed_work *dw = container_of(work, struct delayed_work, work);
+       struct delayed_work *dw = to_delayed_work(work);
        struct zfcp_wka_port *wka_port =
                        container_of(dw, struct zfcp_wka_port, work);
 
index 099b5455bbce287f60ef888566913616f13e9908..b13481369642f272c34d7e021f2c32365177fb7c 100644 (file)
@@ -596,8 +596,6 @@ int __init scsi_init_devinfo(void)
                error = -ENOMEM;
                goto out;
        }
-
-       p->owner = THIS_MODULE;
 #endif /* CONFIG_SCSI_PROC_FS */
 
  out:
index 82f7b2dd08a23e934aa4d6e08ce76e3c84ab1dc4..77fbddb507fdcb65b5d4fc940e6780ae756f6da9 100644 (file)
@@ -115,8 +115,6 @@ void scsi_proc_hostdir_add(struct scsi_host_template *sht)
                if (!sht->proc_dir)
                        printk(KERN_ERR "%s: proc_mkdir failed for %s\n",
                               __func__, sht->proc_name);
-               else
-                       sht->proc_dir->owner = sht->module;
        }
        mutex_unlock(&global_host_template_mutex);
 }
@@ -163,7 +161,6 @@ void scsi_proc_host_add(struct Scsi_Host *shost)
        } 
 
        p->write_proc = proc_scsi_write_proc;
-       p->owner = sht->module;
 }
 
 /**
index bde4b4b0b80f08efe1f2c5db4da2fb7e0e61b9b5..5c6ef51da274db66b60e2e83cd2195044b55d252 100644 (file)
@@ -406,6 +406,18 @@ static int cpm_uart_startup(struct uart_port *port)
 
        pr_debug("CPM uart[%d]:startup\n", port->line);
 
+       /* If the port is not the console, make sure rx is disabled. */
+       if (!(pinfo->flags & FLAG_CONSOLE)) {
+               /* Disable UART rx */
+               if (IS_SMC(pinfo)) {
+                       clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN);
+                       clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX);
+               } else {
+                       clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR);
+                       clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
+               }
+               cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
+       }
        /* Install interrupt handler. */
        retval = request_irq(port->irq, cpm_uart_int, 0, "cpm_uart", port);
        if (retval)
@@ -420,8 +432,6 @@ static int cpm_uart_startup(struct uart_port *port)
                setbits32(&pinfo->sccp->scc_gsmrl, (SCC_GSMRL_ENR | SCC_GSMRL_ENT));
        }
 
-       if (!(pinfo->flags & FLAG_CONSOLE))
-               cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
        return 0;
 }
 
index 0c3a2ab1612c25b38b1b9a8f40d933e51792bbc4..7f72f8ceaa6f0ace5bbfac731662999081b4ebc5 100644 (file)
@@ -50,8 +50,8 @@
 /* OF Platform device Usage :
  *
  * This driver is only used for PSCs configured in uart mode.  The device
- * tree will have a node for each PSC in uart mode w/ device_type = "serial"
- * and "mpc52xx-psc-uart" in the compatible string
+ * tree will have a node for each PSC with "mpc52xx-psc-uart" in the compatible
+ * list.
  *
  * By default, PSC devices are enumerated in the order they are found.  However
  * a particular PSC number can be forces by adding 'device_no = <port#>'
@@ -522,7 +522,7 @@ mpc52xx_uart_startup(struct uart_port *port)
 
        /* Request IRQ */
        ret = request_irq(port->irq, mpc52xx_uart_int,
-               IRQF_DISABLED | IRQF_SAMPLE_RANDOM | IRQF_SHARED,
+               IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
                "mpc52xx_psc_uart", port);
        if (ret)
                return ret;
@@ -1212,30 +1212,18 @@ mpc52xx_uart_of_resume(struct of_device *op)
 #endif
 
 static void
-mpc52xx_uart_of_assign(struct device_node *np, int idx)
+mpc52xx_uart_of_assign(struct device_node *np)
 {
-       int free_idx = -1;
        int i;
 
-       /* Find the first free node */
+       /* Find the first free PSC number */
        for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
                if (mpc52xx_uart_nodes[i] == NULL) {
-                       free_idx = i;
-                       break;
+                       of_node_get(np);
+                       mpc52xx_uart_nodes[i] = np;
+                       return;
                }
        }
-
-       if ((idx < 0) || (idx >= MPC52xx_PSC_MAXNUM))
-               idx = free_idx;
-
-       if (idx < 0)
-               return; /* No free slot; abort */
-
-       of_node_get(np);
-       /* If the slot is already occupied, then swap slots */
-       if (mpc52xx_uart_nodes[idx] && (free_idx != -1))
-               mpc52xx_uart_nodes[free_idx] = mpc52xx_uart_nodes[idx];
-       mpc52xx_uart_nodes[idx] = np;
 }
 
 static void
@@ -1243,23 +1231,17 @@ mpc52xx_uart_of_enumerate(void)
 {
        static int enum_done;
        struct device_node *np;
-       const unsigned int *devno;
        const struct  of_device_id *match;
        int i;
 
        if (enum_done)
                return;
 
-       for_each_node_by_type(np, "serial") {
+       /* Assign index to each PSC in device tree */
+       for_each_matching_node(np, mpc52xx_uart_of_match) {
                match = of_match_node(mpc52xx_uart_of_match, np);
-               if (!match)
-                       continue;
-
                psc_ops = match->data;
-
-               /* Is a particular device number requested? */
-               devno = of_get_property(np, "port-number", NULL);
-               mpc52xx_uart_of_assign(np, devno ? *devno : -1);
+               mpc52xx_uart_of_assign(np);
        }
 
        enum_done = 1;
index 42f4e66fccafeb40cb9b97833d2a3e9da522fa89..b0bb29d804ae43620c7d0ce1ba5c94cc9f11a28a 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/console.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/serial_core.h>
 #include <linux/smp_lock.h>
 #include <linux/device.h>
@@ -1682,20 +1684,20 @@ static const char *uart_type(struct uart_port *port)
 
 #ifdef CONFIG_PROC_FS
 
-static int uart_line_info(char *buf, struct uart_driver *drv, int i)
+static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
 {
        struct uart_state *state = drv->state + i;
        int pm_state;
        struct uart_port *port = state->port;
        char stat_buf[32];
        unsigned int status;
-       int mmio, ret;
+       int mmio;
 
        if (!port)
-               return 0;
+               return;
 
        mmio = port->iotype >= UPIO_MEM;
-       ret = sprintf(buf, "%d: uart:%s %s%08llX irq:%d",
+       seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
                        port->line, uart_type(port),
                        mmio ? "mmio:0x" : "port:",
                        mmio ? (unsigned long long)port->mapbase
@@ -1703,8 +1705,8 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i)
                        port->irq);
 
        if (port->type == PORT_UNKNOWN) {
-               strcat(buf, "\n");
-               return ret + 1;
+               seq_putc(m, '\n');
+               return;
        }
 
        if (capable(CAP_SYS_ADMIN)) {
@@ -1719,19 +1721,19 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i)
                        uart_change_pm(state, pm_state);
                mutex_unlock(&state->mutex);
 
-               ret += sprintf(buf + ret, " tx:%d rx:%d",
+               seq_printf(m, " tx:%d rx:%d",
                                port->icount.tx, port->icount.rx);
                if (port->icount.frame)
-                       ret += sprintf(buf + ret, " fe:%d",
+                       seq_printf(m, " fe:%d",
                                port->icount.frame);
                if (port->icount.parity)
-                       ret += sprintf(buf + ret, " pe:%d",
+                       seq_printf(m, " pe:%d",
                                port->icount.parity);
                if (port->icount.brk)
-                       ret += sprintf(buf + ret, " brk:%d",
+                       seq_printf(m, " brk:%d",
                                port->icount.brk);
                if (port->icount.overrun)
-                       ret += sprintf(buf + ret, " oe:%d",
+                       seq_printf(m, " oe:%d",
                                port->icount.overrun);
 
 #define INFOBIT(bit, str) \
@@ -1753,45 +1755,39 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i)
                STATBIT(TIOCM_RNG, "|RI");
                if (stat_buf[0])
                        stat_buf[0] = ' ';
-               strcat(stat_buf, "\n");
 
-               ret += sprintf(buf + ret, stat_buf);
-       } else {
-               strcat(buf, "\n");
-               ret++;
+               seq_puts(m, stat_buf);
        }
+       seq_putc(m, '\n');
 #undef STATBIT
 #undef INFOBIT
-       return ret;
 }
 
-static int uart_read_proc(char *page, char **start, off_t off,
-                         int count, int *eof, void *data)
+static int uart_proc_show(struct seq_file *m, void *v)
 {
-       struct tty_driver *ttydrv = data;
+       struct tty_driver *ttydrv = m->private;
        struct uart_driver *drv = ttydrv->driver_state;
-       int i, len = 0, l;
-       off_t begin = 0;
+       int i;
 
-       len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n",
+       seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n",
                        "", "", "");
-       for (i = 0; i < drv->nr && len < PAGE_SIZE - 96; i++) {
-               l = uart_line_info(page + len, drv, i);
-               len += l;
-               if (len + begin > off + count)
-                       goto done;
-               if (len + begin < off) {
-                       begin += len;
-                       len = 0;
-               }
-       }
-       *eof = 1;
- done:
-       if (off >= len + begin)
-               return 0;
-       *start = page + (off - begin);
-       return (count < begin + len - off) ? count : (begin + len - off);
+       for (i = 0; i < drv->nr; i++)
+               uart_line_info(m, drv, i);
+       return 0;
 }
+
+static int uart_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, uart_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations uart_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = uart_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 #endif
 
 #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
@@ -2299,7 +2295,7 @@ static const struct tty_operations uart_ops = {
        .break_ctl      = uart_break_ctl,
        .wait_until_sent= uart_wait_until_sent,
 #ifdef CONFIG_PROC_FS
-       .read_proc      = uart_read_proc,
+       .proc_fops      = &uart_proc_fops,
 #endif
        .tiocmget       = uart_tiocmget,
        .tiocmset       = uart_tiocmset,
index cab1ab7cfb789204f70924975fc78b94bafe802a..93c20e135ee1a8412e6d4162572926e904a90f02 100644 (file)
@@ -776,7 +776,7 @@ static struct maple_driver maple_unsupported_device = {
                .bus = &maple_bus_type,
        },
 };
-/**
+/*
  * maple_bus_type - core maple bus structure
  */
 struct bus_type maple_bus_type = {
index d2866c293dee0a5f160e5342755ffc8be525f351..26bd03e61855fba412726f23b638066a90abcaa9 100644 (file)
@@ -178,8 +178,10 @@ static void spi_gpio_chipselect(struct spi_device *spi, int is_active)
        if (is_active)
                setsck(spi, spi->mode & SPI_CPOL);
 
-       /* SPI is normally active-low */
-       gpio_set_value(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
+       if (cs != SPI_GPIO_NO_CHIPSELECT) {
+               /* SPI is normally active-low */
+               gpio_set_value(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
+       }
 }
 
 static int spi_gpio_setup(struct spi_device *spi)
@@ -191,15 +193,17 @@ static int spi_gpio_setup(struct spi_device *spi)
                return -EINVAL;
 
        if (!spi->controller_state) {
-               status = gpio_request(cs, dev_name(&spi->dev));
-               if (status)
-                       return status;
-               status = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH);
+               if (cs != SPI_GPIO_NO_CHIPSELECT) {
+                       status = gpio_request(cs, dev_name(&spi->dev));
+                       if (status)
+                               return status;
+                       status = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH);
+               }
        }
        if (!status)
                status = spi_bitbang_setup(spi);
        if (status) {
-               if (!spi->controller_state)
+               if (!spi->controller_state && cs != SPI_GPIO_NO_CHIPSELECT)
                        gpio_free(cs);
        }
        return status;
@@ -209,7 +213,8 @@ static void spi_gpio_cleanup(struct spi_device *spi)
 {
        unsigned long   cs = (unsigned long) spi->controller_data;
 
-       gpio_free(cs);
+       if (cs != SPI_GPIO_NO_CHIPSELECT)
+               gpio_free(cs);
        spi_bitbang_cleanup(spi);
 }
 
index 44a2b46ccb795e8d6dd8ccef2f43dcad482d5ef1..f4573a96af2459620b0b4b4d5f09c6f87acaf11a 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/completion.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/spi/spi_bitbang.h>
 #include <linux/platform_device.h>
 #include <linux/fsl_devices.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_spi.h>
 
+#include <sysdev/fsl_soc.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
@@ -79,7 +87,7 @@ struct mpc83xx_spi {
        u32(*get_tx) (struct mpc83xx_spi *);
 
        unsigned int count;
-       int irq;
+       unsigned int irq;
 
        unsigned nsecs;         /* (clock cycle time)/2 */
 
@@ -89,9 +97,6 @@ struct mpc83xx_spi {
 
        bool qe_mode;
 
-       void (*activate_cs) (u8 cs, u8 polarity);
-       void (*deactivate_cs) (u8 cs, u8 polarity);
-
        u8 busy;
 
        struct workqueue_struct *workqueue;
@@ -123,6 +128,7 @@ static inline u32 mpc83xx_spi_read_reg(__be32 __iomem * reg)
 }
 
 #define MPC83XX_SPI_RX_BUF(type)                                         \
+static                                                                   \
 void mpc83xx_spi_rx_buf_##type(u32 data, struct mpc83xx_spi *mpc83xx_spi) \
 {                                                                        \
        type * rx = mpc83xx_spi->rx;                                      \
@@ -131,6 +137,7 @@ void mpc83xx_spi_rx_buf_##type(u32 data, struct mpc83xx_spi *mpc83xx_spi) \
 }
 
 #define MPC83XX_SPI_TX_BUF(type)                               \
+static                                                         \
 u32 mpc83xx_spi_tx_buf_##type(struct mpc83xx_spi *mpc83xx_spi) \
 {                                                              \
        u32 data;                                               \
@@ -151,15 +158,14 @@ MPC83XX_SPI_TX_BUF(u32)
 
 static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
 {
-       struct mpc83xx_spi *mpc83xx_spi;
-       u8 pol = spi->mode & SPI_CS_HIGH ? 1 : 0;
+       struct mpc83xx_spi *mpc83xx_spi = spi_master_get_devdata(spi->master);
+       struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data;
+       bool pol = spi->mode & SPI_CS_HIGH;
        struct spi_mpc83xx_cs   *cs = spi->controller_state;
 
-       mpc83xx_spi = spi_master_get_devdata(spi->master);
-
        if (value == BITBANG_CS_INACTIVE) {
-               if (mpc83xx_spi->deactivate_cs)
-                       mpc83xx_spi->deactivate_cs(spi->chip_select, pol);
+               if (pdata->cs_control)
+                       pdata->cs_control(spi, !pol);
        }
 
        if (value == BITBANG_CS_ACTIVE) {
@@ -172,7 +178,7 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
 
                if (cs->hw_mode != regval) {
                        unsigned long flags;
-                       void *tmp_ptr = &mpc83xx_spi->base->mode;
+                       __be32 __iomem *mode = &mpc83xx_spi->base->mode;
 
                        regval = cs->hw_mode;
                        /* Turn off IRQs locally to minimize time that
@@ -180,12 +186,12 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
                         */
                        local_irq_save(flags);
                        /* Turn off SPI unit prior changing mode */
-                       mpc83xx_spi_write_reg(tmp_ptr, regval & ~SPMODE_ENABLE);
-                       mpc83xx_spi_write_reg(tmp_ptr, regval);
+                       mpc83xx_spi_write_reg(mode, regval & ~SPMODE_ENABLE);
+                       mpc83xx_spi_write_reg(mode, regval);
                        local_irq_restore(flags);
                }
-               if (mpc83xx_spi->activate_cs)
-                       mpc83xx_spi->activate_cs(spi->chip_select, pol);
+               if (pdata->cs_control)
+                       pdata->cs_control(spi, pol);
        }
 }
 
@@ -284,7 +290,7 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
        regval =  mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
        if (cs->hw_mode != regval) {
                unsigned long flags;
-               void *tmp_ptr = &mpc83xx_spi->base->mode;
+               __be32 __iomem *mode = &mpc83xx_spi->base->mode;
 
                regval = cs->hw_mode;
                /* Turn off IRQs locally to minimize time
@@ -292,8 +298,8 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
                 */
                local_irq_save(flags);
                /* Turn off SPI unit prior changing mode */
-               mpc83xx_spi_write_reg(tmp_ptr, regval & ~SPMODE_ENABLE);
-               mpc83xx_spi_write_reg(tmp_ptr, regval);
+               mpc83xx_spi_write_reg(mode, regval & ~SPMODE_ENABLE);
+               mpc83xx_spi_write_reg(mode, regval);
                local_irq_restore(flags);
        }
        return 0;
@@ -483,7 +489,7 @@ static int mpc83xx_spi_setup(struct spi_device *spi)
        return 0;
 }
 
-irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data)
+static irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data)
 {
        struct mpc83xx_spi *mpc83xx_spi = context_data;
        u32 event;
@@ -545,43 +551,28 @@ static void mpc83xx_spi_cleanup(struct spi_device *spi)
        kfree(spi->controller_state);
 }
 
-static int __init mpc83xx_spi_probe(struct platform_device *dev)
+static struct spi_master * __devinit
+mpc83xx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
 {
+       struct fsl_spi_platform_data *pdata = dev->platform_data;
        struct spi_master *master;
        struct mpc83xx_spi *mpc83xx_spi;
-       struct fsl_spi_platform_data *pdata;
-       struct resource *r;
        u32 regval;
        int ret = 0;
 
-       /* Get resources(memory, IRQ) associated with the device */
-       master = spi_alloc_master(&dev->dev, sizeof(struct mpc83xx_spi));
-
+       master = spi_alloc_master(dev, sizeof(struct mpc83xx_spi));
        if (master == NULL) {
                ret = -ENOMEM;
                goto err;
        }
 
-       platform_set_drvdata(dev, master);
-       pdata = dev->dev.platform_data;
+       dev_set_drvdata(dev, master);
 
-       if (pdata == NULL) {
-               ret = -ENODEV;
-               goto free_master;
-       }
-
-       r = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (r == NULL) {
-               ret = -ENODEV;
-               goto free_master;
-       }
        master->setup = mpc83xx_spi_setup;
        master->transfer = mpc83xx_spi_transfer;
        master->cleanup = mpc83xx_spi_cleanup;
 
        mpc83xx_spi = spi_master_get_devdata(master);
-       mpc83xx_spi->activate_cs = pdata->activate_cs;
-       mpc83xx_spi->deactivate_cs = pdata->deactivate_cs;
        mpc83xx_spi->qe_mode = pdata->qe_mode;
        mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
        mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
@@ -596,18 +587,13 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
 
        init_completion(&mpc83xx_spi->done);
 
-       mpc83xx_spi->base = ioremap(r->start, r->end - r->start + 1);
+       mpc83xx_spi->base = ioremap(mem->start, mem->end - mem->start + 1);
        if (mpc83xx_spi->base == NULL) {
                ret = -ENOMEM;
                goto put_master;
        }
 
-       mpc83xx_spi->irq = platform_get_irq(dev, 0);
-
-       if (mpc83xx_spi->irq < 0) {
-               ret = -ENXIO;
-               goto unmap_io;
-       }
+       mpc83xx_spi->irq = irq;
 
        /* Register for SPI Interrupt */
        ret = request_irq(mpc83xx_spi->irq, mpc83xx_spi_irq,
@@ -649,9 +635,9 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
 
        printk(KERN_INFO
               "%s: MPC83xx SPI Controller driver at 0x%p (irq = %d)\n",
-              dev_name(&dev->dev), mpc83xx_spi->base, mpc83xx_spi->irq);
+              dev_name(dev), mpc83xx_spi->base, mpc83xx_spi->irq);
 
-       return ret;
+       return master;
 
 unreg_master:
        destroy_workqueue(mpc83xx_spi->workqueue);
@@ -661,18 +647,16 @@ unmap_io:
        iounmap(mpc83xx_spi->base);
 put_master:
        spi_master_put(master);
-free_master:
-       kfree(master);
 err:
-       return ret;
+       return ERR_PTR(ret);
 }
 
-static int __exit mpc83xx_spi_remove(struct platform_device *dev)
+static int __devexit mpc83xx_spi_remove(struct device *dev)
 {
        struct mpc83xx_spi *mpc83xx_spi;
        struct spi_master *master;
 
-       master = platform_get_drvdata(dev);
+       master = dev_get_drvdata(dev);
        mpc83xx_spi = spi_master_get_devdata(master);
 
        flush_workqueue(mpc83xx_spi->workqueue);
@@ -685,23 +669,293 @@ static int __exit mpc83xx_spi_remove(struct platform_device *dev)
        return 0;
 }
 
+struct mpc83xx_spi_probe_info {
+       struct fsl_spi_platform_data pdata;
+       int *gpios;
+       bool *alow_flags;
+};
+
+static struct mpc83xx_spi_probe_info *
+to_of_pinfo(struct fsl_spi_platform_data *pdata)
+{
+       return container_of(pdata, struct mpc83xx_spi_probe_info, pdata);
+}
+
+static void mpc83xx_spi_cs_control(struct spi_device *spi, bool on)
+{
+       struct device *dev = spi->dev.parent;
+       struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
+       u16 cs = spi->chip_select;
+       int gpio = pinfo->gpios[cs];
+       bool alow = pinfo->alow_flags[cs];
+
+       gpio_set_value(gpio, on ^ alow);
+}
+
+static int of_mpc83xx_spi_get_chipselects(struct device *dev)
+{
+       struct device_node *np = dev_archdata_get_node(&dev->archdata);
+       struct fsl_spi_platform_data *pdata = dev->platform_data;
+       struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(pdata);
+       unsigned int ngpios;
+       int i = 0;
+       int ret;
+
+       ngpios = of_gpio_count(np);
+       if (!ngpios) {
+               /*
+                * SPI w/o chip-select line. One SPI device is still permitted
+                * though.
+                */
+               pdata->max_chipselect = 1;
+               return 0;
+       }
+
+       pinfo->gpios = kmalloc(ngpios * sizeof(pinfo->gpios), GFP_KERNEL);
+       if (!pinfo->gpios)
+               return -ENOMEM;
+       memset(pinfo->gpios, -1, ngpios * sizeof(pinfo->gpios));
+
+       pinfo->alow_flags = kzalloc(ngpios * sizeof(pinfo->alow_flags),
+                                   GFP_KERNEL);
+       if (!pinfo->alow_flags) {
+               ret = -ENOMEM;
+               goto err_alloc_flags;
+       }
+
+       for (; i < ngpios; i++) {
+               int gpio;
+               enum of_gpio_flags flags;
+
+               gpio = of_get_gpio_flags(np, i, &flags);
+               if (!gpio_is_valid(gpio)) {
+                       dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
+                       goto err_loop;
+               }
+
+               ret = gpio_request(gpio, dev_name(dev));
+               if (ret) {
+                       dev_err(dev, "can't request gpio #%d: %d\n", i, ret);
+                       goto err_loop;
+               }
+
+               pinfo->gpios[i] = gpio;
+               pinfo->alow_flags[i] = flags & OF_GPIO_ACTIVE_LOW;
+
+               ret = gpio_direction_output(pinfo->gpios[i],
+                                           pinfo->alow_flags[i]);
+               if (ret) {
+                       dev_err(dev, "can't set output direction for gpio "
+                               "#%d: %d\n", i, ret);
+                       goto err_loop;
+               }
+       }
+
+       pdata->max_chipselect = ngpios;
+       pdata->cs_control = mpc83xx_spi_cs_control;
+
+       return 0;
+
+err_loop:
+       while (i >= 0) {
+               if (gpio_is_valid(pinfo->gpios[i]))
+                       gpio_free(pinfo->gpios[i]);
+               i--;
+       }
+
+       kfree(pinfo->alow_flags);
+       pinfo->alow_flags = NULL;
+err_alloc_flags:
+       kfree(pinfo->gpios);
+       pinfo->gpios = NULL;
+       return ret;
+}
+
+static int of_mpc83xx_spi_free_chipselects(struct device *dev)
+{
+       struct fsl_spi_platform_data *pdata = dev->platform_data;
+       struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(pdata);
+       int i;
+
+       if (!pinfo->gpios)
+               return 0;
+
+       for (i = 0; i < pdata->max_chipselect; i++) {
+               if (gpio_is_valid(pinfo->gpios[i]))
+                       gpio_free(pinfo->gpios[i]);
+       }
+
+       kfree(pinfo->gpios);
+       kfree(pinfo->alow_flags);
+       return 0;
+}
+
+static int __devinit of_mpc83xx_spi_probe(struct of_device *ofdev,
+                                         const struct of_device_id *ofid)
+{
+       struct device *dev = &ofdev->dev;
+       struct device_node *np = ofdev->node;
+       struct mpc83xx_spi_probe_info *pinfo;
+       struct fsl_spi_platform_data *pdata;
+       struct spi_master *master;
+       struct resource mem;
+       struct resource irq;
+       const void *prop;
+       int ret = -ENOMEM;
+
+       pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
+       if (!pinfo)
+               return -ENOMEM;
+
+       pdata = &pinfo->pdata;
+       dev->platform_data = pdata;
+
+       /* Allocate bus num dynamically. */
+       pdata->bus_num = -1;
+
+       /* SPI controller is either clocked from QE or SoC clock. */
+       pdata->sysclk = get_brgfreq();
+       if (pdata->sysclk == -1) {
+               pdata->sysclk = fsl_get_sys_freq();
+               if (pdata->sysclk == -1) {
+                       ret = -ENODEV;
+                       goto err_clk;
+               }
+       }
+
+       prop = of_get_property(np, "mode", NULL);
+       if (prop && !strcmp(prop, "cpu-qe"))
+               pdata->qe_mode = 1;
+
+       ret = of_mpc83xx_spi_get_chipselects(dev);
+       if (ret)
+               goto err;
+
+       ret = of_address_to_resource(np, 0, &mem);
+       if (ret)
+               goto err;
+
+       ret = of_irq_to_resource(np, 0, &irq);
+       if (!ret) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       master = mpc83xx_spi_probe(dev, &mem, irq.start);
+       if (IS_ERR(master)) {
+               ret = PTR_ERR(master);
+               goto err;
+       }
+
+       of_register_spi_devices(master, np);
+
+       return 0;
+
+err:
+       of_mpc83xx_spi_free_chipselects(dev);
+err_clk:
+       kfree(pinfo);
+       return ret;
+}
+
+static int __devexit of_mpc83xx_spi_remove(struct of_device *ofdev)
+{
+       int ret;
+
+       ret = mpc83xx_spi_remove(&ofdev->dev);
+       if (ret)
+               return ret;
+       of_mpc83xx_spi_free_chipselects(&ofdev->dev);
+       return 0;
+}
+
+static const struct of_device_id of_mpc83xx_spi_match[] = {
+       { .compatible = "fsl,spi" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, of_mpc83xx_spi_match);
+
+static struct of_platform_driver of_mpc83xx_spi_driver = {
+       .name           = "mpc83xx_spi",
+       .match_table    = of_mpc83xx_spi_match,
+       .probe          = of_mpc83xx_spi_probe,
+       .remove         = __devexit_p(of_mpc83xx_spi_remove),
+};
+
+#ifdef CONFIG_MPC832x_RDB
+/*
+ *                             XXX XXX XXX
+ * This is "legacy" platform driver, was used by the MPC8323E-RDB boards
+ * only. The driver should go away soon, since newer MPC8323E-RDB's device
+ * tree can work with OpenFirmware driver. But for now we support old trees
+ * as well.
+ */
+static int __devinit plat_mpc83xx_spi_probe(struct platform_device *pdev)
+{
+       struct resource *mem;
+       unsigned int irq;
+       struct spi_master *master;
+
+       if (!pdev->dev.platform_data)
+               return -EINVAL;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem)
+               return -EINVAL;
+
+       irq = platform_get_irq(pdev, 0);
+       if (!irq)
+               return -EINVAL;
+
+       master = mpc83xx_spi_probe(&pdev->dev, mem, irq);
+       if (IS_ERR(master))
+               return PTR_ERR(master);
+       return 0;
+}
+
+static int __devexit plat_mpc83xx_spi_remove(struct platform_device *pdev)
+{
+       return mpc83xx_spi_remove(&pdev->dev);
+}
+
 MODULE_ALIAS("platform:mpc83xx_spi");
 static struct platform_driver mpc83xx_spi_driver = {
-       .remove = __exit_p(mpc83xx_spi_remove),
+       .probe = plat_mpc83xx_spi_probe,
+       .remove = __exit_p(plat_mpc83xx_spi_remove),
        .driver = {
                .name = "mpc83xx_spi",
                .owner = THIS_MODULE,
        },
 };
 
+static bool legacy_driver_failed;
+
+static void __init legacy_driver_register(void)
+{
+       legacy_driver_failed = platform_driver_register(&mpc83xx_spi_driver);
+}
+
+static void __exit legacy_driver_unregister(void)
+{
+       if (legacy_driver_failed)
+               return;
+       platform_driver_unregister(&mpc83xx_spi_driver);
+}
+#else
+static void __init legacy_driver_register(void) {}
+static void __exit legacy_driver_unregister(void) {}
+#endif /* CONFIG_MPC832x_RDB */
+
 static int __init mpc83xx_spi_init(void)
 {
-       return platform_driver_probe(&mpc83xx_spi_driver, mpc83xx_spi_probe);
+       legacy_driver_register();
+       return of_register_platform_driver(&of_mpc83xx_spi_driver);
 }
 
 static void __exit mpc83xx_spi_exit(void)
 {
-       platform_driver_unregister(&mpc83xx_spi_driver);
+       of_unregister_platform_driver(&of_mpc83xx_spi_driver);
+       legacy_driver_unregister();
 }
 
 module_init(mpc83xx_spi_init);
index fe7e5f35e5d0393ccd04bac2993413ee2d26bf1a..494d3f756e292905dee3dd979b163b00f0a5c338 100644 (file)
@@ -354,7 +354,7 @@ static int __init xilinx_spi_of_probe(struct of_device *ofdev,
        if (xspi->regs == NULL) {
                rc = -ENOMEM;
                dev_warn(&ofdev->dev, "ioremap failure\n");
-               goto put_master;
+               goto release_mem;
        }
        xspi->irq = r_irq->start;
 
@@ -365,7 +365,7 @@ static int __init xilinx_spi_of_probe(struct of_device *ofdev,
        prop = of_get_property(ofdev->node, "xlnx,num-ss-bits", &len);
        if (!prop || len < sizeof(*prop)) {
                dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
-               goto put_master;
+               goto unmap_io;
        }
        master->num_chipselect = *prop;
 
@@ -397,6 +397,8 @@ free_irq:
        free_irq(xspi->irq, xspi);
 unmap_io:
        iounmap(xspi->regs);
+release_mem:
+       release_mem_region(r_mem->start, resource_size(r_mem));
 put_master:
        spi_master_put(master);
        return rc;
@@ -406,6 +408,7 @@ static int __devexit xilinx_spi_remove(struct of_device *ofdev)
 {
        struct xilinx_spi *xspi;
        struct spi_master *master;
+       struct resource r_mem;
 
        master = platform_get_drvdata(ofdev);
        xspi = spi_master_get_devdata(master);
@@ -413,6 +416,8 @@ static int __devexit xilinx_spi_remove(struct of_device *ofdev)
        spi_bitbang_stop(&xspi->bitbang);
        free_irq(xspi->irq, xspi);
        iounmap(xspi->regs);
+       if (!of_address_to_resource(ofdev->node, 0, &r_mem))
+               release_mem_region(r_mem.start, resource_size(&r_mem));
        dev_set_drvdata(&ofdev->dev, 0);
        spi_master_put(xspi->bitbang.master);
 
index e5752f615e0970d725cc3c005712547d5216092e..80f9cc7137c2dfe33818ee635992ac8cf744fc78 100644 (file)
@@ -719,7 +719,7 @@ void ieee80211_softmac_scan(struct ieee80211_device *ieee)
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
 void ieee80211_softmac_scan_wq(struct work_struct *work)
 {
-       struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+       struct delayed_work *dwork = to_delayed_work(work);
        struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq);
 #else
 void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee)
@@ -777,7 +777,7 @@ out:
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
 void ieee80211_softmac_scan_wq(struct work_struct *work)
 {
-        struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+       struct delayed_work *dwork = to_delayed_work(work);
         struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, softmac_scan_wq);
 #else
 void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee)
@@ -2980,7 +2980,7 @@ void ieee80211_start_monitor_mode(struct ieee80211_device *ieee)
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
 void ieee80211_start_ibss_wq(struct work_struct *work)
 {
-       struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+       struct delayed_work *dwork = to_delayed_work(work);
        struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, start_ibss_wq);
 #else
 void ieee80211_start_ibss_wq(struct ieee80211_device *ieee)
@@ -3162,7 +3162,7 @@ void ieee80211_disassociate(struct ieee80211_device *ieee)
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
 void ieee80211_associate_retry_wq(struct work_struct *work)
 {
-       struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+       struct delayed_work *dwork = to_delayed_work(work);
        struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, associate_retry_wq);
 #else
 void ieee80211_associate_retry_wq(struct ieee80211_device *ieee)
index 66de5cc8ddf119a85d4b66c4829bfe4c97422b90..ff1f23f99f2743fff971d7b4a6bb7d48aecb88cf 100644 (file)
@@ -5438,7 +5438,7 @@ void rtl8180_hw_wakeup_wq (struct work_struct *work)
 //     struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq);
 //     struct ieee80211_device * ieee = (struct ieee80211_device*)
 //                                            container_of(work, struct ieee80211_device, watch_dog_wq);
-       struct delayed_work *dwork = container_of(work,struct delayed_work,work);
+       struct delayed_work *dwork = to_delayed_work(work);
        struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_wakeup_wq);
        struct net_device *dev = ieee->dev;
 #else
@@ -5459,7 +5459,7 @@ void rtl8180_hw_sleep_wq (struct work_struct *work)
 //      struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq);
 //      struct ieee80211_device * ieee = (struct ieee80211_device*)
 //                                             container_of(work, struct ieee80211_device, watch_dog_wq);
-        struct delayed_work *dwork = container_of(work,struct delayed_work,work);
+       struct delayed_work *dwork = to_delayed_work(work);
         struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_sleep_wq);
         struct net_device *dev = ieee->dev;
 #else
@@ -6407,7 +6407,7 @@ priv->txnpring)/8);
 void rtl8180_tx_irq_wq(struct work_struct *work)
 {
        //struct r8180_priv *priv = container_of(work, struct r8180_priv, reset_wq);
-        struct delayed_work *dwork = container_of(work,struct delayed_work,work);
+       struct delayed_work *dwork = to_delayed_work(work);
        struct ieee80211_device * ieee = (struct ieee80211_device*)
                                               container_of(dwork, struct ieee80211_device, watch_dog_wq);
        struct net_device *dev = ieee->dev;
@@ -6691,7 +6691,7 @@ lizhaoming--------------------------- RF power on/power off -----------------
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
 void GPIOChangeRFWorkItemCallBack(struct work_struct *work)
 {
-       //struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+       //struct delayed_work *dwork = to_delayed_work(work);
        struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, GPIOChangeRFWorkItem.work);
        struct net_device *dev = ieee->dev;
        struct r8180_priv *priv = ieee80211_priv(dev);
index 742a5bc44be8670bdaa1bfc06a93ccbfcc9cfc9a..2a70563bbee1003008a20a0f48b880a4503db9ab 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/seq_file.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
 #include <linux/list.h>
@@ -421,57 +422,52 @@ static int serial_break(struct tty_struct *tty, int break_state)
        return 0;
 }
 
-static int serial_read_proc(char *page, char **start, off_t off, int count,
-                                                       int *eof, void *data)
+static int serial_proc_show(struct seq_file *m, void *v)
 {
        struct usb_serial *serial;
-       int length = 0;
        int i;
-       off_t begin = 0;
        char tmp[40];
 
        dbg("%s", __func__);
-       length += sprintf(page, "usbserinfo:1.0 driver:2.0\n");
-       for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
+       seq_puts(m, "usbserinfo:1.0 driver:2.0\n");
+       for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
                serial = usb_serial_get_by_index(i);
                if (serial == NULL)
                        continue;
 
-               length += sprintf(page+length, "%d:", i);
+               seq_printf(m, "%d:", i);
                if (serial->type->driver.owner)
-                       length += sprintf(page+length, " module:%s",
+                       seq_printf(m, " module:%s",
                                module_name(serial->type->driver.owner));
-               length += sprintf(page+length, " name:\"%s\"",
+               seq_printf(m, " name:\"%s\"",
                                serial->type->description);
-               length += sprintf(page+length, " vendor:%04x product:%04x",
+               seq_printf(m, " vendor:%04x product:%04x",
                        le16_to_cpu(serial->dev->descriptor.idVendor),
                        le16_to_cpu(serial->dev->descriptor.idProduct));
-               length += sprintf(page+length, " num_ports:%d",
-                                                       serial->num_ports);
-               length += sprintf(page+length, " port:%d",
-                                                       i - serial->minor + 1);
+               seq_printf(m, " num_ports:%d", serial->num_ports);
+               seq_printf(m, " port:%d", i - serial->minor + 1);
                usb_make_path(serial->dev, tmp, sizeof(tmp));
-               length += sprintf(page+length, " path:%s", tmp);
+               seq_printf(m, " path:%s", tmp);
 
-               length += sprintf(page+length, "\n");
-               if ((length + begin) > (off + count)) {
-                       usb_serial_put(serial);
-                       goto done;
-               }
-               if ((length + begin) < off) {
-                       begin += length;
-                       length = 0;
-               }
+               seq_putc(m, '\n');
                usb_serial_put(serial);
        }
-       *eof = 1;
-done:
-       if (off >= (length + begin))
-               return 0;
-       *start = page + (off-begin);
-       return (count < begin+length-off) ? count : begin+length-off;
+       return 0;
 }
 
+static int serial_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, serial_proc_show, NULL);
+}
+
+static const struct file_operations serial_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = serial_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static int serial_tiocmget(struct tty_struct *tty, struct file *file)
 {
        struct usb_serial_port *port = tty->driver_data;
@@ -1113,9 +1109,9 @@ static const struct tty_operations serial_ops = {
        .unthrottle =           serial_unthrottle,
        .break_ctl =            serial_break,
        .chars_in_buffer =      serial_chars_in_buffer,
-       .read_proc =            serial_read_proc,
        .tiocmget =             serial_tiocmget,
        .tiocmset =             serial_tiocmset,
+       .proc_fops =            &serial_proc_fops,
 };
 
 struct tty_driver *usb_serial_tty_driver;
index f0aac0cf315a5cdabcadfa2831a52377ff030b14..386eaa22d215fc84a3d1ac3b0405e4f511a453a1 100644 (file)
@@ -471,7 +471,7 @@ static void __wusbhc_keep_alive(struct wusbhc *wusbhc)
  */
 static void wusbhc_keep_alive_run(struct work_struct *ws)
 {
-       struct delayed_work *dw = container_of(ws, struct delayed_work, work);
+       struct delayed_work *dw = to_delayed_work(ws);
        struct wusbhc *wusbhc = container_of(dw, struct wusbhc, keep_alive_timer);
 
        mutex_lock(&wusbhc->mutex);
index 7f907fb23b8a3414044eee2b8363b63f340ba1d7..0b17824b0eb5b3aa0db0772b76dc6f19b07e2be4 100644 (file)
@@ -471,9 +471,11 @@ int __init mc68x328fb_init(void)
        fb_info.pseudo_palette = &mc68x328fb_pseudo_palette;
        fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
 
-       fb_alloc_cmap(&fb_info.cmap, 256, 0);
+       if (fb_alloc_cmap(&fb_info.cmap, 256, 0))
+               return -ENOMEM;
 
        if (register_framebuffer(&fb_info) < 0) {
+               fb_dealloc_cmap(&fb_info.cmap);
                return -EINVAL;
        }
 
@@ -494,6 +496,7 @@ module_init(mc68x328fb_init);
 static void __exit mc68x328fb_cleanup(void)
 {
        unregister_framebuffer(&fb_info);
+       fb_dealloc_cmap(&fb_info.cmap);
 }
 
 module_exit(mc68x328fb_cleanup);
index 41c27a44bd82bf5ec95e937cdea0485f610a58ed..ffe2f2796e290ba55352bca2e64264eac59df0f4 100644 (file)
@@ -1597,32 +1597,8 @@ config FB_VT8623
          Driver for CastleRock integrated graphics core in the
          VIA VT8623 [Apollo CLE266] chipset.
 
-config FB_CYBLA
-       tristate "Cyberblade/i1 support"
-       depends on FB && PCI && X86_32 && !64BIT
-       select FB_CFB_IMAGEBLIT
-       ---help---
-         This driver is supposed to support the Trident Cyberblade/i1
-         graphics core integrated in the VIA VT8601A North Bridge,
-         also known as VIA Apollo PLE133.
-
-         Status:
-          - Developed, tested and working on EPIA 5000 and EPIA 800.
-          - Does work reliable on all systems with CRT/LCD connected to
-            normal VGA ports.
-          - Should work on systems that do use the internal LCD port, but
-            this is absolutely not tested.
-
-         Character imageblit, copyarea and rectangle fill are hw accelerated,
-         ypan scrolling is used by default.
-
-         Please do read <file:Documentation/fb/cyblafb/*>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called cyblafb.
-
 config FB_TRIDENT
-       tristate "Trident support"
+       tristate "Trident/CyberXXX/CyberBlade support"
        depends on FB && PCI
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
@@ -1633,21 +1609,14 @@ config FB_TRIDENT
          and Blade XP.
          There are also integrated versions of these chips called CyberXXXX,
          CyberImage or CyberBlade. These chips are mostly found in laptops
-         but also on some motherboards. For more information, read
-         <file:Documentation/fb/tridentfb.txt>
+         but also on some motherboards including early VIA EPIA motherboards.
+         For more information, read <file:Documentation/fb/tridentfb.txt>
 
          Say Y if you have such a graphics board.
 
          To compile this driver as a module, choose M here: the
          module will be called tridentfb.
 
-config FB_TRIDENT_ACCEL
-       bool "Trident Acceleration functions (EXPERIMENTAL)"
-       depends on FB_TRIDENT && EXPERIMENTAL
-       ---help---
-       This will compile the Trident frame buffer device with
-       acceleration functions.
-
 config FB_ARK
        tristate "ARK 2000PV support"
        depends on FB && PCI
@@ -1920,6 +1889,30 @@ config FB_TMIO_ACCELL
        depends on FB_TMIO
        default y
 
+config FB_S3C
+       tristate "Samsung S3C framebuffer support"
+       depends on FB && ARCH_S3C64XX
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       ---help---
+         Frame buffer driver for the built-in FB controller in the Samsung
+         SoC line from the S3C2443 onwards, including the S3C2416, S3C2450,
+         and the S3C64XX series such as the S3C6400 and S3C6410.
+
+         These chips all have the same basic framebuffer design with the
+         actual capabilities depending on the chip. For instance the S3C6400
+         and S3C6410 support 4 hardware windows whereas the S3C24XX series
+         currently only have two.
+
+         Currently the support is only for the S3C6400 and S3C6410 SoCs.
+
+config FB_S3C_DEBUG_REGWRITE
+       bool "Debug register writes"
+       depends on FB_S3C
+       ---help---
+         Show all register writes via printk(KERN_DEBUG)
+
 config FB_S3C2410
        tristate "S3C2410 LCD framebuffer support"
        depends on FB && ARCH_S3C2410
index bb265eca7d57c556c409f6ecf58e3cb76af9c4de..0dbd6c68d76bc50a3b984819aec83178ce5adba6 100644 (file)
@@ -76,6 +76,7 @@ obj-$(CONFIG_FB_ATARI)            += atafb.o c2p_iplan2.o atafb_mfb.o \
                                      atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o
 obj-$(CONFIG_FB_MAC)              += macfb.o
 obj-$(CONFIG_FB_HECUBA)           += hecubafb.o
+obj-$(CONFIG_FB_N411)             += n411.o
 obj-$(CONFIG_FB_HGA)              += hgafb.o
 obj-$(CONFIG_FB_XVR500)           += sunxvr500.o
 obj-$(CONFIG_FB_XVR2500)          += sunxvr2500.o
@@ -110,6 +111,7 @@ obj-$(CONFIG_FB_BROADSHEET)       += broadsheetfb.o
 obj-$(CONFIG_FB_S1D13XXX)        += s1d13xxxfb.o
 obj-$(CONFIG_FB_SH7760)                  += sh7760fb.o
 obj-$(CONFIG_FB_IMX)              += imxfb.o
+obj-$(CONFIG_FB_S3C)             += s3c-fb.o
 obj-$(CONFIG_FB_S3C2410)         += s3c2410fb.o
 obj-$(CONFIG_FB_FSL_DIU)         += fsl-diu-fb.o
 obj-$(CONFIG_FB_COBALT)           += cobalt_lcdfb.o
index 4e046fed1380e7b4f158b4fe4c576b825b575eca..61050ab141288134a62f393533c31b24871ce233 100644 (file)
@@ -408,7 +408,9 @@ static int clcdfb_register(struct clcd_fb *fb)
        /*
         * Allocate colourmap.
         */
-       fb_alloc_cmap(&fb->fb.cmap, 256, 0);
+       ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0);
+       if (ret)
+               goto unmap;
 
        /*
         * Ensure interrupts are disabled.
@@ -426,6 +428,8 @@ static int clcdfb_register(struct clcd_fb *fb)
 
        printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret);
 
+       fb_dealloc_cmap(&fb->fb.cmap);
+ unmap:
        iounmap(fb->regs);
  free_clk:
        clk_put(fb->clk);
@@ -485,6 +489,8 @@ static int clcdfb_remove(struct amba_device *dev)
 
        clcdfb_disable(fb);
        unregister_framebuffer(&fb->fb);
+       if (fb->fb.cmap.len)
+               fb_dealloc_cmap(&fb->fb.cmap);
        iounmap(fb->regs);
        clk_put(fb->clk);
 
index 100f236614650f42337d7007adb5f32cf09ebf77..82bedd7f778967ee879258d27bc9183111107036 100644 (file)
@@ -2437,7 +2437,9 @@ default_chipset:
                goto amifb_error;
        }
 
-       fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0);
+       err = fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0);
+       if (err)
+               goto amifb_error;
 
        if (register_framebuffer(&fb_info) < 0) {
                err = -EINVAL;
@@ -2456,7 +2458,8 @@ amifb_error:
 
 static void amifb_deinit(void)
 {
-       fb_dealloc_cmap(&fb_info.cmap);
+       if (fb_info.cmap.len)
+               fb_dealloc_cmap(&fb_info.cmap);
        chipfree();
        if (videomemory)
                iounmap((void*)videomemory);
index 314d18694b6a38c2d3fd6eeca883e1448bcd0fd2..d583bea608fd755bfe1f16c24d5dc95e184aa316 100644 (file)
@@ -470,7 +470,7 @@ static void ark_dac_read_regs(void *data, u8 *code, int count)
 
        while (count != 0)
        {
-               vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0);
+               vga_wseq(NULL, 0x1C, regval | (code[0] & 4 ? 0x80 : 0));
                code[1] = vga_r(NULL, dac_regs[code[0] & 3]);
                count--;
                code += 2;
@@ -485,7 +485,7 @@ static void ark_dac_write_regs(void *data, u8 *code, int count)
 
        while (count != 0)
        {
-               vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0);
+               vga_wseq(NULL, 0x1C, regval | (code[0] & 4 ? 0x80 : 0));
                vga_w(NULL, dac_regs[code[0] & 3], code[1]);
                count--;
                code += 2;
index 1fd22f460b0fa23e990cced9abe9c26f66b04791..1a1f946d8fef6145859275fe491f9c83bfbcf64a 100644 (file)
@@ -505,19 +505,27 @@ static struct fb_var_screeninfo asiliantfb_var __devinitdata = {
        .vsync_len      = 2,
 };
 
-static void __devinit init_asiliant(struct fb_info *p, unsigned long addr)
+static int __devinit init_asiliant(struct fb_info *p, unsigned long addr)
 {
+       int err;
+
        p->fix                  = asiliantfb_fix;
        p->fix.smem_start       = addr;
        p->var                  = asiliantfb_var;
        p->fbops                = &asiliantfb_ops;
        p->flags                = FBINFO_DEFAULT;
 
-       fb_alloc_cmap(&p->cmap, 256, 0);
+       err = fb_alloc_cmap(&p->cmap, 256, 0);
+       if (err) {
+               printk(KERN_ERR "C&T 69000 fb failed to alloc cmap memory\n");
+               return err;
+       }
 
-       if (register_framebuffer(p) < 0) {
+       err = register_framebuffer(p);
+       if (err < 0) {
                printk(KERN_ERR "C&T 69000 framebuffer failed to register\n");
-               return;
+               fb_dealloc_cmap(&p->cmap);
+               return err;
        }
 
        printk(KERN_INFO "fb%d: Asiliant 69000 frame buffer (%dK RAM detected)\n",
@@ -532,6 +540,7 @@ asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
 {
        unsigned long addr, size;
        struct fb_info *p;
+       int err;
 
        if ((dp->resource[0].flags & IORESOURCE_MEM) == 0)
                return -ENODEV;
@@ -560,7 +569,13 @@ asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
        pci_write_config_dword(dp, 4, 0x02800083);
        writeb(3, p->screen_base + 0x400784);
 
-       init_asiliant(p, addr);
+       err = init_asiliant(p, addr);
+       if (err) {
+               iounmap(p->screen_base);
+               release_mem_region(addr, size);
+               framebuffer_release(p);
+               return err;
+       }
 
        pci_set_drvdata(dp, p);
        return 0;
@@ -571,6 +586,7 @@ static void __devexit asiliantfb_remove(struct pci_dev *dp)
        struct fb_info *p = pci_get_drvdata(dp);
 
        unregister_framebuffer(p);
+       fb_dealloc_cmap(&p->cmap);
        iounmap(p->screen_base);
        release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0));
        pci_set_drvdata(dp, NULL);
index a8f60c33863c6f7df1e239e66de510347a107c22..0cc9724e61a268cc8e21acfbd5cd4ff05100a6f6 100644 (file)
@@ -39,7 +39,8 @@ void aty_reset_engine(const struct atyfb_par *par)
 {
        /* reset engine */
        aty_st_le32(GEN_TEST_CNTL,
-               aty_ld_le32(GEN_TEST_CNTL, par) & ~GUI_ENGINE_ENABLE, par);
+               aty_ld_le32(GEN_TEST_CNTL, par) &
+               ~(GUI_ENGINE_ENABLE | HWCURSOR_ENABLE), par);
        /* enable engine */
        aty_st_le32(GEN_TEST_CNTL,
                aty_ld_le32(GEN_TEST_CNTL, par) | GUI_ENGINE_ENABLE, par);
index faf95da8fcbc074ae7878944f66c2973436ea815..04c710804bb04e93e67cd1b81fe7b811d5c87bce 100644 (file)
@@ -77,9 +77,13 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
        if (par->asleep)
                return -EPERM;
 
-       /* Hide cursor */
        wait_for_fifo(1, par);
-       aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) & ~HWCURSOR_ENABLE, par);
+       if (cursor->enable)
+               aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par)
+                           | HWCURSOR_ENABLE, par);
+       else
+               aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par)
+                               & ~HWCURSOR_ENABLE, par);
 
        /* set position */
        if (cursor->set & FB_CUR_SETPOS) {
@@ -109,7 +113,7 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
                        y<<=1;
                        h<<=1;
                }
-               wait_for_fifo(4, par);
+               wait_for_fifo(3, par);
                aty_st_le32(CUR_OFFSET, (info->fix.smem_len >> 3) + (yoff << 1), par);
                aty_st_le32(CUR_HORZ_VERT_OFF,
                            ((u32) (64 - h + yoff) << 16) | xoff, par);
@@ -177,11 +181,6 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
            }
        }
 
-       if (cursor->enable) {
-               wait_for_fifo(1, par);
-               aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par)
-                           | HWCURSOR_ENABLE, par);
-       }
        return 0;
 }
 
index c6d7cc76516ff116edfff3643156fb5a18d19e7a..97a1f095f327115524bdb9fcd55da6162d8497d2 100644 (file)
@@ -89,6 +89,9 @@ static struct radeon_device_id radeon_workaround_list[] = {
        BUGFIX("Acer Aspire 2010",
               PCI_VENDOR_ID_AI, 0x0061,
               radeon_pm_off, radeon_reinitialize_M10),
+       BUGFIX("Acer Travelmate 290D/292LMi",
+              PCI_VENDOR_ID_AI, 0x005a,
+              radeon_pm_off, radeon_reinitialize_M10),
        { .ident = NULL }
 };
 
@@ -2582,7 +2585,7 @@ static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
                 * calling pci_set_power_state()
                 */
                radeonfb_whack_power_state(rinfo, PCI_D2);
-               pci_set_power_state(rinfo->pdev, PCI_D2);
+               __pci_complete_power_transition(rinfo->pdev, PCI_D2);
        } else {
                printk(KERN_DEBUG "radeonfb (%s): switching to D0 state...\n",
                       pci_name(rinfo->pdev));
index 157057c79ca3760fc80d6df28236dc0bbf106044..dd37cbcaf8ce164a4ac5e7293a745204ede08ac4 100644 (file)
@@ -35,6 +35,8 @@ static int fb_notifier_callback(struct notifier_block *self,
                return 0;
 
        bd = container_of(self, struct backlight_device, fb_notif);
+       if (!lock_fb_info(evdata->info))
+               return -ENODEV;
        mutex_lock(&bd->ops_lock);
        if (bd->ops)
                if (!bd->ops->check_fb ||
@@ -47,6 +49,7 @@ static int fb_notifier_callback(struct notifier_block *self,
                        backlight_update_status(bd);
                }
        mutex_unlock(&bd->ops_lock);
+       unlock_fb_info(evdata->info);
        return 0;
 }
 
index b6449470106cd47e8db704edfd074c53dde8ec4b..0bb13df0fa89e2b3ca01c9468a47cadd2f5a8b88 100644 (file)
@@ -40,6 +40,8 @@ static int fb_notifier_callback(struct notifier_block *self,
        if (!ld->ops)
                return 0;
 
+       if (!lock_fb_info(evdata->info))
+               return -ENODEV;
        mutex_lock(&ld->ops_lock);
        if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info)) {
                if (event == FB_EVENT_BLANK) {
@@ -51,6 +53,7 @@ static int fb_notifier_callback(struct notifier_block *self,
                }
        }
        mutex_unlock(&ld->ops_lock);
+       unlock_fb_info(evdata->info);
        return 0;
 }
 
index a2aa6ddffbe25d6e764a0dc6bdc7dd298e9f1849..d42e385f091c7658418d844f7cc77db306bd0a93 100644 (file)
@@ -34,8 +34,6 @@
  *
  */
 
-#define CIRRUSFB_VERSION "2.0-pre2"
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
  *
  */
 
-/* enable debug output? */
-/* #define CIRRUSFB_DEBUG 1 */
-
 /* disable runtime assertions? */
 /* #define CIRRUSFB_NDEBUG */
 
-/* debug output */
-#ifdef CIRRUSFB_DEBUG
-#define DPRINTK(fmt, args...) \
-       printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
 /* debugging assertions */
 #ifndef CIRRUSFB_NDEBUG
 #define assert(expr) \
 /* board types */
 enum cirrus_board {
        BT_NONE = 0,
-       BT_SD64,
-       BT_PICCOLO,
-       BT_PICASSO,
-       BT_SPECTRUM,
+       BT_SD64,        /* GD5434 */
+       BT_PICCOLO,     /* GD5426 */
+       BT_PICASSO,     /* GD5426 or GD5428 */
+       BT_SPECTRUM,    /* GD5426 or GD5428 */
        BT_PICASSO4,    /* GD5446 */
        BT_ALPINE,      /* GD543x/4x */
        BT_GD5480,
-       BT_LAGUNA,      /* GD546x */
+       BT_LAGUNA,      /* GD5462/64 */
+       BT_LAGUNAB,     /* GD5465 */
 };
 
 /*
@@ -150,15 +138,17 @@ static const struct cirrusfb_board_info_rec {
                .maxclock               = {
                        /* guess */
                        /* the SD64/P4 have a higher max. videoclock */
-                       140000, 140000, 140000, 140000, 140000,
+                       135100, 135100, 85500, 85500, 0
                },
                .init_sr07              = true,
                .init_sr1f              = true,
                .scrn_start_bit19       = true,
                .sr07                   = 0xF0,
                .sr07_1bpp              = 0xF0,
+               .sr07_1bpp_mux          = 0xF6,
                .sr07_8bpp              = 0xF1,
-               .sr1f                   = 0x20
+               .sr07_8bpp_mux          = 0xF7,
+               .sr1f                   = 0x1E
        },
        [BT_PICCOLO] = {
                .name                   = "CL Piccolo",
@@ -210,9 +200,11 @@ static const struct cirrusfb_board_info_rec {
                .init_sr07              = true,
                .init_sr1f              = false,
                .scrn_start_bit19       = true,
-               .sr07                   = 0x20,
-               .sr07_1bpp              = 0x20,
-               .sr07_8bpp              = 0x21,
+               .sr07                   = 0xA0,
+               .sr07_1bpp              = 0xA0,
+               .sr07_1bpp_mux          = 0xA6,
+               .sr07_8bpp              = 0xA1,
+               .sr07_8bpp_mux          = 0xA7,
                .sr1f                   = 0
        },
        [BT_ALPINE] = {
@@ -225,8 +217,8 @@ static const struct cirrusfb_board_info_rec {
                .init_sr1f              = true,
                .scrn_start_bit19       = true,
                .sr07                   = 0xA0,
-               .sr07_1bpp              = 0xA1,
-               .sr07_1bpp_mux          = 0xA7,
+               .sr07_1bpp              = 0xA0,
+               .sr07_1bpp_mux          = 0xA6,
                .sr07_8bpp              = 0xA1,
                .sr07_8bpp_mux          = 0xA7,
                .sr1f                   = 0x1C
@@ -247,8 +239,18 @@ static const struct cirrusfb_board_info_rec {
        [BT_LAGUNA] = {
                .name                   = "CL Laguna",
                .maxclock               = {
-                       /* guess */
-                       135100, 135100, 135100, 135100, 135100,
+                       /* taken from X11 code */
+                       170000, 170000, 170000, 170000, 135100,
+               },
+               .init_sr07              = false,
+               .init_sr1f              = false,
+               .scrn_start_bit19       = true,
+       },
+       [BT_LAGUNAB] = {
+               .name                   = "CL Laguna AGP",
+               .maxclock               = {
+                       /* taken from X11 code */
+                       170000, 250000, 170000, 170000, 135100,
                },
                .init_sr07              = false,
                .init_sr1f              = false,
@@ -262,8 +264,8 @@ static const struct cirrusfb_board_info_rec {
 
 static struct pci_device_id cirrusfb_pci_table[] = {
        CHIP(PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE),
-       CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_ALPINE),
-       CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_ALPINE),
+       CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_SD64),
+       CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_SD64),
        CHIP(PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE), /* GD-5440 is same id */
        CHIP(PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE),
        CHIP(PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE),
@@ -271,7 +273,7 @@ static struct pci_device_id cirrusfb_pci_table[] = {
        CHIP(PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4), /* Picasso 4 is 5446 */
        CHIP(PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA), /* CL Laguna */
        CHIP(PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA), /* CL Laguna 3D */
-       CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNA), /* CL Laguna 3DA*/
+       CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNAB), /* CL Laguna 3DA*/
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table);
@@ -326,10 +328,6 @@ static const struct {
 };
 #endif /* CONFIG_ZORRO */
 
-struct cirrusfb_regs {
-       int multiplexing;
-};
-
 #ifdef CIRRUSFB_DEBUG
 enum cirrusfb_dbg_reg_class {
        CRT,
@@ -340,10 +338,12 @@ enum cirrusfb_dbg_reg_class {
 /* info about board */
 struct cirrusfb_info {
        u8 __iomem *regbase;
+       u8 __iomem *laguna_mmio;
        enum cirrus_board btype;
        unsigned char SFR;      /* Shadow of special function register */
 
-       struct cirrusfb_regs currentmode;
+       int multiplexing;
+       int doubleVCLK;
        int blank_mode;
        u32 pseudo_palette[16];
 
@@ -357,43 +357,8 @@ static char *mode_option __devinitdata = "640x480@60";
 /**** BEGIN PROTOTYPES ******************************************************/
 
 /*--- Interface used by the world ------------------------------------------*/
-static int cirrusfb_init(void);
-#ifndef MODULE
-static int cirrusfb_setup(char *options);
-#endif
-
-static int cirrusfb_open(struct fb_info *info, int user);
-static int cirrusfb_release(struct fb_info *info, int user);
-static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,
-                             unsigned blue, unsigned transp,
-                             struct fb_info *info);
-static int cirrusfb_check_var(struct fb_var_screeninfo *var,
-                             struct fb_info *info);
-static int cirrusfb_set_par(struct fb_info *info);
 static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
                                struct fb_info *info);
-static int cirrusfb_blank(int blank_mode, struct fb_info *info);
-static void cirrusfb_fillrect(struct fb_info *info,
-                             const struct fb_fillrect *region);
-static void cirrusfb_copyarea(struct fb_info *info,
-                             const struct fb_copyarea *area);
-static void cirrusfb_imageblit(struct fb_info *info,
-                              const struct fb_image *image);
-
-/* function table of the above functions */
-static struct fb_ops cirrusfb_ops = {
-       .owner          = THIS_MODULE,
-       .fb_open        = cirrusfb_open,
-       .fb_release     = cirrusfb_release,
-       .fb_setcolreg   = cirrusfb_setcolreg,
-       .fb_check_var   = cirrusfb_check_var,
-       .fb_set_par     = cirrusfb_set_par,
-       .fb_pan_display = cirrusfb_pan_display,
-       .fb_blank       = cirrusfb_blank,
-       .fb_fillrect    = cirrusfb_fillrect,
-       .fb_copyarea    = cirrusfb_copyarea,
-       .fb_imageblit   = cirrusfb_imageblit,
-};
 
 /*--- Internal routines ----------------------------------------------------*/
 static void init_vgachip(struct fb_info *info);
@@ -421,22 +386,27 @@ static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
 static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
                              u_short x, u_short y,
                              u_short width, u_short height,
-                             u_char color, u_short line_length);
+                             u32 fg_color, u32 bg_color,
+                             u_short line_length, u_char blitmode);
 
 static void bestclock(long freq, int *nom, int *den, int *div);
 
 #ifdef CIRRUSFB_DEBUG
-static void cirrusfb_dump(void);
-static void cirrusfb_dbg_reg_dump(caddr_t regbase);
-static void cirrusfb_dbg_print_regs(caddr_t regbase,
+static void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase);
+static void cirrusfb_dbg_print_regs(struct fb_info *info,
+                                   caddr_t regbase,
                                    enum cirrusfb_dbg_reg_class reg_class, ...);
-static void cirrusfb_dbg_print_byte(const char *name, unsigned char val);
 #endif /* CIRRUSFB_DEBUG */
 
 /*** END   PROTOTYPES ********************************************************/
 /*****************************************************************************/
 /*** BEGIN Interface Used by the World ***************************************/
 
+static inline int is_laguna(const struct cirrusfb_info *cinfo)
+{
+       return cinfo->btype == BT_LAGUNA || cinfo->btype == BT_LAGUNAB;
+}
+
 static int opencount;
 
 /*--- Open /dev/fbx ---------------------------------------------------------*/
@@ -460,85 +430,94 @@ static int cirrusfb_release(struct fb_info *info, int user)
 /**** BEGIN Hardware specific Routines **************************************/
 
 /* Check if the MCLK is not a better clock source */
-static int cirrusfb_check_mclk(struct cirrusfb_info *cinfo, long freq)
+static int cirrusfb_check_mclk(struct fb_info *info, long freq)
 {
+       struct cirrusfb_info *cinfo = info->par;
        long mclk = vga_rseq(cinfo->regbase, CL_SEQR1F) & 0x3f;
 
        /* Read MCLK value */
        mclk = (14318 * mclk) >> 3;
-       DPRINTK("Read MCLK of %ld kHz\n", mclk);
+       dev_dbg(info->device, "Read MCLK of %ld kHz\n", mclk);
 
        /* Determine if we should use MCLK instead of VCLK, and if so, what we
         * should divide it by to get VCLK
         */
 
        if (abs(freq - mclk) < 250) {
-               DPRINTK("Using VCLK = MCLK\n");
+               dev_dbg(info->device, "Using VCLK = MCLK\n");
                return 1;
        } else if (abs(freq - (mclk / 2)) < 250) {
-               DPRINTK("Using VCLK = MCLK/2\n");
+               dev_dbg(info->device, "Using VCLK = MCLK/2\n");
                return 2;
        }
 
        return 0;
 }
 
-static int cirrusfb_check_var(struct fb_var_screeninfo *var,
-                             struct fb_info *info)
+static int cirrusfb_check_pixclock(const struct fb_var_screeninfo *var,
+                                  struct fb_info *info)
 {
-       int yres;
-       /* memory size in pixels */
-       unsigned pixels = info->screen_size * 8 / var->bits_per_pixel;
+       long freq;
+       long maxclock;
+       struct cirrusfb_info *cinfo = info->par;
+       unsigned maxclockidx = var->bits_per_pixel >> 3;
 
-       switch (var->bits_per_pixel) {
-       case 1:
-               pixels /= 4;
-               break;          /* 8 pixel per byte, only 1/4th of mem usable */
-       case 8:
-       case 16:
-       case 32:
-               break;          /* 1 pixel == 1 byte */
-       default:
-               printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..."
-                       "color depth not supported.\n",
-                       var->xres, var->yres, var->bits_per_pixel);
-               DPRINTK("EXIT - EINVAL error\n");
-               return -EINVAL;
-       }
+       /* convert from ps to kHz */
+       freq = PICOS2KHZ(var->pixclock);
 
-       if (var->xres_virtual < var->xres)
-               var->xres_virtual = var->xres;
-       /* use highest possible virtual resolution */
-       if (var->yres_virtual == -1) {
-               var->yres_virtual = pixels / var->xres_virtual;
+       dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq);
 
-               printk(KERN_INFO "cirrusfb: virtual resolution set to "
-                       "maximum of %dx%d\n", var->xres_virtual,
-                       var->yres_virtual);
-       }
-       if (var->yres_virtual < var->yres)
-               var->yres_virtual = var->yres;
+       maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx];
+       cinfo->multiplexing = 0;
 
-       if (var->xres_virtual * var->yres_virtual > pixels) {
-               printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected... "
-                     "virtual resolution too high to fit into video memory!\n",
-                       var->xres_virtual, var->yres_virtual,
-                       var->bits_per_pixel);
-               DPRINTK("EXIT - EINVAL error\n");
+       /* If the frequency is greater than we can support, we might be able
+        * to use multiplexing for the video mode */
+       if (freq > maxclock) {
+               dev_err(info->device,
+                       "Frequency greater than maxclock (%ld kHz)\n",
+                       maxclock);
                return -EINVAL;
        }
+       /*
+        * Additional constraint: 8bpp uses DAC clock doubling to allow maximum
+        * pixel clock
+        */
+       if (var->bits_per_pixel == 8) {
+               switch (cinfo->btype) {
+               case BT_ALPINE:
+               case BT_SD64:
+               case BT_PICASSO4:
+                       if (freq > 85500)
+                               cinfo->multiplexing = 1;
+                       break;
+               case BT_GD5480:
+                       if (freq > 135100)
+                               cinfo->multiplexing = 1;
+                       break;
 
+               default:
+                       break;
+               }
+       }
 
-       if (var->xoffset < 0)
-               var->xoffset = 0;
-       if (var->yoffset < 0)
-               var->yoffset = 0;
+       /* If we have a 1MB 5434, we need to put ourselves in a mode where
+        * the VCLK is double the pixel clock. */
+       cinfo->doubleVCLK = 0;
+       if (cinfo->btype == BT_SD64 && info->fix.smem_len <= MB_ &&
+           var->bits_per_pixel == 16) {
+               cinfo->doubleVCLK = 1;
+       }
 
-       /* truncate xoffset and yoffset to maximum if too high */
-       if (var->xoffset > var->xres_virtual - var->xres)
-               var->xoffset = var->xres_virtual - var->xres - 1;
-       if (var->yoffset > var->yres_virtual - var->yres)
-               var->yoffset = var->yres_virtual - var->yres - 1;
+       return 0;
+}
+
+static int cirrusfb_check_var(struct fb_var_screeninfo *var,
+                             struct fb_info *info)
+{
+       int yres;
+       /* memory size in pixels */
+       unsigned pixels = info->screen_size * 8 / var->bits_per_pixel;
+       struct cirrusfb_info *cinfo = info->par;
 
        switch (var->bits_per_pixel) {
        case 1:
@@ -550,7 +529,7 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
 
        case 8:
                var->red.offset = 0;
-               var->red.length = 6;
+               var->red.length = 8;
                var->green = var->red;
                var->blue = var->red;
                break;
@@ -561,20 +540,20 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
                        var->green.offset = -3;
                        var->blue.offset = 8;
                } else {
-                       var->red.offset = 10;
+                       var->red.offset = 11;
                        var->green.offset = 5;
                        var->blue.offset = 0;
                }
                var->red.length = 5;
-               var->green.length = 5;
+               var->green.length = 6;
                var->blue.length = 5;
                break;
 
-       case 32:
+       case 24:
                if (isPReP) {
-                       var->red.offset = 8;
-                       var->green.offset = 16;
-                       var->blue.offset = 24;
+                       var->red.offset = 0;
+                       var->green.offset = 8;
+                       var->blue.offset = 16;
                } else {
                        var->red.offset = 16;
                        var->green.offset = 8;
@@ -586,12 +565,45 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
                break;
 
        default:
-               DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
+               dev_dbg(info->device,
+                       "Unsupported bpp size: %d\n", var->bits_per_pixel);
                assert(false);
                /* should never occur */
                break;
        }
 
+       if (var->xres_virtual < var->xres)
+               var->xres_virtual = var->xres;
+       /* use highest possible virtual resolution */
+       if (var->yres_virtual == -1) {
+               var->yres_virtual = pixels / var->xres_virtual;
+
+               dev_info(info->device,
+                        "virtual resolution set to maximum of %dx%d\n",
+                        var->xres_virtual, var->yres_virtual);
+       }
+       if (var->yres_virtual < var->yres)
+               var->yres_virtual = var->yres;
+
+       if (var->xres_virtual * var->yres_virtual > pixels) {
+               dev_err(info->device, "mode %dx%dx%d rejected... "
+                     "virtual resolution too high to fit into video memory!\n",
+                       var->xres_virtual, var->yres_virtual,
+                       var->bits_per_pixel);
+               return -EINVAL;
+       }
+
+       if (var->xoffset < 0)
+               var->xoffset = 0;
+       if (var->yoffset < 0)
+               var->yoffset = 0;
+
+       /* truncate xoffset and yoffset to maximum if too high */
+       if (var->xoffset > var->xres_virtual - var->xres)
+               var->xoffset = var->xres_virtual - var->xres - 1;
+       if (var->yoffset > var->yres_virtual - var->yres)
+               var->yoffset = var->yres_virtual - var->yres - 1;
+
        var->red.msb_right =
            var->green.msb_right =
            var->blue.msb_right =
@@ -606,99 +618,31 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
                yres = (yres + 1) / 2;
 
        if (yres >= 1280) {
-               printk(KERN_ERR "cirrusfb: ERROR: VerticalTotal >= 1280; "
+               dev_err(info->device, "ERROR: VerticalTotal >= 1280; "
                        "special treatment required! (TODO)\n");
-               DPRINTK("EXIT - EINVAL error\n");
                return -EINVAL;
        }
 
-       return 0;
-}
-
-static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
-                               struct cirrusfb_regs *regs,
-                               struct fb_info *info)
-{
-       long freq;
-       long maxclock;
-       int maxclockidx = var->bits_per_pixel >> 3;
-       struct cirrusfb_info *cinfo = info->par;
-
-       switch (var->bits_per_pixel) {
-       case 1:
-               info->fix.line_length = var->xres_virtual / 8;
-               info->fix.visual = FB_VISUAL_MONO10;
-               break;
-
-       case 8:
-               info->fix.line_length = var->xres_virtual;
-               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
-               break;
-
-       case 16:
-       case 32:
-               info->fix.line_length = var->xres_virtual * maxclockidx;
-               info->fix.visual = FB_VISUAL_TRUECOLOR;
-               break;
-
-       default:
-               DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
-               assert(false);
-               /* should never occur */
-               break;
-       }
-
-       info->fix.type = FB_TYPE_PACKED_PIXELS;
-
-       /* convert from ps to kHz */
-       freq = PICOS2KHZ(var->pixclock);
-
-       DPRINTK("desired pixclock: %ld kHz\n", freq);
-
-       maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx];
-       regs->multiplexing = 0;
+       if (cirrusfb_check_pixclock(var, info))
+               return -EINVAL;
 
-       /* If the frequency is greater than we can support, we might be able
-        * to use multiplexing for the video mode */
-       if (freq > maxclock) {
-               switch (cinfo->btype) {
-               case BT_ALPINE:
-               case BT_GD5480:
-                       regs->multiplexing = 1;
-                       break;
+       if (!is_laguna(cinfo))
+               var->accel_flags = FB_ACCELF_TEXT;
 
-               default:
-                       printk(KERN_ERR "cirrusfb: Frequency greater "
-                               "than maxclock (%ld kHz)\n", maxclock);
-                       DPRINTK("EXIT - return -EINVAL\n");
-                       return -EINVAL;
-               }
-       }
-#if 0
-       /* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where
-        * the VCLK is double the pixel clock. */
-       switch (var->bits_per_pixel) {
-       case 16:
-       case 32:
-               if (var->xres <= 800)
-                       /* Xbh has this type of clock for 32-bit */
-                       freq /= 2;
-               break;
-       }
-#endif
        return 0;
 }
 
-static void cirrusfb_set_mclk_as_source(const struct cirrusfb_info *cinfo,
-                                       int div)
+static void cirrusfb_set_mclk_as_source(const struct fb_info *info, int div)
 {
+       struct cirrusfb_info *cinfo = info->par;
        unsigned char old1f, old1e;
+
        assert(cinfo != NULL);
        old1f = vga_rseq(cinfo->regbase, CL_SEQR1F) & ~0x40;
 
        if (div) {
-               DPRINTK("Set %s as pixclock source.\n",
-                                       (div == 2) ? "MCLK/2" : "MCLK");
+               dev_dbg(info->device, "Set %s as pixclock source.\n",
+                       (div == 2) ? "MCLK/2" : "MCLK");
                old1f |= 0x40;
                old1e = vga_rseq(cinfo->regbase, CL_SEQR1E) & ~0x1;
                if (div == 2)
@@ -718,101 +662,119 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
 {
        struct cirrusfb_info *cinfo = info->par;
        struct fb_var_screeninfo *var = &info->var;
-       struct cirrusfb_regs regs;
        u8 __iomem *regbase = cinfo->regbase;
        unsigned char tmp;
-       int offset = 0, err;
+       int pitch;
        const struct cirrusfb_board_info_rec *bi;
        int hdispend, hsyncstart, hsyncend, htotal;
        int yres, vdispend, vsyncstart, vsyncend, vtotal;
        long freq;
        int nom, den, div;
+       unsigned int control = 0, format = 0, threshold = 0;
 
-       DPRINTK("ENTER\n");
-       DPRINTK("Requested mode: %dx%dx%d\n",
+       dev_dbg(info->device, "Requested mode: %dx%dx%d\n",
               var->xres, var->yres, var->bits_per_pixel);
-       DPRINTK("pixclock: %d\n", var->pixclock);
 
-       init_vgachip(info);
+       switch (var->bits_per_pixel) {
+       case 1:
+               info->fix.line_length = var->xres_virtual / 8;
+               info->fix.visual = FB_VISUAL_MONO10;
+               break;
 
-       err = cirrusfb_decode_var(var, &regs, info);
-       if (err) {
-               /* should never happen */
-               DPRINTK("mode change aborted.  invalid var.\n");
-               return -EINVAL;
+       case 8:
+               info->fix.line_length = var->xres_virtual;
+               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+               break;
+
+       case 16:
+       case 24:
+               info->fix.line_length = var->xres_virtual *
+                                       var->bits_per_pixel >> 3;
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+               break;
        }
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+
+       init_vgachip(info);
 
        bi = &cirrusfb_board_info[cinfo->btype];
 
        hsyncstart = var->xres + var->right_margin;
        hsyncend = hsyncstart + var->hsync_len;
-       htotal = (hsyncend + var->left_margin) / 8 - 5;
-       hdispend = var->xres / 8 - 1;
-       hsyncstart = hsyncstart / 8 + 1;
-       hsyncend = hsyncend / 8 + 1;
+       htotal = (hsyncend + var->left_margin) / 8;
+       hdispend = var->xres / 8;
+       hsyncstart = hsyncstart / 8;
+       hsyncend = hsyncend / 8;
 
-       yres = var->yres;
-       vsyncstart = yres + var->lower_margin;
+       vdispend = var->yres;
+       vsyncstart = vdispend + var->lower_margin;
        vsyncend = vsyncstart + var->vsync_len;
        vtotal = vsyncend + var->upper_margin;
-       vdispend = yres - 1;
 
        if (var->vmode & FB_VMODE_DOUBLE) {
-               yres *= 2;
+               vdispend *= 2;
                vsyncstart *= 2;
                vsyncend *= 2;
                vtotal *= 2;
        } else if (var->vmode & FB_VMODE_INTERLACED) {
-               yres = (yres + 1) / 2;
+               vdispend = (vdispend + 1) / 2;
                vsyncstart = (vsyncstart + 1) / 2;
                vsyncend = (vsyncend + 1) / 2;
                vtotal = (vtotal + 1) / 2;
        }
-
-       vtotal -= 2;
-       vsyncstart -= 1;
-       vsyncend -= 1;
-
+       yres = vdispend;
        if (yres >= 1024) {
                vtotal /= 2;
                vsyncstart /= 2;
                vsyncend /= 2;
                vdispend /= 2;
        }
-       if (regs.multiplexing) {
+
+       vdispend -= 1;
+       vsyncstart -= 1;
+       vsyncend -= 1;
+       vtotal -= 2;
+
+       if (cinfo->multiplexing) {
                htotal /= 2;
                hsyncstart /= 2;
                hsyncend /= 2;
                hdispend /= 2;
        }
+
+       htotal -= 5;
+       hdispend -= 1;
+       hsyncstart += 1;
+       hsyncend += 1;
+
        /* unlock register VGA_CRTC_H_TOTAL..CRT7 */
        vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20);   /* previously: 0x00) */
 
        /* if debugging is enabled, all parameters get output before writing */
-       DPRINTK("CRT0: %d\n", htotal);
+       dev_dbg(info->device, "CRT0: %d\n", htotal);
        vga_wcrt(regbase, VGA_CRTC_H_TOTAL, htotal);
 
-       DPRINTK("CRT1: %d\n", hdispend);
+       dev_dbg(info->device, "CRT1: %d\n", hdispend);
        vga_wcrt(regbase, VGA_CRTC_H_DISP, hdispend);
 
-       DPRINTK("CRT2: %d\n", var->xres / 8);
+       dev_dbg(info->device, "CRT2: %d\n", var->xres / 8);
        vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, var->xres / 8);
 
        /*  + 128: Compatible read */
-       DPRINTK("CRT3: 128+%d\n", (htotal + 5) % 32);
+       dev_dbg(info->device, "CRT3: 128+%d\n", (htotal + 5) % 32);
        vga_wcrt(regbase, VGA_CRTC_H_BLANK_END,
                 128 + ((htotal + 5) % 32));
 
-       DPRINTK("CRT4: %d\n", hsyncstart);
+       dev_dbg(info->device, "CRT4: %d\n", hsyncstart);
        vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, hsyncstart);
 
        tmp = hsyncend % 32;
        if ((htotal + 5) & 32)
                tmp += 128;
-       DPRINTK("CRT5: %d\n", tmp);
+       dev_dbg(info->device, "CRT5: %d\n", tmp);
        vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp);
 
-       DPRINTK("CRT6: %d\n", vtotal & 0xff);
+       dev_dbg(info->device, "CRT6: %d\n", vtotal & 0xff);
        vga_wcrt(regbase, VGA_CRTC_V_TOTAL, vtotal & 0xff);
 
        tmp = 16;               /* LineCompare bit #9 */
@@ -830,7 +792,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                tmp |= 64;
        if (vsyncstart & 512)
                tmp |= 128;
-       DPRINTK("CRT7: %d\n", tmp);
+       dev_dbg(info->device, "CRT7: %d\n", tmp);
        vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp);
 
        tmp = 0x40;             /* LineCompare bit #8 */
@@ -838,25 +800,25 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                tmp |= 0x20;
        if (var->vmode & FB_VMODE_DOUBLE)
                tmp |= 0x80;
-       DPRINTK("CRT9: %d\n", tmp);
+       dev_dbg(info->device, "CRT9: %d\n", tmp);
        vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp);
 
-       DPRINTK("CRT10: %d\n", vsyncstart & 0xff);
+       dev_dbg(info->device, "CRT10: %d\n", vsyncstart & 0xff);
        vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, vsyncstart & 0xff);
 
-       DPRINTK("CRT11: 64+32+%d\n", vsyncend % 16);
+       dev_dbg(info->device, "CRT11: 64+32+%d\n", vsyncend % 16);
        vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, vsyncend % 16 + 64 + 32);
 
-       DPRINTK("CRT12: %d\n", vdispend & 0xff);
+       dev_dbg(info->device, "CRT12: %d\n", vdispend & 0xff);
        vga_wcrt(regbase, VGA_CRTC_V_DISP_END, vdispend & 0xff);
 
-       DPRINTK("CRT15: %d\n", (vdispend + 1) & 0xff);
+       dev_dbg(info->device, "CRT15: %d\n", (vdispend + 1) & 0xff);
        vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, (vdispend + 1) & 0xff);
 
-       DPRINTK("CRT16: %d\n", vtotal & 0xff);
+       dev_dbg(info->device, "CRT16: %d\n", vtotal & 0xff);
        vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, vtotal & 0xff);
 
-       DPRINTK("CRT18: 0xff\n");
+       dev_dbg(info->device, "CRT18: 0xff\n");
        vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff);
 
        tmp = 0;
@@ -871,41 +833,75 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
        if (vtotal & 512)
                tmp |= 128;
 
-       DPRINTK("CRT1a: %d\n", tmp);
+       dev_dbg(info->device, "CRT1a: %d\n", tmp);
        vga_wcrt(regbase, CL_CRT1A, tmp);
 
        freq = PICOS2KHZ(var->pixclock);
+       if (var->bits_per_pixel == 24)
+               if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64)
+                       freq *= 3;
+       if (cinfo->multiplexing)
+               freq /= 2;
+       if (cinfo->doubleVCLK)
+               freq *= 2;
+
        bestclock(freq, &nom, &den, &div);
 
+       dev_dbg(info->device, "VCLK freq: %ld kHz  nom: %d  den: %d  div: %d\n",
+               freq, nom, den, div);
+
        /* set VCLK0 */
        /* hardware RefClock: 14.31818 MHz */
        /* formula: VClk = (OSC * N) / (D * (1+P)) */
        /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
 
-       if (cinfo->btype == BT_ALPINE) {
+       if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_PICASSO4 ||
+           cinfo->btype == BT_SD64) {
                /* if freq is close to mclk or mclk/2 select mclk
                 * as clock source
                 */
-               int divMCLK = cirrusfb_check_mclk(cinfo, freq);
-               if (divMCLK)  {
+               int divMCLK = cirrusfb_check_mclk(info, freq);
+               if (divMCLK)
                        nom = 0;
-                       cirrusfb_set_mclk_as_source(cinfo, divMCLK);
+               cirrusfb_set_mclk_as_source(info, divMCLK);
+       }
+       if (is_laguna(cinfo)) {
+               long pcifc = fb_readl(cinfo->laguna_mmio + 0x3fc);
+               unsigned char tile = fb_readb(cinfo->laguna_mmio + 0x407);
+               unsigned short tile_control;
+
+               if (cinfo->btype == BT_LAGUNAB) {
+                       tile_control = fb_readw(cinfo->laguna_mmio + 0x2c4);
+                       tile_control &= ~0x80;
+                       fb_writew(tile_control, cinfo->laguna_mmio + 0x2c4);
                }
+
+               fb_writel(pcifc | 0x10000000l, cinfo->laguna_mmio + 0x3fc);
+               fb_writeb(tile & 0x3f, cinfo->laguna_mmio + 0x407);
+               control = fb_readw(cinfo->laguna_mmio + 0x402);
+               threshold = fb_readw(cinfo->laguna_mmio + 0xea);
+               control &= ~0x6800;
+               format = 0;
+               threshold &= 0xffc0 & 0x3fbf;
        }
        if (nom) {
-               vga_wseq(regbase, CL_SEQRB, nom);
                tmp = den << 1;
                if (div != 0)
                        tmp |= 1;
-
                /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
                if ((cinfo->btype == BT_SD64) ||
                    (cinfo->btype == BT_ALPINE) ||
                    (cinfo->btype == BT_GD5480))
                        tmp |= 0x80;
 
-               DPRINTK("CL_SEQR1B: %ld\n", (long) tmp);
-               vga_wseq(regbase, CL_SEQR1B, tmp);
+               /* Laguna chipset has reversed clock registers */
+               if (is_laguna(cinfo)) {
+                       vga_wseq(regbase, CL_SEQRE, tmp);
+                       vga_wseq(regbase, CL_SEQR1E, nom);
+               } else {
+                       vga_wseq(regbase, CL_SEQRE, nom);
+                       vga_wseq(regbase, CL_SEQR1E, tmp);
+               }
        }
 
        if (yres >= 1024)
@@ -916,9 +912,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                 * address wrap, no compat. */
                vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3);
 
-/* HAEH?       vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20);
- * previously: 0x00  unlock VGA_CRTC_H_TOTAL..CRT7 */
-
        /* don't know if it would hurt to also program this if no interlaced */
        /* mode is used, but I feel better this way.. :-) */
        if (var->vmode & FB_VMODE_INTERLACED)
@@ -926,19 +919,15 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
        else
                vga_wcrt(regbase, VGA_CRTC_REGS, 0x00); /* interlace control */
 
-       vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0);
-
-       /* adjust horizontal/vertical sync type (low/high) */
+       /* adjust horizontal/vertical sync type (low/high), use VCLK3 */
        /* enable display memory & CRTC I/O address for color mode */
-       tmp = 0x03;
+       tmp = 0x03 | 0xc;
        if (var->sync & FB_SYNC_HOR_HIGH_ACT)
                tmp |= 0x40;
        if (var->sync & FB_SYNC_VERT_HIGH_ACT)
                tmp |= 0x80;
        WGen(cinfo, VGA_MIS_W, tmp);
 
-       /* Screen A Preset Row-Scan register */
-       vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0);
        /* text cursor on and start line */
        vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0);
        /* text cursor end line */
@@ -952,7 +941,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
 
        /* programming for different color depths */
        if (var->bits_per_pixel == 1) {
-               DPRINTK("cirrusfb: preparing for 1 bit deep display\n");
+               dev_dbg(info->device, "preparing for 1 bit deep display\n");
                vga_wgfx(regbase, VGA_GFX_MODE, 0);     /* mode register */
 
                /* SR07 */
@@ -964,68 +953,53 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                case BT_PICASSO4:
                case BT_ALPINE:
                case BT_GD5480:
-                       DPRINTK(" (for GD54xx)\n");
                        vga_wseq(regbase, CL_SEQR7,
-                                 regs.multiplexing ?
+                                cinfo->multiplexing ?
                                        bi->sr07_1bpp_mux : bi->sr07_1bpp);
                        break;
 
                case BT_LAGUNA:
-                       DPRINTK(" (for GD546x)\n");
+               case BT_LAGUNAB:
                        vga_wseq(regbase, CL_SEQR7,
                                vga_rseq(regbase, CL_SEQR7) & ~0x01);
                        break;
 
                default:
-                       printk(KERN_WARNING "cirrusfb: unknown Board\n");
+                       dev_warn(info->device, "unknown Board\n");
                        break;
                }
 
                /* Extended Sequencer Mode */
                switch (cinfo->btype) {
-               case BT_SD64:
-                       /* setting the SEQRF on SD64 is not necessary
-                        * (only during init)
-                        */
-                       DPRINTK("(for SD64)\n");
-                       /*  MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x1a);
-                       break;
 
                case BT_PICCOLO:
                case BT_SPECTRUM:
-                       DPRINTK("(for Piccolo/Spectrum)\n");
-                       /* ### ueberall 0x22? */
-                       /* ##vorher 1c MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
                        /* evtl d0 bei 1 bit? avoid FIFO underruns..? */
                        vga_wseq(regbase, CL_SEQRF, 0xb0);
                        break;
 
                case BT_PICASSO:
-                       DPRINTK("(for Picasso)\n");
-                       /* ##vorher 22 MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
                        /* ## vorher d0 avoid FIFO underruns..? */
                        vga_wseq(regbase, CL_SEQRF, 0xd0);
                        break;
 
+               case BT_SD64:
                case BT_PICASSO4:
                case BT_ALPINE:
                case BT_GD5480:
                case BT_LAGUNA:
-                       DPRINTK(" (for GD54xx)\n");
+               case BT_LAGUNAB:
                        /* do nothing */
                        break;
 
                default:
-                       printk(KERN_WARNING "cirrusfb: unknown Board\n");
+                       dev_warn(info->device, "unknown Board\n");
                        break;
                }
 
                /* pixel mask: pass-through for first plane */
                WGen(cinfo, VGA_PEL_MSK, 0x01);
-               if (regs.multiplexing)
+               if (cinfo->multiplexing)
                        /* hidden dac reg: 1280x1024 */
                        WHDR(cinfo, 0x4a);
                else
@@ -1035,7 +1009,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x06);
                /* plane mask: only write to first plane */
                vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x01);
-               offset = var->xres_virtual / 16;
        }
 
        /******************************************************
@@ -1045,7 +1018,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
         */
 
        else if (var->bits_per_pixel == 8) {
-               DPRINTK("cirrusfb: preparing for 8 bit deep display\n");
+               dev_dbg(info->device, "preparing for 8 bit deep display\n");
                switch (cinfo->btype) {
                case BT_SD64:
                case BT_PICCOLO:
@@ -1054,34 +1027,27 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                case BT_PICASSO4:
                case BT_ALPINE:
                case BT_GD5480:
-                       DPRINTK(" (for GD54xx)\n");
                        vga_wseq(regbase, CL_SEQR7,
-                                 regs.multiplexing ?
+                                 cinfo->multiplexing ?
                                        bi->sr07_8bpp_mux : bi->sr07_8bpp);
                        break;
 
                case BT_LAGUNA:
-                       DPRINTK(" (for GD546x)\n");
+               case BT_LAGUNAB:
                        vga_wseq(regbase, CL_SEQR7,
                                vga_rseq(regbase, CL_SEQR7) | 0x01);
+                       threshold |= 0x10;
                        break;
 
                default:
-                       printk(KERN_WARNING "cirrusfb: unknown Board\n");
+                       dev_warn(info->device, "unknown Board\n");
                        break;
                }
 
                switch (cinfo->btype) {
-               case BT_SD64:
-                       /* MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x1d);
-                       break;
-
                case BT_PICCOLO:
                case BT_PICASSO:
                case BT_SPECTRUM:
-                       /* ### vorher 1c MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
                        /* Fast Page-Mode writes */
                        vga_wseq(regbase, CL_SEQRF, 0xb0);
                        break;
@@ -1091,40 +1057,27 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                        /* ### INCOMPLETE!! */
                        vga_wseq(regbase, CL_SEQRF, 0xb8);
 #endif
-/*                     vga_wseq(regbase, CL_SEQR1F, 0x1c); */
-                       break;
-
                case BT_ALPINE:
-                       DPRINTK(" (for GD543x)\n");
-                       /* We already set SRF and SR1F */
-                       break;
-
+               case BT_SD64:
                case BT_GD5480:
                case BT_LAGUNA:
-                       DPRINTK(" (for GD54xx)\n");
+               case BT_LAGUNAB:
                        /* do nothing */
                        break;
 
                default:
-                       printk(KERN_WARNING "cirrusfb: unknown Board\n");
+                       dev_warn(info->device, "unknown board\n");
                        break;
                }
 
                /* mode register: 256 color mode */
                vga_wgfx(regbase, VGA_GFX_MODE, 64);
-               /* pixel mask: pass-through all planes */
-               WGen(cinfo, VGA_PEL_MSK, 0xff);
-               if (regs.multiplexing)
+               if (cinfo->multiplexing)
                        /* hidden dac reg: 1280x1024 */
                        WHDR(cinfo, 0x4a);
                else
                        /* hidden dac: nothing */
                        WHDR(cinfo, 0);
-               /* memory mode: chain4, ext. memory */
-               vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
-               /* plane mask: enable writing to all 4 planes */
-               vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff);
-               offset = var->xres_virtual / 8;
        }
 
        /******************************************************
@@ -1134,147 +1087,110 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
         */
 
        else if (var->bits_per_pixel == 16) {
-               DPRINTK("cirrusfb: preparing for 16 bit deep display\n");
+               dev_dbg(info->device, "preparing for 16 bit deep display\n");
                switch (cinfo->btype) {
-               case BT_SD64:
-                       /* Extended Sequencer Mode: 256c col. mode */
-                       vga_wseq(regbase, CL_SEQR7, 0xf7);
-                       /* MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x1e);
-                       break;
-
                case BT_PICCOLO:
                case BT_SPECTRUM:
                        vga_wseq(regbase, CL_SEQR7, 0x87);
                        /* Fast Page-Mode writes */
                        vga_wseq(regbase, CL_SEQRF, 0xb0);
-                       /* MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
                        break;
 
                case BT_PICASSO:
                        vga_wseq(regbase, CL_SEQR7, 0x27);
                        /* Fast Page-Mode writes */
                        vga_wseq(regbase, CL_SEQRF, 0xb0);
-                       /* MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
                        break;
 
+               case BT_SD64:
                case BT_PICASSO4:
-                       vga_wseq(regbase, CL_SEQR7, 0x27);
-/*                     vga_wseq(regbase, CL_SEQR1F, 0x1c);  */
-                       break;
-
                case BT_ALPINE:
-                       DPRINTK(" (for GD543x)\n");
-                       vga_wseq(regbase, CL_SEQR7, 0xa7);
+                       /* Extended Sequencer Mode: 256c col. mode */
+                       vga_wseq(regbase, CL_SEQR7,
+                                       cinfo->doubleVCLK ? 0xa3 : 0xa7);
                        break;
 
                case BT_GD5480:
-                       DPRINTK(" (for GD5480)\n");
                        vga_wseq(regbase, CL_SEQR7, 0x17);
                        /* We already set SRF and SR1F */
                        break;
 
                case BT_LAGUNA:
-                       DPRINTK(" (for GD546x)\n");
+               case BT_LAGUNAB:
                        vga_wseq(regbase, CL_SEQR7,
                                vga_rseq(regbase, CL_SEQR7) & ~0x01);
+                       control |= 0x2000;
+                       format |= 0x1400;
+                       threshold |= 0x10;
                        break;
 
                default:
-                       printk(KERN_WARNING "CIRRUSFB: unknown Board\n");
+                       dev_warn(info->device, "unknown Board\n");
                        break;
                }
 
                /* mode register: 256 color mode */
                vga_wgfx(regbase, VGA_GFX_MODE, 64);
-               /* pixel mask: pass-through all planes */
-               WGen(cinfo, VGA_PEL_MSK, 0xff);
 #ifdef CONFIG_PCI
-               WHDR(cinfo, 0xc0);      /* Copy Xbh */
+               WHDR(cinfo, cinfo->doubleVCLK ? 0xe1 : 0xc1);
 #elif defined(CONFIG_ZORRO)
                /* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
                WHDR(cinfo, 0xa0);      /* hidden dac reg: nothing special */
 #endif
-               /* memory mode: chain4, ext. memory */
-               vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
-               /* plane mask: enable writing to all 4 planes */
-               vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff);
-               offset = var->xres_virtual / 4;
        }
 
        /******************************************************
         *
-        * 32 bpp
+        * 24 bpp
         *
         */
 
-       else if (var->bits_per_pixel == 32) {
-               DPRINTK("cirrusfb: preparing for 32 bit deep display\n");
+       else if (var->bits_per_pixel == 24) {
+               dev_dbg(info->device, "preparing for 24 bit deep display\n");
                switch (cinfo->btype) {
-               case BT_SD64:
-                       /* Extended Sequencer Mode: 256c col. mode */
-                       vga_wseq(regbase, CL_SEQR7, 0xf9);
-                       /* MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x1e);
-                       break;
-
                case BT_PICCOLO:
                case BT_SPECTRUM:
                        vga_wseq(regbase, CL_SEQR7, 0x85);
                        /* Fast Page-Mode writes */
                        vga_wseq(regbase, CL_SEQRF, 0xb0);
-                       /* MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
                        break;
 
                case BT_PICASSO:
                        vga_wseq(regbase, CL_SEQR7, 0x25);
                        /* Fast Page-Mode writes */
                        vga_wseq(regbase, CL_SEQRF, 0xb0);
-                       /* MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
                        break;
 
+               case BT_SD64:
                case BT_PICASSO4:
-                       vga_wseq(regbase, CL_SEQR7, 0x25);
-/*                     vga_wseq(regbase, CL_SEQR1F, 0x1c);  */
-                       break;
-
                case BT_ALPINE:
-                       DPRINTK(" (for GD543x)\n");
-                       vga_wseq(regbase, CL_SEQR7, 0xa9);
+                       /* Extended Sequencer Mode: 256c col. mode */
+                       vga_wseq(regbase, CL_SEQR7, 0xa5);
                        break;
 
                case BT_GD5480:
-                       DPRINTK(" (for GD5480)\n");
-                       vga_wseq(regbase, CL_SEQR7, 0x19);
+                       vga_wseq(regbase, CL_SEQR7, 0x15);
                        /* We already set SRF and SR1F */
                        break;
 
                case BT_LAGUNA:
-                       DPRINTK(" (for GD546x)\n");
+               case BT_LAGUNAB:
                        vga_wseq(regbase, CL_SEQR7,
                                vga_rseq(regbase, CL_SEQR7) & ~0x01);
+                       control |= 0x4000;
+                       format |= 0x2400;
+                       threshold |= 0x20;
                        break;
 
                default:
-                       printk(KERN_WARNING "cirrusfb: unknown Board\n");
+                       dev_warn(info->device, "unknown Board\n");
                        break;
                }
 
                /* mode register: 256 color mode */
                vga_wgfx(regbase, VGA_GFX_MODE, 64);
-               /* pixel mask: pass-through all planes */
-               WGen(cinfo, VGA_PEL_MSK, 0xff);
                /* hidden dac reg: 8-8-8 mode (24 or 32) */
                WHDR(cinfo, 0xc5);
-               /* memory mode: chain4, ext. memory */
-               vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
-               /* plane mask: enable writing to all 4 planes */
-               vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff);
-               offset = var->xres_virtual / 4;
        }
 
        /******************************************************
@@ -1284,67 +1200,55 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
         */
 
        else
-               printk(KERN_ERR "cirrusfb: What's this?? "
-                       " requested color depth == %d.\n",
+               dev_err(info->device,
+                       "What's this? requested color depth == %d.\n",
                        var->bits_per_pixel);
 
-       vga_wcrt(regbase, VGA_CRTC_OFFSET, offset & 0xff);
+       pitch = info->fix.line_length >> 3;
+       vga_wcrt(regbase, VGA_CRTC_OFFSET, pitch & 0xff);
        tmp = 0x22;
-       if (offset & 0x100)
+       if (pitch & 0x100)
                tmp |= 0x10;    /* offset overflow bit */
 
        /* screen start addr #16-18, fastpagemode cycles */
        vga_wcrt(regbase, CL_CRT1B, tmp);
 
-       if (cinfo->btype == BT_SD64 ||
-           cinfo->btype == BT_PICASSO4 ||
-           cinfo->btype == BT_ALPINE ||
-           cinfo->btype == BT_GD5480)
-               /* screen start address bit 19 */
-               vga_wcrt(regbase, CL_CRT1D, 0x00);
-
-       /* text cursor location high */
-       vga_wcrt(regbase, VGA_CRTC_CURSOR_HI, 0);
-       /* text cursor location low */
-       vga_wcrt(regbase, VGA_CRTC_CURSOR_LO, 0);
-       /* underline row scanline = at very bottom */
-       vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0);
-
-       /* controller mode */
-       vga_wattr(regbase, VGA_ATC_MODE, 1);
-       /* overscan (border) color */
-       vga_wattr(regbase, VGA_ATC_OVERSCAN, 0);
-       /* color plane enable */
-       vga_wattr(regbase, VGA_ATC_PLANE_ENABLE, 15);
+       /* screen start address bit 19 */
+       if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19)
+               vga_wcrt(regbase, CL_CRT1D, (pitch >> 9) & 1);
+
+       if (is_laguna(cinfo)) {
+               tmp = 0;
+               if ((htotal + 5) & 256)
+                       tmp |= 128;
+               if (hdispend & 256)
+                       tmp |= 64;
+               if (hsyncstart & 256)
+                       tmp |= 48;
+               if (vtotal & 1024)
+                       tmp |= 8;
+               if (vdispend & 1024)
+                       tmp |= 4;
+               if (vsyncstart & 1024)
+                       tmp |= 3;
+
+               vga_wcrt(regbase, CL_CRT1E, tmp);
+               dev_dbg(info->device, "CRT1e: %d\n", tmp);
+       }
+
        /* pixel panning */
        vga_wattr(regbase, CL_AR33, 0);
-       /* color select */
-       vga_wattr(regbase, VGA_ATC_COLOR_PAGE, 0);
 
        /* [ EGS: SetOffset(); ] */
        /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
        AttrOn(cinfo);
 
-       /* set/reset register */
-       vga_wgfx(regbase, VGA_GFX_SR_VALUE, 0);
-       /* set/reset enable */
-       vga_wgfx(regbase, VGA_GFX_SR_ENABLE, 0);
-       /* color compare */
-       vga_wgfx(regbase, VGA_GFX_COMPARE_VALUE, 0);
-       /* data rotate */
-       vga_wgfx(regbase, VGA_GFX_DATA_ROTATE, 0);
-       /* read map select */
-       vga_wgfx(regbase, VGA_GFX_PLANE_READ, 0);
-       /* miscellaneous register */
-       vga_wgfx(regbase, VGA_GFX_MISC, 1);
-       /* color don't care */
-       vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 15);
-       /* bit mask */
-       vga_wgfx(regbase, VGA_GFX_BIT_MASK, 255);
-
-       /* graphics cursor attributes: nothing special */
-       vga_wseq(regbase, CL_SEQR12, 0x0);
-
+       if (is_laguna(cinfo)) {
+               /* no tiles */
+               fb_writew(control | 0x1000, cinfo->laguna_mmio + 0x402);
+               fb_writew(format, cinfo->laguna_mmio + 0xc0);
+               fb_writew(threshold, cinfo->laguna_mmio + 0xea);
+       }
        /* finally, turn on everything - turn off "FullBandwidth" bit */
        /* also, set "DotClock%2" bit where requested */
        tmp = 0x01;
@@ -1355,18 +1259,12 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
 */
 
        vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, tmp);
-       DPRINTK("CL_SEQR1: %d\n", tmp);
-
-       cinfo->currentmode = regs;
-
-       /* pan to requested offset */
-       cirrusfb_pan_display(var, info);
+       dev_dbg(info->device, "CL_SEQR1: %d\n", tmp);
 
 #ifdef CIRRUSFB_DEBUG
-       cirrusfb_dump();
+       cirrusfb_dbg_reg_dump(info, NULL);
 #endif
 
-       DPRINTK("EXIT\n");
        return 0;
 }
 
@@ -1418,27 +1316,19 @@ static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,
 static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
                                struct fb_info *info)
 {
-       int xoffset = 0;
-       int yoffset = 0;
+       int xoffset;
        unsigned long base;
-       unsigned char tmp = 0, tmp2 = 0, xpix;
+       unsigned char tmp, xpix;
        struct cirrusfb_info *cinfo = info->par;
 
-       DPRINTK("ENTER\n");
-       DPRINTK("virtual offset: (%d,%d)\n", var->xoffset, var->yoffset);
-
        /* no range checks for xoffset and yoffset,   */
        /* as fb_pan_display has already done this */
        if (var->vmode & FB_VMODE_YWRAP)
                return -EINVAL;
 
-       info->var.xoffset = var->xoffset;
-       info->var.yoffset = var->yoffset;
-
        xoffset = var->xoffset * info->var.bits_per_pixel / 8;
-       yoffset = var->yoffset;
 
-       base = yoffset * info->fix.line_length + xoffset;
+       base = var->yoffset * info->fix.line_length + xoffset;
 
        if (info->var.bits_per_pixel == 1) {
                /* base is already correct */
@@ -1448,14 +1338,15 @@ static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
                xpix = (unsigned char) ((xoffset % 4) * 2);
        }
 
-       cirrusfb_WaitBLT(cinfo->regbase); /* make sure all the BLT's are done */
+       if (!is_laguna(cinfo))
+               cirrusfb_WaitBLT(cinfo->regbase);
 
        /* lower 8 + 8 bits of screen start address */
-       vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO,
-                (unsigned char) (base & 0xff));
-       vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI,
-                (unsigned char) (base >> 8));
+       vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, base & 0xff);
+       vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, (base >> 8) & 0xff);
 
+       /* 0xf2 is %11110010, exclude tmp bits */
+       tmp = vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2;
        /* construct bits 16, 17 and 18 of screen start address */
        if (base & 0x10000)
                tmp |= 0x01;
@@ -1464,13 +1355,17 @@ static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
        if (base & 0x40000)
                tmp |= 0x08;
 
-       /* 0xf2 is %11110010, exclude tmp bits */
-       tmp2 = (vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2) | tmp;
-       vga_wcrt(cinfo->regbase, CL_CRT1B, tmp2);
+       vga_wcrt(cinfo->regbase, CL_CRT1B, tmp);
 
        /* construct bit 19 of screen start address */
-       if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19)
-               vga_wcrt(cinfo->regbase, CL_CRT1D, (base >> 12) & 0x80);
+       if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) {
+               tmp = vga_rcrt(cinfo->regbase, CL_CRT1D);
+               if (is_laguna(cinfo))
+                       tmp = (tmp & ~0x18) | ((base >> 16) & 0x18);
+               else
+                       tmp = (tmp & ~0x80) | ((base >> 12) & 0x80);
+               vga_wcrt(cinfo->regbase, CL_CRT1D, tmp);
+       }
 
        /* write pixel panning value to AR33; this does not quite work in 8bpp
         *
@@ -1479,9 +1374,6 @@ static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
        if (info->var.bits_per_pixel == 1)
                vga_wattr(cinfo->regbase, CL_AR33, xpix);
 
-       cirrusfb_WaitBLT(cinfo->regbase);
-
-       DPRINTK("EXIT\n");
        return 0;
 }
 
@@ -1502,57 +1394,54 @@ static int cirrusfb_blank(int blank_mode, struct fb_info *info)
        struct cirrusfb_info *cinfo = info->par;
        int current_mode = cinfo->blank_mode;
 
-       DPRINTK("ENTER, blank mode = %d\n", blank_mode);
+       dev_dbg(info->device, "ENTER, blank mode = %d\n", blank_mode);
 
        if (info->state != FBINFO_STATE_RUNNING ||
            current_mode == blank_mode) {
-               DPRINTK("EXIT, returning 0\n");
+               dev_dbg(info->device, "EXIT, returning 0\n");
                return 0;
        }
 
        /* Undo current */
        if (current_mode == FB_BLANK_NORMAL ||
-           current_mode == FB_BLANK_UNBLANK) {
-               /* unblank the screen */
-               val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE);
+           current_mode == FB_BLANK_UNBLANK)
                /* clear "FullBandwidth" bit */
-               vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val & 0xdf);
-               /* and undo VESA suspend trickery */
-               vga_wgfx(cinfo->regbase, CL_GRE, 0x00);
-       }
-
-       /* set new */
-       if (blank_mode > FB_BLANK_NORMAL) {
-               /* blank the screen */
-               val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE);
+               val = 0;
+       else
                /* set "FullBandwidth" bit */
-               vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val | 0x20);
-       }
+               val = 0x20;
+
+       val |= vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE) & 0xdf;
+       vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val);
 
        switch (blank_mode) {
        case FB_BLANK_UNBLANK:
        case FB_BLANK_NORMAL:
+               val = 0x00;
                break;
        case FB_BLANK_VSYNC_SUSPEND:
-               vga_wgfx(cinfo->regbase, CL_GRE, 0x04);
+               val = 0x04;
                break;
        case FB_BLANK_HSYNC_SUSPEND:
-               vga_wgfx(cinfo->regbase, CL_GRE, 0x02);
+               val = 0x02;
                break;
        case FB_BLANK_POWERDOWN:
-               vga_wgfx(cinfo->regbase, CL_GRE, 0x06);
+               val = 0x06;
                break;
        default:
-               DPRINTK("EXIT, returning 1\n");
+               dev_dbg(info->device, "EXIT, returning 1\n");
                return 1;
        }
 
+       vga_wgfx(cinfo->regbase, CL_GRE, val);
+
        cinfo->blank_mode = blank_mode;
-       DPRINTK("EXIT, returning 0\n");
+       dev_dbg(info->device, "EXIT, returning 0\n");
 
        /* Let fbcon do a soft blank for us */
        return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
 }
+
 /**** END   Hardware specific Routines **************************************/
 /****************************************************************************/
 /**** BEGIN Internal Routines ***********************************************/
@@ -1562,8 +1451,6 @@ static void init_vgachip(struct fb_info *info)
        struct cirrusfb_info *cinfo = info->par;
        const struct cirrusfb_board_info_rec *bi;
 
-       DPRINTK("ENTER\n");
-
        assert(cinfo != NULL);
 
        bi = &cirrusfb_board_info[cinfo->btype];
@@ -1591,25 +1478,23 @@ static void init_vgachip(struct fb_info *info)
                /* disable flickerfixer */
                vga_wcrt(cinfo->regbase, CL_CRT51, 0x00);
                mdelay(100);
-               /* from Klaus' NetBSD driver: */
-               vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
-               /* put blitter into 542x compat */
-               vga_wgfx(cinfo->regbase, CL_GR33, 0x00);
                /* mode */
                vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
-               break;
-
-       case BT_GD5480:
+       case BT_GD5480:  /* fall through */
                /* from Klaus' NetBSD driver: */
                vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
+       case BT_ALPINE:  /* fall through */
+               /* put blitter into 542x compat */
+               vga_wgfx(cinfo->regbase, CL_GR33, 0x00);
                break;
 
-       case BT_ALPINE:
+       case BT_LAGUNA:
+       case BT_LAGUNAB:
                /* Nothing to do to reset the board. */
                break;
 
        default:
-               printk(KERN_ERR "cirrusfb: Warning: Unknown board type\n");
+               dev_err(info->device, "Warning: Unknown board type\n");
                break;
        }
 
@@ -1629,31 +1514,28 @@ static void init_vgachip(struct fb_info *info)
                        WGen(cinfo, CL_VSSM2, 0x01);
 
                /* reset sequencer logic */
-               vga_wseq(cinfo->regbase, CL_SEQR0, 0x03);
+               vga_wseq(cinfo->regbase, VGA_SEQ_RESET, 0x03);
 
                /* FullBandwidth (video off) and 8/9 dot clock */
                vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21);
-               /* polarity (-/-), disable access to display memory,
-                * VGA_CRTC_START_HI base address: color
-                */
-               WGen(cinfo, VGA_MIS_W, 0xc1);
 
                /* "magic cookie" - doesn't make any sense to me.. */
 /*      vga_wgfx(cinfo->regbase, CL_GRA, 0xce);   */
                /* unlock all extension registers */
                vga_wseq(cinfo->regbase, CL_SEQR6, 0x12);
 
-               /* reset blitter */
-               vga_wgfx(cinfo->regbase, CL_GR31, 0x04);
-
                switch (cinfo->btype) {
                case BT_GD5480:
                        vga_wseq(cinfo->regbase, CL_SEQRF, 0x98);
                        break;
                case BT_ALPINE:
+               case BT_LAGUNA:
+               case BT_LAGUNAB:
                        break;
                case BT_SD64:
+#ifdef CONFIG_ZORRO
                        vga_wseq(cinfo->regbase, CL_SEQRF, 0xb8);
+#endif
                        break;
                default:
                        vga_wseq(cinfo->regbase, CL_SEQR16, 0x0f);
@@ -1665,8 +1547,8 @@ static void init_vgachip(struct fb_info *info)
        vga_wseq(cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff);
        /* character map select: doesn't even matter in gx mode */
        vga_wseq(cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00);
-       /* memory mode: chain-4, no odd/even, ext. memory */
-       vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0e);
+       /* memory mode: chain4, ext. memory */
+       vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
 
        /* controller-internal base address of video memory */
        if (bi->init_sr07)
@@ -1692,20 +1574,12 @@ static void init_vgachip(struct fb_info *info)
                vga_wseq(cinfo->regbase, CL_SEQR18, 0x02);
        }
 
-       /* MCLK select etc. */
-       if (bi->init_sr1f)
-               vga_wseq(cinfo->regbase, CL_SEQR1F, bi->sr1f);
-
        /* Screen A preset row scan: none */
        vga_wcrt(cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00);
        /* Text cursor start: disable text cursor */
        vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20);
        /* Text cursor end: - */
        vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00);
-       /* Screen start address high: 0 */
-       vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, 0x00);
-       /* Screen start address low: 0 */
-       vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, 0x00);
        /* text cursor location high: 0 */
        vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00);
        /* text cursor location low: 0 */
@@ -1713,10 +1587,6 @@ static void init_vgachip(struct fb_info *info)
 
        /* Underline Row scanline: - */
        vga_wcrt(cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00);
-       /* mode control: timing enable, byte mode, no compat modes */
-       vga_wcrt(cinfo->regbase, VGA_CRTC_MODE, 0xc3);
-       /* Line Compare: not needed */
-       vga_wcrt(cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00);
        /* ### add 0x40 for text modes with > 30 MHz pixclock */
        /* ext. display controls: ext.adr. wrap */
        vga_wcrt(cinfo->regbase, CL_CRT1B, 0x02);
@@ -1739,7 +1609,9 @@ static void init_vgachip(struct fb_info *info)
        vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f);
        /* Bit Mask: no mask at all */
        vga_wgfx(cinfo->regbase, VGA_GFX_BIT_MASK, 0xff);
-       if (cinfo->btype == BT_ALPINE)
+
+       if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64 ||
+           is_laguna(cinfo))
                /* (5434 can't have bit 3 set for bitblt) */
                vga_wgfx(cinfo->regbase, CL_GRB, 0x20);
        else
@@ -1779,18 +1651,11 @@ static void init_vgachip(struct fb_info *info)
        vga_wattr(cinfo->regbase, VGA_ATC_OVERSCAN, 0x00);
        /* Color Plane enable: Enable all 4 planes */
        vga_wattr(cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f);
-/* ###  vga_wattr(cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */
        /* Color Select: - */
        vga_wattr(cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00);
 
        WGen(cinfo, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */
 
-       if (cinfo->btype != BT_ALPINE && cinfo->btype != BT_GD5480)
-       /* polarity (-/-), enable display mem,
-        * VGA_CRTC_START_HI i/o base = color
-        */
-               WGen(cinfo, VGA_MIS_W, 0xc3);
-
        /* BLT Start/status: Blitter reset */
        vga_wgfx(cinfo->regbase, CL_GR31, 0x04);
        /* - " -           : "end-of-reset" */
@@ -1798,8 +1663,6 @@ static void init_vgachip(struct fb_info *info)
 
        /* misc... */
        WHDR(cinfo, 0); /* Hidden DAC register: - */
-
-       DPRINTK("EXIT\n");
        return;
 }
 
@@ -1808,8 +1671,6 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on)
 #ifdef CONFIG_ZORRO /* only works on Zorro boards */
        static int IsOn = 0;    /* XXX not ok for multiple boards */
 
-       DPRINTK("ENTER\n");
-
        if (cinfo->btype == BT_PICASSO4)
                return;         /* nothing to switch */
        if (cinfo->btype == BT_ALPINE)
@@ -1819,8 +1680,6 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on)
        if (cinfo->btype == BT_PICASSO) {
                if ((on && !IsOn) || (!on && IsOn))
                        WSFR(cinfo, 0xff);
-
-               DPRINTK("EXIT\n");
                return;
        }
        if (on) {
@@ -1847,11 +1706,10 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on)
                case BT_SPECTRUM:
                        WSFR(cinfo, 0x4f);
                        break;
-               default: /* do nothing */ break;
+               default: /* do nothing */
+                       break;
                }
        }
-
-       DPRINTK("EXIT\n");
 #endif /* CONFIG_ZORRO */
 }
 
@@ -1859,6 +1717,17 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on)
 /* Linux 2.6-style  accelerated functions */
 /******************************************/
 
+static int cirrusfb_sync(struct fb_info *info)
+{
+       struct cirrusfb_info *cinfo = info->par;
+
+       if (!is_laguna(cinfo)) {
+               while (vga_rgfx(cinfo->regbase, CL_GR31) & 0x03)
+                       cpu_relax();
+       }
+       return 0;
+}
+
 static void cirrusfb_fillrect(struct fb_info *info,
                              const struct fb_fillrect *region)
 {
@@ -1894,8 +1763,8 @@ static void cirrusfb_fillrect(struct fb_info *info,
                          info->var.bits_per_pixel,
                          (region->dx * m) / 8, region->dy,
                          (region->width * m) / 8, region->height,
-                         color,
-                         info->fix.line_length);
+                         color, color,
+                         info->fix.line_length, 0x40);
 }
 
 static void cirrusfb_copyarea(struct fb_info *info,
@@ -1943,9 +1812,46 @@ static void cirrusfb_imageblit(struct fb_info *info,
                               const struct fb_image *image)
 {
        struct cirrusfb_info *cinfo = info->par;
+       unsigned char op = (info->var.bits_per_pixel == 24) ? 0xc : 0x4;
 
-       cirrusfb_WaitBLT(cinfo->regbase);
-       cfb_imageblit(info, image);
+       if (info->state != FBINFO_STATE_RUNNING)
+               return;
+       /* Alpine/SD64 does not work at 24bpp ??? */
+       if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1)
+               cfb_imageblit(info, image);
+       else if ((cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64) &&
+                 op == 0xc)
+               cfb_imageblit(info, image);
+       else {
+               unsigned size = ((image->width + 7) >> 3) * image->height;
+               int m = info->var.bits_per_pixel;
+               u32 fg, bg;
+
+               if (info->var.bits_per_pixel == 8) {
+                       fg = image->fg_color;
+                       bg = image->bg_color;
+               } else {
+                       fg = ((u32 *)(info->pseudo_palette))[image->fg_color];
+                       bg = ((u32 *)(info->pseudo_palette))[image->bg_color];
+               }
+               if (info->var.bits_per_pixel == 24) {
+                       /* clear background first */
+                       cirrusfb_RectFill(cinfo->regbase,
+                                         info->var.bits_per_pixel,
+                                         (image->dx * m) / 8, image->dy,
+                                         (image->width * m) / 8,
+                                         image->height,
+                                         bg, bg,
+                                         info->fix.line_length, 0x40);
+               }
+               cirrusfb_RectFill(cinfo->regbase,
+                                 info->var.bits_per_pixel,
+                                 (image->dx * m) / 8, image->dy,
+                                 (image->width * m) / 8, image->height,
+                                 fg, bg,
+                                 info->fix.line_length, op);
+               memcpy(info->screen_base, image->data, size);
+       }
 }
 
 #ifdef CONFIG_PPC_PREP
@@ -1953,12 +1859,8 @@ static void cirrusfb_imageblit(struct fb_info *info,
 #define PREP_IO_BASE    ((volatile unsigned char *) 0x80000000)
 static void get_prep_addrs(unsigned long *display, unsigned long *registers)
 {
-       DPRINTK("ENTER\n");
-
        *display = PREP_VIDEO_BASE;
        *registers = (unsigned long) PREP_IO_BASE;
-
-       DPRINTK("EXIT\n");
 }
 
 #endif                         /* CONFIG_PPC_PREP */
@@ -1970,40 +1872,43 @@ static int release_io_ports;
  * based on the DRAM bandwidth bit and DRAM bank switching bit.  This
  * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
  * seem to have. */
-static unsigned int __devinit cirrusfb_get_memsize(u8 __iomem *regbase)
+static unsigned int __devinit cirrusfb_get_memsize(struct fb_info *info,
+                                                  u8 __iomem *regbase)
 {
        unsigned long mem;
-       unsigned char SRF;
+       struct cirrusfb_info *cinfo = info->par;
 
-       DPRINTK("ENTER\n");
+       if (is_laguna(cinfo)) {
+               unsigned char SR14 = vga_rseq(regbase, CL_SEQR14);
 
-       SRF = vga_rseq(regbase, CL_SEQRF);
-       switch ((SRF & 0x18)) {
-       case 0x08:
-               mem = 512 * 1024;
-               break;
-       case 0x10:
-               mem = 1024 * 1024;
-               break;
-       /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory
-        * on the 5430.
-        */
-       case 0x18:
-               mem = 2048 * 1024;
-               break;
-       default:
-               printk(KERN_WARNING "CLgenfb: Unknown memory size!\n");
-               mem = 1024 * 1024;
+               mem = ((SR14 & 7) + 1) << 20;
+       } else {
+               unsigned char SRF = vga_rseq(regbase, CL_SEQRF);
+               switch ((SRF & 0x18)) {
+               case 0x08:
+                       mem = 512 * 1024;
+                       break;
+               case 0x10:
+                       mem = 1024 * 1024;
+                       break;
+               /* 64-bit DRAM data bus width; assume 2MB.
+                * Also indicates 2MB memory on the 5430.
+                */
+               case 0x18:
+                       mem = 2048 * 1024;
+                       break;
+               default:
+                       dev_warn(info->device, "Unknown memory size!\n");
+                       mem = 1024 * 1024;
+               }
+               /* If DRAM bank switching is enabled, there must be
+                * twice as much memory installed. (4MB on the 5434)
+                */
+               if (cinfo->btype != BT_ALPINE && (SRF & 0x80) != 0)
+                       mem *= 2;
        }
-       if (SRF & 0x80)
-       /* If DRAM bank switching is enabled, there must be twice as much
-        * memory installed. (4MB on the 5434)
-        */
-               mem *= 2;
 
        /* TODO: Handling of GD5446/5480 (see XF86 sources ...) */
-
-       DPRINTK("EXIT\n");
        return mem;
 }
 
@@ -2014,8 +1919,6 @@ static void get_pci_addrs(const struct pci_dev *pdev,
        assert(display != NULL);
        assert(registers != NULL);
 
-       DPRINTK("ENTER\n");
-
        *display = 0;
        *registers = 0;
 
@@ -2030,14 +1933,15 @@ static void get_pci_addrs(const struct pci_dev *pdev,
        }
 
        assert(*display != 0);
-
-       DPRINTK("EXIT\n");
 }
 
 static void cirrusfb_pci_unmap(struct fb_info *info)
 {
        struct pci_dev *pdev = to_pci_dev(info->device);
+       struct cirrusfb_info *cinfo = info->par;
 
+       if (cinfo->laguna_mmio == NULL)
+               iounmap(cinfo->laguna_mmio);
        iounmap(info->screen_base);
 #if 0 /* if system didn't claim this region, we would... */
        release_mem_region(0xA0000, 65535);
@@ -2067,6 +1971,22 @@ static void cirrusfb_zorro_unmap(struct fb_info *info)
 }
 #endif /* CONFIG_ZORRO */
 
+/* function table of the above functions */
+static struct fb_ops cirrusfb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_open        = cirrusfb_open,
+       .fb_release     = cirrusfb_release,
+       .fb_setcolreg   = cirrusfb_setcolreg,
+       .fb_check_var   = cirrusfb_check_var,
+       .fb_set_par     = cirrusfb_set_par,
+       .fb_pan_display = cirrusfb_pan_display,
+       .fb_blank       = cirrusfb_blank,
+       .fb_fillrect    = cirrusfb_fillrect,
+       .fb_copyarea    = cirrusfb_copyarea,
+       .fb_sync        = cirrusfb_sync,
+       .fb_imageblit   = cirrusfb_imageblit,
+};
+
 static int __devinit cirrusfb_set_fbinfo(struct fb_info *info)
 {
        struct cirrusfb_info *cinfo = info->par;
@@ -2077,10 +1997,16 @@ static int __devinit cirrusfb_set_fbinfo(struct fb_info *info)
                    | FBINFO_HWACCEL_XPAN
                    | FBINFO_HWACCEL_YPAN
                    | FBINFO_HWACCEL_FILLRECT
+                   | FBINFO_HWACCEL_IMAGEBLIT
                    | FBINFO_HWACCEL_COPYAREA;
-       if (noaccel)
+       if (noaccel || is_laguna(cinfo)) {
                info->flags |= FBINFO_HWACCEL_DISABLED;
+               info->fix.accel = FB_ACCEL_NONE;
+       } else
+               info->fix.accel = FB_ACCEL_CIRRUS_ALPINE;
+
        info->fbops = &cirrusfb_ops;
+
        if (cinfo->btype == BT_GD5480) {
                if (var->bits_per_pixel == 16)
                        info->screen_base += 1 * MB_;
@@ -2104,7 +2030,6 @@ static int __devinit cirrusfb_set_fbinfo(struct fb_info *info)
 
        /* FIXME: map region at 0xB8000 if available, fill in here */
        info->fix.mmio_len   = 0;
-       info->fix.accel = FB_ACCEL_NONE;
 
        fb_alloc_cmap(&info->cmap, 256, 0);
 
@@ -2115,70 +2040,56 @@ static int __devinit cirrusfb_register(struct fb_info *info)
 {
        struct cirrusfb_info *cinfo = info->par;
        int err;
-       enum cirrus_board btype;
-
-       DPRINTK("ENTER\n");
-
-       printk(KERN_INFO "cirrusfb: Driver for Cirrus Logic based "
-               "graphic boards, v" CIRRUSFB_VERSION "\n");
-
-       btype = cinfo->btype;
 
        /* sanity checks */
-       assert(btype != BT_NONE);
+       assert(cinfo->btype != BT_NONE);
 
        /* set all the vital stuff */
        cirrusfb_set_fbinfo(info);
 
-       DPRINTK("cirrusfb: (RAM start set to: 0x%p)\n", info->screen_base);
+       dev_dbg(info->device, "(RAM start set to: 0x%p)\n", info->screen_base);
 
        err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
        if (!err) {
-               DPRINTK("wrong initial video mode\n");
+               dev_dbg(info->device, "wrong initial video mode\n");
                err = -EINVAL;
                goto err_dealloc_cmap;
        }
 
        info->var.activate = FB_ACTIVATE_NOW;
 
-       err = cirrusfb_decode_var(&info->var, &cinfo->currentmode, info);
+       err = cirrusfb_check_var(&info->var, info);
        if (err < 0) {
                /* should never happen */
-               DPRINTK("choking on default var... umm, no good.\n");
+               dev_dbg(info->device,
+                       "choking on default var... umm, no good.\n");
                goto err_dealloc_cmap;
        }
 
        err = register_framebuffer(info);
        if (err < 0) {
-               printk(KERN_ERR "cirrusfb: could not register "
-                       "fb device; err = %d!\n", err);
+               dev_err(info->device,
+                       "could not register fb device; err = %d!\n", err);
                goto err_dealloc_cmap;
        }
 
-       DPRINTK("EXIT, returning 0\n");
        return 0;
 
 err_dealloc_cmap:
        fb_dealloc_cmap(&info->cmap);
-       cinfo->unmap(info);
-       framebuffer_release(info);
        return err;
 }
 
 static void __devexit cirrusfb_cleanup(struct fb_info *info)
 {
        struct cirrusfb_info *cinfo = info->par;
-       DPRINTK("ENTER\n");
 
        switch_monitor(cinfo, 0);
-
        unregister_framebuffer(info);
        fb_dealloc_cmap(&info->cmap);
-       printk("Framebuffer unregistered\n");
+       dev_dbg(info->device, "Framebuffer unregistered\n");
        cinfo->unmap(info);
        framebuffer_release(info);
-
-       DPRINTK("EXIT\n");
 }
 
 #ifdef CONFIG_PCI
@@ -2187,7 +2098,6 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev,
 {
        struct cirrusfb_info *cinfo;
        struct fb_info *info;
-       enum cirrus_board btype;
        unsigned long board_addr, board_size;
        int ret;
 
@@ -2201,15 +2111,17 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev,
        if (!info) {
                printk(KERN_ERR "cirrusfb: could not allocate memory\n");
                ret = -ENOMEM;
-               goto err_disable;
+               goto err_out;
        }
 
        cinfo = info->par;
-       cinfo->btype = btype = (enum cirrus_board) ent->driver_data;
+       cinfo->btype = (enum cirrus_board) ent->driver_data;
 
-       DPRINTK(" Found PCI device, base address 0 is 0x%x, btype set to %d\n",
-               pdev->resource[0].start, btype);
-       DPRINTK(" base address 1 is 0x%x\n", pdev->resource[1].start);
+       dev_dbg(info->device,
+               " Found PCI device, base address 0 is 0x%Lx, btype set to %d\n",
+               (unsigned long long)pdev->resource[0].start,  cinfo->btype);
+       dev_dbg(info->device, " base address 1 is 0x%Lx\n",
+               (unsigned long long)pdev->resource[1].start);
 
        if (isPReP) {
                pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, 0x00000000);
@@ -2219,30 +2131,30 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev,
        /* PReP dies if we ioremap the IO registers, but it works w/out... */
                cinfo->regbase = (char __iomem *) info->fix.mmio_start;
        } else {
-               DPRINTK("Attempt to get PCI info for Cirrus Graphics Card\n");
+               dev_dbg(info->device,
+                       "Attempt to get PCI info for Cirrus Graphics Card\n");
                get_pci_addrs(pdev, &board_addr, &info->fix.mmio_start);
                /* FIXME: this forces VGA.  alternatives? */
                cinfo->regbase = NULL;
+               cinfo->laguna_mmio = ioremap(info->fix.mmio_start, 0x1000);
        }
 
-       DPRINTK("Board address: 0x%lx, register address: 0x%lx\n",
+       dev_dbg(info->device, "Board address: 0x%lx, register address: 0x%lx\n",
                board_addr, info->fix.mmio_start);
 
-       board_size = (btype == BT_GD5480) ?
-               32 * MB_ : cirrusfb_get_memsize(cinfo->regbase);
+       board_size = (cinfo->btype == BT_GD5480) ?
+               32 * MB_ : cirrusfb_get_memsize(info, cinfo->regbase);
 
        ret = pci_request_regions(pdev, "cirrusfb");
        if (ret < 0) {
-               printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, "
-                      "abort\n",
-                      board_addr);
+               dev_err(info->device, "cannot reserve region 0x%lx, abort\n",
+                       board_addr);
                goto err_release_fb;
        }
 #if 0 /* if the system didn't claim this region, we would... */
        if (!request_mem_region(0xA0000, 65535, "cirrusfb")) {
-               printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n"
-,
-                      0xA0000L);
+               dev_err(info->device, "cannot reserve region 0x%lx, abort\n",
+                       0xA0000L);
                ret = -EBUSY;
                goto err_release_regions;
        }
@@ -2260,16 +2172,17 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev,
        info->screen_size = board_size;
        cinfo->unmap = cirrusfb_pci_unmap;
 
-       printk(KERN_INFO "RAM (%lu kB) at 0x%lx, Cirrus "
-                       "Logic chipset on PCI bus\n",
-                       info->screen_size >> 10, board_addr);
+       dev_info(info->device,
+                "Cirrus Logic chipset on PCI bus, RAM (%lu kB) at 0x%lx\n",
+                info->screen_size >> 10, board_addr);
        pci_set_drvdata(pdev, info);
 
        ret = cirrusfb_register(info);
-       if (ret)
-               iounmap(info->screen_base);
-       return ret;
+       if (!ret)
+               return 0;
 
+       pci_set_drvdata(pdev, NULL);
+       iounmap(info->screen_base);
 err_release_legacy:
        if (release_io_ports)
                release_region(0x3C0, 32);
@@ -2279,8 +2192,9 @@ err_release_regions:
 #endif
        pci_release_regions(pdev);
 err_release_fb:
+       if (cinfo->laguna_mmio != NULL)
+               iounmap(cinfo->laguna_mmio);
        framebuffer_release(info);
-err_disable:
 err_out:
        return ret;
 }
@@ -2288,11 +2202,8 @@ err_out:
 static void __devexit cirrusfb_pci_unregister(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
-       DPRINTK("ENTER\n");
 
        cirrusfb_cleanup(info);
-
-       DPRINTK("EXIT\n");
 }
 
 static struct pci_driver cirrusfb_pci_driver = {
@@ -2324,8 +2235,6 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
        if (cirrusfb_zorro_table2[btype].id2)
                z2 = zorro_find_device(cirrusfb_zorro_table2[btype].id2, NULL);
        size = cirrusfb_zorro_table2[btype].size;
-       printk(KERN_INFO "cirrusfb: %s board detected; ",
-              cirrusfb_board_info[btype].name);
 
        info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
        if (!info) {
@@ -2334,6 +2243,9 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
                goto err_out;
        }
 
+       dev_info(info->device, "%s board detected\n",
+                cirrusfb_board_info[btype].name);
+
        cinfo = info->par;
        cinfo->btype = btype;
 
@@ -2345,19 +2257,16 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
        info->screen_size = size;
 
        if (!zorro_request_device(z, "cirrusfb")) {
-               printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, "
-                      "abort\n",
-                      board_addr);
+               dev_err(info->device, "cannot reserve region 0x%lx, abort\n",
+                       board_addr);
                ret = -EBUSY;
                goto err_release_fb;
        }
 
-       printk(" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr);
-
        ret = -EIO;
 
        if (btype == BT_PICASSO4) {
-               printk(KERN_INFO " REG at $%lx\n", board_addr + 0x600000);
+               dev_info(info->device, " REG at $%lx\n", board_addr + 0x600000);
 
                /* To be precise, for the P4 this is not the */
                /* begin of the board, but the begin of RAM. */
@@ -2367,7 +2276,7 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
                if (!cinfo->regbase)
                        goto err_release_region;
 
-               DPRINTK("cirrusfb: Virtual address for board set to: $%p\n",
+               dev_dbg(info->device, "Virtual address for board set to: $%p\n",
                        cinfo->regbase);
                cinfo->regbase += 0x600000;
                info->fix.mmio_start = board_addr + 0x600000;
@@ -2377,8 +2286,8 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
                if (!info->screen_base)
                        goto err_unmap_regbase;
        } else {
-               printk(KERN_INFO " REG at $%lx\n",
-                       (unsigned long) z2->resource.start);
+               dev_info(info->device, " REG at $%lx\n",
+                        (unsigned long) z2->resource.start);
 
                info->fix.smem_start = board_addr;
                if (board_addr > 0x01000000)
@@ -2392,27 +2301,32 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
                cinfo->regbase = (caddr_t) ZTWO_VADDR(z2->resource.start);
                info->fix.mmio_start = z2->resource.start;
 
-               DPRINTK("cirrusfb: Virtual address for board set to: $%p\n",
+               dev_dbg(info->device, "Virtual address for board set to: $%p\n",
                        cinfo->regbase);
        }
        cinfo->unmap = cirrusfb_zorro_unmap;
 
-       printk(KERN_INFO "Cirrus Logic chipset on Zorro bus\n");
+       dev_info(info->device,
+                "Cirrus Logic chipset on Zorro bus, RAM (%lu MB) at $%lx\n",
+                board_size / MB_, board_addr);
+
        zorro_set_drvdata(z, info);
 
+       /* MCLK select etc. */
+       if (cirrusfb_board_info[btype].init_sr1f)
+               vga_wseq(cinfo->regbase, CL_SEQR1F,
+                        cirrusfb_board_info[btype].sr1f);
+
        ret = cirrusfb_register(info);
-       if (ret) {
-               if (btype == BT_PICASSO4) {
-                       iounmap(info->screen_base);
-                       iounmap(cinfo->regbase - 0x600000);
-               } else if (board_addr > 0x01000000)
-                       iounmap(info->screen_base);
-       }
-       return ret;
+       if (!ret)
+               return 0;
+
+       if (btype == BT_PICASSO4 || board_addr > 0x01000000)
+               iounmap(info->screen_base);
 
 err_unmap_regbase:
-       /* Parental advisory: explicit hack */
-       iounmap(cinfo->regbase - 0x600000);
+       if (btype == BT_PICASSO4)
+               iounmap(cinfo->regbase - 0x600000);
 err_release_region:
        release_region(board_addr, board_size);
 err_release_fb:
@@ -2424,11 +2338,8 @@ err_out:
 void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z)
 {
        struct fb_info *info = zorro_get_drvdata(z);
-       DPRINTK("ENTER\n");
 
        cirrusfb_cleanup(info);
-
-       DPRINTK("EXIT\n");
 }
 
 static struct zorro_driver cirrusfb_zorro_driver = {
@@ -2439,33 +2350,11 @@ static struct zorro_driver cirrusfb_zorro_driver = {
 };
 #endif /* CONFIG_ZORRO */
 
-static int __init cirrusfb_init(void)
-{
-       int error = 0;
-
-#ifndef MODULE
-       char *option = NULL;
-
-       if (fb_get_options("cirrusfb", &option))
-               return -ENODEV;
-       cirrusfb_setup(option);
-#endif
-
-#ifdef CONFIG_ZORRO
-       error |= zorro_register_driver(&cirrusfb_zorro_driver);
-#endif
-#ifdef CONFIG_PCI
-       error |= pci_register_driver(&cirrusfb_pci_driver);
-#endif
-       return error;
-}
-
 #ifndef MODULE
-static int __init cirrusfb_setup(char *options) {
+static int __init cirrusfb_setup(char *options)
+{
        char *this_opt;
 
-       DPRINTK("ENTER\n");
-
        if (!options || !*options)
                return 0;
 
@@ -2473,8 +2362,6 @@ static int __init cirrusfb_setup(char *options) {
                if (!*this_opt)
                        continue;
 
-               DPRINTK("cirrusfb_setup: option '%s'\n", this_opt);
-
                if (!strcmp(this_opt, "noaccel"))
                        noaccel = 1;
                else if (!strncmp(this_opt, "mode:", 5))
@@ -2494,6 +2381,27 @@ MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
 MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
 MODULE_LICENSE("GPL");
 
+static int __init cirrusfb_init(void)
+{
+       int error = 0;
+
+#ifndef MODULE
+       char *option = NULL;
+
+       if (fb_get_options("cirrusfb", &option))
+               return -ENODEV;
+       cirrusfb_setup(option);
+#endif
+
+#ifdef CONFIG_ZORRO
+       error |= zorro_register_driver(&cirrusfb_zorro_driver);
+#endif
+#ifdef CONFIG_PCI
+       error |= pci_register_driver(&cirrusfb_pci_driver);
+#endif
+       return error;
+}
+
 static void __exit cirrusfb_exit(void)
 {
 #ifdef CONFIG_PCI
@@ -2560,8 +2468,6 @@ static void AttrOn(const struct cirrusfb_info *cinfo)
 {
        assert(cinfo != NULL);
 
-       DPRINTK("ENTER\n");
-
        if (vga_rcrt(cinfo->regbase, CL_CRT24) & 0x80) {
                /* if we're just in "write value" mode, write back the */
                /* same value as before to not modify anything */
@@ -2574,8 +2480,6 @@ static void AttrOn(const struct cirrusfb_info *cinfo)
 
        /* dummy write on Reg0 to be on "write index" mode next time */
        vga_w(cinfo->regbase, VGA_ATT_IW, 0x00);
-
-       DPRINTK("EXIT\n");
 }
 
 /*** WHDR() - write into the Hidden DAC register ***/
@@ -2588,6 +2492,8 @@ static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val)
 {
        unsigned char dummy;
 
+       if (is_laguna(cinfo))
+               return;
        if (cinfo->btype == BT_PICASSO) {
                /* Klaus' hint for correct access to HDR on some boards */
                /* first write 0 to pixel mask (3c6) */
@@ -2655,7 +2561,8 @@ static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned ch
        vga_w(cinfo->regbase, VGA_PEL_IW, regnum);
 
        if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
-           cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
+           cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480 ||
+           cinfo->btype == BT_SD64 || is_laguna(cinfo)) {
                /* but DAC data register IS, at least for Picasso II */
                if (cinfo->btype == BT_PICASSO)
                        data += 0xfff;
@@ -2702,9 +2609,8 @@ static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned ch
 /* FIXME: use interrupts instead */
 static void cirrusfb_WaitBLT(u8 __iomem *regbase)
 {
-       /* now busy-wait until we're done */
        while (vga_rgfx(regbase, CL_GR31) & 0x08)
-               /* do nothing */ ;
+               cpu_relax();
 }
 
 /*******************************************************************
@@ -2713,60 +2619,12 @@ static void cirrusfb_WaitBLT(u8 __iomem *regbase)
        perform accelerated "scrolling"
 ********************************************************************/
 
-static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
-                           u_short curx, u_short cury,
-                           u_short destx, u_short desty,
-                           u_short width, u_short height,
-                           u_short line_length)
-{
-       u_short nwidth, nheight;
-       u_long nsrc, ndest;
-       u_char bltmode;
-
-       DPRINTK("ENTER\n");
-
-       nwidth = width - 1;
-       nheight = height - 1;
-
-       bltmode = 0x00;
-       /* if source adr < dest addr, do the Blt backwards */
-       if (cury <= desty) {
-               if (cury == desty) {
-                       /* if src and dest are on the same line, check x */
-                       if (curx < destx)
-                               bltmode |= 0x01;
-               } else
-                       bltmode |= 0x01;
-       }
-       if (!bltmode) {
-               /* standard case: forward blitting */
-               nsrc = (cury * line_length) + curx;
-               ndest = (desty * line_length) + destx;
-       } else {
-               /* this means start addresses are at the end,
-                * counting backwards
-                */
-               nsrc = cury * line_length + curx +
-                       nheight * line_length + nwidth;
-               ndest = desty * line_length + destx +
-                       nheight * line_length + nwidth;
-       }
-
-       /*
-          run-down of registers to be programmed:
-          destination pitch
-          source pitch
-          BLT width/height
-          source start
-          destination start
-          BLT mode
-          BLT ROP
-          VGA_GFX_SR_VALUE / VGA_GFX_SR_ENABLE: "fill color"
-          start/stop
-        */
-
-       cirrusfb_WaitBLT(regbase);
+static void cirrusfb_set_blitter(u8 __iomem *regbase,
+                           u_short nwidth, u_short nheight,
+                           u_long nsrc, u_long ndest,
+                           u_short bltmode, u_short line_length)
 
+{
        /* pitch: set to line_length */
        /* dest pitch low */
        vga_wgfx(regbase, CL_GR24, line_length & 0xff);
@@ -2813,91 +2671,91 @@ static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
 
        /* and finally: GO! */
        vga_wgfx(regbase, CL_GR31, 0x02);       /* BLT Start/status */
-
-       DPRINTK("EXIT\n");
 }
 
 /*******************************************************************
-       cirrusfb_RectFill()
+       cirrusfb_BitBLT()
 
-       perform accelerated rectangle fill
+       perform accelerated "scrolling"
 ********************************************************************/
 
-static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
-                    u_short x, u_short y, u_short width, u_short height,
-                    u_char color, u_short line_length)
+static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
+                           u_short curx, u_short cury,
+                           u_short destx, u_short desty,
+                           u_short width, u_short height,
+                           u_short line_length)
 {
-       u_short nwidth, nheight;
-       u_long ndest;
-       u_char op;
-
-       DPRINTK("ENTER\n");
-
-       nwidth = width - 1;
-       nheight = height - 1;
+       u_short nwidth = width - 1;
+       u_short nheight = height - 1;
+       u_long nsrc, ndest;
+       u_char bltmode;
 
-       ndest = (y * line_length) + x;
+       bltmode = 0x00;
+       /* if source adr < dest addr, do the Blt backwards */
+       if (cury <= desty) {
+               if (cury == desty) {
+                       /* if src and dest are on the same line, check x */
+                       if (curx < destx)
+                               bltmode |= 0x01;
+               } else
+                       bltmode |= 0x01;
+       }
+       /* standard case: forward blitting */
+       nsrc = (cury * line_length) + curx;
+       ndest = (desty * line_length) + destx;
+       if (bltmode) {
+               /* this means start addresses are at the end,
+                * counting backwards
+                */
+               nsrc += nheight * line_length + nwidth;
+               ndest += nheight * line_length + nwidth;
+       }
 
        cirrusfb_WaitBLT(regbase);
 
-       /* pitch: set to line_length */
-       vga_wgfx(regbase, CL_GR24, line_length & 0xff); /* dest pitch low */
-       vga_wgfx(regbase, CL_GR25, line_length >> 8);   /* dest pitch hi */
-       vga_wgfx(regbase, CL_GR26, line_length & 0xff); /* source pitch low */
-       vga_wgfx(regbase, CL_GR27, line_length >> 8);   /* source pitch hi */
+       cirrusfb_set_blitter(regbase, nwidth, nheight,
+                           nsrc, ndest, bltmode, line_length);
+}
 
-       /* BLT width: actual number of pixels - 1 */
-       vga_wgfx(regbase, CL_GR20, nwidth & 0xff);      /* BLT width low */
-       vga_wgfx(regbase, CL_GR21, nwidth >> 8);        /* BLT width hi */
+/*******************************************************************
+       cirrusfb_RectFill()
 
-       /* BLT height: actual number of lines -1 */
-       vga_wgfx(regbase, CL_GR22, nheight & 0xff);     /* BLT height low */
-       vga_wgfx(regbase, CL_GR23, nheight >> 8);       /* BLT width hi */
+       perform accelerated rectangle fill
+********************************************************************/
 
-       /* BLT destination */
-       /* BLT dest low */
-       vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff));
-       /* BLT dest mid */
-       vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8));
-       /* BLT dest hi */
-       vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16));
+static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
+                    u_short x, u_short y, u_short width, u_short height,
+                    u32 fg_color, u32 bg_color, u_short line_length,
+                    u_char blitmode)
+{
+       u_long ndest = (y * line_length) + x;
+       u_char op;
 
-       /* BLT source: set to 0 (is a dummy here anyway) */
-       vga_wgfx(regbase, CL_GR2C, 0x00);       /* BLT src low */
-       vga_wgfx(regbase, CL_GR2D, 0x00);       /* BLT src mid */
-       vga_wgfx(regbase, CL_GR2E, 0x00);       /* BLT src hi */
+       cirrusfb_WaitBLT(regbase);
 
        /* This is a ColorExpand Blt, using the */
        /* same color for foreground and background */
-       vga_wgfx(regbase, VGA_GFX_SR_VALUE, color);     /* foreground color */
-       vga_wgfx(regbase, VGA_GFX_SR_ENABLE, color);    /* background color */
-
-       op = 0xc0;
-       if (bits_per_pixel == 16) {
-               vga_wgfx(regbase, CL_GR10, color);      /* foreground color */
-               vga_wgfx(regbase, CL_GR11, color);      /* background color */
-               op = 0x50;
-               op = 0xd0;
-       } else if (bits_per_pixel == 32) {
-               vga_wgfx(regbase, CL_GR10, color);      /* foreground color */
-               vga_wgfx(regbase, CL_GR11, color);      /* background color */
-               vga_wgfx(regbase, CL_GR12, color);      /* foreground color */
-               vga_wgfx(regbase, CL_GR13, color);      /* background color */
-               vga_wgfx(regbase, CL_GR14, 0);  /* foreground color */
-               vga_wgfx(regbase, CL_GR15, 0);  /* background color */
-               op = 0x50;
-               op = 0xf0;
-       }
-       /* BLT mode: color expand, Enable 8x8 copy (faster?) */
-       vga_wgfx(regbase, CL_GR30, op); /* BLT mode */
-
-       /* BLT ROP: SrcCopy */
-       vga_wgfx(regbase, CL_GR32, 0x0d);       /* BLT ROP */
-
-       /* and finally: GO! */
-       vga_wgfx(regbase, CL_GR31, 0x02);       /* BLT Start/status */
-
-       DPRINTK("EXIT\n");
+       vga_wgfx(regbase, VGA_GFX_SR_VALUE, bg_color);
+       vga_wgfx(regbase, VGA_GFX_SR_ENABLE, fg_color);
+
+       op = 0x80;
+       if (bits_per_pixel >= 16) {
+               vga_wgfx(regbase, CL_GR10, bg_color >> 8);
+               vga_wgfx(regbase, CL_GR11, fg_color >> 8);
+               op = 0x90;
+       }
+       if (bits_per_pixel >= 24) {
+               vga_wgfx(regbase, CL_GR12, bg_color >> 16);
+               vga_wgfx(regbase, CL_GR13, fg_color >> 16);
+               op = 0xa0;
+       }
+       if (bits_per_pixel == 32) {
+               vga_wgfx(regbase, CL_GR14, bg_color >> 24);
+               vga_wgfx(regbase, CL_GR15, fg_color >> 24);
+               op = 0xb0;
+       }
+       cirrusfb_set_blitter(regbase, width - 1, height - 1,
+                           0, ndest, op | blitmode, line_length);
 }
 
 /**************************************************************************
@@ -2917,8 +2775,6 @@ static void bestclock(long freq, int *nom, int *den, int *div)
        *den = 0;
        *div = 0;
 
-       DPRINTK("ENTER\n");
-
        if (freq < 8000)
                freq = 8000;
 
@@ -2960,12 +2816,6 @@ static void bestclock(long freq, int *nom, int *den, int *div)
                        }
                }
        }
-
-       DPRINTK("Best possible values for given frequency:\n");
-       DPRINTK("       freq: %ld kHz  nom: %d  den: %d  div: %d\n",
-               freq, *nom, *den, *div);
-
-       DPRINTK("EXIT\n");
 }
 
 /* -------------------------------------------------------------------------
@@ -2977,32 +2827,6 @@ static void bestclock(long freq, int *nom, int *den, int *div)
 
 #ifdef CIRRUSFB_DEBUG
 
-/**
- * cirrusfb_dbg_print_byte
- * @name: name associated with byte value to be displayed
- * @val: byte value to be displayed
- *
- * DESCRIPTION:
- * Display an indented string, along with a hexidecimal byte value, and
- * its decoded bits.  Bits 7 through 0 are listed in left-to-right
- * order.
- */
-
-static
-void cirrusfb_dbg_print_byte(const char *name, unsigned char val)
-{
-       DPRINTK("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n",
-               name, val,
-               val & 0x80 ? '1' : '0',
-               val & 0x40 ? '1' : '0',
-               val & 0x20 ? '1' : '0',
-               val & 0x10 ? '1' : '0',
-               val & 0x08 ? '1' : '0',
-               val & 0x04 ? '1' : '0',
-               val & 0x02 ? '1' : '0',
-               val & 0x01 ? '1' : '0');
-}
-
 /**
  * cirrusfb_dbg_print_regs
  * @base: If using newmmio, the newmmio base address, otherwise %NULL
@@ -3014,9 +2838,9 @@ void cirrusfb_dbg_print_byte(const char *name, unsigned char val)
  * used at the given @base address to query the information.
  */
 
-static
-void cirrusfb_dbg_print_regs(caddr_t regbase,
-                            enum cirrusfb_dbg_reg_class reg_class, ...)
+static void cirrusfb_dbg_print_regs(struct fb_info *info,
+                                   caddr_t regbase,
+                                   enum cirrusfb_dbg_reg_class reg_class, ...)
 {
        va_list list;
        unsigned char val = 0;
@@ -3042,7 +2866,7 @@ void cirrusfb_dbg_print_regs(caddr_t regbase,
                        break;
                }
 
-               cirrusfb_dbg_print_byte(name, val);
+               dev_dbg(info->device, "%8s = 0x%02X\n", name, val);
 
                name = va_arg(list, char *);
        }
@@ -3050,18 +2874,6 @@ void cirrusfb_dbg_print_regs(caddr_t regbase,
        va_end(list);
 }
 
-/**
- * cirrusfb_dump
- * @cirrusfbinfo:
- *
- * DESCRIPTION:
- */
-
-static void cirrusfb_dump(void)
-{
-       cirrusfb_dbg_reg_dump(NULL);
-}
-
 /**
  * cirrusfb_dbg_reg_dump
  * @base: If using newmmio, the newmmio base address, otherwise %NULL
@@ -3072,12 +2884,11 @@ static void cirrusfb_dump(void)
  * used at the given @base address to query the information.
  */
 
-static
-void cirrusfb_dbg_reg_dump(caddr_t regbase)
+static void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase)
 {
-       DPRINTK("CIRRUSFB VGA CRTC register dump:\n");
+       dev_dbg(info->device, "VGA CRTC register dump:\n");
 
-       cirrusfb_dbg_print_regs(regbase, CRT,
+       cirrusfb_dbg_print_regs(info, regbase, CRT,
                           "CR00", 0x00,
                           "CR01", 0x01,
                           "CR02", 0x02,
@@ -3127,11 +2938,11 @@ void cirrusfb_dbg_reg_dump(caddr_t regbase)
                           "CR3F", 0x3F,
                           NULL);
 
-       DPRINTK("\n");
+       dev_dbg(info->device, "\n");
 
-       DPRINTK("CIRRUSFB VGA SEQ register dump:\n");
+       dev_dbg(info->device, "VGA SEQ register dump:\n");
 
-       cirrusfb_dbg_print_regs(regbase, SEQ,
+       cirrusfb_dbg_print_regs(info, regbase, SEQ,
                           "SR00", 0x00,
                           "SR01", 0x01,
                           "SR02", 0x02,
@@ -3160,7 +2971,7 @@ void cirrusfb_dbg_reg_dump(caddr_t regbase)
                           "SR1F", 0x1F,
                           NULL);
 
-       DPRINTK("\n");
+       dev_dbg(info->device, "\n");
 }
 
 #endif                         /* CIRRUSFB_DEBUG */
index 1657b9608b040d6b1a1dd0927a6e9cf6ba768f55..2cd500a304f234456c083baf920255a657c650f9 100644 (file)
@@ -2954,8 +2954,11 @@ static int fbcon_fb_unbind(int idx)
 
 static int fbcon_fb_unregistered(struct fb_info *info)
 {
-       int i, idx = info->node;
+       int i, idx;
 
+       if (!lock_fb_info(info))
+               return -ENODEV;
+       idx = info->node;
        for (i = first_fb_vc; i <= last_fb_vc; i++) {
                if (con2fb_map[i] == idx)
                        con2fb_map[i] = -1;
@@ -2979,13 +2982,14 @@ static int fbcon_fb_unregistered(struct fb_info *info)
                }
        }
 
-       if (!num_registered_fb)
-               unregister_con_driver(&fb_con);
-
-
        if (primary_device == idx)
                primary_device = -1;
 
+       unlock_fb_info(info);
+
+       if (!num_registered_fb)
+               unregister_con_driver(&fb_con);
+
        return 0;
 }
 
@@ -3021,9 +3025,13 @@ static inline void fbcon_select_primary(struct fb_info *info)
 
 static int fbcon_fb_registered(struct fb_info *info)
 {
-       int ret = 0, i, idx = info->node;
+       int ret = 0, i, idx;
 
+       if (!lock_fb_info(info))
+               return -ENODEV;
+       idx = info->node;
        fbcon_select_primary(info);
+       unlock_fb_info(info);
 
        if (info_idx == -1) {
                for (i = first_fb_vc; i <= last_fb_vc; i++) {
@@ -3124,7 +3132,7 @@ static void fbcon_get_requirement(struct fb_info *info,
        }
 }
 
-static int fbcon_event_notify(struct notifier_block *self, 
+static int fbcon_event_notify(struct notifier_block *self,
                              unsigned long action, void *data)
 {
        struct fb_event *event = data;
@@ -3132,7 +3140,7 @@ static int fbcon_event_notify(struct notifier_block *self,
        struct fb_videomode *mode;
        struct fb_con2fbmap *con2fb;
        struct fb_blit_caps *caps;
-       int ret = 0;
+       int idx, ret = 0;
 
        /*
         * ignore all events except driver registration and deregistration
@@ -3144,23 +3152,54 @@ static int fbcon_event_notify(struct notifier_block *self,
 
        switch(action) {
        case FB_EVENT_SUSPEND:
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                fbcon_suspended(info);
+               unlock_fb_info(info);
                break;
        case FB_EVENT_RESUME:
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                fbcon_resumed(info);
+               unlock_fb_info(info);
                break;
        case FB_EVENT_MODE_CHANGE:
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                fbcon_modechanged(info);
+               unlock_fb_info(info);
                break;
        case FB_EVENT_MODE_CHANGE_ALL:
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                fbcon_set_all_vcs(info);
+               unlock_fb_info(info);
                break;
        case FB_EVENT_MODE_DELETE:
                mode = event->data;
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                ret = fbcon_mode_deleted(info, mode);
+               unlock_fb_info(info);
                break;
        case FB_EVENT_FB_UNBIND:
-               ret = fbcon_fb_unbind(info->node);
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
+               idx = info->node;
+               unlock_fb_info(info);
+               ret = fbcon_fb_unbind(idx);
                break;
        case FB_EVENT_FB_REGISTERED:
                ret = fbcon_fb_registered(info);
@@ -3178,17 +3217,31 @@ static int fbcon_event_notify(struct notifier_block *self,
                con2fb->framebuffer = con2fb_map[con2fb->console - 1];
                break;
        case FB_EVENT_BLANK:
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                fbcon_fb_blanked(info, *(int *)event->data);
+               unlock_fb_info(info);
                break;
        case FB_EVENT_NEW_MODELIST:
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                fbcon_new_modelist(info);
+               unlock_fb_info(info);
                break;
        case FB_EVENT_GET_REQ:
                caps = event->data;
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                fbcon_get_requirement(info, caps);
+               unlock_fb_info(info);
                break;
        }
-
 done:
        return ret;
 }
diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c
deleted file mode 100644 (file)
index 9704b73..0000000
+++ /dev/null
@@ -1,1683 +0,0 @@
-/*
- * Frame buffer driver for Trident Cyberblade/i1 graphics core
- *
- * Copyright 2005 Knut Petersen <Knut_Petersen@t-online.de>
- *
- * CREDITS:
- *     tridentfb.c by Jani Monoses
- *     see files above for further credits
- *
- */
-
-#define CYBLAFB_DEBUG 0
-#define CYBLAFB_KD_GRAPHICS_QUIRK 1
-
-#define CYBLAFB_PIXMAPSIZE 8192
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <asm/types.h>
-#include <video/cyblafb.h>
-
-#define VERSION "0.62"
-
-struct cyblafb_par {
-       u32 pseudo_pal[16];
-       struct fb_ops ops;
-};
-
-static struct fb_fix_screeninfo cyblafb_fix __devinitdata = {
-       .id = "CyBla",
-       .type = FB_TYPE_PACKED_PIXELS,
-       .xpanstep = 1,
-       .ypanstep = 1,
-       .ywrapstep = 1,
-       .visual = FB_VISUAL_PSEUDOCOLOR,
-       .accel = FB_ACCEL_NONE,
-};
-
-static char *mode __devinitdata = NULL;
-static int bpp __devinitdata = 8;
-static int ref __devinitdata = 75;
-static int fp __devinitdata;
-static int crt __devinitdata;
-static int memsize __devinitdata;
-
-static int basestride;
-static int vesafb;
-static int nativex;
-static int center;
-static int stretch;
-static int pciwb = 1;
-static int pcirb = 1;
-static int pciwr = 1;
-static int pcirr = 1;
-static int disabled;
-static int verbosity;
-static int displaytype;
-
-static void __iomem *io_virt;  // iospace virtual memory address
-
-module_param(mode, charp, 0);
-module_param(bpp, int, 0);
-module_param(ref, int, 0);
-module_param(fp, int, 0);
-module_param(crt, int, 0);
-module_param(nativex, int, 0);
-module_param(center, int, 0);
-module_param(stretch, int, 0);
-module_param(pciwb, int, 0);
-module_param(pcirb, int, 0);
-module_param(pciwr, int, 0);
-module_param(pcirr, int, 0);
-module_param(memsize, int, 0);
-module_param(verbosity, int, 0);
-
-//=========================================
-//
-// Well, we have to fix the upper layers.
-// Until this has been done, we work around
-// the bugs.
-//
-//=========================================
-
-#if (CYBLAFB_KD_GRAPHICS_QUIRK && CYBLAFB_DEBUG)
-       if (disabled) { \
-               printk("********\n");\
-               dump_stack();\
-               return val;\
-       }
-
-#elif CYBLAFB_KD_GRAPHICS_QUIRK
-#define KD_GRAPHICS_RETURN(val)\
-       if (disabled) {\
-               return val;\
-       }
-#else
-#define KD_GRAPHICS_RETURN(val)
-#endif
-
-//=========================================
-//
-// Port access macros for memory mapped io
-//
-//=========================================
-
-#define out8(r, v) writeb(v, io_virt + r)
-#define out32(r, v) writel(v, io_virt + r)
-#define in8(r) readb(io_virt + r)
-#define in32(r) readl(io_virt + r)
-
-//======================================
-//
-// Hardware access inline functions
-//
-//======================================
-
-static inline u8 read3X4(u32 reg)
-{
-       out8(0x3D4, reg);
-       return in8(0x3D5);
-}
-
-static inline u8 read3C4(u32 reg)
-{
-       out8(0x3C4, reg);
-       return in8(0x3C5);
-}
-
-static inline u8 read3CE(u32 reg)
-{
-       out8(0x3CE, reg);
-       return in8(0x3CF);
-}
-
-static inline void write3X4(u32 reg, u8 val)
-{
-       out8(0x3D4, reg);
-       out8(0x3D5, val);
-}
-
-static inline void write3C4(u32 reg, u8 val)
-{
-       out8(0x3C4, reg);
-       out8(0x3C5, val);
-}
-
-static inline void write3CE(u32 reg, u8 val)
-{
-       out8(0x3CE, reg);
-       out8(0x3CF, val);
-}
-
-static inline void write3C0(u32 reg, u8 val)
-{
-       in8(0x3DA);             // read to reset index
-       out8(0x3C0, reg);
-       out8(0x3C0, val);
-}
-
-//=================================================
-//
-// Enable memory mapped io and unprotect registers
-//
-//=================================================
-
-static void enable_mmio(void)
-{
-       u8 tmp;
-
-       outb(0x0B, 0x3C4);
-       inb(0x3C5);             // Set NEW mode
-       outb(SR0E, 0x3C4);      // write enable a lot of extended ports
-       outb(0x80, 0x3C5);
-
-       outb(SR11, 0x3C4);      // write enable those extended ports that
-       outb(0x87, 0x3C5);      // are not affected by SR0E_New
-
-       outb(CR1E, 0x3d4);      // clear write protect bit for port 0x3c2
-       tmp = inb(0x3d5) & 0xBF;
-       outb(CR1E, 0x3d4);
-       outb(tmp, 0x3d5);
-
-       outb(CR39, 0x3D4);
-       outb(inb(0x3D5) | 0x01, 0x3D5); // Enable mmio
-}
-
-//=================================================
-//
-// Set pixel clock VCLK1
-// - multipliers set elswhere
-// - freq in units of 0.01 MHz
-//
-// Hardware bug: SR18 >= 250 is broken for the
-//              cyberblade/i1
-//
-//=================================================
-
-static void set_vclk(struct cyblafb_par *par, int freq)
-{
-       u32 m, n, k;
-       int f, fi, d, di;
-       u8 lo = 0, hi = 0;
-
-       d = 2000;
-       k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3;
-       for (m = 0; m < 64; m++)
-               for (n = 0; n < 250; n++) {
-                       fi = (int)(((5864727 * (n + 8)) /
-                                   ((m + 2) * (1 << k))) >> 12);
-                       if ((di = abs(fi - freq)) < d) {
-                               d = di;
-                               f = fi;
-                               lo = (u8) n;
-                               hi = (u8) ((k << 6) | m);
-                       }
-               }
-       write3C4(SR19, hi);
-       write3C4(SR18, lo);
-       if (verbosity > 0)
-               output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n",
-                      freq / 100, freq % 100, (hi & 0xc0) >> 6, hi & 0x3f, lo);
-}
-
-//================================================
-//
-// Cyberblade specific Graphics Engine (GE) setup
-//
-//================================================
-
-static void cyblafb_setup_GE(int pitch, int bpp)
-{
-       KD_GRAPHICS_RETURN();
-
-       switch (bpp) {
-       case 8:
-               basestride = ((pitch >> 3) << 20) | (0 << 29);
-               break;
-       case 15:
-               basestride = ((pitch >> 3) << 20) | (5 << 29);
-               break;
-       case 16:
-               basestride = ((pitch >> 3) << 20) | (1 << 29);
-               break;
-       case 24:
-       case 32:
-               basestride = ((pitch >> 3) << 20) | (2 << 29);
-               break;
-       }
-
-       write3X4(CR36, 0x90);   // reset GE
-       write3X4(CR36, 0x80);   // enable GE
-       out32(GE24, 1 << 7);    // reset all GE pointers by toggling
-       out32(GE24, 0);         //   d7 of GE24
-       write3X4(CR2D, 0x00);   // GE Timinigs, no delays
-       out32(GE6C, 0);         // Pattern and Style, p 129, ok
-}
-
-//=====================================================================
-//
-// Cyberblade specific syncing
-//
-//   A timeout might be caused by disabled mmio.
-//   Cause:
-//     - bit CR39 & 1 == 0 upon return, X trident driver bug
-//     - kdm bug (KD_GRAPHICS not set on first switch)
-//     - kernel design flaw (it believes in the correctness
-//      of kdm/X
-//   First we try to sync ignoring that problem, as most of the
-//   time that will succeed immediately and the enable_mmio()
-//   would only degrade performance.
-//
-//=====================================================================
-
-static int cyblafb_sync(struct fb_info *info)
-{
-       u32 status, i = 100000;
-
-       KD_GRAPHICS_RETURN(0);
-
-       while (((status = in32(GE20)) & 0xFe800000) && i != 0)
-               i--;
-
-       if (i == 0) {
-               enable_mmio();
-               i = 1000000;
-               while (((status = in32(GE20)) & 0xFA800000) && i != 0)
-                       i--;
-               if (i == 0) {
-                       output("GE Timeout, status: %x\n", status);
-                       if (status & 0x80000000)
-                               output("Bresenham Engine : Busy\n");
-                       if (status & 0x40000000)
-                               output("Setup Engine     : Busy\n");
-                       if (status & 0x20000000)
-                               output("SP / DPE         : Busy\n");
-                       if (status & 0x10000000)
-                               output("Memory Interface : Busy\n");
-                       if (status & 0x08000000)
-                               output("Com Lst Proc     : Busy\n");
-                       if (status & 0x04000000)
-                               output("Block Write      : Busy\n");
-                       if (status & 0x02000000)
-                               output("Command Buffer   : Full\n");
-                       if (status & 0x01000000)
-                               output("RESERVED         : Busy\n");
-                       if (status & 0x00800000)
-                               output("PCI Write Buffer : Busy\n");
-                       cyblafb_setup_GE(info->var.xres,
-                                        info->var.bits_per_pixel);
-               }
-       }
-
-       return 0;
-}
-
-//==============================
-//
-// Cyberblade specific fillrect
-//
-//==============================
-
-static void cyblafb_fillrect(struct fb_info *info, const struct fb_fillrect *fr)
-{
-       u32 bpp = info->var.bits_per_pixel, col, desty, height;
-
-       KD_GRAPHICS_RETURN();
-
-       switch (bpp) {
-       default:
-       case 8:
-               col = fr->color;
-               col |= col << 8;
-               col |= col << 16;
-               break;
-       case 16:
-               col = ((u32 *) (info->pseudo_palette))[fr->color];
-               col |= col << 16;
-               break;
-       case 32:
-               col = ((u32 *) (info->pseudo_palette))[fr->color];
-               break;
-       }
-
-       desty = fr->dy;
-       height = fr->height;
-       while (height) {
-               out32(GEB8, basestride | ((desty * info->var.xres_virtual *
-                                          bpp) >> 6));
-               out32(GE60, col);
-               out32(GE48, fr->rop ? 0x66 : ROP_S);
-               out32(GE44, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
-               out32(GE08, point(fr->dx, 0));
-               out32(GE0C, point(fr->dx + fr->width - 1,
-                                 height > 4096 ? 4095 : height - 1));
-               if (likely(height <= 4096))
-                       return;
-               desty += 4096;
-               height -= 4096;
-       }
-}
-
-//================================================
-//
-// Cyberblade specific copyarea
-//
-// This function silently assumes that it never
-// will be called with width or height exceeding
-// 4096.
-//
-//================================================
-
-static void cyblafb_copyarea(struct fb_info *info, const struct fb_copyarea *ca)
-{
-       u32 s1, s2, d1, d2, direction;
-
-       KD_GRAPHICS_RETURN();
-
-       s1 = point(ca->sx, 0);
-       s2 = point(ca->sx + ca->width - 1, ca->height - 1);
-       d1 = point(ca->dx, 0);
-       d2 = point(ca->dx + ca->width - 1, ca->height - 1);
-
-       if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx)))
-               direction = 0;
-       else
-               direction = 2;
-
-       out32(GEB8, basestride | ((ca->dy * info->var.xres_virtual *
-                                  info->var.bits_per_pixel) >> 6));
-       out32(GEC8, basestride | ((ca->sy * info->var.xres_virtual *
-                                  info->var.bits_per_pixel) >> 6));
-       out32(GE44, 0xa0000000 | 1 << 19 | 1 << 2 | direction);
-       out32(GE00, direction ? s2 : s1);
-       out32(GE04, direction ? s1 : s2);
-       out32(GE08, direction ? d2 : d1);
-       out32(GE0C, direction ? d1 : d2);
-}
-
-//=======================================================================
-//
-// Cyberblade specific imageblit
-//
-// Accelerated for the most usual case, blitting 1 - bit deep
-// character images. Everything else is passed to the generic imageblit
-// unless it is so insane that it is better to printk an alert.
-//
-// Hardware bug: _Never_ blit across pixel column 2048, that will lock
-// the system. We split those blit requests into three blitting
-// operations.
-//
-//=======================================================================
-
-static void cyblafb_imageblit(struct fb_info *info,
-                             const struct fb_image *image)
-{
-       u32 fgcol, bgcol;
-       u32 *pd = (u32 *) image->data;
-       u32 bpp = info->var.bits_per_pixel;
-
-       KD_GRAPHICS_RETURN();
-
-       // Used only for drawing the penguine (image->depth > 1)
-       if (image->depth != 1) {
-               cfb_imageblit(info, image);
-               return;
-       }
-       // That should never happen, but it would be fatal
-       if (image->width == 0 || image->height == 0) {
-               output("imageblit: width/height 0 detected\n");
-               return;
-       }
-
-       if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
-           info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
-               fgcol = ((u32 *) (info->pseudo_palette))[image->fg_color];
-               bgcol = ((u32 *) (info->pseudo_palette))[image->bg_color];
-       } else {
-               fgcol = image->fg_color;
-               bgcol = image->bg_color;
-       }
-
-       switch (bpp) {
-       case 8:
-               fgcol |= fgcol << 8;
-               bgcol |= bgcol << 8;
-       case 16:
-               fgcol |= fgcol << 16;
-               bgcol |= bgcol << 16;
-       default:
-               break;
-       }
-
-       out32(GEB8, basestride | ((image->dy * info->var.xres_virtual *
-                                  bpp) >> 6));
-       out32(GE60, fgcol);
-       out32(GE64, bgcol);
-
-       if (!(image->dx < 2048 && (image->dx + image->width - 1) >= 2048)) {
-               u32 dds = ((image->width + 31) >> 5) * image->height;
-               out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
-               out32(GE08, point(image->dx, 0));
-               out32(GE0C, point(image->dx + image->width - 1,
-                                 image->height - 1));
-               while (dds--)
-                       out32(GE9C, *pd++);
-       } else {
-               int i, j;
-               u32 ddstotal = (image->width + 31) >> 5;
-               u32 ddsleft = (2048 - image->dx + 31) >> 5;
-               u32 skipleft = ddstotal - ddsleft;
-
-               out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
-               out32(GE08, point(image->dx, 0));
-               out32(GE0C, point(2048 - 1, image->height - 1));
-               for (i = 0; i < image->height; i++) {
-                       for (j = 0; j < ddsleft; j++)
-                               out32(GE9C, *pd++);
-                       pd += skipleft;
-               }
-
-               if (image->dx % 32) {
-                       out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
-                       out32(GE08, point(2048, 0));
-                       if (image->width > ddsleft << 5)
-                               out32(GE0C, point(image->dx + (ddsleft << 5) -
-                                                 1, image->height - 1));
-                       else
-                               out32(GE0C, point(image->dx + image->width - 1,
-                                                 image->height - 1));
-                       pd = ((u32 *) image->data) + ddstotal - skipleft - 1;
-                       for (i = 0; i < image->height; i++) {
-                               out32(GE9C, swab32(swab32(*pd) << ((32 -
-                                           (image->dx & 31)) & 31)));
-                               pd += ddstotal;
-                       }
-               }
-
-               if (skipleft) {
-                       out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
-                       out32(GE08, point(image->dx + (ddsleft << 5), 0));
-                       out32(GE0C, point(image->dx + image->width - 1,
-                                         image->height - 1));
-                       pd = (u32 *) image->data;
-                       for (i = 0; i < image->height; i++) {
-                               pd += ddsleft;
-                               for (j = 0; j < skipleft; j++)
-                                       out32(GE9C, *pd++);
-                       }
-               }
-       }
-}
-
-//==========================================================
-//
-// Check if video mode is acceptable. We change var->??? if
-// video mode is slightly off or return error otherwise.
-// info->??? must not be changed!
-//
-//==========================================================
-
-static int cyblafb_check_var(struct fb_var_screeninfo *var,
-                            struct fb_info *info)
-{
-       int bpp = var->bits_per_pixel;
-
-       //
-       // we try to support 8, 16, 24 and 32 bpp modes,
-       // default to 8
-       //
-       // there is a 24 bpp mode, but for now we change requests to 32 bpp
-       // (This is what tridentfb does ... will be changed in the future)
-       //
-       //
-       if (bpp % 8 != 0 || bpp < 8 || bpp > 32)
-               bpp = 8;
-       if (bpp == 24)
-               bpp = var->bits_per_pixel = 32;
-
-       //
-       // interlaced modes are broken, fail if one is requested
-       //
-       if (var->vmode & FB_VMODE_INTERLACED)
-               return -EINVAL;
-
-       //
-       // fail if requested resolution is higher than physical
-       // flatpanel resolution
-       //
-       if ((displaytype == DISPLAY_FP) && nativex && var->xres > nativex)
-               return -EINVAL;
-
-       //
-       // we do not allow vclk to exceed 230 MHz. If the requested
-       // vclk is too high, we default to 200 MHz
-       //
-       if ((bpp == 32 ? 200000000 : 100000000) / var->pixclock > 23000)
-               var->pixclock = (bpp == 32 ? 200000000 : 100000000) / 20000;
-
-       //
-       // enforce (h|v)sync_len limits
-       //
-       var->hsync_len &= ~7;
-       if(var->hsync_len > 248)
-               var->hsync_len = 248;
-
-       var->vsync_len &= 15;
-
-       //
-       // Enforce horizontal and vertical hardware limits.
-       // 1600x1200 is mentioned as a maximum, but higher resolutions could
-       // work with slow refresh, small margins and short sync.
-       //
-       var->xres &= ~7;
-
-       if (((var->xres + var->left_margin + var->right_margin +
-                       var->hsync_len) > (bpp == 32 ? 2040 : 4088)) ||
-                       ((var->yres + var->upper_margin + var->lower_margin +
-                       var->vsync_len) > 2047))
-               return -EINVAL;
-
-       if ((var->xres > 1600) || (var->yres > 1200))
-               output("Mode %dx%d exceeds documented limits.\n",
-                                          var->xres, var->yres);
-       //
-       // try to be smart about (x|y)res_virtual problems.
-       //
-       if (var->xres > var->xres_virtual)
-               var->xres_virtual = var->xres;
-       if (var->yres > var->yres_virtual)
-               var->yres_virtual = var->yres;
-
-       if (bpp == 8 || bpp == 16) {
-               if (var->xres_virtual > 4088)
-                       var->xres_virtual = 4088;
-       } else {
-               if (var->xres_virtual > 2040)
-                       var->xres_virtual = 2040;
-       }
-       var->xres_virtual &= ~7;
-       while (var->xres_virtual * var->yres_virtual * bpp / 8 >
-              info->fix.smem_len) {
-               if (var->yres_virtual > var->yres)
-                       var->yres_virtual--;
-               else if (var->xres_virtual > var->xres)
-                       var->xres_virtual -= 8;
-               else
-                       return -EINVAL;
-       }
-
-       switch (bpp) {
-       case 8:
-               var->red.offset = 0;
-               var->green.offset = 0;
-               var->blue.offset = 0;
-               var->red.length = 6;
-               var->green.length = 6;
-               var->blue.length = 6;
-               break;
-       case 16:
-               var->red.offset = 11;
-               var->green.offset = 5;
-               var->blue.offset = 0;
-               var->red.length = 5;
-               var->green.length = 6;
-               var->blue.length = 5;
-               break;
-       case 32:
-               var->red.offset = 16;
-               var->green.offset = 8;
-               var->blue.offset = 0;
-               var->red.length = 8;
-               var->green.length = 8;
-               var->blue.length = 8;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-//=====================================================================
-//
-// Pan the display
-//
-// The datasheets defines crt start address to be 20 bits wide and
-// to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is
-// CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use
-// it, so it is also safe to be used here. BTW: datasheet CR0E on page
-// 90 really is CR1E, the real CRE is documented on page 72.
-//
-// BUT:
-//
-// As of internal version 0.60 we do not use vga panning any longer.
-// Vga panning did not allow us the use of all available video memory
-// and thus prevented ywrap scrolling. We do use the "right view"
-// register now.
-//
-//
-//=====================================================================
-
-static int cyblafb_pan_display(struct fb_var_screeninfo *var,
-                              struct fb_info *info)
-{
-       KD_GRAPHICS_RETURN(0);
-
-       info->var.xoffset = var->xoffset;
-       info->var.yoffset = var->yoffset;
-       out32(GE10, 0x80000000 | ((var->xoffset + (var->yoffset *
-                   var->xres_virtual)) * var->bits_per_pixel / 32));
-       return 0;
-}
-
-//============================================
-//
-// This will really help in case of a bug ...
-// dump most gaphics core registers.
-//
-//============================================
-
-static void regdump(struct cyblafb_par *par)
-{
-       int i;
-
-       if (verbosity < 2)
-               return;
-
-       printk("\n");
-       for (i = 0; i <= 0xff; i++) {
-               outb(i, 0x3d4);
-               printk("CR%02x=%02x ", i, inb(0x3d5));
-               if (i % 16 == 15)
-                       printk("\n");
-       }
-
-       outb(0x30, 0x3ce);
-       outb(inb(0x3cf) | 0x40, 0x3cf);
-       for (i = 0; i <= 0x1f; i++) {
-               if (i == 0 || (i > 2 && i < 8) || i == 0x10 || i == 0x11
-                   || i == 0x16) {
-                       outb(i, 0x3d4);
-                       printk("CR%02x=%02x ", i, inb(0x3d5));
-               } else
-                       printk("------- ");
-               if (i % 16 == 15)
-                       printk("\n");
-       }
-       outb(0x30, 0x3ce);
-       outb(inb(0x3cf) & 0xbf, 0x3cf);
-
-       printk("\n");
-       for (i = 0; i <= 0x7f; i++) {
-               outb(i, 0x3ce);
-               printk("GR%02x=%02x ", i, inb(0x3cf));
-               if (i % 16 == 15)
-                       printk("\n");
-       }
-
-       printk("\n");
-       for (i = 0; i <= 0xff; i++) {
-               outb(i, 0x3c4);
-               printk("SR%02x=%02x ", i, inb(0x3c5));
-               if (i % 16 == 15)
-                       printk("\n");
-       }
-
-       printk("\n");
-       for (i = 0; i <= 0x1F; i++) {
-               inb(0x3da);     // next access is index!
-               outb(i, 0x3c0);
-               printk("AR%02x=%02x ", i, inb(0x3c1));
-               if (i % 16 == 15)
-                       printk("\n");
-       }
-       printk("\n");
-
-       inb(0x3DA);             // reset internal flag to 3c0 index
-       outb(0x20, 0x3C0);      // enable attr
-
-       return;
-}
-
-//=======================================================================
-//
-// Save State
-//
-// This function is called while a switch to KD_TEXT is in progress,
-// before any of the other functions are called.
-//
-//=======================================================================
-
-static void cyblafb_save_state(struct fb_info *info)
-{
-       struct cyblafb_par *par = info->par;
-       if (verbosity > 0)
-               output("Switching to KD_TEXT\n");
-       disabled = 0;
-       regdump(par);
-       enable_mmio();
-       return;
-}
-
-//=======================================================================
-//
-// Restore State
-//
-// This function is called while a switch to KD_GRAPHICS is in progress,
-// We have to turn on vga style panning registers again because the
-// trident driver of X does not know about GE10.
-//
-//=======================================================================
-
-static void cyblafb_restore_state(struct fb_info *info)
-{
-       if (verbosity > 0)
-               output("Switching to KD_GRAPHICS\n");
-       out32(GE10, 0);
-       disabled = 1;
-       return;
-}
-
-//======================================
-//
-// Set hardware to requested video mode
-//
-//======================================
-
-static int cyblafb_set_par(struct fb_info *info)
-{
-       struct cyblafb_par *par = info->par;
-       u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart,
-           hblankend, preendfetch, vtotal, vdispend, vsyncstart,
-           vsyncend, vblankstart, vblankend;
-       struct fb_var_screeninfo *var = &info->var;
-       int bpp = var->bits_per_pixel;
-       int i;
-
-       KD_GRAPHICS_RETURN(0);
-
-       if (verbosity > 0)
-               output("Switching to new mode: "
-                      "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
-                      var->xres, var->yres, var->xres_virtual,
-                      var->yres_virtual, var->bits_per_pixel, var->pixclock,
-                      var->left_margin, var->right_margin, var->upper_margin,
-                      var->lower_margin, var->hsync_len, var->vsync_len);
-
-       htotal = (var->xres + var->left_margin + var->right_margin +
-                 var->hsync_len) / 8 - 5;
-       hdispend = var->xres / 8 - 1;
-       hsyncstart = (var->xres + var->right_margin) / 8;
-       hsyncend = var->hsync_len / 8;
-       hblankstart = hdispend + 1;
-       hblankend = htotal + 3; // should be htotal + 5, bios does it this way
-       preendfetch = ((var->xres >> 3) + 1) * ((bpp + 1) >> 3);
-
-       vtotal = var->yres + var->upper_margin + var->lower_margin +
-                                                       var->vsync_len - 2;
-       vdispend = var->yres - 1;
-       vsyncstart = var->yres + var->lower_margin;
-       vblankstart = var->yres;
-       vblankend = vtotal; // should be vtotal + 2, but bios does it this way
-       vsyncend = var->vsync_len;
-
-       enable_mmio();          // necessary! ... check X ...
-
-       write3X4(CR11, read3X4(CR11) & 0x7F);   // unlock cr00 .. cr07
-
-       write3CE(GR30, 8);
-
-       if ((displaytype == DISPLAY_FP) && var->xres < nativex) {
-
-               // stretch or center ?
-
-               out8(0x3C2, 0xEB);
-
-               write3CE(GR30, read3CE(GR30) | 0x81);   // shadow mode on
-
-               if (center) {
-                       write3CE(GR52, (read3CE(GR52) & 0x7C) | 0x80);
-                       write3CE(GR53, (read3CE(GR53) & 0x7C) | 0x80);
-               } else if (stretch) {
-                       write3CE(GR5D, 0);
-                       write3CE(GR52, (read3CE(GR52) & 0x7C) | 1);
-                       write3CE(GR53, (read3CE(GR53) & 0x7C) | 1);
-               }
-
-       } else {
-               out8(0x3C2, 0x2B);
-               write3CE(GR30, 8);
-       }
-
-       //
-       // Setup CRxx regs
-       //
-
-       write3X4(CR00, htotal & 0xFF);
-       write3X4(CR01, hdispend & 0xFF);
-       write3X4(CR02, hblankstart & 0xFF);
-       write3X4(CR03, hblankend & 0x1F);
-       write3X4(CR04, hsyncstart & 0xFF);
-       write3X4(CR05, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
-       write3X4(CR06, vtotal & 0xFF);
-       write3X4(CR07, (vtotal & 0x100) >> 8 |
-                      (vdispend & 0x100) >> 7 |
-                      (vsyncstart & 0x100) >> 6 |
-                      (vblankstart & 0x100) >> 5 |
-                      0x10 |
-                      (vtotal & 0x200) >> 4 |
-                      (vdispend & 0x200) >> 3 | (vsyncstart & 0x200) >> 2);
-       write3X4(CR08, 0);
-       write3X4(CR09, (vblankstart & 0x200) >> 4 | 0x40 |      // FIX !!!
-                      ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
-       write3X4(CR0A, 0);      // Init to some reasonable default
-       write3X4(CR0B, 0);      // Init to some reasonable default
-       write3X4(CR0C, 0);      // Offset 0
-       write3X4(CR0D, 0);      // Offset 0
-       write3X4(CR0E, 0);      // Init to some reasonable default
-       write3X4(CR0F, 0);      // Init to some reasonable default
-       write3X4(CR10, vsyncstart & 0xFF);
-       write3X4(CR11, (vsyncend & 0x0F));
-       write3X4(CR12, vdispend & 0xFF);
-       write3X4(CR13, ((info->var.xres_virtual * bpp) / (4 * 16)) & 0xFF);
-       write3X4(CR14, 0x40);   // double word mode
-       write3X4(CR15, vblankstart & 0xFF);
-       write3X4(CR16, vblankend & 0xFF);
-       write3X4(CR17, 0xE3);
-       write3X4(CR18, 0xFF);
-       //       CR19: needed for interlaced modes ... ignore it for now
-       write3X4(CR1A, 0x07);   // Arbitration Control Counter 1
-       write3X4(CR1B, 0x07);   // Arbitration Control Counter 2
-       write3X4(CR1C, 0x07);   // Arbitration Control Counter 3
-       write3X4(CR1D, 0x00);   // Don't know, doesn't hurt ; -)
-       write3X4(CR1E, (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
-       //       CR1F: do not set, contains BIOS info about memsize
-       write3X4(CR20, 0x20);   // enabe wr buf, disable 16bit planar mode
-       write3X4(CR21, 0x20);   // enable linear memory access
-       //       CR22: RO cpu latch readback
-       //       CR23: ???
-       //       CR24: RO AR flag state
-       //       CR25: RAMDAC rw timing, pclk buffer tristate control ????
-       //       CR26: ???
-       write3X4(CR27, (vdispend & 0x400) >> 6 |
-                      (vsyncstart & 0x400) >> 5 |
-                      (vblankstart & 0x400) >> 4 |
-                      (vtotal & 0x400) >> 3 |
-                      0x8);
-       //       CR28: ???
-       write3X4(CR29, (read3X4(CR29) & 0xCF) | ((((info->var.xres_virtual *
-                       bpp) / (4 * 16)) & 0x300) >> 4));
-       write3X4(CR2A, read3X4(CR2A) | 0x40);
-       write3X4(CR2B, (htotal & 0x100) >> 8 |
-                      (hdispend & 0x100) >> 7 |
-                      // (0x00 & 0x100) >> 6 |   hinterlace para bit 8 ???
-                      (hsyncstart & 0x100) >> 5 |
-                      (hblankstart & 0x100) >> 4);
-       //       CR2C: ???
-       //       CR2D: initialized in cyblafb_setup_GE()
-       write3X4(CR2F, 0x92);   // conservative, better signal quality
-       //       CR30: reserved
-       //       CR31: reserved
-       //       CR32: reserved
-       //       CR33: reserved
-       //       CR34: disabled in CR36
-       //       CR35: disabled in CR36
-       //       CR36: initialized in cyblafb_setup_GE
-       //       CR37: i2c, ignore for now
-       write3X4(CR38, (bpp == 8) ? 0x00 :      //
-                      (bpp == 16) ? 0x05 :     // highcolor
-                      (bpp == 24) ? 0x29 :     // packed 24bit truecolor
-                      (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus
-       write3X4(CR39, 0x01 |   // MMIO enable
-                      (pcirb ? 0x02 : 0) |     // pci read burst enable
-                      (pciwb ? 0x04 : 0));     // pci write burst enable
-       write3X4(CR55, 0x1F | // pci clocks * 2 for STOP# during 1st data phase
-                      (pcirr ? 0x40 : 0) |     // pci read retry enable
-                      (pciwr ? 0x80 : 0));     // pci write retry enable
-       write3X4(CR56, preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01) | 2
-                                           : 0);
-       write3X4(CR57, preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
-       write3X4(CR58, 0x82);   // Bios does this .... don't know more
-       //
-       // Setup SRxx regs
-       //
-       write3C4(SR00, 3);
-       write3C4(SR01, 1);      //set char clock 8 dots wide
-       write3C4(SR02, 0x0F);   //enable 4 maps needed in chain4 mode
-       write3C4(SR03, 0);      //no character map select
-       write3C4(SR04, 0x0E);   //memory mode: ext mem, even, chain4
-
-       out8(0x3C4, 0x0b);
-       in8(0x3C5);             // Set NEW mode
-       write3C4(SR0D, 0x00);   // test ... check
-
-       set_vclk(par, (bpp == 32 ? 200000000 : 100000000)
-                                       / info->var.pixclock);  //SR18, SR19
-
-       //
-       // Setup GRxx regs
-       //
-       write3CE(GR00, 0x00);   // test ... check
-       write3CE(GR01, 0x00);   // test ... check
-       write3CE(GR02, 0x00);   // test ... check
-       write3CE(GR03, 0x00);   // test ... check
-       write3CE(GR04, 0x00);   // test ... check
-       write3CE(GR05, 0x40);   // no CGA compat, allow 256 col
-       write3CE(GR06, 0x05);   // graphics mode
-       write3CE(GR07, 0x0F);   // planes?
-       write3CE(GR08, 0xFF);   // test ... check
-       write3CE(GR0F, (bpp == 32) ? 0x1A : 0x12); // vclk / 2 if 32bpp, chain4
-       write3CE(GR20, 0xC0);   // test ... check
-       write3CE(GR2F, 0xA0);   // PCLK = VCLK, no skew,
-
-       //
-       // Setup ARxx regs
-       //
-       for (i = 0; i < 0x10; i++)      // set AR00 .. AR0f
-               write3C0(i, i);
-       write3C0(AR10, 0x41);   // graphics mode and support 256 color modes
-       write3C0(AR12, 0x0F);   // planes
-       write3C0(AR13, 0);      // horizontal pel panning
-       in8(0x3DA);             // reset internal flag to 3c0 index
-       out8(0x3C0, 0x20);      // enable attr
-
-       //
-       // Setup hidden RAMDAC command register
-       //
-       in8(0x3C8);             // these reads are
-       in8(0x3C6);             // necessary to
-       in8(0x3C6);             // unmask the RAMDAC
-       in8(0x3C6);             // command reg, otherwise
-       in8(0x3C6);             // we would write the pixelmask reg!
-       out8(0x3C6, (bpp == 8) ? 0x00 : // 256 colors
-            (bpp == 15) ? 0x10 :       //
-            (bpp == 16) ? 0x30 :       // hicolor
-            (bpp == 24) ? 0xD0 :       // truecolor
-            (bpp == 32) ? 0xD0 : 0);   // truecolor
-       in8(0x3C8);
-
-       //
-       // GR31 is not mentioned in the datasheet
-       //
-       if (displaytype == DISPLAY_FP)
-               write3CE(GR31, (read3CE(GR31) & 0x8F) |
-                        ((info->var.yres > 1024) ? 0x50 :
-                         (info->var.yres > 768) ? 0x30 :
-                         (info->var.yres > 600) ? 0x20 :
-                         (info->var.yres > 480) ? 0x10 : 0));
-
-       info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR
-                                     : FB_VISUAL_TRUECOLOR;
-       info->fix.line_length = info->var.xres_virtual * (bpp >> 3);
-       info->cmap.len = (bpp == 8) ? 256 : 16;
-
-       //
-       // init acceleration engine
-       //
-       cyblafb_setup_GE(info->var.xres_virtual, info->var.bits_per_pixel);
-
-       //
-       // Set/clear flags to allow proper scroll mode selection.
-       //
-       if (var->xres == var->xres_virtual)
-               info->flags &= ~FBINFO_HWACCEL_XPAN;
-       else
-               info->flags |= FBINFO_HWACCEL_XPAN;
-
-       if (var->yres == var->yres_virtual)
-               info->flags &= ~FBINFO_HWACCEL_YPAN;
-       else
-               info->flags |= FBINFO_HWACCEL_YPAN;
-
-       if (info->fix.smem_len !=
-           var->xres_virtual * var->yres_virtual * bpp / 8)
-               info->flags &= ~FBINFO_HWACCEL_YWRAP;
-       else
-               info->flags |= FBINFO_HWACCEL_YWRAP;
-
-       regdump(par);
-
-       return 0;
-}
-
-//========================
-//
-// Set one color register
-//
-//========================
-
-static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green,
-                            unsigned blue, unsigned transp,
-                            struct fb_info *info)
-{
-       int bpp = info->var.bits_per_pixel;
-
-       KD_GRAPHICS_RETURN(0);
-
-       if (regno >= info->cmap.len)
-               return 1;
-
-       if (bpp == 8) {
-               out8(0x3C6, 0xFF);
-               out8(0x3C8, regno);
-               out8(0x3C9, red >> 10);
-               out8(0x3C9, green >> 10);
-               out8(0x3C9, blue >> 10);
-
-       } else if (regno < 16) {
-               if (bpp == 16)  // RGB 565
-                       ((u32 *) info->pseudo_palette)[regno] =
-                               (red & 0xF800) |
-                               ((green & 0xFC00) >> 5) |
-                               ((blue & 0xF800) >> 11);
-               else if (bpp == 32)     // ARGB 8888
-                       ((u32 *) info->pseudo_palette)[regno] =
-                               ((transp & 0xFF00) << 16) |
-                               ((red & 0xFF00) << 8) |
-                               ((green & 0xFF00)) | ((blue & 0xFF00) >> 8);
-       }
-
-       return 0;
-}
-
-//==========================================================
-//
-// Try blanking the screen. For flat panels it does nothing
-//
-//==========================================================
-
-static int cyblafb_blank(int blank_mode, struct fb_info *info)
-{
-       unsigned char PMCont, DPMSCont;
-
-       KD_GRAPHICS_RETURN(0);
-
-       if (displaytype == DISPLAY_FP)
-               return 0;
-
-       out8(0x83C8, 0x04);     // DPMS Control
-       PMCont = in8(0x83C6) & 0xFC;
-
-       DPMSCont = read3CE(GR23) & 0xFC;
-
-       switch (blank_mode) {
-       case FB_BLANK_UNBLANK:  // Screen: On, HSync: On, VSync: On
-       case FB_BLANK_NORMAL:   // Screen: Off, HSync: On, VSync: On
-               PMCont |= 0x03;
-               DPMSCont |= 0x00;
-               break;
-       case FB_BLANK_HSYNC_SUSPEND:    // Screen: Off, HSync: Off, VSync: On
-               PMCont |= 0x02;
-               DPMSCont |= 0x01;
-               break;
-       case FB_BLANK_VSYNC_SUSPEND:    // Screen: Off, HSync: On, VSync: Off
-               PMCont |= 0x02;
-               DPMSCont |= 0x02;
-               break;
-       case FB_BLANK_POWERDOWN:        // Screen: Off, HSync: Off, VSync: Off
-               PMCont |= 0x00;
-               DPMSCont |= 0x03;
-               break;
-       }
-
-       write3CE(GR23, DPMSCont);
-       out8(0x83C8, 4);
-       out8(0x83C6, PMCont);
-       //
-       // let fbcon do a softblank for us
-       //
-       return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
-}
-
-static struct fb_ops cyblafb_ops __devinitdata = {
-       .owner = THIS_MODULE,
-       .fb_setcolreg = cyblafb_setcolreg,
-       .fb_pan_display = cyblafb_pan_display,
-       .fb_blank = cyblafb_blank,
-       .fb_check_var = cyblafb_check_var,
-       .fb_set_par = cyblafb_set_par,
-       .fb_fillrect = cyblafb_fillrect,
-       .fb_copyarea = cyblafb_copyarea,
-       .fb_imageblit = cyblafb_imageblit,
-       .fb_sync = cyblafb_sync,
-       .fb_restore_state = cyblafb_restore_state,
-       .fb_save_state = cyblafb_save_state,
-};
-
-//==========================================================================
-//
-// getstartupmode() decides about the inital video mode
-//
-// There is no reason to use modedb, a lot of video modes there would
-// need altered timings to display correctly. So I decided that it is much
-// better to provide a limited optimized set of modes plus the option of
-// using the mode in effect at startup time (might be selected using the
-// vga=??? parameter). After that the user might use fbset to select any
-// mode he likes, check_var will not try to alter geometry parameters as
-// it would be necessary otherwise.
-//
-//==========================================================================
-
-static int __devinit getstartupmode(struct fb_info *info)
-{
-       u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend,
-           vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend,
-           cr00, cr01, cr02, cr03, cr04, cr05, cr2b,
-           cr06, cr07, cr09, cr10, cr11, cr12, cr15, cr16, cr27,
-           cr38, sr0d, sr18, sr19, gr0f, fi, pxclkdiv, vclkdiv, tmp, i;
-
-       struct modus {
-               int xres; int vxres; int yres; int vyres;
-               int bpp; int pxclk;
-               int left_margin; int right_margin;
-               int upper_margin; int lower_margin;
-               int hsync_len; int vsync_len;
-       } modedb[5] = {
-               {
-               0, 2048, 0, 4096, 0, 0, 0, 0, 0, 0, 0, 0}, {
-               640, 2048, 480, 4096, 0, 0, -40, 24, 17, 0, 216, 3}, {
-               800, 2048, 600, 4096, 0, 0, 96, 24, 14, 0, 136, 11}, {
-               1024, 2048, 768, 4096, 0, 0, 144, 24, 29, 0, 120, 3}, {
-               1280, 2048, 1024, 4096, 0, 0, 232, 16, 39, 0, 160, 3}
-       };
-
-       outb(0x00, 0x3d4); cr00 = inb(0x3d5);
-       outb(0x01, 0x3d4); cr01 = inb(0x3d5);
-       outb(0x02, 0x3d4); cr02 = inb(0x3d5);
-       outb(0x03, 0x3d4); cr03 = inb(0x3d5);
-       outb(0x04, 0x3d4); cr04 = inb(0x3d5);
-       outb(0x05, 0x3d4); cr05 = inb(0x3d5);
-       outb(0x06, 0x3d4); cr06 = inb(0x3d5);
-       outb(0x07, 0x3d4); cr07 = inb(0x3d5);
-       outb(0x09, 0x3d4); cr09 = inb(0x3d5);
-       outb(0x10, 0x3d4); cr10 = inb(0x3d5);
-       outb(0x11, 0x3d4); cr11 = inb(0x3d5);
-       outb(0x12, 0x3d4); cr12 = inb(0x3d5);
-       outb(0x15, 0x3d4); cr15 = inb(0x3d5);
-       outb(0x16, 0x3d4); cr16 = inb(0x3d5);
-       outb(0x27, 0x3d4); cr27 = inb(0x3d5);
-       outb(0x2b, 0x3d4); cr2b = inb(0x3d5);
-       outb(0x38, 0x3d4); cr38 = inb(0x3d5);
-
-       outb(0x0b, 0x3c4);
-       inb(0x3c5);
-
-       outb(0x0d, 0x3c4); sr0d = inb(0x3c5);
-       outb(0x18, 0x3c4); sr18 = inb(0x3c5);
-       outb(0x19, 0x3c4); sr19 = inb(0x3c5);
-       outb(0x0f, 0x3ce); gr0f = inb(0x3cf);
-
-       htotal = cr00 | (cr2b & 0x01) << 8;
-       hdispend = cr01 | (cr2b & 0x02) << 7;
-       hblankstart = cr02 | (cr2b & 0x10) << 4;
-       hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;
-       hsyncstart = cr04 | (cr2b & 0x08) << 5;
-       hsyncend = cr05 & 0x1f;
-
-       modedb[0].xres = hblankstart * 8;
-       modedb[0].hsync_len = hsyncend * 8;
-       modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres;
-       modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres -
-           modedb[0].right_margin - modedb[0].hsync_len;
-
-       vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4
-           | (cr27 & 0x80) << 3;
-       vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3
-           | (cr27 & 0x10) << 6;
-       vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2
-           | (cr27 & 0x20) << 5;
-       vsyncend = cr11 & 0x0f;
-       vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4
-           | (cr27 & 0x40) << 4;
-       vblankend = cr16;
-
-       modedb[0].yres = vdispend + 1;
-       modedb[0].vsync_len = vsyncend;
-       modedb[0].lower_margin = vsyncstart - modedb[0].yres;
-       modedb[0].upper_margin = vtotal - modedb[0].yres -
-           modedb[0].lower_margin - modedb[0].vsync_len + 2;
-
-       tmp = cr38 & 0x3c;
-       modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 :
-           tmp == 8 ? 32 : 8;
-
-       fi = ((5864727 * (sr18 + 8)) /
-             (((sr19 & 0x3f) + 2) * (1 << ((sr19 & 0xc0) >> 6)))) >> 12;
-       pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1;
-       tmp = sr0d & 0x06;
-       vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 !
-       modedb[0].pxclk = ((100000000 * pxclkdiv * vclkdiv) >> 1) / fi;
-
-       if (verbosity > 0)
-               output("detected startup mode: "
-                      "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n",
-                      modedb[0].xres, modedb[0].yres, modedb[0].xres,
-                      modedb[0].bpp, modedb[0].pxclk, modedb[0].left_margin,
-                      modedb[0].right_margin, modedb[0].upper_margin,
-                      modedb[0].lower_margin, modedb[0].hsync_len,
-                      modedb[0].vsync_len);
-
-       //
-       // We use this goto target in case of a failed check_var. No, I really
-       // do not want to do it in another way!
-       //
-
-      tryagain:
-
-       i = (mode == NULL) ? 0 :
-           !strncmp(mode, "640x480", 7) ? 1 :
-           !strncmp(mode, "800x600", 7) ? 2 :
-           !strncmp(mode, "1024x768", 8) ? 3 :
-           !strncmp(mode, "1280x1024", 9) ? 4 : 0;
-
-       ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref;
-
-       if (i == 0) {
-               info->var.pixclock = modedb[i].pxclk;
-               info->var.bits_per_pixel = modedb[i].bpp;
-       } else {
-               info->var.pixclock = (100000000 /
-                                     ((modedb[i].left_margin +
-                                       modedb[i].xres +
-                                       modedb[i].right_margin +
-                                       modedb[i].hsync_len) *
-                                      (modedb[i].upper_margin +
-                                       modedb[i].yres +
-                                       modedb[i].lower_margin +
-                                       modedb[i].vsync_len) * ref / 10000));
-               info->var.bits_per_pixel = bpp;
-       }
-
-       info->var.left_margin = modedb[i].left_margin;
-       info->var.right_margin = modedb[i].right_margin;
-       info->var.xres = modedb[i].xres;
-       if (!(modedb[i].yres == 1280 && modedb[i].bpp == 32))
-               info->var.xres_virtual = modedb[i].vxres;
-       else
-               info->var.xres_virtual = modedb[i].xres;
-       info->var.xoffset = 0;
-       info->var.hsync_len = modedb[i].hsync_len;
-       info->var.upper_margin = modedb[i].upper_margin;
-       info->var.yres = modedb[i].yres;
-       info->var.yres_virtual = modedb[i].vyres;
-       info->var.yoffset = 0;
-       info->var.lower_margin = modedb[i].lower_margin;
-       info->var.vsync_len = modedb[i].vsync_len;
-       info->var.sync = 0;
-       info->var.vmode = FB_VMODE_NONINTERLACED;
-
-       if (cyblafb_check_var(&info->var, info)) {
-               // 640x480 - 8@75 should really never fail. One case would
-               // be fp == 1 and nativex < 640 ... give up then
-               if (i == 1 && bpp == 8 && ref == 75) {
-                       output("Can't find a valid mode :-(\n");
-                       return -EINVAL;
-               }
-               // Our detected mode is unlikely to fail. If it does,
-               // try 640x480 - 8@75 ...
-               if (i == 0) {
-                       mode = "640x480";
-                       bpp = 8;
-                       ref = 75;
-                       output("Detected mode failed check_var! "
-                              "Trying 640x480 - 8@75\n");
-                       goto tryagain;
-               }
-               // A specified video mode failed for some reason.
-               // Try the startup mode first
-               output("Specified mode '%s' failed check! "
-                      "Falling back to startup mode.\n", mode);
-               mode = NULL;
-               goto tryagain;
-       }
-
-       return 0;
-}
-
-//========================================================
-//
-// Detect activated memory size. Undefined values require
-// memsize parameter.
-//
-//========================================================
-
-static unsigned int __devinit get_memsize(void)
-{
-       unsigned char tmp;
-       unsigned int k;
-
-       if (memsize)
-               k = memsize * Kb;
-       else {
-               tmp = read3X4(CR1F) & 0x0F;
-               switch (tmp) {
-               case 0x03:
-                       k = 1 * 1024 * 1024;
-                       break;
-               case 0x07:
-                       k = 2 * 1024 * 1024;
-                       break;
-               case 0x0F:
-                       k = 4 * 1024 * 1024;
-                       break;
-               case 0x04:
-                       k = 8 * 1024 * 1024;
-                       break;
-               default:
-                       k = 1 * 1024 * 1024;
-                       output("Unknown memory size code %x in CR1F."
-                              " We default to 1 Mb for now, please"
-                              " do provide a memsize parameter!\n", tmp);
-               }
-       }
-
-       if (verbosity > 0)
-               output("framebuffer size = %d Kb\n", k / Kb);
-       return k;
-}
-
-//=========================================================
-//
-// Detect if a flat panel monitor connected to the special
-// interface is active. Override is possible by fp and crt
-// parameters.
-//
-//=========================================================
-
-static unsigned int __devinit get_displaytype(void)
-{
-       if (fp)
-               return DISPLAY_FP;
-       if (crt)
-               return DISPLAY_CRT;
-       return (read3CE(GR33) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;
-}
-
-//=====================================
-//
-// Get native resolution of flat panel
-//
-//=====================================
-
-static int __devinit get_nativex(void)
-{
-       int x, y, tmp;
-
-       if (nativex)
-               return nativex;
-
-       tmp = (read3CE(GR52) >> 4) & 3;
-
-       switch (tmp) {
-       case 0: x = 1280; y = 1024;
-               break;
-       case 2: x = 1024; y = 768;
-               break;
-       case 3: x = 800;  y = 600;
-               break;
-       case 4: x = 1400; y = 1050;
-               break;
-       case 1:
-       default:
-               x = 640; y = 480;
-               break;
-       }
-
-       if (verbosity > 0)
-               output("%dx%d flat panel found\n", x, y);
-       return x;
-}
-
-static int __devinit cybla_pci_probe(struct pci_dev *dev,
-                                    const struct pci_device_id *id)
-{
-       struct fb_info *info;
-       struct cyblafb_par *par;
-
-       info = framebuffer_alloc(sizeof(struct cyblafb_par), &dev->dev);
-       if (!info)
-               goto errout_alloc_info;
-
-       info->pixmap.addr = kzalloc(CYBLAFB_PIXMAPSIZE, GFP_KERNEL);
-       if (!info->pixmap.addr) {
-               output("allocation of pixmap buffer failed!\n");
-               goto errout_alloc_pixmap;
-       }
-       info->pixmap.size = CYBLAFB_PIXMAPSIZE - 4;
-       info->pixmap.buf_align = 4;
-       info->pixmap.access_align = 32;
-       info->pixmap.flags = FB_PIXMAP_SYSTEM;
-       info->pixmap.scan_align = 4;
-
-       par = info->par;
-       par->ops = cyblafb_ops;
-
-       info->fix = cyblafb_fix;
-       info->fbops = &par->ops;
-       info->fix = cyblafb_fix;
-
-       if (pci_enable_device(dev)) {
-               output("could not enable device!\n");
-               goto errout_enable;
-       }
-       // might already be requested by vga console or vesafb,
-       // so we do care about success
-       if (!request_region(0x3c0, 0x20, "cyblafb")) {
-               output("region 0x3c0/0x20 already reserved\n");
-               vesafb |= 1;
-
-       }
-       //
-       // Graphics Engine Registers
-       //
-       if (!request_region(GEBase, 0x100, "cyblafb")) {
-               output("region %#x/0x100 already reserved\n", GEBase);
-               vesafb |= 2;
-       }
-
-       regdump(par);
-
-       enable_mmio();
-
-       // setup MMIO region
-       info->fix.mmio_start = pci_resource_start(dev, 1);
-       info->fix.mmio_len = 0x20000;
-
-       if (!request_mem_region(info->fix.mmio_start,
-                               info->fix.mmio_len, "cyblafb")) {
-               output("request_mem_region failed for mmio region!\n");
-               goto errout_mmio_reqmem;
-       }
-
-       io_virt = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
-
-       if (!io_virt) {
-               output("ioremap failed for mmio region\n");
-               goto errout_mmio_remap;
-       }
-       // setup framebuffer memory ... might already be requested
-       // by vesafb. Not to fail in case of an unsuccessful request
-       // is useful if both are loaded.
-       info->fix.smem_start = pci_resource_start(dev, 0);
-       info->fix.smem_len = get_memsize();
-
-       if (!request_mem_region(info->fix.smem_start,
-                               info->fix.smem_len, "cyblafb")) {
-               output("region %#lx/%#x already reserved\n",
-                      info->fix.smem_start, info->fix.smem_len);
-               vesafb |= 4;
-       }
-
-       info->screen_base = ioremap_nocache(info->fix.smem_start,
-                                           info->fix.smem_len);
-
-       if (!info->screen_base) {
-               output("ioremap failed for smem region\n");
-               goto errout_smem_remap;
-       }
-
-       displaytype = get_displaytype();
-
-       if (displaytype == DISPLAY_FP)
-               nativex = get_nativex();
-
-       info->flags = FBINFO_DEFAULT
-                   | FBINFO_HWACCEL_COPYAREA
-                   | FBINFO_HWACCEL_FILLRECT
-                   | FBINFO_HWACCEL_IMAGEBLIT
-                   | FBINFO_READS_FAST
-//                 | FBINFO_PARTIAL_PAN_OK
-                   | FBINFO_MISC_ALWAYS_SETPAR;
-
-       info->pseudo_palette = par->pseudo_pal;
-
-       if (getstartupmode(info))
-               goto errout_findmode;
-
-       fb_alloc_cmap(&info->cmap, 256, 0);
-
-       if (register_framebuffer(info)) {
-               output("Could not register CyBla framebuffer\n");
-               goto errout_register;
-       }
-
-       pci_set_drvdata(dev, info);
-
-       //
-       // normal exit and error paths
-       //
-
-       return 0;
-
-      errout_register:
-      errout_findmode:
-       iounmap(info->screen_base);
-      errout_smem_remap:
-       if (!(vesafb & 4))
-               release_mem_region(info->fix.smem_start, info->fix.smem_len);
-       iounmap(io_virt);
-      errout_mmio_remap:
-       release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
-      errout_mmio_reqmem:
-       if (!(vesafb & 1))
-               release_region(0x3c0, 32);
-      errout_enable:
-       kfree(info->pixmap.addr);
-      errout_alloc_pixmap:
-       framebuffer_release(info);
-      errout_alloc_info:
-       output("CyblaFB version %s aborting init.\n", VERSION);
-       return -ENODEV;
-}
-
-static void __devexit cybla_pci_remove(struct pci_dev *dev)
-{
-       struct fb_info *info = pci_get_drvdata(dev);
-
-       unregister_framebuffer(info);
-       iounmap(io_virt);
-       iounmap(info->screen_base);
-       if (!(vesafb & 4))
-               release_mem_region(info->fix.smem_start, info->fix.smem_len);
-       release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
-       fb_dealloc_cmap(&info->cmap);
-       if (!(vesafb & 2))
-               release_region(GEBase, 0x100);
-       if (!(vesafb & 1))
-               release_region(0x3c0, 32);
-       kfree(info->pixmap.addr);
-       framebuffer_release(info);
-       output("CyblaFB version %s normal exit.\n", VERSION);
-}
-
-//
-// List of boards that we are trying to support
-//
-static struct pci_device_id cybla_devices[] = {
-       {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, cybla_devices);
-
-static struct pci_driver cyblafb_pci_driver = {
-       .name = "cyblafb",
-       .id_table = cybla_devices,
-       .probe = cybla_pci_probe,
-       .remove = __devexit_p(cybla_pci_remove)
-};
-
-//=============================================================
-//
-// kernel command line example:
-//
-//     video=cyblafb:1280x1024, bpp=16, ref=50 ...
-//
-// modprobe command line example:
-//
-//     modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
-//
-//=============================================================
-
-static int __devinit cyblafb_init(void)
-{
-#ifndef MODULE
-       char *options = NULL;
-       char *opt;
-
-       if (fb_get_options("cyblafb", &options))
-               return -ENODEV;
-
-       if (options && *options)
-               while ((opt = strsep(&options, ",")) != NULL) {
-                       if (!*opt)
-                               continue;
-                       else if (!strncmp(opt, "bpp=", 4))
-                               bpp = simple_strtoul(opt + 4, NULL, 0);
-                       else if (!strncmp(opt, "ref=", 4))
-                               ref = simple_strtoul(opt + 4, NULL, 0);
-                       else if (!strncmp(opt, "fp", 2))
-                               displaytype = DISPLAY_FP;
-                       else if (!strncmp(opt, "crt", 3))
-                               displaytype = DISPLAY_CRT;
-                       else if (!strncmp(opt, "nativex=", 8))
-                               nativex = simple_strtoul(opt + 8, NULL, 0);
-                       else if (!strncmp(opt, "center", 6))
-                               center = 1;
-                       else if (!strncmp(opt, "stretch", 7))
-                               stretch = 1;
-                       else if (!strncmp(opt, "pciwb=", 6))
-                               pciwb = simple_strtoul(opt + 6, NULL, 0);
-                       else if (!strncmp(opt, "pcirb=", 6))
-                               pcirb = simple_strtoul(opt + 6, NULL, 0);
-                       else if (!strncmp(opt, "pciwr=", 6))
-                               pciwr = simple_strtoul(opt + 6, NULL, 0);
-                       else if (!strncmp(opt, "pcirr=", 6))
-                               pcirr = simple_strtoul(opt + 6, NULL, 0);
-                       else if (!strncmp(opt, "memsize=", 8))
-                               memsize = simple_strtoul(opt + 8, NULL, 0);
-                       else if (!strncmp(opt, "verbosity=", 10))
-                               verbosity = simple_strtoul(opt + 10, NULL, 0);
-                       else
-                               mode = opt;
-               }
-#endif
-       output("CyblaFB version %s initializing\n", VERSION);
-       return pci_register_driver(&cyblafb_pci_driver);
-}
-
-static void __exit cyblafb_exit(void)
-{
-       pci_unregister_driver(&cyblafb_pci_driver);
-}
-
-module_init(cyblafb_init);
-module_exit(cyblafb_exit);
-
-MODULE_AUTHOR("Knut Petersen <knut_petersen@t-online.de>");
-MODULE_DESCRIPTION("Framebuffer driver for Cyberblade/i1 graphics core");
-MODULE_LICENSE("GPL");
index daf9b81878a463a62bb81427f8e2e97c1978c2e3..0c5b9a9fd56f178cf0ad10bed907138a2b06fe3c 100644 (file)
@@ -129,6 +129,8 @@ static int set_system(const struct dmi_system_id *id)
                screen_info.lfb_width = info->width;
        if (screen_info.lfb_height == 0)
                screen_info.lfb_height = info->height;
+       if (screen_info.orig_video_isVGA == 0)
+               screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
 
        return 0;
 }
@@ -374,9 +376,10 @@ static int __init efifb_init(void)
        int ret;
        char *option = NULL;
 
+       dmi_check_system(dmi_system_table);
+
        if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
                return -ENODEV;
-       dmi_check_system(dmi_system_table);
 
        if (fb_get_options("efifb", &option))
                return -ENODEV;
index 082026546aee979e9bee1f2e8f4a440df02d20a6..0a7a6679ee6eb05e2be754ff816ba3547a0f7fdb 100644 (file)
@@ -85,8 +85,9 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_fsync);
 
 /* vm_ops->page_mkwrite handler */
 static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
-                                 struct page *page)
+                                 struct vm_fault *vmf)
 {
+       struct page *page = vmf->page;
        struct fb_info *info = vma->vm_private_data;
        struct fb_deferred_io *fbdefio = info->fbdefio;
        struct page *cur;
index cfd9dce1ce0b666627b6306e0eb693f669e154f5..2ac32e6b5953bb981e8bc57f9516584bc868d1c9 100644 (file)
 struct fb_info *registered_fb[FB_MAX] __read_mostly;
 int num_registered_fb __read_mostly;
 
+int lock_fb_info(struct fb_info *info)
+{
+       mutex_lock(&info->lock);
+       if (!info->fbops) {
+               mutex_unlock(&info->lock);
+               return 0;
+       }
+       return 1;
+}
+EXPORT_SYMBOL(lock_fb_info);
+
 /*
  * Helpers
  */
@@ -1086,13 +1097,8 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
                        return -EINVAL;
                con2fb.framebuffer = -1;
                event.data = &con2fb;
-
-               if (!lock_fb_info(info))
-                       return -ENODEV;
                event.info = info;
                fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
-               unlock_fb_info(info);
-
                ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
                break;
        case FBIOPUT_CON2FBMAP:
@@ -1109,12 +1115,8 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
                        break;
                }
                event.data = &con2fb;
-               if (!lock_fb_info(info))
-                       return -ENODEV;
                event.info = info;
-               ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP,
-                                             &event);
-               unlock_fb_info(info);
+               ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
                break;
        case FBIOBLANK:
                if (!lock_fb_info(info))
index d9627b57eb4d27e12242116f2fc77c99516ab0dd..135ae18bfce84e7bdd0e307d7d470e8370919ca6 100644 (file)
@@ -362,6 +362,7 @@ int NVCommonSetup(struct fb_info *info)
        case 0x0186:
        case 0x0187:
        case 0x018D:
+       case 0x01D7:
        case 0x0228:
        case 0x0286:
        case 0x028C:
index f132aab8c5de2fbd57acd1ea1c5c3c934d85dd6c..c03f7f55c76d47199909dd89d6d520ac07f68f1f 100644 (file)
@@ -5,7 +5,6 @@
 #include <linux/types.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
-#include <linux/mutex.h>
 #include <video/vga.h>
 
 #define NV_ARCH_04  0x04
@@ -99,7 +98,6 @@ struct nvidia_par {
        RIVA_HW_STATE initial_state;
        RIVA_HW_STATE *CurrentState;
        struct vgastate vgastate;
-       struct mutex open_lock;
        u32 pseudo_palette[16];
        struct pci_dev *pci_dev;
        u32 Architecture;
index 9dbb5a5a267b4ac5e060172748210981f251b1d3..efe10ff86d6365ceaf5ab6f4fb3a0425b8f82c78 100644 (file)
@@ -1004,15 +1004,12 @@ static int nvidiafb_open(struct fb_info *info, int user)
 {
        struct nvidia_par *par = info->par;
 
-       mutex_lock(&par->open_lock);
-
        if (!par->open_count) {
                save_vga_x86(par);
                nvidia_save_vga(par, &par->initial_state);
        }
 
        par->open_count++;
-       mutex_unlock(&par->open_lock);
        return 0;
 }
 
@@ -1021,8 +1018,6 @@ static int nvidiafb_release(struct fb_info *info, int user)
        struct nvidia_par *par = info->par;
        int err = 0;
 
-       mutex_lock(&par->open_lock);
-
        if (!par->open_count) {
                err = -EINVAL;
                goto done;
@@ -1035,7 +1030,6 @@ static int nvidiafb_release(struct fb_info *info, int user)
 
        par->open_count--;
 done:
-       mutex_unlock(&par->open_lock);
        return err;
 }
 
@@ -1300,7 +1294,6 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
 
        par = info->par;
        par->pci_dev = pd;
-       mutex_init(&par->open_lock);
        info->pixmap.addr = kzalloc(8 * 1024, GFP_KERNEL);
 
        if (info->pixmap.addr == NULL)
index f24df0b54e1cad0ff54ab68d5439b99fd8ae03c0..8aa6e47202b943369cb23912b0f8c66ed613877a 100644 (file)
@@ -742,7 +742,7 @@ static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div)
                if (calc_reg_timing(sysclk, div) == 0)
                        break;
        }
-       if (div > max_clk_div)
+       if (div >= max_clk_div)
                goto err;
 
        *extif_mem_div = div;
@@ -752,7 +752,7 @@ static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div)
                        break;
        }
 
-       if (div > max_clk_div)
+       if (div >= max_clk_div)
                goto err;
 
        return 0;
index 1a49519dafa483b864c992dfb1f92b2f8e02505f..060d72fe57cb1f639861ae24cf10a6ed0babdb40 100644 (file)
@@ -338,7 +338,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
 
        omapfb_rqueue_lock(fbdev);
        switch (blank) {
-       case VESA_NO_BLANKING:
+       case FB_BLANK_UNBLANK:
                if (fbdev->state == OMAPFB_SUSPENDED) {
                        if (fbdev->ctrl->resume)
                                fbdev->ctrl->resume();
@@ -349,7 +349,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
                                do_update = 1;
                }
                break;
-       case VESA_POWERDOWN:
+       case FB_BLANK_POWERDOWN:
                if (fbdev->state == OMAPFB_ACTIVE) {
                        fbdev->panel->disable(fbdev->panel);
                        if (fbdev->ctrl->suspend)
@@ -1818,7 +1818,7 @@ static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg)
 {
        struct omapfb_device *fbdev = platform_get_drvdata(pdev);
 
-       omapfb_blank(VESA_POWERDOWN, fbdev->fb_info[0]);
+       omapfb_blank(FB_BLANK_POWERDOWN, fbdev->fb_info[0]);
 
        return 0;
 }
@@ -1828,7 +1828,7 @@ static int omapfb_resume(struct platform_device *pdev)
 {
        struct omapfb_device *fbdev = platform_get_drvdata(pdev);
 
-       omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info[0]);
+       omapfb_blank(FB_BLANK_UNBLANK, fbdev->fb_info[0]);
        return 0;
 }
 
index a7b01d2724b5110ce4365fa35e8c32c05c6b385c..0726aecf3b7e084c87f6abdc66ca44f4c16cb631 100644 (file)
 #define dbg(fmt, args...) do { } while (0)
 #endif
 
-static const int __devinitconst s1d13xxxfb_revisions[] = {
-       S1D13506_CHIP_REV,      /* Rev.4 on HP Jornada 7xx S1D13506 */
-       S1D13806_CHIP_REV,      /* Rev.7 on .. */
+/*
+ * List of card production ids
+ */
+static const int s1d13xxxfb_prod_ids[] = {
+       S1D13505_PROD_ID,
+       S1D13506_PROD_ID,
+       S1D13806_PROD_ID,
+};
+
+/*
+ * List of card strings
+ */
+static const char *s1d13xxxfb_prod_names[] = {
+       "S1D13505",
+       "S1D13506",
+       "S1D13806",
 };
 
 /*
@@ -377,7 +390,6 @@ s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
        return 0;
 }
 
-
 /* framebuffer information structures */
 
 static struct fb_ops s1d13xxxfb_fbops = {
@@ -544,7 +556,7 @@ s1d13xxxfb_probe(struct platform_device *pdev)
        struct s1d13xxxfb_pdata *pdata = NULL;
        int ret = 0;
        int i;
-       u8 revision;
+       u8 revision, prod_id;
 
        dbg("probe called: device is %p\n", pdev);
 
@@ -613,19 +625,31 @@ s1d13xxxfb_probe(struct platform_device *pdev)
                goto bail;
        }
 
-       revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) >> 2;
-
+       /* production id is top 6 bits */
+       prod_id = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) >> 2;
+       /* revision id is lower 2 bits */
+       revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) & 0x3;
        ret = -ENODEV;
 
-       for (i = 0; i < ARRAY_SIZE(s1d13xxxfb_revisions); i++) {
-               if (revision == s1d13xxxfb_revisions[i])
+       for (i = 0; i < ARRAY_SIZE(s1d13xxxfb_prod_ids); i++) {
+               if (prod_id == s1d13xxxfb_prod_ids[i]) {
+                       /* looks like we got it in our list */
+                       default_par->prod_id = prod_id;
+                       default_par->revision = revision;
                        ret = 0;
+                       break;
+               }
        }
 
-       if (!ret)
+       if (!ret) {
+               printk(KERN_INFO PFX "chip production id %i = %s\n",
+                       prod_id, s1d13xxxfb_prod_names[i]);
                printk(KERN_INFO PFX "chip revision %i\n", revision);
-       else {
-               printk(KERN_INFO PFX "unknown chip revision %i\n", revision);
+       } else {
+               printk(KERN_INFO PFX
+                       "unknown chip production id %i, revision %i\n",
+                       prod_id, revision);
+               printk(KERN_INFO PFX "please contant maintainer\n");
                goto bail;
        }
 
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
new file mode 100644 (file)
index 0000000..5e9c630
--- /dev/null
@@ -0,0 +1,1036 @@
+/* linux/drivers/video/s3c-fb.c
+ *
+ * Copyright 2008 Openmoko Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * Samsung SoC Framebuffer driver
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/gfp.h>
+#include <linux/clk.h>
+#include <linux/fb.h>
+#include <linux/io.h>
+
+#include <mach/map.h>
+#include <mach/regs-fb.h>
+#include <plat/fb.h>
+
+/* This driver will export a number of framebuffer interfaces depending
+ * on the configuration passed in via the platform data. Each fb instance
+ * maps to a hardware window. Currently there is no support for runtime
+ * setting of the alpha-blending functions that each window has, so only
+ * window 0 is actually useful.
+ *
+ * Window 0 is treated specially, it is used for the basis of the LCD
+ * output timings and as the control for the output power-down state.
+*/
+
+/* note, some of the functions that get called are derived from including
+ * <mach/regs-fb.h> as they are specific to the architecture that the code
+ * is being built for.
+*/
+
+#ifdef CONFIG_FB_S3C_DEBUG_REGWRITE
+#undef writel
+#define writel(v, r) do { \
+       printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \
+       __raw_writel(v, r); } while(0)
+#endif /* FB_S3C_DEBUG_REGWRITE */
+
+struct s3c_fb;
+
+/**
+ * struct s3c_fb_win - per window private data for each framebuffer.
+ * @windata: The platform data supplied for the window configuration.
+ * @parent: The hardware that this window is part of.
+ * @fbinfo: Pointer pack to the framebuffer info for this window.
+ * @palette_buffer: Buffer/cache to hold palette entries.
+ * @pseudo_palette: For use in TRUECOLOUR modes for entries 0..15/
+ * @index: The window number of this window.
+ * @palette: The bitfields for changing r/g/b into a hardware palette entry.
+ */
+struct s3c_fb_win {
+       struct s3c_fb_pd_win    *windata;
+       struct s3c_fb           *parent;
+       struct fb_info          *fbinfo;
+       struct s3c_fb_palette    palette;
+
+       u32                     *palette_buffer;
+       u32                      pseudo_palette[16];
+       unsigned int             index;
+};
+
+/**
+ * struct s3c_fb - overall hardware state of the hardware
+ * @dev: The device that we bound to, for printing, etc.
+ * @regs_res: The resource we claimed for the IO registers.
+ * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
+ * @regs: The mapped hardware registers.
+ * @enabled: A bitmask of enabled hardware windows.
+ * @pdata: The platform configuration data passed with the device.
+ * @windows: The hardware windows that have been claimed.
+ */
+struct s3c_fb {
+       struct device           *dev;
+       struct resource         *regs_res;
+       struct clk              *bus_clk;
+       void __iomem            *regs;
+
+       unsigned char            enabled;
+
+       struct s3c_fb_platdata  *pdata;
+       struct s3c_fb_win       *windows[S3C_FB_MAX_WIN];
+};
+
+/**
+ * s3c_fb_win_has_palette() - determine if a mode has a palette
+ * @win: The window number being queried.
+ * @bpp: The number of bits per pixel to test.
+ *
+ * Work out if the given window supports palletised data at the specified bpp.
+ */
+static int s3c_fb_win_has_palette(unsigned int win, unsigned int bpp)
+{
+       return s3c_fb_win_pal_size(win) <= (1 << bpp);
+}
+
+/**
+ * s3c_fb_check_var() - framebuffer layer request to verify a given mode.
+ * @var: The screen information to verify.
+ * @info: The framebuffer device.
+ *
+ * Framebuffer layer call to verify the given information and allow us to
+ * update various information depending on the hardware capabilities.
+ */
+static int s3c_fb_check_var(struct fb_var_screeninfo *var,
+                           struct fb_info *info)
+{
+       struct s3c_fb_win *win = info->par;
+       struct s3c_fb_pd_win *windata = win->windata;
+       struct s3c_fb *sfb = win->parent;
+
+       dev_dbg(sfb->dev, "checking parameters\n");
+
+       var->xres_virtual = max((unsigned int)windata->virtual_x, var->xres);
+       var->yres_virtual = max((unsigned int)windata->virtual_y, var->yres);
+
+       if (!s3c_fb_validate_win_bpp(win->index, var->bits_per_pixel)) {
+               dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n",
+                       win->index, var->bits_per_pixel);
+               return -EINVAL;
+       }
+
+       /* always ensure these are zero, for drop through cases below */
+       var->transp.offset = 0;
+       var->transp.length = 0;
+
+       switch (var->bits_per_pixel) {
+       case 1:
+       case 2:
+       case 4:
+       case 8:
+               if (!s3c_fb_win_has_palette(win->index, var->bits_per_pixel)) {
+                       /* non palletised, A:1,R:2,G:3,B:2 mode */
+                       var->red.offset         = 4;
+                       var->green.offset       = 2;
+                       var->blue.offset        = 0;
+                       var->red.length         = 5;
+                       var->green.length       = 3;
+                       var->blue.length        = 2;
+                       var->transp.offset      = 7;
+                       var->transp.length      = 1;
+               } else {
+                       var->red.offset = 0;
+                       var->red.length = var->bits_per_pixel;
+                       var->green      = var->red;
+                       var->blue       = var->red;
+               }
+               break;
+
+       case 19:
+               /* 666 with one bit alpha/transparency */
+               var->transp.offset      = 18;
+               var->transp.length      = 1;
+       case 18:
+               var->bits_per_pixel     = 32;
+
+               /* 666 format */
+               var->red.offset         = 12;
+               var->green.offset       = 6;
+               var->blue.offset        = 0;
+               var->red.length         = 6;
+               var->green.length       = 6;
+               var->blue.length        = 6;
+               break;
+
+       case 16:
+               /* 16 bpp, 565 format */
+               var->red.offset         = 11;
+               var->green.offset       = 5;
+               var->blue.offset        = 0;
+               var->red.length         = 5;
+               var->green.length       = 6;
+               var->blue.length        = 5;
+               break;
+
+       case 28:
+       case 25:
+               var->transp.length      = var->bits_per_pixel - 24;
+               var->transp.offset      = 24;
+               /* drop through */
+       case 24:
+               /* our 24bpp is unpacked, so 32bpp */
+               var->bits_per_pixel     = 32;
+       case 32:
+               var->red.offset         = 16;
+               var->red.length         = 8;
+               var->green.offset       = 8;
+               var->green.length       = 8;
+               var->blue.offset        = 0;
+               var->blue.length        = 8;
+               break;
+
+       default:
+               dev_err(sfb->dev, "invalid bpp\n");
+       }
+
+       dev_dbg(sfb->dev, "%s: verified parameters\n", __func__);
+       return 0;
+}
+
+/**
+ * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock.
+ * @sfb: The hardware state.
+ * @pixclock: The pixel clock wanted, in picoseconds.
+ *
+ * Given the specified pixel clock, work out the necessary divider to get
+ * close to the output frequency.
+ */
+static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
+{
+       unsigned long clk = clk_get_rate(sfb->bus_clk);
+       unsigned long long tmp;
+       unsigned int result;
+
+       tmp = (unsigned long long)clk;
+       tmp *= pixclk;
+
+       do_div(tmp, 1000000000UL);
+       result = (unsigned int)tmp / 1000;
+
+       dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n",
+               pixclk, clk, result, clk / result);
+
+       return result;
+}
+
+/**
+ * s3c_fb_align_word() - align pixel count to word boundary
+ * @bpp: The number of bits per pixel
+ * @pix: The value to be aligned.
+ *
+ * Align the given pixel count so that it will start on an 32bit word
+ * boundary.
+ */
+static int s3c_fb_align_word(unsigned int bpp, unsigned int pix)
+{
+       int pix_per_word;
+
+       if (bpp > 16)
+               return pix;
+
+       pix_per_word = (8 * 32) / bpp;
+       return ALIGN(pix, pix_per_word);
+}
+
+/**
+ * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
+ * @info: The framebuffer to change.
+ *
+ * Framebuffer layer request to set a new mode for the specified framebuffer
+ */
+static int s3c_fb_set_par(struct fb_info *info)
+{
+       struct fb_var_screeninfo *var = &info->var;
+       struct s3c_fb_win *win = info->par;
+       struct s3c_fb *sfb = win->parent;
+       void __iomem *regs = sfb->regs;
+       int win_no = win->index;
+       u32 data;
+       u32 pagewidth;
+       int clkdiv;
+
+       dev_dbg(sfb->dev, "setting framebuffer parameters\n");
+
+       switch (var->bits_per_pixel) {
+       case 32:
+       case 24:
+       case 16:
+       case 12:
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+               break;
+       case 8:
+               if (s3c_fb_win_has_palette(win_no, 8))
+                       info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+               else
+                       info->fix.visual = FB_VISUAL_TRUECOLOR;
+               break;
+       case 1:
+               info->fix.visual = FB_VISUAL_MONO01;
+               break;
+       default:
+               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+               break;
+       }
+
+       info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
+
+       /* disable the window whilst we update it */
+       writel(0, regs + WINCON(win_no));
+
+       /* use window 0 as the basis for the lcd output timings */
+
+       if (win_no == 0) {
+               clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
+
+               data = sfb->pdata->vidcon0;
+               data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
+
+               if (clkdiv > 1)
+                       data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
+               else
+                       data &= ~VIDCON0_CLKDIR;        /* 1:1 clock */
+
+               /* write the timing data to the panel */
+
+               data |= VIDCON0_ENVID | VIDCON0_ENVID_F;
+               writel(data, regs + VIDCON0);
+
+               data = VIDTCON0_VBPD(var->upper_margin - 1) |
+                      VIDTCON0_VFPD(var->lower_margin - 1) |
+                      VIDTCON0_VSPW(var->vsync_len - 1);
+
+               writel(data, regs + VIDTCON0);
+
+               data = VIDTCON1_HBPD(var->left_margin - 1) |
+                      VIDTCON1_HFPD(var->right_margin - 1) |
+                      VIDTCON1_HSPW(var->hsync_len - 1);
+
+               writel(data, regs + VIDTCON1);
+
+               data = VIDTCON2_LINEVAL(var->yres - 1) |
+                      VIDTCON2_HOZVAL(var->xres - 1);
+               writel(data, regs + VIDTCON2);
+       }
+
+       /* write the buffer address */
+
+       writel(info->fix.smem_start, regs + VIDW_BUF_START(win_no));
+
+       data = info->fix.smem_start + info->fix.line_length * var->yres;
+       writel(data, regs + VIDW_BUF_END(win_no));
+
+       pagewidth = (var->xres * var->bits_per_pixel) >> 3;
+       data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) |
+              VIDW_BUF_SIZE_PAGEWIDTH(pagewidth);
+       writel(data, regs + VIDW_BUF_SIZE(win_no));
+
+       /* write 'OSD' registers to control position of framebuffer */
+
+       data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0);
+       writel(data, regs + VIDOSD_A(win_no));
+
+       data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel,
+                                                    var->xres - 1)) |
+              VIDOSDxB_BOTRIGHT_Y(var->yres - 1);
+
+       writel(data, regs + VIDOSD_B(win_no));
+
+       data = var->xres * var->yres;
+       if (s3c_fb_has_osd_d(win_no)) {
+               writel(data, regs + VIDOSD_D(win_no));
+               writel(0, regs + VIDOSD_C(win_no));
+       } else
+               writel(data, regs + VIDOSD_C(win_no));
+
+       data = WINCONx_ENWIN;
+
+       /* note, since we have to round up the bits-per-pixel, we end up
+        * relying on the bitfield information for r/g/b/a to work out
+        * exactly which mode of operation is intended. */
+
+       switch (var->bits_per_pixel) {
+       case 1:
+               data |= WINCON0_BPPMODE_1BPP;
+               data |= WINCONx_BITSWP;
+               data |= WINCONx_BURSTLEN_4WORD;
+               break;
+       case 2:
+               data |= WINCON0_BPPMODE_2BPP;
+               data |= WINCONx_BITSWP;
+               data |= WINCONx_BURSTLEN_8WORD;
+               break;
+       case 4:
+               data |= WINCON0_BPPMODE_4BPP;
+               data |= WINCONx_BITSWP;
+               data |= WINCONx_BURSTLEN_8WORD;
+               break;
+       case 8:
+               if (var->transp.length != 0)
+                       data |= WINCON1_BPPMODE_8BPP_1232;
+               else
+                       data |= WINCON0_BPPMODE_8BPP_PALETTE;
+               data |= WINCONx_BURSTLEN_8WORD;
+               data |= WINCONx_BYTSWP;
+               break;
+       case 16:
+               if (var->transp.length != 0)
+                       data |= WINCON1_BPPMODE_16BPP_A1555;
+               else
+                       data |= WINCON0_BPPMODE_16BPP_565;
+               data |= WINCONx_HAWSWP;
+               data |= WINCONx_BURSTLEN_16WORD;
+               break;
+       case 24:
+       case 32:
+               if (var->red.length == 6) {
+                       if (var->transp.length != 0)
+                               data |= WINCON1_BPPMODE_19BPP_A1666;
+                       else
+                               data |= WINCON1_BPPMODE_18BPP_666;
+               } else if (var->transp.length != 0)
+                       data |= WINCON1_BPPMODE_25BPP_A1888;
+               else
+                       data |= WINCON0_BPPMODE_24BPP_888;
+
+               data |= WINCONx_BURSTLEN_16WORD;
+               break;
+       }
+
+       writel(data, regs + WINCON(win_no));
+       writel(0x0, regs + WINxMAP(win_no));
+
+       return 0;
+}
+
+/**
+ * s3c_fb_update_palette() - set or schedule a palette update.
+ * @sfb: The hardware information.
+ * @win: The window being updated.
+ * @reg: The palette index being changed.
+ * @value: The computed palette value.
+ *
+ * Change the value of a palette register, either by directly writing to
+ * the palette (this requires the palette RAM to be disconnected from the
+ * hardware whilst this is in progress) or schedule the update for later.
+ *
+ * At the moment, since we have no VSYNC interrupt support, we simply set
+ * the palette entry directly.
+ */
+static void s3c_fb_update_palette(struct s3c_fb *sfb,
+                                 struct s3c_fb_win *win,
+                                 unsigned int reg,
+                                 u32 value)
+{
+       void __iomem *palreg;
+       u32 palcon;
+
+       palreg = sfb->regs + s3c_fb_pal_reg(win->index, reg);
+
+       dev_dbg(sfb->dev, "%s: win %d, reg %d (%p): %08x\n",
+               __func__, win->index, reg, palreg, value);
+
+       win->palette_buffer[reg] = value;
+
+       palcon = readl(sfb->regs + WPALCON);
+       writel(palcon | WPALCON_PAL_UPDATE, sfb->regs + WPALCON);
+
+       if (s3c_fb_pal_is16(win->index))
+               writew(value, palreg);
+       else
+               writel(value, palreg);
+
+       writel(palcon, sfb->regs + WPALCON);
+}
+
+static inline unsigned int chan_to_field(unsigned int chan,
+                                        struct fb_bitfield *bf)
+{
+       chan &= 0xffff;
+       chan >>= 16 - bf->length;
+       return chan << bf->offset;
+}
+
+/**
+ * s3c_fb_setcolreg() - framebuffer layer request to change palette.
+ * @regno: The palette index to change.
+ * @red: The red field for the palette data.
+ * @green: The green field for the palette data.
+ * @blue: The blue field for the palette data.
+ * @trans: The transparency (alpha) field for the palette data.
+ * @info: The framebuffer being changed.
+ */
+static int s3c_fb_setcolreg(unsigned regno,
+                           unsigned red, unsigned green, unsigned blue,
+                           unsigned transp, struct fb_info *info)
+{
+       struct s3c_fb_win *win = info->par;
+       struct s3c_fb *sfb = win->parent;
+       unsigned int val;
+
+       dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n",
+               __func__, win->index, regno, red, green, blue);
+
+       switch (info->fix.visual) {
+       case FB_VISUAL_TRUECOLOR:
+               /* true-colour, use pseudo-palette */
+
+               if (regno < 16) {
+                       u32 *pal = info->pseudo_palette;
+
+                       val  = chan_to_field(red,   &info->var.red);
+                       val |= chan_to_field(green, &info->var.green);
+                       val |= chan_to_field(blue,  &info->var.blue);
+
+                       pal[regno] = val;
+               }
+               break;
+
+       case FB_VISUAL_PSEUDOCOLOR:
+               if (regno < s3c_fb_win_pal_size(win->index)) {
+                       val  = chan_to_field(red, &win->palette.r);
+                       val |= chan_to_field(green, &win->palette.g);
+                       val |= chan_to_field(blue, &win->palette.b);
+
+                       s3c_fb_update_palette(sfb, win, regno, val);
+               }
+
+               break;
+
+       default:
+               return 1;       /* unknown type */
+       }
+
+       return 0;
+}
+
+/**
+ * s3c_fb_enable() - Set the state of the main LCD output
+ * @sfb: The main framebuffer state.
+ * @enable: The state to set.
+ */
+static void s3c_fb_enable(struct s3c_fb *sfb, int enable)
+{
+       u32 vidcon0 = readl(sfb->regs + VIDCON0);
+
+       if (enable)
+               vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F;
+       else {
+               /* see the note in the framebuffer datasheet about
+                * why you cannot take both of these bits down at the
+                * same time. */
+
+               if (!(vidcon0 & VIDCON0_ENVID))
+                       return;
+
+               vidcon0 |= VIDCON0_ENVID;
+               vidcon0 &= ~VIDCON0_ENVID_F;
+       }
+
+       writel(vidcon0, sfb->regs + VIDCON0);
+}
+
+/**
+ * s3c_fb_blank() - blank or unblank the given window
+ * @blank_mode: The blank state from FB_BLANK_*
+ * @info: The framebuffer to blank.
+ *
+ * Framebuffer layer request to change the power state.
+ */
+static int s3c_fb_blank(int blank_mode, struct fb_info *info)
+{
+       struct s3c_fb_win *win = info->par;
+       struct s3c_fb *sfb = win->parent;
+       unsigned int index = win->index;
+       u32 wincon;
+
+       dev_dbg(sfb->dev, "blank mode %d\n", blank_mode);
+
+       wincon = readl(sfb->regs + WINCON(index));
+
+       switch (blank_mode) {
+       case FB_BLANK_POWERDOWN:
+               wincon &= ~WINCONx_ENWIN;
+               sfb->enabled &= ~(1 << index);
+               /* fall through to FB_BLANK_NORMAL */
+
+       case FB_BLANK_NORMAL:
+               /* disable the DMA and display 0x0 (black) */
+               writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0),
+                      sfb->regs + WINxMAP(index));
+               break;
+
+       case FB_BLANK_UNBLANK:
+               writel(0x0, sfb->regs + WINxMAP(index));
+               wincon |= WINCONx_ENWIN;
+               sfb->enabled |= (1 << index);
+               break;
+
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
+       default:
+               return 1;
+       }
+
+       writel(wincon, sfb->regs + WINCON(index));
+
+       /* Check the enabled state to see if we need to be running the
+        * main LCD interface, as if there are no active windows then
+        * it is highly likely that we also do not need to output
+        * anything.
+        */
+
+       /* We could do something like the following code, but the current
+        * system of using framebuffer events means that we cannot make
+        * the distinction between just window 0 being inactive and all
+        * the windows being down.
+        *
+        * s3c_fb_enable(sfb, sfb->enabled ? 1 : 0);
+       */
+
+       /* we're stuck with this until we can do something about overriding
+        * the power control using the blanking event for a single fb.
+        */
+       if (index == 0)
+               s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0);
+
+       return 0;
+}
+
+static struct fb_ops s3c_fb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = s3c_fb_check_var,
+       .fb_set_par     = s3c_fb_set_par,
+       .fb_blank       = s3c_fb_blank,
+       .fb_setcolreg   = s3c_fb_setcolreg,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+};
+
+/**
+ * s3c_fb_alloc_memory() - allocate display memory for framebuffer window
+ * @sfb: The base resources for the hardware.
+ * @win: The window to initialise memory for.
+ *
+ * Allocate memory for the given framebuffer.
+ */
+static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb,
+                                        struct s3c_fb_win *win)
+{
+       struct s3c_fb_pd_win *windata = win->windata;
+       unsigned int real_size, virt_size, size;
+       struct fb_info *fbi = win->fbinfo;
+       dma_addr_t map_dma;
+
+       dev_dbg(sfb->dev, "allocating memory for display\n");
+
+       real_size = windata->win_mode.xres * windata->win_mode.yres;
+       virt_size = windata->virtual_x * windata->virtual_y;
+
+       dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n",
+               real_size, windata->win_mode.xres, windata->win_mode.yres,
+               virt_size, windata->virtual_x, windata->virtual_y);
+
+       size = (real_size > virt_size) ? real_size : virt_size;
+       size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp;
+       size /= 8;
+
+       fbi->fix.smem_len = size;
+       size = PAGE_ALIGN(size);
+
+       dev_dbg(sfb->dev, "want %u bytes for window\n", size);
+
+       fbi->screen_base = dma_alloc_writecombine(sfb->dev, size,
+                                                 &map_dma, GFP_KERNEL);
+       if (!fbi->screen_base)
+               return -ENOMEM;
+
+       dev_dbg(sfb->dev, "mapped %x to %p\n",
+               (unsigned int)map_dma, fbi->screen_base);
+
+       memset(fbi->screen_base, 0x0, size);
+       fbi->fix.smem_start = map_dma;
+
+       return 0;
+}
+
+/**
+ * s3c_fb_free_memory() - free the display memory for the given window
+ * @sfb: The base resources for the hardware.
+ * @win: The window to free the display memory for.
+ *
+ * Free the display memory allocated by s3c_fb_alloc_memory().
+ */
+static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
+{
+       struct fb_info *fbi = win->fbinfo;
+
+       dma_free_writecombine(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len),
+                             fbi->screen_base, fbi->fix.smem_start);
+}
+
+/**
+ * s3c_fb_release_win() - release resources for a framebuffer window.
+ * @win: The window to cleanup the resources for.
+ *
+ * Release the resources that where claimed for the hardware window,
+ * such as the framebuffer instance and any memory claimed for it.
+ */
+static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
+{
+       fb_dealloc_cmap(&win->fbinfo->cmap);
+       unregister_framebuffer(win->fbinfo);
+       s3c_fb_free_memory(sfb, win);
+}
+
+/**
+ * s3c_fb_probe_win() - register an hardware window
+ * @sfb: The base resources for the hardware
+ * @res: Pointer to where to place the resultant window.
+ *
+ * Allocate and do the basic initialisation for one of the hardware's graphics
+ * windows.
+ */
+static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
+                                     struct s3c_fb_win **res)
+{
+       struct fb_var_screeninfo *var;
+       struct fb_videomode *initmode;
+       struct s3c_fb_pd_win *windata;
+       struct s3c_fb_win *win;
+       struct fb_info *fbinfo;
+       int palette_size;
+       int ret;
+
+       dev_dbg(sfb->dev, "probing window %d\n", win_no);
+
+       palette_size = s3c_fb_win_pal_size(win_no);
+
+       fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
+                                  palette_size * sizeof(u32), sfb->dev);
+       if (!fbinfo) {
+               dev_err(sfb->dev, "failed to allocate framebuffer\n");
+               return -ENOENT;
+       }
+
+       windata = sfb->pdata->win[win_no];
+       initmode = &windata->win_mode;
+
+       WARN_ON(windata->max_bpp == 0);
+       WARN_ON(windata->win_mode.xres == 0);
+       WARN_ON(windata->win_mode.yres == 0);
+
+       win = fbinfo->par;
+       var = &fbinfo->var;
+       win->fbinfo = fbinfo;
+       win->parent = sfb;
+       win->windata = windata;
+       win->index = win_no;
+       win->palette_buffer = (u32 *)(win + 1);
+
+       ret = s3c_fb_alloc_memory(sfb, win);
+       if (ret) {
+               dev_err(sfb->dev, "failed to allocate display memory\n");
+               goto err_framebuffer;
+       }
+
+       /* setup the r/b/g positions for the window's palette */
+       s3c_fb_init_palette(win_no, &win->palette);
+
+       /* setup the initial video mode from the window */
+       fb_videomode_to_var(&fbinfo->var, initmode);
+
+       fbinfo->fix.type        = FB_TYPE_PACKED_PIXELS;
+       fbinfo->fix.accel       = FB_ACCEL_NONE;
+       fbinfo->var.activate    = FB_ACTIVATE_NOW;
+       fbinfo->var.vmode       = FB_VMODE_NONINTERLACED;
+       fbinfo->var.bits_per_pixel = windata->default_bpp;
+       fbinfo->fbops           = &s3c_fb_ops;
+       fbinfo->flags           = FBINFO_FLAG_DEFAULT;
+       fbinfo->pseudo_palette  = &win->pseudo_palette;
+
+       /* prepare to actually start the framebuffer */
+
+       ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
+       if (ret < 0) {
+               dev_err(sfb->dev, "check_var failed on initial video params\n");
+               goto err_alloc_mem;
+       }
+
+       /* create initial colour map */
+
+       ret = fb_alloc_cmap(&fbinfo->cmap, s3c_fb_win_pal_size(win_no), 1);
+       if (ret == 0)
+               fb_set_cmap(&fbinfo->cmap, fbinfo);
+       else
+               dev_err(sfb->dev, "failed to allocate fb cmap\n");
+
+       s3c_fb_set_par(fbinfo);
+
+       dev_dbg(sfb->dev, "about to register framebuffer\n");
+
+       /* run the check_var and set_par on our configuration. */
+
+       ret = register_framebuffer(fbinfo);
+       if (ret < 0) {
+               dev_err(sfb->dev, "failed to register framebuffer\n");
+               goto err_alloc_mem;
+       }
+
+       *res = win;
+       dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
+
+       return 0;
+
+err_alloc_mem:
+       s3c_fb_free_memory(sfb, win);
+
+err_framebuffer:
+       unregister_framebuffer(fbinfo);
+       return ret;
+}
+
+/**
+ * s3c_fb_clear_win() - clear hardware window registers.
+ * @sfb: The base resources for the hardware.
+ * @win: The window to process.
+ *
+ * Reset the specific window registers to a known state.
+ */
+static void s3c_fb_clear_win(struct s3c_fb *sfb, int win)
+{
+       void __iomem *regs = sfb->regs;
+
+       writel(0, regs + WINCON(win));
+       writel(0xffffff, regs + WxKEYCONy(win, 0));
+       writel(0xffffff, regs + WxKEYCONy(win, 1));
+
+       writel(0, regs + VIDOSD_A(win));
+       writel(0, regs + VIDOSD_B(win));
+       writel(0, regs + VIDOSD_C(win));
+}
+
+static int __devinit s3c_fb_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct s3c_fb_platdata *pd;
+       struct s3c_fb *sfb;
+       struct resource *res;
+       int win;
+       int ret = 0;
+
+       pd = pdev->dev.platform_data;
+       if (!pd) {
+               dev_err(dev, "no platform data specified\n");
+               return -EINVAL;
+       }
+
+       sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL);
+       if (!sfb) {
+               dev_err(dev, "no memory for framebuffers\n");
+               return -ENOMEM;
+       }
+
+       sfb->dev = dev;
+       sfb->pdata = pd;
+
+       sfb->bus_clk = clk_get(dev, "lcd");
+       if (IS_ERR(sfb->bus_clk)) {
+               dev_err(dev, "failed to get bus clock\n");
+               goto err_sfb;
+       }
+
+       clk_enable(sfb->bus_clk);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "failed to find registers\n");
+               ret = -ENOENT;
+               goto err_clk;
+       }
+
+       sfb->regs_res = request_mem_region(res->start, resource_size(res),
+                                          dev_name(dev));
+       if (!sfb->regs_res) {
+               dev_err(dev, "failed to claim register region\n");
+               ret = -ENOENT;
+               goto err_clk;
+       }
+
+       sfb->regs = ioremap(res->start, resource_size(res));
+       if (!sfb->regs) {
+               dev_err(dev, "failed to map registers\n");
+               ret = -ENXIO;
+               goto err_req_region;
+       }
+
+       dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
+
+       /* setup gpio and output polarity controls */
+
+       pd->setup_gpio();
+
+       writel(pd->vidcon1, sfb->regs + VIDCON1);
+
+       /* zero all windows before we do anything */
+
+       for (win = 0; win < S3C_FB_MAX_WIN; win++)
+               s3c_fb_clear_win(sfb, win);
+
+       /* we have the register setup, start allocating framebuffers */
+
+       for (win = 0; win < S3C_FB_MAX_WIN; win++) {
+               if (!pd->win[win])
+                       continue;
+
+               ret = s3c_fb_probe_win(sfb, win, &sfb->windows[win]);
+               if (ret < 0) {
+                       dev_err(dev, "failed to create window %d\n", win);
+                       for (; win >= 0; win--)
+                               s3c_fb_release_win(sfb, sfb->windows[win]);
+                       goto err_ioremap;
+               }
+       }
+
+       platform_set_drvdata(pdev, sfb);
+
+       return 0;
+
+err_ioremap:
+       iounmap(sfb->regs);
+
+err_req_region:
+       release_resource(sfb->regs_res);
+       kfree(sfb->regs_res);
+
+err_clk:
+       clk_disable(sfb->bus_clk);
+       clk_put(sfb->bus_clk);
+
+err_sfb:
+       kfree(sfb);
+       return ret;
+}
+
+/**
+ * s3c_fb_remove() - Cleanup on module finalisation
+ * @pdev: The platform device we are bound to.
+ *
+ * Shutdown and then release all the resources that the driver allocated
+ * on initialisation.
+ */
+static int __devexit s3c_fb_remove(struct platform_device *pdev)
+{
+       struct s3c_fb *sfb = platform_get_drvdata(pdev);
+       int win;
+
+       for (win = 0; win <= S3C_FB_MAX_WIN; win++)
+               s3c_fb_release_win(sfb, sfb->windows[win]);
+
+       iounmap(sfb->regs);
+
+       clk_disable(sfb->bus_clk);
+       clk_put(sfb->bus_clk);
+
+       release_resource(sfb->regs_res);
+       kfree(sfb->regs_res);
+
+       kfree(sfb);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c_fb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct s3c_fb *sfb = platform_get_drvdata(pdev);
+       struct s3c_fb_win *win;
+       int win_no;
+
+       for (win_no = S3C_FB_MAX_WIN; win_no >= 0; win_no--) {
+               win = sfb->windows[win_no];
+               if (!win)
+                       continue;
+
+               /* use the blank function to push into power-down */
+               s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
+       }
+
+       clk_disable(sfb->bus_clk);
+       return 0;
+}
+
+static int s3c_fb_resume(struct platform_device *pdev)
+{
+       struct s3c_fb *sfb = platform_get_drvdata(pdev);
+       struct s3c_fb_win *win;
+       int win_no;
+
+       clk_enable(sfb->bus_clk);
+
+       for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
+               win = sfb->windows[win_no];
+               if (!win)
+                       continue;
+
+               dev_dbg(&pdev->dev, "resuming window %d\n", win_no);
+               s3c_fb_set_par(win->fbinfo);
+       }
+
+       return 0;
+}
+#else
+#define s3c_fb_suspend NULL
+#define s3c_fb_resume  NULL
+#endif
+
+static struct platform_driver s3c_fb_driver = {
+       .probe          = s3c_fb_probe,
+       .remove         = s3c_fb_remove,
+       .suspend        = s3c_fb_suspend,
+       .resume         = s3c_fb_resume,
+       .driver         = {
+               .name   = "s3c-fb",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init s3c_fb_init(void)
+{
+       return platform_driver_register(&s3c_fb_driver);
+}
+
+static void __exit s3c_fb_cleanup(void)
+{
+       platform_driver_unregister(&s3c_fb_driver);
+}
+
+module_init(s3c_fb_init);
+module_exit(s3c_fb_cleanup);
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c-fb");
index f5252c2552fdd482731eef311f3f4ff14a70f03d..bba53714a7b13188796c72ace46b692a5b53cfea 100644 (file)
@@ -837,6 +837,8 @@ static int sgivwfb_remove(struct platform_device *dev)
                iounmap(par->regs);
                iounmap(info->screen_base);
                release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE);
+               fb_dealloc_cmap(&info->cmap);
+               framebuffer_release(info);
        }
        return 0;
 }
index df5336561d1304d4e35c586fead0d6942d9892cf..a439159204a8490fe79e2e0bebae3f9b47167481 100644 (file)
@@ -795,8 +795,9 @@ static int __devinit xxxfb_probe(struct pci_dev *dev,
     if (!retval || retval == 4)
        return -EINVAL;                 
 
-    /* This has to been done !!! */    
-    fb_alloc_cmap(&info->cmap, cmap_len, 0);
+    /* This has to be done! */
+    if (fb_alloc_cmap(&info->cmap, cmap_len, 0))
+       return -ENOMEM;
        
     /* 
      * The following is done in the case of having hardware with a static 
@@ -820,8 +821,10 @@ static int __devinit xxxfb_probe(struct pci_dev *dev,
      */
     /* xxxfb_set_par(info); */
 
-    if (register_framebuffer(info) < 0)
+    if (register_framebuffer(info) < 0) {
+       fb_dealloc_cmap(&info->cmap);
        return -EINVAL;
+    }
     printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
           info->fix.id);
     pci_set_drvdata(dev, info); /* or platform_set_drvdata(pdev, info) */
index dcd98793d5681e14e7521e1f9efcf92806fe4f8b..eb5d73a0670244cee172b1d31aa028a1a86ff8f4 100644 (file)
@@ -1525,7 +1525,10 @@ static int sm501fb_init_fb(struct fb_info *fb,
        }
 
        /* initialise and set the palette */
-       fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0);
+       if (fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0)) {
+               dev_err(info->dev, "failed to allocate cmap memory\n");
+               return -ENOMEM;
+       }
        fb_set_cmap(&fb->cmap, fb);
 
        ret = (fb->fbops->fb_check_var)(&fb->var, fb);
index 5b11a00f49bc3708fbcc9d7b4866424c1539776f..609d0a521ca2df96d064efe7f71dcbd46fb21541 100644 (file)
@@ -1421,13 +1421,16 @@ static int __devinit sstfb_probe(struct pci_dev *pdev,
                goto fail;
        }
        
-       fb_alloc_cmap(&info->cmap, 256, 0);
+       if (fb_alloc_cmap(&info->cmap, 256, 0)) {
+               printk(KERN_ERR "sstfb: can't alloc cmap memory.\n");
+               goto fail;
+       }
 
        /* register fb */
        info->device = &pdev->dev;
        if (register_framebuffer(info) < 0) {
                printk(KERN_ERR "sstfb: can't register framebuffer.\n");
-               goto fail;
+               goto fail_register;
        }
 
        sstfb_clear_screen(info);
@@ -1441,8 +1444,9 @@ static int __devinit sstfb_probe(struct pci_dev *pdev,
 
        return 0;
 
-fail:
+fail_register:
        fb_dealloc_cmap(&info->cmap);
+fail:
        iounmap(info->screen_base);
 fail_fb_remap:
        iounmap(par->mmio_vbase);
index 166481402412538fc2b778924524ff67ae3fe9a6..eabaad765aebcdf1e975c8d68108e098a330175d 100644 (file)
@@ -1262,24 +1262,25 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
        info->flags = FBINFO_DEFAULT;
        info->pseudo_palette = &fb->pseudo_palette;
 
-       /* This has to been done !!! */
-       fb_alloc_cmap(&info->cmap, NR_PALETTE, 0);
+       /* This has to be done !!! */
+       if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0))
+               goto out_err1;
        stifb_init_display(fb);
 
        if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
                printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
                                fix->smem_start, fix->smem_start+fix->smem_len);
-               goto out_err1;
+               goto out_err2;
        }
                
        if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
                printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
                                fix->mmio_start, fix->mmio_start+fix->mmio_len);
-               goto out_err2;
+               goto out_err3;
        }
 
        if (register_framebuffer(&fb->info) < 0)
-               goto out_err3;
+               goto out_err4;
 
        sti->info = info; /* save for unregister_framebuffer() */
 
@@ -1297,13 +1298,14 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
        return 0;
 
 
-out_err3:
+out_err4:
        release_mem_region(fix->mmio_start, fix->mmio_len);
-out_err2:
+out_err3:
        release_mem_region(fix->smem_start, fix->smem_len);
+out_err2:
+       fb_dealloc_cmap(&info->cmap);
 out_err1:
        iounmap(info->screen_base);
-       fb_dealloc_cmap(&info->cmap);
 out_err0:
        kfree(fb);
        return -ENXIO;
index c2ba51b7ea18af54dd9be3d0a6b25b90cf93edae..18b950706cad47f70ee83282a7cb7d905d902ef6 100644 (file)
@@ -349,11 +349,14 @@ static int __devinit e3d_pci_register(struct pci_dev *pdev,
        if (err < 0) {
                printk(KERN_ERR "e3d: Could not register framebuffer %s\n",
                       pci_name(pdev));
-               goto err_unmap_fb;
+               goto err_free_cmap;
        }
 
        return 0;
 
+err_free_cmap:
+       fb_dealloc_cmap(&info->cmap);
+
 err_unmap_fb:
        iounmap(ep->fb_base);
 
@@ -389,6 +392,7 @@ static void __devexit e3d_pci_unregister(struct pci_dev *pdev)
        pci_release_region(pdev, 0);
        pci_release_region(pdev, 1);
 
+       fb_dealloc_cmap(&info->cmap);
         framebuffer_release(info);
 
        pci_disable_device(pdev);
index 14bd3f3680b8e549d6662e4d5779b8b259886a05..ee64771fbe3dd0dee90f15664606901884b85245 100644 (file)
@@ -1393,6 +1393,7 @@ static void __devexit tdfxfb_remove(struct pci_dev *pdev)
        release_mem_region(pci_resource_start(pdev, 0),
                           pci_resource_len(pdev, 0));
        pci_set_drvdata(pdev, NULL);
+       fb_dealloc_cmap(&info->cmap);
        framebuffer_release(info);
 }
 
index 680642c089c9202b64f57f103e264b5ebc035609..a86046ff60ad527f7f10cf16a0451df33abc45a2 100644 (file)
@@ -1663,7 +1663,7 @@ tgafb_register(struct device *dev)
        if (register_framebuffer(info) < 0) {
                printk(KERN_ERR "tgafb: Could not register framebuffer\n");
                ret = -EINVAL;
-               goto err1;
+               goto err2;
        }
 
        if (tga_bus_pci) {
@@ -1682,6 +1682,8 @@ tgafb_register(struct device *dev)
 
        return 0;
 
+ err2:
+       fb_dealloc_cmap(&info->cmap);
  err1:
        if (mem_base)
                iounmap(mem_base);
index 479b2e79ad68ea569882bf7ce7df7645d648a02d..03a9c35e9f552a951ff9ed6798536633d515e020 100644 (file)
@@ -2,7 +2,7 @@
  * Frame buffer driver for Trident TGUI, Blade and Image series
  *
  * Copyright 2001, 2002 - Jani Monoses   <jani@iv.ro>
- *
+ * Copyright 2009 Krzysztof Helt <krzysztof.h1@wp.pl>
  *
  * CREDITS:(in order of appearance)
  *     skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video
@@ -490,7 +490,6 @@ static void tgui_copy_rect(struct tridentfb_par *par,
 /*
  * Accel functions called by the upper layers
  */
-#ifdef CONFIG_FB_TRIDENT_ACCEL
 static void tridentfb_fillrect(struct fb_info *info,
                               const struct fb_fillrect *fr)
 {
@@ -565,11 +564,6 @@ static int tridentfb_sync(struct fb_info *info)
                par->wait_engine(par);
        return 0;
 }
-#else
-#define tridentfb_fillrect cfb_fillrect
-#define tridentfb_copyarea cfb_copyarea
-#define tridentfb_imageblit cfb_imageblit
-#endif /* CONFIG_FB_TRIDENT_ACCEL */
 
 /*
  * Hardware access functions
@@ -1333,9 +1327,7 @@ static struct fb_ops tridentfb_ops = {
        .fb_fillrect = tridentfb_fillrect,
        .fb_copyarea = tridentfb_copyarea,
        .fb_imageblit = tridentfb_imageblit,
-#ifdef CONFIG_FB_TRIDENT_ACCEL
        .fb_sync = tridentfb_sync,
-#endif
 };
 
 static int __devinit trident_pci_probe(struct pci_dev *dev,
@@ -1359,10 +1351,6 @@ static int __devinit trident_pci_probe(struct pci_dev *dev,
 
        chip_id = id->device;
 
-#ifndef CONFIG_FB_TRIDENT_ACCEL
-       noaccel = 1;
-#endif
-
        /* If PCI id is 0x9660 then further detect chip type */
 
        if (chip_id == TGUI9660) {
@@ -1490,6 +1478,9 @@ static int __devinit trident_pci_probe(struct pci_dev *dev,
        } else
                info->flags |= FBINFO_HWACCEL_DISABLED;
 
+       if (is_blade(chip_id) && chip_id != BLADE3D)
+               info->flags |= FBINFO_READS_FAST;
+
        info->pixmap.addr = kmalloc(4096, GFP_KERNEL);
        if (!info->pixmap.addr) {
                err = -ENOMEM;
@@ -1563,6 +1554,7 @@ static void __devexit trident_pci_remove(struct pci_dev *dev)
        release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
        pci_set_drvdata(dev, NULL);
        kfree(info->pixmap.addr);
+       fb_dealloc_cmap(&info->cmap);
        framebuffer_release(info);
 }
 
@@ -1663,4 +1655,5 @@ module_exit(tridentfb_exit);
 MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
 MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("cyblafb");
 
index 74ae75899009fe3ad831c37ec14868d467b97ad7..0b370aebdbfd24d528cab7442d1983801b36b7c5 100644 (file)
@@ -189,7 +189,7 @@ static int uvesafb_exec(struct uvesafb_ktask *task)
        uvfb_tasks[seq] = task;
        mutex_unlock(&uvfb_lock);
 
-       err = cn_netlink_send(m, 0, gfp_any());
+       err = cn_netlink_send(m, 0, GFP_KERNEL);
        if (err == -ESRCH) {
                /*
                 * Try to start the userspace helper if sending
@@ -850,14 +850,16 @@ static int __devinit uvesafb_vbe_init_mode(struct fb_info *info)
        if (vbemode) {
                for (i = 0; i < par->vbe_modes_cnt; i++) {
                        if (par->vbe_modes[i].mode_id == vbemode) {
+                               modeid = i;
+                               uvesafb_setup_var(&info->var, info,
+                                               &par->vbe_modes[modeid]);
                                fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,
-                                                       &info->var, info);
+                                               &info->var, info);
                                /*
                                 * With pixclock set to 0, the default BIOS
                                 * timings will be used in set_par().
                                 */
                                info->var.pixclock = 0;
-                               modeid = i;
                                goto gotmode;
                        }
                }
@@ -904,8 +906,11 @@ static int __devinit uvesafb_vbe_init_mode(struct fb_info *info)
                        fb_videomode_to_var(&info->var, mode);
                } else {
                        modeid = par->vbe_modes[0].mode_id;
+                       uvesafb_setup_var(&info->var, info,
+                                       &par->vbe_modes[modeid]);
                        fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,
-                                   &info->var, info);
+                                       &info->var, info);
+
                        goto gotmode;
                }
        }
@@ -917,9 +922,9 @@ static int __devinit uvesafb_vbe_init_mode(struct fb_info *info)
        if (modeid == -1)
                return -EINVAL;
 
-gotmode:
        uvesafb_setup_var(&info->var, info, &par->vbe_modes[modeid]);
 
+gotmode:
        /*
         * If we are not VBE3.0+ compliant, we're done -- the BIOS will
         * ignore our timings anyway.
@@ -1552,7 +1557,7 @@ static void __devinit uvesafb_init_info(struct fb_info *info,
        }
 
        info->flags = FBINFO_FLAG_DEFAULT |
-                       (par->ypan) ? FBINFO_HWACCEL_YPAN : 0;
+                       (par->ypan ? FBINFO_HWACCEL_YPAN : 0);
 
        if (!par->ypan)
                info->fbops->fb_pan_display = NULL;
index 7b0cef9ca8f98d52fcc927050204f1ec874194b8..4bb9a0b18950028b21546eb443ac9f215bf97f8e 100644 (file)
@@ -119,7 +119,7 @@ static void set_valkyrie_clock(unsigned char *params);
 static int valkyrie_var_to_par(struct fb_var_screeninfo *var,
        struct fb_par_valkyrie *par, const struct fb_info *fb_info);
 
-static void valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p);
+static int valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p);
 static void valkyrie_par_to_fix(struct fb_par_valkyrie *par, struct fb_fix_screeninfo *fix);
 static void valkyrie_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p);
 
@@ -381,18 +381,22 @@ int __init valkyriefb_init(void)
 
        valkyrie_choose_mode(p);
        mac_vmode_to_var(default_vmode, default_cmode, &p->info.var);
-       valkyrie_init_info(&p->info, p);
+       err = valkyrie_init_info(&p->info, p);
+       if (err < 0)
+               goto out_free;
        valkyrie_init_fix(&p->info.fix, p);
        if (valkyriefb_set_par(&p->info))
                /* "can't happen" */
                printk(KERN_ERR "valkyriefb: can't set default video mode\n");
 
        if ((err = register_framebuffer(&p->info)) != 0)
-               goto out_free;
+               goto out_cmap_free;
 
        printk(KERN_INFO "fb%d: valkyrie frame buffer device\n", p->info.node);
        return 0;
 
+ out_cmap_free:
+       fb_dealloc_cmap(&p->info.cmap);
  out_free:
        if (p->frame_buffer)
                iounmap(p->frame_buffer);
@@ -538,14 +542,15 @@ static void valkyrie_par_to_fix(struct fb_par_valkyrie *par,
                /* ywrapstep, xpanstep, ypanstep */
 }
 
-static void __init valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p)
+static int __init valkyrie_init_info(struct fb_info *info,
+               struct fb_info_valkyrie *p)
 {
        info->fbops = &valkyriefb_ops;
        info->screen_base = p->frame_buffer + 0x1000;
        info->flags = FBINFO_DEFAULT;
        info->pseudo_palette = p->pseudo_palette;
-       fb_alloc_cmap(&info->cmap, 256, 0);
        info->par = &p->par;
+       return fb_alloc_cmap(&info->cmap, 256, 0);
 }
 
 
index e16322d157d0b9446a9e9cf6d0c2a99cc2898c7e..d6856f43d241df13d14ab43113c9472387ecbdef 100644 (file)
@@ -438,7 +438,7 @@ static int __init vesafb_probe(struct platform_device *dev)
        info->var = vesafb_defined;
        info->fix = vesafb_fix;
        info->flags = FBINFO_FLAG_DEFAULT |
-               (ypan) ? FBINFO_HWACCEL_YPAN : 0;
+               (ypan ? FBINFO_HWACCEL_YPAN : 0);
 
        if (!ypan)
                info->fbops->fb_pan_display = NULL;
index 93fe08d6c78f6f2a36b84c8977ad95c2781ff6f1..cc919ae465711e17cee1648b61bb679576ed3242 100644 (file)
@@ -543,6 +543,7 @@ static int vfb_remove(struct platform_device *dev)
        if (info) {
                unregister_framebuffer(info);
                rvfree(videomemory, videomemorysize);
+               fb_dealloc_cmap(&info->cmap);
                framebuffer_release(info);
        }
        return 0;
index 632523ff1fb765178421c483313303551df7bc51..45c54bfe99bb86f68b94be7dc73879d50b78d74d 100644 (file)
@@ -267,13 +267,17 @@ int viafb_wait_engine_idle(void)
        int loop = 0;
 
        while (!(readl(viaparinfo->io_virt + VIA_REG_STATUS) &
-                       VIA_VR_QUEUE_BUSY) && (loop++ < MAXLOOP))
+                       VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) {
+               loop++;
                cpu_relax();
+       }
 
        while ((readl(viaparinfo->io_virt + VIA_REG_STATUS) &
                    (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) &&
-                   (loop++ < MAXLOOP))
+                   (loop < MAXLOOP)) {
+               loop++;
                cpu_relax();
+       }
 
        return loop >= MAXLOOP;
 }
index 37b433a08ce8fcaf893b47dcff8719ae4d4d6033..e327b84820d28fdb96c6eab1d74b2a08e78e67ab 100644 (file)
@@ -2059,25 +2059,21 @@ static void viafb_init_proc(struct proc_dir_entry **viafb_entry)
        if (viafb_entry) {
                entry = create_proc_entry("dvp0", 0, *viafb_entry);
                if (entry) {
-                       entry->owner = THIS_MODULE;
                        entry->read_proc = viafb_dvp0_proc_read;
                        entry->write_proc = viafb_dvp0_proc_write;
                }
                entry = create_proc_entry("dvp1", 0, *viafb_entry);
                if (entry) {
-                       entry->owner = THIS_MODULE;
                        entry->read_proc = viafb_dvp1_proc_read;
                        entry->write_proc = viafb_dvp1_proc_write;
                }
                entry = create_proc_entry("dfph", 0, *viafb_entry);
                if (entry) {
-                       entry->owner = THIS_MODULE;
                        entry->read_proc = viafb_dfph_proc_read;
                        entry->write_proc = viafb_dfph_proc_write;
                }
                entry = create_proc_entry("dfpl", 0, *viafb_entry);
                if (entry) {
-                       entry->owner = THIS_MODULE;
                        entry->read_proc = viafb_dfpl_proc_read;
                        entry->write_proc = viafb_dfpl_proc_write;
                }
@@ -2086,7 +2082,6 @@ static void viafb_init_proc(struct proc_dir_entry **viafb_entry)
                    viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
                        entry = create_proc_entry("vt1636", 0, *viafb_entry);
                        if (entry) {
-                               entry->owner = THIS_MODULE;
                                entry->read_proc = viafb_vt1636_proc_read;
                                entry->write_proc = viafb_vt1636_proc_write;
                        }
index 5777196bf6c9cc873ef07dd6e79eb10f1775379b..5c52369ab9bb81115376ec3e8b959908bdbe8d8f 100644 (file)
 
 #ifdef DEBUG
 /* For development, we want to crash whenever the ring is screwed. */
-#define BAD_RING(vq, fmt...)                   \
-       do { dev_err(&vq->vq.vdev->dev, fmt); BUG(); } while(0)
-#define START_USE(vq) \
-       do { if ((vq)->in_use) panic("in_use = %i\n", (vq)->in_use); (vq)->in_use = __LINE__; mb(); } while(0)
-#define END_USE(vq) \
-       do { BUG_ON(!(vq)->in_use); (vq)->in_use = 0; mb(); } while(0)
+#define BAD_RING(_vq, fmt...)                  \
+       do { dev_err(&(_vq)->vq.vdev->dev, fmt); BUG(); } while(0)
+/* Caller is supposed to guarantee no reentry. */
+#define START_USE(_vq)                                         \
+       do {                                                    \
+               if ((_vq)->in_use)                              \
+                       panic("in_use = %i\n", (_vq)->in_use);  \
+               (_vq)->in_use = __LINE__;                       \
+               mb();                                           \
+       } while(0)
+#define END_USE(_vq) \
+       do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; mb(); } while(0)
 #else
-#define BAD_RING(vq, fmt...)                   \
-       do { dev_err(&vq->vq.vdev->dev, fmt); (vq)->broken = true; } while(0)
+#define BAD_RING(_vq, fmt...)                  \
+       do { dev_err(&_vq->vq.vdev->dev, fmt); (_vq)->broken = true; } while(0)
 #define START_USE(vq)
 #define END_USE(vq)
 #endif
index 442bd8bbd4a5dcbed086cae48fed1350ba9e31b6..3ebe9726a9e55471ae9383fe262fc61de2727200 100644 (file)
@@ -69,7 +69,7 @@ static u8 w1_touch_bit(struct w1_master *dev, int bit)
                return w1_read_bit(dev);
        else {
                w1_write_bit(dev, 0);
-               return(0);
+               return 0;
        }
 }
 
@@ -184,17 +184,17 @@ static u8 w1_read_bit(struct w1_master *dev)
  */
 u8 w1_triplet(struct w1_master *dev, int bdir)
 {
-       if ( dev->bus_master->triplet )
-               return(dev->bus_master->triplet(dev->bus_master->data, bdir));
+       if (dev->bus_master->triplet)
+               return dev->bus_master->triplet(dev->bus_master->data, bdir);
        else {
                u8 id_bit   = w1_touch_bit(dev, 1);
                u8 comp_bit = w1_touch_bit(dev, 1);
                u8 retval;
 
-               if ( id_bit && comp_bit )
-                       return(0x03);  /* error */
+               if (id_bit && comp_bit)
+                       return 0x03;  /* error */
 
-               if ( !id_bit && !comp_bit ) {
+               if (!id_bit && !comp_bit) {
                        /* Both bits are valid, take the direction given */
                        retval = bdir ? 0x04 : 0;
                } else {
@@ -203,11 +203,11 @@ u8 w1_triplet(struct w1_master *dev, int bdir)
                        retval = id_bit ? 0x05 : 0x02;
                }
 
-               if ( dev->bus_master->touch_bit )
+               if (dev->bus_master->touch_bit)
                        w1_touch_bit(dev, bdir);
                else
                        w1_write_bit(dev, bdir);
-               return(retval);
+               return retval;
        }
 }
 
index 55f64af072a430d4ce9337baa6b8dc6807ec3c4f..63024145215d729703961ee4c27fad4ab1d6226f 100644 (file)
@@ -772,7 +772,7 @@ config TXX9_WDT
 
 config GEF_WDT
        tristate "GE Fanuc Watchdog Timer"
-       depends on GEF_SBC610
+       depends on GEF_SBC610 || GEF_SBC310 || GEF_PPC9A
        ---help---
          Watchdog timer found in a number of GE Fanuc single board computers.
 
index 6cf155d6b350f1549aedca4dff0e3e6684a733d1..3137361ccbfe077eecfdfdaab61d4373224ed45c 100644 (file)
@@ -380,7 +380,7 @@ asm(".text                      \n\t"
  *     This function checks whether or not a SMBIOS/DMI record is
  *     the 64bit CRU info or not
  */
-static void __devinit dmi_find_cru(const struct dmi_header *dm)
+static void __devinit dmi_find_cru(const struct dmi_header *dm, void *dummy)
 {
        struct smbios_cru64_info *smbios_cru64_ptr;
        unsigned long cru_physical_address;
@@ -403,7 +403,7 @@ static int __devinit detect_cru_service(void)
 {
        cru_rom_addr = NULL;
 
-       dmi_walk(dmi_find_cru);
+       dmi_walk(dmi_find_cru, NULL);
 
        /* if cru_rom_addr has been set then we found a CRU service */
        return ((cru_rom_addr != NULL) ? 0 : -ENODEV);
index 3ccd348d112d62036f4e63a038d23deca7ed67f7..0d61db1e7b49bc5f5fd095795e74001dadda1bc3 100644 (file)
@@ -39,12 +39,6 @@ static int xen_suspend(void *data)
 
        BUG_ON(!irqs_disabled());
 
-       err = device_power_down(PMSG_SUSPEND);
-       if (err) {
-               printk(KERN_ERR "xen_suspend: device_power_down failed: %d\n",
-                      err);
-               return err;
-       }
        err = sysdev_suspend(PMSG_SUSPEND);
        if (err) {
                printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
@@ -69,7 +63,6 @@ static int xen_suspend(void *data)
        xen_mm_unpin_all();
 
        sysdev_resume();
-       device_power_up(PMSG_RESUME);
 
        if (!*cancelled) {
                xen_irq_resume();
@@ -108,6 +101,12 @@ static void do_suspend(void)
        /* XXX use normal device tree? */
        xenbus_suspend();
 
+       err = device_power_down(PMSG_SUSPEND);
+       if (err) {
+               printk(KERN_ERR "device_power_down failed: %d\n", err);
+               goto resume_devices;
+       }
+
        err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
        if (err) {
                printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
@@ -120,6 +119,9 @@ static void do_suspend(void)
        } else
                xenbus_suspend_cancel();
 
+       device_power_up(PMSG_RESUME);
+
+resume_devices:
        device_resume(PMSG_RESUME);
 
        /* Make sure timer events get retriggered on all CPUs */
index 7f83a46f2b7e45502e7c761775f96498280a32e5..dd9becca4241bd20a01706e3e18cb9c47109cbe1 100644 (file)
@@ -219,16 +219,20 @@ static int adfs_remount(struct super_block *sb, int *flags, char *data)
 
 static int adfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
-       struct adfs_sb_info *asb = ADFS_SB(dentry->d_sb);
+       struct super_block *sb = dentry->d_sb;
+       struct adfs_sb_info *sbi = ADFS_SB(sb);
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type    = ADFS_SUPER_MAGIC;
-       buf->f_namelen = asb->s_namelen;
-       buf->f_bsize   = dentry->d_sb->s_blocksize;
-       buf->f_blocks  = asb->s_size;
-       buf->f_files   = asb->s_ids_per_zone * asb->s_map_size;
+       buf->f_namelen = sbi->s_namelen;
+       buf->f_bsize   = sb->s_blocksize;
+       buf->f_blocks  = sbi->s_size;
+       buf->f_files   = sbi->s_ids_per_zone * sbi->s_map_size;
        buf->f_bavail  =
-       buf->f_bfree   = adfs_map_free(dentry->d_sb);
+       buf->f_bfree   = adfs_map_free(sb);
        buf->f_ffree   = (long)(buf->f_bfree * buf->f_files) / (long)buf->f_blocks;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
 
        return 0;
 }
index a19d64b582aac0e2882610b3a5839d88e0bd329d..5ce695e707fe1054617a6a1664579eceb78b3790 100644 (file)
@@ -533,6 +533,7 @@ affs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
        int              free;
+       u64              id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",AFFS_SB(sb)->s_partition_size,
             AFFS_SB(sb)->s_reserved);
@@ -543,6 +544,9 @@ affs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_blocks  = AFFS_SB(sb)->s_partition_size - AFFS_SB(sb)->s_reserved;
        buf->f_bfree   = free;
        buf->f_bavail  = free;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
+       buf->f_namelen = 30;
        return 0;
 }
 
index 7578c1ab9e0be9ec3260c4cce41b78287f213bce..8630615e57fe512ca9c7a10472ce5f959f317234 100644 (file)
@@ -146,7 +146,6 @@ int afs_proc_init(void)
        proc_afs = proc_mkdir("fs/afs", NULL);
        if (!proc_afs)
                goto error_dir;
-       proc_afs->owner = THIS_MODULE;
 
        p = proc_create("cells", 0, proc_afs, &afs_proc_cells_fops);
        if (!p)
index a76803108d06fe58ce8b2a99d24bdae9f3e5004f..b7ff33c63101545c17410c220a2e6c0f5ab51994 100644 (file)
@@ -186,6 +186,8 @@ int autofs4_expire_wait(struct dentry *dentry);
 int autofs4_expire_run(struct super_block *, struct vfsmount *,
                        struct autofs_sb_info *,
                        struct autofs_packet_expire __user *);
+int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
+                           struct autofs_sb_info *sbi, int when);
 int autofs4_expire_multi(struct super_block *, struct vfsmount *,
                        struct autofs_sb_info *, int __user *);
 struct dentry *autofs4_expire_direct(struct super_block *sb,
index 025e105bffea984495c1861aa00e731d979b6c4a..9e5ae8a4f5c867bf1ddb81525cd260028d8d3c9e 100644 (file)
@@ -525,40 +525,13 @@ static int autofs_dev_ioctl_expire(struct file *fp,
                                   struct autofs_sb_info *sbi,
                                   struct autofs_dev_ioctl *param)
 {
-       struct dentry *dentry;
        struct vfsmount *mnt;
-       int err = -EAGAIN;
        int how;
 
        how = param->expire.how;
        mnt = fp->f_path.mnt;
 
-       if (autofs_type_trigger(sbi->type))
-               dentry = autofs4_expire_direct(sbi->sb, mnt, sbi, how);
-       else
-               dentry = autofs4_expire_indirect(sbi->sb, mnt, sbi, how);
-
-       if (dentry) {
-               struct autofs_info *ino = autofs4_dentry_ino(dentry);
-
-               /*
-                * This is synchronous because it makes the daemon a
-                * little easier
-               */
-               err = autofs4_wait(sbi, dentry, NFY_EXPIRE);
-
-               spin_lock(&sbi->fs_lock);
-               if (ino->flags & AUTOFS_INF_MOUNTPOINT) {
-                       ino->flags &= ~AUTOFS_INF_MOUNTPOINT;
-                       sbi->sb->s_root->d_mounted++;
-               }
-               ino->flags &= ~AUTOFS_INF_EXPIRING;
-               complete_all(&ino->expire_complete);
-               spin_unlock(&sbi->fs_lock);
-               dput(dentry);
-       }
-
-       return err;
+       return autofs4_do_expire_multi(sbi->sb, mnt, sbi, how);
 }
 
 /* Check if autofs mount point is in use */
index e3bd50776f9e4f9997d21940c11cd99acd855263..75f7ddacf7d6d0575577e6172185fdc32d5f12ee 100644 (file)
@@ -478,22 +478,16 @@ int autofs4_expire_run(struct super_block *sb,
        return ret;
 }
 
-/* Call repeatedly until it returns -EAGAIN, meaning there's nothing
-   more to be done */
-int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
-                       struct autofs_sb_info *sbi, int __user *arg)
+int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
+                           struct autofs_sb_info *sbi, int when)
 {
        struct dentry *dentry;
        int ret = -EAGAIN;
-       int do_now = 0;
-
-       if (arg && get_user(do_now, arg))
-               return -EFAULT;
 
        if (autofs_type_trigger(sbi->type))
-               dentry = autofs4_expire_direct(sb, mnt, sbi, do_now);
+               dentry = autofs4_expire_direct(sb, mnt, sbi, when);
        else
-               dentry = autofs4_expire_indirect(sb, mnt, sbi, do_now);
+               dentry = autofs4_expire_indirect(sb, mnt, sbi, when);
 
        if (dentry) {
                struct autofs_info *ino = autofs4_dentry_ino(dentry);
@@ -516,3 +510,16 @@ int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
        return ret;
 }
 
+/* Call repeatedly until it returns -EAGAIN, meaning there's nothing
+   more to be done */
+int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
+                       struct autofs_sb_info *sbi, int __user *arg)
+{
+       int do_now = 0;
+
+       if (arg && get_user(do_now, arg))
+               return -EFAULT;
+
+       return autofs4_do_expire_multi(sb, mnt, sbi, do_now);
+}
+
index 74b1469a950452ba86f661b79c1390d03c464857..e383bf0334f173c8c0a381ef2b2c50964931c62c 100644 (file)
@@ -485,22 +485,6 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
        DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d",
                 current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode);
 
-       expiring = autofs4_lookup_expiring(sbi, dentry->d_parent, &dentry->d_name);
-       if (expiring) {
-               /*
-                * If we are racing with expire the request might not
-                * be quite complete but the directory has been removed
-                * so it must have been successful, so just wait for it.
-                */
-               ino = autofs4_dentry_ino(expiring);
-               autofs4_expire_wait(expiring);
-               spin_lock(&sbi->lookup_lock);
-               if (!list_empty(&ino->expiring))
-                       list_del_init(&ino->expiring);
-               spin_unlock(&sbi->lookup_lock);
-               dput(expiring);
-       }
-
        unhashed = autofs4_lookup_active(sbi, dentry->d_parent, &dentry->d_name);
        if (unhashed)
                dentry = unhashed;
@@ -538,14 +522,31 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
        }
 
        if (!oz_mode) {
+               mutex_unlock(&dir->i_mutex);
+               expiring = autofs4_lookup_expiring(sbi,
+                                                  dentry->d_parent,
+                                                  &dentry->d_name);
+               if (expiring) {
+                       /*
+                        * If we are racing with expire the request might not
+                        * be quite complete but the directory has been removed
+                        * so it must have been successful, so just wait for it.
+                        */
+                       ino = autofs4_dentry_ino(expiring);
+                       autofs4_expire_wait(expiring);
+                       spin_lock(&sbi->lookup_lock);
+                       if (!list_empty(&ino->expiring))
+                               list_del_init(&ino->expiring);
+                       spin_unlock(&sbi->lookup_lock);
+                       dput(expiring);
+               }
+
                spin_lock(&dentry->d_lock);
                dentry->d_flags |= DCACHE_AUTOFS_PENDING;
                spin_unlock(&dentry->d_lock);
-               if (dentry->d_op && dentry->d_op->d_revalidate) {
-                       mutex_unlock(&dir->i_mutex);
+               if (dentry->d_op && dentry->d_op->d_revalidate)
                        (dentry->d_op->d_revalidate)(dentry, nd);
-                       mutex_lock(&dir->i_mutex);
-               }
+               mutex_lock(&dir->i_mutex);
        }
 
        /*
index d06cb023ad028a000a2f41db1208fa46991d7f47..76afd0d6b86c93e44ffb1cdf6d67616b57086822 100644 (file)
@@ -900,6 +900,7 @@ static int
 befs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        befs_debug(sb, "---> befs_statfs()");
 
@@ -910,6 +911,8 @@ befs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bavail = buf->f_bfree;
        buf->f_files = 0;       /* UNKNOWN */
        buf->f_ffree = 0;       /* UNKNOWN */
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = BEFS_NAME_LEN;
 
        befs_debug(sb, "<--- befs_statfs()");
index f3e72c5c19f56ec0deee0614e1a625df511a58e0..70cfc4b84ae0995a1d7c66d21ecd833a36b02e74 100644 (file)
@@ -972,9 +972,12 @@ static int elf_fdpic_map_file_constdisp_on_uclinux(
                        params->elfhdr_addr = seg->addr;
 
                /* clear any space allocated but not loaded */
-               if (phdr->p_filesz < phdr->p_memsz)
-                       clear_user((void *) (seg->addr + phdr->p_filesz),
-                                  phdr->p_memsz - phdr->p_filesz);
+               if (phdr->p_filesz < phdr->p_memsz) {
+                       ret = clear_user((void *) (seg->addr + phdr->p_filesz),
+                                        phdr->p_memsz - phdr->p_filesz);
+                       if (ret)
+                               return ret;
+               }
 
                if (mm) {
                        if (phdr->p_flags & PF_X) {
@@ -1014,7 +1017,7 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
        struct elf32_fdpic_loadseg *seg;
        struct elf32_phdr *phdr;
        unsigned long load_addr, delta_vaddr;
-       int loop, dvset;
+       int loop, dvset, ret;
 
        load_addr = params->load_addr;
        delta_vaddr = 0;
@@ -1114,7 +1117,9 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
                 * PT_LOAD */
                if (prot & PROT_WRITE && disp > 0) {
                        kdebug("clear[%d] ad=%lx sz=%lx", loop, maddr, disp);
-                       clear_user((void __user *) maddr, disp);
+                       ret = clear_user((void __user *) maddr, disp);
+                       if (ret)
+                               return ret;
                        maddr += disp;
                }
 
@@ -1149,15 +1154,19 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
                if (prot & PROT_WRITE && excess1 > 0) {
                        kdebug("clear[%d] ad=%lx sz=%lx",
                               loop, maddr + phdr->p_filesz, excess1);
-                       clear_user((void __user *) maddr + phdr->p_filesz,
-                                  excess1);
+                       ret = clear_user((void __user *) maddr + phdr->p_filesz,
+                                        excess1);
+                       if (ret)
+                               return ret;
                }
 
 #else
                if (excess > 0) {
                        kdebug("clear[%d] ad=%lx sz=%lx",
                               loop, maddr + phdr->p_filesz, excess);
-                       clear_user((void *) maddr + phdr->p_filesz, excess);
+                       ret = clear_user((void *) maddr + phdr->p_filesz, excess);
+                       if (ret)
+                               return ret;
                }
 #endif
 
index d2cf5a54a4b816d308ed7c452892fae27e009db1..9adf5e4f7e967b09045e8444c80dd819d72f3031 100644 (file)
@@ -8,7 +8,7 @@ btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
           extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
           extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
           ref-cache.o export.o tree-log.o acl.o free-space-cache.o zlib.o \
-          compression.o
+          compression.o delayed-ref.o
 else
 
 # Normal Makefile
index 72677ce2b74fc87b1ff6a277906492389085f687..b30986f00b9d7eebb9bfd50c93e86a9a34f329be 100644 (file)
@@ -66,6 +66,12 @@ struct btrfs_inode {
         */
        struct list_head delalloc_inodes;
 
+       /*
+        * list for tracking inodes that must be sent to disk before a
+        * rename or truncate commit
+        */
+       struct list_head ordered_operations;
+
        /* the space_info for where this inode's data allocations are done */
        struct btrfs_space_info *space_info;
 
@@ -86,12 +92,6 @@ struct btrfs_inode {
         */
        u64 logged_trans;
 
-       /*
-        * trans that last made a change that should be fully fsync'd.  This
-        * gets reset to zero each time the inode is logged
-        */
-       u64 log_dirty_trans;
-
        /* total number of bytes pending delalloc, used by stat to calc the
         * real block usage of the file
         */
@@ -121,6 +121,25 @@ struct btrfs_inode {
        /* the start of block group preferred for allocations. */
        u64 block_group;
 
+       /* the fsync log has some corner cases that mean we have to check
+        * directories to see if any unlinks have been done before
+        * the directory was logged.  See tree-log.c for all the
+        * details
+        */
+       u64 last_unlink_trans;
+
+       /*
+        * ordered_data_close is set by truncate when a file that used
+        * to have good data has been truncated to zero.  When it is set
+        * the btrfs file release call will add this inode to the
+        * ordered operations list so that we make sure to flush out any
+        * new data the application may have written before commit.
+        *
+        * yes, its silly to have a single bitflag, but we might grow more
+        * of these.
+        */
+       unsigned ordered_data_close:1;
+
        struct inode vfs_inode;
 };
 
index 37f31b5529aa0abe62a4e30ec7170c69c443eb0a..dbb7241246335373dde1fa8597744faec6748942 100644 (file)
@@ -254,18 +254,13 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
  * empty_size -- a hint that you plan on doing more cow.  This is the size in
  * bytes the allocator should try to find free next to the block it returns.
  * This is just a hint and may be ignored by the allocator.
- *
- * prealloc_dest -- if you have already reserved a destination for the cow,
- * this uses that block instead of allocating a new one.
- * btrfs_alloc_reserved_extent is used to finish the allocation.
  */
 static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             struct extent_buffer *buf,
                             struct extent_buffer *parent, int parent_slot,
                             struct extent_buffer **cow_ret,
-                            u64 search_start, u64 empty_size,
-                            u64 prealloc_dest)
+                            u64 search_start, u64 empty_size)
 {
        u64 parent_start;
        struct extent_buffer *cow;
@@ -291,26 +286,10 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
        level = btrfs_header_level(buf);
        nritems = btrfs_header_nritems(buf);
 
-       if (prealloc_dest) {
-               struct btrfs_key ins;
-
-               ins.objectid = prealloc_dest;
-               ins.offset = buf->len;
-               ins.type = BTRFS_EXTENT_ITEM_KEY;
-
-               ret = btrfs_alloc_reserved_extent(trans, root, parent_start,
-                                                 root->root_key.objectid,
-                                                 trans->transid, level, &ins);
-               BUG_ON(ret);
-               cow = btrfs_init_new_buffer(trans, root, prealloc_dest,
-                                           buf->len, level);
-       } else {
-               cow = btrfs_alloc_free_block(trans, root, buf->len,
-                                            parent_start,
-                                            root->root_key.objectid,
-                                            trans->transid, level,
-                                            search_start, empty_size);
-       }
+       cow = btrfs_alloc_free_block(trans, root, buf->len,
+                                    parent_start, root->root_key.objectid,
+                                    trans->transid, level,
+                                    search_start, empty_size);
        if (IS_ERR(cow))
                return PTR_ERR(cow);
 
@@ -413,7 +392,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
 noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
                    struct btrfs_root *root, struct extent_buffer *buf,
                    struct extent_buffer *parent, int parent_slot,
-                   struct extent_buffer **cow_ret, u64 prealloc_dest)
+                   struct extent_buffer **cow_ret)
 {
        u64 search_start;
        int ret;
@@ -436,7 +415,6 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
            btrfs_header_owner(buf) == root->root_key.objectid &&
            !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
                *cow_ret = buf;
-               WARN_ON(prealloc_dest);
                return 0;
        }
 
@@ -447,8 +425,7 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
        btrfs_set_lock_blocking(buf);
 
        ret = __btrfs_cow_block(trans, root, buf, parent,
-                                parent_slot, cow_ret, search_start, 0,
-                                prealloc_dest);
+                                parent_slot, cow_ret, search_start, 0);
        return ret;
 }
 
@@ -617,7 +594,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
                err = __btrfs_cow_block(trans, root, cur, parent, i,
                                        &cur, search_start,
                                        min(16 * blocksize,
-                                           (end_slot - i) * blocksize), 0);
+                                           (end_slot - i) * blocksize));
                if (err) {
                        btrfs_tree_unlock(cur);
                        free_extent_buffer(cur);
@@ -937,7 +914,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                BUG_ON(!child);
                btrfs_tree_lock(child);
                btrfs_set_lock_blocking(child);
-               ret = btrfs_cow_block(trans, root, child, mid, 0, &child, 0);
+               ret = btrfs_cow_block(trans, root, child, mid, 0, &child);
                BUG_ON(ret);
 
                spin_lock(&root->node_lock);
@@ -945,6 +922,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                spin_unlock(&root->node_lock);
 
                ret = btrfs_update_extent_ref(trans, root, child->start,
+                                             child->len,
                                              mid->start, child->start,
                                              root->root_key.objectid,
                                              trans->transid, level - 1);
@@ -971,6 +949,10 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
            BTRFS_NODEPTRS_PER_BLOCK(root) / 4)
                return 0;
 
+       if (trans->transaction->delayed_refs.flushing &&
+           btrfs_header_nritems(mid) > 2)
+               return 0;
+
        if (btrfs_header_nritems(mid) < 2)
                err_on_enospc = 1;
 
@@ -979,7 +961,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                btrfs_tree_lock(left);
                btrfs_set_lock_blocking(left);
                wret = btrfs_cow_block(trans, root, left,
-                                      parent, pslot - 1, &left, 0);
+                                      parent, pslot - 1, &left);
                if (wret) {
                        ret = wret;
                        goto enospc;
@@ -990,7 +972,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                btrfs_tree_lock(right);
                btrfs_set_lock_blocking(right);
                wret = btrfs_cow_block(trans, root, right,
-                                      parent, pslot + 1, &right, 0);
+                                      parent, pslot + 1, &right);
                if (wret) {
                        ret = wret;
                        goto enospc;
@@ -1171,7 +1153,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
                        wret = 1;
                } else {
                        ret = btrfs_cow_block(trans, root, left, parent,
-                                             pslot - 1, &left, 0);
+                                             pslot - 1, &left);
                        if (ret)
                                wret = 1;
                        else {
@@ -1222,7 +1204,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
                } else {
                        ret = btrfs_cow_block(trans, root, right,
                                              parent, pslot + 1,
-                                             &right, 0);
+                                             &right);
                        if (ret)
                                wret = 1;
                        else {
@@ -1492,7 +1474,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
        u8 lowest_level = 0;
        u64 blocknr;
        u64 gen;
-       struct btrfs_key prealloc_block;
 
        lowest_level = p->lowest_level;
        WARN_ON(lowest_level && ins_len > 0);
@@ -1501,8 +1482,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
        if (ins_len < 0)
                lowest_unlock = 2;
 
-       prealloc_block.objectid = 0;
-
 again:
        if (p->skip_locking)
                b = btrfs_root_node(root);
@@ -1529,44 +1508,11 @@ again:
                            !btrfs_header_flag(b, BTRFS_HEADER_FLAG_WRITTEN)) {
                                goto cow_done;
                        }
-
-                       /* ok, we have to cow, is our old prealloc the right
-                        * size?
-                        */
-                       if (prealloc_block.objectid &&
-                           prealloc_block.offset != b->len) {
-                               btrfs_release_path(root, p);
-                               btrfs_free_reserved_extent(root,
-                                          prealloc_block.objectid,
-                                          prealloc_block.offset);
-                               prealloc_block.objectid = 0;
-                               goto again;
-                       }
-
-                       /*
-                        * for higher level blocks, try not to allocate blocks
-                        * with the block and the parent locks held.
-                        */
-                       if (level > 0 && !prealloc_block.objectid) {
-                               u32 size = b->len;
-                               u64 hint = b->start;
-
-                               btrfs_release_path(root, p);
-                               ret = btrfs_reserve_extent(trans, root,
-                                                          size, size, 0,
-                                                          hint, (u64)-1,
-                                                          &prealloc_block, 0);
-                               BUG_ON(ret);
-                               goto again;
-                       }
-
                        btrfs_set_path_blocking(p);
 
                        wret = btrfs_cow_block(trans, root, b,
                                               p->nodes[level + 1],
-                                              p->slots[level + 1],
-                                              &b, prealloc_block.objectid);
-                       prealloc_block.objectid = 0;
+                                              p->slots[level + 1], &b);
                        if (wret) {
                                free_extent_buffer(b);
                                ret = wret;
@@ -1742,12 +1688,8 @@ done:
         * we don't really know what they plan on doing with the path
         * from here on, so for now just mark it as blocking
         */
-       btrfs_set_path_blocking(p);
-       if (prealloc_block.objectid) {
-               btrfs_free_reserved_extent(root,
-                          prealloc_block.objectid,
-                          prealloc_block.offset);
-       }
+       if (!p->leave_spinning)
+               btrfs_set_path_blocking(p);
        return ret;
 }
 
@@ -1768,7 +1710,7 @@ int btrfs_merge_path(struct btrfs_trans_handle *trans,
        int ret;
 
        eb = btrfs_lock_root_node(root);
-       ret = btrfs_cow_block(trans, root, eb, NULL, 0, &eb, 0);
+       ret = btrfs_cow_block(trans, root, eb, NULL, 0, &eb);
        BUG_ON(ret);
 
        btrfs_set_lock_blocking(eb);
@@ -1826,7 +1768,7 @@ int btrfs_merge_path(struct btrfs_trans_handle *trans,
                        }
 
                        ret = btrfs_cow_block(trans, root, eb, parent, slot,
-                                             &eb, 0);
+                                             &eb);
                        BUG_ON(ret);
 
                        if (root->root_key.objectid ==
@@ -2139,7 +2081,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
        spin_unlock(&root->node_lock);
 
        ret = btrfs_update_extent_ref(trans, root, lower->start,
-                                     lower->start, c->start,
+                                     lower->len, lower->start, c->start,
                                      root->root_key.objectid,
                                      trans->transid, level - 1);
        BUG_ON(ret);
@@ -2221,7 +2163,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
                ret = insert_new_root(trans, root, path, level + 1);
                if (ret)
                        return ret;
-       } else {
+       } else if (!trans->transaction->delayed_refs.flushing) {
                ret = push_nodes_for_insert(trans, root, path, level);
                c = path->nodes[level];
                if (!ret && btrfs_header_nritems(c) <
@@ -2329,66 +2271,27 @@ noinline int btrfs_leaf_free_space(struct btrfs_root *root,
        return ret;
 }
 
-/*
- * push some data in the path leaf to the right, trying to free up at
- * least data_size bytes.  returns zero if the push worked, nonzero otherwise
- *
- * returns 1 if the push failed because the other node didn't have enough
- * room, 0 if everything worked out and < 0 if there were major errors.
- */
-static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
-                          *root, struct btrfs_path *path, int data_size,
-                          int empty)
+static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
+                                     struct btrfs_root *root,
+                                     struct btrfs_path *path,
+                                     int data_size, int empty,
+                                     struct extent_buffer *right,
+                                     int free_space, u32 left_nritems)
 {
        struct extent_buffer *left = path->nodes[0];
-       struct extent_buffer *right;
-       struct extent_buffer *upper;
+       struct extent_buffer *upper = path->nodes[1];
        struct btrfs_disk_key disk_key;
        int slot;
        u32 i;
-       int free_space;
        int push_space = 0;
        int push_items = 0;
        struct btrfs_item *item;
-       u32 left_nritems;
        u32 nr;
        u32 right_nritems;
        u32 data_end;
        u32 this_item_size;
        int ret;
 
-       slot = path->slots[1];
-       if (!path->nodes[1])
-               return 1;
-
-       upper = path->nodes[1];
-       if (slot >= btrfs_header_nritems(upper) - 1)
-               return 1;
-
-       btrfs_assert_tree_locked(path->nodes[1]);
-
-       right = read_node_slot(root, upper, slot + 1);
-       btrfs_tree_lock(right);
-       btrfs_set_lock_blocking(right);
-
-       free_space = btrfs_leaf_free_space(root, right);
-       if (free_space < data_size)
-               goto out_unlock;
-
-       /* cow and double check */
-       ret = btrfs_cow_block(trans, root, right, upper,
-                             slot + 1, &right, 0);
-       if (ret)
-               goto out_unlock;
-
-       free_space = btrfs_leaf_free_space(root, right);
-       if (free_space < data_size)
-               goto out_unlock;
-
-       left_nritems = btrfs_header_nritems(left);
-       if (left_nritems == 0)
-               goto out_unlock;
-
        if (empty)
                nr = 0;
        else
@@ -2397,6 +2300,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
        if (path->slots[0] >= left_nritems)
                push_space += data_size;
 
+       slot = path->slots[1];
        i = left_nritems - 1;
        while (i >= nr) {
                item = btrfs_item_nr(left, i);
@@ -2527,25 +2431,83 @@ out_unlock:
        return 1;
 }
 
+/*
+ * push some data in the path leaf to the right, trying to free up at
+ * least data_size bytes.  returns zero if the push worked, nonzero otherwise
+ *
+ * returns 1 if the push failed because the other node didn't have enough
+ * room, 0 if everything worked out and < 0 if there were major errors.
+ */
+static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
+                          *root, struct btrfs_path *path, int data_size,
+                          int empty)
+{
+       struct extent_buffer *left = path->nodes[0];
+       struct extent_buffer *right;
+       struct extent_buffer *upper;
+       int slot;
+       int free_space;
+       u32 left_nritems;
+       int ret;
+
+       if (!path->nodes[1])
+               return 1;
+
+       slot = path->slots[1];
+       upper = path->nodes[1];
+       if (slot >= btrfs_header_nritems(upper) - 1)
+               return 1;
+
+       btrfs_assert_tree_locked(path->nodes[1]);
+
+       right = read_node_slot(root, upper, slot + 1);
+       btrfs_tree_lock(right);
+       btrfs_set_lock_blocking(right);
+
+       free_space = btrfs_leaf_free_space(root, right);
+       if (free_space < data_size)
+               goto out_unlock;
+
+       /* cow and double check */
+       ret = btrfs_cow_block(trans, root, right, upper,
+                             slot + 1, &right);
+       if (ret)
+               goto out_unlock;
+
+       free_space = btrfs_leaf_free_space(root, right);
+       if (free_space < data_size)
+               goto out_unlock;
+
+       left_nritems = btrfs_header_nritems(left);
+       if (left_nritems == 0)
+               goto out_unlock;
+
+       return __push_leaf_right(trans, root, path, data_size, empty,
+                               right, free_space, left_nritems);
+out_unlock:
+       btrfs_tree_unlock(right);
+       free_extent_buffer(right);
+       return 1;
+}
+
 /*
  * push some data in the path leaf to the left, trying to free up at
  * least data_size bytes.  returns zero if the push worked, nonzero otherwise
  */
-static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
-                         *root, struct btrfs_path *path, int data_size,
-                         int empty)
+static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
+                                    struct btrfs_root *root,
+                                    struct btrfs_path *path, int data_size,
+                                    int empty, struct extent_buffer *left,
+                                    int free_space, int right_nritems)
 {
        struct btrfs_disk_key disk_key;
        struct extent_buffer *right = path->nodes[0];
-       struct extent_buffer *left;
        int slot;
        int i;
-       int free_space;
        int push_space = 0;
        int push_items = 0;
        struct btrfs_item *item;
        u32 old_left_nritems;
-       u32 right_nritems;
        u32 nr;
        int ret = 0;
        int wret;
@@ -2553,41 +2515,6 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
        u32 old_left_item_size;
 
        slot = path->slots[1];
-       if (slot == 0)
-               return 1;
-       if (!path->nodes[1])
-               return 1;
-
-       right_nritems = btrfs_header_nritems(right);
-       if (right_nritems == 0)
-               return 1;
-
-       btrfs_assert_tree_locked(path->nodes[1]);
-
-       left = read_node_slot(root, path->nodes[1], slot - 1);
-       btrfs_tree_lock(left);
-       btrfs_set_lock_blocking(left);
-
-       free_space = btrfs_leaf_free_space(root, left);
-       if (free_space < data_size) {
-               ret = 1;
-               goto out;
-       }
-
-       /* cow and double check */
-       ret = btrfs_cow_block(trans, root, left,
-                             path->nodes[1], slot - 1, &left, 0);
-       if (ret) {
-               /* we hit -ENOSPC, but it isn't fatal here */
-               ret = 1;
-               goto out;
-       }
-
-       free_space = btrfs_leaf_free_space(root, left);
-       if (free_space < data_size) {
-               ret = 1;
-               goto out;
-       }
 
        if (empty)
                nr = right_nritems;
@@ -2754,6 +2681,154 @@ out:
        return ret;
 }
 
+/*
+ * push some data in the path leaf to the left, trying to free up at
+ * least data_size bytes.  returns zero if the push worked, nonzero otherwise
+ */
+static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
+                         *root, struct btrfs_path *path, int data_size,
+                         int empty)
+{
+       struct extent_buffer *right = path->nodes[0];
+       struct extent_buffer *left;
+       int slot;
+       int free_space;
+       u32 right_nritems;
+       int ret = 0;
+
+       slot = path->slots[1];
+       if (slot == 0)
+               return 1;
+       if (!path->nodes[1])
+               return 1;
+
+       right_nritems = btrfs_header_nritems(right);
+       if (right_nritems == 0)
+               return 1;
+
+       btrfs_assert_tree_locked(path->nodes[1]);
+
+       left = read_node_slot(root, path->nodes[1], slot - 1);
+       btrfs_tree_lock(left);
+       btrfs_set_lock_blocking(left);
+
+       free_space = btrfs_leaf_free_space(root, left);
+       if (free_space < data_size) {
+               ret = 1;
+               goto out;
+       }
+
+       /* cow and double check */
+       ret = btrfs_cow_block(trans, root, left,
+                             path->nodes[1], slot - 1, &left);
+       if (ret) {
+               /* we hit -ENOSPC, but it isn't fatal here */
+               ret = 1;
+               goto out;
+       }
+
+       free_space = btrfs_leaf_free_space(root, left);
+       if (free_space < data_size) {
+               ret = 1;
+               goto out;
+       }
+
+       return __push_leaf_left(trans, root, path, data_size,
+                              empty, left, free_space, right_nritems);
+out:
+       btrfs_tree_unlock(left);
+       free_extent_buffer(left);
+       return ret;
+}
+
+/*
+ * split the path's leaf in two, making sure there is at least data_size
+ * available for the resulting leaf level of the path.
+ *
+ * returns 0 if all went well and < 0 on failure.
+ */
+static noinline int copy_for_split(struct btrfs_trans_handle *trans,
+                              struct btrfs_root *root,
+                              struct btrfs_path *path,
+                              struct extent_buffer *l,
+                              struct extent_buffer *right,
+                              int slot, int mid, int nritems)
+{
+       int data_copy_size;
+       int rt_data_off;
+       int i;
+       int ret = 0;
+       int wret;
+       struct btrfs_disk_key disk_key;
+
+       nritems = nritems - mid;
+       btrfs_set_header_nritems(right, nritems);
+       data_copy_size = btrfs_item_end_nr(l, mid) - leaf_data_end(root, l);
+
+       copy_extent_buffer(right, l, btrfs_item_nr_offset(0),
+                          btrfs_item_nr_offset(mid),
+                          nritems * sizeof(struct btrfs_item));
+
+       copy_extent_buffer(right, l,
+                    btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) -
+                    data_copy_size, btrfs_leaf_data(l) +
+                    leaf_data_end(root, l), data_copy_size);
+
+       rt_data_off = BTRFS_LEAF_DATA_SIZE(root) -
+                     btrfs_item_end_nr(l, mid);
+
+       for (i = 0; i < nritems; i++) {
+               struct btrfs_item *item = btrfs_item_nr(right, i);
+               u32 ioff;
+
+               if (!right->map_token) {
+                       map_extent_buffer(right, (unsigned long)item,
+                                       sizeof(struct btrfs_item),
+                                       &right->map_token, &right->kaddr,
+                                       &right->map_start, &right->map_len,
+                                       KM_USER1);
+               }
+
+               ioff = btrfs_item_offset(right, item);
+               btrfs_set_item_offset(right, item, ioff + rt_data_off);
+       }
+
+       if (right->map_token) {
+               unmap_extent_buffer(right, right->map_token, KM_USER1);
+               right->map_token = NULL;
+       }
+
+       btrfs_set_header_nritems(l, mid);
+       ret = 0;
+       btrfs_item_key(right, &disk_key, 0);
+       wret = insert_ptr(trans, root, path, &disk_key, right->start,
+                         path->slots[1] + 1, 1);
+       if (wret)
+               ret = wret;
+
+       btrfs_mark_buffer_dirty(right);
+       btrfs_mark_buffer_dirty(l);
+       BUG_ON(path->slots[0] != slot);
+
+       ret = btrfs_update_ref(trans, root, l, right, 0, nritems);
+       BUG_ON(ret);
+
+       if (mid <= slot) {
+               btrfs_tree_unlock(path->nodes[0]);
+               free_extent_buffer(path->nodes[0]);
+               path->nodes[0] = right;
+               path->slots[0] -= mid;
+               path->slots[1] += 1;
+       } else {
+               btrfs_tree_unlock(right);
+               free_extent_buffer(right);
+       }
+
+       BUG_ON(path->slots[0] < 0);
+
+       return ret;
+}
+
 /*
  * split the path's leaf in two, making sure there is at least data_size
  * available for the resulting leaf level of the path.
@@ -2771,17 +2846,14 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
        int mid;
        int slot;
        struct extent_buffer *right;
-       int data_copy_size;
-       int rt_data_off;
-       int i;
        int ret = 0;
        int wret;
        int double_split;
        int num_doubles = 0;
-       struct btrfs_disk_key disk_key;
 
        /* first try to make some room by pushing left and right */
-       if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) {
+       if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY &&
+           !trans->transaction->delayed_refs.flushing) {
                wret = push_leaf_right(trans, root, path, data_size, 0);
                if (wret < 0)
                        return wret;
@@ -2830,11 +2902,14 @@ again:
        write_extent_buffer(right, root->fs_info->chunk_tree_uuid,
                            (unsigned long)btrfs_header_chunk_tree_uuid(right),
                            BTRFS_UUID_SIZE);
+
        if (mid <= slot) {
                if (nritems == 1 ||
                    leaf_space_used(l, mid, nritems - mid) + data_size >
                        BTRFS_LEAF_DATA_SIZE(root)) {
                        if (slot >= nritems) {
+                               struct btrfs_disk_key disk_key;
+
                                btrfs_cpu_key_to_disk(&disk_key, ins_key);
                                btrfs_set_header_nritems(right, 0);
                                wret = insert_ptr(trans, root, path,
@@ -2862,6 +2937,8 @@ again:
                if (leaf_space_used(l, 0, mid) + data_size >
                        BTRFS_LEAF_DATA_SIZE(root)) {
                        if (!extend && data_size && slot == 0) {
+                               struct btrfs_disk_key disk_key;
+
                                btrfs_cpu_key_to_disk(&disk_key, ins_key);
                                btrfs_set_header_nritems(right, 0);
                                wret = insert_ptr(trans, root, path,
@@ -2894,76 +2971,16 @@ again:
                        }
                }
        }
-       nritems = nritems - mid;
-       btrfs_set_header_nritems(right, nritems);
-       data_copy_size = btrfs_item_end_nr(l, mid) - leaf_data_end(root, l);
-
-       copy_extent_buffer(right, l, btrfs_item_nr_offset(0),
-                          btrfs_item_nr_offset(mid),
-                          nritems * sizeof(struct btrfs_item));
-
-       copy_extent_buffer(right, l,
-                    btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) -
-                    data_copy_size, btrfs_leaf_data(l) +
-                    leaf_data_end(root, l), data_copy_size);
-
-       rt_data_off = BTRFS_LEAF_DATA_SIZE(root) -
-                     btrfs_item_end_nr(l, mid);
-
-       for (i = 0; i < nritems; i++) {
-               struct btrfs_item *item = btrfs_item_nr(right, i);
-               u32 ioff;
-
-               if (!right->map_token) {
-                       map_extent_buffer(right, (unsigned long)item,
-                                       sizeof(struct btrfs_item),
-                                       &right->map_token, &right->kaddr,
-                                       &right->map_start, &right->map_len,
-                                       KM_USER1);
-               }
-
-               ioff = btrfs_item_offset(right, item);
-               btrfs_set_item_offset(right, item, ioff + rt_data_off);
-       }
-
-       if (right->map_token) {
-               unmap_extent_buffer(right, right->map_token, KM_USER1);
-               right->map_token = NULL;
-       }
-
-       btrfs_set_header_nritems(l, mid);
-       ret = 0;
-       btrfs_item_key(right, &disk_key, 0);
-       wret = insert_ptr(trans, root, path, &disk_key, right->start,
-                         path->slots[1] + 1, 1);
-       if (wret)
-               ret = wret;
-
-       btrfs_mark_buffer_dirty(right);
-       btrfs_mark_buffer_dirty(l);
-       BUG_ON(path->slots[0] != slot);
 
-       ret = btrfs_update_ref(trans, root, l, right, 0, nritems);
+       ret = copy_for_split(trans, root, path, l, right, slot, mid, nritems);
        BUG_ON(ret);
 
-       if (mid <= slot) {
-               btrfs_tree_unlock(path->nodes[0]);
-               free_extent_buffer(path->nodes[0]);
-               path->nodes[0] = right;
-               path->slots[0] -= mid;
-               path->slots[1] += 1;
-       } else {
-               btrfs_tree_unlock(right);
-               free_extent_buffer(right);
-       }
-
-       BUG_ON(path->slots[0] < 0);
-
        if (double_split) {
                BUG_ON(num_doubles != 0);
                num_doubles++;
                goto again;
        }
+
        return ret;
 }
 
@@ -3021,26 +3038,27 @@ int btrfs_split_item(struct btrfs_trans_handle *trans,
                return -EAGAIN;
        }
 
+       btrfs_set_path_blocking(path);
        ret = split_leaf(trans, root, &orig_key, path,
                         sizeof(struct btrfs_item), 1);
        path->keep_locks = 0;
        BUG_ON(ret);
 
+       btrfs_unlock_up_safe(path, 1);
+       leaf = path->nodes[0];
+       BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item));
+
+split:
        /*
         * make sure any changes to the path from split_leaf leave it
         * in a blocking state
         */
        btrfs_set_path_blocking(path);
 
-       leaf = path->nodes[0];
-       BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item));
-
-split:
        item = btrfs_item_nr(leaf, path->slots[0]);
        orig_offset = btrfs_item_offset(leaf, item);
        item_size = btrfs_item_size(leaf, item);
 
-
        buf = kmalloc(item_size, GFP_NOFS);
        read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf,
                            path->slots[0]), item_size);
@@ -3445,39 +3463,27 @@ out:
 }
 
 /*
- * Given a key and some data, insert items into the tree.
- * This does all the path init required, making room in the tree if needed.
+ * this is a helper for btrfs_insert_empty_items, the main goal here is
+ * to save stack depth by doing the bulk of the work in a function
+ * that doesn't call btrfs_search_slot
  */
-int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root,
-                           struct btrfs_path *path,
-                           struct btrfs_key *cpu_key, u32 *data_size,
-                           int nr)
+static noinline_for_stack int
+setup_items_for_insert(struct btrfs_trans_handle *trans,
+                     struct btrfs_root *root, struct btrfs_path *path,
+                     struct btrfs_key *cpu_key, u32 *data_size,
+                     u32 total_data, u32 total_size, int nr)
 {
-       struct extent_buffer *leaf;
        struct btrfs_item *item;
-       int ret = 0;
-       int slot;
-       int slot_orig;
        int i;
        u32 nritems;
-       u32 total_size = 0;
-       u32 total_data = 0;
        unsigned int data_end;
        struct btrfs_disk_key disk_key;
+       int ret;
+       struct extent_buffer *leaf;
+       int slot;
 
-       for (i = 0; i < nr; i++)
-               total_data += data_size[i];
-
-       total_size = total_data + (nr * sizeof(struct btrfs_item));
-       ret = btrfs_search_slot(trans, root, cpu_key, path, total_size, 1);
-       if (ret == 0)
-               return -EEXIST;
-       if (ret < 0)
-               goto out;
-
-       slot_orig = path->slots[0];
        leaf = path->nodes[0];
+       slot = path->slots[0];
 
        nritems = btrfs_header_nritems(leaf);
        data_end = leaf_data_end(root, leaf);
@@ -3489,9 +3495,6 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
                BUG();
        }
 
-       slot = path->slots[0];
-       BUG_ON(slot < 0);
-
        if (slot != nritems) {
                unsigned int old_data = btrfs_item_end_nr(leaf, slot);
 
@@ -3547,21 +3550,60 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
                data_end -= data_size[i];
                btrfs_set_item_size(leaf, item, data_size[i]);
        }
+
        btrfs_set_header_nritems(leaf, nritems + nr);
-       btrfs_mark_buffer_dirty(leaf);
 
        ret = 0;
        if (slot == 0) {
+               struct btrfs_disk_key disk_key;
                btrfs_cpu_key_to_disk(&disk_key, cpu_key);
                ret = fixup_low_keys(trans, root, path, &disk_key, 1);
        }
+       btrfs_unlock_up_safe(path, 1);
+       btrfs_mark_buffer_dirty(leaf);
 
        if (btrfs_leaf_free_space(root, leaf) < 0) {
                btrfs_print_leaf(root, leaf);
                BUG();
        }
+       return ret;
+}
+
+/*
+ * Given a key and some data, insert items into the tree.
+ * This does all the path init required, making room in the tree if needed.
+ */
+int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root,
+                           struct btrfs_path *path,
+                           struct btrfs_key *cpu_key, u32 *data_size,
+                           int nr)
+{
+       struct extent_buffer *leaf;
+       int ret = 0;
+       int slot;
+       int i;
+       u32 total_size = 0;
+       u32 total_data = 0;
+
+       for (i = 0; i < nr; i++)
+               total_data += data_size[i];
+
+       total_size = total_data + (nr * sizeof(struct btrfs_item));
+       ret = btrfs_search_slot(trans, root, cpu_key, path, total_size, 1);
+       if (ret == 0)
+               return -EEXIST;
+       if (ret < 0)
+               goto out;
+
+       leaf = path->nodes[0];
+       slot = path->slots[0];
+       BUG_ON(slot < 0);
+
+       ret = setup_items_for_insert(trans, root, path, cpu_key, data_size,
+                              total_data, total_size, nr);
+
 out:
-       btrfs_unlock_up_safe(path, 1);
        return ret;
 }
 
@@ -3749,7 +3791,8 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                }
 
                /* delete the leaf if it is mostly empty */
-               if (used < BTRFS_LEAF_DATA_SIZE(root) / 4) {
+               if (used < BTRFS_LEAF_DATA_SIZE(root) / 4 &&
+                   !trans->transaction->delayed_refs.flushing) {
                        /* push_leaf_left fixes the path.
                         * make sure the path still points to our leaf
                         * for possible call to del_ptr below
@@ -3757,6 +3800,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                        slot = path->slots[1];
                        extent_buffer_get(leaf);
 
+                       btrfs_set_path_blocking(path);
                        wret = push_leaf_left(trans, root, path, 1, 1);
                        if (wret < 0 && wret != -ENOSPC)
                                ret = wret;
index 5e1d4e30e9d863a6c66c36549136bb9abd088738..9417713542a2a5867490d0308241f610832400ee 100644 (file)
@@ -45,6 +45,13 @@ struct btrfs_ordered_sum;
 
 #define BTRFS_MAX_LEVEL 8
 
+/*
+ * files bigger than this get some pre-flushing when they are added
+ * to the ordered operations list.  That way we limit the total
+ * work done by the commit
+ */
+#define BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT (8 * 1024 * 1024)
+
 /* holds pointers to all of the tree roots */
 #define BTRFS_ROOT_TREE_OBJECTID 1ULL
 
@@ -401,15 +408,16 @@ struct btrfs_path {
        int locks[BTRFS_MAX_LEVEL];
        int reada;
        /* keep some upper locks as we walk down */
-       int keep_locks;
-       int skip_locking;
        int lowest_level;
 
        /*
         * set by btrfs_split_item, tells search_slot to keep all locks
         * and to force calls to keep space in the nodes
         */
-       int search_for_split;
+       unsigned int search_for_split:1;
+       unsigned int keep_locks:1;
+       unsigned int skip_locking:1;
+       unsigned int leave_spinning:1;
 };
 
 /*
@@ -688,15 +696,18 @@ struct btrfs_fs_info {
        struct rb_root block_group_cache_tree;
 
        struct extent_io_tree pinned_extents;
-       struct extent_io_tree pending_del;
-       struct extent_io_tree extent_ins;
 
        /* logical->physical extent mapping */
        struct btrfs_mapping_tree mapping_tree;
 
        u64 generation;
        u64 last_trans_committed;
-       u64 last_trans_new_blockgroup;
+
+       /*
+        * this is updated to the current trans every time a full commit
+        * is required instead of the faster short fsync log commits
+        */
+       u64 last_trans_log_full_commit;
        u64 open_ioctl_trans;
        unsigned long mount_opt;
        u64 max_extent;
@@ -717,12 +728,21 @@ struct btrfs_fs_info {
        struct mutex tree_log_mutex;
        struct mutex transaction_kthread_mutex;
        struct mutex cleaner_mutex;
-       struct mutex extent_ins_mutex;
        struct mutex pinned_mutex;
        struct mutex chunk_mutex;
        struct mutex drop_mutex;
        struct mutex volume_mutex;
        struct mutex tree_reloc_mutex;
+
+       /*
+        * this protects the ordered operations list only while we are
+        * processing all of the entries on it.  This way we make
+        * sure the commit code doesn't find the list temporarily empty
+        * because another function happens to be doing non-waiting preflush
+        * before jumping into the main commit.
+        */
+       struct mutex ordered_operations_mutex;
+
        struct list_head trans_list;
        struct list_head hashers;
        struct list_head dead_roots;
@@ -737,9 +757,28 @@ struct btrfs_fs_info {
         * ordered extents
         */
        spinlock_t ordered_extent_lock;
+
+       /*
+        * all of the data=ordered extents pending writeback
+        * these can span multiple transactions and basically include
+        * every dirty data page that isn't from nodatacow
+        */
        struct list_head ordered_extents;
+
+       /*
+        * all of the inodes that have delalloc bytes.  It is possible for
+        * this list to be empty even when there is still dirty data=ordered
+        * extents waiting to finish IO.
+        */
        struct list_head delalloc_inodes;
 
+       /*
+        * special rename and truncate targets that must be on disk before
+        * we're allowed to commit.  This is basically the ext3 style
+        * data=ordered list.
+        */
+       struct list_head ordered_operations;
+
        /*
         * there is a pool of worker threads for checksumming during writes
         * and a pool for checksumming after reads.  This is because readers
@@ -781,6 +820,11 @@ struct btrfs_fs_info {
        atomic_t throttle_gen;
 
        u64 total_pinned;
+
+       /* protected by the delalloc lock, used to keep from writing
+        * metadata until there is a nice batch
+        */
+       u64 dirty_metadata_bytes;
        struct list_head dirty_cowonly_roots;
 
        struct btrfs_fs_devices *fs_devices;
@@ -1704,18 +1748,15 @@ static inline struct dentry *fdentry(struct file *file)
 }
 
 /* extent-tree.c */
+int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
+                          struct btrfs_root *root, unsigned long count);
 int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len);
-int btrfs_lookup_extent_ref(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root, u64 bytenr,
-                           u64 num_bytes, u32 *refs);
 int btrfs_update_pinned_extents(struct btrfs_root *root,
                                u64 bytenr, u64 num, int pin);
 int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root, struct extent_buffer *leaf);
 int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root, u64 objectid, u64 bytenr);
-int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
-                        struct btrfs_root *root);
 int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy);
 struct btrfs_block_group_cache *btrfs_lookup_block_group(
                                                 struct btrfs_fs_info *info,
@@ -1777,7 +1818,7 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                         u64 root_objectid, u64 ref_generation,
                         u64 owner_objectid);
 int btrfs_update_extent_ref(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root, u64 bytenr,
+                           struct btrfs_root *root, u64 bytenr, u64 num_bytes,
                            u64 orig_parent, u64 parent,
                            u64 root_objectid, u64 ref_generation,
                            u64 owner_objectid);
@@ -1838,7 +1879,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
 int btrfs_cow_block(struct btrfs_trans_handle *trans,
                    struct btrfs_root *root, struct extent_buffer *buf,
                    struct extent_buffer *parent, int parent_slot,
-                   struct extent_buffer **cow_ret, u64 prealloc_dest);
+                   struct extent_buffer **cow_ret);
 int btrfs_copy_root(struct btrfs_trans_handle *trans,
                      struct btrfs_root *root,
                      struct extent_buffer *buf,
@@ -2060,7 +2101,7 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
 unsigned long btrfs_force_ra(struct address_space *mapping,
                              struct file_ra_state *ra, struct file *file,
                              pgoff_t offset, pgoff_t last_index);
-int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page);
+int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
 int btrfs_readpage(struct file *file, struct page *page);
 void btrfs_delete_inode(struct inode *inode);
 void btrfs_put_inode(struct inode *inode);
diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c
new file mode 100644 (file)
index 0000000..cbf7dc8
--- /dev/null
@@ -0,0 +1,669 @@
+/*
+ * Copyright (C) 2009 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * 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 021110-1307, USA.
+ */
+
+#include <linux/sched.h>
+#include <linux/sort.h>
+#include <linux/ftrace.h>
+#include "ctree.h"
+#include "delayed-ref.h"
+#include "transaction.h"
+
+/*
+ * delayed back reference update tracking.  For subvolume trees
+ * we queue up extent allocations and backref maintenance for
+ * delayed processing.   This avoids deep call chains where we
+ * add extents in the middle of btrfs_search_slot, and it allows
+ * us to buffer up frequently modified backrefs in an rb tree instead
+ * of hammering updates on the extent allocation tree.
+ *
+ * Right now this code is only used for reference counted trees, but
+ * the long term goal is to get rid of the similar code for delayed
+ * extent tree modifications.
+ */
+
+/*
+ * entries in the rb tree are ordered by the byte number of the extent
+ * and by the byte number of the parent block.
+ */
+static int comp_entry(struct btrfs_delayed_ref_node *ref,
+                     u64 bytenr, u64 parent)
+{
+       if (bytenr < ref->bytenr)
+               return -1;
+       if (bytenr > ref->bytenr)
+               return 1;
+       if (parent < ref->parent)
+               return -1;
+       if (parent > ref->parent)
+               return 1;
+       return 0;
+}
+
+/*
+ * insert a new ref into the rbtree.  This returns any existing refs
+ * for the same (bytenr,parent) tuple, or NULL if the new node was properly
+ * inserted.
+ */
+static struct btrfs_delayed_ref_node *tree_insert(struct rb_root *root,
+                                                 u64 bytenr, u64 parent,
+                                                 struct rb_node *node)
+{
+       struct rb_node **p = &root->rb_node;
+       struct rb_node *parent_node = NULL;
+       struct btrfs_delayed_ref_node *entry;
+       int cmp;
+
+       while (*p) {
+               parent_node = *p;
+               entry = rb_entry(parent_node, struct btrfs_delayed_ref_node,
+                                rb_node);
+
+               cmp = comp_entry(entry, bytenr, parent);
+               if (cmp < 0)
+                       p = &(*p)->rb_left;
+               else if (cmp > 0)
+                       p = &(*p)->rb_right;
+               else
+                       return entry;
+       }
+
+       entry = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
+       rb_link_node(node, parent_node, p);
+       rb_insert_color(node, root);
+       return NULL;
+}
+
+/*
+ * find an entry based on (bytenr,parent).  This returns the delayed
+ * ref if it was able to find one, or NULL if nothing was in that spot
+ */
+static struct btrfs_delayed_ref_node *tree_search(struct rb_root *root,
+                                 u64 bytenr, u64 parent,
+                                 struct btrfs_delayed_ref_node **last)
+{
+       struct rb_node *n = root->rb_node;
+       struct btrfs_delayed_ref_node *entry;
+       int cmp;
+
+       while (n) {
+               entry = rb_entry(n, struct btrfs_delayed_ref_node, rb_node);
+               WARN_ON(!entry->in_tree);
+               if (last)
+                       *last = entry;
+
+               cmp = comp_entry(entry, bytenr, parent);
+               if (cmp < 0)
+                       n = n->rb_left;
+               else if (cmp > 0)
+                       n = n->rb_right;
+               else
+                       return entry;
+       }
+       return NULL;
+}
+
+int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
+                          struct btrfs_delayed_ref_head *head)
+{
+       struct btrfs_delayed_ref_root *delayed_refs;
+
+       delayed_refs = &trans->transaction->delayed_refs;
+       assert_spin_locked(&delayed_refs->lock);
+       if (mutex_trylock(&head->mutex))
+               return 0;
+
+       atomic_inc(&head->node.refs);
+       spin_unlock(&delayed_refs->lock);
+
+       mutex_lock(&head->mutex);
+       spin_lock(&delayed_refs->lock);
+       if (!head->node.in_tree) {
+               mutex_unlock(&head->mutex);
+               btrfs_put_delayed_ref(&head->node);
+               return -EAGAIN;
+       }
+       btrfs_put_delayed_ref(&head->node);
+       return 0;
+}
+
+int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
+                          struct list_head *cluster, u64 start)
+{
+       int count = 0;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       struct rb_node *node;
+       struct btrfs_delayed_ref_node *ref;
+       struct btrfs_delayed_ref_head *head;
+
+       delayed_refs = &trans->transaction->delayed_refs;
+       if (start == 0) {
+               node = rb_first(&delayed_refs->root);
+       } else {
+               ref = NULL;
+               tree_search(&delayed_refs->root, start, (u64)-1, &ref);
+               if (ref) {
+                       struct btrfs_delayed_ref_node *tmp;
+
+                       node = rb_prev(&ref->rb_node);
+                       while (node) {
+                               tmp = rb_entry(node,
+                                              struct btrfs_delayed_ref_node,
+                                              rb_node);
+                               if (tmp->bytenr < start)
+                                       break;
+                               ref = tmp;
+                               node = rb_prev(&ref->rb_node);
+                       }
+                       node = &ref->rb_node;
+               } else
+                       node = rb_first(&delayed_refs->root);
+       }
+again:
+       while (node && count < 32) {
+               ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
+               if (btrfs_delayed_ref_is_head(ref)) {
+                       head = btrfs_delayed_node_to_head(ref);
+                       if (list_empty(&head->cluster)) {
+                               list_add_tail(&head->cluster, cluster);
+                               delayed_refs->run_delayed_start =
+                                       head->node.bytenr;
+                               count++;
+
+                               WARN_ON(delayed_refs->num_heads_ready == 0);
+                               delayed_refs->num_heads_ready--;
+                       } else if (count) {
+                               /* the goal of the clustering is to find extents
+                                * that are likely to end up in the same extent
+                                * leaf on disk.  So, we don't want them spread
+                                * all over the tree.  Stop now if we've hit
+                                * a head that was already in use
+                                */
+                               break;
+                       }
+               }
+               node = rb_next(node);
+       }
+       if (count) {
+               return 0;
+       } else if (start) {
+               /*
+                * we've gone to the end of the rbtree without finding any
+                * clusters.  start from the beginning and try again
+                */
+               start = 0;
+               node = rb_first(&delayed_refs->root);
+               goto again;
+       }
+       return 1;
+}
+
+/*
+ * This checks to see if there are any delayed refs in the
+ * btree for a given bytenr.  It returns one if it finds any
+ * and zero otherwise.
+ *
+ * If it only finds a head node, it returns 0.
+ *
+ * The idea is to use this when deciding if you can safely delete an
+ * extent from the extent allocation tree.  There may be a pending
+ * ref in the rbtree that adds or removes references, so as long as this
+ * returns one you need to leave the BTRFS_EXTENT_ITEM in the extent
+ * allocation tree.
+ */
+int btrfs_delayed_ref_pending(struct btrfs_trans_handle *trans, u64 bytenr)
+{
+       struct btrfs_delayed_ref_node *ref;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       struct rb_node *prev_node;
+       int ret = 0;
+
+       delayed_refs = &trans->transaction->delayed_refs;
+       spin_lock(&delayed_refs->lock);
+
+       ref = tree_search(&delayed_refs->root, bytenr, (u64)-1, NULL);
+       if (ref) {
+               prev_node = rb_prev(&ref->rb_node);
+               if (!prev_node)
+                       goto out;
+               ref = rb_entry(prev_node, struct btrfs_delayed_ref_node,
+                              rb_node);
+               if (ref->bytenr == bytenr)
+                       ret = 1;
+       }
+out:
+       spin_unlock(&delayed_refs->lock);
+       return ret;
+}
+
+/*
+ * helper function to lookup reference count
+ *
+ * the head node for delayed ref is used to store the sum of all the
+ * reference count modifications queued up in the rbtree.  This way you
+ * can check to see what the reference count would be if all of the
+ * delayed refs are processed.
+ */
+int btrfs_lookup_extent_ref(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root, u64 bytenr,
+                           u64 num_bytes, u32 *refs)
+{
+       struct btrfs_delayed_ref_node *ref;
+       struct btrfs_delayed_ref_head *head;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       struct btrfs_path *path;
+       struct extent_buffer *leaf;
+       struct btrfs_extent_item *ei;
+       struct btrfs_key key;
+       u32 num_refs;
+       int ret;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       key.objectid = bytenr;
+       key.type = BTRFS_EXTENT_ITEM_KEY;
+       key.offset = num_bytes;
+       delayed_refs = &trans->transaction->delayed_refs;
+again:
+       ret = btrfs_search_slot(trans, root->fs_info->extent_root,
+                               &key, path, 0, 0);
+       if (ret < 0)
+               goto out;
+
+       if (ret == 0) {
+               leaf = path->nodes[0];
+               ei = btrfs_item_ptr(leaf, path->slots[0],
+                                   struct btrfs_extent_item);
+               num_refs = btrfs_extent_refs(leaf, ei);
+       } else {
+               num_refs = 0;
+               ret = 0;
+       }
+
+       spin_lock(&delayed_refs->lock);
+       ref = tree_search(&delayed_refs->root, bytenr, (u64)-1, NULL);
+       if (ref) {
+               head = btrfs_delayed_node_to_head(ref);
+               if (mutex_trylock(&head->mutex)) {
+                       num_refs += ref->ref_mod;
+                       mutex_unlock(&head->mutex);
+                       *refs = num_refs;
+                       goto out;
+               }
+
+               atomic_inc(&ref->refs);
+               spin_unlock(&delayed_refs->lock);
+
+               btrfs_release_path(root->fs_info->extent_root, path);
+
+               mutex_lock(&head->mutex);
+               mutex_unlock(&head->mutex);
+               btrfs_put_delayed_ref(ref);
+               goto again;
+       } else {
+               *refs = num_refs;
+       }
+out:
+       spin_unlock(&delayed_refs->lock);
+       btrfs_free_path(path);
+       return ret;
+}
+
+/*
+ * helper function to update an extent delayed ref in the
+ * rbtree.  existing and update must both have the same
+ * bytenr and parent
+ *
+ * This may free existing if the update cancels out whatever
+ * operation it was doing.
+ */
+static noinline void
+update_existing_ref(struct btrfs_trans_handle *trans,
+                   struct btrfs_delayed_ref_root *delayed_refs,
+                   struct btrfs_delayed_ref_node *existing,
+                   struct btrfs_delayed_ref_node *update)
+{
+       struct btrfs_delayed_ref *existing_ref;
+       struct btrfs_delayed_ref *ref;
+
+       existing_ref = btrfs_delayed_node_to_ref(existing);
+       ref = btrfs_delayed_node_to_ref(update);
+
+       if (ref->pin)
+               existing_ref->pin = 1;
+
+       if (ref->action != existing_ref->action) {
+               /*
+                * this is effectively undoing either an add or a
+                * drop.  We decrement the ref_mod, and if it goes
+                * down to zero we just delete the entry without
+                * every changing the extent allocation tree.
+                */
+               existing->ref_mod--;
+               if (existing->ref_mod == 0) {
+                       rb_erase(&existing->rb_node,
+                                &delayed_refs->root);
+                       existing->in_tree = 0;
+                       btrfs_put_delayed_ref(existing);
+                       delayed_refs->num_entries--;
+                       if (trans->delayed_ref_updates)
+                               trans->delayed_ref_updates--;
+               }
+       } else {
+               if (existing_ref->action == BTRFS_ADD_DELAYED_REF) {
+                       /* if we're adding refs, make sure all the
+                        * details match up.  The extent could
+                        * have been totally freed and reallocated
+                        * by a different owner before the delayed
+                        * ref entries were removed.
+                        */
+                       existing_ref->owner_objectid = ref->owner_objectid;
+                       existing_ref->generation = ref->generation;
+                       existing_ref->root = ref->root;
+                       existing->num_bytes = update->num_bytes;
+               }
+               /*
+                * the action on the existing ref matches
+                * the action on the ref we're trying to add.
+                * Bump the ref_mod by one so the backref that
+                * is eventually added/removed has the correct
+                * reference count
+                */
+               existing->ref_mod += update->ref_mod;
+       }
+}
+
+/*
+ * helper function to update the accounting in the head ref
+ * existing and update must have the same bytenr
+ */
+static noinline void
+update_existing_head_ref(struct btrfs_delayed_ref_node *existing,
+                        struct btrfs_delayed_ref_node *update)
+{
+       struct btrfs_delayed_ref_head *existing_ref;
+       struct btrfs_delayed_ref_head *ref;
+
+       existing_ref = btrfs_delayed_node_to_head(existing);
+       ref = btrfs_delayed_node_to_head(update);
+
+       if (ref->must_insert_reserved) {
+               /* if the extent was freed and then
+                * reallocated before the delayed ref
+                * entries were processed, we can end up
+                * with an existing head ref without
+                * the must_insert_reserved flag set.
+                * Set it again here
+                */
+               existing_ref->must_insert_reserved = ref->must_insert_reserved;
+
+               /*
+                * update the num_bytes so we make sure the accounting
+                * is done correctly
+                */
+               existing->num_bytes = update->num_bytes;
+
+       }
+
+       /*
+        * update the reference mod on the head to reflect this new operation
+        */
+       existing->ref_mod += update->ref_mod;
+}
+
+/*
+ * helper function to actually insert a delayed ref into the rbtree.
+ * this does all the dirty work in terms of maintaining the correct
+ * overall modification count in the head node and properly dealing
+ * with updating existing nodes as new modifications are queued.
+ */
+static noinline int __btrfs_add_delayed_ref(struct btrfs_trans_handle *trans,
+                         struct btrfs_delayed_ref_node *ref,
+                         u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root,
+                         u64 ref_generation, u64 owner_objectid, int action,
+                         int pin)
+{
+       struct btrfs_delayed_ref_node *existing;
+       struct btrfs_delayed_ref *full_ref;
+       struct btrfs_delayed_ref_head *head_ref = NULL;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       int count_mod = 1;
+       int must_insert_reserved = 0;
+
+       /*
+        * the head node stores the sum of all the mods, so dropping a ref
+        * should drop the sum in the head node by one.
+        */
+       if (parent == (u64)-1) {
+               if (action == BTRFS_DROP_DELAYED_REF)
+                       count_mod = -1;
+               else if (action == BTRFS_UPDATE_DELAYED_HEAD)
+                       count_mod = 0;
+       }
+
+       /*
+        * BTRFS_ADD_DELAYED_EXTENT means that we need to update
+        * the reserved accounting when the extent is finally added, or
+        * if a later modification deletes the delayed ref without ever
+        * inserting the extent into the extent allocation tree.
+        * ref->must_insert_reserved is the flag used to record
+        * that accounting mods are required.
+        *
+        * Once we record must_insert_reserved, switch the action to
+        * BTRFS_ADD_DELAYED_REF because other special casing is not required.
+        */
+       if (action == BTRFS_ADD_DELAYED_EXTENT) {
+               must_insert_reserved = 1;
+               action = BTRFS_ADD_DELAYED_REF;
+       } else {
+               must_insert_reserved = 0;
+       }
+
+
+       delayed_refs = &trans->transaction->delayed_refs;
+
+       /* first set the basic ref node struct up */
+       atomic_set(&ref->refs, 1);
+       ref->bytenr = bytenr;
+       ref->parent = parent;
+       ref->ref_mod = count_mod;
+       ref->in_tree = 1;
+       ref->num_bytes = num_bytes;
+
+       if (btrfs_delayed_ref_is_head(ref)) {
+               head_ref = btrfs_delayed_node_to_head(ref);
+               head_ref->must_insert_reserved = must_insert_reserved;
+               INIT_LIST_HEAD(&head_ref->cluster);
+               mutex_init(&head_ref->mutex);
+       } else {
+               full_ref = btrfs_delayed_node_to_ref(ref);
+               full_ref->root = ref_root;
+               full_ref->generation = ref_generation;
+               full_ref->owner_objectid = owner_objectid;
+               full_ref->pin = pin;
+               full_ref->action = action;
+       }
+
+       existing = tree_insert(&delayed_refs->root, bytenr,
+                              parent, &ref->rb_node);
+
+       if (existing) {
+               if (btrfs_delayed_ref_is_head(ref))
+                       update_existing_head_ref(existing, ref);
+               else
+                       update_existing_ref(trans, delayed_refs, existing, ref);
+
+               /*
+                * we've updated the existing ref, free the newly
+                * allocated ref
+                */
+               kfree(ref);
+       } else {
+               if (btrfs_delayed_ref_is_head(ref)) {
+                       delayed_refs->num_heads++;
+                       delayed_refs->num_heads_ready++;
+               }
+               delayed_refs->num_entries++;
+               trans->delayed_ref_updates++;
+       }
+       return 0;
+}
+
+/*
+ * add a delayed ref to the tree.  This does all of the accounting required
+ * to make sure the delayed ref is eventually processed before this
+ * transaction commits.
+ */
+int btrfs_add_delayed_ref(struct btrfs_trans_handle *trans,
+                         u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root,
+                         u64 ref_generation, u64 owner_objectid, int action,
+                         int pin)
+{
+       struct btrfs_delayed_ref *ref;
+       struct btrfs_delayed_ref_head *head_ref;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       int ret;
+
+       ref = kmalloc(sizeof(*ref), GFP_NOFS);
+       if (!ref)
+               return -ENOMEM;
+
+       /*
+        * the parent = 0 case comes from cases where we don't actually
+        * know the parent yet.  It will get updated later via a add/drop
+        * pair.
+        */
+       if (parent == 0)
+               parent = bytenr;
+
+       head_ref = kmalloc(sizeof(*head_ref), GFP_NOFS);
+       if (!head_ref) {
+               kfree(ref);
+               return -ENOMEM;
+       }
+       delayed_refs = &trans->transaction->delayed_refs;
+       spin_lock(&delayed_refs->lock);
+
+       /*
+        * insert both the head node and the new ref without dropping
+        * the spin lock
+        */
+       ret = __btrfs_add_delayed_ref(trans, &head_ref->node, bytenr, num_bytes,
+                                     (u64)-1, 0, 0, 0, action, pin);
+       BUG_ON(ret);
+
+       ret = __btrfs_add_delayed_ref(trans, &ref->node, bytenr, num_bytes,
+                                     parent, ref_root, ref_generation,
+                                     owner_objectid, action, pin);
+       BUG_ON(ret);
+       spin_unlock(&delayed_refs->lock);
+       return 0;
+}
+
+/*
+ * this does a simple search for the head node for a given extent.
+ * It must be called with the delayed ref spinlock held, and it returns
+ * the head node if any where found, or NULL if not.
+ */
+struct btrfs_delayed_ref_head *
+btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr)
+{
+       struct btrfs_delayed_ref_node *ref;
+       struct btrfs_delayed_ref_root *delayed_refs;
+
+       delayed_refs = &trans->transaction->delayed_refs;
+       ref = tree_search(&delayed_refs->root, bytenr, (u64)-1, NULL);
+       if (ref)
+               return btrfs_delayed_node_to_head(ref);
+       return NULL;
+}
+
+/*
+ * add a delayed ref to the tree.  This does all of the accounting required
+ * to make sure the delayed ref is eventually processed before this
+ * transaction commits.
+ *
+ * The main point of this call is to add and remove a backreference in a single
+ * shot, taking the lock only once, and only searching for the head node once.
+ *
+ * It is the same as doing a ref add and delete in two separate calls.
+ */
+int btrfs_update_delayed_ref(struct btrfs_trans_handle *trans,
+                         u64 bytenr, u64 num_bytes, u64 orig_parent,
+                         u64 parent, u64 orig_ref_root, u64 ref_root,
+                         u64 orig_ref_generation, u64 ref_generation,
+                         u64 owner_objectid, int pin)
+{
+       struct btrfs_delayed_ref *ref;
+       struct btrfs_delayed_ref *old_ref;
+       struct btrfs_delayed_ref_head *head_ref;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       int ret;
+
+       ref = kmalloc(sizeof(*ref), GFP_NOFS);
+       if (!ref)
+               return -ENOMEM;
+
+       old_ref = kmalloc(sizeof(*old_ref), GFP_NOFS);
+       if (!old_ref) {
+               kfree(ref);
+               return -ENOMEM;
+       }
+
+       /*
+        * the parent = 0 case comes from cases where we don't actually
+        * know the parent yet.  It will get updated later via a add/drop
+        * pair.
+        */
+       if (parent == 0)
+               parent = bytenr;
+       if (orig_parent == 0)
+               orig_parent = bytenr;
+
+       head_ref = kmalloc(sizeof(*head_ref), GFP_NOFS);
+       if (!head_ref) {
+               kfree(ref);
+               kfree(old_ref);
+               return -ENOMEM;
+       }
+       delayed_refs = &trans->transaction->delayed_refs;
+       spin_lock(&delayed_refs->lock);
+
+       /*
+        * insert both the head node and the new ref without dropping
+        * the spin lock
+        */
+       ret = __btrfs_add_delayed_ref(trans, &head_ref->node, bytenr, num_bytes,
+                                     (u64)-1, 0, 0, 0,
+                                     BTRFS_UPDATE_DELAYED_HEAD, 0);
+       BUG_ON(ret);
+
+       ret = __btrfs_add_delayed_ref(trans, &ref->node, bytenr, num_bytes,
+                                     parent, ref_root, ref_generation,
+                                     owner_objectid, BTRFS_ADD_DELAYED_REF, 0);
+       BUG_ON(ret);
+
+       ret = __btrfs_add_delayed_ref(trans, &old_ref->node, bytenr, num_bytes,
+                                     orig_parent, orig_ref_root,
+                                     orig_ref_generation, owner_objectid,
+                                     BTRFS_DROP_DELAYED_REF, pin);
+       BUG_ON(ret);
+       spin_unlock(&delayed_refs->lock);
+       return 0;
+}
diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h
new file mode 100644 (file)
index 0000000..3bec2ff
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2008 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * 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 021110-1307, USA.
+ */
+#ifndef __DELAYED_REF__
+#define __DELAYED_REF__
+
+/* these are the possible values of struct btrfs_delayed_ref->action */
+#define BTRFS_ADD_DELAYED_REF    1 /* add one backref to the tree */
+#define BTRFS_DROP_DELAYED_REF   2 /* delete one backref from the tree */
+#define BTRFS_ADD_DELAYED_EXTENT 3 /* record a full extent allocation */
+#define BTRFS_UPDATE_DELAYED_HEAD 4 /* not changing ref count on head ref */
+
+struct btrfs_delayed_ref_node {
+       struct rb_node rb_node;
+
+       /* the starting bytenr of the extent */
+       u64 bytenr;
+
+       /* the parent our backref will point to */
+       u64 parent;
+
+       /* the size of the extent */
+       u64 num_bytes;
+
+       /* ref count on this data structure */
+       atomic_t refs;
+
+       /*
+        * how many refs is this entry adding or deleting.  For
+        * head refs, this may be a negative number because it is keeping
+        * track of the total mods done to the reference count.
+        * For individual refs, this will always be a positive number
+        *
+        * It may be more than one, since it is possible for a single
+        * parent to have more than one ref on an extent
+        */
+       int ref_mod;
+
+       /* is this node still in the rbtree? */
+       unsigned int in_tree:1;
+};
+
+/*
+ * the head refs are used to hold a lock on a given extent, which allows us
+ * to make sure that only one process is running the delayed refs
+ * at a time for a single extent.  They also store the sum of all the
+ * reference count modifications we've queued up.
+ */
+struct btrfs_delayed_ref_head {
+       struct btrfs_delayed_ref_node node;
+
+       /*
+        * the mutex is held while running the refs, and it is also
+        * held when checking the sum of reference modifications.
+        */
+       struct mutex mutex;
+
+       struct list_head cluster;
+
+       /*
+        * when a new extent is allocated, it is just reserved in memory
+        * The actual extent isn't inserted into the extent allocation tree
+        * until the delayed ref is processed.  must_insert_reserved is
+        * used to flag a delayed ref so the accounting can be updated
+        * when a full insert is done.
+        *
+        * It is possible the extent will be freed before it is ever
+        * inserted into the extent allocation tree.  In this case
+        * we need to update the in ram accounting to properly reflect
+        * the free has happened.
+        */
+       unsigned int must_insert_reserved:1;
+};
+
+struct btrfs_delayed_ref {
+       struct btrfs_delayed_ref_node node;
+
+       /* the root objectid our ref will point to */
+       u64 root;
+
+       /* the generation for the backref */
+       u64 generation;
+
+       /* owner_objectid of the backref  */
+       u64 owner_objectid;
+
+       /* operation done by this entry in the rbtree */
+       u8 action;
+
+       /* if pin == 1, when the extent is freed it will be pinned until
+        * transaction commit
+        */
+       unsigned int pin:1;
+};
+
+struct btrfs_delayed_ref_root {
+       struct rb_root root;
+
+       /* this spin lock protects the rbtree and the entries inside */
+       spinlock_t lock;
+
+       /* how many delayed ref updates we've queued, used by the
+        * throttling code
+        */
+       unsigned long num_entries;
+
+       /* total number of head nodes in tree */
+       unsigned long num_heads;
+
+       /* total number of head nodes ready for processing */
+       unsigned long num_heads_ready;
+
+       /*
+        * set when the tree is flushing before a transaction commit,
+        * used by the throttling code to decide if new updates need
+        * to be run right away
+        */
+       int flushing;
+
+       u64 run_delayed_start;
+};
+
+static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref)
+{
+       WARN_ON(atomic_read(&ref->refs) == 0);
+       if (atomic_dec_and_test(&ref->refs)) {
+               WARN_ON(ref->in_tree);
+               kfree(ref);
+       }
+}
+
+int btrfs_add_delayed_ref(struct btrfs_trans_handle *trans,
+                         u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root,
+                         u64 ref_generation, u64 owner_objectid, int action,
+                         int pin);
+
+struct btrfs_delayed_ref_head *
+btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr);
+int btrfs_delayed_ref_pending(struct btrfs_trans_handle *trans, u64 bytenr);
+int btrfs_lookup_extent_ref(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root, u64 bytenr,
+                           u64 num_bytes, u32 *refs);
+int btrfs_update_delayed_ref(struct btrfs_trans_handle *trans,
+                         u64 bytenr, u64 num_bytes, u64 orig_parent,
+                         u64 parent, u64 orig_ref_root, u64 ref_root,
+                         u64 orig_ref_generation, u64 ref_generation,
+                         u64 owner_objectid, int pin);
+int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
+                          struct btrfs_delayed_ref_head *head);
+int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
+                          struct list_head *cluster, u64 search_start);
+/*
+ * a node might live in a head or a regular ref, this lets you
+ * test for the proper type to use.
+ */
+static int btrfs_delayed_ref_is_head(struct btrfs_delayed_ref_node *node)
+{
+       return node->parent == (u64)-1;
+}
+
+/*
+ * helper functions to cast a node into its container
+ */
+static inline struct btrfs_delayed_ref *
+btrfs_delayed_node_to_ref(struct btrfs_delayed_ref_node *node)
+{
+       WARN_ON(btrfs_delayed_ref_is_head(node));
+       return container_of(node, struct btrfs_delayed_ref, node);
+
+}
+
+static inline struct btrfs_delayed_ref_head *
+btrfs_delayed_node_to_head(struct btrfs_delayed_ref_node *node)
+{
+       WARN_ON(!btrfs_delayed_ref_is_head(node));
+       return container_of(node, struct btrfs_delayed_ref_head, node);
+
+}
+#endif
index 926a0b287a7d752994fc5a11894f21e91d5561f8..1d70236ba00c7bf4abf5181d2efd3b20d5867e2e 100644 (file)
@@ -145,7 +145,10 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
        key.objectid = dir;
        btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
        key.offset = btrfs_name_hash(name, name_len);
+
        path = btrfs_alloc_path();
+       path->leave_spinning = 1;
+
        data_size = sizeof(*dir_item) + name_len;
        dir_item = insert_with_overflow(trans, root, path, &key, data_size,
                                        name, name_len);
index 6ec80c0fc8697a0a9171e72a8dd4e63905c7993e..92d73929d3814b50024196eb5e8688d2ee330222 100644 (file)
@@ -668,14 +668,31 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
 static int btree_writepage(struct page *page, struct writeback_control *wbc)
 {
        struct extent_io_tree *tree;
+       struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
+       struct extent_buffer *eb;
+       int was_dirty;
+
        tree = &BTRFS_I(page->mapping->host)->io_tree;
+       if (!(current->flags & PF_MEMALLOC)) {
+               return extent_write_full_page(tree, page,
+                                             btree_get_extent, wbc);
+       }
 
-       if (current->flags & PF_MEMALLOC) {
-               redirty_page_for_writepage(wbc, page);
-               unlock_page(page);
-               return 0;
+       redirty_page_for_writepage(wbc, page);
+       eb = btrfs_find_tree_block(root, page_offset(page),
+                                     PAGE_CACHE_SIZE);
+       WARN_ON(!eb);
+
+       was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags);
+       if (!was_dirty) {
+               spin_lock(&root->fs_info->delalloc_lock);
+               root->fs_info->dirty_metadata_bytes += PAGE_CACHE_SIZE;
+               spin_unlock(&root->fs_info->delalloc_lock);
        }
-       return extent_write_full_page(tree, page, btree_get_extent, wbc);
+       free_extent_buffer(eb);
+
+       unlock_page(page);
+       return 0;
 }
 
 static int btree_writepages(struct address_space *mapping,
@@ -684,15 +701,15 @@ static int btree_writepages(struct address_space *mapping,
        struct extent_io_tree *tree;
        tree = &BTRFS_I(mapping->host)->io_tree;
        if (wbc->sync_mode == WB_SYNC_NONE) {
+               struct btrfs_root *root = BTRFS_I(mapping->host)->root;
                u64 num_dirty;
-               u64 start = 0;
                unsigned long thresh = 32 * 1024 * 1024;
 
                if (wbc->for_kupdate)
                        return 0;
 
-               num_dirty = count_range_bits(tree, &start, (u64)-1,
-                                            thresh, EXTENT_DIRTY);
+               /* this is a bit racy, but that's ok */
+               num_dirty = root->fs_info->dirty_metadata_bytes;
                if (num_dirty < thresh)
                        return 0;
        }
@@ -859,9 +876,17 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
            root->fs_info->running_transaction->transid) {
                btrfs_assert_tree_locked(buf);
 
-               /* ugh, clear_extent_buffer_dirty can be expensive */
-               btrfs_set_lock_blocking(buf);
+               if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &buf->bflags)) {
+                       spin_lock(&root->fs_info->delalloc_lock);
+                       if (root->fs_info->dirty_metadata_bytes >= buf->len)
+                               root->fs_info->dirty_metadata_bytes -= buf->len;
+                       else
+                               WARN_ON(1);
+                       spin_unlock(&root->fs_info->delalloc_lock);
+               }
 
+               /* ugh, clear_extent_buffer_dirty needs to lock the page */
+               btrfs_set_lock_blocking(buf);
                clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree,
                                          buf);
        }
@@ -1471,12 +1496,6 @@ static int transaction_kthread(void *arg)
                vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE);
                mutex_lock(&root->fs_info->transaction_kthread_mutex);
 
-               if (root->fs_info->total_ref_cache_size > 20 * 1024 * 1024) {
-                       printk(KERN_INFO "btrfs: total reference cache "
-                              "size %llu\n",
-                              root->fs_info->total_ref_cache_size);
-               }
-
                mutex_lock(&root->fs_info->trans_mutex);
                cur = root->fs_info->running_transaction;
                if (!cur) {
@@ -1493,6 +1512,7 @@ static int transaction_kthread(void *arg)
                mutex_unlock(&root->fs_info->trans_mutex);
                trans = btrfs_start_transaction(root, 1);
                ret = btrfs_commit_transaction(trans, root);
+
 sleep:
                wake_up_process(root->fs_info->cleaner_kthread);
                mutex_unlock(&root->fs_info->transaction_kthread_mutex);
@@ -1552,6 +1572,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        INIT_LIST_HEAD(&fs_info->dead_roots);
        INIT_LIST_HEAD(&fs_info->hashers);
        INIT_LIST_HEAD(&fs_info->delalloc_inodes);
+       INIT_LIST_HEAD(&fs_info->ordered_operations);
        spin_lock_init(&fs_info->delalloc_lock);
        spin_lock_init(&fs_info->new_trans_lock);
        spin_lock_init(&fs_info->ref_cache_lock);
@@ -1611,10 +1632,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 
        extent_io_tree_init(&fs_info->pinned_extents,
                             fs_info->btree_inode->i_mapping, GFP_NOFS);
-       extent_io_tree_init(&fs_info->pending_del,
-                            fs_info->btree_inode->i_mapping, GFP_NOFS);
-       extent_io_tree_init(&fs_info->extent_ins,
-                            fs_info->btree_inode->i_mapping, GFP_NOFS);
        fs_info->do_barriers = 1;
 
        INIT_LIST_HEAD(&fs_info->dead_reloc_roots);
@@ -1627,9 +1644,9 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        insert_inode_hash(fs_info->btree_inode);
 
        mutex_init(&fs_info->trans_mutex);
+       mutex_init(&fs_info->ordered_operations_mutex);
        mutex_init(&fs_info->tree_log_mutex);
        mutex_init(&fs_info->drop_mutex);
-       mutex_init(&fs_info->extent_ins_mutex);
        mutex_init(&fs_info->pinned_mutex);
        mutex_init(&fs_info->chunk_mutex);
        mutex_init(&fs_info->transaction_kthread_mutex);
@@ -2358,8 +2375,7 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
        struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
        u64 transid = btrfs_header_generation(buf);
        struct inode *btree_inode = root->fs_info->btree_inode;
-
-       btrfs_set_lock_blocking(buf);
+       int was_dirty;
 
        btrfs_assert_tree_locked(buf);
        if (transid != root->fs_info->generation) {
@@ -2370,7 +2386,13 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
                        (unsigned long long)root->fs_info->generation);
                WARN_ON(1);
        }
-       set_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree, buf);
+       was_dirty = set_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree,
+                                           buf);
+       if (!was_dirty) {
+               spin_lock(&root->fs_info->delalloc_lock);
+               root->fs_info->dirty_metadata_bytes += buf->len;
+               spin_unlock(&root->fs_info->delalloc_lock);
+       }
 }
 
 void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
@@ -2410,6 +2432,7 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
 int btree_lock_page_hook(struct page *page)
 {
        struct inode *inode = page->mapping->host;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
        struct extent_buffer *eb;
        unsigned long len;
@@ -2425,6 +2448,16 @@ int btree_lock_page_hook(struct page *page)
 
        btrfs_tree_lock(eb);
        btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
+
+       if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) {
+               spin_lock(&root->fs_info->delalloc_lock);
+               if (root->fs_info->dirty_metadata_bytes >= eb->len)
+                       root->fs_info->dirty_metadata_bytes -= eb->len;
+               else
+                       WARN_ON(1);
+               spin_unlock(&root->fs_info->delalloc_lock);
+       }
+
        btrfs_tree_unlock(eb);
        free_extent_buffer(eb);
 out:
index 95029db227be5767d17eeab2a11cb36b63709849..c958ecbc19168ef0e7ef8e7bdd123f5f527b55f7 100644 (file)
@@ -72,6 +72,7 @@ int btrfs_insert_dev_radix(struct btrfs_root *root,
 void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
 int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
 void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
+void btrfs_mark_buffer_dirty_nonblocking(struct extent_buffer *buf);
 int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid);
 int btrfs_set_buffer_uptodate(struct extent_buffer *buf);
 int wait_on_tree_block_writeback(struct btrfs_root *root,
index fefe83ad20595eba078f6480781eefb0fe81c659..f5e7cae63d80f8828f711833b58600a8bce71df9 100644 (file)
@@ -49,17 +49,23 @@ struct pending_extent_op {
        int del;
 };
 
-static int finish_current_insert(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *extent_root, int all);
-static int del_pending_extents(struct btrfs_trans_handle *trans,
-                              struct btrfs_root *extent_root, int all);
-static int pin_down_bytes(struct btrfs_trans_handle *trans,
-                         struct btrfs_root *root,
-                         u64 bytenr, u64 num_bytes, int is_data);
+static int __btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
+                                        struct btrfs_root *root, u64 parent,
+                                        u64 root_objectid, u64 ref_generation,
+                                        u64 owner, struct btrfs_key *ins,
+                                        int ref_mod);
+static int update_reserved_extents(struct btrfs_root *root,
+                                  u64 bytenr, u64 num, int reserve);
 static int update_block_group(struct btrfs_trans_handle *trans,
                              struct btrfs_root *root,
                              u64 bytenr, u64 num_bytes, int alloc,
                              int mark_free);
+static noinline int __btrfs_free_extent(struct btrfs_trans_handle *trans,
+                                       struct btrfs_root *root,
+                                       u64 bytenr, u64 num_bytes, u64 parent,
+                                       u64 root_objectid, u64 ref_generation,
+                                       u64 owner_objectid, int pin,
+                                       int ref_to_drop);
 
 static int do_chunk_alloc(struct btrfs_trans_handle *trans,
                          struct btrfs_root *extent_root, u64 alloc_bytes,
@@ -554,262 +560,13 @@ out:
        return ret;
 }
 
-/*
- * updates all the backrefs that are pending on update_list for the
- * extent_root
- */
-static noinline int update_backrefs(struct btrfs_trans_handle *trans,
-                                   struct btrfs_root *extent_root,
-                                   struct btrfs_path *path,
-                                   struct list_head *update_list)
-{
-       struct btrfs_key key;
-       struct btrfs_extent_ref *ref;
-       struct btrfs_fs_info *info = extent_root->fs_info;
-       struct pending_extent_op *op;
-       struct extent_buffer *leaf;
-       int ret = 0;
-       struct list_head *cur = update_list->next;
-       u64 ref_objectid;
-       u64 ref_root = extent_root->root_key.objectid;
-
-       op = list_entry(cur, struct pending_extent_op, list);
-
-search:
-       key.objectid = op->bytenr;
-       key.type = BTRFS_EXTENT_REF_KEY;
-       key.offset = op->orig_parent;
-
-       ret = btrfs_search_slot(trans, extent_root, &key, path, 0, 1);
-       BUG_ON(ret);
-
-       leaf = path->nodes[0];
-
-loop:
-       ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_ref);
-
-       ref_objectid = btrfs_ref_objectid(leaf, ref);
-
-       if (btrfs_ref_root(leaf, ref) != ref_root ||
-           btrfs_ref_generation(leaf, ref) != op->orig_generation ||
-           (ref_objectid != op->level &&
-            ref_objectid != BTRFS_MULTIPLE_OBJECTIDS)) {
-               printk(KERN_ERR "btrfs couldn't find %llu, parent %llu, "
-                      "root %llu, owner %u\n",
-                      (unsigned long long)op->bytenr,
-                      (unsigned long long)op->orig_parent,
-                      (unsigned long long)ref_root, op->level);
-               btrfs_print_leaf(extent_root, leaf);
-               BUG();
-       }
-
-       key.objectid = op->bytenr;
-       key.offset = op->parent;
-       key.type = BTRFS_EXTENT_REF_KEY;
-       ret = btrfs_set_item_key_safe(trans, extent_root, path, &key);
-       BUG_ON(ret);
-       ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_ref);
-       btrfs_set_ref_generation(leaf, ref, op->generation);
-
-       cur = cur->next;
-
-       list_del_init(&op->list);
-       unlock_extent(&info->extent_ins, op->bytenr,
-                     op->bytenr + op->num_bytes - 1, GFP_NOFS);
-       kfree(op);
-
-       if (cur == update_list) {
-               btrfs_mark_buffer_dirty(path->nodes[0]);
-               btrfs_release_path(extent_root, path);
-               goto out;
-       }
-
-       op = list_entry(cur, struct pending_extent_op, list);
-
-       path->slots[0]++;
-       while (path->slots[0] < btrfs_header_nritems(leaf)) {
-               btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
-               if (key.objectid == op->bytenr &&
-                   key.type == BTRFS_EXTENT_REF_KEY)
-                       goto loop;
-               path->slots[0]++;
-       }
-
-       btrfs_mark_buffer_dirty(path->nodes[0]);
-       btrfs_release_path(extent_root, path);
-       goto search;
-
-out:
-       return 0;
-}
-
-static noinline int insert_extents(struct btrfs_trans_handle *trans,
-                                  struct btrfs_root *extent_root,
-                                  struct btrfs_path *path,
-                                  struct list_head *insert_list, int nr)
-{
-       struct btrfs_key *keys;
-       u32 *data_size;
-       struct pending_extent_op *op;
-       struct extent_buffer *leaf;
-       struct list_head *cur = insert_list->next;
-       struct btrfs_fs_info *info = extent_root->fs_info;
-       u64 ref_root = extent_root->root_key.objectid;
-       int i = 0, last = 0, ret;
-       int total = nr * 2;
-
-       if (!nr)
-               return 0;
-
-       keys = kzalloc(total * sizeof(struct btrfs_key), GFP_NOFS);
-       if (!keys)
-               return -ENOMEM;
-
-       data_size = kzalloc(total * sizeof(u32), GFP_NOFS);
-       if (!data_size) {
-               kfree(keys);
-               return -ENOMEM;
-       }
-
-       list_for_each_entry(op, insert_list, list) {
-               keys[i].objectid = op->bytenr;
-               keys[i].offset = op->num_bytes;
-               keys[i].type = BTRFS_EXTENT_ITEM_KEY;
-               data_size[i] = sizeof(struct btrfs_extent_item);
-               i++;
-
-               keys[i].objectid = op->bytenr;
-               keys[i].offset = op->parent;
-               keys[i].type = BTRFS_EXTENT_REF_KEY;
-               data_size[i] = sizeof(struct btrfs_extent_ref);
-               i++;
-       }
-
-       op = list_entry(cur, struct pending_extent_op, list);
-       i = 0;
-       while (i < total) {
-               int c;
-               ret = btrfs_insert_some_items(trans, extent_root, path,
-                                             keys+i, data_size+i, total-i);
-               BUG_ON(ret < 0);
-
-               if (last && ret > 1)
-                       BUG();
-
-               leaf = path->nodes[0];
-               for (c = 0; c < ret; c++) {
-                       int ref_first = keys[i].type == BTRFS_EXTENT_REF_KEY;
-
-                       /*
-                        * if the first item we inserted was a backref, then
-                        * the EXTENT_ITEM will be the odd c's, else it will
-                        * be the even c's
-                        */
-                       if ((ref_first && (c % 2)) ||
-                           (!ref_first && !(c % 2))) {
-                               struct btrfs_extent_item *itm;
-
-                               itm = btrfs_item_ptr(leaf, path->slots[0] + c,
-                                                    struct btrfs_extent_item);
-                               btrfs_set_extent_refs(path->nodes[0], itm, 1);
-                               op->del++;
-                       } else {
-                               struct btrfs_extent_ref *ref;
-
-                               ref = btrfs_item_ptr(leaf, path->slots[0] + c,
-                                                    struct btrfs_extent_ref);
-                               btrfs_set_ref_root(leaf, ref, ref_root);
-                               btrfs_set_ref_generation(leaf, ref,
-                                                        op->generation);
-                               btrfs_set_ref_objectid(leaf, ref, op->level);
-                               btrfs_set_ref_num_refs(leaf, ref, 1);
-                               op->del++;
-                       }
-
-                       /*
-                        * using del to see when its ok to free up the
-                        * pending_extent_op.  In the case where we insert the
-                        * last item on the list in order to help do batching
-                        * we need to not free the extent op until we actually
-                        * insert the extent_item
-                        */
-                       if (op->del == 2) {
-                               unlock_extent(&info->extent_ins, op->bytenr,
-                                             op->bytenr + op->num_bytes - 1,
-                                             GFP_NOFS);
-                               cur = cur->next;
-                               list_del_init(&op->list);
-                               kfree(op);
-                               if (cur != insert_list)
-                                       op = list_entry(cur,
-                                               struct pending_extent_op,
-                                               list);
-                       }
-               }
-               btrfs_mark_buffer_dirty(leaf);
-               btrfs_release_path(extent_root, path);
-
-               /*
-                * Ok backref's and items usually go right next to eachother,
-                * but if we could only insert 1 item that means that we
-                * inserted on the end of a leaf, and we have no idea what may
-                * be on the next leaf so we just play it safe.  In order to
-                * try and help this case we insert the last thing on our
-                * insert list so hopefully it will end up being the last
-                * thing on the leaf and everything else will be before it,
-                * which will let us insert a whole bunch of items at the same
-                * time.
-                */
-               if (ret == 1 && !last && (i + ret < total)) {
-                       /*
-                        * last: where we will pick up the next time around
-                        * i: our current key to insert, will be total - 1
-                        * cur: the current op we are screwing with
-                        * op: duh
-                        */
-                       last = i + ret;
-                       i = total - 1;
-                       cur = insert_list->prev;
-                       op = list_entry(cur, struct pending_extent_op, list);
-               } else if (last) {
-                       /*
-                        * ok we successfully inserted the last item on the
-                        * list, lets reset everything
-                        *
-                        * i: our current key to insert, so where we left off
-                        *    last time
-                        * last: done with this
-                        * cur: the op we are messing with
-                        * op: duh
-                        * total: since we inserted the last key, we need to
-                        *        decrement total so we dont overflow
-                        */
-                       i = last;
-                       last = 0;
-                       total--;
-                       if (i < total) {
-                               cur = insert_list->next;
-                               op = list_entry(cur, struct pending_extent_op,
-                                               list);
-                       }
-               } else {
-                       i += ret;
-               }
-
-               cond_resched();
-       }
-       ret = 0;
-       kfree(keys);
-       kfree(data_size);
-       return ret;
-}
-
 static noinline int insert_extent_backref(struct btrfs_trans_handle *trans,
                                          struct btrfs_root *root,
                                          struct btrfs_path *path,
                                          u64 bytenr, u64 parent,
                                          u64 ref_root, u64 ref_generation,
-                                         u64 owner_objectid)
+                                         u64 owner_objectid,
+                                         int refs_to_add)
 {
        struct btrfs_key key;
        struct extent_buffer *leaf;
@@ -829,9 +586,10 @@ static noinline int insert_extent_backref(struct btrfs_trans_handle *trans,
                btrfs_set_ref_root(leaf, ref, ref_root);
                btrfs_set_ref_generation(leaf, ref, ref_generation);
                btrfs_set_ref_objectid(leaf, ref, owner_objectid);
-               btrfs_set_ref_num_refs(leaf, ref, 1);
+               btrfs_set_ref_num_refs(leaf, ref, refs_to_add);
        } else if (ret == -EEXIST) {
                u64 existing_owner;
+
                BUG_ON(owner_objectid < BTRFS_FIRST_FREE_OBJECTID);
                leaf = path->nodes[0];
                ref = btrfs_item_ptr(leaf, path->slots[0],
@@ -845,7 +603,7 @@ static noinline int insert_extent_backref(struct btrfs_trans_handle *trans,
 
                num_refs = btrfs_ref_num_refs(leaf, ref);
                BUG_ON(num_refs == 0);
-               btrfs_set_ref_num_refs(leaf, ref, num_refs + 1);
+               btrfs_set_ref_num_refs(leaf, ref, num_refs + refs_to_add);
 
                existing_owner = btrfs_ref_objectid(leaf, ref);
                if (existing_owner != owner_objectid &&
@@ -857,6 +615,7 @@ static noinline int insert_extent_backref(struct btrfs_trans_handle *trans,
        } else {
                goto out;
        }
+       btrfs_unlock_up_safe(path, 1);
        btrfs_mark_buffer_dirty(path->nodes[0]);
 out:
        btrfs_release_path(root, path);
@@ -865,7 +624,8 @@ out:
 
 static noinline int remove_extent_backref(struct btrfs_trans_handle *trans,
                                          struct btrfs_root *root,
-                                         struct btrfs_path *path)
+                                         struct btrfs_path *path,
+                                         int refs_to_drop)
 {
        struct extent_buffer *leaf;
        struct btrfs_extent_ref *ref;
@@ -875,8 +635,8 @@ static noinline int remove_extent_backref(struct btrfs_trans_handle *trans,
        leaf = path->nodes[0];
        ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_ref);
        num_refs = btrfs_ref_num_refs(leaf, ref);
-       BUG_ON(num_refs == 0);
-       num_refs -= 1;
+       BUG_ON(num_refs < refs_to_drop);
+       num_refs -= refs_to_drop;
        if (num_refs == 0) {
                ret = btrfs_del_item(trans, root, path);
        } else {
@@ -927,332 +687,28 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
 #endif
 }
 
-static noinline int free_extents(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *extent_root,
-                                struct list_head *del_list)
-{
-       struct btrfs_fs_info *info = extent_root->fs_info;
-       struct btrfs_path *path;
-       struct btrfs_key key, found_key;
-       struct extent_buffer *leaf;
-       struct list_head *cur;
-       struct pending_extent_op *op;
-       struct btrfs_extent_item *ei;
-       int ret, num_to_del, extent_slot = 0, found_extent = 0;
-       u32 refs;
-       u64 bytes_freed = 0;
-
-       path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
-       path->reada = 1;
-
-search:
-       /* search for the backref for the current ref we want to delete */
-       cur = del_list->next;
-       op = list_entry(cur, struct pending_extent_op, list);
-       ret = lookup_extent_backref(trans, extent_root, path, op->bytenr,
-                                   op->orig_parent,
-                                   extent_root->root_key.objectid,
-                                   op->orig_generation, op->level, 1);
-       if (ret) {
-               printk(KERN_ERR "btrfs unable to find backref byte nr %llu "
-                      "root %llu gen %llu owner %u\n",
-                      (unsigned long long)op->bytenr,
-                      (unsigned long long)extent_root->root_key.objectid,
-                      (unsigned long long)op->orig_generation, op->level);
-               btrfs_print_leaf(extent_root, path->nodes[0]);
-               WARN_ON(1);
-               goto out;
-       }
-
-       extent_slot = path->slots[0];
-       num_to_del = 1;
-       found_extent = 0;
-
-       /*
-        * if we aren't the first item on the leaf we can move back one and see
-        * if our ref is right next to our extent item
-        */
-       if (likely(extent_slot)) {
-               extent_slot--;
-               btrfs_item_key_to_cpu(path->nodes[0], &found_key,
-                                     extent_slot);
-               if (found_key.objectid == op->bytenr &&
-                   found_key.type == BTRFS_EXTENT_ITEM_KEY &&
-                   found_key.offset == op->num_bytes) {
-                       num_to_del++;
-                       found_extent = 1;
-               }
-       }
-
-       /*
-        * if we didn't find the extent we need to delete the backref and then
-        * search for the extent item key so we can update its ref count
-        */
-       if (!found_extent) {
-               key.objectid = op->bytenr;
-               key.type = BTRFS_EXTENT_ITEM_KEY;
-               key.offset = op->num_bytes;
-
-               ret = remove_extent_backref(trans, extent_root, path);
-               BUG_ON(ret);
-               btrfs_release_path(extent_root, path);
-               ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1);
-               BUG_ON(ret);
-               extent_slot = path->slots[0];
-       }
-
-       /* this is where we update the ref count for the extent */
-       leaf = path->nodes[0];
-       ei = btrfs_item_ptr(leaf, extent_slot, struct btrfs_extent_item);
-       refs = btrfs_extent_refs(leaf, ei);
-       BUG_ON(refs == 0);
-       refs--;
-       btrfs_set_extent_refs(leaf, ei, refs);
-
-       btrfs_mark_buffer_dirty(leaf);
-
-       /*
-        * This extent needs deleting.  The reason cur_slot is extent_slot +
-        * num_to_del is because extent_slot points to the slot where the extent
-        * is, and if the backref was not right next to the extent we will be
-        * deleting at least 1 item, and will want to start searching at the
-        * slot directly next to extent_slot.  However if we did find the
-        * backref next to the extent item them we will be deleting at least 2
-        * items and will want to start searching directly after the ref slot
-        */
-       if (!refs) {
-               struct list_head *pos, *n, *end;
-               int cur_slot = extent_slot+num_to_del;
-               u64 super_used;
-               u64 root_used;
-
-               path->slots[0] = extent_slot;
-               bytes_freed = op->num_bytes;
-
-               mutex_lock(&info->pinned_mutex);
-               ret = pin_down_bytes(trans, extent_root, op->bytenr,
-                                    op->num_bytes, op->level >=
-                                    BTRFS_FIRST_FREE_OBJECTID);
-               mutex_unlock(&info->pinned_mutex);
-               BUG_ON(ret < 0);
-               op->del = ret;
-
-               /*
-                * we need to see if we can delete multiple things at once, so
-                * start looping through the list of extents we are wanting to
-                * delete and see if their extent/backref's are right next to
-                * eachother and the extents only have 1 ref
-                */
-               for (pos = cur->next; pos != del_list; pos = pos->next) {
-                       struct pending_extent_op *tmp;
-
-                       tmp = list_entry(pos, struct pending_extent_op, list);
-
-                       /* we only want to delete extent+ref at this stage */
-                       if (cur_slot >= btrfs_header_nritems(leaf) - 1)
-                               break;
-
-                       btrfs_item_key_to_cpu(leaf, &found_key, cur_slot);
-                       if (found_key.objectid != tmp->bytenr ||
-                           found_key.type != BTRFS_EXTENT_ITEM_KEY ||
-                           found_key.offset != tmp->num_bytes)
-                               break;
-
-                       /* check to make sure this extent only has one ref */
-                       ei = btrfs_item_ptr(leaf, cur_slot,
-                                           struct btrfs_extent_item);
-                       if (btrfs_extent_refs(leaf, ei) != 1)
-                               break;
-
-                       btrfs_item_key_to_cpu(leaf, &found_key, cur_slot+1);
-                       if (found_key.objectid != tmp->bytenr ||
-                           found_key.type != BTRFS_EXTENT_REF_KEY ||
-                           found_key.offset != tmp->orig_parent)
-                               break;
-
-                       /*
-                        * the ref is right next to the extent, we can set the
-                        * ref count to 0 since we will delete them both now
-                        */
-                       btrfs_set_extent_refs(leaf, ei, 0);
-
-                       /* pin down the bytes for this extent */
-                       mutex_lock(&info->pinned_mutex);
-                       ret = pin_down_bytes(trans, extent_root, tmp->bytenr,
-                                            tmp->num_bytes, tmp->level >=
-                                            BTRFS_FIRST_FREE_OBJECTID);
-                       mutex_unlock(&info->pinned_mutex);
-                       BUG_ON(ret < 0);
-
-                       /*
-                        * use the del field to tell if we need to go ahead and
-                        * free up the extent when we delete the item or not.
-                        */
-                       tmp->del = ret;
-                       bytes_freed += tmp->num_bytes;
-
-                       num_to_del += 2;
-                       cur_slot += 2;
-               }
-               end = pos;
-
-               /* update the free space counters */
-               spin_lock(&info->delalloc_lock);
-               super_used = btrfs_super_bytes_used(&info->super_copy);
-               btrfs_set_super_bytes_used(&info->super_copy,
-                                          super_used - bytes_freed);
-
-               root_used = btrfs_root_used(&extent_root->root_item);
-               btrfs_set_root_used(&extent_root->root_item,
-                                   root_used - bytes_freed);
-               spin_unlock(&info->delalloc_lock);
-
-               /* delete the items */
-               ret = btrfs_del_items(trans, extent_root, path,
-                                     path->slots[0], num_to_del);
-               BUG_ON(ret);
-
-               /*
-                * loop through the extents we deleted and do the cleanup work
-                * on them
-                */
-               for (pos = cur, n = pos->next; pos != end;
-                    pos = n, n = pos->next) {
-                       struct pending_extent_op *tmp;
-                       tmp = list_entry(pos, struct pending_extent_op, list);
-
-                       /*
-                        * remember tmp->del tells us wether or not we pinned
-                        * down the extent
-                        */
-                       ret = update_block_group(trans, extent_root,
-                                                tmp->bytenr, tmp->num_bytes, 0,
-                                                tmp->del);
-                       BUG_ON(ret);
-
-                       list_del_init(&tmp->list);
-                       unlock_extent(&info->extent_ins, tmp->bytenr,
-                                     tmp->bytenr + tmp->num_bytes - 1,
-                                     GFP_NOFS);
-                       kfree(tmp);
-               }
-       } else if (refs && found_extent) {
-               /*
-                * the ref and extent were right next to eachother, but the
-                * extent still has a ref, so just free the backref and keep
-                * going
-                */
-               ret = remove_extent_backref(trans, extent_root, path);
-               BUG_ON(ret);
-
-               list_del_init(&op->list);
-               unlock_extent(&info->extent_ins, op->bytenr,
-                             op->bytenr + op->num_bytes - 1, GFP_NOFS);
-               kfree(op);
-       } else {
-               /*
-                * the extent has multiple refs and the backref we were looking
-                * for was not right next to it, so just unlock and go next,
-                * we're good to go
-                */
-               list_del_init(&op->list);
-               unlock_extent(&info->extent_ins, op->bytenr,
-                             op->bytenr + op->num_bytes - 1, GFP_NOFS);
-               kfree(op);
-       }
-
-       btrfs_release_path(extent_root, path);
-       if (!list_empty(del_list))
-               goto search;
-
-out:
-       btrfs_free_path(path);
-       return ret;
-}
-
 static int __btrfs_update_extent_ref(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root, u64 bytenr,
+                                    u64 num_bytes,
                                     u64 orig_parent, u64 parent,
                                     u64 orig_root, u64 ref_root,
                                     u64 orig_generation, u64 ref_generation,
                                     u64 owner_objectid)
 {
        int ret;
-       struct btrfs_root *extent_root = root->fs_info->extent_root;
-       struct btrfs_path *path;
-
-       if (root == root->fs_info->extent_root) {
-               struct pending_extent_op *extent_op;
-               u64 num_bytes;
-
-               BUG_ON(owner_objectid >= BTRFS_MAX_LEVEL);
-               num_bytes = btrfs_level_size(root, (int)owner_objectid);
-               mutex_lock(&root->fs_info->extent_ins_mutex);
-               if (test_range_bit(&root->fs_info->extent_ins, bytenr,
-                               bytenr + num_bytes - 1, EXTENT_WRITEBACK, 0)) {
-                       u64 priv;
-                       ret = get_state_private(&root->fs_info->extent_ins,
-                                               bytenr, &priv);
-                       BUG_ON(ret);
-                       extent_op = (struct pending_extent_op *)
-                                                       (unsigned long)priv;
-                       BUG_ON(extent_op->parent != orig_parent);
-                       BUG_ON(extent_op->generation != orig_generation);
+       int pin = owner_objectid < BTRFS_FIRST_FREE_OBJECTID;
 
-                       extent_op->parent = parent;
-                       extent_op->generation = ref_generation;
-               } else {
-                       extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS);
-                       BUG_ON(!extent_op);
-
-                       extent_op->type = PENDING_BACKREF_UPDATE;
-                       extent_op->bytenr = bytenr;
-                       extent_op->num_bytes = num_bytes;
-                       extent_op->parent = parent;
-                       extent_op->orig_parent = orig_parent;
-                       extent_op->generation = ref_generation;
-                       extent_op->orig_generation = orig_generation;
-                       extent_op->level = (int)owner_objectid;
-                       INIT_LIST_HEAD(&extent_op->list);
-                       extent_op->del = 0;
-
-                       set_extent_bits(&root->fs_info->extent_ins,
-                                       bytenr, bytenr + num_bytes - 1,
-                                       EXTENT_WRITEBACK, GFP_NOFS);
-                       set_state_private(&root->fs_info->extent_ins,
-                                         bytenr, (unsigned long)extent_op);
-               }
-               mutex_unlock(&root->fs_info->extent_ins_mutex);
-               return 0;
-       }
-
-       path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
-       ret = lookup_extent_backref(trans, extent_root, path,
-                                   bytenr, orig_parent, orig_root,
-                                   orig_generation, owner_objectid, 1);
-       if (ret)
-               goto out;
-       ret = remove_extent_backref(trans, extent_root, path);
-       if (ret)
-               goto out;
-       ret = insert_extent_backref(trans, extent_root, path, bytenr,
-                                   parent, ref_root, ref_generation,
-                                   owner_objectid);
+       ret = btrfs_update_delayed_ref(trans, bytenr, num_bytes,
+                                      orig_parent, parent, orig_root,
+                                      ref_root, orig_generation,
+                                      ref_generation, owner_objectid, pin);
        BUG_ON(ret);
-       finish_current_insert(trans, extent_root, 0);
-       del_pending_extents(trans, extent_root, 0);
-out:
-       btrfs_free_path(path);
        return ret;
 }
 
 int btrfs_update_extent_ref(struct btrfs_trans_handle *trans,
                            struct btrfs_root *root, u64 bytenr,
-                           u64 orig_parent, u64 parent,
+                           u64 num_bytes, u64 orig_parent, u64 parent,
                            u64 ref_root, u64 ref_generation,
                            u64 owner_objectid)
 {
@@ -1260,19 +716,35 @@ int btrfs_update_extent_ref(struct btrfs_trans_handle *trans,
        if (ref_root == BTRFS_TREE_LOG_OBJECTID &&
            owner_objectid < BTRFS_FIRST_FREE_OBJECTID)
                return 0;
-       ret = __btrfs_update_extent_ref(trans, root, bytenr, orig_parent,
-                                       parent, ref_root, ref_root,
-                                       ref_generation, ref_generation,
-                                       owner_objectid);
+
+       ret = __btrfs_update_extent_ref(trans, root, bytenr, num_bytes,
+                                       orig_parent, parent, ref_root,
+                                       ref_root, ref_generation,
+                                       ref_generation, owner_objectid);
        return ret;
 }
-
 static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                                  struct btrfs_root *root, u64 bytenr,
+                                 u64 num_bytes,
                                  u64 orig_parent, u64 parent,
                                  u64 orig_root, u64 ref_root,
                                  u64 orig_generation, u64 ref_generation,
                                  u64 owner_objectid)
+{
+       int ret;
+
+       ret = btrfs_add_delayed_ref(trans, bytenr, num_bytes, parent, ref_root,
+                                   ref_generation, owner_objectid,
+                                   BTRFS_ADD_DELAYED_REF, 0);
+       BUG_ON(ret);
+       return ret;
+}
+
+static noinline_for_stack int add_extent_ref(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *root, u64 bytenr,
+                         u64 num_bytes, u64 parent, u64 ref_root,
+                         u64 ref_generation, u64 owner_objectid,
+                         int refs_to_add)
 {
        struct btrfs_path *path;
        int ret;
@@ -1286,17 +758,24 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                return -ENOMEM;
 
        path->reada = 1;
+       path->leave_spinning = 1;
        key.objectid = bytenr;
        key.type = BTRFS_EXTENT_ITEM_KEY;
-       key.offset = (u64)-1;
+       key.offset = num_bytes;
 
-       ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path,
-                               0, 1);
-       if (ret < 0)
+       /* first find the extent item and update its reference count */
+       ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key,
+                               path, 0, 1);
+       if (ret < 0) {
+               btrfs_set_path_blocking(path);
                return ret;
-       BUG_ON(ret == 0 || path->slots[0] == 0);
+       }
 
-       path->slots[0]--;
+       if (ret > 0) {
+               WARN_ON(1);
+               btrfs_free_path(path);
+               return -EIO;
+       }
        l = path->nodes[0];
 
        btrfs_item_key_to_cpu(l, &key, path->slots[0]);
@@ -1310,21 +789,24 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
        BUG_ON(key.type != BTRFS_EXTENT_ITEM_KEY);
 
        item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
+
        refs = btrfs_extent_refs(l, item);
-       btrfs_set_extent_refs(l, item, refs + 1);
+       btrfs_set_extent_refs(l, item, refs + refs_to_add);
+       btrfs_unlock_up_safe(path, 1);
+
        btrfs_mark_buffer_dirty(path->nodes[0]);
 
        btrfs_release_path(root->fs_info->extent_root, path);
 
        path->reada = 1;
+       path->leave_spinning = 1;
+
+       /* now insert the actual backref */
        ret = insert_extent_backref(trans, root->fs_info->extent_root,
                                    path, bytenr, parent,
                                    ref_root, ref_generation,
-                                   owner_objectid);
+                                   owner_objectid, refs_to_add);
        BUG_ON(ret);
-       finish_current_insert(trans, root->fs_info->extent_root, 0);
-       del_pending_extents(trans, root->fs_info->extent_root, 0);
-
        btrfs_free_path(path);
        return 0;
 }
@@ -1339,68 +821,278 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
        if (ref_root == BTRFS_TREE_LOG_OBJECTID &&
            owner_objectid < BTRFS_FIRST_FREE_OBJECTID)
                return 0;
-       ret = __btrfs_inc_extent_ref(trans, root, bytenr, 0, parent,
+
+       ret = __btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0, parent,
                                     0, ref_root, 0, ref_generation,
                                     owner_objectid);
        return ret;
 }
 
-int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
-                        struct btrfs_root *root)
-{
-       u64 start;
-       u64 end;
-       int ret;
+static int drop_delayed_ref(struct btrfs_trans_handle *trans,
+                                       struct btrfs_root *root,
+                                       struct btrfs_delayed_ref_node *node)
+{
+       int ret = 0;
+       struct btrfs_delayed_ref *ref = btrfs_delayed_node_to_ref(node);
+
+       BUG_ON(node->ref_mod == 0);
+       ret = __btrfs_free_extent(trans, root, node->bytenr, node->num_bytes,
+                                 node->parent, ref->root, ref->generation,
+                                 ref->owner_objectid, ref->pin, node->ref_mod);
+
+       return ret;
+}
+
+/* helper function to actually process a single delayed ref entry */
+static noinline int run_one_delayed_ref(struct btrfs_trans_handle *trans,
+                                       struct btrfs_root *root,
+                                       struct btrfs_delayed_ref_node *node,
+                                       int insert_reserved)
+{
+       int ret;
+       struct btrfs_delayed_ref *ref;
+
+       if (node->parent == (u64)-1) {
+               struct btrfs_delayed_ref_head *head;
+               /*
+                * we've hit the end of the chain and we were supposed
+                * to insert this extent into the tree.  But, it got
+                * deleted before we ever needed to insert it, so all
+                * we have to do is clean up the accounting
+                */
+               if (insert_reserved) {
+                       update_reserved_extents(root, node->bytenr,
+                                               node->num_bytes, 0);
+               }
+               head = btrfs_delayed_node_to_head(node);
+               mutex_unlock(&head->mutex);
+               return 0;
+       }
+
+       ref = btrfs_delayed_node_to_ref(node);
+       if (ref->action == BTRFS_ADD_DELAYED_REF) {
+               if (insert_reserved) {
+                       struct btrfs_key ins;
+
+                       ins.objectid = node->bytenr;
+                       ins.offset = node->num_bytes;
+                       ins.type = BTRFS_EXTENT_ITEM_KEY;
+
+                       /* record the full extent allocation */
+                       ret = __btrfs_alloc_reserved_extent(trans, root,
+                                       node->parent, ref->root,
+                                       ref->generation, ref->owner_objectid,
+                                       &ins, node->ref_mod);
+                       update_reserved_extents(root, node->bytenr,
+                                               node->num_bytes, 0);
+               } else {
+                       /* just add one backref */
+                       ret = add_extent_ref(trans, root, node->bytenr,
+                                    node->num_bytes,
+                                    node->parent, ref->root, ref->generation,
+                                    ref->owner_objectid, node->ref_mod);
+               }
+               BUG_ON(ret);
+       } else if (ref->action == BTRFS_DROP_DELAYED_REF) {
+               WARN_ON(insert_reserved);
+               ret = drop_delayed_ref(trans, root, node);
+       }
+       return 0;
+}
+
+static noinline struct btrfs_delayed_ref_node *
+select_delayed_ref(struct btrfs_delayed_ref_head *head)
+{
+       struct rb_node *node;
+       struct btrfs_delayed_ref_node *ref;
+       int action = BTRFS_ADD_DELAYED_REF;
+again:
+       /*
+        * select delayed ref of type BTRFS_ADD_DELAYED_REF first.
+        * this prevents ref count from going down to zero when
+        * there still are pending delayed ref.
+        */
+       node = rb_prev(&head->node.rb_node);
+       while (1) {
+               if (!node)
+                       break;
+               ref = rb_entry(node, struct btrfs_delayed_ref_node,
+                               rb_node);
+               if (ref->bytenr != head->node.bytenr)
+                       break;
+               if (btrfs_delayed_node_to_ref(ref)->action == action)
+                       return ref;
+               node = rb_prev(node);
+       }
+       if (action == BTRFS_ADD_DELAYED_REF) {
+               action = BTRFS_DROP_DELAYED_REF;
+               goto again;
+       }
+       return NULL;
+}
+
+static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
+                                      struct btrfs_root *root,
+                                      struct list_head *cluster)
+{
+       struct btrfs_delayed_ref_root *delayed_refs;
+       struct btrfs_delayed_ref_node *ref;
+       struct btrfs_delayed_ref_head *locked_ref = NULL;
+       int ret;
+       int count = 0;
+       int must_insert_reserved = 0;
+
+       delayed_refs = &trans->transaction->delayed_refs;
+       while (1) {
+               if (!locked_ref) {
+                       /* pick a new head ref from the cluster list */
+                       if (list_empty(cluster))
+                               break;
+
+                       locked_ref = list_entry(cluster->next,
+                                    struct btrfs_delayed_ref_head, cluster);
+
+                       /* grab the lock that says we are going to process
+                        * all the refs for this head */
+                       ret = btrfs_delayed_ref_lock(trans, locked_ref);
+
+                       /*
+                        * we may have dropped the spin lock to get the head
+                        * mutex lock, and that might have given someone else
+                        * time to free the head.  If that's true, it has been
+                        * removed from our list and we can move on.
+                        */
+                       if (ret == -EAGAIN) {
+                               locked_ref = NULL;
+                               count++;
+                               continue;
+                       }
+               }
+
+               /*
+                * record the must insert reserved flag before we
+                * drop the spin lock.
+                */
+               must_insert_reserved = locked_ref->must_insert_reserved;
+               locked_ref->must_insert_reserved = 0;
+
+               /*
+                * locked_ref is the head node, so we have to go one
+                * node back for any delayed ref updates
+                */
+               ref = select_delayed_ref(locked_ref);
+               if (!ref) {
+                       /* All delayed refs have been processed, Go ahead
+                        * and send the head node to run_one_delayed_ref,
+                        * so that any accounting fixes can happen
+                        */
+                       ref = &locked_ref->node;
+                       list_del_init(&locked_ref->cluster);
+                       locked_ref = NULL;
+               }
+
+               ref->in_tree = 0;
+               rb_erase(&ref->rb_node, &delayed_refs->root);
+               delayed_refs->num_entries--;
+               spin_unlock(&delayed_refs->lock);
+
+               ret = run_one_delayed_ref(trans, root, ref,
+                                         must_insert_reserved);
+               BUG_ON(ret);
+               btrfs_put_delayed_ref(ref);
+
+               count++;
+               cond_resched();
+               spin_lock(&delayed_refs->lock);
+       }
+       return count;
+}
+
+/*
+ * this starts processing the delayed reference count updates and
+ * extent insertions we have queued up so far.  count can be
+ * 0, which means to process everything in the tree at the start
+ * of the run (but not newly added entries), or it can be some target
+ * number you'd like to process.
+ */
+int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
+                          struct btrfs_root *root, unsigned long count)
+{
+       struct rb_node *node;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       struct btrfs_delayed_ref_node *ref;
+       struct list_head cluster;
+       int ret;
+       int run_all = count == (unsigned long)-1;
+       int run_most = 0;
+
+       if (root == root->fs_info->extent_root)
+               root = root->fs_info->tree_root;
+
+       delayed_refs = &trans->transaction->delayed_refs;
+       INIT_LIST_HEAD(&cluster);
+again:
+       spin_lock(&delayed_refs->lock);
+       if (count == 0) {
+               count = delayed_refs->num_entries * 2;
+               run_most = 1;
+       }
+       while (1) {
+               if (!(run_all || run_most) &&
+                   delayed_refs->num_heads_ready < 64)
+                       break;
+
+               /*
+                * go find something we can process in the rbtree.  We start at
+                * the beginning of the tree, and then build a cluster
+                * of refs to process starting at the first one we are able to
+                * lock
+                */
+               ret = btrfs_find_ref_cluster(trans, &cluster,
+                                            delayed_refs->run_delayed_start);
+               if (ret)
+                       break;
+
+               ret = run_clustered_refs(trans, root, &cluster);
+               BUG_ON(ret < 0);
 
-       while(1) {
-               finish_current_insert(trans, root->fs_info->extent_root, 1);
-               del_pending_extents(trans, root->fs_info->extent_root, 1);
+               count -= min_t(unsigned long, ret, count);
 
-               /* is there more work to do? */
-               ret = find_first_extent_bit(&root->fs_info->pending_del,
-                                           0, &start, &end, EXTENT_WRITEBACK);
-               if (!ret)
-                       continue;
-               ret = find_first_extent_bit(&root->fs_info->extent_ins,
-                                           0, &start, &end, EXTENT_WRITEBACK);
-               if (!ret)
-                       continue;
-               break;
+               if (count == 0)
+                       break;
        }
-       return 0;
-}
 
-int btrfs_lookup_extent_ref(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root, u64 bytenr,
-                           u64 num_bytes, u32 *refs)
-{
-       struct btrfs_path *path;
-       int ret;
-       struct btrfs_key key;
-       struct extent_buffer *l;
-       struct btrfs_extent_item *item;
+       if (run_all) {
+               node = rb_first(&delayed_refs->root);
+               if (!node)
+                       goto out;
+               count = (unsigned long)-1;
 
-       WARN_ON(num_bytes < root->sectorsize);
-       path = btrfs_alloc_path();
-       path->reada = 1;
-       key.objectid = bytenr;
-       key.offset = num_bytes;
-       btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
-       ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path,
-                               0, 0);
-       if (ret < 0)
-               goto out;
-       if (ret != 0) {
-               btrfs_print_leaf(root, path->nodes[0]);
-               printk(KERN_INFO "btrfs failed to find block number %llu\n",
-                      (unsigned long long)bytenr);
-               BUG();
+               while (node) {
+                       ref = rb_entry(node, struct btrfs_delayed_ref_node,
+                                      rb_node);
+                       if (btrfs_delayed_ref_is_head(ref)) {
+                               struct btrfs_delayed_ref_head *head;
+
+                               head = btrfs_delayed_node_to_head(ref);
+                               atomic_inc(&ref->refs);
+
+                               spin_unlock(&delayed_refs->lock);
+                               mutex_lock(&head->mutex);
+                               mutex_unlock(&head->mutex);
+
+                               btrfs_put_delayed_ref(ref);
+                               cond_resched();
+                               goto again;
+                       }
+                       node = rb_next(node);
+               }
+               spin_unlock(&delayed_refs->lock);
+               schedule_timeout(1);
+               goto again;
        }
-       l = path->nodes[0];
-       item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
-       *refs = btrfs_extent_refs(l, item);
 out:
-       btrfs_free_path(path);
+       spin_unlock(&delayed_refs->lock);
        return 0;
 }
 
@@ -1624,7 +1316,7 @@ noinline int btrfs_inc_ref(struct btrfs_trans_handle *trans,
        int refi = 0;
        int slot;
        int (*process_func)(struct btrfs_trans_handle *, struct btrfs_root *,
-                           u64, u64, u64, u64, u64, u64, u64, u64);
+                           u64, u64, u64, u64, u64, u64, u64, u64, u64);
 
        ref_root = btrfs_header_owner(buf);
        ref_generation = btrfs_header_generation(buf);
@@ -1696,12 +1388,19 @@ noinline int btrfs_inc_ref(struct btrfs_trans_handle *trans,
 
                if (level == 0) {
                        btrfs_item_key_to_cpu(buf, &key, slot);
+                       fi = btrfs_item_ptr(buf, slot,
+                                           struct btrfs_file_extent_item);
+
+                       bytenr = btrfs_file_extent_disk_bytenr(buf, fi);
+                       if (bytenr == 0)
+                               continue;
 
                        ret = process_func(trans, root, bytenr,
-                                          orig_buf->start, buf->start,
-                                          orig_root, ref_root,
-                                          orig_generation, ref_generation,
-                                          key.objectid);
+                                  btrfs_file_extent_disk_num_bytes(buf, fi),
+                                  orig_buf->start, buf->start,
+                                  orig_root, ref_root,
+                                  orig_generation, ref_generation,
+                                  key.objectid);
 
                        if (ret) {
                                faili = slot;
@@ -1709,7 +1408,7 @@ noinline int btrfs_inc_ref(struct btrfs_trans_handle *trans,
                                goto fail;
                        }
                } else {
-                       ret = process_func(trans, root, bytenr,
+                       ret = process_func(trans, root, bytenr, buf->len,
                                           orig_buf->start, buf->start,
                                           orig_root, ref_root,
                                           orig_generation, ref_generation,
@@ -1786,17 +1485,17 @@ int btrfs_update_ref(struct btrfs_trans_handle *trans,
                        if (bytenr == 0)
                                continue;
                        ret = __btrfs_update_extent_ref(trans, root, bytenr,
-                                           orig_buf->start, buf->start,
-                                           orig_root, ref_root,
-                                           orig_generation, ref_generation,
-                                           key.objectid);
+                                   btrfs_file_extent_disk_num_bytes(buf, fi),
+                                   orig_buf->start, buf->start,
+                                   orig_root, ref_root, orig_generation,
+                                   ref_generation, key.objectid);
                        if (ret)
                                goto fail;
                } else {
                        bytenr = btrfs_node_blockptr(buf, slot);
                        ret = __btrfs_update_extent_ref(trans, root, bytenr,
-                                           orig_buf->start, buf->start,
-                                           orig_root, ref_root,
+                                           buf->len, orig_buf->start,
+                                           buf->start, orig_root, ref_root,
                                            orig_generation, ref_generation,
                                            level - 1);
                        if (ret)
@@ -1815,7 +1514,6 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
                                 struct btrfs_block_group_cache *cache)
 {
        int ret;
-       int pending_ret;
        struct btrfs_root *extent_root = root->fs_info->extent_root;
        unsigned long bi;
        struct extent_buffer *leaf;
@@ -1831,12 +1529,8 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(leaf);
        btrfs_release_path(extent_root, path);
 fail:
-       finish_current_insert(trans, extent_root, 0);
-       pending_ret = del_pending_extents(trans, extent_root, 0);
        if (ret)
                return ret;
-       if (pending_ret)
-               return pending_ret;
        return 0;
 
 }
@@ -2361,6 +2055,8 @@ int btrfs_update_pinned_extents(struct btrfs_root *root,
                clear_extent_dirty(&fs_info->pinned_extents,
                                bytenr, bytenr + num - 1, GFP_NOFS);
        }
+       mutex_unlock(&root->fs_info->pinned_mutex);
+
        while (num > 0) {
                cache = btrfs_lookup_block_group(fs_info, bytenr);
                BUG_ON(!cache);
@@ -2452,8 +2148,8 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
        u64 end;
        int ret;
 
-       mutex_lock(&root->fs_info->pinned_mutex);
        while (1) {
+               mutex_lock(&root->fs_info->pinned_mutex);
                ret = find_first_extent_bit(unpin, 0, &start, &end,
                                            EXTENT_DIRTY);
                if (ret)
@@ -2461,209 +2157,21 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
 
                ret = btrfs_discard_extent(root, start, end + 1 - start);
 
+               /* unlocks the pinned mutex */
                btrfs_update_pinned_extents(root, start, end + 1 - start, 0);
                clear_extent_dirty(unpin, start, end, GFP_NOFS);
 
-               if (need_resched()) {
-                       mutex_unlock(&root->fs_info->pinned_mutex);
-                       cond_resched();
-                       mutex_lock(&root->fs_info->pinned_mutex);
-               }
+               cond_resched();
        }
        mutex_unlock(&root->fs_info->pinned_mutex);
        return ret;
 }
 
-static int finish_current_insert(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *extent_root, int all)
-{
-       u64 start;
-       u64 end;
-       u64 priv;
-       u64 search = 0;
-       struct btrfs_fs_info *info = extent_root->fs_info;
-       struct btrfs_path *path;
-       struct pending_extent_op *extent_op, *tmp;
-       struct list_head insert_list, update_list;
-       int ret;
-       int num_inserts = 0, max_inserts, restart = 0;
-
-       path = btrfs_alloc_path();
-       INIT_LIST_HEAD(&insert_list);
-       INIT_LIST_HEAD(&update_list);
-
-       max_inserts = extent_root->leafsize /
-               (2 * sizeof(struct btrfs_key) + 2 * sizeof(struct btrfs_item) +
-                sizeof(struct btrfs_extent_ref) +
-                sizeof(struct btrfs_extent_item));
-again:
-       mutex_lock(&info->extent_ins_mutex);
-       while (1) {
-               ret = find_first_extent_bit(&info->extent_ins, search, &start,
-                                           &end, EXTENT_WRITEBACK);
-               if (ret) {
-                       if (restart && !num_inserts &&
-                           list_empty(&update_list)) {
-                               restart = 0;
-                               search = 0;
-                               continue;
-                       }
-                       break;
-               }
-
-               ret = try_lock_extent(&info->extent_ins, start, end, GFP_NOFS);
-               if (!ret) {
-                       if (all)
-                               restart = 1;
-                       search = end + 1;
-                       if (need_resched()) {
-                               mutex_unlock(&info->extent_ins_mutex);
-                               cond_resched();
-                               mutex_lock(&info->extent_ins_mutex);
-                       }
-                       continue;
-               }
-
-               ret = get_state_private(&info->extent_ins, start, &priv);
-               BUG_ON(ret);
-               extent_op = (struct pending_extent_op *)(unsigned long) priv;
-
-               if (extent_op->type == PENDING_EXTENT_INSERT) {
-                       num_inserts++;
-                       list_add_tail(&extent_op->list, &insert_list);
-                       search = end + 1;
-                       if (num_inserts == max_inserts) {
-                               restart = 1;
-                               break;
-                       }
-               } else if (extent_op->type == PENDING_BACKREF_UPDATE) {
-                       list_add_tail(&extent_op->list, &update_list);
-                       search = end + 1;
-               } else {
-                       BUG();
-               }
-       }
-
-       /*
-        * process the update list, clear the writeback bit for it, and if
-        * somebody marked this thing for deletion then just unlock it and be
-        * done, the free_extents will handle it
-        */
-       list_for_each_entry_safe(extent_op, tmp, &update_list, list) {
-               clear_extent_bits(&info->extent_ins, extent_op->bytenr,
-                                 extent_op->bytenr + extent_op->num_bytes - 1,
-                                 EXTENT_WRITEBACK, GFP_NOFS);
-               if (extent_op->del) {
-                       list_del_init(&extent_op->list);
-                       unlock_extent(&info->extent_ins, extent_op->bytenr,
-                                     extent_op->bytenr + extent_op->num_bytes
-                                     - 1, GFP_NOFS);
-                       kfree(extent_op);
-               }
-       }
-       mutex_unlock(&info->extent_ins_mutex);
-
-       /*
-        * still have things left on the update list, go ahead an update
-        * everything
-        */
-       if (!list_empty(&update_list)) {
-               ret = update_backrefs(trans, extent_root, path, &update_list);
-               BUG_ON(ret);
-
-               /* we may have COW'ed new blocks, so lets start over */
-               if (all)
-                       restart = 1;
-       }
-
-       /*
-        * if no inserts need to be done, but we skipped some extents and we
-        * need to make sure everything is cleaned then reset everything and
-        * go back to the beginning
-        */
-       if (!num_inserts && restart) {
-               search = 0;
-               restart = 0;
-               INIT_LIST_HEAD(&update_list);
-               INIT_LIST_HEAD(&insert_list);
-               goto again;
-       } else if (!num_inserts) {
-               goto out;
-       }
-
-       /*
-        * process the insert extents list.  Again if we are deleting this
-        * extent, then just unlock it, pin down the bytes if need be, and be
-        * done with it.  Saves us from having to actually insert the extent
-        * into the tree and then subsequently come along and delete it
-        */
-       mutex_lock(&info->extent_ins_mutex);
-       list_for_each_entry_safe(extent_op, tmp, &insert_list, list) {
-               clear_extent_bits(&info->extent_ins, extent_op->bytenr,
-                                 extent_op->bytenr + extent_op->num_bytes - 1,
-                                 EXTENT_WRITEBACK, GFP_NOFS);
-               if (extent_op->del) {
-                       u64 used;
-                       list_del_init(&extent_op->list);
-                       unlock_extent(&info->extent_ins, extent_op->bytenr,
-                                     extent_op->bytenr + extent_op->num_bytes
-                                     - 1, GFP_NOFS);
-
-                       mutex_lock(&extent_root->fs_info->pinned_mutex);
-                       ret = pin_down_bytes(trans, extent_root,
-                                            extent_op->bytenr,
-                                            extent_op->num_bytes, 0);
-                       mutex_unlock(&extent_root->fs_info->pinned_mutex);
-
-                       spin_lock(&info->delalloc_lock);
-                       used = btrfs_super_bytes_used(&info->super_copy);
-                       btrfs_set_super_bytes_used(&info->super_copy,
-                                       used - extent_op->num_bytes);
-                       used = btrfs_root_used(&extent_root->root_item);
-                       btrfs_set_root_used(&extent_root->root_item,
-                                       used - extent_op->num_bytes);
-                       spin_unlock(&info->delalloc_lock);
-
-                       ret = update_block_group(trans, extent_root,
-                                                extent_op->bytenr,
-                                                extent_op->num_bytes,
-                                                0, ret > 0);
-                       BUG_ON(ret);
-                       kfree(extent_op);
-                       num_inserts--;
-               }
-       }
-       mutex_unlock(&info->extent_ins_mutex);
-
-       ret = insert_extents(trans, extent_root, path, &insert_list,
-                            num_inserts);
-       BUG_ON(ret);
-
-       /*
-        * if restart is set for whatever reason we need to go back and start
-        * searching through the pending list again.
-        *
-        * We just inserted some extents, which could have resulted in new
-        * blocks being allocated, which would result in new blocks needing
-        * updates, so if all is set we _must_ restart to get the updated
-        * blocks.
-        */
-       if (restart || all) {
-               INIT_LIST_HEAD(&insert_list);
-               INIT_LIST_HEAD(&update_list);
-               search = 0;
-               restart = 0;
-               num_inserts = 0;
-               goto again;
-       }
-out:
-       btrfs_free_path(path);
-       return 0;
-}
-
 static int pin_down_bytes(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root,
-                         u64 bytenr, u64 num_bytes, int is_data)
+                         struct btrfs_path *path,
+                         u64 bytenr, u64 num_bytes, int is_data,
+                         struct extent_buffer **must_clean)
 {
        int err = 0;
        struct extent_buffer *buf;
@@ -2686,17 +2194,19 @@ static int pin_down_bytes(struct btrfs_trans_handle *trans,
                u64 header_transid = btrfs_header_generation(buf);
                if (header_owner != BTRFS_TREE_LOG_OBJECTID &&
                    header_owner != BTRFS_TREE_RELOC_OBJECTID &&
+                   header_owner != BTRFS_DATA_RELOC_TREE_OBJECTID &&
                    header_transid == trans->transid &&
                    !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
-                       clean_tree_block(NULL, root, buf);
-                       btrfs_tree_unlock(buf);
-                       free_extent_buffer(buf);
+                       *must_clean = buf;
                        return 1;
                }
                btrfs_tree_unlock(buf);
        }
        free_extent_buffer(buf);
 pinit:
+       btrfs_set_path_blocking(path);
+       mutex_lock(&root->fs_info->pinned_mutex);
+       /* unlocks the pinned mutex */
        btrfs_update_pinned_extents(root, bytenr, num_bytes, 1);
 
        BUG_ON(err < 0);
@@ -2710,7 +2220,8 @@ static int __free_extent(struct btrfs_trans_handle *trans,
                         struct btrfs_root *root,
                         u64 bytenr, u64 num_bytes, u64 parent,
                         u64 root_objectid, u64 ref_generation,
-                        u64 owner_objectid, int pin, int mark_free)
+                        u64 owner_objectid, int pin, int mark_free,
+                        int refs_to_drop)
 {
        struct btrfs_path *path;
        struct btrfs_key key;
@@ -2732,6 +2243,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
                return -ENOMEM;
 
        path->reada = 1;
+       path->leave_spinning = 1;
        ret = lookup_extent_backref(trans, extent_root, path,
                                    bytenr, parent, root_objectid,
                                    ref_generation, owner_objectid, 1);
@@ -2753,9 +2265,11 @@ static int __free_extent(struct btrfs_trans_handle *trans,
                                break;
                }
                if (!found_extent) {
-                       ret = remove_extent_backref(trans, extent_root, path);
+                       ret = remove_extent_backref(trans, extent_root, path,
+                                                   refs_to_drop);
                        BUG_ON(ret);
                        btrfs_release_path(extent_root, path);
+                       path->leave_spinning = 1;
                        ret = btrfs_search_slot(trans, extent_root,
                                                &key, path, -1, 1);
                        if (ret) {
@@ -2771,8 +2285,9 @@ static int __free_extent(struct btrfs_trans_handle *trans,
                btrfs_print_leaf(extent_root, path->nodes[0]);
                WARN_ON(1);
                printk(KERN_ERR "btrfs unable to find ref byte nr %llu "
-                      "root %llu gen %llu owner %llu\n",
+                      "parent %llu root %llu gen %llu owner %llu\n",
                       (unsigned long long)bytenr,
+                      (unsigned long long)parent,
                       (unsigned long long)root_objectid,
                       (unsigned long long)ref_generation,
                       (unsigned long long)owner_objectid);
@@ -2782,17 +2297,23 @@ static int __free_extent(struct btrfs_trans_handle *trans,
        ei = btrfs_item_ptr(leaf, extent_slot,
                            struct btrfs_extent_item);
        refs = btrfs_extent_refs(leaf, ei);
-       BUG_ON(refs == 0);
-       refs -= 1;
-       btrfs_set_extent_refs(leaf, ei, refs);
 
+       /*
+        * we're not allowed to delete the extent item if there
+        * are other delayed ref updates pending
+        */
+
+       BUG_ON(refs < refs_to_drop);
+       refs -= refs_to_drop;
+       btrfs_set_extent_refs(leaf, ei, refs);
        btrfs_mark_buffer_dirty(leaf);
 
-       if (refs == 0 && found_extent && path->slots[0] == extent_slot + 1) {
+       if (refs == 0 && found_extent &&
+           path->slots[0] == extent_slot + 1) {
                struct btrfs_extent_ref *ref;
                ref = btrfs_item_ptr(leaf, path->slots[0],
                                     struct btrfs_extent_ref);
-               BUG_ON(btrfs_ref_num_refs(leaf, ref) != 1);
+               BUG_ON(btrfs_ref_num_refs(leaf, ref) != refs_to_drop);
                /* if the back ref and the extent are next to each other
                 * they get deleted below in one shot
                 */
@@ -2800,11 +2321,13 @@ static int __free_extent(struct btrfs_trans_handle *trans,
                num_to_del = 2;
        } else if (found_extent) {
                /* otherwise delete the extent back ref */
-               ret = remove_extent_backref(trans, extent_root, path);
+               ret = remove_extent_backref(trans, extent_root, path,
+                                           refs_to_drop);
                BUG_ON(ret);
                /* if refs are 0, we need to setup the path for deletion */
                if (refs == 0) {
                        btrfs_release_path(extent_root, path);
+                       path->leave_spinning = 1;
                        ret = btrfs_search_slot(trans, extent_root, &key, path,
                                                -1, 1);
                        BUG_ON(ret);
@@ -2814,16 +2337,18 @@ static int __free_extent(struct btrfs_trans_handle *trans,
        if (refs == 0) {
                u64 super_used;
                u64 root_used;
+               struct extent_buffer *must_clean = NULL;
 
                if (pin) {
-                       mutex_lock(&root->fs_info->pinned_mutex);
-                       ret = pin_down_bytes(trans, root, bytenr, num_bytes,
-                               owner_objectid >= BTRFS_FIRST_FREE_OBJECTID);
-                       mutex_unlock(&root->fs_info->pinned_mutex);
+                       ret = pin_down_bytes(trans, root, path,
+                               bytenr, num_bytes,
+                               owner_objectid >= BTRFS_FIRST_FREE_OBJECTID,
+                               &must_clean);
                        if (ret > 0)
                                mark_free = 1;
                        BUG_ON(ret < 0);
                }
+
                /* block accounting for super block */
                spin_lock(&info->delalloc_lock);
                super_used = btrfs_super_bytes_used(&info->super_copy);
@@ -2835,14 +2360,34 @@ static int __free_extent(struct btrfs_trans_handle *trans,
                btrfs_set_root_used(&root->root_item,
                                           root_used - num_bytes);
                spin_unlock(&info->delalloc_lock);
+
+               /*
+                * it is going to be very rare for someone to be waiting
+                * on the block we're freeing.  del_items might need to
+                * schedule, so rather than get fancy, just force it
+                * to blocking here
+                */
+               if (must_clean)
+                       btrfs_set_lock_blocking(must_clean);
+
                ret = btrfs_del_items(trans, extent_root, path, path->slots[0],
                                      num_to_del);
                BUG_ON(ret);
                btrfs_release_path(extent_root, path);
 
+               if (must_clean) {
+                       clean_tree_block(NULL, root, must_clean);
+                       btrfs_tree_unlock(must_clean);
+                       free_extent_buffer(must_clean);
+               }
+
                if (owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) {
                        ret = btrfs_del_csums(trans, root, bytenr, num_bytes);
                        BUG_ON(ret);
+               } else {
+                       invalidate_mapping_pages(info->btree_inode->i_mapping,
+                            bytenr >> PAGE_CACHE_SHIFT,
+                            (bytenr + num_bytes - 1) >> PAGE_CACHE_SHIFT);
                }
 
                ret = update_block_group(trans, root, bytenr, num_bytes, 0,
@@ -2850,218 +2395,103 @@ static int __free_extent(struct btrfs_trans_handle *trans,
                BUG_ON(ret);
        }
        btrfs_free_path(path);
-       finish_current_insert(trans, extent_root, 0);
        return ret;
 }
 
 /*
- * find all the blocks marked as pending in the radix tree and remove
- * them from the extent map
+ * remove an extent from the root, returns 0 on success
  */
-static int del_pending_extents(struct btrfs_trans_handle *trans,
-                              struct btrfs_root *extent_root, int all)
+static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
+                                       struct btrfs_root *root,
+                                       u64 bytenr, u64 num_bytes, u64 parent,
+                                       u64 root_objectid, u64 ref_generation,
+                                       u64 owner_objectid, int pin,
+                                       int refs_to_drop)
 {
-       int ret;
-       int err = 0;
-       u64 start;
-       u64 end;
-       u64 priv;
-       u64 search = 0;
-       int nr = 0, skipped = 0;
-       struct extent_io_tree *pending_del;
-       struct extent_io_tree *extent_ins;
-       struct pending_extent_op *extent_op;
-       struct btrfs_fs_info *info = extent_root->fs_info;
-       struct list_head delete_list;
-
-       INIT_LIST_HEAD(&delete_list);
-       extent_ins = &extent_root->fs_info->extent_ins;
-       pending_del = &extent_root->fs_info->pending_del;
-
-again:
-       mutex_lock(&info->extent_ins_mutex);
-       while (1) {
-               ret = find_first_extent_bit(pending_del, search, &start, &end,
-                                           EXTENT_WRITEBACK);
-               if (ret) {
-                       if (all && skipped && !nr) {
-                               search = 0;
-                               skipped = 0;
-                               continue;
-                       }
-                       mutex_unlock(&info->extent_ins_mutex);
-                       break;
-               }
-
-               ret = try_lock_extent(extent_ins, start, end, GFP_NOFS);
-               if (!ret) {
-                       search = end+1;
-                       skipped = 1;
-
-                       if (need_resched()) {
-                               mutex_unlock(&info->extent_ins_mutex);
-                               cond_resched();
-                               mutex_lock(&info->extent_ins_mutex);
-                       }
-
-                       continue;
-               }
-               BUG_ON(ret < 0);
-
-               ret = get_state_private(pending_del, start, &priv);
-               BUG_ON(ret);
-               extent_op = (struct pending_extent_op *)(unsigned long)priv;
-
-               clear_extent_bits(pending_del, start, end, EXTENT_WRITEBACK,
-                                 GFP_NOFS);
-               if (!test_range_bit(extent_ins, start, end,
-                                   EXTENT_WRITEBACK, 0)) {
-                       list_add_tail(&extent_op->list, &delete_list);
-                       nr++;
-               } else {
-                       kfree(extent_op);
-
-                       ret = get_state_private(&info->extent_ins, start,
-                                               &priv);
-                       BUG_ON(ret);
-                       extent_op = (struct pending_extent_op *)
-                                               (unsigned long)priv;
-
-                       clear_extent_bits(&info->extent_ins, start, end,
-                                         EXTENT_WRITEBACK, GFP_NOFS);
-
-                       if (extent_op->type == PENDING_BACKREF_UPDATE) {
-                               list_add_tail(&extent_op->list, &delete_list);
-                               search = end + 1;
-                               nr++;
-                               continue;
-                       }
-
-                       mutex_lock(&extent_root->fs_info->pinned_mutex);
-                       ret = pin_down_bytes(trans, extent_root, start,
-                                            end + 1 - start, 0);
-                       mutex_unlock(&extent_root->fs_info->pinned_mutex);
-
-                       ret = update_block_group(trans, extent_root, start,
-                                               end + 1 - start, 0, ret > 0);
-
-                       unlock_extent(extent_ins, start, end, GFP_NOFS);
-                       BUG_ON(ret);
-                       kfree(extent_op);
-               }
-               if (ret)
-                       err = ret;
-
-               search = end + 1;
-
-               if (need_resched()) {
-                       mutex_unlock(&info->extent_ins_mutex);
-                       cond_resched();
-                       mutex_lock(&info->extent_ins_mutex);
-               }
-       }
+       WARN_ON(num_bytes < root->sectorsize);
 
-       if (nr) {
-               ret = free_extents(trans, extent_root, &delete_list);
-               BUG_ON(ret);
-       }
+       /*
+        * if metadata always pin
+        * if data pin when any transaction has committed this
+        */
+       if (owner_objectid < BTRFS_FIRST_FREE_OBJECTID ||
+           ref_generation != trans->transid)
+               pin = 1;
 
-       if (all && skipped) {
-               INIT_LIST_HEAD(&delete_list);
-               search = 0;
-               nr = 0;
-               goto again;
-       }
+       if (ref_generation != trans->transid)
+               pin = 1;
 
-       if (!err)
-               finish_current_insert(trans, extent_root, 0);
-       return err;
+       return __free_extent(trans, root, bytenr, num_bytes, parent,
+                           root_objectid, ref_generation,
+                           owner_objectid, pin, pin == 0, refs_to_drop);
 }
 
 /*
- * remove an extent from the root, returns 0 on success
+ * when we free an extent, it is possible (and likely) that we free the last
+ * delayed ref for that extent as well.  This searches the delayed ref tree for
+ * a given extent, and if there are no other delayed refs to be processed, it
+ * removes it from the tree.
  */
-static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
-                              struct btrfs_root *root,
-                              u64 bytenr, u64 num_bytes, u64 parent,
-                              u64 root_objectid, u64 ref_generation,
-                              u64 owner_objectid, int pin)
+static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,
+                                     struct btrfs_root *root, u64 bytenr)
 {
-       struct btrfs_root *extent_root = root->fs_info->extent_root;
-       int pending_ret;
+       struct btrfs_delayed_ref_head *head;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       struct btrfs_delayed_ref_node *ref;
+       struct rb_node *node;
        int ret;
 
-       WARN_ON(num_bytes < root->sectorsize);
-       if (root == extent_root) {
-               struct pending_extent_op *extent_op = NULL;
-
-               mutex_lock(&root->fs_info->extent_ins_mutex);
-               if (test_range_bit(&root->fs_info->extent_ins, bytenr,
-                               bytenr + num_bytes - 1, EXTENT_WRITEBACK, 0)) {
-                       u64 priv;
-                       ret = get_state_private(&root->fs_info->extent_ins,
-                                               bytenr, &priv);
-                       BUG_ON(ret);
-                       extent_op = (struct pending_extent_op *)
-                                               (unsigned long)priv;
+       delayed_refs = &trans->transaction->delayed_refs;
+       spin_lock(&delayed_refs->lock);
+       head = btrfs_find_delayed_ref_head(trans, bytenr);
+       if (!head)
+               goto out;
 
-                       extent_op->del = 1;
-                       if (extent_op->type == PENDING_EXTENT_INSERT) {
-                               mutex_unlock(&root->fs_info->extent_ins_mutex);
-                               return 0;
-                       }
-               }
+       node = rb_prev(&head->node.rb_node);
+       if (!node)
+               goto out;
 
-               if (extent_op) {
-                       ref_generation = extent_op->orig_generation;
-                       parent = extent_op->orig_parent;
-               }
+       ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
 
-               extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS);
-               BUG_ON(!extent_op);
-
-               extent_op->type = PENDING_EXTENT_DELETE;
-               extent_op->bytenr = bytenr;
-               extent_op->num_bytes = num_bytes;
-               extent_op->parent = parent;
-               extent_op->orig_parent = parent;
-               extent_op->generation = ref_generation;
-               extent_op->orig_generation = ref_generation;
-               extent_op->level = (int)owner_objectid;
-               INIT_LIST_HEAD(&extent_op->list);
-               extent_op->del = 0;
-
-               set_extent_bits(&root->fs_info->pending_del,
-                               bytenr, bytenr + num_bytes - 1,
-                               EXTENT_WRITEBACK, GFP_NOFS);
-               set_state_private(&root->fs_info->pending_del,
-                                 bytenr, (unsigned long)extent_op);
-               mutex_unlock(&root->fs_info->extent_ins_mutex);
-               return 0;
-       }
-       /* if metadata always pin */
-       if (owner_objectid < BTRFS_FIRST_FREE_OBJECTID) {
-               if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) {
-                       mutex_lock(&root->fs_info->pinned_mutex);
-                       btrfs_update_pinned_extents(root, bytenr, num_bytes, 1);
-                       mutex_unlock(&root->fs_info->pinned_mutex);
-                       update_reserved_extents(root, bytenr, num_bytes, 0);
-                       return 0;
-               }
-               pin = 1;
-       }
+       /* there are still entries for this ref, we can't drop it */
+       if (ref->bytenr == bytenr)
+               goto out;
 
-       /* if data pin when any transaction has committed this */
-       if (ref_generation != trans->transid)
-               pin = 1;
+       /*
+        * waiting for the lock here would deadlock.  If someone else has it
+        * locked they are already in the process of dropping it anyway
+        */
+       if (!mutex_trylock(&head->mutex))
+               goto out;
 
-       ret = __free_extent(trans, root, bytenr, num_bytes, parent,
-                           root_objectid, ref_generation,
-                           owner_objectid, pin, pin == 0);
+       /*
+        * at this point we have a head with no other entries.  Go
+        * ahead and process it.
+        */
+       head->node.in_tree = 0;
+       rb_erase(&head->node.rb_node, &delayed_refs->root);
+
+       delayed_refs->num_entries--;
 
-       finish_current_insert(trans, root->fs_info->extent_root, 0);
-       pending_ret = del_pending_extents(trans, root->fs_info->extent_root, 0);
-       return ret ? ret : pending_ret;
+       /*
+        * we don't take a ref on the node because we're removing it from the
+        * tree, so we just steal the ref the tree was holding.
+        */
+       delayed_refs->num_heads--;
+       if (list_empty(&head->cluster))
+               delayed_refs->num_heads_ready--;
+
+       list_del_init(&head->cluster);
+       spin_unlock(&delayed_refs->lock);
+
+       ret = run_one_delayed_ref(trans, root->fs_info->tree_root,
+                                 &head->node, head->must_insert_reserved);
+       BUG_ON(ret);
+       btrfs_put_delayed_ref(&head->node);
+       return 0;
+out:
+       spin_unlock(&delayed_refs->lock);
+       return 0;
 }
 
 int btrfs_free_extent(struct btrfs_trans_handle *trans,
@@ -3072,9 +2502,30 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans,
 {
        int ret;
 
-       ret = __btrfs_free_extent(trans, root, bytenr, num_bytes, parent,
-                                 root_objectid, ref_generation,
-                                 owner_objectid, pin);
+       /*
+        * tree log blocks never actually go into the extent allocation
+        * tree, just update pinning info and exit early.
+        *
+        * data extents referenced by the tree log do need to have
+        * their reference counts bumped.
+        */
+       if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID &&
+           owner_objectid < BTRFS_FIRST_FREE_OBJECTID) {
+               mutex_lock(&root->fs_info->pinned_mutex);
+
+               /* unlocks the pinned mutex */
+               btrfs_update_pinned_extents(root, bytenr, num_bytes, 1);
+               update_reserved_extents(root, bytenr, num_bytes, 0);
+               ret = 0;
+       } else {
+               ret = btrfs_add_delayed_ref(trans, bytenr, num_bytes, parent,
+                                      root_objectid, ref_generation,
+                                      owner_objectid,
+                                      BTRFS_DROP_DELAYED_REF, 1);
+               BUG_ON(ret);
+               ret = check_ref_cleanup(trans, root, bytenr);
+               BUG_ON(ret);
+       }
        return ret;
 }
 
@@ -3475,10 +2926,10 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
 static int __btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
                                         struct btrfs_root *root, u64 parent,
                                         u64 root_objectid, u64 ref_generation,
-                                        u64 owner, struct btrfs_key *ins)
+                                        u64 owner, struct btrfs_key *ins,
+                                        int ref_mod)
 {
        int ret;
-       int pending_ret;
        u64 super_used;
        u64 root_used;
        u64 num_bytes = ins->offset;
@@ -3503,33 +2954,6 @@ static int __btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
        btrfs_set_root_used(&root->root_item, root_used + num_bytes);
        spin_unlock(&info->delalloc_lock);
 
-       if (root == extent_root) {
-               struct pending_extent_op *extent_op;
-
-               extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS);
-               BUG_ON(!extent_op);
-
-               extent_op->type = PENDING_EXTENT_INSERT;
-               extent_op->bytenr = ins->objectid;
-               extent_op->num_bytes = ins->offset;
-               extent_op->parent = parent;
-               extent_op->orig_parent = 0;
-               extent_op->generation = ref_generation;
-               extent_op->orig_generation = 0;
-               extent_op->level = (int)owner;
-               INIT_LIST_HEAD(&extent_op->list);
-               extent_op->del = 0;
-
-               mutex_lock(&root->fs_info->extent_ins_mutex);
-               set_extent_bits(&root->fs_info->extent_ins, ins->objectid,
-                               ins->objectid + ins->offset - 1,
-                               EXTENT_WRITEBACK, GFP_NOFS);
-               set_state_private(&root->fs_info->extent_ins,
-                                 ins->objectid, (unsigned long)extent_op);
-               mutex_unlock(&root->fs_info->extent_ins_mutex);
-               goto update_block;
-       }
-
        memcpy(&keys[0], ins, sizeof(*ins));
        keys[1].objectid = ins->objectid;
        keys[1].type = BTRFS_EXTENT_REF_KEY;
@@ -3540,37 +2964,31 @@ static int __btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
        path = btrfs_alloc_path();
        BUG_ON(!path);
 
+       path->leave_spinning = 1;
        ret = btrfs_insert_empty_items(trans, extent_root, path, keys,
                                       sizes, 2);
        BUG_ON(ret);
 
        extent_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
                                     struct btrfs_extent_item);
-       btrfs_set_extent_refs(path->nodes[0], extent_item, 1);
+       btrfs_set_extent_refs(path->nodes[0], extent_item, ref_mod);
        ref = btrfs_item_ptr(path->nodes[0], path->slots[0] + 1,
                             struct btrfs_extent_ref);
 
        btrfs_set_ref_root(path->nodes[0], ref, root_objectid);
        btrfs_set_ref_generation(path->nodes[0], ref, ref_generation);
        btrfs_set_ref_objectid(path->nodes[0], ref, owner);
-       btrfs_set_ref_num_refs(path->nodes[0], ref, 1);
+       btrfs_set_ref_num_refs(path->nodes[0], ref, ref_mod);
 
        btrfs_mark_buffer_dirty(path->nodes[0]);
 
        trans->alloc_exclude_start = 0;
        trans->alloc_exclude_nr = 0;
        btrfs_free_path(path);
-       finish_current_insert(trans, extent_root, 0);
-       pending_ret = del_pending_extents(trans, extent_root, 0);
 
        if (ret)
                goto out;
-       if (pending_ret) {
-               ret = pending_ret;
-               goto out;
-       }
 
-update_block:
        ret = update_block_group(trans, root, ins->objectid,
                                 ins->offset, 1, 0);
        if (ret) {
@@ -3592,9 +3010,12 @@ int btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
 
        if (root_objectid == BTRFS_TREE_LOG_OBJECTID)
                return 0;
-       ret = __btrfs_alloc_reserved_extent(trans, root, parent, root_objectid,
-                                           ref_generation, owner, ins);
-       update_reserved_extents(root, ins->objectid, ins->offset, 0);
+
+       ret = btrfs_add_delayed_ref(trans, ins->objectid,
+                                   ins->offset, parent, root_objectid,
+                                   ref_generation, owner,
+                                   BTRFS_ADD_DELAYED_EXTENT, 0);
+       BUG_ON(ret);
        return ret;
 }
 
@@ -3621,7 +3042,7 @@ int btrfs_alloc_logged_extent(struct btrfs_trans_handle *trans,
        BUG_ON(ret);
        put_block_group(block_group);
        ret = __btrfs_alloc_reserved_extent(trans, root, parent, root_objectid,
-                                           ref_generation, owner, ins);
+                                           ref_generation, owner, ins, 1);
        return ret;
 }
 
@@ -3640,20 +3061,18 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
                       u64 search_end, struct btrfs_key *ins, u64 data)
 {
        int ret;
-
        ret = __btrfs_reserve_extent(trans, root, num_bytes,
                                     min_alloc_size, empty_size, hint_byte,
                                     search_end, ins, data);
        BUG_ON(ret);
        if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
-               ret = __btrfs_alloc_reserved_extent(trans, root, parent,
-                                       root_objectid, ref_generation,
-                                       owner_objectid, ins);
+               ret = btrfs_add_delayed_ref(trans, ins->objectid,
+                                           ins->offset, parent, root_objectid,
+                                           ref_generation, owner_objectid,
+                                           BTRFS_ADD_DELAYED_EXTENT, 0);
                BUG_ON(ret);
-
-       } else {
-               update_reserved_extents(root, ins->objectid, ins->offset, 1);
        }
+       update_reserved_extents(root, ins->objectid, ins->offset, 1);
        return ret;
 }
 
@@ -3789,7 +3208,7 @@ int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
 
                fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
 
-               ret = __btrfs_free_extent(trans, root, disk_bytenr,
+               ret = btrfs_free_extent(trans, root, disk_bytenr,
                                btrfs_file_extent_disk_num_bytes(leaf, fi),
                                leaf->start, leaf_owner, leaf_generation,
                                key.objectid, 0);
@@ -3829,7 +3248,7 @@ static noinline int cache_drop_leaf_ref(struct btrfs_trans_handle *trans,
         */
        for (i = 0; i < ref->nritems; i++) {
                info = ref->extents + sorted[i].slot;
-               ret = __btrfs_free_extent(trans, root, info->bytenr,
+               ret = btrfs_free_extent(trans, root, info->bytenr,
                                          info->num_bytes, ref->bytenr,
                                          ref->owner, ref->generation,
                                          info->objectid, 0);
@@ -3846,12 +3265,13 @@ static noinline int cache_drop_leaf_ref(struct btrfs_trans_handle *trans,
        return 0;
 }
 
-static int drop_snap_lookup_refcount(struct btrfs_root *root, u64 start,
+static int drop_snap_lookup_refcount(struct btrfs_trans_handle *trans,
+                                    struct btrfs_root *root, u64 start,
                                     u64 len, u32 *refs)
 {
        int ret;
 
-       ret = btrfs_lookup_extent_ref(NULL, root, start, len, refs);
+       ret = btrfs_lookup_extent_ref(trans, root, start, len, refs);
        BUG_ON(ret);
 
 #if 0 /* some debugging code in case we see problems here */
@@ -3959,7 +3379,8 @@ static noinline int drop_level_one_refs(struct btrfs_trans_handle *trans,
                 * we just decrement it below and don't update any
                 * of the refs the leaf points to.
                 */
-               ret = drop_snap_lookup_refcount(root, bytenr, blocksize, &refs);
+               ret = drop_snap_lookup_refcount(trans, root, bytenr,
+                                               blocksize, &refs);
                BUG_ON(ret);
                if (refs != 1)
                        continue;
@@ -4010,7 +3431,7 @@ static noinline int drop_level_one_refs(struct btrfs_trans_handle *trans,
         */
        for (i = 0; i < refi; i++) {
                bytenr = sorted[i].bytenr;
-               ret = __btrfs_free_extent(trans, root, bytenr,
+               ret = btrfs_free_extent(trans, root, bytenr,
                                        blocksize, eb->start,
                                        root_owner, root_gen, 0, 1);
                BUG_ON(ret);
@@ -4053,7 +3474,7 @@ static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
 
        WARN_ON(*level < 0);
        WARN_ON(*level >= BTRFS_MAX_LEVEL);
-       ret = drop_snap_lookup_refcount(root, path->nodes[*level]->start,
+       ret = drop_snap_lookup_refcount(trans, root, path->nodes[*level]->start,
                                path->nodes[*level]->len, &refs);
        BUG_ON(ret);
        if (refs > 1)
@@ -4104,7 +3525,8 @@ static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
                ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]);
                blocksize = btrfs_level_size(root, *level - 1);
 
-               ret = drop_snap_lookup_refcount(root, bytenr, blocksize, &refs);
+               ret = drop_snap_lookup_refcount(trans, root, bytenr,
+                                               blocksize, &refs);
                BUG_ON(ret);
 
                /*
@@ -4119,7 +3541,7 @@ static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
                        root_gen = btrfs_header_generation(parent);
                        path->slots[*level]++;
 
-                       ret = __btrfs_free_extent(trans, root, bytenr,
+                       ret = btrfs_free_extent(trans, root, bytenr,
                                                blocksize, parent->start,
                                                root_owner, root_gen,
                                                *level - 1, 1);
@@ -4165,7 +3587,7 @@ out:
         * cleanup and free the reference on the last node
         * we processed
         */
-       ret = __btrfs_free_extent(trans, root, bytenr, blocksize,
+       ret = btrfs_free_extent(trans, root, bytenr, blocksize,
                                  parent->start, root_owner, root_gen,
                                  *level, 1);
        free_extent_buffer(path->nodes[*level]);
@@ -4354,6 +3776,7 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
        struct btrfs_path *path;
        int i;
        int orig_level;
+       int update_count;
        struct btrfs_root_item *root_item = &root->root_item;
 
        WARN_ON(!mutex_is_locked(&root->fs_info->drop_mutex));
@@ -4395,6 +3818,7 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
                }
        }
        while (1) {
+               unsigned long update;
                wret = walk_down_tree(trans, root, path, &level);
                if (wret > 0)
                        break;
@@ -4407,12 +3831,21 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
                        break;
                if (wret < 0)
                        ret = wret;
-               if (trans->transaction->in_commit) {
+               if (trans->transaction->in_commit ||
+                   trans->transaction->delayed_refs.flushing) {
                        ret = -EAGAIN;
                        break;
                }
                atomic_inc(&root->fs_info->throttle_gen);
                wake_up(&root->fs_info->transaction_throttle);
+               for (update_count = 0; update_count < 16; update_count++) {
+                       update = trans->delayed_ref_updates;
+                       trans->delayed_ref_updates = 0;
+                       if (update)
+                               btrfs_run_delayed_refs(trans, root, update);
+                       else
+                               break;
+               }
        }
        for (i = 0; i <= orig_level; i++) {
                if (path->nodes[i]) {
@@ -5457,6 +4890,7 @@ static noinline int replace_extents_in_leaf(struct btrfs_trans_handle *trans,
                                        root->root_key.objectid,
                                        trans->transid, key.objectid);
                BUG_ON(ret);
+
                ret = btrfs_free_extent(trans, root,
                                        bytenr, num_bytes, leaf->start,
                                        btrfs_header_owner(leaf),
@@ -5768,9 +5202,6 @@ static noinline int relocate_tree_block(struct btrfs_trans_handle *trans,
                                ref_path, NULL, NULL);
        BUG_ON(ret);
 
-       if (root == root->fs_info->extent_root)
-               btrfs_extent_post_op(trans, root);
-
        return 0;
 }
 
@@ -6038,6 +5469,7 @@ static int __insert_orphan_inode(struct btrfs_trans_handle *trans,
        if (!path)
                return -ENOMEM;
 
+       path->leave_spinning = 1;
        ret = btrfs_insert_empty_inode(trans, root, path, objectid);
        if (ret)
                goto out;
@@ -6208,6 +5640,9 @@ again:
        btrfs_remove_leaf_refs(info->tree_root, (u64)-1, 1);
        mutex_unlock(&root->fs_info->cleaner_mutex);
 
+       trans = btrfs_start_transaction(info->tree_root, 1);
+       btrfs_commit_transaction(trans, info->tree_root);
+
        while (1) {
                ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
                if (ret < 0)
@@ -6466,7 +5901,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
 
        extent_root = root->fs_info->extent_root;
 
-       root->fs_info->last_trans_new_blockgroup = trans->transid;
+       root->fs_info->last_trans_log_full_commit = trans->transid;
 
        cache = kzalloc(sizeof(*cache), GFP_NOFS);
        if (!cache)
@@ -6500,9 +5935,6 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
                                sizeof(cache->item));
        BUG_ON(ret);
 
-       finish_current_insert(trans, extent_root, 0);
-       ret = del_pending_extents(trans, extent_root, 0);
-       BUG_ON(ret);
        set_avail_alloc_bits(extent_root->fs_info, type);
 
        return 0;
index ebe6b29e60698156250708766c70bb74b903bfb6..08085af089e27827eba49898146ebe63c6623b07 100644 (file)
@@ -3124,20 +3124,15 @@ void free_extent_buffer(struct extent_buffer *eb)
 int clear_extent_buffer_dirty(struct extent_io_tree *tree,
                              struct extent_buffer *eb)
 {
-       int set;
        unsigned long i;
        unsigned long num_pages;
        struct page *page;
 
-       u64 start = eb->start;
-       u64 end = start + eb->len - 1;
-
-       set = clear_extent_dirty(tree, start, end, GFP_NOFS);
        num_pages = num_extent_pages(eb->start, eb->len);
 
        for (i = 0; i < num_pages; i++) {
                page = extent_buffer_page(eb, i);
-               if (!set && !PageDirty(page))
+               if (!PageDirty(page))
                        continue;
 
                lock_page(page);
@@ -3146,22 +3141,6 @@ int clear_extent_buffer_dirty(struct extent_io_tree *tree,
                else
                        set_page_private(page, EXTENT_PAGE_PRIVATE);
 
-               /*
-                * if we're on the last page or the first page and the
-                * block isn't aligned on a page boundary, do extra checks
-                * to make sure we don't clean page that is partially dirty
-                */
-               if ((i == 0 && (eb->start & (PAGE_CACHE_SIZE - 1))) ||
-                   ((i == num_pages - 1) &&
-                    ((eb->start + eb->len) & (PAGE_CACHE_SIZE - 1)))) {
-                       start = (u64)page->index << PAGE_CACHE_SHIFT;
-                       end  = start + PAGE_CACHE_SIZE - 1;
-                       if (test_range_bit(tree, start, end,
-                                          EXTENT_DIRTY, 0)) {
-                               unlock_page(page);
-                               continue;
-                       }
-               }
                clear_page_dirty_for_io(page);
                spin_lock_irq(&page->mapping->tree_lock);
                if (!PageDirty(page)) {
@@ -3187,29 +3166,13 @@ int set_extent_buffer_dirty(struct extent_io_tree *tree,
 {
        unsigned long i;
        unsigned long num_pages;
+       int was_dirty = 0;
 
+       was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags);
        num_pages = num_extent_pages(eb->start, eb->len);
-       for (i = 0; i < num_pages; i++) {
-               struct page *page = extent_buffer_page(eb, i);
-               /* writepage may need to do something special for the
-                * first page, we have to make sure page->private is
-                * properly set.  releasepage may drop page->private
-                * on us if the page isn't already dirty.
-                */
-               lock_page(page);
-               if (i == 0) {
-                       set_page_extent_head(page, eb->len);
-               } else if (PagePrivate(page) &&
-                          page->private != EXTENT_PAGE_PRIVATE) {
-                       set_page_extent_mapped(page);
-               }
+       for (i = 0; i < num_pages; i++)
                __set_page_dirty_nobuffers(extent_buffer_page(eb, i));
-               set_extent_dirty(tree, page_offset(page),
-                                page_offset(page) + PAGE_CACHE_SIZE - 1,
-                                GFP_NOFS);
-               unlock_page(page);
-       }
-       return 0;
+       return was_dirty;
 }
 
 int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
@@ -3789,6 +3752,10 @@ int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page)
                ret = 0;
                goto out;
        }
+       if (test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) {
+               ret = 0;
+               goto out;
+       }
        /* at this point we can safely release the extent buffer */
        num_pages = num_extent_pages(eb->start, eb->len);
        for (i = 0; i < num_pages; i++)
index 1f9df88afbf6922e9f4af87972f05521ed15e862..5bc20abf3f3d340b22248802e4c8d7d72f4dc4bb 100644 (file)
@@ -25,6 +25,7 @@
 /* these are bit numbers for test/set bit */
 #define EXTENT_BUFFER_UPTODATE 0
 #define EXTENT_BUFFER_BLOCKING 1
+#define EXTENT_BUFFER_DIRTY 2
 
 /*
  * page->private values.  Every page that is controlled by the extent
@@ -254,6 +255,8 @@ int clear_extent_buffer_dirty(struct extent_io_tree *tree,
                              struct extent_buffer *eb);
 int set_extent_buffer_dirty(struct extent_io_tree *tree,
                             struct extent_buffer *eb);
+int test_extent_buffer_dirty(struct extent_io_tree *tree,
+                            struct extent_buffer *eb);
 int set_extent_buffer_uptodate(struct extent_io_tree *tree,
                               struct extent_buffer *eb);
 int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
index 964652435fd1a5f40e061cfe1c3a7dd1d1198248..9b99886562d0b2c8ea9e883f3f2623b0ec6d8674 100644 (file)
@@ -52,6 +52,7 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
        file_key.offset = pos;
        btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
 
+       path->leave_spinning = 1;
        ret = btrfs_insert_empty_item(trans, root, path, &file_key,
                                      sizeof(*item));
        if (ret < 0)
@@ -523,6 +524,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
                key.offset = end_byte - 1;
                key.type = BTRFS_EXTENT_CSUM_KEY;
 
+               path->leave_spinning = 1;
                ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
                if (ret > 0) {
                        if (path->slots[0] == 0)
@@ -757,8 +759,10 @@ insert:
        } else {
                ins_size = csum_size;
        }
+       path->leave_spinning = 1;
        ret = btrfs_insert_empty_item(trans, root, path, &file_key,
                                      ins_size);
+       path->leave_spinning = 0;
        if (ret < 0)
                goto fail_unlock;
        if (ret != 0) {
@@ -776,7 +780,6 @@ found:
        item_end = (struct btrfs_csum_item *)((unsigned char *)item_end +
                                      btrfs_item_size_nr(leaf, path->slots[0]));
        eb_token = NULL;
-       cond_resched();
 next_sector:
 
        if (!eb_token ||
@@ -817,9 +820,9 @@ next_sector:
                eb_token = NULL;
        }
        btrfs_mark_buffer_dirty(path->nodes[0]);
-       cond_resched();
        if (total_bytes < sums->len) {
                btrfs_release_path(root, path);
+               cond_resched();
                goto again;
        }
 out:
index dc78954861b333d75e831e27c6bbe7760f6e1de9..9c9fb46ccd08f9fe7eaf9d22991738f9231810c2 100644 (file)
@@ -606,6 +606,7 @@ next_slot:
                        btrfs_set_key_type(&ins, BTRFS_EXTENT_DATA_KEY);
 
                        btrfs_release_path(root, path);
+                       path->leave_spinning = 1;
                        ret = btrfs_insert_empty_item(trans, root, path, &ins,
                                                      sizeof(*extent));
                        BUG_ON(ret);
@@ -639,17 +640,22 @@ next_slot:
                                                        ram_bytes);
                        btrfs_set_file_extent_type(leaf, extent, found_type);
 
+                       btrfs_unlock_up_safe(path, 1);
                        btrfs_mark_buffer_dirty(path->nodes[0]);
+                       btrfs_set_lock_blocking(path->nodes[0]);
 
                        if (disk_bytenr != 0) {
                                ret = btrfs_update_extent_ref(trans, root,
-                                               disk_bytenr, orig_parent,
+                                               disk_bytenr,
+                                               le64_to_cpu(old.disk_num_bytes),
+                                               orig_parent,
                                                leaf->start,
                                                root->root_key.objectid,
                                                trans->transid, ins.objectid);
 
                                BUG_ON(ret);
                        }
+                       path->leave_spinning = 0;
                        btrfs_release_path(root, path);
                        if (disk_bytenr != 0)
                                inode_add_bytes(inode, extent_end - end);
@@ -912,7 +918,7 @@ again:
        btrfs_set_file_extent_other_encoding(leaf, fi, 0);
 
        if (orig_parent != leaf->start) {
-               ret = btrfs_update_extent_ref(trans, root, bytenr,
+               ret = btrfs_update_extent_ref(trans, root, bytenr, num_bytes,
                                              orig_parent, leaf->start,
                                              root->root_key.objectid,
                                              trans->transid, inode->i_ino);
@@ -1155,6 +1161,20 @@ out_nolock:
                page_cache_release(pinned[1]);
        *ppos = pos;
 
+       /*
+        * we want to make sure fsync finds this change
+        * but we haven't joined a transaction running right now.
+        *
+        * Later on, someone is sure to update the inode and get the
+        * real transid recorded.
+        *
+        * We set last_trans now to the fs_info generation + 1,
+        * this will either be one more than the running transaction
+        * or the generation used for the next transaction if there isn't
+        * one running right now.
+        */
+       BTRFS_I(inode)->last_trans = root->fs_info->generation + 1;
+
        if (num_written > 0 && will_write) {
                struct btrfs_trans_handle *trans;
 
@@ -1167,8 +1187,11 @@ out_nolock:
                        ret = btrfs_log_dentry_safe(trans, root,
                                                    file->f_dentry);
                        if (ret == 0) {
-                               btrfs_sync_log(trans, root);
-                               btrfs_end_transaction(trans, root);
+                               ret = btrfs_sync_log(trans, root);
+                               if (ret == 0)
+                                       btrfs_end_transaction(trans, root);
+                               else
+                                       btrfs_commit_transaction(trans, root);
                        } else {
                                btrfs_commit_transaction(trans, root);
                        }
@@ -1185,6 +1208,18 @@ out_nolock:
 
 int btrfs_release_file(struct inode *inode, struct file *filp)
 {
+       /*
+        * ordered_data_close is set by settattr when we are about to truncate
+        * a file from a non-zero size to a zero size.  This tries to
+        * flush down new bytes that may have been written if the
+        * application were using truncate to replace a file in place.
+        */
+       if (BTRFS_I(inode)->ordered_data_close) {
+               BTRFS_I(inode)->ordered_data_close = 0;
+               btrfs_add_ordered_operation(NULL, BTRFS_I(inode)->root, inode);
+               if (inode->i_size > BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT)
+                       filemap_flush(inode->i_mapping);
+       }
        if (filp->private_data)
                btrfs_ioctl_trans_end(filp);
        return 0;
@@ -1260,8 +1295,11 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
        if (ret > 0) {
                ret = btrfs_commit_transaction(trans, root);
        } else {
-               btrfs_sync_log(trans, root);
-               ret = btrfs_end_transaction(trans, root);
+               ret = btrfs_sync_log(trans, root);
+               if (ret == 0)
+                       ret = btrfs_end_transaction(trans, root);
+               else
+                       ret = btrfs_commit_transaction(trans, root);
        }
        mutex_lock(&dentry->d_inode->i_mutex);
 out:
index 3d46fa1f29a4d75be94f116e148a0f50321973f6..6b627c6118081ccea87d1acaf92000f995dda946 100644 (file)
@@ -73,6 +73,8 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
        if (!path)
                return -ENOMEM;
 
+       path->leave_spinning = 1;
+
        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
        if (ret > 0) {
                ret = -ENOENT;
@@ -127,6 +129,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
        if (!path)
                return -ENOMEM;
 
+       path->leave_spinning = 1;
        ret = btrfs_insert_empty_item(trans, root, path, &key,
                                      ins_len);
        if (ret == -EEXIST) {
index 7d4f948bc22a5b5c811b93b385ff36d5b49e8977..06d8db5afb08ba8800dc776a64f421c1e9322780 100644 (file)
@@ -134,6 +134,7 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
        if (!path)
                return -ENOMEM;
 
+       path->leave_spinning = 1;
        btrfs_set_trans_block_group(trans, inode);
 
        key.objectid = inode->i_ino;
@@ -167,9 +168,9 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
                        cur_size = min_t(unsigned long, compressed_size,
                                       PAGE_CACHE_SIZE);
 
-                       kaddr = kmap(cpage);
+                       kaddr = kmap_atomic(cpage, KM_USER0);
                        write_extent_buffer(leaf, kaddr, ptr, cur_size);
-                       kunmap(cpage);
+                       kunmap_atomic(kaddr, KM_USER0);
 
                        i++;
                        ptr += cur_size;
@@ -204,7 +205,7 @@ fail:
  * does the checks required to make sure the data is small enough
  * to fit as an inline extent.
  */
-static int cow_file_range_inline(struct btrfs_trans_handle *trans,
+static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root,
                                 struct inode *inode, u64 start, u64 end,
                                 size_t compressed_size,
@@ -854,11 +855,6 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
        u64 cur_end;
        int limit = 10 * 1024 * 1042;
 
-       if (!btrfs_test_opt(root, COMPRESS)) {
-               return cow_file_range(inode, locked_page, start, end,
-                                     page_started, nr_written, 1);
-       }
-
        clear_extent_bit(&BTRFS_I(inode)->io_tree, start, end, EXTENT_LOCKED |
                         EXTENT_DELALLOC, 1, 0, GFP_NOFS);
        while (start < end) {
@@ -935,7 +931,8 @@ static noinline int csum_exist_in_range(struct btrfs_root *root,
  * If no cow copies or snapshots exist, we write directly to the existing
  * blocks on disk
  */
-static int run_delalloc_nocow(struct inode *inode, struct page *locked_page,
+static noinline int run_delalloc_nocow(struct inode *inode,
+                                      struct page *locked_page,
                              u64 start, u64 end, int *page_started, int force,
                              unsigned long *nr_written)
 {
@@ -1133,6 +1130,7 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page,
                              unsigned long *nr_written)
 {
        int ret;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
 
        if (btrfs_test_flag(inode, NODATACOW))
                ret = run_delalloc_nocow(inode, locked_page, start, end,
@@ -1140,10 +1138,12 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page,
        else if (btrfs_test_flag(inode, PREALLOC))
                ret = run_delalloc_nocow(inode, locked_page, start, end,
                                         page_started, 0, nr_written);
+       else if (!btrfs_test_opt(root, COMPRESS))
+               ret = cow_file_range(inode, locked_page, start, end,
+                                     page_started, nr_written, 1);
        else
                ret = cow_file_range_async(inode, locked_page, start, end,
                                           page_started, nr_written);
-
        return ret;
 }
 
@@ -1453,6 +1453,7 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
        path = btrfs_alloc_path();
        BUG_ON(!path);
 
+       path->leave_spinning = 1;
        ret = btrfs_drop_extents(trans, root, inode, file_pos,
                                 file_pos + num_bytes, file_pos, &hint);
        BUG_ON(ret);
@@ -1475,6 +1476,10 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
        btrfs_set_file_extent_compression(leaf, fi, compression);
        btrfs_set_file_extent_encryption(leaf, fi, encryption);
        btrfs_set_file_extent_other_encoding(leaf, fi, other_encoding);
+
+       btrfs_unlock_up_safe(path, 1);
+       btrfs_set_lock_blocking(leaf);
+
        btrfs_mark_buffer_dirty(leaf);
 
        inode_add_bytes(inode, num_bytes);
@@ -1487,11 +1492,35 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
                                          root->root_key.objectid,
                                          trans->transid, inode->i_ino, &ins);
        BUG_ON(ret);
-
        btrfs_free_path(path);
+
        return 0;
 }
 
+/*
+ * helper function for btrfs_finish_ordered_io, this
+ * just reads in some of the csum leaves to prime them into ram
+ * before we start the transaction.  It limits the amount of btree
+ * reads required while inside the transaction.
+ */
+static noinline void reada_csum(struct btrfs_root *root,
+                               struct btrfs_path *path,
+                               struct btrfs_ordered_extent *ordered_extent)
+{
+       struct btrfs_ordered_sum *sum;
+       u64 bytenr;
+
+       sum = list_entry(ordered_extent->list.next, struct btrfs_ordered_sum,
+                        list);
+       bytenr = sum->sums[0].bytenr;
+
+       /*
+        * we don't care about the results, the point of this search is
+        * just to get the btree leaves into ram
+        */
+       btrfs_lookup_csum(NULL, root->fs_info->csum_root, path, bytenr, 0);
+}
+
 /* as ordered data IO finishes, this gets called so we can finish
  * an ordered extent if the range of bytes in the file it covers are
  * fully written.
@@ -1500,8 +1529,9 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_trans_handle *trans;
-       struct btrfs_ordered_extent *ordered_extent;
+       struct btrfs_ordered_extent *ordered_extent = NULL;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
+       struct btrfs_path *path;
        int compressed = 0;
        int ret;
 
@@ -1509,9 +1539,33 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
        if (!ret)
                return 0;
 
+       /*
+        * before we join the transaction, try to do some of our IO.
+        * This will limit the amount of IO that we have to do with
+        * the transaction running.  We're unlikely to need to do any
+        * IO if the file extents are new, the disk_i_size checks
+        * covers the most common case.
+        */
+       if (start < BTRFS_I(inode)->disk_i_size) {
+               path = btrfs_alloc_path();
+               if (path) {
+                       ret = btrfs_lookup_file_extent(NULL, root, path,
+                                                      inode->i_ino,
+                                                      start, 0);
+                       ordered_extent = btrfs_lookup_ordered_extent(inode,
+                                                                    start);
+                       if (!list_empty(&ordered_extent->list)) {
+                               btrfs_release_path(root, path);
+                               reada_csum(root, path, ordered_extent);
+                       }
+                       btrfs_free_path(path);
+               }
+       }
+
        trans = btrfs_join_transaction(root, 1);
 
-       ordered_extent = btrfs_lookup_ordered_extent(inode, start);
+       if (!ordered_extent)
+               ordered_extent = btrfs_lookup_ordered_extent(inode, start);
        BUG_ON(!ordered_extent);
        if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags))
                goto nocow;
@@ -2101,6 +2155,7 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
 
        path = btrfs_alloc_path();
        BUG_ON(!path);
+       path->leave_spinning = 1;
        ret = btrfs_lookup_inode(trans, root, path,
                                 &BTRFS_I(inode)->location, 1);
        if (ret) {
@@ -2147,6 +2202,7 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
                goto err;
        }
 
+       path->leave_spinning = 1;
        di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino,
                                    name, name_len, -1);
        if (IS_ERR(di)) {
@@ -2190,8 +2246,6 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
        ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len,
                                         inode, dir->i_ino);
        BUG_ON(ret != 0 && ret != -ENOENT);
-       if (ret != -ENOENT)
-               BTRFS_I(dir)->log_dirty_trans = trans->transid;
 
        ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len,
                                           dir, index);
@@ -2224,6 +2278,9 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
        trans = btrfs_start_transaction(root, 1);
 
        btrfs_set_trans_block_group(trans, dir);
+
+       btrfs_record_unlink_dir(trans, dir, dentry->d_inode, 0);
+
        ret = btrfs_unlink_inode(trans, root, dir, dentry->d_inode,
                                 dentry->d_name.name, dentry->d_name.len);
 
@@ -2498,6 +2555,7 @@ noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
        key.type = (u8)-1;
 
 search_again:
+       path->leave_spinning = 1;
        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
        if (ret < 0)
                goto error;
@@ -2644,6 +2702,7 @@ delete:
                        break;
                }
                if (found_extent) {
+                       btrfs_set_path_blocking(path);
                        ret = btrfs_free_extent(trans, root, extent_start,
                                                extent_num_bytes,
                                                leaf->start, root_owner,
@@ -2848,11 +2907,21 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
        if (err)
                return err;
 
-       if (S_ISREG(inode->i_mode) &&
-           attr->ia_valid & ATTR_SIZE && attr->ia_size > inode->i_size) {
-               err = btrfs_cont_expand(inode, attr->ia_size);
-               if (err)
-                       return err;
+       if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
+               if (attr->ia_size > inode->i_size) {
+                       err = btrfs_cont_expand(inode, attr->ia_size);
+                       if (err)
+                               return err;
+               } else if (inode->i_size > 0 &&
+                          attr->ia_size == 0) {
+
+                       /* we're truncating a file that used to have good
+                        * data down to zero.  Make sure it gets into
+                        * the ordered flush list so that any new writes
+                        * get down to disk quickly.
+                        */
+                       BTRFS_I(inode)->ordered_data_close = 1;
+               }
        }
 
        err = inode_setattr(inode, attr);
@@ -2984,13 +3053,14 @@ static noinline void init_btrfs_i(struct inode *inode)
        bi->disk_i_size = 0;
        bi->flags = 0;
        bi->index_cnt = (u64)-1;
-       bi->log_dirty_trans = 0;
+       bi->last_unlink_trans = 0;
        extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
        extent_io_tree_init(&BTRFS_I(inode)->io_tree,
                             inode->i_mapping, GFP_NOFS);
        extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree,
                             inode->i_mapping, GFP_NOFS);
        INIT_LIST_HEAD(&BTRFS_I(inode)->delalloc_inodes);
+       INIT_LIST_HEAD(&BTRFS_I(inode)->ordered_operations);
        btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree);
        mutex_init(&BTRFS_I(inode)->extent_mutex);
        mutex_init(&BTRFS_I(inode)->log_mutex);
@@ -3449,6 +3519,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
        sizes[0] = sizeof(struct btrfs_inode_item);
        sizes[1] = name_len + sizeof(*ref);
 
+       path->leave_spinning = 1;
        ret = btrfs_insert_empty_items(trans, root, path, key, sizes, 2);
        if (ret != 0)
                goto fail;
@@ -3727,6 +3798,8 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
                drop_inode = 1;
 
        nr = trans->blocks_used;
+
+       btrfs_log_new_name(trans, inode, NULL, dentry->d_parent);
        btrfs_end_transaction_throttle(trans, root);
 fail:
        if (drop_inode) {
@@ -4292,8 +4365,9 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset)
  * beyond EOF, then the page is guaranteed safe against truncation until we
  * unlock the page.
  */
-int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
+       struct page *page = vmf->page;
        struct inode *inode = fdentry(vma->vm_file)->d_inode;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
@@ -4306,10 +4380,15 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page)
        u64 page_end;
 
        ret = btrfs_check_data_free_space(root, inode, PAGE_CACHE_SIZE);
-       if (ret)
+       if (ret) {
+               if (ret == -ENOMEM)
+                       ret = VM_FAULT_OOM;
+               else /* -ENOSPC, -EIO, etc */
+                       ret = VM_FAULT_SIGBUS;
                goto out;
+       }
 
-       ret = -EINVAL;
+       ret = VM_FAULT_NOPAGE; /* make the VM retry the fault */
 again:
        lock_page(page);
        size = i_size_read(inode);
@@ -4357,6 +4436,8 @@ again:
        }
        ClearPageChecked(page);
        set_page_dirty(page);
+
+       BTRFS_I(inode)->last_trans = root->fs_info->generation + 1;
        unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
 
 out_unlock:
@@ -4382,6 +4463,27 @@ static void btrfs_truncate(struct inode *inode)
        btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
 
        trans = btrfs_start_transaction(root, 1);
+
+       /*
+        * setattr is responsible for setting the ordered_data_close flag,
+        * but that is only tested during the last file release.  That
+        * could happen well after the next commit, leaving a great big
+        * window where new writes may get lost if someone chooses to write
+        * to this file after truncating to zero
+        *
+        * The inode doesn't have any dirty data here, and so if we commit
+        * this is a noop.  If someone immediately starts writing to the inode
+        * it is very likely we'll catch some of their writes in this
+        * transaction, and the commit will find this file on the ordered
+        * data list with good things to send down.
+        *
+        * This is a best effort solution, there is still a window where
+        * using truncate to replace the contents of the file will
+        * end up with a zero length file after a crash.
+        */
+       if (inode->i_size == 0 && BTRFS_I(inode)->ordered_data_close)
+               btrfs_add_ordered_operation(trans, root, inode);
+
        btrfs_set_trans_block_group(trans, inode);
        btrfs_i_size_write(inode, inode->i_size);
 
@@ -4458,12 +4560,15 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
        ei->i_acl = BTRFS_ACL_NOT_CACHED;
        ei->i_default_acl = BTRFS_ACL_NOT_CACHED;
        INIT_LIST_HEAD(&ei->i_orphan);
+       INIT_LIST_HEAD(&ei->ordered_operations);
        return &ei->vfs_inode;
 }
 
 void btrfs_destroy_inode(struct inode *inode)
 {
        struct btrfs_ordered_extent *ordered;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+
        WARN_ON(!list_empty(&inode->i_dentry));
        WARN_ON(inode->i_data.nrpages);
 
@@ -4474,13 +4579,24 @@ void btrfs_destroy_inode(struct inode *inode)
            BTRFS_I(inode)->i_default_acl != BTRFS_ACL_NOT_CACHED)
                posix_acl_release(BTRFS_I(inode)->i_default_acl);
 
-       spin_lock(&BTRFS_I(inode)->root->list_lock);
+       /*
+        * Make sure we're properly removed from the ordered operation
+        * lists.
+        */
+       smp_mb();
+       if (!list_empty(&BTRFS_I(inode)->ordered_operations)) {
+               spin_lock(&root->fs_info->ordered_extent_lock);
+               list_del_init(&BTRFS_I(inode)->ordered_operations);
+               spin_unlock(&root->fs_info->ordered_extent_lock);
+       }
+
+       spin_lock(&root->list_lock);
        if (!list_empty(&BTRFS_I(inode)->i_orphan)) {
                printk(KERN_ERR "BTRFS: inode %lu: inode still on the orphan"
                       " list\n", inode->i_ino);
                dump_stack();
        }
-       spin_unlock(&BTRFS_I(inode)->root->list_lock);
+       spin_unlock(&root->list_lock);
 
        while (1) {
                ordered = btrfs_lookup_first_ordered_extent(inode, (u64)-1);
@@ -4605,8 +4721,36 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (ret)
                goto out_unlock;
 
+       /*
+        * we're using rename to replace one file with another.
+        * and the replacement file is large.  Start IO on it now so
+        * we don't add too much work to the end of the transaction
+        */
+       if (new_inode && old_inode && S_ISREG(old_inode->i_mode) &&
+           new_inode->i_size &&
+           old_inode->i_size > BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT)
+               filemap_flush(old_inode->i_mapping);
+
        trans = btrfs_start_transaction(root, 1);
 
+       /*
+        * make sure the inode gets flushed if it is replacing
+        * something.
+        */
+       if (new_inode && new_inode->i_size &&
+           old_inode && S_ISREG(old_inode->i_mode)) {
+               btrfs_add_ordered_operation(trans, root, old_inode);
+       }
+
+       /*
+        * this is an ugly little race, but the rename is required to make
+        * sure that if we crash, the inode is either at the old name
+        * or the new one.  pinning the log transaction lets us make sure
+        * we don't allow a log commit to come in after we unlink the
+        * name but before we add the new name back in.
+        */
+       btrfs_pin_log_trans(root);
+
        btrfs_set_trans_block_group(trans, new_dir);
 
        btrfs_inc_nlink(old_dentry->d_inode);
@@ -4614,6 +4758,9 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        new_dir->i_ctime = new_dir->i_mtime = ctime;
        old_inode->i_ctime = ctime;
 
+       if (old_dentry->d_parent != new_dentry->d_parent)
+               btrfs_record_unlink_dir(trans, old_dir, old_inode, 1);
+
        ret = btrfs_unlink_inode(trans, root, old_dir, old_dentry->d_inode,
                                 old_dentry->d_name.name,
                                 old_dentry->d_name.len);
@@ -4645,7 +4792,14 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (ret)
                goto out_fail;
 
+       btrfs_log_new_name(trans, old_inode, old_dir,
+                                      new_dentry->d_parent);
 out_fail:
+
+       /* this btrfs_end_log_trans just allows the current
+        * log-sub transaction to complete
+        */
+       btrfs_end_log_trans(root);
        btrfs_end_transaction_throttle(trans, root);
 out_unlock:
        return ret;
index 47b0a88c12a23a6d983eff4c3ff0e4bdf1347d2e..a5310c0f41e24f089bfd78e3a2f0939d3957f717 100644 (file)
@@ -71,12 +71,13 @@ void btrfs_clear_lock_blocking(struct extent_buffer *eb)
 static int btrfs_spin_on_block(struct extent_buffer *eb)
 {
        int i;
+
        for (i = 0; i < 512; i++) {
-               cpu_relax();
                if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
                        return 1;
                if (need_resched())
                        break;
+               cpu_relax();
        }
        return 0;
 }
@@ -95,13 +96,15 @@ int btrfs_try_spin_lock(struct extent_buffer *eb)
 {
        int i;
 
-       spin_nested(eb);
-       if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
-               return 1;
-       spin_unlock(&eb->lock);
-
+       if (btrfs_spin_on_block(eb)) {
+               spin_nested(eb);
+               if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
+                       return 1;
+               spin_unlock(&eb->lock);
+       }
        /* spin for a bit on the BLOCKING flag */
        for (i = 0; i < 2; i++) {
+               cpu_relax();
                if (!btrfs_spin_on_block(eb))
                        break;
 
@@ -148,6 +151,9 @@ int btrfs_tree_lock(struct extent_buffer *eb)
        DEFINE_WAIT(wait);
        wait.func = btrfs_wake_function;
 
+       if (!btrfs_spin_on_block(eb))
+               goto sleep;
+
        while(1) {
                spin_nested(eb);
 
@@ -165,9 +171,10 @@ int btrfs_tree_lock(struct extent_buffer *eb)
                 * spin for a bit, and if the blocking flag goes away,
                 * loop around
                 */
+               cpu_relax();
                if (btrfs_spin_on_block(eb))
                        continue;
-
+sleep:
                prepare_to_wait_exclusive(&eb->lock_wq, &wait,
                                          TASK_UNINTERRUPTIBLE);
 
index 77c2411a5f0f0c59b6ab97e78b2828d94a1c7401..53c87b197d701671afde64fd7f8f00b59fdb8cd2 100644 (file)
@@ -310,6 +310,16 @@ int btrfs_remove_ordered_extent(struct inode *inode,
 
        spin_lock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
        list_del_init(&entry->root_extent_list);
+
+       /*
+        * we have no more ordered extents for this inode and
+        * no dirty pages.  We can safely remove it from the
+        * list of ordered extents
+        */
+       if (RB_EMPTY_ROOT(&tree->tree) &&
+           !mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) {
+               list_del_init(&BTRFS_I(inode)->ordered_operations);
+       }
        spin_unlock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
 
        mutex_unlock(&tree->mutex);
@@ -369,6 +379,68 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only)
        return 0;
 }
 
+/*
+ * this is used during transaction commit to write all the inodes
+ * added to the ordered operation list.  These files must be fully on
+ * disk before the transaction commits.
+ *
+ * we have two modes here, one is to just start the IO via filemap_flush
+ * and the other is to wait for all the io.  When we wait, we have an
+ * extra check to make sure the ordered operation list really is empty
+ * before we return
+ */
+int btrfs_run_ordered_operations(struct btrfs_root *root, int wait)
+{
+       struct btrfs_inode *btrfs_inode;
+       struct inode *inode;
+       struct list_head splice;
+
+       INIT_LIST_HEAD(&splice);
+
+       mutex_lock(&root->fs_info->ordered_operations_mutex);
+       spin_lock(&root->fs_info->ordered_extent_lock);
+again:
+       list_splice_init(&root->fs_info->ordered_operations, &splice);
+
+       while (!list_empty(&splice)) {
+               btrfs_inode = list_entry(splice.next, struct btrfs_inode,
+                                  ordered_operations);
+
+               inode = &btrfs_inode->vfs_inode;
+
+               list_del_init(&btrfs_inode->ordered_operations);
+
+               /*
+                * the inode may be getting freed (in sys_unlink path).
+                */
+               inode = igrab(inode);
+
+               if (!wait && inode) {
+                       list_add_tail(&BTRFS_I(inode)->ordered_operations,
+                             &root->fs_info->ordered_operations);
+               }
+               spin_unlock(&root->fs_info->ordered_extent_lock);
+
+               if (inode) {
+                       if (wait)
+                               btrfs_wait_ordered_range(inode, 0, (u64)-1);
+                       else
+                               filemap_flush(inode->i_mapping);
+                       iput(inode);
+               }
+
+               cond_resched();
+               spin_lock(&root->fs_info->ordered_extent_lock);
+       }
+       if (wait && !list_empty(&root->fs_info->ordered_operations))
+               goto again;
+
+       spin_unlock(&root->fs_info->ordered_extent_lock);
+       mutex_unlock(&root->fs_info->ordered_operations_mutex);
+
+       return 0;
+}
+
 /*
  * Used to start IO or wait for a given ordered extent to finish.
  *
@@ -726,3 +798,49 @@ int btrfs_wait_on_page_writeback_range(struct address_space *mapping,
 
        return ret;
 }
+
+/*
+ * add a given inode to the list of inodes that must be fully on
+ * disk before a transaction commit finishes.
+ *
+ * This basically gives us the ext3 style data=ordered mode, and it is mostly
+ * used to make sure renamed files are fully on disk.
+ *
+ * It is a noop if the inode is already fully on disk.
+ *
+ * If trans is not null, we'll do a friendly check for a transaction that
+ * is already flushing things and force the IO down ourselves.
+ */
+int btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root,
+                               struct inode *inode)
+{
+       u64 last_mod;
+
+       last_mod = max(BTRFS_I(inode)->generation, BTRFS_I(inode)->last_trans);
+
+       /*
+        * if this file hasn't been changed since the last transaction
+        * commit, we can safely return without doing anything
+        */
+       if (last_mod < root->fs_info->last_trans_committed)
+               return 0;
+
+       /*
+        * the transaction is already committing.  Just start the IO and
+        * don't bother with all of this list nonsense
+        */
+       if (trans && root->fs_info->running_transaction->blocked) {
+               btrfs_wait_ordered_range(inode, 0, (u64)-1);
+               return 0;
+       }
+
+       spin_lock(&root->fs_info->ordered_extent_lock);
+       if (list_empty(&BTRFS_I(inode)->ordered_operations)) {
+               list_add_tail(&BTRFS_I(inode)->ordered_operations,
+                             &root->fs_info->ordered_operations);
+       }
+       spin_unlock(&root->fs_info->ordered_extent_lock);
+
+       return 0;
+}
index ab66d5e8d6d697eac5110401d5e37b0f2afa8f9e..3d31c8827b013407d6f4b14796896a6aac8ba53b 100644 (file)
@@ -155,4 +155,8 @@ int btrfs_wait_on_page_writeback_range(struct address_space *mapping,
 int btrfs_fdatawrite_range(struct address_space *mapping, loff_t start,
                           loff_t end, int sync_mode);
 int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only);
+int btrfs_run_ordered_operations(struct btrfs_root *root, int wait);
+int btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root,
+                               struct inode *inode);
 #endif
index 4112d53d4f4dad195636c6ffa93deaded831af6e..664782c6a2dfbf6e65628f09fe2ff8552335f016 100644 (file)
@@ -65,6 +65,15 @@ static noinline int join_transaction(struct btrfs_root *root)
                cur_trans->use_count = 1;
                cur_trans->commit_done = 0;
                cur_trans->start_time = get_seconds();
+
+               cur_trans->delayed_refs.root.rb_node = NULL;
+               cur_trans->delayed_refs.num_entries = 0;
+               cur_trans->delayed_refs.num_heads_ready = 0;
+               cur_trans->delayed_refs.num_heads = 0;
+               cur_trans->delayed_refs.flushing = 0;
+               cur_trans->delayed_refs.run_delayed_start = 0;
+               spin_lock_init(&cur_trans->delayed_refs.lock);
+
                INIT_LIST_HEAD(&cur_trans->pending_snapshots);
                list_add_tail(&cur_trans->list, &root->fs_info->trans_list);
                extent_io_tree_init(&cur_trans->dirty_pages,
@@ -182,6 +191,8 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
        h->block_group = 0;
        h->alloc_exclude_nr = 0;
        h->alloc_exclude_start = 0;
+       h->delayed_ref_updates = 0;
+
        root->fs_info->running_transaction->use_count++;
        mutex_unlock(&root->fs_info->trans_mutex);
        return h;
@@ -271,7 +282,6 @@ void btrfs_throttle(struct btrfs_root *root)
        if (!root->fs_info->open_ioctl_trans)
                wait_current_trans(root);
        mutex_unlock(&root->fs_info->trans_mutex);
-
        throttle_on_drops(root);
 }
 
@@ -280,6 +290,27 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
 {
        struct btrfs_transaction *cur_trans;
        struct btrfs_fs_info *info = root->fs_info;
+       int count = 0;
+
+       while (count < 4) {
+               unsigned long cur = trans->delayed_ref_updates;
+               trans->delayed_ref_updates = 0;
+               if (cur &&
+                   trans->transaction->delayed_refs.num_heads_ready > 64) {
+                       trans->delayed_ref_updates = 0;
+
+                       /*
+                        * do a full flush if the transaction is trying
+                        * to close
+                        */
+                       if (trans->transaction->delayed_refs.flushing)
+                               cur = 0;
+                       btrfs_run_delayed_refs(trans, root, cur);
+               } else {
+                       break;
+               }
+               count++;
+       }
 
        mutex_lock(&info->trans_mutex);
        cur_trans = info->running_transaction;
@@ -424,9 +455,10 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
        u64 old_root_bytenr;
        struct btrfs_root *tree_root = root->fs_info->tree_root;
 
-       btrfs_extent_post_op(trans, root);
        btrfs_write_dirty_block_groups(trans, root);
-       btrfs_extent_post_op(trans, root);
+
+       ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+       BUG_ON(ret);
 
        while (1) {
                old_root_bytenr = btrfs_root_bytenr(&root->root_item);
@@ -438,14 +470,14 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
                                     btrfs_header_level(root->node));
                btrfs_set_root_generation(&root->root_item, trans->transid);
 
-               btrfs_extent_post_op(trans, root);
-
                ret = btrfs_update_root(trans, tree_root,
                                        &root->root_key,
                                        &root->root_item);
                BUG_ON(ret);
                btrfs_write_dirty_block_groups(trans, root);
-               btrfs_extent_post_op(trans, root);
+
+               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+               BUG_ON(ret);
        }
        return 0;
 }
@@ -459,15 +491,18 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct list_head *next;
        struct extent_buffer *eb;
+       int ret;
 
-       btrfs_extent_post_op(trans, fs_info->tree_root);
+       ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+       BUG_ON(ret);
 
        eb = btrfs_lock_root_node(fs_info->tree_root);
-       btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb, 0);
+       btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb);
        btrfs_tree_unlock(eb);
        free_extent_buffer(eb);
 
-       btrfs_extent_post_op(trans, fs_info->tree_root);
+       ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+       BUG_ON(ret);
 
        while (!list_empty(&fs_info->dirty_cowonly_roots)) {
                next = fs_info->dirty_cowonly_roots.next;
@@ -475,6 +510,9 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
                root = list_entry(next, struct btrfs_root, dirty_list);
 
                update_cowonly_root(trans, root);
+
+               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+               BUG_ON(ret);
        }
        return 0;
 }
@@ -634,6 +672,31 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly)
        return 0;
 }
 
+/*
+ * when dropping snapshots, we generate a ton of delayed refs, and it makes
+ * sense not to join the transaction while it is trying to flush the current
+ * queue of delayed refs out.
+ *
+ * This is used by the drop snapshot code only
+ */
+static noinline int wait_transaction_pre_flush(struct btrfs_fs_info *info)
+{
+       DEFINE_WAIT(wait);
+
+       mutex_lock(&info->trans_mutex);
+       while (info->running_transaction &&
+              info->running_transaction->delayed_refs.flushing) {
+               prepare_to_wait(&info->transaction_wait, &wait,
+                               TASK_UNINTERRUPTIBLE);
+               mutex_unlock(&info->trans_mutex);
+               schedule();
+               mutex_lock(&info->trans_mutex);
+               finish_wait(&info->transaction_wait, &wait);
+       }
+       mutex_unlock(&info->trans_mutex);
+       return 0;
+}
+
 /*
  * Given a list of roots that need to be deleted, call btrfs_drop_snapshot on
  * all of them
@@ -661,7 +724,22 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root,
                atomic_inc(&root->fs_info->throttles);
 
                while (1) {
+                       /*
+                        * we don't want to jump in and create a bunch of
+                        * delayed refs if the transaction is starting to close
+                        */
+                       wait_transaction_pre_flush(tree_root->fs_info);
                        trans = btrfs_start_transaction(tree_root, 1);
+
+                       /*
+                        * we've joined a transaction, make sure it isn't
+                        * closing right now
+                        */
+                       if (trans->transaction->delayed_refs.flushing) {
+                               btrfs_end_transaction(trans, tree_root);
+                               continue;
+                       }
+
                        mutex_lock(&root->fs_info->drop_mutex);
                        ret = btrfs_drop_snapshot(trans, dirty->root);
                        if (ret != -EAGAIN)
@@ -766,7 +844,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
 
        old = btrfs_lock_root_node(root);
-       btrfs_cow_block(trans, root, old, NULL, 0, &old, 0);
+       btrfs_cow_block(trans, root, old, NULL, 0, &old);
 
        btrfs_copy_root(trans, root, old, &tmp, objectid);
        btrfs_tree_unlock(old);
@@ -894,12 +972,31 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        struct extent_io_tree *pinned_copy;
        DEFINE_WAIT(wait);
        int ret;
+       int should_grow = 0;
+       unsigned long now = get_seconds();
+
+       btrfs_run_ordered_operations(root, 0);
+
+       /* make a pass through all the delayed refs we have so far
+        * any runnings procs may add more while we are here
+        */
+       ret = btrfs_run_delayed_refs(trans, root, 0);
+       BUG_ON(ret);
+
+       cur_trans = trans->transaction;
+       /*
+        * set the flushing flag so procs in this transaction have to
+        * start sending their work down.
+        */
+       cur_trans->delayed_refs.flushing = 1;
+
+       ret = btrfs_run_delayed_refs(trans, root, 0);
+       BUG_ON(ret);
 
-       INIT_LIST_HEAD(&dirty_fs_roots);
        mutex_lock(&root->fs_info->trans_mutex);
-       if (trans->transaction->in_commit) {
-               cur_trans = trans->transaction;
-               trans->transaction->use_count++;
+       INIT_LIST_HEAD(&dirty_fs_roots);
+       if (cur_trans->in_commit) {
+               cur_trans->use_count++;
                mutex_unlock(&root->fs_info->trans_mutex);
                btrfs_end_transaction(trans, root);
 
@@ -922,7 +1019,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        trans->transaction->in_commit = 1;
        trans->transaction->blocked = 1;
-       cur_trans = trans->transaction;
        if (cur_trans->list.prev != &root->fs_info->trans_list) {
                prev_trans = list_entry(cur_trans->list.prev,
                                        struct btrfs_transaction, list);
@@ -937,6 +1033,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                }
        }
 
+       if (now < cur_trans->start_time || now - cur_trans->start_time < 1)
+               should_grow = 1;
+
        do {
                int snap_pending = 0;
                joined = cur_trans->num_joined;
@@ -949,7 +1048,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
                if (cur_trans->num_writers > 1)
                        timeout = MAX_SCHEDULE_TIMEOUT;
-               else
+               else if (should_grow)
                        timeout = 1;
 
                mutex_unlock(&root->fs_info->trans_mutex);
@@ -959,16 +1058,30 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                        BUG_ON(ret);
                }
 
-               schedule_timeout(timeout);
+               /*
+                * rename don't use btrfs_join_transaction, so, once we
+                * set the transaction to blocked above, we aren't going
+                * to get any new ordered operations.  We can safely run
+                * it here and no for sure that nothing new will be added
+                * to the list
+                */
+               btrfs_run_ordered_operations(root, 1);
+
+               smp_mb();
+               if (cur_trans->num_writers > 1 || should_grow)
+                       schedule_timeout(timeout);
 
                mutex_lock(&root->fs_info->trans_mutex);
                finish_wait(&cur_trans->writer_wait, &wait);
        } while (cur_trans->num_writers > 1 ||
-                (cur_trans->num_joined != joined));
+                (should_grow && cur_trans->num_joined != joined));
 
        ret = create_pending_snapshots(trans, root->fs_info);
        BUG_ON(ret);
 
+       ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+       BUG_ON(ret);
+
        WARN_ON(cur_trans != trans->transaction);
 
        /* btrfs_commit_tree_roots is responsible for getting the
@@ -1032,6 +1145,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        btrfs_copy_pinned(root, pinned_copy);
 
        trans->transaction->blocked = 0;
+
        wake_up(&root->fs_info->transaction_throttle);
        wake_up(&root->fs_info->transaction_wait);
 
@@ -1058,6 +1172,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        mutex_lock(&root->fs_info->trans_mutex);
 
        cur_trans->commit_done = 1;
+
        root->fs_info->last_trans_committed = cur_trans->transid;
        wake_up(&cur_trans->commit_wait);
 
index ea292117f88252f2f6c14ccde2cce4eac50d9509..94f5bde2b58d40144a5d5ddf3a11607cef4b0e82 100644 (file)
 #ifndef __BTRFS_TRANSACTION__
 #define __BTRFS_TRANSACTION__
 #include "btrfs_inode.h"
+#include "delayed-ref.h"
 
 struct btrfs_transaction {
        u64 transid;
+       /*
+        * total writers in this transaction, it must be zero before the
+        * transaction can end
+        */
        unsigned long num_writers;
+
        unsigned long num_joined;
        int in_commit;
        int use_count;
@@ -34,6 +40,7 @@ struct btrfs_transaction {
        wait_queue_head_t writer_wait;
        wait_queue_head_t commit_wait;
        struct list_head pending_snapshots;
+       struct btrfs_delayed_ref_root delayed_refs;
 };
 
 struct btrfs_trans_handle {
@@ -44,6 +51,7 @@ struct btrfs_trans_handle {
        u64 block_group;
        u64 alloc_exclude_start;
        u64 alloc_exclude_nr;
+       unsigned long delayed_ref_updates;
 };
 
 struct btrfs_pending_snapshot {
index 98d25fa4570ea902abc4c8345ecf29f62af9013c..b10eacdb16200e686b3519a46747b706b927761f 100644 (file)
@@ -124,8 +124,6 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
        }
 
        btrfs_release_path(root, path);
-       if (is_extent)
-               btrfs_extent_post_op(trans, root);
 out:
        if (path)
                btrfs_free_path(path);
index 9c462fbd60fac14ad17f192afb08c37794295d36..fc9b87a7975bd38f76d7e22c84cfe010e3aafa42 100644 (file)
 #define LOG_INODE_ALL 0
 #define LOG_INODE_EXISTS 1
 
+/*
+ * directory trouble cases
+ *
+ * 1) on rename or unlink, if the inode being unlinked isn't in the fsync
+ * log, we must force a full commit before doing an fsync of the directory
+ * where the unlink was done.
+ * ---> record transid of last unlink/rename per directory
+ *
+ * mkdir foo/some_dir
+ * normal commit
+ * rename foo/some_dir foo2/some_dir
+ * mkdir foo/some_dir
+ * fsync foo/some_dir/some_file
+ *
+ * The fsync above will unlink the original some_dir without recording
+ * it in its new location (foo2).  After a crash, some_dir will be gone
+ * unless the fsync of some_file forces a full commit
+ *
+ * 2) we must log any new names for any file or dir that is in the fsync
+ * log. ---> check inode while renaming/linking.
+ *
+ * 2a) we must log any new names for any file or dir during rename
+ * when the directory they are being removed from was logged.
+ * ---> check inode and old parent dir during rename
+ *
+ *  2a is actually the more important variant.  With the extra logging
+ *  a crash might unlink the old name without recreating the new one
+ *
+ * 3) after a crash, we must go through any directories with a link count
+ * of zero and redo the rm -rf
+ *
+ * mkdir f1/foo
+ * normal commit
+ * rm -rf f1/foo
+ * fsync(f1)
+ *
+ * The directory f1 was fully removed from the FS, but fsync was never
+ * called on f1, only its parent dir.  After a crash the rm -rf must
+ * be replayed.  This must be able to recurse down the entire
+ * directory tree.  The inode link count fixup code takes care of the
+ * ugly details.
+ */
+
 /*
  * stages for the tree walking.  The first
  * stage (0) is to only pin down the blocks we find
 #define LOG_WALK_REPLAY_INODES 1
 #define LOG_WALK_REPLAY_ALL 2
 
-static int __btrfs_log_inode(struct btrfs_trans_handle *trans,
+static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root, struct inode *inode,
                             int inode_only);
 static int link_to_fixup_dir(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             struct btrfs_path *path, u64 objectid);
+static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
+                                      struct btrfs_root *root,
+                                      struct btrfs_root *log,
+                                      struct btrfs_path *path,
+                                      u64 dirid, int del_all);
 
 /*
  * tree logging is a special write ahead log used to make sure that
@@ -132,11 +180,26 @@ static int join_running_log_trans(struct btrfs_root *root)
        return ret;
 }
 
+/*
+ * This either makes the current running log transaction wait
+ * until you call btrfs_end_log_trans() or it makes any future
+ * log transactions wait until you call btrfs_end_log_trans()
+ */
+int btrfs_pin_log_trans(struct btrfs_root *root)
+{
+       int ret = -ENOENT;
+
+       mutex_lock(&root->log_mutex);
+       atomic_inc(&root->log_writers);
+       mutex_unlock(&root->log_mutex);
+       return ret;
+}
+
 /*
  * indicate we're done making changes to the log tree
  * and wake up anyone waiting to do a sync
  */
-static int end_log_trans(struct btrfs_root *root)
+int btrfs_end_log_trans(struct btrfs_root *root)
 {
        if (atomic_dec_and_test(&root->log_writers)) {
                smp_mb();
@@ -203,7 +266,6 @@ static int process_one_buffer(struct btrfs_root *log,
                mutex_lock(&log->fs_info->pinned_mutex);
                btrfs_update_pinned_extents(log->fs_info->extent_root,
                                            eb->start, eb->len, 1);
-               mutex_unlock(&log->fs_info->pinned_mutex);
        }
 
        if (btrfs_buffer_uptodate(eb, gen)) {
@@ -603,6 +665,7 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
 
        ret = link_to_fixup_dir(trans, root, path, location.objectid);
        BUG_ON(ret);
+
        ret = btrfs_unlink_inode(trans, root, dir, inode, name, name_len);
        BUG_ON(ret);
        kfree(name);
@@ -804,6 +867,7 @@ conflict_again:
                                            victim_name_len)) {
                                btrfs_inc_nlink(inode);
                                btrfs_release_path(root, path);
+
                                ret = btrfs_unlink_inode(trans, root, dir,
                                                         inode, victim_name,
                                                         victim_name_len);
@@ -922,13 +986,20 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
                key.offset--;
                btrfs_release_path(root, path);
        }
-       btrfs_free_path(path);
+       btrfs_release_path(root, path);
        if (nlink != inode->i_nlink) {
                inode->i_nlink = nlink;
                btrfs_update_inode(trans, root, inode);
        }
        BTRFS_I(inode)->index_cnt = (u64)-1;
 
+       if (inode->i_nlink == 0 && S_ISDIR(inode->i_mode)) {
+               ret = replay_dir_deletes(trans, root, NULL, path,
+                                        inode->i_ino, 1);
+               BUG_ON(ret);
+       }
+       btrfs_free_path(path);
+
        return 0;
 }
 
@@ -971,9 +1042,12 @@ static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans,
 
                iput(inode);
 
-               if (key.offset == 0)
-                       break;
-               key.offset--;
+               /*
+                * fixup on a directory may create new entries,
+                * make sure we always look for the highset possible
+                * offset
+                */
+               key.offset = (u64)-1;
        }
        btrfs_release_path(root, path);
        return 0;
@@ -1313,11 +1387,11 @@ again:
                read_extent_buffer(eb, name, (unsigned long)(di + 1),
                                  name_len);
                log_di = NULL;
-               if (dir_key->type == BTRFS_DIR_ITEM_KEY) {
+               if (log && dir_key->type == BTRFS_DIR_ITEM_KEY) {
                        log_di = btrfs_lookup_dir_item(trans, log, log_path,
                                                       dir_key->objectid,
                                                       name, name_len, 0);
-               } else if (dir_key->type == BTRFS_DIR_INDEX_KEY) {
+               } else if (log && dir_key->type == BTRFS_DIR_INDEX_KEY) {
                        log_di = btrfs_lookup_dir_index_item(trans, log,
                                                     log_path,
                                                     dir_key->objectid,
@@ -1378,7 +1452,7 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
                                       struct btrfs_root *root,
                                       struct btrfs_root *log,
                                       struct btrfs_path *path,
-                                      u64 dirid)
+                                      u64 dirid, int del_all)
 {
        u64 range_start;
        u64 range_end;
@@ -1408,10 +1482,14 @@ again:
        range_start = 0;
        range_end = 0;
        while (1) {
-               ret = find_dir_range(log, path, dirid, key_type,
-                                    &range_start, &range_end);
-               if (ret != 0)
-                       break;
+               if (del_all)
+                       range_end = (u64)-1;
+               else {
+                       ret = find_dir_range(log, path, dirid, key_type,
+                                            &range_start, &range_end);
+                       if (ret != 0)
+                               break;
+               }
 
                dir_key.offset = range_start;
                while (1) {
@@ -1437,7 +1515,8 @@ again:
                                break;
 
                        ret = check_item_in_log(trans, root, log, path,
-                                               log_path, dir, &found_key);
+                                               log_path, dir,
+                                               &found_key);
                        BUG_ON(ret);
                        if (found_key.offset == (u64)-1)
                                break;
@@ -1514,7 +1593,7 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
                        mode = btrfs_inode_mode(eb, inode_item);
                        if (S_ISDIR(mode)) {
                                ret = replay_dir_deletes(wc->trans,
-                                        root, log, path, key.objectid);
+                                        root, log, path, key.objectid, 0);
                                BUG_ON(ret);
                        }
                        ret = overwrite_item(wc->trans, root, path,
@@ -1533,6 +1612,17 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
                                        root, inode, inode->i_size,
                                        BTRFS_EXTENT_DATA_KEY);
                                BUG_ON(ret);
+
+                               /* if the nlink count is zero here, the iput
+                                * will free the inode.  We bump it to make
+                                * sure it doesn't get freed until the link
+                                * count fixup is done
+                                */
+                               if (inode->i_nlink == 0) {
+                                       btrfs_inc_nlink(inode);
+                                       btrfs_update_inode(wc->trans,
+                                                          root, inode);
+                               }
                                iput(inode);
                        }
                        ret = link_to_fixup_dir(wc->trans, root,
@@ -1840,7 +1930,8 @@ static int update_log_root(struct btrfs_trans_handle *trans,
        return ret;
 }
 
-static int wait_log_commit(struct btrfs_root *root, unsigned long transid)
+static int wait_log_commit(struct btrfs_trans_handle *trans,
+                          struct btrfs_root *root, unsigned long transid)
 {
        DEFINE_WAIT(wait);
        int index = transid % 2;
@@ -1854,9 +1945,12 @@ static int wait_log_commit(struct btrfs_root *root, unsigned long transid)
                prepare_to_wait(&root->log_commit_wait[index],
                                &wait, TASK_UNINTERRUPTIBLE);
                mutex_unlock(&root->log_mutex);
-               if (root->log_transid < transid + 2 &&
+
+               if (root->fs_info->last_trans_log_full_commit !=
+                   trans->transid && root->log_transid < transid + 2 &&
                    atomic_read(&root->log_commit[index]))
                        schedule();
+
                finish_wait(&root->log_commit_wait[index], &wait);
                mutex_lock(&root->log_mutex);
        } while (root->log_transid < transid + 2 &&
@@ -1864,14 +1958,16 @@ static int wait_log_commit(struct btrfs_root *root, unsigned long transid)
        return 0;
 }
 
-static int wait_for_writer(struct btrfs_root *root)
+static int wait_for_writer(struct btrfs_trans_handle *trans,
+                          struct btrfs_root *root)
 {
        DEFINE_WAIT(wait);
        while (atomic_read(&root->log_writers)) {
                prepare_to_wait(&root->log_writer_wait,
                                &wait, TASK_UNINTERRUPTIBLE);
                mutex_unlock(&root->log_mutex);
-               if (atomic_read(&root->log_writers))
+               if (root->fs_info->last_trans_log_full_commit !=
+                   trans->transid && atomic_read(&root->log_writers))
                        schedule();
                mutex_lock(&root->log_mutex);
                finish_wait(&root->log_writer_wait, &wait);
@@ -1882,7 +1978,14 @@ static int wait_for_writer(struct btrfs_root *root)
 /*
  * btrfs_sync_log does sends a given tree log down to the disk and
  * updates the super blocks to record it.  When this call is done,
- * you know that any inodes previously logged are safely on disk
+ * you know that any inodes previously logged are safely on disk only
+ * if it returns 0.
+ *
+ * Any other return value means you need to call btrfs_commit_transaction.
+ * Some of the edge cases for fsyncing directories that have had unlinks
+ * or renames done in the past mean that sometimes the only safe
+ * fsync is to commit the whole FS.  When btrfs_sync_log returns -EAGAIN,
+ * that has happened.
  */
 int btrfs_sync_log(struct btrfs_trans_handle *trans,
                   struct btrfs_root *root)
@@ -1896,7 +1999,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
        mutex_lock(&root->log_mutex);
        index1 = root->log_transid % 2;
        if (atomic_read(&root->log_commit[index1])) {
-               wait_log_commit(root, root->log_transid);
+               wait_log_commit(trans, root, root->log_transid);
                mutex_unlock(&root->log_mutex);
                return 0;
        }
@@ -1904,18 +2007,26 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
 
        /* wait for previous tree log sync to complete */
        if (atomic_read(&root->log_commit[(index1 + 1) % 2]))
-               wait_log_commit(root, root->log_transid - 1);
+               wait_log_commit(trans, root, root->log_transid - 1);
 
        while (1) {
                unsigned long batch = root->log_batch;
                mutex_unlock(&root->log_mutex);
                schedule_timeout_uninterruptible(1);
                mutex_lock(&root->log_mutex);
-               wait_for_writer(root);
+
+               wait_for_writer(trans, root);
                if (batch == root->log_batch)
                        break;
        }
 
+       /* bail out if we need to do a full commit */
+       if (root->fs_info->last_trans_log_full_commit == trans->transid) {
+               ret = -EAGAIN;
+               mutex_unlock(&root->log_mutex);
+               goto out;
+       }
+
        ret = btrfs_write_and_wait_marked_extents(log, &log->dirty_log_pages);
        BUG_ON(ret);
 
@@ -1951,16 +2062,29 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
 
        index2 = log_root_tree->log_transid % 2;
        if (atomic_read(&log_root_tree->log_commit[index2])) {
-               wait_log_commit(log_root_tree, log_root_tree->log_transid);
+               wait_log_commit(trans, log_root_tree,
+                               log_root_tree->log_transid);
                mutex_unlock(&log_root_tree->log_mutex);
                goto out;
        }
        atomic_set(&log_root_tree->log_commit[index2], 1);
 
-       if (atomic_read(&log_root_tree->log_commit[(index2 + 1) % 2]))
-               wait_log_commit(log_root_tree, log_root_tree->log_transid - 1);
+       if (atomic_read(&log_root_tree->log_commit[(index2 + 1) % 2])) {
+               wait_log_commit(trans, log_root_tree,
+                               log_root_tree->log_transid - 1);
+       }
+
+       wait_for_writer(trans, log_root_tree);
 
-       wait_for_writer(log_root_tree);
+       /*
+        * now that we've moved on to the tree of log tree roots,
+        * check the full commit flag again
+        */
+       if (root->fs_info->last_trans_log_full_commit == trans->transid) {
+               mutex_unlock(&log_root_tree->log_mutex);
+               ret = -EAGAIN;
+               goto out_wake_log_root;
+       }
 
        ret = btrfs_write_and_wait_marked_extents(log_root_tree,
                                &log_root_tree->dirty_log_pages);
@@ -1985,7 +2109,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
         * in and cause problems either.
         */
        write_ctree_super(trans, root->fs_info->tree_root, 2);
+       ret = 0;
 
+out_wake_log_root:
        atomic_set(&log_root_tree->log_commit[index2], 0);
        smp_mb();
        if (waitqueue_active(&log_root_tree->log_commit_wait[index2]))
@@ -1998,7 +2124,8 @@ out:
        return 0;
 }
 
-/* * free all the extents used by the tree log.  This should be called
+/*
+ * free all the extents used by the tree log.  This should be called
  * at commit time of the full transaction
  */
 int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
@@ -2132,7 +2259,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
 
        btrfs_free_path(path);
        mutex_unlock(&BTRFS_I(dir)->log_mutex);
-       end_log_trans(root);
+       btrfs_end_log_trans(root);
 
        return 0;
 }
@@ -2159,7 +2286,7 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
        ret = btrfs_del_inode_ref(trans, log, name, name_len, inode->i_ino,
                                  dirid, &index);
        mutex_unlock(&BTRFS_I(inode)->log_mutex);
-       end_log_trans(root);
+       btrfs_end_log_trans(root);
 
        return ret;
 }
@@ -2559,7 +2686,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
  *
  * This handles both files and directories.
  */
-static int __btrfs_log_inode(struct btrfs_trans_handle *trans,
+static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root, struct inode *inode,
                             int inode_only)
 {
@@ -2585,28 +2712,17 @@ static int __btrfs_log_inode(struct btrfs_trans_handle *trans,
        min_key.offset = 0;
 
        max_key.objectid = inode->i_ino;
+
+       /* today the code can only do partial logging of directories */
+       if (!S_ISDIR(inode->i_mode))
+           inode_only = LOG_INODE_ALL;
+
        if (inode_only == LOG_INODE_EXISTS || S_ISDIR(inode->i_mode))
                max_key.type = BTRFS_XATTR_ITEM_KEY;
        else
                max_key.type = (u8)-1;
        max_key.offset = (u64)-1;
 
-       /*
-        * if this inode has already been logged and we're in inode_only
-        * mode, we don't want to delete the things that have already
-        * been written to the log.
-        *
-        * But, if the inode has been through an inode_only log,
-        * the logged_trans field is not set.  This allows us to catch
-        * any new names for this inode in the backrefs by logging it
-        * again
-        */
-       if (inode_only == LOG_INODE_EXISTS &&
-           BTRFS_I(inode)->logged_trans == trans->transid) {
-               btrfs_free_path(path);
-               btrfs_free_path(dst_path);
-               goto out;
-       }
        mutex_lock(&BTRFS_I(inode)->log_mutex);
 
        /*
@@ -2693,7 +2809,6 @@ next_slot:
        if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) {
                btrfs_release_path(root, path);
                btrfs_release_path(log, dst_path);
-               BTRFS_I(inode)->log_dirty_trans = 0;
                ret = log_directory_changes(trans, root, inode, path, dst_path);
                BUG_ON(ret);
        }
@@ -2702,19 +2817,69 @@ next_slot:
 
        btrfs_free_path(path);
        btrfs_free_path(dst_path);
-out:
        return 0;
 }
 
-int btrfs_log_inode(struct btrfs_trans_handle *trans,
-                   struct btrfs_root *root, struct inode *inode,
-                   int inode_only)
+/*
+ * follow the dentry parent pointers up the chain and see if any
+ * of the directories in it require a full commit before they can
+ * be logged.  Returns zero if nothing special needs to be done or 1 if
+ * a full commit is required.
+ */
+static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
+                                              struct inode *inode,
+                                              struct dentry *parent,
+                                              struct super_block *sb,
+                                              u64 last_committed)
 {
-       int ret;
+       int ret = 0;
+       struct btrfs_root *root;
 
-       start_log_trans(trans, root);
-       ret = __btrfs_log_inode(trans, root, inode, inode_only);
-       end_log_trans(root);
+       /*
+        * for regular files, if its inode is already on disk, we don't
+        * have to worry about the parents at all.  This is because
+        * we can use the last_unlink_trans field to record renames
+        * and other fun in this file.
+        */
+       if (S_ISREG(inode->i_mode) &&
+           BTRFS_I(inode)->generation <= last_committed &&
+           BTRFS_I(inode)->last_unlink_trans <= last_committed)
+                       goto out;
+
+       if (!S_ISDIR(inode->i_mode)) {
+               if (!parent || !parent->d_inode || sb != parent->d_inode->i_sb)
+                       goto out;
+               inode = parent->d_inode;
+       }
+
+       while (1) {
+               BTRFS_I(inode)->logged_trans = trans->transid;
+               smp_mb();
+
+               if (BTRFS_I(inode)->last_unlink_trans > last_committed) {
+                       root = BTRFS_I(inode)->root;
+
+                       /*
+                        * make sure any commits to the log are forced
+                        * to be full commits
+                        */
+                       root->fs_info->last_trans_log_full_commit =
+                               trans->transid;
+                       ret = 1;
+                       break;
+               }
+
+               if (!parent || !parent->d_inode || sb != parent->d_inode->i_sb)
+                       break;
+
+               if (parent == sb->s_root)
+                       break;
+
+               parent = parent->d_parent;
+               inode = parent->d_inode;
+
+       }
+out:
        return ret;
 }
 
@@ -2724,31 +2889,65 @@ int btrfs_log_inode(struct btrfs_trans_handle *trans,
  * only logging is done of any parent directories that are older than
  * the last committed transaction
  */
-int btrfs_log_dentry(struct btrfs_trans_handle *trans,
-                   struct btrfs_root *root, struct dentry *dentry)
+int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
+                   struct btrfs_root *root, struct inode *inode,
+                   struct dentry *parent, int exists_only)
 {
-       int inode_only = LOG_INODE_ALL;
+       int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL;
        struct super_block *sb;
-       int ret;
+       int ret = 0;
+       u64 last_committed = root->fs_info->last_trans_committed;
+
+       sb = inode->i_sb;
+
+       if (root->fs_info->last_trans_log_full_commit >
+           root->fs_info->last_trans_committed) {
+               ret = 1;
+               goto end_no_trans;
+       }
+
+       ret = check_parent_dirs_for_sync(trans, inode, parent,
+                                        sb, last_committed);
+       if (ret)
+               goto end_no_trans;
 
        start_log_trans(trans, root);
-       sb = dentry->d_inode->i_sb;
-       while (1) {
-               ret = __btrfs_log_inode(trans, root, dentry->d_inode,
-                                       inode_only);
-               BUG_ON(ret);
-               inode_only = LOG_INODE_EXISTS;
 
-               dentry = dentry->d_parent;
-               if (!dentry || !dentry->d_inode || sb != dentry->d_inode->i_sb)
+       ret = btrfs_log_inode(trans, root, inode, inode_only);
+       BUG_ON(ret);
+
+       /*
+        * for regular files, if its inode is already on disk, we don't
+        * have to worry about the parents at all.  This is because
+        * we can use the last_unlink_trans field to record renames
+        * and other fun in this file.
+        */
+       if (S_ISREG(inode->i_mode) &&
+           BTRFS_I(inode)->generation <= last_committed &&
+           BTRFS_I(inode)->last_unlink_trans <= last_committed)
+                       goto no_parent;
+
+       inode_only = LOG_INODE_EXISTS;
+       while (1) {
+               if (!parent || !parent->d_inode || sb != parent->d_inode->i_sb)
                        break;
 
-               if (BTRFS_I(dentry->d_inode)->generation <=
-                   root->fs_info->last_trans_committed)
+               inode = parent->d_inode;
+               if (BTRFS_I(inode)->generation >
+                   root->fs_info->last_trans_committed) {
+                       ret = btrfs_log_inode(trans, root, inode, inode_only);
+                       BUG_ON(ret);
+               }
+               if (parent == sb->s_root)
                        break;
+
+               parent = parent->d_parent;
        }
-       end_log_trans(root);
-       return 0;
+no_parent:
+       ret = 0;
+       btrfs_end_log_trans(root);
+end_no_trans:
+       return ret;
 }
 
 /*
@@ -2760,12 +2959,8 @@ int btrfs_log_dentry(struct btrfs_trans_handle *trans,
 int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root, struct dentry *dentry)
 {
-       u64 gen;
-       gen = root->fs_info->last_trans_new_blockgroup;
-       if (gen > root->fs_info->last_trans_committed)
-               return 1;
-       else
-               return btrfs_log_dentry(trans, root, dentry);
+       return btrfs_log_inode_parent(trans, root, dentry->d_inode,
+                                     dentry->d_parent, 0);
 }
 
 /*
@@ -2884,3 +3079,94 @@ again:
        kfree(log_root_tree);
        return 0;
 }
+
+/*
+ * there are some corner cases where we want to force a full
+ * commit instead of allowing a directory to be logged.
+ *
+ * They revolve around files there were unlinked from the directory, and
+ * this function updates the parent directory so that a full commit is
+ * properly done if it is fsync'd later after the unlinks are done.
+ */
+void btrfs_record_unlink_dir(struct btrfs_trans_handle *trans,
+                            struct inode *dir, struct inode *inode,
+                            int for_rename)
+{
+       /*
+        * when we're logging a file, if it hasn't been renamed
+        * or unlinked, and its inode is fully committed on disk,
+        * we don't have to worry about walking up the directory chain
+        * to log its parents.
+        *
+        * So, we use the last_unlink_trans field to put this transid
+        * into the file.  When the file is logged we check it and
+        * don't log the parents if the file is fully on disk.
+        */
+       if (S_ISREG(inode->i_mode))
+               BTRFS_I(inode)->last_unlink_trans = trans->transid;
+
+       /*
+        * if this directory was already logged any new
+        * names for this file/dir will get recorded
+        */
+       smp_mb();
+       if (BTRFS_I(dir)->logged_trans == trans->transid)
+               return;
+
+       /*
+        * if the inode we're about to unlink was logged,
+        * the log will be properly updated for any new names
+        */
+       if (BTRFS_I(inode)->logged_trans == trans->transid)
+               return;
+
+       /*
+        * when renaming files across directories, if the directory
+        * there we're unlinking from gets fsync'd later on, there's
+        * no way to find the destination directory later and fsync it
+        * properly.  So, we have to be conservative and force commits
+        * so the new name gets discovered.
+        */
+       if (for_rename)
+               goto record;
+
+       /* we can safely do the unlink without any special recording */
+       return;
+
+record:
+       BTRFS_I(dir)->last_unlink_trans = trans->transid;
+}
+
+/*
+ * Call this after adding a new name for a file and it will properly
+ * update the log to reflect the new name.
+ *
+ * It will return zero if all goes well, and it will return 1 if a
+ * full transaction commit is required.
+ */
+int btrfs_log_new_name(struct btrfs_trans_handle *trans,
+                       struct inode *inode, struct inode *old_dir,
+                       struct dentry *parent)
+{
+       struct btrfs_root * root = BTRFS_I(inode)->root;
+
+       /*
+        * this will force the logging code to walk the dentry chain
+        * up for the file
+        */
+       if (S_ISREG(inode->i_mode))
+               BTRFS_I(inode)->last_unlink_trans = trans->transid;
+
+       /*
+        * if this inode hasn't been logged and directory we're renaming it
+        * from hasn't been logged, we don't need to log it
+        */
+       if (BTRFS_I(inode)->logged_trans <=
+           root->fs_info->last_trans_committed &&
+           (!old_dir || BTRFS_I(old_dir)->logged_trans <=
+                   root->fs_info->last_trans_committed))
+               return 0;
+
+       return btrfs_log_inode_parent(trans, root, inode, parent, 1);
+}
+
index b9409b32ed0299a43f0b04b4598ec8b3d9b266b8..d09c7609e16b3281a0b7658083888c277fb1ccf8 100644 (file)
 int btrfs_sync_log(struct btrfs_trans_handle *trans,
                   struct btrfs_root *root);
 int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root);
-int btrfs_log_dentry(struct btrfs_trans_handle *trans,
-                   struct btrfs_root *root, struct dentry *dentry);
 int btrfs_recover_log_trees(struct btrfs_root *tree_root);
 int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root, struct dentry *dentry);
-int btrfs_log_inode(struct btrfs_trans_handle *trans,
-                   struct btrfs_root *root, struct inode *inode,
-                   int inode_only);
 int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root,
                                 const char *name, int name_len,
@@ -38,4 +33,16 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
                               struct btrfs_root *root,
                               const char *name, int name_len,
                               struct inode *inode, u64 dirid);
+int btrfs_join_running_log_trans(struct btrfs_root *root);
+int btrfs_end_log_trans(struct btrfs_root *root);
+int btrfs_pin_log_trans(struct btrfs_root *root);
+int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
+                   struct btrfs_root *root, struct inode *inode,
+                   struct dentry *parent, int exists_only);
+void btrfs_record_unlink_dir(struct btrfs_trans_handle *trans,
+                            struct inode *dir, struct inode *inode,
+                            int for_rename);
+int btrfs_log_new_name(struct btrfs_trans_handle *trans,
+                       struct inode *inode, struct inode *old_dir,
+                       struct dentry *parent);
 #endif
index a2fd743d97cb85380b5140e5d84ba9c50c383b84..2963858f0f31f106b878966c75ca09991c7486f7 100644 (file)
@@ -199,13 +199,13 @@ __find_get_block_slow(struct block_device *bdev, sector_t block)
        head = page_buffers(page);
        bh = head;
        do {
-               if (bh->b_blocknr == block) {
+               if (!buffer_mapped(bh))
+                       all_mapped = 0;
+               else if (bh->b_blocknr == block) {
                        ret = bh;
                        get_bh(bh);
                        goto out_unlock;
                }
-               if (!buffer_mapped(bh))
-                       all_mapped = 0;
                bh = bh->b_this_page;
        } while (bh != head);
 
@@ -290,7 +290,7 @@ static void free_more_memory(void)
                                                &zone);
                if (zone)
                        try_to_free_pages(node_zonelist(nid, GFP_NOFS), 0,
-                                               GFP_NOFS);
+                                               GFP_NOFS, NULL);
        }
 }
 
@@ -547,6 +547,39 @@ repeat:
        return err;
 }
 
+void do_thaw_all(unsigned long unused)
+{
+       struct super_block *sb;
+       char b[BDEVNAME_SIZE];
+
+       spin_lock(&sb_lock);
+restart:
+       list_for_each_entry(sb, &super_blocks, s_list) {
+               sb->s_count++;
+               spin_unlock(&sb_lock);
+               down_read(&sb->s_umount);
+               while (sb->s_bdev && !thaw_bdev(sb->s_bdev, sb))
+                       printk(KERN_WARNING "Emergency Thaw on %s\n",
+                              bdevname(sb->s_bdev, b));
+               up_read(&sb->s_umount);
+               spin_lock(&sb_lock);
+               if (__put_super_and_need_restart(sb))
+                       goto restart;
+       }
+       spin_unlock(&sb_lock);
+       printk(KERN_WARNING "Emergency Thaw complete\n");
+}
+
+/**
+ * emergency_thaw_all -- forcibly thaw every frozen filesystem
+ *
+ * Used for emergency unfreeze of all filesystems via SysRq
+ */
+void emergency_thaw_all(void)
+{
+       pdflush_operation(do_thaw_all, 0);
+}
+
 /**
  * sync_mapping_buffers - write out & wait upon a mapping's "associated" buffers
  * @mapping: the mapping which wants those buffers written
@@ -621,14 +654,7 @@ static void __set_page_dirty(struct page *page,
        spin_lock_irq(&mapping->tree_lock);
        if (page->mapping) {    /* Race with truncate? */
                WARN_ON_ONCE(warn && !PageUptodate(page));
-
-               if (mapping_cap_account_dirty(mapping)) {
-                       __inc_zone_page_state(page, NR_FILE_DIRTY);
-                       __inc_bdi_stat(mapping->backing_dev_info,
-                                       BDI_RECLAIMABLE);
-                       task_dirty_inc(current);
-                       task_io_account_write(PAGE_CACHE_SIZE);
-               }
+               account_page_dirtied(page, mapping);
                radix_tree_tag_set(&mapping->page_tree,
                                page_index(page), PAGECACHE_TAG_DIRTY);
        }
@@ -2320,13 +2346,14 @@ int block_commit_write(struct page *page, unsigned from, unsigned to)
  * unlock the page.
  */
 int
-block_page_mkwrite(struct vm_area_struct *vma, struct page *page,
+block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
                   get_block_t get_block)
 {
+       struct page *page = vmf->page;
        struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
        unsigned long end;
        loff_t size;
-       int ret = -EINVAL;
+       int ret = VM_FAULT_NOPAGE; /* make the VM retry the fault */
 
        lock_page(page);
        size = i_size_read(inode);
@@ -2346,6 +2373,13 @@ block_page_mkwrite(struct vm_area_struct *vma, struct page *page,
        if (!ret)
                ret = block_commit_write(page, 0, end);
 
+       if (unlikely(ret)) {
+               if (ret == -ENOMEM)
+                       ret = VM_FAULT_OOM;
+               else /* -ENOSPC, -EIO, etc */
+                       ret = VM_FAULT_SIGBUS;
+       }
+
 out_unlock:
        unlock_page(page);
        return ret;
index 877e4d9a1159d11203170ec463202187dd3a6466..7f19fefd3d45a2790d426e68e59f80f687b4911c 100644 (file)
@@ -404,7 +404,6 @@ cifs_proc_init(void)
        if (proc_fs_cifs == NULL)
                return;
 
-       proc_fs_cifs->owner = THIS_MODULE;
        proc_create("DebugData", 0, proc_fs_cifs, &cifs_debug_data_proc_fops);
 
 #ifdef CONFIG_CIFS_STATS
index 5e374aad33f73a8b478677b724f65f7b0835699b..440a019256ddde7a0283f23496f629a97e1f6b13 100644 (file)
@@ -1195,16 +1195,12 @@ out:
        return ret;
 }
 
-asmlinkage ssize_t
-compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen)
+static size_t compat_readv(struct file *file,
+                          const struct compat_iovec __user *vec,
+                          unsigned long vlen, loff_t *pos)
 {
-       struct file *file;
        ssize_t ret = -EBADF;
 
-       file = fget(fd);
-       if (!file)
-               return -EBADF;
-
        if (!(file->f_mode & FMODE_READ))
                goto out;
 
@@ -1212,25 +1208,56 @@ compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsign
        if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
                goto out;
 
-       ret = compat_do_readv_writev(READ, file, vec, vlen, &file->f_pos);
+       ret = compat_do_readv_writev(READ, file, vec, vlen, pos);
 
 out:
        if (ret > 0)
                add_rchar(current, ret);
        inc_syscr(current);
-       fput(file);
        return ret;
 }
 
 asmlinkage ssize_t
-compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen)
+compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec,
+                unsigned long vlen)
 {
        struct file *file;
-       ssize_t ret = -EBADF;
+       int fput_needed;
+       ssize_t ret;
 
-       file = fget(fd);
+       file = fget_light(fd, &fput_needed);
        if (!file)
                return -EBADF;
+       ret = compat_readv(file, vec, vlen, &file->f_pos);
+       fput_light(file, fput_needed);
+       return ret;
+}
+
+asmlinkage ssize_t
+compat_sys_preadv(unsigned long fd, const struct compat_iovec __user *vec,
+                 unsigned long vlen, u32 pos_high, u32 pos_low)
+{
+       loff_t pos = ((loff_t)pos_high << 32) | pos_low;
+       struct file *file;
+       int fput_needed;
+       ssize_t ret;
+
+       if (pos < 0)
+               return -EINVAL;
+       file = fget_light(fd, &fput_needed);
+       if (!file)
+               return -EBADF;
+       ret = compat_readv(file, vec, vlen, &pos);
+       fput_light(file, fput_needed);
+       return ret;
+}
+
+static size_t compat_writev(struct file *file,
+                           const struct compat_iovec __user *vec,
+                           unsigned long vlen, loff_t *pos)
+{
+       ssize_t ret = -EBADF;
+
        if (!(file->f_mode & FMODE_WRITE))
                goto out;
 
@@ -1238,13 +1265,47 @@ compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, unsig
        if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
                goto out;
 
-       ret = compat_do_readv_writev(WRITE, file, vec, vlen, &file->f_pos);
+       ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos);
 
 out:
        if (ret > 0)
                add_wchar(current, ret);
        inc_syscw(current);
-       fput(file);
+       return ret;
+}
+
+asmlinkage ssize_t
+compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec,
+                 unsigned long vlen)
+{
+       struct file *file;
+       int fput_needed;
+       ssize_t ret;
+
+       file = fget_light(fd, &fput_needed);
+       if (!file)
+               return -EBADF;
+       ret = compat_writev(file, vec, vlen, &file->f_pos);
+       fput_light(file, fput_needed);
+       return ret;
+}
+
+asmlinkage ssize_t
+compat_sys_pwritev(unsigned long fd, const struct compat_iovec __user *vec,
+                  unsigned long vlen, u32 pos_high, u32 pos_low)
+{
+       loff_t pos = ((loff_t)pos_high << 32) | pos_low;
+       struct file *file;
+       int fput_needed;
+       ssize_t ret;
+
+       if (pos < 0)
+               return -EINVAL;
+       file = fget_light(fd, &fput_needed);
+       if (!file)
+               return -EBADF;
+       ret = compat_writev(file, vec, vlen, &pos);
+       fput_light(file, fput_needed);
        return ret;
 }
 
@@ -1420,12 +1481,17 @@ int compat_do_execve(char * filename,
 {
        struct linux_binprm *bprm;
        struct file *file;
+       struct files_struct *displaced;
        int retval;
 
+       retval = unshare_files(&displaced);
+       if (retval)
+               goto out_ret;
+
        retval = -ENOMEM;
        bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
        if (!bprm)
-               goto out_ret;
+               goto out_files;
 
        retval = mutex_lock_interruptible(&current->cred_exec_mutex);
        if (retval < 0)
@@ -1436,7 +1502,7 @@ int compat_do_execve(char * filename,
        bprm->cred = prepare_exec_creds();
        if (!bprm->cred)
                goto out_unlock;
-       check_unsafe_exec(bprm, current->files);
+       check_unsafe_exec(bprm);
 
        file = open_exec(filename);
        retval = PTR_ERR(file);
@@ -1487,6 +1553,8 @@ int compat_do_execve(char * filename,
        mutex_unlock(&current->cred_exec_mutex);
        acct_update_integrals(current);
        free_bprm(bprm);
+       if (displaced)
+               put_files_struct(displaced);
        return retval;
 
 out:
@@ -1506,6 +1574,9 @@ out_unlock:
 out_free:
        free_bprm(bprm);
 
+out_files:
+       if (displaced)
+               reset_files_struct(displaced);
 out_ret:
        return retval;
 }
index a07338d2d140818770865aca94dfc2337e9527a6..dd3634e4c967983f2024221b33c34b81e51ad2ad 100644 (file)
@@ -318,6 +318,7 @@ out:
 static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type = CRAMFS_MAGIC;
        buf->f_bsize = PAGE_CACHE_SIZE;
@@ -326,6 +327,8 @@ static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bavail = 0;
        buf->f_files = CRAMFS_SB(sb)->files;
        buf->f_ffree = 0;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = CRAMFS_MAXPATHLEN;
        return 0;
 }
@@ -459,11 +462,14 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s
 static int cramfs_readpage(struct file *file, struct page * page)
 {
        struct inode *inode = page->mapping->host;
-       u32 maxblock, bytes_filled;
+       u32 maxblock;
+       int bytes_filled;
        void *pgdata;
 
        maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
        bytes_filled = 0;
+       pgdata = kmap(page);
+
        if (page->index < maxblock) {
                struct super_block *sb = inode->i_sb;
                u32 blkptr_offset = OFFSET(inode) + page->index*4;
@@ -472,30 +478,43 @@ static int cramfs_readpage(struct file *file, struct page * page)
                start_offset = OFFSET(inode) + maxblock*4;
                mutex_lock(&read_mutex);
                if (page->index)
-                       start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4, 4);
-               compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) - start_offset);
+                       start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4,
+                               4);
+               compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) -
+                       start_offset);
                mutex_unlock(&read_mutex);
-               pgdata = kmap(page);
+
                if (compr_len == 0)
                        ; /* hole */
-               else if (compr_len > (PAGE_CACHE_SIZE << 1))
-                       printk(KERN_ERR "cramfs: bad compressed blocksize %u\n", compr_len);
-               else {
+               else if (unlikely(compr_len > (PAGE_CACHE_SIZE << 1))) {
+                       pr_err("cramfs: bad compressed blocksize %u\n",
+                               compr_len);
+                       goto err;
+               } else {
                        mutex_lock(&read_mutex);
                        bytes_filled = cramfs_uncompress_block(pgdata,
                                 PAGE_CACHE_SIZE,
                                 cramfs_read(sb, start_offset, compr_len),
                                 compr_len);
                        mutex_unlock(&read_mutex);
+                       if (unlikely(bytes_filled < 0))
+                               goto err;
                }
-       } else
-               pgdata = kmap(page);
+       }
+
        memset(pgdata + bytes_filled, 0, PAGE_CACHE_SIZE - bytes_filled);
-       kunmap(page);
        flush_dcache_page(page);
+       kunmap(page);
        SetPageUptodate(page);
        unlock_page(page);
        return 0;
+
+err:
+       kunmap(page);
+       ClearPageUptodate(page);
+       SetPageError(page);
+       unlock_page(page);
+       return 0;
 }
 
 static const struct address_space_operations cramfs_aops = {
index fc3ccb74626ffb3a581da4049c703242352dedfa..023329800d2e42152fec5a531f91f4310cae1729 100644 (file)
@@ -50,7 +50,7 @@ int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen)
 err:
        printk("Error %d while decompressing!\n", err);
        printk("%p(%d)->%p(%d)\n", src, srclen, dst, dstlen);
-       return 0;
+       return -EIO;
 }
 
 int cramfs_uncompress_init(void)
index 44d725f612cf346ec2e4d9bf2801913de393b967..b6a719a909f8eee1829764ea770e879c1c9c73fe 100644 (file)
@@ -18,7 +18,7 @@ static void drop_pagecache_sb(struct super_block *sb)
 
        spin_lock(&inode_lock);
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
-               if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW))
+               if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW))
                        continue;
                if (inode->i_mapping->nrpages == 0)
                        continue;
index e4a6223c314594c71402ef373ee0e6e092d55bd3..af737bb56cb71942ebed99c9bad8eb6a34bdaeb8 100644 (file)
@@ -740,8 +740,7 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
 out_release_free_unlock:
        crypto_free_hash(s->hash_desc.tfm);
 out_free_unlock:
-       memset(s->block_aligned_filename, 0, s->block_aligned_filename_size);
-       kfree(s->block_aligned_filename);
+       kzfree(s->block_aligned_filename);
 out_unlock:
        mutex_unlock(s->tfm_mutex);
 out:
index 96ef51489e0124d0ae77618160e99707f34dcb49..295e7fa567556f2efc99d17588af9248a409e4c0 100644 (file)
@@ -291,8 +291,7 @@ int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon)
        if (daemon->user_ns)
                put_user_ns(daemon->user_ns);
        mutex_unlock(&daemon->mux);
-       memset(daemon, 0, sizeof(*daemon));
-       kfree(daemon);
+       kzfree(daemon);
 out:
        return rc;
 }
index 73b19cfc91fc57510cc96d8863b776748550b65a..f04942810818ade709f8f7cfa416b21f87c6736a 100644 (file)
@@ -329,18 +329,22 @@ out_no_fs:
 }
 
 static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) {
-       struct efs_sb_info *sb = SUPER_INFO(dentry->d_sb);
+       struct super_block *sb = dentry->d_sb;
+       struct efs_sb_info *sbi = SUPER_INFO(sb);
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type    = EFS_SUPER_MAGIC;       /* efs magic number */
        buf->f_bsize   = EFS_BLOCKSIZE;         /* blocksize */
-       buf->f_blocks  = sb->total_groups *     /* total data blocks */
-                       (sb->group_size - sb->inode_blocks);
-       buf->f_bfree   = sb->data_free;         /* free data blocks */
-       buf->f_bavail  = sb->data_free;         /* free blocks for non-root */
-       buf->f_files   = sb->total_groups *     /* total inodes */
-                       sb->inode_blocks *
+       buf->f_blocks  = sbi->total_groups *    /* total data blocks */
+                       (sbi->group_size - sbi->inode_blocks);
+       buf->f_bfree   = sbi->data_free;        /* free data blocks */
+       buf->f_bavail  = sbi->data_free;        /* free blocks for non-root */
+       buf->f_files   = sbi->total_groups *    /* total inodes */
+                       sbi->inode_blocks *
                        (EFS_BLOCKSIZE / sizeof(struct efs_dinode));
-       buf->f_ffree   = sb->inode_free;        /* free inodes */
+       buf->f_ffree   = sbi->inode_free;       /* free inodes */
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = EFS_MAXNAMELEN;        /* max filename length */
 
        return 0;
index 5de2c2db3aa2381ccc04b02ca440ba56d14cfaba..2a701d593d35f36d2511c25df916a5d61098b019 100644 (file)
@@ -28,6 +28,7 @@ struct eventfd_ctx {
         * issue a wakeup.
         */
        __u64 count;
+       unsigned int flags;
 };
 
 /*
@@ -50,7 +51,7 @@ int eventfd_signal(struct file *file, int n)
                n = (int) (ULLONG_MAX - ctx->count);
        ctx->count += n;
        if (waitqueue_active(&ctx->wqh))
-               wake_up_locked(&ctx->wqh);
+               wake_up_locked_poll(&ctx->wqh, POLLIN);
        spin_unlock_irqrestore(&ctx->wqh.lock, flags);
 
        return n;
@@ -87,22 +88,20 @@ static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,
 {
        struct eventfd_ctx *ctx = file->private_data;
        ssize_t res;
-       __u64 ucnt;
+       __u64 ucnt = 0;
        DECLARE_WAITQUEUE(wait, current);
 
        if (count < sizeof(ucnt))
                return -EINVAL;
        spin_lock_irq(&ctx->wqh.lock);
        res = -EAGAIN;
-       ucnt = ctx->count;
-       if (ucnt > 0)
+       if (ctx->count > 0)
                res = sizeof(ucnt);
        else if (!(file->f_flags & O_NONBLOCK)) {
                __add_wait_queue(&ctx->wqh, &wait);
                for (res = 0;;) {
                        set_current_state(TASK_INTERRUPTIBLE);
                        if (ctx->count > 0) {
-                               ucnt = ctx->count;
                                res = sizeof(ucnt);
                                break;
                        }
@@ -117,10 +116,11 @@ static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,
                __remove_wait_queue(&ctx->wqh, &wait);
                __set_current_state(TASK_RUNNING);
        }
-       if (res > 0) {
-               ctx->count = 0;
+       if (likely(res > 0)) {
+               ucnt = (ctx->flags & EFD_SEMAPHORE) ? 1 : ctx->count;
+               ctx->count -= ucnt;
                if (waitqueue_active(&ctx->wqh))
-                       wake_up_locked(&ctx->wqh);
+                       wake_up_locked_poll(&ctx->wqh, POLLOUT);
        }
        spin_unlock_irq(&ctx->wqh.lock);
        if (res > 0 && put_user(ucnt, (__u64 __user *) buf))
@@ -166,10 +166,10 @@ static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t c
                __remove_wait_queue(&ctx->wqh, &wait);
                __set_current_state(TASK_RUNNING);
        }
-       if (res > 0) {
+       if (likely(res > 0)) {
                ctx->count += ucnt;
                if (waitqueue_active(&ctx->wqh))
-                       wake_up_locked(&ctx->wqh);
+                       wake_up_locked_poll(&ctx->wqh, POLLIN);
        }
        spin_unlock_irq(&ctx->wqh.lock);
 
@@ -207,7 +207,7 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
        BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC);
        BUILD_BUG_ON(EFD_NONBLOCK != O_NONBLOCK);
 
-       if (flags & ~(EFD_CLOEXEC | EFD_NONBLOCK))
+       if (flags & ~EFD_FLAGS_SET)
                return -EINVAL;
 
        ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
@@ -216,13 +216,14 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
 
        init_waitqueue_head(&ctx->wqh);
        ctx->count = count;
+       ctx->flags = flags;
 
        /*
         * When we call this, the initialization must be complete, since
         * anon_inode_getfd() will install the fd.
         */
        fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx,
-                             flags & (O_CLOEXEC | O_NONBLOCK));
+                             flags & EFD_SHARED_FCNTL_FLAGS);
        if (fd < 0)
                kfree(ctx);
        return fd;
@@ -232,3 +233,4 @@ SYSCALL_DEFINE1(eventfd, unsigned int, count)
 {
        return sys_eventfd2(count, 0);
 }
+
index c5c424f23fd5fb08a873ea2eb38a6f4a623b2913..a89f370fadb5d72666b87c4b16bfaa9c3833788a 100644 (file)
@@ -1,6 +1,6 @@
 /*
- *  fs/eventpoll.c (Efficent event polling implementation)
- *  Copyright (C) 2001,...,2007         Davide Libenzi
+ *  fs/eventpoll.c (Efficient event retrieval implementation)
+ *  Copyright (C) 2001,...,2009         Davide Libenzi
  *
  *  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
  * a better scalability.
  */
 
-#define DEBUG_EPOLL 0
-
-#if DEBUG_EPOLL > 0
-#define DPRINTK(x) printk x
-#define DNPRINTK(n, x) do { if ((n) <= DEBUG_EPOLL) printk x; } while (0)
-#else /* #if DEBUG_EPOLL > 0 */
-#define DPRINTK(x) (void) 0
-#define DNPRINTK(n, x) (void) 0
-#endif /* #if DEBUG_EPOLL > 0 */
-
-#define DEBUG_EPI 0
-
-#if DEBUG_EPI != 0
-#define EPI_SLAB_DEBUG (SLAB_DEBUG_FREE | SLAB_RED_ZONE /* | SLAB_POISON */)
-#else /* #if DEBUG_EPI != 0 */
-#define EPI_SLAB_DEBUG 0
-#endif /* #if DEBUG_EPI != 0 */
-
 /* Epoll private bits inside the event mask */
 #define EP_PRIVATE_BITS (EPOLLONESHOT | EPOLLET)
 
-/* Maximum number of poll wake up nests we are allowing */
-#define EP_MAX_POLLWAKE_NESTS 4
+/* Maximum number of nesting allowed inside epoll sets */
+#define EP_MAX_NESTS 4
 
 /* Maximum msec timeout value storeable in a long int */
 #define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ)
@@ -110,24 +92,21 @@ struct epoll_filefd {
 };
 
 /*
- * Node that is linked into the "wake_task_list" member of the "struct poll_safewake".
- * It is used to keep track on all tasks that are currently inside the wake_up() code
- * to 1) short-circuit the one coming from the same task and same wait queue head
- * (loop) 2) allow a maximum number of epoll descriptors inclusion nesting
- * 3) let go the ones coming from other tasks.
+ * Structure used to track possible nested calls, for too deep recursions
+ * and loop cycles.
  */
-struct wake_task_node {
+struct nested_call_node {
        struct list_head llink;
-       struct task_struct *task;
-       wait_queue_head_t *wq;
+       void *cookie;
+       int cpu;
 };
 
 /*
- * This is used to implement the safe poll wake up avoiding to reenter
- * the poll callback from inside wake_up().
+ * This structure is used as collector for nested calls, to check for
+ * maximum recursion dept and loop cycles.
  */
-struct poll_safewake {
-       struct list_head wake_task_list;
+struct nested_calls {
+       struct list_head tasks_call_list;
        spinlock_t lock;
 };
 
@@ -213,7 +192,7 @@ struct eppoll_entry {
        struct list_head llink;
 
        /* The "base" pointer is set to the container "struct epitem" */
-       void *base;
+       struct epitem *base;
 
        /*
         * Wait queue item that will be linked to the target file wait
@@ -231,6 +210,12 @@ struct ep_pqueue {
        struct epitem *epi;
 };
 
+/* Used by the ep_send_events() function as callback private data */
+struct ep_send_events_data {
+       int maxevents;
+       struct epoll_event __user *events;
+};
+
 /*
  * Configuration options available inside /proc/sys/fs/epoll/
  */
@@ -242,8 +227,11 @@ static int max_user_watches __read_mostly;
  */
 static DEFINE_MUTEX(epmutex);
 
-/* Safe wake up implementation */
-static struct poll_safewake psw;
+/* Used for safe wake up implementation */
+static struct nested_calls poll_safewake_ncalls;
+
+/* Used to call file's f_op->poll() under the nested calls boundaries */
+static struct nested_calls poll_readywalk_ncalls;
 
 /* Slab cache used to allocate "struct epitem" */
 static struct kmem_cache *epi_cache __read_mostly;
@@ -312,89 +300,230 @@ static inline int ep_op_has_event(int op)
 }
 
 /* Initialize the poll safe wake up structure */
-static void ep_poll_safewake_init(struct poll_safewake *psw)
+static void ep_nested_calls_init(struct nested_calls *ncalls)
 {
-
-       INIT_LIST_HEAD(&psw->wake_task_list);
-       spin_lock_init(&psw->lock);
+       INIT_LIST_HEAD(&ncalls->tasks_call_list);
+       spin_lock_init(&ncalls->lock);
 }
 
-/*
- * Perform a safe wake up of the poll wait list. The problem is that
- * with the new callback'd wake up system, it is possible that the
- * poll callback is reentered from inside the call to wake_up() done
- * on the poll wait queue head. The rule is that we cannot reenter the
- * wake up code from the same task more than EP_MAX_POLLWAKE_NESTS times,
- * and we cannot reenter the same wait queue head at all. This will
- * enable to have a hierarchy of epoll file descriptor of no more than
- * EP_MAX_POLLWAKE_NESTS deep. We need the irq version of the spin lock
- * because this one gets called by the poll callback, that in turn is called
- * from inside a wake_up(), that might be called from irq context.
+/**
+ * ep_call_nested - Perform a bound (possibly) nested call, by checking
+ *                  that the recursion limit is not exceeded, and that
+ *                  the same nested call (by the meaning of same cookie) is
+ *                  no re-entered.
+ *
+ * @ncalls: Pointer to the nested_calls structure to be used for this call.
+ * @max_nests: Maximum number of allowed nesting calls.
+ * @nproc: Nested call core function pointer.
+ * @priv: Opaque data to be passed to the @nproc callback.
+ * @cookie: Cookie to be used to identify this nested call.
+ *
+ * Returns: Returns the code returned by the @nproc callback, or -1 if
+ *          the maximum recursion limit has been exceeded.
  */
-static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq)
+static int ep_call_nested(struct nested_calls *ncalls, int max_nests,
+                         int (*nproc)(void *, void *, int), void *priv,
+                         void *cookie)
 {
-       int wake_nests = 0;
+       int error, call_nests = 0;
        unsigned long flags;
-       struct task_struct *this_task = current;
-       struct list_head *lsthead = &psw->wake_task_list;
-       struct wake_task_node *tncur;
-       struct wake_task_node tnode;
+       int this_cpu = get_cpu();
+       struct list_head *lsthead = &ncalls->tasks_call_list;
+       struct nested_call_node *tncur;
+       struct nested_call_node tnode;
 
-       spin_lock_irqsave(&psw->lock, flags);
+       spin_lock_irqsave(&ncalls->lock, flags);
 
-       /* Try to see if the current task is already inside this wakeup call */
+       /*
+        * Try to see if the current task is already inside this wakeup call.
+        * We use a list here, since the population inside this set is always
+        * very much limited.
+        */
        list_for_each_entry(tncur, lsthead, llink) {
-
-               if (tncur->wq == wq ||
-                   (tncur->task == this_task && ++wake_nests > EP_MAX_POLLWAKE_NESTS)) {
+               if (tncur->cpu == this_cpu &&
+                   (tncur->cookie == cookie || ++call_nests > max_nests)) {
                        /*
                         * Ops ... loop detected or maximum nest level reached.
                         * We abort this wake by breaking the cycle itself.
                         */
-                       spin_unlock_irqrestore(&psw->lock, flags);
-                       return;
+                       error = -1;
+                       goto out_unlock;
                }
        }
 
-       /* Add the current task to the list */
-       tnode.task = this_task;
-       tnode.wq = wq;
+       /* Add the current task and cookie to the list */
+       tnode.cpu = this_cpu;
+       tnode.cookie = cookie;
        list_add(&tnode.llink, lsthead);
 
-       spin_unlock_irqrestore(&psw->lock, flags);
+       spin_unlock_irqrestore(&ncalls->lock, flags);
 
-       /* Do really wake up now */
-       wake_up_nested(wq, 1 + wake_nests);
+       /* Call the nested function */
+       error = (*nproc)(priv, cookie, call_nests);
 
        /* Remove the current task from the list */
-       spin_lock_irqsave(&psw->lock, flags);
+       spin_lock_irqsave(&ncalls->lock, flags);
        list_del(&tnode.llink);
-       spin_unlock_irqrestore(&psw->lock, flags);
+ out_unlock:
+       spin_unlock_irqrestore(&ncalls->lock, flags);
+
+       put_cpu();
+       return error;
+}
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+static inline void ep_wake_up_nested(wait_queue_head_t *wqueue,
+                                    unsigned long events, int subclass)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave_nested(&wqueue->lock, flags, subclass);
+       wake_up_locked_poll(wqueue, events);
+       spin_unlock_irqrestore(&wqueue->lock, flags);
+}
+#else
+static inline void ep_wake_up_nested(wait_queue_head_t *wqueue,
+                                    unsigned long events, int subclass)
+{
+       wake_up_poll(wqueue, events);
+}
+#endif
+
+static int ep_poll_wakeup_proc(void *priv, void *cookie, int call_nests)
+{
+       ep_wake_up_nested((wait_queue_head_t *) cookie, POLLIN,
+                         1 + call_nests);
+       return 0;
+}
+
+/*
+ * Perform a safe wake up of the poll wait list. The problem is that
+ * with the new callback'd wake up system, it is possible that the
+ * poll callback is reentered from inside the call to wake_up() done
+ * on the poll wait queue head. The rule is that we cannot reenter the
+ * wake up code from the same task more than EP_MAX_NESTS times,
+ * and we cannot reenter the same wait queue head at all. This will
+ * enable to have a hierarchy of epoll file descriptor of no more than
+ * EP_MAX_NESTS deep.
+ */
+static void ep_poll_safewake(wait_queue_head_t *wq)
+{
+       ep_call_nested(&poll_safewake_ncalls, EP_MAX_NESTS,
+                      ep_poll_wakeup_proc, NULL, wq);
 }
 
 /*
- * This function unregister poll callbacks from the associated file descriptor.
- * Since this must be called without holding "ep->lock" the atomic exchange trick
- * will protect us from multiple unregister.
+ * This function unregisters poll callbacks from the associated file
+ * descriptor.  Must be called with "mtx" held (or "epmutex" if called from
+ * ep_free).
  */
 static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi)
 {
-       int nwait;
        struct list_head *lsthead = &epi->pwqlist;
        struct eppoll_entry *pwq;
 
-       /* This is called without locks, so we need the atomic exchange */
-       nwait = xchg(&epi->nwait, 0);
+       while (!list_empty(lsthead)) {
+               pwq = list_first_entry(lsthead, struct eppoll_entry, llink);
 
-       if (nwait) {
-               while (!list_empty(lsthead)) {
-                       pwq = list_first_entry(lsthead, struct eppoll_entry, llink);
+               list_del(&pwq->llink);
+               remove_wait_queue(pwq->whead, &pwq->wait);
+               kmem_cache_free(pwq_cache, pwq);
+       }
+}
 
-                       list_del_init(&pwq->llink);
-                       remove_wait_queue(pwq->whead, &pwq->wait);
-                       kmem_cache_free(pwq_cache, pwq);
-               }
+/**
+ * ep_scan_ready_list - Scans the ready list in a way that makes possible for
+ *                      the scan code, to call f_op->poll(). Also allows for
+ *                      O(NumReady) performance.
+ *
+ * @ep: Pointer to the epoll private data structure.
+ * @sproc: Pointer to the scan callback.
+ * @priv: Private opaque data passed to the @sproc callback.
+ *
+ * Returns: The same integer error code returned by the @sproc callback.
+ */
+static int ep_scan_ready_list(struct eventpoll *ep,
+                             int (*sproc)(struct eventpoll *,
+                                          struct list_head *, void *),
+                             void *priv)
+{
+       int error, pwake = 0;
+       unsigned long flags;
+       struct epitem *epi, *nepi;
+       LIST_HEAD(txlist);
+
+       /*
+        * We need to lock this because we could be hit by
+        * eventpoll_release_file() and epoll_ctl().
+        */
+       mutex_lock(&ep->mtx);
+
+       /*
+        * Steal the ready list, and re-init the original one to the
+        * empty list. Also, set ep->ovflist to NULL so that events
+        * happening while looping w/out locks, are not lost. We cannot
+        * have the poll callback to queue directly on ep->rdllist,
+        * because we want the "sproc" callback to be able to do it
+        * in a lockless way.
+        */
+       spin_lock_irqsave(&ep->lock, flags);
+       list_splice_init(&ep->rdllist, &txlist);
+       ep->ovflist = NULL;
+       spin_unlock_irqrestore(&ep->lock, flags);
+
+       /*
+        * Now call the callback function.
+        */
+       error = (*sproc)(ep, &txlist, priv);
+
+       spin_lock_irqsave(&ep->lock, flags);
+       /*
+        * During the time we spent inside the "sproc" callback, some
+        * other events might have been queued by the poll callback.
+        * We re-insert them inside the main ready-list here.
+        */
+       for (nepi = ep->ovflist; (epi = nepi) != NULL;
+            nepi = epi->next, epi->next = EP_UNACTIVE_PTR) {
+               /*
+                * We need to check if the item is already in the list.
+                * During the "sproc" callback execution time, items are
+                * queued into ->ovflist but the "txlist" might already
+                * contain them, and the list_splice() below takes care of them.
+                */
+               if (!ep_is_linked(&epi->rdllink))
+                       list_add_tail(&epi->rdllink, &ep->rdllist);
+       }
+       /*
+        * We need to set back ep->ovflist to EP_UNACTIVE_PTR, so that after
+        * releasing the lock, events will be queued in the normal way inside
+        * ep->rdllist.
+        */
+       ep->ovflist = EP_UNACTIVE_PTR;
+
+       /*
+        * Quickly re-inject items left on "txlist".
+        */
+       list_splice(&txlist, &ep->rdllist);
+
+       if (!list_empty(&ep->rdllist)) {
+               /*
+                * Wake up (if active) both the eventpoll wait list and
+                * the ->poll() wait list (delayed after we release the lock).
+                */
+               if (waitqueue_active(&ep->wq))
+                       wake_up_locked(&ep->wq);
+               if (waitqueue_active(&ep->poll_wait))
+                       pwake++;
        }
+       spin_unlock_irqrestore(&ep->lock, flags);
+
+       mutex_unlock(&ep->mtx);
+
+       /* We have to call this outside the lock */
+       if (pwake)
+               ep_poll_safewake(&ep->poll_wait);
+
+       return error;
 }
 
 /*
@@ -434,9 +563,6 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi)
 
        atomic_dec(&ep->user->epoll_watches);
 
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %p)\n",
-                    current, ep, file));
-
        return 0;
 }
 
@@ -447,7 +573,7 @@ static void ep_free(struct eventpoll *ep)
 
        /* We need to release all tasks waiting for these file */
        if (waitqueue_active(&ep->poll_wait))
-               ep_poll_safewake(&psw, &ep->poll_wait);
+               ep_poll_safewake(&ep->poll_wait);
 
        /*
         * We need to lock this because we could be hit by
@@ -492,26 +618,54 @@ static int ep_eventpoll_release(struct inode *inode, struct file *file)
        if (ep)
                ep_free(ep);
 
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: close() ep=%p\n", current, ep));
        return 0;
 }
 
+static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head,
+                              void *priv)
+{
+       struct epitem *epi, *tmp;
+
+       list_for_each_entry_safe(epi, tmp, head, rdllink) {
+               if (epi->ffd.file->f_op->poll(epi->ffd.file, NULL) &
+                   epi->event.events)
+                       return POLLIN | POLLRDNORM;
+               else {
+                       /*
+                        * Item has been dropped into the ready list by the poll
+                        * callback, but it's not actually ready, as far as
+                        * caller requested events goes. We can remove it here.
+                        */
+                       list_del_init(&epi->rdllink);
+               }
+       }
+
+       return 0;
+}
+
+static int ep_poll_readyevents_proc(void *priv, void *cookie, int call_nests)
+{
+       return ep_scan_ready_list(priv, ep_read_events_proc, NULL);
+}
+
 static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait)
 {
-       unsigned int pollflags = 0;
-       unsigned long flags;
+       int pollflags;
        struct eventpoll *ep = file->private_data;
 
        /* Insert inside our poll wait queue */
        poll_wait(file, &ep->poll_wait, wait);
 
-       /* Check our condition */
-       spin_lock_irqsave(&ep->lock, flags);
-       if (!list_empty(&ep->rdllist))
-               pollflags = POLLIN | POLLRDNORM;
-       spin_unlock_irqrestore(&ep->lock, flags);
+       /*
+        * Proceed to find out if wanted events are really available inside
+        * the ready list. This need to be done under ep_call_nested()
+        * supervision, since the call to f_op->poll() done on listed files
+        * could re-enter here.
+        */
+       pollflags = ep_call_nested(&poll_readywalk_ncalls, EP_MAX_NESTS,
+                                  ep_poll_readyevents_proc, ep, ep);
 
-       return pollflags;
+       return pollflags != -1 ? pollflags : 0;
 }
 
 /* File callbacks that implement the eventpoll file behaviour */
@@ -541,7 +695,7 @@ void eventpoll_release_file(struct file *file)
         * We don't want to get "file->f_lock" because it is not
         * necessary. It is not necessary because we're in the "struct file"
         * cleanup path, and this means that noone is using this file anymore.
-        * So, for example, epoll_ctl() cannot hit here sicne if we reach this
+        * So, for example, epoll_ctl() cannot hit here since if we reach this
         * point, the file counter already went to zero and fget() would fail.
         * The only hit might come from ep_free() but by holding the mutex
         * will correctly serialize the operation. We do need to acquire
@@ -588,8 +742,6 @@ static int ep_alloc(struct eventpoll **pep)
 
        *pep = ep;
 
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_alloc() ep=%p\n",
-                    current, ep));
        return 0;
 
 free_uid:
@@ -623,9 +775,6 @@ static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd)
                }
        }
 
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_find(%p) -> %p\n",
-                    current, file, epir));
-
        return epir;
 }
 
@@ -641,9 +790,6 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
        struct epitem *epi = ep_item_from_wait(wait);
        struct eventpoll *ep = epi->ep;
 
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n",
-                    current, epi->ffd.file, epi, ep));
-
        spin_lock_irqsave(&ep->lock, flags);
 
        /*
@@ -655,6 +801,15 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
        if (!(epi->event.events & ~EP_PRIVATE_BITS))
                goto out_unlock;
 
+       /*
+        * Check the events coming with the callback. At this stage, not
+        * every device reports the events in the "key" parameter of the
+        * callback. We need to be able to handle both cases here, hence the
+        * test for "key" != NULL before the event match test.
+        */
+       if (key && !((unsigned long) key & epi->event.events))
+               goto out_unlock;
+
        /*
         * If we are trasfering events to userspace, we can hold no locks
         * (because we're accessing user memory, and because of linux f_op->poll()
@@ -670,12 +825,9 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
        }
 
        /* If this file is already in the ready list we exit soon */
-       if (ep_is_linked(&epi->rdllink))
-               goto is_linked;
-
-       list_add_tail(&epi->rdllink, &ep->rdllist);
+       if (!ep_is_linked(&epi->rdllink))
+               list_add_tail(&epi->rdllink, &ep->rdllist);
 
-is_linked:
        /*
         * Wake up ( if active ) both the eventpoll wait list and the ->poll()
         * wait list.
@@ -690,7 +842,7 @@ out_unlock:
 
        /* We have to call this outside the lock */
        if (pwake)
-               ep_poll_safewake(&psw, &ep->poll_wait);
+               ep_poll_safewake(&ep->poll_wait);
 
        return 1;
 }
@@ -817,10 +969,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
 
        /* We have to call this outside the lock */
        if (pwake)
-               ep_poll_safewake(&psw, &ep->poll_wait);
-
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_insert(%p, %p, %d)\n",
-                    current, ep, tfile, fd));
+               ep_poll_safewake(&ep->poll_wait);
 
        return 0;
 
@@ -851,15 +1000,14 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
 {
        int pwake = 0;
        unsigned int revents;
-       unsigned long flags;
 
        /*
-        * Set the new event interest mask before calling f_op->poll(), otherwise
-        * a potential race might occur. In fact if we do this operation inside
-        * the lock, an event might happen between the f_op->poll() call and the
-        * new event set registering.
+        * Set the new event interest mask before calling f_op->poll();
+        * otherwise we might miss an event that happens between the
+        * f_op->poll() call and the new event set registering.
         */
        epi->event.events = event->events;
+       epi->event.data = event->data; /* protected by mtx */
 
        /*
         * Get current event bits. We can safely use the file* here because
@@ -867,16 +1015,12 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
         */
        revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL);
 
-       spin_lock_irqsave(&ep->lock, flags);
-
-       /* Copy the data member from inside the lock */
-       epi->event.data = event->data;
-
        /*
         * If the item is "hot" and it is not registered inside the ready
         * list, push it inside.
         */
        if (revents & event->events) {
+               spin_lock_irq(&ep->lock);
                if (!ep_is_linked(&epi->rdllink)) {
                        list_add_tail(&epi->rdllink, &ep->rdllist);
 
@@ -886,142 +1030,84 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
                        if (waitqueue_active(&ep->poll_wait))
                                pwake++;
                }
+               spin_unlock_irq(&ep->lock);
        }
-       spin_unlock_irqrestore(&ep->lock, flags);
 
        /* We have to call this outside the lock */
        if (pwake)
-               ep_poll_safewake(&psw, &ep->poll_wait);
+               ep_poll_safewake(&ep->poll_wait);
 
        return 0;
 }
 
-static int ep_send_events(struct eventpoll *ep, struct epoll_event __user *events,
-                         int maxevents)
+static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
+                              void *priv)
 {
-       int eventcnt, error = -EFAULT, pwake = 0;
+       struct ep_send_events_data *esed = priv;
+       int eventcnt;
        unsigned int revents;
-       unsigned long flags;
-       struct epitem *epi, *nepi;
-       struct list_head txlist;
-
-       INIT_LIST_HEAD(&txlist);
-
-       /*
-        * We need to lock this because we could be hit by
-        * eventpoll_release_file() and epoll_ctl(EPOLL_CTL_DEL).
-        */
-       mutex_lock(&ep->mtx);
-
-       /*
-        * Steal the ready list, and re-init the original one to the
-        * empty list. Also, set ep->ovflist to NULL so that events
-        * happening while looping w/out locks, are not lost. We cannot
-        * have the poll callback to queue directly on ep->rdllist,
-        * because we are doing it in the loop below, in a lockless way.
-        */
-       spin_lock_irqsave(&ep->lock, flags);
-       list_splice(&ep->rdllist, &txlist);
-       INIT_LIST_HEAD(&ep->rdllist);
-       ep->ovflist = NULL;
-       spin_unlock_irqrestore(&ep->lock, flags);
+       struct epitem *epi;
+       struct epoll_event __user *uevent;
 
        /*
-        * We can loop without lock because this is a task private list.
-        * We just splice'd out the ep->rdllist in ep_collect_ready_items().
-        * Items cannot vanish during the loop because we are holding "mtx".
+        * We can loop without lock because we are passed a task private list.
+        * Items cannot vanish during the loop because ep_scan_ready_list() is
+        * holding "mtx" during this call.
         */
-       for (eventcnt = 0; !list_empty(&txlist) && eventcnt < maxevents;) {
-               epi = list_first_entry(&txlist, struct epitem, rdllink);
+       for (eventcnt = 0, uevent = esed->events;
+            !list_empty(head) && eventcnt < esed->maxevents;) {
+               epi = list_first_entry(head, struct epitem, rdllink);
 
                list_del_init(&epi->rdllink);
 
-               /*
-                * Get the ready file event set. We can safely use the file
-                * because we are holding the "mtx" and this will guarantee
-                * that both the file and the item will not vanish.
-                */
-               revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL);
-               revents &= epi->event.events;
+               revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL) &
+                       epi->event.events;
 
                /*
-                * Is the event mask intersect the caller-requested one,
-                * deliver the event to userspace. Again, we are holding
-                * "mtx", so no operations coming from userspace can change
-                * the item.
+                * If the event mask intersect the caller-requested one,
+                * deliver the event to userspace. Again, ep_scan_ready_list()
+                * is holding "mtx", so no operations coming from userspace
+                * can change the item.
                 */
                if (revents) {
-                       if (__put_user(revents,
-                                      &events[eventcnt].events) ||
-                           __put_user(epi->event.data,
-                                      &events[eventcnt].data))
-                               goto errxit;
+                       if (__put_user(revents, &uevent->events) ||
+                           __put_user(epi->event.data, &uevent->data)) {
+                               list_add(&epi->rdllink, head);
+                               return eventcnt ? eventcnt : -EFAULT;
+                       }
+                       eventcnt++;
+                       uevent++;
                        if (epi->event.events & EPOLLONESHOT)
                                epi->event.events &= EP_PRIVATE_BITS;
-                       eventcnt++;
+                       else if (!(epi->event.events & EPOLLET)) {
+                               /*
+                                * If this file has been added with Level
+                                * Trigger mode, we need to insert back inside
+                                * the ready list, so that the next call to
+                                * epoll_wait() will check again the events
+                                * availability. At this point, noone can insert
+                                * into ep->rdllist besides us. The epoll_ctl()
+                                * callers are locked out by
+                                * ep_scan_ready_list() holding "mtx" and the
+                                * poll callback will queue them in ep->ovflist.
+                                */
+                               list_add_tail(&epi->rdllink, &ep->rdllist);
+                       }
                }
-               /*
-                * At this point, noone can insert into ep->rdllist besides
-                * us. The epoll_ctl() callers are locked out by us holding
-                * "mtx" and the poll callback will queue them in ep->ovflist.
-                */
-               if (!(epi->event.events & EPOLLET) &&
-                   (revents & epi->event.events))
-                       list_add_tail(&epi->rdllink, &ep->rdllist);
-       }
-       error = 0;
-
-errxit:
-
-       spin_lock_irqsave(&ep->lock, flags);
-       /*
-        * During the time we spent in the loop above, some other events
-        * might have been queued by the poll callback. We re-insert them
-        * inside the main ready-list here.
-        */
-       for (nepi = ep->ovflist; (epi = nepi) != NULL;
-            nepi = epi->next, epi->next = EP_UNACTIVE_PTR) {
-               /*
-                * If the above loop quit with errors, the epoll item might still
-                * be linked to "txlist", and the list_splice() done below will
-                * take care of those cases.
-                */
-               if (!ep_is_linked(&epi->rdllink))
-                       list_add_tail(&epi->rdllink, &ep->rdllist);
        }
-       /*
-        * We need to set back ep->ovflist to EP_UNACTIVE_PTR, so that after
-        * releasing the lock, events will be queued in the normal way inside
-        * ep->rdllist.
-        */
-       ep->ovflist = EP_UNACTIVE_PTR;
 
-       /*
-        * In case of error in the event-send loop, or in case the number of
-        * ready events exceeds the userspace limit, we need to splice the
-        * "txlist" back inside ep->rdllist.
-        */
-       list_splice(&txlist, &ep->rdllist);
-
-       if (!list_empty(&ep->rdllist)) {
-               /*
-                * Wake up (if active) both the eventpoll wait list and the ->poll()
-                * wait list (delayed after we release the lock).
-                */
-               if (waitqueue_active(&ep->wq))
-                       wake_up_locked(&ep->wq);
-               if (waitqueue_active(&ep->poll_wait))
-                       pwake++;
-       }
-       spin_unlock_irqrestore(&ep->lock, flags);
+       return eventcnt;
+}
 
-       mutex_unlock(&ep->mtx);
+static int ep_send_events(struct eventpoll *ep,
+                         struct epoll_event __user *events, int maxevents)
+{
+       struct ep_send_events_data esed;
 
-       /* We have to call this outside the lock */
-       if (pwake)
-               ep_poll_safewake(&psw, &ep->poll_wait);
+       esed.maxevents = maxevents;
+       esed.events = events;
 
-       return eventcnt == 0 ? error: eventcnt;
+       return ep_scan_ready_list(ep, ep_send_events_proc, &esed);
 }
 
 static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
@@ -1033,7 +1119,7 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
        wait_queue_t wait;
 
        /*
-        * Calculate the timeout by checking for the "infinite" value ( -1 )
+        * Calculate the timeout by checking for the "infinite" value (-1)
         * and the overflow condition. The passed timeout is in milliseconds,
         * that why (t * HZ) / 1000.
         */
@@ -1076,9 +1162,8 @@ retry:
 
                set_current_state(TASK_RUNNING);
        }
-
        /* Is it worth to try to dig for events ? */
-       eavail = !list_empty(&ep->rdllist);
+       eavail = !list_empty(&ep->rdllist) || ep->ovflist != EP_UNACTIVE_PTR;
 
        spin_unlock_irqrestore(&ep->lock, flags);
 
@@ -1099,41 +1184,30 @@ retry:
  */
 SYSCALL_DEFINE1(epoll_create1, int, flags)
 {
-       int error, fd = -1;
-       struct eventpoll *ep;
+       int error;
+       struct eventpoll *ep = NULL;
 
        /* Check the EPOLL_* constant for consistency.  */
        BUILD_BUG_ON(EPOLL_CLOEXEC != O_CLOEXEC);
 
        if (flags & ~EPOLL_CLOEXEC)
                return -EINVAL;
-
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n",
-                    current, flags));
-
        /*
-        * Create the internal data structure ( "struct eventpoll" ).
+        * Create the internal data structure ("struct eventpoll").
         */
        error = ep_alloc(&ep);
-       if (error < 0) {
-               fd = error;
-               goto error_return;
-       }
-
+       if (error < 0)
+               return error;
        /*
         * Creates all the items needed to setup an eventpoll file. That is,
         * a file structure and a free file descriptor.
         */
-       fd = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep,
-                             flags & O_CLOEXEC);
-       if (fd < 0)
+       error = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep,
+                                flags & O_CLOEXEC);
+       if (error < 0)
                ep_free(ep);
 
-error_return:
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
-                    current, flags, fd));
-
-       return fd;
+       return error;
 }
 
 SYSCALL_DEFINE1(epoll_create, int, size)
@@ -1158,9 +1232,6 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
        struct epitem *epi;
        struct epoll_event epds;
 
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p)\n",
-                    current, epfd, op, fd, event));
-
        error = -EFAULT;
        if (ep_op_has_event(op) &&
            copy_from_user(&epds, event, sizeof(struct epoll_event)))
@@ -1211,7 +1282,6 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
        case EPOLL_CTL_ADD:
                if (!epi) {
                        epds.events |= POLLERR | POLLHUP;
-
                        error = ep_insert(ep, &epds, tfile, fd);
                } else
                        error = -EEXIST;
@@ -1237,8 +1307,6 @@ error_tgt_fput:
 error_fput:
        fput(file);
 error_return:
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p) = %d\n",
-                    current, epfd, op, fd, event, error));
 
        return error;
 }
@@ -1254,9 +1322,6 @@ SYSCALL_DEFINE4(epoll_wait, int, epfd, struct epoll_event __user *, events,
        struct file *file;
        struct eventpoll *ep;
 
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d)\n",
-                    current, epfd, events, maxevents, timeout));
-
        /* The maximum number of event must be greater than zero */
        if (maxevents <= 0 || maxevents > EP_MAX_EVENTS)
                return -EINVAL;
@@ -1293,8 +1358,6 @@ SYSCALL_DEFINE4(epoll_wait, int, epfd, struct epoll_event __user *, events,
 error_fput:
        fput(file);
 error_return:
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d) = %d\n",
-                    current, epfd, events, maxevents, timeout, error));
 
        return error;
 }
@@ -1359,17 +1422,18 @@ static int __init eventpoll_init(void)
                EP_ITEM_COST;
 
        /* Initialize the structure used to perform safe poll wait head wake ups */
-       ep_poll_safewake_init(&psw);
+       ep_nested_calls_init(&poll_safewake_ncalls);
+
+       /* Initialize the structure used to perform file's f_op->poll() calls */
+       ep_nested_calls_init(&poll_readywalk_ncalls);
 
        /* Allocates slab cache used to allocate "struct epitem" items */
        epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem),
-                       0, SLAB_HWCACHE_ALIGN|EPI_SLAB_DEBUG|SLAB_PANIC,
-                       NULL);
+                       0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
 
        /* Allocates slab cache used to allocate "struct eppoll_entry" */
        pwq_cache = kmem_cache_create("eventpoll_pwq",
-                       sizeof(struct eppoll_entry), 0,
-                       EPI_SLAB_DEBUG|SLAB_PANIC, NULL);
+                       sizeof(struct eppoll_entry), 0, SLAB_PANIC, NULL);
 
        return 0;
 }
index b9f1c144b7a1037b6eb6e449812f75e204b1fed2..c5128fbc9165235832a3851b663eb23a2ab8935d 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1056,28 +1056,24 @@ EXPORT_SYMBOL(install_exec_creds);
  * - the caller must hold current->cred_exec_mutex to protect against
  *   PTRACE_ATTACH
  */
-void check_unsafe_exec(struct linux_binprm *bprm, struct files_struct *files)
+void check_unsafe_exec(struct linux_binprm *bprm)
 {
        struct task_struct *p = current, *t;
        unsigned long flags;
-       unsigned n_fs, n_files, n_sighand;
+       unsigned n_fs, n_sighand;
 
        bprm->unsafe = tracehook_unsafe_exec(p);
 
        n_fs = 1;
-       n_files = 1;
        n_sighand = 1;
        lock_task_sighand(p, &flags);
        for (t = next_thread(p); t != p; t = next_thread(t)) {
                if (t->fs == p->fs)
                        n_fs++;
-               if (t->files == files)
-                       n_files++;
                n_sighand++;
        }
 
        if (atomic_read(&p->fs->count) > n_fs ||
-           atomic_read(&p->files->count) > n_files ||
            atomic_read(&p->sighand->count) > n_sighand)
                bprm->unsafe |= LSM_UNSAFE_SHARE;
 
@@ -1300,7 +1296,7 @@ int do_execve(char * filename,
        bprm->cred = prepare_exec_creds();
        if (!bprm->cred)
                goto out_unlock;
-       check_unsafe_exec(bprm, displaced);
+       check_unsafe_exec(bprm);
 
        file = open_exec(filename);
        retval = PTR_ERR(file);
index 5853f4440af41949081cfd2bf3e2b8f1b9363c18..3d724a95882f618672a45ee8f945d9164f80b89f 100644 (file)
@@ -42,7 +42,7 @@ const struct file_operations ext3_dir_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = ext3_readdir,         /* we take BKL. needed?*/
-       .ioctl          = ext3_ioctl,           /* BKL held */
+       .unlocked_ioctl = ext3_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ext3_compat_ioctl,
 #endif
index 3be1e0689c9aa34443b5695f7800c41fbcafceef..521f8238b2fa1e967b47040355e5834fe3fc3e53 100644 (file)
@@ -112,7 +112,7 @@ const struct file_operations ext3_file_operations = {
        .write          = do_sync_write,
        .aio_read       = generic_file_aio_read,
        .aio_write      = ext3_file_write,
-       .ioctl          = ext3_ioctl,
+       .unlocked_ioctl = ext3_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ext3_compat_ioctl,
 #endif
index 4a09ff169870517b13f65e0d26507c6505e465b2..d3ef6566b0190340b21f94402a811f5a45d4f38d 100644 (file)
@@ -1149,12 +1149,15 @@ static int ext3_write_begin(struct file *file, struct address_space *mapping,
                                struct page **pagep, void **fsdata)
 {
        struct inode *inode = mapping->host;
-       int ret, needed_blocks = ext3_writepage_trans_blocks(inode);
+       int ret;
        handle_t *handle;
        int retries = 0;
        struct page *page;
        pgoff_t index;
        unsigned from, to;
+       /* Reserve one block more for addition to orphan list in case
+        * we allocate blocks but write fails for some reason */
+       int needed_blocks = ext3_writepage_trans_blocks(inode) + 1;
 
        index = pos >> PAGE_CACHE_SHIFT;
        from = pos & (PAGE_CACHE_SIZE - 1);
@@ -1184,14 +1187,19 @@ retry:
        }
 write_begin_failed:
        if (ret) {
-               ext3_journal_stop(handle);
-               unlock_page(page);
-               page_cache_release(page);
                /*
                 * block_write_begin may have instantiated a few blocks
                 * outside i_size.  Trim these off again. Don't need
                 * i_size_read because we hold i_mutex.
+                *
+                * Add inode to orphan list in case we crash before truncate
+                * finishes.
                 */
+               if (pos + len > inode->i_size)
+                       ext3_orphan_add(handle, inode);
+               ext3_journal_stop(handle);
+               unlock_page(page);
+               page_cache_release(page);
                if (pos + len > inode->i_size)
                        vmtruncate(inode, inode->i_size);
        }
@@ -1211,6 +1219,18 @@ int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh)
        return err;
 }
 
+/* For ordered writepage and write_end functions */
+static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
+{
+       /*
+        * Write could have mapped the buffer but it didn't copy the data in
+        * yet. So avoid filing such buffer into a transaction.
+        */
+       if (buffer_mapped(bh) && buffer_uptodate(bh))
+               return ext3_journal_dirty_data(handle, bh);
+       return 0;
+}
+
 /* For write_end() in data=journal mode */
 static int write_end_fn(handle_t *handle, struct buffer_head *bh)
 {
@@ -1221,26 +1241,20 @@ static int write_end_fn(handle_t *handle, struct buffer_head *bh)
 }
 
 /*
- * Generic write_end handler for ordered and writeback ext3 journal modes.
- * We can't use generic_write_end, because that unlocks the page and we need to
- * unlock the page after ext3_journal_stop, but ext3_journal_stop must run
- * after block_write_end.
+ * This is nasty and subtle: ext3_write_begin() could have allocated blocks
+ * for the whole page but later we failed to copy the data in. Update inode
+ * size according to what we managed to copy. The rest is going to be
+ * truncated in write_end function.
  */
-static int ext3_generic_write_end(struct file *file,
-                               struct address_space *mapping,
-                               loff_t pos, unsigned len, unsigned copied,
-                               struct page *page, void *fsdata)
+static void update_file_sizes(struct inode *inode, loff_t pos, unsigned copied)
 {
-       struct inode *inode = file->f_mapping->host;
-
-       copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);
-
-       if (pos+copied > inode->i_size) {
-               i_size_write(inode, pos+copied);
+       /* What matters to us is i_disksize. We don't write i_size anywhere */
+       if (pos + copied > inode->i_size)
+               i_size_write(inode, pos + copied);
+       if (pos + copied > EXT3_I(inode)->i_disksize) {
+               EXT3_I(inode)->i_disksize = pos + copied;
                mark_inode_dirty(inode);
        }
-
-       return copied;
 }
 
 /*
@@ -1260,35 +1274,29 @@ static int ext3_ordered_write_end(struct file *file,
        unsigned from, to;
        int ret = 0, ret2;
 
-       from = pos & (PAGE_CACHE_SIZE - 1);
-       to = from + len;
+       copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);
 
+       from = pos & (PAGE_CACHE_SIZE - 1);
+       to = from + copied;
        ret = walk_page_buffers(handle, page_buffers(page),
-               from, to, NULL, ext3_journal_dirty_data);
+               from, to, NULL, journal_dirty_data_fn);
 
-       if (ret == 0) {
-               /*
-                * generic_write_end() will run mark_inode_dirty() if i_size
-                * changes.  So let's piggyback the i_disksize mark_inode_dirty
-                * into that.
-                */
-               loff_t new_i_size;
-
-               new_i_size = pos + copied;
-               if (new_i_size > EXT3_I(inode)->i_disksize)
-                       EXT3_I(inode)->i_disksize = new_i_size;
-               ret2 = ext3_generic_write_end(file, mapping, pos, len, copied,
-                                                       page, fsdata);
-               copied = ret2;
-               if (ret2 < 0)
-                       ret = ret2;
-       }
+       if (ret == 0)
+               update_file_sizes(inode, pos, copied);
+       /*
+        * There may be allocated blocks outside of i_size because
+        * we failed to copy some data. Prepare for truncate.
+        */
+       if (pos + len > inode->i_size)
+               ext3_orphan_add(handle, inode);
        ret2 = ext3_journal_stop(handle);
        if (!ret)
                ret = ret2;
        unlock_page(page);
        page_cache_release(page);
 
+       if (pos + len > inode->i_size)
+               vmtruncate(inode, inode->i_size);
        return ret ? ret : copied;
 }
 
@@ -1299,25 +1307,22 @@ static int ext3_writeback_write_end(struct file *file,
 {
        handle_t *handle = ext3_journal_current_handle();
        struct inode *inode = file->f_mapping->host;
-       int ret = 0, ret2;
-       loff_t new_i_size;
-
-       new_i_size = pos + copied;
-       if (new_i_size > EXT3_I(inode)->i_disksize)
-               EXT3_I(inode)->i_disksize = new_i_size;
-
-       ret2 = ext3_generic_write_end(file, mapping, pos, len, copied,
-                                                       page, fsdata);
-       copied = ret2;
-       if (ret2 < 0)
-               ret = ret2;
+       int ret;
 
-       ret2 = ext3_journal_stop(handle);
-       if (!ret)
-               ret = ret2;
+       copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);
+       update_file_sizes(inode, pos, copied);
+       /*
+        * There may be allocated blocks outside of i_size because
+        * we failed to copy some data. Prepare for truncate.
+        */
+       if (pos + len > inode->i_size)
+               ext3_orphan_add(handle, inode);
+       ret = ext3_journal_stop(handle);
        unlock_page(page);
        page_cache_release(page);
 
+       if (pos + len > inode->i_size)
+               vmtruncate(inode, inode->i_size);
        return ret ? ret : copied;
 }
 
@@ -1338,15 +1343,23 @@ static int ext3_journalled_write_end(struct file *file,
        if (copied < len) {
                if (!PageUptodate(page))
                        copied = 0;
-               page_zero_new_buffers(page, from+copied, to);
+               page_zero_new_buffers(page, from + copied, to);
+               to = from + copied;
        }
 
        ret = walk_page_buffers(handle, page_buffers(page), from,
                                to, &partial, write_end_fn);
        if (!partial)
                SetPageUptodate(page);
-       if (pos+copied > inode->i_size)
-               i_size_write(inode, pos+copied);
+
+       if (pos + copied > inode->i_size)
+               i_size_write(inode, pos + copied);
+       /*
+        * There may be allocated blocks outside of i_size because
+        * we failed to copy some data. Prepare for truncate.
+        */
+       if (pos + len > inode->i_size)
+               ext3_orphan_add(handle, inode);
        EXT3_I(inode)->i_state |= EXT3_STATE_JDATA;
        if (inode->i_size > EXT3_I(inode)->i_disksize) {
                EXT3_I(inode)->i_disksize = inode->i_size;
@@ -1361,6 +1374,8 @@ static int ext3_journalled_write_end(struct file *file,
        unlock_page(page);
        page_cache_release(page);
 
+       if (pos + len > inode->i_size)
+               vmtruncate(inode, inode->i_size);
        return ret ? ret : copied;
 }
 
@@ -1428,17 +1443,11 @@ static int bput_one(handle_t *handle, struct buffer_head *bh)
        return 0;
 }
 
-static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
-{
-       if (buffer_mapped(bh))
-               return ext3_journal_dirty_data(handle, bh);
-       return 0;
-}
-
 static int buffer_unmapped(handle_t *handle, struct buffer_head *bh)
 {
        return !buffer_mapped(bh);
 }
+
 /*
  * Note that we always start a transaction even if we're not journalling
  * data.  This is to preserve ordering: any hole instantiation within
index 5e86ce9a86e05b20d3ffe297dd4b9191fee08994..88974814783a346ca18d9eddea1c417cccbf695b 100644 (file)
 #include <linux/mount.h>
 #include <linux/time.h>
 #include <linux/compat.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 
-int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
-               unsigned long arg)
+long ext3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
+       struct inode *inode = filp->f_dentry->d_inode;
        struct ext3_inode_info *ei = EXT3_I(inode);
        unsigned int flags;
        unsigned short rsv_window_size;
@@ -39,29 +38,25 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                unsigned int oldflags;
                unsigned int jflag;
 
+               if (!is_owner_or_cap(inode))
+                       return -EACCES;
+
+               if (get_user(flags, (int __user *) arg))
+                       return -EFAULT;
+
                err = mnt_want_write(filp->f_path.mnt);
                if (err)
                        return err;
 
-               if (!is_owner_or_cap(inode)) {
-                       err = -EACCES;
-                       goto flags_out;
-               }
-
-               if (get_user(flags, (int __user *) arg)) {
-                       err = -EFAULT;
-                       goto flags_out;
-               }
-
                flags = ext3_mask_flags(inode->i_mode, flags);
 
                mutex_lock(&inode->i_mutex);
+
                /* Is it quota file? Do not allow user to mess with it */
-               if (IS_NOQUOTA(inode)) {
-                       mutex_unlock(&inode->i_mutex);
-                       err = -EPERM;
+               err = -EPERM;
+               if (IS_NOQUOTA(inode))
                        goto flags_out;
-               }
+
                oldflags = ei->i_flags;
 
                /* The JOURNAL_DATA flag is modifiable only by root */
@@ -74,11 +69,8 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                 * This test looks nicer. Thanks to Pauline Middelink
                 */
                if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) {
-                       if (!capable(CAP_LINUX_IMMUTABLE)) {
-                               mutex_unlock(&inode->i_mutex);
-                               err = -EPERM;
+                       if (!capable(CAP_LINUX_IMMUTABLE))
                                goto flags_out;
-                       }
                }
 
                /*
@@ -86,17 +78,12 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                 * the relevant capability.
                 */
                if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) {
-                       if (!capable(CAP_SYS_RESOURCE)) {
-                               mutex_unlock(&inode->i_mutex);
-                               err = -EPERM;
+                       if (!capable(CAP_SYS_RESOURCE))
                                goto flags_out;
-                       }
                }
 
-
                handle = ext3_journal_start(inode, 1);
                if (IS_ERR(handle)) {
-                       mutex_unlock(&inode->i_mutex);
                        err = PTR_ERR(handle);
                        goto flags_out;
                }
@@ -116,15 +103,13 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                err = ext3_mark_iloc_dirty(handle, inode, &iloc);
 flags_err:
                ext3_journal_stop(handle);
-               if (err) {
-                       mutex_unlock(&inode->i_mutex);
-                       return err;
-               }
+               if (err)
+                       goto flags_out;
 
                if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL))
                        err = ext3_change_inode_journal_flag(inode, jflag);
-               mutex_unlock(&inode->i_mutex);
 flags_out:
+               mutex_unlock(&inode->i_mutex);
                mnt_drop_write(filp->f_path.mnt);
                return err;
        }
@@ -140,6 +125,7 @@ flags_out:
 
                if (!is_owner_or_cap(inode))
                        return -EPERM;
+
                err = mnt_want_write(filp->f_path.mnt);
                if (err)
                        return err;
@@ -147,6 +133,7 @@ flags_out:
                        err = -EFAULT;
                        goto setversion_out;
                }
+
                handle = ext3_journal_start(inode, 1);
                if (IS_ERR(handle)) {
                        err = PTR_ERR(handle);
@@ -299,9 +286,6 @@ group_add_out:
 #ifdef CONFIG_COMPAT
 long ext3_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
-       int ret;
-
        /* These are just misnamed, they actually get/put from/to user an int */
        switch (cmd) {
        case EXT3_IOC32_GETFLAGS:
@@ -341,9 +325,6 @@ long ext3_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        default:
                return -ENOIOCTLCMD;
        }
-       lock_kernel();
-       ret = ext3_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
-       unlock_kernel();
-       return ret;
+       return ext3_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
 }
 #endif
index e2fc63cbba8b81e91945eee43d35c4b482f58fdc..6ddaa0a42b24a1c7d3576ce1a5287d869f0c2f46 100644 (file)
@@ -161,12 +161,12 @@ static struct dx_frame *dx_probe(struct qstr *entry,
                                 struct dx_frame *frame,
                                 int *err);
 static void dx_release (struct dx_frame *frames);
-static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
+static int dx_make_map(struct ext3_dir_entry_2 *de, unsigned blocksize,
                        struct dx_hash_info *hinfo, struct dx_map_entry map[]);
 static void dx_sort_map(struct dx_map_entry *map, unsigned count);
 static struct ext3_dir_entry_2 *dx_move_dirents (char *from, char *to,
                struct dx_map_entry *offsets, int count);
-static struct ext3_dir_entry_2* dx_pack_dirents (char *base, int size);
+static struct ext3_dir_entry_2 *dx_pack_dirents(char *base, unsigned blocksize);
 static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block);
 static int ext3_htree_next_block(struct inode *dir, __u32 hash,
                                 struct dx_frame *frame,
@@ -708,14 +708,14 @@ errout:
  * Create map of hash values, offsets, and sizes, stored at end of block.
  * Returns number of entries mapped.
  */
-static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
-                       struct dx_hash_info *hinfo, struct dx_map_entry *map_tail)
+static int dx_make_map(struct ext3_dir_entry_2 *de, unsigned blocksize,
+               struct dx_hash_info *hinfo, struct dx_map_entry *map_tail)
 {
        int count = 0;
        char *base = (char *) de;
        struct dx_hash_info h = *hinfo;
 
-       while ((char *) de < base + size)
+       while ((char *) de < base + blocksize)
        {
                if (de->name_len && de->inode) {
                        ext3fs_dirhash(de->name, de->name_len, &h);
@@ -1047,8 +1047,16 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
                        return ERR_PTR(-EIO);
                }
                inode = ext3_iget(dir->i_sb, ino);
-               if (IS_ERR(inode))
-                       return ERR_CAST(inode);
+               if (unlikely(IS_ERR(inode))) {
+                       if (PTR_ERR(inode) == -ESTALE) {
+                               ext3_error(dir->i_sb, __func__,
+                                               "deleted inode referenced: %lu",
+                                               ino);
+                               return ERR_PTR(-EIO);
+                       } else {
+                               return ERR_CAST(inode);
+                       }
+               }
        }
        return d_splice_alias(inode, dentry);
 }
@@ -1120,13 +1128,14 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
  * Compact each dir entry in the range to the minimal rec_len.
  * Returns pointer to last entry in range.
  */
-static struct ext3_dir_entry_2* dx_pack_dirents(char *base, int size)
+static struct ext3_dir_entry_2 *dx_pack_dirents(char *base, unsigned blocksize)
 {
-       struct ext3_dir_entry_2 *next, *to, *prev, *de = (struct ext3_dir_entry_2 *) base;
+       struct ext3_dir_entry_2 *next, *to, *prev;
+       struct ext3_dir_entry_2 *de = (struct ext3_dir_entry_2 *)base;
        unsigned rec_len = 0;
 
        prev = to = de;
-       while ((char*)de < base + size) {
+       while ((char *)de < base + blocksize) {
                next = ext3_next_entry(de);
                if (de->inode && de->name_len) {
                        rec_len = EXT3_DIR_REC_LEN(de->name_len);
index 38f40d55899c81e3f483c5237989bd68cf134db3..53c72ad85877314c16c0eef0f19fb3889a6743da 100644 (file)
@@ -55,7 +55,8 @@ static int ext4_block_in_group(struct super_block *sb, ext4_fsblk_t block,
 }
 
 static int ext4_group_used_meta_blocks(struct super_block *sb,
-                               ext4_group_t block_group)
+                                      ext4_group_t block_group,
+                                      struct ext4_group_desc *gdp)
 {
        ext4_fsblk_t tmp;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -63,10 +64,6 @@ static int ext4_group_used_meta_blocks(struct super_block *sb,
        int used_blocks = sbi->s_itb_per_group + 2;
 
        if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
-               struct ext4_group_desc *gdp;
-               struct buffer_head *bh;
-
-               gdp = ext4_get_group_desc(sb, block_group, &bh);
                if (!ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp),
                                        block_group))
                        used_blocks--;
@@ -177,7 +174,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
                 */
                mark_bitmap_end(group_blocks, sb->s_blocksize * 8, bh->b_data);
        }
-       return free_blocks - ext4_group_used_meta_blocks(sb, block_group);
+       return free_blocks - ext4_group_used_meta_blocks(sb, block_group, gdp);
 }
 
 
@@ -473,9 +470,8 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
 
        if (sbi->s_log_groups_per_flex) {
                ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
-               spin_lock(sb_bgl_lock(sbi, flex_group));
-               sbi->s_flex_groups[flex_group].free_blocks += blocks_freed;
-               spin_unlock(sb_bgl_lock(sbi, flex_group));
+               atomic_add(blocks_freed,
+                          &sbi->s_flex_groups[flex_group].free_blocks);
        }
        /*
         * request to reload the buddy with the
index 2df2e40b01af0cc031d4546306079c0d4a6669ac..b64789929a65bc00243e9b10298f056aadaeb306 100644 (file)
@@ -67,7 +67,8 @@ int ext4_check_dir_entry(const char *function, struct inode *dir,
                         unsigned int offset)
 {
        const char *error_msg = NULL;
-       const int rlen = ext4_rec_len_from_disk(de->rec_len);
+       const int rlen = ext4_rec_len_from_disk(de->rec_len,
+                                               dir->i_sb->s_blocksize);
 
        if (rlen < EXT4_DIR_REC_LEN(1))
                error_msg = "rec_len is smaller than minimal";
@@ -178,10 +179,11 @@ revalidate:
                                 * least that it is non-zero.  A
                                 * failure will be detected in the
                                 * dirent test below. */
-                               if (ext4_rec_len_from_disk(de->rec_len)
-                                               < EXT4_DIR_REC_LEN(1))
+                               if (ext4_rec_len_from_disk(de->rec_len,
+                                       sb->s_blocksize) < EXT4_DIR_REC_LEN(1))
                                        break;
-                               i += ext4_rec_len_from_disk(de->rec_len);
+                               i += ext4_rec_len_from_disk(de->rec_len,
+                                                           sb->s_blocksize);
                        }
                        offset = i;
                        filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
@@ -203,7 +205,8 @@ revalidate:
                                ret = stored;
                                goto out;
                        }
-                       offset += ext4_rec_len_from_disk(de->rec_len);
+                       offset += ext4_rec_len_from_disk(de->rec_len,
+                                       sb->s_blocksize);
                        if (le32_to_cpu(de->inode)) {
                                /* We might block in the next section
                                 * if the data destination is
@@ -225,7 +228,8 @@ revalidate:
                                        goto revalidate;
                                stored++;
                        }
-                       filp->f_pos += ext4_rec_len_from_disk(de->rec_len);
+                       filp->f_pos += ext4_rec_len_from_disk(de->rec_len,
+                                               sb->s_blocksize);
                }
                offset = 0;
                brelse(bh);
index 6083bb38057b8bca9fd18f83a871435d787f2468..d0f15ef56de1b1b6b325d0a86207e78260b1f40a 100644 (file)
  */
 #undef EXT4FS_DEBUG
 
-/*
- * Define EXT4_RESERVATION to reserve data blocks for expanding files
- */
-#define EXT4_DEFAULT_RESERVE_BLOCKS    8
-/*max window size: 1024(direct blocks) + 3([t,d]indirect blocks) */
-#define EXT4_MAX_RESERVE_BLOCKS                1027
-#define EXT4_RESERVE_WINDOW_NOT_ALLOCATED 0
-
 /*
  * Debug code
  */
@@ -54,8 +46,6 @@
 #define ext4_debug(f, a...)    do {} while (0)
 #endif
 
-#define EXT4_MULTIBLOCK_ALLOCATOR      1
-
 /* prefer goal again. length */
 #define EXT4_MB_HINT_MERGE             1
 /* blocks already reserved */
@@ -180,8 +170,9 @@ struct ext4_group_desc
  */
 
 struct flex_groups {
-       __u32 free_inodes;
-       __u32 free_blocks;
+       atomic_t free_inodes;
+       atomic_t free_blocks;
+       atomic_t used_dirs;
 };
 
 #define EXT4_BG_INODE_UNINIT   0x0001 /* Inode table/bitmap not in use */
@@ -249,6 +240,30 @@ struct flex_groups {
 #define EXT4_FL_USER_VISIBLE           0x000BDFFF /* User visible flags */
 #define EXT4_FL_USER_MODIFIABLE                0x000B80FF /* User modifiable flags */
 
+/* Flags that should be inherited by new inodes from their parent. */
+#define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
+                          EXT4_SYNC_FL | EXT4_IMMUTABLE_FL | EXT4_APPEND_FL |\
+                          EXT4_NODUMP_FL | EXT4_NOATIME_FL |\
+                          EXT4_NOCOMPR_FL | EXT4_JOURNAL_DATA_FL |\
+                          EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL)
+
+/* Flags that are appropriate for regular files (all but dir-specific ones). */
+#define EXT4_REG_FLMASK (~(EXT4_DIRSYNC_FL | EXT4_TOPDIR_FL))
+
+/* Flags that are appropriate for non-directories/regular files. */
+#define EXT4_OTHER_FLMASK (EXT4_NODUMP_FL | EXT4_NOATIME_FL)
+
+/* Mask out flags that are inappropriate for the given type of inode. */
+static inline __u32 ext4_mask_flags(umode_t mode, __u32 flags)
+{
+       if (S_ISDIR(mode))
+               return flags;
+       else if (S_ISREG(mode))
+               return flags & EXT4_REG_FLMASK;
+       else
+               return flags & EXT4_OTHER_FLMASK;
+}
+
 /*
  * Inode dynamic state flags
  */
@@ -256,6 +271,7 @@ struct flex_groups {
 #define EXT4_STATE_NEW                 0x00000002 /* inode is newly created */
 #define EXT4_STATE_XATTR               0x00000004 /* has in-inode xattrs */
 #define EXT4_STATE_NO_EXPAND           0x00000008 /* No space for expansion */
+#define EXT4_STATE_DA_ALLOC_CLOSE      0x00000010 /* Alloc DA blks on close */
 
 /* Used to pass group descriptor data when online resize is done */
 struct ext4_new_group_input {
@@ -303,7 +319,9 @@ struct ext4_new_group_data {
 #define EXT4_IOC_GROUP_EXTEND          _IOW('f', 7, unsigned long)
 #define EXT4_IOC_GROUP_ADD             _IOW('f', 8, struct ext4_new_group_input)
 #define EXT4_IOC_MIGRATE               _IO('f', 9)
+ /* note ioctl 10 reserved for an early version of the FIEMAP ioctl */
  /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */
+#define EXT4_IOC_ALLOC_DA_BLKS         _IO('f', 12)
 
 /*
  * ioctl commands in 32 bit emulation
@@ -531,7 +549,7 @@ do {                                                                               \
 #define EXT4_MOUNT_NO_UID32            0x02000  /* Disable 32-bit UIDs */
 #define EXT4_MOUNT_XATTR_USER          0x04000 /* Extended user attributes */
 #define EXT4_MOUNT_POSIX_ACL           0x08000 /* POSIX Access Control Lists */
-#define EXT4_MOUNT_RESERVATION         0x10000 /* Preallocation */
+#define EXT4_MOUNT_NO_AUTO_DA_ALLOC    0x10000 /* No auto delalloc mapping */
 #define EXT4_MOUNT_BARRIER             0x20000 /* Use block barriers */
 #define EXT4_MOUNT_NOBH                        0x40000 /* No bufferheads */
 #define EXT4_MOUNT_QUOTA               0x80000 /* Some quota option set */
@@ -666,7 +684,8 @@ struct ext4_super_block {
        __u8    s_log_groups_per_flex;  /* FLEX_BG group size */
        __u8    s_reserved_char_pad2;
        __le16  s_reserved_pad;
-       __u32   s_reserved[162];        /* Padding to the end of the block */
+       __le64  s_kbytes_written;       /* nr of lifetime kilobytes written */
+       __u32   s_reserved[160];        /* Padding to the end of the block */
 };
 
 #ifdef __KERNEL__
@@ -813,6 +832,12 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
 #define EXT4_DEF_MIN_BATCH_TIME        0
 #define EXT4_DEF_MAX_BATCH_TIME        15000 /* 15ms */
 
+/*
+ * Minimum number of groups in a flexgroup before we separate out
+ * directories into the first block group of a flexgroup
+ */
+#define EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME        4
+
 /*
  * Structure of a directory entry
  */
@@ -865,24 +890,6 @@ struct ext4_dir_entry_2 {
                                         ~EXT4_DIR_ROUND)
 #define EXT4_MAX_REC_LEN               ((1<<16)-1)
 
-static inline unsigned ext4_rec_len_from_disk(__le16 dlen)
-{
-       unsigned len = le16_to_cpu(dlen);
-
-       if (len == EXT4_MAX_REC_LEN || len == 0)
-               return 1 << 16;
-       return len;
-}
-
-static inline __le16 ext4_rec_len_to_disk(unsigned len)
-{
-       if (len == (1 << 16))
-               return cpu_to_le16(EXT4_MAX_REC_LEN);
-       else if (len > (1 << 16))
-               BUG();
-       return cpu_to_le16(len);
-}
-
 /*
  * Hash Tree Directory indexing
  * (c) Daniel Phillips, 2001
@@ -970,22 +977,6 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
 
 extern struct proc_dir_entry *ext4_proc_root;
 
-#ifdef CONFIG_PROC_FS
-extern const struct file_operations ext4_ui_proc_fops;
-
-#define        EXT4_PROC_HANDLER(name, var)                                    \
-do {                                                                   \
-       proc = proc_create_data(name, mode, sbi->s_proc,                \
-                               &ext4_ui_proc_fops, &sbi->s_##var);     \
-       if (proc == NULL) {                                             \
-               printk(KERN_ERR "EXT4-fs: can't create %s\n", name);    \
-               goto err_out;                                           \
-       }                                                               \
-} while (0)
-#else
-#define EXT4_PROC_HANDLER(name, var)
-#endif
-
 /*
  * Function prototypes
  */
@@ -1092,13 +1083,14 @@ extern int ext4_can_truncate(struct inode *inode);
 extern void ext4_truncate(struct inode *);
 extern void ext4_set_inode_flags(struct inode *);
 extern void ext4_get_inode_flags(struct ext4_inode_info *);
+extern int ext4_alloc_da_blocks(struct inode *inode);
 extern void ext4_set_aops(struct inode *inode);
 extern int ext4_writepage_trans_blocks(struct inode *);
 extern int ext4_meta_trans_blocks(struct inode *, int nrblocks, int idxblocks);
 extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks);
 extern int ext4_block_truncate_page(handle_t *handle,
                struct address_space *mapping, loff_t from);
-extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page);
+extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
 extern qsize_t ext4_get_reserved_space(struct inode *inode);
 
 /* ioctl.c */
@@ -1107,7 +1099,10 @@ extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
 
 /* migrate.c */
 extern int ext4_ext_migrate(struct inode *);
+
 /* namei.c */
+extern unsigned int ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize);
+extern __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize);
 extern int ext4_orphan_add(handle_t *, struct inode *);
 extern int ext4_orphan_del(handle_t *, struct inode *);
 extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
index 18cb67b2cbbc85c46b8c6e09efbeb13d1513b618..f0c3ec85bd488a83cfc31f8bb4f601306112e787 100644 (file)
@@ -241,5 +241,6 @@ extern int ext4_ext_search_left(struct inode *, struct ext4_ext_path *,
 extern int ext4_ext_search_right(struct inode *, struct ext4_ext_path *,
                                                ext4_lblk_t *, ext4_fsblk_t *);
 extern void ext4_ext_drop_refs(struct ext4_ext_path *);
+extern int ext4_ext_check_inode(struct inode *inode);
 #endif /* _EXT4_EXTENTS */
 
index e69acc16f5c4300be5b5cd641f515fba320a98db..4ce2187123aad818de707f4e82a988fdb8ee14a3 100644 (file)
@@ -33,9 +33,6 @@ typedef __u32 ext4_lblk_t;
 /* data type for block group number */
 typedef unsigned int ext4_group_t;
 
-#define rsv_start rsv_window._rsv_start
-#define rsv_end rsv_window._rsv_end
-
 /*
  * storage for cached extent
  */
@@ -125,6 +122,9 @@ struct ext4_inode_info {
        struct list_head i_prealloc_list;
        spinlock_t i_prealloc_lock;
 
+       /* ialloc */
+       ext4_group_t    i_last_alloc_group;
+
        /* allocation reservation info for delalloc */
        unsigned int i_reserved_data_blocks;
        unsigned int i_reserved_meta_blocks;
index 039b6ea1a0429b30e5e95253b42ed83d24494869..57b71fefbccf753fb05e2436eea4da2da7663b3a 100644 (file)
@@ -62,12 +62,10 @@ struct ext4_sb_info {
        struct percpu_counter s_freeinodes_counter;
        struct percpu_counter s_dirs_counter;
        struct percpu_counter s_dirtyblocks_counter;
-       struct blockgroup_lock s_blockgroup_lock;
+       struct blockgroup_lock *s_blockgroup_lock;
        struct proc_dir_entry *s_proc;
-
-       /* root of the per fs reservation window tree */
-       spinlock_t s_rsv_window_lock;
-       struct rb_root s_rsv_window_root;
+       struct kobject s_kobj;
+       struct completion s_kobj_unregister;
 
        /* Journaling */
        struct inode *s_journal_inode;
@@ -146,6 +144,10 @@ struct ext4_sb_info {
        /* locality groups */
        struct ext4_locality_group *s_locality_groups;
 
+       /* for write statistics */
+       unsigned long s_sectors_written_start;
+       u64 s_kbytes_written;
+
        unsigned int s_log_groups_per_flex;
        struct flex_groups *s_flex_groups;
 };
@@ -153,7 +155,7 @@ struct ext4_sb_info {
 static inline spinlock_t *
 sb_bgl_lock(struct ext4_sb_info *sbi, unsigned int block_group)
 {
-       return bgl_lock_ptr(&sbi->s_blockgroup_lock, block_group);
+       return bgl_lock_ptr(sbi->s_blockgroup_lock, block_group);
 }
 
 #endif /* _EXT4_SB */
index e0aa4fe4f596fcb11549de818436edced6887f3b..ac77d8b8251da9cb6ac720db55e8b7e72ec97a91 100644 (file)
@@ -152,6 +152,8 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
        ext4_fsblk_t bg_start;
        ext4_fsblk_t last_block;
        ext4_grpblk_t colour;
+       ext4_group_t block_group;
+       int flex_size = ext4_flex_bg_size(EXT4_SB(inode->i_sb));
        int depth;
 
        if (path) {
@@ -170,10 +172,31 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
        }
 
        /* OK. use inode's group */
-       bg_start = (ei->i_block_group * EXT4_BLOCKS_PER_GROUP(inode->i_sb)) +
+       block_group = ei->i_block_group;
+       if (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) {
+               /*
+                * If there are at least EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME
+                * block groups per flexgroup, reserve the first block 
+                * group for directories and special files.  Regular 
+                * files will start at the second block group.  This
+                * tends to speed up directory access and improves 
+                * fsck times.
+                */
+               block_group &= ~(flex_size-1);
+               if (S_ISREG(inode->i_mode))
+                       block_group++;
+       }
+       bg_start = (block_group * EXT4_BLOCKS_PER_GROUP(inode->i_sb)) +
                le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_first_data_block);
        last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1;
 
+       /*
+        * If we are doing delayed allocation, we don't need take
+        * colour into account.
+        */
+       if (test_opt(inode->i_sb, DELALLOC))
+               return bg_start;
+
        if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block)
                colour = (current->pid % 16) *
                        (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
@@ -301,7 +324,64 @@ ext4_ext_max_entries(struct inode *inode, int depth)
        return max;
 }
 
-static int __ext4_ext_check_header(const char *function, struct inode *inode,
+static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext)
+{
+       ext4_fsblk_t block = ext_pblock(ext);
+       int len = ext4_ext_get_actual_len(ext);
+       struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
+       if (unlikely(block < le32_to_cpu(es->s_first_data_block) ||
+                       ((block + len) > ext4_blocks_count(es))))
+               return 0;
+       else
+               return 1;
+}
+
+static int ext4_valid_extent_idx(struct inode *inode,
+                               struct ext4_extent_idx *ext_idx)
+{
+       ext4_fsblk_t block = idx_pblock(ext_idx);
+       struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
+       if (unlikely(block < le32_to_cpu(es->s_first_data_block) ||
+                       (block > ext4_blocks_count(es))))
+               return 0;
+       else
+               return 1;
+}
+
+static int ext4_valid_extent_entries(struct inode *inode,
+                               struct ext4_extent_header *eh,
+                               int depth)
+{
+       struct ext4_extent *ext;
+       struct ext4_extent_idx *ext_idx;
+       unsigned short entries;
+       if (eh->eh_entries == 0)
+               return 1;
+
+       entries = le16_to_cpu(eh->eh_entries);
+
+       if (depth == 0) {
+               /* leaf entries */
+               ext = EXT_FIRST_EXTENT(eh);
+               while (entries) {
+                       if (!ext4_valid_extent(inode, ext))
+                               return 0;
+                       ext++;
+                       entries--;
+               }
+       } else {
+               ext_idx = EXT_FIRST_INDEX(eh);
+               while (entries) {
+                       if (!ext4_valid_extent_idx(inode, ext_idx))
+                               return 0;
+                       ext_idx++;
+                       entries--;
+               }
+       }
+       return 1;
+}
+
+static int __ext4_ext_check(const char *function, struct inode *inode,
                                        struct ext4_extent_header *eh,
                                        int depth)
 {
@@ -329,11 +409,15 @@ static int __ext4_ext_check_header(const char *function, struct inode *inode,
                error_msg = "invalid eh_entries";
                goto corrupted;
        }
+       if (!ext4_valid_extent_entries(inode, eh, depth)) {
+               error_msg = "invalid extent entries";
+               goto corrupted;
+       }
        return 0;
 
 corrupted:
        ext4_error(inode->i_sb, function,
-                       "bad header in inode #%lu: %s - magic %x, "
+                       "bad header/extent in inode #%lu: %s - magic %x, "
                        "entries %u, max %u(%u), depth %u(%u)",
                        inode->i_ino, error_msg, le16_to_cpu(eh->eh_magic),
                        le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
@@ -342,8 +426,13 @@ corrupted:
        return -EIO;
 }
 
-#define ext4_ext_check_header(inode, eh, depth)        \
-       __ext4_ext_check_header(__func__, inode, eh, depth)
+#define ext4_ext_check(inode, eh, depth)       \
+       __ext4_ext_check(__func__, inode, eh, depth)
+
+int ext4_ext_check_inode(struct inode *inode)
+{
+       return ext4_ext_check(inode, ext_inode_hdr(inode), ext_depth(inode));
+}
 
 #ifdef EXT_DEBUG
 static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
@@ -547,9 +636,6 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
 
        eh = ext_inode_hdr(inode);
        depth = ext_depth(inode);
-       if (ext4_ext_check_header(inode, eh, depth))
-               return ERR_PTR(-EIO);
-
 
        /* account possible depth increase */
        if (!path) {
@@ -565,6 +651,8 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
        i = depth;
        /* walk through the tree */
        while (i) {
+               int need_to_validate = 0;
+
                ext_debug("depth %d: num %d, max %d\n",
                          ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
 
@@ -573,10 +661,17 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
                path[ppos].p_depth = i;
                path[ppos].p_ext = NULL;
 
-               bh = sb_bread(inode->i_sb, path[ppos].p_block);
-               if (!bh)
+               bh = sb_getblk(inode->i_sb, path[ppos].p_block);
+               if (unlikely(!bh))
                        goto err;
-
+               if (!bh_uptodate_or_lock(bh)) {
+                       if (bh_submit_read(bh) < 0) {
+                               put_bh(bh);
+                               goto err;
+                       }
+                       /* validate the extent entries */
+                       need_to_validate = 1;
+               }
                eh = ext_block_hdr(bh);
                ppos++;
                BUG_ON(ppos > depth);
@@ -584,7 +679,7 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
                path[ppos].p_hdr = eh;
                i--;
 
-               if (ext4_ext_check_header(inode, eh, i))
+               if (need_to_validate && ext4_ext_check(inode, eh, i))
                        goto err;
        }
 
@@ -1181,7 +1276,7 @@ got_index:
                        return -EIO;
                eh = ext_block_hdr(bh);
                /* subtract from p_depth to get proper eh_depth */
-               if (ext4_ext_check_header(inode, eh, path->p_depth - depth)) {
+               if (ext4_ext_check(inode, eh, path->p_depth - depth)) {
                        put_bh(bh);
                        return -EIO;
                }
@@ -1194,7 +1289,7 @@ got_index:
        if (bh == NULL)
                return -EIO;
        eh = ext_block_hdr(bh);
-       if (ext4_ext_check_header(inode, eh, path->p_depth - depth)) {
+       if (ext4_ext_check(inode, eh, path->p_depth - depth)) {
                put_bh(bh);
                return -EIO;
        }
@@ -2137,7 +2232,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
                return -ENOMEM;
        }
        path[0].p_hdr = ext_inode_hdr(inode);
-       if (ext4_ext_check_header(inode, path[0].p_hdr, depth)) {
+       if (ext4_ext_check(inode, path[0].p_hdr, depth)) {
                err = -EIO;
                goto out;
        }
@@ -2191,7 +2286,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
                                err = -EIO;
                                break;
                        }
-                       if (ext4_ext_check_header(inode, ext_block_hdr(bh),
+                       if (ext4_ext_check(inode, ext_block_hdr(bh),
                                                        depth - i - 1)) {
                                err = -EIO;
                                break;
index f731cb545a0359cc664de79a3fe9ab6c7ca4f3b8..588af8c77246f71b9a2b088602dba33b88c43f52 100644 (file)
  */
 static int ext4_release_file(struct inode *inode, struct file *filp)
 {
+       if (EXT4_I(inode)->i_state & EXT4_STATE_DA_ALLOC_CLOSE) {
+               ext4_alloc_da_blocks(inode);
+               EXT4_I(inode)->i_state &= ~EXT4_STATE_DA_ALLOC_CLOSE;
+       }
        /* if we are the last writer on the inode, drop the block reservation */
        if ((filp->f_mode & FMODE_WRITE) &&
-                       (atomic_read(&inode->i_writecount) == 1))
+                       (atomic_read(&inode->i_writecount) == 1) &&
+                       !EXT4_I(inode)->i_reserved_data_blocks)
        {
                down_write(&EXT4_I(inode)->i_data_sem);
                ext4_discard_preallocations(inode);
index fb51b40e3e8f5a60960d8584815f390d71ae1124..47b84e8df56859ca1e741cfb6543b5966ee45657 100644 (file)
@@ -189,7 +189,6 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
        struct ext4_super_block *es;
        struct ext4_sb_info *sbi;
        int fatal = 0, err, count, cleared;
-       ext4_group_t flex_group;
 
        if (atomic_read(&inode->i_count) > 1) {
                printk(KERN_ERR "ext4_free_inode: inode has count=%d\n",
@@ -268,6 +267,13 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
                        if (is_directory) {
                                count = ext4_used_dirs_count(sb, gdp) - 1;
                                ext4_used_dirs_set(sb, gdp, count);
+                               if (sbi->s_log_groups_per_flex) {
+                                       ext4_group_t f;
+
+                                       f = ext4_flex_group(sbi, block_group);
+                                       atomic_dec(&sbi->s_flex_groups[f].free_inodes);
+                               }
+
                        }
                        gdp->bg_checksum = ext4_group_desc_csum(sbi,
                                                        block_group, gdp);
@@ -277,10 +283,10 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
                                percpu_counter_dec(&sbi->s_dirs_counter);
 
                        if (sbi->s_log_groups_per_flex) {
-                               flex_group = ext4_flex_group(sbi, block_group);
-                               spin_lock(sb_bgl_lock(sbi, flex_group));
-                               sbi->s_flex_groups[flex_group].free_inodes++;
-                               spin_unlock(sb_bgl_lock(sbi, flex_group));
+                               ext4_group_t f;
+
+                               f = ext4_flex_group(sbi, block_group);
+                               atomic_inc(&sbi->s_flex_groups[f].free_inodes);
                        }
                }
                BUFFER_TRACE(bh2, "call ext4_handle_dirty_metadata");
@@ -360,9 +366,9 @@ static int find_group_flex(struct super_block *sb, struct inode *parent,
                sbi->s_log_groups_per_flex;
 
 find_close_to_parent:
-       flexbg_free_blocks = flex_group[best_flex].free_blocks;
+       flexbg_free_blocks = atomic_read(&flex_group[best_flex].free_blocks);
        flex_freeb_ratio = flexbg_free_blocks * 100 / blocks_per_flex;
-       if (flex_group[best_flex].free_inodes &&
+       if (atomic_read(&flex_group[best_flex].free_inodes) &&
            flex_freeb_ratio > free_block_ratio)
                goto found_flexbg;
 
@@ -375,24 +381,24 @@ find_close_to_parent:
                if (i == parent_fbg_group || i == parent_fbg_group - 1)
                        continue;
 
-               flexbg_free_blocks = flex_group[i].free_blocks;
+               flexbg_free_blocks = atomic_read(&flex_group[i].free_blocks);
                flex_freeb_ratio = flexbg_free_blocks * 100 / blocks_per_flex;
 
                if (flex_freeb_ratio > free_block_ratio &&
-                   flex_group[i].free_inodes) {
+                   (atomic_read(&flex_group[i].free_inodes))) {
                        best_flex = i;
                        goto found_flexbg;
                }
 
-               if (flex_group[best_flex].free_inodes == 0 ||
-                   (flex_group[i].free_blocks >
-                    flex_group[best_flex].free_blocks &&
-                    flex_group[i].free_inodes))
+               if ((atomic_read(&flex_group[best_flex].free_inodes) == 0) ||
+                   ((atomic_read(&flex_group[i].free_blocks) >
+                     atomic_read(&flex_group[best_flex].free_blocks)) &&
+                    atomic_read(&flex_group[i].free_inodes)))
                        best_flex = i;
        }
 
-       if (!flex_group[best_flex].free_inodes ||
-           !flex_group[best_flex].free_blocks)
+       if (!atomic_read(&flex_group[best_flex].free_inodes) ||
+           !atomic_read(&flex_group[best_flex].free_blocks))
                return -1;
 
 found_flexbg:
@@ -410,6 +416,42 @@ out:
        return 0;
 }
 
+struct orlov_stats {
+       __u32 free_inodes;
+       __u32 free_blocks;
+       __u32 used_dirs;
+};
+
+/*
+ * Helper function for Orlov's allocator; returns critical information
+ * for a particular block group or flex_bg.  If flex_size is 1, then g
+ * is a block group number; otherwise it is flex_bg number.
+ */
+void get_orlov_stats(struct super_block *sb, ext4_group_t g,
+                      int flex_size, struct orlov_stats *stats)
+{
+       struct ext4_group_desc *desc;
+       struct flex_groups *flex_group = EXT4_SB(sb)->s_flex_groups;
+
+       if (flex_size > 1) {
+               stats->free_inodes = atomic_read(&flex_group[g].free_inodes);
+               stats->free_blocks = atomic_read(&flex_group[g].free_blocks);
+               stats->used_dirs = atomic_read(&flex_group[g].used_dirs);
+               return;
+       }
+
+       desc = ext4_get_group_desc(sb, g, NULL);
+       if (desc) {
+               stats->free_inodes = ext4_free_inodes_count(sb, desc);
+               stats->free_blocks = ext4_free_blks_count(sb, desc);
+               stats->used_dirs = ext4_used_dirs_count(sb, desc);
+       } else {
+               stats->free_inodes = 0;
+               stats->free_blocks = 0;
+               stats->used_dirs = 0;
+       }
+}
+
 /*
  * Orlov's allocator for directories.
  *
@@ -425,35 +467,34 @@ out:
  * it has too many directories already (max_dirs) or
  * it has too few free inodes left (min_inodes) or
  * it has too few free blocks left (min_blocks) or
- * it's already running too large debt (max_debt).
  * Parent's group is preferred, if it doesn't satisfy these
  * conditions we search cyclically through the rest. If none
  * of the groups look good we just look for a group with more
  * free inodes than average (starting at parent's group).
- *
- * Debt is incremented each time we allocate a directory and decremented
- * when we allocate an inode, within 0--255.
  */
 
-#define INODE_COST 64
-#define BLOCK_COST 256
-
 static int find_group_orlov(struct super_block *sb, struct inode *parent,
-                               ext4_group_t *group)
+                           ext4_group_t *group, int mode)
 {
        ext4_group_t parent_group = EXT4_I(parent)->i_block_group;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       struct ext4_super_block *es = sbi->s_es;
        ext4_group_t ngroups = sbi->s_groups_count;
        int inodes_per_group = EXT4_INODES_PER_GROUP(sb);
        unsigned int freei, avefreei;
        ext4_fsblk_t freeb, avefreeb;
-       ext4_fsblk_t blocks_per_dir;
        unsigned int ndirs;
-       int max_debt, max_dirs, min_inodes;
+       int max_dirs, min_inodes;
        ext4_grpblk_t min_blocks;
-       ext4_group_t i;
+       ext4_group_t i, grp, g;
        struct ext4_group_desc *desc;
+       struct orlov_stats stats;
+       int flex_size = ext4_flex_bg_size(sbi);
+
+       if (flex_size > 1) {
+               ngroups = (ngroups + flex_size - 1) >>
+                       sbi->s_log_groups_per_flex;
+               parent_group >>= sbi->s_log_groups_per_flex;
+       }
 
        freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter);
        avefreei = freei / ngroups;
@@ -462,71 +503,97 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
        do_div(avefreeb, ngroups);
        ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter);
 
-       if ((parent == sb->s_root->d_inode) ||
-           (EXT4_I(parent)->i_flags & EXT4_TOPDIR_FL)) {
+       if (S_ISDIR(mode) &&
+           ((parent == sb->s_root->d_inode) ||
+            (EXT4_I(parent)->i_flags & EXT4_TOPDIR_FL))) {
                int best_ndir = inodes_per_group;
-               ext4_group_t grp;
                int ret = -1;
 
                get_random_bytes(&grp, sizeof(grp));
                parent_group = (unsigned)grp % ngroups;
                for (i = 0; i < ngroups; i++) {
-                       grp = (parent_group + i) % ngroups;
-                       desc = ext4_get_group_desc(sb, grp, NULL);
-                       if (!desc || !ext4_free_inodes_count(sb, desc))
+                       g = (parent_group + i) % ngroups;
+                       get_orlov_stats(sb, g, flex_size, &stats);
+                       if (!stats.free_inodes)
                                continue;
-                       if (ext4_used_dirs_count(sb, desc) >= best_ndir)
+                       if (stats.used_dirs >= best_ndir)
                                continue;
-                       if (ext4_free_inodes_count(sb, desc) < avefreei)
+                       if (stats.free_inodes < avefreei)
                                continue;
-                       if (ext4_free_blks_count(sb, desc) < avefreeb)
+                       if (stats.free_blocks < avefreeb)
                                continue;
-                       *group = grp;
+                       grp = g;
                        ret = 0;
-                       best_ndir = ext4_used_dirs_count(sb, desc);
+                       best_ndir = stats.used_dirs;
+               }
+               if (ret)
+                       goto fallback;
+       found_flex_bg:
+               if (flex_size == 1) {
+                       *group = grp;
+                       return 0;
+               }
+
+               /*
+                * We pack inodes at the beginning of the flexgroup's
+                * inode tables.  Block allocation decisions will do
+                * something similar, although regular files will
+                * start at 2nd block group of the flexgroup.  See
+                * ext4_ext_find_goal() and ext4_find_near().
+                */
+               grp *= flex_size;
+               for (i = 0; i < flex_size; i++) {
+                       if (grp+i >= sbi->s_groups_count)
+                               break;
+                       desc = ext4_get_group_desc(sb, grp+i, NULL);
+                       if (desc && ext4_free_inodes_count(sb, desc)) {
+                               *group = grp+i;
+                               return 0;
+                       }
                }
-               if (ret == 0)
-                       return ret;
                goto fallback;
        }
 
-       blocks_per_dir = ext4_blocks_count(es) - freeb;
-       do_div(blocks_per_dir, ndirs);
-
        max_dirs = ndirs / ngroups + inodes_per_group / 16;
-       min_inodes = avefreei - inodes_per_group / 4;
-       min_blocks = avefreeb - EXT4_BLOCKS_PER_GROUP(sb) / 4;
-
-       max_debt = EXT4_BLOCKS_PER_GROUP(sb);
-       max_debt /= max_t(int, blocks_per_dir, BLOCK_COST);
-       if (max_debt * INODE_COST > inodes_per_group)
-               max_debt = inodes_per_group / INODE_COST;
-       if (max_debt > 255)
-               max_debt = 255;
-       if (max_debt == 0)
-               max_debt = 1;
+       min_inodes = avefreei - inodes_per_group*flex_size / 4;
+       if (min_inodes < 1)
+               min_inodes = 1;
+       min_blocks = avefreeb - EXT4_BLOCKS_PER_GROUP(sb)*flex_size / 4;
+
+       /*
+        * Start looking in the flex group where we last allocated an
+        * inode for this parent directory
+        */
+       if (EXT4_I(parent)->i_last_alloc_group != ~0) {
+               parent_group = EXT4_I(parent)->i_last_alloc_group;
+               if (flex_size > 1)
+                       parent_group >>= sbi->s_log_groups_per_flex;
+       }
 
        for (i = 0; i < ngroups; i++) {
-               *group = (parent_group + i) % ngroups;
-               desc = ext4_get_group_desc(sb, *group, NULL);
-               if (!desc || !ext4_free_inodes_count(sb, desc))
-                       continue;
-               if (ext4_used_dirs_count(sb, desc) >= max_dirs)
+               grp = (parent_group + i) % ngroups;
+               get_orlov_stats(sb, grp, flex_size, &stats);
+               if (stats.used_dirs >= max_dirs)
                        continue;
-               if (ext4_free_inodes_count(sb, desc) < min_inodes)
+               if (stats.free_inodes < min_inodes)
                        continue;
-               if (ext4_free_blks_count(sb, desc) < min_blocks)
+               if (stats.free_blocks < min_blocks)
                        continue;
-               return 0;
+               goto found_flex_bg;
        }
 
 fallback:
+       ngroups = sbi->s_groups_count;
+       avefreei = freei / ngroups;
+       parent_group = EXT4_I(parent)->i_block_group;
        for (i = 0; i < ngroups; i++) {
-               *group = (parent_group + i) % ngroups;
-               desc = ext4_get_group_desc(sb, *group, NULL);
+               grp = (parent_group + i) % ngroups;
+               desc = ext4_get_group_desc(sb, grp, NULL);
                if (desc && ext4_free_inodes_count(sb, desc) &&
-                       ext4_free_inodes_count(sb, desc) >= avefreei)
+                   ext4_free_inodes_count(sb, desc) >= avefreei) {
+                       *group = grp;
                        return 0;
+               }
        }
 
        if (avefreei) {
@@ -542,12 +609,51 @@ fallback:
 }
 
 static int find_group_other(struct super_block *sb, struct inode *parent,
-                               ext4_group_t *group)
+                           ext4_group_t *group, int mode)
 {
        ext4_group_t parent_group = EXT4_I(parent)->i_block_group;
        ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
        struct ext4_group_desc *desc;
-       ext4_group_t i;
+       ext4_group_t i, last;
+       int flex_size = ext4_flex_bg_size(EXT4_SB(sb));
+
+       /*
+        * Try to place the inode is the same flex group as its
+        * parent.  If we can't find space, use the Orlov algorithm to
+        * find another flex group, and store that information in the
+        * parent directory's inode information so that use that flex
+        * group for future allocations.
+        */
+       if (flex_size > 1) {
+               int retry = 0;
+
+       try_again:
+               parent_group &= ~(flex_size-1);
+               last = parent_group + flex_size;
+               if (last > ngroups)
+                       last = ngroups;
+               for  (i = parent_group; i < last; i++) {
+                       desc = ext4_get_group_desc(sb, i, NULL);
+                       if (desc && ext4_free_inodes_count(sb, desc)) {
+                               *group = i;
+                               return 0;
+                       }
+               }
+               if (!retry && EXT4_I(parent)->i_last_alloc_group != ~0) {
+                       retry = 1;
+                       parent_group = EXT4_I(parent)->i_last_alloc_group;
+                       goto try_again;
+               }
+               /*
+                * If this didn't work, use the Orlov search algorithm
+                * to find a new flex group; we pass in the mode to
+                * avoid the topdir algorithms.
+                */
+               *group = parent_group + flex_size;
+               if (*group > ngroups)
+                       *group = 0;
+               return find_group_orlov(sb, parent, group, mode);
+       }
 
        /*
         * Try to place the inode in its parent directory
@@ -665,6 +771,11 @@ static int ext4_claim_inode(struct super_block *sb,
        if (S_ISDIR(mode)) {
                count = ext4_used_dirs_count(sb, gdp) + 1;
                ext4_used_dirs_set(sb, gdp, count);
+               if (sbi->s_log_groups_per_flex) {
+                       ext4_group_t f = ext4_flex_group(sbi, group);
+
+                       atomic_inc(&sbi->s_flex_groups[f].free_inodes);
+               }
        }
        gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp);
 err_ret:
@@ -716,10 +827,10 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
        sbi = EXT4_SB(sb);
        es = sbi->s_es;
 
-       if (sbi->s_log_groups_per_flex) {
+       if (sbi->s_log_groups_per_flex && test_opt(sb, OLDALLOC)) {
                ret2 = find_group_flex(sb, dir, &group);
                if (ret2 == -1) {
-                       ret2 = find_group_other(sb, dir, &group);
+                       ret2 = find_group_other(sb, dir, &group, mode);
                        if (ret2 == 0 && once)
                                once = 0;
                                printk(KERN_NOTICE "ext4: find_group_flex "
@@ -733,11 +844,12 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
                if (test_opt(sb, OLDALLOC))
                        ret2 = find_group_dir(sb, dir, &group);
                else
-                       ret2 = find_group_orlov(sb, dir, &group);
+                       ret2 = find_group_orlov(sb, dir, &group, mode);
        } else
-               ret2 = find_group_other(sb, dir, &group);
+               ret2 = find_group_other(sb, dir, &group, mode);
 
 got_group:
+       EXT4_I(dir)->i_last_alloc_group = group;
        err = -ENOSPC;
        if (ret2 == -1)
                goto out;
@@ -858,9 +970,7 @@ got:
 
        if (sbi->s_log_groups_per_flex) {
                flex_group = ext4_flex_group(sbi, group);
-               spin_lock(sb_bgl_lock(sbi, flex_group));
-               sbi->s_flex_groups[flex_group].free_inodes--;
-               spin_unlock(sb_bgl_lock(sbi, flex_group));
+               atomic_dec(&sbi->s_flex_groups[flex_group].free_inodes);
        }
 
        inode->i_uid = current_fsuid();
@@ -885,19 +995,16 @@ got:
        ei->i_disksize = 0;
 
        /*
-        * Don't inherit extent flag from directory. We set extent flag on
-        * newly created directory and file only if -o extent mount option is
-        * specified
+        * Don't inherit extent flag from directory, amongst others. We set
+        * extent flag on newly created directory and file only if -o extent
+        * mount option is specified
         */
-       ei->i_flags = EXT4_I(dir)->i_flags & ~(EXT4_INDEX_FL|EXT4_EXTENTS_FL);
-       if (S_ISLNK(mode))
-               ei->i_flags &= ~(EXT4_IMMUTABLE_FL|EXT4_APPEND_FL);
-       /* dirsync only applies to directories */
-       if (!S_ISDIR(mode))
-               ei->i_flags &= ~EXT4_DIRSYNC_FL;
+       ei->i_flags =
+               ext4_mask_flags(mode, EXT4_I(dir)->i_flags & EXT4_FL_INHERITED);
        ei->i_file_acl = 0;
        ei->i_dtime = 0;
        ei->i_block_group = group;
+       ei->i_last_alloc_group = ~0;
 
        ext4_set_inode_flags(inode);
        if (IS_DIRSYNC(inode))
index 71d3ecd5db798ce6bcab06331ca7ec4819f62ea1..a2e7952bc5f9a6e3f3ed877dde89fb93ef4b4035 100644 (file)
@@ -371,6 +371,34 @@ static int ext4_block_to_path(struct inode *inode,
        return n;
 }
 
+static int __ext4_check_blockref(const char *function, struct inode *inode,
+                                unsigned int *p, unsigned int max) {
+
+       unsigned int maxblocks = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es);
+       unsigned int *bref = p;
+       while (bref < p+max) {
+               if (unlikely(*bref >= maxblocks)) {
+                       ext4_error(inode->i_sb, function,
+                                  "block reference %u >= max (%u) "
+                                  "in inode #%lu, offset=%d",
+                                  *bref, maxblocks,
+                                  inode->i_ino, (int)(bref-p));
+                       return -EIO;
+               }
+               bref++;
+       }
+       return 0;
+}
+
+
+#define ext4_check_indirect_blockref(inode, bh)                         \
+        __ext4_check_blockref(__func__, inode, (__le32 *)(bh)->b_data,  \
+                             EXT4_ADDR_PER_BLOCK((inode)->i_sb))
+
+#define ext4_check_inode_blockref(inode)                                \
+        __ext4_check_blockref(__func__, inode, EXT4_I(inode)->i_data,   \
+                             EXT4_NDIR_BLOCKS)
+
 /**
  *     ext4_get_branch - read the chain of indirect blocks leading to data
  *     @inode: inode in question
@@ -415,9 +443,22 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth,
        if (!p->key)
                goto no_block;
        while (--depth) {
-               bh = sb_bread(sb, le32_to_cpu(p->key));
-               if (!bh)
+               bh = sb_getblk(sb, le32_to_cpu(p->key));
+               if (unlikely(!bh))
                        goto failure;
+                  
+               if (!bh_uptodate_or_lock(bh)) {
+                       if (bh_submit_read(bh) < 0) {
+                               put_bh(bh);
+                               goto failure;
+                       }
+                       /* validate block references */
+                       if (ext4_check_indirect_blockref(inode, bh)) {
+                               put_bh(bh);
+                               goto failure;
+                       }
+               }
+               
                add_chain(++p, bh, (__le32 *)bh->b_data + *++offsets);
                /* Reader: end */
                if (!p->key)
@@ -459,6 +500,8 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
        ext4_fsblk_t bg_start;
        ext4_fsblk_t last_block;
        ext4_grpblk_t colour;
+       ext4_group_t block_group;
+       int flex_size = ext4_flex_bg_size(EXT4_SB(inode->i_sb));
 
        /* Try to find previous block */
        for (p = ind->p - 1; p >= start; p--) {
@@ -474,9 +517,22 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
         * It is going to be referred to from the inode itself? OK, just put it
         * into the same cylinder group then.
         */
-       bg_start = ext4_group_first_block_no(inode->i_sb, ei->i_block_group);
+       block_group = ei->i_block_group;
+       if (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) {
+               block_group &= ~(flex_size-1);
+               if (S_ISREG(inode->i_mode))
+                       block_group++;
+       }
+       bg_start = ext4_group_first_block_no(inode->i_sb, block_group);
        last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1;
 
+       /*
+        * If we are doing delayed allocation, we don't need take
+        * colour into account.
+        */
+       if (test_opt(inode->i_sb, DELALLOC))
+               return bg_start;
+
        if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block)
                colour = (current->pid % 16) *
                        (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
@@ -1052,9 +1108,16 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used)
        /*
         * free those over-booking quota for metadata blocks
         */
-
        if (mdb_free)
                vfs_dq_release_reservation_block(inode, mdb_free);
+
+       /*
+        * If we have done all the pending block allocations and if
+        * there aren't any writers on the inode, we can discard the
+        * inode's preallocations.
+        */
+       if (!total && (atomic_read(&inode->i_writecount) == 0))
+               ext4_discard_preallocations(inode);
 }
 
 /*
@@ -1688,9 +1751,10 @@ static void ext4_da_page_release_reservation(struct page *page,
 
 struct mpage_da_data {
        struct inode *inode;
-       struct buffer_head lbh;                 /* extent of blocks */
+       sector_t b_blocknr;             /* start block number of extent */
+       size_t b_size;                  /* size of extent */
+       unsigned long b_state;          /* state of the extent */
        unsigned long first_page, next_page;    /* extent of pages */
-       get_block_t *get_block;
        struct writeback_control *wbc;
        int io_done;
        int pages_written;
@@ -1704,7 +1768,6 @@ struct mpage_da_data {
  * @mpd->inode: inode
  * @mpd->first_page: first page of the extent
  * @mpd->next_page: page after the last page of the extent
- * @mpd->get_block: the filesystem's block mapper function
  *
  * By the time mpage_da_submit_io() is called we expect all blocks
  * to be allocated. this may be wrong if allocation failed.
@@ -1724,7 +1787,7 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd)
        /*
         * We need to start from the first_page to the next_page - 1
         * to make sure we also write the mapped dirty buffer_heads.
-        * If we look at mpd->lbh.b_blocknr we would only be looking
+        * If we look at mpd->b_blocknr we would only be looking
         * at the currently mapped buffer_heads.
         */
        index = mpd->first_page;
@@ -1914,68 +1977,111 @@ static void ext4_print_free_blocks(struct inode *inode)
        return;
 }
 
+#define                EXT4_DELALLOC_RSVED     1
+static int ext4_da_get_block_write(struct inode *inode, sector_t iblock,
+                                  struct buffer_head *bh_result, int create)
+{
+       int ret;
+       unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
+       loff_t disksize = EXT4_I(inode)->i_disksize;
+       handle_t *handle = NULL;
+
+       handle = ext4_journal_current_handle();
+       BUG_ON(!handle);
+       ret = ext4_get_blocks_wrap(handle, inode, iblock, max_blocks,
+                                  bh_result, create, 0, EXT4_DELALLOC_RSVED);
+       if (ret <= 0)
+               return ret;
+
+       bh_result->b_size = (ret << inode->i_blkbits);
+
+       if (ext4_should_order_data(inode)) {
+               int retval;
+               retval = ext4_jbd2_file_inode(handle, inode);
+               if (retval)
+                       /*
+                        * Failed to add inode for ordered mode. Don't
+                        * update file size
+                        */
+                       return retval;
+       }
+
+       /*
+        * Update on-disk size along with block allocation we don't
+        * use 'extend_disksize' as size may change within already
+        * allocated block -bzzz
+        */
+       disksize = ((loff_t) iblock + ret) << inode->i_blkbits;
+       if (disksize > i_size_read(inode))
+               disksize = i_size_read(inode);
+       if (disksize > EXT4_I(inode)->i_disksize) {
+               ext4_update_i_disksize(inode, disksize);
+               ret = ext4_mark_inode_dirty(handle, inode);
+               return ret;
+       }
+       return 0;
+}
+
 /*
  * mpage_da_map_blocks - go through given space
  *
- * @mpd->lbh - bh describing space
- * @mpd->get_block - the filesystem's block mapper function
+ * @mpd - bh describing space
  *
  * The function skips space we know is already mapped to disk blocks.
  *
  */
-static int  mpage_da_map_blocks(struct mpage_da_data *mpd)
+static int mpage_da_map_blocks(struct mpage_da_data *mpd)
 {
        int err = 0;
        struct buffer_head new;
-       struct buffer_head *lbh = &mpd->lbh;
        sector_t next;
 
        /*
         * We consider only non-mapped and non-allocated blocks
         */
-       if (buffer_mapped(lbh) && !buffer_delay(lbh))
+       if ((mpd->b_state  & (1 << BH_Mapped)) &&
+           !(mpd->b_state & (1 << BH_Delay)))
                return 0;
-       new.b_state = lbh->b_state;
+       new.b_state = mpd->b_state;
        new.b_blocknr = 0;
-       new.b_size = lbh->b_size;
-       next = lbh->b_blocknr;
+       new.b_size = mpd->b_size;
+       next = mpd->b_blocknr;
        /*
         * If we didn't accumulate anything
         * to write simply return
         */
        if (!new.b_size)
                return 0;
-       err = mpd->get_block(mpd->inode, next, &new, 1);
-       if (err) {
 
-               /* If get block returns with error
-                * we simply return. Later writepage
-                * will redirty the page and writepages
-                * will find the dirty page again
+       err = ext4_da_get_block_write(mpd->inode, next, &new, 1);
+       if (err) {
+               /*
+                * If get block returns with error we simply
+                * return. Later writepage will redirty the page and
+                * writepages will find the dirty page again
                 */
                if (err == -EAGAIN)
                        return 0;
 
                if (err == -ENOSPC &&
-                               ext4_count_free_blocks(mpd->inode->i_sb)) {
+                   ext4_count_free_blocks(mpd->inode->i_sb)) {
                        mpd->retval = err;
                        return 0;
                }
 
                /*
-                * get block failure will cause us
-                * to loop in writepages. Because
-                * a_ops->writepage won't be able to
-                * make progress. The page will be redirtied
-                * by writepage and writepages will again
-                * try to write the same.
+                * get block failure will cause us to loop in
+                * writepages, because a_ops->writepage won't be able
+                * to make progress. The page will be redirtied by
+                * writepage and writepages will again try to write
+                * the same.
                 */
                printk(KERN_EMERG "%s block allocation failed for inode %lu "
                                  "at logical offset %llu with max blocks "
                                  "%zd with error %d\n",
                                  __func__, mpd->inode->i_ino,
                                  (unsigned long long)next,
-                                 lbh->b_size >> mpd->inode->i_blkbits, err);
+                                 mpd->b_size >> mpd->inode->i_blkbits, err);
                printk(KERN_EMERG "This should not happen.!! "
                                        "Data will be lost\n");
                if (err == -ENOSPC) {
@@ -1983,7 +2089,7 @@ static int  mpage_da_map_blocks(struct mpage_da_data *mpd)
                }
                /* invlaidate all the pages */
                ext4_da_block_invalidatepages(mpd, next,
-                               lbh->b_size >> mpd->inode->i_blkbits);
+                               mpd->b_size >> mpd->inode->i_blkbits);
                return err;
        }
        BUG_ON(new.b_size == 0);
@@ -1995,7 +2101,8 @@ static int  mpage_da_map_blocks(struct mpage_da_data *mpd)
         * If blocks are delayed marked, we need to
         * put actual blocknr and drop delayed bit
         */
-       if (buffer_delay(lbh) || buffer_unwritten(lbh))
+       if ((mpd->b_state & (1 << BH_Delay)) ||
+           (mpd->b_state & (1 << BH_Unwritten)))
                mpage_put_bnr_to_bhs(mpd, next, &new);
 
        return 0;
@@ -2014,12 +2121,11 @@ static int  mpage_da_map_blocks(struct mpage_da_data *mpd)
  * the function is used to collect contig. blocks in same state
  */
 static void mpage_add_bh_to_extent(struct mpage_da_data *mpd,
-                                  sector_t logical, struct buffer_head *bh)
+                                  sector_t logical, size_t b_size,
+                                  unsigned long b_state)
 {
        sector_t next;
-       size_t b_size = bh->b_size;
-       struct buffer_head *lbh = &mpd->lbh;
-       int nrblocks = lbh->b_size >> mpd->inode->i_blkbits;
+       int nrblocks = mpd->b_size >> mpd->inode->i_blkbits;
 
        /* check if thereserved journal credits might overflow */
        if (!(EXT4_I(mpd->inode)->i_flags & EXT4_EXTENTS_FL)) {
@@ -2046,19 +2152,19 @@ static void mpage_add_bh_to_extent(struct mpage_da_data *mpd,
        /*
         * First block in the extent
         */
-       if (lbh->b_size == 0) {
-               lbh->b_blocknr = logical;
-               lbh->b_size = b_size;
-               lbh->b_state = bh->b_state & BH_FLAGS;
+       if (mpd->b_size == 0) {
+               mpd->b_blocknr = logical;
+               mpd->b_size = b_size;
+               mpd->b_state = b_state & BH_FLAGS;
                return;
        }
 
-       next = lbh->b_blocknr + nrblocks;
+       next = mpd->b_blocknr + nrblocks;
        /*
         * Can we merge the block to our big extent?
         */
-       if (logical == next && (bh->b_state & BH_FLAGS) == lbh->b_state) {
-               lbh->b_size += b_size;
+       if (logical == next && (b_state & BH_FLAGS) == mpd->b_state) {
+               mpd->b_size += b_size;
                return;
        }
 
@@ -2087,7 +2193,7 @@ static int __mpage_da_writepage(struct page *page,
 {
        struct mpage_da_data *mpd = data;
        struct inode *inode = mpd->inode;
-       struct buffer_head *bh, *head, fake;
+       struct buffer_head *bh, *head;
        sector_t logical;
 
        if (mpd->io_done) {
@@ -2129,9 +2235,9 @@ static int __mpage_da_writepage(struct page *page,
                /*
                 * ... and blocks
                 */
-               mpd->lbh.b_size = 0;
-               mpd->lbh.b_state = 0;
-               mpd->lbh.b_blocknr = 0;
+               mpd->b_size = 0;
+               mpd->b_state = 0;
+               mpd->b_blocknr = 0;
        }
 
        mpd->next_page = page->index + 1;
@@ -2139,16 +2245,8 @@ static int __mpage_da_writepage(struct page *page,
                  (PAGE_CACHE_SHIFT - inode->i_blkbits);
 
        if (!page_has_buffers(page)) {
-               /*
-                * There is no attached buffer heads yet (mmap?)
-                * we treat the page asfull of dirty blocks
-                */
-               bh = &fake;
-               bh->b_size = PAGE_CACHE_SIZE;
-               bh->b_state = 0;
-               set_buffer_dirty(bh);
-               set_buffer_uptodate(bh);
-               mpage_add_bh_to_extent(mpd, logical, bh);
+               mpage_add_bh_to_extent(mpd, logical, PAGE_CACHE_SIZE,
+                                      (1 << BH_Dirty) | (1 << BH_Uptodate));
                if (mpd->io_done)
                        return MPAGE_DA_EXTENT_TAIL;
        } else {
@@ -2166,8 +2264,10 @@ static int __mpage_da_writepage(struct page *page,
                         * with the page in ext4_da_writepage
                         */
                        if (buffer_dirty(bh) &&
-                               (!buffer_mapped(bh) || buffer_delay(bh))) {
-                               mpage_add_bh_to_extent(mpd, logical, bh);
+                           (!buffer_mapped(bh) || buffer_delay(bh))) {
+                               mpage_add_bh_to_extent(mpd, logical,
+                                                      bh->b_size,
+                                                      bh->b_state);
                                if (mpd->io_done)
                                        return MPAGE_DA_EXTENT_TAIL;
                        } else if (buffer_dirty(bh) && (buffer_mapped(bh))) {
@@ -2179,9 +2279,8 @@ static int __mpage_da_writepage(struct page *page,
                                 * unmapped buffer_head later we need to
                                 * use the b_state flag of that buffer_head.
                                 */
-                               if (mpd->lbh.b_size == 0)
-                                       mpd->lbh.b_state =
-                                               bh->b_state & BH_FLAGS;
+                               if (mpd->b_size == 0)
+                                       mpd->b_state = bh->b_state & BH_FLAGS;
                        }
                        logical++;
                } while ((bh = bh->b_this_page) != head);
@@ -2190,51 +2289,6 @@ static int __mpage_da_writepage(struct page *page,
        return 0;
 }
 
-/*
- * mpage_da_writepages - walk the list of dirty pages of the given
- * address space, allocates non-allocated blocks, maps newly-allocated
- * blocks to existing bhs and issue IO them
- *
- * @mapping: address space structure to write
- * @wbc: subtract the number of written pages from *@wbc->nr_to_write
- * @get_block: the filesystem's block mapper function.
- *
- * This is a library function, which implements the writepages()
- * address_space_operation.
- */
-static int mpage_da_writepages(struct address_space *mapping,
-                              struct writeback_control *wbc,
-                              struct mpage_da_data *mpd)
-{
-       int ret;
-
-       if (!mpd->get_block)
-               return generic_writepages(mapping, wbc);
-
-       mpd->lbh.b_size = 0;
-       mpd->lbh.b_state = 0;
-       mpd->lbh.b_blocknr = 0;
-       mpd->first_page = 0;
-       mpd->next_page = 0;
-       mpd->io_done = 0;
-       mpd->pages_written = 0;
-       mpd->retval = 0;
-
-       ret = write_cache_pages(mapping, wbc, __mpage_da_writepage, mpd);
-       /*
-        * Handle last extent of pages
-        */
-       if (!mpd->io_done && mpd->next_page != mpd->first_page) {
-               if (mpage_da_map_blocks(mpd) == 0)
-                       mpage_da_submit_io(mpd);
-
-               mpd->io_done = 1;
-               ret = MPAGE_DA_EXTENT_TAIL;
-       }
-       wbc->nr_to_write -= mpd->pages_written;
-       return ret;
-}
-
 /*
  * this is a special callback for ->write_begin() only
  * it's intention is to return mapped block or reserve space
@@ -2274,51 +2328,6 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
 
        return ret;
 }
-#define                EXT4_DELALLOC_RSVED     1
-static int ext4_da_get_block_write(struct inode *inode, sector_t iblock,
-                                  struct buffer_head *bh_result, int create)
-{
-       int ret;
-       unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
-       loff_t disksize = EXT4_I(inode)->i_disksize;
-       handle_t *handle = NULL;
-
-       handle = ext4_journal_current_handle();
-       BUG_ON(!handle);
-       ret = ext4_get_blocks_wrap(handle, inode, iblock, max_blocks,
-                       bh_result, create, 0, EXT4_DELALLOC_RSVED);
-       if (ret > 0) {
-
-               bh_result->b_size = (ret << inode->i_blkbits);
-
-               if (ext4_should_order_data(inode)) {
-                       int retval;
-                       retval = ext4_jbd2_file_inode(handle, inode);
-                       if (retval)
-                               /*
-                                * Failed to add inode for ordered
-                                * mode. Don't update file size
-                                */
-                               return retval;
-               }
-
-               /*
-                * Update on-disk size along with block allocation
-                * we don't use 'extend_disksize' as size may change
-                * within already allocated block -bzzz
-                */
-               disksize = ((loff_t) iblock + ret) << inode->i_blkbits;
-               if (disksize > i_size_read(inode))
-                       disksize = i_size_read(inode);
-               if (disksize > EXT4_I(inode)->i_disksize) {
-                       ext4_update_i_disksize(inode, disksize);
-                       ret = ext4_mark_inode_dirty(handle, inode);
-                       return ret;
-               }
-               ret = 0;
-       }
-       return ret;
-}
 
 static int ext4_bh_unmapped_or_delay(handle_t *handle, struct buffer_head *bh)
 {
@@ -2569,8 +2578,38 @@ retry:
                        dump_stack();
                        goto out_writepages;
                }
-               mpd.get_block = ext4_da_get_block_write;
-               ret = mpage_da_writepages(mapping, wbc, &mpd);
+
+               /*
+                * Now call __mpage_da_writepage to find the next
+                * contiguous region of logical blocks that need
+                * blocks to be allocated by ext4.  We don't actually
+                * submit the blocks for I/O here, even though
+                * write_cache_pages thinks it will, and will set the
+                * pages as clean for write before calling
+                * __mpage_da_writepage().
+                */
+               mpd.b_size = 0;
+               mpd.b_state = 0;
+               mpd.b_blocknr = 0;
+               mpd.first_page = 0;
+               mpd.next_page = 0;
+               mpd.io_done = 0;
+               mpd.pages_written = 0;
+               mpd.retval = 0;
+               ret = write_cache_pages(mapping, wbc, __mpage_da_writepage,
+                                       &mpd);
+               /*
+                * If we have a contigous extent of pages and we
+                * haven't done the I/O yet, map the blocks and submit
+                * them for I/O.
+                */
+               if (!mpd.io_done && mpd.next_page != mpd.first_page) {
+                       if (mpage_da_map_blocks(&mpd) == 0)
+                               mpage_da_submit_io(&mpd);
+                       mpd.io_done = 1;
+                       ret = MPAGE_DA_EXTENT_TAIL;
+               }
+               wbc->nr_to_write -= mpd.pages_written;
 
                ext4_journal_stop(handle);
 
@@ -2846,6 +2885,48 @@ out:
        return;
 }
 
+/*
+ * Force all delayed allocation blocks to be allocated for a given inode.
+ */
+int ext4_alloc_da_blocks(struct inode *inode)
+{
+       if (!EXT4_I(inode)->i_reserved_data_blocks &&
+           !EXT4_I(inode)->i_reserved_meta_blocks)
+               return 0;
+
+       /*
+        * We do something simple for now.  The filemap_flush() will
+        * also start triggering a write of the data blocks, which is
+        * not strictly speaking necessary (and for users of
+        * laptop_mode, not even desirable).  However, to do otherwise
+        * would require replicating code paths in:
+        * 
+        * ext4_da_writepages() ->
+        *    write_cache_pages() ---> (via passed in callback function)
+        *        __mpage_da_writepage() -->
+        *           mpage_add_bh_to_extent()
+        *           mpage_da_map_blocks()
+        *
+        * The problem is that write_cache_pages(), located in
+        * mm/page-writeback.c, marks pages clean in preparation for
+        * doing I/O, which is not desirable if we're not planning on
+        * doing I/O at all.
+        *
+        * We could call write_cache_pages(), and then redirty all of
+        * the pages by calling redirty_page_for_writeback() but that
+        * would be ugly in the extreme.  So instead we would need to
+        * replicate parts of the code in the above functions,
+        * simplifying them becuase we wouldn't actually intend to
+        * write out the pages, but rather only collect contiguous
+        * logical block extents, call the multi-block allocator, and
+        * then update the buffer heads with the block allocations.
+        * 
+        * For now, though, we'll cheat by calling filemap_flush(),
+        * which will map the blocks, and start the I/O, but not
+        * actually wait for the I/O to complete.
+        */
+       return filemap_flush(inode->i_mapping);
+}
 
 /*
  * bmap() is special.  It gets used by applications such as lilo and by
@@ -3868,6 +3949,9 @@ void ext4_truncate(struct inode *inode)
        if (!ext4_can_truncate(inode))
                return;
 
+       if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC))
+               ei->i_state |= EXT4_STATE_DA_ALLOC_CLOSE;
+
        if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) {
                ext4_ext_truncate(inode);
                return;
@@ -4110,12 +4194,7 @@ make_io:
                        unsigned num;
 
                        table = ext4_inode_table(sb, gdp);
-                       /* Make sure s_inode_readahead_blks is a power of 2 */
-                       while (EXT4_SB(sb)->s_inode_readahead_blks &
-                              (EXT4_SB(sb)->s_inode_readahead_blks-1))
-                               EXT4_SB(sb)->s_inode_readahead_blks = 
-                                  (EXT4_SB(sb)->s_inode_readahead_blks &
-                                   (EXT4_SB(sb)->s_inode_readahead_blks-1));
+                       /* s_inode_readahead_blks is always a power of 2 */
                        b = block & ~(EXT4_SB(sb)->s_inode_readahead_blks-1);
                        if (table > b)
                                b = table;
@@ -4287,6 +4366,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
        ei->i_disksize = inode->i_size;
        inode->i_generation = le32_to_cpu(raw_inode->i_generation);
        ei->i_block_group = iloc.block_group;
+       ei->i_last_alloc_group = ~0;
        /*
         * NOTE! The in-memory inode i_data array is in little-endian order
         * even on big-endian machines: we do NOT byteswap the block numbers!
@@ -4329,6 +4409,20 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                        (__u64)(le32_to_cpu(raw_inode->i_version_hi)) << 32;
        }
 
+       if (ei->i_flags & EXT4_EXTENTS_FL) {
+               /* Validate extent which is part of inode */
+               ret = ext4_ext_check_inode(inode);
+       } else if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+                  (S_ISLNK(inode->i_mode) &&
+                   !ext4_inode_is_fast_symlink(inode))) {
+               /* Validate block references which are part of inode */
+               ret = ext4_check_inode_blockref(inode);
+       }
+       if (ret) {
+               brelse(bh);
+               goto bad_inode;
+       }
+
        if (S_ISREG(inode->i_mode)) {
                inode->i_op = &ext4_file_inode_operations;
                inode->i_fop = &ext4_file_operations;
@@ -4345,7 +4439,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                        inode->i_op = &ext4_symlink_inode_operations;
                        ext4_set_aops(inode);
                }
-       } else {
+       } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
+             S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
                inode->i_op = &ext4_special_inode_operations;
                if (raw_inode->i_block[0])
                        init_special_inode(inode, inode->i_mode,
@@ -4353,6 +4448,13 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                else
                        init_special_inode(inode, inode->i_mode,
                           new_decode_dev(le32_to_cpu(raw_inode->i_block[1])));
+       } else {
+               brelse(bh);
+               ret = -EIO;
+               ext4_error(inode->i_sb, __func__, 
+                          "bogus i_mode (%o) for inode=%lu",
+                          inode->i_mode, inode->i_ino);
+               goto bad_inode;
        }
        brelse(iloc.bh);
        ext4_set_inode_flags(inode);
@@ -5146,8 +5248,9 @@ static int ext4_bh_unmapped(handle_t *handle, struct buffer_head *bh)
        return !buffer_mapped(bh);
 }
 
-int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
+       struct page *page = vmf->page;
        loff_t size;
        unsigned long len;
        int ret = -EINVAL;
@@ -5199,6 +5302,8 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page)
                goto out_unlock;
        ret = 0;
 out_unlock:
+       if (ret)
+               ret = VM_FAULT_SIGBUS;
        up_read(&inode->i_alloc_sem);
        return ret;
 }
index 42dc83fb247a98f6dd4450314bf2f96d4e36c175..91e75f7a9e732c4ba6cdf909cfd3607f32dbd800 100644 (file)
@@ -48,8 +48,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                if (err)
                        return err;
 
-               if (!S_ISDIR(inode->i_mode))
-                       flags &= ~EXT4_DIRSYNC_FL;
+               flags = ext4_mask_flags(inode->i_mode, flags);
 
                err = -EPERM;
                mutex_lock(&inode->i_mutex);
@@ -263,6 +262,20 @@ setversion_out:
                return err;
        }
 
+       case EXT4_IOC_ALLOC_DA_BLKS:
+       {
+               int err;
+               if (!is_owner_or_cap(inode))
+                       return -EACCES;
+
+               err = mnt_want_write(filp->f_path.mnt);
+               if (err)
+                       return err;
+               err = ext4_alloc_da_blocks(inode);
+               mnt_drop_write(filp->f_path.mnt);
+               return err;
+       }
+
        default:
                return -ENOTTY;
        }
index b038188bd039e8f8c2762c13318c078fd353b17a..f871677a798499c4327629cf282d4f75b38d44b3 100644 (file)
  * The allocation request involve request for multiple number of blocks
  * near to the goal(block) value specified.
  *
- * During initialization phase of the allocator we decide to use the group
- * preallocation or inode preallocation depending on the size file. The
- * size of the file could be the resulting file size we would have after
- * allocation or the current file size which ever is larger. If the size is
- * less that sbi->s_mb_stream_request we select the group
- * preallocation. The default value of s_mb_stream_request is 16
- * blocks. This can also be tuned via
- * /proc/fs/ext4/<partition>/stream_req. The value is represented in terms
- * of number of blocks.
+ * During initialization phase of the allocator we decide to use the
+ * group preallocation or inode preallocation depending on the size of
+ * the file. The size of the file could be the resulting file size we
+ * would have after allocation, or the current file size, which ever
+ * is larger. If the size is less than sbi->s_mb_stream_request we
+ * select to use the group preallocation. The default value of
+ * s_mb_stream_request is 16 blocks. This can also be tuned via
+ * /sys/fs/ext4/<partition>/mb_stream_req. The value is represented in
+ * terms of number of blocks.
  *
  * The main motivation for having small file use group preallocation is to
- * ensure that we have small file closer in the disk.
+ * ensure that we have small files closer together on the disk.
  *
- * First stage the allocator looks at the inode prealloc list
- * ext4_inode_info->i_prealloc_list contain list of prealloc spaces for
- * this particular inode. The inode prealloc space is represented as:
+ * First stage the allocator looks at the inode prealloc list,
+ * ext4_inode_info->i_prealloc_list, which contains list of prealloc
+ * spaces for this particular inode. The inode prealloc space is
+ * represented as:
  *
  * pa_lstart -> the logical start block for this prealloc space
  * pa_pstart -> the physical start block for this prealloc space
  * list. In case of inode preallocation we follow a list of heuristics
  * based on file size. This can be found in ext4_mb_normalize_request. If
  * we are doing a group prealloc we try to normalize the request to
- * sbi->s_mb_group_prealloc. Default value of s_mb_group_prealloc is set to
+ * sbi->s_mb_group_prealloc. Default value of s_mb_group_prealloc is
  * 512 blocks. This can be tuned via
- * /proc/fs/ext4/<partition/group_prealloc. The value is represented in
+ * /sys/fs/ext4/<partition/mb_group_prealloc. The value is represented in
  * terms of number of blocks. If we have mounted the file system with -O
  * stripe=<value> option the group prealloc request is normalized to the
  * stripe value (sbi->s_stripe)
  *
- * The regular allocator(using the buddy cache) support few tunables.
+ * The regular allocator(using the buddy cache) supports few tunables.
  *
- * /proc/fs/ext4/<partition>/min_to_scan
- * /proc/fs/ext4/<partition>/max_to_scan
- * /proc/fs/ext4/<partition>/order2_req
+ * /sys/fs/ext4/<partition>/mb_min_to_scan
+ * /sys/fs/ext4/<partition>/mb_max_to_scan
+ * /sys/fs/ext4/<partition>/mb_order2_req
  *
- * The regular allocator use buddy scan only if the request len is power of
+ * The regular allocator uses buddy scan only if the request len is power of
  * 2 blocks and the order of allocation is >= sbi->s_mb_order2_reqs. The
  * value of s_mb_order2_reqs can be tuned via
- * /proc/fs/ext4/<partition>/order2_req.  If the request len is equal to
+ * /sys/fs/ext4/<partition>/mb_order2_req.  If the request len is equal to
  * stripe size (sbi->s_stripe), we try to search for contigous block in
- * stripe size. This should result in better allocation on RAID setup. If
- * not we search in the specific group using bitmap for best extents. The
- * tunable min_to_scan and max_to_scan controll the behaviour here.
+ * stripe size. This should result in better allocation on RAID setups. If
+ * not, we search in the specific group using bitmap for best extents. The
+ * tunable min_to_scan and max_to_scan control the behaviour here.
  * min_to_scan indicate how long the mballoc __must__ look for a best
- * extent and max_to_scanindicate how long the mballoc __can__ look for a
+ * extent and max_to_scan indicates how long the mballoc __can__ look for a
  * best extent in the found extents. Searching for the blocks starts with
  * the group specified as the goal value in allocation context via
  * ac_g_ex. Each group is first checked based on the criteria whether it
@@ -337,8 +338,6 @@ static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
                                        ext4_group_t group);
 static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
                                                ext4_group_t group);
-static int ext4_mb_init_per_dev_proc(struct super_block *sb);
-static int ext4_mb_destroy_per_dev_proc(struct super_block *sb);
 static void release_blocks_on_commit(journal_t *journal, transaction_t *txn);
 
 
@@ -1726,6 +1725,7 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac,
 {
        unsigned free, fragments;
        unsigned i, bits;
+       int flex_size = ext4_flex_bg_size(EXT4_SB(ac->ac_sb));
        struct ext4_group_desc *desc;
        struct ext4_group_info *grp = ext4_get_group_info(ac->ac_sb, group);
 
@@ -1747,6 +1747,12 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac,
                if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))
                        return 0;
 
+               /* Avoid using the first bg of a flexgroup for data files */
+               if ((ac->ac_flags & EXT4_MB_HINT_DATA) &&
+                   (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) &&
+                   ((group % flex_size) == 0))
+                       return 0;
+
                bits = ac->ac_sb->s_blocksize_bits + 1;
                for (i = ac->ac_2order; i <= bits; i++)
                        if (grp->bb_counters[i] > 0)
@@ -1971,7 +1977,7 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
        /*
         * We search using buddy data only if the order of the request
         * is greater than equal to the sbi_s_mb_order2_reqs
-        * You can tune it via /proc/fs/ext4/<partition>/order2_req
+        * You can tune it via /sys/fs/ext4/<partition>/mb_order2_req
         */
        if (i >= sbi->s_mb_order2_reqs) {
                /*
@@ -2693,7 +2699,7 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
        i = (sb->s_blocksize_bits + 2) * sizeof(unsigned int);
        sbi->s_mb_maxs = kmalloc(i, GFP_KERNEL);
        if (sbi->s_mb_maxs == NULL) {
-               kfree(sbi->s_mb_maxs);
+               kfree(sbi->s_mb_offsets);
                return -ENOMEM;
        }
 
@@ -2746,7 +2752,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
                spin_lock_init(&lg->lg_prealloc_lock);
        }
 
-       ext4_mb_init_per_dev_proc(sb);
        ext4_mb_history_init(sb);
 
        if (sbi->s_journal)
@@ -2829,7 +2834,6 @@ int ext4_mb_release(struct super_block *sb)
 
        free_percpu(sbi->s_locality_groups);
        ext4_mb_history_release(sb);
-       ext4_mb_destroy_per_dev_proc(sb);
 
        return 0;
 }
@@ -2890,62 +2894,6 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
        mb_debug("freed %u blocks in %u structures\n", count, count2);
 }
 
-#define EXT4_MB_STATS_NAME             "stats"
-#define EXT4_MB_MAX_TO_SCAN_NAME       "max_to_scan"
-#define EXT4_MB_MIN_TO_SCAN_NAME       "min_to_scan"
-#define EXT4_MB_ORDER2_REQ             "order2_req"
-#define EXT4_MB_STREAM_REQ             "stream_req"
-#define EXT4_MB_GROUP_PREALLOC         "group_prealloc"
-
-static int ext4_mb_init_per_dev_proc(struct super_block *sb)
-{
-#ifdef CONFIG_PROC_FS
-       mode_t mode = S_IFREG | S_IRUGO | S_IWUSR;
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-       struct proc_dir_entry *proc;
-
-       if (sbi->s_proc == NULL)
-               return -EINVAL;
-
-       EXT4_PROC_HANDLER(EXT4_MB_STATS_NAME, mb_stats);
-       EXT4_PROC_HANDLER(EXT4_MB_MAX_TO_SCAN_NAME, mb_max_to_scan);
-       EXT4_PROC_HANDLER(EXT4_MB_MIN_TO_SCAN_NAME, mb_min_to_scan);
-       EXT4_PROC_HANDLER(EXT4_MB_ORDER2_REQ, mb_order2_reqs);
-       EXT4_PROC_HANDLER(EXT4_MB_STREAM_REQ, mb_stream_request);
-       EXT4_PROC_HANDLER(EXT4_MB_GROUP_PREALLOC, mb_group_prealloc);
-       return 0;
-
-err_out:
-       remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_proc);
-       return -ENOMEM;
-#else
-       return 0;
-#endif
-}
-
-static int ext4_mb_destroy_per_dev_proc(struct super_block *sb)
-{
-#ifdef CONFIG_PROC_FS
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-
-       if (sbi->s_proc == NULL)
-               return -EINVAL;
-
-       remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_proc);
-#endif
-       return 0;
-}
-
 int __init init_ext4_mballoc(void)
 {
        ext4_pspace_cachep =
@@ -3096,9 +3044,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
        if (sbi->s_log_groups_per_flex) {
                ext4_group_t flex_group = ext4_flex_group(sbi,
                                                          ac->ac_b_ex.fe_group);
-               spin_lock(sb_bgl_lock(sbi, flex_group));
-               sbi->s_flex_groups[flex_group].free_blocks -= ac->ac_b_ex.fe_len;
-               spin_unlock(sb_bgl_lock(sbi, flex_group));
+               atomic_sub(ac->ac_b_ex.fe_len,
+                          &sbi->s_flex_groups[flex_group].free_blocks);
        }
 
        err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
@@ -3116,7 +3063,7 @@ out_err:
  * here we normalize request for locality group
  * Group request are normalized to s_strip size if we set the same via mount
  * option. If not we set it to s_mb_group_prealloc which can be configured via
- * /proc/fs/ext4/<partition>/group_prealloc
+ * /sys/fs/ext4/<partition>/mb_group_prealloc
  *
  * XXX: should we try to preallocate more than the group has now?
  */
@@ -3608,8 +3555,11 @@ static void ext4_mb_put_pa(struct ext4_allocation_context *ac,
        spin_unlock(&pa->pa_lock);
 
        grp_blk = pa->pa_pstart;
-       /* If linear, pa_pstart may be in the next group when pa is used up */
-       if (pa->pa_linear)
+       /* 
+        * If doing group-based preallocation, pa_pstart may be in the
+        * next group when pa is used up
+        */
+       if (pa->pa_type == MB_GROUP_PA)
                grp_blk--;
 
        ext4_get_group_no_and_offset(sb, grp_blk, &grp, NULL);
@@ -3704,7 +3654,7 @@ ext4_mb_new_inode_pa(struct ext4_allocation_context *ac)
        INIT_LIST_HEAD(&pa->pa_inode_list);
        INIT_LIST_HEAD(&pa->pa_group_list);
        pa->pa_deleted = 0;
-       pa->pa_linear = 0;
+       pa->pa_type = MB_INODE_PA;
 
        mb_debug("new inode pa %p: %llu/%u for %u\n", pa,
                        pa->pa_pstart, pa->pa_len, pa->pa_lstart);
@@ -3767,7 +3717,7 @@ ext4_mb_new_group_pa(struct ext4_allocation_context *ac)
        INIT_LIST_HEAD(&pa->pa_inode_list);
        INIT_LIST_HEAD(&pa->pa_group_list);
        pa->pa_deleted = 0;
-       pa->pa_linear = 1;
+       pa->pa_type = MB_GROUP_PA;
 
        mb_debug("new group pa %p: %llu/%u for %u\n", pa,
                 pa->pa_pstart, pa->pa_len, pa->pa_lstart);
@@ -4021,7 +3971,7 @@ repeat:
                list_del_rcu(&pa->pa_inode_list);
                spin_unlock(pa->pa_obj_lock);
 
-               if (pa->pa_linear)
+               if (pa->pa_type == MB_GROUP_PA)
                        ext4_mb_release_group_pa(&e4b, pa, ac);
                else
                        ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa, ac);
@@ -4121,7 +4071,7 @@ repeat:
        spin_unlock(&ei->i_prealloc_lock);
 
        list_for_each_entry_safe(pa, tmp, &list, u.pa_tmp_list) {
-               BUG_ON(pa->pa_linear != 0);
+               BUG_ON(pa->pa_type != MB_INODE_PA);
                ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL);
 
                err = ext4_mb_load_buddy(sb, group, &e4b);
@@ -4232,7 +4182,7 @@ static inline void ext4_mb_show_ac(struct ext4_allocation_context *ac)
  * file is determined by the current size or the resulting size after
  * allocation which ever is larger
  *
- * One can tune this size via /proc/fs/ext4/<partition>/stream_req
+ * One can tune this size via /sys/fs/ext4/<partition>/mb_stream_req
  */
 static void ext4_mb_group_or_file(struct ext4_allocation_context *ac)
 {
@@ -4373,7 +4323,7 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
                        continue;
                }
                /* only lg prealloc space */
-               BUG_ON(!pa->pa_linear);
+               BUG_ON(pa->pa_type != MB_GROUP_PA);
 
                /* seems this one can be freed ... */
                pa->pa_deleted = 1;
@@ -4442,7 +4392,7 @@ static void ext4_mb_add_n_trim(struct ext4_allocation_context *ac)
                                                pa_inode_list) {
                spin_lock(&tmp_pa->pa_lock);
                if (tmp_pa->pa_deleted) {
-                       spin_unlock(&pa->pa_lock);
+                       spin_unlock(&tmp_pa->pa_lock);
                        continue;
                }
                if (!added && pa->pa_free < tmp_pa->pa_free) {
@@ -4479,7 +4429,7 @@ static int ext4_mb_release_context(struct ext4_allocation_context *ac)
 {
        struct ext4_prealloc_space *pa = ac->ac_pa;
        if (pa) {
-               if (pa->pa_linear) {
+               if (pa->pa_type == MB_GROUP_PA) {
                        /* see comment in ext4_mb_use_group_pa() */
                        spin_lock(&pa->pa_lock);
                        pa->pa_pstart += ac->ac_b_ex.fe_len;
@@ -4499,7 +4449,7 @@ static int ext4_mb_release_context(struct ext4_allocation_context *ac)
                 * doesn't grow big.  We need to release
                 * alloc_semp before calling ext4_mb_add_n_trim()
                 */
-               if (pa->pa_linear && likely(pa->pa_free)) {
+               if ((pa->pa_type == MB_GROUP_PA) && likely(pa->pa_free)) {
                        spin_lock(pa->pa_obj_lock);
                        list_del_rcu(&pa->pa_inode_list);
                        spin_unlock(pa->pa_obj_lock);
@@ -4936,9 +4886,7 @@ do_more:
 
        if (sbi->s_log_groups_per_flex) {
                ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
-               spin_lock(sb_bgl_lock(sbi, flex_group));
-               sbi->s_flex_groups[flex_group].free_blocks += count;
-               spin_unlock(sb_bgl_lock(sbi, flex_group));
+               atomic_add(count, &sbi->s_flex_groups[flex_group].free_blocks);
        }
 
        ext4_mb_release_desc(&e4b);
index 10a2921baf14c986c809a8746fb4b90d3a7f8fbe..dd9e6cd5f6cf4dc97ae6c97b4c6c5c9d5bee9e4d 100644 (file)
@@ -132,12 +132,15 @@ struct ext4_prealloc_space {
        ext4_lblk_t             pa_lstart;      /* log. block */
        unsigned short          pa_len;         /* len of preallocated chunk */
        unsigned short          pa_free;        /* how many blocks are free */
-       unsigned short          pa_linear;      /* consumed in one direction
-                                                * strictly, for grp prealloc */
+       unsigned short          pa_type;        /* pa type. inode or group */
        spinlock_t              *pa_obj_lock;
        struct inode            *pa_inode;      /* hack, for history only */
 };
 
+enum {
+       MB_INODE_PA = 0,
+       MB_GROUP_PA = 1
+};
 
 struct ext4_free_extent {
        ext4_lblk_t fe_logical;
@@ -247,7 +250,6 @@ static inline void ext4_mb_store_history(struct ext4_allocation_context *ac)
 
 #define in_range(b, first, len)        ((b) >= (first) && (b) <= (first) + (len) - 1)
 
-struct buffer_head *read_block_bitmap(struct super_block *, ext4_group_t);
 static inline ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb,
                                        struct ext4_free_extent *fex)
 {
index 83410244d3ee11f483db465373665c9843df91cc..22098e1cd085911a7aeffc975ac7a0773a32bbc0 100644 (file)
@@ -161,12 +161,12 @@ static struct dx_frame *dx_probe(const struct qstr *d_name,
                                 struct dx_frame *frame,
                                 int *err);
 static void dx_release(struct dx_frame *frames);
-static int dx_make_map(struct ext4_dir_entry_2 *de, int size,
+static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize,
                       struct dx_hash_info *hinfo, struct dx_map_entry map[]);
 static void dx_sort_map(struct dx_map_entry *map, unsigned count);
 static struct ext4_dir_entry_2 *dx_move_dirents(char *from, char *to,
-               struct dx_map_entry *offsets, int count);
-static struct ext4_dir_entry_2* dx_pack_dirents(char *base, int size);
+               struct dx_map_entry *offsets, int count, unsigned blocksize);
+static struct ext4_dir_entry_2* dx_pack_dirents(char *base, unsigned blocksize);
 static void dx_insert_block(struct dx_frame *frame,
                                        u32 hash, ext4_lblk_t block);
 static int ext4_htree_next_block(struct inode *dir, __u32 hash,
@@ -180,14 +180,38 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir,
 static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
                             struct inode *inode);
 
+unsigned int ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize)
+{
+       unsigned len = le16_to_cpu(dlen);
+
+       if (len == EXT4_MAX_REC_LEN || len == 0)
+               return blocksize;
+       return (len & 65532) | ((len & 3) << 16);
+}
+  
+__le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize)
+{
+       if ((len > blocksize) || (blocksize > (1 << 18)) || (len & 3))
+               BUG();
+       if (len < 65536)
+               return cpu_to_le16(len);
+       if (len == blocksize) {
+               if (blocksize == 65536)
+                       return cpu_to_le16(EXT4_MAX_REC_LEN);
+               else 
+                       return cpu_to_le16(0);
+       }
+       return cpu_to_le16((len & 65532) | ((len >> 16) & 3));
+}
+
 /*
  * p is at least 6 bytes before the end of page
  */
 static inline struct ext4_dir_entry_2 *
-ext4_next_entry(struct ext4_dir_entry_2 *p)
+ext4_next_entry(struct ext4_dir_entry_2 *p, unsigned long blocksize)
 {
        return (struct ext4_dir_entry_2 *)((char *)p +
-               ext4_rec_len_from_disk(p->rec_len));
+               ext4_rec_len_from_disk(p->rec_len, blocksize));
 }
 
 /*
@@ -294,7 +318,7 @@ static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext4_dir_ent
                        space += EXT4_DIR_REC_LEN(de->name_len);
                        names++;
                }
-               de = ext4_next_entry(de);
+               de = ext4_next_entry(de, size);
        }
        printk("(%i)\n", names);
        return (struct stats) { names, space, 1 };
@@ -585,7 +609,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
        top = (struct ext4_dir_entry_2 *) ((char *) de +
                                           dir->i_sb->s_blocksize -
                                           EXT4_DIR_REC_LEN(0));
-       for (; de < top; de = ext4_next_entry(de)) {
+       for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) {
                if (!ext4_check_dir_entry("htree_dirblock_to_tree", dir, de, bh,
                                        (block<<EXT4_BLOCK_SIZE_BITS(dir->i_sb))
                                                +((char *)de - bh->b_data))) {
@@ -663,7 +687,7 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
        }
        if (start_hash < 2 || (start_hash ==2 && start_minor_hash==0)) {
                de = (struct ext4_dir_entry_2 *) frames[0].bh->b_data;
-               de = ext4_next_entry(de);
+               de = ext4_next_entry(de, dir->i_sb->s_blocksize);
                if ((err = ext4_htree_store_dirent(dir_file, 2, 0, de)) != 0)
                        goto errout;
                count++;
@@ -713,15 +737,15 @@ errout:
  * Create map of hash values, offsets, and sizes, stored at end of block.
  * Returns number of entries mapped.
  */
-static int dx_make_map (struct ext4_dir_entry_2 *de, int size,
-                       struct dx_hash_info *hinfo, struct dx_map_entry *map_tail)
+static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize,
+                      struct dx_hash_info *hinfo,
+                      struct dx_map_entry *map_tail)
 {
        int count = 0;
        char *base = (char *) de;
        struct dx_hash_info h = *hinfo;
 
-       while ((char *) de < base + size)
-       {
+       while ((char *) de < base + blocksize) {
                if (de->name_len && de->inode) {
                        ext4fs_dirhash(de->name, de->name_len, &h);
                        map_tail--;
@@ -732,7 +756,7 @@ static int dx_make_map (struct ext4_dir_entry_2 *de, int size,
                        cond_resched();
                }
                /* XXX: do we need to check rec_len == 0 case? -Chris */
-               de = ext4_next_entry(de);
+               de = ext4_next_entry(de, blocksize);
        }
        return count;
 }
@@ -832,7 +856,8 @@ static inline int search_dirblock(struct buffer_head *bh,
                        return 1;
                }
                /* prevent looping on a bad block */
-               de_len = ext4_rec_len_from_disk(de->rec_len);
+               de_len = ext4_rec_len_from_disk(de->rec_len,
+                                               dir->i_sb->s_blocksize);
                if (de_len <= 0)
                        return -1;
                offset += de_len;
@@ -996,7 +1021,7 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q
                de = (struct ext4_dir_entry_2 *) bh->b_data;
                top = (struct ext4_dir_entry_2 *) ((char *) de + sb->s_blocksize -
                                       EXT4_DIR_REC_LEN(0));
-               for (; de < top; de = ext4_next_entry(de)) {
+               for (; de < top; de = ext4_next_entry(de, sb->s_blocksize)) {
                        int off = (block << EXT4_BLOCK_SIZE_BITS(sb))
                                  + ((char *) de - bh->b_data);
 
@@ -1052,8 +1077,16 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, stru
                        return ERR_PTR(-EIO);
                }
                inode = ext4_iget(dir->i_sb, ino);
-               if (IS_ERR(inode))
-                       return ERR_CAST(inode);
+               if (unlikely(IS_ERR(inode))) {
+                       if (PTR_ERR(inode) == -ESTALE) {
+                               ext4_error(dir->i_sb, __func__,
+                                               "deleted inode referenced: %u",
+                                               ino);
+                               return ERR_PTR(-EIO);
+                       } else {
+                               return ERR_CAST(inode);
+                       }
+               }
        }
        return d_splice_alias(inode, dentry);
 }
@@ -1109,7 +1142,8 @@ static inline void ext4_set_de_type(struct super_block *sb,
  * Returns pointer to last entry moved.
  */
 static struct ext4_dir_entry_2 *
-dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
+dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count,
+               unsigned blocksize)
 {
        unsigned rec_len = 0;
 
@@ -1118,7 +1152,7 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
                rec_len = EXT4_DIR_REC_LEN(de->name_len);
                memcpy (to, de, rec_len);
                ((struct ext4_dir_entry_2 *) to)->rec_len =
-                               ext4_rec_len_to_disk(rec_len);
+                               ext4_rec_len_to_disk(rec_len, blocksize);
                de->inode = 0;
                map++;
                to += rec_len;
@@ -1130,19 +1164,19 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
  * Compact each dir entry in the range to the minimal rec_len.
  * Returns pointer to last entry in range.
  */
-static struct ext4_dir_entry_2* dx_pack_dirents(char *base, int size)
+static struct ext4_dir_entry_2* dx_pack_dirents(char *base, unsigned blocksize)
 {
        struct ext4_dir_entry_2 *next, *to, *prev, *de = (struct ext4_dir_entry_2 *) base;
        unsigned rec_len = 0;
 
        prev = to = de;
-       while ((char*)de < base + size) {
-               next = ext4_next_entry(de);
+       while ((char*)de < base + blocksize) {
+               next = ext4_next_entry(de, blocksize);
                if (de->inode && de->name_len) {
                        rec_len = EXT4_DIR_REC_LEN(de->name_len);
                        if (de > to)
                                memmove(to, de, rec_len);
-                       to->rec_len = ext4_rec_len_to_disk(rec_len);
+                       to->rec_len = ext4_rec_len_to_disk(rec_len, blocksize);
                        prev = to;
                        to = (struct ext4_dir_entry_2 *) (((char *) to) + rec_len);
                }
@@ -1215,10 +1249,12 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
                                        hash2, split, count-split));
 
        /* Fancy dance to stay within two buffers */
-       de2 = dx_move_dirents(data1, data2, map + split, count - split);
+       de2 = dx_move_dirents(data1, data2, map + split, count - split, blocksize);
        de = dx_pack_dirents(data1, blocksize);
-       de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de);
-       de2->rec_len = ext4_rec_len_to_disk(data2 + blocksize - (char *) de2);
+       de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de,
+                                          blocksize);
+       de2->rec_len = ext4_rec_len_to_disk(data2 + blocksize - (char *) de2,
+                                           blocksize);
        dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data1, blocksize, 1));
        dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data2, blocksize, 1));
 
@@ -1268,6 +1304,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
        const char      *name = dentry->d_name.name;
        int             namelen = dentry->d_name.len;
        unsigned int    offset = 0;
+       unsigned int    blocksize = dir->i_sb->s_blocksize;
        unsigned short  reclen;
        int             nlen, rlen, err;
        char            *top;
@@ -1275,7 +1312,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
        reclen = EXT4_DIR_REC_LEN(namelen);
        if (!de) {
                de = (struct ext4_dir_entry_2 *)bh->b_data;
-               top = bh->b_data + dir->i_sb->s_blocksize - reclen;
+               top = bh->b_data + blocksize - reclen;
                while ((char *) de <= top) {
                        if (!ext4_check_dir_entry("ext4_add_entry", dir, de,
                                                  bh, offset)) {
@@ -1287,7 +1324,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
                                return -EEXIST;
                        }
                        nlen = EXT4_DIR_REC_LEN(de->name_len);
-                       rlen = ext4_rec_len_from_disk(de->rec_len);
+                       rlen = ext4_rec_len_from_disk(de->rec_len, blocksize);
                        if ((de->inode? rlen - nlen: rlen) >= reclen)
                                break;
                        de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
@@ -1306,11 +1343,11 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
 
        /* By now the buffer is marked for journaling */
        nlen = EXT4_DIR_REC_LEN(de->name_len);
-       rlen = ext4_rec_len_from_disk(de->rec_len);
+       rlen = ext4_rec_len_from_disk(de->rec_len, blocksize);
        if (de->inode) {
                struct ext4_dir_entry_2 *de1 = (struct ext4_dir_entry_2 *)((char *)de + nlen);
-               de1->rec_len = ext4_rec_len_to_disk(rlen - nlen);
-               de->rec_len = ext4_rec_len_to_disk(nlen);
+               de1->rec_len = ext4_rec_len_to_disk(rlen - nlen, blocksize);
+               de->rec_len = ext4_rec_len_to_disk(nlen, blocksize);
                de = de1;
        }
        de->file_type = EXT4_FT_UNKNOWN;
@@ -1380,7 +1417,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
        /* The 0th block becomes the root, move the dirents out */
        fde = &root->dotdot;
        de = (struct ext4_dir_entry_2 *)((char *)fde +
-               ext4_rec_len_from_disk(fde->rec_len));
+               ext4_rec_len_from_disk(fde->rec_len, blocksize));
        if ((char *) de >= (((char *) root) + blocksize)) {
                ext4_error(dir->i_sb, __func__,
                           "invalid rec_len for '..' in inode %lu",
@@ -1402,12 +1439,14 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
        memcpy (data1, de, len);
        de = (struct ext4_dir_entry_2 *) data1;
        top = data1 + len;
-       while ((char *)(de2 = ext4_next_entry(de)) < top)
+       while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top)
                de = de2;
-       de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de);
+       de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de,
+                                          blocksize);
        /* Initialize the root; the dot dirents already exist */
        de = (struct ext4_dir_entry_2 *) (&root->dotdot);
-       de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(2));
+       de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(2),
+                                          blocksize);
        memset (&root->info, 0, sizeof(root->info));
        root->info.info_length = sizeof(root->info);
        root->info.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
@@ -1488,7 +1527,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
                return retval;
        de = (struct ext4_dir_entry_2 *) bh->b_data;
        de->inode = 0;
-       de->rec_len = ext4_rec_len_to_disk(blocksize);
+       de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize);
        return add_dirent_to_buf(handle, dentry, inode, de, bh);
 }
 
@@ -1551,7 +1590,8 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
                        goto cleanup;
                node2 = (struct dx_node *)(bh2->b_data);
                entries2 = node2->entries;
-               node2->fake.rec_len = ext4_rec_len_to_disk(sb->s_blocksize);
+               node2->fake.rec_len = ext4_rec_len_to_disk(sb->s_blocksize,
+                                                          sb->s_blocksize);
                node2->fake.inode = 0;
                BUFFER_TRACE(frame->bh, "get_write_access");
                err = ext4_journal_get_write_access(handle, frame->bh);
@@ -1639,6 +1679,7 @@ static int ext4_delete_entry(handle_t *handle,
                             struct buffer_head *bh)
 {
        struct ext4_dir_entry_2 *de, *pde;
+       unsigned int blocksize = dir->i_sb->s_blocksize;
        int i;
 
        i = 0;
@@ -1652,8 +1693,11 @@ static int ext4_delete_entry(handle_t *handle,
                        ext4_journal_get_write_access(handle, bh);
                        if (pde)
                                pde->rec_len = ext4_rec_len_to_disk(
-                                       ext4_rec_len_from_disk(pde->rec_len) +
-                                       ext4_rec_len_from_disk(de->rec_len));
+                                       ext4_rec_len_from_disk(pde->rec_len,
+                                                              blocksize) +
+                                       ext4_rec_len_from_disk(de->rec_len,
+                                                              blocksize),
+                                       blocksize);
                        else
                                de->inode = 0;
                        dir->i_version++;
@@ -1661,9 +1705,9 @@ static int ext4_delete_entry(handle_t *handle,
                        ext4_handle_dirty_metadata(handle, dir, bh);
                        return 0;
                }
-               i += ext4_rec_len_from_disk(de->rec_len);
+               i += ext4_rec_len_from_disk(de->rec_len, blocksize);
                pde = de;
-               de = ext4_next_entry(de);
+               de = ext4_next_entry(de, blocksize);
        }
        return -ENOENT;
 }
@@ -1793,6 +1837,7 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        struct inode *inode;
        struct buffer_head *dir_block;
        struct ext4_dir_entry_2 *de;
+       unsigned int blocksize = dir->i_sb->s_blocksize;
        int err, retries = 0;
 
        if (EXT4_DIR_LINK_MAX(dir))
@@ -1824,13 +1869,14 @@ retry:
        de = (struct ext4_dir_entry_2 *) dir_block->b_data;
        de->inode = cpu_to_le32(inode->i_ino);
        de->name_len = 1;
-       de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len));
+       de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len),
+                                          blocksize);
        strcpy(de->name, ".");
        ext4_set_de_type(dir->i_sb, de, S_IFDIR);
-       de = ext4_next_entry(de);
+       de = ext4_next_entry(de, blocksize);
        de->inode = cpu_to_le32(dir->i_ino);
-       de->rec_len = ext4_rec_len_to_disk(inode->i_sb->s_blocksize -
-                                               EXT4_DIR_REC_LEN(1));
+       de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(1),
+                                          blocksize);
        de->name_len = 2;
        strcpy(de->name, "..");
        ext4_set_de_type(dir->i_sb, de, S_IFDIR);
@@ -1885,7 +1931,7 @@ static int empty_dir(struct inode *inode)
                return 1;
        }
        de = (struct ext4_dir_entry_2 *) bh->b_data;
-       de1 = ext4_next_entry(de);
+       de1 = ext4_next_entry(de, sb->s_blocksize);
        if (le32_to_cpu(de->inode) != inode->i_ino ||
                        !le32_to_cpu(de1->inode) ||
                        strcmp(".", de->name) ||
@@ -1896,9 +1942,9 @@ static int empty_dir(struct inode *inode)
                brelse(bh);
                return 1;
        }
-       offset = ext4_rec_len_from_disk(de->rec_len) +
-                ext4_rec_len_from_disk(de1->rec_len);
-       de = ext4_next_entry(de1);
+       offset = ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize) +
+                ext4_rec_len_from_disk(de1->rec_len, sb->s_blocksize);
+       de = ext4_next_entry(de1, sb->s_blocksize);
        while (offset < inode->i_size) {
                if (!bh ||
                        (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
@@ -1927,8 +1973,8 @@ static int empty_dir(struct inode *inode)
                        brelse(bh);
                        return 0;
                }
-               offset += ext4_rec_len_from_disk(de->rec_len);
-               de = ext4_next_entry(de);
+               offset += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize);
+               de = ext4_next_entry(de, sb->s_blocksize);
        }
        brelse(bh);
        return 1;
@@ -2297,8 +2343,8 @@ retry:
        return err;
 }
 
-#define PARENT_INO(buffer) \
-       (ext4_next_entry((struct ext4_dir_entry_2 *)(buffer))->inode)
+#define PARENT_INO(buffer, size) \
+       (ext4_next_entry((struct ext4_dir_entry_2 *)(buffer), size)->inode)
 
 /*
  * Anybody can rename anything with this: the permission checks are left to the
@@ -2311,7 +2357,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct inode *old_inode, *new_inode;
        struct buffer_head *old_bh, *new_bh, *dir_bh;
        struct ext4_dir_entry_2 *old_de, *new_de;
-       int retval;
+       int retval, force_da_alloc = 0;
 
        old_bh = new_bh = dir_bh = NULL;
 
@@ -2358,7 +2404,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
                dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval);
                if (!dir_bh)
                        goto end_rename;
-               if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)
+               if (le32_to_cpu(PARENT_INO(dir_bh->b_data,
+                               old_dir->i_sb->s_blocksize)) != old_dir->i_ino)
                        goto end_rename;
                retval = -EMLINK;
                if (!new_inode && new_dir != old_dir &&
@@ -2430,7 +2477,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (dir_bh) {
                BUFFER_TRACE(dir_bh, "get_write_access");
                ext4_journal_get_write_access(handle, dir_bh);
-               PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
+               PARENT_INO(dir_bh->b_data, new_dir->i_sb->s_blocksize) =
+                                               cpu_to_le32(new_dir->i_ino);
                BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata");
                ext4_handle_dirty_metadata(handle, old_dir, dir_bh);
                ext4_dec_count(handle, old_dir);
@@ -2449,6 +2497,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
                ext4_mark_inode_dirty(handle, new_inode);
                if (!new_inode->i_nlink)
                        ext4_orphan_add(handle, new_inode);
+               if (!test_opt(new_dir->i_sb, NO_AUTO_DA_ALLOC))
+                       force_da_alloc = 1;
        }
        retval = 0;
 
@@ -2457,6 +2507,8 @@ end_rename:
        brelse(old_bh);
        brelse(new_bh);
        ext4_journal_stop(handle);
+       if (retval == 0 && force_da_alloc)
+               ext4_alloc_da_blocks(old_inode);
        return retval;
 }
 
index c06886abd6588b3c975ee92dd1eb76a88be29e3a..546c7dd869e19176e77cb54278e9bdfc2b520da4 100644 (file)
@@ -938,10 +938,10 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
        if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
                ext4_group_t flex_group;
                flex_group = ext4_flex_group(sbi, input->group);
-               sbi->s_flex_groups[flex_group].free_blocks +=
-                       input->free_blocks_count;
-               sbi->s_flex_groups[flex_group].free_inodes +=
-                       EXT4_INODES_PER_GROUP(sb);
+               atomic_add(input->free_blocks_count,
+                          &sbi->s_flex_groups[flex_group].free_blocks);
+               atomic_add(EXT4_INODES_PER_GROUP(sb),
+                          &sbi->s_flex_groups[flex_group].free_inodes);
        }
 
        ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh);
index f7371a6a923d359480108517c1a3358276a42eb7..9987bba99db3cc62c2faa887b95783676f83b480 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/quotaops.h>
 #include <linux/seq_file.h>
 #include <linux/proc_fs.h>
+#include <linux/ctype.h>
 #include <linux/marker.h>
 #include <linux/log2.h>
 #include <linux/crc16.h>
@@ -48,6 +49,7 @@
 #include "group.h"
 
 struct proc_dir_entry *ext4_proc_root;
+static struct kset *ext4_kset;
 
 static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
                             unsigned long journal_devnum);
@@ -577,9 +579,9 @@ static void ext4_put_super(struct super_block *sb)
                ext4_commit_super(sb, es, 1);
        }
        if (sbi->s_proc) {
-               remove_proc_entry("inode_readahead_blks", sbi->s_proc);
                remove_proc_entry(sb->s_id, ext4_proc_root);
        }
+       kobject_del(&sbi->s_kobj);
 
        for (i = 0; i < sbi->s_gdb_count; i++)
                brelse(sbi->s_group_desc[i]);
@@ -615,6 +617,17 @@ static void ext4_put_super(struct super_block *sb)
                ext4_blkdev_remove(sbi);
        }
        sb->s_fs_info = NULL;
+       /*
+        * Now that we are completely done shutting down the
+        * superblock, we need to actually destroy the kobject.
+        */
+       unlock_kernel();
+       unlock_super(sb);
+       kobject_put(&sbi->s_kobj);
+       wait_for_completion(&sbi->s_kobj_unregister);
+       lock_super(sb);
+       lock_kernel();
+       kfree(sbi->s_blockgroup_lock);
        kfree(sbi);
        return;
 }
@@ -803,8 +816,6 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
        if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT4_DEFM_ACL))
                seq_puts(seq, ",noacl");
 #endif
-       if (!test_opt(sb, RESERVATION))
-               seq_puts(seq, ",noreservation");
        if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) {
                seq_printf(seq, ",commit=%u",
                           (unsigned) (sbi->s_commit_interval / HZ));
@@ -855,6 +866,9 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
        if (test_opt(sb, DATA_ERR_ABORT))
                seq_puts(seq, ",data_err=abort");
 
+       if (test_opt(sb, NO_AUTO_DA_ALLOC))
+               seq_puts(seq, ",noauto_da_alloc");
+
        ext4_show_quota_options(seq, sb);
        return 0;
 }
@@ -1004,7 +1018,7 @@ enum {
        Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
        Opt_nouid32, Opt_debug, Opt_oldalloc, Opt_orlov,
        Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
-       Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh,
+       Opt_auto_da_alloc, Opt_noauto_da_alloc, Opt_noload, Opt_nobh, Opt_bh,
        Opt_commit, Opt_min_batch_time, Opt_max_batch_time,
        Opt_journal_update, Opt_journal_dev,
        Opt_journal_checksum, Opt_journal_async_commit,
@@ -1012,8 +1026,8 @@ enum {
        Opt_data_err_abort, Opt_data_err_ignore,
        Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
        Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
-       Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
-       Opt_grpquota, Opt_i_version,
+       Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err, Opt_resize,
+       Opt_usrquota, Opt_grpquota, Opt_i_version,
        Opt_stripe, Opt_delalloc, Opt_nodelalloc,
        Opt_inode_readahead_blks, Opt_journal_ioprio
 };
@@ -1039,8 +1053,6 @@ static const match_table_t tokens = {
        {Opt_nouser_xattr, "nouser_xattr"},
        {Opt_acl, "acl"},
        {Opt_noacl, "noacl"},
-       {Opt_reservation, "reservation"},
-       {Opt_noreservation, "noreservation"},
        {Opt_noload, "noload"},
        {Opt_nobh, "nobh"},
        {Opt_bh, "bh"},
@@ -1068,6 +1080,8 @@ static const match_table_t tokens = {
        {Opt_quota, "quota"},
        {Opt_usrquota, "usrquota"},
        {Opt_barrier, "barrier=%u"},
+       {Opt_barrier, "barrier"},
+       {Opt_nobarrier, "nobarrier"},
        {Opt_i_version, "i_version"},
        {Opt_stripe, "stripe=%u"},
        {Opt_resize, "resize"},
@@ -1075,6 +1089,9 @@ static const match_table_t tokens = {
        {Opt_nodelalloc, "nodelalloc"},
        {Opt_inode_readahead_blks, "inode_readahead_blks=%u"},
        {Opt_journal_ioprio, "journal_ioprio=%u"},
+       {Opt_auto_da_alloc, "auto_da_alloc=%u"},
+       {Opt_auto_da_alloc, "auto_da_alloc"},
+       {Opt_noauto_da_alloc, "noauto_da_alloc"},
        {Opt_err, NULL},
 };
 
@@ -1207,12 +1224,6 @@ static int parse_options(char *options, struct super_block *sb,
                               "not supported\n");
                        break;
 #endif
-               case Opt_reservation:
-                       set_opt(sbi->s_mount_opt, RESERVATION);
-                       break;
-               case Opt_noreservation:
-                       clear_opt(sbi->s_mount_opt, RESERVATION);
-                       break;
                case Opt_journal_update:
                        /* @@@ FIXME */
                        /* Eventually we will want to be able to create
@@ -1415,9 +1426,14 @@ set_qf_format:
                case Opt_abort:
                        set_opt(sbi->s_mount_opt, ABORT);
                        break;
+               case Opt_nobarrier:
+                       clear_opt(sbi->s_mount_opt, BARRIER);
+                       break;
                case Opt_barrier:
-                       if (match_int(&args[0], &option))
-                               return 0;
+                       if (match_int(&args[0], &option)) {
+                               set_opt(sbi->s_mount_opt, BARRIER);
+                               break;
+                       }
                        if (option)
                                set_opt(sbi->s_mount_opt, BARRIER);
                        else
@@ -1463,6 +1479,11 @@ set_qf_format:
                                return 0;
                        if (option < 0 || option > (1 << 30))
                                return 0;
+                       if (option & (option - 1)) {
+                               printk(KERN_ERR "EXT4-fs: inode_readahead_blks"
+                                      " must be a power of 2\n");
+                               return 0;
+                       }
                        sbi->s_inode_readahead_blks = option;
                        break;
                case Opt_journal_ioprio:
@@ -1473,6 +1494,19 @@ set_qf_format:
                        *journal_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE,
                                                            option);
                        break;
+               case Opt_noauto_da_alloc:
+                       set_opt(sbi->s_mount_opt,NO_AUTO_DA_ALLOC);
+                       break;
+               case Opt_auto_da_alloc:
+                       if (match_int(&args[0], &option)) {
+                               clear_opt(sbi->s_mount_opt, NO_AUTO_DA_ALLOC);
+                               break;
+                       }
+                       if (option)
+                               clear_opt(sbi->s_mount_opt, NO_AUTO_DA_ALLOC);
+                       else
+                               set_opt(sbi->s_mount_opt,NO_AUTO_DA_ALLOC);
+                       break;
                default:
                        printk(KERN_ERR
                               "EXT4-fs: Unrecognized mount option \"%s\" "
@@ -1612,10 +1646,12 @@ static int ext4_fill_flex_info(struct super_block *sb)
                gdp = ext4_get_group_desc(sb, i, &bh);
 
                flex_group = ext4_flex_group(sbi, i);
-               sbi->s_flex_groups[flex_group].free_inodes +=
-                       ext4_free_inodes_count(sb, gdp);
-               sbi->s_flex_groups[flex_group].free_blocks +=
-                       ext4_free_blks_count(sb, gdp);
+               atomic_set(&sbi->s_flex_groups[flex_group].free_inodes,
+                          ext4_free_inodes_count(sb, gdp));
+               atomic_set(&sbi->s_flex_groups[flex_group].free_blocks,
+                          ext4_free_blks_count(sb, gdp));
+               atomic_set(&sbi->s_flex_groups[flex_group].used_dirs,
+                          ext4_used_dirs_count(sb, gdp));
        }
 
        return 1;
@@ -1991,6 +2027,181 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi)
        return 0;
 }
 
+/* sysfs supprt */
+
+struct ext4_attr {
+       struct attribute attr;
+       ssize_t (*show)(struct ext4_attr *, struct ext4_sb_info *, char *);
+       ssize_t (*store)(struct ext4_attr *, struct ext4_sb_info *, 
+                        const char *, size_t);
+       int offset;
+};
+
+static int parse_strtoul(const char *buf,
+               unsigned long max, unsigned long *value)
+{
+       char *endp;
+
+       while (*buf && isspace(*buf))
+               buf++;
+       *value = simple_strtoul(buf, &endp, 0);
+       while (*endp && isspace(*endp))
+               endp++;
+       if (*endp || *value > max)
+               return -EINVAL;
+
+       return 0;
+}
+
+static ssize_t delayed_allocation_blocks_show(struct ext4_attr *a,
+                                             struct ext4_sb_info *sbi,
+                                             char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%llu\n",
+                       (s64) percpu_counter_sum(&sbi->s_dirtyblocks_counter));
+}
+
+static ssize_t session_write_kbytes_show(struct ext4_attr *a,
+                                        struct ext4_sb_info *sbi, char *buf)
+{
+       struct super_block *sb = sbi->s_buddy_cache->i_sb;
+
+       return snprintf(buf, PAGE_SIZE, "%lu\n",
+                       (part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
+                        sbi->s_sectors_written_start) >> 1);
+}
+
+static ssize_t lifetime_write_kbytes_show(struct ext4_attr *a,
+                                         struct ext4_sb_info *sbi, char *buf)
+{
+       struct super_block *sb = sbi->s_buddy_cache->i_sb;
+
+       return snprintf(buf, PAGE_SIZE, "%llu\n",
+                       sbi->s_kbytes_written + 
+                       ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
+                         EXT4_SB(sb)->s_sectors_written_start) >> 1));
+}
+
+static ssize_t inode_readahead_blks_store(struct ext4_attr *a,
+                                         struct ext4_sb_info *sbi,
+                                         const char *buf, size_t count)
+{
+       unsigned long t;
+
+       if (parse_strtoul(buf, 0x40000000, &t))
+               return -EINVAL;
+
+       /* inode_readahead_blks must be a power of 2 */
+       if (t & (t-1))
+               return -EINVAL;
+
+       sbi->s_inode_readahead_blks = t;
+       return count;
+}
+
+static ssize_t sbi_ui_show(struct ext4_attr *a,
+                               struct ext4_sb_info *sbi, char *buf)
+{
+       unsigned int *ui = (unsigned int *) (((char *) sbi) + a->offset);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", *ui);
+}
+
+static ssize_t sbi_ui_store(struct ext4_attr *a,
+                           struct ext4_sb_info *sbi,
+                           const char *buf, size_t count)
+{
+       unsigned int *ui = (unsigned int *) (((char *) sbi) + a->offset);
+       unsigned long t;
+
+       if (parse_strtoul(buf, 0xffffffff, &t))
+               return -EINVAL;
+       *ui = t;
+       return count;
+}
+
+#define EXT4_ATTR_OFFSET(_name,_mode,_show,_store,_elname) \
+static struct ext4_attr ext4_attr_##_name = {                  \
+       .attr = {.name = __stringify(_name), .mode = _mode },   \
+       .show   = _show,                                        \
+       .store  = _store,                                       \
+       .offset = offsetof(struct ext4_sb_info, _elname),       \
+}
+#define EXT4_ATTR(name, mode, show, store) \
+static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store)
+
+#define EXT4_RO_ATTR(name) EXT4_ATTR(name, 0444, name##_show, NULL)
+#define EXT4_RW_ATTR(name) EXT4_ATTR(name, 0644, name##_show, name##_store)
+#define EXT4_RW_ATTR_SBI_UI(name, elname)      \
+       EXT4_ATTR_OFFSET(name, 0644, sbi_ui_show, sbi_ui_store, elname)
+#define ATTR_LIST(name) &ext4_attr_##name.attr
+
+EXT4_RO_ATTR(delayed_allocation_blocks);
+EXT4_RO_ATTR(session_write_kbytes);
+EXT4_RO_ATTR(lifetime_write_kbytes);
+EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show,
+                inode_readahead_blks_store, s_inode_readahead_blks);
+EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats);
+EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan);
+EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan);
+EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs);
+EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request);
+EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc);
+
+static struct attribute *ext4_attrs[] = {
+       ATTR_LIST(delayed_allocation_blocks),
+       ATTR_LIST(session_write_kbytes),
+       ATTR_LIST(lifetime_write_kbytes),
+       ATTR_LIST(inode_readahead_blks),
+       ATTR_LIST(mb_stats),
+       ATTR_LIST(mb_max_to_scan),
+       ATTR_LIST(mb_min_to_scan),
+       ATTR_LIST(mb_order2_req),
+       ATTR_LIST(mb_stream_req),
+       ATTR_LIST(mb_group_prealloc),
+       NULL,
+};
+
+static ssize_t ext4_attr_show(struct kobject *kobj,
+                             struct attribute *attr, char *buf)
+{
+       struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info,
+                                               s_kobj);
+       struct ext4_attr *a = container_of(attr, struct ext4_attr, attr);
+
+       return a->show ? a->show(a, sbi, buf) : 0;
+}
+
+static ssize_t ext4_attr_store(struct kobject *kobj,
+                              struct attribute *attr,
+                              const char *buf, size_t len)
+{
+       struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info,
+                                               s_kobj);
+       struct ext4_attr *a = container_of(attr, struct ext4_attr, attr);
+
+       return a->store ? a->store(a, sbi, buf, len) : 0;
+}
+
+static void ext4_sb_release(struct kobject *kobj)
+{
+       struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info,
+                                               s_kobj);
+       complete(&sbi->s_kobj_unregister);
+}
+
+
+static struct sysfs_ops ext4_attr_ops = {
+       .show   = ext4_attr_show,
+       .store  = ext4_attr_store,
+};
+
+static struct kobj_type ext4_ktype = {
+       .default_attrs  = ext4_attrs,
+       .sysfs_ops      = &ext4_attr_ops,
+       .release        = ext4_sb_release,
+};
+
 static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                                __releases(kernel_lock)
                                __acquires(kernel_lock)
@@ -2021,12 +2232,21 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (!sbi)
                return -ENOMEM;
+
+       sbi->s_blockgroup_lock =
+               kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
+       if (!sbi->s_blockgroup_lock) {
+               kfree(sbi);
+               return -ENOMEM;
+       }
        sb->s_fs_info = sbi;
        sbi->s_mount_opt = 0;
        sbi->s_resuid = EXT4_DEF_RESUID;
        sbi->s_resgid = EXT4_DEF_RESGID;
        sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
        sbi->s_sb_block = sb_block;
+       sbi->s_sectors_written_start = part_stat_read(sb->s_bdev->bd_part,
+                                                     sectors[1]);
 
        unlock_kernel();
 
@@ -2064,6 +2284,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_magic = le16_to_cpu(es->s_magic);
        if (sb->s_magic != EXT4_SUPER_MAGIC)
                goto cantfind_ext4;
+       sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written);
 
        /* Set defaults before we parse the mount options */
        def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
@@ -2101,7 +2322,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME;
        sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME;
 
-       set_opt(sbi->s_mount_opt, RESERVATION);
        set_opt(sbi->s_mount_opt, BARRIER);
 
        /*
@@ -2325,14 +2545,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 #ifdef CONFIG_PROC_FS
        if (ext4_proc_root)
                sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root);
-
-       if (sbi->s_proc)
-               proc_create_data("inode_readahead_blks", 0644, sbi->s_proc,
-                                &ext4_ui_proc_fops,
-                                &sbi->s_inode_readahead_blks);
 #endif
 
-       bgl_lock_init(&sbi->s_blockgroup_lock);
+       bgl_lock_init(sbi->s_blockgroup_lock);
 
        for (i = 0; i < db_count; i++) {
                block = descriptor_loc(sb, logical_sb_block, i);
@@ -2564,6 +2779,16 @@ no_journal:
                goto failed_mount4;
        }
 
+       sbi->s_kobj.kset = ext4_kset;
+       init_completion(&sbi->s_kobj_unregister);
+       err = kobject_init_and_add(&sbi->s_kobj, &ext4_ktype, NULL,
+                                  "%s", sb->s_id);
+       if (err) {
+               ext4_mb_release(sb);
+               ext4_ext_release(sb);
+               goto failed_mount4;
+       };
+
        /*
         * akpm: core read_super() calls in here with the superblock locked.
         * That deadlocks, because orphan cleanup needs to lock the superblock
@@ -2618,7 +2843,6 @@ failed_mount2:
        kfree(sbi->s_group_desc);
 failed_mount:
        if (sbi->s_proc) {
-               remove_proc_entry("inode_readahead_blks", sbi->s_proc);
                remove_proc_entry(sb->s_id, ext4_proc_root);
        }
 #ifdef CONFIG_QUOTA
@@ -2913,6 +3137,10 @@ static int ext4_commit_super(struct super_block *sb,
                set_buffer_uptodate(sbh);
        }
        es->s_wtime = cpu_to_le32(get_seconds());
+       es->s_kbytes_written =
+               cpu_to_le64(EXT4_SB(sb)->s_kbytes_written + 
+                           ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
+                             EXT4_SB(sb)->s_sectors_written_start) >> 1));
        ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
                                        &EXT4_SB(sb)->s_freeblocks_counter));
        es->s_free_inodes_count = cpu_to_le32(percpu_counter_sum_positive(
@@ -3647,45 +3875,6 @@ static int ext4_get_sb(struct file_system_type *fs_type,
        return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super, mnt);
 }
 
-#ifdef CONFIG_PROC_FS
-static int ext4_ui_proc_show(struct seq_file *m, void *v)
-{
-       unsigned int *p = m->private;
-
-       seq_printf(m, "%u\n", *p);
-       return 0;
-}
-
-static int ext4_ui_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, ext4_ui_proc_show, PDE(inode)->data);
-}
-
-static ssize_t ext4_ui_proc_write(struct file *file, const char __user *buf,
-                              size_t cnt, loff_t *ppos)
-{
-       unsigned long *p = PDE(file->f_path.dentry->d_inode)->data;
-       char str[32];
-
-       if (cnt >= sizeof(str))
-               return -EINVAL;
-       if (copy_from_user(str, buf, cnt))
-               return -EFAULT;
-
-       *p = simple_strtoul(str, NULL, 0);
-       return cnt;
-}
-
-const struct file_operations ext4_ui_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = ext4_ui_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .write          = ext4_ui_proc_write,
-};
-#endif
-
 static struct file_system_type ext4_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "ext4",
@@ -3719,6 +3908,9 @@ static int __init init_ext4_fs(void)
 {
        int err;
 
+       ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj);
+       if (!ext4_kset)
+               return -ENOMEM;
        ext4_proc_root = proc_mkdir("fs/ext4", NULL);
        err = init_ext4_mballoc();
        if (err)
@@ -3760,6 +3952,7 @@ static void __exit exit_ext4_fs(void)
        exit_ext4_xattr();
        exit_ext4_mballoc();
        remove_proc_entry("fs/ext4", NULL);
+       kset_unregister(ext4_kset);
 }
 
 MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
index de0004fe6e0049c8a09a494444d19831313da64c..2cc952e4c3dc37279a8fde4f1279408c4151d474 100644 (file)
@@ -523,7 +523,9 @@ static int fat_remount(struct super_block *sb, int *flags, char *data)
 
 static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
-       struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
+       struct super_block *sb = dentry->d_sb;
+       struct msdos_sb_info *sbi = MSDOS_SB(sb);
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        /* If the count of free cluster is still unknown, counts it here. */
        if (sbi->free_clusters == -1 || !sbi->free_clus_valid) {
@@ -537,6 +539,8 @@ static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_blocks = sbi->max_cluster - FAT_START_ENT;
        buf->f_bfree = sbi->free_clusters;
        buf->f_bavail = sbi->free_clusters;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = sbi->options.isvfat ? 260 : 12;
 
        return 0;
index d865ca66ccba1a6fb331150a75c7d50b5545e87c..cc8e4de2fee5f0caefa6c5e00ea4e1abf33359b8 100644 (file)
@@ -531,6 +531,12 @@ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fap
                if (!new)
                        return -ENOMEM;
        }
+
+       /*
+        * We need to take f_lock first since it's not an IRQ-safe
+        * lock.
+        */
+       spin_lock(&filp->f_lock);
        write_lock_irq(&fasync_lock);
        for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
                if (fa->fa_file == filp) {
@@ -555,14 +561,12 @@ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fap
                result = 1;
        }
 out:
-       /* Fix up FASYNC bit while still holding fasync_lock */
-       spin_lock(&filp->f_lock);
        if (on)
                filp->f_flags |= FASYNC;
        else
                filp->f_flags &= ~FASYNC;
-       spin_unlock(&filp->f_lock);
        write_unlock_irq(&fasync_lock);
+       spin_unlock(&filp->f_lock);
        return result;
 }
 
index e3fe9918faafb710446f5bd73445eeca5ce5b0d7..eed4806399020bbf8d100d1e309b420612a1a093 100644 (file)
@@ -196,7 +196,7 @@ static void redirty_tail(struct inode *inode)
                struct inode *tail_inode;
 
                tail_inode = list_entry(sb->s_dirty.next, struct inode, i_list);
-               if (!time_after_eq(inode->dirtied_when,
+               if (time_before(inode->dirtied_when,
                                tail_inode->dirtied_when))
                        inode->dirtied_when = jiffies;
        }
@@ -220,6 +220,21 @@ static void inode_sync_complete(struct inode *inode)
        wake_up_bit(&inode->i_state, __I_SYNC);
 }
 
+static bool inode_dirtied_after(struct inode *inode, unsigned long t)
+{
+       bool ret = time_after(inode->dirtied_when, t);
+#ifndef CONFIG_64BIT
+       /*
+        * For inodes being constantly redirtied, dirtied_when can get stuck.
+        * It _appears_ to be in the future, but is actually in distant past.
+        * This test is necessary to prevent such wrapped-around relative times
+        * from permanently stopping the whole pdflush writeback.
+        */
+       ret = ret && time_before_eq(inode->dirtied_when, jiffies);
+#endif
+       return ret;
+}
+
 /*
  * Move expired dirty inodes from @delaying_queue to @dispatch_queue.
  */
@@ -231,7 +246,7 @@ static void move_expired_inodes(struct list_head *delaying_queue,
                struct inode *inode = list_entry(delaying_queue->prev,
                                                struct inode, i_list);
                if (older_than_this &&
-                       time_after(inode->dirtied_when, *older_than_this))
+                   inode_dirtied_after(inode, *older_than_this))
                        break;
                list_move(&inode->i_list, dispatch_queue);
        }
@@ -492,8 +507,11 @@ void generic_sync_sb_inodes(struct super_block *sb,
                        continue;               /* blockdev has wrong queue */
                }
 
-               /* Was this inode dirtied after sync_sb_inodes was called? */
-               if (time_after(inode->dirtied_when, start))
+               /*
+                * Was this inode dirtied after sync_sb_inodes was called?
+                * This keeps sync from extra jobs and livelock.
+                */
+               if (inode_dirtied_after(inode, start))
                        break;
 
                /* Is another pdflush already flushing this queue? */
@@ -538,7 +556,8 @@ void generic_sync_sb_inodes(struct super_block *sb,
                list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
                        struct address_space *mapping;
 
-                       if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW))
+                       if (inode->i_state &
+                                       (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW))
                                continue;
                        mapping = inode->i_mapping;
                        if (mapping->nrpages == 0)
index d9fdb7cec5388756720374f9b4c70ec56d453bb2..4e340fedf768e92a1f3c60e8e2cd8621a7ecb87f 100644 (file)
@@ -1234,8 +1234,9 @@ static void fuse_vma_close(struct vm_area_struct *vma)
  * - sync(2)
  * - try_to_free_pages() with order > PAGE_ALLOC_COSTLY_ORDER
  */
-static int fuse_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+static int fuse_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
+       struct page *page = vmf->page;
        /*
         * Don't use page->mapping as it may become NULL from a
         * concurrent truncate.
@@ -1465,7 +1466,7 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin)
        case SEEK_END:
                retval = fuse_update_attributes(inode, NULL, file, NULL);
                if (retval)
-                       return retval;
+                       goto exit;
                offset += i_size_read(inode);
                break;
        case SEEK_CUR:
@@ -1479,6 +1480,7 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin)
                }
                retval = offset;
        }
+exit:
        mutex_unlock(&inode->i_mutex);
        return retval;
 }
index 3b9e8de3500be1c40b2fbb798cb8dcdc8d4b51b5..70b9b8548945d92450afc5936eddf72744ecccd7 100644 (file)
@@ -337,8 +337,9 @@ static int gfs2_allocate_page_backing(struct page *page)
  * blocks allocated on disk to back that page.
  */
 
-static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
+       struct page *page = vmf->page;
        struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
@@ -412,6 +413,8 @@ out_unlock:
        gfs2_glock_dq(&gh);
 out:
        gfs2_holder_uninit(&gh);
+       if (ret)
+               ret = VM_FAULT_SIGBUS;
        return ret;
 }
 
index c8b5acf4b0b7c086953e5526677bf30c740272d4..a36bb749926da345772e937e5c9af67388af1c05 100644 (file)
@@ -82,6 +82,7 @@ static void hfs_put_super(struct super_block *sb)
 static int hfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type = HFS_SUPER_MAGIC;
        buf->f_bsize = sb->s_blocksize;
@@ -90,6 +91,8 @@ static int hfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bavail = buf->f_bfree;
        buf->f_files = HFS_SB(sb)->fs_ablocks;
        buf->f_ffree = HFS_SB(sb)->free_ablocks;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = HFS_NAMELEN;
 
        return 0;
index eb74531a0a8e267bec8491a18a83ed65b1a8d853..f2a64020f42e1ee855c997bb4c0a713ee0c2f4ee 100644 (file)
@@ -223,6 +223,7 @@ static void hfsplus_put_super(struct super_block *sb)
 static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type = HFSPLUS_SUPER_MAGIC;
        buf->f_bsize = sb->s_blocksize;
@@ -231,6 +232,8 @@ static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bavail = buf->f_bfree;
        buf->f_files = 0xFFFFFFFF;
        buf->f_ffree = 0xFFFFFFFF - HFSPLUS_SB(sb).next_cnid;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = HFSPLUS_MAX_STRLEN;
 
        return 0;
index 0d049b8919c42ed1c62871f26815994a5f00e254..c40f6e24244476d3af40988d7320cbf4de3ac0f5 100644 (file)
@@ -136,6 +136,7 @@ static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *s = dentry->d_sb;
        struct hpfs_sb_info *sbi = hpfs_sb(s);
+       u64 id = huge_encode_dev(s->s_bdev->bd_dev);
        lock_kernel();
 
        /*if (sbi->sb_n_free == -1) {*/
@@ -149,6 +150,8 @@ static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bavail = sbi->sb_n_free;
        buf->f_files = sbi->sb_dirband_size / 4;
        buf->f_ffree = sbi->sb_n_free_dnodes;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = 254;
 
        unlock_kernel();
index b278f7f52024ba556d32604ac61cab01e114f39b..a5089a6dd67a741b79279ffb435d94e2162f510e 100644 (file)
@@ -280,7 +280,12 @@ static ssize_t hppfs_read(struct file *file, char __user *buf, size_t count,
                               "errno = %d\n", err);
                        return err;
                }
-               count = hppfs_read_file(hppfs->host_fd, buf, count);
+               err = hppfs_read_file(hppfs->host_fd, buf, count);
+               if (err < 0) {
+                       printk(KERN_ERR "hppfs_read: read failed: %d\n", err);
+                       return err;
+               }
+               count = err;
                if (count > 0)
                        *ppos += count;
        }
index 9b800d97a68771b2299e978ebfdb003476e1c075..23a3c76711e08bb151f91a84cc3ea5e4f7bb20c8 100644 (file)
@@ -943,14 +943,13 @@ static struct vfsmount *hugetlbfs_vfsmount;
 
 static int can_do_hugetlb_shm(void)
 {
-       return likely(capable(CAP_IPC_LOCK) ||
-                       in_group_p(sysctl_hugetlb_shm_group) ||
-                       can_do_mlock());
+       return capable(CAP_IPC_LOCK) || in_group_p(sysctl_hugetlb_shm_group);
 }
 
 struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag)
 {
        int error = -ENOMEM;
+       int unlock_shm = 0;
        struct file *file;
        struct inode *inode;
        struct dentry *dentry, *root;
@@ -960,11 +959,14 @@ struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag)
        if (!hugetlbfs_vfsmount)
                return ERR_PTR(-ENOENT);
 
-       if (!can_do_hugetlb_shm())
-               return ERR_PTR(-EPERM);
-
-       if (!user_shm_lock(size, user))
-               return ERR_PTR(-ENOMEM);
+       if (!can_do_hugetlb_shm()) {
+               if (user_shm_lock(size, user)) {
+                       unlock_shm = 1;
+                       WARN_ONCE(1,
+                         "Using mlock ulimits for SHM_HUGETLB deprecated\n");
+               } else
+                       return ERR_PTR(-EPERM);
+       }
 
        root = hugetlbfs_vfsmount->mnt_root;
        quick_string.name = name;
@@ -1004,7 +1006,8 @@ out_inode:
 out_dentry:
        dput(dentry);
 out_shm_unlock:
-       user_shm_unlock(size, user);
+       if (unlock_shm)
+               user_shm_unlock(size, user);
        return ERR_PTR(error);
 }
 
index 0d8ac497b3d552315b56e53c95f3f0440f59e45d..53af885f173243df3a5bf0906b589edccece84db 100644 (file)
@@ -43,7 +43,7 @@ extern void __init chrdev_init(void);
 /*
  * exec.c
  */
-extern void check_unsafe_exec(struct linux_binprm *, struct files_struct *);
+extern void check_unsafe_exec(struct linux_binprm *);
 
 /*
  * namespace.c
index 13d2eddd0692d74b732f6b7b31ca2fbf5fd63014..b4cbe9603c7d9fcd479df7463781afd7328566ef 100644 (file)
@@ -923,6 +923,7 @@ out_freesbi:
 static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type = ISOFS_SUPER_MAGIC;
        buf->f_bsize = sb->s_blocksize;
@@ -932,6 +933,8 @@ static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf)
        buf->f_bavail = 0;
        buf->f_files = ISOFS_SB(sb)->s_ninodes;
        buf->f_ffree = 0;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = NAME_MAX;
        return 0;
 }
index e79c07812afa4d044ec46bc92d77ba8f759aacb4..737f7246a4b5ddc750b4a5198928f4b5afacc193 100644 (file)
@@ -637,6 +637,8 @@ struct journal_head *journal_get_descriptor_buffer(journal_t *journal)
                return NULL;
 
        bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
+       if (!bh)
+               return NULL;
        lock_buffer(bh);
        memset(bh->b_data, 0, journal->j_blocksize);
        set_buffer_uptodate(bh);
@@ -733,9 +735,7 @@ journal_t * journal_init_dev(struct block_device *bdev,
        if (!journal->j_wbuf) {
                printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
                        __func__);
-               kfree(journal);
-               journal = NULL;
-               goto out;
+               goto out_err;
        }
        journal->j_dev = bdev;
        journal->j_fs_dev = fs_dev;
@@ -743,11 +743,19 @@ journal_t * journal_init_dev(struct block_device *bdev,
        journal->j_maxlen = len;
 
        bh = __getblk(journal->j_dev, start, journal->j_blocksize);
-       J_ASSERT(bh != NULL);
+       if (!bh) {
+               printk(KERN_ERR
+                      "%s: Cannot get buffer for journal superblock\n",
+                      __func__);
+               goto out_err;
+       }
        journal->j_sb_buffer = bh;
        journal->j_superblock = (journal_superblock_t *)bh->b_data;
-out:
+
        return journal;
+out_err:
+       kfree(journal);
+       return NULL;
 }
 
 /**
@@ -787,8 +795,7 @@ journal_t * journal_init_inode (struct inode *inode)
        if (!journal->j_wbuf) {
                printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
                        __func__);
-               kfree(journal);
-               return NULL;
+               goto out_err;
        }
 
        err = journal_bmap(journal, 0, &blocknr);
@@ -796,16 +803,23 @@ journal_t * journal_init_inode (struct inode *inode)
        if (err) {
                printk(KERN_ERR "%s: Cannnot locate journal superblock\n",
                       __func__);
-               kfree(journal);
-               return NULL;
+               goto out_err;
        }
 
        bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
-       J_ASSERT(bh != NULL);
+       if (!bh) {
+               printk(KERN_ERR
+                      "%s: Cannot get buffer for journal superblock\n",
+                      __func__);
+               goto out_err;
+       }
        journal->j_sb_buffer = bh;
        journal->j_superblock = (journal_superblock_t *)bh->b_data;
 
        return journal;
+out_err:
+       kfree(journal);
+       return NULL;
 }
 
 /*
index 62804e57a44caf2f893d16cc481f7ac347efe19a..4ea72377c7a28797b609c77084b03be21485800d 100644 (file)
@@ -367,6 +367,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        int tag_bytes = journal_tag_bytes(journal);
        struct buffer_head *cbh = NULL; /* For transactional checksums */
        __u32 crc32_sum = ~0;
+       int write_op = WRITE;
 
        /*
         * First job: lock down the current transaction and wait for
@@ -401,6 +402,8 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        spin_lock(&journal->j_state_lock);
        commit_transaction->t_state = T_LOCKED;
 
+       if (commit_transaction->t_synchronous_commit)
+               write_op = WRITE_SYNC;
        stats.u.run.rs_wait = commit_transaction->t_max_wait;
        stats.u.run.rs_locked = jiffies;
        stats.u.run.rs_running = jbd2_time_diff(commit_transaction->t_start,
@@ -680,7 +683,7 @@ start_journal_io:
                                clear_buffer_dirty(bh);
                                set_buffer_uptodate(bh);
                                bh->b_end_io = journal_end_buffer_io_sync;
-                               submit_bh(WRITE, bh);
+                               submit_bh(write_op, bh);
                        }
                        cond_resched();
                        stats.u.run.rs_blocks_logged += bufs;
index 257ff26257655f4573669a5ab6cb7ee817e0371b..bbe6d592d8b3723a17e2ef7be46098e3bdc10ebf 100644 (file)
  *                     need do nothing.
  * RevokeValid set, Revoked set:
  *                     buffer has been revoked.
+ *
+ * Locking rules:
+ * We keep two hash tables of revoke records. One hashtable belongs to the
+ * running transaction (is pointed to by journal->j_revoke), the other one
+ * belongs to the committing transaction. Accesses to the second hash table
+ * happen only from the kjournald and no other thread touches this table.  Also
+ * journal_switch_revoke_table() which switches which hashtable belongs to the
+ * running and which to the committing transaction is called only from
+ * kjournald. Therefore we need no locks when accessing the hashtable belonging
+ * to the committing transaction.
+ *
+ * All users operating on the hash table belonging to the running transaction
+ * have a handle to the transaction. Therefore they are safe from kjournald
+ * switching hash tables under them. For operations on the lists of entries in
+ * the hash table j_revoke_lock is used.
+ *
+ * Finally, also replay code uses the hash tables but at this moment noone else
+ * can touch them (filesystem isn't mounted yet) and hence no locking is
+ * needed.
  */
 
 #ifndef __KERNEL__
@@ -401,8 +420,6 @@ int jbd2_journal_revoke(handle_t *handle, unsigned long long blocknr,
  * the second time we would still have a pending revoke to cancel.  So,
  * do not trust the Revoked bit on buffers unless RevokeValid is also
  * set.
- *
- * The caller must have the journal locked.
  */
 int jbd2_journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
 {
@@ -480,10 +497,7 @@ void jbd2_journal_switch_revoke_table(journal_t *journal)
 /*
  * Write revoke records to the journal for all entries in the current
  * revoke hash, deleting the entries as we go.
- *
- * Called with the journal lock held.
  */
-
 void jbd2_journal_write_revoke_records(journal_t *journal,
                                  transaction_t *transaction)
 {
index 28ce21d8598e11f16182a973d31d7e8bef83c145..996ffda06bf306fde630e833f91332b745107689 100644 (file)
@@ -1315,6 +1315,8 @@ int jbd2_journal_stop(handle_t *handle)
                }
        }
 
+       if (handle->h_sync)
+               transaction->t_synchronous_commit = 1;
        current->journal_info = NULL;
        spin_lock(&journal->j_state_lock);
        spin_lock(&transaction->t_handle_lock);
index 9ff619a6f9cca643e59667c8b9f6033eef61fdd5..57cef19951dbc5aa703561d941ad217349a0e7fb 100644 (file)
@@ -1,6 +1,7 @@
 config JFS_FS
        tristate "JFS filesystem support"
        select NLS
+       select CRC32
        help
          This is a port of IBM's Journaled Filesystem .  More information is
          available in the file <file:Documentation/filesystems/jfs.txt>.
index 6a73de84bcef142350ad60f3b3fefe2b172de043..dd824d9b0b1a11877b2c901d335b2c746709bd08 100644 (file)
@@ -90,7 +90,6 @@ void jfs_proc_init(void)
 
        if (!(base = proc_mkdir("fs/jfs", NULL)))
                return;
-       base->owner = THIS_MODULE;
 
        for (i = 0; i < NPROCENT; i++)
                proc_create(Entries[i].name, 0, base, Entries[i].proc_fops);
index 169802ea07f991c85cf3e75f07ba41f701777100..bbbd5f202e3740d7e735449eb8e6e9626d56e4f1 100644 (file)
@@ -362,11 +362,12 @@ exit:
 int extHint(struct inode *ip, s64 offset, xad_t * xp)
 {
        struct super_block *sb = ip->i_sb;
-       struct xadlist xadl;
-       struct lxdlist lxdl;
-       lxd_t lxd;
+       int nbperpage = JFS_SBI(sb)->nbperpage;
        s64 prev;
-       int rc, nbperpage = JFS_SBI(sb)->nbperpage;
+       int rc = 0;
+       s64 xaddr;
+       int xlen;
+       int xflag;
 
        /* init the hint as "no hint provided" */
        XADaddress(xp, 0);
@@ -376,46 +377,30 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp)
         */
        prev = ((offset & ~POFFSET) >> JFS_SBI(sb)->l2bsize) - nbperpage;
 
-       /* if the offsets in the first page of the file,
-        * no hint provided.
+       /* if the offset is in the first page of the file, no hint provided.
         */
        if (prev < 0)
-               return (0);
-
-       /* prepare to lookup the previous page's extent info */
-       lxdl.maxnlxd = 1;
-       lxdl.nlxd = 1;
-       lxdl.lxd = &lxd;
-       LXDoffset(&lxd, prev)
-       LXDlength(&lxd, nbperpage);
-
-       xadl.maxnxad = 1;
-       xadl.nxad = 0;
-       xadl.xad = xp;
-
-       /* perform the lookup */
-       if ((rc = xtLookupList(ip, &lxdl, &xadl, 0)))
-               return (rc);
-
-       /* check if no extent exists for the previous page.
-        * this is possible for sparse files.
-        */
-       if (xadl.nxad == 0) {
-//             assert(ISSPARSE(ip));
-               return (0);
-       }
+               goto out;
 
-       /* only preserve the abnr flag within the xad flags
-        * of the returned hint.
-        */
-       xp->flag &= XAD_NOTRECORDED;
+       rc = xtLookup(ip, prev, nbperpage, &xflag, &xaddr, &xlen, 0);
 
-       if(xadl.nxad != 1 || lengthXAD(xp) != nbperpage) {
-               jfs_error(ip->i_sb, "extHint: corrupt xtree");
-               return -EIO;
-       }
+       if ((rc == 0) && xlen) {
+               if (xlen != nbperpage) {
+                       jfs_error(ip->i_sb, "extHint: corrupt xtree");
+                       rc = -EIO;
+               }
+               XADaddress(xp, xaddr);
+               XADlength(xp, xlen);
+               /*
+                * only preserve the abnr flag within the xad flags
+                * of the returned hint.
+                */
+               xp->flag  = xflag & XAD_NOTRECORDED;
+       } else
+               rc = 0;
 
-       return (0);
+out:
+       return (rc);
 }
 
 
index 0f94381ca6d081a6e50af4c33f8228d60f10318a..346057218edcdd440e1df24480264381c8101aa6 100644 (file)
 #include "jfs_superblock.h"
 #include "jfs_debug.h"
 
-/*
- * __mark_inode_dirty expects inodes to be hashed.  Since we don't want
- * special inodes in the fileset inode space, we make them appear hashed,
- * but do not put on any lists.
- */
-
 /*
  * imap locks
  */
@@ -497,7 +491,9 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
        release_metapage(mp);
 
        /*
-        * that will look hashed, but won't be on any list; hlist_del()
+        * __mark_inode_dirty expects inodes to be hashed.  Since we don't
+        * want special inodes in the fileset inode space, we make them
+        * appear hashed, but do not put on any lists.  hlist_del()
         * will work fine and require no locking.
         */
        ip->i_hash.pprev = &ip->i_hash.next;
index c350057087dd39db3809992338432ac07120bd16..07b6c5dfb4b6e641cda09581c4fff8abb8603ea5 100644 (file)
@@ -369,6 +369,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
        unsigned long bio_bytes = 0;
        unsigned long bio_offset = 0;
        int offset;
+       int bad_blocks = 0;
 
        page_start = (sector_t)page->index <<
                     (PAGE_CACHE_SHIFT - inode->i_blkbits);
@@ -394,6 +395,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
                }
 
                clear_bit(META_dirty, &mp->flag);
+               set_bit(META_io, &mp->flag);
                block_offset = offset >> inode->i_blkbits;
                lblock = page_start + block_offset;
                if (bio) {
@@ -402,7 +404,6 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
                                len = min(xlen, blocks_per_mp);
                                xlen -= len;
                                bio_bytes += len << inode->i_blkbits;
-                               set_bit(META_io, &mp->flag);
                                continue;
                        }
                        /* Not contiguous */
@@ -424,12 +425,14 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
                xlen = (PAGE_CACHE_SIZE - offset) >> inode->i_blkbits;
                pblock = metapage_get_blocks(inode, lblock, &xlen);
                if (!pblock) {
-                       /* Need better error handling */
                        printk(KERN_ERR "JFS: metapage_get_blocks failed\n");
-                       dec_io(page, last_write_complete);
+                       /*
+                        * We already called inc_io(), but can't cancel it
+                        * with dec_io() until we're done with the page
+                        */
+                       bad_blocks++;
                        continue;
                }
-               set_bit(META_io, &mp->flag);
                len = min(xlen, (int)JFS_SBI(inode->i_sb)->nbperpage);
 
                bio = bio_alloc(GFP_NOFS, 1);
@@ -459,6 +462,9 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
 
        unlock_page(page);
 
+       if (bad_blocks)
+               goto err_out;
+
        if (nr_underway == 0)
                end_page_writeback(page);
 
@@ -474,7 +480,9 @@ skip:
        bio_put(bio);
        unlock_page(page);
        dec_io(page, last_write_complete);
-
+err_out:
+       while (bad_blocks--)
+               dec_io(page, last_write_complete);
        return -EIO;
 }
 
index 649f9817accd05f5899e54dca2ecb0dcb406c6d6..43ea3713c083febbdd5df2cac7a7b611561e3574 100644 (file)
@@ -57,35 +57,6 @@ struct timestruc_t {
 #define        HIGHORDER       0x80000000u     /* high order bit on    */
 #define        ONES            0xffffffffu     /* all bit on           */
 
-/*
- *     logical xd (lxd)
- */
-typedef struct {
-       unsigned len:24;
-       unsigned off1:8;
-       u32 off2;
-} lxd_t;
-
-/* lxd_t field construction */
-#define        LXDlength(lxd, length32)        ( (lxd)->len = length32 )
-#define        LXDoffset(lxd, offset64)\
-{\
-       (lxd)->off1 = ((s64)offset64) >> 32;\
-       (lxd)->off2 = (offset64) & 0xffffffff;\
-}
-
-/* lxd_t field extraction */
-#define        lengthLXD(lxd)  ( (lxd)->len )
-#define        offsetLXD(lxd)\
-       ( ((s64)((lxd)->off1)) << 32 | (lxd)->off2 )
-
-/* lxd list */
-struct lxdlist {
-       s16 maxnlxd;
-       s16 nlxd;
-       lxd_t *lxd;
-};
-
 /*
  *     physical xd (pxd)
  */
index a27e26c905687b53157e2ce219eb391f91e360d7..d654a6458648d1a3427be4924f5463f5d77d5f40 100644 (file)
@@ -164,11 +164,8 @@ int xtLookup(struct inode *ip, s64 lstart,
                /* is lookup offset beyond eof ? */
                size = ((u64) ip->i_size + (JFS_SBI(ip->i_sb)->bsize - 1)) >>
                    JFS_SBI(ip->i_sb)->l2bsize;
-               if (lstart >= size) {
-                       jfs_err("xtLookup: lstart (0x%lx) >= size (0x%lx)",
-                               (ulong) lstart, (ulong) size);
+               if (lstart >= size)
                        return 0;
-               }
        }
 
        /*
@@ -220,264 +217,6 @@ int xtLookup(struct inode *ip, s64 lstart,
        return rc;
 }
 
-
-/*
- *     xtLookupList()
- *
- * function: map a single logical extent into a list of physical extent;
- *
- * parameter:
- *     struct inode    *ip,
- *     struct lxdlist  *lxdlist,       lxd list (in)
- *     struct xadlist  *xadlist,       xad list (in/out)
- *     int             flag)
- *
- * coverage of lxd by xad under assumption of
- * . lxd's are ordered and disjoint.
- * . xad's are ordered and disjoint.
- *
- * return:
- *     0:      success
- *
- * note: a page being written (even a single byte) is backed fully,
- *     except the last page which is only backed with blocks
- *     required to cover the last byte;
- *     the extent backing a page is fully contained within an xad;
- */
-int xtLookupList(struct inode *ip, struct lxdlist * lxdlist,
-                struct xadlist * xadlist, int flag)
-{
-       int rc = 0;
-       struct btstack btstack;
-       int cmp;
-       s64 bn;
-       struct metapage *mp;
-       xtpage_t *p;
-       int index;
-       lxd_t *lxd;
-       xad_t *xad, *pxd;
-       s64 size, lstart, lend, xstart, xend, pstart;
-       s64 llen, xlen, plen;
-       s64 xaddr, paddr;
-       int nlxd, npxd, maxnpxd;
-
-       npxd = xadlist->nxad = 0;
-       maxnpxd = xadlist->maxnxad;
-       pxd = xadlist->xad;
-
-       nlxd = lxdlist->nlxd;
-       lxd = lxdlist->lxd;
-
-       lstart = offsetLXD(lxd);
-       llen = lengthLXD(lxd);
-       lend = lstart + llen;
-
-       size = (ip->i_size + (JFS_SBI(ip->i_sb)->bsize - 1)) >>
-           JFS_SBI(ip->i_sb)->l2bsize;
-
-       /*
-        * search for the xad entry covering the logical extent
-        */
-      search:
-       if (lstart >= size)
-               return 0;
-
-       if ((rc = xtSearch(ip, lstart, NULL, &cmp, &btstack, 0)))
-               return rc;
-
-       /*
-        *      compute the physical extent covering logical extent
-        *
-        * N.B. search may have failed (e.g., hole in sparse file),
-        * and returned the index of the next entry.
-        */
-//map:
-       /* retrieve search result */
-       XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
-
-       /* is xad on the next sibling page ? */
-       if (index == le16_to_cpu(p->header.nextindex)) {
-               if (p->header.flag & BT_ROOT)
-                       goto mapend;
-
-               if ((bn = le64_to_cpu(p->header.next)) == 0)
-                       goto mapend;
-
-               XT_PUTPAGE(mp);
-
-               /* get next sibling page */
-               XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
-               if (rc)
-                       return rc;
-
-               index = XTENTRYSTART;
-       }
-
-       xad = &p->xad[index];
-
-       /*
-        * is lxd covered by xad ?
-        */
-      compare:
-       xstart = offsetXAD(xad);
-       xlen = lengthXAD(xad);
-       xend = xstart + xlen;
-       xaddr = addressXAD(xad);
-
-      compare1:
-       if (xstart < lstart)
-               goto compare2;
-
-       /* (lstart <= xstart) */
-
-       /* lxd is NOT covered by xad */
-       if (lend <= xstart) {
-               /*
-                * get next lxd
-                */
-               if (--nlxd == 0)
-                       goto mapend;
-               lxd++;
-
-               lstart = offsetLXD(lxd);
-               llen = lengthLXD(lxd);
-               lend = lstart + llen;
-               if (lstart >= size)
-                       goto mapend;
-
-               /* compare with the current xad */
-               goto compare1;
-       }
-       /* lxd is covered by xad */
-       else {                  /* (xstart < lend) */
-
-               /* initialize new pxd */
-               pstart = xstart;
-               plen = min(lend - xstart, xlen);
-               paddr = xaddr;
-
-               goto cover;
-       }
-
-       /* (xstart < lstart) */
-      compare2:
-       /* lxd is covered by xad */
-       if (lstart < xend) {
-               /* initialize new pxd */
-               pstart = lstart;
-               plen = min(xend - lstart, llen);
-               paddr = xaddr + (lstart - xstart);
-
-               goto cover;
-       }
-       /* lxd is NOT covered by xad */
-       else {                  /* (xend <= lstart) */
-
-               /*
-                * get next xad
-                *
-                * linear search next xad covering lxd on
-                * the current xad page, and then tree search
-                */
-               if (index == le16_to_cpu(p->header.nextindex) - 1) {
-                       if (p->header.flag & BT_ROOT)
-                               goto mapend;
-
-                       XT_PUTPAGE(mp);
-                       goto search;
-               } else {
-                       index++;
-                       xad++;
-
-                       /* compare with new xad */
-                       goto compare;
-               }
-       }
-
-       /*
-        * lxd is covered by xad and a new pxd has been initialized
-        * (lstart <= xstart < lend) or (xstart < lstart < xend)
-        */
-      cover:
-       /* finalize pxd corresponding to current xad */
-       XT_PUTENTRY(pxd, xad->flag, pstart, plen, paddr);
-
-       if (++npxd >= maxnpxd)
-               goto mapend;
-       pxd++;
-
-       /*
-        * lxd is fully covered by xad
-        */
-       if (lend <= xend) {
-               /*
-                * get next lxd
-                */
-               if (--nlxd == 0)
-                       goto mapend;
-               lxd++;
-
-               lstart = offsetLXD(lxd);
-               llen = lengthLXD(lxd);
-               lend = lstart + llen;
-               if (lstart >= size)
-                       goto mapend;
-
-               /*
-                * test for old xad covering new lxd
-                * (old xstart < new lstart)
-                */
-               goto compare2;
-       }
-       /*
-        * lxd is partially covered by xad
-        */
-       else {                  /* (xend < lend) */
-
-               /*
-                * get next xad
-                *
-                * linear search next xad covering lxd on
-                * the current xad page, and then next xad page search
-                */
-               if (index == le16_to_cpu(p->header.nextindex) - 1) {
-                       if (p->header.flag & BT_ROOT)
-                               goto mapend;
-
-                       if ((bn = le64_to_cpu(p->header.next)) == 0)
-                               goto mapend;
-
-                       XT_PUTPAGE(mp);
-
-                       /* get next sibling page */
-                       XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
-                       if (rc)
-                               return rc;
-
-                       index = XTENTRYSTART;
-                       xad = &p->xad[index];
-               } else {
-                       index++;
-                       xad++;
-               }
-
-               /*
-                * test for new xad covering old lxd
-                * (old lstart < new xstart)
-                */
-               goto compare;
-       }
-
-      mapend:
-       xadlist->nxad = npxd;
-
-//out:
-       XT_PUTPAGE(mp);
-
-       return rc;
-}
-
-
 /*
  *     xtSearch()
  *
index 70815c8a3d6a9114c481e6276b5fe8d35aacbfb2..08c0c749b986bd64e87265043ac5cf3b467ad2ac 100644 (file)
@@ -110,8 +110,6 @@ typedef union {
  */
 extern int xtLookup(struct inode *ip, s64 lstart, s64 llen,
                    int *pflag, s64 * paddr, int *plen, int flag);
-extern int xtLookupList(struct inode *ip, struct lxdlist * lxdlist,
-                       struct xadlist * xadlist, int flag);
 extern void xtInitRoot(tid_t tid, struct inode *ip);
 extern int xtInsert(tid_t tid, struct inode *ip,
                    int xflag, s64 xoff, int xlen, s64 * xaddrp, int flag);
index b37d1f78b854349d3681df7a88708f4310a266e4..6f21adf9479af7602009a736b5cede2b820db79c 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/posix_acl.h>
 #include <linux/buffer_head.h>
 #include <linux/exportfs.h>
+#include <linux/crc32.h>
 #include <asm/uaccess.h>
 #include <linux/seq_file.h>
 
@@ -168,6 +169,9 @@ static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_files = maxinodes;
        buf->f_ffree = maxinodes - (atomic_read(&imap->im_numinos) -
                                    atomic_read(&imap->im_numfree));
+       buf->f_fsid.val[0] = (u32)crc32_le(0, sbi->uuid, sizeof(sbi->uuid)/2);
+       buf->f_fsid.val[1] = (u32)crc32_le(0, sbi->uuid + sizeof(sbi->uuid)/2,
+                                       sizeof(sbi->uuid)/2);
 
        buf->f_namelen = JFS_NAME_MAX;
        return 0;
index aedc47a264c1f8ccf9d00eac8a46c298af58cac6..1f3b0fc0d351de0f6bd6ea7f48e3344e99f1fe56 100644 (file)
@@ -139,55 +139,6 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
        return 0;
 }
 
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static const struct in6_addr *nlmclnt_map_v4addr(const struct sockaddr *sap,
-                                                struct in6_addr *addr_mapped)
-{
-       const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
-
-       switch (sap->sa_family) {
-       case AF_INET6:
-               return &((const struct sockaddr_in6 *)sap)->sin6_addr;
-       case AF_INET:
-               ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, addr_mapped);
-               return addr_mapped;
-       }
-
-       return NULL;
-}
-
-/*
- * If lockd is using a PF_INET6 listener, all incoming requests appear
- * to come from AF_INET6 remotes.  The address of AF_INET remotes are
- * mapped to AF_INET6 automatically by the network layer.  In case the
- * user passed an AF_INET server address at mount time, ensure both
- * addresses are AF_INET6 before comparing them.
- */
-static int nlmclnt_cmp_addr(const struct nlm_host *host,
-                           const struct sockaddr *sap)
-{
-       const struct in6_addr *addr1;
-       const struct in6_addr *addr2;
-       struct in6_addr addr1_mapped;
-       struct in6_addr addr2_mapped;
-
-       addr1 = nlmclnt_map_v4addr(nlm_addr(host), &addr1_mapped);
-       if (likely(addr1 != NULL)) {
-               addr2 = nlmclnt_map_v4addr(sap, &addr2_mapped);
-               if (likely(addr2 != NULL))
-                       return ipv6_addr_equal(addr1, addr2);
-       }
-
-       return 0;
-}
-#else  /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
-static int nlmclnt_cmp_addr(const struct nlm_host *host,
-                           const struct sockaddr *sap)
-{
-       return nlm_cmp_addr(nlm_addr(host), sap);
-}
-#endif /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
-
 /*
  * The server lockd has called us back to tell us the lock was granted
  */
@@ -215,7 +166,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
                 */
                if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid)
                        continue;
-               if (!nlmclnt_cmp_addr(block->b_host, addr))
+               if (!nlm_cmp_addr(nlm_addr(block->b_host), addr))
                        continue;
                if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0)
                        continue;
index 5e2c4d5ac82774011072c05f5f039ec466fca59e..6d5d4a4169e5ae472dcf2ad43e46e0495c20fb05 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/lockd.h>
 
+#include <asm/unaligned.h>
+
 #define NLMDBG_FACILITY                NLMDBG_MONITOR
 #define NSM_PROGRAM            100024
 #define NSM_VERSION            1
@@ -274,10 +276,12 @@ static void nsm_init_private(struct nsm_handle *nsm)
 {
        u64 *p = (u64 *)&nsm->sm_priv.data;
        struct timespec ts;
+       s64 ns;
 
        ktime_get_ts(&ts);
-       *p++ = timespec_to_ns(&ts);
-       *p = (unsigned long)nsm;
+       ns = timespec_to_ns(&ts);
+       put_unaligned(ns, p);
+       put_unaligned((unsigned long)nsm, p + 1);
 }
 
 static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
index 64f1c31b58533317d65a256b79e1d5c474620421..abf83881f68a762f736b1a99faa16aff669256af 100644 (file)
@@ -52,17 +52,6 @@ static struct task_struct    *nlmsvc_task;
 static struct svc_rqst         *nlmsvc_rqst;
 unsigned long                  nlmsvc_timeout;
 
-/*
- * If the kernel has IPv6 support available, always listen for
- * both AF_INET and AF_INET6 requests.
- */
-#if (defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)) && \
-       defined(CONFIG_SUNRPC_REGISTER_V4)
-static const sa_family_t       nlmsvc_family = AF_INET6;
-#else  /* (CONFIG_IPV6 || CONFIG_IPV6_MODULE) && CONFIG_SUNRPC_REGISTER_V4 */
-static const sa_family_t       nlmsvc_family = AF_INET;
-#endif /* (CONFIG_IPV6 || CONFIG_IPV6_MODULE) && CONFIG_SUNRPC_REGISTER_V4 */
-
 /*
  * These can be set at insmod time (useful for NFS as root filesystem),
  * and also changed through the sysctl interface.  -- Jamie Lokier, Aug 2003
@@ -204,19 +193,30 @@ lockd(void *vrqstp)
        return 0;
 }
 
-static int create_lockd_listener(struct svc_serv *serv, char *name,
-                                unsigned short port)
+static int create_lockd_listener(struct svc_serv *serv, const char *name,
+                                const int family, const unsigned short port)
 {
        struct svc_xprt *xprt;
 
-       xprt = svc_find_xprt(serv, name, 0, 0);
+       xprt = svc_find_xprt(serv, name, family, 0);
        if (xprt == NULL)
-               return svc_create_xprt(serv, name, port, SVC_SOCK_DEFAULTS);
-
+               return svc_create_xprt(serv, name, family, port,
+                                               SVC_SOCK_DEFAULTS);
        svc_xprt_put(xprt);
        return 0;
 }
 
+static int create_lockd_family(struct svc_serv *serv, const int family)
+{
+       int err;
+
+       err = create_lockd_listener(serv, "udp", family, nlm_udpport);
+       if (err < 0)
+               return err;
+
+       return create_lockd_listener(serv, "tcp", family, nlm_tcpport);
+}
+
 /*
  * Ensure there are active UDP and TCP listeners for lockd.
  *
@@ -232,13 +232,15 @@ static int make_socks(struct svc_serv *serv)
        static int warned;
        int err;
 
-       err = create_lockd_listener(serv, "udp", nlm_udpport);
+       err = create_lockd_family(serv, PF_INET);
        if (err < 0)
                goto out_err;
 
-       err = create_lockd_listener(serv, "tcp", nlm_tcpport);
-       if (err < 0)
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       err = create_lockd_family(serv, PF_INET6);
+       if (err < 0 && err != -EAFNOSUPPORT)
                goto out_err;
+#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */
 
        warned = 0;
        return 0;
@@ -274,7 +276,7 @@ int lockd_up(void)
                        "lockd_up: no pid, %d users??\n", nlmsvc_users);
 
        error = -ENOMEM;
-       serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, nlmsvc_family, NULL);
+       serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL);
        if (!serv) {
                printk(KERN_WARNING "lockd_up: create service failed\n");
                goto out;
index 618865b3128ba7534a0971167ad608633591e31b..daad3c2740dbd5d85d7afee2f07c3ffdb8f996f3 100644 (file)
@@ -321,15 +321,20 @@ out:
 
 static int minix_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
-       struct minix_sb_info *sbi = minix_sb(dentry->d_sb);
-       buf->f_type = dentry->d_sb->s_magic;
-       buf->f_bsize = dentry->d_sb->s_blocksize;
+       struct super_block *sb = dentry->d_sb;
+       struct minix_sb_info *sbi = minix_sb(sb);
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
+       buf->f_type = sb->s_magic;
+       buf->f_bsize = sb->s_blocksize;
        buf->f_blocks = (sbi->s_nzones - sbi->s_firstdatazone) << sbi->s_log_zone_size;
        buf->f_bfree = minix_count_free_blocks(sbi);
        buf->f_bavail = buf->f_bfree;
        buf->f_files = sbi->s_ninodes;
        buf->f_ffree = minix_count_free_inodes(sbi);
        buf->f_namelen = sbi->s_namelen;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
+
        return 0;
 }
 
index 3e634f2a1083cf556e9c3429320e0cd458d3c5b1..a886e692ddd006359aa8b021f053e3b7f9904567 100644 (file)
@@ -38,19 +38,10 @@ static struct svc_program nfs4_callback_program;
 
 unsigned int nfs_callback_set_tcpport;
 unsigned short nfs_callback_tcpport;
+unsigned short nfs_callback_tcpport6;
 static const int nfs_set_port_min = 0;
 static const int nfs_set_port_max = 65535;
 
-/*
- * If the kernel has IPv6 support available, always listen for
- * both AF_INET and AF_INET6 requests.
- */
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static const sa_family_t       nfs_callback_family = AF_INET6;
-#else
-static const sa_family_t       nfs_callback_family = AF_INET;
-#endif
-
 static int param_set_port(const char *val, struct kernel_param *kp)
 {
        char *endp;
@@ -116,19 +107,29 @@ int nfs_callback_up(void)
        mutex_lock(&nfs_callback_mutex);
        if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
                goto out;
-       serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE,
-                               nfs_callback_family, NULL);
+       serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
        ret = -ENOMEM;
        if (!serv)
                goto out_err;
 
-       ret = svc_create_xprt(serv, "tcp", nfs_callback_set_tcpport,
-                             SVC_SOCK_ANONYMOUS);
+       ret = svc_create_xprt(serv, "tcp", PF_INET,
+                               nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
        if (ret <= 0)
                goto out_err;
        nfs_callback_tcpport = ret;
        dprintk("NFS: Callback listener port = %u (af %u)\n",
-                       nfs_callback_tcpport, nfs_callback_family);
+                       nfs_callback_tcpport, PF_INET);
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       ret = svc_create_xprt(serv, "tcp", PF_INET6,
+                               nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
+       if (ret > 0) {
+               nfs_callback_tcpport6 = ret;
+               dprintk("NFS: Callback listener port = %u (af %u)\n",
+                               nfs_callback_tcpport6, PF_INET6);
+       } else if (ret != -EAFNOSUPPORT)
+               goto out_err;
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
 
        nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]);
        if (IS_ERR(nfs_callback_info.rqst)) {
index bb25d2135ff1e7e15ead85466b5c36a0de5737cf..e110e286a26217d681b8a26e4165d5fff3a7b75d 100644 (file)
@@ -72,5 +72,6 @@ extern void nfs_callback_down(void);
 
 extern unsigned int nfs_callback_set_tcpport;
 extern unsigned short nfs_callback_tcpport;
+extern unsigned short nfs_callback_tcpport6;
 
 #endif /* __LINUX_FS_NFS_CALLBACK_H */
index 574158ae2398aaeb1151d76f0a85f2b73871b976..aba38017bdefc9773cc498090cca4766dcf2d863 100644 (file)
@@ -224,38 +224,6 @@ void nfs_put_client(struct nfs_client *clp)
 }
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static const struct in6_addr *nfs_map_ipv4_addr(const struct sockaddr *sa, struct in6_addr *addr_mapped)
-{
-       switch (sa->sa_family) {
-               default:
-                       return NULL;
-               case AF_INET6:
-                       return &((const struct sockaddr_in6 *)sa)->sin6_addr;
-                       break;
-               case AF_INET:
-                       ipv6_addr_set_v4mapped(((const struct sockaddr_in *)sa)->sin_addr.s_addr,
-                                       addr_mapped);
-                       return addr_mapped;
-       }
-}
-
-static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
-               const struct sockaddr *sa2)
-{
-       const struct in6_addr *addr1;
-       const struct in6_addr *addr2;
-       struct in6_addr addr1_mapped;
-       struct in6_addr addr2_mapped;
-
-       addr1 = nfs_map_ipv4_addr(sa1, &addr1_mapped);
-       if (likely(addr1 != NULL)) {
-               addr2 = nfs_map_ipv4_addr(sa2, &addr2_mapped);
-               if (likely(addr2 != NULL))
-                       return ipv6_addr_equal(addr1, addr2);
-       }
-       return 0;
-}
-
 /*
  * Test if two ip6 socket addresses refer to the same socket by
  * comparing relevant fields. The padding bytes specifically, are not
@@ -267,38 +235,21 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
  *
  * The caller should ensure both socket addresses are AF_INET6.
  */
-static int nfs_sockaddr_cmp_ip6(const struct sockaddr *sa1,
-                               const struct sockaddr *sa2)
+static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1,
+                                     const struct sockaddr *sa2)
 {
-       const struct sockaddr_in6 *saddr1 = (const struct sockaddr_in6 *)sa1;
-       const struct sockaddr_in6 *saddr2 = (const struct sockaddr_in6 *)sa2;
+       const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
+       const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
 
-       if (!ipv6_addr_equal(&saddr1->sin6_addr,
-                            &saddr1->sin6_addr))
+       if (ipv6_addr_scope(&sin1->sin6_addr) == IPV6_ADDR_SCOPE_LINKLOCAL &&
+           sin1->sin6_scope_id != sin2->sin6_scope_id)
                return 0;
-       if (ipv6_addr_scope(&saddr1->sin6_addr) == IPV6_ADDR_SCOPE_LINKLOCAL &&
-           saddr1->sin6_scope_id != saddr2->sin6_scope_id)
-               return 0;
-       return saddr1->sin6_port == saddr2->sin6_port;
-}
-#else
-static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1,
-                                const struct sockaddr_in *sa2)
-{
-       return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr;
-}
 
-static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
-                                const struct sockaddr *sa2)
-{
-       if (unlikely(sa1->sa_family != AF_INET || sa2->sa_family != AF_INET))
-               return 0;
-       return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1,
-                       (const struct sockaddr_in *)sa2);
+       return ipv6_addr_equal(&sin1->sin6_addr, &sin1->sin6_addr);
 }
-
-static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1,
-                               const struct sockaddr * sa2)
+#else  /* !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) */
+static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1,
+                                     const struct sockaddr *sa2)
 {
        return 0;
 }
@@ -311,20 +262,57 @@ static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1,
  *
  * The caller should ensure both socket addresses are AF_INET.
  */
+static int nfs_sockaddr_match_ipaddr4(const struct sockaddr *sa1,
+                                     const struct sockaddr *sa2)
+{
+       const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
+       const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
+
+       return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
+}
+
+static int nfs_sockaddr_cmp_ip6(const struct sockaddr *sa1,
+                               const struct sockaddr *sa2)
+{
+       const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
+       const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
+
+       return nfs_sockaddr_match_ipaddr6(sa1, sa2) &&
+               (sin1->sin6_port == sin2->sin6_port);
+}
+
 static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1,
                                const struct sockaddr *sa2)
 {
-       const struct sockaddr_in *saddr1 = (const struct sockaddr_in *)sa1;
-       const struct sockaddr_in *saddr2 = (const struct sockaddr_in *)sa2;
+       const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
+       const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
+
+       return nfs_sockaddr_match_ipaddr4(sa1, sa2) &&
+               (sin1->sin_port == sin2->sin_port);
+}
 
-       if (saddr1->sin_addr.s_addr != saddr2->sin_addr.s_addr)
+/*
+ * Test if two socket addresses represent the same actual socket,
+ * by comparing (only) relevant fields, excluding the port number.
+ */
+static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
+                                    const struct sockaddr *sa2)
+{
+       if (sa1->sa_family != sa2->sa_family)
                return 0;
-       return saddr1->sin_port == saddr2->sin_port;
+
+       switch (sa1->sa_family) {
+       case AF_INET:
+               return nfs_sockaddr_match_ipaddr4(sa1, sa2);
+       case AF_INET6:
+               return nfs_sockaddr_match_ipaddr6(sa1, sa2);
+       }
+       return 0;
 }
 
 /*
  * Test if two socket addresses represent the same actual socket,
- * by comparing (only) relevant fields.
+ * by comparing (only) relevant fields, including the port number.
  */
 static int nfs_sockaddr_cmp(const struct sockaddr *sa1,
                            const struct sockaddr *sa2)
@@ -1606,8 +1594,6 @@ int __init nfs_fs_proc_init(void)
        if (!proc_fs_nfs)
                goto error_0;
 
-       proc_fs_nfs->owner = THIS_MODULE;
-
        /* a file of servers with which we're dealing */
        p = proc_create("servers", S_IFREG|S_IRUGO,
                        proc_fs_nfs, &nfs_server_list_fops);
index 78bf72fc1db3a79fe08ae65c77960eff1326443f..370b190a09d1d7ac7d03fe1cd45457ec866749a4 100644 (file)
@@ -1624,8 +1624,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                } else if (atomic_read(&new_dentry->d_count) > 1)
                        /* dentry still busy? */
                        goto out;
-       } else
-               nfs_drop_nlink(new_inode);
+       }
 
 go_ahead:
        /*
@@ -1638,10 +1637,8 @@ go_ahead:
        }
        nfs_inode_return_delegation(old_inode);
 
-       if (new_inode != NULL) {
+       if (new_inode != NULL)
                nfs_inode_return_delegation(new_inode);
-               d_delete(new_dentry);
-       }
 
        error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
                                           new_dir, &new_dentry->d_name);
@@ -1650,6 +1647,8 @@ out:
        if (rehash)
                d_rehash(rehash);
        if (!error) {
+               if (new_inode != NULL)
+                       nfs_drop_nlink(new_inode);
                d_move(old_dentry, new_dentry);
                nfs_set_verifier(new_dentry,
                                        nfs_save_change_attribute(new_dir));
index 90f292b520d25eec248a9728b7d61cf20cd061f9..0abf3f331f56c6a20249a00bd4719cb1cd3b9112 100644 (file)
@@ -64,11 +64,7 @@ const struct file_operations nfs_file_operations = {
        .write          = do_sync_write,
        .aio_read       = nfs_file_read,
        .aio_write      = nfs_file_write,
-#ifdef CONFIG_MMU
        .mmap           = nfs_file_mmap,
-#else
-       .mmap           = generic_file_mmap,
-#endif
        .open           = nfs_file_open,
        .flush          = nfs_file_flush,
        .release        = nfs_file_release,
@@ -141,9 +137,6 @@ nfs_file_release(struct inode *inode, struct file *filp)
                        dentry->d_parent->d_name.name,
                        dentry->d_name.name);
 
-       /* Ensure that dirty pages are flushed out with the right creds */
-       if (filp->f_mode & FMODE_WRITE)
-               nfs_wb_all(dentry->d_inode);
        nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
        return nfs_release(inode, filp);
 }
@@ -235,7 +228,6 @@ nfs_file_flush(struct file *file, fl_owner_t id)
        struct nfs_open_context *ctx = nfs_file_open_context(file);
        struct dentry   *dentry = file->f_path.dentry;
        struct inode    *inode = dentry->d_inode;
-       int             status;
 
        dprintk("NFS: flush(%s/%s)\n",
                        dentry->d_parent->d_name.name,
@@ -245,11 +237,8 @@ nfs_file_flush(struct file *file, fl_owner_t id)
                return 0;
        nfs_inc_stats(inode, NFSIOS_VFSFLUSH);
 
-       /* Ensure that data+attribute caches are up to date after close() */
-       status = nfs_do_fsync(ctx, inode);
-       if (!status)
-               nfs_revalidate_inode(NFS_SERVER(inode), inode);
-       return status;
+       /* Flush writes to the server and return any errors */
+       return nfs_do_fsync(ctx, inode);
 }
 
 static ssize_t
@@ -304,11 +293,13 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
        dprintk("NFS: mmap(%s/%s)\n",
                dentry->d_parent->d_name.name, dentry->d_name.name);
 
-       status = nfs_revalidate_mapping(inode, file->f_mapping);
+       /* Note: generic_file_mmap() returns ENOSYS on nommu systems
+        *       so we call that before revalidating the mapping
+        */
+       status = generic_file_mmap(file, vma);
        if (!status) {
                vma->vm_ops = &nfs_file_vm_ops;
-               vma->vm_flags |= VM_CAN_NONLINEAR;
-               file_accessed(file);
+               status = nfs_revalidate_mapping(inode, file->f_mapping);
        }
        return status;
 }
@@ -354,6 +345,15 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
                file->f_path.dentry->d_name.name,
                mapping->host->i_ino, len, (long long) pos);
 
+       /*
+        * Prevent starvation issues if someone is doing a consistency
+        * sync-to-disk
+        */
+       ret = wait_on_bit(&NFS_I(mapping->host)->flags, NFS_INO_FLUSHING,
+                       nfs_wait_bit_killable, TASK_KILLABLE);
+       if (ret)
+               return ret;
+
        page = grab_cache_page_write_begin(mapping, index, flags);
        if (!page)
                return -ENOMEM;
@@ -451,8 +451,9 @@ const struct address_space_operations nfs_file_aops = {
        .launder_page = nfs_launder_page,
 };
 
-static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
+       struct page *page = vmf->page;
        struct file *filp = vma->vm_file;
        struct dentry *dentry = filp->f_path.dentry;
        unsigned pagelen;
@@ -483,6 +484,8 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
                ret = pagelen;
 out_unlock:
        unlock_page(page);
+       if (ret)
+               ret = VM_FAULT_SIGBUS;
        return ret;
 }
 
index b7c9b2df1f299dd15d30b81d533b602d8ae09572..46177cb8706402cff250c18a7b10640deee0b38f 100644 (file)
@@ -156,7 +156,7 @@ int nfs4_path_walk(struct nfs_server *server,
                return ret;
        }
 
-       if (fattr.type != NFDIR) {
+       if (!S_ISDIR(fattr.mode)) {
                printk(KERN_ERR "nfs4_get_root:"
                       " getroot encountered non-directory\n");
                return -ENOTDIR;
@@ -213,7 +213,7 @@ eat_dot_dir:
                return ret;
        }
 
-       if (fattr.type != NFDIR) {
+       if (!S_ISDIR(fattr.mode)) {
                printk(KERN_ERR "nfs4_get_root:"
                       " lookupfh encountered non-directory\n");
                return -ENOTDIR;
index 0c381686171e30cc1eab1f71128bce7837bd22dd..a834d1d850b78caf0df89e3f293b9f4b9efb88e7 100644 (file)
@@ -65,6 +65,18 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
        return nfs_fileid_to_ino_t(fattr->fileid);
 }
 
+/**
+ * nfs_wait_bit_killable - helper for functions that are sleeping on bit locks
+ * @word: long word containing the bit lock
+ */
+int nfs_wait_bit_killable(void *word)
+{
+       if (fatal_signal_pending(current))
+               return -ERESTARTSYS;
+       schedule();
+       return 0;
+}
+
 /**
  * nfs_compat_user_ino64 - returns the user-visible inode number
  * @fileid: 64-bit fileid
@@ -249,13 +261,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
        struct inode *inode = ERR_PTR(-ENOENT);
        unsigned long hash;
 
-       if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+       if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0)
                goto out_no_inode;
-
-       if (!fattr->nlink) {
-               printk("NFS: Buggy server - nlink == 0!\n");
+       if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0)
                goto out_no_inode;
-       }
 
        hash = nfs_fattr_to_ino_t(fattr);
 
@@ -291,7 +300,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
                            && fattr->size <= NFS_LIMIT_READDIRPLUS)
                                set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
                        /* Deal with crossing mountpoints */
-                       if (!nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) {
+                       if ((fattr->valid & NFS_ATTR_FATTR_FSID)
+                                       && !nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) {
                                if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
                                        inode->i_op = &nfs_referral_inode_operations;
                                else
@@ -304,28 +314,45 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
                else
                        init_special_inode(inode, inode->i_mode, fattr->rdev);
 
+               memset(&inode->i_atime, 0, sizeof(inode->i_atime));
+               memset(&inode->i_mtime, 0, sizeof(inode->i_mtime));
+               memset(&inode->i_ctime, 0, sizeof(inode->i_ctime));
+               nfsi->change_attr = 0;
+               inode->i_size = 0;
+               inode->i_nlink = 0;
+               inode->i_uid = -2;
+               inode->i_gid = -2;
+               inode->i_blocks = 0;
+               memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
+
                nfsi->read_cache_jiffies = fattr->time_start;
                nfsi->attr_gencount = fattr->gencount;
-               inode->i_atime = fattr->atime;
-               inode->i_mtime = fattr->mtime;
-               inode->i_ctime = fattr->ctime;
-               if (fattr->valid & NFS_ATTR_FATTR_V4)
+               if (fattr->valid & NFS_ATTR_FATTR_ATIME)
+                       inode->i_atime = fattr->atime;
+               if (fattr->valid & NFS_ATTR_FATTR_MTIME)
+                       inode->i_mtime = fattr->mtime;
+               if (fattr->valid & NFS_ATTR_FATTR_CTIME)
+                       inode->i_ctime = fattr->ctime;
+               if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
                        nfsi->change_attr = fattr->change_attr;
-               inode->i_size = nfs_size_to_loff_t(fattr->size);
-               inode->i_nlink = fattr->nlink;
-               inode->i_uid = fattr->uid;
-               inode->i_gid = fattr->gid;
-               if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
+               if (fattr->valid & NFS_ATTR_FATTR_SIZE)
+                       inode->i_size = nfs_size_to_loff_t(fattr->size);
+               if (fattr->valid & NFS_ATTR_FATTR_NLINK)
+                       inode->i_nlink = fattr->nlink;
+               if (fattr->valid & NFS_ATTR_FATTR_OWNER)
+                       inode->i_uid = fattr->uid;
+               if (fattr->valid & NFS_ATTR_FATTR_GROUP)
+                       inode->i_gid = fattr->gid;
+               if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
+                       inode->i_blocks = fattr->du.nfs2.blocks;
+               if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
                        /*
                         * report the blocks in 512byte units
                         */
                        inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
-               } else {
-                       inode->i_blocks = fattr->du.nfs2.blocks;
                }
                nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
                nfsi->attrtimeo_timestamp = now;
-               memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
                nfsi->access_cache = RB_ROOT;
 
                unlock_new_inode(inode);
@@ -514,6 +541,32 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
        return err;
 }
 
+/**
+ * nfs_close_context - Common close_context() routine NFSv2/v3
+ * @ctx: pointer to context
+ * @is_sync: is this a synchronous close
+ *
+ * always ensure that the attributes are up to date if we're mounted
+ * with close-to-open semantics
+ */
+void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
+{
+       struct inode *inode;
+       struct nfs_server *server;
+
+       if (!(ctx->mode & FMODE_WRITE))
+               return;
+       if (!is_sync)
+               return;
+       inode = ctx->path.dentry->d_inode;
+       if (!list_empty(&NFS_I(inode)->open_files))
+               return;
+       server = NFS_SERVER(inode);
+       if (server->flags & NFS_MOUNT_NOCTO)
+               return;
+       nfs_revalidate_inode(server, inode);
+}
+
 static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, struct dentry *dentry, struct rpc_cred *cred)
 {
        struct nfs_open_context *ctx;
@@ -540,24 +593,15 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
        return ctx;
 }
 
-static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait)
+static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
 {
-       struct inode *inode;
-
-       if (ctx == NULL)
-               return;
+       struct inode *inode = ctx->path.dentry->d_inode;
 
-       inode = ctx->path.dentry->d_inode;
        if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock))
                return;
        list_del(&ctx->list);
        spin_unlock(&inode->i_lock);
-       if (ctx->state != NULL) {
-               if (wait)
-                       nfs4_close_sync(&ctx->path, ctx->state, ctx->mode);
-               else
-                       nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
-       }
+       NFS_PROTO(inode)->close_context(ctx, is_sync);
        if (ctx->cred != NULL)
                put_rpccred(ctx->cred);
        path_put(&ctx->path);
@@ -670,9 +714,6 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
        if (NFS_STALE(inode))
                goto out;
 
-       if (NFS_STALE(inode))
-               goto out;
-
        nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
        status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr);
        if (status != 0) {
@@ -815,25 +856,31 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
 
-       if ((fattr->valid & NFS_ATTR_WCC_V4) != 0 &&
-                       nfsi->change_attr == fattr->pre_change_attr) {
+       if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE)
+                       && (fattr->valid & NFS_ATTR_FATTR_CHANGE)
+                       && nfsi->change_attr == fattr->pre_change_attr) {
                nfsi->change_attr = fattr->change_attr;
                if (S_ISDIR(inode->i_mode))
                        nfsi->cache_validity |= NFS_INO_INVALID_DATA;
        }
        /* If we have atomic WCC data, we may update some attributes */
-       if ((fattr->valid & NFS_ATTR_WCC) != 0) {
-               if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
+       if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME)
+                       && (fattr->valid & NFS_ATTR_FATTR_CTIME)
+                       && timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
                        memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
-               if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
+
+       if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME)
+                       && (fattr->valid & NFS_ATTR_FATTR_MTIME)
+                       && timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
                        memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
                        if (S_ISDIR(inode->i_mode))
                                nfsi->cache_validity |= NFS_INO_INVALID_DATA;
-               }
-               if (i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size) &&
-                   nfsi->npages == 0)
-                       i_size_write(inode, nfs_size_to_loff_t(fattr->size));
        }
+       if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE)
+                       && (fattr->valid & NFS_ATTR_FATTR_SIZE)
+                       && i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size)
+                       && nfsi->npages == 0)
+                       i_size_write(inode, nfs_size_to_loff_t(fattr->size));
 }
 
 /**
@@ -853,35 +900,39 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
 
 
        /* Has the inode gone and changed behind our back? */
-       if (nfsi->fileid != fattr->fileid
-                       || (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) {
+       if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
+               return -EIO;
+       if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
                return -EIO;
-       }
 
-       if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
+       if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
                        nfsi->change_attr != fattr->change_attr)
                invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
 
        /* Verify a few of the more important attributes */
-       if (!timespec_equal(&inode->i_mtime, &fattr->mtime))
+       if ((fattr->valid & NFS_ATTR_FATTR_MTIME) && !timespec_equal(&inode->i_mtime, &fattr->mtime))
                invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
 
-       cur_size = i_size_read(inode);
-       new_isize = nfs_size_to_loff_t(fattr->size);
-       if (cur_size != new_isize && nfsi->npages == 0)
-               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
+       if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
+               cur_size = i_size_read(inode);
+               new_isize = nfs_size_to_loff_t(fattr->size);
+               if (cur_size != new_isize && nfsi->npages == 0)
+                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
+       }
 
        /* Have any file permissions changed? */
-       if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
-                       || inode->i_uid != fattr->uid
-                       || inode->i_gid != fattr->gid)
+       if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO))
+               invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
+       if ((fattr->valid & NFS_ATTR_FATTR_OWNER) && inode->i_uid != fattr->uid)
+               invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
+       if ((fattr->valid & NFS_ATTR_FATTR_GROUP) && inode->i_gid != fattr->gid)
                invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
 
        /* Has the link count changed? */
-       if (inode->i_nlink != fattr->nlink)
+       if ((fattr->valid & NFS_ATTR_FATTR_NLINK) && inode->i_nlink != fattr->nlink)
                invalid |= NFS_INO_INVALID_ATTR;
 
-       if (!timespec_equal(&inode->i_atime, &fattr->atime))
+       if ((fattr->valid & NFS_ATTR_FATTR_ATIME) && !timespec_equal(&inode->i_atime, &fattr->atime))
                invalid |= NFS_INO_INVALID_ATIME;
 
        if (invalid != 0)
@@ -893,11 +944,15 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
 
 static int nfs_ctime_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
 {
+       if (!(fattr->valid & NFS_ATTR_FATTR_CTIME))
+               return 0;
        return timespec_compare(&fattr->ctime, &inode->i_ctime) > 0;
 }
 
 static int nfs_size_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
 {
+       if (!(fattr->valid & NFS_ATTR_FATTR_SIZE))
+               return 0;
        return nfs_size_to_loff_t(fattr->size) > i_size_read(inode);
 }
 
@@ -1033,20 +1088,31 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
        /* Don't do a WCC update if these attributes are already stale */
        if ((fattr->valid & NFS_ATTR_FATTR) == 0 ||
                        !nfs_inode_attrs_need_update(inode, fattr)) {
-               fattr->valid &= ~(NFS_ATTR_WCC_V4|NFS_ATTR_WCC);
+               fattr->valid &= ~(NFS_ATTR_FATTR_PRECHANGE
+                               | NFS_ATTR_FATTR_PRESIZE
+                               | NFS_ATTR_FATTR_PREMTIME
+                               | NFS_ATTR_FATTR_PRECTIME);
                goto out_noforce;
        }
-       if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
-                       (fattr->valid & NFS_ATTR_WCC_V4) == 0) {
+       if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
+                       (fattr->valid & NFS_ATTR_FATTR_PRECHANGE) == 0) {
                fattr->pre_change_attr = NFS_I(inode)->change_attr;
-               fattr->valid |= NFS_ATTR_WCC_V4;
+               fattr->valid |= NFS_ATTR_FATTR_PRECHANGE;
        }
-       if ((fattr->valid & NFS_ATTR_FATTR) != 0 &&
-                       (fattr->valid & NFS_ATTR_WCC) == 0) {
+       if ((fattr->valid & NFS_ATTR_FATTR_CTIME) != 0 &&
+                       (fattr->valid & NFS_ATTR_FATTR_PRECTIME) == 0) {
                memcpy(&fattr->pre_ctime, &inode->i_ctime, sizeof(fattr->pre_ctime));
+               fattr->valid |= NFS_ATTR_FATTR_PRECTIME;
+       }
+       if ((fattr->valid & NFS_ATTR_FATTR_MTIME) != 0 &&
+                       (fattr->valid & NFS_ATTR_FATTR_PREMTIME) == 0) {
                memcpy(&fattr->pre_mtime, &inode->i_mtime, sizeof(fattr->pre_mtime));
+               fattr->valid |= NFS_ATTR_FATTR_PREMTIME;
+       }
+       if ((fattr->valid & NFS_ATTR_FATTR_SIZE) != 0 &&
+                       (fattr->valid & NFS_ATTR_FATTR_PRESIZE) == 0) {
                fattr->pre_size = i_size_read(inode);
-               fattr->valid |= NFS_ATTR_WCC;
+               fattr->valid |= NFS_ATTR_FATTR_PRESIZE;
        }
 out_noforce:
        status = nfs_post_op_update_inode_locked(inode, fattr);
@@ -1078,18 +1144,18 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        __func__, inode->i_sb->s_id, inode->i_ino,
                        atomic_read(&inode->i_count), fattr->valid);
 
-       if (nfsi->fileid != fattr->fileid)
+       if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
                goto out_fileid;
 
        /*
         * Make sure the inode's type hasn't changed.
         */
-       if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
+       if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
                goto out_changed;
 
        server = NFS_SERVER(inode);
        /* Update the fsid? */
-       if (S_ISDIR(inode->i_mode) &&
+       if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) &&
                        !nfs_fsid_equal(&server->fsid, &fattr->fsid) &&
                        !test_bit(NFS_INO_MOUNTPOINT, &nfsi->flags))
                server->fsid = fattr->fsid;
@@ -1099,14 +1165,27 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
         */
        nfsi->read_cache_jiffies = fattr->time_start;
 
-       nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ATIME
-                       | NFS_INO_REVAL_PAGECACHE);
+       if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) || (fattr->valid & (NFS_ATTR_FATTR_MTIME|NFS_ATTR_FATTR_CTIME)))
+           nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
+                   | NFS_INO_INVALID_ATIME
+                   | NFS_INO_REVAL_PAGECACHE);
 
        /* Do atomic weak cache consistency updates */
        nfs_wcc_update_inode(inode, fattr);
 
        /* More cache consistency checks */
-       if (!(fattr->valid & NFS_ATTR_FATTR_V4)) {
+       if (fattr->valid & NFS_ATTR_FATTR_CHANGE) {
+               if (nfsi->change_attr != fattr->change_attr) {
+                       dprintk("NFS: change_attr change on server for file %s/%ld\n",
+                                       inode->i_sb->s_id, inode->i_ino);
+                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+                       if (S_ISDIR(inode->i_mode))
+                               nfs_force_lookup_revalidate(inode);
+                       nfsi->change_attr = fattr->change_attr;
+               }
+       }
+
+       if (fattr->valid & NFS_ATTR_FATTR_MTIME) {
                /* NFSv2/v3: Check if the mtime agrees */
                if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
                        dprintk("NFS: mtime change on server for file %s/%ld\n",
@@ -1114,59 +1193,80 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
                        if (S_ISDIR(inode->i_mode))
                                nfs_force_lookup_revalidate(inode);
+                       memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
                }
+       }
+       if (fattr->valid & NFS_ATTR_FATTR_CTIME) {
                /* If ctime has changed we should definitely clear access+acl caches */
-               if (!timespec_equal(&inode->i_ctime, &fattr->ctime))
+               if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) {
                        invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
-       } else if (nfsi->change_attr != fattr->change_attr) {
-               dprintk("NFS: change_attr change on server for file %s/%ld\n",
-                               inode->i_sb->s_id, inode->i_ino);
-               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
-               if (S_ISDIR(inode->i_mode))
-                       nfs_force_lookup_revalidate(inode);
+                       /* and probably clear data for a directory too as utimes can cause
+                        * havoc with our cache.
+                        */
+                       if (S_ISDIR(inode->i_mode)) {
+                               invalid |= NFS_INO_INVALID_DATA;
+                               nfs_force_lookup_revalidate(inode);
+                       }
+                       memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
+               }
        }
 
        /* Check if our cached file size is stale */
-       new_isize = nfs_size_to_loff_t(fattr->size);
-       cur_isize = i_size_read(inode);
-       if (new_isize != cur_isize) {
-               /* Do we perhaps have any outstanding writes, or has
-                * the file grown beyond our last write? */
-               if (nfsi->npages == 0 || new_isize > cur_isize) {
-                       i_size_write(inode, new_isize);
-                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+       if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
+               new_isize = nfs_size_to_loff_t(fattr->size);
+               cur_isize = i_size_read(inode);
+               if (new_isize != cur_isize) {
+                       /* Do we perhaps have any outstanding writes, or has
+                        * the file grown beyond our last write? */
+                       if (nfsi->npages == 0 || new_isize > cur_isize) {
+                               i_size_write(inode, new_isize);
+                               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+                       }
+                       dprintk("NFS: isize change on server for file %s/%ld\n",
+                                       inode->i_sb->s_id, inode->i_ino);
                }
-               dprintk("NFS: isize change on server for file %s/%ld\n",
-                               inode->i_sb->s_id, inode->i_ino);
        }
 
 
-       memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
-       memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
-       memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
-       nfsi->change_attr = fattr->change_attr;
-
-       if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) ||
-           inode->i_uid != fattr->uid ||
-           inode->i_gid != fattr->gid)
-               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+       if (fattr->valid & NFS_ATTR_FATTR_ATIME)
+               memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
 
-       if (inode->i_nlink != fattr->nlink)
-               invalid |= NFS_INO_INVALID_ATTR;
+       if (fattr->valid & NFS_ATTR_FATTR_MODE) {
+               if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) {
+                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+                       inode->i_mode = fattr->mode;
+               }
+       }
+       if (fattr->valid & NFS_ATTR_FATTR_OWNER) {
+               if (inode->i_uid != fattr->uid) {
+                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+                       inode->i_uid = fattr->uid;
+               }
+       }
+       if (fattr->valid & NFS_ATTR_FATTR_GROUP) {
+               if (inode->i_gid != fattr->gid) {
+                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+                       inode->i_gid = fattr->gid;
+               }
+       }
 
-       inode->i_mode = fattr->mode;
-       inode->i_nlink = fattr->nlink;
-       inode->i_uid = fattr->uid;
-       inode->i_gid = fattr->gid;
+       if (fattr->valid & NFS_ATTR_FATTR_NLINK) {
+               if (inode->i_nlink != fattr->nlink) {
+                       invalid |= NFS_INO_INVALID_ATTR;
+                       if (S_ISDIR(inode->i_mode))
+                               invalid |= NFS_INO_INVALID_DATA;
+                       inode->i_nlink = fattr->nlink;
+               }
+       }
 
-       if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
+       if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
                /*
                 * report the blocks in 512byte units
                 */
                inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
-       } else {
-               inode->i_blocks = fattr->du.nfs2.blocks;
        }
+       if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
+               inode->i_blocks = fattr->du.nfs2.blocks;
 
        /* Update attrtimeo value if we're out of the unstable period */
        if (invalid & NFS_INO_INVALID_ATTR) {
@@ -1274,7 +1374,6 @@ static void init_once(void *foo)
        INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
        INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
        INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
-       nfsi->ncommit = 0;
        nfsi->npages = 0;
        atomic_set(&nfsi->silly_count, 1);
        INIT_HLIST_HEAD(&nfsi->silly_list);
index 340ede8f608fe3402952890e7d82f26c004cbb65..2041f68ff1cc1129d41d7fd55b4749714113d4c9 100644 (file)
@@ -152,6 +152,9 @@ extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
 extern struct rpc_procinfo nfs4_procedures[];
 #endif
 
+/* proc.c */
+void nfs_close_context(struct nfs_open_context *ctx, int is_sync);
+
 /* dir.c */
 extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask);
 
@@ -165,6 +168,7 @@ extern void nfs_clear_inode(struct inode *);
 extern void nfs4_clear_inode(struct inode *);
 #endif
 void nfs_zap_acl_cache(struct inode *inode);
+extern int nfs_wait_bit_killable(void *word);
 
 /* super.c */
 void nfs_parse_ip_address(char *, size_t, struct sockaddr *, size_t *);
index 28bab67d1519bc23b1db1d190713e7971fe79d94..c862c9340f9a4598d3391c44d557187ec5b06871 100644 (file)
@@ -120,8 +120,8 @@ xdr_decode_time(__be32 *p, struct timespec *timep)
 static __be32 *
 xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
 {
-       u32 rdev;
-       fattr->type = (enum nfs_ftype) ntohl(*p++);
+       u32 rdev, type;
+       type = ntohl(*p++);
        fattr->mode = ntohl(*p++);
        fattr->nlink = ntohl(*p++);
        fattr->uid = ntohl(*p++);
@@ -136,10 +136,9 @@ xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
        p = xdr_decode_time(p, &fattr->atime);
        p = xdr_decode_time(p, &fattr->mtime);
        p = xdr_decode_time(p, &fattr->ctime);
-       fattr->valid |= NFS_ATTR_FATTR;
+       fattr->valid |= NFS_ATTR_FATTR_V2;
        fattr->rdev = new_decode_dev(rdev);
-       if (fattr->type == NFCHR && rdev == NFS2_FIFO_DEV) {
-               fattr->type = NFFIFO;
+       if (type == NFCHR && rdev == NFS2_FIFO_DEV) {
                fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
                fattr->rdev = 0;
        }
index c55be7a7679e27f6c011766add0b2bf8e9cfc447..b82fe6847f14ebfeba27f3bf01303f6f4df63236 100644 (file)
@@ -834,4 +834,5 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
        .commit_done    = nfs3_commit_done,
        .lock           = nfs3_proc_lock,
        .clear_acl_cache = nfs3_forget_cached_acls,
+       .close_context  = nfs_close_context,
 };
index 6cdeacffde469143045588c6b20e6cff72cc586a..e6a1932c7110a245d77b0595d7ad57778ee3aad6 100644 (file)
 /*
  * Map file type to S_IFMT bits
  */
-static struct {
-       unsigned int    mode;
-       unsigned int    nfs2type;
-} nfs_type2fmt[] = {
-      { 0,             NFNON   },
-      { S_IFREG,       NFREG   },
-      { S_IFDIR,       NFDIR   },
-      { S_IFBLK,       NFBLK   },
-      { S_IFCHR,       NFCHR   },
-      { S_IFLNK,       NFLNK   },
-      { S_IFSOCK,      NFSOCK  },
-      { S_IFIFO,       NFFIFO  },
-      { 0,             NFBAD   }
+static const umode_t nfs_type2fmt[] = {
+       [NF3BAD] = 0,
+       [NF3REG] = S_IFREG,
+       [NF3DIR] = S_IFDIR,
+       [NF3BLK] = S_IFBLK,
+       [NF3CHR] = S_IFCHR,
+       [NF3LNK] = S_IFLNK,
+       [NF3SOCK] = S_IFSOCK,
+       [NF3FIFO] = S_IFIFO,
 };
 
 /*
@@ -148,13 +144,12 @@ static __be32 *
 xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
 {
        unsigned int    type, major, minor;
-       int             fmode;
+       umode_t         fmode;
 
        type = ntohl(*p++);
-       if (type >= NF3BAD)
-               type = NF3BAD;
-       fmode = nfs_type2fmt[type].mode;
-       fattr->type = nfs_type2fmt[type].nfs2type;
+       if (type > NF3FIFO)
+               type = NF3NON;
+       fmode = nfs_type2fmt[type];
        fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
        fattr->nlink = ntohl(*p++);
        fattr->uid = ntohl(*p++);
@@ -177,7 +172,7 @@ xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
        p = xdr_decode_time3(p, &fattr->ctime);
 
        /* Update the mode bits */
-       fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
+       fattr->valid |= NFS_ATTR_FATTR_V3;
        return p;
 }
 
@@ -233,7 +228,9 @@ xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
        p = xdr_decode_hyper(p, &fattr->pre_size);
        p = xdr_decode_time3(p, &fattr->pre_mtime);
        p = xdr_decode_time3(p, &fattr->pre_ctime);
-       fattr->valid |= NFS_ATTR_WCC;
+       fattr->valid |= NFS_ATTR_FATTR_PRESIZE
+               | NFS_ATTR_FATTR_PREMTIME
+               | NFS_ATTR_FATTR_PRECTIME;
        return p;
 }
 
index 8dde84b988d9cd349604eb4663a70fc4333fe367..97bacccff57947fe756dc8bae29ad06e57d0159b 100644 (file)
@@ -193,14 +193,6 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
        kunmap_atomic(start, KM_USER0);
 }
 
-static int nfs4_wait_bit_killable(void *word)
-{
-       if (fatal_signal_pending(current))
-               return -ERESTARTSYS;
-       schedule();
-       return 0;
-}
-
 static int nfs4_wait_clnt_recover(struct nfs_client *clp)
 {
        int res;
@@ -208,7 +200,7 @@ static int nfs4_wait_clnt_recover(struct nfs_client *clp)
        might_sleep();
 
        res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING,
-                       nfs4_wait_bit_killable, TASK_KILLABLE);
+                       nfs_wait_bit_killable, TASK_KILLABLE);
        return res;
 }
 
@@ -1439,7 +1431,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
        if (calldata->arg.seqid == NULL)
                goto out_free_calldata;
        calldata->arg.fmode = 0;
-       calldata->arg.bitmask = server->attr_bitmask;
+       calldata->arg.bitmask = server->cache_consistency_bitmask;
        calldata->res.fattr = &calldata->fattr;
        calldata->res.seqid = calldata->arg.seqid;
        calldata->res.server = server;
@@ -1580,6 +1572,15 @@ out_drop:
        return 0;
 }
 
+void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
+{
+       if (ctx->state == NULL)
+               return;
+       if (is_sync)
+               nfs4_close_sync(&ctx->path, ctx->state, ctx->mode);
+       else
+               nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
+}
 
 static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
 {
@@ -1600,6 +1601,9 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
                        server->caps |= NFS_CAP_HARDLINKS;
                if (res.has_symlinks != 0)
                        server->caps |= NFS_CAP_SYMLINKS;
+               memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
+               server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
+               server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
                server->acl_bitmask = res.acl_bitmask;
        }
        return status;
@@ -2079,7 +2083,7 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
        struct nfs_removeargs *args = msg->rpc_argp;
        struct nfs_removeres *res = msg->rpc_resp;
 
-       args->bitmask = server->attr_bitmask;
+       args->bitmask = server->cache_consistency_bitmask;
        res->server = server;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
 }
@@ -2323,7 +2327,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
                .pages = &page,
                .pgbase = 0,
                .count = count,
-               .bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask,
+               .bitmask = NFS_SERVER(dentry->d_inode)->cache_consistency_bitmask,
        };
        struct nfs4_readdir_res res;
        struct rpc_message msg = {
@@ -2552,7 +2556,7 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
 {
        struct nfs_server *server = NFS_SERVER(data->inode);
 
-       data->args.bitmask = server->attr_bitmask;
+       data->args.bitmask = server->cache_consistency_bitmask;
        data->res.server = server;
        data->timestamp   = jiffies;
 
@@ -2575,7 +2579,7 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa
 {
        struct nfs_server *server = NFS_SERVER(data->inode);
        
-       data->args.bitmask = server->attr_bitmask;
+       data->args.bitmask = server->cache_consistency_bitmask;
        data->res.server = server;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
 }
@@ -3678,6 +3682,19 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
        return len;
 }
 
+static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr)
+{
+       if (!((fattr->valid & NFS_ATTR_FATTR_FILEID) &&
+               (fattr->valid & NFS_ATTR_FATTR_FSID) &&
+               (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)))
+               return;
+
+       fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
+               NFS_ATTR_FATTR_NLINK;
+       fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+       fattr->nlink = 2;
+}
+
 int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
                struct nfs4_fs_locations *fs_locations, struct page *page)
 {
@@ -3704,6 +3721,7 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
        fs_locations->server = server;
        fs_locations->nlocations = 0;
        status = rpc_call_sync(server->client, &msg, 0);
+       nfs_fixup_referral_attributes(&fs_locations->fattr);
        dprintk("%s: returned status = %d\n", __func__, status);
        return status;
 }
@@ -3767,6 +3785,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .commit_done    = nfs4_commit_done,
        .lock           = nfs4_proc_lock,
        .clear_acl_cache = nfs4_zap_acl_attr,
+       .close_context  = nfs4_close_context,
 };
 
 /*
index 2022fe47966f52d641496fe633ad0d0b98b15fc7..0298e909559fdc67f0bc5e7bab885595743e90a1 100644 (file)
@@ -62,8 +62,14 @@ static LIST_HEAD(nfs4_clientid_list);
 
 static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred)
 {
-       int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK,
-                       nfs_callback_tcpport, cred);
+       unsigned short port;
+       int status;
+
+       port = nfs_callback_tcpport;
+       if (clp->cl_addr.ss_family == AF_INET6)
+               port = nfs_callback_tcpport6;
+
+       status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred);
        if (status == 0)
                status = nfs4_proc_setclientid_confirm(clp, cred);
        if (status == 0)
index d1e4c8f8a0a9e8b5106564cf71986579340efa77..1690f0e44b9169bf0d0277b98f1a43776b0bd18a 100644 (file)
@@ -522,20 +522,17 @@ static int nfs4_stat_to_errno(int);
                                 decode_lookup_maxsz + \
                                 decode_fs_locations_maxsz)
 
-static struct {
-       unsigned int    mode;
-       unsigned int    nfs2type;
-} nfs_type2fmt[] = {
-       { 0,            NFNON        },
-       { S_IFREG,      NFREG        },
-       { S_IFDIR,      NFDIR        },
-       { S_IFBLK,      NFBLK        },
-       { S_IFCHR,      NFCHR        },
-       { S_IFLNK,      NFLNK        },
-       { S_IFSOCK,     NFSOCK       },
-       { S_IFIFO,      NFFIFO       },
-       { 0,            NFNON        },
-       { 0,            NFNON        },
+static const umode_t nfs_type2fmt[] = {
+       [NF4BAD] = 0,
+       [NF4REG] = S_IFREG,
+       [NF4DIR] = S_IFDIR,
+       [NF4BLK] = S_IFBLK,
+       [NF4CHR] = S_IFCHR,
+       [NF4LNK] = S_IFLNK,
+       [NF4SOCK] = S_IFSOCK,
+       [NF4FIFO] = S_IFIFO,
+       [NF4ATTRDIR] = 0,
+       [NF4NAMEDATTR] = 0,
 };
 
 struct compound_hdr {
@@ -2160,6 +2157,7 @@ static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint3
 static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
 {
        __be32 *p;
+       int ret = 0;
 
        *type = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
@@ -2172,14 +2170,16 @@ static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *
                        return -EIO;
                }
                bitmap[0] &= ~FATTR4_WORD0_TYPE;
+               ret = NFS_ATTR_FATTR_TYPE;
        }
-       dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type].nfs2type);
-       return 0;
+       dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type]);
+       return ret;
 }
 
 static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
 {
        __be32 *p;
+       int ret = 0;
 
        *change = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
@@ -2188,15 +2188,17 @@ static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t
                READ_BUF(8);
                READ64(*change);
                bitmap[0] &= ~FATTR4_WORD0_CHANGE;
+               ret = NFS_ATTR_FATTR_CHANGE;
        }
        dprintk("%s: change attribute=%Lu\n", __func__,
                        (unsigned long long)*change);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
 {
        __be32 *p;
+       int ret = 0;
 
        *size = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
@@ -2205,9 +2207,10 @@ static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *
                READ_BUF(8);
                READ64(*size);
                bitmap[0] &= ~FATTR4_WORD0_SIZE;
+               ret = NFS_ATTR_FATTR_SIZE;
        }
        dprintk("%s: file size=%Lu\n", __func__, (unsigned long long)*size);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
@@ -2245,6 +2248,7 @@ static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap,
 static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
 {
        __be32 *p;
+       int ret = 0;
 
        fsid->major = 0;
        fsid->minor = 0;
@@ -2255,11 +2259,12 @@ static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs
                READ64(fsid->major);
                READ64(fsid->minor);
                bitmap[0] &= ~FATTR4_WORD0_FSID;
+               ret = NFS_ATTR_FATTR_FSID;
        }
        dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __func__,
                        (unsigned long long)fsid->major,
                        (unsigned long long)fsid->minor);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
@@ -2297,6 +2302,7 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint
 static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
 {
        __be32 *p;
+       int ret = 0;
 
        *fileid = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
@@ -2305,14 +2311,16 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t
                READ_BUF(8);
                READ64(*fileid);
                bitmap[0] &= ~FATTR4_WORD0_FILEID;
+               ret = NFS_ATTR_FATTR_FILEID;
        }
        dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
 {
        __be32 *p;
+       int ret = 0;
 
        *fileid = 0;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
@@ -2321,9 +2329,10 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma
                READ_BUF(8);
                READ64(*fileid);
                bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
+               ret = NFS_ATTR_FATTR_FILEID;
        }
        dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
@@ -2479,6 +2488,8 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
                if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
                        res->nlocations++;
        }
+       if (res->nlocations != 0)
+               status = NFS_ATTR_FATTR_V4_REFERRAL;
 out:
        dprintk("%s: fs_locations done, error = %d\n", __func__, status);
        return status;
@@ -2580,26 +2591,30 @@ static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32
        return status;
 }
 
-static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode)
+static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *mode)
 {
+       uint32_t tmp;
        __be32 *p;
+       int ret = 0;
 
        *mode = 0;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
                return -EIO;
        if (likely(bitmap[1] & FATTR4_WORD1_MODE)) {
                READ_BUF(4);
-               READ32(*mode);
-               *mode &= ~S_IFMT;
+               READ32(tmp);
+               *mode = tmp & ~S_IFMT;
                bitmap[1] &= ~FATTR4_WORD1_MODE;
+               ret = NFS_ATTR_FATTR_MODE;
        }
        dprintk("%s: file mode=0%o\n", __func__, (unsigned int)*mode);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
 {
        __be32 *p;
+       int ret = 0;
 
        *nlink = 1;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
@@ -2608,15 +2623,17 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t
                READ_BUF(4);
                READ32(*nlink);
                bitmap[1] &= ~FATTR4_WORD1_NUMLINKS;
+               ret = NFS_ATTR_FATTR_NLINK;
        }
        dprintk("%s: nlink=%u\n", __func__, (unsigned int)*nlink);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *uid)
 {
        uint32_t len;
        __be32 *p;
+       int ret = 0;
 
        *uid = -2;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
@@ -2626,7 +2643,9 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
                READ32(len);
                READ_BUF(len);
                if (len < XDR_MAX_NETOBJ) {
-                       if (nfs_map_name_to_uid(clp, (char *)p, len, uid) != 0)
+                       if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0)
+                               ret = NFS_ATTR_FATTR_OWNER;
+                       else
                                dprintk("%s: nfs_map_name_to_uid failed!\n",
                                                __func__);
                } else
@@ -2635,13 +2654,14 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
                bitmap[1] &= ~FATTR4_WORD1_OWNER;
        }
        dprintk("%s: uid=%d\n", __func__, (int)*uid);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *gid)
 {
        uint32_t len;
        __be32 *p;
+       int ret = 0;
 
        *gid = -2;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
@@ -2651,7 +2671,9 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
                READ32(len);
                READ_BUF(len);
                if (len < XDR_MAX_NETOBJ) {
-                       if (nfs_map_group_to_gid(clp, (char *)p, len, gid) != 0)
+                       if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0)
+                               ret = NFS_ATTR_FATTR_GROUP;
+                       else
                                dprintk("%s: nfs_map_group_to_gid failed!\n",
                                                __func__);
                } else
@@ -2660,13 +2682,14 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
                bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
        }
        dprintk("%s: gid=%d\n", __func__, (int)*gid);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
 {
        uint32_t major = 0, minor = 0;
        __be32 *p;
+       int ret = 0;
 
        *rdev = MKDEV(0,0);
        if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U)))
@@ -2681,9 +2704,10 @@ static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rde
                if (MAJOR(tmp) == major && MINOR(tmp) == minor)
                        *rdev = tmp;
                bitmap[1] &= ~ FATTR4_WORD1_RAWDEV;
+               ret = NFS_ATTR_FATTR_RDEV;
        }
        dprintk("%s: rdev=(0x%x:0x%x)\n", __func__, major, minor);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
@@ -2740,6 +2764,7 @@ static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uin
 static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
 {
        __be32 *p;
+       int ret = 0;
 
        *used = 0;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
@@ -2748,10 +2773,11 @@ static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint
                READ_BUF(8);
                READ64(*used);
                bitmap[1] &= ~FATTR4_WORD1_SPACE_USED;
+               ret = NFS_ATTR_FATTR_SPACE_USED;
        }
        dprintk("%s: space used=%Lu\n", __func__,
                        (unsigned long long)*used);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
@@ -2778,6 +2804,8 @@ static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, str
                return -EIO;
        if (likely(bitmap[1] & FATTR4_WORD1_TIME_ACCESS)) {
                status = decode_attr_time(xdr, time);
+               if (status == 0)
+                       status = NFS_ATTR_FATTR_ATIME;
                bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS;
        }
        dprintk("%s: atime=%ld\n", __func__, (long)time->tv_sec);
@@ -2794,6 +2822,8 @@ static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, s
                return -EIO;
        if (likely(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) {
                status = decode_attr_time(xdr, time);
+               if (status == 0)
+                       status = NFS_ATTR_FATTR_CTIME;
                bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
        }
        dprintk("%s: ctime=%ld\n", __func__, (long)time->tv_sec);
@@ -2810,6 +2840,8 @@ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, str
                return -EIO;
        if (likely(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) {
                status = decode_attr_time(xdr, time);
+               if (status == 0)
+                       status = NFS_ATTR_FATTR_MTIME;
                bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
        }
        dprintk("%s: mtime=%ld\n", __func__, (long)time->tv_sec);
@@ -2994,63 +3026,116 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
        uint32_t attrlen,
                 bitmap[2] = {0},
                 type;
-       int status, fmode = 0;
+       int status;
+       umode_t fmode = 0;
        uint64_t fileid;
 
-       if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
-               goto xdr_error;
-       if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
+       status = decode_op_hdr(xdr, OP_GETATTR);
+       if (status < 0)
                goto xdr_error;
 
-       fattr->bitmap[0] = bitmap[0];
-       fattr->bitmap[1] = bitmap[1];
+       status = decode_attr_bitmap(xdr, bitmap);
+       if (status < 0)
+               goto xdr_error;
 
-       if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
+       status = decode_attr_length(xdr, &attrlen, &savep);
+       if (status < 0)
                goto xdr_error;
 
 
-       if ((status = decode_attr_type(xdr, bitmap, &type)) != 0)
+       status = decode_attr_type(xdr, bitmap, &type);
+       if (status < 0)
                goto xdr_error;
-       fattr->type = nfs_type2fmt[type].nfs2type;
-       fmode = nfs_type2fmt[type].mode;
+       fattr->mode = 0;
+       if (status != 0) {
+               fattr->mode |= nfs_type2fmt[type];
+               fattr->valid |= status;
+       }
 
-       if ((status = decode_attr_change(xdr, bitmap, &fattr->change_attr)) != 0)
+       status = decode_attr_change(xdr, bitmap, &fattr->change_attr);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_size(xdr, bitmap, &fattr->size)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_size(xdr, bitmap, &fattr->size);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_fsid(xdr, bitmap, &fattr->fsid);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_fileid(xdr, bitmap, &fattr->fileid);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
+       fattr->valid |= status;
+
+       status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
                                                struct nfs4_fs_locations,
-                                               fattr))) != 0)
+                                               fattr));
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_mode(xdr, bitmap, &fmode);
+       if (status < 0)
                goto xdr_error;
-       fattr->mode |= fmode;
-       if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0)
+       if (status != 0) {
+               fattr->mode |= fmode;
+               fattr->valid |= status;
+       }
+
+       status = decode_attr_nlink(xdr, bitmap, &fattr->nlink);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_rdev(xdr, bitmap, &fattr->rdev);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_time_access(xdr, bitmap, &fattr->atime)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_time_access(xdr, bitmap, &fattr->atime);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid);
+       if (status < 0)
                goto xdr_error;
-       if (fattr->fileid == 0 && fileid != 0)
+       if (status != 0 && !(fattr->valid & status)) {
                fattr->fileid = fileid;
-       if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
-               fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
+               fattr->valid |= status;
+       }
+
+       status = verify_attr_len(xdr, savep, attrlen);
 xdr_error:
        dprintk("%s: xdr returned %d\n", __func__, -status);
        return status;
@@ -4078,9 +4163,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_se
        status = decode_setattr(&xdr, res);
        if (status)
                goto out;
-       status = decode_getfattr(&xdr, res->fattr, res->server);
-       if (status == NFS4ERR_DELAY)
-               status = 0;
+       decode_getfattr(&xdr, res->fattr, res->server);
 out:
        return status;
 }
index 7f079209d70a91ff79f036dbec62ace856023913..e2975939126abe4b949e3e7f0d09f8790ba81260 100644 (file)
@@ -176,17 +176,6 @@ void nfs_release_request(struct nfs_page *req)
        kref_put(&req->wb_kref, nfs_free_request);
 }
 
-static int nfs_wait_bit_killable(void *word)
-{
-       int ret = 0;
-
-       if (fatal_signal_pending(current))
-               ret = -ERESTARTSYS;
-       else
-               schedule();
-       return ret;
-}
-
 /**
  * nfs_wait_on_request - Wait for a request to complete.
  * @req: request to wait upon.
index 193465210d7cdeec5548f7fbb2fbe0ccfecf2375..7be72d90d49de3191899c8be4626d7cfc385d148 100644 (file)
@@ -663,4 +663,5 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
        .commit_setup   = nfs_proc_commit_setup,
        .lock           = nfs_proc_lock,
        .lock_check_bounds = nfs_lock_check_bounds,
+       .close_context  = nfs_close_context,
 };
index d6686f4786dc55b5d5f06afe913e2930f2b45b96..0942fcbbad3c85c119a774521e4790cee0d0c5e5 100644 (file)
@@ -1018,6 +1018,7 @@ static int nfs_parse_mount_options(char *raw,
                case Opt_rdma:
                        mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */
                        mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+                       xprt_load_transport(p);
                        break;
                case Opt_acl:
                        mnt->flags &= ~NFS_MOUNT_NOACL;
@@ -1205,12 +1206,14 @@ static int nfs_parse_mount_options(char *raw,
                                /* vector side protocols to TCP */
                                mnt->flags |= NFS_MOUNT_TCP;
                                mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+                               xprt_load_transport(string);
                                break;
                        default:
                                errors++;
                                dfprintk(MOUNT, "NFS:   unrecognized "
                                                "transport protocol\n");
                        }
+                       kfree(string);
                        break;
                case Opt_mountproto:
                        string = match_strdup(args);
@@ -1218,7 +1221,6 @@ static int nfs_parse_mount_options(char *raw,
                                goto out_nomem;
                        token = match_token(string,
                                            nfs_xprt_protocol_tokens, args);
-                       kfree(string);
 
                        switch (token) {
                        case Opt_xprt_udp:
index 9f9845859fc1805627c317bc18963473427cbdd2..e560a78995a3cf5027a01df5168060183ef49547 100644 (file)
@@ -313,19 +313,34 @@ static int nfs_writepages_callback(struct page *page, struct writeback_control *
 int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
        struct inode *inode = mapping->host;
+       unsigned long *bitlock = &NFS_I(inode)->flags;
        struct nfs_pageio_descriptor pgio;
        int err;
 
+       /* Stop dirtying of new pages while we sync */
+       err = wait_on_bit_lock(bitlock, NFS_INO_FLUSHING,
+                       nfs_wait_bit_killable, TASK_KILLABLE);
+       if (err)
+               goto out_err;
+
        nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
 
        nfs_pageio_init_write(&pgio, inode, wb_priority(wbc));
        err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio);
        nfs_pageio_complete(&pgio);
+
+       clear_bit_unlock(NFS_INO_FLUSHING, bitlock);
+       smp_mb__after_clear_bit();
+       wake_up_bit(bitlock, NFS_INO_FLUSHING);
+
        if (err < 0)
-               return err;
-       if (pgio.pg_error < 0)
-               return pgio.pg_error;
+               goto out_err;
+       err = pgio.pg_error;
+       if (err < 0)
+               goto out_err;
        return 0;
+out_err:
+       return err;
 }
 
 /*
@@ -404,7 +419,6 @@ nfs_mark_request_commit(struct nfs_page *req)
        struct nfs_inode *nfsi = NFS_I(inode);
 
        spin_lock(&inode->i_lock);
-       nfsi->ncommit++;
        set_bit(PG_CLEAN, &(req)->wb_flags);
        radix_tree_tag_set(&nfsi->nfs_page_tree,
                        req->wb_index,
@@ -524,6 +538,12 @@ static void nfs_cancel_commit_list(struct list_head *head)
 }
 
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
+static int
+nfs_need_commit(struct nfs_inode *nfsi)
+{
+       return radix_tree_tagged(&nfsi->nfs_page_tree, NFS_PAGE_TAG_COMMIT);
+}
+
 /*
  * nfs_scan_commit - Scan an inode for commit requests
  * @inode: NFS inode to scan
@@ -538,16 +558,18 @@ static int
 nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
-       int res = 0;
 
-       if (nfsi->ncommit != 0) {
-               res = nfs_scan_list(nfsi, dst, idx_start, npages,
-                               NFS_PAGE_TAG_COMMIT);
-               nfsi->ncommit -= res;
-       }
-       return res;
+       if (!nfs_need_commit(nfsi))
+               return 0;
+
+       return nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT);
 }
 #else
+static inline int nfs_need_commit(struct nfs_inode *nfsi)
+{
+       return 0;
+}
+
 static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
 {
        return 0;
@@ -820,7 +842,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
        data->args.stable  = NFS_UNSTABLE;
        if (how & FLUSH_STABLE) {
                data->args.stable = NFS_DATA_SYNC;
-               if (!NFS_I(inode)->ncommit)
+               if (!nfs_need_commit(NFS_I(inode)))
                        data->args.stable = NFS_FILE_SYNC;
        }
 
@@ -1425,18 +1447,13 @@ static int nfs_write_mapping(struct address_space *mapping, int how)
 {
        struct writeback_control wbc = {
                .bdi = mapping->backing_dev_info,
-               .sync_mode = WB_SYNC_NONE,
+               .sync_mode = WB_SYNC_ALL,
                .nr_to_write = LONG_MAX,
                .range_start = 0,
                .range_end = LLONG_MAX,
                .for_writepages = 1,
        };
-       int ret;
 
-       ret = __nfs_write_mapping(mapping, &wbc, how);
-       if (ret < 0)
-               return ret;
-       wbc.sync_mode = WB_SYNC_ALL;
        return __nfs_write_mapping(mapping, &wbc, how);
 }
 
index 3d93b2064ce5e83b4e8d8672a84684414daf9e65..a4ed8644d69c0f5050d8e11cc6b66686b7804084 100644 (file)
@@ -938,10 +938,12 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
                char transport[16];
                int port;
                if (sscanf(buf, "%15s %4d", transport, &port) == 2) {
+                       if (port < 1 || port > 65535)
+                               return -EINVAL;
                        err = nfsd_create_serv();
                        if (!err) {
                                err = svc_create_xprt(nfsd_serv,
-                                                     transport, port,
+                                                     transport, PF_INET, port,
                                                      SVC_SOCK_ANONYMOUS);
                                if (err == -ENOENT)
                                        /* Give a reasonable perror msg for
@@ -960,7 +962,7 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
                char transport[16];
                int port;
                if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) {
-                       if (port == 0)
+                       if (port < 1 || port > 65535)
                                return -EINVAL;
                        if (nfsd_serv) {
                                xprt = svc_find_xprt(nfsd_serv, transport,
index 07e4f5d7baa8c63f3639cfee85cb043d0ae8cd84..bc3567bab8c47dfb98a50aa00ef6dd5b068e40e2 100644 (file)
@@ -229,7 +229,6 @@ int nfsd_create_serv(void)
 
        atomic_set(&nfsd_busy, 0);
        nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
-                                     AF_INET,
                                      nfsd_last_thread, nfsd, THIS_MODULE);
        if (nfsd_serv == NULL)
                err = -ENOMEM;
@@ -244,7 +243,7 @@ static int nfsd_init_socks(int port)
        if (!list_empty(&nfsd_serv->sv_permsocks))
                return 0;
 
-       error = svc_create_xprt(nfsd_serv, "udp", port,
+       error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port,
                                        SVC_SOCK_DEFAULTS);
        if (error < 0)
                return error;
@@ -253,7 +252,7 @@ static int nfsd_init_socks(int port)
        if (error < 0)
                return error;
 
-       error = svc_create_xprt(nfsd_serv, "tcp", port,
+       error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port,
                                        SVC_SOCK_DEFAULTS);
        if (error < 0)
                return error;
index 34314b33dbd409f379df4874894625553edc2880..5a9e34475e37951eb03be7ae62d8c55666b53c48 100644 (file)
@@ -32,8 +32,8 @@
 /**
  * The little endian Unicode string $I30 as a global constant.
  */
-ntfschar I30[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('I'),
-               const_cpu_to_le16('3'), const_cpu_to_le16('0'), 0 };
+ntfschar I30[5] = { cpu_to_le16('$'), cpu_to_le16('I'),
+               cpu_to_le16('3'),       cpu_to_le16('0'), 0 };
 
 /**
  * ntfs_lookup_inode_by_name - find an inode in a directory given its name
index 86bef156cf0a15b277d879021b24138a333d4eeb..82c5085559c6796332f97bfe3064861c5cc46aad 100644 (file)
@@ -1975,8 +1975,7 @@ int ntfs_read_inode_mount(struct inode *vi)
                                goto em_put_err_out;
                        next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry +
                                        le16_to_cpu(al_entry->length));
-                       if (le32_to_cpu(al_entry->type) >
-                                       const_le32_to_cpu(AT_DATA))
+                       if (le32_to_cpu(al_entry->type) > le32_to_cpu(AT_DATA))
                                goto em_put_err_out;
                        if (AT_DATA != al_entry->type)
                                continue;
index 1e383328eceb769c778b2694dbed5a86f200e150..50931b1ce4b9bac7a7089a4f97c1dd93af21c9d0 100644 (file)
 
 #include "types.h"
 
-/*
- * Constant endianness conversion defines.
- */
-#define const_le16_to_cpu(x)   __constant_le16_to_cpu(x)
-#define const_le32_to_cpu(x)   __constant_le32_to_cpu(x)
-#define const_le64_to_cpu(x)   __constant_le64_to_cpu(x)
-
-#define const_cpu_to_le16(x)   __constant_cpu_to_le16(x)
-#define const_cpu_to_le32(x)   __constant_cpu_to_le32(x)
-#define const_cpu_to_le64(x)   __constant_cpu_to_le64(x)
-
 /* The NTFS oem_id "NTFS    " */
-#define magicNTFS      const_cpu_to_le64(0x202020205346544eULL)
+#define magicNTFS      cpu_to_le64(0x202020205346544eULL)
 
 /*
  * Location of bootsector on partition:
@@ -114,25 +103,25 @@ typedef struct {
  */
 enum {
        /* Found in $MFT/$DATA. */
-       magic_FILE = const_cpu_to_le32(0x454c4946), /* Mft entry. */
-       magic_INDX = const_cpu_to_le32(0x58444e49), /* Index buffer. */
-       magic_HOLE = const_cpu_to_le32(0x454c4f48), /* ? (NTFS 3.0+?) */
+       magic_FILE = cpu_to_le32(0x454c4946), /* Mft entry. */
+       magic_INDX = cpu_to_le32(0x58444e49), /* Index buffer. */
+       magic_HOLE = cpu_to_le32(0x454c4f48), /* ? (NTFS 3.0+?) */
 
        /* Found in $LogFile/$DATA. */
-       magic_RSTR = const_cpu_to_le32(0x52545352), /* Restart page. */
-       magic_RCRD = const_cpu_to_le32(0x44524352), /* Log record page. */
+       magic_RSTR = cpu_to_le32(0x52545352), /* Restart page. */
+       magic_RCRD = cpu_to_le32(0x44524352), /* Log record page. */
 
        /* Found in $LogFile/$DATA.  (May be found in $MFT/$DATA, also?) */
-       magic_CHKD = const_cpu_to_le32(0x444b4843), /* Modified by chkdsk. */
+       magic_CHKD = cpu_to_le32(0x444b4843), /* Modified by chkdsk. */
 
        /* Found in all ntfs record containing records. */
-       magic_BAAD = const_cpu_to_le32(0x44414142), /* Failed multi sector
+       magic_BAAD = cpu_to_le32(0x44414142), /* Failed multi sector
                                                       transfer was detected. */
        /*
         * Found in $LogFile/$DATA when a page is full of 0xff bytes and is
         * thus not initialized.  Page must be initialized before using it.
         */
-       magic_empty = const_cpu_to_le32(0xffffffff) /* Record is empty. */
+       magic_empty = cpu_to_le32(0xffffffff) /* Record is empty. */
 };
 
 typedef le32 NTFS_RECORD_TYPE;
@@ -258,8 +247,8 @@ typedef enum {
  * information about the mft record in which they are present.
  */
 enum {
-       MFT_RECORD_IN_USE       = const_cpu_to_le16(0x0001),
-       MFT_RECORD_IS_DIRECTORY = const_cpu_to_le16(0x0002),
+       MFT_RECORD_IN_USE       = cpu_to_le16(0x0001),
+       MFT_RECORD_IS_DIRECTORY = cpu_to_le16(0x0002),
 } __attribute__ ((__packed__));
 
 typedef le16 MFT_RECORD_FLAGS;
@@ -309,7 +298,7 @@ typedef le16 MFT_RECORD_FLAGS;
  * Note: The _LE versions will return a CPU endian formatted value!
  */
 #define MFT_REF_MASK_CPU 0x0000ffffffffffffULL
-#define MFT_REF_MASK_LE const_cpu_to_le64(MFT_REF_MASK_CPU)
+#define MFT_REF_MASK_LE cpu_to_le64(MFT_REF_MASK_CPU)
 
 typedef u64 MFT_REF;
 typedef le64 leMFT_REF;
@@ -477,25 +466,25 @@ typedef struct {
  * a revealing choice of symbol I do not know what is... (-;
  */
 enum {
-       AT_UNUSED                       = const_cpu_to_le32(         0),
-       AT_STANDARD_INFORMATION         = const_cpu_to_le32(      0x10),
-       AT_ATTRIBUTE_LIST               = const_cpu_to_le32(      0x20),
-       AT_FILE_NAME                    = const_cpu_to_le32(      0x30),
-       AT_OBJECT_ID                    = const_cpu_to_le32(      0x40),
-       AT_SECURITY_DESCRIPTOR          = const_cpu_to_le32(      0x50),
-       AT_VOLUME_NAME                  = const_cpu_to_le32(      0x60),
-       AT_VOLUME_INFORMATION           = const_cpu_to_le32(      0x70),
-       AT_DATA                         = const_cpu_to_le32(      0x80),
-       AT_INDEX_ROOT                   = const_cpu_to_le32(      0x90),
-       AT_INDEX_ALLOCATION             = const_cpu_to_le32(      0xa0),
-       AT_BITMAP                       = const_cpu_to_le32(      0xb0),
-       AT_REPARSE_POINT                = const_cpu_to_le32(      0xc0),
-       AT_EA_INFORMATION               = const_cpu_to_le32(      0xd0),
-       AT_EA                           = const_cpu_to_le32(      0xe0),
-       AT_PROPERTY_SET                 = const_cpu_to_le32(      0xf0),
-       AT_LOGGED_UTILITY_STREAM        = const_cpu_to_le32(     0x100),
-       AT_FIRST_USER_DEFINED_ATTRIBUTE = const_cpu_to_le32(    0x1000),
-       AT_END                          = const_cpu_to_le32(0xffffffff)
+       AT_UNUSED                       = cpu_to_le32(         0),
+       AT_STANDARD_INFORMATION         = cpu_to_le32(      0x10),
+       AT_ATTRIBUTE_LIST               = cpu_to_le32(      0x20),
+       AT_FILE_NAME                    = cpu_to_le32(      0x30),
+       AT_OBJECT_ID                    = cpu_to_le32(      0x40),
+       AT_SECURITY_DESCRIPTOR          = cpu_to_le32(      0x50),
+       AT_VOLUME_NAME                  = cpu_to_le32(      0x60),
+       AT_VOLUME_INFORMATION           = cpu_to_le32(      0x70),
+       AT_DATA                         = cpu_to_le32(      0x80),
+       AT_INDEX_ROOT                   = cpu_to_le32(      0x90),
+       AT_INDEX_ALLOCATION             = cpu_to_le32(      0xa0),
+       AT_BITMAP                       = cpu_to_le32(      0xb0),
+       AT_REPARSE_POINT                = cpu_to_le32(      0xc0),
+       AT_EA_INFORMATION               = cpu_to_le32(      0xd0),
+       AT_EA                           = cpu_to_le32(      0xe0),
+       AT_PROPERTY_SET                 = cpu_to_le32(      0xf0),
+       AT_LOGGED_UTILITY_STREAM        = cpu_to_le32(     0x100),
+       AT_FIRST_USER_DEFINED_ATTRIBUTE = cpu_to_le32(    0x1000),
+       AT_END                          = cpu_to_le32(0xffffffff)
 };
 
 typedef le32 ATTR_TYPE;
@@ -539,13 +528,13 @@ typedef le32 ATTR_TYPE;
  *     equal then the second le32 values would be compared, etc.
  */
 enum {
-       COLLATION_BINARY                = const_cpu_to_le32(0x00),
-       COLLATION_FILE_NAME             = const_cpu_to_le32(0x01),
-       COLLATION_UNICODE_STRING        = const_cpu_to_le32(0x02),
-       COLLATION_NTOFS_ULONG           = const_cpu_to_le32(0x10),
-       COLLATION_NTOFS_SID             = const_cpu_to_le32(0x11),
-       COLLATION_NTOFS_SECURITY_HASH   = const_cpu_to_le32(0x12),
-       COLLATION_NTOFS_ULONGS          = const_cpu_to_le32(0x13),
+       COLLATION_BINARY                = cpu_to_le32(0x00),
+       COLLATION_FILE_NAME             = cpu_to_le32(0x01),
+       COLLATION_UNICODE_STRING        = cpu_to_le32(0x02),
+       COLLATION_NTOFS_ULONG           = cpu_to_le32(0x10),
+       COLLATION_NTOFS_SID             = cpu_to_le32(0x11),
+       COLLATION_NTOFS_SECURITY_HASH   = cpu_to_le32(0x12),
+       COLLATION_NTOFS_ULONGS          = cpu_to_le32(0x13),
 };
 
 typedef le32 COLLATION_RULE;
@@ -559,25 +548,25 @@ typedef le32 COLLATION_RULE;
  * NT4.
  */
 enum {
-       ATTR_DEF_INDEXABLE      = const_cpu_to_le32(0x02), /* Attribute can be
+       ATTR_DEF_INDEXABLE      = cpu_to_le32(0x02), /* Attribute can be
                                        indexed. */
-       ATTR_DEF_MULTIPLE       = const_cpu_to_le32(0x04), /* Attribute type
+       ATTR_DEF_MULTIPLE       = cpu_to_le32(0x04), /* Attribute type
                                        can be present multiple times in the
                                        mft records of an inode. */
-       ATTR_DEF_NOT_ZERO       = const_cpu_to_le32(0x08), /* Attribute value
+       ATTR_DEF_NOT_ZERO       = cpu_to_le32(0x08), /* Attribute value
                                        must contain at least one non-zero
                                        byte. */
-       ATTR_DEF_INDEXED_UNIQUE = const_cpu_to_le32(0x10), /* Attribute must be
+       ATTR_DEF_INDEXED_UNIQUE = cpu_to_le32(0x10), /* Attribute must be
                                        indexed and the attribute value must be
                                        unique for the attribute type in all of
                                        the mft records of an inode. */
-       ATTR_DEF_NAMED_UNIQUE   = const_cpu_to_le32(0x20), /* Attribute must be
+       ATTR_DEF_NAMED_UNIQUE   = cpu_to_le32(0x20), /* Attribute must be
                                        named and the name must be unique for
                                        the attribute type in all of the mft
                                        records of an inode. */
-       ATTR_DEF_RESIDENT       = const_cpu_to_le32(0x40), /* Attribute must be
+       ATTR_DEF_RESIDENT       = cpu_to_le32(0x40), /* Attribute must be
                                        resident. */
-       ATTR_DEF_ALWAYS_LOG     = const_cpu_to_le32(0x80), /* Always log
+       ATTR_DEF_ALWAYS_LOG     = cpu_to_le32(0x80), /* Always log
                                        modifications to this attribute,
                                        regardless of whether it is resident or
                                        non-resident.  Without this, only log
@@ -614,12 +603,12 @@ typedef struct {
  * Attribute flags (16-bit).
  */
 enum {
-       ATTR_IS_COMPRESSED    = const_cpu_to_le16(0x0001),
-       ATTR_COMPRESSION_MASK = const_cpu_to_le16(0x00ff), /* Compression method
+       ATTR_IS_COMPRESSED    = cpu_to_le16(0x0001),
+       ATTR_COMPRESSION_MASK = cpu_to_le16(0x00ff), /* Compression method
                                                              mask.  Also, first
                                                              illegal value. */
-       ATTR_IS_ENCRYPTED     = const_cpu_to_le16(0x4000),
-       ATTR_IS_SPARSE        = const_cpu_to_le16(0x8000),
+       ATTR_IS_ENCRYPTED     = cpu_to_le16(0x4000),
+       ATTR_IS_SPARSE        = cpu_to_le16(0x8000),
 } __attribute__ ((__packed__));
 
 typedef le16 ATTR_FLAGS;
@@ -811,32 +800,32 @@ typedef ATTR_RECORD ATTR_REC;
  * flags appear in all of the above.
  */
 enum {
-       FILE_ATTR_READONLY              = const_cpu_to_le32(0x00000001),
-       FILE_ATTR_HIDDEN                = const_cpu_to_le32(0x00000002),
-       FILE_ATTR_SYSTEM                = const_cpu_to_le32(0x00000004),
-       /* Old DOS volid. Unused in NT. = const_cpu_to_le32(0x00000008), */
+       FILE_ATTR_READONLY              = cpu_to_le32(0x00000001),
+       FILE_ATTR_HIDDEN                = cpu_to_le32(0x00000002),
+       FILE_ATTR_SYSTEM                = cpu_to_le32(0x00000004),
+       /* Old DOS volid. Unused in NT. = cpu_to_le32(0x00000008), */
 
-       FILE_ATTR_DIRECTORY             = const_cpu_to_le32(0x00000010),
+       FILE_ATTR_DIRECTORY             = cpu_to_le32(0x00000010),
        /* Note, FILE_ATTR_DIRECTORY is not considered valid in NT.  It is
           reserved for the DOS SUBDIRECTORY flag. */
-       FILE_ATTR_ARCHIVE               = const_cpu_to_le32(0x00000020),
-       FILE_ATTR_DEVICE                = const_cpu_to_le32(0x00000040),
-       FILE_ATTR_NORMAL                = const_cpu_to_le32(0x00000080),
+       FILE_ATTR_ARCHIVE               = cpu_to_le32(0x00000020),
+       FILE_ATTR_DEVICE                = cpu_to_le32(0x00000040),
+       FILE_ATTR_NORMAL                = cpu_to_le32(0x00000080),
 
-       FILE_ATTR_TEMPORARY             = const_cpu_to_le32(0x00000100),
-       FILE_ATTR_SPARSE_FILE           = const_cpu_to_le32(0x00000200),
-       FILE_ATTR_REPARSE_POINT         = const_cpu_to_le32(0x00000400),
-       FILE_ATTR_COMPRESSED            = const_cpu_to_le32(0x00000800),
+       FILE_ATTR_TEMPORARY             = cpu_to_le32(0x00000100),
+       FILE_ATTR_SPARSE_FILE           = cpu_to_le32(0x00000200),
+       FILE_ATTR_REPARSE_POINT         = cpu_to_le32(0x00000400),
+       FILE_ATTR_COMPRESSED            = cpu_to_le32(0x00000800),
 
-       FILE_ATTR_OFFLINE               = const_cpu_to_le32(0x00001000),
-       FILE_ATTR_NOT_CONTENT_INDEXED   = const_cpu_to_le32(0x00002000),
-       FILE_ATTR_ENCRYPTED             = const_cpu_to_le32(0x00004000),
+       FILE_ATTR_OFFLINE               = cpu_to_le32(0x00001000),
+       FILE_ATTR_NOT_CONTENT_INDEXED   = cpu_to_le32(0x00002000),
+       FILE_ATTR_ENCRYPTED             = cpu_to_le32(0x00004000),
 
-       FILE_ATTR_VALID_FLAGS           = const_cpu_to_le32(0x00007fb7),
+       FILE_ATTR_VALID_FLAGS           = cpu_to_le32(0x00007fb7),
        /* Note, FILE_ATTR_VALID_FLAGS masks out the old DOS VolId and the
           FILE_ATTR_DEVICE and preserves everything else.  This mask is used
           to obtain all flags that are valid for reading. */
-       FILE_ATTR_VALID_SET_FLAGS       = const_cpu_to_le32(0x000031a7),
+       FILE_ATTR_VALID_SET_FLAGS       = cpu_to_le32(0x000031a7),
        /* Note, FILE_ATTR_VALID_SET_FLAGS masks out the old DOS VolId, the
           F_A_DEVICE, F_A_DIRECTORY, F_A_SPARSE_FILE, F_A_REPARSE_POINT,
           F_A_COMPRESSED, and F_A_ENCRYPTED and preserves the rest.  This mask
@@ -846,11 +835,11 @@ enum {
         * FILENAME_ATTR attributes but not in the STANDARD_INFORMATION
         * attribute of an mft record.
         */
-       FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT   = const_cpu_to_le32(0x10000000),
+       FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT   = cpu_to_le32(0x10000000),
        /* Note, this is a copy of the corresponding bit from the mft record,
           telling us whether this is a directory or not, i.e. whether it has
           an index root attribute or not. */
-       FILE_ATTR_DUP_VIEW_INDEX_PRESENT        = const_cpu_to_le32(0x20000000),
+       FILE_ATTR_DUP_VIEW_INDEX_PRESENT        = cpu_to_le32(0x20000000),
        /* Note, this is a copy of the corresponding bit from the mft record,
           telling us whether this file has a view index present (eg. object id
           index, quota index, one of the security indexes or the encrypting
@@ -1446,42 +1435,42 @@ enum {
        /* Specific rights for files and directories are as follows: */
 
        /* Right to read data from the file. (FILE) */
-       FILE_READ_DATA                  = const_cpu_to_le32(0x00000001),
+       FILE_READ_DATA                  = cpu_to_le32(0x00000001),
        /* Right to list contents of a directory. (DIRECTORY) */
-       FILE_LIST_DIRECTORY             = const_cpu_to_le32(0x00000001),
+       FILE_LIST_DIRECTORY             = cpu_to_le32(0x00000001),
 
        /* Right to write data to the file. (FILE) */
-       FILE_WRITE_DATA                 = const_cpu_to_le32(0x00000002),
+       FILE_WRITE_DATA                 = cpu_to_le32(0x00000002),
        /* Right to create a file in the directory. (DIRECTORY) */
-       FILE_ADD_FILE                   = const_cpu_to_le32(0x00000002),
+       FILE_ADD_FILE                   = cpu_to_le32(0x00000002),
 
        /* Right to append data to the file. (FILE) */
-       FILE_APPEND_DATA                = const_cpu_to_le32(0x00000004),
+       FILE_APPEND_DATA                = cpu_to_le32(0x00000004),
        /* Right to create a subdirectory. (DIRECTORY) */
-       FILE_ADD_SUBDIRECTORY           = const_cpu_to_le32(0x00000004),
+       FILE_ADD_SUBDIRECTORY           = cpu_to_le32(0x00000004),
 
        /* Right to read extended attributes. (FILE/DIRECTORY) */
-       FILE_READ_EA                    = const_cpu_to_le32(0x00000008),
+       FILE_READ_EA                    = cpu_to_le32(0x00000008),
 
        /* Right to write extended attributes. (FILE/DIRECTORY) */
-       FILE_WRITE_EA                   = const_cpu_to_le32(0x00000010),
+       FILE_WRITE_EA                   = cpu_to_le32(0x00000010),
 
        /* Right to execute a file. (FILE) */
-       FILE_EXECUTE                    = const_cpu_to_le32(0x00000020),
+       FILE_EXECUTE                    = cpu_to_le32(0x00000020),
        /* Right to traverse the directory. (DIRECTORY) */
-       FILE_TRAVERSE                   = const_cpu_to_le32(0x00000020),
+       FILE_TRAVERSE                   = cpu_to_le32(0x00000020),
 
        /*
         * Right to delete a directory and all the files it contains (its
         * children), even if the files are read-only. (DIRECTORY)
         */
-       FILE_DELETE_CHILD               = const_cpu_to_le32(0x00000040),
+       FILE_DELETE_CHILD               = cpu_to_le32(0x00000040),
 
        /* Right to read file attributes. (FILE/DIRECTORY) */
-       FILE_READ_ATTRIBUTES            = const_cpu_to_le32(0x00000080),
+       FILE_READ_ATTRIBUTES            = cpu_to_le32(0x00000080),
 
        /* Right to change file attributes. (FILE/DIRECTORY) */
-       FILE_WRITE_ATTRIBUTES           = const_cpu_to_le32(0x00000100),
+       FILE_WRITE_ATTRIBUTES           = cpu_to_le32(0x00000100),
 
        /*
         * The standard rights (bits 16 to 23).  These are independent of the
@@ -1489,27 +1478,27 @@ enum {
         */
 
        /* Right to delete the object. */
-       DELETE                          = const_cpu_to_le32(0x00010000),
+       DELETE                          = cpu_to_le32(0x00010000),
 
        /*
         * Right to read the information in the object's security descriptor,
         * not including the information in the SACL, i.e. right to read the
         * security descriptor and owner.
         */
-       READ_CONTROL                    = const_cpu_to_le32(0x00020000),
+       READ_CONTROL                    = cpu_to_le32(0x00020000),
 
        /* Right to modify the DACL in the object's security descriptor. */
-       WRITE_DAC                       = const_cpu_to_le32(0x00040000),
+       WRITE_DAC                       = cpu_to_le32(0x00040000),
 
        /* Right to change the owner in the object's security descriptor. */
-       WRITE_OWNER                     = const_cpu_to_le32(0x00080000),
+       WRITE_OWNER                     = cpu_to_le32(0x00080000),
 
        /*
         * Right to use the object for synchronization.  Enables a process to
         * wait until the object is in the signalled state.  Some object types
         * do not support this access right.
         */
-       SYNCHRONIZE                     = const_cpu_to_le32(0x00100000),
+       SYNCHRONIZE                     = cpu_to_le32(0x00100000),
 
        /*
         * The following STANDARD_RIGHTS_* are combinations of the above for
@@ -1517,25 +1506,25 @@ enum {
         */
 
        /* These are currently defined to READ_CONTROL. */
-       STANDARD_RIGHTS_READ            = const_cpu_to_le32(0x00020000),
-       STANDARD_RIGHTS_WRITE           = const_cpu_to_le32(0x00020000),
-       STANDARD_RIGHTS_EXECUTE         = const_cpu_to_le32(0x00020000),
+       STANDARD_RIGHTS_READ            = cpu_to_le32(0x00020000),
+       STANDARD_RIGHTS_WRITE           = cpu_to_le32(0x00020000),
+       STANDARD_RIGHTS_EXECUTE         = cpu_to_le32(0x00020000),
 
        /* Combines DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER access. */
-       STANDARD_RIGHTS_REQUIRED        = const_cpu_to_le32(0x000f0000),
+       STANDARD_RIGHTS_REQUIRED        = cpu_to_le32(0x000f0000),
 
        /*
         * Combines DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER, and
         * SYNCHRONIZE access.
         */
-       STANDARD_RIGHTS_ALL             = const_cpu_to_le32(0x001f0000),
+       STANDARD_RIGHTS_ALL             = cpu_to_le32(0x001f0000),
 
        /*
         * The access system ACL and maximum allowed access types (bits 24 to
         * 25, bits 26 to 27 are reserved).
         */
-       ACCESS_SYSTEM_SECURITY          = const_cpu_to_le32(0x01000000),
-       MAXIMUM_ALLOWED                 = const_cpu_to_le32(0x02000000),
+       ACCESS_SYSTEM_SECURITY          = cpu_to_le32(0x01000000),
+       MAXIMUM_ALLOWED                 = cpu_to_le32(0x02000000),
 
        /*
         * The generic rights (bits 28 to 31).  These map onto the standard and
@@ -1543,10 +1532,10 @@ enum {
         */
 
        /* Read, write, and execute access. */
-       GENERIC_ALL                     = const_cpu_to_le32(0x10000000),
+       GENERIC_ALL                     = cpu_to_le32(0x10000000),
 
        /* Execute access. */
-       GENERIC_EXECUTE                 = const_cpu_to_le32(0x20000000),
+       GENERIC_EXECUTE                 = cpu_to_le32(0x20000000),
 
        /*
         * Write access.  For files, this maps onto:
@@ -1555,7 +1544,7 @@ enum {
         * For directories, the mapping has the same numerical value.  See
         * above for the descriptions of the rights granted.
         */
-       GENERIC_WRITE                   = const_cpu_to_le32(0x40000000),
+       GENERIC_WRITE                   = cpu_to_le32(0x40000000),
 
        /*
         * Read access.  For files, this maps onto:
@@ -1564,7 +1553,7 @@ enum {
         * For directories, the mapping has the same numberical value.  See
         * above for the descriptions of the rights granted.
         */
-       GENERIC_READ                    = const_cpu_to_le32(0x80000000),
+       GENERIC_READ                    = cpu_to_le32(0x80000000),
 };
 
 typedef le32 ACCESS_MASK;
@@ -1604,8 +1593,8 @@ typedef struct {
  * The object ACE flags (32-bit).
  */
 enum {
-       ACE_OBJECT_TYPE_PRESENT                 = const_cpu_to_le32(1),
-       ACE_INHERITED_OBJECT_TYPE_PRESENT       = const_cpu_to_le32(2),
+       ACE_OBJECT_TYPE_PRESENT                 = cpu_to_le32(1),
+       ACE_INHERITED_OBJECT_TYPE_PRESENT       = cpu_to_le32(2),
 };
 
 typedef le32 OBJECT_ACE_FLAGS;
@@ -1706,23 +1695,23 @@ typedef enum {
  *     expressed as offsets from the beginning of the security descriptor.
  */
 enum {
-       SE_OWNER_DEFAULTED              = const_cpu_to_le16(0x0001),
-       SE_GROUP_DEFAULTED              = const_cpu_to_le16(0x0002),
-       SE_DACL_PRESENT                 = const_cpu_to_le16(0x0004),
-       SE_DACL_DEFAULTED               = const_cpu_to_le16(0x0008),
-
-       SE_SACL_PRESENT                 = const_cpu_to_le16(0x0010),
-       SE_SACL_DEFAULTED               = const_cpu_to_le16(0x0020),
-
-       SE_DACL_AUTO_INHERIT_REQ        = const_cpu_to_le16(0x0100),
-       SE_SACL_AUTO_INHERIT_REQ        = const_cpu_to_le16(0x0200),
-       SE_DACL_AUTO_INHERITED          = const_cpu_to_le16(0x0400),
-       SE_SACL_AUTO_INHERITED          = const_cpu_to_le16(0x0800),
-
-       SE_DACL_PROTECTED               = const_cpu_to_le16(0x1000),
-       SE_SACL_PROTECTED               = const_cpu_to_le16(0x2000),
-       SE_RM_CONTROL_VALID             = const_cpu_to_le16(0x4000),
-       SE_SELF_RELATIVE                = const_cpu_to_le16(0x8000)
+       SE_OWNER_DEFAULTED              = cpu_to_le16(0x0001),
+       SE_GROUP_DEFAULTED              = cpu_to_le16(0x0002),
+       SE_DACL_PRESENT                 = cpu_to_le16(0x0004),
+       SE_DACL_DEFAULTED               = cpu_to_le16(0x0008),
+
+       SE_SACL_PRESENT                 = cpu_to_le16(0x0010),
+       SE_SACL_DEFAULTED               = cpu_to_le16(0x0020),
+
+       SE_DACL_AUTO_INHERIT_REQ        = cpu_to_le16(0x0100),
+       SE_SACL_AUTO_INHERIT_REQ        = cpu_to_le16(0x0200),
+       SE_DACL_AUTO_INHERITED          = cpu_to_le16(0x0400),
+       SE_SACL_AUTO_INHERITED          = cpu_to_le16(0x0800),
+
+       SE_DACL_PROTECTED               = cpu_to_le16(0x1000),
+       SE_SACL_PROTECTED               = cpu_to_le16(0x2000),
+       SE_RM_CONTROL_VALID             = cpu_to_le16(0x4000),
+       SE_SELF_RELATIVE                = cpu_to_le16(0x8000)
 } __attribute__ ((__packed__));
 
 typedef le16 SECURITY_DESCRIPTOR_CONTROL;
@@ -1910,21 +1899,21 @@ typedef struct {
  * Possible flags for the volume (16-bit).
  */
 enum {
-       VOLUME_IS_DIRTY                 = const_cpu_to_le16(0x0001),
-       VOLUME_RESIZE_LOG_FILE          = const_cpu_to_le16(0x0002),
-       VOLUME_UPGRADE_ON_MOUNT         = const_cpu_to_le16(0x0004),
-       VOLUME_MOUNTED_ON_NT4           = const_cpu_to_le16(0x0008),
+       VOLUME_IS_DIRTY                 = cpu_to_le16(0x0001),
+       VOLUME_RESIZE_LOG_FILE          = cpu_to_le16(0x0002),
+       VOLUME_UPGRADE_ON_MOUNT         = cpu_to_le16(0x0004),
+       VOLUME_MOUNTED_ON_NT4           = cpu_to_le16(0x0008),
 
-       VOLUME_DELETE_USN_UNDERWAY      = const_cpu_to_le16(0x0010),
-       VOLUME_REPAIR_OBJECT_ID         = const_cpu_to_le16(0x0020),
+       VOLUME_DELETE_USN_UNDERWAY      = cpu_to_le16(0x0010),
+       VOLUME_REPAIR_OBJECT_ID         = cpu_to_le16(0x0020),
 
-       VOLUME_CHKDSK_UNDERWAY          = const_cpu_to_le16(0x4000),
-       VOLUME_MODIFIED_BY_CHKDSK       = const_cpu_to_le16(0x8000),
+       VOLUME_CHKDSK_UNDERWAY          = cpu_to_le16(0x4000),
+       VOLUME_MODIFIED_BY_CHKDSK       = cpu_to_le16(0x8000),
 
-       VOLUME_FLAGS_MASK               = const_cpu_to_le16(0xc03f),
+       VOLUME_FLAGS_MASK               = cpu_to_le16(0xc03f),
 
        /* To make our life easier when checking if we must mount read-only. */
-       VOLUME_MUST_MOUNT_RO_MASK       = const_cpu_to_le16(0xc027),
+       VOLUME_MUST_MOUNT_RO_MASK       = cpu_to_le16(0xc027),
 } __attribute__ ((__packed__));
 
 typedef le16 VOLUME_FLAGS;
@@ -2109,26 +2098,26 @@ typedef struct {
  * The user quota flags.  Names explain meaning.
  */
 enum {
-       QUOTA_FLAG_DEFAULT_LIMITS       = const_cpu_to_le32(0x00000001),
-       QUOTA_FLAG_LIMIT_REACHED        = const_cpu_to_le32(0x00000002),
-       QUOTA_FLAG_ID_DELETED           = const_cpu_to_le32(0x00000004),
+       QUOTA_FLAG_DEFAULT_LIMITS       = cpu_to_le32(0x00000001),
+       QUOTA_FLAG_LIMIT_REACHED        = cpu_to_le32(0x00000002),
+       QUOTA_FLAG_ID_DELETED           = cpu_to_le32(0x00000004),
 
-       QUOTA_FLAG_USER_MASK            = const_cpu_to_le32(0x00000007),
+       QUOTA_FLAG_USER_MASK            = cpu_to_le32(0x00000007),
        /* This is a bit mask for the user quota flags. */
 
        /*
         * These flags are only present in the quota defaults index entry, i.e.
         * in the entry where owner_id = QUOTA_DEFAULTS_ID.
         */
-       QUOTA_FLAG_TRACKING_ENABLED     = const_cpu_to_le32(0x00000010),
-       QUOTA_FLAG_ENFORCEMENT_ENABLED  = const_cpu_to_le32(0x00000020),
-       QUOTA_FLAG_TRACKING_REQUESTED   = const_cpu_to_le32(0x00000040),
-       QUOTA_FLAG_LOG_THRESHOLD        = const_cpu_to_le32(0x00000080),
-
-       QUOTA_FLAG_LOG_LIMIT            = const_cpu_to_le32(0x00000100),
-       QUOTA_FLAG_OUT_OF_DATE          = const_cpu_to_le32(0x00000200),
-       QUOTA_FLAG_CORRUPT              = const_cpu_to_le32(0x00000400),
-       QUOTA_FLAG_PENDING_DELETES      = const_cpu_to_le32(0x00000800),
+       QUOTA_FLAG_TRACKING_ENABLED     = cpu_to_le32(0x00000010),
+       QUOTA_FLAG_ENFORCEMENT_ENABLED  = cpu_to_le32(0x00000020),
+       QUOTA_FLAG_TRACKING_REQUESTED   = cpu_to_le32(0x00000040),
+       QUOTA_FLAG_LOG_THRESHOLD        = cpu_to_le32(0x00000080),
+
+       QUOTA_FLAG_LOG_LIMIT            = cpu_to_le32(0x00000100),
+       QUOTA_FLAG_OUT_OF_DATE          = cpu_to_le32(0x00000200),
+       QUOTA_FLAG_CORRUPT              = cpu_to_le32(0x00000400),
+       QUOTA_FLAG_PENDING_DELETES      = cpu_to_le32(0x00000800),
 };
 
 typedef le32 QUOTA_FLAGS;
@@ -2172,9 +2161,9 @@ typedef struct {
  * Predefined owner_id values (32-bit).
  */
 enum {
-       QUOTA_INVALID_ID        = const_cpu_to_le32(0x00000000),
-       QUOTA_DEFAULTS_ID       = const_cpu_to_le32(0x00000001),
-       QUOTA_FIRST_USER_ID     = const_cpu_to_le32(0x00000100),
+       QUOTA_INVALID_ID        = cpu_to_le32(0x00000000),
+       QUOTA_DEFAULTS_ID       = cpu_to_le32(0x00000001),
+       QUOTA_FIRST_USER_ID     = cpu_to_le32(0x00000100),
 };
 
 /*
@@ -2189,14 +2178,14 @@ typedef enum {
  * Index entry flags (16-bit).
  */
 enum {
-       INDEX_ENTRY_NODE = const_cpu_to_le16(1), /* This entry contains a
+       INDEX_ENTRY_NODE = cpu_to_le16(1), /* This entry contains a
                        sub-node, i.e. a reference to an index block in form of
                        a virtual cluster number (see below). */
-       INDEX_ENTRY_END  = const_cpu_to_le16(2), /* This signifies the last
+       INDEX_ENTRY_END  = cpu_to_le16(2), /* This signifies the last
                        entry in an index block.  The index entry does not
                        represent a file but it can point to a sub-node. */
 
-       INDEX_ENTRY_SPACE_FILLER = const_cpu_to_le16(0xffff), /* gcc: Force
+       INDEX_ENTRY_SPACE_FILLER = cpu_to_le16(0xffff), /* gcc: Force
                        enum bit width to 16-bit. */
 } __attribute__ ((__packed__));
 
@@ -2334,26 +2323,26 @@ typedef struct {
  * These are the predefined reparse point tags:
  */
 enum {
-       IO_REPARSE_TAG_IS_ALIAS         = const_cpu_to_le32(0x20000000),
-       IO_REPARSE_TAG_IS_HIGH_LATENCY  = const_cpu_to_le32(0x40000000),
-       IO_REPARSE_TAG_IS_MICROSOFT     = const_cpu_to_le32(0x80000000),
+       IO_REPARSE_TAG_IS_ALIAS         = cpu_to_le32(0x20000000),
+       IO_REPARSE_TAG_IS_HIGH_LATENCY  = cpu_to_le32(0x40000000),
+       IO_REPARSE_TAG_IS_MICROSOFT     = cpu_to_le32(0x80000000),
 
-       IO_REPARSE_TAG_RESERVED_ZERO    = const_cpu_to_le32(0x00000000),
-       IO_REPARSE_TAG_RESERVED_ONE     = const_cpu_to_le32(0x00000001),
-       IO_REPARSE_TAG_RESERVED_RANGE   = const_cpu_to_le32(0x00000001),
+       IO_REPARSE_TAG_RESERVED_ZERO    = cpu_to_le32(0x00000000),
+       IO_REPARSE_TAG_RESERVED_ONE     = cpu_to_le32(0x00000001),
+       IO_REPARSE_TAG_RESERVED_RANGE   = cpu_to_le32(0x00000001),
 
-       IO_REPARSE_TAG_NSS              = const_cpu_to_le32(0x68000005),
-       IO_REPARSE_TAG_NSS_RECOVER      = const_cpu_to_le32(0x68000006),
-       IO_REPARSE_TAG_SIS              = const_cpu_to_le32(0x68000007),
-       IO_REPARSE_TAG_DFS              = const_cpu_to_le32(0x68000008),
+       IO_REPARSE_TAG_NSS              = cpu_to_le32(0x68000005),
+       IO_REPARSE_TAG_NSS_RECOVER      = cpu_to_le32(0x68000006),
+       IO_REPARSE_TAG_SIS              = cpu_to_le32(0x68000007),
+       IO_REPARSE_TAG_DFS              = cpu_to_le32(0x68000008),
 
-       IO_REPARSE_TAG_MOUNT_POINT      = const_cpu_to_le32(0x88000003),
+       IO_REPARSE_TAG_MOUNT_POINT      = cpu_to_le32(0x88000003),
 
-       IO_REPARSE_TAG_HSM              = const_cpu_to_le32(0xa8000004),
+       IO_REPARSE_TAG_HSM              = cpu_to_le32(0xa8000004),
 
-       IO_REPARSE_TAG_SYMBOLIC_LINK    = const_cpu_to_le32(0xe8000000),
+       IO_REPARSE_TAG_SYMBOLIC_LINK    = cpu_to_le32(0xe8000000),
 
-       IO_REPARSE_TAG_VALID_VALUES     = const_cpu_to_le32(0xe000ffff),
+       IO_REPARSE_TAG_VALID_VALUES     = cpu_to_le32(0xe000ffff),
 };
 
 /*
index 9468e1c45ae305dae0a5a626d38de952da914d7b..b5a6f08bd35c8b9010f75cce7358cb723e108c6c 100644 (file)
@@ -104,7 +104,7 @@ typedef struct {
  * in this particular client array.  Also inside the client records themselves,
  * this means that there are no client records preceding or following this one.
  */
-#define LOGFILE_NO_CLIENT      const_cpu_to_le16(0xffff)
+#define LOGFILE_NO_CLIENT      cpu_to_le16(0xffff)
 #define LOGFILE_NO_CLIENT_CPU  0xffff
 
 /*
@@ -112,8 +112,8 @@ typedef struct {
  * information about the log file in which they are present.
  */
 enum {
-       RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16(0x0002),
-       RESTART_SPACE_FILLER    = const_cpu_to_le16(0xffff), /* gcc: Force enum bit width to 16. */
+       RESTART_VOLUME_IS_CLEAN = cpu_to_le16(0x0002),
+       RESTART_SPACE_FILLER    = cpu_to_le16(0xffff), /* gcc: Force enum bit width to 16. */
 } __attribute__ ((__packed__));
 
 typedef le16 RESTART_AREA_FLAGS;
index 17d32ca6bc35b7dc5036033e1afa8b91e5ee4d38..23bf68453d7dec8f16e5691d17dadbbe9776e1b2 100644 (file)
@@ -2839,7 +2839,7 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
         */
 
        /* Mark the mft record as not in use. */
-       m->flags &= const_cpu_to_le16(~const_le16_to_cpu(MFT_RECORD_IN_USE));
+       m->flags &= ~MFT_RECORD_IN_USE;
 
        /* Increment the sequence number, skipping zero, if it is not zero. */
        old_seq_no = m->sequence_number;
index 4a46743b5077a5e98e59d8f2b0205a4bc20e75a5..f76951dcd4a6e984f2469b06df80dd0aa9e96891 100644 (file)
@@ -618,7 +618,7 @@ static bool is_boot_sector_ntfs(const struct super_block *sb,
         * many BIOSes will refuse to boot from a bootsector if the magic is
         * incorrect, so we emit a warning.
         */
-       if (!silent && b->end_of_sector_marker != const_cpu_to_le16(0xaa55))
+       if (!silent && b->end_of_sector_marker != cpu_to_le16(0xaa55))
                ntfs_warning(sb, "Invalid end of sector marker.");
        return true;
 not_ntfs:
@@ -1242,13 +1242,13 @@ static int check_windows_hibernation_status(ntfs_volume *vol)
        u32 *kaddr, *kend;
        ntfs_name *name = NULL;
        int ret = 1;
-       static const ntfschar hiberfil[13] = { const_cpu_to_le16('h'),
-                       const_cpu_to_le16('i'), const_cpu_to_le16('b'),
-                       const_cpu_to_le16('e'), const_cpu_to_le16('r'),
-                       const_cpu_to_le16('f'), const_cpu_to_le16('i'),
-                       const_cpu_to_le16('l'), const_cpu_to_le16('.'),
-                       const_cpu_to_le16('s'), const_cpu_to_le16('y'),
-                       const_cpu_to_le16('s'), 0 };
+       static const ntfschar hiberfil[13] = { cpu_to_le16('h'),
+                       cpu_to_le16('i'), cpu_to_le16('b'),
+                       cpu_to_le16('e'), cpu_to_le16('r'),
+                       cpu_to_le16('f'), cpu_to_le16('i'),
+                       cpu_to_le16('l'), cpu_to_le16('.'),
+                       cpu_to_le16('s'), cpu_to_le16('y'),
+                       cpu_to_le16('s'), 0 };
 
        ntfs_debug("Entering.");
        /*
@@ -1296,7 +1296,7 @@ static int check_windows_hibernation_status(ntfs_volume *vol)
                goto iput_out;
        }
        kaddr = (u32*)page_address(page);
-       if (*(le32*)kaddr == const_cpu_to_le32(0x72626968)/*'hibr'*/) {
+       if (*(le32*)kaddr == cpu_to_le32(0x72626968)/*'hibr'*/) {
                ntfs_debug("Magic \"hibr\" found in hiberfil.sys.  Windows is "
                                "hibernated on the volume.  This is the "
                                "system volume.");
@@ -1337,12 +1337,12 @@ static bool load_and_init_quota(ntfs_volume *vol)
        MFT_REF mref;
        struct inode *tmp_ino;
        ntfs_name *name = NULL;
-       static const ntfschar Quota[7] = { const_cpu_to_le16('$'),
-                       const_cpu_to_le16('Q'), const_cpu_to_le16('u'),
-                       const_cpu_to_le16('o'), const_cpu_to_le16('t'),
-                       const_cpu_to_le16('a'), 0 };
-       static ntfschar Q[3] = { const_cpu_to_le16('$'),
-                       const_cpu_to_le16('Q'), 0 };
+       static const ntfschar Quota[7] = { cpu_to_le16('$'),
+                       cpu_to_le16('Q'), cpu_to_le16('u'),
+                       cpu_to_le16('o'), cpu_to_le16('t'),
+                       cpu_to_le16('a'), 0 };
+       static ntfschar Q[3] = { cpu_to_le16('$'),
+                       cpu_to_le16('Q'), 0 };
 
        ntfs_debug("Entering.");
        /*
@@ -1416,16 +1416,16 @@ static bool load_and_init_usnjrnl(ntfs_volume *vol)
        struct page *page;
        ntfs_name *name = NULL;
        USN_HEADER *uh;
-       static const ntfschar UsnJrnl[9] = { const_cpu_to_le16('$'),
-                       const_cpu_to_le16('U'), const_cpu_to_le16('s'),
-                       const_cpu_to_le16('n'), const_cpu_to_le16('J'),
-                       const_cpu_to_le16('r'), const_cpu_to_le16('n'),
-                       const_cpu_to_le16('l'), 0 };
-       static ntfschar Max[5] = { const_cpu_to_le16('$'),
-                       const_cpu_to_le16('M'), const_cpu_to_le16('a'),
-                       const_cpu_to_le16('x'), 0 };
-       static ntfschar J[3] = { const_cpu_to_le16('$'),
-                       const_cpu_to_le16('J'), 0 };
+       static const ntfschar UsnJrnl[9] = { cpu_to_le16('$'),
+                       cpu_to_le16('U'), cpu_to_le16('s'),
+                       cpu_to_le16('n'), cpu_to_le16('J'),
+                       cpu_to_le16('r'), cpu_to_le16('n'),
+                       cpu_to_le16('l'), 0 };
+       static ntfschar Max[5] = { cpu_to_le16('$'),
+                       cpu_to_le16('M'), cpu_to_le16('a'),
+                       cpu_to_le16('x'), 0 };
+       static ntfschar J[3] = { cpu_to_le16('$'),
+                       cpu_to_le16('J'), 0 };
 
        ntfs_debug("Entering.");
        /*
index 4087fbdac327e19a586576aa6bc5bf95d307f96d..00d8e6bd7c369d1f124dc0c13c2b511bfb57cfd5 100644 (file)
@@ -116,27 +116,27 @@ typedef struct {
  * documentation: http://www.linux-ntfs.org/
  */
 enum {
-       USN_REASON_DATA_OVERWRITE       = const_cpu_to_le32(0x00000001),
-       USN_REASON_DATA_EXTEND          = const_cpu_to_le32(0x00000002),
-       USN_REASON_DATA_TRUNCATION      = const_cpu_to_le32(0x00000004),
-       USN_REASON_NAMED_DATA_OVERWRITE = const_cpu_to_le32(0x00000010),
-       USN_REASON_NAMED_DATA_EXTEND    = const_cpu_to_le32(0x00000020),
-       USN_REASON_NAMED_DATA_TRUNCATION= const_cpu_to_le32(0x00000040),
-       USN_REASON_FILE_CREATE          = const_cpu_to_le32(0x00000100),
-       USN_REASON_FILE_DELETE          = const_cpu_to_le32(0x00000200),
-       USN_REASON_EA_CHANGE            = const_cpu_to_le32(0x00000400),
-       USN_REASON_SECURITY_CHANGE      = const_cpu_to_le32(0x00000800),
-       USN_REASON_RENAME_OLD_NAME      = const_cpu_to_le32(0x00001000),
-       USN_REASON_RENAME_NEW_NAME      = const_cpu_to_le32(0x00002000),
-       USN_REASON_INDEXABLE_CHANGE     = const_cpu_to_le32(0x00004000),
-       USN_REASON_BASIC_INFO_CHANGE    = const_cpu_to_le32(0x00008000),
-       USN_REASON_HARD_LINK_CHANGE     = const_cpu_to_le32(0x00010000),
-       USN_REASON_COMPRESSION_CHANGE   = const_cpu_to_le32(0x00020000),
-       USN_REASON_ENCRYPTION_CHANGE    = const_cpu_to_le32(0x00040000),
-       USN_REASON_OBJECT_ID_CHANGE     = const_cpu_to_le32(0x00080000),
-       USN_REASON_REPARSE_POINT_CHANGE = const_cpu_to_le32(0x00100000),
-       USN_REASON_STREAM_CHANGE        = const_cpu_to_le32(0x00200000),
-       USN_REASON_CLOSE                = const_cpu_to_le32(0x80000000),
+       USN_REASON_DATA_OVERWRITE       = cpu_to_le32(0x00000001),
+       USN_REASON_DATA_EXTEND          = cpu_to_le32(0x00000002),
+       USN_REASON_DATA_TRUNCATION      = cpu_to_le32(0x00000004),
+       USN_REASON_NAMED_DATA_OVERWRITE = cpu_to_le32(0x00000010),
+       USN_REASON_NAMED_DATA_EXTEND    = cpu_to_le32(0x00000020),
+       USN_REASON_NAMED_DATA_TRUNCATION= cpu_to_le32(0x00000040),
+       USN_REASON_FILE_CREATE          = cpu_to_le32(0x00000100),
+       USN_REASON_FILE_DELETE          = cpu_to_le32(0x00000200),
+       USN_REASON_EA_CHANGE            = cpu_to_le32(0x00000400),
+       USN_REASON_SECURITY_CHANGE      = cpu_to_le32(0x00000800),
+       USN_REASON_RENAME_OLD_NAME      = cpu_to_le32(0x00001000),
+       USN_REASON_RENAME_NEW_NAME      = cpu_to_le32(0x00002000),
+       USN_REASON_INDEXABLE_CHANGE     = cpu_to_le32(0x00004000),
+       USN_REASON_BASIC_INFO_CHANGE    = cpu_to_le32(0x00008000),
+       USN_REASON_HARD_LINK_CHANGE     = cpu_to_le32(0x00010000),
+       USN_REASON_COMPRESSION_CHANGE   = cpu_to_le32(0x00020000),
+       USN_REASON_ENCRYPTION_CHANGE    = cpu_to_le32(0x00040000),
+       USN_REASON_OBJECT_ID_CHANGE     = cpu_to_le32(0x00080000),
+       USN_REASON_REPARSE_POINT_CHANGE = cpu_to_le32(0x00100000),
+       USN_REASON_STREAM_CHANGE        = cpu_to_le32(0x00200000),
+       USN_REASON_CLOSE                = cpu_to_le32(0x80000000),
 };
 
 typedef le32 USN_REASON_FLAGS;
@@ -148,9 +148,9 @@ typedef le32 USN_REASON_FLAGS;
  *     http://www.linux-ntfs.org/
  */
 enum {
-       USN_SOURCE_DATA_MANAGEMENT        = const_cpu_to_le32(0x00000001),
-       USN_SOURCE_AUXILIARY_DATA         = const_cpu_to_le32(0x00000002),
-       USN_SOURCE_REPLICATION_MANAGEMENT = const_cpu_to_le32(0x00000004),
+       USN_SOURCE_DATA_MANAGEMENT        = cpu_to_le32(0x00000001),
+       USN_SOURCE_AUXILIARY_DATA         = cpu_to_le32(0x00000002),
+       USN_SOURCE_REPLICATION_MANAGEMENT = cpu_to_le32(0x00000004),
 };
 
 typedef le32 USN_SOURCE_INFO_FLAGS;
index eea1d24713ea13d6f4500eb059613a75d98ae933..b606496b72ec55c65554c6e72a9353e7739a4e9f 100644 (file)
@@ -154,8 +154,9 @@ out:
        return ret;
 }
 
-static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
+       struct page *page = vmf->page;
        struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
        struct buffer_head *di_bh = NULL;
        sigset_t blocked, oldset;
@@ -196,7 +197,8 @@ out:
        ret2 = ocfs2_vm_op_unblock_sigs(&oldset);
        if (ret2 < 0)
                mlog_errno(ret2);
-
+       if (ret)
+               ret = VM_FAULT_SIGBUS;
        return ret;
 }
 
index 633e9dc972bbc63edb052e89cd924aad8e25e8c3..d79e808fd028dbdd7fb31aa4390a84d50010440e 100644 (file)
@@ -262,14 +262,19 @@ static int omfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *s = dentry->d_sb;
        struct omfs_sb_info *sbi = OMFS_SB(s);
+       u64 id = huge_encode_dev(s->s_bdev->bd_dev);
+
        buf->f_type = OMFS_MAGIC;
        buf->f_bsize = sbi->s_blocksize;
        buf->f_blocks = sbi->s_num_blocks;
        buf->f_files = sbi->s_num_blocks;
        buf->f_namelen = OMFS_NAMELEN;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
 
        buf->f_bfree = buf->f_bavail = buf->f_ffree =
                omfs_count_free(s);
+
        return 0;
 }
 
index aef6d55b7de6761913d78a6ab594d5ddce7119ec..e0afd326b6881b7ff2506e1d9041ed12c7ce1e0d 100644 (file)
@@ -146,15 +146,22 @@ static unsigned int pid_entry_count_dirs(const struct pid_entry *entries,
        return count;
 }
 
-static struct fs_struct *get_fs_struct(struct task_struct *task)
+static int get_fs_path(struct task_struct *task, struct path *path, bool root)
 {
        struct fs_struct *fs;
+       int result = -ENOENT;
+
        task_lock(task);
        fs = task->fs;
-       if(fs)
-               atomic_inc(&fs->count);
+       if (fs) {
+               read_lock(&fs->lock);
+               *path = root ? fs->root : fs->pwd;
+               path_get(path);
+               read_unlock(&fs->lock);
+               result = 0;
+       }
        task_unlock(task);
-       return fs;
+       return result;
 }
 
 static int get_nr_threads(struct task_struct *tsk)
@@ -172,42 +179,24 @@ static int get_nr_threads(struct task_struct *tsk)
 static int proc_cwd_link(struct inode *inode, struct path *path)
 {
        struct task_struct *task = get_proc_task(inode);
-       struct fs_struct *fs = NULL;
        int result = -ENOENT;
 
        if (task) {
-               fs = get_fs_struct(task);
+               result = get_fs_path(task, path, 0);
                put_task_struct(task);
        }
-       if (fs) {
-               read_lock(&fs->lock);
-               *path = fs->pwd;
-               path_get(&fs->pwd);
-               read_unlock(&fs->lock);
-               result = 0;
-               put_fs_struct(fs);
-       }
        return result;
 }
 
 static int proc_root_link(struct inode *inode, struct path *path)
 {
        struct task_struct *task = get_proc_task(inode);
-       struct fs_struct *fs = NULL;
        int result = -ENOENT;
 
        if (task) {
-               fs = get_fs_struct(task);
+               result = get_fs_path(task, path, 1);
                put_task_struct(task);
        }
-       if (fs) {
-               read_lock(&fs->lock);
-               *path = fs->root;
-               path_get(&fs->root);
-               read_unlock(&fs->lock);
-               result = 0;
-               put_fs_struct(fs);
-       }
        return result;
 }
 
@@ -596,7 +585,6 @@ static int mounts_open_common(struct inode *inode, struct file *file,
        struct task_struct *task = get_proc_task(inode);
        struct nsproxy *nsp;
        struct mnt_namespace *ns = NULL;
-       struct fs_struct *fs = NULL;
        struct path root;
        struct proc_mounts *p;
        int ret = -EINVAL;
@@ -610,22 +598,16 @@ static int mounts_open_common(struct inode *inode, struct file *file,
                                get_mnt_ns(ns);
                }
                rcu_read_unlock();
-               if (ns)
-                       fs = get_fs_struct(task);
+               if (ns && get_fs_path(task, &root, 1) == 0)
+                       ret = 0;
                put_task_struct(task);
        }
 
        if (!ns)
                goto err;
-       if (!fs)
+       if (ret)
                goto err_put_ns;
 
-       read_lock(&fs->lock);
-       root = fs->root;
-       path_get(&root);
-       read_unlock(&fs->lock);
-       put_fs_struct(fs);
-
        ret = -ENOMEM;
        p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
        if (!p)
index 5d2989e9dcc125d17aac475df1007b86f43490fd..fa678abc9db1524c35cd543c9b32a1b49e713faf 100644 (file)
@@ -37,7 +37,7 @@ static int proc_match(int len, const char *name, struct proc_dir_entry *de)
 #define PROC_BLOCK_SIZE        (PAGE_SIZE - 1024)
 
 static ssize_t
-proc_file_read(struct file *file, char __user *buf, size_t nbytes,
+__proc_file_read(struct file *file, char __user *buf, size_t nbytes,
               loff_t *ppos)
 {
        struct inode * inode = file->f_path.dentry->d_inode;
@@ -182,20 +182,48 @@ proc_file_read(struct file *file, char __user *buf, size_t nbytes,
        return retval;
 }
 
+static ssize_t
+proc_file_read(struct file *file, char __user *buf, size_t nbytes,
+              loff_t *ppos)
+{
+       struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+       ssize_t rv = -EIO;
+
+       spin_lock(&pde->pde_unload_lock);
+       if (!pde->proc_fops) {
+               spin_unlock(&pde->pde_unload_lock);
+               return rv;
+       }
+       pde->pde_users++;
+       spin_unlock(&pde->pde_unload_lock);
+
+       rv = __proc_file_read(file, buf, nbytes, ppos);
+
+       pde_users_dec(pde);
+       return rv;
+}
+
 static ssize_t
 proc_file_write(struct file *file, const char __user *buffer,
                size_t count, loff_t *ppos)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
-       struct proc_dir_entry * dp;
-       
-       dp = PDE(inode);
-
-       if (!dp->write_proc)
-               return -EIO;
+       struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+       ssize_t rv = -EIO;
+
+       if (pde->write_proc) {
+               spin_lock(&pde->pde_unload_lock);
+               if (!pde->proc_fops) {
+                       spin_unlock(&pde->pde_unload_lock);
+                       return rv;
+               }
+               pde->pde_users++;
+               spin_unlock(&pde->pde_unload_lock);
 
-       /* FIXME: does this routine need ppos?  probably... */
-       return dp->write_proc(file, buffer, count, dp->data);
+               /* FIXME: does this routine need ppos?  probably... */
+               rv = pde->write_proc(file, buffer, count, pde->data);
+               pde_users_dec(pde);
+       }
+       return rv;
 }
 
 
@@ -307,6 +335,21 @@ static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */
 /*
  * Return an inode number between PROC_DYNAMIC_FIRST and
  * 0xffffffff, or zero on failure.
+ *
+ * Current inode allocations in the proc-fs (hex-numbers):
+ *
+ * 00000000            reserved
+ * 00000001-00000fff   static entries  (goners)
+ *      001            root-ino
+ *
+ * 00001000-00001fff   unused
+ * 0001xxxx-7fffxxxx   pid-dir entries for pid 1-7fff
+ * 80000000-efffffff   unused
+ * f0000000-ffffffff   dynamic entries
+ *
+ * Goal:
+ *     Once we split the thing into several virtual filesystems,
+ *     we will get rid of magical ranges (and this comment, BTW).
  */
 static unsigned int get_inode_number(void)
 {
diff --git a/fs/proc/inode-alloc.txt b/fs/proc/inode-alloc.txt
deleted file mode 100644 (file)
index 77212f9..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-Current inode allocations in the proc-fs (hex-numbers):
-
-  00000000             reserved
-  00000001-00000fff    static entries  (goners)
-       001             root-ino
-
-  00001000-00001fff    unused
-  0001xxxx-7fffxxxx    pid-dir entries for pid 1-7fff
-  80000000-efffffff    unused
-  f0000000-ffffffff    dynamic entries
-
-Goal:
-       a) once we'll split the thing into several virtual filesystems we
-       will get rid of magical ranges (and this file, BTW).
index d8bb5c671f420a83c17c740425e6f71f9d85799e..d78ade305541d84a0a7b7682f203cd649c1e5a6a 100644 (file)
@@ -58,11 +58,8 @@ static void proc_delete_inode(struct inode *inode)
 
        /* Let go of any associated proc directory entry */
        de = PROC_I(inode)->pde;
-       if (de) {
-               if (de->owner)
-                       module_put(de->owner);
+       if (de)
                de_put(de);
-       }
        if (PROC_I(inode)->sysctl)
                sysctl_head_put(PROC_I(inode)->sysctl);
        clear_inode(inode);
@@ -127,7 +124,7 @@ static void __pde_users_dec(struct proc_dir_entry *pde)
                complete(pde->pde_unload_completion);
 }
 
-static void pde_users_dec(struct proc_dir_entry *pde)
+void pde_users_dec(struct proc_dir_entry *pde)
 {
        spin_lock(&pde->pde_unload_lock);
        __pde_users_dec(pde);
@@ -449,12 +446,9 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
 {
        struct inode * inode;
 
-       if (!try_module_get(de->owner))
-               goto out_mod;
-
        inode = iget_locked(sb, ino);
        if (!inode)
-               goto out_ino;
+               return NULL;
        if (inode->i_state & I_NEW) {
                inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
                PROC_I(inode)->fd = 0;
@@ -485,16 +479,9 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
                        }
                }
                unlock_new_inode(inode);
-       } else {
-              module_put(de->owner);
+       } else
               de_put(de);
-       }
        return inode;
-
-out_ino:
-       module_put(de->owner);
-out_mod:
-       return NULL;
 }                      
 
 int proc_fill_super(struct super_block *s)
index cd53ff838498de03973494d6a70ddae9f193a1ce..f6db9618a88896f741bff9d1403d20189b445e6e 100644 (file)
@@ -91,3 +91,4 @@ struct pde_opener {
        int (*release)(struct inode *, struct file *);
        struct list_head lh;
 };
+void pde_users_dec(struct proc_dir_entry *pde);
index 43d23948384addca6930aa65acbf49804226827f..74ea974f5ca6d86bd249ee920527be9c95157522 100644 (file)
@@ -120,7 +120,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
                K(i.freeram-i.freehigh),
 #endif
 #ifndef CONFIG_MMU
-               K((unsigned long) atomic_read(&mmap_pages_allocated)),
+               K((unsigned long) atomic_long_read(&mmap_pages_allocated)),
 #endif
                K(i.totalswap),
                K(i.freeswap),
index d153946d6d15553223c563f901d12bd976c65832..83adcc86943742ef58bf22b4fb16a986a560450e 100644 (file)
@@ -144,17 +144,12 @@ void proc_tty_register_driver(struct tty_driver *driver)
 {
        struct proc_dir_entry *ent;
                
-       if (!driver->ops->read_proc || !driver->driver_name ||
-           driver->proc_entry)
+       if (!driver->driver_name || driver->proc_entry ||
+           !driver->ops->proc_fops)
                return;
 
-       ent = create_proc_entry(driver->driver_name, 0, proc_tty_driver);
-       if (!ent)
-               return;
-       ent->read_proc = driver->ops->read_proc;
-       ent->owner = driver->owner;
-       ent->data = driver;
-
+       ent = proc_create_data(driver->driver_name, 0, proc_tty_driver,
+                              driver->ops->proc_fops, driver);
        driver->proc_entry = ent;
 }
 
index 94063840832ad99709d4ca878d9aff8704ac6424..b0ae0be4801f821f81c872299c135f55e6fb377c 100644 (file)
@@ -693,8 +693,8 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
                goto out_pages;
        }
 
-       pm.out = (u64 *)buf;
-       pm.end = (u64 *)(buf + count);
+       pm.out = (u64 __user *)buf;
+       pm.end = (u64 __user *)(buf + count);
 
        pagemap_walk.pmd_entry = pagemap_pte_range;
        pagemap_walk.pte_hole = pagemap_pte_hole;
@@ -720,9 +720,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
        if (ret == PM_END_OF_BUFFER)
                ret = 0;
        /* don't need mmap_sem for these, but this looks cleaner */
-       *ppos += (char *)pm.out - buf;
+       *ppos += (char __user *)pm.out - buf;
        if (!ret)
-               ret = (char *)pm.out - buf;
+               ret = (char __user *)pm.out - buf;
 
 out_pages:
        for (; pagecount; pagecount--) {
index 343ea1216bc8e05ddc84e75af47cfbab73fee529..370be0a2c9098ea411ed98bd49d2de929392f32f 100644 (file)
@@ -136,14 +136,14 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
        }
 
        seq_printf(m,
-                  "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n",
+                  "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
                   vma->vm_start,
                   vma->vm_end,
                   flags & VM_READ ? 'r' : '-',
                   flags & VM_WRITE ? 'w' : '-',
                   flags & VM_EXEC ? 'x' : '-',
                   flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
-                  vma->vm_pgoff << PAGE_SHIFT,
+                  (unsigned long long) vma->vm_pgoff << PAGE_SHIFT,
                   MAJOR(dev), MINOR(dev), ino, &len);
 
        if (file) {
index df26aa88fa47cd46731f506d270d2faafc2e1fbd..0c10a0b3f1460c5ff8d533de1c6304a657c097fd 100644 (file)
@@ -1,45 +1,43 @@
+#include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/sched.h>
+#include <linux/seq_file.h>
 #include <linux/time.h>
 #include <asm/cputime.h>
 
-static int proc_calc_metrics(char *page, char **start, off_t off,
-                                int count, int *eof, int len)
-{
-       if (len <= off + count)
-               *eof = 1;
-       *start = page + off;
-       len -= off;
-       if (len > count)
-               len = count;
-       if (len < 0)
-               len = 0;
-       return len;
-}
-
-static int uptime_read_proc(char *page, char **start, off_t off, int count,
-                           int *eof, void *data)
+static int uptime_proc_show(struct seq_file *m, void *v)
 {
        struct timespec uptime;
        struct timespec idle;
-       int len;
        cputime_t idletime = cputime_add(init_task.utime, init_task.stime);
 
        do_posix_clock_monotonic_gettime(&uptime);
        monotonic_to_bootbased(&uptime);
        cputime_to_timespec(idletime, &idle);
-       len = sprintf(page, "%lu.%02lu %lu.%02lu\n",
+       seq_printf(m, "%lu.%02lu %lu.%02lu\n",
                        (unsigned long) uptime.tv_sec,
                        (uptime.tv_nsec / (NSEC_PER_SEC / 100)),
                        (unsigned long) idle.tv_sec,
                        (idle.tv_nsec / (NSEC_PER_SEC / 100)));
-       return proc_calc_metrics(page, start, off, count, eof, len);
+       return 0;
 }
 
+static int uptime_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, uptime_proc_show, NULL);
+}
+
+static const struct file_operations uptime_proc_fops = {
+       .open           = uptime_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static int __init proc_uptime_init(void)
 {
-       create_proc_read_entry("uptime", 0, NULL, uptime_read_proc, NULL);
+       proc_create("uptime", 0, NULL, &uptime_proc_fops);
        return 0;
 }
 module_init(proc_uptime_init);
index 2aad1044b84ccf1342578cd66407ef88e406cf1d..fe1f0f31d11caac6854e9ced2fb471075f3bf894 100644 (file)
@@ -282,6 +282,7 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock )
 static int qnx4_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        lock_kernel();
 
@@ -291,6 +292,8 @@ static int qnx4_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bfree   = qnx4_count_free_blocks(sb);
        buf->f_bavail  = buf->f_bfree;
        buf->f_namelen = QNX4_NAME_MAX;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
 
        unlock_kernel();
 
index 2ca967a5ef77de2011d9896695bf80ad4f0e155b..607c579e5eca0cc0427c53a844d68ff159186e47 100644 (file)
@@ -823,7 +823,7 @@ static void add_dquot_ref(struct super_block *sb, int type)
 
        spin_lock(&inode_lock);
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
-               if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW))
+               if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW))
                        continue;
                if (!atomic_read(&inode->i_writecount))
                        continue;
index 995ef1d6686cf38348af80da2083eb0c90bcf2ca..ebb2c417912c0c7306d73c007b771702e7faee2e 100644 (file)
@@ -59,7 +59,6 @@ const struct inode_operations ramfs_file_inode_operations = {
  */
 int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
 {
-       struct pagevec lru_pvec;
        unsigned long npages, xpages, loop, limit;
        struct page *pages;
        unsigned order;
@@ -102,24 +101,20 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
        memset(data, 0, newsize);
 
        /* attach all the pages to the inode's address space */
-       pagevec_init(&lru_pvec, 0);
        for (loop = 0; loop < npages; loop++) {
                struct page *page = pages + loop;
 
-               ret = add_to_page_cache(page, inode->i_mapping, loop, GFP_KERNEL);
+               ret = add_to_page_cache_lru(page, inode->i_mapping, loop,
+                                       GFP_KERNEL);
                if (ret < 0)
                        goto add_error;
 
-               if (!pagevec_add(&lru_pvec, page))
-                       __pagevec_lru_add_file(&lru_pvec);
-
                /* prevent the page from being discarded on memory pressure */
                SetPageDirty(page);
 
                unlock_page(page);
        }
 
-       pagevec_lru_add_file(&lru_pvec);
        return 0;
 
  fsize_exceeded:
@@ -128,10 +123,8 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
        return -EFBIG;
 
  add_error:
-       pagevec_lru_add_file(&lru_pvec);
-       page_cache_release(pages + loop);
-       for (loop++; loop < npages; loop++)
-               __free_page(pages + loop);
+       while (loop < npages)
+               __free_page(pages + loop++);
        return ret;
 }
 
index b7e6ac706b87b30ba96701b3bb7820e47f319218..a404fb88e4569ff63ef9cc001216519d702c577c 100644 (file)
 #include <linux/backing-dev.h>
 #include <linux/ramfs.h>
 #include <linux/sched.h>
+#include <linux/parser.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
 /* some random number */
 #define RAMFS_MAGIC    0x858458f6
 
+#define RAMFS_DEFAULT_MODE     0755
+
 static const struct super_operations ramfs_ops;
 static const struct inode_operations ramfs_dir_inode_operations;
 
@@ -158,12 +161,75 @@ static const struct inode_operations ramfs_dir_inode_operations = {
 static const struct super_operations ramfs_ops = {
        .statfs         = simple_statfs,
        .drop_inode     = generic_delete_inode,
+       .show_options   = generic_show_options,
+};
+
+struct ramfs_mount_opts {
+       umode_t mode;
+};
+
+enum {
+       Opt_mode,
+       Opt_err
+};
+
+static const match_table_t tokens = {
+       {Opt_mode, "mode=%o"},
+       {Opt_err, NULL}
+};
+
+struct ramfs_fs_info {
+       struct ramfs_mount_opts mount_opts;
 };
 
+static int ramfs_parse_options(char *data, struct ramfs_mount_opts *opts)
+{
+       substring_t args[MAX_OPT_ARGS];
+       int option;
+       int token;
+       char *p;
+
+       opts->mode = RAMFS_DEFAULT_MODE;
+
+       while ((p = strsep(&data, ",")) != NULL) {
+               if (!*p)
+                       continue;
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_mode:
+                       if (match_octal(&args[0], &option))
+                               return -EINVAL;
+                       opts->mode = option & S_IALLUGO;
+                       break;
+               default:
+                       printk(KERN_ERR "ramfs: bad mount option: %s\n", p);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 static int ramfs_fill_super(struct super_block * sb, void * data, int silent)
 {
-       struct inode * inode;
-       struct dentry * root;
+       struct ramfs_fs_info *fsi;
+       struct inode *inode = NULL;
+       struct dentry *root;
+       int err;
+
+       save_mount_options(sb, data);
+
+       fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL);
+       if (!fsi) {
+               err = -ENOMEM;
+               goto fail;
+       }
+       sb->s_fs_info = fsi;
+
+       err = ramfs_parse_options(data, &fsi->mount_opts);
+       if (err)
+               goto fail;
 
        sb->s_maxbytes = MAX_LFS_FILESIZE;
        sb->s_blocksize = PAGE_CACHE_SIZE;
@@ -171,17 +237,23 @@ static int ramfs_fill_super(struct super_block * sb, void * data, int silent)
        sb->s_magic = RAMFS_MAGIC;
        sb->s_op = &ramfs_ops;
        sb->s_time_gran = 1;
-       inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0);
-       if (!inode)
-               return -ENOMEM;
+       inode = ramfs_get_inode(sb, S_IFDIR | fsi->mount_opts.mode, 0);
+       if (!inode) {
+               err = -ENOMEM;
+               goto fail;
+       }
 
        root = d_alloc_root(inode);
        if (!root) {
-               iput(inode);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto fail;
        }
        sb->s_root = root;
        return 0;
+fail:
+       kfree(fsi);
+       iput(inode);
+       return err;
 }
 
 int ramfs_get_sb(struct file_system_type *fs_type,
@@ -197,10 +269,16 @@ static int rootfs_get_sb(struct file_system_type *fs_type,
                            mnt);
 }
 
+static void ramfs_kill_sb(struct super_block *sb)
+{
+       kfree(sb->s_fs_info);
+       kill_litter_super(sb);
+}
+
 static struct file_system_type ramfs_fs_type = {
        .name           = "ramfs",
        .get_sb         = ramfs_get_sb,
-       .kill_sb        = kill_litter_super,
+       .kill_sb        = ramfs_kill_sb,
 };
 static struct file_system_type rootfs_fs_type = {
        .name           = "rootfs",
index 400fe81c973e90cccdb94c814325bc3ce4e39d19..6d5d8ff238aa50cdce17c4126f775d9af9b00b8f 100644 (file)
@@ -731,6 +731,56 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
        return ret;
 }
 
+SYSCALL_DEFINE5(preadv, unsigned long, fd, const struct iovec __user *, vec,
+               unsigned long, vlen, u32, pos_high, u32, pos_low)
+{
+       loff_t pos = ((loff_t)pos_high << 32) | pos_low;
+       struct file *file;
+       ssize_t ret = -EBADF;
+       int fput_needed;
+
+       if (pos < 0)
+               return -EINVAL;
+
+       file = fget_light(fd, &fput_needed);
+       if (file) {
+               ret = -ESPIPE;
+               if (file->f_mode & FMODE_PREAD)
+                       ret = vfs_readv(file, vec, vlen, &pos);
+               fput_light(file, fput_needed);
+       }
+
+       if (ret > 0)
+               add_rchar(current, ret);
+       inc_syscr(current);
+       return ret;
+}
+
+SYSCALL_DEFINE5(pwritev, unsigned long, fd, const struct iovec __user *, vec,
+               unsigned long, vlen, u32, pos_high, u32, pos_low)
+{
+       loff_t pos = ((loff_t)pos_high << 32) | pos_low;
+       struct file *file;
+       ssize_t ret = -EBADF;
+       int fput_needed;
+
+       if (pos < 0)
+               return -EINVAL;
+
+       file = fget_light(fd, &fput_needed);
+       if (file) {
+               ret = -ESPIPE;
+               if (file->f_mode & FMODE_PWRITE)
+                       ret = vfs_writev(file, vec, vlen, &pos);
+               fput_light(file, fput_needed);
+       }
+
+       if (ret > 0)
+               add_wchar(current, ret);
+       inc_syscw(current);
+       return ret;
+}
+
 static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
                           size_t count, loff_t max)
 {
index 949b8c6addc84c40bf57a58d32932529957f4f09..513f431038f9a749960b6c9b328ece5799684330 100644 (file)
@@ -1,5 +1,6 @@
 config REISERFS_FS
        tristate "Reiserfs support"
+       select CRC32
        help
          Stores not just filenames but the files themselves in a balanced
          tree.  Uses journalling.
index 0eb7ac08048471ac4f34a81cd50c1b4ccc32e81d..7c5ab6330dd6bbe4edbd1f6b62a3a1d5a3f6b645 100644 (file)
@@ -7,10 +7,10 @@ obj-$(CONFIG_REISERFS_FS) += reiserfs.o
 reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \
                 super.o prints.o objectid.o lbalance.o ibalance.o stree.o \
                 hashes.o tail_conversion.o journal.o resize.o \
-                item_ops.o ioctl.o procfs.o
+                item_ops.o ioctl.o procfs.o xattr.o
 
 ifeq ($(CONFIG_REISERFS_FS_XATTR),y)
-reiserfs-objs += xattr.o xattr_user.o xattr_trusted.o
+reiserfs-objs += xattr_user.o xattr_trusted.o
 endif
 
 ifeq ($(CONFIG_REISERFS_FS_SECURITY),y)
index 90e1670e4e6f5a6a20da1dac768d03bc67992884..14e8c9d460e5e517ac200274107a7411a09178f3 100644 (file)
@@ -1,4 +1,4 @@
-[LICENSING] 
+[LICENSING]
 
 ReiserFS is hereby licensed under the GNU General
 Public License version 2.
@@ -31,7 +31,7 @@ the GPL as not allowing those additional licensing options, you read
 it wrongly, and Richard Stallman agrees with me, when carefully read
 you can see that those restrictions on additional terms do not apply
 to the owner of the copyright, and my interpretation of this shall
-govern for this license.  
+govern for this license.
 
 Finally, nothing in this license shall be interpreted to allow you to
 fail to fairly credit me, or to remove my credits, without my
index f32d1425cc9fe58957906967a4f666009e97397f..e716161ab325c8f246b33c11110a60fff351100f 100644 (file)
@@ -40,8 +40,8 @@
 
 #define SET_OPTION(optname) \
    do { \
-        reiserfs_warning(s, "reiserfs: option \"%s\" is set", #optname); \
-        set_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s)); \
+       reiserfs_info(s, "block allocator option \"%s\" is set", #optname); \
+       set_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s)); \
     } while(0)
 #define TEST_OPTION(optname, s) \
     test_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s))
@@ -64,9 +64,9 @@ int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value)
        unsigned int bmap_count = reiserfs_bmap_count(s);
 
        if (block == 0 || block >= SB_BLOCK_COUNT(s)) {
-               reiserfs_warning(s,
-                                "vs-4010: is_reusable: block number is out of range %lu (%u)",
-                                block, SB_BLOCK_COUNT(s));
+               reiserfs_error(s, "vs-4010",
+                              "block number is out of range %lu (%u)",
+                              block, SB_BLOCK_COUNT(s));
                return 0;
        }
 
@@ -79,31 +79,30 @@ int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value)
                b_blocknr_t bmap1 = REISERFS_SB(s)->s_sbh->b_blocknr + 1;
                if (block >= bmap1 &&
                    block <= bmap1 + bmap_count) {
-                       reiserfs_warning(s, "vs: 4019: is_reusable: "
-                                        "bitmap block %lu(%u) can't be freed or reused",
-                                        block, bmap_count);
+                       reiserfs_error(s, "vs-4019", "bitmap block %lu(%u) "
+                                      "can't be freed or reused",
+                                      block, bmap_count);
                        return 0;
                }
        } else {
                if (offset == 0) {
-                       reiserfs_warning(s, "vs: 4020: is_reusable: "
-                                        "bitmap block %lu(%u) can't be freed or reused",
-                                        block, bmap_count);
+                       reiserfs_error(s, "vs-4020", "bitmap block %lu(%u) "
+                                      "can't be freed or reused",
+                                      block, bmap_count);
                        return 0;
                }
        }
 
        if (bmap >= bmap_count) {
-               reiserfs_warning(s,
-                                "vs-4030: is_reusable: there is no so many bitmap blocks: "
-                                "block=%lu, bitmap_nr=%u", block, bmap);
+               reiserfs_error(s, "vs-4030", "bitmap for requested block "
+                              "is out of range: block=%lu, bitmap_nr=%u",
+                              block, bmap);
                return 0;
        }
 
        if (bit_value == 0 && block == SB_ROOT_BLOCK(s)) {
-               reiserfs_warning(s,
-                                "vs-4050: is_reusable: this is root block (%u), "
-                                "it must be busy", SB_ROOT_BLOCK(s));
+               reiserfs_error(s, "vs-4050", "this is root block (%u), "
+                              "it must be busy", SB_ROOT_BLOCK(s));
                return 0;
        }
 
@@ -154,8 +153,8 @@ static int scan_bitmap_block(struct reiserfs_transaction_handle *th,
 /* - I mean `a window of zero bits' as in description of this function - Zam. */
 
        if (!bi) {
-               reiserfs_warning(s, "NULL bitmap info pointer for bitmap %d",
-                                bmap_n);
+               reiserfs_error(s, "jdm-4055", "NULL bitmap info pointer "
+                              "for bitmap %d", bmap_n);
                return 0;
        }
 
@@ -400,11 +399,8 @@ static void _reiserfs_free_block(struct reiserfs_transaction_handle *th,
        get_bit_address(s, block, &nr, &offset);
 
        if (nr >= reiserfs_bmap_count(s)) {
-               reiserfs_warning(s, "vs-4075: reiserfs_free_block: "
-                                "block %lu is out of range on %s "
-                                "(nr=%u,max=%u)", block,
-                                reiserfs_bdevname(s), nr,
-                                reiserfs_bmap_count(s));
+               reiserfs_error(s, "vs-4075", "block %lu is out of range",
+                              block);
                return;
        }
 
@@ -416,9 +412,8 @@ static void _reiserfs_free_block(struct reiserfs_transaction_handle *th,
 
        /* clear bit for the given block in bit map */
        if (!reiserfs_test_and_clear_le_bit(offset, bmbh->b_data)) {
-               reiserfs_warning(s, "vs-4080: reiserfs_free_block: "
-                                "free_block (%s:%lu)[dev:blocknr]: bit already cleared",
-                                reiserfs_bdevname(s), block);
+               reiserfs_error(s, "vs-4080",
+                              "block %lu: bit already cleared", block);
        }
        apbi[nr].free_count++;
        journal_mark_dirty(th, s, bmbh);
@@ -445,7 +440,7 @@ void reiserfs_free_block(struct reiserfs_transaction_handle *th,
                return;
 
        if (block > sb_block_count(REISERFS_SB(s)->s_rs)) {
-               reiserfs_panic(th->t_super, "bitmap-4072",
+               reiserfs_error(th->t_super, "bitmap-4072",
                               "Trying to free block outside file system "
                               "boundaries (%lu > %lu)",
                               block, sb_block_count(REISERFS_SB(s)->s_rs));
@@ -477,9 +472,8 @@ static void __discard_prealloc(struct reiserfs_transaction_handle *th,
        BUG_ON(!th->t_trans_id);
 #ifdef CONFIG_REISERFS_CHECK
        if (ei->i_prealloc_count < 0)
-               reiserfs_warning(th->t_super,
-                                "zam-4001:%s: inode has negative prealloc blocks count.",
-                                __func__);
+               reiserfs_error(th->t_super, "zam-4001",
+                              "inode has negative prealloc blocks count.");
 #endif
        while (ei->i_prealloc_count > 0) {
                reiserfs_free_prealloc_block(th, inode, ei->i_prealloc_block);
@@ -515,9 +509,9 @@ void reiserfs_discard_all_prealloc(struct reiserfs_transaction_handle *th)
                                i_prealloc_list);
 #ifdef CONFIG_REISERFS_CHECK
                if (!ei->i_prealloc_count) {
-                       reiserfs_warning(th->t_super,
-                                        "zam-4001:%s: inode is in prealloc list but has no preallocated blocks.",
-                                        __func__);
+                       reiserfs_error(th->t_super, "zam-4001",
+                                      "inode is in prealloc list but has "
+                                      "no preallocated blocks.");
                }
 #endif
                __discard_prealloc(th, ei);
@@ -631,12 +625,12 @@ int reiserfs_parse_alloc_options(struct super_block *s, char *options)
                        continue;
                }
 
-               reiserfs_warning(s, "zam-4001: %s : unknown option - %s",
-                                __func__, this_char);
+               reiserfs_warning(s, "zam-4001", "unknown option - %s",
+                                this_char);
                return 1;
        }
 
-       reiserfs_warning(s, "allocator options = [%08x]\n", SB_ALLOC_OPTS(s));
+       reiserfs_info(s, "allocator options = [%08x]\n", SB_ALLOC_OPTS(s));
        return 0;
 }
 
@@ -1221,7 +1215,9 @@ void reiserfs_cache_bitmap_metadata(struct super_block *sb,
        unsigned long *cur = (unsigned long *)(bh->b_data + bh->b_size);
 
        /* The first bit must ALWAYS be 1 */
-       BUG_ON(!reiserfs_test_le_bit(0, (unsigned long *)bh->b_data));
+       if (!reiserfs_test_le_bit(0, (unsigned long *)bh->b_data))
+               reiserfs_error(sb, "reiserfs-2025", "bitmap block %lu is "
+                              "corrupted: first bit must be 1", bh->b_blocknr);
 
        info->free_count = 0;
 
index e6b03d2020c1c51aedbe6e443ccc7e236c50d242..67a80d7e59e2ade01b7608e398857d1cee9cec07 100644 (file)
@@ -41,10 +41,10 @@ static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
 
 #define store_ih(where,what) copy_item_head (where, what)
 
-//
-static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent,
+                          filldir_t filldir, loff_t *pos)
 {
-       struct inode *inode = filp->f_path.dentry->d_inode;
+       struct inode *inode = dentry->d_inode;
        struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */
        INITIALIZE_PATH(path_to_entry);
        struct buffer_head *bh;
@@ -64,13 +64,9 @@ static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
        /* form key for search the next directory entry using f_pos field of
           file structure */
-       make_cpu_key(&pos_key, inode,
-                    (filp->f_pos) ? (filp->f_pos) : DOT_OFFSET, TYPE_DIRENTRY,
-                    3);
+       make_cpu_key(&pos_key, inode, *pos ?: DOT_OFFSET, TYPE_DIRENTRY, 3);
        next_pos = cpu_key_k_offset(&pos_key);
 
-       /*  reiserfs_warning (inode->i_sb, "reiserfs_readdir 1: f_pos = %Ld", filp->f_pos); */
-
        path_to_entry.reada = PATH_READA;
        while (1) {
              research:
@@ -144,7 +140,7 @@ static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                                /* Ignore the .reiserfs_priv entry */
                                if (reiserfs_xattrs(inode->i_sb) &&
                                    !old_format_only(inode->i_sb) &&
-                                   filp->f_path.dentry == inode->i_sb->s_root &&
+                                   dentry == inode->i_sb->s_root &&
                                    REISERFS_SB(inode->i_sb)->priv_root &&
                                    REISERFS_SB(inode->i_sb)->priv_root->d_inode
                                    && deh_objectid(deh) ==
@@ -156,7 +152,7 @@ static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                                }
 
                                d_off = deh_offset(deh);
-                               filp->f_pos = d_off;
+                               *pos = d_off;
                                d_ino = deh_objectid(deh);
                                if (d_reclen <= 32) {
                                        local_buf = small_buf;
@@ -223,15 +219,21 @@ static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
        }                       /* while */
 
-      end:
-       filp->f_pos = next_pos;
+end:
+       *pos = next_pos;
        pathrelse(&path_to_entry);
        reiserfs_check_path(&path_to_entry);
-      out:
+out:
        reiserfs_write_unlock(inode->i_sb);
        return ret;
 }
 
+static int reiserfs_readdir(struct file *file, void *dirent, filldir_t filldir)
+{
+       struct dentry *dentry = file->f_path.dentry;
+       return reiserfs_readdir_dentry(dentry, dirent, filldir, &file->f_pos);
+}
+
 /* compose directory item containing "." and ".." entries (entries are
    not aligned to 4 byte boundary) */
 /* the last four params are LE */
index 2f87f5b14630e2323c9e91c784adc8affb0b1831..4beb964a2a3e602d4fc1723597d9ad5b669ff1c0 100644 (file)
@@ -29,6 +29,43 @@ struct tree_balance *cur_tb = NULL;  /* detects whether more than one
                                           is interrupting do_balance */
 #endif
 
+static inline void buffer_info_init_left(struct tree_balance *tb,
+                                         struct buffer_info *bi)
+{
+       bi->tb          = tb;
+       bi->bi_bh       = tb->L[0];
+       bi->bi_parent   = tb->FL[0];
+       bi->bi_position = get_left_neighbor_position(tb, 0);
+}
+
+static inline void buffer_info_init_right(struct tree_balance *tb,
+                                          struct buffer_info *bi)
+{
+       bi->tb          = tb;
+       bi->bi_bh       = tb->R[0];
+       bi->bi_parent   = tb->FR[0];
+       bi->bi_position = get_right_neighbor_position(tb, 0);
+}
+
+static inline void buffer_info_init_tbS0(struct tree_balance *tb,
+                                         struct buffer_info *bi)
+{
+       bi->tb          = tb;
+       bi->bi_bh        = PATH_PLAST_BUFFER(tb->tb_path);
+       bi->bi_parent   = PATH_H_PPARENT(tb->tb_path, 0);
+       bi->bi_position = PATH_H_POSITION(tb->tb_path, 1);
+}
+
+static inline void buffer_info_init_bh(struct tree_balance *tb,
+                                       struct buffer_info *bi,
+                                       struct buffer_head *bh)
+{
+       bi->tb          = tb;
+       bi->bi_bh       = bh;
+       bi->bi_parent   = NULL;
+       bi->bi_position = 0;
+}
+
 inline void do_balance_mark_leaf_dirty(struct tree_balance *tb,
                                       struct buffer_head *bh, int flag)
 {
@@ -39,21 +76,21 @@ inline void do_balance_mark_leaf_dirty(struct tree_balance *tb,
 #define do_balance_mark_internal_dirty do_balance_mark_leaf_dirty
 #define do_balance_mark_sb_dirty do_balance_mark_leaf_dirty
 
-/* summary: 
+/* summary:
  if deleting something ( tb->insert_size[0] < 0 )
    return(balance_leaf_when_delete()); (flag d handled here)
  else
    if lnum is larger than 0 we put items into the left node
    if rnum is larger than 0 we put items into the right node
    if snum1 is larger than 0 we put items into the new node s1
-   if snum2 is larger than 0 we put items into the new node s2 
+   if snum2 is larger than 0 we put items into the new node s2
 Note that all *num* count new items being created.
 
 It would be easier to read balance_leaf() if each of these summary
 lines was a separate procedure rather than being inlined.  I think
 that there are many passages here and in balance_leaf_when_delete() in
 which two calls to one procedure can replace two passages, and it
-might save cache space and improve software maintenance costs to do so.  
+might save cache space and improve software maintenance costs to do so.
 
 Vladimir made the perceptive comment that we should offload most of
 the decision making in this function into fix_nodes/check_balance, and
@@ -86,6 +123,7 @@ static int balance_leaf_when_delete(struct tree_balance *tb, int flag)
               "PAP-12010: tree can not be empty");
 
        ih = B_N_PITEM_HEAD(tbS0, item_pos);
+       buffer_info_init_tbS0(tb, &bi);
 
        /* Delete or truncate the item */
 
@@ -96,10 +134,6 @@ static int balance_leaf_when_delete(struct tree_balance *tb, int flag)
                       "vs-12013: mode Delete, insert size %d, ih to be deleted %h",
                       -tb->insert_size[0], ih);
 
-               bi.tb = tb;
-               bi.bi_bh = tbS0;
-               bi.bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
-               bi.bi_position = PATH_H_POSITION(tb->tb_path, 1);
                leaf_delete_items(&bi, 0, item_pos, 1, -1);
 
                if (!item_pos && tb->CFL[0]) {
@@ -121,10 +155,6 @@ static int balance_leaf_when_delete(struct tree_balance *tb, int flag)
                break;
 
        case M_CUT:{            /* cut item in S[0] */
-                       bi.tb = tb;
-                       bi.bi_bh = tbS0;
-                       bi.bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
-                       bi.bi_position = PATH_H_POSITION(tb->tb_path, 1);
                        if (is_direntry_le_ih(ih)) {
 
                                /* UFS unlink semantics are such that you can only delete one directory entry at a time. */
@@ -153,8 +183,8 @@ static int balance_leaf_when_delete(struct tree_balance *tb, int flag)
 
        default:
                print_cur_tb("12040");
-               reiserfs_panic(tb->tb_sb,
-                              "PAP-12040: balance_leaf_when_delete: unexpectable mode: %s(%d)",
+               reiserfs_panic(tb->tb_sb, "PAP-12040",
+                              "unexpected mode: %s(%d)",
                               (flag ==
                                M_PASTE) ? "PASTE" : ((flag ==
                                                       M_INSERT) ? "INSERT" :
@@ -258,15 +288,15 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
     )
 {
        struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
-       int item_pos = PATH_LAST_POSITION(tb->tb_path); /*  index into the array of item headers in S[0] 
+       int item_pos = PATH_LAST_POSITION(tb->tb_path); /*  index into the array of item headers in S[0]
                                                           of the affected item */
        struct buffer_info bi;
        struct buffer_head *S_new[2];   /* new nodes allocated to hold what could not fit into S */
        int snum[2];            /* number of items that will be placed
                                   into S_new (includes partially shifted
                                   items) */
-       int sbytes[2];          /* if an item is partially shifted into S_new then 
-                                  if it is a directory item 
+       int sbytes[2];          /* if an item is partially shifted into S_new then
+                                  if it is a directory item
                                   it is the number of entries from the item that are shifted into S_new
                                   else
                                   it is the number of bytes from the item that are shifted into S_new
@@ -325,11 +355,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,     /* item h
                                               ih_item_len(ih));
 
                                        /* Insert new item into L[0] */
-                                       bi.tb = tb;
-                                       bi.bi_bh = tb->L[0];
-                                       bi.bi_parent = tb->FL[0];
-                                       bi.bi_position =
-                                           get_left_neighbor_position(tb, 0);
+                                       buffer_info_init_left(tb, &bi);
                                        leaf_insert_into_buf(&bi,
                                                             n + item_pos -
                                                             ret_val, ih, body,
@@ -369,11 +395,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,     /* item h
                                            leaf_shift_left(tb, tb->lnum[0] - 1,
                                                            tb->lbytes);
                                        /* Insert new item into L[0] */
-                                       bi.tb = tb;
-                                       bi.bi_bh = tb->L[0];
-                                       bi.bi_parent = tb->FL[0];
-                                       bi.bi_position =
-                                           get_left_neighbor_position(tb, 0);
+                                       buffer_info_init_left(tb, &bi);
                                        leaf_insert_into_buf(&bi,
                                                             n + item_pos -
                                                             ret_val, ih, body,
@@ -429,13 +451,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,     /* item h
                                                        }
 
                                                        /* Append given directory entry to directory item */
-                                                       bi.tb = tb;
-                                                       bi.bi_bh = tb->L[0];
-                                                       bi.bi_parent =
-                                                           tb->FL[0];
-                                                       bi.bi_position =
-                                                           get_left_neighbor_position
-                                                           (tb, 0);
+                                                       buffer_info_init_left(tb, &bi);
                                                        leaf_paste_in_buffer
                                                            (&bi,
                                                             n + item_pos -
@@ -449,8 +465,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,      /* item h
                                                        /* when we have merge directory item, pos_in_item has been changed too */
 
                                                        /* paste new directory entry. 1 is entry number */
-                                                       leaf_paste_entries(bi.
-                                                                          bi_bh,
+                                                       leaf_paste_entries(&bi,
                                                                           n +
                                                                           item_pos
                                                                           -
@@ -524,13 +539,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,     /* item h
                                                                             (tbS0,
                                                                              item_pos)));
                                                        /* Append to body of item in L[0] */
-                                                       bi.tb = tb;
-                                                       bi.bi_bh = tb->L[0];
-                                                       bi.bi_parent =
-                                                           tb->FL[0];
-                                                       bi.bi_position =
-                                                           get_left_neighbor_position
-                                                           (tb, 0);
+                                                       buffer_info_init_left(tb, &bi);
                                                        leaf_paste_in_buffer
                                                            (&bi,
                                                             n + item_pos -
@@ -681,11 +690,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,     /* item h
                                            leaf_shift_left(tb, tb->lnum[0],
                                                            tb->lbytes);
                                        /* Append to body of item in L[0] */
-                                       bi.tb = tb;
-                                       bi.bi_bh = tb->L[0];
-                                       bi.bi_parent = tb->FL[0];
-                                       bi.bi_position =
-                                           get_left_neighbor_position(tb, 0);
+                                       buffer_info_init_left(tb, &bi);
                                        leaf_paste_in_buffer(&bi,
                                                             n + item_pos -
                                                             ret_val,
@@ -699,7 +704,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,      /* item h
                                                           n + item_pos -
                                                           ret_val);
                                        if (is_direntry_le_ih(pasted))
-                                               leaf_paste_entries(bi.bi_bh,
+                                               leaf_paste_entries(&bi,
                                                                   n +
                                                                   item_pos -
                                                                   ret_val,
@@ -722,8 +727,9 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,      /* item h
                                }
                                break;
                        default:        /* cases d and t */
-                               reiserfs_panic(tb->tb_sb,
-                                              "PAP-12130: balance_leaf: lnum > 0: unexpectable mode: %s(%d)",
+                               reiserfs_panic(tb->tb_sb, "PAP-12130",
+                                              "lnum > 0: unexpected mode: "
+                                              " %s(%d)",
                                               (flag ==
                                                M_DELETE) ? "DELETE" : ((flag ==
                                                                         M_CUT)
@@ -776,11 +782,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,     /* item h
                                        set_le_ih_k_offset(ih, offset);
                                        put_ih_item_len(ih, tb->rbytes);
                                        /* Insert part of the item into R[0] */
-                                       bi.tb = tb;
-                                       bi.bi_bh = tb->R[0];
-                                       bi.bi_parent = tb->FR[0];
-                                       bi.bi_position =
-                                           get_right_neighbor_position(tb, 0);
+                                       buffer_info_init_right(tb, &bi);
                                        if ((old_len - tb->rbytes) > zeros_num) {
                                                r_zeros_number = 0;
                                                r_body =
@@ -817,11 +819,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,     /* item h
                                                             tb->rnum[0] - 1,
                                                             tb->rbytes);
                                        /* Insert new item into R[0] */
-                                       bi.tb = tb;
-                                       bi.bi_bh = tb->R[0];
-                                       bi.bi_parent = tb->FR[0];
-                                       bi.bi_position =
-                                           get_right_neighbor_position(tb, 0);
+                                       buffer_info_init_right(tb, &bi);
                                        leaf_insert_into_buf(&bi,
                                                             item_pos - n +
                                                             tb->rnum[0] - 1,
@@ -881,21 +879,14 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                                                            pos_in_item -
                                                            entry_count +
                                                            tb->rbytes - 1;
-                                                       bi.tb = tb;
-                                                       bi.bi_bh = tb->R[0];
-                                                       bi.bi_parent =
-                                                           tb->FR[0];
-                                                       bi.bi_position =
-                                                           get_right_neighbor_position
-                                                           (tb, 0);
+                                                       buffer_info_init_right(tb, &bi);
                                                        leaf_paste_in_buffer
                                                            (&bi, 0,
                                                             paste_entry_position,
                                                             tb->insert_size[0],
                                                             body, zeros_num);
                                                        /* paste entry */
-                                                       leaf_paste_entries(bi.
-                                                                          bi_bh,
+                                                       leaf_paste_entries(&bi,
                                                                           0,
                                                                           paste_entry_position,
                                                                           1,
@@ -1019,12 +1010,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
                                                    (tb, tb->CFR[0], 0);
 
                                                /* Append part of body into R[0] */
-                                               bi.tb = tb;
-                                               bi.bi_bh = tb->R[0];
-                                               bi.bi_parent = tb->FR[0];
-                                               bi.bi_position =
-                                                   get_right_neighbor_position
-                                                   (tb, 0);
+                                               buffer_info_init_right(tb, &bi);
                                                if (n_rem > zeros_num) {
                                                        r_zeros_number = 0;
                                                        r_body =
@@ -1071,12 +1057,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
                                                             tb->rbytes);
                                        /* append item in R[0] */
                                        if (pos_in_item >= 0) {
-                                               bi.tb = tb;
-                                               bi.bi_bh = tb->R[0];
-                                               bi.bi_parent = tb->FR[0];
-                                               bi.bi_position =
-                                                   get_right_neighbor_position
-                                                   (tb, 0);
+                                               buffer_info_init_right(tb, &bi);
                                                leaf_paste_in_buffer(&bi,
                                                                     item_pos -
                                                                     n +
@@ -1096,7 +1077,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                                                           tb->rnum[0]);
                                        if (is_direntry_le_ih(pasted)
                                            && pos_in_item >= 0) {
-                                               leaf_paste_entries(bi.bi_bh,
+                                               leaf_paste_entries(&bi,
                                                                   item_pos -
                                                                   n +
                                                                   tb->rnum[0],
@@ -1136,8 +1117,8 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                        }
                        break;
                default:        /* cases d and t */
-                       reiserfs_panic(tb->tb_sb,
-                                      "PAP-12175: balance_leaf: rnum > 0: unexpectable mode: %s(%d)",
+                       reiserfs_panic(tb->tb_sb, "PAP-12175",
+                                      "rnum > 0: unexpected mode: %s(%d)",
                                       (flag ==
                                        M_DELETE) ? "DELETE" : ((flag ==
                                                                 M_CUT) ? "CUT"
@@ -1167,8 +1148,8 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                   not set correctly */
                if (tb->CFL[0]) {
                        if (!tb->CFR[0])
-                               reiserfs_panic(tb->tb_sb,
-                                              "vs-12195: balance_leaf: CFR not initialized");
+                               reiserfs_panic(tb->tb_sb, "vs-12195",
+                                              "CFR not initialized");
                        copy_key(B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0]),
                                 B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0]));
                        do_balance_mark_internal_dirty(tb, tb->CFL[0], 0);
@@ -1232,10 +1213,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
                                        put_ih_item_len(ih, sbytes[i]);
 
                                        /* Insert part of the item into S_new[i] before 0-th item */
-                                       bi.tb = tb;
-                                       bi.bi_bh = S_new[i];
-                                       bi.bi_parent = NULL;
-                                       bi.bi_position = 0;
+                                       buffer_info_init_bh(tb, &bi, S_new[i]);
 
                                        if ((old_len - sbytes[i]) > zeros_num) {
                                                r_zeros_number = 0;
@@ -1267,10 +1245,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
                                                        S_new[i]);
 
                                        /* Insert new item into S_new[i] */
-                                       bi.tb = tb;
-                                       bi.bi_bh = S_new[i];
-                                       bi.bi_parent = NULL;
-                                       bi.bi_position = 0;
+                                       buffer_info_init_bh(tb, &bi, S_new[i]);
                                        leaf_insert_into_buf(&bi,
                                                             item_pos - n +
                                                             snum[i] - 1, ih,
@@ -1327,10 +1302,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
                                                             sbytes[i] - 1,
                                                             S_new[i]);
                                                        /* Paste given directory entry to directory item */
-                                                       bi.tb = tb;
-                                                       bi.bi_bh = S_new[i];
-                                                       bi.bi_parent = NULL;
-                                                       bi.bi_position = 0;
+                                                       buffer_info_init_bh(tb, &bi, S_new[i]);
                                                        leaf_paste_in_buffer
                                                            (&bi, 0,
                                                             pos_in_item -
@@ -1339,8 +1311,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                                                             tb->insert_size[0],
                                                             body, zeros_num);
                                                        /* paste new directory entry */
-                                                       leaf_paste_entries(bi.
-                                                                          bi_bh,
+                                                       leaf_paste_entries(&bi,
                                                                           0,
                                                                           pos_in_item
                                                                           -
@@ -1401,11 +1372,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
                                                if (n_rem < 0)
                                                        n_rem = 0;
                                                /* Append part of body into S_new[0] */
-                                               bi.tb = tb;
-                                               bi.bi_bh = S_new[i];
-                                               bi.bi_parent = NULL;
-                                               bi.bi_position = 0;
-
+                                               buffer_info_init_bh(tb, &bi, S_new[i]);
                                                if (n_rem > zeros_num) {
                                                        r_zeros_number = 0;
                                                        r_body =
@@ -1475,7 +1442,10 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
                                            && (pos_in_item != ih_item_len(ih_check)
                                                || tb->insert_size[0] <= 0))
                                                reiserfs_panic(tb->tb_sb,
-                                                              "PAP-12235: balance_leaf: pos_in_item must be equal to ih_item_len");
+                                                            "PAP-12235",
+                                                            "pos_in_item "
+                                                            "must be equal "
+                                                            "to ih_item_len");
 #endif                         /* CONFIG_REISERFS_CHECK */
 
                                        leaf_mi =
@@ -1489,10 +1459,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
                                               leaf_mi);
 
                                        /* paste into item */
-                                       bi.tb = tb;
-                                       bi.bi_bh = S_new[i];
-                                       bi.bi_parent = NULL;
-                                       bi.bi_position = 0;
+                                       buffer_info_init_bh(tb, &bi, S_new[i]);
                                        leaf_paste_in_buffer(&bi,
                                                             item_pos - n +
                                                             snum[i],
@@ -1505,7 +1472,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                                                           item_pos - n +
                                                           snum[i]);
                                        if (is_direntry_le_ih(pasted)) {
-                                               leaf_paste_entries(bi.bi_bh,
+                                               leaf_paste_entries(&bi,
                                                                   item_pos -
                                                                   n + snum[i],
                                                                   pos_in_item,
@@ -1535,8 +1502,8 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                        }
                        break;
                default:        /* cases d and t */
-                       reiserfs_panic(tb->tb_sb,
-                                      "PAP-12245: balance_leaf: blknum > 2: unexpectable mode: %s(%d)",
+                       reiserfs_panic(tb->tb_sb, "PAP-12245",
+                                      "blknum > 2: unexpected mode: %s(%d)",
                                       (flag ==
                                        M_DELETE) ? "DELETE" : ((flag ==
                                                                 M_CUT) ? "CUT"
@@ -1559,10 +1526,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
 
                switch (flag) {
                case M_INSERT:  /* insert item into S[0] */
-                       bi.tb = tb;
-                       bi.bi_bh = tbS0;
-                       bi.bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
-                       bi.bi_position = PATH_H_POSITION(tb->tb_path, 1);
+                       buffer_info_init_tbS0(tb, &bi);
                        leaf_insert_into_buf(&bi, item_pos, ih, body,
                                             zeros_num);
 
@@ -1589,14 +1553,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
                                                       "PAP-12260: insert_size is 0 already");
 
                                                /* prepare space */
-                                               bi.tb = tb;
-                                               bi.bi_bh = tbS0;
-                                               bi.bi_parent =
-                                                   PATH_H_PPARENT(tb->tb_path,
-                                                                  0);
-                                               bi.bi_position =
-                                                   PATH_H_POSITION(tb->tb_path,
-                                                                   1);
+                                               buffer_info_init_tbS0(tb, &bi);
                                                leaf_paste_in_buffer(&bi,
                                                                     item_pos,
                                                                     pos_in_item,
@@ -1606,7 +1563,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                                                                     zeros_num);
 
                                                /* paste entry */
-                                               leaf_paste_entries(bi.bi_bh,
+                                               leaf_paste_entries(&bi,
                                                                   item_pos,
                                                                   pos_in_item,
                                                                   1,
@@ -1644,14 +1601,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
                                                RFALSE(tb->insert_size[0] <= 0,
                                                       "PAP-12275: insert size must not be %d",
                                                       tb->insert_size[0]);
-                                               bi.tb = tb;
-                                               bi.bi_bh = tbS0;
-                                               bi.bi_parent =
-                                                   PATH_H_PPARENT(tb->tb_path,
-                                                                  0);
-                                               bi.bi_position =
-                                                   PATH_H_POSITION(tb->tb_path,
-                                                                   1);
+                                               buffer_info_init_tbS0(tb, &bi);
                                                leaf_paste_in_buffer(&bi,
                                                                     item_pos,
                                                                     pos_in_item,
@@ -1681,10 +1631,11 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,  /* item h
                                                        print_cur_tb("12285");
                                                        reiserfs_panic(tb->
                                                                       tb_sb,
-                                                                      "PAP-12285: balance_leaf: insert_size must be 0 (%d)",
-                                                                      tb->
-                                                                      insert_size
-                                                                      [0]);
+                                                           "PAP-12285",
+                                                           "insert_size "
+                                                           "must be 0 "
+                                                           "(%d)",
+                                                           tb->insert_size[0]);
                                                }
                                        }
 #endif                         /* CONFIG_REISERFS_CHECK */
@@ -1697,11 +1648,10 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,  /* item h
        if (flag == M_PASTE && tb->insert_size[0]) {
                print_cur_tb("12290");
                reiserfs_panic(tb->tb_sb,
-                              "PAP-12290: balance_leaf: insert_size is still not 0 (%d)",
+                              "PAP-12290", "insert_size is still not 0 (%d)",
                               tb->insert_size[0]);
        }
 #endif                         /* CONFIG_REISERFS_CHECK */
-
        return 0;
 }                              /* Leaf level of the tree is balanced (end of balance_leaf) */
 
@@ -1724,7 +1674,6 @@ void make_empty_node(struct buffer_info *bi)
 struct buffer_head *get_FEB(struct tree_balance *tb)
 {
        int i;
-       struct buffer_head *first_b;
        struct buffer_info bi;
 
        for (i = 0; i < MAX_FEB_SIZE; i++)
@@ -1732,19 +1681,15 @@ struct buffer_head *get_FEB(struct tree_balance *tb)
                        break;
 
        if (i == MAX_FEB_SIZE)
-               reiserfs_panic(tb->tb_sb,
-                              "vs-12300: get_FEB: FEB list is empty");
+               reiserfs_panic(tb->tb_sb, "vs-12300", "FEB list is empty");
 
-       bi.tb = tb;
-       bi.bi_bh = first_b = tb->FEB[i];
-       bi.bi_parent = NULL;
-       bi.bi_position = 0;
+       buffer_info_init_bh(tb, &bi, tb->FEB[i]);
        make_empty_node(&bi);
-       set_buffer_uptodate(first_b);
+       set_buffer_uptodate(tb->FEB[i]);
+       tb->used[i] = tb->FEB[i];
        tb->FEB[i] = NULL;
-       tb->used[i] = first_b;
 
-       return (first_b);
+       return tb->used[i];
 }
 
 /* This is now used because reiserfs_free_block has to be able to
@@ -1755,15 +1700,16 @@ static void store_thrown(struct tree_balance *tb, struct buffer_head *bh)
        int i;
 
        if (buffer_dirty(bh))
-               reiserfs_warning(tb->tb_sb,
-                                "store_thrown deals with dirty buffer");
+               reiserfs_warning(tb->tb_sb, "reiserfs-12320",
+                                "called with dirty buffer");
        for (i = 0; i < ARRAY_SIZE(tb->thrown); i++)
                if (!tb->thrown[i]) {
                        tb->thrown[i] = bh;
                        get_bh(bh);     /* free_thrown puts this */
                        return;
                }
-       reiserfs_warning(tb->tb_sb, "store_thrown: too many thrown buffers");
+       reiserfs_warning(tb->tb_sb, "reiserfs-12321",
+                        "too many thrown buffers");
 }
 
 static void free_thrown(struct tree_balance *tb)
@@ -1774,8 +1720,8 @@ static void free_thrown(struct tree_balance *tb)
                if (tb->thrown[i]) {
                        blocknr = tb->thrown[i]->b_blocknr;
                        if (buffer_dirty(tb->thrown[i]))
-                               reiserfs_warning(tb->tb_sb,
-                                                "free_thrown deals with dirty buffer %d",
+                               reiserfs_warning(tb->tb_sb, "reiserfs-12322",
+                                                "called with dirty buffer %d",
                                                 blocknr);
                        brelse(tb->thrown[i]);  /* incremented in store_thrown */
                        reiserfs_free_block(tb->transaction_handle, NULL,
@@ -1873,20 +1819,19 @@ static void check_internal_node(struct super_block *s, struct buffer_head *bh,
        for (i = 0; i <= B_NR_ITEMS(bh); i++, dc++) {
                if (!is_reusable(s, dc_block_number(dc), 1)) {
                        print_cur_tb(mes);
-                       reiserfs_panic(s,
-                                      "PAP-12338: check_internal_node: invalid child pointer %y in %b",
+                       reiserfs_panic(s, "PAP-12338",
+                                      "invalid child pointer %y in %b",
                                       dc, bh);
                }
        }
 }
 
-static int locked_or_not_in_tree(struct buffer_head *bh, char *which)
+static int locked_or_not_in_tree(struct tree_balance *tb,
+                                 struct buffer_head *bh, char *which)
 {
        if ((!buffer_journal_prepared(bh) && buffer_locked(bh)) ||
            !B_IS_IN_TREE(bh)) {
-               reiserfs_warning(NULL,
-                                "vs-12339: locked_or_not_in_tree: %s (%b)",
-                                which, bh);
+               reiserfs_warning(tb->tb_sb, "vs-12339", "%s (%b)", which, bh);
                return 1;
        }
        return 0;
@@ -1897,26 +1842,28 @@ static int check_before_balancing(struct tree_balance *tb)
        int retval = 0;
 
        if (cur_tb) {
-               reiserfs_panic(tb->tb_sb, "vs-12335: check_before_balancing: "
-                              "suspect that schedule occurred based on cur_tb not being null at this point in code. "
-                              "do_balance cannot properly handle schedule occurring while it runs.");
+               reiserfs_panic(tb->tb_sb, "vs-12335", "suspect that schedule "
+                              "occurred based on cur_tb not being null at "
+                              "this point in code. do_balance cannot properly "
+                              "handle schedule occurring while it runs.");
        }
 
        /* double check that buffers that we will modify are unlocked. (fix_nodes should already have
           prepped all of these for us). */
        if (tb->lnum[0]) {
-               retval |= locked_or_not_in_tree(tb->L[0], "L[0]");
-               retval |= locked_or_not_in_tree(tb->FL[0], "FL[0]");
-               retval |= locked_or_not_in_tree(tb->CFL[0], "CFL[0]");
+               retval |= locked_or_not_in_tree(tb, tb->L[0], "L[0]");
+               retval |= locked_or_not_in_tree(tb, tb->FL[0], "FL[0]");
+               retval |= locked_or_not_in_tree(tb, tb->CFL[0], "CFL[0]");
                check_leaf(tb->L[0]);
        }
        if (tb->rnum[0]) {
-               retval |= locked_or_not_in_tree(tb->R[0], "R[0]");
-               retval |= locked_or_not_in_tree(tb->FR[0], "FR[0]");
-               retval |= locked_or_not_in_tree(tb->CFR[0], "CFR[0]");
+               retval |= locked_or_not_in_tree(tb, tb->R[0], "R[0]");
+               retval |= locked_or_not_in_tree(tb, tb->FR[0], "FR[0]");
+               retval |= locked_or_not_in_tree(tb, tb->CFR[0], "CFR[0]");
                check_leaf(tb->R[0]);
        }
-       retval |= locked_or_not_in_tree(PATH_PLAST_BUFFER(tb->tb_path), "S[0]");
+       retval |= locked_or_not_in_tree(tb, PATH_PLAST_BUFFER(tb->tb_path),
+                                       "S[0]");
        check_leaf(PATH_PLAST_BUFFER(tb->tb_path));
 
        return retval;
@@ -1930,8 +1877,8 @@ static void check_after_balance_leaf(struct tree_balance *tb)
                    dc_size(B_N_CHILD
                            (tb->FL[0], get_left_neighbor_position(tb, 0)))) {
                        print_cur_tb("12221");
-                       reiserfs_panic(tb->tb_sb,
-                                      "PAP-12355: check_after_balance_leaf: shift to left was incorrect");
+                       reiserfs_panic(tb->tb_sb, "PAP-12355",
+                                      "shift to left was incorrect");
                }
        }
        if (tb->rnum[0]) {
@@ -1940,8 +1887,8 @@ static void check_after_balance_leaf(struct tree_balance *tb)
                    dc_size(B_N_CHILD
                            (tb->FR[0], get_right_neighbor_position(tb, 0)))) {
                        print_cur_tb("12222");
-                       reiserfs_panic(tb->tb_sb,
-                                      "PAP-12360: check_after_balance_leaf: shift to right was incorrect");
+                       reiserfs_panic(tb->tb_sb, "PAP-12360",
+                                      "shift to right was incorrect");
                }
        }
        if (PATH_H_PBUFFER(tb->tb_path, 1) &&
@@ -1955,7 +1902,7 @@ static void check_after_balance_leaf(struct tree_balance *tb)
                                               PATH_H_POSITION(tb->tb_path,
                                                               1))));
                print_cur_tb("12223");
-               reiserfs_warning(tb->tb_sb,
+               reiserfs_warning(tb->tb_sb, "reiserfs-12363",
                                 "B_FREE_SPACE (PATH_H_PBUFFER(tb->tb_path,0)) = %d; "
                                 "MAX_CHILD_SIZE (%d) - dc_size( %y, %d ) [%d] = %d",
                                 left,
@@ -1966,8 +1913,7 @@ static void check_after_balance_leaf(struct tree_balance *tb)
                                         (PATH_H_PBUFFER(tb->tb_path, 1),
                                          PATH_H_POSITION(tb->tb_path, 1))),
                                 right);
-               reiserfs_panic(tb->tb_sb,
-                              "PAP-12365: check_after_balance_leaf: S is incorrect");
+               reiserfs_panic(tb->tb_sb, "PAP-12365", "S is incorrect");
        }
 }
 
@@ -2037,7 +1983,7 @@ static inline void do_balance_starts(struct tree_balance *tb)
        /* store_print_tb (tb); */
 
        /* do not delete, just comment it out */
-/*    print_tb(flag, PATH_LAST_POSITION(tb->tb_path), tb->tb_path->pos_in_item, tb, 
+/*    print_tb(flag, PATH_LAST_POSITION(tb->tb_path), tb->tb_path->pos_in_item, tb,
             "check");*/
        RFALSE(check_before_balancing(tb), "PAP-12340: locked buffers in TB");
 #ifdef CONFIG_REISERFS_CHECK
@@ -2102,14 +2048,13 @@ void do_balance(struct tree_balance *tb,        /* tree_balance structure */
        tb->need_balance_dirty = 0;
 
        if (FILESYSTEM_CHANGED_TB(tb)) {
-               reiserfs_panic(tb->tb_sb,
-                              "clm-6000: do_balance, fs generation has changed\n");
+               reiserfs_panic(tb->tb_sb, "clm-6000", "fs generation has "
+                              "changed");
        }
        /* if we have no real work to do  */
        if (!tb->insert_size[0]) {
-               reiserfs_warning(tb->tb_sb,
-                                "PAP-12350: do_balance: insert_size == 0, mode == %c",
-                                flag);
+               reiserfs_warning(tb->tb_sb, "PAP-12350",
+                                "insert_size == 0, mode == %c", flag);
                unfix_nodes(tb);
                return;
        }
index 33408417038c2c93c576534c8d946deaa66ef4e9..9f436668b7f816e6b40bad3759fb7f32268344c6 100644 (file)
 ** insertion/balancing, for files that are written in one write.
 ** It avoids unnecessary tail packings (balances) for files that are written in
 ** multiple writes and are small enough to have tails.
-** 
+**
 ** file_release is called by the VFS layer when the file is closed.  If
 ** this is the last open file descriptor, and the file
 ** small enough to have a tail, and the tail is currently in an
 ** unformatted node, the tail is converted back into a direct item.
-** 
+**
 ** We use reiserfs_truncate_file to pack the tail, since it already has
-** all the conditions coded.  
+** all the conditions coded.
 */
 static int reiserfs_file_release(struct inode *inode, struct file *filp)
 {
@@ -76,7 +76,7 @@ static int reiserfs_file_release(struct inode *inode, struct file *filp)
                         * and let the admin know what is going on.
                         */
                        igrab(inode);
-                       reiserfs_warning(inode->i_sb,
+                       reiserfs_warning(inode->i_sb, "clm-9001",
                                         "pinning inode %lu because the "
                                         "preallocation can't be freed",
                                         inode->i_ino);
@@ -134,23 +134,23 @@ static void reiserfs_vfs_truncate_file(struct inode *inode)
  * be removed...
  */
 
-static int reiserfs_sync_file(struct file *p_s_filp,
-                             struct dentry *p_s_dentry, int datasync)
+static int reiserfs_sync_file(struct file *filp,
+                             struct dentry *dentry, int datasync)
 {
-       struct inode *p_s_inode = p_s_dentry->d_inode;
-       int n_err;
+       struct inode *inode = dentry->d_inode;
+       int err;
        int barrier_done;
 
-       BUG_ON(!S_ISREG(p_s_inode->i_mode));
-       n_err = sync_mapping_buffers(p_s_inode->i_mapping);
-       reiserfs_write_lock(p_s_inode->i_sb);
-       barrier_done = reiserfs_commit_for_inode(p_s_inode);
-       reiserfs_write_unlock(p_s_inode->i_sb);
-       if (barrier_done != 1 && reiserfs_barrier_flush(p_s_inode->i_sb))
-               blkdev_issue_flush(p_s_inode->i_sb->s_bdev, NULL);
+       BUG_ON(!S_ISREG(inode->i_mode));
+       err = sync_mapping_buffers(inode->i_mapping);
+       reiserfs_write_lock(inode->i_sb);
+       barrier_done = reiserfs_commit_for_inode(inode);
+       reiserfs_write_unlock(inode->i_sb);
+       if (barrier_done != 1 && reiserfs_barrier_flush(inode->i_sb))
+               blkdev_issue_flush(inode->i_sb->s_bdev, NULL);
        if (barrier_done < 0)
                return barrier_done;
-       return (n_err < 0) ? -EIO : 0;
+       return (err < 0) ? -EIO : 0;
 }
 
 /* taken fs/buffer.c:__block_commit_write */
@@ -223,7 +223,7 @@ int reiserfs_commit_page(struct inode *inode, struct page *page,
 }
 
 /* Write @count bytes at position @ppos in a file indicated by @file
-   from the buffer @buf.  
+   from the buffer @buf.
 
    generic_file_write() is only appropriate for filesystems that are not seeking to optimize performance and want
    something simple that works.  It is not for serious use by general purpose filesystems, excepting the one that it was
index 07d05e0842b72525b32eabac59dda28e7e3cc26a..5e5a4e6fbaf8290d2bf91799d7e116390256ccf0 100644 (file)
@@ -30,8 +30,8 @@
  ** get_direct_parent
  ** get_neighbors
  ** fix_nodes
- ** 
- ** 
+ **
+ **
  **/
 
 #include <linux/time.h>
@@ -135,8 +135,7 @@ static void create_virtual_node(struct tree_balance *tb, int h)
                vn->vn_free_ptr +=
                    op_create_vi(vn, vi, is_affected, tb->insert_size[0]);
                if (tb->vn_buf + tb->vn_buf_size < vn->vn_free_ptr)
-                       reiserfs_panic(tb->tb_sb,
-                                      "vs-8030: create_virtual_node: "
+                       reiserfs_panic(tb->tb_sb, "vs-8030",
                                       "virtual node space consumed");
 
                if (!is_affected)
@@ -186,8 +185,9 @@ static void create_virtual_node(struct tree_balance *tb, int h)
                             && I_ENTRY_COUNT(B_N_PITEM_HEAD(Sh, 0)) == 1)) {
                                /* node contains more than 1 item, or item is not directory item, or this item contains more than 1 entry */
                                print_block(Sh, 0, -1, -1);
-                               reiserfs_panic(tb->tb_sb,
-                                              "vs-8045: create_virtual_node: rdkey %k, affected item==%d (mode==%c) Must be %c",
+                               reiserfs_panic(tb->tb_sb, "vs-8045",
+                                              "rdkey %k, affected item==%d "
+                                              "(mode==%c) Must be %c",
                                               key, vn->vn_affected_item_num,
                                               vn->vn_mode, M_DELETE);
                        }
@@ -377,9 +377,9 @@ static int get_num_ver(int mode, struct tree_balance *tb, int h,
        int needed_nodes;
        int start_item,         /* position of item we start filling node from */
         end_item,              /* position of item we finish filling node by */
-        start_bytes,           /* number of first bytes (entries for directory) of start_item-th item 
+        start_bytes,           /* number of first bytes (entries for directory) of start_item-th item
                                   we do not include into node that is being filled */
-        end_bytes;             /* number of last bytes (entries for directory) of end_item-th item 
+        end_bytes;             /* number of last bytes (entries for directory) of end_item-th item
                                   we do node include into node that is being filled */
        int split_item_positions[2];    /* these are positions in virtual item of
                                           items, that are split between S[0] and
@@ -496,8 +496,8 @@ static int get_num_ver(int mode, struct tree_balance *tb, int h,
                snum012[needed_nodes - 1 + 3] = units;
 
                if (needed_nodes > 2)
-                       reiserfs_warning(tb->tb_sb, "vs-8111: get_num_ver: "
-                                        "split_item_position is out of boundary");
+                       reiserfs_warning(tb->tb_sb, "vs-8111",
+                                        "split_item_position is out of range");
                snum012[needed_nodes - 1]++;
                split_item_positions[needed_nodes - 1] = i;
                needed_nodes++;
@@ -533,8 +533,8 @@ static int get_num_ver(int mode, struct tree_balance *tb, int h,
 
                if (vn->vn_vi[split_item_num].vi_index != TYPE_DIRENTRY &&
                    vn->vn_vi[split_item_num].vi_index != TYPE_INDIRECT)
-                       reiserfs_warning(tb->tb_sb, "vs-8115: get_num_ver: not "
-                                        "directory or indirect item");
+                       reiserfs_warning(tb->tb_sb, "vs-8115",
+                                        "not directory or indirect item");
        }
 
        /* now we know S2bytes, calculate S1bytes */
@@ -569,7 +569,7 @@ extern struct tree_balance *cur_tb;
 
 /* Set parameters for balancing.
  * Performs write of results of analysis of balancing into structure tb,
- * where it will later be used by the functions that actually do the balancing. 
+ * where it will later be used by the functions that actually do the balancing.
  * Parameters:
  *     tb      tree_balance structure;
  *     h       current level of the node;
@@ -749,25 +749,26 @@ else \
                  -1, -1);\
 }
 
-static void free_buffers_in_tb(struct tree_balance *p_s_tb)
+static void free_buffers_in_tb(struct tree_balance *tb)
 {
-       int n_counter;
-
-       decrement_counters_in_path(p_s_tb->tb_path);
-
-       for (n_counter = 0; n_counter < MAX_HEIGHT; n_counter++) {
-               decrement_bcount(p_s_tb->L[n_counter]);
-               p_s_tb->L[n_counter] = NULL;
-               decrement_bcount(p_s_tb->R[n_counter]);
-               p_s_tb->R[n_counter] = NULL;
-               decrement_bcount(p_s_tb->FL[n_counter]);
-               p_s_tb->FL[n_counter] = NULL;
-               decrement_bcount(p_s_tb->FR[n_counter]);
-               p_s_tb->FR[n_counter] = NULL;
-               decrement_bcount(p_s_tb->CFL[n_counter]);
-               p_s_tb->CFL[n_counter] = NULL;
-               decrement_bcount(p_s_tb->CFR[n_counter]);
-               p_s_tb->CFR[n_counter] = NULL;
+       int i;
+
+       pathrelse(tb->tb_path);
+
+       for (i = 0; i < MAX_HEIGHT; i++) {
+               brelse(tb->L[i]);
+               brelse(tb->R[i]);
+               brelse(tb->FL[i]);
+               brelse(tb->FR[i]);
+               brelse(tb->CFL[i]);
+               brelse(tb->CFR[i]);
+
+               tb->L[i] = NULL;
+               tb->R[i] = NULL;
+               tb->FL[i] = NULL;
+               tb->FR[i] = NULL;
+               tb->CFL[i] = NULL;
+               tb->CFR[i] = NULL;
        }
 }
 
@@ -777,14 +778,14 @@ static void free_buffers_in_tb(struct tree_balance *p_s_tb)
  *             NO_DISK_SPACE - no disk space.
  */
 /* The function is NOT SCHEDULE-SAFE! */
-static int get_empty_nodes(struct tree_balance *p_s_tb, int n_h)
+static int get_empty_nodes(struct tree_balance *tb, int h)
 {
-       struct buffer_head *p_s_new_bh,
-           *p_s_Sh = PATH_H_PBUFFER(p_s_tb->tb_path, n_h);
-       b_blocknr_t *p_n_blocknr, a_n_blocknrs[MAX_AMOUNT_NEEDED] = { 0, };
-       int n_counter, n_number_of_freeblk, n_amount_needed,    /* number of needed empty blocks */
-        n_retval = CARRY_ON;
-       struct super_block *p_s_sb = p_s_tb->tb_sb;
+       struct buffer_head *new_bh,
+           *Sh = PATH_H_PBUFFER(tb->tb_path, h);
+       b_blocknr_t *blocknr, blocknrs[MAX_AMOUNT_NEEDED] = { 0, };
+       int counter, number_of_freeblk, amount_needed,  /* number of needed empty blocks */
+        retval = CARRY_ON;
+       struct super_block *sb = tb->tb_sb;
 
        /* number_of_freeblk is the number of empty blocks which have been
           acquired for use by the balancing algorithm minus the number of
@@ -792,7 +793,7 @@ static int get_empty_nodes(struct tree_balance *p_s_tb, int n_h)
           number_of_freeblk = tb->cur_blknum can be non-zero if a schedule occurs
           after empty blocks are acquired, and the balancing analysis is
           then restarted, amount_needed is the number needed by this level
-          (n_h) of the balancing analysis.
+          (h) of the balancing analysis.
 
           Note that for systems with many processes writing, it would be
           more layout optimal to calculate the total number needed by all
@@ -800,54 +801,54 @@ static int get_empty_nodes(struct tree_balance *p_s_tb, int n_h)
 
        /* Initiate number_of_freeblk to the amount acquired prior to the restart of
           the analysis or 0 if not restarted, then subtract the amount needed
-          by all of the levels of the tree below n_h. */
-       /* blknum includes S[n_h], so we subtract 1 in this calculation */
-       for (n_counter = 0, n_number_of_freeblk = p_s_tb->cur_blknum;
-            n_counter < n_h; n_counter++)
-               n_number_of_freeblk -=
-                   (p_s_tb->blknum[n_counter]) ? (p_s_tb->blknum[n_counter] -
+          by all of the levels of the tree below h. */
+       /* blknum includes S[h], so we subtract 1 in this calculation */
+       for (counter = 0, number_of_freeblk = tb->cur_blknum;
+            counter < h; counter++)
+               number_of_freeblk -=
+                   (tb->blknum[counter]) ? (tb->blknum[counter] -
                                                   1) : 0;
 
        /* Allocate missing empty blocks. */
-       /* if p_s_Sh == 0  then we are getting a new root */
-       n_amount_needed = (p_s_Sh) ? (p_s_tb->blknum[n_h] - 1) : 1;
+       /* if Sh == 0  then we are getting a new root */
+       amount_needed = (Sh) ? (tb->blknum[h] - 1) : 1;
        /*  Amount_needed = the amount that we need more than the amount that we have. */
-       if (n_amount_needed > n_number_of_freeblk)
-               n_amount_needed -= n_number_of_freeblk;
+       if (amount_needed > number_of_freeblk)
+               amount_needed -= number_of_freeblk;
        else                    /* If we have enough already then there is nothing to do. */
                return CARRY_ON;
 
        /* No need to check quota - is not allocated for blocks used for formatted nodes */
-       if (reiserfs_new_form_blocknrs(p_s_tb, a_n_blocknrs,
-                                      n_amount_needed) == NO_DISK_SPACE)
+       if (reiserfs_new_form_blocknrs(tb, blocknrs,
+                                      amount_needed) == NO_DISK_SPACE)
                return NO_DISK_SPACE;
 
        /* for each blocknumber we just got, get a buffer and stick it on FEB */
-       for (p_n_blocknr = a_n_blocknrs, n_counter = 0;
-            n_counter < n_amount_needed; p_n_blocknr++, n_counter++) {
+       for (blocknr = blocknrs, counter = 0;
+            counter < amount_needed; blocknr++, counter++) {
 
-               RFALSE(!*p_n_blocknr,
+               RFALSE(!*blocknr,
                       "PAP-8135: reiserfs_new_blocknrs failed when got new blocks");
 
-               p_s_new_bh = sb_getblk(p_s_sb, *p_n_blocknr);
-               RFALSE(buffer_dirty(p_s_new_bh) ||
-                      buffer_journaled(p_s_new_bh) ||
-                      buffer_journal_dirty(p_s_new_bh),
+               new_bh = sb_getblk(sb, *blocknr);
+               RFALSE(buffer_dirty(new_bh) ||
+                      buffer_journaled(new_bh) ||
+                      buffer_journal_dirty(new_bh),
                       "PAP-8140: journlaled or dirty buffer %b for the new block",
-                      p_s_new_bh);
+                      new_bh);
 
                /* Put empty buffers into the array. */
-               RFALSE(p_s_tb->FEB[p_s_tb->cur_blknum],
+               RFALSE(tb->FEB[tb->cur_blknum],
                       "PAP-8141: busy slot for new buffer");
 
-               set_buffer_journal_new(p_s_new_bh);
-               p_s_tb->FEB[p_s_tb->cur_blknum++] = p_s_new_bh;
+               set_buffer_journal_new(new_bh);
+               tb->FEB[tb->cur_blknum++] = new_bh;
        }
 
-       if (n_retval == CARRY_ON && FILESYSTEM_CHANGED_TB(p_s_tb))
-               n_retval = REPEAT_SEARCH;
+       if (retval == CARRY_ON && FILESYSTEM_CHANGED_TB(tb))
+               retval = REPEAT_SEARCH;
 
-       return n_retval;
+       return retval;
 }
 
 /* Get free space of the left neighbor, which is stored in the parent
@@ -895,35 +896,36 @@ static int get_rfree(struct tree_balance *tb, int h)
 }
 
 /* Check whether left neighbor is in memory. */
-static int is_left_neighbor_in_cache(struct tree_balance *p_s_tb, int n_h)
+static int is_left_neighbor_in_cache(struct tree_balance *tb, int h)
 {
-       struct buffer_head *p_s_father, *left;
-       struct super_block *p_s_sb = p_s_tb->tb_sb;
-       b_blocknr_t n_left_neighbor_blocknr;
-       int n_left_neighbor_position;
+       struct buffer_head *father, *left;
+       struct super_block *sb = tb->tb_sb;
+       b_blocknr_t left_neighbor_blocknr;
+       int left_neighbor_position;
 
-       if (!p_s_tb->FL[n_h])   /* Father of the left neighbor does not exist. */
+       /* Father of the left neighbor does not exist. */
+       if (!tb->FL[h])
                return 0;
 
        /* Calculate father of the node to be balanced. */
-       p_s_father = PATH_H_PBUFFER(p_s_tb->tb_path, n_h + 1);
+       father = PATH_H_PBUFFER(tb->tb_path, h + 1);
 
-       RFALSE(!p_s_father ||
-              !B_IS_IN_TREE(p_s_father) ||
-              !B_IS_IN_TREE(p_s_tb->FL[n_h]) ||
-              !buffer_uptodate(p_s_father) ||
-              !buffer_uptodate(p_s_tb->FL[n_h]),
+       RFALSE(!father ||
+              !B_IS_IN_TREE(father) ||
+              !B_IS_IN_TREE(tb->FL[h]) ||
+              !buffer_uptodate(father) ||
+              !buffer_uptodate(tb->FL[h]),
               "vs-8165: F[h] (%b) or FL[h] (%b) is invalid",
-              p_s_father, p_s_tb->FL[n_h]);
+              father, tb->FL[h]);
 
        /* Get position of the pointer to the left neighbor into the left father. */
-       n_left_neighbor_position = (p_s_father == p_s_tb->FL[n_h]) ?
-           p_s_tb->lkey[n_h] : B_NR_ITEMS(p_s_tb->FL[n_h]);
+       left_neighbor_position = (father == tb->FL[h]) ?
+           tb->lkey[h] : B_NR_ITEMS(tb->FL[h]);
        /* Get left neighbor block number. */
-       n_left_neighbor_blocknr =
-           B_N_CHILD_NUM(p_s_tb->FL[n_h], n_left_neighbor_position);
+       left_neighbor_blocknr =
+           B_N_CHILD_NUM(tb->FL[h], left_neighbor_position);
        /* Look for the left neighbor in the cache. */
-       if ((left = sb_find_get_block(p_s_sb, n_left_neighbor_blocknr))) {
+       if ((left = sb_find_get_block(sb, left_neighbor_blocknr))) {
 
                RFALSE(buffer_uptodate(left) && !B_IS_IN_TREE(left),
                       "vs-8170: left neighbor (%b %z) is not in the tree",
@@ -938,10 +940,10 @@ static int is_left_neighbor_in_cache(struct tree_balance *p_s_tb, int n_h)
 #define LEFT_PARENTS  'l'
 #define RIGHT_PARENTS 'r'
 
-static void decrement_key(struct cpu_key *p_s_key)
+static void decrement_key(struct cpu_key *key)
 {
        // call item specific function for this key
-       item_ops[cpu_key_k_type(p_s_key)]->decrement_key(p_s_key);
+       item_ops[cpu_key_k_type(key)]->decrement_key(key);
 }
 
 /* Calculate far left/right parent of the left/right neighbor of the current node, that
@@ -952,77 +954,77 @@ static void decrement_key(struct cpu_key *p_s_key)
                SCHEDULE_OCCURRED - schedule occurred while the function worked;
  *             CARRY_ON         - schedule didn't occur while the function worked;
  */
-static int get_far_parent(struct tree_balance *p_s_tb,
-                         int n_h,
-                         struct buffer_head **pp_s_father,
-                         struct buffer_head **pp_s_com_father, char c_lr_par)
+static int get_far_parent(struct tree_balance *tb,
+                         int h,
+                         struct buffer_head **pfather,
+                         struct buffer_head **pcom_father, char c_lr_par)
 {
-       struct buffer_head *p_s_parent;
+       struct buffer_head *parent;
        INITIALIZE_PATH(s_path_to_neighbor_father);
-       struct treepath *p_s_path = p_s_tb->tb_path;
+       struct treepath *path = tb->tb_path;
        struct cpu_key s_lr_father_key;
-       int n_counter,
-           n_position = INT_MAX,
-           n_first_last_position = 0,
-           n_path_offset = PATH_H_PATH_OFFSET(p_s_path, n_h);
+       int counter,
+           position = INT_MAX,
+           first_last_position = 0,
+           path_offset = PATH_H_PATH_OFFSET(path, h);
 
-       /* Starting from F[n_h] go upwards in the tree, and look for the common
-          ancestor of F[n_h], and its neighbor l/r, that should be obtained. */
+       /* Starting from F[h] go upwards in the tree, and look for the common
+          ancestor of F[h], and its neighbor l/r, that should be obtained. */
 
-       n_counter = n_path_offset;
+       counter = path_offset;
 
-       RFALSE(n_counter < FIRST_PATH_ELEMENT_OFFSET,
+       RFALSE(counter < FIRST_PATH_ELEMENT_OFFSET,
               "PAP-8180: invalid path length");
 
-       for (; n_counter > FIRST_PATH_ELEMENT_OFFSET; n_counter--) {
+       for (; counter > FIRST_PATH_ELEMENT_OFFSET; counter--) {
                /* Check whether parent of the current buffer in the path is really parent in the tree. */
                if (!B_IS_IN_TREE
-                   (p_s_parent = PATH_OFFSET_PBUFFER(p_s_path, n_counter - 1)))
+                   (parent = PATH_OFFSET_PBUFFER(path, counter - 1)))
                        return REPEAT_SEARCH;
                /* Check whether position in the parent is correct. */
-               if ((n_position =
-                    PATH_OFFSET_POSITION(p_s_path,
-                                         n_counter - 1)) >
-                   B_NR_ITEMS(p_s_parent))
+               if ((position =
+                    PATH_OFFSET_POSITION(path,
+                                         counter - 1)) >
+                   B_NR_ITEMS(parent))
                        return REPEAT_SEARCH;
                /* Check whether parent at the path really points to the child. */
-               if (B_N_CHILD_NUM(p_s_parent, n_position) !=
-                   PATH_OFFSET_PBUFFER(p_s_path, n_counter)->b_blocknr)
+               if (B_N_CHILD_NUM(parent, position) !=
+                   PATH_OFFSET_PBUFFER(path, counter)->b_blocknr)
                        return REPEAT_SEARCH;
                /* Return delimiting key if position in the parent is not equal to first/last one. */
                if (c_lr_par == RIGHT_PARENTS)
-                       n_first_last_position = B_NR_ITEMS(p_s_parent);
-               if (n_position != n_first_last_position) {
-                       *pp_s_com_father = p_s_parent;
-                       get_bh(*pp_s_com_father);
-                       /*(*pp_s_com_father = p_s_parent)->b_count++; */
+                       first_last_position = B_NR_ITEMS(parent);
+               if (position != first_last_position) {
+                       *pcom_father = parent;
+                       get_bh(*pcom_father);
+                       /*(*pcom_father = parent)->b_count++; */
                        break;
                }
        }
 
        /* if we are in the root of the tree, then there is no common father */
-       if (n_counter == FIRST_PATH_ELEMENT_OFFSET) {
+       if (counter == FIRST_PATH_ELEMENT_OFFSET) {
                /* Check whether first buffer in the path is the root of the tree. */
                if (PATH_OFFSET_PBUFFER
-                   (p_s_tb->tb_path,
+                   (tb->tb_path,
                     FIRST_PATH_ELEMENT_OFFSET)->b_blocknr ==
-                   SB_ROOT_BLOCK(p_s_tb->tb_sb)) {
-                       *pp_s_father = *pp_s_com_father = NULL;
+                   SB_ROOT_BLOCK(tb->tb_sb)) {
+                       *pfather = *pcom_father = NULL;
                        return CARRY_ON;
                }
                return REPEAT_SEARCH;
        }
 
-       RFALSE(B_LEVEL(*pp_s_com_father) <= DISK_LEAF_NODE_LEVEL,
+       RFALSE(B_LEVEL(*pcom_father) <= DISK_LEAF_NODE_LEVEL,
               "PAP-8185: (%b %z) level too small",
-              *pp_s_com_father, *pp_s_com_father);
+              *pcom_father, *pcom_father);
 
        /* Check whether the common parent is locked. */
 
-       if (buffer_locked(*pp_s_com_father)) {
-               __wait_on_buffer(*pp_s_com_father);
-               if (FILESYSTEM_CHANGED_TB(p_s_tb)) {
-                       decrement_bcount(*pp_s_com_father);
+       if (buffer_locked(*pcom_father)) {
+               __wait_on_buffer(*pcom_father);
+               if (FILESYSTEM_CHANGED_TB(tb)) {
+                       brelse(*pcom_father);
                        return REPEAT_SEARCH;
                }
        }
@@ -1032,128 +1034,131 @@ static int get_far_parent(struct tree_balance *p_s_tb,
 
        /* Form key to get parent of the left/right neighbor. */
        le_key2cpu_key(&s_lr_father_key,
-                      B_N_PDELIM_KEY(*pp_s_com_father,
+                      B_N_PDELIM_KEY(*pcom_father,
                                      (c_lr_par ==
-                                      LEFT_PARENTS) ? (p_s_tb->lkey[n_h - 1] =
-                                                       n_position -
-                                                       1) : (p_s_tb->rkey[n_h -
+                                      LEFT_PARENTS) ? (tb->lkey[h - 1] =
+                                                       position -
+                                                       1) : (tb->rkey[h -
                                                                           1] =
-                                                             n_position)));
+                                                             position)));
 
        if (c_lr_par == LEFT_PARENTS)
                decrement_key(&s_lr_father_key);
 
        if (search_by_key
-           (p_s_tb->tb_sb, &s_lr_father_key, &s_path_to_neighbor_father,
-            n_h + 1) == IO_ERROR)
+           (tb->tb_sb, &s_lr_father_key, &s_path_to_neighbor_father,
+            h + 1) == IO_ERROR)
                // path is released
                return IO_ERROR;
 
-       if (FILESYSTEM_CHANGED_TB(p_s_tb)) {
-               decrement_counters_in_path(&s_path_to_neighbor_father);
-               decrement_bcount(*pp_s_com_father);
+       if (FILESYSTEM_CHANGED_TB(tb)) {
+               pathrelse(&s_path_to_neighbor_father);
+               brelse(*pcom_father);
                return REPEAT_SEARCH;
        }
 
-       *pp_s_father = PATH_PLAST_BUFFER(&s_path_to_neighbor_father);
+       *pfather = PATH_PLAST_BUFFER(&s_path_to_neighbor_father);
 
-       RFALSE(B_LEVEL(*pp_s_father) != n_h + 1,
-              "PAP-8190: (%b %z) level too small", *pp_s_father, *pp_s_father);
+       RFALSE(B_LEVEL(*pfather) != h + 1,
+              "PAP-8190: (%b %z) level too small", *pfather, *pfather);
        RFALSE(s_path_to_neighbor_father.path_length <
               FIRST_PATH_ELEMENT_OFFSET, "PAP-8192: path length is too small");
 
        s_path_to_neighbor_father.path_length--;
-       decrement_counters_in_path(&s_path_to_neighbor_father);
+       pathrelse(&s_path_to_neighbor_father);
        return CARRY_ON;
 }
 
-/* Get parents of neighbors of node in the path(S[n_path_offset]) and common parents of
- * S[n_path_offset] and L[n_path_offset]/R[n_path_offset]: F[n_path_offset], FL[n_path_offset],
- * FR[n_path_offset], CFL[n_path_offset], CFR[n_path_offset].
- * Calculate numbers of left and right delimiting keys position: lkey[n_path_offset], rkey[n_path_offset].
+/* Get parents of neighbors of node in the path(S[path_offset]) and common parents of
+ * S[path_offset] and L[path_offset]/R[path_offset]: F[path_offset], FL[path_offset],
+ * FR[path_offset], CFL[path_offset], CFR[path_offset].
+ * Calculate numbers of left and right delimiting keys position: lkey[path_offset], rkey[path_offset].
  * Returns:    SCHEDULE_OCCURRED - schedule occurred while the function worked;
  *             CARRY_ON - schedule didn't occur while the function worked;
  */
-static int get_parents(struct tree_balance *p_s_tb, int n_h)
+static int get_parents(struct tree_balance *tb, int h)
 {
-       struct treepath *p_s_path = p_s_tb->tb_path;
-       int n_position,
-           n_ret_value,
-           n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h);
-       struct buffer_head *p_s_curf, *p_s_curcf;
+       struct treepath *path = tb->tb_path;
+       int position,
+           ret,
+           path_offset = PATH_H_PATH_OFFSET(tb->tb_path, h);
+       struct buffer_head *curf, *curcf;
 
        /* Current node is the root of the tree or will be root of the tree */
-       if (n_path_offset <= FIRST_PATH_ELEMENT_OFFSET) {
+       if (path_offset <= FIRST_PATH_ELEMENT_OFFSET) {
                /* The root can not have parents.
                   Release nodes which previously were obtained as parents of the current node neighbors. */
-               decrement_bcount(p_s_tb->FL[n_h]);
-               decrement_bcount(p_s_tb->CFL[n_h]);
-               decrement_bcount(p_s_tb->FR[n_h]);
-               decrement_bcount(p_s_tb->CFR[n_h]);
-               p_s_tb->FL[n_h] = p_s_tb->CFL[n_h] = p_s_tb->FR[n_h] =
-                   p_s_tb->CFR[n_h] = NULL;
+               brelse(tb->FL[h]);
+               brelse(tb->CFL[h]);
+               brelse(tb->FR[h]);
+               brelse(tb->CFR[h]);
+               tb->FL[h]  = NULL;
+               tb->CFL[h] = NULL;
+               tb->FR[h]  = NULL;
+               tb->CFR[h] = NULL;
                return CARRY_ON;
        }
 
-       /* Get parent FL[n_path_offset] of L[n_path_offset]. */
-       if ((n_position = PATH_OFFSET_POSITION(p_s_path, n_path_offset - 1))) {
+       /* Get parent FL[path_offset] of L[path_offset]. */
+       position = PATH_OFFSET_POSITION(path, path_offset - 1);
+       if (position) {
                /* Current node is not the first child of its parent. */
-               /*(p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1))->b_count += 2; */
-               p_s_curf = p_s_curcf =
-                   PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1);
-               get_bh(p_s_curf);
-               get_bh(p_s_curf);
-               p_s_tb->lkey[n_h] = n_position - 1;
+               curf = PATH_OFFSET_PBUFFER(path, path_offset - 1);
+               curcf = PATH_OFFSET_PBUFFER(path, path_offset - 1);
+               get_bh(curf);
+               get_bh(curf);
+               tb->lkey[h] = position - 1;
        } else {
-               /* Calculate current parent of L[n_path_offset], which is the left neighbor of the current node.
-                  Calculate current common parent of L[n_path_offset] and the current node. Note that
-                  CFL[n_path_offset] not equal FL[n_path_offset] and CFL[n_path_offset] not equal F[n_path_offset].
-                  Calculate lkey[n_path_offset]. */
-               if ((n_ret_value = get_far_parent(p_s_tb, n_h + 1, &p_s_curf,
-                                                 &p_s_curcf,
+               /* Calculate current parent of L[path_offset], which is the left neighbor of the current node.
+                  Calculate current common parent of L[path_offset] and the current node. Note that
+                  CFL[path_offset] not equal FL[path_offset] and CFL[path_offset] not equal F[path_offset].
+                  Calculate lkey[path_offset]. */
+               if ((ret = get_far_parent(tb, h + 1, &curf,
+                                                 &curcf,
                                                  LEFT_PARENTS)) != CARRY_ON)
-                       return n_ret_value;
+                       return ret;
        }
 
-       decrement_bcount(p_s_tb->FL[n_h]);
-       p_s_tb->FL[n_h] = p_s_curf;     /* New initialization of FL[n_h]. */
-       decrement_bcount(p_s_tb->CFL[n_h]);
-       p_s_tb->CFL[n_h] = p_s_curcf;   /* New initialization of CFL[n_h]. */
+       brelse(tb->FL[h]);
+       tb->FL[h] = curf;       /* New initialization of FL[h]. */
+       brelse(tb->CFL[h]);
+       tb->CFL[h] = curcf;     /* New initialization of CFL[h]. */
 
-       RFALSE((p_s_curf && !B_IS_IN_TREE(p_s_curf)) ||
-              (p_s_curcf && !B_IS_IN_TREE(p_s_curcf)),
-              "PAP-8195: FL (%b) or CFL (%b) is invalid", p_s_curf, p_s_curcf);
+       RFALSE((curf && !B_IS_IN_TREE(curf)) ||
+              (curcf && !B_IS_IN_TREE(curcf)),
+              "PAP-8195: FL (%b) or CFL (%b) is invalid", curf, curcf);
 
-/* Get parent FR[n_h] of R[n_h]. */
+/* Get parent FR[h] of R[h]. */
 
-/* Current node is the last child of F[n_h]. FR[n_h] != F[n_h]. */
-       if (n_position == B_NR_ITEMS(PATH_H_PBUFFER(p_s_path, n_h + 1))) {
-/* Calculate current parent of R[n_h], which is the right neighbor of F[n_h].
-   Calculate current common parent of R[n_h] and current node. Note that CFR[n_h]
-   not equal FR[n_path_offset] and CFR[n_h] not equal F[n_h]. */
-               if ((n_ret_value =
-                    get_far_parent(p_s_tb, n_h + 1, &p_s_curf, &p_s_curcf,
+/* Current node is the last child of F[h]. FR[h] != F[h]. */
+       if (position == B_NR_ITEMS(PATH_H_PBUFFER(path, h + 1))) {
+/* Calculate current parent of R[h], which is the right neighbor of F[h].
+   Calculate current common parent of R[h] and current node. Note that CFR[h]
+   not equal FR[path_offset] and CFR[h] not equal F[h]. */
+               if ((ret =
+                    get_far_parent(tb, h + 1, &curf, &curcf,
                                    RIGHT_PARENTS)) != CARRY_ON)
-                       return n_ret_value;
+                       return ret;
        } else {
-/* Current node is not the last child of its parent F[n_h]. */
-               /*(p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1))->b_count += 2; */
-               p_s_curf = p_s_curcf =
-                   PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1);
-               get_bh(p_s_curf);
-               get_bh(p_s_curf);
-               p_s_tb->rkey[n_h] = n_position;
+/* Current node is not the last child of its parent F[h]. */
+               curf = PATH_OFFSET_PBUFFER(path, path_offset - 1);
+               curcf = PATH_OFFSET_PBUFFER(path, path_offset - 1);
+               get_bh(curf);
+               get_bh(curf);
+               tb->rkey[h] = position;
        }
 
-       decrement_bcount(p_s_tb->FR[n_h]);
-       p_s_tb->FR[n_h] = p_s_curf;     /* New initialization of FR[n_path_offset]. */
+       brelse(tb->FR[h]);
+       /* New initialization of FR[path_offset]. */
+       tb->FR[h] = curf;
 
-       decrement_bcount(p_s_tb->CFR[n_h]);
-       p_s_tb->CFR[n_h] = p_s_curcf;   /* New initialization of CFR[n_path_offset]. */
+       brelse(tb->CFR[h]);
+       /* New initialization of CFR[path_offset]. */
+       tb->CFR[h] = curcf;
 
-       RFALSE((p_s_curf && !B_IS_IN_TREE(p_s_curf)) ||
-              (p_s_curcf && !B_IS_IN_TREE(p_s_curcf)),
-              "PAP-8205: FR (%b) or CFR (%b) is invalid", p_s_curf, p_s_curcf);
+       RFALSE((curf && !B_IS_IN_TREE(curf)) ||
+              (curcf && !B_IS_IN_TREE(curcf)),
+              "PAP-8205: FR (%b) or CFR (%b) is invalid", curf, curcf);
 
        return CARRY_ON;
 }
@@ -1203,7 +1208,7 @@ static inline int can_node_be_removed(int mode, int lfree, int sfree, int rfree,
  *     h       current level of the node;
  *     inum    item number in S[h];
  *     mode    i - insert, p - paste;
- * Returns:    1 - schedule occurred; 
+ * Returns:    1 - schedule occurred;
  *             0 - balancing for higher levels needed;
  *            -1 - no balancing for higher levels needed;
  *            -2 - no disk space.
@@ -1217,7 +1222,7 @@ static int ip_check_balance(struct tree_balance *tb, int h)
                                   contains node being balanced.  The mnemonic is
                                   that the attempted change in node space used level
                                   is levbytes bytes. */
-        n_ret_value;
+        ret;
 
        int lfree, sfree, rfree /* free space in L, S and R */ ;
 
@@ -1238,7 +1243,7 @@ static int ip_check_balance(struct tree_balance *tb, int h)
        /* we perform 8 calls to get_num_ver().  For each call we calculate five parameters.
           where 4th parameter is s1bytes and 5th - s2bytes
         */
-       short snum012[40] = { 0, };     /* s0num, s1num, s2num for 8 cases 
+       short snum012[40] = { 0, };     /* s0num, s1num, s2num for 8 cases
                                           0,1 - do not shift and do not shift but bottle
                                           2 - shift only whole item to left
                                           3 - shift to left and bottle as much as possible
@@ -1255,24 +1260,24 @@ static int ip_check_balance(struct tree_balance *tb, int h)
        /* Calculate balance parameters for creating new root. */
        if (!Sh) {
                if (!h)
-                       reiserfs_panic(tb->tb_sb,
-                                      "vs-8210: ip_check_balance: S[0] can not be 0");
-               switch (n_ret_value = get_empty_nodes(tb, h)) {
+                       reiserfs_panic(tb->tb_sb, "vs-8210",
+                                      "S[0] can not be 0");
+               switch (ret = get_empty_nodes(tb, h)) {
                case CARRY_ON:
                        set_parameters(tb, h, 0, 0, 1, NULL, -1, -1);
                        return NO_BALANCING_NEEDED;     /* no balancing for higher levels needed */
 
                case NO_DISK_SPACE:
                case REPEAT_SEARCH:
-                       return n_ret_value;
+                       return ret;
                default:
-                       reiserfs_panic(tb->tb_sb,
-                                      "vs-8215: ip_check_balance: incorrect return value of get_empty_nodes");
+                       reiserfs_panic(tb->tb_sb, "vs-8215", "incorrect "
+                                      "return value of get_empty_nodes");
                }
        }
 
-       if ((n_ret_value = get_parents(tb, h)) != CARRY_ON)     /* get parents of S[h] neighbors. */
-               return n_ret_value;
+       if ((ret = get_parents(tb, h)) != CARRY_ON)     /* get parents of S[h] neighbors. */
+               return ret;
 
        sfree = B_FREE_SPACE(Sh);
 
@@ -1287,7 +1292,7 @@ static int ip_check_balance(struct tree_balance *tb, int h)
 
        create_virtual_node(tb, h);
 
-       /*  
+       /*
           determine maximal number of items we can shift to the left neighbor (in tb structure)
           and the maximal number of bytes that can flow to the left neighbor
           from the left most liquid item that cannot be shifted from S[0] entirely (returned value)
@@ -1348,13 +1353,13 @@ static int ip_check_balance(struct tree_balance *tb, int h)
 
        {
                int lpar, rpar, nset, lset, rset, lrset;
-               /* 
+               /*
                 * regular overflowing of the node
                 */
 
-               /* get_num_ver works in 2 modes (FLOW & NO_FLOW) 
+               /* get_num_ver works in 2 modes (FLOW & NO_FLOW)
                   lpar, rpar - number of items we can shift to left/right neighbor (including splitting item)
-                  nset, lset, rset, lrset - shows, whether flowing items give better packing 
+                  nset, lset, rset, lrset - shows, whether flowing items give better packing
                 */
 #define FLOW 1
 #define NO_FLOW 0              /* do not any splitting */
@@ -1544,7 +1549,7 @@ static int ip_check_balance(struct tree_balance *tb, int h)
  *     h       current level of the node;
  *     inum    item number in S[h];
  *     mode    i - insert, p - paste;
- * Returns:    1 - schedule occurred; 
+ * Returns:    1 - schedule occurred;
  *             0 - balancing for higher levels needed;
  *            -1 - no balancing for higher levels needed;
  *            -2 - no disk space.
@@ -1559,7 +1564,7 @@ static int dc_check_balance_internal(struct tree_balance *tb, int h)
        /* Sh is the node whose balance is currently being checked,
           and Fh is its father.  */
        struct buffer_head *Sh, *Fh;
-       int maxsize, n_ret_value;
+       int maxsize, ret;
        int lfree, rfree /* free space in L and R */ ;
 
        Sh = PATH_H_PBUFFER(tb->tb_path, h);
@@ -1584,8 +1589,8 @@ static int dc_check_balance_internal(struct tree_balance *tb, int h)
                return CARRY_ON;
        }
 
-       if ((n_ret_value = get_parents(tb, h)) != CARRY_ON)
-               return n_ret_value;
+       if ((ret = get_parents(tb, h)) != CARRY_ON)
+               return ret;
 
        /* get free space of neighbors */
        rfree = get_rfree(tb, h);
@@ -1727,7 +1732,7 @@ static int dc_check_balance_internal(struct tree_balance *tb, int h)
  *     h       current level of the node;
  *     inum    item number in S[h];
  *     mode    i - insert, p - paste;
- * Returns:    1 - schedule occurred; 
+ * Returns:    1 - schedule occurred;
  *             0 - balancing for higher levels needed;
  *            -1 - no balancing for higher levels needed;
  *            -2 - no disk space.
@@ -1742,7 +1747,7 @@ static int dc_check_balance_leaf(struct tree_balance *tb, int h)
           attempted change in node space used level is levbytes bytes. */
        int levbytes;
        /* the maximal item size */
-       int maxsize, n_ret_value;
+       int maxsize, ret;
        /* S0 is the node whose balance is currently being checked,
           and F0 is its father.  */
        struct buffer_head *S0, *F0;
@@ -1764,8 +1769,8 @@ static int dc_check_balance_leaf(struct tree_balance *tb, int h)
                return NO_BALANCING_NEEDED;
        }
 
-       if ((n_ret_value = get_parents(tb, h)) != CARRY_ON)
-               return n_ret_value;
+       if ((ret = get_parents(tb, h)) != CARRY_ON)
+               return ret;
 
        /* get free space of neighbors */
        rfree = get_rfree(tb, h);
@@ -1821,7 +1826,7 @@ static int dc_check_balance_leaf(struct tree_balance *tb, int h)
  *     h       current level of the node;
  *     inum    item number in S[h];
  *     mode    d - delete, c - cut.
- * Returns:    1 - schedule occurred; 
+ * Returns:    1 - schedule occurred;
  *             0 - balancing for higher levels needed;
  *            -1 - no balancing for higher levels needed;
  *            -2 - no disk space.
@@ -1850,7 +1855,7 @@ static int dc_check_balance(struct tree_balance *tb, int h)
  *     h       current level of the node;
  *     inum    item number in S[h];
  *     mode    i - insert, p - paste, d - delete, c - cut.
- * Returns:    1 - schedule occurred; 
+ * Returns:    1 - schedule occurred;
  *             0 - balancing for higher levels needed;
  *            -1 - no balancing for higher levels needed;
  *            -2 - no disk space.
@@ -1884,137 +1889,138 @@ static int check_balance(int mode,
 }
 
 /* Check whether parent at the path is the really parent of the current node.*/
-static int get_direct_parent(struct tree_balance *p_s_tb, int n_h)
+static int get_direct_parent(struct tree_balance *tb, int h)
 {
-       struct buffer_head *p_s_bh;
-       struct treepath *p_s_path = p_s_tb->tb_path;
-       int n_position,
-           n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h);
+       struct buffer_head *bh;
+       struct treepath *path = tb->tb_path;
+       int position,
+           path_offset = PATH_H_PATH_OFFSET(tb->tb_path, h);
 
        /* We are in the root or in the new root. */
-       if (n_path_offset <= FIRST_PATH_ELEMENT_OFFSET) {
+       if (path_offset <= FIRST_PATH_ELEMENT_OFFSET) {
 
-               RFALSE(n_path_offset < FIRST_PATH_ELEMENT_OFFSET - 1,
+               RFALSE(path_offset < FIRST_PATH_ELEMENT_OFFSET - 1,
                       "PAP-8260: invalid offset in the path");
 
-               if (PATH_OFFSET_PBUFFER(p_s_path, FIRST_PATH_ELEMENT_OFFSET)->
-                   b_blocknr == SB_ROOT_BLOCK(p_s_tb->tb_sb)) {
+               if (PATH_OFFSET_PBUFFER(path, FIRST_PATH_ELEMENT_OFFSET)->
+                   b_blocknr == SB_ROOT_BLOCK(tb->tb_sb)) {
                        /* Root is not changed. */
-                       PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1) = NULL;
-                       PATH_OFFSET_POSITION(p_s_path, n_path_offset - 1) = 0;
+                       PATH_OFFSET_PBUFFER(path, path_offset - 1) = NULL;
+                       PATH_OFFSET_POSITION(path, path_offset - 1) = 0;
                        return CARRY_ON;
                }
                return REPEAT_SEARCH;   /* Root is changed and we must recalculate the path. */
        }
 
        if (!B_IS_IN_TREE
-           (p_s_bh = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1)))
+           (bh = PATH_OFFSET_PBUFFER(path, path_offset - 1)))
                return REPEAT_SEARCH;   /* Parent in the path is not in the tree. */
 
-       if ((n_position =
-            PATH_OFFSET_POSITION(p_s_path,
-                                 n_path_offset - 1)) > B_NR_ITEMS(p_s_bh))
+       if ((position =
+            PATH_OFFSET_POSITION(path,
+                                 path_offset - 1)) > B_NR_ITEMS(bh))
                return REPEAT_SEARCH;
 
-       if (B_N_CHILD_NUM(p_s_bh, n_position) !=
-           PATH_OFFSET_PBUFFER(p_s_path, n_path_offset)->b_blocknr)
+       if (B_N_CHILD_NUM(bh, position) !=
+           PATH_OFFSET_PBUFFER(path, path_offset)->b_blocknr)
                /* Parent in the path is not parent of the current node in the tree. */
                return REPEAT_SEARCH;
 
-       if (buffer_locked(p_s_bh)) {
-               __wait_on_buffer(p_s_bh);
-               if (FILESYSTEM_CHANGED_TB(p_s_tb))
+       if (buffer_locked(bh)) {
+               __wait_on_buffer(bh);
+               if (FILESYSTEM_CHANGED_TB(tb))
                        return REPEAT_SEARCH;
        }
 
        return CARRY_ON;        /* Parent in the path is unlocked and really parent of the current node.  */
 }
 
-/* Using lnum[n_h] and rnum[n_h] we should determine what neighbors
- * of S[n_h] we
- * need in order to balance S[n_h], and get them if necessary.
+/* Using lnum[h] and rnum[h] we should determine what neighbors
+ * of S[h] we
+ * need in order to balance S[h], and get them if necessary.
  * Returns:    SCHEDULE_OCCURRED - schedule occurred while the function worked;
  *             CARRY_ON - schedule didn't occur while the function worked;
  */
-static int get_neighbors(struct tree_balance *p_s_tb, int n_h)
+static int get_neighbors(struct tree_balance *tb, int h)
 {
-       int n_child_position,
-           n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h + 1);
-       unsigned long n_son_number;
-       struct super_block *p_s_sb = p_s_tb->tb_sb;
-       struct buffer_head *p_s_bh;
+       int child_position,
+           path_offset = PATH_H_PATH_OFFSET(tb->tb_path, h + 1);
+       unsigned long son_number;
+       struct super_block *sb = tb->tb_sb;
+       struct buffer_head *bh;
 
-       PROC_INFO_INC(p_s_sb, get_neighbors[n_h]);
+       PROC_INFO_INC(sb, get_neighbors[h]);
 
-       if (p_s_tb->lnum[n_h]) {
-               /* We need left neighbor to balance S[n_h]. */
-               PROC_INFO_INC(p_s_sb, need_l_neighbor[n_h]);
-               p_s_bh = PATH_OFFSET_PBUFFER(p_s_tb->tb_path, n_path_offset);
+       if (tb->lnum[h]) {
+               /* We need left neighbor to balance S[h]. */
+               PROC_INFO_INC(sb, need_l_neighbor[h]);
+               bh = PATH_OFFSET_PBUFFER(tb->tb_path, path_offset);
 
-               RFALSE(p_s_bh == p_s_tb->FL[n_h] &&
-                      !PATH_OFFSET_POSITION(p_s_tb->tb_path, n_path_offset),
+               RFALSE(bh == tb->FL[h] &&
+                      !PATH_OFFSET_POSITION(tb->tb_path, path_offset),
                       "PAP-8270: invalid position in the parent");
 
-               n_child_position =
-                   (p_s_bh ==
-                    p_s_tb->FL[n_h]) ? p_s_tb->lkey[n_h] : B_NR_ITEMS(p_s_tb->
-                                                                      FL[n_h]);
-               n_son_number = B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position);
-               p_s_bh = sb_bread(p_s_sb, n_son_number);
-               if (!p_s_bh)
+               child_position =
+                   (bh ==
+                    tb->FL[h]) ? tb->lkey[h] : B_NR_ITEMS(tb->
+                                                                      FL[h]);
+               son_number = B_N_CHILD_NUM(tb->FL[h], child_position);
+               bh = sb_bread(sb, son_number);
+               if (!bh)
                        return IO_ERROR;
-               if (FILESYSTEM_CHANGED_TB(p_s_tb)) {
-                       decrement_bcount(p_s_bh);
-                       PROC_INFO_INC(p_s_sb, get_neighbors_restart[n_h]);
+               if (FILESYSTEM_CHANGED_TB(tb)) {
+                       brelse(bh);
+                       PROC_INFO_INC(sb, get_neighbors_restart[h]);
                        return REPEAT_SEARCH;
                }
 
-               RFALSE(!B_IS_IN_TREE(p_s_tb->FL[n_h]) ||
-                      n_child_position > B_NR_ITEMS(p_s_tb->FL[n_h]) ||
-                      B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position) !=
-                      p_s_bh->b_blocknr, "PAP-8275: invalid parent");
-               RFALSE(!B_IS_IN_TREE(p_s_bh), "PAP-8280: invalid child");
-               RFALSE(!n_h &&
-                      B_FREE_SPACE(p_s_bh) !=
-                      MAX_CHILD_SIZE(p_s_bh) -
-                      dc_size(B_N_CHILD(p_s_tb->FL[0], n_child_position)),
+               RFALSE(!B_IS_IN_TREE(tb->FL[h]) ||
+                      child_position > B_NR_ITEMS(tb->FL[h]) ||
+                      B_N_CHILD_NUM(tb->FL[h], child_position) !=
+                      bh->b_blocknr, "PAP-8275: invalid parent");
+               RFALSE(!B_IS_IN_TREE(bh), "PAP-8280: invalid child");
+               RFALSE(!h &&
+                      B_FREE_SPACE(bh) !=
+                      MAX_CHILD_SIZE(bh) -
+                      dc_size(B_N_CHILD(tb->FL[0], child_position)),
                       "PAP-8290: invalid child size of left neighbor");
 
-               decrement_bcount(p_s_tb->L[n_h]);
-               p_s_tb->L[n_h] = p_s_bh;
+               brelse(tb->L[h]);
+               tb->L[h] = bh;
        }
 
-       if (p_s_tb->rnum[n_h]) {        /* We need right neighbor to balance S[n_path_offset]. */
-               PROC_INFO_INC(p_s_sb, need_r_neighbor[n_h]);
-               p_s_bh = PATH_OFFSET_PBUFFER(p_s_tb->tb_path, n_path_offset);
+       /* We need right neighbor to balance S[path_offset]. */
+       if (tb->rnum[h]) {      /* We need right neighbor to balance S[path_offset]. */
+               PROC_INFO_INC(sb, need_r_neighbor[h]);
+               bh = PATH_OFFSET_PBUFFER(tb->tb_path, path_offset);
 
-               RFALSE(p_s_bh == p_s_tb->FR[n_h] &&
-                      PATH_OFFSET_POSITION(p_s_tb->tb_path,
-                                           n_path_offset) >=
-                      B_NR_ITEMS(p_s_bh),
+               RFALSE(bh == tb->FR[h] &&
+                      PATH_OFFSET_POSITION(tb->tb_path,
+                                           path_offset) >=
+                      B_NR_ITEMS(bh),
                       "PAP-8295: invalid position in the parent");
 
-               n_child_position =
-                   (p_s_bh == p_s_tb->FR[n_h]) ? p_s_tb->rkey[n_h] + 1 : 0;
-               n_son_number = B_N_CHILD_NUM(p_s_tb->FR[n_h], n_child_position);
-               p_s_bh = sb_bread(p_s_sb, n_son_number);
-               if (!p_s_bh)
+               child_position =
+                   (bh == tb->FR[h]) ? tb->rkey[h] + 1 : 0;
+               son_number = B_N_CHILD_NUM(tb->FR[h], child_position);
+               bh = sb_bread(sb, son_number);
+               if (!bh)
                        return IO_ERROR;
-               if (FILESYSTEM_CHANGED_TB(p_s_tb)) {
-                       decrement_bcount(p_s_bh);
-                       PROC_INFO_INC(p_s_sb, get_neighbors_restart[n_h]);
+               if (FILESYSTEM_CHANGED_TB(tb)) {
+                       brelse(bh);
+                       PROC_INFO_INC(sb, get_neighbors_restart[h]);
                        return REPEAT_SEARCH;
                }
-               decrement_bcount(p_s_tb->R[n_h]);
-               p_s_tb->R[n_h] = p_s_bh;
+               brelse(tb->R[h]);
+               tb->R[h] = bh;
 
-               RFALSE(!n_h
-                      && B_FREE_SPACE(p_s_bh) !=
-                      MAX_CHILD_SIZE(p_s_bh) -
-                      dc_size(B_N_CHILD(p_s_tb->FR[0], n_child_position)),
+               RFALSE(!h
+                      && B_FREE_SPACE(bh) !=
+                      MAX_CHILD_SIZE(bh) -
+                      dc_size(B_N_CHILD(tb->FR[0], child_position)),
                       "PAP-8300: invalid child size of right neighbor (%d != %d - %d)",
-                      B_FREE_SPACE(p_s_bh), MAX_CHILD_SIZE(p_s_bh),
-                      dc_size(B_N_CHILD(p_s_tb->FR[0], n_child_position)));
+                      B_FREE_SPACE(bh), MAX_CHILD_SIZE(bh),
+                      dc_size(B_N_CHILD(tb->FR[0], child_position)));
 
        }
        return CARRY_ON;
@@ -2088,52 +2094,46 @@ static int get_mem_for_virtual_node(struct tree_balance *tb)
 }
 
 #ifdef CONFIG_REISERFS_CHECK
-static void tb_buffer_sanity_check(struct super_block *p_s_sb,
-                                  struct buffer_head *p_s_bh,
+static void tb_buffer_sanity_check(struct super_block *sb,
+                                  struct buffer_head *bh,
                                   const char *descr, int level)
 {
-       if (p_s_bh) {
-               if (atomic_read(&(p_s_bh->b_count)) <= 0) {
-
-                       reiserfs_panic(p_s_sb,
-                                      "jmacd-1: tb_buffer_sanity_check(): negative or zero reference counter for buffer %s[%d] (%b)\n",
-                                      descr, level, p_s_bh);
-               }
-
-               if (!buffer_uptodate(p_s_bh)) {
-                       reiserfs_panic(p_s_sb,
-                                      "jmacd-2: tb_buffer_sanity_check(): buffer is not up to date %s[%d] (%b)\n",
-                                      descr, level, p_s_bh);
-               }
-
-               if (!B_IS_IN_TREE(p_s_bh)) {
-                       reiserfs_panic(p_s_sb,
-                                      "jmacd-3: tb_buffer_sanity_check(): buffer is not in tree %s[%d] (%b)\n",
-                                      descr, level, p_s_bh);
-               }
-
-               if (p_s_bh->b_bdev != p_s_sb->s_bdev) {
-                       reiserfs_panic(p_s_sb,
-                                      "jmacd-4: tb_buffer_sanity_check(): buffer has wrong device %s[%d] (%b)\n",
-                                      descr, level, p_s_bh);
-               }
-
-               if (p_s_bh->b_size != p_s_sb->s_blocksize) {
-                       reiserfs_panic(p_s_sb,
-                                      "jmacd-5: tb_buffer_sanity_check(): buffer has wrong blocksize %s[%d] (%b)\n",
-                                      descr, level, p_s_bh);
-               }
-
-               if (p_s_bh->b_blocknr > SB_BLOCK_COUNT(p_s_sb)) {
-                       reiserfs_panic(p_s_sb,
-                                      "jmacd-6: tb_buffer_sanity_check(): buffer block number too high %s[%d] (%b)\n",
-                                      descr, level, p_s_bh);
-               }
+       if (bh) {
+               if (atomic_read(&(bh->b_count)) <= 0)
+
+                       reiserfs_panic(sb, "jmacd-1", "negative or zero "
+                                      "reference counter for buffer %s[%d] "
+                                      "(%b)", descr, level, bh);
+
+               if (!buffer_uptodate(bh))
+                       reiserfs_panic(sb, "jmacd-2", "buffer is not up "
+                                      "to date %s[%d] (%b)",
+                                      descr, level, bh);
+
+               if (!B_IS_IN_TREE(bh))
+                       reiserfs_panic(sb, "jmacd-3", "buffer is not "
+                                      "in tree %s[%d] (%b)",
+                                      descr, level, bh);
+
+               if (bh->b_bdev != sb->s_bdev)
+                       reiserfs_panic(sb, "jmacd-4", "buffer has wrong "
+                                      "device %s[%d] (%b)",
+                                      descr, level, bh);
+
+               if (bh->b_size != sb->s_blocksize)
+                       reiserfs_panic(sb, "jmacd-5", "buffer has wrong "
+                                      "blocksize %s[%d] (%b)",
+                                      descr, level, bh);
+
+               if (bh->b_blocknr > SB_BLOCK_COUNT(sb))
+                       reiserfs_panic(sb, "jmacd-6", "buffer block "
+                                      "number too high %s[%d] (%b)",
+                                      descr, level, bh);
        }
 }
 #else
-static void tb_buffer_sanity_check(struct super_block *p_s_sb,
-                                  struct buffer_head *p_s_bh,
+static void tb_buffer_sanity_check(struct super_block *sb,
+                                  struct buffer_head *bh,
                                   const char *descr, int level)
 {;
 }
@@ -2144,7 +2144,7 @@ static int clear_all_dirty_bits(struct super_block *s, struct buffer_head *bh)
        return reiserfs_prepare_for_journal(s, bh, 0);
 }
 
-static int wait_tb_buffers_until_unlocked(struct tree_balance *p_s_tb)
+static int wait_tb_buffers_until_unlocked(struct tree_balance *tb)
 {
        struct buffer_head *locked;
 #ifdef CONFIG_REISERFS_CHECK
@@ -2156,95 +2156,94 @@ static int wait_tb_buffers_until_unlocked(struct tree_balance *p_s_tb)
 
                locked = NULL;
 
-               for (i = p_s_tb->tb_path->path_length;
+               for (i = tb->tb_path->path_length;
                     !locked && i > ILLEGAL_PATH_ELEMENT_OFFSET; i--) {
-                       if (PATH_OFFSET_PBUFFER(p_s_tb->tb_path, i)) {
+                       if (PATH_OFFSET_PBUFFER(tb->tb_path, i)) {
                                /* if I understand correctly, we can only be sure the last buffer
                                 ** in the path is in the tree --clm
                                 */
 #ifdef CONFIG_REISERFS_CHECK
-                               if (PATH_PLAST_BUFFER(p_s_tb->tb_path) ==
-                                   PATH_OFFSET_PBUFFER(p_s_tb->tb_path, i)) {
-                                       tb_buffer_sanity_check(p_s_tb->tb_sb,
+                               if (PATH_PLAST_BUFFER(tb->tb_path) ==
+                                   PATH_OFFSET_PBUFFER(tb->tb_path, i))
+                                       tb_buffer_sanity_check(tb->tb_sb,
                                                               PATH_OFFSET_PBUFFER
-                                                              (p_s_tb->tb_path,
+                                                              (tb->tb_path,
                                                                i), "S",
-                                                              p_s_tb->tb_path->
+                                                              tb->tb_path->
                                                               path_length - i);
-                               }
 #endif
-                               if (!clear_all_dirty_bits(p_s_tb->tb_sb,
+                               if (!clear_all_dirty_bits(tb->tb_sb,
                                                          PATH_OFFSET_PBUFFER
-                                                         (p_s_tb->tb_path,
+                                                         (tb->tb_path,
                                                           i))) {
                                        locked =
-                                           PATH_OFFSET_PBUFFER(p_s_tb->tb_path,
+                                           PATH_OFFSET_PBUFFER(tb->tb_path,
                                                                i);
                                }
                        }
                }
 
-               for (i = 0; !locked && i < MAX_HEIGHT && p_s_tb->insert_size[i];
+               for (i = 0; !locked && i < MAX_HEIGHT && tb->insert_size[i];
                     i++) {
 
-                       if (p_s_tb->lnum[i]) {
+                       if (tb->lnum[i]) {
 
-                               if (p_s_tb->L[i]) {
-                                       tb_buffer_sanity_check(p_s_tb->tb_sb,
-                                                              p_s_tb->L[i],
+                               if (tb->L[i]) {
+                                       tb_buffer_sanity_check(tb->tb_sb,
+                                                              tb->L[i],
                                                               "L", i);
                                        if (!clear_all_dirty_bits
-                                           (p_s_tb->tb_sb, p_s_tb->L[i]))
-                                               locked = p_s_tb->L[i];
+                                           (tb->tb_sb, tb->L[i]))
+                                               locked = tb->L[i];
                                }
 
-                               if (!locked && p_s_tb->FL[i]) {
-                                       tb_buffer_sanity_check(p_s_tb->tb_sb,
-                                                              p_s_tb->FL[i],
+                               if (!locked && tb->FL[i]) {
+                                       tb_buffer_sanity_check(tb->tb_sb,
+                                                              tb->FL[i],
                                                               "FL", i);
                                        if (!clear_all_dirty_bits
-                                           (p_s_tb->tb_sb, p_s_tb->FL[i]))
-                                               locked = p_s_tb->FL[i];
+                                           (tb->tb_sb, tb->FL[i]))
+                                               locked = tb->FL[i];
                                }
 
-                               if (!locked && p_s_tb->CFL[i]) {
-                                       tb_buffer_sanity_check(p_s_tb->tb_sb,
-                                                              p_s_tb->CFL[i],
+                               if (!locked && tb->CFL[i]) {
+                                       tb_buffer_sanity_check(tb->tb_sb,
+                                                              tb->CFL[i],
                                                               "CFL", i);
                                        if (!clear_all_dirty_bits
-                                           (p_s_tb->tb_sb, p_s_tb->CFL[i]))
-                                               locked = p_s_tb->CFL[i];
+                                           (tb->tb_sb, tb->CFL[i]))
+                                               locked = tb->CFL[i];
                                }
 
                        }
 
-                       if (!locked && (p_s_tb->rnum[i])) {
+                       if (!locked && (tb->rnum[i])) {
 
-                               if (p_s_tb->R[i]) {
-                                       tb_buffer_sanity_check(p_s_tb->tb_sb,
-                                                              p_s_tb->R[i],
+                               if (tb->R[i]) {
+                                       tb_buffer_sanity_check(tb->tb_sb,
+                                                              tb->R[i],
                                                               "R", i);
                                        if (!clear_all_dirty_bits
-                                           (p_s_tb->tb_sb, p_s_tb->R[i]))
-                                               locked = p_s_tb->R[i];
+                                           (tb->tb_sb, tb->R[i]))
+                                               locked = tb->R[i];
                                }
 
-                               if (!locked && p_s_tb->FR[i]) {
-                                       tb_buffer_sanity_check(p_s_tb->tb_sb,
-                                                              p_s_tb->FR[i],
+                               if (!locked && tb->FR[i]) {
+                                       tb_buffer_sanity_check(tb->tb_sb,
+                                                              tb->FR[i],
                                                               "FR", i);
                                        if (!clear_all_dirty_bits
-                                           (p_s_tb->tb_sb, p_s_tb->FR[i]))
-                                               locked = p_s_tb->FR[i];
+                                           (tb->tb_sb, tb->FR[i]))
+                                               locked = tb->FR[i];
                                }
 
-                               if (!locked && p_s_tb->CFR[i]) {
-                                       tb_buffer_sanity_check(p_s_tb->tb_sb,
-                                                              p_s_tb->CFR[i],
+                               if (!locked && tb->CFR[i]) {
+                                       tb_buffer_sanity_check(tb->tb_sb,
+                                                              tb->CFR[i],
                                                               "CFR", i);
                                        if (!clear_all_dirty_bits
-                                           (p_s_tb->tb_sb, p_s_tb->CFR[i]))
-                                               locked = p_s_tb->CFR[i];
+                                           (tb->tb_sb, tb->CFR[i]))
+                                               locked = tb->CFR[i];
                                }
                        }
                }
@@ -2257,10 +2256,10 @@ static int wait_tb_buffers_until_unlocked(struct tree_balance *p_s_tb)
                 ** --clm
                 */
                for (i = 0; !locked && i < MAX_FEB_SIZE; i++) {
-                       if (p_s_tb->FEB[i]) {
+                       if (tb->FEB[i]) {
                                if (!clear_all_dirty_bits
-                                   (p_s_tb->tb_sb, p_s_tb->FEB[i]))
-                                       locked = p_s_tb->FEB[i];
+                                   (tb->tb_sb, tb->FEB[i]))
+                                       locked = tb->FEB[i];
                        }
                }
 
@@ -2268,21 +2267,20 @@ static int wait_tb_buffers_until_unlocked(struct tree_balance *p_s_tb)
 #ifdef CONFIG_REISERFS_CHECK
                        repeat_counter++;
                        if ((repeat_counter % 10000) == 0) {
-                               reiserfs_warning(p_s_tb->tb_sb,
-                                                "wait_tb_buffers_until_released(): too many "
-                                                "iterations waiting for buffer to unlock "
+                               reiserfs_warning(tb->tb_sb, "reiserfs-8200",
+                                                "too many iterations waiting "
+                                                "for buffer to unlock "
                                                 "(%b)", locked);
 
                                /* Don't loop forever.  Try to recover from possible error. */
 
-                               return (FILESYSTEM_CHANGED_TB(p_s_tb)) ?
+                               return (FILESYSTEM_CHANGED_TB(tb)) ?
                                    REPEAT_SEARCH : CARRY_ON;
                        }
 #endif
                        __wait_on_buffer(locked);
-                       if (FILESYSTEM_CHANGED_TB(p_s_tb)) {
+                       if (FILESYSTEM_CHANGED_TB(tb))
                                return REPEAT_SEARCH;
-                       }
                }
 
        } while (locked);
@@ -2295,15 +2293,15 @@ static int wait_tb_buffers_until_unlocked(struct tree_balance *p_s_tb)
  *     analyze what and where should be moved;
  *     get sufficient number of new nodes;
  * Balancing will start only after all resources will be collected at a time.
- * 
+ *
  * When ported to SMP kernels, only at the last moment after all needed nodes
  * are collected in cache, will the resources be locked using the usual
  * textbook ordered lock acquisition algorithms.  Note that ensuring that
  * this code neither write locks what it does not need to write lock nor locks out of order
  * will be a pain in the butt that could have been avoided.  Grumble grumble. -Hans
- * 
+ *
  * fix is meant in the sense of render unchanging
- * 
+ *
  * Latency might be improved by first gathering a list of what buffers are needed
  * and then getting as many of them in parallel as possible? -Hans
  *
@@ -2312,159 +2310,160 @@ static int wait_tb_buffers_until_unlocked(struct tree_balance *p_s_tb)
  *     tb      tree_balance structure;
  *     inum    item number in S[h];
  *      pos_in_item - comment this if you can
- *      ins_ih & ins_sd are used when inserting
+ *      ins_ih item head of item being inserted
+ *     data    inserted item or data to be pasted
  * Returns:    1 - schedule occurred while the function worked;
  *             0 - schedule didn't occur while the function worked;
- *             -1 - if no_disk_space 
+ *             -1 - if no_disk_space
  */
 
-int fix_nodes(int n_op_mode, struct tree_balance *p_s_tb, struct item_head *p_s_ins_ih,        // item head of item being inserted
-             const void *data  // inserted item or data to be pasted
-    )
+int fix_nodes(int op_mode, struct tree_balance *tb,
+             struct item_head *ins_ih, const void *data)
 {
-       int n_ret_value, n_h, n_item_num = PATH_LAST_POSITION(p_s_tb->tb_path);
-       int n_pos_in_item;
+       int ret, h, item_num = PATH_LAST_POSITION(tb->tb_path);
+       int pos_in_item;
 
        /* we set wait_tb_buffers_run when we have to restore any dirty bits cleared
         ** during wait_tb_buffers_run
         */
        int wait_tb_buffers_run = 0;
-       struct buffer_head *p_s_tbS0 = PATH_PLAST_BUFFER(p_s_tb->tb_path);
+       struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
 
-       ++REISERFS_SB(p_s_tb->tb_sb)->s_fix_nodes;
+       ++REISERFS_SB(tb->tb_sb)->s_fix_nodes;
 
-       n_pos_in_item = p_s_tb->tb_path->pos_in_item;
+       pos_in_item = tb->tb_path->pos_in_item;
 
-       p_s_tb->fs_gen = get_generation(p_s_tb->tb_sb);
+       tb->fs_gen = get_generation(tb->tb_sb);
 
        /* we prepare and log the super here so it will already be in the
         ** transaction when do_balance needs to change it.
         ** This way do_balance won't have to schedule when trying to prepare
         ** the super for logging
         */
-       reiserfs_prepare_for_journal(p_s_tb->tb_sb,
-                                    SB_BUFFER_WITH_SB(p_s_tb->tb_sb), 1);
-       journal_mark_dirty(p_s_tb->transaction_handle, p_s_tb->tb_sb,
-                          SB_BUFFER_WITH_SB(p_s_tb->tb_sb));
-       if (FILESYSTEM_CHANGED_TB(p_s_tb))
+       reiserfs_prepare_for_journal(tb->tb_sb,
+                                    SB_BUFFER_WITH_SB(tb->tb_sb), 1);
+       journal_mark_dirty(tb->transaction_handle, tb->tb_sb,
+                          SB_BUFFER_WITH_SB(tb->tb_sb));
+       if (FILESYSTEM_CHANGED_TB(tb))
                return REPEAT_SEARCH;
 
        /* if it possible in indirect_to_direct conversion */
-       if (buffer_locked(p_s_tbS0)) {
-               __wait_on_buffer(p_s_tbS0);
-               if (FILESYSTEM_CHANGED_TB(p_s_tb))
+       if (buffer_locked(tbS0)) {
+               __wait_on_buffer(tbS0);
+               if (FILESYSTEM_CHANGED_TB(tb))
                        return REPEAT_SEARCH;
        }
 #ifdef CONFIG_REISERFS_CHECK
        if (cur_tb) {
                print_cur_tb("fix_nodes");
-               reiserfs_panic(p_s_tb->tb_sb,
-                              "PAP-8305: fix_nodes:  there is pending do_balance");
+               reiserfs_panic(tb->tb_sb, "PAP-8305",
+                              "there is pending do_balance");
        }
 
-       if (!buffer_uptodate(p_s_tbS0) || !B_IS_IN_TREE(p_s_tbS0)) {
-               reiserfs_panic(p_s_tb->tb_sb,
-                              "PAP-8320: fix_nodes: S[0] (%b %z) is not uptodate "
-                              "at the beginning of fix_nodes or not in tree (mode %c)",
-                              p_s_tbS0, p_s_tbS0, n_op_mode);
-       }
+       if (!buffer_uptodate(tbS0) || !B_IS_IN_TREE(tbS0))
+               reiserfs_panic(tb->tb_sb, "PAP-8320", "S[0] (%b %z) is "
+                              "not uptodate at the beginning of fix_nodes "
+                              "or not in tree (mode %c)",
+                              tbS0, tbS0, op_mode);
 
        /* Check parameters. */
-       switch (n_op_mode) {
+       switch (op_mode) {
        case M_INSERT:
-               if (n_item_num <= 0 || n_item_num > B_NR_ITEMS(p_s_tbS0))
-                       reiserfs_panic(p_s_tb->tb_sb,
-                                      "PAP-8330: fix_nodes: Incorrect item number %d (in S0 - %d) in case of insert",
-                                      n_item_num, B_NR_ITEMS(p_s_tbS0));
+               if (item_num <= 0 || item_num > B_NR_ITEMS(tbS0))
+                       reiserfs_panic(tb->tb_sb, "PAP-8330", "Incorrect "
+                                      "item number %d (in S0 - %d) in case "
+                                      "of insert", item_num,
+                                      B_NR_ITEMS(tbS0));
                break;
        case M_PASTE:
        case M_DELETE:
        case M_CUT:
-               if (n_item_num < 0 || n_item_num >= B_NR_ITEMS(p_s_tbS0)) {
-                       print_block(p_s_tbS0, 0, -1, -1);
-                       reiserfs_panic(p_s_tb->tb_sb,
-                                      "PAP-8335: fix_nodes: Incorrect item number(%d); mode = %c insert_size = %d\n",
-                                      n_item_num, n_op_mode,
-                                      p_s_tb->insert_size[0]);
+               if (item_num < 0 || item_num >= B_NR_ITEMS(tbS0)) {
+                       print_block(tbS0, 0, -1, -1);
+                       reiserfs_panic(tb->tb_sb, "PAP-8335", "Incorrect "
+                                      "item number(%d); mode = %c "
+                                      "insert_size = %d",
+                                      item_num, op_mode,
+                                      tb->insert_size[0]);
                }
                break;
        default:
-               reiserfs_panic(p_s_tb->tb_sb,
-                              "PAP-8340: fix_nodes: Incorrect mode of operation");
+               reiserfs_panic(tb->tb_sb, "PAP-8340", "Incorrect mode "
+                              "of operation");
        }
 #endif
 
-       if (get_mem_for_virtual_node(p_s_tb) == REPEAT_SEARCH)
+       if (get_mem_for_virtual_node(tb) == REPEAT_SEARCH)
                // FIXME: maybe -ENOMEM when tb->vn_buf == 0? Now just repeat
                return REPEAT_SEARCH;
 
-       /* Starting from the leaf level; for all levels n_h of the tree. */
-       for (n_h = 0; n_h < MAX_HEIGHT && p_s_tb->insert_size[n_h]; n_h++) {
-               if ((n_ret_value = get_direct_parent(p_s_tb, n_h)) != CARRY_ON) {
+       /* Starting from the leaf level; for all levels h of the tree. */
+       for (h = 0; h < MAX_HEIGHT && tb->insert_size[h]; h++) {
+               ret = get_direct_parent(tb, h);
+               if (ret != CARRY_ON)
                        goto repeat;
-               }
 
-               if ((n_ret_value =
-                    check_balance(n_op_mode, p_s_tb, n_h, n_item_num,
-                                  n_pos_in_item, p_s_ins_ih,
-                                  data)) != CARRY_ON) {
-                       if (n_ret_value == NO_BALANCING_NEEDED) {
+               ret = check_balance(op_mode, tb, h, item_num,
+                                   pos_in_item, ins_ih, data);
+               if (ret != CARRY_ON) {
+                       if (ret == NO_BALANCING_NEEDED) {
                                /* No balancing for higher levels needed. */
-                               if ((n_ret_value =
-                                    get_neighbors(p_s_tb, n_h)) != CARRY_ON) {
+                               ret = get_neighbors(tb, h);
+                               if (ret != CARRY_ON)
                                        goto repeat;
-                               }
-                               if (n_h != MAX_HEIGHT - 1)
-                                       p_s_tb->insert_size[n_h + 1] = 0;
+                               if (h != MAX_HEIGHT - 1)
+                                       tb->insert_size[h + 1] = 0;
                                /* ok, analysis and resource gathering are complete */
                                break;
                        }
                        goto repeat;
                }
 
-               if ((n_ret_value = get_neighbors(p_s_tb, n_h)) != CARRY_ON) {
+               ret = get_neighbors(tb, h);
+               if (ret != CARRY_ON)
                        goto repeat;
-               }
 
-               if ((n_ret_value = get_empty_nodes(p_s_tb, n_h)) != CARRY_ON) {
-                       goto repeat;    /* No disk space, or schedule occurred and
-                                          analysis may be invalid and needs to be redone. */
-               }
+               /* No disk space, or schedule occurred and analysis may be
+                * invalid and needs to be redone. */
+               ret = get_empty_nodes(tb, h);
+               if (ret != CARRY_ON)
+                       goto repeat;
 
-               if (!PATH_H_PBUFFER(p_s_tb->tb_path, n_h)) {
+               if (!PATH_H_PBUFFER(tb->tb_path, h)) {
                        /* We have a positive insert size but no nodes exist on this
                           level, this means that we are creating a new root. */
 
-                       RFALSE(p_s_tb->blknum[n_h] != 1,
+                       RFALSE(tb->blknum[h] != 1,
                               "PAP-8350: creating new empty root");
 
-                       if (n_h < MAX_HEIGHT - 1)
-                               p_s_tb->insert_size[n_h + 1] = 0;
-               } else if (!PATH_H_PBUFFER(p_s_tb->tb_path, n_h + 1)) {
-                       if (p_s_tb->blknum[n_h] > 1) {
-                               /* The tree needs to be grown, so this node S[n_h]
+                       if (h < MAX_HEIGHT - 1)
+                               tb->insert_size[h + 1] = 0;
+               } else if (!PATH_H_PBUFFER(tb->tb_path, h + 1)) {
+                       if (tb->blknum[h] > 1) {
+                               /* The tree needs to be grown, so this node S[h]
                                   which is the root node is split into two nodes,
-                                  and a new node (S[n_h+1]) will be created to
+                                  and a new node (S[h+1]) will be created to
                                   become the root node.  */
 
-                               RFALSE(n_h == MAX_HEIGHT - 1,
+                               RFALSE(h == MAX_HEIGHT - 1,
                                       "PAP-8355: attempt to create too high of a tree");
 
-                               p_s_tb->insert_size[n_h + 1] =
+                               tb->insert_size[h + 1] =
                                    (DC_SIZE +
-                                    KEY_SIZE) * (p_s_tb->blknum[n_h] - 1) +
+                                    KEY_SIZE) * (tb->blknum[h] - 1) +
                                    DC_SIZE;
-                       } else if (n_h < MAX_HEIGHT - 1)
-                               p_s_tb->insert_size[n_h + 1] = 0;
+                       } else if (h < MAX_HEIGHT - 1)
+                               tb->insert_size[h + 1] = 0;
                } else
-                       p_s_tb->insert_size[n_h + 1] =
-                           (DC_SIZE + KEY_SIZE) * (p_s_tb->blknum[n_h] - 1);
+                       tb->insert_size[h + 1] =
+                           (DC_SIZE + KEY_SIZE) * (tb->blknum[h] - 1);
        }
 
-       if ((n_ret_value = wait_tb_buffers_until_unlocked(p_s_tb)) == CARRY_ON) {
-               if (FILESYSTEM_CHANGED_TB(p_s_tb)) {
+       ret = wait_tb_buffers_until_unlocked(tb);
+       if (ret == CARRY_ON) {
+               if (FILESYSTEM_CHANGED_TB(tb)) {
                        wait_tb_buffers_run = 1;
-                       n_ret_value = REPEAT_SEARCH;
+                       ret = REPEAT_SEARCH;
                        goto repeat;
                } else {
                        return CARRY_ON;
@@ -2485,57 +2484,57 @@ int fix_nodes(int n_op_mode, struct tree_balance *p_s_tb, struct item_head *p_s_
 
                /* Release path buffers. */
                if (wait_tb_buffers_run) {
-                       pathrelse_and_restore(p_s_tb->tb_sb, p_s_tb->tb_path);
+                       pathrelse_and_restore(tb->tb_sb, tb->tb_path);
                } else {
-                       pathrelse(p_s_tb->tb_path);
+                       pathrelse(tb->tb_path);
                }
                /* brelse all resources collected for balancing */
                for (i = 0; i < MAX_HEIGHT; i++) {
                        if (wait_tb_buffers_run) {
-                               reiserfs_restore_prepared_buffer(p_s_tb->tb_sb,
-                                                                p_s_tb->L[i]);
-                               reiserfs_restore_prepared_buffer(p_s_tb->tb_sb,
-                                                                p_s_tb->R[i]);
-                               reiserfs_restore_prepared_buffer(p_s_tb->tb_sb,
-                                                                p_s_tb->FL[i]);
-                               reiserfs_restore_prepared_buffer(p_s_tb->tb_sb,
-                                                                p_s_tb->FR[i]);
-                               reiserfs_restore_prepared_buffer(p_s_tb->tb_sb,
-                                                                p_s_tb->
+                               reiserfs_restore_prepared_buffer(tb->tb_sb,
+                                                                tb->L[i]);
+                               reiserfs_restore_prepared_buffer(tb->tb_sb,
+                                                                tb->R[i]);
+                               reiserfs_restore_prepared_buffer(tb->tb_sb,
+                                                                tb->FL[i]);
+                               reiserfs_restore_prepared_buffer(tb->tb_sb,
+                                                                tb->FR[i]);
+                               reiserfs_restore_prepared_buffer(tb->tb_sb,
+                                                                tb->
                                                                 CFL[i]);
-                               reiserfs_restore_prepared_buffer(p_s_tb->tb_sb,
-                                                                p_s_tb->
+                               reiserfs_restore_prepared_buffer(tb->tb_sb,
+                                                                tb->
                                                                 CFR[i]);
                        }
 
-                       brelse(p_s_tb->L[i]);
-                       p_s_tb->L[i] = NULL;
-                       brelse(p_s_tb->R[i]);
-                       p_s_tb->R[i] = NULL;
-                       brelse(p_s_tb->FL[i]);
-                       p_s_tb->FL[i] = NULL;
-                       brelse(p_s_tb->FR[i]);
-                       p_s_tb->FR[i] = NULL;
-                       brelse(p_s_tb->CFL[i]);
-                       p_s_tb->CFL[i] = NULL;
-                       brelse(p_s_tb->CFR[i]);
-                       p_s_tb->CFR[i] = NULL;
+                       brelse(tb->L[i]);
+                       brelse(tb->R[i]);
+                       brelse(tb->FL[i]);
+                       brelse(tb->FR[i]);
+                       brelse(tb->CFL[i]);
+                       brelse(tb->CFR[i]);
+
+                       tb->L[i] = NULL;
+                       tb->R[i] = NULL;
+                       tb->FL[i] = NULL;
+                       tb->FR[i] = NULL;
+                       tb->CFL[i] = NULL;
+                       tb->CFR[i] = NULL;
                }
 
                if (wait_tb_buffers_run) {
                        for (i = 0; i < MAX_FEB_SIZE; i++) {
-                               if (p_s_tb->FEB[i]) {
+                               if (tb->FEB[i])
                                        reiserfs_restore_prepared_buffer
-                                           (p_s_tb->tb_sb, p_s_tb->FEB[i]);
-                               }
+                                           (tb->tb_sb, tb->FEB[i]);
                        }
                }
-               return n_ret_value;
+               return ret;
        }
 
 }
 
-/* Anatoly will probably forgive me renaming p_s_tb to tb. I just
+/* Anatoly will probably forgive me renaming tb to tb. I just
    wanted to make lines shorter */
 void unfix_nodes(struct tree_balance *tb)
 {
index e664ac16fad92e9320b94f98fa3e52c9df191fcf..6471c670743e63276f05f7c560b42b90b8c1a9e0 100644 (file)
@@ -7,7 +7,7 @@
  * (see Applied Cryptography, 2nd edition, p448).
  *
  * Jeremy Fitzhardinge <jeremy@zip.com.au> 1998
- * 
+ *
  * Jeremy has agreed to the contents of reiserfs/README. -Hans
  * Yura's function is added (04/07/2000)
  */
index de391a82b9999830cb8eb89b3633b960ac96e2e8..2074fd95046b428e5b2ea0d1e1dc4cfab52bafee 100644 (file)
@@ -105,8 +105,8 @@ static void internal_define_dest_src_infos(int shift_mode,
                break;
 
        default:
-               reiserfs_panic(tb->tb_sb,
-                              "internal_define_dest_src_infos: shift type is unknown (%d)",
+               reiserfs_panic(tb->tb_sb, "ibalance-1",
+                              "shift type is unknown (%d)",
                               shift_mode);
        }
 }
@@ -278,7 +278,7 @@ static void internal_delete_childs(struct buffer_info *cur_bi, int from, int n)
 
 /* copy cpy_num node pointers and cpy_num - 1 items from buffer src to buffer dest
 * last_first == FIRST_TO_LAST means, that we copy first items from src to tail of dest
- * last_first == LAST_TO_FIRST means, that we copy last items from src to head of dest 
+ * last_first == LAST_TO_FIRST means, that we copy last items from src to head of dest
  */
 static void internal_copy_pointers_items(struct buffer_info *dest_bi,
                                         struct buffer_head *src,
@@ -385,7 +385,7 @@ static void internal_move_pointers_items(struct buffer_info *dest_bi,
        if (last_first == FIRST_TO_LAST) {      /* shift_left occurs */
                first_pointer = 0;
                first_item = 0;
-               /* delete cpy_num - del_par pointers and keys starting for pointers with first_pointer, 
+               /* delete cpy_num - del_par pointers and keys starting for pointers with first_pointer,
                   for key - with first_item */
                internal_delete_pointers_items(src_bi, first_pointer,
                                               first_item, cpy_num - del_par);
@@ -453,7 +453,7 @@ static void internal_insert_key(struct buffer_info *dest_bi, int dest_position_b
        }
 }
 
-/* Insert d_key'th (delimiting) key from buffer cfl to tail of dest. 
+/* Insert d_key'th (delimiting) key from buffer cfl to tail of dest.
  * Copy pointer_amount node pointers and pointer_amount - 1 items from buffer src to buffer dest.
  * Replace  d_key'th key in buffer cfl.
  * Delete pointer_amount items and node pointers from buffer src.
@@ -518,7 +518,7 @@ static void internal_shift1_left(struct tree_balance *tb,
        /*    internal_move_pointers_items (tb->L[h], tb->S[h], FIRST_TO_LAST, pointer_amount, 1); */
 }
 
-/* Insert d_key'th (delimiting) key from buffer cfr to head of dest. 
+/* Insert d_key'th (delimiting) key from buffer cfr to head of dest.
  * Copy n node pointers and n - 1 items from buffer src to buffer dest.
  * Replace  d_key'th key in buffer cfr.
  * Delete n items and node pointers from buffer src.
@@ -702,8 +702,8 @@ static void balance_internal_when_delete(struct tree_balance *tb,
 
                return;
        }
-       reiserfs_panic(tb->tb_sb,
-                      "balance_internal_when_delete: unexpected tb->lnum[%d]==%d or tb->rnum[%d]==%d",
+       reiserfs_panic(tb->tb_sb, "ibalance-2",
+                      "unexpected tb->lnum[%d]==%d or tb->rnum[%d]==%d",
                       h, tb->lnum[h], h, tb->rnum[h]);
 }
 
@@ -749,7 +749,7 @@ int balance_internal(struct tree_balance *tb,       /* tree_balance structure
        this means that new pointers and items must be inserted AFTER *
        child_pos
        }
-       else 
+       else
        {
        it is the position of the leftmost pointer that must be deleted (together with
        its corresponding key to the left of the pointer)
@@ -940,8 +940,8 @@ int balance_internal(struct tree_balance *tb,       /* tree_balance structure
                struct block_head *blkh;
 
                if (tb->blknum[h] != 1)
-                       reiserfs_panic(NULL,
-                                      "balance_internal: One new node required for creating the new root");
+                       reiserfs_panic(NULL, "ibalance-3", "One new node "
+                                      "required for creating the new root");
                /* S[h] = empty buffer from the list FEB. */
                tbSh = get_FEB(tb);
                blkh = B_BLK_HEAD(tbSh);
index 823227a7662a4eb57d1dcd62093f4786302e6a85..6fd0f47e45db72b252808386450e468ad425af61 100644 (file)
@@ -363,7 +363,7 @@ static int _get_block_create_0(struct inode *inode, sector_t block,
                }
                /* make sure we don't read more bytes than actually exist in
                 ** the file.  This can happen in odd cases where i_size isn't
-                ** correct, and when direct item padding results in a few 
+                ** correct, and when direct item padding results in a few
                 ** extra bytes at the end of the direct item
                 */
                if ((le_ih_k_offset(ih) + path.pos_in_item) > inode->i_size)
@@ -438,15 +438,15 @@ static int reiserfs_bmap(struct inode *inode, sector_t block,
 ** -ENOENT instead of a valid buffer.  block_prepare_write expects to
 ** be able to do i/o on the buffers returned, unless an error value
 ** is also returned.
-** 
+**
 ** So, this allows block_prepare_write to be used for reading a single block
 ** in a page.  Where it does not produce a valid page for holes, or past the
 ** end of the file.  This turns out to be exactly what we need for reading
 ** tails for conversion.
 **
 ** The point of the wrapper is forcing a certain value for create, even
-** though the VFS layer is calling this function with create==1.  If you 
-** don't want to send create == GET_BLOCK_NO_HOLE to reiserfs_get_block, 
+** though the VFS layer is calling this function with create==1.  If you
+** don't want to send create == GET_BLOCK_NO_HOLE to reiserfs_get_block,
 ** don't use this function.
 */
 static int reiserfs_get_block_create_0(struct inode *inode, sector_t block,
@@ -602,7 +602,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
        int done;
        int fs_gen;
        struct reiserfs_transaction_handle *th = NULL;
-       /* space reserved in transaction batch: 
+       /* space reserved in transaction batch:
           . 3 balancings in direct->indirect conversion
           . 1 block involved into reiserfs_update_sd()
           XXX in practically impossible worst case direct2indirect()
@@ -754,7 +754,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
                reiserfs_write_unlock(inode->i_sb);
 
                /* the item was found, so new blocks were not added to the file
-                ** there is no need to make sure the inode is updated with this 
+                ** there is no need to make sure the inode is updated with this
                 ** transaction
                 */
                return retval;
@@ -841,10 +841,12 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
                                                          tail_offset);
                                if (retval) {
                                        if (retval != -ENOSPC)
-                                               reiserfs_warning(inode->i_sb,
-                                                                "clm-6004: convert tail failed inode %lu, error %d",
-                                                                inode->i_ino,
-                                                                retval);
+                                               reiserfs_error(inode->i_sb,
+                                                       "clm-6004",
+                                                       "convert tail failed "
+                                                       "inode %lu, error %d",
+                                                       inode->i_ino,
+                                                       retval);
                                        if (allocated_block_nr) {
                                                /* the bitmap, the super, and the stat data == 3 */
                                                if (!th)
@@ -984,7 +986,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
 
                /* this loop could log more blocks than we had originally asked
                 ** for.  So, we have to allow the transaction to end if it is
-                ** too big or too full.  Update the inode so things are 
+                ** too big or too full.  Update the inode so things are
                 ** consistent if we crash before the function returns
                 **
                 ** release the path so that anybody waiting on the path before
@@ -995,7 +997,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
                        if (retval)
                                goto failure;
                }
-               /* inserting indirect pointers for a hole can take a 
+               /* inserting indirect pointers for a hole can take a
                 ** long time.  reschedule if needed
                 */
                cond_resched();
@@ -1006,8 +1008,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
                        goto failure;
                }
                if (retval == POSITION_FOUND) {
-                       reiserfs_warning(inode->i_sb,
-                                        "vs-825: reiserfs_get_block: "
+                       reiserfs_warning(inode->i_sb, "vs-825",
                                         "%K should not be found", &key);
                        retval = -EEXIST;
                        if (allocated_block_nr)
@@ -1299,8 +1300,7 @@ static void update_stat_data(struct treepath *path, struct inode *inode,
        ih = PATH_PITEM_HEAD(path);
 
        if (!is_statdata_le_ih(ih))
-               reiserfs_panic(inode->i_sb,
-                              "vs-13065: update_stat_data: key %k, found item %h",
+               reiserfs_panic(inode->i_sb, "vs-13065", "key %k, found item %h",
                               INODE_PKEY(inode), ih);
 
        if (stat_data_v1(ih)) {
@@ -1332,10 +1332,9 @@ void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th,
                /* look for the object's stat data */
                retval = search_item(inode->i_sb, &key, &path);
                if (retval == IO_ERROR) {
-                       reiserfs_warning(inode->i_sb,
-                                        "vs-13050: reiserfs_update_sd: "
-                                        "i/o failure occurred trying to update %K stat data",
-                                        &key);
+                       reiserfs_error(inode->i_sb, "vs-13050",
+                                      "i/o failure occurred trying to "
+                                      "update %K stat data", &key);
                        return;
                }
                if (retval == ITEM_NOT_FOUND) {
@@ -1345,9 +1344,9 @@ void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th,
                                /*reiserfs_warning (inode->i_sb, "vs-13050: reiserfs_update_sd: i_nlink == 0, stat data not found"); */
                                return;
                        }
-                       reiserfs_warning(inode->i_sb,
-                                        "vs-13060: reiserfs_update_sd: "
-                                        "stat data of object %k (nlink == %d) not found (pos %d)",
+                       reiserfs_warning(inode->i_sb, "vs-13060",
+                                        "stat data of object %k (nlink == %d) "
+                                        "not found (pos %d)",
                                         INODE_PKEY(inode), inode->i_nlink,
                                         pos);
                        reiserfs_check_path(&path);
@@ -1424,10 +1423,9 @@ void reiserfs_read_locked_inode(struct inode *inode,
        /* look for the object's stat data */
        retval = search_item(inode->i_sb, &key, &path_to_sd);
        if (retval == IO_ERROR) {
-               reiserfs_warning(inode->i_sb,
-                                "vs-13070: reiserfs_read_locked_inode: "
-                                "i/o failure occurred trying to find stat data of %K",
-                                &key);
+               reiserfs_error(inode->i_sb, "vs-13070",
+                              "i/o failure occurred trying to find "
+                              "stat data of %K", &key);
                reiserfs_make_bad_inode(inode);
                return;
        }
@@ -1446,7 +1444,7 @@ void reiserfs_read_locked_inode(struct inode *inode,
           update sd on unlink all that is required is to check for nlink
           here. This bug was first found by Sizif when debugging
           SquidNG/Butterfly, forgotten, and found again after Philippe
-          Gramoulle <philippe.gramoulle@mmania.com> reproduced it. 
+          Gramoulle <philippe.gramoulle@mmania.com> reproduced it.
 
           More logical fix would require changes in fs/inode.c:iput() to
           remove inode from hash-table _after_ fs cleaned disk stuff up and
@@ -1457,8 +1455,7 @@ void reiserfs_read_locked_inode(struct inode *inode,
           during mount (fs/reiserfs/super.c:finish_unfinished()). */
        if ((inode->i_nlink == 0) &&
            !REISERFS_SB(inode->i_sb)->s_is_unlinked_ok) {
-               reiserfs_warning(inode->i_sb,
-                                "vs-13075: reiserfs_read_locked_inode: "
+               reiserfs_warning(inode->i_sb, "vs-13075",
                                 "dead inode read from disk %K. "
                                 "This is likely to be race with knfsd. Ignore",
                                 &key);
@@ -1555,7 +1552,7 @@ struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
         */
        if (fh_type > fh_len) {
                if (fh_type != 6 || fh_len != 5)
-                       reiserfs_warning(sb,
+                       reiserfs_warning(sb, "reiserfs-13077",
                                "nfsd/reiserfs, fhtype=%d, len=%d - odd",
                                fh_type, fh_len);
                fh_type = 5;
@@ -1622,7 +1619,7 @@ int reiserfs_write_inode(struct inode *inode, int do_sync)
        if (inode->i_sb->s_flags & MS_RDONLY)
                return -EROFS;
        /* memory pressure can sometimes initiate write_inode calls with sync == 1,
-        ** these cases are just when the system needs ram, not when the 
+        ** these cases are just when the system needs ram, not when the
         ** inode needs to reach disk for safety, and they can safely be
         ** ignored because the altered inode has already been logged.
         */
@@ -1680,13 +1677,13 @@ static int reiserfs_new_directory(struct reiserfs_transaction_handle *th,
        /* look for place in the tree for new item */
        retval = search_item(sb, &key, path);
        if (retval == IO_ERROR) {
-               reiserfs_warning(sb, "vs-13080: reiserfs_new_directory: "
-                                "i/o failure occurred creating new directory");
+               reiserfs_error(sb, "vs-13080",
+                              "i/o failure occurred creating new directory");
                return -EIO;
        }
        if (retval == ITEM_FOUND) {
                pathrelse(path);
-               reiserfs_warning(sb, "vs-13070: reiserfs_new_directory: "
+               reiserfs_warning(sb, "vs-13070",
                                 "object with this key exists (%k)",
                                 &(ih->ih_key));
                return -EEXIST;
@@ -1720,13 +1717,13 @@ static int reiserfs_new_symlink(struct reiserfs_transaction_handle *th, struct i
        /* look for place in the tree for new item */
        retval = search_item(sb, &key, path);
        if (retval == IO_ERROR) {
-               reiserfs_warning(sb, "vs-13080: reiserfs_new_symlinik: "
-                                "i/o failure occurred creating new symlink");
+               reiserfs_error(sb, "vs-13080",
+                              "i/o failure occurred creating new symlink");
                return -EIO;
        }
        if (retval == ITEM_FOUND) {
                pathrelse(path);
-               reiserfs_warning(sb, "vs-13080: reiserfs_new_symlink: "
+               reiserfs_warning(sb, "vs-13080",
                                 "object with this key exists (%k)",
                                 &(ih->ih_key));
                return -EEXIST;
@@ -1739,7 +1736,7 @@ static int reiserfs_new_symlink(struct reiserfs_transaction_handle *th, struct i
 /* inserts the stat data into the tree, and then calls
    reiserfs_new_directory (to insert ".", ".." item if new object is
    directory) or reiserfs_new_symlink (to insert symlink body if new
-   object is symlink) or nothing (if new object is regular file) 
+   object is symlink) or nothing (if new object is regular file)
 
    NOTE! uid and gid must already be set in the inode.  If we return
    non-zero due to an error, we have to drop the quota previously allocated
@@ -1747,10 +1744,11 @@ static int reiserfs_new_symlink(struct reiserfs_transaction_handle *th, struct i
    if we return non-zero, we also end the transaction.  */
 int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
                       struct inode *dir, int mode, const char *symname,
-                      /* 0 for regular, EMTRY_DIR_SIZE for dirs, 
+                      /* 0 for regular, EMTRY_DIR_SIZE for dirs,
                          strlen (symname) for symlinks) */
                       loff_t i_size, struct dentry *dentry,
-                      struct inode *inode)
+                      struct inode *inode,
+                      struct reiserfs_security_handle *security)
 {
        struct super_block *sb;
        struct reiserfs_iget_args args;
@@ -1796,7 +1794,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
                goto out_bad_inode;
        }
        if (old_format_only(sb))
-               /* not a perfect generation count, as object ids can be reused, but 
+               /* not a perfect generation count, as object ids can be reused, but
                 ** this is as good as reiserfs can do right now.
                 ** note that the private part of inode isn't filled in yet, we have
                 ** to use the directory.
@@ -1917,9 +1915,8 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
                goto out_inserted_sd;
        }
 
-       /* XXX CHECK THIS */
        if (reiserfs_posixacl(inode->i_sb)) {
-               retval = reiserfs_inherit_default_acl(dir, dentry, inode);
+               retval = reiserfs_inherit_default_acl(th, dir, dentry, inode);
                if (retval) {
                        err = retval;
                        reiserfs_check_path(&path_to_key);
@@ -1927,10 +1924,23 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
                        goto out_inserted_sd;
                }
        } else if (inode->i_sb->s_flags & MS_POSIXACL) {
-               reiserfs_warning(inode->i_sb, "ACLs aren't enabled in the fs, "
+               reiserfs_warning(inode->i_sb, "jdm-13090",
+                                "ACLs aren't enabled in the fs, "
                                 "but vfs thinks they are!");
-       } else if (is_reiserfs_priv_object(dir)) {
-               reiserfs_mark_inode_private(inode);
+       } else if (IS_PRIVATE(dir))
+               inode->i_flags |= S_PRIVATE;
+
+       if (security->name) {
+               retval = reiserfs_security_write(th, inode, security);
+               if (retval) {
+                       err = retval;
+                       reiserfs_check_path(&path_to_key);
+                       retval = journal_end(th, th->t_super,
+                                            th->t_blocks_allocated);
+                       if (retval)
+                               err = retval;
+                       goto out_inserted_sd;
+               }
        }
 
        reiserfs_update_sd(th, inode);
@@ -1960,19 +1970,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
        inode->i_nlink = 0;
        th->t_trans_id = 0;     /* so the caller can't use this handle later */
        unlock_new_inode(inode); /* OK to do even if we hadn't locked it */
-
-       /* If we were inheriting an ACL, we need to release the lock so that
-        * iput doesn't deadlock in reiserfs_delete_xattrs. The locking
-        * code really needs to be reworked, but this will take care of it
-        * for now. -jeffm */
-#ifdef CONFIG_REISERFS_FS_POSIX_ACL
-       if (REISERFS_I(dir)->i_acl_default && !IS_ERR(REISERFS_I(dir)->i_acl_default)) {
-               reiserfs_write_unlock_xattrs(dir->i_sb);
-               iput(inode);
-               reiserfs_write_lock_xattrs(dir->i_sb);
-       } else
-#endif
-               iput(inode);
+       iput(inode);
        return err;
 }
 
@@ -1989,7 +1987,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
 **
 ** on failure, nonzero is returned, page_result and bh_result are untouched.
 */
-static int grab_tail_page(struct inode *p_s_inode,
+static int grab_tail_page(struct inode *inode,
                          struct page **page_result,
                          struct buffer_head **bh_result)
 {
@@ -1997,11 +1995,11 @@ static int grab_tail_page(struct inode *p_s_inode,
        /* we want the page with the last byte in the file,
         ** not the page that will hold the next byte for appending
         */
-       unsigned long index = (p_s_inode->i_size - 1) >> PAGE_CACHE_SHIFT;
+       unsigned long index = (inode->i_size - 1) >> PAGE_CACHE_SHIFT;
        unsigned long pos = 0;
        unsigned long start = 0;
-       unsigned long blocksize = p_s_inode->i_sb->s_blocksize;
-       unsigned long offset = (p_s_inode->i_size) & (PAGE_CACHE_SIZE - 1);
+       unsigned long blocksize = inode->i_sb->s_blocksize;
+       unsigned long offset = (inode->i_size) & (PAGE_CACHE_SIZE - 1);
        struct buffer_head *bh;
        struct buffer_head *head;
        struct page *page;
@@ -2015,7 +2013,7 @@ static int grab_tail_page(struct inode *p_s_inode,
        if ((offset & (blocksize - 1)) == 0) {
                return -ENOENT;
        }
-       page = grab_cache_page(p_s_inode->i_mapping, index);
+       page = grab_cache_page(inode->i_mapping, index);
        error = -ENOMEM;
        if (!page) {
                goto out;
@@ -2044,10 +2042,8 @@ static int grab_tail_page(struct inode *p_s_inode,
                 ** I've screwed up the code to find the buffer, or the code to
                 ** call prepare_write
                 */
-               reiserfs_warning(p_s_inode->i_sb,
-                                "clm-6000: error reading block %lu on dev %s",
-                                bh->b_blocknr,
-                                reiserfs_bdevname(p_s_inode->i_sb));
+               reiserfs_error(inode->i_sb, "clm-6000",
+                              "error reading block %lu", bh->b_blocknr);
                error = -EIO;
                goto unlock;
        }
@@ -2069,57 +2065,58 @@ static int grab_tail_page(struct inode *p_s_inode,
 **
 ** some code taken from block_truncate_page
 */
-int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps)
+int reiserfs_truncate_file(struct inode *inode, int update_timestamps)
 {
        struct reiserfs_transaction_handle th;
        /* we want the offset for the first byte after the end of the file */
-       unsigned long offset = p_s_inode->i_size & (PAGE_CACHE_SIZE - 1);
-       unsigned blocksize = p_s_inode->i_sb->s_blocksize;
+       unsigned long offset = inode->i_size & (PAGE_CACHE_SIZE - 1);
+       unsigned blocksize = inode->i_sb->s_blocksize;
        unsigned length;
        struct page *page = NULL;
        int error;
        struct buffer_head *bh = NULL;
        int err2;
 
-       reiserfs_write_lock(p_s_inode->i_sb);
+       reiserfs_write_lock(inode->i_sb);
 
-       if (p_s_inode->i_size > 0) {
-               if ((error = grab_tail_page(p_s_inode, &page, &bh))) {
-                       // -ENOENT means we truncated past the end of the file, 
+       if (inode->i_size > 0) {
+               error = grab_tail_page(inode, &page, &bh);
+               if (error) {
+                       // -ENOENT means we truncated past the end of the file,
                        // and get_block_create_0 could not find a block to read in,
                        // which is ok.
                        if (error != -ENOENT)
-                               reiserfs_warning(p_s_inode->i_sb,
-                                                "clm-6001: grab_tail_page failed %d",
-                                                error);
+                               reiserfs_error(inode->i_sb, "clm-6001",
+                                              "grab_tail_page failed %d",
+                                              error);
                        page = NULL;
                        bh = NULL;
                }
        }
 
-       /* so, if page != NULL, we have a buffer head for the offset at 
-        ** the end of the file. if the bh is mapped, and bh->b_blocknr != 0, 
-        ** then we have an unformatted node.  Otherwise, we have a direct item, 
-        ** and no zeroing is required on disk.  We zero after the truncate, 
-        ** because the truncate might pack the item anyway 
+       /* so, if page != NULL, we have a buffer head for the offset at
+        ** the end of the file. if the bh is mapped, and bh->b_blocknr != 0,
+        ** then we have an unformatted node.  Otherwise, we have a direct item,
+        ** and no zeroing is required on disk.  We zero after the truncate,
+        ** because the truncate might pack the item anyway
         ** (it will unmap bh if it packs).
         */
        /* it is enough to reserve space in transaction for 2 balancings:
           one for "save" link adding and another for the first
           cut_from_item. 1 is for update_sd */
-       error = journal_begin(&th, p_s_inode->i_sb,
+       error = journal_begin(&th, inode->i_sb,
                              JOURNAL_PER_BALANCE_CNT * 2 + 1);
        if (error)
                goto out;
-       reiserfs_update_inode_transaction(p_s_inode);
+       reiserfs_update_inode_transaction(inode);
        if (update_timestamps)
                /* we are doing real truncate: if the system crashes before the last
                   transaction of truncating gets committed - on reboot the file
                   either appears truncated properly or not truncated at all */
-               add_save_link(&th, p_s_inode, 1);
-       err2 = reiserfs_do_truncate(&th, p_s_inode, page, update_timestamps);
+               add_save_link(&th, inode, 1);
+       err2 = reiserfs_do_truncate(&th, inode, page, update_timestamps);
        error =
-           journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1);
+           journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1);
        if (error)
                goto out;
 
@@ -2130,7 +2127,7 @@ int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps)
        }
        
        if (update_timestamps) {
-               error = remove_save_link(p_s_inode, 1 /* truncate */ );
+               error = remove_save_link(inode, 1 /* truncate */);
                if (error)
                        goto out;
        }
@@ -2149,14 +2146,14 @@ int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps)
                page_cache_release(page);
        }
 
-       reiserfs_write_unlock(p_s_inode->i_sb);
+       reiserfs_write_unlock(inode->i_sb);
        return 0;
       out:
        if (page) {
                unlock_page(page);
                page_cache_release(page);
        }
-       reiserfs_write_unlock(p_s_inode->i_sb);
+       reiserfs_write_unlock(inode->i_sb);
        return error;
 }
 
@@ -2208,9 +2205,8 @@ static int map_block_for_writepage(struct inode *inode,
        /* we've found an unformatted node */
        if (indirect_item_found(retval, ih)) {
                if (bytes_copied > 0) {
-                       reiserfs_warning(inode->i_sb,
-                                        "clm-6002: bytes_copied %d",
-                                        bytes_copied);
+                       reiserfs_warning(inode->i_sb, "clm-6002",
+                                        "bytes_copied %d", bytes_copied);
                }
                if (!get_block_num(item, pos_in_item)) {
                        /* crap, we are writing to a hole */
@@ -2267,9 +2263,8 @@ static int map_block_for_writepage(struct inode *inode,
                        goto research;
                }
        } else {
-               reiserfs_warning(inode->i_sb,
-                                "clm-6003: bad item inode %lu, device %s",
-                                inode->i_ino, reiserfs_bdevname(inode->i_sb));
+               reiserfs_warning(inode->i_sb, "clm-6003",
+                                "bad item inode %lu", inode->i_ino);
                retval = -EIO;
                goto out;
        }
@@ -2312,8 +2307,8 @@ static int map_block_for_writepage(struct inode *inode,
        return retval;
 }
 
-/* 
- * mason@suse.com: updated in 2.5.54 to follow the same general io 
+/*
+ * mason@suse.com: updated in 2.5.54 to follow the same general io
  * start/recovery path as __block_write_full_page, along with special
  * code to handle reiserfs tails.
  */
@@ -2453,7 +2448,7 @@ static int reiserfs_write_full_page(struct page *page,
        unlock_page(page);
 
        /*
-        * since any buffer might be the only dirty buffer on the page, 
+        * since any buffer might be the only dirty buffer on the page,
         * the first submit_bh can bring the page out of writeback.
         * be careful with the buffers.
         */
@@ -2472,8 +2467,8 @@ static int reiserfs_write_full_page(struct page *page,
        if (nr == 0) {
                /*
                 * if this page only had a direct item, it is very possible for
-                * no io to be required without there being an error.  Or, 
-                * someone else could have locked them and sent them down the 
+                * no io to be required without there being an error.  Or,
+                * someone else could have locked them and sent them down the
                 * pipe without locking the page
                 */
                bh = head;
@@ -2492,7 +2487,7 @@ static int reiserfs_write_full_page(struct page *page,
 
       fail:
        /* catches various errors, we need to make sure any valid dirty blocks
-        * get to the media.  The page is currently locked and not marked for 
+        * get to the media.  The page is currently locked and not marked for
         * writeback
         */
        ClearPageUptodate(page);
index 830332021ed47bd33e5dca5d903f5725db1ba7c5..0ccc3fdda7bfb7d5d00e59e8b26e74a0331e6d3c 100644 (file)
@@ -189,7 +189,7 @@ int reiserfs_unpack(struct inode *inode, struct file *filp)
        }
 
        /* we unpack by finding the page with the tail, and calling
-        ** reiserfs_prepare_write on that page.  This will force a 
+        ** reiserfs_prepare_write on that page.  This will force a
         ** reiserfs_get_block to unpack the tail for us.
         */
        index = inode->i_size >> PAGE_CACHE_SHIFT;
index 9475557ab499434b8c7d9e74a2abebd2114d8d62..72cb1cc51b87d3ab987eb97f5cf09c3d306f3e40 100644 (file)
@@ -97,7 +97,8 @@ static int sd_unit_num(struct virtual_item *vi)
 
 static void sd_print_vi(struct virtual_item *vi)
 {
-       reiserfs_warning(NULL, "STATDATA, index %d, type 0x%x, %h",
+       reiserfs_warning(NULL, "reiserfs-16100",
+                        "STATDATA, index %d, type 0x%x, %h",
                         vi->vi_index, vi->vi_type, vi->vi_ih);
 }
 
@@ -190,7 +191,8 @@ static int direct_unit_num(struct virtual_item *vi)
 
 static void direct_print_vi(struct virtual_item *vi)
 {
-       reiserfs_warning(NULL, "DIRECT, index %d, type 0x%x, %h",
+       reiserfs_warning(NULL, "reiserfs-16101",
+                        "DIRECT, index %d, type 0x%x, %h",
                         vi->vi_index, vi->vi_type, vi->vi_ih);
 }
 
@@ -278,7 +280,7 @@ static void indirect_print_item(struct item_head *ih, char *item)
        unp = (__le32 *) item;
 
        if (ih_item_len(ih) % UNFM_P_SIZE)
-               reiserfs_warning(NULL, "indirect_print_item: invalid item len");
+               reiserfs_warning(NULL, "reiserfs-16102", "invalid item len");
 
        printk("%d pointers\n[ ", (int)I_UNFM_NUM(ih));
        for (j = 0; j < I_UNFM_NUM(ih); j++) {
@@ -334,7 +336,8 @@ static int indirect_unit_num(struct virtual_item *vi)
 
 static void indirect_print_vi(struct virtual_item *vi)
 {
-       reiserfs_warning(NULL, "INDIRECT, index %d, type 0x%x, %h",
+       reiserfs_warning(NULL, "reiserfs-16103",
+                        "INDIRECT, index %d, type 0x%x, %h",
                         vi->vi_index, vi->vi_type, vi->vi_ih);
 }
 
@@ -359,7 +362,7 @@ static struct item_operations indirect_ops = {
 
 static int direntry_bytes_number(struct item_head *ih, int block_size)
 {
-       reiserfs_warning(NULL, "vs-16090: direntry_bytes_number: "
+       reiserfs_warning(NULL, "vs-16090",
                         "bytes number is asked for direntry");
        return 0;
 }
@@ -514,8 +517,9 @@ static int direntry_create_vi(struct virtual_node *vn,
                    ((is_affected
                      && (vn->vn_mode == M_PASTE
                          || vn->vn_mode == M_CUT)) ? insert_size : 0)) {
-                       reiserfs_panic(NULL,
-                                      "vs-8025: set_entry_sizes: (mode==%c, insert_size==%d), invalid length of directory item",
+                       reiserfs_panic(NULL, "vs-8025", "(mode==%c, "
+                                      "insert_size==%d), invalid length of "
+                                      "directory item",
                                       vn->vn_mode, insert_size);
                }
        }
@@ -546,7 +550,8 @@ static int direntry_check_left(struct virtual_item *vi, int free,
        }
 
        if (entries == dir_u->entry_count) {
-               reiserfs_panic(NULL, "free space %d, entry_count %d\n", free,
+               reiserfs_panic(NULL, "item_ops-1",
+                              "free space %d, entry_count %d", free,
                               dir_u->entry_count);
        }
 
@@ -614,7 +619,8 @@ static void direntry_print_vi(struct virtual_item *vi)
        int i;
        struct direntry_uarea *dir_u = vi->vi_uarea;
 
-       reiserfs_warning(NULL, "DIRENTRY, index %d, type 0x%x, %h, flags 0x%x",
+       reiserfs_warning(NULL, "reiserfs-16104",
+                        "DIRENTRY, index %d, type 0x%x, %h, flags 0x%x",
                         vi->vi_index, vi->vi_type, vi->vi_ih, dir_u->flags);
        printk("%d entries: ", dir_u->entry_count);
        for (i = 0; i < dir_u->entry_count; i++)
@@ -642,43 +648,43 @@ static struct item_operations direntry_ops = {
 //
 static int errcatch_bytes_number(struct item_head *ih, int block_size)
 {
-       reiserfs_warning(NULL,
-                        "green-16001: Invalid item type observed, run fsck ASAP");
+       reiserfs_warning(NULL, "green-16001",
+                        "Invalid item type observed, run fsck ASAP");
        return 0;
 }
 
 static void errcatch_decrement_key(struct cpu_key *key)
 {
-       reiserfs_warning(NULL,
-                        "green-16002: Invalid item type observed, run fsck ASAP");
+       reiserfs_warning(NULL, "green-16002",
+                        "Invalid item type observed, run fsck ASAP");
 }
 
 static int errcatch_is_left_mergeable(struct reiserfs_key *key,
                                      unsigned long bsize)
 {
-       reiserfs_warning(NULL,
-                        "green-16003: Invalid item type observed, run fsck ASAP");
+       reiserfs_warning(NULL, "green-16003",
+                        "Invalid item type observed, run fsck ASAP");
        return 0;
 }
 
 static void errcatch_print_item(struct item_head *ih, char *item)
 {
-       reiserfs_warning(NULL,
-                        "green-16004: Invalid item type observed, run fsck ASAP");
+       reiserfs_warning(NULL, "green-16004",
+                        "Invalid item type observed, run fsck ASAP");
 }
 
 static void errcatch_check_item(struct item_head *ih, char *item)
 {
-       reiserfs_warning(NULL,
-                        "green-16005: Invalid item type observed, run fsck ASAP");
+       reiserfs_warning(NULL, "green-16005",
+                        "Invalid item type observed, run fsck ASAP");
 }
 
 static int errcatch_create_vi(struct virtual_node *vn,
                              struct virtual_item *vi,
                              int is_affected, int insert_size)
 {
-       reiserfs_warning(NULL,
-                        "green-16006: Invalid item type observed, run fsck ASAP");
+       reiserfs_warning(NULL, "green-16006",
+                        "Invalid item type observed, run fsck ASAP");
        return 0;               // We might return -1 here as well, but it won't help as create_virtual_node() from where
        // this operation is called from is of return type void.
 }
@@ -686,36 +692,36 @@ static int errcatch_create_vi(struct virtual_node *vn,
 static int errcatch_check_left(struct virtual_item *vi, int free,
                               int start_skip, int end_skip)
 {
-       reiserfs_warning(NULL,
-                        "green-16007: Invalid item type observed, run fsck ASAP");
+       reiserfs_warning(NULL, "green-16007",
+                        "Invalid item type observed, run fsck ASAP");
        return -1;
 }
 
 static int errcatch_check_right(struct virtual_item *vi, int free)
 {
-       reiserfs_warning(NULL,
-                        "green-16008: Invalid item type observed, run fsck ASAP");
+       reiserfs_warning(NULL, "green-16008",
+                        "Invalid item type observed, run fsck ASAP");
        return -1;
 }
 
 static int errcatch_part_size(struct virtual_item *vi, int first, int count)
 {
-       reiserfs_warning(NULL,
-                        "green-16009: Invalid item type observed, run fsck ASAP");
+       reiserfs_warning(NULL, "green-16009",
+                        "Invalid item type observed, run fsck ASAP");
        return 0;
 }
 
 static int errcatch_unit_num(struct virtual_item *vi)
 {
-       reiserfs_warning(NULL,
-                        "green-16010: Invalid item type observed, run fsck ASAP");
+       reiserfs_warning(NULL, "green-16010",
+                        "Invalid item type observed, run fsck ASAP");
        return 0;
 }
 
 static void errcatch_print_vi(struct virtual_item *vi)
 {
-       reiserfs_warning(NULL,
-                        "green-16011: Invalid item type observed, run fsck ASAP");
+       reiserfs_warning(NULL, "green-16011",
+                        "Invalid item type observed, run fsck ASAP");
 }
 
 static struct item_operations errcatch_ops = {
index 9643c3bbeb3b611d3817bc17698d76c5d54e89b5..77f5bb746bf073969140539752ee87dc8f4f0861 100644 (file)
@@ -1,36 +1,36 @@
 /*
 ** Write ahead logging implementation copyright Chris Mason 2000
 **
-** The background commits make this code very interelated, and 
+** The background commits make this code very interelated, and
 ** overly complex.  I need to rethink things a bit....The major players:
 **
-** journal_begin -- call with the number of blocks you expect to log.  
+** journal_begin -- call with the number of blocks you expect to log.
 **                  If the current transaction is too
-**                 old, it will block until the current transaction is 
+**                 old, it will block until the current transaction is
 **                 finished, and then start a new one.
-**                 Usually, your transaction will get joined in with 
+**                 Usually, your transaction will get joined in with
 **                  previous ones for speed.
 **
-** journal_join  -- same as journal_begin, but won't block on the current 
+** journal_join  -- same as journal_begin, but won't block on the current
 **                  transaction regardless of age.  Don't ever call
-**                  this.  Ever.  There are only two places it should be 
+**                  this.  Ever.  There are only two places it should be
 **                  called from, and they are both inside this file.
 **
-** journal_mark_dirty -- adds blocks into this transaction.  clears any flags 
+** journal_mark_dirty -- adds blocks into this transaction.  clears any flags
 **                       that might make them get sent to disk
-**                       and then marks them BH_JDirty.  Puts the buffer head 
-**                       into the current transaction hash.  
+**                       and then marks them BH_JDirty.  Puts the buffer head
+**                       into the current transaction hash.
 **
 ** journal_end -- if the current transaction is batchable, it does nothing
 **                   otherwise, it could do an async/synchronous commit, or
-**                   a full flush of all log and real blocks in the 
+**                   a full flush of all log and real blocks in the
 **                   transaction.
 **
-** flush_old_commits -- if the current transaction is too old, it is ended and 
-**                      commit blocks are sent to disk.  Forces commit blocks 
-**                      to disk for all backgrounded commits that have been 
+** flush_old_commits -- if the current transaction is too old, it is ended and
+**                      commit blocks are sent to disk.  Forces commit blocks
+**                      to disk for all backgrounded commits that have been
 **                      around too long.
-**                  -- Note, if you call this as an immediate flush from 
+**                  -- Note, if you call this as an immediate flush from
 **                     from within kupdate, it will ignore the immediate flag
 */
 
@@ -97,7 +97,7 @@ static int flush_commit_list(struct super_block *s,
                             struct reiserfs_journal_list *jl, int flushall);
 static int can_dirty(struct reiserfs_journal_cnode *cn);
 static int journal_join(struct reiserfs_transaction_handle *th,
-                       struct super_block *p_s_sb, unsigned long nblocks);
+                       struct super_block *sb, unsigned long nblocks);
 static int release_journal_dev(struct super_block *super,
                               struct reiserfs_journal *journal);
 static int dirty_one_transaction(struct super_block *s,
@@ -113,12 +113,12 @@ enum {
 };
 
 static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
-                             struct super_block *p_s_sb,
+                             struct super_block *sb,
                              unsigned long nblocks, int join);
 
-static void init_journal_hash(struct super_block *p_s_sb)
+static void init_journal_hash(struct super_block *sb)
 {
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
        memset(journal->j_hash_table, 0,
               JOURNAL_HASH_SIZE * sizeof(struct reiserfs_journal_cnode *));
 }
@@ -145,7 +145,7 @@ static void disable_barrier(struct super_block *s)
 }
 
 static struct reiserfs_bitmap_node *allocate_bitmap_node(struct super_block
-                                                        *p_s_sb)
+                                                        *sb)
 {
        struct reiserfs_bitmap_node *bn;
        static int id;
@@ -154,7 +154,7 @@ static struct reiserfs_bitmap_node *allocate_bitmap_node(struct super_block
        if (!bn) {
                return NULL;
        }
-       bn->data = kzalloc(p_s_sb->s_blocksize, GFP_NOFS);
+       bn->data = kzalloc(sb->s_blocksize, GFP_NOFS);
        if (!bn->data) {
                kfree(bn);
                return NULL;
@@ -164,9 +164,9 @@ static struct reiserfs_bitmap_node *allocate_bitmap_node(struct super_block
        return bn;
 }
 
-static struct reiserfs_bitmap_node *get_bitmap_node(struct super_block *p_s_sb)
+static struct reiserfs_bitmap_node *get_bitmap_node(struct super_block *sb)
 {
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
        struct reiserfs_bitmap_node *bn = NULL;
        struct list_head *entry = journal->j_bitmap_nodes.next;
 
@@ -176,21 +176,21 @@ static struct reiserfs_bitmap_node *get_bitmap_node(struct super_block *p_s_sb)
        if (entry != &journal->j_bitmap_nodes) {
                bn = list_entry(entry, struct reiserfs_bitmap_node, list);
                list_del(entry);
-               memset(bn->data, 0, p_s_sb->s_blocksize);
+               memset(bn->data, 0, sb->s_blocksize);
                journal->j_free_bitmap_nodes--;
                return bn;
        }
-       bn = allocate_bitmap_node(p_s_sb);
+       bn = allocate_bitmap_node(sb);
        if (!bn) {
                yield();
                goto repeat;
        }
        return bn;
 }
-static inline void free_bitmap_node(struct super_block *p_s_sb,
+static inline void free_bitmap_node(struct super_block *sb,
                                    struct reiserfs_bitmap_node *bn)
 {
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
        journal->j_used_bitmap_nodes--;
        if (journal->j_free_bitmap_nodes > REISERFS_MAX_BITMAP_NODES) {
                kfree(bn->data);
@@ -201,46 +201,46 @@ static inline void free_bitmap_node(struct super_block *p_s_sb,
        }
 }
 
-static void allocate_bitmap_nodes(struct super_block *p_s_sb)
+static void allocate_bitmap_nodes(struct super_block *sb)
 {
        int i;
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
        struct reiserfs_bitmap_node *bn = NULL;
        for (i = 0; i < REISERFS_MIN_BITMAP_NODES; i++) {
-               bn = allocate_bitmap_node(p_s_sb);
+               bn = allocate_bitmap_node(sb);
                if (bn) {
                        list_add(&bn->list, &journal->j_bitmap_nodes);
                        journal->j_free_bitmap_nodes++;
                } else {
-                       break;  // this is ok, we'll try again when more are needed 
+                       break;  /* this is ok, we'll try again when more are needed */
                }
        }
 }
 
-static int set_bit_in_list_bitmap(struct super_block *p_s_sb,
+static int set_bit_in_list_bitmap(struct super_block *sb,
                                  b_blocknr_t block,
                                  struct reiserfs_list_bitmap *jb)
 {
-       unsigned int bmap_nr = block / (p_s_sb->s_blocksize << 3);
-       unsigned int bit_nr = block % (p_s_sb->s_blocksize << 3);
+       unsigned int bmap_nr = block / (sb->s_blocksize << 3);
+       unsigned int bit_nr = block % (sb->s_blocksize << 3);
 
        if (!jb->bitmaps[bmap_nr]) {
-               jb->bitmaps[bmap_nr] = get_bitmap_node(p_s_sb);
+               jb->bitmaps[bmap_nr] = get_bitmap_node(sb);
        }
        set_bit(bit_nr, (unsigned long *)jb->bitmaps[bmap_nr]->data);
        return 0;
 }
 
-static void cleanup_bitmap_list(struct super_block *p_s_sb,
+static void cleanup_bitmap_list(struct super_block *sb,
                                struct reiserfs_list_bitmap *jb)
 {
        int i;
        if (jb->bitmaps == NULL)
                return;
 
-       for (i = 0; i < reiserfs_bmap_count(p_s_sb); i++) {
+       for (i = 0; i < reiserfs_bmap_count(sb); i++) {
                if (jb->bitmaps[i]) {
-                       free_bitmap_node(p_s_sb, jb->bitmaps[i]);
+                       free_bitmap_node(sb, jb->bitmaps[i]);
                        jb->bitmaps[i] = NULL;
                }
        }
@@ -249,7 +249,7 @@ static void cleanup_bitmap_list(struct super_block *p_s_sb,
 /*
 ** only call this on FS unmount.
 */
-static int free_list_bitmaps(struct super_block *p_s_sb,
+static int free_list_bitmaps(struct super_block *sb,
                             struct reiserfs_list_bitmap *jb_array)
 {
        int i;
@@ -257,16 +257,16 @@ static int free_list_bitmaps(struct super_block *p_s_sb,
        for (i = 0; i < JOURNAL_NUM_BITMAPS; i++) {
                jb = jb_array + i;
                jb->journal_list = NULL;
-               cleanup_bitmap_list(p_s_sb, jb);
+               cleanup_bitmap_list(sb, jb);
                vfree(jb->bitmaps);
                jb->bitmaps = NULL;
        }
        return 0;
 }
 
-static int free_bitmap_nodes(struct super_block *p_s_sb)
+static int free_bitmap_nodes(struct super_block *sb)
 {
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
        struct list_head *next = journal->j_bitmap_nodes.next;
        struct reiserfs_bitmap_node *bn;
 
@@ -283,10 +283,10 @@ static int free_bitmap_nodes(struct super_block *p_s_sb)
 }
 
 /*
-** get memory for JOURNAL_NUM_BITMAPS worth of bitmaps. 
+** get memory for JOURNAL_NUM_BITMAPS worth of bitmaps.
 ** jb_array is the array to be filled in.
 */
-int reiserfs_allocate_list_bitmaps(struct super_block *p_s_sb,
+int reiserfs_allocate_list_bitmaps(struct super_block *sb,
                                   struct reiserfs_list_bitmap *jb_array,
                                   unsigned int bmap_nr)
 {
@@ -300,30 +300,30 @@ int reiserfs_allocate_list_bitmaps(struct super_block *p_s_sb,
                jb->journal_list = NULL;
                jb->bitmaps = vmalloc(mem);
                if (!jb->bitmaps) {
-                       reiserfs_warning(p_s_sb,
-                                        "clm-2000, unable to allocate bitmaps for journal lists");
+                       reiserfs_warning(sb, "clm-2000", "unable to "
+                                        "allocate bitmaps for journal lists");
                        failed = 1;
                        break;
                }
                memset(jb->bitmaps, 0, mem);
        }
        if (failed) {
-               free_list_bitmaps(p_s_sb, jb_array);
+               free_list_bitmaps(sb, jb_array);
                return -1;
        }
        return 0;
 }
 
 /*
-** find an available list bitmap.  If you can't find one, flush a commit list 
+** find an available list bitmap.  If you can't find one, flush a commit list
 ** and try again
 */
-static struct reiserfs_list_bitmap *get_list_bitmap(struct super_block *p_s_sb,
+static struct reiserfs_list_bitmap *get_list_bitmap(struct super_block *sb,
                                                    struct reiserfs_journal_list
                                                    *jl)
 {
        int i, j;
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
        struct reiserfs_list_bitmap *jb = NULL;
 
        for (j = 0; j < (JOURNAL_NUM_BITMAPS * 3); j++) {
@@ -331,7 +331,7 @@ static struct reiserfs_list_bitmap *get_list_bitmap(struct super_block *p_s_sb,
                journal->j_list_bitmap_index = (i + 1) % JOURNAL_NUM_BITMAPS;
                jb = journal->j_list_bitmap + i;
                if (journal->j_list_bitmap[i].journal_list) {
-                       flush_commit_list(p_s_sb,
+                       flush_commit_list(sb,
                                          journal->j_list_bitmap[i].
                                          journal_list, 1);
                        if (!journal->j_list_bitmap[i].journal_list) {
@@ -348,7 +348,7 @@ static struct reiserfs_list_bitmap *get_list_bitmap(struct super_block *p_s_sb,
        return jb;
 }
 
-/* 
+/*
 ** allocates a new chunk of X nodes, and links them all together as a list.
 ** Uses the cnode->next and cnode->prev pointers
 ** returns NULL on failure
@@ -376,14 +376,14 @@ static struct reiserfs_journal_cnode *allocate_cnodes(int num_cnodes)
 }
 
 /*
-** pulls a cnode off the free list, or returns NULL on failure 
+** pulls a cnode off the free list, or returns NULL on failure
 */
-static struct reiserfs_journal_cnode *get_cnode(struct super_block *p_s_sb)
+static struct reiserfs_journal_cnode *get_cnode(struct super_block *sb)
 {
        struct reiserfs_journal_cnode *cn;
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
 
-       reiserfs_check_lock_depth(p_s_sb, "get_cnode");
+       reiserfs_check_lock_depth(sb, "get_cnode");
 
        if (journal->j_cnode_free <= 0) {
                return NULL;
@@ -403,14 +403,14 @@ static struct reiserfs_journal_cnode *get_cnode(struct super_block *p_s_sb)
 }
 
 /*
-** returns a cnode to the free list 
+** returns a cnode to the free list
 */
-static void free_cnode(struct super_block *p_s_sb,
+static void free_cnode(struct super_block *sb,
                       struct reiserfs_journal_cnode *cn)
 {
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
 
-       reiserfs_check_lock_depth(p_s_sb, "free_cnode");
+       reiserfs_check_lock_depth(sb, "free_cnode");
 
        journal->j_cnode_used--;
        journal->j_cnode_free++;
@@ -436,8 +436,8 @@ void reiserfs_check_lock_depth(struct super_block *sb, char *caller)
 {
 #ifdef CONFIG_SMP
        if (current->lock_depth < 0) {
-               reiserfs_panic(sb, "%s called without kernel lock held",
-                              caller);
+               reiserfs_panic(sb, "journal-1", "%s called without kernel "
+                              "lock held", caller);
        }
 #else
        ;
@@ -481,11 +481,11 @@ static inline struct reiserfs_journal_cnode *get_journal_hash_dev(struct
 ** reject it on the next call to reiserfs_in_journal
 **
 */
-int reiserfs_in_journal(struct super_block *p_s_sb,
+int reiserfs_in_journal(struct super_block *sb,
                        unsigned int bmap_nr, int bit_nr, int search_all,
                        b_blocknr_t * next_zero_bit)
 {
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
        struct reiserfs_journal_cnode *cn;
        struct reiserfs_list_bitmap *jb;
        int i;
@@ -493,14 +493,14 @@ int reiserfs_in_journal(struct super_block *p_s_sb,
 
        *next_zero_bit = 0;     /* always start this at zero. */
 
-       PROC_INFO_INC(p_s_sb, journal.in_journal);
+       PROC_INFO_INC(sb, journal.in_journal);
        /* If we aren't doing a search_all, this is a metablock, and it will be logged before use.
         ** if we crash before the transaction that freed it commits,  this transaction won't
         ** have committed either, and the block will never be written
         */
        if (search_all) {
                for (i = 0; i < JOURNAL_NUM_BITMAPS; i++) {
-                       PROC_INFO_INC(p_s_sb, journal.in_journal_bitmap);
+                       PROC_INFO_INC(sb, journal.in_journal_bitmap);
                        jb = journal->j_list_bitmap + i;
                        if (jb->journal_list && jb->bitmaps[bmap_nr] &&
                            test_bit(bit_nr,
@@ -510,28 +510,28 @@ int reiserfs_in_journal(struct super_block *p_s_sb,
                                    find_next_zero_bit((unsigned long *)
                                                       (jb->bitmaps[bmap_nr]->
                                                        data),
-                                                      p_s_sb->s_blocksize << 3,
+                                                      sb->s_blocksize << 3,
                                                       bit_nr + 1);
                                return 1;
                        }
                }
        }
 
-       bl = bmap_nr * (p_s_sb->s_blocksize << 3) + bit_nr;
+       bl = bmap_nr * (sb->s_blocksize << 3) + bit_nr;
        /* is it in any old transactions? */
        if (search_all
            && (cn =
-               get_journal_hash_dev(p_s_sb, journal->j_list_hash_table, bl))) {
+               get_journal_hash_dev(sb, journal->j_list_hash_table, bl))) {
                return 1;
        }
 
        /* is it in the current transaction.  This should never happen */
-       if ((cn = get_journal_hash_dev(p_s_sb, journal->j_hash_table, bl))) {
+       if ((cn = get_journal_hash_dev(sb, journal->j_hash_table, bl))) {
                BUG();
                return 1;
        }
 
-       PROC_INFO_INC(p_s_sb, journal.in_journal_reusable);
+       PROC_INFO_INC(sb, journal.in_journal_reusable);
        /* safe for reuse */
        return 0;
 }
@@ -553,16 +553,16 @@ static inline void insert_journal_hash(struct reiserfs_journal_cnode **table,
 }
 
 /* lock the current transaction */
-static inline void lock_journal(struct super_block *p_s_sb)
+static inline void lock_journal(struct super_block *sb)
 {
-       PROC_INFO_INC(p_s_sb, journal.lock_journal);
-       mutex_lock(&SB_JOURNAL(p_s_sb)->j_mutex);
+       PROC_INFO_INC(sb, journal.lock_journal);
+       mutex_lock(&SB_JOURNAL(sb)->j_mutex);
 }
 
 /* unlock the current transaction */
-static inline void unlock_journal(struct super_block *p_s_sb)
+static inline void unlock_journal(struct super_block *sb)
 {
-       mutex_unlock(&SB_JOURNAL(p_s_sb)->j_mutex);
+       mutex_unlock(&SB_JOURNAL(sb)->j_mutex);
 }
 
 static inline void get_journal_list(struct reiserfs_journal_list *jl)
@@ -574,7 +574,7 @@ static inline void put_journal_list(struct super_block *s,
                                    struct reiserfs_journal_list *jl)
 {
        if (jl->j_refcount < 1) {
-               reiserfs_panic(s, "trans id %lu, refcount at %d",
+               reiserfs_panic(s, "journal-2", "trans id %u, refcount at %d",
                               jl->j_trans_id, jl->j_refcount);
        }
        if (--jl->j_refcount == 0)
@@ -586,20 +586,20 @@ static inline void put_journal_list(struct super_block *s,
 ** it gets called by flush_commit_list, and cleans up any data stored about blocks freed during a
 ** transaction.
 */
-static void cleanup_freed_for_journal_list(struct super_block *p_s_sb,
+static void cleanup_freed_for_journal_list(struct super_block *sb,
                                           struct reiserfs_journal_list *jl)
 {
 
        struct reiserfs_list_bitmap *jb = jl->j_list_bitmap;
        if (jb) {
-               cleanup_bitmap_list(p_s_sb, jb);
+               cleanup_bitmap_list(sb, jb);
        }
        jl->j_list_bitmap->journal_list = NULL;
        jl->j_list_bitmap = NULL;
 }
 
 static int journal_list_still_alive(struct super_block *s,
-                                   unsigned long trans_id)
+                                   unsigned int trans_id)
 {
        struct reiserfs_journal *journal = SB_JOURNAL(s);
        struct list_head *entry = &journal->j_journal_list;
@@ -644,8 +644,8 @@ static void reiserfs_end_buffer_io_sync(struct buffer_head *bh, int uptodate)
        char b[BDEVNAME_SIZE];
 
        if (buffer_journaled(bh)) {
-               reiserfs_warning(NULL,
-                                "clm-2084: pinned buffer %lu:%s sent to disk",
+               reiserfs_warning(NULL, "clm-2084",
+                                "pinned buffer %lu:%s sent to disk",
                                 bh->b_blocknr, bdevname(bh->b_bdev, b));
        }
        if (uptodate)
@@ -933,9 +933,9 @@ static int flush_older_commits(struct super_block *s,
        struct reiserfs_journal_list *other_jl;
        struct reiserfs_journal_list *first_jl;
        struct list_head *entry;
-       unsigned long trans_id = jl->j_trans_id;
-       unsigned long other_trans_id;
-       unsigned long first_trans_id;
+       unsigned int trans_id = jl->j_trans_id;
+       unsigned int other_trans_id;
+       unsigned int first_trans_id;
 
       find_first:
        /*
@@ -1014,7 +1014,7 @@ static int flush_commit_list(struct super_block *s,
        int i;
        b_blocknr_t bn;
        struct buffer_head *tbh = NULL;
-       unsigned long trans_id = jl->j_trans_id;
+       unsigned int trans_id = jl->j_trans_id;
        struct reiserfs_journal *journal = SB_JOURNAL(s);
        int barrier = 0;
        int retval = 0;
@@ -1122,7 +1122,8 @@ static int flush_commit_list(struct super_block *s,
                        sync_dirty_buffer(tbh);
                if (unlikely(!buffer_uptodate(tbh))) {
 #ifdef CONFIG_REISERFS_CHECK
-                       reiserfs_warning(s, "journal-601, buffer write failed");
+                       reiserfs_warning(s, "journal-601",
+                                        "buffer write failed");
 #endif
                        retval = -EIO;
                }
@@ -1154,14 +1155,14 @@ static int flush_commit_list(struct super_block *s,
         * up propagating the write error out to the filesystem. */
        if (unlikely(!buffer_uptodate(jl->j_commit_bh))) {
 #ifdef CONFIG_REISERFS_CHECK
-               reiserfs_warning(s, "journal-615buffer write failed");
+               reiserfs_warning(s, "journal-615", "buffer write failed");
 #endif
                retval = -EIO;
        }
        bforget(jl->j_commit_bh);
        if (journal->j_last_commit_id != 0 &&
            (jl->j_trans_id - journal->j_last_commit_id) != 1) {
-               reiserfs_warning(s, "clm-2200last commit %lu, current %lu",
+               reiserfs_warning(s, "clm-2200", "last commit %lu, current %lu",
                                 journal->j_last_commit_id, jl->j_trans_id);
        }
        journal->j_last_commit_id = jl->j_trans_id;
@@ -1191,8 +1192,8 @@ static int flush_commit_list(struct super_block *s,
 }
 
 /*
-** flush_journal_list frequently needs to find a newer transaction for a given block.  This does that, or 
-** returns NULL if it can't find anything 
+** flush_journal_list frequently needs to find a newer transaction for a given block.  This does that, or
+** returns NULL if it can't find anything
 */
 static struct reiserfs_journal_list *find_newer_jl_for_cn(struct
                                                          reiserfs_journal_cnode
@@ -1236,11 +1237,11 @@ static void remove_journal_hash(struct super_block *,
 ** journal list for this transaction.  Aside from freeing the cnode, this also allows the
 ** block to be reallocated for data blocks if it had been deleted.
 */
-static void remove_all_from_journal_list(struct super_block *p_s_sb,
+static void remove_all_from_journal_list(struct super_block *sb,
                                         struct reiserfs_journal_list *jl,
                                         int debug)
 {
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
        struct reiserfs_journal_cnode *cn, *last;
        cn = jl->j_realblock;
 
@@ -1250,18 +1251,18 @@ static void remove_all_from_journal_list(struct super_block *p_s_sb,
        while (cn) {
                if (cn->blocknr != 0) {
                        if (debug) {
-                               reiserfs_warning(p_s_sb,
+                               reiserfs_warning(sb, "reiserfs-2201",
                                                 "block %u, bh is %d, state %ld",
                                                 cn->blocknr, cn->bh ? 1 : 0,
                                                 cn->state);
                        }
                        cn->state = 0;
-                       remove_journal_hash(p_s_sb, journal->j_list_hash_table,
+                       remove_journal_hash(sb, journal->j_list_hash_table,
                                            jl, cn->blocknr, 1);
                }
                last = cn;
                cn = cn->next;
-               free_cnode(p_s_sb, last);
+               free_cnode(sb, last);
        }
        jl->j_realblock = NULL;
 }
@@ -1273,12 +1274,12 @@ static void remove_all_from_journal_list(struct super_block *p_s_sb,
 ** called by flush_journal_list, before it calls remove_all_from_journal_list
 **
 */
-static int _update_journal_header_block(struct super_block *p_s_sb,
+static int _update_journal_header_block(struct super_block *sb,
                                        unsigned long offset,
-                                       unsigned long trans_id)
+                                       unsigned int trans_id)
 {
        struct reiserfs_journal_header *jh;
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
 
        if (reiserfs_is_journal_aborted(journal))
                return -EIO;
@@ -1288,8 +1289,8 @@ static int _update_journal_header_block(struct super_block *p_s_sb,
                        wait_on_buffer((journal->j_header_bh));
                        if (unlikely(!buffer_uptodate(journal->j_header_bh))) {
 #ifdef CONFIG_REISERFS_CHECK
-                               reiserfs_warning(p_s_sb,
-                                                "journal-699: buffer write failed");
+                               reiserfs_warning(sb, "journal-699",
+                                                "buffer write failed");
 #endif
                                return -EIO;
                        }
@@ -1302,49 +1303,49 @@ static int _update_journal_header_block(struct super_block *p_s_sb,
                jh->j_first_unflushed_offset = cpu_to_le32(offset);
                jh->j_mount_id = cpu_to_le32(journal->j_mount_id);
 
-               if (reiserfs_barrier_flush(p_s_sb)) {
+               if (reiserfs_barrier_flush(sb)) {
                        int ret;
                        lock_buffer(journal->j_header_bh);
                        ret = submit_barrier_buffer(journal->j_header_bh);
                        if (ret == -EOPNOTSUPP) {
                                set_buffer_uptodate(journal->j_header_bh);
-                               disable_barrier(p_s_sb);
+                               disable_barrier(sb);
                                goto sync;
                        }
                        wait_on_buffer(journal->j_header_bh);
-                       check_barrier_completion(p_s_sb, journal->j_header_bh);
+                       check_barrier_completion(sb, journal->j_header_bh);
                } else {
                      sync:
                        set_buffer_dirty(journal->j_header_bh);
                        sync_dirty_buffer(journal->j_header_bh);
                }
                if (!buffer_uptodate(journal->j_header_bh)) {
-                       reiserfs_warning(p_s_sb,
-                                        "journal-837: IO error during journal replay");
+                       reiserfs_warning(sb, "journal-837",
+                                        "IO error during journal replay");
                        return -EIO;
                }
        }
        return 0;
 }
 
-static int update_journal_header_block(struct super_block *p_s_sb,
+static int update_journal_header_block(struct super_block *sb,
                                       unsigned long offset,
-                                      unsigned long trans_id)
+                                      unsigned int trans_id)
 {
-       return _update_journal_header_block(p_s_sb, offset, trans_id);
+       return _update_journal_header_block(sb, offset, trans_id);
 }
 
-/* 
-** flush any and all journal lists older than you are 
+/*
+** flush any and all journal lists older than you are
 ** can only be called from flush_journal_list
 */
-static int flush_older_journal_lists(struct super_block *p_s_sb,
+static int flush_older_journal_lists(struct super_block *sb,
                                     struct reiserfs_journal_list *jl)
 {
        struct list_head *entry;
        struct reiserfs_journal_list *other_jl;
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
-       unsigned long trans_id = jl->j_trans_id;
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
+       unsigned int trans_id = jl->j_trans_id;
 
        /* we know we are the only ones flushing things, no extra race
         * protection is required.
@@ -1358,7 +1359,7 @@ static int flush_older_journal_lists(struct super_block *p_s_sb,
        if (other_jl->j_trans_id < trans_id) {
                BUG_ON(other_jl->j_refcount <= 0);
                /* do not flush all */
-               flush_journal_list(p_s_sb, other_jl, 0);
+               flush_journal_list(sb, other_jl, 0);
 
                /* other_jl is now deleted from the list */
                goto restart;
@@ -1381,8 +1382,8 @@ static void del_from_work_list(struct super_block *s,
 ** always set flushall to 1, unless you are calling from inside
 ** flush_journal_list
 **
-** IMPORTANT.  This can only be called while there are no journal writers, 
-** and the journal is locked.  That means it can only be called from 
+** IMPORTANT.  This can only be called while there are no journal writers,
+** and the journal is locked.  That means it can only be called from
 ** do_journal_end, or by journal_release
 */
 static int flush_journal_list(struct super_block *s,
@@ -1401,8 +1402,7 @@ static int flush_journal_list(struct super_block *s,
        BUG_ON(j_len_saved <= 0);
 
        if (atomic_read(&journal->j_wcount) != 0) {
-               reiserfs_warning(s,
-                                "clm-2048: flush_journal_list called with wcount %d",
+               reiserfs_warning(s, "clm-2048", "called with wcount %d",
                                 atomic_read(&journal->j_wcount));
        }
        BUG_ON(jl->j_trans_id == 0);
@@ -1416,8 +1416,7 @@ static int flush_journal_list(struct super_block *s,
 
        count = 0;
        if (j_len_saved > journal->j_trans_max) {
-               reiserfs_panic(s,
-                              "journal-715: flush_journal_list, length is %lu, trans id %lu\n",
+               reiserfs_panic(s, "journal-715", "length is %lu, trans id %lu",
                               j_len_saved, jl->j_trans_id);
                return 0;
        }
@@ -1430,7 +1429,7 @@ static int flush_journal_list(struct super_block *s,
                goto flush_older_and_return;
        }
 
-       /* start by putting the commit list on disk.  This will also flush 
+       /* start by putting the commit list on disk.  This will also flush
         ** the commit lists of any olders transactions
         */
        flush_commit_list(s, jl, 1);
@@ -1445,12 +1444,12 @@ static int flush_journal_list(struct super_block *s,
                goto flush_older_and_return;
        }
 
-       /* loop through each cnode, see if we need to write it, 
-        ** or wait on a more recent transaction, or just ignore it 
+       /* loop through each cnode, see if we need to write it,
+        ** or wait on a more recent transaction, or just ignore it
         */
        if (atomic_read(&(journal->j_wcount)) != 0) {
-               reiserfs_panic(s,
-                              "journal-844: panic journal list is flushing, wcount is not 0\n");
+               reiserfs_panic(s, "journal-844", "journal list is flushing, "
+                              "wcount is not 0");
        }
        cn = jl->j_realblock;
        while (cn) {
@@ -1474,8 +1473,8 @@ static int flush_journal_list(struct super_block *s,
                if (!pjl && cn->bh) {
                        saved_bh = cn->bh;
 
-                       /* we do this to make sure nobody releases the buffer while 
-                        ** we are working with it 
+                       /* we do this to make sure nobody releases the buffer while
+                        ** we are working with it
                         */
                        get_bh(saved_bh);
 
@@ -1498,8 +1497,8 @@ static int flush_journal_list(struct super_block *s,
                        goto free_cnode;
                }
 
-               /* bh == NULL when the block got to disk on its own, OR, 
-                ** the block got freed in a future transaction 
+               /* bh == NULL when the block got to disk on its own, OR,
+                ** the block got freed in a future transaction
                 */
                if (saved_bh == NULL) {
                        goto free_cnode;
@@ -1510,8 +1509,8 @@ static int flush_journal_list(struct super_block *s,
                 ** is not marked JDirty_wait
                 */
                if ((!was_jwait) && !buffer_locked(saved_bh)) {
-                       reiserfs_warning(s,
-                                        "journal-813: BAD! buffer %llu %cdirty %cjwait, "
+                       reiserfs_warning(s, "journal-813",
+                                        "BAD! buffer %llu %cdirty %cjwait, "
                                         "not in a newer tranasction",
                                         (unsigned long long)saved_bh->
                                         b_blocknr, was_dirty ? ' ' : '!',
@@ -1529,8 +1528,8 @@ static int flush_journal_list(struct super_block *s,
                                unlock_buffer(saved_bh);
                        count++;
                } else {
-                       reiserfs_warning(s,
-                                        "clm-2082: Unable to flush buffer %llu in %s",
+                       reiserfs_warning(s, "clm-2082",
+                                        "Unable to flush buffer %llu in %s",
                                         (unsigned long long)saved_bh->
                                         b_blocknr, __func__);
                }
@@ -1541,8 +1540,8 @@ static int flush_journal_list(struct super_block *s,
                        /* we incremented this to keep others from taking the buffer head away */
                        put_bh(saved_bh);
                        if (atomic_read(&(saved_bh->b_count)) < 0) {
-                               reiserfs_warning(s,
-                                                "journal-945: saved_bh->b_count < 0");
+                               reiserfs_warning(s, "journal-945",
+                                                "saved_bh->b_count < 0");
                        }
                }
        }
@@ -1551,18 +1550,18 @@ static int flush_journal_list(struct super_block *s,
                while (cn) {
                        if (test_bit(BLOCK_NEEDS_FLUSH, &cn->state)) {
                                if (!cn->bh) {
-                                       reiserfs_panic(s,
-                                                      "journal-1011: cn->bh is NULL\n");
+                                       reiserfs_panic(s, "journal-1011",
+                                                      "cn->bh is NULL");
                                }
                                wait_on_buffer(cn->bh);
                                if (!cn->bh) {
-                                       reiserfs_panic(s,
-                                                      "journal-1012: cn->bh is NULL\n");
+                                       reiserfs_panic(s, "journal-1012",
+                                                      "cn->bh is NULL");
                                }
                                if (unlikely(!buffer_uptodate(cn->bh))) {
 #ifdef CONFIG_REISERFS_CHECK
-                                       reiserfs_warning(s,
-                                                        "journal-949: buffer write failed\n");
+                                       reiserfs_warning(s, "journal-949",
+                                                        "buffer write failed");
 #endif
                                        err = -EIO;
                                }
@@ -1587,7 +1586,7 @@ static int flush_journal_list(struct super_block *s,
                               __func__);
       flush_older_and_return:
 
-       /* before we can update the journal header block, we _must_ flush all 
+       /* before we can update the journal header block, we _must_ flush all
         ** real blocks from all older transactions to disk.  This is because
         ** once the header block is updated, this transaction will not be
         ** replayed after a crash
@@ -1597,7 +1596,7 @@ static int flush_journal_list(struct super_block *s,
        }
 
        err = journal->j_errno;
-       /* before we can remove everything from the hash tables for this 
+       /* before we can remove everything from the hash tables for this
         ** transaction, we must make sure it can never be replayed
         **
         ** since we are only called from do_journal_end, we know for sure there
@@ -1623,7 +1622,7 @@ static int flush_journal_list(struct super_block *s,
 
        if (journal->j_last_flush_id != 0 &&
            (jl->j_trans_id - journal->j_last_flush_id) != 1) {
-               reiserfs_warning(s, "clm-2201last flush %lu, current %lu",
+               reiserfs_warning(s, "clm-2201", "last flush %lu, current %lu",
                                 journal->j_last_flush_id, jl->j_trans_id);
        }
        journal->j_last_flush_id = jl->j_trans_id;
@@ -1758,13 +1757,13 @@ static int dirty_one_transaction(struct super_block *s,
 static int kupdate_transactions(struct super_block *s,
                                struct reiserfs_journal_list *jl,
                                struct reiserfs_journal_list **next_jl,
-                               unsigned long *next_trans_id,
+                               unsigned int *next_trans_id,
                                int num_blocks, int num_trans)
 {
        int ret = 0;
        int written = 0;
        int transactions_flushed = 0;
-       unsigned long orig_trans_id = jl->j_trans_id;
+       unsigned int orig_trans_id = jl->j_trans_id;
        struct buffer_chunk chunk;
        struct list_head *entry;
        struct reiserfs_journal *journal = SB_JOURNAL(s);
@@ -1833,7 +1832,7 @@ static int flush_used_journal_lists(struct super_block *s,
        int limit = 256;
        struct reiserfs_journal_list *tjl;
        struct reiserfs_journal_list *flush_jl;
-       unsigned long trans_id;
+       unsigned int trans_id;
        struct reiserfs_journal *journal = SB_JOURNAL(s);
 
        flush_jl = tjl = jl;
@@ -1909,22 +1908,22 @@ void remove_journal_hash(struct super_block *sb,
        }
 }
 
-static void free_journal_ram(struct super_block *p_s_sb)
+static void free_journal_ram(struct super_block *sb)
 {
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
        kfree(journal->j_current_jl);
        journal->j_num_lists--;
 
        vfree(journal->j_cnode_free_orig);
-       free_list_bitmaps(p_s_sb, journal->j_list_bitmap);
-       free_bitmap_nodes(p_s_sb);      /* must be after free_list_bitmaps */
+       free_list_bitmaps(sb, journal->j_list_bitmap);
+       free_bitmap_nodes(sb);  /* must be after free_list_bitmaps */
        if (journal->j_header_bh) {
                brelse(journal->j_header_bh);
        }
        /* j_header_bh is on the journal dev, make sure not to release the journal
         * dev until we brelse j_header_bh
         */
-       release_journal_dev(p_s_sb, journal);
+       release_journal_dev(sb, journal);
        vfree(journal);
 }
 
@@ -1933,27 +1932,27 @@ static void free_journal_ram(struct super_block *p_s_sb)
 ** of read_super() yet.  Any other caller must keep error at 0.
 */
 static int do_journal_release(struct reiserfs_transaction_handle *th,
-                             struct super_block *p_s_sb, int error)
+                             struct super_block *sb, int error)
 {
        struct reiserfs_transaction_handle myth;
        int flushed = 0;
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
 
        /* we only want to flush out transactions if we were called with error == 0
         */
-       if (!error && !(p_s_sb->s_flags & MS_RDONLY)) {
+       if (!error && !(sb->s_flags & MS_RDONLY)) {
                /* end the current trans */
                BUG_ON(!th->t_trans_id);
-               do_journal_end(th, p_s_sb, 10, FLUSH_ALL);
+               do_journal_end(th, sb, 10, FLUSH_ALL);
 
                /* make sure something gets logged to force our way into the flush code */
-               if (!journal_join(&myth, p_s_sb, 1)) {
-                       reiserfs_prepare_for_journal(p_s_sb,
-                                                    SB_BUFFER_WITH_SB(p_s_sb),
+               if (!journal_join(&myth, sb, 1)) {
+                       reiserfs_prepare_for_journal(sb,
+                                                    SB_BUFFER_WITH_SB(sb),
                                                     1);
-                       journal_mark_dirty(&myth, p_s_sb,
-                                          SB_BUFFER_WITH_SB(p_s_sb));
-                       do_journal_end(&myth, p_s_sb, 1, FLUSH_ALL);
+                       journal_mark_dirty(&myth, sb,
+                                          SB_BUFFER_WITH_SB(sb));
+                       do_journal_end(&myth, sb, 1, FLUSH_ALL);
                        flushed = 1;
                }
        }
@@ -1961,26 +1960,26 @@ static int do_journal_release(struct reiserfs_transaction_handle *th,
        /* this also catches errors during the do_journal_end above */
        if (!error && reiserfs_is_journal_aborted(journal)) {
                memset(&myth, 0, sizeof(myth));
-               if (!journal_join_abort(&myth, p_s_sb, 1)) {
-                       reiserfs_prepare_for_journal(p_s_sb,
-                                                    SB_BUFFER_WITH_SB(p_s_sb),
+               if (!journal_join_abort(&myth, sb, 1)) {
+                       reiserfs_prepare_for_journal(sb,
+                                                    SB_BUFFER_WITH_SB(sb),
                                                     1);
-                       journal_mark_dirty(&myth, p_s_sb,
-                                          SB_BUFFER_WITH_SB(p_s_sb));
-                       do_journal_end(&myth, p_s_sb, 1, FLUSH_ALL);
+                       journal_mark_dirty(&myth, sb,
+                                          SB_BUFFER_WITH_SB(sb));
+                       do_journal_end(&myth, sb, 1, FLUSH_ALL);
                }
        }
 
        reiserfs_mounted_fs_count--;
        /* wait for all commits to finish */
-       cancel_delayed_work(&SB_JOURNAL(p_s_sb)->j_work);
+       cancel_delayed_work(&SB_JOURNAL(sb)->j_work);
        flush_workqueue(commit_wq);
        if (!reiserfs_mounted_fs_count) {
                destroy_workqueue(commit_wq);
                commit_wq = NULL;
        }
 
-       free_journal_ram(p_s_sb);
+       free_journal_ram(sb);
 
        return 0;
 }
@@ -1989,41 +1988,41 @@ static int do_journal_release(struct reiserfs_transaction_handle *th,
 ** call on unmount.  flush all journal trans, release all alloc'd ram
 */
 int journal_release(struct reiserfs_transaction_handle *th,
-                   struct super_block *p_s_sb)
+                   struct super_block *sb)
 {
-       return do_journal_release(th, p_s_sb, 0);
+       return do_journal_release(th, sb, 0);
 }
 
 /*
 ** only call from an error condition inside reiserfs_read_super!
 */
 int journal_release_error(struct reiserfs_transaction_handle *th,
-                         struct super_block *p_s_sb)
+                         struct super_block *sb)
 {
-       return do_journal_release(th, p_s_sb, 1);
+       return do_journal_release(th, sb, 1);
 }
 
 /* compares description block with commit block.  returns 1 if they differ, 0 if they are the same */
-static int journal_compare_desc_commit(struct super_block *p_s_sb,
+static int journal_compare_desc_commit(struct super_block *sb,
                                       struct reiserfs_journal_desc *desc,
                                       struct reiserfs_journal_commit *commit)
 {
        if (get_commit_trans_id(commit) != get_desc_trans_id(desc) ||
            get_commit_trans_len(commit) != get_desc_trans_len(desc) ||
-           get_commit_trans_len(commit) > SB_JOURNAL(p_s_sb)->j_trans_max ||
+           get_commit_trans_len(commit) > SB_JOURNAL(sb)->j_trans_max ||
            get_commit_trans_len(commit) <= 0) {
                return 1;
        }
        return 0;
 }
 
-/* returns 0 if it did not find a description block  
+/* returns 0 if it did not find a description block
 ** returns -1 if it found a corrupt commit block
-** returns 1 if both desc and commit were valid 
+** returns 1 if both desc and commit were valid
 */
-static int journal_transaction_is_valid(struct super_block *p_s_sb,
+static int journal_transaction_is_valid(struct super_block *sb,
                                        struct buffer_head *d_bh,
-                                       unsigned long *oldest_invalid_trans_id,
+                                       unsigned int *oldest_invalid_trans_id,
                                        unsigned long *newest_mount_id)
 {
        struct reiserfs_journal_desc *desc;
@@ -2039,7 +2038,7 @@ static int journal_transaction_is_valid(struct super_block *p_s_sb,
            && !memcmp(get_journal_desc_magic(d_bh), JOURNAL_DESC_MAGIC, 8)) {
                if (oldest_invalid_trans_id && *oldest_invalid_trans_id
                    && get_desc_trans_id(desc) > *oldest_invalid_trans_id) {
-                       reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+                       reiserfs_debug(sb, REISERFS_DEBUG_CODE,
                                       "journal-986: transaction "
                                       "is valid returning because trans_id %d is greater than "
                                       "oldest_invalid %lu",
@@ -2049,7 +2048,7 @@ static int journal_transaction_is_valid(struct super_block *p_s_sb,
                }
                if (newest_mount_id
                    && *newest_mount_id > get_desc_mount_id(desc)) {
-                       reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+                       reiserfs_debug(sb, REISERFS_DEBUG_CODE,
                                       "journal-1087: transaction "
                                       "is valid returning because mount_id %d is less than "
                                       "newest_mount_id %lu",
@@ -2057,36 +2056,37 @@ static int journal_transaction_is_valid(struct super_block *p_s_sb,
                                       *newest_mount_id);
                        return -1;
                }
-               if (get_desc_trans_len(desc) > SB_JOURNAL(p_s_sb)->j_trans_max) {
-                       reiserfs_warning(p_s_sb,
-                                        "journal-2018: Bad transaction length %d encountered, ignoring transaction",
+               if (get_desc_trans_len(desc) > SB_JOURNAL(sb)->j_trans_max) {
+                       reiserfs_warning(sb, "journal-2018",
+                                        "Bad transaction length %d "
+                                        "encountered, ignoring transaction",
                                         get_desc_trans_len(desc));
                        return -1;
                }
-               offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb);
+               offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(sb);
 
                /* ok, we have a journal description block, lets see if the transaction was valid */
                c_bh =
-                   journal_bread(p_s_sb,
-                                 SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+                   journal_bread(sb,
+                                 SB_ONDISK_JOURNAL_1st_BLOCK(sb) +
                                  ((offset + get_desc_trans_len(desc) +
-                                   1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)));
+                                   1) % SB_ONDISK_JOURNAL_SIZE(sb)));
                if (!c_bh)
                        return 0;
                commit = (struct reiserfs_journal_commit *)c_bh->b_data;
-               if (journal_compare_desc_commit(p_s_sb, desc, commit)) {
-                       reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+               if (journal_compare_desc_commit(sb, desc, commit)) {
+                       reiserfs_debug(sb, REISERFS_DEBUG_CODE,
                                       "journal_transaction_is_valid, commit offset %ld had bad "
                                       "time %d or length %d",
                                       c_bh->b_blocknr -
-                                      SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
+                                      SB_ONDISK_JOURNAL_1st_BLOCK(sb),
                                       get_commit_trans_id(commit),
                                       get_commit_trans_len(commit));
                        brelse(c_bh);
                        if (oldest_invalid_trans_id) {
                                *oldest_invalid_trans_id =
                                    get_desc_trans_id(desc);
-                               reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+                               reiserfs_debug(sb, REISERFS_DEBUG_CODE,
                                               "journal-1004: "
                                               "transaction_is_valid setting oldest invalid trans_id "
                                               "to %d",
@@ -2095,11 +2095,11 @@ static int journal_transaction_is_valid(struct super_block *p_s_sb,
                        return -1;
                }
                brelse(c_bh);
-               reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+               reiserfs_debug(sb, REISERFS_DEBUG_CODE,
                               "journal-1006: found valid "
                               "transaction start offset %llu, len %d id %d",
                               d_bh->b_blocknr -
-                              SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
+                              SB_ONDISK_JOURNAL_1st_BLOCK(sb),
                               get_desc_trans_len(desc),
                               get_desc_trans_id(desc));
                return 1;
@@ -2121,63 +2121,63 @@ static void brelse_array(struct buffer_head **heads, int num)
 ** this either reads in a replays a transaction, or returns because the transaction
 ** is invalid, or too old.
 */
-static int journal_read_transaction(struct super_block *p_s_sb,
+static int journal_read_transaction(struct super_block *sb,
                                    unsigned long cur_dblock,
                                    unsigned long oldest_start,
-                                   unsigned long oldest_trans_id,
+                                   unsigned int oldest_trans_id,
                                    unsigned long newest_mount_id)
 {
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
        struct reiserfs_journal_desc *desc;
        struct reiserfs_journal_commit *commit;
-       unsigned long trans_id = 0;
+       unsigned int trans_id = 0;
        struct buffer_head *c_bh;
        struct buffer_head *d_bh;
        struct buffer_head **log_blocks = NULL;
        struct buffer_head **real_blocks = NULL;
-       unsigned long trans_offset;
+       unsigned int trans_offset;
        int i;
        int trans_half;
 
-       d_bh = journal_bread(p_s_sb, cur_dblock);
+       d_bh = journal_bread(sb, cur_dblock);
        if (!d_bh)
                return 1;
        desc = (struct reiserfs_journal_desc *)d_bh->b_data;
-       trans_offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb);
-       reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1037: "
+       trans_offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(sb);
+       reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1037: "
                       "journal_read_transaction, offset %llu, len %d mount_id %d",
-                      d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
+                      d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(sb),
                       get_desc_trans_len(desc), get_desc_mount_id(desc));
        if (get_desc_trans_id(desc) < oldest_trans_id) {
-               reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1039: "
+               reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1039: "
                               "journal_read_trans skipping because %lu is too old",
                               cur_dblock -
-                              SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb));
+                              SB_ONDISK_JOURNAL_1st_BLOCK(sb));
                brelse(d_bh);
                return 1;
        }
        if (get_desc_mount_id(desc) != newest_mount_id) {
-               reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1146: "
+               reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1146: "
                               "journal_read_trans skipping because %d is != "
                               "newest_mount_id %lu", get_desc_mount_id(desc),
                               newest_mount_id);
                brelse(d_bh);
                return 1;
        }
-       c_bh = journal_bread(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+       c_bh = journal_bread(sb, SB_ONDISK_JOURNAL_1st_BLOCK(sb) +
                             ((trans_offset + get_desc_trans_len(desc) + 1) %
-                             SB_ONDISK_JOURNAL_SIZE(p_s_sb)));
+                             SB_ONDISK_JOURNAL_SIZE(sb)));
        if (!c_bh) {
                brelse(d_bh);
                return 1;
        }
        commit = (struct reiserfs_journal_commit *)c_bh->b_data;
-       if (journal_compare_desc_commit(p_s_sb, desc, commit)) {
-               reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+       if (journal_compare_desc_commit(sb, desc, commit)) {
+               reiserfs_debug(sb, REISERFS_DEBUG_CODE,
                               "journal_read_transaction, "
                               "commit offset %llu had bad time %d or length %d",
                               c_bh->b_blocknr -
-                              SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
+                              SB_ONDISK_JOURNAL_1st_BLOCK(sb),
                               get_commit_trans_id(commit),
                               get_commit_trans_len(commit));
                brelse(c_bh);
@@ -2195,38 +2195,41 @@ static int journal_read_transaction(struct super_block *p_s_sb,
                brelse(d_bh);
                kfree(log_blocks);
                kfree(real_blocks);
-               reiserfs_warning(p_s_sb,
-                                "journal-1169: kmalloc failed, unable to mount FS");
+               reiserfs_warning(sb, "journal-1169",
+                                "kmalloc failed, unable to mount FS");
                return -1;
        }
        /* get all the buffer heads */
-       trans_half = journal_trans_half(p_s_sb->s_blocksize);
+       trans_half = journal_trans_half(sb->s_blocksize);
        for (i = 0; i < get_desc_trans_len(desc); i++) {
                log_blocks[i] =
-                   journal_getblk(p_s_sb,
-                                  SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+                   journal_getblk(sb,
+                                  SB_ONDISK_JOURNAL_1st_BLOCK(sb) +
                                   (trans_offset + 1 +
-                                   i) % SB_ONDISK_JOURNAL_SIZE(p_s_sb));
+                                   i) % SB_ONDISK_JOURNAL_SIZE(sb));
                if (i < trans_half) {
                        real_blocks[i] =
-                           sb_getblk(p_s_sb,
+                           sb_getblk(sb,
                                      le32_to_cpu(desc->j_realblock[i]));
                } else {
                        real_blocks[i] =
-                           sb_getblk(p_s_sb,
+                           sb_getblk(sb,
                                      le32_to_cpu(commit->
                                                  j_realblock[i - trans_half]));
                }
-               if (real_blocks[i]->b_blocknr > SB_BLOCK_COUNT(p_s_sb)) {
-                       reiserfs_warning(p_s_sb,
-                                        "journal-1207: REPLAY FAILURE fsck required! Block to replay is outside of filesystem");
+               if (real_blocks[i]->b_blocknr > SB_BLOCK_COUNT(sb)) {
+                       reiserfs_warning(sb, "journal-1207",
+                                        "REPLAY FAILURE fsck required! "
+                                        "Block to replay is outside of "
+                                        "filesystem");
                        goto abort_replay;
                }
                /* make sure we don't try to replay onto log or reserved area */
                if (is_block_in_log_or_reserved_area
-                   (p_s_sb, real_blocks[i]->b_blocknr)) {
-                       reiserfs_warning(p_s_sb,
-                                        "journal-1204: REPLAY FAILURE fsck required! Trying to replay onto a log block");
+                   (sb, real_blocks[i]->b_blocknr)) {
+                       reiserfs_warning(sb, "journal-1204",
+                                        "REPLAY FAILURE fsck required! "
+                                        "Trying to replay onto a log block");
                      abort_replay:
                        brelse_array(log_blocks, i);
                        brelse_array(real_blocks, i);
@@ -2242,8 +2245,9 @@ static int journal_read_transaction(struct super_block *p_s_sb,
        for (i = 0; i < get_desc_trans_len(desc); i++) {
                wait_on_buffer(log_blocks[i]);
                if (!buffer_uptodate(log_blocks[i])) {
-                       reiserfs_warning(p_s_sb,
-                                        "journal-1212: REPLAY FAILURE fsck required! buffer write failed");
+                       reiserfs_warning(sb, "journal-1212",
+                                        "REPLAY FAILURE fsck required! "
+                                        "buffer write failed");
                        brelse_array(log_blocks + i,
                                     get_desc_trans_len(desc) - i);
                        brelse_array(real_blocks, get_desc_trans_len(desc));
@@ -2266,8 +2270,9 @@ static int journal_read_transaction(struct super_block *p_s_sb,
        for (i = 0; i < get_desc_trans_len(desc); i++) {
                wait_on_buffer(real_blocks[i]);
                if (!buffer_uptodate(real_blocks[i])) {
-                       reiserfs_warning(p_s_sb,
-                                        "journal-1226: REPLAY FAILURE, fsck required! buffer write failed");
+                       reiserfs_warning(sb, "journal-1226",
+                                        "REPLAY FAILURE, fsck required! "
+                                        "buffer write failed");
                        brelse_array(real_blocks + i,
                                     get_desc_trans_len(desc) - i);
                        brelse(c_bh);
@@ -2279,15 +2284,15 @@ static int journal_read_transaction(struct super_block *p_s_sb,
                brelse(real_blocks[i]);
        }
        cur_dblock =
-           SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+           SB_ONDISK_JOURNAL_1st_BLOCK(sb) +
            ((trans_offset + get_desc_trans_len(desc) +
-             2) % SB_ONDISK_JOURNAL_SIZE(p_s_sb));
-       reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+             2) % SB_ONDISK_JOURNAL_SIZE(sb));
+       reiserfs_debug(sb, REISERFS_DEBUG_CODE,
                       "journal-1095: setting journal " "start to offset %ld",
-                      cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb));
+                      cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(sb));
 
        /* init starting values for the first transaction, in case this is the last transaction to be replayed. */
-       journal->j_start = cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb);
+       journal->j_start = cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(sb);
        journal->j_last_flush_trans_id = trans_id;
        journal->j_trans_id = trans_id + 1;
        /* check for trans_id overflow */
@@ -2352,12 +2357,12 @@ static struct buffer_head *reiserfs_breada(struct block_device *dev,
 **
 ** On exit, it sets things up so the first transaction will work correctly.
 */
-static int journal_read(struct super_block *p_s_sb)
+static int journal_read(struct super_block *sb)
 {
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
        struct reiserfs_journal_desc *desc;
-       unsigned long oldest_trans_id = 0;
-       unsigned long oldest_invalid_trans_id = 0;
+       unsigned int oldest_trans_id = 0;
+       unsigned int oldest_invalid_trans_id = 0;
        time_t start;
        unsigned long oldest_start = 0;
        unsigned long cur_dblock = 0;
@@ -2370,46 +2375,46 @@ static int journal_read(struct super_block *p_s_sb)
        int ret;
        char b[BDEVNAME_SIZE];
 
-       cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb);
-       reiserfs_info(p_s_sb, "checking transaction log (%s)\n",
+       cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(sb);
+       reiserfs_info(sb, "checking transaction log (%s)\n",
                      bdevname(journal->j_dev_bd, b));
        start = get_seconds();
 
-       /* step 1, read in the journal header block.  Check the transaction it says 
-        ** is the first unflushed, and if that transaction is not valid, 
+       /* step 1, read in the journal header block.  Check the transaction it says
+        ** is the first unflushed, and if that transaction is not valid,
         ** replay is done
         */
-       journal->j_header_bh = journal_bread(p_s_sb,
-                                            SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb)
-                                            + SB_ONDISK_JOURNAL_SIZE(p_s_sb));
+       journal->j_header_bh = journal_bread(sb,
+                                            SB_ONDISK_JOURNAL_1st_BLOCK(sb)
+                                            + SB_ONDISK_JOURNAL_SIZE(sb));
        if (!journal->j_header_bh) {
                return 1;
        }
        jh = (struct reiserfs_journal_header *)(journal->j_header_bh->b_data);
        if (le32_to_cpu(jh->j_first_unflushed_offset) <
-           SB_ONDISK_JOURNAL_SIZE(p_s_sb)
+           SB_ONDISK_JOURNAL_SIZE(sb)
            && le32_to_cpu(jh->j_last_flush_trans_id) > 0) {
                oldest_start =
-                   SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+                   SB_ONDISK_JOURNAL_1st_BLOCK(sb) +
                    le32_to_cpu(jh->j_first_unflushed_offset);
                oldest_trans_id = le32_to_cpu(jh->j_last_flush_trans_id) + 1;
                newest_mount_id = le32_to_cpu(jh->j_mount_id);
-               reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+               reiserfs_debug(sb, REISERFS_DEBUG_CODE,
                               "journal-1153: found in "
                               "header: first_unflushed_offset %d, last_flushed_trans_id "
                               "%lu", le32_to_cpu(jh->j_first_unflushed_offset),
                               le32_to_cpu(jh->j_last_flush_trans_id));
                valid_journal_header = 1;
 
-               /* now, we try to read the first unflushed offset.  If it is not valid, 
-                ** there is nothing more we can do, and it makes no sense to read 
+               /* now, we try to read the first unflushed offset.  If it is not valid,
+                ** there is nothing more we can do, and it makes no sense to read
                 ** through the whole log.
                 */
                d_bh =
-                   journal_bread(p_s_sb,
-                                 SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+                   journal_bread(sb,
+                                 SB_ONDISK_JOURNAL_1st_BLOCK(sb) +
                                  le32_to_cpu(jh->j_first_unflushed_offset));
-               ret = journal_transaction_is_valid(p_s_sb, d_bh, NULL, NULL);
+               ret = journal_transaction_is_valid(sb, d_bh, NULL, NULL);
                if (!ret) {
                        continue_replay = 0;
                }
@@ -2417,9 +2422,9 @@ static int journal_read(struct super_block *p_s_sb)
                goto start_log_replay;
        }
 
-       if (continue_replay && bdev_read_only(p_s_sb->s_bdev)) {
-               reiserfs_warning(p_s_sb,
-                                "clm-2076: device is readonly, unable to replay log");
+       if (continue_replay && bdev_read_only(sb->s_bdev)) {
+               reiserfs_warning(sb, "clm-2076",
+                                "device is readonly, unable to replay log");
                return -1;
        }
 
@@ -2428,17 +2433,17 @@ static int journal_read(struct super_block *p_s_sb)
         */
        while (continue_replay
               && cur_dblock <
-              (SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
-               SB_ONDISK_JOURNAL_SIZE(p_s_sb))) {
+              (SB_ONDISK_JOURNAL_1st_BLOCK(sb) +
+               SB_ONDISK_JOURNAL_SIZE(sb))) {
                /* Note that it is required for blocksize of primary fs device and journal
                   device to be the same */
                d_bh =
                    reiserfs_breada(journal->j_dev_bd, cur_dblock,
-                                   p_s_sb->s_blocksize,
-                                   SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
-                                   SB_ONDISK_JOURNAL_SIZE(p_s_sb));
+                                   sb->s_blocksize,
+                                   SB_ONDISK_JOURNAL_1st_BLOCK(sb) +
+                                   SB_ONDISK_JOURNAL_SIZE(sb));
                ret =
-                   journal_transaction_is_valid(p_s_sb, d_bh,
+                   journal_transaction_is_valid(sb, d_bh,
                                                 &oldest_invalid_trans_id,
                                                 &newest_mount_id);
                if (ret == 1) {
@@ -2447,26 +2452,26 @@ static int journal_read(struct super_block *p_s_sb)
                                oldest_trans_id = get_desc_trans_id(desc);
                                oldest_start = d_bh->b_blocknr;
                                newest_mount_id = get_desc_mount_id(desc);
-                               reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+                               reiserfs_debug(sb, REISERFS_DEBUG_CODE,
                                               "journal-1179: Setting "
                                               "oldest_start to offset %llu, trans_id %lu",
                                               oldest_start -
                                               SB_ONDISK_JOURNAL_1st_BLOCK
-                                              (p_s_sb), oldest_trans_id);
+                                              (sb), oldest_trans_id);
                        } else if (oldest_trans_id > get_desc_trans_id(desc)) {
                                /* one we just read was older */
                                oldest_trans_id = get_desc_trans_id(desc);
                                oldest_start = d_bh->b_blocknr;
-                               reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+                               reiserfs_debug(sb, REISERFS_DEBUG_CODE,
                                               "journal-1180: Resetting "
                                               "oldest_start to offset %lu, trans_id %lu",
                                               oldest_start -
                                               SB_ONDISK_JOURNAL_1st_BLOCK
-                                              (p_s_sb), oldest_trans_id);
+                                              (sb), oldest_trans_id);
                        }
                        if (newest_mount_id < get_desc_mount_id(desc)) {
                                newest_mount_id = get_desc_mount_id(desc);
-                               reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+                               reiserfs_debug(sb, REISERFS_DEBUG_CODE,
                                               "journal-1299: Setting "
                                               "newest_mount_id to %d",
                                               get_desc_mount_id(desc));
@@ -2481,17 +2486,17 @@ static int journal_read(struct super_block *p_s_sb)
       start_log_replay:
        cur_dblock = oldest_start;
        if (oldest_trans_id) {
-               reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+               reiserfs_debug(sb, REISERFS_DEBUG_CODE,
                               "journal-1206: Starting replay "
                               "from offset %llu, trans_id %lu",
-                              cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
+                              cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(sb),
                               oldest_trans_id);
 
        }
        replay_count = 0;
        while (continue_replay && oldest_trans_id > 0) {
                ret =
-                   journal_read_transaction(p_s_sb, cur_dblock, oldest_start,
+                   journal_read_transaction(sb, cur_dblock, oldest_start,
                                             oldest_trans_id, newest_mount_id);
                if (ret < 0) {
                        return ret;
@@ -2499,14 +2504,14 @@ static int journal_read(struct super_block *p_s_sb)
                        break;
                }
                cur_dblock =
-                   SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + journal->j_start;
+                   SB_ONDISK_JOURNAL_1st_BLOCK(sb) + journal->j_start;
                replay_count++;
                if (cur_dblock == oldest_start)
                        break;
        }
 
        if (oldest_trans_id == 0) {
-               reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+               reiserfs_debug(sb, REISERFS_DEBUG_CODE,
                               "journal-1225: No valid " "transactions found");
        }
        /* j_start does not get set correctly if we don't replay any transactions.
@@ -2526,16 +2531,16 @@ static int journal_read(struct super_block *p_s_sb)
        } else {
                journal->j_mount_id = newest_mount_id + 1;
        }
-       reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1299: Setting "
+       reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1299: Setting "
                       "newest_mount_id to %lu", journal->j_mount_id);
        journal->j_first_unflushed_offset = journal->j_start;
        if (replay_count > 0) {
-               reiserfs_info(p_s_sb,
+               reiserfs_info(sb,
                              "replayed %d transactions in %lu seconds\n",
                              replay_count, get_seconds() - start);
        }
-       if (!bdev_read_only(p_s_sb->s_bdev) &&
-           _update_journal_header_block(p_s_sb, journal->j_start,
+       if (!bdev_read_only(sb->s_bdev) &&
+           _update_journal_header_block(sb, journal->j_start,
                                         journal->j_last_flush_trans_id)) {
                /* replay failed, caller must call free_journal_ram and abort
                 ** the mount
@@ -2560,9 +2565,9 @@ static struct reiserfs_journal_list *alloc_journal_list(struct super_block *s)
        return jl;
 }
 
-static void journal_list_init(struct super_block *p_s_sb)
+static void journal_list_init(struct super_block *sb)
 {
-       SB_JOURNAL(p_s_sb)->j_current_jl = alloc_journal_list(p_s_sb);
+       SB_JOURNAL(sb)->j_current_jl = alloc_journal_list(sb);
 }
 
 static int release_journal_dev(struct super_block *super,
@@ -2580,9 +2585,8 @@ static int release_journal_dev(struct super_block *super,
        }
 
        if (result != 0) {
-               reiserfs_warning(super,
-                                "sh-457: release_journal_dev: Cannot release journal device: %i",
-                                result);
+               reiserfs_warning(super, "sh-457",
+                                "Cannot release journal device: %i", result);
        }
        return result;
 }
@@ -2612,7 +2616,7 @@ static int journal_init_dev(struct super_block *super,
                if (IS_ERR(journal->j_dev_bd)) {
                        result = PTR_ERR(journal->j_dev_bd);
                        journal->j_dev_bd = NULL;
-                       reiserfs_warning(super, "sh-458: journal_init_dev: "
+                       reiserfs_warning(super, "sh-458",
                                         "cannot init journal device '%s': %i",
                                         __bdevname(jdev, b), result);
                        return result;
@@ -2662,30 +2666,30 @@ static int journal_init_dev(struct super_block *super,
  */
 #define REISERFS_STANDARD_BLKSIZE (4096)
 
-static int check_advise_trans_params(struct super_block *p_s_sb,
+static int check_advise_trans_params(struct super_block *sb,
                                     struct reiserfs_journal *journal)
 {
         if (journal->j_trans_max) {
                /* Non-default journal params.
                   Do sanity check for them. */
                int ratio = 1;
-               if (p_s_sb->s_blocksize < REISERFS_STANDARD_BLKSIZE)
-                       ratio = REISERFS_STANDARD_BLKSIZE / p_s_sb->s_blocksize;
+               if (sb->s_blocksize < REISERFS_STANDARD_BLKSIZE)
+                       ratio = REISERFS_STANDARD_BLKSIZE / sb->s_blocksize;
 
                if (journal->j_trans_max > JOURNAL_TRANS_MAX_DEFAULT / ratio ||
                    journal->j_trans_max < JOURNAL_TRANS_MIN_DEFAULT / ratio ||
-                   SB_ONDISK_JOURNAL_SIZE(p_s_sb) / journal->j_trans_max <
+                   SB_ONDISK_JOURNAL_SIZE(sb) / journal->j_trans_max <
                    JOURNAL_MIN_RATIO) {
-                       reiserfs_warning(p_s_sb,
-                                "sh-462: bad transaction max size (%u). FSCK?",
-                                journal->j_trans_max);
+                       reiserfs_warning(sb, "sh-462",
+                                        "bad transaction max size (%u). "
+                                        "FSCK?", journal->j_trans_max);
                        return 1;
                }
                if (journal->j_max_batch != (journal->j_trans_max) *
                        JOURNAL_MAX_BATCH_DEFAULT/JOURNAL_TRANS_MAX_DEFAULT) {
-                       reiserfs_warning(p_s_sb,
-                               "sh-463: bad transaction max batch (%u). FSCK?",
-                               journal->j_max_batch);
+                       reiserfs_warning(sb, "sh-463",
+                                        "bad transaction max batch (%u). "
+                                        "FSCK?", journal->j_max_batch);
                        return 1;
                }
        } else {
@@ -2693,9 +2697,11 @@ static int check_advise_trans_params(struct super_block *p_s_sb,
                    The file system was created by old version
                   of mkreiserfs, so some fields contain zeros,
                   and we need to advise proper values for them */
-               if (p_s_sb->s_blocksize != REISERFS_STANDARD_BLKSIZE)
-                       reiserfs_panic(p_s_sb, "sh-464: bad blocksize (%u)",
-                                      p_s_sb->s_blocksize);
+               if (sb->s_blocksize != REISERFS_STANDARD_BLKSIZE) {
+                       reiserfs_warning(sb, "sh-464", "bad blocksize (%u)",
+                                        sb->s_blocksize);
+                       return 1;
+               }
                journal->j_trans_max = JOURNAL_TRANS_MAX_DEFAULT;
                journal->j_max_batch = JOURNAL_MAX_BATCH_DEFAULT;
                journal->j_max_commit_age = JOURNAL_MAX_COMMIT_AGE;
@@ -2706,10 +2712,10 @@ static int check_advise_trans_params(struct super_block *p_s_sb,
 /*
 ** must be called once on fs mount.  calls journal_read for you
 */
-int journal_init(struct super_block *p_s_sb, const char *j_dev_name,
+int journal_init(struct super_block *sb, const char *j_dev_name,
                 int old_format, unsigned int commit_max_age)
 {
-       int num_cnodes = SB_ONDISK_JOURNAL_SIZE(p_s_sb) * 2;
+       int num_cnodes = SB_ONDISK_JOURNAL_SIZE(sb) * 2;
        struct buffer_head *bhjh;
        struct reiserfs_super_block *rs;
        struct reiserfs_journal_header *jh;
@@ -2717,10 +2723,10 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name,
        struct reiserfs_journal_list *jl;
        char b[BDEVNAME_SIZE];
 
-       journal = SB_JOURNAL(p_s_sb) = vmalloc(sizeof(struct reiserfs_journal));
+       journal = SB_JOURNAL(sb) = vmalloc(sizeof(struct reiserfs_journal));
        if (!journal) {
-               reiserfs_warning(p_s_sb,
-                                "journal-1256: unable to get memory for journal structure");
+               reiserfs_warning(sb, "journal-1256",
+                                "unable to get memory for journal structure");
                return 1;
        }
        memset(journal, 0, sizeof(struct reiserfs_journal));
@@ -2729,51 +2735,51 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name,
        INIT_LIST_HEAD(&journal->j_working_list);
        INIT_LIST_HEAD(&journal->j_journal_list);
        journal->j_persistent_trans = 0;
-       if (reiserfs_allocate_list_bitmaps(p_s_sb,
+       if (reiserfs_allocate_list_bitmaps(sb,
                                           journal->j_list_bitmap,
-                                          reiserfs_bmap_count(p_s_sb)))
+                                          reiserfs_bmap_count(sb)))
                goto free_and_return;
-       allocate_bitmap_nodes(p_s_sb);
+       allocate_bitmap_nodes(sb);
 
        /* reserved for journal area support */
-       SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb) = (old_format ?
+       SB_JOURNAL_1st_RESERVED_BLOCK(sb) = (old_format ?
                                                 REISERFS_OLD_DISK_OFFSET_IN_BYTES
-                                                / p_s_sb->s_blocksize +
-                                                reiserfs_bmap_count(p_s_sb) +
+                                                / sb->s_blocksize +
+                                                reiserfs_bmap_count(sb) +
                                                 1 :
                                                 REISERFS_DISK_OFFSET_IN_BYTES /
-                                                p_s_sb->s_blocksize + 2);
+                                                sb->s_blocksize + 2);
 
        /* Sanity check to see is the standard journal fitting withing first bitmap
           (actual for small blocksizes) */
-       if (!SB_ONDISK_JOURNAL_DEVICE(p_s_sb) &&
-           (SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb) +
-            SB_ONDISK_JOURNAL_SIZE(p_s_sb) > p_s_sb->s_blocksize * 8)) {
-               reiserfs_warning(p_s_sb,
-                                "journal-1393: journal does not fit for area "
-                                "addressed by first of bitmap blocks. It starts at "
+       if (!SB_ONDISK_JOURNAL_DEVICE(sb) &&
+           (SB_JOURNAL_1st_RESERVED_BLOCK(sb) +
+            SB_ONDISK_JOURNAL_SIZE(sb) > sb->s_blocksize * 8)) {
+               reiserfs_warning(sb, "journal-1393",
+                                "journal does not fit for area addressed "
+                                "by first of bitmap blocks. It starts at "
                                 "%u and its size is %u. Block size %ld",
-                                SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb),
-                                SB_ONDISK_JOURNAL_SIZE(p_s_sb),
-                                p_s_sb->s_blocksize);
+                                SB_JOURNAL_1st_RESERVED_BLOCK(sb),
+                                SB_ONDISK_JOURNAL_SIZE(sb),
+                                sb->s_blocksize);
                goto free_and_return;
        }
 
-       if (journal_init_dev(p_s_sb, journal, j_dev_name) != 0) {
-               reiserfs_warning(p_s_sb,
-                                "sh-462: unable to initialize jornal device");
+       if (journal_init_dev(sb, journal, j_dev_name) != 0) {
+               reiserfs_warning(sb, "sh-462",
+                                "unable to initialize jornal device");
                goto free_and_return;
        }
 
-       rs = SB_DISK_SUPER_BLOCK(p_s_sb);
+       rs = SB_DISK_SUPER_BLOCK(sb);
 
        /* read journal header */
-       bhjh = journal_bread(p_s_sb,
-                            SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
-                            SB_ONDISK_JOURNAL_SIZE(p_s_sb));
+       bhjh = journal_bread(sb,
+                            SB_ONDISK_JOURNAL_1st_BLOCK(sb) +
+                            SB_ONDISK_JOURNAL_SIZE(sb));
        if (!bhjh) {
-               reiserfs_warning(p_s_sb,
-                                "sh-459: unable to read journal header");
+               reiserfs_warning(sb, "sh-459",
+                                "unable to read journal header");
                goto free_and_return;
        }
        jh = (struct reiserfs_journal_header *)(bhjh->b_data);
@@ -2782,10 +2788,10 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name,
        if (is_reiserfs_jr(rs)
            && (le32_to_cpu(jh->jh_journal.jp_journal_magic) !=
                sb_jp_journal_magic(rs))) {
-               reiserfs_warning(p_s_sb,
-                                "sh-460: journal header magic %x "
-                                "(device %s) does not match to magic found in super "
-                                "block %x", jh->jh_journal.jp_journal_magic,
+               reiserfs_warning(sb, "sh-460",
+                                "journal header magic %x (device %s) does "
+                                "not match to magic found in super block %x",
+                                jh->jh_journal.jp_journal_magic,
                                 bdevname(journal->j_dev_bd, b),
                                 sb_jp_journal_magic(rs));
                brelse(bhjh);
@@ -2798,7 +2804,7 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name,
            le32_to_cpu(jh->jh_journal.jp_journal_max_commit_age);
        journal->j_max_trans_age = JOURNAL_MAX_TRANS_AGE;
 
-       if (check_advise_trans_params(p_s_sb, journal) != 0)
+       if (check_advise_trans_params(sb, journal) != 0)
                goto free_and_return;
        journal->j_default_max_commit_age = journal->j_max_commit_age;
 
@@ -2807,12 +2813,12 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name,
                journal->j_max_trans_age = commit_max_age;
        }
 
-       reiserfs_info(p_s_sb, "journal params: device %s, size %u, "
+       reiserfs_info(sb, "journal params: device %s, size %u, "
                      "journal first block %u, max trans len %u, max batch %u, "
                      "max commit age %u, max trans age %u\n",
                      bdevname(journal->j_dev_bd, b),
-                     SB_ONDISK_JOURNAL_SIZE(p_s_sb),
-                     SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
+                     SB_ONDISK_JOURNAL_SIZE(sb),
+                     SB_ONDISK_JOURNAL_1st_BLOCK(sb),
                      journal->j_trans_max,
                      journal->j_max_batch,
                      journal->j_max_commit_age, journal->j_max_trans_age);
@@ -2820,7 +2826,7 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name,
        brelse(bhjh);
 
        journal->j_list_bitmap_index = 0;
-       journal_list_init(p_s_sb);
+       journal_list_init(sb);
 
        memset(journal->j_list_hash_table, 0,
               JOURNAL_HASH_SIZE * sizeof(struct reiserfs_journal_cnode *));
@@ -2852,7 +2858,7 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name,
        journal->j_must_wait = 0;
 
        if (journal->j_cnode_free == 0) {
-               reiserfs_warning(p_s_sb, "journal-2004: Journal cnode memory "
+               reiserfs_warning(sb, "journal-2004", "Journal cnode memory "
                                 "allocation failed (%ld bytes). Journal is "
                                 "too large for available memory. Usually "
                                 "this is due to a journal that is too large.",
@@ -2860,16 +2866,17 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name,
                goto free_and_return;
        }
 
-       init_journal_hash(p_s_sb);
+       init_journal_hash(sb);
        jl = journal->j_current_jl;
-       jl->j_list_bitmap = get_list_bitmap(p_s_sb, jl);
+       jl->j_list_bitmap = get_list_bitmap(sb, jl);
        if (!jl->j_list_bitmap) {
-               reiserfs_warning(p_s_sb,
-                                "journal-2005, get_list_bitmap failed for journal list 0");
+               reiserfs_warning(sb, "journal-2005",
+                                "get_list_bitmap failed for journal list 0");
                goto free_and_return;
        }
-       if (journal_read(p_s_sb) < 0) {
-               reiserfs_warning(p_s_sb, "Replay Failure, unable to mount");
+       if (journal_read(sb) < 0) {
+               reiserfs_warning(sb, "reiserfs-2006",
+                                "Replay Failure, unable to mount");
                goto free_and_return;
        }
 
@@ -2878,10 +2885,10 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name,
                commit_wq = create_workqueue("reiserfs");
 
        INIT_DELAYED_WORK(&journal->j_work, flush_async_commits);
-       journal->j_work_sb = p_s_sb;
+       journal->j_work_sb = sb;
        return 0;
       free_and_return:
-       free_journal_ram(p_s_sb);
+       free_journal_ram(sb);
        return 1;
 }
 
@@ -2912,7 +2919,7 @@ int journal_transaction_should_end(struct reiserfs_transaction_handle *th,
        return 0;
 }
 
-/* this must be called inside a transaction, and requires the 
+/* this must be called inside a transaction, and requires the
 ** kernel_lock to be held
 */
 void reiserfs_block_writes(struct reiserfs_transaction_handle *th)
@@ -2970,7 +2977,7 @@ static void wake_queued_writers(struct super_block *s)
                wake_up(&journal->j_join_wait);
 }
 
-static void let_transaction_grow(struct super_block *sb, unsigned long trans_id)
+static void let_transaction_grow(struct super_block *sb, unsigned int trans_id)
 {
        struct reiserfs_journal *journal = SB_JOURNAL(sb);
        unsigned long bcount = journal->j_bcount;
@@ -2997,43 +3004,43 @@ static void let_transaction_grow(struct super_block *sb, unsigned long trans_id)
 ** expect to use in nblocks.
 */
 static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
-                             struct super_block *p_s_sb, unsigned long nblocks,
+                             struct super_block *sb, unsigned long nblocks,
                              int join)
 {
        time_t now = get_seconds();
-       int old_trans_id;
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       unsigned int old_trans_id;
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
        struct reiserfs_transaction_handle myth;
        int sched_count = 0;
        int retval;
 
-       reiserfs_check_lock_depth(p_s_sb, "journal_begin");
+       reiserfs_check_lock_depth(sb, "journal_begin");
        BUG_ON(nblocks > journal->j_trans_max);
 
-       PROC_INFO_INC(p_s_sb, journal.journal_being);
+       PROC_INFO_INC(sb, journal.journal_being);
        /* set here for journal_join */
        th->t_refcount = 1;
-       th->t_super = p_s_sb;
+       th->t_super = sb;
 
       relock:
-       lock_journal(p_s_sb);
+       lock_journal(sb);
        if (join != JBEGIN_ABORT && reiserfs_is_journal_aborted(journal)) {
-               unlock_journal(p_s_sb);
+               unlock_journal(sb);
                retval = journal->j_errno;
                goto out_fail;
        }
        journal->j_bcount++;
 
        if (test_bit(J_WRITERS_BLOCKED, &journal->j_state)) {
-               unlock_journal(p_s_sb);
-               reiserfs_wait_on_write_block(p_s_sb);
-               PROC_INFO_INC(p_s_sb, journal.journal_relock_writers);
+               unlock_journal(sb);
+               reiserfs_wait_on_write_block(sb);
+               PROC_INFO_INC(sb, journal.journal_relock_writers);
                goto relock;
        }
        now = get_seconds();
 
        /* if there is no room in the journal OR
-        ** if this transaction is too old, and we weren't called joinable, wait for it to finish before beginning 
+        ** if this transaction is too old, and we weren't called joinable, wait for it to finish before beginning
         ** we don't sleep if there aren't other writers
         */
 
@@ -3048,7 +3055,7 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
            || (!join && journal->j_cnode_free < (journal->j_trans_max * 3))) {
 
                old_trans_id = journal->j_trans_id;
-               unlock_journal(p_s_sb); /* allow others to finish this transaction */
+               unlock_journal(sb);     /* allow others to finish this transaction */
 
                if (!join && (journal->j_len_alloc + nblocks + 2) >=
                    journal->j_max_batch &&
@@ -3056,7 +3063,7 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
                    (journal->j_len_alloc * 75)) {
                        if (atomic_read(&journal->j_wcount) > 10) {
                                sched_count++;
-                               queue_log_writer(p_s_sb);
+                               queue_log_writer(sb);
                                goto relock;
                        }
                }
@@ -3066,25 +3073,25 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
                if (atomic_read(&journal->j_jlock)) {
                        while (journal->j_trans_id == old_trans_id &&
                               atomic_read(&journal->j_jlock)) {
-                               queue_log_writer(p_s_sb);
+                               queue_log_writer(sb);
                        }
                        goto relock;
                }
-               retval = journal_join(&myth, p_s_sb, 1);
+               retval = journal_join(&myth, sb, 1);
                if (retval)
                        goto out_fail;
 
                /* someone might have ended the transaction while we joined */
                if (old_trans_id != journal->j_trans_id) {
-                       retval = do_journal_end(&myth, p_s_sb, 1, 0);
+                       retval = do_journal_end(&myth, sb, 1, 0);
                } else {
-                       retval = do_journal_end(&myth, p_s_sb, 1, COMMIT_NOW);
+                       retval = do_journal_end(&myth, sb, 1, COMMIT_NOW);
                }
 
                if (retval)
                        goto out_fail;
 
-               PROC_INFO_INC(p_s_sb, journal.journal_relock_wcount);
+               PROC_INFO_INC(sb, journal.journal_relock_wcount);
                goto relock;
        }
        /* we are the first writer, set trans_id */
@@ -3096,7 +3103,7 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
        th->t_blocks_logged = 0;
        th->t_blocks_allocated = nblocks;
        th->t_trans_id = journal->j_trans_id;
-       unlock_journal(p_s_sb);
+       unlock_journal(sb);
        INIT_LIST_HEAD(&th->t_list);
        get_fs_excl();
        return 0;
@@ -3106,7 +3113,7 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
        /* Re-set th->t_super, so we can properly keep track of how many
         * persistent transactions there are. We need to do this so if this
         * call is part of a failed restart_transaction, we can free it later */
-       th->t_super = p_s_sb;
+       th->t_super = sb;
        return retval;
 }
 
@@ -3157,7 +3164,7 @@ int reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *th)
 }
 
 static int journal_join(struct reiserfs_transaction_handle *th,
-                       struct super_block *p_s_sb, unsigned long nblocks)
+                       struct super_block *sb, unsigned long nblocks)
 {
        struct reiserfs_transaction_handle *cur_th = current->journal_info;
 
@@ -3166,11 +3173,11 @@ static int journal_join(struct reiserfs_transaction_handle *th,
         */
        th->t_handle_save = cur_th;
        BUG_ON(cur_th && cur_th->t_refcount > 1);
-       return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_JOIN);
+       return do_journal_begin_r(th, sb, nblocks, JBEGIN_JOIN);
 }
 
 int journal_join_abort(struct reiserfs_transaction_handle *th,
-                      struct super_block *p_s_sb, unsigned long nblocks)
+                      struct super_block *sb, unsigned long nblocks)
 {
        struct reiserfs_transaction_handle *cur_th = current->journal_info;
 
@@ -3179,11 +3186,11 @@ int journal_join_abort(struct reiserfs_transaction_handle *th,
         */
        th->t_handle_save = cur_th;
        BUG_ON(cur_th && cur_th->t_refcount > 1);
-       return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_ABORT);
+       return do_journal_begin_r(th, sb, nblocks, JBEGIN_ABORT);
 }
 
 int journal_begin(struct reiserfs_transaction_handle *th,
-                 struct super_block *p_s_sb, unsigned long nblocks)
+                 struct super_block *sb, unsigned long nblocks)
 {
        struct reiserfs_transaction_handle *cur_th = current->journal_info;
        int ret;
@@ -3191,28 +3198,29 @@ int journal_begin(struct reiserfs_transaction_handle *th,
        th->t_handle_save = NULL;
        if (cur_th) {
                /* we are nesting into the current transaction */
-               if (cur_th->t_super == p_s_sb) {
+               if (cur_th->t_super == sb) {
                        BUG_ON(!cur_th->t_refcount);
                        cur_th->t_refcount++;
                        memcpy(th, cur_th, sizeof(*th));
                        if (th->t_refcount <= 1)
-                               reiserfs_warning(p_s_sb,
-                                                "BAD: refcount <= 1, but journal_info != 0");
+                               reiserfs_warning(sb, "reiserfs-2005",
+                                                "BAD: refcount <= 1, but "
+                                                "journal_info != 0");
                        return 0;
                } else {
                        /* we've ended up with a handle from a different filesystem.
                         ** save it and restore on journal_end.  This should never
                         ** really happen...
                         */
-                       reiserfs_warning(p_s_sb,
-                                        "clm-2100: nesting info a different FS");
+                       reiserfs_warning(sb, "clm-2100",
+                                        "nesting info a different FS");
                        th->t_handle_save = current->journal_info;
                        current->journal_info = th;
                }
        } else {
                current->journal_info = th;
        }
-       ret = do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_REG);
+       ret = do_journal_begin_r(th, sb, nblocks, JBEGIN_REG);
        BUG_ON(current->journal_info != th);
 
        /* I guess this boils down to being the reciprocal of clm-2100 above.
@@ -3232,32 +3240,32 @@ int journal_begin(struct reiserfs_transaction_handle *th,
 **
 ** if it was dirty, cleans and files onto the clean list.  I can't let it be dirty again until the
 ** transaction is committed.
-** 
+**
 ** if j_len, is bigger than j_len_alloc, it pushes j_len_alloc to 10 + j_len.
 */
 int journal_mark_dirty(struct reiserfs_transaction_handle *th,
-                      struct super_block *p_s_sb, struct buffer_head *bh)
+                      struct super_block *sb, struct buffer_head *bh)
 {
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
        struct reiserfs_journal_cnode *cn = NULL;
        int count_already_incd = 0;
        int prepared = 0;
        BUG_ON(!th->t_trans_id);
 
-       PROC_INFO_INC(p_s_sb, journal.mark_dirty);
+       PROC_INFO_INC(sb, journal.mark_dirty);
        if (th->t_trans_id != journal->j_trans_id) {
-               reiserfs_panic(th->t_super,
-                              "journal-1577: handle trans id %ld != current trans id %ld\n",
+               reiserfs_panic(th->t_super, "journal-1577",
+                              "handle trans id %ld != current trans id %ld",
                               th->t_trans_id, journal->j_trans_id);
        }
 
-       p_s_sb->s_dirt = 1;
+       sb->s_dirt = 1;
 
        prepared = test_clear_buffer_journal_prepared(bh);
        clear_buffer_journal_restore_dirty(bh);
        /* already in this transaction, we are done */
        if (buffer_journaled(bh)) {
-               PROC_INFO_INC(p_s_sb, journal.mark_dirty_already);
+               PROC_INFO_INC(sb, journal.mark_dirty_already);
                return 0;
        }
 
@@ -3266,7 +3274,8 @@ int journal_mark_dirty(struct reiserfs_transaction_handle *th,
         ** could get to disk too early.  NOT GOOD.
         */
        if (!prepared || buffer_dirty(bh)) {
-               reiserfs_warning(p_s_sb, "journal-1777: buffer %llu bad state "
+               reiserfs_warning(sb, "journal-1777",
+                                "buffer %llu bad state "
                                 "%cPREPARED %cLOCKED %cDIRTY %cJDIRTY_WAIT",
                                 (unsigned long long)bh->b_blocknr,
                                 prepared ? ' ' : '!',
@@ -3276,23 +3285,23 @@ int journal_mark_dirty(struct reiserfs_transaction_handle *th,
        }
 
        if (atomic_read(&(journal->j_wcount)) <= 0) {
-               reiserfs_warning(p_s_sb,
-                                "journal-1409: journal_mark_dirty returning because j_wcount was %d",
+               reiserfs_warning(sb, "journal-1409",
+                                "returning because j_wcount was %d",
                                 atomic_read(&(journal->j_wcount)));
                return 1;
        }
-       /* this error means I've screwed up, and we've overflowed the transaction.  
+       /* this error means I've screwed up, and we've overflowed the transaction.
         ** Nothing can be done here, except make the FS readonly or panic.
         */
        if (journal->j_len >= journal->j_trans_max) {
-               reiserfs_panic(th->t_super,
-                              "journal-1413: journal_mark_dirty: j_len (%lu) is too big\n",
+               reiserfs_panic(th->t_super, "journal-1413",
+                              "j_len (%lu) is too big",
                               journal->j_len);
        }
 
        if (buffer_journal_dirty(bh)) {
                count_already_incd = 1;
-               PROC_INFO_INC(p_s_sb, journal.mark_dirty_notjournal);
+               PROC_INFO_INC(sb, journal.mark_dirty_notjournal);
                clear_buffer_journal_dirty(bh);
        }
 
@@ -3304,9 +3313,9 @@ int journal_mark_dirty(struct reiserfs_transaction_handle *th,
 
        /* now put this guy on the end */
        if (!cn) {
-               cn = get_cnode(p_s_sb);
+               cn = get_cnode(sb);
                if (!cn) {
-                       reiserfs_panic(p_s_sb, "get_cnode failed!\n");
+                       reiserfs_panic(sb, "journal-4", "get_cnode failed!");
                }
 
                if (th->t_blocks_logged == th->t_blocks_allocated) {
@@ -3318,7 +3327,7 @@ int journal_mark_dirty(struct reiserfs_transaction_handle *th,
 
                cn->bh = bh;
                cn->blocknr = bh->b_blocknr;
-               cn->sb = p_s_sb;
+               cn->sb = sb;
                cn->jlist = NULL;
                insert_journal_hash(journal->j_hash_table, cn);
                if (!count_already_incd) {
@@ -3339,11 +3348,11 @@ int journal_mark_dirty(struct reiserfs_transaction_handle *th,
 }
 
 int journal_end(struct reiserfs_transaction_handle *th,
-               struct super_block *p_s_sb, unsigned long nblocks)
+               struct super_block *sb, unsigned long nblocks)
 {
        if (!current->journal_info && th->t_refcount > 1)
-               reiserfs_warning(p_s_sb, "REISER-NESTING: th NULL, refcount %d",
-                                th->t_refcount);
+               reiserfs_warning(sb, "REISER-NESTING",
+                                "th NULL, refcount %d", th->t_refcount);
 
        if (!th->t_trans_id) {
                WARN_ON(1);
@@ -3366,26 +3375,26 @@ int journal_end(struct reiserfs_transaction_handle *th,
                }
                return 0;
        } else {
-               return do_journal_end(th, p_s_sb, nblocks, 0);
+               return do_journal_end(th, sb, nblocks, 0);
        }
 }
 
-/* removes from the current transaction, relsing and descrementing any counters.  
+/* removes from the current transaction, relsing and descrementing any counters.
 ** also files the removed buffer directly onto the clean list
 **
 ** called by journal_mark_freed when a block has been deleted
 **
 ** returns 1 if it cleaned and relsed the buffer. 0 otherwise
 */
-static int remove_from_transaction(struct super_block *p_s_sb,
+static int remove_from_transaction(struct super_block *sb,
                                   b_blocknr_t blocknr, int already_cleaned)
 {
        struct buffer_head *bh;
        struct reiserfs_journal_cnode *cn;
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
        int ret = 0;
 
-       cn = get_journal_hash_dev(p_s_sb, journal->j_hash_table, blocknr);
+       cn = get_journal_hash_dev(sb, journal->j_hash_table, blocknr);
        if (!cn || !cn->bh) {
                return ret;
        }
@@ -3403,7 +3412,7 @@ static int remove_from_transaction(struct super_block *p_s_sb,
                journal->j_last = cn->prev;
        }
        if (bh)
-               remove_journal_hash(p_s_sb, journal->j_hash_table, NULL,
+               remove_journal_hash(sb, journal->j_hash_table, NULL,
                                    bh->b_blocknr, 0);
        clear_buffer_journaled(bh);     /* don't log this one */
 
@@ -3413,14 +3422,14 @@ static int remove_from_transaction(struct super_block *p_s_sb,
                clear_buffer_journal_test(bh);
                put_bh(bh);
                if (atomic_read(&(bh->b_count)) < 0) {
-                       reiserfs_warning(p_s_sb,
-                                        "journal-1752: remove from trans, b_count < 0");
+                       reiserfs_warning(sb, "journal-1752",
+                                        "b_count < 0");
                }
                ret = 1;
        }
        journal->j_len--;
        journal->j_len_alloc--;
-       free_cnode(p_s_sb, cn);
+       free_cnode(sb, cn);
        return ret;
 }
 
@@ -3468,22 +3477,22 @@ static int can_dirty(struct reiserfs_journal_cnode *cn)
 }
 
 /* syncs the commit blocks, but does not force the real buffers to disk
-** will wait until the current transaction is done/committed before returning 
+** will wait until the current transaction is done/committed before returning
 */
 int journal_end_sync(struct reiserfs_transaction_handle *th,
-                    struct super_block *p_s_sb, unsigned long nblocks)
+                    struct super_block *sb, unsigned long nblocks)
 {
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
 
        BUG_ON(!th->t_trans_id);
        /* you can sync while nested, very, very bad */
        BUG_ON(th->t_refcount > 1);
        if (journal->j_len == 0) {
-               reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb),
+               reiserfs_prepare_for_journal(sb, SB_BUFFER_WITH_SB(sb),
                                             1);
-               journal_mark_dirty(th, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb));
+               journal_mark_dirty(th, sb, SB_BUFFER_WITH_SB(sb));
        }
-       return do_journal_end(th, p_s_sb, nblocks, COMMIT_NOW | WAIT);
+       return do_journal_end(th, sb, nblocks, COMMIT_NOW | WAIT);
 }
 
 /*
@@ -3493,7 +3502,7 @@ static void flush_async_commits(struct work_struct *work)
 {
        struct reiserfs_journal *journal =
                container_of(work, struct reiserfs_journal, j_work.work);
-       struct super_block *p_s_sb = journal->j_work_sb;
+       struct super_block *sb = journal->j_work_sb;
        struct reiserfs_journal_list *jl;
        struct list_head *entry;
 
@@ -3502,7 +3511,7 @@ static void flush_async_commits(struct work_struct *work)
                /* last entry is the youngest, commit it and you get everything */
                entry = journal->j_journal_list.prev;
                jl = JOURNAL_LIST_ENTRY(entry);
-               flush_commit_list(p_s_sb, jl, 1);
+               flush_commit_list(sb, jl, 1);
        }
        unlock_kernel();
 }
@@ -3511,11 +3520,11 @@ static void flush_async_commits(struct work_struct *work)
 ** flushes any old transactions to disk
 ** ends the current transaction if it is too old
 */
-int reiserfs_flush_old_commits(struct super_block *p_s_sb)
+int reiserfs_flush_old_commits(struct super_block *sb)
 {
        time_t now;
        struct reiserfs_transaction_handle th;
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
 
        now = get_seconds();
        /* safety check so we don't flush while we are replaying the log during
@@ -3532,35 +3541,35 @@ int reiserfs_flush_old_commits(struct super_block *p_s_sb)
            journal->j_trans_start_time > 0 &&
            journal->j_len > 0 &&
            (now - journal->j_trans_start_time) > journal->j_max_trans_age) {
-               if (!journal_join(&th, p_s_sb, 1)) {
-                       reiserfs_prepare_for_journal(p_s_sb,
-                                                    SB_BUFFER_WITH_SB(p_s_sb),
+               if (!journal_join(&th, sb, 1)) {
+                       reiserfs_prepare_for_journal(sb,
+                                                    SB_BUFFER_WITH_SB(sb),
                                                     1);
-                       journal_mark_dirty(&th, p_s_sb,
-                                          SB_BUFFER_WITH_SB(p_s_sb));
+                       journal_mark_dirty(&th, sb,
+                                          SB_BUFFER_WITH_SB(sb));
 
                        /* we're only being called from kreiserfsd, it makes no sense to do
                         ** an async commit so that kreiserfsd can do it later
                         */
-                       do_journal_end(&th, p_s_sb, 1, COMMIT_NOW | WAIT);
+                       do_journal_end(&th, sb, 1, COMMIT_NOW | WAIT);
                }
        }
-       return p_s_sb->s_dirt;
+       return sb->s_dirt;
 }
 
 /*
 ** returns 0 if do_journal_end should return right away, returns 1 if do_journal_end should finish the commit
-** 
-** if the current transaction is too old, but still has writers, this will wait on j_join_wait until all 
+**
+** if the current transaction is too old, but still has writers, this will wait on j_join_wait until all
 ** the writers are done.  By the time it wakes up, the transaction it was called has already ended, so it just
 ** flushes the commit list and returns 0.
 **
 ** Won't batch when flush or commit_now is set.  Also won't batch when others are waiting on j_join_wait.
-** 
+**
 ** Note, we can't allow the journal_end to proceed while there are still writers in the log.
 */
 static int check_journal_end(struct reiserfs_transaction_handle *th,
-                            struct super_block *p_s_sb, unsigned long nblocks,
+                            struct super_block *sb, unsigned long nblocks,
                             int flags)
 {
 
@@ -3569,13 +3578,13 @@ static int check_journal_end(struct reiserfs_transaction_handle *th,
        int commit_now = flags & COMMIT_NOW;
        int wait_on_commit = flags & WAIT;
        struct reiserfs_journal_list *jl;
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
 
        BUG_ON(!th->t_trans_id);
 
        if (th->t_trans_id != journal->j_trans_id) {
-               reiserfs_panic(th->t_super,
-                              "journal-1577: handle trans id %ld != current trans id %ld\n",
+               reiserfs_panic(th->t_super, "journal-1577",
+                              "handle trans id %ld != current trans id %ld",
                               th->t_trans_id, journal->j_trans_id);
        }
 
@@ -3584,7 +3593,7 @@ static int check_journal_end(struct reiserfs_transaction_handle *th,
                atomic_dec(&(journal->j_wcount));
        }
 
-       /* BUG, deal with case where j_len is 0, but people previously freed blocks need to be released 
+       /* BUG, deal with case where j_len is 0, but people previously freed blocks need to be released
         ** will be dealt with by next transaction that actually writes something, but should be taken
         ** care of in this trans
         */
@@ -3593,7 +3602,7 @@ static int check_journal_end(struct reiserfs_transaction_handle *th,
        /* if wcount > 0, and we are called to with flush or commit_now,
         ** we wait on j_join_wait.  We will wake up when the last writer has
         ** finished the transaction, and started it on its way to the disk.
-        ** Then, we flush the commit or journal list, and just return 0 
+        ** Then, we flush the commit or journal list, and just return 0
         ** because the rest of journal end was already done for this transaction.
         */
        if (atomic_read(&(journal->j_wcount)) > 0) {
@@ -3608,31 +3617,31 @@ static int check_journal_end(struct reiserfs_transaction_handle *th,
                        if (flush) {
                                journal->j_next_full_flush = 1;
                        }
-                       unlock_journal(p_s_sb);
+                       unlock_journal(sb);
 
                        /* sleep while the current transaction is still j_jlocked */
                        while (journal->j_trans_id == trans_id) {
                                if (atomic_read(&journal->j_jlock)) {
-                                       queue_log_writer(p_s_sb);
+                                       queue_log_writer(sb);
                                } else {
-                                       lock_journal(p_s_sb);
+                                       lock_journal(sb);
                                        if (journal->j_trans_id == trans_id) {
                                                atomic_set(&(journal->j_jlock),
                                                           1);
                                        }
-                                       unlock_journal(p_s_sb);
+                                       unlock_journal(sb);
                                }
                        }
                        BUG_ON(journal->j_trans_id == trans_id);
                        
                        if (commit_now
-                           && journal_list_still_alive(p_s_sb, trans_id)
+                           && journal_list_still_alive(sb, trans_id)
                            && wait_on_commit) {
-                               flush_commit_list(p_s_sb, jl, 1);
+                               flush_commit_list(sb, jl, 1);
                        }
                        return 0;
                }
-               unlock_journal(p_s_sb);
+               unlock_journal(sb);
                return 0;
        }
 
@@ -3649,13 +3658,13 @@ static int check_journal_end(struct reiserfs_transaction_handle *th,
            && journal->j_len_alloc < journal->j_max_batch
            && journal->j_cnode_free > (journal->j_trans_max * 3)) {
                journal->j_bcount++;
-               unlock_journal(p_s_sb);
+               unlock_journal(sb);
                return 0;
        }
 
-       if (journal->j_start > SB_ONDISK_JOURNAL_SIZE(p_s_sb)) {
-               reiserfs_panic(p_s_sb,
-                              "journal-003: journal_end: j_start (%ld) is too high\n",
+       if (journal->j_start > SB_ONDISK_JOURNAL_SIZE(sb)) {
+               reiserfs_panic(sb, "journal-003",
+                              "j_start (%ld) is too high",
                               journal->j_start);
        }
        return 1;
@@ -3664,7 +3673,7 @@ static int check_journal_end(struct reiserfs_transaction_handle *th,
 /*
 ** Does all the work that makes deleting blocks safe.
 ** when deleting a block mark BH_JNew, just remove it from the current transaction, clean it's buffer_head and move on.
-** 
+**
 ** otherwise:
 ** set a bit for the block in the journal bitmap.  That will prevent it from being allocated for unformatted nodes
 ** before this transaction has finished.
@@ -3676,16 +3685,16 @@ static int check_journal_end(struct reiserfs_transaction_handle *th,
 ** Then remove it from the current transaction, decrementing any counters and filing it on the clean list.
 */
 int journal_mark_freed(struct reiserfs_transaction_handle *th,
-                      struct super_block *p_s_sb, b_blocknr_t blocknr)
+                      struct super_block *sb, b_blocknr_t blocknr)
 {
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
        struct reiserfs_journal_cnode *cn = NULL;
        struct buffer_head *bh = NULL;
        struct reiserfs_list_bitmap *jb = NULL;
        int cleaned = 0;
        BUG_ON(!th->t_trans_id);
 
-       cn = get_journal_hash_dev(p_s_sb, journal->j_hash_table, blocknr);
+       cn = get_journal_hash_dev(sb, journal->j_hash_table, blocknr);
        if (cn && cn->bh) {
                bh = cn->bh;
                get_bh(bh);
@@ -3695,15 +3704,15 @@ int journal_mark_freed(struct reiserfs_transaction_handle *th,
                clear_buffer_journal_new(bh);
                clear_prepared_bits(bh);
                reiserfs_clean_and_file_buffer(bh);
-               cleaned = remove_from_transaction(p_s_sb, blocknr, cleaned);
+               cleaned = remove_from_transaction(sb, blocknr, cleaned);
        } else {
                /* set the bit for this block in the journal bitmap for this transaction */
                jb = journal->j_current_jl->j_list_bitmap;
                if (!jb) {
-                       reiserfs_panic(p_s_sb,
-                                      "journal-1702: journal_mark_freed, journal_list_bitmap is NULL\n");
+                       reiserfs_panic(sb, "journal-1702",
+                                      "journal_list_bitmap is NULL");
                }
-               set_bit_in_list_bitmap(p_s_sb, blocknr, jb);
+               set_bit_in_list_bitmap(sb, blocknr, jb);
 
                /* Note, the entire while loop is not allowed to schedule.  */
 
@@ -3711,13 +3720,13 @@ int journal_mark_freed(struct reiserfs_transaction_handle *th,
                        clear_prepared_bits(bh);
                        reiserfs_clean_and_file_buffer(bh);
                }
-               cleaned = remove_from_transaction(p_s_sb, blocknr, cleaned);
+               cleaned = remove_from_transaction(sb, blocknr, cleaned);
 
                /* find all older transactions with this block, make sure they don't try to write it out */
-               cn = get_journal_hash_dev(p_s_sb, journal->j_list_hash_table,
+               cn = get_journal_hash_dev(sb, journal->j_list_hash_table,
                                          blocknr);
                while (cn) {
-                       if (p_s_sb == cn->sb && blocknr == cn->blocknr) {
+                       if (sb == cn->sb && blocknr == cn->blocknr) {
                                set_bit(BLOCK_FREED, &cn->state);
                                if (cn->bh) {
                                        if (!cleaned) {
@@ -3733,8 +3742,9 @@ int journal_mark_freed(struct reiserfs_transaction_handle *th,
                                                put_bh(cn->bh);
                                                if (atomic_read
                                                    (&(cn->bh->b_count)) < 0) {
-                                                       reiserfs_warning(p_s_sb,
-                                                                        "journal-2138: cn->bh->b_count < 0");
+                                                       reiserfs_warning(sb,
+                                                                "journal-2138",
+                                                                "cn->bh->b_count < 0");
                                                }
                                        }
                                        if (cn->jlist) {        /* since we are clearing the bh, we MUST dec nonzerolen */
@@ -3824,7 +3834,7 @@ static int __commit_trans_jl(struct inode *inode, unsigned long id,
 
 int reiserfs_commit_for_inode(struct inode *inode)
 {
-       unsigned long id = REISERFS_I(inode)->i_trans_id;
+       unsigned int id = REISERFS_I(inode)->i_trans_id;
        struct reiserfs_journal_list *jl = REISERFS_I(inode)->i_jl;
 
        /* for the whole inode, assume unset id means it was
@@ -3839,18 +3849,18 @@ int reiserfs_commit_for_inode(struct inode *inode)
        return __commit_trans_jl(inode, id, jl);
 }
 
-void reiserfs_restore_prepared_buffer(struct super_block *p_s_sb,
+void reiserfs_restore_prepared_buffer(struct super_block *sb,
                                      struct buffer_head *bh)
 {
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
-       PROC_INFO_INC(p_s_sb, journal.restore_prepared);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
+       PROC_INFO_INC(sb, journal.restore_prepared);
        if (!bh) {
                return;
        }
        if (test_clear_buffer_journal_restore_dirty(bh) &&
            buffer_journal_dirty(bh)) {
                struct reiserfs_journal_cnode *cn;
-               cn = get_journal_hash_dev(p_s_sb,
+               cn = get_journal_hash_dev(sb,
                                          journal->j_list_hash_table,
                                          bh->b_blocknr);
                if (cn && can_dirty(cn)) {
@@ -3867,12 +3877,12 @@ extern struct tree_balance *cur_tb;
 ** be written to disk while we are altering it.  So, we must:
 ** clean it
 ** wait on it.
-** 
+**
 */
-int reiserfs_prepare_for_journal(struct super_block *p_s_sb,
+int reiserfs_prepare_for_journal(struct super_block *sb,
                                 struct buffer_head *bh, int wait)
 {
-       PROC_INFO_INC(p_s_sb, journal.prepare);
+       PROC_INFO_INC(sb, journal.prepare);
 
        if (!trylock_buffer(bh)) {
                if (!wait)
@@ -3909,7 +3919,7 @@ static void flush_old_journal_lists(struct super_block *s)
        }
 }
 
-/* 
+/*
 ** long and ugly.  If flush, will not return until all commit
 ** blocks and all real buffers in the trans are on disk.
 ** If no_async, won't return until all commit blocks are on disk.
@@ -3920,10 +3930,10 @@ static void flush_old_journal_lists(struct super_block *s)
 ** journal lists, etc just won't happen.
 */
 static int do_journal_end(struct reiserfs_transaction_handle *th,
-                         struct super_block *p_s_sb, unsigned long nblocks,
+                         struct super_block *sb, unsigned long nblocks,
                          int flags)
 {
-       struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+       struct reiserfs_journal *journal = SB_JOURNAL(sb);
        struct reiserfs_journal_cnode *cn, *next, *jl_cn;
        struct reiserfs_journal_cnode *last_cn = NULL;
        struct reiserfs_journal_desc *desc;
@@ -3938,7 +3948,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
        struct reiserfs_journal_list *jl, *temp_jl;
        struct list_head *entry, *safe;
        unsigned long jindex;
-       unsigned long commit_trans_id;
+       unsigned int commit_trans_id;
        int trans_half;
 
        BUG_ON(th->t_refcount > 1);
@@ -3946,21 +3956,21 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
 
        /* protect flush_older_commits from doing mistakes if the
            transaction ID counter gets overflowed.  */
-       if (th->t_trans_id == ~0UL)
+       if (th->t_trans_id == ~0U)
                flags |= FLUSH_ALL | COMMIT_NOW | WAIT;
        flush = flags & FLUSH_ALL;
        wait_on_commit = flags & WAIT;
 
        put_fs_excl();
        current->journal_info = th->t_handle_save;
-       reiserfs_check_lock_depth(p_s_sb, "journal end");
+       reiserfs_check_lock_depth(sb, "journal end");
        if (journal->j_len == 0) {
-               reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb),
+               reiserfs_prepare_for_journal(sb, SB_BUFFER_WITH_SB(sb),
                                             1);
-               journal_mark_dirty(th, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb));
+               journal_mark_dirty(th, sb, SB_BUFFER_WITH_SB(sb));
        }
 
-       lock_journal(p_s_sb);
+       lock_journal(sb);
        if (journal->j_next_full_flush) {
                flags |= FLUSH_ALL;
                flush = 1;
@@ -3970,13 +3980,13 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
                wait_on_commit = 1;
        }
 
-       /* check_journal_end locks the journal, and unlocks if it does not return 1 
+       /* check_journal_end locks the journal, and unlocks if it does not return 1
         ** it tells us if we should continue with the journal_end, or just return
         */
-       if (!check_journal_end(th, p_s_sb, nblocks, flags)) {
-               p_s_sb->s_dirt = 1;
-               wake_queued_writers(p_s_sb);
-               reiserfs_async_progress_wait(p_s_sb);
+       if (!check_journal_end(th, sb, nblocks, flags)) {
+               sb->s_dirt = 1;
+               wake_queued_writers(sb);
+               reiserfs_async_progress_wait(sb);
                goto out;
        }
 
@@ -4005,8 +4015,8 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
 
        /* setup description block */
        d_bh =
-           journal_getblk(p_s_sb,
-                          SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+           journal_getblk(sb,
+                          SB_ONDISK_JOURNAL_1st_BLOCK(sb) +
                           journal->j_start);
        set_buffer_uptodate(d_bh);
        desc = (struct reiserfs_journal_desc *)(d_bh)->b_data;
@@ -4015,9 +4025,9 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
        set_desc_trans_id(desc, journal->j_trans_id);
 
        /* setup commit block.  Don't write (keep it clean too) this one until after everyone else is written */
-       c_bh = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+       c_bh = journal_getblk(sb, SB_ONDISK_JOURNAL_1st_BLOCK(sb) +
                              ((journal->j_start + journal->j_len +
-                               1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)));
+                               1) % SB_ONDISK_JOURNAL_SIZE(sb)));
        commit = (struct reiserfs_journal_commit *)c_bh->b_data;
        memset(c_bh->b_data, 0, c_bh->b_size);
        set_commit_trans_id(commit, journal->j_trans_id);
@@ -4050,13 +4060,13 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
         **  for each real block, add it to the journal list hash,
         ** copy into real block index array in the commit or desc block
         */
-       trans_half = journal_trans_half(p_s_sb->s_blocksize);
+       trans_half = journal_trans_half(sb->s_blocksize);
        for (i = 0, cn = journal->j_first; cn; cn = cn->next, i++) {
                if (buffer_journaled(cn->bh)) {
-                       jl_cn = get_cnode(p_s_sb);
+                       jl_cn = get_cnode(sb);
                        if (!jl_cn) {
-                               reiserfs_panic(p_s_sb,
-                                              "journal-1676, get_cnode returned NULL\n");
+                               reiserfs_panic(sb, "journal-1676",
+                                              "get_cnode returned NULL");
                        }
                        if (i == 0) {
                                jl->j_realblock = jl_cn;
@@ -4067,18 +4077,19 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
                                last_cn->next = jl_cn;
                        }
                        last_cn = jl_cn;
-                       /* make sure the block we are trying to log is not a block 
+                       /* make sure the block we are trying to log is not a block
                           of journal or reserved area */
 
                        if (is_block_in_log_or_reserved_area
-                           (p_s_sb, cn->bh->b_blocknr)) {
-                               reiserfs_panic(p_s_sb,
-                                              "journal-2332: Trying to log block %lu, which is a log block\n",
+                           (sb, cn->bh->b_blocknr)) {
+                               reiserfs_panic(sb, "journal-2332",
+                                              "Trying to log block %lu, "
+                                              "which is a log block",
                                               cn->bh->b_blocknr);
                        }
                        jl_cn->blocknr = cn->bh->b_blocknr;
                        jl_cn->state = 0;
-                       jl_cn->sb = p_s_sb;
+                       jl_cn->sb = sb;
                        jl_cn->bh = cn->bh;
                        jl_cn->jlist = jl;
                        insert_journal_hash(journal->j_list_hash_table, jl_cn);
@@ -4119,11 +4130,11 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
                        char *addr;
                        struct page *page;
                        tmp_bh =
-                           journal_getblk(p_s_sb,
-                                          SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+                           journal_getblk(sb,
+                                          SB_ONDISK_JOURNAL_1st_BLOCK(sb) +
                                           ((cur_write_start +
                                             jindex) %
-                                           SB_ONDISK_JOURNAL_SIZE(p_s_sb)));
+                                           SB_ONDISK_JOURNAL_SIZE(sb)));
                        set_buffer_uptodate(tmp_bh);
                        page = cn->bh->b_page;
                        addr = kmap(page);
@@ -4137,12 +4148,13 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
                        clear_buffer_journaled(cn->bh);
                } else {
                        /* JDirty cleared sometime during transaction.  don't log this one */
-                       reiserfs_warning(p_s_sb,
-                                        "journal-2048: do_journal_end: BAD, buffer in journal hash, but not JDirty!");
+                       reiserfs_warning(sb, "journal-2048",
+                                        "BAD, buffer in journal hash, "
+                                        "but not JDirty!");
                        brelse(cn->bh);
                }
                next = cn->next;
-               free_cnode(p_s_sb, cn);
+               free_cnode(sb, cn);
                cn = next;
                cond_resched();
        }
@@ -4152,7 +4164,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
         ** so we dirty/relse c_bh in flush_commit_list, with commit_left <= 1.
         */
 
-       journal->j_current_jl = alloc_journal_list(p_s_sb);
+       journal->j_current_jl = alloc_journal_list(sb);
 
        /* now it is safe to insert this transaction on the main list */
        list_add_tail(&jl->j_list, &journal->j_journal_list);
@@ -4163,7 +4175,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
        old_start = journal->j_start;
        journal->j_start =
            (journal->j_start + journal->j_len +
-            2) % SB_ONDISK_JOURNAL_SIZE(p_s_sb);
+            2) % SB_ONDISK_JOURNAL_SIZE(sb);
        atomic_set(&(journal->j_wcount), 0);
        journal->j_bcount = 0;
        journal->j_last = NULL;
@@ -4178,7 +4190,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
        journal->j_len_alloc = 0;
        journal->j_next_full_flush = 0;
        journal->j_next_async_flush = 0;
-       init_journal_hash(p_s_sb);
+       init_journal_hash(sb);
 
        // make sure reiserfs_add_jh sees the new current_jl before we
        // write out the tails
@@ -4207,14 +4219,14 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
         ** queue don't wait for this proc to flush journal lists and such.
         */
        if (flush) {
-               flush_commit_list(p_s_sb, jl, 1);
-               flush_journal_list(p_s_sb, jl, 1);
+               flush_commit_list(sb, jl, 1);
+               flush_journal_list(sb, jl, 1);
        } else if (!(jl->j_state & LIST_COMMIT_PENDING))
                queue_delayed_work(commit_wq, &journal->j_work, HZ / 10);
 
-       /* if the next transaction has any chance of wrapping, flush 
-        ** transactions that might get overwritten.  If any journal lists are very 
-        ** old flush them as well.  
+       /* if the next transaction has any chance of wrapping, flush
+        ** transactions that might get overwritten.  If any journal lists are very
+        ** old flush them as well.
         */
       first_jl:
        list_for_each_safe(entry, safe, &journal->j_journal_list) {
@@ -4222,11 +4234,11 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
                if (journal->j_start <= temp_jl->j_start) {
                        if ((journal->j_start + journal->j_trans_max + 1) >=
                            temp_jl->j_start) {
-                               flush_used_journal_lists(p_s_sb, temp_jl);
+                               flush_used_journal_lists(sb, temp_jl);
                                goto first_jl;
                        } else if ((journal->j_start +
                                    journal->j_trans_max + 1) <
-                                  SB_ONDISK_JOURNAL_SIZE(p_s_sb)) {
+                                  SB_ONDISK_JOURNAL_SIZE(sb)) {
                                /* if we don't cross into the next transaction and we don't
                                 * wrap, there is no way we can overlap any later transactions
                                 * break now
@@ -4235,11 +4247,11 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
                        }
                } else if ((journal->j_start +
                            journal->j_trans_max + 1) >
-                          SB_ONDISK_JOURNAL_SIZE(p_s_sb)) {
+                          SB_ONDISK_JOURNAL_SIZE(sb)) {
                        if (((journal->j_start + journal->j_trans_max + 1) %
-                            SB_ONDISK_JOURNAL_SIZE(p_s_sb)) >=
+                            SB_ONDISK_JOURNAL_SIZE(sb)) >=
                            temp_jl->j_start) {
-                               flush_used_journal_lists(p_s_sb, temp_jl);
+                               flush_used_journal_lists(sb, temp_jl);
                                goto first_jl;
                        } else {
                                /* we don't overlap anything from out start to the end of the
@@ -4250,46 +4262,47 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
                        }
                }
        }
-       flush_old_journal_lists(p_s_sb);
+       flush_old_journal_lists(sb);
 
        journal->j_current_jl->j_list_bitmap =
-           get_list_bitmap(p_s_sb, journal->j_current_jl);
+           get_list_bitmap(sb, journal->j_current_jl);
 
        if (!(journal->j_current_jl->j_list_bitmap)) {
-               reiserfs_panic(p_s_sb,
-                              "journal-1996: do_journal_end, could not get a list bitmap\n");
+               reiserfs_panic(sb, "journal-1996",
+                              "could not get a list bitmap");
        }
 
        atomic_set(&(journal->j_jlock), 0);
-       unlock_journal(p_s_sb);
+       unlock_journal(sb);
        /* wake up any body waiting to join. */
        clear_bit(J_WRITERS_QUEUED, &journal->j_state);
        wake_up(&(journal->j_join_wait));
 
        if (!flush && wait_on_commit &&
-           journal_list_still_alive(p_s_sb, commit_trans_id)) {
-               flush_commit_list(p_s_sb, jl, 1);
+           journal_list_still_alive(sb, commit_trans_id)) {
+               flush_commit_list(sb, jl, 1);
        }
       out:
-       reiserfs_check_lock_depth(p_s_sb, "journal end2");
+       reiserfs_check_lock_depth(sb, "journal end2");
 
        memset(th, 0, sizeof(*th));
        /* Re-set th->t_super, so we can properly keep track of how many
         * persistent transactions there are. We need to do this so if this
         * call is part of a failed restart_transaction, we can free it later */
-       th->t_super = p_s_sb;
+       th->t_super = sb;
 
        return journal->j_errno;
 }
 
-static void __reiserfs_journal_abort_hard(struct super_block *sb)
+/* Send the file system read only and refuse new transactions */
+void reiserfs_abort_journal(struct super_block *sb, int errno)
 {
        struct reiserfs_journal *journal = SB_JOURNAL(sb);
        if (test_bit(J_ABORTED, &journal->j_state))
                return;
 
-       printk(KERN_CRIT "REISERFS: Aborting journal for filesystem on %s\n",
-              reiserfs_bdevname(sb));
+       if (!journal->j_errno)
+               journal->j_errno = errno;
 
        sb->s_flags |= MS_RDONLY;
        set_bit(J_ABORTED, &journal->j_state);
@@ -4299,19 +4312,3 @@ static void __reiserfs_journal_abort_hard(struct super_block *sb)
 #endif
 }
 
-static void __reiserfs_journal_abort_soft(struct super_block *sb, int errno)
-{
-       struct reiserfs_journal *journal = SB_JOURNAL(sb);
-       if (test_bit(J_ABORTED, &journal->j_state))
-               return;
-
-       if (!journal->j_errno)
-               journal->j_errno = errno;
-
-       __reiserfs_journal_abort_hard(sb);
-}
-
-void reiserfs_journal_abort(struct super_block *sb, int errno)
-{
-       __reiserfs_journal_abort_soft(sb, errno);
-}
index 6de060a6aa7fc79c04a6f1d3d3a6b70648bd2af6..381750a155f62d544ac6286896e314b43b5404ac 100644 (file)
@@ -111,7 +111,7 @@ static void leaf_copy_dir_entries(struct buffer_info *dest_bi,
        item_num_in_dest =
            (last_first == FIRST_TO_LAST) ? (B_NR_ITEMS(dest) - 1) : 0;
 
-       leaf_paste_entries(dest_bi->bi_bh, item_num_in_dest,
+       leaf_paste_entries(dest_bi, item_num_in_dest,
                           (last_first ==
                            FIRST_TO_LAST) ? I_ENTRY_COUNT(B_N_PITEM_HEAD(dest,
                                                                          item_num_in_dest))
@@ -119,8 +119,8 @@ static void leaf_copy_dir_entries(struct buffer_info *dest_bi,
                           DEH_SIZE * copy_count + copy_records_len);
 }
 
-/* Copy the first (if last_first == FIRST_TO_LAST) or last (last_first == LAST_TO_FIRST) item or 
-   part of it or nothing (see the return 0 below) from SOURCE to the end 
+/* Copy the first (if last_first == FIRST_TO_LAST) or last (last_first == LAST_TO_FIRST) item or
+   part of it or nothing (see the return 0 below) from SOURCE to the end
    (if last_first) or beginning (!last_first) of the DEST */
 /* returns 1 if anything was copied, else 0 */
 static int leaf_copy_boundary_item(struct buffer_info *dest_bi,
@@ -168,10 +168,11 @@ static int leaf_copy_boundary_item(struct buffer_info *dest_bi,
                        if (bytes_or_entries == ih_item_len(ih)
                            && is_indirect_le_ih(ih))
                                if (get_ih_free_space(ih))
-                                       reiserfs_panic(NULL,
-                                                      "vs-10020: leaf_copy_boundary_item: "
-                                                      "last unformatted node must be filled entirely (%h)",
-                                                      ih);
+                                       reiserfs_panic(sb_from_bi(dest_bi),
+                                                      "vs-10020",
+                                                      "last unformatted node "
+                                                      "must be filled "
+                                                      "entirely (%h)", ih);
                }
 #endif
 
@@ -395,7 +396,7 @@ static void leaf_item_bottle(struct buffer_info *dest_bi,
                else {
                        struct item_head n_ih;
 
-                       /* copy part of the body of the item number 'item_num' of SOURCE to the end of the DEST 
+                       /* copy part of the body of the item number 'item_num' of SOURCE to the end of the DEST
                           part defined by 'cpy_bytes'; create new item header; change old item_header (????);
                           n_ih = new item_header;
                         */
@@ -425,7 +426,7 @@ static void leaf_item_bottle(struct buffer_info *dest_bi,
                else {
                        struct item_head n_ih;
 
-                       /* copy part of the body of the item number 'item_num' of SOURCE to the begin of the DEST 
+                       /* copy part of the body of the item number 'item_num' of SOURCE to the begin of the DEST
                           part defined by 'cpy_bytes'; create new item header;
                           n_ih = new item_header;
                         */
@@ -622,9 +623,8 @@ static void leaf_define_dest_src_infos(int shift_mode, struct tree_balance *tb,
                break;
 
        default:
-               reiserfs_panic(NULL,
-                              "vs-10250: leaf_define_dest_src_infos: shift type is unknown (%d)",
-                              shift_mode);
+               reiserfs_panic(sb_from_bi(src_bi), "vs-10250",
+                              "shift type is unknown (%d)", shift_mode);
        }
        RFALSE(!src_bi->bi_bh || !dest_bi->bi_bh,
               "vs-10260: mode==%d, source (%p) or dest (%p) buffer is initialized incorrectly",
@@ -674,9 +674,9 @@ int leaf_shift_left(struct tree_balance *tb, int shift_num, int shift_bytes)
 #ifdef CONFIG_REISERFS_CHECK
                        if (tb->tb_mode == M_PASTE || tb->tb_mode == M_INSERT) {
                                print_cur_tb("vs-10275");
-                               reiserfs_panic(tb->tb_sb,
-                                              "vs-10275: leaf_shift_left: balance condition corrupted (%c)",
-                                              tb->tb_mode);
+                               reiserfs_panic(tb->tb_sb, "vs-10275",
+                                              "balance condition corrupted "
+                                              "(%c)", tb->tb_mode);
                        }
 #endif
 
@@ -724,7 +724,7 @@ int leaf_shift_right(struct tree_balance *tb, int shift_num, int shift_bytes)
 static void leaf_delete_items_entirely(struct buffer_info *bi,
                                       int first, int del_num);
 /*  If del_bytes == -1, starting from position 'first' delete del_num items in whole in buffer CUR.
-    If not. 
+    If not.
     If last_first == 0. Starting from position 'first' delete del_num-1 items in whole. Delete part of body of
     the first item. Part defined by del_bytes. Don't delete first item header
     If last_first == 1. Starting from position 'first+1' delete del_num-1 items in whole. Delete part of body of
@@ -783,7 +783,7 @@ void leaf_delete_items(struct buffer_info *cur_bi, int last_first,
                                /* len = body len of item */
                                len = ih_item_len(ih);
 
-                       /* delete the part of the last item of the bh 
+                       /* delete the part of the last item of the bh
                           do not delete item header
                         */
                        leaf_cut_from_buffer(cur_bi, B_NR_ITEMS(bh) - 1,
@@ -865,7 +865,7 @@ void leaf_insert_into_buf(struct buffer_info *bi, int before,
        }
 }
 
-/* paste paste_size bytes to affected_item_num-th item. 
+/* paste paste_size bytes to affected_item_num-th item.
    When item is a directory, this only prepare space for new entries */
 void leaf_paste_in_buffer(struct buffer_info *bi, int affected_item_num,
                          int pos_in_item, int paste_size,
@@ -889,9 +889,12 @@ void leaf_paste_in_buffer(struct buffer_info *bi, int affected_item_num,
 
 #ifdef CONFIG_REISERFS_CHECK
        if (zeros_number > paste_size) {
+               struct super_block *sb = NULL;
+               if (bi && bi->tb)
+                       sb = bi->tb->tb_sb;
                print_cur_tb("10177");
-               reiserfs_panic(NULL,
-                              "vs-10177: leaf_paste_in_buffer: ero number == %d, paste_size == %d",
+               reiserfs_panic(sb, "vs-10177",
+                              "zeros_number == %d, paste_size == %d",
                               zeros_number, paste_size);
        }
 #endif                         /* CONFIG_REISERFS_CHECK */
@@ -1019,7 +1022,7 @@ static int leaf_cut_entries(struct buffer_head *bh,
 /*  when cut item is part of regular file
         pos_in_item - first byte that must be cut
         cut_size - number of bytes to be cut beginning from pos_in_item
+
    when cut item is part of directory
         pos_in_item - number of first deleted entry
         cut_size - count of deleted entries
@@ -1191,7 +1194,7 @@ static void leaf_delete_items_entirely(struct buffer_info *bi,
 }
 
 /* paste new_entry_count entries (new_dehs, records) into position before to item_num-th item */
-void leaf_paste_entries(struct buffer_head *bh,
+void leaf_paste_entries(struct buffer_info *bi,
                        int item_num,
                        int before,
                        int new_entry_count,
@@ -1203,6 +1206,7 @@ void leaf_paste_entries(struct buffer_head *bh,
        struct reiserfs_de_head *deh;
        char *insert_point;
        int i, old_entry_num;
+       struct buffer_head *bh = bi->bi_bh;
 
        if (new_entry_count == 0)
                return;
@@ -1271,7 +1275,7 @@ void leaf_paste_entries(struct buffer_head *bh,
        /* change item key if necessary (when we paste before 0-th entry */
        if (!before) {
                set_le_ih_k_offset(ih, deh_offset(new_dehs));
-/*      memcpy (&ih->ih_key.k_offset, 
+/*      memcpy (&ih->ih_key.k_offset,
                       &new_dehs->deh_offset, SHORT_KEY_SIZE);*/
        }
 #ifdef CONFIG_REISERFS_CHECK
@@ -1287,13 +1291,17 @@ void leaf_paste_entries(struct buffer_head *bh,
                        prev = (i != 0) ? deh_location(&(deh[i - 1])) : 0;
 
                        if (prev && prev <= deh_location(&(deh[i])))
-                               reiserfs_warning(NULL,
-                                                "vs-10240: leaf_paste_entries: directory item (%h) corrupted (prev %a, cur(%d) %a)",
-                                                ih, deh + i - 1, i, deh + i);
+                               reiserfs_error(sb_from_bi(bi), "vs-10240",
+                                              "directory item (%h) "
+                                              "corrupted (prev %a, "
+                                              "cur(%d) %a)",
+                                              ih, deh + i - 1, i, deh + i);
                        if (next && next >= deh_location(&(deh[i])))
-                               reiserfs_warning(NULL,
-                                                "vs-10250: leaf_paste_entries: directory item (%h) corrupted (cur(%d) %a, next %a)",
-                                                ih, i, deh + i, deh + i + 1);
+                               reiserfs_error(sb_from_bi(bi), "vs-10250",
+                                              "directory item (%h) "
+                                              "corrupted (cur(%d) %a, "
+                                              "next %a)",
+                                              ih, i, deh + i, deh + i + 1);
                }
        }
 #endif
index 639d635d9d4ba3a89ab07f43d5f2cf084a0b9671..efd4d720718ec789bc32a98c7902e3e36d55983d 100644 (file)
@@ -106,7 +106,7 @@ key of the first directory entry in it.
 This function first calls search_by_key, then, if item whose first
 entry matches is not found it looks for the entry inside directory
 item found by search_by_key. Fills the path to the entry, and to the
-entry position in the item 
+entry position in the item
 
 */
 
@@ -120,8 +120,8 @@ int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
        switch (retval) {
        case ITEM_NOT_FOUND:
                if (!PATH_LAST_POSITION(path)) {
-                       reiserfs_warning(sb,
-                                        "vs-7000: search_by_entry_key: search_by_key returned item position == 0");
+                       reiserfs_error(sb, "vs-7000", "search_by_key "
+                                      "returned item position == 0");
                        pathrelse(path);
                        return IO_ERROR;
                }
@@ -135,8 +135,7 @@ int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
 
        default:
                pathrelse(path);
-               reiserfs_warning(sb,
-                                "vs-7002: search_by_entry_key: no path to here");
+               reiserfs_error(sb, "vs-7002", "no path to here");
                return IO_ERROR;
        }
 
@@ -146,10 +145,9 @@ int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
        if (!is_direntry_le_ih(de->de_ih) ||
            COMP_SHORT_KEYS(&(de->de_ih->ih_key), key)) {
                print_block(de->de_bh, 0, -1, -1);
-               reiserfs_panic(sb,
-                              "vs-7005: search_by_entry_key: found item %h is not directory item or "
-                              "does not belong to the same directory as key %K",
-                              de->de_ih, key);
+               reiserfs_panic(sb, "vs-7005", "found item %h is not directory "
+                              "item or does not belong to the same directory "
+                              "as key %K", de->de_ih, key);
        }
 #endif                         /* CONFIG_REISERFS_CHECK */
 
@@ -300,8 +298,7 @@ static int reiserfs_find_entry(struct inode *dir, const char *name, int namelen,
                    search_by_entry_key(dir->i_sb, &key_to_search,
                                        path_to_entry, de);
                if (retval == IO_ERROR) {
-                       reiserfs_warning(dir->i_sb, "zam-7001: io error in %s",
-                                        __func__);
+                       reiserfs_error(dir->i_sb, "zam-7001", "io error");
                        return IO_ERROR;
                }
 
@@ -361,9 +358,10 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
                        return ERR_PTR(-EACCES);
                }
 
-               /* Propogate the priv_object flag so we know we're in the priv tree */
-               if (is_reiserfs_priv_object(dir))
-                       reiserfs_mark_inode_private(inode);
+               /* Propagate the private flag so we know we're
+                * in the priv tree */
+               if (IS_PRIVATE(dir))
+                       inode->i_flags |= S_PRIVATE;
        }
        reiserfs_write_unlock(dir->i_sb);
        if (retval == IO_ERROR) {
@@ -373,7 +371,7 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
        return d_splice_alias(inode, dentry);
 }
 
-/* 
+/*
 ** looks up the dentry of the parent directory for child.
 ** taken from ext2_get_parent
 */
@@ -403,7 +401,7 @@ struct dentry *reiserfs_get_parent(struct dentry *child)
        return d_obtain_alias(inode);
 }
 
-/* add entry to the directory (entry can be hidden). 
+/* add entry to the directory (entry can be hidden).
 
 insert definition of when hidden directories are used here -Hans
 
@@ -484,10 +482,9 @@ static int reiserfs_add_entry(struct reiserfs_transaction_handle *th,
                }
 
                if (retval != NAME_FOUND) {
-                       reiserfs_warning(dir->i_sb,
-                                        "zam-7002:%s: \"reiserfs_find_entry\" "
-                                        "has returned unexpected value (%d)",
-                                        __func__, retval);
+                       reiserfs_error(dir->i_sb, "zam-7002",
+                                      "reiserfs_find_entry() returned "
+                                      "unexpected value (%d)", retval);
                }
 
                return -EEXIST;
@@ -498,8 +495,9 @@ static int reiserfs_add_entry(struct reiserfs_transaction_handle *th,
                                MAX_GENERATION_NUMBER + 1);
        if (gen_number > MAX_GENERATION_NUMBER) {
                /* there is no free generation number */
-               reiserfs_warning(dir->i_sb,
-                                "reiserfs_add_entry: Congratulations! we have got hash function screwed up");
+               reiserfs_warning(dir->i_sb, "reiserfs-7010",
+                                "Congratulations! we have got hash function "
+                                "screwed up");
                if (buffer != small_buf)
                        kfree(buffer);
                pathrelse(&path);
@@ -515,10 +513,9 @@ static int reiserfs_add_entry(struct reiserfs_transaction_handle *th,
        if (gen_number != 0) {  /* we need to re-search for the insertion point */
                if (search_by_entry_key(dir->i_sb, &entry_key, &path, &de) !=
                    NAME_NOT_FOUND) {
-                       reiserfs_warning(dir->i_sb,
-                                        "vs-7032: reiserfs_add_entry: "
-                                        "entry with this key (%K) already exists",
-                                        &entry_key);
+                       reiserfs_warning(dir->i_sb, "vs-7032",
+                                        "entry with this key (%K) already "
+                                        "exists", &entry_key);
 
                        if (buffer != small_buf)
                                kfree(buffer);
@@ -562,7 +559,7 @@ static int drop_new_inode(struct inode *inode)
        return 0;
 }
 
-/* utility function that does setup for reiserfs_new_inode.  
+/* utility function that does setup for reiserfs_new_inode.
 ** vfs_dq_init needs lots of credits so it's better to have it
 ** outside of a transaction, so we had to pull some bits of
 ** reiserfs_new_inode out into this func.
@@ -601,20 +598,22 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode,
            2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) +
                 REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb));
        struct reiserfs_transaction_handle th;
-       int locked;
+       struct reiserfs_security_handle security;
 
        if (!(inode = new_inode(dir->i_sb))) {
                return -ENOMEM;
        }
        new_inode_init(inode, dir, mode);
 
-       locked = reiserfs_cache_default_acl(dir);
-
+       jbegin_count += reiserfs_cache_default_acl(dir);
+       retval = reiserfs_security_init(dir, inode, &security);
+       if (retval < 0) {
+               drop_new_inode(inode);
+               return retval;
+       }
+       jbegin_count += retval;
        reiserfs_write_lock(dir->i_sb);
 
-       if (locked)
-               reiserfs_write_lock_xattrs(dir->i_sb);
-
        retval = journal_begin(&th, dir->i_sb, jbegin_count);
        if (retval) {
                drop_new_inode(inode);
@@ -623,15 +622,10 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode,
 
        retval =
            reiserfs_new_inode(&th, dir, mode, NULL, 0 /*i_size */ , dentry,
-                              inode);
+                              inode, &security);
        if (retval)
                goto out_failed;
 
-       if (locked) {
-               reiserfs_write_unlock_xattrs(dir->i_sb);
-               locked = 0;
-       }
-
        inode->i_op = &reiserfs_file_inode_operations;
        inode->i_fop = &reiserfs_file_operations;
        inode->i_mapping->a_ops = &reiserfs_address_space_operations;
@@ -658,8 +652,6 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode,
        retval = journal_end(&th, dir->i_sb, jbegin_count);
 
       out_failed:
-       if (locked)
-               reiserfs_write_unlock_xattrs(dir->i_sb);
        reiserfs_write_unlock(dir->i_sb);
        return retval;
 }
@@ -670,12 +662,12 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
        int retval;
        struct inode *inode;
        struct reiserfs_transaction_handle th;
+       struct reiserfs_security_handle security;
        /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
        int jbegin_count =
            JOURNAL_PER_BALANCE_CNT * 3 +
            2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) +
                 REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb));
-       int locked;
 
        if (!new_valid_dev(rdev))
                return -EINVAL;
@@ -685,13 +677,15 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
        }
        new_inode_init(inode, dir, mode);
 
-       locked = reiserfs_cache_default_acl(dir);
-
+       jbegin_count += reiserfs_cache_default_acl(dir);
+       retval = reiserfs_security_init(dir, inode, &security);
+       if (retval < 0) {
+               drop_new_inode(inode);
+               return retval;
+       }
+       jbegin_count += retval;
        reiserfs_write_lock(dir->i_sb);
 
-       if (locked)
-               reiserfs_write_lock_xattrs(dir->i_sb);
-
        retval = journal_begin(&th, dir->i_sb, jbegin_count);
        if (retval) {
                drop_new_inode(inode);
@@ -700,16 +694,11 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
 
        retval =
            reiserfs_new_inode(&th, dir, mode, NULL, 0 /*i_size */ , dentry,
-                              inode);
+                              inode, &security);
        if (retval) {
                goto out_failed;
        }
 
-       if (locked) {
-               reiserfs_write_unlock_xattrs(dir->i_sb);
-               locked = 0;
-       }
-
        inode->i_op = &reiserfs_special_inode_operations;
        init_special_inode(inode, inode->i_mode, rdev);
 
@@ -739,8 +728,6 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
        retval = journal_end(&th, dir->i_sb, jbegin_count);
 
       out_failed:
-       if (locked)
-               reiserfs_write_unlock_xattrs(dir->i_sb);
        reiserfs_write_unlock(dir->i_sb);
        return retval;
 }
@@ -750,12 +737,12 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        int retval;
        struct inode *inode;
        struct reiserfs_transaction_handle th;
+       struct reiserfs_security_handle security;
        /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
        int jbegin_count =
            JOURNAL_PER_BALANCE_CNT * 3 +
            2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) +
                 REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb));
-       int locked;
 
 #ifdef DISPLACE_NEW_PACKING_LOCALITIES
        /* set flag that new packing locality created and new blocks for the content     * of that directory are not displaced yet */
@@ -767,11 +754,14 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        }
        new_inode_init(inode, dir, mode);
 
-       locked = reiserfs_cache_default_acl(dir);
-
+       jbegin_count += reiserfs_cache_default_acl(dir);
+       retval = reiserfs_security_init(dir, inode, &security);
+       if (retval < 0) {
+               drop_new_inode(inode);
+               return retval;
+       }
+       jbegin_count += retval;
        reiserfs_write_lock(dir->i_sb);
-       if (locked)
-               reiserfs_write_lock_xattrs(dir->i_sb);
 
        retval = journal_begin(&th, dir->i_sb, jbegin_count);
        if (retval) {
@@ -787,17 +777,12 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
            retval = reiserfs_new_inode(&th, dir, mode, NULL /*symlink */ ,
                                        old_format_only(dir->i_sb) ?
                                        EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
-                                       dentry, inode);
+                                       dentry, inode, &security);
        if (retval) {
                dir->i_nlink--;
                goto out_failed;
        }
 
-       if (locked) {
-               reiserfs_write_unlock_xattrs(dir->i_sb);
-               locked = 0;
-       }
-
        reiserfs_update_inode_transaction(inode);
        reiserfs_update_inode_transaction(dir);
 
@@ -827,8 +812,6 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        unlock_new_inode(inode);
        retval = journal_end(&th, dir->i_sb, jbegin_count);
       out_failed:
-       if (locked)
-               reiserfs_write_unlock_xattrs(dir->i_sb);
        reiserfs_write_unlock(dir->i_sb);
        return retval;
 }
@@ -837,7 +820,7 @@ static inline int reiserfs_empty_dir(struct inode *inode)
 {
        /* we can cheat because an old format dir cannot have
         ** EMPTY_DIR_SIZE, and a new format dir cannot have
-        ** EMPTY_DIR_SIZE_V1.  So, if the inode is either size, 
+        ** EMPTY_DIR_SIZE_V1.  So, if the inode is either size,
         ** regardless of disk format version, the directory is empty.
         */
        if (inode->i_size != EMPTY_DIR_SIZE &&
@@ -903,8 +886,9 @@ static int reiserfs_rmdir(struct inode *dir, struct dentry *dentry)
                goto end_rmdir;
 
        if (inode->i_nlink != 2 && inode->i_nlink != 1)
-               reiserfs_warning(inode->i_sb, "%s: empty directory has nlink "
-                                "!= 2 (%d)", __func__, inode->i_nlink);
+               reiserfs_error(inode->i_sb, "reiserfs-7040",
+                              "empty directory has nlink != 2 (%d)",
+                              inode->i_nlink);
 
        clear_nlink(inode);
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
@@ -980,10 +964,9 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
        }
 
        if (!inode->i_nlink) {
-               reiserfs_warning(inode->i_sb, "%s: deleting nonexistent file "
-                                "(%s:%lu), %d", __func__,
-                                reiserfs_bdevname(inode->i_sb), inode->i_ino,
-                                inode->i_nlink);
+               reiserfs_warning(inode->i_sb, "reiserfs-7042",
+                                "deleting nonexistent file (%lu), %d",
+                                inode->i_ino, inode->i_nlink);
                inode->i_nlink = 1;
        }
 
@@ -1037,6 +1020,7 @@ static int reiserfs_symlink(struct inode *parent_dir,
        char *name;
        int item_len;
        struct reiserfs_transaction_handle th;
+       struct reiserfs_security_handle security;
        int mode = S_IFLNK | S_IRWXUGO;
        /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
        int jbegin_count =
@@ -1049,6 +1033,13 @@ static int reiserfs_symlink(struct inode *parent_dir,
        }
        new_inode_init(inode, parent_dir, mode);
 
+       retval = reiserfs_security_init(parent_dir, inode, &security);
+       if (retval < 0) {
+               drop_new_inode(inode);
+               return retval;
+       }
+       jbegin_count += retval;
+
        reiserfs_write_lock(parent_dir->i_sb);
        item_len = ROUND_UP(strlen(symname));
        if (item_len > MAX_DIRECT_ITEM_LEN(parent_dir->i_sb->s_blocksize)) {
@@ -1066,8 +1057,6 @@ static int reiserfs_symlink(struct inode *parent_dir,
        memcpy(name, symname, strlen(symname));
        padd_item(name, item_len, strlen(symname));
 
-       /* We would inherit the default ACL here, but symlinks don't get ACLs */
-
        retval = journal_begin(&th, parent_dir->i_sb, jbegin_count);
        if (retval) {
                drop_new_inode(inode);
@@ -1077,7 +1066,7 @@ static int reiserfs_symlink(struct inode *parent_dir,
 
        retval =
            reiserfs_new_inode(&th, parent_dir, mode, name, strlen(symname),
-                              dentry, inode);
+                              dentry, inode, &security);
        kfree(name);
        if (retval) {           /* reiserfs_new_inode iputs for us */
                goto out_failed;
@@ -1173,7 +1162,7 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir,
        return retval;
 }
 
-// de contains information pointing to an entry which 
+/* de contains information pointing to an entry which */
 static int de_still_valid(const char *name, int len,
                          struct reiserfs_dir_entry *de)
 {
@@ -1196,15 +1185,14 @@ static int entry_points_to_object(const char *name, int len,
 
        if (inode) {
                if (!de_visible(de->de_deh + de->de_entry_num))
-                       reiserfs_panic(NULL,
-                                      "vs-7042: entry_points_to_object: entry must be visible");
+                       reiserfs_panic(inode->i_sb, "vs-7042",
+                                      "entry must be visible");
                return (de->de_objectid == inode->i_ino) ? 1 : 0;
        }
 
        /* this must be added hidden entry */
        if (de_visible(de->de_deh + de->de_entry_num))
-               reiserfs_panic(NULL,
-                              "vs-7043: entry_points_to_object: entry must be visible");
+               reiserfs_panic(NULL, "vs-7043", "entry must be visible");
 
        return 1;
 }
@@ -1218,10 +1206,10 @@ static void set_ino_in_dir_entry(struct reiserfs_dir_entry *de,
        de->de_deh[de->de_entry_num].deh_objectid = key->k_objectid;
 }
 
-/* 
+/*
  * process, that is going to call fix_nodes/do_balance must hold only
  * one path. If it holds 2 or more, it can get into endless waiting in
- * get_empty_nodes or its clones 
+ * get_empty_nodes or its clones
  */
 static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                           struct inode *new_dir, struct dentry *new_dentry)
@@ -1275,7 +1263,7 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        old_inode_mode = old_inode->i_mode;
        if (S_ISDIR(old_inode_mode)) {
-               // make sure, that directory being renamed has correct ".." 
+               // make sure, that directory being renamed has correct ".."
                // and that its new parent directory has not too many links
                // already
 
@@ -1286,8 +1274,8 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        }
                }
 
-               /* directory is renamed, its parent directory will be changed, 
-                ** so find ".." entry 
+               /* directory is renamed, its parent directory will be changed,
+                ** so find ".." entry
                 */
                dot_dot_de.de_gen_number_bit_string = NULL;
                retval =
@@ -1318,8 +1306,8 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                               new_dentry->d_name.len, old_inode, 0);
        if (retval == -EEXIST) {
                if (!new_dentry_inode) {
-                       reiserfs_panic(old_dir->i_sb,
-                                      "vs-7050: new entry is found, new inode == 0\n");
+                       reiserfs_panic(old_dir->i_sb, "vs-7050",
+                                      "new entry is found, new inode == 0");
                }
        } else if (retval) {
                int err = journal_end(&th, old_dir->i_sb, jbegin_count);
@@ -1397,9 +1385,9 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                   this stuff, yes? Then, having
                   gathered everything into RAM we
                   should lock the buffers, yes?  -Hans */
-               /* probably.  our rename needs to hold more 
-                ** than one path at once.  The seals would 
-                ** have to be written to deal with multi-path 
+               /* probably.  our rename needs to hold more
+                ** than one path at once.  The seals would
+                ** have to be written to deal with multi-path
                 ** issues -chris
                 */
                /* sanity checking before doing the rename - avoid races many
@@ -1477,7 +1465,7 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        }
 
        if (S_ISDIR(old_inode_mode)) {
-               // adjust ".." of renamed directory 
+               /* adjust ".." of renamed directory */
                set_ino_in_dir_entry(&dot_dot_de, INODE_PKEY(new_dir));
                journal_mark_dirty(&th, new_dir->i_sb, dot_dot_de.de_bh);
 
@@ -1499,8 +1487,8 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (reiserfs_cut_from_item
            (&th, &old_entry_path, &(old_de.de_entry_key), old_dir, NULL,
             0) < 0)
-               reiserfs_warning(old_dir->i_sb,
-                                "vs-7060: reiserfs_rename: couldn't not cut old name. Fsck later?");
+               reiserfs_error(old_dir->i_sb, "vs-7060",
+                              "couldn't not cut old name. Fsck later?");
 
        old_dir->i_size -= DEH_SIZE + old_de.de_entrylen;
 
index ea0cf8c28a9965a20ce35602fc6dd36919edbd00..3a6de810bd61848418b4254493ce7ac1dd345a1c 100644 (file)
@@ -18,8 +18,7 @@
 static void check_objectid_map(struct super_block *s, __le32 * map)
 {
        if (le32_to_cpu(map[0]) != 1)
-               reiserfs_panic(s,
-                              "vs-15010: check_objectid_map: map corrupted: %lx",
+               reiserfs_panic(s, "vs-15010", "map corrupted: %lx",
                               (long unsigned int)le32_to_cpu(map[0]));
 
        // FIXME: add something else here
@@ -61,7 +60,7 @@ __u32 reiserfs_get_unused_objectid(struct reiserfs_transaction_handle *th)
        /* comment needed -Hans */
        unused_objectid = le32_to_cpu(map[1]);
        if (unused_objectid == U32_MAX) {
-               reiserfs_warning(s, "%s: no more object ids", __func__);
+               reiserfs_warning(s, "reiserfs-15100", "no more object ids");
                reiserfs_restore_prepared_buffer(s, SB_BUFFER_WITH_SB(s));
                return 0;
        }
@@ -160,9 +159,8 @@ void reiserfs_release_objectid(struct reiserfs_transaction_handle *th,
                i += 2;
        }
 
-       reiserfs_warning(s,
-                        "vs-15011: reiserfs_release_objectid: tried to free free object id (%lu)",
-                        (long unsigned)objectid_to_release);
+       reiserfs_error(s, "vs-15011", "tried to free free object id (%lu)",
+                      (long unsigned)objectid_to_release);
 }
 
 int reiserfs_convert_objectid_map_v1(struct super_block *s)
@@ -182,7 +180,7 @@ int reiserfs_convert_objectid_map_v1(struct super_block *s)
 
        if (cur_size > new_size) {
                /* mark everyone used that was listed as free at the end of the objectid
-                ** map 
+                ** map
                 */
                objectid_map[new_size - 1] = objectid_map[cur_size - 1];
                set_sb_oid_cursize(disk_sb, new_size);
index 740bb8c0c1ae8e455caafadd37351a6d14b2815e..536eacaeb71005a935a95c88dd7afba67535a4ac 100644 (file)
@@ -157,19 +157,16 @@ static void sprintf_disk_child(char *buf, struct disk_child *dc)
                dc_size(dc));
 }
 
-static char *is_there_reiserfs_struct(char *fmt, int *what, int *skip)
+static char *is_there_reiserfs_struct(char *fmt, int *what)
 {
        char *k = fmt;
 
-       *skip = 0;
-
        while ((k = strchr(k, '%')) != NULL) {
                if (k[1] == 'k' || k[1] == 'K' || k[1] == 'h' || k[1] == 't' ||
                    k[1] == 'z' || k[1] == 'b' || k[1] == 'y' || k[1] == 'a') {
                        *what = k[1];
                        break;
                }
-               (*skip)++;
                k++;
        }
        return k;
@@ -181,30 +178,29 @@ static char *is_there_reiserfs_struct(char *fmt, int *what, int *skip)
    appropriative printk. With this reiserfs_warning you can use format
    specification for complex structures like you used to do with
    printfs for integers, doubles and pointers. For instance, to print
-   out key structure you have to write just: 
-   reiserfs_warning ("bad key %k", key); 
-   instead of 
-   printk ("bad key %lu %lu %lu %lu", key->k_dir_id, key->k_objectid, 
-           key->k_offset, key->k_uniqueness); 
+   out key structure you have to write just:
+   reiserfs_warning ("bad key %k", key);
+   instead of
+   printk ("bad key %lu %lu %lu %lu", key->k_dir_id, key->k_objectid,
+           key->k_offset, key->k_uniqueness);
 */
-
+static DEFINE_SPINLOCK(error_lock);
 static void prepare_error_buf(const char *fmt, va_list args)
 {
        char *fmt1 = fmt_buf;
        char *k;
        char *p = error_buf;
-       int i, j, what, skip;
+       int what;
+
+       spin_lock(&error_lock);
 
        strcpy(fmt1, fmt);
 
-       while ((k = is_there_reiserfs_struct(fmt1, &what, &skip)) != NULL) {
+       while ((k = is_there_reiserfs_struct(fmt1, &what)) != NULL) {
                *k = 0;
 
                p += vsprintf(p, fmt1, args);
 
-               for (i = 0; i < skip; i++)
-                       j = va_arg(args, int);
-
                switch (what) {
                case 'k':
                        sprintf_le_key(p, va_arg(args, struct reiserfs_key *));
@@ -243,15 +239,16 @@ static void prepare_error_buf(const char *fmt, va_list args)
                fmt1 = k + 2;
        }
        vsprintf(p, fmt1, args);
+       spin_unlock(&error_lock);
 
 }
 
 /* in addition to usual conversion specifiers this accepts reiserfs
-   specific conversion specifiers: 
-   %k to print little endian key, 
-   %K to print cpu key, 
+   specific conversion specifiers:
+   %k to print little endian key,
+   %K to print cpu key,
    %h to print item_head,
-   %t to print directory entry 
+   %t to print directory entry
    %z to print block head (arg must be struct buffer_head *
    %b to print buffer_head
 */
@@ -264,14 +261,17 @@ static void prepare_error_buf(const char *fmt, va_list args)
     va_end( args );\
 }
 
-void reiserfs_warning(struct super_block *sb, const char *fmt, ...)
+void __reiserfs_warning(struct super_block *sb, const char *id,
+                        const char *function, const char *fmt, ...)
 {
        do_reiserfs_warning(fmt);
        if (sb)
-               printk(KERN_WARNING "ReiserFS: %s: warning: %s\n",
-                      reiserfs_bdevname(sb), error_buf);
+               printk(KERN_WARNING "REISERFS warning (device %s): %s%s%s: "
+                      "%s\n", sb->s_id, id ? id : "", id ? " " : "",
+                      function, error_buf);
        else
-               printk(KERN_WARNING "ReiserFS: warning: %s\n", error_buf);
+               printk(KERN_WARNING "REISERFS warning: %s%s%s: %s\n",
+                      id ? id : "", id ? " " : "", function, error_buf);
 }
 
 /* No newline.. reiserfs_info calls can be followed by printk's */
@@ -279,10 +279,10 @@ void reiserfs_info(struct super_block *sb, const char *fmt, ...)
 {
        do_reiserfs_warning(fmt);
        if (sb)
-               printk(KERN_NOTICE "ReiserFS: %s: %s",
-                      reiserfs_bdevname(sb), error_buf);
+               printk(KERN_NOTICE "REISERFS (device %s): %s",
+                      sb->s_id, error_buf);
        else
-               printk(KERN_NOTICE "ReiserFS: %s", error_buf);
+               printk(KERN_NOTICE "REISERFS %s:", error_buf);
 }
 
 /* No newline.. reiserfs_printk calls can be followed by printk's */
@@ -297,10 +297,10 @@ void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...)
 #ifdef CONFIG_REISERFS_CHECK
        do_reiserfs_warning(fmt);
        if (s)
-               printk(KERN_DEBUG "ReiserFS: %s: %s\n",
-                      reiserfs_bdevname(s), error_buf);
+               printk(KERN_DEBUG "REISERFS debug (device %s): %s\n",
+                      s->s_id, error_buf);
        else
-               printk(KERN_DEBUG "ReiserFS: %s\n", error_buf);
+               printk(KERN_DEBUG "REISERFS debug: %s\n", error_buf);
 #endif
 }
 
@@ -314,17 +314,17 @@ void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...)
     maintainer-errorid.  Don't bother with reusing errorids, there are
     lots of numbers out there.
 
-    Example: 
-    
+    Example:
+
     reiserfs_panic(
        p_sb, "reiser-29: reiserfs_new_blocknrs: "
        "one of search_start or rn(%d) is equal to MAX_B_NUM,"
-       "which means that we are optimizing location based on the bogus location of a temp buffer (%p).", 
+       "which means that we are optimizing location based on the bogus location of a temp buffer (%p).",
        rn, bh
     );
 
     Regular panic()s sometimes clear the screen before the message can
-    be read, thus the need for the while loop.  
+    be read, thus the need for the while loop.
 
     Numbering scheme for panic used by Vladimir and Anatoly( Hans completely ignores this scheme, and considers it
     pointless complexity):
@@ -353,14 +353,46 @@ void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...)
 extern struct tree_balance *cur_tb;
 #endif
 
-void reiserfs_panic(struct super_block *sb, const char *fmt, ...)
+void __reiserfs_panic(struct super_block *sb, const char *id,
+                     const char *function, const char *fmt, ...)
 {
        do_reiserfs_warning(fmt);
 
+#ifdef CONFIG_REISERFS_CHECK
        dump_stack();
+#endif
+       if (sb)
+               panic(KERN_WARNING "REISERFS panic (device %s): %s%s%s: %s\n",
+                     sb->s_id, id ? id : "", id ? " " : "",
+                     function, error_buf);
+       else
+               panic(KERN_WARNING "REISERFS panic: %s%s%s: %s\n",
+                     id ? id : "", id ? " " : "", function, error_buf);
+}
+
+void __reiserfs_error(struct super_block *sb, const char *id,
+                     const char *function, const char *fmt, ...)
+{
+       do_reiserfs_warning(fmt);
 
-       panic(KERN_EMERG "REISERFS: panic (device %s): %s\n",
-              reiserfs_bdevname(sb), error_buf);
+       BUG_ON(sb == NULL);
+
+       if (reiserfs_error_panic(sb))
+               __reiserfs_panic(sb, id, function, error_buf);
+
+       if (id && id[0])
+               printk(KERN_CRIT "REISERFS error (device %s): %s %s: %s\n",
+                      sb->s_id, id, function, error_buf);
+       else
+               printk(KERN_CRIT "REISERFS error (device %s): %s: %s\n",
+                      sb->s_id, function, error_buf);
+
+       if (sb->s_flags & MS_RDONLY)
+               return;
+
+       reiserfs_info(sb, "Remounting filesystem read-only\n");
+       sb->s_flags |= MS_RDONLY;
+       reiserfs_abort_journal(sb, -EIO);
 }
 
 void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...)
@@ -368,18 +400,18 @@ void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...)
        do_reiserfs_warning(fmt);
 
        if (reiserfs_error_panic(sb)) {
-               panic(KERN_CRIT "REISERFS: panic (device %s): %s\n",
-                     reiserfs_bdevname(sb), error_buf);
+               panic(KERN_CRIT "REISERFS panic (device %s): %s\n", sb->s_id,
+                     error_buf);
        }
 
-       if (sb->s_flags & MS_RDONLY)
+       if (reiserfs_is_journal_aborted(SB_JOURNAL(sb)))
                return;
 
-       printk(KERN_CRIT "REISERFS: abort (device %s): %s\n",
-              reiserfs_bdevname(sb), error_buf);
+       printk(KERN_CRIT "REISERFS abort (device %s): %s\n", sb->s_id,
+              error_buf);
 
        sb->s_flags |= MS_RDONLY;
-       reiserfs_journal_abort(sb, errno);
+       reiserfs_abort_journal(sb, errno);
 }
 
 /* this prints internal nodes (4 keys/items in line) (dc_number,
@@ -681,12 +713,10 @@ static void check_leaf_block_head(struct buffer_head *bh)
        blkh = B_BLK_HEAD(bh);
        nr = blkh_nr_item(blkh);
        if (nr > (bh->b_size - BLKH_SIZE) / IH_SIZE)
-               reiserfs_panic(NULL,
-                              "vs-6010: check_leaf_block_head: invalid item number %z",
+               reiserfs_panic(NULL, "vs-6010", "invalid item number %z",
                               bh);
        if (blkh_free_space(blkh) > bh->b_size - BLKH_SIZE - IH_SIZE * nr)
-               reiserfs_panic(NULL,
-                              "vs-6020: check_leaf_block_head: invalid free space %z",
+               reiserfs_panic(NULL, "vs-6020", "invalid free space %z",
                               bh);
 
 }
@@ -697,21 +727,15 @@ static void check_internal_block_head(struct buffer_head *bh)
 
        blkh = B_BLK_HEAD(bh);
        if (!(B_LEVEL(bh) > DISK_LEAF_NODE_LEVEL && B_LEVEL(bh) <= MAX_HEIGHT))
-               reiserfs_panic(NULL,
-                              "vs-6025: check_internal_block_head: invalid level %z",
-                              bh);
+               reiserfs_panic(NULL, "vs-6025", "invalid level %z", bh);
 
        if (B_NR_ITEMS(bh) > (bh->b_size - BLKH_SIZE) / IH_SIZE)
-               reiserfs_panic(NULL,
-                              "vs-6030: check_internal_block_head: invalid item number %z",
-                              bh);
+               reiserfs_panic(NULL, "vs-6030", "invalid item number %z", bh);
 
        if (B_FREE_SPACE(bh) !=
            bh->b_size - BLKH_SIZE - KEY_SIZE * B_NR_ITEMS(bh) -
            DC_SIZE * (B_NR_ITEMS(bh) + 1))
-               reiserfs_panic(NULL,
-                              "vs-6040: check_internal_block_head: invalid free space %z",
-                              bh);
+               reiserfs_panic(NULL, "vs-6040", "invalid free space %z", bh);
 
 }
 
index 37173fa07d1532c854fef231bda9a0744ce81374..9229e5514a4e13eef0fbaaef47f547bc90989a10 100644 (file)
@@ -321,7 +321,7 @@ static int show_journal(struct seq_file *m, struct super_block *sb)
                   /* incore fields */
                   "j_1st_reserved_block: \t%i\n"
                   "j_state: \t%li\n"
-                  "j_trans_id: \t%lu\n"
+                  "j_trans_id: \t%u\n"
                   "j_mount_id: \t%lu\n"
                   "j_start: \t%lu\n"
                   "j_len: \t%lu\n"
@@ -329,7 +329,7 @@ static int show_journal(struct seq_file *m, struct super_block *sb)
                   "j_wcount: \t%i\n"
                   "j_bcount: \t%lu\n"
                   "j_first_unflushed_offset: \t%lu\n"
-                  "j_last_flush_trans_id: \t%lu\n"
+                  "j_last_flush_trans_id: \t%u\n"
                   "j_trans_start_time: \t%li\n"
                   "j_list_bitmap_index: \t%i\n"
                   "j_must_wait: \t%i\n"
@@ -492,7 +492,6 @@ int reiserfs_proc_info_init(struct super_block *sb)
        spin_lock_init(&__PINFO(sb).lock);
        REISERFS_SB(sb)->procdir = proc_mkdir(b, proc_info_root);
        if (REISERFS_SB(sb)->procdir) {
-               REISERFS_SB(sb)->procdir->owner = THIS_MODULE;
                REISERFS_SB(sb)->procdir->data = sb;
                add_file(sb, "version", show_version);
                add_file(sb, "super", show_super);
@@ -503,7 +502,7 @@ int reiserfs_proc_info_init(struct super_block *sb)
                add_file(sb, "journal", show_journal);
                return 0;
        }
-       reiserfs_warning(sb, "reiserfs: cannot create /proc/%s/%s",
+       reiserfs_warning(sb, "cannot create /proc/%s/%s",
                         proc_info_root_name, b);
        return 1;
 }
@@ -556,11 +555,8 @@ int reiserfs_proc_info_global_init(void)
 {
        if (proc_info_root == NULL) {
                proc_info_root = proc_mkdir(proc_info_root_name, NULL);
-               if (proc_info_root) {
-                       proc_info_root->owner = THIS_MODULE;
-               } else {
-                       reiserfs_warning(NULL,
-                                        "reiserfs: cannot create /proc/%s",
+               if (!proc_info_root) {
+                       reiserfs_warning(NULL, "cannot create /proc/%s",
                                         proc_info_root_name);
                        return 1;
                }
@@ -634,7 +630,7 @@ int reiserfs_global_version_in_proc(char *buffer, char **start,
  *
  */
 
-/* 
+/*
  * Make Linus happy.
  * Local variables:
  * c-indentation-style: "K&R"
index f71c3948edef8324ac68a71042fbc35209cb5ea3..238e9d9b31e04bf877f1644630990672d1c5daba 100644 (file)
@@ -1,8 +1,8 @@
-/* 
+/*
  * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
  */
 
-/* 
+/*
  * Written by Alexander Zarochentcev.
  *
  * The kernel part of the (on-line) reiserfs resizer.
@@ -101,7 +101,7 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
                        memcpy(jbitmap[i].bitmaps, jb->bitmaps, copy_size);
 
                        /* just in case vfree schedules on us, copy the new
-                        ** pointer into the journal struct before freeing the 
+                        ** pointer into the journal struct before freeing the
                         ** old one
                         */
                        node_tmp = jb->bitmaps;
index 73aaa33f6735661fe7932843faada42866663efc..d036ee5b1c81a8bd43d8f8836fbd78b68c462acb 100644 (file)
@@ -23,7 +23,6 @@
  * get_rkey
  * key_in_buffer
  * decrement_bcount
- * decrement_counters_in_path
  * reiserfs_check_path
  * pathrelse_and_restore
  * pathrelse
 #include <linux/quotaops.h>
 
 /* Does the buffer contain a disk block which is in the tree. */
-inline int B_IS_IN_TREE(const struct buffer_head *p_s_bh)
+inline int B_IS_IN_TREE(const struct buffer_head *bh)
 {
 
-       RFALSE(B_LEVEL(p_s_bh) > MAX_HEIGHT,
-              "PAP-1010: block (%b) has too big level (%z)", p_s_bh, p_s_bh);
+       RFALSE(B_LEVEL(bh) > MAX_HEIGHT,
+              "PAP-1010: block (%b) has too big level (%z)", bh, bh);
 
-       return (B_LEVEL(p_s_bh) != FREE_LEVEL);
+       return (B_LEVEL(bh) != FREE_LEVEL);
 }
 
 //
 // to gets item head in le form
 //
-inline void copy_item_head(struct item_head *p_v_to,
-                          const struct item_head *p_v_from)
+inline void copy_item_head(struct item_head *to,
+                          const struct item_head *from)
 {
-       memcpy(p_v_to, p_v_from, IH_SIZE);
+       memcpy(to, from, IH_SIZE);
 }
 
 /* k1 is pointer to on-disk structure which is stored in little-endian
    form. k2 is pointer to cpu variable. For key of items of the same
    object this returns 0.
-   Returns: -1 if key1 < key2 
+   Returns: -1 if key1 < key2
    0 if key1 == key2
    1 if key1 > key2 */
 inline int comp_short_keys(const struct reiserfs_key *le_key,
@@ -136,15 +135,15 @@ static inline int comp_keys(const struct reiserfs_key *le_key,
 inline int comp_short_le_keys(const struct reiserfs_key *key1,
                              const struct reiserfs_key *key2)
 {
-       __u32 *p_s_1_u32, *p_s_2_u32;
-       int n_key_length = REISERFS_SHORT_KEY_LEN;
+       __u32 *k1_u32, *k2_u32;
+       int key_length = REISERFS_SHORT_KEY_LEN;
 
-       p_s_1_u32 = (__u32 *) key1;
-       p_s_2_u32 = (__u32 *) key2;
-       for (; n_key_length--; ++p_s_1_u32, ++p_s_2_u32) {
-               if (le32_to_cpu(*p_s_1_u32) < le32_to_cpu(*p_s_2_u32))
+       k1_u32 = (__u32 *) key1;
+       k2_u32 = (__u32 *) key2;
+       for (; key_length--; ++k1_u32, ++k2_u32) {
+               if (le32_to_cpu(*k1_u32) < le32_to_cpu(*k2_u32))
                        return -1;
-               if (le32_to_cpu(*p_s_1_u32) > le32_to_cpu(*p_s_2_u32))
+               if (le32_to_cpu(*k1_u32) > le32_to_cpu(*k2_u32))
                        return 1;
        }
        return 0;
@@ -175,52 +174,51 @@ inline int comp_le_keys(const struct reiserfs_key *k1,
  *  Binary search toolkit function                                        *
  *  Search for an item in the array by the item key                       *
  *  Returns:    1 if found,  0 if not found;                              *
- *        *p_n_pos = number of the searched element if found, else the    *
- *        number of the first element that is larger than p_v_key.        *
+ *        *pos = number of the searched element if found, else the        *
+ *        number of the first element that is larger than key.            *
  **************************************************************************/
-/* For those not familiar with binary search: n_lbound is the leftmost item that it
- could be, n_rbound the rightmost item that it could be.  We examine the item
- halfway between n_lbound and n_rbound, and that tells us either that we can increase
n_lbound, or decrease n_rbound, or that we have found it, or if n_lbound <= n_rbound that
+/* For those not familiar with binary search: lbound is the leftmost item that it
+ could be, rbound the rightmost item that it could be.  We examine the item
+ halfway between lbound and rbound, and that tells us either that we can increase
lbound, or decrease rbound, or that we have found it, or if lbound <= rbound that
  there are no possible items, and we have not found it. With each examination we
  cut the number of possible items it could be by one more than half rounded down,
  or we find it. */
-static inline int bin_search(const void *p_v_key,      /* Key to search for.                   */
-                            const void *p_v_base,      /* First item in the array.             */
-                            int p_n_num,       /* Number of items in the array.        */
-                            int p_n_width,     /* Item size in the array.
-                                                  searched. Lest the reader be
-                                                  confused, note that this is crafted
-                                                  as a general function, and when it
-                                                  is applied specifically to the array
-                                                  of item headers in a node, p_n_width
-                                                  is actually the item header size not
-                                                  the item size.                      */
-                            int *p_n_pos       /* Number of the searched for element. */
+static inline int bin_search(const void *key,  /* Key to search for. */
+                            const void *base,  /* First item in the array. */
+                            int num,   /* Number of items in the array. */
+                            int width, /* Item size in the array.
+                                          searched. Lest the reader be
+                                          confused, note that this is crafted
+                                          as a general function, and when it
+                                          is applied specifically to the array
+                                          of item headers in a node, width
+                                          is actually the item header size not
+                                          the item size. */
+                            int *pos /* Number of the searched for element. */
     )
 {
-       int n_rbound, n_lbound, n_j;
+       int rbound, lbound, j;
 
-       for (n_j = ((n_rbound = p_n_num - 1) + (n_lbound = 0)) / 2;
-            n_lbound <= n_rbound; n_j = (n_rbound + n_lbound) / 2)
+       for (j = ((rbound = num - 1) + (lbound = 0)) / 2;
+            lbound <= rbound; j = (rbound + lbound) / 2)
                switch (comp_keys
-                       ((struct reiserfs_key *)((char *)p_v_base +
-                                                n_j * p_n_width),
-                        (struct cpu_key *)p_v_key)) {
+                       ((struct reiserfs_key *)((char *)base + j * width),
+                        (struct cpu_key *)key)) {
                case -1:
-                       n_lbound = n_j + 1;
+                       lbound = j + 1;
                        continue;
                case 1:
-                       n_rbound = n_j - 1;
+                       rbound = j - 1;
                        continue;
                case 0:
-                       *p_n_pos = n_j;
+                       *pos = j;
                        return ITEM_FOUND;      /* Key found in the array.  */
                }
 
        /* bin_search did not find given key, it returns position of key,
           that is minimal and greater than the given one. */
-       *p_n_pos = n_lbound;
+       *pos = lbound;
        return ITEM_NOT_FOUND;
 }
 
@@ -243,90 +241,88 @@ static const struct reiserfs_key MAX_KEY = {
    of the path, and going upwards.  We must check the path's validity at each step.  If the key is not in
    the path, there is no delimiting key in the tree (buffer is first or last buffer in tree), and in this
    case we return a special key, either MIN_KEY or MAX_KEY. */
-static inline const struct reiserfs_key *get_lkey(const struct treepath
-                                                 *p_s_chk_path,
-                                                 const struct super_block
-                                                 *p_s_sb)
+static inline const struct reiserfs_key *get_lkey(const struct treepath *chk_path,
+                                                 const struct super_block *sb)
 {
-       int n_position, n_path_offset = p_s_chk_path->path_length;
-       struct buffer_head *p_s_parent;
+       int position, path_offset = chk_path->path_length;
+       struct buffer_head *parent;
 
-       RFALSE(n_path_offset < FIRST_PATH_ELEMENT_OFFSET,
+       RFALSE(path_offset < FIRST_PATH_ELEMENT_OFFSET,
               "PAP-5010: invalid offset in the path");
 
        /* While not higher in path than first element. */
-       while (n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET) {
+       while (path_offset-- > FIRST_PATH_ELEMENT_OFFSET) {
 
                RFALSE(!buffer_uptodate
-                      (PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)),
+                      (PATH_OFFSET_PBUFFER(chk_path, path_offset)),
                       "PAP-5020: parent is not uptodate");
 
                /* Parent at the path is not in the tree now. */
                if (!B_IS_IN_TREE
-                   (p_s_parent =
-                    PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)))
+                   (parent =
+                    PATH_OFFSET_PBUFFER(chk_path, path_offset)))
                        return &MAX_KEY;
                /* Check whether position in the parent is correct. */
-               if ((n_position =
-                    PATH_OFFSET_POSITION(p_s_chk_path,
-                                         n_path_offset)) >
-                   B_NR_ITEMS(p_s_parent))
+               if ((position =
+                    PATH_OFFSET_POSITION(chk_path,
+                                         path_offset)) >
+                   B_NR_ITEMS(parent))
                        return &MAX_KEY;
                /* Check whether parent at the path really points to the child. */
-               if (B_N_CHILD_NUM(p_s_parent, n_position) !=
-                   PATH_OFFSET_PBUFFER(p_s_chk_path,
-                                       n_path_offset + 1)->b_blocknr)
+               if (B_N_CHILD_NUM(parent, position) !=
+                   PATH_OFFSET_PBUFFER(chk_path,
+                                       path_offset + 1)->b_blocknr)
                        return &MAX_KEY;
                /* Return delimiting key if position in the parent is not equal to zero. */
-               if (n_position)
-                       return B_N_PDELIM_KEY(p_s_parent, n_position - 1);
+               if (position)
+                       return B_N_PDELIM_KEY(parent, position - 1);
        }
        /* Return MIN_KEY if we are in the root of the buffer tree. */
-       if (PATH_OFFSET_PBUFFER(p_s_chk_path, FIRST_PATH_ELEMENT_OFFSET)->
-           b_blocknr == SB_ROOT_BLOCK(p_s_sb))
+       if (PATH_OFFSET_PBUFFER(chk_path, FIRST_PATH_ELEMENT_OFFSET)->
+           b_blocknr == SB_ROOT_BLOCK(sb))
                return &MIN_KEY;
        return &MAX_KEY;
 }
 
 /* Get delimiting key of the buffer at the path and its right neighbor. */
-inline const struct reiserfs_key *get_rkey(const struct treepath *p_s_chk_path,
-                                          const struct super_block *p_s_sb)
+inline const struct reiserfs_key *get_rkey(const struct treepath *chk_path,
+                                          const struct super_block *sb)
 {
-       int n_position, n_path_offset = p_s_chk_path->path_length;
-       struct buffer_head *p_s_parent;
+       int position, path_offset = chk_path->path_length;
+       struct buffer_head *parent;
 
-       RFALSE(n_path_offset < FIRST_PATH_ELEMENT_OFFSET,
+       RFALSE(path_offset < FIRST_PATH_ELEMENT_OFFSET,
               "PAP-5030: invalid offset in the path");
 
-       while (n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET) {
+       while (path_offset-- > FIRST_PATH_ELEMENT_OFFSET) {
 
                RFALSE(!buffer_uptodate
-                      (PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)),
+                      (PATH_OFFSET_PBUFFER(chk_path, path_offset)),
                       "PAP-5040: parent is not uptodate");
 
                /* Parent at the path is not in the tree now. */
                if (!B_IS_IN_TREE
-                   (p_s_parent =
-                    PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)))
+                   (parent =
+                    PATH_OFFSET_PBUFFER(chk_path, path_offset)))
                        return &MIN_KEY;
                /* Check whether position in the parent is correct. */
-               if ((n_position =
-                    PATH_OFFSET_POSITION(p_s_chk_path,
-                                         n_path_offset)) >
-                   B_NR_ITEMS(p_s_parent))
+               if ((position =
+                    PATH_OFFSET_POSITION(chk_path,
+                                         path_offset)) >
+                   B_NR_ITEMS(parent))
                        return &MIN_KEY;
                /* Check whether parent at the path really points to the child. */
-               if (B_N_CHILD_NUM(p_s_parent, n_position) !=
-                   PATH_OFFSET_PBUFFER(p_s_chk_path,
-                                       n_path_offset + 1)->b_blocknr)
+               if (B_N_CHILD_NUM(parent, position) !=
+                   PATH_OFFSET_PBUFFER(chk_path,
+                                       path_offset + 1)->b_blocknr)
                        return &MIN_KEY;
                /* Return delimiting key if position in the parent is not the last one. */
-               if (n_position != B_NR_ITEMS(p_s_parent))
-                       return B_N_PDELIM_KEY(p_s_parent, n_position);
+               if (position != B_NR_ITEMS(parent))
+                       return B_N_PDELIM_KEY(parent, position);
        }
        /* Return MAX_KEY if we are in the root of the buffer tree. */
-       if (PATH_OFFSET_PBUFFER(p_s_chk_path, FIRST_PATH_ELEMENT_OFFSET)->
-           b_blocknr == SB_ROOT_BLOCK(p_s_sb))
+       if (PATH_OFFSET_PBUFFER(chk_path, FIRST_PATH_ELEMENT_OFFSET)->
+           b_blocknr == SB_ROOT_BLOCK(sb))
                return &MAX_KEY;
        return &MIN_KEY;
 }
@@ -336,60 +332,29 @@ inline const struct reiserfs_key *get_rkey(const struct treepath *p_s_chk_path,
    the path.  These delimiting keys are stored at least one level above that buffer in the tree. If the
    buffer is the first or last node in the tree order then one of the delimiting keys may be absent, and in
    this case get_lkey and get_rkey return a special key which is MIN_KEY or MAX_KEY. */
-static inline int key_in_buffer(struct treepath *p_s_chk_path, /* Path which should be checked.  */
-                               const struct cpu_key *p_s_key,  /* Key which should be checked.   */
-                               struct super_block *p_s_sb      /* Super block pointer.           */
+static inline int key_in_buffer(struct treepath *chk_path,     /* Path which should be checked.  */
+                               const struct cpu_key *key,      /* Key which should be checked.   */
+                               struct super_block *sb
     )
 {
 
-       RFALSE(!p_s_key || p_s_chk_path->path_length < FIRST_PATH_ELEMENT_OFFSET
-              || p_s_chk_path->path_length > MAX_HEIGHT,
+       RFALSE(!key || chk_path->path_length < FIRST_PATH_ELEMENT_OFFSET
+              || chk_path->path_length > MAX_HEIGHT,
               "PAP-5050: pointer to the key(%p) is NULL or invalid path length(%d)",
-              p_s_key, p_s_chk_path->path_length);
-       RFALSE(!PATH_PLAST_BUFFER(p_s_chk_path)->b_bdev,
+              key, chk_path->path_length);
+       RFALSE(!PATH_PLAST_BUFFER(chk_path)->b_bdev,
               "PAP-5060: device must not be NODEV");
 
-       if (comp_keys(get_lkey(p_s_chk_path, p_s_sb), p_s_key) == 1)
+       if (comp_keys(get_lkey(chk_path, sb), key) == 1)
                /* left delimiting key is bigger, that the key we look for */
                return 0;
-       //  if ( comp_keys(p_s_key, get_rkey(p_s_chk_path, p_s_sb)) != -1 )
-       if (comp_keys(get_rkey(p_s_chk_path, p_s_sb), p_s_key) != 1)
-               /* p_s_key must be less than right delimitiing key */
+       /*  if ( comp_keys(key, get_rkey(chk_path, sb)) != -1 ) */
+       if (comp_keys(get_rkey(chk_path, sb), key) != 1)
+               /* key must be less than right delimitiing key */
                return 0;
        return 1;
 }
 
-inline void decrement_bcount(struct buffer_head *p_s_bh)
-{
-       if (p_s_bh) {
-               if (atomic_read(&(p_s_bh->b_count))) {
-                       put_bh(p_s_bh);
-                       return;
-               }
-               reiserfs_panic(NULL,
-                              "PAP-5070: decrement_bcount: trying to free free buffer %b",
-                              p_s_bh);
-       }
-}
-
-/* Decrement b_count field of the all buffers in the path. */
-void decrement_counters_in_path(struct treepath *p_s_search_path)
-{
-       int n_path_offset = p_s_search_path->path_length;
-
-       RFALSE(n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET ||
-              n_path_offset > EXTENDED_MAX_HEIGHT - 1,
-              "PAP-5080: invalid path offset of %d", n_path_offset);
-
-       while (n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET) {
-               struct buffer_head *bh;
-
-               bh = PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--);
-               decrement_bcount(bh);
-       }
-       p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
-}
-
 int reiserfs_check_path(struct treepath *p)
 {
        RFALSE(p->path_length != ILLEGAL_PATH_ELEMENT_OFFSET,
@@ -397,40 +362,38 @@ int reiserfs_check_path(struct treepath *p)
        return 0;
 }
 
-/* Release all buffers in the path. Restore dirty bits clean
-** when preparing the buffer for the log
-**
-** only called from fix_nodes()
-*/
-void pathrelse_and_restore(struct super_block *s, struct treepath *p_s_search_path)
+/* Drop the reference to each buffer in a path and restore
+ * dirty bits clean when preparing the buffer for the log.
+ * This version should only be called from fix_nodes() */
+void pathrelse_and_restore(struct super_block *sb,
+                          struct treepath *search_path)
 {
-       int n_path_offset = p_s_search_path->path_length;
+       int path_offset = search_path->path_length;
 
-       RFALSE(n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET,
+       RFALSE(path_offset < ILLEGAL_PATH_ELEMENT_OFFSET,
               "clm-4000: invalid path offset");
 
-       while (n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET) {
-               reiserfs_restore_prepared_buffer(s,
-                                                PATH_OFFSET_PBUFFER
-                                                (p_s_search_path,
-                                                 n_path_offset));
-               brelse(PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--));
+       while (path_offset > ILLEGAL_PATH_ELEMENT_OFFSET) {
+               struct buffer_head *bh;
+               bh = PATH_OFFSET_PBUFFER(search_path, path_offset--);
+               reiserfs_restore_prepared_buffer(sb, bh);
+               brelse(bh);
        }
-       p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
+       search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
 }
 
-/* Release all buffers in the path. */
-void pathrelse(struct treepath *p_s_search_path)
+/* Drop the reference to each buffer in a path */
+void pathrelse(struct treepath *search_path)
 {
-       int n_path_offset = p_s_search_path->path_length;
+       int path_offset = search_path->path_length;
 
-       RFALSE(n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET,
+       RFALSE(path_offset < ILLEGAL_PATH_ELEMENT_OFFSET,
               "PAP-5090: invalid path offset");
 
-       while (n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET)
-               brelse(PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--));
+       while (path_offset > ILLEGAL_PATH_ELEMENT_OFFSET)
+               brelse(PATH_OFFSET_PBUFFER(search_path, path_offset--));
 
-       p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
+       search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
 }
 
 static int is_leaf(char *buf, int blocksize, struct buffer_head *bh)
@@ -444,23 +407,24 @@ static int is_leaf(char *buf, int blocksize, struct buffer_head *bh)
 
        blkh = (struct block_head *)buf;
        if (blkh_level(blkh) != DISK_LEAF_NODE_LEVEL) {
-               reiserfs_warning(NULL,
-                                "is_leaf: this should be caught earlier");
+               reiserfs_warning(NULL, "reiserfs-5080",
+                                "this should be caught earlier");
                return 0;
        }
 
        nr = blkh_nr_item(blkh);
        if (nr < 1 || nr > ((blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN))) {
                /* item number is too big or too small */
-               reiserfs_warning(NULL, "is_leaf: nr_item seems wrong: %z", bh);
+               reiserfs_warning(NULL, "reiserfs-5081",
+                                "nr_item seems wrong: %z", bh);
                return 0;
        }
        ih = (struct item_head *)(buf + BLKH_SIZE) + nr - 1;
        used_space = BLKH_SIZE + IH_SIZE * nr + (blocksize - ih_location(ih));
        if (used_space != blocksize - blkh_free_space(blkh)) {
                /* free space does not match to calculated amount of use space */
-               reiserfs_warning(NULL, "is_leaf: free space seems wrong: %z",
-                                bh);
+               reiserfs_warning(NULL, "reiserfs-5082",
+                                "free space seems wrong: %z", bh);
                return 0;
        }
        // FIXME: it is_leaf will hit performance too much - we may have
@@ -471,29 +435,29 @@ static int is_leaf(char *buf, int blocksize, struct buffer_head *bh)
        prev_location = blocksize;
        for (i = 0; i < nr; i++, ih++) {
                if (le_ih_k_type(ih) == TYPE_ANY) {
-                       reiserfs_warning(NULL,
-                                        "is_leaf: wrong item type for item %h",
+                       reiserfs_warning(NULL, "reiserfs-5083",
+                                        "wrong item type for item %h",
                                         ih);
                        return 0;
                }
                if (ih_location(ih) >= blocksize
                    || ih_location(ih) < IH_SIZE * nr) {
-                       reiserfs_warning(NULL,
-                                        "is_leaf: item location seems wrong: %h",
+                       reiserfs_warning(NULL, "reiserfs-5084",
+                                        "item location seems wrong: %h",
                                         ih);
                        return 0;
                }
                if (ih_item_len(ih) < 1
                    || ih_item_len(ih) > MAX_ITEM_LEN(blocksize)) {
-                       reiserfs_warning(NULL,
-                                        "is_leaf: item length seems wrong: %h",
+                       reiserfs_warning(NULL, "reiserfs-5085",
+                                        "item length seems wrong: %h",
                                         ih);
                        return 0;
                }
                if (prev_location - ih_location(ih) != ih_item_len(ih)) {
-                       reiserfs_warning(NULL,
-                                        "is_leaf: item location seems wrong (second one): %h",
-                                        ih);
+                       reiserfs_warning(NULL, "reiserfs-5086",
+                                        "item location seems wrong "
+                                        "(second one): %h", ih);
                        return 0;
                }
                prev_location = ih_location(ih);
@@ -514,24 +478,23 @@ static int is_internal(char *buf, int blocksize, struct buffer_head *bh)
        nr = blkh_level(blkh);
        if (nr <= DISK_LEAF_NODE_LEVEL || nr > MAX_HEIGHT) {
                /* this level is not possible for internal nodes */
-               reiserfs_warning(NULL,
-                                "is_internal: this should be caught earlier");
+               reiserfs_warning(NULL, "reiserfs-5087",
+                                "this should be caught earlier");
                return 0;
        }
 
        nr = blkh_nr_item(blkh);
        if (nr > (blocksize - BLKH_SIZE - DC_SIZE) / (KEY_SIZE + DC_SIZE)) {
                /* for internal which is not root we might check min number of keys */
-               reiserfs_warning(NULL,
-                                "is_internal: number of key seems wrong: %z",
-                                bh);
+               reiserfs_warning(NULL, "reiserfs-5088",
+                                "number of key seems wrong: %z", bh);
                return 0;
        }
 
        used_space = BLKH_SIZE + KEY_SIZE * nr + DC_SIZE * (nr + 1);
        if (used_space != blocksize - blkh_free_space(blkh)) {
-               reiserfs_warning(NULL,
-                                "is_internal: free space seems wrong: %z", bh);
+               reiserfs_warning(NULL, "reiserfs-5089",
+                                "free space seems wrong: %z", bh);
                return 0;
        }
        // one may imagine much more checks
@@ -543,8 +506,8 @@ static int is_internal(char *buf, int blocksize, struct buffer_head *bh)
 static int is_tree_node(struct buffer_head *bh, int level)
 {
        if (B_LEVEL(bh) != level) {
-               reiserfs_warning(NULL,
-                                "is_tree_node: node level %d does not match to the expected one %d",
+               reiserfs_warning(NULL, "reiserfs-5090", "node level %d does "
+                                "not match to the expected one %d",
                                 B_LEVEL(bh), level);
                return 0;
        }
@@ -580,10 +543,10 @@ static void search_by_key_reada(struct super_block *s,
 /**************************************************************************
  * Algorithm   SearchByKey                                                *
  *             look for item in the Disk S+Tree by its key                *
- * Input:  p_s_sb   -  super block                                        *
- *         p_s_key  - pointer to the key to search                        *
+ * Input:  sb   -  super block                                            *
+ *         key  - pointer to the key to search                            *
  * Output: ITEM_FOUND, ITEM_NOT_FOUND or IO_ERROR                         *
- *         p_s_search_path - path from the root to the needed leaf        *
+ *         search_path - path from the root to the needed leaf            *
  **************************************************************************/
 
 /* This function fills up the path from the root to the leaf as it
@@ -600,22 +563,22 @@ static void search_by_key_reada(struct super_block *s,
    correctness of the top of the path but need not be checked for the
    correctness of the bottom of the path */
 /* The function is NOT SCHEDULE-SAFE! */
-int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key,   /* Key to search. */
-                 struct treepath *p_s_search_path,/* This structure was
+int search_by_key(struct super_block *sb, const struct cpu_key *key,   /* Key to search. */
+                 struct treepath *search_path,/* This structure was
                                                   allocated and initialized
                                                   by the calling
                                                   function. It is filled up
                                                   by this function.  */
-                 int n_stop_level      /* How far down the tree to search. To
+                 int stop_level        /* How far down the tree to search. To
                                           stop at leaf level - set to
                                           DISK_LEAF_NODE_LEVEL */
     )
 {
-       b_blocknr_t n_block_number;
+       b_blocknr_t block_number;
        int expected_level;
-       struct buffer_head *p_s_bh;
-       struct path_element *p_s_last_element;
-       int n_node_level, n_retval;
+       struct buffer_head *bh;
+       struct path_element *last_element;
+       int node_level, retval;
        int right_neighbor_of_leaf_node;
        int fs_gen;
        struct buffer_head *reada_bh[SEARCH_BY_KEY_READA];
@@ -623,80 +586,79 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key,      /*
        int reada_count = 0;
 
 #ifdef CONFIG_REISERFS_CHECK
-       int n_repeat_counter = 0;
+       int repeat_counter = 0;
 #endif
 
-       PROC_INFO_INC(p_s_sb, search_by_key);
+       PROC_INFO_INC(sb, search_by_key);
 
        /* As we add each node to a path we increase its count.  This means that
           we must be careful to release all nodes in a path before we either
           discard the path struct or re-use the path struct, as we do here. */
 
-       decrement_counters_in_path(p_s_search_path);
+       pathrelse(search_path);
 
        right_neighbor_of_leaf_node = 0;
 
        /* With each iteration of this loop we search through the items in the
           current node, and calculate the next current node(next path element)
           for the next iteration of this loop.. */
-       n_block_number = SB_ROOT_BLOCK(p_s_sb);
+       block_number = SB_ROOT_BLOCK(sb);
        expected_level = -1;
        while (1) {
 
 #ifdef CONFIG_REISERFS_CHECK
-               if (!(++n_repeat_counter % 50000))
-                       reiserfs_warning(p_s_sb, "PAP-5100: search_by_key: %s:"
-                                        "there were %d iterations of while loop "
-                                        "looking for key %K",
-                                        current->comm, n_repeat_counter,
-                                        p_s_key);
+               if (!(++repeat_counter % 50000))
+                       reiserfs_warning(sb, "PAP-5100",
+                                        "%s: there were %d iterations of "
+                                        "while loop looking for key %K",
+                                        current->comm, repeat_counter,
+                                        key);
 #endif
 
                /* prep path to have another element added to it. */
-               p_s_last_element =
-                   PATH_OFFSET_PELEMENT(p_s_search_path,
-                                        ++p_s_search_path->path_length);
-               fs_gen = get_generation(p_s_sb);
+               last_element =
+                   PATH_OFFSET_PELEMENT(search_path,
+                                        ++search_path->path_length);
+               fs_gen = get_generation(sb);
 
                /* Read the next tree node, and set the last element in the path to
                   have a pointer to it. */
-               if ((p_s_bh = p_s_last_element->pe_buffer =
-                    sb_getblk(p_s_sb, n_block_number))) {
-                       if (!buffer_uptodate(p_s_bh) && reada_count > 1) {
-                               search_by_key_reada(p_s_sb, reada_bh,
+               if ((bh = last_element->pe_buffer =
+                    sb_getblk(sb, block_number))) {
+                       if (!buffer_uptodate(bh) && reada_count > 1)
+                               search_by_key_reada(sb, reada_bh,
                                                    reada_blocks, reada_count);
-                       }
-                       ll_rw_block(READ, 1, &p_s_bh);
-                       wait_on_buffer(p_s_bh);
-                       if (!buffer_uptodate(p_s_bh))
+                       ll_rw_block(READ, 1, &bh);
+                       wait_on_buffer(bh);
+                       if (!buffer_uptodate(bh))
                                goto io_error;
                } else {
                      io_error:
-                       p_s_search_path->path_length--;
-                       pathrelse(p_s_search_path);
+                       search_path->path_length--;
+                       pathrelse(search_path);
                        return IO_ERROR;
                }
                reada_count = 0;
                if (expected_level == -1)
-                       expected_level = SB_TREE_HEIGHT(p_s_sb);
+                       expected_level = SB_TREE_HEIGHT(sb);
                expected_level--;
 
                /* It is possible that schedule occurred. We must check whether the key
                   to search is still in the tree rooted from the current buffer. If
                   not then repeat search from the root. */
-               if (fs_changed(fs_gen, p_s_sb) &&
-                   (!B_IS_IN_TREE(p_s_bh) ||
-                    B_LEVEL(p_s_bh) != expected_level ||
-                    !key_in_buffer(p_s_search_path, p_s_key, p_s_sb))) {
-                       PROC_INFO_INC(p_s_sb, search_by_key_fs_changed);
-                       PROC_INFO_INC(p_s_sb, search_by_key_restarted);
-                       PROC_INFO_INC(p_s_sb,
+               if (fs_changed(fs_gen, sb) &&
+                   (!B_IS_IN_TREE(bh) ||
+                    B_LEVEL(bh) != expected_level ||
+                    !key_in_buffer(search_path, key, sb))) {
+                       PROC_INFO_INC(sb, search_by_key_fs_changed);
+                       PROC_INFO_INC(sb, search_by_key_restarted);
+                       PROC_INFO_INC(sb,
                                      sbk_restarted[expected_level - 1]);
-                       decrement_counters_in_path(p_s_search_path);
+                       pathrelse(search_path);
 
                        /* Get the root block number so that we can repeat the search
                           starting from the root. */
-                       n_block_number = SB_ROOT_BLOCK(p_s_sb);
+                       block_number = SB_ROOT_BLOCK(sb);
                        expected_level = -1;
                        right_neighbor_of_leaf_node = 0;
 
@@ -704,53 +666,53 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key,      /*
                        continue;
                }
 
-               /* only check that the key is in the buffer if p_s_key is not
+               /* only check that the key is in the buffer if key is not
                   equal to the MAX_KEY. Latter case is only possible in
                   "finish_unfinished()" processing during mount. */
-               RFALSE(comp_keys(&MAX_KEY, p_s_key) &&
-                      !key_in_buffer(p_s_search_path, p_s_key, p_s_sb),
+               RFALSE(comp_keys(&MAX_KEY, key) &&
+                      !key_in_buffer(search_path, key, sb),
                       "PAP-5130: key is not in the buffer");
 #ifdef CONFIG_REISERFS_CHECK
                if (cur_tb) {
                        print_cur_tb("5140");
-                       reiserfs_panic(p_s_sb,
-                                      "PAP-5140: search_by_key: schedule occurred in do_balance!");
+                       reiserfs_panic(sb, "PAP-5140",
+                                      "schedule occurred in do_balance!");
                }
 #endif
 
                // make sure, that the node contents look like a node of
                // certain level
-               if (!is_tree_node(p_s_bh, expected_level)) {
-                       reiserfs_warning(p_s_sb, "vs-5150: search_by_key: "
-                                        "invalid format found in block %ld. Fsck?",
-                                        p_s_bh->b_blocknr);
-                       pathrelse(p_s_search_path);
+               if (!is_tree_node(bh, expected_level)) {
+                       reiserfs_error(sb, "vs-5150",
+                                      "invalid format found in block %ld. "
+                                      "Fsck?", bh->b_blocknr);
+                       pathrelse(search_path);
                        return IO_ERROR;
                }
 
                /* ok, we have acquired next formatted node in the tree */
-               n_node_level = B_LEVEL(p_s_bh);
+               node_level = B_LEVEL(bh);
 
-               PROC_INFO_BH_STAT(p_s_sb, p_s_bh, n_node_level - 1);
+               PROC_INFO_BH_STAT(sb, bh, node_level - 1);
 
-               RFALSE(n_node_level < n_stop_level,
+               RFALSE(node_level < stop_level,
                       "vs-5152: tree level (%d) is less than stop level (%d)",
-                      n_node_level, n_stop_level);
+                      node_level, stop_level);
 
-               n_retval = bin_search(p_s_key, B_N_PITEM_HEAD(p_s_bh, 0),
-                                     B_NR_ITEMS(p_s_bh),
-                                     (n_node_level ==
+               retval = bin_search(key, B_N_PITEM_HEAD(bh, 0),
+                                     B_NR_ITEMS(bh),
+                                     (node_level ==
                                       DISK_LEAF_NODE_LEVEL) ? IH_SIZE :
                                      KEY_SIZE,
-                                     &(p_s_last_element->pe_position));
-               if (n_node_level == n_stop_level) {
-                       return n_retval;
+                                     &(last_element->pe_position));
+               if (node_level == stop_level) {
+                       return retval;
                }
 
                /* we are not in the stop level */
-               if (n_retval == ITEM_FOUND)
+               if (retval == ITEM_FOUND)
                        /* item has been found, so we choose the pointer which is to the right of the found one */
-                       p_s_last_element->pe_position++;
+                       last_element->pe_position++;
 
                /* if item was not found we choose the position which is to
                   the left of the found item. This requires no code,
@@ -759,24 +721,24 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key,      /*
                /* So we have chosen a position in the current node which is
                   an internal node.  Now we calculate child block number by
                   position in the node. */
-               n_block_number =
-                   B_N_CHILD_NUM(p_s_bh, p_s_last_element->pe_position);
+               block_number =
+                   B_N_CHILD_NUM(bh, last_element->pe_position);
 
                /* if we are going to read leaf nodes, try for read ahead as well */
-               if ((p_s_search_path->reada & PATH_READA) &&
-                   n_node_level == DISK_LEAF_NODE_LEVEL + 1) {
-                       int pos = p_s_last_element->pe_position;
-                       int limit = B_NR_ITEMS(p_s_bh);
+               if ((search_path->reada & PATH_READA) &&
+                   node_level == DISK_LEAF_NODE_LEVEL + 1) {
+                       int pos = last_element->pe_position;
+                       int limit = B_NR_ITEMS(bh);
                        struct reiserfs_key *le_key;
 
-                       if (p_s_search_path->reada & PATH_READA_BACK)
+                       if (search_path->reada & PATH_READA_BACK)
                                limit = 0;
                        while (reada_count < SEARCH_BY_KEY_READA) {
                                if (pos == limit)
                                        break;
                                reada_blocks[reada_count++] =
-                                   B_N_CHILD_NUM(p_s_bh, pos);
-                               if (p_s_search_path->reada & PATH_READA_BACK)
+                                   B_N_CHILD_NUM(bh, pos);
+                               if (search_path->reada & PATH_READA_BACK)
                                        pos--;
                                else
                                        pos++;
@@ -784,9 +746,9 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key,        /*
                                /*
                                 * check to make sure we're in the same object
                                 */
-                               le_key = B_N_PDELIM_KEY(p_s_bh, pos);
+                               le_key = B_N_PDELIM_KEY(bh, pos);
                                if (le32_to_cpu(le_key->k_objectid) !=
-                                   p_s_key->on_disk_key.k_objectid) {
+                                   key->on_disk_key.k_objectid) {
                                        break;
                                }
                        }
@@ -795,11 +757,11 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key,      /*
 }
 
 /* Form the path to an item and position in this item which contains
-   file byte defined by p_s_key. If there is no such item
+   file byte defined by key. If there is no such item
    corresponding to the key, we point the path to the item with
-   maximal key less than p_s_key, and *p_n_pos_in_item is set to one
+   maximal key less than key, and *pos_in_item is set to one
    past the last entry/byte in the item.  If searching for entry in a
-   directory item, and it is not found, *p_n_pos_in_item is set to one
+   directory item, and it is not found, *pos_in_item is set to one
    entry more than the entry with maximal key which is less than the
    sought key.
 
@@ -810,48 +772,48 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key,      /*
    units of directory entries.  */
 
 /* The function is NOT SCHEDULE-SAFE! */
-int search_for_position_by_key(struct super_block *p_s_sb,     /* Pointer to the super block.          */
+int search_for_position_by_key(struct super_block *sb, /* Pointer to the super block.          */
                               const struct cpu_key *p_cpu_key, /* Key to search (cpu variable)         */
-                              struct treepath *p_s_search_path /* Filled up by this function.          */
+                              struct treepath *search_path     /* Filled up by this function.          */
     )
 {
        struct item_head *p_le_ih;      /* pointer to on-disk structure */
-       int n_blk_size;
+       int blk_size;
        loff_t item_offset, offset;
        struct reiserfs_dir_entry de;
        int retval;
 
        /* If searching for directory entry. */
        if (is_direntry_cpu_key(p_cpu_key))
-               return search_by_entry_key(p_s_sb, p_cpu_key, p_s_search_path,
+               return search_by_entry_key(sb, p_cpu_key, search_path,
                                           &de);
 
        /* If not searching for directory entry. */
 
        /* If item is found. */
-       retval = search_item(p_s_sb, p_cpu_key, p_s_search_path);
+       retval = search_item(sb, p_cpu_key, search_path);
        if (retval == IO_ERROR)
                return retval;
        if (retval == ITEM_FOUND) {
 
                RFALSE(!ih_item_len
                       (B_N_PITEM_HEAD
-                       (PATH_PLAST_BUFFER(p_s_search_path),
-                        PATH_LAST_POSITION(p_s_search_path))),
+                       (PATH_PLAST_BUFFER(search_path),
+                        PATH_LAST_POSITION(search_path))),
                       "PAP-5165: item length equals zero");
 
-               pos_in_item(p_s_search_path) = 0;
+               pos_in_item(search_path) = 0;
                return POSITION_FOUND;
        }
 
-       RFALSE(!PATH_LAST_POSITION(p_s_search_path),
+       RFALSE(!PATH_LAST_POSITION(search_path),
               "PAP-5170: position equals zero");
 
        /* Item is not found. Set path to the previous item. */
        p_le_ih =
-           B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_search_path),
-                          --PATH_LAST_POSITION(p_s_search_path));
-       n_blk_size = p_s_sb->s_blocksize;
+           B_N_PITEM_HEAD(PATH_PLAST_BUFFER(search_path),
+                          --PATH_LAST_POSITION(search_path));
+       blk_size = sb->s_blocksize;
 
        if (comp_short_keys(&(p_le_ih->ih_key), p_cpu_key)) {
                return FILE_NOT_FOUND;
@@ -863,10 +825,10 @@ int search_for_position_by_key(struct super_block *p_s_sb,        /* Pointer to the sup
 
        /* Needed byte is contained in the item pointed to by the path. */
        if (item_offset <= offset &&
-           item_offset + op_bytes_number(p_le_ih, n_blk_size) > offset) {
-               pos_in_item(p_s_search_path) = offset - item_offset;
+           item_offset + op_bytes_number(p_le_ih, blk_size) > offset) {
+               pos_in_item(search_path) = offset - item_offset;
                if (is_indirect_le_ih(p_le_ih)) {
-                       pos_in_item(p_s_search_path) /= n_blk_size;
+                       pos_in_item(search_path) /= blk_size;
                }
                return POSITION_FOUND;
        }
@@ -874,30 +836,30 @@ int search_for_position_by_key(struct super_block *p_s_sb,        /* Pointer to the sup
        /* Needed byte is not contained in the item pointed to by the
           path. Set pos_in_item out of the item. */
        if (is_indirect_le_ih(p_le_ih))
-               pos_in_item(p_s_search_path) =
+               pos_in_item(search_path) =
                    ih_item_len(p_le_ih) / UNFM_P_SIZE;
        else
-               pos_in_item(p_s_search_path) = ih_item_len(p_le_ih);
+               pos_in_item(search_path) = ih_item_len(p_le_ih);
 
        return POSITION_NOT_FOUND;
 }
 
 /* Compare given item and item pointed to by the path. */
-int comp_items(const struct item_head *stored_ih, const struct treepath *p_s_path)
+int comp_items(const struct item_head *stored_ih, const struct treepath *path)
 {
-       struct buffer_head *p_s_bh;
+       struct buffer_head *bh = PATH_PLAST_BUFFER(path);
        struct item_head *ih;
 
        /* Last buffer at the path is not in the tree. */
-       if (!B_IS_IN_TREE(p_s_bh = PATH_PLAST_BUFFER(p_s_path)))
+       if (!B_IS_IN_TREE(bh))
                return 1;
 
        /* Last path position is invalid. */
-       if (PATH_LAST_POSITION(p_s_path) >= B_NR_ITEMS(p_s_bh))
+       if (PATH_LAST_POSITION(path) >= B_NR_ITEMS(bh))
                return 1;
 
        /* we need only to know, whether it is the same item */
-       ih = get_ih(p_s_path);
+       ih = get_ih(path);
        return memcmp(stored_ih, ih, IH_SIZE);
 }
 
@@ -924,9 +886,9 @@ static inline int prepare_for_direct_item(struct treepath *path,
        }
        // new file gets truncated
        if (get_inode_item_key_version(inode) == KEY_FORMAT_3_6) {
-               // 
+               //
                round_len = ROUND_UP(new_file_length);
-               /* this was n_new_file_length < le_ih ... */
+               /* this was new_file_length < le_ih ... */
                if (round_len < le_ih_k_offset(le_ih)) {
                        *cut_size = -(IH_SIZE + ih_item_len(le_ih));
                        return M_DELETE;        /* Delete this item. */
@@ -986,96 +948,95 @@ static inline int prepare_for_direntry_item(struct treepath *path,
     In case of file truncate calculate whether this item must be deleted/truncated or last
     unformatted node of this item will be converted to a direct item.
     This function returns a determination of what balance mode the calling function should employ. */
-static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, struct inode *inode, struct treepath *p_s_path, const struct cpu_key *p_s_item_key, int *p_n_removed,    /* Number of unformatted nodes which were removed
+static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, struct inode *inode, struct treepath *path, const struct cpu_key *item_key, int *removed,        /* Number of unformatted nodes which were removed
                                                                                                                                                                                   from end of the file. */
-                                     int *p_n_cut_size, unsigned long long n_new_file_length   /* MAX_KEY_OFFSET in case of delete. */
+                                     int *cut_size, unsigned long long new_file_length /* MAX_KEY_OFFSET in case of delete. */
     )
 {
-       struct super_block *p_s_sb = inode->i_sb;
-       struct item_head *p_le_ih = PATH_PITEM_HEAD(p_s_path);
-       struct buffer_head *p_s_bh = PATH_PLAST_BUFFER(p_s_path);
+       struct super_block *sb = inode->i_sb;
+       struct item_head *p_le_ih = PATH_PITEM_HEAD(path);
+       struct buffer_head *bh = PATH_PLAST_BUFFER(path);
 
        BUG_ON(!th->t_trans_id);
 
        /* Stat_data item. */
        if (is_statdata_le_ih(p_le_ih)) {
 
-               RFALSE(n_new_file_length != max_reiserfs_offset(inode),
+               RFALSE(new_file_length != max_reiserfs_offset(inode),
                       "PAP-5210: mode must be M_DELETE");
 
-               *p_n_cut_size = -(IH_SIZE + ih_item_len(p_le_ih));
+               *cut_size = -(IH_SIZE + ih_item_len(p_le_ih));
                return M_DELETE;
        }
 
        /* Directory item. */
        if (is_direntry_le_ih(p_le_ih))
-               return prepare_for_direntry_item(p_s_path, p_le_ih, inode,
-                                                n_new_file_length,
-                                                p_n_cut_size);
+               return prepare_for_direntry_item(path, p_le_ih, inode,
+                                                new_file_length,
+                                                cut_size);
 
        /* Direct item. */
        if (is_direct_le_ih(p_le_ih))
-               return prepare_for_direct_item(p_s_path, p_le_ih, inode,
-                                              n_new_file_length, p_n_cut_size);
+               return prepare_for_direct_item(path, p_le_ih, inode,
+                                              new_file_length, cut_size);
 
        /* Case of an indirect item. */
        {
-           int blk_size = p_s_sb->s_blocksize;
+           int blk_size = sb->s_blocksize;
            struct item_head s_ih;
            int need_re_search;
            int delete = 0;
            int result = M_CUT;
            int pos = 0;
 
-           if ( n_new_file_length == max_reiserfs_offset (inode) ) {
+           if ( new_file_length == max_reiserfs_offset (inode) ) {
                /* prepare_for_delete_or_cut() is called by
                 * reiserfs_delete_item() */
-               n_new_file_length = 0;
+               new_file_length = 0;
                delete = 1;
            }
 
            do {
                need_re_search = 0;
-               *p_n_cut_size = 0;
-               p_s_bh = PATH_PLAST_BUFFER(p_s_path);
-               copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
+               *cut_size = 0;
+               bh = PATH_PLAST_BUFFER(path);
+               copy_item_head(&s_ih, PATH_PITEM_HEAD(path));
                pos = I_UNFM_NUM(&s_ih);
 
-               while (le_ih_k_offset (&s_ih) + (pos - 1) * blk_size > n_new_file_length) {
+               while (le_ih_k_offset (&s_ih) + (pos - 1) * blk_size > new_file_length) {
                    __le32 *unfm;
                    __u32 block;
 
                    /* Each unformatted block deletion may involve one additional
                     * bitmap block into the transaction, thereby the initial
                     * journal space reservation might not be enough. */
-                   if (!delete && (*p_n_cut_size) != 0 &&
-                       reiserfs_transaction_free_space(th) < JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD) {
+                   if (!delete && (*cut_size) != 0 &&
+                       reiserfs_transaction_free_space(th) < JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD)
                        break;
-                   }
 
-                   unfm = (__le32 *)B_I_PITEM(p_s_bh, &s_ih) + pos - 1;
+                   unfm = (__le32 *)B_I_PITEM(bh, &s_ih) + pos - 1;
                    block = get_block_num(unfm, 0);
 
                    if (block != 0) {
-                       reiserfs_prepare_for_journal(p_s_sb, p_s_bh, 1);
+                       reiserfs_prepare_for_journal(sb, bh, 1);
                        put_block_num(unfm, 0, 0);
-                       journal_mark_dirty (th, p_s_sb, p_s_bh);
+                       journal_mark_dirty(th, sb, bh);
                        reiserfs_free_block(th, inode, block, 1);
                    }
 
                    cond_resched();
 
-                   if (item_moved (&s_ih, p_s_path))  {
+                   if (item_moved (&s_ih, path))  {
                        need_re_search = 1;
                        break;
                    }
 
                    pos --;
-                   (*p_n_removed) ++;
-                   (*p_n_cut_size) -= UNFM_P_SIZE;
+                   (*removed)++;
+                   (*cut_size) -= UNFM_P_SIZE;
 
                    if (pos == 0) {
-                       (*p_n_cut_size) -= IH_SIZE;
+                       (*cut_size) -= IH_SIZE;
                        result = M_DELETE;
                        break;
                    }
@@ -1083,12 +1044,12 @@ static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, st
                /* a trick.  If the buffer has been logged, this will do nothing.  If
                ** we've broken the loop without logging it, it will restore the
                ** buffer */
-               reiserfs_restore_prepared_buffer(p_s_sb, p_s_bh);
+               reiserfs_restore_prepared_buffer(sb, bh);
            } while (need_re_search &&
-                    search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path) == POSITION_FOUND);
-           pos_in_item(p_s_path) = pos * UNFM_P_SIZE;
+                    search_for_position_by_key(sb, item_key, path) == POSITION_FOUND);
+           pos_in_item(path) = pos * UNFM_P_SIZE;
 
-           if (*p_n_cut_size == 0) {
+           if (*cut_size == 0) {
                /* Nothing were cut. maybe convert last unformatted node to the
                 * direct item? */
                result = M_CONVERT;
@@ -1098,45 +1059,45 @@ static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, st
 }
 
 /* Calculate number of bytes which will be deleted or cut during balance */
-static int calc_deleted_bytes_number(struct tree_balance *p_s_tb, char c_mode)
+static int calc_deleted_bytes_number(struct tree_balance *tb, char mode)
 {
-       int n_del_size;
-       struct item_head *p_le_ih = PATH_PITEM_HEAD(p_s_tb->tb_path);
+       int del_size;
+       struct item_head *p_le_ih = PATH_PITEM_HEAD(tb->tb_path);
 
        if (is_statdata_le_ih(p_le_ih))
                return 0;
 
-       n_del_size =
-           (c_mode ==
-            M_DELETE) ? ih_item_len(p_le_ih) : -p_s_tb->insert_size[0];
+       del_size =
+           (mode ==
+            M_DELETE) ? ih_item_len(p_le_ih) : -tb->insert_size[0];
        if (is_direntry_le_ih(p_le_ih)) {
-               // return EMPTY_DIR_SIZE; /* We delete emty directoris only. */
-               // we can't use EMPTY_DIR_SIZE, as old format dirs have a different
-               // empty size.  ick. FIXME, is this right?
-               //
-               return n_del_size;
+               /* return EMPTY_DIR_SIZE; We delete emty directoris only.
+                * we can't use EMPTY_DIR_SIZE, as old format dirs have a different
+                * empty size.  ick. FIXME, is this right? */
+               return del_size;
        }
 
        if (is_indirect_le_ih(p_le_ih))
-               n_del_size = (n_del_size / UNFM_P_SIZE) * (PATH_PLAST_BUFFER(p_s_tb->tb_path)->b_size); // - get_ih_free_space (p_le_ih);
-       return n_del_size;
+               del_size = (del_size / UNFM_P_SIZE) *
+                               (PATH_PLAST_BUFFER(tb->tb_path)->b_size);
+       return del_size;
 }
 
 static void init_tb_struct(struct reiserfs_transaction_handle *th,
-                          struct tree_balance *p_s_tb,
-                          struct super_block *p_s_sb,
-                          struct treepath *p_s_path, int n_size)
+                          struct tree_balance *tb,
+                          struct super_block *sb,
+                          struct treepath *path, int size)
 {
 
        BUG_ON(!th->t_trans_id);
 
-       memset(p_s_tb, '\0', sizeof(struct tree_balance));
-       p_s_tb->transaction_handle = th;
-       p_s_tb->tb_sb = p_s_sb;
-       p_s_tb->tb_path = p_s_path;
-       PATH_OFFSET_PBUFFER(p_s_path, ILLEGAL_PATH_ELEMENT_OFFSET) = NULL;
-       PATH_OFFSET_POSITION(p_s_path, ILLEGAL_PATH_ELEMENT_OFFSET) = 0;
-       p_s_tb->insert_size[0] = n_size;
+       memset(tb, '\0', sizeof(struct tree_balance));
+       tb->transaction_handle = th;
+       tb->tb_sb = sb;
+       tb->tb_path = path;
+       PATH_OFFSET_PBUFFER(path, ILLEGAL_PATH_ELEMENT_OFFSET) = NULL;
+       PATH_OFFSET_POSITION(path, ILLEGAL_PATH_ELEMENT_OFFSET) = 0;
+       tb->insert_size[0] = size;
 }
 
 void padd_item(char *item, int total_length, int length)
@@ -1175,73 +1136,77 @@ char head2type(struct item_head *ih)
 }
 #endif
 
-/* Delete object item. */
-int reiserfs_delete_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_path,    /* Path to the deleted item. */
-                        const struct cpu_key *p_s_item_key,    /* Key to search for the deleted item.  */
-                        struct inode *p_s_inode,       /* inode is here just to update i_blocks and quotas */
-                        struct buffer_head *p_s_un_bh)
-{                              /* NULL or unformatted node pointer.    */
-       struct super_block *p_s_sb = p_s_inode->i_sb;
+/* Delete object item.
+ * th       - active transaction handle
+ * path     - path to the deleted item
+ * item_key - key to search for the deleted item
+ * indode   - used for updating i_blocks and quotas
+ * un_bh    - NULL or unformatted node pointer
+ */
+int reiserfs_delete_item(struct reiserfs_transaction_handle *th,
+                        struct treepath *path, const struct cpu_key *item_key,
+                        struct inode *inode, struct buffer_head *un_bh)
+{
+       struct super_block *sb = inode->i_sb;
        struct tree_balance s_del_balance;
        struct item_head s_ih;
        struct item_head *q_ih;
        int quota_cut_bytes;
-       int n_ret_value, n_del_size, n_removed;
+       int ret_value, del_size, removed;
 
 #ifdef CONFIG_REISERFS_CHECK
-       char c_mode;
-       int n_iter = 0;
+       char mode;
+       int iter = 0;
 #endif
 
        BUG_ON(!th->t_trans_id);
 
-       init_tb_struct(th, &s_del_balance, p_s_sb, p_s_path,
+       init_tb_struct(th, &s_del_balance, sb, path,
                       0 /*size is unknown */ );
 
        while (1) {
-               n_removed = 0;
+               removed = 0;
 
 #ifdef CONFIG_REISERFS_CHECK
-               n_iter++;
-               c_mode =
+               iter++;
+               mode =
 #endif
-                   prepare_for_delete_or_cut(th, p_s_inode, p_s_path,
-                                             p_s_item_key, &n_removed,
-                                             &n_del_size,
-                                             max_reiserfs_offset(p_s_inode));
+                   prepare_for_delete_or_cut(th, inode, path,
+                                             item_key, &removed,
+                                             &del_size,
+                                             max_reiserfs_offset(inode));
 
-               RFALSE(c_mode != M_DELETE, "PAP-5320: mode must be M_DELETE");
+               RFALSE(mode != M_DELETE, "PAP-5320: mode must be M_DELETE");
 
-               copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
-               s_del_balance.insert_size[0] = n_del_size;
+               copy_item_head(&s_ih, PATH_PITEM_HEAD(path));
+               s_del_balance.insert_size[0] = del_size;
 
-               n_ret_value = fix_nodes(M_DELETE, &s_del_balance, NULL, NULL);
-               if (n_ret_value != REPEAT_SEARCH)
+               ret_value = fix_nodes(M_DELETE, &s_del_balance, NULL, NULL);
+               if (ret_value != REPEAT_SEARCH)
                        break;
 
-               PROC_INFO_INC(p_s_sb, delete_item_restarted);
+               PROC_INFO_INC(sb, delete_item_restarted);
 
                // file system changed, repeat search
-               n_ret_value =
-                   search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path);
-               if (n_ret_value == IO_ERROR)
+               ret_value =
+                   search_for_position_by_key(sb, item_key, path);
+               if (ret_value == IO_ERROR)
                        break;
-               if (n_ret_value == FILE_NOT_FOUND) {
-                       reiserfs_warning(p_s_sb,
-                                        "vs-5340: reiserfs_delete_item: "
+               if (ret_value == FILE_NOT_FOUND) {
+                       reiserfs_warning(sb, "vs-5340",
                                         "no items of the file %K found",
-                                        p_s_item_key);
+                                        item_key);
                        break;
                }
        }                       /* while (1) */
 
-       if (n_ret_value != CARRY_ON) {
+       if (ret_value != CARRY_ON) {
                unfix_nodes(&s_del_balance);
                return 0;
        }
        // reiserfs_delete_item returns item length when success
-       n_ret_value = calc_deleted_bytes_number(&s_del_balance, M_DELETE);
-       q_ih = get_ih(p_s_path);
+       ret_value = calc_deleted_bytes_number(&s_del_balance, M_DELETE);
+       q_ih = get_ih(path);
        quota_cut_bytes = ih_item_len(q_ih);
 
        /* hack so the quota code doesn't have to guess if the file
@@ -1250,15 +1215,15 @@ int reiserfs_delete_item(struct reiserfs_transaction_handle *th, struct treepath
         ** split into multiple items, and we only want to decrement for
         ** the unfm node once
         */
-       if (!S_ISLNK(p_s_inode->i_mode) && is_direct_le_ih(q_ih)) {
-               if ((le_ih_k_offset(q_ih) & (p_s_sb->s_blocksize - 1)) == 1) {
-                       quota_cut_bytes = p_s_sb->s_blocksize + UNFM_P_SIZE;
+       if (!S_ISLNK(inode->i_mode) && is_direct_le_ih(q_ih)) {
+               if ((le_ih_k_offset(q_ih) & (sb->s_blocksize - 1)) == 1) {
+                       quota_cut_bytes = sb->s_blocksize + UNFM_P_SIZE;
                } else {
                        quota_cut_bytes = 0;
                }
        }
 
-       if (p_s_un_bh) {
+       if (un_bh) {
                int off;
                char *data;
 
@@ -1276,31 +1241,31 @@ int reiserfs_delete_item(struct reiserfs_transaction_handle *th, struct treepath
                 ** The unformatted node must be dirtied later on.  We can't be
                 ** sure here if the entire tail has been deleted yet.
                 **
-                ** p_s_un_bh is from the page cache (all unformatted nodes are
+                ** un_bh is from the page cache (all unformatted nodes are
                 ** from the page cache) and might be a highmem page.  So, we
-                ** can't use p_s_un_bh->b_data.
+                ** can't use un_bh->b_data.
                 ** -clm
                 */
 
-               data = kmap_atomic(p_s_un_bh->b_page, KM_USER0);
+               data = kmap_atomic(un_bh->b_page, KM_USER0);
                off = ((le_ih_k_offset(&s_ih) - 1) & (PAGE_CACHE_SIZE - 1));
                memcpy(data + off,
-                      B_I_PITEM(PATH_PLAST_BUFFER(p_s_path), &s_ih),
-                      n_ret_value);
+                      B_I_PITEM(PATH_PLAST_BUFFER(path), &s_ih),
+                      ret_value);
                kunmap_atomic(data, KM_USER0);
        }
        /* Perform balancing after all resources have been collected at once. */
        do_balance(&s_del_balance, NULL, NULL, M_DELETE);
 
 #ifdef REISERQUOTA_DEBUG
-       reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+       reiserfs_debug(sb, REISERFS_DEBUG_CODE,
                       "reiserquota delete_item(): freeing %u, id=%u type=%c",
-                      quota_cut_bytes, p_s_inode->i_uid, head2type(&s_ih));
+                      quota_cut_bytes, inode->i_uid, head2type(&s_ih));
 #endif
-       vfs_dq_free_space_nodirty(p_s_inode, quota_cut_bytes);
+       vfs_dq_free_space_nodirty(inode, quota_cut_bytes);
 
        /* Return deleted body length */
-       return n_ret_value;
+       return ret_value;
 }
 
 /* Summary Of Mechanisms For Handling Collisions Between Processes:
@@ -1338,10 +1303,9 @@ void reiserfs_delete_solid_item(struct reiserfs_transaction_handle *th,
        while (1) {
                retval = search_item(th->t_super, &cpu_key, &path);
                if (retval == IO_ERROR) {
-                       reiserfs_warning(th->t_super,
-                                        "vs-5350: reiserfs_delete_solid_item: "
-                                        "i/o failure occurred trying to delete %K",
-                                        &cpu_key);
+                       reiserfs_error(th->t_super, "vs-5350",
+                                      "i/o failure occurred trying "
+                                      "to delete %K", &cpu_key);
                        break;
                }
                if (retval != ITEM_FOUND) {
@@ -1355,9 +1319,8 @@ void reiserfs_delete_solid_item(struct reiserfs_transaction_handle *th,
                             GET_GENERATION_NUMBER(le_key_k_offset
                                                   (le_key_version(key),
                                                    key)) == 1))
-                               reiserfs_warning(th->t_super,
-                                                "vs-5355: reiserfs_delete_solid_item: %k not found",
-                                                key);
+                               reiserfs_warning(th->t_super, "vs-5355",
+                                                "%k not found", key);
                        break;
                }
                if (!tb_init) {
@@ -1389,8 +1352,7 @@ void reiserfs_delete_solid_item(struct reiserfs_transaction_handle *th,
                        break;
                }
                // IO_ERROR, NO_DISK_SPACE, etc
-               reiserfs_warning(th->t_super,
-                                "vs-5360: reiserfs_delete_solid_item: "
+               reiserfs_warning(th->t_super, "vs-5360",
                                 "could not delete %K due to fix_nodes failure",
                                 &cpu_key);
                unfix_nodes(&tb);
@@ -1462,36 +1424,37 @@ static void unmap_buffers(struct page *page, loff_t pos)
 }
 
 static int maybe_indirect_to_direct(struct reiserfs_transaction_handle *th,
-                                   struct inode *p_s_inode,
+                                   struct inode *inode,
                                    struct page *page,
-                                   struct treepath *p_s_path,
-                                   const struct cpu_key *p_s_item_key,
-                                   loff_t n_new_file_size, char *p_c_mode)
+                                   struct treepath *path,
+                                   const struct cpu_key *item_key,
+                                   loff_t new_file_size, char *mode)
 {
-       struct super_block *p_s_sb = p_s_inode->i_sb;
-       int n_block_size = p_s_sb->s_blocksize;
+       struct super_block *sb = inode->i_sb;
+       int block_size = sb->s_blocksize;
        int cut_bytes;
        BUG_ON(!th->t_trans_id);
-       BUG_ON(n_new_file_size != p_s_inode->i_size);
+       BUG_ON(new_file_size != inode->i_size);
 
        /* the page being sent in could be NULL if there was an i/o error
         ** reading in the last block.  The user will hit problems trying to
         ** read the file, but for now we just skip the indirect2direct
         */
-       if (atomic_read(&p_s_inode->i_count) > 1 ||
-           !tail_has_to_be_packed(p_s_inode) ||
-           !page || (REISERFS_I(p_s_inode)->i_flags & i_nopack_mask)) {
-               // leave tail in an unformatted node    
-               *p_c_mode = M_SKIP_BALANCING;
+       if (atomic_read(&inode->i_count) > 1 ||
+           !tail_has_to_be_packed(inode) ||
+           !page || (REISERFS_I(inode)->i_flags & i_nopack_mask)) {
+               /* leave tail in an unformatted node */
+               *mode = M_SKIP_BALANCING;
                cut_bytes =
-                   n_block_size - (n_new_file_size & (n_block_size - 1));
-               pathrelse(p_s_path);
+                   block_size - (new_file_size & (block_size - 1));
+               pathrelse(path);
                return cut_bytes;
        }
-       /* Permorm the conversion to a direct_item. */
-       /*return indirect_to_direct (p_s_inode, p_s_path, p_s_item_key, n_new_file_size, p_c_mode); */
-       return indirect2direct(th, p_s_inode, page, p_s_path, p_s_item_key,
-                              n_new_file_size, p_c_mode);
+       /* Perform the conversion to a direct_item. */
+       /* return indirect_to_direct(inode, path, item_key,
+                                 new_file_size, mode); */
+       return indirect2direct(th, inode, page, path, item_key,
+                              new_file_size, mode);
 }
 
 /* we did indirect_to_direct conversion. And we have inserted direct
@@ -1515,8 +1478,8 @@ static void indirect_to_direct_roll_back(struct reiserfs_transaction_handle *th,
                /* look for the last byte of the tail */
                if (search_for_position_by_key(inode->i_sb, &tail_key, path) ==
                    POSITION_NOT_FOUND)
-                       reiserfs_panic(inode->i_sb,
-                                      "vs-5615: indirect_to_direct_roll_back: found invalid item");
+                       reiserfs_panic(inode->i_sb, "vs-5615",
+                                      "found invalid item");
                RFALSE(path->pos_in_item !=
                       ih_item_len(PATH_PITEM_HEAD(path)) - 1,
                       "vs-5616: appended bytes found");
@@ -1533,38 +1496,39 @@ static void indirect_to_direct_roll_back(struct reiserfs_transaction_handle *th,
                set_cpu_key_k_offset(&tail_key,
                                     cpu_key_k_offset(&tail_key) - removed);
        }
-       reiserfs_warning(inode->i_sb,
-                        "indirect_to_direct_roll_back: indirect_to_direct conversion has been rolled back due to lack of disk space");
+       reiserfs_warning(inode->i_sb, "reiserfs-5091", "indirect_to_direct "
+                        "conversion has been rolled back due to "
+                        "lack of disk space");
        //mark_file_without_tail (inode);
        mark_inode_dirty(inode);
 }
 
 /* (Truncate or cut entry) or delete object item. Returns < 0 on failure */
 int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th,
-                          struct treepath *p_s_path,
-                          struct cpu_key *p_s_item_key,
-                          struct inode *p_s_inode,
-                          struct page *page, loff_t n_new_file_size)
+                          struct treepath *path,
+                          struct cpu_key *item_key,
+                          struct inode *inode,
+                          struct page *page, loff_t new_file_size)
 {
-       struct super_block *p_s_sb = p_s_inode->i_sb;
+       struct super_block *sb = inode->i_sb;
        /* Every function which is going to call do_balance must first
           create a tree_balance structure.  Then it must fill up this
           structure by using the init_tb_struct and fix_nodes functions.
           After that we can make tree balancing. */
        struct tree_balance s_cut_balance;
        struct item_head *p_le_ih;
-       int n_cut_size = 0,     /* Amount to be cut. */
-           n_ret_value = CARRY_ON, n_removed = 0,      /* Number of the removed unformatted nodes. */
-           n_is_inode_locked = 0;
-       char c_mode;            /* Mode of the balance. */
+       int cut_size = 0,       /* Amount to be cut. */
+           ret_value = CARRY_ON, removed = 0,  /* Number of the removed unformatted nodes. */
+           is_inode_locked = 0;
+       char mode;              /* Mode of the balance. */
        int retval2 = -1;
        int quota_cut_bytes;
        loff_t tail_pos = 0;
 
        BUG_ON(!th->t_trans_id);
 
-       init_tb_struct(th, &s_cut_balance, p_s_inode->i_sb, p_s_path,
-                      n_cut_size);
+       init_tb_struct(th, &s_cut_balance, inode->i_sb, path,
+                      cut_size);
 
        /* Repeat this loop until we either cut the item without needing
           to balance, or we fix_nodes without schedule occurring */
@@ -1574,144 +1538,142 @@ int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th,
                   free unformatted nodes which are pointed to by the cut
                   pointers. */
 
-               c_mode =
-                   prepare_for_delete_or_cut(th, p_s_inode, p_s_path,
-                                             p_s_item_key, &n_removed,
-                                             &n_cut_size, n_new_file_size);
-               if (c_mode == M_CONVERT) {
+               mode =
+                   prepare_for_delete_or_cut(th, inode, path,
+                                             item_key, &removed,
+                                             &cut_size, new_file_size);
+               if (mode == M_CONVERT) {
                        /* convert last unformatted node to direct item or leave
                           tail in the unformatted node */
-                       RFALSE(n_ret_value != CARRY_ON,
+                       RFALSE(ret_value != CARRY_ON,
                               "PAP-5570: can not convert twice");
 
-                       n_ret_value =
-                           maybe_indirect_to_direct(th, p_s_inode, page,
-                                                    p_s_path, p_s_item_key,
-                                                    n_new_file_size, &c_mode);
-                       if (c_mode == M_SKIP_BALANCING)
+                       ret_value =
+                           maybe_indirect_to_direct(th, inode, page,
+                                                    path, item_key,
+                                                    new_file_size, &mode);
+                       if (mode == M_SKIP_BALANCING)
                                /* tail has been left in the unformatted node */
-                               return n_ret_value;
+                               return ret_value;
 
-                       n_is_inode_locked = 1;
+                       is_inode_locked = 1;
 
                        /* removing of last unformatted node will change value we
                           have to return to truncate. Save it */
-                       retval2 = n_ret_value;
-                       /*retval2 = p_s_sb->s_blocksize - (n_new_file_size & (p_s_sb->s_blocksize - 1)); */
+                       retval2 = ret_value;
+                       /*retval2 = sb->s_blocksize - (new_file_size & (sb->s_blocksize - 1)); */
 
                        /* So, we have performed the first part of the conversion:
                           inserting the new direct item.  Now we are removing the
                           last unformatted node pointer. Set key to search for
                           it. */
-                       set_cpu_key_k_type(p_s_item_key, TYPE_INDIRECT);
-                       p_s_item_key->key_length = 4;
-                       n_new_file_size -=
-                           (n_new_file_size & (p_s_sb->s_blocksize - 1));
-                       tail_pos = n_new_file_size;
-                       set_cpu_key_k_offset(p_s_item_key, n_new_file_size + 1);
+                       set_cpu_key_k_type(item_key, TYPE_INDIRECT);
+                       item_key->key_length = 4;
+                       new_file_size -=
+                           (new_file_size & (sb->s_blocksize - 1));
+                       tail_pos = new_file_size;
+                       set_cpu_key_k_offset(item_key, new_file_size + 1);
                        if (search_for_position_by_key
-                           (p_s_sb, p_s_item_key,
-                            p_s_path) == POSITION_NOT_FOUND) {
-                               print_block(PATH_PLAST_BUFFER(p_s_path), 3,
-                                           PATH_LAST_POSITION(p_s_path) - 1,
-                                           PATH_LAST_POSITION(p_s_path) + 1);
-                               reiserfs_panic(p_s_sb,
-                                              "PAP-5580: reiserfs_cut_from_item: item to convert does not exist (%K)",
-                                              p_s_item_key);
+                           (sb, item_key,
+                            path) == POSITION_NOT_FOUND) {
+                               print_block(PATH_PLAST_BUFFER(path), 3,
+                                           PATH_LAST_POSITION(path) - 1,
+                                           PATH_LAST_POSITION(path) + 1);
+                               reiserfs_panic(sb, "PAP-5580", "item to "
+                                              "convert does not exist (%K)",
+                                              item_key);
                        }
                        continue;
                }
-               if (n_cut_size == 0) {
-                       pathrelse(p_s_path);
+               if (cut_size == 0) {
+                       pathrelse(path);
                        return 0;
                }
 
-               s_cut_balance.insert_size[0] = n_cut_size;
+               s_cut_balance.insert_size[0] = cut_size;
 
-               n_ret_value = fix_nodes(c_mode, &s_cut_balance, NULL, NULL);
-               if (n_ret_value != REPEAT_SEARCH)
+               ret_value = fix_nodes(mode, &s_cut_balance, NULL, NULL);
+               if (ret_value != REPEAT_SEARCH)
                        break;
 
-               PROC_INFO_INC(p_s_sb, cut_from_item_restarted);
+               PROC_INFO_INC(sb, cut_from_item_restarted);
 
-               n_ret_value =
-                   search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path);
-               if (n_ret_value == POSITION_FOUND)
+               ret_value =
+                   search_for_position_by_key(sb, item_key, path);
+               if (ret_value == POSITION_FOUND)
                        continue;
 
-               reiserfs_warning(p_s_sb,
-                                "PAP-5610: reiserfs_cut_from_item: item %K not found",
-                                p_s_item_key);
+               reiserfs_warning(sb, "PAP-5610", "item %K not found",
+                                item_key);
                unfix_nodes(&s_cut_balance);
-               return (n_ret_value == IO_ERROR) ? -EIO : -ENOENT;
+               return (ret_value == IO_ERROR) ? -EIO : -ENOENT;
        }                       /* while */
 
        // check fix_nodes results (IO_ERROR or NO_DISK_SPACE)
-       if (n_ret_value != CARRY_ON) {
-               if (n_is_inode_locked) {
+       if (ret_value != CARRY_ON) {
+               if (is_inode_locked) {
                        // FIXME: this seems to be not needed: we are always able
                        // to cut item
-                       indirect_to_direct_roll_back(th, p_s_inode, p_s_path);
+                       indirect_to_direct_roll_back(th, inode, path);
                }
-               if (n_ret_value == NO_DISK_SPACE)
-                       reiserfs_warning(p_s_sb, "NO_DISK_SPACE");
+               if (ret_value == NO_DISK_SPACE)
+                       reiserfs_warning(sb, "reiserfs-5092",
+                                        "NO_DISK_SPACE");
                unfix_nodes(&s_cut_balance);
                return -EIO;
        }
 
        /* go ahead and perform balancing */
 
-       RFALSE(c_mode == M_PASTE || c_mode == M_INSERT, "invalid mode");
+       RFALSE(mode == M_PASTE || mode == M_INSERT, "invalid mode");
 
        /* Calculate number of bytes that need to be cut from the item. */
        quota_cut_bytes =
-           (c_mode ==
-            M_DELETE) ? ih_item_len(get_ih(p_s_path)) : -s_cut_balance.
+           (mode ==
+            M_DELETE) ? ih_item_len(get_ih(path)) : -s_cut_balance.
            insert_size[0];
        if (retval2 == -1)
-               n_ret_value = calc_deleted_bytes_number(&s_cut_balance, c_mode);
+               ret_value = calc_deleted_bytes_number(&s_cut_balance, mode);
        else
-               n_ret_value = retval2;
+               ret_value = retval2;
 
        /* For direct items, we only change the quota when deleting the last
         ** item.
         */
        p_le_ih = PATH_PITEM_HEAD(s_cut_balance.tb_path);
-       if (!S_ISLNK(p_s_inode->i_mode) && is_direct_le_ih(p_le_ih)) {
-               if (c_mode == M_DELETE &&
-                   (le_ih_k_offset(p_le_ih) & (p_s_sb->s_blocksize - 1)) ==
+       if (!S_ISLNK(inode->i_mode) && is_direct_le_ih(p_le_ih)) {
+               if (mode == M_DELETE &&
+                   (le_ih_k_offset(p_le_ih) & (sb->s_blocksize - 1)) ==
                    1) {
                        // FIXME: this is to keep 3.5 happy
-                       REISERFS_I(p_s_inode)->i_first_direct_byte = U32_MAX;
-                       quota_cut_bytes = p_s_sb->s_blocksize + UNFM_P_SIZE;
+                       REISERFS_I(inode)->i_first_direct_byte = U32_MAX;
+                       quota_cut_bytes = sb->s_blocksize + UNFM_P_SIZE;
                } else {
                        quota_cut_bytes = 0;
                }
        }
 #ifdef CONFIG_REISERFS_CHECK
-       if (n_is_inode_locked) {
+       if (is_inode_locked) {
                struct item_head *le_ih =
                    PATH_PITEM_HEAD(s_cut_balance.tb_path);
                /* we are going to complete indirect2direct conversion. Make
                   sure, that we exactly remove last unformatted node pointer
                   of the item */
                if (!is_indirect_le_ih(le_ih))
-                       reiserfs_panic(p_s_sb,
-                                      "vs-5652: reiserfs_cut_from_item: "
+                       reiserfs_panic(sb, "vs-5652",
                                       "item must be indirect %h", le_ih);
 
-               if (c_mode == M_DELETE && ih_item_len(le_ih) != UNFM_P_SIZE)
-                       reiserfs_panic(p_s_sb,
-                                      "vs-5653: reiserfs_cut_from_item: "
-                                      "completing indirect2direct conversion indirect item %h "
-                                      "being deleted must be of 4 byte long",
-                                      le_ih);
+               if (mode == M_DELETE && ih_item_len(le_ih) != UNFM_P_SIZE)
+                       reiserfs_panic(sb, "vs-5653", "completing "
+                                      "indirect2direct conversion indirect "
+                                      "item %h being deleted must be of "
+                                      "4 byte long", le_ih);
 
-               if (c_mode == M_CUT
+               if (mode == M_CUT
                    && s_cut_balance.insert_size[0] != -UNFM_P_SIZE) {
-                       reiserfs_panic(p_s_sb,
-                                      "vs-5654: reiserfs_cut_from_item: "
-                                      "can not complete indirect2direct conversion of %h (CUT, insert_size==%d)",
+                       reiserfs_panic(sb, "vs-5654", "can not complete "
+                                      "indirect2direct conversion of %h "
+                                      "(CUT, insert_size==%d)",
                                       le_ih, s_cut_balance.insert_size[0]);
                }
                /* it would be useful to make sure, that right neighboring
@@ -1719,23 +1681,23 @@ int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th,
        }
 #endif
 
-       do_balance(&s_cut_balance, NULL, NULL, c_mode);
-       if (n_is_inode_locked) {
+       do_balance(&s_cut_balance, NULL, NULL, mode);
+       if (is_inode_locked) {
                /* we've done an indirect->direct conversion.  when the data block
                 ** was freed, it was removed from the list of blocks that must
                 ** be flushed before the transaction commits, make sure to
                 ** unmap and invalidate it
                 */
                unmap_buffers(page, tail_pos);
-               REISERFS_I(p_s_inode)->i_flags &= ~i_pack_on_close_mask;
+               REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
        }
 #ifdef REISERQUOTA_DEBUG
-       reiserfs_debug(p_s_inode->i_sb, REISERFS_DEBUG_CODE,
+       reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE,
                       "reiserquota cut_from_item(): freeing %u id=%u type=%c",
-                      quota_cut_bytes, p_s_inode->i_uid, '?');
+                      quota_cut_bytes, inode->i_uid, '?');
 #endif
-       vfs_dq_free_space_nodirty(p_s_inode, quota_cut_bytes);
-       return n_ret_value;
+       vfs_dq_free_space_nodirty(inode, quota_cut_bytes);
+       return ret_value;
 }
 
 static void truncate_directory(struct reiserfs_transaction_handle *th,
@@ -1743,8 +1705,7 @@ static void truncate_directory(struct reiserfs_transaction_handle *th,
 {
        BUG_ON(!th->t_trans_id);
        if (inode->i_nlink)
-               reiserfs_warning(inode->i_sb,
-                                "vs-5655: truncate_directory: link count != 0");
+               reiserfs_error(inode->i_sb, "vs-5655", "link count != 0");
 
        set_le_key_k_offset(KEY_FORMAT_3_5, INODE_PKEY(inode), DOT_OFFSET);
        set_le_key_k_type(KEY_FORMAT_3_5, INODE_PKEY(inode), TYPE_DIRENTRY);
@@ -1756,8 +1717,8 @@ static void truncate_directory(struct reiserfs_transaction_handle *th,
 
 /* Truncate file to the new size. Note, this must be called with a transaction
    already started */
-int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, struct inode *p_s_inode,      /* ->i_size contains new
-                                                                                                  size */
+int reiserfs_do_truncate(struct reiserfs_transaction_handle *th,
+                         struct inode *inode,  /* ->i_size contains new size */
                         struct page *page,     /* up to date for last block */
                         int update_timestamps  /* when it is called by
                                                   file_release to convert
@@ -1768,47 +1729,45 @@ int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, struct inode *p
        INITIALIZE_PATH(s_search_path); /* Path to the current object item. */
        struct item_head *p_le_ih;      /* Pointer to an item header. */
        struct cpu_key s_item_key;      /* Key to search for a previous file item. */
-       loff_t n_file_size,     /* Old file size. */
-        n_new_file_size;       /* New file size. */
-       int n_deleted;          /* Number of deleted or truncated bytes. */
+       loff_t file_size,       /* Old file size. */
+        new_file_size; /* New file size. */
+       int deleted;            /* Number of deleted or truncated bytes. */
        int retval;
        int err = 0;
 
        BUG_ON(!th->t_trans_id);
        if (!
-           (S_ISREG(p_s_inode->i_mode) || S_ISDIR(p_s_inode->i_mode)
-            || S_ISLNK(p_s_inode->i_mode)))
+           (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
+            || S_ISLNK(inode->i_mode)))
                return 0;
 
-       if (S_ISDIR(p_s_inode->i_mode)) {
+       if (S_ISDIR(inode->i_mode)) {
                // deletion of directory - no need to update timestamps
-               truncate_directory(th, p_s_inode);
+               truncate_directory(th, inode);
                return 0;
        }
 
        /* Get new file size. */
-       n_new_file_size = p_s_inode->i_size;
+       new_file_size = inode->i_size;
 
        // FIXME: note, that key type is unimportant here
-       make_cpu_key(&s_item_key, p_s_inode, max_reiserfs_offset(p_s_inode),
+       make_cpu_key(&s_item_key, inode, max_reiserfs_offset(inode),
                     TYPE_DIRECT, 3);
 
        retval =
-           search_for_position_by_key(p_s_inode->i_sb, &s_item_key,
+           search_for_position_by_key(inode->i_sb, &s_item_key,
                                       &s_search_path);
        if (retval == IO_ERROR) {
-               reiserfs_warning(p_s_inode->i_sb,
-                                "vs-5657: reiserfs_do_truncate: "
-                                "i/o failure occurred trying to truncate %K",
-                                &s_item_key);
+               reiserfs_error(inode->i_sb, "vs-5657",
+                              "i/o failure occurred trying to truncate %K",
+                              &s_item_key);
                err = -EIO;
                goto out;
        }
        if (retval == POSITION_FOUND || retval == FILE_NOT_FOUND) {
-               reiserfs_warning(p_s_inode->i_sb,
-                                "PAP-5660: reiserfs_do_truncate: "
-                                "wrong result %d of search for %K", retval,
-                                &s_item_key);
+               reiserfs_error(inode->i_sb, "PAP-5660",
+                              "wrong result %d of search for %K", retval,
+                              &s_item_key);
 
                err = -EIO;
                goto out;
@@ -1819,56 +1778,56 @@ int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, struct inode *p
        /* Get real file size (total length of all file items) */
        p_le_ih = PATH_PITEM_HEAD(&s_search_path);
        if (is_statdata_le_ih(p_le_ih))
-               n_file_size = 0;
+               file_size = 0;
        else {
                loff_t offset = le_ih_k_offset(p_le_ih);
                int bytes =
-                   op_bytes_number(p_le_ih, p_s_inode->i_sb->s_blocksize);
+                   op_bytes_number(p_le_ih, inode->i_sb->s_blocksize);
 
                /* this may mismatch with real file size: if last direct item
                   had no padding zeros and last unformatted node had no free
                   space, this file would have this file size */
-               n_file_size = offset + bytes - 1;
+               file_size = offset + bytes - 1;
        }
        /*
         * are we doing a full truncate or delete, if so
         * kick in the reada code
         */
-       if (n_new_file_size == 0)
+       if (new_file_size == 0)
                s_search_path.reada = PATH_READA | PATH_READA_BACK;
 
-       if (n_file_size == 0 || n_file_size < n_new_file_size) {
+       if (file_size == 0 || file_size < new_file_size) {
                goto update_and_out;
        }
 
        /* Update key to search for the last file item. */
-       set_cpu_key_k_offset(&s_item_key, n_file_size);
+       set_cpu_key_k_offset(&s_item_key, file_size);
 
        do {
                /* Cut or delete file item. */
-               n_deleted =
+               deleted =
                    reiserfs_cut_from_item(th, &s_search_path, &s_item_key,
-                                          p_s_inode, page, n_new_file_size);
-               if (n_deleted < 0) {
-                       reiserfs_warning(p_s_inode->i_sb,
-                                        "vs-5665: reiserfs_do_truncate: reiserfs_cut_from_item failed");
+                                          inode, page, new_file_size);
+               if (deleted < 0) {
+                       reiserfs_warning(inode->i_sb, "vs-5665",
+                                        "reiserfs_cut_from_item failed");
                        reiserfs_check_path(&s_search_path);
                        return 0;
                }
 
-               RFALSE(n_deleted > n_file_size,
+               RFALSE(deleted > file_size,
                       "PAP-5670: reiserfs_cut_from_item: too many bytes deleted: deleted %d, file_size %lu, item_key %K",
-                      n_deleted, n_file_size, &s_item_key);
+                      deleted, file_size, &s_item_key);
 
                /* Change key to search the last file item. */
-               n_file_size -= n_deleted;
+               file_size -= deleted;
 
-               set_cpu_key_k_offset(&s_item_key, n_file_size);
+               set_cpu_key_k_offset(&s_item_key, file_size);
 
                /* While there are bytes to truncate and previous file item is presented in the tree. */
 
                /*
-                ** This loop could take a really long time, and could log 
+                ** This loop could take a really long time, and could log
                 ** many more blocks than a transaction can hold.  So, we do a polite
                 ** journal end here, and if the transaction needs ending, we make
                 ** sure the file is consistent before ending the current trans
@@ -1877,37 +1836,38 @@ int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, struct inode *p
                if (journal_transaction_should_end(th, 0) ||
                    reiserfs_transaction_free_space(th) <= JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD) {
                        int orig_len_alloc = th->t_blocks_allocated;
-                       decrement_counters_in_path(&s_search_path);
+                       pathrelse(&s_search_path);
 
                        if (update_timestamps) {
-                               p_s_inode->i_mtime = p_s_inode->i_ctime =
-                                   CURRENT_TIME_SEC;
+                               inode->i_mtime = CURRENT_TIME_SEC;
+                               inode->i_ctime = CURRENT_TIME_SEC;
                        }
-                       reiserfs_update_sd(th, p_s_inode);
+                       reiserfs_update_sd(th, inode);
 
-                       err = journal_end(th, p_s_inode->i_sb, orig_len_alloc);
+                       err = journal_end(th, inode->i_sb, orig_len_alloc);
                        if (err)
                                goto out;
-                       err = journal_begin(th, p_s_inode->i_sb,
+                       err = journal_begin(th, inode->i_sb,
                                            JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD + JOURNAL_PER_BALANCE_CNT * 4) ;
                        if (err)
                                goto out;
-                       reiserfs_update_inode_transaction(p_s_inode);
+                       reiserfs_update_inode_transaction(inode);
                }
-       } while (n_file_size > ROUND_UP(n_new_file_size) &&
-                search_for_position_by_key(p_s_inode->i_sb, &s_item_key,
+       } while (file_size > ROUND_UP(new_file_size) &&
+                search_for_position_by_key(inode->i_sb, &s_item_key,
                                            &s_search_path) == POSITION_FOUND);
 
-       RFALSE(n_file_size > ROUND_UP(n_new_file_size),
+       RFALSE(file_size > ROUND_UP(new_file_size),
               "PAP-5680: truncate did not finish: new_file_size %Ld, current %Ld, oid %d",
-              n_new_file_size, n_file_size, s_item_key.on_disk_key.k_objectid);
+              new_file_size, file_size, s_item_key.on_disk_key.k_objectid);
 
       update_and_out:
        if (update_timestamps) {
                // this is truncate, not file closing
-               p_s_inode->i_mtime = p_s_inode->i_ctime = CURRENT_TIME_SEC;
+               inode->i_mtime = CURRENT_TIME_SEC;
+               inode->i_ctime = CURRENT_TIME_SEC;
        }
-       reiserfs_update_sd(th, p_s_inode);
+       reiserfs_update_sd(th, inode);
 
       out:
        pathrelse(&s_search_path);
@@ -1917,7 +1877,7 @@ int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, struct inode *p
 #ifdef CONFIG_REISERFS_CHECK
 // this makes sure, that we __append__, not overwrite or add holes
 static void check_research_for_paste(struct treepath *path,
-                                    const struct cpu_key *p_s_key)
+                                    const struct cpu_key *key)
 {
        struct item_head *found_ih = get_ih(path);
 
@@ -1925,36 +1885,36 @@ static void check_research_for_paste(struct treepath *path,
                if (le_ih_k_offset(found_ih) +
                    op_bytes_number(found_ih,
                                    get_last_bh(path)->b_size) !=
-                   cpu_key_k_offset(p_s_key)
+                   cpu_key_k_offset(key)
                    || op_bytes_number(found_ih,
                                       get_last_bh(path)->b_size) !=
                    pos_in_item(path))
-                       reiserfs_panic(NULL,
-                                      "PAP-5720: check_research_for_paste: "
-                                      "found direct item %h or position (%d) does not match to key %K",
-                                      found_ih, pos_in_item(path), p_s_key);
+                       reiserfs_panic(NULL, "PAP-5720", "found direct item "
+                                      "%h or position (%d) does not match "
+                                      "to key %K", found_ih,
+                                      pos_in_item(path), key);
        }
        if (is_indirect_le_ih(found_ih)) {
                if (le_ih_k_offset(found_ih) +
                    op_bytes_number(found_ih,
                                    get_last_bh(path)->b_size) !=
-                   cpu_key_k_offset(p_s_key)
+                   cpu_key_k_offset(key)
                    || I_UNFM_NUM(found_ih) != pos_in_item(path)
                    || get_ih_free_space(found_ih) != 0)
-                       reiserfs_panic(NULL,
-                                      "PAP-5730: check_research_for_paste: "
-                                      "found indirect item (%h) or position (%d) does not match to key (%K)",
-                                      found_ih, pos_in_item(path), p_s_key);
+                       reiserfs_panic(NULL, "PAP-5730", "found indirect "
+                                      "item (%h) or position (%d) does not "
+                                      "match to key (%K)",
+                                      found_ih, pos_in_item(path), key);
        }
 }
 #endif                         /* config reiserfs check */
 
 /* Paste bytes to the existing item. Returns bytes number pasted into the item. */
-int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_search_path, /* Path to the pasted item.          */
-                            const struct cpu_key *p_s_key,     /* Key to search for the needed item. */
+int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct treepath *search_path,     /* Path to the pasted item.       */
+                            const struct cpu_key *key, /* Key to search for the needed item. */
                             struct inode *inode,       /* Inode item belongs to */
-                            const char *p_c_body,      /* Pointer to the bytes to paste.    */
-                            int n_pasted_size)
+                            const char *body,  /* Pointer to the bytes to paste.    */
+                            int pasted_size)
 {                              /* Size of pasted bytes.             */
        struct tree_balance s_paste_balance;
        int retval;
@@ -1967,18 +1927,18 @@ int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct tree
 #ifdef REISERQUOTA_DEBUG
        reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE,
                       "reiserquota paste_into_item(): allocating %u id=%u type=%c",
-                      n_pasted_size, inode->i_uid,
-                      key2type(&(p_s_key->on_disk_key)));
+                      pasted_size, inode->i_uid,
+                      key2type(&(key->on_disk_key)));
 #endif
 
-       if (vfs_dq_alloc_space_nodirty(inode, n_pasted_size)) {
-               pathrelse(p_s_search_path);
+       if (vfs_dq_alloc_space_nodirty(inode, pasted_size)) {
+               pathrelse(search_path);
                return -EDQUOT;
        }
-       init_tb_struct(th, &s_paste_balance, th->t_super, p_s_search_path,
-                      n_pasted_size);
+       init_tb_struct(th, &s_paste_balance, th->t_super, search_path,
+                      pasted_size);
 #ifdef DISPLACE_NEW_PACKING_LOCALITIES
-       s_paste_balance.key = p_s_key->on_disk_key;
+       s_paste_balance.key = key->on_disk_key;
 #endif
 
        /* DQUOT_* can schedule, must check before the fix_nodes */
@@ -1988,33 +1948,33 @@ int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct tree
 
        while ((retval =
                fix_nodes(M_PASTE, &s_paste_balance, NULL,
-                         p_c_body)) == REPEAT_SEARCH) {
+                         body)) == REPEAT_SEARCH) {
              search_again:
                /* file system changed while we were in the fix_nodes */
                PROC_INFO_INC(th->t_super, paste_into_item_restarted);
                retval =
-                   search_for_position_by_key(th->t_super, p_s_key,
-                                              p_s_search_path);
+                   search_for_position_by_key(th->t_super, key,
+                                              search_path);
                if (retval == IO_ERROR) {
                        retval = -EIO;
                        goto error_out;
                }
                if (retval == POSITION_FOUND) {
-                       reiserfs_warning(inode->i_sb,
-                                        "PAP-5710: reiserfs_paste_into_item: entry or pasted byte (%K) exists",
-                                        p_s_key);
+                       reiserfs_warning(inode->i_sb, "PAP-5710",
+                                        "entry or pasted byte (%K) exists",
+                                        key);
                        retval = -EEXIST;
                        goto error_out;
                }
 #ifdef CONFIG_REISERFS_CHECK
-               check_research_for_paste(p_s_search_path, p_s_key);
+               check_research_for_paste(search_path, key);
 #endif
        }
 
        /* Perform balancing after all resources are collected by fix_nodes, and
           accessing them will not risk triggering schedule. */
        if (retval == CARRY_ON) {
-               do_balance(&s_paste_balance, NULL /*ih */ , p_c_body, M_PASTE);
+               do_balance(&s_paste_balance, NULL /*ih */ , body, M_PASTE);
                return 0;
        }
        retval = (retval == NO_DISK_SPACE) ? -ENOSPC : -EIO;
@@ -2024,18 +1984,24 @@ int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct tree
 #ifdef REISERQUOTA_DEBUG
        reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE,
                       "reiserquota paste_into_item(): freeing %u id=%u type=%c",
-                      n_pasted_size, inode->i_uid,
-                      key2type(&(p_s_key->on_disk_key)));
+                      pasted_size, inode->i_uid,
+                      key2type(&(key->on_disk_key)));
 #endif
-       vfs_dq_free_space_nodirty(inode, n_pasted_size);
+       vfs_dq_free_space_nodirty(inode, pasted_size);
        return retval;
 }
 
-/* Insert new item into the buffer at the path. */
-int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_path,    /* Path to the inserteded item.         */
-                        const struct cpu_key *key, struct item_head *p_s_ih,   /* Pointer to the item header to insert. */
-                        struct inode *inode, const char *p_c_body)
-{                              /* Pointer to the bytes to insert.      */
+/* Insert new item into the buffer at the path.
+ * th   - active transaction handle
+ * path - path to the inserted item
+ * ih   - pointer to the item header to insert
+ * body - pointer to the bytes to insert
+ */
+int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
+                        struct treepath *path, const struct cpu_key *key,
+                        struct item_head *ih, struct inode *inode,
+                        const char *body)
+{
        struct tree_balance s_ins_balance;
        int retval;
        int fs_gen = 0;
@@ -2045,28 +2011,27 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct treepath
 
        if (inode) {            /* Do we count quotas for item? */
                fs_gen = get_generation(inode->i_sb);
-               quota_bytes = ih_item_len(p_s_ih);
+               quota_bytes = ih_item_len(ih);
 
                /* hack so the quota code doesn't have to guess if the file has
                 ** a tail, links are always tails, so there's no guessing needed
                 */
-               if (!S_ISLNK(inode->i_mode) && is_direct_le_ih(p_s_ih)) {
+               if (!S_ISLNK(inode->i_mode) && is_direct_le_ih(ih))
                        quota_bytes = inode->i_sb->s_blocksize + UNFM_P_SIZE;
-               }
 #ifdef REISERQUOTA_DEBUG
                reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE,
                               "reiserquota insert_item(): allocating %u id=%u type=%c",
-                              quota_bytes, inode->i_uid, head2type(p_s_ih));
+                              quota_bytes, inode->i_uid, head2type(ih));
 #endif
                /* We can't dirty inode here. It would be immediately written but
                 * appropriate stat item isn't inserted yet... */
                if (vfs_dq_alloc_space_nodirty(inode, quota_bytes)) {
-                       pathrelse(p_s_path);
+                       pathrelse(path);
                        return -EDQUOT;
                }
        }
-       init_tb_struct(th, &s_ins_balance, th->t_super, p_s_path,
-                      IH_SIZE + ih_item_len(p_s_ih));
+       init_tb_struct(th, &s_ins_balance, th->t_super, path,
+                      IH_SIZE + ih_item_len(ih));
 #ifdef DISPLACE_NEW_PACKING_LOCALITIES
        s_ins_balance.key = key->on_disk_key;
 #endif
@@ -2076,19 +2041,18 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct treepath
        }
 
        while ((retval =
-               fix_nodes(M_INSERT, &s_ins_balance, p_s_ih,
-                         p_c_body)) == REPEAT_SEARCH) {
+               fix_nodes(M_INSERT, &s_ins_balance, ih,
+                         body)) == REPEAT_SEARCH) {
              search_again:
                /* file system changed while we were in the fix_nodes */
                PROC_INFO_INC(th->t_super, insert_item_restarted);
-               retval = search_item(th->t_super, key, p_s_path);
+               retval = search_item(th->t_super, key, path);
                if (retval == IO_ERROR) {
                        retval = -EIO;
                        goto error_out;
                }
                if (retval == ITEM_FOUND) {
-                       reiserfs_warning(th->t_super,
-                                        "PAP-5760: reiserfs_insert_item: "
+                       reiserfs_warning(th->t_super, "PAP-5760",
                                         "key %K already exists in the tree",
                                         key);
                        retval = -EEXIST;
@@ -2098,7 +2062,7 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct treepath
 
        /* make balancing after all resources will be collected at a time */
        if (retval == CARRY_ON) {
-               do_balance(&s_ins_balance, p_s_ih, p_c_body, M_INSERT);
+               do_balance(&s_ins_balance, ih, body, M_INSERT);
                return 0;
        }
 
@@ -2109,7 +2073,7 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct treepath
 #ifdef REISERQUOTA_DEBUG
        reiserfs_debug(th->t_super, REISERFS_DEBUG_CODE,
                       "reiserquota insert_item(): freeing %u id=%u type=%c",
-                      quota_bytes, inode->i_uid, head2type(p_s_ih));
+                      quota_bytes, inode->i_uid, head2type(ih));
 #endif
        if (inode)
                vfs_dq_free_space_nodirty(inode, quota_bytes);
index 5dbafb7394015aafbaf04bbdb00d0461c6941c90..0ae6486d90462ae4b644611fbd7baa221af8db57 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/mnt_namespace.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
+#include <linux/crc32.h>
 
 struct file_system_type reiserfs_fs_type;
 
@@ -183,9 +184,9 @@ static int finish_unfinished(struct super_block *s)
                if (REISERFS_SB(s)->s_qf_names[i]) {
                        int ret = reiserfs_quota_on_mount(s, i);
                        if (ret < 0)
-                               reiserfs_warning(s,
-                                                "reiserfs: cannot turn on journaled quota: error %d",
-                                                ret);
+                               reiserfs_warning(s, "reiserfs-2500",
+                                                "cannot turn on journaled "
+                                                "quota: error %d", ret);
                }
        }
 #endif
@@ -195,17 +196,16 @@ static int finish_unfinished(struct super_block *s)
        while (!retval) {
                retval = search_item(s, &max_cpu_key, &path);
                if (retval != ITEM_NOT_FOUND) {
-                       reiserfs_warning(s,
-                                        "vs-2140: finish_unfinished: search_by_key returned %d",
-                                        retval);
+                       reiserfs_error(s, "vs-2140",
+                                      "search_by_key returned %d", retval);
                        break;
                }
 
                bh = get_last_bh(&path);
                item_pos = get_item_pos(&path);
                if (item_pos != B_NR_ITEMS(bh)) {
-                       reiserfs_warning(s,
-                                        "vs-2060: finish_unfinished: wrong position found");
+                       reiserfs_warning(s, "vs-2060",
+                                        "wrong position found");
                        break;
                }
                item_pos--;
@@ -235,8 +235,7 @@ static int finish_unfinished(struct super_block *s)
                if (!inode) {
                        /* the unlink almost completed, it just did not manage to remove
                           "save" link and release objectid */
-                       reiserfs_warning(s,
-                                        "vs-2180: finish_unfinished: iget failed for %K",
+                       reiserfs_warning(s, "vs-2180", "iget failed for %K",
                                         &obj_key);
                        retval = remove_save_link_only(s, &save_link_key, 1);
                        continue;
@@ -244,8 +243,8 @@ static int finish_unfinished(struct super_block *s)
 
                if (!truncate && inode->i_nlink) {
                        /* file is not unlinked */
-                       reiserfs_warning(s,
-                                        "vs-2185: finish_unfinished: file %K is not unlinked",
+                       reiserfs_warning(s, "vs-2185",
+                                        "file %K is not unlinked",
                                         &obj_key);
                        retval = remove_save_link_only(s, &save_link_key, 0);
                        continue;
@@ -257,8 +256,9 @@ static int finish_unfinished(struct super_block *s)
                           The only imaginable way is to execute unfinished truncate request
                           then boot into old kernel, remove the file and create dir with
                           the same key. */
-                       reiserfs_warning(s,
-                                        "green-2101: impossible truncate on a directory %k. Please report",
+                       reiserfs_warning(s, "green-2101",
+                                        "impossible truncate on a "
+                                        "directory %k. Please report",
                                         INODE_PKEY(inode));
                        retval = remove_save_link_only(s, &save_link_key, 0);
                        truncate = 0;
@@ -288,9 +288,10 @@ static int finish_unfinished(struct super_block *s)
                                /* removal gets completed in iput */
                                retval = 0;
                        } else {
-                               reiserfs_warning(s, "Dead loop in "
-                                               "finish_unfinished detected, "
-                                               "just remove save link\n");
+                               reiserfs_warning(s, "super-2189", "Dead loop "
+                                                "in finish_unfinished "
+                                                "detected, just remove "
+                                                "save link\n");
                                retval = remove_save_link_only(s,
                                                        &save_link_key, 0);
                        }
@@ -360,8 +361,9 @@ void add_save_link(struct reiserfs_transaction_handle *th,
        } else {
                /* truncate */
                if (S_ISDIR(inode->i_mode))
-                       reiserfs_warning(inode->i_sb,
-                                        "green-2102: Adding a truncate savelink for a directory %k! Please report",
+                       reiserfs_warning(inode->i_sb, "green-2102",
+                                        "Adding a truncate savelink for "
+                                        "a directory %k! Please report",
                                         INODE_PKEY(inode));
                set_cpu_key_k_offset(&key, 1);
                set_cpu_key_k_type(&key, TYPE_INDIRECT);
@@ -376,9 +378,9 @@ void add_save_link(struct reiserfs_transaction_handle *th,
        retval = search_item(inode->i_sb, &key, &path);
        if (retval != ITEM_NOT_FOUND) {
                if (retval != -ENOSPC)
-                       reiserfs_warning(inode->i_sb, "vs-2100: add_save_link:"
-                                        "search_by_key (%K) returned %d", &key,
-                                        retval);
+                       reiserfs_error(inode->i_sb, "vs-2100",
+                                      "search_by_key (%K) returned %d", &key,
+                                      retval);
                pathrelse(&path);
                return;
        }
@@ -391,9 +393,8 @@ void add_save_link(struct reiserfs_transaction_handle *th,
            reiserfs_insert_item(th, &path, &key, &ih, NULL, (char *)&link);
        if (retval) {
                if (retval != -ENOSPC)
-                       reiserfs_warning(inode->i_sb,
-                                        "vs-2120: add_save_link: insert_item returned %d",
-                                        retval);
+                       reiserfs_error(inode->i_sb, "vs-2120",
+                                      "insert_item returned %d", retval);
        } else {
                if (truncate)
                        REISERFS_I(inode)->i_flags |=
@@ -492,8 +493,7 @@ static void reiserfs_put_super(struct super_block *s)
        print_statistics(s);
 
        if (REISERFS_SB(s)->reserved_blocks != 0) {
-               reiserfs_warning(s,
-                                "green-2005: reiserfs_put_super: reserved blocks left %d",
+               reiserfs_warning(s, "green-2005", "reserved blocks left %d",
                                 REISERFS_SB(s)->reserved_blocks);
        }
 
@@ -559,8 +559,8 @@ static void reiserfs_dirty_inode(struct inode *inode)
 
        int err = 0;
        if (inode->i_sb->s_flags & MS_RDONLY) {
-               reiserfs_warning(inode->i_sb,
-                                "clm-6006: writing inode %lu on readonly FS",
+               reiserfs_warning(inode->i_sb, "clm-6006",
+                                "writing inode %lu on readonly FS",
                                 inode->i_ino);
                return;
        }
@@ -757,7 +757,7 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts,
                           char **opt_arg, unsigned long *bit_flags)
 {
        char *p;
-       /* foo=bar, 
+       /* foo=bar,
           ^   ^  ^
           |   |  +-- option_end
           |   +-- arg_start
@@ -792,13 +792,15 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts,
                        if (bit_flags) {
                                if (opt->clrmask ==
                                    (1 << REISERFS_UNSUPPORTED_OPT))
-                                       reiserfs_warning(s, "%s not supported.",
+                                       reiserfs_warning(s, "super-6500",
+                                                        "%s not supported.\n",
                                                         p);
                                else
                                        *bit_flags &= ~opt->clrmask;
                                if (opt->setmask ==
                                    (1 << REISERFS_UNSUPPORTED_OPT))
-                                       reiserfs_warning(s, "%s not supported.",
+                                       reiserfs_warning(s, "super-6501",
+                                                        "%s not supported.\n",
                                                         p);
                                else
                                        *bit_flags |= opt->setmask;
@@ -807,7 +809,8 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts,
                }
        }
        if (!opt->option_name) {
-               reiserfs_warning(s, "unknown mount option \"%s\"", p);
+               reiserfs_warning(s, "super-6502",
+                                "unknown mount option \"%s\"", p);
                return -1;
        }
 
@@ -815,8 +818,9 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts,
        switch (*p) {
        case '=':
                if (!opt->arg_required) {
-                       reiserfs_warning(s,
-                                        "the option \"%s\" does not require an argument",
+                       reiserfs_warning(s, "super-6503",
+                                        "the option \"%s\" does not "
+                                        "require an argument\n",
                                         opt->option_name);
                        return -1;
                }
@@ -824,14 +828,15 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts,
 
        case 0:
                if (opt->arg_required) {
-                       reiserfs_warning(s,
-                                        "the option \"%s\" requires an argument",
-                                        opt->option_name);
+                       reiserfs_warning(s, "super-6504",
+                                        "the option \"%s\" requires an "
+                                        "argument\n", opt->option_name);
                        return -1;
                }
                break;
        default:
-               reiserfs_warning(s, "head of option \"%s\" is only correct",
+               reiserfs_warning(s, "super-6505",
+                                "head of option \"%s\" is only correct\n",
                                 opt->option_name);
                return -1;
        }
@@ -843,7 +848,8 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts,
            && !(opt->arg_required & (1 << REISERFS_OPT_ALLOWEMPTY))
            && !strlen(p)) {
                /* this catches "option=," if not allowed */
-               reiserfs_warning(s, "empty argument for \"%s\"",
+               reiserfs_warning(s, "super-6506",
+                                "empty argument for \"%s\"\n",
                                 opt->option_name);
                return -1;
        }
@@ -865,7 +871,8 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts,
                }
        }
 
-       reiserfs_warning(s, "bad value \"%s\" for option \"%s\"", p,
+       reiserfs_warning(s, "super-6506",
+                        "bad value \"%s\" for option \"%s\"\n", p,
                         opt->option_name);
        return -1;
 }
@@ -955,9 +962,9 @@ static int reiserfs_parse_options(struct super_block *s, char *options,     /* strin
                                *blocks = simple_strtoul(arg, &p, 0);
                                if (*p != '\0') {
                                        /* NNN does not look like a number */
-                                       reiserfs_warning(s,
-                                                        "reiserfs_parse_options: bad value %s",
-                                                        arg);
+                                       reiserfs_warning(s, "super-6507",
+                                                        "bad value %s for "
+                                                        "-oresize\n", arg);
                                        return 0;
                                }
                        }
@@ -968,8 +975,8 @@ static int reiserfs_parse_options(struct super_block *s, char *options,     /* strin
                        unsigned long val = simple_strtoul(arg, &p, 0);
                        /* commit=NNN (time in seconds) */
                        if (*p != '\0' || val >= (unsigned int)-1) {
-                               reiserfs_warning(s,
-                                                "reiserfs_parse_options: bad value %s",
+                               reiserfs_warning(s, "super-6508",
+                                                "bad value %s for -ocommit\n",
                                                 arg);
                                return 0;
                        }
@@ -977,16 +984,18 @@ static int reiserfs_parse_options(struct super_block *s, char *options,   /* strin
                }
 
                if (c == 'w') {
-                       reiserfs_warning(s, "reiserfs: nolargeio option is no longer supported");
+                       reiserfs_warning(s, "super-6509", "nolargeio option "
+                                        "is no longer supported");
                        return 0;
                }
 
                if (c == 'j') {
                        if (arg && *arg && jdev_name) {
                                if (*jdev_name) {       //Hm, already assigned?
-                                       reiserfs_warning(s,
-                                                        "reiserfs_parse_options: journal device was already  specified to be %s",
-                                                        *jdev_name);
+                                       reiserfs_warning(s, "super-6510",
+                                                        "journal device was "
+                                                        "already specified to "
+                                                        "be %s", *jdev_name);
                                        return 0;
                                }
                                *jdev_name = arg;
@@ -998,29 +1007,35 @@ static int reiserfs_parse_options(struct super_block *s, char *options,  /* strin
 
                        if (sb_any_quota_loaded(s) &&
                            (!*arg != !REISERFS_SB(s)->s_qf_names[qtype])) {
-                               reiserfs_warning(s,
-                                                "reiserfs_parse_options: cannot change journaled quota options when quota turned on.");
+                               reiserfs_warning(s, "super-6511",
+                                                "cannot change journaled "
+                                                "quota options when quota "
+                                                "turned on.");
                                return 0;
                        }
                        if (*arg) {     /* Some filename specified? */
                                if (REISERFS_SB(s)->s_qf_names[qtype]
                                    && strcmp(REISERFS_SB(s)->s_qf_names[qtype],
                                              arg)) {
-                                       reiserfs_warning(s,
-                                                        "reiserfs_parse_options: %s quota file already specified.",
+                                       reiserfs_warning(s, "super-6512",
+                                                        "%s quota file "
+                                                        "already specified.",
                                                         QTYPE2NAME(qtype));
                                        return 0;
                                }
                                if (strchr(arg, '/')) {
-                                       reiserfs_warning(s,
-                                                        "reiserfs_parse_options: quotafile must be on filesystem root.");
+                                       reiserfs_warning(s, "super-6513",
+                                                        "quotafile must be "
+                                                        "on filesystem root.");
                                        return 0;
                                }
                                qf_names[qtype] =
                                    kmalloc(strlen(arg) + 1, GFP_KERNEL);
                                if (!qf_names[qtype]) {
-                                       reiserfs_warning(s,
-                                                        "reiserfs_parse_options: not enough memory for storing quotafile name.");
+                                       reiserfs_warning(s, "reiserfs-2502",
+                                                        "not enough memory "
+                                                        "for storing "
+                                                        "quotafile name.");
                                        return 0;
                                }
                                strcpy(qf_names[qtype], arg);
@@ -1038,21 +1053,24 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin
                        else if (!strcmp(arg, "vfsv0"))
                                *qfmt = QFMT_VFS_V0;
                        else {
-                               reiserfs_warning(s,
-                                                "reiserfs_parse_options: unknown quota format specified.");
+                               reiserfs_warning(s, "super-6514",
+                                                "unknown quota format "
+                                                "specified.");
                                return 0;
                        }
                        if (sb_any_quota_loaded(s) &&
                            *qfmt != REISERFS_SB(s)->s_jquota_fmt) {
-                               reiserfs_warning(s,
-                                                "reiserfs_parse_options: cannot change journaled quota options when quota turned on.");
+                               reiserfs_warning(s, "super-6515",
+                                                "cannot change journaled "
+                                                "quota options when quota "
+                                                "turned on.");
                                return 0;
                        }
                }
 #else
                if (c == 'u' || c == 'g' || c == 'f') {
-                       reiserfs_warning(s,
-                                        "reiserfs_parse_options: journaled quota options not supported.");
+                       reiserfs_warning(s, "reiserfs-2503", "journaled "
+                                        "quota options not supported.");
                        return 0;
                }
 #endif
@@ -1061,15 +1079,15 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin
 #ifdef CONFIG_QUOTA
        if (!REISERFS_SB(s)->s_jquota_fmt && !*qfmt
            && (qf_names[USRQUOTA] || qf_names[GRPQUOTA])) {
-               reiserfs_warning(s,
-                                "reiserfs_parse_options: journaled quota format not specified.");
+               reiserfs_warning(s, "super-6515",
+                                "journaled quota format not specified.");
                return 0;
        }
        /* This checking is not precise wrt the quota type but for our purposes it is sufficient */
        if (!(*mount_options & (1 << REISERFS_QUOTA))
            && sb_any_quota_loaded(s)) {
-               reiserfs_warning(s,
-                                "reiserfs_parse_options: quota options must be present when quota is turned on.");
+               reiserfs_warning(s, "super-6516", "quota options must "
+                                "be present when quota is turned on.");
                return 0;
        }
 #endif
@@ -1129,14 +1147,15 @@ static void handle_attrs(struct super_block *s)
 
        if (reiserfs_attrs(s)) {
                if (old_format_only(s)) {
-                       reiserfs_warning(s,
-                                        "reiserfs: cannot support attributes on 3.5.x disk format");
+                       reiserfs_warning(s, "super-6517", "cannot support "
+                                        "attributes on 3.5.x disk format");
                        REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_ATTRS);
                        return;
                }
                if (!(le32_to_cpu(rs->s_flags) & reiserfs_attrs_cleared)) {
-                       reiserfs_warning(s,
-                                        "reiserfs: cannot support attributes until flag is set in super-block");
+                       reiserfs_warning(s, "super-6518", "cannot support "
+                                        "attributes until flag is set in "
+                                        "super-block");
                        REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_ATTRS);
                }
        }
@@ -1278,6 +1297,8 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
                REISERFS_SB(s)->s_mount_state = sb_umount_state(rs);
                s->s_flags &= ~MS_RDONLY;
                set_sb_umount_state(rs, REISERFS_ERROR_FS);
+               if (!old_format_only(s))
+                       set_sb_mnt_count(rs, sb_mnt_count(rs) + 1);
                /* mark_buffer_dirty (SB_BUFFER_WITH_SB (s), 1); */
                journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
                REISERFS_SB(s)->s_mount_state = REISERFS_VALID_FS;
@@ -1312,7 +1333,7 @@ static int read_super_block(struct super_block *s, int offset)
 
        bh = sb_bread(s, offset / s->s_blocksize);
        if (!bh) {
-               reiserfs_warning(s, "sh-2006: read_super_block: "
+               reiserfs_warning(s, "sh-2006",
                                 "bread failed (dev %s, block %lu, size %lu)",
                                 reiserfs_bdevname(s), offset / s->s_blocksize,
                                 s->s_blocksize);
@@ -1326,15 +1347,15 @@ static int read_super_block(struct super_block *s, int offset)
        }
        //
        // ok, reiserfs signature (old or new) found in at the given offset
-       //    
+       //
        fs_blocksize = sb_blocksize(rs);
        brelse(bh);
        sb_set_blocksize(s, fs_blocksize);
 
        bh = sb_bread(s, offset / s->s_blocksize);
        if (!bh) {
-               reiserfs_warning(s, "sh-2007: read_super_block: "
-                                "bread failed (dev %s, block %lu, size %lu)\n",
+               reiserfs_warning(s, "sh-2007",
+                                "bread failed (dev %s, block %lu, size %lu)",
                                 reiserfs_bdevname(s), offset / s->s_blocksize,
                                 s->s_blocksize);
                return 1;
@@ -1342,8 +1363,8 @@ static int read_super_block(struct super_block *s, int offset)
 
        rs = (struct reiserfs_super_block *)bh->b_data;
        if (sb_blocksize(rs) != s->s_blocksize) {
-               reiserfs_warning(s, "sh-2011: read_super_block: "
-                                "can't find a reiserfs filesystem on (dev %s, block %Lu, size %lu)\n",
+               reiserfs_warning(s, "sh-2011", "can't find a reiserfs "
+                                "filesystem on (dev %s, block %Lu, size %lu)",
                                 reiserfs_bdevname(s),
                                 (unsigned long long)bh->b_blocknr,
                                 s->s_blocksize);
@@ -1353,9 +1374,10 @@ static int read_super_block(struct super_block *s, int offset)
 
        if (rs->s_v1.s_root_block == cpu_to_le32(-1)) {
                brelse(bh);
-               reiserfs_warning(s,
-                                "Unfinished reiserfsck --rebuild-tree run detected. Please run\n"
-                                "reiserfsck --rebuild-tree and wait for a completion. If that fails\n"
+               reiserfs_warning(s, "super-6519", "Unfinished reiserfsck "
+                                "--rebuild-tree run detected. Please run\n"
+                                "reiserfsck --rebuild-tree and wait for a "
+                                "completion. If that fails\n"
                                 "get newer reiserfsprogs package");
                return 1;
        }
@@ -1367,18 +1389,15 @@ static int read_super_block(struct super_block *s, int offset)
                /* magic is of non-standard journal filesystem, look at s_version to
                   find which format is in use */
                if (sb_version(rs) == REISERFS_VERSION_2)
-                       reiserfs_warning(s,
-                                        "read_super_block: found reiserfs format \"3.6\""
-                                        " with non-standard journal");
+                       reiserfs_info(s, "found reiserfs format \"3.6\""
+                                     " with non-standard journal\n");
                else if (sb_version(rs) == REISERFS_VERSION_1)
-                       reiserfs_warning(s,
-                                        "read_super_block: found reiserfs format \"3.5\""
-                                        " with non-standard journal");
+                       reiserfs_info(s, "found reiserfs format \"3.5\""
+                                     " with non-standard journal\n");
                else {
-                       reiserfs_warning(s,
-                                        "sh-2012: read_super_block: found unknown "
-                                        "format \"%u\" of reiserfs with non-standard magic",
-                                        sb_version(rs));
+                       reiserfs_warning(s, "sh-2012", "found unknown "
+                                        "format \"%u\" of reiserfs with "
+                                        "non-standard magic", sb_version(rs));
                        return 1;
                }
        } else
@@ -1408,8 +1427,7 @@ static int reread_meta_blocks(struct super_block *s)
        ll_rw_block(READ, 1, &(SB_BUFFER_WITH_SB(s)));
        wait_on_buffer(SB_BUFFER_WITH_SB(s));
        if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) {
-               reiserfs_warning(s,
-                                "reread_meta_blocks, error reading the super");
+               reiserfs_warning(s, "reiserfs-2504", "error reading the super");
                return 1;
        }
 
@@ -1452,8 +1470,8 @@ static __u32 find_hash_out(struct super_block *s)
                        if (reiserfs_rupasov_hash(s)) {
                                hash = YURA_HASH;
                        }
-                       reiserfs_warning(s, "FS seems to be empty, autodetect "
-                                        "is using the default hash");
+                       reiserfs_info(s, "FS seems to be empty, autodetect "
+                                        "is using the default hash\n");
                        break;
                }
                r5hash = GET_HASH_VALUE(r5_hash(de.de_name, de.de_namelen));
@@ -1473,10 +1491,10 @@ static __u32 find_hash_out(struct super_block *s)
                        && (yurahash ==
                            GET_HASH_VALUE(deh_offset
                                           (&(de.de_deh[de.de_entry_num])))))) {
-                       reiserfs_warning(s,
-                                        "Unable to automatically detect hash function. "
-                                        "Please mount with -o hash={tea,rupasov,r5}",
-                                        reiserfs_bdevname(s));
+                       reiserfs_warning(s, "reiserfs-2506", "Unable to "
+                                        "automatically detect hash function. "
+                                        "Please mount with -o "
+                                        "hash={tea,rupasov,r5}");
                        hash = UNSET_HASH;
                        break;
                }
@@ -1490,7 +1508,8 @@ static __u32 find_hash_out(struct super_block *s)
                         (deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash)
                        hash = R5_HASH;
                else {
-                       reiserfs_warning(s, "Unrecognised hash function");
+                       reiserfs_warning(s, "reiserfs-2506",
+                                        "Unrecognised hash function");
                        hash = UNSET_HASH;
                }
        } while (0);
@@ -1514,21 +1533,24 @@ static int what_hash(struct super_block *s)
                code = find_hash_out(s);
 
        if (code != UNSET_HASH && reiserfs_hash_detect(s)) {
-               /* detection has found the hash, and we must check against the 
-                ** mount options 
+               /* detection has found the hash, and we must check against the
+                ** mount options
                 */
                if (reiserfs_rupasov_hash(s) && code != YURA_HASH) {
-                       reiserfs_warning(s, "Error, %s hash detected, "
+                       reiserfs_warning(s, "reiserfs-2507",
+                                        "Error, %s hash detected, "
                                         "unable to force rupasov hash",
                                         reiserfs_hashname(code));
                        code = UNSET_HASH;
                } else if (reiserfs_tea_hash(s) && code != TEA_HASH) {
-                       reiserfs_warning(s, "Error, %s hash detected, "
+                       reiserfs_warning(s, "reiserfs-2508",
+                                        "Error, %s hash detected, "
                                         "unable to force tea hash",
                                         reiserfs_hashname(code));
                        code = UNSET_HASH;
                } else if (reiserfs_r5_hash(s) && code != R5_HASH) {
-                       reiserfs_warning(s, "Error, %s hash detected, "
+                       reiserfs_warning(s, "reiserfs-2509",
+                                        "Error, %s hash detected, "
                                         "unable to force r5 hash",
                                         reiserfs_hashname(code));
                        code = UNSET_HASH;
@@ -1544,7 +1566,7 @@ static int what_hash(struct super_block *s)
                }
        }
 
-       /* if we are mounted RW, and we have a new valid hash code, update 
+       /* if we are mounted RW, and we have a new valid hash code, update
         ** the super
         */
        if (code != UNSET_HASH &&
@@ -1587,9 +1609,9 @@ static int function2code(hashf_t func)
        return 0;
 }
 
-#define SWARN(silent, s, ...)                  \
+#define SWARN(silent, s, id, ...)                      \
        if (!(silent))                          \
-               reiserfs_warning (s, __VA_ARGS__)
+               reiserfs_warning(s, id, __VA_ARGS__)
 
 static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
 {
@@ -1623,10 +1645,6 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
        REISERFS_SB(s)->s_alloc_options.preallocmin = 0;
        /* Preallocate by 16 blocks (17-1) at once */
        REISERFS_SB(s)->s_alloc_options.preallocsize = 17;
-#ifdef CONFIG_REISERFS_FS_XATTR
-       /* Initialize the rwsem for xattr dir */
-       init_rwsem(&REISERFS_SB(s)->xattr_dir_sem);
-#endif
        /* setup default block allocator options */
        reiserfs_init_alloc_options(s);
 
@@ -1641,8 +1659,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
 #endif
 
        if (blocks) {
-               SWARN(silent, s, "jmacd-7: reiserfs_fill_super: resize option "
-                     "for remount only");
+               SWARN(silent, s, "jmacd-7", "resize option for remount only");
                goto error;
        }
 
@@ -1651,8 +1668,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
                old_format = 1;
        /* try new format (64-th 1k block), which can contain reiserfs super block */
        else if (read_super_block(s, REISERFS_DISK_OFFSET_IN_BYTES)) {
-               SWARN(silent, s,
-                     "sh-2021: reiserfs_fill_super: can not find reiserfs on %s",
+               SWARN(silent, s, "sh-2021", "can not find reiserfs on %s",
                      reiserfs_bdevname(s));
                goto error;
        }
@@ -1664,13 +1680,12 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
        if (s->s_bdev && s->s_bdev->bd_inode
            && i_size_read(s->s_bdev->bd_inode) <
            sb_block_count(rs) * sb_blocksize(rs)) {
-               SWARN(silent, s,
-                     "Filesystem on %s cannot be mounted because it is bigger than the device",
-                     reiserfs_bdevname(s));
-               SWARN(silent, s,
-                     "You may need to run fsck or increase size of your LVM partition");
-               SWARN(silent, s,
-                     "Or may be you forgot to reboot after fdisk when it told you to");
+               SWARN(silent, s, "", "Filesystem cannot be "
+                     "mounted because it is bigger than the device");
+               SWARN(silent, s, "", "You may need to run fsck "
+                     "or increase size of your LVM partition");
+               SWARN(silent, s, "", "Or may be you forgot to "
+                     "reboot after fdisk when it told you to");
                goto error;
        }
 
@@ -1678,14 +1693,13 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
        sbi->s_mount_state = REISERFS_VALID_FS;
 
        if ((errval = reiserfs_init_bitmap_cache(s))) {
-               SWARN(silent, s,
-                     "jmacd-8: reiserfs_fill_super: unable to read bitmap");
+               SWARN(silent, s, "jmacd-8", "unable to read bitmap");
                goto error;
        }
        errval = -EINVAL;
 #ifdef CONFIG_REISERFS_CHECK
-       SWARN(silent, s, "CONFIG_REISERFS_CHECK is set ON");
-       SWARN(silent, s, "- it is slow mode for debugging.");
+       SWARN(silent, s, "", "CONFIG_REISERFS_CHECK is set ON");
+       SWARN(silent, s, "", "- it is slow mode for debugging.");
 #endif
 
        /* make data=ordered the default */
@@ -1706,8 +1720,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
        }
        // set_device_ro(s->s_dev, 1) ;
        if (journal_init(s, jdev_name, old_format, commit_max_age)) {
-               SWARN(silent, s,
-                     "sh-2022: reiserfs_fill_super: unable to initialize journal space");
+               SWARN(silent, s, "sh-2022",
+                     "unable to initialize journal space");
                goto error;
        } else {
                jinit_done = 1; /* once this is set, journal_release must be called
@@ -1715,8 +1729,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
                                 */
        }
        if (reread_meta_blocks(s)) {
-               SWARN(silent, s,
-                     "jmacd-9: reiserfs_fill_super: unable to reread meta blocks after journal init");
+               SWARN(silent, s, "jmacd-9",
+                     "unable to reread meta blocks after journal init");
                goto error;
        }
 
@@ -1724,8 +1738,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
                goto error;
 
        if (bdev_read_only(s->s_bdev) && !(s->s_flags & MS_RDONLY)) {
-               SWARN(silent, s,
-                     "clm-7000: Detected readonly device, marking FS readonly");
+               SWARN(silent, s, "clm-7000",
+                     "Detected readonly device, marking FS readonly");
                s->s_flags |= MS_RDONLY;
        }
        args.objectid = REISERFS_ROOT_OBJECTID;
@@ -1734,8 +1748,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
            iget5_locked(s, REISERFS_ROOT_OBJECTID, reiserfs_find_actor,
                         reiserfs_init_locked_inode, (void *)(&args));
        if (!root_inode) {
-               SWARN(silent, s,
-                     "jmacd-10: reiserfs_fill_super: get root inode failed");
+               SWARN(silent, s, "jmacd-10", "get root inode failed");
                goto error;
        }
 
@@ -1784,7 +1797,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
                 * avoiding corruption. -jeffm */
                if (bmap_would_wrap(reiserfs_bmap_count(s)) &&
                    sb_bmap_nr(rs) != 0) {
-                       reiserfs_warning(s, "super-2030This file system "
+                       reiserfs_warning(s, "super-2030", "This file system "
                                        "claims to use %u bitmap blocks in "
                                        "its super block, but requires %u. "
                                        "Clearing to zero.", sb_bmap_nr(rs),
@@ -1817,7 +1830,9 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
                        } else if (!silent) {
                                reiserfs_info(s, "using 3.5.x disk format\n");
                        }
-               }
+               } else
+                       set_sb_mnt_count(rs, sb_mnt_count(rs) + 1);
+
 
                journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
                errval = journal_end(&th, s, 1);
@@ -1890,6 +1905,10 @@ static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bsize = dentry->d_sb->s_blocksize;
        /* changed to accommodate gcc folks. */
        buf->f_type = REISERFS_SUPER_MAGIC;
+       buf->f_fsid.val[0] = (u32)crc32_le(0, rs->s_uuid, sizeof(rs->s_uuid)/2);
+       buf->f_fsid.val[1] = (u32)crc32_le(0, rs->s_uuid + sizeof(rs->s_uuid)/2,
+                               sizeof(rs->s_uuid)/2);
+
        return 0;
 }
 
@@ -2031,8 +2050,8 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
        if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) {
                err = reiserfs_unpack(inode, NULL);
                if (err) {
-                       reiserfs_warning(sb,
-                               "reiserfs: Unpacking tail of quota file failed"
+                       reiserfs_warning(sb, "super-6520",
+                               "Unpacking tail of quota file failed"
                                " (%d). Cannot turn on quotas.", err);
                        err = -EINVAL;
                        goto out;
@@ -2043,8 +2062,8 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
        if (REISERFS_SB(sb)->s_qf_names[type]) {
                /* Quotafile not of fs root? */
                if (path.dentry->d_parent != sb->s_root)
-                       reiserfs_warning(sb,
-                                "reiserfs: Quota file not on filesystem root. "
+                       reiserfs_warning(sb, "super-6521",
+                                "Quota file not on filesystem root. "
                                 "Journalled quota will not work.");
        }
 
@@ -2195,9 +2214,6 @@ static int __init init_reiserfs_fs(void)
                return ret;
        }
 
-       if ((ret = reiserfs_xattr_register_handlers()))
-               goto failed_reiserfs_xattr_register_handlers;
-
        reiserfs_proc_info_global_init();
        reiserfs_proc_register_global("version",
                                      reiserfs_global_version_in_proc);
@@ -2208,9 +2224,6 @@ static int __init init_reiserfs_fs(void)
                return 0;
        }
 
-       reiserfs_xattr_unregister_handlers();
-
-      failed_reiserfs_xattr_register_handlers:
        reiserfs_proc_unregister_global("version");
        reiserfs_proc_info_global_done();
        destroy_inodecache();
@@ -2220,7 +2233,6 @@ static int __init init_reiserfs_fs(void)
 
 static void __exit exit_reiserfs_fs(void)
 {
-       reiserfs_xattr_unregister_handlers();
        reiserfs_proc_unregister_global("version");
        reiserfs_proc_info_global_done();
        unregister_filesystem(&reiserfs_fs_type);
index f8121a1147e863e80039ba676939b9c5abd7bd7f..d7f6e51bef2af42390c40da795dee558ee97af34 100644 (file)
@@ -26,7 +26,7 @@ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode,
                                   converted item. */
        struct item_head ind_ih;        /* new indirect item to be inserted or
                                           key of unfm pointer to be pasted */
-       int n_blk_size, n_retval;       /* returned value for reiserfs_insert_item and clones */
+       int blk_size, retval;   /* returned value for reiserfs_insert_item and clones */
        unp_t unfm_ptr;         /* Handle on an unformatted node
                                   that will be inserted in the
                                   tree. */
@@ -35,7 +35,7 @@ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode,
 
        REISERFS_SB(sb)->s_direct2indirect++;
 
-       n_blk_size = sb->s_blocksize;
+       blk_size = sb->s_blocksize;
 
        /* and key to search for append or insert pointer to the new
           unformatted node. */
@@ -46,11 +46,11 @@ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode,
        /* Set the key to search for the place for new unfm pointer */
        make_cpu_key(&end_key, inode, tail_offset, TYPE_INDIRECT, 4);
 
-       // FIXME: we could avoid this 
+       /* FIXME: we could avoid this */
        if (search_for_position_by_key(sb, &end_key, path) == POSITION_FOUND) {
-               reiserfs_warning(sb, "PAP-14030: direct2indirect: "
-                                "pasted or inserted byte exists in the tree %K. "
-                                "Use fsck to repair.", &end_key);
+               reiserfs_error(sb, "PAP-14030",
+                              "pasted or inserted byte exists in "
+                              "the tree %K. Use fsck to repair.", &end_key);
                pathrelse(path);
                return -EIO;
        }
@@ -64,17 +64,17 @@ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode,
                set_ih_free_space(&ind_ih, 0);  /* delete at nearest future */
                put_ih_item_len(&ind_ih, UNFM_P_SIZE);
                PATH_LAST_POSITION(path)++;
-               n_retval =
+               retval =
                    reiserfs_insert_item(th, path, &end_key, &ind_ih, inode,
                                         (char *)&unfm_ptr);
        } else {
                /* Paste into last indirect item of an object. */
-               n_retval = reiserfs_paste_into_item(th, path, &end_key, inode,
+               retval = reiserfs_paste_into_item(th, path, &end_key, inode,
                                                    (char *)&unfm_ptr,
                                                    UNFM_P_SIZE);
        }
-       if (n_retval) {
-               return n_retval;
+       if (retval) {
+               return retval;
        }
        // note: from here there are two keys which have matching first
        // three key components. They only differ by the fourth one.
@@ -92,14 +92,13 @@ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode,
                   last item of the file */
                if (search_for_position_by_key(sb, &end_key, path) ==
                    POSITION_FOUND)
-                       reiserfs_panic(sb,
-                                      "PAP-14050: direct2indirect: "
+                       reiserfs_panic(sb, "PAP-14050",
                                       "direct item (%K) not found", &end_key);
                p_le_ih = PATH_PITEM_HEAD(path);
                RFALSE(!is_direct_le_ih(p_le_ih),
                       "vs-14055: direct item expected(%K), found %h",
                       &end_key, p_le_ih);
-               tail_size = (le_ih_k_offset(p_le_ih) & (n_blk_size - 1))
+               tail_size = (le_ih_k_offset(p_le_ih) & (blk_size - 1))
                    + ih_item_len(p_le_ih) - 1;
 
                /* we only send the unbh pointer if the buffer is not up to date.
@@ -114,11 +113,11 @@ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode,
                } else {
                        up_to_date_bh = unbh;
                }
-               n_retval = reiserfs_delete_item(th, path, &end_key, inode,
+               retval = reiserfs_delete_item(th, path, &end_key, inode,
                                                up_to_date_bh);
 
-               total_tail += n_retval;
-               if (tail_size == n_retval)
+               total_tail += retval;
+               if (tail_size == retval)
                        // done: file does not have direct items anymore
                        break;
 
@@ -130,7 +129,7 @@ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode,
                unsigned pgoff =
                    (tail_offset + total_tail - 1) & (PAGE_CACHE_SIZE - 1);
                char *kaddr = kmap_atomic(up_to_date_bh->b_page, KM_USER0);
-               memset(kaddr + pgoff, 0, n_blk_size - total_tail);
+               memset(kaddr + pgoff, 0, blk_size - total_tail);
                kunmap_atomic(kaddr, KM_USER0);
        }
 
@@ -171,14 +170,18 @@ void reiserfs_unmap_buffer(struct buffer_head *bh)
    what we expect from it (number of cut bytes). But when tail remains
    in the unformatted node, we set mode to SKIP_BALANCING and unlock
    inode */
-int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_inode, struct page *page, struct treepath *p_s_path,     /* path to the indirect item. */
-                   const struct cpu_key *p_s_item_key, /* Key to look for unformatted node pointer to be cut. */
+int indirect2direct(struct reiserfs_transaction_handle *th,
+                   struct inode *inode, struct page *page,
+                   struct treepath *path,      /* path to the indirect item. */
+                   const struct cpu_key *item_key,     /* Key to look for
+                                                        * unformatted node
+                                                        * pointer to be cut. */
                    loff_t n_new_file_size,     /* New file size. */
-                   char *p_c_mode)
+                   char *mode)
 {
-       struct super_block *p_s_sb = p_s_inode->i_sb;
+       struct super_block *sb = inode->i_sb;
        struct item_head s_ih;
-       unsigned long n_block_size = p_s_sb->s_blocksize;
+       unsigned long block_size = sb->s_blocksize;
        char *tail;
        int tail_len, round_tail_len;
        loff_t pos, pos1;       /* position of first byte of the tail */
@@ -186,22 +189,22 @@ int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_in
 
        BUG_ON(!th->t_trans_id);
 
-       REISERFS_SB(p_s_sb)->s_indirect2direct++;
+       REISERFS_SB(sb)->s_indirect2direct++;
 
-       *p_c_mode = M_SKIP_BALANCING;
+       *mode = M_SKIP_BALANCING;
 
        /* store item head path points to. */
-       copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
+       copy_item_head(&s_ih, PATH_PITEM_HEAD(path));
 
-       tail_len = (n_new_file_size & (n_block_size - 1));
-       if (get_inode_sd_version(p_s_inode) == STAT_DATA_V2)
+       tail_len = (n_new_file_size & (block_size - 1));
+       if (get_inode_sd_version(inode) == STAT_DATA_V2)
                round_tail_len = ROUND_UP(tail_len);
        else
                round_tail_len = tail_len;
 
        pos =
            le_ih_k_offset(&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE -
-                                        1) * p_s_sb->s_blocksize;
+                                        1) * sb->s_blocksize;
        pos1 = pos;
 
        // we are protected by i_mutex. The tail can not disapper, not
@@ -210,27 +213,26 @@ int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_in
 
        tail = (char *)kmap(page);      /* this can schedule */
 
-       if (path_changed(&s_ih, p_s_path)) {
+       if (path_changed(&s_ih, path)) {
                /* re-search indirect item */
-               if (search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path)
+               if (search_for_position_by_key(sb, item_key, path)
                    == POSITION_NOT_FOUND)
-                       reiserfs_panic(p_s_sb,
-                                      "PAP-5520: indirect2direct: "
+                       reiserfs_panic(sb, "PAP-5520",
                                       "item to be converted %K does not exist",
-                                      p_s_item_key);
-               copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
+                                      item_key);
+               copy_item_head(&s_ih, PATH_PITEM_HEAD(path));
 #ifdef CONFIG_REISERFS_CHECK
                pos = le_ih_k_offset(&s_ih) - 1 +
                    (ih_item_len(&s_ih) / UNFM_P_SIZE -
-                    1) * p_s_sb->s_blocksize;
+                    1) * sb->s_blocksize;
                if (pos != pos1)
-                       reiserfs_panic(p_s_sb, "vs-5530: indirect2direct: "
-                                      "tail position changed while we were reading it");
+                       reiserfs_panic(sb, "vs-5530", "tail position "
+                                      "changed while we were reading it");
 #endif
        }
 
        /* Set direct item header to insert. */
-       make_le_item_head(&s_ih, NULL, get_inode_item_key_version(p_s_inode),
+       make_le_item_head(&s_ih, NULL, get_inode_item_key_version(inode),
                          pos1 + 1, TYPE_DIRECT, round_tail_len,
                          0xffff /*ih_free_space */ );
 
@@ -240,13 +242,13 @@ int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_in
         */
        tail = tail + (pos & (PAGE_CACHE_SIZE - 1));
 
-       PATH_LAST_POSITION(p_s_path)++;
+       PATH_LAST_POSITION(path)++;
 
-       key = *p_s_item_key;
+       key = *item_key;
        set_cpu_key_k_type(&key, TYPE_DIRECT);
        key.key_length = 4;
        /* Insert tail as new direct item in the tree */
-       if (reiserfs_insert_item(th, p_s_path, &key, &s_ih, p_s_inode,
+       if (reiserfs_insert_item(th, path, &key, &s_ih, inode,
                                 tail ? tail : NULL) < 0) {
                /* No disk memory. So we can not convert last unformatted node
                   to the direct item.  In this case we used to adjust
@@ -255,12 +257,12 @@ int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_in
                   unformatted node. For now i_size is considered as guard for
                   going out of file size */
                kunmap(page);
-               return n_block_size - round_tail_len;
+               return block_size - round_tail_len;
        }
        kunmap(page);
 
        /* make sure to get the i_blocks changes from reiserfs_insert_item */
-       reiserfs_update_sd(th, p_s_inode);
+       reiserfs_update_sd(th, inode);
 
        // note: we have now the same as in above direct2indirect
        // conversion: there are two keys which have matching first three
@@ -268,11 +270,11 @@ int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_in
 
        /* We have inserted new direct item and must remove last
           unformatted node. */
-       *p_c_mode = M_CUT;
+       *mode = M_CUT;
 
        /* we store position of first direct item in the in-core inode */
-       //mark_file_with_tail (p_s_inode, pos1 + 1);
-       REISERFS_I(p_s_inode)->i_first_direct_byte = pos1 + 1;
+       /* mark_file_with_tail (inode, pos1 + 1); */
+       REISERFS_I(inode)->i_first_direct_byte = pos1 + 1;
 
-       return n_block_size - round_tail_len;
+       return block_size - round_tail_len;
 }
index ae881ccd2f03472c24ba2aee911377787237ff84..f83f52bae390f6484702f8e470de497b41b59921 100644 (file)
  * these are special cases for filesystem ACLs, they are interpreted by the
  * kernel, in addition, they are negatively and positively cached and attached
  * to the inode so that unnecessary lookups are avoided.
+ *
+ * Locking works like so:
+ * Directory components (xattr root, xattr dir) are protectd by their i_mutex.
+ * The xattrs themselves are protected by the xattr_sem.
  */
 
 #include <linux/reiserfs_fs.h>
 #include <net/checksum.h>
 #include <linux/smp_lock.h>
 #include <linux/stat.h>
+#include <linux/quotaops.h>
 
-#define FL_READONLY 128
-#define FL_DIR_SEM_HELD 256
 #define PRIVROOT_NAME ".reiserfs_priv"
 #define XAROOT_NAME   "xattrs"
 
-static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char
-                                                               *prefix);
 
-/* Returns the dentry referring to the root of the extended attribute
- * directory tree. If it has already been retrieved, it is used. If it
- * hasn't been created and the flags indicate creation is allowed, we
- * attempt to create it. On error, we return a pointer-encoded error.
- */
-static struct dentry *get_xa_root(struct super_block *sb, int flags)
+/* Helpers for inode ops. We do this so that we don't have all the VFS
+ * overhead and also for proper i_mutex annotation.
+ * dir->i_mutex must be held for all of them. */
+#ifdef CONFIG_REISERFS_FS_XATTR
+static int xattr_create(struct inode *dir, struct dentry *dentry, int mode)
 {
-       struct dentry *privroot = dget(REISERFS_SB(sb)->priv_root);
-       struct dentry *xaroot;
+       BUG_ON(!mutex_is_locked(&dir->i_mutex));
+       vfs_dq_init(dir);
+       return dir->i_op->create(dir, dentry, mode, NULL);
+}
+#endif
 
-       /* This needs to be created at mount-time */
-       if (!privroot)
-               return ERR_PTR(-ENODATA);
+static int xattr_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+       BUG_ON(!mutex_is_locked(&dir->i_mutex));
+       vfs_dq_init(dir);
+       return dir->i_op->mkdir(dir, dentry, mode);
+}
 
-       mutex_lock_nested(&privroot->d_inode->i_mutex, I_MUTEX_XATTR);
-       if (REISERFS_SB(sb)->xattr_root) {
-               xaroot = dget(REISERFS_SB(sb)->xattr_root);
-               goto out;
-       }
+/* We use I_MUTEX_CHILD here to silence lockdep. It's safe because xattr
+ * mutation ops aren't called during rename or splace, which are the
+ * only other users of I_MUTEX_CHILD. It violates the ordering, but that's
+ * better than allocating another subclass just for this code. */
+static int xattr_unlink(struct inode *dir, struct dentry *dentry)
+{
+       int error;
+       BUG_ON(!mutex_is_locked(&dir->i_mutex));
+       vfs_dq_init(dir);
 
-       xaroot = lookup_one_len(XAROOT_NAME, privroot, strlen(XAROOT_NAME));
-       if (IS_ERR(xaroot)) {
-               goto out;
-       } else if (!xaroot->d_inode) {
+       mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
+       error = dir->i_op->unlink(dir, dentry);
+       mutex_unlock(&dentry->d_inode->i_mutex);
+
+       if (!error)
+               d_delete(dentry);
+       return error;
+}
+
+static int xattr_rmdir(struct inode *dir, struct dentry *dentry)
+{
+       int error;
+       BUG_ON(!mutex_is_locked(&dir->i_mutex));
+       vfs_dq_init(dir);
+
+       mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
+       dentry_unhash(dentry);
+       error = dir->i_op->rmdir(dir, dentry);
+       if (!error)
+               dentry->d_inode->i_flags |= S_DEAD;
+       mutex_unlock(&dentry->d_inode->i_mutex);
+       if (!error)
+               d_delete(dentry);
+       dput(dentry);
+
+       return error;
+}
+
+#define xattr_may_create(flags)        (!flags || flags & XATTR_CREATE)
+
+/* Returns and possibly creates the xattr dir. */
+static struct dentry *lookup_or_create_dir(struct dentry *parent,
+                                           const char *name, int flags)
+{
+       struct dentry *dentry;
+       BUG_ON(!parent);
+
+       dentry = lookup_one_len(name, parent, strlen(name));
+       if (IS_ERR(dentry))
+               return dentry;
+       else if (!dentry->d_inode) {
                int err = -ENODATA;
-               if (flags == 0 || flags & XATTR_CREATE)
-                       err = privroot->d_inode->i_op->mkdir(privroot->d_inode,
-                                                            xaroot, 0700);
+
+               if (xattr_may_create(flags)) {
+                       mutex_lock_nested(&parent->d_inode->i_mutex,
+                                         I_MUTEX_XATTR);
+                       err = xattr_mkdir(parent->d_inode, dentry, 0700);
+                       mutex_unlock(&parent->d_inode->i_mutex);
+               }
+
                if (err) {
-                       dput(xaroot);
-                       xaroot = ERR_PTR(err);
-                       goto out;
+                       dput(dentry);
+                       dentry = ERR_PTR(err);
                }
        }
-       REISERFS_SB(sb)->xattr_root = dget(xaroot);
 
-      out:
-       mutex_unlock(&privroot->d_inode->i_mutex);
-       dput(privroot);
-       return xaroot;
+       return dentry;
+}
+
+static struct dentry *open_xa_root(struct super_block *sb, int flags)
+{
+       struct dentry *privroot = REISERFS_SB(sb)->priv_root;
+       if (!privroot)
+               return ERR_PTR(-ENODATA);
+       return lookup_or_create_dir(privroot, XAROOT_NAME, flags);
 }
 
-/* Opens the directory corresponding to the inode's extended attribute store.
- * If flags allow, the tree to the directory may be created. If creation is
- * prohibited, -ENODATA is returned. */
 static struct dentry *open_xa_dir(const struct inode *inode, int flags)
 {
        struct dentry *xaroot, *xadir;
        char namebuf[17];
 
-       xaroot = get_xa_root(inode->i_sb, flags);
+       xaroot = open_xa_root(inode->i_sb, flags);
        if (IS_ERR(xaroot))
                return xaroot;
 
-       /* ok, we have xaroot open */
        snprintf(namebuf, sizeof(namebuf), "%X.%X",
                 le32_to_cpu(INODE_PKEY(inode)->k_objectid),
                 inode->i_generation);
-       xadir = lookup_one_len(namebuf, xaroot, strlen(namebuf));
-       if (IS_ERR(xadir)) {
-               dput(xaroot);
-               return xadir;
-       }
-
-       if (!xadir->d_inode) {
-               int err;
-               if (flags == 0 || flags & XATTR_CREATE) {
-                       /* Although there is nothing else trying to create this directory,
-                        * another directory with the same hash may be created, so we need
-                        * to protect against that */
-                       err =
-                           xaroot->d_inode->i_op->mkdir(xaroot->d_inode, xadir,
-                                                        0700);
-                       if (err) {
-                               dput(xaroot);
-                               dput(xadir);
-                               return ERR_PTR(err);
-                       }
-               }
-               if (!xadir->d_inode) {
-                       dput(xaroot);
-                       dput(xadir);
-                       return ERR_PTR(-ENODATA);
-               }
-       }
 
+       xadir = lookup_or_create_dir(xaroot, namebuf, flags);
        dput(xaroot);
        return xadir;
+
 }
 
-/* Returns a dentry corresponding to a specific extended attribute file
- * for the inode. If flags allow, the file is created. Otherwise, a
- * valid or negative dentry, or an error is returned. */
-static struct dentry *get_xa_file_dentry(const struct inode *inode,
-                                        const char *name, int flags)
-{
-       struct dentry *xadir, *xafile;
-       int err = 0;
+/* The following are side effects of other operations that aren't explicitly
+ * modifying extended attributes. This includes operations such as permissions
+ * or ownership changes, object deletions, etc. */
+struct reiserfs_dentry_buf {
+       struct dentry *xadir;
+       int count;
+       struct dentry *dentries[8];
+};
 
-       xadir = open_xa_dir(inode, flags);
-       if (IS_ERR(xadir)) {
-               return ERR_CAST(xadir);
-       } else if (!xadir->d_inode) {
-               dput(xadir);
-               return ERR_PTR(-ENODATA);
-       }
+static int
+fill_with_dentries(void *buf, const char *name, int namelen, loff_t offset,
+                   u64 ino, unsigned int d_type)
+{
+       struct reiserfs_dentry_buf *dbuf = buf;
+       struct dentry *dentry;
 
-       xafile = lookup_one_len(name, xadir, strlen(name));
-       if (IS_ERR(xafile)) {
-               dput(xadir);
-               return ERR_CAST(xafile);
-       }
+       if (dbuf->count == ARRAY_SIZE(dbuf->dentries))
+               return -ENOSPC;
 
-       if (xafile->d_inode) {  /* file exists */
-               if (flags & XATTR_CREATE) {
-                       err = -EEXIST;
-                       dput(xafile);
-                       goto out;
-               }
-       } else if (flags & XATTR_REPLACE || flags & FL_READONLY) {
-               goto out;
-       } else {
-               /* inode->i_mutex is down, so nothing else can try to create
-                * the same xattr */
-               err = xadir->d_inode->i_op->create(xadir->d_inode, xafile,
-                                                  0700 | S_IFREG, NULL);
+       if (name[0] == '.' && (name[1] == '\0' ||
+                              (name[1] == '.' && name[2] == '\0')))
+               return 0;
 
-               if (err) {
-                       dput(xafile);
-                       goto out;
-               }
+       dentry = lookup_one_len(name, dbuf->xadir, namelen);
+       if (IS_ERR(dentry)) {
+               return PTR_ERR(dentry);
+       } else if (!dentry->d_inode) {
+               /* A directory entry exists, but no file? */
+               reiserfs_error(dentry->d_sb, "xattr-20003",
+                              "Corrupted directory: xattr %s listed but "
+                              "not found for file %s.\n",
+                              dentry->d_name.name, dbuf->xadir->d_name.name);
+               dput(dentry);
+               return -EIO;
        }
 
-      out:
-       dput(xadir);
-       if (err)
-               xafile = ERR_PTR(err);
-       else if (!xafile->d_inode) {
-               dput(xafile);
-               xafile = ERR_PTR(-ENODATA);
-       }
-       return xafile;
+       dbuf->dentries[dbuf->count++] = dentry;
+       return 0;
 }
 
-/*
- * this is very similar to fs/reiserfs/dir.c:reiserfs_readdir, but
- * we need to drop the path before calling the filldir struct.  That
- * would be a big performance hit to the non-xattr case, so I've copied
- * the whole thing for now. --clm
- *
- * the big difference is that I go backwards through the directory,
- * and don't mess with f->f_pos, but the idea is the same.  Do some
- * action on each and every entry in the directory.
- *
- * we're called with i_mutex held, so there are no worries about the directory
- * changing underneath us.
- */
-static int __xattr_readdir(struct inode *inode, void *dirent, filldir_t filldir)
+static void
+cleanup_dentry_buf(struct reiserfs_dentry_buf *buf)
 {
-       struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */
-       INITIALIZE_PATH(path_to_entry);
-       struct buffer_head *bh;
-       int entry_num;
-       struct item_head *ih, tmp_ih;
-       int search_res;
-       char *local_buf;
-       loff_t next_pos;
-       char small_buf[32];     /* avoid kmalloc if we can */
-       struct reiserfs_de_head *deh;
-       int d_reclen;
-       char *d_name;
-       off_t d_off;
-       ino_t d_ino;
-       struct reiserfs_dir_entry de;
-
-       /* form key for search the next directory entry using f_pos field of
-          file structure */
-       next_pos = max_reiserfs_offset(inode);
-
-       while (1) {
-             research:
-               if (next_pos <= DOT_DOT_OFFSET)
-                       break;
-               make_cpu_key(&pos_key, inode, next_pos, TYPE_DIRENTRY, 3);
-
-               search_res =
-                   search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry,
-                                       &de);
-               if (search_res == IO_ERROR) {
-                       // FIXME: we could just skip part of directory which could
-                       // not be read
-                       pathrelse(&path_to_entry);
-                       return -EIO;
-               }
+       int i;
+       for (i = 0; i < buf->count; i++)
+               if (buf->dentries[i])
+                       dput(buf->dentries[i]);
+}
+
+static int reiserfs_for_each_xattr(struct inode *inode,
+                                  int (*action)(struct dentry *, void *),
+                                  void *data)
+{
+       struct dentry *dir;
+       int i, err = 0;
+       loff_t pos = 0;
+       struct reiserfs_dentry_buf buf = {
+               .count = 0,
+       };
 
-               if (search_res == NAME_NOT_FOUND)
-                       de.de_entry_num--;
+       /* Skip out, an xattr has no xattrs associated with it */
+       if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1)
+               return 0;
 
-               set_de_name_and_namelen(&de);
-               entry_num = de.de_entry_num;
-               deh = &(de.de_deh[entry_num]);
+       dir = open_xa_dir(inode, XATTR_REPLACE);
+       if (IS_ERR(dir)) {
+               err = PTR_ERR(dir);
+               goto out;
+       } else if (!dir->d_inode) {
+               err = 0;
+               goto out_dir;
+       }
 
-               bh = de.de_bh;
-               ih = de.de_ih;
+       mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR);
+       buf.xadir = dir;
+       err = reiserfs_readdir_dentry(dir, &buf, fill_with_dentries, &pos);
+       while ((err == 0 || err == -ENOSPC) && buf.count) {
+               err = 0;
 
-               if (!is_direntry_le_ih(ih)) {
-                       reiserfs_warning(inode->i_sb, "not direntry %h", ih);
-                       break;
-               }
-               copy_item_head(&tmp_ih, ih);
+               for (i = 0; i < buf.count && buf.dentries[i]; i++) {
+                       int lerr = 0;
+                       struct dentry *dentry = buf.dentries[i];
 
-               /* we must have found item, that is item of this directory, */
-               RFALSE(COMP_SHORT_KEYS(&(ih->ih_key), &pos_key),
-                      "vs-9000: found item %h does not match to dir we readdir %K",
-                      ih, &pos_key);
+                       if (err == 0 && !S_ISDIR(dentry->d_inode->i_mode))
+                               lerr = action(dentry, data);
 
-               if (deh_offset(deh) <= DOT_DOT_OFFSET) {
-                       break;
+                       dput(dentry);
+                       buf.dentries[i] = NULL;
+                       err = lerr ?: err;
                }
+               buf.count = 0;
+               if (!err)
+                       err = reiserfs_readdir_dentry(dir, &buf,
+                                                     fill_with_dentries, &pos);
+       }
+       mutex_unlock(&dir->d_inode->i_mutex);
 
-               /* look for the previous entry in the directory */
-               next_pos = deh_offset(deh) - 1;
-
-               if (!de_visible(deh))
-                       /* it is hidden entry */
-                       continue;
+       /* Clean up after a failed readdir */
+       cleanup_dentry_buf(&buf);
 
-               d_reclen = entry_length(bh, ih, entry_num);
-               d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh);
-               d_off = deh_offset(deh);
-               d_ino = deh_objectid(deh);
+       if (!err) {
+               /* We start a transaction here to avoid a ABBA situation
+                * between the xattr root's i_mutex and the journal lock.
+                * This doesn't incur much additional overhead since the
+                * new transaction will just nest inside the
+                * outer transaction. */
+               int blocks = JOURNAL_PER_BALANCE_CNT * 2 + 2 +
+                            4 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb);
+               struct reiserfs_transaction_handle th;
+               err = journal_begin(&th, inode->i_sb, blocks);
+               if (!err) {
+                       int jerror;
+                       mutex_lock_nested(&dir->d_parent->d_inode->i_mutex,
+                                         I_MUTEX_XATTR);
+                       err = action(dir, data);
+                       jerror = journal_end(&th, inode->i_sb, blocks);
+                       mutex_unlock(&dir->d_parent->d_inode->i_mutex);
+                       err = jerror ?: err;
+               }
+       }
+out_dir:
+       dput(dir);
+out:
+       /* -ENODATA isn't an error */
+       if (err == -ENODATA)
+               err = 0;
+       return err;
+}
 
-               if (!d_name[d_reclen - 1])
-                       d_reclen = strlen(d_name);
+static int delete_one_xattr(struct dentry *dentry, void *data)
+{
+       struct inode *dir = dentry->d_parent->d_inode;
 
-               if (d_reclen > REISERFS_MAX_NAME(inode->i_sb->s_blocksize)) {
-                       /* too big to send back to VFS */
-                       continue;
-               }
+       /* This is the xattr dir, handle specially. */
+       if (S_ISDIR(dentry->d_inode->i_mode))
+               return xattr_rmdir(dir, dentry);
 
-               /* Ignore the .reiserfs_priv entry */
-               if (reiserfs_xattrs(inode->i_sb) &&
-                   !old_format_only(inode->i_sb) &&
-                   deh_objectid(deh) ==
-                   le32_to_cpu(INODE_PKEY
-                               (REISERFS_SB(inode->i_sb)->priv_root->d_inode)->
-                               k_objectid))
-                       continue;
-
-               if (d_reclen <= 32) {
-                       local_buf = small_buf;
-               } else {
-                       local_buf = kmalloc(d_reclen, GFP_NOFS);
-                       if (!local_buf) {
-                               pathrelse(&path_to_entry);
-                               return -ENOMEM;
-                       }
-                       if (item_moved(&tmp_ih, &path_to_entry)) {
-                               kfree(local_buf);
+       return xattr_unlink(dir, dentry);
+}
 
-                               /* sigh, must retry.  Do this same offset again */
-                               next_pos = d_off;
-                               goto research;
-                       }
-               }
+static int chown_one_xattr(struct dentry *dentry, void *data)
+{
+       struct iattr *attrs = data;
+       return reiserfs_setattr(dentry, attrs);
+}
 
-               // Note, that we copy name to user space via temporary
-               // buffer (local_buf) because filldir will block if
-               // user space buffer is swapped out. At that time
-               // entry can move to somewhere else
-               memcpy(local_buf, d_name, d_reclen);
-
-               /* the filldir function might need to start transactions,
-                * or do who knows what.  Release the path now that we've
-                * copied all the important stuff out of the deh
-                */
-               pathrelse(&path_to_entry);
-
-               if (filldir(dirent, local_buf, d_reclen, d_off, d_ino,
-                           DT_UNKNOWN) < 0) {
-                       if (local_buf != small_buf) {
-                               kfree(local_buf);
-                       }
-                       goto end;
-               }
-               if (local_buf != small_buf) {
-                       kfree(local_buf);
-               }
-       }                       /* while */
+/* No i_mutex, but the inode is unconnected. */
+int reiserfs_delete_xattrs(struct inode *inode)
+{
+       int err = reiserfs_for_each_xattr(inode, delete_one_xattr, NULL);
+       if (err)
+               reiserfs_warning(inode->i_sb, "jdm-20004",
+                                "Couldn't delete all xattrs (%d)\n", err);
+       return err;
+}
 
-      end:
-       pathrelse(&path_to_entry);
-       return 0;
+/* inode->i_mutex: down */
+int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs)
+{
+       int err = reiserfs_for_each_xattr(inode, chown_one_xattr, attrs);
+       if (err)
+               reiserfs_warning(inode->i_sb, "jdm-20007",
+                                "Couldn't chown all xattrs (%d)\n", err);
+       return err;
 }
 
-/*
- * this could be done with dedicated readdir ops for the xattr files,
- * but I want to get something working asap
- * this is stolen from vfs_readdir
- *
- */
-static
-int xattr_readdir(struct inode *inode, filldir_t filler, void *buf)
+#ifdef CONFIG_REISERFS_FS_XATTR
+/* Returns a dentry corresponding to a specific extended attribute file
+ * for the inode. If flags allow, the file is created. Otherwise, a
+ * valid or negative dentry, or an error is returned. */
+static struct dentry *xattr_lookup(struct inode *inode, const char *name,
+                                   int flags)
 {
-       int res = -ENOENT;
-       mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR);
-       if (!IS_DEADDIR(inode)) {
-               lock_kernel();
-               res = __xattr_readdir(inode, buf, filler);
-               unlock_kernel();
+       struct dentry *xadir, *xafile;
+       int err = 0;
+
+       xadir = open_xa_dir(inode, flags);
+       if (IS_ERR(xadir))
+               return ERR_CAST(xadir);
+
+       xafile = lookup_one_len(name, xadir, strlen(name));
+       if (IS_ERR(xafile)) {
+               err = PTR_ERR(xafile);
+               goto out;
        }
-       mutex_unlock(&inode->i_mutex);
-       return res;
+
+       if (xafile->d_inode && (flags & XATTR_CREATE))
+               err = -EEXIST;
+
+       if (!xafile->d_inode) {
+               err = -ENODATA;
+               if (xattr_may_create(flags)) {
+                       mutex_lock_nested(&xadir->d_inode->i_mutex,
+                                         I_MUTEX_XATTR);
+                       err = xattr_create(xadir->d_inode, xafile,
+                                             0700|S_IFREG);
+                       mutex_unlock(&xadir->d_inode->i_mutex);
+               }
+       }
+
+       if (err)
+               dput(xafile);
+out:
+       dput(xadir);
+       if (err)
+               return ERR_PTR(err);
+       return xafile;
 }
 
 /* Internal operations on file data */
@@ -375,14 +385,14 @@ static inline void reiserfs_put_page(struct page *page)
        page_cache_release(page);
 }
 
-static struct page *reiserfs_get_page(struct inode *dir, unsigned long n)
+static struct page *reiserfs_get_page(struct inode *dir, size_t n)
 {
        struct address_space *mapping = dir->i_mapping;
        struct page *page;
        /* We can deadlock if we try to free dentries,
           and an unlink/rmdir has just occured - GFP_NOFS avoids this */
        mapping_set_gfp_mask(mapping, GFP_NOFS);
-       page = read_mapping_page(mapping, n, NULL);
+       page = read_mapping_page(mapping, n >> PAGE_CACHE_SHIFT, NULL);
        if (!IS_ERR(page)) {
                kmap(page);
                if (PageError(page))
@@ -405,6 +415,45 @@ int reiserfs_commit_write(struct file *f, struct page *page,
 int reiserfs_prepare_write(struct file *f, struct page *page,
                           unsigned from, unsigned to);
 
+static void update_ctime(struct inode *inode)
+{
+       struct timespec now = current_fs_time(inode->i_sb);
+       if (hlist_unhashed(&inode->i_hash) || !inode->i_nlink ||
+           timespec_equal(&inode->i_ctime, &now))
+               return;
+
+       inode->i_ctime = CURRENT_TIME_SEC;
+       mark_inode_dirty(inode);
+}
+
+static int lookup_and_delete_xattr(struct inode *inode, const char *name)
+{
+       int err = 0;
+       struct dentry *dentry, *xadir;
+
+       xadir = open_xa_dir(inode, XATTR_REPLACE);
+       if (IS_ERR(xadir))
+               return PTR_ERR(xadir);
+
+       dentry = lookup_one_len(name, xadir, strlen(name));
+       if (IS_ERR(dentry)) {
+               err = PTR_ERR(dentry);
+               goto out_dput;
+       }
+
+       if (dentry->d_inode) {
+               mutex_lock_nested(&xadir->d_inode->i_mutex, I_MUTEX_XATTR);
+               err = xattr_unlink(xadir->d_inode, dentry);
+               mutex_unlock(&xadir->d_inode->i_mutex);
+               update_ctime(inode);
+       }
+
+       dput(dentry);
+out_dput:
+       dput(xadir);
+       return err;
+}
+
 
 /* Generic extended attribute operations that can be used by xa plugins */
 
@@ -412,58 +461,32 @@ int reiserfs_prepare_write(struct file *f, struct page *page,
  * inode->i_mutex: down
  */
 int
-reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer,
-                  size_t buffer_size, int flags)
+reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th,
+                         struct inode *inode, const char *name,
+                         const void *buffer, size_t buffer_size, int flags)
 {
        int err = 0;
        struct dentry *dentry;
        struct page *page;
        char *data;
-       struct address_space *mapping;
        size_t file_pos = 0;
        size_t buffer_pos = 0;
-       struct inode *xinode;
-       struct iattr newattrs;
+       size_t new_size;
        __u32 xahash = 0;
 
        if (get_inode_sd_version(inode) == STAT_DATA_V1)
                return -EOPNOTSUPP;
 
-       /* Empty xattrs are ok, they're just empty files, no hash */
-       if (buffer && buffer_size)
-               xahash = xattr_hash(buffer, buffer_size);
+       if (!buffer)
+               return lookup_and_delete_xattr(inode, name);
 
-      open_file:
-       dentry = get_xa_file_dentry(inode, name, flags);
-       if (IS_ERR(dentry)) {
-               err = PTR_ERR(dentry);
-               goto out;
-       }
-
-       xinode = dentry->d_inode;
-       REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
+       dentry = xattr_lookup(inode, name, flags);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
 
-       /* we need to copy it off.. */
-       if (xinode->i_nlink > 1) {
-               dput(dentry);
-               err = reiserfs_xattr_del(inode, name);
-               if (err < 0)
-                       goto out;
-               /* We just killed the old one, we're not replacing anymore */
-               if (flags & XATTR_REPLACE)
-                       flags &= ~XATTR_REPLACE;
-               goto open_file;
-       }
+       down_write(&REISERFS_I(inode)->i_xattr_sem);
 
-       /* Resize it so we're ok to write there */
-       newattrs.ia_size = buffer_size;
-       newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
-       mutex_lock_nested(&xinode->i_mutex, I_MUTEX_XATTR);
-       err = notify_change(dentry, &newattrs);
-       if (err)
-               goto out_filp;
-
-       mapping = xinode->i_mapping;
+       xahash = xattr_hash(buffer, buffer_size);
        while (buffer_pos < buffer_size || buffer_pos == 0) {
                size_t chunk;
                size_t skip = 0;
@@ -473,10 +496,10 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer,
                else
                        chunk = buffer_size - buffer_pos;
 
-               page = reiserfs_get_page(xinode, file_pos >> PAGE_CACHE_SHIFT);
+               page = reiserfs_get_page(dentry->d_inode, file_pos);
                if (IS_ERR(page)) {
                        err = PTR_ERR(page);
-                       goto out_filp;
+                       goto out_unlock;
                }
 
                lock_page(page);
@@ -510,28 +533,61 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer,
                        break;
        }
 
-       /* We can't mark the inode dirty if it's not hashed. This is the case
-        * when we're inheriting the default ACL. If we dirty it, the inode
-        * gets marked dirty, but won't (ever) make it onto the dirty list until
-        * it's synced explicitly to clear I_DIRTY. This is bad. */
-       if (!hlist_unhashed(&inode->i_hash)) {
-               inode->i_ctime = CURRENT_TIME_SEC;
-               mark_inode_dirty(inode);
+       new_size = buffer_size + sizeof(struct reiserfs_xattr_header);
+       if (!err && new_size < i_size_read(dentry->d_inode)) {
+               struct iattr newattrs = {
+                       .ia_ctime = current_fs_time(inode->i_sb),
+                       .ia_size = buffer_size,
+                       .ia_valid = ATTR_SIZE | ATTR_CTIME,
+               };
+               mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_XATTR);
+               down_write(&dentry->d_inode->i_alloc_sem);
+               err = reiserfs_setattr(dentry, &newattrs);
+               up_write(&dentry->d_inode->i_alloc_sem);
+               mutex_unlock(&dentry->d_inode->i_mutex);
+       } else
+               update_ctime(inode);
+out_unlock:
+       up_write(&REISERFS_I(inode)->i_xattr_sem);
+       dput(dentry);
+       return err;
+}
+
+/* We need to start a transaction to maintain lock ordering */
+int reiserfs_xattr_set(struct inode *inode, const char *name,
+                      const void *buffer, size_t buffer_size, int flags)
+{
+
+       struct reiserfs_transaction_handle th;
+       int error, error2;
+       size_t jbegin_count = reiserfs_xattr_nblocks(inode, buffer_size);
+
+       if (!(flags & XATTR_REPLACE))
+               jbegin_count += reiserfs_xattr_jcreate_nblocks(inode);
+
+       reiserfs_write_lock(inode->i_sb);
+       error = journal_begin(&th, inode->i_sb, jbegin_count);
+       if (error) {
+               reiserfs_write_unlock(inode->i_sb);
+               return error;
        }
 
-      out_filp:
-       mutex_unlock(&xinode->i_mutex);
-       dput(dentry);
+       error = reiserfs_xattr_set_handle(&th, inode, name,
+                                         buffer, buffer_size, flags);
 
-      out:
-       return err;
+       error2 = journal_end(&th, inode->i_sb, jbegin_count);
+       if (error == 0)
+               error = error2;
+       reiserfs_write_unlock(inode->i_sb);
+
+       return error;
 }
 
 /*
  * inode->i_mutex: down
  */
 int
-reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer,
+reiserfs_xattr_get(struct inode *inode, const char *name, void *buffer,
                   size_t buffer_size)
 {
        ssize_t err = 0;
@@ -540,7 +596,6 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer,
        size_t file_pos = 0;
        size_t buffer_pos = 0;
        struct page *page;
-       struct inode *xinode;
        __u32 hash = 0;
 
        if (name == NULL)
@@ -551,25 +606,25 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer,
        if (get_inode_sd_version(inode) == STAT_DATA_V1)
                return -EOPNOTSUPP;
 
-       dentry = get_xa_file_dentry(inode, name, FL_READONLY);
+       dentry = xattr_lookup(inode, name, XATTR_REPLACE);
        if (IS_ERR(dentry)) {
                err = PTR_ERR(dentry);
                goto out;
        }
 
-       xinode = dentry->d_inode;
-       isize = xinode->i_size;
-       REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
+       down_read(&REISERFS_I(inode)->i_xattr_sem);
+
+       isize = i_size_read(dentry->d_inode);
 
        /* Just return the size needed */
        if (buffer == NULL) {
                err = isize - sizeof(struct reiserfs_xattr_header);
-               goto out_dput;
+               goto out_unlock;
        }
 
        if (buffer_size < isize - sizeof(struct reiserfs_xattr_header)) {
                err = -ERANGE;
-               goto out_dput;
+               goto out_unlock;
        }
 
        while (file_pos < isize) {
@@ -581,10 +636,10 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer,
                else
                        chunk = isize - file_pos;
 
-               page = reiserfs_get_page(xinode, file_pos >> PAGE_CACHE_SHIFT);
+               page = reiserfs_get_page(dentry->d_inode, file_pos);
                if (IS_ERR(page)) {
                        err = PTR_ERR(page);
-                       goto out_dput;
+                       goto out_unlock;
                }
 
                lock_page(page);
@@ -598,12 +653,12 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer,
                        if (rxh->h_magic != cpu_to_le32(REISERFS_XATTR_MAGIC)) {
                                unlock_page(page);
                                reiserfs_put_page(page);
-                               reiserfs_warning(inode->i_sb,
+                               reiserfs_warning(inode->i_sb, "jdm-20001",
                                                 "Invalid magic for xattr (%s) "
                                                 "associated with %k", name,
                                                 INODE_PKEY(inode));
                                err = -EIO;
-                               goto out_dput;
+                               goto out_unlock;
                        }
                        hash = le32_to_cpu(rxh->h_hash);
                }
@@ -618,256 +673,83 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer,
 
        if (xattr_hash(buffer, isize - sizeof(struct reiserfs_xattr_header)) !=
            hash) {
-               reiserfs_warning(inode->i_sb,
+               reiserfs_warning(inode->i_sb, "jdm-20002",
                                 "Invalid hash for xattr (%s) associated "
                                 "with %k", name, INODE_PKEY(inode));
                err = -EIO;
        }
 
-      out_dput:
+out_unlock:
+       up_read(&REISERFS_I(inode)->i_xattr_sem);
        dput(dentry);
 
-      out:
+out:
        return err;
 }
 
-static int
-__reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen)
-{
-       struct dentry *dentry;
-       struct inode *dir = xadir->d_inode;
-       int err = 0;
-
-       dentry = lookup_one_len(name, xadir, namelen);
-       if (IS_ERR(dentry)) {
-               err = PTR_ERR(dentry);
-               goto out;
-       } else if (!dentry->d_inode) {
-               err = -ENODATA;
-               goto out_file;
-       }
-
-       /* Skip directories.. */
-       if (S_ISDIR(dentry->d_inode->i_mode))
-               goto out_file;
-
-       if (!is_reiserfs_priv_object(dentry->d_inode)) {
-               reiserfs_warning(dir->i_sb, "OID %08x [%.*s/%.*s] doesn't have "
-                                "priv flag set [parent is %sset].",
-                                le32_to_cpu(INODE_PKEY(dentry->d_inode)->
-                                            k_objectid), xadir->d_name.len,
-                                xadir->d_name.name, namelen, name,
-                                is_reiserfs_priv_object(xadir->
-                                                        d_inode) ? "" :
-                                "not ");
-               dput(dentry);
-               return -EIO;
-       }
-
-       err = dir->i_op->unlink(dir, dentry);
-       if (!err)
-               d_delete(dentry);
-
-      out_file:
-       dput(dentry);
-
-      out:
-       return err;
-}
-
-int reiserfs_xattr_del(struct inode *inode, const char *name)
-{
-       struct dentry *dir;
-       int err;
-
-       dir = open_xa_dir(inode, FL_READONLY);
-       if (IS_ERR(dir)) {
-               err = PTR_ERR(dir);
-               goto out;
-       }
-
-       err = __reiserfs_xattr_del(dir, name, strlen(name));
-       dput(dir);
-
-       if (!err) {
-               inode->i_ctime = CURRENT_TIME_SEC;
-               mark_inode_dirty(inode);
-       }
-
-      out:
-       return err;
-}
-
-/* The following are side effects of other operations that aren't explicitly
- * modifying extended attributes. This includes operations such as permissions
- * or ownership changes, object deletions, etc. */
-
-static int
-reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen,
-                             loff_t offset, u64 ino, unsigned int d_type)
-{
-       struct dentry *xadir = (struct dentry *)buf;
-
-       return __reiserfs_xattr_del(xadir, name, namelen);
-
-}
-
-/* This is called w/ inode->i_mutex downed */
-int reiserfs_delete_xattrs(struct inode *inode)
-{
-       struct dentry *dir, *root;
-       int err = 0;
-
-       /* Skip out, an xattr has no xattrs associated with it */
-       if (is_reiserfs_priv_object(inode) ||
-           get_inode_sd_version(inode) == STAT_DATA_V1 ||
-           !reiserfs_xattrs(inode->i_sb)) {
-               return 0;
-       }
-       reiserfs_read_lock_xattrs(inode->i_sb);
-       dir = open_xa_dir(inode, FL_READONLY);
-       reiserfs_read_unlock_xattrs(inode->i_sb);
-       if (IS_ERR(dir)) {
-               err = PTR_ERR(dir);
-               goto out;
-       } else if (!dir->d_inode) {
-               dput(dir);
-               return 0;
-       }
-
-       lock_kernel();
-       err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir);
-       if (err) {
-               unlock_kernel();
-               goto out_dir;
-       }
-
-       /* Leftovers besides . and .. -- that's not good. */
-       if (dir->d_inode->i_nlink <= 2) {
-               root = get_xa_root(inode->i_sb, XATTR_REPLACE);
-               reiserfs_write_lock_xattrs(inode->i_sb);
-               err = vfs_rmdir(root->d_inode, dir);
-               reiserfs_write_unlock_xattrs(inode->i_sb);
-               dput(root);
-       } else {
-               reiserfs_warning(inode->i_sb,
-                                "Couldn't remove all entries in directory");
-       }
-       unlock_kernel();
-
-      out_dir:
-       dput(dir);
-
-      out:
-       if (!err)
-               REISERFS_I(inode)->i_flags =
-                   REISERFS_I(inode)->i_flags & ~i_has_xattr_dir;
-       return err;
-}
-
-struct reiserfs_chown_buf {
-       struct inode *inode;
-       struct dentry *xadir;
-       struct iattr *attrs;
+/* Actual operations that are exported to VFS-land */
+struct xattr_handler *reiserfs_xattr_handlers[] = {
+       &reiserfs_xattr_user_handler,
+       &reiserfs_xattr_trusted_handler,
+#ifdef CONFIG_REISERFS_FS_SECURITY
+       &reiserfs_xattr_security_handler,
+#endif
+#ifdef CONFIG_REISERFS_FS_POSIX_ACL
+       &reiserfs_posix_acl_access_handler,
+       &reiserfs_posix_acl_default_handler,
+#endif
+       NULL
 };
 
-/* XXX: If there is a better way to do this, I'd love to hear about it */
-static int
-reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen,
-                            loff_t offset, u64 ino, unsigned int d_type)
-{
-       struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf;
-       struct dentry *xafile, *xadir = chown_buf->xadir;
-       struct iattr *attrs = chown_buf->attrs;
-       int err = 0;
-
-       xafile = lookup_one_len(name, xadir, namelen);
-       if (IS_ERR(xafile))
-               return PTR_ERR(xafile);
-       else if (!xafile->d_inode) {
-               dput(xafile);
-               return -ENODATA;
-       }
-
-       if (!S_ISDIR(xafile->d_inode->i_mode))
-               err = notify_change(xafile, attrs);
-       dput(xafile);
-
-       return err;
-}
+/*
+ * In order to implement different sets of xattr operations for each xattr
+ * prefix with the generic xattr API, a filesystem should create a
+ * null-terminated array of struct xattr_handler (one for each prefix) and
+ * hang a pointer to it off of the s_xattr field of the superblock.
+ *
+ * The generic_fooxattr() functions will use this list to dispatch xattr
+ * operations to the correct xattr_handler.
+ */
+#define for_each_xattr_handler(handlers, handler)              \
+               for ((handler) = *(handlers)++;                 \
+                       (handler) != NULL;                      \
+                       (handler) = *(handlers)++)
 
-int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs)
+/* This is the implementation for the xattr plugin infrastructure */
+static inline struct xattr_handler *
+find_xattr_handler_prefix(struct xattr_handler **handlers,
+                          const char *name)
 {
-       struct dentry *dir;
-       int err = 0;
-       struct reiserfs_chown_buf buf;
-       unsigned int ia_valid = attrs->ia_valid;
+       struct xattr_handler *xah;
 
-       /* Skip out, an xattr has no xattrs associated with it */
-       if (is_reiserfs_priv_object(inode) ||
-           get_inode_sd_version(inode) == STAT_DATA_V1 ||
-           !reiserfs_xattrs(inode->i_sb)) {
-               return 0;
-       }
-       reiserfs_read_lock_xattrs(inode->i_sb);
-       dir = open_xa_dir(inode, FL_READONLY);
-       reiserfs_read_unlock_xattrs(inode->i_sb);
-       if (IS_ERR(dir)) {
-               if (PTR_ERR(dir) != -ENODATA)
-                       err = PTR_ERR(dir);
-               goto out;
-       } else if (!dir->d_inode) {
-               dput(dir);
-               goto out;
-       }
+       if (!handlers)
+               return NULL;
 
-       lock_kernel();
-
-       attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME);
-       buf.xadir = dir;
-       buf.attrs = attrs;
-       buf.inode = inode;
-
-       err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf);
-       if (err) {
-               unlock_kernel();
-               goto out_dir;
+       for_each_xattr_handler(handlers, xah) {
+               if (strncmp(xah->prefix, name, strlen(xah->prefix)) == 0)
+                       break;
        }
 
-       err = notify_change(dir, attrs);
-       unlock_kernel();
-
-      out_dir:
-       dput(dir);
-
-      out:
-       attrs->ia_valid = ia_valid;
-       return err;
+       return xah;
 }
 
-/* Actual operations that are exported to VFS-land */
 
 /*
  * Inode operation getxattr()
- * Preliminary locking: we down dentry->d_inode->i_mutex
  */
 ssize_t
 reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer,
                  size_t size)
 {
-       struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name);
-       int err;
+       struct inode *inode = dentry->d_inode;
+       struct xattr_handler *handler;
 
-       if (!xah || !reiserfs_xattrs(dentry->d_sb) ||
-           get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
+       handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name);
+
+       if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1)
                return -EOPNOTSUPP;
 
-       reiserfs_read_lock_xattr_i(dentry->d_inode);
-       reiserfs_read_lock_xattrs(dentry->d_sb);
-       err = xah->get(dentry->d_inode, name, buffer, size);
-       reiserfs_read_unlock_xattrs(dentry->d_sb);
-       reiserfs_read_unlock_xattr_i(dentry->d_inode);
-       return err;
+       return handler->get(inode, name, buffer, size);
 }
 
 /*
@@ -879,27 +761,15 @@ int
 reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
                  size_t size, int flags)
 {
-       struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name);
-       int err;
-       int lock;
+       struct inode *inode = dentry->d_inode;
+       struct xattr_handler *handler;
 
-       if (!xah || !reiserfs_xattrs(dentry->d_sb) ||
-           get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
+       handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name);
+
+       if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1)
                return -EOPNOTSUPP;
 
-       reiserfs_write_lock_xattr_i(dentry->d_inode);
-       lock = !has_xattr_dir(dentry->d_inode);
-       if (lock)
-               reiserfs_write_lock_xattrs(dentry->d_sb);
-       else
-               reiserfs_read_lock_xattrs(dentry->d_sb);
-       err = xah->set(dentry->d_inode, name, value, size, flags);
-       if (lock)
-               reiserfs_write_unlock_xattrs(dentry->d_sb);
-       else
-               reiserfs_read_unlock_xattrs(dentry->d_sb);
-       reiserfs_write_unlock_xattr_i(dentry->d_inode);
-       return err;
+       return handler->set(inode, name, value, size, flags);
 }
 
 /*
@@ -909,86 +779,66 @@ reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
  */
 int reiserfs_removexattr(struct dentry *dentry, const char *name)
 {
-       int err;
-       struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name);
+       struct inode *inode = dentry->d_inode;
+       struct xattr_handler *handler;
+       handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name);
 
-       if (!xah || !reiserfs_xattrs(dentry->d_sb) ||
-           get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
+       if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1)
                return -EOPNOTSUPP;
 
-       reiserfs_write_lock_xattr_i(dentry->d_inode);
-       reiserfs_read_lock_xattrs(dentry->d_sb);
-
-       /* Deletion pre-operation */
-       if (xah->del) {
-               err = xah->del(dentry->d_inode, name);
-               if (err)
-                       goto out;
-       }
-
-       err = reiserfs_xattr_del(dentry->d_inode, name);
-
-       dentry->d_inode->i_ctime = CURRENT_TIME_SEC;
-       mark_inode_dirty(dentry->d_inode);
-
-      out:
-       reiserfs_read_unlock_xattrs(dentry->d_sb);
-       reiserfs_write_unlock_xattr_i(dentry->d_inode);
-       return err;
+       return handler->set(inode, name, NULL, 0, XATTR_REPLACE);
 }
 
-/* This is what filldir will use:
- * r_pos will always contain the amount of space required for the entire
- * list. If r_pos becomes larger than r_size, we need more space and we
- * return an error indicating this. If r_pos is less than r_size, then we've
- * filled the buffer successfully and we return success */
-struct reiserfs_listxattr_buf {
-       int r_pos;
-       int r_size;
-       char *r_buf;
-       struct inode *r_inode;
+struct listxattr_buf {
+       size_t size;
+       size_t pos;
+       char *buf;
+       struct inode *inode;
 };
 
-static int
-reiserfs_listxattr_filler(void *buf, const char *name, int namelen,
-                         loff_t offset, u64 ino, unsigned int d_type)
+static int listxattr_filler(void *buf, const char *name, int namelen,
+                           loff_t offset, u64 ino, unsigned int d_type)
 {
-       struct reiserfs_listxattr_buf *b = (struct reiserfs_listxattr_buf *)buf;
-       int len = 0;
-       if (name[0] != '.'
-           || (namelen != 1 && (name[1] != '.' || namelen != 2))) {
-               struct reiserfs_xattr_handler *xah =
-                   find_xattr_handler_prefix(name);
-               if (!xah)
-                       return 0;       /* Unsupported xattr name, skip it */
-
-               /* We call ->list() twice because the operation isn't required to just
-                * return the name back - we want to make sure we have enough space */
-               len += xah->list(b->r_inode, name, namelen, NULL);
-
-               if (len) {
-                       if (b->r_pos + len + 1 <= b->r_size) {
-                               char *p = b->r_buf + b->r_pos;
-                               p += xah->list(b->r_inode, name, namelen, p);
-                               *p++ = '\0';
-                       }
-                       b->r_pos += len + 1;
+       struct listxattr_buf *b = (struct listxattr_buf *)buf;
+       size_t size;
+       if (name[0] != '.' ||
+           (namelen != 1 && (name[1] != '.' || namelen != 2))) {
+               struct xattr_handler *handler;
+               handler = find_xattr_handler_prefix(b->inode->i_sb->s_xattr,
+                                                   name);
+               if (!handler)   /* Unsupported xattr name */
+                       return 0;
+               if (b->buf) {
+                       size = handler->list(b->inode, b->buf + b->pos,
+                                        b->size, name, namelen);
+                       if (size > b->size)
+                               return -ERANGE;
+               } else {
+                       size = handler->list(b->inode, NULL, 0, name, namelen);
                }
-       }
 
+               b->pos += size;
+       }
        return 0;
 }
 
 /*
  * Inode operation listxattr()
  *
- * Preliminary locking: we down dentry->d_inode->i_mutex
+ * We totally ignore the generic listxattr here because it would be stupid
+ * not to. Since the xattrs are organized in a directory, we can just
+ * readdir to find them.
  */
 ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
 {
        struct dentry *dir;
        int err = 0;
-       struct reiserfs_listxattr_buf buf;
+       loff_t pos = 0;
+       struct listxattr_buf buf = {
+               .inode = dentry->d_inode,
+               .buf = buffer,
+               .size = buffer ? size : 0,
+       };
 
        if (!dentry->d_inode)
                return -EINVAL;
@@ -997,130 +847,104 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
            get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
                return -EOPNOTSUPP;
 
-       reiserfs_read_lock_xattr_i(dentry->d_inode);
-       reiserfs_read_lock_xattrs(dentry->d_sb);
-       dir = open_xa_dir(dentry->d_inode, FL_READONLY);
-       reiserfs_read_unlock_xattrs(dentry->d_sb);
+       dir = open_xa_dir(dentry->d_inode, XATTR_REPLACE);
        if (IS_ERR(dir)) {
                err = PTR_ERR(dir);
                if (err == -ENODATA)
-                       err = 0;        /* Not an error if there aren't any xattrs */
+                       err = 0;  /* Not an error if there aren't any xattrs */
                goto out;
        }
 
-       buf.r_buf = buffer;
-       buf.r_size = buffer ? size : 0;
-       buf.r_pos = 0;
-       buf.r_inode = dentry->d_inode;
+       mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR);
+       err = reiserfs_readdir_dentry(dir, &buf, listxattr_filler, &pos);
+       mutex_unlock(&dir->d_inode->i_mutex);
 
-       REISERFS_I(dentry->d_inode)->i_flags |= i_has_xattr_dir;
-
-       err = xattr_readdir(dir->d_inode, reiserfs_listxattr_filler, &buf);
-       if (err)
-               goto out_dir;
-
-       if (buf.r_pos > buf.r_size && buffer != NULL)
-               err = -ERANGE;
-       else
-               err = buf.r_pos;
+       if (!err)
+               err = buf.pos;
 
-      out_dir:
        dput(dir);
-
-      out:
-       reiserfs_read_unlock_xattr_i(dentry->d_inode);
+out:
        return err;
 }
 
-/* This is the implementation for the xattr plugin infrastructure */
-static LIST_HEAD(xattr_handlers);
-static DEFINE_RWLOCK(handler_lock);
-
-static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char
-                                                               *prefix)
+static int reiserfs_check_acl(struct inode *inode, int mask)
 {
-       struct reiserfs_xattr_handler *xah = NULL;
-       struct list_head *p;
+       struct posix_acl *acl;
+       int error = -EAGAIN; /* do regular unix permission checks by default */
 
-       read_lock(&handler_lock);
-       list_for_each(p, &xattr_handlers) {
-               xah = list_entry(p, struct reiserfs_xattr_handler, handlers);
-               if (strncmp(xah->prefix, prefix, strlen(xah->prefix)) == 0)
-                       break;
-               xah = NULL;
+       acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
+
+       if (acl) {
+               if (!IS_ERR(acl)) {
+                       error = posix_acl_permission(inode, acl, mask);
+                       posix_acl_release(acl);
+               } else if (PTR_ERR(acl) != -ENODATA)
+                       error = PTR_ERR(acl);
        }
 
-       read_unlock(&handler_lock);
-       return xah;
+       return error;
 }
 
-static void __unregister_handlers(void)
+int reiserfs_permission(struct inode *inode, int mask)
 {
-       struct reiserfs_xattr_handler *xah;
-       struct list_head *p, *tmp;
-
-       list_for_each_safe(p, tmp, &xattr_handlers) {
-               xah = list_entry(p, struct reiserfs_xattr_handler, handlers);
-               if (xah->exit)
-                       xah->exit();
-
-               list_del_init(p);
-       }
-       INIT_LIST_HEAD(&xattr_handlers);
+       /*
+        * We don't do permission checks on the internal objects.
+        * Permissions are determined by the "owning" object.
+        */
+       if (IS_PRIVATE(inode))
+               return 0;
+       /*
+        * Stat data v1 doesn't support ACLs.
+        */
+       if (get_inode_sd_version(inode) == STAT_DATA_V1)
+               return generic_permission(inode, mask, NULL);
+       else
+               return generic_permission(inode, mask, reiserfs_check_acl);
 }
 
-int __init reiserfs_xattr_register_handlers(void)
+static int create_privroot(struct dentry *dentry)
 {
-       int err = 0;
-       struct reiserfs_xattr_handler *xah;
-       struct list_head *p;
-
-       write_lock(&handler_lock);
-
-       /* If we're already initialized, nothing to do */
-       if (!list_empty(&xattr_handlers)) {
-               write_unlock(&handler_lock);
-               return 0;
-       }
-
-       /* Add the handlers */
-       list_add_tail(&user_handler.handlers, &xattr_handlers);
-       list_add_tail(&trusted_handler.handlers, &xattr_handlers);
-#ifdef CONFIG_REISERFS_FS_SECURITY
-       list_add_tail(&security_handler.handlers, &xattr_handlers);
-#endif
-#ifdef CONFIG_REISERFS_FS_POSIX_ACL
-       list_add_tail(&posix_acl_access_handler.handlers, &xattr_handlers);
-       list_add_tail(&posix_acl_default_handler.handlers, &xattr_handlers);
-#endif
-
-       /* Run initializers, if available */
-       list_for_each(p, &xattr_handlers) {
-               xah = list_entry(p, struct reiserfs_xattr_handler, handlers);
-               if (xah->init) {
-                       err = xah->init();
-                       if (err) {
-                               list_del_init(p);
-                               break;
-                       }
-               }
+       int err;
+       struct inode *inode = dentry->d_parent->d_inode;
+       mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR);
+       err = xattr_mkdir(inode, dentry, 0700);
+       mutex_unlock(&inode->i_mutex);
+       if (err) {
+               dput(dentry);
+               dentry = NULL;
        }
 
-       /* Clean up other handlers, if any failed */
-       if (err)
-               __unregister_handlers();
+       if (dentry && dentry->d_inode)
+               reiserfs_info(dentry->d_sb, "Created %s - reserved for xattr "
+                             "storage.\n", PRIVROOT_NAME);
 
-       write_unlock(&handler_lock);
        return err;
 }
 
-void reiserfs_xattr_unregister_handlers(void)
+static int xattr_mount_check(struct super_block *s)
 {
-       write_lock(&handler_lock);
-       __unregister_handlers();
-       write_unlock(&handler_lock);
+       /* We need generation numbers to ensure that the oid mapping is correct
+        * v3.5 filesystems don't have them. */
+       if (old_format_only(s)) {
+               if (reiserfs_xattrs_optional(s)) {
+                       /* Old format filesystem, but optional xattrs have
+                        * been enabled. Error out. */
+                       reiserfs_warning(s, "jdm-2005",
+                                        "xattrs/ACLs not supported "
+                                        "on pre-v3.6 format filesystems. "
+                                        "Failing mount.");
+                       return -EOPNOTSUPP;
+               }
+       }
+
+       return 0;
 }
 
+#else
+int __init reiserfs_xattr_register_handlers(void) { return 0; }
+void reiserfs_xattr_unregister_handlers(void) {}
+#endif
+
 /* This will catch lookups from the fs root to .reiserfs_priv */
 static int
 xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name)
@@ -1147,48 +971,23 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
 {
        int err = 0;
 
-       /* We need generation numbers to ensure that the oid mapping is correct
-        * v3.5 filesystems don't have them. */
-       if (!old_format_only(s)) {
-               set_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
-       } else if (reiserfs_xattrs_optional(s)) {
-               /* Old format filesystem, but optional xattrs have been enabled
-                * at mount time. Error out. */
-               reiserfs_warning(s, "xattrs/ACLs not supported on pre v3.6 "
-                                "format filesystem. Failing mount.");
-               err = -EOPNOTSUPP;
+#ifdef CONFIG_REISERFS_FS_XATTR
+       err = xattr_mount_check(s);
+       if (err)
                goto error;
-       } else {
-               /* Old format filesystem, but no optional xattrs have been enabled. This
-                * means we silently disable xattrs on the filesystem. */
-               clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
-       }
+#endif
 
        /* If we don't have the privroot located yet - go find it */
-       if (reiserfs_xattrs(s) && !REISERFS_SB(s)->priv_root) {
+       if (!REISERFS_SB(s)->priv_root) {
                struct dentry *dentry;
                dentry = lookup_one_len(PRIVROOT_NAME, s->s_root,
                                        strlen(PRIVROOT_NAME));
                if (!IS_ERR(dentry)) {
-                       if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) {
-                               struct inode *inode = dentry->d_parent->d_inode;
-                               mutex_lock_nested(&inode->i_mutex,
-                                                 I_MUTEX_XATTR);
-                               err = inode->i_op->mkdir(inode, dentry, 0700);
-                               mutex_unlock(&inode->i_mutex);
-                               if (err) {
-                                       dput(dentry);
-                                       dentry = NULL;
-                               }
-
-                               if (dentry && dentry->d_inode)
-                                       reiserfs_warning(s,
-                                                        "Created %s on %s - reserved for "
-                                                        "xattr storage.",
-                                                        PRIVROOT_NAME,
-                                                        reiserfs_bdevname
-                                                        (inode->i_sb));
-                       } else if (!dentry->d_inode) {
+#ifdef CONFIG_REISERFS_FS_XATTR
+                       if (!(mount_flags & MS_RDONLY) && !dentry->d_inode)
+                               err = create_privroot(dentry);
+#endif
+                       if (!dentry->d_inode) {
                                dput(dentry);
                                dentry = NULL;
                        }
@@ -1197,73 +996,41 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
 
                if (!err && dentry) {
                        s->s_root->d_op = &xattr_lookup_poison_ops;
-                       reiserfs_mark_inode_private(dentry->d_inode);
+                       dentry->d_inode->i_flags |= S_PRIVATE;
                        REISERFS_SB(s)->priv_root = dentry;
-               } else if (!(mount_flags & MS_RDONLY)) {        /* xattrs are unavailable */
-                       /* If we're read-only it just means that the dir hasn't been
-                        * created. Not an error -- just no xattrs on the fs. We'll
-                        * check again if we go read-write */
-                       reiserfs_warning(s, "xattrs/ACLs enabled and couldn't "
-                                        "find/create .reiserfs_priv. Failing mount.");
+#ifdef CONFIG_REISERFS_FS_XATTR
+               /* xattrs are unavailable */
+               } else if (!(mount_flags & MS_RDONLY)) {
+                       /* If we're read-only it just means that the dir
+                        * hasn't been created. Not an error -- just no
+                        * xattrs on the fs. We'll check again if we
+                        * go read-write */
+                       reiserfs_warning(s, "jdm-20006",
+                                        "xattrs/ACLs enabled and couldn't "
+                                        "find/create .reiserfs_priv. "
+                                        "Failing mount.");
                        err = -EOPNOTSUPP;
+#endif
                }
        }
 
-      error:
-       /* This is only nonzero if there was an error initializing the xattr
-        * directory or if there is a condition where we don't support them. */
+#ifdef CONFIG_REISERFS_FS_XATTR
+       if (!err)
+               s->s_xattr = reiserfs_xattr_handlers;
+
+error:
        if (err) {
-               clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
                clear_bit(REISERFS_XATTRS_USER, &(REISERFS_SB(s)->s_mount_opt));
                clear_bit(REISERFS_POSIXACL, &(REISERFS_SB(s)->s_mount_opt));
        }
+#endif
 
        /* The super_block MS_POSIXACL must mirror the (no)acl mount option. */
        s->s_flags = s->s_flags & ~MS_POSIXACL;
+#ifdef CONFIG_REISERFS_FS_POSIX_ACL
        if (reiserfs_posixacl(s))
                s->s_flags |= MS_POSIXACL;
+#endif
 
        return err;
 }
-
-static int reiserfs_check_acl(struct inode *inode, int mask)
-{
-       struct posix_acl *acl;
-       int error = -EAGAIN; /* do regular unix permission checks by default */
-
-       reiserfs_read_lock_xattr_i(inode);
-       reiserfs_read_lock_xattrs(inode->i_sb);
-
-       acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
-
-       reiserfs_read_unlock_xattrs(inode->i_sb);
-       reiserfs_read_unlock_xattr_i(inode);
-
-       if (acl) {
-               if (!IS_ERR(acl)) {
-                       error = posix_acl_permission(inode, acl, mask);
-                       posix_acl_release(acl);
-               } else if (PTR_ERR(acl) != -ENODATA)
-                       error = PTR_ERR(acl);
-       }
-
-       return error;
-}
-
-int reiserfs_permission(struct inode *inode, int mask)
-{
-       /*
-        * We don't do permission checks on the internal objects.
-        * Permissions are determined by the "owning" object.
-        */
-       if (is_reiserfs_priv_object(inode))
-               return 0;
-
-       /*
-        * Stat data v1 doesn't support ACLs.
-        */
-       if (get_inode_sd_version(inode) == STAT_DATA_V1)
-               return generic_permission(inode, mask, NULL);
-       else
-               return generic_permission(inode, mask, reiserfs_check_acl);
-}
index b7e4fa4539deeb9155e97affef199cbacb729f70..d423416d93d14a90e894331b574f238b45055d78 100644 (file)
 #include <linux/reiserfs_acl.h>
 #include <asm/uaccess.h>
 
-static int reiserfs_set_acl(struct inode *inode, int type,
+static int reiserfs_set_acl(struct reiserfs_transaction_handle *th,
+                           struct inode *inode, int type,
                            struct posix_acl *acl);
 
 static int
 xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
 {
        struct posix_acl *acl;
-       int error;
-
+       int error, error2;
+       struct reiserfs_transaction_handle th;
+       size_t jcreate_blocks;
        if (!reiserfs_posixacl(inode->i_sb))
                return -EOPNOTSUPP;
        if (!is_owner_or_cap(inode))
@@ -36,7 +38,21 @@ xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
        } else
                acl = NULL;
 
-       error = reiserfs_set_acl(inode, type, acl);
+       /* Pessimism: We can't assume that anything from the xattr root up
+        * has been created. */
+
+       jcreate_blocks = reiserfs_xattr_jcreate_nblocks(inode) +
+                        reiserfs_xattr_nblocks(inode, size) * 2;
+
+       reiserfs_write_lock(inode->i_sb);
+       error = journal_begin(&th, inode->i_sb, jcreate_blocks);
+       if (error == 0) {
+               error = reiserfs_set_acl(&th, inode, type, acl);
+               error2 = journal_end(&th, inode->i_sb, jcreate_blocks);
+               if (error2)
+                       error = error2;
+       }
+       reiserfs_write_unlock(inode->i_sb);
 
       release_and_out:
        posix_acl_release(acl);
@@ -172,6 +188,29 @@ static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size)
        return ERR_PTR(-EINVAL);
 }
 
+static inline void iset_acl(struct inode *inode, struct posix_acl **i_acl,
+                           struct posix_acl *acl)
+{
+       spin_lock(&inode->i_lock);
+       if (*i_acl != ERR_PTR(-ENODATA))
+               posix_acl_release(*i_acl);
+       *i_acl = posix_acl_dup(acl);
+       spin_unlock(&inode->i_lock);
+}
+
+static inline struct posix_acl *iget_acl(struct inode *inode,
+                                        struct posix_acl **i_acl)
+{
+       struct posix_acl *acl = ERR_PTR(-ENODATA);
+
+       spin_lock(&inode->i_lock);
+       if (*i_acl != ERR_PTR(-ENODATA))
+               acl = posix_acl_dup(*i_acl);
+       spin_unlock(&inode->i_lock);
+
+       return acl;
+}
+
 /*
  * Inode operation get_posix_acl().
  *
@@ -199,11 +238,11 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
                return ERR_PTR(-EINVAL);
        }
 
-       if (IS_ERR(*p_acl)) {
-               if (PTR_ERR(*p_acl) == -ENODATA)
-                       return NULL;
-       } else if (*p_acl != NULL)
-               return posix_acl_dup(*p_acl);
+       acl = iget_acl(inode, p_acl);
+       if (acl && !IS_ERR(acl))
+               return acl;
+       else if (PTR_ERR(acl) == -ENODATA)
+               return NULL;
 
        size = reiserfs_xattr_get(inode, name, NULL, 0);
        if (size < 0) {
@@ -229,7 +268,7 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
        } else {
                acl = posix_acl_from_disk(value, retval);
                if (!IS_ERR(acl))
-                       *p_acl = posix_acl_dup(acl);
+                       iset_acl(inode, p_acl, acl);
        }
 
        kfree(value);
@@ -243,12 +282,13 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
  * BKL held [before 2.5.x]
  */
 static int
-reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
+reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
+                int type, struct posix_acl *acl)
 {
        char *name;
        void *value = NULL;
        struct posix_acl **p_acl;
-       size_t size;
+       size_t size = 0;
        int error;
        struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
 
@@ -285,31 +325,28 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
                value = posix_acl_to_disk(acl, &size);
                if (IS_ERR(value))
                        return (int)PTR_ERR(value);
-               error = reiserfs_xattr_set(inode, name, value, size, 0);
-       } else {
-               error = reiserfs_xattr_del(inode, name);
-               if (error == -ENODATA) {
-                       /* This may seem odd here, but it means that the ACL was set
-                        * with a value representable with mode bits. If there was
-                        * an ACL before, reiserfs_xattr_del already dirtied the inode.
-                        */
+       }
+
+       error = reiserfs_xattr_set_handle(th, inode, name, value, size, 0);
+
+       /*
+        * Ensure that the inode gets dirtied if we're only using
+        * the mode bits and an old ACL didn't exist. We don't need
+        * to check if the inode is hashed here since we won't get
+        * called by reiserfs_inherit_default_acl().
+        */
+       if (error == -ENODATA) {
+               error = 0;
+               if (type == ACL_TYPE_ACCESS) {
+                       inode->i_ctime = CURRENT_TIME_SEC;
                        mark_inode_dirty(inode);
-                       error = 0;
                }
        }
 
        kfree(value);
 
-       if (!error) {
-               /* Release the old one */
-               if (!IS_ERR(*p_acl) && *p_acl)
-                       posix_acl_release(*p_acl);
-
-               if (acl == NULL)
-                       *p_acl = ERR_PTR(-ENODATA);
-               else
-                       *p_acl = posix_acl_dup(acl);
-       }
+       if (!error)
+               iset_acl(inode, p_acl, acl);
 
        return error;
 }
@@ -317,7 +354,8 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
 /* dir->i_mutex: locked,
  * inode is new and not released into the wild yet */
 int
-reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
+reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
+                            struct inode *dir, struct dentry *dentry,
                             struct inode *inode)
 {
        struct posix_acl *acl;
@@ -335,8 +373,8 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
        /* Don't apply ACLs to objects in the .reiserfs_priv tree.. This
         * would be useless since permissions are ignored, and a pain because
         * it introduces locking cycles */
-       if (is_reiserfs_priv_object(dir)) {
-               reiserfs_mark_inode_private(inode);
+       if (IS_PRIVATE(dir)) {
+               inode->i_flags |= S_PRIVATE;
                goto apply_umask;
        }
 
@@ -354,7 +392,8 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
 
                /* Copy the default ACL to the default ACL of a new directory */
                if (S_ISDIR(inode->i_mode)) {
-                       err = reiserfs_set_acl(inode, ACL_TYPE_DEFAULT, acl);
+                       err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,
+                                              acl);
                        if (err)
                                goto cleanup;
                }
@@ -375,9 +414,9 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
 
                        /* If we need an ACL.. */
                        if (need_acl > 0) {
-                               err =
-                                   reiserfs_set_acl(inode, ACL_TYPE_ACCESS,
-                                                    acl_copy);
+                               err = reiserfs_set_acl(th, inode,
+                                                      ACL_TYPE_ACCESS,
+                                                      acl_copy);
                                if (err)
                                        goto cleanup_copy;
                        }
@@ -395,25 +434,45 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
        return err;
 }
 
-/* Looks up and caches the result of the default ACL.
- * We do this so that we don't need to carry the xattr_sem into
- * reiserfs_new_inode if we don't need to */
+/* This is used to cache the default acl before a new object is created.
+ * The biggest reason for this is to get an idea of how many blocks will
+ * actually be required for the create operation if we must inherit an ACL.
+ * An ACL write can add up to 3 object creations and an additional file write
+ * so we'd prefer not to reserve that many blocks in the journal if we can.
+ * It also has the advantage of not loading the ACL with a transaction open,
+ * this may seem silly, but if the owner of the directory is doing the
+ * creation, the ACL may not be loaded since the permissions wouldn't require
+ * it.
+ * We return the number of blocks required for the transaction.
+ */
 int reiserfs_cache_default_acl(struct inode *inode)
 {
-       int ret = 0;
-       if (reiserfs_posixacl(inode->i_sb) && !is_reiserfs_priv_object(inode)) {
-               struct posix_acl *acl;
-               reiserfs_read_lock_xattr_i(inode);
-               reiserfs_read_lock_xattrs(inode->i_sb);
-               acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT);
-               reiserfs_read_unlock_xattrs(inode->i_sb);
-               reiserfs_read_unlock_xattr_i(inode);
-               ret = (acl && !IS_ERR(acl));
-               if (ret)
-                       posix_acl_release(acl);
+       struct posix_acl *acl;
+       int nblocks = 0;
+
+       if (IS_PRIVATE(inode))
+               return 0;
+
+       acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT);
+
+       if (acl && !IS_ERR(acl)) {
+               int size = reiserfs_acl_size(acl->a_count);
+
+               /* Other xattrs can be created during inode creation. We don't
+                * want to claim too many blocks, so we check to see if we
+                * we need to create the tree to the xattrs, and then we
+                * just want two files. */
+               nblocks = reiserfs_xattr_jcreate_nblocks(inode);
+               nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
+
+               REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
+
+               /* We need to account for writes + bitmaps for two files */
+               nblocks += reiserfs_xattr_nblocks(inode, size) * 4;
+               posix_acl_release(acl);
        }
 
-       return ret;
+       return nblocks;
 }
 
 int reiserfs_acl_chmod(struct inode *inode)
@@ -429,9 +488,7 @@ int reiserfs_acl_chmod(struct inode *inode)
                return 0;
        }
 
-       reiserfs_read_lock_xattrs(inode->i_sb);
        acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
-       reiserfs_read_unlock_xattrs(inode->i_sb);
        if (!acl)
                return 0;
        if (IS_ERR(acl))
@@ -442,18 +499,20 @@ int reiserfs_acl_chmod(struct inode *inode)
                return -ENOMEM;
        error = posix_acl_chmod_masq(clone, inode->i_mode);
        if (!error) {
-               int lock = !has_xattr_dir(inode);
-               reiserfs_write_lock_xattr_i(inode);
-               if (lock)
-                       reiserfs_write_lock_xattrs(inode->i_sb);
-               else
-                       reiserfs_read_lock_xattrs(inode->i_sb);
-               error = reiserfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
-               if (lock)
-                       reiserfs_write_unlock_xattrs(inode->i_sb);
-               else
-                       reiserfs_read_unlock_xattrs(inode->i_sb);
-               reiserfs_write_unlock_xattr_i(inode);
+               struct reiserfs_transaction_handle th;
+               size_t size = reiserfs_xattr_nblocks(inode,
+                                            reiserfs_acl_size(clone->a_count));
+               reiserfs_write_lock(inode->i_sb);
+               error = journal_begin(&th, inode->i_sb, size * 2);
+               if (!error) {
+                       int error2;
+                       error = reiserfs_set_acl(&th, inode, ACL_TYPE_ACCESS,
+                                                clone);
+                       error2 = journal_end(&th, inode->i_sb, size * 2);
+                       if (error2)
+                               error = error2;
+               }
+               reiserfs_write_unlock(inode->i_sb);
        }
        posix_acl_release(clone);
        return error;
@@ -477,38 +536,22 @@ posix_acl_access_set(struct inode *inode, const char *name,
        return xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
 }
 
-static int posix_acl_access_del(struct inode *inode, const char *name)
+static size_t posix_acl_access_list(struct inode *inode, char *list,
+                                   size_t list_size, const char *name,
+                                   size_t name_len)
 {
-       struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
-       struct posix_acl **acl = &reiserfs_i->i_acl_access;
-       if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
-               return -EINVAL;
-       if (!IS_ERR(*acl) && *acl) {
-               posix_acl_release(*acl);
-               *acl = ERR_PTR(-ENODATA);
-       }
-
-       return 0;
-}
-
-static int
-posix_acl_access_list(struct inode *inode, const char *name, int namelen,
-                     char *out)
-{
-       int len = namelen;
+       const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
        if (!reiserfs_posixacl(inode->i_sb))
                return 0;
-       if (out)
-               memcpy(out, name, len);
-
-       return len;
+       if (list && size <= list_size)
+               memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
+       return size;
 }
 
-struct reiserfs_xattr_handler posix_acl_access_handler = {
+struct xattr_handler reiserfs_posix_acl_access_handler = {
        .prefix = POSIX_ACL_XATTR_ACCESS,
        .get = posix_acl_access_get,
        .set = posix_acl_access_set,
-       .del = posix_acl_access_del,
        .list = posix_acl_access_list,
 };
 
@@ -530,37 +573,21 @@ posix_acl_default_set(struct inode *inode, const char *name,
        return xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
 }
 
-static int posix_acl_default_del(struct inode *inode, const char *name)
+static size_t posix_acl_default_list(struct inode *inode, char *list,
+                                    size_t list_size, const char *name,
+                                    size_t name_len)
 {
-       struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
-       struct posix_acl **acl = &reiserfs_i->i_acl_default;
-       if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
-               return -EINVAL;
-       if (!IS_ERR(*acl) && *acl) {
-               posix_acl_release(*acl);
-               *acl = ERR_PTR(-ENODATA);
-       }
-
-       return 0;
-}
-
-static int
-posix_acl_default_list(struct inode *inode, const char *name, int namelen,
-                      char *out)
-{
-       int len = namelen;
+       const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
        if (!reiserfs_posixacl(inode->i_sb))
                return 0;
-       if (out)
-               memcpy(out, name, len);
-
-       return len;
+       if (list && size <= list_size)
+               memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
+       return size;
 }
 
-struct reiserfs_xattr_handler posix_acl_default_handler = {
+struct xattr_handler reiserfs_posix_acl_default_handler = {
        .prefix = POSIX_ACL_XATTR_DEFAULT,
        .get = posix_acl_default_get,
        .set = posix_acl_default_set,
-       .del = posix_acl_default_del,
        .list = posix_acl_default_list,
 };
index 056008db13775ccf235b6b2b3822f66efe9fb825..4d3c20e787c39040badef94770ffdfdf1a77f70d 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/pagemap.h>
 #include <linux/xattr.h>
 #include <linux/reiserfs_xattr.h>
+#include <linux/security.h>
 #include <asm/uaccess.h>
 
 static int
@@ -12,7 +13,7 @@ security_get(struct inode *inode, const char *name, void *buffer, size_t size)
        if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
                return -EINVAL;
 
-       if (is_reiserfs_priv_object(inode))
+       if (IS_PRIVATE(inode))
                return -EPERM;
 
        return reiserfs_xattr_get(inode, name, buffer, size);
@@ -25,41 +26,84 @@ security_set(struct inode *inode, const char *name, const void *buffer,
        if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
                return -EINVAL;
 
-       if (is_reiserfs_priv_object(inode))
+       if (IS_PRIVATE(inode))
                return -EPERM;
 
        return reiserfs_xattr_set(inode, name, buffer, size, flags);
 }
 
-static int security_del(struct inode *inode, const char *name)
+static size_t security_list(struct inode *inode, char *list, size_t list_len,
+                           const char *name, size_t namelen)
 {
-       if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
-               return -EINVAL;
+       const size_t len = namelen + 1;
 
-       if (is_reiserfs_priv_object(inode))
-               return -EPERM;
+       if (IS_PRIVATE(inode))
+               return 0;
+
+       if (list && len <= list_len) {
+               memcpy(list, name, namelen);
+               list[namelen] = '\0';
+       }
 
-       return 0;
+       return len;
 }
 
-static int
-security_list(struct inode *inode, const char *name, int namelen, char *out)
+/* Initializes the security context for a new inode and returns the number
+ * of blocks needed for the transaction. If successful, reiserfs_security
+ * must be released using reiserfs_security_free when the caller is done. */
+int reiserfs_security_init(struct inode *dir, struct inode *inode,
+                          struct reiserfs_security_handle *sec)
 {
-       int len = namelen;
+       int blocks = 0;
+       int error = security_inode_init_security(inode, dir, &sec->name,
+                                                &sec->value, &sec->length);
+       if (error) {
+               if (error == -EOPNOTSUPP)
+                       error = 0;
 
-       if (is_reiserfs_priv_object(inode))
-               return 0;
+               sec->name = NULL;
+               sec->value = NULL;
+               sec->length = 0;
+               return error;
+       }
 
-       if (out)
-               memcpy(out, name, len);
+       if (sec->length) {
+               blocks = reiserfs_xattr_jcreate_nblocks(inode) +
+                        reiserfs_xattr_nblocks(inode, sec->length);
+               /* We don't want to count the directories twice if we have
+                * a default ACL. */
+               REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
+       }
+       return blocks;
+}
 
-       return len;
+int reiserfs_security_write(struct reiserfs_transaction_handle *th,
+                           struct inode *inode,
+                           struct reiserfs_security_handle *sec)
+{
+       int error;
+       if (strlen(sec->name) < sizeof(XATTR_SECURITY_PREFIX))
+               return -EINVAL;
+
+       error = reiserfs_xattr_set_handle(th, inode, sec->name, sec->value,
+                                         sec->length, XATTR_CREATE);
+       if (error == -ENODATA || error == -EOPNOTSUPP)
+               error = 0;
+
+       return error;
+}
+
+void reiserfs_security_free(struct reiserfs_security_handle *sec)
+{
+       kfree(sec->name);
+       kfree(sec->value);
+       sec->name = NULL;
+       sec->value = NULL;
 }
 
-struct reiserfs_xattr_handler security_handler = {
+struct xattr_handler reiserfs_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
        .get = security_get,
        .set = security_set,
-       .del = security_del,
        .list = security_list,
 };
index 60abe2bb1f980bbb11de6d2b161ea16946bc595a..a865042f75e2e2c0cbb46150e150e1b0911e31b0 100644 (file)
@@ -13,10 +13,7 @@ trusted_get(struct inode *inode, const char *name, void *buffer, size_t size)
        if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
                return -EINVAL;
 
-       if (!reiserfs_xattrs(inode->i_sb))
-               return -EOPNOTSUPP;
-
-       if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
+       if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode))
                return -EPERM;
 
        return reiserfs_xattr_get(inode, name, buffer, size);
@@ -29,50 +26,30 @@ trusted_set(struct inode *inode, const char *name, const void *buffer,
        if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
                return -EINVAL;
 
-       if (!reiserfs_xattrs(inode->i_sb))
-               return -EOPNOTSUPP;
-
-       if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
+       if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode))
                return -EPERM;
 
        return reiserfs_xattr_set(inode, name, buffer, size, flags);
 }
 
-static int trusted_del(struct inode *inode, const char *name)
+static size_t trusted_list(struct inode *inode, char *list, size_t list_size,
+                          const char *name, size_t name_len)
 {
-       if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
-               return -EINVAL;
+       const size_t len = name_len + 1;
 
-       if (!reiserfs_xattrs(inode->i_sb))
-               return -EOPNOTSUPP;
-
-       if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
-               return -EPERM;
-
-       return 0;
-}
-
-static int
-trusted_list(struct inode *inode, const char *name, int namelen, char *out)
-{
-       int len = namelen;
-
-       if (!reiserfs_xattrs(inode->i_sb))
+       if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode))
                return 0;
 
-       if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
-               return 0;
-
-       if (out)
-               memcpy(out, name, len);
-
+       if (list && len <= list_size) {
+               memcpy(list, name, name_len);
+               list[name_len] = '\0';
+       }
        return len;
 }
 
-struct reiserfs_xattr_handler trusted_handler = {
+struct xattr_handler reiserfs_xattr_trusted_handler = {
        .prefix = XATTR_TRUSTED_PREFIX,
        .get = trusted_get,
        .set = trusted_set,
-       .del = trusted_del,
        .list = trusted_list,
 };
index 1384efcb938e078d882587ee9e84e1de10090bb2..e3238dc4f3db941ebf3108d347402fbc9a8281df 100644 (file)
@@ -6,10 +6,6 @@
 #include <linux/reiserfs_xattr.h>
 #include <asm/uaccess.h>
 
-#ifdef CONFIG_REISERFS_FS_POSIX_ACL
-# include <linux/reiserfs_acl.h>
-#endif
-
 static int
 user_get(struct inode *inode, const char *name, void *buffer, size_t size)
 {
@@ -25,7 +21,6 @@ static int
 user_set(struct inode *inode, const char *name, const void *buffer,
         size_t size, int flags)
 {
-
        if (strlen(name) < sizeof(XATTR_USER_PREFIX))
                return -EINVAL;
 
@@ -34,33 +29,23 @@ user_set(struct inode *inode, const char *name, const void *buffer,
        return reiserfs_xattr_set(inode, name, buffer, size, flags);
 }
 
-static int user_del(struct inode *inode, const char *name)
+static size_t user_list(struct inode *inode, char *list, size_t list_size,
+                       const char *name, size_t name_len)
 {
-       if (strlen(name) < sizeof(XATTR_USER_PREFIX))
-               return -EINVAL;
-
-       if (!reiserfs_xattrs_user(inode->i_sb))
-               return -EOPNOTSUPP;
-       return 0;
-}
+       const size_t len = name_len + 1;
 
-static int
-user_list(struct inode *inode, const char *name, int namelen, char *out)
-{
-       int len = namelen;
        if (!reiserfs_xattrs_user(inode->i_sb))
                return 0;
-
-       if (out)
-               memcpy(out, name, len);
-
+       if (list && len <= list_size) {
+               memcpy(list, name, name_len);
+               list[name_len] = '\0';
+       }
        return len;
 }
 
-struct reiserfs_xattr_handler user_handler = {
+struct xattr_handler reiserfs_xattr_user_handler = {
        .prefix = XATTR_USER_PREFIX,
        .get = user_get,
        .set = user_set,
-       .del = user_del,
        .list = user_list,
 };
index a1a4cfe1921040d6044657e6c235e2f5d55f8292..7f40f30c55c5bdf31ecab91b9075b5d320e8ae0d 100644 (file)
@@ -513,7 +513,7 @@ int seq_bitmap(struct seq_file *m, const unsigned long *bits,
 }
 EXPORT_SYMBOL(seq_bitmap);
 
-int seq_bitmap_list(struct seq_file *m, unsigned long *bits,
+int seq_bitmap_list(struct seq_file *m, const unsigned long *bits,
                unsigned int nr_bits)
 {
        if (m->count < m->size) {
index 681ec0d83799cc22595f44aadad42ca5d63e0538..ffa6edcd2d0cd30822490df1b2d9ebcde4b44867 100644 (file)
@@ -301,6 +301,7 @@ failure:
 static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info;
+       u64 id = huge_encode_dev(dentry->d_sb->s_bdev->bd_dev);
 
        TRACE("Entered squashfs_statfs\n");
 
@@ -311,6 +312,8 @@ static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_files = msblk->inodes;
        buf->f_ffree = 0;
        buf->f_namelen = SQUASHFS_NAME_LEN;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
 
        return 0;
 }
index 07703d3ff4a1ebdb8729bfcbfd7d759a7afbc06a..93e0c0281d4511cc1319bcb0fdb2ed05eb1453a4 100644 (file)
@@ -234,7 +234,7 @@ static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        return ret;
 }
 
-static int bin_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+static int bin_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct file *file = vma->vm_file;
        struct bin_buffer *bb = file->private_data;
@@ -242,15 +242,15 @@ static int bin_page_mkwrite(struct vm_area_struct *vma, struct page *page)
        int ret;
 
        if (!bb->vm_ops)
-               return -EINVAL;
+               return VM_FAULT_SIGBUS;
 
        if (!bb->vm_ops->page_mkwrite)
                return 0;
 
        if (!sysfs_get_active_two(attr_sd))
-               return -EINVAL;
+               return VM_FAULT_SIGBUS;
 
-       ret = bb->vm_ops->page_mkwrite(vma, page);
+       ret = bb->vm_ops->page_mkwrite(vma, vmf);
 
        sysfs_put_active_two(attr_sd);
        return ret;
index 3d81bf58dae2d5ebef8f430914d3cc06d5bb9302..da20b48d350fdd674d3a7e6ec2fd64984473a20b 100644 (file)
@@ -90,6 +90,7 @@ static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
        struct sysv_sb_info *sbi = SYSV_SB(sb);
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type = sb->s_magic;
        buf->f_bsize = sb->s_blocksize;
@@ -98,6 +99,8 @@ static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_files = sbi->s_ninodes;
        buf->f_ffree = sysv_count_free_inodes(sb);
        buf->f_namelen = SYSV_NAMELEN;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        return 0;
 }
 
index 93b6de51f261727f2c5f4e62814a0e79d3b109b5..0ff89fe71e5103c3effe3dfd27dc2bac58b8bfc5 100644 (file)
@@ -1434,8 +1434,9 @@ static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags)
  * mmap()d file has taken write protection fault and is being made
  * writable. UBIFS must ensure page is budgeted for.
  */
-static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
+       struct page *page = vmf->page;
        struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
        struct ubifs_info *c = inode->i_sb->s_fs_info;
        struct timespec now = ubifs_current_time(inode);
@@ -1447,7 +1448,7 @@ static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
        ubifs_assert(!(inode->i_sb->s_flags & MS_RDONLY));
 
        if (unlikely(c->ro_media))
-               return -EROFS;
+               return VM_FAULT_SIGBUS; /* -EROFS */
 
        /*
         * We have not locked @page so far so we may budget for changing the
@@ -1480,7 +1481,7 @@ static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
                if (err == -ENOSPC)
                        ubifs_warn("out of space for mmapped file "
                                   "(inode number %lu)", inode->i_ino);
-               return err;
+               return VM_FAULT_SIGBUS;
        }
 
        lock_page(page);
@@ -1520,6 +1521,8 @@ static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
 out_unlock:
        unlock_page(page);
        ubifs_release_budget(c, &req);
+       if (err)
+               err = VM_FAULT_SIGBUS;
        return err;
 }
 
index e1c1fc5ee2395cca67ad36e10f0577fdef0f0651..60359291761f2eb2a8229f053b1d5763c19115c6 100644 (file)
@@ -1268,6 +1268,7 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf)
        struct ufs_super_block_first *usb1;
        struct ufs_super_block_second *usb2;
        struct ufs_super_block_third *usb3;
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        lock_kernel();
 
@@ -1290,6 +1291,8 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf)
                ? (buf->f_bfree - (((long)buf->f_blocks / 100) * uspi->s_minfree)) : 0;
        buf->f_files = uspi->s_ncg * uspi->s_ipg;
        buf->f_namelen = UFS_MAXNAMLEN;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
 
        unlock_kernel();
 
index e14c4e3aea0c331f67ba529946e201c6d814e8ce..f4e25544157422812b4a1e576d3539e86b75b9bd 100644 (file)
@@ -234,9 +234,9 @@ xfs_file_mmap(
 STATIC int
 xfs_vm_page_mkwrite(
        struct vm_area_struct   *vma,
-       struct page             *page)
+       struct vm_fault         *vmf)
 {
-       return block_page_mkwrite(vma, page, xfs_get_blocks);
+       return block_page_mkwrite(vma, vmf, xfs_get_blocks);
 }
 
 const struct file_operations xfs_file_operations = {
index 26cefcde5cee9abba5df2dc5627d4f38b4016f05..68e4677fb9e73f87bdb6194e2ad3dd24ca726606 100644 (file)
@@ -18,6 +18,7 @@
 #ifdef __KERNEL__
 
 #include <linux/init.h>
+#include <linux/highmem.h>
 #include <asm/mem-layout.h>
 #include <asm/spr-regs.h>
 #include <asm/mb-regs.h>
@@ -116,6 +117,7 @@ static inline void *kmap_atomic(struct page *page, enum km_type type)
        unsigned long paddr;
 
        pagefault_disable();
+       debug_kmap_atomic(type);
        paddr = page_to_phys(page);
 
        switch (type) {
diff --git a/include/asm-generic/dma-mapping.h b/include/asm-generic/dma-mapping.h
deleted file mode 100644 (file)
index 189486c..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-/* Copyright (C) 2002 by James.Bottomley@HansenPartnership.com 
- *
- * Implements the generic device dma API via the existing pci_ one
- * for unconverted architectures
- */
-
-#ifndef _ASM_GENERIC_DMA_MAPPING_H
-#define _ASM_GENERIC_DMA_MAPPING_H
-
-
-#ifdef CONFIG_PCI
-
-/* we implement the API below in terms of the existing PCI one,
- * so include it */
-#include <linux/pci.h>
-/* need struct page definitions */
-#include <linux/mm.h>
-
-static inline int
-dma_supported(struct device *dev, u64 mask)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       return pci_dma_supported(to_pci_dev(dev), mask);
-}
-
-static inline int
-dma_set_mask(struct device *dev, u64 dma_mask)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
-}
-
-static inline void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-                  gfp_t flag)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
-}
-
-static inline void
-dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-                   dma_addr_t dma_handle)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       pci_free_consistent(to_pci_dev(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)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction);
-}
-
-static inline void
-dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-                enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction);
-}
-
-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)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction);
-}
-
-static inline void
-dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-              enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction);
-}
-
-static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-          enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction);
-}
-
-static inline void
-dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-            enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction);
-}
-
-static inline void
-dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
-                       enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle,
-                                   size, (int)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)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle,
-                                      size, (int)direction);
-}
-
-static inline void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-                   enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction);
-}
-
-static inline void
-dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-                      enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction);
-}
-
-static inline int
-dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-       return pci_dma_mapping_error(to_pci_dev(dev), dma_addr);
-}
-
-
-#else
-
-static inline int
-dma_supported(struct device *dev, u64 mask)
-{
-       return 0;
-}
-
-static inline int
-dma_set_mask(struct device *dev, u64 dma_mask)
-{
-       BUG();
-       return 0;
-}
-
-static inline void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-                  gfp_t flag)
-{
-       BUG();
-       return NULL;
-}
-
-static inline void
-dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-                   dma_addr_t dma_handle)
-{
-       BUG();
-}
-
-static inline dma_addr_t
-dma_map_single(struct device *dev, void *cpu_addr, size_t size,
-              enum dma_data_direction direction)
-{
-       BUG();
-       return 0;
-}
-
-static inline void
-dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-                enum dma_data_direction direction)
-{
-       BUG();
-}
-
-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)
-{
-       BUG();
-       return 0;
-}
-
-static inline void
-dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-              enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-          enum dma_data_direction direction)
-{
-       BUG();
-       return 0;
-}
-
-static inline void
-dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-            enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline void
-dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
-                       enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline void
-dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
-                          enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-                   enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline void
-dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-                      enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline int
-dma_error(dma_addr_t dma_addr)
-{
-       return 0;
-}
-
-#endif
-
-/* Now for the API extensions over the pci_ one */
-
-#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
-#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-#define dma_is_consistent(d, h)        (1)
-
-static inline int
-dma_get_cache_alignment(void)
-{
-       /* no easy way to get cache size on all processors, so return
-        * the maximum possible, to be safe */
-       return (1 << INTERNODE_CACHE_SHIFT);
-}
-
-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)
-{
-       /* just sync everything, that's all the pci API can do */
-       dma_sync_single_for_cpu(dev, dma_handle, offset+size, direction);
-}
-
-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)
-{
-       /* just sync everything, that's all the pci API can do */
-       dma_sync_single_for_device(dev, dma_handle, offset+size, direction);
-}
-
-static inline void
-dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-              enum dma_data_direction direction)
-{
-       /* could define this in terms of the dma_cache ... operations,
-        * but if you get this on a platform, you should convert the platform
-        * to using the generic device DMA API */
-       BUG();
-}
-
-#endif
-
index 81797ec9ab2917413ba28d166adb267726c8f177..d6c379dc64fac63797364c7e385dc91778df5ac4 100644 (file)
@@ -55,6 +55,10 @@ struct module;
  *     handled is (base + ngpio - 1).
  * @can_sleep: flag must be set iff get()/set() methods sleep, as they
  *     must while accessing GPIO expander chips over I2C or SPI
+ * @names: if set, must be an array of strings to use as alternative
+ *      names for the GPIOs in this chip. Any entry in the array
+ *      may be NULL if there is no alias for the GPIO, however the
+ *      array must be @ngpio entries long.
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
  * they can all be accessed through a common programing interface.
@@ -92,6 +96,7 @@ struct gpio_chip {
                                                struct gpio_chip *chip);
        int                     base;
        u16                     ngpio;
+       char                    **names;
        unsigned                can_sleep:1;
        unsigned                exported:1;
 };
index 0e9e2bc0ee96e66d08beb37bb71933ab2ece7636..88bada2ebc4b1fb1bb980f96daa8409ac5933eb2 100644 (file)
 #ifndef cpumask_of_node
 #define cpumask_of_node(node)  ((void)node, cpu_online_mask)
 #endif
-#ifndef node_to_first_cpu
-#define node_to_first_cpu(node)        ((void)(node),0)
-#endif
 #ifndef pcibus_to_node
 #define pcibus_to_node(bus)    ((void)(bus), -1)
 #endif
 
-#ifndef pcibus_to_cpumask
-#define pcibus_to_cpumask(bus) (pcibus_to_node(bus) == -1 ? \
-                                       CPU_MASK_ALL : \
-                                       node_to_cpumask(pcibus_to_node(bus)) \
-                               )
-#endif
-
 #ifndef cpumask_of_pcibus
 #define cpumask_of_pcibus(bus) (pcibus_to_node(bus) == -1 ?            \
                                 cpu_all_mask :                         \
index f5cfba81ee10c1f59b007dcf34fd9db508a9bff5..dded923883b2549c52bebb63e5ba5fe664382cb8 100644 (file)
@@ -316,6 +316,9 @@ static inline int __raw_write_trylock(raw_rwlock_t *lock)
        return 0;
 }
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
index 5256854c045342849f190715b4f4ebdd12ed0780..90f2abb04bfdc5178ab50645852fe04ab812d3da 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/highmem.h>
 #include <asm/kmap_types.h>
 #include <asm/pgtable.h>
 
@@ -77,6 +78,7 @@ static inline unsigned long kmap_atomic(struct page *page, enum km_type type)
        if (page < highmem_start_page)
                return page_address(page);
 
+       debug_kmap_atomic(type);
        idx = type + KM_TYPE_NR * smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #if HIGHMEM_DEBUG
index c19a93c3be85f0755515812aaf9916ce59a0e587..c8c42215143158ef6eed2d5bcb9a00f42f29a857 100644 (file)
@@ -281,16 +281,16 @@ typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd,
 
 struct drm_ioctl_desc {
        unsigned int cmd;
-       drm_ioctl_t *func;
        int flags;
+       drm_ioctl_t *func;
 };
 
 /**
  * Creates a driver or general drm_ioctl_desc array entry for the given
  * ioctl, for use by drm_ioctl().
  */
-#define DRM_IOCTL_DEF(ioctl, func, flags) \
-       [DRM_IOCTL_NR(ioctl)] = {ioctl, func, flags}
+#define DRM_IOCTL_DEF(ioctl, _func, _flags) \
+       [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags}
 
 struct drm_magic_entry {
        struct list_head head;
@@ -522,20 +522,33 @@ struct drm_mm {
 };
 
 
+/**
+ * Kernel side of a mapping
+ */
+struct drm_local_map {
+       resource_size_t offset;  /**< Requested physical address (0 for SAREA)*/
+       unsigned long size;      /**< Requested physical size (bytes) */
+       enum drm_map_type type;  /**< Type of memory to map */
+       enum drm_map_flags flags;        /**< Flags */
+       void *handle;            /**< User-space: "Handle" to pass to mmap() */
+                                /**< Kernel-space: kernel-virtual address */
+       int mtrr;                /**< MTRR slot used */
+};
+
+typedef struct drm_local_map drm_local_map_t;
+
 /**
  * Mappings list
  */
 struct drm_map_list {
        struct list_head head;          /**< list head */
        struct drm_hash_item hash;
-       struct drm_map *map;                    /**< mapping */
+       struct drm_local_map *map;      /**< mapping */
        uint64_t user_token;
        struct drm_master *master;
        struct drm_mm_node *file_offset_node;   /**< fake offset */
 };
 
-typedef struct drm_map drm_local_map_t;
-
 /**
  * Context handle list
  */
@@ -560,7 +573,7 @@ struct drm_ati_pcigart_info {
        dma_addr_t bus_addr;
        dma_addr_t table_mask;
        struct drm_dma_handle *table_handle;
-       drm_local_map_t mapping;
+       struct drm_local_map mapping;
        int table_size;
 };
 
@@ -675,7 +688,6 @@ struct drm_driver {
        int (*kernel_context_switch) (struct drm_device *dev, int old,
                                      int new);
        void (*kernel_context_switch_unlock) (struct drm_device *dev);
-       int (*dri_library_name) (struct drm_device *dev, char *buf);
 
        /**
         * get_vblank_counter - get raw hardware vblank counter
@@ -747,8 +759,8 @@ struct drm_driver {
                                        struct drm_file *file_priv);
        void (*reclaim_buffers_idlelocked) (struct drm_device *dev,
                                            struct drm_file *file_priv);
-       unsigned long (*get_map_ofs) (struct drm_map * map);
-       unsigned long (*get_reg_ofs) (struct drm_device *dev);
+       resource_size_t (*get_map_ofs) (struct drm_local_map * map);
+       resource_size_t (*get_reg_ofs) (struct drm_device *dev);
        void (*set_version) (struct drm_device *dev,
                             struct drm_set_version *sv);
 
@@ -981,7 +993,7 @@ struct drm_device {
        sigset_t sigmask;
 
        struct drm_driver *driver;
-       drm_local_map_t *agp_buffer_map;
+       struct drm_local_map *agp_buffer_map;
        unsigned int agp_buffer_token;
        struct drm_minor *control;              /**< Control node for card */
        struct drm_minor *primary;              /**< render type primary screen head */
@@ -1098,8 +1110,8 @@ extern int drm_release(struct inode *inode, struct file *filp);
 extern int drm_mmap(struct file *filp, struct vm_area_struct *vma);
 extern int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma);
 extern void drm_vm_open_locked(struct vm_area_struct *vma);
-extern unsigned long drm_core_get_map_ofs(struct drm_map * map);
-extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev);
+extern resource_size_t drm_core_get_map_ofs(struct drm_local_map * map);
+extern resource_size_t drm_core_get_reg_ofs(struct drm_device *dev);
 extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
 
                                /* Memory management support (drm_memory.h) */
@@ -1202,13 +1214,13 @@ extern int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv
                                /* Buffer management support (drm_bufs.h) */
 extern int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc * request);
 extern int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc * request);
-extern int drm_addmap(struct drm_device *dev, unsigned int offset,
+extern int drm_addmap(struct drm_device *dev, resource_size_t offset,
                      unsigned int size, enum drm_map_type type,
-                     enum drm_map_flags flags, drm_local_map_t ** map_ptr);
+                     enum drm_map_flags flags, struct drm_local_map **map_ptr);
 extern int drm_addmap_ioctl(struct drm_device *dev, void *data,
                            struct drm_file *file_priv);
-extern int drm_rmmap(struct drm_device *dev, drm_local_map_t *map);
-extern int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map);
+extern int drm_rmmap(struct drm_device *dev, struct drm_local_map *map);
+extern int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map);
 extern int drm_rmmap_ioctl(struct drm_device *dev, void *data,
                           struct drm_file *file_priv);
 extern int drm_addbufs(struct drm_device *dev, void *data,
@@ -1222,10 +1234,10 @@ extern int drm_freebufs(struct drm_device *dev, void *data,
 extern int drm_mapbufs(struct drm_device *dev, void *data,
                       struct drm_file *file_priv);
 extern int drm_order(unsigned long size);
-extern unsigned long drm_get_resource_start(struct drm_device *dev,
+extern resource_size_t drm_get_resource_start(struct drm_device *dev,
+                                             unsigned int resource);
+extern resource_size_t drm_get_resource_len(struct drm_device *dev,
                                            unsigned int resource);
-extern unsigned long drm_get_resource_len(struct drm_device *dev,
-                                         unsigned int resource);
 
                                /* DMA support (drm_dma.h) */
 extern int drm_dma_setup(struct drm_device *dev);
@@ -1301,7 +1313,7 @@ extern struct drm_master *drm_master_get(struct drm_master *master);
 extern void drm_master_put(struct drm_master **master);
 extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
                       struct drm_driver *driver);
-extern int drm_put_dev(struct drm_device *dev);
+extern void drm_put_dev(struct drm_device *dev);
 extern int drm_put_minor(struct drm_minor **minor);
 extern unsigned int drm_debug;
 
@@ -1311,7 +1323,7 @@ extern struct dentry *drm_debugfs_root;
 
 extern struct idr drm_minors_idr;
 
-extern drm_local_map_t *drm_getsarea(struct drm_device *dev);
+extern struct drm_local_map *drm_getsarea(struct drm_device *dev);
 
                                /* Proc support (drm_proc.h) */
 extern int drm_proc_init(struct drm_minor *minor, int minor_id,
@@ -1453,12 +1465,12 @@ int drm_gem_open_ioctl(struct drm_device *dev, void *data,
 void drm_gem_open(struct drm_device *dev, struct drm_file *file_private);
 void drm_gem_release(struct drm_device *dev, struct drm_file *file_private);
 
-extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev);
-extern void drm_core_ioremap_wc(struct drm_map *map, struct drm_device *dev);
-extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev);
+extern void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev);
+extern void drm_core_ioremap_wc(struct drm_local_map *map, struct drm_device *dev);
+extern void drm_core_ioremapfree(struct drm_local_map *map, struct drm_device *dev);
 
-static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev,
-                                                  unsigned int token)
+static __inline__ struct drm_local_map *drm_core_findmap(struct drm_device *dev,
+                                                        unsigned int token)
 {
        struct drm_map_list *_entry;
        list_for_each_entry(_entry, &dev->maplist, head)
@@ -1485,7 +1497,7 @@ static __inline__ int drm_device_is_pcie(struct drm_device *dev)
        return pci_find_capability(dev->pdev, PCI_CAP_ID_EXP);
 }
 
-static __inline__ void drm_core_dropmap(struct drm_map *map)
+static __inline__ void drm_core_dropmap(struct drm_local_map *map)
 {
 }
 
index 5ded1acfb5430fd969094e9fa817c285aefa9611..3c1924c010e8c3a2898bbb908f778b1ebed27bf4 100644 (file)
@@ -550,7 +550,7 @@ struct drm_mode_config {
        int min_width, min_height;
        int max_width, max_height;
        struct drm_mode_config_funcs *funcs;
-       unsigned long fb_base;
+       resource_size_t fb_base;
 
        /* pointers to standard properties */
        struct list_head property_blob_list;
@@ -613,7 +613,8 @@ extern void drm_fb_release(struct drm_file *file_priv);
 extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group);
 extern struct edid *drm_get_edid(struct drm_connector *connector,
                                 struct i2c_adapter *adapter);
-extern unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter);
+extern int drm_do_probe_ddc_edid(struct i2c_adapter *adapter,
+                                unsigned char *buf, int len);
 extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
 extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode);
 extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode);
@@ -731,4 +732,5 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev,
                                    void *data, struct drm_file *file_priv);
 extern int drm_mode_gamma_set_ioctl(struct drm_device *dev,
                                    void *data, struct drm_file *file_priv);
+extern bool drm_detect_hdmi_monitor(struct edid *edid);
 #endif /* __DRM_CRTC_H__ */
index 8dbd2572b7c3bc558bee3f6f3b18b1989c69e5fb..013551d03c035c984d19e02b692a0ed5b5c3015f 100644 (file)
@@ -6,6 +6,19 @@
 #include <linux/interrupt.h>   /* For task queue support */
 #include <linux/delay.h>
 
+#ifndef readq
+static u64 readq(void __iomem *reg)
+{
+       return ((u64) readl(reg)) | (((u64) readl(reg + 4UL)) << 32);
+}
+
+static void writeq(u64 val, void __iomem *reg)
+{
+       writel(val & 0xffffffff, reg);
+       writel(val >> 32, reg + 0x4UL);
+}
+#endif
+
 /** Current process ID */
 #define DRM_CURRENTPID                 task_pid_nr(current)
 #define DRM_SUSER(p)                   capable(CAP_SYS_ADMIN)
 /** Write a dword into a MMIO region */
 #define DRM_WRITE32(map, offset, val)  writel(val, ((void __iomem *)(map)->handle) + (offset))
 /** Read memory barrier */
+
+/** Read a qword from a MMIO region - be careful using these unless you really understand them */
+#define DRM_READ64(map, offset)                readq(((void __iomem *)(map)->handle) + (offset))
+/** Write a qword into a MMIO region */
+#define DRM_WRITE64(map, offset, val)  writeq(val, ((void __iomem *)(map)->handle) + (offset))
+
 #define DRM_READMEMORYBARRIER()                rmb()
 /** Write memory barrier */
 #define DRM_WRITEMEMORYBARRIER()       wmb()
index 76c4c8243038388b3843e6470c256afbe1e125c8..2df74eb09563508f50d367afe70f1d37f31abd68 100644 (file)
        {0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x791e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \
        {0x1002, 0x791f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \
+       {0x1002, 0x793f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS600|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7941, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS600|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7942, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS600|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x796c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \
        {0x1002, 0x796d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \
        {0x1002, 0x796e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \
        {0x1002, 0x796f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \
+       {0x1002, 0x9400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9402, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9403, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9405, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x940A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x940B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x940F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9442, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9444, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x944A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x944B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x944C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x944E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9450, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9452, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9456, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x945A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x945B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x946A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x946B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x947A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x947B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9480, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9487, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9488, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9489, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x948F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9490, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9491, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9498, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x949C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x949E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x949F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94C0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94C1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94C3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94C5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94C6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94C8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94C9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94CD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9501, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9504, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9505, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9506, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9507, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9508, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9509, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x950F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9511, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9515, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9517, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9519, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9540, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9541, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9542, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x954E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x954F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9553, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9555, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9580, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9581, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9583, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9586, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9587, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9588, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9589, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x958A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x958B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x958C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x958D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x958E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x958F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9590, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9591, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9593, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9595, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9596, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9597, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9598, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9599, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x959B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x95C0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x95C5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x95C6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x95C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x95C9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x95C2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x95C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x95CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x95CD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x95CE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x95CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x9611, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x9612, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x9613, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x9614, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x9615, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x9616, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0, 0, 0}
 
 #define r128_PCI_IDS \
index 72ecf67ad3ec1591c24d74920c488f118b70ca2a..fe3e3a4b4aed9257ec14a6c1e3799fd52444b90e 100644 (file)
@@ -306,6 +306,8 @@ typedef union {
 
 #define RADEON_SCRATCH_REG_OFFSET      32
 
+#define R600_SCRATCH_REG_OFFSET         256
+
 #define RADEON_NR_SAREA_CLIPRECTS      12
 
 /* There are 2 heaps (local/GART).  Each region within a heap is a
@@ -528,7 +530,8 @@ typedef struct drm_radeon_init {
                RADEON_INIT_CP = 0x01,
                RADEON_CLEANUP_CP = 0x02,
                RADEON_INIT_R200_CP = 0x03,
-               RADEON_INIT_R300_CP = 0x04
+               RADEON_INIT_R300_CP = 0x04,
+               RADEON_INIT_R600_CP = 0x05
        } func;
        unsigned long sarea_priv_offset;
        int is_pci;
index e9581fd9fb66b45499a5e4b490ea301b50f2405e..ca9b9b9bd3311fc1e769b47251ed3ecb761a59a2 100644 (file)
@@ -67,6 +67,7 @@ header-y += falloc.h
 header-y += fd.h
 header-y += fdreg.h
 header-y += fib_rules.h
+header-y += fiemap.h
 header-y += firewire-cdev.h
 header-y += firewire-constants.h
 header-y += fuse.h
@@ -158,8 +159,6 @@ header-y += ultrasound.h
 header-y += un.h
 header-y += utime.h
 header-y += veth.h
-header-y += video_decoder.h
-header-y += video_encoder.h
 header-y += videotext.h
 header-y += x25.h
 
index 78199151c00b2b1a996f2723f5496159da66a6fb..d047f846c3ed6d434555f2734aee472627e9ef6b 100644 (file)
@@ -257,6 +257,40 @@ void __init acpi_no_s4_hw_signature(void);
 void __init acpi_old_suspend_ordering(void);
 void __init acpi_s4_no_nvs(void);
 #endif /* CONFIG_PM_SLEEP */
+
+#define OSC_QUERY_TYPE                 0
+#define OSC_SUPPORT_TYPE               1
+#define OSC_CONTROL_TYPE               2
+#define OSC_SUPPORT_MASKS              0x1f
+
+/* _OSC DW0 Definition */
+#define OSC_QUERY_ENABLE               1
+#define OSC_REQUEST_ERROR              2
+#define OSC_INVALID_UUID_ERROR         4
+#define OSC_INVALID_REVISION_ERROR     8
+#define OSC_CAPABILITIES_MASK_ERROR    16
+
+/* _OSC DW1 Definition (OS Support Fields) */
+#define OSC_EXT_PCI_CONFIG_SUPPORT             1
+#define OSC_ACTIVE_STATE_PWR_SUPPORT           2
+#define OSC_CLOCK_PWR_CAPABILITY_SUPPORT       4
+#define OSC_PCI_SEGMENT_GROUPS_SUPPORT         8
+#define OSC_MSI_SUPPORT                                16
+
+/* _OSC DW1 Definition (OS Control Fields) */
+#define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL      1
+#define OSC_SHPC_NATIVE_HP_CONTROL             2
+#define OSC_PCI_EXPRESS_PME_CONTROL            4
+#define OSC_PCI_EXPRESS_AER_CONTROL            8
+#define OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL  16
+
+#define OSC_CONTROL_MASKS      (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |    \
+                               OSC_SHPC_NATIVE_HP_CONTROL |            \
+                               OSC_PCI_EXPRESS_PME_CONTROL |           \
+                               OSC_PCI_EXPRESS_AER_CONTROL |           \
+                               OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
+
+extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
 #else  /* CONFIG_ACPI */
 
 static inline int early_acpi_boot_init(void)
index 91a773993a5c99d7c360e3944bece7d7b099d4c7..850f39b33e743f927acf0d2ca9777971c873e345 100644 (file)
 #ifndef _LINUX_AUTO_DEV_IOCTL_H
 #define _LINUX_AUTO_DEV_IOCTL_H
 
+#include <linux/auto_fs.h>
+
+#ifdef __KERNEL__
 #include <linux/string.h>
-#include <linux/types.h>
+#else
+#include <string.h>
+#endif /* __KERNEL__ */
 
 #define AUTOFS_DEVICE_NAME             "autofs"
 
index c21e5972a3e8a0c1d20531cfabe35b14bb2a0141..63265852b7d16216b377d27036375bc42de042e1 100644 (file)
 #ifdef __KERNEL__
 #include <linux/fs.h>
 #include <linux/limits.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#else
 #include <asm/types.h>
+#include <sys/ioctl.h>
 #endif /* __KERNEL__ */
 
-#include <linux/ioctl.h>
-
 /* This file describes autofs v3 */
 #define AUTOFS_PROTO_VERSION   3
 
index 77b4a9e4600485318a141597a9cd226e2c922f4c..6638b8148de7d9a45635ca95b6952b6651df2542 100644 (file)
@@ -35,8 +35,7 @@ struct linux_binprm{
 #endif
        struct mm_struct *mm;
        unsigned long p; /* current top of mem */
-       unsigned int sh_bang:1,
-               misc_bang:1,
+       unsigned int
                cred_prepared:1,/* true if creds already prepared (multiple
                                 * preps happen for interpreters) */
                cap_effective:1;/* true if has elevated effective capabilities,
index 455d83219fae5f3e40bdf83575da34ea9c864da7..bc3ab70736955675afef688d4209c5bf8392b4b3 100644 (file)
@@ -146,10 +146,10 @@ extern void *alloc_large_system_hash(const char *tablename,
 
 #define HASH_EARLY     0x00000001      /* Allocating during early boot? */
 
-/* Only NUMA needs hash distribution.
- * IA64 and x86_64 have sufficient vmalloc space.
+/* Only NUMA needs hash distribution. 64bit NUMA architectures have
+ * sufficient vmalloc space.
  */
-#if defined(CONFIG_NUMA) && (defined(CONFIG_IA64) || defined(CONFIG_X86_64))
+#if defined(CONFIG_NUMA) && defined(CONFIG_64BIT)
 #define HASHDIST_DEFAULT 1
 #else
 #define HASHDIST_DEFAULT 0
index f19fd9045ea0a621e05bc6eb11d515a78656f8bb..3d7bcde2e3325dacb1e5ec32ee3f1a50ad4e1725 100644 (file)
@@ -216,7 +216,7 @@ int cont_write_begin(struct file *, struct address_space *, loff_t,
                        get_block_t *, loff_t *);
 int generic_cont_expand_simple(struct inode *inode, loff_t size);
 int block_commit_write(struct page *page, unsigned from, unsigned to);
-int block_page_mkwrite(struct vm_area_struct *vma, struct page *page,
+int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
                                get_block_t get_block);
 void block_sync_page(struct page *);
 sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
index 499900d0cee7110748229ee3898b50734352e5e4..4316a546beb51a201394b1eb8c97a51c8eea2c0a 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/cgroupstats.h>
 #include <linux/prio_heap.h>
 #include <linux/rwsem.h>
+#include <linux/idr.h>
 
 #ifdef CONFIG_CGROUPS
 
@@ -22,6 +23,7 @@ struct cgroupfs_root;
 struct cgroup_subsys;
 struct inode;
 struct cgroup;
+struct css_id;
 
 extern int cgroup_init_early(void);
 extern int cgroup_init(void);
@@ -47,18 +49,24 @@ enum cgroup_subsys_id {
 
 /* Per-subsystem/per-cgroup state maintained by the system. */
 struct cgroup_subsys_state {
-       /* The cgroup that this subsystem is attached to. Useful
+       /*
+        * The cgroup that this subsystem is attached to. Useful
         * for subsystems that want to know about the cgroup
-        * hierarchy structure */
+        * hierarchy structure
+        */
        struct cgroup *cgroup;
 
-       /* State maintained by the cgroup system to allow subsystems
+       /*
+        * State maintained by the cgroup system to allow subsystems
         * to be "busy". Should be accessed via css_get(),
-        * css_tryget() and and css_put(). */
+        * css_tryget() and and css_put().
+        */
 
        atomic_t refcnt;
 
        unsigned long flags;
+       /* ID for this css, if possible */
+       struct css_id *id;
 };
 
 /* bits in struct cgroup_subsys_state flags field */
@@ -120,19 +128,26 @@ static inline void css_put(struct cgroup_subsys_state *css)
 enum {
        /* Control Group is dead */
        CGRP_REMOVED,
-       /* Control Group has previously had a child cgroup or a task,
-        * but no longer (only if CGRP_NOTIFY_ON_RELEASE is set) */
+       /*
+        * Control Group has previously had a child cgroup or a task,
+        * but no longer (only if CGRP_NOTIFY_ON_RELEASE is set)
+        */
        CGRP_RELEASABLE,
        /* Control Group requires release notifications to userspace */
        CGRP_NOTIFY_ON_RELEASE,
+       /*
+        * A thread in rmdir() is wating for this cgroup.
+        */
+       CGRP_WAIT_ON_RMDIR,
 };
 
 struct cgroup {
        unsigned long flags;            /* "unsigned long" so bitops work */
 
-       /* count users of this cgroup. >0 means busy, but doesn't
-        * necessarily indicate the number of tasks in the
-        * cgroup */
+       /*
+        * count users of this cgroup. >0 means busy, but doesn't
+        * necessarily indicate the number of tasks in the cgroup
+        */
        atomic_t count;
 
        /*
@@ -142,7 +157,7 @@ struct cgroup {
        struct list_head sibling;       /* my parent's children */
        struct list_head children;      /* my children */
 
-       struct cgroup *parent;  /* my parent */
+       struct cgroup *parent;          /* my parent */
        struct dentry *dentry;          /* cgroup fs entry, RCU protected */
 
        /* Private pointers for each registered subsystem */
@@ -177,11 +192,12 @@ struct cgroup {
        struct rcu_head rcu_head;
 };
 
-/* A css_set is a structure holding pointers to a set of
+/*
+ * A css_set is a structure holding pointers to a set of
  * cgroup_subsys_state objects. This saves space in the task struct
  * object and speeds up fork()/exit(), since a single inc/dec and a
- * list_add()/del() can bump the reference count on the entire
- * cgroup set for a task.
+ * list_add()/del() can bump the reference count on the entire cgroup
+ * set for a task.
  */
 
 struct css_set {
@@ -226,13 +242,8 @@ struct cgroup_map_cb {
        void *state;
 };
 
-/* struct cftype:
- *
- * The files in the cgroup filesystem mostly have a very simple read/write
- * handling, some common function will take care of it. Nevertheless some cases
- * (read tasks) are special and therefore I define this structure for every
- * kind of file.
- *
+/*
+ * struct cftype: handler definitions for cgroup control files
  *
  * When reading/writing to a file:
  *     - the cgroup to use is file->f_dentry->d_parent->d_fsdata
@@ -241,10 +252,17 @@ struct cgroup_map_cb {
 
 #define MAX_CFTYPE_NAME 64
 struct cftype {
-       /* By convention, the name should begin with the name of the
-        * subsystem, followed by a period */
+       /*
+        * By convention, the name should begin with the name of the
+        * subsystem, followed by a period
+        */
        char name[MAX_CFTYPE_NAME];
        int private;
+       /*
+        * If not 0, file mode is set to this value, otherwise it will
+        * be figured out automatically
+        */
+       mode_t mode;
 
        /*
         * If non-zero, defines the maximum length of string that can
@@ -319,15 +337,20 @@ struct cgroup_scanner {
        void (*process_task)(struct task_struct *p,
                        struct cgroup_scanner *scan);
        struct ptr_heap *heap;
+       void *data;
 };
 
-/* Add a new file to the given cgroup directory. Should only be
- * called by subsystems from within a populate() method */
+/*
+ * Add a new file to the given cgroup directory. Should only be
+ * called by subsystems from within a populate() method
+ */
 int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
                       const struct cftype *cft);
 
-/* Add a set of new files to the given cgroup directory. Should
- * only be called by subsystems from within a populate() method */
+/*
+ * Add a set of new files to the given cgroup directory. Should
+ * only be called by subsystems from within a populate() method
+ */
 int cgroup_add_files(struct cgroup *cgrp,
                        struct cgroup_subsys *subsys,
                        const struct cftype cft[],
@@ -339,15 +362,15 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen);
 
 int cgroup_task_count(const struct cgroup *cgrp);
 
-/* Return true if the cgroup is a descendant of the current cgroup */
-int cgroup_is_descendant(const struct cgroup *cgrp);
+/* Return true if cgrp is a descendant of the task's cgroup */
+int cgroup_is_descendant(const struct cgroup *cgrp, struct task_struct *task);
 
 /* Control Group subsystem type. See Documentation/cgroups.txt for details */
 
 struct cgroup_subsys {
        struct cgroup_subsys_state *(*create)(struct cgroup_subsys *ss,
                                                  struct cgroup *cgrp);
-       void (*pre_destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
+       int (*pre_destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
        void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
        int (*can_attach)(struct cgroup_subsys *ss,
                          struct cgroup *cgrp, struct task_struct *tsk);
@@ -364,6 +387,11 @@ struct cgroup_subsys {
        int active;
        int disabled;
        int early_init;
+       /*
+        * True if this subsys uses ID. ID is not available before cgroup_init()
+        * (not available in early_init time.)
+        */
+       bool use_id;
 #define MAX_CGROUP_TYPE_NAMELEN 32
        const char *name;
 
@@ -386,6 +414,9 @@ struct cgroup_subsys {
         */
        struct cgroupfs_root *root;
        struct list_head sibling;
+       /* used when use_id == true */
+       struct idr idr;
+       spinlock_t id_lock;
 };
 
 #define SUBSYS(_x) extern struct cgroup_subsys _x ## _subsys;
@@ -419,7 +450,8 @@ struct cgroup_iter {
        struct list_head *task;
 };
 
-/* To iterate across the tasks in a cgroup:
+/*
+ * To iterate across the tasks in a cgroup:
  *
  * 1) call cgroup_iter_start to intialize an iterator
  *
@@ -428,9 +460,10 @@ struct cgroup_iter {
  *
  * 3) call cgroup_iter_end() to destroy the iterator.
  *
- * Or, call cgroup_scan_tasks() to iterate through every task in a cpuset.
- *    - cgroup_scan_tasks() holds the css_set_lock when calling the test_task()
- *      callback, but not while calling the process_task() callback.
+ * Or, call cgroup_scan_tasks() to iterate through every task in a
+ * cgroup - cgroup_scan_tasks() holds the css_set_lock when calling
+ * the test_task() callback, but not while calling the process_task()
+ * callback.
  */
 void cgroup_iter_start(struct cgroup *cgrp, struct cgroup_iter *it);
 struct task_struct *cgroup_iter_next(struct cgroup *cgrp,
@@ -439,6 +472,44 @@ void cgroup_iter_end(struct cgroup *cgrp, struct cgroup_iter *it);
 int cgroup_scan_tasks(struct cgroup_scanner *scan);
 int cgroup_attach_task(struct cgroup *, struct task_struct *);
 
+/*
+ * CSS ID is ID for cgroup_subsys_state structs under subsys. This only works
+ * if cgroup_subsys.use_id == true. It can be used for looking up and scanning.
+ * CSS ID is assigned at cgroup allocation (create) automatically
+ * and removed when subsys calls free_css_id() function. This is because
+ * the lifetime of cgroup_subsys_state is subsys's matter.
+ *
+ * Looking up and scanning function should be called under rcu_read_lock().
+ * Taking cgroup_mutex()/hierarchy_mutex() is not necessary for following calls.
+ * But the css returned by this routine can be "not populated yet" or "being
+ * destroyed". The caller should check css and cgroup's status.
+ */
+
+/*
+ * Typically Called at ->destroy(), or somewhere the subsys frees
+ * cgroup_subsys_state.
+ */
+void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css);
+
+/* Find a cgroup_subsys_state which has given ID */
+
+struct cgroup_subsys_state *css_lookup(struct cgroup_subsys *ss, int id);
+
+/*
+ * Get a cgroup whose id is greater than or equal to id under tree of root.
+ * Returning a cgroup_subsys_state or NULL.
+ */
+struct cgroup_subsys_state *css_get_next(struct cgroup_subsys *ss, int id,
+               struct cgroup_subsys_state *root, int *foundid);
+
+/* Returns true if root is ancestor of cg */
+bool css_is_ancestor(struct cgroup_subsys_state *cg,
+                    const struct cgroup_subsys_state *root);
+
+/* Get id and depth of css */
+unsigned short css_id(struct cgroup_subsys_state *css);
+unsigned short css_depth(struct cgroup_subsys_state *css);
+
 #else /* !CONFIG_CGROUPS */
 
 static inline int cgroup_init_early(void) { return 0; }
index b880864672de75e09cfd522f1f6df1fded3ba56b..9723edd6455cb8d612923f8a5706fb691e2a1525 100644 (file)
@@ -191,6 +191,12 @@ asmlinkage ssize_t compat_sys_readv(unsigned long fd,
                const struct compat_iovec __user *vec, unsigned long vlen);
 asmlinkage ssize_t compat_sys_writev(unsigned long fd,
                const struct compat_iovec __user *vec, unsigned long vlen);
+asmlinkage ssize_t compat_sys_preadv(unsigned long fd,
+               const struct compat_iovec __user *vec,
+               unsigned long vlen, u32 pos_high, u32 pos_low);
+asmlinkage ssize_t compat_sys_pwritev(unsigned long fd,
+               const struct compat_iovec __user *vec,
+               unsigned long vlen, u32 pos_high, u32 pos_low);
 
 int compat_do_execve(char * filename, compat_uptr_t __user *argv,
                compat_uptr_t __user *envp, struct pt_regs * regs);
index c2747ac2ae43b8a7b22bebdef63ee92cbcf1c31a..2643d848df9014df4776423028e223498f5a6d66 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/node.h>
 #include <linux/compiler.h>
 #include <linux/cpumask.h>
-#include <linux/mutex.h>
 
 struct cpu {
        int node_id;            /* The node which contains the CPU */
@@ -103,16 +102,6 @@ extern struct sysdev_class cpu_sysdev_class;
 #ifdef CONFIG_HOTPLUG_CPU
 /* Stop CPUs going up and down. */
 
-static inline void cpuhotplug_mutex_lock(struct mutex *cpu_hp_mutex)
-{
-       mutex_lock(cpu_hp_mutex);
-}
-
-static inline void cpuhotplug_mutex_unlock(struct mutex *cpu_hp_mutex)
-{
-       mutex_unlock(cpu_hp_mutex);
-}
-
 extern void get_online_cpus(void);
 extern void put_online_cpus(void);
 #define hotcpu_notifier(fn, pri) {                             \
@@ -126,11 +115,6 @@ int cpu_down(unsigned int cpu);
 
 #else          /* CONFIG_HOTPLUG_CPU */
 
-static inline void cpuhotplug_mutex_lock(struct mutex *cpu_hp_mutex)
-{ }
-static inline void cpuhotplug_mutex_unlock(struct mutex *cpu_hp_mutex)
-{ }
-
 #define get_online_cpus()      do { } while (0)
 #define put_online_cpus()      do { } while (0)
 #define hotcpu_notifier(fn, pri)       do { (void)(fn); } while (0)
index 90c6074a36cab42c47df2ac8f6239cfe2ae0ddfe..05ea1dd7d681d072a5ae1c9c7c2da56d75bbc6e6 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/cpumask.h>
 #include <linux/nodemask.h>
 #include <linux/cgroup.h>
+#include <linux/mm.h>
 
 #ifdef CONFIG_CPUSETS
 
@@ -29,19 +30,29 @@ void cpuset_init_current_mems_allowed(void);
 void cpuset_update_task_memory_state(void);
 int cpuset_nodemask_valid_mems_allowed(nodemask_t *nodemask);
 
-extern int __cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask);
-extern int __cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask);
+extern int __cpuset_node_allowed_softwall(int node, gfp_t gfp_mask);
+extern int __cpuset_node_allowed_hardwall(int node, gfp_t gfp_mask);
 
-static int inline cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
+static inline int cpuset_node_allowed_softwall(int node, gfp_t gfp_mask)
 {
        return number_of_cpusets <= 1 ||
-               __cpuset_zone_allowed_softwall(z, gfp_mask);
+               __cpuset_node_allowed_softwall(node, gfp_mask);
 }
 
-static int inline cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask)
+static inline int cpuset_node_allowed_hardwall(int node, gfp_t gfp_mask)
 {
        return number_of_cpusets <= 1 ||
-               __cpuset_zone_allowed_hardwall(z, gfp_mask);
+               __cpuset_node_allowed_hardwall(node, gfp_mask);
+}
+
+static inline int cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
+{
+       return cpuset_node_allowed_softwall(zone_to_nid(z), gfp_mask);
+}
+
+static inline int cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask)
+{
+       return cpuset_node_allowed_hardwall(zone_to_nid(z), gfp_mask);
 }
 
 extern int cpuset_mems_allowed_intersects(const struct task_struct *tsk1,
@@ -90,12 +101,12 @@ static inline void cpuset_init_smp(void) {}
 static inline void cpuset_cpus_allowed(struct task_struct *p,
                                       struct cpumask *mask)
 {
-       *mask = cpu_possible_map;
+       cpumask_copy(mask, cpu_possible_mask);
 }
 static inline void cpuset_cpus_allowed_locked(struct task_struct *p,
                                              struct cpumask *mask)
 {
-       *mask = cpu_possible_map;
+       cpumask_copy(mask, cpu_possible_mask);
 }
 
 static inline nodemask_t cpuset_mems_allowed(struct task_struct *p)
@@ -112,6 +123,16 @@ static inline int cpuset_nodemask_valid_mems_allowed(nodemask_t *nodemask)
        return 1;
 }
 
+static inline int cpuset_node_allowed_softwall(int node, gfp_t gfp_mask)
+{
+       return 1;
+}
+
+static inline int cpuset_node_allowed_hardwall(int node, gfp_t gfp_mask)
+{
+       return 1;
+}
+
 static inline int cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
 {
        return 1;
diff --git a/include/linux/dma-debug.h b/include/linux/dma-debug.h
new file mode 100644 (file)
index 0000000..28d53cb
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2008 Advanced Micro Devices, Inc.
+ *
+ * Author: Joerg Roedel <joerg.roedel@amd.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.
+ *
+ * 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 __DMA_DEBUG_H
+#define __DMA_DEBUG_H
+
+#include <linux/types.h>
+
+struct device;
+struct scatterlist;
+struct bus_type;
+
+#ifdef CONFIG_DMA_API_DEBUG
+
+extern void dma_debug_add_bus(struct bus_type *bus);
+
+extern void dma_debug_init(u32 num_entries);
+
+extern void debug_dma_map_page(struct device *dev, struct page *page,
+                              size_t offset, size_t size,
+                              int direction, dma_addr_t dma_addr,
+                              bool map_single);
+
+extern void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
+                                size_t size, int direction, bool map_single);
+
+extern void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
+                            int nents, int mapped_ents, int direction);
+
+extern void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
+                              int nelems, int dir);
+
+extern void debug_dma_alloc_coherent(struct device *dev, size_t size,
+                                    dma_addr_t dma_addr, void *virt);
+
+extern void debug_dma_free_coherent(struct device *dev, size_t size,
+                                   void *virt, dma_addr_t addr);
+
+extern void debug_dma_sync_single_for_cpu(struct device *dev,
+                                         dma_addr_t dma_handle, size_t size,
+                                         int direction);
+
+extern void debug_dma_sync_single_for_device(struct device *dev,
+                                            dma_addr_t dma_handle,
+                                            size_t size, int direction);
+
+extern void debug_dma_sync_single_range_for_cpu(struct device *dev,
+                                               dma_addr_t dma_handle,
+                                               unsigned long offset,
+                                               size_t size,
+                                               int direction);
+
+extern void debug_dma_sync_single_range_for_device(struct device *dev,
+                                                  dma_addr_t dma_handle,
+                                                  unsigned long offset,
+                                                  size_t size, int direction);
+
+extern void debug_dma_sync_sg_for_cpu(struct device *dev,
+                                     struct scatterlist *sg,
+                                     int nelems, int direction);
+
+extern void debug_dma_sync_sg_for_device(struct device *dev,
+                                        struct scatterlist *sg,
+                                        int nelems, int direction);
+
+extern void debug_dma_dump_mappings(struct device *dev);
+
+#else /* CONFIG_DMA_API_DEBUG */
+
+static inline void dma_debug_add_bus(struct bus_type *bus)
+{
+}
+
+static inline void dma_debug_init(u32 num_entries)
+{
+}
+
+static inline void debug_dma_map_page(struct device *dev, struct page *page,
+                                     size_t offset, size_t size,
+                                     int direction, dma_addr_t dma_addr,
+                                     bool map_single)
+{
+}
+
+static inline void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
+                                       size_t size, int direction,
+                                       bool map_single)
+{
+}
+
+static inline void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
+                                   int nents, int mapped_ents, int direction)
+{
+}
+
+static inline void debug_dma_unmap_sg(struct device *dev,
+                                     struct scatterlist *sglist,
+                                     int nelems, int dir)
+{
+}
+
+static inline void debug_dma_alloc_coherent(struct device *dev, size_t size,
+                                           dma_addr_t dma_addr, void *virt)
+{
+}
+
+static inline void debug_dma_free_coherent(struct device *dev, size_t size,
+                                          void *virt, dma_addr_t addr)
+{
+}
+
+static inline void debug_dma_sync_single_for_cpu(struct device *dev,
+                                                dma_addr_t dma_handle,
+                                                size_t size, int direction)
+{
+}
+
+static inline void debug_dma_sync_single_for_device(struct device *dev,
+                                                   dma_addr_t dma_handle,
+                                                   size_t size, int direction)
+{
+}
+
+static inline void debug_dma_sync_single_range_for_cpu(struct device *dev,
+                                                      dma_addr_t dma_handle,
+                                                      unsigned long offset,
+                                                      size_t size,
+                                                      int direction)
+{
+}
+
+static inline void debug_dma_sync_single_range_for_device(struct device *dev,
+                                                         dma_addr_t dma_handle,
+                                                         unsigned long offset,
+                                                         size_t size,
+                                                         int direction)
+{
+}
+
+static inline void debug_dma_sync_sg_for_cpu(struct device *dev,
+                                            struct scatterlist *sg,
+                                            int nelems, int direction)
+{
+}
+
+static inline void debug_dma_sync_sg_for_device(struct device *dev,
+                                               struct scatterlist *sg,
+                                               int nelems, int direction)
+{
+}
+
+static inline void debug_dma_dump_mappings(struct device *dev)
+{
+}
+
+#endif /* CONFIG_DMA_API_DEBUG */
+
+#endif /* __DMA_DEBUG_H */
index ba9114ec5d3aa953a13f057e157b6b866de76f53..d7d090d210317b258f400239fdf42d76bd8db7f6 100644 (file)
@@ -3,6 +3,8 @@
 
 #include <linux/device.h>
 #include <linux/err.h>
+#include <linux/dma-attrs.h>
+#include <linux/scatterlist.h>
 
 /* These definitions mirror those in pci.h, so they can be used
  * interchangeably with their PCI_ counterparts */
@@ -13,6 +15,52 @@ enum dma_data_direction {
        DMA_NONE = 3,
 };
 
+struct dma_map_ops {
+       void* (*alloc_coherent)(struct device *dev, size_t size,
+                               dma_addr_t *dma_handle, gfp_t gfp);
+       void (*free_coherent)(struct device *dev, size_t size,
+                             void *vaddr, dma_addr_t dma_handle);
+       dma_addr_t (*map_page)(struct device *dev, struct page *page,
+                              unsigned long offset, size_t size,
+                              enum dma_data_direction dir,
+                              struct dma_attrs *attrs);
+       void (*unmap_page)(struct device *dev, dma_addr_t dma_handle,
+                          size_t size, enum dma_data_direction dir,
+                          struct dma_attrs *attrs);
+       int (*map_sg)(struct device *dev, struct scatterlist *sg,
+                     int nents, enum dma_data_direction dir,
+                     struct dma_attrs *attrs);
+       void (*unmap_sg)(struct device *dev,
+                        struct scatterlist *sg, int nents,
+                        enum dma_data_direction dir,
+                        struct dma_attrs *attrs);
+       void (*sync_single_for_cpu)(struct device *dev,
+                                   dma_addr_t dma_handle, size_t size,
+                                   enum dma_data_direction dir);
+       void (*sync_single_for_device)(struct device *dev,
+                                      dma_addr_t dma_handle, size_t size,
+                                      enum dma_data_direction dir);
+       void (*sync_single_range_for_cpu)(struct device *dev,
+                                         dma_addr_t dma_handle,
+                                         unsigned long offset,
+                                         size_t size,
+                                         enum dma_data_direction dir);
+       void (*sync_single_range_for_device)(struct device *dev,
+                                            dma_addr_t dma_handle,
+                                            unsigned long offset,
+                                            size_t size,
+                                            enum dma_data_direction dir);
+       void (*sync_sg_for_cpu)(struct device *dev,
+                               struct scatterlist *sg, int nents,
+                               enum dma_data_direction dir);
+       void (*sync_sg_for_device)(struct device *dev,
+                                  struct scatterlist *sg, int nents,
+                                  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 is_phys;
+};
+
 #define DMA_BIT_MASK(n)        (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
 
 /*
index f28440784cf0861eed96d57dada953f8d3113bae..2f34274689564e3bffb72739ac754081e4ad66f7 100644 (file)
 #include <linux/acpi.h>
 #include <linux/types.h>
 #include <linux/msi.h>
+#include <linux/irqreturn.h>
 
-#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP)
 struct intel_iommu;
-
+#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP)
 struct dmar_drhd_unit {
        struct list_head list;          /* list of drhd units   */
        struct  acpi_dmar_header *hdr;  /* ACPI header          */
@@ -49,7 +49,7 @@ extern int dmar_dev_scope_init(void);
 
 /* Intel IOMMU detection */
 extern void detect_intel_iommu(void);
-
+extern int enable_drhd_fault_handling(void);
 
 extern int parse_ioapics_under_ir(void);
 extern int alloc_iommu(struct dmar_drhd_unit *);
@@ -63,12 +63,12 @@ static inline int dmar_table_init(void)
 {
        return -ENODEV;
 }
+static inline int enable_drhd_fault_handling(void)
+{
+       return -1;
+}
 #endif /* !CONFIG_DMAR && !CONFIG_INTR_REMAP */
 
-#ifdef CONFIG_INTR_REMAP
-extern int intr_remapping_enabled;
-extern int enable_intr_remapping(int);
-
 struct irte {
        union {
                struct {
@@ -97,6 +97,10 @@ struct irte {
                __u64 high;
        };
 };
+#ifdef CONFIG_INTR_REMAP
+extern int intr_remapping_enabled;
+extern int enable_intr_remapping(int);
+
 extern int get_irte(int irq, struct irte *entry);
 extern int modify_irte(int irq, struct irte *irte_modified);
 extern int alloc_irte(struct intel_iommu *iommu, int irq, u16 count);
@@ -111,14 +115,40 @@ extern int irq_remapped(int irq);
 extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev);
 extern struct intel_iommu *map_ioapic_to_ir(int apic);
 #else
+static inline int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
+{
+       return -1;
+}
+static inline int modify_irte(int irq, struct irte *irte_modified)
+{
+       return -1;
+}
+static inline int free_irte(int irq)
+{
+       return -1;
+}
+static inline int map_irq_to_irte_handle(int irq, u16 *sub_handle)
+{
+       return -1;
+}
+static inline int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index,
+                              u16 sub_handle)
+{
+       return -1;
+}
+static inline struct intel_iommu *map_dev_to_ir(struct pci_dev *dev)
+{
+       return NULL;
+}
+static inline struct intel_iommu *map_ioapic_to_ir(int apic)
+{
+       return NULL;
+}
 #define irq_remapped(irq)              (0)
 #define enable_intr_remapping(mode)    (-1)
 #define intr_remapping_enabled         (0)
 #endif
 
-#ifdef CONFIG_DMAR
-extern const char *dmar_get_fault_reason(u8 fault_reason);
-
 /* Can't use the common MSI interrupt functions
  * since DMAR is not a pci device
  */
@@ -127,8 +157,10 @@ extern void dmar_msi_mask(unsigned int irq);
 extern void dmar_msi_read(int irq, struct msi_msg *msg);
 extern void dmar_msi_write(int irq, struct msi_msg *msg);
 extern int dmar_set_interrupt(struct intel_iommu *iommu);
+extern irqreturn_t dmar_fault(int irq, void *dev_id);
 extern int arch_setup_dmar_msi(unsigned int irq);
 
+#ifdef CONFIG_DMAR
 extern int iommu_detected, no_iommu;
 extern struct list_head dmar_rmrr_units;
 struct dmar_rmrr_unit {
index d741b9ceb0e06ad75b032a9f3251ca038d98f5ac..bb5489c82c99495b6bf2900175e1c22c25dd610c 100644 (file)
@@ -47,7 +47,8 @@ extern int dmi_get_year(int field);
 extern int dmi_name_in_vendors(const char *str);
 extern int dmi_name_in_serial(const char *str);
 extern int dmi_available;
-extern int dmi_walk(void (*decode)(const struct dmi_header *));
+extern int dmi_walk(void (*decode)(const struct dmi_header *, void *),
+       void *private_data);
 extern bool dmi_match(enum dmi_field f, const char *str);
 
 #else
@@ -61,8 +62,8 @@ static inline int dmi_get_year(int year) { return 0; }
 static inline int dmi_name_in_vendors(const char *s) { return 0; }
 static inline int dmi_name_in_serial(const char *s) { return 0; }
 #define dmi_available 0
-static inline int dmi_walk(void (*decode)(const struct dmi_header *))
-       { return -1; }
+static inline int dmi_walk(void (*decode)(const struct dmi_header *, void *),
+       void *private_data) { return -1; }
 static inline bool dmi_match(enum dmi_field f, const char *str)
        { return false; }
 static inline const struct dmi_system_id *
index a667637b54e3912783c9f1e086c57df74784e05b..f45a8ae5f8281bc51348b942a36899b8355f13d9 100644 (file)
 /* For O_CLOEXEC and O_NONBLOCK */
 #include <linux/fcntl.h>
 
-/* Flags for eventfd2.  */
+/*
+ * CAREFUL: Check include/asm-generic/fcntl.h when defining
+ * new flags, since they might collide with O_* ones. We want
+ * to re-use O_* flags that couldn't possibly have a meaning
+ * from eventfd, in order to leave a free define-space for
+ * shared O_* flags.
+ */
+#define EFD_SEMAPHORE (1 << 0)
 #define EFD_CLOEXEC O_CLOEXEC
 #define EFD_NONBLOCK O_NONBLOCK
 
+#define EFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK)
+#define EFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS | EFD_SEMAPHORE)
+
 struct file *eventfd_fget(int fd);
 int eventfd_signal(struct file *file, int n);
 
index dd495b8c3091e21b3b55a25e8c8294e07f611113..e263acaa405b8deba36ad227c745dfc2fc4c8fad 100644 (file)
@@ -893,9 +893,8 @@ extern int ext3_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                       u64 start, u64 len);
 
 /* ioctl.c */
-extern int ext3_ioctl (struct inode *, struct file *, unsigned int,
-                      unsigned long);
-extern long ext3_compat_ioctl (struct file *, unsigned int, unsigned long);
+extern long ext3_ioctl(struct file *, unsigned int, unsigned long);
+extern long ext3_compat_ioctl(struct file *, unsigned int, unsigned long);
 
 /* namei.c */
 extern int ext3_orphan_add(handle_t *, struct inode *);
index 31527e17076b7c8697dcf7fdeb9717d8dead779a..f563c50139325b98c11ec5ea492b36d9aa1b7ee3 100644 (file)
@@ -123,6 +123,7 @@ struct dentry;
 #define FB_ACCEL_TRIDENT_3DIMAGE 51    /* Trident 3DImage              */
 #define FB_ACCEL_TRIDENT_BLADE3D 52    /* Trident Blade3D              */
 #define FB_ACCEL_TRIDENT_BLADEXP 53    /* Trident BladeXP              */
+#define FB_ACCEL_CIRRUS_ALPINE   53    /* Cirrus Logic 543x/544x/5480  */
 #define FB_ACCEL_NEOMAGIC_NM2070 90    /* NeoMagic NM2070              */
 #define FB_ACCEL_NEOMAGIC_NM2090 91    /* NeoMagic NM2090              */
 #define FB_ACCEL_NEOMAGIC_NM2093 92    /* NeoMagic NM2093              */
@@ -960,15 +961,7 @@ extern struct fb_info *registered_fb[FB_MAX];
 extern int num_registered_fb;
 extern struct class *fb_class;
 
-static inline int lock_fb_info(struct fb_info *info)
-{
-       mutex_lock(&info->lock);
-       if (!info->fbops) {
-               mutex_unlock(&info->lock);
-               return 0;
-       }
-       return 1;
-}
+extern int lock_fb_info(struct fb_info *info);
 
 static inline void unlock_fb_info(struct fb_info *info)
 {
index 42436ae42f7022468fd3fc8f4a947b69f704a7ed..61211ad823fe6b4e251e048866751cffd4409741 100644 (file)
@@ -849,7 +849,7 @@ struct file {
 #define f_dentry       f_path.dentry
 #define f_vfsmnt       f_path.mnt
        const struct file_operations    *f_op;
-       spinlock_t              f_lock;  /* f_ep_links, f_flags */
+       spinlock_t              f_lock;  /* f_ep_links, f_flags, no IRQ */
        atomic_long_t           f_count;
        unsigned int            f_flags;
        fmode_t                 f_mode;
@@ -1878,6 +1878,7 @@ extern struct block_device *open_by_devnum(dev_t, fmode_t);
 extern void invalidate_bdev(struct block_device *);
 extern int sync_blockdev(struct block_device *bdev);
 extern struct super_block *freeze_bdev(struct block_device *);
+extern void emergency_thaw_all(void);
 extern int thaw_bdev(struct block_device *bdev, struct super_block *sb);
 extern int fsync_bdev(struct block_device *);
 extern int fsync_super(struct super_block *);
index a97c053d3a9ae2b9063da2b67c374be3145fd05a..18b467dbe278bf4b399274ff272355d2984530ce 100644 (file)
@@ -4,7 +4,10 @@
 #include <linux/path.h>
 
 struct fs_struct {
-       atomic_t count;
+       atomic_t count; /* This usage count is used by check_unsafe_exec() for
+                        * security checking purposes - therefore it may not be
+                        * incremented, except by clone(CLONE_FS).
+                        */
        rwlock_t lock;
        int umask;
        struct path root, pwd;
index d9051d717d27e6c96798ca34fe6600fe5f4189db..7ef1caf5026962c4e49ab7c8d3b68430645a60a1 100644 (file)
@@ -95,14 +95,15 @@ struct fsl_usb2_platform_data {
 #define FSL_USB2_PORT0_ENABLED 0x00000001
 #define FSL_USB2_PORT1_ENABLED 0x00000002
 
+struct spi_device;
+
 struct fsl_spi_platform_data {
        u32     initial_spmode; /* initial SPMODE value */
-       u16     bus_num;
+       s16     bus_num;
        bool    qe_mode;
        /* board specific information */
        u16     max_chipselect;
-       void    (*activate_cs)(u8 cs, u8 polarity);
-       void    (*deactivate_cs)(u8 cs, u8 polarity);
+       void    (*cs_control)(struct spi_device *spi, bool on);
        u32     sysclk;
 };
 
index 677432b9cb7e6e45dc98c400b304689d0cb4ca13..a7f8134c594ee5570008440980f349abbcb1944a 100644 (file)
@@ -379,6 +379,30 @@ struct ftrace_graph_ret {
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 
+/*
+ * Stack of return addresses for functions
+ * of a thread.
+ * Used in struct thread_info
+ */
+struct ftrace_ret_stack {
+       unsigned long ret;
+       unsigned long func;
+       unsigned long long calltime;
+};
+
+/*
+ * Primary handler of a function return.
+ * It relays on ftrace_return_to_handler.
+ * Defined in entry_32/64.S
+ */
+extern void return_to_handler(void);
+
+extern int
+ftrace_push_return_trace(unsigned long ret, unsigned long long time,
+                        unsigned long func, int *depth);
+extern void
+ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret);
+
 /*
  * Sometimes we don't want to trace a function with the function
  * graph tracer but we want them to keep traced by the usual function
index 13875ce9112ac0163b28e0816f20164e1ec39bae..7ff5c55f9b554120379baadd28be15cebbfe839a 100644 (file)
@@ -187,4 +187,16 @@ static inline void copy_highpage(struct page *to, struct page *from)
        kunmap_atomic(vto, KM_USER1);
 }
 
+#if defined(CONFIG_DEBUG_HIGHMEM) && defined(CONFIG_TRACE_IRQFLAGS_SUPPORT)
+
+void debug_kmap_atomic(enum km_type type);
+
+#else
+
+static inline void debug_kmap_atomic(enum km_type type)
+{
+}
+
+#endif
+
 #endif /* _LINUX_HIGHMEM_H */
index 1ffc23bc5d1e4051df980ee13f4700686629f24d..f27604af83784e9f90698edc5c04713ffc80231e 100644 (file)
@@ -71,6 +71,7 @@
 #define I2C_DRIVERID_VP27SMPX  93      /* Panasonic VP27s tuner internal MPX */
 #define I2C_DRIVERID_M52790    95      /* Mitsubishi M52790SP/FP AV switch */
 #define I2C_DRIVERID_CS5345    96      /* cs5345 audio processor       */
+#define I2C_DRIVERID_AU8522    97      /* Auvitek au8522       */
 
 #define I2C_DRIVERID_OV7670 1048       /* Omnivision 7670 camera */
 
@@ -87,6 +88,7 @@
 #define I2C_HW_B_CX2341X       0x010020 /* Conexant CX2341X MPEG encoder cards */
 #define I2C_HW_B_CX23885       0x010022 /* conexant 23885 based tv cards (bus1) */
 #define I2C_HW_B_AU0828                0x010023 /* auvitek au0828 usb bridge */
+#define I2C_HW_B_HDPVR         0x010025 /* Hauppauge HD PVR */
 
 /* --- SGI adapters                                                    */
 #define I2C_HW_SGI_VINO                0x160000
index f6edd522a929f0705b403328191c2fb8581aaebc..8ace93024d60f96cb054f404c3d6381b786eb105 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_AT24_H
 
 #include <linux/types.h>
+#include <linux/memory.h>
 
 /*
  * As seen through Linux I2C, differences between the most common types of I2C
@@ -23,6 +24,9 @@ struct at24_platform_data {
 #define AT24_FLAG_READONLY     0x40    /* sysfs-entry will be read-only */
 #define AT24_FLAG_IRUGO                0x20    /* sysfs-entry will be world-readable */
 #define AT24_FLAG_TAKE8ADDR    0x10    /* take always 8 addresses (24c00) */
+
+       void            (*setup)(struct memory_accessor *, void *context);
+       void            *context;
 };
 
 #endif /* _LINUX_AT24_H */
index 854eba8b2ba33f9c375d88e28fb80ef4e28b1a17..a5d26f66ef78b3b784b7ceebe32b459c09af4963 100644 (file)
 #define ERROR_RESET    3       /* Reset controller every 4th retry */
 #define ERROR_RECAL    1       /* Recalibrate every 2nd retry */
 
+/* Error codes returned in rq->errors to the higher part of the driver. */
+enum {
+       IDE_DRV_ERROR_GENERAL   = 101,
+       IDE_DRV_ERROR_FILEMARK  = 102,
+       IDE_DRV_ERROR_EOD       = 103,
+};
+
 /*
  * Definitions for accessing IDE controller registers
  */
@@ -193,26 +200,8 @@ static inline void ide_std_init_ports(hw_regs_t *hw,
        hw->io_ports.ctl_addr = ctl_addr;
 }
 
-#if defined(CONFIG_ARM) || defined(CONFIG_M68K) || defined(CONFIG_MIPS) || \
-    defined(CONFIG_PARISC) || defined(CONFIG_PPC) || defined(CONFIG_SPARC)
-#include <asm/ide.h>
-#else
-#include <asm-generic/ide_iops.h>
-#endif
-
 #define MAX_HWIFS      10
 
-/* Currently only m68k, apus and m8xx need it */
-#ifndef IDE_ARCH_ACK_INTR
-# define ide_ack_intr(hwif) (1)
-#endif
-
-/* Currently only Atari needs it */
-#ifndef IDE_ARCH_LOCK
-# define ide_release_lock()                    do {} while (0)
-# define ide_get_lock(hdlr, data)              do {} while (0)
-#endif /* IDE_ARCH_LOCK */
-
 /*
  * Now for the data we need to maintain per-drive:  ide_drive_t
  */
@@ -252,56 +241,52 @@ typedef enum {
 
 enum {
        IDE_TFLAG_LBA48                 = (1 << 0),
-       IDE_TFLAG_FLAGGED               = (1 << 2),
-       IDE_TFLAG_OUT_DATA              = (1 << 3),
-       IDE_TFLAG_OUT_HOB_FEATURE       = (1 << 4),
-       IDE_TFLAG_OUT_HOB_NSECT         = (1 << 5),
-       IDE_TFLAG_OUT_HOB_LBAL          = (1 << 6),
-       IDE_TFLAG_OUT_HOB_LBAM          = (1 << 7),
-       IDE_TFLAG_OUT_HOB_LBAH          = (1 << 8),
+       IDE_TFLAG_OUT_HOB_FEATURE       = (1 << 1),
+       IDE_TFLAG_OUT_HOB_NSECT         = (1 << 2),
+       IDE_TFLAG_OUT_HOB_LBAL          = (1 << 3),
+       IDE_TFLAG_OUT_HOB_LBAM          = (1 << 4),
+       IDE_TFLAG_OUT_HOB_LBAH          = (1 << 5),
        IDE_TFLAG_OUT_HOB               = IDE_TFLAG_OUT_HOB_FEATURE |
                                          IDE_TFLAG_OUT_HOB_NSECT |
                                          IDE_TFLAG_OUT_HOB_LBAL |
                                          IDE_TFLAG_OUT_HOB_LBAM |
                                          IDE_TFLAG_OUT_HOB_LBAH,
-       IDE_TFLAG_OUT_FEATURE           = (1 << 9),
-       IDE_TFLAG_OUT_NSECT             = (1 << 10),
-       IDE_TFLAG_OUT_LBAL              = (1 << 11),
-       IDE_TFLAG_OUT_LBAM              = (1 << 12),
-       IDE_TFLAG_OUT_LBAH              = (1 << 13),
+       IDE_TFLAG_OUT_FEATURE           = (1 << 6),
+       IDE_TFLAG_OUT_NSECT             = (1 << 7),
+       IDE_TFLAG_OUT_LBAL              = (1 << 8),
+       IDE_TFLAG_OUT_LBAM              = (1 << 9),
+       IDE_TFLAG_OUT_LBAH              = (1 << 10),
        IDE_TFLAG_OUT_TF                = IDE_TFLAG_OUT_FEATURE |
                                          IDE_TFLAG_OUT_NSECT |
                                          IDE_TFLAG_OUT_LBAL |
                                          IDE_TFLAG_OUT_LBAM |
                                          IDE_TFLAG_OUT_LBAH,
-       IDE_TFLAG_OUT_DEVICE            = (1 << 14),
-       IDE_TFLAG_WRITE                 = (1 << 15),
-       IDE_TFLAG_FLAGGED_SET_IN_FLAGS  = (1 << 16),
-       IDE_TFLAG_IN_DATA               = (1 << 17),
-       IDE_TFLAG_CUSTOM_HANDLER        = (1 << 18),
-       IDE_TFLAG_DMA_PIO_FALLBACK      = (1 << 19),
-       IDE_TFLAG_IN_HOB_FEATURE        = (1 << 20),
-       IDE_TFLAG_IN_HOB_NSECT          = (1 << 21),
-       IDE_TFLAG_IN_HOB_LBAL           = (1 << 22),
-       IDE_TFLAG_IN_HOB_LBAM           = (1 << 23),
-       IDE_TFLAG_IN_HOB_LBAH           = (1 << 24),
+       IDE_TFLAG_OUT_DEVICE            = (1 << 11),
+       IDE_TFLAG_WRITE                 = (1 << 12),
+       IDE_TFLAG_CUSTOM_HANDLER        = (1 << 13),
+       IDE_TFLAG_DMA_PIO_FALLBACK      = (1 << 14),
+       IDE_TFLAG_IN_HOB_ERROR          = (1 << 15),
+       IDE_TFLAG_IN_HOB_NSECT          = (1 << 16),
+       IDE_TFLAG_IN_HOB_LBAL           = (1 << 17),
+       IDE_TFLAG_IN_HOB_LBAM           = (1 << 18),
+       IDE_TFLAG_IN_HOB_LBAH           = (1 << 19),
        IDE_TFLAG_IN_HOB_LBA            = IDE_TFLAG_IN_HOB_LBAL |
                                          IDE_TFLAG_IN_HOB_LBAM |
                                          IDE_TFLAG_IN_HOB_LBAH,
-       IDE_TFLAG_IN_HOB                = IDE_TFLAG_IN_HOB_FEATURE |
+       IDE_TFLAG_IN_HOB                = IDE_TFLAG_IN_HOB_ERROR |
                                          IDE_TFLAG_IN_HOB_NSECT |
                                          IDE_TFLAG_IN_HOB_LBA,
-       IDE_TFLAG_IN_FEATURE            = (1 << 1),
-       IDE_TFLAG_IN_NSECT              = (1 << 25),
-       IDE_TFLAG_IN_LBAL               = (1 << 26),
-       IDE_TFLAG_IN_LBAM               = (1 << 27),
-       IDE_TFLAG_IN_LBAH               = (1 << 28),
+       IDE_TFLAG_IN_ERROR              = (1 << 20),
+       IDE_TFLAG_IN_NSECT              = (1 << 21),
+       IDE_TFLAG_IN_LBAL               = (1 << 22),
+       IDE_TFLAG_IN_LBAM               = (1 << 23),
+       IDE_TFLAG_IN_LBAH               = (1 << 24),
        IDE_TFLAG_IN_LBA                = IDE_TFLAG_IN_LBAL |
                                          IDE_TFLAG_IN_LBAM |
                                          IDE_TFLAG_IN_LBAH,
        IDE_TFLAG_IN_TF                 = IDE_TFLAG_IN_NSECT |
                                          IDE_TFLAG_IN_LBA,
-       IDE_TFLAG_IN_DEVICE             = (1 << 29),
+       IDE_TFLAG_IN_DEVICE             = (1 << 25),
        IDE_TFLAG_HOB                   = IDE_TFLAG_OUT_HOB |
                                          IDE_TFLAG_IN_HOB,
        IDE_TFLAG_TF                    = IDE_TFLAG_OUT_TF |
@@ -309,15 +294,28 @@ enum {
        IDE_TFLAG_DEVICE                = IDE_TFLAG_OUT_DEVICE |
                                          IDE_TFLAG_IN_DEVICE,
        /* force 16-bit I/O operations */
-       IDE_TFLAG_IO_16BIT              = (1 << 30),
-       /* ide_task_t was allocated using kmalloc() */
-       IDE_TFLAG_DYN                   = (1 << 31),
+       IDE_TFLAG_IO_16BIT              = (1 << 26),
+       /* struct ide_cmd was allocated using kmalloc() */
+       IDE_TFLAG_DYN                   = (1 << 27),
+       IDE_TFLAG_FS                    = (1 << 28),
+       IDE_TFLAG_MULTI_PIO             = (1 << 29),
+};
+
+enum {
+       IDE_FTFLAG_FLAGGED              = (1 << 0),
+       IDE_FTFLAG_SET_IN_FLAGS         = (1 << 1),
+       IDE_FTFLAG_OUT_DATA             = (1 << 2),
+       IDE_FTFLAG_IN_DATA              = (1 << 3),
 };
 
 struct ide_taskfile {
        u8      hob_data;       /*  0: high data byte (for TASKFILE IOCTL) */
+                               /*  1-5: additional data to support LBA48 */
+       union {
+               u8 hob_error;   /*   read: error */
+               u8 hob_feature; /*  write: feature */
+       };
 
-       u8      hob_feature;    /*  1-5: additional data to support LBA48 */
        u8      hob_nsect;
        u8      hob_lbal;
        u8      hob_lbam;
@@ -343,16 +341,29 @@ struct ide_taskfile {
        };
 };
 
-typedef struct ide_task_s {
+struct ide_cmd {
        union {
                struct ide_taskfile     tf;
                u8                      tf_array[14];
        };
+       u8                      ftf_flags;      /* for TASKFILE ioctl */
        u32                     tf_flags;
-       int                     data_phase;
+       int                     protocol;
+
+       int                     sg_nents;         /* number of sg entries */
+       int                     orig_sg_nents;
+       int                     sg_dma_direction; /* DMA transfer direction */
+
+       unsigned int            nbytes;
+       unsigned int            nleft;
+       unsigned int            last_xfer_len;
+
+       struct scatterlist      *cursg;
+       unsigned int            cursg_ofs;
+
        struct request          *rq;            /* copy of request */
        void                    *special;       /* valid_t generally */
-} ide_task_t;
+};
 
 /* ATAPI packet command flags */
 enum {
@@ -364,15 +375,13 @@ enum {
        PC_FLAG_DMA_IN_PROGRESS         = (1 << 4),
        PC_FLAG_DMA_ERROR               = (1 << 5),
        PC_FLAG_WRITING                 = (1 << 6),
-       /* command timed out */
-       PC_FLAG_TIMEDOUT                = (1 << 7),
 };
 
 /*
  * With each packet command, we allocate a buffer of IDE_PC_BUFFER_SIZE bytes.
  * This is used for several packet commands (not for READ/WRITE commands).
  */
-#define IDE_PC_BUFFER_SIZE     256
+#define IDE_PC_BUFFER_SIZE     64
 #define ATAPI_WAIT_PC          (60 * HZ)
 
 struct ide_atapi_pc {
@@ -410,9 +419,6 @@ struct ide_atapi_pc {
        struct idetape_bh *bh;
        char *b_data;
 
-       struct scatterlist *sg;
-       unsigned int sg_cnt;
-
        unsigned long timeout;
 };
 
@@ -436,7 +442,6 @@ struct ide_disk_ops {
                                        int);
        ide_startstop_t (*do_request)(struct ide_drive_s *, struct request *,
                                      sector_t);
-       int             (*end_request)(struct ide_drive_s *, int, int);
        int             (*ioctl)(struct ide_drive_s *, struct block_device *,
                                 fmode_t, unsigned int, unsigned long);
 };
@@ -454,11 +459,6 @@ enum {
        IDE_AFLAG_TOCADDR_AS_BCD        = (1 << 3),
        /* TOC track numbers are in BCD. */
        IDE_AFLAG_TOCTRACKS_AS_BCD      = (1 << 4),
-       /*
-        * Drive does not provide data in multiples of SECTOR_SIZE
-        * when more than one interrupt is needed.
-        */
-       IDE_AFLAG_LIMIT_NFRAMES         = (1 << 5),
        /* Saved TOC information is current. */
        IDE_AFLAG_TOC_VALID             = (1 << 6),
        /* We think that the drive door is locked. */
@@ -512,8 +512,6 @@ enum {
        IDE_DFLAG_NICE1                 = (1 << 5),
        /* device is physically present */
        IDE_DFLAG_PRESENT               = (1 << 6),
-       /* device ejected hint */
-       IDE_DFLAG_DEAD                  = (1 << 7),
        /* id read from device (synthetic if not set) */
        IDE_DFLAG_ID_READ               = (1 << 8),
        IDE_DFLAG_NOPROBE               = (1 << 9),
@@ -605,7 +603,7 @@ struct ide_drive_s {
 
        unsigned int    bios_cyl;       /* BIOS/fdisk/LILO number of cyls */
        unsigned int    cyl;            /* "real" number of cyls */
-       unsigned int    drive_data;     /* used by set_pio_mode/selectproc */
+       unsigned int    drive_data;     /* used by set_pio_mode/dev_select() */
        unsigned int    failures;       /* current failure count */
        unsigned int    max_failures;   /* maximum allowed failure count */
        u64             probed_capacity;/* initial reported media capacity (ide-cd only currently) */
@@ -627,8 +625,11 @@ struct ide_drive_s {
        /* current packet command */
        struct ide_atapi_pc *pc;
 
+       /* last failed packet command */
+       struct ide_atapi_pc *failed_pc;
+
        /* callback for packet commands */
-       void (*pc_callback)(struct ide_drive_s *, int);
+       int  (*pc_callback)(struct ide_drive_s *, int);
 
        void (*pc_update_buffers)(struct ide_drive_s *, struct ide_atapi_pc *);
        int  (*pc_io_buffers)(struct ide_drive_s *, struct ide_atapi_pc *,
@@ -658,16 +659,16 @@ struct ide_tp_ops {
        void    (*exec_command)(struct hwif_s *, u8);
        u8      (*read_status)(struct hwif_s *);
        u8      (*read_altstatus)(struct hwif_s *);
+       void    (*write_devctl)(struct hwif_s *, u8);
 
-       void    (*set_irq)(struct hwif_s *, int);
-
-       void    (*tf_load)(ide_drive_t *, struct ide_task_s *);
-       void    (*tf_read)(ide_drive_t *, struct ide_task_s *);
+       void    (*dev_select)(ide_drive_t *);
+       void    (*tf_load)(ide_drive_t *, struct ide_cmd *);
+       void    (*tf_read)(ide_drive_t *, struct ide_cmd *);
 
-       void    (*input_data)(ide_drive_t *, struct request *, void *,
-                             unsigned int);
-       void    (*output_data)(ide_drive_t *, struct request *, void *,
-                              unsigned int);
+       void    (*input_data)(ide_drive_t *, struct ide_cmd *,
+                             void *, unsigned int);
+       void    (*output_data)(ide_drive_t *, struct ide_cmd *,
+                              void *, unsigned int);
 };
 
 extern const struct ide_tp_ops default_tp_ops;
@@ -678,7 +679,6 @@ extern const struct ide_tp_ops default_tp_ops;
  * @init_dev:          host specific initialization of a device
  * @set_pio_mode:      routine to program host for PIO mode
  * @set_dma_mode:      routine to program host for DMA mode
- * @selectproc:                tweaks hardware to select drive
  * @reset_poll:                chipset polling based on hba specifics
  * @pre_reset:         chipset specific changes to default for device-hba resets
  * @resetproc:         routine to reset controller after a disk reset
@@ -695,7 +695,6 @@ struct ide_port_ops {
        void    (*init_dev)(ide_drive_t *);
        void    (*set_pio_mode)(ide_drive_t *, const u8);
        void    (*set_dma_mode)(ide_drive_t *, const u8);
-       void    (*selectproc)(ide_drive_t *);
        int     (*reset_poll)(ide_drive_t *);
        void    (*pre_reset)(ide_drive_t *);
        void    (*resetproc)(ide_drive_t *);
@@ -711,13 +710,15 @@ struct ide_port_ops {
 
 struct ide_dma_ops {
        void    (*dma_host_set)(struct ide_drive_s *, int);
-       int     (*dma_setup)(struct ide_drive_s *);
-       void    (*dma_exec_cmd)(struct ide_drive_s *, u8);
+       int     (*dma_setup)(struct ide_drive_s *, struct ide_cmd *);
        void    (*dma_start)(struct ide_drive_s *);
        int     (*dma_end)(struct ide_drive_s *);
        int     (*dma_test_irq)(struct ide_drive_s *);
        void    (*dma_lost_irq)(struct ide_drive_s *);
-       void    (*dma_timeout)(struct ide_drive_s *);
+       /* below ones are optional */
+       int     (*dma_check)(struct ide_drive_s *, struct ide_cmd *);
+       int     (*dma_timer_expiry)(struct ide_drive_s *);
+       void    (*dma_clear)(struct ide_drive_s *);
        /*
         * The following method is optional and only required to be
         * implemented for the SFF-8038i compatible controllers.
@@ -780,19 +781,8 @@ typedef struct hwif_s {
        /* Scatter-gather list used to build the above */
        struct scatterlist *sg_table;
        int sg_max_nents;               /* Maximum number of entries in it */
-       int sg_nents;                   /* Current number of entries in it */
-       int orig_sg_nents;
-       int sg_dma_direction;           /* dma transfer direction */
-
-       /* data phase of the active command (currently only valid for PIO/DMA) */
-       int             data_phase;
-
-       struct ide_task_s task;         /* current command */
 
-       unsigned int nsect;
-       unsigned int nleft;
-       struct scatterlist *cursg;
-       unsigned int cursg_ofs;
+       struct ide_cmd cmd;             /* current command */
 
        int             rqsize;         /* max sectors per request */
        int             irq;            /* our irq number */
@@ -850,9 +840,18 @@ struct ide_host {
        ide_hwif_t      *ports[MAX_HOST_PORTS + 1];
        unsigned int    n_ports;
        struct device   *dev[2];
+
        int             (*init_chipset)(struct pci_dev *);
+
+       void            (*get_lock)(irq_handler_t, void *);
+       void            (*release_lock)(void);
+
        irq_handler_t   irq_handler;
+
        unsigned long   host_flags;
+
+       int             irq_flags;
+
        void            *host_priv;
        ide_hwif_t      *cur_port;      /* for hosts requiring serialization */
 
@@ -869,7 +868,7 @@ typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
 typedef int (ide_expiry_t)(ide_drive_t *);
 
 /* used by ide-cd, ide-floppy, etc. */
-typedef void (xfer_func_t)(ide_drive_t *, struct request *rq, void *, unsigned);
+typedef void (xfer_func_t)(ide_drive_t *, struct ide_cmd *, void *, unsigned);
 
 extern struct mutex ide_setting_mtx;
 
@@ -1045,10 +1044,11 @@ enum {
 };
 
 /* DRV_NAME has to be defined in the driver before using the macro below */
-#define __ide_debug_log(lvl, fmt, args...)                     \
-{                                                              \
-       if (unlikely(drive->debug_mask & lvl))                  \
-               printk(KERN_INFO DRV_NAME ": " fmt, ## args);   \
+#define __ide_debug_log(lvl, fmt, args...)                             \
+{                                                                      \
+       if (unlikely(drive->debug_mask & lvl))                          \
+               printk(KERN_INFO DRV_NAME ": %s: " fmt "\n",            \
+                                         __func__, ## args);           \
 }
 
 /*
@@ -1087,7 +1087,7 @@ int generic_ide_resume(struct device *);
 
 void ide_complete_power_step(ide_drive_t *, struct request *);
 ide_startstop_t ide_start_power_step(ide_drive_t *, struct request *);
-void ide_complete_pm_request(ide_drive_t *, struct request *);
+void ide_complete_pm_rq(ide_drive_t *, struct request *);
 void ide_check_pm_state(ide_drive_t *, struct request *);
 
 /*
@@ -1099,7 +1099,6 @@ void ide_check_pm_state(ide_drive_t *, struct request *);
 struct ide_driver {
        const char                      *version;
        ide_startstop_t (*do_request)(ide_drive_t *, struct request *, sector_t);
-       int             (*end_request)(ide_drive_t *, int, int);
        struct device_driver    gen_driver;
        int             (*probe)(ide_drive_t *);
        void            (*remove)(ide_drive_t *);
@@ -1130,19 +1129,15 @@ int generic_ide_ioctl(ide_drive_t *, struct block_device *, unsigned, unsigned l
 extern int ide_vlb_clk;
 extern int ide_pci_clk;
 
-int ide_end_request(ide_drive_t *, int, int);
-int ide_end_dequeued_request(ide_drive_t *, struct request *, int, int);
+unsigned int ide_rq_bytes(struct request *);
+int ide_end_rq(ide_drive_t *, struct request *, int, unsigned int);
 void ide_kill_rq(ide_drive_t *, struct request *);
 
-void __ide_set_handler(ide_drive_t *, ide_handler_t *, unsigned int,
-                      ide_expiry_t *);
-void ide_set_handler(ide_drive_t *, ide_handler_t *, unsigned int,
-                    ide_expiry_t *);
-
-void ide_execute_command(ide_drive_t *, u8, ide_handler_t *, unsigned int,
-                        ide_expiry_t *);
+void __ide_set_handler(ide_drive_t *, ide_handler_t *, unsigned int);
+void ide_set_handler(ide_drive_t *, ide_handler_t *, unsigned int);
 
-void ide_execute_pkt_cmd(ide_drive_t *);
+void ide_execute_command(ide_drive_t *, struct ide_cmd *, ide_handler_t *,
+                        unsigned int);
 
 void ide_pad_transfer(ide_drive_t *, int, int);
 
@@ -1164,25 +1159,23 @@ extern ide_startstop_t ide_do_reset (ide_drive_t *);
 extern int ide_devset_execute(ide_drive_t *drive,
                              const struct ide_devset *setting, int arg);
 
-extern void ide_end_drive_cmd(ide_drive_t *, u8, u8);
+void ide_complete_cmd(ide_drive_t *, struct ide_cmd *, u8, u8);
+int ide_complete_rq(ide_drive_t *, int, unsigned int);
 
 void ide_tf_dump(const char *, struct ide_taskfile *);
 
 void ide_exec_command(ide_hwif_t *, u8);
 u8 ide_read_status(ide_hwif_t *);
 u8 ide_read_altstatus(ide_hwif_t *);
+void ide_write_devctl(ide_hwif_t *, u8);
 
-void ide_set_irq(ide_hwif_t *, int);
-
-void ide_tf_load(ide_drive_t *, ide_task_t *);
-void ide_tf_read(ide_drive_t *, ide_task_t *);
+void ide_dev_select(ide_drive_t *);
+void ide_tf_load(ide_drive_t *, struct ide_cmd *);
+void ide_tf_read(ide_drive_t *, struct ide_cmd *);
 
-void ide_input_data(ide_drive_t *, struct request *, void *, unsigned int);
-void ide_output_data(ide_drive_t *, struct request *, void *, unsigned int);
+void ide_input_data(ide_drive_t *, struct ide_cmd *, void *, unsigned int);
+void ide_output_data(ide_drive_t *, struct ide_cmd *, void *, unsigned int);
 
-int ide_io_buffers(ide_drive_t *, struct ide_atapi_pc *, unsigned int, int);
-
-extern void SELECT_DRIVE(ide_drive_t *);
 void SELECT_MASK(ide_drive_t *, int);
 
 u8 ide_read_error(ide_drive_t *);
@@ -1224,16 +1217,18 @@ int ide_cd_expiry(ide_drive_t *);
 
 int ide_cd_get_xferlen(struct request *);
 
-ide_startstop_t ide_issue_pc(ide_drive_t *);
+ide_startstop_t ide_issue_pc(ide_drive_t *, struct ide_cmd *);
+
+ide_startstop_t do_rw_taskfile(ide_drive_t *, struct ide_cmd *);
 
-ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *);
+void ide_pio_bytes(ide_drive_t *, struct ide_cmd *, unsigned int, unsigned int);
 
-void task_end_request(ide_drive_t *, struct request *, u8);
+void ide_finish_cmd(ide_drive_t *, struct ide_cmd *, u8);
 
-int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *, u16);
-int ide_no_data_taskfile(ide_drive_t *, ide_task_t *);
+int ide_raw_taskfile(ide_drive_t *, struct ide_cmd *, u8 *, u16);
+int ide_no_data_taskfile(ide_drive_t *, struct ide_cmd *);
 
-int ide_taskfile_ioctl(ide_drive_t *, unsigned int, unsigned long);
+int ide_taskfile_ioctl(ide_drive_t *, unsigned long);
 
 int ide_dev_read_id(ide_drive_t *, u8, u16 *);
 
@@ -1335,6 +1330,10 @@ enum {
        IDE_HFLAG_ERROR_STOPS_FIFO      = (1 << 19),
        /* serialize ports */
        IDE_HFLAG_SERIALIZE             = (1 << 20),
+       /* host is DTC2278 */
+       IDE_HFLAG_DTC2278               = (1 << 21),
+       /* 4 devices on a single set of I/O ports */
+       IDE_HFLAG_4DRIVES               = (1 << 22),
        /* host is TRM290 */
        IDE_HFLAG_TRM290                = (1 << 23),
        /* use 32-bit I/O ops */
@@ -1362,7 +1361,12 @@ enum {
 
 struct ide_port_info {
        char                    *name;
+
        int                     (*init_chipset)(struct pci_dev *);
+
+       void                    (*get_lock)(irq_handler_t, void *);
+       void                    (*release_lock)(void);
+
        void                    (*init_iops)(ide_hwif_t *);
        void                    (*init_hwif)(ide_hwif_t *);
        int                     (*init_dma)(ide_hwif_t *,
@@ -1379,6 +1383,9 @@ struct ide_port_info {
        u16                     max_sectors;    /* if < than the default one */
 
        u32                     host_flags;
+
+       int                     irq_flags;
+
        u8                      pio_mask;
        u8                      swdma_mask;
        u8                      mwdma_mask;
@@ -1398,8 +1405,8 @@ int ide_pci_resume(struct pci_dev *);
 #define ide_pci_resume NULL
 #endif
 
-void ide_map_sg(ide_drive_t *, struct request *);
-void ide_init_sg_cmd(ide_drive_t *, struct request *);
+void ide_map_sg(ide_drive_t *, struct ide_cmd *);
+void ide_init_sg_cmd(struct ide_cmd *, unsigned int);
 
 #define BAD_DMA_DRIVE          0
 #define GOOD_DMA_DRIVE         1
@@ -1433,18 +1440,18 @@ ide_startstop_t ide_dma_intr(ide_drive_t *);
 int ide_allocate_dma_engine(ide_hwif_t *);
 void ide_release_dma_engine(ide_hwif_t *);
 
-int ide_build_sglist(ide_drive_t *, struct request *);
-void ide_destroy_dmatable(ide_drive_t *);
+int ide_dma_prepare(ide_drive_t *, struct ide_cmd *);
+void ide_dma_unmap_sg(ide_drive_t *, struct ide_cmd *);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_SFF
 int config_drive_for_dma(ide_drive_t *);
-extern int ide_build_dmatable(ide_drive_t *, struct request *);
+int ide_build_dmatable(ide_drive_t *, struct ide_cmd *);
 void ide_dma_host_set(ide_drive_t *, int);
-extern int ide_dma_setup(ide_drive_t *);
-void ide_dma_exec_cmd(ide_drive_t *, u8);
+int ide_dma_setup(ide_drive_t *, struct ide_cmd *);
 extern void ide_dma_start(ide_drive_t *);
 int ide_dma_end(ide_drive_t *);
 int ide_dma_test_irq(ide_drive_t *);
+int ide_dma_sff_timer_expiry(ide_drive_t *);
 u8 ide_dma_sff_read_status(ide_hwif_t *);
 extern const struct ide_dma_ops sff_dma_ops;
 #else
@@ -1452,7 +1459,6 @@ static inline int config_drive_for_dma(ide_drive_t *drive) { return 0; }
 #endif /* CONFIG_BLK_DEV_IDEDMA_SFF */
 
 void ide_dma_lost_irq(ide_drive_t *);
-void ide_dma_timeout(ide_drive_t *);
 ide_startstop_t ide_dma_timeout_retry(ide_drive_t *, int);
 
 #else
@@ -1465,8 +1471,13 @@ static inline void ide_dma_on(ide_drive_t *drive) { ; }
 static inline void ide_dma_verbose(ide_drive_t *drive) { ; }
 static inline int ide_set_dma(ide_drive_t *drive) { return 1; }
 static inline void ide_check_dma_crc(ide_drive_t *drive) { ; }
+static inline ide_startstop_t ide_dma_intr(ide_drive_t *drive) { return ide_stopped; }
 static inline ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) { return ide_stopped; }
 static inline void ide_release_dma_engine(ide_hwif_t *hwif) { ; }
+static inline int ide_dma_prepare(ide_drive_t *drive,
+                                 struct ide_cmd *cmd) { return 1; }
+static inline void ide_dma_unmap_sg(ide_drive_t *drive,
+                                   struct ide_cmd *cmd) { ; }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 #ifdef CONFIG_BLK_DEV_IDEACPI
index dd846df8cd32182f6740ea59f6451079deb3060d..e968db71e33a94548160cb38c216289ab1577c30 100644 (file)
@@ -106,6 +106,7 @@ int idr_get_new(struct idr *idp, void *ptr, int *id);
 int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
 int idr_for_each(struct idr *idp,
                 int (*fn)(int id, void *p, void *data), void *data);
+void *idr_get_next(struct idr *idp, int *nextid);
 void *idr_replace(struct idr *idp, void *ptr, int id);
 void idr_remove(struct idr *idp, int id);
 void idr_remove_all(struct idr *idp);
index d2e3cbfba14f45ea30b34bc78e36735c5db2755d..1d6c71d96edeac0d730fb178e91120bebe695300 100644 (file)
@@ -292,6 +292,8 @@ struct intel_iommu {
        spinlock_t      register_lock; /* protect register handling */
        int             seq_id; /* sequence id of the iommu */
        int             agaw; /* agaw of this iommu */
+       unsigned int    irq;
+       unsigned char   name[13];    /* Device Name */
 
 #ifdef CONFIG_DMAR
        unsigned long   *domain_ids; /* bitmap of domains */
@@ -299,8 +301,6 @@ struct intel_iommu {
        spinlock_t      lock; /* protect context, domain ids */
        struct root_entry *root_entry; /* virtual address */
 
-       unsigned int irq;
-       unsigned char name[7];    /* Device Name */
        struct iommu_flush flush;
 #endif
        struct q_inval  *qi;            /* Queued invalidation info */
@@ -321,6 +321,7 @@ extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev);
 extern int alloc_iommu(struct dmar_drhd_unit *drhd);
 extern void free_iommu(struct intel_iommu *iommu);
 extern int dmar_enable_qi(struct intel_iommu *iommu);
+extern void dmar_disable_qi(struct intel_iommu *iommu);
 extern void qi_global_iec(struct intel_iommu *iommu);
 
 extern int qi_flush_context(struct intel_iommu *iommu, u16 did, u16 sid,
@@ -331,11 +332,4 @@ extern int qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr,
 
 extern int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu);
 
-extern void *intel_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t);
-extern void intel_free_coherent(struct device *, size_t, void *, dma_addr_t);
-extern dma_addr_t intel_map_single(struct device *, phys_addr_t, size_t, int);
-extern void intel_unmap_single(struct device *, dma_addr_t, size_t, int);
-extern int intel_map_sg(struct device *, struct scatterlist *, int, int);
-extern void intel_unmap_sg(struct device *, struct scatterlist *, int, int);
-
 #endif
index 0c9cb63e689530cfbc6a060b8a0b07ff2175bd62..c68bffd182bbe4d977848fd3507150da83be4d7b 100644 (file)
@@ -117,6 +117,15 @@ extern void disable_irq_nosync(unsigned int irq);
 extern void disable_irq(unsigned int irq);
 extern void enable_irq(unsigned int irq);
 
+/* The following three functions are for the core kernel use only. */
+extern void suspend_device_irqs(void);
+extern void resume_device_irqs(void);
+#ifdef CONFIG_PM_SLEEP
+extern int check_wakeup_irqs(void);
+#else
+static inline int check_wakeup_irqs(void) { return 0; }
+#endif
+
 #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS)
 
 extern cpumask_var_t irq_default_affinity;
index 62b73668b60247c06da84bc8cca6919a9a34f6d6..f7c9c75a277547e7a6e8278d6f4da77a62eb3746 100644 (file)
@@ -230,6 +230,6 @@ static inline void ipmi_free_smi_msg(struct ipmi_smi_msg *msg)
    automatically be dstroyed when the interface is destroyed. */
 int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
                            read_proc_t *read_proc,
-                           void *data, struct module *owner);
+                           void *data);
 
 #endif /* __LINUX_IPMI_SMI_H */
index 873e4ac11b813accc72c6699265b039f62e7c575..974890b3c52fbfe0048df3cf7d736798caf873b6 100644 (file)
 #include <linux/cache.h>
 #include <linux/spinlock.h>
 #include <linux/cpumask.h>
+#include <linux/gfp.h>
 #include <linux/irqreturn.h>
 #include <linux/irqnr.h>
 #include <linux/errno.h>
+#include <linux/topology.h>
 
 #include <asm/irq.h>
 #include <asm/ptrace.h>
@@ -65,6 +67,7 @@ typedef       void (*irq_flow_handler_t)(unsigned int irq,
 #define IRQ_SPURIOUS_DISABLED  0x00800000      /* IRQ was disabled by the spurious trap */
 #define IRQ_MOVE_PCNTXT                0x01000000      /* IRQ migration from process context */
 #define IRQ_AFFINITY_SET       0x02000000      /* IRQ affinity was set from userspace*/
+#define IRQ_SUSPENDED          0x04000000      /* IRQ has gone through suspend sequence */
 
 #ifdef CONFIG_IRQ_PER_CPU
 # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
index f2720280b9ec5e12d596baf2e4e8a63a890dc364..062d20f74322795c08fc7651409259f7387c4fe4 100644 (file)
@@ -60,10 +60,10 @@ struct ivtv_dma_frame {
 
 #define IVTV_IOC_DMA_FRAME  _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtv_dma_frame)
 
-/* These are the VBI types as they appear in the embedded VBI private packets. */
-#define IVTV_SLICED_TYPE_TELETEXT_B     (1)
-#define IVTV_SLICED_TYPE_CAPTION_525    (4)
-#define IVTV_SLICED_TYPE_WSS_625        (5)
-#define IVTV_SLICED_TYPE_VPS            (7)
+/* Deprecated defines: applications should use the defines from videodev2.h */
+#define IVTV_SLICED_TYPE_TELETEXT_B     V4L2_MPEG_VBI_IVTV_TELETEXT_B
+#define IVTV_SLICED_TYPE_CAPTION_525    V4L2_MPEG_VBI_IVTV_CAPTION_525
+#define IVTV_SLICED_TYPE_WSS_625        V4L2_MPEG_VBI_IVTV_WSS_625
+#define IVTV_SLICED_TYPE_VPS            V4L2_MPEG_VBI_IVTV_VPS
 
 #endif /* _LINUX_IVTV_H */
index 4d248b3f1323d828170a9de92d2aba1db7c5f0f4..8815a3456b3bf9a78915cabed347779667aefba3 100644 (file)
@@ -648,6 +648,12 @@ struct transaction_s
         */
        int t_handle_count;
 
+       /*
+        * This transaction is being forced and some process is
+        * waiting for it to finish.
+        */
+       int t_synchronous_commit:1;
+
        /*
         * For use by the filesystem to store fs-specific data
         * structures associated with the transaction
index f81d80f47dcbc14b93628df8b2bb43ad76e0db46..556d781e69fe2220fd88696de68da014ae963d12 100644 (file)
@@ -242,6 +242,7 @@ extern struct ratelimit_state printk_ratelimit_state;
 extern int printk_ratelimit(void);
 extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
                                   unsigned int interval_msec);
+void log_buf_kexec_setup(void);
 #else
 static inline int vprintk(const char *s, va_list args)
        __attribute__ ((format (printf, 1, 0)));
@@ -253,6 +254,9 @@ static inline int printk_ratelimit(void) { return 0; }
 static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies, \
                                          unsigned int interval_msec)   \
                { return false; }
+static inline void log_buf_kexec_setup(void)
+{
+}
 #endif
 
 extern int printk_needs_cpu(int cpu);
@@ -353,6 +357,8 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
         printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
 #define pr_info(fmt, ...) \
         printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_cont(fmt, ...) \
+       printk(KERN_CONT fmt, ##__VA_ARGS__)
 
 /* If you are writing a driver, please use dev_dbg instead */
 #if defined(DEBUG)
index 23bf02fb124ffae0dfb282453582385ea34d1919..da5a5a1f4cd2ec17fb2a5f544cc71f8e800b2d10 100644 (file)
@@ -20,43 +20,10 @@ struct lockdep_map;
 #include <linux/stacktrace.h>
 
 /*
- * Lock-class usage-state bits:
+ * We'd rather not expose kernel/lockdep_states.h this wide, but we do need
+ * the total number of states... :-(
  */
-enum lock_usage_bit
-{
-       LOCK_USED = 0,
-       LOCK_USED_IN_HARDIRQ,
-       LOCK_USED_IN_SOFTIRQ,
-       LOCK_ENABLED_SOFTIRQS,
-       LOCK_ENABLED_HARDIRQS,
-       LOCK_USED_IN_HARDIRQ_READ,
-       LOCK_USED_IN_SOFTIRQ_READ,
-       LOCK_ENABLED_SOFTIRQS_READ,
-       LOCK_ENABLED_HARDIRQS_READ,
-       LOCK_USAGE_STATES
-};
-
-/*
- * Usage-state bitmasks:
- */
-#define LOCKF_USED                     (1 << LOCK_USED)
-#define LOCKF_USED_IN_HARDIRQ          (1 << LOCK_USED_IN_HARDIRQ)
-#define LOCKF_USED_IN_SOFTIRQ          (1 << LOCK_USED_IN_SOFTIRQ)
-#define LOCKF_ENABLED_HARDIRQS         (1 << LOCK_ENABLED_HARDIRQS)
-#define LOCKF_ENABLED_SOFTIRQS         (1 << LOCK_ENABLED_SOFTIRQS)
-
-#define LOCKF_ENABLED_IRQS (LOCKF_ENABLED_HARDIRQS | LOCKF_ENABLED_SOFTIRQS)
-#define LOCKF_USED_IN_IRQ (LOCKF_USED_IN_HARDIRQ | LOCKF_USED_IN_SOFTIRQ)
-
-#define LOCKF_USED_IN_HARDIRQ_READ     (1 << LOCK_USED_IN_HARDIRQ_READ)
-#define LOCKF_USED_IN_SOFTIRQ_READ     (1 << LOCK_USED_IN_SOFTIRQ_READ)
-#define LOCKF_ENABLED_HARDIRQS_READ    (1 << LOCK_ENABLED_HARDIRQS_READ)
-#define LOCKF_ENABLED_SOFTIRQS_READ    (1 << LOCK_ENABLED_SOFTIRQS_READ)
-
-#define LOCKF_ENABLED_IRQS_READ \
-               (LOCKF_ENABLED_HARDIRQS_READ | LOCKF_ENABLED_SOFTIRQS_READ)
-#define LOCKF_USED_IN_IRQ_READ \
-               (LOCKF_USED_IN_HARDIRQ_READ | LOCKF_USED_IN_SOFTIRQ_READ)
+#define XXX_LOCK_USAGE_STATES          (1+3*4)
 
 #define MAX_LOCKDEP_SUBCLASSES         8UL
 
@@ -97,7 +64,7 @@ struct lock_class {
         * IRQ/softirq usage tracking bits:
         */
        unsigned long                   usage_mask;
-       struct stack_trace              usage_traces[LOCK_USAGE_STATES];
+       struct stack_trace              usage_traces[XXX_LOCK_USAGE_STATES];
 
        /*
         * These fields represent a directed graph of lock dependencies,
@@ -324,7 +291,11 @@ static inline void lock_set_subclass(struct lockdep_map *lock,
        lock_set_class(lock, lock->name, lock->key, subclass, ip);
 }
 
-# define INIT_LOCKDEP                          .lockdep_recursion = 0,
+extern void lockdep_set_current_reclaim_state(gfp_t gfp_mask);
+extern void lockdep_clear_current_reclaim_state(void);
+extern void lockdep_trace_alloc(gfp_t mask);
+
+# define INIT_LOCKDEP                          .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
 
 #define lockdep_depth(tsk)     (debug_locks ? (tsk)->lockdep_depth : 0)
 
@@ -342,6 +313,9 @@ static inline void lockdep_on(void)
 # define lock_release(l, n, i)                 do { } while (0)
 # define lock_set_class(l, n, k, s, i)         do { } while (0)
 # define lock_set_subclass(l, s, i)            do { } while (0)
+# define lockdep_set_current_reclaim_state(g)  do { } while (0)
+# define lockdep_clear_current_reclaim_state() do { } while (0)
+# define lockdep_trace_alloc(g)                        do { } while (0)
 # define lockdep_init()                                do { } while (0)
 # define lockdep_info()                                do { } while (0)
 # define lockdep_init_map(lock, name, key, sub) \
@@ -390,6 +364,23 @@ do {                                                               \
 
 #endif /* CONFIG_LOCK_STAT */
 
+#ifdef CONFIG_LOCKDEP
+
+/*
+ * On lockdep we dont want the hand-coded irq-enable of
+ * _raw_*_lock_flags() code, because lockdep assumes
+ * that interrupts are not re-enabled during lock-acquire:
+ */
+#define LOCK_CONTENDED_FLAGS(_lock, try, lock, lockfl, flags) \
+       LOCK_CONTENDED((_lock), (try), (lock))
+
+#else /* CONFIG_LOCKDEP */
+
+#define LOCK_CONTENDED_FLAGS(_lock, try, lock, lockfl, flags) \
+       lockfl((_lock), (flags))
+
+#endif /* CONFIG_LOCKDEP */
+
 #ifdef CONFIG_GENERIC_HARDIRQS
 extern void early_init_irq_lock_class(void);
 #else
index 6ffd6db5bb0d746c2a92deb358c450b2989b5c61..40725447f5e0e958ef58097636603f00ca3d04e0 100644 (file)
@@ -160,5 +160,6 @@ int loop_unregister_transfer(int number);
 #define LOOP_SET_STATUS64      0x4C04
 #define LOOP_GET_STATUS64      0x4C05
 #define LOOP_CHANGE_FD         0x4C06
+#define LOOP_SET_CAPACITY      0x4C07
 
 #endif
index 326f45c86530302c6e94ba8a872971bf7474646c..18146c980b68b33d5aafdd8403531f5548dd545a 100644 (file)
@@ -88,9 +88,6 @@ extern void mem_cgroup_end_migration(struct mem_cgroup *mem,
 /*
  * For memory reclaim.
  */
-extern int mem_cgroup_calc_mapped_ratio(struct mem_cgroup *mem);
-extern long mem_cgroup_reclaim_imbalance(struct mem_cgroup *mem);
-
 extern int mem_cgroup_get_reclaim_priority(struct mem_cgroup *mem);
 extern void mem_cgroup_note_reclaim_priority(struct mem_cgroup *mem,
                                                        int priority);
@@ -104,6 +101,8 @@ struct zone_reclaim_stat *mem_cgroup_get_reclaim_stat(struct mem_cgroup *memcg,
                                                      struct zone *zone);
 struct zone_reclaim_stat*
 mem_cgroup_get_reclaim_stat_from_page(struct page *page);
+extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg,
+                                       struct task_struct *p);
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
 extern int do_swap_account;
@@ -209,16 +208,6 @@ static inline void mem_cgroup_end_migration(struct mem_cgroup *mem,
 {
 }
 
-static inline int mem_cgroup_calc_mapped_ratio(struct mem_cgroup *mem)
-{
-       return 0;
-}
-
-static inline int mem_cgroup_reclaim_imbalance(struct mem_cgroup *mem)
-{
-       return 0;
-}
-
 static inline int mem_cgroup_get_reclaim_priority(struct mem_cgroup *mem)
 {
        return 0;
@@ -270,6 +259,11 @@ mem_cgroup_get_reclaim_stat_from_page(struct page *page)
        return NULL;
 }
 
+static inline void
+mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
+{
+}
+
 #endif /* CONFIG_CGROUP_MEM_CONT */
 
 #endif /* _LINUX_MEMCONTROL_H */
index 3fdc10806d31b9f55470dc3fc3949653ceb1498d..42767d1a62e784e9ce25dfbc9cc37ab9232f226a 100644 (file)
@@ -99,4 +99,15 @@ enum mem_add_context { BOOT, HOTPLUG };
 #define hotplug_memory_notifier(fn, pri) do { } while (0)
 #endif
 
+/*
+ * 'struct memory_accessor' is a generic interface to provide
+ * in-kernel access to persistent memory such as i2c or SPI EEPROMs
+ */
+struct memory_accessor {
+       ssize_t (*read)(struct memory_accessor *, char *buf, off_t offset,
+                       size_t count);
+       ssize_t (*write)(struct memory_accessor *, const char *buf,
+                        off_t offset, size_t count);
+};
+
 #endif /* _LINUX_MEMORY_H_ */
index 065cdf8c09fb50fcce6ff67bcae848ac555c6b7a..bff1f0d475c7593240d5a464ae8ecc7c03e07299 100644 (file)
@@ -104,6 +104,7 @@ extern unsigned int kobjsize(const void *objp);
 #define VM_CAN_NONLINEAR 0x08000000    /* Has ->fault & does nonlinear pages */
 #define VM_MIXEDMAP    0x10000000      /* Can contain "struct page" and pure PFN pages */
 #define VM_SAO         0x20000000      /* Strong Access Ordering (powerpc) */
+#define VM_PFN_AT_MMAP 0x40000000      /* PFNMAP vma that is fully mapped at mmap time */
 
 #ifndef VM_STACK_DEFAULT_FLAGS         /* arch can override this */
 #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
@@ -134,6 +135,7 @@ extern pgprot_t protection_map[16];
 
 #define FAULT_FLAG_WRITE       0x01    /* Fault was a write access */
 #define FAULT_FLAG_NONLINEAR   0x02    /* Fault was via a nonlinear mapping */
+#define FAULT_FLAG_MKWRITE     0x04    /* Fault was mkwrite of existing pte */
 
 /*
  * This interface is used by x86 PAT code to identify a pfn mapping that is
@@ -145,7 +147,7 @@ extern pgprot_t protection_map[16];
  */
 static inline int is_linear_pfn_mapping(struct vm_area_struct *vma)
 {
-       return ((vma->vm_flags & VM_PFNMAP) && vma->vm_pgoff);
+       return (vma->vm_flags & VM_PFN_AT_MMAP);
 }
 
 static inline int is_pfn_mapping(struct vm_area_struct *vma)
@@ -186,7 +188,7 @@ struct vm_operations_struct {
 
        /* notification that a previously read-only page is about to become
         * writable, if an error is returned it will cause a SIGBUS */
-       int (*page_mkwrite)(struct vm_area_struct *vma, struct page *page);
+       int (*page_mkwrite)(struct vm_area_struct *vma, struct vm_fault *vmf);
 
        /* called by access_process_vm when get_user_pages() fails, typically
         * for use by special VMAs that can switch between memory and hardware
@@ -833,6 +835,7 @@ int __set_page_dirty_nobuffers(struct page *page);
 int __set_page_dirty_no_writeback(struct page *page);
 int redirty_page_for_writepage(struct writeback_control *wbc,
                                struct page *page);
+void account_page_dirtied(struct page *page, struct address_space *mapping);
 int set_page_dirty(struct page *page);
 int set_page_dirty_lock(struct page *page);
 int clear_page_dirty_for_io(struct page *page);
@@ -1076,7 +1079,7 @@ static inline void setup_per_cpu_pageset(void) {}
 #endif
 
 /* nommu.c */
-extern atomic_t mmap_pages_allocated;
+extern atomic_long_t mmap_pages_allocated;
 
 /* prio_tree.c */
 void vma_prio_tree_add(struct vm_area_struct *, struct vm_area_struct *old);
index d84feb7bdbf00b8fa054364c7fa2d80d2a20b2a6..0e80e26ecf21220104d8d2abbeb9cca6a1215e6e 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/rwsem.h>
 #include <linux/completion.h>
 #include <linux/cpumask.h>
+#include <linux/page-debug-flags.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
 
@@ -94,6 +95,9 @@ struct page {
        void *virtual;                  /* Kernel virtual address (NULL if
                                           not kmapped, ie. highmem) */
 #endif /* WANT_PAGE_VIRTUAL */
+#ifdef CONFIG_WANT_PAGE_DEBUG_FLAGS
+       unsigned long debug_flags;      /* Use atomic bitops on this */
+#endif
 };
 
 /*
index 1aca6cebbb78916aaeb4764b3ec7e7da3276cf91..26ef24076b76a391e94fb395dfc3c820da545155 100644 (file)
@@ -806,6 +806,14 @@ extern struct zone *next_zone(struct zone *zone);
             zone;                                      \
             zone = next_zone(zone))
 
+#define for_each_populated_zone(zone)                  \
+       for (zone = (first_online_pgdat())->node_zones; \
+            zone;                                      \
+            zone = next_zone(zone))                    \
+               if (!populated_zone(zone))              \
+                       ; /* do nothing */              \
+               else
+
 static inline struct zone *zonelist_zone(struct zoneref *zoneref)
 {
        return zoneref->zone;
index d2b8a1e8ca11000cf622717ab3302bf9a64888c3..6991ab5b24d1bbfd736df4d27315a83ee7271779 100644 (file)
@@ -20,20 +20,23 @@ extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
 
 struct msi_desc {
        struct {
-               __u8    type    : 5;    /* {0: unused, 5h:MSI, 11h:MSI-X} */
+               __u8    is_msix : 1;
+               __u8    multiple: 3;    /* log2 number of messages */
                __u8    maskbit : 1;    /* mask-pending bit supported ?   */
-               __u8    masked  : 1;
                __u8    is_64   : 1;    /* Address size: 0=32bit 1=64bit  */
                __u8    pos;            /* Location of the msi capability */
-               __u32   maskbits_mask;  /* mask bits mask */
                __u16   entry_nr;       /* specific enabled entry         */
                unsigned default_irq;   /* default pre-assigned irq       */
-       }msi_attrib;
+       } msi_attrib;
 
+       u32 masked;                     /* mask bits */
        unsigned int irq;
        struct list_head list;
 
-       void __iomem *mask_base;
+       union {
+               void __iomem *mask_base;
+               u8 mask_pos;
+       };
        struct pci_dev *dev;
 
        /* Last set MSI message */
index 7a0e5c4f8072c53f4b0d6a7dfa681355324e065f..3069ec7e0ab84ca54a282c72d73385e44e69d63a 100644 (file)
@@ -50,8 +50,10 @@ struct mutex {
        atomic_t                count;
        spinlock_t              wait_lock;
        struct list_head        wait_list;
-#ifdef CONFIG_DEBUG_MUTEXES
+#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)
        struct thread_info      *owner;
+#endif
+#ifdef CONFIG_DEBUG_MUTEXES
        const char              *name;
        void                    *magic;
 #endif
@@ -68,7 +70,6 @@ struct mutex_waiter {
        struct list_head        list;
        struct task_struct      *task;
 #ifdef CONFIG_DEBUG_MUTEXES
-       struct mutex            *lock;
        void                    *magic;
 #endif
 };
index 8cc8807f77d6da286c6225ccb4a8c69642b826e3..bde2557c2a9cec10613328369aebe64bbf3150c4 100644 (file)
@@ -166,8 +166,7 @@ struct nfs_inode {
         */
        struct radix_tree_root  nfs_page_tree;
 
-       unsigned long           ncommit,
-                               npages;
+       unsigned long           npages;
 
        /* Open contexts for shared mmap writes */
        struct list_head        open_files;
@@ -207,6 +206,7 @@ struct nfs_inode {
 #define NFS_INO_STALE          (1)             /* possible stale inode */
 #define NFS_INO_ACL_LRU_SET    (2)             /* Inode is on the LRU list */
 #define NFS_INO_MOUNTPOINT     (3)             /* inode is remote mountpoint */
+#define NFS_INO_FLUSHING       (4)             /* inode is flushing out data */
 
 static inline struct nfs_inode *NFS_I(const struct inode *inode)
 {
index 9bb81aec91cf859de0591b4fb51b49ba9a622297..29b1e40dce99cc3f76fea6b55904546af753725e 100644 (file)
@@ -106,6 +106,11 @@ struct nfs_server {
        u32                     attr_bitmask[2];/* V4 bitmask representing the set
                                                   of attributes supported on this
                                                   filesystem */
+       u32                     cache_consistency_bitmask[2];
+                                               /* V4 bitmask representing the subset
+                                                  of change attribute, size, ctime
+                                                  and mtime attributes supported by
+                                                  the server */
        u32                     acl_bitmask;    /* V4 bitmask representing the ACEs
                                                   that are supported on this
                                                   filesystem */
index 43a713fce11cbfbd25571424e7201758f15b4bf5..b89c34e40bc2b23e5d34485f8640a28197b7a3e5 100644 (file)
@@ -27,12 +27,8 @@ static inline int nfs_fsid_equal(const struct nfs_fsid *a, const struct nfs_fsid
 }
 
 struct nfs_fattr {
-       unsigned short          valid;          /* which fields are valid */
-       __u64                   pre_size;       /* pre_op_attr.size       */
-       struct timespec         pre_mtime;      /* pre_op_attr.mtime      */
-       struct timespec         pre_ctime;      /* pre_op_attr.ctime      */
-       enum nfs_ftype          type;           /* always use NFSv2 types */
-       __u32                   mode;
+       unsigned int            valid;          /* which fields are valid */
+       umode_t                 mode;
        __u32                   nlink;
        __u32                   uid;
        __u32                   gid;
@@ -52,19 +48,55 @@ struct nfs_fattr {
        struct timespec         atime;
        struct timespec         mtime;
        struct timespec         ctime;
-       __u32                   bitmap[2];      /* NFSv4 returned attribute bitmap */
        __u64                   change_attr;    /* NFSv4 change attribute */
        __u64                   pre_change_attr;/* pre-op NFSv4 change attribute */
+       __u64                   pre_size;       /* pre_op_attr.size       */
+       struct timespec         pre_mtime;      /* pre_op_attr.mtime      */
+       struct timespec         pre_ctime;      /* pre_op_attr.ctime      */
        unsigned long           time_start;
        unsigned long           gencount;
 };
 
-#define NFS_ATTR_WCC           0x0001          /* pre-op WCC data    */
-#define NFS_ATTR_FATTR         0x0002          /* post-op attributes */
-#define NFS_ATTR_FATTR_V3      0x0004          /* NFSv3 attributes */
-#define NFS_ATTR_FATTR_V4      0x0008          /* NFSv4 change attribute */
-#define NFS_ATTR_WCC_V4                0x0010          /* pre-op change attribute */
-#define NFS_ATTR_FATTR_V4_REFERRAL     0x0020          /* NFSv4 referral */
+#define NFS_ATTR_FATTR_TYPE            (1U << 0)
+#define NFS_ATTR_FATTR_MODE            (1U << 1)
+#define NFS_ATTR_FATTR_NLINK           (1U << 2)
+#define NFS_ATTR_FATTR_OWNER           (1U << 3)
+#define NFS_ATTR_FATTR_GROUP           (1U << 4)
+#define NFS_ATTR_FATTR_RDEV            (1U << 5)
+#define NFS_ATTR_FATTR_SIZE            (1U << 6)
+#define NFS_ATTR_FATTR_PRESIZE         (1U << 7)
+#define NFS_ATTR_FATTR_BLOCKS_USED     (1U << 8)
+#define NFS_ATTR_FATTR_SPACE_USED      (1U << 9)
+#define NFS_ATTR_FATTR_FSID            (1U << 10)
+#define NFS_ATTR_FATTR_FILEID          (1U << 11)
+#define NFS_ATTR_FATTR_ATIME           (1U << 12)
+#define NFS_ATTR_FATTR_MTIME           (1U << 13)
+#define NFS_ATTR_FATTR_CTIME           (1U << 14)
+#define NFS_ATTR_FATTR_PREMTIME                (1U << 15)
+#define NFS_ATTR_FATTR_PRECTIME                (1U << 16)
+#define NFS_ATTR_FATTR_CHANGE          (1U << 17)
+#define NFS_ATTR_FATTR_PRECHANGE       (1U << 18)
+#define NFS_ATTR_FATTR_V4_REFERRAL     (1U << 19)      /* NFSv4 referral */
+
+#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
+               | NFS_ATTR_FATTR_MODE \
+               | NFS_ATTR_FATTR_NLINK \
+               | NFS_ATTR_FATTR_OWNER \
+               | NFS_ATTR_FATTR_GROUP \
+               | NFS_ATTR_FATTR_RDEV \
+               | NFS_ATTR_FATTR_SIZE \
+               | NFS_ATTR_FATTR_FSID \
+               | NFS_ATTR_FATTR_FILEID \
+               | NFS_ATTR_FATTR_ATIME \
+               | NFS_ATTR_FATTR_MTIME \
+               | NFS_ATTR_FATTR_CTIME)
+#define NFS_ATTR_FATTR_V2 (NFS_ATTR_FATTR \
+               | NFS_ATTR_FATTR_BLOCKS_USED)
+#define NFS_ATTR_FATTR_V3 (NFS_ATTR_FATTR \
+               | NFS_ATTR_FATTR_SPACE_USED)
+#define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \
+               | NFS_ATTR_FATTR_SPACE_USED \
+               | NFS_ATTR_FATTR_CHANGE)
 
 /*
  * Info on the file system
@@ -836,6 +868,7 @@ struct nfs_rpc_ops {
        int     (*lock)(struct file *, int, struct file_lock *);
        int     (*lock_check_bounds)(const struct file_lock *);
        void    (*clear_acl_cache)(struct inode *);
+       void    (*close_context)(struct nfs_open_context *ctx, int);
 };
 
 /*
diff --git a/include/linux/page-debug-flags.h b/include/linux/page-debug-flags.h
new file mode 100644 (file)
index 0000000..b0638fd
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef LINUX_PAGE_DEBUG_FLAGS_H
+#define  LINUX_PAGE_DEBUG_FLAGS_H
+
+/*
+ * page->debug_flags bits:
+ *
+ * PAGE_DEBUG_FLAG_POISON is set for poisoned pages. This is used to
+ * implement generic debug pagealloc feature. The pages are filled with
+ * poison patterns and set this flag after free_pages(). The poisoned
+ * pages are verified whether the patterns are not corrupted and clear
+ * the flag before alloc_pages().
+ */
+
+enum page_debug_flags {
+       PAGE_DEBUG_FLAG_POISON,         /* Page is poisoned */
+};
+
+/*
+ * Ensure that CONFIG_WANT_PAGE_DEBUG_FLAGS reliably
+ * gets turned off when no debug features are enabling it!
+ */
+
+#ifdef CONFIG_WANT_PAGE_DEBUG_FLAGS
+#if !defined(CONFIG_PAGE_POISONING) \
+/* && !defined(CONFIG_PAGE_DEBUG_SOMETHING_ELSE) && ... */
+#error WANT_PAGE_DEBUG_FLAGS is turned on with no debug features!
+#endif
+#endif /* CONFIG_WANT_PAGE_DEBUG_FLAGS */
+
+#endif /* LINUX_PAGE_DEBUG_FLAGS_H */
index 219a523ecdb0b5240f18710bc7a0da81c7538cae..61df1779b2a52050c89dd68534cd402f9c3f4100 100644 (file)
@@ -96,6 +96,8 @@ enum pageflags {
        PG_swapbacked,          /* Page is backed by RAM/swap */
 #ifdef CONFIG_UNEVICTABLE_LRU
        PG_unevictable,         /* Page is "unevictable"  */
+#endif
+#ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT
        PG_mlocked,             /* Page is vma mlocked */
 #endif
 #ifdef CONFIG_IA64_UNCACHED_ALLOCATOR
@@ -234,20 +236,20 @@ PAGEFLAG_FALSE(SwapCache)
 #ifdef CONFIG_UNEVICTABLE_LRU
 PAGEFLAG(Unevictable, unevictable) __CLEARPAGEFLAG(Unevictable, unevictable)
        TESTCLEARFLAG(Unevictable, unevictable)
+#else
+PAGEFLAG_FALSE(Unevictable) TESTCLEARFLAG_FALSE(Unevictable)
+       SETPAGEFLAG_NOOP(Unevictable) CLEARPAGEFLAG_NOOP(Unevictable)
+       __CLEARPAGEFLAG_NOOP(Unevictable)
+#endif
 
+#ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT
 #define MLOCK_PAGES 1
 PAGEFLAG(Mlocked, mlocked) __CLEARPAGEFLAG(Mlocked, mlocked)
        TESTSCFLAG(Mlocked, mlocked)
-
 #else
-
 #define MLOCK_PAGES 0
 PAGEFLAG_FALSE(Mlocked)
        SETPAGEFLAG_NOOP(Mlocked) TESTCLEARFLAG_FALSE(Mlocked)
-
-PAGEFLAG_FALSE(Unevictable) TESTCLEARFLAG_FALSE(Unevictable)
-       SETPAGEFLAG_NOOP(Unevictable) CLEARPAGEFLAG_NOOP(Unevictable)
-       __CLEARPAGEFLAG_NOOP(Unevictable)
 #endif
 
 #ifdef CONFIG_IA64_UNCACHED_ALLOCATOR
@@ -367,9 +369,13 @@ static inline void __ClearPageTail(struct page *page)
 
 #ifdef CONFIG_UNEVICTABLE_LRU
 #define __PG_UNEVICTABLE       (1 << PG_unevictable)
-#define __PG_MLOCKED           (1 << PG_mlocked)
 #else
 #define __PG_UNEVICTABLE       0
+#endif
+
+#ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT
+#define __PG_MLOCKED           (1 << PG_mlocked)
+#else
 #define __PG_MLOCKED           0
 #endif
 
index 602cc1fdee90c152dc458642256b623ce8cbfa78..7339c7bf73315e56a981b382229abfc39384e23b 100644 (file)
@@ -91,24 +91,23 @@ static inline void page_cgroup_init(void)
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
 #include <linux/swap.h>
-extern struct mem_cgroup *
-swap_cgroup_record(swp_entry_t ent, struct mem_cgroup *mem);
-extern struct mem_cgroup *lookup_swap_cgroup(swp_entry_t ent);
+extern unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id);
+extern unsigned short lookup_swap_cgroup(swp_entry_t ent);
 extern int swap_cgroup_swapon(int type, unsigned long max_pages);
 extern void swap_cgroup_swapoff(int type);
 #else
 #include <linux/swap.h>
 
 static inline
-struct mem_cgroup *swap_cgroup_record(swp_entry_t ent, struct mem_cgroup *mem)
+unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
 {
-       return NULL;
+       return 0;
 }
 
 static inline
-struct mem_cgroup *lookup_swap_cgroup(swp_entry_t ent)
+unsigned short lookup_swap_cgroup(swp_entry_t ent)
 {
-       return NULL;
+       return 0;
 }
 
 static inline int
index 01ca0856caff38a8d910df0915e4bb6cc93be536..076a7dc67c2bd25c89bec24ce036d719f1886dc3 100644 (file)
  * Bits in mapping->flags.  The lower __GFP_BITS_SHIFT bits are the page
  * allocation mode flags.
  */
-#define        AS_EIO          (__GFP_BITS_SHIFT + 0)  /* IO error on async write */
-#define AS_ENOSPC      (__GFP_BITS_SHIFT + 1)  /* ENOSPC on async write */
-#define AS_MM_ALL_LOCKS        (__GFP_BITS_SHIFT + 2)  /* under mm_take_all_locks() */
+enum mapping_flags {
+       AS_EIO          = __GFP_BITS_SHIFT + 0, /* IO error on async write */
+       AS_ENOSPC       = __GFP_BITS_SHIFT + 1, /* ENOSPC on async write */
+       AS_MM_ALL_LOCKS = __GFP_BITS_SHIFT + 2, /* under mm_take_all_locks() */
+#ifdef CONFIG_UNEVICTABLE_LRU
+       AS_UNEVICTABLE  = __GFP_BITS_SHIFT + 3, /* e.g., ramdisk, SHM_LOCK */
+#endif
+};
 
 static inline void mapping_set_error(struct address_space *mapping, int error)
 {
@@ -33,7 +38,6 @@ static inline void mapping_set_error(struct address_space *mapping, int error)
 }
 
 #ifdef CONFIG_UNEVICTABLE_LRU
-#define AS_UNEVICTABLE (__GFP_BITS_SHIFT + 2)  /* e.g., ramdisk, SHM_LOCK */
 
 static inline void mapping_set_unevictable(struct address_space *mapping)
 {
index 7b2886fa7fdc2885972d0ba2286afe59f0d1b82b..bab82f4c571c611d91fb9f180dc2a69ed12c95e2 100644 (file)
@@ -24,7 +24,6 @@ void __pagevec_release(struct pagevec *pvec);
 void __pagevec_free(struct pagevec *pvec);
 void ____pagevec_lru_add(struct pagevec *pvec, enum lru_list lru);
 void pagevec_strip(struct pagevec *pvec);
-void pagevec_swap_free(struct pagevec *pvec);
 unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
                pgoff_t start, unsigned nr_pages);
 unsigned pagevec_lookup_tag(struct pagevec *pvec,
index 042c166f65d5e155d46bacfbd6981268d928d376..092e82e0048c969e7b54b17dbd6dcd548969bb6c 100644 (file)
 
 #include <linux/acpi.h>
 
-#define OSC_QUERY_TYPE                 0
-#define OSC_SUPPORT_TYPE               1
-#define OSC_CONTROL_TYPE               2
-#define OSC_SUPPORT_MASKS              0x1f
-
-/*
- * _OSC DW0 Definition 
- */
-#define OSC_QUERY_ENABLE               1
-#define OSC_REQUEST_ERROR              2
-#define OSC_INVALID_UUID_ERROR         4
-#define OSC_INVALID_REVISION_ERROR     8
-#define OSC_CAPABILITIES_MASK_ERROR    16
-
-/*
- * _OSC DW1 Definition (OS Support Fields)
- */
-#define OSC_EXT_PCI_CONFIG_SUPPORT             1
-#define OSC_ACTIVE_STATE_PWR_SUPPORT           2
-#define OSC_CLOCK_PWR_CAPABILITY_SUPPORT       4
-#define OSC_PCI_SEGMENT_GROUPS_SUPPORT         8
-#define OSC_MSI_SUPPORT                                16
-
-/*
- * _OSC DW1 Definition (OS Control Fields)
- */
-#define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL      1
-#define OSC_SHPC_NATIVE_HP_CONTROL             2
-#define OSC_PCI_EXPRESS_PME_CONTROL            4
-#define OSC_PCI_EXPRESS_AER_CONTROL            8
-#define OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL  16
-
-#define OSC_CONTROL_MASKS      (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |    \
-                               OSC_SHPC_NATIVE_HP_CONTROL |            \
-                               OSC_PCI_EXPRESS_PME_CONTROL |           \
-                               OSC_PCI_EXPRESS_AER_CONTROL |           \
-                               OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
-
 #ifdef CONFIG_ACPI
-extern acpi_status pci_osc_control_set(acpi_handle handle, u32 flags);
-int pci_acpi_osc_support(acpi_handle handle, u32 flags);
 static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
 {
-       /* Find root host bridge */
-       while (pdev->bus->self)
-               pdev = pdev->bus->self;
-
-       return acpi_get_pci_rootbridge_handle(pci_domain_nr(pdev->bus),
-                       pdev->bus->number);
+       struct pci_bus *pbus = pdev->bus;
+       /* Find a PCI root bus */
+       while (pbus->parent)
+               pbus = pbus->parent;
+       return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus),
+                                             pbus->number);
 }
 
 static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
 {
-       int seg = pci_domain_nr(pbus), busnr = pbus->number;
-       struct pci_dev *bridge = pbus->self;
-       if (bridge)
-               return DEVICE_ACPI_HANDLE(&(bridge->dev));
-       return acpi_get_pci_rootbridge_handle(seg, busnr);
+       if (pbus->parent)
+               return DEVICE_ACPI_HANDLE(&(pbus->self->dev));
+       return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus),
+                                             pbus->number);
 }
 #else
-#if !defined(AE_ERROR)
-typedef u32            acpi_status;
-#define AE_ERROR       (acpi_status) (0x0001)
-#endif    
-static inline acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
-{return AE_ERROR;}
 static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
 { return NULL; }
 #endif
index 7bd624bfdcfd37945e3c59bf2a74f0d2f1dabb21..a7fe4bbd7ff1f7be9eb28952bffd8802c55e6ff8 100644 (file)
@@ -52,6 +52,7 @@
 #include <asm/atomic.h>
 #include <linux/device.h>
 #include <linux/io.h>
+#include <linux/irqreturn.h>
 
 /* Include the ID list */
 #include <linux/pci_ids.h>
@@ -93,6 +94,12 @@ enum {
        /* #6: expansion ROM resource */
        PCI_ROM_RESOURCE,
 
+       /* device specific resources */
+#ifdef CONFIG_PCI_IOV
+       PCI_IOV_RESOURCES,
+       PCI_IOV_RESOURCE_END = PCI_IOV_RESOURCES + PCI_SRIOV_NUM_BARS - 1,
+#endif
+
        /* resources assigned to buses behind the bridge */
 #define PCI_BRIDGE_RESOURCE_NUM 4
 
@@ -180,6 +187,7 @@ struct pci_cap_saved_state {
 
 struct pcie_link_state;
 struct pci_vpd;
+struct pci_sriov;
 
 /*
  * The pci_dev structure is used to describe PCI devices.
@@ -257,6 +265,8 @@ struct pci_dev {
        unsigned int    is_managed:1;
        unsigned int    is_pcie:1;
        unsigned int    state_saved:1;
+       unsigned int    is_physfn:1;
+       unsigned int    is_virtfn:1;
        pci_dev_flags_t dev_flags;
        atomic_t        enable_cnt;     /* pci_enable_device has been called */
 
@@ -270,6 +280,12 @@ struct pci_dev {
        struct list_head msi_list;
 #endif
        struct pci_vpd *vpd;
+#ifdef CONFIG_PCI_IOV
+       union {
+               struct pci_sriov *sriov;        /* SR-IOV capability related */
+               struct pci_dev *physfn; /* the PF this VF is associated with */
+       };
+#endif
 };
 
 extern struct pci_dev *alloc_pci_dev(void);
@@ -341,6 +357,15 @@ struct pci_bus {
 #define pci_bus_b(n)   list_entry(n, struct pci_bus, node)
 #define to_pci_bus(n)  container_of(n, struct pci_bus, dev)
 
+/*
+ * Returns true if the pci bus is root (behind host-pci bridge),
+ * false otherwise
+ */
+static inline bool pci_is_root_bus(struct pci_bus *pbus)
+{
+       return !(pbus->parent);
+}
+
 #ifdef CONFIG_PCI_MSI
 static inline bool pci_dev_msi_enabled(struct pci_dev *pci_dev)
 {
@@ -528,7 +553,7 @@ void pcibios_update_irq(struct pci_dev *, int irq);
 /* Generic PCI functions used internally */
 
 extern struct pci_bus *pci_find_bus(int domain, int busnr);
-void pci_bus_add_devices(struct pci_bus *bus);
+void pci_bus_add_devices(const struct pci_bus *bus);
 struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus,
                                      struct pci_ops *ops, void *sysdata);
 static inline struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops,
@@ -689,6 +714,7 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size);
 /* Power management related routines */
 int pci_save_state(struct pci_dev *dev);
 int pci_restore_state(struct pci_dev *dev);
+int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state);
 int pci_set_power_state(struct pci_dev *dev, pci_power_t state);
 pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
 bool pci_pme_capable(struct pci_dev *dev, pci_power_t state);
@@ -701,6 +727,9 @@ int pci_back_from_sleep(struct pci_dev *dev);
 
 /* Functions for PCI Hotplug drivers to use */
 int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap);
+#ifdef CONFIG_HOTPLUG
+unsigned int pci_rescan_bus(struct pci_bus *bus);
+#endif
 
 /* Vital product data routines */
 ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
@@ -708,7 +737,7 @@ ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void
 int pci_vpd_truncate(struct pci_dev *dev, size_t size);
 
 /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
-void pci_bus_assign_resources(struct pci_bus *bus);
+void pci_bus_assign_resources(const struct pci_bus *bus);
 void pci_bus_size_bridges(struct pci_bus *bus);
 int pci_claim_resource(struct pci_dev *, int);
 void pci_assign_unassigned_resources(void);
@@ -789,7 +818,7 @@ struct msix_entry {
 
 
 #ifndef CONFIG_PCI_MSI
-static inline int pci_enable_msi(struct pci_dev *dev)
+static inline int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec)
 {
        return -1;
 }
@@ -799,6 +828,10 @@ static inline void pci_msi_shutdown(struct pci_dev *dev)
 static inline void pci_disable_msi(struct pci_dev *dev)
 { }
 
+static inline int pci_msix_table_size(struct pci_dev *dev)
+{
+       return 0;
+}
 static inline int pci_enable_msix(struct pci_dev *dev,
                                  struct msix_entry *entries, int nvec)
 {
@@ -820,9 +853,10 @@ static inline int pci_msi_enabled(void)
        return 0;
 }
 #else
-extern int pci_enable_msi(struct pci_dev *dev);
+extern int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec);
 extern void pci_msi_shutdown(struct pci_dev *dev);
 extern void pci_disable_msi(struct pci_dev *dev);
+extern int pci_msix_table_size(struct pci_dev *dev);
 extern int pci_enable_msix(struct pci_dev *dev,
        struct msix_entry *entries, int nvec);
 extern void pci_msix_shutdown(struct pci_dev *dev);
@@ -841,6 +875,8 @@ static inline int pcie_aspm_enabled(void)
 extern int pcie_aspm_enabled(void);
 #endif
 
+#define pci_enable_msi(pdev)   pci_enable_msi_block(pdev, 1)
+
 #ifdef CONFIG_HT_IRQ
 /* The functions a driver should call */
 int  ht_create_irq(struct pci_dev *dev, int idx);
@@ -1194,5 +1230,23 @@ int pci_ext_cfg_avail(struct pci_dev *dev);
 
 void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar);
 
+#ifdef CONFIG_PCI_IOV
+extern int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
+extern void pci_disable_sriov(struct pci_dev *dev);
+extern irqreturn_t pci_sriov_migration(struct pci_dev *dev);
+#else
+static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
+{
+       return -ENODEV;
+}
+static inline void pci_disable_sriov(struct pci_dev *dev)
+{
+}
+static inline irqreturn_t pci_sriov_migration(struct pci_dev *dev)
+{
+       return IRQ_NONE;
+}
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* LINUX_PCI_H */
index 2c9e8080da5e620873656fae4ac57c5c31a7030a..170f8b1f22db1dc7f065e0de8525cb1b80ce4898 100644 (file)
 #define PCI_DEVICE_ID_AMD_OPUS_7443    0x7443
 #define PCI_DEVICE_ID_AMD_VIPER_7443   0x7443
 #define PCI_DEVICE_ID_AMD_OPUS_7445    0x7445
+#define PCI_DEVICE_ID_AMD_8111_PCI     0x7460
 #define PCI_DEVICE_ID_AMD_8111_LPC     0x7468
 #define PCI_DEVICE_ID_AMD_8111_IDE     0x7469
 #define PCI_DEVICE_ID_AMD_8111_SMBUS2  0x746a
 #define PCI_DEVICE_ID_TDI_EHCI          0x0101
 
 #define PCI_VENDOR_ID_FREESCALE                0x1957
+#define PCI_DEVICE_ID_MPC8315E         0x00b4
+#define PCI_DEVICE_ID_MPC8315          0x00b5
+#define PCI_DEVICE_ID_MPC8314E         0x00b6
+#define PCI_DEVICE_ID_MPC8314          0x00b7
+#define PCI_DEVICE_ID_MPC8378E         0x00c4
+#define PCI_DEVICE_ID_MPC8378          0x00c5
+#define PCI_DEVICE_ID_MPC8377E         0x00c6
+#define PCI_DEVICE_ID_MPC8377          0x00c7
 #define PCI_DEVICE_ID_MPC8548E         0x0012
 #define PCI_DEVICE_ID_MPC8548          0x0013
 #define PCI_DEVICE_ID_MPC8543E         0x0014
 #define PCI_DEVICE_ID_INTEL_82801CA_12 0x248c
 #define PCI_DEVICE_ID_INTEL_82801DB_0  0x24c0
 #define PCI_DEVICE_ID_INTEL_82801DB_1  0x24c1
+#define PCI_DEVICE_ID_INTEL_82801DB_2  0x24c2
 #define PCI_DEVICE_ID_INTEL_82801DB_3  0x24c3
 #define PCI_DEVICE_ID_INTEL_82801DB_5  0x24c5
 #define PCI_DEVICE_ID_INTEL_82801DB_6  0x24c6
index 027815b4635e677ad441c73a19b0bf48a62f5243..e4d08c1b2e0b40689d74911624468762eea0e281 100644 (file)
 #define  PCI_PM_CAP_PME_SHIFT  11      /* Start of the PME Mask in PMC */
 #define PCI_PM_CTRL            4       /* PM control and status register */
 #define  PCI_PM_CTRL_STATE_MASK        0x0003  /* Current power state (D0 to D3) */
-#define  PCI_PM_CTRL_NO_SOFT_RESET     0x0004  /* No reset for D3hot->D0 */
+#define  PCI_PM_CTRL_NO_SOFT_RESET     0x0008  /* No reset for D3hot->D0 */
 #define  PCI_PM_CTRL_PME_ENABLE        0x0100  /* PME pin enable */
 #define  PCI_PM_CTRL_DATA_SEL_MASK     0x1e00  /* Data select (??) */
 #define  PCI_PM_CTRL_DATA_SCALE_MASK   0x6000  /* Data scale (??) */
 #define  PCI_EXP_TYPE_UPSTREAM 0x5     /* Upstream Port */
 #define  PCI_EXP_TYPE_DOWNSTREAM 0x6   /* Downstream Port */
 #define  PCI_EXP_TYPE_PCI_BRIDGE 0x7   /* PCI/PCI-X Bridge */
+#define  PCI_EXP_TYPE_RC_END   0x9     /* Root Complex Integrated Endpoint */
 #define PCI_EXP_FLAGS_SLOT     0x0100  /* Slot implemented */
 #define PCI_EXP_FLAGS_IRQ      0x3e00  /* Interrupt message number */
 #define PCI_EXP_DEVCAP         4       /* Device capabilities */
 #define  PCI_EXP_DEVCAP2_ARI   0x20    /* Alternative Routing-ID */
 #define PCI_EXP_DEVCTL2                40      /* Device Control 2 */
 #define  PCI_EXP_DEVCTL2_ARI   0x20    /* Alternative Routing-ID */
+#define PCI_EXP_LNKCTL2                48      /* Link Control 2 */
+#define PCI_EXP_SLTCTL2                56      /* Slot Control 2 */
 
 /* Extended Capabilities (PCI-X 2.0 and Express) */
 #define PCI_EXT_CAP_ID(header)         (header & 0x0000ffff)
 #define PCI_EXT_CAP_ID_DSN     3
 #define PCI_EXT_CAP_ID_PWR     4
 #define PCI_EXT_CAP_ID_ARI     14
+#define PCI_EXT_CAP_ID_SRIOV   16
 
 /* Advanced Error Reporting */
 #define PCI_ERR_UNCOR_STATUS   4       /* Uncorrectable Error Status */
 #define  PCI_ARI_CTRL_ACS      0x0002  /* ACS Function Groups Enable */
 #define  PCI_ARI_CTRL_FG(x)    (((x) >> 4) & 7) /* Function Group */
 
+/* Single Root I/O Virtualization */
+#define PCI_SRIOV_CAP          0x04    /* SR-IOV Capabilities */
+#define  PCI_SRIOV_CAP_VFM     0x01    /* VF Migration Capable */
+#define  PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */
+#define PCI_SRIOV_CTRL         0x08    /* SR-IOV Control */
+#define  PCI_SRIOV_CTRL_VFE    0x01    /* VF Enable */
+#define  PCI_SRIOV_CTRL_VFM    0x02    /* VF Migration Enable */
+#define  PCI_SRIOV_CTRL_INTR   0x04    /* VF Migration Interrupt Enable */
+#define  PCI_SRIOV_CTRL_MSE    0x08    /* VF Memory Space Enable */
+#define  PCI_SRIOV_CTRL_ARI    0x10    /* ARI Capable Hierarchy */
+#define PCI_SRIOV_STATUS       0x0a    /* SR-IOV Status */
+#define  PCI_SRIOV_STATUS_VFM  0x01    /* VF Migration Status */
+#define PCI_SRIOV_INITIAL_VF   0x0c    /* Initial VFs */
+#define PCI_SRIOV_TOTAL_VF     0x0e    /* Total VFs */
+#define PCI_SRIOV_NUM_VF       0x10    /* Number of VFs */
+#define PCI_SRIOV_FUNC_LINK    0x12    /* Function Dependency Link */
+#define PCI_SRIOV_VF_OFFSET    0x14    /* First VF Offset */
+#define PCI_SRIOV_VF_STRIDE    0x16    /* Following VF Stride */
+#define PCI_SRIOV_VF_DID       0x1a    /* VF Device ID */
+#define PCI_SRIOV_SUP_PGSIZE   0x1c    /* Supported Page Sizes */
+#define PCI_SRIOV_SYS_PGSIZE   0x20    /* System Page Size */
+#define PCI_SRIOV_BAR          0x24    /* VF BAR0 */
+#define  PCI_SRIOV_NUM_BARS    6       /* Number of VF BARs */
+#define PCI_SRIOV_VFM          0x3c    /* VF Migration State Array Offset*/
+#define  PCI_SRIOV_VFM_BIR(x)  ((x) & 7)       /* State BIR */
+#define  PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7)    /* State Offset */
+#define  PCI_SRIOV_VFM_UA      0x0     /* Inactive.Unavailable */
+#define  PCI_SRIOV_VFM_MI      0x1     /* Dormant.MigrateIn */
+#define  PCI_SRIOV_VFM_MO      0x2     /* Active.MigrateOut */
+#define  PCI_SRIOV_VFM_AV      0x3     /* Active.Available */
+
 #endif /* LINUX_PCI_REGS_H */
index 6cd91e3f982052df783c2ec9b9df130bff118659..b4c79545330be8b5ef8e061161b8a2d61ce868b2 100644 (file)
 #define PCIE_ANY_PORT                  7
 
 /* Service Type */
-#define PCIE_PORT_SERVICE_PME          1       /* Power Management Event */
-#define PCIE_PORT_SERVICE_AER          2       /* Advanced Error Reporting */
-#define PCIE_PORT_SERVICE_HP           4       /* Native Hotplug */
-#define PCIE_PORT_SERVICE_VC           8       /* Virtual Channel */
+#define PCIE_PORT_SERVICE_PME_SHIFT    0       /* Power Management Event */
+#define PCIE_PORT_SERVICE_PME          (1 << PCIE_PORT_SERVICE_PME_SHIFT)
+#define PCIE_PORT_SERVICE_AER_SHIFT    1       /* Advanced Error Reporting */
+#define PCIE_PORT_SERVICE_AER          (1 << PCIE_PORT_SERVICE_AER_SHIFT)
+#define PCIE_PORT_SERVICE_HP_SHIFT     2       /* Native Hotplug */
+#define PCIE_PORT_SERVICE_HP           (1 << PCIE_PORT_SERVICE_HP_SHIFT)
+#define PCIE_PORT_SERVICE_VC_SHIFT     3       /* Virtual Channel */
+#define PCIE_PORT_SERVICE_VC           (1 << PCIE_PORT_SERVICE_VC_SHIFT)
 
 /* Root/Upstream/Downstream Port's Interrupt Mode */
+#define PCIE_PORT_NO_IRQ               (-1)
 #define PCIE_PORT_INTx_MODE            0
 #define PCIE_PORT_MSI_MODE             1
 #define PCIE_PORT_MSIX_MODE            2
 
-struct pcie_port_service_id {
-       __u32 vendor, device;           /* Vendor and device ID or PCI_ANY_ID*/
-       __u32 subvendor, subdevice;     /* Subsystem ID's or PCI_ANY_ID */
-       __u32 class, class_mask;        /* (class,subclass,prog-if) triplet */
-       __u32 port_type, service_type;  /* Port Entity */
-       kernel_ulong_t driver_data;
+struct pcie_port_data {
+       int port_type;          /* Type of the port */
+       int port_irq_mode;      /* [0:INTx | 1:MSI | 2:MSI-X] */
 };
 
 struct pcie_device {
        int             irq;        /* Service IRQ/MSI/MSI-X Vector */
-       int             interrupt_mode; /* [0:INTx | 1:MSI | 2:MSI-X] */        
-       struct pcie_port_service_id id; /* Service ID */
-       struct pci_dev  *port;      /* Root/Upstream/Downstream Port */
+       struct pci_dev *port;       /* Root/Upstream/Downstream Port */
+       u32             service;    /* Port service this device represents */
        void            *priv_data; /* Service Private Data */
        struct device   device;     /* Generic Device Interface */
 };
@@ -56,10 +57,9 @@ static inline void* get_service_data(struct pcie_device *dev)
 
 struct pcie_port_service_driver {
        const char *name;
-       int (*probe) (struct pcie_device *dev, 
-               const struct pcie_port_service_id *id);
+       int (*probe) (struct pcie_device *dev);
        void (*remove) (struct pcie_device *dev);
-       int (*suspend) (struct pcie_device *dev, pm_message_t state);
+       int (*suspend) (struct pcie_device *dev);
        int (*resume) (struct pcie_device *dev);
 
        /* Service Error Recovery Handler */
@@ -68,7 +68,9 @@ struct pcie_port_service_driver {
        /* Link Reset Capability - AER service driver specific */
        pci_ers_result_t (*reset_link) (struct pci_dev *dev);
 
-       const struct pcie_port_service_id *id_table;
+       int port_type;  /* Type of the port this driver can handle */
+       u32 service;    /* Port service this device represents */
+
        struct device_driver driver;
 };
 #define to_service_driver(d) \
index 9f31683728fd7e2c59f738ae35ab6835066270c1..6729f7dcd60e66cc0116878ad640256a7061bbfe 100644 (file)
@@ -17,6 +17,9 @@
  */
 #define TIMER_ENTRY_STATIC     ((void *) 0x74737461)
 
+/********** mm/debug-pagealloc.c **********/
+#define PAGE_POISON 0xaa
+
 /********** mm/slab.c **********/
 /*
  * Magic nums for obj red zoning.
index b8bdb96eff78b8112ddf4717b651c4ef1126ead7..fbfa3d44d33d819ef6af58c95e136ed6cc7e594a 100644 (file)
@@ -41,9 +41,6 @@ enum {
  * while parent/subdir create the directory structure (every
  * /proc file has a parent, but "subdir" is NULL for all
  * non-directory entries).
- *
- * "owner" is used to protect module
- * from unloading while proc_dir_entry is in use
  */
 
 typedef        int (read_proc_t)(char *page, char **start, off_t off,
@@ -70,7 +67,6 @@ struct proc_dir_entry {
         * somewhere.
         */
        const struct file_operations *proc_fops;
-       struct module *owner;
        struct proc_dir_entry *next, *parent, *subdir;
        void *data;
        read_proc_t *read_proc;
index 98b93ca4db064e5d6ebae919206fe5ed55a45427..67c15653fc230c9341ed1131c1e846156c6772bb 100644 (file)
@@ -94,6 +94,7 @@ extern void ptrace_notify(int exit_code);
 extern void __ptrace_link(struct task_struct *child,
                          struct task_struct *new_parent);
 extern void __ptrace_unlink(struct task_struct *child);
+extern void exit_ptrace(struct task_struct *tracer);
 extern void ptrace_fork(struct task_struct *task, unsigned long clone_flags);
 #define PTRACE_MODE_READ   1
 #define PTRACE_MODE_ATTACH 2
index fe00f781a622ab73a2230414a09b4e6fe6df96ae..8cc65757e47adfc476ed4b2ca2c1d020c06ab6bf 100644 (file)
@@ -49,13 +49,12 @@ static inline int reiserfs_acl_count(size_t size)
 #ifdef CONFIG_REISERFS_FS_POSIX_ACL
 struct posix_acl *reiserfs_get_acl(struct inode *inode, int type);
 int reiserfs_acl_chmod(struct inode *inode);
-int reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
+int reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
+                                struct inode *dir, struct dentry *dentry,
                                 struct inode *inode);
 int reiserfs_cache_default_acl(struct inode *dir);
-extern int reiserfs_xattr_posix_acl_init(void) __init;
-extern int reiserfs_xattr_posix_acl_exit(void);
-extern struct reiserfs_xattr_handler posix_acl_default_handler;
-extern struct reiserfs_xattr_handler posix_acl_access_handler;
+extern struct xattr_handler reiserfs_posix_acl_default_handler;
+extern struct xattr_handler reiserfs_posix_acl_access_handler;
 
 static inline void reiserfs_init_acl_access(struct inode *inode)
 {
@@ -75,23 +74,14 @@ static inline struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
        return NULL;
 }
 
-static inline int reiserfs_xattr_posix_acl_init(void)
-{
-       return 0;
-}
-
-static inline int reiserfs_xattr_posix_acl_exit(void)
-{
-       return 0;
-}
-
 static inline int reiserfs_acl_chmod(struct inode *inode)
 {
        return 0;
 }
 
 static inline int
-reiserfs_inherit_default_acl(const struct inode *dir, struct dentry *dentry,
+reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
+                            const struct inode *dir, struct dentry *dentry,
                             struct inode *inode)
 {
        return 0;
index e356c99f06590c0d48e1aa687f5c9465813608bb..2245c78d5876e7035519d65cc487855b1be778b9 100644 (file)
@@ -58,8 +58,6 @@
 #define reiserfs_write_lock( sb ) lock_kernel()
 #define reiserfs_write_unlock( sb ) unlock_kernel()
 
-/* xattr stuff */
-#define REISERFS_XATTR_DIR_SEM(s) (REISERFS_SB(s)->xattr_dir_sem)
 struct fid;
 
 /* in reading the #defines, it may help to understand that they employ
@@ -104,15 +102,21 @@ struct fid;
 */
 #define REISERFS_DEBUG_CODE 5  /* extra messages to help find/debug errors */
 
-void reiserfs_warning(struct super_block *s, const char *fmt, ...);
+void __reiserfs_warning(struct super_block *s, const char *id,
+                        const char *func, const char *fmt, ...);
+#define reiserfs_warning(s, id, fmt, args...) \
+        __reiserfs_warning(s, id, __func__, fmt, ##args)
 /* assertions handling */
 
 /** always check a condition and panic if it's false. */
-#define __RASSERT( cond, scond, format, args... )                                      \
-if( !( cond ) )                                                                \
-  reiserfs_panic( NULL, "reiserfs[%i]: assertion " scond " failed at " \
-                 __FILE__ ":%i:%s: " format "\n",              \
-                 in_interrupt() ? -1 : task_pid_nr(current), __LINE__ , __func__ , ##args )
+#define __RASSERT(cond, scond, format, args...)                        \
+do {                                                                   \
+       if (!(cond))                                                    \
+               reiserfs_panic(NULL, "assertion failure", "(" #cond ") at " \
+                              __FILE__ ":%i:%s: " format "\n",         \
+                              in_interrupt() ? -1 : task_pid_nr(current), \
+                              __LINE__, __func__ , ##args);            \
+} while (0)
 
 #define RASSERT(cond, format, args...) __RASSERT(cond, #cond, format, ##args)
 
@@ -196,7 +200,11 @@ struct reiserfs_super_block {
        __le32 s_flags;         /* Right now used only by inode-attributes, if enabled */
        unsigned char s_uuid[16];       /* filesystem unique identifier */
        unsigned char s_label[16];      /* filesystem volume label */
-       char s_unused[88];      /* zero filled by mkreiserfs and
+       __le16 s_mnt_count;             /* Count of mounts since last fsck */
+       __le16 s_max_mnt_count;         /* Maximum mounts before check */
+       __le32 s_lastcheck;             /* Timestamp of last fsck */
+       __le32 s_check_interval;        /* Interval between checks */
+       char s_unused[76];      /* zero filled by mkreiserfs and
                                 * reiserfs_convert_objectid_map_v1()
                                 * so any additions must be updated
                                 * there as well. */
@@ -578,10 +586,8 @@ static inline int uniqueness2type(__u32 uniqueness)
                return TYPE_DIRECT;
        case V1_DIRENTRY_UNIQUENESS:
                return TYPE_DIRENTRY;
-       default:
-               reiserfs_warning(NULL, "vs-500: unknown uniqueness %d",
-                                uniqueness);
        case V1_ANY_UNIQUENESS:
+       default:
                return TYPE_ANY;
        }
 }
@@ -598,9 +604,8 @@ static inline __u32 type2uniqueness(int type)
                return V1_DIRECT_UNIQUENESS;
        case TYPE_DIRENTRY:
                return V1_DIRENTRY_UNIQUENESS;
-       default:
-               reiserfs_warning(NULL, "vs-501: unknown type %d", type);
        case TYPE_ANY:
+       default:
                return V1_ANY_UNIQUENESS;
        }
 }
@@ -712,9 +717,9 @@ static inline void cpu_key_k_offset_dec(struct cpu_key *key)
 #define is_indirect_cpu_ih(ih) (is_indirect_cpu_key (&((ih)->ih_key)))
 #define is_statdata_cpu_ih(ih) (is_statdata_cpu_key (&((ih)->ih_key)))
 
-#define I_K_KEY_IN_ITEM(p_s_ih, p_s_key, n_blocksize) \
-    ( ! COMP_SHORT_KEYS(p_s_ih, p_s_key) && \
-          I_OFF_BYTE_IN_ITEM(p_s_ih, k_offset (p_s_key), n_blocksize) )
+#define I_K_KEY_IN_ITEM(ih, key, n_blocksize) \
+    (!COMP_SHORT_KEYS(ih, key) && \
+         I_OFF_BYTE_IN_ITEM(ih, k_offset(key), n_blocksize))
 
 /* maximal length of item */
 #define MAX_ITEM_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE)
@@ -770,25 +775,25 @@ struct block_head {
 #define DISK_LEAF_NODE_LEVEL  1        /* Leaf node level. */
 
 /* Given the buffer head of a formatted node, resolve to the block head of that node. */
-#define B_BLK_HEAD(p_s_bh)            ((struct block_head *)((p_s_bh)->b_data))
+#define B_BLK_HEAD(bh)                 ((struct block_head *)((bh)->b_data))
 /* Number of items that are in buffer. */
-#define B_NR_ITEMS(p_s_bh)            (blkh_nr_item(B_BLK_HEAD(p_s_bh)))
-#define B_LEVEL(p_s_bh)               (blkh_level(B_BLK_HEAD(p_s_bh)))
-#define B_FREE_SPACE(p_s_bh)          (blkh_free_space(B_BLK_HEAD(p_s_bh)))
+#define B_NR_ITEMS(bh)                 (blkh_nr_item(B_BLK_HEAD(bh)))
+#define B_LEVEL(bh)                    (blkh_level(B_BLK_HEAD(bh)))
+#define B_FREE_SPACE(bh)               (blkh_free_space(B_BLK_HEAD(bh)))
 
-#define PUT_B_NR_ITEMS(p_s_bh,val)    do { set_blkh_nr_item(B_BLK_HEAD(p_s_bh),val); } while (0)
-#define PUT_B_LEVEL(p_s_bh,val)       do { set_blkh_level(B_BLK_HEAD(p_s_bh),val); } while (0)
-#define PUT_B_FREE_SPACE(p_s_bh,val)  do { set_blkh_free_space(B_BLK_HEAD(p_s_bh),val); } while (0)
+#define PUT_B_NR_ITEMS(bh, val)                do { set_blkh_nr_item(B_BLK_HEAD(bh), val); } while (0)
+#define PUT_B_LEVEL(bh, val)           do { set_blkh_level(B_BLK_HEAD(bh), val); } while (0)
+#define PUT_B_FREE_SPACE(bh, val)      do { set_blkh_free_space(B_BLK_HEAD(bh), val); } while (0)
 
 /* Get right delimiting key. -- little endian */
-#define B_PRIGHT_DELIM_KEY(p_s_bh)   (&(blk_right_delim_key(B_BLK_HEAD(p_s_bh))))
+#define B_PRIGHT_DELIM_KEY(bh)         (&(blk_right_delim_key(B_BLK_HEAD(bh))))
 
 /* Does the buffer contain a disk leaf. */
-#define B_IS_ITEMS_LEVEL(p_s_bh)     (B_LEVEL(p_s_bh) == DISK_LEAF_NODE_LEVEL)
+#define B_IS_ITEMS_LEVEL(bh)           (B_LEVEL(bh) == DISK_LEAF_NODE_LEVEL)
 
 /* Does the buffer contain a disk internal node */
-#define B_IS_KEYS_LEVEL(p_s_bh)      (B_LEVEL(p_s_bh) > DISK_LEAF_NODE_LEVEL \
-                                            && B_LEVEL(p_s_bh) <= MAX_HEIGHT)
+#define B_IS_KEYS_LEVEL(bh)      (B_LEVEL(bh) > DISK_LEAF_NODE_LEVEL \
+                                           && B_LEVEL(bh) <= MAX_HEIGHT)
 
 /***************************************************************************/
 /*                             STAT DATA                                   */
@@ -1138,12 +1143,13 @@ struct disk_child {
 #define put_dc_size(dc_p, val)   do { (dc_p)->dc_size = cpu_to_le16(val); } while(0)
 
 /* Get disk child by buffer header and position in the tree node. */
-#define B_N_CHILD(p_s_bh,n_pos)  ((struct disk_child *)\
-((p_s_bh)->b_data+BLKH_SIZE+B_NR_ITEMS(p_s_bh)*KEY_SIZE+DC_SIZE*(n_pos)))
+#define B_N_CHILD(bh, n_pos)  ((struct disk_child *)\
+((bh)->b_data + BLKH_SIZE + B_NR_ITEMS(bh) * KEY_SIZE + DC_SIZE * (n_pos)))
 
 /* Get disk child number by buffer header and position in the tree node. */
-#define B_N_CHILD_NUM(p_s_bh,n_pos) (dc_block_number(B_N_CHILD(p_s_bh,n_pos)))
-#define PUT_B_N_CHILD_NUM(p_s_bh,n_pos, val) (put_dc_block_number(B_N_CHILD(p_s_bh,n_pos), val ))
+#define B_N_CHILD_NUM(bh, n_pos) (dc_block_number(B_N_CHILD(bh, n_pos)))
+#define PUT_B_N_CHILD_NUM(bh, n_pos, val) \
+                               (put_dc_block_number(B_N_CHILD(bh, n_pos), val))
 
  /* maximal value of field child_size in structure disk_child */
  /* child size is the combined size of all items and their headers */
@@ -1214,33 +1220,33 @@ struct treepath {
 struct treepath var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
 
 /* Get path element by path and path position. */
-#define PATH_OFFSET_PELEMENT(p_s_path,n_offset)  ((p_s_path)->path_elements +(n_offset))
+#define PATH_OFFSET_PELEMENT(path, n_offset)  ((path)->path_elements + (n_offset))
 
 /* Get buffer header at the path by path and path position. */
-#define PATH_OFFSET_PBUFFER(p_s_path,n_offset)   (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_buffer)
+#define PATH_OFFSET_PBUFFER(path, n_offset)   (PATH_OFFSET_PELEMENT(path, n_offset)->pe_buffer)
 
 /* Get position in the element at the path by path and path position. */
-#define PATH_OFFSET_POSITION(p_s_path,n_offset) (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_position)
+#define PATH_OFFSET_POSITION(path, n_offset) (PATH_OFFSET_PELEMENT(path, n_offset)->pe_position)
 
-#define PATH_PLAST_BUFFER(p_s_path) (PATH_OFFSET_PBUFFER((p_s_path), (p_s_path)->path_length))
+#define PATH_PLAST_BUFFER(path) (PATH_OFFSET_PBUFFER((path), (path)->path_length))
                                /* you know, to the person who didn't
                                   write this the macro name does not
                                   at first suggest what it does.
                                   Maybe POSITION_FROM_PATH_END? Or
                                   maybe we should just focus on
                                   dumping paths... -Hans */
-#define PATH_LAST_POSITION(p_s_path) (PATH_OFFSET_POSITION((p_s_path), (p_s_path)->path_length))
+#define PATH_LAST_POSITION(path) (PATH_OFFSET_POSITION((path), (path)->path_length))
 
-#define PATH_PITEM_HEAD(p_s_path)    B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_path),PATH_LAST_POSITION(p_s_path))
+#define PATH_PITEM_HEAD(path)    B_N_PITEM_HEAD(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION(path))
 
 /* in do_balance leaf has h == 0 in contrast with path structure,
    where root has level == 0. That is why we need these defines */
-#define PATH_H_PBUFFER(p_s_path, h) PATH_OFFSET_PBUFFER (p_s_path, p_s_path->path_length - (h))        /* tb->S[h] */
+#define PATH_H_PBUFFER(path, h) PATH_OFFSET_PBUFFER (path, path->path_length - (h))    /* tb->S[h] */
 #define PATH_H_PPARENT(path, h) PATH_H_PBUFFER (path, (h) + 1) /* tb->F[h] or tb->S[0]->b_parent */
 #define PATH_H_POSITION(path, h) PATH_OFFSET_POSITION (path, path->path_length - (h))
 #define PATH_H_B_ITEM_ORDER(path, h) PATH_H_POSITION(path, h + 1)      /* tb->S[h]->b_item_order */
 
-#define PATH_H_PATH_OFFSET(p_s_path, n_h) ((p_s_path)->path_length - (n_h))
+#define PATH_H_PATH_OFFSET(path, n_h) ((path)->path_length - (n_h))
 
 #define get_last_bh(path) PATH_PLAST_BUFFER(path)
 #define get_ih(path) PATH_PITEM_HEAD(path)
@@ -1470,6 +1476,16 @@ struct buffer_info {
        int bi_position;
 };
 
+static inline struct super_block *sb_from_tb(struct tree_balance *tb)
+{
+       return tb ? tb->tb_sb : NULL;
+}
+
+static inline struct super_block *sb_from_bi(struct buffer_info *bi)
+{
+       return bi ? sb_from_tb(bi->tb) : NULL;
+}
+
 /* there are 4 types of items: stat data, directory item, indirect, direct.
 +-------------------+------------+--------------+------------+
 |                  |  k_offset  | k_uniqueness | mergeable? |
@@ -1520,7 +1536,7 @@ extern struct item_operations *item_ops[TYPE_ANY + 1];
 #define COMP_SHORT_KEYS comp_short_keys
 
 /* number of blocks pointed to by the indirect item */
-#define I_UNFM_NUM(p_s_ih)     ( ih_item_len(p_s_ih) / UNFM_P_SIZE )
+#define I_UNFM_NUM(ih) (ih_item_len(ih) / UNFM_P_SIZE)
 
 /* the used space within the unformatted node corresponding to pos within the item pointed to by ih */
 #define I_POS_UNFM_SIZE(ih,pos,size) (((pos) == I_UNFM_NUM(ih) - 1 ) ? (size) - ih_free_space(ih) : (size))
@@ -1623,6 +1639,10 @@ struct reiserfs_journal_header {
 #define JOURNAL_MAX_COMMIT_AGE 30
 #define JOURNAL_MAX_TRANS_AGE 30
 #define JOURNAL_PER_BALANCE_CNT (3 * (MAX_HEIGHT-2) + 9)
+#define JOURNAL_BLOCKS_PER_OBJECT(sb)  (JOURNAL_PER_BALANCE_CNT * 3 + \
+                                        2 * (REISERFS_QUOTA_INIT_BLOCKS(sb) + \
+                                             REISERFS_QUOTA_TRANS_BLOCKS(sb)))
+
 #ifdef CONFIG_QUOTA
 /* We need to update data and inode (atime) */
 #define REISERFS_QUOTA_TRANS_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? 2 : 0)
@@ -1697,7 +1717,7 @@ struct reiserfs_transaction_handle {
        int t_refcount;
        int t_blocks_logged;    /* number of blocks this writer has logged */
        int t_blocks_allocated; /* number of blocks this writer allocated */
-       unsigned long t_trans_id;       /* sanity check, equals the current trans id */
+       unsigned int t_trans_id;        /* sanity check, equals the current trans id */
        void *t_handle_save;    /* save existing current->journal_info */
        unsigned displace_new_blocks:1; /* if new block allocation occurres, that block
                                           should be displaced from others */
@@ -1773,13 +1793,13 @@ int journal_end_sync(struct reiserfs_transaction_handle *, struct super_block *,
 int journal_mark_freed(struct reiserfs_transaction_handle *,
                       struct super_block *, b_blocknr_t blocknr);
 int journal_transaction_should_end(struct reiserfs_transaction_handle *, int);
-int reiserfs_in_journal(struct super_block *p_s_sb, unsigned int bmap_nr,
-                       int bit_nr, int searchall, b_blocknr_t *next);
+int reiserfs_in_journal(struct super_block *sb, unsigned int bmap_nr,
+                        int bit_nr, int searchall, b_blocknr_t *next);
 int journal_begin(struct reiserfs_transaction_handle *,
-                 struct super_block *p_s_sb, unsigned long);
+                 struct super_block *sb, unsigned long);
 int journal_join_abort(struct reiserfs_transaction_handle *,
-                      struct super_block *p_s_sb, unsigned long);
-void reiserfs_journal_abort(struct super_block *sb, int errno);
+                      struct super_block *sb, unsigned long);
+void reiserfs_abort_journal(struct super_block *sb, int errno);
 void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...);
 int reiserfs_allocate_list_bitmaps(struct super_block *s,
                                   struct reiserfs_list_bitmap *, unsigned int);
@@ -1796,8 +1816,8 @@ int reiserfs_convert_objectid_map_v1(struct super_block *);
 
 /* stree.c */
 int B_IS_IN_TREE(const struct buffer_head *);
-extern void copy_item_head(struct item_head *p_v_to,
-                          const struct item_head *p_v_from);
+extern void copy_item_head(struct item_head *to,
+                          const struct item_head *from);
 
 // first key is in cpu form, second - le
 extern int comp_short_keys(const struct reiserfs_key *le_key,
@@ -1832,20 +1852,20 @@ static inline void copy_key(struct reiserfs_key *to,
        memcpy(to, from, KEY_SIZE);
 }
 
-int comp_items(const struct item_head *stored_ih, const struct treepath *p_s_path);
-const struct reiserfs_key *get_rkey(const struct treepath *p_s_chk_path,
-                                   const struct super_block *p_s_sb);
+int comp_items(const struct item_head *stored_ih, const struct treepath *path);
+const struct reiserfs_key *get_rkey(const struct treepath *chk_path,
+                                   const struct super_block *sb);
 int search_by_key(struct super_block *, const struct cpu_key *,
                  struct treepath *, int);
 #define search_item(s,key,path) search_by_key (s, key, path, DISK_LEAF_NODE_LEVEL)
-int search_for_position_by_key(struct super_block *p_s_sb,
-                              const struct cpu_key *p_s_cpu_key,
-                              struct treepath *p_s_search_path);
-extern void decrement_bcount(struct buffer_head *p_s_bh);
-void decrement_counters_in_path(struct treepath *p_s_search_path);
-void pathrelse(struct treepath *p_s_search_path);
+int search_for_position_by_key(struct super_block *sb,
+                              const struct cpu_key *cpu_key,
+                              struct treepath *search_path);
+extern void decrement_bcount(struct buffer_head *bh);
+void decrement_counters_in_path(struct treepath *search_path);
+void pathrelse(struct treepath *search_path);
 int reiserfs_check_path(struct treepath *p);
-void pathrelse_and_restore(struct super_block *s, struct treepath *p_s_search_path);
+void pathrelse_and_restore(struct super_block *s, struct treepath *search_path);
 
 int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
                         struct treepath *path,
@@ -1868,14 +1888,14 @@ int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th,
 int reiserfs_delete_item(struct reiserfs_transaction_handle *th,
                         struct treepath *path,
                         const struct cpu_key *key,
-                        struct inode *inode, struct buffer_head *p_s_un_bh);
+                        struct inode *inode, struct buffer_head *un_bh);
 
 void reiserfs_delete_solid_item(struct reiserfs_transaction_handle *th,
                                struct inode *inode, struct reiserfs_key *key);
 int reiserfs_delete_object(struct reiserfs_transaction_handle *th,
-                          struct inode *p_s_inode);
+                          struct inode *inode);
 int reiserfs_do_truncate(struct reiserfs_transaction_handle *th,
-                        struct inode *p_s_inode, struct page *,
+                        struct inode *inode, struct page *,
                         int update_timestamps);
 
 #define i_block_size(inode) ((inode)->i_sb->s_blocksize)
@@ -1919,10 +1939,12 @@ void make_le_item_head(struct item_head *ih, const struct cpu_key *key,
                       loff_t offset, int type, int length, int entry_count);
 struct inode *reiserfs_iget(struct super_block *s, const struct cpu_key *key);
 
+struct reiserfs_security_handle;
 int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
                       struct inode *dir, int mode,
                       const char *symname, loff_t i_size,
-                      struct dentry *dentry, struct inode *inode);
+                      struct dentry *dentry, struct inode *inode,
+                      struct reiserfs_security_handle *security);
 
 void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th,
                             struct inode *inode, loff_t size);
@@ -1980,7 +2002,7 @@ int reiserfs_global_version_in_proc(char *buffer, char **start, off_t offset,
 #define PROC_INFO_MAX( sb, field, value ) VOID_V
 #define PROC_INFO_INC( sb, field ) VOID_V
 #define PROC_INFO_ADD( sb, field, val ) VOID_V
-#define PROC_INFO_BH_STAT( p_s_sb, p_s_bh, n_node_level ) VOID_V
+#define PROC_INFO_BH_STAT(sb, bh, n_node_level) VOID_V
 #endif
 
 /* dir.c */
@@ -1988,6 +2010,7 @@ extern const struct inode_operations reiserfs_dir_inode_operations;
 extern const struct inode_operations reiserfs_symlink_inode_operations;
 extern const struct inode_operations reiserfs_special_inode_operations;
 extern const struct file_operations reiserfs_dir_operations;
+int reiserfs_readdir_dentry(struct dentry *, void *, filldir_t, loff_t *);
 
 /* tail_conversion.c */
 int direct2indirect(struct reiserfs_transaction_handle *, struct inode *,
@@ -2004,13 +2027,20 @@ extern const struct address_space_operations reiserfs_address_space_operations;
 
 /* fix_nodes.c */
 
-int fix_nodes(int n_op_mode, struct tree_balance *p_s_tb,
-             struct item_head *p_s_ins_ih, const void *);
+int fix_nodes(int n_op_mode, struct tree_balance *tb,
+             struct item_head *ins_ih, const void *);
 void unfix_nodes(struct tree_balance *);
 
 /* prints.c */
-void reiserfs_panic(struct super_block *s, const char *fmt, ...)
+void __reiserfs_panic(struct super_block *s, const char *id,
+                     const char *function, const char *fmt, ...)
     __attribute__ ((noreturn));
+#define reiserfs_panic(s, id, fmt, args...) \
+       __reiserfs_panic(s, id, __func__, fmt, ##args)
+void __reiserfs_error(struct super_block *s, const char *id,
+                     const char *function, const char *fmt, ...);
+#define reiserfs_error(s, id, fmt, args...) \
+        __reiserfs_error(s, id, __func__, fmt, ##args)
 void reiserfs_info(struct super_block *s, const char *fmt, ...);
 void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...);
 void print_indirect_item(struct buffer_head *bh, int item_num);
@@ -2047,7 +2077,7 @@ void leaf_paste_in_buffer(struct buffer_info *bi, int pasted_item_num,
                          int zeros_number);
 void leaf_cut_from_buffer(struct buffer_info *bi, int cut_item_num,
                          int pos_in_item, int cut_size);
-void leaf_paste_entries(struct buffer_head *bh, int item_num, int before,
+void leaf_paste_entries(struct buffer_info *bi, int item_num, int before,
                        int new_entry_count, struct reiserfs_de_head *new_dehs,
                        const char *records, int paste_size);
 /* ibalance.c */
@@ -2203,6 +2233,6 @@ long reiserfs_compat_ioctl(struct file *filp,
                   unsigned int cmd, unsigned long arg);
 int reiserfs_unpack(struct inode *inode, struct file *filp);
 
-
 #endif /* __KERNEL__ */
+
 #endif                         /* _LINUX_REISER_FS_H */
index ce3663fb0101dca7513183833b474424f4d10c54..76360b36ac3324040a5066cc15ddca9b5c2e98b0 100644 (file)
@@ -51,7 +51,7 @@ struct reiserfs_inode_info {
        /* we use these for fsync or O_SYNC to decide which transaction
         ** needs to be committed in order for this inode to be properly
         ** flushed */
-       unsigned long i_trans_id;
+       unsigned int i_trans_id;
        struct reiserfs_journal_list *i_jl;
        struct mutex i_mmap;
 #ifdef CONFIG_REISERFS_FS_POSIX_ACL
@@ -59,7 +59,7 @@ struct reiserfs_inode_info {
        struct posix_acl *i_acl_default;
 #endif
 #ifdef CONFIG_REISERFS_FS_XATTR
-       struct rw_semaphore xattr_sem;
+       struct rw_semaphore i_xattr_sem;
 #endif
        struct inode vfs_inode;
 };
index bda6b562a1e05dc5ee936ca52dfc8bfb14ae86a9..5621d87c44793401affb812cf47213f50406a63b 100644 (file)
@@ -14,7 +14,7 @@ typedef enum {
 } reiserfs_super_block_flags;
 
 /* struct reiserfs_super_block accessors/mutators
- * since this is a disk structure, it will always be in 
+ * since this is a disk structure, it will always be in
  * little endian format. */
 #define sb_block_count(sbp)         (le32_to_cpu((sbp)->s_v1.s_block_count))
 #define set_sb_block_count(sbp,v)   ((sbp)->s_v1.s_block_count = cpu_to_le32(v))
@@ -73,6 +73,9 @@ typedef enum {
 #define sb_version(sbp)            (le16_to_cpu((sbp)->s_v1.s_version))
 #define set_sb_version(sbp,v)      ((sbp)->s_v1.s_version = cpu_to_le16(v))
 
+#define sb_mnt_count(sbp)         (le16_to_cpu((sbp)->s_mnt_count))
+#define set_sb_mnt_count(sbp, v)   ((sbp)->s_mnt_count = cpu_to_le16(v))
+
 #define sb_reserved_for_journal(sbp) \
               (le16_to_cpu((sbp)->s_v1.s_reserved_for_journal))
 #define set_sb_reserved_for_journal(sbp,v) \
@@ -80,16 +83,16 @@ typedef enum {
 
 /* LOGGING -- */
 
-/* These all interelate for performance.  
+/* These all interelate for performance.
 **
-** If the journal block count is smaller than n transactions, you lose speed. 
+** If the journal block count is smaller than n transactions, you lose speed.
 ** I don't know what n is yet, I'm guessing 8-16.
 **
 ** typical transaction size depends on the application, how often fsync is
-** called, and how many metadata blocks you dirty in a 30 second period.  
+** called, and how many metadata blocks you dirty in a 30 second period.
 ** The more small files (<16k) you use, the larger your transactions will
 ** be.
-** 
+**
 ** If your journal fills faster than dirty buffers get flushed to disk, it must flush them before allowing the journal
 ** to wrap, which slows things down.  If you need high speed meta data updates, the journal should be big enough
 ** to prevent wrapping before dirty meta blocks get to disk.
@@ -153,7 +156,7 @@ struct reiserfs_journal_list {
        atomic_t j_commit_left;
        atomic_t j_older_commits_done;  /* all commits older than this on disk */
        struct mutex j_commit_mutex;
-       unsigned long j_trans_id;
+       unsigned int j_trans_id;
        time_t j_timestamp;
        struct reiserfs_list_bitmap *j_list_bitmap;
        struct buffer_head *j_commit_bh;        /* commit buffer head */
@@ -182,7 +185,7 @@ struct reiserfs_journal {
        int j_1st_reserved_block;       /* first block on s_dev of reserved area journal */
 
        unsigned long j_state;
-       unsigned long j_trans_id;
+       unsigned int j_trans_id;
        unsigned long j_mount_id;
        unsigned long j_start;  /* start of current waiting commit (index into j_ap_blocks) */
        unsigned long j_len;    /* length of current waiting commit */
@@ -223,10 +226,10 @@ struct reiserfs_journal {
        int j_num_work_lists;   /* number that need attention from kreiserfsd */
 
        /* debugging to make sure things are flushed in order */
-       int j_last_flush_id;
+       unsigned int j_last_flush_id;
 
        /* debugging to make sure things are committed in order */
-       int j_last_commit_id;
+       unsigned int j_last_commit_id;
 
        struct list_head j_bitmap_nodes;
        struct list_head j_dirty_buffers;
@@ -239,7 +242,7 @@ struct reiserfs_journal {
 
        struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS]; /* array of bitmaps to record the deleted blocks */
        struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE]; /* hash table for real buffer heads in current trans */
-       struct reiserfs_journal_cnode *j_list_hash_table[JOURNAL_HASH_SIZE];    /* hash table for all the real buffer heads in all 
+       struct reiserfs_journal_cnode *j_list_hash_table[JOURNAL_HASH_SIZE];    /* hash table for all the real buffer heads in all
                                                                                   the transactions */
        struct list_head j_prealloc_list;       /* list of inodes which have preallocated blocks */
        int j_persistent_trans;
@@ -399,10 +402,7 @@ struct reiserfs_sb_info {
        int reserved_blocks;    /* amount of blocks reserved for further allocations */
        spinlock_t bitmap_lock; /* this lock on now only used to protect reserved_blocks variable */
        struct dentry *priv_root;       /* root of /.reiserfs_priv */
-#ifdef CONFIG_REISERFS_FS_XATTR
        struct dentry *xattr_root;      /* root of /.reiserfs_priv/.xa */
-       struct rw_semaphore xattr_dir_sem;
-#endif
        int j_errno;
 #ifdef CONFIG_QUOTA
        char *s_qf_names[MAXQUOTAS];
@@ -426,7 +426,7 @@ enum reiserfs_mount_options {
                                   partition will be dealt with in a
                                   manner of 3.5.x */
 
-/* -o hash={tea, rupasov, r5, detect} is meant for properly mounting 
+/* -o hash={tea, rupasov, r5, detect} is meant for properly mounting
 ** reiserfs disks from 3.5.19 or earlier.  99% of the time, this option
 ** is not required.  If the normal autodection code can't determine which
 ** hash to use (because both hashes had the same value for a file)
@@ -451,7 +451,6 @@ enum reiserfs_mount_options {
        REISERFS_NO_UNHASHED_RELOCATION,
        REISERFS_HASHED_RELOCATION,
        REISERFS_ATTRS,
-       REISERFS_XATTRS,
        REISERFS_XATTRS_USER,
        REISERFS_POSIXACL,
        REISERFS_BARRIER_NONE,
@@ -489,7 +488,7 @@ enum reiserfs_mount_options {
 #define reiserfs_data_log(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_LOG))
 #define reiserfs_data_ordered(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_ORDERED))
 #define reiserfs_data_writeback(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_WRITEBACK))
-#define reiserfs_xattrs(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS))
+#define reiserfs_xattrs(s) ((s)->s_xattr != NULL)
 #define reiserfs_xattrs_user(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS_USER))
 #define reiserfs_posixacl(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_POSIXACL))
 #define reiserfs_xattrs_optional(s) (reiserfs_xattrs_user(s) || reiserfs_posixacl(s))
index af135ae895db2d3523839c5f1a0857ed54db3aca..dcae01e63e4080636d76955c813c38047b980991 100644 (file)
@@ -15,6 +15,12 @@ struct reiserfs_xattr_header {
        __le32 h_hash;          /* hash of the value */
 };
 
+struct reiserfs_security_handle {
+       char *name;
+       void *value;
+       size_t length;
+};
+
 #ifdef __KERNEL__
 
 #include <linux/init.h>
@@ -29,22 +35,13 @@ struct iattr;
 struct super_block;
 struct nameidata;
 
-struct reiserfs_xattr_handler {
-       char *prefix;
-       int (*init) (void);
-       void (*exit) (void);
-       int (*get) (struct inode * inode, const char *name, void *buffer,
-                   size_t size);
-       int (*set) (struct inode * inode, const char *name, const void *buffer,
-                   size_t size, int flags);
-       int (*del) (struct inode * inode, const char *name);
-       int (*list) (struct inode * inode, const char *name, int namelen,
-                    char *out);
-       struct list_head handlers;
-};
+int reiserfs_xattr_register_handlers(void) __init;
+void reiserfs_xattr_unregister_handlers(void);
+int reiserfs_xattr_init(struct super_block *sb, int mount_flags);
+int reiserfs_delete_xattrs(struct inode *inode);
+int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs);
 
 #ifdef CONFIG_REISERFS_FS_XATTR
-#define is_reiserfs_priv_object(inode) IS_PRIVATE(inode)
 #define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)
 ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name,
                          void *buffer, size_t size);
@@ -52,104 +49,97 @@ int reiserfs_setxattr(struct dentry *dentry, const char *name,
                      const void *value, size_t size, int flags);
 ssize_t reiserfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
 int reiserfs_removexattr(struct dentry *dentry, const char *name);
-int reiserfs_delete_xattrs(struct inode *inode);
-int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs);
-int reiserfs_xattr_init(struct super_block *sb, int mount_flags);
 int reiserfs_permission(struct inode *inode, int mask);
 
-int reiserfs_xattr_del(struct inode *, const char *);
-int reiserfs_xattr_get(const struct inode *, const char *, void *, size_t);
+int reiserfs_xattr_get(struct inode *, const char *, void *, size_t);
 int reiserfs_xattr_set(struct inode *, const char *, const void *, size_t, int);
-
-extern struct reiserfs_xattr_handler user_handler;
-extern struct reiserfs_xattr_handler trusted_handler;
-extern struct reiserfs_xattr_handler security_handler;
-
-int reiserfs_xattr_register_handlers(void) __init;
-void reiserfs_xattr_unregister_handlers(void);
-
-static inline void reiserfs_write_lock_xattrs(struct super_block *sb)
-{
-       down_write(&REISERFS_XATTR_DIR_SEM(sb));
-}
-static inline void reiserfs_write_unlock_xattrs(struct super_block *sb)
-{
-       up_write(&REISERFS_XATTR_DIR_SEM(sb));
-}
-static inline void reiserfs_read_lock_xattrs(struct super_block *sb)
-{
-       down_read(&REISERFS_XATTR_DIR_SEM(sb));
-}
-
-static inline void reiserfs_read_unlock_xattrs(struct super_block *sb)
+int reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *,
+                             struct inode *, const char *, const void *,
+                             size_t, int);
+
+extern struct xattr_handler reiserfs_xattr_user_handler;
+extern struct xattr_handler reiserfs_xattr_trusted_handler;
+extern struct xattr_handler reiserfs_xattr_security_handler;
+#ifdef CONFIG_REISERFS_FS_SECURITY
+int reiserfs_security_init(struct inode *dir, struct inode *inode,
+                          struct reiserfs_security_handle *sec);
+int reiserfs_security_write(struct reiserfs_transaction_handle *th,
+                           struct inode *inode,
+                           struct reiserfs_security_handle *sec);
+void reiserfs_security_free(struct reiserfs_security_handle *sec);
+#endif
+
+#define xattr_size(size) ((size) + sizeof(struct reiserfs_xattr_header))
+static inline loff_t reiserfs_xattr_nblocks(struct inode *inode, loff_t size)
 {
-       up_read(&REISERFS_XATTR_DIR_SEM(sb));
+       loff_t ret = 0;
+       if (reiserfs_file_data_log(inode)) {
+               ret = _ROUND_UP(xattr_size(size), inode->i_sb->s_blocksize);
+               ret >>= inode->i_sb->s_blocksize_bits;
+       }
+       return ret;
 }
 
-static inline void reiserfs_write_lock_xattr_i(struct inode *inode)
-{
-       down_write(&REISERFS_I(inode)->xattr_sem);
-}
-static inline void reiserfs_write_unlock_xattr_i(struct inode *inode)
+/* We may have to create up to 3 objects: xattr root, xattr dir, xattr file.
+ * Let's try to be smart about it.
+ * xattr root: We cache it. If it's not cached, we may need to create it.
+ * xattr dir: If anything has been loaded for this inode, we can set a flag
+ *            saying so.
+ * xattr file: Since we don't cache xattrs, we can't tell. We always include
+ *             blocks for it.
+ *
+ * However, since root and dir can be created between calls - YOU MUST SAVE
+ * THIS VALUE.
+ */
+static inline size_t reiserfs_xattr_jcreate_nblocks(struct inode *inode)
 {
-       up_write(&REISERFS_I(inode)->xattr_sem);
-}
-static inline void reiserfs_read_lock_xattr_i(struct inode *inode)
-{
-       down_read(&REISERFS_I(inode)->xattr_sem);
-}
+       size_t nblocks = JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
 
-static inline void reiserfs_read_unlock_xattr_i(struct inode *inode)
-{
-       up_read(&REISERFS_I(inode)->xattr_sem);
-}
+       if ((REISERFS_I(inode)->i_flags & i_has_xattr_dir) == 0) {
+               nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
+               if (REISERFS_SB(inode->i_sb)->xattr_root == NULL)
+                       nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
+       }
 
-static inline void reiserfs_mark_inode_private(struct inode *inode)
-{
-       inode->i_flags |= S_PRIVATE;
+       return nblocks;
 }
 
 static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
 {
-       init_rwsem(&REISERFS_I(inode)->xattr_sem);
+       init_rwsem(&REISERFS_I(inode)->i_xattr_sem);
 }
 
 #else
 
-#define is_reiserfs_priv_object(inode) 0
-#define reiserfs_mark_inode_private(inode) do {;} while(0)
 #define reiserfs_getxattr NULL
 #define reiserfs_setxattr NULL
 #define reiserfs_listxattr NULL
 #define reiserfs_removexattr NULL
-#define reiserfs_write_lock_xattrs(sb) do {;} while(0)
-#define reiserfs_write_unlock_xattrs(sb) do {;} while(0)
-#define reiserfs_read_lock_xattrs(sb)
-#define reiserfs_read_unlock_xattrs(sb)
 
 #define reiserfs_permission NULL
 
-#define reiserfs_xattr_register_handlers() 0
-#define reiserfs_xattr_unregister_handlers()
-
-static inline int reiserfs_delete_xattrs(struct inode *inode)
+static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
 {
-       return 0;
-};
-static inline int reiserfs_chown_xattrs(struct inode *inode,
-                                       struct iattr *attrs)
+}
+#endif  /*  CONFIG_REISERFS_FS_XATTR  */
+
+#ifndef CONFIG_REISERFS_FS_SECURITY
+static inline int reiserfs_security_init(struct inode *dir,
+                                        struct inode *inode,
+                                        struct reiserfs_security_handle *sec)
 {
        return 0;
-};
-static inline int reiserfs_xattr_init(struct super_block *sb, int mount_flags)
+}
+static inline int
+reiserfs_security_write(struct reiserfs_transaction_handle *th,
+                       struct inode *inode,
+                       struct reiserfs_security_handle *sec)
 {
-       sb->s_flags = (sb->s_flags & ~MS_POSIXACL);     /* to be sure */
        return 0;
-};
-static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
-{
 }
-#endif  /*  CONFIG_REISERFS_FS_XATTR  */
+static inline void reiserfs_security_free(struct reiserfs_security_handle *sec)
+{}
+#endif
 
 #endif  /*  __KERNEL__  */
 
index bf74e63c98fec6d4249df6e5fdc00553e3104398..8ba646e610d9232ce6b9b1a0bff42844a866b456 100644 (file)
  * is used depends on the board. */
 struct v3020_platform_data {
        int leftshift; /* (1<<(leftshift)) & readl() */
+
+       int use_gpio:1;
+       unsigned int gpio_cs;
+       unsigned int gpio_wr;
+       unsigned int gpio_rd;
+       unsigned int gpio_io;
 };
 
 #define V3020_STATUS_0 0x00
index 4046b75563c1c26dc8d11352b77c73139d1b99ce..60f88a7fb13d71ec5abd0f174e6777fc77b0f5b9 100644 (file)
@@ -99,6 +99,7 @@ struct rtc_pll_info {
 
 #ifdef __KERNEL__
 
+#include <linux/types.h>
 #include <linux/interrupt.h>
 
 extern int rtc_month_days(unsigned int month, unsigned int year);
@@ -232,6 +233,11 @@ int rtc_register(rtc_task_t *task);
 int rtc_unregister(rtc_task_t *task);
 int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg);
 
+static inline bool is_leap_year(unsigned int year)
+{
+       return (!(year % 4) && (year % 100)) || !(year % 400);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_RTC_H_ */
index 1d19c025f9d2e78b34692b3f350d9bef6fe522ed..206ac003e8c0ba2b3f492e6e2dd4ec15d53b1b47 100644 (file)
@@ -331,7 +331,9 @@ extern signed long schedule_timeout(signed long timeout);
 extern signed long schedule_timeout_interruptible(signed long timeout);
 extern signed long schedule_timeout_killable(signed long timeout);
 extern signed long schedule_timeout_uninterruptible(signed long timeout);
+asmlinkage void __schedule(void);
 asmlinkage void schedule(void);
+extern int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner);
 
 struct nsproxy;
 struct user_namespace;
@@ -389,8 +391,15 @@ extern void arch_unmap_area_topdown(struct mm_struct *, unsigned long);
                (mm)->hiwater_vm = (mm)->total_vm;      \
 } while (0)
 
-#define get_mm_hiwater_rss(mm) max((mm)->hiwater_rss, get_mm_rss(mm))
-#define get_mm_hiwater_vm(mm)  max((mm)->hiwater_vm, (mm)->total_vm)
+static inline unsigned long get_mm_hiwater_rss(struct mm_struct *mm)
+{
+       return max(mm->hiwater_rss, get_mm_rss(mm));
+}
+
+static inline unsigned long get_mm_hiwater_vm(struct mm_struct *mm)
+{
+       return max(mm->hiwater_vm, mm->total_vm);
+}
 
 extern void set_dumpable(struct mm_struct *mm, int value);
 extern int get_dumpable(struct mm_struct *mm);
@@ -538,25 +547,8 @@ struct signal_struct {
 
        struct list_head cpu_timers[3];
 
-       /* job control IDs */
-
-       /*
-        * pgrp and session fields are deprecated.
-        * use the task_session_Xnr and task_pgrp_Xnr routines below
-        */
-
-       union {
-               pid_t pgrp __deprecated;
-               pid_t __pgrp;
-       };
-
        struct pid *tty_old_pgrp;
 
-       union {
-               pid_t session __deprecated;
-               pid_t __session;
-       };
-
        /* boolean value for session group leader */
        int leader;
 
@@ -1334,6 +1326,7 @@ struct task_struct {
        int lockdep_depth;
        unsigned int lockdep_recursion;
        struct held_lock held_locks[MAX_LOCK_DEPTH];
+       gfp_t lockdep_reclaim_gfp;
 #endif
 
 /* journalling filesystem info */
@@ -1459,16 +1452,6 @@ static inline int rt_task(struct task_struct *p)
        return rt_prio(p->prio);
 }
 
-static inline void set_task_session(struct task_struct *tsk, pid_t session)
-{
-       tsk->signal->__session = session;
-}
-
-static inline void set_task_pgrp(struct task_struct *tsk, pid_t pgrp)
-{
-       tsk->signal->__pgrp = pgrp;
-}
-
 static inline struct pid *task_pid(struct task_struct *task)
 {
        return task->pids[PIDTYPE_PID].pid;
@@ -1479,6 +1462,11 @@ static inline struct pid *task_tgid(struct task_struct *task)
        return task->group_leader->pids[PIDTYPE_PID].pid;
 }
 
+/*
+ * Without tasklist or rcu lock it is not safe to dereference
+ * the result of task_pgrp/task_session even if task == current,
+ * we can race with another thread doing sys_setsid/sys_setpgid.
+ */
 static inline struct pid *task_pgrp(struct task_struct *task)
 {
        return task->group_leader->pids[PIDTYPE_PGID].pid;
@@ -1504,17 +1492,23 @@ struct pid_namespace;
  *
  * see also pid_nr() etc in include/linux/pid.h
  */
+pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type,
+                       struct pid_namespace *ns);
 
 static inline pid_t task_pid_nr(struct task_struct *tsk)
 {
        return tsk->pid;
 }
 
-pid_t task_pid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns);
+static inline pid_t task_pid_nr_ns(struct task_struct *tsk,
+                                       struct pid_namespace *ns)
+{
+       return __task_pid_nr_ns(tsk, PIDTYPE_PID, ns);
+}
 
 static inline pid_t task_pid_vnr(struct task_struct *tsk)
 {
-       return pid_vnr(task_pid(tsk));
+       return __task_pid_nr_ns(tsk, PIDTYPE_PID, NULL);
 }
 
 
@@ -1531,31 +1525,34 @@ static inline pid_t task_tgid_vnr(struct task_struct *tsk)
 }
 
 
-static inline pid_t task_pgrp_nr(struct task_struct *tsk)
+static inline pid_t task_pgrp_nr_ns(struct task_struct *tsk,
+                                       struct pid_namespace *ns)
 {
-       return tsk->signal->__pgrp;
+       return __task_pid_nr_ns(tsk, PIDTYPE_PGID, ns);
 }
 
-pid_t task_pgrp_nr_ns(struct task_struct *tsk, struct pid_namespace *ns);
-
 static inline pid_t task_pgrp_vnr(struct task_struct *tsk)
 {
-       return pid_vnr(task_pgrp(tsk));
+       return __task_pid_nr_ns(tsk, PIDTYPE_PGID, NULL);
 }
 
 
-static inline pid_t task_session_nr(struct task_struct *tsk)
+static inline pid_t task_session_nr_ns(struct task_struct *tsk,
+                                       struct pid_namespace *ns)
 {
-       return tsk->signal->__session;
+       return __task_pid_nr_ns(tsk, PIDTYPE_SID, ns);
 }
 
-pid_t task_session_nr_ns(struct task_struct *tsk, struct pid_namespace *ns);
-
 static inline pid_t task_session_vnr(struct task_struct *tsk)
 {
-       return pid_vnr(task_session(tsk));
+       return __task_pid_nr_ns(tsk, PIDTYPE_SID, NULL);
 }
 
+/* obsolete, do not use */
+static inline pid_t task_pgrp_nr(struct task_struct *tsk)
+{
+       return task_pgrp_nr_ns(tsk, &init_pid_ns);
+}
 
 /**
  * pid_alive - check that a task structure is not stale
@@ -1965,7 +1962,8 @@ extern void mm_release(struct task_struct *, struct mm_struct *);
 /* Allocate a new mm structure and copy contents from tsk->mm */
 extern struct mm_struct *dup_mm(struct task_struct *tsk);
 
-extern int  copy_thread(int, unsigned long, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
+extern int copy_thread(unsigned long, unsigned long, unsigned long,
+                       struct task_struct *, struct pt_regs *);
 extern void flush_thread(void);
 extern void exit_thread(void);
 
@@ -2050,6 +2048,11 @@ static inline int thread_group_empty(struct task_struct *p)
 #define delay_group_leader(p) \
                (thread_group_leader(p) && !thread_group_empty(p))
 
+static inline int task_detached(struct task_struct *p)
+{
+       return p->exit_signal == -1;
+}
+
 /*
  * Protects ->fs, ->files, ->mm, ->group_info, ->comm, keyring
  * subscriptions and synchronises with wait4().  Also used in procfs.  Also
index 1f2ab6353c00a323198c0400d69aff158447e24e..54ed15799a8315fd1738390ef4c5666353ddc435 100644 (file)
@@ -880,11 +880,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     @sock contains the listening socket structure.
  *     @newsock contains the newly created server socket for connection.
  *     Return 0 if permission is granted.
- * @socket_post_accept:
- *     This hook allows a security module to copy security
- *     information into the newly created socket's inode.
- *     @sock contains the listening socket structure.
- *     @newsock contains the newly created server socket for connection.
  * @socket_sendmsg:
  *     Check permission before transmitting a message to another socket.
  *     @sock contains the socket structure.
@@ -1554,8 +1549,6 @@ struct security_operations {
                               struct sockaddr *address, int addrlen);
        int (*socket_listen) (struct socket *sock, int backlog);
        int (*socket_accept) (struct socket *sock, struct socket *newsock);
-       void (*socket_post_accept) (struct socket *sock,
-                                   struct socket *newsock);
        int (*socket_sendmsg) (struct socket *sock,
                               struct msghdr *msg, int size);
        int (*socket_recvmsg) (struct socket *sock,
@@ -2537,7 +2530,6 @@ int security_socket_bind(struct socket *sock, struct sockaddr *address, int addr
 int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen);
 int security_socket_listen(struct socket *sock, int backlog);
 int security_socket_accept(struct socket *sock, struct socket *newsock);
-void security_socket_post_accept(struct socket *sock, struct socket *newsock);
 int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size);
 int security_socket_recvmsg(struct socket *sock, struct msghdr *msg,
                            int size, int flags);
@@ -2616,11 +2608,6 @@ static inline int security_socket_accept(struct socket *sock,
        return 0;
 }
 
-static inline void security_socket_post_accept(struct socket *sock,
-                                              struct socket *newsock)
-{
-}
-
 static inline int security_socket_sendmsg(struct socket *sock,
                                          struct msghdr *msg, int size)
 {
index f616f31576d719597cd91b25498fece72e24cc8d..004f3b3342c5d580664b73aab18a9229186c9ed9 100644 (file)
@@ -55,7 +55,7 @@ int seq_bitmap(struct seq_file *m, const unsigned long *bits,
                                   unsigned int nr_bits);
 static inline int seq_cpumask(struct seq_file *m, const struct cpumask *mask)
 {
-       return seq_bitmap(m, mask->bits, nr_cpu_ids);
+       return seq_bitmap(m, cpumask_bits(mask), nr_cpu_ids);
 }
 
 static inline int seq_nodemask(struct seq_file *m, nodemask_t *mask)
@@ -63,12 +63,13 @@ static inline int seq_nodemask(struct seq_file *m, nodemask_t *mask)
        return seq_bitmap(m, mask->bits, MAX_NUMNODES);
 }
 
-int seq_bitmap_list(struct seq_file *m, unsigned long *bits,
+int seq_bitmap_list(struct seq_file *m, const unsigned long *bits,
                unsigned int nr_bits);
 
-static inline int seq_cpumask_list(struct seq_file *m, cpumask_t *mask)
+static inline int seq_cpumask_list(struct seq_file *m,
+                                  const struct cpumask *mask)
 {
-       return seq_bitmap_list(m, mask->bits, NR_CPUS);
+       return seq_bitmap_list(m, cpumask_bits(mask), nr_cpu_ids);
 }
 
 static inline int seq_nodemask_list(struct seq_file *m, nodemask_t *mask)
index 1085212c446e2bf562e9b4e1867be002af9ebaf6..306e7b1c69edf30243836e89d7141e47934e7a98 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __LINUX_SPI_EEPROM_H
 #define __LINUX_SPI_EEPROM_H
 
+#include <linux/memory.h>
+
 /*
  * Put one of these structures in platform_data for SPI EEPROMS handled
  * by the "at25" driver.  On SPI, most EEPROMS understand the same core
@@ -17,6 +19,10 @@ struct spi_eeprom {
 #define        EE_ADDR2        0x0002                  /* 16 bit addrs */
 #define        EE_ADDR3        0x0004                  /* 24 bit addrs */
 #define        EE_READONLY     0x0008                  /* disallow writes */
+
+       /* for exporting this chip's data to other kernel code */
+       void (*setup)(struct memory_accessor *mem, void *context);
+       void *context;
 };
 
 #endif /* __LINUX_SPI_EEPROM_H */
index 0f01a0f1f40c9718a67dfc08f2561a0c13521fc7..ca6782ee4b9fce4f9208020e552129db6f0fbd5a 100644 (file)
  *     ...
  *     };
  *
+ * If chipselect is not used (there's only one device on the bus), assign
+ * SPI_GPIO_NO_CHIPSELECT to the controller_data:
+ *             .controller_data = (void *) SPI_GPIO_NO_CHIPSELECT;
+ *
  * If the bitbanged bus is later switched to a "native" controller,
  * that platform_device and controller_data should be removed.
  */
 
+#define SPI_GPIO_NO_CHIPSELECT         ((unsigned long)-1l)
+
 /**
  * struct spi_gpio_platform_data - parameter for bitbanged SPI master
  * @sck: number of the GPIO used for clock output
index a0c66a2e00add24f97bfcc908dff123fa4a200c6..252b245cfcf4cb098658da65f60f02436b12902f 100644 (file)
@@ -153,9 +153,11 @@ do {                                                               \
  extern int _raw_spin_trylock(spinlock_t *lock);
  extern void _raw_spin_unlock(spinlock_t *lock);
  extern void _raw_read_lock(rwlock_t *lock);
+#define _raw_read_lock_flags(lock, flags) _raw_read_lock(lock)
  extern int _raw_read_trylock(rwlock_t *lock);
  extern void _raw_read_unlock(rwlock_t *lock);
  extern void _raw_write_lock(rwlock_t *lock);
+#define _raw_write_lock_flags(lock, flags) _raw_write_lock(lock)
  extern int _raw_write_trylock(rwlock_t *lock);
  extern void _raw_write_unlock(rwlock_t *lock);
 #else
@@ -165,9 +167,13 @@ do {                                                               \
 # define _raw_spin_trylock(lock)       __raw_spin_trylock(&(lock)->raw_lock)
 # define _raw_spin_unlock(lock)                __raw_spin_unlock(&(lock)->raw_lock)
 # define _raw_read_lock(rwlock)                __raw_read_lock(&(rwlock)->raw_lock)
+# define _raw_read_lock_flags(lock, flags) \
+               __raw_read_lock_flags(&(lock)->raw_lock, *(flags))
 # define _raw_read_trylock(rwlock)     __raw_read_trylock(&(rwlock)->raw_lock)
 # define _raw_read_unlock(rwlock)      __raw_read_unlock(&(rwlock)->raw_lock)
 # define _raw_write_lock(rwlock)       __raw_write_lock(&(rwlock)->raw_lock)
+# define _raw_write_lock_flags(lock, flags) \
+               __raw_write_lock_flags(&(lock)->raw_lock, *(flags))
 # define _raw_write_trylock(rwlock)    __raw_write_trylock(&(rwlock)->raw_lock)
 # define _raw_write_unlock(rwlock)     __raw_write_unlock(&(rwlock)->raw_lock)
 #endif
index d18fc198aa2fd3c337e821e78eedc97e5ea8459b..8852739f36dfe94529ad3bdb09555741b0829b9e 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/stddef.h>      /* for NULL */
 
 extern char *strndup_user(const char __user *, long);
+extern void *memdup_user(const void __user *, size_t);
 
 /*
  * Include machine specific inline routines
index 3435d24bfe5515d6abd41f3323316aadb68f0c11..d3a4c0231933c4e3e5885fd46362b15a6ce96a77 100644 (file)
@@ -69,7 +69,6 @@ struct svc_serv {
        struct list_head        sv_tempsocks;   /* all temporary sockets */
        int                     sv_tmpcnt;      /* count of temporary sockets */
        struct timer_list       sv_temptimer;   /* timer for aging temporary sockets */
-       sa_family_t             sv_family;      /* listener's address family */
 
        char *                  sv_name;        /* service name */
 
@@ -385,19 +384,19 @@ struct svc_procedure {
 /*
  * Function prototypes.
  */
-struct svc_serv *svc_create(struct svc_program *, unsigned int, sa_family_t,
+struct svc_serv *svc_create(struct svc_program *, unsigned int,
                            void (*shutdown)(struct svc_serv *));
 struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
                                        struct svc_pool *pool);
 void              svc_exit_thread(struct svc_rqst *);
 struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
-                       sa_family_t, void (*shutdown)(struct svc_serv *),
+                       void (*shutdown)(struct svc_serv *),
                        svc_thread_fn, struct module *);
 int               svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
 void              svc_destroy(struct svc_serv *);
 int               svc_process(struct svc_rqst *);
-int               svc_register(const struct svc_serv *, const unsigned short,
-                               const unsigned short);
+int               svc_register(const struct svc_serv *, const int,
+                               const unsigned short, const unsigned short);
 
 void              svc_wake_up(struct svc_serv *);
 void              svc_reserve(struct svc_rqst *rqstp, int space);
index 0127daca43548c85c219abc6445101165380eef9..0d9cb6ef28b00cf58c7b25824a0325e8909eb98a 100644 (file)
@@ -71,7 +71,8 @@ int   svc_reg_xprt_class(struct svc_xprt_class *);
 void   svc_unreg_xprt_class(struct svc_xprt_class *);
 void   svc_xprt_init(struct svc_xprt_class *, struct svc_xprt *,
                      struct svc_serv *);
-int    svc_create_xprt(struct svc_serv *, char *, unsigned short, int);
+int    svc_create_xprt(struct svc_serv *, const char *, const int,
+                       const unsigned short, int);
 void   svc_xprt_enqueue(struct svc_xprt *xprt);
 void   svc_xprt_received(struct svc_xprt *);
 void   svc_xprt_put(struct svc_xprt *xprt);
@@ -80,7 +81,8 @@ void  svc_close_xprt(struct svc_xprt *xprt);
 void   svc_delete_xprt(struct svc_xprt *xprt);
 int    svc_port_is_privileged(struct sockaddr *sin);
 int    svc_print_xprts(char *buf, int maxlen);
-struct svc_xprt *svc_find_xprt(struct svc_serv *, char *, int, int);
+struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
+                       const sa_family_t af, const unsigned short port);
 int    svc_xprt_names(struct svc_serv *serv, char *buf, int buflen);
 
 static inline void svc_xprt_get(struct svc_xprt *xprt)
@@ -88,29 +90,32 @@ static inline void svc_xprt_get(struct svc_xprt *xprt)
        kref_get(&xprt->xpt_ref);
 }
 static inline void svc_xprt_set_local(struct svc_xprt *xprt,
-                                     struct sockaddr *sa, int salen)
+                                     const struct sockaddr *sa,
+                                     const size_t salen)
 {
        memcpy(&xprt->xpt_local, sa, salen);
        xprt->xpt_locallen = salen;
 }
 static inline void svc_xprt_set_remote(struct svc_xprt *xprt,
-                                      struct sockaddr *sa, int salen)
+                                      const struct sockaddr *sa,
+                                      const size_t salen)
 {
        memcpy(&xprt->xpt_remote, sa, salen);
        xprt->xpt_remotelen = salen;
 }
-static inline unsigned short svc_addr_port(struct sockaddr *sa)
+static inline unsigned short svc_addr_port(const struct sockaddr *sa)
 {
-       unsigned short ret = 0;
+       const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
+       const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
+
        switch (sa->sa_family) {
        case AF_INET:
-               ret = ntohs(((struct sockaddr_in *)sa)->sin_port);
-               break;
+               return ntohs(sin->sin_port);
        case AF_INET6:
-               ret = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
-               break;
+               return ntohs(sin6->sin6_port);
        }
-       return ret;
+
+       return 0;
 }
 
 static inline size_t svc_addr_len(struct sockaddr *sa)
@@ -124,36 +129,39 @@ static inline size_t svc_addr_len(struct sockaddr *sa)
        return -EAFNOSUPPORT;
 }
 
-static inline unsigned short svc_xprt_local_port(struct svc_xprt *xprt)
+static inline unsigned short svc_xprt_local_port(const struct svc_xprt *xprt)
 {
-       return svc_addr_port((struct sockaddr *)&xprt->xpt_local);
+       return svc_addr_port((const struct sockaddr *)&xprt->xpt_local);
 }
 
-static inline unsigned short svc_xprt_remote_port(struct svc_xprt *xprt)
+static inline unsigned short svc_xprt_remote_port(const struct svc_xprt *xprt)
 {
-       return svc_addr_port((struct sockaddr *)&xprt->xpt_remote);
+       return svc_addr_port((const struct sockaddr *)&xprt->xpt_remote);
 }
 
-static inline char *__svc_print_addr(struct sockaddr *addr,
-                                    char *buf, size_t len)
+static inline char *__svc_print_addr(const struct sockaddr *addr,
+                                    char *buf, const size_t len)
 {
+       const struct sockaddr_in *sin = (const struct sockaddr_in *)addr;
+       const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)addr;
+
        switch (addr->sa_family) {
        case AF_INET:
-               snprintf(buf, len, "%pI4, port=%u",
-                       &((struct sockaddr_in *)addr)->sin_addr,
-                       ntohs(((struct sockaddr_in *) addr)->sin_port));
+               snprintf(buf, len, "%pI4, port=%u", &sin->sin_addr,
+                       ntohs(sin->sin_port));
                break;
 
        case AF_INET6:
                snprintf(buf, len, "%pI6, port=%u",
-                        &((struct sockaddr_in6 *)addr)->sin6_addr,
-                       ntohs(((struct sockaddr_in6 *) addr)->sin6_port));
+                        &sin6->sin6_addr,
+                       ntohs(sin6->sin6_port));
                break;
 
        default:
                snprintf(buf, len, "unknown address type: %d", addr->sa_family);
                break;
        }
+
        return buf;
 }
 #endif /* SUNRPC_SVC_XPRT_H */
index 11fc71d50c1e8aa0806eb7d9ce24cbfd291831eb..1758d9f5b5c3bc1edda4dd0628feceacdd1b10df 100644 (file)
@@ -235,6 +235,7 @@ static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *
  */
 int                    xprt_register_transport(struct xprt_class *type);
 int                    xprt_unregister_transport(struct xprt_class *type);
+int                    xprt_load_transport(const char *);
 void                   xprt_set_retrans_timeout_def(struct rpc_task *task);
 void                   xprt_set_retrans_timeout_rtt(struct rpc_task *task);
 void                   xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status);
@@ -259,6 +260,7 @@ void                        xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie);
 #define XPRT_BOUND             (4)
 #define XPRT_BINDING           (5)
 #define XPRT_CLOSING           (6)
+#define XPRT_CONNECTION_ABORT  (7)
 
 static inline void xprt_set_connected(struct rpc_xprt *xprt)
 {
index c7d9bb1832ba98ff88ea0fa19f7734b4f238103a..3e3a4364cbff4ef42d72e3341218296bdd9efe54 100644 (file)
@@ -1,9 +1,6 @@
 #ifndef _LINUX_SUSPEND_H
 #define _LINUX_SUSPEND_H
 
-#if defined(CONFIG_X86) || defined(CONFIG_FRV) || defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
-#include <asm/suspend.h>
-#endif
 #include <linux/swap.h>
 #include <linux/notifier.h>
 #include <linux/init.h>
index d30215578877e499e30cec085664c50619bc3056..62d81435347a7e2a7fa212fd9ae2b17e3e43224c 100644 (file)
@@ -212,7 +212,7 @@ static inline void lru_cache_add_active_file(struct page *page)
 
 /* linux/mm/vmscan.c */
 extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
-                                       gfp_t gfp_mask);
+                                       gfp_t gfp_mask, nodemask_t *mask);
 extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem,
                                                  gfp_t gfp_mask, bool noswap,
                                                  unsigned int swappiness);
@@ -382,6 +382,11 @@ static inline struct page *swapin_readahead(swp_entry_t swp, gfp_t gfp_mask,
        return NULL;
 }
 
+static inline int swap_writepage(struct page *p, struct writeback_control *wbc)
+{
+       return 0;
+}
+
 static inline struct page *lookup_swap_cache(swp_entry_t swp)
 {
        return NULL;
index dedd3c0cfe300c8fbaf841cd525d8991cd404c19..ac9ff54f7cb305943e5444f27be83460ef398206 100644 (file)
@@ -31,7 +31,7 @@ extern dma_addr_t swiotlb_phys_to_bus(struct device *hwdev,
                                      phys_addr_t address);
 extern phys_addr_t swiotlb_bus_to_phys(dma_addr_t address);
 
-extern int swiotlb_arch_range_needs_mapping(void *ptr, size_t size);
+extern int swiotlb_arch_range_needs_mapping(phys_addr_t paddr, size_t size);
 
 extern void
 *swiotlb_alloc_coherent(struct device *hwdev, size_t size,
@@ -41,20 +41,13 @@ extern void
 swiotlb_free_coherent(struct device *hwdev, size_t size,
                      void *vaddr, dma_addr_t dma_handle);
 
-extern dma_addr_t
-swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir);
-
-extern void
-swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr,
-                    size_t size, int dir);
-
-extern dma_addr_t
-swiotlb_map_single_attrs(struct device *hwdev, void *ptr, size_t size,
-                        int dir, struct dma_attrs *attrs);
-
-extern void
-swiotlb_unmap_single_attrs(struct device *hwdev, dma_addr_t dev_addr,
-                          size_t size, int dir, struct dma_attrs *attrs);
+extern dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
+                                  unsigned long offset, size_t size,
+                                  enum dma_data_direction dir,
+                                  struct dma_attrs *attrs);
+extern void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
+                              size_t size, enum dma_data_direction dir,
+                              struct dma_attrs *attrs);
 
 extern int
 swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nents,
@@ -66,36 +59,38 @@ swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents,
 
 extern int
 swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
-                    int dir, struct dma_attrs *attrs);
+                    enum dma_data_direction dir, struct dma_attrs *attrs);
 
 extern void
 swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
-                      int nelems, int dir, struct dma_attrs *attrs);
+                      int nelems, enum dma_data_direction dir,
+                      struct dma_attrs *attrs);
 
 extern void
 swiotlb_sync_single_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
-                           size_t size, int dir);
+                           size_t size, enum dma_data_direction dir);
 
 extern void
 swiotlb_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg,
-                       int nelems, int dir);
+                       int nelems, enum dma_data_direction dir);
 
 extern void
 swiotlb_sync_single_for_device(struct device *hwdev, dma_addr_t dev_addr,
-                              size_t size, int dir);
+                              size_t size, enum dma_data_direction dir);
 
 extern void
 swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
-                          int nelems, int dir);
+                          int nelems, enum dma_data_direction dir);
 
 extern void
 swiotlb_sync_single_range_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
-                                 unsigned long offset, size_t size, int dir);
+                                 unsigned long offset, size_t size,
+                                 enum dma_data_direction dir);
 
 extern void
 swiotlb_sync_single_range_for_device(struct device *hwdev, dma_addr_t dev_addr,
                                     unsigned long offset, size_t size,
-                                    int dir);
+                                    enum dma_data_direction dir);
 
 extern int
 swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr);
index 99b8bdb17b2b9235cd9b937be79bacae78668835..0ff2779c44d09f28e773cdb5f2014198e7be7c42 100644 (file)
 #define MGSL_MODE_MONOSYNC     3
 #define MGSL_MODE_BISYNC       4
 #define MGSL_MODE_RAW          6
+#define MGSL_MODE_BASE_CLOCK    7
 
 #define MGSL_BUS_TYPE_ISA      1
 #define MGSL_BUS_TYPE_EISA     2
index f9f900cfd066f1ad19ac979dba0c48f2384b95e2..b299a82a05e7abd369f6b30d9b7182238112b685 100644 (file)
@@ -461,6 +461,10 @@ asmlinkage long sys_pread64(unsigned int fd, char __user *buf,
                            size_t count, loff_t pos);
 asmlinkage long sys_pwrite64(unsigned int fd, const char __user *buf,
                             size_t count, loff_t pos);
+asmlinkage long sys_preadv(unsigned long fd, const struct iovec __user *vec,
+                          unsigned long vlen, u32 pos_high, u32 pos_low);
+asmlinkage long sys_pwritev(unsigned long fd, const struct iovec __user *vec,
+                           unsigned long vlen, u32 pos_high, u32 pos_low);
 asmlinkage long sys_getcwd(char __user *buf, unsigned long size);
 asmlinkage long sys_mkdir(const char __user *pathname, int mode);
 asmlinkage long sys_chdir(const char __user *filename);
index e2d662e3416e38026bbc7385f744481de1b7d0a0..6cdb6f3331f11b6a80d7cd2c85a45706937b16d3 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/ktime.h>
 #include <linux/stddef.h>
 #include <linux/debugobjects.h>
+#include <linux/stringify.h>
 
 struct tvec_base;
 
@@ -21,52 +22,126 @@ struct timer_list {
        char start_comm[16];
        int start_pid;
 #endif
+#ifdef CONFIG_LOCKDEP
+       struct lockdep_map lockdep_map;
+#endif
 };
 
 extern struct tvec_base boot_tvec_bases;
 
+#ifdef CONFIG_LOCKDEP
+/*
+ * NB: because we have to copy the lockdep_map, setting the lockdep_map key
+ * (second argument) here is required, otherwise it could be initialised to
+ * the copy of the lockdep_map later! We use the pointer to and the string
+ * "<file>:<line>" as the key resp. the name of the lockdep_map.
+ */
+#define __TIMER_LOCKDEP_MAP_INITIALIZER(_kn)                           \
+       .lockdep_map = STATIC_LOCKDEP_MAP_INIT(_kn, &_kn),
+#else
+#define __TIMER_LOCKDEP_MAP_INITIALIZER(_kn)
+#endif
+
 #define TIMER_INITIALIZER(_function, _expires, _data) {                \
                .entry = { .prev = TIMER_ENTRY_STATIC },        \
                .function = (_function),                        \
                .expires = (_expires),                          \
                .data = (_data),                                \
                .base = &boot_tvec_bases,                       \
+               __TIMER_LOCKDEP_MAP_INITIALIZER(                \
+                       __FILE__ ":" __stringify(__LINE__))     \
        }
 
 #define DEFINE_TIMER(_name, _function, _expires, _data)                \
        struct timer_list _name =                               \
                TIMER_INITIALIZER(_function, _expires, _data)
 
-void init_timer(struct timer_list *timer);
-void init_timer_deferrable(struct timer_list *timer);
+void init_timer_key(struct timer_list *timer,
+                   const char *name,
+                   struct lock_class_key *key);
+void init_timer_deferrable_key(struct timer_list *timer,
+                              const char *name,
+                              struct lock_class_key *key);
+
+#ifdef CONFIG_LOCKDEP
+#define init_timer(timer)                                              \
+       do {                                                            \
+               static struct lock_class_key __key;                     \
+               init_timer_key((timer), #timer, &__key);                \
+       } while (0)
+
+#define init_timer_deferrable(timer)                                   \
+       do {                                                            \
+               static struct lock_class_key __key;                     \
+               init_timer_deferrable_key((timer), #timer, &__key);     \
+       } while (0)
+
+#define init_timer_on_stack(timer)                                     \
+       do {                                                            \
+               static struct lock_class_key __key;                     \
+               init_timer_on_stack_key((timer), #timer, &__key);       \
+       } while (0)
+
+#define setup_timer(timer, fn, data)                                   \
+       do {                                                            \
+               static struct lock_class_key __key;                     \
+               setup_timer_key((timer), #timer, &__key, (fn), (data));\
+       } while (0)
+
+#define setup_timer_on_stack(timer, fn, data)                          \
+       do {                                                            \
+               static struct lock_class_key __key;                     \
+               setup_timer_on_stack_key((timer), #timer, &__key,       \
+                                        (fn), (data));                 \
+       } while (0)
+#else
+#define init_timer(timer)\
+       init_timer_key((timer), NULL, NULL)
+#define init_timer_deferrable(timer)\
+       init_timer_deferrable_key((timer), NULL, NULL)
+#define init_timer_on_stack(timer)\
+       init_timer_on_stack_key((timer), NULL, NULL)
+#define setup_timer(timer, fn, data)\
+       setup_timer_key((timer), NULL, NULL, (fn), (data))
+#define setup_timer_on_stack(timer, fn, data)\
+       setup_timer_on_stack_key((timer), NULL, NULL, (fn), (data))
+#endif
 
 #ifdef CONFIG_DEBUG_OBJECTS_TIMERS
-extern void init_timer_on_stack(struct timer_list *timer);
+extern void init_timer_on_stack_key(struct timer_list *timer,
+                                   const char *name,
+                                   struct lock_class_key *key);
 extern void destroy_timer_on_stack(struct timer_list *timer);
 #else
 static inline void destroy_timer_on_stack(struct timer_list *timer) { }
-static inline void init_timer_on_stack(struct timer_list *timer)
+static inline void init_timer_on_stack_key(struct timer_list *timer,
+                                          const char *name,
+                                          struct lock_class_key *key)
 {
-       init_timer(timer);
+       init_timer_key(timer, name, key);
 }
 #endif
 
-static inline void setup_timer(struct timer_list * timer,
+static inline void setup_timer_key(struct timer_list * timer,
+                               const char *name,
+                               struct lock_class_key *key,
                                void (*function)(unsigned long),
                                unsigned long data)
 {
        timer->function = function;
        timer->data = data;
-       init_timer(timer);
+       init_timer_key(timer, name, key);
 }
 
-static inline void setup_timer_on_stack(struct timer_list *timer,
+static inline void setup_timer_on_stack_key(struct timer_list *timer,
+                                       const char *name,
+                                       struct lock_class_key *key,
                                        void (*function)(unsigned long),
                                        unsigned long data)
 {
        timer->function = function;
        timer->data = data;
-       init_timer_on_stack(timer);
+       init_timer_on_stack_key(timer, name, key);
 }
 
 /**
index 6186a789d6c7a2f6d5c3ce7a3651a1db184b67ed..c7aa154f4bfcf97081048f4e8ab59ef6fa8147ed 100644 (file)
@@ -388,17 +388,14 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info,
  * tracehook_consider_ignored_signal - suppress short-circuit of ignored signal
  * @task:              task receiving the signal
  * @sig:               signal number being sent
- * @handler:           %SIG_IGN or %SIG_DFL
  *
  * Return zero iff tracing doesn't care to examine this ignored signal,
  * so it can short-circuit normal delivery and never even get queued.
- * Either @handler is %SIG_DFL and @sig's default is ignore, or it's %SIG_IGN.
  *
  * Called with @task->sighand->siglock held.
  */
 static inline int tracehook_consider_ignored_signal(struct task_struct *task,
-                                                   int sig,
-                                                   void __user *handler)
+                                                   int sig)
 {
        return (task_ptrace(task) & PT_PTRACED) != 0;
 }
@@ -407,19 +404,17 @@ static inline int tracehook_consider_ignored_signal(struct task_struct *task,
  * tracehook_consider_fatal_signal - suppress special handling of fatal signal
  * @task:              task receiving the signal
  * @sig:               signal number being sent
- * @handler:           %SIG_DFL or %SIG_IGN
  *
  * Return nonzero to prevent special handling of this termination signal.
- * Normally @handler is %SIG_DFL.  It can be %SIG_IGN if @sig is ignored,
- * in which case force_sig() is about to reset it to %SIG_DFL.
+ * Normally handler for signal is %SIG_DFL.  It can be %SIG_IGN if @sig is
+ * ignored, in which case force_sig() is about to reset it to %SIG_DFL.
  * When this returns zero, this signal might cause a quick termination
  * that does not give the debugger a chance to intercept the signal.
  *
  * Called with or without @task->sighand->siglock held.
  */
 static inline int tracehook_consider_fatal_signal(struct task_struct *task,
-                                                 int sig,
-                                                 void __user *handler)
+                                                 int sig)
 {
        return (task_ptrace(task) & PT_PTRACED) != 0;
 }
@@ -507,7 +502,7 @@ static inline int tracehook_notify_jctl(int notify, int why)
 static inline int tracehook_notify_death(struct task_struct *task,
                                         void **death_cookie, int group_dead)
 {
-       if (task->exit_signal == -1)
+       if (task_detached(task))
                return task->ptrace ? SIGCHLD : DEATH_REAP;
 
        /*
index 08e088334dba25288b8fba8423dfcb58774c833a..8615d661ab60c042fe8e8b5df420a4fde66a03d3 100644 (file)
@@ -252,8 +252,6 @@ struct tty_operations {
        void (*set_ldisc)(struct tty_struct *tty);
        void (*wait_until_sent)(struct tty_struct *tty, int timeout);
        void (*send_xchar)(struct tty_struct *tty, char ch);
-       int (*read_proc)(char *page, char **start, off_t off,
-                         int count, int *eof, void *data);
        int (*tiocmget)(struct tty_struct *tty, struct file *file);
        int (*tiocmset)(struct tty_struct *tty, struct file *file,
                        unsigned int set, unsigned int clear);
@@ -264,6 +262,7 @@ struct tty_operations {
        int (*poll_get_char)(struct tty_driver *driver, int line);
        void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
 #endif
+       const struct file_operations *proc_fops;
 };
 
 struct tty_driver {
diff --git a/include/linux/video_decoder.h b/include/linux/video_decoder.h
deleted file mode 100644 (file)
index e26c0c8..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef _LINUX_VIDEO_DECODER_H
-#define _LINUX_VIDEO_DECODER_H
-
-#include <linux/types.h>
-
-#define HAVE_VIDEO_DECODER 1
-
-struct video_decoder_capability { /* this name is too long */
-       __u32   flags;
-#define        VIDEO_DECODER_PAL       1       /* can decode PAL signal */
-#define        VIDEO_DECODER_NTSC      2       /* can decode NTSC */
-#define        VIDEO_DECODER_SECAM     4       /* can decode SECAM */
-#define        VIDEO_DECODER_AUTO      8       /* can autosense norm */
-#define        VIDEO_DECODER_CCIR      16      /* CCIR-601 pixel rate (720 pixels per line) instead of square pixel rate */
-       int     inputs;                 /* number of inputs */
-       int     outputs;                /* number of outputs */
-};
-
-/*
-DECODER_GET_STATUS returns the following flags.  The only one you need is
-DECODER_STATUS_GOOD, the others are just nice things to know.
-*/
-#define        DECODER_STATUS_GOOD     1       /* receiving acceptable input */
-#define        DECODER_STATUS_COLOR    2       /* receiving color information */
-#define        DECODER_STATUS_PAL      4       /* auto detected */
-#define        DECODER_STATUS_NTSC     8       /* auto detected */
-#define        DECODER_STATUS_SECAM    16      /* auto detected */
-
-struct video_decoder_init {
-       unsigned char len;
-       const unsigned char *data;
-};
-
-#define        DECODER_GET_CAPABILITIES _IOR('d', 1, struct video_decoder_capability)
-#define        DECODER_GET_STATUS      _IOR('d', 2, int)
-#define        DECODER_SET_NORM        _IOW('d', 3, int)
-#define        DECODER_SET_INPUT       _IOW('d', 4, int)       /* 0 <= input < #inputs */
-#define        DECODER_SET_OUTPUT      _IOW('d', 5, int)       /* 0 <= output < #outputs */
-#define        DECODER_ENABLE_OUTPUT   _IOW('d', 6, int)       /* boolean output enable control */
-#define        DECODER_SET_PICTURE     _IOW('d', 7, struct video_picture)
-#define        DECODER_SET_GPIO        _IOW('d', 8, int)       /* switch general purpose pin */
-#define        DECODER_INIT            _IOW('d', 9, struct video_decoder_init) /* init internal registers at once */
-#define        DECODER_SET_VBI_BYPASS  _IOW('d', 10, int)      /* switch vbi bypass */
-
-#define        DECODER_DUMP            _IO('d', 192)           /* debug hook */
-
-
-#endif
diff --git a/include/linux/video_encoder.h b/include/linux/video_encoder.h
deleted file mode 100644 (file)
index b7b6423..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef _LINUX_VIDEO_ENCODER_H
-#define _LINUX_VIDEO_ENCODER_H
-
-#include <linux/types.h>
-
-struct video_encoder_capability { /* this name is too long */
-       __u32   flags;
-#define        VIDEO_ENCODER_PAL       1       /* can encode PAL signal */
-#define        VIDEO_ENCODER_NTSC      2       /* can encode NTSC */
-#define        VIDEO_ENCODER_SECAM     4       /* can encode SECAM */
-#define        VIDEO_ENCODER_CCIR      16      /* CCIR-601 pixel rate (720 pixels per line) instead of square pixel rate */
-       int     inputs;                 /* number of inputs */
-       int     outputs;                /* number of outputs */
-};
-
-#define        ENCODER_GET_CAPABILITIES _IOR('e', 1, struct video_encoder_capability)
-#define        ENCODER_SET_NORM        _IOW('e', 2, int)
-#define        ENCODER_SET_INPUT       _IOW('e', 3, int)       /* 0 <= input < #inputs */
-#define        ENCODER_SET_OUTPUT      _IOW('e', 4, int)       /* 0 <= output < #outputs */
-#define        ENCODER_ENABLE_OUTPUT   _IOW('e', 5, int)       /* boolean output enable control */
-
-
-#endif
index 837f392fbe9761bad9cadaf26f02ffa2d0a8bda0..b19eab140977258ae145b48510307dc9401ef713 100644 (file)
 #include <linux/ioctl.h>
 #include <linux/videodev2.h>
 
+#if defined(__MIN_V4L1) && defined (__KERNEL__)
+
+/*
+ * Used by those V4L2 core functions that need a minimum V4L1 support,
+ * in order to allow V4L1 Compatibilty code compilation.
+ */
+
+struct video_mbuf
+{
+       int     size;           /* Total memory to map */
+       int     frames;         /* Frames */
+       int     offsets[VIDEO_MAX_FRAME];
+};
+
+#define VIDIOCGMBUF            _IOR('v',20, struct video_mbuf)         /* Memory map buffer info */
+
+#else
 #if defined(CONFIG_VIDEO_V4L1_COMPAT) || !defined (__KERNEL__)
 
 #define VID_TYPE_CAPTURE       1       /* Can capture */
@@ -312,6 +329,7 @@ struct video_code
 #define VID_PLAY_END_MARK              14
 
 #endif /* CONFIG_VIDEO_V4L1_COMPAT */
+#endif /* __MIN_V4L1 */
 
 #endif /* __LINUX_VIDEODEV_H */
 
index 5571dbe1c0addb74d48809925f2b09ff7bd144f3..139d234923cdc5003fa6e53bfa95e67bb8bb673f 100644 (file)
@@ -344,6 +344,8 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_SPCA508  v4l2_fourcc('S', '5', '0', '8') /* YUVY per line */
 #define V4L2_PIX_FMT_SPCA561  v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */
 #define V4L2_PIX_FMT_PAC207   v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */
+#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     */
 
@@ -829,6 +831,7 @@ struct v4l2_querymenu {
 #define V4L2_CTRL_FLAG_UPDATE          0x0008
 #define V4L2_CTRL_FLAG_INACTIVE        0x0010
 #define V4L2_CTRL_FLAG_SLIDER          0x0020
+#define V4L2_CTRL_FLAG_WRITE_ONLY      0x0040
 
 /*  Query flag, to be ORed with the control ID */
 #define V4L2_CTRL_FLAG_NEXT_CTRL       0x80000000
@@ -879,8 +882,15 @@ enum v4l2_power_line_frequency {
 #define V4L2_CID_BACKLIGHT_COMPENSATION        (V4L2_CID_BASE+28)
 #define V4L2_CID_CHROMA_AGC                     (V4L2_CID_BASE+29)
 #define V4L2_CID_COLOR_KILLER                   (V4L2_CID_BASE+30)
+#define V4L2_CID_COLORFX                       (V4L2_CID_BASE+31)
+enum v4l2_colorfx {
+       V4L2_COLORFX_NONE       = 0,
+       V4L2_COLORFX_BW         = 1,
+       V4L2_COLORFX_SEPIA      = 2,
+};
+
 /* last CID + 1 */
-#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+31)
+#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+32)
 
 /*  MPEG-class control IDs defined by V4L2 */
 #define V4L2_CID_MPEG_BASE                     (V4L2_CTRL_CLASS_MPEG | 0x900)
@@ -1338,6 +1348,53 @@ struct v4l2_sliced_vbi_data {
        __u8    data[48];
 };
 
+/*
+ * Sliced VBI data inserted into MPEG Streams
+ */
+
+/*
+ * V4L2_MPEG_STREAM_VBI_FMT_IVTV:
+ *
+ * Structure of payload contained in an MPEG 2 Private Stream 1 PES Packet in an
+ * MPEG-2 Program Pack that contains V4L2_MPEG_STREAM_VBI_FMT_IVTV Sliced VBI
+ * data
+ *
+ * Note, the MPEG-2 Program Pack and Private Stream 1 PES packet header
+ * definitions are not included here.  See the MPEG-2 specifications for details
+ * on these headers.
+ */
+
+/* Line type IDs */
+#define V4L2_MPEG_VBI_IVTV_TELETEXT_B     (1)
+#define V4L2_MPEG_VBI_IVTV_CAPTION_525    (4)
+#define V4L2_MPEG_VBI_IVTV_WSS_625        (5)
+#define V4L2_MPEG_VBI_IVTV_VPS            (7)
+
+struct v4l2_mpeg_vbi_itv0_line {
+       __u8 id;        /* One of V4L2_MPEG_VBI_IVTV_* above */
+       __u8 data[42];  /* Sliced VBI data for the line */
+} __attribute__ ((packed));
+
+struct v4l2_mpeg_vbi_itv0 {
+       __le32 linemask[2]; /* Bitmasks of VBI service lines present */
+       struct v4l2_mpeg_vbi_itv0_line line[35];
+} __attribute__ ((packed));
+
+struct v4l2_mpeg_vbi_ITV0 {
+       struct v4l2_mpeg_vbi_itv0_line line[36];
+} __attribute__ ((packed));
+
+#define V4L2_MPEG_VBI_IVTV_MAGIC0      "itv0"
+#define V4L2_MPEG_VBI_IVTV_MAGIC1      "ITV0"
+
+struct v4l2_mpeg_vbi_fmt_ivtv {
+       __u8 magic[4];
+       union {
+               struct v4l2_mpeg_vbi_itv0 itv0;
+               struct v4l2_mpeg_vbi_ITV0 ITV0;
+       };
+} __attribute__ ((packed));
+
 /*
  *     A G G R E G A T E   S T R U C T U R E S
  */
@@ -1403,14 +1460,6 @@ struct v4l2_dbg_chip_ident {
        __u32 revision;    /* chip revision, chip specific */
 } __attribute__ ((packed));
 
-/* VIDIOC_G_CHIP_IDENT_OLD: Deprecated, do not use */
-struct v4l2_chip_ident_old {
-       __u32 match_type;  /* Match type */
-       __u32 match_chip;  /* Match this chip, meaning determined by match_type */
-       __u32 ident;       /* chip identifier as specified in <media/v4l2-chip-ident.h> */
-       __u32 revision;    /* chip revision, chip specific */
-};
-
 /*
  *     I O C T L   C O D E S   F O R   V I D E O   D E V I C E S
  *
@@ -1488,8 +1537,6 @@ struct v4l2_chip_ident_old {
 /* Experimental, meant for debugging, testing and internal use.
    Never use this ioctl in applications! */
 #define VIDIOC_DBG_G_CHIP_IDENT _IOWR('V', 81, struct v4l2_dbg_chip_ident)
-/* This is deprecated and will go away in 2.6.30 */
-#define VIDIOC_G_CHIP_IDENT_OLD _IOWR('V', 81, struct v4l2_chip_ident_old)
 #endif
 
 #define VIDIOC_S_HW_FREQ_SEEK   _IOW('V', 82, struct v4l2_hw_freq_seek)
index a210ede73b568d25bc672b44c8bd17986d326b7e..5d631c17eaee339f4cbcc826622887278a24546f 100644 (file)
@@ -135,8 +135,11 @@ static inline void __remove_wait_queue(wait_queue_head_t *head,
 void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
                        int nr_exclusive, int sync, void *key);
 void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr, void *key);
-extern void __wake_up_locked(wait_queue_head_t *q, unsigned int mode);
-extern void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr);
+void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key);
+void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode, int nr,
+                       void *key);
+void __wake_up_locked(wait_queue_head_t *q, unsigned int mode);
+void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr);
 void __wake_up_bit(wait_queue_head_t *, void *, int);
 int __wait_on_bit(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned);
 int __wait_on_bit_lock(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned);
@@ -155,21 +158,17 @@ wait_queue_head_t *bit_waitqueue(void *, int);
 #define wake_up_interruptible_all(x)   __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL)
 #define wake_up_interruptible_sync(x)  __wake_up_sync((x), TASK_INTERRUPTIBLE, 1)
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
 /*
- * macro to avoid include hell
+ * Wakeup macros to be used to report events to the targets.
  */
-#define wake_up_nested(x, s)                                           \
-do {                                                                   \
-       unsigned long flags;                                            \
-                                                                       \
-       spin_lock_irqsave_nested(&(x)->lock, flags, (s));               \
-       wake_up_locked(x);                                              \
-       spin_unlock_irqrestore(&(x)->lock, flags);                      \
-} while (0)
-#else
-#define wake_up_nested(x, s)           wake_up(x)
-#endif
+#define wake_up_poll(x, m)                             \
+       __wake_up(x, TASK_NORMAL, 1, (void *) (m))
+#define wake_up_locked_poll(x, m)                              \
+       __wake_up_locked_key((x), TASK_NORMAL, (void *) (m))
+#define wake_up_interruptible_poll(x, m)                       \
+       __wake_up(x, TASK_INTERRUPTIBLE, 1, (void *) (m))
+#define wake_up_interruptible_sync_poll(x, m)                          \
+       __wake_up_sync_key((x), TASK_INTERRUPTIBLE, 1, (void *) (m))
 
 #define __wait_event(wq, condition)                                    \
 do {                                                                   \
index 3cd51e579ab1c2cddd3960e1154b9c493794a85b..13e1adf55c4c7c0ba30d81bbc54abe6d56b93b5e 100644 (file)
@@ -41,6 +41,11 @@ struct delayed_work {
        struct timer_list timer;
 };
 
+static inline struct delayed_work *to_delayed_work(struct work_struct *work)
+{
+       return container_of(work, struct delayed_work, work);
+}
+
 struct execute_work {
        struct work_struct work;
 };
index 7300ecdc480c93b3e2010fecb41b9ceefb680799..93445477f86a7cdfe8352e15e21fbad77d9f7f0a 100644 (file)
@@ -109,8 +109,8 @@ extern int dirty_background_ratio;
 extern unsigned long dirty_background_bytes;
 extern int vm_dirty_ratio;
 extern unsigned long vm_dirty_bytes;
-extern int dirty_writeback_interval;
-extern int dirty_expire_interval;
+extern unsigned int dirty_writeback_interval;
+extern unsigned int dirty_expire_interval;
 extern int vm_highmem_is_dirtyable;
 extern int block_dump;
 extern int laptop_mode;
diff --git a/include/media/bt819.h b/include/media/bt819.h
new file mode 100644 (file)
index 0000000..38f666b
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+    bt819.h - bt819 notifications
+
+    Copyright (C) 2009 Hans Verkuil (hverkuil@xs4all.nl)
+
+    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 _BT819_H_
+#define _BT819_H_
+
+#include <linux/ioctl.h>
+
+/* v4l2_device notifications. */
+
+/* Needed to reset the FIFO buffer when changing the input
+   or the video standard. */
+#define BT819_FIFO_RESET_LOW   _IO('b', 0)
+#define BT819_FIFO_RESET_HIGH  _IO('b', 1)
+
+#endif
index 9ec4d5889ef5a9e1981c5a903d1db8a61e30da35..9ebe8558b9b69f0cd5d5e3f69d426e803ce4103f 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    cx23415/6 header containing common defines.
+    cx23415/6/8 header containing common defines.
 
     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
@@ -28,6 +28,7 @@ enum cx2341x_port {
 enum cx2341x_cap {
        CX2341X_CAP_HAS_SLICED_VBI = 1 << 0,
        CX2341X_CAP_HAS_TS         = 1 << 1,
+       CX2341X_CAP_HAS_AC3        = 1 << 2,
 };
 
 struct cx2341x_mpeg_params {
@@ -47,11 +48,12 @@ struct cx2341x_mpeg_params {
        enum v4l2_mpeg_audio_sampling_freq audio_sampling_freq;
        enum v4l2_mpeg_audio_encoding audio_encoding;
        enum v4l2_mpeg_audio_l2_bitrate audio_l2_bitrate;
+       enum v4l2_mpeg_audio_ac3_bitrate audio_ac3_bitrate;
        enum v4l2_mpeg_audio_mode audio_mode;
        enum v4l2_mpeg_audio_mode_extension audio_mode_extension;
        enum v4l2_mpeg_audio_emphasis audio_emphasis;
        enum v4l2_mpeg_audio_crc audio_crc;
-       u16 audio_properties;
+       u32 audio_properties;
        u16 audio_mute;
 
        /* video */
index db431d513f2f01ce27cb9d150ed85f62f61d7195..2c3fbaa33f744b397521ea35a181d85b8f2d4132 100644 (file)
 #ifndef _CX25840_H_
 #define _CX25840_H_
 
+/* Note that the cx25840 driver requires that the bridge driver calls the
+   v4l2_subdev's init operation in order to load the driver's firmware.
+   Without this the audio standard detection will fail and you will
+   only get mono.
+
+   Since loading the firmware is often problematic when the driver is
+   compiled into the kernel I recommend postponing calling this function
+   until the first open of the video device. Another reason for
+   postponing it is that loading this firmware takes a long time (seconds)
+   due to the slow i2c bus speed. So it will speed up the boot process if
+   you can avoid loading the fw as long as the video device isn't used. */
+
 enum cx25840_video_input {
        /* Composite video inputs In1-In8 */
        CX25840_COMPOSITE1 = 1,
index 5bf2ea00678c0c9c245c8c1826b71f516025af7e..7b5b91f60425d687508856ee50444106b2e0cdff 100644 (file)
@@ -111,6 +111,7 @@ 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];
@@ -159,6 +160,8 @@ 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];
 #endif
 
 /*
index 00fa57eb9fde928fc04d440ae39cdde2205266ee..07963d7054008be6490f79ee91a4f9740900e5d6 100644 (file)
@@ -14,8 +14,7 @@ struct IR_i2c {
        /* Used to avoid fast repeating */
        unsigned char          old;
 
-       struct work_struct     work;
-       struct timer_list      timer;
+       struct delayed_work    work;
        char                   phys[32];
        int                    (*get_key)(struct IR_i2c*, u32*, u32*);
 };
index e391d55edb951df8fe9d037c569a2dce324298d6..57db48dd85b8ffd1dfe5d4ee2b8cb56eda765f85 100644 (file)
 
 #include <media/soc_camera.h>
 
+/* for flags */
+#define OV772X_FLAG_VFLIP     0x00000001 /* Vertical flip image */
+#define OV772X_FLAG_HFLIP     0x00000002 /* Horizontal flip image */
+
 struct ov772x_camera_info {
        unsigned long          buswidth;
+       unsigned long          flags;
        struct soc_camera_link link;
 };
 
index c5a6e22a4b37d626d90370b3becb212105534478..fff4235adae54c9901502ae973ce2c2aed585880 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/stringify.h>
 #include <linux/mutex.h>
 #include <linux/scatterlist.h>
+#include <media/v4l2-device.h>
 
 #include <linux/vmalloc.h>     /* for vmalloc() */
 #include <linux/mm.h>          /* for vmalloc_to_page() */
@@ -110,6 +111,8 @@ struct saa7146_dev
 
        struct list_head                item;
 
+       struct v4l2_device              v4l2_dev;
+
        /* different device locks */
        spinlock_t                      slock;
        struct mutex                    lock;
@@ -145,6 +148,11 @@ struct saa7146_dev
        struct saa7146_dma              d_rps1;
 };
 
+static inline struct saa7146_dev *to_saa7146_dev(struct v4l2_device *v4l2_dev)
+{
+       return container_of(v4l2_dev, struct saa7146_dev, v4l2_dev);
+}
+
 /* from saa7146_i2c.c */
 int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate);
 
index c8d0b23fde295542d02c86421cdfc6e305383bd2..eed5fccc83f3c242e2ff95766ab2bbbd0fd669b4 100644 (file)
@@ -150,16 +150,6 @@ struct saa7146_vv
        unsigned int resources; /* resource management for device */
 };
 
-#define SAA7146_EXCLUSIVE      0x1
-#define SAA7146_BEFORE         0x2
-#define SAA7146_AFTER          0x4
-
-struct saa7146_extension_ioctls
-{
-       unsigned int    cmd;
-       int             flags;
-};
-
 /* flags */
 #define SAA7146_USE_PORT_B_FOR_VBI     0x2     /* use input port b for vbi hardware bug workaround */
 
@@ -176,8 +166,10 @@ struct saa7146_ext_vv
        int num_stds;
        int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *);
 
-       struct saa7146_extension_ioctls *ioctls;
-       long (*ioctl)(struct saa7146_fh *, unsigned int cmd, void *arg);
+       /* the extension can override this */
+       struct v4l2_ioctl_ops ops;
+       /* pointer to the saa7146 core ops */
+       const struct v4l2_ioctl_ops *core_ops;
 
        struct v4l2_file_operations vbi_fops;
 };
@@ -213,6 +205,7 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *saa, int source, int sy
 void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data);
 
 /* from saa7146_video.c */
+extern const struct v4l2_ioctl_ops saa7146_video_ioctl_ops;
 extern struct saa7146_use_ops saa7146_video_uops;
 int saa7146_start_preview(struct saa7146_fh *fh);
 int saa7146_stop_preview(struct saa7146_fh *fh);
index b5dbefea3740c65b7ae87e8f7964e6c8764e3c83..0f3524cff4355df94cba4c4e13eeba361ed3a706 100644 (file)
@@ -1,10 +1,11 @@
 #ifndef __ASM_SH_MOBILE_CEU_H__
 #define __ASM_SH_MOBILE_CEU_H__
 
-#include <media/soc_camera.h>
+#define SH_CEU_FLAG_USE_8BIT_BUS       (1 << 0) /* use  8bit bus width */
+#define SH_CEU_FLAG_USE_16BIT_BUS      (1 << 1) /* use 16bit bus width */
 
 struct sh_mobile_ceu_info {
-       unsigned long flags; /* SOCAM_... */
+       unsigned long flags;
 };
 
 #endif /* __ASM_SH_MOBILE_CEU_H__ */
index 7440d9250665489f2699fc1557bc1a7ae655b337..37013688af44b64c8107e94fa7e416411e69dcfa 100644 (file)
@@ -45,6 +45,7 @@ struct soc_camera_device {
        int num_formats;
        struct soc_camera_format_xlate *user_formats;
        int num_user_formats;
+       enum v4l2_field field;          /* Preserve field over close() */
        struct module *owner;
        void *host_priv;                /* Per-device host private data */
        /* soc_camera.c private count. Only accessed with .video_lock held */
@@ -74,7 +75,8 @@ struct soc_camera_host_ops {
        int (*resume)(struct soc_camera_device *);
        int (*get_formats)(struct soc_camera_device *, int,
                           struct soc_camera_format_xlate *);
-       int (*set_fmt)(struct soc_camera_device *, __u32, struct v4l2_rect *);
+       int (*set_crop)(struct soc_camera_device *, struct v4l2_rect *);
+       int (*set_fmt)(struct soc_camera_device *, struct v4l2_format *);
        int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *);
        void (*init_videobuf)(struct videobuf_queue *,
                              struct soc_camera_device *);
@@ -93,13 +95,18 @@ struct soc_camera_host_ops {
 struct soc_camera_link {
        /* Camera bus id, used to match a camera and a bus */
        int bus_id;
-       /* GPIO number to switch between 8 and 10 bit modes */
-       unsigned int gpio;
        /* Per camera SOCAM_SENSOR_* bus flags */
        unsigned long flags;
        /* Optional callbacks to power on or off and reset the sensor */
        int (*power)(struct device *, int);
        int (*reset)(struct device *);
+       /*
+        * some platforms may support different data widths than the sensors
+        * native ones due to different data line routing. Let the board code
+        * overwrite the width flags.
+        */
+       int (*set_bus_param)(struct soc_camera_link *, unsigned long flags);
+       unsigned long (*query_bus_param)(struct soc_camera_link *);
 };
 
 static inline struct soc_camera_device *to_soc_camera_dev(struct device *dev)
@@ -159,7 +166,8 @@ struct soc_camera_ops {
        int (*release)(struct soc_camera_device *);
        int (*start_capture)(struct soc_camera_device *);
        int (*stop_capture)(struct soc_camera_device *);
-       int (*set_fmt)(struct soc_camera_device *, __u32, struct v4l2_rect *);
+       int (*set_crop)(struct soc_camera_device *, struct v4l2_rect *);
+       int (*set_fmt)(struct soc_camera_device *, struct v4l2_format *);
        int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *);
        unsigned long (*query_bus_param)(struct soc_camera_device *);
        int (*set_bus_param)(struct soc_camera_device *, unsigned long);
@@ -239,15 +247,19 @@ static inline struct v4l2_queryctrl const *soc_camera_find_qctrl(
 static inline unsigned long soc_camera_bus_param_compatible(
                        unsigned long camera_flags, unsigned long bus_flags)
 {
-       unsigned long common_flags, hsync, vsync, pclk;
+       unsigned long common_flags, hsync, vsync, pclk, data, buswidth, mode;
 
        common_flags = camera_flags & bus_flags;
 
        hsync = common_flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW);
        vsync = common_flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW);
        pclk = common_flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING);
+       data = common_flags & (SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_LOW);
+       mode = common_flags & (SOCAM_MASTER | SOCAM_SLAVE);
+       buswidth = common_flags & SOCAM_DATAWIDTH_MASK;
 
-       return (!hsync || !vsync || !pclk) ? 0 : common_flags;
+       return (!hsync || !vsync || !pclk || !data || !mode || !buswidth) ? 0 :
+               common_flags;
 }
 
 extern unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl,
index 9aaf652b20ef7a3ff638e171906f60231de68161..1be461a2907768d29dbe060030c85dedfc4766b7 100644 (file)
@@ -37,10 +37,8 @@ enum {
        /* module saa7110: just ident 100 */
        V4L2_IDENT_SAA7110 = 100,
 
-       /* module saa7111: just ident 101 */
+       /* module saa7115: reserved range 101-149 */
        V4L2_IDENT_SAA7111 = 101,
-
-       /* module saa7115: reserved range 102-149 */
        V4L2_IDENT_SAA7113 = 103,
        V4L2_IDENT_SAA7114 = 104,
        V4L2_IDENT_SAA7115 = 105,
@@ -63,44 +61,96 @@ enum {
        V4L2_IDENT_OV7720 = 251,
        V4L2_IDENT_OV7725 = 252,
 
-       /* Conexant MPEG encoder/decoders: reserved range 410-420 */
+       /* module saa7146: reserved range 300-309 */
+       V4L2_IDENT_SAA7146 = 300,
+
+       /* Conexant MPEG encoder/decoders: reserved range 400-420 */
+       V4L2_IDENT_CX23418_843 = 403, /* Integrated A/V Decoder on the '418 */
        V4L2_IDENT_CX23415 = 415,
        V4L2_IDENT_CX23416 = 416,
        V4L2_IDENT_CX23418 = 418,
 
+       /* module au0828 */
+       V4L2_IDENT_AU0828 = 828,
+
+       /* module indycam: just ident 2000 */
+       V4L2_IDENT_INDYCAM = 2000,
+
+       /* module bt819: reserved range 810-819 */
+       V4L2_IDENT_BT815A = 815,
+       V4L2_IDENT_BT817A = 817,
+       V4L2_IDENT_BT819A = 819,
+
+       /* module bt856: just ident 856 */
+       V4L2_IDENT_BT856 = 856,
+
+       /* module bt866: just ident 866 */
+       V4L2_IDENT_BT866 = 866,
+
+       /* module ks0127: reserved range 1120-1129 */
+       V4L2_IDENT_KS0122S = 1122,
+       V4L2_IDENT_KS0127  = 1127,
+       V4L2_IDENT_KS0127B = 1128,
+
        /* module vp27smpx: just ident 2700 */
        V4L2_IDENT_VP27SMPX = 2700,
 
+       /* module vpx3220: reserved range: 3210-3229 */
+       V4L2_IDENT_VPX3214C = 3214,
+       V4L2_IDENT_VPX3216B = 3216,
+       V4L2_IDENT_VPX3220A = 3220,
+
        /* module tvp5150 */
        V4L2_IDENT_TVP5150 = 5150,
 
+       /* module saa5246a: just ident 5246 */
+       V4L2_IDENT_SAA5246A = 5246,
+
+       /* module saa5249: just ident 5249 */
+       V4L2_IDENT_SAA5249 = 5249,
+
        /* module cs5345: just ident 5345 */
        V4L2_IDENT_CS5345 = 5345,
 
+       /* module tea6415c: just ident 6415 */
+       V4L2_IDENT_TEA6415C = 6415,
+
+       /* module tea6420: just ident 6420 */
+       V4L2_IDENT_TEA6420 = 6420,
+
+       /* module saa6588: just ident 6588 */
+       V4L2_IDENT_SAA6588 = 6588,
+
        /* module saa6752hs: reserved range 6750-6759 */
        V4L2_IDENT_SAA6752HS = 6752,
        V4L2_IDENT_SAA6752HS_AC3 = 6753,
 
+       /* module adv7170: just ident 7170 */
+       V4L2_IDENT_ADV7170 = 7170,
+
+       /* module adv7175: just ident 7175 */
+       V4L2_IDENT_ADV7175 = 7175,
+
+       /* module saa7185: just ident 7185 */
+       V4L2_IDENT_SAA7185 = 7185,
+
+       /* module saa7191: just ident 7191 */
+       V4L2_IDENT_SAA7191 = 7191,
+
        /* module wm8739: just ident 8739 */
        V4L2_IDENT_WM8739 = 8739,
 
        /* module wm8775: just ident 8775 */
        V4L2_IDENT_WM8775 = 8775,
 
-       /* module tw9910: just ident 9910 */
-       V4L2_IDENT_TW9910 = 9910,
-
-       /* module cs53132a: just ident 53132 */
-       V4L2_IDENT_CS53l32A = 53132,
-
-       /* module upd64031a: just ident 64031 */
-       V4L2_IDENT_UPD64031A = 64031,
+       /* module tda9840: just ident 9840 */
+       V4L2_IDENT_TDA9840 = 9840,
 
-       /* module upd64083: just ident 64083 */
-       V4L2_IDENT_UPD64083 = 64083,
+       /* module cafe_ccic, just ident 8801 */
+       V4L2_IDENT_CAFE = 8801,
 
-       /* module m52790: just ident 52790 */
-       V4L2_IDENT_M52790 = 52790,
+       /* module tw9910: just ident 9910 */
+       V4L2_IDENT_TW9910 = 9910,
 
        /* module msp3400: reserved range 34000-34999 and 44000-44999 */
        V4L2_IDENT_MSPX4XX  = 34000, /* generic MSPX4XX identifier, only
@@ -178,6 +228,18 @@ enum {
        V4L2_IDENT_MT9V022IX7ATC        = 45010, /* No way to detect "normal" I77ATx */
        V4L2_IDENT_MT9V022IX7ATM        = 45015, /* and "lead free" IA7ATx chips */
        V4L2_IDENT_MT9T031              = 45020,
+
+       /* module cs53132a: just ident 53132 */
+       V4L2_IDENT_CS53l32A = 53132,
+
+       /* module upd64031a: just ident 64031 */
+       V4L2_IDENT_UPD64031A = 64031,
+
+       /* module upd64083: just ident 64083 */
+       V4L2_IDENT_UPD64083 = 64083,
+
+       /* module m52790: just ident 52790 */
+       V4L2_IDENT_M52790 = 52790,
 };
 
 #endif
index 95e74f1874e1cc53b24b6ac11af0d47149e99b9c..3a6905615d689e277f1e12e9858b3b5194ffc0e6 100644 (file)
@@ -102,11 +102,15 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
 const char *v4l2_ctrl_get_name(u32 id);
 const char **v4l2_ctrl_get_menu(u32 id);
 int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def);
-int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl);
 int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu,
                struct v4l2_queryctrl *qctrl, const char **menu_items);
 #define V4L2_CTRL_MENU_IDS_END (0xffffffff)
 int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids);
+
+/* Note: ctrl_classes points to an array of u32 pointers. Each u32 array is a
+   0-terminated array of control IDs. Each array must be sorted low to high
+   and belong to the same control class. The array of u32 pointers must also
+   be sorted, from low class IDs to high class IDs. */
 u32 v4l2_ctrl_next(const u32 * const *ctrl_classes, u32 id);
 
 /* ------------------------------------------------------------------------- */
@@ -149,6 +153,21 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter,
 /* Initialize an v4l2_subdev with data from an i2c_client struct */
 void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
                const struct v4l2_subdev_ops *ops);
+/* Return i2c client address of v4l2_subdev. */
+unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd);
+
+enum v4l2_i2c_tuner_type {
+       ADDRS_RADIO,    /* Radio tuner addresses */
+       ADDRS_DEMOD,    /* Demod tuner addresses */
+       ADDRS_TV,       /* TV tuner addresses */
+       /* TV tuner addresses if demod is present, this excludes
+          addresses used by the demodulator from the list of
+          candidates. */
+       ADDRS_TV_WITH_DEMOD,
+};
+/* Return a list of I2C tuner addresses to probe. Use only if the tuner
+   addresses are unknown. */
+const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type);
 
 /* ------------------------------------------------------------------------- */
 
@@ -284,4 +303,7 @@ struct v4l2_crystal_freq {
    a v4l2_gpio struct if a direction is also needed. */
 #define VIDIOC_INT_S_GPIO              _IOW('d', 117, u32)
 
+/* Get input status. Same as the status field in the v4l2_input struct. */
+#define VIDIOC_INT_G_INPUT_STATUS      _IOR('d', 118, u32)
+
 #endif /* V4L2_COMMON_H_ */
index e36faab8459b873f7ec07147abbcb834a12861cf..2058dd45e91547b849dfbb1a8ca000b470d8d862 100644 (file)
@@ -40,6 +40,8 @@ struct v4l2_file_operations {
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
        long (*ioctl) (struct file *, unsigned int, unsigned long);
        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
+       unsigned long (*get_unmapped_area) (struct file *, unsigned long,
+                               unsigned long, unsigned long, unsigned long);
        int (*mmap) (struct file *, struct vm_area_struct *);
        int (*open) (struct file *);
        int (*release) (struct file *);
index 55e41afd95ef39c59c8d110e9ebc7eed476e7812..0dd3e8e8653e136d28b97154d35c9cdb7f074b09 100644 (file)
@@ -33,7 +33,9 @@
 #define V4L2_DEVICE_NAME_SIZE (BUS_ID_SIZE + 16)
 
 struct v4l2_device {
-       /* dev->driver_data points to this struct */
+       /* dev->driver_data points to this struct.
+          Note: dev might be NULL if there is no parent device
+          as is the case with e.g. ISA devices. */
        struct device *dev;
        /* used to keep track of the registered subdevs */
        struct list_head subdevs;
@@ -42,33 +44,43 @@ struct v4l2_device {
        spinlock_t lock;
        /* unique device name, by default the driver name + bus ID */
        char name[V4L2_DEVICE_NAME_SIZE];
+       /* notify callback called by some sub-devices. */
+       void (*notify)(struct v4l2_subdev *sd,
+                       unsigned int notification, void *arg);
 };
 
-/* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev */
+/* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev.
+   dev may be NULL in rare cases (ISA devices). In that case you
+   must fill in the v4l2_dev->name field before calling this function. */
 int __must_check v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
-/* Set v4l2_dev->dev->driver_data to NULL and unregister all sub-devices */
+/* Set v4l2_dev->dev to NULL. Call when the USB parent disconnects.
+   Since the parent disappears this ensures that v4l2_dev doesn't have an
+   invalid parent pointer. */
+void v4l2_device_disconnect(struct v4l2_device *v4l2_dev);
+/* Unregister all sub-devices and any other resources related to v4l2_dev. */
 void v4l2_device_unregister(struct v4l2_device *v4l2_dev);
 
 /* Register a subdev with a v4l2 device. While registered the subdev module
    is marked as in-use. An error is returned if the module is no longer
    loaded when you attempt to register it. */
-int __must_check v4l2_device_register_subdev(struct v4l2_device *dev, struct v4l2_subdev *sd);
+int __must_check v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
+                                               struct v4l2_subdev *sd);
 /* Unregister a subdev with a v4l2 device. Can also be called if the subdev
    wasn't registered. In that case it will do nothing. */
 void v4l2_device_unregister_subdev(struct v4l2_subdev *sd);
 
 /* Iterate over all subdevs. */
-#define v4l2_device_for_each_subdev(sd, dev)                           \
-       list_for_each_entry(sd, &(dev)->subdevs, list)
+#define v4l2_device_for_each_subdev(sd, v4l2_dev)                      \
+       list_for_each_entry(sd, &(v4l2_dev)->subdevs, list)
 
 /* Call the specified callback for all subdevs matching the condition.
    Ignore any errors. Note that you cannot add or delete a subdev
    while walking the subdevs list. */
-#define __v4l2_device_call_subdevs(dev, cond, o, f, args...)           \
+#define __v4l2_device_call_subdevs(v4l2_dev, cond, o, f, args...)      \
        do {                                                            \
                struct v4l2_subdev *sd;                                 \
                                                                        \
-               list_for_each_entry(sd, &(dev)->subdevs, list)          \
+               list_for_each_entry(sd, &(v4l2_dev)->subdevs, list)     \
                        if ((cond) && sd->ops->o && sd->ops->o->f)      \
                                sd->ops->o->f(sd , ##args);             \
        } while (0)
@@ -77,12 +89,12 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd);
    If the callback returns an error other than 0 or -ENOIOCTLCMD, then
    return with that error code. Note that you cannot add or delete a
    subdev while walking the subdevs list. */
-#define __v4l2_device_call_subdevs_until_err(dev, cond, o, f, args...)  \
+#define __v4l2_device_call_subdevs_until_err(v4l2_dev, cond, o, f, args...) \
 ({                                                                     \
        struct v4l2_subdev *sd;                                         \
        long err = 0;                                                   \
                                                                        \
-       list_for_each_entry(sd, &(dev)->subdevs, list) {                \
+       list_for_each_entry(sd, &(v4l2_dev)->subdevs, list) {           \
                if ((cond) && sd->ops->o && sd->ops->o->f)              \
                        err = sd->ops->o->f(sd , ##args);               \
                if (err && err != -ENOIOCTLCMD)                         \
@@ -94,16 +106,16 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd);
 /* Call the specified callback for all subdevs matching grp_id (if 0, then
    match them all). Ignore any errors. Note that you cannot add or delete
    a subdev while walking the subdevs list. */
-#define v4l2_device_call_all(dev, grpid, o, f, args...)                \
-       __v4l2_device_call_subdevs(dev,                                 \
+#define v4l2_device_call_all(v4l2_dev, grpid, o, f, args...)           \
+       __v4l2_device_call_subdevs(v4l2_dev,                            \
                        !(grpid) || sd->grp_id == (grpid), o, f , ##args)
 
 /* Call the specified callback for all subdevs matching grp_id (if 0, then
    match them all). If the callback returns an error other than 0 or
    -ENOIOCTLCMD, then return with that error code. Note that you cannot
    add or delete a subdev while walking the subdevs list. */
-#define v4l2_device_call_until_err(dev, grpid, o, f, args...)          \
-       __v4l2_device_call_subdevs_until_err(dev,                       \
+#define v4l2_device_call_until_err(v4l2_dev, grpid, o, f, args...)     \
+       __v4l2_device_call_subdevs_until_err(v4l2_dev,                  \
                       !(grpid) || sd->grp_id == (grpid), o, f , ##args)
 
 #endif
index b01c044868d060e8c33fff3bf59d226b94ff33eb..7a4529defa8841ffa606d8af52d2dac289e5de29 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/mutex.h>
 #include <linux/compiler.h> /* need __user */
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
+#define __MIN_V4L1
 #include <linux/videodev.h>
 #else
 #include <linux/videodev2.h>
@@ -267,6 +268,7 @@ struct v4l2_ioctl_ops {
 
 /*  Video standard functions  */
 extern const char *v4l2_norm_to_name(v4l2_std_id id);
+extern void v4l2_video_std_frame_period(int id, struct v4l2_fract *frameperiod);
 extern int v4l2_video_std_construct(struct v4l2_standard *vs,
                                    int id, const char *name);
 /* Prints the ioctl in a human-readable format */
index 37b09e56e943ecf0938c175c3a9e83df8b171a7f..1d181b4ccb0143f3f837ded4ab319616cf63a0b0 100644 (file)
@@ -78,6 +78,9 @@ struct v4l2_subdev_core_ops {
        int (*queryctrl)(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc);
        int (*g_ctrl)(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
        int (*s_ctrl)(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
+       int (*g_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls);
+       int (*s_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls);
+       int (*try_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls);
        int (*querymenu)(struct v4l2_subdev *sd, struct v4l2_querymenu *qm);
        long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -112,9 +115,17 @@ struct v4l2_subdev_video_ops {
        int (*g_vbi_data)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_data *vbi_data);
        int (*g_sliced_vbi_cap)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_cap *cap);
        int (*s_std_output)(struct v4l2_subdev *sd, v4l2_std_id std);
+       int (*querystd)(struct v4l2_subdev *sd, v4l2_std_id *std);
+       int (*g_input_status)(struct v4l2_subdev *sd, u32 *status);
        int (*s_stream)(struct v4l2_subdev *sd, int enable);
-       int (*s_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
+       int (*enum_fmt)(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmtdesc);
        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 (*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);
+       int (*enum_frameintervals)(struct v4l2_subdev *sd, struct v4l2_frmivalenum *fival);
 };
 
 struct v4l2_subdev_ops {
@@ -132,7 +143,7 @@ struct v4l2_subdev_ops {
 struct v4l2_subdev {
        struct list_head list;
        struct module *owner;
-       struct v4l2_device *dev;
+       struct v4l2_device *v4l2_dev;
        const struct v4l2_subdev_ops *ops;
        /* name must be unique */
        char name[V4L2_SUBDEV_NAME_SIZE];
@@ -171,7 +182,7 @@ static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
        /* ops->core MUST be set */
        BUG_ON(!ops || !ops->core);
        sd->ops = ops;
-       sd->dev = NULL;
+       sd->v4l2_dev = NULL;
        sd->name[0] = '\0';
        sd->grp_id = 0;
        sd->priv = NULL;
@@ -186,4 +197,9 @@ static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
        (!(sd) ? -ENODEV : (((sd) && (sd)->ops->o && (sd)->ops->o->f) ? \
                (sd)->ops->o->f((sd) , ##args) : -ENOIOCTLCMD))
 
+/* Send a notification to v4l2_device. */
+#define v4l2_subdev_notify(sd, notification, arg)                         \
+       ((!(sd) || !(sd)->v4l2_dev || !(sd)->v4l2_dev->notify) ? -ENODEV : \
+        (sd)->v4l2_dev->notify((sd), (notification), (arg)))
+
 #endif
index 874f1340d0493d9f8f1e66a5186ae984e9e93a51..1c5946c447580faa83d4de48b03bb4c26ca4c9ee 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/poll.h>
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
+#define __MIN_V4L1
 #include <linux/videodev.h>
 #endif
 #include <linux/videodev2.h>
index bedc7f62e35d43e522efcd348c202dfb7f4ad261..abd443604c9fa042ec72d564eff7fb7a86307300 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/net.h>
 #include <linux/skbuff.h>
 #include <net/netlabel.h>
+#include <net/request_sock.h>
 #include <asm/atomic.h>
 
 /* known doi values */
@@ -215,6 +216,10 @@ int cipso_v4_sock_setattr(struct sock *sk,
                          const struct netlbl_lsm_secattr *secattr);
 void cipso_v4_sock_delattr(struct sock *sk);
 int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
+int cipso_v4_req_setattr(struct request_sock *req,
+                        const struct cipso_v4_doi *doi_def,
+                        const struct netlbl_lsm_secattr *secattr);
+void cipso_v4_req_delattr(struct request_sock *req);
 int cipso_v4_skbuff_setattr(struct sk_buff *skb,
                            const struct cipso_v4_doi *doi_def,
                            const struct netlbl_lsm_secattr *secattr);
@@ -247,6 +252,18 @@ static inline int cipso_v4_sock_getattr(struct sock *sk,
        return -ENOSYS;
 }
 
+static inline int cipso_v4_req_setattr(struct request_sock *req,
+                                      const struct cipso_v4_doi *doi_def,
+                                      const struct netlbl_lsm_secattr *secattr)
+{
+       return -ENOSYS;
+}
+
+static inline void cipso_v4_req_delattr(struct request_sock *req)
+{
+       return;
+}
+
 static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb,
                                      const struct cipso_v4_doi *doi_def,
                                      const struct netlbl_lsm_secattr *secattr)
index 749011eedc0b2740ed47ca50f5b30b5717d86e57..60ebbc1fef46a157cdb4393f123b21b07a7e0dc5 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/in.h>
 #include <linux/in6.h>
 #include <net/netlink.h>
+#include <net/request_sock.h>
 #include <asm/atomic.h>
 
 struct cipso_v4_doi;
@@ -406,6 +407,7 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
  */
 int netlbl_enabled(void);
 int netlbl_sock_setattr(struct sock *sk,
+                       u16 family,
                        const struct netlbl_lsm_secattr *secattr);
 void netlbl_sock_delattr(struct sock *sk);
 int netlbl_sock_getattr(struct sock *sk,
@@ -413,6 +415,9 @@ int netlbl_sock_getattr(struct sock *sk,
 int netlbl_conn_setattr(struct sock *sk,
                        struct sockaddr *addr,
                        const struct netlbl_lsm_secattr *secattr);
+int netlbl_req_setattr(struct request_sock *req,
+                      const struct netlbl_lsm_secattr *secattr);
+void netlbl_req_delattr(struct request_sock *req);
 int netlbl_skbuff_setattr(struct sk_buff *skb,
                          u16 family,
                          const struct netlbl_lsm_secattr *secattr);
@@ -519,7 +524,8 @@ static inline int netlbl_enabled(void)
        return 0;
 }
 static inline int netlbl_sock_setattr(struct sock *sk,
-                                    const struct netlbl_lsm_secattr *secattr)
+                                     u16 family,
+                                     const struct netlbl_lsm_secattr *secattr)
 {
        return -ENOSYS;
 }
@@ -537,6 +543,15 @@ static inline int netlbl_conn_setattr(struct sock *sk,
 {
        return -ENOSYS;
 }
+static inline int netlbl_req_setattr(struct request_sock *req,
+                                    const struct netlbl_lsm_secattr *secattr)
+{
+       return -ENOSYS;
+}
+static inline void netlbl_req_delattr(struct request_sock *req)
+{
+       return;
+}
 static inline int netlbl_skbuff_setattr(struct sk_buff *skb,
                                      u16 family,
                                      const struct netlbl_lsm_secattr *secattr)
index 426899e529c55313ee2aa35374e01f6c4fd74de5..5718a02d3afbea1eb993be1e9d1c81c65ea6c9f6 100644 (file)
@@ -22,8 +22,9 @@
  *
  */
 
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
 
 struct snd_tea575x;
 
@@ -35,11 +36,10 @@ struct snd_tea575x_ops {
 
 struct snd_tea575x {
        struct snd_card *card;
-       struct video_device vd;         /* video device */
-       struct v4l2_file_operations fops;
+       struct video_device *vd;        /* video device */
        int dev_nr;                     /* requested device number + 1 */
-       int vd_registered;              /* video device is registered */
        int tea5759;                    /* 5759 chip is present */
+       int mute;                       /* Device is muted? */
        unsigned int freq_fixup;        /* crystal onboard */
        unsigned int val;               /* hw value */
        unsigned long freq;             /* frequency */
index 51ac69f05bdcc6d547a7671f2a072e0f6a20f353..f0851e3bb7cc0124656a4277d73b2da17173812a 100644 (file)
 #define PWR_MGT_SLOWDOWN_MCLK                  0x00002000
 
 #define PMI_PMSCR_REG                          0x60
-                                                                                
+
 /* used by ATI bug fix for hardware ROM */
 #define RAGE128_MPP_TB_CONFIG                   0x01c0
 
index b2776b6c86795de5a84b7fc5fdb53cdf77be6634..9a5e9ee30782a0943671e2055b43d1b3c0d4ed59 100644 (file)
@@ -32,7 +32,6 @@
 #define CL_VSSM2       0x3c3   /* Motherboard Sleep */
 
 /*** VGA Sequencer Registers ***/
-#define CL_SEQR0       0x0     /* Reset */
 /* the following are from the "extension registers" group */
 #define CL_SEQR6       0x6     /* Unlock ALL Extensions */
 #define CL_SEQR7       0x7     /* Extended Sequencer Mode */
@@ -71,6 +70,7 @@
 #define CL_CRT1B       0x1b    /* Extended Display Controls */
 #define CL_CRT1C       0x1c    /* Sync adjust and genlock register */
 #define CL_CRT1D       0x1d    /* Overlay Extended Control register */
+#define CL_CRT1E       0x1e    /* Another overflow register */
 #define CL_CRT25       0x25    /* Part Status Register */
 #define CL_CRT27       0x27    /* ID Register */
 #define CL_CRT51       0x51    /* P4 disable "flicker fixer" */
index 1f5ebeaa818f4241d98e7a7e5f8e4cb0f1a1625f..001b935e71c46287084b70552c0727b1b902d0fd 100644 (file)
@@ -453,7 +453,7 @@ static __inline__ int newport_wait(struct newport_regs *regs)
 {
        int t = BUSY_TIMEOUT;
 
-       while (t--)
+       while (--t)
                if (!(regs->cset.status & NPORT_STAT_GBUSY))
                        break;
        return !t;
@@ -463,7 +463,7 @@ static __inline__ int newport_bfwait(struct newport_regs *regs)
 {
        int t = BUSY_TIMEOUT;
 
-       while (t--)
+       while (--t)
                if(!(regs->cset.status & NPORT_STAT_BBUSY))
                        break;
        return !t;
index e072b16b39abf88bb0bb4e2281d0bf09dd00f0bc..56b188abfb54d5ee72f78c858c955debc5c7ffdf 100644 (file)
@@ -5,12 +5,12 @@
 #define RADEON_REGSIZE                 0x4000
 
 
-#define MM_INDEX                               0x0000  
-#define MM_DATA                                0x0004  
-#define BUS_CNTL                               0x0030  
-#define HI_STAT                                0x004C  
+#define MM_INDEX                               0x0000
+#define MM_DATA                                0x0004
+#define BUS_CNTL                               0x0030
+#define HI_STAT                                0x004C
 #define BUS_CNTL1                              0x0034
-#define I2C_CNTL_1                            0x0094  
+#define I2C_CNTL_1                            0x0094
 #define CNFG_CNTL                              0x00E0
 #define CNFG_MEMSIZE                           0x00F8
 #define CNFG_APER_0_BASE                       0x0100
@@ -18,8 +18,8 @@
 #define CNFG_APER_SIZE                         0x0108
 #define CNFG_REG_1_BASE                        0x010C
 #define CNFG_REG_APER_SIZE                     0x0110
-#define PAD_AGPINPUT_DELAY                     0x0164  
-#define PAD_CTLR_STRENGTH                      0x0168  
+#define PAD_AGPINPUT_DELAY                     0x0164
+#define PAD_CTLR_STRENGTH                      0x0168
 #define PAD_CTLR_UPDATE                        0x016C
 #define PAD_CTLR_MISC                          0x0aa0
 #define AGP_CNTL                               0x0174
 #define CAP0_TRIG_CNTL                        0x0950
 #define CAP1_TRIG_CNTL                        0x09c0
 #define VIPH_CONTROL                          0x0C40
-#define VENDOR_ID                              0x0F00  
-#define DEVICE_ID                              0x0F02  
-#define COMMAND                                0x0F04  
-#define STATUS                                 0x0F06  
-#define REVISION_ID                            0x0F08  
-#define REGPROG_INF                            0x0F09  
-#define SUB_CLASS                              0x0F0A  
-#define BASE_CODE                              0x0F0B  
-#define CACHE_LINE                             0x0F0C  
-#define LATENCY                                0x0F0D  
-#define HEADER                                 0x0F0E  
-#define BIST                                   0x0F0F  
-#define REG_MEM_BASE                           0x0F10  
-#define REG_IO_BASE                            0x0F14  
+#define VENDOR_ID                              0x0F00
+#define DEVICE_ID                              0x0F02
+#define COMMAND                                0x0F04
+#define STATUS                                 0x0F06
+#define REVISION_ID                            0x0F08
+#define REGPROG_INF                            0x0F09
+#define SUB_CLASS                              0x0F0A
+#define BASE_CODE                              0x0F0B
+#define CACHE_LINE                             0x0F0C
+#define LATENCY                                0x0F0D
+#define HEADER                                 0x0F0E
+#define BIST                                   0x0F0F
+#define REG_MEM_BASE                           0x0F10
+#define REG_IO_BASE                            0x0F14
 #define REG_REG_BASE                           0x0F18
 #define ADAPTER_ID                             0x0F2C
 #define BIOS_ROM                               0x0F30
-#define CAPABILITIES_PTR                       0x0F34  
-#define INTERRUPT_LINE                         0x0F3C  
-#define INTERRUPT_PIN                          0x0F3D  
-#define MIN_GRANT                              0x0F3E  
-#define MAX_LATENCY                            0x0F3F  
-#define ADAPTER_ID_W                           0x0F4C  
-#define PMI_CAP_ID                             0x0F50  
-#define PMI_NXT_CAP_PTR                        0x0F51  
-#define PMI_PMC_REG                            0x0F52  
-#define PM_STATUS                              0x0F54  
-#define PMI_DATA                               0x0F57  
-#define AGP_CAP_ID                             0x0F58  
-#define AGP_STATUS                             0x0F5C  
-#define AGP_COMMAND                            0x0F60  
+#define CAPABILITIES_PTR                       0x0F34
+#define INTERRUPT_LINE                         0x0F3C
+#define INTERRUPT_PIN                          0x0F3D
+#define MIN_GRANT                              0x0F3E
+#define MAX_LATENCY                            0x0F3F
+#define ADAPTER_ID_W                           0x0F4C
+#define PMI_CAP_ID                             0x0F50
+#define PMI_NXT_CAP_PTR                        0x0F51
+#define PMI_PMC_REG                            0x0F52
+#define PM_STATUS                              0x0F54
+#define PMI_DATA                               0x0F57
+#define AGP_CAP_ID                             0x0F58
+#define AGP_STATUS                             0x0F5C
+#define AGP_COMMAND                            0x0F60
 #define AIC_CTRL                               0x01D0
 #define AIC_STAT                               0x01D4
 #define AIC_PT_BASE                            0x01D8
-#define AIC_LO_ADDR                            0x01DC  
-#define AIC_HI_ADDR                            0x01E0  
-#define AIC_TLB_ADDR                           0x01E4  
-#define AIC_TLB_DATA                           0x01E8  
-#define DAC_CNTL                               0x0058  
+#define AIC_LO_ADDR                            0x01DC
+#define AIC_HI_ADDR                            0x01E0
+#define AIC_TLB_ADDR                           0x01E4
+#define AIC_TLB_DATA                           0x01E8
+#define DAC_CNTL                               0x0058
 #define DAC_CNTL2                              0x007c
-#define CRTC_GEN_CNTL                          0x0050  
-#define MEM_CNTL                               0x0140  
+#define CRTC_GEN_CNTL                          0x0050
+#define MEM_CNTL                               0x0140
 #define MC_CNTL                                0x0140
-#define EXT_MEM_CNTL                           0x0144  
+#define EXT_MEM_CNTL                           0x0144
 #define MC_TIMING_CNTL                         0x0144
-#define MC_AGP_LOCATION                        0x014C  
-#define MEM_IO_CNTL_A0                         0x0178  
+#define MC_AGP_LOCATION                        0x014C
+#define MEM_IO_CNTL_A0                         0x0178
 #define MEM_REFRESH_CNTL                       0x0178
-#define MEM_INIT_LATENCY_TIMER                 0x0154  
+#define MEM_INIT_LATENCY_TIMER                 0x0154
 #define MC_INIT_GFX_LAT_TIMER                  0x0154
-#define MEM_SDRAM_MODE_REG                     0x0158  
-#define AGP_BASE                               0x0170  
-#define MEM_IO_CNTL_A1                         0x017C  
+#define MEM_SDRAM_MODE_REG                     0x0158
+#define AGP_BASE                               0x0170
+#define MEM_IO_CNTL_A1                         0x017C
 #define MC_READ_CNTL_AB                        0x017C
 #define MEM_IO_CNTL_B0                         0x0180
 #define MC_INIT_MISC_LAT_TIMER                 0x0180
 #define MEM_IO_CNTL_B1                         0x0184
 #define MC_IOPAD_CNTL                          0x0184
 #define MC_DEBUG                               0x0188
-#define MC_STATUS                              0x0150  
-#define MEM_IO_OE_CNTL                         0x018C  
+#define MC_STATUS                              0x0150
+#define MEM_IO_OE_CNTL                         0x018C
 #define MC_CHIP_IO_OE_CNTL_AB                  0x018C
-#define MC_FB_LOCATION                         0x0148  
-#define HOST_PATH_CNTL                         0x0130  
-#define MEM_VGA_WP_SEL                         0x0038  
-#define MEM_VGA_RP_SEL                         0x003C  
-#define HDP_DEBUG                              0x0138  
+#define MC_FB_LOCATION                         0x0148
+#define HOST_PATH_CNTL                         0x0130
+#define MEM_VGA_WP_SEL                         0x0038
+#define MEM_VGA_RP_SEL                         0x003C
+#define HDP_DEBUG                              0x0138
 #define SW_SEMAPHORE                           0x013C
-#define CRTC2_GEN_CNTL                         0x03f8  
+#define CRTC2_GEN_CNTL                         0x03f8
 #define CRTC2_DISPLAY_BASE_ADDR                0x033c
-#define SURFACE_CNTL                           0x0B00  
-#define SURFACE0_LOWER_BOUND                   0x0B04  
-#define SURFACE1_LOWER_BOUND                   0x0B14  
-#define SURFACE2_LOWER_BOUND                   0x0B24  
-#define SURFACE3_LOWER_BOUND                   0x0B34  
-#define SURFACE4_LOWER_BOUND                   0x0B44  
+#define SURFACE_CNTL                           0x0B00
+#define SURFACE0_LOWER_BOUND                   0x0B04
+#define SURFACE1_LOWER_BOUND                   0x0B14
+#define SURFACE2_LOWER_BOUND                   0x0B24
+#define SURFACE3_LOWER_BOUND                   0x0B34
+#define SURFACE4_LOWER_BOUND                   0x0B44
 #define SURFACE5_LOWER_BOUND                   0x0B54
 #define SURFACE6_LOWER_BOUND                   0x0B64
 #define SURFACE7_LOWER_BOUND                   0x0B74
-#define SURFACE0_UPPER_BOUND                   0x0B08  
-#define SURFACE1_UPPER_BOUND                   0x0B18  
-#define SURFACE2_UPPER_BOUND                   0x0B28  
-#define SURFACE3_UPPER_BOUND                   0x0B38  
-#define SURFACE4_UPPER_BOUND                   0x0B48  
-#define SURFACE5_UPPER_BOUND                   0x0B58  
-#define SURFACE6_UPPER_BOUND                   0x0B68  
-#define SURFACE7_UPPER_BOUND                   0x0B78  
-#define SURFACE0_INFO                          0x0B0C  
-#define SURFACE1_INFO                          0x0B1C  
-#define SURFACE2_INFO                          0x0B2C  
-#define SURFACE3_INFO                          0x0B3C  
-#define SURFACE4_INFO                          0x0B4C  
-#define SURFACE5_INFO                          0x0B5C  
+#define SURFACE0_UPPER_BOUND                   0x0B08
+#define SURFACE1_UPPER_BOUND                   0x0B18
+#define SURFACE2_UPPER_BOUND                   0x0B28
+#define SURFACE3_UPPER_BOUND                   0x0B38
+#define SURFACE4_UPPER_BOUND                   0x0B48
+#define SURFACE5_UPPER_BOUND                   0x0B58
+#define SURFACE6_UPPER_BOUND                   0x0B68
+#define SURFACE7_UPPER_BOUND                   0x0B78
+#define SURFACE0_INFO                          0x0B0C
+#define SURFACE1_INFO                          0x0B1C
+#define SURFACE2_INFO                          0x0B2C
+#define SURFACE3_INFO                          0x0B3C
+#define SURFACE4_INFO                          0x0B4C
+#define SURFACE5_INFO                          0x0B5C
 #define SURFACE6_INFO                          0x0B6C
 #define SURFACE7_INFO                          0x0B7C
 #define SURFACE_ACCESS_FLAGS                   0x0BF8
-#define SURFACE_ACCESS_CLR                     0x0BFC  
-#define GEN_INT_CNTL                           0x0040  
-#define GEN_INT_STATUS                         0x0044  
+#define SURFACE_ACCESS_CLR                     0x0BFC
+#define GEN_INT_CNTL                           0x0040
+#define GEN_INT_STATUS                         0x0044
 #define CRTC_EXT_CNTL                          0x0054
-#define RB3D_CNTL                             0x1C3C  
-#define WAIT_UNTIL                             0x1720  
-#define ISYNC_CNTL                             0x1724  
-#define RBBM_GUICNTL                           0x172C  
-#define RBBM_STATUS                            0x0E40  
-#define RBBM_STATUS_alt_1                      0x1740  
-#define RBBM_CNTL                              0x00EC  
-#define RBBM_CNTL_alt_1                        0x0E44  
-#define RBBM_SOFT_RESET                        0x00F0  
-#define RBBM_SOFT_RESET_alt_1                  0x0E48  
-#define NQWAIT_UNTIL                           0x0E50  
+#define RB3D_CNTL                             0x1C3C
+#define WAIT_UNTIL                             0x1720
+#define ISYNC_CNTL                             0x1724
+#define RBBM_GUICNTL                           0x172C
+#define RBBM_STATUS                            0x0E40
+#define RBBM_STATUS_alt_1                      0x1740
+#define RBBM_CNTL                              0x00EC
+#define RBBM_CNTL_alt_1                        0x0E44
+#define RBBM_SOFT_RESET                        0x00F0
+#define RBBM_SOFT_RESET_alt_1                  0x0E48
+#define NQWAIT_UNTIL                           0x0E50
 #define RBBM_DEBUG                             0x0E6C
 #define RBBM_CMDFIFO_ADDR                      0x0E70
 #define RBBM_CMDFIFO_DATAL                     0x0E74
-#define RBBM_CMDFIFO_DATAH                     0x0E78  
-#define RBBM_CMDFIFO_STAT                      0x0E7C  
-#define CRTC_STATUS                            0x005C  
-#define GPIO_VGA_DDC                           0x0060  
-#define GPIO_DVI_DDC                           0x0064  
-#define GPIO_MONID                             0x0068  
+#define RBBM_CMDFIFO_DATAH                     0x0E78
+#define RBBM_CMDFIFO_STAT                      0x0E7C
+#define CRTC_STATUS                            0x005C
+#define GPIO_VGA_DDC                           0x0060
+#define GPIO_DVI_DDC                           0x0064
+#define GPIO_MONID                             0x0068
 #define GPIO_CRT2_DDC                          0x006c
-#define PALETTE_INDEX                          0x00B0  
-#define PALETTE_DATA                           0x00B4  
-#define PALETTE_30_DATA                        0x00B8  
-#define CRTC_H_TOTAL_DISP                      0x0200  
-#define CRTC_H_SYNC_STRT_WID                   0x0204  
-#define CRTC_V_TOTAL_DISP                      0x0208  
-#define CRTC_V_SYNC_STRT_WID                   0x020C  
-#define CRTC_VLINE_CRNT_VLINE                  0x0210  
+#define PALETTE_INDEX                          0x00B0
+#define PALETTE_DATA                           0x00B4
+#define PALETTE_30_DATA                        0x00B8
+#define CRTC_H_TOTAL_DISP                      0x0200
+#define CRTC_H_SYNC_STRT_WID                   0x0204
+#define CRTC_V_TOTAL_DISP                      0x0208
+#define CRTC_V_SYNC_STRT_WID                   0x020C
+#define CRTC_VLINE_CRNT_VLINE                  0x0210
 #define CRTC_CRNT_FRAME                        0x0214
 #define CRTC_GUI_TRIG_VLINE                    0x0218
 #define CRTC_DEBUG                             0x021C
-#define CRTC_OFFSET_RIGHT                      0x0220  
-#define CRTC_OFFSET                            0x0224  
-#define CRTC_OFFSET_CNTL                       0x0228  
-#define CRTC_PITCH                             0x022C  
-#define OVR_CLR                                0x0230  
-#define OVR_WID_LEFT_RIGHT                     0x0234  
-#define OVR_WID_TOP_BOTTOM                     0x0238  
-#define DISPLAY_BASE_ADDR                      0x023C  
-#define SNAPSHOT_VH_COUNTS                     0x0240  
-#define SNAPSHOT_F_COUNT                       0x0244  
-#define N_VIF_COUNT                            0x0248  
-#define SNAPSHOT_VIF_COUNT                     0x024C  
-#define FP_CRTC_H_TOTAL_DISP                   0x0250  
-#define FP_CRTC_V_TOTAL_DISP                   0x0254  
+#define CRTC_OFFSET_RIGHT                      0x0220
+#define CRTC_OFFSET                            0x0224
+#define CRTC_OFFSET_CNTL                       0x0228
+#define CRTC_PITCH                             0x022C
+#define OVR_CLR                                0x0230
+#define OVR_WID_LEFT_RIGHT                     0x0234
+#define OVR_WID_TOP_BOTTOM                     0x0238
+#define DISPLAY_BASE_ADDR                      0x023C
+#define SNAPSHOT_VH_COUNTS                     0x0240
+#define SNAPSHOT_F_COUNT                       0x0244
+#define N_VIF_COUNT                            0x0248
+#define SNAPSHOT_VIF_COUNT                     0x024C
+#define FP_CRTC_H_TOTAL_DISP                   0x0250
+#define FP_CRTC_V_TOTAL_DISP                   0x0254
 #define CRT_CRTC_H_SYNC_STRT_WID               0x0258
 #define CRT_CRTC_V_SYNC_STRT_WID               0x025C
 #define CUR_OFFSET                             0x0260
-#define CUR_HORZ_VERT_POSN                     0x0264  
-#define CUR_HORZ_VERT_OFF                      0x0268  
-#define CUR_CLR0                               0x026C  
-#define CUR_CLR1                               0x0270  
-#define FP_HORZ_VERT_ACTIVE                    0x0278  
-#define CRTC_MORE_CNTL                         0x027C  
+#define CUR_HORZ_VERT_POSN                     0x0264
+#define CUR_HORZ_VERT_OFF                      0x0268
+#define CUR_CLR0                               0x026C
+#define CUR_CLR1                               0x0270
+#define FP_HORZ_VERT_ACTIVE                    0x0278
+#define CRTC_MORE_CNTL                         0x027C
 #define CRTC_H_CUTOFF_ACTIVE_EN                (1<<4)
 #define CRTC_V_CUTOFF_ACTIVE_EN                (1<<5)
-#define DAC_EXT_CNTL                           0x0280  
-#define FP_GEN_CNTL                            0x0284  
-#define FP_HORZ_STRETCH                        0x028C  
-#define FP_VERT_STRETCH                        0x0290  
-#define FP_H_SYNC_STRT_WID                     0x02C4  
-#define FP_V_SYNC_STRT_WID                     0x02C8  
-#define AUX_WINDOW_HORZ_CNTL                   0x02D8  
-#define AUX_WINDOW_VERT_CNTL                   0x02DC  
+#define DAC_EXT_CNTL                           0x0280
+#define FP_GEN_CNTL                            0x0284
+#define FP_HORZ_STRETCH                        0x028C
+#define FP_VERT_STRETCH                        0x0290
+#define FP_H_SYNC_STRT_WID                     0x02C4
+#define FP_V_SYNC_STRT_WID                     0x02C8
+#define AUX_WINDOW_HORZ_CNTL                   0x02D8
+#define AUX_WINDOW_VERT_CNTL                   0x02DC
 //#define DDA_CONFIG                          0x02e0
 //#define DDA_ON_OFF                          0x02e4
 #define DVI_I2C_CNTL_1                        0x02e4
 #define GRPH2_BUFFER_CNTL                      0x03F0
 #define VGA_BUFFER_CNTL                        0x02F4
 #define OV0_Y_X_START                          0x0400
-#define OV0_Y_X_END                            0x0404  
-#define OV0_PIPELINE_CNTL                      0x0408  
-#define OV0_REG_LOAD_CNTL                      0x0410  
-#define OV0_SCALE_CNTL                         0x0420  
-#define OV0_V_INC                              0x0424  
-#define OV0_P1_V_ACCUM_INIT                    0x0428  
-#define OV0_P23_V_ACCUM_INIT                   0x042C  
-#define OV0_P1_BLANK_LINES_AT_TOP              0x0430  
-#define OV0_P23_BLANK_LINES_AT_TOP             0x0434  
-#define OV0_BASE_ADDR                          0x043C  
-#define OV0_VID_BUF0_BASE_ADRS                 0x0440  
-#define OV0_VID_BUF1_BASE_ADRS                 0x0444  
-#define OV0_VID_BUF2_BASE_ADRS                 0x0448  
-#define OV0_VID_BUF3_BASE_ADRS                 0x044C  
+#define OV0_Y_X_END                            0x0404
+#define OV0_PIPELINE_CNTL                      0x0408
+#define OV0_REG_LOAD_CNTL                      0x0410
+#define OV0_SCALE_CNTL                         0x0420
+#define OV0_V_INC                              0x0424
+#define OV0_P1_V_ACCUM_INIT                    0x0428
+#define OV0_P23_V_ACCUM_INIT                   0x042C
+#define OV0_P1_BLANK_LINES_AT_TOP              0x0430
+#define OV0_P23_BLANK_LINES_AT_TOP             0x0434
+#define OV0_BASE_ADDR                          0x043C
+#define OV0_VID_BUF0_BASE_ADRS                 0x0440
+#define OV0_VID_BUF1_BASE_ADRS                 0x0444
+#define OV0_VID_BUF2_BASE_ADRS                 0x0448
+#define OV0_VID_BUF3_BASE_ADRS                 0x044C
 #define OV0_VID_BUF4_BASE_ADRS                 0x0450
 #define OV0_VID_BUF5_BASE_ADRS                 0x0454
 #define OV0_VID_BUF_PITCH0_VALUE               0x0460
-#define OV0_VID_BUF_PITCH1_VALUE               0x0464  
-#define OV0_AUTO_FLIP_CNTRL                    0x0470  
-#define OV0_DEINTERLACE_PATTERN                0x0474  
-#define OV0_SUBMIT_HISTORY                     0x0478  
-#define OV0_H_INC                              0x0480  
-#define OV0_STEP_BY                            0x0484  
-#define OV0_P1_H_ACCUM_INIT                    0x0488  
-#define OV0_P23_H_ACCUM_INIT                   0x048C  
-#define OV0_P1_X_START_END                     0x0494  
-#define OV0_P2_X_START_END                     0x0498  
-#define OV0_P3_X_START_END                     0x049C  
-#define OV0_FILTER_CNTL                        0x04A0  
-#define OV0_FOUR_TAP_COEF_0                    0x04B0  
-#define OV0_FOUR_TAP_COEF_1                    0x04B4  
+#define OV0_VID_BUF_PITCH1_VALUE               0x0464
+#define OV0_AUTO_FLIP_CNTRL                    0x0470
+#define OV0_DEINTERLACE_PATTERN                0x0474
+#define OV0_SUBMIT_HISTORY                     0x0478
+#define OV0_H_INC                              0x0480
+#define OV0_STEP_BY                            0x0484
+#define OV0_P1_H_ACCUM_INIT                    0x0488
+#define OV0_P23_H_ACCUM_INIT                   0x048C
+#define OV0_P1_X_START_END                     0x0494
+#define OV0_P2_X_START_END                     0x0498
+#define OV0_P3_X_START_END                     0x049C
+#define OV0_FILTER_CNTL                        0x04A0
+#define OV0_FOUR_TAP_COEF_0                    0x04B0
+#define OV0_FOUR_TAP_COEF_1                    0x04B4
 #define OV0_FOUR_TAP_COEF_2                    0x04B8
 #define OV0_FOUR_TAP_COEF_3                    0x04BC
 #define OV0_FOUR_TAP_COEF_4                    0x04C0
-#define OV0_FLAG_CNTRL                         0x04DC  
-#define OV0_SLICE_CNTL                         0x04E0  
-#define OV0_VID_KEY_CLR_LOW                    0x04E4  
-#define OV0_VID_KEY_CLR_HIGH                   0x04E8  
-#define OV0_GRPH_KEY_CLR_LOW                   0x04EC  
-#define OV0_GRPH_KEY_CLR_HIGH                  0x04F0  
-#define OV0_KEY_CNTL                           0x04F4  
-#define OV0_TEST                               0x04F8  
-#define SUBPIC_CNTL                            0x0540  
-#define SUBPIC_DEFCOLCON                       0x0544  
-#define SUBPIC_Y_X_START                       0x054C  
-#define SUBPIC_Y_X_END                         0x0550  
-#define SUBPIC_V_INC                           0x0554  
-#define SUBPIC_H_INC                           0x0558  
+#define OV0_FLAG_CNTRL                         0x04DC
+#define OV0_SLICE_CNTL                         0x04E0
+#define OV0_VID_KEY_CLR_LOW                    0x04E4
+#define OV0_VID_KEY_CLR_HIGH                   0x04E8
+#define OV0_GRPH_KEY_CLR_LOW                   0x04EC
+#define OV0_GRPH_KEY_CLR_HIGH                  0x04F0
+#define OV0_KEY_CNTL                           0x04F4
+#define OV0_TEST                               0x04F8
+#define SUBPIC_CNTL                            0x0540
+#define SUBPIC_DEFCOLCON                       0x0544
+#define SUBPIC_Y_X_START                       0x054C
+#define SUBPIC_Y_X_END                         0x0550
+#define SUBPIC_V_INC                           0x0554
+#define SUBPIC_H_INC                           0x0558
 #define SUBPIC_BUF0_OFFSET                     0x055C
 #define SUBPIC_BUF1_OFFSET                     0x0560
 #define SUBPIC_LC0_OFFSET                      0x0564
-#define SUBPIC_LC1_OFFSET                      0x0568  
-#define SUBPIC_PITCH                           0x056C  
-#define SUBPIC_BTN_HLI_COLCON                  0x0570  
-#define SUBPIC_BTN_HLI_Y_X_START               0x0574  
-#define SUBPIC_BTN_HLI_Y_X_END                 0x0578  
-#define SUBPIC_PALETTE_INDEX                   0x057C  
-#define SUBPIC_PALETTE_DATA                    0x0580  
-#define SUBPIC_H_ACCUM_INIT                    0x0584  
-#define SUBPIC_V_ACCUM_INIT                    0x0588  
-#define DISP_MISC_CNTL                         0x0D00  
-#define DAC_MACRO_CNTL                         0x0D04  
-#define DISP_PWR_MAN                           0x0D08  
-#define DISP_TEST_DEBUG_CNTL                   0x0D10  
-#define DISP_HW_DEBUG                          0x0D14  
+#define SUBPIC_LC1_OFFSET                      0x0568
+#define SUBPIC_PITCH                           0x056C
+#define SUBPIC_BTN_HLI_COLCON                  0x0570
+#define SUBPIC_BTN_HLI_Y_X_START               0x0574
+#define SUBPIC_BTN_HLI_Y_X_END                 0x0578
+#define SUBPIC_PALETTE_INDEX                   0x057C
+#define SUBPIC_PALETTE_DATA                    0x0580
+#define SUBPIC_H_ACCUM_INIT                    0x0584
+#define SUBPIC_V_ACCUM_INIT                    0x0588
+#define DISP_MISC_CNTL                         0x0D00
+#define DAC_MACRO_CNTL                         0x0D04
+#define DISP_PWR_MAN                           0x0D08
+#define DISP_TEST_DEBUG_CNTL                   0x0D10
+#define DISP_HW_DEBUG                          0x0D14
 #define DAC_CRC_SIG1                           0x0D18
 #define DAC_CRC_SIG2                           0x0D1C
 #define OV0_LIN_TRANS_A                        0x0D20
-#define OV0_LIN_TRANS_B                        0x0D24  
-#define OV0_LIN_TRANS_C                        0x0D28  
-#define OV0_LIN_TRANS_D                        0x0D2C  
-#define OV0_LIN_TRANS_E                        0x0D30  
-#define OV0_LIN_TRANS_F                        0x0D34  
-#define OV0_GAMMA_0_F                          0x0D40  
-#define OV0_GAMMA_10_1F                        0x0D44  
-#define OV0_GAMMA_20_3F                        0x0D48  
-#define OV0_GAMMA_40_7F                        0x0D4C  
-#define OV0_GAMMA_380_3BF                      0x0D50  
-#define OV0_GAMMA_3C0_3FF                      0x0D54  
-#define DISP_MERGE_CNTL                        0x0D60  
-#define DISP_OUTPUT_CNTL                       0x0D64  
-#define DISP_LIN_TRANS_GRPH_A                  0x0D80  
+#define OV0_LIN_TRANS_B                        0x0D24
+#define OV0_LIN_TRANS_C                        0x0D28
+#define OV0_LIN_TRANS_D                        0x0D2C
+#define OV0_LIN_TRANS_E                        0x0D30
+#define OV0_LIN_TRANS_F                        0x0D34
+#define OV0_GAMMA_0_F                          0x0D40
+#define OV0_GAMMA_10_1F                        0x0D44
+#define OV0_GAMMA_20_3F                        0x0D48
+#define OV0_GAMMA_40_7F                        0x0D4C
+#define OV0_GAMMA_380_3BF                      0x0D50
+#define OV0_GAMMA_3C0_3FF                      0x0D54
+#define DISP_MERGE_CNTL                        0x0D60
+#define DISP_OUTPUT_CNTL                       0x0D64
+#define DISP_LIN_TRANS_GRPH_A                  0x0D80
 #define DISP_LIN_TRANS_GRPH_B                  0x0D84
 #define DISP_LIN_TRANS_GRPH_C                  0x0D88
 #define DISP_LIN_TRANS_GRPH_D                  0x0D8C
-#define DISP_LIN_TRANS_GRPH_E                  0x0D90  
-#define DISP_LIN_TRANS_GRPH_F                  0x0D94  
-#define DISP_LIN_TRANS_VID_A                   0x0D98  
-#define DISP_LIN_TRANS_VID_B                   0x0D9C  
-#define DISP_LIN_TRANS_VID_C                   0x0DA0  
-#define DISP_LIN_TRANS_VID_D                   0x0DA4  
-#define DISP_LIN_TRANS_VID_E                   0x0DA8  
-#define DISP_LIN_TRANS_VID_F                   0x0DAC  
-#define RMX_HORZ_FILTER_0TAP_COEF              0x0DB0  
-#define RMX_HORZ_FILTER_1TAP_COEF              0x0DB4  
-#define RMX_HORZ_FILTER_2TAP_COEF              0x0DB8  
-#define RMX_HORZ_PHASE                         0x0DBC  
-#define DAC_EMBEDDED_SYNC_CNTL                 0x0DC0  
-#define DAC_BROAD_PULSE                        0x0DC4  
+#define DISP_LIN_TRANS_GRPH_E                  0x0D90
+#define DISP_LIN_TRANS_GRPH_F                  0x0D94
+#define DISP_LIN_TRANS_VID_A                   0x0D98
+#define DISP_LIN_TRANS_VID_B                   0x0D9C
+#define DISP_LIN_TRANS_VID_C                   0x0DA0
+#define DISP_LIN_TRANS_VID_D                   0x0DA4
+#define DISP_LIN_TRANS_VID_E                   0x0DA8
+#define DISP_LIN_TRANS_VID_F                   0x0DAC
+#define RMX_HORZ_FILTER_0TAP_COEF              0x0DB0
+#define RMX_HORZ_FILTER_1TAP_COEF              0x0DB4
+#define RMX_HORZ_FILTER_2TAP_COEF              0x0DB8
+#define RMX_HORZ_PHASE                         0x0DBC
+#define DAC_EMBEDDED_SYNC_CNTL                 0x0DC0
+#define DAC_BROAD_PULSE                        0x0DC4
 #define DAC_SKEW_CLKS                          0x0DC8
 #define DAC_INCR                               0x0DCC
 #define DAC_NEG_SYNC_LEVEL                     0x0DD0
-#define DAC_POS_SYNC_LEVEL                     0x0DD4  
-#define DAC_BLANK_LEVEL                        0x0DD8  
-#define CLOCK_CNTL_INDEX                       0x0008  
-#define CLOCK_CNTL_DATA                        0x000C  
-#define CP_RB_CNTL                             0x0704  
-#define CP_RB_BASE                             0x0700  
-#define CP_RB_RPTR_ADDR                        0x070C  
-#define CP_RB_RPTR                             0x0710  
-#define CP_RB_WPTR                             0x0714  
-#define CP_RB_WPTR_DELAY                       0x0718  
-#define CP_IB_BASE                             0x0738  
-#define CP_IB_BUFSZ                            0x073C  
-#define SCRATCH_REG0                           0x15E0  
-#define GUI_SCRATCH_REG0                       0x15E0  
-#define SCRATCH_REG1                           0x15E4  
-#define GUI_SCRATCH_REG1                       0x15E4  
+#define DAC_POS_SYNC_LEVEL                     0x0DD4
+#define DAC_BLANK_LEVEL                        0x0DD8
+#define CLOCK_CNTL_INDEX                       0x0008
+#define CLOCK_CNTL_DATA                        0x000C
+#define CP_RB_CNTL                             0x0704
+#define CP_RB_BASE                             0x0700
+#define CP_RB_RPTR_ADDR                        0x070C
+#define CP_RB_RPTR                             0x0710
+#define CP_RB_WPTR                             0x0714
+#define CP_RB_WPTR_DELAY                       0x0718
+#define CP_IB_BASE                             0x0738
+#define CP_IB_BUFSZ                            0x073C
+#define SCRATCH_REG0                           0x15E0
+#define GUI_SCRATCH_REG0                       0x15E0
+#define SCRATCH_REG1                           0x15E4
+#define GUI_SCRATCH_REG1                       0x15E4
 #define SCRATCH_REG2                           0x15E8
 #define GUI_SCRATCH_REG2                       0x15E8
 #define SCRATCH_REG3                           0x15EC
-#define GUI_SCRATCH_REG3                       0x15EC  
-#define SCRATCH_REG4                           0x15F0  
-#define GUI_SCRATCH_REG4                       0x15F0  
-#define SCRATCH_REG5                           0x15F4  
-#define GUI_SCRATCH_REG5                       0x15F4  
-#define SCRATCH_UMSK                           0x0770  
-#define SCRATCH_ADDR                           0x0774  
-#define DP_BRUSH_FRGD_CLR                      0x147C  
+#define GUI_SCRATCH_REG3                       0x15EC
+#define SCRATCH_REG4                           0x15F0
+#define GUI_SCRATCH_REG4                       0x15F0
+#define SCRATCH_REG5                           0x15F4
+#define GUI_SCRATCH_REG5                       0x15F4
+#define SCRATCH_UMSK                           0x0770
+#define SCRATCH_ADDR                           0x0774
+#define DP_BRUSH_FRGD_CLR                      0x147C
 #define DP_BRUSH_BKGD_CLR                      0x1478
 #define DST_LINE_START                         0x1600
-#define DST_LINE_END                           0x1604  
-#define SRC_OFFSET                             0x15AC  
+#define DST_LINE_END                           0x1604
+#define SRC_OFFSET                             0x15AC
 #define SRC_PITCH                              0x15B0
 #define SRC_TILE                               0x1704
 #define SRC_PITCH_OFFSET                       0x1428
-#define SRC_X                                  0x1414  
-#define SRC_Y                                  0x1418  
-#define SRC_X_Y                                0x1590  
-#define SRC_Y_X                                0x1434  
+#define SRC_X                                  0x1414
+#define SRC_Y                                  0x1418
+#define SRC_X_Y                                0x1590
+#define SRC_Y_X                                0x1434
 #define DST_Y_X                                       0x1438
 #define DST_WIDTH_HEIGHT                      0x1598
 #define DST_HEIGHT_WIDTH                      0x143c
 #define DST_OFFSET                             0x1404
-#define SRC_CLUT_ADDRESS                       0x1780  
-#define SRC_CLUT_DATA                          0x1784  
-#define SRC_CLUT_DATA_RD                       0x1788  
-#define HOST_DATA0                             0x17C0  
-#define HOST_DATA1                             0x17C4  
-#define HOST_DATA2                             0x17C8  
-#define HOST_DATA3                             0x17CC  
-#define HOST_DATA4                             0x17D0  
-#define HOST_DATA5                             0x17D4  
-#define HOST_DATA6                             0x17D8  
+#define SRC_CLUT_ADDRESS                       0x1780
+#define SRC_CLUT_DATA                          0x1784
+#define SRC_CLUT_DATA_RD                       0x1788
+#define HOST_DATA0                             0x17C0
+#define HOST_DATA1                             0x17C4
+#define HOST_DATA2                             0x17C8
+#define HOST_DATA3                             0x17CC
+#define HOST_DATA4                             0x17D0
+#define HOST_DATA5                             0x17D4
+#define HOST_DATA6                             0x17D8
 #define HOST_DATA7                             0x17DC
 #define HOST_DATA_LAST                         0x17E0
 #define DP_SRC_ENDIAN                          0x15D4
-#define DP_SRC_FRGD_CLR                        0x15D8  
-#define DP_SRC_BKGD_CLR                        0x15DC  
-#define SC_LEFT                                0x1640  
-#define SC_RIGHT                               0x1644  
-#define SC_TOP                                 0x1648  
-#define SC_BOTTOM                              0x164C  
-#define SRC_SC_RIGHT                           0x1654  
-#define SRC_SC_BOTTOM                          0x165C  
-#define DP_CNTL                                0x16C0  
-#define DP_CNTL_XDIR_YDIR_YMAJOR               0x16D0  
-#define DP_DATATYPE                            0x16C4  
-#define DP_MIX                                 0x16C8  
-#define DP_WRITE_MSK                           0x16CC  
-#define DP_XOP                                 0x17F8  
+#define DP_SRC_FRGD_CLR                        0x15D8
+#define DP_SRC_BKGD_CLR                        0x15DC
+#define SC_LEFT                                0x1640
+#define SC_RIGHT                               0x1644
+#define SC_TOP                                 0x1648
+#define SC_BOTTOM                              0x164C
+#define SRC_SC_RIGHT                           0x1654
+#define SRC_SC_BOTTOM                          0x165C
+#define DP_CNTL                                0x16C0
+#define DP_CNTL_XDIR_YDIR_YMAJOR               0x16D0
+#define DP_DATATYPE                            0x16C4
+#define DP_MIX                                 0x16C8
+#define DP_WRITE_MSK                           0x16CC
+#define DP_XOP                                 0x17F8
 #define CLR_CMP_CLR_SRC                        0x15C4
 #define CLR_CMP_CLR_DST                        0x15C8
 #define CLR_CMP_CNTL                           0x15C0
-#define CLR_CMP_MSK                            0x15CC  
-#define DSTCACHE_MODE                          0x1710  
-#define DSTCACHE_CTLSTAT                       0x1714  
-#define DEFAULT_PITCH_OFFSET                   0x16E0  
-#define DEFAULT_SC_BOTTOM_RIGHT                0x16E8  
+#define CLR_CMP_MSK                            0x15CC
+#define DSTCACHE_MODE                          0x1710
+#define DSTCACHE_CTLSTAT                       0x1714
+#define DEFAULT_PITCH_OFFSET                   0x16E0
+#define DEFAULT_SC_BOTTOM_RIGHT                0x16E8
 #define DEFAULT_SC_TOP_LEFT                    0x16EC
 #define SRC_PITCH_OFFSET                       0x1428
 #define DST_PITCH_OFFSET                       0x142C
-#define DP_GUI_MASTER_CNTL                     0x146C  
-#define SC_TOP_LEFT                            0x16EC  
-#define SC_BOTTOM_RIGHT                        0x16F0  
-#define SRC_SC_BOTTOM_RIGHT                    0x16F4  
+#define DP_GUI_MASTER_CNTL                     0x146C
+#define SC_TOP_LEFT                            0x16EC
+#define SC_BOTTOM_RIGHT                        0x16F0
+#define SRC_SC_BOTTOM_RIGHT                    0x16F4
 #define RB2D_DSTCACHE_MODE                    0x3428
 #define RB2D_DSTCACHE_CTLSTAT_broken          0x342C /* do not use */
 #define LVDS_GEN_CNTL                         0x02d0
 #define VERT_FP_LOOP_STRETCH                      (0x7 << 28)
 #define VERT_STRETCH_RESERVED                     0xf1000000
 
-/* DAC_CNTL bit constants */   
+/* DAC_CNTL bit constants */
 #define DAC_8BIT_EN                                0x00000100
 #define DAC_4BPP_PIX_ORDER                         0x00000200
 #define DAC_CRC_EN                                 0x00080000
 #define DAC_CMP_EN                                 (1 <<  3)
 #define DAC_CMP_OUTPUT                             (1 <<  7)
 
-/* DAC_CNTL2 bit constants */   
+/* DAC_CNTL2 bit constants */
 #define DAC2_EXPAND_MODE                          (1 << 14)
 #define DAC2_CMP_EN                                (1 << 7)
 #define DAC2_PALETTE_ACCESS_CNTL                   (1 << 5)
index fe41b84079460033618a0598fa424aefc6c55576..c3b2a2aa7140afed4251baabb45a1671fe16ccc7 100644 (file)
 #define        S1D13XXXFB_H
 
 #define S1D_PALETTE_SIZE               256
-#define S1D13506_CHIP_REV              4       /* expected chip revision number for s1d13506 */
-#define S1D13806_CHIP_REV              7       /* expected chip revision number for s1d13806 */
-#define S1D_FBID                       "S1D13806"
-#define S1D_DEVICENAME                 "s1d13806fb"
+#define S1D_FBID                       "S1D13xxx"
+#define S1D_DEVICENAME                 "s1d13xxxfb"
+
+/* S1DREG_REV_CODE register = prod_id (6 bits) + revision (2 bits) */
+#define S1D13505_PROD_ID               0x3     /* 000011 */
+#define S1D13506_PROD_ID               0x4     /* 000100 */
+#define S1D13806_PROD_ID               0x7     /* 000111 */
 
 /* register definitions (tested on s1d13896) */
-#define S1DREG_REV_CODE                        0x0000  /* Revision Code Register */
+#define S1DREG_REV_CODE                        0x0000  /* Prod + Rev Code Register */
 #define S1DREG_MISC                    0x0001  /* Miscellaneous Register */
 #define S1DREG_GPIO_CNF0               0x0004  /* General IO Pins Configuration Register 0 */
 #define S1DREG_GPIO_CNF1               0x0005  /* General IO Pins Configuration Register 1 */
@@ -141,10 +144,11 @@ struct s1d13xxxfb_regval {
        u8      value;
 };
 
-
 struct s1d13xxxfb_par {
        void __iomem    *regs;
        unsigned char   display;
+       unsigned char   prod_id;
+       unsigned char   revision;
 
        unsigned int    pseudo_palette[16];
 #ifdef CONFIG_PM
index 14c483d2b7c90b4a5713b6ed116fa16260f1228d..1398a14b01919d500c59367ff5cffd61d9f39cad 100644 (file)
@@ -531,7 +531,7 @@ config CGROUP_DEVICE
 
 config CPUSETS
        bool "Cpuset support"
-       depends on SMP && CGROUPS
+       depends on CGROUPS
        help
          This option will let you create and manage CPUSETs which
          allow dynamically partitioning a system into sets of CPUs and
@@ -597,6 +597,8 @@ config CGROUP_MEM_RES_CTLR_SWAP
          is disabled by boot option, this will be automatically disabled and
          there will be no overhead from this. Even when you set this config=y,
          if boot option "noswapaccount" is set, swap will not be accounted.
+         Now, memory usage of swap_cgroup is 2 bytes per entry. If swap page
+         size is 4096bytes, 512k per 1Gbytes of swap.
 
 endif # CGROUPS
 
index 619c1baf7701e8b6c8b42f07ca3f3521f4b5b97d..80cd713f6cc5cc8b3f09317534acebdf4983903a 100644 (file)
@@ -571,11 +571,11 @@ static int __init populate_rootfs(void)
        if (initrd_start) {
 #ifdef CONFIG_BLK_DEV_RAM
                int fd;
-               printk(KERN_INFO "checking if image is initramfs...");
+               printk(KERN_INFO "checking if image is initramfs...\n");
                err = unpack_to_rootfs((char *)initrd_start,
                        initrd_end - initrd_start);
                if (!err) {
-                       printk(" it is\n");
+                       printk(KERN_INFO "rootfs image is initramfs; unpacking...\n");
                        free_initrd();
                        return 0;
                } else {
@@ -583,7 +583,8 @@ static int __init populate_rootfs(void)
                        unpack_to_rootfs(__initramfs_start,
                                 __initramfs_end - __initramfs_start);
                }
-               printk("it isn't (%s); looks like an initrd\n", err);
+               printk(KERN_INFO "rootfs image is not initramfs (%s)"
+                               "; looks like an initrd\n", err);
                fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);
                if (fd >= 0) {
                        sys_write(fd, (char *)initrd_start,
index 6bf83afd654da44b5b52383a4697d4d98e0ff6fa..07c8658ffca54d1cb6da86a12b9f7512575590c0 100644 (file)
@@ -407,8 +407,7 @@ static void __init smp_init(void)
         * Set up the current CPU as possible to migrate to.
         * The other ones will be done by cpu_up/cpu_down()
         */
-       cpu = smp_processor_id();
-       cpu_set(cpu, cpu_active_map);
+       set_cpu_active(smp_processor_id(), true);
 
        /* FIXME: This should be done in userspace --RR */
        for_each_present_cpu(cpu) {
@@ -794,6 +793,7 @@ static void run_init_process(char *init_filename)
  * makes it inline to init() and it becomes part of init.text section
  */
 static noinline int init_post(void)
+       __releases(kernel_lock)
 {
        /* need to finish all async __init code before freeing the memory */
        async_synchronize_full();
@@ -842,7 +842,7 @@ static int __init kernel_init(void * unused)
        /*
         * init can run on any cpu.
         */
-       set_cpus_allowed_ptr(current, CPU_MASK_ALL_PTR);
+       set_cpus_allowed_ptr(current, cpu_all_mask);
        /*
         * Tell the world that we're going to be the grim
         * reaper of innocent orphaned children.
index 4a7a12c95abeff95f5f50838ad8f6bf9da1262b1..40eab7314aeb6c38fcef65ea58cea52421e646ff 100644 (file)
@@ -26,7 +26,7 @@ static void *get_ipc(ctl_table *table)
        return which;
 }
 
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_PROC_SYSCTL
 static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp,
        void __user *buffer, size_t *lenp, loff_t *ppos)
 {
index f239d87e0d37eea4a83106804035432f6c91c331..faa46da99ebed7884ebb632f70ec7d79799d7f87 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -555,12 +555,14 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
        in_use = shm_ids(ns).in_use;
 
        for (total = 0, next_id = 0; total < in_use; next_id++) {
+               struct kern_ipc_perm *ipc;
                struct shmid_kernel *shp;
                struct inode *inode;
 
-               shp = idr_find(&shm_ids(ns).ipcs_idr, next_id);
-               if (shp == NULL)
+               ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id);
+               if (ipc == NULL)
                        continue;
+               shp = container_of(ipc, struct shmid_kernel, shm_perm);
 
                inode = shp->shm_file->f_path.dentry->d_inode;
 
index c500ca7239b21a465831e2b3f0454f14505ff3e9..382109b5baebc2a79d31f041ceb51babd1474c95 100644 (file)
@@ -94,7 +94,6 @@ struct cgroupfs_root {
        char release_agent_path[PATH_MAX];
 };
 
-
 /*
  * The "rootnode" hierarchy is the "dummy hierarchy", reserved for the
  * subsystems that are otherwise unattached - it never has more than a
@@ -102,6 +101,39 @@ struct cgroupfs_root {
  */
 static struct cgroupfs_root rootnode;
 
+/*
+ * CSS ID -- ID per subsys's Cgroup Subsys State(CSS). used only when
+ * cgroup_subsys->use_id != 0.
+ */
+#define CSS_ID_MAX     (65535)
+struct css_id {
+       /*
+        * The css to which this ID points. This pointer is set to valid value
+        * after cgroup is populated. If cgroup is removed, this will be NULL.
+        * This pointer is expected to be RCU-safe because destroy()
+        * is called after synchronize_rcu(). But for safe use, css_is_removed()
+        * css_tryget() should be used for avoiding race.
+        */
+       struct cgroup_subsys_state *css;
+       /*
+        * ID of this css.
+        */
+       unsigned short id;
+       /*
+        * Depth in hierarchy which this ID belongs to.
+        */
+       unsigned short depth;
+       /*
+        * ID is freed by RCU. (and lookup routine is RCU safe.)
+        */
+       struct rcu_head rcu_head;
+       /*
+        * Hierarchy of CSS ID belongs to.
+        */
+       unsigned short stack[0]; /* Array of Length (depth+1) */
+};
+
+
 /* The list of hierarchy roots */
 
 static LIST_HEAD(roots);
@@ -185,6 +217,8 @@ struct cg_cgroup_link {
 static struct css_set init_css_set;
 static struct cg_cgroup_link init_css_set_link;
 
+static int cgroup_subsys_init_idr(struct cgroup_subsys *ss);
+
 /* css_set_lock protects the list of css_set objects, and the
  * chain of tasks off each css_set.  Nests outside task->alloc_lock
  * due to cgroup_iter_start() */
@@ -567,6 +601,9 @@ static struct backing_dev_info cgroup_backing_dev_info = {
        .capabilities   = BDI_CAP_NO_ACCT_AND_WRITEBACK,
 };
 
+static int alloc_css_id(struct cgroup_subsys *ss,
+                       struct cgroup *parent, struct cgroup *child);
+
 static struct inode *cgroup_new_inode(mode_t mode, struct super_block *sb)
 {
        struct inode *inode = new_inode(sb);
@@ -585,13 +622,18 @@ static struct inode *cgroup_new_inode(mode_t mode, struct super_block *sb)
  * Call subsys's pre_destroy handler.
  * This is called before css refcnt check.
  */
-static void cgroup_call_pre_destroy(struct cgroup *cgrp)
+static int cgroup_call_pre_destroy(struct cgroup *cgrp)
 {
        struct cgroup_subsys *ss;
+       int ret = 0;
+
        for_each_subsys(cgrp->root, ss)
-               if (ss->pre_destroy)
-                       ss->pre_destroy(ss, cgrp);
-       return;
+               if (ss->pre_destroy) {
+                       ret = ss->pre_destroy(ss, cgrp);
+                       if (ret)
+                               break;
+               }
+       return ret;
 }
 
 static void free_cgroup_rcu(struct rcu_head *obj)
@@ -685,6 +727,22 @@ static void cgroup_d_remove_dir(struct dentry *dentry)
        remove_dir(dentry);
 }
 
+/*
+ * A queue for waiters to do rmdir() cgroup. A tasks will sleep when
+ * cgroup->count == 0 && list_empty(&cgroup->children) && subsys has some
+ * reference to css->refcnt. In general, this refcnt is expected to goes down
+ * to zero, soon.
+ *
+ * CGRP_WAIT_ON_RMDIR flag is modified under cgroup's inode->i_mutex;
+ */
+DECLARE_WAIT_QUEUE_HEAD(cgroup_rmdir_waitq);
+
+static void cgroup_wakeup_rmdir_waiters(const struct cgroup *cgrp)
+{
+       if (unlikely(test_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags)))
+               wake_up_all(&cgroup_rmdir_waitq);
+}
+
 static int rebind_subsystems(struct cgroupfs_root *root,
                              unsigned long final_bits)
 {
@@ -857,16 +915,16 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data)
        }
 
        ret = rebind_subsystems(root, opts.subsys_bits);
+       if (ret)
+               goto out_unlock;
 
        /* (re)populate subsystem files */
-       if (!ret)
-               cgroup_populate_dir(cgrp);
+       cgroup_populate_dir(cgrp);
 
        if (opts.release_agent)
                strcpy(root->release_agent_path, opts.release_agent);
  out_unlock:
-       if (opts.release_agent)
-               kfree(opts.release_agent);
+       kfree(opts.release_agent);
        mutex_unlock(&cgroup_mutex);
        mutex_unlock(&cgrp->dentry->d_inode->i_mutex);
        return ret;
@@ -969,15 +1027,13 @@ static int cgroup_get_sb(struct file_system_type *fs_type,
        /* First find the desired set of subsystems */
        ret = parse_cgroupfs_options(data, &opts);
        if (ret) {
-               if (opts.release_agent)
-                       kfree(opts.release_agent);
+               kfree(opts.release_agent);
                return ret;
        }
 
        root = kzalloc(sizeof(*root), GFP_KERNEL);
        if (!root) {
-               if (opts.release_agent)
-                       kfree(opts.release_agent);
+               kfree(opts.release_agent);
                return -ENOMEM;
        }
 
@@ -1280,6 +1336,12 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
        set_bit(CGRP_RELEASABLE, &oldcgrp->flags);
        synchronize_rcu();
        put_css_set(cg);
+
+       /*
+        * wake up rmdir() waiter. the rmdir should fail since the cgroup
+        * is no longer empty.
+        */
+       cgroup_wakeup_rmdir_waiters(cgrp);
        return 0;
 }
 
@@ -1625,7 +1687,7 @@ static struct inode_operations cgroup_dir_inode_operations = {
        .rename = cgroup_rename,
 };
 
-static int cgroup_create_file(struct dentry *dentry, int mode,
+static int cgroup_create_file(struct dentry *dentry, mode_t mode,
                                struct super_block *sb)
 {
        static const struct dentry_operations cgroup_dops = {
@@ -1671,7 +1733,7 @@ static int cgroup_create_file(struct dentry *dentry, int mode,
  * @mode: mode to set on new directory.
  */
 static int cgroup_create_dir(struct cgroup *cgrp, struct dentry *dentry,
-                               int mode)
+                               mode_t mode)
 {
        struct dentry *parent;
        int error = 0;
@@ -1689,6 +1751,33 @@ static int cgroup_create_dir(struct cgroup *cgrp, struct dentry *dentry,
        return error;
 }
 
+/**
+ * cgroup_file_mode - deduce file mode of a control file
+ * @cft: the control file in question
+ *
+ * returns cft->mode if ->mode is not 0
+ * returns S_IRUGO|S_IWUSR if it has both a read and a write handler
+ * returns S_IRUGO if it has only a read handler
+ * returns S_IWUSR if it has only a write hander
+ */
+static mode_t cgroup_file_mode(const struct cftype *cft)
+{
+       mode_t mode = 0;
+
+       if (cft->mode)
+               return cft->mode;
+
+       if (cft->read || cft->read_u64 || cft->read_s64 ||
+           cft->read_map || cft->read_seq_string)
+               mode |= S_IRUGO;
+
+       if (cft->write || cft->write_u64 || cft->write_s64 ||
+           cft->write_string || cft->trigger)
+               mode |= S_IWUSR;
+
+       return mode;
+}
+
 int cgroup_add_file(struct cgroup *cgrp,
                       struct cgroup_subsys *subsys,
                       const struct cftype *cft)
@@ -1696,6 +1785,7 @@ int cgroup_add_file(struct cgroup *cgrp,
        struct dentry *dir = cgrp->dentry;
        struct dentry *dentry;
        int error;
+       mode_t mode;
 
        char name[MAX_CGROUP_TYPE_NAMELEN + MAX_CFTYPE_NAME + 2] = { 0 };
        if (subsys && !test_bit(ROOT_NOPREFIX, &cgrp->root->flags)) {
@@ -1706,7 +1796,8 @@ int cgroup_add_file(struct cgroup *cgrp,
        BUG_ON(!mutex_is_locked(&dir->d_inode->i_mutex));
        dentry = lookup_one_len(name, dir, strlen(name));
        if (!IS_ERR(dentry)) {
-               error = cgroup_create_file(dentry, 0644 | S_IFREG,
+               mode = cgroup_file_mode(cft);
+               error = cgroup_create_file(dentry, mode | S_IFREG,
                                                cgrp->root->sb);
                if (!error)
                        dentry->d_fsdata = (void *)cft;
@@ -2288,6 +2379,7 @@ static struct cftype files[] = {
                .write_u64 = cgroup_tasks_write,
                .release = cgroup_tasks_release,
                .private = FILE_TASKLIST,
+               .mode = S_IRUGO | S_IWUSR,
        },
 
        {
@@ -2327,6 +2419,17 @@ static int cgroup_populate_dir(struct cgroup *cgrp)
                if (ss->populate && (err = ss->populate(ss, cgrp)) < 0)
                        return err;
        }
+       /* This cgroup is ready now */
+       for_each_subsys(cgrp->root, ss) {
+               struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
+               /*
+                * Update id->css pointer and make this css visible from
+                * CSS ID functions. This pointer will be dereferened
+                * from RCU-read-side without locks.
+                */
+               if (css->id)
+                       rcu_assign_pointer(css->id->css, css);
+       }
 
        return 0;
 }
@@ -2338,6 +2441,7 @@ static void init_cgroup_css(struct cgroup_subsys_state *css,
        css->cgroup = cgrp;
        atomic_set(&css->refcnt, 1);
        css->flags = 0;
+       css->id = NULL;
        if (cgrp == dummytop)
                set_bit(CSS_ROOT, &css->flags);
        BUG_ON(cgrp->subsys[ss->subsys_id]);
@@ -2376,7 +2480,7 @@ static void cgroup_unlock_hierarchy(struct cgroupfs_root *root)
  * Must be called with the mutex on the parent inode held
  */
 static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
-                            int mode)
+                            mode_t mode)
 {
        struct cgroup *cgrp;
        struct cgroupfs_root *root = parent->root;
@@ -2413,6 +2517,10 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
                        goto err_destroy;
                }
                init_cgroup_css(css, ss, cgrp);
+               if (ss->use_id)
+                       if (alloc_css_id(ss, parent, cgrp))
+                               goto err_destroy;
+               /* At error, ->destroy() callback has to free assigned ID. */
        }
 
        cgroup_lock_hierarchy(root);
@@ -2555,9 +2663,11 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
        struct cgroup *cgrp = dentry->d_fsdata;
        struct dentry *d;
        struct cgroup *parent;
+       DEFINE_WAIT(wait);
+       int ret;
 
        /* the vfs holds both inode->i_mutex already */
-
+again:
        mutex_lock(&cgroup_mutex);
        if (atomic_read(&cgrp->count) != 0) {
                mutex_unlock(&cgroup_mutex);
@@ -2573,17 +2683,39 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
         * Call pre_destroy handlers of subsys. Notify subsystems
         * that rmdir() request comes.
         */
-       cgroup_call_pre_destroy(cgrp);
+       ret = cgroup_call_pre_destroy(cgrp);
+       if (ret)
+               return ret;
 
        mutex_lock(&cgroup_mutex);
        parent = cgrp->parent;
-
-       if (atomic_read(&cgrp->count)
-           || !list_empty(&cgrp->children)
-           || !cgroup_clear_css_refs(cgrp)) {
+       if (atomic_read(&cgrp->count) || !list_empty(&cgrp->children)) {
                mutex_unlock(&cgroup_mutex);
                return -EBUSY;
        }
+       /*
+        * css_put/get is provided for subsys to grab refcnt to css. In typical
+        * case, subsystem has no reference after pre_destroy(). But, under
+        * hierarchy management, some *temporal* refcnt can be hold.
+        * To avoid returning -EBUSY to a user, waitqueue is used. If subsys
+        * is really busy, it should return -EBUSY at pre_destroy(). wake_up
+        * is called when css_put() is called and refcnt goes down to 0.
+        */
+       set_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags);
+       prepare_to_wait(&cgroup_rmdir_waitq, &wait, TASK_INTERRUPTIBLE);
+
+       if (!cgroup_clear_css_refs(cgrp)) {
+               mutex_unlock(&cgroup_mutex);
+               schedule();
+               finish_wait(&cgroup_rmdir_waitq, &wait);
+               clear_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags);
+               if (signal_pending(current))
+                       return -EINTR;
+               goto again;
+       }
+       /* NO css_tryget() can success after here. */
+       finish_wait(&cgroup_rmdir_waitq, &wait);
+       clear_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags);
 
        spin_lock(&release_list_lock);
        set_bit(CGRP_REMOVED, &cgrp->flags);
@@ -2708,6 +2840,8 @@ int __init cgroup_init(void)
                struct cgroup_subsys *ss = subsys[i];
                if (!ss->early_init)
                        cgroup_init_subsys(ss);
+               if (ss->use_id)
+                       cgroup_subsys_init_idr(ss);
        }
 
        /* Add init_css_set to the hash table */
@@ -3084,18 +3218,19 @@ int cgroup_clone(struct task_struct *tsk, struct cgroup_subsys *subsys,
 }
 
 /**
- * cgroup_is_descendant - see if @cgrp is a descendant of current task's cgrp
+ * cgroup_is_descendant - see if @cgrp is a descendant of @task's cgrp
  * @cgrp: the cgroup in question
+ * @task: the task in question
  *
- * See if @cgrp is a descendant of the current task's cgroup in
- * the appropriate hierarchy.
+ * See if @cgrp is a descendant of @task's cgroup in the appropriate
+ * hierarchy.
  *
  * If we are sending in dummytop, then presumably we are creating
  * the top cgroup in the subsystem.
  *
  * Called only by the ns (nsproxy) cgroup.
  */
-int cgroup_is_descendant(const struct cgroup *cgrp)
+int cgroup_is_descendant(const struct cgroup *cgrp, struct task_struct *task)
 {
        int ret;
        struct cgroup *target;
@@ -3105,7 +3240,7 @@ int cgroup_is_descendant(const struct cgroup *cgrp)
                return 1;
 
        get_first_subsys(cgrp, NULL, &subsys_id);
-       target = task_cgroup(current, subsys_id);
+       target = task_cgroup(task, subsys_id);
        while (cgrp != target && cgrp!= cgrp->top_cgroup)
                cgrp = cgrp->parent;
        ret = (cgrp == target);
@@ -3138,10 +3273,12 @@ void __css_put(struct cgroup_subsys_state *css)
 {
        struct cgroup *cgrp = css->cgroup;
        rcu_read_lock();
-       if ((atomic_dec_return(&css->refcnt) == 1) &&
-           notify_on_release(cgrp)) {
-               set_bit(CGRP_RELEASABLE, &cgrp->flags);
-               check_for_release(cgrp);
+       if (atomic_dec_return(&css->refcnt) == 1) {
+               if (notify_on_release(cgrp)) {
+                       set_bit(CGRP_RELEASABLE, &cgrp->flags);
+                       check_for_release(cgrp);
+               }
+               cgroup_wakeup_rmdir_waiters(cgrp);
        }
        rcu_read_unlock();
 }
@@ -3241,3 +3378,232 @@ static int __init cgroup_disable(char *str)
        return 1;
 }
 __setup("cgroup_disable=", cgroup_disable);
+
+/*
+ * Functons for CSS ID.
+ */
+
+/*
+ *To get ID other than 0, this should be called when !cgroup_is_removed().
+ */
+unsigned short css_id(struct cgroup_subsys_state *css)
+{
+       struct css_id *cssid = rcu_dereference(css->id);
+
+       if (cssid)
+               return cssid->id;
+       return 0;
+}
+
+unsigned short css_depth(struct cgroup_subsys_state *css)
+{
+       struct css_id *cssid = rcu_dereference(css->id);
+
+       if (cssid)
+               return cssid->depth;
+       return 0;
+}
+
+bool css_is_ancestor(struct cgroup_subsys_state *child,
+                   const struct cgroup_subsys_state *root)
+{
+       struct css_id *child_id = rcu_dereference(child->id);
+       struct css_id *root_id = rcu_dereference(root->id);
+
+       if (!child_id || !root_id || (child_id->depth < root_id->depth))
+               return false;
+       return child_id->stack[root_id->depth] == root_id->id;
+}
+
+static void __free_css_id_cb(struct rcu_head *head)
+{
+       struct css_id *id;
+
+       id = container_of(head, struct css_id, rcu_head);
+       kfree(id);
+}
+
+void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css)
+{
+       struct css_id *id = css->id;
+       /* When this is called before css_id initialization, id can be NULL */
+       if (!id)
+               return;
+
+       BUG_ON(!ss->use_id);
+
+       rcu_assign_pointer(id->css, NULL);
+       rcu_assign_pointer(css->id, NULL);
+       spin_lock(&ss->id_lock);
+       idr_remove(&ss->idr, id->id);
+       spin_unlock(&ss->id_lock);
+       call_rcu(&id->rcu_head, __free_css_id_cb);
+}
+
+/*
+ * This is called by init or create(). Then, calls to this function are
+ * always serialized (By cgroup_mutex() at create()).
+ */
+
+static struct css_id *get_new_cssid(struct cgroup_subsys *ss, int depth)
+{
+       struct css_id *newid;
+       int myid, error, size;
+
+       BUG_ON(!ss->use_id);
+
+       size = sizeof(*newid) + sizeof(unsigned short) * (depth + 1);
+       newid = kzalloc(size, GFP_KERNEL);
+       if (!newid)
+               return ERR_PTR(-ENOMEM);
+       /* get id */
+       if (unlikely(!idr_pre_get(&ss->idr, GFP_KERNEL))) {
+               error = -ENOMEM;
+               goto err_out;
+       }
+       spin_lock(&ss->id_lock);
+       /* Don't use 0. allocates an ID of 1-65535 */
+       error = idr_get_new_above(&ss->idr, newid, 1, &myid);
+       spin_unlock(&ss->id_lock);
+
+       /* Returns error when there are no free spaces for new ID.*/
+       if (error) {
+               error = -ENOSPC;
+               goto err_out;
+       }
+       if (myid > CSS_ID_MAX)
+               goto remove_idr;
+
+       newid->id = myid;
+       newid->depth = depth;
+       return newid;
+remove_idr:
+       error = -ENOSPC;
+       spin_lock(&ss->id_lock);
+       idr_remove(&ss->idr, myid);
+       spin_unlock(&ss->id_lock);
+err_out:
+       kfree(newid);
+       return ERR_PTR(error);
+
+}
+
+static int __init cgroup_subsys_init_idr(struct cgroup_subsys *ss)
+{
+       struct css_id *newid;
+       struct cgroup_subsys_state *rootcss;
+
+       spin_lock_init(&ss->id_lock);
+       idr_init(&ss->idr);
+
+       rootcss = init_css_set.subsys[ss->subsys_id];
+       newid = get_new_cssid(ss, 0);
+       if (IS_ERR(newid))
+               return PTR_ERR(newid);
+
+       newid->stack[0] = newid->id;
+       newid->css = rootcss;
+       rootcss->id = newid;
+       return 0;
+}
+
+static int alloc_css_id(struct cgroup_subsys *ss, struct cgroup *parent,
+                       struct cgroup *child)
+{
+       int subsys_id, i, depth = 0;
+       struct cgroup_subsys_state *parent_css, *child_css;
+       struct css_id *child_id, *parent_id = NULL;
+
+       subsys_id = ss->subsys_id;
+       parent_css = parent->subsys[subsys_id];
+       child_css = child->subsys[subsys_id];
+       depth = css_depth(parent_css) + 1;
+       parent_id = parent_css->id;
+
+       child_id = get_new_cssid(ss, depth);
+       if (IS_ERR(child_id))
+               return PTR_ERR(child_id);
+
+       for (i = 0; i < depth; i++)
+               child_id->stack[i] = parent_id->stack[i];
+       child_id->stack[depth] = child_id->id;
+       /*
+        * child_id->css pointer will be set after this cgroup is available
+        * see cgroup_populate_dir()
+        */
+       rcu_assign_pointer(child_css->id, child_id);
+
+       return 0;
+}
+
+/**
+ * css_lookup - lookup css by id
+ * @ss: cgroup subsys to be looked into.
+ * @id: the id
+ *
+ * Returns pointer to cgroup_subsys_state if there is valid one with id.
+ * NULL if not. Should be called under rcu_read_lock()
+ */
+struct cgroup_subsys_state *css_lookup(struct cgroup_subsys *ss, int id)
+{
+       struct css_id *cssid = NULL;
+
+       BUG_ON(!ss->use_id);
+       cssid = idr_find(&ss->idr, id);
+
+       if (unlikely(!cssid))
+               return NULL;
+
+       return rcu_dereference(cssid->css);
+}
+
+/**
+ * css_get_next - lookup next cgroup under specified hierarchy.
+ * @ss: pointer to subsystem
+ * @id: current position of iteration.
+ * @root: pointer to css. search tree under this.
+ * @foundid: position of found object.
+ *
+ * Search next css under the specified hierarchy of rootid. Calling under
+ * rcu_read_lock() is necessary. Returns NULL if it reaches the end.
+ */
+struct cgroup_subsys_state *
+css_get_next(struct cgroup_subsys *ss, int id,
+            struct cgroup_subsys_state *root, int *foundid)
+{
+       struct cgroup_subsys_state *ret = NULL;
+       struct css_id *tmp;
+       int tmpid;
+       int rootid = css_id(root);
+       int depth = css_depth(root);
+
+       if (!rootid)
+               return NULL;
+
+       BUG_ON(!ss->use_id);
+       /* fill start point for scan */
+       tmpid = id;
+       while (1) {
+               /*
+                * scan next entry from bitmap(tree), tmpid is updated after
+                * idr_get_next().
+                */
+               spin_lock(&ss->id_lock);
+               tmp = idr_get_next(&ss->idr, &tmpid);
+               spin_unlock(&ss->id_lock);
+
+               if (!tmp)
+                       break;
+               if (tmp->depth >= depth && tmp->stack[depth] == rootid) {
+                       ret = rcu_dereference(tmp->css);
+                       if (ret) {
+                               *foundid = tmpid;
+                               break;
+                       }
+               }
+               /* continue to scan from next id */
+               tmpid = tmpid + 1;
+       }
+       return ret;
+}
+
index daca6209202df4a84df7e0fc41025e33c7642131..0c92d797baa6d163853245481597f7fc03236da4 100644 (file)
@@ -40,9 +40,7 @@ static u64 taskcount_read(struct cgroup *cont, struct cftype *cft)
 {
        u64 count;
 
-       cgroup_lock();
        count = cgroup_task_count(cont);
-       cgroup_unlock();
        return count;
 }
 
index 79e40f00dcb89b8b3b5dedb5cc1c7da507e6b322..395b6974dc8d56ccb2d91ede756069fe9b10c975 100644 (file)
@@ -281,7 +281,7 @@ int __ref cpu_down(unsigned int cpu)
                goto out;
        }
 
-       cpu_clear(cpu, cpu_active_map);
+       set_cpu_active(cpu, false);
 
        /*
         * Make sure the all cpus did the reschedule and are not
@@ -296,7 +296,7 @@ int __ref cpu_down(unsigned int cpu)
        err = _cpu_down(cpu, 0);
 
        if (cpu_online(cpu))
-               cpu_set(cpu, cpu_active_map);
+               set_cpu_active(cpu, true);
 
 out:
        cpu_maps_update_done();
@@ -333,7 +333,7 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
                goto out_notify;
        BUG_ON(!cpu_online(cpu));
 
-       cpu_set(cpu, cpu_active_map);
+       set_cpu_active(cpu, true);
 
        /* Now call notifier in preparation. */
        raw_notifier_call_chain(&cpu_chain, CPU_ONLINE | mod, hcpu);
index f76db9dcaa05e592f3138f5389ae4c22827b58d9..026faccca869e396d378693422e29e9c82f739ac 100644 (file)
@@ -128,10 +128,6 @@ static inline struct cpuset *task_cs(struct task_struct *task)
        return container_of(task_subsys_state(task, cpuset_subsys_id),
                            struct cpuset, css);
 }
-struct cpuset_hotplug_scanner {
-       struct cgroup_scanner scan;
-       struct cgroup *to;
-};
 
 /* bits in struct cpuset flags field */
 typedef enum {
@@ -521,6 +517,7 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
        return 0;
 }
 
+#ifdef CONFIG_SMP
 /*
  * Helper routine for generate_sched_domains().
  * Do cpusets a, b have overlapping cpus_allowed masks?
@@ -815,6 +812,18 @@ static void do_rebuild_sched_domains(struct work_struct *unused)
 
        put_online_cpus();
 }
+#else /* !CONFIG_SMP */
+static void do_rebuild_sched_domains(struct work_struct *unused)
+{
+}
+
+static int generate_sched_domains(struct cpumask **domains,
+                       struct sched_domain_attr **attributes)
+{
+       *domains = NULL;
+       return 1;
+}
+#endif /* CONFIG_SMP */
 
 static DECLARE_WORK(rebuild_sched_domains_work, do_rebuild_sched_domains);
 
@@ -1026,101 +1035,70 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
        mutex_unlock(&callback_mutex);
 }
 
+/*
+ * Rebind task's vmas to cpuset's new mems_allowed, and migrate pages to new
+ * nodes if memory_migrate flag is set. Called with cgroup_mutex held.
+ */
+static void cpuset_change_nodemask(struct task_struct *p,
+                                  struct cgroup_scanner *scan)
+{
+       struct mm_struct *mm;
+       struct cpuset *cs;
+       int migrate;
+       const nodemask_t *oldmem = scan->data;
+
+       mm = get_task_mm(p);
+       if (!mm)
+               return;
+
+       cs = cgroup_cs(scan->cg);
+       migrate = is_memory_migrate(cs);
+
+       mpol_rebind_mm(mm, &cs->mems_allowed);
+       if (migrate)
+               cpuset_migrate_mm(mm, oldmem, &cs->mems_allowed);
+       mmput(mm);
+}
+
 static void *cpuset_being_rebound;
 
 /**
  * update_tasks_nodemask - Update the nodemasks of tasks in the cpuset.
  * @cs: the cpuset in which each task's mems_allowed mask needs to be changed
  * @oldmem: old mems_allowed of cpuset cs
+ * @heap: if NULL, defer allocating heap memory to cgroup_scan_tasks()
  *
  * Called with cgroup_mutex held
- * Return 0 if successful, -errno if not.
+ * No return value. It's guaranteed that cgroup_scan_tasks() always returns 0
+ * if @heap != NULL.
  */
-static int update_tasks_nodemask(struct cpuset *cs, const nodemask_t *oldmem)
+static void update_tasks_nodemask(struct cpuset *cs, const nodemask_t *oldmem,
+                                struct ptr_heap *heap)
 {
-       struct task_struct *p;
-       struct mm_struct **mmarray;
-       int i, n, ntasks;
-       int migrate;
-       int fudge;
-       struct cgroup_iter it;
-       int retval;
+       struct cgroup_scanner scan;
 
        cpuset_being_rebound = cs;              /* causes mpol_dup() rebind */
 
-       fudge = 10;                             /* spare mmarray[] slots */
-       fudge += cpumask_weight(cs->cpus_allowed);/* imagine 1 fork-bomb/cpu */
-       retval = -ENOMEM;
-
-       /*
-        * Allocate mmarray[] to hold mm reference for each task
-        * in cpuset cs.  Can't kmalloc GFP_KERNEL while holding
-        * tasklist_lock.  We could use GFP_ATOMIC, but with a
-        * few more lines of code, we can retry until we get a big
-        * enough mmarray[] w/o using GFP_ATOMIC.
-        */
-       while (1) {
-               ntasks = cgroup_task_count(cs->css.cgroup);  /* guess */
-               ntasks += fudge;
-               mmarray = kmalloc(ntasks * sizeof(*mmarray), GFP_KERNEL);
-               if (!mmarray)
-                       goto done;
-               read_lock(&tasklist_lock);              /* block fork */
-               if (cgroup_task_count(cs->css.cgroup) <= ntasks)
-                       break;                          /* got enough */
-               read_unlock(&tasklist_lock);            /* try again */
-               kfree(mmarray);
-       }
-
-       n = 0;
-
-       /* Load up mmarray[] with mm reference for each task in cpuset. */
-       cgroup_iter_start(cs->css.cgroup, &it);
-       while ((p = cgroup_iter_next(cs->css.cgroup, &it))) {
-               struct mm_struct *mm;
-
-               if (n >= ntasks) {
-                       printk(KERN_WARNING
-                               "Cpuset mempolicy rebind incomplete.\n");
-                       break;
-               }
-               mm = get_task_mm(p);
-               if (!mm)
-                       continue;
-               mmarray[n++] = mm;
-       }
-       cgroup_iter_end(cs->css.cgroup, &it);
-       read_unlock(&tasklist_lock);
+       scan.cg = cs->css.cgroup;
+       scan.test_task = NULL;
+       scan.process_task = cpuset_change_nodemask;
+       scan.heap = heap;
+       scan.data = (nodemask_t *)oldmem;
 
        /*
-        * Now that we've dropped the tasklist spinlock, we can
-        * rebind the vma mempolicies of each mm in mmarray[] to their
-        * new cpuset, and release that mm.  The mpol_rebind_mm()
-        * call takes mmap_sem, which we couldn't take while holding
-        * tasklist_lock.  Forks can happen again now - the mpol_dup()
-        * cpuset_being_rebound check will catch such forks, and rebind
-        * their vma mempolicies too.  Because we still hold the global
-        * cgroup_mutex, we know that no other rebind effort will
-        * be contending for the global variable cpuset_being_rebound.
+        * The mpol_rebind_mm() call takes mmap_sem, which we couldn't
+        * take while holding tasklist_lock.  Forks can happen - the
+        * mpol_dup() cpuset_being_rebound check will catch such forks,
+        * and rebind their vma mempolicies too.  Because we still hold
+        * the global cgroup_mutex, we know that no other rebind effort
+        * will be contending for the global variable cpuset_being_rebound.
         * It's ok if we rebind the same mm twice; mpol_rebind_mm()
         * is idempotent.  Also migrate pages in each mm to new nodes.
         */
-       migrate = is_memory_migrate(cs);
-       for (i = 0; i < n; i++) {
-               struct mm_struct *mm = mmarray[i];
-
-               mpol_rebind_mm(mm, &cs->mems_allowed);
-               if (migrate)
-                       cpuset_migrate_mm(mm, oldmem, &cs->mems_allowed);
-               mmput(mm);
-       }
+       cgroup_scan_tasks(&scan);
 
        /* We're done rebinding vmas to this cpuset's new mems_allowed. */
-       kfree(mmarray);
        cpuset_being_rebound = NULL;
-       retval = 0;
-done:
-       return retval;
 }
 
 /*
@@ -1141,6 +1119,7 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs,
 {
        nodemask_t oldmem;
        int retval;
+       struct ptr_heap heap;
 
        /*
         * top_cpuset.mems_allowed tracks node_stats[N_HIGH_MEMORY];
@@ -1175,12 +1154,18 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs,
        if (retval < 0)
                goto done;
 
+       retval = heap_init(&heap, PAGE_SIZE, GFP_KERNEL, NULL);
+       if (retval < 0)
+               goto done;
+
        mutex_lock(&callback_mutex);
        cs->mems_allowed = trialcs->mems_allowed;
        cs->mems_generation = cpuset_mems_generation++;
        mutex_unlock(&callback_mutex);
 
-       retval = update_tasks_nodemask(cs, &oldmem);
+       update_tasks_nodemask(cs, &oldmem, &heap);
+
+       heap_free(&heap);
 done:
        return retval;
 }
@@ -1192,8 +1177,10 @@ int current_cpuset_is_being_rebound(void)
 
 static int update_relax_domain_level(struct cpuset *cs, s64 val)
 {
+#ifdef CONFIG_SMP
        if (val < -1 || val >= SD_LV_MAX)
                return -EINVAL;
+#endif
 
        if (val != cs->relax_domain_level) {
                cs->relax_domain_level = val;
@@ -1355,19 +1342,22 @@ static int cpuset_can_attach(struct cgroup_subsys *ss,
                             struct cgroup *cont, struct task_struct *tsk)
 {
        struct cpuset *cs = cgroup_cs(cont);
-       int ret = 0;
 
        if (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))
                return -ENOSPC;
 
-       if (tsk->flags & PF_THREAD_BOUND) {
-               mutex_lock(&callback_mutex);
-               if (!cpumask_equal(&tsk->cpus_allowed, cs->cpus_allowed))
-                       ret = -EINVAL;
-               mutex_unlock(&callback_mutex);
-       }
+       /*
+        * Kthreads bound to specific cpus cannot be moved to a new cpuset; we
+        * cannot change their cpu affinity and isolating such threads by their
+        * set of allowed nodes is unnecessary.  Thus, cpusets are not
+        * applicable for such threads.  This prevents checking for success of
+        * set_cpus_allowed_ptr() on all attached tasks before cpus_allowed may
+        * be changed.
+        */
+       if (tsk->flags & PF_THREAD_BOUND)
+               return -EINVAL;
 
-       return ret < 0 ? ret : security_task_setscheduler(tsk, 0, NULL);
+       return security_task_setscheduler(tsk, 0, NULL);
 }
 
 static void cpuset_attach(struct cgroup_subsys *ss,
@@ -1706,6 +1696,7 @@ static struct cftype files[] = {
                .read_u64 = cpuset_read_u64,
                .write_u64 = cpuset_write_u64,
                .private = FILE_MEMORY_PRESSURE,
+               .mode = S_IRUGO,
        },
 
        {
@@ -1913,10 +1904,9 @@ int __init cpuset_init(void)
 static void cpuset_do_move_task(struct task_struct *tsk,
                                struct cgroup_scanner *scan)
 {
-       struct cpuset_hotplug_scanner *chsp;
+       struct cgroup *new_cgroup = scan->data;
 
-       chsp = container_of(scan, struct cpuset_hotplug_scanner, scan);
-       cgroup_attach_task(chsp->to, tsk);
+       cgroup_attach_task(new_cgroup, tsk);
 }
 
 /**
@@ -1932,15 +1922,15 @@ static void cpuset_do_move_task(struct task_struct *tsk,
  */
 static void move_member_tasks_to_cpuset(struct cpuset *from, struct cpuset *to)
 {
-       struct cpuset_hotplug_scanner scan;
+       struct cgroup_scanner scan;
 
-       scan.scan.cg = from->css.cgroup;
-       scan.scan.test_task = NULL; /* select all tasks in cgroup */
-       scan.scan.process_task = cpuset_do_move_task;
-       scan.scan.heap = NULL;
-       scan.to = to->css.cgroup;
+       scan.cg = from->css.cgroup;
+       scan.test_task = NULL; /* select all tasks in cgroup */
+       scan.process_task = cpuset_do_move_task;
+       scan.heap = NULL;
+       scan.data = to->css.cgroup;
 
-       if (cgroup_scan_tasks(&scan.scan))
+       if (cgroup_scan_tasks(&scan))
                printk(KERN_ERR "move_member_tasks_to_cpuset: "
                                "cgroup_scan_tasks failed\n");
 }
@@ -2033,7 +2023,7 @@ static void scan_for_empty_cpusets(struct cpuset *root)
                        remove_tasks_in_empty_cpuset(cp);
                else {
                        update_tasks_cpumask(cp, NULL);
-                       update_tasks_nodemask(cp, &oldmems);
+                       update_tasks_nodemask(cp, &oldmems, NULL);
                }
        }
 }
@@ -2069,7 +2059,9 @@ static int cpuset_track_online_cpus(struct notifier_block *unused_nb,
        }
 
        cgroup_lock();
+       mutex_lock(&callback_mutex);
        cpumask_copy(top_cpuset.cpus_allowed, cpu_online_mask);
+       mutex_unlock(&callback_mutex);
        scan_for_empty_cpusets(&top_cpuset);
        ndoms = generate_sched_domains(&doms, &attr);
        cgroup_unlock();
@@ -2092,11 +2084,12 @@ static int cpuset_track_online_nodes(struct notifier_block *self,
        cgroup_lock();
        switch (action) {
        case MEM_ONLINE:
-               top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
-               break;
        case MEM_OFFLINE:
+               mutex_lock(&callback_mutex);
                top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
-               scan_for_empty_cpusets(&top_cpuset);
+               mutex_unlock(&callback_mutex);
+               if (action == MEM_OFFLINE)
+                       scan_for_empty_cpusets(&top_cpuset);
                break;
        default:
                break;
@@ -2206,26 +2199,24 @@ static const struct cpuset *nearest_hardwall_ancestor(const struct cpuset *cs)
 }
 
 /**
- * cpuset_zone_allowed_softwall - Can we allocate on zone z's memory node?
- * @z: is this zone on an allowed node?
+ * cpuset_node_allowed_softwall - Can we allocate on a memory node?
+ * @node: is this an allowed node?
  * @gfp_mask: memory allocation flags
  *
- * If we're in interrupt, yes, we can always allocate.  If
- * __GFP_THISNODE is set, yes, we can always allocate.  If zone
- * z's node is in our tasks mems_allowed, yes.  If it's not a
- * __GFP_HARDWALL request and this zone's nodes is in the nearest
- * hardwalled cpuset ancestor to this tasks cpuset, yes.
- * If the task has been OOM killed and has access to memory reserves
- * as specified by the TIF_MEMDIE flag, yes.
+ * If we're in interrupt, yes, we can always allocate.  If __GFP_THISNODE is
+ * set, yes, we can always allocate.  If node is in our task's mems_allowed,
+ * yes.  If it's not a __GFP_HARDWALL request and this node is in the nearest
+ * hardwalled cpuset ancestor to this task's cpuset, yes.  If the task has been
+ * OOM killed and has access to memory reserves as specified by the TIF_MEMDIE
+ * flag, yes.
  * Otherwise, no.
  *
- * If __GFP_HARDWALL is set, cpuset_zone_allowed_softwall()
- * reduces to cpuset_zone_allowed_hardwall().  Otherwise,
- * cpuset_zone_allowed_softwall() might sleep, and might allow a zone
- * from an enclosing cpuset.
+ * If __GFP_HARDWALL is set, cpuset_node_allowed_softwall() reduces to
+ * cpuset_node_allowed_hardwall().  Otherwise, cpuset_node_allowed_softwall()
+ * might sleep, and might allow a node from an enclosing cpuset.
  *
- * cpuset_zone_allowed_hardwall() only handles the simpler case of
- * hardwall cpusets, and never sleeps.
+ * cpuset_node_allowed_hardwall() only handles the simpler case of hardwall
+ * cpusets, and never sleeps.
  *
  * The __GFP_THISNODE placement logic is really handled elsewhere,
  * by forcibly using a zonelist starting at a specified node, and by
@@ -2264,20 +2255,17 @@ static const struct cpuset *nearest_hardwall_ancestor(const struct cpuset *cs)
  *     GFP_USER     - only nodes in current tasks mems allowed ok.
  *
  * Rule:
- *    Don't call cpuset_zone_allowed_softwall if you can't sleep, unless you
+ *    Don't call cpuset_node_allowed_softwall if you can't sleep, unless you
  *    pass in the __GFP_HARDWALL flag set in gfp_flag, which disables
  *    the code that might scan up ancestor cpusets and sleep.
  */
-
-int __cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
+int __cpuset_node_allowed_softwall(int node, gfp_t gfp_mask)
 {
-       int node;                       /* node that zone z is on */
        const struct cpuset *cs;        /* current cpuset ancestors */
        int allowed;                    /* is allocation in zone z allowed? */
 
        if (in_interrupt() || (gfp_mask & __GFP_THISNODE))
                return 1;
-       node = zone_to_nid(z);
        might_sleep_if(!(gfp_mask & __GFP_HARDWALL));
        if (node_isset(node, current->mems_allowed))
                return 1;
@@ -2306,15 +2294,15 @@ int __cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
 }
 
 /*
- * cpuset_zone_allowed_hardwall - Can we allocate on zone z's memory node?
- * @z: is this zone on an allowed node?
+ * cpuset_node_allowed_hardwall - Can we allocate on a memory node?
+ * @node: is this an allowed node?
  * @gfp_mask: memory allocation flags
  *
- * If we're in interrupt, yes, we can always allocate.
- * If __GFP_THISNODE is set, yes, we can always allocate.  If zone
- * z's node is in our tasks mems_allowed, yes.   If the task has been
- * OOM killed and has access to memory reserves as specified by the
- * TIF_MEMDIE flag, yes.  Otherwise, no.
+ * If we're in interrupt, yes, we can always allocate.  If __GFP_THISNODE is
+ * set, yes, we can always allocate.  If node is in our task's mems_allowed,
+ * yes.  If the task has been OOM killed and has access to memory reserves as
+ * specified by the TIF_MEMDIE flag, yes.
+ * Otherwise, no.
  *
  * The __GFP_THISNODE placement logic is really handled elsewhere,
  * by forcibly using a zonelist starting at a specified node, and by
@@ -2322,20 +2310,16 @@ int __cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
  * any node on the zonelist except the first.  By the time any such
  * calls get to this routine, we should just shut up and say 'yes'.
  *
- * Unlike the cpuset_zone_allowed_softwall() variant, above,
- * this variant requires that the zone be in the current tasks
+ * Unlike the cpuset_node_allowed_softwall() variant, above,
+ * this variant requires that the node be in the current task's
  * mems_allowed or that we're in interrupt.  It does not scan up the
  * cpuset hierarchy for the nearest enclosing mem_exclusive cpuset.
  * It never sleeps.
  */
-
-int __cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask)
+int __cpuset_node_allowed_hardwall(int node, gfp_t gfp_mask)
 {
-       int node;                       /* node that zone z is on */
-
        if (in_interrupt() || (gfp_mask & __GFP_THISNODE))
                return 1;
-       node = zone_to_nid(z);
        if (node_isset(node, current->mems_allowed))
                return 1;
        /*
index 167e1e3ad7c61f5c0a73db9dc457c30a97527a91..3bec141c82f690b0ecb0cf1678c7a964e04c8521 100644 (file)
@@ -61,11 +61,6 @@ DEFINE_TRACE(sched_process_wait);
 
 static void exit_mm(struct task_struct * tsk);
 
-static inline int task_detached(struct task_struct *p)
-{
-       return p->exit_signal == -1;
-}
-
 static void __unhash_process(struct task_struct *p)
 {
        nr_threads--;
@@ -362,16 +357,12 @@ static void reparent_to_kthreadd(void)
 void __set_special_pids(struct pid *pid)
 {
        struct task_struct *curr = current->group_leader;
-       pid_t nr = pid_nr(pid);
 
-       if (task_session(curr) != pid) {
+       if (task_session(curr) != pid)
                change_pid(curr, PIDTYPE_SID, pid);
-               set_task_session(curr, nr);
-       }
-       if (task_pgrp(curr) != pid) {
+
+       if (task_pgrp(curr) != pid)
                change_pid(curr, PIDTYPE_PGID, pid);
-               set_task_pgrp(curr, nr);
-       }
 }
 
 static void set_special_pids(struct pid *pid)
@@ -731,119 +722,6 @@ static void exit_mm(struct task_struct * tsk)
        mmput(mm);
 }
 
-/*
- * Return nonzero if @parent's children should reap themselves.
- *
- * Called with write_lock_irq(&tasklist_lock) held.
- */
-static int ignoring_children(struct task_struct *parent)
-{
-       int ret;
-       struct sighand_struct *psig = parent->sighand;
-       unsigned long flags;
-       spin_lock_irqsave(&psig->siglock, flags);
-       ret = (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN ||
-              (psig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT));
-       spin_unlock_irqrestore(&psig->siglock, flags);
-       return ret;
-}
-
-/*
- * Detach all tasks we were using ptrace on.
- * Any that need to be release_task'd are put on the @dead list.
- *
- * Called with write_lock(&tasklist_lock) held.
- */
-static void ptrace_exit(struct task_struct *parent, struct list_head *dead)
-{
-       struct task_struct *p, *n;
-       int ign = -1;
-
-       list_for_each_entry_safe(p, n, &parent->ptraced, ptrace_entry) {
-               __ptrace_unlink(p);
-
-               if (p->exit_state != EXIT_ZOMBIE)
-                       continue;
-
-               /*
-                * If it's a zombie, our attachedness prevented normal
-                * parent notification or self-reaping.  Do notification
-                * now if it would have happened earlier.  If it should
-                * reap itself, add it to the @dead list.  We can't call
-                * release_task() here because we already hold tasklist_lock.
-                *
-                * If it's our own child, there is no notification to do.
-                * But if our normal children self-reap, then this child
-                * was prevented by ptrace and we must reap it now.
-                */
-               if (!task_detached(p) && thread_group_empty(p)) {
-                       if (!same_thread_group(p->real_parent, parent))
-                               do_notify_parent(p, p->exit_signal);
-                       else {
-                               if (ign < 0)
-                                       ign = ignoring_children(parent);
-                               if (ign)
-                                       p->exit_signal = -1;
-                       }
-               }
-
-               if (task_detached(p)) {
-                       /*
-                        * Mark it as in the process of being reaped.
-                        */
-                       p->exit_state = EXIT_DEAD;
-                       list_add(&p->ptrace_entry, dead);
-               }
-       }
-}
-
-/*
- * Finish up exit-time ptrace cleanup.
- *
- * Called without locks.
- */
-static void ptrace_exit_finish(struct task_struct *parent,
-                              struct list_head *dead)
-{
-       struct task_struct *p, *n;
-
-       BUG_ON(!list_empty(&parent->ptraced));
-
-       list_for_each_entry_safe(p, n, dead, ptrace_entry) {
-               list_del_init(&p->ptrace_entry);
-               release_task(p);
-       }
-}
-
-static void reparent_thread(struct task_struct *p, struct task_struct *father)
-{
-       if (p->pdeath_signal)
-               /* We already hold the tasklist_lock here.  */
-               group_send_sig_info(p->pdeath_signal, SEND_SIG_NOINFO, p);
-
-       list_move_tail(&p->sibling, &p->real_parent->children);
-
-       /* If this is a threaded reparent there is no need to
-        * notify anyone anything has happened.
-        */
-       if (same_thread_group(p->real_parent, father))
-               return;
-
-       /* We don't want people slaying init.  */
-       if (!task_detached(p))
-               p->exit_signal = SIGCHLD;
-
-       /* If we'd notified the old parent about this child's death,
-        * also notify the new parent.
-        */
-       if (!ptrace_reparented(p) &&
-           p->exit_state == EXIT_ZOMBIE &&
-           !task_detached(p) && thread_group_empty(p))
-               do_notify_parent(p, p->exit_signal);
-
-       kill_orphaned_pgrp(p, father);
-}
-
 /*
  * When we die, we re-parent all our children.
  * Try to give them to another thread in our thread
@@ -883,17 +761,51 @@ static struct task_struct *find_new_reaper(struct task_struct *father)
        return pid_ns->child_reaper;
 }
 
+/*
+* Any that need to be release_task'd are put on the @dead list.
+ */
+static void reparent_thread(struct task_struct *father, struct task_struct *p,
+                               struct list_head *dead)
+{
+       if (p->pdeath_signal)
+               group_send_sig_info(p->pdeath_signal, SEND_SIG_NOINFO, p);
+
+       list_move_tail(&p->sibling, &p->real_parent->children);
+
+       if (task_detached(p))
+               return;
+       /*
+        * If this is a threaded reparent there is no need to
+        * notify anyone anything has happened.
+        */
+       if (same_thread_group(p->real_parent, father))
+               return;
+
+       /* We don't want people slaying init.  */
+       p->exit_signal = SIGCHLD;
+
+       /* If it has exited notify the new parent about this child's death. */
+       if (!p->ptrace &&
+           p->exit_state == EXIT_ZOMBIE && thread_group_empty(p)) {
+               do_notify_parent(p, p->exit_signal);
+               if (task_detached(p)) {
+                       p->exit_state = EXIT_DEAD;
+                       list_move_tail(&p->sibling, dead);
+               }
+       }
+
+       kill_orphaned_pgrp(p, father);
+}
+
 static void forget_original_parent(struct task_struct *father)
 {
        struct task_struct *p, *n, *reaper;
-       LIST_HEAD(ptrace_dead);
+       LIST_HEAD(dead_children);
+
+       exit_ptrace(father);
 
        write_lock_irq(&tasklist_lock);
        reaper = find_new_reaper(father);
-       /*
-        * First clean up ptrace if we were using it.
-        */
-       ptrace_exit(father, &ptrace_dead);
 
        list_for_each_entry_safe(p, n, &father->children, sibling) {
                p->real_parent = reaper;
@@ -901,13 +813,16 @@ static void forget_original_parent(struct task_struct *father)
                        BUG_ON(p->ptrace);
                        p->parent = p->real_parent;
                }
-               reparent_thread(p, father);
+               reparent_thread(father, p, &dead_children);
        }
-
        write_unlock_irq(&tasklist_lock);
+
        BUG_ON(!list_empty(&father->children));
 
-       ptrace_exit_finish(father, &ptrace_dead);
+       list_for_each_entry_safe(p, n, &dead_children, sibling) {
+               list_del_init(&p->sibling);
+               release_task(p);
+       }
 }
 
 /*
@@ -1417,6 +1332,18 @@ static int wait_task_zombie(struct task_struct *p, int options,
        return retval;
 }
 
+static int *task_stopped_code(struct task_struct *p, bool ptrace)
+{
+       if (ptrace) {
+               if (task_is_stopped_or_traced(p))
+                       return &p->exit_code;
+       } else {
+               if (p->signal->flags & SIGNAL_STOP_STOPPED)
+                       return &p->signal->group_exit_code;
+       }
+       return NULL;
+}
+
 /*
  * Handle sys_wait4 work for one task in state TASK_STOPPED.  We hold
  * read_lock(&tasklist_lock) on entry.  If we return zero, we still hold
@@ -1427,7 +1354,7 @@ static int wait_task_stopped(int ptrace, struct task_struct *p,
                             int options, struct siginfo __user *infop,
                             int __user *stat_addr, struct rusage __user *ru)
 {
-       int retval, exit_code, why;
+       int retval, exit_code, *p_code, why;
        uid_t uid = 0; /* unneeded, required by compiler */
        pid_t pid;
 
@@ -1437,22 +1364,16 @@ static int wait_task_stopped(int ptrace, struct task_struct *p,
        exit_code = 0;
        spin_lock_irq(&p->sighand->siglock);
 
-       if (unlikely(!task_is_stopped_or_traced(p)))
-               goto unlock_sig;
-
-       if (!ptrace && p->signal->group_stop_count > 0)
-               /*
-                * A group stop is in progress and this is the group leader.
-                * We won't report until all threads have stopped.
-                */
+       p_code = task_stopped_code(p, ptrace);
+       if (unlikely(!p_code))
                goto unlock_sig;
 
-       exit_code = p->exit_code;
+       exit_code = *p_code;
        if (!exit_code)
                goto unlock_sig;
 
        if (!unlikely(options & WNOWAIT))
-               p->exit_code = 0;
+               *p_code = 0;
 
        /* don't need the RCU readlock here as we're holding a spinlock */
        uid = __task_cred(p)->uid;
@@ -1608,7 +1529,7 @@ static int wait_consider_task(struct task_struct *parent, int ptrace,
         */
        *notask_error = 0;
 
-       if (task_is_stopped_or_traced(p))
+       if (task_stopped_code(p, ptrace))
                return wait_task_stopped(ptrace, p, options,
                                         infop, stat_addr, ru);
 
@@ -1812,7 +1733,7 @@ SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr,
                pid = find_get_pid(-upid);
        } else if (upid == 0) {
                type = PIDTYPE_PGID;
-               pid = get_pid(task_pgrp(current));
+               pid = get_task_pid(current, PIDTYPE_PGID);
        } else /* upid > 0 */ {
                type = PIDTYPE_PID;
                pid = find_get_pid(upid);
index 6715ebc3761de3ed10eeda84ff932e59ff8289c5..f74458231449fb2d63caa8093f4a9b7ae664016a 100644 (file)
@@ -284,7 +284,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
        mm->free_area_cache = oldmm->mmap_base;
        mm->cached_hole_size = ~0UL;
        mm->map_count = 0;
-       cpus_clear(mm->cpu_vm_mask);
+       cpumask_clear(mm_cpumask(mm));
        mm->mm_rb = RB_ROOT;
        rb_link = &mm->mm_rb.rb_node;
        rb_parent = NULL;
@@ -841,6 +841,8 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
        atomic_set(&sig->live, 1);
        init_waitqueue_head(&sig->wait_chldexit);
        sig->flags = 0;
+       if (clone_flags & CLONE_NEWPID)
+               sig->flags |= SIGNAL_UNKILLABLE;
        sig->group_exit_code = 0;
        sig->group_exit_task = NULL;
        sig->group_stop_count = 0;
@@ -1125,7 +1127,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                goto bad_fork_cleanup_mm;
        if ((retval = copy_io(clone_flags, p)))
                goto bad_fork_cleanup_namespaces;
-       retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
+       retval = copy_thread(clone_flags, stack_start, stack_size, p, regs);
        if (retval)
                goto bad_fork_cleanup_io;
 
@@ -1263,8 +1265,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                        p->signal->leader_pid = pid;
                        tty_kref_put(p->signal->tty);
                        p->signal->tty = tty_kref_get(current->signal->tty);
-                       set_task_pgrp(p, task_pgrp_nr(current));
-                       set_task_session(p, task_session_nr(current));
                        attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
                        attach_pid(p, PIDTYPE_SID, task_session(current));
                        list_add_tail_rcu(&p->tasks, &init_task.tasks);
@@ -1488,6 +1488,7 @@ void __init proc_caches_init(void)
        mm_cachep = kmem_cache_create("mm_struct",
                        sizeof(struct mm_struct), ARCH_MIN_MMSTRUCT_ALIGN,
                        SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+       vm_area_cachep = KMEM_CACHE(vm_area_struct, SLAB_PANIC);
        mmap_init();
 }
 
index 438701adce2344faab6551f3c833f3bb36c60b05..6b50a024bca22e32b0a606fb4b7ea6daf1525967 100644 (file)
@@ -114,7 +114,9 @@ struct futex_q {
 };
 
 /*
- * Split the global futex_lock into every hash list lock.
+ * Hash buckets are shared by all the futex_keys that hash to the same
+ * location.  Each key may have multiple futex_q structures, one for each task
+ * waiting on a futex.
  */
 struct futex_hash_bucket {
        spinlock_t lock;
@@ -189,8 +191,7 @@ static void drop_futex_key_refs(union futex_key *key)
 /**
  * get_futex_key - Get parameters which are the keys for a futex.
  * @uaddr: virtual address of the futex
- * @shared: NULL for a PROCESS_PRIVATE futex,
- *     &current->mm->mmap_sem for a PROCESS_SHARED futex
+ * @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED
  * @key: address where result is stored.
  *
  * Returns a negative error code or 0
@@ -200,9 +201,7 @@ static void drop_futex_key_refs(union futex_key *key)
  * offset_within_page).  For private mappings, it's (uaddr, current->mm).
  * We can usually work out the index without swapping in the page.
  *
- * fshared is NULL for PROCESS_PRIVATE futexes
- * For other futexes, it points to &current->mm->mmap_sem and
- * caller must have taken the reader lock. but NOT any spinlocks.
+ * lock_page() might sleep, the caller should not hold a spinlock.
  */
 static int get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
 {
@@ -299,41 +298,6 @@ static int get_futex_value_locked(u32 *dest, u32 __user *from)
        return ret ? -EFAULT : 0;
 }
 
-/*
- * Fault handling.
- */
-static int futex_handle_fault(unsigned long address, int attempt)
-{
-       struct vm_area_struct * vma;
-       struct mm_struct *mm = current->mm;
-       int ret = -EFAULT;
-
-       if (attempt > 2)
-               return ret;
-
-       down_read(&mm->mmap_sem);
-       vma = find_vma(mm, address);
-       if (vma && address >= vma->vm_start &&
-           (vma->vm_flags & VM_WRITE)) {
-               int fault;
-               fault = handle_mm_fault(mm, vma, address, 1);
-               if (unlikely((fault & VM_FAULT_ERROR))) {
-#if 0
-                       /* XXX: let's do this when we verify it is OK */
-                       if (ret & VM_FAULT_OOM)
-                               ret = -ENOMEM;
-#endif
-               } else {
-                       ret = 0;
-                       if (fault & VM_FAULT_MAJOR)
-                               current->maj_flt++;
-                       else
-                               current->min_flt++;
-               }
-       }
-       up_read(&mm->mmap_sem);
-       return ret;
-}
 
 /*
  * PI code:
@@ -589,10 +553,9 @@ static void wake_futex(struct futex_q *q)
         * The waiting task can free the futex_q as soon as this is written,
         * without taking any locks.  This must come last.
         *
-        * A memory barrier is required here to prevent the following store
-        * to lock_ptr from getting ahead of the wakeup. Clearing the lock
-        * at the end of wake_up_all() does not prevent this store from
-        * moving.
+        * A memory barrier is required here to prevent the following store to
+        * lock_ptr from getting ahead of the wakeup. Clearing the lock at the
+        * end of wake_up() does not prevent this store from moving.
         */
        smp_wmb();
        q->lock_ptr = NULL;
@@ -692,9 +655,16 @@ double_lock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2)
        }
 }
 
+static inline void
+double_unlock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2)
+{
+       spin_unlock(&hb1->lock);
+       if (hb1 != hb2)
+               spin_unlock(&hb2->lock);
+}
+
 /*
- * Wake up all waiters hashed on the physical page that is mapped
- * to this virtual address:
+ * Wake up waiters matching bitset queued on this futex (uaddr).
  */
 static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset)
 {
@@ -750,9 +720,9 @@ futex_wake_op(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
        struct futex_hash_bucket *hb1, *hb2;
        struct plist_head *head;
        struct futex_q *this, *next;
-       int ret, op_ret, attempt = 0;
+       int ret, op_ret;
 
-retryfull:
+retry:
        ret = get_futex_key(uaddr1, fshared, &key1);
        if (unlikely(ret != 0))
                goto out;
@@ -763,16 +733,13 @@ retryfull:
        hb1 = hash_futex(&key1);
        hb2 = hash_futex(&key2);
 
-retry:
        double_lock_hb(hb1, hb2);
-
+retry_private:
        op_ret = futex_atomic_op_inuser(op, uaddr2);
        if (unlikely(op_ret < 0)) {
                u32 dummy;
 
-               spin_unlock(&hb1->lock);
-               if (hb1 != hb2)
-                       spin_unlock(&hb2->lock);
+               double_unlock_hb(hb1, hb2);
 
 #ifndef CONFIG_MMU
                /*
@@ -788,26 +755,16 @@ retry:
                        goto out_put_keys;
                }
 
-               /*
-                * futex_atomic_op_inuser needs to both read and write
-                * *(int __user *)uaddr2, but we can't modify it
-                * non-atomically.  Therefore, if get_user below is not
-                * enough, we need to handle the fault ourselves, while
-                * still holding the mmap_sem.
-                */
-               if (attempt++) {
-                       ret = futex_handle_fault((unsigned long)uaddr2,
-                                                attempt);
-                       if (ret)
-                               goto out_put_keys;
-                       goto retry;
-               }
-
                ret = get_user(dummy, uaddr2);
                if (ret)
-                       return ret;
+                       goto out_put_keys;
+
+               if (!fshared)
+                       goto retry_private;
 
-               goto retryfull;
+               put_futex_key(fshared, &key2);
+               put_futex_key(fshared, &key1);
+               goto retry;
        }
 
        head = &hb1->chain;
@@ -834,9 +791,7 @@ retry:
                ret += op_ret;
        }
 
-       spin_unlock(&hb1->lock);
-       if (hb1 != hb2)
-               spin_unlock(&hb2->lock);
+       double_unlock_hb(hb1, hb2);
 out_put_keys:
        put_futex_key(fshared, &key2);
 out_put_key1:
@@ -869,6 +824,7 @@ retry:
        hb1 = hash_futex(&key1);
        hb2 = hash_futex(&key2);
 
+retry_private:
        double_lock_hb(hb1, hb2);
 
        if (likely(cmpval != NULL)) {
@@ -877,16 +833,18 @@ retry:
                ret = get_futex_value_locked(&curval, uaddr1);
 
                if (unlikely(ret)) {
-                       spin_unlock(&hb1->lock);
-                       if (hb1 != hb2)
-                               spin_unlock(&hb2->lock);
+                       double_unlock_hb(hb1, hb2);
 
                        ret = get_user(curval, uaddr1);
+                       if (ret)
+                               goto out_put_keys;
 
-                       if (!ret)
-                               goto retry;
+                       if (!fshared)
+                               goto retry_private;
 
-                       goto out_put_keys;
+                       put_futex_key(fshared, &key2);
+                       put_futex_key(fshared, &key1);
+                       goto retry;
                }
                if (curval != *cmpval) {
                        ret = -EAGAIN;
@@ -923,9 +881,7 @@ retry:
        }
 
 out_unlock:
-       spin_unlock(&hb1->lock);
-       if (hb1 != hb2)
-               spin_unlock(&hb2->lock);
+       double_unlock_hb(hb1, hb2);
 
        /* drop_futex_key_refs() must be called outside the spinlocks. */
        while (--drop_count >= 0)
@@ -1063,7 +1019,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
        struct futex_pi_state *pi_state = q->pi_state;
        struct task_struct *oldowner = pi_state->owner;
        u32 uval, curval, newval;
-       int ret, attempt = 0;
+       int ret;
 
        /* Owner died? */
        if (!pi_state->owner)
@@ -1076,11 +1032,9 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
         * in the user space variable. This must be atomic as we have
         * to preserve the owner died bit here.
         *
-        * Note: We write the user space value _before_ changing the
-        * pi_state because we can fault here. Imagine swapped out
-        * pages or a fork, which was running right before we acquired
-        * mmap_sem, that marked all the anonymous memory readonly for
-        * cow.
+        * Note: We write the user space value _before_ changing the pi_state
+        * because we can fault here. Imagine swapped out pages or a fork
+        * that marked all the anonymous memory readonly for cow.
         *
         * Modifying pi_state _before_ the user space value would
         * leave the pi_state in an inconsistent state when we fault
@@ -1136,7 +1090,7 @@ retry:
 handle_fault:
        spin_unlock(q->lock_ptr);
 
-       ret = futex_handle_fault((unsigned long)uaddr, attempt++);
+       ret = get_user(uval, uaddr);
 
        spin_lock(q->lock_ptr);
 
@@ -1185,10 +1139,11 @@ retry:
        if (unlikely(ret != 0))
                goto out;
 
+retry_private:
        hb = queue_lock(&q);
 
        /*
-        * Access the page AFTER the futex is queued.
+        * Access the page AFTER the hash-bucket is locked.
         * Order is important:
         *
         *   Userspace waiter: val = var; if (cond(val)) futex_wait(&var, val);
@@ -1204,20 +1159,23 @@ retry:
         * a wakeup when *uaddr != val on entry to the syscall.  This is
         * rare, but normal.
         *
-        * for shared futexes, we hold the mmap semaphore, so the mapping
+        * For shared futexes, we hold the mmap semaphore, so the mapping
         * cannot have changed since we looked it up in get_futex_key.
         */
        ret = get_futex_value_locked(&uval, uaddr);
 
        if (unlikely(ret)) {
                queue_unlock(&q, hb);
-               put_futex_key(fshared, &q.key);
 
                ret = get_user(uval, uaddr);
+               if (ret)
+                       goto out_put_key;
 
-               if (!ret)
-                       goto retry;
-               goto out;
+               if (!fshared)
+                       goto retry_private;
+
+               put_futex_key(fshared, &q.key);
+               goto retry;
        }
        ret = -EWOULDBLOCK;
        if (unlikely(uval != val)) {
@@ -1248,16 +1206,13 @@ retry:
                if (!abs_time)
                        schedule();
                else {
-                       unsigned long slack;
-                       slack = current->timer_slack_ns;
-                       if (rt_task(current))
-                               slack = 0;
                        hrtimer_init_on_stack(&t.timer,
                                              clockrt ? CLOCK_REALTIME :
                                              CLOCK_MONOTONIC,
                                              HRTIMER_MODE_ABS);
                        hrtimer_init_sleeper(&t, current);
-                       hrtimer_set_expires_range_ns(&t.timer, *abs_time, slack);
+                       hrtimer_set_expires_range_ns(&t.timer, *abs_time,
+                                                    current->timer_slack_ns);
 
                        hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS);
                        if (!hrtimer_active(&t.timer))
@@ -1354,7 +1309,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,
        struct futex_hash_bucket *hb;
        u32 uval, newval, curval;
        struct futex_q q;
-       int ret, lock_taken, ownerdied = 0, attempt = 0;
+       int ret, lock_taken, ownerdied = 0;
 
        if (refill_pi_state_cache())
                return -ENOMEM;
@@ -1374,7 +1329,7 @@ retry:
        if (unlikely(ret != 0))
                goto out;
 
-retry_unlocked:
+retry_private:
        hb = queue_lock(&q);
 
 retry_locked:
@@ -1458,6 +1413,7 @@ retry_locked:
                         * exit to complete.
                         */
                        queue_unlock(&q, hb);
+                       put_futex_key(fshared, &q.key);
                        cond_resched();
                        goto retry;
 
@@ -1564,6 +1520,13 @@ retry_locked:
                }
        }
 
+       /*
+        * If fixup_pi_state_owner() faulted and was unable to handle the
+        * fault, unlock it and return the fault to userspace.
+        */
+       if (ret && (rt_mutex_owner(&q.pi_state->pi_mutex) == current))
+               rt_mutex_unlock(&q.pi_state->pi_mutex);
+
        /* Unqueue and drop the lock */
        unqueue_me_pi(&q);
 
@@ -1591,22 +1554,18 @@ uaddr_faulted:
         */
        queue_unlock(&q, hb);
 
-       if (attempt++) {
-               ret = futex_handle_fault((unsigned long)uaddr, attempt);
-               if (ret)
-                       goto out_put_key;
-               goto retry_unlocked;
-       }
-
        ret = get_user(uval, uaddr);
-       if (!ret)
-               goto retry;
+       if (ret)
+               goto out_put_key;
 
-       if (to)
-               destroy_hrtimer_on_stack(&to->timer);
-       return ret;
+       if (!fshared)
+               goto retry_private;
+
+       put_futex_key(fshared, &q.key);
+       goto retry;
 }
 
+
 /*
  * Userspace attempted a TID -> 0 atomic transition, and failed.
  * This is the in-kernel slowpath: we look up the PI state (if any),
@@ -1619,7 +1578,7 @@ static int futex_unlock_pi(u32 __user *uaddr, int fshared)
        u32 uval;
        struct plist_head *head;
        union futex_key key = FUTEX_KEY_INIT;
-       int ret, attempt = 0;
+       int ret;
 
 retry:
        if (get_user(uval, uaddr))
@@ -1635,7 +1594,6 @@ retry:
                goto out;
 
        hb = hash_futex(&key);
-retry_unlocked:
        spin_lock(&hb->lock);
 
        /*
@@ -1700,14 +1658,7 @@ pi_faulted:
         * we have to drop the mmap_sem in order to call get_user().
         */
        spin_unlock(&hb->lock);
-
-       if (attempt++) {
-               ret = futex_handle_fault((unsigned long)uaddr, attempt);
-               if (ret)
-                       goto out;
-               uval = 0;
-               goto retry_unlocked;
-       }
+       put_futex_key(fshared, &key);
 
        ret = get_user(uval, uaddr);
        if (!ret)
index 4dd5b1edac984bca7326297ecee3daf0239301f1..3394f8f52964b3d9b4433a3560ff94eb32b20cb8 100644 (file)
@@ -4,3 +4,4 @@ obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
 obj-$(CONFIG_NUMA_MIGRATE_IRQ_DESC) += numa_migrate.o
+obj-$(CONFIG_PM_SLEEP) += pm.o
index ee1aa9f8e8b9341af0c81ec9073f52e48375eb5b..01ce20eab38fed96a7b5a861940ba58d47c18fbf 100644 (file)
@@ -12,6 +12,8 @@ extern void compat_irq_chip_set_default_handler(struct irq_desc *desc);
 
 extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
                unsigned long flags);
+extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp);
+extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume);
 
 extern struct lock_class_key irq_desc_lock_class;
 extern void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr);
index 6458e99984c08f3af7a108ac0f7db03b21a7e5e8..1516ab77355c928bd1e1f5c8b6759e53d3b0c7e3 100644 (file)
@@ -162,6 +162,20 @@ static inline int setup_affinity(unsigned int irq, struct irq_desc *desc)
 }
 #endif
 
+void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend)
+{
+       if (suspend) {
+               if (!desc->action || (desc->action->flags & IRQF_TIMER))
+                       return;
+               desc->status |= IRQ_SUSPENDED;
+       }
+
+       if (!desc->depth++) {
+               desc->status |= IRQ_DISABLED;
+               desc->chip->disable(irq);
+       }
+}
+
 /**
  *     disable_irq_nosync - disable an irq without waiting
  *     @irq: Interrupt to disable
@@ -182,10 +196,7 @@ void disable_irq_nosync(unsigned int irq)
                return;
 
        spin_lock_irqsave(&desc->lock, flags);
-       if (!desc->depth++) {
-               desc->status |= IRQ_DISABLED;
-               desc->chip->disable(irq);
-       }
+       __disable_irq(desc, irq, false);
        spin_unlock_irqrestore(&desc->lock, flags);
 }
 EXPORT_SYMBOL(disable_irq_nosync);
@@ -215,15 +226,21 @@ void disable_irq(unsigned int irq)
 }
 EXPORT_SYMBOL(disable_irq);
 
-static void __enable_irq(struct irq_desc *desc, unsigned int irq)
+void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume)
 {
+       if (resume)
+               desc->status &= ~IRQ_SUSPENDED;
+
        switch (desc->depth) {
        case 0:
+ err_out:
                WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);
                break;
        case 1: {
                unsigned int status = desc->status & ~IRQ_DISABLED;
 
+               if (desc->status & IRQ_SUSPENDED)
+                       goto err_out;
                /* Prevent probing on this irq: */
                desc->status = status | IRQ_NOPROBE;
                check_irq_resend(desc, irq);
@@ -253,7 +270,7 @@ void enable_irq(unsigned int irq)
                return;
 
        spin_lock_irqsave(&desc->lock, flags);
-       __enable_irq(desc, irq);
+       __enable_irq(desc, irq, false);
        spin_unlock_irqrestore(&desc->lock, flags);
 }
 EXPORT_SYMBOL(enable_irq);
@@ -511,7 +528,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
         */
        if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) {
                desc->status &= ~IRQ_SPURIOUS_DISABLED;
-               __enable_irq(desc, irq);
+               __enable_irq(desc, irq, false);
        }
 
        spin_unlock_irqrestore(&desc->lock, flags);
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
new file mode 100644 (file)
index 0000000..638d8be
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * linux/kernel/irq/pm.c
+ *
+ * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ *
+ * This file contains power management functions related to interrupts.
+ */
+
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+
+#include "internals.h"
+
+/**
+ * suspend_device_irqs - disable all currently enabled interrupt lines
+ *
+ * During system-wide suspend or hibernation device interrupts need to be
+ * disabled at the chip level and this function is provided for this purpose.
+ * It disables all interrupt lines that are enabled at the moment and sets the
+ * IRQ_SUSPENDED flag for them.
+ */
+void suspend_device_irqs(void)
+{
+       struct irq_desc *desc;
+       int irq;
+
+       for_each_irq_desc(irq, desc) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&desc->lock, flags);
+               __disable_irq(desc, irq, true);
+               spin_unlock_irqrestore(&desc->lock, flags);
+       }
+
+       for_each_irq_desc(irq, desc)
+               if (desc->status & IRQ_SUSPENDED)
+                       synchronize_irq(irq);
+}
+EXPORT_SYMBOL_GPL(suspend_device_irqs);
+
+/**
+ * resume_device_irqs - enable interrupt lines disabled by suspend_device_irqs()
+ *
+ * Enable all interrupt lines previously disabled by suspend_device_irqs() that
+ * have the IRQ_SUSPENDED flag set.
+ */
+void resume_device_irqs(void)
+{
+       struct irq_desc *desc;
+       int irq;
+
+       for_each_irq_desc(irq, desc) {
+               unsigned long flags;
+
+               if (!(desc->status & IRQ_SUSPENDED))
+                       continue;
+
+               spin_lock_irqsave(&desc->lock, flags);
+               __enable_irq(desc, irq, true);
+               spin_unlock_irqrestore(&desc->lock, flags);
+       }
+}
+EXPORT_SYMBOL_GPL(resume_device_irqs);
+
+/**
+ * check_wakeup_irqs - check if any wake-up interrupts are pending
+ */
+int check_wakeup_irqs(void)
+{
+       struct irq_desc *desc;
+       int irq;
+
+       for_each_irq_desc(irq, desc)
+               if ((desc->status & IRQ_WAKEUP) && (desc->status & IRQ_PENDING))
+                       return -EBUSY;
+
+       return 0;
+}
index c7fd6692939d6bd03c13019996874677f296d83c..5a758c6e4950492fcb15248c91ed4f5f6b824dbc 100644 (file)
@@ -42,7 +42,7 @@
 note_buf_t* crash_notes;
 
 /* vmcoreinfo stuff */
-unsigned char vmcoreinfo_data[VMCOREINFO_BYTES];
+static unsigned char vmcoreinfo_data[VMCOREINFO_BYTES];
 u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4];
 size_t vmcoreinfo_size;
 size_t vmcoreinfo_max_size = sizeof(vmcoreinfo_data);
@@ -1409,6 +1409,7 @@ static int __init crash_save_vmcoreinfo_init(void)
        VMCOREINFO_OFFSET(list_head, prev);
        VMCOREINFO_OFFSET(vm_struct, addr);
        VMCOREINFO_LENGTH(zone.free_area, MAX_ORDER);
+       log_buf_kexec_setup();
        VMCOREINFO_LENGTH(free_area.free_list, MIGRATE_TYPES);
        VMCOREINFO_NUMBER(NR_FREE_PAGES);
        VMCOREINFO_NUMBER(PG_lru);
@@ -1450,11 +1451,7 @@ int kernel_kexec(void)
                error = device_suspend(PMSG_FREEZE);
                if (error)
                        goto Resume_console;
-               error = disable_nonboot_cpus();
-               if (error)
-                       goto Resume_devices;
                device_pm_lock();
-               local_irq_disable();
                /* At this point, device_suspend() has been called,
                 * but *not* device_power_down(). We *must*
                 * device_power_down() now.  Otherwise, drivers for
@@ -1464,12 +1461,15 @@ int kernel_kexec(void)
                 */
                error = device_power_down(PMSG_FREEZE);
                if (error)
-                       goto Enable_irqs;
-
+                       goto Resume_devices;
+               error = disable_nonboot_cpus();
+               if (error)
+                       goto Enable_cpus;
+               local_irq_disable();
                /* Suspend system devices */
                error = sysdev_suspend(PMSG_FREEZE);
                if (error)
-                       goto Power_up_devices;
+                       goto Enable_irqs;
        } else
 #endif
        {
@@ -1483,13 +1483,13 @@ int kernel_kexec(void)
 #ifdef CONFIG_KEXEC_JUMP
        if (kexec_image->preserve_context) {
                sysdev_resume();
- Power_up_devices:
-               device_power_up(PMSG_RESTORE);
  Enable_irqs:
                local_irq_enable();
-               device_pm_unlock();
+ Enable_cpus:
                enable_nonboot_cpus();
+               device_power_up(PMSG_RESTORE);
  Resume_devices:
+               device_pm_unlock();
                device_resume(PMSG_RESTORE);
  Resume_console:
                resume_console();
index a27a5f64443dc5c9a27d04679171cf15dfc1eabf..f0c8f545180d13193960d3171a1e58272488e72f 100644 (file)
@@ -167,7 +167,7 @@ static int ____call_usermodehelper(void *data)
        }
 
        /* We can run anywhere, unlike our parent keventd(). */
-       set_cpus_allowed_ptr(current, CPU_MASK_ALL_PTR);
+       set_cpus_allowed_ptr(current, cpu_all_mask);
 
        /*
         * Our parent is keventd, which runs with elevated scheduling priority.
index 4fbc456f393d0b1fb328667d9e93cc214c39da06..84bbadd4d0213c1558ade617ab49695df0b1bd9f 100644 (file)
@@ -110,7 +110,7 @@ static void create_kthread(struct kthread_create_info *create)
                 */
                sched_setscheduler(create->result, SCHED_NORMAL, &param);
                set_user_nice(create->result, KTHREAD_NICE_LEVEL);
-               set_cpus_allowed_ptr(create->result, CPU_MASK_ALL_PTR);
+               set_cpus_allowed_ptr(create->result, cpu_all_mask);
        }
        complete(&create->done);
 }
@@ -240,7 +240,7 @@ int kthreadd(void *unused)
        set_task_comm(tsk, "kthreadd");
        ignore_signals(tsk);
        set_user_nice(tsk, KTHREAD_NICE_LEVEL);
-       set_cpus_allowed_ptr(tsk, CPU_MASK_ALL_PTR);
+       set_cpus_allowed_ptr(tsk, cpu_all_mask);
 
        current->flags |= PF_NOFREEZE | PF_FREEZER_NOSIG;
 
index 06b0c3568f0b230a8c6b669d055c8c442a7eb790..3673a3f44d9d445f7cdf42f2ee5592731a4c0db7 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/utsname.h>
 #include <linux/hash.h>
 #include <linux/ftrace.h>
+#include <linux/stringify.h>
 
 #include <asm/sections.h>
 
@@ -310,12 +311,14 @@ EXPORT_SYMBOL(lockdep_on);
 #if VERBOSE
 # define HARDIRQ_VERBOSE       1
 # define SOFTIRQ_VERBOSE       1
+# define RECLAIM_VERBOSE       1
 #else
 # define HARDIRQ_VERBOSE       0
 # define SOFTIRQ_VERBOSE       0
+# define RECLAIM_VERBOSE       0
 #endif
 
-#if VERBOSE || HARDIRQ_VERBOSE || SOFTIRQ_VERBOSE
+#if VERBOSE || HARDIRQ_VERBOSE || SOFTIRQ_VERBOSE || RECLAIM_VERBOSE
 /*
  * Quick filtering for interesting events:
  */
@@ -443,17 +446,18 @@ atomic_t nr_find_usage_backwards_recursions;
  * Locking printouts:
  */
 
+#define __USAGE(__STATE)                                               \
+       [LOCK_USED_IN_##__STATE] = "IN-"__stringify(__STATE)"-W",       \
+       [LOCK_ENABLED_##__STATE] = __stringify(__STATE)"-ON-W",         \
+       [LOCK_USED_IN_##__STATE##_READ] = "IN-"__stringify(__STATE)"-R",\
+       [LOCK_ENABLED_##__STATE##_READ] = __stringify(__STATE)"-ON-R",
+
 static const char *usage_str[] =
 {
-       [LOCK_USED] =                   "initial-use ",
-       [LOCK_USED_IN_HARDIRQ] =        "in-hardirq-W",
-       [LOCK_USED_IN_SOFTIRQ] =        "in-softirq-W",
-       [LOCK_ENABLED_SOFTIRQS] =       "softirq-on-W",
-       [LOCK_ENABLED_HARDIRQS] =       "hardirq-on-W",
-       [LOCK_USED_IN_HARDIRQ_READ] =   "in-hardirq-R",
-       [LOCK_USED_IN_SOFTIRQ_READ] =   "in-softirq-R",
-       [LOCK_ENABLED_SOFTIRQS_READ] =  "softirq-on-R",
-       [LOCK_ENABLED_HARDIRQS_READ] =  "hardirq-on-R",
+#define LOCKDEP_STATE(__STATE) __USAGE(__STATE)
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
+       [LOCK_USED] = "INITIAL USE",
 };
 
 const char * __get_key_name(struct lockdep_subclass_key *key, char *str)
@@ -461,46 +465,45 @@ const char * __get_key_name(struct lockdep_subclass_key *key, char *str)
        return kallsyms_lookup((unsigned long)key, NULL, NULL, NULL, str);
 }
 
-void
-get_usage_chars(struct lock_class *class, char *c1, char *c2, char *c3, char *c4)
+static inline unsigned long lock_flag(enum lock_usage_bit bit)
 {
-       *c1 = '.', *c2 = '.', *c3 = '.', *c4 = '.';
-
-       if (class->usage_mask & LOCKF_USED_IN_HARDIRQ)
-               *c1 = '+';
-       else
-               if (class->usage_mask & LOCKF_ENABLED_HARDIRQS)
-                       *c1 = '-';
+       return 1UL << bit;
+}
 
-       if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ)
-               *c2 = '+';
-       else
-               if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS)
-                       *c2 = '-';
+static char get_usage_char(struct lock_class *class, enum lock_usage_bit bit)
+{
+       char c = '.';
 
-       if (class->usage_mask & LOCKF_ENABLED_HARDIRQS_READ)
-               *c3 = '-';
-       if (class->usage_mask & LOCKF_USED_IN_HARDIRQ_READ) {
-               *c3 = '+';
-               if (class->usage_mask & LOCKF_ENABLED_HARDIRQS_READ)
-                       *c3 = '?';
+       if (class->usage_mask & lock_flag(bit + 2))
+               c = '+';
+       if (class->usage_mask & lock_flag(bit)) {
+               c = '-';
+               if (class->usage_mask & lock_flag(bit + 2))
+                       c = '?';
        }
 
-       if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS_READ)
-               *c4 = '-';
-       if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ_READ) {
-               *c4 = '+';
-               if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS_READ)
-                       *c4 = '?';
-       }
+       return c;
+}
+
+void get_usage_chars(struct lock_class *class, char usage[LOCK_USAGE_CHARS])
+{
+       int i = 0;
+
+#define LOCKDEP_STATE(__STATE)                                                 \
+       usage[i++] = get_usage_char(class, LOCK_USED_IN_##__STATE);     \
+       usage[i++] = get_usage_char(class, LOCK_USED_IN_##__STATE##_READ);
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
+
+       usage[i] = '\0';
 }
 
 static void print_lock_name(struct lock_class *class)
 {
-       char str[KSYM_NAME_LEN], c1, c2, c3, c4;
+       char str[KSYM_NAME_LEN], usage[LOCK_USAGE_CHARS];
        const char *name;
 
-       get_usage_chars(class, &c1, &c2, &c3, &c4);
+       get_usage_chars(class, usage);
 
        name = class->name;
        if (!name) {
@@ -513,7 +516,7 @@ static void print_lock_name(struct lock_class *class)
                if (class->subclass)
                        printk("/%d", class->subclass);
        }
-       printk("){%c%c%c%c}", c1, c2, c3, c4);
+       printk("){%s}", usage);
 }
 
 static void print_lockdep_cache(struct lockdep_map *lock)
@@ -1263,9 +1266,49 @@ check_usage(struct task_struct *curr, struct held_lock *prev,
                        bit_backwards, bit_forwards, irqclass);
 }
 
-static int
-check_prev_add_irq(struct task_struct *curr, struct held_lock *prev,
-               struct held_lock *next)
+static const char *state_names[] = {
+#define LOCKDEP_STATE(__STATE) \
+       __stringify(__STATE),
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
+};
+
+static const char *state_rnames[] = {
+#define LOCKDEP_STATE(__STATE) \
+       __stringify(__STATE)"-READ",
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
+};
+
+static inline const char *state_name(enum lock_usage_bit bit)
+{
+       return (bit & 1) ? state_rnames[bit >> 2] : state_names[bit >> 2];
+}
+
+static int exclusive_bit(int new_bit)
+{
+       /*
+        * USED_IN
+        * USED_IN_READ
+        * ENABLED
+        * ENABLED_READ
+        *
+        * bit 0 - write/read
+        * bit 1 - used_in/enabled
+        * bit 2+  state
+        */
+
+       int state = new_bit & ~3;
+       int dir = new_bit & 2;
+
+       /*
+        * keep state, bit flip the direction and strip read.
+        */
+       return state | (dir ^ 2);
+}
+
+static int check_irq_usage(struct task_struct *curr, struct held_lock *prev,
+                          struct held_lock *next, enum lock_usage_bit bit)
 {
        /*
         * Prove that the new dependency does not connect a hardirq-safe
@@ -1273,38 +1316,34 @@ check_prev_add_irq(struct task_struct *curr, struct held_lock *prev,
         * the backwards-subgraph starting at <prev>, and the
         * forwards-subgraph starting at <next>:
         */
-       if (!check_usage(curr, prev, next, LOCK_USED_IN_HARDIRQ,
-                                       LOCK_ENABLED_HARDIRQS, "hard"))
+       if (!check_usage(curr, prev, next, bit,
+                          exclusive_bit(bit), state_name(bit)))
                return 0;
 
+       bit++; /* _READ */
+
        /*
         * Prove that the new dependency does not connect a hardirq-safe-read
         * lock with a hardirq-unsafe lock - to achieve this we search
         * the backwards-subgraph starting at <prev>, and the
         * forwards-subgraph starting at <next>:
         */
-       if (!check_usage(curr, prev, next, LOCK_USED_IN_HARDIRQ_READ,
-                                       LOCK_ENABLED_HARDIRQS, "hard-read"))
+       if (!check_usage(curr, prev, next, bit,
+                          exclusive_bit(bit), state_name(bit)))
                return 0;
 
-       /*
-        * Prove that the new dependency does not connect a softirq-safe
-        * lock with a softirq-unsafe lock - to achieve this we search
-        * the backwards-subgraph starting at <prev>, and the
-        * forwards-subgraph starting at <next>:
-        */
-       if (!check_usage(curr, prev, next, LOCK_USED_IN_SOFTIRQ,
-                                       LOCK_ENABLED_SOFTIRQS, "soft"))
-               return 0;
-       /*
-        * Prove that the new dependency does not connect a softirq-safe-read
-        * lock with a softirq-unsafe lock - to achieve this we search
-        * the backwards-subgraph starting at <prev>, and the
-        * forwards-subgraph starting at <next>:
-        */
-       if (!check_usage(curr, prev, next, LOCK_USED_IN_SOFTIRQ_READ,
-                                       LOCK_ENABLED_SOFTIRQS, "soft"))
+       return 1;
+}
+
+static int
+check_prev_add_irq(struct task_struct *curr, struct held_lock *prev,
+               struct held_lock *next)
+{
+#define LOCKDEP_STATE(__STATE)                                         \
+       if (!check_irq_usage(curr, prev, next, LOCK_USED_IN_##__STATE)) \
                return 0;
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
 
        return 1;
 }
@@ -1933,7 +1972,7 @@ void print_irqtrace_events(struct task_struct *curr)
        print_ip_sym(curr->softirq_disable_ip);
 }
 
-static int hardirq_verbose(struct lock_class *class)
+static int HARDIRQ_verbose(struct lock_class *class)
 {
 #if HARDIRQ_VERBOSE
        return class_filter(class);
@@ -1941,7 +1980,7 @@ static int hardirq_verbose(struct lock_class *class)
        return 0;
 }
 
-static int softirq_verbose(struct lock_class *class)
+static int SOFTIRQ_verbose(struct lock_class *class)
 {
 #if SOFTIRQ_VERBOSE
        return class_filter(class);
@@ -1949,185 +1988,94 @@ static int softirq_verbose(struct lock_class *class)
        return 0;
 }
 
+static int RECLAIM_FS_verbose(struct lock_class *class)
+{
+#if RECLAIM_VERBOSE
+       return class_filter(class);
+#endif
+       return 0;
+}
+
 #define STRICT_READ_CHECKS     1
 
-static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
-               enum lock_usage_bit new_bit)
+static int (*state_verbose_f[])(struct lock_class *class) = {
+#define LOCKDEP_STATE(__STATE) \
+       __STATE##_verbose,
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
+};
+
+static inline int state_verbose(enum lock_usage_bit bit,
+                               struct lock_class *class)
 {
-       int ret = 1;
+       return state_verbose_f[bit >> 2](class);
+}
 
-       switch(new_bit) {
-       case LOCK_USED_IN_HARDIRQ:
-               if (!valid_state(curr, this, new_bit, LOCK_ENABLED_HARDIRQS))
-                       return 0;
-               if (!valid_state(curr, this, new_bit,
-                                LOCK_ENABLED_HARDIRQS_READ))
-                       return 0;
-               /*
-                * just marked it hardirq-safe, check that this lock
-                * took no hardirq-unsafe lock in the past:
-                */
-               if (!check_usage_forwards(curr, this,
-                                         LOCK_ENABLED_HARDIRQS, "hard"))
-                       return 0;
-#if STRICT_READ_CHECKS
-               /*
-                * just marked it hardirq-safe, check that this lock
-                * took no hardirq-unsafe-read lock in the past:
-                */
-               if (!check_usage_forwards(curr, this,
-                               LOCK_ENABLED_HARDIRQS_READ, "hard-read"))
-                       return 0;
-#endif
-               if (hardirq_verbose(hlock_class(this)))
-                       ret = 2;
-               break;
-       case LOCK_USED_IN_SOFTIRQ:
-               if (!valid_state(curr, this, new_bit, LOCK_ENABLED_SOFTIRQS))
-                       return 0;
-               if (!valid_state(curr, this, new_bit,
-                                LOCK_ENABLED_SOFTIRQS_READ))
-                       return 0;
-               /*
-                * just marked it softirq-safe, check that this lock
-                * took no softirq-unsafe lock in the past:
-                */
-               if (!check_usage_forwards(curr, this,
-                                         LOCK_ENABLED_SOFTIRQS, "soft"))
-                       return 0;
-#if STRICT_READ_CHECKS
-               /*
-                * just marked it softirq-safe, check that this lock
-                * took no softirq-unsafe-read lock in the past:
-                */
-               if (!check_usage_forwards(curr, this,
-                               LOCK_ENABLED_SOFTIRQS_READ, "soft-read"))
-                       return 0;
-#endif
-               if (softirq_verbose(hlock_class(this)))
-                       ret = 2;
-               break;
-       case LOCK_USED_IN_HARDIRQ_READ:
-               if (!valid_state(curr, this, new_bit, LOCK_ENABLED_HARDIRQS))
-                       return 0;
-               /*
-                * just marked it hardirq-read-safe, check that this lock
-                * took no hardirq-unsafe lock in the past:
-                */
-               if (!check_usage_forwards(curr, this,
-                                         LOCK_ENABLED_HARDIRQS, "hard"))
-                       return 0;
-               if (hardirq_verbose(hlock_class(this)))
-                       ret = 2;
-               break;
-       case LOCK_USED_IN_SOFTIRQ_READ:
-               if (!valid_state(curr, this, new_bit, LOCK_ENABLED_SOFTIRQS))
-                       return 0;
-               /*
-                * just marked it softirq-read-safe, check that this lock
-                * took no softirq-unsafe lock in the past:
-                */
-               if (!check_usage_forwards(curr, this,
-                                         LOCK_ENABLED_SOFTIRQS, "soft"))
-                       return 0;
-               if (softirq_verbose(hlock_class(this)))
-                       ret = 2;
-               break;
-       case LOCK_ENABLED_HARDIRQS:
-               if (!valid_state(curr, this, new_bit, LOCK_USED_IN_HARDIRQ))
-                       return 0;
-               if (!valid_state(curr, this, new_bit,
-                                LOCK_USED_IN_HARDIRQ_READ))
-                       return 0;
-               /*
-                * just marked it hardirq-unsafe, check that no hardirq-safe
-                * lock in the system ever took it in the past:
-                */
-               if (!check_usage_backwards(curr, this,
-                                          LOCK_USED_IN_HARDIRQ, "hard"))
-                       return 0;
-#if STRICT_READ_CHECKS
-               /*
-                * just marked it hardirq-unsafe, check that no
-                * hardirq-safe-read lock in the system ever took
-                * it in the past:
-                */
-               if (!check_usage_backwards(curr, this,
-                                  LOCK_USED_IN_HARDIRQ_READ, "hard-read"))
-                       return 0;
-#endif
-               if (hardirq_verbose(hlock_class(this)))
-                       ret = 2;
-               break;
-       case LOCK_ENABLED_SOFTIRQS:
-               if (!valid_state(curr, this, new_bit, LOCK_USED_IN_SOFTIRQ))
-                       return 0;
-               if (!valid_state(curr, this, new_bit,
-                                LOCK_USED_IN_SOFTIRQ_READ))
-                       return 0;
-               /*
-                * just marked it softirq-unsafe, check that no softirq-safe
-                * lock in the system ever took it in the past:
-                */
-               if (!check_usage_backwards(curr, this,
-                                          LOCK_USED_IN_SOFTIRQ, "soft"))
-                       return 0;
-#if STRICT_READ_CHECKS
-               /*
-                * just marked it softirq-unsafe, check that no
-                * softirq-safe-read lock in the system ever took
-                * it in the past:
-                */
-               if (!check_usage_backwards(curr, this,
-                                  LOCK_USED_IN_SOFTIRQ_READ, "soft-read"))
-                       return 0;
-#endif
-               if (softirq_verbose(hlock_class(this)))
-                       ret = 2;
-               break;
-       case LOCK_ENABLED_HARDIRQS_READ:
-               if (!valid_state(curr, this, new_bit, LOCK_USED_IN_HARDIRQ))
-                       return 0;
-#if STRICT_READ_CHECKS
-               /*
-                * just marked it hardirq-read-unsafe, check that no
-                * hardirq-safe lock in the system ever took it in the past:
-                */
-               if (!check_usage_backwards(curr, this,
-                                          LOCK_USED_IN_HARDIRQ, "hard"))
-                       return 0;
-#endif
-               if (hardirq_verbose(hlock_class(this)))
-                       ret = 2;
-               break;
-       case LOCK_ENABLED_SOFTIRQS_READ:
-               if (!valid_state(curr, this, new_bit, LOCK_USED_IN_SOFTIRQ))
+typedef int (*check_usage_f)(struct task_struct *, struct held_lock *,
+                            enum lock_usage_bit bit, const char *name);
+
+static int
+mark_lock_irq(struct task_struct *curr, struct held_lock *this, int new_bit)
+{
+       int excl_bit = exclusive_bit(new_bit);
+       int read = new_bit & 1;
+       int dir = new_bit & 2;
+
+       /*
+        * mark USED_IN has to look forwards -- to ensure no dependency
+        * has ENABLED state, which would allow recursion deadlocks.
+        *
+        * mark ENABLED has to look backwards -- to ensure no dependee
+        * has USED_IN state, which, again, would allow  recursion deadlocks.
+        */
+       check_usage_f usage = dir ?
+               check_usage_backwards : check_usage_forwards;
+
+       /*
+        * Validate that this particular lock does not have conflicting
+        * usage states.
+        */
+       if (!valid_state(curr, this, new_bit, excl_bit))
+               return 0;
+
+       /*
+        * Validate that the lock dependencies don't have conflicting usage
+        * states.
+        */
+       if ((!read || !dir || STRICT_READ_CHECKS) &&
+                       !usage(curr, this, excl_bit, state_name(new_bit)))
+               return 0;
+
+       /*
+        * Check for read in write conflicts
+        */
+       if (!read) {
+               if (!valid_state(curr, this, new_bit, excl_bit + 1))
                        return 0;
-#if STRICT_READ_CHECKS
-               /*
-                * just marked it softirq-read-unsafe, check that no
-                * softirq-safe lock in the system ever took it in the past:
-                */
-               if (!check_usage_backwards(curr, this,
-                                          LOCK_USED_IN_SOFTIRQ, "soft"))
+
+               if (STRICT_READ_CHECKS &&
+                       !usage(curr, this, excl_bit + 1,
+                               state_name(new_bit + 1)))
                        return 0;
-#endif
-               if (softirq_verbose(hlock_class(this)))
-                       ret = 2;
-               break;
-       default:
-               WARN_ON(1);
-               break;
        }
 
-       return ret;
+       if (state_verbose(new_bit, hlock_class(this)))
+               return 2;
+
+       return 1;
 }
 
+enum mark_type {
+#define LOCKDEP_STATE(__STATE) __STATE,
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
+};
+
 /*
  * Mark all held locks with a usage bit:
  */
 static int
-mark_held_locks(struct task_struct *curr, int hardirq)
+mark_held_locks(struct task_struct *curr, enum mark_type mark)
 {
        enum lock_usage_bit usage_bit;
        struct held_lock *hlock;
@@ -2136,17 +2084,12 @@ mark_held_locks(struct task_struct *curr, int hardirq)
        for (i = 0; i < curr->lockdep_depth; i++) {
                hlock = curr->held_locks + i;
 
-               if (hardirq) {
-                       if (hlock->read)
-                               usage_bit = LOCK_ENABLED_HARDIRQS_READ;
-                       else
-                               usage_bit = LOCK_ENABLED_HARDIRQS;
-               } else {
-                       if (hlock->read)
-                               usage_bit = LOCK_ENABLED_SOFTIRQS_READ;
-                       else
-                               usage_bit = LOCK_ENABLED_SOFTIRQS;
-               }
+               usage_bit = 2 + (mark << 2); /* ENABLED */
+               if (hlock->read)
+                       usage_bit += 1; /* READ */
+
+               BUG_ON(usage_bit >= LOCK_USAGE_STATES);
+
                if (!mark_lock(curr, hlock, usage_bit))
                        return 0;
        }
@@ -2200,7 +2143,7 @@ void trace_hardirqs_on_caller(unsigned long ip)
         * We are going to turn hardirqs on, so set the
         * usage bit for all held locks:
         */
-       if (!mark_held_locks(curr, 1))
+       if (!mark_held_locks(curr, HARDIRQ))
                return;
        /*
         * If we have softirqs enabled, then set the usage
@@ -2208,7 +2151,7 @@ void trace_hardirqs_on_caller(unsigned long ip)
         * this bit from being set before)
         */
        if (curr->softirqs_enabled)
-               if (!mark_held_locks(curr, 0))
+               if (!mark_held_locks(curr, SOFTIRQ))
                        return;
 
        curr->hardirq_enable_ip = ip;
@@ -2288,7 +2231,7 @@ void trace_softirqs_on(unsigned long ip)
         * enabled too:
         */
        if (curr->hardirqs_enabled)
-               mark_held_locks(curr, 0);
+               mark_held_locks(curr, SOFTIRQ);
 }
 
 /*
@@ -2317,6 +2260,48 @@ void trace_softirqs_off(unsigned long ip)
                debug_atomic_inc(&redundant_softirqs_off);
 }
 
+static void __lockdep_trace_alloc(gfp_t gfp_mask, unsigned long flags)
+{
+       struct task_struct *curr = current;
+
+       if (unlikely(!debug_locks))
+               return;
+
+       /* no reclaim without waiting on it */
+       if (!(gfp_mask & __GFP_WAIT))
+               return;
+
+       /* this guy won't enter reclaim */
+       if ((curr->flags & PF_MEMALLOC) && !(gfp_mask & __GFP_NOMEMALLOC))
+               return;
+
+       /* We're only interested __GFP_FS allocations for now */
+       if (!(gfp_mask & __GFP_FS))
+               return;
+
+       if (DEBUG_LOCKS_WARN_ON(irqs_disabled_flags(flags)))
+               return;
+
+       mark_held_locks(curr, RECLAIM_FS);
+}
+
+static void check_flags(unsigned long flags);
+
+void lockdep_trace_alloc(gfp_t gfp_mask)
+{
+       unsigned long flags;
+
+       if (unlikely(current->lockdep_recursion))
+               return;
+
+       raw_local_irq_save(flags);
+       check_flags(flags);
+       current->lockdep_recursion = 1;
+       __lockdep_trace_alloc(gfp_mask, flags);
+       current->lockdep_recursion = 0;
+       raw_local_irq_restore(flags);
+}
+
 static int mark_irqflags(struct task_struct *curr, struct held_lock *hlock)
 {
        /*
@@ -2345,19 +2330,35 @@ static int mark_irqflags(struct task_struct *curr, struct held_lock *hlock)
        if (!hlock->hardirqs_off) {
                if (hlock->read) {
                        if (!mark_lock(curr, hlock,
-                                       LOCK_ENABLED_HARDIRQS_READ))
+                                       LOCK_ENABLED_HARDIRQ_READ))
                                return 0;
                        if (curr->softirqs_enabled)
                                if (!mark_lock(curr, hlock,
-                                               LOCK_ENABLED_SOFTIRQS_READ))
+                                               LOCK_ENABLED_SOFTIRQ_READ))
                                        return 0;
                } else {
                        if (!mark_lock(curr, hlock,
-                                       LOCK_ENABLED_HARDIRQS))
+                                       LOCK_ENABLED_HARDIRQ))
                                return 0;
                        if (curr->softirqs_enabled)
                                if (!mark_lock(curr, hlock,
-                                               LOCK_ENABLED_SOFTIRQS))
+                                               LOCK_ENABLED_SOFTIRQ))
+                                       return 0;
+               }
+       }
+
+       /*
+        * We reuse the irq context infrastructure more broadly as a general
+        * context checking code. This tests GFP_FS recursion (a lock taken
+        * during reclaim for a GFP_FS allocation is held over a GFP_FS
+        * allocation).
+        */
+       if (!hlock->trylock && (curr->lockdep_reclaim_gfp & __GFP_FS)) {
+               if (hlock->read) {
+                       if (!mark_lock(curr, hlock, LOCK_USED_IN_RECLAIM_FS_READ))
+                                       return 0;
+               } else {
+                       if (!mark_lock(curr, hlock, LOCK_USED_IN_RECLAIM_FS))
                                        return 0;
                }
        }
@@ -2412,6 +2413,10 @@ static inline int separate_irq_context(struct task_struct *curr,
        return 0;
 }
 
+void lockdep_trace_alloc(gfp_t gfp_mask)
+{
+}
+
 #endif
 
 /*
@@ -2445,14 +2450,13 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
                return 0;
 
        switch (new_bit) {
-       case LOCK_USED_IN_HARDIRQ:
-       case LOCK_USED_IN_SOFTIRQ:
-       case LOCK_USED_IN_HARDIRQ_READ:
-       case LOCK_USED_IN_SOFTIRQ_READ:
-       case LOCK_ENABLED_HARDIRQS:
-       case LOCK_ENABLED_SOFTIRQS:
-       case LOCK_ENABLED_HARDIRQS_READ:
-       case LOCK_ENABLED_SOFTIRQS_READ:
+#define LOCKDEP_STATE(__STATE)                 \
+       case LOCK_USED_IN_##__STATE:            \
+       case LOCK_USED_IN_##__STATE##_READ:     \
+       case LOCK_ENABLED_##__STATE:            \
+       case LOCK_ENABLED_##__STATE##_READ:
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
                ret = mark_lock_irq(curr, this, new_bit);
                if (!ret)
                        return 0;
@@ -2966,6 +2970,16 @@ void lock_release(struct lockdep_map *lock, int nested,
 }
 EXPORT_SYMBOL_GPL(lock_release);
 
+void lockdep_set_current_reclaim_state(gfp_t gfp_mask)
+{
+       current->lockdep_reclaim_gfp = gfp_mask;
+}
+
+void lockdep_clear_current_reclaim_state(void)
+{
+       current->lockdep_reclaim_gfp = 0;
+}
+
 #ifdef CONFIG_LOCK_STAT
 static int
 print_lock_contention_bug(struct task_struct *curr, struct lockdep_map *lock,
index 56b196932c081e915568d4fef27a92c08e129758..a2cc7e9a6e841b9e955709b9139cd96b3d803f2e 100644 (file)
@@ -6,6 +6,45 @@
  * lockdep subsystem internal functions and variables.
  */
 
+/*
+ * Lock-class usage-state bits:
+ */
+enum lock_usage_bit {
+#define LOCKDEP_STATE(__STATE)         \
+       LOCK_USED_IN_##__STATE,         \
+       LOCK_USED_IN_##__STATE##_READ,  \
+       LOCK_ENABLED_##__STATE,         \
+       LOCK_ENABLED_##__STATE##_READ,
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
+       LOCK_USED,
+       LOCK_USAGE_STATES
+};
+
+/*
+ * Usage-state bitmasks:
+ */
+#define __LOCKF(__STATE)       LOCKF_##__STATE = (1 << LOCK_##__STATE),
+
+enum {
+#define LOCKDEP_STATE(__STATE)                                         \
+       __LOCKF(USED_IN_##__STATE)                                      \
+       __LOCKF(USED_IN_##__STATE##_READ)                               \
+       __LOCKF(ENABLED_##__STATE)                                      \
+       __LOCKF(ENABLED_##__STATE##_READ)
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
+       __LOCKF(USED)
+};
+
+#define LOCKF_ENABLED_IRQ (LOCKF_ENABLED_HARDIRQ | LOCKF_ENABLED_SOFTIRQ)
+#define LOCKF_USED_IN_IRQ (LOCKF_USED_IN_HARDIRQ | LOCKF_USED_IN_SOFTIRQ)
+
+#define LOCKF_ENABLED_IRQ_READ \
+               (LOCKF_ENABLED_HARDIRQ_READ | LOCKF_ENABLED_SOFTIRQ_READ)
+#define LOCKF_USED_IN_IRQ_READ \
+               (LOCKF_USED_IN_HARDIRQ_READ | LOCKF_USED_IN_SOFTIRQ_READ)
+
 /*
  * MAX_LOCKDEP_ENTRIES is the maximum number of lock dependencies
  * we track.
 extern struct list_head all_lock_classes;
 extern struct lock_chain lock_chains[];
 
-extern void
-get_usage_chars(struct lock_class *class, char *c1, char *c2, char *c3, char *c4);
+#define LOCK_USAGE_CHARS (1+LOCK_USAGE_STATES/2)
+
+extern void get_usage_chars(struct lock_class *class,
+                           char usage[LOCK_USAGE_CHARS]);
 
 extern const char * __get_key_name(struct lockdep_subclass_key *key, char *str);
 
index 13716b8138961ee9f5feffe23ad9115fc27766e3..d7135aa2d2c4ccc0f3638cfa6fb3b2742e33c43c 100644 (file)
@@ -84,7 +84,7 @@ static int l_show(struct seq_file *m, void *v)
 {
        struct lock_class *class = v;
        struct lock_list *entry;
-       char c1, c2, c3, c4;
+       char usage[LOCK_USAGE_CHARS];
 
        if (v == SEQ_START_TOKEN) {
                seq_printf(m, "all lock classes:\n");
@@ -100,8 +100,8 @@ static int l_show(struct seq_file *m, void *v)
        seq_printf(m, " BD:%5ld", lockdep_count_backward_deps(class));
 #endif
 
-       get_usage_chars(class, &c1, &c2, &c3, &c4);
-       seq_printf(m, " %c%c%c%c", c1, c2, c3, c4);
+       get_usage_chars(class, usage);
+       seq_printf(m, " %s", usage);
 
        seq_printf(m, ": ");
        print_name(m, class);
@@ -300,27 +300,27 @@ static int lockdep_stats_show(struct seq_file *m, void *v)
                        nr_uncategorized++;
                if (class->usage_mask & LOCKF_USED_IN_IRQ)
                        nr_irq_safe++;
-               if (class->usage_mask & LOCKF_ENABLED_IRQS)
+               if (class->usage_mask & LOCKF_ENABLED_IRQ)
                        nr_irq_unsafe++;
                if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ)
                        nr_softirq_safe++;
-               if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS)
+               if (class->usage_mask & LOCKF_ENABLED_SOFTIRQ)
                        nr_softirq_unsafe++;
                if (class->usage_mask & LOCKF_USED_IN_HARDIRQ)
                        nr_hardirq_safe++;
-               if (class->usage_mask & LOCKF_ENABLED_HARDIRQS)
+               if (class->usage_mask & LOCKF_ENABLED_HARDIRQ)
                        nr_hardirq_unsafe++;
                if (class->usage_mask & LOCKF_USED_IN_IRQ_READ)
                        nr_irq_read_safe++;
-               if (class->usage_mask & LOCKF_ENABLED_IRQS_READ)
+               if (class->usage_mask & LOCKF_ENABLED_IRQ_READ)
                        nr_irq_read_unsafe++;
                if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ_READ)
                        nr_softirq_read_safe++;
-               if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS_READ)
+               if (class->usage_mask & LOCKF_ENABLED_SOFTIRQ_READ)
                        nr_softirq_read_unsafe++;
                if (class->usage_mask & LOCKF_USED_IN_HARDIRQ_READ)
                        nr_hardirq_read_safe++;
-               if (class->usage_mask & LOCKF_ENABLED_HARDIRQS_READ)
+               if (class->usage_mask & LOCKF_ENABLED_HARDIRQ_READ)
                        nr_hardirq_read_unsafe++;
 
 #ifdef CONFIG_PROVE_LOCKING
@@ -601,6 +601,10 @@ static void seq_stats(struct seq_file *m, struct lock_stat_data *data)
 static void seq_header(struct seq_file *m)
 {
        seq_printf(m, "lock_stat version 0.3\n");
+
+       if (unlikely(!debug_locks))
+               seq_printf(m, "*WARNING* lock debugging disabled!! - possibly due to a lockdep warning\n");
+
        seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1));
        seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s "
                        "%14s %14s\n",
diff --git a/kernel/lockdep_states.h b/kernel/lockdep_states.h
new file mode 100644 (file)
index 0000000..995b0cc
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Lockdep states,
+ *
+ * please update XXX_LOCK_USAGE_STATES in include/linux/lockdep.h whenever
+ * you add one, or come up with a nice dynamic solution.
+ */
+LOCKDEP_STATE(HARDIRQ)
+LOCKDEP_STATE(SOFTIRQ)
+LOCKDEP_STATE(RECLAIM_FS)
index 1d94160eb5326e94c0222da947b8c1ee4ee44875..50d022e5a5606dd64d985afbff9d33621f06ab96 100644 (file)
 /*
  * Must be called with lock->wait_lock held.
  */
-void debug_mutex_set_owner(struct mutex *lock, struct thread_info *new_owner)
-{
-       lock->owner = new_owner;
-}
-
 void debug_mutex_lock_common(struct mutex *lock, struct mutex_waiter *waiter)
 {
        memset(waiter, MUTEX_DEBUG_INIT, sizeof(*waiter));
@@ -59,7 +54,6 @@ void debug_mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter,
 
        /* Mark the current thread as blocked on the lock: */
        ti->task->blocked_on = waiter;
-       waiter->lock = lock;
 }
 
 void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter,
@@ -82,7 +76,7 @@ void debug_mutex_unlock(struct mutex *lock)
        DEBUG_LOCKS_WARN_ON(lock->magic != lock);
        DEBUG_LOCKS_WARN_ON(lock->owner != current_thread_info());
        DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next);
-       DEBUG_LOCKS_WARN_ON(lock->owner != current_thread_info());
+       mutex_clear_owner(lock);
 }
 
 void debug_mutex_init(struct mutex *lock, const char *name,
@@ -95,7 +89,6 @@ void debug_mutex_init(struct mutex *lock, const char *name,
        debug_check_no_locks_freed((void *)lock, sizeof(*lock));
        lockdep_init_map(&lock->dep_map, name, key, 0);
 #endif
-       lock->owner = NULL;
        lock->magic = lock;
 }
 
index babfbdfc534b7127e3769405433499f1929a44a5..6b2d735846a56f17425749b6501fe2023c0e6cdb 100644 (file)
 /*
  * This must be called with lock->wait_lock held.
  */
-extern void
-debug_mutex_set_owner(struct mutex *lock, struct thread_info *new_owner);
-
-static inline void debug_mutex_clear_owner(struct mutex *lock)
-{
-       lock->owner = NULL;
-}
-
 extern void debug_mutex_lock_common(struct mutex *lock,
                                    struct mutex_waiter *waiter);
 extern void debug_mutex_wake_waiter(struct mutex *lock,
@@ -35,6 +27,16 @@ extern void debug_mutex_unlock(struct mutex *lock);
 extern void debug_mutex_init(struct mutex *lock, const char *name,
                             struct lock_class_key *key);
 
+static inline void mutex_set_owner(struct mutex *lock)
+{
+       lock->owner = current_thread_info();
+}
+
+static inline void mutex_clear_owner(struct mutex *lock)
+{
+       lock->owner = NULL;
+}
+
 #define spin_lock_mutex(lock, flags)                   \
        do {                                            \
                struct mutex *l = container_of(lock, struct mutex, wait_lock); \
index 4f45d4b658ef6ab1fda9357725b01361a6768a76..5d79781394a306e75048668262a6c3f49f5321ef 100644 (file)
  * Many thanks to Arjan van de Ven, Thomas Gleixner, Steven Rostedt and
  * David Howells for suggestions and improvements.
  *
+ *  - Adaptive spinning for mutexes by Peter Zijlstra. (Ported to mainline
+ *    from the -rt tree, where it was originally implemented for rtmutexes
+ *    by Steven Rostedt, based on work by Gregory Haskins, Peter Morreale
+ *    and Sven Dietrich.
+ *
  * Also see Documentation/mutex-design.txt.
  */
 #include <linux/mutex.h>
@@ -46,6 +51,7 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
        atomic_set(&lock->count, 1);
        spin_lock_init(&lock->wait_lock);
        INIT_LIST_HEAD(&lock->wait_list);
+       mutex_clear_owner(lock);
 
        debug_mutex_init(lock, name, key);
 }
@@ -91,6 +97,7 @@ void inline __sched mutex_lock(struct mutex *lock)
         * 'unlocked' into 'locked' state.
         */
        __mutex_fastpath_lock(&lock->count, __mutex_lock_slowpath);
+       mutex_set_owner(lock);
 }
 
 EXPORT_SYMBOL(mutex_lock);
@@ -115,6 +122,14 @@ void __sched mutex_unlock(struct mutex *lock)
         * The unlocking fastpath is the 0->1 transition from 'locked'
         * into 'unlocked' state:
         */
+#ifndef CONFIG_DEBUG_MUTEXES
+       /*
+        * When debugging is enabled we must not clear the owner before time,
+        * the slow path will always be taken, and that clears the owner field
+        * after verifying that it was indeed current.
+        */
+       mutex_clear_owner(lock);
+#endif
        __mutex_fastpath_unlock(&lock->count, __mutex_unlock_slowpath);
 }
 
@@ -129,21 +144,75 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
 {
        struct task_struct *task = current;
        struct mutex_waiter waiter;
-       unsigned int old_val;
        unsigned long flags;
 
+       preempt_disable();
+       mutex_acquire(&lock->dep_map, subclass, 0, ip);
+#if defined(CONFIG_SMP) && !defined(CONFIG_DEBUG_MUTEXES)
+       /*
+        * Optimistic spinning.
+        *
+        * We try to spin for acquisition when we find that there are no
+        * pending waiters and the lock owner is currently running on a
+        * (different) CPU.
+        *
+        * The rationale is that if the lock owner is running, it is likely to
+        * release the lock soon.
+        *
+        * Since this needs the lock owner, and this mutex implementation
+        * doesn't track the owner atomically in the lock field, we need to
+        * track it non-atomically.
+        *
+        * We can't do this for DEBUG_MUTEXES because that relies on wait_lock
+        * to serialize everything.
+        */
+
+       for (;;) {
+               struct thread_info *owner;
+
+               /*
+                * If there's an owner, wait for it to either
+                * release the lock or go to sleep.
+                */
+               owner = ACCESS_ONCE(lock->owner);
+               if (owner && !mutex_spin_on_owner(lock, owner))
+                       break;
+
+               if (atomic_cmpxchg(&lock->count, 1, 0) == 1) {
+                       lock_acquired(&lock->dep_map, ip);
+                       mutex_set_owner(lock);
+                       preempt_enable();
+                       return 0;
+               }
+
+               /*
+                * When there's no owner, we might have preempted between the
+                * owner acquiring the lock and setting the owner field. If
+                * we're an RT task that will live-lock because we won't let
+                * the owner complete.
+                */
+               if (!owner && (need_resched() || rt_task(task)))
+                       break;
+
+               /*
+                * The cpu_relax() call is a compiler barrier which forces
+                * everything in this loop to be re-loaded. We don't need
+                * memory barriers as we'll eventually observe the right
+                * values at the cost of a few extra spins.
+                */
+               cpu_relax();
+       }
+#endif
        spin_lock_mutex(&lock->wait_lock, flags);
 
        debug_mutex_lock_common(lock, &waiter);
-       mutex_acquire(&lock->dep_map, subclass, 0, ip);
        debug_mutex_add_waiter(lock, &waiter, task_thread_info(task));
 
        /* add waiting tasks to the end of the waitqueue (FIFO): */
        list_add_tail(&waiter.list, &lock->wait_list);
        waiter.task = task;
 
-       old_val = atomic_xchg(&lock->count, -1);
-       if (old_val == 1)
+       if (atomic_xchg(&lock->count, -1) == 1)
                goto done;
 
        lock_contended(&lock->dep_map, ip);
@@ -158,8 +227,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                 * that when we release the lock, we properly wake up the
                 * other waiters:
                 */
-               old_val = atomic_xchg(&lock->count, -1);
-               if (old_val == 1)
+               if (atomic_xchg(&lock->count, -1) == 1)
                        break;
 
                /*
@@ -173,21 +241,22 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                        spin_unlock_mutex(&lock->wait_lock, flags);
 
                        debug_mutex_free_waiter(&waiter);
+                       preempt_enable();
                        return -EINTR;
                }
                __set_task_state(task, state);
 
                /* didnt get the lock, go to sleep: */
                spin_unlock_mutex(&lock->wait_lock, flags);
-               schedule();
+               __schedule();
                spin_lock_mutex(&lock->wait_lock, flags);
        }
 
 done:
        lock_acquired(&lock->dep_map, ip);
        /* got the lock - rejoice! */
-       mutex_remove_waiter(lock, &waiter, task_thread_info(task));
-       debug_mutex_set_owner(lock, task_thread_info(task));
+       mutex_remove_waiter(lock, &waiter, current_thread_info());
+       mutex_set_owner(lock);
 
        /* set it to 0 if there are no waiters left: */
        if (likely(list_empty(&lock->wait_list)))
@@ -196,6 +265,7 @@ done:
        spin_unlock_mutex(&lock->wait_lock, flags);
 
        debug_mutex_free_waiter(&waiter);
+       preempt_enable();
 
        return 0;
 }
@@ -222,7 +292,8 @@ int __sched
 mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass)
 {
        might_sleep();
-       return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, subclass, _RET_IP_);
+       return __mutex_lock_common(lock, TASK_INTERRUPTIBLE,
+                                  subclass, _RET_IP_);
 }
 
 EXPORT_SYMBOL_GPL(mutex_lock_interruptible_nested);
@@ -260,8 +331,6 @@ __mutex_unlock_common_slowpath(atomic_t *lock_count, int nested)
                wake_up_process(waiter->task);
        }
 
-       debug_mutex_clear_owner(lock);
-
        spin_unlock_mutex(&lock->wait_lock, flags);
 }
 
@@ -298,18 +367,30 @@ __mutex_lock_interruptible_slowpath(atomic_t *lock_count);
  */
 int __sched mutex_lock_interruptible(struct mutex *lock)
 {
+       int ret;
+
        might_sleep();
-       return __mutex_fastpath_lock_retval
+       ret =  __mutex_fastpath_lock_retval
                        (&lock->count, __mutex_lock_interruptible_slowpath);
+       if (!ret)
+               mutex_set_owner(lock);
+
+       return ret;
 }
 
 EXPORT_SYMBOL(mutex_lock_interruptible);
 
 int __sched mutex_lock_killable(struct mutex *lock)
 {
+       int ret;
+
        might_sleep();
-       return __mutex_fastpath_lock_retval
+       ret = __mutex_fastpath_lock_retval
                        (&lock->count, __mutex_lock_killable_slowpath);
+       if (!ret)
+               mutex_set_owner(lock);
+
+       return ret;
 }
 EXPORT_SYMBOL(mutex_lock_killable);
 
@@ -352,9 +433,10 @@ static inline int __mutex_trylock_slowpath(atomic_t *lock_count)
 
        prev = atomic_xchg(&lock->count, -1);
        if (likely(prev == 1)) {
-               debug_mutex_set_owner(lock, current_thread_info());
+               mutex_set_owner(lock);
                mutex_acquire(&lock->dep_map, 0, 1, _RET_IP_);
        }
+
        /* Set it back to 0 if there are no waiters: */
        if (likely(list_empty(&lock->wait_list)))
                atomic_set(&lock->count, 0);
@@ -380,8 +462,13 @@ static inline int __mutex_trylock_slowpath(atomic_t *lock_count)
  */
 int __sched mutex_trylock(struct mutex *lock)
 {
-       return __mutex_fastpath_trylock(&lock->count,
-                                       __mutex_trylock_slowpath);
+       int ret;
+
+       ret = __mutex_fastpath_trylock(&lock->count, __mutex_trylock_slowpath);
+       if (ret)
+               mutex_set_owner(lock);
+
+       return ret;
 }
 
 EXPORT_SYMBOL(mutex_trylock);
index a075dafbb290c18bdf8972c361d8063f2478fa69..67578ca48f94e1dad6f7cf3760c28d20a86605e2 100644 (file)
 #define mutex_remove_waiter(lock, waiter, ti) \
                __list_del((waiter)->list.prev, (waiter)->list.next)
 
-#define debug_mutex_set_owner(lock, new_owner)         do { } while (0)
-#define debug_mutex_clear_owner(lock)                  do { } while (0)
+#ifdef CONFIG_SMP
+static inline void mutex_set_owner(struct mutex *lock)
+{
+       lock->owner = current_thread_info();
+}
+
+static inline void mutex_clear_owner(struct mutex *lock)
+{
+       lock->owner = NULL;
+}
+#else
+static inline void mutex_set_owner(struct mutex *lock)
+{
+}
+
+static inline void mutex_clear_owner(struct mutex *lock)
+{
+}
+#endif
+
 #define debug_mutex_wake_waiter(lock, waiter)          do { } while (0)
 #define debug_mutex_free_waiter(waiter)                        do { } while (0)
 #define debug_mutex_add_waiter(lock, waiter, ti)       do { } while (0)
index 78bc3fdac0d262f019d1c1c4caee95e9c26aa147..5aa854f9e5ae0cae90d37d7594d265cdbab6fc01 100644 (file)
@@ -34,7 +34,7 @@ int ns_cgroup_clone(struct task_struct *task, struct pid *pid)
 
 /*
  * Rules:
- *   1. you can only enter a cgroup which is a child of your current
+ *   1. you can only enter a cgroup which is a descendant of your current
  *     cgroup
  *   2. you can only place another process into a cgroup if
  *     a. you have CAP_SYS_ADMIN
@@ -45,21 +45,15 @@ int ns_cgroup_clone(struct task_struct *task, struct pid *pid)
 static int ns_can_attach(struct cgroup_subsys *ss,
                struct cgroup *new_cgroup, struct task_struct *task)
 {
-       struct cgroup *orig;
-
        if (current != task) {
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
 
-               if (!cgroup_is_descendant(new_cgroup))
+               if (!cgroup_is_descendant(new_cgroup, current))
                        return -EPERM;
        }
 
-       if (atomic_read(&new_cgroup->count) != 0)
-               return -EPERM;
-
-       orig = task_cgroup(task, ns_subsys_id);
-       if (orig && orig != new_cgroup->parent)
+       if (!cgroup_is_descendant(new_cgroup, task))
                return -EPERM;
 
        return 0;
@@ -77,7 +71,7 @@ static struct cgroup_subsys_state *ns_create(struct cgroup_subsys *ss,
 
        if (!capable(CAP_SYS_ADMIN))
                return ERR_PTR(-EPERM);
-       if (!cgroup_is_descendant(cgroup))
+       if (!cgroup_is_descendant(cgroup, current))
                return ERR_PTR(-EPERM);
 
        ns_cgroup = kzalloc(sizeof(*ns_cgroup), GFP_KERNEL);
index 1b3586fe753afc25a482f92e78b46483d90a369c..b2e5f78fd2812cdc31624583f347853f1d236024 100644 (file)
@@ -403,6 +403,8 @@ struct pid *get_task_pid(struct task_struct *task, enum pid_type type)
 {
        struct pid *pid;
        rcu_read_lock();
+       if (type != PIDTYPE_PID)
+               task = task->group_leader;
        pid = get_pid(task->pids[type].pid);
        rcu_read_unlock();
        return pid;
@@ -450,11 +452,24 @@ pid_t pid_vnr(struct pid *pid)
 }
 EXPORT_SYMBOL_GPL(pid_vnr);
 
-pid_t task_pid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
+pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type,
+                       struct pid_namespace *ns)
 {
-       return pid_nr_ns(task_pid(tsk), ns);
+       pid_t nr = 0;
+
+       rcu_read_lock();
+       if (!ns)
+               ns = current->nsproxy->pid_ns;
+       if (likely(pid_alive(task))) {
+               if (type != PIDTYPE_PID)
+                       task = task->group_leader;
+               nr = pid_nr_ns(task->pids[type].pid, ns);
+       }
+       rcu_read_unlock();
+
+       return nr;
 }
-EXPORT_SYMBOL(task_pid_nr_ns);
+EXPORT_SYMBOL(__task_pid_nr_ns);
 
 pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
 {
@@ -462,18 +477,6 @@ pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
 }
 EXPORT_SYMBOL(task_tgid_nr_ns);
 
-pid_t task_pgrp_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
-{
-       return pid_nr_ns(task_pgrp(tsk), ns);
-}
-EXPORT_SYMBOL(task_pgrp_nr_ns);
-
-pid_t task_session_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
-{
-       return pid_nr_ns(task_session(tsk), ns);
-}
-EXPORT_SYMBOL(task_session_nr_ns);
-
 struct pid_namespace *task_active_pid_ns(struct task_struct *tsk)
 {
        return ns_of_pid(task_pid(tsk));
index fab8ea86fac3f44156b0e3c50c00404080073da6..2d1001b4858de568515ea1f8fce0540afd4a103a 100644 (file)
@@ -152,6 +152,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
 {
        int nr;
        int rc;
+       struct task_struct *task;
 
        /*
         * The last thread in the cgroup-init thread group is terminating.
@@ -169,7 +170,19 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
        read_lock(&tasklist_lock);
        nr = next_pidmap(pid_ns, 1);
        while (nr > 0) {
-               kill_proc_info(SIGKILL, SEND_SIG_PRIV, nr);
+               rcu_read_lock();
+
+               /*
+                * Use force_sig() since it clears SIGNAL_UNKILLABLE ensuring
+                * any nested-container's init processes don't ignore the
+                * signal
+                */
+               task = pid_task(find_vpid(nr), PIDTYPE_PID);
+               if (task)
+                       force_sig(SIGKILL, task);
+
+               rcu_read_unlock();
+
                nr = next_pidmap(pid_ns, nr);
        }
        read_unlock(&tasklist_lock);
index 4a4a206b1979c657c887df31907166080a004d8f..f3db382c2b2d4cf15c4e4f1ae988752b6bc68f81 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/console.h>
 #include <linux/cpu.h>
 #include <linux/freezer.h>
+#include <asm/suspend.h>
 
 #include "power.h"
 
@@ -214,7 +215,7 @@ static int create_image(int platform_mode)
                return error;
 
        device_pm_lock();
-       local_irq_disable();
+
        /* At this point, device_suspend() has been called, but *not*
         * device_power_down(). We *must* call device_power_down() now.
         * Otherwise, drivers for some devices (e.g. interrupt controllers)
@@ -225,13 +226,25 @@ static int create_image(int platform_mode)
        if (error) {
                printk(KERN_ERR "PM: Some devices failed to power down, "
                        "aborting hibernation\n");
-               goto Enable_irqs;
+               goto Unlock;
        }
+
+       error = platform_pre_snapshot(platform_mode);
+       if (error || hibernation_test(TEST_PLATFORM))
+               goto Platform_finish;
+
+       error = disable_nonboot_cpus();
+       if (error || hibernation_test(TEST_CPUS)
+           || hibernation_testmode(HIBERNATION_TEST))
+               goto Enable_cpus;
+
+       local_irq_disable();
+
        sysdev_suspend(PMSG_FREEZE);
        if (error) {
                printk(KERN_ERR "PM: Some devices failed to power down, "
                        "aborting hibernation\n");
-               goto Power_up_devices;
+               goto Enable_irqs;
        }
 
        if (hibernation_test(TEST_CORE))
@@ -247,17 +260,28 @@ static int create_image(int platform_mode)
        restore_processor_state();
        if (!in_suspend)
                platform_leave(platform_mode);
+
  Power_up:
        sysdev_resume();
        /* NOTE:  device_power_up() is just a resume() for devices
         * that suspended with irqs off ... no overall powerup.
         */
- Power_up_devices:
-       device_power_up(in_suspend ?
-               (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
+
  Enable_irqs:
        local_irq_enable();
+
+ Enable_cpus:
+       enable_nonboot_cpus();
+
+ Platform_finish:
+       platform_finish(platform_mode);
+
+       device_power_up(in_suspend ?
+               (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
+
+ Unlock:
        device_pm_unlock();
+
        return error;
 }
 
@@ -291,25 +315,9 @@ int hibernation_snapshot(int platform_mode)
        if (hibernation_test(TEST_DEVICES))
                goto Recover_platform;
 
-       error = platform_pre_snapshot(platform_mode);
-       if (error || hibernation_test(TEST_PLATFORM))
-               goto Finish;
-
-       error = disable_nonboot_cpus();
-       if (!error) {
-               if (hibernation_test(TEST_CPUS))
-                       goto Enable_cpus;
-
-               if (hibernation_testmode(HIBERNATION_TEST))
-                       goto Enable_cpus;
+       error = create_image(platform_mode);
+       /* Control returns here after successful restore */
 
-               error = create_image(platform_mode);
-               /* Control returns here after successful restore */
-       }
- Enable_cpus:
-       enable_nonboot_cpus();
- Finish:
-       platform_finish(platform_mode);
  Resume_devices:
        device_resume(in_suspend ?
                (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
@@ -331,19 +339,33 @@ int hibernation_snapshot(int platform_mode)
  *     kernel.
  */
 
-static int resume_target_kernel(void)
+static int resume_target_kernel(bool platform_mode)
 {
        int error;
 
        device_pm_lock();
-       local_irq_disable();
+
        error = device_power_down(PMSG_QUIESCE);
        if (error) {
                printk(KERN_ERR "PM: Some devices failed to power down, "
                        "aborting resume\n");
-               goto Enable_irqs;
+               goto Unlock;
        }
-       sysdev_suspend(PMSG_QUIESCE);
+
+       error = platform_pre_restore(platform_mode);
+       if (error)
+               goto Cleanup;
+
+       error = disable_nonboot_cpus();
+       if (error)
+               goto Enable_cpus;
+
+       local_irq_disable();
+
+       error = sysdev_suspend(PMSG_QUIESCE);
+       if (error)
+               goto Enable_irqs;
+
        /* We'll ignore saved state, but this gets preempt count (etc) right */
        save_processor_state();
        error = restore_highmem();
@@ -366,11 +388,23 @@ static int resume_target_kernel(void)
        swsusp_free();
        restore_processor_state();
        touch_softlockup_watchdog();
+
        sysdev_resume();
-       device_power_up(PMSG_RECOVER);
+
  Enable_irqs:
        local_irq_enable();
+
+ Enable_cpus:
+       enable_nonboot_cpus();
+
+ Cleanup:
+       platform_restore_cleanup(platform_mode);
+
+       device_power_up(PMSG_RECOVER);
+
+ Unlock:
        device_pm_unlock();
+
        return error;
 }
 
@@ -390,19 +424,10 @@ int hibernation_restore(int platform_mode)
        pm_prepare_console();
        suspend_console();
        error = device_suspend(PMSG_QUIESCE);
-       if (error)
-               goto Finish;
-
-       error = platform_pre_restore(platform_mode);
        if (!error) {
-               error = disable_nonboot_cpus();
-               if (!error)
-                       error = resume_target_kernel();
-               enable_nonboot_cpus();
+               error = resume_target_kernel(platform_mode);
+               device_resume(PMSG_RECOVER);
        }
-       platform_restore_cleanup(platform_mode);
-       device_resume(PMSG_RECOVER);
- Finish:
        resume_console();
        pm_restore_console();
        return error;
@@ -438,38 +463,46 @@ int hibernation_platform_enter(void)
                goto Resume_devices;
        }
 
+       device_pm_lock();
+
+       error = device_power_down(PMSG_HIBERNATE);
+       if (error)
+               goto Unlock;
+
        error = hibernation_ops->prepare();
        if (error)
-               goto Resume_devices;
+               goto Platofrm_finish;
 
        error = disable_nonboot_cpus();
        if (error)
-               goto Finish;
+               goto Platofrm_finish;
 
-       device_pm_lock();
        local_irq_disable();
-       error = device_power_down(PMSG_HIBERNATE);
-       if (!error) {
-               sysdev_suspend(PMSG_HIBERNATE);
-               hibernation_ops->enter();
-               /* We should never get here */
-               while (1);
-       }
-       local_irq_enable();
-       device_pm_unlock();
+       sysdev_suspend(PMSG_HIBERNATE);
+       hibernation_ops->enter();
+       /* We should never get here */
+       while (1);
 
        /*
         * We don't need to reenable the nonboot CPUs or resume consoles, since
         * the system is going to be halted anyway.
         */
Finish:
Platofrm_finish:
        hibernation_ops->finish();
+
+       device_power_up(PMSG_RESTORE);
+
+ Unlock:
+       device_pm_unlock();
+
  Resume_devices:
        entering_platform_hibernation = false;
        device_resume(PMSG_RESTORE);
        resume_console();
+
  Close:
        hibernation_ops->end();
+
        return error;
 }
 
index c9632f841f646fbfc146ecee855fd04068a548ae..f172f41858bb877305082c2e512d59848d6fdced 100644 (file)
@@ -287,17 +287,32 @@ void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
  */
 static int suspend_enter(suspend_state_t state)
 {
-       int error = 0;
+       int error;
 
        device_pm_lock();
-       arch_suspend_disable_irqs();
-       BUG_ON(!irqs_disabled());
 
-       if ((error = device_power_down(PMSG_SUSPEND))) {
+       error = device_power_down(PMSG_SUSPEND);
+       if (error) {
                printk(KERN_ERR "PM: Some devices failed to power down\n");
                goto Done;
        }
 
+       if (suspend_ops->prepare) {
+               error = suspend_ops->prepare();
+               if (error)
+                       goto Power_up_devices;
+       }
+
+       if (suspend_test(TEST_PLATFORM))
+               goto Platfrom_finish;
+
+       error = disable_nonboot_cpus();
+       if (error || suspend_test(TEST_CPUS))
+               goto Enable_cpus;
+
+       arch_suspend_disable_irqs();
+       BUG_ON(!irqs_disabled());
+
        error = sysdev_suspend(PMSG_SUSPEND);
        if (!error) {
                if (!suspend_test(TEST_CORE))
@@ -305,11 +320,22 @@ static int suspend_enter(suspend_state_t state)
                sysdev_resume();
        }
 
-       device_power_up(PMSG_RESUME);
- Done:
        arch_suspend_enable_irqs();
        BUG_ON(irqs_disabled());
+
+ Enable_cpus:
+       enable_nonboot_cpus();
+
+ Platfrom_finish:
+       if (suspend_ops->finish)
+               suspend_ops->finish();
+
+ Power_up_devices:
+       device_power_up(PMSG_RESUME);
+
+ Done:
        device_pm_unlock();
+
        return error;
 }
 
@@ -341,23 +367,8 @@ int suspend_devices_and_enter(suspend_state_t state)
        if (suspend_test(TEST_DEVICES))
                goto Recover_platform;
 
-       if (suspend_ops->prepare) {
-               error = suspend_ops->prepare();
-               if (error)
-                       goto Resume_devices;
-       }
-
-       if (suspend_test(TEST_PLATFORM))
-               goto Finish;
-
-       error = disable_nonboot_cpus();
-       if (!error && !suspend_test(TEST_CPUS))
-               suspend_enter(state);
+       suspend_enter(state);
 
-       enable_nonboot_cpus();
- Finish:
-       if (suspend_ops->finish)
-               suspend_ops->finish();
  Resume_devices:
        suspend_test_start();
        device_resume(PMSG_RESUME);
index f5fc2d7680f26dbbb84aa1af4b9afa68ba7edf8b..33e2e4a819f97014a6e70e5f06d52e246ba783b3 100644 (file)
@@ -321,13 +321,10 @@ static int create_mem_extents(struct list_head *list, gfp_t gfp_mask)
 
        INIT_LIST_HEAD(list);
 
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                unsigned long zone_start, zone_end;
                struct mem_extent *ext, *cur, *aux;
 
-               if (!populated_zone(zone))
-                       continue;
-
                zone_start = zone->zone_start_pfn;
                zone_end = zone->zone_start_pfn + zone->spanned_pages;
 
@@ -804,8 +801,8 @@ static unsigned int count_free_highmem_pages(void)
        struct zone *zone;
        unsigned int cnt = 0;
 
-       for_each_zone(zone)
-               if (populated_zone(zone) && is_highmem(zone))
+       for_each_populated_zone(zone)
+               if (is_highmem(zone))
                        cnt += zone_page_state(zone, NR_FREE_PAGES);
 
        return cnt;
index a92c9145155975b306d52dab08fb095e3af8370e..78c35047586dbaf6ad4766a88e73062a56fde543 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/highmem.h>
 #include <linux/time.h>
 #include <linux/rbtree.h>
+#include <linux/io.h>
 
 #include "power.h"
 
@@ -229,17 +230,16 @@ int swsusp_shrink_memory(void)
                size = count_data_pages() + PAGES_FOR_IO + SPARE_PAGES;
                tmp = size;
                size += highmem_size;
-               for_each_zone (zone)
-                       if (populated_zone(zone)) {
-                               tmp += snapshot_additional_pages(zone);
-                               if (is_highmem(zone)) {
-                                       highmem_size -=
+               for_each_populated_zone(zone) {
+                       tmp += snapshot_additional_pages(zone);
+                       if (is_highmem(zone)) {
+                               highmem_size -=
                                        zone_page_state(zone, NR_FREE_PAGES);
-                               } else {
-                                       tmp -= zone_page_state(zone, NR_FREE_PAGES);
-                                       tmp += zone->lowmem_reserve[ZONE_NORMAL];
-                               }
+                       } else {
+                               tmp -= zone_page_state(zone, NR_FREE_PAGES);
+                               tmp += zone->lowmem_reserve[ZONE_NORMAL];
                        }
+               }
 
                if (highmem_size < 0)
                        highmem_size = 0;
index e3602d0755b0dd99c9fb47887fd67d371cdd5424..a5f61a9acedb3cfd72a7d87a29317f9f146d896d 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/security.h>
 #include <linux/bootmem.h>
 #include <linux/syscalls.h>
+#include <linux/kexec.h>
 
 #include <asm/uaccess.h>
 
@@ -135,6 +136,24 @@ static char *log_buf = __log_buf;
 static int log_buf_len = __LOG_BUF_LEN;
 static unsigned logged_chars; /* Number of chars produced since last read+clear operation */
 
+#ifdef CONFIG_KEXEC
+/*
+ * This appends the listed symbols to /proc/vmcoreinfo
+ *
+ * /proc/vmcoreinfo is used by various utiilties, like crash and makedumpfile to
+ * obtain access to symbols that are otherwise very difficult to locate.  These
+ * symbols are specifically used so that utilities can access and extract the
+ * dmesg log from a vmcore file after a crash.
+ */
+void log_buf_kexec_setup(void)
+{
+       VMCOREINFO_SYMBOL(log_buf);
+       VMCOREINFO_SYMBOL(log_end);
+       VMCOREINFO_SYMBOL(log_buf_len);
+       VMCOREINFO_SYMBOL(logged_chars);
+}
+#endif
+
 static int __init log_buf_len_setup(char *str)
 {
        unsigned size = memparse(str, &str);
index c9cf48b21f052a620b34151cc9de6c4b48f4ad66..5105f5a6a2ce3d843affaed6130ef5eb873db87f 100644 (file)
@@ -60,11 +60,15 @@ static void ptrace_untrace(struct task_struct *child)
 {
        spin_lock(&child->sighand->siglock);
        if (task_is_traced(child)) {
-               if (child->signal->flags & SIGNAL_STOP_STOPPED) {
+               /*
+                * If the group stop is completed or in progress,
+                * this thread was already counted as stopped.
+                */
+               if (child->signal->flags & SIGNAL_STOP_STOPPED ||
+                   child->signal->group_stop_count)
                        __set_task_state(child, TASK_STOPPED);
-               } else {
+               else
                        signal_wake_up(child, 1);
-               }
        }
        spin_unlock(&child->sighand->siglock);
 }
@@ -235,18 +239,58 @@ out:
        return retval;
 }
 
-static inline void __ptrace_detach(struct task_struct *child, unsigned int data)
+/*
+ * Called with irqs disabled, returns true if childs should reap themselves.
+ */
+static int ignoring_children(struct sighand_struct *sigh)
 {
-       child->exit_code = data;
-       /* .. re-parent .. */
-       __ptrace_unlink(child);
-       /* .. and wake it up. */
-       if (child->exit_state != EXIT_ZOMBIE)
-               wake_up_process(child);
+       int ret;
+       spin_lock(&sigh->siglock);
+       ret = (sigh->action[SIGCHLD-1].sa.sa_handler == SIG_IGN) ||
+             (sigh->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT);
+       spin_unlock(&sigh->siglock);
+       return ret;
+}
+
+/*
+ * Called with tasklist_lock held for writing.
+ * Unlink a traced task, and clean it up if it was a traced zombie.
+ * Return true if it needs to be reaped with release_task().
+ * (We can't call release_task() here because we already hold tasklist_lock.)
+ *
+ * If it's a zombie, our attachedness prevented normal parent notification
+ * or self-reaping.  Do notification now if it would have happened earlier.
+ * If it should reap itself, return true.
+ *
+ * If it's our own child, there is no notification to do.
+ * But if our normal children self-reap, then this child
+ * was prevented by ptrace and we must reap it now.
+ */
+static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p)
+{
+       __ptrace_unlink(p);
+
+       if (p->exit_state == EXIT_ZOMBIE) {
+               if (!task_detached(p) && thread_group_empty(p)) {
+                       if (!same_thread_group(p->real_parent, tracer))
+                               do_notify_parent(p, p->exit_signal);
+                       else if (ignoring_children(tracer->sighand))
+                               p->exit_signal = -1;
+               }
+               if (task_detached(p)) {
+                       /* Mark it as in the process of being reaped. */
+                       p->exit_state = EXIT_DEAD;
+                       return true;
+               }
+       }
+
+       return false;
 }
 
 int ptrace_detach(struct task_struct *child, unsigned int data)
 {
+       bool dead = false;
+
        if (!valid_signal(data))
                return -EIO;
 
@@ -255,14 +299,45 @@ int ptrace_detach(struct task_struct *child, unsigned int data)
        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 
        write_lock_irq(&tasklist_lock);
-       /* protect against de_thread()->release_task() */
-       if (child->ptrace)
-               __ptrace_detach(child, data);
+       /*
+        * This child can be already killed. Make sure de_thread() or
+        * our sub-thread doing do_wait() didn't do release_task() yet.
+        */
+       if (child->ptrace) {
+               child->exit_code = data;
+               dead = __ptrace_detach(current, child);
+       }
        write_unlock_irq(&tasklist_lock);
 
+       if (unlikely(dead))
+               release_task(child);
+
        return 0;
 }
 
+/*
+ * Detach all tasks we were using ptrace on.
+ */
+void exit_ptrace(struct task_struct *tracer)
+{
+       struct task_struct *p, *n;
+       LIST_HEAD(ptrace_dead);
+
+       write_lock_irq(&tasklist_lock);
+       list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) {
+               if (__ptrace_detach(tracer, p))
+                       list_add(&p->ptrace_entry, &ptrace_dead);
+       }
+       write_unlock_irq(&tasklist_lock);
+
+       BUG_ON(!list_empty(&tracer->ptraced));
+
+       list_for_each_entry_safe(p, n, &ptrace_dead, ptrace_entry) {
+               list_del_init(&p->ptrace_entry);
+               release_task(p);
+       }
+}
+
 int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
 {
        int copied = 0;
index 7c4142a79f0ab5a2ef80300b3d5be3188bdec8c7..9b4a975a4b4afc1f1eba22c1cb30d21aef844959 100644 (file)
@@ -126,6 +126,7 @@ static atomic_t n_rcu_torture_mberror;
 static atomic_t n_rcu_torture_error;
 static long n_rcu_torture_timers = 0;
 static struct list_head rcu_torture_removed;
+static cpumask_var_t shuffle_tmp_mask;
 
 static int stutter_pause_test = 0;
 
@@ -889,10 +890,9 @@ static int rcu_idle_cpu;   /* Force all torture tasks off this CPU */
  */
 static void rcu_torture_shuffle_tasks(void)
 {
-       cpumask_t tmp_mask;
        int i;
 
-       cpus_setall(tmp_mask);
+       cpumask_setall(shuffle_tmp_mask);
        get_online_cpus();
 
        /* No point in shuffling if there is only one online CPU (ex: UP) */
@@ -902,29 +902,29 @@ static void rcu_torture_shuffle_tasks(void)
        }
 
        if (rcu_idle_cpu != -1)
-               cpu_clear(rcu_idle_cpu, tmp_mask);
+               cpumask_clear_cpu(rcu_idle_cpu, shuffle_tmp_mask);
 
-       set_cpus_allowed_ptr(current, &tmp_mask);
+       set_cpus_allowed_ptr(current, shuffle_tmp_mask);
 
        if (reader_tasks) {
                for (i = 0; i < nrealreaders; i++)
                        if (reader_tasks[i])
                                set_cpus_allowed_ptr(reader_tasks[i],
-                                                    &tmp_mask);
+                                                    shuffle_tmp_mask);
        }
 
        if (fakewriter_tasks) {
                for (i = 0; i < nfakewriters; i++)
                        if (fakewriter_tasks[i])
                                set_cpus_allowed_ptr(fakewriter_tasks[i],
-                                                    &tmp_mask);
+                                                    shuffle_tmp_mask);
        }
 
        if (writer_task)
-               set_cpus_allowed_ptr(writer_task, &tmp_mask);
+               set_cpus_allowed_ptr(writer_task, shuffle_tmp_mask);
 
        if (stats_task)
-               set_cpus_allowed_ptr(stats_task, &tmp_mask);
+               set_cpus_allowed_ptr(stats_task, shuffle_tmp_mask);
 
        if (rcu_idle_cpu == -1)
                rcu_idle_cpu = num_online_cpus() - 1;
@@ -1012,6 +1012,7 @@ rcu_torture_cleanup(void)
        if (shuffler_task) {
                VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task");
                kthread_stop(shuffler_task);
+               free_cpumask_var(shuffle_tmp_mask);
        }
        shuffler_task = NULL;
 
@@ -1190,10 +1191,18 @@ rcu_torture_init(void)
        }
        if (test_no_idle_hz) {
                rcu_idle_cpu = num_online_cpus() - 1;
+
+               if (!alloc_cpumask_var(&shuffle_tmp_mask, GFP_KERNEL)) {
+                       firsterr = -ENOMEM;
+                       VERBOSE_PRINTK_ERRSTRING("Failed to alloc mask");
+                       goto unwind;
+               }
+
                /* Create the shuffler thread */
                shuffler_task = kthread_run(rcu_torture_shuffle, NULL,
                                          "rcu_torture_shuffle");
                if (IS_ERR(shuffler_task)) {
+                       free_cpumask_var(shuffle_tmp_mask);
                        firsterr = PTR_ERR(shuffler_task);
                        VERBOSE_PRINTK_ERRSTRING("Failed to create shuffler");
                        shuffler_task = NULL;
index 8f2179c8056ff9f9de0b2679588d86589393b508..e92db8c06acf86a340a865d1f5965001ea9c0d70 100644 (file)
@@ -797,13 +797,15 @@ void relay_subbufs_consumed(struct rchan *chan,
        if (!chan)
                return;
 
-       if (cpu >= NR_CPUS || !chan->buf[cpu])
+       if (cpu >= NR_CPUS || !chan->buf[cpu] ||
+                                       subbufs_consumed > chan->n_subbufs)
                return;
 
        buf = chan->buf[cpu];
-       buf->subbufs_consumed += subbufs_consumed;
-       if (buf->subbufs_consumed > buf->subbufs_produced)
+       if (subbufs_consumed > buf->subbufs_produced - buf->subbufs_consumed)
                buf->subbufs_consumed = buf->subbufs_produced;
+       else
+               buf->subbufs_consumed += subbufs_consumed;
 }
 EXPORT_SYMBOL_GPL(relay_subbufs_consumed);
 
index f4c413bdd38d790e10957e970edc02657c245670..73513f4e19df1b9683d5929c926c63fb8663e3e1 100644 (file)
@@ -3190,7 +3190,7 @@ static int move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest,
        return 0;
 }
 /********** Helpers for find_busiest_group ************************/
-/**
+/*
  * sd_lb_stats - Structure to store the statistics of a sched_domain
  *             during load balancing.
  */
@@ -3222,7 +3222,7 @@ struct sd_lb_stats {
 #endif
 };
 
-/**
+/*
  * sg_lb_stats - stats of a sched_group required for load_balancing
  */
 struct sg_lb_stats {
@@ -3360,16 +3360,17 @@ static inline void update_sd_power_savings_stats(struct sched_group *group,
 }
 
 /**
- * check_power_save_busiest_group - Check if we have potential to perform
- *     some power-savings balance. If yes, set the busiest group to be
- *     the least loaded group in the sched_domain, so that it's CPUs can
- *     be put to idle.
- *
+ * check_power_save_busiest_group - see if there is potential for some power-savings balance
  * @sds: Variable containing the statistics of the sched_domain
  *     under consideration.
  * @this_cpu: Cpu at which we're currently performing load-balancing.
  * @imbalance: Variable to store the imbalance.
  *
+ * Description:
+ * Check if we have potential to perform some power-savings balance.
+ * If yes, set the busiest group to be the least loaded group in the
+ * sched_domain, so that it's CPUs can be put to idle.
+ *
  * Returns 1 if there is potential to perform power-savings balance.
  * Else returns 0.
  */
@@ -4941,15 +4942,13 @@ pick_next_task(struct rq *rq)
 /*
  * schedule() is the main scheduler function.
  */
-asmlinkage void __sched schedule(void)
+asmlinkage void __sched __schedule(void)
 {
        struct task_struct *prev, *next;
        unsigned long *switch_count;
        struct rq *rq;
        int cpu;
 
-need_resched:
-       preempt_disable();
        cpu = smp_processor_id();
        rq = cpu_rq(cpu);
        rcu_qsctr_inc(cpu);
@@ -5006,13 +5005,80 @@ need_resched_nonpreemptible:
 
        if (unlikely(reacquire_kernel_lock(current) < 0))
                goto need_resched_nonpreemptible;
+}
 
+asmlinkage void __sched schedule(void)
+{
+need_resched:
+       preempt_disable();
+       __schedule();
        preempt_enable_no_resched();
        if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
                goto need_resched;
 }
 EXPORT_SYMBOL(schedule);
 
+#ifdef CONFIG_SMP
+/*
+ * Look out! "owner" is an entirely speculative pointer
+ * access and not reliable.
+ */
+int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner)
+{
+       unsigned int cpu;
+       struct rq *rq;
+
+       if (!sched_feat(OWNER_SPIN))
+               return 0;
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+       /*
+        * Need to access the cpu field knowing that
+        * DEBUG_PAGEALLOC could have unmapped it if
+        * the mutex owner just released it and exited.
+        */
+       if (probe_kernel_address(&owner->cpu, cpu))
+               goto out;
+#else
+       cpu = owner->cpu;
+#endif
+
+       /*
+        * Even if the access succeeded (likely case),
+        * the cpu field may no longer be valid.
+        */
+       if (cpu >= nr_cpumask_bits)
+               goto out;
+
+       /*
+        * We need to validate that we can do a
+        * get_cpu() and that we have the percpu area.
+        */
+       if (!cpu_online(cpu))
+               goto out;
+
+       rq = cpu_rq(cpu);
+
+       for (;;) {
+               /*
+                * Owner changed, break to re-assess state.
+                */
+               if (lock->owner != owner)
+                       break;
+
+               /*
+                * Is that owner really running on that cpu?
+                */
+               if (task_thread_info(rq->curr) != owner || need_resched())
+                       return 0;
+
+               cpu_relax();
+       }
+out:
+       return 1;
+}
+#endif
+
 #ifdef CONFIG_PREEMPT
 /*
  * this is the entry point to schedule() from in-kernel preemption
@@ -5130,11 +5196,17 @@ void __wake_up_locked(wait_queue_head_t *q, unsigned int mode)
        __wake_up_common(q, mode, 1, 0, NULL);
 }
 
+void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key)
+{
+       __wake_up_common(q, mode, 1, 0, key);
+}
+
 /**
- * __wake_up_sync - wake up threads blocked on a waitqueue.
+ * __wake_up_sync_key - wake up threads blocked on a waitqueue.
  * @q: the waitqueue
  * @mode: which threads
  * @nr_exclusive: how many wake-one or wake-many threads to wake up
+ * @key: opaque value to be passed to wakeup targets
  *
  * The sync wakeup differs that the waker knows that it will schedule
  * away soon, so while the target thread will be woken up, it will not
@@ -5143,8 +5215,8 @@ void __wake_up_locked(wait_queue_head_t *q, unsigned int mode)
  *
  * On UP it can prevent extra preemption.
  */
-void
-__wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
+void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode,
+                       int nr_exclusive, void *key)
 {
        unsigned long flags;
        int sync = 1;
@@ -5156,9 +5228,18 @@ __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
                sync = 0;
 
        spin_lock_irqsave(&q->lock, flags);
-       __wake_up_common(q, mode, nr_exclusive, sync, NULL);
+       __wake_up_common(q, mode, nr_exclusive, sync, key);
        spin_unlock_irqrestore(&q->lock, flags);
 }
+EXPORT_SYMBOL_GPL(__wake_up_sync_key);
+
+/*
+ * __wake_up_sync - see __wake_up_sync_key()
+ */
+void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
+{
+       __wake_up_sync_key(q, mode, nr_exclusive, NULL);
+}
 EXPORT_SYMBOL_GPL(__wake_up_sync);     /* For internal use only */
 
 /**
index 642a94ef8a0a7fb39f9b341eb292dfad9ab38762..9a7e859b8fbfdd753f09a4bc0949cf5345e2ae75 100644 (file)
@@ -25,7 +25,7 @@ struct cpupri {
 
 #ifdef CONFIG_SMP
 int  cpupri_find(struct cpupri *cp,
-                struct task_struct *p, cpumask_t *lowest_mask);
+                struct task_struct *p, struct cpumask *lowest_mask);
 void cpupri_set(struct cpupri *cp, int cpu, int pri);
 int cpupri_init(struct cpupri *cp, bool bootmem);
 void cpupri_cleanup(struct cpupri *cp);
index 76f61756e677647dda4ae01ede5ac942329a09c8..4569bfa7df9b9fee6f057e22aca18299d3c45f3b 100644 (file)
@@ -14,3 +14,4 @@ SCHED_FEAT(LB_WAKEUP_UPDATE, 1)
 SCHED_FEAT(ASYM_EFF_LOAD, 1)
 SCHED_FEAT(WAKEUP_OVERLAP, 0)
 SCHED_FEAT(LAST_BUDDY, 1)
+SCHED_FEAT(OWNER_SPIN, 1)
index 1c8814481a117d5df731465b5a56bbf4738c48c1..d8034737db4cb86f8adca044560a3765ac65dba5 100644 (file)
@@ -55,10 +55,22 @@ static int sig_handler_ignored(void __user *handler, int sig)
                (handler == SIG_DFL && sig_kernel_ignore(sig));
 }
 
-static int sig_ignored(struct task_struct *t, int sig)
+static int sig_task_ignored(struct task_struct *t, int sig,
+               int from_ancestor_ns)
 {
        void __user *handler;
 
+       handler = sig_handler(t, sig);
+
+       if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) &&
+                       handler == SIG_DFL && !from_ancestor_ns)
+               return 1;
+
+       return sig_handler_ignored(handler, sig);
+}
+
+static int sig_ignored(struct task_struct *t, int sig, int from_ancestor_ns)
+{
        /*
         * Blocked signals are never ignored, since the
         * signal handler may change by the time it is
@@ -67,14 +79,13 @@ static int sig_ignored(struct task_struct *t, int sig)
        if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig))
                return 0;
 
-       handler = sig_handler(t, sig);
-       if (!sig_handler_ignored(handler, sig))
+       if (!sig_task_ignored(t, sig, from_ancestor_ns))
                return 0;
 
        /*
         * Tracers may want to know about even ignored signals.
         */
-       return !tracehook_consider_ignored_signal(t, sig, handler);
+       return !tracehook_consider_ignored_signal(t, sig);
 }
 
 /*
@@ -318,7 +329,7 @@ int unhandled_signal(struct task_struct *tsk, int sig)
                return 1;
        if (handler != SIG_IGN && handler != SIG_DFL)
                return 0;
-       return !tracehook_consider_fatal_signal(tsk, sig, handler);
+       return !tracehook_consider_fatal_signal(tsk, sig);
 }
 
 
@@ -624,7 +635,7 @@ static int check_kill_permission(int sig, struct siginfo *info,
  * Returns true if the signal should be actually delivered, otherwise
  * it should be dropped.
  */
-static int prepare_signal(int sig, struct task_struct *p)
+static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns)
 {
        struct signal_struct *signal = p->signal;
        struct task_struct *t;
@@ -708,7 +719,7 @@ static int prepare_signal(int sig, struct task_struct *p)
                }
        }
 
-       return !sig_ignored(p, sig);
+       return !sig_ignored(p, sig, from_ancestor_ns);
 }
 
 /*
@@ -777,7 +788,7 @@ static void complete_signal(int sig, struct task_struct *p, int group)
            !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) &&
            !sigismember(&t->real_blocked, sig) &&
            (sig == SIGKILL ||
-            !tracehook_consider_fatal_signal(t, sig, SIG_DFL))) {
+            !tracehook_consider_fatal_signal(t, sig))) {
                /*
                 * This signal will be fatal to the whole group.
                 */
@@ -813,8 +824,8 @@ static inline int legacy_queue(struct sigpending *signals, int sig)
        return (sig < SIGRTMIN) && sigismember(&signals->signal, sig);
 }
 
-static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
-                       int group)
+static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
+                       int group, int from_ancestor_ns)
 {
        struct sigpending *pending;
        struct sigqueue *q;
@@ -822,7 +833,8 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
        trace_sched_signal_send(sig, t);
 
        assert_spin_locked(&t->sighand->siglock);
-       if (!prepare_signal(sig, t))
+
+       if (!prepare_signal(sig, t, from_ancestor_ns))
                return 0;
 
        pending = group ? &t->signal->shared_pending : &t->pending;
@@ -871,6 +883,8 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
                        break;
                default:
                        copy_siginfo(&q->info, info);
+                       if (from_ancestor_ns)
+                               q->info.si_pid = 0;
                        break;
                }
        } else if (!is_si_special(info)) {
@@ -889,6 +903,20 @@ out_set:
        return 0;
 }
 
+static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
+                       int group)
+{
+       int from_ancestor_ns = 0;
+
+#ifdef CONFIG_PID_NS
+       if (!is_si_special(info) && SI_FROMUSER(info) &&
+                       task_pid_nr_ns(current, task_active_pid_ns(t)) <= 0)
+               from_ancestor_ns = 1;
+#endif
+
+       return __send_signal(sig, info, t, group, from_ancestor_ns);
+}
+
 int print_fatal_signals;
 
 static void print_fatal_signal(struct pt_regs *regs, int signr)
@@ -1133,7 +1161,7 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
        if (sig && p->sighand) {
                unsigned long flags;
                spin_lock_irqsave(&p->sighand->siglock, flags);
-               ret = __group_send_sig_info(sig, info, p);
+               ret = __send_signal(sig, info, p, 1, 0);
                spin_unlock_irqrestore(&p->sighand->siglock, flags);
        }
 out_unlock:
@@ -1320,7 +1348,7 @@ int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)
                goto ret;
 
        ret = 1; /* the signal is ignored */
-       if (!prepare_signal(sig, t))
+       if (!prepare_signal(sig, t, 0))
                goto out;
 
        ret = 0;
@@ -1844,9 +1872,16 @@ relock:
 
                /*
                 * Global init gets no signals it doesn't want.
+                * Container-init gets no signals it doesn't want from same
+                * container.
+                *
+                * Note that if global/container-init sees a sig_kernel_only()
+                * signal here, the signal must have been generated internally
+                * or must have come from an ancestor namespace. In either
+                * case, the signal cannot be dropped.
                 */
                if (unlikely(signal->flags & SIGNAL_UNKILLABLE) &&
-                   !signal_group_exit(signal))
+                               !sig_kernel_only(signr))
                        continue;
 
                if (sig_kernel_stop(signr)) {
index 29ab20749dd3da1df6bd6f03f5cdbf62ed9ae52e..7932653c4ebde88e7010ec1da9601ef974e8c3bb 100644 (file)
@@ -121,7 +121,8 @@ unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock)
        local_irq_save(flags);
        preempt_disable();
        rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
-       LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
+       LOCK_CONTENDED_FLAGS(lock, _raw_read_trylock, _raw_read_lock,
+                            _raw_read_lock_flags, &flags);
        return flags;
 }
 EXPORT_SYMBOL(_read_lock_irqsave);
@@ -151,7 +152,8 @@ unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock)
        local_irq_save(flags);
        preempt_disable();
        rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
-       LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);
+       LOCK_CONTENDED_FLAGS(lock, _raw_write_trylock, _raw_write_lock,
+                            _raw_write_lock_flags, &flags);
        return flags;
 }
 EXPORT_SYMBOL(_write_lock_irqsave);
@@ -299,16 +301,8 @@ unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclas
        local_irq_save(flags);
        preempt_disable();
        spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
-       /*
-        * On lockdep we dont want the hand-coded irq-enable of
-        * _raw_spin_lock_flags() code, because lockdep assumes
-        * that interrupts are not re-enabled during lock-acquire:
-        */
-#ifdef CONFIG_LOCKDEP
-       LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
-#else
-       _raw_spin_lock_flags(lock, &flags);
-#endif
+       LOCK_CONTENDED_FLAGS(lock, _raw_spin_trylock, _raw_spin_lock,
+                               _raw_spin_lock_flags, &flags);
        return flags;
 }
 EXPORT_SYMBOL(_spin_lock_irqsave_nested);
index 74541ca49536fda5dab61d473f8ce9d6aa3f3254..912823e2a11b0afb0f4448e5163bb9e39c7fc8b8 100644 (file)
@@ -44,7 +44,7 @@ static DEFINE_MUTEX(setup_lock);
 static int refcount;
 static struct workqueue_struct *stop_machine_wq;
 static struct stop_machine_data active, idle;
-static const cpumask_t *active_cpus;
+static const struct cpumask *active_cpus;
 static void *stop_machine_work;
 
 static void set_state(enum stopmachine_state newstate)
index 37f458e6882adbd1f2b0697e5077c92e4252e03f..742cefa527e67e1f4b42d55abcb76bbbebadbbfe 100644 (file)
@@ -1013,10 +1013,8 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid)
        if (err)
                goto out;
 
-       if (task_pgrp(p) != pgrp) {
+       if (task_pgrp(p) != pgrp)
                change_pid(p, PIDTYPE_PGID, pgrp);
-               set_task_pgrp(p, pid_nr(pgrp));
-       }
 
        err = 0;
 out:
index c5ef44ff850f5af111943d76a5484318d6a5bc35..5ec4543dfc06513d20e288f8a19e06068b65e7f9 100644 (file)
@@ -95,12 +95,9 @@ static int sixty = 60;
 static int neg_one = -1;
 #endif
 
-#if defined(CONFIG_MMU) && defined(CONFIG_FILE_LOCKING)
-static int two = 2;
-#endif
-
 static int zero;
 static int one = 1;
+static int two = 2;
 static unsigned long one_ul = 1;
 static int one_hundred = 100;
 
@@ -1010,7 +1007,7 @@ static struct ctl_table vm_table[] = {
                .data           = &dirty_expire_interval,
                .maxlen         = sizeof(dirty_expire_interval),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_userhz_jiffies,
+               .proc_handler   = &proc_dointvec,
        },
        {
                .ctl_name       = VM_NR_PDFLUSH_THREADS,
@@ -1373,10 +1370,7 @@ static struct ctl_table fs_table[] = {
                .data           = &lease_break_time,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
-               .extra1         = &zero,
-               .extra2         = &two,
+               .proc_handler   = &proc_dointvec,
        },
 #endif
 #ifdef CONFIG_AIO
@@ -1417,7 +1411,10 @@ static struct ctl_table fs_table[] = {
                .data           = &suid_dumpable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &zero,
+               .extra2         = &two,
        },
 #if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE)
        {
index 9b77fc9a9ac8286074b1784771dac7c0eb2a08e2..b4555568b4e4ad16f34a887eabed6f21e05abfba 100644 (file)
@@ -491,14 +491,18 @@ static inline void debug_timer_free(struct timer_list *timer)
        debug_object_free(timer, &timer_debug_descr);
 }
 
-static void __init_timer(struct timer_list *timer);
+static void __init_timer(struct timer_list *timer,
+                        const char *name,
+                        struct lock_class_key *key);
 
-void init_timer_on_stack(struct timer_list *timer)
+void init_timer_on_stack_key(struct timer_list *timer,
+                            const char *name,
+                            struct lock_class_key *key)
 {
        debug_object_init_on_stack(timer, &timer_debug_descr);
-       __init_timer(timer);
+       __init_timer(timer, name, key);
 }
-EXPORT_SYMBOL_GPL(init_timer_on_stack);
+EXPORT_SYMBOL_GPL(init_timer_on_stack_key);
 
 void destroy_timer_on_stack(struct timer_list *timer)
 {
@@ -512,7 +516,9 @@ static inline void debug_timer_activate(struct timer_list *timer) { }
 static inline void debug_timer_deactivate(struct timer_list *timer) { }
 #endif
 
-static void __init_timer(struct timer_list *timer)
+static void __init_timer(struct timer_list *timer,
+                        const char *name,
+                        struct lock_class_key *key)
 {
        timer->entry.next = NULL;
        timer->base = __raw_get_cpu_var(tvec_bases);
@@ -521,6 +527,7 @@ static void __init_timer(struct timer_list *timer)
        timer->start_pid = -1;
        memset(timer->start_comm, 0, TASK_COMM_LEN);
 #endif
+       lockdep_init_map(&timer->lockdep_map, name, key, 0);
 }
 
 /**
@@ -530,19 +537,23 @@ static void __init_timer(struct timer_list *timer)
  * init_timer() must be done to a timer prior calling *any* of the
  * other timer functions.
  */
-void init_timer(struct timer_list *timer)
+void init_timer_key(struct timer_list *timer,
+                   const char *name,
+                   struct lock_class_key *key)
 {
        debug_timer_init(timer);
-       __init_timer(timer);
+       __init_timer(timer, name, key);
 }
-EXPORT_SYMBOL(init_timer);
+EXPORT_SYMBOL(init_timer_key);
 
-void init_timer_deferrable(struct timer_list *timer)
+void init_timer_deferrable_key(struct timer_list *timer,
+                              const char *name,
+                              struct lock_class_key *key)
 {
-       init_timer(timer);
+       init_timer_key(timer, name, key);
        timer_set_deferrable(timer);
 }
-EXPORT_SYMBOL(init_timer_deferrable);
+EXPORT_SYMBOL(init_timer_deferrable_key);
 
 static inline void detach_timer(struct timer_list *timer,
                                int clear_pending)
@@ -826,6 +837,15 @@ EXPORT_SYMBOL(try_to_del_timer_sync);
  */
 int del_timer_sync(struct timer_list *timer)
 {
+#ifdef CONFIG_LOCKDEP
+       unsigned long flags;
+
+       local_irq_save(flags);
+       lock_map_acquire(&timer->lockdep_map);
+       lock_map_release(&timer->lockdep_map);
+       local_irq_restore(flags);
+#endif
+
        for (;;) {
                int ret = try_to_del_timer_sync(timer);
                if (ret >= 0)
@@ -897,10 +917,36 @@ static inline void __run_timers(struct tvec_base *base)
 
                        set_running_timer(base, timer);
                        detach_timer(timer, 1);
+
                        spin_unlock_irq(&base->lock);
                        {
                                int preempt_count = preempt_count();
+
+#ifdef CONFIG_LOCKDEP
+                               /*
+                                * It is permissible to free the timer from
+                                * inside the function that is called from
+                                * it, this we need to take into account for
+                                * lockdep too. To avoid bogus "held lock
+                                * freed" warnings as well as problems when
+                                * looking into timer->lockdep_map, make a
+                                * copy and use that here.
+                                */
+                               struct lockdep_map lockdep_map =
+                                       timer->lockdep_map;
+#endif
+                               /*
+                                * Couple the lock chain with the lock chain at
+                                * del_timer_sync() by acquiring the lock_map
+                                * around the fn() call here and in
+                                * del_timer_sync().
+                                */
+                               lock_map_acquire(&lockdep_map);
+
                                fn(data);
+
+                               lock_map_release(&lockdep_map);
+
                                if (preempt_count != preempt_count()) {
                                        printk(KERN_ERR "huh, entered %p "
                                               "with preempt_count %08x, exited"
index 930c08e5b38e0d35ab93b79896b0150907d31e50..dce71a5b51bce5a953b5000628bbf1c58dc37cff 100644 (file)
@@ -42,6 +42,81 @@ static struct tracer_flags tracer_flags = {
 /* pid on the last trace processed */
 static pid_t last_pid[NR_CPUS] = { [0 ... NR_CPUS-1] = -1 };
 
+/* Add a function return address to the trace stack on thread info.*/
+int
+ftrace_push_return_trace(unsigned long ret, unsigned long long time,
+                        unsigned long func, int *depth)
+{
+       int index;
+
+       if (!current->ret_stack)
+               return -EBUSY;
+
+       /* The return trace stack is full */
+       if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) {
+               atomic_inc(&current->trace_overrun);
+               return -EBUSY;
+       }
+
+       index = ++current->curr_ret_stack;
+       barrier();
+       current->ret_stack[index].ret = ret;
+       current->ret_stack[index].func = func;
+       current->ret_stack[index].calltime = time;
+       *depth = index;
+
+       return 0;
+}
+
+/* Retrieve a function return address to the trace stack on thread info.*/
+void
+ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret)
+{
+       int index;
+
+       index = current->curr_ret_stack;
+
+       if (unlikely(index < 0)) {
+               ftrace_graph_stop();
+               WARN_ON(1);
+               /* Might as well panic, otherwise we have no where to go */
+               *ret = (unsigned long)panic;
+               return;
+       }
+
+       *ret = current->ret_stack[index].ret;
+       trace->func = current->ret_stack[index].func;
+       trace->calltime = current->ret_stack[index].calltime;
+       trace->overrun = atomic_read(&current->trace_overrun);
+       trace->depth = index;
+       barrier();
+       current->curr_ret_stack--;
+
+}
+
+/*
+ * Send the trace to the ring-buffer.
+ * @return the original return address.
+ */
+unsigned long ftrace_return_to_handler(void)
+{
+       struct ftrace_graph_ret trace;
+       unsigned long ret;
+
+       ftrace_pop_return_trace(&trace, &ret);
+       trace.rettime = cpu_clock(raw_smp_processor_id());
+       ftrace_graph_return(&trace);
+
+       if (unlikely(!ret)) {
+               ftrace_graph_stop();
+               WARN_ON(1);
+               /* Might as well panic. What else to do? */
+               ret = (unsigned long)panic;
+       }
+
+       return ret;
+}
+
 static int graph_trace_init(struct trace_array *tr)
 {
        int cpu, ret;
index 3b34b3545936dfcd179eca7f9fd2aebf4a2abfa0..92359cc747a7c52cb85e362ab3b9178e4756ee2d 100644 (file)
@@ -37,7 +37,7 @@ static void put_uts(ctl_table *table, int write, void *which)
                up_write(&uts_sem);
 }
 
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_PROC_SYSCTL
 /*
  *     Special case of dostring for the UTS structure. This has locks
  *     to observe. Should this be in kernel/sys.c ????
index 1f0c509b40d34d944bea77e300e237ab9145439c..32f8e0d2bf5ad2d629b63432e654f2948949420a 100644 (file)
@@ -48,8 +48,6 @@ struct cpu_workqueue_struct {
 
        struct workqueue_struct *wq;
        struct task_struct *thread;
-
-       int run_depth;          /* Detect run_workqueue() recursion depth */
 } ____cacheline_aligned;
 
 /*
@@ -262,13 +260,6 @@ EXPORT_SYMBOL_GPL(queue_delayed_work_on);
 static void run_workqueue(struct cpu_workqueue_struct *cwq)
 {
        spin_lock_irq(&cwq->lock);
-       cwq->run_depth++;
-       if (cwq->run_depth > 3) {
-               /* morton gets to eat his hat */
-               printk("%s: recursion depth exceeded: %d\n",
-                       __func__, cwq->run_depth);
-               dump_stack();
-       }
        while (!list_empty(&cwq->worklist)) {
                struct work_struct *work = list_entry(cwq->worklist.next,
                                                struct work_struct, entry);
@@ -311,7 +302,6 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq)
                spin_lock_irq(&cwq->lock);
                cwq->current_work = NULL;
        }
-       cwq->run_depth--;
        spin_unlock_irq(&cwq->lock);
 }
 
@@ -368,29 +358,20 @@ static void insert_wq_barrier(struct cpu_workqueue_struct *cwq,
 
 static int flush_cpu_workqueue(struct cpu_workqueue_struct *cwq)
 {
-       int active;
+       int active = 0;
+       struct wq_barrier barr;
 
-       if (cwq->thread == current) {
-               /*
-                * Probably keventd trying to flush its own queue. So simply run
-                * it by hand rather than deadlocking.
-                */
-               run_workqueue(cwq);
-               active = 1;
-       } else {
-               struct wq_barrier barr;
+       WARN_ON(cwq->thread == current);
 
-               active = 0;
-               spin_lock_irq(&cwq->lock);
-               if (!list_empty(&cwq->worklist) || cwq->current_work != NULL) {
-                       insert_wq_barrier(cwq, &barr, &cwq->worklist);
-                       active = 1;
-               }
-               spin_unlock_irq(&cwq->lock);
-
-               if (active)
-                       wait_for_completion(&barr.done);
+       spin_lock_irq(&cwq->lock);
+       if (!list_empty(&cwq->worklist) || cwq->current_work != NULL) {
+               insert_wq_barrier(cwq, &barr, &cwq->worklist);
+               active = 1;
        }
+       spin_unlock_irq(&cwq->lock);
+
+       if (active)
+               wait_for_completion(&barr.done);
 
        return active;
 }
@@ -416,7 +397,7 @@ void flush_workqueue(struct workqueue_struct *wq)
        might_sleep();
        lock_map_acquire(&wq->lockdep_map);
        lock_map_release(&wq->lockdep_map);
-       for_each_cpu_mask_nr(cpu, *cpu_map)
+       for_each_cpu(cpu, cpu_map)
                flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, cpu));
 }
 EXPORT_SYMBOL_GPL(flush_workqueue);
@@ -547,7 +528,7 @@ static void wait_on_work(struct work_struct *work)
        wq = cwq->wq;
        cpu_map = wq_cpu_map(wq);
 
-       for_each_cpu_mask_nr(cpu, *cpu_map)
+       for_each_cpu(cpu, cpu_map)
                wait_on_cpu_work(per_cpu_ptr(wq->cpu_wq, cpu), work);
 }
 
@@ -911,7 +892,7 @@ void destroy_workqueue(struct workqueue_struct *wq)
        list_del(&wq->list);
        spin_unlock(&workqueue_lock);
 
-       for_each_cpu_mask_nr(cpu, *cpu_map)
+       for_each_cpu(cpu, cpu_map)
                cleanup_workqueue_thread(per_cpu_ptr(wq->cpu_wq, cpu));
        cpu_maps_update_done();
 
index 0626fa4856e6c80d45321606c025da5b28f83842..9638d99644afe4b5ff04d4ac8fcd194d1b67f614 100644 (file)
@@ -796,6 +796,7 @@ config SYSCTL_SYSCALL_CHECK
          to properly maintain and use. This enables checks that help
          you to keep things correct.
 
+source mm/Kconfig.debug
 source kernel/trace/Kconfig
 
 config PROVIDE_OHCI1394_DMA_INIT
@@ -912,6 +913,17 @@ config DYNAMIC_DEBUG
 
          See Documentation/dynamic-debug-howto.txt for additional information.
 
+config DMA_API_DEBUG
+       bool "Enable debugging of DMA-API usage"
+       depends on HAVE_DMA_API_DEBUG
+       help
+         Enable this option to debug the use of the DMA API by device drivers.
+         With this option you will be able to detect common bugs in device
+         drivers like double-freeing of DMA mappings or freeing mappings that
+         were never allocated.
+         This option causes a performance degredation.  Use only if you want
+         to debug device drivers. If unsure, say N.
+
 source "samples/Kconfig"
 
 source "lib/Kconfig.kgdb"
index 051a33a8e0285b99c0bf4e98a61580d9e32431a8..d6edd6753f40c87be4ed2d656fe7cb0e3c92bdd9 100644 (file)
@@ -90,6 +90,8 @@ obj-$(CONFIG_DYNAMIC_DEBUG) += dynamic_debug.o
 
 obj-$(CONFIG_NLATTR) += nlattr.o
 
+obj-$(CONFIG_DMA_API_DEBUG) += dma-debug.o
+
 hostprogs-y    := gen_crc32table
 clean-files    := crc32table.h
 
index 3389e2440da0f30a76d49ab63f3419bce857849b..1f71b97de0f945e9cd59c264e87c1148aa74cf33 100644 (file)
@@ -109,10 +109,10 @@ bool alloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, int node)
 #endif
        /* FIXME: Bandaid to save us from old primitives which go to NR_CPUS. */
        if (*mask) {
+               unsigned char *ptr = (unsigned char *)cpumask_bits(*mask);
                unsigned int tail;
                tail = BITS_TO_LONGS(NR_CPUS - nr_cpumask_bits) * sizeof(long);
-               memset(cpumask_bits(*mask) + cpumask_size() - tail,
-                      0, tail);
+               memset(ptr + cpumask_size() - tail, 0, tail);
        }
 
        return *mask != NULL;
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
new file mode 100644 (file)
index 0000000..d3da7ed
--- /dev/null
@@ -0,0 +1,955 @@
+/*
+ * Copyright (C) 2008 Advanced Micro Devices, Inc.
+ *
+ * Author: Joerg Roedel <joerg.roedel@amd.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.
+ *
+ * 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/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/stacktrace.h>
+#include <linux/dma-debug.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#include <asm/sections.h>
+
+#define HASH_SIZE       1024ULL
+#define HASH_FN_SHIFT   13
+#define HASH_FN_MASK    (HASH_SIZE - 1)
+
+enum {
+       dma_debug_single,
+       dma_debug_page,
+       dma_debug_sg,
+       dma_debug_coherent,
+};
+
+#define DMA_DEBUG_STACKTRACE_ENTRIES 5
+
+struct dma_debug_entry {
+       struct list_head list;
+       struct device    *dev;
+       int              type;
+       phys_addr_t      paddr;
+       u64              dev_addr;
+       u64              size;
+       int              direction;
+       int              sg_call_ents;
+       int              sg_mapped_ents;
+#ifdef CONFIG_STACKTRACE
+       struct           stack_trace stacktrace;
+       unsigned long    st_entries[DMA_DEBUG_STACKTRACE_ENTRIES];
+#endif
+};
+
+struct hash_bucket {
+       struct list_head list;
+       spinlock_t lock;
+} ____cacheline_aligned_in_smp;
+
+/* Hash list to save the allocated dma addresses */
+static struct hash_bucket dma_entry_hash[HASH_SIZE];
+/* List of pre-allocated dma_debug_entry's */
+static LIST_HEAD(free_entries);
+/* Lock for the list above */
+static DEFINE_SPINLOCK(free_entries_lock);
+
+/* Global disable flag - will be set in case of an error */
+static bool global_disable __read_mostly;
+
+/* Global error count */
+static u32 error_count;
+
+/* Global error show enable*/
+static u32 show_all_errors __read_mostly;
+/* Number of errors to show */
+static u32 show_num_errors = 1;
+
+static u32 num_free_entries;
+static u32 min_free_entries;
+
+/* number of preallocated entries requested by kernel cmdline */
+static u32 req_entries;
+
+/* debugfs dentry's for the stuff above */
+static struct dentry *dma_debug_dent        __read_mostly;
+static struct dentry *global_disable_dent   __read_mostly;
+static struct dentry *error_count_dent      __read_mostly;
+static struct dentry *show_all_errors_dent  __read_mostly;
+static struct dentry *show_num_errors_dent  __read_mostly;
+static struct dentry *num_free_entries_dent __read_mostly;
+static struct dentry *min_free_entries_dent __read_mostly;
+
+static const char *type2name[4] = { "single", "page",
+                                   "scather-gather", "coherent" };
+
+static const char *dir2name[4] = { "DMA_BIDIRECTIONAL", "DMA_TO_DEVICE",
+                                  "DMA_FROM_DEVICE", "DMA_NONE" };
+
+/*
+ * The access to some variables in this macro is racy. We can't use atomic_t
+ * here because all these variables are exported to debugfs. Some of them even
+ * writeable. This is also the reason why a lock won't help much. But anyway,
+ * the races are no big deal. Here is why:
+ *
+ *   error_count: the addition is racy, but the worst thing that can happen is
+ *                that we don't count some errors
+ *   show_num_errors: the subtraction is racy. Also no big deal because in
+ *                    worst case this will result in one warning more in the
+ *                    system log than the user configured. This variable is
+ *                    writeable via debugfs.
+ */
+static inline void dump_entry_trace(struct dma_debug_entry *entry)
+{
+#ifdef CONFIG_STACKTRACE
+       if (entry) {
+               printk(KERN_WARNING "Mapped at:\n");
+               print_stack_trace(&entry->stacktrace, 0);
+       }
+#endif
+}
+
+#define err_printk(dev, entry, format, arg...) do {            \
+               error_count += 1;                               \
+               if (show_all_errors || show_num_errors > 0) {   \
+                       WARN(1, "%s %s: " format,               \
+                            dev_driver_string(dev),            \
+                            dev_name(dev) , ## arg);           \
+                       dump_entry_trace(entry);                \
+               }                                               \
+               if (!show_all_errors && show_num_errors > 0)    \
+                       show_num_errors -= 1;                   \
+       } while (0);
+
+/*
+ * Hash related functions
+ *
+ * Every DMA-API request is saved into a struct dma_debug_entry. To
+ * have quick access to these structs they are stored into a hash.
+ */
+static int hash_fn(struct dma_debug_entry *entry)
+{
+       /*
+        * Hash function is based on the dma address.
+        * We use bits 20-27 here as the index into the hash
+        */
+       return (entry->dev_addr >> HASH_FN_SHIFT) & HASH_FN_MASK;
+}
+
+/*
+ * Request exclusive access to a hash bucket for a given dma_debug_entry.
+ */
+static struct hash_bucket *get_hash_bucket(struct dma_debug_entry *entry,
+                                          unsigned long *flags)
+{
+       int idx = hash_fn(entry);
+       unsigned long __flags;
+
+       spin_lock_irqsave(&dma_entry_hash[idx].lock, __flags);
+       *flags = __flags;
+       return &dma_entry_hash[idx];
+}
+
+/*
+ * Give up exclusive access to the hash bucket
+ */
+static void put_hash_bucket(struct hash_bucket *bucket,
+                           unsigned long *flags)
+{
+       unsigned long __flags = *flags;
+
+       spin_unlock_irqrestore(&bucket->lock, __flags);
+}
+
+/*
+ * Search a given entry in the hash bucket list
+ */
+static struct dma_debug_entry *hash_bucket_find(struct hash_bucket *bucket,
+                                               struct dma_debug_entry *ref)
+{
+       struct dma_debug_entry *entry;
+
+       list_for_each_entry(entry, &bucket->list, list) {
+               if ((entry->dev_addr == ref->dev_addr) &&
+                   (entry->dev == ref->dev))
+                       return entry;
+       }
+
+       return NULL;
+}
+
+/*
+ * Add an entry to a hash bucket
+ */
+static void hash_bucket_add(struct hash_bucket *bucket,
+                           struct dma_debug_entry *entry)
+{
+       list_add_tail(&entry->list, &bucket->list);
+}
+
+/*
+ * Remove entry from a hash bucket list
+ */
+static void hash_bucket_del(struct dma_debug_entry *entry)
+{
+       list_del(&entry->list);
+}
+
+/*
+ * Dump mapping entries for debugging purposes
+ */
+void debug_dma_dump_mappings(struct device *dev)
+{
+       int idx;
+
+       for (idx = 0; idx < HASH_SIZE; idx++) {
+               struct hash_bucket *bucket = &dma_entry_hash[idx];
+               struct dma_debug_entry *entry;
+               unsigned long flags;
+
+               spin_lock_irqsave(&bucket->lock, flags);
+
+               list_for_each_entry(entry, &bucket->list, list) {
+                       if (!dev || dev == entry->dev) {
+                               dev_info(entry->dev,
+                                        "%s idx %d P=%Lx D=%Lx L=%Lx %s\n",
+                                        type2name[entry->type], idx,
+                                        (unsigned long long)entry->paddr,
+                                        entry->dev_addr, entry->size,
+                                        dir2name[entry->direction]);
+                       }
+               }
+
+               spin_unlock_irqrestore(&bucket->lock, flags);
+       }
+}
+EXPORT_SYMBOL(debug_dma_dump_mappings);
+
+/*
+ * Wrapper function for adding an entry to the hash.
+ * This function takes care of locking itself.
+ */
+static void add_dma_entry(struct dma_debug_entry *entry)
+{
+       struct hash_bucket *bucket;
+       unsigned long flags;
+
+       bucket = get_hash_bucket(entry, &flags);
+       hash_bucket_add(bucket, entry);
+       put_hash_bucket(bucket, &flags);
+}
+
+/* struct dma_entry allocator
+ *
+ * The next two functions implement the allocator for
+ * struct dma_debug_entries.
+ */
+static struct dma_debug_entry *dma_entry_alloc(void)
+{
+       struct dma_debug_entry *entry = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&free_entries_lock, flags);
+
+       if (list_empty(&free_entries)) {
+               printk(KERN_ERR "DMA-API: debugging out of memory "
+                               "- disabling\n");
+               global_disable = true;
+               goto out;
+       }
+
+       entry = list_entry(free_entries.next, struct dma_debug_entry, list);
+       list_del(&entry->list);
+       memset(entry, 0, sizeof(*entry));
+
+#ifdef CONFIG_STACKTRACE
+       entry->stacktrace.max_entries = DMA_DEBUG_STACKTRACE_ENTRIES;
+       entry->stacktrace.entries = entry->st_entries;
+       entry->stacktrace.skip = 2;
+       save_stack_trace(&entry->stacktrace);
+#endif
+       num_free_entries -= 1;
+       if (num_free_entries < min_free_entries)
+               min_free_entries = num_free_entries;
+
+out:
+       spin_unlock_irqrestore(&free_entries_lock, flags);
+
+       return entry;
+}
+
+static void dma_entry_free(struct dma_debug_entry *entry)
+{
+       unsigned long flags;
+
+       /*
+        * add to beginning of the list - this way the entries are
+        * more likely cache hot when they are reallocated.
+        */
+       spin_lock_irqsave(&free_entries_lock, flags);
+       list_add(&entry->list, &free_entries);
+       num_free_entries += 1;
+       spin_unlock_irqrestore(&free_entries_lock, flags);
+}
+
+/*
+ * DMA-API debugging init code
+ *
+ * The init code does two things:
+ *   1. Initialize core data structures
+ *   2. Preallocate a given number of dma_debug_entry structs
+ */
+
+static int prealloc_memory(u32 num_entries)
+{
+       struct dma_debug_entry *entry, *next_entry;
+       int i;
+
+       for (i = 0; i < num_entries; ++i) {
+               entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+               if (!entry)
+                       goto out_err;
+
+               list_add_tail(&entry->list, &free_entries);
+       }
+
+       num_free_entries = num_entries;
+       min_free_entries = num_entries;
+
+       printk(KERN_INFO "DMA-API: preallocated %d debug entries\n",
+                       num_entries);
+
+       return 0;
+
+out_err:
+
+       list_for_each_entry_safe(entry, next_entry, &free_entries, list) {
+               list_del(&entry->list);
+               kfree(entry);
+       }
+
+       return -ENOMEM;
+}
+
+static int dma_debug_fs_init(void)
+{
+       dma_debug_dent = debugfs_create_dir("dma-api", NULL);
+       if (!dma_debug_dent) {
+               printk(KERN_ERR "DMA-API: can not create debugfs directory\n");
+               return -ENOMEM;
+       }
+
+       global_disable_dent = debugfs_create_bool("disabled", 0444,
+                       dma_debug_dent,
+                       (u32 *)&global_disable);
+       if (!global_disable_dent)
+               goto out_err;
+
+       error_count_dent = debugfs_create_u32("error_count", 0444,
+                       dma_debug_dent, &error_count);
+       if (!error_count_dent)
+               goto out_err;
+
+       show_all_errors_dent = debugfs_create_u32("all_errors", 0644,
+                       dma_debug_dent,
+                       &show_all_errors);
+       if (!show_all_errors_dent)
+               goto out_err;
+
+       show_num_errors_dent = debugfs_create_u32("num_errors", 0644,
+                       dma_debug_dent,
+                       &show_num_errors);
+       if (!show_num_errors_dent)
+               goto out_err;
+
+       num_free_entries_dent = debugfs_create_u32("num_free_entries", 0444,
+                       dma_debug_dent,
+                       &num_free_entries);
+       if (!num_free_entries_dent)
+               goto out_err;
+
+       min_free_entries_dent = debugfs_create_u32("min_free_entries", 0444,
+                       dma_debug_dent,
+                       &min_free_entries);
+       if (!min_free_entries_dent)
+               goto out_err;
+
+       return 0;
+
+out_err:
+       debugfs_remove_recursive(dma_debug_dent);
+
+       return -ENOMEM;
+}
+
+static int device_dma_allocations(struct device *dev)
+{
+       struct dma_debug_entry *entry;
+       unsigned long flags;
+       int count = 0, i;
+
+       for (i = 0; i < HASH_SIZE; ++i) {
+               spin_lock_irqsave(&dma_entry_hash[i].lock, flags);
+               list_for_each_entry(entry, &dma_entry_hash[i].list, list) {
+                       if (entry->dev == dev)
+                               count += 1;
+               }
+               spin_unlock_irqrestore(&dma_entry_hash[i].lock, flags);
+       }
+
+       return count;
+}
+
+static int dma_debug_device_change(struct notifier_block *nb,
+                                   unsigned long action, void *data)
+{
+       struct device *dev = data;
+       int count;
+
+
+       switch (action) {
+       case BUS_NOTIFY_UNBIND_DRIVER:
+               count = device_dma_allocations(dev);
+               if (count == 0)
+                       break;
+               err_printk(dev, NULL, "DMA-API: device driver has pending "
+                               "DMA allocations while released from device "
+                               "[count=%d]\n", count);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+void dma_debug_add_bus(struct bus_type *bus)
+{
+       struct notifier_block *nb;
+
+       nb = kzalloc(sizeof(struct notifier_block), GFP_KERNEL);
+       if (nb == NULL) {
+               printk(KERN_ERR "dma_debug_add_bus: out of memory\n");
+               return;
+       }
+
+       nb->notifier_call = dma_debug_device_change;
+
+       bus_register_notifier(bus, nb);
+}
+
+/*
+ * Let the architectures decide how many entries should be preallocated.
+ */
+void dma_debug_init(u32 num_entries)
+{
+       int i;
+
+       if (global_disable)
+               return;
+
+       for (i = 0; i < HASH_SIZE; ++i) {
+               INIT_LIST_HEAD(&dma_entry_hash[i].list);
+               dma_entry_hash[i].lock = SPIN_LOCK_UNLOCKED;
+       }
+
+       if (dma_debug_fs_init() != 0) {
+               printk(KERN_ERR "DMA-API: error creating debugfs entries "
+                               "- disabling\n");
+               global_disable = true;
+
+               return;
+       }
+
+       if (req_entries)
+               num_entries = req_entries;
+
+       if (prealloc_memory(num_entries) != 0) {
+               printk(KERN_ERR "DMA-API: debugging out of memory error "
+                               "- disabled\n");
+               global_disable = true;
+
+               return;
+       }
+
+       printk(KERN_INFO "DMA-API: debugging enabled by kernel config\n");
+}
+
+static __init int dma_debug_cmdline(char *str)
+{
+       if (!str)
+               return -EINVAL;
+
+       if (strncmp(str, "off", 3) == 0) {
+               printk(KERN_INFO "DMA-API: debugging disabled on kernel "
+                                "command line\n");
+               global_disable = true;
+       }
+
+       return 0;
+}
+
+static __init int dma_debug_entries_cmdline(char *str)
+{
+       int res;
+
+       if (!str)
+               return -EINVAL;
+
+       res = get_option(&str, &req_entries);
+
+       if (!res)
+               req_entries = 0;
+
+       return 0;
+}
+
+__setup("dma_debug=", dma_debug_cmdline);
+__setup("dma_debug_entries=", dma_debug_entries_cmdline);
+
+static void check_unmap(struct dma_debug_entry *ref)
+{
+       struct dma_debug_entry *entry;
+       struct hash_bucket *bucket;
+       unsigned long flags;
+
+       if (dma_mapping_error(ref->dev, ref->dev_addr)) {
+               err_printk(ref->dev, NULL, "DMA-API: device driver tries "
+                          "to free an invalid DMA memory address\n");
+               return;
+       }
+
+       bucket = get_hash_bucket(ref, &flags);
+       entry = hash_bucket_find(bucket, ref);
+
+       if (!entry) {
+               err_printk(ref->dev, NULL, "DMA-API: device driver tries "
+                          "to free DMA memory it has not allocated "
+                          "[device address=0x%016llx] [size=%llu bytes]\n",
+                          ref->dev_addr, ref->size);
+               goto out;
+       }
+
+       if (ref->size != entry->size) {
+               err_printk(ref->dev, entry, "DMA-API: device driver frees "
+                          "DMA memory with different size "
+                          "[device address=0x%016llx] [map size=%llu bytes] "
+                          "[unmap size=%llu bytes]\n",
+                          ref->dev_addr, entry->size, ref->size);
+       }
+
+       if (ref->type != entry->type) {
+               err_printk(ref->dev, entry, "DMA-API: device driver frees "
+                          "DMA memory with wrong function "
+                          "[device address=0x%016llx] [size=%llu bytes] "
+                          "[mapped as %s] [unmapped as %s]\n",
+                          ref->dev_addr, ref->size,
+                          type2name[entry->type], type2name[ref->type]);
+       } else if ((entry->type == dma_debug_coherent) &&
+                  (ref->paddr != entry->paddr)) {
+               err_printk(ref->dev, entry, "DMA-API: device driver frees "
+                          "DMA memory with different CPU address "
+                          "[device address=0x%016llx] [size=%llu bytes] "
+                          "[cpu alloc address=%p] [cpu free address=%p]",
+                          ref->dev_addr, ref->size,
+                          (void *)entry->paddr, (void *)ref->paddr);
+       }
+
+       if (ref->sg_call_ents && ref->type == dma_debug_sg &&
+           ref->sg_call_ents != entry->sg_call_ents) {
+               err_printk(ref->dev, entry, "DMA-API: device driver frees "
+                          "DMA sg list with different entry count "
+                          "[map count=%d] [unmap count=%d]\n",
+                          entry->sg_call_ents, ref->sg_call_ents);
+       }
+
+       /*
+        * This may be no bug in reality - but most implementations of the
+        * DMA API don't handle this properly, so check for it here
+        */
+       if (ref->direction != entry->direction) {
+               err_printk(ref->dev, entry, "DMA-API: device driver frees "
+                          "DMA memory with different direction "
+                          "[device address=0x%016llx] [size=%llu bytes] "
+                          "[mapped with %s] [unmapped with %s]\n",
+                          ref->dev_addr, ref->size,
+                          dir2name[entry->direction],
+                          dir2name[ref->direction]);
+       }
+
+       hash_bucket_del(entry);
+       dma_entry_free(entry);
+
+out:
+       put_hash_bucket(bucket, &flags);
+}
+
+static void check_for_stack(struct device *dev, void *addr)
+{
+       if (object_is_on_stack(addr))
+               err_printk(dev, NULL, "DMA-API: device driver maps memory from"
+                               "stack [addr=%p]\n", addr);
+}
+
+static inline bool overlap(void *addr, u64 size, void *start, void *end)
+{
+       void *addr2 = (char *)addr + size;
+
+       return ((addr >= start && addr < end) ||
+               (addr2 >= start && addr2 < end) ||
+               ((addr < start) && (addr2 >= end)));
+}
+
+static void check_for_illegal_area(struct device *dev, void *addr, u64 size)
+{
+       if (overlap(addr, size, _text, _etext) ||
+           overlap(addr, size, __start_rodata, __end_rodata))
+               err_printk(dev, NULL, "DMA-API: device driver maps "
+                               "memory from kernel text or rodata "
+                               "[addr=%p] [size=%llu]\n", addr, size);
+}
+
+static void check_sync(struct device *dev, dma_addr_t addr,
+                      u64 size, u64 offset, int direction, bool to_cpu)
+{
+       struct dma_debug_entry ref = {
+               .dev            = dev,
+               .dev_addr       = addr,
+               .size           = size,
+               .direction      = direction,
+       };
+       struct dma_debug_entry *entry;
+       struct hash_bucket *bucket;
+       unsigned long flags;
+
+       bucket = get_hash_bucket(&ref, &flags);
+
+       entry = hash_bucket_find(bucket, &ref);
+
+       if (!entry) {
+               err_printk(dev, NULL, "DMA-API: device driver tries "
+                               "to sync DMA memory it has not allocated "
+                               "[device address=0x%016llx] [size=%llu bytes]\n",
+                               (unsigned long long)addr, size);
+               goto out;
+       }
+
+       if ((offset + size) > entry->size) {
+               err_printk(dev, entry, "DMA-API: device driver syncs"
+                               " DMA memory outside allocated range "
+                               "[device address=0x%016llx] "
+                               "[allocation size=%llu bytes] [sync offset=%llu] "
+                               "[sync size=%llu]\n", entry->dev_addr, entry->size,
+                               offset, size);
+       }
+
+       if (direction != entry->direction) {
+               err_printk(dev, entry, "DMA-API: device driver syncs "
+                               "DMA memory with different direction "
+                               "[device address=0x%016llx] [size=%llu bytes] "
+                               "[mapped with %s] [synced with %s]\n",
+                               (unsigned long long)addr, entry->size,
+                               dir2name[entry->direction],
+                               dir2name[direction]);
+       }
+
+       if (entry->direction == DMA_BIDIRECTIONAL)
+               goto out;
+
+       if (to_cpu && !(entry->direction == DMA_FROM_DEVICE) &&
+                     !(direction == DMA_TO_DEVICE))
+               err_printk(dev, entry, "DMA-API: device driver syncs "
+                               "device read-only DMA memory for cpu "
+                               "[device address=0x%016llx] [size=%llu bytes] "
+                               "[mapped with %s] [synced with %s]\n",
+                               (unsigned long long)addr, entry->size,
+                               dir2name[entry->direction],
+                               dir2name[direction]);
+
+       if (!to_cpu && !(entry->direction == DMA_TO_DEVICE) &&
+                      !(direction == DMA_FROM_DEVICE))
+               err_printk(dev, entry, "DMA-API: device driver syncs "
+                               "device write-only DMA memory to device "
+                               "[device address=0x%016llx] [size=%llu bytes] "
+                               "[mapped with %s] [synced with %s]\n",
+                               (unsigned long long)addr, entry->size,
+                               dir2name[entry->direction],
+                               dir2name[direction]);
+
+out:
+       put_hash_bucket(bucket, &flags);
+
+}
+
+void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
+                       size_t size, int direction, dma_addr_t dma_addr,
+                       bool map_single)
+{
+       struct dma_debug_entry *entry;
+
+       if (unlikely(global_disable))
+               return;
+
+       if (unlikely(dma_mapping_error(dev, dma_addr)))
+               return;
+
+       entry = dma_entry_alloc();
+       if (!entry)
+               return;
+
+       entry->dev       = dev;
+       entry->type      = dma_debug_page;
+       entry->paddr     = page_to_phys(page) + offset;
+       entry->dev_addr  = dma_addr;
+       entry->size      = size;
+       entry->direction = direction;
+
+       if (map_single)
+               entry->type = dma_debug_single;
+
+       if (!PageHighMem(page)) {
+               void *addr = ((char *)page_address(page)) + offset;
+               check_for_stack(dev, addr);
+               check_for_illegal_area(dev, addr, size);
+       }
+
+       add_dma_entry(entry);
+}
+EXPORT_SYMBOL(debug_dma_map_page);
+
+void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
+                         size_t size, int direction, bool map_single)
+{
+       struct dma_debug_entry ref = {
+               .type           = dma_debug_page,
+               .dev            = dev,
+               .dev_addr       = addr,
+               .size           = size,
+               .direction      = direction,
+       };
+
+       if (unlikely(global_disable))
+               return;
+
+       if (map_single)
+               ref.type = dma_debug_single;
+
+       check_unmap(&ref);
+}
+EXPORT_SYMBOL(debug_dma_unmap_page);
+
+void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
+                     int nents, int mapped_ents, int direction)
+{
+       struct dma_debug_entry *entry;
+       struct scatterlist *s;
+       int i;
+
+       if (unlikely(global_disable))
+               return;
+
+       for_each_sg(sg, s, mapped_ents, i) {
+               entry = dma_entry_alloc();
+               if (!entry)
+                       return;
+
+               entry->type           = dma_debug_sg;
+               entry->dev            = dev;
+               entry->paddr          = sg_phys(s);
+               entry->size           = s->length;
+               entry->dev_addr       = s->dma_address;
+               entry->direction      = direction;
+               entry->sg_call_ents   = nents;
+               entry->sg_mapped_ents = mapped_ents;
+
+               if (!PageHighMem(sg_page(s))) {
+                       check_for_stack(dev, sg_virt(s));
+                       check_for_illegal_area(dev, sg_virt(s), s->length);
+               }
+
+               add_dma_entry(entry);
+       }
+}
+EXPORT_SYMBOL(debug_dma_map_sg);
+
+void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
+                       int nelems, int dir)
+{
+       struct dma_debug_entry *entry;
+       struct scatterlist *s;
+       int mapped_ents = 0, i;
+       unsigned long flags;
+
+       if (unlikely(global_disable))
+               return;
+
+       for_each_sg(sglist, s, nelems, i) {
+
+               struct dma_debug_entry ref = {
+                       .type           = dma_debug_sg,
+                       .dev            = dev,
+                       .paddr          = sg_phys(s),
+                       .dev_addr       = s->dma_address,
+                       .size           = s->length,
+                       .direction      = dir,
+                       .sg_call_ents   = 0,
+               };
+
+               if (mapped_ents && i >= mapped_ents)
+                       break;
+
+               if (mapped_ents == 0) {
+                       struct hash_bucket *bucket;
+                       ref.sg_call_ents = nelems;
+                       bucket = get_hash_bucket(&ref, &flags);
+                       entry = hash_bucket_find(bucket, &ref);
+                       if (entry)
+                               mapped_ents = entry->sg_mapped_ents;
+                       put_hash_bucket(bucket, &flags);
+               }
+
+               check_unmap(&ref);
+       }
+}
+EXPORT_SYMBOL(debug_dma_unmap_sg);
+
+void debug_dma_alloc_coherent(struct device *dev, size_t size,
+                             dma_addr_t dma_addr, void *virt)
+{
+       struct dma_debug_entry *entry;
+
+       if (unlikely(global_disable))
+               return;
+
+       if (unlikely(virt == NULL))
+               return;
+
+       entry = dma_entry_alloc();
+       if (!entry)
+               return;
+
+       entry->type      = dma_debug_coherent;
+       entry->dev       = dev;
+       entry->paddr     = virt_to_phys(virt);
+       entry->size      = size;
+       entry->dev_addr  = dma_addr;
+       entry->direction = DMA_BIDIRECTIONAL;
+
+       add_dma_entry(entry);
+}
+EXPORT_SYMBOL(debug_dma_alloc_coherent);
+
+void debug_dma_free_coherent(struct device *dev, size_t size,
+                        void *virt, dma_addr_t addr)
+{
+       struct dma_debug_entry ref = {
+               .type           = dma_debug_coherent,
+               .dev            = dev,
+               .paddr          = virt_to_phys(virt),
+               .dev_addr       = addr,
+               .size           = size,
+               .direction      = DMA_BIDIRECTIONAL,
+       };
+
+       if (unlikely(global_disable))
+               return;
+
+       check_unmap(&ref);
+}
+EXPORT_SYMBOL(debug_dma_free_coherent);
+
+void debug_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+                                  size_t size, int direction)
+{
+       if (unlikely(global_disable))
+               return;
+
+       check_sync(dev, dma_handle, size, 0, direction, true);
+}
+EXPORT_SYMBOL(debug_dma_sync_single_for_cpu);
+
+void debug_dma_sync_single_for_device(struct device *dev,
+                                     dma_addr_t dma_handle, size_t size,
+                                     int direction)
+{
+       if (unlikely(global_disable))
+               return;
+
+       check_sync(dev, dma_handle, size, 0, direction, false);
+}
+EXPORT_SYMBOL(debug_dma_sync_single_for_device);
+
+void debug_dma_sync_single_range_for_cpu(struct device *dev,
+                                        dma_addr_t dma_handle,
+                                        unsigned long offset, size_t size,
+                                        int direction)
+{
+       if (unlikely(global_disable))
+               return;
+
+       check_sync(dev, dma_handle, size, offset, direction, true);
+}
+EXPORT_SYMBOL(debug_dma_sync_single_range_for_cpu);
+
+void debug_dma_sync_single_range_for_device(struct device *dev,
+                                           dma_addr_t dma_handle,
+                                           unsigned long offset,
+                                           size_t size, int direction)
+{
+       if (unlikely(global_disable))
+               return;
+
+       check_sync(dev, dma_handle, size, offset, direction, false);
+}
+EXPORT_SYMBOL(debug_dma_sync_single_range_for_device);
+
+void debug_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+                              int nelems, int direction)
+{
+       struct scatterlist *s;
+       int i;
+
+       if (unlikely(global_disable))
+               return;
+
+       for_each_sg(sg, s, nelems, i) {
+               check_sync(dev, s->dma_address, s->dma_length, 0,
+                               direction, true);
+       }
+}
+EXPORT_SYMBOL(debug_dma_sync_sg_for_cpu);
+
+void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+                                 int nelems, int direction)
+{
+       struct scatterlist *s;
+       int i;
+
+       if (unlikely(global_disable))
+               return;
+
+       for_each_sg(sg, s, nelems, i) {
+               check_sync(dev, s->dma_address, s->dma_length, 0,
+                               direction, false);
+       }
+}
+EXPORT_SYMBOL(debug_dma_sync_sg_for_device);
+
index dab4bca86f5d1981027c0be5104a69ce7d05fbe9..80ca9aca038be447573b8130cbc22c1133f34867 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -578,6 +578,52 @@ int idr_for_each(struct idr *idp,
 }
 EXPORT_SYMBOL(idr_for_each);
 
+/**
+ * idr_get_next - lookup next object of id to given id.
+ * @idp: idr handle
+ * @id:  pointer to lookup key
+ *
+ * Returns pointer to registered object with id, which is next number to
+ * given id.
+ */
+
+void *idr_get_next(struct idr *idp, int *nextidp)
+{
+       struct idr_layer *p, *pa[MAX_LEVEL];
+       struct idr_layer **paa = &pa[0];
+       int id = *nextidp;
+       int n, max;
+
+       /* find first ent */
+       n = idp->layers * IDR_BITS;
+       max = 1 << n;
+       p = rcu_dereference(idp->top);
+       if (!p)
+               return NULL;
+
+       while (id < max) {
+               while (n > 0 && p) {
+                       n -= IDR_BITS;
+                       *paa++ = p;
+                       p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]);
+               }
+
+               if (p) {
+                       *nextidp = id;
+                       return p;
+               }
+
+               id += 1 << n;
+               while (n < fls(id)) {
+                       n += IDR_BITS;
+                       p = *--paa;
+               }
+       }
+       return NULL;
+}
+
+
+
 /**
  * idr_replace - replace pointer for given id
  * @idp: idr handle
index 97e547037084dc22fc3fd93f5fd2aacd7419db02..e4a6482d8b26e5034805a401905480974e6dcd8c 100644 (file)
--- a/lib/lmb.c
+++ b/lib/lmb.c
@@ -29,33 +29,33 @@ static int __init early_lmb(char *p)
 }
 early_param("lmb", early_lmb);
 
-void lmb_dump_all(void)
+static void lmb_dump(struct lmb_region *region, char *name)
 {
-       unsigned long i;
+       unsigned long long base, size;
+       int i;
+
+       pr_info(" %s.cnt  = 0x%lx\n", name, region->cnt);
+
+       for (i = 0; i < region->cnt; i++) {
+               base = region->region[i].base;
+               size = region->region[i].size;
+
+               pr_info(" %s[0x%x]\t0x%016llx - 0x%016llx, 0x%llx bytes\n",
+                   name, i, base, base + size - 1, size);
+       }
+}
 
+void lmb_dump_all(void)
+{
        if (!lmb_debug)
                return;
 
-       pr_info("lmb_dump_all:\n");
-       pr_info("    memory.cnt           = 0x%lx\n", lmb.memory.cnt);
-       pr_info("    memory.size                  = 0x%llx\n",
-           (unsigned long long)lmb.memory.size);
-       for (i=0; i < lmb.memory.cnt ;i++) {
-               pr_info("    memory.region[0x%lx].base       = 0x%llx\n",
-                   i, (unsigned long long)lmb.memory.region[i].base);
-               pr_info("                     .size     = 0x%llx\n",
-                   (unsigned long long)lmb.memory.region[i].size);
-       }
+       pr_info("LMB configuration:\n");
+       pr_info(" rmo_size    = 0x%llx\n", (unsigned long long)lmb.rmo_size);
+       pr_info(" memory.size = 0x%llx\n", (unsigned long long)lmb.memory.size);
 
-       pr_info("    reserved.cnt         = 0x%lx\n", lmb.reserved.cnt);
-       pr_info("    reserved.size        = 0x%llx\n",
-           (unsigned long long)lmb.memory.size);
-       for (i=0; i < lmb.reserved.cnt ;i++) {
-               pr_info("    reserved.region[0x%lx].base       = 0x%llx\n",
-                   i, (unsigned long long)lmb.reserved.region[i].base);
-               pr_info("                     .size     = 0x%llx\n",
-                   (unsigned long long)lmb.reserved.region[i].size);
-       }
+       lmb_dump(&lmb.memory, "memory");
+       lmb_dump(&lmb.reserved, "reserved");
 }
 
 static unsigned long lmb_addrs_overlap(u64 base1, u64 size1, u64 base2,
index 9956b99649f02af0667666e098449f9df38d26b4..f653659e0bc1fb161525332d775c973e2fb0ba98 100644 (file)
@@ -163,17 +163,14 @@ static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
                        {
                                if (!other->rb_right || rb_is_black(other->rb_right))
                                {
-                                       struct rb_node *o_left;
-                                       if ((o_left = other->rb_left))
-                                               rb_set_black(o_left);
+                                       rb_set_black(other->rb_left);
                                        rb_set_red(other);
                                        __rb_rotate_right(other, root);
                                        other = parent->rb_right;
                                }
                                rb_set_color(other, rb_color(parent));
                                rb_set_black(parent);
-                               if (other->rb_right)
-                                       rb_set_black(other->rb_right);
+                               rb_set_black(other->rb_right);
                                __rb_rotate_left(parent, root);
                                node = root->rb_node;
                                break;
@@ -200,17 +197,14 @@ static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
                        {
                                if (!other->rb_left || rb_is_black(other->rb_left))
                                {
-                                       register struct rb_node *o_right;
-                                       if ((o_right = other->rb_right))
-                                               rb_set_black(o_right);
+                                       rb_set_black(other->rb_right);
                                        rb_set_red(other);
                                        __rb_rotate_left(other, root);
                                        other = parent->rb_left;
                                }
                                rb_set_color(other, rb_color(parent));
                                rb_set_black(parent);
-                               if (other->rb_left)
-                                       rb_set_black(other->rb_left);
+                               rb_set_black(other->rb_left);
                                __rb_rotate_right(parent, root);
                                node = root->rb_node;
                                break;
index 1f991acc2a057acf65728448a5c3488d8e963351..32e2bd3b11424ca7b0d7905930d3ea9b6adf14ff 100644 (file)
@@ -145,7 +145,7 @@ static void *swiotlb_bus_to_virt(dma_addr_t address)
        return phys_to_virt(swiotlb_bus_to_phys(address));
 }
 
-int __weak swiotlb_arch_range_needs_mapping(void *ptr, size_t size)
+int __weak swiotlb_arch_range_needs_mapping(phys_addr_t paddr, size_t size)
 {
        return 0;
 }
@@ -315,9 +315,9 @@ address_needs_mapping(struct device *hwdev, dma_addr_t addr, size_t size)
        return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size);
 }
 
-static inline int range_needs_mapping(void *ptr, size_t size)
+static inline int range_needs_mapping(phys_addr_t paddr, size_t size)
 {
-       return swiotlb_force || swiotlb_arch_range_needs_mapping(ptr, size);
+       return swiotlb_force || swiotlb_arch_range_needs_mapping(paddr, size);
 }
 
 static int is_swiotlb_buffer(char *addr)
@@ -636,11 +636,14 @@ swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
  * Once the device is given the dma address, the device owns this memory until
  * either swiotlb_unmap_single or swiotlb_dma_sync_single is performed.
  */
-dma_addr_t
-swiotlb_map_single_attrs(struct device *hwdev, void *ptr, size_t size,
-                        int dir, struct dma_attrs *attrs)
-{
-       dma_addr_t dev_addr = swiotlb_virt_to_bus(hwdev, ptr);
+dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
+                           unsigned long offset, size_t size,
+                           enum dma_data_direction dir,
+                           struct dma_attrs *attrs)
+{
+       phys_addr_t phys = page_to_phys(page) + offset;
+       void *ptr = page_address(page) + offset;
+       dma_addr_t dev_addr = swiotlb_phys_to_bus(dev, phys);
        void *map;
 
        BUG_ON(dir == DMA_NONE);
@@ -649,37 +652,30 @@ swiotlb_map_single_attrs(struct device *hwdev, void *ptr, size_t size,
         * we can safely return the device addr and not worry about bounce
         * buffering it.
         */
-       if (!address_needs_mapping(hwdev, dev_addr, size) &&
-           !range_needs_mapping(ptr, size))
+       if (!address_needs_mapping(dev, dev_addr, size) &&
+           !range_needs_mapping(virt_to_phys(ptr), size))
                return dev_addr;
 
        /*
         * Oh well, have to allocate and map a bounce buffer.
         */
-       map = map_single(hwdev, virt_to_phys(ptr), size, dir);
+       map = map_single(dev, phys, size, dir);
        if (!map) {
-               swiotlb_full(hwdev, size, dir, 1);
+               swiotlb_full(dev, size, dir, 1);
                map = io_tlb_overflow_buffer;
        }
 
-       dev_addr = swiotlb_virt_to_bus(hwdev, map);
+       dev_addr = swiotlb_virt_to_bus(dev, map);
 
        /*
         * Ensure that the address returned is DMA'ble
         */
-       if (address_needs_mapping(hwdev, dev_addr, size))
+       if (address_needs_mapping(dev, dev_addr, size))
                panic("map_single: bounce buffer is not DMA'ble");
 
        return dev_addr;
 }
-EXPORT_SYMBOL(swiotlb_map_single_attrs);
-
-dma_addr_t
-swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
-{
-       return swiotlb_map_single_attrs(hwdev, ptr, size, dir, NULL);
-}
-EXPORT_SYMBOL(swiotlb_map_single);
+EXPORT_SYMBOL_GPL(swiotlb_map_page);
 
 /*
  * Unmap a single streaming mode DMA translation.  The dma_addr and size must
@@ -689,9 +685,9 @@ EXPORT_SYMBOL(swiotlb_map_single);
  * After this call, reads by the cpu to the buffer are guaranteed to see
  * whatever the device wrote there.
  */
-void
-swiotlb_unmap_single_attrs(struct device *hwdev, dma_addr_t dev_addr,
-                          size_t size, int dir, struct dma_attrs *attrs)
+void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
+                       size_t size, enum dma_data_direction dir,
+                       struct dma_attrs *attrs)
 {
        char *dma_addr = swiotlb_bus_to_virt(dev_addr);
 
@@ -701,15 +697,7 @@ swiotlb_unmap_single_attrs(struct device *hwdev, dma_addr_t dev_addr,
        else if (dir == DMA_FROM_DEVICE)
                dma_mark_clean(dma_addr, size);
 }
-EXPORT_SYMBOL(swiotlb_unmap_single_attrs);
-
-void
-swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr, size_t size,
-                    int dir)
-{
-       return swiotlb_unmap_single_attrs(hwdev, dev_addr, size, dir, NULL);
-}
-EXPORT_SYMBOL(swiotlb_unmap_single);
+EXPORT_SYMBOL_GPL(swiotlb_unmap_page);
 
 /*
  * Make physical memory consistent for a single streaming mode DMA translation
@@ -736,7 +724,7 @@ swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
 
 void
 swiotlb_sync_single_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
-                           size_t size, int dir)
+                           size_t size, enum dma_data_direction dir)
 {
        swiotlb_sync_single(hwdev, dev_addr, size, dir, SYNC_FOR_CPU);
 }
@@ -744,7 +732,7 @@ EXPORT_SYMBOL(swiotlb_sync_single_for_cpu);
 
 void
 swiotlb_sync_single_for_device(struct device *hwdev, dma_addr_t dev_addr,
-                              size_t size, int dir)
+                              size_t size, enum dma_data_direction dir)
 {
        swiotlb_sync_single(hwdev, dev_addr, size, dir, SYNC_FOR_DEVICE);
 }
@@ -769,7 +757,8 @@ swiotlb_sync_single_range(struct device *hwdev, dma_addr_t dev_addr,
 
 void
 swiotlb_sync_single_range_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
-                                 unsigned long offset, size_t size, int dir)
+                                 unsigned long offset, size_t size,
+                                 enum dma_data_direction dir)
 {
        swiotlb_sync_single_range(hwdev, dev_addr, offset, size, dir,
                                  SYNC_FOR_CPU);
@@ -778,7 +767,8 @@ EXPORT_SYMBOL_GPL(swiotlb_sync_single_range_for_cpu);
 
 void
 swiotlb_sync_single_range_for_device(struct device *hwdev, dma_addr_t dev_addr,
-                                    unsigned long offset, size_t size, int dir)
+                                    unsigned long offset, size_t size,
+                                    enum dma_data_direction dir)
 {
        swiotlb_sync_single_range(hwdev, dev_addr, offset, size, dir,
                                  SYNC_FOR_DEVICE);
@@ -803,7 +793,7 @@ EXPORT_SYMBOL_GPL(swiotlb_sync_single_range_for_device);
  */
 int
 swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
-                    int dir, struct dma_attrs *attrs)
+                    enum dma_data_direction dir, struct dma_attrs *attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -811,10 +801,10 @@ swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
        BUG_ON(dir == DMA_NONE);
 
        for_each_sg(sgl, sg, nelems, i) {
-               void *addr = sg_virt(sg);
-               dma_addr_t dev_addr = swiotlb_virt_to_bus(hwdev, addr);
+               phys_addr_t paddr = sg_phys(sg);
+               dma_addr_t dev_addr = swiotlb_phys_to_bus(hwdev, paddr);
 
-               if (range_needs_mapping(addr, sg->length) ||
+               if (range_needs_mapping(paddr, sg->length) ||
                    address_needs_mapping(hwdev, dev_addr, sg->length)) {
                        void *map = map_single(hwdev, sg_phys(sg),
                                               sg->length, dir);
@@ -850,7 +840,7 @@ EXPORT_SYMBOL(swiotlb_map_sg);
  */
 void
 swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
-                      int nelems, int dir, struct dma_attrs *attrs)
+                      int nelems, enum dma_data_direction dir, struct dma_attrs *attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -858,11 +848,11 @@ swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
        BUG_ON(dir == DMA_NONE);
 
        for_each_sg(sgl, sg, nelems, i) {
-               if (sg->dma_address != swiotlb_virt_to_bus(hwdev, sg_virt(sg)))
+               if (sg->dma_address != swiotlb_phys_to_bus(hwdev, sg_phys(sg)))
                        unmap_single(hwdev, swiotlb_bus_to_virt(sg->dma_address),
                                     sg->dma_length, dir);
                else if (dir == DMA_FROM_DEVICE)
-                       dma_mark_clean(sg_virt(sg), sg->dma_length);
+                       dma_mark_clean(swiotlb_bus_to_virt(sg->dma_address), sg->dma_length);
        }
 }
 EXPORT_SYMBOL(swiotlb_unmap_sg_attrs);
@@ -892,17 +882,17 @@ swiotlb_sync_sg(struct device *hwdev, struct scatterlist *sgl,
        BUG_ON(dir == DMA_NONE);
 
        for_each_sg(sgl, sg, nelems, i) {
-               if (sg->dma_address != swiotlb_virt_to_bus(hwdev, sg_virt(sg)))
+               if (sg->dma_address != swiotlb_phys_to_bus(hwdev, sg_phys(sg)))
                        sync_single(hwdev, swiotlb_bus_to_virt(sg->dma_address),
                                    sg->dma_length, dir, target);
                else if (dir == DMA_FROM_DEVICE)
-                       dma_mark_clean(sg_virt(sg), sg->dma_length);
+                       dma_mark_clean(swiotlb_bus_to_virt(sg->dma_address), sg->dma_length);
        }
 }
 
 void
 swiotlb_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg,
-                       int nelems, int dir)
+                       int nelems, enum dma_data_direction dir)
 {
        swiotlb_sync_sg(hwdev, sg, nelems, dir, SYNC_FOR_CPU);
 }
@@ -910,7 +900,7 @@ EXPORT_SYMBOL(swiotlb_sync_sg_for_cpu);
 
 void
 swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
-                          int nelems, int dir)
+                          int nelems, enum dma_data_direction dir)
 {
        swiotlb_sync_sg(hwdev, sg, nelems, dir, SYNC_FOR_DEVICE);
 }
index a5b77811fdf2c4b5f6b14a8d971a6519f6e420c6..b53427ad30a34618e6c8da34ffcc540a581de552 100644 (file)
@@ -206,7 +206,6 @@ config VIRT_TO_BUS
 config UNEVICTABLE_LRU
        bool "Add LRU list to track non-evictable pages"
        default y
-       depends on MMU
        help
          Keeps unevictable pages off of the active and inactive pageout
          lists, so kswapd will not waste CPU time or have its balancing
@@ -214,5 +213,13 @@ config UNEVICTABLE_LRU
          will use one page flag and increase the code size a little,
          say Y unless you know what you are doing.
 
+config HAVE_MLOCK
+       bool
+       default y if MMU=y
+
+config HAVE_MLOCKED_PAGE_BIT
+       bool
+       default y if HAVE_MLOCK=y && UNEVICTABLE_LRU=y
+
 config MMU_NOTIFIER
        bool
diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug
new file mode 100644 (file)
index 0000000..bb01e29
--- /dev/null
@@ -0,0 +1,26 @@
+config DEBUG_PAGEALLOC
+       bool "Debug page memory allocations"
+       depends on DEBUG_KERNEL && ARCH_SUPPORTS_DEBUG_PAGEALLOC
+       depends on !HIBERNATION || !PPC && !SPARC
+       ---help---
+         Unmap pages from the kernel linear mapping after free_pages().
+         This results in a large slowdown, but helps to find certain types
+         of memory corruptions.
+
+config WANT_PAGE_DEBUG_FLAGS
+       bool
+
+config PAGE_POISONING
+       bool "Debug page memory allocations"
+       depends on DEBUG_KERNEL && !ARCH_SUPPORTS_DEBUG_PAGEALLOC
+       depends on !HIBERNATION
+       select DEBUG_PAGEALLOC
+       select WANT_PAGE_DEBUG_FLAGS
+       help
+          Fill the pages with poison patterns after free_pages() and verify
+          the patterns before alloc_pages(). This results in a large slowdown,
+          but helps to find certain types of memory corruptions.
+
+          This option cannot enalbe with hibernation. Otherwise, it will get
+          wrong messages for memory corruption because the free pages are not
+          saved to the suspend image.
index 818569b68f4652e623f5d2bd4ed91fe68fcea2b4..ec73c68b601547680e6b1f49df5462b093a7e278 100644 (file)
@@ -24,6 +24,7 @@ obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o
 obj-$(CONFIG_TMPFS_POSIX_ACL) += shmem_acl.o
 obj-$(CONFIG_SLOB) += slob.o
 obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
+obj-$(CONFIG_PAGE_POISONING) += debug-pagealloc.o
 obj-$(CONFIG_SLAB) += slab.o
 obj-$(CONFIG_SLUB) += slub.o
 obj-$(CONFIG_FAILSLAB) += failslab.o
index 1882923bc706071b79f823dd17b8f69d4fccf145..139d5b7b6621471ccb88c2ea3dd6b0fe66b15618 100644 (file)
@@ -143,7 +143,7 @@ void free_percpu(void *__pdata)
 {
        if (unlikely(!__pdata))
                return;
-       __percpu_depopulate_mask(__pdata, &cpu_possible_map);
+       __percpu_depopulate_mask(__pdata, cpu_possible_mask);
        kfree(__percpu_disguise(__pdata));
 }
 EXPORT_SYMBOL_GPL(free_percpu);
diff --git a/mm/debug-pagealloc.c b/mm/debug-pagealloc.c
new file mode 100644 (file)
index 0000000..a1e3324
--- /dev/null
@@ -0,0 +1,129 @@
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/page-debug-flags.h>
+#include <linux/poison.h>
+
+static inline void set_page_poison(struct page *page)
+{
+       __set_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
+}
+
+static inline void clear_page_poison(struct page *page)
+{
+       __clear_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
+}
+
+static inline bool page_poison(struct page *page)
+{
+       return test_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
+}
+
+static void poison_highpage(struct page *page)
+{
+       /*
+        * Page poisoning for highmem pages is not implemented.
+        *
+        * This can be called from interrupt contexts.
+        * So we need to create a new kmap_atomic slot for this
+        * application and it will need interrupt protection.
+        */
+}
+
+static void poison_page(struct page *page)
+{
+       void *addr;
+
+       if (PageHighMem(page)) {
+               poison_highpage(page);
+               return;
+       }
+       set_page_poison(page);
+       addr = page_address(page);
+       memset(addr, PAGE_POISON, PAGE_SIZE);
+}
+
+static void poison_pages(struct page *page, int n)
+{
+       int i;
+
+       for (i = 0; i < n; i++)
+               poison_page(page + i);
+}
+
+static bool single_bit_flip(unsigned char a, unsigned char b)
+{
+       unsigned char error = a ^ b;
+
+       return error && !(error & (error - 1));
+}
+
+static void check_poison_mem(unsigned char *mem, size_t bytes)
+{
+       unsigned char *start;
+       unsigned char *end;
+
+       for (start = mem; start < mem + bytes; start++) {
+               if (*start != PAGE_POISON)
+                       break;
+       }
+       if (start == mem + bytes)
+               return;
+
+       for (end = mem + bytes - 1; end > start; end--) {
+               if (*end != PAGE_POISON)
+                       break;
+       }
+
+       if (!printk_ratelimit())
+               return;
+       else if (start == end && single_bit_flip(*start, PAGE_POISON))
+               printk(KERN_ERR "pagealloc: single bit error\n");
+       else
+               printk(KERN_ERR "pagealloc: memory corruption\n");
+
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, start,
+                       end - start + 1, 1);
+       dump_stack();
+}
+
+static void unpoison_highpage(struct page *page)
+{
+       /*
+        * See comment in poison_highpage().
+        * Highmem pages should not be poisoned for now
+        */
+       BUG_ON(page_poison(page));
+}
+
+static void unpoison_page(struct page *page)
+{
+       if (PageHighMem(page)) {
+               unpoison_highpage(page);
+               return;
+       }
+       if (page_poison(page)) {
+               void *addr = page_address(page);
+
+               check_poison_mem(addr, PAGE_SIZE);
+               clear_page_poison(page);
+       }
+}
+
+static void unpoison_pages(struct page *page, int n)
+{
+       int i;
+
+       for (i = 0; i < n; i++)
+               unpoison_page(page + i);
+}
+
+void kernel_map_pages(struct page *page, int numpages, int enable)
+{
+       if (!debug_pagealloc_enabled)
+               return;
+
+       if (enable)
+               unpoison_pages(page, numpages);
+       else
+               poison_pages(page, numpages);
+}
index 0c04615651b7e8b412e85cdeee26365ddee7515c..427dfe3ce78c68eebe0afde4636b6fdc91ecdec5 100644 (file)
@@ -89,8 +89,8 @@ do_xip_mapping_read(struct address_space *mapping,
                        }
                }
                nr = nr - offset;
-               if (nr > len)
-                       nr = len;
+               if (nr > len - copied)
+                       nr = len - copied;
 
                error = mapping->a_ops->get_xip_mem(mapping, index, 0,
                                                        &xip_mem, &xip_pfn);
index 910198037bf59baa6649a75d1d632203483aa22b..68eb1d9b63fa5daba881a8b6551fa38f8e0eabfc 100644 (file)
@@ -422,3 +422,48 @@ void __init page_address_init(void)
 }
 
 #endif /* defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL) */
+
+#if defined(CONFIG_DEBUG_HIGHMEM) && defined(CONFIG_TRACE_IRQFLAGS_SUPPORT)
+
+void debug_kmap_atomic(enum km_type type)
+{
+       static unsigned warn_count = 10;
+
+       if (unlikely(warn_count == 0))
+               return;
+
+       if (unlikely(in_interrupt())) {
+               if (in_irq()) {
+                       if (type != KM_IRQ0 && type != KM_IRQ1 &&
+                           type != KM_BIO_SRC_IRQ && type != KM_BIO_DST_IRQ &&
+                           type != KM_BOUNCE_READ) {
+                               WARN_ON(1);
+                               warn_count--;
+                       }
+               } else if (!irqs_disabled()) {  /* softirq */
+                       if (type != KM_IRQ0 && type != KM_IRQ1 &&
+                           type != KM_SOFTIRQ0 && type != KM_SOFTIRQ1 &&
+                           type != KM_SKB_SUNRPC_DATA &&
+                           type != KM_SKB_DATA_SOFTIRQ &&
+                           type != KM_BOUNCE_READ) {
+                               WARN_ON(1);
+                               warn_count--;
+                       }
+               }
+       }
+
+       if (type == KM_IRQ0 || type == KM_IRQ1 || type == KM_BOUNCE_READ ||
+                       type == KM_BIO_SRC_IRQ || type == KM_BIO_DST_IRQ) {
+               if (!irqs_disabled()) {
+                       WARN_ON(1);
+                       warn_count--;
+               }
+       } else if (type == KM_SOFTIRQ0 || type == KM_SOFTIRQ1) {
+               if (irq_count() == 0 && !irqs_disabled()) {
+                       WARN_ON(1);
+                       warn_count--;
+               }
+       }
+}
+
+#endif
index 107da3d809a87b0ad13e57256a050763a0b3d17b..28c655ba935396bb14a73957cb07ac58cb5e63fa 100644 (file)
@@ -918,7 +918,7 @@ static void return_unused_surplus_pages(struct hstate *h,
  * an instantiated the change should be committed via vma_commit_reservation.
  * No action is required on failure.
  */
-static int vma_needs_reservation(struct hstate *h,
+static long vma_needs_reservation(struct hstate *h,
                        struct vm_area_struct *vma, unsigned long addr)
 {
        struct address_space *mapping = vma->vm_file->f_mapping;
@@ -933,7 +933,7 @@ static int vma_needs_reservation(struct hstate *h,
                return 1;
 
        } else  {
-               int err;
+               long err;
                pgoff_t idx = vma_hugecache_offset(h, vma, addr);
                struct resv_map *reservations = vma_resv_map(vma);
 
@@ -969,7 +969,7 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
        struct page *page;
        struct address_space *mapping = vma->vm_file->f_mapping;
        struct inode *inode = mapping->host;
-       unsigned int chg;
+       long chg;
 
        /*
         * Processes that did not create the mapping will have no reserves and
index 478223b73a2ab22c4c6b62acf2a693f889b60367..987bb03fbdd88f33f36986b6ecbb33f02a62c6e2 100644 (file)
@@ -63,6 +63,7 @@ static inline unsigned long page_order(struct page *page)
        return page_private(page);
 }
 
+#ifdef CONFIG_HAVE_MLOCK
 extern long mlock_vma_pages_range(struct vm_area_struct *vma,
                        unsigned long start, unsigned long end);
 extern void munlock_vma_pages_range(struct vm_area_struct *vma,
@@ -71,6 +72,7 @@ static inline void munlock_vma_pages_all(struct vm_area_struct *vma)
 {
        munlock_vma_pages_range(vma, vma->vm_start, vma->vm_end);
 }
+#endif
 
 #ifdef CONFIG_UNEVICTABLE_LRU
 /*
@@ -90,7 +92,7 @@ static inline void unevictable_migrate_page(struct page *new, struct page *old)
 }
 #endif
 
-#ifdef CONFIG_UNEVICTABLE_LRU
+#ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT
 /*
  * Called only in fault path via page_evictable() for a new page
  * to determine if it's being mapped into a LOCKED vma.
@@ -165,7 +167,7 @@ static inline void free_page_mlock(struct page *page)
        }
 }
 
-#else /* CONFIG_UNEVICTABLE_LRU */
+#else /* CONFIG_HAVE_MLOCKED_PAGE_BIT */
 static inline int is_mlocked_vma(struct vm_area_struct *v, struct page *p)
 {
        return 0;
@@ -175,7 +177,7 @@ static inline void mlock_vma_page(struct page *page) { }
 static inline void mlock_migrate_page(struct page *new, struct page *old) { }
 static inline void free_page_mlock(struct page *page) { }
 
-#endif /* CONFIG_UNEVICTABLE_LRU */
+#endif /* CONFIG_HAVE_MLOCKED_PAGE_BIT */
 
 /*
  * Return the mem_map entry representing the 'offset' subpage within
index 8e4be9cb2a6a7642601516e3587d151dcea586f4..2fc6d6c482387ed35a735746bf4580d3d38e68da 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/backing-dev.h>
 #include <linux/bit_spinlock.h>
 #include <linux/rcupdate.h>
+#include <linux/limits.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/swap.h>
@@ -95,6 +96,15 @@ static s64 mem_cgroup_read_stat(struct mem_cgroup_stat *stat,
        return ret;
 }
 
+static s64 mem_cgroup_local_usage(struct mem_cgroup_stat *stat)
+{
+       s64 ret;
+
+       ret = mem_cgroup_read_stat(stat, MEM_CGROUP_STAT_CACHE);
+       ret += mem_cgroup_read_stat(stat, MEM_CGROUP_STAT_RSS);
+       return ret;
+}
+
 /*
  * per-zone information in memory controller.
  */
@@ -154,9 +164,9 @@ struct mem_cgroup {
 
        /*
         * While reclaiming in a hiearchy, we cache the last child we
-        * reclaimed from. Protected by hierarchy_mutex
+        * reclaimed from.
         */
-       struct mem_cgroup *last_scanned_child;
+       int last_scanned_child;
        /*
         * Should the accounting and control be hierarchical, per subtree?
         */
@@ -247,7 +257,7 @@ page_cgroup_zoneinfo(struct page_cgroup *pc)
        return mem_cgroup_zoneinfo(mem, nid, zid);
 }
 
-static unsigned long mem_cgroup_get_all_zonestat(struct mem_cgroup *mem,
+static unsigned long mem_cgroup_get_local_zonestat(struct mem_cgroup *mem,
                                        enum lru_list idx)
 {
        int nid, zid;
@@ -286,6 +296,9 @@ struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p)
 static struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
 {
        struct mem_cgroup *mem = NULL;
+
+       if (!mm)
+               return NULL;
        /*
         * Because we have no locks, mm->owner's may be being moved to other
         * cgroup. We use css_tryget() here even if this looks
@@ -308,6 +321,42 @@ static bool mem_cgroup_is_obsolete(struct mem_cgroup *mem)
        return css_is_removed(&mem->css);
 }
 
+
+/*
+ * Call callback function against all cgroup under hierarchy tree.
+ */
+static int mem_cgroup_walk_tree(struct mem_cgroup *root, void *data,
+                         int (*func)(struct mem_cgroup *, void *))
+{
+       int found, ret, nextid;
+       struct cgroup_subsys_state *css;
+       struct mem_cgroup *mem;
+
+       if (!root->use_hierarchy)
+               return (*func)(root, data);
+
+       nextid = 1;
+       do {
+               ret = 0;
+               mem = NULL;
+
+               rcu_read_lock();
+               css = css_get_next(&mem_cgroup_subsys, nextid, &root->css,
+                                  &found);
+               if (css && css_tryget(css))
+                       mem = container_of(css, struct mem_cgroup, css);
+               rcu_read_unlock();
+
+               if (mem) {
+                       ret = (*func)(mem, data);
+                       css_put(&mem->css);
+               }
+               nextid = found + 1;
+       } while (!ret && css);
+
+       return ret;
+}
+
 /*
  * Following LRU functions are allowed to be used without PCG_LOCK.
  * Operations are called by routine of global LRU independently from memcg.
@@ -441,30 +490,23 @@ void mem_cgroup_move_lists(struct page *page,
 int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *mem)
 {
        int ret;
+       struct mem_cgroup *curr = NULL;
 
        task_lock(task);
-       ret = task->mm && mm_match_cgroup(task->mm, mem);
+       rcu_read_lock();
+       curr = try_get_mem_cgroup_from_mm(task->mm);
+       rcu_read_unlock();
        task_unlock(task);
+       if (!curr)
+               return 0;
+       if (curr->use_hierarchy)
+               ret = css_is_ancestor(&curr->css, &mem->css);
+       else
+               ret = (curr == mem);
+       css_put(&curr->css);
        return ret;
 }
 
-/*
- * Calculate mapped_ratio under memory controller. This will be used in
- * vmscan.c for deteremining we have to reclaim mapped pages.
- */
-int mem_cgroup_calc_mapped_ratio(struct mem_cgroup *mem)
-{
-       long total, rss;
-
-       /*
-        * usage is recorded in bytes. But, here, we assume the number of
-        * physical pages can be represented by "long" on any arch.
-        */
-       total = (long) (mem->res.usage >> PAGE_SHIFT) + 1L;
-       rss = (long)mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_RSS);
-       return (int)((rss * 100L) / total);
-}
-
 /*
  * prev_priority control...this will be used in memory reclaim path.
  */
@@ -501,8 +543,8 @@ static int calc_inactive_ratio(struct mem_cgroup *memcg, unsigned long *present_
        unsigned long gb;
        unsigned long inactive_ratio;
 
-       inactive = mem_cgroup_get_all_zonestat(memcg, LRU_INACTIVE_ANON);
-       active = mem_cgroup_get_all_zonestat(memcg, LRU_ACTIVE_ANON);
+       inactive = mem_cgroup_get_local_zonestat(memcg, LRU_INACTIVE_ANON);
+       active = mem_cgroup_get_local_zonestat(memcg, LRU_ACTIVE_ANON);
 
        gb = (inactive + active) >> (30 - PAGE_SHIFT);
        if (gb)
@@ -629,172 +671,202 @@ unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
 #define mem_cgroup_from_res_counter(counter, member)   \
        container_of(counter, struct mem_cgroup, member)
 
-/*
- * This routine finds the DFS walk successor. This routine should be
- * called with hierarchy_mutex held
- */
-static struct mem_cgroup *
-__mem_cgroup_get_next_node(struct mem_cgroup *curr, struct mem_cgroup *root_mem)
+static bool mem_cgroup_check_under_limit(struct mem_cgroup *mem)
 {
-       struct cgroup *cgroup, *curr_cgroup, *root_cgroup;
-
-       curr_cgroup = curr->css.cgroup;
-       root_cgroup = root_mem->css.cgroup;
+       if (do_swap_account) {
+               if (res_counter_check_under_limit(&mem->res) &&
+                       res_counter_check_under_limit(&mem->memsw))
+                       return true;
+       } else
+               if (res_counter_check_under_limit(&mem->res))
+                       return true;
+       return false;
+}
 
-       if (!list_empty(&curr_cgroup->children)) {
-               /*
-                * Walk down to children
-                */
-               cgroup = list_entry(curr_cgroup->children.next,
-                                               struct cgroup, sibling);
-               curr = mem_cgroup_from_cont(cgroup);
-               goto done;
-       }
+static unsigned int get_swappiness(struct mem_cgroup *memcg)
+{
+       struct cgroup *cgrp = memcg->css.cgroup;
+       unsigned int swappiness;
 
-visit_parent:
-       if (curr_cgroup == root_cgroup) {
-               /* caller handles NULL case */
-               curr = NULL;
-               goto done;
-       }
+       /* root ? */
+       if (cgrp->parent == NULL)
+               return vm_swappiness;
 
-       /*
-        * Goto next sibling
-        */
-       if (curr_cgroup->sibling.next != &curr_cgroup->parent->children) {
-               cgroup = list_entry(curr_cgroup->sibling.next, struct cgroup,
-                                               sibling);
-               curr = mem_cgroup_from_cont(cgroup);
-               goto done;
-       }
+       spin_lock(&memcg->reclaim_param_lock);
+       swappiness = memcg->swappiness;
+       spin_unlock(&memcg->reclaim_param_lock);
 
-       /*
-        * Go up to next parent and next parent's sibling if need be
-        */
-       curr_cgroup = curr_cgroup->parent;
-       goto visit_parent;
+       return swappiness;
+}
 
-done:
-       return curr;
+static int mem_cgroup_count_children_cb(struct mem_cgroup *mem, void *data)
+{
+       int *val = data;
+       (*val)++;
+       return 0;
 }
 
-/*
- * Visit the first child (need not be the first child as per the ordering
- * of the cgroup list, since we track last_scanned_child) of @mem and use
- * that to reclaim free pages from.
+/**
+ * mem_cgroup_print_mem_info: Called from OOM with tasklist_lock held in read mode.
+ * @memcg: The memory cgroup that went over limit
+ * @p: Task that is going to be killed
+ *
+ * NOTE: @memcg and @p's mem_cgroup can be different when hierarchy is
+ * enabled
  */
-static struct mem_cgroup *
-mem_cgroup_get_next_node(struct mem_cgroup *root_mem)
+void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
 {
-       struct cgroup *cgroup;
-       struct mem_cgroup *orig, *next;
-       bool obsolete;
-
+       struct cgroup *task_cgrp;
+       struct cgroup *mem_cgrp;
        /*
-        * Scan all children under the mem_cgroup mem
+        * Need a buffer in BSS, can't rely on allocations. The code relies
+        * on the assumption that OOM is serialized for memory controller.
+        * If this assumption is broken, revisit this code.
         */
-       mutex_lock(&mem_cgroup_subsys.hierarchy_mutex);
+       static char memcg_name[PATH_MAX];
+       int ret;
+
+       if (!memcg)
+               return;
 
-       orig = root_mem->last_scanned_child;
-       obsolete = mem_cgroup_is_obsolete(orig);
 
-       if (list_empty(&root_mem->css.cgroup->children)) {
+       rcu_read_lock();
+
+       mem_cgrp = memcg->css.cgroup;
+       task_cgrp = task_cgroup(p, mem_cgroup_subsys_id);
+
+       ret = cgroup_path(task_cgrp, memcg_name, PATH_MAX);
+       if (ret < 0) {
                /*
-                * root_mem might have children before and last_scanned_child
-                * may point to one of them. We put it later.
+                * Unfortunately, we are unable to convert to a useful name
+                * But we'll still print out the usage information
                 */
-               if (orig)
-                       VM_BUG_ON(!obsolete);
-               next = NULL;
+               rcu_read_unlock();
                goto done;
        }
+       rcu_read_unlock();
 
-       if (!orig || obsolete) {
-               cgroup = list_first_entry(&root_mem->css.cgroup->children,
-                               struct cgroup, sibling);
-               next = mem_cgroup_from_cont(cgroup);
-       } else
-               next = __mem_cgroup_get_next_node(orig, root_mem);
+       printk(KERN_INFO "Task in %s killed", memcg_name);
 
+       rcu_read_lock();
+       ret = cgroup_path(mem_cgrp, memcg_name, PATH_MAX);
+       if (ret < 0) {
+               rcu_read_unlock();
+               goto done;
+       }
+       rcu_read_unlock();
+
+       /*
+        * Continues from above, so we don't need an KERN_ level
+        */
+       printk(KERN_CONT " as a result of limit of %s\n", memcg_name);
 done:
-       if (next)
-               mem_cgroup_get(next);
-       root_mem->last_scanned_child = next;
-       if (orig)
-               mem_cgroup_put(orig);
-       mutex_unlock(&mem_cgroup_subsys.hierarchy_mutex);
-       return (next) ? next : root_mem;
+
+       printk(KERN_INFO "memory: usage %llukB, limit %llukB, failcnt %llu\n",
+               res_counter_read_u64(&memcg->res, RES_USAGE) >> 10,
+               res_counter_read_u64(&memcg->res, RES_LIMIT) >> 10,
+               res_counter_read_u64(&memcg->res, RES_FAILCNT));
+       printk(KERN_INFO "memory+swap: usage %llukB, limit %llukB, "
+               "failcnt %llu\n",
+               res_counter_read_u64(&memcg->memsw, RES_USAGE) >> 10,
+               res_counter_read_u64(&memcg->memsw, RES_LIMIT) >> 10,
+               res_counter_read_u64(&memcg->memsw, RES_FAILCNT));
 }
 
-static bool mem_cgroup_check_under_limit(struct mem_cgroup *mem)
+/*
+ * This function returns the number of memcg under hierarchy tree. Returns
+ * 1(self count) if no children.
+ */
+static int mem_cgroup_count_children(struct mem_cgroup *mem)
 {
-       if (do_swap_account) {
-               if (res_counter_check_under_limit(&mem->res) &&
-                       res_counter_check_under_limit(&mem->memsw))
-                       return true;
-       } else
-               if (res_counter_check_under_limit(&mem->res))
-                       return true;
-       return false;
+       int num = 0;
+       mem_cgroup_walk_tree(mem, &num, mem_cgroup_count_children_cb);
+       return num;
 }
 
-static unsigned int get_swappiness(struct mem_cgroup *memcg)
+/*
+ * Visit the first child (need not be the first child as per the ordering
+ * of the cgroup list, since we track last_scanned_child) of @mem and use
+ * that to reclaim free pages from.
+ */
+static struct mem_cgroup *
+mem_cgroup_select_victim(struct mem_cgroup *root_mem)
 {
-       struct cgroup *cgrp = memcg->css.cgroup;
-       unsigned int swappiness;
+       struct mem_cgroup *ret = NULL;
+       struct cgroup_subsys_state *css;
+       int nextid, found;
 
-       /* root ? */
-       if (cgrp->parent == NULL)
-               return vm_swappiness;
+       if (!root_mem->use_hierarchy) {
+               css_get(&root_mem->css);
+               ret = root_mem;
+       }
 
-       spin_lock(&memcg->reclaim_param_lock);
-       swappiness = memcg->swappiness;
-       spin_unlock(&memcg->reclaim_param_lock);
+       while (!ret) {
+               rcu_read_lock();
+               nextid = root_mem->last_scanned_child + 1;
+               css = css_get_next(&mem_cgroup_subsys, nextid, &root_mem->css,
+                                  &found);
+               if (css && css_tryget(css))
+                       ret = container_of(css, struct mem_cgroup, css);
+
+               rcu_read_unlock();
+               /* Updates scanning parameter */
+               spin_lock(&root_mem->reclaim_param_lock);
+               if (!css) {
+                       /* this means start scan from ID:1 */
+                       root_mem->last_scanned_child = 0;
+               } else
+                       root_mem->last_scanned_child = found;
+               spin_unlock(&root_mem->reclaim_param_lock);
+       }
 
-       return swappiness;
+       return ret;
 }
 
 /*
- * Dance down the hierarchy if needed to reclaim memory. We remember the
- * last child we reclaimed from, so that we don't end up penalizing
- * one child extensively based on its position in the children list.
+ * Scan the hierarchy if needed to reclaim memory. We remember the last child
+ * we reclaimed from, so that we don't end up penalizing one child extensively
+ * based on its position in the children list.
  *
  * root_mem is the original ancestor that we've been reclaim from.
+ *
+ * We give up and return to the caller when we visit root_mem twice.
+ * (other groups can be removed while we're walking....)
+ *
+ * If shrink==true, for avoiding to free too much, this returns immedieately.
  */
 static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
-                                               gfp_t gfp_mask, bool noswap)
-{
-       struct mem_cgroup *next_mem;
-       int ret = 0;
-
-       /*
-        * Reclaim unconditionally and don't check for return value.
-        * We need to reclaim in the current group and down the tree.
-        * One might think about checking for children before reclaiming,
-        * but there might be left over accounting, even after children
-        * have left.
-        */
-       ret += try_to_free_mem_cgroup_pages(root_mem, gfp_mask, noswap,
-                                          get_swappiness(root_mem));
-       if (mem_cgroup_check_under_limit(root_mem))
-               return 1;       /* indicate reclaim has succeeded */
-       if (!root_mem->use_hierarchy)
-               return ret;
-
-       next_mem = mem_cgroup_get_next_node(root_mem);
-
-       while (next_mem != root_mem) {
-               if (mem_cgroup_is_obsolete(next_mem)) {
-                       next_mem = mem_cgroup_get_next_node(root_mem);
+                                  gfp_t gfp_mask, bool noswap, bool shrink)
+{
+       struct mem_cgroup *victim;
+       int ret, total = 0;
+       int loop = 0;
+
+       while (loop < 2) {
+               victim = mem_cgroup_select_victim(root_mem);
+               if (victim == root_mem)
+                       loop++;
+               if (!mem_cgroup_local_usage(&victim->stat)) {
+                       /* this cgroup's local usage == 0 */
+                       css_put(&victim->css);
                        continue;
                }
-               ret += try_to_free_mem_cgroup_pages(next_mem, gfp_mask, noswap,
-                                                  get_swappiness(next_mem));
+               /* we use swappiness of local cgroup */
+               ret = try_to_free_mem_cgroup_pages(victim, gfp_mask, noswap,
+                                                  get_swappiness(victim));
+               css_put(&victim->css);
+               /*
+                * At shrinking usage, we can't check we should stop here or
+                * reclaim more. It's depends on callers. last_scanned_child
+                * will work enough for keeping fairness under tree.
+                */
+               if (shrink)
+                       return ret;
+               total += ret;
                if (mem_cgroup_check_under_limit(root_mem))
-                       return 1;       /* indicate reclaim has succeeded */
-               next_mem = mem_cgroup_get_next_node(root_mem);
+                       return 1 + total;
        }
-       return ret;
+       return total;
 }
 
 bool mem_cgroup_oom_called(struct task_struct *task)
@@ -813,6 +885,19 @@ bool mem_cgroup_oom_called(struct task_struct *task)
        rcu_read_unlock();
        return ret;
 }
+
+static int record_last_oom_cb(struct mem_cgroup *mem, void *data)
+{
+       mem->last_oom_jiffies = jiffies;
+       return 0;
+}
+
+static void record_last_oom(struct mem_cgroup *mem)
+{
+       mem_cgroup_walk_tree(mem, NULL, record_last_oom_cb);
+}
+
+
 /*
  * Unlike exported interface, "oom" parameter is added. if oom==true,
  * oom-killer can be invoked.
@@ -875,7 +960,7 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm,
                        goto nomem;
 
                ret = mem_cgroup_hierarchical_reclaim(mem_over_limit, gfp_mask,
-                                                       noswap);
+                                                       noswap, false);
                if (ret)
                        continue;
 
@@ -895,7 +980,7 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm,
                                mutex_lock(&memcg_tasklist);
                                mem_cgroup_out_of_memory(mem_over_limit, gfp_mask);
                                mutex_unlock(&memcg_tasklist);
-                               mem_over_limit->last_oom_jiffies = jiffies;
+                               record_last_oom(mem_over_limit);
                        }
                        goto nomem;
                }
@@ -906,20 +991,55 @@ nomem:
        return -ENOMEM;
 }
 
+
+/*
+ * A helper function to get mem_cgroup from ID. must be called under
+ * rcu_read_lock(). The caller must check css_is_removed() or some if
+ * it's concern. (dropping refcnt from swap can be called against removed
+ * memcg.)
+ */
+static struct mem_cgroup *mem_cgroup_lookup(unsigned short id)
+{
+       struct cgroup_subsys_state *css;
+
+       /* ID 0 is unused ID */
+       if (!id)
+               return NULL;
+       css = css_lookup(&mem_cgroup_subsys, id);
+       if (!css)
+               return NULL;
+       return container_of(css, struct mem_cgroup, css);
+}
+
 static struct mem_cgroup *try_get_mem_cgroup_from_swapcache(struct page *page)
 {
        struct mem_cgroup *mem;
+       struct page_cgroup *pc;
+       unsigned short id;
        swp_entry_t ent;
 
+       VM_BUG_ON(!PageLocked(page));
+
        if (!PageSwapCache(page))
                return NULL;
 
-       ent.val = page_private(page);
-       mem = lookup_swap_cgroup(ent);
-       if (!mem)
-               return NULL;
-       if (!css_tryget(&mem->css))
-               return NULL;
+       pc = lookup_page_cgroup(page);
+       /*
+        * Used bit of swapcache is solid under page lock.
+        */
+       if (PageCgroupUsed(pc)) {
+               mem = pc->mem_cgroup;
+               if (mem && !css_tryget(&mem->css))
+                       mem = NULL;
+       } else {
+               ent.val = page_private(page);
+               id = lookup_swap_cgroup(ent);
+               rcu_read_lock();
+               mem = mem_cgroup_lookup(id);
+               if (mem && !css_tryget(&mem->css))
+                       mem = NULL;
+               rcu_read_unlock();
+       }
        return mem;
 }
 
@@ -1118,6 +1238,10 @@ int mem_cgroup_newpage_charge(struct page *page,
                                MEM_CGROUP_CHARGE_TYPE_MAPPED, NULL);
 }
 
+static void
+__mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
+                                       enum charge_type ctype);
+
 int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
                                gfp_t gfp_mask)
 {
@@ -1154,16 +1278,6 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
                unlock_page_cgroup(pc);
        }
 
-       if (do_swap_account && PageSwapCache(page)) {
-               mem = try_get_mem_cgroup_from_swapcache(page);
-               if (mem)
-                       mm = NULL;
-                 else
-                       mem = NULL;
-               /* SwapCache may be still linked to LRU now. */
-               mem_cgroup_lru_del_before_commit_swapcache(page);
-       }
-
        if (unlikely(!mm && !mem))
                mm = &init_mm;
 
@@ -1171,22 +1285,16 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
                return mem_cgroup_charge_common(page, mm, gfp_mask,
                                MEM_CGROUP_CHARGE_TYPE_CACHE, NULL);
 
-       ret = mem_cgroup_charge_common(page, mm, gfp_mask,
-                               MEM_CGROUP_CHARGE_TYPE_SHMEM, mem);
-       if (mem)
-               css_put(&mem->css);
-       if (PageSwapCache(page))
-               mem_cgroup_lru_add_after_commit_swapcache(page);
+       /* shmem */
+       if (PageSwapCache(page)) {
+               ret = mem_cgroup_try_charge_swapin(mm, page, gfp_mask, &mem);
+               if (!ret)
+                       __mem_cgroup_commit_charge_swapin(page, mem,
+                                       MEM_CGROUP_CHARGE_TYPE_SHMEM);
+       } else
+               ret = mem_cgroup_charge_common(page, mm, gfp_mask,
+                                       MEM_CGROUP_CHARGE_TYPE_SHMEM, mem);
 
-       if (do_swap_account && !ret && PageSwapCache(page)) {
-               swp_entry_t ent = {.val = page_private(page)};
-               /* avoid double counting */
-               mem = swap_cgroup_record(ent, NULL);
-               if (mem) {
-                       res_counter_uncharge(&mem->memsw, PAGE_SIZE);
-                       mem_cgroup_put(mem);
-               }
-       }
        return ret;
 }
 
@@ -1229,7 +1337,9 @@ charge_cur_mm:
        return __mem_cgroup_try_charge(mm, mask, ptr, true);
 }
 
-void mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr)
+static void
+__mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
+                                       enum charge_type ctype)
 {
        struct page_cgroup *pc;
 
@@ -1239,7 +1349,7 @@ void mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr)
                return;
        pc = lookup_page_cgroup(page);
        mem_cgroup_lru_del_before_commit_swapcache(page);
-       __mem_cgroup_commit_charge(ptr, pc, MEM_CGROUP_CHARGE_TYPE_MAPPED);
+       __mem_cgroup_commit_charge(ptr, pc, ctype);
        mem_cgroup_lru_add_after_commit_swapcache(page);
        /*
         * Now swap is on-memory. This means this page may be
@@ -1250,18 +1360,32 @@ void mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr)
         */
        if (do_swap_account && PageSwapCache(page)) {
                swp_entry_t ent = {.val = page_private(page)};
+               unsigned short id;
                struct mem_cgroup *memcg;
-               memcg = swap_cgroup_record(ent, NULL);
+
+               id = swap_cgroup_record(ent, 0);
+               rcu_read_lock();
+               memcg = mem_cgroup_lookup(id);
                if (memcg) {
+                       /*
+                        * This recorded memcg can be obsolete one. So, avoid
+                        * calling css_tryget
+                        */
                        res_counter_uncharge(&memcg->memsw, PAGE_SIZE);
                        mem_cgroup_put(memcg);
                }
-
+               rcu_read_unlock();
        }
        /* add this page(page_cgroup) to the LRU we want. */
 
 }
 
+void mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr)
+{
+       __mem_cgroup_commit_charge_swapin(page, ptr,
+                                       MEM_CGROUP_CHARGE_TYPE_MAPPED);
+}
+
 void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *mem)
 {
        if (mem_cgroup_disabled())
@@ -1324,8 +1448,8 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
        res_counter_uncharge(&mem->res, PAGE_SIZE);
        if (do_swap_account && (ctype != MEM_CGROUP_CHARGE_TYPE_SWAPOUT))
                res_counter_uncharge(&mem->memsw, PAGE_SIZE);
-
        mem_cgroup_charge_statistics(mem, pc, false);
+
        ClearPageCgroupUsed(pc);
        /*
         * pc->mem_cgroup is not cleared here. It will be accessed when it's
@@ -1377,7 +1501,7 @@ void mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent)
                                        MEM_CGROUP_CHARGE_TYPE_SWAPOUT);
        /* record memcg information */
        if (do_swap_account && memcg) {
-               swap_cgroup_record(ent, memcg);
+               swap_cgroup_record(ent, css_id(&memcg->css));
                mem_cgroup_get(memcg);
        }
        if (memcg)
@@ -1392,15 +1516,23 @@ void mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent)
 void mem_cgroup_uncharge_swap(swp_entry_t ent)
 {
        struct mem_cgroup *memcg;
+       unsigned short id;
 
        if (!do_swap_account)
                return;
 
-       memcg = swap_cgroup_record(ent, NULL);
+       id = swap_cgroup_record(ent, 0);
+       rcu_read_lock();
+       memcg = mem_cgroup_lookup(id);
        if (memcg) {
+               /*
+                * We uncharge this because swap is freed.
+                * This memcg can be obsolete one. We avoid calling css_tryget
+                */
                res_counter_uncharge(&memcg->memsw, PAGE_SIZE);
                mem_cgroup_put(memcg);
        }
+       rcu_read_unlock();
 }
 #endif
 
@@ -1508,7 +1640,8 @@ int mem_cgroup_shrink_usage(struct page *page,
                return 0;
 
        do {
-               progress = mem_cgroup_hierarchical_reclaim(mem, gfp_mask, true);
+               progress = mem_cgroup_hierarchical_reclaim(mem,
+                                       gfp_mask, true, false);
                progress += mem_cgroup_check_under_limit(mem);
        } while (!progress && --retry);
 
@@ -1523,11 +1656,21 @@ static DEFINE_MUTEX(set_limit_mutex);
 static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
                                unsigned long long val)
 {
-
-       int retry_count = MEM_CGROUP_RECLAIM_RETRIES;
+       int retry_count;
        int progress;
        u64 memswlimit;
        int ret = 0;
+       int children = mem_cgroup_count_children(memcg);
+       u64 curusage, oldusage;
+
+       /*
+        * For keeping hierarchical_reclaim simple, how long we should retry
+        * is depends on callers. We set our retry-count to be function
+        * of # of children which we should visit in this loop.
+        */
+       retry_count = MEM_CGROUP_RECLAIM_RETRIES * children;
+
+       oldusage = res_counter_read_u64(&memcg->res, RES_USAGE);
 
        while (retry_count) {
                if (signal_pending(current)) {
@@ -1553,8 +1696,13 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
                        break;
 
                progress = mem_cgroup_hierarchical_reclaim(memcg, GFP_KERNEL,
-                                                          false);
-               if (!progress)                  retry_count--;
+                                                  false, true);
+               curusage = res_counter_read_u64(&memcg->res, RES_USAGE);
+               /* Usage is reduced ? */
+               if (curusage >= oldusage)
+                       retry_count--;
+               else
+                       oldusage = curusage;
        }
 
        return ret;
@@ -1563,13 +1711,16 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
 int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
                                unsigned long long val)
 {
-       int retry_count = MEM_CGROUP_RECLAIM_RETRIES;
+       int retry_count;
        u64 memlimit, oldusage, curusage;
-       int ret;
+       int children = mem_cgroup_count_children(memcg);
+       int ret = -EBUSY;
 
        if (!do_swap_account)
                return -EINVAL;
-
+       /* see mem_cgroup_resize_res_limit */
+       retry_count = children * MEM_CGROUP_RECLAIM_RETRIES;
+       oldusage = res_counter_read_u64(&memcg->memsw, RES_USAGE);
        while (retry_count) {
                if (signal_pending(current)) {
                        ret = -EINTR;
@@ -1593,11 +1744,13 @@ int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
                if (!ret)
                        break;
 
-               oldusage = res_counter_read_u64(&memcg->memsw, RES_USAGE);
-               mem_cgroup_hierarchical_reclaim(memcg, GFP_KERNEL, true);
+               mem_cgroup_hierarchical_reclaim(memcg, GFP_KERNEL, true, true);
                curusage = res_counter_read_u64(&memcg->memsw, RES_USAGE);
+               /* Usage is reduced ? */
                if (curusage >= oldusage)
                        retry_count--;
+               else
+                       oldusage = curusage;
        }
        return ret;
 }
@@ -1893,54 +2046,90 @@ static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
        return 0;
 }
 
-static const struct mem_cgroup_stat_desc {
-       const char *msg;
-       u64 unit;
-} mem_cgroup_stat_desc[] = {
-       [MEM_CGROUP_STAT_CACHE] = { "cache", PAGE_SIZE, },
-       [MEM_CGROUP_STAT_RSS] = { "rss", PAGE_SIZE, },
-       [MEM_CGROUP_STAT_PGPGIN_COUNT] = {"pgpgin", 1, },
-       [MEM_CGROUP_STAT_PGPGOUT_COUNT] = {"pgpgout", 1, },
+
+/* For read statistics */
+enum {
+       MCS_CACHE,
+       MCS_RSS,
+       MCS_PGPGIN,
+       MCS_PGPGOUT,
+       MCS_INACTIVE_ANON,
+       MCS_ACTIVE_ANON,
+       MCS_INACTIVE_FILE,
+       MCS_ACTIVE_FILE,
+       MCS_UNEVICTABLE,
+       NR_MCS_STAT,
+};
+
+struct mcs_total_stat {
+       s64 stat[NR_MCS_STAT];
+};
+
+struct {
+       char *local_name;
+       char *total_name;
+} memcg_stat_strings[NR_MCS_STAT] = {
+       {"cache", "total_cache"},
+       {"rss", "total_rss"},
+       {"pgpgin", "total_pgpgin"},
+       {"pgpgout", "total_pgpgout"},
+       {"inactive_anon", "total_inactive_anon"},
+       {"active_anon", "total_active_anon"},
+       {"inactive_file", "total_inactive_file"},
+       {"active_file", "total_active_file"},
+       {"unevictable", "total_unevictable"}
 };
 
+
+static int mem_cgroup_get_local_stat(struct mem_cgroup *mem, void *data)
+{
+       struct mcs_total_stat *s = data;
+       s64 val;
+
+       /* per cpu stat */
+       val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_CACHE);
+       s->stat[MCS_CACHE] += val * PAGE_SIZE;
+       val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_RSS);
+       s->stat[MCS_RSS] += val * PAGE_SIZE;
+       val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGIN_COUNT);
+       s->stat[MCS_PGPGIN] += val;
+       val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGOUT_COUNT);
+       s->stat[MCS_PGPGOUT] += val;
+
+       /* per zone stat */
+       val = mem_cgroup_get_local_zonestat(mem, LRU_INACTIVE_ANON);
+       s->stat[MCS_INACTIVE_ANON] += val * PAGE_SIZE;
+       val = mem_cgroup_get_local_zonestat(mem, LRU_ACTIVE_ANON);
+       s->stat[MCS_ACTIVE_ANON] += val * PAGE_SIZE;
+       val = mem_cgroup_get_local_zonestat(mem, LRU_INACTIVE_FILE);
+       s->stat[MCS_INACTIVE_FILE] += val * PAGE_SIZE;
+       val = mem_cgroup_get_local_zonestat(mem, LRU_ACTIVE_FILE);
+       s->stat[MCS_ACTIVE_FILE] += val * PAGE_SIZE;
+       val = mem_cgroup_get_local_zonestat(mem, LRU_UNEVICTABLE);
+       s->stat[MCS_UNEVICTABLE] += val * PAGE_SIZE;
+       return 0;
+}
+
+static void
+mem_cgroup_get_total_stat(struct mem_cgroup *mem, struct mcs_total_stat *s)
+{
+       mem_cgroup_walk_tree(mem, s, mem_cgroup_get_local_stat);
+}
+
 static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft,
                                 struct cgroup_map_cb *cb)
 {
        struct mem_cgroup *mem_cont = mem_cgroup_from_cont(cont);
-       struct mem_cgroup_stat *stat = &mem_cont->stat;
+       struct mcs_total_stat mystat;
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(stat->cpustat[0].count); i++) {
-               s64 val;
+       memset(&mystat, 0, sizeof(mystat));
+       mem_cgroup_get_local_stat(mem_cont, &mystat);
 
-               val = mem_cgroup_read_stat(stat, i);
-               val *= mem_cgroup_stat_desc[i].unit;
-               cb->fill(cb, mem_cgroup_stat_desc[i].msg, val);
-       }
-       /* showing # of active pages */
-       {
-               unsigned long active_anon, inactive_anon;
-               unsigned long active_file, inactive_file;
-               unsigned long unevictable;
-
-               inactive_anon = mem_cgroup_get_all_zonestat(mem_cont,
-                                               LRU_INACTIVE_ANON);
-               active_anon = mem_cgroup_get_all_zonestat(mem_cont,
-                                               LRU_ACTIVE_ANON);
-               inactive_file = mem_cgroup_get_all_zonestat(mem_cont,
-                                               LRU_INACTIVE_FILE);
-               active_file = mem_cgroup_get_all_zonestat(mem_cont,
-                                               LRU_ACTIVE_FILE);
-               unevictable = mem_cgroup_get_all_zonestat(mem_cont,
-                                                       LRU_UNEVICTABLE);
-
-               cb->fill(cb, "active_anon", (active_anon) * PAGE_SIZE);
-               cb->fill(cb, "inactive_anon", (inactive_anon) * PAGE_SIZE);
-               cb->fill(cb, "active_file", (active_file) * PAGE_SIZE);
-               cb->fill(cb, "inactive_file", (inactive_file) * PAGE_SIZE);
-               cb->fill(cb, "unevictable", unevictable * PAGE_SIZE);
+       for (i = 0; i < NR_MCS_STAT; i++)
+               cb->fill(cb, memcg_stat_strings[i].local_name, mystat.stat[i]);
 
-       }
+       /* Hierarchical information */
        {
                unsigned long long limit, memsw_limit;
                memcg_get_hierarchical_limit(mem_cont, &limit, &memsw_limit);
@@ -1949,6 +2138,12 @@ static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft,
                        cb->fill(cb, "hierarchical_memsw_limit", memsw_limit);
        }
 
+       memset(&mystat, 0, sizeof(mystat));
+       mem_cgroup_get_total_stat(mem_cont, &mystat);
+       for (i = 0; i < NR_MCS_STAT; i++)
+               cb->fill(cb, memcg_stat_strings[i].total_name, mystat.stat[i]);
+
+
 #ifdef CONFIG_DEBUG_VM
        cb->fill(cb, "inactive_ratio", calc_inactive_ratio(mem_cont, NULL));
 
@@ -2178,6 +2373,8 @@ static void __mem_cgroup_free(struct mem_cgroup *mem)
 {
        int node;
 
+       free_css_id(&mem_cgroup_subsys, &mem->css);
+
        for_each_node_state(node, N_POSSIBLE)
                free_mem_cgroup_per_zone_info(mem, node);
 
@@ -2228,11 +2425,12 @@ static struct cgroup_subsys_state * __ref
 mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
 {
        struct mem_cgroup *mem, *parent;
+       long error = -ENOMEM;
        int node;
 
        mem = mem_cgroup_alloc();
        if (!mem)
-               return ERR_PTR(-ENOMEM);
+               return ERR_PTR(error);
 
        for_each_node_state(node, N_POSSIBLE)
                if (alloc_mem_cgroup_per_zone_info(mem, node))
@@ -2260,7 +2458,7 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
                res_counter_init(&mem->res, NULL);
                res_counter_init(&mem->memsw, NULL);
        }
-       mem->last_scanned_child = NULL;
+       mem->last_scanned_child = 0;
        spin_lock_init(&mem->reclaim_param_lock);
 
        if (parent)
@@ -2269,26 +2467,22 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
        return &mem->css;
 free_out:
        __mem_cgroup_free(mem);
-       return ERR_PTR(-ENOMEM);
+       return ERR_PTR(error);
 }
 
-static void mem_cgroup_pre_destroy(struct cgroup_subsys *ss,
+static int mem_cgroup_pre_destroy(struct cgroup_subsys *ss,
                                        struct cgroup *cont)
 {
        struct mem_cgroup *mem = mem_cgroup_from_cont(cont);
-       mem_cgroup_force_empty(mem, false);
+
+       return mem_cgroup_force_empty(mem, false);
 }
 
 static void mem_cgroup_destroy(struct cgroup_subsys *ss,
                                struct cgroup *cont)
 {
        struct mem_cgroup *mem = mem_cgroup_from_cont(cont);
-       struct mem_cgroup *last_scanned_child = mem->last_scanned_child;
 
-       if (last_scanned_child) {
-               VM_BUG_ON(!mem_cgroup_is_obsolete(last_scanned_child));
-               mem_cgroup_put(last_scanned_child);
-       }
        mem_cgroup_put(mem);
 }
 
@@ -2327,6 +2521,7 @@ struct cgroup_subsys mem_cgroup_subsys = {
        .populate = mem_cgroup_populate,
        .attach = mem_cgroup_move_task,
        .early_init = 0,
+       .use_id = 1,
 };
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
index baa999e87cd21d2f9e67c8e3b1093bb6831513fb..cf6873e91c6a7eeb166031a7c8ae9fd4f3dda100 100644 (file)
@@ -1151,6 +1151,11 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
                if ((flags & FOLL_WRITE) &&
                    !pte_dirty(pte) && !PageDirty(page))
                        set_page_dirty(page);
+               /*
+                * pte_mkyoung() would be more correct here, but atomic care
+                * is needed to avoid losing the dirty bit: it is easier to use
+                * mark_page_accessed().
+                */
                mark_page_accessed(page);
        }
 unlock:
@@ -1665,9 +1670,10 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
         * behaviour that some programs depend on. We mark the "original"
         * un-COW'ed pages by matching them up with "vma->vm_pgoff".
         */
-       if (addr == vma->vm_start && end == vma->vm_end)
+       if (addr == vma->vm_start && end == vma->vm_end) {
                vma->vm_pgoff = pfn;
-       else if (is_cow_mapping(vma->vm_flags))
+               vma->vm_flags |= VM_PFN_AT_MMAP;
+       } else if (is_cow_mapping(vma->vm_flags))
                return -EINVAL;
 
        vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
@@ -1679,6 +1685,7 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
                 * needed from higher level routine calling unmap_vmas
                 */
                vma->vm_flags &= ~(VM_IO | VM_RESERVED | VM_PFNMAP);
+               vma->vm_flags &= ~VM_PFN_AT_MMAP;
                return -EINVAL;
        }
 
@@ -1938,6 +1945,15 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
                 * get_user_pages(.write=1, .force=1).
                 */
                if (vma->vm_ops && vma->vm_ops->page_mkwrite) {
+                       struct vm_fault vmf;
+                       int tmp;
+
+                       vmf.virtual_address = (void __user *)(address &
+                                                               PAGE_MASK);
+                       vmf.pgoff = old_page->index;
+                       vmf.flags = FAULT_FLAG_WRITE|FAULT_FLAG_MKWRITE;
+                       vmf.page = old_page;
+
                        /*
                         * Notify the address space that the page is about to
                         * become writable so that it can prohibit this or wait
@@ -1949,8 +1965,12 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
                        page_cache_get(old_page);
                        pte_unmap_unlock(page_table, ptl);
 
-                       if (vma->vm_ops->page_mkwrite(vma, old_page) < 0)
+                       tmp = vma->vm_ops->page_mkwrite(vma, &vmf);
+                       if (unlikely(tmp &
+                                       (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) {
+                               ret = tmp;
                                goto unwritable_page;
+                       }
 
                        /*
                         * Since we dropped the lock we need to revalidate
@@ -2099,7 +2119,7 @@ oom:
 
 unwritable_page:
        page_cache_release(old_page);
-       return VM_FAULT_SIGBUS;
+       return ret;
 }
 
 /*
@@ -2433,8 +2453,6 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
                count_vm_event(PGMAJFAULT);
        }
 
-       mark_page_accessed(page);
-
        lock_page(page);
        delayacct_clear_flag(DELAYACCT_PF_SWAPIN);
 
@@ -2643,9 +2661,14 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                         * to become writable
                         */
                        if (vma->vm_ops->page_mkwrite) {
+                               int tmp;
+
                                unlock_page(page);
-                               if (vma->vm_ops->page_mkwrite(vma, page) < 0) {
-                                       ret = VM_FAULT_SIGBUS;
+                               vmf.flags |= FAULT_FLAG_MKWRITE;
+                               tmp = vma->vm_ops->page_mkwrite(vma, &vmf);
+                               if (unlikely(tmp &
+                                         (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) {
+                                       ret = tmp;
                                        anon = 1; /* no anon but release vmf.page */
                                        goto out_unlocked;
                                }
index 1abb9185a686d2787125c7af61120b68e726ccb5..4a3841186c11100f05e01f498c13794621b1edff 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2481,7 +2481,4 @@ void mm_drop_all_locks(struct mm_struct *mm)
  */
 void __init mmap_init(void)
 {
-       vm_area_cachep = kmem_cache_create("vm_area_struct",
-                       sizeof(struct vm_area_struct), 0,
-                       SLAB_PANIC, NULL);
 }
index 2fcf47d449b4e203d46bbbf76827aeedbd2e2c22..72eda4aee2cb46d72e070271d82ae13daef78b36 100644 (file)
@@ -69,7 +69,7 @@ int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT;
 int sysctl_nr_trim_pages = 1; /* page trimming behaviour */
 int heap_stack_gap = 0;
 
-atomic_t mmap_pages_allocated;
+atomic_long_t mmap_pages_allocated;
 
 EXPORT_SYMBOL(mem_map);
 EXPORT_SYMBOL(num_physpages);
@@ -463,12 +463,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk)
  */
 void __init mmap_init(void)
 {
-       vm_region_jar = kmem_cache_create("vm_region_jar",
-                                         sizeof(struct vm_region), 0,
-                                         SLAB_PANIC, NULL);
-       vm_area_cachep = kmem_cache_create("vm_area_struct",
-                                          sizeof(struct vm_area_struct), 0,
-                                          SLAB_PANIC, NULL);
+       vm_region_jar = KMEM_CACHE(vm_region, SLAB_PANIC);
 }
 
 /*
@@ -486,27 +481,24 @@ static noinline void validate_nommu_regions(void)
                return;
 
        last = rb_entry(lastp, struct vm_region, vm_rb);
-       if (unlikely(last->vm_end <= last->vm_start))
-               BUG();
-       if (unlikely(last->vm_top < last->vm_end))
-               BUG();
+       BUG_ON(unlikely(last->vm_end <= last->vm_start));
+       BUG_ON(unlikely(last->vm_top < last->vm_end));
 
        while ((p = rb_next(lastp))) {
                region = rb_entry(p, struct vm_region, vm_rb);
                last = rb_entry(lastp, struct vm_region, vm_rb);
 
-               if (unlikely(region->vm_end <= region->vm_start))
-                       BUG();
-               if (unlikely(region->vm_top < region->vm_end))
-                       BUG();
-               if (unlikely(region->vm_start < last->vm_top))
-                       BUG();
+               BUG_ON(unlikely(region->vm_end <= region->vm_start));
+               BUG_ON(unlikely(region->vm_top < region->vm_end));
+               BUG_ON(unlikely(region->vm_start < last->vm_top));
 
                lastp = p;
        }
 }
 #else
-#define validate_nommu_regions() do {} while(0)
+static void validate_nommu_regions(void)
+{
+}
 #endif
 
 /*
@@ -563,16 +555,17 @@ static void free_page_series(unsigned long from, unsigned long to)
                struct page *page = virt_to_page(from);
 
                kdebug("- free %lx", from);
-               atomic_dec(&mmap_pages_allocated);
+               atomic_long_dec(&mmap_pages_allocated);
                if (page_count(page) != 1)
-                       kdebug("free page %p [%d]", page, page_count(page));
+                       kdebug("free page %p: refcount not one: %d",
+                              page, page_count(page));
                put_page(page);
        }
 }
 
 /*
  * release a reference to a region
- * - the caller must hold the region semaphore, which this releases
+ * - the caller must hold the region semaphore for writing, which this releases
  * - the region may not have been added to the tree yet, in which case vm_top
  *   will equal vm_start
  */
@@ -1096,7 +1089,7 @@ static int do_mmap_private(struct vm_area_struct *vma,
                goto enomem;
 
        total = 1 << order;
-       atomic_add(total, &mmap_pages_allocated);
+       atomic_long_add(total, &mmap_pages_allocated);
 
        point = rlen >> PAGE_SHIFT;
 
@@ -1107,7 +1100,7 @@ static int do_mmap_private(struct vm_area_struct *vma,
                        order = ilog2(total - point);
                        n = 1 << order;
                        kdebug("shave %lu/%lu @%lu", n, total - point, total);
-                       atomic_sub(n, &mmap_pages_allocated);
+                       atomic_long_sub(n, &mmap_pages_allocated);
                        total -= n;
                        set_page_refcounted(pages + total);
                        __free_pages(pages + total, order);
@@ -1536,10 +1529,15 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
        /* find the first potentially overlapping VMA */
        vma = find_vma(mm, start);
        if (!vma) {
-               printk(KERN_WARNING
-                      "munmap of memory not mmapped by process %d (%s):"
-                      " 0x%lx-0x%lx\n",
-                      current->pid, current->comm, start, start + len - 1);
+               static int limit = 0;
+               if (limit < 5) {
+                       printk(KERN_WARNING
+                              "munmap of memory not mmapped by process %d"
+                              " (%s): 0x%lx-0x%lx\n",
+                              current->pid, current->comm,
+                              start, start + len - 1);
+                       limit++;
+               }
                return -EINVAL;
        }
 
index 40ba05061a4fbc8a43d3eb046a58fe756748cd06..2f3166e308d9713378d6a37b6a54e6272abf0f1f 100644 (file)
@@ -55,7 +55,7 @@ static DEFINE_SPINLOCK(zone_scan_lock);
 
 unsigned long badness(struct task_struct *p, unsigned long uptime)
 {
-       unsigned long points, cpu_time, run_time, s;
+       unsigned long points, cpu_time, run_time;
        struct mm_struct *mm;
        struct task_struct *child;
 
@@ -110,12 +110,10 @@ unsigned long badness(struct task_struct *p, unsigned long uptime)
        else
                run_time = 0;
 
-       s = int_sqrt(cpu_time);
-       if (s)
-               points /= s;
-       s = int_sqrt(int_sqrt(run_time));
-       if (s)
-               points /= s;
+       if (cpu_time)
+               points /= int_sqrt(cpu_time);
+       if (run_time)
+               points /= int_sqrt(int_sqrt(run_time));
 
        /*
         * Niced processes are most likely less important, so double
@@ -396,6 +394,7 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
                cpuset_print_task_mems_allowed(current);
                task_unlock(current);
                dump_stack();
+               mem_cgroup_print_oom_info(mem, current);
                show_mem();
                if (sysctl_oom_dump_tasks)
                        dump_tasks(mem);
index 40ca7cdb653ec280d8115ff3d8b35cb6ee57669e..30351f0063acb125f4581f0a1c6197662254d8ab 100644 (file)
@@ -92,14 +92,14 @@ int vm_dirty_ratio = 20;
 unsigned long vm_dirty_bytes;
 
 /*
- * The interval between `kupdate'-style writebacks, in jiffies
+ * The interval between `kupdate'-style writebacks
  */
-int dirty_writeback_interval = 5 * HZ;
+unsigned int dirty_writeback_interval = 5 * 100; /* sentiseconds */
 
 /*
- * The longest number of jiffies for which data is allowed to remain dirty
+ * The longest time for which data is allowed to remain dirty
  */
-int dirty_expire_interval = 30 * HZ;
+unsigned int dirty_expire_interval = 30 * 100; /* sentiseconds */
 
 /*
  * Flag that makes the machine dump writes/reads and block dirtyings.
@@ -770,9 +770,9 @@ static void wb_kupdate(unsigned long arg)
 
        sync_supers();
 
-       oldest_jif = jiffies - dirty_expire_interval;
+       oldest_jif = jiffies - msecs_to_jiffies(dirty_expire_interval);
        start_jif = jiffies;
-       next_jif = start_jif + dirty_writeback_interval;
+       next_jif = start_jif + msecs_to_jiffies(dirty_writeback_interval * 10);
        nr_to_write = global_page_state(NR_FILE_DIRTY) +
                        global_page_state(NR_UNSTABLE_NFS) +
                        (inodes_stat.nr_inodes - inodes_stat.nr_unused);
@@ -801,9 +801,10 @@ static void wb_kupdate(unsigned long arg)
 int dirty_writeback_centisecs_handler(ctl_table *table, int write,
        struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
 {
-       proc_dointvec_userhz_jiffies(table, write, file, buffer, length, ppos);
+       proc_dointvec(table, write, file, buffer, length, ppos);
        if (dirty_writeback_interval)
-               mod_timer(&wb_timer, jiffies + dirty_writeback_interval);
+               mod_timer(&wb_timer, jiffies +
+                       msecs_to_jiffies(dirty_writeback_interval * 10));
        else
                del_timer(&wb_timer);
        return 0;
@@ -905,7 +906,8 @@ void __init page_writeback_init(void)
 {
        int shift;
 
-       mod_timer(&wb_timer, jiffies + dirty_writeback_interval);
+       mod_timer(&wb_timer,
+                 jiffies + msecs_to_jiffies(dirty_writeback_interval * 10));
        writeback_set_ratelimit();
        register_cpu_notifier(&ratelimit_nb);
 
@@ -1197,6 +1199,20 @@ int __set_page_dirty_no_writeback(struct page *page)
        return 0;
 }
 
+/*
+ * Helper function for set_page_dirty family.
+ * NOTE: This relies on being atomic wrt interrupts.
+ */
+void account_page_dirtied(struct page *page, struct address_space *mapping)
+{
+       if (mapping_cap_account_dirty(mapping)) {
+               __inc_zone_page_state(page, NR_FILE_DIRTY);
+               __inc_bdi_stat(mapping->backing_dev_info, BDI_RECLAIMABLE);
+               task_dirty_inc(current);
+               task_io_account_write(PAGE_CACHE_SIZE);
+       }
+}
+
 /*
  * For address_spaces which do not use buffers.  Just tag the page as dirty in
  * its radix tree.
@@ -1226,13 +1242,7 @@ int __set_page_dirty_nobuffers(struct page *page)
                if (mapping2) { /* Race with truncate? */
                        BUG_ON(mapping2 != mapping);
                        WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page));
-                       if (mapping_cap_account_dirty(mapping)) {
-                               __inc_zone_page_state(page, NR_FILE_DIRTY);
-                               __inc_bdi_stat(mapping->backing_dev_info,
-                                               BDI_RECLAIMABLE);
-                               task_dirty_inc(current);
-                               task_io_account_write(PAGE_CACHE_SIZE);
-                       }
+                       account_page_dirtied(page, mapping);
                        radix_tree_tag_set(&mapping->page_tree,
                                page_index(page), PAGECACHE_TAG_DIRTY);
                }
index 5c44ed49ca93c5a1d7a39f5570b0d1254a45de80..0284e528748d5b99528e6cd0d3611c52c08fe335 100644 (file)
@@ -922,13 +922,10 @@ static void drain_pages(unsigned int cpu)
        unsigned long flags;
        struct zone *zone;
 
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                struct per_cpu_pageset *pset;
                struct per_cpu_pages *pcp;
 
-               if (!populated_zone(zone))
-                       continue;
-
                pset = zone_pcp(zone, cpu);
 
                pcp = &pset->pcp;
@@ -1479,6 +1476,8 @@ __alloc_pages_internal(gfp_t gfp_mask, unsigned int order,
        unsigned long did_some_progress;
        unsigned long pages_reclaimed = 0;
 
+       lockdep_trace_alloc(gfp_mask);
+
        might_sleep_if(wait);
 
        if (should_fail_alloc_page(gfp_mask, order))
@@ -1578,12 +1577,16 @@ nofail_alloc:
         */
        cpuset_update_task_memory_state();
        p->flags |= PF_MEMALLOC;
+
+       lockdep_set_current_reclaim_state(gfp_mask);
        reclaim_state.reclaimed_slab = 0;
        p->reclaim_state = &reclaim_state;
 
-       did_some_progress = try_to_free_pages(zonelist, order, gfp_mask);
+       did_some_progress = try_to_free_pages(zonelist, order,
+                                               gfp_mask, nodemask);
 
        p->reclaim_state = NULL;
+       lockdep_clear_current_reclaim_state();
        p->flags &= ~PF_MEMALLOC;
 
        cond_resched();
@@ -1874,10 +1877,7 @@ void show_free_areas(void)
        int cpu;
        struct zone *zone;
 
-       for_each_zone(zone) {
-               if (!populated_zone(zone))
-                       continue;
-
+       for_each_populated_zone(zone) {
                show_node(zone);
                printk("%s per-cpu:\n", zone->name);
 
@@ -1917,12 +1917,9 @@ void show_free_areas(void)
                global_page_state(NR_PAGETABLE),
                global_page_state(NR_BOUNCE));
 
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                int i;
 
-               if (!populated_zone(zone))
-                       continue;
-
                show_node(zone);
                printk("%s"
                        " free:%lukB"
@@ -1962,12 +1959,9 @@ void show_free_areas(void)
                printk("\n");
        }
 
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                unsigned long nr[MAX_ORDER], flags, order, total = 0;
 
-               if (!populated_zone(zone))
-                       continue;
-
                show_node(zone);
                printk("%s: ", zone->name);
 
@@ -2779,11 +2773,7 @@ static int __cpuinit process_zones(int cpu)
 
        node_set_state(node, N_CPU);    /* this node has a cpu */
 
-       for_each_zone(zone) {
-
-               if (!populated_zone(zone))
-                       continue;
-
+       for_each_populated_zone(zone) {
                zone_pcp(zone, cpu) = kmalloc_node(sizeof(struct per_cpu_pageset),
                                         GFP_KERNEL, node);
                if (!zone_pcp(zone, cpu))
index ceecfbb143fa9d7b2a3f9ffb4ca9980da6bc0b53..791905c991df9d94497c36cd23cb3fead537f4d9 100644 (file)
@@ -285,12 +285,8 @@ struct swap_cgroup_ctrl {
 
 struct swap_cgroup_ctrl swap_cgroup_ctrl[MAX_SWAPFILES];
 
-/*
- * This 8bytes seems big..maybe we can reduce this when we can use "id" for
- * cgroup rather than pointer.
- */
 struct swap_cgroup {
-       struct mem_cgroup       *val;
+       unsigned short          id;
 };
 #define SC_PER_PAGE    (PAGE_SIZE/sizeof(struct swap_cgroup))
 #define SC_POS_MASK    (SC_PER_PAGE - 1)
@@ -342,10 +338,10 @@ not_enough_page:
  * @ent: swap entry to be recorded into
  * @mem: mem_cgroup to be recorded
  *
- * Returns old value at success, NULL at failure.
- * (Of course, old value can be NULL.)
+ * Returns old value at success, 0 at failure.
+ * (Of course, old value can be 0.)
  */
-struct mem_cgroup *swap_cgroup_record(swp_entry_t ent, struct mem_cgroup *mem)
+unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
 {
        int type = swp_type(ent);
        unsigned long offset = swp_offset(ent);
@@ -354,18 +350,18 @@ struct mem_cgroup *swap_cgroup_record(swp_entry_t ent, struct mem_cgroup *mem)
        struct swap_cgroup_ctrl *ctrl;
        struct page *mappage;
        struct swap_cgroup *sc;
-       struct mem_cgroup *old;
+       unsigned short old;
 
        if (!do_swap_account)
-               return NULL;
+               return 0;
 
        ctrl = &swap_cgroup_ctrl[type];
 
        mappage = ctrl->map[idx];
        sc = page_address(mappage);
        sc += pos;
-       old = sc->val;
-       sc->val = mem;
+       old = sc->id;
+       sc->id = id;
 
        return old;
 }
@@ -374,9 +370,9 @@ struct mem_cgroup *swap_cgroup_record(swp_entry_t ent, struct mem_cgroup *mem)
  * lookup_swap_cgroup - lookup mem_cgroup tied to swap entry
  * @ent: swap entry to be looked up.
  *
- * Returns pointer to mem_cgroup at success. NULL at failure.
+ * Returns CSS ID of mem_cgroup at success. 0 at failure. (0 is invalid ID)
  */
-struct mem_cgroup *lookup_swap_cgroup(swp_entry_t ent)
+unsigned short lookup_swap_cgroup(swp_entry_t ent)
 {
        int type = swp_type(ent);
        unsigned long offset = swp_offset(ent);
@@ -385,16 +381,16 @@ struct mem_cgroup *lookup_swap_cgroup(swp_entry_t ent)
        struct swap_cgroup_ctrl *ctrl;
        struct page *mappage;
        struct swap_cgroup *sc;
-       struct mem_cgroup *ret;
+       unsigned short ret;
 
        if (!do_swap_account)
-               return NULL;
+               return 0;
 
        ctrl = &swap_cgroup_ctrl[type];
        mappage = ctrl->map[idx];
        sc = page_address(mappage);
        sc += pos;
-       ret = sc->val;
+       ret = sc->id;
        return ret;
 }
 
@@ -430,13 +426,6 @@ int swap_cgroup_swapon(int type, unsigned long max_pages)
        }
        mutex_unlock(&swap_cgroup_mutex);
 
-       printk(KERN_INFO
-               "swap_cgroup: uses %ld bytes of vmalloc for pointer array space"
-               " and %ld bytes to hold mem_cgroup pointers on swap\n",
-               array_size, length * PAGE_SIZE);
-       printk(KERN_INFO
-       "swap_cgroup can be disabled by noswapaccount boot option.\n");
-
        return 0;
 nomem:
        printk(KERN_INFO "couldn't allocate enough memory for swap_cgroup.\n");
index 15de509b68fd657c7b9ecb0356cdadf9bc43b1ef..118905e3d7886f795875b376c70d23e4bfc4c038 100644 (file)
@@ -191,7 +191,7 @@ static int pdflush(void *dummy)
 
        /*
         * Some configs put our parent kthread in a limited cpuset,
-        * which kthread() overrides, forcing cpus_allowed == CPU_MASK_ALL.
+        * which kthread() overrides, forcing cpus_allowed == cpu_all_mask.
         * Our needs are more modest - cut back to our cpusets cpus_allowed.
         * This is needed as pdflush's are dynamically created and destroyed.
         * The boottime pdflush's are easily placed w/o these 2 lines.
index 7ec78e24a30dcc549670b88643078509bbd12e4d..d94d2e9146bc4dfa5d946449274be75419f0b8da 100644 (file)
@@ -1068,8 +1068,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
                swap_duplicate(swap);
                BUG_ON(page_mapped(page));
                page_cache_release(page);       /* pagecache ref */
-               set_page_dirty(page);
-               unlock_page(page);
+               swap_writepage(page, wbc);
                if (inode) {
                        mutex_lock(&shmem_swaplist_mutex);
                        /* move instead of add in case we're racing */
index 4d00855629c4921e3c590406335549683e6c6daf..208323fd37bc3b7efcdca7dbbd1f9d68ab901025 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3318,6 +3318,8 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
        unsigned long save_flags;
        void *ptr;
 
+       lockdep_trace_alloc(flags);
+
        if (slab_should_failslab(cachep, flags))
                return NULL;
 
@@ -3394,6 +3396,8 @@ __cache_alloc(struct kmem_cache *cachep, gfp_t flags, void *caller)
        unsigned long save_flags;
        void *objp;
 
+       lockdep_trace_alloc(flags);
+
        if (slab_should_failslab(cachep, flags))
                return NULL;
 
@@ -3988,8 +3992,7 @@ static void cache_reap(struct work_struct *w)
        struct kmem_cache *searchp;
        struct kmem_list3 *l3;
        int node = numa_node_id();
-       struct delayed_work *work =
-               container_of(w, struct delayed_work, work);
+       struct delayed_work *work = to_delayed_work(w);
 
        if (!mutex_trylock(&cache_chain_mutex))
                /* Give up. Setup the next iteration. */
index 0bfa680a8981127307d1d922231dca3d66f9b2bd..7a3411524dacd555e9ce70e287a4232072391e10 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -475,6 +475,8 @@ void *__kmalloc_node(size_t size, gfp_t gfp, int node)
        unsigned int *m;
        int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
 
+       lockdep_trace_alloc(gfp);
+
        if (size < PAGE_SIZE - align) {
                if (!size)
                        return ZERO_SIZE_PTR;
index c65a4edafc3343e83a2513f8edab9b0ed82f3ab5..c4ea9158c9fbd0e4630062aa0098406000be45c3 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1590,6 +1590,7 @@ static __always_inline void *slab_alloc(struct kmem_cache *s,
        unsigned long flags;
        unsigned int objsize;
 
+       lockdep_trace_alloc(gfpflags);
        might_sleep_if(gfpflags & __GFP_WAIT);
 
        if (should_failslab(s->objsize, gfpflags))
index 083f5b63e7a8bdb8ab5196e11970691c2bd351d4..da432d9f0ae825eb4e050ed8168c1600c6a793da 100644 (file)
@@ -164,9 +164,7 @@ void __meminit mminit_validate_memmodel_limits(unsigned long *start_pfn,
                WARN_ON_ONCE(1);
                *start_pfn = max_sparsemem_pfn;
                *end_pfn = max_sparsemem_pfn;
-       }
-
-       if (*end_pfn > max_sparsemem_pfn) {
+       } else if (*end_pfn > max_sparsemem_pfn) {
                mminit_dprintk(MMINIT_WARNING, "pfnvalidation",
                        "End of range %lu -> %lu exceeds SPARSEMEM max %lu\n",
                        *start_pfn, *end_pfn, max_sparsemem_pfn);
index 8adb9feb61e10b7385e01d3410d8cb0f0a4807e1..6e83084c1f6c3bf2c1a9fa36fb5649ea181e363c 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -456,29 +456,6 @@ void pagevec_strip(struct pagevec *pvec)
        }
 }
 
-/**
- * pagevec_swap_free - try to free swap space from the pages in a pagevec
- * @pvec: pagevec with swapcache pages to free the swap space of
- *
- * The caller needs to hold an extra reference to each page and
- * not hold the page lock on the pages.  This function uses a
- * trylock on the page lock so it may not always free the swap
- * space associated with a page.
- */
-void pagevec_swap_free(struct pagevec *pvec)
-{
-       int i;
-
-       for (i = 0; i < pagevec_count(pvec); i++) {
-               struct page *page = pvec->pages[i];
-
-               if (PageSwapCache(page) && trylock_page(page)) {
-                       try_to_free_swap(page);
-                       unlock_page(page);
-               }
-       }
-}
-
 /**
  * pagevec_lookup - gang pagecache lookup
  * @pvec:      Where the resulting pages are placed
index 37eaccdf3054e13d60cd83cf5c6cb9869731aec1..7c122e49f769ccea98ae105746e0238acc1652ce 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -69,6 +69,36 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp)
 }
 EXPORT_SYMBOL(kmemdup);
 
+/**
+ * memdup_user - duplicate memory region from user space
+ *
+ * @src: source address in user space
+ * @len: number of bytes to copy
+ *
+ * Returns an ERR_PTR() on failure.
+ */
+void *memdup_user(const void __user *src, size_t len)
+{
+       void *p;
+
+       /*
+        * Always use GFP_KERNEL, since copy_from_user() can sleep and
+        * cause pagefault, which makes it pointless to use GFP_NOFS
+        * or GFP_ATOMIC.
+        */
+       p = kmalloc_track_caller(len, GFP_KERNEL);
+       if (!p)
+               return ERR_PTR(-ENOMEM);
+
+       if (copy_from_user(p, src, len)) {
+               kfree(p);
+               return ERR_PTR(-EFAULT);
+       }
+
+       return p;
+}
+EXPORT_SYMBOL(memdup_user);
+
 /**
  * __krealloc - like krealloc() but don't free @p.
  * @p: object to reallocate memory for.
index af58324c361addc715ee2eb9b839bada21cb2773..fab19876b4d178986979c2b5d2cb353285507b46 100644 (file)
@@ -671,10 +671,7 @@ struct vmap_block {
        DECLARE_BITMAP(alloc_map, VMAP_BBMAP_BITS);
        DECLARE_BITMAP(dirty_map, VMAP_BBMAP_BITS);
        union {
-               struct {
-                       struct list_head free_list;
-                       struct list_head dirty_list;
-               };
+               struct list_head free_list;
                struct rcu_head rcu_head;
        };
 };
@@ -741,7 +738,6 @@ static struct vmap_block *new_vmap_block(gfp_t gfp_mask)
        bitmap_zero(vb->alloc_map, VMAP_BBMAP_BITS);
        bitmap_zero(vb->dirty_map, VMAP_BBMAP_BITS);
        INIT_LIST_HEAD(&vb->free_list);
-       INIT_LIST_HEAD(&vb->dirty_list);
 
        vb_idx = addr_to_vb_idx(va->va_start);
        spin_lock(&vmap_block_tree_lock);
@@ -772,12 +768,7 @@ static void free_vmap_block(struct vmap_block *vb)
        struct vmap_block *tmp;
        unsigned long vb_idx;
 
-       spin_lock(&vb->vbq->lock);
-       if (!list_empty(&vb->free_list))
-               list_del(&vb->free_list);
-       if (!list_empty(&vb->dirty_list))
-               list_del(&vb->dirty_list);
-       spin_unlock(&vb->vbq->lock);
+       BUG_ON(!list_empty(&vb->free_list));
 
        vb_idx = addr_to_vb_idx(vb->va->va_start);
        spin_lock(&vmap_block_tree_lock);
@@ -862,11 +853,7 @@ static void vb_free(const void *addr, unsigned long size)
 
        spin_lock(&vb->lock);
        bitmap_allocate_region(vb->dirty_map, offset >> PAGE_SHIFT, order);
-       if (!vb->dirty) {
-               spin_lock(&vb->vbq->lock);
-               list_add(&vb->dirty_list, &vb->vbq->dirty);
-               spin_unlock(&vb->vbq->lock);
-       }
+
        vb->dirty += 1UL << order;
        if (vb->dirty == VMAP_BBMAP_BITS) {
                BUG_ON(vb->free || !list_empty(&vb->free_list));
index 56ddf41149eb77a55158ced628c02f817b990618..06e72693b4587a6181b002dec4f14ac5a7d4ba06 100644 (file)
@@ -60,8 +60,8 @@ struct scan_control {
 
        int may_writepage;
 
-       /* Can pages be swapped as part of reclaim? */
-       int may_swap;
+       /* Can mapped pages be reclaimed? */
+       int may_unmap;
 
        /* This context's SWAP_CLUSTER_MAX. If freeing memory for
         * suspend, we effectively ignore SWAP_CLUSTER_MAX.
@@ -78,6 +78,12 @@ struct scan_control {
        /* Which cgroup do we reclaim from */
        struct mem_cgroup *mem_cgroup;
 
+       /*
+        * Nodemask of nodes allowed by the caller. If NULL, all nodes
+        * are scanned.
+        */
+       nodemask_t      *nodemask;
+
        /* Pluggable isolate pages callback */
        unsigned long (*isolate_pages)(unsigned long nr, struct list_head *dst,
                        unsigned long *scanned, int order, int mode,
@@ -214,8 +220,9 @@ unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
                do_div(delta, lru_pages + 1);
                shrinker->nr += delta;
                if (shrinker->nr < 0) {
-                       printk(KERN_ERR "%s: nr=%ld\n",
-                                       __func__, shrinker->nr);
+                       printk(KERN_ERR "shrink_slab: %pF negative objects to "
+                              "delete nr=%ld\n",
+                              shrinker->shrink, shrinker->nr);
                        shrinker->nr = max_pass;
                }
 
@@ -606,7 +613,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                if (unlikely(!page_evictable(page, NULL)))
                        goto cull_mlocked;
 
-               if (!sc->may_swap && page_mapped(page))
+               if (!sc->may_unmap && page_mapped(page))
                        goto keep_locked;
 
                /* Double the slab pressure for mapped and swapcache pages */
@@ -1298,17 +1305,11 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
        }
        __mod_zone_page_state(zone, NR_LRU_BASE + lru, pgmoved);
        pgdeactivate += pgmoved;
-       if (buffer_heads_over_limit) {
-               spin_unlock_irq(&zone->lru_lock);
-               pagevec_strip(&pvec);
-               spin_lock_irq(&zone->lru_lock);
-       }
        __count_zone_vm_events(PGREFILL, zone, pgscanned);
        __count_vm_events(PGDEACTIVATE, pgdeactivate);
        spin_unlock_irq(&zone->lru_lock);
-       if (vm_swap_full())
-               pagevec_swap_free(&pvec);
-
+       if (buffer_heads_over_limit)
+               pagevec_strip(&pvec);
        pagevec_release(&pvec);
 }
 
@@ -1543,7 +1544,8 @@ static void shrink_zones(int priority, struct zonelist *zonelist,
        struct zone *zone;
 
        sc->all_unreclaimable = 1;
-       for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
+       for_each_zone_zonelist_nodemask(zone, z, zonelist, high_zoneidx,
+                                       sc->nodemask) {
                if (!populated_zone(zone))
                        continue;
                /*
@@ -1688,17 +1690,18 @@ out:
 }
 
 unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
-                                                               gfp_t gfp_mask)
+                               gfp_t gfp_mask, nodemask_t *nodemask)
 {
        struct scan_control sc = {
                .gfp_mask = gfp_mask,
                .may_writepage = !laptop_mode,
                .swap_cluster_max = SWAP_CLUSTER_MAX,
-               .may_swap = 1,
+               .may_unmap = 1,
                .swappiness = vm_swappiness,
                .order = order,
                .mem_cgroup = NULL,
                .isolate_pages = isolate_pages_global,
+               .nodemask = nodemask,
        };
 
        return do_try_to_free_pages(zonelist, &sc);
@@ -1713,17 +1716,18 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
 {
        struct scan_control sc = {
                .may_writepage = !laptop_mode,
-               .may_swap = 1,
+               .may_unmap = 1,
                .swap_cluster_max = SWAP_CLUSTER_MAX,
                .swappiness = swappiness,
                .order = 0,
                .mem_cgroup = mem_cont,
                .isolate_pages = mem_cgroup_isolate_pages,
+               .nodemask = NULL, /* we don't care the placement */
        };
        struct zonelist *zonelist;
 
        if (noswap)
-               sc.may_swap = 0;
+               sc.may_unmap = 0;
 
        sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
                        (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK);
@@ -1762,7 +1766,7 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order)
        struct reclaim_state *reclaim_state = current->reclaim_state;
        struct scan_control sc = {
                .gfp_mask = GFP_KERNEL,
-               .may_swap = 1,
+               .may_unmap = 1,
                .swap_cluster_max = SWAP_CLUSTER_MAX,
                .swappiness = vm_swappiness,
                .order = order,
@@ -1965,6 +1969,8 @@ static int kswapd(void *p)
        };
        node_to_cpumask_ptr(cpumask, pgdat->node_id);
 
+       lockdep_set_current_reclaim_state(GFP_KERNEL);
+
        if (!cpumask_empty(cpumask))
                set_cpus_allowed_ptr(tsk, cpumask);
        current->reclaim_state = &reclaim_state;
@@ -2048,22 +2054,19 @@ unsigned long global_lru_pages(void)
 #ifdef CONFIG_PM
 /*
  * Helper function for shrink_all_memory().  Tries to reclaim 'nr_pages' pages
- * from LRU lists system-wide, for given pass and priority, and returns the
- * number of reclaimed pages
+ * from LRU lists system-wide, for given pass and priority.
  *
  * For pass > 3 we also try to shrink the LRU lists that contain a few pages
  */
-static unsigned long shrink_all_zones(unsigned long nr_pages, int prio,
+static void shrink_all_zones(unsigned long nr_pages, int prio,
                                      int pass, struct scan_control *sc)
 {
        struct zone *zone;
-       unsigned long ret = 0;
+       unsigned long nr_reclaimed = 0;
 
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                enum lru_list l;
 
-               if (!populated_zone(zone))
-                       continue;
                if (zone_is_all_unreclaimable(zone) && prio != DEF_PRIORITY)
                        continue;
 
@@ -2082,14 +2085,16 @@ static unsigned long shrink_all_zones(unsigned long nr_pages, int prio,
 
                                zone->lru[l].nr_scan = 0;
                                nr_to_scan = min(nr_pages, lru_pages);
-                               ret += shrink_list(l, nr_to_scan, zone,
+                               nr_reclaimed += shrink_list(l, nr_to_scan, zone,
                                                                sc, prio);
-                               if (ret >= nr_pages)
-                                       return ret;
+                               if (nr_reclaimed >= nr_pages) {
+                                       sc->nr_reclaimed = nr_reclaimed;
+                                       return;
+                               }
                        }
                }
        }
-       return ret;
+       sc->nr_reclaimed = nr_reclaimed;
 }
 
 /*
@@ -2103,13 +2108,11 @@ static unsigned long shrink_all_zones(unsigned long nr_pages, int prio,
 unsigned long shrink_all_memory(unsigned long nr_pages)
 {
        unsigned long lru_pages, nr_slab;
-       unsigned long ret = 0;
        int pass;
        struct reclaim_state reclaim_state;
        struct scan_control sc = {
                .gfp_mask = GFP_KERNEL,
-               .may_swap = 0,
-               .swap_cluster_max = nr_pages,
+               .may_unmap = 0,
                .may_writepage = 1,
                .isolate_pages = isolate_pages_global,
        };
@@ -2125,8 +2128,8 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
                if (!reclaim_state.reclaimed_slab)
                        break;
 
-               ret += reclaim_state.reclaimed_slab;
-               if (ret >= nr_pages)
+               sc.nr_reclaimed += reclaim_state.reclaimed_slab;
+               if (sc.nr_reclaimed >= nr_pages)
                        goto out;
 
                nr_slab -= reclaim_state.reclaimed_slab;
@@ -2145,21 +2148,22 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
 
                /* Force reclaiming mapped pages in the passes #3 and #4 */
                if (pass > 2)
-                       sc.may_swap = 1;
+                       sc.may_unmap = 1;
 
                for (prio = DEF_PRIORITY; prio >= 0; prio--) {
-                       unsigned long nr_to_scan = nr_pages - ret;
+                       unsigned long nr_to_scan = nr_pages - sc.nr_reclaimed;
 
                        sc.nr_scanned = 0;
-                       ret += shrink_all_zones(nr_to_scan, prio, pass, &sc);
-                       if (ret >= nr_pages)
+                       sc.swap_cluster_max = nr_to_scan;
+                       shrink_all_zones(nr_to_scan, prio, pass, &sc);
+                       if (sc.nr_reclaimed >= nr_pages)
                                goto out;
 
                        reclaim_state.reclaimed_slab = 0;
                        shrink_slab(sc.nr_scanned, sc.gfp_mask,
                                        global_lru_pages());
-                       ret += reclaim_state.reclaimed_slab;
-                       if (ret >= nr_pages)
+                       sc.nr_reclaimed += reclaim_state.reclaimed_slab;
+                       if (sc.nr_reclaimed >= nr_pages)
                                goto out;
 
                        if (sc.nr_scanned && prio < DEF_PRIORITY - 2)
@@ -2168,21 +2172,23 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
        }
 
        /*
-        * If ret = 0, we could not shrink LRUs, but there may be something
-        * in slab caches
+        * If sc.nr_reclaimed = 0, we could not shrink LRUs, but there may be
+        * something in slab caches
         */
-       if (!ret) {
+       if (!sc.nr_reclaimed) {
                do {
                        reclaim_state.reclaimed_slab = 0;
                        shrink_slab(nr_pages, sc.gfp_mask, global_lru_pages());
-                       ret += reclaim_state.reclaimed_slab;
-               } while (ret < nr_pages && reclaim_state.reclaimed_slab > 0);
+                       sc.nr_reclaimed += reclaim_state.reclaimed_slab;
+               } while (sc.nr_reclaimed < nr_pages &&
+                               reclaim_state.reclaimed_slab > 0);
        }
 
+
 out:
        current->reclaim_state = NULL;
 
-       return ret;
+       return sc.nr_reclaimed;
 }
 #endif
 
@@ -2288,11 +2294,12 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
        int priority;
        struct scan_control sc = {
                .may_writepage = !!(zone_reclaim_mode & RECLAIM_WRITE),
-               .may_swap = !!(zone_reclaim_mode & RECLAIM_SWAP),
+               .may_unmap = !!(zone_reclaim_mode & RECLAIM_SWAP),
                .swap_cluster_max = max_t(unsigned long, nr_pages,
                                        SWAP_CLUSTER_MAX),
                .gfp_mask = gfp_mask,
                .swappiness = vm_swappiness,
+               .order = order,
                .isolate_pages = isolate_pages_global,
        };
        unsigned long slab_reclaimable;
index 91149746bb8d6c94ac036879bbe557551630a1e1..66f6130976cb65c569f41108507479a68ec0779c 100644 (file)
@@ -27,7 +27,7 @@ static void sum_vm_events(unsigned long *ret, const struct cpumask *cpumask)
 
        memset(ret, 0, NR_VM_EVENT_ITEMS * sizeof(unsigned long));
 
-       for_each_cpu_mask_nr(cpu, *cpumask) {
+       for_each_cpu(cpu, cpumask) {
                struct vm_event_state *this = &per_cpu(vm_event_states, cpu);
 
                for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
@@ -135,11 +135,7 @@ static void refresh_zone_stat_thresholds(void)
        int cpu;
        int threshold;
 
-       for_each_zone(zone) {
-
-               if (!zone->present_pages)
-                       continue;
-
+       for_each_populated_zone(zone) {
                threshold = calculate_threshold(zone);
 
                for_each_online_cpu(cpu)
@@ -301,12 +297,9 @@ void refresh_cpu_vm_stats(int cpu)
        int i;
        int global_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
 
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                struct per_cpu_pageset *p;
 
-               if (!populated_zone(zone))
-                       continue;
-
                p = zone_pcp(zone, cpu);
 
                for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
@@ -898,7 +891,7 @@ static void vmstat_update(struct work_struct *w)
 {
        refresh_cpu_vm_stats(smp_processor_id());
        schedule_delayed_work(&__get_cpu_var(vmstat_work),
-               sysctl_stat_interval);
+               round_jiffies_relative(sysctl_stat_interval));
 }
 
 static void __cpuinit start_cpu_timer(int cpu)
@@ -906,7 +899,8 @@ static void __cpuinit start_cpu_timer(int cpu)
        struct delayed_work *vmstat_work = &per_cpu(vmstat_work, cpu);
 
        INIT_DELAYED_WORK_DEFERRABLE(vmstat_work, vmstat_update);
-       schedule_delayed_work_on(cpu, vmstat_work, HZ + cpu);
+       schedule_delayed_work_on(cpu, vmstat_work,
+                                __round_jiffies_relative(HZ, cpu));
 }
 
 /*
index 162199a2d74f18e6b41ee7322c2ed8d66dfc4539..fd8e0847b25473ac9318aa22769af66500dbb073 100644 (file)
@@ -281,7 +281,6 @@ int __init atalk_proc_init(void)
        atalk_proc_dir = proc_mkdir("atalk", init_net.proc_net);
        if (!atalk_proc_dir)
                goto out;
-       atalk_proc_dir->owner = THIS_MODULE;
 
        p = proc_create("interface", S_IRUGO, atalk_proc_dir,
                        &atalk_seq_interface_fops);
index 4990541ef5da4ca7d0b2325bd39ebb4ffbf3c290..1a0f5ccea9c4494cad2c29755863f7dd0559e540 100644 (file)
@@ -281,7 +281,6 @@ int mpc_proc_init(void)
                printk(KERN_ERR "Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME);
                return -ENOMEM;
        }
-       p->owner = THIS_MODULE;
        return 0;
 }
 
index 49487b313f221cf6394fa2c918fc67858ae1f45f..e7b3b273907d197b1a64ac8d1cd9c1ce0c3edc16 100644 (file)
@@ -476,7 +476,6 @@ int __init atm_proc_init(void)
                                     atm_proc_root, e->proc_fops);
                if (!dirent)
                        goto err_out_remove;
-               dirent->owner = THIS_MODULE;
                e->dirent = dirent;
        }
        ret = 0;
index abdc703a11d2709ea0305f1cf0b9d9ff0965818a..cab71ea2796d472f740a88277d75805081873748 100644 (file)
@@ -1093,11 +1093,6 @@ static void rfcomm_tty_hangup(struct tty_struct *tty)
        }
 }
 
-static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused)
-{
-       return 0;
-}
-
 static int rfcomm_tty_tiocmget(struct tty_struct *tty, struct file *filp)
 {
        struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
@@ -1156,7 +1151,6 @@ static const struct tty_operations rfcomm_ops = {
        .send_xchar             = rfcomm_tty_send_xchar,
        .hangup                 = rfcomm_tty_hangup,
        .wait_until_sent        = rfcomm_tty_wait_until_sent,
-       .read_proc              = rfcomm_tty_read_proc,
        .tiocmget               = rfcomm_tty_tiocmget,
        .tiocmset               = rfcomm_tty_tiocmset,
 };
index b7c7d46511365ef5ff8c7bc93678a2ef97966c18..95d7f32643aef3a3e0b3830200ea592bb1b54849 100644 (file)
@@ -1604,10 +1604,6 @@ static int __init bcm_module_init(void)
 
        /* create /proc/net/can-bcm directory */
        proc_dir = proc_mkdir("can-bcm", init_net.proc_net);
-
-       if (proc_dir)
-               proc_dir->owner = THIS_MODULE;
-
        return 0;
 }
 
index 520fef5e5398aa867a267ae32bbffbba557795c2..1463653dbe34e986eb5f6283b7823ef109cb0fa8 100644 (file)
@@ -473,8 +473,6 @@ void can_init_proc(void)
                return;
        }
 
-       can_dir->owner = THIS_MODULE;
-
        /* own procfs entries from the AF_CAN core */
        pde_version     = can_create_proc_readentry(CAN_PROC_VERSION, 0644,
                                        can_proc_read_version, NULL);
index 32d419f5ac983e2601cda6ce189476a87886c699..3779c1438c11c84613f5ba9b40619907c9a18a9d 100644 (file)
@@ -3806,7 +3806,6 @@ static int __init pg_init(void)
        pg_proc_dir = proc_mkdir(PG_PROC_DIR, init_net.proc_net);
        if (!pg_proc_dir)
                return -ENODEV;
-       pg_proc_dir->owner = THIS_MODULE;
 
        pe = proc_create(PGCTRL, 0600, pg_proc_dir, &pktgen_fops);
        if (pe == NULL) {
index 0620046e4eba837d0ecdf72b5eb6dcc192060ed5..7dbf3ffb35ccd6cb3308dab70fa33ce9cd9f8d5c 100644 (file)
@@ -1677,7 +1677,7 @@ static void sock_def_error_report(struct sock *sk)
 {
        read_lock(&sk->sk_callback_lock);
        if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-               wake_up_interruptible(sk->sk_sleep);
+               wake_up_interruptible_poll(sk->sk_sleep, POLLERR);
        sk_wake_async(sk, SOCK_WAKE_IO, POLL_ERR);
        read_unlock(&sk->sk_callback_lock);
 }
@@ -1686,7 +1686,8 @@ static void sock_def_readable(struct sock *sk, int len)
 {
        read_lock(&sk->sk_callback_lock);
        if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-               wake_up_interruptible_sync(sk->sk_sleep);
+               wake_up_interruptible_sync_poll(sk->sk_sleep, POLLIN |
+                                               POLLRDNORM | POLLRDBAND);
        sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
        read_unlock(&sk->sk_callback_lock);
 }
@@ -1700,7 +1701,8 @@ static void sock_def_write_space(struct sock *sk)
         */
        if ((atomic_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf) {
                if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-                       wake_up_interruptible_sync(sk->sk_sleep);
+                       wake_up_interruptible_sync_poll(sk->sk_sleep, POLLOUT |
+                                               POLLWRNORM | POLLWRBAND);
 
                /* Should agree with poll, otherwise some programs break */
                if (sock_writeable(sk))
index 7bc992976d29bd18b70dd39544791d66f4351901..039cc1ffe977a5cf1073f88a9826f6798ecd26e4 100644 (file)
@@ -1942,23 +1942,85 @@ socket_setattr_failure:
 }
 
 /**
- * cipso_v4_sock_delattr - Delete the CIPSO option from a socket
- * @sk: the socket
+ * cipso_v4_req_setattr - Add a CIPSO option to a connection request socket
+ * @req: the connection request socket
+ * @doi_def: the CIPSO DOI to use
+ * @secattr: the specific security attributes of the socket
  *
  * Description:
- * Removes the CIPSO option from a socket, if present.
+ * Set the CIPSO option on the given socket using the DOI definition and
+ * security attributes passed to the function.  Returns zero on success and
+ * negative values on failure.
  *
  */
-void cipso_v4_sock_delattr(struct sock *sk)
+int cipso_v4_req_setattr(struct request_sock *req,
+                        const struct cipso_v4_doi *doi_def,
+                        const struct netlbl_lsm_secattr *secattr)
 {
-       u8 hdr_delta;
-       struct ip_options *opt;
-       struct inet_sock *sk_inet;
+       int ret_val = -EPERM;
+       unsigned char *buf = NULL;
+       u32 buf_len;
+       u32 opt_len;
+       struct ip_options *opt = NULL;
+       struct inet_request_sock *req_inet;
 
-       sk_inet = inet_sk(sk);
-       opt = sk_inet->opt;
-       if (opt == NULL || opt->cipso == 0)
-               return;
+       /* We allocate the maximum CIPSO option size here so we are probably
+        * being a little wasteful, but it makes our life _much_ easier later
+        * on and after all we are only talking about 40 bytes. */
+       buf_len = CIPSO_V4_OPT_LEN_MAX;
+       buf = kmalloc(buf_len, GFP_ATOMIC);
+       if (buf == NULL) {
+               ret_val = -ENOMEM;
+               goto req_setattr_failure;
+       }
+
+       ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
+       if (ret_val < 0)
+               goto req_setattr_failure;
+       buf_len = ret_val;
+
+       /* We can't use ip_options_get() directly because it makes a call to
+        * ip_options_get_alloc() which allocates memory with GFP_KERNEL and
+        * we won't always have CAP_NET_RAW even though we _always_ want to
+        * set the IPOPT_CIPSO option. */
+       opt_len = (buf_len + 3) & ~3;
+       opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
+       if (opt == NULL) {
+               ret_val = -ENOMEM;
+               goto req_setattr_failure;
+       }
+       memcpy(opt->__data, buf, buf_len);
+       opt->optlen = opt_len;
+       opt->cipso = sizeof(struct iphdr);
+       kfree(buf);
+       buf = NULL;
+
+       req_inet = inet_rsk(req);
+       opt = xchg(&req_inet->opt, opt);
+       kfree(opt);
+
+       return 0;
+
+req_setattr_failure:
+       kfree(buf);
+       kfree(opt);
+       return ret_val;
+}
+
+/**
+ * cipso_v4_delopt - Delete the CIPSO option from a set of IP options
+ * @opt_ptr: IP option pointer
+ *
+ * Description:
+ * Deletes the CIPSO IP option from a set of IP options and makes the necessary
+ * adjustments to the IP option structure.  Returns zero on success, negative
+ * values on failure.
+ *
+ */
+int cipso_v4_delopt(struct ip_options **opt_ptr)
+{
+       int hdr_delta = 0;
+       struct ip_options *opt = *opt_ptr;
 
        if (opt->srr || opt->rr || opt->ts || opt->router_alert) {
                u8 cipso_len;
@@ -2003,11 +2065,34 @@ void cipso_v4_sock_delattr(struct sock *sk)
        } else {
                /* only the cipso option was present on the socket so we can
                 * remove the entire option struct */
-               sk_inet->opt = NULL;
+               *opt_ptr = NULL;
                hdr_delta = opt->optlen;
                kfree(opt);
        }
 
+       return hdr_delta;
+}
+
+/**
+ * cipso_v4_sock_delattr - Delete the CIPSO option from a socket
+ * @sk: the socket
+ *
+ * Description:
+ * Removes the CIPSO option from a socket, if present.
+ *
+ */
+void cipso_v4_sock_delattr(struct sock *sk)
+{
+       int hdr_delta;
+       struct ip_options *opt;
+       struct inet_sock *sk_inet;
+
+       sk_inet = inet_sk(sk);
+       opt = sk_inet->opt;
+       if (opt == NULL || opt->cipso == 0)
+               return;
+
+       hdr_delta = cipso_v4_delopt(&sk_inet->opt);
        if (sk_inet->is_icsk && hdr_delta > 0) {
                struct inet_connection_sock *sk_conn = inet_csk(sk);
                sk_conn->icsk_ext_hdr_len -= hdr_delta;
@@ -2015,6 +2100,27 @@ void cipso_v4_sock_delattr(struct sock *sk)
        }
 }
 
+/**
+ * cipso_v4_req_delattr - Delete the CIPSO option from a request socket
+ * @reg: the request socket
+ *
+ * Description:
+ * Removes the CIPSO option from a request socket, if present.
+ *
+ */
+void cipso_v4_req_delattr(struct request_sock *req)
+{
+       struct ip_options *opt;
+       struct inet_request_sock *req_inet;
+
+       req_inet = inet_rsk(req);
+       opt = req_inet->opt;
+       if (opt == NULL || opt->cipso == 0)
+               return;
+
+       cipso_v4_delopt(&req_inet->opt);
+}
+
 /**
  * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions
  * @cipso: the CIPSO v4 option
index d346c22aa6ae170a45d540f27cc04c3028f16c6e..b35a950d2e06ee38d89908aae0c725ea29c16aae 100644 (file)
@@ -288,10 +288,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
        if (!req)
                goto out;
 
-       if (security_inet_conn_request(sk, skb, req)) {
-               reqsk_free(req);
-               goto out;
-       }
        ireq = inet_rsk(req);
        treq = tcp_rsk(req);
        treq->rcv_isn           = ntohl(th->seq) - 1;
@@ -322,6 +318,11 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
                }
        }
 
+       if (security_inet_conn_request(sk, skb, req)) {
+               reqsk_free(req);
+               goto out;
+       }
+
        req->expires    = 0UL;
        req->retrans    = 0;
 
index d0a314879d811981dec4d00afde21aa3582a7116..5d427f86b4142115cbc6c02222b8bbd0b34f9506 100644 (file)
@@ -1230,14 +1230,15 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 
        tcp_openreq_init(req, &tmp_opt, skb);
 
-       if (security_inet_conn_request(sk, skb, req))
-               goto drop_and_free;
-
        ireq = inet_rsk(req);
        ireq->loc_addr = daddr;
        ireq->rmt_addr = saddr;
        ireq->no_srccheck = inet_sk(sk)->transparent;
        ireq->opt = tcp_v4_save_options(sk, skb);
+
+       if (security_inet_conn_request(sk, skb, req))
+               goto drop_and_free;
+
        if (!want_cookie)
                TCP_ECN_create_request(req, tcp_hdr(skb));
 
index 086d5ef098fd0b541359c8bd8448075406ef05cf..811984d9324b6ea0f925d4d3124db1bc7c0e575a 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/sched.h>
+#include <linux/seq_file.h>
 #include <linux/termios.h>
 #include <linux/tty.h>
 #include <linux/interrupt.h>
@@ -72,8 +73,7 @@ static int ircomm_tty_control_indication(void *instance, void *sap,
 static void ircomm_tty_flow_indication(void *instance, void *sap,
                                       LOCAL_FLOW cmd);
 #ifdef CONFIG_PROC_FS
-static int ircomm_tty_read_proc(char *buf, char **start, off_t offset, int len,
-                               int *eof, void *unused);
+static const struct file_operations ircomm_tty_proc_fops;
 #endif /* CONFIG_PROC_FS */
 static struct tty_driver *driver;
 
@@ -98,7 +98,7 @@ static const struct tty_operations ops = {
        .hangup          = ircomm_tty_hangup,
        .wait_until_sent = ircomm_tty_wait_until_sent,
 #ifdef CONFIG_PROC_FS
-       .read_proc       = ircomm_tty_read_proc,
+       .proc_fops       = &ircomm_tty_proc_fops,
 #endif /* CONFIG_PROC_FS */
 };
 
@@ -1245,150 +1245,170 @@ static void ircomm_tty_flow_indication(void *instance, void *sap,
 }
 
 #ifdef CONFIG_PROC_FS
-static int ircomm_tty_line_info(struct ircomm_tty_cb *self, char *buf)
+static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m)
 {
-       int  ret=0;
+       char sep;
 
-       ret += sprintf(buf+ret, "State: %s\n", ircomm_tty_state[self->state]);
+       seq_printf(m, "State: %s\n", ircomm_tty_state[self->state]);
 
-       ret += sprintf(buf+ret, "Service type: ");
+       seq_puts(m, "Service type: ");
        if (self->service_type & IRCOMM_9_WIRE)
-               ret += sprintf(buf+ret, "9_WIRE");
+               seq_puts(m, "9_WIRE");
        else if (self->service_type & IRCOMM_3_WIRE)
-               ret += sprintf(buf+ret, "3_WIRE");
+               seq_puts(m, "3_WIRE");
        else if (self->service_type & IRCOMM_3_WIRE_RAW)
-               ret += sprintf(buf+ret, "3_WIRE_RAW");
+               seq_puts(m, "3_WIRE_RAW");
        else
-               ret += sprintf(buf+ret, "No common service type!\n");
-       ret += sprintf(buf+ret, "\n");
-
-       ret += sprintf(buf+ret, "Port name: %s\n", self->settings.port_name);
-
-       ret += sprintf(buf+ret, "DTE status: ");
-       if (self->settings.dte & IRCOMM_RTS)
-               ret += sprintf(buf+ret, "RTS|");
-       if (self->settings.dte & IRCOMM_DTR)
-               ret += sprintf(buf+ret, "DTR|");
-       if (self->settings.dte)
-               ret--; /* remove the last | */
-       ret += sprintf(buf+ret, "\n");
-
-       ret += sprintf(buf+ret, "DCE status: ");
-       if (self->settings.dce & IRCOMM_CTS)
-               ret += sprintf(buf+ret, "CTS|");
-       if (self->settings.dce & IRCOMM_DSR)
-               ret += sprintf(buf+ret, "DSR|");
-       if (self->settings.dce & IRCOMM_CD)
-               ret += sprintf(buf+ret, "CD|");
-       if (self->settings.dce & IRCOMM_RI)
-               ret += sprintf(buf+ret, "RI|");
-       if (self->settings.dce)
-               ret--; /* remove the last | */
-       ret += sprintf(buf+ret, "\n");
-
-       ret += sprintf(buf+ret, "Configuration: ");
+               seq_puts(m, "No common service type!\n");
+       seq_putc(m, '\n');
+
+       seq_printf(m, "Port name: %s\n", self->settings.port_name);
+
+       seq_printf(m, "DTE status:");
+       sep = ' ';
+       if (self->settings.dte & IRCOMM_RTS) {
+               seq_printf(m, "%cRTS", sep);
+               sep = '|';
+       }
+       if (self->settings.dte & IRCOMM_DTR) {
+               seq_printf(m, "%cDTR", sep);
+               sep = '|';
+       }
+       seq_putc(m, '\n');
+
+       seq_puts(m, "DCE status:");
+       sep = ' ';
+       if (self->settings.dce & IRCOMM_CTS) {
+               seq_printf(m, "%cCTS", sep);
+               sep = '|';
+       }
+       if (self->settings.dce & IRCOMM_DSR) {
+               seq_printf(m, "%cDSR", sep);
+               sep = '|';
+       }
+       if (self->settings.dce & IRCOMM_CD) {
+               seq_printf(m, "%cCD", sep);
+               sep = '|';
+       }
+       if (self->settings.dce & IRCOMM_RI) {
+               seq_printf(m, "%cRI", sep);
+               sep = '|';
+       }
+       seq_putc(m, '\n');
+
+       seq_puts(m, "Configuration: ");
        if (!self->settings.null_modem)
-               ret += sprintf(buf+ret, "DTE <-> DCE\n");
+               seq_puts(m, "DTE <-> DCE\n");
        else
-               ret += sprintf(buf+ret,
-                              "DTE <-> DTE (null modem emulation)\n");
-
-       ret += sprintf(buf+ret, "Data rate: %d\n", self->settings.data_rate);
-
-       ret += sprintf(buf+ret, "Flow control: ");
-       if (self->settings.flow_control & IRCOMM_XON_XOFF_IN)
-               ret += sprintf(buf+ret, "XON_XOFF_IN|");
-       if (self->settings.flow_control & IRCOMM_XON_XOFF_OUT)
-               ret += sprintf(buf+ret, "XON_XOFF_OUT|");
-       if (self->settings.flow_control & IRCOMM_RTS_CTS_IN)
-               ret += sprintf(buf+ret, "RTS_CTS_IN|");
-       if (self->settings.flow_control & IRCOMM_RTS_CTS_OUT)
-               ret += sprintf(buf+ret, "RTS_CTS_OUT|");
-       if (self->settings.flow_control & IRCOMM_DSR_DTR_IN)
-               ret += sprintf(buf+ret, "DSR_DTR_IN|");
-       if (self->settings.flow_control & IRCOMM_DSR_DTR_OUT)
-               ret += sprintf(buf+ret, "DSR_DTR_OUT|");
-       if (self->settings.flow_control & IRCOMM_ENQ_ACK_IN)
-               ret += sprintf(buf+ret, "ENQ_ACK_IN|");
-       if (self->settings.flow_control & IRCOMM_ENQ_ACK_OUT)
-               ret += sprintf(buf+ret, "ENQ_ACK_OUT|");
-       if (self->settings.flow_control)
-               ret--; /* remove the last | */
-       ret += sprintf(buf+ret, "\n");
-
-       ret += sprintf(buf+ret, "Flags: ");
-       if (self->flags & ASYNC_CTS_FLOW)
-               ret += sprintf(buf+ret, "ASYNC_CTS_FLOW|");
-       if (self->flags & ASYNC_CHECK_CD)
-               ret += sprintf(buf+ret, "ASYNC_CHECK_CD|");
-       if (self->flags & ASYNC_INITIALIZED)
-               ret += sprintf(buf+ret, "ASYNC_INITIALIZED|");
-       if (self->flags & ASYNC_LOW_LATENCY)
-               ret += sprintf(buf+ret, "ASYNC_LOW_LATENCY|");
-       if (self->flags & ASYNC_CLOSING)
-               ret += sprintf(buf+ret, "ASYNC_CLOSING|");
-       if (self->flags & ASYNC_NORMAL_ACTIVE)
-               ret += sprintf(buf+ret, "ASYNC_NORMAL_ACTIVE|");
-       if (self->flags)
-               ret--; /* remove the last | */
-       ret += sprintf(buf+ret, "\n");
-
-       ret += sprintf(buf+ret, "Role: %s\n", self->client ?
-                      "client" : "server");
-       ret += sprintf(buf+ret, "Open count: %d\n", self->open_count);
-       ret += sprintf(buf+ret, "Max data size: %d\n", self->max_data_size);
-       ret += sprintf(buf+ret, "Max header size: %d\n", self->max_header_size);
+               seq_puts(m, "DTE <-> DTE (null modem emulation)\n");
+
+       seq_printf(m, "Data rate: %d\n", self->settings.data_rate);
+
+       seq_puts(m, "Flow control:");
+       sep = ' ';
+       if (self->settings.flow_control & IRCOMM_XON_XOFF_IN) {
+               seq_printf(m, "%cXON_XOFF_IN", sep);
+               sep = '|';
+       }
+       if (self->settings.flow_control & IRCOMM_XON_XOFF_OUT) {
+               seq_printf(m, "%cXON_XOFF_OUT", sep);
+               sep = '|';
+       }
+       if (self->settings.flow_control & IRCOMM_RTS_CTS_IN) {
+               seq_printf(m, "%cRTS_CTS_IN", sep);
+               sep = '|';
+       }
+       if (self->settings.flow_control & IRCOMM_RTS_CTS_OUT) {
+               seq_printf(m, "%cRTS_CTS_OUT", sep);
+               sep = '|';
+       }
+       if (self->settings.flow_control & IRCOMM_DSR_DTR_IN) {
+               seq_printf(m, "%cDSR_DTR_IN", sep);
+               sep = '|';
+       }
+       if (self->settings.flow_control & IRCOMM_DSR_DTR_OUT) {
+               seq_printf(m, "%cDSR_DTR_OUT", sep);
+               sep = '|';
+       }
+       if (self->settings.flow_control & IRCOMM_ENQ_ACK_IN) {
+               seq_printf(m, "%cENQ_ACK_IN", sep);
+               sep = '|';
+       }
+       if (self->settings.flow_control & IRCOMM_ENQ_ACK_OUT) {
+               seq_printf(m, "%cENQ_ACK_OUT", sep);
+               sep = '|';
+       }
+       seq_putc(m, '\n');
+
+       seq_puts(m, "Flags:");
+       sep = ' ';
+       if (self->flags & ASYNC_CTS_FLOW) {
+               seq_printf(m, "%cASYNC_CTS_FLOW", sep);
+               sep = '|';
+       }
+       if (self->flags & ASYNC_CHECK_CD) {
+               seq_printf(m, "%cASYNC_CHECK_CD", sep);
+               sep = '|';
+       }
+       if (self->flags & ASYNC_INITIALIZED) {
+               seq_printf(m, "%cASYNC_INITIALIZED", sep);
+               sep = '|';
+       }
+       if (self->flags & ASYNC_LOW_LATENCY) {
+               seq_printf(m, "%cASYNC_LOW_LATENCY", sep);
+               sep = '|';
+       }
+       if (self->flags & ASYNC_CLOSING) {
+               seq_printf(m, "%cASYNC_CLOSING", sep);
+               sep = '|';
+       }
+       if (self->flags & ASYNC_NORMAL_ACTIVE) {
+               seq_printf(m, "%cASYNC_NORMAL_ACTIVE", sep);
+               sep = '|';
+       }
+       seq_putc(m, '\n');
+
+       seq_printf(m, "Role: %s\n", self->client ? "client" : "server");
+       seq_printf(m, "Open count: %d\n", self->open_count);
+       seq_printf(m, "Max data size: %d\n", self->max_data_size);
+       seq_printf(m, "Max header size: %d\n", self->max_header_size);
 
        if (self->tty)
-               ret += sprintf(buf+ret, "Hardware: %s\n",
+               seq_printf(m, "Hardware: %s\n",
                               self->tty->hw_stopped ? "Stopped" : "Running");
-
-       ret += sprintf(buf+ret, "\n");
-       return ret;
 }
 
-
-/*
- * Function ircomm_tty_read_proc (buf, start, offset, len, eof, unused)
- *
- *
- *
- */
-static int ircomm_tty_read_proc(char *buf, char **start, off_t offset, int len,
-                               int *eof, void *unused)
+static int ircomm_tty_proc_show(struct seq_file *m, void *v)
 {
        struct ircomm_tty_cb *self;
-       int count = 0, l;
-       off_t begin = 0;
        unsigned long flags;
 
        spin_lock_irqsave(&ircomm_tty->hb_spinlock, flags);
 
        self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
-       while ((self != NULL) && (count < 4000)) {
+       while (self != NULL) {
                if (self->magic != IRCOMM_TTY_MAGIC)
                        break;
 
-               l = ircomm_tty_line_info(self, buf + count);
-               count += l;
-               if (count+begin > offset+len)
-                       goto done;
-               if (count+begin < offset) {
-                       begin += count;
-                       count = 0;
-               }
-
+               ircomm_tty_line_info(self, m);
                self = (struct ircomm_tty_cb *) hashbin_get_next(ircomm_tty);
        }
-       *eof = 1;
-done:
        spin_unlock_irqrestore(&ircomm_tty->hb_spinlock, flags);
+       return 0;
+}
 
-       if (offset >= count+begin)
-               return 0;
-       *start = buf + (offset-begin);
-       return ((len < begin+count-offset) ? len : begin+count-offset);
+static int ircomm_tty_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ircomm_tty_proc_show, NULL);
 }
+
+static const struct file_operations ircomm_tty_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ircomm_tty_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 #endif /* CONFIG_PROC_FS */
 
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
index 88e80a312732a9ed18e7e1d511d79ac6f0f9d682..8ff1861649e87716d8ecf826c8682182a825a88b 100644 (file)
@@ -70,7 +70,6 @@ void __init irda_proc_register(void)
        proc_irda = proc_mkdir("irda", init_net.proc_net);
        if (proc_irda == NULL)
                return;
-       proc_irda->owner = THIS_MODULE;
 
        for (i = 0; i < ARRAY_SIZE(irda_dirs); i++)
                d = proc_create(irda_dirs[i].name, 0, proc_irda,
index b58bd7c6cdf8b5323df957c1bc113b8970aa9762..d208b3396d94e417546a143c4c7a1d09f9e95f3b 100644 (file)
@@ -236,7 +236,6 @@ int __init llc_proc_init(void)
        llc_proc_dir = proc_mkdir("llc", init_net.proc_net);
        if (!llc_proc_dir)
                goto out;
-       llc_proc_dir->owner = THIS_MODULE;
 
        p = proc_create("socket", S_IRUGO, llc_proc_dir, &llc_seq_socket_fops);
        if (!p)
index fd9229db075cbc64a74dcc25367bc4a478f79c90..b0e582f2d37aa5a9bf52c8efc86384fe0439472b 100644 (file)
@@ -619,8 +619,9 @@ int netlbl_enabled(void)
 }
 
 /**
- * netlbl_socket_setattr - Label a socket using the correct protocol
+ * netlbl_sock_setattr - Label a socket using the correct protocol
  * @sk: the socket to label
+ * @family: protocol family
  * @secattr: the security attributes
  *
  * Description:
@@ -633,29 +634,45 @@ int netlbl_enabled(void)
  *
  */
 int netlbl_sock_setattr(struct sock *sk,
+                       u16 family,
                        const struct netlbl_lsm_secattr *secattr)
 {
-       int ret_val = -ENOENT;
+       int ret_val;
        struct netlbl_dom_map *dom_entry;
 
        rcu_read_lock();
        dom_entry = netlbl_domhsh_getentry(secattr->domain);
-       if (dom_entry == NULL)
+       if (dom_entry == NULL) {
+               ret_val = -ENOENT;
                goto socket_setattr_return;
-       switch (dom_entry->type) {
-       case NETLBL_NLTYPE_ADDRSELECT:
-               ret_val = -EDESTADDRREQ;
-               break;
-       case NETLBL_NLTYPE_CIPSOV4:
-               ret_val = cipso_v4_sock_setattr(sk,
-                                               dom_entry->type_def.cipsov4,
-                                               secattr);
+       }
+       switch (family) {
+       case AF_INET:
+               switch (dom_entry->type) {
+               case NETLBL_NLTYPE_ADDRSELECT:
+                       ret_val = -EDESTADDRREQ;
+                       break;
+               case NETLBL_NLTYPE_CIPSOV4:
+                       ret_val = cipso_v4_sock_setattr(sk,
+                                                   dom_entry->type_def.cipsov4,
+                                                   secattr);
+                       break;
+               case NETLBL_NLTYPE_UNLABELED:
+                       ret_val = 0;
+                       break;
+               default:
+                       ret_val = -ENOENT;
+               }
                break;
-       case NETLBL_NLTYPE_UNLABELED:
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case AF_INET6:
+               /* since we don't support any IPv6 labeling protocols right
+                * now we can optimize everything away until we do */
                ret_val = 0;
                break;
+#endif /* IPv6 */
        default:
-               ret_val = -ENOENT;
+               ret_val = -EPROTONOSUPPORT;
        }
 
 socket_setattr_return:
@@ -689,9 +706,25 @@ void netlbl_sock_delattr(struct sock *sk)
  * on failure.
  *
  */
-int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
+int netlbl_sock_getattr(struct sock *sk,
+                       struct netlbl_lsm_secattr *secattr)
 {
-       return cipso_v4_sock_getattr(sk, secattr);
+       int ret_val;
+
+       switch (sk->sk_family) {
+       case AF_INET:
+               ret_val = cipso_v4_sock_getattr(sk, secattr);
+               break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case AF_INET6:
+               ret_val = -ENOMSG;
+               break;
+#endif /* IPv6 */
+       default:
+               ret_val = -EPROTONOSUPPORT;
+       }
+
+       return ret_val;
 }
 
 /**
@@ -748,7 +781,7 @@ int netlbl_conn_setattr(struct sock *sk,
                break;
 #endif /* IPv6 */
        default:
-               ret_val = 0;
+               ret_val = -EPROTONOSUPPORT;
        }
 
 conn_setattr_return:
@@ -756,6 +789,90 @@ conn_setattr_return:
        return ret_val;
 }
 
+/**
+ * netlbl_req_setattr - Label a request socket using the correct protocol
+ * @req: the request socket to label
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Attach the correct label to the given socket using the security attributes
+ * specified in @secattr.  Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_req_setattr(struct request_sock *req,
+                      const struct netlbl_lsm_secattr *secattr)
+{
+       int ret_val;
+       struct netlbl_dom_map *dom_entry;
+       struct netlbl_domaddr4_map *af4_entry;
+       u32 proto_type;
+       struct cipso_v4_doi *proto_cv4;
+
+       rcu_read_lock();
+       dom_entry = netlbl_domhsh_getentry(secattr->domain);
+       if (dom_entry == NULL) {
+               ret_val = -ENOENT;
+               goto req_setattr_return;
+       }
+       switch (req->rsk_ops->family) {
+       case AF_INET:
+               if (dom_entry->type == NETLBL_NLTYPE_ADDRSELECT) {
+                       struct inet_request_sock *req_inet = inet_rsk(req);
+                       af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
+                                                           req_inet->rmt_addr);
+                       if (af4_entry == NULL) {
+                               ret_val = -ENOENT;
+                               goto req_setattr_return;
+                       }
+                       proto_type = af4_entry->type;
+                       proto_cv4 = af4_entry->type_def.cipsov4;
+               } else {
+                       proto_type = dom_entry->type;
+                       proto_cv4 = dom_entry->type_def.cipsov4;
+               }
+               switch (proto_type) {
+               case NETLBL_NLTYPE_CIPSOV4:
+                       ret_val = cipso_v4_req_setattr(req, proto_cv4, secattr);
+                       break;
+               case NETLBL_NLTYPE_UNLABELED:
+                       /* just delete the protocols we support for right now
+                        * but we could remove other protocols if needed */
+                       cipso_v4_req_delattr(req);
+                       ret_val = 0;
+                       break;
+               default:
+                       ret_val = -ENOENT;
+               }
+               break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case AF_INET6:
+               /* since we don't support any IPv6 labeling protocols right
+                * now we can optimize everything away until we do */
+               ret_val = 0;
+               break;
+#endif /* IPv6 */
+       default:
+               ret_val = -EPROTONOSUPPORT;
+       }
+
+req_setattr_return:
+       rcu_read_unlock();
+       return ret_val;
+}
+
+/**
+* netlbl_req_delattr - Delete all the NetLabel labels on a socket
+* @req: the socket
+*
+* Description:
+* Remove all the NetLabel labeling from @req.
+*
+*/
+void netlbl_req_delattr(struct request_sock *req)
+{
+       cipso_v4_req_delattr(req);
+}
+
 /**
  * netlbl_skbuff_setattr - Label a packet using the correct protocol
  * @skb: the packet
@@ -808,7 +925,7 @@ int netlbl_skbuff_setattr(struct sk_buff *skb,
                break;
 #endif /* IPv6 */
        default:
-               ret_val = 0;
+               ret_val = -EPROTONOSUPPORT;
        }
 
 skbuff_setattr_return:
@@ -833,9 +950,17 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
                          u16 family,
                          struct netlbl_lsm_secattr *secattr)
 {
-       if (CIPSO_V4_OPTEXIST(skb) &&
-           cipso_v4_skbuff_getattr(skb, secattr) == 0)
-               return 0;
+       switch (family) {
+       case AF_INET:
+               if (CIPSO_V4_OPTEXIST(skb) &&
+                   cipso_v4_skbuff_getattr(skb, secattr) == 0)
+                       return 0;
+               break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case AF_INET6:
+               break;
+#endif /* IPv6 */
+       }
 
        return netlbl_unlabel_getattr(skb, family, secattr);
 }
index cb198af8887c97628a82a903b1c93623dcb992e8..8eb3e61cb7011d1032d5562c0f266281ddf00688 100644 (file)
@@ -106,12 +106,8 @@ static __init int sctp_proc_init(void)
                goto out_nomem;
 #ifdef CONFIG_PROC_FS
        if (!proc_net_sctp) {
-               struct proc_dir_entry *ent;
-               ent = proc_mkdir("sctp", init_net.proc_net);
-               if (ent) {
-                       ent->owner = THIS_MODULE;
-                       proc_net_sctp = ent;
-               } else
+               proc_net_sctp = proc_mkdir("sctp", init_net.proc_net);
+               if (!proc_net_sctp)
                        goto out_free_percpu;
        }
 
index 0b14b79c03aff9503f4c56f80b4a6e5850737ca8..91d0c0254ffe7113e98e90a24bd7a824424e9a7f 100644 (file)
@@ -1536,8 +1536,6 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
        fd_install(newfd, newfile);
        err = newfd;
 
-       security_socket_post_accept(sock, newsock);
-
 out_put:
        fput_light(sock->file, fput_needed);
 out:
index 5592883e1e4a9feab8c44dbd42d9ef049da0031c..afd91c78ce8e5dbd53360f65cbc8ab0d87d4e70f 100644 (file)
@@ -17,28 +17,6 @@ config SUNRPC_XPRT_RDMA
 
          If unsure, say N.
 
-config SUNRPC_REGISTER_V4
-       bool "Register local RPC services via rpcbind v4 (EXPERIMENTAL)"
-       depends on SUNRPC && EXPERIMENTAL
-       default n
-       help
-         Sun added support for registering RPC services at an IPv6
-         address by creating two new versions of the rpcbind protocol
-         (RFC 1833).
-
-         This option enables support in the kernel RPC server for
-         registering kernel RPC services via version 4 of the rpcbind
-         protocol.  If you enable this option, you must run a portmapper
-         daemon that supports rpcbind protocol version 4.
-
-         Serving NFS over IPv6 from knfsd (the kernel's NFS server)
-         requires that you enable this option and use a portmapper that
-         supports rpcbind version 4.
-
-         If unsure, say N to get traditional behavior (register kernel
-         RPC services using only rpcbind version 2).  Distributions
-         using the legacy Linux portmapper daemon must say N here.
-
 config RPCSEC_GSS_KRB5
        tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
        depends on SUNRPC && EXPERIMENTAL
index 4735caad26edc4195f503befa997a432145c7528..20029a79a5debf4a645623843c110eecaf5017ad 100644 (file)
@@ -313,7 +313,6 @@ static int create_cache_proc_entries(struct cache_detail *cd)
        cd->proc_ent = proc_mkdir(cd->name, proc_net_rpc);
        if (cd->proc_ent == NULL)
                goto out_nomem;
-       cd->proc_ent->owner = cd->owner;
        cd->channel_ent = cd->content_ent = NULL;
 
        p = proc_create_data("flush", S_IFREG|S_IRUSR|S_IWUSR,
@@ -321,7 +320,6 @@ static int create_cache_proc_entries(struct cache_detail *cd)
        cd->flush_ent = p;
        if (p == NULL)
                goto out_nomem;
-       p->owner = cd->owner;
 
        if (cd->cache_request || cd->cache_parse) {
                p = proc_create_data("channel", S_IFREG|S_IRUSR|S_IWUSR,
@@ -329,7 +327,6 @@ static int create_cache_proc_entries(struct cache_detail *cd)
                cd->channel_ent = p;
                if (p == NULL)
                        goto out_nomem;
-               p->owner = cd->owner;
        }
        if (cd->cache_show) {
                p = proc_create_data("content", S_IFREG|S_IRUSR|S_IWUSR,
@@ -337,7 +334,6 @@ static int create_cache_proc_entries(struct cache_detail *cd)
                cd->content_ent = p;
                if (p == NULL)
                        goto out_nomem;
-               p->owner = cd->owner;
        }
        return 0;
 out_nomem:
index 836f15c0c4a3489b6e9d5ba5a7bfc59514a0db3d..5abab094441f97cbe8dd7f91dcd554579030b6be 100644 (file)
@@ -1032,27 +1032,20 @@ call_connect_status(struct rpc_task *task)
        dprint_status(task);
 
        task->tk_status = 0;
-       if (status >= 0) {
+       if (status >= 0 || status == -EAGAIN) {
                clnt->cl_stats->netreconn++;
                task->tk_action = call_transmit;
                return;
        }
 
-       /* Something failed: remote service port may have changed */
-       rpc_force_rebind(clnt);
-
        switch (status) {
-       case -ENOTCONN:
-       case -EAGAIN:
-               task->tk_action = call_bind;
-               if (!RPC_IS_SOFT(task))
-                       return;
                /* if soft mounted, test if we've timed out */
        case -ETIMEDOUT:
                task->tk_action = call_timeout;
-               return;
+               break;
+       default:
+               rpc_exit(task, -EIO);
        }
-       rpc_exit(task, -EIO);
 }
 
 /*
@@ -1105,14 +1098,26 @@ static void
 call_transmit_status(struct rpc_task *task)
 {
        task->tk_action = call_status;
-       /*
-        * Special case: if we've been waiting on the socket's write_space()
-        * callback, then don't call xprt_end_transmit().
-        */
-       if (task->tk_status == -EAGAIN)
-               return;
-       xprt_end_transmit(task);
-       rpc_task_force_reencode(task);
+       switch (task->tk_status) {
+       case -EAGAIN:
+               break;
+       default:
+               xprt_end_transmit(task);
+               /*
+                * Special cases: if we've been waiting on the
+                * socket's write_space() callback, or if the
+                * socket just returned a connection error,
+                * then hold onto the transport lock.
+                */
+       case -ECONNREFUSED:
+       case -ECONNRESET:
+       case -ENOTCONN:
+       case -EHOSTDOWN:
+       case -EHOSTUNREACH:
+       case -ENETUNREACH:
+       case -EPIPE:
+               rpc_task_force_reencode(task);
+       }
 }
 
 /*
@@ -1152,9 +1157,12 @@ call_status(struct rpc_task *task)
                        xprt_conditional_disconnect(task->tk_xprt,
                                        req->rq_connect_cookie);
                break;
+       case -ECONNRESET:
        case -ECONNREFUSED:
-       case -ENOTCONN:
                rpc_force_rebind(clnt);
+               rpc_delay(task, 3*HZ);
+       case -EPIPE:
+       case -ENOTCONN:
                task->tk_action = call_bind;
                break;
        case -EAGAIN:
index 03ae007641e48523ee22cbd4aa4d5cef825b84c5..beee6da330358cb75ef2e7cb22037d635d0080f0 100644 (file)
@@ -63,9 +63,16 @@ enum {
  * r_owner
  *
  * The "owner" is allowed to unset a service in the rpcbind database.
- * We always use the following (arbitrary) fixed string.
+ *
+ * For AF_LOCAL SET/UNSET requests, rpcbind treats this string as a
+ * UID which it maps to a local user name via a password lookup.
+ * In all other cases it is ignored.
+ *
+ * For SET/UNSET requests, user space provides a value, even for
+ * network requests, and GETADDR uses an empty string.  We follow
+ * those precedents here.
  */
-#define RPCB_OWNER_STRING      "rpcb"
+#define RPCB_OWNER_STRING      "0"
 #define RPCB_MAXOWNERLEN       sizeof(RPCB_OWNER_STRING)
 
 static void                    rpcb_getport_done(struct rpc_task *, void *);
@@ -124,12 +131,6 @@ static const struct sockaddr_in rpcb_inaddr_loopback = {
        .sin_port               = htons(RPCBIND_PORT),
 };
 
-static const struct sockaddr_in6 rpcb_in6addr_loopback = {
-       .sin6_family            = AF_INET6,
-       .sin6_addr              = IN6ADDR_LOOPBACK_INIT,
-       .sin6_port              = htons(RPCBIND_PORT),
-};
-
 static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr,
                                          size_t addrlen, u32 version)
 {
@@ -176,9 +177,10 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
        return rpc_create(&args);
 }
 
-static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
-                             u32 version, struct rpc_message *msg)
+static int rpcb_register_call(const u32 version, struct rpc_message *msg)
 {
+       struct sockaddr *addr = (struct sockaddr *)&rpcb_inaddr_loopback;
+       size_t addrlen = sizeof(rpcb_inaddr_loopback);
        struct rpc_clnt *rpcb_clnt;
        int result, error = 0;
 
@@ -192,7 +194,7 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
                error = PTR_ERR(rpcb_clnt);
 
        if (error < 0) {
-               printk(KERN_WARNING "RPC: failed to contact local rpcbind "
+               dprintk("RPC:       failed to contact local rpcbind "
                                "server (errno %d).\n", -error);
                return error;
        }
@@ -254,25 +256,23 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
        if (port)
                msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET];
 
-       return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
-                                       sizeof(rpcb_inaddr_loopback),
-                                       RPCBVERS_2, &msg);
+       return rpcb_register_call(RPCBVERS_2, &msg);
 }
 
 /*
  * Fill in AF_INET family-specific arguments to register
  */
-static int rpcb_register_netid4(struct sockaddr_in *address_to_register,
-                               struct rpc_message *msg)
+static int rpcb_register_inet4(const struct sockaddr *sap,
+                              struct rpc_message *msg)
 {
+       const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
        struct rpcbind_args *map = msg->rpc_argp;
-       unsigned short port = ntohs(address_to_register->sin_port);
+       unsigned short port = ntohs(sin->sin_port);
        char buf[32];
 
        /* Construct AF_INET universal address */
        snprintf(buf, sizeof(buf), "%pI4.%u.%u",
-                &address_to_register->sin_addr.s_addr,
-                port >> 8, port & 0xff);
+                &sin->sin_addr.s_addr, port >> 8, port & 0xff);
        map->r_addr = buf;
 
        dprintk("RPC:       %sregistering [%u, %u, %s, '%s'] with "
@@ -284,29 +284,27 @@ static int rpcb_register_netid4(struct sockaddr_in *address_to_register,
        if (port)
                msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
 
-       return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
-                                       sizeof(rpcb_inaddr_loopback),
-                                       RPCBVERS_4, msg);
+       return rpcb_register_call(RPCBVERS_4, msg);
 }
 
 /*
  * Fill in AF_INET6 family-specific arguments to register
  */
-static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
-                               struct rpc_message *msg)
+static int rpcb_register_inet6(const struct sockaddr *sap,
+                              struct rpc_message *msg)
 {
+       const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
        struct rpcbind_args *map = msg->rpc_argp;
-       unsigned short port = ntohs(address_to_register->sin6_port);
+       unsigned short port = ntohs(sin6->sin6_port);
        char buf[64];
 
        /* Construct AF_INET6 universal address */
-       if (ipv6_addr_any(&address_to_register->sin6_addr))
+       if (ipv6_addr_any(&sin6->sin6_addr))
                snprintf(buf, sizeof(buf), "::.%u.%u",
                                port >> 8, port & 0xff);
        else
                snprintf(buf, sizeof(buf), "%pI6.%u.%u",
-                        &address_to_register->sin6_addr,
-                        port >> 8, port & 0xff);
+                        &sin6->sin6_addr, port >> 8, port & 0xff);
        map->r_addr = buf;
 
        dprintk("RPC:       %sregistering [%u, %u, %s, '%s'] with "
@@ -318,9 +316,21 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
        if (port)
                msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
 
-       return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback,
-                                       sizeof(rpcb_in6addr_loopback),
-                                       RPCBVERS_4, msg);
+       return rpcb_register_call(RPCBVERS_4, msg);
+}
+
+static int rpcb_unregister_all_protofamilies(struct rpc_message *msg)
+{
+       struct rpcbind_args *map = msg->rpc_argp;
+
+       dprintk("RPC:       unregistering [%u, %u, '%s'] with "
+               "local rpcbind\n",
+                       map->r_prog, map->r_vers, map->r_netid);
+
+       map->r_addr = "";
+       msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
+
+       return rpcb_register_call(RPCBVERS_4, msg);
 }
 
 /**
@@ -340,10 +350,11 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
  * invoke this function once for each [program, version, address,
  * netid] tuple they wish to advertise.
  *
- * Callers may also unregister RPC services that are no longer
- * available by setting the port number in the passed-in address
- * to zero.  Callers pass a netid of "" to unregister all
- * transport netids associated with [program, version, address].
+ * Callers may also unregister RPC services that are registered at a
+ * specific address by setting the port number in @address to zero.
+ * They may unregister all registered protocol families at once for
+ * a service by passing a NULL @address argument.  If @netid is ""
+ * then all netids for [program, version, address] are unregistered.
  *
  * This function uses rpcbind protocol version 4 to contact the
  * local rpcbind daemon.  The local rpcbind daemon must support
@@ -378,13 +389,14 @@ int rpcb_v4_register(const u32 program, const u32 version,
                .rpc_argp       = &map,
        };
 
+       if (address == NULL)
+               return rpcb_unregister_all_protofamilies(&msg);
+
        switch (address->sa_family) {
        case AF_INET:
-               return rpcb_register_netid4((struct sockaddr_in *)address,
-                                           &msg);
+               return rpcb_register_inet4(address, &msg);
        case AF_INET6:
-               return rpcb_register_netid6((struct sockaddr_in6 *)address,
-                                           &msg);
+               return rpcb_register_inet6(address, &msg);
        }
 
        return -EAFNOSUPPORT;
@@ -579,7 +591,7 @@ void rpcb_getport_async(struct rpc_task *task)
        map->r_xprt = xprt_get(xprt);
        map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
        map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR);
-       map->r_owner = RPCB_OWNER_STRING;       /* ignored for GETADDR */
+       map->r_owner = "";
        map->r_status = -EIO;
 
        child = rpcb_call_async(rpcb_clnt, map, proc);
@@ -703,11 +715,16 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
        *portp = 0;
        addr_len = ntohl(*p++);
 
+       if (addr_len == 0) {
+               dprintk("RPC:       rpcb_decode_getaddr: "
+                                       "service is not registered\n");
+               return 0;
+       }
+
        /*
-        * Simple sanity check.  The smallest possible universal
-        * address is an IPv4 address string containing 11 bytes.
+        * Simple sanity check.
         */
-       if (addr_len < 11 || addr_len > RPCBIND_MAXUADDRLEN)
+       if (addr_len > RPCBIND_MAXUADDRLEN)
                goto out_err;
 
        /*
index 085372ef4feb148bf99d0525074ef7c819c09051..1ef6e46d9da273b276625e765e6d6bd1c880457a 100644 (file)
@@ -262,14 +262,8 @@ void
 rpc_proc_init(void)
 {
        dprintk("RPC:       registering /proc/net/rpc\n");
-       if (!proc_net_rpc) {
-               struct proc_dir_entry *ent;
-               ent = proc_mkdir("rpc", init_net.proc_net);
-               if (ent) {
-                       ent->owner = THIS_MODULE;
-                       proc_net_rpc = ent;
-               }
-       }
+       if (!proc_net_rpc)
+               proc_net_rpc = proc_mkdir("rpc", init_net.proc_net);
 }
 
 void
index c51fed4d1af1d3b93ebfbbf9e2eaeaf4a76fb16f..9f2f2412a2f35245056f5174cd5bbbb956cabd13 100644 (file)
@@ -312,7 +312,7 @@ svc_pool_map_set_cpumask(struct task_struct *task, unsigned int pidx)
        switch (m->mode) {
        case SVC_POOL_PERCPU:
        {
-               set_cpus_allowed_ptr(task, &cpumask_of_cpu(node));
+               set_cpus_allowed_ptr(task, cpumask_of(node));
                break;
        }
        case SVC_POOL_PERNODE:
@@ -359,7 +359,7 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu)
  */
 static struct svc_serv *
 __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
-          sa_family_t family, void (*shutdown)(struct svc_serv *serv))
+            void (*shutdown)(struct svc_serv *serv))
 {
        struct svc_serv *serv;
        unsigned int vers;
@@ -368,7 +368,6 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
 
        if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
                return NULL;
-       serv->sv_family    = family;
        serv->sv_name      = prog->pg_name;
        serv->sv_program   = prog;
        serv->sv_nrthreads = 1;
@@ -427,21 +426,21 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
 
 struct svc_serv *
 svc_create(struct svc_program *prog, unsigned int bufsize,
-               sa_family_t family, void (*shutdown)(struct svc_serv *serv))
+          void (*shutdown)(struct svc_serv *serv))
 {
-       return __svc_create(prog, bufsize, /*npools*/1, family, shutdown);
+       return __svc_create(prog, bufsize, /*npools*/1, shutdown);
 }
 EXPORT_SYMBOL_GPL(svc_create);
 
 struct svc_serv *
 svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
-                 sa_family_t family, void (*shutdown)(struct svc_serv *serv),
+                 void (*shutdown)(struct svc_serv *serv),
                  svc_thread_fn func, struct module *mod)
 {
        struct svc_serv *serv;
        unsigned int npools = svc_pool_map_get();
 
-       serv = __svc_create(prog, bufsize, npools, family, shutdown);
+       serv = __svc_create(prog, bufsize, npools, shutdown);
 
        if (serv != NULL) {
                serv->sv_function = func;
@@ -719,8 +718,6 @@ svc_exit_thread(struct svc_rqst *rqstp)
 }
 EXPORT_SYMBOL_GPL(svc_exit_thread);
 
-#ifdef CONFIG_SUNRPC_REGISTER_V4
-
 /*
  * Register an "inet" protocol family netid with the local
  * rpcbind daemon via an rpcbind v4 SET request.
@@ -735,12 +732,13 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
                                const unsigned short protocol,
                                const unsigned short port)
 {
-       struct sockaddr_in sin = {
+       const struct sockaddr_in sin = {
                .sin_family             = AF_INET,
                .sin_addr.s_addr        = htonl(INADDR_ANY),
                .sin_port               = htons(port),
        };
-       char *netid;
+       const char *netid;
+       int error;
 
        switch (protocol) {
        case IPPROTO_UDP:
@@ -750,13 +748,23 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
                netid = RPCBIND_NETID_TCP;
                break;
        default:
-               return -EPROTONOSUPPORT;
+               return -ENOPROTOOPT;
        }
 
-       return rpcb_v4_register(program, version,
-                               (struct sockaddr *)&sin, netid);
+       error = rpcb_v4_register(program, version,
+                                       (const struct sockaddr *)&sin, netid);
+
+       /*
+        * User space didn't support rpcbind v4, so retry this
+        * registration request with the legacy rpcbind v2 protocol.
+        */
+       if (error == -EPROTONOSUPPORT)
+               error = rpcb_register(program, version, protocol, port);
+
+       return error;
 }
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 /*
  * Register an "inet6" protocol family netid with the local
  * rpcbind daemon via an rpcbind v4 SET request.
@@ -771,12 +779,13 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
                                const unsigned short protocol,
                                const unsigned short port)
 {
-       struct sockaddr_in6 sin6 = {
+       const struct sockaddr_in6 sin6 = {
                .sin6_family            = AF_INET6,
                .sin6_addr              = IN6ADDR_ANY_INIT,
                .sin6_port              = htons(port),
        };
-       char *netid;
+       const char *netid;
+       int error;
 
        switch (protocol) {
        case IPPROTO_UDP:
@@ -786,12 +795,22 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
                netid = RPCBIND_NETID_TCP6;
                break;
        default:
-               return -EPROTONOSUPPORT;
+               return -ENOPROTOOPT;
        }
 
-       return rpcb_v4_register(program, version,
-                               (struct sockaddr *)&sin6, netid);
+       error = rpcb_v4_register(program, version,
+                                       (const struct sockaddr *)&sin6, netid);
+
+       /*
+        * User space didn't support rpcbind version 4, so we won't
+        * use a PF_INET6 listener.
+        */
+       if (error == -EPROTONOSUPPORT)
+               error = -EAFNOSUPPORT;
+
+       return error;
 }
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
 
 /*
  * Register a kernel RPC service via rpcbind version 4.
@@ -799,69 +818,43 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
  * Returns zero on success; a negative errno value is returned
  * if any error occurs.
  */
-static int __svc_register(const u32 program, const u32 version,
-                         const sa_family_t family,
+static int __svc_register(const char *progname,
+                         const u32 program, const u32 version,
+                         const int family,
                          const unsigned short protocol,
                          const unsigned short port)
 {
-       int error;
+       int error = -EAFNOSUPPORT;
 
        switch (family) {
-       case AF_INET:
-               return __svc_rpcb_register4(program, version,
+       case PF_INET:
+               error = __svc_rpcb_register4(program, version,
                                                protocol, port);
-       case AF_INET6:
+               break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case PF_INET6:
                error = __svc_rpcb_register6(program, version,
                                                protocol, port);
-               if (error < 0)
-                       return error;
-
-               /*
-                * Work around bug in some versions of Linux rpcbind
-                * which don't allow registration of both inet and
-                * inet6 netids.
-                *
-                * Error return ignored for now.
-                */
-               __svc_rpcb_register4(program, version,
-                                               protocol, port);
-               return 0;
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
        }
 
-       return -EAFNOSUPPORT;
-}
-
-#else  /* CONFIG_SUNRPC_REGISTER_V4 */
-
-/*
- * Register a kernel RPC service via rpcbind version 2.
- *
- * Returns zero on success; a negative errno value is returned
- * if any error occurs.
- */
-static int __svc_register(const u32 program, const u32 version,
-                         sa_family_t family,
-                         const unsigned short protocol,
-                         const unsigned short port)
-{
-       if (family != AF_INET)
-               return -EAFNOSUPPORT;
-
-       return rpcb_register(program, version, protocol, port);
+       if (error < 0)
+               printk(KERN_WARNING "svc: failed to register %sv%u RPC "
+                       "service (errno %d).\n", progname, version, -error);
+       return error;
 }
 
-#endif /* CONFIG_SUNRPC_REGISTER_V4 */
-
 /**
  * svc_register - register an RPC service with the local portmapper
  * @serv: svc_serv struct for the service to register
+ * @family: protocol family of service's listener socket
  * @proto: transport protocol number to advertise
  * @port: port to advertise
  *
- * Service is registered for any address in serv's address family
+ * Service is registered for any address in the passed-in protocol family
  */
-int svc_register(const struct svc_serv *serv, const unsigned short proto,
-                const unsigned short port)
+int svc_register(const struct svc_serv *serv, const int family,
+                const unsigned short proto, const unsigned short port)
 {
        struct svc_program      *progp;
        unsigned int            i;
@@ -879,15 +872,15 @@ int svc_register(const struct svc_serv *serv, const unsigned short proto,
                                        i,
                                        proto == IPPROTO_UDP?  "udp" : "tcp",
                                        port,
-                                       serv->sv_family,
+                                       family,
                                        progp->pg_vers[i]->vs_hidden?
                                                " (but not telling portmap)" : "");
 
                        if (progp->pg_vers[i]->vs_hidden)
                                continue;
 
-                       error = __svc_register(progp->pg_prog, i,
-                                               serv->sv_family, proto, port);
+                       error = __svc_register(progp->pg_name, progp->pg_prog,
+                                               i, family, proto, port);
                        if (error < 0)
                                break;
                }
@@ -896,38 +889,31 @@ int svc_register(const struct svc_serv *serv, const unsigned short proto,
        return error;
 }
 
-#ifdef CONFIG_SUNRPC_REGISTER_V4
-
+/*
+ * If user space is running rpcbind, it should take the v4 UNSET
+ * and clear everything for this [program, version].  If user space
+ * is running portmap, it will reject the v4 UNSET, but won't have
+ * any "inet6" entries anyway.  So a PMAP_UNSET should be sufficient
+ * in this case to clear all existing entries for [program, version].
+ */
 static void __svc_unregister(const u32 program, const u32 version,
                             const char *progname)
 {
-       struct sockaddr_in6 sin6 = {
-               .sin6_family            = AF_INET6,
-               .sin6_addr              = IN6ADDR_ANY_INIT,
-               .sin6_port              = 0,
-       };
        int error;
 
-       error = rpcb_v4_register(program, version,
-                               (struct sockaddr *)&sin6, "");
-       dprintk("svc: %s(%sv%u), error %d\n",
-                       __func__, progname, version, error);
-}
-
-#else  /* CONFIG_SUNRPC_REGISTER_V4 */
+       error = rpcb_v4_register(program, version, NULL, "");
 
-static void __svc_unregister(const u32 program, const u32 version,
-                            const char *progname)
-{
-       int error;
+       /*
+        * User space didn't support rpcbind v4, so retry this
+        * request with the legacy rpcbind v2 protocol.
+        */
+       if (error == -EPROTONOSUPPORT)
+               error = rpcb_register(program, version, 0, 0);
 
-       error = rpcb_register(program, version, 0, 0);
        dprintk("svc: %s(%sv%u), error %d\n",
                        __func__, progname, version, error);
 }
 
-#endif /* CONFIG_SUNRPC_REGISTER_V4 */
-
 /*
  * All netids, bind addresses and ports registered for [program, version]
  * are removed from the local rpcbind database (if the service is not
index e588df5d6b34292f63fcf1d9e43c8ae05eeecb17..2819ee093f365210c21c3895858221e5c4a3b656 100644 (file)
@@ -161,7 +161,9 @@ EXPORT_SYMBOL_GPL(svc_xprt_init);
 
 static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
                                         struct svc_serv *serv,
-                                        unsigned short port, int flags)
+                                        const int family,
+                                        const unsigned short port,
+                                        int flags)
 {
        struct sockaddr_in sin = {
                .sin_family             = AF_INET,
@@ -176,12 +178,12 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
        struct sockaddr *sap;
        size_t len;
 
-       switch (serv->sv_family) {
-       case AF_INET:
+       switch (family) {
+       case PF_INET:
                sap = (struct sockaddr *)&sin;
                len = sizeof(sin);
                break;
-       case AF_INET6:
+       case PF_INET6:
                sap = (struct sockaddr *)&sin6;
                len = sizeof(sin6);
                break;
@@ -192,7 +194,8 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
        return xcl->xcl_ops->xpo_create(serv, sap, len, flags);
 }
 
-int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
+int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
+                   const int family, const unsigned short port,
                    int flags)
 {
        struct svc_xprt_class *xcl;
@@ -209,7 +212,7 @@ int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
                        goto err;
 
                spin_unlock(&svc_xprt_class_lock);
-               newxprt = __svc_xpo_create(xcl, serv, port, flags);
+               newxprt = __svc_xpo_create(xcl, serv, family, port, flags);
                if (IS_ERR(newxprt)) {
                        module_put(xcl->xcl_owner);
                        return PTR_ERR(newxprt);
@@ -1033,7 +1036,13 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
        return dr;
 }
 
-/*
+/**
+ * svc_find_xprt - find an RPC transport instance
+ * @serv: pointer to svc_serv to search
+ * @xcl_name: C string containing transport's class name
+ * @af: Address family of transport's local address
+ * @port: transport's IP port number
+ *
  * Return the transport instance pointer for the endpoint accepting
  * connections/peer traffic from the specified transport class,
  * address family and port.
@@ -1042,14 +1051,14 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
  * wild-card, and will result in matching the first transport in the
  * service's list that has a matching class name.
  */
-struct svc_xprt *svc_find_xprt(struct svc_serv *serv, char *xcl_name,
-                              int af, int port)
+struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
+                              const sa_family_t af, const unsigned short port)
 {
        struct svc_xprt *xprt;
        struct svc_xprt *found = NULL;
 
        /* Sanity check the args */
-       if (!serv || !xcl_name)
+       if (serv == NULL || xcl_name == NULL)
                return found;
 
        spin_lock_bh(&serv->sv_lock);
@@ -1058,7 +1067,7 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, char *xcl_name,
                        continue;
                if (af != AF_UNSPEC && af != xprt->xpt_local.ss_family)
                        continue;
-               if (port && port != svc_xprt_local_port(xprt))
+               if (port != 0 && port != svc_xprt_local_port(xprt))
                        continue;
                found = xprt;
                svc_xprt_get(xprt);
index 5763e6460feac2535429bd97b7f9e43b36816cd9..9d504234af4a664f5f116171b9d6e02825d1ac4f 100644 (file)
@@ -1110,7 +1110,6 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
        struct svc_sock *svsk;
        struct sock     *inet;
        int             pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
-       int             val;
 
        dprintk("svc: svc_setup_socket %p\n", sock);
        if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) {
@@ -1122,7 +1121,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
 
        /* Register socket with portmapper */
        if (*errp >= 0 && pmap_register)
-               *errp = svc_register(serv, inet->sk_protocol,
+               *errp = svc_register(serv, inet->sk_family, inet->sk_protocol,
                                     ntohs(inet_sk(inet)->sport));
 
        if (*errp < 0) {
@@ -1143,18 +1142,6 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
        else
                svc_tcp_init(svsk, serv);
 
-       /*
-        * We start one listener per sv_serv.  We want AF_INET
-        * requests to be automatically shunted to our AF_INET6
-        * listener using a mapped IPv4 address.  Make sure
-        * no-one starts an equivalent IPv4 listener, which
-        * would steal our incoming connections.
-        */
-       val = 0;
-       if (serv->sv_family == AF_INET6)
-               kernel_setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
-                                       (char *)&val, sizeof(val));
-
        dprintk("svc: svc_setup_socket created %p (inet %p)\n",
                                svsk, svsk->sk_sk);
 
@@ -1222,6 +1209,8 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
        struct sockaddr_storage addr;
        struct sockaddr *newsin = (struct sockaddr *)&addr;
        int             newlen;
+       int             family;
+       int             val;
        RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
 
        dprintk("svc: svc_create_socket(%s, %d, %s)\n",
@@ -1233,14 +1222,35 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
                                "sockets supported\n");
                return ERR_PTR(-EINVAL);
        }
+
        type = (protocol == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM;
+       switch (sin->sa_family) {
+       case AF_INET6:
+               family = PF_INET6;
+               break;
+       case AF_INET:
+               family = PF_INET;
+               break;
+       default:
+               return ERR_PTR(-EINVAL);
+       }
 
-       error = sock_create_kern(sin->sa_family, type, protocol, &sock);
+       error = sock_create_kern(family, type, protocol, &sock);
        if (error < 0)
                return ERR_PTR(error);
 
        svc_reclassify_socket(sock);
 
+       /*
+        * If this is an PF_INET6 listener, we want to avoid
+        * getting requests from IPv4 remotes.  Those should
+        * be shunted to a PF_INET listener via rpcbind.
+        */
+       val = 1;
+       if (family == PF_INET6)
+               kernel_setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
+                                       (char *)&val, sizeof(val));
+
        if (type == SOCK_STREAM)
                sock->sk->sk_reuse = 1;         /* allow address reuse */
        error = kernel_bind(sock, sin, len);
index 62098d101a1fa612e70dfe2319bfb99abee412b3..a0bfe53f162145c9d636f090066a03fd8a42e74f 100644 (file)
@@ -151,6 +151,37 @@ out:
 }
 EXPORT_SYMBOL_GPL(xprt_unregister_transport);
 
+/**
+ * xprt_load_transport - load a transport implementation
+ * @transport_name: transport to load
+ *
+ * Returns:
+ * 0:          transport successfully loaded
+ * -ENOENT:    transport module not available
+ */
+int xprt_load_transport(const char *transport_name)
+{
+       struct xprt_class *t;
+       char module_name[sizeof t->name + 5];
+       int result;
+
+       result = 0;
+       spin_lock(&xprt_list_lock);
+       list_for_each_entry(t, &xprt_list, list) {
+               if (strcmp(t->name, transport_name) == 0) {
+                       spin_unlock(&xprt_list_lock);
+                       goto out;
+               }
+       }
+       spin_unlock(&xprt_list_lock);
+       strcpy(module_name, "xprt");
+       strncat(module_name, transport_name, sizeof t->name);
+       result = request_module(module_name);
+out:
+       return result;
+}
+EXPORT_SYMBOL_GPL(xprt_load_transport);
+
 /**
  * xprt_reserve_xprt - serialize write access to transports
  * @task: task that is requesting access to the transport
@@ -580,7 +611,7 @@ void xprt_disconnect_done(struct rpc_xprt *xprt)
        dprintk("RPC:       disconnected transport %p\n", xprt);
        spin_lock_bh(&xprt->transport_lock);
        xprt_clear_connected(xprt);
-       xprt_wake_pending_tasks(xprt, -ENOTCONN);
+       xprt_wake_pending_tasks(xprt, -EAGAIN);
        spin_unlock_bh(&xprt->transport_lock);
 }
 EXPORT_SYMBOL_GPL(xprt_disconnect_done);
@@ -598,7 +629,7 @@ void xprt_force_disconnect(struct rpc_xprt *xprt)
        /* Try to schedule an autoclose RPC call */
        if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
                queue_work(rpciod_workqueue, &xprt->task_cleanup);
-       xprt_wake_pending_tasks(xprt, -ENOTCONN);
+       xprt_wake_pending_tasks(xprt, -EAGAIN);
        spin_unlock_bh(&xprt->transport_lock);
 }
 
@@ -625,7 +656,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie)
        /* Try to schedule an autoclose RPC call */
        if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
                queue_work(rpciod_workqueue, &xprt->task_cleanup);
-       xprt_wake_pending_tasks(xprt, -ENOTCONN);
+       xprt_wake_pending_tasks(xprt, -EAGAIN);
 out:
        spin_unlock_bh(&xprt->transport_lock);
 }
@@ -695,9 +726,8 @@ static void xprt_connect_status(struct rpc_task *task)
        }
 
        switch (task->tk_status) {
-       case -ENOTCONN:
-               dprintk("RPC: %5u xprt_connect_status: connection broken\n",
-                               task->tk_pid);
+       case -EAGAIN:
+               dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid);
                break;
        case -ETIMEDOUT:
                dprintk("RPC: %5u xprt_connect_status: connect attempt timed "
@@ -818,15 +848,8 @@ int xprt_prepare_transmit(struct rpc_task *task)
                err = req->rq_received;
                goto out_unlock;
        }
-       if (!xprt->ops->reserve_xprt(task)) {
+       if (!xprt->ops->reserve_xprt(task))
                err = -EAGAIN;
-               goto out_unlock;
-       }
-
-       if (!xprt_connected(xprt)) {
-               err = -ENOTCONN;
-               goto out_unlock;
-       }
 out_unlock:
        spin_unlock_bh(&xprt->transport_lock);
        return err;
@@ -870,32 +893,26 @@ void xprt_transmit(struct rpc_task *task)
        req->rq_connect_cookie = xprt->connect_cookie;
        req->rq_xtime = jiffies;
        status = xprt->ops->send_request(task);
-       if (status == 0) {
-               dprintk("RPC: %5u xmit complete\n", task->tk_pid);
-               spin_lock_bh(&xprt->transport_lock);
+       if (status != 0) {
+               task->tk_status = status;
+               return;
+       }
 
-               xprt->ops->set_retrans_timeout(task);
+       dprintk("RPC: %5u xmit complete\n", task->tk_pid);
+       spin_lock_bh(&xprt->transport_lock);
 
-               xprt->stat.sends++;
-               xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs;
-               xprt->stat.bklog_u += xprt->backlog.qlen;
+       xprt->ops->set_retrans_timeout(task);
 
-               /* Don't race with disconnect */
-               if (!xprt_connected(xprt))
-                       task->tk_status = -ENOTCONN;
-               else if (!req->rq_received)
-                       rpc_sleep_on(&xprt->pending, task, xprt_timer);
-               spin_unlock_bh(&xprt->transport_lock);
-               return;
-       }
+       xprt->stat.sends++;
+       xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs;
+       xprt->stat.bklog_u += xprt->backlog.qlen;
 
-       /* Note: at this point, task->tk_sleeping has not yet been set,
-        *       hence there is no danger of the waking up task being put on
-        *       schedq, and being picked up by a parallel run of rpciod().
-        */
-       task->tk_status = status;
-       if (status == -ECONNREFUSED)
-               rpc_sleep_on(&xprt->sending, task, NULL);
+       /* Don't race with disconnect */
+       if (!xprt_connected(xprt))
+               task->tk_status = -ENOTCONN;
+       else if (!req->rq_received)
+               rpc_sleep_on(&xprt->pending, task, xprt_timer);
+       spin_unlock_bh(&xprt->transport_lock);
 }
 
 static inline void do_xprt_reserve(struct rpc_task *task)
index 14106d26bb95881b2f7e3c5496aa8b10625a298f..e5e28d1946a41a852a558caa83ca49c68265bed7 100644 (file)
@@ -310,6 +310,19 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad)
                __func__, pad, destp, rqst->rq_slen, curlen);
 
        copy_len = rqst->rq_snd_buf.page_len;
+
+       if (rqst->rq_snd_buf.tail[0].iov_len) {
+               curlen = rqst->rq_snd_buf.tail[0].iov_len;
+               if (destp + copy_len != rqst->rq_snd_buf.tail[0].iov_base) {
+                       memmove(destp + copy_len,
+                               rqst->rq_snd_buf.tail[0].iov_base, curlen);
+                       r_xprt->rx_stats.pullup_copy_count += curlen;
+               }
+               dprintk("RPC:       %s: tail destp 0x%p len %d\n",
+                       __func__, destp + copy_len, curlen);
+               rqst->rq_svec[0].iov_len += curlen;
+       }
+
        r_xprt->rx_stats.pullup_copy_count += copy_len;
        npages = PAGE_ALIGN(rqst->rq_snd_buf.page_base+copy_len) >> PAGE_SHIFT;
        for (i = 0; copy_len && i < npages; i++) {
@@ -332,17 +345,6 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad)
                destp += curlen;
                copy_len -= curlen;
        }
-       if (rqst->rq_snd_buf.tail[0].iov_len) {
-               curlen = rqst->rq_snd_buf.tail[0].iov_len;
-               if (destp != rqst->rq_snd_buf.tail[0].iov_base) {
-                       memcpy(destp,
-                               rqst->rq_snd_buf.tail[0].iov_base, curlen);
-                       r_xprt->rx_stats.pullup_copy_count += curlen;
-               }
-               dprintk("RPC:       %s: tail destp 0x%p len %d curlen %d\n",
-                       __func__, destp, copy_len, curlen);
-               rqst->rq_svec[0].iov_len += curlen;
-       }
        /* header now contains entire send message */
        return pad;
 }
@@ -656,7 +658,7 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
                if (curlen > rqst->rq_rcv_buf.tail[0].iov_len)
                        curlen = rqst->rq_rcv_buf.tail[0].iov_len;
                if (rqst->rq_rcv_buf.tail[0].iov_base != srcp)
-                       memcpy(rqst->rq_rcv_buf.tail[0].iov_base, srcp, curlen);
+                       memmove(rqst->rq_rcv_buf.tail[0].iov_base, srcp, curlen);
                dprintk("RPC:       %s: tail srcp 0x%p len %d curlen %d\n",
                        __func__, srcp, copy_len, curlen);
                rqst->rq_rcv_buf.tail[0].iov_len = curlen;
index a3334e3b73cc19f82c47453ad4da6603153ca0b2..6c26a675435a00903d13093481f273a7bafbbaab 100644 (file)
@@ -191,7 +191,6 @@ static int map_xdr(struct svcxprt_rdma *xprt,
                   struct xdr_buf *xdr,
                   struct svc_rdma_req_map *vec)
 {
-       int sge_max = (xdr->len+PAGE_SIZE-1) / PAGE_SIZE + 3;
        int sge_no;
        u32 sge_bytes;
        u32 page_bytes;
@@ -235,7 +234,11 @@ static int map_xdr(struct svcxprt_rdma *xprt,
                sge_no++;
        }
 
-       BUG_ON(sge_no > sge_max);
+       dprintk("svcrdma: map_xdr: sge_no %d page_no %d "
+               "page_base %u page_len %u head_len %zu tail_len %zu\n",
+               sge_no, page_no, xdr->page_base, xdr->page_len,
+               xdr->head[0].iov_len, xdr->tail[0].iov_len);
+
        vec->count = sge_no;
        return 0;
 }
@@ -579,7 +582,6 @@ static int send_reply(struct svcxprt_rdma *rdma,
                        ctxt->sge[page_no+1].length = 0;
        }
        BUG_ON(sge_no > rdma->sc_max_sge);
-       BUG_ON(sge_no > ctxt->count);
        memset(&send_wr, 0, sizeof send_wr);
        ctxt->wr_op = IB_WR_SEND;
        send_wr.wr_id = (unsigned long)ctxt;
index 568330eebbfeb68e469ead8f23f8f059093850b4..d40ff50887aa468544c500de540d7b6a29108b67 100644 (file)
@@ -49,6 +49,9 @@ unsigned int xprt_tcp_slot_table_entries = RPC_DEF_SLOT_TABLE;
 unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT;
 unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT;
 
+#define XS_TCP_LINGER_TO       (15U * HZ)
+static unsigned int xs_tcp_fin_timeout __read_mostly = XS_TCP_LINGER_TO;
+
 /*
  * We can register our own files under /proc/sys/sunrpc by
  * calling register_sysctl_table() again.  The files in that
@@ -116,6 +119,14 @@ static ctl_table xs_tunables_table[] = {
                .extra1         = &xprt_min_resvport_limit,
                .extra2         = &xprt_max_resvport_limit
        },
+       {
+               .procname       = "tcp_fin_timeout",
+               .data           = &xs_tcp_fin_timeout,
+               .maxlen         = sizeof(xs_tcp_fin_timeout),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_jiffies,
+               .strategy       = sysctl_jiffies
+       },
        {
                .ctl_name = 0,
        },
@@ -521,11 +532,12 @@ static void xs_nospace_callback(struct rpc_task *task)
  * @task: task to put to sleep
  *
  */
-static void xs_nospace(struct rpc_task *task)
+static int xs_nospace(struct rpc_task *task)
 {
        struct rpc_rqst *req = task->tk_rqstp;
        struct rpc_xprt *xprt = req->rq_xprt;
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+       int ret = 0;
 
        dprintk("RPC: %5u xmit incomplete (%u left of %u)\n",
                        task->tk_pid, req->rq_slen - req->rq_bytes_sent,
@@ -537,6 +549,7 @@ static void xs_nospace(struct rpc_task *task)
        /* Don't race with disconnect */
        if (xprt_connected(xprt)) {
                if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) {
+                       ret = -EAGAIN;
                        /*
                         * Notify TCP that we're limited by the application
                         * window size
@@ -548,10 +561,11 @@ static void xs_nospace(struct rpc_task *task)
                }
        } else {
                clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
-               task->tk_status = -ENOTCONN;
+               ret = -ENOTCONN;
        }
 
        spin_unlock_bh(&xprt->transport_lock);
+       return ret;
 }
 
 /**
@@ -594,6 +608,8 @@ static int xs_udp_send_request(struct rpc_task *task)
                /* Still some bytes left; set up for a retry later. */
                status = -EAGAIN;
        }
+       if (!transport->sock)
+               goto out;
 
        switch (status) {
        case -ENOTSOCK:
@@ -601,21 +617,19 @@ static int xs_udp_send_request(struct rpc_task *task)
                /* Should we call xs_close() here? */
                break;
        case -EAGAIN:
-               xs_nospace(task);
+               status = xs_nospace(task);
                break;
+       default:
+               dprintk("RPC:       sendmsg returned unrecognized error %d\n",
+                       -status);
        case -ENETUNREACH:
        case -EPIPE:
        case -ECONNREFUSED:
                /* When the server has died, an ICMP port unreachable message
                 * prompts ECONNREFUSED. */
                clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
-               break;
-       default:
-               clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
-               dprintk("RPC:       sendmsg returned unrecognized error %d\n",
-                       -status);
        }
-
+out:
        return status;
 }
 
@@ -697,6 +711,8 @@ static int xs_tcp_send_request(struct rpc_task *task)
                status = -EAGAIN;
                break;
        }
+       if (!transport->sock)
+               goto out;
 
        switch (status) {
        case -ENOTSOCK:
@@ -704,23 +720,19 @@ static int xs_tcp_send_request(struct rpc_task *task)
                /* Should we call xs_close() here? */
                break;
        case -EAGAIN:
-               xs_nospace(task);
+               status = xs_nospace(task);
                break;
+       default:
+               dprintk("RPC:       sendmsg returned unrecognized error %d\n",
+                       -status);
        case -ECONNRESET:
+       case -EPIPE:
                xs_tcp_shutdown(xprt);
        case -ECONNREFUSED:
        case -ENOTCONN:
-       case -EPIPE:
-               status = -ENOTCONN;
-               clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
-               break;
-       default:
-               dprintk("RPC:       sendmsg returned unrecognized error %d\n",
-                       -status);
                clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
-               xs_tcp_shutdown(xprt);
        }
-
+out:
        return status;
 }
 
@@ -767,23 +779,13 @@ static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *s
        sk->sk_error_report = transport->old_error_report;
 }
 
-/**
- * xs_close - close a socket
- * @xprt: transport
- *
- * This is used when all requests are complete; ie, no DRC state remains
- * on the server we want to save.
- */
-static void xs_close(struct rpc_xprt *xprt)
+static void xs_reset_transport(struct sock_xprt *transport)
 {
-       struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
        struct socket *sock = transport->sock;
        struct sock *sk = transport->inet;
 
-       if (!sk)
-               goto clear_close_wait;
-
-       dprintk("RPC:       xs_close xprt %p\n", xprt);
+       if (sk == NULL)
+               return;
 
        write_lock_bh(&sk->sk_callback_lock);
        transport->inet = NULL;
@@ -797,8 +799,25 @@ static void xs_close(struct rpc_xprt *xprt)
        sk->sk_no_check = 0;
 
        sock_release(sock);
-clear_close_wait:
+}
+
+/**
+ * xs_close - close a socket
+ * @xprt: transport
+ *
+ * This is used when all requests are complete; ie, no DRC state remains
+ * on the server we want to save.
+ */
+static void xs_close(struct rpc_xprt *xprt)
+{
+       struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+
+       dprintk("RPC:       xs_close xprt %p\n", xprt);
+
+       xs_reset_transport(transport);
+
        smp_mb__before_clear_bit();
+       clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
        clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
        clear_bit(XPRT_CLOSING, &xprt->state);
        smp_mb__after_clear_bit();
@@ -1126,6 +1145,47 @@ out:
        read_unlock(&sk->sk_callback_lock);
 }
 
+/*
+ * Do the equivalent of linger/linger2 handling for dealing with
+ * broken servers that don't close the socket in a timely
+ * fashion
+ */
+static void xs_tcp_schedule_linger_timeout(struct rpc_xprt *xprt,
+               unsigned long timeout)
+{
+       struct sock_xprt *transport;
+
+       if (xprt_test_and_set_connecting(xprt))
+               return;
+       set_bit(XPRT_CONNECTION_ABORT, &xprt->state);
+       transport = container_of(xprt, struct sock_xprt, xprt);
+       queue_delayed_work(rpciod_workqueue, &transport->connect_worker,
+                          timeout);
+}
+
+static void xs_tcp_cancel_linger_timeout(struct rpc_xprt *xprt)
+{
+       struct sock_xprt *transport;
+
+       transport = container_of(xprt, struct sock_xprt, xprt);
+
+       if (!test_bit(XPRT_CONNECTION_ABORT, &xprt->state) ||
+           !cancel_delayed_work(&transport->connect_worker))
+               return;
+       clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
+       xprt_clear_connecting(xprt);
+}
+
+static void xs_sock_mark_closed(struct rpc_xprt *xprt)
+{
+       smp_mb__before_clear_bit();
+       clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
+       clear_bit(XPRT_CLOSING, &xprt->state);
+       smp_mb__after_clear_bit();
+       /* Mark transport as closed and wake up all pending tasks */
+       xprt_disconnect_done(xprt);
+}
+
 /**
  * xs_tcp_state_change - callback to handle TCP socket state changes
  * @sk: socket whose state has changed
@@ -1158,7 +1218,7 @@ static void xs_tcp_state_change(struct sock *sk)
                        transport->tcp_flags =
                                TCP_RCV_COPY_FRAGHDR | TCP_RCV_COPY_XID;
 
-                       xprt_wake_pending_tasks(xprt, 0);
+                       xprt_wake_pending_tasks(xprt, -EAGAIN);
                }
                spin_unlock_bh(&xprt->transport_lock);
                break;
@@ -1171,10 +1231,10 @@ static void xs_tcp_state_change(struct sock *sk)
                clear_bit(XPRT_CONNECTED, &xprt->state);
                clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
                smp_mb__after_clear_bit();
+               xs_tcp_schedule_linger_timeout(xprt, xs_tcp_fin_timeout);
                break;
        case TCP_CLOSE_WAIT:
                /* The server initiated a shutdown of the socket */
-               set_bit(XPRT_CLOSING, &xprt->state);
                xprt_force_disconnect(xprt);
        case TCP_SYN_SENT:
                xprt->connect_cookie++;
@@ -1187,40 +1247,35 @@ static void xs_tcp_state_change(struct sock *sk)
                        xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
                break;
        case TCP_LAST_ACK:
+               set_bit(XPRT_CLOSING, &xprt->state);
+               xs_tcp_schedule_linger_timeout(xprt, xs_tcp_fin_timeout);
                smp_mb__before_clear_bit();
                clear_bit(XPRT_CONNECTED, &xprt->state);
                smp_mb__after_clear_bit();
                break;
        case TCP_CLOSE:
-               smp_mb__before_clear_bit();
-               clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
-               clear_bit(XPRT_CLOSING, &xprt->state);
-               smp_mb__after_clear_bit();
-               /* Mark transport as closed and wake up all pending tasks */
-               xprt_disconnect_done(xprt);
+               xs_tcp_cancel_linger_timeout(xprt);
+               xs_sock_mark_closed(xprt);
        }
  out:
        read_unlock(&sk->sk_callback_lock);
 }
 
 /**
- * xs_tcp_error_report - callback mainly for catching RST events
+ * xs_error_report - callback mainly for catching socket errors
  * @sk: socket
  */
-static void xs_tcp_error_report(struct sock *sk)
+static void xs_error_report(struct sock *sk)
 {
        struct rpc_xprt *xprt;
 
        read_lock(&sk->sk_callback_lock);
-       if (sk->sk_err != ECONNRESET || sk->sk_state != TCP_ESTABLISHED)
-               goto out;
        if (!(xprt = xprt_from_sock(sk)))
                goto out;
        dprintk("RPC:       %s client %p...\n"
                        "RPC:       error %d\n",
                        __func__, xprt, sk->sk_err);
-
-       xprt_force_disconnect(xprt);
+       xprt_wake_pending_tasks(xprt, -EAGAIN);
 out:
        read_unlock(&sk->sk_callback_lock);
 }
@@ -1494,6 +1549,7 @@ static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
                sk->sk_user_data = xprt;
                sk->sk_data_ready = xs_udp_data_ready;
                sk->sk_write_space = xs_udp_write_space;
+               sk->sk_error_report = xs_error_report;
                sk->sk_no_check = UDP_CSUM_NORCV;
                sk->sk_allocation = GFP_ATOMIC;
 
@@ -1526,9 +1582,10 @@ static void xs_udp_connect_worker4(struct work_struct *work)
                goto out;
 
        /* Start by resetting any existing state */
-       xs_close(xprt);
+       xs_reset_transport(transport);
 
-       if ((err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) {
+       err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
+       if (err < 0) {
                dprintk("RPC:       can't create UDP transport socket (%d).\n", -err);
                goto out;
        }
@@ -1545,8 +1602,8 @@ static void xs_udp_connect_worker4(struct work_struct *work)
        xs_udp_finish_connecting(xprt, sock);
        status = 0;
 out:
-       xprt_wake_pending_tasks(xprt, status);
        xprt_clear_connecting(xprt);
+       xprt_wake_pending_tasks(xprt, status);
 }
 
 /**
@@ -1567,9 +1624,10 @@ static void xs_udp_connect_worker6(struct work_struct *work)
                goto out;
 
        /* Start by resetting any existing state */
-       xs_close(xprt);
+       xs_reset_transport(transport);
 
-       if ((err = sock_create_kern(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) {
+       err = sock_create_kern(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock);
+       if (err < 0) {
                dprintk("RPC:       can't create UDP transport socket (%d).\n", -err);
                goto out;
        }
@@ -1586,18 +1644,17 @@ static void xs_udp_connect_worker6(struct work_struct *work)
        xs_udp_finish_connecting(xprt, sock);
        status = 0;
 out:
-       xprt_wake_pending_tasks(xprt, status);
        xprt_clear_connecting(xprt);
+       xprt_wake_pending_tasks(xprt, status);
 }
 
 /*
  * We need to preserve the port number so the reply cache on the server can
  * find our cached RPC replies when we get around to reconnecting.
  */
-static void xs_tcp_reuse_connection(struct rpc_xprt *xprt)
+static void xs_abort_connection(struct rpc_xprt *xprt, struct sock_xprt *transport)
 {
        int result;
-       struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
        struct sockaddr any;
 
        dprintk("RPC:       disconnecting xprt %p to reuse port\n", xprt);
@@ -1609,11 +1666,24 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt)
        memset(&any, 0, sizeof(any));
        any.sa_family = AF_UNSPEC;
        result = kernel_connect(transport->sock, &any, sizeof(any), 0);
-       if (result)
+       if (!result)
+               xs_sock_mark_closed(xprt);
+       else
                dprintk("RPC:       AF_UNSPEC connect return code %d\n",
                                result);
 }
 
+static void xs_tcp_reuse_connection(struct rpc_xprt *xprt, struct sock_xprt *transport)
+{
+       unsigned int state = transport->inet->sk_state;
+
+       if (state == TCP_CLOSE && transport->sock->state == SS_UNCONNECTED)
+               return;
+       if ((1 << state) & (TCPF_ESTABLISHED|TCPF_SYN_SENT))
+               return;
+       xs_abort_connection(xprt, transport);
+}
+
 static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
 {
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
@@ -1629,7 +1699,7 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
                sk->sk_data_ready = xs_tcp_data_ready;
                sk->sk_state_change = xs_tcp_state_change;
                sk->sk_write_space = xs_tcp_write_space;
-               sk->sk_error_report = xs_tcp_error_report;
+               sk->sk_error_report = xs_error_report;
                sk->sk_allocation = GFP_ATOMIC;
 
                /* socket options */
@@ -1657,37 +1727,42 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
 }
 
 /**
- * xs_tcp_connect_worker4 - connect a TCP socket to a remote endpoint
- * @work: RPC transport to connect
+ * xs_tcp_setup_socket - create a TCP socket and connect to a remote endpoint
+ * @xprt: RPC transport to connect
+ * @transport: socket transport to connect
+ * @create_sock: function to create a socket of the correct type
  *
  * Invoked by a work queue tasklet.
  */
-static void xs_tcp_connect_worker4(struct work_struct *work)
+static void xs_tcp_setup_socket(struct rpc_xprt *xprt,
+               struct sock_xprt *transport,
+               struct socket *(*create_sock)(struct rpc_xprt *,
+                       struct sock_xprt *))
 {
-       struct sock_xprt *transport =
-               container_of(work, struct sock_xprt, connect_worker.work);
-       struct rpc_xprt *xprt = &transport->xprt;
        struct socket *sock = transport->sock;
-       int err, status = -EIO;
+       int status = -EIO;
 
        if (xprt->shutdown)
                goto out;
 
        if (!sock) {
-               /* start from scratch */
-               if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
-                       dprintk("RPC:       can't create TCP transport socket (%d).\n", -err);
+               clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
+               sock = create_sock(xprt, transport);
+               if (IS_ERR(sock)) {
+                       status = PTR_ERR(sock);
                        goto out;
                }
-               xs_reclassify_socket4(sock);
+       } else {
+               int abort_and_exit;
 
-               if (xs_bind4(transport, sock) < 0) {
-                       sock_release(sock);
-                       goto out;
-               }
-       } else
+               abort_and_exit = test_and_clear_bit(XPRT_CONNECTION_ABORT,
+                               &xprt->state);
                /* "close" the socket, preserving the local port */
-               xs_tcp_reuse_connection(xprt);
+               xs_tcp_reuse_connection(xprt, transport);
+
+               if (abort_and_exit)
+                       goto out_eagain;
+       }
 
        dprintk("RPC:       worker connecting xprt %p to address: %s\n",
                        xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
@@ -1696,83 +1771,104 @@ static void xs_tcp_connect_worker4(struct work_struct *work)
        dprintk("RPC:       %p connect status %d connected %d sock state %d\n",
                        xprt, -status, xprt_connected(xprt),
                        sock->sk->sk_state);
-       if (status < 0) {
-               switch (status) {
-                       case -EINPROGRESS:
-                       case -EALREADY:
-                               goto out_clear;
-                       case -ECONNREFUSED:
-                       case -ECONNRESET:
-                               /* retry with existing socket, after a delay */
-                               break;
-                       default:
-                               /* get rid of existing socket, and retry */
-                               xs_tcp_shutdown(xprt);
-               }
+       switch (status) {
+       case -ECONNREFUSED:
+       case -ECONNRESET:
+       case -ENETUNREACH:
+               /* retry with existing socket, after a delay */
+       case 0:
+       case -EINPROGRESS:
+       case -EALREADY:
+               xprt_clear_connecting(xprt);
+               return;
        }
+       /* get rid of existing socket, and retry */
+       xs_tcp_shutdown(xprt);
+       printk("%s: connect returned unhandled error %d\n",
+                       __func__, status);
+out_eagain:
+       status = -EAGAIN;
 out:
-       xprt_wake_pending_tasks(xprt, status);
-out_clear:
        xprt_clear_connecting(xprt);
+       xprt_wake_pending_tasks(xprt, status);
+}
+
+static struct socket *xs_create_tcp_sock4(struct rpc_xprt *xprt,
+               struct sock_xprt *transport)
+{
+       struct socket *sock;
+       int err;
+
+       /* start from scratch */
+       err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
+       if (err < 0) {
+               dprintk("RPC:       can't create TCP transport socket (%d).\n",
+                               -err);
+               goto out_err;
+       }
+       xs_reclassify_socket4(sock);
+
+       if (xs_bind4(transport, sock) < 0) {
+               sock_release(sock);
+               goto out_err;
+       }
+       return sock;
+out_err:
+       return ERR_PTR(-EIO);
 }
 
 /**
- * xs_tcp_connect_worker6 - connect a TCP socket to a remote endpoint
+ * xs_tcp_connect_worker4 - connect a TCP socket to a remote endpoint
  * @work: RPC transport to connect
  *
  * Invoked by a work queue tasklet.
  */
-static void xs_tcp_connect_worker6(struct work_struct *work)
+static void xs_tcp_connect_worker4(struct work_struct *work)
 {
        struct sock_xprt *transport =
                container_of(work, struct sock_xprt, connect_worker.work);
        struct rpc_xprt *xprt = &transport->xprt;
-       struct socket *sock = transport->sock;
-       int err, status = -EIO;
 
-       if (xprt->shutdown)
-               goto out;
+       xs_tcp_setup_socket(xprt, transport, xs_create_tcp_sock4);
+}
 
-       if (!sock) {
-               /* start from scratch */
-               if ((err = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
-                       dprintk("RPC:       can't create TCP transport socket (%d).\n", -err);
-                       goto out;
-               }
-               xs_reclassify_socket6(sock);
+static struct socket *xs_create_tcp_sock6(struct rpc_xprt *xprt,
+               struct sock_xprt *transport)
+{
+       struct socket *sock;
+       int err;
+
+       /* start from scratch */
+       err = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &sock);
+       if (err < 0) {
+               dprintk("RPC:       can't create TCP transport socket (%d).\n",
+                               -err);
+               goto out_err;
+       }
+       xs_reclassify_socket6(sock);
 
-               if (xs_bind6(transport, sock) < 0) {
-                       sock_release(sock);
-                       goto out;
-               }
-       } else
-               /* "close" the socket, preserving the local port */
-               xs_tcp_reuse_connection(xprt);
+       if (xs_bind6(transport, sock) < 0) {
+               sock_release(sock);
+               goto out_err;
+       }
+       return sock;
+out_err:
+       return ERR_PTR(-EIO);
+}
 
-       dprintk("RPC:       worker connecting xprt %p to address: %s\n",
-                       xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
+/**
+ * xs_tcp_connect_worker6 - connect a TCP socket to a remote endpoint
+ * @work: RPC transport to connect
+ *
+ * Invoked by a work queue tasklet.
+ */
+static void xs_tcp_connect_worker6(struct work_struct *work)
+{
+       struct sock_xprt *transport =
+               container_of(work, struct sock_xprt, connect_worker.work);
+       struct rpc_xprt *xprt = &transport->xprt;
 
-       status = xs_tcp_finish_connecting(xprt, sock);
-       dprintk("RPC:       %p connect status %d connected %d sock state %d\n",
-                       xprt, -status, xprt_connected(xprt), sock->sk->sk_state);
-       if (status < 0) {
-               switch (status) {
-                       case -EINPROGRESS:
-                       case -EALREADY:
-                               goto out_clear;
-                       case -ECONNREFUSED:
-                       case -ECONNRESET:
-                               /* retry with existing socket, after a delay */
-                               break;
-                       default:
-                               /* get rid of existing socket, and retry */
-                               xs_tcp_shutdown(xprt);
-               }
-       }
-out:
-       xprt_wake_pending_tasks(xprt, status);
-out_clear:
-       xprt_clear_connecting(xprt);
+       xs_tcp_setup_socket(xprt, transport, xs_create_tcp_sock6);
 }
 
 /**
@@ -1817,9 +1913,6 @@ static void xs_tcp_connect(struct rpc_task *task)
 {
        struct rpc_xprt *xprt = task->tk_xprt;
 
-       /* Initiate graceful shutdown of the socket if not already done */
-       if (test_bit(XPRT_CONNECTED, &xprt->state))
-               xs_tcp_shutdown(xprt);
        /* Exit if we need to wait for socket shutdown to complete */
        if (test_bit(XPRT_CLOSING, &xprt->state))
                return;
index c545bd1300b5f77d0278be05b546297141251d5d..21b6cead6a8ed38927abab1bd8cd9c491194c1bf 100644 (file)
@@ -620,10 +620,6 @@ static int cap_socket_accept(struct socket *sock, struct socket *newsock)
        return 0;
 }
 
-static void cap_socket_post_accept(struct socket *sock, struct socket *newsock)
-{
-}
-
 static int cap_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
 {
        return 0;
@@ -1014,7 +1010,6 @@ void security_fixup_ops(struct security_operations *ops)
        set_to_cap_if_null(ops, socket_connect);
        set_to_cap_if_null(ops, socket_listen);
        set_to_cap_if_null(ops, socket_accept);
-       set_to_cap_if_null(ops, socket_post_accept);
        set_to_cap_if_null(ops, socket_sendmsg);
        set_to_cap_if_null(ops, socket_recvmsg);
        set_to_cap_if_null(ops, socket_getsockname);
index 3aacd0fe7179b26a4e08bc7bce343dd7fbadc239..5fda7df197237854c8a4fa5f4d8ff9d9ce27f232 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/uaccess.h>
 #include <linux/seq_file.h>
 #include <linux/rcupdate.h>
+#include <linux/mutex.h>
 
 #define ACC_MKNOD 1
 #define ACC_READ  2
 #define DEV_CHAR  2
 #define DEV_ALL   4  /* this represents all devices */
 
+static DEFINE_MUTEX(devcgroup_mutex);
+
 /*
  * whitelist locking rules:
- * hold cgroup_lock() for update/read.
+ * hold devcgroup_mutex for update/read.
  * hold rcu_read_lock() for read.
  */
 
@@ -67,7 +70,7 @@ static int devcgroup_can_attach(struct cgroup_subsys *ss,
 }
 
 /*
- * called under cgroup_lock()
+ * called under devcgroup_mutex
  */
 static int dev_whitelist_copy(struct list_head *dest, struct list_head *orig)
 {
@@ -92,7 +95,7 @@ free_and_exit:
 
 /* Stupid prototype - don't bother combining existing entries */
 /*
- * called under cgroup_lock()
+ * called under devcgroup_mutex
  */
 static int dev_whitelist_add(struct dev_cgroup *dev_cgroup,
                        struct dev_whitelist_item *wh)
@@ -130,7 +133,7 @@ static void whitelist_item_free(struct rcu_head *rcu)
 }
 
 /*
- * called under cgroup_lock()
+ * called under devcgroup_mutex
  */
 static void dev_whitelist_rm(struct dev_cgroup *dev_cgroup,
                        struct dev_whitelist_item *wh)
@@ -185,8 +188,10 @@ static struct cgroup_subsys_state *devcgroup_create(struct cgroup_subsys *ss,
                list_add(&wh->list, &dev_cgroup->whitelist);
        } else {
                parent_dev_cgroup = cgroup_to_devcgroup(parent_cgroup);
+               mutex_lock(&devcgroup_mutex);
                ret = dev_whitelist_copy(&dev_cgroup->whitelist,
                                &parent_dev_cgroup->whitelist);
+               mutex_unlock(&devcgroup_mutex);
                if (ret) {
                        kfree(dev_cgroup);
                        return ERR_PTR(ret);
@@ -273,7 +278,7 @@ static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft,
  * does the access granted to dev_cgroup c contain the access
  * requested in whitelist item refwh.
  * return 1 if yes, 0 if no.
- * call with c->lock held
+ * call with devcgroup_mutex held
  */
 static int may_access_whitelist(struct dev_cgroup *c,
                                       struct dev_whitelist_item *refwh)
@@ -426,11 +431,11 @@ static int devcgroup_access_write(struct cgroup *cgrp, struct cftype *cft,
                                  const char *buffer)
 {
        int retval;
-       if (!cgroup_lock_live_group(cgrp))
-               return -ENODEV;
+
+       mutex_lock(&devcgroup_mutex);
        retval = devcgroup_update_access(cgroup_to_devcgroup(cgrp),
                                         cft->private, buffer);
-       cgroup_unlock();
+       mutex_unlock(&devcgroup_mutex);
        return retval;
 }
 
index c3586c0d97e2f17c672d1f2cfec8584b580ed5e6..206e53844d2f86b5658d9524b0af9d83ddd41c05 100644 (file)
@@ -1007,11 +1007,6 @@ int security_socket_accept(struct socket *sock, struct socket *newsock)
        return security_ops->socket_accept(sock, newsock);
 }
 
-void security_socket_post_accept(struct socket *sock, struct socket *newsock)
-{
-       security_ops->socket_post_accept(sock, newsock);
-}
-
 int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
 {
        return security_ops->socket_sendmsg(sock, msg, size);
index 7c52ba243c6490acf9d22f719763a3931fbaabfb..ba808ef6babb58799f615aa4ec615824cfb20f66 100644 (file)
@@ -93,7 +93,6 @@
 
 extern unsigned int policydb_loaded_version;
 extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
-extern int selinux_compat_net;
 extern struct security_operations *security_ops;
 
 /* SECMARK reference count */
@@ -311,7 +310,7 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
        ssec->sid = SECINITSID_UNLABELED;
        sk->sk_security = ssec;
 
-       selinux_netlbl_sk_security_reset(ssec, family);
+       selinux_netlbl_sk_security_reset(ssec);
 
        return 0;
 }
@@ -2945,7 +2944,6 @@ static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
 static int selinux_revalidate_file_permission(struct file *file, int mask)
 {
        const struct cred *cred = current_cred();
-       int rc;
        struct inode *inode = file->f_path.dentry->d_inode;
 
        if (!mask) {
@@ -2957,29 +2955,15 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
        if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
                mask |= MAY_APPEND;
 
-       rc = file_has_perm(cred, file,
-                          file_mask_to_av(inode->i_mode, mask));
-       if (rc)
-               return rc;
-
-       return selinux_netlbl_inode_permission(inode, mask);
+       return file_has_perm(cred, file,
+                            file_mask_to_av(inode->i_mode, mask));
 }
 
 static int selinux_file_permission(struct file *file, int mask)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
-       struct file_security_struct *fsec = file->f_security;
-       struct inode_security_struct *isec = inode->i_security;
-       u32 sid = current_sid();
-
-       if (!mask) {
+       if (!mask)
                /* No permission to check.  Existence test. */
                return 0;
-       }
-
-       if (sid == fsec->sid && fsec->isid == isec->sid
-           && fsec->pseqno == avc_policy_seqno())
-               return selinux_netlbl_inode_permission(inode, mask);
 
        return selinux_revalidate_file_permission(file, mask);
 }
@@ -3723,7 +3707,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
                sksec = sock->sk->sk_security;
                sksec->sid = isec->sid;
                sksec->sclass = isec->sclass;
-               err = selinux_netlbl_socket_post_create(sock);
+               err = selinux_netlbl_socket_post_create(sock->sk, family);
        }
 
        return err;
@@ -3914,13 +3898,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
 static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
                                  int size)
 {
-       int rc;
-
-       rc = socket_has_perm(current, sock, SOCKET__WRITE);
-       if (rc)
-               return rc;
-
-       return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
+       return socket_has_perm(current, sock, SOCKET__WRITE);
 }
 
 static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
@@ -4040,72 +4018,6 @@ static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
                            SECCLASS_NODE, NODE__RECVFROM, ad);
 }
 
-static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
-                                               struct sk_buff *skb,
-                                               struct avc_audit_data *ad,
-                                               u16 family,
-                                               char *addrp)
-{
-       int err;
-       struct sk_security_struct *sksec = sk->sk_security;
-       u16 sk_class;
-       u32 netif_perm, node_perm, recv_perm;
-       u32 port_sid, node_sid, if_sid, sk_sid;
-
-       sk_sid = sksec->sid;
-       sk_class = sksec->sclass;
-
-       switch (sk_class) {
-       case SECCLASS_UDP_SOCKET:
-               netif_perm = NETIF__UDP_RECV;
-               node_perm = NODE__UDP_RECV;
-               recv_perm = UDP_SOCKET__RECV_MSG;
-               break;
-       case SECCLASS_TCP_SOCKET:
-               netif_perm = NETIF__TCP_RECV;
-               node_perm = NODE__TCP_RECV;
-               recv_perm = TCP_SOCKET__RECV_MSG;
-               break;
-       case SECCLASS_DCCP_SOCKET:
-               netif_perm = NETIF__DCCP_RECV;
-               node_perm = NODE__DCCP_RECV;
-               recv_perm = DCCP_SOCKET__RECV_MSG;
-               break;
-       default:
-               netif_perm = NETIF__RAWIP_RECV;
-               node_perm = NODE__RAWIP_RECV;
-               recv_perm = 0;
-               break;
-       }
-
-       err = sel_netif_sid(skb->iif, &if_sid);
-       if (err)
-               return err;
-       err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
-       if (err)
-               return err;
-
-       err = sel_netnode_sid(addrp, family, &node_sid);
-       if (err)
-               return err;
-       err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
-       if (err)
-               return err;
-
-       if (!recv_perm)
-               return 0;
-       err = sel_netport_sid(sk->sk_protocol,
-                             ntohs(ad->u.net.sport), &port_sid);
-       if (unlikely(err)) {
-               printk(KERN_WARNING
-                      "SELinux: failure in"
-                      " selinux_sock_rcv_skb_iptables_compat(),"
-                      " network port label not found\n");
-               return err;
-       }
-       return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad);
-}
-
 static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
                                       u16 family)
 {
@@ -4123,14 +4035,12 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
        if (err)
                return err;
 
-       if (selinux_compat_net)
-               err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
-                                                          family, addrp);
-       else if (selinux_secmark_enabled())
+       if (selinux_secmark_enabled()) {
                err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
                                   PACKET__RECV, &ad);
-       if (err)
-               return err;
+               if (err)
+                       return err;
+       }
 
        if (selinux_policycap_netpeer) {
                err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
@@ -4172,7 +4082,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
         * to the selinux_sock_rcv_skb_compat() function to deal with the
         * special handling.  We do this in an attempt to keep this function
         * as fast and as clean as possible. */
-       if (selinux_compat_net || !selinux_policycap_netpeer)
+       if (!selinux_policycap_netpeer)
                return selinux_sock_rcv_skb_compat(sk, skb, family);
 
        secmark_active = selinux_secmark_enabled();
@@ -4304,7 +4214,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
        newssec->peer_sid = ssec->peer_sid;
        newssec->sclass = ssec->sclass;
 
-       selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
+       selinux_netlbl_sk_security_reset(newssec);
 }
 
 static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
@@ -4348,16 +4258,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
        if (peersid == SECSID_NULL) {
                req->secid = sksec->sid;
                req->peer_secid = SECSID_NULL;
-               return 0;
+       } else {
+               err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
+               if (err)
+                       return err;
+               req->secid = newsid;
+               req->peer_secid = peersid;
        }
 
-       err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
-       if (err)
-               return err;
-
-       req->secid = newsid;
-       req->peer_secid = peersid;
-       return 0;
+       return selinux_netlbl_inet_conn_request(req, family);
 }
 
 static void selinux_inet_csk_clone(struct sock *newsk,
@@ -4374,7 +4283,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
 
        /* We don't need to take any sort of lock here as we are the only
         * thread with access to newsksec */
-       selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
+       selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
 }
 
 static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
@@ -4387,8 +4296,6 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
                family = PF_INET;
 
        selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
-
-       selinux_netlbl_inet_conn_established(sk, family);
 }
 
 static void selinux_req_classify_flow(const struct request_sock *req,
@@ -4540,71 +4447,6 @@ static unsigned int selinux_ipv4_output(unsigned int hooknum,
        return selinux_ip_output(skb, PF_INET);
 }
 
-static int selinux_ip_postroute_iptables_compat(struct sock *sk,
-                                               int ifindex,
-                                               struct avc_audit_data *ad,
-                                               u16 family, char *addrp)
-{
-       int err;
-       struct sk_security_struct *sksec = sk->sk_security;
-       u16 sk_class;
-       u32 netif_perm, node_perm, send_perm;
-       u32 port_sid, node_sid, if_sid, sk_sid;
-
-       sk_sid = sksec->sid;
-       sk_class = sksec->sclass;
-
-       switch (sk_class) {
-       case SECCLASS_UDP_SOCKET:
-               netif_perm = NETIF__UDP_SEND;
-               node_perm = NODE__UDP_SEND;
-               send_perm = UDP_SOCKET__SEND_MSG;
-               break;
-       case SECCLASS_TCP_SOCKET:
-               netif_perm = NETIF__TCP_SEND;
-               node_perm = NODE__TCP_SEND;
-               send_perm = TCP_SOCKET__SEND_MSG;
-               break;
-       case SECCLASS_DCCP_SOCKET:
-               netif_perm = NETIF__DCCP_SEND;
-               node_perm = NODE__DCCP_SEND;
-               send_perm = DCCP_SOCKET__SEND_MSG;
-               break;
-       default:
-               netif_perm = NETIF__RAWIP_SEND;
-               node_perm = NODE__RAWIP_SEND;
-               send_perm = 0;
-               break;
-       }
-
-       err = sel_netif_sid(ifindex, &if_sid);
-       if (err)
-               return err;
-       err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
-               return err;
-
-       err = sel_netnode_sid(addrp, family, &node_sid);
-       if (err)
-               return err;
-       err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
-       if (err)
-               return err;
-
-       if (send_perm != 0)
-               return 0;
-
-       err = sel_netport_sid(sk->sk_protocol,
-                             ntohs(ad->u.net.dport), &port_sid);
-       if (unlikely(err)) {
-               printk(KERN_WARNING
-                      "SELinux: failure in"
-                      " selinux_ip_postroute_iptables_compat(),"
-                      " network port label not found\n");
-               return err;
-       }
-       return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
-}
-
 static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
                                                int ifindex,
                                                u16 family)
@@ -4625,15 +4467,10 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
        if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
                return NF_DROP;
 
-       if (selinux_compat_net) {
-               if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
-                                                        &ad, family, addrp))
-                       return NF_DROP;
-       } else if (selinux_secmark_enabled()) {
+       if (selinux_secmark_enabled())
                if (avc_has_perm(sksec->sid, skb->secmark,
                                 SECCLASS_PACKET, PACKET__SEND, &ad))
                        return NF_DROP;
-       }
 
        if (selinux_policycap_netpeer)
                if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
@@ -4657,7 +4494,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
         * to the selinux_ip_postroute_compat() function to deal with the
         * special handling.  We do this in an attempt to keep this function
         * as fast and as clean as possible. */
-       if (selinux_compat_net || !selinux_policycap_netpeer)
+       if (!selinux_policycap_netpeer)
                return selinux_ip_postroute_compat(skb, ifindex, family);
 #ifdef CONFIG_XFRM
        /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
index b913c8d060386728bfe0bc68441a56b4ad3f012f..b4b5b9b2f0be1758babefede244375e604b08ccb 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/net.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
+#include <net/request_sock.h>
 
 #include "avc.h"
 #include "objsec.h"
@@ -42,8 +43,7 @@ void selinux_netlbl_cache_invalidate(void);
 void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway);
 
 void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec);
-void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
-                                     int family);
+void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec);
 
 int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
                                 u16 family,
@@ -53,9 +53,9 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
                                 u16 family,
                                 u32 sid);
 
-void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family);
-int selinux_netlbl_socket_post_create(struct socket *sock);
-int selinux_netlbl_inode_permission(struct inode *inode, int mask);
+int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family);
+void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family);
+int selinux_netlbl_socket_post_create(struct sock *sk, u16 family);
 int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
                                struct sk_buff *skb,
                                u16 family,
@@ -85,8 +85,7 @@ static inline void selinux_netlbl_sk_security_free(
 }
 
 static inline void selinux_netlbl_sk_security_reset(
-                                              struct sk_security_struct *ssec,
-                                              int family)
+                                              struct sk_security_struct *ssec)
 {
        return;
 }
@@ -113,17 +112,17 @@ static inline int selinux_netlbl_conn_setsid(struct sock *sk,
        return 0;
 }
 
-static inline void selinux_netlbl_inet_conn_established(struct sock *sk,
-                                                       u16 family)
+static inline int selinux_netlbl_inet_conn_request(struct request_sock *req,
+                                                  u16 family)
 {
-       return;
+       return 0;
 }
-static inline int selinux_netlbl_socket_post_create(struct socket *sock)
+static inline void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
 {
-       return 0;
+       return;
 }
-static inline int selinux_netlbl_inode_permission(struct inode *inode,
-                                                 int mask)
+static inline int selinux_netlbl_socket_post_create(struct sock *sk,
+                                                   u16 family)
 {
        return 0;
 }
index 350794ab9b4212d7e50b07f3c778bb42bb81aa3a..2e984413c7b2daaa5313e7bf8fa1b3b193064252 100644 (file)
@@ -99,41 +99,6 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
        return secattr;
 }
 
-/**
- * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
- * @sk: the socket to label
- *
- * Description:
- * Attempt to label a socket using the NetLabel mechanism.  Returns zero values
- * on success, negative values on failure.
- *
- */
-static int selinux_netlbl_sock_setsid(struct sock *sk)
-{
-       int rc;
-       struct sk_security_struct *sksec = sk->sk_security;
-       struct netlbl_lsm_secattr *secattr;
-
-       if (sksec->nlbl_state != NLBL_REQUIRE)
-               return 0;
-
-       secattr = selinux_netlbl_sock_genattr(sk);
-       if (secattr == NULL)
-               return -ENOMEM;
-       rc = netlbl_sock_setattr(sk, secattr);
-       switch (rc) {
-       case 0:
-               sksec->nlbl_state = NLBL_LABELED;
-               break;
-       case -EDESTADDRREQ:
-               sksec->nlbl_state = NLBL_REQSKB;
-               rc = 0;
-               break;
-       }
-
-       return rc;
-}
-
 /**
  * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
  *
@@ -188,13 +153,9 @@ void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec)
  * The caller is responsibile for all the NetLabel sk_security_struct locking.
  *
  */
-void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
-                                     int family)
+void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec)
 {
-       if (family == PF_INET)
-               ssec->nlbl_state = NLBL_REQUIRE;
-       else
-               ssec->nlbl_state = NLBL_UNSET;
+       ssec->nlbl_state = NLBL_UNSET;
 }
 
 /**
@@ -281,127 +242,86 @@ skbuff_setsid_return:
 }
 
 /**
- * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection
- * @sk: the new connection
+ * selinux_netlbl_inet_conn_request - Label an incoming stream connection
+ * @req: incoming connection request socket
  *
  * Description:
- * A new connection has been established on @sk so make sure it is labeled
- * correctly with the NetLabel susbsystem.
+ * A new incoming connection request is represented by @req, we need to label
+ * the new request_sock here and the stack will ensure the on-the-wire label
+ * will get preserved when a full sock is created once the connection handshake
+ * is complete.  Returns zero on success, negative values on failure.
  *
  */
-void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family)
+int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
 {
        int rc;
-       struct sk_security_struct *sksec = sk->sk_security;
-       struct netlbl_lsm_secattr *secattr;
-       struct inet_sock *sk_inet = inet_sk(sk);
-       struct sockaddr_in addr;
-
-       if (sksec->nlbl_state != NLBL_REQUIRE)
-               return;
+       struct netlbl_lsm_secattr secattr;
 
-       secattr = selinux_netlbl_sock_genattr(sk);
-       if (secattr == NULL)
-               return;
+       if (family != PF_INET)
+               return 0;
 
-       rc = netlbl_sock_setattr(sk, secattr);
-       switch (rc) {
-       case 0:
-               sksec->nlbl_state = NLBL_LABELED;
-               break;
-       case -EDESTADDRREQ:
-               /* no PF_INET6 support yet because we don't support any IPv6
-                * labeling protocols */
-               if (family != PF_INET) {
-                       sksec->nlbl_state = NLBL_UNSET;
-                       return;
-               }
-
-               addr.sin_family = family;
-               addr.sin_addr.s_addr = sk_inet->daddr;
-               if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr,
-                                       secattr) != 0) {
-                       /* we failed to label the connected socket (could be
-                        * for a variety of reasons, the actual "why" isn't
-                        * important here) so we have to go to our backup plan,
-                        * labeling the packets individually in the netfilter
-                        * local output hook.  this is okay but we need to
-                        * adjust the MSS of the connection to take into
-                        * account any labeling overhead, since we don't know
-                        * the exact overhead at this point we'll use the worst
-                        * case value which is 40 bytes for IPv4 */
-                       struct inet_connection_sock *sk_conn = inet_csk(sk);
-                       sk_conn->icsk_ext_hdr_len += 40 -
-                                     (sk_inet->opt ? sk_inet->opt->optlen : 0);
-                       sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
-
-                       sksec->nlbl_state = NLBL_REQSKB;
-               } else
-                       sksec->nlbl_state = NLBL_CONNLABELED;
-               break;
-       default:
-               /* note that we are failing to label the socket which could be
-                * a bad thing since it means traffic could leave the system
-                * without the desired labeling, however, all is not lost as
-                * we have a check in selinux_netlbl_inode_permission() to
-                * pick up the pieces that we might drop here because we can't
-                * return an error code */
-               break;
-       }
+       netlbl_secattr_init(&secattr);
+       rc = security_netlbl_sid_to_secattr(req->secid, &secattr);
+       if (rc != 0)
+               goto inet_conn_request_return;
+       rc = netlbl_req_setattr(req, &secattr);
+inet_conn_request_return:
+       netlbl_secattr_destroy(&secattr);
+       return rc;
 }
 
 /**
- * selinux_netlbl_socket_post_create - Label a socket using NetLabel
- * @sock: the socket to label
+ * selinux_netlbl_inet_csk_clone - Initialize the newly created sock
+ * @sk: the new sock
  *
  * Description:
- * Attempt to label a socket using the NetLabel mechanism using the given
- * SID.  Returns zero values on success, negative values on failure.
+ * A new connection has been established using @sk, we've already labeled the
+ * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but
+ * we need to set the NetLabel state here since we now have a sock structure.
  *
  */
-int selinux_netlbl_socket_post_create(struct socket *sock)
+void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
 {
-       return selinux_netlbl_sock_setsid(sock->sk);
+       struct sk_security_struct *sksec = sk->sk_security;
+
+       if (family == PF_INET)
+               sksec->nlbl_state = NLBL_LABELED;
+       else
+               sksec->nlbl_state = NLBL_UNSET;
 }
 
 /**
- * selinux_netlbl_inode_permission - Verify the socket is NetLabel labeled
- * @inode: the file descriptor's inode
- * @mask: the permission mask
+ * selinux_netlbl_socket_post_create - Label a socket using NetLabel
+ * @sock: the socket to label
+ * @family: protocol family
  *
  * Description:
- * Looks at a file's inode and if it is marked as a socket protected by
- * NetLabel then verify that the socket has been labeled, if not try to label
- * the socket now with the inode's SID.  Returns zero on success, negative
- * values on failure.
+ * Attempt to label a socket using the NetLabel mechanism using the given
+ * SID.  Returns zero values on success, negative values on failure.
  *
  */
-int selinux_netlbl_inode_permission(struct inode *inode, int mask)
+int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
 {
        int rc;
-       struct sock *sk;
-       struct socket *sock;
-       struct sk_security_struct *sksec;
+       struct sk_security_struct *sksec = sk->sk_security;
+       struct netlbl_lsm_secattr *secattr;
 
-       if (!S_ISSOCK(inode->i_mode) ||
-           ((mask & (MAY_WRITE | MAY_APPEND)) == 0))
-               return 0;
-       sock = SOCKET_I(inode);
-       sk = sock->sk;
-       if (sk == NULL)
-               return 0;
-       sksec = sk->sk_security;
-       if (sksec == NULL || sksec->nlbl_state != NLBL_REQUIRE)
+       if (family != PF_INET)
                return 0;
 
-       local_bh_disable();
-       bh_lock_sock_nested(sk);
-       if (likely(sksec->nlbl_state == NLBL_REQUIRE))
-               rc = selinux_netlbl_sock_setsid(sk);
-       else
+       secattr = selinux_netlbl_sock_genattr(sk);
+       if (secattr == NULL)
+               return -ENOMEM;
+       rc = netlbl_sock_setattr(sk, family, secattr);
+       switch (rc) {
+       case 0:
+               sksec->nlbl_state = NLBL_LABELED;
+               break;
+       case -EDESTADDRREQ:
+               sksec->nlbl_state = NLBL_REQSKB;
                rc = 0;
-       bh_unlock_sock(sk);
-       local_bh_enable();
+               break;
+       }
 
        return rc;
 }
index d3c8b982cfb0e179cb11d130318f3ebf3fd5b50d..2d5136ec3d5451c945f89e59b2f9ea4433bfa6a4 100644 (file)
@@ -47,8 +47,6 @@ static char *policycap_names[] = {
 
 unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
 
-int selinux_compat_net = 0;
-
 static int __init checkreqprot_setup(char *str)
 {
        unsigned long checkreqprot;
@@ -58,16 +56,6 @@ static int __init checkreqprot_setup(char *str)
 }
 __setup("checkreqprot=", checkreqprot_setup);
 
-static int __init selinux_compat_net_setup(char *str)
-{
-       unsigned long compat_net;
-       if (!strict_strtoul(str, 0, &compat_net))
-               selinux_compat_net = compat_net ? 1 : 0;
-       return 1;
-}
-__setup("selinux_compat_net=", selinux_compat_net_setup);
-
-
 static DEFINE_MUTEX(sel_mutex);
 
 /* global data for booleans */
@@ -450,61 +438,6 @@ static const struct file_operations sel_checkreqprot_ops = {
        .write          = sel_write_checkreqprot,
 };
 
-static ssize_t sel_read_compat_net(struct file *filp, char __user *buf,
-                                  size_t count, loff_t *ppos)
-{
-       char tmpbuf[TMPBUFLEN];
-       ssize_t length;
-
-       length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_compat_net);
-       return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
-}
-
-static ssize_t sel_write_compat_net(struct file *file, const char __user *buf,
-                                   size_t count, loff_t *ppos)
-{
-       char *page;
-       ssize_t length;
-       int new_value;
-
-       length = task_has_security(current, SECURITY__LOAD_POLICY);
-       if (length)
-               return length;
-
-       if (count >= PAGE_SIZE)
-               return -ENOMEM;
-       if (*ppos != 0) {
-               /* No partial writes. */
-               return -EINVAL;
-       }
-       page = (char *)get_zeroed_page(GFP_KERNEL);
-       if (!page)
-               return -ENOMEM;
-       length = -EFAULT;
-       if (copy_from_user(page, buf, count))
-               goto out;
-
-       length = -EINVAL;
-       if (sscanf(page, "%d", &new_value) != 1)
-               goto out;
-
-       if (new_value) {
-               printk(KERN_NOTICE
-                      "SELinux: compat_net is deprecated, please use secmark"
-                      " instead\n");
-               selinux_compat_net = 1;
-       } else
-               selinux_compat_net = 0;
-       length = count;
-out:
-       free_page((unsigned long) page);
-       return length;
-}
-static const struct file_operations sel_compat_net_ops = {
-       .read           = sel_read_compat_net,
-       .write          = sel_write_compat_net,
-};
-
 /*
  * Remaining nodes use transaction based IO methods like nfsd/nfsctl.c
  */
@@ -1665,7 +1598,6 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
                [SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR},
                [SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO},
                [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR},
-               [SEL_COMPAT_NET] = {"compat_net", &sel_compat_net_ops, S_IRUGO|S_IWUSR},
                [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
                [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
                /* last one */ {""}
index b79582e4fbfd6e82dc2679890731953f5ba1926f..42ef313f98560451b2b45d563d1f5e26e23ca795 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/security.h>
 #include <linux/in.h>
 #include <net/netlabel.h>
+#include <linux/list.h>
+#include <linux/rculist.h>
 
 /*
  * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
@@ -40,7 +42,6 @@ struct superblock_smack {
 struct socket_smack {
        char            *smk_out;                       /* outbound label */
        char            *smk_in;                        /* inbound label */
-       int             smk_labeled;                    /* label scheme */
        char            smk_packet[SMK_LABELLEN];       /* TCP peer label */
 };
 
@@ -59,17 +60,10 @@ struct inode_smack {
  * A label access rule.
  */
 struct smack_rule {
-       char    *smk_subject;
-       char    *smk_object;
-       int     smk_access;
-};
-
-/*
- * An entry in the table of permitted label accesses.
- */
-struct smk_list_entry {
-       struct smk_list_entry   *smk_next;
-       struct smack_rule       smk_rule;
+       struct list_head        list;
+       char                    *smk_subject;
+       char                    *smk_object;
+       int                     smk_access;
 };
 
 /*
@@ -85,7 +79,7 @@ struct smack_cipso {
  * An entry in the table identifying hosts.
  */
 struct smk_netlbladdr {
-       struct smk_netlbladdr   *smk_next;
+       struct list_head        list;
        struct sockaddr_in      smk_host;       /* network address */
        struct in_addr          smk_mask;       /* network mask */
        char                    *smk_label;     /* label */
@@ -113,7 +107,7 @@ struct smk_netlbladdr {
  * the cipso direct mapping in used internally.
  */
 struct smack_known {
-       struct smack_known      *smk_next;
+       struct list_head        list;
        char                    smk_known[SMK_LABELLEN];
        u32                     smk_secid;
        struct smack_cipso      *smk_cipso;
@@ -138,6 +132,8 @@ struct smack_known {
 #define XATTR_NAME_SMACKIPIN   XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
 #define XATTR_NAME_SMACKIPOUT  XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
 
+#define SMACK_CIPSO_OPTION     "-CIPSO"
+
 /*
  * How communications on this socket are treated.
  * Usually it's determined by the underlying netlabel code
@@ -205,8 +201,8 @@ u32 smack_to_secid(const char *);
 extern int smack_cipso_direct;
 extern char *smack_net_ambient;
 extern char *smack_onlycap;
+extern const char *smack_cipso_option;
 
-extern struct smack_known *smack_known;
 extern struct smack_known smack_known_floor;
 extern struct smack_known smack_known_hat;
 extern struct smack_known smack_known_huh;
@@ -214,8 +210,10 @@ extern struct smack_known smack_known_invalid;
 extern struct smack_known smack_known_star;
 extern struct smack_known smack_known_web;
 
-extern struct smk_list_entry *smack_list;
-extern struct smk_netlbladdr *smack_netlbladdrs;
+extern struct list_head smack_known_list;
+extern struct list_head smack_rule_list;
+extern struct list_head smk_netlbladdr_list;
+
 extern struct security_operations smack_ops;
 
 /*
index cfa19ca125e3596ed2b80b3bb0d2a0f05a594903..ac0a2707f6d41583e9e325819ab2265483320853 100644 (file)
 #include "smack.h"
 
 struct smack_known smack_known_huh = {
-       .smk_next       = NULL,
        .smk_known      = "?",
        .smk_secid      = 2,
        .smk_cipso      = NULL,
 };
 
 struct smack_known smack_known_hat = {
-       .smk_next       = &smack_known_huh,
        .smk_known      = "^",
        .smk_secid      = 3,
        .smk_cipso      = NULL,
 };
 
 struct smack_known smack_known_star = {
-       .smk_next       = &smack_known_hat,
        .smk_known      = "*",
        .smk_secid      = 4,
        .smk_cipso      = NULL,
 };
 
 struct smack_known smack_known_floor = {
-       .smk_next       = &smack_known_star,
        .smk_known      = "_",
        .smk_secid      = 5,
        .smk_cipso      = NULL,
 };
 
 struct smack_known smack_known_invalid = {
-       .smk_next       = &smack_known_floor,
        .smk_known      = "",
        .smk_secid      = 6,
        .smk_cipso      = NULL,
 };
 
 struct smack_known smack_known_web = {
-       .smk_next       = &smack_known_invalid,
        .smk_known      = "@",
        .smk_secid      = 7,
        .smk_cipso      = NULL,
 };
 
-struct smack_known *smack_known = &smack_known_web;
+LIST_HEAD(smack_known_list);
 
 /*
  * The initial value needs to be bigger than any of the
@@ -87,7 +81,6 @@ static u32 smack_next_secid = 10;
 int smk_access(char *subject_label, char *object_label, int request)
 {
        u32 may = MAY_NOT;
-       struct smk_list_entry *sp;
        struct smack_rule *srp;
 
        /*
@@ -139,9 +132,8 @@ int smk_access(char *subject_label, char *object_label, int request)
         * access (e.g. read is included in readwrite) it's
         * good.
         */
-       for (sp = smack_list; sp != NULL; sp = sp->smk_next) {
-               srp = &sp->smk_rule;
-
+       rcu_read_lock();
+       list_for_each_entry_rcu(srp, &smack_rule_list, list) {
                if (srp->smk_subject == subject_label ||
                    strcmp(srp->smk_subject, subject_label) == 0) {
                        if (srp->smk_object == object_label ||
@@ -151,6 +143,7 @@ int smk_access(char *subject_label, char *object_label, int request)
                        }
                }
        }
+       rcu_read_unlock();
        /*
         * This is a bit map operation.
         */
@@ -228,14 +221,17 @@ struct smack_known *smk_import_entry(const char *string, int len)
 
        mutex_lock(&smack_known_lock);
 
-       for (skp = smack_known; skp != NULL; skp = skp->smk_next)
-               if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0)
+       found = 0;
+       list_for_each_entry_rcu(skp, &smack_known_list, list) {
+               if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
+                       found = 1;
                        break;
+               }
+       }
 
-       if (skp == NULL) {
+       if (found == 0) {
                skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
                if (skp != NULL) {
-                       skp->smk_next = smack_known;
                        strncpy(skp->smk_known, smack, SMK_MAXLEN);
                        skp->smk_secid = smack_next_secid++;
                        skp->smk_cipso = NULL;
@@ -244,8 +240,7 @@ struct smack_known *smk_import_entry(const char *string, int len)
                         * Make sure that the entry is actually
                         * filled before putting it on the list.
                         */
-                       smp_mb();
-                       smack_known = skp;
+                       list_add_rcu(&skp->list, &smack_known_list);
                }
        }
 
@@ -266,6 +261,9 @@ char *smk_import(const char *string, int len)
 {
        struct smack_known *skp;
 
+       /* labels cannot begin with a '-' */
+       if (string[0] == '-')
+               return NULL;
        skp = smk_import_entry(string, len);
        if (skp == NULL)
                return NULL;
@@ -283,14 +281,19 @@ char *smack_from_secid(const u32 secid)
 {
        struct smack_known *skp;
 
-       for (skp = smack_known; skp != NULL; skp = skp->smk_next)
-               if (skp->smk_secid == secid)
+       rcu_read_lock();
+       list_for_each_entry_rcu(skp, &smack_known_list, list) {
+               if (skp->smk_secid == secid) {
+                       rcu_read_unlock();
                        return skp->smk_known;
+               }
+       }
 
        /*
         * If we got this far someone asked for the translation
         * of a secid that is not on the list.
         */
+       rcu_read_unlock();
        return smack_known_invalid.smk_known;
 }
 
@@ -305,9 +308,14 @@ u32 smack_to_secid(const char *smack)
 {
        struct smack_known *skp;
 
-       for (skp = smack_known; skp != NULL; skp = skp->smk_next)
-               if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0)
+       rcu_read_lock();
+       list_for_each_entry_rcu(skp, &smack_known_list, list) {
+               if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
+                       rcu_read_unlock();
                        return skp->smk_secid;
+               }
+       }
+       rcu_read_unlock();
        return 0;
 }
 
@@ -332,7 +340,8 @@ void smack_from_cipso(u32 level, char *cp, char *result)
        struct smack_known *kp;
        char *final = NULL;
 
-       for (kp = smack_known; final == NULL && kp != NULL; kp = kp->smk_next) {
+       rcu_read_lock();
+       list_for_each_entry(kp, &smack_known_list, list) {
                if (kp->smk_cipso == NULL)
                        continue;
 
@@ -344,6 +353,7 @@ void smack_from_cipso(u32 level, char *cp, char *result)
 
                spin_unlock_bh(&kp->smk_cipsolock);
        }
+       rcu_read_unlock();
        if (final == NULL)
                final = smack_known_huh.smk_known;
        strncpy(result, final, SMK_MAXLEN);
@@ -360,13 +370,19 @@ void smack_from_cipso(u32 level, char *cp, char *result)
 int smack_to_cipso(const char *smack, struct smack_cipso *cp)
 {
        struct smack_known *kp;
+       int found = 0;
 
-       for (kp = smack_known; kp != NULL; kp = kp->smk_next)
+       rcu_read_lock();
+       list_for_each_entry_rcu(kp, &smack_known_list, list) {
                if (kp->smk_known == smack ||
-                   strcmp(kp->smk_known, smack) == 0)
+                   strcmp(kp->smk_known, smack) == 0) {
+                       found = 1;
                        break;
+               }
+       }
+       rcu_read_unlock();
 
-       if (kp == NULL || kp->smk_cipso == NULL)
+       if (found == 0 || kp->smk_cipso == NULL)
                return -ENOENT;
 
        memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
index 84b62b5e9e2c681b3837a5da2a8cd2f39ce409f6..921514902eca4cac7ca80eaa07622f487b2e51a0 100644 (file)
@@ -7,6 +7,8 @@
  *     Casey Schaufler <casey@schaufler-ca.com>
  *
  *  Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
+ *  Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *                Paul Moore <paul.moore@hp.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,
@@ -20,6 +22,7 @@
 #include <linux/ext2_fs.h>
 #include <linux/kd.h>
 #include <asm/ioctls.h>
+#include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
 #include <linux/mutex.h>
@@ -606,6 +609,9 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
            strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) {
                if (!capable(CAP_MAC_ADMIN))
                        rc = -EPERM;
+               /* a label cannot be void and cannot begin with '-' */
+               if (size == 0 || (size > 0 && ((char *)value)[0] == '-'))
+                       rc = -EINVAL;
        } else
                rc = cap_inode_setxattr(dentry, name, value, size, flags);
 
@@ -1275,7 +1281,6 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
 
        ssp->smk_in = csp;
        ssp->smk_out = csp;
-       ssp->smk_labeled = SMACK_CIPSO_SOCKET;
        ssp->smk_packet[0] = '\0';
 
        sk->sk_security = ssp;
@@ -1294,6 +1299,43 @@ static void smack_sk_free_security(struct sock *sk)
        kfree(sk->sk_security);
 }
 
+/**
+* smack_host_label - check host based restrictions
+* @sip: the object end
+*
+* looks for host based access restrictions
+*
+* This version will only be appropriate for really small sets of single label
+* hosts.  The caller is responsible for ensuring that the RCU read lock is
+* taken before calling this function.
+*
+* Returns the label of the far end or NULL if it's not special.
+*/
+static char *smack_host_label(struct sockaddr_in *sip)
+{
+       struct smk_netlbladdr *snp;
+       struct in_addr *siap = &sip->sin_addr;
+
+       if (siap->s_addr == 0)
+               return NULL;
+
+       list_for_each_entry_rcu(snp, &smk_netlbladdr_list, list)
+               /*
+               * we break after finding the first match because
+               * the list is sorted from longest to shortest mask
+               * so we have found the most specific match
+               */
+               if ((&snp->smk_host.sin_addr)->s_addr ==
+                   (siap->s_addr & (&snp->smk_mask)->s_addr)) {
+                       /* we have found the special CIPSO option */
+                       if (snp->smk_label == smack_cipso_option)
+                               return NULL;
+                       return snp->smk_label;
+               }
+
+       return NULL;
+}
+
 /**
  * smack_set_catset - convert a capset to netlabel mls categories
  * @catset: the Smack categories
@@ -1365,11 +1407,10 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
  */
 static int smack_netlabel(struct sock *sk, int labeled)
 {
-       struct socket_smack *ssp;
+       struct socket_smack *ssp = sk->sk_security;
        struct netlbl_lsm_secattr secattr;
        int rc = 0;
 
-       ssp = sk->sk_security;
        /*
         * Usually the netlabel code will handle changing the
         * packet labeling based on the label.
@@ -1387,26 +1428,50 @@ static int smack_netlabel(struct sock *sk, int labeled)
        else {
                netlbl_secattr_init(&secattr);
                smack_to_secattr(ssp->smk_out, &secattr);
-               rc = netlbl_sock_setattr(sk, &secattr);
+               rc = netlbl_sock_setattr(sk, sk->sk_family, &secattr);
                netlbl_secattr_destroy(&secattr);
        }
 
        bh_unlock_sock(sk);
        local_bh_enable();
-       /*
-        * Remember the label scheme used so that it is not
-        * necessary to do the netlabel setting if it has not
-        * changed the next time through.
-        *
-        * The -EDESTADDRREQ case is an indication that there's
-        * a single level host involved.
-        */
-       if (rc == 0)
-               ssp->smk_labeled = labeled;
 
        return rc;
 }
 
+/**
+ * smack_netlbel_send - Set the secattr on a socket and perform access checks
+ * @sk: the socket
+ * @sap: the destination address
+ *
+ * Set the correct secattr for the given socket based on the destination
+ * address and perform any outbound access checks needed.
+ *
+ * Returns 0 on success or an error code.
+ *
+ */
+static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
+{
+       int rc;
+       int sk_lbl;
+       char *hostsp;
+       struct socket_smack *ssp = sk->sk_security;
+
+       rcu_read_lock();
+       hostsp = smack_host_label(sap);
+       if (hostsp != NULL) {
+               sk_lbl = SMACK_UNLABELED_SOCKET;
+               rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
+       } else {
+               sk_lbl = SMACK_CIPSO_SOCKET;
+               rc = 0;
+       }
+       rcu_read_unlock();
+       if (rc != 0)
+               return rc;
+
+       return smack_netlabel(sk, sk_lbl);
+}
+
 /**
  * smack_inode_setsecurity - set smack xattrs
  * @inode: the object
@@ -1428,7 +1493,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
        struct socket *sock;
        int rc = 0;
 
-       if (value == NULL || size > SMK_LABELLEN)
+       if (value == NULL || size > SMK_LABELLEN || size == 0)
                return -EACCES;
 
        sp = smk_import(value, size);
@@ -1488,41 +1553,6 @@ static int smack_socket_post_create(struct socket *sock, int family,
        return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
 }
 
-
-/**
- * smack_host_label - check host based restrictions
- * @sip: the object end
- *
- * looks for host based access restrictions
- *
- * This version will only be appropriate for really small
- * sets of single label hosts.
- *
- * Returns the label of the far end or NULL if it's not special.
- */
-static char *smack_host_label(struct sockaddr_in *sip)
-{
-       struct smk_netlbladdr *snp;
-       struct in_addr *siap = &sip->sin_addr;
-
-       if (siap->s_addr == 0)
-               return NULL;
-
-       for (snp = smack_netlbladdrs; snp != NULL; snp = snp->smk_next) {
-               /*
-                * we break after finding the first match because
-                * the list is sorted from longest to shortest mask
-                * so we have found the most specific match
-                */
-               if ((&snp->smk_host.sin_addr)->s_addr  ==
-                       (siap->s_addr & (&snp->smk_mask)->s_addr)) {
-                       return snp->smk_label;
-               }
-       }
-
-       return NULL;
-}
-
 /**
  * smack_socket_connect - connect access check
  * @sock: the socket
@@ -1536,30 +1566,12 @@ static char *smack_host_label(struct sockaddr_in *sip)
 static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
                                int addrlen)
 {
-       struct socket_smack *ssp = sock->sk->sk_security;
-       char *hostsp;
-       int rc;
-
        if (sock->sk == NULL || sock->sk->sk_family != PF_INET)
                return 0;
-
        if (addrlen < sizeof(struct sockaddr_in))
                return -EINVAL;
 
-       hostsp = smack_host_label((struct sockaddr_in *)sap);
-       if (hostsp == NULL) {
-               if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
-                       return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
-               return 0;
-       }
-
-       rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
-       if (rc != 0)
-               return rc;
-
-       if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET)
-               return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
-       return 0;
+       return smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap);
 }
 
 /**
@@ -2260,9 +2272,6 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
                                int size)
 {
        struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
-       struct socket_smack *ssp = sock->sk->sk_security;
-       char *hostsp;
-       int rc;
 
        /*
         * Perfectly reasonable for this to be NULL
@@ -2270,22 +2279,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
        if (sip == NULL || sip->sin_family != PF_INET)
                return 0;
 
-       hostsp = smack_host_label(sip);
-       if (hostsp == NULL) {
-               if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
-                       return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
-               return 0;
-       }
-
-       rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
-       if (rc != 0)
-               return rc;
-
-       if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET)
-               return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
-
-       return 0;
-
+       return smack_netlabel_send(sock->sk, sip);
 }
 
 
@@ -2490,31 +2484,24 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
 }
 
 /**
- * smack_sock_graft - graft access state between two sockets
- * @sk: fresh sock
- * @parent: donor socket
+ * smack_sock_graft - Initialize a newly created socket with an existing sock
+ * @sk: child sock
+ * @parent: parent socket
  *
- * Sets the netlabel socket state on sk from parent
+ * Set the smk_{in,out} state of an existing sock based on the process that
+ * is creating the new socket.
  */
 static void smack_sock_graft(struct sock *sk, struct socket *parent)
 {
        struct socket_smack *ssp;
-       int rc;
 
-       if (sk == NULL)
-               return;
-
-       if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
+       if (sk == NULL ||
+           (sk->sk_family != PF_INET && sk->sk_family != PF_INET6))
                return;
 
        ssp = sk->sk_security;
        ssp->smk_in = ssp->smk_out = current_security();
-       ssp->smk_packet[0] = '\0';
-
-       rc = smack_netlabel(sk, SMACK_CIPSO_SOCKET);
-       if (rc != 0)
-               printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
-                      __func__, -rc);
+       /* cssp->smk_packet is already set in smack_inet_csk_clone() */
 }
 
 /**
@@ -2529,35 +2516,82 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent)
 static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
                                   struct request_sock *req)
 {
-       struct netlbl_lsm_secattr skb_secattr;
+       u16 family = sk->sk_family;
        struct socket_smack *ssp = sk->sk_security;
+       struct netlbl_lsm_secattr secattr;
+       struct sockaddr_in addr;
+       struct iphdr *hdr;
        char smack[SMK_LABELLEN];
        int rc;
 
-       if (skb == NULL)
-               return -EACCES;
+       /* handle mapped IPv4 packets arriving via IPv6 sockets */
+       if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+               family = PF_INET;
 
-       netlbl_secattr_init(&skb_secattr);
-       rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr);
+       netlbl_secattr_init(&secattr);
+       rc = netlbl_skbuff_getattr(skb, family, &secattr);
        if (rc == 0)
-               smack_from_secattr(&skb_secattr, smack);
+               smack_from_secattr(&secattr, smack);
        else
                strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN);
-       netlbl_secattr_destroy(&skb_secattr);
+       netlbl_secattr_destroy(&secattr);
+
        /*
-        * Receiving a packet requires that the other end
-        * be able to write here. Read access is not required.
-        *
-        * If the request is successful save the peer's label
-        * so that SO_PEERCRED can report it.
+        * Receiving a packet requires that the other end be able to write
+        * here. Read access is not required.
         */
        rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
-       if (rc == 0)
-               strncpy(ssp->smk_packet, smack, SMK_MAXLEN);
+       if (rc != 0)
+               return rc;
+
+       /*
+        * Save the peer's label in the request_sock so we can later setup
+        * smk_packet in the child socket so that SO_PEERCRED can report it.
+        */
+       req->peer_secid = smack_to_secid(smack);
+
+       /*
+        * We need to decide if we want to label the incoming connection here
+        * if we do we only need to label the request_sock and the stack will
+        * propogate the wire-label to the sock when it is created.
+        */
+       hdr = ip_hdr(skb);
+       addr.sin_addr.s_addr = hdr->saddr;
+       rcu_read_lock();
+       if (smack_host_label(&addr) == NULL) {
+               rcu_read_unlock();
+               netlbl_secattr_init(&secattr);
+               smack_to_secattr(smack, &secattr);
+               rc = netlbl_req_setattr(req, &secattr);
+               netlbl_secattr_destroy(&secattr);
+       } else {
+               rcu_read_unlock();
+               netlbl_req_delattr(req);
+       }
 
        return rc;
 }
 
+/**
+ * smack_inet_csk_clone - Copy the connection information to the new socket
+ * @sk: the new socket
+ * @req: the connection's request_sock
+ *
+ * Transfer the connection's peer label to the newly created socket.
+ */
+static void smack_inet_csk_clone(struct sock *sk,
+                                const struct request_sock *req)
+{
+       struct socket_smack *ssp = sk->sk_security;
+       char *smack;
+
+       if (req->peer_secid != 0) {
+               smack = smack_from_secid(req->peer_secid);
+               strncpy(ssp->smk_packet, smack, SMK_MAXLEN);
+       } else
+               ssp->smk_packet[0] = '\0';
+}
+
 /*
  * Key management security hooks
  *
@@ -2909,6 +2943,7 @@ struct security_operations smack_ops = {
        .sk_free_security =             smack_sk_free_security,
        .sock_graft =                   smack_sock_graft,
        .inet_conn_request =            smack_inet_conn_request,
+       .inet_csk_clone =               smack_inet_csk_clone,
 
  /* key management security hooks */
 #ifdef CONFIG_KEYS
@@ -2930,6 +2965,17 @@ struct security_operations smack_ops = {
        .release_secctx =               smack_release_secctx,
 };
 
+
+static __init void init_smack_know_list(void)
+{
+       list_add(&smack_known_huh.list, &smack_known_list);
+       list_add(&smack_known_hat.list, &smack_known_list);
+       list_add(&smack_known_star.list, &smack_known_list);
+       list_add(&smack_known_floor.list, &smack_known_list);
+       list_add(&smack_known_invalid.list, &smack_known_list);
+       list_add(&smack_known_web.list, &smack_known_list);
+}
+
 /**
  * smack_init - initialize the smack system
  *
@@ -2950,6 +2996,8 @@ static __init int smack_init(void)
        cred = (struct cred *) current->cred;
        cred->security = &smack_known_floor.smk_known;
 
+       /* initilize the smack_know_list */
+       init_smack_know_list();
        /*
         * Initialize locks
         */
index a1b57e4dba3e0865902a7a3691ee1d3afc1f8748..e03a7e19c73b3a0b49d7533db45ecb719d250f30 100644 (file)
@@ -80,10 +80,14 @@ char *smack_onlycap;
  * Packets are sent there unlabeled, but only from tasks that
  * can write to the specified label.
  */
-struct smk_netlbladdr *smack_netlbladdrs;
+
+LIST_HEAD(smk_netlbladdr_list);
+LIST_HEAD(smack_rule_list);
 
 static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
-struct smk_list_entry *smack_list;
+
+const char *smack_cipso_option = SMACK_CIPSO_OPTION;
+
 
 #define        SEQ_READ_FINISHED       1
 
@@ -134,24 +138,27 @@ static void *load_seq_start(struct seq_file *s, loff_t *pos)
 {
        if (*pos == SEQ_READ_FINISHED)
                return NULL;
-
-       return smack_list;
+       if (list_empty(&smack_rule_list))
+               return NULL;
+       return smack_rule_list.next;
 }
 
 static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-       struct smk_list_entry *skp = ((struct smk_list_entry *) v)->smk_next;
+       struct list_head *list = v;
 
-       if (skp == NULL)
+       if (list_is_last(list, &smack_rule_list)) {
                *pos = SEQ_READ_FINISHED;
-
-       return skp;
+               return NULL;
+       }
+       return list->next;
 }
 
 static int load_seq_show(struct seq_file *s, void *v)
 {
-       struct smk_list_entry *slp = (struct smk_list_entry *) v;
-       struct smack_rule *srp = &slp->smk_rule;
+       struct list_head *list = v;
+       struct smack_rule *srp =
+                list_entry(list, struct smack_rule, list);
 
        seq_printf(s, "%s %s", (char *)srp->smk_subject,
                   (char *)srp->smk_object);
@@ -212,32 +219,23 @@ static int smk_open_load(struct inode *inode, struct file *file)
  */
 static int smk_set_access(struct smack_rule *srp)
 {
-       struct smk_list_entry *sp;
-       struct smk_list_entry *newp;
+       struct smack_rule *sp;
        int ret = 0;
-
+       int found;
        mutex_lock(&smack_list_lock);
 
-       for (sp = smack_list; sp != NULL; sp = sp->smk_next)
-               if (sp->smk_rule.smk_subject == srp->smk_subject &&
-                   sp->smk_rule.smk_object == srp->smk_object) {
-                       sp->smk_rule.smk_access = srp->smk_access;
+       found = 0;
+       list_for_each_entry_rcu(sp, &smack_rule_list, list) {
+               if (sp->smk_subject == srp->smk_subject &&
+                   sp->smk_object == srp->smk_object) {
+                       found = 1;
+                       sp->smk_access = srp->smk_access;
                        break;
                }
-
-       if (sp == NULL) {
-               newp = kzalloc(sizeof(struct smk_list_entry), GFP_KERNEL);
-               if (newp == NULL) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-
-               newp->smk_rule = *srp;
-               newp->smk_next = smack_list;
-               smack_list = newp;
        }
+       if (found == 0)
+               list_add_rcu(&srp->list, &smack_rule_list);
 
-out:
        mutex_unlock(&smack_list_lock);
 
        return ret;
@@ -261,7 +259,7 @@ out:
 static ssize_t smk_write_load(struct file *file, const char __user *buf,
                              size_t count, loff_t *ppos)
 {
-       struct smack_rule rule;
+       struct smack_rule *rule;
        char *data;
        int rc = -EINVAL;
 
@@ -272,9 +270,8 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
         */
        if (!capable(CAP_MAC_ADMIN))
                return -EPERM;
-       if (*ppos != 0)
-               return -EINVAL;
-       if (count != SMK_LOADLEN)
+
+       if (*ppos != 0 || count != SMK_LOADLEN)
                return -EINVAL;
 
        data = kzalloc(count, GFP_KERNEL);
@@ -286,25 +283,31 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
                goto out;
        }
 
-       rule.smk_subject = smk_import(data, 0);
-       if (rule.smk_subject == NULL)
+       rule = kzalloc(sizeof(*rule), GFP_KERNEL);
+       if (rule == NULL) {
+               rc = -ENOMEM;
                goto out;
+       }
 
-       rule.smk_object = smk_import(data + SMK_LABELLEN, 0);
-       if (rule.smk_object == NULL)
-               goto out;
+       rule->smk_subject = smk_import(data, 0);
+       if (rule->smk_subject == NULL)
+               goto out_free_rule;
 
-       rule.smk_access = 0;
+       rule->smk_object = smk_import(data + SMK_LABELLEN, 0);
+       if (rule->smk_object == NULL)
+               goto out_free_rule;
+
+       rule->smk_access = 0;
 
        switch (data[SMK_LABELLEN + SMK_LABELLEN]) {
        case '-':
                break;
        case 'r':
        case 'R':
-               rule.smk_access |= MAY_READ;
+               rule->smk_access |= MAY_READ;
                break;
        default:
-               goto out;
+               goto out_free_rule;
        }
 
        switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
@@ -312,10 +315,10 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
                break;
        case 'w':
        case 'W':
-               rule.smk_access |= MAY_WRITE;
+               rule->smk_access |= MAY_WRITE;
                break;
        default:
-               goto out;
+               goto out_free_rule;
        }
 
        switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
@@ -323,10 +326,10 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
                break;
        case 'x':
        case 'X':
-               rule.smk_access |= MAY_EXEC;
+               rule->smk_access |= MAY_EXEC;
                break;
        default:
-               goto out;
+               goto out_free_rule;
        }
 
        switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
@@ -334,17 +337,20 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
                break;
        case 'a':
        case 'A':
-               rule.smk_access |= MAY_APPEND;
+               rule->smk_access |= MAY_APPEND;
                break;
        default:
-               goto out;
+               goto out_free_rule;
        }
 
-       rc = smk_set_access(&rule);
+       rc = smk_set_access(rule);
 
        if (!rc)
                rc = count;
+       goto out;
 
+out_free_rule:
+       kfree(rule);
 out:
        kfree(data);
        return rc;
@@ -433,24 +439,26 @@ static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
 {
        if (*pos == SEQ_READ_FINISHED)
                return NULL;
+       if (list_empty(&smack_known_list))
+               return NULL;
 
-       return smack_known;
+       return smack_known_list.next;
 }
 
 static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-       struct smack_known *skp = ((struct smack_known *) v)->smk_next;
+       struct list_head  *list = v;
 
        /*
-        * Omit labels with no associated cipso value
+        * labels with no associated cipso value wont be printed
+        * in cipso_seq_show
         */
-       while (skp != NULL && !skp->smk_cipso)
-               skp = skp->smk_next;
-
-       if (skp == NULL)
+       if (list_is_last(list, &smack_known_list)) {
                *pos = SEQ_READ_FINISHED;
+               return NULL;
+       }
 
-       return skp;
+       return list->next;
 }
 
 /*
@@ -459,7 +467,9 @@ static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
  */
 static int cipso_seq_show(struct seq_file *s, void *v)
 {
-       struct smack_known *skp = (struct smack_known *) v;
+       struct list_head  *list = v;
+       struct smack_known *skp =
+                list_entry(list, struct smack_known, list);
        struct smack_cipso *scp = skp->smk_cipso;
        char *cbp;
        char sep = '/';
@@ -558,6 +568,11 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
                goto unlockedout;
        }
 
+       /* labels cannot begin with a '-' */
+       if (data[0] == '-') {
+               rc = -EINVAL;
+               goto unlockedout;
+       }
        data[count] = '\0';
        rule = data;
        /*
@@ -638,18 +653,21 @@ static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos)
 {
        if (*pos == SEQ_READ_FINISHED)
                return NULL;
-
-       return smack_netlbladdrs;
+       if (list_empty(&smk_netlbladdr_list))
+               return NULL;
+       return smk_netlbladdr_list.next;
 }
 
 static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-       struct smk_netlbladdr *skp = ((struct smk_netlbladdr *) v)->smk_next;
+       struct list_head *list = v;
 
-       if (skp == NULL)
+       if (list_is_last(list, &smk_netlbladdr_list)) {
                *pos = SEQ_READ_FINISHED;
+               return NULL;
+       }
 
-       return skp;
+       return list->next;
 }
 #define BEBITS (sizeof(__be32) * 8)
 
@@ -658,7 +676,9 @@ static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
  */
 static int netlbladdr_seq_show(struct seq_file *s, void *v)
 {
-       struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v;
+       struct list_head *list = v;
+       struct smk_netlbladdr *skp =
+                        list_entry(list, struct smk_netlbladdr, list);
        unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
        int maskn;
        u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr);
@@ -702,30 +722,36 @@ static int smk_open_netlbladdr(struct inode *inode, struct file *file)
  *
  * This helper insert netlabel in the smack_netlbladdrs list
  * sorted by netmask length (longest to smallest)
+ * locked by &smk_netlbladdr_lock in smk_write_netlbladdr
+ *
  */
 static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
 {
-       struct smk_netlbladdr *m;
+       struct smk_netlbladdr *m, *m_next;
 
-       if (smack_netlbladdrs == NULL) {
-               smack_netlbladdrs = new;
+       if (list_empty(&smk_netlbladdr_list)) {
+               list_add_rcu(&new->list, &smk_netlbladdr_list);
                return;
        }
 
+       m = list_entry(rcu_dereference(smk_netlbladdr_list.next),
+                        struct smk_netlbladdr, list);
+
        /* the comparison '>' is a bit hacky, but works */
-       if (new->smk_mask.s_addr > smack_netlbladdrs->smk_mask.s_addr) {
-               new->smk_next = smack_netlbladdrs;
-               smack_netlbladdrs = new;
+       if (new->smk_mask.s_addr > m->smk_mask.s_addr) {
+               list_add_rcu(&new->list, &smk_netlbladdr_list);
                return;
        }
-       for (m = smack_netlbladdrs; m != NULL; m = m->smk_next) {
-               if (m->smk_next == NULL) {
-                       m->smk_next = new;
+
+       list_for_each_entry_rcu(m, &smk_netlbladdr_list, list) {
+               if (list_is_last(&m->list, &smk_netlbladdr_list)) {
+                       list_add_rcu(&new->list, &m->list);
                        return;
                }
-               if (new->smk_mask.s_addr > m->smk_next->smk_mask.s_addr) {
-                       new->smk_next = m->smk_next;
-                       m->smk_next = new;
+               m_next = list_entry(rcu_dereference(m->list.next),
+                                struct smk_netlbladdr, list);
+               if (new->smk_mask.s_addr > m_next->smk_mask.s_addr) {
+                       list_add_rcu(&new->list, &m->list);
                        return;
                }
        }
@@ -755,6 +781,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
        struct netlbl_audit audit_info;
        struct in_addr mask;
        unsigned int m;
+       int found;
        u32 mask_bits = (1<<31);
        __be32 nsa;
        u32 temp_mask;
@@ -789,9 +816,18 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
        if (m > BEBITS)
                return -EINVAL;
 
-       sp = smk_import(smack, 0);
-       if (sp == NULL)
-               return -EINVAL;
+       /* if smack begins with '-', its an option, don't import it */
+       if (smack[0] != '-') {
+               sp = smk_import(smack, 0);
+               if (sp == NULL)
+                       return -EINVAL;
+       } else {
+               /* check known options */
+               if (strcmp(smack, smack_cipso_option) == 0)
+                       sp = (char *)smack_cipso_option;
+               else
+                       return -EINVAL;
+       }
 
        for (temp_mask = 0; m > 0; m--) {
                temp_mask |= mask_bits;
@@ -808,14 +844,17 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
 
        nsa = newname.sin_addr.s_addr;
        /* try to find if the prefix is already in the list */
-       for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next)
+       found = 0;
+       list_for_each_entry_rcu(skp, &smk_netlbladdr_list, list) {
                if (skp->smk_host.sin_addr.s_addr == nsa &&
-                   skp->smk_mask.s_addr == mask.s_addr)
+                   skp->smk_mask.s_addr == mask.s_addr) {
+                       found = 1;
                        break;
-
+               }
+       }
        smk_netlabel_audit_set(&audit_info);
 
-       if (skp == NULL) {
+       if (found == 0) {
                skp = kzalloc(sizeof(*skp), GFP_KERNEL);
                if (skp == NULL)
                        rc = -ENOMEM;
@@ -827,18 +866,23 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
                        smk_netlbladdr_insert(skp);
                }
        } else {
-               rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
-                       &skp->smk_host.sin_addr, &skp->smk_mask,
-                       PF_INET, &audit_info);
+               /* we delete the unlabeled entry, only if the previous label
+                * wasnt the special CIPSO option */
+               if (skp->smk_label != smack_cipso_option)
+                       rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
+                                       &skp->smk_host.sin_addr, &skp->smk_mask,
+                                       PF_INET, &audit_info);
+               else
+                       rc = 0;
                skp->smk_label = sp;
        }
 
        /*
         * Now tell netlabel about the single label nature of
         * this host so that incoming packets get labeled.
+        * but only if we didn't get the special CIPSO option
         */
-
-       if (rc == 0)
+       if (rc == 0 && sp != smack_cipso_option)
                rc = netlbl_cfg_unlbl_static_add(&init_net, NULL,
                        &skp->smk_host.sin_addr, &skp->smk_mask, PF_INET,
                        smack_to_secid(skp->smk_label), &audit_info);
index 6dcb7cc0ed1d5c5eaa0bc9714fd37b7cb32d39d9..26a76d67aa1c21b8f21b4eae22ca1dc091d1a43d 100644 (file)
@@ -55,7 +55,7 @@ struct tomoyo_path_info {
 struct tomoyo_path_info_with_data {
        /* Keep "head" first, for this pointer is passed to tomoyo_free(). */
        struct tomoyo_path_info head;
-       char bariier1[16]; /* Safeguard for overrun. */
+       char barrier1[16]; /* Safeguard for overrun. */
        char body[TOMOYO_MAX_PATHNAME_LEN];
        char barrier2[16]; /* Safeguard for overrun. */
 };
index 70fa87189f3624694dc52ab3f04f48f13dba6fee..35df614f6c5599329a403beb7295f3ffe3a51d2e 100644 (file)
@@ -154,11 +154,6 @@ EXPORT_SYMBOL(snd_seq_root);
 struct snd_info_entry *snd_oss_root;
 #endif
 
-static inline void snd_info_entry_prepare(struct proc_dir_entry *de)
-{
-       de->owner = THIS_MODULE;
-}
-
 static void snd_remove_proc_entry(struct proc_dir_entry *parent,
                                  struct proc_dir_entry *de)
 {
@@ -522,32 +517,11 @@ static const struct file_operations snd_info_entry_operations =
        .release =              snd_info_entry_release,
 };
 
-/**
- * snd_create_proc_entry - create a procfs entry
- * @name: the name of the proc file
- * @mode: the file permission bits, S_Ixxx
- * @parent: the parent proc-directory entry
- *
- * Creates a new proc file entry with the given name and permission
- * on the given directory.
- *
- * Returns the pointer of new instance or NULL on failure.
- */
-static struct proc_dir_entry *snd_create_proc_entry(const char *name, mode_t mode,
-                                                   struct proc_dir_entry *parent)
-{
-       struct proc_dir_entry *p;
-       p = create_proc_entry(name, mode, parent);
-       if (p)
-               snd_info_entry_prepare(p);
-       return p;
-}
-
 int __init snd_info_init(void)
 {
        struct proc_dir_entry *p;
 
-       p = snd_create_proc_entry("asound", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
+       p = create_proc_entry("asound", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
        if (p == NULL)
                return -ENOMEM;
        snd_proc_root = p;
@@ -974,12 +948,11 @@ int snd_info_register(struct snd_info_entry * entry)
                return -ENXIO;
        root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
        mutex_lock(&info_mutex);
-       p = snd_create_proc_entry(entry->name, entry->mode, root);
+       p = create_proc_entry(entry->name, entry->mode, root);
        if (!p) {
                mutex_unlock(&info_mutex);
                return -ENOMEM;
        }
-       p->owner = entry->module;
        if (!S_ISDIR(entry->mode))
                p->proc_fops = &snd_info_entry_operations;
        p->size = entry->size;
index 9d98a6658ac9d757c004f7c130a7c143109dfe51..d31c373e076d543a619aa101917a3ef61689e0e8 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/version.h>
 #include <sound/core.h>
 #include <sound/tea575x-tuner.h>
 
@@ -31,6 +32,13 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips");
 MODULE_LICENSE("GPL");
 
+static int radio_nr = -1;
+module_param(radio_nr, int, 0);
+
+#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
+#define FREQ_LO                 (87 * 16000)
+#define FREQ_HI                (108 * 16000)
+
 /*
  * definitions
  */
@@ -53,6 +61,17 @@ MODULE_LICENSE("GPL");
 #define TEA575X_BIT_DUMMY      (1<<15)         /* buffer */
 #define TEA575X_BIT_FREQ_MASK  0x7fff
 
+static struct v4l2_queryctrl radio_qctrl[] = {
+       {
+               .id            = V4L2_CID_AUDIO_MUTE,
+               .name          = "Mute",
+               .minimum       = 0,
+               .maximum       = 1,
+               .default_value = 1,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+       }
+};
+
 /*
  * lowlevel part
  */
@@ -84,94 +103,146 @@ static void snd_tea575x_set_freq(struct snd_tea575x *tea)
  * Linux Video interface
  */
 
-static long snd_tea575x_ioctl(struct file *file,
-                            unsigned int cmd, unsigned long data)
+static int vidioc_querycap(struct file *file, void  *priv,
+                                       struct v4l2_capability *v)
 {
        struct snd_tea575x *tea = video_drvdata(file);
-       void __user *arg = (void __user *)data;
-
-       switch(cmd) {
-               case VIDIOCGCAP:
-               {
-                       struct video_capability v;
-                       v.type = VID_TYPE_TUNER;
-                       v.channels = 1;
-                       v.audios = 1;
-                       /* No we don't do pictures */
-                       v.maxwidth = 0;
-                       v.maxheight = 0;
-                       v.minwidth = 0;
-                       v.minheight = 0;
-                       strcpy(v.name, tea->tea5759 ? "TEA5759" : "TEA5757");
-                       if (copy_to_user(arg,&v,sizeof(v)))
-                               return -EFAULT;
-                       return 0;
-               }
-               case VIDIOCGTUNER:
-               {
-                       struct video_tuner v;
-                       if (copy_from_user(&v, arg,sizeof(v))!=0)
-                               return -EFAULT;
-                       if (v.tuner)    /* Only 1 tuner */
-                               return -EINVAL;
-                       v.rangelow = (87*16000);
-                       v.rangehigh = (108*16000);
-                       v.flags = VIDEO_TUNER_LOW;
-                       v.mode = VIDEO_MODE_AUTO;
-                       strcpy(v.name, "FM");
-                       v.signal = 0xFFFF;
-                       if (copy_to_user(arg, &v, sizeof(v)))
-                               return -EFAULT;
-                       return 0;
-               }
-               case VIDIOCSTUNER:
-               {
-                       struct video_tuner v;
-                       if(copy_from_user(&v, arg, sizeof(v)))
-                               return -EFAULT;
-                       if(v.tuner!=0)
-                               return -EINVAL;
-                       /* Only 1 tuner so no setting needed ! */
+
+       strcpy(v->card, tea->tea5759 ? "TEA5759" : "TEA5757");
+       strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver));
+       strlcpy(v->card, "Maestro Radio", sizeof(v->card));
+       sprintf(v->bus_info, "PCI");
+       v->version = RADIO_VERSION;
+       v->capabilities = V4L2_CAP_TUNER;
+       return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *v)
+{
+       if (v->index > 0)
+               return -EINVAL;
+
+       strcpy(v->name, "FM");
+       v->type = V4L2_TUNER_RADIO;
+       v->rangelow = FREQ_LO;
+       v->rangehigh = FREQ_HI;
+       v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+       v->capability = V4L2_TUNER_CAP_LOW;
+       v->audmode = V4L2_TUNER_MODE_MONO;
+       v->signal = 0xffff;
+       return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *v)
+{
+       if (v->index > 0)
+               return -EINVAL;
+       return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+                                       struct v4l2_frequency *f)
+{
+       struct snd_tea575x *tea = video_drvdata(file);
+
+       f->type = V4L2_TUNER_RADIO;
+       f->frequency = tea->freq;
+       return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+                                       struct v4l2_frequency *f)
+{
+       struct snd_tea575x *tea = video_drvdata(file);
+
+       if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
+               return -EINVAL;
+
+       tea->freq = f->frequency;
+
+       snd_tea575x_set_freq(tea);
+
+       return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       if (a->index > 1)
+               return -EINVAL;
+
+       strcpy(a->name, "Radio");
+       a->capability = V4L2_AUDCAP_STEREO;
+       return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       if (a->index != 0)
+               return -EINVAL;
+       return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+                                       struct v4l2_queryctrl *qc)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+               if (qc->id && qc->id == radio_qctrl[i].id) {
+                       memcpy(qc, &(radio_qctrl[i]),
+                                               sizeof(*qc));
                        return 0;
                }
-               case VIDIOCGFREQ:
-                       if(copy_to_user(arg, &tea->freq, sizeof(tea->freq)))
-                               return -EFAULT;
-                       return 0;
-               case VIDIOCSFREQ:
-                       if(copy_from_user(&tea->freq, arg, sizeof(tea->freq)))
-                               return -EFAULT;
-                       snd_tea575x_set_freq(tea);
-                       return 0;
-               case VIDIOCGAUDIO:
-               {
-                       struct video_audio v;
-                       memset(&v, 0, sizeof(v));
-                       strcpy(v.name, "Radio");
-                       if(copy_to_user(arg,&v, sizeof(v)))
-                               return -EFAULT;
+       }
+       return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+                                       struct v4l2_control *ctrl)
+{
+       struct snd_tea575x *tea = video_drvdata(file);
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               if (tea->ops->mute) {
+                       ctrl->value = tea->mute;
                        return 0;
                }
-               case VIDIOCSAUDIO:
-               {
-                       struct video_audio v;
-                       if(copy_from_user(&v, arg, sizeof(v)))
-                               return -EFAULT;
-                       if (tea->ops->mute)
-                               tea->ops->mute(tea,
-                                              (v.flags &
-                                               VIDEO_AUDIO_MUTE) ? 1 : 0);
-                       if(v.audio)
-                               return -EINVAL;
+       }
+       return -EINVAL;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+                                       struct v4l2_control *ctrl)
+{
+       struct snd_tea575x *tea = video_drvdata(file);
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               if (tea->ops->mute) {
+                       tea->ops->mute(tea, ctrl->value);
+                       tea->mute = 1;
                        return 0;
                }
-               default:
-                       return -ENOIOCTLCMD;
        }
+       return -EINVAL;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
 }
 
-static void snd_tea575x_release(struct video_device *vfd)
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
+       if (i != 0)
+               return -EINVAL;
+       return 0;
 }
 
 static int snd_tea575x_exclusive_open(struct file *file)
@@ -189,50 +260,91 @@ static int snd_tea575x_exclusive_release(struct file *file)
        return 0;
 }
 
+static const struct v4l2_file_operations tea575x_fops = {
+       .owner          = THIS_MODULE,
+       .open           = snd_tea575x_exclusive_open,
+       .release        = snd_tea575x_exclusive_release,
+       .ioctl          = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops tea575x_ioctl_ops = {
+       .vidioc_querycap    = vidioc_querycap,
+       .vidioc_g_tuner     = vidioc_g_tuner,
+       .vidioc_s_tuner     = vidioc_s_tuner,
+       .vidioc_g_audio     = vidioc_g_audio,
+       .vidioc_s_audio     = vidioc_s_audio,
+       .vidioc_g_input     = vidioc_g_input,
+       .vidioc_s_input     = vidioc_s_input,
+       .vidioc_g_frequency = vidioc_g_frequency,
+       .vidioc_s_frequency = vidioc_s_frequency,
+       .vidioc_queryctrl   = vidioc_queryctrl,
+       .vidioc_g_ctrl      = vidioc_g_ctrl,
+       .vidioc_s_ctrl      = vidioc_s_ctrl,
+};
+
+static struct video_device tea575x_radio = {
+       .name           = "tea575x-tuner",
+       .fops           = &tea575x_fops,
+       .ioctl_ops      = &tea575x_ioctl_ops,
+       .release        = video_device_release,
+};
+
 /*
  * initialize all the tea575x chips
  */
 void snd_tea575x_init(struct snd_tea575x *tea)
 {
+       int retval;
        unsigned int val;
+       struct video_device *tea575x_radio_inst;
 
        val = tea->ops->read(tea);
        if (val == 0x1ffffff || val == 0) {
-               snd_printk(KERN_ERR "Cannot find TEA575x chip\n");
+               snd_printk(KERN_ERR
+                          "tea575x-tuner: Cannot find TEA575x chip\n");
                return;
        }
 
-       memset(&tea->vd, 0, sizeof(tea->vd));
-       strcpy(tea->vd.name, tea->tea5759 ? "TEA5759 radio" : "TEA5757 radio");
-       tea->vd.release = snd_tea575x_release;
-       video_set_drvdata(&tea->vd, tea);
-       tea->vd.fops = &tea->fops;
        tea->in_use = 0;
-       tea->fops.owner = tea->card->module;
-       tea->fops.open = snd_tea575x_exclusive_open;
-       tea->fops.release = snd_tea575x_exclusive_release;
-       tea->fops.ioctl = snd_tea575x_ioctl;
-       if (video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->dev_nr - 1) < 0) {
-               snd_printk(KERN_ERR "unable to register tea575x tuner\n");
+       tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40;
+       tea->freq = 90500 * 16;         /* 90.5Mhz default */
+
+       tea575x_radio_inst = video_device_alloc();
+       if (tea575x_radio_inst == NULL) {
+               printk(KERN_ERR "tea575x-tuner: not enough memory\n");
                return;
        }
-       tea->vd_registered = 1;
 
-       tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40;
-       tea->freq = 90500 * 16;         /* 90.5Mhz default */
+       memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio));
+
+       strcpy(tea575x_radio.name, tea->tea5759 ?
+                                  "TEA5759 radio" : "TEA5757 radio");
+
+       video_set_drvdata(tea575x_radio_inst, tea);
+
+       retval = video_register_device(tea575x_radio_inst,
+                                      VFL_TYPE_RADIO, radio_nr);
+       if (retval) {
+               printk(KERN_ERR "tea575x-tuner: can't register video device!\n");
+               kfree(tea575x_radio_inst);
+               return;
+       }
 
        snd_tea575x_set_freq(tea);
 
        /* mute on init */
-       if (tea->ops->mute)
+       if (tea->ops->mute) {
                tea->ops->mute(tea, 1);
+               tea->mute = 1;
+       }
+       tea->vd = tea575x_radio_inst;
 }
 
 void snd_tea575x_exit(struct snd_tea575x *tea)
 {
-       if (tea->vd_registered) {
-               video_unregister_device(&tea->vd);
-               tea->vd_registered = 0;
+       if (tea->vd) {
+               video_unregister_device(tea->vd);
+               tea->vd = NULL;
        }
 }
 
index ca25e6179d7671b0b5c3d7a9a3922088606e1ec1..93422e3a3f0cc2f642a5a30cfd09ee89cbb55a43 100644 (file)
@@ -507,7 +507,7 @@ config SND_FM801
 config SND_FM801_TEA575X_BOOL
        bool "ForteMedia FM801 + TEA5757 tuner"
        depends on SND_FM801
-       depends on VIDEO_V4L1=y || VIDEO_V4L1=SND_FM801
+       depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_FM801
        help
          Say Y here to include support for soundcards based on the ForteMedia
          FM801 chip with a TEA5757 tuner connected to GPIO1-3 pins (Media
index 43a3a0fe8f29b3637bcd49eb0d3824d5da67d2a6..588c588791e288a836931aae27ffa694bbd0c99f 100644 (file)
@@ -46,49 +46,50 @@ config INITRAMFS_ROOT_GID
          If you are not sure, leave it set to "0".
 
 config RD_GZIP
-       bool "Initial ramdisk compressed using gzip"
+       bool "Support initial ramdisks compressed using gzip" if EMBEDDED
        default y
-       depends on BLK_DEV_INITRD=y
+       depends on BLK_DEV_INITRD
        select DECOMPRESS_GZIP
        help
          Support loading of a gzip encoded initial ramdisk or cpio buffer.
          If unsure, say Y.
 
 config RD_BZIP2
-       bool "Initial ramdisk compressed using bzip2"
-       default n
-       depends on BLK_DEV_INITRD=y
+       bool "Support initial ramdisks compressed using bzip2" if EMBEDDED
+       default !EMBEDDED
+       depends on BLK_DEV_INITRD
        select DECOMPRESS_BZIP2
        help
          Support loading of a bzip2 encoded initial ramdisk or cpio buffer
          If unsure, say N.
 
 config RD_LZMA
-       bool "Initial ramdisk compressed using lzma"
-       default n
-       depends on BLK_DEV_INITRD=y
+       bool "Support initial ramdisks compressed using LZMA" if EMBEDDED
+       default !EMBEDDED
+       depends on BLK_DEV_INITRD
        select DECOMPRESS_LZMA
        help
-         Support loading of a lzma encoded initial ramdisk or cpio buffer
+         Support loading of a LZMA encoded initial ramdisk or cpio buffer
          If unsure, say N.
 
+if INITRAMFS_SOURCE!=""
+
 choice
        prompt "Built-in initramfs compression mode"
        help
-         This setting is only meaningful if the INITRAMFS_SOURCE is
-         set. It decides by which algorithm the INITRAMFS_SOURCE will
-         be compressed.
-         Several compression algorithms are available, which differ
-         in efficiency, compression and decompression speed.
-         Compression speed is only relevant when building a kernel.
-         Decompression speed is relevant at each boot.
-
-         If you have any problems with bzip2 or lzma compressed
+         This option decides by which algorithm the builtin initramfs
+         will be compressed.  Several compression algorithms are
+         available, which differ in efficiency, compression and
+         decompression speed.  Compression speed is only relevant
+         when building a kernel.  Decompression speed is relevant at
+         each boot.
+
+         If you have any problems with bzip2 or LZMA compressed
          initramfs, mail me (Alain Knaff) <alain@knaff.lu>.
 
-         High compression options are mostly useful for users who
-         are low on disk space (embedded systems), but for whom ram
-         size matters less.
+         High compression options are mostly useful for users who are
+         low on RAM, since it reduces the memory consumption during
+         boot.
 
          If in doubt, select 'gzip'
 
@@ -133,3 +134,14 @@ config INITRAMFS_COMPRESSION_LZMA
          smaller with LZMA in comparison to gzip.
 
 endchoice
+
+endif
+
+if INITRAMFS_SOURCE=""
+# The builtin initramfs is so small so we don't want to bug the user...
+
+config INITRAMFS_COMPRESSION_NONE
+       bool
+       default y
+
+endif